start putting LDSTSplitter together
[soc.git] / src / soc / scoreboard / addr_split.py
1 # LDST Address Splitter. For misaligned address crossing cache line boundary
2
3 from nmigen import Elaboratable, Module, Signal, Record, Array
4 from nmutil.latch import SRLatch, latchregister
5 from nmigen.compat.sim import run_simulation
6 from nmigen.cli import verilog, rtlil
7
8 from soc.scoreboard.addr_match import LenExpand
9 #from nmutil.queue import Queue
10
11 class LDData(Record):
12 def __init__(self, dwidth):
13 Record.__init__(self, (('err', 1), ('data', dwidth)))
14
15
16 class LDLatch(Elaboratable):
17
18 def __init__(self, dwidth, awidth, mlen):
19 self.addr_i = Signal(awidth, reset_less=True)
20 self.mask_i = Signal(mlen, reset_less=True)
21 self.valid_i = Signal(reset_less=True)
22 self.ld_i = LDData(dwidth)
23 self.ld_o = LDData(dwidth)
24 self.valid_o = Signal(reset_less=True)
25
26 def elaborate(self, platform):
27 m = Module()
28 comb = m.d.comb
29 m.submodules.in_l = in_l = SRLatch(sync=False, name="in_l")
30
31 comb += self.valid_o.eq(in_l.q & self.valid_i)
32 latchregister(m, self.ld_i, self.ld_o, in_l.q & self.valid_o, "ld_i_r")
33
34 return m
35
36
37 class LDSTSplitter(Elaboratable):
38
39 def __init__(self, dwidth, awidth, dlen):
40 self.dwidth, self.awidth, self.dlen = dwidth, awidth, dlen
41 self.addr_i = Signal(awidth, reset_less=True)
42 self.len_i = Signal(dlen, reset_less=True)
43 self.is_ld_i = Signal(reset_less=True)
44 self.ld_data_o = LDData(dwidth)
45 self.ld_valid_i = Signal(reset_less=True)
46 self.valid_o = Signal(2, reset_less=True)
47 self.ld_data_i = Array((LDData(dwidth), LDData(dwidth)))
48
49 #self.is_st_i = Signal(reset_less=True)
50 #self.st_data_i = Signal(dwidth, reset_less=True)
51
52 def elaborate(self, platform):
53 m = Module()
54 comb = m.d.comb
55 dlen = self.dlen
56 mlen = 1 << dlen
57 m.submodules.ld1 = ld1 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
58 m.submodules.ld2 = ld2 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
59 m.submodules.lenexp = lenexp = LenExpand(self.dlen)
60
61 # set up len-expander, len to mask. ld1 gets first bit, ld2 gets rest
62 comb += lenexp.addr_i.eq(self.addr_i)
63 comb += lenexp.len_i.eq(self.len_i)
64 mask1 = lenexp.lexp_o[0:mlen]
65 mask2 = lenexp.lexp_o[mlen:]
66
67 # set up new address records: addr1 is "as-is", addr2 is +1
68 comb += ld1.addr_i.eq(self.addr_i[dlen:])
69 comb += ld2.addr_i.eq(self.addr_i[dlen:] + 1) # TODO exception if rolls
70
71 # set up connections to LD-split. note: not active if mask is zero
72 for i, (ld, mask) in enumerate(((ld1, mask1),
73 (ld2, mask2))):
74 comb += ld.valid_i.eq(self.ld_valid_i)
75 comb += self.valid_o[i].eq(ld.valid_o & (mask != 0))
76
77 return m
78
79 def __iter__(self):
80 yield self.addr_i
81 yield self.len_i
82 yield self.is_ld_i
83 yield self.ld_data_o.err
84 yield self.ld_data_o.data
85 yield self.ld_valid_i
86 yield self.valid_o
87 for i in range(2):
88 yield self.ld_data_i[i].err
89 yield self.ld_data_i[i].data
90
91 def ports(self):
92 return list(self)
93
94
95 if __name__ == '__main__':
96 dut = LDSTSplitter(32, 48, 3)
97 vl = rtlil.convert(dut, ports=dut.ports())
98 with open("ldst_splitter.il", "w") as f:
99 f.write(vl)
100