3 not in any way intended for production use. this runs a FSM that:
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
10 * does it all over again
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
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
24 from nmutil
.singlepipe
import ControlBase
25 from soc
.simple
.core_data
import FetchOutput
, FetchInput
27 from nmigen
.lib
.coding
import PriorityEncoder
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
,
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
53 from nmutil
.util
import rising_edge
56 def get_insn(f_instr_o
, pc
):
57 if f_instr_o
.width
== 32:
60 # 64-bit: bit 2 of pc decides which word to select
61 return f_instr_o
.word_select(pc
[2], 32)
63 # gets state input or reads from state regfile
66 def state_get(m
, res
, core_rst
, state_i
, name
, regfile
, regnum
):
69 # read the {insert state variable here}
70 res_ok_delay
= Signal(name
="%s_ok_delay" % name
)
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
)
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
)
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.
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
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")
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)
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)
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)
121 return regread
, invert
, unary
, all1s
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
129 idx
= Signal(2, name
=name
+"idx")
130 invert
= Signal(name
=name
+"crinvert")
132 with m
.Case(SVP64PredCR
.LT
.value
):
133 comb
+= idx
.eq(CR
.LT
)
135 with m
.Case(SVP64PredCR
.GE
.value
):
136 comb
+= idx
.eq(CR
.LT
)
138 with m
.Case(SVP64PredCR
.GT
.value
):
139 comb
+= idx
.eq(CR
.GT
)
141 with m
.Case(SVP64PredCR
.LE
.value
):
142 comb
+= idx
.eq(CR
.GT
)
144 with m
.Case(SVP64PredCR
.EQ
.value
):
145 comb
+= idx
.eq(CR
.EQ
)
147 with m
.Case(SVP64PredCR
.NE
.value
):
148 comb
+= idx
.eq(CR
.EQ
)
150 with m
.Case(SVP64PredCR
.SO
.value
):
151 comb
+= idx
.eq(CR
.SO
)
153 with m
.Case(SVP64PredCR
.NS
.value
):
154 comb
+= idx
.eq(CR
.SO
)
159 class TestIssuerBase(Elaboratable
):
160 """TestIssuerBase - common base class for Issuers
162 takes care of power-on reset, peripherals, debug, DEC/TB,
163 and gets PC/MSR/SVSTATE from the State Regfile etc.
166 def __init__(self
, pspec
):
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)
173 if self
.microwatt_compat
:
174 self
.microwatt_old
= False
175 self
.microwatt_debug
= True # set to False when using an FPGA
177 # test is SVP64 is to be enabled
178 self
.svp64_en
= hasattr(pspec
, "svp64") and (pspec
.svp64
== True)
180 # and if regfiles are reduced
181 self
.regreduce_en
= (hasattr(pspec
, "regreduce") and
182 (pspec
.regreduce
== True))
184 # and if overlap requested
185 self
.allow_overlap
= (hasattr(pspec
, "allow_overlap") and
186 (pspec
.allow_overlap
== True))
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
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
201 # XXX MUST keep this up-to-date with litex, and
202 # soc-cocotb-sim, and err.. all needs sorting out, argh
205 'eint', 'gpio', 'mspi0',
206 # 'mspi1', - disabled for now
207 # 'pwm', 'sd0', - disabled for now
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
220 self
.wb_sram_en
= Const(1)
222 # add 4k sram blocks?
223 self
.sram4x4k
= (hasattr(pspec
, "sram4x4kblock") and
224 pspec
.sram4x4kblock
== True)
228 self
.sram4k
.append(SPBlock512W64B8W(name
="sram4k_%d" % i
,
232 # add interrupt controller?
233 self
.xics
= hasattr(pspec
, "xics") and pspec
.xics
== True
235 self
.xics_icp
= XICS_ICP()
236 self
.xics_ics
= XICS_ICS()
237 self
.int_level_i
= self
.xics_ics
.int_level_i
239 self
.ext_irq
= Signal()
241 # add GPIO peripheral?
242 self
.gpio
= hasattr(pspec
, "gpio") and pspec
.gpio
== True
244 self
.simple_gpio
= SimpleGPIO()
245 self
.gpio_o
= self
.simple_gpio
.gpio_o
247 # main instruction core. suitable for prototyping / demo only
248 self
.core
= core
= NonProductionCore(pspec
)
249 self
.core_rst
= ResetSignal(self
.core_domain
)
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
261 self
.svp64
= SVP64PrefixDecoder() # for decoding SVP64 prefix
263 self
.update_svstate
= Signal() # set this if updating svstate
264 self
.new_svstate
= new_svstate
= SVSTATERec("new_svstate")
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
274 self
.dbg
= CoreDebug()
275 self
.dbg_rst_i
= Signal(reset_less
=True)
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)
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
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
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
308 self
.int_pred
= intrf
.r_ports
['pred'] # INT predicate read
309 self
.cr_pred
= crrf
.r_ports
['cr_pred'] # CR predicate read
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']
317 # pulse to synchronize the simulator at instruction end
318 self
.insn_done
= Signal()
320 # indicate any instruction still outstanding, in execution
321 self
.any_busy
= Signal()
324 # store copies of predicate masks
325 self
.srcmask
= Signal(64)
326 self
.dstmask
= Signal(64)
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')
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)
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()
349 def setup_peripherals(self
, m
):
350 comb
, sync
= m
.d
.comb
, m
.d
.sync
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
)
359 if self
.microwatt_compat
:
360 m
.submodules
.core
= core
= self
.core
362 m
.submodules
.core
= core
= csd(self
.core
)
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
)
369 # set up JTAG Debug Module (in correct domain)
370 m
.submodules
.dbg
= dbg
= dbd(self
.dbg
)
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
)
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())
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
))
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
)
405 cur_state
= self
.cur_state
407 # 4x 4k SRAM blocks. these simply "exist", they get routed in litex
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
)
413 # XICS interrupt handler
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
420 sync
+= cur_state
.eint
.eq(self
.ext_irq
) # connect externally
422 # GPIO test peripheral
424 m
.submodules
.simple_gpio
= simple_gpio
= csd(self
.simple_gpio
)
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])
432 # instruction decoder
433 pdecode
= create_pdecode()
434 m
.submodules
.dec2
= pdecode2
= csd(self
.pdecode2
)
436 m
.submodules
.svp64
= svp64
= csd(self
.svp64
)
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
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())
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
)
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)
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
)
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
)
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
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
489 def do_dmi(self
, m
, dbg
):
490 """deals with DMI debug requests
492 currently only provides read requests for the INT regfile, CR and XER
493 it will later also deal with *writing* to these regfiles.
497 dmi
, d_reg
, d_cr
, d_xer
, = dbg
.dmi
, dbg
.d_gpr
, dbg
.d_cr
, dbg
.d_xer
499 intrf
= self
.core
.regs
.rf
['int']
500 fastrf
= self
.core
.regs
.rf
['fast']
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?
506 comb
+= self
.int_r
.ren
.eq(1 << d_reg
.addr
)
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)
518 with m
.If(d_fast
.req
): # request for regfile access being made
520 comb
+= self
.fast_r
.ren
.eq(1 << d_fast
.addr
)
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)
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)
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)
551 def tb_dec_fsm(self
, m
, spr_dec
):
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
559 see v3.0B p1097-1099 for Timer Resource and p1065 and p1076
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
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
):
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
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
)
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
):
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
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
)
612 def elaborate(self
, platform
):
615 comb
, sync
= m
.d
.comb
, m
.d
.sync
616 cur_state
= self
.cur_state
617 pdecode2
= self
.pdecode2
620 # set up peripherals and core
621 core_rst
= self
.core_rst
622 self
.setup_peripherals(m
)
624 # reset current state if core reset requested
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
)
631 # check halted condition: requested PC to execute matches DMI stop addr
632 # and immediately stop. address of 0xffff_ffff_ffff_ffff can never
635 comb
+= halted
.eq(dbg
.stop_addr_o
== dbg
.state
.pc
)
637 comb
+= dbg
.core_stopped_i
.eq(1)
638 comb
+= dbg
.terminate_i
.eq(1)
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
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
,
650 self
.state_r_msr
, StateRegs
.MSR
)
651 state_get(m
, state
.pc
, core_rst
, self
.pc_i
,
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
)
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)
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
)
667 # this bit doesn't have to be in the FSM: connect up to read
668 # regfiles on demand from DMI
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
)
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)
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'
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'
729 yield from self
.pc_i
.ports()
730 yield from self
.msr_i
.ports()
733 yield from self
.core
.ports()
734 yield from self
.imem
.ports()
735 yield self
.core_bigendian_i
741 def external_ports(self
):
742 if self
.microwatt_compat
:
743 ports
= [self
.core
.o
.core_terminate_o
,
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
,
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']:
756 for name
, sig
in self
.core
.l0
.cmpi
.wb_bus().fields
.items():
757 if name
not in ['err', 'bte', 'cti', 'adr']:
759 # microwatt non-compliant with wishbone
760 ports
.append(self
.ibus_adr
)
761 ports
.append(self
.dbus_adr
)
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
,
770 ports
+= list(self
.jtag
.external_ports())
772 # don't add DMI if JTAG is enabled
773 ports
+= list(self
.dbg
.dmi
.ports())
775 ports
+= list(self
.imem
.ibus
.fields
.values())
776 ports
+= list(self
.core
.l0
.cmpi
.wb_bus().fields
.values())
779 for sram
in self
.sram4k
:
780 ports
+= list(sram
.bus
.fields
.values())
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
)
787 ports
.append(self
.ext_irq
)
790 ports
+= list(self
.simple_gpio
.bus
.fields
.values())
791 ports
.append(self
.gpio_o
)
799 class TestIssuerInternal(TestIssuerBase
):
800 """TestIssuer - reads instructions from TestMemory and issues them
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.
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
):
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.
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
823 # also note instruction fetch failed
824 if hasattr(core
, "icache"):
825 fetch_failed
= core
.icache
.i_out
.fetch_failed
828 fetch_failed
= Const(0, 1)
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)
836 with m
.FSM(name
='fetch_fsm'):
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
):
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
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
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
866 #if self.allow_overlap:
867 # stopping = dbg.stopping_o
869 # stopping: jump back to idle
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)
879 # not busy (or fetch failed!): instruction fetched
880 # when fetch failed, the instruction gets ignored
882 if hasattr(core
, "icache"):
883 # blech, icache returns actual instruction
884 insn
= self
.imem
.f_instr_o
886 # but these return raw memory
887 insn
= get_insn(self
.imem
.f_instr_o
, cur_state
.pc
)
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"
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"
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"
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)
931 # not busy: instruction fetched
932 if hasattr(core
, "icache"):
933 # blech, icache returns actual instruction
934 insn
= self
.imem
.f_instr_o
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
944 pmode
= pdecode2
.rm_dec
.predmode
946 if pmode != SVP64PredMode.ALWAYS.value:
947 fire predicate loading FSM and wait before
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"
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
):
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
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"
976 note: this ENTIRE FSM is not to be called when svp64 is disabled
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
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')
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)
1003 with m
.FSM(name
="fetch_predicate"):
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
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
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)
1029 sync
+= self
.srcmask
.eq(-1)
1030 sync
+= self
.dstmask
.eq(-1)
1031 m
.next
= "FETCH_PRED_DONE"
1033 with m
.State("INT_DST_READ"):
1034 # store destination mask
1035 inv
= Repl(dinvert
, 64)
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
)
1042 # invert mask if requested
1043 sync
+= new_dstmask
.eq(self
.int_pred
.o_data ^ inv
)
1044 # skip fetching source mask register, when zero
1046 sync
+= new_srcmask
.eq(-1)
1047 m
.next
= "FETCH_PRED_SHIFT_MASK"
1048 # fetch source predicate register
1050 comb
+= int_pred
.addr
.eq(sregread
)
1051 comb
+= int_pred
.ren
.eq(1)
1052 m
.next
= "INT_SRC_READ"
1054 with m
.State("INT_SRC_READ"):
1056 inv
= Repl(sinvert
, 64)
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
)
1063 # invert mask if requested
1064 sync
+= new_srcmask
.eq(self
.int_pred
.o_data ^ inv
)
1065 m
.next
= "FETCH_PRED_SHIFT_MASK"
1067 # fetch masks from the CR register file
1068 # implements the following loop:
1069 # idx, inv = get_predcr(mask)
1071 # for cr_idx in range(vl):
1072 # cr = crl[cr_idx + SVP64CROffs.CRPred] # takes one cycle
1074 # mask |= 1 << cr_idx
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 ...
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)
1096 sync
+= cr_read
.eq(0)
1097 sync
+= cr_idx
.eq(0)
1098 m
.next
= "FETCH_PRED_SHIFT_MASK"
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)
1107 comb
+= cr_field
.eq(cr_pred
.o_data
)
1108 comb
+= scr_bit
.eq(cr_field
.bit_select(sidx
, 1)
1110 comb
+= dcr_bit
.eq(cr_field
.bit_select(didx
, 1)
1112 # set the corresponding mask bit
1113 bit_to_set
= Signal
.like(self
.srcmask
)
1114 comb
+= bit_to_set
.eq(1 << cur_cr_idx
)
1116 sync
+= new_srcmask
.eq(new_srcmask | bit_to_set
)
1118 sync
+= new_dstmask
.eq(new_dstmask | bit_to_set
)
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"
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"
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
):
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
1146 SVP64 RM prefixes have already been set up by the
1147 "fetch" phase, so execute is fairly straightforward.
1152 pdecode2
= self
.pdecode2
1153 cur_state
= self
.cur_state
1154 new_svstate
= self
.new_svstate
1157 dec_opcode_i
= pdecode2
.dec
.raw_opcode_in
# raw opcode
1159 # for updating svstate (things like srcstep etc.)
1160 comb
+= new_svstate
.eq(cur_state
.svstate
)
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)
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
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)
1183 fetch_failed
= Const(0, 1)
1184 flush_needed
= False
1186 sync
+= fetch_pc_i_valid
.eq(0)
1188 with m
.FSM(name
="issue_fsm"):
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"
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)
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
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"
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)
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"
1246 m
.next
= "PRED_START" # fetching predicate
1248 m
.next
= "DECODE_SV" # skip predication
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"
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"
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
1266 pred_src_zero
= pdecode2
.rm_dec
.pred_sz
1267 pred_dst_zero
= pdecode2
.rm_dec
.pred_dz
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
,
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))
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
,
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))
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)
1314 m
.next
= "ISSUE_START"
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)
1321 m
.next
= "DECODE_SV"
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])
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
)
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)
1351 m
.next
= "INSN_EXECUTE" # move to "execute"
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
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"
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)
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"
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")
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)
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
)
1401 with m
.If(exec_pc_o_valid
):
1403 # was this the last loop iteration?
1405 cur_vl
= cur_state
.svstate
.vl
1406 comb
+= is_last
.eq(next_srcstep
== cur_vl
)
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"
1413 # return directly to Decode if Execute generated an
1415 with m
.Elif(pdecode2
.ldst_exc
.happened
):
1416 m
.next
= "DECODE_SV"
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 |
1423 m
.next
= "ISSUE_START"
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
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)
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"
1448 # returning to Execute? then, first update SRCSTEP
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"
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
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
):
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.
1475 pdecode2
= self
.pdecode2
1478 core_busy_o
= core
.n
.o_data
.busy_o
# core is busy
1479 core_ivalid_i
= core
.p
.i_valid
# instruction is valid
1481 if hasattr(core
, "icache"):
1482 fetch_failed
= core
.icache
.i_out
.fetch_failed
1484 fetch_failed
= Const(0, 1)
1486 with m
.FSM(name
="exec_fsm"):
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"
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
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
1535 def elaborate(self
, platform
):
1536 m
= super().elaborate(platform
)
1538 comb
, sync
= m
.d
.comb
, m
.d
.sync
1539 cur_state
= self
.cur_state
1540 pdecode2
= self
.pdecode2
1544 # set up peripherals and core
1545 core_rst
= self
.core_rst
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
1550 # address of the next instruction, in the absence of a branch
1551 # depends on the instruction size
1554 # connect up debug signals
1555 with m
.If(core
.o
.core_terminate_o
):
1556 comb
+= dbg
.terminate_i
.eq(1)
1558 # pass the prefix mode from Fetch to Issue, so the latter can loop
1560 is_svp64_mode
= Signal()
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
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"
1570 # fetch FSM hands over the instruction to be decoded / issued
1571 fetch_insn_o_valid
= Signal()
1572 fetch_insn_i_ready
= Signal()
1574 # predicate fetch FSM decodes and fetches the predicate
1575 pred_insn_i_valid
= Signal()
1576 pred_insn_o_ready
= Signal()
1578 # predicate fetch FSM delivers the masks
1579 pred_mask_o_valid
= Signal()
1580 pred_mask_i_ready
= Signal()
1582 # issue FSM delivers the instruction to the be executed
1583 exec_insn_i_valid
= Signal()
1584 exec_insn_o_ready
= Signal()
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()
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.
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.
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
)
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
)
1613 self
.fetch_predicate_fsm(m
,
1614 pred_insn_i_valid
, pred_insn_o_ready
,
1615 pred_mask_o_valid
, pred_mask_i_ready
)
1617 self
.execute_fsm(m
, core
,
1618 exec_insn_i_valid
, exec_insn_o_ready
,
1619 exec_pc_o_valid
, exec_pc_i_ready
)
1621 # whatever was done above, over-ride it if core reset is held
1622 with m
.If(core_rst
):
1628 class TestIssuer(Elaboratable
):
1629 def __init__(self
, pspec
):
1630 self
.ti
= TestIssuerInternal(pspec
)
1631 self
.pll
= DummyPLL(instance
=True)
1633 self
.dbg_rst_i
= Signal(reset_less
=True)
1635 # PLL direct clock or not
1636 self
.pll_en
= hasattr(pspec
, "use_pll") and pspec
.use_pll
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")
1644 def elaborate(self
, platform
):
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
1653 # ClockSelect runs at PLL output internal clock rate
1654 m
.submodules
.wrappll
= pll
= self
.pll
1656 # add clock domains from PLL
1657 cd_pll
= ClockDomain("pllclk")
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
)
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
)
1671 # input to pll clock selection
1672 comb
+= pll
.clk_sel_i
.eq(self
.clk_sel_i
)
1674 # now wire up ResetSignals. don't mind them being in this domain
1675 pll_rst
= ResetSignal("pllclk")
1676 comb
+= pll_rst
.eq(ResetSignal())
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
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"
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
)
1703 return list(self
.ti
.ports()) + list(self
.pll
.ports()) + \
1704 [ClockSignal(), ResetSignal()]
1706 def external_ports(self
):
1707 ports
= self
.ti
.external_ports()
1708 ports
.append(ClockSignal())
1709 ports
.append(ResetSignal())
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
)
1720 if __name__
== '__main__':
1721 units
= {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1, 'logical': 1,
1727 pspec
= TestMemPspec(ldst_ifacetype
='bare_wb',
1728 imem_ifacetype
='bare_wb',
1733 dut
= TestIssuer(pspec
)
1734 vl
= main(dut
, ports
=dut
.ports(), name
="test_issuer")
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
: