Properly wire core reset to ti_rst
[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
1156 # temporaries
1157 dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode
1158
1159 # for updating svstate (things like srcstep etc.)
1160 comb += new_svstate.eq(cur_state.svstate)
1161
1162 # precalculate srcstep+1 and dststep+1
1163 cur_srcstep = cur_state.svstate.srcstep
1164 cur_dststep = cur_state.svstate.dststep
1165 next_srcstep = Signal.like(cur_srcstep)
1166 next_dststep = Signal.like(cur_dststep)
1167 comb += next_srcstep.eq(cur_state.svstate.srcstep+1)
1168 comb += next_dststep.eq(cur_state.svstate.dststep+1)
1169
1170 # note if an exception happened. in a pipelined or OoO design
1171 # this needs to be accompanied by "shadowing" (or stalling)
1172 exc_happened = self.core.o.exc_happened
1173 # also note instruction fetch failed
1174 if hasattr(core, "icache"):
1175 fetch_failed = core.icache.i_out.fetch_failed
1176 flush_needed = True
1177 # set to fault in decoder
1178 # update (highest priority) instruction fault
1179 rising_fetch_failed = rising_edge(m, fetch_failed)
1180 with m.If(rising_fetch_failed):
1181 sync += pdecode2.instr_fault.eq(1)
1182 else:
1183 fetch_failed = Const(0, 1)
1184 flush_needed = False
1185
1186 sync += fetch_pc_i_valid.eq(0)
1187
1188 with m.FSM(name="issue_fsm"):
1189
1190 # sync with the "fetch" phase which is reading the instruction
1191 # at this point, there is no instruction running, that
1192 # could inadvertently update the PC.
1193 with m.State("ISSUE_START"):
1194 # reset instruction fault
1195 sync += pdecode2.instr_fault.eq(0)
1196 # wait on "core stop" release, before next fetch
1197 # need to do this here, in case we are in a VL==0 loop
1198 with m.If(~dbg.core_stop_o & ~core_rst):
1199 sync += fetch_pc_i_valid.eq(1) # tell fetch to start
1200 sync += cur_state.pc.eq(dbg.state.pc)
1201 sync += cur_state.svstate.eq(dbg.state.svstate)
1202 sync += cur_state.msr.eq(dbg.state.msr)
1203 with m.If(fetch_pc_o_ready): # fetch acknowledged us
1204 m.next = "INSN_WAIT"
1205 with m.Else():
1206 # tell core it's stopped, and acknowledge debug handshake
1207 comb += dbg.core_stopped_i.eq(1)
1208 # while stopped, allow updating SVSTATE
1209 with m.If(self.svstate_i.ok):
1210 comb += new_svstate.eq(self.svstate_i.data)
1211 comb += self.update_svstate.eq(1)
1212 sync += self.sv_changed.eq(1)
1213
1214 # wait for an instruction to arrive from Fetch
1215 with m.State("INSN_WAIT"):
1216 # when using "single-step" mode, checking dbg.stopping_o
1217 # prevents progress. allow issue to proceed once started
1218 stopping = Const(0)
1219 #if self.allow_overlap:
1220 # stopping = dbg.stopping_o
1221 with m.If(stopping):
1222 # stopping: jump back to idle
1223 m.next = "ISSUE_START"
1224 if flush_needed:
1225 # request the icache to stop asserting "failed"
1226 comb += core.icache.flush_in.eq(1)
1227 # stop instruction fault
1228 sync += pdecode2.instr_fault.eq(0)
1229 with m.Else():
1230 comb += fetch_insn_i_ready.eq(1)
1231 with m.If(fetch_insn_o_valid):
1232 # loop into ISSUE_START if it's a SVP64 instruction
1233 # and VL == 0. this because VL==0 is a for-loop
1234 # from 0 to 0 i.e. always, always a NOP.
1235 cur_vl = cur_state.svstate.vl
1236 with m.If(is_svp64_mode & (cur_vl == 0)):
1237 # update the PC before fetching the next instruction
1238 # since we are in a VL==0 loop, no instruction was
1239 # executed that we could be overwriting
1240 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
1241 comb += self.state_w_pc.i_data.eq(nia)
1242 comb += self.insn_done.eq(1)
1243 m.next = "ISSUE_START"
1244 with m.Else():
1245 if self.svp64_en:
1246 m.next = "PRED_START" # fetching predicate
1247 else:
1248 m.next = "DECODE_SV" # skip predication
1249
1250 with m.State("PRED_START"):
1251 comb += pred_insn_i_valid.eq(1) # tell fetch_pred to start
1252 with m.If(pred_insn_o_ready): # fetch_pred acknowledged us
1253 m.next = "MASK_WAIT"
1254
1255 with m.State("MASK_WAIT"):
1256 comb += pred_mask_i_ready.eq(1) # ready to receive the masks
1257 with m.If(pred_mask_o_valid): # predication masks are ready
1258 m.next = "PRED_SKIP"
1259
1260 # skip zeros in predicate
1261 with m.State("PRED_SKIP"):
1262 with m.If(~is_svp64_mode):
1263 m.next = "DECODE_SV" # nothing to do
1264 with m.Else():
1265 if self.svp64_en:
1266 pred_src_zero = pdecode2.rm_dec.pred_sz
1267 pred_dst_zero = pdecode2.rm_dec.pred_dz
1268
1269 # new srcstep, after skipping zeros
1270 skip_srcstep = Signal.like(cur_srcstep)
1271 # value to be added to the current srcstep
1272 src_delta = Signal.like(cur_srcstep)
1273 # add leading zeros to srcstep, if not in zero mode
1274 with m.If(~pred_src_zero):
1275 # priority encoder (count leading zeros)
1276 # append guard bit, in case the mask is all zeros
1277 pri_enc_src = PriorityEncoder(65)
1278 m.submodules.pri_enc_src = pri_enc_src
1279 comb += pri_enc_src.i.eq(Cat(self.srcmask,
1280 Const(1, 1)))
1281 comb += src_delta.eq(pri_enc_src.o)
1282 # apply delta to srcstep
1283 comb += skip_srcstep.eq(cur_srcstep + src_delta)
1284 # shift-out all leading zeros from the mask
1285 # plus the leading "one" bit
1286 # TODO count leading zeros and shift-out the zero
1287 # bits, in the same step, in hardware
1288 sync += self.srcmask.eq(self.srcmask >> (src_delta+1))
1289
1290 # same as above, but for dststep
1291 skip_dststep = Signal.like(cur_dststep)
1292 dst_delta = Signal.like(cur_dststep)
1293 with m.If(~pred_dst_zero):
1294 pri_enc_dst = PriorityEncoder(65)
1295 m.submodules.pri_enc_dst = pri_enc_dst
1296 comb += pri_enc_dst.i.eq(Cat(self.dstmask,
1297 Const(1, 1)))
1298 comb += dst_delta.eq(pri_enc_dst.o)
1299 comb += skip_dststep.eq(cur_dststep + dst_delta)
1300 sync += self.dstmask.eq(self.dstmask >> (dst_delta+1))
1301
1302 # TODO: initialize mask[VL]=1 to avoid passing past VL
1303 with m.If((skip_srcstep >= cur_vl) |
1304 (skip_dststep >= cur_vl)):
1305 # end of VL loop. Update PC and reset src/dst step
1306 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
1307 comb += self.state_w_pc.i_data.eq(nia)
1308 comb += new_svstate.srcstep.eq(0)
1309 comb += new_svstate.dststep.eq(0)
1310 comb += self.update_svstate.eq(1)
1311 # synchronize with the simulator
1312 comb += self.insn_done.eq(1)
1313 # go back to Issue
1314 m.next = "ISSUE_START"
1315 with m.Else():
1316 # update new src/dst step
1317 comb += new_svstate.srcstep.eq(skip_srcstep)
1318 comb += new_svstate.dststep.eq(skip_dststep)
1319 comb += self.update_svstate.eq(1)
1320 # proceed to Decode
1321 m.next = "DECODE_SV"
1322
1323 # pass predicate mask bits through to satellite decoders
1324 # TODO: for SIMD this will be *multiple* bits
1325 sync += core.i.sv_pred_sm.eq(self.srcmask[0])
1326 sync += core.i.sv_pred_dm.eq(self.dstmask[0])
1327
1328 # after src/dst step have been updated, we are ready
1329 # to decode the instruction
1330 with m.State("DECODE_SV"):
1331 # decode the instruction
1332 with m.If(~fetch_failed):
1333 sync += pdecode2.instr_fault.eq(0)
1334 sync += core.i.e.eq(pdecode2.e)
1335 sync += core.i.state.eq(cur_state)
1336 sync += core.i.raw_insn_i.eq(dec_opcode_i)
1337 sync += core.i.bigendian_i.eq(self.core_bigendian_i)
1338 if self.svp64_en:
1339 sync += core.i.sv_rm.eq(pdecode2.sv_rm)
1340 # set RA_OR_ZERO detection in satellite decoders
1341 sync += core.i.sv_a_nz.eq(pdecode2.sv_a_nz)
1342 # and svp64 detection
1343 sync += core.i.is_svp64_mode.eq(is_svp64_mode)
1344 # and svp64 bit-rev'd ldst mode
1345 ldst_dec = pdecode2.use_svp64_ldst_dec
1346 sync += core.i.use_svp64_ldst_dec.eq(ldst_dec)
1347 # after decoding, reset any previous exception condition,
1348 # allowing it to be set again during the next execution
1349 sync += pdecode2.ldst_exc.eq(0)
1350
1351 m.next = "INSN_EXECUTE" # move to "execute"
1352
1353 # handshake with execution FSM, move to "wait" once acknowledged
1354 with m.State("INSN_EXECUTE"):
1355 # when using "single-step" mode, checking dbg.stopping_o
1356 # prevents progress. allow execute to proceed once started
1357 stopping = Const(0)
1358 #if self.allow_overlap:
1359 # stopping = dbg.stopping_o
1360 with m.If(stopping):
1361 # stopping: jump back to idle
1362 m.next = "ISSUE_START"
1363 if flush_needed:
1364 # request the icache to stop asserting "failed"
1365 comb += core.icache.flush_in.eq(1)
1366 # stop instruction fault
1367 sync += pdecode2.instr_fault.eq(0)
1368 with m.Else():
1369 comb += exec_insn_i_valid.eq(1) # trigger execute
1370 with m.If(exec_insn_o_ready): # execute acknowledged us
1371 m.next = "EXECUTE_WAIT"
1372
1373 with m.State("EXECUTE_WAIT"):
1374 comb += exec_pc_i_ready.eq(1)
1375 # see https://bugs.libre-soc.org/show_bug.cgi?id=636
1376 # the exception info needs to be blatted into
1377 # pdecode.ldst_exc, and the instruction "re-run".
1378 # when ldst_exc.happened is set, the PowerDecoder2
1379 # reacts very differently: it re-writes the instruction
1380 # with a "trap" (calls PowerDecoder2.trap()) which
1381 # will *overwrite* whatever was requested and jump the
1382 # PC to the exception address, as well as alter MSR.
1383 # nothing else needs to be done other than to note
1384 # the change of PC and MSR (and, later, SVSTATE)
1385 with m.If(exc_happened):
1386 mmu = core.fus.get_exc("mmu0")
1387 ldst = core.fus.get_exc("ldst0")
1388 if mmu is not None:
1389 with m.If(fetch_failed):
1390 # instruction fetch: exception is from MMU
1391 # reset instr_fault (highest priority)
1392 sync += pdecode2.ldst_exc.eq(mmu)
1393 sync += pdecode2.instr_fault.eq(0)
1394 if flush_needed:
1395 # request icache to stop asserting "failed"
1396 comb += core.icache.flush_in.eq(1)
1397 with m.If(~fetch_failed):
1398 # otherwise assume it was a LDST exception
1399 sync += pdecode2.ldst_exc.eq(ldst)
1400
1401 with m.If(exec_pc_o_valid):
1402
1403 # was this the last loop iteration?
1404 is_last = Signal()
1405 cur_vl = cur_state.svstate.vl
1406 comb += is_last.eq(next_srcstep == cur_vl)
1407
1408 with m.If(pdecode2.instr_fault):
1409 # reset instruction fault, try again
1410 sync += pdecode2.instr_fault.eq(0)
1411 m.next = "ISSUE_START"
1412
1413 # return directly to Decode if Execute generated an
1414 # exception.
1415 with m.Elif(pdecode2.ldst_exc.happened):
1416 m.next = "DECODE_SV"
1417
1418 # if MSR, PC or SVSTATE were changed by the previous
1419 # instruction, go directly back to Fetch, without
1420 # updating either MSR PC or SVSTATE
1421 with m.Elif(self.msr_changed | self.pc_changed |
1422 self.sv_changed):
1423 m.next = "ISSUE_START"
1424
1425 # also return to Fetch, when no output was a vector
1426 # (regardless of SRCSTEP and VL), or when the last
1427 # instruction was really the last one of the VL loop
1428 with m.Elif((~pdecode2.loop_continue) | is_last):
1429 # before going back to fetch, update the PC state
1430 # register with the NIA.
1431 # ok here we are not reading the branch unit.
1432 # TODO: this just blithely overwrites whatever
1433 # pipeline updated the PC
1434 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
1435 comb += self.state_w_pc.i_data.eq(nia)
1436 # reset SRCSTEP before returning to Fetch
1437 if self.svp64_en:
1438 with m.If(pdecode2.loop_continue):
1439 comb += new_svstate.srcstep.eq(0)
1440 comb += new_svstate.dststep.eq(0)
1441 comb += self.update_svstate.eq(1)
1442 else:
1443 comb += new_svstate.srcstep.eq(0)
1444 comb += new_svstate.dststep.eq(0)
1445 comb += self.update_svstate.eq(1)
1446 m.next = "ISSUE_START"
1447
1448 # returning to Execute? then, first update SRCSTEP
1449 with m.Else():
1450 comb += new_svstate.srcstep.eq(next_srcstep)
1451 comb += new_svstate.dststep.eq(next_dststep)
1452 comb += self.update_svstate.eq(1)
1453 # return to mask skip loop
1454 m.next = "PRED_SKIP"
1455
1456
1457 # check if svstate needs updating: if so, write it to State Regfile
1458 with m.If(self.update_svstate):
1459 sync += cur_state.svstate.eq(self.new_svstate) # for next clock
1460
1461 def execute_fsm(self, m, core,
1462 exec_insn_i_valid, exec_insn_o_ready,
1463 exec_pc_o_valid, exec_pc_i_ready):
1464 """execute FSM
1465
1466 execute FSM. this interacts with the "issue" FSM
1467 through exec_insn_ready/valid (incoming) and exec_pc_ready/valid
1468 (outgoing). SVP64 RM prefixes have already been set up by the
1469 "issue" phase, so execute is fairly straightforward.
1470 """
1471
1472 comb = m.d.comb
1473 sync = m.d.sync
1474 dbg = self.dbg
1475 pdecode2 = self.pdecode2
1476
1477 # temporaries
1478 core_busy_o = core.n.o_data.busy_o # core is busy
1479 core_ivalid_i = core.p.i_valid # instruction is valid
1480
1481 if hasattr(core, "icache"):
1482 fetch_failed = core.icache.i_out.fetch_failed
1483 else:
1484 fetch_failed = Const(0, 1)
1485
1486 with m.FSM(name="exec_fsm"):
1487
1488 # waiting for instruction bus (stays there until not busy)
1489 with m.State("INSN_START"):
1490 comb += exec_insn_o_ready.eq(1)
1491 with m.If(exec_insn_i_valid):
1492 comb += core_ivalid_i.eq(1) # instruction is valid/issued
1493 sync += self.sv_changed.eq(0)
1494 sync += self.pc_changed.eq(0)
1495 sync += self.msr_changed.eq(0)
1496 with m.If(core.p.o_ready): # only move if accepted
1497 m.next = "INSN_ACTIVE" # move to "wait completion"
1498
1499 # instruction started: must wait till it finishes
1500 with m.State("INSN_ACTIVE"):
1501 # note changes to MSR, PC and SVSTATE, and DEC/TB
1502 # these last two are done together, and passed to the
1503 # DEC/TB FSM
1504 with m.If(self.state_nia.wen & (1 << StateRegs.SVSTATE)):
1505 sync += self.sv_changed.eq(1)
1506 with m.If(self.state_nia.wen & (1 << StateRegs.MSR)):
1507 sync += self.msr_changed.eq(1)
1508 with m.If(self.state_nia.wen & (1 << StateRegs.PC)):
1509 sync += self.pc_changed.eq(1)
1510 with m.If((self.state_spr.wen &
1511 ((1 << StateRegs.DEC) | (1 << StateRegs.TB))).bool()):
1512 comb += self.pause_dec_tb.eq(1)
1513 with m.If(~core_busy_o): # instruction done!
1514 comb += exec_pc_o_valid.eq(1)
1515 with m.If(exec_pc_i_ready):
1516 # when finished, indicate "done".
1517 # however, if there was an exception, the instruction
1518 # is *not* yet done. this is an implementation
1519 # detail: we choose to implement exceptions by
1520 # taking the exception information from the LDST
1521 # unit, putting that *back* into the PowerDecoder2,
1522 # and *re-running the entire instruction*.
1523 # if we erroneously indicate "done" here, it is as if
1524 # there were *TWO* instructions:
1525 # 1) the failed LDST 2) a TRAP.
1526 with m.If(~pdecode2.ldst_exc.happened &
1527 ~pdecode2.instr_fault):
1528 comb += self.insn_done.eq(1)
1529 m.next = "INSN_START" # back to fetch
1530 # terminate returns directly to INSN_START
1531 with m.If(dbg.terminate_i):
1532 # comb += self.insn_done.eq(1) - no because it's not
1533 m.next = "INSN_START" # back to fetch
1534
1535 def elaborate(self, platform):
1536 m = super().elaborate(platform)
1537 # convenience
1538 comb, sync = m.d.comb, m.d.sync
1539 cur_state = self.cur_state
1540 pdecode2 = self.pdecode2
1541 dbg = self.dbg
1542 core = self.core
1543
1544 # set up peripherals and core
1545 core_rst = self.core_rst
1546
1547 # indicate to outside world if any FU is still executing
1548 comb += self.any_busy.eq(core.n.o_data.any_busy_o) # any FU executing
1549
1550 # address of the next instruction, in the absence of a branch
1551 # depends on the instruction size
1552 nia = Signal(64)
1553
1554 # connect up debug signals
1555 with m.If(core.o.core_terminate_o):
1556 comb += dbg.terminate_i.eq(1)
1557
1558 # pass the prefix mode from Fetch to Issue, so the latter can loop
1559 # on VL==0
1560 is_svp64_mode = Signal()
1561
1562 # there are *THREE^WFOUR-if-SVP64-enabled* FSMs, fetch (32/64-bit)
1563 # issue, decode/execute, now joined by "Predicate fetch/calculate".
1564 # these are the handshake signals between each
1565
1566 # fetch FSM can run as soon as the PC is valid
1567 fetch_pc_i_valid = Signal() # Execute tells Fetch "start next read"
1568 fetch_pc_o_ready = Signal() # Fetch Tells SVSTATE "proceed"
1569
1570 # fetch FSM hands over the instruction to be decoded / issued
1571 fetch_insn_o_valid = Signal()
1572 fetch_insn_i_ready = Signal()
1573
1574 # predicate fetch FSM decodes and fetches the predicate
1575 pred_insn_i_valid = Signal()
1576 pred_insn_o_ready = Signal()
1577
1578 # predicate fetch FSM delivers the masks
1579 pred_mask_o_valid = Signal()
1580 pred_mask_i_ready = Signal()
1581
1582 # issue FSM delivers the instruction to the be executed
1583 exec_insn_i_valid = Signal()
1584 exec_insn_o_ready = Signal()
1585
1586 # execute FSM, hands over the PC/SVSTATE back to the issue FSM
1587 exec_pc_o_valid = Signal()
1588 exec_pc_i_ready = Signal()
1589
1590 # the FSMs here are perhaps unusual in that they detect conditions
1591 # then "hold" information, combinatorially, for the core
1592 # (as opposed to using sync - which would be on a clock's delay)
1593 # this includes the actual opcode, valid flags and so on.
1594
1595 # Fetch, then predicate fetch, then Issue, then Execute.
1596 # Issue is where the VL for-loop # lives. the ready/valid
1597 # signalling is used to communicate between the four.
1598
1599 self.fetch_fsm(m, dbg, core, nia, is_svp64_mode,
1600 fetch_pc_o_ready, fetch_pc_i_valid,
1601 fetch_insn_o_valid, fetch_insn_i_ready)
1602
1603 self.issue_fsm(m, core, nia,
1604 dbg, core_rst, is_svp64_mode,
1605 fetch_pc_o_ready, fetch_pc_i_valid,
1606 fetch_insn_o_valid, fetch_insn_i_ready,
1607 pred_insn_i_valid, pred_insn_o_ready,
1608 pred_mask_o_valid, pred_mask_i_ready,
1609 exec_insn_i_valid, exec_insn_o_ready,
1610 exec_pc_o_valid, exec_pc_i_ready)
1611
1612 if self.svp64_en:
1613 self.fetch_predicate_fsm(m,
1614 pred_insn_i_valid, pred_insn_o_ready,
1615 pred_mask_o_valid, pred_mask_i_ready)
1616
1617 self.execute_fsm(m, core,
1618 exec_insn_i_valid, exec_insn_o_ready,
1619 exec_pc_o_valid, exec_pc_i_ready)
1620
1621 # whatever was done above, over-ride it if core reset is held
1622 with m.If(core_rst):
1623 sync += nia.eq(0)
1624
1625 return m
1626
1627
1628 class TestIssuer(Elaboratable):
1629 def __init__(self, pspec):
1630 self.ti = TestIssuerInternal(pspec)
1631 self.pll = DummyPLL(instance=True)
1632
1633 self.dbg_rst_i = Signal(reset_less=True)
1634
1635 # PLL direct clock or not
1636 self.pll_en = hasattr(pspec, "use_pll") and pspec.use_pll
1637 if self.pll_en:
1638 self.pll_test_o = Signal(reset_less=True)
1639 self.pll_vco_o = Signal(reset_less=True)
1640 self.clk_sel_i = Signal(2, reset_less=True)
1641 self.ref_clk = ClockSignal() # can't rename it but that's ok
1642 self.pllclk_clk = ClockSignal("pllclk")
1643
1644 def elaborate(self, platform):
1645 m = Module()
1646 comb = m.d.comb
1647
1648 # TestIssuer nominally runs at main clock, actually it is
1649 # all combinatorial internally except for coresync'd components
1650 m.submodules.ti = ti = self.ti
1651
1652 if self.pll_en:
1653 # ClockSelect runs at PLL output internal clock rate
1654 m.submodules.wrappll = pll = self.pll
1655
1656 # add clock domains from PLL
1657 cd_pll = ClockDomain("pllclk")
1658 m.domains += cd_pll
1659
1660 # PLL clock established. has the side-effect of running clklsel
1661 # at the PLL's speed (see DomainRenamer("pllclk") above)
1662 pllclk = self.pllclk_clk
1663 comb += pllclk.eq(pll.clk_pll_o)
1664
1665 # wire up external 24mhz to PLL
1666 #comb += pll.clk_24_i.eq(self.ref_clk)
1667 # output 18 mhz PLL test signal, and analog oscillator out
1668 comb += self.pll_test_o.eq(pll.pll_test_o)
1669 comb += self.pll_vco_o.eq(pll.pll_vco_o)
1670
1671 # input to pll clock selection
1672 comb += pll.clk_sel_i.eq(self.clk_sel_i)
1673
1674 # now wire up ResetSignals. don't mind them being in this domain
1675 pll_rst = ResetSignal("pllclk")
1676 comb += pll_rst.eq(ResetSignal())
1677
1678 # internal clock is set to selector clock-out. has the side-effect of
1679 # running TestIssuer at this speed (see DomainRenamer("intclk") above)
1680 # debug clock runs at coresync internal clock
1681 if self.ti.dbg_domain != 'sync':
1682 cd_dbgsync = ClockDomain("dbgsync")
1683 intclk = ClockSignal(self.ti.core_domain)
1684 dbgclk = ClockSignal(self.ti.dbg_domain)
1685 # XXX BYPASS PLL XXX
1686 # XXX BYPASS PLL XXX
1687 # XXX BYPASS PLL XXX
1688 if self.pll_en:
1689 comb += intclk.eq(self.ref_clk)
1690 assert self.ti.core_domain != 'sync', \
1691 "cannot set core_domain to sync and use pll at the same time"
1692 else:
1693 if self.ti.core_domain != 'sync':
1694 comb += intclk.eq(ClockSignal())
1695 if self.ti.dbg_domain != 'sync':
1696 dbgclk = ClockSignal(self.ti.dbg_domain)
1697 comb += dbgclk.eq(intclk)
1698 comb += self.ti.dbg_rst_i.eq(self.dbg_rst_i)
1699
1700 return m
1701
1702 def ports(self):
1703 return list(self.ti.ports()) + list(self.pll.ports()) + \
1704 [ClockSignal(), ResetSignal()]
1705
1706 def external_ports(self):
1707 ports = self.ti.external_ports()
1708 ports.append(ClockSignal())
1709 ports.append(ResetSignal())
1710 if self.pll_en:
1711 ports.append(self.clk_sel_i)
1712 ports.append(self.pll.clk_24_i)
1713 ports.append(self.pll_test_o)
1714 ports.append(self.pll_vco_o)
1715 ports.append(self.pllclk_clk)
1716 ports.append(self.ref_clk)
1717 return ports
1718
1719
1720 if __name__ == '__main__':
1721 units = {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1, 'logical': 1,
1722 'spr': 1,
1723 'div': 1,
1724 'mul': 1,
1725 'shiftrot': 1
1726 }
1727 pspec = TestMemPspec(ldst_ifacetype='bare_wb',
1728 imem_ifacetype='bare_wb',
1729 addr_wid=64,
1730 mask_wid=8,
1731 reg_wid=64,
1732 units=units)
1733 dut = TestIssuer(pspec)
1734 vl = main(dut, ports=dut.ports(), name="test_issuer")
1735
1736 if len(sys.argv) == 1:
1737 vl = rtlil.convert(dut, ports=dut.external_ports(), name="test_issuer")
1738 with open("test_issuer.il", "w") as f:
1739 f.write(vl)