test_ldst_pi.py: add dcache regression and random test from test_dcache.py
[soc.git] / src / soc / experiment / dcache.py
index 7059cf83a8e2462a1b80b2423af1d837a717d179..072d34a90d108e601d0640930607ca205ab2fe4b 100644 (file)
@@ -8,6 +8,12 @@ see WB4 spec, p84, section 5.2.1
 
 IMPORTANT: for store, the data is sampled the cycle AFTER the "valid"
 is raised.  sigh
+
+Links:
+
+* https://libre-soc.org/3d_gpu/architecture/set_associative_cache.jpg
+* https://bugs.libre-soc.org/show_bug.cgi?id=469
+
 """
 
 import sys
@@ -441,8 +447,8 @@ class DTLBUpdate(Elaboratable):
         self.dv = Signal(TLB_NUM_WAYS) # tlb_way_valids_t
 
         self.tb_out = Signal(TLB_TAG_WAY_BITS) # tlb_way_tags_t
-        self.pb_out = Signal(TLB_NUM_WAYS)     # tlb_way_valids_t
-        self.db_out = Signal(TLB_PTE_WAY_BITS) # tlb_way_ptes_t
+        self.db_out = Signal(TLB_NUM_WAYS)     # tlb_way_valids_t
+        self.pb_out = Signal(TLB_PTE_WAY_BITS) # tlb_way_ptes_t
 
     def elaborate(self, platform):
         m = Module()
@@ -459,7 +465,7 @@ class DTLBUpdate(Elaboratable):
             pass # clear all back in parent
         with m.Elif(self.tlbie):
             with m.If(self.tlb_hit):
-                comb += db_out.bit_select(self.tlb_hit_way, 1).eq(1)
+                comb += db_out.bit_select(self.tlb_hit_way, 1).eq(0)
                 comb += self.v_updated.eq(1)
 
         with m.Elif(self.tlbwe):
@@ -579,6 +585,7 @@ class DCachePendingHit(Elaboratable):
 
 class DCache(Elaboratable):
     """Set associative dcache write-through
+
     TODO (in no specific order):
     * See list in icache.vhdl
     * Complete load misses on the cycle when WB data comes instead of
@@ -614,7 +621,7 @@ class DCache(Elaboratable):
 
         with m.If(m_in.valid):
             comb += r.req.valid.eq(1)
-            comb += r.req.load.eq(~(m_in.tlbie | m_in.tlbld))
+            comb += r.req.load.eq(~(m_in.tlbie | m_in.tlbld))# no invalidate
             comb += r.req.dcbz.eq(0)
             comb += r.req.nc.eq(0)
             comb += r.req.reserve.eq(0)
@@ -627,6 +634,9 @@ class DCache(Elaboratable):
             comb += r.doall.eq(m_in.doall)
             comb += r.tlbld.eq(m_in.tlbld)
             comb += r.mmu_req.eq(1)
+            m.d.sync += Display("    DCACHE req mmu addr %x pte %x ld %d",
+                                 m_in.addr, m_in.pte, r.req.load)
+
         with m.Else():
             comb += r.req.eq(d_in)
             comb += r.req.data.eq(0)
@@ -644,6 +654,11 @@ class DCache(Elaboratable):
                      ~r0.mmu_req):
                 sync += r0.req.data.eq(d_in.data)
                 sync += r0.d_valid.eq(1)
