1 from nmigen
.compat
.sim
import run_simulation
2 from nmigen
.cli
import verilog
, rtlil
3 from nmigen
.hdl
.ast
import unsigned
4 from nmigen
import Module
, Const
, Signal
, Array
, Cat
, Elaboratable
, Memory
6 from soc
.regfile
.regfile
import RegFileArray
, treereduce
7 from soc
.scoreboard
.fu_fu_matrix
import FUFUDepMatrix
8 from soc
.scoreboard
.fu_reg_matrix
import FURegDepMatrix
9 from soc
.scoreboard
.global_pending
import GlobalPending
10 from soc
.scoreboard
.group_picker
import GroupPicker
11 from soc
.scoreboard
.issue_unit
import IssueUnitGroup
, IssueUnitArray
, RegDecode
12 from soc
.scoreboard
.shadow
import ShadowMatrix
, BranchSpeculationRecord
13 from soc
.scoreboard
.instruction_q
import Instruction
, InstructionQ
14 from soc
.scoreboard
.memfu
import MemFunctionUnits
16 from soc
.experiment
.compalu
import ComputationUnitNoDelay
17 from soc
.experiment
.compldst
import LDSTCompUnit
18 from soc
.experiment
.testmem
import TestMemory
20 from soc
.experiment
.alu_hier
import ALU
, BranchALU
22 from soc
.decoder
.power_enums
import InternalOp
, Function
24 from nmutil
.latch
import SRLatch
25 from nmutil
.nmoperator
import eq
27 from random
import randint
, seed
28 from copy
import deepcopy
31 from soc
.experiment
.sim
import RegSim
, MemSim
32 from soc
.experiment
.sim
import IADD
, ISUB
, IMUL
, ISHF
, IBGT
, IBLT
, IBEQ
, IBNE
35 class CompUnitsBase(Elaboratable
):
36 """ Computation Unit Base class.
38 Amazingly, this class works recursively. It's supposed to just
39 look after some ALUs (that can handle the same operations),
40 grouping them together, however it turns out that the same code
41 can also group *groups* of Computation Units together as well.
43 Basically it was intended just to concatenate the ALU's issue,
44 go_rd etc. signals together, which start out as bits and become
45 sequences. Turns out that the same trick works just as well
48 So this class may be used recursively to present a top-level
49 sequential concatenation of all the signals in and out of
50 ALUs, whilst at the same time making it convenient to group
53 At the lower level, the intent is that groups of (identical)
54 ALUs may be passed the same operation. Even beyond that,
55 the intent is that that group of (identical) ALUs actually
56 share the *same pipeline* and as such become a "Concurrent
57 Computation Unit" as defined by Mitch Alsup (see section
61 def __init__(self
, rwid
, units
, ldstmode
=False):
64 * :rwid: bit width of register file(s) - both FP and INT
65 * :units: sequence of ALUs (or CompUnitsBase derivatives)
68 self
.ldstmode
= ldstmode
71 if units
and isinstance(units
[0], CompUnitsBase
):
74 self
.n_units
+= u
.n_units
76 self
.n_units
= len(units
)
78 n_units
= self
.n_units
81 self
.issue_i
= Signal(n_units
, reset_less
=True)
82 self
.go_rd_i
= Signal(n_units
, reset_less
=True)
83 self
.go_wr_i
= Signal(n_units
, reset_less
=True)
84 self
.shadown_i
= Signal(n_units
, reset_less
=True)
85 self
.go_die_i
= Signal(n_units
, reset_less
=True)
87 self
.go_ad_i
= Signal(n_units
, reset_less
=True)
88 self
.go_st_i
= Signal(n_units
, reset_less
=True)
91 self
.busy_o
= Signal(n_units
, reset_less
=True)
92 self
.rd_rel_o
= Signal(n_units
, reset_less
=True)
93 self
.req_rel_o
= Signal(n_units
, reset_less
=True)
94 self
.done_o
= Signal(n_units
, reset_less
=True)
96 self
.ld_o
= Signal(n_units
, reset_less
=True) # op is LD
97 self
.st_o
= Signal(n_units
, reset_less
=True) # op is ST
98 self
.adr_rel_o
= Signal(n_units
, reset_less
=True)
99 self
.sto_rel_o
= Signal(n_units
, reset_less
=True)
100 self
.load_mem_o
= Signal(n_units
, reset_less
=True)
101 self
.stwd_mem_o
= Signal(n_units
, reset_less
=True)
102 self
.addr_o
= Signal(rwid
, reset_less
=True)
104 # in/out register data (note: not register#, actual data)
105 self
.data_o
= Signal(rwid
, reset_less
=True)
106 self
.src1_i
= Signal(rwid
, reset_less
=True)
107 self
.src2_i
= Signal(rwid
, reset_less
=True)
110 def elaborate(self
, platform
):
114 for i
, alu
in enumerate(self
.units
):
115 setattr(m
.submodules
, "comp%d" % i
, alu
)
126 for alu
in self
.units
:
127 req_rel_l
.append(alu
.req_rel_o
)
128 done_l
.append(alu
.done_o
)
129 rd_rel_l
.append(alu
.rd_rel_o
)
130 shadow_l
.append(alu
.shadown_i
)
131 godie_l
.append(alu
.go_die_i
)
132 go_wr_l
.append(alu
.go_wr_i
)
133 go_rd_l
.append(alu
.go_rd_i
)
134 issue_l
.append(alu
.issue_i
)
135 busy_l
.append(alu
.busy_o
)
136 comb
+= self
.rd_rel_o
.eq(Cat(*rd_rel_l
))
137 comb
+= self
.req_rel_o
.eq(Cat(*req_rel_l
))
138 comb
+= self
.done_o
.eq(Cat(*done_l
))
139 comb
+= self
.busy_o
.eq(Cat(*busy_l
))
140 comb
+= Cat(*godie_l
).eq(self
.go_die_i
)
141 comb
+= Cat(*shadow_l
).eq(self
.shadown_i
)
142 comb
+= Cat(*go_wr_l
).eq(self
.go_wr_i
)
143 comb
+= Cat(*go_rd_l
).eq(self
.go_rd_i
)
144 comb
+= Cat(*issue_l
).eq(self
.issue_i
)
146 # connect data register input/output
148 # merge (OR) all integer FU / ALU outputs to a single value
150 data_o
= treereduce(self
.units
, "data_o")
151 comb
+= self
.data_o
.eq(data_o
)
153 addr_o
= treereduce(self
.units
, "addr_o")
154 comb
+= self
.addr_o
.eq(addr_o
)
156 for i
, alu
in enumerate(self
.units
):
157 comb
+= alu
.src1_i
.eq(self
.src1_i
)
158 comb
+= alu
.src2_i
.eq(self
.src2_i
)
160 if not self
.ldstmode
:
171 for alu
in self
.units
:
172 ld_l
.append(alu
.ld_o
)
173 st_l
.append(alu
.st_o
)
174 adr_rel_l
.append(alu
.adr_rel_o
)
175 sto_rel_l
.append(alu
.sto_rel_o
)
176 ldmem_l
.append(alu
.load_mem_o
)
177 stmem_l
.append(alu
.stwd_mem_o
)
178 go_ad_l
.append(alu
.go_ad_i
)
179 go_st_l
.append(alu
.go_st_i
)
180 comb
+= self
.ld_o
.eq(Cat(*ld_l
))
181 comb
+= self
.st_o
.eq(Cat(*st_l
))
182 comb
+= self
.adr_rel_o
.eq(Cat(*adr_rel_l
))
183 comb
+= self
.sto_rel_o
.eq(Cat(*sto_rel_l
))
184 comb
+= self
.load_mem_o
.eq(Cat(*ldmem_l
))
185 comb
+= self
.stwd_mem_o
.eq(Cat(*stmem_l
))
186 comb
+= Cat(*go_ad_l
).eq(self
.go_ad_i
)
187 comb
+= Cat(*go_st_l
).eq(self
.go_st_i
)
192 class CompUnitLDSTs(CompUnitsBase
):
194 def __init__(self
, rwid
, opwid
, n_ldsts
, mem
):
197 * :rwid: bit width of register file(s) - both FP and INT
198 * :opwid: operand bit width
203 self
.oper_i
= Signal(opwid
, reset_less
=True)
204 self
.imm_i
= Signal(rwid
, reset_less
=True)
208 for i
in range(n_ldsts
):
209 self
.alus
.append(ALU(rwid
))
212 for alu
in self
.alus
:
213 aluopwid
= 4 # see compldst.py for "internal" opcode
214 units
.append(LDSTCompUnit(rwid
, aluopwid
, alu
, mem
))
216 CompUnitsBase
.__init
__(self
, rwid
, units
, ldstmode
=True)
218 def elaborate(self
, platform
):
219 m
= CompUnitsBase
.elaborate(self
, platform
)
222 # hand the same operation to all units, 4 lower bits though
223 for alu
in self
.units
:
224 comb
+= alu
.oper_i
[0:4].eq(self
.oper_i
)
225 comb
+= alu
.imm_i
.eq(self
.imm_i
)
226 comb
+= alu
.isalu_i
.eq(0)
231 class CompUnitALUs(CompUnitsBase
):
233 def __init__(self
, rwid
, opwid
, n_alus
):
236 * :rwid: bit width of register file(s) - both FP and INT
237 * :opwid: operand bit width
242 self
.oper_i
= Signal(opwid
, reset_less
=True)
243 self
.imm_i
= Signal(rwid
, reset_less
=True)
247 for i
in range(n_alus
):
248 alus
.append(ALU(rwid
))
252 aluopwid
= 3 # extra bit for immediate mode
253 units
.append(ComputationUnitNoDelay(rwid
, alu
))
255 CompUnitsBase
.__init
__(self
, rwid
, units
)
257 def elaborate(self
, platform
):
258 m
= CompUnitsBase
.elaborate(self
, platform
)
261 # hand the same operation to all units, only lower 3 bits though
262 for alu
in self
.units
:
263 comb
+= alu
.oper_i
[0:3].eq(self
.oper_i
)
264 comb
+= alu
.imm_i
.eq(self
.imm_i
)
269 class CompUnitBR(CompUnitsBase
):
271 def __init__(self
, rwid
, opwid
):
274 * :rwid: bit width of register file(s) - both FP and INT
275 * :opwid: operand bit width
277 Note: bgt unit is returned so that a shadow unit can be created
283 self
.oper_i
= Signal(opwid
, reset_less
=True)
284 self
.imm_i
= Signal(rwid
, reset_less
=True)
287 self
.bgt
= BranchALU(rwid
)
288 aluopwid
= 3 # extra bit for immediate mode
289 self
.br1
= ComputationUnitNoDelay(rwid
, self
.bgt
)
290 CompUnitsBase
.__init
__(self
, rwid
, [self
.br1
])
292 def elaborate(self
, platform
):
293 m
= CompUnitsBase
.elaborate(self
, platform
)
296 # hand the same operation to all units
297 for alu
in self
.units
:
298 comb
+= alu
.oper_i
.eq(self
.oper_i
)
299 comb
+= alu
.imm_i
.eq(self
.imm_i
)
304 class FunctionUnits(Elaboratable
):
306 def __init__(self
, n_regs
, n_int_alus
):
308 self
.n_int_alus
= n_int_alus
310 self
.dest_i
= Signal(n_regs
, reset_less
=True) # Dest R# in
311 self
.src1_i
= Signal(n_regs
, reset_less
=True) # oper1 R# in
312 self
.src2_i
= Signal(n_regs
, reset_less
=True) # oper2 R# in
314 self
.g_int_rd_pend_o
= Signal(n_regs
, reset_less
=True)
315 self
.g_int_wr_pend_o
= Signal(n_regs
, reset_less
=True)
317 self
.dest_rsel_o
= Signal(n_regs
, reset_less
=True) # dest reg (bot)
318 self
.src1_rsel_o
= Signal(n_regs
, reset_less
=True) # src1 reg (bot)
319 self
.src2_rsel_o
= Signal(n_regs
, reset_less
=True) # src2 reg (bot)
321 self
.readable_o
= Signal(n_int_alus
, reset_less
=True)
322 self
.writable_o
= Signal(n_int_alus
, reset_less
=True)
324 self
.go_rd_i
= Signal(n_int_alus
, reset_less
=True)
325 self
.go_wr_i
= Signal(n_int_alus
, reset_less
=True)
326 self
.go_die_i
= Signal(n_int_alus
, reset_less
=True)
327 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
329 # Note: FURegs wr_pend_o is also outputted from here, for use in WaWGrid
331 def elaborate(self
, platform
):
336 n_intfus
= self
.n_int_alus
338 # Integer FU-FU Dep Matrix
339 intfudeps
= FUFUDepMatrix(n_intfus
, n_intfus
)
340 m
.submodules
.intfudeps
= intfudeps
341 # Integer FU-Reg Dep Matrix
342 intregdeps
= FURegDepMatrix(n_intfus
, self
.n_regs
, 2)
343 m
.submodules
.intregdeps
= intregdeps
345 comb
+= self
.g_int_rd_pend_o
.eq(intregdeps
.v_rd_rsel_o
)
346 comb
+= self
.g_int_wr_pend_o
.eq(intregdeps
.v_wr_rsel_o
)
348 comb
+= intregdeps
.rd_pend_i
.eq(intregdeps
.v_rd_rsel_o
)
349 comb
+= intregdeps
.wr_pend_i
.eq(intregdeps
.v_wr_rsel_o
)
351 comb
+= intfudeps
.rd_pend_i
.eq(intregdeps
.rd_pend_o
)
352 comb
+= intfudeps
.wr_pend_i
.eq(intregdeps
.wr_pend_o
)
353 self
.wr_pend_o
= intregdeps
.wr_pend_o
# also output for use in WaWGrid
355 comb
+= intfudeps
.issue_i
.eq(self
.fn_issue_i
)
356 comb
+= intfudeps
.go_rd_i
.eq(self
.go_rd_i
)
357 comb
+= intfudeps
.go_wr_i
.eq(self
.go_wr_i
)
358 comb
+= intfudeps
.go_die_i
.eq(self
.go_die_i
)
359 comb
+= self
.readable_o
.eq(intfudeps
.readable_o
)
360 comb
+= self
.writable_o
.eq(intfudeps
.writable_o
)
362 # Connect function issue / arrays, and dest/src1/src2
363 comb
+= intregdeps
.dest_i
.eq(self
.dest_i
)
364 comb
+= intregdeps
.src_i
[0].eq(self
.src1_i
)
365 comb
+= intregdeps
.src_i
[1].eq(self
.src2_i
)
367 comb
+= intregdeps
.go_rd_i
.eq(self
.go_rd_i
)
368 comb
+= intregdeps
.go_wr_i
.eq(self
.go_wr_i
)
369 comb
+= intregdeps
.go_die_i
.eq(self
.go_die_i
)
370 comb
+= intregdeps
.issue_i
.eq(self
.fn_issue_i
)
372 comb
+= self
.dest_rsel_o
.eq(intregdeps
.dest_rsel_o
)
373 comb
+= self
.src1_rsel_o
.eq(intregdeps
.src_rsel_o
[0])
374 comb
+= self
.src2_rsel_o
.eq(intregdeps
.src_rsel_o
[1])
379 class Scoreboard(Elaboratable
):
380 def __init__(self
, rwid
, n_regs
):
383 * :rwid: bit width of register file(s) - both FP and INT
384 * :n_regs: depth of register file(s) - number of FP and INT regs
390 self
.intregs
= RegFileArray(rwid
, n_regs
)
391 self
.fpregs
= RegFileArray(rwid
, n_regs
)
393 # Memory (test for now)
394 self
.mem
= TestMemory(self
.rwid
, 8) # not too big, takes too long
396 # issue q needs to get at these
397 self
.aluissue
= IssueUnitGroup(2)
398 self
.lsissue
= IssueUnitGroup(2)
399 self
.brissue
= IssueUnitGroup(1)
401 self
.alu_oper_i
= Signal(4, reset_less
=True)
402 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
403 self
.br_oper_i
= Signal(4, reset_less
=True)
404 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
405 self
.ls_oper_i
= Signal(4, reset_less
=True)
406 self
.ls_imm_i
= Signal(rwid
, reset_less
=True)
409 self
.int_dest_i
= Signal(range(n_regs
), reset_less
=True) # Dest R# in
410 self
.int_src1_i
= Signal(range(n_regs
), reset_less
=True) # oper1 R# in
411 self
.int_src2_i
= Signal(range(n_regs
), reset_less
=True) # oper2 R# in
412 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
415 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
416 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
418 # for branch speculation experiment. branch_direction = 0 if
419 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
420 # branch_succ and branch_fail are requests to have the current
421 # instruction be dependent on the branch unit "shadow" capability.
422 self
.branch_succ_i
= Signal(reset_less
=True)
423 self
.branch_fail_i
= Signal(reset_less
=True)
424 self
.branch_direction_o
= Signal(2, reset_less
=True)
426 def elaborate(self
, platform
):
431 m
.submodules
.intregs
= self
.intregs
432 m
.submodules
.fpregs
= self
.fpregs
433 m
.submodules
.mem
= mem
= self
.mem
436 int_dest
= self
.intregs
.write_port("dest")
437 int_src1
= self
.intregs
.read_port("src1")
438 int_src2
= self
.intregs
.read_port("src2")
440 fp_dest
= self
.fpregs
.write_port("dest")
441 fp_src1
= self
.fpregs
.read_port("src1")
442 fp_src2
= self
.fpregs
.read_port("src2")
444 # Int ALUs and BR ALUs
446 cua
= CompUnitALUs(self
.rwid
, 3, n_alus
=self
.aluissue
.n_insns
)
447 cub
= CompUnitBR(self
.rwid
, 3) # 1 BR ALUs
451 cul
= CompUnitLDSTs(self
.rwid
, 4, self
.lsissue
.n_insns
, self
.mem
)
454 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cul
, cub
])
455 bgt
= cub
.bgt
# get at the branch computation unit
459 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
462 m
.submodules
.memfus
= memfus
= MemFunctionUnits(n_ldsts
, 5)
464 # Memory Priority Picker 1: one gateway per memory port
465 # picks 1 reader and 1 writer to intreg
466 mempick1
= GroupPicker(n_ldsts
)
467 m
.submodules
.mempick1
= mempick1
469 # Count of number of FUs
470 n_intfus
= n_int_alus
471 n_fp_fus
= 0 # for now
473 # Integer Priority Picker 1: Adder + Subtractor (and LD/ST)
474 # picks 1 reader and 1 writer to intreg
475 intpick1
= GroupPicker(n_intfus
)
476 m
.submodules
.intpick1
= intpick1
479 regdecode
= RegDecode(self
.n_regs
)
480 m
.submodules
.regdecode
= regdecode
481 issueunit
= IssueUnitArray([self
.aluissue
, self
.lsissue
, self
.brissue
])
482 m
.submodules
.issueunit
= issueunit
484 # Shadow Matrix. currently n_intfus shadows, to be used for
485 # write-after-write hazards. NOTE: there is one extra for branches,
486 # so the shadow width is increased by 1
487 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
488 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
490 # record previous instruction to cast shadow on current instruction
491 prev_shadow
= Signal(n_intfus
)
493 # Branch Speculation recorder. tracks the success/fail state as
494 # each instruction is issued, so that when the branch occurs the
495 # allow/cancel can be issued as appropriate.
496 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
499 # ok start wiring things together...
500 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
501 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
505 # Issue Unit is where it starts. set up some in/outs for this module
507 comb
+= [regdecode
.dest_i
.eq(self
.int_dest_i
),
508 regdecode
.src1_i
.eq(self
.int_src1_i
),
509 regdecode
.src2_i
.eq(self
.int_src2_i
),
510 regdecode
.enable_i
.eq(self
.reg_enable_i
),
511 self
.issue_o
.eq(issueunit
.issue_o
)
514 # take these to outside (issue needs them)
515 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
516 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
517 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
518 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
519 comb
+= cul
.oper_i
.eq(self
.ls_oper_i
)
520 comb
+= cul
.imm_i
.eq(self
.ls_imm_i
)
522 # TODO: issueunit.f (FP)
524 # and int function issue / busy arrays, and dest/src1/src2
525 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
526 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
527 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
529 fn_issue_o
= issueunit
.fn_issue_o
531 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
532 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
533 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
536 # Memory Function Unit
538 reset_b
= Signal(cul
.n_units
, reset_less
=True)
539 sync
+= reset_b
.eq(cul
.go_st_i | cul
.go_wr_i | cul
.go_die_i
)
541 comb
+= memfus
.fn_issue_i
.eq(cul
.issue_i
) # Comp Unit Issue -> Mem FUs
542 comb
+= memfus
.addr_en_i
.eq(cul
.adr_rel_o
) # Match enable on adr rel
543 comb
+= memfus
.addr_rs_i
.eq(reset_b
) # reset same as LDSTCompUnit
545 # LD/STs have to accumulate prior LD/STs (TODO: multi-issue as well,
546 # in a transitive fashion). This cycle activates based on LDSTCompUnit
547 # issue_i. multi-issue gets a bit more complex but not a lot.
548 prior_ldsts
= Signal(cul
.n_units
, reset_less
=True)
549 sync
+= prior_ldsts
.eq(memfus
.g_int_ld_pend_o | memfus
.g_int_st_pend_o
)
550 with m
.If(self
.ls_oper_i
[3]): # LD bit of operand
551 comb
+= memfus
.ld_i
.eq(cul
.issue_i | prior_ldsts
)
552 with m
.If(self
.ls_oper_i
[2]): # ST bit of operand
553 comb
+= memfus
.st_i
.eq(cul
.issue_i | prior_ldsts
)
555 # TODO: adr_rel_o needs to go into L1 Cache. for now,
556 # just immediately activate go_adr
557 comb
+= cul
.go_ad_i
.eq(cul
.adr_rel_o
)
559 # connect up address data
560 comb
+= memfus
.addrs_i
[0].eq(cul
.units
[0].addr_o
)
561 comb
+= memfus
.addrs_i
[1].eq(cul
.units
[1].addr_o
)
563 # connect loadable / storable to go_ld/go_st.
564 # XXX should only be done when the memory ld/st has actually happened!
565 go_st_i
= Signal(cul
.n_units
, reset_less
=True)
566 go_ld_i
= Signal(cul
.n_units
, reset_less
=True)
567 comb
+= go_ld_i
.eq(memfus
.loadable_o
& memfus
.addr_nomatch_o
&
568 cul
.adr_rel_o
& cul
.ld_o
)
569 comb
+= go_st_i
.eq(memfus
.storable_o
& memfus
.addr_nomatch_o
&
570 cul
.sto_rel_o
& cul
.st_o
)
571 comb
+= memfus
.go_ld_i
.eq(go_ld_i
)
572 comb
+= memfus
.go_st_i
.eq(go_st_i
)
573 #comb += cul.go_wr_i.eq(go_ld_i)
574 comb
+= cul
.go_st_i
.eq(go_st_i
)
576 #comb += cu.go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus])
577 #comb += cu.go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus])
578 #comb += cu.issue_i[0:n_intfus].eq(fn_issue_o[0:n_intfus])
581 # merge shadow matrices outputs
584 # these are explained in ShadowMatrix docstring, and are to be
585 # connected to the FUReg and FUFU Matrices, to get them to reset
586 anydie
= Signal(n_intfus
, reset_less
=True)
587 allshadown
= Signal(n_intfus
, reset_less
=True)
588 shreset
= Signal(n_intfus
, reset_less
=True)
589 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
590 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
591 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
594 # connect fu-fu matrix
597 # Group Picker... done manually for now.
598 go_rd_o
= intpick1
.go_rd_o
599 go_wr_o
= intpick1
.go_wr_o
600 go_rd_i
= intfus
.go_rd_i
601 go_wr_i
= intfus
.go_wr_i
602 go_die_i
= intfus
.go_die_i
603 # NOTE: connect to the shadowed versions so that they can "die" (reset)
604 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
605 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
606 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
610 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
611 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.done_o
[0:n_intfus
])
612 int_rd_o
= intfus
.readable_o
613 int_wr_o
= intfus
.writable_o
614 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
615 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
621 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
622 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
623 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
625 # NOTE; this setup is for the instruction order preservation...
627 # connect shadows / go_dies to Computation Units
628 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
629 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
631 # ok connect first n_int_fu shadows to busy lines, to create an
632 # instruction-order linked-list-like arrangement, using a bit-matrix
633 # (instead of e.g. a ring buffer).
635 # when written, the shadow can be cancelled (and was good)
636 for i
in range(n_intfus
):
637 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
639 # *previous* instruction shadows *current* instruction, and, obviously,
640 # if the previous is completed (!busy) don't cast the shadow!
641 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
642 for i
in range(n_intfus
):
643 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
646 # ... and this is for branch speculation. it uses the extra bit
647 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
648 # only needs to set shadow_i, s_fail_i and s_good_i
650 # issue captures shadow_i (if enabled)
651 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
653 bactive
= Signal(reset_less
=True)
654 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
656 # instruction being issued (fn_issue_o) has a shadow cast by the branch
657 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
658 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
659 for i
in range(n_intfus
):
660 with m
.If(fn_issue_o
& (Const(1 << i
))):
661 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
663 # finally, we need an indicator to the test infrastructure as to
664 # whether the branch succeeded or failed, plus, link up to the
665 # "recorder" of whether the instruction was under shadow or not
667 with m
.If(br1
.issue_i
):
668 sync
+= bspec
.active_i
.eq(1)
669 with m
.If(self
.branch_succ_i
):
670 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f) # XXX MAGIC CONSTANT
671 with m
.If(self
.branch_fail_i
):
672 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f) # XXX MAGIC CONSTANT
674 # branch is active (TODO: a better signal: this is over-using the
675 # go_write signal - actually the branch should not be "writing")
676 with m
.If(br1
.go_wr_i
):
677 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
678 sync
+= bspec
.active_i
.eq(0)
679 comb
+= bspec
.br_i
.eq(1)
680 # branch occurs if data == 1, failed if data == 0
681 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
682 for i
in range(n_intfus
):
683 # *expected* direction of the branch matched against *actual*
684 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
686 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
689 # Connect Register File(s)
691 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
692 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
693 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
695 # connect ALUs to regfule
696 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
697 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
698 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
700 # connect ALU Computation Units
701 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
702 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
703 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
708 yield from self
.intregs
709 yield from self
.fpregs
710 yield self
.int_dest_i
711 yield self
.int_src1_i
712 yield self
.int_src2_i
714 yield self
.branch_succ_i
715 yield self
.branch_fail_i
716 yield self
.branch_direction_o
722 class IssueToScoreboard(Elaboratable
):
724 def __init__(self
, qlen
, n_in
, n_out
, rwid
, opwid
, n_regs
):
732 mqbits
= unsigned(int(log(qlen
) / log(2))+2)
733 self
.p_add_i
= Signal(mqbits
) # instructions to add (from data_i)
734 self
.p_ready_o
= Signal() # instructions were added
735 self
.data_i
= Instruction
._nq
(n_in
, "data_i")
737 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
738 self
.qlen_o
= Signal(mqbits
, reset_less
=True)
740 def elaborate(self
, platform
):
745 iq
= InstructionQ(self
.rwid
, self
.opw
, self
.qlen
,
746 self
.n_in
, self
.n_out
)
747 sc
= Scoreboard(self
.rwid
, self
.n_regs
)
751 # get at the regfile for testing
752 self
.intregs
= sc
.intregs
754 # and the "busy" signal and instruction queue length
755 comb
+= self
.busy_o
.eq(sc
.busy_o
)
756 comb
+= self
.qlen_o
.eq(iq
.qlen_o
)
758 # link up instruction queue
759 comb
+= iq
.p_add_i
.eq(self
.p_add_i
)
760 comb
+= self
.p_ready_o
.eq(iq
.p_ready_o
)
761 for i
in range(self
.n_in
):
762 comb
+= eq(iq
.data_i
[i
], self
.data_i
[i
])
764 # take instruction and process it. note that it's possible to
765 # "inspect" the queue contents *without* actually removing the
766 # items. items are only removed when the
769 wait_issue_br
= Signal()
770 wait_issue_alu
= Signal()
771 wait_issue_ls
= Signal()
773 with m
.If(wait_issue_br | wait_issue_alu | wait_issue_ls
):
774 # set instruction pop length to 1 if the unit accepted
775 with m
.If(wait_issue_ls
& (sc
.lsissue
.fn_issue_o
!= 0)):
776 with m
.If(iq
.qlen_o
!= 0):
777 comb
+= iq
.n_sub_i
.eq(1)
778 with m
.If(wait_issue_br
& (sc
.brissue
.fn_issue_o
!= 0)):
779 with m
.If(iq
.qlen_o
!= 0):
780 comb
+= iq
.n_sub_i
.eq(1)
781 with m
.If(wait_issue_alu
& (sc
.aluissue
.fn_issue_o
!= 0)):
782 with m
.If(iq
.qlen_o
!= 0):
783 comb
+= iq
.n_sub_i
.eq(1)
785 # see if some instruction(s) are here. note that this is
786 # "inspecting" the in-place queue. note also that on the
787 # cycle following "waiting" for fn_issue_o to be set, the
788 # "resetting" done above (insn_i=0) could be re-ASSERTed.
789 with m
.If(iq
.qlen_o
!= 0):
790 # get the operands and operation
791 imm
= iq
.data_o
[0].imm_data
.data
792 dest
= iq
.data_o
[0].write_reg
.data
793 src1
= iq
.data_o
[0].read_reg1
.data
794 src2
= iq
.data_o
[0].read_reg2
.data
795 op
= iq
.data_o
[0].insn_type
796 fu
= iq
.data_o
[0].fn_unit
797 opi
= iq
.data_o
[0].imm_data
.ok
# immediate set
799 # set the src/dest regs
800 comb
+= sc
.int_dest_i
.eq(dest
)
801 comb
+= sc
.int_src1_i
.eq(src1
)
802 comb
+= sc
.int_src2_i
.eq(src2
)
803 comb
+= sc
.reg_enable_i
.eq(1) # enable the regfile
805 # choose a Function-Unit-Group
806 with m
.If((op
& (0x3 << 2)) != 0): # branch
807 comb
+= sc
.br_oper_i
.eq(Cat(op
[0:2], opi
))
808 comb
+= sc
.br_imm_i
.eq(imm
)
809 comb
+= sc
.brissue
.insn_i
.eq(1)
810 comb
+= wait_issue_br
.eq(1)
811 with m
.Elif((op
& (0x3 << 4)) != 0): # ld/st
817 comb
+= sc
.ls_oper_i
.eq(Cat(op
[0], opi
[0], op
[4:6]))
818 comb
+= sc
.ls_imm_i
.eq(imm
)
819 comb
+= sc
.lsissue
.insn_i
.eq(1)
820 comb
+= wait_issue_ls
.eq(1)
822 comb
+= sc
.alu_oper_i
.eq(Cat(op
[0:2], opi
))
823 comb
+= sc
.alu_imm_i
.eq(imm
)
824 comb
+= sc
.aluissue
.insn_i
.eq(1)
825 comb
+= wait_issue_alu
.eq(1)
828 # these indicate that the instruction is to be made
829 # shadow-dependent on
830 # (either) branch success or branch fail
831 # yield sc.branch_fail_i.eq(branch_fail)
832 # yield sc.branch_succ_i.eq(branch_success)
838 for o
in self
.data_i
:
846 def instr_q(dut
, op
, funit
, op_imm
, imm
, src1
, src2
, dest
,
847 branch_success
, branch_fail
):
848 instrs
= [{'insn_type': op
, 'fn_unit': funit
, 'write_reg': dest
,
849 'imm_data': (imm
, op_imm
),
850 'read_reg1': src1
, 'read_reg2': src2
}]
853 for idx
, instr
in enumerate(instrs
):
854 imm
, op_imm
= instr
['imm_data']
855 reg1
= instr
['read_reg1']
856 reg2
= instr
['read_reg2']
857 dest
= instr
['write_reg']
858 insn_type
= instr
['insn_type']
859 fn_unit
= instr
['fn_unit']
860 yield dut
.data_i
[idx
].insn_type
.eq(insn_type
)
861 yield dut
.data_i
[idx
].fn_unit
.eq(fn_unit
)
862 yield dut
.data_i
[idx
].read_reg1
.data
.eq(reg1
)
863 yield dut
.data_i
[idx
].read_reg1
.ok
.eq(1) # XXX TODO
864 yield dut
.data_i
[idx
].read_reg2
.data
.eq(reg2
)
865 yield dut
.data_i
[idx
].read_reg2
.ok
.eq(1) # XXX TODO
866 yield dut
.data_i
[idx
].write_reg
.data
.eq(dest
)
867 yield dut
.data_i
[idx
].write_reg
.ok
.eq(1) # XXX TODO
868 yield dut
.data_i
[idx
].imm_data
.data
.eq(imm
)
869 yield dut
.data_i
[idx
].imm_data
.ok
.eq(op_imm
)
870 di
= yield dut
.data_i
[idx
]
871 print("senddata %d %x" % (idx
, di
))
872 yield dut
.p_add_i
.eq(sendlen
)
874 o_p_ready
= yield dut
.p_ready_o
877 o_p_ready
= yield dut
.p_ready_o
879 yield dut
.p_add_i
.eq(0)
882 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
883 yield from disable_issue(dut
)
884 yield dut
.int_dest_i
.eq(dest
)
885 yield dut
.int_src1_i
.eq(src1
)
886 yield dut
.int_src2_i
.eq(src2
)
887 if (op
& (0x3 << 2)) != 0: # branch
888 yield dut
.brissue
.insn_i
.eq(1)
889 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
890 yield dut
.br_imm_i
.eq(imm
)
891 dut_issue
= dut
.brissue
893 yield dut
.aluissue
.insn_i
.eq(1)
894 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
895 yield dut
.alu_imm_i
.eq(imm
)
896 dut_issue
= dut
.aluissue
897 yield dut
.reg_enable_i
.eq(1)
899 # these indicate that the instruction is to be made shadow-dependent on
900 # (either) branch success or branch fail
901 yield dut
.branch_fail_i
.eq(branch_fail
)
902 yield dut
.branch_succ_i
.eq(branch_success
)
905 yield from wait_for_issue(dut
, dut_issue
)
908 def print_reg(dut
, rnums
):
911 reg
= yield dut
.intregs
.regs
[rnum
].reg
912 rs
.append("%x" % reg
)
913 rnums
= map(str, rnums
)
914 print("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
917 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
919 for i
in range(n_ops
):
920 src1
= randint(1, dut
.n_regs
-1)
921 src2
= randint(1, dut
.n_regs
-1)
922 imm
= randint(1, (1 << dut
.rwid
)-1)
923 dest
= randint(1, dut
.n_regs
-1)
924 op
= randint(0, max_opnums
)
925 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
928 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
930 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
934 def wait_for_busy_clear(dut
):
936 busy_o
= yield dut
.busy_o
943 def disable_issue(dut
):
944 yield dut
.aluissue
.insn_i
.eq(0)
945 yield dut
.brissue
.insn_i
.eq(0)
946 yield dut
.lsissue
.insn_i
.eq(0)
949 def wait_for_issue(dut
, dut_issue
):
951 issue_o
= yield dut_issue
.fn_issue_o
953 yield from disable_issue(dut
)
954 yield dut
.reg_enable_i
.eq(0)
957 # yield from print_reg(dut, [1,2,3])
959 # yield from print_reg(dut, [1,2,3])
962 def scoreboard_branch_sim(dut
, alusim
):
968 print("rseed", iseed
)
972 yield dut
.branch_direction_o
.eq(0)
974 # set random values in the registers
975 for i
in range(1, dut
.n_regs
):
977 val
= randint(0, (1 << alusim
.rwidth
)-1)
978 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
979 alusim
.setval(i
, val
)
982 # create some instructions: branches create a tree
983 insts
= create_random_ops(dut
, 1, True, 1)
984 #insts.append((6, 6, 1, 2, (0, 0)))
985 #insts.append((4, 3, 3, 0, (0, 0)))
987 src1
= randint(1, dut
.n_regs
-1)
988 src2
= randint(1, dut
.n_regs
-1)
990 op
= 4 # only BGT at the moment
992 branch_ok
= create_random_ops(dut
, 1, True, 1)
993 branch_fail
= create_random_ops(dut
, 1, True, 1)
995 insts
.append((src1
, src2
, (branch_ok
, branch_fail
), op
, (0, 0)))
999 insts
.append((3, 5, 2, 0, (0, 0)))
1002 #branch_ok.append ( (5, 7, 5, 1, (1, 0)) )
1003 branch_ok
.append(None)
1004 branch_fail
.append((1, 1, 2, 0, (0, 1)))
1005 #branch_fail.append( None )
1006 insts
.append((6, 4, (branch_ok
, branch_fail
), 4, (0, 0)))
1008 siminsts
= deepcopy(insts
)
1010 # issue instruction(s)
1013 branch_direction
= 0
1018 branch_direction
= yield dut
.branch_direction_o
# way branch went
1019 (src1
, src2
, dest
, op
, (shadow_on
, shadow_off
)) = insts
.pop(0)
1020 if branch_direction
== 1 and shadow_on
:
1021 print("skip", i
, src1
, src2
, dest
, op
, shadow_on
, shadow_off
)
1022 continue # branch was "success" and this is a "failed"... skip
1023 if branch_direction
== 2 and shadow_off
:
1024 print("skip", i
, src1
, src2
, dest
, op
, shadow_on
, shadow_off
)
1025 continue # branch was "fail" and this is a "success"... skip
1026 if branch_direction
!= 0:
1031 branch_ok
, branch_fail
= dest
1033 # ok zip up the branch success / fail instructions and
1034 # drop them into the queue, one marked "to have branch success"
1035 # the other to be marked shadow branch "fail".
1036 # one out of each of these will be cancelled
1037 for ok
, fl
in zip(branch_ok
, branch_fail
):
1039 instrs
.append((ok
[0], ok
[1], ok
[2], ok
[3], (1, 0)))
1041 instrs
.append((fl
[0], fl
[1], fl
[2], fl
[3], (0, 1)))
1042 print("instr %d: (%d, %d, %d, %d, (%d, %d))" %
1043 (i
, src1
, src2
, dest
, op
, shadow_on
, shadow_off
))
1044 yield from int_instr(dut
, op
, src1
, src2
, dest
,
1045 shadow_on
, shadow_off
)
1047 # wait for all instructions to stop before checking
1049 yield from wait_for_busy_clear(dut
)
1053 instr
= siminsts
.pop(0)
1056 (src1
, src2
, dest
, op
, (shadow_on
, shadow_off
)) = instr
1060 branch_ok
, branch_fail
= dest
1062 print("sim %d: (%d, %d, %d, %d, (%d, %d))" %
1063 (i
, src1
, src2
, dest
, op
, shadow_on
, shadow_off
))
1064 branch_res
= alusim
.op(op
, src1
, src2
, dest
)
1067 siminsts
+= branch_ok
1069 siminsts
+= branch_fail
1072 yield from alusim
.check(dut
)
1073 yield from alusim
.dump(dut
)
1076 def scoreboard_sim(dut
, alusim
):
1082 # set random values in the registers
1083 for i
in range(1, dut
.n_regs
):
1084 #val = randint(0, (1<<alusim.rwidth)-1)
1087 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
1088 alusim
.setval(i
, val
)
1090 # create some instructions (some random, some regression tests)
1093 instrs
= create_random_ops(dut
, 15, True, 4)
1095 if False: # LD/ST test (with immediate)
1096 instrs
.append((1, 2, 0, 0x20, 1, 1, (0, 0))) # LD
1097 #instrs.append( (1, 2, 0, 0x10, 1, 1, (0, 0)) )
1100 instrs
.append((1, 2, 2, 1, 1, 20, (0, 0)))
1103 instrs
.append((7, 3, 2, 4, 0, 0, (0, 0)))
1104 instrs
.append((7, 6, 6, 2, 0, 0, (0, 0)))
1105 instrs
.append((1, 7, 2, 2, 0, 0, (0, 0)))
1108 instrs
.append((2, 3, 3, InternalOp
.OP_ADD
, Function
.ALU
,
1112 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
1113 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
1114 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
1115 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
1116 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
1119 instrs
.append((3, 3, 4, 0, 0, 13979, (0, 0)))
1120 instrs
.append((6, 4, 1, 2, 0, 40976, (0, 0)))
1121 instrs
.append((1, 4, 7, 4, 1, 23652, (0, 0)))
1124 instrs
.append((5, 6, 2, 1))
1125 instrs
.append((2, 2, 4, 0))
1126 #instrs.append((2, 2, 3, 1))
1129 instrs
.append((2, 1, 2, 3))
1132 instrs
.append((2, 6, 2, 1))
1133 instrs
.append((2, 1, 2, 0))
1136 instrs
.append((1, 2, 7, 2))
1137 instrs
.append((7, 1, 5, 0))
1138 instrs
.append((4, 4, 1, 1))
1141 instrs
.append((5, 6, 2, 2))
1142 instrs
.append((1, 1, 4, 1))
1143 instrs
.append((6, 5, 3, 0))
1146 # Write-after-Write Hazard
1147 instrs
.append((3, 6, 7, 2))
1148 instrs
.append((4, 4, 7, 1))
1151 # self-read/write-after-write followed by Read-after-Write
1152 instrs
.append((1, 1, 1, 1))
1153 instrs
.append((1, 5, 3, 0))
1156 # Read-after-Write followed by self-read-after-write
1157 instrs
.append((5, 6, 1, 2))
1158 instrs
.append((1, 1, 1, 1))
1161 # self-read-write sandwich
1162 instrs
.append((5, 6, 1, 2))
1163 instrs
.append((1, 1, 1, 1))
1164 instrs
.append((1, 5, 3, 0))
1167 # very weird failure
1168 instrs
.append((5, 2, 5, 2))
1169 instrs
.append((2, 6, 3, 0))
1170 instrs
.append((4, 2, 2, 1))
1174 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
1175 alusim
.setval(5, v1
)
1176 yield dut
.intregs
.regs
[3].reg
.eq(5)
1178 instrs
.append((5, 3, 3, 4, (0, 0)))
1179 instrs
.append((4, 2, 1, 2, (0, 1)))
1183 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
1184 alusim
.setval(5, v1
)
1185 yield dut
.intregs
.regs
[3].reg
.eq(5)
1187 instrs
.append((5, 3, 3, 4, (0, 0)))
1188 instrs
.append((4, 2, 1, 2, (1, 0)))
1191 instrs
.append((4, 3, 5, 1, 0, (0, 0)))
1192 instrs
.append((5, 2, 3, 1, 0, (0, 0)))
1193 instrs
.append((7, 1, 5, 2, 0, (0, 0)))
1194 instrs
.append((5, 6, 6, 4, 0, (0, 0)))
1195 instrs
.append((7, 5, 2, 2, 0, (1, 0)))
1196 instrs
.append((1, 7, 5, 0, 0, (0, 1)))
1197 instrs
.append((1, 6, 1, 2, 0, (1, 0)))
1198 instrs
.append((1, 6, 7, 3, 0, (0, 0)))
1199 instrs
.append((6, 7, 7, 0, 0, (0, 0)))
1201 # issue instruction(s), wait for issue to be free before proceeding
1202 for i
, instr
in enumerate(instrs
):
1204 src1
, src2
, dest
, op
, fn_unit
, opi
, imm
, (br_ok
, br_fail
) = instr
1206 print("instr %d: (%d, %d, %d, %s, %s, %d, %d)" %
1207 (i
, src1
, src2
, dest
, op
, fn_unit
, opi
, imm
))
1208 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
1209 yield from instr_q(dut
, op
, fn_unit
, opi
, imm
, src1
, src2
, dest
,
1212 # wait for all instructions to stop before checking
1214 iqlen
= yield dut
.qlen_o
1222 yield from wait_for_busy_clear(dut
)
1225 yield from alusim
.check(dut
)
1226 yield from alusim
.dump(dut
)
1229 def test_scoreboard():
1230 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
1231 alusim
= RegSim(16, 8)
1232 memsim
= MemSim(16, 8)
1233 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
1234 with
open("test_scoreboard6600.il", "w") as f
:
1237 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
1238 vcd_name
='test_scoreboard6600.vcd')
1240 # run_simulation(dut, scoreboard_branch_sim(dut, alusim),
1241 # vcd_name='test_scoreboard6600.vcd')
1244 if __name__
== '__main__':