e004c3c443afaabf5f2fa36e3d0d4693a1a7c8da
1 from nmigen
import (Elaboratable
, Module
, Signal
, Shape
, unsigned
, Cat
, Mux
,
4 from nmutil
.util
import rising_edge
5 from enum
import Enum
, unique
7 from soc
.experiment
.dcache
import DCache
8 from soc
.experiment
.pimem
import PortInterfaceBase
9 from soc
.experiment
.mem_types
import LoadStore1ToMMUType
10 from soc
.experiment
.mem_types
import MMUToLoadStore1Type
12 from soc
.minerva
.wishbone
import make_wb_layout
13 from soc
.bus
.sram
import SRAM
18 IDLE
= 0 # ready for instruction
19 SECOND_REQ
= 1 # send 2nd request of unaligned xfer
20 ACK_WAIT
= 2 # waiting for ack from dcache
21 MMU_LOOKUP
= 3 # waiting for MMU to look up translation
22 TLBIE_WAIT
= 4 # waiting for MMU to finish doing a tlbie
23 FINISH_LFS
= 5 # write back converted SP data for lfs*
24 COMPLETE
= 6 # extra cycle to complete an operation
27 # glue logic for microwatt mmu and dcache
28 class LoadStore1(PortInterfaceBase
):
29 def __init__(self
, pspec
):
31 self
.disable_cache
= (hasattr(pspec
, "disable_cache") and
32 pspec
.disable_cache
== True)
33 regwid
= pspec
.reg_wid
34 addrwid
= pspec
.addr_wid
36 super().__init
__(regwid
, addrwid
)
37 self
.dcache
= DCache()
38 self
.d_in
= self
.dcache
.d_in
39 self
.d_out
= self
.dcache
.d_out
40 self
.l_in
= LoadStore1ToMMUType()
41 self
.l_out
= MMUToLoadStore1Type()
43 self
.mmureq
= Signal()
44 self
.derror
= Signal()
46 # TODO, convert dcache wb_in/wb_out to "standard" nmigen Wishbone bus
47 self
.dbus
= Record(make_wb_layout(pspec
))
49 # for creating a single clock blip to DCache
50 self
.d_valid
= Signal()
51 self
.d_w_data
= Signal(64) # XXX
52 self
.d_w_valid
= Signal()
53 self
.d_validblip
= Signal()
55 # DSISR and DAR cached values. note that the MMU FSM is where
56 # these are accessed by OP_MTSPR/OP_MFSPR, on behalf of LoadStore1.
57 # by contrast microwatt has the spr set/get done *in* loadstore1.vhdl
58 self
.dsisr
= Signal(64)
61 # state info for LD/ST
63 # latch most of the input request
67 self
.addr
= Signal(64)
68 self
.store_data
= Signal(64)
69 self
.load_data
= Signal(64)
70 self
.byte_sel
= Signal(8)
71 self
.update
= Signal()
72 #self.xerc : xer_common_t;
73 #self.reserve = Signal()
74 #self.atomic = Signal()
75 #self.atomic_last = Signal()
77 self
.nc
= Signal() # non-cacheable access
78 self
.virt_mode
= Signal()
79 self
.priv_mode
= Signal()
80 self
.state
= Signal(State
)
81 self
.instr_fault
= Signal()
82 self
.align_intr
= Signal()
84 self
.wait_dcache
= Signal()
85 self
.wait_mmu
= Signal()
86 #self.mode_32bit = Signal()
87 self
.wr_sel
= Signal(2)
88 self
.interrupt
= Signal()
89 #self.intr_vec : integer range 0 to 16#fff#;
90 #self.nia = Signal(64)
91 #self.srr1 = Signal(16)
93 def set_wr_addr(self
, m
, addr
, mask
):
94 m
.d
.comb
+= self
.load
.eq(0) # store operation
96 m
.d
.comb
+= self
.d_in
.load
.eq(0)
97 m
.d
.comb
+= self
.byte_sel
.eq(mask
)
98 m
.d
.comb
+= self
.addr
.eq(addr
)
99 # option to disable the cache entirely for write
100 if self
.disable_cache
:
101 m
.d
.comb
+= self
.nc
.eq(1)
104 def set_rd_addr(self
, m
, addr
, mask
):
105 m
.d
.comb
+= self
.d_valid
.eq(1)
106 m
.d
.comb
+= self
.d_in
.valid
.eq(self
.d_validblip
)
107 m
.d
.comb
+= self
.load
.eq(1) # load operation
108 m
.d
.comb
+= self
.d_in
.load
.eq(1)
109 m
.d
.comb
+= self
.byte_sel
.eq(mask
)
110 m
.d
.comb
+= self
.addr
.eq(addr
)
111 # BAD HACK! disable cacheing on LD when address is 0xCxxx_xxxx
112 # this is for peripherals. same thing done in Microwatt loadstore1.vhdl
113 with m
.If(addr
[28:] == Const(0xc, 4)):
114 m
.d
.comb
+= self
.nc
.eq(1)
115 # option to disable the cache entirely for read
116 if self
.disable_cache
:
117 m
.d
.comb
+= self
.nc
.eq(1)
118 return None #FIXME return value
120 def set_wr_data(self
, m
, data
, wen
):
121 # do the "blip" on write data
122 m
.d
.comb
+= self
.d_valid
.eq(1)
123 m
.d
.comb
+= self
.d_in
.valid
.eq(self
.d_validblip
)
124 # put data into comb which is picked up in main elaborate()
125 m
.d
.comb
+= self
.d_w_valid
.eq(1)
126 m
.d
.comb
+= self
.d_w_data
.eq(data
)
127 #m.d.sync += self.d_in.byte_sel.eq(wen) # this might not be needed
128 st_ok
= self
.done
# TODO indicates write data is valid
132 def get_rd_data(self
, m
):
133 ld_ok
= self
.done
# indicates read data is valid
134 data
= self
.d_out
.data
# actual read data
138 if d_in.error = '1' then
139 if d_in.cache_paradox = '1' then
140 -- signal an interrupt straight away
142 dsisr(63 - 38) := not r2.req.load;
143 -- XXX there is no architected bit for this
144 -- (probably should be a machine check in fact)
145 dsisr(63 - 35) := d_in.cache_paradox;
147 -- Look up the translation for TLB miss
148 -- and also for permission error and RC error
149 -- in case the PTE has been updated.
151 v.state := MMU_LOOKUP;
157 def elaborate(self
, platform
):
158 m
= super().elaborate(platform
)
161 # create dcache module
162 m
.submodules
.dcache
= dcache
= self
.dcache
165 d_out
, l_out
, dbus
= self
.d_out
, self
.l_out
, self
.dbus
167 with m
.If(d_out
.error
):
168 with m
.If(d_out
.cache_paradox
):
169 comb
+= self
.derror
.eq(1)
171 sync += self.dsisr[63 - 38].eq(~r2.req.load)
172 # -- XXX there is no architected bit for this
173 # -- (probably should be a machine check in fact)
174 sync += self.dsisr[63 - 35].eq(d_in.cache_paradox)
177 # Look up the translation for TLB miss
178 # and also for permission error and RC error
179 # in case the PTE has been updated.
180 comb
+= self
.mmureq
.eq(1)
181 # v.state := MMU_LOOKUP;
182 # v.stage1_en := '0';
186 #happened, alignment, instr_fault, invalid,
187 comb
+= exc
.happened
.eq(d_out
.error | l_out
.err
)
188 comb
+= exc
.invalid
.eq(l_out
.invalid
)
190 #badtree, perm_error, rc_error, segment_fault
191 comb
+= exc
.badtree
.eq(l_out
.badtree
)
192 comb
+= exc
.perm_error
.eq(l_out
.perm_error
)
193 comb
+= exc
.rc_error
.eq(l_out
.rc_error
)
194 comb
+= exc
.segment_fault
.eq(l_out
.segerr
)
196 # TODO connect those signals somewhere
197 #print(d_out.valid) -> no error
198 #print(d_out.store_done) -> no error
199 #print(d_out.cache_paradox) -> ?
200 #print(l_out.done) -> no error
202 # TODO some exceptions set SPRs
204 # TODO, connect dcache wb_in/wb_out to "standard" nmigen Wishbone bus
205 comb
+= dbus
.adr
.eq(dcache
.wb_out
.adr
)
206 comb
+= dbus
.dat_w
.eq(dcache
.wb_out
.dat
)
207 comb
+= dbus
.sel
.eq(dcache
.wb_out
.sel
)
208 comb
+= dbus
.cyc
.eq(dcache
.wb_out
.cyc
)
209 comb
+= dbus
.stb
.eq(dcache
.wb_out
.stb
)
210 comb
+= dbus
.we
.eq(dcache
.wb_out
.we
)
212 comb
+= dcache
.wb_in
.dat
.eq(dbus
.dat_r
)
213 comb
+= dcache
.wb_in
.ack
.eq(dbus
.ack
)
214 if hasattr(dbus
, "stall"):
215 comb
+= dcache
.wb_in
.stall
.eq(dbus
.stall
)
217 # create a blip (single pulse) on valid read/write request
218 m
.d
.comb
+= self
.d_validblip
.eq(rising_edge(m
, self
.d_valid
))
220 # write out d data only when flag set
221 with m
.If(self
.d_w_valid
):
222 m
.d
.sync
+= self
.d_in
.data
.eq(self
.d_w_data
)
224 m
.d
.sync
+= self
.d_in
.data
.eq(0)
226 m
.d
.comb
+= self
.d_in
.load
.eq(self
.load
)
227 m
.d
.comb
+= self
.d_in
.byte_sel
.eq(self
.byte_sel
)
228 m
.d
.comb
+= self
.d_in
.addr
.eq(self
.addr
)
229 m
.d
.comb
+= self
.d_in
.nc
.eq(self
.nc
)
230 m
.d
.comb
+= self
.done
.eq(self
.d_out
.valid
)
235 yield from super().ports()
239 class TestSRAMLoadStore1(LoadStore1
):
240 def __init__(self
, pspec
):
241 super().__init
__(pspec
)
243 # small 32-entry Memory
244 if (hasattr(pspec
, "dmem_test_depth") and
245 isinstance(pspec
.dmem_test_depth
, int)):
246 depth
= pspec
.dmem_test_depth
249 print("TestSRAMBareLoadStoreUnit depth", depth
)
251 self
.mem
= Memory(width
=pspec
.reg_wid
, depth
=depth
)
253 def elaborate(self
, platform
):
254 m
= super().elaborate(platform
)
256 m
.submodules
.sram
= sram
= SRAM(memory
=self
.mem
, granularity
=8,
257 features
={'cti', 'bte', 'err'})
260 # directly connect the wishbone bus of LoadStoreUnitInterface to SRAM
261 # note: SRAM is a target (slave), dbus is initiator (master)
262 fanouts
= ['dat_w', 'sel', 'cyc', 'stb', 'we', 'cti', 'bte']
263 fanins
= ['dat_r', 'ack', 'err']
264 for fanout
in fanouts
:
265 print("fanout", fanout
, getattr(sram
.bus
, fanout
).shape(),
266 getattr(dbus
, fanout
).shape())
267 comb
+= getattr(sram
.bus
, fanout
).eq(getattr(dbus
, fanout
))
268 comb
+= getattr(sram
.bus
, fanout
).eq(getattr(dbus
, fanout
))
270 comb
+= getattr(dbus
, fanin
).eq(getattr(sram
.bus
, fanin
))
272 comb
+= sram
.bus
.adr
.eq(dbus
.adr
)