1 from nmigen
.compat
.sim
import run_simulation
2 from nmigen
.cli
import verilog
, rtlil
3 from nmigen
import Module
, Const
, Signal
, Array
, Cat
, Elaboratable
5 from regfile
.regfile
import RegFileArray
, treereduce
6 from scoreboard
.fn_unit
import IntFnUnit
, FPFnUnit
, LDFnUnit
, STFnUnit
7 from scoreboard
.fu_fu_matrix
import FUFUDepMatrix
8 from scoreboard
.fu_reg_matrix
import FURegDepMatrix
9 from scoreboard
.global_pending
import GlobalPending
10 from scoreboard
.group_picker
import GroupPicker
11 from scoreboard
.issue_unit
import IntFPIssueUnit
, RegDecode
12 from scoreboard
.shadow
import ShadowMatrix
, WaWGrid
14 from compalu
import ComputationUnitNoDelay
16 from alu_hier
import ALU
, BranchALU
17 from nmutil
.latch
import SRLatch
19 from random
import randint
22 class CompUnits(Elaboratable
):
24 def __init__(self
, rwid
, n_units
):
27 * :rwid: bit width of register file(s) - both FP and INT
28 * :n_units: number of ALUs
30 self
.n_units
= n_units
33 self
.issue_i
= Signal(n_units
, reset_less
=True)
34 self
.go_rd_i
= Signal(n_units
, reset_less
=True)
35 self
.go_wr_i
= Signal(n_units
, reset_less
=True)
36 self
.shadown_i
= Signal(n_units
, reset_less
=True)
37 self
.go_die_i
= Signal(n_units
, reset_less
=True)
38 self
.busy_o
= Signal(n_units
, reset_less
=True)
39 self
.rd_rel_o
= Signal(n_units
, reset_less
=True)
40 self
.req_rel_o
= Signal(n_units
, reset_less
=True)
42 self
.dest_o
= Signal(rwid
, reset_less
=True)
43 self
.src1_data_i
= Signal(rwid
, reset_less
=True)
44 self
.src2_data_i
= Signal(rwid
, reset_less
=True)
46 def elaborate(self
, platform
):
55 bgt
= BranchALU(self
.rwid
)
57 m
.submodules
.comp1
= comp1
= ComputationUnitNoDelay(self
.rwid
, 2, add
)
58 m
.submodules
.comp2
= comp2
= ComputationUnitNoDelay(self
.rwid
, 2, sub
)
59 m
.submodules
.comp3
= comp3
= ComputationUnitNoDelay(self
.rwid
, 2, mul
)
60 m
.submodules
.comp4
= comp4
= ComputationUnitNoDelay(self
.rwid
, 2, shf
)
61 m
.submodules
.br1
= br1
= ComputationUnitNoDelay(self
.rwid
, 2, bgt
)
62 int_alus
= [comp1
, comp2
, comp3
, comp4
, br1
]
64 m
.d
.comb
+= comp1
.oper_i
.eq(Const(0, 2)) # op=add
65 m
.d
.comb
+= comp2
.oper_i
.eq(Const(1, 2)) # op=sub
66 m
.d
.comb
+= comp3
.oper_i
.eq(Const(2, 2)) # op=mul
67 m
.d
.comb
+= comp4
.oper_i
.eq(Const(3, 2)) # op=shf
68 m
.d
.comb
+= br1
.oper_i
.eq(Const(0, 2)) # op=bgt
79 req_rel_l
.append(alu
.req_rel_o
)
80 rd_rel_l
.append(alu
.rd_rel_o
)
81 shadow_l
.append(alu
.shadown_i
)
82 godie_l
.append(alu
.go_die_i
)
83 go_wr_l
.append(alu
.go_wr_i
)
84 go_rd_l
.append(alu
.go_rd_i
)
85 issue_l
.append(alu
.issue_i
)
86 busy_l
.append(alu
.busy_o
)
87 m
.d
.comb
+= self
.rd_rel_o
.eq(Cat(*rd_rel_l
))
88 m
.d
.comb
+= self
.req_rel_o
.eq(Cat(*req_rel_l
))
89 m
.d
.comb
+= self
.busy_o
.eq(Cat(*busy_l
))
90 m
.d
.comb
+= Cat(*godie_l
).eq(self
.go_die_i
)
91 m
.d
.comb
+= Cat(*shadow_l
).eq(self
.shadown_i
)
92 m
.d
.comb
+= Cat(*go_wr_l
).eq(self
.go_wr_i
)
93 m
.d
.comb
+= Cat(*go_rd_l
).eq(self
.go_rd_i
)
94 m
.d
.comb
+= Cat(*issue_l
).eq(self
.issue_i
)
96 # connect data register input/output
98 # merge (OR) all integer FU / ALU outputs to a single value
99 # bit of a hack: treereduce needs a list with an item named "dest_o"
100 dest_o
= treereduce(int_alus
)
101 m
.d
.comb
+= self
.dest_o
.eq(dest_o
)
103 for i
, alu
in enumerate(int_alus
):
104 m
.d
.comb
+= alu
.src1_i
.eq(self
.src1_data_i
)
105 m
.d
.comb
+= alu
.src2_i
.eq(self
.src2_data_i
)
110 class FunctionUnits(Elaboratable
):
112 def __init__(self
, n_regs
, n_int_alus
):
114 self
.n_int_alus
= n_int_alus
116 self
.dest_i
= Signal(n_regs
, reset_less
=True) # Dest R# in
117 self
.src1_i
= Signal(n_regs
, reset_less
=True) # oper1 R# in
118 self
.src2_i
= Signal(n_regs
, reset_less
=True) # oper2 R# in
120 self
.g_int_rd_pend_o
= Signal(n_regs
, reset_less
=True)
121 self
.g_int_wr_pend_o
= Signal(n_regs
, reset_less
=True)
123 self
.dest_rsel_o
= Signal(n_regs
, reset_less
=True) # dest reg (bot)
124 self
.src1_rsel_o
= Signal(n_regs
, reset_less
=True) # src1 reg (bot)
125 self
.src2_rsel_o
= Signal(n_regs
, reset_less
=True) # src2 reg (bot)
127 self
.req_rel_i
= Signal(n_int_alus
, reset_less
= True)
128 self
.readable_o
= Signal(n_int_alus
, reset_less
=True)
129 self
.writable_o
= Signal(n_int_alus
, reset_less
=True)
131 self
.go_rd_i
= Signal(n_int_alus
, reset_less
=True)
132 self
.go_wr_i
= Signal(n_int_alus
, reset_less
=True)
133 self
.req_rel_o
= Signal(n_int_alus
, reset_less
=True)
134 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
136 # Note: FURegs wr_pend_o is also outputted from here, for use in WaWGrid
138 def elaborate(self
, platform
):
141 n_int_fus
= self
.n_int_alus
143 # Integer FU-FU Dep Matrix
144 intfudeps
= FUFUDepMatrix(n_int_fus
, n_int_fus
)
145 m
.submodules
.intfudeps
= intfudeps
146 # Integer FU-Reg Dep Matrix
147 intregdeps
= FURegDepMatrix(n_int_fus
, self
.n_regs
)
148 m
.submodules
.intregdeps
= intregdeps
150 m
.d
.comb
+= self
.g_int_rd_pend_o
.eq(intregdeps
.rd_rsel_o
)
151 m
.d
.comb
+= self
.g_int_wr_pend_o
.eq(intregdeps
.wr_rsel_o
)
153 m
.d
.comb
+= intregdeps
.rd_pend_i
.eq(intregdeps
.rd_rsel_o
)
154 m
.d
.comb
+= intregdeps
.wr_pend_i
.eq(intregdeps
.wr_rsel_o
)
156 m
.d
.comb
+= intfudeps
.rd_pend_i
.eq(intregdeps
.rd_pend_o
)
157 m
.d
.comb
+= intfudeps
.wr_pend_i
.eq(intregdeps
.wr_pend_o
)
158 self
.wr_pend_o
= intregdeps
.wr_pend_o
# also output for use in WaWGrid
160 m
.d
.comb
+= intfudeps
.issue_i
.eq(self
.fn_issue_i
)
161 m
.d
.comb
+= intfudeps
.go_rd_i
.eq(self
.go_rd_i
)
162 m
.d
.comb
+= intfudeps
.go_wr_i
.eq(self
.go_wr_i
)
163 m
.d
.comb
+= self
.readable_o
.eq(intfudeps
.readable_o
)
164 m
.d
.comb
+= self
.writable_o
.eq(intfudeps
.writable_o
)
166 # Connect function issue / arrays, and dest/src1/src2
167 m
.d
.comb
+= intregdeps
.dest_i
.eq(self
.dest_i
)
168 m
.d
.comb
+= intregdeps
.src1_i
.eq(self
.src1_i
)
169 m
.d
.comb
+= intregdeps
.src2_i
.eq(self
.src2_i
)
171 m
.d
.comb
+= intregdeps
.go_rd_i
.eq(self
.go_rd_i
)
172 m
.d
.comb
+= intregdeps
.go_wr_i
.eq(self
.go_wr_i
)
173 m
.d
.comb
+= intregdeps
.issue_i
.eq(self
.fn_issue_i
)
175 m
.d
.comb
+= self
.dest_rsel_o
.eq(intregdeps
.dest_rsel_o
)
176 m
.d
.comb
+= self
.src1_rsel_o
.eq(intregdeps
.src1_rsel_o
)
177 m
.d
.comb
+= self
.src2_rsel_o
.eq(intregdeps
.src2_rsel_o
)
182 class Scoreboard(Elaboratable
):
183 def __init__(self
, rwid
, n_regs
):
186 * :rwid: bit width of register file(s) - both FP and INT
187 * :n_regs: depth of register file(s) - number of FP and INT regs
193 self
.intregs
= RegFileArray(rwid
, n_regs
)
194 self
.fpregs
= RegFileArray(rwid
, n_regs
)
197 self
.int_store_i
= Signal(reset_less
=True) # instruction is a store
198 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
199 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
200 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
201 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
204 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
205 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
207 # for branch speculation experiment. branch_direction = 0 if
208 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
209 # branch_succ and branch_fail are requests to have the current
210 # instruction be dependent on the branch unit "shadow" capability.
211 self
.branch_succ_i
= Signal(reset_less
=True)
212 self
.branch_fail_i
= Signal(reset_less
=True)
213 self
.branch_direction_o
= Signal(2, reset_less
=True)
215 def elaborate(self
, platform
):
218 m
.submodules
.intregs
= self
.intregs
219 m
.submodules
.fpregs
= self
.fpregs
222 m
.d
.sync
+= self
.branch_succ_i
.eq(Const(0))
223 m
.d
.sync
+= self
.branch_fail_i
.eq(Const(0))
224 m
.d
.sync
+= self
.branch_direction_o
.eq(Const(0))
227 int_dest
= self
.intregs
.write_port("dest")
228 int_src1
= self
.intregs
.read_port("src1")
229 int_src2
= self
.intregs
.read_port("src2")
231 fp_dest
= self
.fpregs
.write_port("dest")
232 fp_src1
= self
.fpregs
.read_port("src1")
233 fp_src2
= self
.fpregs
.read_port("src2")
235 # Int ALUs and Comp Units
237 m
.submodules
.cu
= cu
= CompUnits(self
.rwid
, n_int_alus
)
238 m
.d
.comb
+= cu
.go_die_i
.eq(0)
241 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
243 # Count of number of FUs
244 n_int_fus
= n_int_alus
245 n_fp_fus
= 0 # for now
247 # Integer Priority Picker 1: Adder + Subtractor
248 intpick1
= GroupPicker(n_int_fus
) # picks between add, sub, mul and shf
249 m
.submodules
.intpick1
= intpick1
252 regdecode
= RegDecode(self
.n_regs
)
253 m
.submodules
.regdecode
= regdecode
254 issueunit
= IntFPIssueUnit(self
.n_regs
, n_int_fus
, n_fp_fus
)
255 m
.submodules
.issueunit
= issueunit
257 # Shadow Matrix. currently n_int_fus shadows, to be used for
258 # write-after-write hazards
259 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_int_fus
, n_int_fus
)
260 # combined go_rd/wr + go_die (go_die used to reset latches)
261 go_rd_rst
= Signal(n_int_fus
, reset_less
=True)
262 go_wr_rst
= Signal(n_int_fus
, reset_less
=True)
263 # record previous instruction to cast shadow on current instruction
264 fn_issue_prev
= Signal(n_int_fus
)
265 prev_shadow
= Signal(n_int_fus
)
268 # ok start wiring things together...
269 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
270 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
274 # Issue Unit is where it starts. set up some in/outs for this module
276 m
.d
.comb
+= [issueunit
.i
.store_i
.eq(self
.int_store_i
),
277 regdecode
.dest_i
.eq(self
.int_dest_i
),
278 regdecode
.src1_i
.eq(self
.int_src1_i
),
279 regdecode
.src2_i
.eq(self
.int_src2_i
),
280 regdecode
.enable_i
.eq(self
.reg_enable_i
),
281 issueunit
.i
.dest_i
.eq(regdecode
.dest_o
),
282 self
.issue_o
.eq(issueunit
.issue_o
)
284 self
.int_insn_i
= issueunit
.i
.insn_i
# enabled by instruction decode
286 # connect global rd/wr pending vector (for WaW detection)
287 m
.d
.sync
+= issueunit
.i
.g_wr_pend_i
.eq(intfus
.g_int_wr_pend_o
)
288 # TODO: issueunit.f (FP)
290 # and int function issue / busy arrays, and dest/src1/src2
291 m
.d
.comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
292 m
.d
.comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
293 m
.d
.comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
295 fn_issue_o
= issueunit
.i
.fn_issue_o
297 m
.d
.comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
298 m
.d
.comb
+= issueunit
.i
.busy_i
.eq(cu
.busy_o
)
299 m
.d
.comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
302 # connect fu-fu matrix
305 # Group Picker... done manually for now.
306 go_rd_o
= intpick1
.go_rd_o
307 go_wr_o
= intpick1
.go_wr_o
308 go_rd_i
= intfus
.go_rd_i
309 go_wr_i
= intfus
.go_wr_i
310 # NOTE: connect to the shadowed versions so that they can "die" (reset)
311 m
.d
.comb
+= go_rd_i
[0:n_int_fus
].eq(go_rd_rst
[0:n_int_fus
]) # rd
312 m
.d
.comb
+= go_wr_i
[0:n_int_fus
].eq(go_wr_rst
[0:n_int_fus
]) # wr
316 m
.d
.comb
+= intpick1
.rd_rel_i
[0:n_int_fus
].eq(cu
.rd_rel_o
[0:n_int_fus
])
317 m
.d
.comb
+= intpick1
.req_rel_i
[0:n_int_fus
].eq(cu
.req_rel_o
[0:n_int_fus
])
318 int_rd_o
= intfus
.readable_o
319 int_wr_o
= intfus
.writable_o
320 m
.d
.comb
+= intpick1
.readable_i
[0:n_int_fus
].eq(int_rd_o
[0:n_int_fus
])
321 m
.d
.comb
+= intpick1
.writable_i
[0:n_int_fus
].eq(int_wr_o
[0:n_int_fus
])
327 m
.d
.comb
+= shadows
.issue_i
.eq(fn_issue_o
)
328 # these are explained in ShadowMatrix docstring, and are to be
329 # connected to the FUReg and FUFU Matrices, to get them to reset
330 # NOTE: do NOT connect these to the Computation Units. The CUs need to
331 # do something slightly different (due to the revolving-door SRLatches)
332 m
.d
.comb
+= go_rd_rst
.eq(go_rd_o | shadows
.go_die_o
)
333 m
.d
.comb
+= go_wr_rst
.eq(go_wr_o | shadows
.go_die_o
)
335 # connect shadows / go_dies to Computation Units
336 m
.d
.comb
+= cu
.shadown_i
[0:n_int_fus
].eq(shadows
.shadown_o
[0:n_int_fus
])
337 m
.d
.comb
+= cu
.go_die_i
[0:n_int_fus
].eq(shadows
.go_die_o
[0:n_int_fus
])
339 # ok connect first n_int_fu shadows to busy lines, to create an
340 # instruction-order linked-list-like arrangement, using a bit-matrix
341 # (instead of e.g. a ring buffer).
344 # when written, the shadow can be cancelled (and was good)
345 m
.d
.comb
+= shadows
.s_good_i
[0:n_int_fus
].eq(go_wr_o
[0:n_int_fus
])
347 # work out the current-activated busy unit (by recording the old one)
348 with m
.If(fn_issue_o
): # only update prev bit if instruction issued
349 m
.d
.sync
+= fn_issue_prev
.eq(fn_issue_o
)
351 # *previous* instruction shadows *current* instruction, and, obviously,
352 # if the previous is completed (!busy) don't cast the shadow!
353 m
.d
.comb
+= prev_shadow
.eq(~fn_issue_o
& fn_issue_prev
& cu
.busy_o
)
354 for i
in range(n_int_fus
):
355 m
.d
.comb
+= shadows
.shadow_i
[i
].eq(prev_shadow
)
358 # Connect Register File(s)
360 print ("intregdeps wen len", len(intfus
.dest_rsel_o
))
361 m
.d
.comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
362 m
.d
.comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
363 m
.d
.comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
365 # connect ALUs to regfule
366 m
.d
.comb
+= int_dest
.data_i
.eq(cu
.dest_o
)
367 m
.d
.comb
+= cu
.src1_data_i
.eq(int_src1
.data_o
)
368 m
.d
.comb
+= cu
.src2_data_i
.eq(int_src2
.data_o
)
370 # connect ALU Computation Units
371 m
.d
.comb
+= cu
.go_rd_i
[0:n_int_fus
].eq(go_rd_o
[0:n_int_fus
])
372 m
.d
.comb
+= cu
.go_wr_i
[0:n_int_fus
].eq(go_wr_o
[0:n_int_fus
])
373 m
.d
.comb
+= cu
.issue_i
[0:n_int_fus
].eq(fn_issue_o
[0:n_int_fus
])
379 yield from self
.intregs
380 yield from self
.fpregs
381 yield self
.int_store_i
382 yield self
.int_dest_i
383 yield self
.int_src1_i
384 yield self
.int_src2_i
386 yield self
.branch_succ_i
387 yield self
.branch_fail_i
388 yield self
.branch_direction_o
403 def __init__(self
, rwidth
, nregs
):
405 self
.regs
= [0] * nregs
407 def op(self
, op
, src1
, src2
, dest
):
408 maxbits
= (1 << self
.rwidth
) - 1
409 src1
= self
.regs
[src1
] & maxbits
410 src2
= self
.regs
[src2
] & maxbits
418 val
= src1
>> (src2
& maxbits
)
420 val
= int(src1
> src2
)
422 val
= int(src1
< src2
)
424 val
= int(src1
== src2
)
426 val
= int(src1
!= src2
)
428 self
.regs
[dest
] = val
430 def setval(self
, dest
, val
):
431 self
.regs
[dest
] = val
434 for i
, val
in enumerate(self
.regs
):
435 reg
= yield dut
.intregs
.regs
[i
].reg
436 okstr
= "OK" if reg
== val
else "!ok"
437 print("reg %d expected %x received %x %s" % (i
, val
, reg
, okstr
))
439 def check(self
, dut
):
440 for i
, val
in enumerate(self
.regs
):
441 reg
= yield dut
.intregs
.regs
[i
].reg
443 print("reg %d expected %x received %x\n" % (i
, val
, reg
))
444 yield from self
.dump(dut
)
447 def int_instr(dut
, op
, src1
, src2
, dest
, branch_success
, branch_fail
):
448 for i
in range(len(dut
.int_insn_i
)):
449 yield dut
.int_insn_i
[i
].eq(0)
450 yield dut
.int_dest_i
.eq(dest
)
451 yield dut
.int_src1_i
.eq(src1
)
452 yield dut
.int_src2_i
.eq(src2
)
453 yield dut
.int_insn_i
[op
].eq(1)
454 yield dut
.reg_enable_i
.eq(1)
456 # these indicate that the instruction is to be made shadow-dependent on
457 # (either) branch success or branch fail
458 yield dut
.branch_fail_i
.eq(branch_fail
)
459 yield dut
.branch_succ_i
.eq(branch_success
)
462 def print_reg(dut
, rnums
):
465 reg
= yield dut
.intregs
.regs
[rnum
].reg
466 rs
.append("%x" % reg
)
467 rnums
= map(str, rnums
)
468 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
471 def create_random_ops(n_ops
, shadowing
=False):
473 for i
in range(n_ops
):
474 src1
= randint(1, dut
.n_regs
-1)
475 src2
= randint(1, dut
.n_regs
-1)
476 dest
= randint(1, dut
.n_regs
-1)
480 instrs
.append((src1
, src2
, dest
, op
, (False, False)))
482 instrs
.append((src1
, src2
, dest
, op
))
486 def wait_for_busy_clear(dut
):
488 busy_o
= yield dut
.busy_o
495 def wait_for_issue(dut
):
497 issue_o
= yield dut
.issue_o
499 for i
in range(len(dut
.int_insn_i
)):
500 yield dut
.int_insn_i
[i
].eq(0)
501 yield dut
.reg_enable_i
.eq(0)
504 #yield from print_reg(dut, [1,2,3])
506 #yield from print_reg(dut, [1,2,3])
508 def scoreboard_branch_sim(dut
, alusim
):
510 yield dut
.int_store_i
.eq(1)
514 # set random values in the registers
515 for i
in range(1, dut
.n_regs
):
517 val
= randint(0, (1<<alusim
.rwidth
)-1)
518 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
519 alusim
.setval(i
, val
)
521 # create some instructions: branches create a tree
522 insts
= create_random_ops(5)
524 src1
= randint(1, dut
.n_regs
-1)
525 src2
= randint(1, dut
.n_regs
-1)
528 branch_ok
= create_random_ops(5)
529 branch_fail
= create_random_ops(5)
531 insts
.append((src1
, src2
, (branch_ok
, branch_fail
), op
, (0, 0)))
533 # issue instruction(s)
539 (src1
, src2
, dest
, op
, (shadow_on
, shadow_off
)) = insts
.pop()
540 if branch_direction
== 1 and shadow_off
:
541 continue # branch was "success" and this is a "failed"... skip
542 if branch_direction
== 2 and shadow_on
:
543 continue # branch was "fail" and this is a "success"... skip
546 branch_ok
, branch_fail
= dest
548 # ok zip up the branch success / fail instructions and
549 # drop them into the queue, one marked "to have branch success"
550 # the other to be marked shadow branch "fail".
551 # one out of each of these will be cancelled
552 for ok
, fl
in zip(branch_ok
, branch_fail
):
553 instrs
.append((ok
[0], ok
[1], ok
[2], ok
[3], (1, 0)))
554 instrs
.append((fl
[0], fl
[1], fl
[2], fl
[3], (0, 1)))
555 print ("instr %d: (%d, %d, %d, %d)" % (i
, src1
, src2
, dest
, op
))
556 yield from int_instr(dut
, op
, src1
, src2
, dest
,
557 shadow_on
, shadow_off
)
559 yield from wait_for_issue(dut
)
560 branch_direction
= dut
.branch_direction_o
# which way branch went
562 # wait for all instructions to stop before checking
564 yield from wait_for_busy_clear(dut
)
566 for (src1
, src2
, dest
, op
, (shadow_on
, shadow_off
)) in insts
:
569 branch_ok
, branch_fail
= dest
571 branch_res
= alusim
.op(op
, src1
, src2
, dest
)
574 insts
.append(branch_ok
)
576 insts
.append(branch_fail
)
579 yield from alusim
.check(dut
)
580 yield from alusim
.dump(dut
)
583 def scoreboard_sim(dut
, alusim
):
585 yield dut
.int_store_i
.eq(1)
589 # set random values in the registers
590 for i
in range(1, dut
.n_regs
):
592 val
= randint(0, (1<<alusim
.rwidth
)-1)
593 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
594 alusim
.setval(i
, val
)
596 # create some instructions (some random, some regression tests)
600 src1
= randint(1, dut
.n_regs
-1)
601 src2
= randint(1, dut
.n_regs
-1)
603 dest
= randint(1, dut
.n_regs
-1)
605 if dest
not in [src1
, src2
]:
615 instrs
.append((src1
, src2
, dest
, op
))
618 instrs
.append((2, 3, 3, 0))
619 instrs
.append((5, 3, 3, 1))
622 instrs
.append((5, 6, 2, 1))
623 instrs
.append((2, 2, 4, 0))
624 #instrs.append((2, 2, 3, 1))
627 instrs
.append((2, 1, 2, 3))
630 instrs
.append((2, 6, 2, 1))
631 instrs
.append((2, 1, 2, 0))
634 instrs
.append((1, 2, 7, 2))
635 instrs
.append((7, 1, 5, 0))
636 instrs
.append((4, 4, 1, 1))
639 instrs
.append((5, 6, 2, 2))
640 instrs
.append((1, 1, 4, 1))
641 instrs
.append((6, 5, 3, 0))
644 # Write-after-Write Hazard
645 instrs
.append( (3, 6, 7, 2) )
646 instrs
.append( (4, 4, 7, 1) )
649 # self-read/write-after-write followed by Read-after-Write
650 instrs
.append((1, 1, 1, 1))
651 instrs
.append((1, 5, 3, 0))
654 # Read-after-Write followed by self-read-after-write
655 instrs
.append((5, 6, 1, 2))
656 instrs
.append((1, 1, 1, 1))
659 # self-read-write sandwich
660 instrs
.append((5, 6, 1, 2))
661 instrs
.append((1, 1, 1, 1))
662 instrs
.append((1, 5, 3, 0))
666 instrs
.append( (5, 2, 5, 2) )
667 instrs
.append( (2, 6, 3, 0) )
668 instrs
.append( (4, 2, 2, 1) )
670 # issue instruction(s), wait for issue to be free before proceeding
671 for i
, (src1
, src2
, dest
, op
) in enumerate(instrs
):
673 print ("instr %d: (%d, %d, %d, %d)" % (i
, src1
, src2
, dest
, op
))
674 alusim
.op(op
, src1
, src2
, dest
)
675 yield from int_instr(dut
, op
, src1
, src2
, dest
, 0, 0)
677 yield from wait_for_issue(dut
)
679 # wait for all instructions to stop before checking
681 yield from wait_for_busy_clear(dut
)
684 yield from alusim
.check(dut
)
685 yield from alusim
.dump(dut
)
688 def test_scoreboard():
689 dut
= Scoreboard(16, 8)
690 alusim
= RegSim(16, 8)
691 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
692 with
open("test_scoreboard6600.il", "w") as f
:
695 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
696 vcd_name
='test_scoreboard6600.vcd')
699 if __name__
== '__main__':