+        with m.If(d_in.valid):
+            m.d.sync += Display("    DCACHE req cache "
+                                "virt %d addr %x data %x ld %d",
+                                 r.req.virt_mode, r.req.addr,
+                                 r.req.data, r.req.load)
 
     def tlb_read(self, m, r0_stall, tlb_valid_way,
                  tlb_tag_way, tlb_pte_way, dtlb_valid_bits,
@@ -709,9 +724,10 @@ class DCache(Elaboratable):
         comb += eatag.eq(r0.req.addr[TLB_LG_END : 64 ])
 
         for i in range(TLB_NUM_WAYS):
-            is_tag_hit = Signal()
-            comb += is_tag_hit.eq(tlb_valid_way[i]
-                                  & (read_tlb_tag(i, tlb_tag_way) == eatag))
+            is_tag_hit = Signal(name="is_tag_hit%d" % i)
+            tlb_tag = Signal(TLB_EA_TAG_BITS, name="tlb_tag%d" % i)
+            comb += tlb_tag.eq(read_tlb_tag(i, tlb_tag_way))
+            comb += is_tag_hit.eq(tlb_valid_way[i] & (tlb_tag == eatag))
             with m.If(is_tag_hit):
                 comb += hitway.eq(i)
                 comb += hit.eq(1)
@@ -743,6 +759,16 @@ class DCache(Elaboratable):
             comb += perm_attr.rd_perm.eq(1)
             comb += perm_attr.wr_perm.eq(1)
 
+        with m.If(valid_ra):
+            m.d.sync += Display("DCACHE virt mode %d hit %d ra %x pte %x",
+                                r0.req.virt_mode, tlb_hit, ra, pte)
+            m.d.sync += Display("       perm ref=%d", perm_attr.reference)
+            m.d.sync += Display("       perm chg=%d", perm_attr.changed)
+            m.d.sync += Display("       perm noc=%d", perm_attr.nocache)
+            m.d.sync += Display("       perm prv=%d", perm_attr.priv)
+            m.d.sync += Display("       perm rdp=%d", perm_attr.rd_perm)
+            m.d.sync += Display("       perm wrp=%d", perm_attr.wr_perm)
+
     def tlb_update(self, m, r0_valid, r0, dtlb_valid_bits, tlb_req_index,
                     tlb_hit_way, tlb_hit, tlb_plru_victim, tlb_tag_way,
                     dtlb_tags, tlb_pte_way, dtlb_ptes):
@@ -925,10 +951,15 @@ class DCache(Elaboratable):
         comb += op.eq(Op.OP_NONE)
         with m.If(go):
             with m.If(~access_ok):
+                m.d.sync += Display("DCACHE access fail valid_ra=%d p=%d rc=%d",
+                                 valid_ra, perm_ok, rc_ok)
                 comb += op.eq(Op.OP_BAD)
             with m.Elif(cancel_store):
+                m.d.sync += Display("DCACHE cancel store")
                 comb += op.eq(Op.OP_STCX_FAIL)
             with m.Else():
+                m.d.sync += Display("DCACHE valid_ra=%d nc=%d ld=%d",
+                                 valid_ra, nc, r0.req.load)
                 comb += opsel.eq(Cat(is_hit, nc, r0.req.load))
                 with m.Switch(opsel):
                     with m.Case(0b101): comb += op.eq(Op.OP_LOAD_HIT)
@@ -1066,8 +1097,8 @@ class DCache(Elaboratable):
 
             # Slow ops (i.e. load miss)
             with m.If(r1.slow_valid):
-                sync += Display("completing MMU load miss, data=%x",
-                                m_out.data)
+                sync += Display("completing MMU load miss, adr=%x data=%x",
+                                r1.req.real_addr, m_out.data)
 
     def rams(self, m, r1, early_req_row, cache_out_row, replace_way):
         """rams
@@ -1093,7 +1124,7 @@ class DCache(Elaboratable):
             wr_sel_m = Signal(ROW_SIZE)
             _d_out   = Signal(WB_DATA_BITS, name="dout_%d" % i) # cache_row_t
 
-            way = CacheRam(ROW_BITS, WB_DATA_BITS, ADD_BUF=True)
+            way = CacheRam(ROW_BITS, WB_DATA_BITS, ADD_BUF=True, ram_num=i)
             setattr(m.submodules, "cacheram_%d" % i, way)
 
             comb += way.rd_en.eq(do_read)
@@ -1183,10 +1214,10 @@ class DCache(Elaboratable):
             sync += r1.mmu_error.eq(r0.mmu_req)
             sync += r1.cache_paradox.eq(access_ok)
 
-            with m.Else():
-                sync += r1.ls_error.eq(0)
-                sync += r1.mmu_error.eq(0)
-                sync += r1.cache_paradox.eq(0)
+        with m.Else():
+            sync += r1.ls_error.eq(0)
+            sync += r1.mmu_error.eq(0)
+            sync += r1.cache_paradox.eq(0)
 
         with m.If(req_op == Op.OP_STCX_FAIL):
             sync += r1.stcx_fail.eq(1)
@@ -1468,6 +1499,9 @@ cache_tags(r1.store_index)((i + 1) * TAG_WIDTH - 1 downto i * TAG_WIDTH) <=
                         sync += cache_valids[r1.store_index].eq(cv)
 
                         sync += r1.state.eq(State.IDLE)
+                        sync += Display("cache valid set %x "
+                                        "idx %d way %d",
+                                         cv, r1.store_index, r1.store_way)
 
                     # Increment store row counter
                     sync += r1.store_row.eq(next_row(r1.store_row))
@@ -1694,283 +1728,9 @@ cache_tags(r1.store_index)((i + 1) * TAG_WIDTH - 1 downto i * TAG_WIDTH) <=
 
         return m
 
-def dcache_load(dut, addr, nc=0):
-    yield dut.d_in.load.eq(1)
-    yield dut.d_in.nc.eq(nc)
-    yield dut.d_in.addr.eq(addr)
-    yield dut.d_in.byte_sel.eq(~0)
-    yield dut.d_in.valid.eq(1)
-    yield
-    yield dut.d_in.valid.eq(0)
-    yield dut.d_in.byte_sel.eq(0)
-    while not (yield dut.d_out.valid):
-        yield
-    # yield # data is valid one cycle AFTER valid goes hi? (no it isn't)
-    data = yield dut.d_out.data
-    return data
-
-
-def dcache_store(dut, addr, data, nc=0):
-    yield dut.d_in.load.eq(0)
-    yield dut.d_in.nc.eq(nc)
-    yield dut.d_in.byte_sel.eq(~0)
-    yield dut.d_in.addr.eq(addr)
-    yield dut.d_in.valid.eq(1)
-    yield
-    yield dut.d_in.data.eq(data)    # leave set, but the cycle AFTER
-    yield dut.d_in.valid.eq(0)
-    yield dut.d_in.byte_sel.eq(0)
-    while not (yield dut.d_out.valid):
-        yield
-
-
-def dcache_random_sim(dut, mem):
-
-    # start copy of mem
-    sim_mem = deepcopy(mem)
-    memsize = len(sim_mem)
-    print ("mem len", memsize)
-
-    # clear stuff
-    yield dut.d_in.valid.eq(0)
-    yield dut.d_in.load.eq(0)
-    yield dut.d_in.priv_mode.eq(1)
-    yield dut.d_in.nc.eq(0)
-    yield dut.d_in.addr.eq(0)
-    yield dut.d_in.data.eq(0)
-    yield dut.m_in.valid.eq(0)
-    yield dut.m_in.addr.eq(0)
-    yield dut.m_in.pte.eq(0)
-    # wait 4 * clk_period
-    yield
-    yield
-    yield
-    yield
-
-    print ()
-
-    #for i in range(1024):
-    #    sim_mem[i] = i
-
-    for i in range(1024):
-        addr = randint(0, memsize-1)
-        data = randint(0, (1<<64)-1)
-        sim_mem[addr] = data
-        row = addr
-        addr *= 8
-
-        print ("random testing %d 0x%x row %d data 0x%x" % (i, addr, row, data))
-
-        yield from dcache_load(dut, addr)
-        yield from dcache_store(dut, addr, data)
-
-        addr = randint(0, memsize-1)
-        sim_data = sim_mem[addr]
-        row = addr
-        addr *= 8
-
-        print ("    load 0x%x row %d expect data 0x%x" % (addr, row, sim_data))
-        data = yield from dcache_load(dut, addr)
-        assert data == sim_data, \
-            "check addr 0x%x row %d data %x != %x" % (addr, row, data, sim_data)
-
-    for addr in range(memsize):
-        data = yield from dcache_load(dut, addr*8)
-        assert data == sim_mem[addr], \
-            "final check %x data %x != %x" % (addr*8, data, sim_mem[addr])
-
-def dcache_regression_sim(dut, mem):
-
-    # start copy of mem
-    sim_mem = deepcopy(mem)
-    memsize = len(sim_mem)
-    print ("mem len", memsize)
-
-    # clear stuff
-    yield dut.d_in.valid.eq(0)
-    yield dut.d_in.load.eq(0)
-    yield dut.d_in.priv_mode.eq(1)
-    yield dut.d_in.nc.eq(0)
-    yield dut.d_in.addr.eq(0)
-    yield dut.d_in.data.eq(0)
-    yield dut.m_in.valid.eq(0)
-    yield dut.m_in.addr.eq(0)
-    yield dut.m_in.pte.eq(0)
-    # wait 4 * clk_period
-    yield
-    yield
-    yield
-    yield
-
-    addr = 0
-    row = addr
-    addr *= 8
-
-    print ("random testing %d 0x%x row %d" % (i, addr, row))
-
-    yield from dcache_load(dut, addr)
-
-    addr = 2
-    sim_data = sim_mem[addr]
-    row = addr
-    addr *= 8
-
-    print ("    load 0x%x row %d expect data 0x%x" % (addr, row, sim_data))
-    data = yield from dcache_load(dut, addr)
-    assert data == sim_data, \
-        "check addr 0x%x row %d data %x != %x" % (addr, row, data, sim_data)
-
-
-
-def dcache_sim(dut, mem):
-    # clear stuff
-    yield dut.d_in.valid.eq(0)
-    yield dut.d_in.load.eq(0)
-    yield dut.d_in.priv_mode.eq(1)
-    yield dut.d_in.nc.eq(0)
-    yield dut.d_in.addr.eq(0)
-    yield dut.d_in.data.eq(0)
-    yield dut.m_in.valid.eq(0)
-    yield dut.m_in.addr.eq(0)
-    yield dut.m_in.pte.eq(0)
-    # wait 4 * clk_period
-    yield
-    yield
-    yield
-    yield
-
-    # Cacheable read of address 4
-    data = yield from dcache_load(dut, 0x58)
-    addr = yield dut.d_in.addr
-    assert data == 0x0000001700000016, \
-        f"data @%x=%x expected 0x0000001700000016" % (addr, data)
-
-    # Cacheable read of address 20
-    data = yield from dcache_load(dut, 0x20)
-    addr = yield dut.d_in.addr
-    assert data == 0x0000000900000008, \
-        f"data @%x=%x expected 0x0000000900000008" % (addr, data)
-
-    # Cacheable read of address 30
-    data = yield from dcache_load(dut, 0x530)
-    addr = yield dut.d_in.addr
-    assert data == 0x0000014D0000014C, \
-        f"data @%x=%x expected 0000014D0000014C" % (addr, data)
-
-    # 2nd Cacheable read of address 30
-    data = yield from dcache_load(dut, 0x530)
-    addr = yield dut.d_in.addr
-    assert data == 0x0000014D0000014C, \
-        f"data @%x=%x expected 0000014D0000014C" % (addr, data)
-
-    # Non-cacheable read of address 100
-    data = yield from dcache_load(dut, 0x100, nc=1)
-    addr = yield dut.d_in.addr
-    assert data == 0x0000004100000040, \
-        f"data @%x=%x expected 0000004100000040" % (addr, data)
-
-    # Store at address 530
-    yield from dcache_store(dut, 0x530, 0x121)
-
-    # Store at address 30
-    yield from dcache_store(dut, 0x530, 0x12345678)
-
-    # 3nd Cacheable read of address 530
-    data = yield from dcache_load(dut, 0x530)
-    addr = yield dut.d_in.addr
-    assert data == 0x12345678, \
-        f"data @%x=%x expected 0x12345678" % (addr, data)
-
-    # 4th Cacheable read of address 20
-    data = yield from dcache_load(dut, 0x20)
-    addr = yield dut.d_in.addr
-    assert data == 0x0000000900000008, \
-        f"data @%x=%x expected 0x0000000900000008" % (addr, data)
-
-    yield
-    yield
-    yield
-    yield
-
-
-def test_dcache(mem, test_fn, test_name):
-    dut = DCache()
-
-    memory = Memory(width=64, depth=len(mem), init=mem, simulate=True)
-    sram = SRAM(memory=memory, granularity=8)
-
-    m = Module()
-    m.submodules.dcache = dut
-    m.submodules.sram = sram
-
-    m.d.comb += sram.bus.cyc.eq(dut.wb_out.cyc)
-    m.d.comb += sram.bus.stb.eq(dut.wb_out.stb)
-    m.d.comb += sram.bus.we.eq(dut.wb_out.we)
-    m.d.comb += sram.bus.sel.eq(dut.wb_out.sel)
-    m.d.comb += sram.bus.adr.eq(dut.wb_out.adr)
-    m.d.comb += sram.bus.dat_w.eq(dut.wb_out.dat)
-
-    m.d.comb += dut.wb_in.ack.eq(sram.bus.ack)
-    m.d.comb += dut.wb_in.dat.eq(sram.bus.dat_r)
-
-    dcache_write_gtkw(test_name)
-
-    # nmigen Simulation
-    sim = Simulator(m)
-    sim.add_clock(1e-6)
-
-    sim.add_sync_process(wrap(test_fn(dut, mem)))
-    with sim.write_vcd('test_dcache%s.vcd' % test_name):
-        sim.run()
-
-
-def dcache_write_gtkw(test_name):
-    traces = [
-        'clk',
-        ('d_in', [
-            'd_in_load', 'd_in_nc', 'd_in_addr[63:0]', 'd_in_data[63:0]',
-            'd_in_byte_sel[7:0]', 'd_in_valid'
-        ]),
-        ('d_out', [
-            'd_out_valid', 'd_out_data[63:0]'
-        ]),
-        ('wb_out', [
-            'wb_out_cyc', 'wb_out_stb', 'wb_out_we',
-            'wb_out_adr[31:0]', 'wb_out_sel[7:0]', 'wb_out_dat[63:0]'
-        ]),
-        ('wb_in', [
-            'wb_in_stall', 'wb_in_ack', 'wb_in_dat[63:0]'
-        ])
-    ]
-    write_gtkw('test_dcache%s.gtkw' % test_name,
-               'test_dcache%s.vcd' % test_name,
-               traces, module='top.dcache')
-
 
 if __name__ == '__main__':
-    seed(0)
     dut = DCache()
     vl = rtlil.convert(dut, ports=[])
     with open("test_dcache.il", "w") as f:
         f.write(vl)
-
-    mem = []
-    memsize = 16
-    for i in range(memsize):
-        mem.append(i)
-
-    test_dcache(mem, dcache_regression_sim, "simpleregression")
-
-    mem = []
-    memsize = 256
-    for i in range(memsize):
-        mem.append(i)
-
-    test_dcache(mem, dcache_random_sim, "random")
-
-    mem = []
-    for i in range(1024):
-        mem.append((i*2)| ((i*2+1)<<32))
-
-    test_dcache(mem, dcache_sim, "")
-