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