Skip to content

CPU_MMU_CACHE_25

Source: Verilog/CPU-BOARD-3202/circuit/CPU_MMU_CACHE_25.v

Where it sits (Simulation): ND120_TOP > ND120_CORE > ND3202D > CPU_15 > CPU_MMU_24 > CPU_MMU_CACHE_25 - instance path: CORE.CPU_BOARD.CPU.MMU.CACHE

Used in: CPU_MMU_24 (all tops)

Contains: Am9150 (only on Simulation, Nexys, MEGA65 R6, MEGA65 R3, QMTECH, Basys3, Cmod), PAL_44402D_EN (only on Simulation, Nexys, MEGA65 R6, MEGA65 R3, QMTECH, Basys3, Cmod), TMM2018D_25 x4 (only on Simulation, Nexys, MEGA65 R6, MEGA65 R3, QMTECH, Basys3, Cmod)

Module hierarchy - All modules

CPU_MMU_CACHE_25 symbol

Schematic

Drawn from the Verilog: the yosys netlist of the Simulation (Verilator) build, instance CORE.CPU_BOARD.CPU.MMU.CACHE. Sub-modules are boxes (click the picture to open it full size; there every sub-module box links to its page, and every wire shows its Verilog name).

CPU_MMU_CACHE_25 schematic

Description

ND120 CPU, MM&M CPU/MMU/CACHE CACHE SHEET 25 of 50 Last reviewed: 2-FEB-2025 Ronny Hansen

Ports

Direction Width Name Description
input 1 sysclk System clock in FPGA
input 1 sys_rst_n (active low) System reset in FPGA
input 1 BRK_n (active low) CPU Break signal (from CPU_MMU_24.BRK_n)
input [10:0] CA_10_0 Cache address, 11 bits (from CPU_MMU_24.CA_10_0)
input 1 CCLR_n (active low) Cache clear (from CPU_MMU_24.CCLR_n)
input 1 CWR Cache write (from CPU_MMU_24.CWR)
input 1 CYD Cycle done (from CPU_MMU_24.CYD)
input 1 DT_n (active low) Data transfer (from CPU_MMU_24.DT_n)
input 1 ECD_n (active low)
input 1 FMISS Force miss (from CPU_MMU_24.FMISS)
input [1:0] HIT_1_0_n (active low)
input 1 LSHADOW Load shadow signal (from CPU_MMU_24.LSHADOW)
input 1 PD2 Power down 2 (from CPU_MMU_24.PD2)
input 1 RT_n (active low) Reset trap (from CPU_15.RT_n)
input 1 SW1_CONSOLE Switch on the console (on/off) (from CPU_MMU_24.SW1_CONSOLE)
input 1 UCLK User clock (from CPU_MMU_24.UCLK)
input 1 UCLK_EN UCLK clock-enable pulse (FPGA_FF_MODE, else 0)
input 1 WCINH_n (active low)
input [15:0] CD_15_0_IN Cache data input, 16 bits (from CPU_MMU_24.CD_15_0_IN)
output [15:0] CD_15_0_OUT Cache data output, 16 bits (to CPU_MMU_24.CD_15_0_OUT)
input [13:0] CPN_23_10_IN
output [13:0] CPN_23_10_OUT
output 1 CON Cache ON (CON) goes to IDB1 when ECSR_n is low. CON_n goes to IDB2 (to CPU_MMU_CSR_26.CON)
output 1 CON_n (active low)
output 1 HIT Cache hit signal, indicates a successful cache lookup (to CPU_MMU_24.HIT)
output 1 WCA_n (active low) Write Cache Address, controls writing to the cache address register (to CPU_MMU_24.WCA_n)
output 1 LED1 LED 1, RED. Controlld by SW1. When LED is on, CON is 0. and CON_n is 1.

Verilog source

Verilog/CPU-BOARD-3202/circuit/CPU_MMU_CACHE_25.v on GitHub.

Show the Verilog of CPU_MMU_CACHE_25 (342 lines)
/**************************************************************************
** ND120 CPU, MM&M                                                       **
** CPU/MMU/CACHE                                                         **
** CACHE                                                                 **
** SHEET 25 of 50                                                        **
**                                                                       **
** Last reviewed: 2-FEB-2025                                             **
** Ronny Hansen                                                          **
***************************************************************************/


