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