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 ..experiment
.score6600
import IssueToScoreboard
, RegSim
, instr_q
, wait_for_busy_clear
, wait_for_issue
, CompUnitALUs
, CompUnitBR
27 class Memory(Elaboratable
):
28 def __init__(self
, regwid
, addrw
):
29 self
.ddepth
= regwid
/8
30 depth
= (1 << addrw
) / self
.ddepth
31 self
.adr
= Signal(addrw
)
32 self
.dat_r
= Signal(regwid
)
33 self
.dat_w
= Signal(regwid
)
35 self
.mem
= Memory(width
=regwid
, depth
=depth
, init
=range(0, depth
))
37 def elaborate(self
, platform
):
39 m
.submodules
.rdport
= rdport
= self
.mem
.read_port()
40 m
.submodules
.wrport
= wrport
= self
.mem
.write_port()
42 rdport
.addr
.eq(self
.adr
[self
.ddepth
:]), # ignore low bits
43 self
.dat_r
.eq(rdport
.data
),
44 wrport
.addr
.eq(self
.adr
),
45 wrport
.data
.eq(self
.dat_w
),
46 wrport
.en
.eq(self
.we
),
52 def __init__(self
, regwid
, addrw
):
54 self
.ddepth
= regwid
//8
55 depth
= (1 << addrw
) // self
.ddepth
56 self
.mem
= list(range(0, depth
))
59 return self
.mem
[addr
>> self
.ddepth
]
61 def st(self
, addr
, data
):
62 self
.mem
[addr
>> self
.ddepth
] = data
& ((1 << self
.regwid
)-1)
65 class MemFunctionUnits(Elaboratable
):
67 def __init__(self
, n_int_alus
):
68 self
.n_int_alus
= n_int_alus
70 self
.ld_i
= Signal(n_int_alus
, reset_less
=True) # Dest R# in
71 self
.st_i
= Signal(n_int_alus
, reset_less
=True) # oper1 R# in
73 self
.load_hit_i
= Signal(n_int_alus
, reset_less
=True) # Load Hit
74 self
.stwd_hit_i
= Signal(n_int_alus
, reset_less
=True) # Store Hit
76 #self.g_int_st_pend_o = Signal(n_int_alus, reset_less=True)
77 #self.g_int_ld_pend_o = Signal(n_int_alus, reset_less=True)
79 # self.ld_rsel_o = Signal(n_int_alus, reset_less=True) # dest reg (bot)
80 # self.st_rsel_o = Signal(n_int_alus, reset_less=True) # src1 reg (bot)
82 self
.req_rel_i
= Signal(n_int_alus
, reset_less
=True)
83 self
.loadable_o
= Signal(n_int_alus
, reset_less
=True)
84 self
.storable_o
= Signal(n_int_alus
, reset_less
=True)
86 self
.go_st_i
= Signal(n_int_alus
, reset_less
=True)
87 self
.go_ld_i
= Signal(n_int_alus
, reset_less
=True)
88 self
.go_die_i
= Signal(n_int_alus
, reset_less
=True)
89 self
.req_rel_o
= Signal(n_int_alus
, reset_less
=True)
90 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
92 # Note: FURegs ld_pend_o is also outputted from here, for use in WaWGrid
94 def elaborate(self
, platform
):
99 n_intfus
= self
.n_int_alus
101 # Integer LD/ST Dep Matrix
102 ldstdeps
= LDSTDepMatrix(n_intfus
)
103 m
.submodules
.ldstdeps
= ldstdeps
104 # Integer FU-Mem Dep Matrix
105 fumemdeps
= FUMemDepMatrix(n_intfus
, n_intfus
)
106 m
.submodules
.fumemdeps
= fumemdeps
108 #comb += self.g_int_st_pend_o.eq(fumemdeps.v_st_rsel_o)
109 #comb += self.g_int_ld_pend_o.eq(fumemdeps.v_ld_rsel_o)
111 #comb += fumemdeps.st_pend_i.eq(fumemdeps.v_st_rsel_o)
112 #comb += fumemdeps.ld_pend_i.eq(fumemdeps.v_ld_rsel_o)
114 #comb += ldstdeps.st_pend_i.eq(fumemdeps.st_pend_o)
115 #comb += ldstdeps.ld_pend_i.eq(fumemdeps.ld_pend_o)
116 # self.ld_pend_o = fumemdeps.ld_pend_o # also output for use in WaWGrid
118 comb
+= ldstdeps
.ld_pend_i
.eq(self
.ld_i
)
119 comb
+= ldstdeps
.st_pend_i
.eq(self
.st_i
)
120 comb
+= ldstdeps
.issue_i
.eq(self
.fn_issue_i
)
121 comb
+= ldstdeps
.load_hit_i
.eq(self
.load_hit_i
)
122 comb
+= ldstdeps
.stwd_hit_i
.eq(self
.stwd_hit_i
)
123 comb
+= ldstdeps
.go_die_i
.eq(self
.go_die_i
)
124 comb
+= self
.storable_o
.eq(fumemdeps
.storable_o
)
125 comb
+= self
.loadable_o
.eq(fumemdeps
.loadable_o
)
126 comb
+= fumemdeps
.ld_pend_i
.eq(ldstdeps
.ld_hold_st_o
)
127 comb
+= fumemdeps
.st_pend_i
.eq(ldstdeps
.st_hold_ld_o
)
129 # Connect function issue / arrays, and dest/src1/src2
131 comb
+= fumemdeps
.go_st_i
.eq(self
.stwd_hit_i
)
132 comb
+= fumemdeps
.go_ld_i
.eq(self
.load_hit_i
)
133 comb
+= fumemdeps
.go_die_i
.eq(self
.go_die_i
)
134 comb
+= fumemdeps
.issue_i
.eq(self
.fn_issue_i
)
136 #comb += self.ld_rsel_o.eq(fumemdeps.ld_rsel_o)
137 #comb += self.st_rsel_o.eq(fumemdeps.st_rsel_o)
144 # yield self.g_int_st_pend_o
145 # yield self.g_int_ld_pend_o
146 # yield self.ld_rsel_o
147 # yield self.st_rsel_o
149 yield self
.loadable_o
150 yield self
.storable_o
151 yield self
.load_hit_i
152 yield self
.stwd_hit_i
157 yield self
.fn_issue_i
163 class Scoreboard(Elaboratable
):
164 def __init__(self
, rwid
, n_regs
):
167 * :rwid: bit width of register file(s) - both FP and INT
168 * :n_regs: depth of register file(s) - number of FP and INT regs
174 self
.intregs
= RegFileArray(rwid
, n_regs
)
175 self
.fpregs
= RegFileArray(rwid
, n_regs
)
177 # issue q needs to get at these
178 self
.aluissue
= IssueUnitGroup(4)
179 self
.brissue
= IssueUnitGroup(1)
181 self
.alu_oper_i
= Signal(4, reset_less
=True)
182 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
183 self
.br_oper_i
= Signal(4, reset_less
=True)
184 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
187 self
.int_dest_i
= Signal(range(n_regs
), reset_less
=True) # Dest R# in
188 self
.int_src1_i
= Signal(range(n_regs
), reset_less
=True) # oper1 R# in
189 self
.int_src2_i
= Signal(range(n_regs
), reset_less
=True) # oper2 R# in
190 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
193 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
194 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
196 # for branch speculation experiment. branch_direction = 0 if
197 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
198 # branch_succ and branch_fail are requests to have the current
199 # instruction be dependent on the branch unit "shadow" capability.
200 self
.branch_succ_i
= Signal(reset_less
=True)
201 self
.branch_fail_i
= Signal(reset_less
=True)
202 self
.branch_direction_o
= Signal(2, reset_less
=True)
204 def elaborate(self
, platform
):
209 m
.submodules
.intregs
= self
.intregs
210 m
.submodules
.fpregs
= self
.fpregs
213 int_dest
= self
.intregs
.write_port("dest")
214 int_src1
= self
.intregs
.read_port("src1")
215 int_src2
= self
.intregs
.read_port("src2")
217 fp_dest
= self
.fpregs
.write_port("dest")
218 fp_src1
= self
.fpregs
.read_port("src1")
219 fp_src2
= self
.fpregs
.read_port("src2")
221 # Int ALUs and Comp Units
223 cua
= CompUnitALUs(self
.rwid
, 3)
224 cub
= CompUnitBR(self
.rwid
, 3)
225 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
226 bgt
= cub
.bgt
# get at the branch computation unit
230 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
232 # Count of number of FUs
233 n_intfus
= n_int_alus
234 n_fp_fus
= 0 # for now
236 # Integer Priority Picker 1: Adder + Subtractor
237 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
238 m
.submodules
.intpick1
= intpick1
241 regdecode
= RegDecode(self
.n_regs
)
242 m
.submodules
.regdecode
= regdecode
243 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
244 m
.submodules
.issueunit
= issueunit
246 # Shadow Matrix. currently n_intfus shadows, to be used for
247 # write-after-write hazards. NOTE: there is one extra for branches,
248 # so the shadow width is increased by 1
249 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
250 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
252 # record previous instruction to cast shadow on current instruction
253 prev_shadow
= Signal(n_intfus
)
255 # Branch Speculation recorder. tracks the success/fail state as
256 # each instruction is issued, so that when the branch occurs the
257 # allow/cancel can be issued as appropriate.
258 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
261 # ok start wiring things together...
262 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
263 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
267 # Issue Unit is where it starts. set up some in/outs for this module
269 comb
+= [regdecode
.dest_i
.eq(self
.int_dest_i
),
270 regdecode
.src1_i
.eq(self
.int_src1_i
),
271 regdecode
.src2_i
.eq(self
.int_src2_i
),
272 regdecode
.enable_i
.eq(self
.reg_enable_i
),
273 self
.issue_o
.eq(issueunit
.issue_o
)
276 # take these to outside (issue needs them)
277 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
278 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
279 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
280 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
282 # TODO: issueunit.f (FP)
284 # and int function issue / busy arrays, and dest/src1/src2
285 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
286 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
287 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
289 fn_issue_o
= issueunit
.fn_issue_o
291 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
292 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
293 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
296 # merge shadow matrices outputs
299 # these are explained in ShadowMatrix docstring, and are to be
300 # connected to the FUReg and FUFU Matrices, to get them to reset
301 anydie
= Signal(n_intfus
, reset_less
=True)
302 allshadown
= Signal(n_intfus
, reset_less
=True)
303 shreset
= Signal(n_intfus
, reset_less
=True)
304 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
305 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
306 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
309 # connect fu-fu matrix
312 # Group Picker... done manually for now.
313 go_rd_o
= intpick1
.go_rd_o
314 go_wr_o
= intpick1
.go_wr_o
315 go_rd_i
= intfus
.go_rd_i
316 go_wr_i
= intfus
.go_wr_i
317 go_die_i
= intfus
.go_die_i
318 # NOTE: connect to the shadowed versions so that they can "die" (reset)
319 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
320 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
321 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
325 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
326 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
327 int_rd_o
= intfus
.readable_o
328 int_wr_o
= intfus
.writable_o
329 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
330 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
336 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
337 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
338 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
340 # NOTE; this setup is for the instruction order preservation...
342 # connect shadows / go_dies to Computation Units
343 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
344 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
346 # ok connect first n_int_fu shadows to busy lines, to create an
347 # instruction-order linked-list-like arrangement, using a bit-matrix
348 # (instead of e.g. a ring buffer).
351 # when written, the shadow can be cancelled (and was good)
352 for i
in range(n_intfus
):
353 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
355 # *previous* instruction shadows *current* instruction, and, obviously,
356 # if the previous is completed (!busy) don't cast the shadow!
357 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
358 for i
in range(n_intfus
):
359 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
362 # ... and this is for branch speculation. it uses the extra bit
363 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
364 # only needs to set shadow_i, s_fail_i and s_good_i
366 # issue captures shadow_i (if enabled)
367 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
369 bactive
= Signal(reset_less
=True)
370 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
372 # instruction being issued (fn_issue_o) has a shadow cast by the branch
373 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
374 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
375 for i
in range(n_intfus
):
376 with m
.If(fn_issue_o
& (Const(1 << i
))):
377 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
379 # finally, we need an indicator to the test infrastructure as to
380 # whether the branch succeeded or failed, plus, link up to the
381 # "recorder" of whether the instruction was under shadow or not
383 with m
.If(br1
.issue_i
):
384 sync
+= bspec
.active_i
.eq(1)
385 with m
.If(self
.branch_succ_i
):
386 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
387 with m
.If(self
.branch_fail_i
):
388 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
390 # branch is active (TODO: a better signal: this is over-using the
391 # go_write signal - actually the branch should not be "writing")
392 with m
.If(br1
.go_wr_i
):
393 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
394 sync
+= bspec
.active_i
.eq(0)
395 comb
+= bspec
.br_i
.eq(1)
396 # branch occurs if data == 1, failed if data == 0
397 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
398 for i
in range(n_intfus
):
399 # *expected* direction of the branch matched against *actual*
400 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
402 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
405 # Connect Register File(s)
407 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
408 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
409 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
411 # connect ALUs to regfule
412 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
413 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
414 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
416 # connect ALU Computation Units
417 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
418 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
419 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
424 yield from self
.intregs
425 yield from self
.fpregs
426 yield self
.int_dest_i
427 yield self
.int_src1_i
428 yield self
.int_src2_i
430 yield self
.branch_succ_i
431 yield self
.branch_fail_i
432 yield self
.branch_direction_o
438 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
439 yield from disable_issue(dut
)
440 yield dut
.int_dest_i
.eq(dest
)
441 yield dut
.int_src1_i
.eq(src1
)
442 yield dut
.int_src2_i
.eq(src2
)
443 if (op
& (0x3 << 2)) != 0: # branch
444 yield dut
.brissue
.insn_i
.eq(1)
445 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
446 yield dut
.br_imm_i
.eq(imm
)
447 dut_issue
= dut
.brissue
449 yield dut
.aluissue
.insn_i
.eq(1)
450 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
451 yield dut
.alu_imm_i
.eq(imm
)
452 dut_issue
= dut
.aluissue
453 yield dut
.reg_enable_i
.eq(1)
455 # these indicate that the instruction is to be made shadow-dependent on
456 # (either) branch success or branch fail
457 yield dut
.branch_fail_i
.eq(branch_fail
)
458 yield dut
.branch_succ_i
.eq(branch_success
)
461 yield from wait_for_issue(dut
, dut_issue
)
464 def print_reg(dut
, rnums
):
467 reg
= yield dut
.intregs
.regs
[rnum
].reg
468 rs
.append("%x" % reg
)
469 rnums
= map(str, rnums
)
470 print("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
473 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
475 for i
in range(n_ops
):
476 src1
= randint(1, dut
.n_regs
-1)
477 src2
= randint(1, dut
.n_regs
-1)
478 imm
= randint(1, (1 << dut
.rwid
)-1)
479 dest
= randint(1, dut
.n_regs
-1)
480 op
= randint(0, max_opnums
)
481 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
484 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
486 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
490 def scoreboard_sim(dut
, alusim
):
496 # set random values in the registers
497 for i
in range(1, dut
.n_regs
):
498 val
= randint(0, (1 << alusim
.rwidth
)-1)
501 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
502 alusim
.setval(i
, val
)
504 # create some instructions (some random, some regression tests)
507 instrs
= create_random_ops(dut
, 15, True, 4)
510 instrs
.append((1, 2, 2, 1, 1, 20, (0, 0)))
513 instrs
.append((7, 3, 2, 4, (0, 0)))
514 instrs
.append((7, 6, 6, 2, (0, 0)))
515 instrs
.append((1, 7, 2, 2, (0, 0)))
518 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
519 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
520 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
521 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
522 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
525 instrs
.append((3, 3, 4, 0, 0, 13979, (0, 0)))
526 instrs
.append((6, 4, 1, 2, 0, 40976, (0, 0)))
527 instrs
.append((1, 4, 7, 4, 1, 23652, (0, 0)))
530 instrs
.append((5, 6, 2, 1))
531 instrs
.append((2, 2, 4, 0))
532 #instrs.append((2, 2, 3, 1))
535 instrs
.append((2, 1, 2, 3))
538 instrs
.append((2, 6, 2, 1))
539 instrs
.append((2, 1, 2, 0))
542 instrs
.append((1, 2, 7, 2))
543 instrs
.append((7, 1, 5, 0))
544 instrs
.append((4, 4, 1, 1))
547 instrs
.append((5, 6, 2, 2))
548 instrs
.append((1, 1, 4, 1))
549 instrs
.append((6, 5, 3, 0))
552 # Write-after-Write Hazard
553 instrs
.append((3, 6, 7, 2))
554 instrs
.append((4, 4, 7, 1))
557 # self-read/write-after-write followed by Read-after-Write
558 instrs
.append((1, 1, 1, 1))
559 instrs
.append((1, 5, 3, 0))
562 # Read-after-Write followed by self-read-after-write
563 instrs
.append((5, 6, 1, 2))
564 instrs
.append((1, 1, 1, 1))
567 # self-read-write sandwich
568 instrs
.append((5, 6, 1, 2))
569 instrs
.append((1, 1, 1, 1))
570 instrs
.append((1, 5, 3, 0))
574 instrs
.append((5, 2, 5, 2))
575 instrs
.append((2, 6, 3, 0))
576 instrs
.append((4, 2, 2, 1))
580 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
582 yield dut
.intregs
.regs
[3].reg
.eq(5)
584 instrs
.append((5, 3, 3, 4, (0, 0)))
585 instrs
.append((4, 2, 1, 2, (0, 1)))
589 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
591 yield dut
.intregs
.regs
[3].reg
.eq(5)
593 instrs
.append((5, 3, 3, 4, (0, 0)))
594 instrs
.append((4, 2, 1, 2, (1, 0)))
597 instrs
.append((4, 3, 5, 1, 0, (0, 0)))
598 instrs
.append((5, 2, 3, 1, 0, (0, 0)))
599 instrs
.append((7, 1, 5, 2, 0, (0, 0)))
600 instrs
.append((5, 6, 6, 4, 0, (0, 0)))
601 instrs
.append((7, 5, 2, 2, 0, (1, 0)))
602 instrs
.append((1, 7, 5, 0, 0, (0, 1)))
603 instrs
.append((1, 6, 1, 2, 0, (1, 0)))
604 instrs
.append((1, 6, 7, 3, 0, (0, 0)))
605 instrs
.append((6, 7, 7, 0, 0, (0, 0)))
607 # issue instruction(s), wait for issue to be free before proceeding
608 for i
, instr
in enumerate(instrs
):
609 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
611 print("instr %d: (%d, %d, %d, %d, %d, %d)" %
612 (i
, src1
, src2
, dest
, op
, opi
, imm
))
613 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
614 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
617 # wait for all instructions to stop before checking
619 iqlen
= yield dut
.qlen_o
627 yield from wait_for_busy_clear(dut
)
630 yield from alusim
.check(dut
)
631 yield from alusim
.dump(dut
)
634 @unittest.skip("doesn't work") # FIXME
635 def test_scoreboard():
636 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
637 alusim
= RegSim(16, 8)
638 memsim
= MemSim(16, 16)
639 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
640 with
open("test_scoreboard6600.il", "w") as f
:
643 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
644 vcd_name
='test_scoreboard6600.vcd')
646 # run_simulation(dut, scoreboard_branch_sim(dut, alusim),
647 # vcd_name='test_scoreboard6600.vcd')
651 yield dut
.ld_i
.eq(0x1)
652 yield dut
.fn_issue_i
.eq(0x1)
654 # yield dut.ld_i.eq(0x0)
655 yield dut
.st_i
.eq(0x2)
656 yield dut
.fn_issue_i
.eq(0x2)
658 # yield dut.st_i.eq(0x0)
659 yield dut
.fn_issue_i
.eq(0x0)
662 yield dut
.load_hit_i
.eq(0x1)
664 yield dut
.load_hit_i
.eq(0x0)
666 yield dut
.stwd_hit_i
.eq(0x2)
668 yield dut
.stwd_hit_i
.eq(0x0)
673 dut
= MemFunctionUnits(3)
674 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
675 with
open("test_mem_fus.il", "w") as f
:
678 run_simulation(dut
, mem_sim(dut
),
679 vcd_name
='test_mem_fus.vcd')
682 if __name__
== '__main__':