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
23 # FIXME: fixed up imports
24 from soc
.experiment
.score6600
import (IssueToScoreboard
, RegSim
, instr_q
,
25 wait_for_busy_clear
, wait_for_issue
,
26 CompUnitALUs
, CompUnitBR
)
29 class Memory(Elaboratable
):
30 def __init__(self
, regwid
, addrw
):
31 self
.ddepth
= regwid
/8
32 depth
= (1 << addrw
) / self
.ddepth
33 self
.adr
= Signal(addrw
)
34 self
.dat_r
= Signal(regwid
)
35 self
.dat_w
= Signal(regwid
)
37 self
.mem
= Memory(width
=regwid
, depth
=depth
, init
=range(0, depth
))
39 def elaborate(self
, platform
):
41 m
.submodules
.rdport
= rdport
= self
.mem
.read_port()
42 m
.submodules
.wrport
= wrport
= self
.mem
.write_port()
44 rdport
.addr
.eq(self
.adr
[self
.ddepth
:]), # ignore low bits
45 self
.dat_r
.eq(rdport
.data
),
46 wrport
.addr
.eq(self
.adr
),
47 wrport
.data
.eq(self
.dat_w
),
48 wrport
.en
.eq(self
.we
),
54 def __init__(self
, regwid
, addrw
):
56 self
.ddepth
= regwid
//8
57 depth
= (1 << addrw
) // self
.ddepth
58 self
.mem
= list(range(0, depth
))
61 return self
.mem
[addr
>> self
.ddepth
]
63 def st(self
, addr
, data
):
64 self
.mem
[addr
>> self
.ddepth
] = data
& ((1 << self
.regwid
)-1)
67 class MemFunctionUnits(Elaboratable
):
69 def __init__(self
, n_int_alus
):
70 self
.n_int_alus
= n_int_alus
72 self
.ld_i
= Signal(n_int_alus
, reset_less
=True) # Dest R# in
73 self
.st_i
= Signal(n_int_alus
, reset_less
=True) # oper1 R# in
75 self
.load_hit_i
= Signal(n_int_alus
, reset_less
=True) # Load Hit
76 self
.stwd_hit_i
= Signal(n_int_alus
, reset_less
=True) # Store Hit
78 #self.g_int_st_pend_o = Signal(n_int_alus, reset_less=True)
79 #self.g_int_ld_pend_o = Signal(n_int_alus, reset_less=True)
81 # self.ld_rsel_o = Signal(n_int_alus, reset_less=True) # dest reg (bot)
82 # self.st_rsel_o = Signal(n_int_alus, reset_less=True) # src1 reg (bot)
84 self
.req_rel_i
= Signal(n_int_alus
, reset_less
=True)
85 self
.loadable_o
= Signal(n_int_alus
, reset_less
=True)
86 self
.storable_o
= Signal(n_int_alus
, reset_less
=True)
88 self
.go_st_i
= Signal(n_int_alus
, reset_less
=True)
89 self
.go_ld_i
= Signal(n_int_alus
, reset_less
=True)
90 self
.go_die_i
= Signal(n_int_alus
, reset_less
=True)
91 self
.req_rel_o
= Signal(n_int_alus
, reset_less
=True)
92 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
94 # Note: FURegs ld_pend_o is also outputted from here, for use in WaWGrid
96 def elaborate(self
, platform
):
101 n_intfus
= self
.n_int_alus
103 # Integer LD/ST Dep Matrix
104 ldstdeps
= LDSTDepMatrix(n_intfus
)
105 m
.submodules
.ldstdeps
= ldstdeps
106 # Integer FU-Mem Dep Matrix
107 fumemdeps
= FUMemDepMatrix(n_intfus
, n_intfus
)
108 m
.submodules
.fumemdeps
= fumemdeps
110 #comb += self.g_int_st_pend_o.eq(fumemdeps.v_st_rsel_o)
111 #comb += self.g_int_ld_pend_o.eq(fumemdeps.v_ld_rsel_o)
113 #comb += fumemdeps.st_pend_i.eq(fumemdeps.v_st_rsel_o)
114 #comb += fumemdeps.ld_pend_i.eq(fumemdeps.v_ld_rsel_o)
116 #comb += ldstdeps.st_pend_i.eq(fumemdeps.st_pend_o)
117 #comb += ldstdeps.ld_pend_i.eq(fumemdeps.ld_pend_o)
118 # self.ld_pend_o = fumemdeps.ld_pend_o # also output for use in WaWGrid
120 comb
+= ldstdeps
.ld_pend_i
.eq(self
.ld_i
)
121 comb
+= ldstdeps
.st_pend_i
.eq(self
.st_i
)
122 comb
+= ldstdeps
.issue_i
.eq(self
.fn_issue_i
)
123 comb
+= ldstdeps
.load_hit_i
.eq(self
.load_hit_i
)
124 comb
+= ldstdeps
.stwd_hit_i
.eq(self
.stwd_hit_i
)
125 comb
+= ldstdeps
.go_die_i
.eq(self
.go_die_i
)
126 comb
+= self
.storable_o
.eq(fumemdeps
.storable_o
)
127 comb
+= self
.loadable_o
.eq(fumemdeps
.loadable_o
)
128 comb
+= fumemdeps
.ld_pend_i
.eq(ldstdeps
.ld_hold_st_o
)
129 comb
+= fumemdeps
.st_pend_i
.eq(ldstdeps
.st_hold_ld_o
)
131 # Connect function issue / arrays, and dest/src1/src2
133 comb
+= fumemdeps
.go_st_i
.eq(self
.stwd_hit_i
)
134 comb
+= fumemdeps
.go_ld_i
.eq(self
.load_hit_i
)
135 comb
+= fumemdeps
.go_die_i
.eq(self
.go_die_i
)
136 comb
+= fumemdeps
.issue_i
.eq(self
.fn_issue_i
)
138 #comb += self.ld_rsel_o.eq(fumemdeps.ld_rsel_o)
139 #comb += self.st_rsel_o.eq(fumemdeps.st_rsel_o)
146 # yield self.g_int_st_pend_o
147 # yield self.g_int_ld_pend_o
148 # yield self.ld_rsel_o
149 # yield self.st_rsel_o
151 yield self
.loadable_o
152 yield self
.storable_o
153 yield self
.load_hit_i
154 yield self
.stwd_hit_i
159 yield self
.fn_issue_i
165 class Scoreboard(Elaboratable
):
166 def __init__(self
, rwid
, n_regs
):
169 * :rwid: bit width of register file(s) - both FP and INT
170 * :n_regs: depth of register file(s) - number of FP and INT regs
176 self
.intregs
= RegFileArray(rwid
, n_regs
)
177 self
.fpregs
= RegFileArray(rwid
, n_regs
)
179 # issue q needs to get at these
180 self
.aluissue
= IssueUnitGroup(4)
181 self
.brissue
= IssueUnitGroup(1)
183 self
.alu_oper_i
= Signal(4, reset_less
=True)
184 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
185 self
.br_oper_i
= Signal(4, reset_less
=True)
186 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
189 self
.int_dest_i
= Signal(range(n_regs
), reset_less
=True) # Dest R# in
190 self
.int_src1_i
= Signal(range(n_regs
), reset_less
=True) # oper1 R# in
191 self
.int_src2_i
= Signal(range(n_regs
), reset_less
=True) # oper2 R# in
192 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
195 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
196 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
198 # for branch speculation experiment. branch_direction = 0 if
199 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
200 # branch_succ and branch_fail are requests to have the current
201 # instruction be dependent on the branch unit "shadow" capability.
202 self
.branch_succ_i
= Signal(reset_less
=True)
203 self
.branch_fail_i
= Signal(reset_less
=True)
204 self
.branch_direction_o
= Signal(2, reset_less
=True)
206 def elaborate(self
, platform
):
211 m
.submodules
.intregs
= self
.intregs
212 m
.submodules
.fpregs
= self
.fpregs
215 int_dest
= self
.intregs
.write_port("dest")
216 int_src1
= self
.intregs
.read_port("src1")
217 int_src2
= self
.intregs
.read_port("src2")
219 fp_dest
= self
.fpregs
.write_port("dest")
220 fp_src1
= self
.fpregs
.read_port("src1")
221 fp_src2
= self
.fpregs
.read_port("src2")
223 # Int ALUs and Comp Units
225 cua
= CompUnitALUs(self
.rwid
, 3)
226 cub
= CompUnitBR(self
.rwid
, 3)
227 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
228 bgt
= cub
.bgt
# get at the branch computation unit
232 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
234 # Count of number of FUs
235 n_intfus
= n_int_alus
236 n_fp_fus
= 0 # for now
238 # Integer Priority Picker 1: Adder + Subtractor
239 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
240 m
.submodules
.intpick1
= intpick1
243 regdecode
= RegDecode(self
.n_regs
)
244 m
.submodules
.regdecode
= regdecode
245 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
246 m
.submodules
.issueunit
= issueunit
248 # Shadow Matrix. currently n_intfus shadows, to be used for
249 # write-after-write hazards. NOTE: there is one extra for branches,
250 # so the shadow width is increased by 1
251 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
252 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
254 # record previous instruction to cast shadow on current instruction
255 prev_shadow
= Signal(n_intfus
)
257 # Branch Speculation recorder. tracks the success/fail state as
258 # each instruction is issued, so that when the branch occurs the
259 # allow/cancel can be issued as appropriate.
260 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
263 # ok start wiring things together...
264 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
265 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
269 # Issue Unit is where it starts. set up some in/outs for this module
271 comb
+= [regdecode
.dest_i
.eq(self
.int_dest_i
),
272 regdecode
.src1_i
.eq(self
.int_src1_i
),
273 regdecode
.src2_i
.eq(self
.int_src2_i
),
274 regdecode
.enable_i
.eq(self
.reg_enable_i
),
275 self
.issue_o
.eq(issueunit
.issue_o
)
278 # take these to outside (issue needs them)
279 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
280 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
281 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
282 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
284 # TODO: issueunit.f (FP)
286 # and int function issue / busy arrays, and dest/src1/src2
287 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
288 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
289 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
291 fn_issue_o
= issueunit
.fn_issue_o
293 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
294 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
295 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
298 # merge shadow matrices outputs
301 # these are explained in ShadowMatrix docstring, and are to be
302 # connected to the FUReg and FUFU Matrices, to get them to reset
303 anydie
= Signal(n_intfus
, reset_less
=True)
304 allshadown
= Signal(n_intfus
, reset_less
=True)
305 shreset
= Signal(n_intfus
, reset_less
=True)
306 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
307 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
308 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
311 # connect fu-fu matrix
314 # Group Picker... done manually for now.
315 go_rd_o
= intpick1
.go_rd_o
316 go_wr_o
= intpick1
.go_wr_o
317 go_rd_i
= intfus
.go_rd_i
318 go_wr_i
= intfus
.go_wr_i
319 go_die_i
= intfus
.go_die_i
320 # NOTE: connect to the shadowed versions so that they can "die" (reset)
321 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
322 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
323 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
327 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
328 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
329 int_rd_o
= intfus
.readable_o
330 int_wr_o
= intfus
.writable_o
331 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
332 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
338 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
339 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
340 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
342 # NOTE; this setup is for the instruction order preservation...
344 # connect shadows / go_dies to Computation Units
345 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
346 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
348 # ok connect first n_int_fu shadows to busy lines, to create an
349 # instruction-order linked-list-like arrangement, using a bit-matrix
350 # (instead of e.g. a ring buffer).
353 # when written, the shadow can be cancelled (and was good)
354 for i
in range(n_intfus
):
355 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
357 # *previous* instruction shadows *current* instruction, and, obviously,
358 # if the previous is completed (!busy) don't cast the shadow!
359 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
360 for i
in range(n_intfus
):
361 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
364 # ... and this is for branch speculation. it uses the extra bit
365 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
366 # only needs to set shadow_i, s_fail_i and s_good_i
368 # issue captures shadow_i (if enabled)
369 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
371 bactive
= Signal(reset_less
=True)
372 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
374 # instruction being issued (fn_issue_o) has a shadow cast by the branch
375 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
376 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
377 for i
in range(n_intfus
):
378 with m
.If(fn_issue_o
& (Const(1 << i
))):
379 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
381 # finally, we need an indicator to the test infrastructure as to
382 # whether the branch succeeded or failed, plus, link up to the
383 # "recorder" of whether the instruction was under shadow or not
385 with m
.If(br1
.issue_i
):
386 sync
+= bspec
.active_i
.eq(1)
387 with m
.If(self
.branch_succ_i
):
388 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
389 with m
.If(self
.branch_fail_i
):
390 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
392 # branch is active (TODO: a better signal: this is over-using the
393 # go_write signal - actually the branch should not be "writing")
394 with m
.If(br1
.go_wr_i
):
395 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
396 sync
+= bspec
.active_i
.eq(0)
397 comb
+= bspec
.br_i
.eq(1)
398 # branch occurs if data == 1, failed if data == 0
399 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
400 for i
in range(n_intfus
):
401 # *expected* direction of the branch matched against *actual*
402 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
404 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
407 # Connect Register File(s)
409 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
410 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
411 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
413 # connect ALUs to regfule
414 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
415 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
416 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
418 # connect ALU Computation Units
419 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
420 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
421 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
426 yield from self
.intregs
427 yield from self
.fpregs
428 yield self
.int_dest_i
429 yield self
.int_src1_i
430 yield self
.int_src2_i
432 yield self
.branch_succ_i
433 yield self
.branch_fail_i
434 yield self
.branch_direction_o
440 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
441 yield from disable_issue(dut
)
442 yield dut
.int_dest_i
.eq(dest
)
443 yield dut
.int_src1_i
.eq(src1
)
444 yield dut
.int_src2_i
.eq(src2
)
445 if (op
& (0x3 << 2)) != 0: # branch
446 yield dut
.brissue
.insn_i
.eq(1)
447 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
448 yield dut
.br_imm_i
.eq(imm
)
449 dut_issue
= dut
.brissue
451 yield dut
.aluissue
.insn_i
.eq(1)
452 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
453 yield dut
.alu_imm_i
.eq(imm
)
454 dut_issue
= dut
.aluissue
455 yield dut
.reg_enable_i
.eq(1)
457 # these indicate that the instruction is to be made shadow-dependent on
458 # (either) branch success or branch fail
459 yield dut
.branch_fail_i
.eq(branch_fail
)
460 yield dut
.branch_succ_i
.eq(branch_success
)
463 yield from wait_for_issue(dut
, dut_issue
)
466 def print_reg(dut
, rnums
):
469 reg
= yield dut
.intregs
.regs
[rnum
].reg
470 rs
.append("%x" % reg
)
471 rnums
= map(str, rnums
)
472 print("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
475 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
477 for i
in range(n_ops
):
478 src1
= randint(1, dut
.n_regs
-1)
479 src2
= randint(1, dut
.n_regs
-1)
480 imm
= randint(1, (1 << dut
.rwid
)-1)
481 dest
= randint(1, dut
.n_regs
-1)
482 op
= randint(0, max_opnums
)
483 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
486 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
488 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
492 def scoreboard_sim(dut
, alusim
):
498 # set random values in the registers
499 for i
in range(1, dut
.n_regs
):
500 val
= randint(0, (1 << alusim
.rwidth
)-1)
503 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
504 alusim
.setval(i
, val
)
506 # create some instructions (some random, some regression tests)
509 instrs
= create_random_ops(dut
, 15, True, 4)
512 instrs
.append((1, 2, 2, 1, 1, 20, (0, 0)))
515 instrs
.append((7, 3, 2, 4, (0, 0)))
516 instrs
.append((7, 6, 6, 2, (0, 0)))
517 instrs
.append((1, 7, 2, 2, (0, 0)))
520 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
521 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
522 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
523 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
524 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
527 instrs
.append((3, 3, 4, 0, 0, 13979, (0, 0)))
528 instrs
.append((6, 4, 1, 2, 0, 40976, (0, 0)))
529 instrs
.append((1, 4, 7, 4, 1, 23652, (0, 0)))
532 instrs
.append((5, 6, 2, 1))
533 instrs
.append((2, 2, 4, 0))
534 #instrs.append((2, 2, 3, 1))
537 instrs
.append((2, 1, 2, 3))
540 instrs
.append((2, 6, 2, 1))
541 instrs
.append((2, 1, 2, 0))
544 instrs
.append((1, 2, 7, 2))
545 instrs
.append((7, 1, 5, 0))
546 instrs
.append((4, 4, 1, 1))
549 instrs
.append((5, 6, 2, 2))
550 instrs
.append((1, 1, 4, 1))
551 instrs
.append((6, 5, 3, 0))
554 # Write-after-Write Hazard
555 instrs
.append((3, 6, 7, 2))
556 instrs
.append((4, 4, 7, 1))
559 # self-read/write-after-write followed by Read-after-Write
560 instrs
.append((1, 1, 1, 1))
561 instrs
.append((1, 5, 3, 0))
564 # Read-after-Write followed by self-read-after-write
565 instrs
.append((5, 6, 1, 2))
566 instrs
.append((1, 1, 1, 1))
569 # self-read-write sandwich
570 instrs
.append((5, 6, 1, 2))
571 instrs
.append((1, 1, 1, 1))
572 instrs
.append((1, 5, 3, 0))
576 instrs
.append((5, 2, 5, 2))
577 instrs
.append((2, 6, 3, 0))
578 instrs
.append((4, 2, 2, 1))
582 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
584 yield dut
.intregs
.regs
[3].reg
.eq(5)
586 instrs
.append((5, 3, 3, 4, (0, 0)))
587 instrs
.append((4, 2, 1, 2, (0, 1)))
591 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
593 yield dut
.intregs
.regs
[3].reg
.eq(5)
595 instrs
.append((5, 3, 3, 4, (0, 0)))
596 instrs
.append((4, 2, 1, 2, (1, 0)))
599 instrs
.append((4, 3, 5, 1, 0, (0, 0)))
600 instrs
.append((5, 2, 3, 1, 0, (0, 0)))
601 instrs
.append((7, 1, 5, 2, 0, (0, 0)))
602 instrs
.append((5, 6, 6, 4, 0, (0, 0)))
603 instrs
.append((7, 5, 2, 2, 0, (1, 0)))
604 instrs
.append((1, 7, 5, 0, 0, (0, 1)))
605 instrs
.append((1, 6, 1, 2, 0, (1, 0)))
606 instrs
.append((1, 6, 7, 3, 0, (0, 0)))
607 instrs
.append((6, 7, 7, 0, 0, (0, 0)))
609 # issue instruction(s), wait for issue to be free before proceeding
610 for i
, instr
in enumerate(instrs
):
611 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
613 print("instr %d: (%d, %d, %d, %d, %d, %d)" %
614 (i
, src1
, src2
, dest
, op
, opi
, imm
))
615 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
616 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
619 # wait for all instructions to stop before checking
621 iqlen
= yield dut
.qlen_o
629 yield from wait_for_busy_clear(dut
)
632 yield from alusim
.check(dut
)
633 yield from alusim
.dump(dut
)
636 @unittest.skip("doesn't work") # FIXME
637 def test_scoreboard():
638 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
639 alusim
= RegSim(16, 8)
640 memsim
= MemSim(16, 16)
641 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
642 with
open("test_scoreboard6600.il", "w") as f
:
645 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
646 vcd_name
='test_scoreboard6600.vcd')
648 # run_simulation(dut, scoreboard_branch_sim(dut, alusim),
649 # vcd_name='test_scoreboard6600.vcd')
653 yield dut
.ld_i
.eq(0x1)
654 yield dut
.fn_issue_i
.eq(0x1)
656 # yield dut.ld_i.eq(0x0)
657 yield dut
.st_i
.eq(0x2)
658 yield dut
.fn_issue_i
.eq(0x2)
660 # yield dut.st_i.eq(0x0)
661 yield dut
.fn_issue_i
.eq(0x0)
664 yield dut
.load_hit_i
.eq(0x1)
666 yield dut
.load_hit_i
.eq(0x0)
668 yield dut
.stwd_hit_i
.eq(0x2)
670 yield dut
.stwd_hit_i
.eq(0x0)
675 dut
= MemFunctionUnits(3)
676 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
677 with
open("test_mem_fus.il", "w") as f
:
680 run_simulation(dut
, mem_sim(dut
),
681 vcd_name
='test_mem_fus.vcd')
684 if __name__
== '__main__':