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
.ldst_matrix
import LDSTDepMatrix
7 from scoreboard
.mem_fu_matrix
import MemFUDepMatrix
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_int_alus
):
62 self
.n_int_alus
= n_int_alus
64 self
.ld_i
= Signal(n_int_alus
, reset_less
=True) # Dest R# in
65 self
.st_i
= Signal(n_int_alus
, reset_less
=True) # oper1 R# in
67 self
.load_hit_i
= Signal(n_int_alus
, reset_less
=True) # Load Hit
68 self
.stwd_hit_i
= Signal(n_int_alus
, reset_less
=True) # Store Hit
70 self
.g_int_st_pend_o
= Signal(n_int_alus
, reset_less
=True)
71 self
.g_int_ld_pend_o
= Signal(n_int_alus
, reset_less
=True)
73 self
.ld_rsel_o
= Signal(n_int_alus
, reset_less
=True) # dest reg (bot)
74 self
.st_rsel_o
= Signal(n_int_alus
, reset_less
=True) # src1 reg (bot)
76 self
.req_rel_i
= Signal(n_int_alus
, reset_less
= True)
77 self
.ld_hold_st_o
= Signal(n_int_alus
, reset_less
=True)
78 self
.st_hold_ld_o
= Signal(n_int_alus
, reset_less
=True)
80 self
.go_st_i
= Signal(n_int_alus
, reset_less
=True)
81 self
.go_ld_i
= Signal(n_int_alus
, reset_less
=True)
82 self
.go_die_i
= Signal(n_int_alus
, reset_less
=True)
83 self
.req_rel_o
= Signal(n_int_alus
, reset_less
=True)
84 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
86 # Note: FURegs ld_pend_o is also outputted from here, for use in WaWGrid
88 def elaborate(self
, platform
):
93 n_intfus
= self
.n_int_alus
95 # Integer FU-FU Dep Matrix
96 ldstdeps
= LDSTDepMatrix(n_intfus
)
97 m
.submodules
.ldstdeps
= ldstdeps
98 # Integer FU-Reg Dep Matrix
99 memfudeps
= MemFUDepMatrix(n_intfus
, n_intfus
)
100 m
.submodules
.memfudeps
= memfudeps
102 comb
+= self
.g_int_st_pend_o
.eq(memfudeps
.v_st_rsel_o
)
103 comb
+= self
.g_int_ld_pend_o
.eq(memfudeps
.v_ld_rsel_o
)
105 comb
+= memfudeps
.st_pend_i
.eq(memfudeps
.v_st_rsel_o
)
106 comb
+= memfudeps
.ld_pend_i
.eq(memfudeps
.v_ld_rsel_o
)
108 comb
+= ldstdeps
.st_pend_i
.eq(memfudeps
.st_pend_o
)
109 comb
+= ldstdeps
.ld_pend_i
.eq(memfudeps
.ld_pend_o
)
110 self
.ld_pend_o
= memfudeps
.ld_pend_o
# also output for use in WaWGrid
112 comb
+= ldstdeps
.issue_i
.eq(self
.fn_issue_i
)
113 comb
+= ldstdeps
.load_hit_i
.eq(self
.load_hit_i
)
114 comb
+= ldstdeps
.stwd_hit_i
.eq(self
.stwd_hit_i
)
115 comb
+= ldstdeps
.go_die_i
.eq(self
.go_die_i
)
116 comb
+= self
.ld_hold_st_o
.eq(ldstdeps
.ld_hold_st_o
)
117 comb
+= self
.st_hold_ld_o
.eq(ldstdeps
.st_hold_ld_o
)
119 # Connect function issue / arrays, and dest/src1/src2
120 comb
+= memfudeps
.ld_i
.eq(self
.ld_i
)
121 comb
+= memfudeps
.st_i
.eq(self
.st_i
)
123 comb
+= memfudeps
.go_st_i
.eq(self
.go_st_i
)
124 comb
+= memfudeps
.go_ld_i
.eq(self
.go_ld_i
)
125 comb
+= memfudeps
.go_die_i
.eq(self
.go_die_i
)
126 comb
+= memfudeps
.issue_i
.eq(self
.fn_issue_i
)
128 comb
+= self
.ld_rsel_o
.eq(memfudeps
.ld_rsel_o
)
129 comb
+= self
.st_rsel_o
.eq(memfudeps
.st_rsel_o
)
136 yield self
.g_int_st_pend_o
137 yield self
.g_int_ld_pend_o
141 yield self
.ld_hold_st_o
142 yield self
.st_hold_ld_o
143 yield self
.load_hit_i
144 yield self
.stwd_hit_i
149 yield self
.fn_issue_i
155 class Scoreboard(Elaboratable
):
156 def __init__(self
, rwid
, n_regs
):
159 * :rwid: bit width of register file(s) - both FP and INT
160 * :n_regs: depth of register file(s) - number of FP and INT regs
166 self
.intregs
= RegFileArray(rwid
, n_regs
)
167 self
.fpregs
= RegFileArray(rwid
, n_regs
)
169 # issue q needs to get at these
170 self
.aluissue
= IssueUnitGroup(4)
171 self
.brissue
= IssueUnitGroup(1)
173 self
.alu_oper_i
= Signal(4, reset_less
=True)
174 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
175 self
.br_oper_i
= Signal(4, reset_less
=True)
176 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
179 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
180 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
181 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
182 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
185 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
186 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
188 # for branch speculation experiment. branch_direction = 0 if
189 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
190 # branch_succ and branch_fail are requests to have the current
191 # instruction be dependent on the branch unit "shadow" capability.
192 self
.branch_succ_i
= Signal(reset_less
=True)
193 self
.branch_fail_i
= Signal(reset_less
=True)
194 self
.branch_direction_o
= Signal(2, reset_less
=True)
196 def elaborate(self
, platform
):
201 m
.submodules
.intregs
= self
.intregs
202 m
.submodules
.fpregs
= self
.fpregs
205 int_dest
= self
.intregs
.write_port("dest")
206 int_src1
= self
.intregs
.read_port("src1")
207 int_src2
= self
.intregs
.read_port("src2")
209 fp_dest
= self
.fpregs
.write_port("dest")
210 fp_src1
= self
.fpregs
.read_port("src1")
211 fp_src2
= self
.fpregs
.read_port("src2")
213 # Int ALUs and Comp Units
215 cua
= CompUnitALUs(self
.rwid
, 3)
216 cub
= CompUnitBR(self
.rwid
, 3)
217 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
218 bgt
= cub
.bgt
# get at the branch computation unit
222 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
224 # Count of number of FUs
225 n_intfus
= n_int_alus
226 n_fp_fus
= 0 # for now
228 # Integer Priority Picker 1: Adder + Subtractor
229 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
230 m
.submodules
.intpick1
= intpick1
233 regdecode
= RegDecode(self
.n_regs
)
234 m
.submodules
.regdecode
= regdecode
235 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
236 m
.submodules
.issueunit
= issueunit
238 # Shadow Matrix. currently n_intfus shadows, to be used for
239 # write-after-write hazards. NOTE: there is one extra for branches,
240 # so the shadow width is increased by 1
241 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
242 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
244 # record previous instruction to cast shadow on current instruction
245 prev_shadow
= Signal(n_intfus
)
247 # Branch Speculation recorder. tracks the success/fail state as
248 # each instruction is issued, so that when the branch occurs the
249 # allow/cancel can be issued as appropriate.
250 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
253 # ok start wiring things together...
254 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
255 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
259 # Issue Unit is where it starts. set up some in/outs for this module
261 comb
+= [ regdecode
.dest_i
.eq(self
.int_dest_i
),
262 regdecode
.src1_i
.eq(self
.int_src1_i
),
263 regdecode
.src2_i
.eq(self
.int_src2_i
),
264 regdecode
.enable_i
.eq(self
.reg_enable_i
),
265 self
.issue_o
.eq(issueunit
.issue_o
)
268 # take these to outside (issue needs them)
269 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
270 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
271 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
272 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
274 # TODO: issueunit.f (FP)
276 # and int function issue / busy arrays, and dest/src1/src2
277 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
278 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
279 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
281 fn_issue_o
= issueunit
.fn_issue_o
283 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
284 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
285 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
288 # merge shadow matrices outputs
291 # these are explained in ShadowMatrix docstring, and are to be
292 # connected to the FUReg and FUFU Matrices, to get them to reset
293 anydie
= Signal(n_intfus
, reset_less
=True)
294 allshadown
= Signal(n_intfus
, reset_less
=True)
295 shreset
= Signal(n_intfus
, reset_less
=True)
296 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
297 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
298 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
301 # connect fu-fu matrix
304 # Group Picker... done manually for now.
305 go_rd_o
= intpick1
.go_rd_o
306 go_wr_o
= intpick1
.go_wr_o
307 go_rd_i
= intfus
.go_rd_i
308 go_wr_i
= intfus
.go_wr_i
309 go_die_i
= intfus
.go_die_i
310 # NOTE: connect to the shadowed versions so that they can "die" (reset)
311 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
312 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
313 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
317 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
318 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
319 int_rd_o
= intfus
.readable_o
320 int_wr_o
= intfus
.writable_o
321 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
322 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
328 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
329 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
330 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
332 # NOTE; this setup is for the instruction order preservation...
334 # connect shadows / go_dies to Computation Units
335 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
336 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
338 # ok connect first n_int_fu shadows to busy lines, to create an
339 # instruction-order linked-list-like arrangement, using a bit-matrix
340 # (instead of e.g. a ring buffer).
343 # when written, the shadow can be cancelled (and was good)
344 for i
in range(n_intfus
):
345 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
347 # *previous* instruction shadows *current* instruction, and, obviously,
348 # if the previous is completed (!busy) don't cast the shadow!
349 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
350 for i
in range(n_intfus
):
351 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
354 # ... and this is for branch speculation. it uses the extra bit
355 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
356 # only needs to set shadow_i, s_fail_i and s_good_i
358 # issue captures shadow_i (if enabled)
359 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
361 bactive
= Signal(reset_less
=True)
362 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
364 # instruction being issued (fn_issue_o) has a shadow cast by the branch
365 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
366 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
367 for i
in range(n_intfus
):
368 with m
.If(fn_issue_o
& (Const(1<<i
))):
369 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
371 # finally, we need an indicator to the test infrastructure as to
372 # whether the branch succeeded or failed, plus, link up to the
373 # "recorder" of whether the instruction was under shadow or not
375 with m
.If(br1
.issue_i
):
376 sync
+= bspec
.active_i
.eq(1)
377 with m
.If(self
.branch_succ_i
):
378 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
379 with m
.If(self
.branch_fail_i
):
380 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
382 # branch is active (TODO: a better signal: this is over-using the
383 # go_write signal - actually the branch should not be "writing")
384 with m
.If(br1
.go_wr_i
):
385 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
386 sync
+= bspec
.active_i
.eq(0)
387 comb
+= bspec
.br_i
.eq(1)
388 # branch occurs if data == 1, failed if data == 0
389 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
390 for i
in range(n_intfus
):
391 # *expected* direction of the branch matched against *actual*
392 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
394 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
397 # Connect Register File(s)
399 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
400 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
401 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
403 # connect ALUs to regfule
404 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
405 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
406 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
408 # connect ALU Computation Units
409 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
410 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
411 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
416 yield from self
.intregs
417 yield from self
.fpregs
418 yield self
.int_dest_i
419 yield self
.int_src1_i
420 yield self
.int_src2_i
422 yield self
.branch_succ_i
423 yield self
.branch_fail_i
424 yield self
.branch_direction_o
432 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
433 yield from disable_issue(dut
)
434 yield dut
.int_dest_i
.eq(dest
)
435 yield dut
.int_src1_i
.eq(src1
)
436 yield dut
.int_src2_i
.eq(src2
)
437 if (op
& (0x3<<2)) != 0: # branch
438 yield dut
.brissue
.insn_i
.eq(1)
439 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
440 yield dut
.br_imm_i
.eq(imm
)
441 dut_issue
= dut
.brissue
443 yield dut
.aluissue
.insn_i
.eq(1)
444 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
445 yield dut
.alu_imm_i
.eq(imm
)
446 dut_issue
= dut
.aluissue
447 yield dut
.reg_enable_i
.eq(1)
449 # these indicate that the instruction is to be made shadow-dependent on
450 # (either) branch success or branch fail
451 yield dut
.branch_fail_i
.eq(branch_fail
)
452 yield dut
.branch_succ_i
.eq(branch_success
)
455 yield from wait_for_issue(dut
, dut_issue
)
458 def print_reg(dut
, rnums
):
461 reg
= yield dut
.intregs
.regs
[rnum
].reg
462 rs
.append("%x" % reg
)
463 rnums
= map(str, rnums
)
464 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
467 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
469 for i
in range(n_ops
):
470 src1
= randint(1, dut
.n_regs
-1)
471 src2
= randint(1, dut
.n_regs
-1)
472 imm
= randint(1, (1<<dut
.rwid
)-1)
473 dest
= randint(1, dut
.n_regs
-1)
474 op
= randint(0, max_opnums
)
475 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
478 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
480 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
485 def scoreboard_sim(dut
, alusim
):
491 # set random values in the registers
492 for i
in range(1, dut
.n_regs
):
493 val
= randint(0, (1<<alusim
.rwidth
)-1)
496 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
497 alusim
.setval(i
, val
)
499 # create some instructions (some random, some regression tests)
502 instrs
= create_random_ops(dut
, 15, True, 4)
505 instrs
.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
508 instrs
.append( (7, 3, 2, 4, (0, 0)) )
509 instrs
.append( (7, 6, 6, 2, (0, 0)) )
510 instrs
.append( (1, 7, 2, 2, (0, 0)) )
513 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
514 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
515 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
516 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
517 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
520 instrs
.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
521 instrs
.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
522 instrs
.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
525 instrs
.append((5, 6, 2, 1))
526 instrs
.append((2, 2, 4, 0))
527 #instrs.append((2, 2, 3, 1))
530 instrs
.append((2, 1, 2, 3))
533 instrs
.append((2, 6, 2, 1))
534 instrs
.append((2, 1, 2, 0))
537 instrs
.append((1, 2, 7, 2))
538 instrs
.append((7, 1, 5, 0))
539 instrs
.append((4, 4, 1, 1))
542 instrs
.append((5, 6, 2, 2))
543 instrs
.append((1, 1, 4, 1))
544 instrs
.append((6, 5, 3, 0))
547 # Write-after-Write Hazard
548 instrs
.append( (3, 6, 7, 2) )
549 instrs
.append( (4, 4, 7, 1) )
552 # self-read/write-after-write followed by Read-after-Write
553 instrs
.append((1, 1, 1, 1))
554 instrs
.append((1, 5, 3, 0))
557 # Read-after-Write followed by self-read-after-write
558 instrs
.append((5, 6, 1, 2))
559 instrs
.append((1, 1, 1, 1))
562 # self-read-write sandwich
563 instrs
.append((5, 6, 1, 2))
564 instrs
.append((1, 1, 1, 1))
565 instrs
.append((1, 5, 3, 0))
569 instrs
.append( (5, 2, 5, 2) )
570 instrs
.append( (2, 6, 3, 0) )
571 instrs
.append( (4, 2, 2, 1) )
575 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
577 yield dut
.intregs
.regs
[3].reg
.eq(5)
579 instrs
.append((5, 3, 3, 4, (0, 0)))
580 instrs
.append((4, 2, 1, 2, (0, 1)))
584 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
586 yield dut
.intregs
.regs
[3].reg
.eq(5)
588 instrs
.append((5, 3, 3, 4, (0, 0)))
589 instrs
.append((4, 2, 1, 2, (1, 0)))
592 instrs
.append( (4, 3, 5, 1, 0, (0, 0)) )
593 instrs
.append( (5, 2, 3, 1, 0, (0, 0)) )
594 instrs
.append( (7, 1, 5, 2, 0, (0, 0)) )
595 instrs
.append( (5, 6, 6, 4, 0, (0, 0)) )
596 instrs
.append( (7, 5, 2, 2, 0, (1, 0)) )
597 instrs
.append( (1, 7, 5, 0, 0, (0, 1)) )
598 instrs
.append( (1, 6, 1, 2, 0, (1, 0)) )
599 instrs
.append( (1, 6, 7, 3, 0, (0, 0)) )
600 instrs
.append( (6, 7, 7, 0, 0, (0, 0)) )
602 # issue instruction(s), wait for issue to be free before proceeding
603 for i
, instr
in enumerate(instrs
):
604 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
606 print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
607 (i
, src1
, src2
, dest
, op
, opi
, imm
))
608 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
609 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
612 # wait for all instructions to stop before checking
614 iqlen
= yield dut
.qlen_o
622 yield from wait_for_busy_clear(dut
)
625 yield from alusim
.check(dut
)
626 yield from alusim
.dump(dut
)
629 def test_scoreboard():
630 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
631 alusim
= RegSim(16, 8)
632 memsim
= MemSim(16, 16)
633 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
634 with
open("test_scoreboard6600.il", "w") as f
:
637 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
638 vcd_name
='test_scoreboard6600.vcd')
640 #run_simulation(dut, scoreboard_branch_sim(dut, alusim),
641 # vcd_name='test_scoreboard6600.vcd')
645 yield dut
.ld_i
.eq(0x1)
646 yield dut
.fn_issue_i
.eq(0x1)
648 yield dut
.st_i
.eq(0x2)
649 yield dut
.fn_issue_i
.eq(0x2)
651 yield dut
.fn_issue_i
.eq(0x0)
654 yield dut
.stwd_hit_i
.eq(0x2)
659 dut
= MemFunctionUnits(4)
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__':