module CPU_MMU_CACHE_25 (

    input sysclk,    // System clock in FPGA
    input sys_rst_n, // System reset in FPGA

    input        BRK_n,  //! CPU Break signal (from CPU_MMU_24.BRK_n)
    input [10:0] CA_10_0,  //! Cache address, 11 bits (from CPU_MMU_24.CA_10_0)
    input        CCLR_n,  //! Cache clear (from CPU_MMU_24.CCLR_n)
    input        CWR,  //! Cache write (from CPU_MMU_24.CWR)
    input        CYD,  //! Cycle done (from CPU_MMU_24.CYD)
    input        DT_n,  //! Data transfer (from CPU_MMU_24.DT_n)
    input        ECD_n,
    input        FMISS,  //! Force miss (from CPU_MMU_24.FMISS)
    input [ 1:0] HIT_1_0_n,
    input        LSHADOW,  //! Load shadow signal (from CPU_MMU_24.LSHADOW)
    input        PD2,  //! Power down 2 (from CPU_MMU_24.PD2)
    input        RT_n,  //! Reset trap (from CPU_15.RT_n)
    input        SW1_CONSOLE,  //! Switch on the console (on/off) (from CPU_MMU_24.SW1_CONSOLE)
    input        UCLK,  //! User clock (from CPU_MMU_24.UCLK)
    input        UCLK_EN,  //! UCLK clock-enable pulse (FPGA_FF_MODE, else 0)
    input        WCINH_n,

    input  [15:0] CD_15_0_IN,  //! Cache data input, 16 bits (from CPU_MMU_24.CD_15_0_IN)
    output [15:0] CD_15_0_OUT,  //! Cache data output, 16 bits (to CPU_MMU_24.CD_15_0_OUT)

    input  [13:0] CPN_23_10_IN,
    output [13:0] CPN_23_10_OUT,

    /*******************************************************************************
   ** The outputs are defined here                                               **
   *******************************************************************************/

    output CON,      //! Cache ON (CON) goes to IDB1 when ECSR_n is low. CON_n goes to IDB2 (to CPU_MMU_CSR_26.CON)
    output CON_n,
    output HIT,      //! Cache hit signal, indicates a successful cache lookup (to CPU_MMU_24.HIT)
    output WCA_n,    //! Write Cache Address, controls writing to the cache address register (to CPU_MMU_24.WCA_n)

    output LED1  //LED 1, RED. Controlld by SW1. When LED is on, CON is 0. and CON_n is 1.
);




  /*******************************************************************************
   ** The wires are defined here                                                 **
   *******************************************************************************/
  wire [15:0] s_cd_15_0_out;
  wire [10:0] s_ca_10_0;
  wire [ 1:0] s_hit_1_0_n;
  wire        s_wca_n   /* verilator public_flat_rd */;   // probed by runSim (cache log)
  wire        s_brk_n;
  wire        s_wcinh_n;
  wire        s_used_n;
  wire        s_con;
  wire        s_con_n;
  wire        s_cclr_n  /* verilator public_flat_rd */;   // probed by runSim (cache log)
  wire        s_hit;
  wire        s_dt_n    /* verilator public_flat_rd */;   // probed by runSim (cache log)
  wire        s_lshadow;
  wire        s_cyd;
  wire        s_cwr;
  wire        s_uclk;
  wire        s_rt_n    /* verilator public_flat_rd */;   // probed by runSim (cache log)
  wire        s_pd2     /* verilator public_flat_rd */;   // probed by runSim (cache log)
  wire        s_fmiss;
  wire        s_ecd_n;
  wire        s_ewc_n;
  wire        s_gnd;


  wire [15:0] s_CPN_25_10_OUT;
  wire [ 3:0] s_21f_in  /* verilator public_flat_rd */;   // probed by runSim (cache log)
  wire [ 3:0] s_21f_out;


  /*******************************************************************************
   ** Here all input connections are defined                                     **
   *******************************************************************************/
  assign s_ca_10_0 = CA_10_0;
  assign s_hit_1_0_n[1:0] = HIT_1_0_n;
`ifdef ND120_NO_CACHE
  // CACHE COMPILED OUT (-DND120_NO_CACHE).
  //
  // This is NOT an invented mode: the board has SW1, a real cache on/off
  // switch, and CON low IS the off position. So the machine reports its cache
  // status as DISABLED exactly as it would with the switch thrown, LED1 lit,
  // and the hit comparators held disabled - and every access goes to main
  // memory. What the define adds on top is that the cache SRAMs and the
  // used-bit PAL are not instantiated at all, so the logic is not merely
  // bypassed, it is absent.
  //
  // Why it exists: on the Tang Nano 20K the design does not fit with the
  // cache present. Ignore SW1_CONSOLE and force the off position.
  assign s_con = 1'b0;
`else
  assign s_con = SW1_CONSOLE;
