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 soc
.regfile
.regfile
import RegFileArray
, treereduce
6 from soc
.scoreboard
.ldst_matrix
import LDSTDepMatrix
7 from soc
.scoreboard
.fu_mem_matrix
import FUMemDepMatrix
8 from soc
.scoreboard
.global_pending
import GlobalPending
9 from soc
.scoreboard
.group_picker
import GroupPicker
10 from soc
.scoreboard
.issue_unit
import IssueUnitGroup
, IssueUnitArray
, RegDecode
11 from soc
.scoreboard
.shadow
import ShadowMatrix
, BranchSpeculationRecord
14 from nmutil
.latch
import SRLatch
15 from nmutil
.nmoperator
import eq
17 from random
import randint
, seed
18 from copy
import deepcopy
21 # FIXME: fixed up imports
22 from ..experiment
.score6600
import IssueToScoreboard
, RegSim
, instr_q
, wait_for_busy_clear
, wait_for_issue
, CompUnitALUs
, CompUnitBR
25 class Memory(Elaboratable
):
26 def __init__(self
, regwid
, addrw
):
27 self
.ddepth
= regwid
/8
28 depth
= (1 << addrw
) / self
.ddepth
29 self
.adr
= Signal(addrw
)
30 self
.dat_r
= Signal(regwid
)
31 self
.dat_w
= Signal(regwid
)
33 self
.mem
= Memory(width
=regwid
, depth
=depth
, init
=range(0, depth
))
35 def elaborate(self
, platform
):
37 m
.submodules
.rdport
= rdport
= self
.mem
.read_port()
38 m
.submodules
.wrport
= wrport
= self
.mem
.write_port()
40 rdport
.addr
.eq(self
.adr
[self
.ddepth
:]), # ignore low bits
41 self
.dat_r
.eq(rdport
.data
),
42 wrport
.addr
.eq(self
.adr
),
43 wrport
.data
.eq(self
.dat_w
),
44 wrport
.en
.eq(self
.we
),
50 def __init__(self
, regwid
, addrw
):
52 self
.ddepth
= regwid
//8
53 depth
= (1 << addrw
) // self
.ddepth
54 self
.mem
= list(range(0, depth
))
57 return self
.mem
[addr
>> self
.ddepth
]
59 def st(self
, addr
, data
):
60 self
.mem
[addr
>> self
.ddepth
] = data
& ((1 << self
.regwid
)-1)
63 class MemFunctionUnits(Elaboratable
):
65 def __init__(self
, n_int_alus
):
66 self
.n_int_alus
= n_int_alus
68 self
.ld_i
= Signal(n_int_alus
, reset_less
=True) # Dest R# in
69 self
.st_i
= Signal(n_int_alus
, reset_less
=True) # oper1 R# in
71 self
.load_hit_i
= Signal(n_int_alus
, reset_less
=True) # Load Hit
72 self
.stwd_hit_i
= Signal(n_int_alus
, reset_less
=True) # Store Hit
74 #self.g_int_st_pend_o = Signal(n_int_alus, reset_less=True)
75 #self.g_int_ld_pend_o = Signal(n_int_alus, reset_less=True)
77 # self.ld_rsel_o = Signal(n_int_alus, reset_less=True) # dest reg (bot)
78 # self.st_rsel_o = Signal(n_int_alus, reset_less=True) # src1 reg (bot)
80 self
.req_rel_i
= Signal(n_int_alus
, reset_less
=True)
81 self
.loadable_o
= Signal(n_int_alus
, reset_less
=True)
82 self
.storable_o
= Signal(n_int_alus
, reset_less
=True)
84 self
.go_st_i
= Signal(n_int_alus
, reset_less
=True)
85 self
.go_ld_i
= Signal(n_int_alus
, reset_less
=True)
86 self
.go_die_i
= Signal(n_int_alus
, reset_less
=True)
87 self
.req_rel_o
= Signal(n_int_alus
, reset_less
=True)
88 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
90 # Note: FURegs ld_pend_o is also outputted from here, for use in WaWGrid
92 def elaborate(self
, platform
):
97 n_intfus
= self
.n_int_alus
99 # Integer LD/ST Dep Matrix
100 ldstdeps
= LDSTDepMatrix(n_intfus
)
101 m
.submodules
.ldstdeps
= ldstdeps
102 # Integer FU-Mem Dep Matrix
103 fumemdeps
= FUMemDepMatrix(n_intfus
, n_intfus
)
104 m
.submodules
.fumemdeps
= fumemdeps
106 #comb += self.g_int_st_pend_o.eq(fumemdeps.v_st_rsel_o)
107 #comb += self.g_int_ld_pend_o.eq(fumemdeps.v_ld_rsel_o)
109 #comb += fumemdeps.st_pend_i.eq(fumemdeps.v_st_rsel_o)
110 #comb += fumemdeps.ld_pend_i.eq(fumemdeps.v_ld_rsel_o)
112 #comb += ldstdeps.st_pend_i.eq(fumemdeps.st_pend_o)
113 #comb += ldstdeps.ld_pend_i.eq(fumemdeps.ld_pend_o)
114 # self.ld_pend_o = fumemdeps.ld_pend_o # also output for use in WaWGrid
116 comb
+= ldstdeps
.ld_pend_i
.eq(self
.ld_i
)
117 comb
+= ldstdeps
.st_pend_i
.eq(self
.st_i
)
118 comb
+= ldstdeps
.issue_i
.eq(self
.fn_issue_i
)
119 comb
+= ldstdeps
.load_hit_i
.eq(self
.load_hit_i
)
120 comb
+= ldstdeps
.stwd_hit_i
.eq(self
.stwd_hit_i
)
121 comb
+= ldstdeps
.go_die_i
.eq(self
.go_die_i
)
122 comb
+= self
.storable_o
.eq(fumemdeps
.storable_o
)
123 comb
+= self
.loadable_o
.eq(fumemdeps
.loadable_o
)
124 comb
+= fumemdeps
.ld_pend_i
.eq(ldstdeps
.ld_hold_st_o
)
125 comb
+= fumemdeps
.st_pend_i
.eq(ldstdeps
.st_hold_ld_o
)
127 # Connect function issue / arrays, and dest/src1/src2
129 comb
+= fumemdeps
.go_st_i
.eq(self
.stwd_hit_i
)
130 comb
+= fumemdeps
.go_ld_i
.eq(self
.load_hit_i
)
131 comb
+= fumemdeps
.go_die_i
.eq(self
.go_die_i
)
132 comb
+= fumemdeps
.issue_i
.eq(self
.fn_issue_i
)
134 #comb += self.ld_rsel_o.eq(fumemdeps.ld_rsel_o)
135 #comb += self.st_rsel_o.eq(fumemdeps.st_rsel_o)
142 # yield self.g_int_st_pend_o
143 # yield self.g_int_ld_pend_o
144 # yield self.ld_rsel_o
145 # yield self.st_rsel_o
147 yield self
.loadable_o
148 yield self
.storable_o
149 yield self
.load_hit_i
150 yield self
.stwd_hit_i
155 yield self
.fn_issue_i
161 class Scoreboard(Elaboratable
):
162 def __init__(self
, rwid
, n_regs
):
165 * :rwid: bit width of register file(s) - both FP and INT
166 * :n_regs: depth of register file(s) - number of FP and INT regs
172 self
.intregs
= RegFileArray(rwid
, n_regs
)
173 self
.fpregs
= RegFileArray(rwid
, n_regs
)
175 # issue q needs to get at these
176 self
.aluissue
= IssueUnitGroup(4)
177 self
.brissue
= IssueUnitGroup(1)
179 self
.alu_oper_i
= Signal(4, reset_less
=True)
180 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
181 self
.br_oper_i
= Signal(4, reset_less
=True)
182 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
185 self
.int_dest_i
= Signal(range(n_regs
), reset_less
=True) # Dest R# in
186 self
.int_src1_i
= Signal(range(n_regs
), reset_less
=True) # oper1 R# in
187 self
.int_src2_i
= Signal(range(n_regs
), reset_less
=True) # oper2 R# in
188 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
191 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
192 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
194 # for branch speculation experiment. branch_direction = 0 if
195 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
196 # branch_succ and branch_fail are requests to have the current
197 # instruction be dependent on the branch unit "shadow" capability.
198 self
.branch_succ_i
= Signal(reset_less
=True)
199 self
.branch_fail_i
= Signal(reset_less
=True)
200 self
.branch_direction_o
= Signal(2, reset_less
=True)
202 def elaborate(self
, platform
):
207 m
.submodules
.intregs
= self
.intregs
208 m
.submodules
.fpregs
= self
.fpregs
211 int_dest
= self
.intregs
.write_port("dest")
212 int_src1
= self
.intregs
.read_port("src1")
213 int_src2
= self
.intregs
.read_port("src2")
215 fp_dest
= self
.fpregs
.write_port("dest")
216 fp_src1
= self
.fpregs
.read_port("src1")
217 fp_src2
= self
.fpregs
.read_port("src2")
219 # Int ALUs and Comp Units
221 cua
= CompUnitALUs(self
.rwid
, 3)
222 cub
= CompUnitBR(self
.rwid
, 3)
223 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
224 bgt
= cub
.bgt
# get at the branch computation unit
228 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
230 # Count of number of FUs
231 n_intfus
= n_int_alus
232 n_fp_fus
= 0 # for now
234 # Integer Priority Picker 1: Adder + Subtractor
235 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
236 m
.submodules
.intpick1
= intpick1
239 regdecode
= RegDecode(self
.n_regs
)
240 m
.submodules
.regdecode
= regdecode
241 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
242 m
.submodules
.issueunit
= issueunit
244 # Shadow Matrix. currently n_intfus shadows, to be used for
245 # write-after-write hazards. NOTE: there is one extra for branches,
246 # so the shadow width is increased by 1
247 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
248 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
250 # record previous instruction to cast shadow on current instruction
251 prev_shadow
= Signal(n_intfus
)
253 # Branch Speculation recorder. tracks the success/fail state as
254 # each instruction is issued, so that when the branch occurs the
255 # allow/cancel can be issued as appropriate.
256 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
259 # ok start wiring things together...
260 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
261 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
265 # Issue Unit is where it starts. set up some in/outs for this module
267 comb
+= [regdecode
.dest_i
.eq(self
.int_dest_i
),
268 regdecode
.src1_i
.eq(self
.int_src1_i
),
269 regdecode
.src2_i
.eq(self
.int_src2_i
),
270 regdecode
.enable_i
.eq(self
.reg_enable_i
),
271 self
.issue_o
.eq(issueunit
.issue_o
)
274 # take these to outside (issue needs them)
275 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
276 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
277 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
278 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
280 # TODO: issueunit.f (FP)
282 # and int function issue / busy arrays, and dest/src1/src2
283 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
284 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
285 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
287 fn_issue_o
= issueunit
.fn_issue_o
289 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
290 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
291 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
294 # merge shadow matrices outputs
297 # these are explained in ShadowMatrix docstring, and are to be
298 # connected to the FUReg and FUFU Matrices, to get them to reset
299 anydie
= Signal(n_intfus
, reset_less
=True)
300 allshadown
= Signal(n_intfus
, reset_less
=True)
301 shreset
= Signal(n_intfus
, reset_less
=True)
302 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
303 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
304 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
307 # connect fu-fu matrix
310 # Group Picker... done manually for now.
311 go_rd_o
= intpick1
.go_rd_o
312 go_wr_o
= intpick1
.go_wr_o
313 go_rd_i
= intfus
.go_rd_i
314 go_wr_i
= intfus
.go_wr_i
315 go_die_i
= intfus
.go_die_i
316 # NOTE: connect to the shadowed versions so that they can "die" (reset)
317 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
318 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
319 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
323 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
324 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
325 int_rd_o
= intfus
.readable_o
326 int_wr_o
= intfus
.writable_o
327 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
328 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
334 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
335 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
336 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
338 # NOTE; this setup is for the instruction order preservation...
340 # connect shadows / go_dies to Computation Units
341 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
342 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
344 # ok connect first n_int_fu shadows to busy lines, to create an
345 # instruction-order linked-list-like arrangement, using a bit-matrix
346 # (instead of e.g. a ring buffer).
349 # when written, the shadow can be cancelled (and was good)
350 for i
in range(n_intfus
):
351 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
353 # *previous* instruction shadows *current* instruction, and, obviously,
354 # if the previous is completed (!busy) don't cast the shadow!
355 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
356 for i
in range(n_intfus
):
357 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
360 # ... and this is for branch speculation. it uses the extra bit
361 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
362 # only needs to set shadow_i, s_fail_i and s_good_i
364 # issue captures shadow_i (if enabled)
365 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
367 bactive
= Signal(reset_less
=True)
368 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
370 # instruction being issued (fn_issue_o) has a shadow cast by the branch
371 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
372 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
373 for i
in range(n_intfus
):
374 with m
.If(fn_issue_o
& (Const(1 << i
))):
375 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
377 # finally, we need an indicator to the test infrastructure as to
378 # whether the branch succeeded or failed, plus, link up to the
379 # "recorder" of whether the instruction was under shadow or not
381 with m
.If(br1
.issue_i
):
382 sync
+= bspec
.active_i
.eq(1)
383 with m
.If(self
.branch_succ_i
):
384 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
385 with m
.If(self
.branch_fail_i
):
386 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
388 # branch is active (TODO: a better signal: this is over-using the
389 # go_write signal - actually the branch should not be "writing")
390 with m
.If(br1
.go_wr_i
):
391 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
392 sync
+= bspec
.active_i
.eq(0)
393 comb
+= bspec
.br_i
.eq(1)
394 # branch occurs if data == 1, failed if data == 0
395 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
396 for i
in range(n_intfus
):
397 # *expected* direction of the branch matched against *actual*
398 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
400 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
403 # Connect Register File(s)
405 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
406 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
407 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
409 # connect ALUs to regfule
410 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
411 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
412 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
414 # connect ALU Computation Units
415 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
416 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
417 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
422 yield from self
.intregs
423 yield from self
.fpregs
424 yield self
.int_dest_i
425 yield self
.int_src1_i
426 yield self
.int_src2_i
428 yield self
.branch_succ_i
429 yield self
.branch_fail_i
430 yield self
.branch_direction_o
436 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
437 yield from disable_issue(dut
)
438 yield dut
.int_dest_i
.eq(dest
)
439 yield dut
.int_src1_i
.eq(src1
)
440 yield dut
.int_src2_i
.eq(src2
)
441 if (op
& (0x3 << 2)) != 0: # branch
442 yield dut
.brissue
.insn_i
.eq(1)
443 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
444 yield dut
.br_imm_i
.eq(imm
)
445 dut_issue
= dut
.brissue
447 yield dut
.aluissue
.insn_i
.eq(1)
448 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
449 yield dut
.alu_imm_i
.eq(imm
)
450 dut_issue
= dut
.aluissue
451 yield dut
.reg_enable_i
.eq(1)
453 # these indicate that the instruction is to be made shadow-dependent on
454 # (either) branch success or branch fail
455 yield dut
.branch_fail_i
.eq(branch_fail
)
456 yield dut
.branch_succ_i
.eq(branch_success
)
459 yield from wait_for_issue(dut
, dut_issue
)
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(dut
, n_ops
, shadowing
=False, max_opnums
=3):
473 for i
in range(n_ops
):
474 src1
= randint(1, dut
.n_regs
-1)
475 src2
= randint(1, dut
.n_regs
-1)
476 imm
= randint(1, (1 << dut
.rwid
)-1)
477 dest
= randint(1, dut
.n_regs
-1)
478 op
= randint(0, max_opnums
)
479 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
482 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
484 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
488 def scoreboard_sim(dut
, alusim
):
494 # set random values in the registers
495 for i
in range(1, dut
.n_regs
):
496 val
= randint(0, (1 << alusim
.rwidth
)-1)
499 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
500 alusim
.setval(i
, val
)
502 # create some instructions (some random, some regression tests)
505 instrs
= create_random_ops(dut
, 15, True, 4)
508 instrs
.append((1, 2, 2, 1, 1, 20, (0, 0)))
511 instrs
.append((7, 3, 2, 4, (0, 0)))
512 instrs
.append((7, 6, 6, 2, (0, 0)))
513 instrs
.append((1, 7, 2, 2, (0, 0)))
516 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
517 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
518 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
519 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
520 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
523 instrs
.append((3, 3, 4, 0, 0, 13979, (0, 0)))
524 instrs
.append((6, 4, 1, 2, 0, 40976, (0, 0)))
525 instrs
.append((1, 4, 7, 4, 1, 23652, (0, 0)))
528 instrs
.append((5, 6, 2, 1))
529 instrs
.append((2, 2, 4, 0))
530 #instrs.append((2, 2, 3, 1))
533 instrs
.append((2, 1, 2, 3))
536 instrs
.append((2, 6, 2, 1))
537 instrs
.append((2, 1, 2, 0))
540 instrs
.append((1, 2, 7, 2))
541 instrs
.append((7, 1, 5, 0))
542 instrs
.append((4, 4, 1, 1))
545 instrs
.append((5, 6, 2, 2))
546 instrs
.append((1, 1, 4, 1))
547 instrs
.append((6, 5, 3, 0))
550 # Write-after-Write Hazard
551 instrs
.append((3, 6, 7, 2))
552 instrs
.append((4, 4, 7, 1))
555 # self-read/write-after-write followed by Read-after-Write
556 instrs
.append((1, 1, 1, 1))
557 instrs
.append((1, 5, 3, 0))
560 # Read-after-Write followed by self-read-after-write
561 instrs
.append((5, 6, 1, 2))
562 instrs
.append((1, 1, 1, 1))
565 # self-read-write sandwich
566 instrs
.append((5, 6, 1, 2))
567 instrs
.append((1, 1, 1, 1))
568 instrs
.append((1, 5, 3, 0))
572 instrs
.append((5, 2, 5, 2))
573 instrs
.append((2, 6, 3, 0))
574 instrs
.append((4, 2, 2, 1))
578 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
580 yield dut
.intregs
.regs
[3].reg
.eq(5)
582 instrs
.append((5, 3, 3, 4, (0, 0)))
583 instrs
.append((4, 2, 1, 2, (0, 1)))
587 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
589 yield dut
.intregs
.regs
[3].reg
.eq(5)
591 instrs
.append((5, 3, 3, 4, (0, 0)))
592 instrs
.append((4, 2, 1, 2, (1, 0)))
595 instrs
.append((4, 3, 5, 1, 0, (0, 0)))
596 instrs
.append((5, 2, 3, 1, 0, (0, 0)))
597 instrs
.append((7, 1, 5, 2, 0, (0, 0)))
598 instrs
.append((5, 6, 6, 4, 0, (0, 0)))
599 instrs
.append((7, 5, 2, 2, 0, (1, 0)))
600 instrs
.append((1, 7, 5, 0, 0, (0, 1)))
601 instrs
.append((1, 6, 1, 2, 0, (1, 0)))
602 instrs
.append((1, 6, 7, 3, 0, (0, 0)))
603 instrs
.append((6, 7, 7, 0, 0, (0, 0)))
605 # issue instruction(s), wait for issue to be free before proceeding
606 for i
, instr
in enumerate(instrs
):
607 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
609 print("instr %d: (%d, %d, %d, %d, %d, %d)" %
610 (i
, src1
, src2
, dest
, op
, opi
, imm
))
611 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
612 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
615 # wait for all instructions to stop before checking
617 iqlen
= yield dut
.qlen_o
625 yield from wait_for_busy_clear(dut
)
628 yield from alusim
.check(dut
)
629 yield from alusim
.dump(dut
)
632 def test_scoreboard():
633 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
634 alusim
= RegSim(16, 8)
635 memsim
= MemSim(16, 16)
636 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
637 with
open("test_scoreboard6600.il", "w") as f
:
640 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
641 vcd_name
='test_scoreboard6600.vcd')
643 # run_simulation(dut, scoreboard_branch_sim(dut, alusim),
644 # vcd_name='test_scoreboard6600.vcd')
648 yield dut
.ld_i
.eq(0x1)
649 yield dut
.fn_issue_i
.eq(0x1)
651 # yield dut.ld_i.eq(0x0)
652 yield dut
.st_i
.eq(0x2)
653 yield dut
.fn_issue_i
.eq(0x2)
655 # yield dut.st_i.eq(0x0)
656 yield dut
.fn_issue_i
.eq(0x0)
659 yield dut
.load_hit_i
.eq(0x1)
661 yield dut
.load_hit_i
.eq(0x0)
663 yield dut
.stwd_hit_i
.eq(0x2)
665 yield dut
.stwd_hit_i
.eq(0x0)
670 dut
= MemFunctionUnits(3)
671 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
672 with
open("test_mem_fus.il", "w") as f
:
675 run_simulation(dut
, mem_sim(dut
),
676 vcd_name
='test_mem_fus.vcd')
679 if __name__
== '__main__':