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