1 """PortInterface to LoadStoreUnitInterface adapter
3 PortInterface LoadStoreUnitInterface
4 ------------- ----------------------
9 data_len/4 x_mask/16 (translate using LenExpand)
11 busy_o/1 most likely to be x_busy_o
13 addr.data/64 x_addr_i (x_addr_i[:4] goes into LenExpand)
14 addr.ok/1 probably x_i_valid & ~x_stall_i
16 addr_ok_o/1 no equivalent. *might* work using x_stall_i
17 exc_o/6(?) m_load_err_o and m_store_err_o
19 ld.data/64 m_ld_data_o
20 ld.ok/1 probably implicit, when x_busy drops low
21 st.data/64 x_st_data_i
22 st.ok/1 probably kinda redundant, set to x_st_i
25 from soc
.minerva
.units
.loadstore
import LoadStoreUnitInterface
26 from soc
.experiment
.pimem
import PortInterface
27 from soc
.scoreboard
.addr_match
import LenExpand
28 from soc
.experiment
.pimem
import PortInterfaceBase
29 from nmigen
.utils
import log2_int
31 from nmigen
import Elaboratable
, Module
, Signal
32 from nmutil
.latch
import SRLatch
33 from nmutil
.util
import rising_edge
37 class Pi2LSUI(PortInterfaceBase
):
39 def __init__(self
, name
, lsui
=None,
40 data_wid
=64, mask_wid
=8, addr_wid
=64):
41 print("pi2lsui reg mask addr", data_wid
, mask_wid
, addr_wid
)
42 super().__init
__(data_wid
, addr_wid
)
44 lsui
= LoadStoreUnitInterface(addr_wid
, self
.addrbits
, data_wid
)
46 self
.lsui_busy
= Signal()
47 self
.valid_l
= SRLatch(False, name
="valid")
49 def set_wr_addr(self
, m
, addr
, mask
, misalign
, msr
, is_dcbz
, is_nc
):
50 print("pi2lsui TODO, implement is_dcbz")
51 m
.d
.comb
+= self
.valid_l
.s
.eq(1)
52 m
.d
.comb
+= self
.lsui
.x_mask_i
.eq(mask
)
53 m
.d
.comb
+= self
.lsui
.x_addr_i
.eq(addr
)
55 def set_rd_addr(self
, m
, addr
, mask
, misalign
, msr
, is_nc
):
56 m
.d
.comb
+= self
.valid_l
.s
.eq(1)
57 m
.d
.comb
+= self
.lsui
.x_mask_i
.eq(mask
)
58 m
.d
.comb
+= self
.lsui
.x_addr_i
.eq(addr
)
60 def set_wr_data(self
, m
, data
, wen
): # mask already done in addr setup
61 m
.d
.comb
+= self
.lsui
.x_st_data_i
.eq(data
)
62 return (~
(self
.lsui
.x_busy_o | self
.lsui_busy
))
64 def get_rd_data(self
, m
):
65 return self
.lsui
.m_ld_data_o
, ~self
.lsui_busy
67 def elaborate(self
, platform
):
68 m
= super().elaborate(platform
)
69 pi
, lsui
, addrbits
= self
.pi
, self
.lsui
, self
.addrbits
71 m
.submodules
.valid_l
= self
.valid_l
72 ld_in_progress
= Signal()
74 # pass ld/st through to LSUI
75 m
.d
.comb
+= lsui
.x_ld_i
.eq(pi
.is_ld_i
)
76 m
.d
.comb
+= lsui
.x_st_i
.eq(pi
.is_st_i
)
78 # ooo how annoying. x_busy_o is set synchronously, i.e. one
79 # clock too late for this converter to "notice". consequently,
80 # when trying to wait for ld/st, here: on the first cycle
81 # it goes "oh, x_busy_o isn't set, the ld/st must have been
82 # completed already, we must be done" when in fact it hasn't
83 # started. to "fix" that we actually have to have a full FSM
84 # tracking from when LD/ST starts, right the way through. sigh.
85 # first clock busy signal. needed because x_busy_o is sync
88 # detect when ld/st starts. set busy *immediately*
89 with m
.If((pi
.is_ld_i | pi
.is_st_i
) & self
.valid_l
.q
):
90 m
.d
.comb
+= self
.lsui_busy
.eq(1)
93 # detect when busy drops: must then wait for ld/st to end..
94 #m.d.comb += self.lsui_busy.eq(self.lsui.x_busy_o)
95 m
.d
.comb
+= self
.lsui_busy
.eq(1)
96 with m
.If(~self
.lsui
.x_busy_o
):
97 m
.next
= "WAITDEASSERT"
98 with m
.State("WAITDEASSERT"):
99 # when no longer busy: back to start
100 with m
.If(~pi
.is_st_i
& ~pi
.busy_o
):
103 # indicate valid at both ends. OR with lsui_busy (stops comb loop)
104 m
.d
.comb
+= self
.lsui
.m_i_valid
.eq(self
.valid_l
.q
)
105 m
.d
.comb
+= self
.lsui
.x_i_valid
.eq(self
.valid_l
.q
)
107 # reset the valid latch when not busy. sync to stop loop
108 lsui_active
= Signal()
109 m
.d
.comb
+= lsui_active
.eq(~self
.lsui
.x_busy_o
)
110 m
.d
.comb
+= self
.valid_l
.r
.eq(rising_edge(m
, lsui_active
))
115 class Pi2LSUI1(Elaboratable
):
117 def __init__(self
, name
, pi
=None, lsui
=None,
118 data_wid
=64, mask_wid
=8, addr_wid
=64):
119 print("pi2lsui reg mask addr", data_wid
, mask_wid
, addr_wid
)
120 self
.addrbits
= mask_wid
122 piname
= "%s_pi" % name
123 pi
= PortInterface(piname
, regwid
=data_wid
, addrwid
=addr_wid
)
126 lsui
= LoadStoreUnitInterface(addr_wid
, self
.addrbits
, data_wid
)
129 def splitaddr(self
, addr
):
130 """split the address into top and bottom bits of the memory granularity
132 return addr
[:self
.addrbits
], addr
[self
.addrbits
:]
134 def connect_port(self
, inport
):
135 return self
.pi
.connect_port(inport
)
137 def elaborate(self
, platform
):
139 pi
, lsui
, addrbits
= self
.pi
, self
.lsui
, self
.addrbits
140 m
.submodules
.lenexp
= lenexp
= LenExpand(log2_int(self
.addrbits
), 8)
142 ld_in_progress
= Signal(reset
=0)
143 st_in_progress
= Signal(reset
=0)
145 m
.d
.comb
+= lsui
.x_ld_i
.eq(pi
.is_ld_i
)
146 m
.d
.comb
+= lsui
.x_st_i
.eq(pi
.is_st_i
)
147 m
.d
.comb
+= pi
.busy_o
.eq(pi
.is_ld_i | pi
.is_st_i
) # lsui.x_busy_o)
149 lsbaddr
, msbaddr
= self
.splitaddr(pi
.addr
.data
)
150 m
.d
.comb
+= lenexp
.len_i
.eq(pi
.data_len
)
151 m
.d
.comb
+= lenexp
.addr_i
.eq(lsbaddr
) # LSBs of addr
152 m
.d
.comb
+= lsui
.x_addr_i
.eq(pi
.addr
.data
) # XXX hmmm...
154 with m
.If(pi
.addr
.ok
):
155 # expand the LSBs of address plus LD/ST len into 16-bit mask
156 m
.d
.comb
+= lsui
.x_mask_i
.eq(lenexp
.lexp_o
)
157 # pass through the address, indicate "valid"
158 m
.d
.comb
+= lsui
.x_i_valid
.eq(1)
159 # indicate "OK" - XXX should be checking address valid
160 m
.d
.comb
+= pi
.addr_ok_o
.eq(1)
162 with m
.If(~lsui
.x_busy_o
& pi
.is_st_i
& pi
.addr
.ok
):
163 m
.d
.sync
+= st_in_progress
.eq(1)
165 with m
.If(pi
.is_ld_i
):
166 # shift/mask out the loaded data
167 m
.d
.comb
+= pi
.ld
.data
.eq((lsui
.m_ld_data_o
& lenexp
.rexp_o
) >>
169 # remember we're in the process of loading
170 with m
.If(pi
.addr
.ok
):
171 m
.d
.sync
+= ld_in_progress
.eq(1)
173 # If a load happened on the previous cycle and the memory is
174 # not busy, that means it returned the data from the load. In
175 # that case ld.ok should be set andwe can clear the
176 # ld_in_progress flag
177 with m
.If(ld_in_progress
& ~lsui
.x_busy_o
):
178 m
.d
.comb
+= pi
.ld
.ok
.eq(1)
179 m
.d
.sync
+= ld_in_progress
.eq(0)
181 m
.d
.comb
+= pi
.ld
.ok
.eq(0)
183 with m
.If(pi
.is_st_i
& pi
.st
.ok
):
184 m
.d
.comb
+= lsui
.x_st_data_i
.eq(pi
.st
.data
<< (lenexp
.addr_i
*8))
185 with m
.If(st_in_progress
):
186 m
.d
.sync
+= st_in_progress
.eq(0)
188 m
.d
.comb
+= pi
.busy_o
.eq(0)