1 # LDST Address Splitter. For misaligned address crossing cache line boundary
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
8 from soc
.scoreboard
.addr_match
import LenExpand
9 #from nmutil.queue import Queue
12 def __init__(self
, dwidth
, name
=None):
13 Record
.__init
__(self
, (('err', 1), ('data', dwidth
)), name
=name
)
16 class LDLatch(Elaboratable
):
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)
26 def elaborate(self
, platform
):
29 m
.submodules
.in_l
= in_l
= SRLatch(sync
=False, name
="in_l")
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")
50 class LDSTSplitter(Elaboratable
):
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")))
65 #self.is_st_i = Signal(reset_less=True)
66 #self.st_data_i = Signal(dwidth, reset_less=True)
68 def elaborate(self
, platform
):
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
)
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
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
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
),
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
)
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])
103 comb
+= self
.valid_o
.eq(self
.sld_valid_o
.all())
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
)))
122 yield self
.ld_data_o
.err
123 yield self
.ld_data_o
.data
124 yield self
.ld_valid_i
126 yield self
.sld_valid_i
128 yield self
.sld_data_i
[i
].err
129 yield self
.sld_data_i
[i
].data
138 data
= 0b1101001110110010011
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
))
153 yield dut
.len_i
.eq(ld_len
)
154 yield dut
.addr_i
.eq(addr
)
155 yield dut
.ld_valid_i
.eq(1)
158 valid_o
= yield dut
.valid_o
162 ld_data_o
= yield dut
.ld_data_o
166 assert ld_data_o
== data
171 valid_i
= yield dut
.ld_valid_i
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)
183 yield dut
.sld_data_i
[1].eq(data2
)
184 yield dut
.sld_valid_i
[1].eq(1)
187 sim
.add_sync_process(lds
)
188 sim
.add_sync_process(send_in
)
190 prefix
= "ldst_splitter"
191 with sim
.write_vcd("%s.vcd" % prefix
, traces
=dut
.ports()):
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
: