move scoreboard multi rd/wr to new folder
[soc.git] / src / soc / scoreboard / test_mem_fu_matrix.py
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
4
5 from soc.regfile.regfile import RegFileArray, treereduce
6 from soc.scoreboard.ldst_matrix import LDSTDepMatrix
7 from soc.scoreboard.fu_mem_matrix import FUMemDepMatrix
8 from soc.scoreboard.global_pending import GlobalPending
9 from soc.scoreboard.group_picker import GroupPicker
10 from soc.scoreboard.issue_unit import IssueUnitGroup, IssueUnitArray, RegDecode
11 from soc.scoreboard.shadow import ShadowMatrix, BranchSpeculationRecord
12
13
14 from nmutil.latch import SRLatch
15 from nmutil.nmoperator import eq
16
17 from random import randint, seed
18 from copy import deepcopy
19 from math import log
20
21 # FIXME: fixed up imports
22 from ..experiment.score6600 import IssueToScoreboard, RegSim, instr_q, wait_for_busy_clear, wait_for_issue, CompUnitALUs, CompUnitBR
23
24
25 class Memory(Elaboratable):
26 def __init__(self, regwid, addrw):
27 self.ddepth = regwid/8
28 depth = (1 << addrw) / self.ddepth
29 self.adr = Signal(addrw)
30 self.dat_r = Signal(regwid)
31 self.dat_w = Signal(regwid)
32 self.we = Signal()
33 self.mem = Memory(width=regwid, depth=depth, init=range(0, depth))
34
35 def elaborate(self, platform):
36 m = Module()
37 m.submodules.rdport = rdport = self.mem.read_port()
38 m.submodules.wrport = wrport = self.mem.write_port()
39 m.d.comb += [
40 rdport.addr.eq(self.adr[self.ddepth:]), # ignore low bits
41 self.dat_r.eq(rdport.data),
42 wrport.addr.eq(self.adr),
43 wrport.data.eq(self.dat_w),
44 wrport.en.eq(self.we),
45 ]
46 return m
47
48
49 class MemSim:
50 def __init__(self, regwid, addrw):
51 self.regwid = regwid
52 self.ddepth = regwid//8
53 depth = (1 << addrw) // self.ddepth
54 self.mem = list(range(0, depth))
55
56 def ld(self, addr):
57 return self.mem[addr >> self.ddepth]
58
59 def st(self, addr, data):
60 self.mem[addr >> self.ddepth] = data & ((1 << self.regwid)-1)
61
62
63 class MemFunctionUnits(Elaboratable):
64
65 def __init__(self, n_int_alus):
66 self.n_int_alus = n_int_alus
67
68 self.ld_i = Signal(n_int_alus, reset_less=True) # Dest R# in
69 self.st_i = Signal(n_int_alus, reset_less=True) # oper1 R# in
70
71 self.load_hit_i = Signal(n_int_alus, reset_less=True) # Load Hit
72 self.stwd_hit_i = Signal(n_int_alus, reset_less=True) # Store Hit
73
74 #self.g_int_st_pend_o = Signal(n_int_alus, reset_less=True)
75 #self.g_int_ld_pend_o = Signal(n_int_alus, reset_less=True)
76
77 # self.ld_rsel_o = Signal(n_int_alus, reset_less=True) # dest reg (bot)
78 # self.st_rsel_o = Signal(n_int_alus, reset_less=True) # src1 reg (bot)
79
80 self.req_rel_i = Signal(n_int_alus, reset_less=True)
81 self.loadable_o = Signal(n_int_alus, reset_less=True)
82 self.storable_o = Signal(n_int_alus, reset_less=True)
83
84 self.go_st_i = Signal(n_int_alus, reset_less=True)
85 self.go_ld_i = Signal(n_int_alus, reset_less=True)
86 self.go_die_i = Signal(n_int_alus, reset_less=True)
87 self.req_rel_o = Signal(n_int_alus, reset_less=True)
88 self.fn_issue_i = Signal(n_int_alus, reset_less=True)
89
90 # Note: FURegs ld_pend_o is also outputted from here, for use in WaWGrid
91
92 def elaborate(self, platform):
93 m = Module()
94 comb = m.d.comb
95 sync = m.d.sync
96
97 n_intfus = self.n_int_alus
98
99 # Integer LD/ST Dep Matrix
100 ldstdeps = LDSTDepMatrix(n_intfus)
101 m.submodules.ldstdeps = ldstdeps
102 # Integer FU-Mem Dep Matrix
103 fumemdeps = FUMemDepMatrix(n_intfus, n_intfus)
104 m.submodules.fumemdeps = fumemdeps
105
106 #comb += self.g_int_st_pend_o.eq(fumemdeps.v_st_rsel_o)
107 #comb += self.g_int_ld_pend_o.eq(fumemdeps.v_ld_rsel_o)
108
109 #comb += fumemdeps.st_pend_i.eq(fumemdeps.v_st_rsel_o)
110 #comb += fumemdeps.ld_pend_i.eq(fumemdeps.v_ld_rsel_o)
111
112 #comb += ldstdeps.st_pend_i.eq(fumemdeps.st_pend_o)
113 #comb += ldstdeps.ld_pend_i.eq(fumemdeps.ld_pend_o)
114 # self.ld_pend_o = fumemdeps.ld_pend_o # also output for use in WaWGrid
115
116 comb += ldstdeps.ld_pend_i.eq(self.ld_i)
117 comb += ldstdeps.st_pend_i.eq(self.st_i)
118 comb += ldstdeps.issue_i.eq(self.fn_issue_i)
119 comb += ldstdeps.load_hit_i.eq(self.load_hit_i)
120 comb += ldstdeps.stwd_hit_i.eq(self.stwd_hit_i)
121 comb += ldstdeps.go_die_i.eq(self.go_die_i)
122 comb += self.storable_o.eq(fumemdeps.storable_o)
123 comb += self.loadable_o.eq(fumemdeps.loadable_o)
124 comb += fumemdeps.ld_pend_i.eq(ldstdeps.ld_hold_st_o)
125 comb += fumemdeps.st_pend_i.eq(ldstdeps.st_hold_ld_o)
126
127 # Connect function issue / arrays, and dest/src1/src2
128
129 comb += fumemdeps.go_st_i.eq(self.stwd_hit_i)
130 comb += fumemdeps.go_ld_i.eq(self.load_hit_i)
131 comb += fumemdeps.go_die_i.eq(self.go_die_i)
132 comb += fumemdeps.issue_i.eq(self.fn_issue_i)
133
134 #comb += self.ld_rsel_o.eq(fumemdeps.ld_rsel_o)
135 #comb += self.st_rsel_o.eq(fumemdeps.st_rsel_o)
136
137 return m
138
139 def __iter__(self):
140 yield self.ld_i
141 yield self.st_i
142 # yield self.g_int_st_pend_o
143 # yield self.g_int_ld_pend_o
144 # yield self.ld_rsel_o
145 # yield self.st_rsel_o
146 yield self.req_rel_i
147 yield self.loadable_o
148 yield self.storable_o
149 yield self.load_hit_i
150 yield self.stwd_hit_i
151 yield self.go_st_i
152 yield self.go_ld_i
153 yield self.go_die_i
154 yield self.req_rel_o
155 yield self.fn_issue_i
156
157 def ports(self):
158 return list(self)
159
160
161 class Scoreboard(Elaboratable):
162 def __init__(self, rwid, n_regs):
163 """ Inputs:
164
165 * :rwid: bit width of register file(s) - both FP and INT
166 * :n_regs: depth of register file(s) - number of FP and INT regs
167 """
168 self.rwid = rwid
169 self.n_regs = n_regs
170
171 # Register Files
172 self.intregs = RegFileArray(rwid, n_regs)
173 self.fpregs = RegFileArray(rwid, n_regs)
174
175 # issue q needs to get at these
176 self.aluissue = IssueUnitGroup(4)
177 self.brissue = IssueUnitGroup(1)
178 # and these
179 self.alu_oper_i = Signal(4, reset_less=True)
180 self.alu_imm_i = Signal(rwid, reset_less=True)
181 self.br_oper_i = Signal(4, reset_less=True)
182 self.br_imm_i = Signal(rwid, reset_less=True)
183
184 # inputs
185 self.int_dest_i = Signal(range(n_regs), reset_less=True) # Dest R# in
186 self.int_src1_i = Signal(range(n_regs), reset_less=True) # oper1 R# in
187 self.int_src2_i = Signal(range(n_regs), reset_less=True) # oper2 R# in
188 self.reg_enable_i = Signal(reset_less=True) # enable reg decode
189
190 # outputs
191 self.issue_o = Signal(reset_less=True) # instruction was accepted
192 self.busy_o = Signal(reset_less=True) # at least one CU is busy
193
194 # for branch speculation experiment. branch_direction = 0 if
195 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
196 # branch_succ and branch_fail are requests to have the current
197 # instruction be dependent on the branch unit "shadow" capability.
198 self.branch_succ_i = Signal(reset_less=True)
199 self.branch_fail_i = Signal(reset_less=True)
200 self.branch_direction_o = Signal(2, reset_less=True)
201
202 def elaborate(self, platform):
203 m = Module()
204 comb = m.d.comb
205 sync = m.d.sync
206
207 m.submodules.intregs = self.intregs
208 m.submodules.fpregs = self.fpregs
209
210 # register ports
211 int_dest = self.intregs.write_port("dest")
212 int_src1 = self.intregs.read_port("src1")
213 int_src2 = self.intregs.read_port("src2")
214
215 fp_dest = self.fpregs.write_port("dest")
216 fp_src1 = self.fpregs.read_port("src1")
217 fp_src2 = self.fpregs.read_port("src2")
218
219 # Int ALUs and Comp Units
220 n_int_alus = 5
221 cua = CompUnitALUs(self.rwid, 3)
222 cub = CompUnitBR(self.rwid, 3)
223 m.submodules.cu = cu = CompUnitsBase(self.rwid, [cua, cub])
224 bgt = cub.bgt # get at the branch computation unit
225 br1 = cub.br1
226
227 # Int FUs
228 m.submodules.intfus = intfus = FunctionUnits(self.n_regs, n_int_alus)
229
230 # Count of number of FUs
231 n_intfus = n_int_alus
232 n_fp_fus = 0 # for now
233
234 # Integer Priority Picker 1: Adder + Subtractor
235 intpick1 = GroupPicker(n_intfus) # picks between add, sub, mul and shf
236 m.submodules.intpick1 = intpick1
237
238 # INT/FP Issue Unit
239 regdecode = RegDecode(self.n_regs)
240 m.submodules.regdecode = regdecode
241 issueunit = IssueUnitArray([self.aluissue, self.brissue])
242 m.submodules.issueunit = issueunit
243
244 # Shadow Matrix. currently n_intfus shadows, to be used for
245 # write-after-write hazards. NOTE: there is one extra for branches,
246 # so the shadow width is increased by 1
247 m.submodules.shadows = shadows = ShadowMatrix(n_intfus, n_intfus, True)
248 m.submodules.bshadow = bshadow = ShadowMatrix(n_intfus, 1, False)
249
250 # record previous instruction to cast shadow on current instruction
251 prev_shadow = Signal(n_intfus)
252
253 # Branch Speculation recorder. tracks the success/fail state as
254 # each instruction is issued, so that when the branch occurs the
255 # allow/cancel can be issued as appropriate.
256 m.submodules.specrec = bspec = BranchSpeculationRecord(n_intfus)
257
258 # ---------
259 # ok start wiring things together...
260 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
261 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
262 # ---------
263
264 # ---------
265 # Issue Unit is where it starts. set up some in/outs for this module
266 # ---------
267 comb += [regdecode.dest_i.eq(self.int_dest_i),
268 regdecode.src1_i.eq(self.int_src1_i),
269 regdecode.src2_i.eq(self.int_src2_i),
270 regdecode.enable_i.eq(self.reg_enable_i),
271 self.issue_o.eq(issueunit.issue_o)
272 ]
273
274 # take these to outside (issue needs them)
275 comb += cua.oper_i.eq(self.alu_oper_i)
276 comb += cua.imm_i.eq(self.alu_imm_i)
277 comb += cub.oper_i.eq(self.br_oper_i)
278 comb += cub.imm_i.eq(self.br_imm_i)
279
280 # TODO: issueunit.f (FP)
281
282 # and int function issue / busy arrays, and dest/src1/src2
283 comb += intfus.dest_i.eq(regdecode.dest_o)
284 comb += intfus.src1_i.eq(regdecode.src1_o)
285 comb += intfus.src2_i.eq(regdecode.src2_o)
286
287 fn_issue_o = issueunit.fn_issue_o
288
289 comb += intfus.fn_issue_i.eq(fn_issue_o)
290 comb += issueunit.busy_i.eq(cu.busy_o)
291 comb += self.busy_o.eq(cu.busy_o.bool())
292
293 # ---------
294 # merge shadow matrices outputs
295 # ---------
296
297 # these are explained in ShadowMatrix docstring, and are to be
298 # connected to the FUReg and FUFU Matrices, to get them to reset
299 anydie = Signal(n_intfus, reset_less=True)
300 allshadown = Signal(n_intfus, reset_less=True)
301 shreset = Signal(n_intfus, reset_less=True)
302 comb += allshadown.eq(shadows.shadown_o & bshadow.shadown_o)
303 comb += anydie.eq(shadows.go_die_o | bshadow.go_die_o)
304 comb += shreset.eq(bspec.match_g_o | bspec.match_f_o)
305
306 # ---------
307 # connect fu-fu matrix
308 # ---------
309
310 # Group Picker... done manually for now.
311 go_rd_o = intpick1.go_rd_o
312 go_wr_o = intpick1.go_wr_o
313 go_rd_i = intfus.go_rd_i
314 go_wr_i = intfus.go_wr_i
315 go_die_i = intfus.go_die_i
316 # NOTE: connect to the shadowed versions so that they can "die" (reset)
317 comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd
318 comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr
319 comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die
320
321 # Connect Picker
322 # ---------
323 comb += intpick1.rd_rel_i[0:n_intfus].eq(cu.rd_rel_o[0:n_intfus])
324 comb += intpick1.req_rel_i[0:n_intfus].eq(cu.req_rel_o[0:n_intfus])
325 int_rd_o = intfus.readable_o
326 int_wr_o = intfus.writable_o
327 comb += intpick1.readable_i[0:n_intfus].eq(int_rd_o[0:n_intfus])
328 comb += intpick1.writable_i[0:n_intfus].eq(int_wr_o[0:n_intfus])
329
330 # ---------
331 # Shadow Matrix
332 # ---------
333
334 comb += shadows.issue_i.eq(fn_issue_o)
335 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
336 comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
337 # ---------
338 # NOTE; this setup is for the instruction order preservation...
339
340 # connect shadows / go_dies to Computation Units
341 comb += cu.shadown_i[0:n_intfus].eq(allshadown)
342 comb += cu.go_die_i[0:n_intfus].eq(anydie)
343
344 # ok connect first n_int_fu shadows to busy lines, to create an
345 # instruction-order linked-list-like arrangement, using a bit-matrix
346 # (instead of e.g. a ring buffer).
347 # XXX TODO
348
349 # when written, the shadow can be cancelled (and was good)
350 for i in range(n_intfus):
351 comb += shadows.s_good_i[i][0:n_intfus].eq(go_wr_o[0:n_intfus])
352
353 # *previous* instruction shadows *current* instruction, and, obviously,
354 # if the previous is completed (!busy) don't cast the shadow!
355 comb += prev_shadow.eq(~fn_issue_o & cu.busy_o)
356 for i in range(n_intfus):
357 comb += shadows.shadow_i[i][0:n_intfus].eq(prev_shadow)
358
359 # ---------
360 # ... and this is for branch speculation. it uses the extra bit
361 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
362 # only needs to set shadow_i, s_fail_i and s_good_i
363
364 # issue captures shadow_i (if enabled)
365 comb += bshadow.reset_i[0:n_intfus].eq(shreset[0:n_intfus])
366
367 bactive = Signal(reset_less=True)
368 comb += bactive.eq((bspec.active_i | br1.issue_i) & ~br1.go_wr_i)
369
370 # instruction being issued (fn_issue_o) has a shadow cast by the branch
371 with m.If(bactive & (self.branch_succ_i | self.branch_fail_i)):
372 comb += bshadow.issue_i.eq(fn_issue_o)
373 for i in range(n_intfus):
374 with m.If(fn_issue_o & (Const(1 << i))):
375 comb += bshadow.shadow_i[i][0].eq(1)
376
377 # finally, we need an indicator to the test infrastructure as to
378 # whether the branch succeeded or failed, plus, link up to the
379 # "recorder" of whether the instruction was under shadow or not
380
381 with m.If(br1.issue_i):
382 sync += bspec.active_i.eq(1)
383 with m.If(self.branch_succ_i):
384 comb += bspec.good_i.eq(fn_issue_o & 0x1f)
385 with m.If(self.branch_fail_i):
386 comb += bspec.fail_i.eq(fn_issue_o & 0x1f)
387
388 # branch is active (TODO: a better signal: this is over-using the
389 # go_write signal - actually the branch should not be "writing")
390 with m.If(br1.go_wr_i):
391 sync += self.branch_direction_o.eq(br1.data_o+Const(1, 2))
392 sync += bspec.active_i.eq(0)
393 comb += bspec.br_i.eq(1)
394 # branch occurs if data == 1, failed if data == 0
395 comb += bspec.br_ok_i.eq(br1.data_o == 1)
396 for i in range(n_intfus):
397 # *expected* direction of the branch matched against *actual*
398 comb += bshadow.s_good_i[i][0].eq(bspec.match_g_o[i])
399 # ... or it didn't
400 comb += bshadow.s_fail_i[i][0].eq(bspec.match_f_o[i])
401
402 # ---------
403 # Connect Register File(s)
404 # ---------
405 comb += int_dest.wen.eq(intfus.dest_rsel_o)
406 comb += int_src1.ren.eq(intfus.src1_rsel_o)
407 comb += int_src2.ren.eq(intfus.src2_rsel_o)
408
409 # connect ALUs to regfule
410 comb += int_dest.data_i.eq(cu.data_o)
411 comb += cu.src1_i.eq(int_src1.data_o)
412 comb += cu.src2_i.eq(int_src2.data_o)
413
414 # connect ALU Computation Units
415 comb += cu.go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus])
416 comb += cu.go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus])
417 comb += cu.issue_i[0:n_intfus].eq(fn_issue_o[0:n_intfus])
418
419 return m
420
421 def __iter__(self):
422 yield from self.intregs
423 yield from self.fpregs
424 yield self.int_dest_i
425 yield self.int_src1_i
426 yield self.int_src2_i
427 yield self.issue_o
428 yield self.branch_succ_i
429 yield self.branch_fail_i
430 yield self.branch_direction_o
431
432 def ports(self):
433 return list(self)
434
435
436 def int_instr(dut, op, imm, src1, src2, dest, branch_success, branch_fail):
437 yield from disable_issue(dut)
438 yield dut.int_dest_i.eq(dest)
439 yield dut.int_src1_i.eq(src1)
440 yield dut.int_src2_i.eq(src2)
441 if (op & (0x3 << 2)) != 0: # branch
442 yield dut.brissue.insn_i.eq(1)
443 yield dut.br_oper_i.eq(Const(op & 0x3, 2))
444 yield dut.br_imm_i.eq(imm)
445 dut_issue = dut.brissue
446 else:
447 yield dut.aluissue.insn_i.eq(1)
448 yield dut.alu_oper_i.eq(Const(op & 0x3, 2))
449 yield dut.alu_imm_i.eq(imm)
450 dut_issue = dut.aluissue
451 yield dut.reg_enable_i.eq(1)
452
453 # these indicate that the instruction is to be made shadow-dependent on
454 # (either) branch success or branch fail
455 yield dut.branch_fail_i.eq(branch_fail)
456 yield dut.branch_succ_i.eq(branch_success)
457
458 yield
459 yield from wait_for_issue(dut, dut_issue)
460
461
462 def print_reg(dut, rnums):
463 rs = []
464 for rnum in rnums:
465 reg = yield dut.intregs.regs[rnum].reg
466 rs.append("%x" % reg)
467 rnums = map(str, rnums)
468 print("reg %s: %s" % (','.join(rnums), ','.join(rs)))
469
470
471 def create_random_ops(dut, n_ops, shadowing=False, max_opnums=3):
472 insts = []
473 for i in range(n_ops):
474 src1 = randint(1, dut.n_regs-1)
475 src2 = randint(1, dut.n_regs-1)
476 imm = randint(1, (1 << dut.rwid)-1)
477 dest = randint(1, dut.n_regs-1)
478 op = randint(0, max_opnums)
479 opi = 0 if randint(0, 2) else 1 # set true if random is nonzero
480
481 if shadowing:
482 insts.append((src1, src2, dest, op, opi, imm, (0, 0)))
483 else:
484 insts.append((src1, src2, dest, op, opi, imm))
485 return insts
486
487
488 def scoreboard_sim(dut, alusim):
489
490 seed(0)
491
492 for i in range(50):
493
494 # set random values in the registers
495 for i in range(1, dut.n_regs):
496 val = randint(0, (1 << alusim.rwidth)-1)
497 #val = 31+i*3
498 #val = i
499 yield dut.intregs.regs[i].reg.eq(val)
500 alusim.setval(i, val)
501
502 # create some instructions (some random, some regression tests)
503 instrs = []
504 if True:
505 instrs = create_random_ops(dut, 15, True, 4)
506
507 if False:
508 instrs.append((1, 2, 2, 1, 1, 20, (0, 0)))
509
510 if False:
511 instrs.append((7, 3, 2, 4, (0, 0)))
512 instrs.append((7, 6, 6, 2, (0, 0)))
513 instrs.append((1, 7, 2, 2, (0, 0)))
514
515 if False:
516 instrs.append((2, 3, 3, 0, 0, 0, (0, 0)))
517 instrs.append((5, 3, 3, 1, 0, 0, (0, 0)))
518 instrs.append((3, 5, 5, 2, 0, 0, (0, 0)))
519 instrs.append((5, 3, 3, 3, 0, 0, (0, 0)))
520 instrs.append((3, 5, 5, 0, 0, 0, (0, 0)))
521
522 if False:
523 instrs.append((3, 3, 4, 0, 0, 13979, (0, 0)))
524 instrs.append((6, 4, 1, 2, 0, 40976, (0, 0)))
525 instrs.append((1, 4, 7, 4, 1, 23652, (0, 0)))
526
527 if False:
528 instrs.append((5, 6, 2, 1))
529 instrs.append((2, 2, 4, 0))
530 #instrs.append((2, 2, 3, 1))
531
532 if False:
533 instrs.append((2, 1, 2, 3))
534
535 if False:
536 instrs.append((2, 6, 2, 1))
537 instrs.append((2, 1, 2, 0))
538
539 if False:
540 instrs.append((1, 2, 7, 2))
541 instrs.append((7, 1, 5, 0))
542 instrs.append((4, 4, 1, 1))
543
544 if False:
545 instrs.append((5, 6, 2, 2))
546 instrs.append((1, 1, 4, 1))
547 instrs.append((6, 5, 3, 0))
548
549 if False:
550 # Write-after-Write Hazard
551 instrs.append((3, 6, 7, 2))
552 instrs.append((4, 4, 7, 1))
553
554 if False:
555 # self-read/write-after-write followed by Read-after-Write
556 instrs.append((1, 1, 1, 1))
557 instrs.append((1, 5, 3, 0))
558
559 if False:
560 # Read-after-Write followed by self-read-after-write
561 instrs.append((5, 6, 1, 2))
562 instrs.append((1, 1, 1, 1))
563
564 if False:
565 # self-read-write sandwich
566 instrs.append((5, 6, 1, 2))
567 instrs.append((1, 1, 1, 1))
568 instrs.append((1, 5, 3, 0))
569
570 if False:
571 # very weird failure
572 instrs.append((5, 2, 5, 2))
573 instrs.append((2, 6, 3, 0))
574 instrs.append((4, 2, 2, 1))
575
576 if False:
577 v1 = 4
578 yield dut.intregs.regs[5].reg.eq(v1)
579 alusim.setval(5, v1)
580 yield dut.intregs.regs[3].reg.eq(5)
581 alusim.setval(3, 5)
582 instrs.append((5, 3, 3, 4, (0, 0)))
583 instrs.append((4, 2, 1, 2, (0, 1)))
584
585 if False:
586 v1 = 6
587 yield dut.intregs.regs[5].reg.eq(v1)
588 alusim.setval(5, v1)
589 yield dut.intregs.regs[3].reg.eq(5)
590 alusim.setval(3, 5)
591 instrs.append((5, 3, 3, 4, (0, 0)))
592 instrs.append((4, 2, 1, 2, (1, 0)))
593
594 if False:
595 instrs.append((4, 3, 5, 1, 0, (0, 0)))
596 instrs.append((5, 2, 3, 1, 0, (0, 0)))
597 instrs.append((7, 1, 5, 2, 0, (0, 0)))
598 instrs.append((5, 6, 6, 4, 0, (0, 0)))
599 instrs.append((7, 5, 2, 2, 0, (1, 0)))
600 instrs.append((1, 7, 5, 0, 0, (0, 1)))
601 instrs.append((1, 6, 1, 2, 0, (1, 0)))
602 instrs.append((1, 6, 7, 3, 0, (0, 0)))
603 instrs.append((6, 7, 7, 0, 0, (0, 0)))
604
605 # issue instruction(s), wait for issue to be free before proceeding
606 for i, instr in enumerate(instrs):
607 src1, src2, dest, op, opi, imm, (br_ok, br_fail) = instr
608
609 print("instr %d: (%d, %d, %d, %d, %d, %d)" %
610 (i, src1, src2, dest, op, opi, imm))
611 alusim.op(op, opi, imm, src1, src2, dest)
612 yield from instr_q(dut, op, opi, imm, src1, src2, dest,
613 br_ok, br_fail)
614
615 # wait for all instructions to stop before checking
616 while True:
617 iqlen = yield dut.qlen_o
618 if iqlen == 0:
619 break
620 yield
621 yield
622 yield
623 yield
624 yield
625 yield from wait_for_busy_clear(dut)
626
627 # check status
628 yield from alusim.check(dut)
629 yield from alusim.dump(dut)
630
631
632 def test_scoreboard():
633 dut = IssueToScoreboard(2, 1, 1, 16, 8, 8)
634 alusim = RegSim(16, 8)
635 memsim = MemSim(16, 16)
636 vl = rtlil.convert(dut, ports=dut.ports())
637 with open("test_scoreboard6600.il", "w") as f:
638 f.write(vl)
639
640 run_simulation(dut, scoreboard_sim(dut, alusim),
641 vcd_name='test_scoreboard6600.vcd')
642
643 # run_simulation(dut, scoreboard_branch_sim(dut, alusim),
644 # vcd_name='test_scoreboard6600.vcd')
645
646
647 def mem_sim(dut):
648 yield dut.ld_i.eq(0x1)
649 yield dut.fn_issue_i.eq(0x1)
650 yield
651 # yield dut.ld_i.eq(0x0)
652 yield dut.st_i.eq(0x2)
653 yield dut.fn_issue_i.eq(0x2)
654 yield
655 # yield dut.st_i.eq(0x0)
656 yield dut.fn_issue_i.eq(0x0)
657 yield
658
659 yield dut.load_hit_i.eq(0x1)
660 yield
661 yield dut.load_hit_i.eq(0x0)
662 yield
663 yield dut.stwd_hit_i.eq(0x2)
664 yield
665 yield dut.stwd_hit_i.eq(0x0)
666 yield
667
668
669 def test_mem_fus():
670 dut = MemFunctionUnits(3)
671 vl = rtlil.convert(dut, ports=dut.ports())
672 with open("test_mem_fus.il", "w") as f:
673 f.write(vl)
674
675 run_simulation(dut, mem_sim(dut),
676 vcd_name='test_mem_fus.vcd')
677
678
679 if __name__ == '__main__':
680 test_mem_fus()