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