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
.fu_fu_matrix
import FUFUDepMatrix
7 from scoreboard
.fu_reg_matrix
import FURegDepMatrix
8 from scoreboard
.global_pending
import GlobalPending
9 from scoreboard
.group_picker
import GroupPicker
10 from scoreboard
.issue_unit
import IssueUnitGroup
, IssueUnitArray
, RegDecode
11 from scoreboard
.shadow
import ShadowMatrix
, BranchSpeculationRecord
13 from nmutil
.latch
import SRLatch
14 from nmutil
.nmoperator
import eq
16 from random
import randint
, seed
17 from copy
import deepcopy
21 class Memory(Elaboratable
):
22 def __init__(self
, regwid
, addrw
):
23 self
.ddepth
= regwid
/8
24 depth
= (1<<addrw
) / self
.ddepth
25 self
.adr
= Signal(addrw
)
26 self
.dat_r
= Signal(regwid
)
27 self
.dat_w
= Signal(regwid
)
29 self
.mem
= Memory(width
=regwid
, depth
=depth
, init
=range(0, depth
))
31 def elaborate(self
, platform
):
33 m
.submodules
.rdport
= rdport
= self
.mem
.read_port()
34 m
.submodules
.wrport
= wrport
= self
.mem
.write_port()
36 rdport
.addr
.eq(self
.adr
[self
.ddepth
:]), # ignore low bits
37 self
.dat_r
.eq(rdport
.data
),
38 wrport
.addr
.eq(self
.adr
),
39 wrport
.data
.eq(self
.dat_w
),
40 wrport
.en
.eq(self
.we
),
46 def __init__(self
, regwid
, addrw
):
48 self
.ddepth
= regwid
//8
49 depth
= (1<<addrw
) // self
.ddepth
50 self
.mem
= list(range(0, depth
))
53 return self
.mem
[addr
>>self
.ddepth
]
55 def st(self
, addr
, data
):
56 self
.mem
[addr
>>self
.ddepth
] = data
& ((1<<self
.regwid
)-1)
59 class MemFunctionUnits(Elaboratable
):
61 def __init__(self
, n_ldsts
):
62 self
.n_ldsts
= n_ldsts
64 self
.st_i
= Signal(n_ldsts
, reset_less
=True) # Dest R# in
65 self
.ld_i
= Signal(n_ldsts
, reset_less
=True) # oper1 R# in
67 self
.g_int_ld_pend_o
= Signal(n_ldsts
, reset_less
=True)
68 self
.g_int_st_pend_o
= Signal(n_ldsts
, reset_less
=True)
70 self
.st_rsel_o
= Signal(n_ldsts
, reset_less
=True) # dest reg (bot)
71 self
.ld_rsel_o
= Signal(n_ldsts
, reset_less
=True) # src1 reg (bot)
73 self
.loadable_o
= Signal(n_ldsts
, reset_less
=True)
74 self
.storable_o
= Signal(n_ldsts
, reset_less
=True)
76 self
.go_ld_i
= Signal(n_ldsts
, reset_less
=True)
77 self
.go_st_i
= Signal(n_ldsts
, reset_less
=True)
78 self
.go_die_i
= Signal(n_ldsts
, reset_less
=True)
79 self
.fn_issue_i
= Signal(n_ldsts
, reset_less
=True)
81 # Note: FURegs st_pend_o is also outputted from here, for use in WaWGrid
83 def elaborate(self
, platform
):
90 # Integer FU-FU Dep Matrix
91 intfudeps
= FUFUDepMatrix(n_fus
, n_fus
)
92 m
.submodules
.intfudeps
= intfudeps
93 # Integer FU-Reg Dep Matrix
94 intregdeps
= FURegDepMatrix(n_fus
, n_fus
, 1)
95 m
.submodules
.intregdeps
= intregdeps
97 # connect fureg matrix as a mem system
98 comb
+= self
.g_int_ld_pend_o
.eq(intregdeps
.v_rd_rsel_o
)
99 comb
+= self
.g_int_st_pend_o
.eq(intregdeps
.v_wr_rsel_o
)
101 comb
+= intregdeps
.rd_pend_i
.eq(intregdeps
.v_rd_rsel_o
)
102 comb
+= intregdeps
.wr_pend_i
.eq(intregdeps
.v_wr_rsel_o
)
104 comb
+= intfudeps
.rd_pend_i
.eq(intregdeps
.rd_pend_o
)
105 comb
+= intfudeps
.wr_pend_i
.eq(intregdeps
.wr_pend_o
)
106 self
.st_pend_o
= intregdeps
.wr_pend_o
# also output for use in WaWGrid
108 comb
+= intfudeps
.issue_i
.eq(self
.fn_issue_i
)
109 comb
+= intfudeps
.go_rd_i
.eq(self
.go_ld_i
)
110 comb
+= intfudeps
.go_wr_i
.eq(self
.go_st_i
)
111 comb
+= intfudeps
.go_die_i
.eq(self
.go_die_i
)
112 comb
+= self
.loadable_o
.eq(intfudeps
.readable_o
)
113 comb
+= self
.storable_o
.eq(intfudeps
.writable_o
)
115 # Connect function issue / arrays, and dest/src1/src2
116 comb
+= intregdeps
.dest_i
.eq(self
.st_i
)
117 comb
+= intregdeps
.src_i
[0].eq(self
.ld_i
)
119 comb
+= intregdeps
.go_rd_i
.eq(self
.go_ld_i
)
120 comb
+= intregdeps
.go_wr_i
.eq(self
.go_st_i
)
121 comb
+= intregdeps
.go_die_i
.eq(self
.go_die_i
)
122 comb
+= intregdeps
.issue_i
.eq(self
.fn_issue_i
)
124 comb
+= self
.st_rsel_o
.eq(intregdeps
.dest_rsel_o
)
125 comb
+= self
.ld_rsel_o
.eq(intregdeps
.src_rsel_o
[0])
132 yield self
.g_int_st_pend_o
133 yield self
.g_int_ld_pend_o
136 yield self
.loadable_o
137 yield self
.storable_o
141 yield self
.fn_issue_i
147 class Scoreboard(Elaboratable
):
148 def __init__(self
, rwid
, n_regs
):
151 * :rwid: bit width of register file(s) - both FP and INT
152 * :n_regs: depth of register file(s) - number of FP and INT regs
158 self
.intregs
= RegFileArray(rwid
, n_regs
)
159 self
.fpregs
= RegFileArray(rwid
, n_regs
)
161 # issue q needs to get at these
162 self
.aluissue
= IssueUnitGroup(4)
163 self
.brissue
= IssueUnitGroup(1)
165 self
.alu_oper_i
= Signal(4, reset_less
=True)
166 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
167 self
.br_oper_i
= Signal(4, reset_less
=True)
168 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
171 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
172 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
173 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
174 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
177 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
178 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
180 # for branch speculation experiment. branch_direction = 0 if
181 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
182 # branch_succ and branch_fail are requests to have the current
183 # instruction be dependent on the branch unit "shadow" capability.
184 self
.branch_succ_i
= Signal(reset_less
=True)
185 self
.branch_fail_i
= Signal(reset_less
=True)
186 self
.branch_direction_o
= Signal(2, reset_less
=True)
188 def elaborate(self
, platform
):
193 m
.submodules
.intregs
= self
.intregs
194 m
.submodules
.fpregs
= self
.fpregs
197 int_dest
= self
.intregs
.write_port("dest")
198 int_src1
= self
.intregs
.read_port("src1")
199 int_src2
= self
.intregs
.read_port("src2")
201 fp_dest
= self
.fpregs
.write_port("dest")
202 fp_src1
= self
.fpregs
.read_port("src1")
203 fp_src2
= self
.fpregs
.read_port("src2")
205 # Int ALUs and Comp Units
207 cua
= CompUnitALUs(self
.rwid
, 3)
208 cub
= CompUnitBR(self
.rwid
, 3)
209 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
210 bgt
= cub
.bgt
# get at the branch computation unit
214 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
216 # Count of number of FUs
217 n_intfus
= n_int_alus
218 n_fp_fus
= 0 # for now
220 # Integer Priority Picker 1: Adder + Subtractor
221 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
222 m
.submodules
.intpick1
= intpick1
225 regdecode
= RegDecode(self
.n_regs
)
226 m
.submodules
.regdecode
= regdecode
227 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
228 m
.submodules
.issueunit
= issueunit
230 # Shadow Matrix. currently n_intfus shadows, to be used for
231 # write-after-write hazards. NOTE: there is one extra for branches,
232 # so the shadow width is increased by 1
233 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
234 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
236 # record previous instruction to cast shadow on current instruction
237 prev_shadow
= Signal(n_intfus
)
239 # Branch Speculation recorder. tracks the success/fail state as
240 # each instruction is issued, so that when the branch occurs the
241 # allow/cancel can be issued as appropriate.
242 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
245 # ok start wiring things together...
246 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
247 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
251 # Issue Unit is where it starts. set up some in/outs for this module
253 comb
+= [ regdecode
.dest_i
.eq(self
.int_dest_i
),
254 regdecode
.src1_i
.eq(self
.int_src1_i
),
255 regdecode
.src2_i
.eq(self
.int_src2_i
),
256 regdecode
.enable_i
.eq(self
.reg_enable_i
),
257 self
.issue_o
.eq(issueunit
.issue_o
)
260 # take these to outside (issue needs them)
261 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
262 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
263 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
264 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
266 # TODO: issueunit.f (FP)
268 # and int function issue / busy arrays, and dest/src1/src2
269 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
270 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
271 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
273 fn_issue_o
= issueunit
.fn_issue_o
275 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
276 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
277 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
280 # merge shadow matrices outputs
283 # these are explained in ShadowMatrix docstring, and are to be
284 # connected to the FUReg and FUFU Matrices, to get them to reset
285 anydie
= Signal(n_intfus
, reset_less
=True)
286 allshadown
= Signal(n_intfus
, reset_less
=True)
287 shreset
= Signal(n_intfus
, reset_less
=True)
288 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
289 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
290 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
293 # connect fu-fu matrix
296 # Group Picker... done manually for now.
297 go_rd_o
= intpick1
.go_rd_o
298 go_wr_o
= intpick1
.go_wr_o
299 go_rd_i
= intfus
.go_rd_i
300 go_wr_i
= intfus
.go_wr_i
301 go_die_i
= intfus
.go_die_i
302 # NOTE: connect to the shadowed versions so that they can "die" (reset)
303 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
304 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
305 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
309 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
310 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
311 int_rd_o
= intfus
.readable_o
312 int_wr_o
= intfus
.writable_o
313 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
314 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
320 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
321 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
322 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
324 # NOTE; this setup is for the instruction order preservation...
326 # connect shadows / go_dies to Computation Units
327 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
328 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
330 # ok connect first n_int_fu shadows to busy lines, to create an
331 # instruction-order linked-list-like arrangement, using a bit-matrix
332 # (instead of e.g. a ring buffer).
335 # when written, the shadow can be cancelled (and was good)
336 for i
in range(n_intfus
):
337 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
339 # *previous* instruction shadows *current* instruction, and, obviously,
340 # if the previous is completed (!busy) don't cast the shadow!
341 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
342 for i
in range(n_intfus
):
343 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
346 # ... and this is for branch speculation. it uses the extra bit
347 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
348 # only needs to set shadow_i, s_fail_i and s_good_i
350 # issue captures shadow_i (if enabled)
351 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
353 bactive
= Signal(reset_less
=True)
354 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
356 # instruction being issued (fn_issue_o) has a shadow cast by the branch
357 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
358 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
359 for i
in range(n_intfus
):
360 with m
.If(fn_issue_o
& (Const(1<<i
))):
361 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
363 # finally, we need an indicator to the test infrastructure as to
364 # whether the branch succeeded or failed, plus, link up to the
365 # "recorder" of whether the instruction was under shadow or not
367 with m
.If(br1
.issue_i
):
368 sync
+= bspec
.active_i
.eq(1)
369 with m
.If(self
.branch_succ_i
):
370 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
371 with m
.If(self
.branch_fail_i
):
372 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
374 # branch is active (TODO: a better signal: this is over-using the
375 # go_write signal - actually the branch should not be "writing")
376 with m
.If(br1
.go_wr_i
):
377 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
378 sync
+= bspec
.active_i
.eq(0)
379 comb
+= bspec
.br_i
.eq(1)
380 # branch occurs if data == 1, failed if data == 0
381 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
382 for i
in range(n_intfus
):
383 # *expected* direction of the branch matched against *actual*
384 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
386 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
389 # Connect Register File(s)
391 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
392 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
393 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
395 # connect ALUs to regfule
396 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
397 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
398 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
400 # connect ALU Computation Units
401 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
402 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
403 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
408 yield from self
.intregs
409 yield from self
.fpregs
410 yield self
.int_dest_i
411 yield self
.int_src1_i
412 yield self
.int_src2_i
414 yield self
.branch_succ_i
415 yield self
.branch_fail_i
416 yield self
.branch_direction_o
424 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
425 yield from disable_issue(dut
)
426 yield dut
.int_dest_i
.eq(dest
)
427 yield dut
.int_src1_i
.eq(src1
)
428 yield dut
.int_src2_i
.eq(src2
)
429 if (op
& (0x3<<2)) != 0: # branch
430 yield dut
.brissue
.insn_i
.eq(1)
431 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
432 yield dut
.br_imm_i
.eq(imm
)
433 dut_issue
= dut
.brissue
435 yield dut
.aluissue
.insn_i
.eq(1)
436 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
437 yield dut
.alu_imm_i
.eq(imm
)
438 dut_issue
= dut
.aluissue
439 yield dut
.reg_enable_i
.eq(1)
441 # these indicate that the instruction is to be made shadow-dependent on
442 # (either) branch success or branch fail
443 yield dut
.branch_fail_i
.eq(branch_fail
)
444 yield dut
.branch_succ_i
.eq(branch_success
)
447 yield from wait_for_issue(dut
, dut_issue
)
450 def print_reg(dut
, rnums
):
453 reg
= yield dut
.intregs
.regs
[rnum
].reg
454 rs
.append("%x" % reg
)
455 rnums
= map(str, rnums
)
456 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
459 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
461 for i
in range(n_ops
):
462 src1
= randint(1, dut
.n_regs
-1)
463 src2
= randint(1, dut
.n_regs
-1)
464 imm
= randint(1, (1<<dut
.rwid
)-1)
465 dest
= randint(1, dut
.n_regs
-1)
466 op
= randint(0, max_opnums
)
467 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
470 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
472 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
477 def scoreboard_sim(dut
, alusim
):
483 # set random values in the registers
484 for i
in range(1, dut
.n_regs
):
485 val
= randint(0, (1<<alusim
.rwidth
)-1)
488 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
489 alusim
.setval(i
, val
)
491 # create some instructions (some random, some regression tests)
494 instrs
= create_random_ops(dut
, 15, True, 4)
497 instrs
.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
500 instrs
.append( (7, 3, 2, 4, (0, 0)) )
501 instrs
.append( (7, 6, 6, 2, (0, 0)) )
502 instrs
.append( (1, 7, 2, 2, (0, 0)) )
505 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
506 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
507 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
508 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
509 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
512 instrs
.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
513 instrs
.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
514 instrs
.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
517 instrs
.append((5, 6, 2, 1))
518 instrs
.append((2, 2, 4, 0))
519 #instrs.append((2, 2, 3, 1))
522 instrs
.append((2, 1, 2, 3))
525 instrs
.append((2, 6, 2, 1))
526 instrs
.append((2, 1, 2, 0))
529 instrs
.append((1, 2, 7, 2))
530 instrs
.append((7, 1, 5, 0))
531 instrs
.append((4, 4, 1, 1))
534 instrs
.append((5, 6, 2, 2))
535 instrs
.append((1, 1, 4, 1))
536 instrs
.append((6, 5, 3, 0))
539 # Write-after-Write Hazard
540 instrs
.append( (3, 6, 7, 2) )
541 instrs
.append( (4, 4, 7, 1) )
544 # self-read/write-after-write followed by Read-after-Write
545 instrs
.append((1, 1, 1, 1))
546 instrs
.append((1, 5, 3, 0))
549 # Read-after-Write followed by self-read-after-write
550 instrs
.append((5, 6, 1, 2))
551 instrs
.append((1, 1, 1, 1))
554 # self-read-write sandwich
555 instrs
.append((5, 6, 1, 2))
556 instrs
.append((1, 1, 1, 1))
557 instrs
.append((1, 5, 3, 0))
561 instrs
.append( (5, 2, 5, 2) )
562 instrs
.append( (2, 6, 3, 0) )
563 instrs
.append( (4, 2, 2, 1) )
567 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
569 yield dut
.intregs
.regs
[3].reg
.eq(5)
571 instrs
.append((5, 3, 3, 4, (0, 0)))
572 instrs
.append((4, 2, 1, 2, (0, 1)))
576 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
578 yield dut
.intregs
.regs
[3].reg
.eq(5)
580 instrs
.append((5, 3, 3, 4, (0, 0)))
581 instrs
.append((4, 2, 1, 2, (1, 0)))
584 instrs
.append( (4, 3, 5, 1, 0, (0, 0)) )
585 instrs
.append( (5, 2, 3, 1, 0, (0, 0)) )
586 instrs
.append( (7, 1, 5, 2, 0, (0, 0)) )
587 instrs
.append( (5, 6, 6, 4, 0, (0, 0)) )
588 instrs
.append( (7, 5, 2, 2, 0, (1, 0)) )
589 instrs
.append( (1, 7, 5, 0, 0, (0, 1)) )
590 instrs
.append( (1, 6, 1, 2, 0, (1, 0)) )
591 instrs
.append( (1, 6, 7, 3, 0, (0, 0)) )
592 instrs
.append( (6, 7, 7, 0, 0, (0, 0)) )
594 # issue instruction(s), wait for issue to be free before proceeding
595 for i
, instr
in enumerate(instrs
):
596 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
598 print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
599 (i
, src1
, src2
, dest
, op
, opi
, imm
))
600 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
601 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
604 # wait for all instructions to stop before checking
606 iqlen
= yield dut
.qlen_o
614 yield from wait_for_busy_clear(dut
)
617 yield from alusim
.check(dut
)
618 yield from alusim
.dump(dut
)
621 def test_scoreboard():
622 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
623 alusim
= RegSim(16, 8)
624 memsim
= MemSim(16, 16)
625 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
626 with
open("test_scoreboard6600.il", "w") as f
:
629 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
630 vcd_name
='test_scoreboard6600.vcd')
632 #run_simulation(dut, scoreboard_branch_sim(dut, alusim),
633 # vcd_name='test_scoreboard6600.vcd')
637 yield dut
.ld_i
.eq(0x1)
638 yield dut
.fn_issue_i
.eq(0x1)
640 yield dut
.ld_i
.eq(0x0)
641 yield dut
.st_i
.eq(0x3)
642 yield dut
.fn_issue_i
.eq(0x2)
644 yield dut
.st_i
.eq(0x0)
645 yield dut
.fn_issue_i
.eq(0x0)
648 yield dut
.go_ld_i
.eq(0x1)
650 yield dut
.go_ld_i
.eq(0x0)
652 yield dut
.go_st_i
.eq(0x2)
654 yield dut
.go_st_i
.eq(0x0)
659 dut
= MemFunctionUnits(3)
660 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
661 with
open("test_mem_fus.il", "w") as f
:
664 run_simulation(dut
, mem_sim(dut
),
665 vcd_name
='test_mem_fus.vcd')
668 if __name__
== '__main__':