`endif
  assign s_brk_n = BRK_n;
  assign s_wcinh_n = WCINH_n;
  assign s_cclr_n = CCLR_n;
  assign s_dt_n = DT_n;
  assign s_lshadow = LSHADOW;
  assign s_cyd = CYD;
  assign s_cwr = CWR;
  assign s_uclk = UCLK;
  assign s_rt_n = RT_n;
  assign s_pd2 = PD2;
  assign s_fmiss = FMISS;
  assign s_ecd_n = ECD_n;

  /*******************************************************************************
   ** Here all output connections are defined                                    **
   *******************************************************************************/
  // Banner word-index-2 fix (26-JUL): the cache data SRAM (23F/24F) is driven onto
  // the wired-OR CD bus for the whole read-transfer (CS=ECD, sheet 25). On a MISS the
  // memory data only survives that OR because the refill (WCA) forces the SRAM output
  // to 0 while writing. For a CACHE-INHIBIT page (WCINH) the refill is suppressed, so a
  // line still holding stale non-zero data (e.g. 0177777 cached during init-clear, then
  // the memory rewritten by DMA which bypasses the cache) JAMS the OR bus over the
  // correct memory word -> banner "INSTRUCTION" printed as "INST\x7f\x7fCTION".
  // Gate the cache CD output by HIT so it contributes 0 unless this line genuinely
  // matches the requested address; memory then passes cleanly on every miss/inhibit.
  // Escape hatch: -DND120_CACHE_DRIVE_UNGATED restores the raw schematic behaviour.
`ifdef ND120_NO_CACHE
  // No cache RAM exists in this build, so the sheet contributes nothing to the
  // wired-OR CD bus and memory data passes cleanly on every access.
  assign CD_15_0_OUT = 16'b0;
`elsif ND120_CACHE_DRIVE_UNGATED
  assign CD_15_0_OUT = s_cd_15_0_out[15:0];
`else
  assign CD_15_0_OUT = s_hit ? s_cd_15_0_out[15:0] : 16'b0;
`endif
  assign CON = s_con;
  assign CON_n = s_con_n;
  assign HIT = s_hit;
  assign WCA_n = s_wca_n;

  assign CPN_23_10_OUT = s_CPN_25_10_OUT[13:0];


  // Code to make LINTER not complaing about bits not read in CPN 25:10 (which is none-existsing)
  (* keep = "true", DONT_TOUCH = "true" *) wire [1:0] unused_CPN_bits;
  assign unused_CPN_bits[1:0] =  s_CPN_25_10_OUT[15:14];

  /*******************************************************************************
   ** Here all in-lined components are defined                                   **
   *******************************************************************************/

  // Ground
  assign s_gnd = 1'b0;
  assign s_con_n = ~s_con;

  // Led1 cathode is connected to CON signal, and ANODE to VCC, so a low on s_CON will give light in LED1
  assign LED1      = s_con_n;

  /*******************************************************************************
   ** Here all normal components are defined                                     **
   *******************************************************************************/
  /*
   NAND_GATE_3_INPUTS #(.BubblesMask(3'b000))
      GATES_1 (.input1(s_brk_n),
               .input2(s_con),
               .input3(s_wcinh_n),
               .result(s_ewc_n));
   */

  assign s_ewc_n = ~(s_brk_n & s_con & s_wcinh_n);

  /*
   AND_GATE_5_INPUTS #(.BubblesMask({1'b1, 4'hF}))
      GATES_2 (.input1(s_used_n),
               .input2(s_hit_1_0_n[1]),
               .input3(s_hit_1_0_n[0]),
               .input4(s_cwr),
               .input5(s_gnd), //GND
               .result(s_hit));
   */

`ifdef ND120_NO_CACHE
  // With CON forced to the off position the comparators on sheet 27 are held
  // disabled and report NO MATCH, so this is 0 by the same logic the switch
  // gives. Stated directly here so no cache signal is left undriven once the
  // RAMs below are omitted.
  assign s_hit = 1'b0;
`else
  assign s_hit = !s_used_n & !s_hit_1_0_n[0] & !s_hit_1_0_n[1] & !s_cwr;
`endif
  /*******************************************************************************
   ** Here all sub-circuits are defined                                          **
   *******************************************************************************/

