b75d21954185a08442499ada531f50e40f4d95eb
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
12 from scoreboard
.addr_match
import PartialAddrMatch
14 from nmutil
.latch
import SRLatch
15 from nmutil
.nmoperator
import eq
17 from random
import randint
, seed
18 from copy
import deepcopy
22 class Memory(Elaboratable
):
23 def __init__(self
, regwid
, addrw
):
24 self
.ddepth
= regwid
/8
25 depth
= (1<<addrw
) / self
.ddepth
26 self
.adr
= Signal(addrw
)
27 self
.dat_r
= Signal(regwid
)
28 self
.dat_w
= Signal(regwid
)
30 self
.mem
= Memory(width
=regwid
, depth
=depth
, init
=range(0, depth
))
32 def elaborate(self
, platform
):
34 m
.submodules
.rdport
= rdport
= self
.mem
.read_port()
35 m
.submodules
.wrport
= wrport
= self
.mem
.write_port()
37 rdport
.addr
.eq(self
.adr
[self
.ddepth
:]), # ignore low bits
38 self
.dat_r
.eq(rdport
.data
),
39 wrport
.addr
.eq(self
.adr
),
40 wrport
.data
.eq(self
.dat_w
),
41 wrport
.en
.eq(self
.we
),
47 def __init__(self
, regwid
, addrw
):
49 self
.ddepth
= regwid
//8
50 depth
= (1<<addrw
) // self
.ddepth
51 self
.mem
= list(range(0, depth
))
54 return self
.mem
[addr
>>self
.ddepth
]
56 def st(self
, addr
, data
):
57 self
.mem
[addr
>>self
.ddepth
] = data
& ((1<<self
.regwid
)-1)
60 class FUMemMatchMatrix(FURegDepMatrix
, PartialAddrMatch
):
61 """ implement a FU-Regs overload with memory-address matching
63 def __init__(self
, n_fu
, addrbitwid
):
64 PartialAddrMatch
.__init
__(self
, n_fu
, addrbitwid
)
65 FURegDepMatrix
.__init
__(self
, n_fu
, n_fu
, 1, self
.addr_match_o
)
67 def elaborate(self
, platform
):
69 FURegDepMatrix
._elaborate
(self
, m
, platform
)
70 PartialAddrMatch
._elaborate
(self
, m
, platform
)
75 class MemFunctionUnits(Elaboratable
):
77 def __init__(self
, n_ldsts
):
78 self
.n_ldsts
= n_ldsts
80 self
.st_i
= Signal(n_ldsts
, reset_less
=True) # Dest R# in
81 self
.ld_i
= Signal(n_ldsts
, reset_less
=True) # oper1 R# in
83 self
.g_int_ld_pend_o
= Signal(n_ldsts
, reset_less
=True)
84 self
.g_int_st_pend_o
= Signal(n_ldsts
, reset_less
=True)
86 self
.st_rsel_o
= Signal(n_ldsts
, reset_less
=True) # dest reg (bot)
87 self
.ld_rsel_o
= Signal(n_ldsts
, reset_less
=True) # src1 reg (bot)
89 self
.loadable_o
= Signal(n_ldsts
, reset_less
=True)
90 self
.storable_o
= Signal(n_ldsts
, reset_less
=True)
92 self
.go_ld_i
= Signal(n_ldsts
, reset_less
=True)
93 self
.go_st_i
= Signal(n_ldsts
, reset_less
=True)
94 self
.go_die_i
= Signal(n_ldsts
, reset_less
=True)
95 self
.fn_issue_i
= Signal(n_ldsts
, reset_less
=True)
97 # Note: FURegs st_pend_o is also outputted from here, for use in WaWGrid
99 def elaborate(self
, platform
):
106 # Integer FU-FU Dep Matrix
107 intfudeps
= FUFUDepMatrix(n_fus
, n_fus
)
108 m
.submodules
.intfudeps
= intfudeps
109 # Integer FU-Reg Dep Matrix
110 intregdeps
= FUMemMatchMatrix(n_fus
, 11)
111 m
.submodules
.intregdeps
= intregdeps
113 # ok, because we do not know in advance what the AGEN (address gen)
114 # is, we have to make a transitive dependency set. i.e. the LD
115 # (or ST) being requested now must depend on ALL prior LDs *AND* STs.
116 # these get dropped very rapidly once AGEN is carried out.
118 # connect fureg matrix as a mem system
119 comb
+= self
.g_int_ld_pend_o
.eq(intregdeps
.v_rd_rsel_o
)
120 comb
+= self
.g_int_st_pend_o
.eq(intregdeps
.v_wr_rsel_o
)
122 comb
+= intregdeps
.rd_pend_i
.eq(intregdeps
.v_rd_rsel_o
)
123 comb
+= intregdeps
.wr_pend_i
.eq(intregdeps
.v_wr_rsel_o
)
125 comb
+= intfudeps
.rd_pend_i
.eq(intregdeps
.rd_pend_o
)
126 comb
+= intfudeps
.wr_pend_i
.eq(intregdeps
.wr_pend_o
)
127 self
.st_pend_o
= intregdeps
.wr_pend_o
# also output for use in WaWGrid
129 comb
+= intfudeps
.issue_i
.eq(self
.fn_issue_i
)
130 comb
+= intfudeps
.go_rd_i
.eq(self
.go_ld_i
)
131 comb
+= intfudeps
.go_wr_i
.eq(self
.go_st_i
)
132 comb
+= intfudeps
.go_die_i
.eq(self
.go_die_i
)
133 comb
+= self
.loadable_o
.eq(intfudeps
.readable_o
)
134 comb
+= self
.storable_o
.eq(intfudeps
.writable_o
)
136 # Connect function issue / arrays, and dest/src1/src2
137 comb
+= intregdeps
.dest_i
.eq(self
.st_i
)
138 comb
+= intregdeps
.src_i
[0].eq(self
.ld_i
)
140 comb
+= intregdeps
.go_rd_i
.eq(self
.go_ld_i
)
141 comb
+= intregdeps
.go_wr_i
.eq(self
.go_st_i
)
142 comb
+= intregdeps
.go_die_i
.eq(self
.go_die_i
)
143 comb
+= intregdeps
.issue_i
.eq(self
.fn_issue_i
)
145 comb
+= self
.st_rsel_o
.eq(intregdeps
.dest_rsel_o
)
146 comb
+= self
.ld_rsel_o
.eq(intregdeps
.src_rsel_o
[0])
153 yield self
.g_int_st_pend_o
154 yield self
.g_int_ld_pend_o
157 yield self
.loadable_o
158 yield self
.storable_o
162 yield self
.fn_issue_i
168 class Scoreboard(Elaboratable
):
169 def __init__(self
, rwid
, n_regs
):
172 * :rwid: bit width of register file(s) - both FP and INT
173 * :n_regs: depth of register file(s) - number of FP and INT regs
179 self
.intregs
= RegFileArray(rwid
, n_regs
)
180 self
.fpregs
= RegFileArray(rwid
, n_regs
)
182 # issue q needs to get at these
183 self
.aluissue
= IssueUnitGroup(4)
184 self
.brissue
= IssueUnitGroup(1)
186 self
.alu_oper_i
= Signal(4, reset_less
=True)
187 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
188 self
.br_oper_i
= Signal(4, reset_less
=True)
189 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
192 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
193 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
194 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
195 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
198 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
199 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
201 # for branch speculation experiment. branch_direction = 0 if
202 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
203 # branch_succ and branch_fail are requests to have the current
204 # instruction be dependent on the branch unit "shadow" capability.
205 self
.branch_succ_i
= Signal(reset_less
=True)
206 self
.branch_fail_i
= Signal(reset_less
=True)
207 self
.branch_direction_o
= Signal(2, reset_less
=True)
209 def elaborate(self
, platform
):
214 m
.submodules
.intregs
= self
.intregs
215 m
.submodules
.fpregs
= self
.fpregs
218 int_dest
= self
.intregs
.write_port("dest")
219 int_src1
= self
.intregs
.read_port("src1")
220 int_src2
= self
.intregs
.read_port("src2")
222 fp_dest
= self
.fpregs
.write_port("dest")
223 fp_src1
= self
.fpregs
.read_port("src1")
224 fp_src2
= self
.fpregs
.read_port("src2")
226 # Int ALUs and Comp Units
228 cua
= CompUnitALUs(self
.rwid
, 3)
229 cub
= CompUnitBR(self
.rwid
, 3)
230 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
231 bgt
= cub
.bgt
# get at the branch computation unit
235 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
237 # Count of number of FUs
238 n_intfus
= n_int_alus
239 n_fp_fus
= 0 # for now
241 # Integer Priority Picker 1: Adder + Subtractor
242 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
243 m
.submodules
.intpick1
= intpick1
246 regdecode
= RegDecode(self
.n_regs
)
247 m
.submodules
.regdecode
= regdecode
248 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
249 m
.submodules
.issueunit
= issueunit
251 # Shadow Matrix. currently n_intfus shadows, to be used for
252 # write-after-write hazards. NOTE: there is one extra for branches,
253 # so the shadow width is increased by 1
254 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
255 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
257 # record previous instruction to cast shadow on current instruction
258 prev_shadow
= Signal(n_intfus
)
260 # Branch Speculation recorder. tracks the success/fail state as
261 # each instruction is issued, so that when the branch occurs the
262 # allow/cancel can be issued as appropriate.
263 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
266 # ok start wiring things together...
267 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
268 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
272 # Issue Unit is where it starts. set up some in/outs for this module
274 comb
+= [ regdecode
.dest_i
.eq(self
.int_dest_i
),
275 regdecode
.src1_i
.eq(self
.int_src1_i
),
276 regdecode
.src2_i
.eq(self
.int_src2_i
),
277 regdecode
.enable_i
.eq(self
.reg_enable_i
),
278 self
.issue_o
.eq(issueunit
.issue_o
)
281 # take these to outside (issue needs them)
282 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
283 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
284 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
285 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
287 # TODO: issueunit.f (FP)
289 # and int function issue / busy arrays, and dest/src1/src2
290 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
291 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
292 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
294 fn_issue_o
= issueunit
.fn_issue_o
296 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
297 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
298 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
301 # merge shadow matrices outputs
304 # these are explained in ShadowMatrix docstring, and are to be
305 # connected to the FUReg and FUFU Matrices, to get them to reset
306 anydie
= Signal(n_intfus
, reset_less
=True)
307 allshadown
= Signal(n_intfus
, reset_less
=True)
308 shreset
= Signal(n_intfus
, reset_less
=True)
309 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
310 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
311 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
314 # connect fu-fu matrix
317 # Group Picker... done manually for now.
318 go_rd_o
= intpick1
.go_rd_o
319 go_wr_o
= intpick1
.go_wr_o
320 go_rd_i
= intfus
.go_rd_i
321 go_wr_i
= intfus
.go_wr_i
322 go_die_i
= intfus
.go_die_i
323 # NOTE: connect to the shadowed versions so that they can "die" (reset)
324 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
325 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
326 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
330 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
331 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
332 int_rd_o
= intfus
.readable_o
333 int_wr_o
= intfus
.writable_o
334 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
335 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
341 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
342 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
343 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
345 # NOTE; this setup is for the instruction order preservation...
347 # connect shadows / go_dies to Computation Units
348 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
349 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
351 # ok connect first n_int_fu shadows to busy lines, to create an
352 # instruction-order linked-list-like arrangement, using a bit-matrix
353 # (instead of e.g. a ring buffer).
356 # when written, the shadow can be cancelled (and was good)
357 for i
in range(n_intfus
):
358 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
360 # *previous* instruction shadows *current* instruction, and, obviously,
361 # if the previous is completed (!busy) don't cast the shadow!
362 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
363 for i
in range(n_intfus
):
364 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
367 # ... and this is for branch speculation. it uses the extra bit
368 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
369 # only needs to set shadow_i, s_fail_i and s_good_i
371 # issue captures shadow_i (if enabled)
372 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
374 bactive
= Signal(reset_less
=True)
375 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
377 # instruction being issued (fn_issue_o) has a shadow cast by the branch
378 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
379 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
380 for i
in range(n_intfus
):
381 with m
.If(fn_issue_o
& (Const(1<<i
))):
382 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
384 # finally, we need an indicator to the test infrastructure as to
385 # whether the branch succeeded or failed, plus, link up to the
386 # "recorder" of whether the instruction was under shadow or not
388 with m
.If(br1
.issue_i
):
389 sync
+= bspec
.active_i
.eq(1)
390 with m
.If(self
.branch_succ_i
):
391 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
392 with m
.If(self
.branch_fail_i
):
393 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
395 # branch is active (TODO: a better signal: this is over-using the
396 # go_write signal - actually the branch should not be "writing")
397 with m
.If(br1
.go_wr_i
):
398 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
399 sync
+= bspec
.active_i
.eq(0)
400 comb
+= bspec
.br_i
.eq(1)
401 # branch occurs if data == 1, failed if data == 0
402 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
403 for i
in range(n_intfus
):
404 # *expected* direction of the branch matched against *actual*
405 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
407 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
410 # Connect Register File(s)
412 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
413 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
414 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
416 # connect ALUs to regfule
417 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
418 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
419 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
421 # connect ALU Computation Units
422 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
423 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
424 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
429 yield from self
.intregs
430 yield from self
.fpregs
431 yield self
.int_dest_i
432 yield self
.int_src1_i
433 yield self
.int_src2_i
435 yield self
.branch_succ_i
436 yield self
.branch_fail_i
437 yield self
.branch_direction_o
445 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
446 yield from disable_issue(dut
)
447 yield dut
.int_dest_i
.eq(dest
)
448 yield dut
.int_src1_i
.eq(src1
)
449 yield dut
.int_src2_i
.eq(src2
)
450 if (op
& (0x3<<2)) != 0: # branch
451 yield dut
.brissue
.insn_i
.eq(1)
452 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
453 yield dut
.br_imm_i
.eq(imm
)
454 dut_issue
= dut
.brissue
456 yield dut
.aluissue
.insn_i
.eq(1)
457 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
458 yield dut
.alu_imm_i
.eq(imm
)
459 dut_issue
= dut
.aluissue
460 yield dut
.reg_enable_i
.eq(1)
462 # these indicate that the instruction is to be made shadow-dependent on
463 # (either) branch success or branch fail
464 yield dut
.branch_fail_i
.eq(branch_fail
)
465 yield dut
.branch_succ_i
.eq(branch_success
)
468 yield from wait_for_issue(dut
, dut_issue
)
471 def print_reg(dut
, rnums
):
474 reg
= yield dut
.intregs
.regs
[rnum
].reg
475 rs
.append("%x" % reg
)
476 rnums
= map(str, rnums
)
477 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
480 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
482 for i
in range(n_ops
):
483 src1
= randint(1, dut
.n_regs
-1)
484 src2
= randint(1, dut
.n_regs
-1)
485 imm
= randint(1, (1<<dut
.rwid
)-1)
486 dest
= randint(1, dut
.n_regs
-1)
487 op
= randint(0, max_opnums
)
488 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
491 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
493 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
498 def scoreboard_sim(dut
, alusim
):
504 # set random values in the registers
505 for i
in range(1, dut
.n_regs
):
506 val
= randint(0, (1<<alusim
.rwidth
)-1)
509 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
510 alusim
.setval(i
, val
)
512 # create some instructions (some random, some regression tests)
515 instrs
= create_random_ops(dut
, 15, True, 4)
518 instrs
.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
521 instrs
.append( (7, 3, 2, 4, (0, 0)) )
522 instrs
.append( (7, 6, 6, 2, (0, 0)) )
523 instrs
.append( (1, 7, 2, 2, (0, 0)) )
526 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
527 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
528 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
529 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
530 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
533 instrs
.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
534 instrs
.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
535 instrs
.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
538 instrs
.append((5, 6, 2, 1))
539 instrs
.append((2, 2, 4, 0))
540 #instrs.append((2, 2, 3, 1))
543 instrs
.append((2, 1, 2, 3))
546 instrs
.append((2, 6, 2, 1))
547 instrs
.append((2, 1, 2, 0))
550 instrs
.append((1, 2, 7, 2))
551 instrs
.append((7, 1, 5, 0))
552 instrs
.append((4, 4, 1, 1))
555 instrs
.append((5, 6, 2, 2))
556 instrs
.append((1, 1, 4, 1))
557 instrs
.append((6, 5, 3, 0))
560 # Write-after-Write Hazard
561 instrs
.append( (3, 6, 7, 2) )
562 instrs
.append( (4, 4, 7, 1) )
565 # self-read/write-after-write followed by Read-after-Write
566 instrs
.append((1, 1, 1, 1))
567 instrs
.append((1, 5, 3, 0))
570 # Read-after-Write followed by self-read-after-write
571 instrs
.append((5, 6, 1, 2))
572 instrs
.append((1, 1, 1, 1))
575 # self-read-write sandwich
576 instrs
.append((5, 6, 1, 2))
577 instrs
.append((1, 1, 1, 1))
578 instrs
.append((1, 5, 3, 0))
582 instrs
.append( (5, 2, 5, 2) )
583 instrs
.append( (2, 6, 3, 0) )
584 instrs
.append( (4, 2, 2, 1) )
588 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
590 yield dut
.intregs
.regs
[3].reg
.eq(5)
592 instrs
.append((5, 3, 3, 4, (0, 0)))
593 instrs
.append((4, 2, 1, 2, (0, 1)))
597 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
599 yield dut
.intregs
.regs
[3].reg
.eq(5)
601 instrs
.append((5, 3, 3, 4, (0, 0)))
602 instrs
.append((4, 2, 1, 2, (1, 0)))
605 instrs
.append( (4, 3, 5, 1, 0, (0, 0)) )
606 instrs
.append( (5, 2, 3, 1, 0, (0, 0)) )
607 instrs
.append( (7, 1, 5, 2, 0, (0, 0)) )
608 instrs
.append( (5, 6, 6, 4, 0, (0, 0)) )
609 instrs
.append( (7, 5, 2, 2, 0, (1, 0)) )
610 instrs
.append( (1, 7, 5, 0, 0, (0, 1)) )
611 instrs
.append( (1, 6, 1, 2, 0, (1, 0)) )
612 instrs
.append( (1, 6, 7, 3, 0, (0, 0)) )
613 instrs
.append( (6, 7, 7, 0, 0, (0, 0)) )
615 # issue instruction(s), wait for issue to be free before proceeding
616 for i
, instr
in enumerate(instrs
):
617 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
619 print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
620 (i
, src1
, src2
, dest
, op
, opi
, imm
))
621 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
622 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
625 # wait for all instructions to stop before checking
627 iqlen
= yield dut
.qlen_o
635 yield from wait_for_busy_clear(dut
)
638 yield from alusim
.check(dut
)
639 yield from alusim
.dump(dut
)
642 def test_scoreboard():
643 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
644 alusim
= RegSim(16, 8)
645 memsim
= MemSim(16, 16)
646 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
647 with
open("test_scoreboard6600.il", "w") as f
:
650 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
651 vcd_name
='test_scoreboard6600.vcd')
653 #run_simulation(dut, scoreboard_branch_sim(dut, alusim),
654 # vcd_name='test_scoreboard6600.vcd')
658 yield dut
.ld_i
.eq(0x1)
659 yield dut
.fn_issue_i
.eq(0x1)
661 yield dut
.ld_i
.eq(0x0)
662 yield dut
.st_i
.eq(0x3)
663 yield dut
.fn_issue_i
.eq(0x2)
665 yield dut
.st_i
.eq(0x0)
666 yield dut
.fn_issue_i
.eq(0x0)
669 yield dut
.go_ld_i
.eq(0x1)
671 yield dut
.go_ld_i
.eq(0x0)
673 yield dut
.go_st_i
.eq(0x2)
675 yield dut
.go_st_i
.eq(0x0)
680 dut
= MemFunctionUnits(3)
681 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
682 with
open("test_mem_fus.il", "w") as f
:
685 run_simulation(dut
, mem_sim(dut
),
686 vcd_name
='test_mem_fus.vcd')
689 if __name__
== '__main__':