sort out pc reset when DMI interface requests reset
[soc.git] / src / soc / simple / issuer.py
1 """simple core issuer
2
3 not in any way intended for production use. this runs a FSM that:
4
5 * reads the Program Counter from StateRegs
6 * reads an instruction from a fixed-size Test Memory
7 * issues it to the Simple Core
8 * waits for it to complete
9 * increments the PC
10 * does it all over again
11
12 the purpose of this module is to verify the functional correctness
13 of the Function Units in the absolute simplest and clearest possible
14 way, and to at provide something that can be further incrementally
15 improved.
16 """
17
18 from nmigen import (Elaboratable, Module, Signal, ClockSignal, ResetSignal,
19 ClockDomain, DomainRenamer, Mux, Const, Repl, Cat)
20 from nmigen.cli import rtlil
21 from nmigen.cli import main
22 import sys
23
24 from nmigen.lib.coding import PriorityEncoder
25
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,
36 SVP64PredMode)
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
47
48
49 from nmutil.util import rising_edge
50
51 def get_insn(f_instr_o, pc):
52 if f_instr_o.width == 32:
53 return f_instr_o
54 else:
55 # 64-bit: bit 2 of pc decides which word to select
56 return f_instr_o.word_select(pc[2], 32)
57
58 # gets state input or reads from state regfile
59 def state_get(m, core_rst, state_i, name, regfile, regnum):
60 comb = m.d.comb
61 sync = m.d.sync
62 # read the PC
63 res = Signal(64, reset_less=True, name=name)
64 res_ok_delay = Signal(name="%s_ok_delay" % name)
65 with m.If(~core_rst):
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)
70 with m.Else():
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)
76 return res
77
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.
83
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
88 """
89 comb = m.d.comb
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")
94 with m.Switch(mask):
95 with m.Case(SVP64PredInt.ALWAYS.value):
96 comb += all1s.eq(1) # use 0b1111 (all ones)
97 with m.Case(SVP64PredInt.R3_UNARY.value):
98 comb += regread.eq(3)
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)
104 comb += invert.eq(1)
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)
109 comb += invert.eq(1)
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)
114 comb += invert.eq(1)
115 return regread, invert, unary, all1s
116
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
120 """
121 comb = m.d.comb
122 idx = Signal(2, name=name+"idx")
123 invert = Signal(name=name+"crinvert")
124 with m.Switch(mask):
125 with m.Case(SVP64PredCR.LT.value):
126 comb += idx.eq(0)
127 comb += invert.eq(1)
128 with m.Case(SVP64PredCR.GE.value):
129 comb += idx.eq(0)
130 comb += invert.eq(0)
131 with m.Case(SVP64PredCR.GT.value):
132 comb += idx.eq(1)
133 comb += invert.eq(1)
134 with m.Case(SVP64PredCR.LE.value):
135 comb += idx.eq(1)
136 comb += invert.eq(0)
137 with m.Case(SVP64PredCR.EQ.value):
138 comb += idx.eq(2)
139 comb += invert.eq(1)
140 with m.Case(SVP64PredCR.NE.value):
141 comb += idx.eq(1)
142 comb += invert.eq(0)
143 with m.Case(SVP64PredCR.SO.value):
144 comb += idx.eq(3)
145 comb += invert.eq(1)
146 with m.Case(SVP64PredCR.NS.value):
147 comb += idx.eq(3)
148 comb += invert.eq(0)
149 return idx, invert
150
151
152 class TestIssuerInternal(Elaboratable):
153 """TestIssuer - reads instructions from TestMemory and issues them
154
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.
158 """
159 def __init__(self, pspec):
160
161 # test is SVP64 is to be enabled
162 self.svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
163
164 # and if regfiles are reduced
165 self.regreduce_en = (hasattr(pspec, "regreduce") and
166 (pspec.regreduce == True))
167
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'
172 if self.jtag_en:
173 # XXX MUST keep this up-to-date with litex, and
174 # soc-cocotb-sim, and err.. all needs sorting out, argh
175 subset = ['uart',
176 'mtwi',
177 'eint', 'gpio', 'mspi0',
178 # 'mspi1', - disabled for now
179 # 'pwm', 'sd0', - disabled for now
180 'sdr']
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
190 else:
191 self.wb_sram_en = Const(1)
192
193 # add 4k sram blocks?
194 self.sram4x4k = (hasattr(pspec, "sram4x4kblock") and
195 pspec.sram4x4kblock == True)
196 if self.sram4x4k:
197 self.sram4k = []
198 for i in range(4):
199 self.sram4k.append(SPBlock512W64B8W(name="sram4k_%d" % i,
200 features={'err'}))
201
202 # add interrupt controller?
203 self.xics = hasattr(pspec, "xics") and pspec.xics == True
204 if self.xics:
205 self.xics_icp = XICS_ICP()
206 self.xics_ics = XICS_ICS()
207 self.int_level_i = self.xics_ics.int_level_i
208
209 # add GPIO peripheral?
210 self.gpio = hasattr(pspec, "gpio") and pspec.gpio == True
211 if self.gpio:
212 self.simple_gpio = SimpleGPIO()
213 self.gpio_o = self.simple_gpio.gpio_o
214
215 # main instruction core. suitable for prototyping / demo only
216 self.core = core = NonProductionCore(pspec)
217
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)
225 if self.svp64_en:
226 self.svp64 = SVP64PrefixDecoder() # for decoding SVP64 prefix
227
228 # Test Instruction memory
229 self.imem = ConfigFetchUnit(pspec).fu
230
231 # DMI interface
232 self.dbg = CoreDebug()
233
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)
241
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
249
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
257
258 if self.svp64_en:
259 # for predication
260 self.int_pred = intrf.r_ports['pred'] # INT predicate read
261 self.cr_pred = crrf.r_ports['cr_pred'] # CR predicate read
262
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'
266
267 # pulse to synchronize the simulator at instruction end
268 self.insn_done = Signal()
269
270 if self.svp64_en:
271 # store copies of predicate masks
272 self.srcmask = Signal(64)
273 self.dstmask = Signal(64)
274
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):
278 """fetch FSM
279
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.
283 """
284 comb = m.d.comb
285 sync = m.d.sync
286 pdecode2 = self.pdecode2
287 cur_state = self.cur_state
288 dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode
289
290 msr_read = Signal(reset=1)
291
292 with m.FSM(name='fetch_fsm'):
293
294 # waiting (zzz)
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
307
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)
311
312 m.next = "INSN_READ" # move to "wait for bus" phase
313
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)
324 with m.Else():
325 # not busy: instruction fetched
326 insn = get_insn(self.imem.f_instr_o, cur_state.pc)
327 if self.svp64_en:
328 svp64 = self.svp64
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"
345 with m.Else():
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"
351 else:
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"
356
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)
362 with m.Else():
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
370 # predicate reading.
371 if self.svp64_en:
372 pmode = pdecode2.rm_dec.predmode
373 """
374 if pmode != SVP64PredMode.ALWAYS.value:
375 fire predicate loading FSM and wait before
376 moving to INSN_READY
377 else:
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"
381 """
382
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):
387 m.next = "IDLE"
388
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
394
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"
402
403 note: this ENTIRE FSM is not to be called when svp64 is disabled
404 """
405 comb = m.d.comb
406 sync = m.d.sync
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
416
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)
428 # cr_bit = Signal(1)
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)
434
435 # decode predicates
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')
440
441 with m.FSM(name="fetch_predicate"):
442
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
448 with m.If(dall1s):
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
457 with m.Else():
458 comb += int_pred.addr.eq(dregread)
459 comb += int_pred.ren.eq(1)
460 m.next = "INT_DST_READ"
461 with m.Else():
462 sync += self.srcmask.eq(-1)
463 sync += self.dstmask.eq(-1)
464 m.next = "FETCH_PRED_DONE"
465
466 with m.State("INT_DST_READ"):
467 # store destination mask
468 inv = Repl(dinvert, 64)
469 new_dstmask = Signal(64)
470 # invert mask if requested
471 comb += new_dstmask.eq(self.int_pred.data_o ^ inv)
472 # shift-out already used mask bits
473 sync += self.dstmask.eq(new_dstmask >> dststep)
474 # skip fetching source mask register, when zero
475 with m.If(sall1s):
476 sync += self.srcmask.eq(-1)
477 m.next = "FETCH_PRED_DONE"
478 # fetch source predicate register
479 with m.Else():
480 comb += int_pred.addr.eq(sregread)
481 comb += int_pred.ren.eq(1)
482 m.next = "INT_SRC_READ"
483
484 with m.State("INT_SRC_READ"):
485 # store source mask
486 inv = Repl(sinvert, 64)
487 new_srcmask = Signal(64)
488 # invert mask if requested
489 comb += new_srcmask.eq(self.int_pred.data_o ^ inv)
490 # shift-out already used mask bits
491 sync += self.srcmask.eq(new_srcmask >> srcstep)
492 m.next = "FETCH_PRED_DONE"
493
494 with m.State("FETCH_PRED_DONE"):
495 comb += pred_mask_valid_o.eq(1)
496 with m.If(pred_mask_ready_i):
497 m.next = "FETCH_PRED_IDLE"
498
499 def issue_fsm(self, m, core, pc_changed, sv_changed, nia,
500 dbg, core_rst, is_svp64_mode,
501 fetch_pc_ready_o, fetch_pc_valid_i,
502 fetch_insn_valid_o, fetch_insn_ready_i,
503 pred_insn_valid_i, pred_insn_ready_o,
504 pred_mask_valid_o, pred_mask_ready_i,
505 exec_insn_valid_i, exec_insn_ready_o,
506 exec_pc_valid_o, exec_pc_ready_i):
507 """issue FSM
508
509 decode / issue FSM. this interacts with the "fetch" FSM
510 through fetch_insn_ready/valid (incoming) and fetch_pc_ready/valid
511 (outgoing). also interacts with the "execute" FSM
512 through exec_insn_ready/valid (outgoing) and exec_pc_ready/valid
513 (incoming).
514 SVP64 RM prefixes have already been set up by the
515 "fetch" phase, so execute is fairly straightforward.
516 """
517
518 comb = m.d.comb
519 sync = m.d.sync
520 pdecode2 = self.pdecode2
521 cur_state = self.cur_state
522
523 # temporaries
524 dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode
525
526 # for updating svstate (things like srcstep etc.)
527 update_svstate = Signal() # set this (below) if updating
528 new_svstate = SVSTATERec("new_svstate")
529 comb += new_svstate.eq(cur_state.svstate)
530
531 # precalculate srcstep+1 and dststep+1
532 cur_srcstep = cur_state.svstate.srcstep
533 cur_dststep = cur_state.svstate.dststep
534 next_srcstep = Signal.like(cur_srcstep)
535 next_dststep = Signal.like(cur_dststep)
536 comb += next_srcstep.eq(cur_state.svstate.srcstep+1)
537 comb += next_dststep.eq(cur_state.svstate.dststep+1)
538
539 with m.FSM(name="issue_fsm"):
540
541 # sync with the "fetch" phase which is reading the instruction
542 # at this point, there is no instruction running, that
543 # could inadvertently update the PC.
544 with m.State("ISSUE_START"):
545 # wait on "core stop" release, before next fetch
546 # need to do this here, in case we are in a VL==0 loop
547 with m.If(~dbg.core_stop_o & ~core_rst):
548 comb += fetch_pc_valid_i.eq(1) # tell fetch to start
549 with m.If(fetch_pc_ready_o): # fetch acknowledged us
550 m.next = "INSN_WAIT"
551 with m.Else():
552 # tell core it's stopped, and acknowledge debug handshake
553 comb += core.core_stopped_i.eq(1)
554 comb += dbg.core_stopped_i.eq(1)
555 # while stopped, allow updating the PC and SVSTATE
556 with m.If(self.pc_i.ok):
557 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
558 comb += self.state_w_pc.data_i.eq(self.pc_i.data)
559 sync += pc_changed.eq(1)
560 with m.If(self.svstate_i.ok):
561 comb += new_svstate.eq(self.svstate_i.data)
562 comb += update_svstate.eq(1)
563 sync += sv_changed.eq(1)
564
565 # wait for an instruction to arrive from Fetch
566 with m.State("INSN_WAIT"):
567 comb += fetch_insn_ready_i.eq(1)
568 with m.If(fetch_insn_valid_o):
569 # loop into ISSUE_START if it's a SVP64 instruction
570 # and VL == 0. this because VL==0 is a for-loop
571 # from 0 to 0 i.e. always, always a NOP.
572 cur_vl = cur_state.svstate.vl
573 with m.If(is_svp64_mode & (cur_vl == 0)):
574 # update the PC before fetching the next instruction
575 # since we are in a VL==0 loop, no instruction was
576 # executed that we could be overwriting
577 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
578 comb += self.state_w_pc.data_i.eq(nia)
579 comb += self.insn_done.eq(1)
580 m.next = "ISSUE_START"
581 with m.Else():
582 if self.svp64_en:
583 m.next = "PRED_START" # start fetching predicate
584 else:
585 m.next = "DECODE_SV" # skip predication
586
587 with m.State("PRED_START"):
588 comb += pred_insn_valid_i.eq(1) # tell fetch_pred to start
589 with m.If(pred_insn_ready_o): # fetch_pred acknowledged us
590 m.next = "MASK_WAIT"
591
592 with m.State("MASK_WAIT"):
593 comb += pred_mask_ready_i.eq(1) # ready to receive the masks
594 with m.If(pred_mask_valid_o): # predication masks are ready
595 m.next = "PRED_SKIP"
596
597 # skip zeros in predicate
598 with m.State("PRED_SKIP"):
599 with m.If(~is_svp64_mode):
600 m.next = "DECODE_SV" # nothing to do
601 with m.Else():
602 if self.svp64_en:
603 pred_src_zero = pdecode2.rm_dec.pred_sz
604 pred_dst_zero = pdecode2.rm_dec.pred_dz
605
606 # new srcstep, after skipping zeros
607 skip_srcstep = Signal.like(cur_srcstep)
608 # value to be added to the current srcstep
609 src_delta = Signal.like(cur_srcstep)
610 # add leading zeros to srcstep, if not in zero mode
611 with m.If(~pred_src_zero):
612 # priority encoder (count leading zeros)
613 # append guard bit, in case the mask is all zeros
614 pri_enc_src = PriorityEncoder(65)
615 m.submodules.pri_enc_src = pri_enc_src
616 comb += pri_enc_src.i.eq(Cat(self.srcmask,
617 Const(1, 1)))
618 comb += src_delta.eq(pri_enc_src.o)
619 # apply delta to srcstep
620 comb += skip_srcstep.eq(cur_srcstep + src_delta)
621 # shift-out all leading zeros from the mask
622 # plus the leading "one" bit
623 # TODO count leading zeros and shift-out the zero
624 # bits, in the same step, in hardware
625 sync += self.srcmask.eq(self.srcmask >> (src_delta+1))
626
627 # same as above, but for dststep
628 skip_dststep = Signal.like(cur_dststep)
629 dst_delta = Signal.like(cur_dststep)
630 with m.If(~pred_dst_zero):
631 pri_enc_dst = PriorityEncoder(65)
632 m.submodules.pri_enc_dst = pri_enc_dst
633 comb += pri_enc_dst.i.eq(Cat(self.dstmask,
634 Const(1, 1)))
635 comb += dst_delta.eq(pri_enc_dst.o)
636 comb += skip_dststep.eq(cur_dststep + dst_delta)
637 sync += self.dstmask.eq(self.dstmask >> (dst_delta+1))
638
639 # TODO: initialize mask[VL]=1 to avoid passing past VL
640 with m.If((skip_srcstep >= cur_vl) |
641 (skip_dststep >= cur_vl)):
642 # end of VL loop. Update PC and reset src/dst step
643 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
644 comb += self.state_w_pc.data_i.eq(nia)
645 comb += new_svstate.srcstep.eq(0)
646 comb += new_svstate.dststep.eq(0)
647 comb += update_svstate.eq(1)
648 # synchronize with the simulator
649 comb += self.insn_done.eq(1)
650 # go back to Issue
651 m.next = "ISSUE_START"
652 with m.Else():
653 # update new src/dst step
654 comb += new_svstate.srcstep.eq(skip_srcstep)
655 comb += new_svstate.dststep.eq(skip_dststep)
656 comb += update_svstate.eq(1)
657 # proceed to Decode
658 m.next = "DECODE_SV"
659
660 # after src/dst step have been updated, we are ready
661 # to decode the instruction
662 with m.State("DECODE_SV"):
663 # decode the instruction
664 sync += core.e.eq(pdecode2.e)
665 sync += core.state.eq(cur_state)
666 sync += core.raw_insn_i.eq(dec_opcode_i)
667 sync += core.bigendian_i.eq(self.core_bigendian_i)
668 # set RA_OR_ZERO detection in satellite decoders
669 sync += core.sv_a_nz.eq(pdecode2.sv_a_nz)
670 m.next = "INSN_EXECUTE" # move to "execute"
671
672 # handshake with execution FSM, move to "wait" once acknowledged
673 with m.State("INSN_EXECUTE"):
674 comb += exec_insn_valid_i.eq(1) # trigger execute
675 with m.If(exec_insn_ready_o): # execute acknowledged us
676 m.next = "EXECUTE_WAIT"
677
678 with m.State("EXECUTE_WAIT"):
679 # wait on "core stop" release, at instruction end
680 # need to do this here, in case we are in a VL>1 loop
681 with m.If(~dbg.core_stop_o & ~core_rst):
682 comb += exec_pc_ready_i.eq(1)
683 with m.If(exec_pc_valid_o):
684
685 # was this the last loop iteration?
686 is_last = Signal()
687 cur_vl = cur_state.svstate.vl
688 comb += is_last.eq(next_srcstep == cur_vl)
689
690 # if either PC or SVSTATE were changed by the previous
691 # instruction, go directly back to Fetch, without
692 # updating either PC or SVSTATE
693 with m.If(pc_changed | sv_changed):
694 m.next = "ISSUE_START"
695
696 # also return to Fetch, when no output was a vector
697 # (regardless of SRCSTEP and VL), or when the last
698 # instruction was really the last one of the VL loop
699 with m.Elif((~pdecode2.loop_continue) | is_last):
700 # before going back to fetch, update the PC state
701 # register with the NIA.
702 # ok here we are not reading the branch unit.
703 # TODO: this just blithely overwrites whatever
704 # pipeline updated the PC
705 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
706 comb += self.state_w_pc.data_i.eq(nia)
707 # reset SRCSTEP before returning to Fetch
708 if self.svp64_en:
709 with m.If(pdecode2.loop_continue):
710 comb += new_svstate.srcstep.eq(0)
711 comb += new_svstate.dststep.eq(0)
712 comb += update_svstate.eq(1)
713 else:
714 comb += new_svstate.srcstep.eq(0)
715 comb += new_svstate.dststep.eq(0)
716 comb += update_svstate.eq(1)
717 m.next = "ISSUE_START"
718
719 # returning to Execute? then, first update SRCSTEP
720 with m.Else():
721 comb += new_svstate.srcstep.eq(next_srcstep)
722 comb += new_svstate.dststep.eq(next_dststep)
723 comb += update_svstate.eq(1)
724 # return to mask skip loop
725 m.next = "PRED_SKIP"
726
727 with m.Else():
728 comb += core.core_stopped_i.eq(1)
729 comb += dbg.core_stopped_i.eq(1)
730 # while stopped, allow updating the PC and SVSTATE
731 with m.If(self.pc_i.ok):
732 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
733 comb += self.state_w_pc.data_i.eq(self.pc_i.data)
734 sync += pc_changed.eq(1)
735 with m.If(self.svstate_i.ok):
736 comb += new_svstate.eq(self.svstate_i.data)
737 comb += update_svstate.eq(1)
738 sync += sv_changed.eq(1)
739
740 # check if svstate needs updating: if so, write it to State Regfile
741 with m.If(update_svstate):
742 comb += self.state_w_sv.wen.eq(1<<StateRegs.SVSTATE)
743 comb += self.state_w_sv.data_i.eq(new_svstate)
744 sync += cur_state.svstate.eq(new_svstate) # for next clock
745
746 def execute_fsm(self, m, core, pc_changed, sv_changed,
747 exec_insn_valid_i, exec_insn_ready_o,
748 exec_pc_valid_o, exec_pc_ready_i):
749 """execute FSM
750
751 execute FSM. this interacts with the "issue" FSM
752 through exec_insn_ready/valid (incoming) and exec_pc_ready/valid
753 (outgoing). SVP64 RM prefixes have already been set up by the
754 "issue" phase, so execute is fairly straightforward.
755 """
756
757 comb = m.d.comb
758 sync = m.d.sync
759 pdecode2 = self.pdecode2
760
761 # temporaries
762 core_busy_o = core.busy_o # core is busy
763 core_ivalid_i = core.ivalid_i # instruction is valid
764 core_issue_i = core.issue_i # instruction is issued
765 insn_type = core.e.do.insn_type # instruction MicroOp type
766
767 with m.FSM(name="exec_fsm"):
768
769 # waiting for instruction bus (stays there until not busy)
770 with m.State("INSN_START"):
771 comb += exec_insn_ready_o.eq(1)
772 with m.If(exec_insn_valid_i):
773 comb += core_ivalid_i.eq(1) # instruction is valid
774 comb += core_issue_i.eq(1) # and issued
775 sync += sv_changed.eq(0)
776 sync += pc_changed.eq(0)
777 m.next = "INSN_ACTIVE" # move to "wait completion"
778
779 # instruction started: must wait till it finishes
780 with m.State("INSN_ACTIVE"):
781 with m.If(insn_type != MicrOp.OP_NOP):
782 comb += core_ivalid_i.eq(1) # instruction is valid
783 # note changes to PC and SVSTATE
784 with m.If(self.state_nia.wen & (1<<StateRegs.SVSTATE)):
785 sync += sv_changed.eq(1)
786 with m.If(self.state_nia.wen & (1<<StateRegs.PC)):
787 sync += pc_changed.eq(1)
788 with m.If(~core_busy_o): # instruction done!
789 comb += exec_pc_valid_o.eq(1)
790 with m.If(exec_pc_ready_i):
791 comb += self.insn_done.eq(1)
792 m.next = "INSN_START" # back to fetch
793
794 def setup_peripherals(self, m):
795 comb, sync = m.d.comb, m.d.sync
796
797 m.submodules.core = core = DomainRenamer("coresync")(self.core)
798 m.submodules.imem = imem = self.imem
799 m.submodules.dbg = dbg = self.dbg
800 if self.jtag_en:
801 m.submodules.jtag = jtag = self.jtag
802 # TODO: UART2GDB mux, here, from external pin
803 # see https://bugs.libre-soc.org/show_bug.cgi?id=499
804 sync += dbg.dmi.connect_to(jtag.dmi)
805
806 cur_state = self.cur_state
807
808 # 4x 4k SRAM blocks. these simply "exist", they get routed in litex
809 if self.sram4x4k:
810 for i, sram in enumerate(self.sram4k):
811 m.submodules["sram4k_%d" % i] = sram
812 comb += sram.enable.eq(self.wb_sram_en)
813
814 # XICS interrupt handler
815 if self.xics:
816 m.submodules.xics_icp = icp = self.xics_icp
817 m.submodules.xics_ics = ics = self.xics_ics
818 comb += icp.ics_i.eq(ics.icp_o) # connect ICS to ICP
819 sync += cur_state.eint.eq(icp.core_irq_o) # connect ICP to core
820
821 # GPIO test peripheral
822 if self.gpio:
823 m.submodules.simple_gpio = simple_gpio = self.simple_gpio
824
825 # connect one GPIO output to ICS bit 15 (like in microwatt soc.vhdl)
826 # XXX causes litex ECP5 test to get wrong idea about input and output
827 # (but works with verilator sim *sigh*)
828 #if self.gpio and self.xics:
829 # comb += self.int_level_i[15].eq(simple_gpio.gpio_o[0])
830
831 # instruction decoder
832 pdecode = create_pdecode()
833 m.submodules.dec2 = pdecode2 = self.pdecode2
834 if self.svp64_en:
835 m.submodules.svp64 = svp64 = self.svp64
836
837 # convenience
838 dmi, d_reg, d_cr, d_xer, = dbg.dmi, dbg.d_gpr, dbg.d_cr, dbg.d_xer
839 intrf = self.core.regs.rf['int']
840
841 # clock delay power-on reset
842 cd_por = ClockDomain(reset_less=True)
843 cd_sync = ClockDomain()
844 core_sync = ClockDomain("coresync")
845 m.domains += cd_por, cd_sync, core_sync
846
847 ti_rst = Signal(reset_less=True)
848 delay = Signal(range(4), reset=3)
849 with m.If(delay != 0):
850 m.d.por += delay.eq(delay - 1)
851 comb += cd_por.clk.eq(ClockSignal())
852
853 # power-on reset delay
854 core_rst = ResetSignal("coresync")
855 comb += ti_rst.eq(delay != 0 | dbg.core_rst_o | ResetSignal())
856 comb += core_rst.eq(ti_rst)
857
858 # busy/halted signals from core
859 comb += self.busy_o.eq(core.busy_o)
860 comb += pdecode2.dec.bigendian.eq(self.core_bigendian_i)
861
862 # temporary hack: says "go" immediately for both address gen and ST
863 l0 = core.l0
864 ldst = core.fus.fus['ldst0']
865 st_go_edge = rising_edge(m, ldst.st.rel_o)
866 m.d.comb += ldst.ad.go_i.eq(ldst.ad.rel_o) # link addr-go direct to rel
867 m.d.comb += ldst.st.go_i.eq(st_go_edge) # link store-go to rising rel
868
869 return core_rst
870
871 def elaborate(self, platform):
872 m = Module()
873 # convenience
874 comb, sync = m.d.comb, m.d.sync
875 cur_state = self.cur_state
876 pdecode2 = self.pdecode2
877 dbg = self.dbg
878 core = self.core
879
880 # set up peripherals and core
881 core_rst = self.setup_peripherals(m)
882
883 # reset current state if core reset requested
884 with m.If(core_rst):
885 m.d.sync += self.cur_state.eq(0)
886
887 # PC and instruction from I-Memory
888 comb += self.pc_o.eq(cur_state.pc)
889 pc_changed = Signal() # note write to PC
890 sv_changed = Signal() # note write to SVSTATE
891
892 # read state either from incoming override or from regfile
893 # TODO: really should be doing MSR in the same way
894 pc = state_get(m, core_rst, self.pc_i,
895 "pc", # read PC
896 self.state_r_pc, StateRegs.PC)
897 svstate = state_get(m, core_rst, self.svstate_i,
898 "svstate", # read SVSTATE
899 self.state_r_sv, StateRegs.SVSTATE)
900
901 # don't write pc every cycle
902 comb += self.state_w_pc.wen.eq(0)
903 comb += self.state_w_pc.data_i.eq(0)
904
905 # don't read msr every cycle
906 comb += self.state_r_msr.ren.eq(0)
907
908 # address of the next instruction, in the absence of a branch
909 # depends on the instruction size
910 nia = Signal(64)
911 with m.If(core_rst):
912 sync += nia.eq(0)
913
914 # connect up debug signals
915 # TODO comb += core.icache_rst_i.eq(dbg.icache_rst_o)
916 comb += dbg.terminate_i.eq(core.core_terminate_o)
917 comb += dbg.state.pc.eq(pc)
918 comb += dbg.state.svstate.eq(svstate)
919 comb += dbg.state.msr.eq(cur_state.msr)
920
921 # pass the prefix mode from Fetch to Issue, so the latter can loop
922 # on VL==0
923 is_svp64_mode = Signal()
924
925 # there are *THREE* FSMs, fetch (32/64-bit) issue, decode/execute.
926 # these are the handshake signals between fetch and decode/execute
927
928 # fetch FSM can run as soon as the PC is valid
929 fetch_pc_valid_i = Signal() # Execute tells Fetch "start next read"
930 fetch_pc_ready_o = Signal() # Fetch Tells SVSTATE "proceed"
931
932 # fetch FSM hands over the instruction to be decoded / issued
933 fetch_insn_valid_o = Signal()
934 fetch_insn_ready_i = Signal()
935
936 # predicate fetch FSM decodes and fetches the predicate
937 pred_insn_valid_i = Signal()
938 pred_insn_ready_o = Signal()
939
940 # predicate fetch FSM delivers the masks
941 pred_mask_valid_o = Signal()
942 pred_mask_ready_i = Signal()
943
944 # issue FSM delivers the instruction to the be executed
945 exec_insn_valid_i = Signal()
946 exec_insn_ready_o = Signal()
947
948 # execute FSM, hands over the PC/SVSTATE back to the issue FSM
949 exec_pc_valid_o = Signal()
950 exec_pc_ready_i = Signal()
951
952 # the FSMs here are perhaps unusual in that they detect conditions
953 # then "hold" information, combinatorially, for the core
954 # (as opposed to using sync - which would be on a clock's delay)
955 # this includes the actual opcode, valid flags and so on.
956
957 # Fetch, then predicate fetch, then Issue, then Execute.
958 # Issue is where the VL for-loop # lives. the ready/valid
959 # signalling is used to communicate between the four.
960
961 self.fetch_fsm(m, core, pc, svstate, nia, is_svp64_mode,
962 fetch_pc_ready_o, fetch_pc_valid_i,
963 fetch_insn_valid_o, fetch_insn_ready_i)
964
965 self.issue_fsm(m, core, pc_changed, sv_changed, nia,
966 dbg, core_rst, is_svp64_mode,
967 fetch_pc_ready_o, fetch_pc_valid_i,
968 fetch_insn_valid_o, fetch_insn_ready_i,
969 pred_insn_valid_i, pred_insn_ready_o,
970 pred_mask_valid_o, pred_mask_ready_i,
971 exec_insn_valid_i, exec_insn_ready_o,
972 exec_pc_valid_o, exec_pc_ready_i)
973
974 if self.svp64_en:
975 self.fetch_predicate_fsm(m,
976 pred_insn_valid_i, pred_insn_ready_o,
977 pred_mask_valid_o, pred_mask_ready_i)
978
979 self.execute_fsm(m, core, pc_changed, sv_changed,
980 exec_insn_valid_i, exec_insn_ready_o,
981 exec_pc_valid_o, exec_pc_ready_i)
982
983 # this bit doesn't have to be in the FSM: connect up to read
984 # regfiles on demand from DMI
985 self.do_dmi(m, dbg)
986
987 # DEC and TB inc/dec FSM. copy of DEC is put into CoreState,
988 # (which uses that in PowerDecoder2 to raise 0x900 exception)
989 self.tb_dec_fsm(m, cur_state.dec)
990
991 return m
992
993 def do_dmi(self, m, dbg):
994 """deals with DMI debug requests
995
996 currently only provides read requests for the INT regfile, CR and XER
997 it will later also deal with *writing* to these regfiles.
998 """
999 comb = m.d.comb
1000 sync = m.d.sync
1001 dmi, d_reg, d_cr, d_xer, = dbg.dmi, dbg.d_gpr, dbg.d_cr, dbg.d_xer
1002 intrf = self.core.regs.rf['int']
1003
1004 with m.If(d_reg.req): # request for regfile access being made
1005 # TODO: error-check this
1006 # XXX should this be combinatorial? sync better?
1007 if intrf.unary:
1008 comb += self.int_r.ren.eq(1<<d_reg.addr)
1009 else:
1010 comb += self.int_r.addr.eq(d_reg.addr)
1011 comb += self.int_r.ren.eq(1)
1012 d_reg_delay = Signal()
1013 sync += d_reg_delay.eq(d_reg.req)
1014 with m.If(d_reg_delay):
1015 # data arrives one clock later
1016 comb += d_reg.data.eq(self.int_r.data_o)
1017 comb += d_reg.ack.eq(1)
1018
1019 # sigh same thing for CR debug
1020 with m.If(d_cr.req): # request for regfile access being made
1021 comb += self.cr_r.ren.eq(0b11111111) # enable all
1022 d_cr_delay = Signal()
1023 sync += d_cr_delay.eq(d_cr.req)
1024 with m.If(d_cr_delay):
1025 # data arrives one clock later
1026 comb += d_cr.data.eq(self.cr_r.data_o)
1027 comb += d_cr.ack.eq(1)
1028
1029 # aaand XER...
1030 with m.If(d_xer.req): # request for regfile access being made
1031 comb += self.xer_r.ren.eq(0b111111) # enable all
1032 d_xer_delay = Signal()
1033 sync += d_xer_delay.eq(d_xer.req)
1034 with m.If(d_xer_delay):
1035 # data arrives one clock later
1036 comb += d_xer.data.eq(self.xer_r.data_o)
1037 comb += d_xer.ack.eq(1)
1038
1039 def tb_dec_fsm(self, m, spr_dec):
1040 """tb_dec_fsm
1041
1042 this is a FSM for updating either dec or tb. it runs alternately
1043 DEC, TB, DEC, TB. note that SPR pipeline could have written a new
1044 value to DEC, however the regfile has "passthrough" on it so this
1045 *should* be ok.
1046
1047 see v3.0B p1097-1099 for Timeer Resource and p1065 and p1076
1048 """
1049
1050 comb, sync = m.d.comb, m.d.sync
1051 fast_rf = self.core.regs.rf['fast']
1052 fast_r_dectb = fast_rf.r_ports['issue'] # DEC/TB
1053 fast_w_dectb = fast_rf.w_ports['issue'] # DEC/TB
1054
1055 with m.FSM() as fsm:
1056
1057 # initiates read of current DEC
1058 with m.State("DEC_READ"):
1059 comb += fast_r_dectb.addr.eq(FastRegs.DEC)
1060 comb += fast_r_dectb.ren.eq(1)
1061 m.next = "DEC_WRITE"
1062
1063 # waits for DEC read to arrive (1 cycle), updates with new value
1064 with m.State("DEC_WRITE"):
1065 new_dec = Signal(64)
1066 # TODO: MSR.LPCR 32-bit decrement mode
1067 comb += new_dec.eq(fast_r_dectb.data_o - 1)
1068 comb += fast_w_dectb.addr.eq(FastRegs.DEC)
1069 comb += fast_w_dectb.wen.eq(1)
1070 comb += fast_w_dectb.data_i.eq(new_dec)
1071 sync += spr_dec.eq(new_dec) # copy into cur_state for decoder
1072 m.next = "TB_READ"
1073
1074 # initiates read of current TB
1075 with m.State("TB_READ"):
1076 comb += fast_r_dectb.addr.eq(FastRegs.TB)
1077 comb += fast_r_dectb.ren.eq(1)
1078 m.next = "TB_WRITE"
1079
1080 # waits for read TB to arrive, initiates write of current TB
1081 with m.State("TB_WRITE"):
1082 new_tb = Signal(64)
1083 comb += new_tb.eq(fast_r_dectb.data_o + 1)
1084 comb += fast_w_dectb.addr.eq(FastRegs.TB)
1085 comb += fast_w_dectb.wen.eq(1)
1086 comb += fast_w_dectb.data_i.eq(new_tb)
1087 m.next = "DEC_READ"
1088
1089 return m
1090
1091 def __iter__(self):
1092 yield from self.pc_i.ports()
1093 yield self.pc_o
1094 yield self.memerr_o
1095 yield from self.core.ports()
1096 yield from self.imem.ports()
1097 yield self.core_bigendian_i
1098 yield self.busy_o
1099
1100 def ports(self):
1101 return list(self)
1102
1103 def external_ports(self):
1104 ports = self.pc_i.ports()
1105 ports += [self.pc_o, self.memerr_o, self.core_bigendian_i, self.busy_o,
1106 ]
1107
1108 if self.jtag_en:
1109 ports += list(self.jtag.external_ports())
1110 else:
1111 # don't add DMI if JTAG is enabled
1112 ports += list(self.dbg.dmi.ports())
1113
1114 ports += list(self.imem.ibus.fields.values())
1115 ports += list(self.core.l0.cmpi.lsmem.lsi.slavebus.fields.values())
1116
1117 if self.sram4x4k:
1118 for sram in self.sram4k:
1119 ports += list(sram.bus.fields.values())
1120
1121 if self.xics:
1122 ports += list(self.xics_icp.bus.fields.values())
1123 ports += list(self.xics_ics.bus.fields.values())
1124 ports.append(self.int_level_i)
1125
1126 if self.gpio:
1127 ports += list(self.simple_gpio.bus.fields.values())
1128 ports.append(self.gpio_o)
1129
1130 return ports
1131
1132 def ports(self):
1133 return list(self)
1134
1135
1136 class TestIssuer(Elaboratable):
1137 def __init__(self, pspec):
1138 self.ti = TestIssuerInternal(pspec)
1139
1140 self.pll = DummyPLL()
1141
1142 # PLL direct clock or not
1143 self.pll_en = hasattr(pspec, "use_pll") and pspec.use_pll
1144 if self.pll_en:
1145 self.pll_18_o = Signal(reset_less=True)
1146
1147 def elaborate(self, platform):
1148 m = Module()
1149 comb = m.d.comb
1150
1151 # TestIssuer runs at direct clock
1152 m.submodules.ti = ti = self.ti
1153 cd_int = ClockDomain("coresync")
1154
1155 if self.pll_en:
1156 # ClockSelect runs at PLL output internal clock rate
1157 m.submodules.pll = pll = self.pll
1158
1159 # add clock domains from PLL
1160 cd_pll = ClockDomain("pllclk")
1161 m.domains += cd_pll
1162
1163 # PLL clock established. has the side-effect of running clklsel
1164 # at the PLL's speed (see DomainRenamer("pllclk") above)
1165 pllclk = ClockSignal("pllclk")
1166 comb += pllclk.eq(pll.clk_pll_o)
1167
1168 # wire up external 24mhz to PLL
1169 comb += pll.clk_24_i.eq(ClockSignal())
1170
1171 # output 18 mhz PLL test signal
1172 comb += self.pll_18_o.eq(pll.pll_18_o)
1173
1174 # now wire up ResetSignals. don't mind them being in this domain
1175 pll_rst = ResetSignal("pllclk")
1176 comb += pll_rst.eq(ResetSignal())
1177
1178 # internal clock is set to selector clock-out. has the side-effect of
1179 # running TestIssuer at this speed (see DomainRenamer("intclk") above)
1180 intclk = ClockSignal("coresync")
1181 if self.pll_en:
1182 comb += intclk.eq(pll.clk_pll_o)
1183 else:
1184 comb += intclk.eq(ClockSignal())
1185
1186 return m
1187
1188 def ports(self):
1189 return list(self.ti.ports()) + list(self.pll.ports()) + \
1190 [ClockSignal(), ResetSignal()]
1191
1192 def external_ports(self):
1193 ports = self.ti.external_ports()
1194 ports.append(ClockSignal())
1195 ports.append(ResetSignal())
1196 if self.pll_en:
1197 ports.append(self.pll.clk_sel_i)
1198 ports.append(self.pll_18_o)
1199 ports.append(self.pll.pll_lck_o)
1200 return ports
1201
1202
1203 if __name__ == '__main__':
1204 units = {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1, 'logical': 1,
1205 'spr': 1,
1206 'div': 1,
1207 'mul': 1,
1208 'shiftrot': 1
1209 }
1210 pspec = TestMemPspec(ldst_ifacetype='bare_wb',
1211 imem_ifacetype='bare_wb',
1212 addr_wid=48,
1213 mask_wid=8,
1214 reg_wid=64,
1215 units=units)
1216 dut = TestIssuer(pspec)
1217 vl = main(dut, ports=dut.ports(), name="test_issuer")
1218
1219 if len(sys.argv) == 1:
1220 vl = rtlil.convert(dut, ports=dut.external_ports(), name="test_issuer")
1221 with open("test_issuer.il", "w") as f:
1222 f.write(vl)