1 from nmigen
import Elaboratable
, Module
, Signal
, Record
2 from nmutil
.formaltest
import FHDLTestCase
3 from nmigen
.asserts
import AnyConst
, AnySeq
, Assert
, Assume
, Past
, Initial
5 from soc
.minerva
.cache
import L1Cache
8 class L1CacheSpec(Elaboratable
):
10 A cache read at a given address must either:
11 - miss and start a cache refill;
12 - hit and return the last refilled value for that address.
14 def __init__(self
, cache
):
17 def elaborate(self
, platform
):
19 m
.submodules
.dut
= cache
= self
.cache
21 addr
= AnyConst(cache
.s1_addr
.shape())
24 with m
.If(~cache
.s1_stall
):
26 cache
.s2_addr
.eq(cache
.s1_addr
),
27 cache
.s2_re
.eq(s1_re
),
28 cache
.s2_valid
.eq(cache
.s1_valid
)
31 m
.d
.comb
+= Assume(cache
.s1_valid
.implies(cache
.s1_addr
== addr
))
32 with m
.If(cache
.s2_re
& cache
.s2_miss
& cache
.s2_valid
):
33 m
.d
.comb
+= Assume(cache
.s1_stall
)
35 spec_s2_rdata
= Signal(32)
36 spec_bus_re
= Signal()
37 spec_bus_addr
= Record
.like(cache
.bus_addr
)
38 spec_bus_last
= Signal()
39 last_offset
= Signal
.like(cache
.s2_addr
.offset
)
41 with m
.If(~
Past(cache
.s1_stall
)):
42 with m
.If(cache
.s2_re
& cache
.s2_miss
& cache
.s2_valid
):
45 spec_bus_addr
.eq(cache
.s2_addr
),
46 last_offset
.eq(cache
.s2_addr
.offset
- 1)
49 with m
.If(cache
.bus_re
):
50 with m
.If(cache
.bus_valid
):
51 # Lines are refilled with an incremental burst that
52 # starts at the missed address
53 # and wraps around the offset bits.
54 m
.d
.sync
+= spec_bus_addr
.offset
.eq(spec_bus_addr
.offset
+ 1)
55 with m
.If((cache
.bus_addr
== cache
.s2_addr
) & ~cache
.bus_error
):
56 m
.d
.sync
+= spec_s2_rdata
.eq(cache
.bus_rdata
)
57 # A burst ends when all words in the line have
58 # been refilled, or an error occured.
59 m
.d
.comb
+= spec_bus_last
.eq(cache
.bus_addr
.offset
== last_offset
)
60 with m
.If(cache
.bus_valid
& cache
.bus_last | cache
.bus_error
):
61 m
.d
.sync
+= spec_bus_re
.eq(0)
63 with m
.If(cache
.s2_re
& cache
.s2_valid
& ~cache
.s2_miss
):
64 m
.d
.comb
+= Assert(cache
.s2_rdata
== spec_s2_rdata
)
66 m
.d
.comb
+= Assert(cache
.bus_re
== spec_bus_re
)
67 with m
.If(cache
.bus_re
):
69 Assert(cache
.bus_addr
== spec_bus_addr
),
70 Assert(cache
.bus_last
== spec_bus_last
)
75 Assume(cache
.s1_stall
),
76 Assume(~cache
.s2_valid
),
77 Assume(~cache
.bus_re
),
84 class L1CacheTestCase(FHDLTestCase
):
85 def check(self
, cache
):
86 self
.assertFormal(L1CacheSpec(cache
), mode
="bmc", depth
=10)
88 def test_direct_mapped(self
):
89 self
.check(L1Cache(nways
=1, nlines
=2, nwords
=4, base
=0, limit
=1024))
91 def test_2_ways(self
):
92 self
.check(L1Cache(nways
=2, nlines
=2, nwords
=4, base
=0, limit
=1024))