de9715e54b068832acc7eebb62b9ae2e31cc680b
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 PartialAddrMatch
._elaborate
(self
, m
, platform
)
70 FURegDepMatrix
._elaborate
(self
, m
, platform
)
75 class MemFunctionUnits(Elaboratable
):
77 def __init__(self
, n_ldsts
, addrbitwid
):
78 self
.n_ldsts
= n_ldsts
79 self
.bitwid
= addrbitwid
81 self
.st_i
= Signal(n_ldsts
, reset_less
=True) # Dest R# in
82 self
.ld_i
= Signal(n_ldsts
, reset_less
=True) # oper1 R# in
84 self
.g_int_ld_pend_o
= Signal(n_ldsts
, reset_less
=True)
85 self
.g_int_st_pend_o
= Signal(n_ldsts
, reset_less
=True)
87 self
.st_rsel_o
= Signal(n_ldsts
, reset_less
=True) # dest reg (bot)
88 self
.ld_rsel_o
= Signal(n_ldsts
, reset_less
=True) # src1 reg (bot)
90 self
.loadable_o
= Signal(n_ldsts
, reset_less
=True)
91 self
.storable_o
= Signal(n_ldsts
, reset_less
=True)
93 self
.go_ld_i
= Signal(n_ldsts
, reset_less
=True)
94 self
.go_st_i
= Signal(n_ldsts
, reset_less
=True)
95 self
.go_die_i
= Signal(n_ldsts
, reset_less
=True)
96 self
.fn_issue_i
= Signal(n_ldsts
, reset_less
=True)
99 self
.addrs_i
= Array(Signal(self
.bitwid
, name
="addrs_i%d" % i
) \
100 for i
in range(n_ldsts
))
101 self
.addr_we_i
= Signal(n_ldsts
) # write-enable for incoming address
102 self
.addr_en_i
= Signal(n_ldsts
) # address activated (0 == ignore)
104 # Note: FURegs st_pend_o is also outputted from here, for use in WaWGrid
106 def elaborate(self
, platform
):
113 # Integer FU-FU Dep Matrix
114 intfudeps
= FUFUDepMatrix(n_fus
, n_fus
)
115 m
.submodules
.intfudeps
= intfudeps
116 # Integer FU-Reg Dep Matrix
117 intregdeps
= FUMemMatchMatrix(n_fus
, self
.bitwid
)
118 m
.submodules
.intregdeps
= intregdeps
120 # ok, because we do not know in advance what the AGEN (address gen)
121 # is, we have to make a transitive dependency set. i.e. the LD
122 # (or ST) being requested now must depend on ALL prior LDs *AND* STs.
123 # these get dropped very rapidly once AGEN is carried out.
126 # connect fureg matrix as a mem system
127 comb
+= self
.g_int_ld_pend_o
.eq(intregdeps
.v_rd_rsel_o
)
128 comb
+= self
.g_int_st_pend_o
.eq(intregdeps
.v_wr_rsel_o
)
130 comb
+= intregdeps
.rd_pend_i
.eq(intregdeps
.v_rd_rsel_o
)
131 comb
+= intregdeps
.wr_pend_i
.eq(intregdeps
.v_wr_rsel_o
)
133 comb
+= intfudeps
.rd_pend_i
.eq(intregdeps
.rd_pend_o
)
134 comb
+= intfudeps
.wr_pend_i
.eq(intregdeps
.wr_pend_o
)
135 self
.st_pend_o
= intregdeps
.wr_pend_o
# also output for use in WaWGrid
137 comb
+= intfudeps
.issue_i
.eq(self
.fn_issue_i
)
138 comb
+= intfudeps
.go_rd_i
.eq(self
.go_ld_i
)
139 comb
+= intfudeps
.go_wr_i
.eq(self
.go_st_i
)
140 comb
+= intfudeps
.go_die_i
.eq(self
.go_die_i
)
141 comb
+= self
.loadable_o
.eq(intfudeps
.readable_o
)
142 comb
+= self
.storable_o
.eq(intfudeps
.writable_o
)
144 # Connect function issue / arrays, and dest/src1/src2
145 comb
+= intregdeps
.dest_i
.eq(self
.st_i
)
146 comb
+= intregdeps
.src_i
[0].eq(self
.ld_i
)
148 comb
+= intregdeps
.go_rd_i
.eq(self
.go_ld_i
)
149 comb
+= intregdeps
.go_wr_i
.eq(self
.go_st_i
)
150 comb
+= intregdeps
.go_die_i
.eq(self
.go_die_i
)
151 comb
+= intregdeps
.issue_i
.eq(self
.fn_issue_i
)
153 comb
+= self
.st_rsel_o
.eq(intregdeps
.dest_rsel_o
)
154 comb
+= self
.ld_rsel_o
.eq(intregdeps
.src_rsel_o
[0])
156 # connect address matching: these get connected to the Addr CUs
157 for i
in range(self
.n_ldsts
):
158 comb
+= intregdeps
.addrs_i
[i
].eq(self
.addrs_i
[i
])
159 comb
+= intregdeps
.addr_we_i
.eq(self
.addr_we_i
)
160 comb
+= intregdeps
.addr_en_i
.eq(self
.addr_en_i
)
167 yield self
.g_int_st_pend_o
168 yield self
.g_int_ld_pend_o
171 yield self
.loadable_o
172 yield self
.storable_o
176 yield self
.fn_issue_i
177 yield from self
.addrs_i
185 class Scoreboard(Elaboratable
):
186 def __init__(self
, rwid
, n_regs
):
189 * :rwid: bit width of register file(s) - both FP and INT
190 * :n_regs: depth of register file(s) - number of FP and INT regs
196 self
.intregs
= RegFileArray(rwid
, n_regs
)
197 self
.fpregs
= RegFileArray(rwid
, n_regs
)
199 # issue q needs to get at these
200 self
.aluissue
= IssueUnitGroup(4)
201 self
.brissue
= IssueUnitGroup(1)
203 self
.alu_oper_i
= Signal(4, reset_less
=True)
204 self
.alu_imm_i
= Signal(rwid
, reset_less
=True)
205 self
.br_oper_i
= Signal(4, reset_less
=True)
206 self
.br_imm_i
= Signal(rwid
, reset_less
=True)
209 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
210 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
211 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
212 self
.reg_enable_i
= Signal(reset_less
=True) # enable reg decode
215 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
216 self
.busy_o
= Signal(reset_less
=True) # at least one CU is busy
218 # for branch speculation experiment. branch_direction = 0 if
219 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
220 # branch_succ and branch_fail are requests to have the current
221 # instruction be dependent on the branch unit "shadow" capability.
222 self
.branch_succ_i
= Signal(reset_less
=True)
223 self
.branch_fail_i
= Signal(reset_less
=True)
224 self
.branch_direction_o
= Signal(2, reset_less
=True)
226 def elaborate(self
, platform
):
231 m
.submodules
.intregs
= self
.intregs
232 m
.submodules
.fpregs
= self
.fpregs
235 int_dest
= self
.intregs
.write_port("dest")
236 int_src1
= self
.intregs
.read_port("src1")
237 int_src2
= self
.intregs
.read_port("src2")
239 fp_dest
= self
.fpregs
.write_port("dest")
240 fp_src1
= self
.fpregs
.read_port("src1")
241 fp_src2
= self
.fpregs
.read_port("src2")
243 # Int ALUs and Comp Units
245 cua
= CompUnitALUs(self
.rwid
, 3)
246 cub
= CompUnitBR(self
.rwid
, 3)
247 m
.submodules
.cu
= cu
= CompUnitsBase(self
.rwid
, [cua
, cub
])
248 bgt
= cub
.bgt
# get at the branch computation unit
252 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
254 # Count of number of FUs
255 n_intfus
= n_int_alus
256 n_fp_fus
= 0 # for now
258 # Integer Priority Picker 1: Adder + Subtractor
259 intpick1
= GroupPicker(n_intfus
) # picks between add, sub, mul and shf
260 m
.submodules
.intpick1
= intpick1
263 regdecode
= RegDecode(self
.n_regs
)
264 m
.submodules
.regdecode
= regdecode
265 issueunit
= IssueUnitArray([self
.aluissue
, self
.brissue
])
266 m
.submodules
.issueunit
= issueunit
268 # Shadow Matrix. currently n_intfus shadows, to be used for
269 # write-after-write hazards. NOTE: there is one extra for branches,
270 # so the shadow width is increased by 1
271 m
.submodules
.shadows
= shadows
= ShadowMatrix(n_intfus
, n_intfus
, True)
272 m
.submodules
.bshadow
= bshadow
= ShadowMatrix(n_intfus
, 1, False)
274 # record previous instruction to cast shadow on current instruction
275 prev_shadow
= Signal(n_intfus
)
277 # Branch Speculation recorder. tracks the success/fail state as
278 # each instruction is issued, so that when the branch occurs the
279 # allow/cancel can be issued as appropriate.
280 m
.submodules
.specrec
= bspec
= BranchSpeculationRecord(n_intfus
)
283 # ok start wiring things together...
284 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
285 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
289 # Issue Unit is where it starts. set up some in/outs for this module
291 comb
+= [ regdecode
.dest_i
.eq(self
.int_dest_i
),
292 regdecode
.src1_i
.eq(self
.int_src1_i
),
293 regdecode
.src2_i
.eq(self
.int_src2_i
),
294 regdecode
.enable_i
.eq(self
.reg_enable_i
),
295 self
.issue_o
.eq(issueunit
.issue_o
)
298 # take these to outside (issue needs them)
299 comb
+= cua
.oper_i
.eq(self
.alu_oper_i
)
300 comb
+= cua
.imm_i
.eq(self
.alu_imm_i
)
301 comb
+= cub
.oper_i
.eq(self
.br_oper_i
)
302 comb
+= cub
.imm_i
.eq(self
.br_imm_i
)
304 # TODO: issueunit.f (FP)
306 # and int function issue / busy arrays, and dest/src1/src2
307 comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
308 comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
309 comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
311 fn_issue_o
= issueunit
.fn_issue_o
313 comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
314 comb
+= issueunit
.busy_i
.eq(cu
.busy_o
)
315 comb
+= self
.busy_o
.eq(cu
.busy_o
.bool())
318 # merge shadow matrices outputs
321 # these are explained in ShadowMatrix docstring, and are to be
322 # connected to the FUReg and FUFU Matrices, to get them to reset
323 anydie
= Signal(n_intfus
, reset_less
=True)
324 allshadown
= Signal(n_intfus
, reset_less
=True)
325 shreset
= Signal(n_intfus
, reset_less
=True)
326 comb
+= allshadown
.eq(shadows
.shadown_o
& bshadow
.shadown_o
)
327 comb
+= anydie
.eq(shadows
.go_die_o | bshadow
.go_die_o
)
328 comb
+= shreset
.eq(bspec
.match_g_o | bspec
.match_f_o
)
331 # connect fu-fu matrix
334 # Group Picker... done manually for now.
335 go_rd_o
= intpick1
.go_rd_o
336 go_wr_o
= intpick1
.go_wr_o
337 go_rd_i
= intfus
.go_rd_i
338 go_wr_i
= intfus
.go_wr_i
339 go_die_i
= intfus
.go_die_i
340 # NOTE: connect to the shadowed versions so that they can "die" (reset)
341 comb
+= go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
]) # rd
342 comb
+= go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
]) # wr
343 comb
+= go_die_i
[0:n_intfus
].eq(anydie
[0:n_intfus
]) # die
347 comb
+= intpick1
.rd_rel_i
[0:n_intfus
].eq(cu
.rd_rel_o
[0:n_intfus
])
348 comb
+= intpick1
.req_rel_i
[0:n_intfus
].eq(cu
.req_rel_o
[0:n_intfus
])
349 int_rd_o
= intfus
.readable_o
350 int_wr_o
= intfus
.writable_o
351 comb
+= intpick1
.readable_i
[0:n_intfus
].eq(int_rd_o
[0:n_intfus
])
352 comb
+= intpick1
.writable_i
[0:n_intfus
].eq(int_wr_o
[0:n_intfus
])
358 comb
+= shadows
.issue_i
.eq(fn_issue_o
)
359 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
360 comb
+= shadows
.reset_i
[0:n_intfus
].eq(bshadow
.go_die_o
[0:n_intfus
])
362 # NOTE; this setup is for the instruction order preservation...
364 # connect shadows / go_dies to Computation Units
365 comb
+= cu
.shadown_i
[0:n_intfus
].eq(allshadown
)
366 comb
+= cu
.go_die_i
[0:n_intfus
].eq(anydie
)
368 # ok connect first n_int_fu shadows to busy lines, to create an
369 # instruction-order linked-list-like arrangement, using a bit-matrix
370 # (instead of e.g. a ring buffer).
373 # when written, the shadow can be cancelled (and was good)
374 for i
in range(n_intfus
):
375 comb
+= shadows
.s_good_i
[i
][0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
377 # *previous* instruction shadows *current* instruction, and, obviously,
378 # if the previous is completed (!busy) don't cast the shadow!
379 comb
+= prev_shadow
.eq(~fn_issue_o
& cu
.busy_o
)
380 for i
in range(n_intfus
):
381 comb
+= shadows
.shadow_i
[i
][0:n_intfus
].eq(prev_shadow
)
384 # ... and this is for branch speculation. it uses the extra bit
385 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
386 # only needs to set shadow_i, s_fail_i and s_good_i
388 # issue captures shadow_i (if enabled)
389 comb
+= bshadow
.reset_i
[0:n_intfus
].eq(shreset
[0:n_intfus
])
391 bactive
= Signal(reset_less
=True)
392 comb
+= bactive
.eq((bspec
.active_i | br1
.issue_i
) & ~br1
.go_wr_i
)
394 # instruction being issued (fn_issue_o) has a shadow cast by the branch
395 with m
.If(bactive
& (self
.branch_succ_i | self
.branch_fail_i
)):
396 comb
+= bshadow
.issue_i
.eq(fn_issue_o
)
397 for i
in range(n_intfus
):
398 with m
.If(fn_issue_o
& (Const(1<<i
))):
399 comb
+= bshadow
.shadow_i
[i
][0].eq(1)
401 # finally, we need an indicator to the test infrastructure as to
402 # whether the branch succeeded or failed, plus, link up to the
403 # "recorder" of whether the instruction was under shadow or not
405 with m
.If(br1
.issue_i
):
406 sync
+= bspec
.active_i
.eq(1)
407 with m
.If(self
.branch_succ_i
):
408 comb
+= bspec
.good_i
.eq(fn_issue_o
& 0x1f)
409 with m
.If(self
.branch_fail_i
):
410 comb
+= bspec
.fail_i
.eq(fn_issue_o
& 0x1f)
412 # branch is active (TODO: a better signal: this is over-using the
413 # go_write signal - actually the branch should not be "writing")
414 with m
.If(br1
.go_wr_i
):
415 sync
+= self
.branch_direction_o
.eq(br1
.data_o
+Const(1, 2))
416 sync
+= bspec
.active_i
.eq(0)
417 comb
+= bspec
.br_i
.eq(1)
418 # branch occurs if data == 1, failed if data == 0
419 comb
+= bspec
.br_ok_i
.eq(br1
.data_o
== 1)
420 for i
in range(n_intfus
):
421 # *expected* direction of the branch matched against *actual*
422 comb
+= bshadow
.s_good_i
[i
][0].eq(bspec
.match_g_o
[i
])
424 comb
+= bshadow
.s_fail_i
[i
][0].eq(bspec
.match_f_o
[i
])
427 # Connect Register File(s)
429 comb
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
430 comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
431 comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
433 # connect ALUs to regfule
434 comb
+= int_dest
.data_i
.eq(cu
.data_o
)
435 comb
+= cu
.src1_i
.eq(int_src1
.data_o
)
436 comb
+= cu
.src2_i
.eq(int_src2
.data_o
)
438 # connect ALU Computation Units
439 comb
+= cu
.go_rd_i
[0:n_intfus
].eq(go_rd_o
[0:n_intfus
])
440 comb
+= cu
.go_wr_i
[0:n_intfus
].eq(go_wr_o
[0:n_intfus
])
441 comb
+= cu
.issue_i
[0:n_intfus
].eq(fn_issue_o
[0:n_intfus
])
446 yield from self
.intregs
447 yield from self
.fpregs
448 yield self
.int_dest_i
449 yield self
.int_src1_i
450 yield self
.int_src2_i
452 yield self
.branch_succ_i
453 yield self
.branch_fail_i
454 yield self
.branch_direction_o
462 def int_instr(dut
, op
, imm
, src1
, src2
, dest
, branch_success
, branch_fail
):
463 yield from disable_issue(dut
)
464 yield dut
.int_dest_i
.eq(dest
)
465 yield dut
.int_src1_i
.eq(src1
)
466 yield dut
.int_src2_i
.eq(src2
)
467 if (op
& (0x3<<2)) != 0: # branch
468 yield dut
.brissue
.insn_i
.eq(1)
469 yield dut
.br_oper_i
.eq(Const(op
& 0x3, 2))
470 yield dut
.br_imm_i
.eq(imm
)
471 dut_issue
= dut
.brissue
473 yield dut
.aluissue
.insn_i
.eq(1)
474 yield dut
.alu_oper_i
.eq(Const(op
& 0x3, 2))
475 yield dut
.alu_imm_i
.eq(imm
)
476 dut_issue
= dut
.aluissue
477 yield dut
.reg_enable_i
.eq(1)
479 # these indicate that the instruction is to be made shadow-dependent on
480 # (either) branch success or branch fail
481 yield dut
.branch_fail_i
.eq(branch_fail
)
482 yield dut
.branch_succ_i
.eq(branch_success
)
485 yield from wait_for_issue(dut
, dut_issue
)
488 def print_reg(dut
, rnums
):
491 reg
= yield dut
.intregs
.regs
[rnum
].reg
492 rs
.append("%x" % reg
)
493 rnums
= map(str, rnums
)
494 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
497 def create_random_ops(dut
, n_ops
, shadowing
=False, max_opnums
=3):
499 for i
in range(n_ops
):
500 src1
= randint(1, dut
.n_regs
-1)
501 src2
= randint(1, dut
.n_regs
-1)
502 imm
= randint(1, (1<<dut
.rwid
)-1)
503 dest
= randint(1, dut
.n_regs
-1)
504 op
= randint(0, max_opnums
)
505 opi
= 0 if randint(0, 2) else 1 # set true if random is nonzero
508 insts
.append((src1
, src2
, dest
, op
, opi
, imm
, (0, 0)))
510 insts
.append((src1
, src2
, dest
, op
, opi
, imm
))
515 def scoreboard_sim(dut
, alusim
):
521 # set random values in the registers
522 for i
in range(1, dut
.n_regs
):
523 val
= randint(0, (1<<alusim
.rwidth
)-1)
526 yield dut
.intregs
.regs
[i
].reg
.eq(val
)
527 alusim
.setval(i
, val
)
529 # create some instructions (some random, some regression tests)
532 instrs
= create_random_ops(dut
, 15, True, 4)
535 instrs
.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
538 instrs
.append( (7, 3, 2, 4, (0, 0)) )
539 instrs
.append( (7, 6, 6, 2, (0, 0)) )
540 instrs
.append( (1, 7, 2, 2, (0, 0)) )
543 instrs
.append((2, 3, 3, 0, 0, 0, (0, 0)))
544 instrs
.append((5, 3, 3, 1, 0, 0, (0, 0)))
545 instrs
.append((3, 5, 5, 2, 0, 0, (0, 0)))
546 instrs
.append((5, 3, 3, 3, 0, 0, (0, 0)))
547 instrs
.append((3, 5, 5, 0, 0, 0, (0, 0)))
550 instrs
.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
551 instrs
.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
552 instrs
.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
555 instrs
.append((5, 6, 2, 1))
556 instrs
.append((2, 2, 4, 0))
557 #instrs.append((2, 2, 3, 1))
560 instrs
.append((2, 1, 2, 3))
563 instrs
.append((2, 6, 2, 1))
564 instrs
.append((2, 1, 2, 0))
567 instrs
.append((1, 2, 7, 2))
568 instrs
.append((7, 1, 5, 0))
569 instrs
.append((4, 4, 1, 1))
572 instrs
.append((5, 6, 2, 2))
573 instrs
.append((1, 1, 4, 1))
574 instrs
.append((6, 5, 3, 0))
577 # Write-after-Write Hazard
578 instrs
.append( (3, 6, 7, 2) )
579 instrs
.append( (4, 4, 7, 1) )
582 # self-read/write-after-write followed by Read-after-Write
583 instrs
.append((1, 1, 1, 1))
584 instrs
.append((1, 5, 3, 0))
587 # Read-after-Write followed by self-read-after-write
588 instrs
.append((5, 6, 1, 2))
589 instrs
.append((1, 1, 1, 1))
592 # self-read-write sandwich
593 instrs
.append((5, 6, 1, 2))
594 instrs
.append((1, 1, 1, 1))
595 instrs
.append((1, 5, 3, 0))
599 instrs
.append( (5, 2, 5, 2) )
600 instrs
.append( (2, 6, 3, 0) )
601 instrs
.append( (4, 2, 2, 1) )
605 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
607 yield dut
.intregs
.regs
[3].reg
.eq(5)
609 instrs
.append((5, 3, 3, 4, (0, 0)))
610 instrs
.append((4, 2, 1, 2, (0, 1)))
614 yield dut
.intregs
.regs
[5].reg
.eq(v1
)
616 yield dut
.intregs
.regs
[3].reg
.eq(5)
618 instrs
.append((5, 3, 3, 4, (0, 0)))
619 instrs
.append((4, 2, 1, 2, (1, 0)))
622 instrs
.append( (4, 3, 5, 1, 0, (0, 0)) )
623 instrs
.append( (5, 2, 3, 1, 0, (0, 0)) )
624 instrs
.append( (7, 1, 5, 2, 0, (0, 0)) )
625 instrs
.append( (5, 6, 6, 4, 0, (0, 0)) )
626 instrs
.append( (7, 5, 2, 2, 0, (1, 0)) )
627 instrs
.append( (1, 7, 5, 0, 0, (0, 1)) )
628 instrs
.append( (1, 6, 1, 2, 0, (1, 0)) )
629 instrs
.append( (1, 6, 7, 3, 0, (0, 0)) )
630 instrs
.append( (6, 7, 7, 0, 0, (0, 0)) )
632 # issue instruction(s), wait for issue to be free before proceeding
633 for i
, instr
in enumerate(instrs
):
634 src1
, src2
, dest
, op
, opi
, imm
, (br_ok
, br_fail
) = instr
636 print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
637 (i
, src1
, src2
, dest
, op
, opi
, imm
))
638 alusim
.op(op
, opi
, imm
, src1
, src2
, dest
)
639 yield from instr_q(dut
, op
, opi
, imm
, src1
, src2
, dest
,
642 # wait for all instructions to stop before checking
644 iqlen
= yield dut
.qlen_o
652 yield from wait_for_busy_clear(dut
)
655 yield from alusim
.check(dut
)
656 yield from alusim
.dump(dut
)
659 def test_scoreboard():
660 dut
= IssueToScoreboard(2, 1, 1, 16, 8, 8)
661 alusim
= RegSim(16, 8)
662 memsim
= MemSim(16, 16)
663 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
664 with
open("test_scoreboard6600.il", "w") as f
:
667 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
668 vcd_name
='test_scoreboard6600.vcd')
670 #run_simulation(dut, scoreboard_branch_sim(dut, alusim),
671 # vcd_name='test_scoreboard6600.vcd')
675 yield dut
.ld_i
.eq(0x1)
676 yield dut
.fn_issue_i
.eq(0x1)
678 yield dut
.ld_i
.eq(0x0)
679 yield dut
.st_i
.eq(0x3)
680 yield dut
.fn_issue_i
.eq(0x2)
682 yield dut
.st_i
.eq(0x0)
683 yield dut
.fn_issue_i
.eq(0x0)
686 yield dut
.addrs_i
[0].eq(0x012)
687 yield dut
.addrs_i
[1].eq(0x012)
688 yield dut
.addrs_i
[2].eq(0x010)
689 yield dut
.addr_en_i
.eq(0x3)
691 yield dut
.addr_we_i
.eq(0x3)
693 yield dut
.go_ld_i
.eq(0x1)
695 yield dut
.go_ld_i
.eq(0x0)
697 yield dut
.go_st_i
.eq(0x2)
699 yield dut
.go_st_i
.eq(0x0)
704 dut
= MemFunctionUnits(3, 11)
705 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
706 with
open("test_mem_fus.il", "w") as f
:
709 run_simulation(dut
, mem_sim(dut
),
710 vcd_name
='test_mem_fus.vcd')
713 if __name__
== '__main__':