Wait one clock after SoC reset drops to start cache access
[soc.git] / src / soc / simple / issuer.py
1 """simple core issuer
2
3 not in any way intended for production use. this runs a FSM that:
4
5 * reads the Program Counter from StateRegs
6 * reads an instruction from a fixed-size Test Memory
7 * issues it to the Simple Core
8 * waits for it to complete
9 * increments the PC
10 * does it all over again
11
12 the purpose of this module is to verify the functional correctness
13 of the Function Units in the absolute simplest and clearest possible
14 way, and to at provide something that can be further incrementally
15 improved.
16 """
17
18 from nmigen import (Elaboratable, Module, Signal, ClockSignal, ResetSignal,
19 ClockDomain, DomainRenamer, Mux, Const, Repl, Cat)
20 from nmigen.cli import rtlil
21 from nmigen.cli import main
22 import sys
23
24 from nmutil.singlepipe import ControlBase
25 from soc.simple.core_data import FetchOutput, FetchInput
26
27 from nmigen.lib.coding import PriorityEncoder
28
29 from openpower.decoder.power_decoder import create_pdecode
30 from openpower.decoder.power_decoder2 import PowerDecode2, SVP64PrefixDecoder
31 from openpower.decoder.decode2execute1 import IssuerDecode2ToOperand
32 from openpower.decoder.decode2execute1 import Data
33 from openpower.decoder.power_enums import (MicrOp, SVP64PredInt, SVP64PredCR,
34 SVP64PredMode)
35 from openpower.state import CoreState
36 from openpower.consts import (CR, SVP64CROffs, MSR)
37 from soc.experiment.testmem import TestMemory # test only for instructions
38 from soc.regfile.regfiles import StateRegs, FastRegs
39 from soc.simple.core import NonProductionCore
40 from soc.config.test.test_loadstore import TestMemPspec
41 from soc.config.ifetch import ConfigFetchUnit
42 from soc.debug.dmi import CoreDebug, DMIInterface
43 from soc.debug.jtag import JTAG
44 from soc.config.pinouts import get_pinspecs
45 from soc.interrupts.xics import XICS_ICP, XICS_ICS
46 from soc.bus.simple_gpio import SimpleGPIO
47 from soc.bus.SPBlock512W64B8W import SPBlock512W64B8W
48 from soc.clock.select import ClockSelect
49 from soc.clock.dummypll import DummyPLL
50 from openpower.sv.svstate import SVSTATERec
51 from soc.experiment.icache import ICache
52
53 from nmutil.util import rising_edge
54
55
56 def get_insn(f_instr_o, pc):
57 if f_instr_o.width == 32:
58 return f_instr_o
59 else:
60 # 64-bit: bit 2 of pc decides which word to select
61 return f_instr_o.word_select(pc[2], 32)
62
63 # gets state input or reads from state regfile
64
65
66 def state_get(m, res, core_rst, state_i, name, regfile, regnum):
67 comb = m.d.comb
68 sync = m.d.sync
69 # read the {insert state variable here}
70 res_ok_delay = Signal(name="%s_ok_delay" % name)
71 with m.If(~core_rst):
72 sync += res_ok_delay.eq(~state_i.ok)
73 with m.If(state_i.ok):
74 # incoming override (start from pc_i)
75 comb += res.eq(state_i.data)
76 with m.Else():
77 # otherwise read StateRegs regfile for {insert state here}...
78 comb += regfile.ren.eq(1 << regnum)
79 # ... but on a 1-clock delay
80 with m.If(res_ok_delay):
81 comb += res.eq(regfile.o_data)
82
83
84 def get_predint(m, mask, name):
85 """decode SVP64 predicate integer mask field to reg number and invert
86 this is identical to the equivalent function in ISACaller except that
87 it doesn't read the INT directly, it just decodes "what needs to be done"
88 i.e. which INT reg, whether it is shifted and whether it is bit-inverted.
89
90 * all1s is set to indicate that no mask is to be applied.
91 * regread indicates the GPR register number to be read
92 * invert is set to indicate that the register value is to be inverted
93 * unary indicates that the contents of the register is to be shifted 1<<r3
94 """
95 comb = m.d.comb
96 regread = Signal(5, name=name+"regread")
97 invert = Signal(name=name+"invert")
98 unary = Signal(name=name+"unary")
99 all1s = Signal(name=name+"all1s")
100 with m.Switch(mask):
101 with m.Case(SVP64PredInt.ALWAYS.value):
102 comb += all1s.eq(1) # use 0b1111 (all ones)
103 with m.Case(SVP64PredInt.R3_UNARY.value):
104 comb += regread.eq(3)
105 comb += unary.eq(1) # 1<<r3 - shift r3 (single bit)
106 with m.Case(SVP64PredInt.R3.value):
107 comb += regread.eq(3)
108 with m.Case(SVP64PredInt.R3_N.value):
109 comb += regread.eq(3)
110 comb += invert.eq(1)
111 with m.Case(SVP64PredInt.R10.value):
112 comb += regread.eq(10)
113 with m.Case(SVP64PredInt.R10_N.value):
114 comb += regread.eq(10)
115 comb += invert.eq(1)
116 with m.Case(SVP64PredInt.R30.value):
117 comb += regread.eq(30)
118 with m.Case(SVP64PredInt.R30_N.value):
119 comb += regread.eq(30)
120 comb += invert.eq(1)
121 return regread, invert, unary, all1s
122
123
124 def get_predcr(m, mask, name):
125 """decode SVP64 predicate CR to reg number field and invert status
126 this is identical to _get_predcr in ISACaller
127 """
128 comb = m.d.comb
129 idx = Signal(2, name=name+"idx")
130 invert = Signal(name=name+"crinvert")
131 with m.Switch(mask):
132 with m.Case(SVP64PredCR.LT.value):
133 comb += idx.eq(CR.LT)
134 comb += invert.eq(0)
135 with m.Case(SVP64PredCR.GE.value):
136 comb += idx.eq(CR.LT)
137 comb += invert.eq(1)
138 with m.Case(SVP64PredCR.GT.value):
139 comb += idx.eq(CR.GT)
140 comb += invert.eq(0)
141 with m.Case(SVP64PredCR.LE.value):
142 comb += idx.eq(CR.GT)
143 comb += invert.eq(1)
144 with m.Case(SVP64PredCR.EQ.value):
145 comb += idx.eq(CR.EQ)
146 comb += invert.eq(0)
147 with m.Case(SVP64PredCR.NE.value):
148 comb += idx.eq(CR.EQ)
149 comb += invert.eq(1)
150 with m.Case(SVP64PredCR.SO.value):
151 comb += idx.eq(CR.SO)
152 comb += invert.eq(0)
153 with m.Case(SVP64PredCR.NS.value):
154 comb += idx.eq(CR.SO)
155 comb += invert.eq(1)
156 return idx, invert
157
158
159 class TestIssuerBase(Elaboratable):
160 """TestIssuerBase - common base class for Issuers
161
162 takes care of power-on reset, peripherals, debug, DEC/TB,
163 and gets PC/MSR/SVSTATE from the State Regfile etc.
164 """
165
166 def __init__(self, pspec):
167
168 # test if microwatt compatibility is to be enabled
169 self.microwatt_compat = (hasattr(pspec, "microwatt_compat") and
170 (pspec.microwatt_compat == True))
171 self.alt_reset = Signal(reset_less=True) # not connected yet (microwatt)
172
173 if self.microwatt_compat:
174 self.microwatt_old = False
175 self.microwatt_debug = True # set to False when using an FPGA
176
177 # test is SVP64 is to be enabled
178 self.svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
179
180 # and if regfiles are reduced
181 self.regreduce_en = (hasattr(pspec, "regreduce") and
182 (pspec.regreduce == True))
183
184 # and if overlap requested
185 self.allow_overlap = (hasattr(pspec, "allow_overlap") and
186 (pspec.allow_overlap == True))
187
188 # and get the core domain
189 self.core_domain = "coresync"
190 if (hasattr(pspec, "core_domain") and
191 isinstance(pspec.core_domain, str)):
192 self.core_domain = pspec.core_domain
193
194 # JTAG interface. add this right at the start because if it's
195 # added it *modifies* the pspec, by adding enable/disable signals
196 # for parts of the rest of the core
197 self.jtag_en = hasattr(pspec, "debug") and pspec.debug == 'jtag'
198 #self.dbg_domain = "sync" # sigh "dbgsunc" too problematic
199 self.dbg_domain = "dbgsync" # domain for DMI/JTAG clock
200 if self.jtag_en:
201 # XXX MUST keep this up-to-date with litex, and
202 # soc-cocotb-sim, and err.. all needs sorting out, argh
203 subset = ['uart',
204 'mtwi',
205 'eint', 'gpio', 'mspi0',
206 # 'mspi1', - disabled for now
207 # 'pwm', 'sd0', - disabled for now
208 'sdr']
209 self.jtag = JTAG(get_pinspecs(subset=subset),
210 domain=self.dbg_domain)
211 # add signals to pspec to enable/disable icache and dcache
212 # (or data and intstruction wishbone if icache/dcache not included)
213 # https://bugs.libre-soc.org/show_bug.cgi?id=520
214 # TODO: do we actually care if these are not domain-synchronised?
215 # honestly probably not.
216 pspec.wb_icache_en = self.jtag.wb_icache_en
217 pspec.wb_dcache_en = self.jtag.wb_dcache_en
218 self.wb_sram_en = self.jtag.wb_sram_en
219 else:
220 self.wb_sram_en = Const(1)
221
222 # add 4k sram blocks?
223 self.sram4x4k = (hasattr(pspec, "sram4x4kblock") and
224 pspec.sram4x4kblock == True)
225 if self.sram4x4k:
226 self.sram4k = []
227 for i in range(4):
228 self.sram4k.append(SPBlock512W64B8W(name="sram4k_%d" % i,
229 # features={'err'}
230 ))
231
232 # add interrupt controller?
233 self.xics = hasattr(pspec, "xics") and pspec.xics == True
234 if self.xics:
235 self.xics_icp = XICS_ICP()
236 self.xics_ics = XICS_ICS()
237 self.int_level_i = self.xics_ics.int_level_i
238 else:
239 self.ext_irq = Signal()
240
241 # add GPIO peripheral?
242 self.gpio = hasattr(pspec, "gpio") and pspec.gpio == True
243 if self.gpio:
244 self.simple_gpio = SimpleGPIO()
245 self.gpio_o = self.simple_gpio.gpio_o
246
247 # main instruction core. suitable for prototyping / demo only
248 self.core = core = NonProductionCore(pspec)
249 self.core_rst = ResetSignal(self.core_domain)
250
251 # instruction decoder. goes into Trap Record
252 #pdecode = create_pdecode()
253 self.cur_state = CoreState("cur") # current state (MSR/PC/SVSTATE)
254 self.pdecode2 = PowerDecode2(None, state=self.cur_state,
255 opkls=IssuerDecode2ToOperand,
256 svp64_en=self.svp64_en,
257 regreduce_en=self.regreduce_en)
258 pdecode = self.pdecode2.dec
259
260 if self.svp64_en:
261 self.svp64 = SVP64PrefixDecoder() # for decoding SVP64 prefix
262
263 self.update_svstate = Signal() # set this if updating svstate
264 self.new_svstate = new_svstate = SVSTATERec("new_svstate")
265
266 # Test Instruction memory
267 if hasattr(core, "icache"):
268 # XXX BLECH! use pspec to transfer the I-Cache to ConfigFetchUnit
269 # truly dreadful. needs a huge reorg.
270 pspec.icache = core.icache
271 self.imem = ConfigFetchUnit(pspec).fu
272
273 # DMI interface
274 self.dbg = CoreDebug()
275 self.dbg_rst_i = Signal(reset_less=True)
276
277 # instruction go/monitor
278 self.pc_o = Signal(64, reset_less=True)
279 self.pc_i = Data(64, "pc_i") # set "ok" to indicate "please change me"
280 self.msr_i = Data(64, "msr_i") # set "ok" to indicate "please change me"
281 self.svstate_i = Data(64, "svstate_i") # ditto
282 self.core_bigendian_i = Signal() # TODO: set based on MSR.LE
283 self.busy_o = Signal(reset_less=True)
284 self.memerr_o = Signal(reset_less=True)
285
286 # STATE regfile read /write ports for PC, MSR, SVSTATE
287 staterf = self.core.regs.rf['state']
288 self.state_r_msr = staterf.r_ports['msr'] # MSR rd
289 self.state_r_pc = staterf.r_ports['cia'] # PC rd
290 self.state_r_sv = staterf.r_ports['sv'] # SVSTATE rd
291
292 self.state_w_msr = staterf.w_ports['d_wr2'] # MSR wr
293 self.state_w_pc = staterf.w_ports['d_wr1'] # PC wr
294 self.state_w_sv = staterf.w_ports['sv'] # SVSTATE wr
295
296 # DMI interface access
297 intrf = self.core.regs.rf['int']
298 fastrf = self.core.regs.rf['fast']
299 crrf = self.core.regs.rf['cr']
300 xerrf = self.core.regs.rf['xer']
301 self.int_r = intrf.r_ports['dmi'] # INT DMI read
302 self.cr_r = crrf.r_ports['full_cr_dbg'] # CR DMI read
303 self.xer_r = xerrf.r_ports['full_xer'] # XER DMI read
304 self.fast_r = fastrf.r_ports['dmi'] # FAST DMI read
305
306 if self.svp64_en:
307 # for predication
308 self.int_pred = intrf.r_ports['pred'] # INT predicate read
309 self.cr_pred = crrf.r_ports['cr_pred'] # CR predicate read
310
311 # hack method of keeping an eye on whether branch/trap set the PC
312 self.state_nia = self.core.regs.rf['state'].w_ports['nia']
313 self.state_nia.wen.name = 'state_nia_wen'
314 # and whether SPR pipeline sets DEC or TB
315 self.state_spr = self.core.regs.rf['state'].w_ports['state1']
316
317 # pulse to synchronize the simulator at instruction end
318 self.insn_done = Signal()
319
320 # indicate any instruction still outstanding, in execution
321 self.any_busy = Signal()
322
323 if self.svp64_en:
324 # store copies of predicate masks
325 self.srcmask = Signal(64)
326 self.dstmask = Signal(64)
327
328 # sigh, the wishbone addresses are not wishbone-compliant
329 # in old versions of microwatt, tplaten_3d_game is a new one
330 if self.microwatt_compat:
331 self.ibus_adr = Signal(32, name='wishbone_insn_out.adr')
332 self.dbus_adr = Signal(32, name='wishbone_data_out.adr')
333
334 # add an output of the PC and instruction, and whether it was requested
335 # this is for verilator debug purposes
336 if self.microwatt_compat:
337 self.nia = Signal(64)
338 self.msr_o = Signal(64)
339 self.nia_req = Signal(1)
340 self.insn = Signal(32)
341 self.ldst_req = Signal(1)
342 self.ldst_addr = Signal(1)
343
344 # for pausing dec/tb during an SPR pipeline event, this
345 # ensures that an SPR write (mtspr) to TB or DEC does not
346 # get overwritten by the DEC/TB FSM
347 self.pause_dec_tb = Signal()
348
349 def setup_peripherals(self, m):
350 comb, sync = m.d.comb, m.d.sync
351
352 # okaaaay so the debug module must be in coresync clock domain
353 # but NOT its reset signal. to cope with this, set every single
354 # submodule explicitly in coresync domain, debug and JTAG
355 # in their own one but using *external* reset.
356 csd = DomainRenamer(self.core_domain)
357 dbd = DomainRenamer(self.dbg_domain)
358
359 if self.microwatt_compat:
360 m.submodules.core = core = self.core
361 else:
362 m.submodules.core = core = csd(self.core)
363
364 # this _so_ needs sorting out. ICache is added down inside
365 # LoadStore1 and is already a submodule of LoadStore1
366 if not isinstance(self.imem, ICache):
367 m.submodules.imem = imem = csd(self.imem)
368
369 # set up JTAG Debug Module (in correct domain)
370 m.submodules.dbg = dbg = dbd(self.dbg)
371 if self.jtag_en:
372 m.submodules.jtag = jtag = dbd(self.jtag)
373 # TODO: UART2GDB mux, here, from external pin
374 # see https://bugs.libre-soc.org/show_bug.cgi?id=499
375 sync += dbg.dmi.connect_to(jtag.dmi)
376
377 # fixup the clocks in microwatt-compat mode (but leave resets alone
378 # so that microwatt soc.vhdl can pull a reset on the core or DMI
379 # can do it, just like in TestIssuer)
380 if self.microwatt_compat:
381 intclk = ClockSignal(self.core_domain)
382 dbgclk = ClockSignal(self.dbg_domain)
383 if self.core_domain != 'sync':
384 comb += intclk.eq(ClockSignal())
385 if self.dbg_domain != 'sync':
386 comb += dbgclk.eq(ClockSignal())
387
388 # if using old version of microwatt
389 # drop the first 3 bits of the incoming wishbone addresses
390 if self.microwatt_compat:
391 ibus = self.imem.ibus
392 dbus = self.core.l0.cmpi.wb_bus()
393 if self.microwatt_old:
394 comb += self.ibus_adr.eq(Cat(Const(0, 3), ibus.adr))
395 comb += self.dbus_adr.eq(Cat(Const(0, 3), dbus.adr))
396 else:
397 comb += self.ibus_adr.eq(ibus.adr)
398 comb += self.dbus_adr.eq(dbus.adr)
399 if self.microwatt_debug:
400 # microwatt verilator debug purposes
401 pi = self.core.l0.cmpi.pi.pi
402 comb += self.ldst_req.eq(pi.addr_ok_o)
403 comb += self.ldst_addr.eq(pi.addr)
404
405 cur_state = self.cur_state
406
407 # 4x 4k SRAM blocks. these simply "exist", they get routed in litex
408 if self.sram4x4k:
409 for i, sram in enumerate(self.sram4k):
410 m.submodules["sram4k_%d" % i] = csd(sram)
411 comb += sram.enable.eq(self.wb_sram_en)
412
413 # XICS interrupt handler
414 if self.xics:
415 m.submodules.xics_icp = icp = csd(self.xics_icp)
416 m.submodules.xics_ics = ics = csd(self.xics_ics)
417 comb += icp.ics_i.eq(ics.icp_o) # connect ICS to ICP
418 sync += cur_state.eint.eq(icp.core_irq_o) # connect ICP to core
419 else:
420 sync += cur_state.eint.eq(self.ext_irq) # connect externally
421
422 # GPIO test peripheral
423 if self.gpio:
424 m.submodules.simple_gpio = simple_gpio = csd(self.simple_gpio)
425
426 # connect one GPIO output to ICS bit 15 (like in microwatt soc.vhdl)
427 # XXX causes litex ECP5 test to get wrong idea about input and output
428 # (but works with verilator sim *sigh*)
429 # if self.gpio and self.xics:
430 # comb += self.int_level_i[15].eq(simple_gpio.gpio_o[0])
431
432 # instruction decoder
433 pdecode = create_pdecode()
434 m.submodules.dec2 = pdecode2 = csd(self.pdecode2)
435 if self.svp64_en:
436 m.submodules.svp64 = svp64 = csd(self.svp64)
437
438 # clock delay power-on reset
439 cd_por = ClockDomain(reset_less=True)
440 cd_sync = ClockDomain()
441 m.domains += cd_por, cd_sync
442 core_sync = ClockDomain(self.core_domain)
443 if self.core_domain != "sync":
444 m.domains += core_sync
445 if self.dbg_domain != "sync":
446 dbg_sync = ClockDomain(self.dbg_domain)
447 m.domains += dbg_sync
448
449 # create a delay, but remember it is in the power-on-reset clock domain!
450 ti_rst = Signal(reset_less=True)
451 delay = Signal(range(4), reset=3)
452 stop_delay = Signal(range(16), reset=5)
453 with m.If(delay != 0):
454 m.d.por += delay.eq(delay - 1) # decrement... in POR domain!
455 with m.If(stop_delay != 0):
456 m.d.por += stop_delay.eq(stop_delay - 1) # likewise
457 comb += cd_por.clk.eq(ClockSignal())
458
459 # power-on reset delay
460 if self.core_domain != "sync":
461 comb += ti_rst.eq(delay != 0 | dbg.core_rst_o | ResetSignal())
462 comb += self.core_rst.eq(ti_rst)
463 else:
464 with m.If(delay != 0 | dbg.core_rst_o):
465 comb += self.core_rst.eq(1)
466 with m.If(stop_delay != 0):
467 # run DMI core-stop as well but on an extra couple of cycles
468 comb += dbg.core_stopped_i.eq(1)
469
470 # connect external reset signal to DMI Reset
471 if self.dbg_domain != "sync":
472 dbg_rst = ResetSignal(self.dbg_domain)
473 comb += dbg_rst.eq(self.dbg_rst_i)
474
475 # busy/halted signals from core
476 core_busy_o = ~core.p.o_ready | core.n.o_data.busy_o # core is busy
477 comb += self.busy_o.eq(core_busy_o)
478 comb += pdecode2.dec.bigendian.eq(self.core_bigendian_i)
479
480 # temporary hack: says "go" immediately for both address gen and ST
481 # XXX: st.go_i is set to 1 cycle delay to reduce combinatorial chains
482 l0 = core.l0
483 ldst = core.fus.fus['ldst0']
484 st_go_edge = rising_edge(m, ldst.st.rel_o)
485 # link addr-go direct to rel
486 m.d.comb += ldst.ad.go_i.eq(ldst.ad.rel_o)
487 m.d.sync += ldst.st.go_i.eq(st_go_edge) # link store-go to rising rel
488
489 def do_dmi(self, m, dbg):
490 """deals with DMI debug requests
491
492 currently only provides read requests for the INT regfile, CR and XER
493 it will later also deal with *writing* to these regfiles.
494 """
495 comb = m.d.comb
496 sync = m.d.sync
497 dmi, d_reg, d_cr, d_xer, = dbg.dmi, dbg.d_gpr, dbg.d_cr, dbg.d_xer
498 d_fast = dbg.d_fast
499 intrf = self.core.regs.rf['int']
500 fastrf = self.core.regs.rf['fast']
501
502 with m.If(d_reg.req): # request for regfile access being made
503 # TODO: error-check this
504 # XXX should this be combinatorial? sync better?
505 if intrf.unary:
506 comb += self.int_r.ren.eq(1 << d_reg.addr)
507 else:
508 comb += self.int_r.addr.eq(d_reg.addr)
509 comb += self.int_r.ren.eq(1)
510 d_reg_delay = Signal()
511 sync += d_reg_delay.eq(d_reg.req)
512 with m.If(d_reg_delay):
513 # data arrives one clock later
514 comb += d_reg.data.eq(self.int_r.o_data)
515 comb += d_reg.ack.eq(1)
516
517 # fast regfile
518 with m.If(d_fast.req): # request for regfile access being made
519 if fastrf.unary:
520 comb += self.fast_r.ren.eq(1 << d_fast.addr)
521 else:
522 comb += self.fast_r.addr.eq(d_fast.addr)
523 comb += self.fast_r.ren.eq(1)
524 d_fast_delay = Signal()
525 sync += d_fast_delay.eq(d_fast.req)
526 with m.If(d_fast_delay):
527 # data arrives one clock later
528 comb += d_fast.data.eq(self.fast_r.o_data)
529 comb += d_fast.ack.eq(1)
530
531 # sigh same thing for CR debug
532 with m.If(d_cr.req): # request for regfile access being made
533 comb += self.cr_r.ren.eq(0b11111111) # enable all
534 d_cr_delay = Signal()
535 sync += d_cr_delay.eq(d_cr.req)
536 with m.If(d_cr_delay):
537 # data arrives one clock later
538 comb += d_cr.data.eq(self.cr_r.o_data)
539 comb += d_cr.ack.eq(1)
540
541 # aaand XER...
542 with m.If(d_xer.req): # request for regfile access being made
543 comb += self.xer_r.ren.eq(0b111111) # enable all
544 d_xer_delay = Signal()
545 sync += d_xer_delay.eq(d_xer.req)
546 with m.If(d_xer_delay):
547 # data arrives one clock later
548 comb += d_xer.data.eq(self.xer_r.o_data)
549 comb += d_xer.ack.eq(1)
550
551 def tb_dec_fsm(self, m, spr_dec):
552 """tb_dec_fsm
553
554 this is a FSM for updating either dec or tb. it runs alternately
555 DEC, TB, DEC, TB. note that SPR pipeline could have written a new
556 value to DEC, however the regfile has "passthrough" on it so this
557 *should* be ok.
558
559 see v3.0B p1097-1099 for Timer Resource and p1065 and p1076
560 """
561
562 comb, sync = m.d.comb, m.d.sync
563 state_rf = self.core.regs.rf['state']
564 state_r_dectb = state_rf.r_ports['issue'] # DEC/TB
565 state_w_dectb = state_rf.w_ports['issue'] # DEC/TB
566
567 with m.FSM() as fsm:
568
569 # initiates read of current DEC
570 with m.State("DEC_READ"):
571 comb += state_r_dectb.ren.eq(1<<StateRegs.DEC)
572 with m.If(~self.pause_dec_tb):
573 m.next = "DEC_WRITE"
574
575 # waits for DEC read to arrive (1 cycle), updates with new value
576 # respects if dec/tb writing has been paused
577 with m.State("DEC_WRITE"):
578 with m.If(self.pause_dec_tb):
579 # if paused, return to reading
580 m.next = "DEC_READ"
581 with m.Else():
582 new_dec = Signal(64)
583 # TODO: MSR.LPCR 32-bit decrement mode
584 comb += new_dec.eq(state_r_dectb.o_data - 1)
585 comb += state_w_dectb.wen.eq(1<<StateRegs.DEC)
586 comb += state_w_dectb.i_data.eq(new_dec)
587 # copy to cur_state for decoder, for an interrupt
588 sync += spr_dec.eq(new_dec)
589 m.next = "TB_READ"
590
591 # initiates read of current TB
592 with m.State("TB_READ"):
593 comb += state_r_dectb.ren.eq(1<<StateRegs.TB)
594 with m.If(~self.pause_dec_tb):
595 m.next = "TB_WRITE"
596
597 # waits for read TB to arrive, initiates write of current TB
598 # respects if dec/tb writing has been paused
599 with m.State("TB_WRITE"):
600 with m.If(self.pause_dec_tb):
601 # if paused, return to reading
602 m.next = "TB_READ"
603 with m.Else():
604 new_tb = Signal(64)
605 comb += new_tb.eq(state_r_dectb.o_data + 1)
606 comb += state_w_dectb.wen.eq(1<<StateRegs.TB)
607 comb += state_w_dectb.i_data.eq(new_tb)
608 m.next = "DEC_READ"
609
610 return m
611
612 def elaborate(self, platform):
613 m = Module()
614 # convenience
615 comb, sync = m.d.comb, m.d.sync
616 cur_state = self.cur_state
617 pdecode2 = self.pdecode2
618 dbg = self.dbg
619
620 # set up peripherals and core
621 core_rst = self.core_rst
622 self.setup_peripherals(m)
623
624 # reset current state if core reset requested
625 with m.If(core_rst):
626 m.d.sync += self.cur_state.eq(0)
627 # and, sigh, set configured values, which are also done in regfile
628 m.d.sync += self.cur_state.pc.eq(self.core.pc_at_reset)
629 m.d.sync += self.cur_state.msr.eq(self.core.msr_at_reset)
630
631 # check halted condition: requested PC to execute matches DMI stop addr
632 # and immediately stop. address of 0xffff_ffff_ffff_ffff can never
633 # match
634 halted = Signal()
635 comb += halted.eq(dbg.stop_addr_o == dbg.state.pc)
636 with m.If(halted):
637 comb += dbg.core_stopped_i.eq(1)
638 comb += dbg.terminate_i.eq(1)
639
640 # PC and instruction from I-Memory
641 comb += self.pc_o.eq(cur_state.pc)
642 self.pc_changed = Signal() # note write to PC
643 self.msr_changed = Signal() # note write to MSR
644 self.sv_changed = Signal() # note write to SVSTATE
645
646 # read state either from incoming override or from regfile
647 state = CoreState("get") # current state (MSR/PC/SVSTATE)
648 state_get(m, state.msr, core_rst, self.msr_i,
649 "msr", # read MSR
650 self.state_r_msr, StateRegs.MSR)
651 state_get(m, state.pc, core_rst, self.pc_i,
652 "pc", # read PC
653 self.state_r_pc, StateRegs.PC)
654 state_get(m, state.svstate, core_rst, self.svstate_i,
655 "svstate", # read SVSTATE
656 self.state_r_sv, StateRegs.SVSTATE)
657
658 # don't write pc every cycle
659 comb += self.state_w_pc.wen.eq(0)
660 comb += self.state_w_pc.i_data.eq(0)
661
662 # connect up debug state. note "combinatorially same" below,
663 # this is a bit naff, passing state over in the dbg class, but
664 # because it is combinatorial it achieves the desired goal
665 comb += dbg.state.eq(state)
666
667 # this bit doesn't have to be in the FSM: connect up to read
668 # regfiles on demand from DMI
669 self.do_dmi(m, dbg)
670
671 # DEC and TB inc/dec FSM. copy of DEC is put into CoreState,
672 # (which uses that in PowerDecoder2 to raise 0x900 exception)
673 self.tb_dec_fsm(m, cur_state.dec)
674
675 # while stopped, allow updating the MSR, PC and SVSTATE.
676 # these are mainly for debugging purposes (including DMI/JTAG)
677 with m.If(dbg.core_stopped_i):
678 with m.If(self.pc_i.ok):
679 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
680 comb += self.state_w_pc.i_data.eq(self.pc_i.data)
681 sync += self.pc_changed.eq(1)
682 with m.If(self.msr_i.ok):
683 comb += self.state_w_msr.wen.eq(1 << StateRegs.MSR)
684 comb += self.state_w_msr.i_data.eq(self.msr_i.data)
685 sync += self.msr_changed.eq(1)
686 with m.If(self.svstate_i.ok | self.update_svstate):
687 with m.If(self.svstate_i.ok): # over-ride from external source
688 comb += self.new_svstate.eq(self.svstate_i.data)
689 comb += self.state_w_sv.wen.eq(1 << StateRegs.SVSTATE)
690 comb += self.state_w_sv.i_data.eq(self.new_svstate)
691 sync += self.sv_changed.eq(1)
692
693 # start renaming some of the ports to match microwatt
694 if self.microwatt_compat:
695 self.core.o.core_terminate_o.name = "terminated_out"
696 # names of DMI interface
697 self.dbg.dmi.addr_i.name = 'dmi_addr'
698 self.dbg.dmi.din.name = 'dmi_din'
699 self.dbg.dmi.dout.name = 'dmi_dout'
700 self.dbg.dmi.req_i.name = 'dmi_req'
701 self.dbg.dmi.we_i.name = 'dmi_wr'
702 self.dbg.dmi.ack_o.name = 'dmi_ack'
703 # wishbone instruction bus
704 ibus = self.imem.ibus
705 ibus.adr.name = 'wishbone_insn_out.adr'
706 ibus.dat_w.name = 'wishbone_insn_out.dat'
707 ibus.sel.name = 'wishbone_insn_out.sel'
708 ibus.cyc.name = 'wishbone_insn_out.cyc'
709 ibus.stb.name = 'wishbone_insn_out.stb'
710 ibus.we.name = 'wishbone_insn_out.we'
711 ibus.dat_r.name = 'wishbone_insn_in.dat'
712 ibus.ack.name = 'wishbone_insn_in.ack'
713 ibus.stall.name = 'wishbone_insn_in.stall'
714 # wishbone data bus
715 dbus = self.core.l0.cmpi.wb_bus()
716 dbus.adr.name = 'wishbone_data_out.adr'
717 dbus.dat_w.name = 'wishbone_data_out.dat'
718 dbus.sel.name = 'wishbone_data_out.sel'
719 dbus.cyc.name = 'wishbone_data_out.cyc'
720 dbus.stb.name = 'wishbone_data_out.stb'
721 dbus.we.name = 'wishbone_data_out.we'
722 dbus.dat_r.name = 'wishbone_data_in.dat'
723 dbus.ack.name = 'wishbone_data_in.ack'
724 dbus.stall.name = 'wishbone_data_in.stall'
725
726 return m
727
728 def __iter__(self):
729 yield from self.pc_i.ports()
730 yield from self.msr_i.ports()
731 yield self.pc_o
732 yield self.memerr_o
733 yield from self.core.ports()
734 yield from self.imem.ports()
735 yield self.core_bigendian_i
736 yield self.busy_o
737
738 def ports(self):
739 return list(self)
740
741 def external_ports(self):
742 if self.microwatt_compat:
743 ports = [self.core.o.core_terminate_o,
744 self.ext_irq,
745 self.alt_reset, # not connected yet
746 self.nia, self.insn, self.nia_req, self.msr_o,
747 self.ldst_req, self.ldst_addr,
748 ClockSignal(),
749 ResetSignal(),
750 ]
751 ports += list(self.dbg.dmi.ports())
752 # for dbus/ibus microwatt, exclude err btw and cti
753 for name, sig in self.imem.ibus.fields.items():
754 if name not in ['err', 'bte', 'cti', 'adr']:
755 ports.append(sig)
756 for name, sig in self.core.l0.cmpi.wb_bus().fields.items():
757 if name not in ['err', 'bte', 'cti', 'adr']:
758 ports.append(sig)
759 # microwatt non-compliant with wishbone
760 ports.append(self.ibus_adr)
761 ports.append(self.dbus_adr)
762 return ports
763
764 ports = self.pc_i.ports()
765 ports = self.msr_i.ports()
766 ports += [self.pc_o, self.memerr_o, self.core_bigendian_i, self.busy_o,
767 ]
768
769 if self.jtag_en:
770 ports += list(self.jtag.external_ports())
771 else:
772 # don't add DMI if JTAG is enabled
773 ports += list(self.dbg.dmi.ports())
774
775 ports += list(self.imem.ibus.fields.values())
776 ports += list(self.core.l0.cmpi.wb_bus().fields.values())
777
778 if self.sram4x4k:
779 for sram in self.sram4k:
780 ports += list(sram.bus.fields.values())
781
782 if self.xics:
783 ports += list(self.xics_icp.bus.fields.values())
784 ports += list(self.xics_ics.bus.fields.values())
785 ports.append(self.int_level_i)
786 else:
787 ports.append(self.ext_irq)
788
789 if self.gpio:
790 ports += list(self.simple_gpio.bus.fields.values())
791 ports.append(self.gpio_o)
792
793 return ports
794
795 def ports(self):
796 return list(self)
797
798
799 class TestIssuerInternal(TestIssuerBase):
800 """TestIssuer - reads instructions from TestMemory and issues them
801
802 efficiency and speed is not the main goal here: functional correctness
803 and code clarity is. optimisations (which almost 100% interfere with
804 easy understanding) come later.
805 """
806
807 def fetch_fsm(self, m, dbg, core, nia, is_svp64_mode,
808 fetch_pc_o_ready, fetch_pc_i_valid,
809 fetch_insn_o_valid, fetch_insn_i_ready):
810 """fetch FSM
811
812 this FSM performs fetch of raw instruction data, partial-decodes
813 it 32-bit at a time to detect SVP64 prefixes, and will optionally
814 read a 2nd 32-bit quantity if that occurs.
815 """
816 comb = m.d.comb
817 sync = m.d.sync
818 pdecode2 = self.pdecode2
819 cur_state = self.cur_state
820 dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode
821 pc, msr, svstate = cur_state.pc, cur_state.msr, cur_state.svstate
822
823 # also note instruction fetch failed
824 if hasattr(core, "icache"):
825 fetch_failed = core.icache.i_out.fetch_failed
826 flush_needed = True
827 else:
828 fetch_failed = Const(0, 1)
829 flush_needed = False
830
831 # set priv / virt mode on I-Cache, sigh
832 if isinstance(self.imem, ICache):
833 comb += self.imem.i_in.priv_mode.eq(~msr[MSR.PR])
834 comb += self.imem.i_in.virt_mode.eq(msr[MSR.IR]) # Instr. Redir (VM)
835
836 with m.FSM(name='fetch_fsm'):
837
838 # allow fetch to not run at startup due to I-Cache reset not
839 # having time to settle. power-on-reset holds dbg.core_stopped_i
840 with m.State("PRE_IDLE"):
841 with m.If(~dbg.core_stopped_i & ~dbg.core_stop_o):
842 m.next = "IDLE"
843
844 # waiting (zzz)
845 with m.State("IDLE"):
846 # fetch allowed if not failed and stopped but not stepping
847 # (see dmi.py for how core_stop_o is generated)
848 with m.If(~fetch_failed & ~dbg.core_stop_o):
849 comb += fetch_pc_o_ready.eq(1)
850 with m.If(fetch_pc_i_valid & ~pdecode2.instr_fault
851 & ~dbg.core_stop_o):
852 # instruction allowed to go: start by reading the PC
853 # capture the PC and also drop it into Insn Memory
854 # we have joined a pair of combinatorial memory
855 # lookups together. this is Generally Bad.
856 comb += self.imem.a_pc_i.eq(pc)
857 comb += self.imem.a_i_valid.eq(1)
858 comb += self.imem.f_i_valid.eq(1)
859 m.next = "INSN_READ" # move to "wait for bus" phase
860
861 # dummy pause to find out why simulation is not keeping up
862 with m.State("INSN_READ"):
863 # when using "single-step" mode, checking dbg.stopping_o
864 # prevents progress. allow fetch to proceed once started
865 stopping = Const(0)
866 #if self.allow_overlap:
867 # stopping = dbg.stopping_o
868 with m.If(stopping):
869 # stopping: jump back to idle
870 m.next = "IDLE"
871 with m.Else():
872 with m.If(self.imem.f_busy_o &
873 ~pdecode2.instr_fault): # zzz...
874 # busy but not fetch failed: stay in wait-read
875 comb += self.imem.a_pc_i.eq(pc)
876 comb += self.imem.a_i_valid.eq(1)
877 comb += self.imem.f_i_valid.eq(1)
878 with m.Else():
879 # not busy (or fetch failed!): instruction fetched
880 # when fetch failed, the instruction gets ignored
881 # by the decoder
882 if hasattr(core, "icache"):
883 # blech, icache returns actual instruction
884 insn = self.imem.f_instr_o
885 else:
886 # but these return raw memory
887 insn = get_insn(self.imem.f_instr_o, cur_state.pc)
888 if self.svp64_en:
889 svp64 = self.svp64
890 # decode the SVP64 prefix, if any
891 comb += svp64.raw_opcode_in.eq(insn)
892 comb += svp64.bigendian.eq(self.core_bigendian_i)
893 # pass the decoded prefix (if any) to PowerDecoder2
894 sync += pdecode2.sv_rm.eq(svp64.svp64_rm)
895 sync += pdecode2.is_svp64_mode.eq(is_svp64_mode)
896 # remember whether this is a prefixed instruction,
897 # so the FSM can readily loop when VL==0
898 sync += is_svp64_mode.eq(svp64.is_svp64_mode)
899 # calculate the address of the following instruction
900 insn_size = Mux(svp64.is_svp64_mode, 8, 4)
901 sync += nia.eq(cur_state.pc + insn_size)
902 with m.If(~svp64.is_svp64_mode):
903 # with no prefix, store the instruction
904 # and hand it directly to the next FSM
905 sync += dec_opcode_i.eq(insn)
906 m.next = "INSN_READY"
907 with m.Else():
908 # fetch the rest of the instruction from memory
909 comb += self.imem.a_pc_i.eq(cur_state.pc + 4)
910 comb += self.imem.a_i_valid.eq(1)
911 comb += self.imem.f_i_valid.eq(1)
912 m.next = "INSN_READ2"
913 else:
914 # not SVP64 - 32-bit only
915 sync += nia.eq(cur_state.pc + 4)
916 sync += dec_opcode_i.eq(insn)
917 if self.microwatt_compat:
918 # for verilator debug purposes
919 comb += self.insn.eq(insn)
920 comb += self.nia.eq(cur_state.pc)
921 comb += self.msr_o.eq(cur_state.msr)
922 comb += self.nia_req.eq(1)
923 m.next = "INSN_READY"
924
925 with m.State("INSN_READ2"):
926 with m.If(self.imem.f_busy_o): # zzz...
927 # busy: stay in wait-read
928 comb += self.imem.a_i_valid.eq(1)
929 comb += self.imem.f_i_valid.eq(1)
930 with m.Else():
931 # not busy: instruction fetched
932 if hasattr(core, "icache"):
933 # blech, icache returns actual instruction
934 insn = self.imem.f_instr_o
935 else:
936 insn = get_insn(self.imem.f_instr_o, cur_state.pc+4)
937 sync += dec_opcode_i.eq(insn)
938 m.next = "INSN_READY"
939 # TODO: probably can start looking at pdecode2.rm_dec
940 # here or maybe even in INSN_READ state, if svp64_mode
941 # detected, in order to trigger - and wait for - the
942 # predicate reading.
943 if self.svp64_en:
944 pmode = pdecode2.rm_dec.predmode
945 """
946 if pmode != SVP64PredMode.ALWAYS.value:
947 fire predicate loading FSM and wait before
948 moving to INSN_READY
949 else:
950 sync += self.srcmask.eq(-1) # set to all 1s
951 sync += self.dstmask.eq(-1) # set to all 1s
952 m.next = "INSN_READY"
953 """
954
955 with m.State("INSN_READY"):
956 # hand over the instruction, to be decoded
957 comb += fetch_insn_o_valid.eq(1)
958 with m.If(fetch_insn_i_ready):
959 m.next = "IDLE"
960
961
962 def fetch_predicate_fsm(self, m,
963 pred_insn_i_valid, pred_insn_o_ready,
964 pred_mask_o_valid, pred_mask_i_ready):
965 """fetch_predicate_fsm - obtains (constructs in the case of CR)
966 src/dest predicate masks
967
968 https://bugs.libre-soc.org/show_bug.cgi?id=617
969 the predicates can be read here, by using IntRegs r_ports['pred']
970 or CRRegs r_ports['pred']. in the case of CRs it will have to
971 be done through multiple reads, extracting one relevant at a time.
972 later, a faster way would be to use the 32-bit-wide CR port but
973 this is more complex decoding, here. equivalent code used in
974 ISACaller is "from openpower.decoder.isa.caller import get_predcr"
975
976 note: this ENTIRE FSM is not to be called when svp64 is disabled
977 """
978 comb = m.d.comb
979 sync = m.d.sync
980 pdecode2 = self.pdecode2
981 rm_dec = pdecode2.rm_dec # SVP64RMModeDecode
982 predmode = rm_dec.predmode
983 srcpred, dstpred = rm_dec.srcpred, rm_dec.dstpred
984 cr_pred, int_pred = self.cr_pred, self.int_pred # read regfiles
985 # get src/dst step, so we can skip already used mask bits
986 cur_state = self.cur_state
987 srcstep = cur_state.svstate.srcstep
988 dststep = cur_state.svstate.dststep
989 cur_vl = cur_state.svstate.vl
990
991 # decode predicates
992 sregread, sinvert, sunary, sall1s = get_predint(m, srcpred, 's')
993 dregread, dinvert, dunary, dall1s = get_predint(m, dstpred, 'd')
994 sidx, scrinvert = get_predcr(m, srcpred, 's')
995 didx, dcrinvert = get_predcr(m, dstpred, 'd')
996
997 # store fetched masks, for either intpred or crpred
998 # when src/dst step is not zero, the skipped mask bits need to be
999 # shifted-out, before actually storing them in src/dest mask
1000 new_srcmask = Signal(64, reset_less=True)
1001 new_dstmask = Signal(64, reset_less=True)
1002
1003 with m.FSM(name="fetch_predicate"):
1004
1005 with m.State("FETCH_PRED_IDLE"):
1006 comb += pred_insn_o_ready.eq(1)
1007 with m.If(pred_insn_i_valid):
1008 with m.If(predmode == SVP64PredMode.INT):
1009 # skip fetching destination mask register, when zero
1010 with m.If(dall1s):
1011 sync += new_dstmask.eq(-1)
1012 # directly go to fetch source mask register
1013 # guaranteed not to be zero (otherwise predmode
1014 # would be SVP64PredMode.ALWAYS, not INT)
1015 comb += int_pred.addr.eq(sregread)
1016 comb += int_pred.ren.eq(1)
1017 m.next = "INT_SRC_READ"
1018 # fetch destination predicate register
1019 with m.Else():
1020 comb += int_pred.addr.eq(dregread)
1021 comb += int_pred.ren.eq(1)
1022 m.next = "INT_DST_READ"
1023 with m.Elif(predmode == SVP64PredMode.CR):
1024 # go fetch masks from the CR register file
1025 sync += new_srcmask.eq(0)
1026 sync += new_dstmask.eq(0)
1027 m.next = "CR_READ"
1028 with m.Else():
1029 sync += self.srcmask.eq(-1)
1030 sync += self.dstmask.eq(-1)
1031 m.next = "FETCH_PRED_DONE"
1032
1033 with m.State("INT_DST_READ"):
1034 # store destination mask
1035 inv = Repl(dinvert, 64)
1036 with m.If(dunary):
1037 # set selected mask bit for 1<<r3 mode
1038 dst_shift = Signal(range(64))
1039 comb += dst_shift.eq(self.int_pred.o_data & 0b111111)
1040 sync += new_dstmask.eq(1 << dst_shift)
1041 with m.Else():
1042 # invert mask if requested
1043 sync += new_dstmask.eq(self.int_pred.o_data ^ inv)
1044 # skip fetching source mask register, when zero
1045 with m.If(sall1s):
1046 sync += new_srcmask.eq(-1)
1047 m.next = "FETCH_PRED_SHIFT_MASK"
1048 # fetch source predicate register
1049 with m.Else():
1050 comb += int_pred.addr.eq(sregread)
1051 comb += int_pred.ren.eq(1)
1052 m.next = "INT_SRC_READ"
1053
1054 with m.State("INT_SRC_READ"):
1055 # store source mask
1056 inv = Repl(sinvert, 64)
1057 with m.If(sunary):
1058 # set selected mask bit for 1<<r3 mode
1059 src_shift = Signal(range(64))
1060 comb += src_shift.eq(self.int_pred.o_data & 0b111111)
1061 sync += new_srcmask.eq(1 << src_shift)
1062 with m.Else():
1063 # invert mask if requested
1064 sync += new_srcmask.eq(self.int_pred.o_data ^ inv)
1065 m.next = "FETCH_PRED_SHIFT_MASK"
1066
1067 # fetch masks from the CR register file
1068 # implements the following loop:
1069 # idx, inv = get_predcr(mask)
1070 # mask = 0
1071 # for cr_idx in range(vl):
1072 # cr = crl[cr_idx + SVP64CROffs.CRPred] # takes one cycle
1073 # if cr[idx] ^ inv:
1074 # mask |= 1 << cr_idx
1075 # return mask
1076 with m.State("CR_READ"):
1077 # CR index to be read, which will be ready by the next cycle
1078 cr_idx = Signal.like(cur_vl, reset_less=True)
1079 # submit the read operation to the regfile
1080 with m.If(cr_idx != cur_vl):
1081 # the CR read port is unary ...
1082 # ren = 1 << cr_idx
1083 # ... in MSB0 convention ...
1084 # ren = 1 << (7 - cr_idx)
1085 # ... and with an offset:
1086 # ren = 1 << (7 - off - cr_idx)
1087 idx = SVP64CROffs.CRPred + cr_idx
1088 comb += cr_pred.ren.eq(1 << (7 - idx))
1089 # signal data valid in the next cycle
1090 cr_read = Signal(reset_less=True)
1091 sync += cr_read.eq(1)
1092 # load the next index
1093 sync += cr_idx.eq(cr_idx + 1)
1094 with m.Else():
1095 # exit on loop end
1096 sync += cr_read.eq(0)
1097 sync += cr_idx.eq(0)
1098 m.next = "FETCH_PRED_SHIFT_MASK"
1099 with m.If(cr_read):
1100 # compensate for the one cycle delay on the regfile
1101 cur_cr_idx = Signal.like(cur_vl)
1102 comb += cur_cr_idx.eq(cr_idx - 1)
1103 # read the CR field, select the appropriate bit
1104 cr_field = Signal(4)
1105 scr_bit = Signal()
1106 dcr_bit = Signal()
1107 comb += cr_field.eq(cr_pred.o_data)
1108 comb += scr_bit.eq(cr_field.bit_select(sidx, 1)
1109 ^ scrinvert)
1110 comb += dcr_bit.eq(cr_field.bit_select(didx, 1)
1111 ^ dcrinvert)
1112 # set the corresponding mask bit
1113 bit_to_set = Signal.like(self.srcmask)
1114 comb += bit_to_set.eq(1 << cur_cr_idx)
1115 with m.If(scr_bit):
1116 sync += new_srcmask.eq(new_srcmask | bit_to_set)
1117 with m.If(dcr_bit):
1118 sync += new_dstmask.eq(new_dstmask | bit_to_set)
1119
1120 with m.State("FETCH_PRED_SHIFT_MASK"):
1121 # shift-out skipped mask bits
1122 sync += self.srcmask.eq(new_srcmask >> srcstep)
1123 sync += self.dstmask.eq(new_dstmask >> dststep)
1124 m.next = "FETCH_PRED_DONE"
1125
1126 with m.State("FETCH_PRED_DONE"):
1127 comb += pred_mask_o_valid.eq(1)
1128 with m.If(pred_mask_i_ready):
1129 m.next = "FETCH_PRED_IDLE"
1130
1131 def issue_fsm(self, m, core, nia,
1132 dbg, core_rst, is_svp64_mode,
1133 fetch_pc_o_ready, fetch_pc_i_valid,
1134 fetch_insn_o_valid, fetch_insn_i_ready,
1135 pred_insn_i_valid, pred_insn_o_ready,
1136 pred_mask_o_valid, pred_mask_i_ready,
1137 exec_insn_i_valid, exec_insn_o_ready,
1138 exec_pc_o_valid, exec_pc_i_ready):
1139 """issue FSM
1140
1141 decode / issue FSM. this interacts with the "fetch" FSM
1142 through fetch_insn_ready/valid (incoming) and fetch_pc_ready/valid
1143 (outgoing). also interacts with the "execute" FSM
1144 through exec_insn_ready/valid (outgoing) and exec_pc_ready/valid
1145 (incoming).
1146 SVP64 RM prefixes have already been set up by the
1147 "fetch" phase, so execute is fairly straightforward.
1148 """
1149
1150 comb = m.d.comb
1151 sync = m.d.sync
1152 pdecode2 = self.pdecode2
1153 cur_state = self.cur_state
1154 new_svstate = self.new_svstate
1155 main_rst_delay = Signal(reset_less=True)
1156
1157 # temporaries
1158 dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode
1159
1160 # for updating svstate (things like srcstep etc.)
1161 comb += new_svstate.eq(cur_state.svstate)
1162
1163 # precalculate srcstep+1 and dststep+1
1164 cur_srcstep = cur_state.svstate.srcstep
1165 cur_dststep = cur_state.svstate.dststep
1166 next_srcstep = Signal.like(cur_srcstep)
1167 next_dststep = Signal.like(cur_dststep)
1168 comb += next_srcstep.eq(cur_state.svstate.srcstep+1)
1169 comb += next_dststep.eq(cur_state.svstate.dststep+1)
1170
1171 # reset release delay
1172 sync += main_rst_delay.eq(ResetSignal())
1173
1174 # note if an exception happened. in a pipelined or OoO design
1175 # this needs to be accompanied by "shadowing" (or stalling)
1176 exc_happened = self.core.o.exc_happened
1177 # also note instruction fetch failed
1178 if hasattr(core, "icache"):
1179 fetch_failed = core.icache.i_out.fetch_failed
1180 flush_needed = True
1181 # set to fault in decoder
1182 # update (highest priority) instruction fault
1183 rising_fetch_failed = rising_edge(m, fetch_failed)
1184 with m.If(rising_fetch_failed):
1185 sync += pdecode2.instr_fault.eq(1)
1186 else:
1187 fetch_failed = Const(0, 1)
1188 flush_needed = False
1189
1190 sync += fetch_pc_i_valid.eq(0)
1191
1192 with m.FSM(name="issue_fsm"):
1193
1194 # sync with the "fetch" phase which is reading the instruction
1195 # at this point, there is no instruction running, that
1196 # could inadvertently update the PC.
1197 with m.State("ISSUE_START"):
1198 # reset instruction fault
1199 sync += pdecode2.instr_fault.eq(0)
1200 # wait on "core stop" release, before next fetch
1201 # need to do this here, in case we are in a VL==0 loop
1202 with m.If(~dbg.core_stop_o & ~core_rst & ~main_rst_delay):
1203 sync += fetch_pc_i_valid.eq(1) # tell fetch to start
1204 sync += cur_state.pc.eq(dbg.state.pc)
1205 sync += cur_state.svstate.eq(dbg.state.svstate)
1206 sync += cur_state.msr.eq(dbg.state.msr)
1207 with m.If(fetch_pc_o_ready): # fetch acknowledged us
1208 m.next = "INSN_WAIT"
1209 with m.Else():
1210 # tell core it's stopped, and acknowledge debug handshake
1211 comb += dbg.core_stopped_i.eq(1)
1212 # while stopped, allow updating SVSTATE
1213 with m.If(self.svstate_i.ok):
1214 comb += new_svstate.eq(self.svstate_i.data)
1215 comb += self.update_svstate.eq(1)
1216 sync += self.sv_changed.eq(1)
1217
1218 # wait for an instruction to arrive from Fetch
1219 with m.State("INSN_WAIT"):
1220 # when using "single-step" mode, checking dbg.stopping_o
1221 # prevents progress. allow issue to proceed once started
1222 stopping = Const(0)
1223 #if self.allow_overlap:
1224 # stopping = dbg.stopping_o
1225 with m.If(stopping):
1226 # stopping: jump back to idle
1227 m.next = "ISSUE_START"
1228 if flush_needed:
1229 # request the icache to stop asserting "failed"
1230 comb += core.icache.flush_in.eq(1)
1231 # stop instruction fault
1232 sync += pdecode2.instr_fault.eq(0)
1233 with m.Else():
1234 comb += fetch_insn_i_ready.eq(1)
1235 with m.If(fetch_insn_o_valid):
1236 # loop into ISSUE_START if it's a SVP64 instruction
1237 # and VL == 0. this because VL==0 is a for-loop
1238 # from 0 to 0 i.e. always, always a NOP.
1239 cur_vl = cur_state.svstate.vl
1240 with m.If(is_svp64_mode & (cur_vl == 0)):
1241 # update the PC before fetching the next instruction
1242 # since we are in a VL==0 loop, no instruction was
1243 # executed that we could be overwriting
1244 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
1245 comb += self.state_w_pc.i_data.eq(nia)
1246 comb += self.insn_done.eq(1)
1247 m.next = "ISSUE_START"
1248 with m.Else():
1249 if self.svp64_en:
1250 m.next = "PRED_START" # fetching predicate
1251 else:
1252 m.next = "DECODE_SV" # skip predication
1253
1254 with m.State("PRED_START"):
1255 comb += pred_insn_i_valid.eq(1) # tell fetch_pred to start
1256 with m.If(pred_insn_o_ready): # fetch_pred acknowledged us
1257 m.next = "MASK_WAIT"
1258
1259 with m.State("MASK_WAIT"):
1260 comb += pred_mask_i_ready.eq(1) # ready to receive the masks
1261 with m.If(pred_mask_o_valid): # predication masks are ready
1262 m.next = "PRED_SKIP"
1263
1264 # skip zeros in predicate
1265 with m.State("PRED_SKIP"):
1266 with m.If(~is_svp64_mode):
1267 m.next = "DECODE_SV" # nothing to do
1268 with m.Else():
1269 if self.svp64_en:
1270 pred_src_zero = pdecode2.rm_dec.pred_sz
1271 pred_dst_zero = pdecode2.rm_dec.pred_dz
1272
1273 # new srcstep, after skipping zeros
1274 skip_srcstep = Signal.like(cur_srcstep)
1275 # value to be added to the current srcstep
1276 src_delta = Signal.like(cur_srcstep)
1277 # add leading zeros to srcstep, if not in zero mode
1278 with m.If(~pred_src_zero):
1279 # priority encoder (count leading zeros)
1280 # append guard bit, in case the mask is all zeros
1281 pri_enc_src = PriorityEncoder(65)
1282 m.submodules.pri_enc_src = pri_enc_src
1283 comb += pri_enc_src.i.eq(Cat(self.srcmask,
1284 Const(1, 1)))
1285 comb += src_delta.eq(pri_enc_src.o)
1286 # apply delta to srcstep
1287 comb += skip_srcstep.eq(cur_srcstep + src_delta)
1288 # shift-out all leading zeros from the mask
1289 # plus the leading "one" bit
1290 # TODO count leading zeros and shift-out the zero
1291 # bits, in the same step, in hardware
1292 sync += self.srcmask.eq(self.srcmask >> (src_delta+1))
1293
1294 # same as above, but for dststep
1295 skip_dststep = Signal.like(cur_dststep)
1296 dst_delta = Signal.like(cur_dststep)
1297 with m.If(~pred_dst_zero):
1298 pri_enc_dst = PriorityEncoder(65)
1299 m.submodules.pri_enc_dst = pri_enc_dst
1300 comb += pri_enc_dst.i.eq(Cat(self.dstmask,
1301 Const(1, 1)))
1302 comb += dst_delta.eq(pri_enc_dst.o)
1303 comb += skip_dststep.eq(cur_dststep + dst_delta)
1304 sync += self.dstmask.eq(self.dstmask >> (dst_delta+1))
1305
1306 # TODO: initialize mask[VL]=1 to avoid passing past VL
1307 with m.If((skip_srcstep >= cur_vl) |
1308 (skip_dststep >= cur_vl)):
1309 # end of VL loop. Update PC and reset src/dst step
1310 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
1311 comb += self.state_w_pc.i_data.eq(nia)
1312 comb += new_svstate.srcstep.eq(0)
1313 comb += new_svstate.dststep.eq(0)
1314 comb += self.update_svstate.eq(1)
1315 # synchronize with the simulator
1316 comb += self.insn_done.eq(1)
1317 # go back to Issue
1318 m.next = "ISSUE_START"
1319 with m.Else():
1320 # update new src/dst step
1321 comb += new_svstate.srcstep.eq(skip_srcstep)
1322 comb += new_svstate.dststep.eq(skip_dststep)
1323 comb += self.update_svstate.eq(1)
1324 # proceed to Decode
1325 m.next = "DECODE_SV"
1326
1327 # pass predicate mask bits through to satellite decoders
1328 # TODO: for SIMD this will be *multiple* bits
1329 sync += core.i.sv_pred_sm.eq(self.srcmask[0])
1330 sync += core.i.sv_pred_dm.eq(self.dstmask[0])
1331
1332 # after src/dst step have been updated, we are ready
1333 # to decode the instruction
1334 with m.State("DECODE_SV"):
1335 # decode the instruction
1336 with m.If(~fetch_failed):
1337 sync += pdecode2.instr_fault.eq(0)
1338 sync += core.i.e.eq(pdecode2.e)
1339 sync += core.i.state.eq(cur_state)
1340 sync += core.i.raw_insn_i.eq(dec_opcode_i)
1341 sync += core.i.bigendian_i.eq(self.core_bigendian_i)
1342 if self.svp64_en:
1343 sync += core.i.sv_rm.eq(pdecode2.sv_rm)
1344 # set RA_OR_ZERO detection in satellite decoders
1345 sync += core.i.sv_a_nz.eq(pdecode2.sv_a_nz)
1346 # and svp64 detection
1347 sync += core.i.is_svp64_mode.eq(is_svp64_mode)
1348 # and svp64 bit-rev'd ldst mode
1349 ldst_dec = pdecode2.use_svp64_ldst_dec
1350 sync += core.i.use_svp64_ldst_dec.eq(ldst_dec)
1351 # after decoding, reset any previous exception condition,
1352 # allowing it to be set again during the next execution
1353 sync += pdecode2.ldst_exc.eq(0)
1354
1355 m.next = "INSN_EXECUTE" # move to "execute"
1356
1357 # handshake with execution FSM, move to "wait" once acknowledged
1358 with m.State("INSN_EXECUTE"):
1359 # when using "single-step" mode, checking dbg.stopping_o
1360 # prevents progress. allow execute to proceed once started
1361 stopping = Const(0)
1362 #if self.allow_overlap:
1363 # stopping = dbg.stopping_o
1364 with m.If(stopping):
1365 # stopping: jump back to idle
1366 m.next = "ISSUE_START"
1367 if flush_needed:
1368 # request the icache to stop asserting "failed"
1369 comb += core.icache.flush_in.eq(1)
1370 # stop instruction fault
1371 sync += pdecode2.instr_fault.eq(0)
1372 with m.Else():
1373 comb += exec_insn_i_valid.eq(1) # trigger execute
1374 with m.If(exec_insn_o_ready): # execute acknowledged us
1375 m.next = "EXECUTE_WAIT"
1376
1377 with m.State("EXECUTE_WAIT"):
1378 comb += exec_pc_i_ready.eq(1)
1379 # see https://bugs.libre-soc.org/show_bug.cgi?id=636
1380 # the exception info needs to be blatted into
1381 # pdecode.ldst_exc, and the instruction "re-run".
1382 # when ldst_exc.happened is set, the PowerDecoder2
1383 # reacts very differently: it re-writes the instruction
1384 # with a "trap" (calls PowerDecoder2.trap()) which
1385 # will *overwrite* whatever was requested and jump the
1386 # PC to the exception address, as well as alter MSR.
1387 # nothing else needs to be done other than to note
1388 # the change of PC and MSR (and, later, SVSTATE)
1389 with m.If(exc_happened):
1390 mmu = core.fus.get_exc("mmu0")
1391 ldst = core.fus.get_exc("ldst0")
1392 if mmu is not None:
1393 with m.If(fetch_failed):
1394 # instruction fetch: exception is from MMU
1395 # reset instr_fault (highest priority)
1396 sync += pdecode2.ldst_exc.eq(mmu)
1397 sync += pdecode2.instr_fault.eq(0)
1398 if flush_needed:
1399 # request icache to stop asserting "failed"
1400 comb += core.icache.flush_in.eq(1)
1401 with m.If(~fetch_failed):
1402 # otherwise assume it was a LDST exception
1403 sync += pdecode2.ldst_exc.eq(ldst)
1404
1405 with m.If(exec_pc_o_valid):
1406
1407 # was this the last loop iteration?
1408 is_last = Signal()
1409 cur_vl = cur_state.svstate.vl
1410 comb += is_last.eq(next_srcstep == cur_vl)
1411
1412 with m.If(pdecode2.instr_fault):
1413 # reset instruction fault, try again
1414 sync += pdecode2.instr_fault.eq(0)
1415 m.next = "ISSUE_START"
1416
1417 # return directly to Decode if Execute generated an
1418 # exception.
1419 with m.Elif(pdecode2.ldst_exc.happened):
1420 m.next = "DECODE_SV"
1421
1422 # if MSR, PC or SVSTATE were changed by the previous
1423 # instruction, go directly back to Fetch, without
1424 # updating either MSR PC or SVSTATE
1425 with m.Elif(self.msr_changed | self.pc_changed |
1426 self.sv_changed):
1427 m.next = "ISSUE_START"
1428
1429 # also return to Fetch, when no output was a vector
1430 # (regardless of SRCSTEP and VL), or when the last
1431 # instruction was really the last one of the VL loop
1432 with m.Elif((~pdecode2.loop_continue) | is_last):
1433 # before going back to fetch, update the PC state
1434 # register with the NIA.
1435 # ok here we are not reading the branch unit.
1436 # TODO: this just blithely overwrites whatever
1437 # pipeline updated the PC
1438 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
1439 comb += self.state_w_pc.i_data.eq(nia)
1440 # reset SRCSTEP before returning to Fetch
1441 if self.svp64_en:
1442 with m.If(pdecode2.loop_continue):
1443 comb += new_svstate.srcstep.eq(0)
1444 comb += new_svstate.dststep.eq(0)
1445 comb += self.update_svstate.eq(1)
1446 else:
1447 comb += new_svstate.srcstep.eq(0)
1448 comb += new_svstate.dststep.eq(0)
1449 comb += self.update_svstate.eq(1)
1450 m.next = "ISSUE_START"
1451
1452 # returning to Execute? then, first update SRCSTEP
1453 with m.Else():
1454 comb += new_svstate.srcstep.eq(next_srcstep)
1455 comb += new_svstate.dststep.eq(next_dststep)
1456 comb += self.update_svstate.eq(1)
1457 # return to mask skip loop
1458 m.next = "PRED_SKIP"
1459
1460
1461 # check if svstate needs updating: if so, write it to State Regfile
1462 with m.If(self.update_svstate):
1463 sync += cur_state.svstate.eq(self.new_svstate) # for next clock
1464
1465 def execute_fsm(self, m, core,
1466 exec_insn_i_valid, exec_insn_o_ready,
1467 exec_pc_o_valid, exec_pc_i_ready):
1468 """execute FSM
1469
1470 execute FSM. this interacts with the "issue" FSM
1471 through exec_insn_ready/valid (incoming) and exec_pc_ready/valid
1472 (outgoing). SVP64 RM prefixes have already been set up by the
1473 "issue" phase, so execute is fairly straightforward.
1474 """
1475
1476 comb = m.d.comb
1477 sync = m.d.sync
1478 dbg = self.dbg
1479 pdecode2 = self.pdecode2
1480
1481 # temporaries
1482 core_busy_o = core.n.o_data.busy_o # core is busy
1483 core_ivalid_i = core.p.i_valid # instruction is valid
1484
1485 if hasattr(core, "icache"):
1486 fetch_failed = core.icache.i_out.fetch_failed
1487 else:
1488 fetch_failed = Const(0, 1)
1489
1490 with m.FSM(name="exec_fsm"):
1491
1492 # waiting for instruction bus (stays there until not busy)
1493 with m.State("INSN_START"):
1494 comb += exec_insn_o_ready.eq(1)
1495 with m.If(exec_insn_i_valid):
1496 comb += core_ivalid_i.eq(1) # instruction is valid/issued
1497 sync += self.sv_changed.eq(0)
1498 sync += self.pc_changed.eq(0)
1499 sync += self.msr_changed.eq(0)
1500 with m.If(core.p.o_ready): # only move if accepted
1501 m.next = "INSN_ACTIVE" # move to "wait completion"
1502
1503 # instruction started: must wait till it finishes
1504 with m.State("INSN_ACTIVE"):
1505 # note changes to MSR, PC and SVSTATE, and DEC/TB
1506 # these last two are done together, and passed to the
1507 # DEC/TB FSM
1508 with m.If(self.state_nia.wen & (1 << StateRegs.SVSTATE)):
1509 sync += self.sv_changed.eq(1)
1510 with m.If(self.state_nia.wen & (1 << StateRegs.MSR)):
1511 sync += self.msr_changed.eq(1)
1512 with m.If(self.state_nia.wen & (1 << StateRegs.PC)):
1513 sync += self.pc_changed.eq(1)
1514 with m.If((self.state_spr.wen &
1515 ((1 << StateRegs.DEC) | (1 << StateRegs.TB))).bool()):
1516 comb += self.pause_dec_tb.eq(1)
1517 with m.If(~core_busy_o): # instruction done!
1518 comb += exec_pc_o_valid.eq(1)
1519 with m.If(exec_pc_i_ready):
1520 # when finished, indicate "done".
1521 # however, if there was an exception, the instruction
1522 # is *not* yet done. this is an implementation
1523 # detail: we choose to implement exceptions by
1524 # taking the exception information from the LDST
1525 # unit, putting that *back* into the PowerDecoder2,
1526 # and *re-running the entire instruction*.
1527 # if we erroneously indicate "done" here, it is as if
1528 # there were *TWO* instructions:
1529 # 1) the failed LDST 2) a TRAP.
1530 with m.If(~pdecode2.ldst_exc.happened &
1531 ~pdecode2.instr_fault):
1532 comb += self.insn_done.eq(1)
1533 m.next = "INSN_START" # back to fetch
1534 # terminate returns directly to INSN_START
1535 with m.If(dbg.terminate_i):
1536 # comb += self.insn_done.eq(1) - no because it's not
1537 m.next = "INSN_START" # back to fetch
1538
1539 def elaborate(self, platform):
1540 m = super().elaborate(platform)
1541 # convenience
1542 comb, sync = m.d.comb, m.d.sync
1543 cur_state = self.cur_state
1544 pdecode2 = self.pdecode2
1545 dbg = self.dbg
1546 core = self.core
1547
1548 # set up peripherals and core
1549 core_rst = self.core_rst
1550
1551 # indicate to outside world if any FU is still executing
1552 comb += self.any_busy.eq(core.n.o_data.any_busy_o) # any FU executing
1553
1554 # address of the next instruction, in the absence of a branch
1555 # depends on the instruction size
1556 nia = Signal(64)
1557
1558 # connect up debug signals
1559 with m.If(core.o.core_terminate_o):
1560 comb += dbg.terminate_i.eq(1)
1561
1562 # pass the prefix mode from Fetch to Issue, so the latter can loop
1563 # on VL==0
1564 is_svp64_mode = Signal()
1565
1566 # there are *THREE^WFOUR-if-SVP64-enabled* FSMs, fetch (32/64-bit)
1567 # issue, decode/execute, now joined by "Predicate fetch/calculate".
1568 # these are the handshake signals between each
1569
1570 # fetch FSM can run as soon as the PC is valid
1571 fetch_pc_i_valid = Signal() # Execute tells Fetch "start next read"
1572 fetch_pc_o_ready = Signal() # Fetch Tells SVSTATE "proceed"
1573
1574 # fetch FSM hands over the instruction to be decoded / issued
1575 fetch_insn_o_valid = Signal()
1576 fetch_insn_i_ready = Signal()
1577
1578 # predicate fetch FSM decodes and fetches the predicate
1579 pred_insn_i_valid = Signal()
1580 pred_insn_o_ready = Signal()
1581
1582 # predicate fetch FSM delivers the masks
1583 pred_mask_o_valid = Signal()
1584 pred_mask_i_ready = Signal()
1585
1586 # issue FSM delivers the instruction to the be executed
1587 exec_insn_i_valid = Signal()
1588 exec_insn_o_ready = Signal()
1589
1590 # execute FSM, hands over the PC/SVSTATE back to the issue FSM
1591 exec_pc_o_valid = Signal()
1592 exec_pc_i_ready = Signal()
1593
1594 # the FSMs here are perhaps unusual in that they detect conditions
1595 # then "hold" information, combinatorially, for the core
1596 # (as opposed to using sync - which would be on a clock's delay)
1597 # this includes the actual opcode, valid flags and so on.
1598
1599 # Fetch, then predicate fetch, then Issue, then Execute.
1600 # Issue is where the VL for-loop # lives. the ready/valid
1601 # signalling is used to communicate between the four.
1602
1603 self.fetch_fsm(m, dbg, core, nia, is_svp64_mode,
1604 fetch_pc_o_ready, fetch_pc_i_valid,
1605 fetch_insn_o_valid, fetch_insn_i_ready)
1606
1607 self.issue_fsm(m, core, nia,
1608 dbg, core_rst, is_svp64_mode,
1609 fetch_pc_o_ready, fetch_pc_i_valid,
1610 fetch_insn_o_valid, fetch_insn_i_ready,
1611 pred_insn_i_valid, pred_insn_o_ready,
1612 pred_mask_o_valid, pred_mask_i_ready,
1613 exec_insn_i_valid, exec_insn_o_ready,
1614 exec_pc_o_valid, exec_pc_i_ready)
1615
1616 if self.svp64_en:
1617 self.fetch_predicate_fsm(m,
1618 pred_insn_i_valid, pred_insn_o_ready,
1619 pred_mask_o_valid, pred_mask_i_ready)
1620
1621 self.execute_fsm(m, core,
1622 exec_insn_i_valid, exec_insn_o_ready,
1623 exec_pc_o_valid, exec_pc_i_ready)
1624
1625 # whatever was done above, over-ride it if core reset is held
1626 with m.If(core_rst):
1627 sync += nia.eq(0)
1628
1629 return m
1630
1631
1632 class TestIssuer(Elaboratable):
1633 def __init__(self, pspec):
1634 self.ti = TestIssuerInternal(pspec)
1635 self.pll = DummyPLL(instance=True)
1636
1637 self.dbg_rst_i = Signal(reset_less=True)
1638
1639 # PLL direct clock or not
1640 self.pll_en = hasattr(pspec, "use_pll") and pspec.use_pll
1641 if self.pll_en:
1642 self.pll_test_o = Signal(reset_less=True)
1643 self.pll_vco_o = Signal(reset_less=True)
1644 self.clk_sel_i = Signal(2, reset_less=True)
1645 self.ref_clk = ClockSignal() # can't rename it but that's ok
1646 self.pllclk_clk = ClockSignal("pllclk")
1647
1648 def elaborate(self, platform):
1649 m = Module()
1650 comb = m.d.comb
1651
1652 # TestIssuer nominally runs at main clock, actually it is
1653 # all combinatorial internally except for coresync'd components
1654 m.submodules.ti = ti = self.ti
1655
1656 if self.pll_en:
1657 # ClockSelect runs at PLL output internal clock rate
1658 m.submodules.wrappll = pll = self.pll
1659
1660 # add clock domains from PLL
1661 cd_pll = ClockDomain("pllclk")
1662 m.domains += cd_pll
1663
1664 # PLL clock established. has the side-effect of running clklsel
1665 # at the PLL's speed (see DomainRenamer("pllclk") above)
1666 pllclk = self.pllclk_clk
1667 comb += pllclk.eq(pll.clk_pll_o)
1668
1669 # wire up external 24mhz to PLL
1670 #comb += pll.clk_24_i.eq(self.ref_clk)
1671 # output 18 mhz PLL test signal, and analog oscillator out
1672 comb += self.pll_test_o.eq(pll.pll_test_o)
1673 comb += self.pll_vco_o.eq(pll.pll_vco_o)
1674
1675 # input to pll clock selection
1676 comb += pll.clk_sel_i.eq(self.clk_sel_i)
1677
1678 # now wire up ResetSignals. don't mind them being in this domain
1679 pll_rst = ResetSignal("pllclk")
1680 comb += pll_rst.eq(ResetSignal())
1681
1682 # internal clock is set to selector clock-out. has the side-effect of
1683 # running TestIssuer at this speed (see DomainRenamer("intclk") above)
1684 # debug clock runs at coresync internal clock
1685 if self.ti.dbg_domain != 'sync':
1686 cd_dbgsync = ClockDomain("dbgsync")
1687 intclk = ClockSignal(self.ti.core_domain)
1688 dbgclk = ClockSignal(self.ti.dbg_domain)
1689 # XXX BYPASS PLL XXX
1690 # XXX BYPASS PLL XXX
1691 # XXX BYPASS PLL XXX
1692 if self.pll_en:
1693 comb += intclk.eq(self.ref_clk)
1694 assert self.ti.core_domain != 'sync', \
1695 "cannot set core_domain to sync and use pll at the same time"
1696 else:
1697 if self.ti.core_domain != 'sync':
1698 comb += intclk.eq(ClockSignal())
1699 if self.ti.dbg_domain != 'sync':
1700 dbgclk = ClockSignal(self.ti.dbg_domain)
1701 comb += dbgclk.eq(intclk)
1702 comb += self.ti.dbg_rst_i.eq(self.dbg_rst_i)
1703
1704 return m
1705
1706 def ports(self):
1707 return list(self.ti.ports()) + list(self.pll.ports()) + \
1708 [ClockSignal(), ResetSignal()]
1709
1710 def external_ports(self):
1711 ports = self.ti.external_ports()
1712 ports.append(ClockSignal())
1713 ports.append(ResetSignal())
1714 if self.pll_en:
1715 ports.append(self.clk_sel_i)
1716 ports.append(self.pll.clk_24_i)
1717 ports.append(self.pll_test_o)
1718 ports.append(self.pll_vco_o)
1719 ports.append(self.pllclk_clk)
1720 ports.append(self.ref_clk)
1721 return ports
1722
1723
1724 if __name__ == '__main__':
1725 units = {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1, 'logical': 1,
1726 'spr': 1,
1727 'div': 1,
1728 'mul': 1,
1729 'shiftrot': 1
1730 }
1731 pspec = TestMemPspec(ldst_ifacetype='bare_wb',
1732 imem_ifacetype='bare_wb',
1733 addr_wid=64,
1734 mask_wid=8,
1735 reg_wid=64,
1736 units=units)
1737 dut = TestIssuer(pspec)
1738 vl = main(dut, ports=dut.ports(), name="test_issuer")
1739
1740 if len(sys.argv) == 1:
1741 vl = rtlil.convert(dut, ports=dut.external_ports(), name="test_issuer")
1742 with open("test_issuer.il", "w") as f:
1743 f.write(vl)