`ifdef ND120_NO_CACHE
  // The five cache memories (23F/24F data, 16F/20F tag, 21F used-bits) and the
  // used-bit PAL 18F are NOT INSTANTIATED in this build. Everything they drive
  // is given its cache-off constant here.
  assign s_cd_15_0_out    = 16'b0;
  assign s_CPN_25_10_OUT  = 16'b0;
  assign s_used_n         = 1'b1;   // no line is "used"
  assign s_wca_n          = 1'b1;   // never write a cache address
`else

  //  16K bit Static RAM  (2KByte) - ASYNC read, see the parameter in TMM2018D_25.v
  TMM2018D_25 #(.ASYNC_READ(1)) CHIP_23F
  (
    .clk    (sysclk),               // Clock input (BLOCK RAM MUST HAVE CLOCK)
    .reset_n(sys_rst_n),            // FPGA Reset input (active low)

    // Input signals
    .ADDRESS(s_ca_10_0[10:0]),
    .CS_n   (s_ecd_n),
    .OE_n   (s_gnd),
    .W_n    (s_wca_n),

    // Bus data in and out
    .D      (CD_15_0_IN[15:8]),
    .D_OUT  (s_cd_15_0_out[15:8])
  );

  //  16K bit Static RAM  (2KByte)
  TMM2018D_25 #(.ASYNC_READ(1)) CHIP_24F
  (
    .clk    (sysclk),              // Clock input (BLOCK RAM MUST HAVE CLOCK)
    .reset_n(sys_rst_n),           // FPGA Reset input (active low)

     // Input signals
    .ADDRESS(s_ca_10_0[10:0]),
    .CS_n   (s_ecd_n),
    .OE_n   (s_gnd),
    .W_n    (s_wca_n),

    // Bus data in and out
    .D      (CD_15_0_IN[7:0]),
    .D_OUT  (s_cd_15_0_out[7:0])
  );

  // P3 (docs/plan-fix-unconstrained-clocks.md): in FF mode the UBITS PAL
  // registers capture on posedge sysclk gated by the rise-aligned UCLK
  // enable instead of clocking on the routed s_uclk net (uclk_Z clock root).
`ifdef FPGA_FF_MODE
  localparam UCLK_CE = 1;
`else
  localparam UCLK_CE = 0;
`endif

  PAL_44402D_EN #(.USE_ENABLE(UCLK_CE)) PAL_44402_UBITS (  // PAL16R4D
      .sysclk(sysclk),
      .EN(UCLK_EN),
      .CLK (s_uclk),
      .OE_n(s_pd2),

      .DT_n(s_dt_n),
      .RT_n(s_rt_n),
      .LSHADOW(s_lshadow),
      .FMISS(s_fmiss),
      .CYD(s_cyd),
      .HIT0_n(s_hit_1_0_n[0]),
      .HIT1_n(s_hit_1_0_n[1]),
      .EWC_n(s_ewc_n),

      .USED_n(s_used_n),
      .WCA_n (s_wca_n),
      .OUBI  (s_21f_out[0]),
      .OUBD  (s_21f_out[1]),


      .NUBI_n(s_21f_in[0]),
      .NUBD_n(s_21f_in[1]),

      //.Q2_n(), // Not connected
      .IHIT_n()  //.Q3_n(s_ihit) // IHIT_n not connected
  );

  assign s_21f_in[3:2] = 2'b00;

// Code to make LINTER _not_ complain about bits not read in s_21f_out bits 3 and 2
  (* keep = "true", DONT_TOUCH = "true" *) wire [1:0] unused_21f_out_bits;
  assign unused_21f_out_bits[1:0] = s_21f_out[3:2];

  // 4KBit * 4 DYNAMIC RAM
  Am9150 CHIP_21F
  (
      .clk            (sysclk),          // Clock input (BLOCK RAM MUST HAVE CLOCK)
      .address        (s_ca_10_0[9:0]),
      .OUTPUT_ENABLE_n(s_gnd),
      .RESET_n        (s_cclr_n),
      .CHIP_SELECT_n  (s_gnd),
      .WRITE_ENABLE_n (s_wca_n),

      .data_in        (s_21f_in[3:0]),
      .data_out       (s_21f_out[3:0])
  );

  //  16K bit Static RAM  (2KByte)
  TMM2018D_25 #(.ASYNC_READ(1)) CHIP_16F
  (
    .clk(sysclk),  // Clock input (BLOCK RAM MUST HAVE CLOCK)
    .reset_n(sys_rst_n),  // FPGA Reset input (active low)

     // Input signals
    .ADDRESS(s_ca_10_0[10:0]),
    .CS_n(s_pd2),
    .OE_n(s_gnd),
    .W_n(s_wca_n),

    // Bus data in and out
    .D({
    2'b00, CPN_23_10_IN[13:8]
    }),  // bit D0 and D1 is not connected (we need only 6 bits) for CPN 23-18
    .D_OUT(s_CPN_25_10_OUT[15:8]) // CPN 25:10. CPN 25 and 24 is none existsting and not connected in the schema.
  );

  //  16K bit Static RAM  (2KByte)
  TMM2018D_25 #(.ASYNC_READ(1)) CHIP_20F
  (
    .clk    (sysclk),                // Clock input (BLOCK RAM MUST HAVE CLOCK)
    .reset_n(sys_rst_n),             // FPGA Reset input (active low)

    // Input signals
    .ADDRESS(s_ca_10_0[10:0]),
    .CS_n   (s_pd2),
    .OE_n   (s_gnd),
    .W_n    (s_wca_n),

      // Bus data in and out
    .D      (CPN_23_10_IN[7:0]),
    .D_OUT  (s_CPN_25_10_OUT[7:0])  // CPN 17-10

  );
`endif  // ND120_NO_CACHE

endmodule