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
.fu_mem_matrix
import FUMemDepMatrix
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
.loadable_o
= Signal(n_int_alus
, reset_less
=True)
78 self
.storable_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 LD/ST Dep Matrix
96 ldstdeps
= LDSTDepMatrix(n_intfus
)
97 m
.submodules
.ldstdeps
= ldstdeps
98 # Integer FU-Mem Dep Matrix
99 fumemdeps
= FUMemDepMatrix(n_intfus
, n_intfus
)
100 m
.submodules
.fumemdeps
= fumemdeps
102 #comb += self.g_int_st_pend_o.eq(fumemdeps.v_st_rsel_o)
103 #comb += self.g_int_ld_pend_o.eq(fumemdeps.v_ld_rsel_o)
105 #comb += fumemdeps.st_pend_i.eq(fumemdeps.v_st_rsel_o)
106 #comb += fumemdeps.ld_pend_i.eq(fumemdeps.v_ld_rsel_o)
108 #comb += ldstdeps.st_pend_i.eq(fumemdeps.st_pend_o)
109 #comb += ldstdeps.ld_pend_i.eq(fumemdeps.ld_pend_o)
110 #self.ld_pend_o = fumemdeps.ld_pend_o # also output for use in WaWGrid
112 comb
+= ldstdeps
.ld_pend_i
.eq(self
.ld_i
)
113 comb
+= ldstdeps
.st_pend_i
.eq(self
.st_i
)
114 comb
+= ldstdeps
.issue_i
.eq(self
.fn_issue_i
)
115 comb
+= ldstdeps
.load_hit_i
.eq(self
.load_hit_i
)
116 comb
+= ldstdeps
.stwd_hit_i
.eq(self
.stwd_hit_i
)
117 comb
+= ldstdeps
.go_die_i
.eq(self
.go_die_i
)
118 comb
+= self
.storable_o
.eq(fumemdeps
.storable_o
)
119 comb
+= self
.loadable_o
.eq(fumemdeps
.loadable_o
)
120 comb
+= fumemdeps
.ld_pend_i
.eq(ldstdeps
.ld_hold_st_o
)
121 comb
+= fumemdeps
.st_pend_i
.eq(ldstdeps
.st_hold_ld_o
)
123 # Connect function issue / arrays, and dest/src1/src2
125 comb
+= fumemdeps
.go_st_i
.eq(self
.stwd_hit_i
)
126 comb
+= fumemdeps
.go_ld_i
.eq(self
.load_hit_i
)
127 comb
+= fumemdeps
.go_die_i
.eq(self
.go_die_i
)
128 comb
+= fumemdeps
.issue_i
.eq(self
.fn_issue_i
)
130 #comb += self.ld_rsel_o.eq(fumemdeps.ld_rsel_o)
131 #comb += self.st_rsel_o.eq(fumemdeps.st_rsel_o)
138 #yield self.g_int_st_pend_o
139 #yield self.g_int_ld_pend_o
140 #yield self.ld_rsel_o
141 #yield self.st_rsel_o
143 yield self
.loadable_o
144 yield self
.storable_o
145 yield self
.load_hit_i
146 yield self
.stwd_hit_i
151 yield self
.fn_issue_i
157 class Scoreboard(Elaboratable
):
158 def __init__(self
, rwid
, n_regs
):
161 * :rwid: bit width of register file(s) - both FP and INT
162 * :n_regs: depth of register file(s) - number of FP and INT regs
168 self
.intregs
= RegFileArray(rwid
, n_regs
)
169 self
.fpregs
= RegFileArray(rwid
, n_regs
)
171 # issue q needs to get at these
172 self
.aluissue
= IssueUnitGroup(4)
173 self
.brissue
= IssueUnitGroup(1)
175 self
.alu_oper_i
= Signal(4, reset_less
=True)
176 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
177 self
.br_oper_i
= Signal(4, reset_less
=True)
178 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
181 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
182 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
183 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
184 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
187 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
188 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
190 # for branch speculation experiment. branch_direction = 0 if
191 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
192 # branch_succ and branch_fail are requests to have the current
193 # instruction be dependent on the branch unit "shadow" capability.
194 self
.branch_succ_i
= Signal(reset_less
=True)
195 self
.branch_fail_i
= Signal(reset_less
=True)
196 self
.branch_direction_o
= Signal(2, reset_less
=True)
198 def elaborate(self
, platform
):
203 m
.submodules
.intregs
= self
.intregs
204 m
.submodules
.fpregs
= self
.fpregs
207 int_dest
= self
.intregs
.write_port("dest")
208 int_src1
= self
.intregs
.read_port("src1")
209 int_src2
= self
.intregs
.read_port("src2")
211 fp_dest
= self
.fpregs
.write_port("dest")
212 fp_src1
= self
.fpregs
.read_port("src1")
213 fp_src2
= self
.fpregs
.read_port("src2")
215 # Int ALUs and Comp Units
217 cua
= CompUnitALUs(self
.rwid
, 3)
218 cub
= CompUnitBR(self
.rwid
, 3)
219 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
220 bgt
= cub
.bgt
# get at the branch computation unit
224 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
226 # Count of number of FUs
227 n_intfus
= n_int_alus
228 n_fp_fus
= 0 # for now
230 # Integer Priority Picker 1: Adder + Subtractor
231 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
232 m
.submodules
.intpick1
= intpick1
235 regdecode
= RegDecode(self
.n_regs
)
236 m
.submodules
.regdecode
= regdecode
237 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
238 m
.submodules
.issueunit
= issueunit
240 # Shadow Matrix. currently n_intfus shadows, to be used for
241 # write-after-write hazards. NOTE: there is one extra for branches,
242 # so the shadow width is increased by 1
243 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
244 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
246 # record previous instruction to cast shadow on current instruction
247 prev_shadow
= Signal(n_intfus
)
249 # Branch Speculation recorder. tracks the success/fail state as
250 # each instruction is issued, so that when the branch occurs the
251 # allow/cancel can be issued as appropriate.
252 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
255 # ok start wiring things together...
256 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
257 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
261 # Issue Unit is where it starts. set up some in/outs for this module
263 comb
+= [ regdecode
.dest_i
.eq(self
.int_dest_i
),
264 regdecode
.src1_i
.eq(self
.int_src1_i
),
265 regdecode
.src2_i
.eq(self
.int_src2_i
),
266 regdecode
.enable_i
.eq(self
.reg_enable_i
),
267 self
.issue_o
.eq(issueunit
.issue_o
)
270 # take these to outside (issue needs them)
271 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
272 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
273 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
274 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
276 # TODO: issueunit.f (FP)
278 # and int function issue / busy arrays, and dest/src1/src2
279 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
280 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
281 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
283 fn_issue_o
= issueunit
.fn_issue_o
285 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
286 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
287 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
290 # merge shadow matrices outputs
293 # these are explained in ShadowMatrix docstring, and are to be
294 # connected to the FUReg and FUFU Matrices, to get them to reset
295 anydie
= Signal(n_intfus
, reset_less
=True)
296 allshadown
= Signal(n_intfus
, reset_less
=True)
297 shreset
= Signal(n_intfus
, reset_less
=True)
298 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
299 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
300 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
303 # connect fu-fu matrix
306 # Group Picker... done manually for now.
307 go_rd_o
= intpick1
.go_rd_o
308 go_wr_o
= intpick1
.go_wr_o
309 go_rd_i
= intfus
.go_rd_i
310 go_wr_i
= intfus
.go_wr_i
311 go_die_i
= intfus
.go_die_i
312 # NOTE: connect to the shadowed versions so that they can "die" (reset)
313 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
314 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
315 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
319 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
320 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
321 int_rd_o
= intfus
.readable_o
322 int_wr_o
= intfus
.writable_o
323 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
324 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
330 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
331 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
332 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
334 # NOTE; this setup is for the instruction order preservation...
336 # connect shadows / go_dies to Computation Units
337 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
338 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
340 # ok connect first n_int_fu shadows to busy lines, to create an
341 # instruction-order linked-list-like arrangement, using a bit-matrix
342 # (instead of e.g. a ring buffer).
345 # when written, the shadow can be cancelled (and was good)
346 for i
in range(n_intfus
):
347 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
349 # *previous* instruction shadows *current* instruction, and, obviously,
350 # if the previous is completed (!busy) don't cast the shadow!
351 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
352 for i
in range(n_intfus
):
353 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
356 # ... and this is for branch speculation. it uses the extra bit
357 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
358 # only needs to set shadow_i, s_fail_i and s_good_i
360 # issue captures shadow_i (if enabled)
361 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
363 bactive
= Signal(reset_less
=True)
364 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
366 # instruction being issued (fn_issue_o) has a shadow cast by the branch
367 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
368 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
369 for i
in range(n_intfus
):
370 with m
.If(fn_issue_o
& (Const(1<<i
))):
371 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
373 # finally, we need an indicator to the test infrastructure as to
374 # whether the branch succeeded or failed, plus, link up to the
375 # "recorder" of whether the instruction was under shadow or not
377 with m
.If(br1
.issue_i
):
378 sync
+= bspec
.active_i
.eq(1)
379 with m
.If(self
.branch_succ_i
):
380 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
381 with m
.If(self
.branch_fail_i
):
382 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
384 # branch is active (TODO: a better signal: this is over-using the
385 # go_write signal - actually the branch should not be "writing")
386 with m
.If(br1
.go_wr_i
):
387 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
388 sync
+= bspec
.active_i
.eq(0)
389 comb
+= bspec
.br_i
.eq(1)
390 # branch occurs if data == 1, failed if data == 0
391 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
392 for i
in range(n_intfus
):
393 # *expected* direction of the branch matched against *actual*
394 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
396 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
399 # Connect Register File(s)
401 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
402 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
403 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
405 # connect ALUs to regfule
406 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
407 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
408 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
410 # connect ALU Computation Units
411 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
412 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
413 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
418 yield from self
.intregs
419 yield from self
.fpregs
420 yield self
.int_dest_i
421 yield self
.int_src1_i
422 yield self
.int_src2_i
424 yield self
.branch_succ_i
425 yield self
.branch_fail_i
426 yield self
.branch_direction_o
434 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
435 yield from disable_issue(dut
)
436 yield dut
.int_dest_i
.eq(dest
)
437 yield dut
.int_src1_i
.eq(src1
)
438 yield dut
.int_src2_i
.eq(src2
)
439 if (op
& (0x3<<2)) != 0: # branch
440 yield dut
.brissue
.insn_i
.eq(1)
441 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
442 yield dut
.br_imm_i
.eq(imm
)
443 dut_issue
= dut
.brissue
445 yield dut
.aluissue
.insn_i
.eq(1)
446 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
447 yield dut
.alu_imm_i
.eq(imm
)
448 dut_issue
= dut
.aluissue
449 yield dut
.reg_enable_i
.eq(1)
451 # these indicate that the instruction is to be made shadow-dependent on
452 # (either) branch success or branch fail
453 yield dut
.branch_fail_i
.eq(branch_fail
)
454 yield dut
.branch_succ_i
.eq(branch_success
)
457 yield from wait_for_issue(dut
, dut_issue
)
460 def print_reg(dut
, rnums
):
463 reg
= yield dut
.intregs
.regs
[rnum
].reg
464 rs
.append("%x" % reg
)
465 rnums
= map(str, rnums
)
466 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
469 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
471 for i
in range(n_ops
):
472 src1
= randint(1, dut
.n_regs
-1)
473 src2
= randint(1, dut
.n_regs
-1)
474 imm
= randint(1, (1<<dut
.rwid
)-1)
475 dest
= randint(1, dut
.n_regs
-1)
476 op
= randint(0, max_opnums
)
477 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
480 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
482 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
487 def scoreboard_sim(dut
, alusim
):
493 # set random values in the registers
494 for i
in range(1, dut
.n_regs
):
495 val
= randint(0, (1<<alusim
.rwidth
)-1)
498 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
499 alusim
.setval(i
, val
)
501 # create some instructions (some random, some regression tests)
504 instrs
= create_random_ops(dut
, 15, True, 4)
507 instrs
.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
510 instrs
.append( (7, 3, 2, 4, (0, 0)) )
511 instrs
.append( (7, 6, 6, 2, (0, 0)) )
512 instrs
.append( (1, 7, 2, 2, (0, 0)) )
515 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
516 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
517 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
518 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
519 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
522 instrs
.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
523 instrs
.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
524 instrs
.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
527 instrs
.append((5, 6, 2, 1))
528 instrs
.append((2, 2, 4, 0))
529 #instrs.append((2, 2, 3, 1))
532 instrs
.append((2, 1, 2, 3))
535 instrs
.append((2, 6, 2, 1))
536 instrs
.append((2, 1, 2, 0))
539 instrs
.append((1, 2, 7, 2))
540 instrs
.append((7, 1, 5, 0))
541 instrs
.append((4, 4, 1, 1))
544 instrs
.append((5, 6, 2, 2))
545 instrs
.append((1, 1, 4, 1))
546 instrs
.append((6, 5, 3, 0))
549 # Write-after-Write Hazard
550 instrs
.append( (3, 6, 7, 2) )
551 instrs
.append( (4, 4, 7, 1) )
554 # self-read/write-after-write followed by Read-after-Write
555 instrs
.append((1, 1, 1, 1))
556 instrs
.append((1, 5, 3, 0))
559 # Read-after-Write followed by self-read-after-write
560 instrs
.append((5, 6, 1, 2))
561 instrs
.append((1, 1, 1, 1))
564 # self-read-write sandwich
565 instrs
.append((5, 6, 1, 2))
566 instrs
.append((1, 1, 1, 1))
567 instrs
.append((1, 5, 3, 0))
571 instrs
.append( (5, 2, 5, 2) )
572 instrs
.append( (2, 6, 3, 0) )
573 instrs
.append( (4, 2, 2, 1) )
577 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
579 yield dut
.intregs
.regs
[3].reg
.eq(5)
581 instrs
.append((5, 3, 3, 4, (0, 0)))
582 instrs
.append((4, 2, 1, 2, (0, 1)))
586 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
588 yield dut
.intregs
.regs
[3].reg
.eq(5)
590 instrs
.append((5, 3, 3, 4, (0, 0)))
591 instrs
.append((4, 2, 1, 2, (1, 0)))
594 instrs
.append( (4, 3, 5, 1, 0, (0, 0)) )
595 instrs
.append( (5, 2, 3, 1, 0, (0, 0)) )
596 instrs
.append( (7, 1, 5, 2, 0, (0, 0)) )
597 instrs
.append( (5, 6, 6, 4, 0, (0, 0)) )
598 instrs
.append( (7, 5, 2, 2, 0, (1, 0)) )
599 instrs
.append( (1, 7, 5, 0, 0, (0, 1)) )
600 instrs
.append( (1, 6, 1, 2, 0, (1, 0)) )
601 instrs
.append( (1, 6, 7, 3, 0, (0, 0)) )
602 instrs
.append( (6, 7, 7, 0, 0, (0, 0)) )
604 # issue instruction(s), wait for issue to be free before proceeding
605 for i
, instr
in enumerate(instrs
):
606 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
608 print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
609 (i
, src1
, src2
, dest
, op
, opi
, imm
))
610 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
611 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
614 # wait for all instructions to stop before checking
616 iqlen
= yield dut
.qlen_o
624 yield from wait_for_busy_clear(dut
)
627 yield from alusim
.check(dut
)
628 yield from alusim
.dump(dut
)
631 def test_scoreboard():
632 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
633 alusim
= RegSim(16, 8)
634 memsim
= MemSim(16, 16)
635 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
636 with
open("test_scoreboard6600.il", "w") as f
:
639 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
640 vcd_name
='test_scoreboard6600.vcd')
642 #run_simulation(dut, scoreboard_branch_sim(dut, alusim),
643 # vcd_name='test_scoreboard6600.vcd')
647 yield dut
.ld_i
.eq(0x1)
648 yield dut
.fn_issue_i
.eq(0x1)
650 #yield dut.ld_i.eq(0x0)
651 yield dut
.st_i
.eq(0x2)
652 yield dut
.fn_issue_i
.eq(0x2)
654 #yield dut.st_i.eq(0x0)
655 yield dut
.fn_issue_i
.eq(0x0)
658 yield dut
.load_hit_i
.eq(0x1)
660 yield dut
.load_hit_i
.eq(0x0)
662 yield dut
.stwd_hit_i
.eq(0x2)
664 yield dut
.stwd_hit_i
.eq(0x0)
669 dut
= MemFunctionUnits(3)
670 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
671 with
open("test_mem_fus.il", "w") as f
:
674 run_simulation(dut
, mem_sim(dut
),
675 vcd_name
='test_mem_fus.vcd')
678 if __name__
== '__main__':