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