1 """ Load / Store partial address matcher
3 Loads and Stores do not need a full match (CAM), they need "good enough"
4 avoidance. Around 11 bits on a 64-bit address is "good enough".
6 The simplest way to use this module is to ignore not only the top bits,
7 but also the bottom bits as well: in this case (this RV64 processor),
8 enough to cover a DWORD (64-bit). that means ignore the bottom 4 bits,
9 due to the possibility of 64-bit LD/ST being misaligned.
11 To reiterate: the use of this module is an *optimisation*. All it has
12 to do is cover the cases that are *definitely* matches (by checking 11
13 bits or so), and if a few opportunities for parallel LD/STs are missed
14 because the top (or bottom) bits weren't checked, so what: all that
15 happens is: the mis-matched addresses are LD/STd on single-cycles. Big Deal.
18 from nmigen
.compat
.sim
import run_simulation
19 from nmigen
.cli
import verilog
, rtlil
20 from nmigen
import Module
, Signal
, Const
, Array
, Cat
, Elaboratable
23 class PartialAddrMatch(Elaboratable
):
24 """A partial address matcher
26 def __init__(self
, n_adr
, bitwid
):
30 self
.addrs_i
= Array(Signal(bitwid
, name
="addr") for i
in range(n_adr
))
31 self
.addr_we_i
= Signal(n_adr
) # write-enable for incoming address
32 self
.addr_en_i
= Signal(n_adr
) # address activated (0 == ignore)
35 self
.addr_match_o
= Signal(n_adr
)
37 def elaborate(self
, platform
):
42 addrs_r
= Array(Signal(self
.bitwid
, "a_r") for i
in range(self
.n_adr
))
43 addr_en_r
= Signal(self
.n_adr
)
45 # copy in addresses (and "enable" signals)
46 for i
in range(self
.n_adr
):
47 with m
.If(self
.addr_we_i
[i
]):
48 sync
+= addrs_r
[i
].eq(self
.addrs_i
[i
])
49 sync
+= addr_en_r
[i
].eq(self
.addr_en_i
[i
])
51 # is there a clash, yes/no
52 for i
in range(self
.n_adr
):
54 for j
in range(self
.n_adr
):
56 match
.append(Const(0)) # don't match against self!
58 match
.append(addrs_r
[i
] == addrs_r
[j
])
59 comb
+= self
.addr_match_o
.eq(Cat(*match
).bool() & addr_en_r
)
64 yield from self
.addrs_i
67 yield self
.addr_match_o
73 def part_addr_sim(dut
):
74 yield dut
.dest_i
.eq(1)
75 yield dut
.issue_i
.eq(1)
77 yield dut
.issue_i
.eq(0)
79 yield dut
.src1_i
.eq(1)
80 yield dut
.issue_i
.eq(1)
82 yield dut
.issue_i
.eq(0)
84 yield dut
.go_rd_i
.eq(1)
86 yield dut
.go_rd_i
.eq(0)
88 yield dut
.go_wr_i
.eq(1)
90 yield dut
.go_wr_i
.eq(0)
94 dut
= PartialAddrMatch(3, 10)
95 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
96 with
open("test_part_addr.il", "w") as f
:
99 run_simulation(dut
, part_addr_sim(dut
), vcd_name
='test_part_addr.vcd')
101 if __name__
== '__main__':