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 nmigen
.lib
.coding
import PriorityEncoder
26 from soc
.decoder
.power_decoder
import create_pdecode
27 from soc
.decoder
.power_decoder2
import PowerDecode2
, SVP64PrefixDecoder
28 from soc
.decoder
.decode2execute1
import IssuerDecode2ToOperand
29 from soc
.decoder
.decode2execute1
import Data
30 from soc
.experiment
.testmem
import TestMemory
# test only for instructions
31 from soc
.regfile
.regfiles
import StateRegs
, FastRegs
32 from soc
.simple
.core
import NonProductionCore
33 from soc
.config
.test
.test_loadstore
import TestMemPspec
34 from soc
.config
.ifetch
import ConfigFetchUnit
35 from soc
.decoder
.power_enums
import (MicrOp
, SVP64PredInt
, SVP64PredCR
,
37 from soc
.debug
.dmi
import CoreDebug
, DMIInterface
38 from soc
.debug
.jtag
import JTAG
39 from soc
.config
.pinouts
import get_pinspecs
40 from soc
.config
.state
import CoreState
41 from soc
.interrupts
.xics
import XICS_ICP
, XICS_ICS
42 from soc
.bus
.simple_gpio
import SimpleGPIO
43 from soc
.bus
.SPBlock512W64B8W
import SPBlock512W64B8W
44 from soc
.clock
.select
import ClockSelect
45 from soc
.clock
.dummypll
import DummyPLL
46 from soc
.sv
.svstate
import SVSTATERec
49 from nmutil
.util
import rising_edge
51 def get_insn(f_instr_o
, pc
):
52 if f_instr_o
.width
== 32:
55 # 64-bit: bit 2 of pc decides which word to select
56 return f_instr_o
.word_select(pc
[2], 32)
58 # gets state input or reads from state regfile
59 def state_get(m
, core_rst
, state_i
, name
, regfile
, regnum
):
63 res
= Signal(64, reset_less
=True, name
=name
)
64 res_ok_delay
= Signal(name
="%s_ok_delay" % name
)
66 sync
+= res_ok_delay
.eq(~state_i
.ok
)
67 with m
.If(state_i
.ok
):
68 # incoming override (start from pc_i)
69 comb
+= res
.eq(state_i
.data
)
71 # otherwise read StateRegs regfile for PC...
72 comb
+= regfile
.ren
.eq(1<<regnum
)
73 # ... but on a 1-clock delay
74 with m
.If(res_ok_delay
):
75 comb
+= res
.eq(regfile
.data_o
)
78 def get_predint(m
, mask
, name
):
79 """decode SVP64 predicate integer mask field to reg number and invert
80 this is identical to the equivalent function in ISACaller except that
81 it doesn't read the INT directly, it just decodes "what needs to be done"
82 i.e. which INT reg, whether it is shifted and whether it is bit-inverted.
84 * all1s is set to indicate that no mask is to be applied.
85 * regread indicates the GPR register number to be read
86 * invert is set to indicate that the register value is to be inverted
87 * unary indicates that the contents of the register is to be shifted 1<<r3
90 regread
= Signal(5, name
=name
+"regread")
91 invert
= Signal(name
=name
+"invert")
92 unary
= Signal(name
=name
+"unary")
93 all1s
= Signal(name
=name
+"all1s")
95 with m
.Case(SVP64PredInt
.ALWAYS
.value
):
96 comb
+= all1s
.eq(1) # use 0b1111 (all ones)
97 with m
.Case(SVP64PredInt
.R3_UNARY
.value
):
99 comb
+= unary
.eq(1) # 1<<r3 - shift r3 (single bit)
100 with m
.Case(SVP64PredInt
.R3
.value
):
101 comb
+= regread
.eq(3)
102 with m
.Case(SVP64PredInt
.R3_N
.value
):
103 comb
+= regread
.eq(3)
105 with m
.Case(SVP64PredInt
.R10
.value
):
106 comb
+= regread
.eq(10)
107 with m
.Case(SVP64PredInt
.R10_N
.value
):
108 comb
+= regread
.eq(10)
110 with m
.Case(SVP64PredInt
.R30
.value
):
111 comb
+= regread
.eq(30)
112 with m
.Case(SVP64PredInt
.R30_N
.value
):
113 comb
+= regread
.eq(30)
115 return regread
, invert
, unary
, all1s
117 def get_predcr(m
, mask
, name
):
118 """decode SVP64 predicate CR to reg number field and invert status
119 this is identical to _get_predcr in ISACaller
122 idx
= Signal(2, name
=name
+"idx")
123 invert
= Signal(name
=name
+"crinvert")
125 with m
.Case(SVP64PredCR
.LT
.value
):
128 with m
.Case(SVP64PredCR
.GE
.value
):
131 with m
.Case(SVP64PredCR
.GT
.value
):
134 with m
.Case(SVP64PredCR
.LE
.value
):
137 with m
.Case(SVP64PredCR
.EQ
.value
):
140 with m
.Case(SVP64PredCR
.NE
.value
):
143 with m
.Case(SVP64PredCR
.SO
.value
):
146 with m
.Case(SVP64PredCR
.NS
.value
):
152 class TestIssuerInternal(Elaboratable
):
153 """TestIssuer - reads instructions from TestMemory and issues them
155 efficiency and speed is not the main goal here: functional correctness
156 and code clarity is. optimisations (which almost 100% interfere with
157 easy understanding) come later.
159 def __init__(self
, pspec
):
161 # test is SVP64 is to be enabled
162 self
.svp64_en
= hasattr(pspec
, "svp64") and (pspec
.svp64
== True)
164 # and if regfiles are reduced
165 self
.regreduce_en
= (hasattr(pspec
, "regreduce") and
166 (pspec
.regreduce
== True))
168 # JTAG interface. add this right at the start because if it's
169 # added it *modifies* the pspec, by adding enable/disable signals
170 # for parts of the rest of the core
171 self
.jtag_en
= hasattr(pspec
, "debug") and pspec
.debug
== 'jtag'
173 # XXX MUST keep this up-to-date with litex, and
174 # soc-cocotb-sim, and err.. all needs sorting out, argh
177 'eint', 'gpio', 'mspi0',
178 # 'mspi1', - disabled for now
179 # 'pwm', 'sd0', - disabled for now
181 self
.jtag
= JTAG(get_pinspecs(subset
=subset
))
182 # add signals to pspec to enable/disable icache and dcache
183 # (or data and intstruction wishbone if icache/dcache not included)
184 # https://bugs.libre-soc.org/show_bug.cgi?id=520
185 # TODO: do we actually care if these are not domain-synchronised?
186 # honestly probably not.
187 pspec
.wb_icache_en
= self
.jtag
.wb_icache_en
188 pspec
.wb_dcache_en
= self
.jtag
.wb_dcache_en
189 self
.wb_sram_en
= self
.jtag
.wb_sram_en
191 self
.wb_sram_en
= Const(1)
193 # add 4k sram blocks?
194 self
.sram4x4k
= (hasattr(pspec
, "sram4x4kblock") and
195 pspec
.sram4x4kblock
== True)
199 self
.sram4k
.append(SPBlock512W64B8W(name
="sram4k_%d" % i
,
202 # add interrupt controller?
203 self
.xics
= hasattr(pspec
, "xics") and pspec
.xics
== True
205 self
.xics_icp
= XICS_ICP()
206 self
.xics_ics
= XICS_ICS()
207 self
.int_level_i
= self
.xics_ics
.int_level_i
209 # add GPIO peripheral?
210 self
.gpio
= hasattr(pspec
, "gpio") and pspec
.gpio
== True
212 self
.simple_gpio
= SimpleGPIO()
213 self
.gpio_o
= self
.simple_gpio
.gpio_o
215 # main instruction core. suitable for prototyping / demo only
216 self
.core
= core
= NonProductionCore(pspec
)
218 # instruction decoder. goes into Trap Record
219 pdecode
= create_pdecode()
220 self
.cur_state
= CoreState("cur") # current state (MSR/PC/SVSTATE)
221 self
.pdecode2
= PowerDecode2(pdecode
, state
=self
.cur_state
,
222 opkls
=IssuerDecode2ToOperand
,
223 svp64_en
=self
.svp64_en
,
224 regreduce_en
=self
.regreduce_en
)
226 self
.svp64
= SVP64PrefixDecoder() # for decoding SVP64 prefix
228 # Test Instruction memory
229 self
.imem
= ConfigFetchUnit(pspec
).fu
232 self
.dbg
= CoreDebug()
234 # instruction go/monitor
235 self
.pc_o
= Signal(64, reset_less
=True)
236 self
.pc_i
= Data(64, "pc_i") # set "ok" to indicate "please change me"
237 self
.svstate_i
= Data(32, "svstate_i") # ditto
238 self
.core_bigendian_i
= Signal() # TODO: set based on MSR.LE
239 self
.busy_o
= Signal(reset_less
=True)
240 self
.memerr_o
= Signal(reset_less
=True)
242 # STATE regfile read /write ports for PC, MSR, SVSTATE
243 staterf
= self
.core
.regs
.rf
['state']
244 self
.state_r_pc
= staterf
.r_ports
['cia'] # PC rd
245 self
.state_w_pc
= staterf
.w_ports
['d_wr1'] # PC wr
246 self
.state_r_msr
= staterf
.r_ports
['msr'] # MSR rd
247 self
.state_r_sv
= staterf
.r_ports
['sv'] # SVSTATE rd
248 self
.state_w_sv
= staterf
.w_ports
['sv'] # SVSTATE wr
250 # DMI interface access
251 intrf
= self
.core
.regs
.rf
['int']
252 crrf
= self
.core
.regs
.rf
['cr']
253 xerrf
= self
.core
.regs
.rf
['xer']
254 self
.int_r
= intrf
.r_ports
['dmi'] # INT read
255 self
.cr_r
= crrf
.r_ports
['full_cr_dbg'] # CR read
256 self
.xer_r
= xerrf
.r_ports
['full_xer'] # XER read
260 self
.int_pred
= intrf
.r_ports
['pred'] # INT predicate read
261 self
.cr_pred
= crrf
.r_ports
['cr_pred'] # CR predicate read
263 # hack method of keeping an eye on whether branch/trap set the PC
264 self
.state_nia
= self
.core
.regs
.rf
['state'].w_ports
['nia']
265 self
.state_nia
.wen
.name
= 'state_nia_wen'
267 # pulse to synchronize the simulator at instruction end
268 self
.insn_done
= Signal()
271 # store copies of predicate masks
272 self
.srcmask
= Signal(64)
273 self
.dstmask
= Signal(64)
275 def fetch_fsm(self
, m
, core
, pc
, svstate
, nia
, is_svp64_mode
,
276 fetch_pc_ready_o
, fetch_pc_valid_i
,
277 fetch_insn_valid_o
, fetch_insn_ready_i
):
280 this FSM performs fetch of raw instruction data, partial-decodes
281 it 32-bit at a time to detect SVP64 prefixes, and will optionally
282 read a 2nd 32-bit quantity if that occurs.
286 pdecode2
= self
.pdecode2
287 cur_state
= self
.cur_state
288 dec_opcode_i
= pdecode2
.dec
.raw_opcode_in
# raw opcode
290 msr_read
= Signal(reset
=1)
292 with m
.FSM(name
='fetch_fsm'):
295 with m
.State("IDLE"):
296 comb
+= fetch_pc_ready_o
.eq(1)
297 with m
.If(fetch_pc_valid_i
):
298 # instruction allowed to go: start by reading the PC
299 # capture the PC and also drop it into Insn Memory
300 # we have joined a pair of combinatorial memory
301 # lookups together. this is Generally Bad.
302 comb
+= self
.imem
.a_pc_i
.eq(pc
)
303 comb
+= self
.imem
.a_valid_i
.eq(1)
304 comb
+= self
.imem
.f_valid_i
.eq(1)
305 sync
+= cur_state
.pc
.eq(pc
)
306 sync
+= cur_state
.svstate
.eq(svstate
) # and svstate
308 # initiate read of MSR. arrives one clock later
309 comb
+= self
.state_r_msr
.ren
.eq(1 << StateRegs
.MSR
)
310 sync
+= msr_read
.eq(0)
312 m
.next
= "INSN_READ" # move to "wait for bus" phase
314 # dummy pause to find out why simulation is not keeping up
315 with m
.State("INSN_READ"):
316 # one cycle later, msr/sv read arrives. valid only once.
317 with m
.If(~msr_read
):
318 sync
+= msr_read
.eq(1) # yeah don't read it again
319 sync
+= cur_state
.msr
.eq(self
.state_r_msr
.data_o
)
320 with m
.If(self
.imem
.f_busy_o
): # zzz...
321 # busy: stay in wait-read
322 comb
+= self
.imem
.a_valid_i
.eq(1)
323 comb
+= self
.imem
.f_valid_i
.eq(1)
325 # not busy: instruction fetched
326 insn
= get_insn(self
.imem
.f_instr_o
, cur_state
.pc
)
329 # decode the SVP64 prefix, if any
330 comb
+= svp64
.raw_opcode_in
.eq(insn
)
331 comb
+= svp64
.bigendian
.eq(self
.core_bigendian_i
)
332 # pass the decoded prefix (if any) to PowerDecoder2
333 sync
+= pdecode2
.sv_rm
.eq(svp64
.svp64_rm
)
334 # remember whether this is a prefixed instruction, so
335 # the FSM can readily loop when VL==0
336 sync
+= is_svp64_mode
.eq(svp64
.is_svp64_mode
)
337 # calculate the address of the following instruction
338 insn_size
= Mux(svp64
.is_svp64_mode
, 8, 4)
339 sync
+= nia
.eq(cur_state
.pc
+ insn_size
)
340 with m
.If(~svp64
.is_svp64_mode
):
341 # with no prefix, store the instruction
342 # and hand it directly to the next FSM
343 sync
+= dec_opcode_i
.eq(insn
)
344 m
.next
= "INSN_READY"
346 # fetch the rest of the instruction from memory
347 comb
+= self
.imem
.a_pc_i
.eq(cur_state
.pc
+ 4)
348 comb
+= self
.imem
.a_valid_i
.eq(1)
349 comb
+= self
.imem
.f_valid_i
.eq(1)
350 m
.next
= "INSN_READ2"
352 # not SVP64 - 32-bit only
353 sync
+= nia
.eq(cur_state
.pc
+ 4)
354 sync
+= dec_opcode_i
.eq(insn
)
355 m
.next
= "INSN_READY"
357 with m
.State("INSN_READ2"):
358 with m
.If(self
.imem
.f_busy_o
): # zzz...
359 # busy: stay in wait-read
360 comb
+= self
.imem
.a_valid_i
.eq(1)
361 comb
+= self
.imem
.f_valid_i
.eq(1)
363 # not busy: instruction fetched
364 insn
= get_insn(self
.imem
.f_instr_o
, cur_state
.pc
+4)
365 sync
+= dec_opcode_i
.eq(insn
)
366 m
.next
= "INSN_READY"
367 # TODO: probably can start looking at pdecode2.rm_dec
368 # here or maybe even in INSN_READ state, if svp64_mode
369 # detected, in order to trigger - and wait for - the
372 pmode
= pdecode2
.rm_dec
.predmode
374 if pmode != SVP64PredMode.ALWAYS.value:
375 fire predicate loading FSM and wait before
378 sync += self.srcmask.eq(-1) # set to all 1s
379 sync += self.dstmask.eq(-1) # set to all 1s
380 m.next = "INSN_READY"
383 with m
.State("INSN_READY"):
384 # hand over the instruction, to be decoded
385 comb
+= fetch_insn_valid_o
.eq(1)
386 with m
.If(fetch_insn_ready_i
):
389 def fetch_predicate_fsm(self
, m
,
390 pred_insn_valid_i
, pred_insn_ready_o
,
391 pred_mask_valid_o
, pred_mask_ready_i
):
392 """fetch_predicate_fsm - obtains (constructs in the case of CR)
393 src/dest predicate masks
395 https://bugs.libre-soc.org/show_bug.cgi?id=617
396 the predicates can be read here, by using IntRegs r_ports['pred']
397 or CRRegs r_ports['pred']. in the case of CRs it will have to
398 be done through multiple reads, extracting one relevant at a time.
399 later, a faster way would be to use the 32-bit-wide CR port but
400 this is more complex decoding, here. equivalent code used in
401 ISACaller is "from soc.decoder.isa.caller import get_predcr"
403 note: this ENTIRE FSM is not to be called when svp64 is disabled
407 pdecode2
= self
.pdecode2
408 rm_dec
= pdecode2
.rm_dec
# SVP64RMModeDecode
409 predmode
= rm_dec
.predmode
410 srcpred
, dstpred
= rm_dec
.srcpred
, rm_dec
.dstpred
411 cr_pred
, int_pred
= self
.cr_pred
, self
.int_pred
# read regfiles
412 # get src/dst step, so we can skip already used mask bits
413 cur_state
= self
.cur_state
414 srcstep
= cur_state
.svstate
.srcstep
415 dststep
= cur_state
.svstate
.dststep
417 # elif predmode == CR:
418 # CR-src sidx, sinvert = get_predcr(m, srcpred)
419 # CR-dst didx, dinvert = get_predcr(m, dstpred)
420 # TODO read CR-src and CR-dst into self.srcmask+dstmask with loop
421 # has to cope with first one then the other
422 # for cr_idx = FSM-state-loop(0..VL-1):
423 # FSM-state-trigger-CR-read:
424 # cr_ren = (1<<7-(cr_idx+SVP64CROffs.CRPred))
425 # comb += cr_pred.ren.eq(cr_ren)
426 # FSM-state-1-clock-later-actual-Read:
427 # cr_field = Signal(4)
429 # # read the CR field, select the appropriate bit
430 # comb += cr_field.eq(cr_pred.data_o)
431 # comb += cr_bit.eq(cr_field.bit_select(idx)))
432 # # just like in branch BO tests
433 # comd += self.srcmask[cr_idx].eq(inv ^ cr_bit)
436 sregread
, sinvert
, sunary
, sall1s
= get_predint(m
, srcpred
, 's')
437 dregread
, dinvert
, dunary
, dall1s
= get_predint(m
, dstpred
, 'd')
438 sidx
, scrinvert
= get_predcr(m
, srcpred
, 's')
439 didx
, dcrinvert
= get_predcr(m
, dstpred
, 'd')
441 with m
.FSM(name
="fetch_predicate"):
443 with m
.State("FETCH_PRED_IDLE"):
444 comb
+= pred_insn_ready_o
.eq(1)
445 with m
.If(pred_insn_valid_i
):
446 with m
.If(predmode
== SVP64PredMode
.INT
):
447 # skip fetching destination mask register, when zero
449 sync
+= self
.dstmask
.eq(-1)
450 # directly go to fetch source mask register
451 # guaranteed not to be zero (otherwise predmode
452 # would be SVP64PredMode.ALWAYS, not INT)
453 comb
+= int_pred
.addr
.eq(sregread
)
454 comb
+= int_pred
.ren
.eq(1)
455 m
.next
= "INT_SRC_READ"
456 # fetch destination predicate register
458 comb
+= int_pred
.addr
.eq(dregread
)
459 comb
+= int_pred
.ren
.eq(1)
460 m
.next
= "INT_DST_READ"
462 sync
+= self
.srcmask
.eq(-1)
463 sync
+= self
.dstmask
.eq(-1)
464 m
.next
= "FETCH_PRED_DONE"
466 with m
.State("INT_DST_READ"):
467 # store destination mask
468 inv
= Repl(dinvert
, 64)
469 new_dstmask
= Signal(64)
471 # set selected mask bit for 1<<r3 mode
472 dst_shift
= Signal(range(64))
473 comb
+= dst_shift
.eq(self
.int_pred
.data_o
& 0b111111)
474 comb
+= new_dstmask
.eq(1 << dst_shift
)
476 # invert mask if requested
477 comb
+= new_dstmask
.eq(self
.int_pred
.data_o ^ inv
)
478 # shift-out already used mask bits
479 sync
+= self
.dstmask
.eq(new_dstmask
>> dststep
)
480 # skip fetching source mask register, when zero
482 sync
+= self
.srcmask
.eq(-1)
483 m
.next
= "FETCH_PRED_DONE"
484 # fetch source predicate register
486 comb
+= int_pred
.addr
.eq(sregread
)
487 comb
+= int_pred
.ren
.eq(1)
488 m
.next
= "INT_SRC_READ"
490 with m
.State("INT_SRC_READ"):
492 inv
= Repl(sinvert
, 64)
493 new_srcmask
= Signal(64)
495 # set selected mask bit for 1<<r3 mode
496 src_shift
= Signal(range(64))
497 comb
+= src_shift
.eq(self
.int_pred
.data_o
& 0b111111)
498 comb
+= new_srcmask
.eq(1 << src_shift
)
500 # invert mask if requested
501 comb
+= new_srcmask
.eq(self
.int_pred
.data_o ^ inv
)
502 # shift-out already used mask bits
503 sync
+= self
.srcmask
.eq(new_srcmask
>> srcstep
)
504 m
.next
= "FETCH_PRED_DONE"
506 with m
.State("FETCH_PRED_DONE"):
507 comb
+= pred_mask_valid_o
.eq(1)
508 with m
.If(pred_mask_ready_i
):
509 m
.next
= "FETCH_PRED_IDLE"
511 def issue_fsm(self
, m
, core
, pc_changed
, sv_changed
, nia
,
512 dbg
, core_rst
, is_svp64_mode
,
513 fetch_pc_ready_o
, fetch_pc_valid_i
,
514 fetch_insn_valid_o
, fetch_insn_ready_i
,
515 pred_insn_valid_i
, pred_insn_ready_o
,
516 pred_mask_valid_o
, pred_mask_ready_i
,
517 exec_insn_valid_i
, exec_insn_ready_o
,
518 exec_pc_valid_o
, exec_pc_ready_i
):
521 decode / issue FSM. this interacts with the "fetch" FSM
522 through fetch_insn_ready/valid (incoming) and fetch_pc_ready/valid
523 (outgoing). also interacts with the "execute" FSM
524 through exec_insn_ready/valid (outgoing) and exec_pc_ready/valid
526 SVP64 RM prefixes have already been set up by the
527 "fetch" phase, so execute is fairly straightforward.
532 pdecode2
= self
.pdecode2
533 cur_state
= self
.cur_state
536 dec_opcode_i
= pdecode2
.dec
.raw_opcode_in
# raw opcode
538 # for updating svstate (things like srcstep etc.)
539 update_svstate
= Signal() # set this (below) if updating
540 new_svstate
= SVSTATERec("new_svstate")
541 comb
+= new_svstate
.eq(cur_state
.svstate
)
543 # precalculate srcstep+1 and dststep+1
544 cur_srcstep
= cur_state
.svstate
.srcstep
545 cur_dststep
= cur_state
.svstate
.dststep
546 next_srcstep
= Signal
.like(cur_srcstep
)
547 next_dststep
= Signal
.like(cur_dststep
)
548 comb
+= next_srcstep
.eq(cur_state
.svstate
.srcstep
+1)
549 comb
+= next_dststep
.eq(cur_state
.svstate
.dststep
+1)
551 with m
.FSM(name
="issue_fsm"):
553 # sync with the "fetch" phase which is reading the instruction
554 # at this point, there is no instruction running, that
555 # could inadvertently update the PC.
556 with m
.State("ISSUE_START"):
557 # wait on "core stop" release, before next fetch
558 # need to do this here, in case we are in a VL==0 loop
559 with m
.If(~dbg
.core_stop_o
& ~core_rst
):
560 comb
+= fetch_pc_valid_i
.eq(1) # tell fetch to start
561 with m
.If(fetch_pc_ready_o
): # fetch acknowledged us
564 # tell core it's stopped, and acknowledge debug handshake
565 comb
+= dbg
.core_stopped_i
.eq(1)
566 # while stopped, allow updating the PC and SVSTATE
567 with m
.If(self
.pc_i
.ok
):
568 comb
+= self
.state_w_pc
.wen
.eq(1 << StateRegs
.PC
)
569 comb
+= self
.state_w_pc
.data_i
.eq(self
.pc_i
.data
)
570 sync
+= pc_changed
.eq(1)
571 with m
.If(self
.svstate_i
.ok
):
572 comb
+= new_svstate
.eq(self
.svstate_i
.data
)
573 comb
+= update_svstate
.eq(1)
574 sync
+= sv_changed
.eq(1)
576 # wait for an instruction to arrive from Fetch
577 with m
.State("INSN_WAIT"):
578 comb
+= fetch_insn_ready_i
.eq(1)
579 with m
.If(fetch_insn_valid_o
):
580 # loop into ISSUE_START if it's a SVP64 instruction
581 # and VL == 0. this because VL==0 is a for-loop
582 # from 0 to 0 i.e. always, always a NOP.
583 cur_vl
= cur_state
.svstate
.vl
584 with m
.If(is_svp64_mode
& (cur_vl
== 0)):
585 # update the PC before fetching the next instruction
586 # since we are in a VL==0 loop, no instruction was
587 # executed that we could be overwriting
588 comb
+= self
.state_w_pc
.wen
.eq(1 << StateRegs
.PC
)
589 comb
+= self
.state_w_pc
.data_i
.eq(nia
)
590 comb
+= self
.insn_done
.eq(1)
591 m
.next
= "ISSUE_START"
594 m
.next
= "PRED_START" # start fetching predicate
596 m
.next
= "DECODE_SV" # skip predication
598 with m
.State("PRED_START"):
599 comb
+= pred_insn_valid_i
.eq(1) # tell fetch_pred to start
600 with m
.If(pred_insn_ready_o
): # fetch_pred acknowledged us
603 with m
.State("MASK_WAIT"):
604 comb
+= pred_mask_ready_i
.eq(1) # ready to receive the masks
605 with m
.If(pred_mask_valid_o
): # predication masks are ready
608 # skip zeros in predicate
609 with m
.State("PRED_SKIP"):
610 with m
.If(~is_svp64_mode
):
611 m
.next
= "DECODE_SV" # nothing to do
614 pred_src_zero
= pdecode2
.rm_dec
.pred_sz
615 pred_dst_zero
= pdecode2
.rm_dec
.pred_dz
617 # new srcstep, after skipping zeros
618 skip_srcstep
= Signal
.like(cur_srcstep
)
619 # value to be added to the current srcstep
620 src_delta
= Signal
.like(cur_srcstep
)
621 # add leading zeros to srcstep, if not in zero mode
622 with m
.If(~pred_src_zero
):
623 # priority encoder (count leading zeros)
624 # append guard bit, in case the mask is all zeros
625 pri_enc_src
= PriorityEncoder(65)
626 m
.submodules
.pri_enc_src
= pri_enc_src
627 comb
+= pri_enc_src
.i
.eq(Cat(self
.srcmask
,
629 comb
+= src_delta
.eq(pri_enc_src
.o
)
630 # apply delta to srcstep
631 comb
+= skip_srcstep
.eq(cur_srcstep
+ src_delta
)
632 # shift-out all leading zeros from the mask
633 # plus the leading "one" bit
634 # TODO count leading zeros and shift-out the zero
635 # bits, in the same step, in hardware
636 sync
+= self
.srcmask
.eq(self
.srcmask
>> (src_delta
+1))
638 # same as above, but for dststep
639 skip_dststep
= Signal
.like(cur_dststep
)
640 dst_delta
= Signal
.like(cur_dststep
)
641 with m
.If(~pred_dst_zero
):
642 pri_enc_dst
= PriorityEncoder(65)
643 m
.submodules
.pri_enc_dst
= pri_enc_dst
644 comb
+= pri_enc_dst
.i
.eq(Cat(self
.dstmask
,
646 comb
+= dst_delta
.eq(pri_enc_dst
.o
)
647 comb
+= skip_dststep
.eq(cur_dststep
+ dst_delta
)
648 sync
+= self
.dstmask
.eq(self
.dstmask
>> (dst_delta
+1))
650 # TODO: initialize mask[VL]=1 to avoid passing past VL
651 with m
.If((skip_srcstep
>= cur_vl
) |
652 (skip_dststep
>= cur_vl
)):
653 # end of VL loop. Update PC and reset src/dst step
654 comb
+= self
.state_w_pc
.wen
.eq(1 << StateRegs
.PC
)
655 comb
+= self
.state_w_pc
.data_i
.eq(nia
)
656 comb
+= new_svstate
.srcstep
.eq(0)
657 comb
+= new_svstate
.dststep
.eq(0)
658 comb
+= update_svstate
.eq(1)
659 # synchronize with the simulator
660 comb
+= self
.insn_done
.eq(1)
662 m
.next
= "ISSUE_START"
664 # update new src/dst step
665 comb
+= new_svstate
.srcstep
.eq(skip_srcstep
)
666 comb
+= new_svstate
.dststep
.eq(skip_dststep
)
667 comb
+= update_svstate
.eq(1)
671 # after src/dst step have been updated, we are ready
672 # to decode the instruction
673 with m
.State("DECODE_SV"):
674 # decode the instruction
675 sync
+= core
.e
.eq(pdecode2
.e
)
676 sync
+= core
.state
.eq(cur_state
)
677 sync
+= core
.raw_insn_i
.eq(dec_opcode_i
)
678 sync
+= core
.bigendian_i
.eq(self
.core_bigendian_i
)
679 # set RA_OR_ZERO detection in satellite decoders
680 sync
+= core
.sv_a_nz
.eq(pdecode2
.sv_a_nz
)
681 m
.next
= "INSN_EXECUTE" # move to "execute"
683 # handshake with execution FSM, move to "wait" once acknowledged
684 with m
.State("INSN_EXECUTE"):
685 comb
+= exec_insn_valid_i
.eq(1) # trigger execute
686 with m
.If(exec_insn_ready_o
): # execute acknowledged us
687 m
.next
= "EXECUTE_WAIT"
689 with m
.State("EXECUTE_WAIT"):
690 # wait on "core stop" release, at instruction end
691 # need to do this here, in case we are in a VL>1 loop
692 with m
.If(~dbg
.core_stop_o
& ~core_rst
):
693 comb
+= exec_pc_ready_i
.eq(1)
694 with m
.If(exec_pc_valid_o
):
696 # was this the last loop iteration?
698 cur_vl
= cur_state
.svstate
.vl
699 comb
+= is_last
.eq(next_srcstep
== cur_vl
)
701 # if either PC or SVSTATE were changed by the previous
702 # instruction, go directly back to Fetch, without
703 # updating either PC or SVSTATE
704 with m
.If(pc_changed | sv_changed
):
705 m
.next
= "ISSUE_START"
707 # also return to Fetch, when no output was a vector
708 # (regardless of SRCSTEP and VL), or when the last
709 # instruction was really the last one of the VL loop
710 with m
.Elif((~pdecode2
.loop_continue
) | is_last
):
711 # before going back to fetch, update the PC state
712 # register with the NIA.
713 # ok here we are not reading the branch unit.
714 # TODO: this just blithely overwrites whatever
715 # pipeline updated the PC
716 comb
+= self
.state_w_pc
.wen
.eq(1 << StateRegs
.PC
)
717 comb
+= self
.state_w_pc
.data_i
.eq(nia
)
718 # reset SRCSTEP before returning to Fetch
720 with m
.If(pdecode2
.loop_continue
):
721 comb
+= new_svstate
.srcstep
.eq(0)
722 comb
+= new_svstate
.dststep
.eq(0)
723 comb
+= update_svstate
.eq(1)
725 comb
+= new_svstate
.srcstep
.eq(0)
726 comb
+= new_svstate
.dststep
.eq(0)
727 comb
+= update_svstate
.eq(1)
728 m
.next
= "ISSUE_START"
730 # returning to Execute? then, first update SRCSTEP
732 comb
+= new_svstate
.srcstep
.eq(next_srcstep
)
733 comb
+= new_svstate
.dststep
.eq(next_dststep
)
734 comb
+= update_svstate
.eq(1)
735 # return to mask skip loop
739 comb
+= dbg
.core_stopped_i
.eq(1)
740 # while stopped, allow updating the PC and SVSTATE
741 with m
.If(self
.pc_i
.ok
):
742 comb
+= self
.state_w_pc
.wen
.eq(1 << StateRegs
.PC
)
743 comb
+= self
.state_w_pc
.data_i
.eq(self
.pc_i
.data
)
744 sync
+= pc_changed
.eq(1)
745 with m
.If(self
.svstate_i
.ok
):
746 comb
+= new_svstate
.eq(self
.svstate_i
.data
)
747 comb
+= update_svstate
.eq(1)
748 sync
+= sv_changed
.eq(1)
750 # check if svstate needs updating: if so, write it to State Regfile
751 with m
.If(update_svstate
):
752 comb
+= self
.state_w_sv
.wen
.eq(1<<StateRegs
.SVSTATE
)
753 comb
+= self
.state_w_sv
.data_i
.eq(new_svstate
)
754 sync
+= cur_state
.svstate
.eq(new_svstate
) # for next clock
756 def execute_fsm(self
, m
, core
, pc_changed
, sv_changed
,
757 exec_insn_valid_i
, exec_insn_ready_o
,
758 exec_pc_valid_o
, exec_pc_ready_i
):
761 execute FSM. this interacts with the "issue" FSM
762 through exec_insn_ready/valid (incoming) and exec_pc_ready/valid
763 (outgoing). SVP64 RM prefixes have already been set up by the
764 "issue" phase, so execute is fairly straightforward.
769 pdecode2
= self
.pdecode2
772 core_busy_o
= core
.busy_o
# core is busy
773 core_ivalid_i
= core
.ivalid_i
# instruction is valid
774 core_issue_i
= core
.issue_i
# instruction is issued
775 insn_type
= core
.e
.do
.insn_type
# instruction MicroOp type
777 with m
.FSM(name
="exec_fsm"):
779 # waiting for instruction bus (stays there until not busy)
780 with m
.State("INSN_START"):
781 comb
+= exec_insn_ready_o
.eq(1)
782 with m
.If(exec_insn_valid_i
):
783 comb
+= core_ivalid_i
.eq(1) # instruction is valid
784 comb
+= core_issue_i
.eq(1) # and issued
785 sync
+= sv_changed
.eq(0)
786 sync
+= pc_changed
.eq(0)
787 m
.next
= "INSN_ACTIVE" # move to "wait completion"
789 # instruction started: must wait till it finishes
790 with m
.State("INSN_ACTIVE"):
791 with m
.If(insn_type
!= MicrOp
.OP_NOP
):
792 comb
+= core_ivalid_i
.eq(1) # instruction is valid
793 # note changes to PC and SVSTATE
794 with m
.If(self
.state_nia
.wen
& (1<<StateRegs
.SVSTATE
)):
795 sync
+= sv_changed
.eq(1)
796 with m
.If(self
.state_nia
.wen
& (1<<StateRegs
.PC
)):
797 sync
+= pc_changed
.eq(1)
798 with m
.If(~core_busy_o
): # instruction done!
799 comb
+= exec_pc_valid_o
.eq(1)
800 with m
.If(exec_pc_ready_i
):
801 comb
+= self
.insn_done
.eq(1)
802 m
.next
= "INSN_START" # back to fetch
804 def setup_peripherals(self
, m
):
805 comb
, sync
= m
.d
.comb
, m
.d
.sync
807 m
.submodules
.core
= core
= DomainRenamer("coresync")(self
.core
)
808 m
.submodules
.imem
= imem
= self
.imem
809 m
.submodules
.dbg
= dbg
= self
.dbg
811 m
.submodules
.jtag
= jtag
= self
.jtag
812 # TODO: UART2GDB mux, here, from external pin
813 # see https://bugs.libre-soc.org/show_bug.cgi?id=499
814 sync
+= dbg
.dmi
.connect_to(jtag
.dmi
)
816 cur_state
= self
.cur_state
818 # 4x 4k SRAM blocks. these simply "exist", they get routed in litex
820 for i
, sram
in enumerate(self
.sram4k
):
821 m
.submodules
["sram4k_%d" % i
] = sram
822 comb
+= sram
.enable
.eq(self
.wb_sram_en
)
824 # XICS interrupt handler
826 m
.submodules
.xics_icp
= icp
= self
.xics_icp
827 m
.submodules
.xics_ics
= ics
= self
.xics_ics
828 comb
+= icp
.ics_i
.eq(ics
.icp_o
) # connect ICS to ICP
829 sync
+= cur_state
.eint
.eq(icp
.core_irq_o
) # connect ICP to core
831 # GPIO test peripheral
833 m
.submodules
.simple_gpio
= simple_gpio
= self
.simple_gpio
835 # connect one GPIO output to ICS bit 15 (like in microwatt soc.vhdl)
836 # XXX causes litex ECP5 test to get wrong idea about input and output
837 # (but works with verilator sim *sigh*)
838 #if self.gpio and self.xics:
839 # comb += self.int_level_i[15].eq(simple_gpio.gpio_o[0])
841 # instruction decoder
842 pdecode
= create_pdecode()
843 m
.submodules
.dec2
= pdecode2
= self
.pdecode2
845 m
.submodules
.svp64
= svp64
= self
.svp64
848 dmi
, d_reg
, d_cr
, d_xer
, = dbg
.dmi
, dbg
.d_gpr
, dbg
.d_cr
, dbg
.d_xer
849 intrf
= self
.core
.regs
.rf
['int']
851 # clock delay power-on reset
852 cd_por
= ClockDomain(reset_less
=True)
853 cd_sync
= ClockDomain()
854 core_sync
= ClockDomain("coresync")
855 m
.domains
+= cd_por
, cd_sync
, core_sync
857 ti_rst
= Signal(reset_less
=True)
858 delay
= Signal(range(4), reset
=3)
859 with m
.If(delay
!= 0):
860 m
.d
.por
+= delay
.eq(delay
- 1)
861 comb
+= cd_por
.clk
.eq(ClockSignal())
863 # power-on reset delay
864 core_rst
= ResetSignal("coresync")
865 comb
+= ti_rst
.eq(delay
!= 0 | dbg
.core_rst_o |
ResetSignal())
866 comb
+= core_rst
.eq(ti_rst
)
868 # busy/halted signals from core
869 comb
+= self
.busy_o
.eq(core
.busy_o
)
870 comb
+= pdecode2
.dec
.bigendian
.eq(self
.core_bigendian_i
)
872 # temporary hack: says "go" immediately for both address gen and ST
874 ldst
= core
.fus
.fus
['ldst0']
875 st_go_edge
= rising_edge(m
, ldst
.st
.rel_o
)
876 m
.d
.comb
+= ldst
.ad
.go_i
.eq(ldst
.ad
.rel_o
) # link addr-go direct to rel
877 m
.d
.comb
+= ldst
.st
.go_i
.eq(st_go_edge
) # link store-go to rising rel
881 def elaborate(self
, platform
):
884 comb
, sync
= m
.d
.comb
, m
.d
.sync
885 cur_state
= self
.cur_state
886 pdecode2
= self
.pdecode2
890 # set up peripherals and core
891 core_rst
= self
.setup_peripherals(m
)
893 # reset current state if core reset requested
895 m
.d
.sync
+= self
.cur_state
.eq(0)
897 # PC and instruction from I-Memory
898 comb
+= self
.pc_o
.eq(cur_state
.pc
)
899 pc_changed
= Signal() # note write to PC
900 sv_changed
= Signal() # note write to SVSTATE
902 # read state either from incoming override or from regfile
903 # TODO: really should be doing MSR in the same way
904 pc
= state_get(m
, core_rst
, self
.pc_i
,
906 self
.state_r_pc
, StateRegs
.PC
)
907 svstate
= state_get(m
, core_rst
, self
.svstate_i
,
908 "svstate", # read SVSTATE
909 self
.state_r_sv
, StateRegs
.SVSTATE
)
911 # don't write pc every cycle
912 comb
+= self
.state_w_pc
.wen
.eq(0)
913 comb
+= self
.state_w_pc
.data_i
.eq(0)
915 # don't read msr every cycle
916 comb
+= self
.state_r_msr
.ren
.eq(0)
918 # address of the next instruction, in the absence of a branch
919 # depends on the instruction size
922 # connect up debug signals
923 # TODO comb += core.icache_rst_i.eq(dbg.icache_rst_o)
924 comb
+= dbg
.terminate_i
.eq(core
.core_terminate_o
)
925 comb
+= dbg
.state
.pc
.eq(pc
)
926 comb
+= dbg
.state
.svstate
.eq(svstate
)
927 comb
+= dbg
.state
.msr
.eq(cur_state
.msr
)
929 # pass the prefix mode from Fetch to Issue, so the latter can loop
931 is_svp64_mode
= Signal()
933 # there are *THREE* FSMs, fetch (32/64-bit) issue, decode/execute.
934 # these are the handshake signals between fetch and decode/execute
936 # fetch FSM can run as soon as the PC is valid
937 fetch_pc_valid_i
= Signal() # Execute tells Fetch "start next read"
938 fetch_pc_ready_o
= Signal() # Fetch Tells SVSTATE "proceed"
940 # fetch FSM hands over the instruction to be decoded / issued
941 fetch_insn_valid_o
= Signal()
942 fetch_insn_ready_i
= Signal()
944 # predicate fetch FSM decodes and fetches the predicate
945 pred_insn_valid_i
= Signal()
946 pred_insn_ready_o
= Signal()
948 # predicate fetch FSM delivers the masks
949 pred_mask_valid_o
= Signal()
950 pred_mask_ready_i
= Signal()
952 # issue FSM delivers the instruction to the be executed
953 exec_insn_valid_i
= Signal()
954 exec_insn_ready_o
= Signal()
956 # execute FSM, hands over the PC/SVSTATE back to the issue FSM
957 exec_pc_valid_o
= Signal()
958 exec_pc_ready_i
= Signal()
960 # the FSMs here are perhaps unusual in that they detect conditions
961 # then "hold" information, combinatorially, for the core
962 # (as opposed to using sync - which would be on a clock's delay)
963 # this includes the actual opcode, valid flags and so on.
965 # Fetch, then predicate fetch, then Issue, then Execute.
966 # Issue is where the VL for-loop # lives. the ready/valid
967 # signalling is used to communicate between the four.
969 self
.fetch_fsm(m
, core
, pc
, svstate
, nia
, is_svp64_mode
,
970 fetch_pc_ready_o
, fetch_pc_valid_i
,
971 fetch_insn_valid_o
, fetch_insn_ready_i
)
973 self
.issue_fsm(m
, core
, pc_changed
, sv_changed
, nia
,
974 dbg
, core_rst
, is_svp64_mode
,
975 fetch_pc_ready_o
, fetch_pc_valid_i
,
976 fetch_insn_valid_o
, fetch_insn_ready_i
,
977 pred_insn_valid_i
, pred_insn_ready_o
,
978 pred_mask_valid_o
, pred_mask_ready_i
,
979 exec_insn_valid_i
, exec_insn_ready_o
,
980 exec_pc_valid_o
, exec_pc_ready_i
)
983 self
.fetch_predicate_fsm(m
,
984 pred_insn_valid_i
, pred_insn_ready_o
,
985 pred_mask_valid_o
, pred_mask_ready_i
)
987 self
.execute_fsm(m
, core
, pc_changed
, sv_changed
,
988 exec_insn_valid_i
, exec_insn_ready_o
,
989 exec_pc_valid_o
, exec_pc_ready_i
)
991 # whatever was done above, over-ride it if core reset is held
995 # this bit doesn't have to be in the FSM: connect up to read
996 # regfiles on demand from DMI
999 # DEC and TB inc/dec FSM. copy of DEC is put into CoreState,
1000 # (which uses that in PowerDecoder2 to raise 0x900 exception)
1001 self
.tb_dec_fsm(m
, cur_state
.dec
)
1005 def do_dmi(self
, m
, dbg
):
1006 """deals with DMI debug requests
1008 currently only provides read requests for the INT regfile, CR and XER
1009 it will later also deal with *writing* to these regfiles.
1013 dmi
, d_reg
, d_cr
, d_xer
, = dbg
.dmi
, dbg
.d_gpr
, dbg
.d_cr
, dbg
.d_xer
1014 intrf
= self
.core
.regs
.rf
['int']
1016 with m
.If(d_reg
.req
): # request for regfile access being made
1017 # TODO: error-check this
1018 # XXX should this be combinatorial? sync better?
1020 comb
+= self
.int_r
.ren
.eq(1<<d_reg
.addr
)
1022 comb
+= self
.int_r
.addr
.eq(d_reg
.addr
)
1023 comb
+= self
.int_r
.ren
.eq(1)
1024 d_reg_delay
= Signal()
1025 sync
+= d_reg_delay
.eq(d_reg
.req
)
1026 with m
.If(d_reg_delay
):
1027 # data arrives one clock later
1028 comb
+= d_reg
.data
.eq(self
.int_r
.data_o
)
1029 comb
+= d_reg
.ack
.eq(1)
1031 # sigh same thing for CR debug
1032 with m
.If(d_cr
.req
): # request for regfile access being made
1033 comb
+= self
.cr_r
.ren
.eq(0b11111111) # enable all
1034 d_cr_delay
= Signal()
1035 sync
+= d_cr_delay
.eq(d_cr
.req
)
1036 with m
.If(d_cr_delay
):
1037 # data arrives one clock later
1038 comb
+= d_cr
.data
.eq(self
.cr_r
.data_o
)
1039 comb
+= d_cr
.ack
.eq(1)
1042 with m
.If(d_xer
.req
): # request for regfile access being made
1043 comb
+= self
.xer_r
.ren
.eq(0b111111) # enable all
1044 d_xer_delay
= Signal()
1045 sync
+= d_xer_delay
.eq(d_xer
.req
)
1046 with m
.If(d_xer_delay
):
1047 # data arrives one clock later
1048 comb
+= d_xer
.data
.eq(self
.xer_r
.data_o
)
1049 comb
+= d_xer
.ack
.eq(1)
1051 def tb_dec_fsm(self
, m
, spr_dec
):
1054 this is a FSM for updating either dec or tb. it runs alternately
1055 DEC, TB, DEC, TB. note that SPR pipeline could have written a new
1056 value to DEC, however the regfile has "passthrough" on it so this
1059 see v3.0B p1097-1099 for Timeer Resource and p1065 and p1076
1062 comb
, sync
= m
.d
.comb
, m
.d
.sync
1063 fast_rf
= self
.core
.regs
.rf
['fast']
1064 fast_r_dectb
= fast_rf
.r_ports
['issue'] # DEC/TB
1065 fast_w_dectb
= fast_rf
.w_ports
['issue'] # DEC/TB
1067 with m
.FSM() as fsm
:
1069 # initiates read of current DEC
1070 with m
.State("DEC_READ"):
1071 comb
+= fast_r_dectb
.addr
.eq(FastRegs
.DEC
)
1072 comb
+= fast_r_dectb
.ren
.eq(1)
1073 m
.next
= "DEC_WRITE"
1075 # waits for DEC read to arrive (1 cycle), updates with new value
1076 with m
.State("DEC_WRITE"):
1077 new_dec
= Signal(64)
1078 # TODO: MSR.LPCR 32-bit decrement mode
1079 comb
+= new_dec
.eq(fast_r_dectb
.data_o
- 1)
1080 comb
+= fast_w_dectb
.addr
.eq(FastRegs
.DEC
)
1081 comb
+= fast_w_dectb
.wen
.eq(1)
1082 comb
+= fast_w_dectb
.data_i
.eq(new_dec
)
1083 sync
+= spr_dec
.eq(new_dec
) # copy into cur_state for decoder
1086 # initiates read of current TB
1087 with m
.State("TB_READ"):
1088 comb
+= fast_r_dectb
.addr
.eq(FastRegs
.TB
)
1089 comb
+= fast_r_dectb
.ren
.eq(1)
1092 # waits for read TB to arrive, initiates write of current TB
1093 with m
.State("TB_WRITE"):
1095 comb
+= new_tb
.eq(fast_r_dectb
.data_o
+ 1)
1096 comb
+= fast_w_dectb
.addr
.eq(FastRegs
.TB
)
1097 comb
+= fast_w_dectb
.wen
.eq(1)
1098 comb
+= fast_w_dectb
.data_i
.eq(new_tb
)
1104 yield from self
.pc_i
.ports()
1107 yield from self
.core
.ports()
1108 yield from self
.imem
.ports()
1109 yield self
.core_bigendian_i
1115 def external_ports(self
):
1116 ports
= self
.pc_i
.ports()
1117 ports
+= [self
.pc_o
, self
.memerr_o
, self
.core_bigendian_i
, self
.busy_o
,
1121 ports
+= list(self
.jtag
.external_ports())
1123 # don't add DMI if JTAG is enabled
1124 ports
+= list(self
.dbg
.dmi
.ports())
1126 ports
+= list(self
.imem
.ibus
.fields
.values())
1127 ports
+= list(self
.core
.l0
.cmpi
.lsmem
.lsi
.slavebus
.fields
.values())
1130 for sram
in self
.sram4k
:
1131 ports
+= list(sram
.bus
.fields
.values())
1134 ports
+= list(self
.xics_icp
.bus
.fields
.values())
1135 ports
+= list(self
.xics_ics
.bus
.fields
.values())
1136 ports
.append(self
.int_level_i
)
1139 ports
+= list(self
.simple_gpio
.bus
.fields
.values())
1140 ports
.append(self
.gpio_o
)
1148 class TestIssuer(Elaboratable
):
1149 def __init__(self
, pspec
):
1150 self
.ti
= TestIssuerInternal(pspec
)
1152 self
.pll
= DummyPLL()
1154 # PLL direct clock or not
1155 self
.pll_en
= hasattr(pspec
, "use_pll") and pspec
.use_pll
1157 self
.pll_18_o
= Signal(reset_less
=True)
1159 def elaborate(self
, platform
):
1163 # TestIssuer runs at direct clock
1164 m
.submodules
.ti
= ti
= self
.ti
1165 cd_int
= ClockDomain("coresync")
1168 # ClockSelect runs at PLL output internal clock rate
1169 m
.submodules
.pll
= pll
= self
.pll
1171 # add clock domains from PLL
1172 cd_pll
= ClockDomain("pllclk")
1175 # PLL clock established. has the side-effect of running clklsel
1176 # at the PLL's speed (see DomainRenamer("pllclk") above)
1177 pllclk
= ClockSignal("pllclk")
1178 comb
+= pllclk
.eq(pll
.clk_pll_o
)
1180 # wire up external 24mhz to PLL
1181 comb
+= pll
.clk_24_i
.eq(ClockSignal())
1183 # output 18 mhz PLL test signal
1184 comb
+= self
.pll_18_o
.eq(pll
.pll_18_o
)
1186 # now wire up ResetSignals. don't mind them being in this domain
1187 pll_rst
= ResetSignal("pllclk")
1188 comb
+= pll_rst
.eq(ResetSignal())
1190 # internal clock is set to selector clock-out. has the side-effect of
1191 # running TestIssuer at this speed (see DomainRenamer("intclk") above)
1192 intclk
= ClockSignal("coresync")
1194 comb
+= intclk
.eq(pll
.clk_pll_o
)
1196 comb
+= intclk
.eq(ClockSignal())
1201 return list(self
.ti
.ports()) + list(self
.pll
.ports()) + \
1202 [ClockSignal(), ResetSignal()]
1204 def external_ports(self
):
1205 ports
= self
.ti
.external_ports()
1206 ports
.append(ClockSignal())
1207 ports
.append(ResetSignal())
1209 ports
.append(self
.pll
.clk_sel_i
)
1210 ports
.append(self
.pll_18_o
)
1211 ports
.append(self
.pll
.pll_ana_o
)
1215 if __name__
== '__main__':
1216 units
= {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1, 'logical': 1,
1222 pspec
= TestMemPspec(ldst_ifacetype
='bare_wb',
1223 imem_ifacetype
='bare_wb',
1228 dut
= TestIssuer(pspec
)
1229 vl
= main(dut
, ports
=dut
.ports(), name
="test_issuer")
1231 if len(sys
.argv
) == 1:
1232 vl
= rtlil
.convert(dut
, ports
=dut
.external_ports(), name
="test_issuer")
1233 with
open("test_issuer.il", "w") as f
: