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