working on simulation to test Address Splitter
[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, Const
4 from nmutil.latch import SRLatch, latchregister
5 from nmigen.back.pysim import Simulator, Delay
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, name=None):
13 Record.__init__(self, (('err', 1), ('data', dwidth)), name=name)
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, "ld_i")
23 self.ld_o = LDData(dwidth, "ld_o")
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 += in_l.s.eq(self.valid_i)
32 comb += self.valid_o.eq(in_l.q & self.valid_i)
33 latchregister(m, self.ld_i, self.ld_o, in_l.q & self.valid_o, "ld_i_r")
34
35 return m
36
37 def __iter__(self):
38 yield self.addr_i
39 yield self.mask_i
40 yield self.ld_i.err
41 yield self.ld_i.data
42 yield self.ld_o.err
43 yield self.ld_o.data
44 yield self.valid_i
45 yield self.valid_o
46
47 def ports(self):
48 return list(self)
49
50 class LDSTSplitter(Elaboratable):
51
52 def __init__(self, dwidth, awidth, dlen):
53 self.dwidth, self.awidth, self.dlen = dwidth, awidth, dlen
54 self.addr_i = Signal(awidth, reset_less=True)
55 self.len_i = Signal(dlen, reset_less=True)
56 self.is_ld_i = Signal(reset_less=True)
57 self.ld_data_o = LDData(dwidth, "ld_data_o")
58 self.ld_valid_i = Signal(reset_less=True)
59 self.valid_o = Signal(reset_less=True)
60 self.sld_valid_o = Signal(2, reset_less=True)
61 self.sld_valid_i = Signal(2, reset_less=True)
62 self.sld_data_i = Array((LDData(dwidth, "ld_data_i1"),
63 LDData(dwidth, "ld_data_i2")))
64
65 #self.is_st_i = Signal(reset_less=True)
66 #self.st_data_i = Signal(dwidth, reset_less=True)
67
68 def elaborate(self, platform):
69 m = Module()
70 comb = m.d.comb
71 dlen = self.dlen
72 mlen = 1 << dlen
73 m.submodules.ld1 = ld1 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
74 m.submodules.ld2 = ld2 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
75 m.submodules.lenexp = lenexp = LenExpand(self.dlen)
76
77 # set up len-expander, len to mask. ld1 gets first bit, ld2 gets rest
78 comb += lenexp.addr_i.eq(self.addr_i)
79 comb += lenexp.len_i.eq(self.len_i)
80 mask1 = Signal(mlen, reset_less=True)
81 mask2 = Signal(mlen, reset_less=True)
82 comb += mask1.eq(lenexp.lexp_o[0:mlen]) # Lo bits of expanded len-mask
83 comb += mask2.eq(lenexp.lexp_o[mlen:]) # Hi bits of expanded len-mask
84
85 # set up new address records: addr1 is "as-is", addr2 is +1
86 comb += ld1.addr_i.eq(self.addr_i[dlen:])
87 comb += ld2.addr_i.eq(self.addr_i[dlen:] + 1) # TODO exception if rolls
88
89 # set up connections to LD-split. note: not active if mask is zero
90 mzero = Const(0, mlen)
91 for i, (ld, mask) in enumerate(((ld1, mask1),
92 (ld2, mask2))):
93 ld_valid = Signal(name="ldvalid_i%d" % i, reset_less=True)
94 comb += ld_valid.eq(self.ld_valid_i & self.sld_valid_i[i])
95 comb += ld.valid_i.eq(ld_valid & (mask != mzero))
96 comb += ld.ld_i.eq(self.sld_data_i[i])
97 comb += self.sld_valid_o[i].eq(ld.valid_o)
98
99 # sort out valid: mask2 zero we ignore 2nd LD
100 with m.If(mask2 == mzero):
101 comb += self.valid_o.eq(self.sld_valid_o[0])
102 with m.Else():
103 comb += self.valid_o.eq(self.sld_valid_o.all())
104
105 # all bits valid (including when a data error occurs!) decode ld1/ld2
106 with m.If(self.valid_o):
107 # errors cause error condition
108 comb += self.ld_data_o.err.eq(ld1.ld_o.err | ld2.ld_o.err)
109 # data needs recombining via shifting.
110 ashift1 = self.addr_i[:self.dlen]
111 # note that data from LD1 will be in *cache-line* byte position
112 # likewise from LD2 but we *know* it is at the start of the line
113 comb += self.ld_data_o.data.eq((ld1.ld_o.data >> ashift1) |
114 (ld2.ld_o.data << (1<<self.dlen)))
115
116 return m
117
118 def __iter__(self):
119 yield self.addr_i
120 yield self.len_i
121 yield self.is_ld_i
122 yield self.ld_data_o.err
123 yield self.ld_data_o.data
124 yield self.ld_valid_i
125 yield self.valid_o
126 yield self.sld_valid_i
127 for i in range(2):
128 yield self.sld_data_i[i].err
129 yield self.sld_data_i[i].data
130
131 def ports(self):
132 return list(self)
133
134 def sim(dut):
135
136 sim = Simulator(dut)
137 sim.add_clock(1e-6)
138 data = 0b1101001110110010011
139 dlen = 4 # 4 bits
140 addr = 0b1101
141 ld_len = 8
142 dlm = ((1<<dlen)-1)
143 print ("dlm", dlm, bin(addr&dlm))
144 dmask = ((1<<ld_len)-1) << (addr & dlm)
145 print ("dmask", bin(dmask))
146 dmask1 = dmask >> (1<<dlen)
147 print ("dmask1", bin(dmask1))
148 dmask = dmask & ((1<<(1<<dlen))-1)
149 print ("dmask", bin(dmask))
150
151 def send_in():
152 print ("send_in")
153 yield dut.len_i.eq(ld_len)
154 yield dut.addr_i.eq(addr)
155 yield dut.ld_valid_i.eq(1)
156 print ("waiting")
157 while True:
158 valid_o = yield dut.valid_o
159 if valid_o:
160 break
161 yield
162 ld_data_o = yield dut.ld_data_o
163 yield
164
165 print (ld_data_o)
166 assert ld_data_o == data
167
168 def lds():
169 print ("lds")
170 while True:
171 valid_i = yield dut.ld_valid_i
172 if valid_i:
173 break
174 yield
175
176 data1 = (data & dmask) << (addr & dlm)
177 data2 = ((data >> (1<<dlen)) & dmask1)
178 print ("ld data", bin(data), bin(data1), bin(data2))
179 yield dut.sld_data_i[0].eq(data1)
180 yield dut.sld_valid_i[0].eq(1)
181 yield
182 yield
183 yield dut.sld_data_i[1].eq(data2)
184 yield dut.sld_valid_i[1].eq(1)
185 yield
186
187 sim.add_sync_process(lds)
188 sim.add_sync_process(send_in)
189
190 prefix = "ldst_splitter"
191 with sim.write_vcd("%s.vcd" % prefix, traces=dut.ports()):
192 sim.run()
193
194
195 if __name__ == '__main__':
196 dut = LDSTSplitter(32, 48, 4)
197 vl = rtlil.convert(dut, ports=dut.ports())
198 with open("ldst_splitter.il", "w") as f:
199 f.write(vl)
200
201 sim(dut)