80b9e63ffe86eb475de8f97f85667714e0b4aa37
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_int_alus
):
62 self
.n_int_alus
= n_int_alus
64 self
.st_i
= Signal(n_int_alus
, reset_less
=True) # Dest R# in
65 self
.ld_i
= Signal(n_int_alus
, reset_less
=True) # oper1 R# in
67 self
.g_int_ld_pend_o
= Signal(n_int_alus
, reset_less
=True)
68 self
.g_int_st_pend_o
= Signal(n_int_alus
, reset_less
=True)
70 self
.st_rsel_o
= Signal(n_int_alus
, reset_less
=True) # dest reg (bot)
71 self
.ld_rsel_o
= Signal(n_int_alus
, reset_less
=True) # src1 reg (bot)
73 self
.loadable_o
= Signal(n_int_alus
, reset_less
=True)
74 self
.storable_o
= Signal(n_int_alus
, reset_less
=True)
76 self
.go_ld_i
= Signal(n_int_alus
, reset_less
=True)
77 self
.go_st_i
= Signal(n_int_alus
, reset_less
=True)
78 self
.go_die_i
= Signal(n_int_alus
, reset_less
=True)
79 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
81 # Note: FURegs st_pend_o is also outputted from here, for use in WaWGrid
83 def elaborate(self
, platform
):
88 n_intfus
= self
.n_int_alus
90 # Integer FU-FU Dep Matrix
91 intfudeps
= FUFUDepMatrix(n_intfus
, n_intfus
)
92 m
.submodules
.intfudeps
= intfudeps
93 # Integer FU-Reg Dep Matrix
94 intregdeps
= FURegDepMatrix(n_intfus
, n_intfus
, 1)
95 m
.submodules
.intregdeps
= intregdeps
97 comb
+= self
.g_int_ld_pend_o
.eq(intregdeps
.v_rd_rsel_o
)
98 comb
+= self
.g_int_st_pend_o
.eq(intregdeps
.v_wr_rsel_o
)
100 comb
+= intregdeps
.rd_pend_i
.eq(intregdeps
.v_rd_rsel_o
)
101 comb
+= intregdeps
.wr_pend_i
.eq(intregdeps
.v_wr_rsel_o
)
103 comb
+= intfudeps
.rd_pend_i
.eq(intregdeps
.rd_pend_o
)
104 comb
+= intfudeps
.wr_pend_i
.eq(intregdeps
.wr_pend_o
)
105 self
.st_pend_o
= intregdeps
.wr_pend_o
# also output for use in WaWGrid
107 comb
+= intfudeps
.issue_i
.eq(self
.fn_issue_i
)
108 comb
+= intfudeps
.go_rd_i
.eq(self
.go_ld_i
)
109 comb
+= intfudeps
.go_wr_i
.eq(self
.go_st_i
)
110 comb
+= intfudeps
.go_die_i
.eq(self
.go_die_i
)
111 comb
+= self
.loadable_o
.eq(intfudeps
.readable_o
)
112 comb
+= self
.storable_o
.eq(intfudeps
.writable_o
)
114 # Connect function issue / arrays, and dest/src1/src2
115 comb
+= intregdeps
.dest_i
.eq(self
.st_i
)
116 comb
+= intregdeps
.src_i
[0].eq(self
.ld_i
)
118 comb
+= intregdeps
.go_rd_i
.eq(self
.go_ld_i
)
119 comb
+= intregdeps
.go_wr_i
.eq(self
.go_st_i
)
120 comb
+= intregdeps
.go_die_i
.eq(self
.go_die_i
)
121 comb
+= intregdeps
.issue_i
.eq(self
.fn_issue_i
)
123 comb
+= self
.st_rsel_o
.eq(intregdeps
.dest_rsel_o
)
124 comb
+= self
.ld_rsel_o
.eq(intregdeps
.src_rsel_o
[0])
131 yield self
.g_int_st_pend_o
132 yield self
.g_int_ld_pend_o
135 yield self
.loadable_o
136 yield self
.storable_o
140 yield self
.fn_issue_i
146 class Scoreboard(Elaboratable
):
147 def __init__(self
, rwid
, n_regs
):
150 * :rwid: bit width of register file(s) - both FP and INT
151 * :n_regs: depth of register file(s) - number of FP and INT regs
157 self
.intregs
= RegFileArray(rwid
, n_regs
)
158 self
.fpregs
= RegFileArray(rwid
, n_regs
)
160 # issue q needs to get at these
161 self
.aluissue
= IssueUnitGroup(4)
162 self
.brissue
= IssueUnitGroup(1)
164 self
.alu_oper_i
= Signal(4, reset_less
=True)
165 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
166 self
.br_oper_i
= Signal(4, reset_less
=True)
167 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
170 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
171 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
172 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
173 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
176 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
177 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
179 # for branch speculation experiment. branch_direction = 0 if
180 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
181 # branch_succ and branch_fail are requests to have the current
182 # instruction be dependent on the branch unit "shadow" capability.
183 self
.branch_succ_i
= Signal(reset_less
=True)
184 self
.branch_fail_i
= Signal(reset_less
=True)
185 self
.branch_direction_o
= Signal(2, reset_less
=True)
187 def elaborate(self
, platform
):
192 m
.submodules
.intregs
= self
.intregs
193 m
.submodules
.fpregs
= self
.fpregs
196 int_dest
= self
.intregs
.write_port("dest")
197 int_src1
= self
.intregs
.read_port("src1")
198 int_src2
= self
.intregs
.read_port("src2")
200 fp_dest
= self
.fpregs
.write_port("dest")
201 fp_src1
= self
.fpregs
.read_port("src1")
202 fp_src2
= self
.fpregs
.read_port("src2")
204 # Int ALUs and Comp Units
206 cua
= CompUnitALUs(self
.rwid
, 3)
207 cub
= CompUnitBR(self
.rwid
, 3)
208 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
209 bgt
= cub
.bgt
# get at the branch computation unit
213 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
215 # Count of number of FUs
216 n_intfus
= n_int_alus
217 n_fp_fus
= 0 # for now
219 # Integer Priority Picker 1: Adder + Subtractor
220 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
221 m
.submodules
.intpick1
= intpick1
224 regdecode
= RegDecode(self
.n_regs
)
225 m
.submodules
.regdecode
= regdecode
226 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
227 m
.submodules
.issueunit
= issueunit
229 # Shadow Matrix. currently n_intfus shadows, to be used for
230 # write-after-write hazards. NOTE: there is one extra for branches,
231 # so the shadow width is increased by 1
232 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
233 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
235 # record previous instruction to cast shadow on current instruction
236 prev_shadow
= Signal(n_intfus
)
238 # Branch Speculation recorder. tracks the success/fail state as
239 # each instruction is issued, so that when the branch occurs the
240 # allow/cancel can be issued as appropriate.
241 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
244 # ok start wiring things together...
245 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
246 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
250 # Issue Unit is where it starts. set up some in/outs for this module
252 comb
+= [ regdecode
.dest_i
.eq(self
.int_dest_i
),
253 regdecode
.src1_i
.eq(self
.int_src1_i
),
254 regdecode
.src2_i
.eq(self
.int_src2_i
),
255 regdecode
.enable_i
.eq(self
.reg_enable_i
),
256 self
.issue_o
.eq(issueunit
.issue_o
)
259 # take these to outside (issue needs them)
260 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
261 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
262 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
263 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
265 # TODO: issueunit.f (FP)
267 # and int function issue / busy arrays, and dest/src1/src2
268 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
269 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
270 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
272 fn_issue_o
= issueunit
.fn_issue_o
274 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
275 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
276 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
279 # merge shadow matrices outputs
282 # these are explained in ShadowMatrix docstring, and are to be
283 # connected to the FUReg and FUFU Matrices, to get them to reset
284 anydie
= Signal(n_intfus
, reset_less
=True)
285 allshadown
= Signal(n_intfus
, reset_less
=True)
286 shreset
= Signal(n_intfus
, reset_less
=True)
287 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
288 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
289 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
292 # connect fu-fu matrix
295 # Group Picker... done manually for now.
296 go_rd_o
= intpick1
.go_rd_o
297 go_wr_o
= intpick1
.go_wr_o
298 go_rd_i
= intfus
.go_rd_i
299 go_wr_i
= intfus
.go_wr_i
300 go_die_i
= intfus
.go_die_i
301 # NOTE: connect to the shadowed versions so that they can "die" (reset)
302 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
303 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
304 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
308 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
309 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
310 int_rd_o
= intfus
.readable_o
311 int_wr_o
= intfus
.writable_o
312 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
313 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
319 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
320 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
321 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
323 # NOTE; this setup is for the instruction order preservation...
325 # connect shadows / go_dies to Computation Units
326 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
327 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
329 # ok connect first n_int_fu shadows to busy lines, to create an
330 # instruction-order linked-list-like arrangement, using a bit-matrix
331 # (instead of e.g. a ring buffer).
334 # when written, the shadow can be cancelled (and was good)
335 for i
in range(n_intfus
):
336 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
338 # *previous* instruction shadows *current* instruction, and, obviously,
339 # if the previous is completed (!busy) don't cast the shadow!
340 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
341 for i
in range(n_intfus
):
342 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
345 # ... and this is for branch speculation. it uses the extra bit
346 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
347 # only needs to set shadow_i, s_fail_i and s_good_i
349 # issue captures shadow_i (if enabled)
350 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
352 bactive
= Signal(reset_less
=True)
353 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
355 # instruction being issued (fn_issue_o) has a shadow cast by the branch
356 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
357 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
358 for i
in range(n_intfus
):
359 with m
.If(fn_issue_o
& (Const(1<<i
))):
360 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
362 # finally, we need an indicator to the test infrastructure as to
363 # whether the branch succeeded or failed, plus, link up to the
364 # "recorder" of whether the instruction was under shadow or not
366 with m
.If(br1
.issue_i
):
367 sync
+= bspec
.active_i
.eq(1)
368 with m
.If(self
.branch_succ_i
):
369 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
370 with m
.If(self
.branch_fail_i
):
371 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
373 # branch is active (TODO: a better signal: this is over-using the
374 # go_write signal - actually the branch should not be "writing")
375 with m
.If(br1
.go_wr_i
):
376 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
377 sync
+= bspec
.active_i
.eq(0)
378 comb
+= bspec
.br_i
.eq(1)
379 # branch occurs if data == 1, failed if data == 0
380 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
381 for i
in range(n_intfus
):
382 # *expected* direction of the branch matched against *actual*
383 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
385 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
388 # Connect Register File(s)
390 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
391 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
392 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
394 # connect ALUs to regfule
395 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
396 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
397 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
399 # connect ALU Computation Units
400 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
401 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
402 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
407 yield from self
.intregs
408 yield from self
.fpregs
409 yield self
.int_dest_i
410 yield self
.int_src1_i
411 yield self
.int_src2_i
413 yield self
.branch_succ_i
414 yield self
.branch_fail_i
415 yield self
.branch_direction_o
423 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
424 yield from disable_issue(dut
)
425 yield dut
.int_dest_i
.eq(dest
)
426 yield dut
.int_src1_i
.eq(src1
)
427 yield dut
.int_src2_i
.eq(src2
)
428 if (op
& (0x3<<2)) != 0: # branch
429 yield dut
.brissue
.insn_i
.eq(1)
430 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
431 yield dut
.br_imm_i
.eq(imm
)
432 dut_issue
= dut
.brissue
434 yield dut
.aluissue
.insn_i
.eq(1)
435 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
436 yield dut
.alu_imm_i
.eq(imm
)
437 dut_issue
= dut
.aluissue
438 yield dut
.reg_enable_i
.eq(1)
440 # these indicate that the instruction is to be made shadow-dependent on
441 # (either) branch success or branch fail
442 yield dut
.branch_fail_i
.eq(branch_fail
)
443 yield dut
.branch_succ_i
.eq(branch_success
)
446 yield from wait_for_issue(dut
, dut_issue
)
449 def print_reg(dut
, rnums
):
452 reg
= yield dut
.intregs
.regs
[rnum
].reg
453 rs
.append("%x" % reg
)
454 rnums
= map(str, rnums
)
455 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
458 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
460 for i
in range(n_ops
):
461 src1
= randint(1, dut
.n_regs
-1)
462 src2
= randint(1, dut
.n_regs
-1)
463 imm
= randint(1, (1<<dut
.rwid
)-1)
464 dest
= randint(1, dut
.n_regs
-1)
465 op
= randint(0, max_opnums
)
466 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
469 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
471 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
476 def scoreboard_sim(dut
, alusim
):
482 # set random values in the registers
483 for i
in range(1, dut
.n_regs
):
484 val
= randint(0, (1<<alusim
.rwidth
)-1)
487 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
488 alusim
.setval(i
, val
)
490 # create some instructions (some random, some regression tests)
493 instrs
= create_random_ops(dut
, 15, True, 4)
496 instrs
.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
499 instrs
.append( (7, 3, 2, 4, (0, 0)) )
500 instrs
.append( (7, 6, 6, 2, (0, 0)) )
501 instrs
.append( (1, 7, 2, 2, (0, 0)) )
504 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
505 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
506 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
507 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
508 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
511 instrs
.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
512 instrs
.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
513 instrs
.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
516 instrs
.append((5, 6, 2, 1))
517 instrs
.append((2, 2, 4, 0))
518 #instrs.append((2, 2, 3, 1))
521 instrs
.append((2, 1, 2, 3))
524 instrs
.append((2, 6, 2, 1))
525 instrs
.append((2, 1, 2, 0))
528 instrs
.append((1, 2, 7, 2))
529 instrs
.append((7, 1, 5, 0))
530 instrs
.append((4, 4, 1, 1))
533 instrs
.append((5, 6, 2, 2))
534 instrs
.append((1, 1, 4, 1))
535 instrs
.append((6, 5, 3, 0))
538 # Write-after-Write Hazard
539 instrs
.append( (3, 6, 7, 2) )
540 instrs
.append( (4, 4, 7, 1) )
543 # self-read/write-after-write followed by Read-after-Write
544 instrs
.append((1, 1, 1, 1))
545 instrs
.append((1, 5, 3, 0))
548 # Read-after-Write followed by self-read-after-write
549 instrs
.append((5, 6, 1, 2))
550 instrs
.append((1, 1, 1, 1))
553 # self-read-write sandwich
554 instrs
.append((5, 6, 1, 2))
555 instrs
.append((1, 1, 1, 1))
556 instrs
.append((1, 5, 3, 0))
560 instrs
.append( (5, 2, 5, 2) )
561 instrs
.append( (2, 6, 3, 0) )
562 instrs
.append( (4, 2, 2, 1) )
566 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
568 yield dut
.intregs
.regs
[3].reg
.eq(5)
570 instrs
.append((5, 3, 3, 4, (0, 0)))
571 instrs
.append((4, 2, 1, 2, (0, 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, (1, 0)))
583 instrs
.append( (4, 3, 5, 1, 0, (0, 0)) )
584 instrs
.append( (5, 2, 3, 1, 0, (0, 0)) )
585 instrs
.append( (7, 1, 5, 2, 0, (0, 0)) )
586 instrs
.append( (5, 6, 6, 4, 0, (0, 0)) )
587 instrs
.append( (7, 5, 2, 2, 0, (1, 0)) )
588 instrs
.append( (1, 7, 5, 0, 0, (0, 1)) )
589 instrs
.append( (1, 6, 1, 2, 0, (1, 0)) )
590 instrs
.append( (1, 6, 7, 3, 0, (0, 0)) )
591 instrs
.append( (6, 7, 7, 0, 0, (0, 0)) )
593 # issue instruction(s), wait for issue to be free before proceeding
594 for i
, instr
in enumerate(instrs
):
595 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
597 print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
598 (i
, src1
, src2
, dest
, op
, opi
, imm
))
599 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
600 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
603 # wait for all instructions to stop before checking
605 iqlen
= yield dut
.qlen_o
613 yield from wait_for_busy_clear(dut
)
616 yield from alusim
.check(dut
)
617 yield from alusim
.dump(dut
)
620 def test_scoreboard():
621 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
622 alusim
= RegSim(16, 8)
623 memsim
= MemSim(16, 16)
624 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
625 with
open("test_scoreboard6600.il", "w") as f
:
628 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
629 vcd_name
='test_scoreboard6600.vcd')
631 #run_simulation(dut, scoreboard_branch_sim(dut, alusim),
632 # vcd_name='test_scoreboard6600.vcd')
636 yield dut
.ld_i
.eq(0x1)
637 yield dut
.fn_issue_i
.eq(0x1)
639 yield dut
.ld_i
.eq(0x0)
640 yield dut
.st_i
.eq(0x3)
641 yield dut
.fn_issue_i
.eq(0x2)
643 yield dut
.st_i
.eq(0x0)
644 yield dut
.fn_issue_i
.eq(0x0)
647 yield dut
.go_ld_i
.eq(0x1)
649 yield dut
.go_ld_i
.eq(0x0)
651 yield dut
.go_st_i
.eq(0x2)
653 yield dut
.go_st_i
.eq(0x0)
658 dut
= MemFunctionUnits(3)
659 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
660 with
open("test_mem_fus.il", "w") as f
:
663 run_simulation(dut
, mem_sim(dut
),
664 vcd_name
='test_mem_fus.vcd')
667 if __name__
== '__main__':