Implement 1<<r3 predicate mode
[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 with m.If(dunary):
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.bit_select(dst_shift, 1).eq(1)
475 with m.Else():
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
481 with m.If(sall1s):
482 sync += self.srcmask.eq(-1)
483 m.next = "FETCH_PRED_DONE"
484 # fetch source predicate register
485 with m.Else():
486 comb += int_pred.addr.eq(sregread)
487 comb += int_pred.ren.eq(1)
488 m.next = "INT_SRC_READ"
489
490 with m.State("INT_SRC_READ"):
491 # store source mask
492 inv = Repl(sinvert, 64)
493 new_srcmask = Signal(64)
494 with m.If(sunary):
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.bit_select(src_shift, 1).eq(1)
499 with m.Else():
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"
505
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"
510
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):
519 """issue FSM
520
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
525 (incoming).
526 SVP64 RM prefixes have already been set up by the
527 "fetch" phase, so execute is fairly straightforward.
528 """
529
530 comb = m.d.comb
531 sync = m.d.sync
532 pdecode2 = self.pdecode2
533 cur_state = self.cur_state
534
535 # temporaries
536 dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode
537
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)
542
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)
550
551 with m.FSM(name="issue_fsm"):
552
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
562 m.next = "INSN_WAIT"
563 with m.Else():
564 # tell core it's stopped, and acknowledge debug handshake
565 comb += core.core_stopped_i.eq(1)
566 comb += dbg.core_stopped_i.eq(1)
567 # while stopped, allow updating the PC and SVSTATE
568 with m.If(self.pc_i.ok):
569 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
570 comb += self.state_w_pc.data_i.eq(self.pc_i.data)
571 sync += pc_changed.eq(1)
572 with m.If(self.svstate_i.ok):
573 comb += new_svstate.eq(self.svstate_i.data)
574 comb += update_svstate.eq(1)
575 sync += sv_changed.eq(1)
576
577 # wait for an instruction to arrive from Fetch
578 with m.State("INSN_WAIT"):
579 comb += fetch_insn_ready_i.eq(1)
580 with m.If(fetch_insn_valid_o):
581 # loop into ISSUE_START if it's a SVP64 instruction
582 # and VL == 0. this because VL==0 is a for-loop
583 # from 0 to 0 i.e. always, always a NOP.
584 cur_vl = cur_state.svstate.vl
585 with m.If(is_svp64_mode & (cur_vl == 0)):
586 # update the PC before fetching the next instruction
587 # since we are in a VL==0 loop, no instruction was
588 # executed that we could be overwriting
589 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
590 comb += self.state_w_pc.data_i.eq(nia)
591 comb += self.insn_done.eq(1)
592 m.next = "ISSUE_START"
593 with m.Else():
594 if self.svp64_en:
595 m.next = "PRED_START" # start fetching predicate
596 else:
597 m.next = "DECODE_SV" # skip predication
598
599 with m.State("PRED_START"):
600 comb += pred_insn_valid_i.eq(1) # tell fetch_pred to start
601 with m.If(pred_insn_ready_o): # fetch_pred acknowledged us
602 m.next = "MASK_WAIT"
603
604 with m.State("MASK_WAIT"):
605 comb += pred_mask_ready_i.eq(1) # ready to receive the masks
606 with m.If(pred_mask_valid_o): # predication masks are ready
607 m.next = "PRED_SKIP"
608
609 # skip zeros in predicate
610 with m.State("PRED_SKIP"):
611 with m.If(~is_svp64_mode):
612 m.next = "DECODE_SV" # nothing to do
613 with m.Else():
614 if self.svp64_en:
615 pred_src_zero = pdecode2.rm_dec.pred_sz
616 pred_dst_zero = pdecode2.rm_dec.pred_dz
617
618 # new srcstep, after skipping zeros
619 skip_srcstep = Signal.like(cur_srcstep)
620 # value to be added to the current srcstep
621 src_delta = Signal.like(cur_srcstep)
622 # add leading zeros to srcstep, if not in zero mode
623 with m.If(~pred_src_zero):
624 # priority encoder (count leading zeros)
625 # append guard bit, in case the mask is all zeros
626 pri_enc_src = PriorityEncoder(65)
627 m.submodules.pri_enc_src = pri_enc_src
628 comb += pri_enc_src.i.eq(Cat(self.srcmask,
629 Const(1, 1)))
630 comb += src_delta.eq(pri_enc_src.o)
631 # apply delta to srcstep
632 comb += skip_srcstep.eq(cur_srcstep + src_delta)
633 # shift-out all leading zeros from the mask
634 # plus the leading "one" bit
635 # TODO count leading zeros and shift-out the zero
636 # bits, in the same step, in hardware
637 sync += self.srcmask.eq(self.srcmask >> (src_delta+1))
638
639 # same as above, but for dststep
640 skip_dststep = Signal.like(cur_dststep)
641 dst_delta = Signal.like(cur_dststep)
642 with m.If(~pred_dst_zero):
643 pri_enc_dst = PriorityEncoder(65)
644 m.submodules.pri_enc_dst = pri_enc_dst
645 comb += pri_enc_dst.i.eq(Cat(self.dstmask,
646 Const(1, 1)))
647 comb += dst_delta.eq(pri_enc_dst.o)
648 comb += skip_dststep.eq(cur_dststep + dst_delta)
649 sync += self.dstmask.eq(self.dstmask >> (dst_delta+1))
650
651 # TODO: initialize mask[VL]=1 to avoid passing past VL
652 with m.If((skip_srcstep >= cur_vl) |
653 (skip_dststep >= cur_vl)):
654 # end of VL loop. Update PC and reset src/dst step
655 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
656 comb += self.state_w_pc.data_i.eq(nia)
657 comb += new_svstate.srcstep.eq(0)
658 comb += new_svstate.dststep.eq(0)
659 comb += update_svstate.eq(1)
660 # synchronize with the simulator
661 comb += self.insn_done.eq(1)
662 # go back to Issue
663 m.next = "ISSUE_START"
664 with m.Else():
665 # update new src/dst step
666 comb += new_svstate.srcstep.eq(skip_srcstep)
667 comb += new_svstate.dststep.eq(skip_dststep)
668 comb += update_svstate.eq(1)
669 # proceed to Decode
670 m.next = "DECODE_SV"
671
672 # after src/dst step have been updated, we are ready
673 # to decode the instruction
674 with m.State("DECODE_SV"):
675 # decode the instruction
676 sync += core.e.eq(pdecode2.e)
677 sync += core.state.eq(cur_state)
678 sync += core.raw_insn_i.eq(dec_opcode_i)
679 sync += core.bigendian_i.eq(self.core_bigendian_i)
680 # set RA_OR_ZERO detection in satellite decoders
681 sync += core.sv_a_nz.eq(pdecode2.sv_a_nz)
682 m.next = "INSN_EXECUTE" # move to "execute"
683
684 # handshake with execution FSM, move to "wait" once acknowledged
685 with m.State("INSN_EXECUTE"):
686 comb += exec_insn_valid_i.eq(1) # trigger execute
687 with m.If(exec_insn_ready_o): # execute acknowledged us
688 m.next = "EXECUTE_WAIT"
689
690 with m.State("EXECUTE_WAIT"):
691 # wait on "core stop" release, at instruction end
692 # need to do this here, in case we are in a VL>1 loop
693 with m.If(~dbg.core_stop_o & ~core_rst):
694 comb += exec_pc_ready_i.eq(1)
695 with m.If(exec_pc_valid_o):
696
697 # was this the last loop iteration?
698 is_last = Signal()
699 cur_vl = cur_state.svstate.vl
700 comb += is_last.eq(next_srcstep == cur_vl)
701
702 # if either PC or SVSTATE were changed by the previous
703 # instruction, go directly back to Fetch, without
704 # updating either PC or SVSTATE
705 with m.If(pc_changed | sv_changed):
706 m.next = "ISSUE_START"
707
708 # also return to Fetch, when no output was a vector
709 # (regardless of SRCSTEP and VL), or when the last
710 # instruction was really the last one of the VL loop
711 with m.Elif((~pdecode2.loop_continue) | is_last):
712 # before going back to fetch, update the PC state
713 # register with the NIA.
714 # ok here we are not reading the branch unit.
715 # TODO: this just blithely overwrites whatever
716 # pipeline updated the PC
717 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
718 comb += self.state_w_pc.data_i.eq(nia)
719 # reset SRCSTEP before returning to Fetch
720 if self.svp64_en:
721 with m.If(pdecode2.loop_continue):
722 comb += new_svstate.srcstep.eq(0)
723 comb += new_svstate.dststep.eq(0)
724 comb += update_svstate.eq(1)
725 else:
726 comb += new_svstate.srcstep.eq(0)
727 comb += new_svstate.dststep.eq(0)
728 comb += update_svstate.eq(1)
729 m.next = "ISSUE_START"
730
731 # returning to Execute? then, first update SRCSTEP
732 with m.Else():
733 comb += new_svstate.srcstep.eq(next_srcstep)
734 comb += new_svstate.dststep.eq(next_dststep)
735 comb += update_svstate.eq(1)
736 # return to mask skip loop
737 m.next = "PRED_SKIP"
738
739 with m.Else():
740 comb += core.core_stopped_i.eq(1)
741 comb += dbg.core_stopped_i.eq(1)
742 # while stopped, allow updating the PC and SVSTATE
743 with m.If(self.pc_i.ok):
744 comb += self.state_w_pc.wen.eq(1 << StateRegs.PC)
745 comb += self.state_w_pc.data_i.eq(self.pc_i.data)
746 sync += pc_changed.eq(1)
747 with m.If(self.svstate_i.ok):
748 comb += new_svstate.eq(self.svstate_i.data)
749 comb += update_svstate.eq(1)
750 sync += sv_changed.eq(1)
751
752 # check if svstate needs updating: if so, write it to State Regfile
753 with m.If(update_svstate):
754 comb += self.state_w_sv.wen.eq(1<<StateRegs.SVSTATE)
755 comb += self.state_w_sv.data_i.eq(new_svstate)
756 sync += cur_state.svstate.eq(new_svstate) # for next clock
757
758 def execute_fsm(self, m, core, pc_changed, sv_changed,
759 exec_insn_valid_i, exec_insn_ready_o,
760 exec_pc_valid_o, exec_pc_ready_i):
761 """execute FSM
762
763 execute FSM. this interacts with the "issue" FSM
764 through exec_insn_ready/valid (incoming) and exec_pc_ready/valid
765 (outgoing). SVP64 RM prefixes have already been set up by the
766 "issue" phase, so execute is fairly straightforward.
767 """
768
769 comb = m.d.comb
770 sync = m.d.sync
771 pdecode2 = self.pdecode2
772
773 # temporaries
774 core_busy_o = core.busy_o # core is busy
775 core_ivalid_i = core.ivalid_i # instruction is valid
776 core_issue_i = core.issue_i # instruction is issued
777 insn_type = core.e.do.insn_type # instruction MicroOp type
778
779 with m.FSM(name="exec_fsm"):
780
781 # waiting for instruction bus (stays there until not busy)
782 with m.State("INSN_START"):
783 comb += exec_insn_ready_o.eq(1)
784 with m.If(exec_insn_valid_i):
785 comb += core_ivalid_i.eq(1) # instruction is valid
786 comb += core_issue_i.eq(1) # and issued
787 sync += sv_changed.eq(0)
788 sync += pc_changed.eq(0)
789 m.next = "INSN_ACTIVE" # move to "wait completion"
790
791 # instruction started: must wait till it finishes
792 with m.State("INSN_ACTIVE"):
793 with m.If(insn_type != MicrOp.OP_NOP):
794 comb += core_ivalid_i.eq(1) # instruction is valid
795 # note changes to PC and SVSTATE
796 with m.If(self.state_nia.wen & (1<<StateRegs.SVSTATE)):
797 sync += sv_changed.eq(1)
798 with m.If(self.state_nia.wen & (1<<StateRegs.PC)):
799 sync += pc_changed.eq(1)
800 with m.If(~core_busy_o): # instruction done!
801 comb += exec_pc_valid_o.eq(1)
802 with m.If(exec_pc_ready_i):
803 comb += self.insn_done.eq(1)
804 m.next = "INSN_START" # back to fetch
805
806 def setup_peripherals(self, m):
807 comb, sync = m.d.comb, m.d.sync
808
809 m.submodules.core = core = DomainRenamer("coresync")(self.core)
810 m.submodules.imem = imem = self.imem
811 m.submodules.dbg = dbg = self.dbg
812 if self.jtag_en:
813 m.submodules.jtag = jtag = self.jtag
814 # TODO: UART2GDB mux, here, from external pin
815 # see https://bugs.libre-soc.org/show_bug.cgi?id=499
816 sync += dbg.dmi.connect_to(jtag.dmi)
817
818 cur_state = self.cur_state
819
820 # 4x 4k SRAM blocks. these simply "exist", they get routed in litex
821 if self.sram4x4k:
822 for i, sram in enumerate(self.sram4k):
823 m.submodules["sram4k_%d" % i] = sram
824 comb += sram.enable.eq(self.wb_sram_en)
825
826 # XICS interrupt handler
827 if self.xics:
828 m.submodules.xics_icp = icp = self.xics_icp
829 m.submodules.xics_ics = ics = self.xics_ics
830 comb += icp.ics_i.eq(ics.icp_o) # connect ICS to ICP
831 sync += cur_state.eint.eq(icp.core_irq_o) # connect ICP to core
832
833 # GPIO test peripheral
834 if self.gpio:
835 m.submodules.simple_gpio = simple_gpio = self.simple_gpio
836
837 # connect one GPIO output to ICS bit 15 (like in microwatt soc.vhdl)
838 # XXX causes litex ECP5 test to get wrong idea about input and output
839 # (but works with verilator sim *sigh*)
840 #if self.gpio and self.xics:
841 # comb += self.int_level_i[15].eq(simple_gpio.gpio_o[0])
842
843 # instruction decoder
844 pdecode = create_pdecode()
845 m.submodules.dec2 = pdecode2 = self.pdecode2
846 if self.svp64_en:
847 m.submodules.svp64 = svp64 = self.svp64
848
849 # convenience
850 dmi, d_reg, d_cr, d_xer, = dbg.dmi, dbg.d_gpr, dbg.d_cr, dbg.d_xer
851 intrf = self.core.regs.rf['int']
852
853 # clock delay power-on reset
854 cd_por = ClockDomain(reset_less=True)
855 cd_sync = ClockDomain()
856 core_sync = ClockDomain("coresync")
857 m.domains += cd_por, cd_sync, core_sync
858
859 ti_rst = Signal(reset_less=True)
860 delay = Signal(range(4), reset=3)
861 with m.If(delay != 0):
862 m.d.por += delay.eq(delay - 1)
863 comb += cd_por.clk.eq(ClockSignal())
864
865 # power-on reset delay
866 core_rst = ResetSignal("coresync")
867 comb += ti_rst.eq(delay != 0 | dbg.core_rst_o | ResetSignal())
868 comb += core_rst.eq(ti_rst)
869
870 # busy/halted signals from core
871 comb += self.busy_o.eq(core.busy_o)
872 comb += pdecode2.dec.bigendian.eq(self.core_bigendian_i)
873
874 # temporary hack: says "go" immediately for both address gen and ST
875 l0 = core.l0
876 ldst = core.fus.fus['ldst0']
877 st_go_edge = rising_edge(m, ldst.st.rel_o)
878 m.d.comb += ldst.ad.go_i.eq(ldst.ad.rel_o) # link addr-go direct to rel
879 m.d.comb += ldst.st.go_i.eq(st_go_edge) # link store-go to rising rel
880
881 return core_rst
882
883 def elaborate(self, platform):
884 m = Module()
885 # convenience
886 comb, sync = m.d.comb, m.d.sync
887 cur_state = self.cur_state
888 pdecode2 = self.pdecode2
889 dbg = self.dbg
890 core = self.core
891
892 # set up peripherals and core
893 core_rst = self.setup_peripherals(m)
894
895 # reset current state if core reset requested
896 with m.If(core_rst):
897 m.d.sync += self.cur_state.eq(0)
898
899 # PC and instruction from I-Memory
900 comb += self.pc_o.eq(cur_state.pc)
901 pc_changed = Signal() # note write to PC
902 sv_changed = Signal() # note write to SVSTATE
903
904 # read state either from incoming override or from regfile
905 # TODO: really should be doing MSR in the same way
906 pc = state_get(m, core_rst, self.pc_i,
907 "pc", # read PC
908 self.state_r_pc, StateRegs.PC)
909 svstate = state_get(m, core_rst, self.svstate_i,
910 "svstate", # read SVSTATE
911 self.state_r_sv, StateRegs.SVSTATE)
912
913 # don't write pc every cycle
914 comb += self.state_w_pc.wen.eq(0)
915 comb += self.state_w_pc.data_i.eq(0)
916
917 # don't read msr every cycle
918 comb += self.state_r_msr.ren.eq(0)
919
920 # address of the next instruction, in the absence of a branch
921 # depends on the instruction size
922 nia = Signal(64)
923
924 # connect up debug signals
925 # TODO comb += core.icache_rst_i.eq(dbg.icache_rst_o)
926 comb += dbg.terminate_i.eq(core.core_terminate_o)
927 comb += dbg.state.pc.eq(pc)
928 comb += dbg.state.svstate.eq(svstate)
929 comb += dbg.state.msr.eq(cur_state.msr)
930
931 # pass the prefix mode from Fetch to Issue, so the latter can loop
932 # on VL==0
933 is_svp64_mode = Signal()
934
935 # there are *THREE* FSMs, fetch (32/64-bit) issue, decode/execute.
936 # these are the handshake signals between fetch and decode/execute
937
938 # fetch FSM can run as soon as the PC is valid
939 fetch_pc_valid_i = Signal() # Execute tells Fetch "start next read"
940 fetch_pc_ready_o = Signal() # Fetch Tells SVSTATE "proceed"
941
942 # fetch FSM hands over the instruction to be decoded / issued
943 fetch_insn_valid_o = Signal()
944 fetch_insn_ready_i = Signal()
945
946 # predicate fetch FSM decodes and fetches the predicate
947 pred_insn_valid_i = Signal()
948 pred_insn_ready_o = Signal()
949
950 # predicate fetch FSM delivers the masks
951 pred_mask_valid_o = Signal()
952 pred_mask_ready_i = Signal()
953
954 # issue FSM delivers the instruction to the be executed
955 exec_insn_valid_i = Signal()
956 exec_insn_ready_o = Signal()
957
958 # execute FSM, hands over the PC/SVSTATE back to the issue FSM
959 exec_pc_valid_o = Signal()
960 exec_pc_ready_i = Signal()
961
962 # the FSMs here are perhaps unusual in that they detect conditions
963 # then "hold" information, combinatorially, for the core
964 # (as opposed to using sync - which would be on a clock's delay)
965 # this includes the actual opcode, valid flags and so on.
966
967 # Fetch, then predicate fetch, then Issue, then Execute.
968 # Issue is where the VL for-loop # lives. the ready/valid
969 # signalling is used to communicate between the four.
970
971 self.fetch_fsm(m, core, pc, svstate, nia, is_svp64_mode,
972 fetch_pc_ready_o, fetch_pc_valid_i,
973 fetch_insn_valid_o, fetch_insn_ready_i)
974
975 self.issue_fsm(m, core, pc_changed, sv_changed, nia,
976 dbg, core_rst, is_svp64_mode,
977 fetch_pc_ready_o, fetch_pc_valid_i,
978 fetch_insn_valid_o, fetch_insn_ready_i,
979 pred_insn_valid_i, pred_insn_ready_o,
980 pred_mask_valid_o, pred_mask_ready_i,
981 exec_insn_valid_i, exec_insn_ready_o,
982 exec_pc_valid_o, exec_pc_ready_i)
983
984 if self.svp64_en:
985 self.fetch_predicate_fsm(m,
986 pred_insn_valid_i, pred_insn_ready_o,
987 pred_mask_valid_o, pred_mask_ready_i)
988
989 self.execute_fsm(m, core, pc_changed, sv_changed,
990 exec_insn_valid_i, exec_insn_ready_o,
991 exec_pc_valid_o, exec_pc_ready_i)
992
993 # whatever was done above, over-ride it if core reset is held
994 with m.If(core_rst):
995 sync += nia.eq(0)
996
997 # this bit doesn't have to be in the FSM: connect up to read
998 # regfiles on demand from DMI
999 self.do_dmi(m, dbg)
1000
1001 # DEC and TB inc/dec FSM. copy of DEC is put into CoreState,
1002 # (which uses that in PowerDecoder2 to raise 0x900 exception)
1003 self.tb_dec_fsm(m, cur_state.dec)
1004
1005 return m
1006
1007 def do_dmi(self, m, dbg):
1008 """deals with DMI debug requests
1009
1010 currently only provides read requests for the INT regfile, CR and XER
1011 it will later also deal with *writing* to these regfiles.
1012 """
1013 comb = m.d.comb
1014 sync = m.d.sync
1015 dmi, d_reg, d_cr, d_xer, = dbg.dmi, dbg.d_gpr, dbg.d_cr, dbg.d_xer
1016 intrf = self.core.regs.rf['int']
1017
1018 with m.If(d_reg.req): # request for regfile access being made
1019 # TODO: error-check this
1020 # XXX should this be combinatorial? sync better?
1021 if intrf.unary:
1022 comb += self.int_r.ren.eq(1<<d_reg.addr)
1023 else:
1024 comb += self.int_r.addr.eq(d_reg.addr)
1025 comb += self.int_r.ren.eq(1)
1026 d_reg_delay = Signal()
1027 sync += d_reg_delay.eq(d_reg.req)
1028 with m.If(d_reg_delay):
1029 # data arrives one clock later
1030 comb += d_reg.data.eq(self.int_r.data_o)
1031 comb += d_reg.ack.eq(1)
1032
1033 # sigh same thing for CR debug
1034 with m.If(d_cr.req): # request for regfile access being made
1035 comb += self.cr_r.ren.eq(0b11111111) # enable all
1036 d_cr_delay = Signal()
1037 sync += d_cr_delay.eq(d_cr.req)
1038 with m.If(d_cr_delay):
1039 # data arrives one clock later
1040 comb += d_cr.data.eq(self.cr_r.data_o)
1041 comb += d_cr.ack.eq(1)
1042
1043 # aaand XER...
1044 with m.If(d_xer.req): # request for regfile access being made
1045 comb += self.xer_r.ren.eq(0b111111) # enable all
1046 d_xer_delay = Signal()
1047 sync += d_xer_delay.eq(d_xer.req)
1048 with m.If(d_xer_delay):
1049 # data arrives one clock later
1050 comb += d_xer.data.eq(self.xer_r.data_o)
1051 comb += d_xer.ack.eq(1)
1052
1053 def tb_dec_fsm(self, m, spr_dec):
1054 """tb_dec_fsm
1055
1056 this is a FSM for updating either dec or tb. it runs alternately
1057 DEC, TB, DEC, TB. note that SPR pipeline could have written a new
1058 value to DEC, however the regfile has "passthrough" on it so this
1059 *should* be ok.
1060
1061 see v3.0B p1097-1099 for Timeer Resource and p1065 and p1076
1062 """
1063
1064 comb, sync = m.d.comb, m.d.sync
1065 fast_rf = self.core.regs.rf['fast']
1066 fast_r_dectb = fast_rf.r_ports['issue'] # DEC/TB
1067 fast_w_dectb = fast_rf.w_ports['issue'] # DEC/TB
1068
1069 with m.FSM() as fsm:
1070
1071 # initiates read of current DEC
1072 with m.State("DEC_READ"):
1073 comb += fast_r_dectb.addr.eq(FastRegs.DEC)
1074 comb += fast_r_dectb.ren.eq(1)
1075 m.next = "DEC_WRITE"
1076
1077 # waits for DEC read to arrive (1 cycle), updates with new value
1078 with m.State("DEC_WRITE"):
1079 new_dec = Signal(64)
1080 # TODO: MSR.LPCR 32-bit decrement mode
1081 comb += new_dec.eq(fast_r_dectb.data_o - 1)
1082 comb += fast_w_dectb.addr.eq(FastRegs.DEC)
1083 comb += fast_w_dectb.wen.eq(1)
1084 comb += fast_w_dectb.data_i.eq(new_dec)
1085 sync += spr_dec.eq(new_dec) # copy into cur_state for decoder
1086 m.next = "TB_READ"
1087
1088 # initiates read of current TB
1089 with m.State("TB_READ"):
1090 comb += fast_r_dectb.addr.eq(FastRegs.TB)
1091 comb += fast_r_dectb.ren.eq(1)
1092 m.next = "TB_WRITE"
1093
1094 # waits for read TB to arrive, initiates write of current TB
1095 with m.State("TB_WRITE"):
1096 new_tb = Signal(64)
1097 comb += new_tb.eq(fast_r_dectb.data_o + 1)
1098 comb += fast_w_dectb.addr.eq(FastRegs.TB)
1099 comb += fast_w_dectb.wen.eq(1)
1100 comb += fast_w_dectb.data_i.eq(new_tb)
1101 m.next = "DEC_READ"
1102
1103 return m
1104
1105 def __iter__(self):
1106 yield from self.pc_i.ports()
1107 yield self.pc_o
1108 yield self.memerr_o
1109 yield from self.core.ports()
1110 yield from self.imem.ports()
1111 yield self.core_bigendian_i
1112 yield self.busy_o
1113
1114 def ports(self):
1115 return list(self)
1116
1117 def external_ports(self):
1118 ports = self.pc_i.ports()
1119 ports += [self.pc_o, self.memerr_o, self.core_bigendian_i, self.busy_o,
1120 ]
1121
1122 if self.jtag_en:
1123 ports += list(self.jtag.external_ports())
1124 else:
1125 # don't add DMI if JTAG is enabled
1126 ports += list(self.dbg.dmi.ports())
1127
1128 ports += list(self.imem.ibus.fields.values())
1129 ports += list(self.core.l0.cmpi.lsmem.lsi.slavebus.fields.values())
1130
1131 if self.sram4x4k:
1132 for sram in self.sram4k:
1133 ports += list(sram.bus.fields.values())
1134
1135 if self.xics:
1136 ports += list(self.xics_icp.bus.fields.values())
1137 ports += list(self.xics_ics.bus.fields.values())
1138 ports.append(self.int_level_i)
1139
1140 if self.gpio:
1141 ports += list(self.simple_gpio.bus.fields.values())
1142 ports.append(self.gpio_o)
1143
1144 return ports
1145
1146 def ports(self):
1147 return list(self)
1148
1149
1150 class TestIssuer(Elaboratable):
1151 def __init__(self, pspec):
1152 self.ti = TestIssuerInternal(pspec)
1153
1154 self.pll = DummyPLL()
1155
1156 # PLL direct clock or not
1157 self.pll_en = hasattr(pspec, "use_pll") and pspec.use_pll
1158 if self.pll_en:
1159 self.pll_18_o = Signal(reset_less=True)
1160
1161 def elaborate(self, platform):
1162 m = Module()
1163 comb = m.d.comb
1164
1165 # TestIssuer runs at direct clock
1166 m.submodules.ti = ti = self.ti
1167 cd_int = ClockDomain("coresync")
1168
1169 if self.pll_en:
1170 # ClockSelect runs at PLL output internal clock rate
1171 m.submodules.pll = pll = self.pll
1172
1173 # add clock domains from PLL
1174 cd_pll = ClockDomain("pllclk")
1175 m.domains += cd_pll
1176
1177 # PLL clock established. has the side-effect of running clklsel
1178 # at the PLL's speed (see DomainRenamer("pllclk") above)
1179 pllclk = ClockSignal("pllclk")
1180 comb += pllclk.eq(pll.clk_pll_o)
1181
1182 # wire up external 24mhz to PLL
1183 comb += pll.clk_24_i.eq(ClockSignal())
1184
1185 # output 18 mhz PLL test signal
1186 comb += self.pll_18_o.eq(pll.pll_18_o)
1187
1188 # now wire up ResetSignals. don't mind them being in this domain
1189 pll_rst = ResetSignal("pllclk")
1190 comb += pll_rst.eq(ResetSignal())
1191
1192 # internal clock is set to selector clock-out. has the side-effect of
1193 # running TestIssuer at this speed (see DomainRenamer("intclk") above)
1194 intclk = ClockSignal("coresync")
1195 if self.pll_en:
1196 comb += intclk.eq(pll.clk_pll_o)
1197 else:
1198 comb += intclk.eq(ClockSignal())
1199
1200 return m
1201
1202 def ports(self):
1203 return list(self.ti.ports()) + list(self.pll.ports()) + \
1204 [ClockSignal(), ResetSignal()]
1205
1206 def external_ports(self):
1207 ports = self.ti.external_ports()
1208 ports.append(ClockSignal())
1209 ports.append(ResetSignal())
1210 if self.pll_en:
1211 ports.append(self.pll.clk_sel_i)
1212 ports.append(self.pll_18_o)
1213 ports.append(self.pll.pll_lck_o)
1214 return ports
1215
1216
1217 if __name__ == '__main__':
1218 units = {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1, 'logical': 1,
1219 'spr': 1,
1220 'div': 1,
1221 'mul': 1,
1222 'shiftrot': 1
1223 }
1224 pspec = TestMemPspec(ldst_ifacetype='bare_wb',
1225 imem_ifacetype='bare_wb',
1226 addr_wid=48,
1227 mask_wid=8,
1228 reg_wid=64,
1229 units=units)
1230 dut = TestIssuer(pspec)
1231 vl = main(dut, ports=dut.ports(), name="test_issuer")
1232
1233 if len(sys.argv) == 1:
1234 vl = rtlil.convert(dut, ports=dut.external_ports(), name="test_issuer")
1235 with open("test_issuer.il", "w") as f:
1236 f.write(vl)