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