set number of ALUs to 2
[soc.git] / src / experiment / score6600.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, Memory
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.instruction_q import Instruction, InstructionQ
13 from scoreboard.memfu import MemFunctionUnits
14
15 from compalu import ComputationUnitNoDelay
16 from compldst import LDSTCompUnit
17
18 from alu_hier import ALU, BranchALU
19 from nmutil.latch import SRLatch
20 from nmutil.nmoperator import eq
21
22 from random import randint, seed
23 from copy import deepcopy
24 from math import log
25
26
27 class TestMemory(Elaboratable):
28 def __init__(self, regwid, addrw):
29 self.ddepth = 1 # regwid //8
30 depth = (1<<addrw) // self.ddepth
31 self.adr = Signal(addrw)
32 self.dat_r = Signal(regwid)
33 self.dat_w = Signal(regwid)
34 self.we = Signal()
35 self.mem = Memory(width=regwid, depth=depth, init=range(0, depth))
36
37 def elaborate(self, platform):
38 m = Module()
39 m.submodules.rdport = rdport = self.mem.read_port()
40 m.submodules.wrport = wrport = self.mem.write_port()
41 m.d.comb += [
42 rdport.addr.eq(self.adr[self.ddepth:]), # ignore low bits
43 self.dat_r.eq(rdport.data),
44 wrport.addr.eq(self.adr),
45 wrport.data.eq(self.dat_w),
46 wrport.en.eq(self.we),
47 ]
48 return m
49
50
51 class MemSim:
52 def __init__(self, regwid, addrw):
53 self.regwid = regwid
54 self.ddepth = 1 # regwid//8
55 depth = (1<<addrw) // self.ddepth
56 self.mem = list(range(0, depth))
57
58 def ld(self, addr):
59 return self.mem[addr>>self.ddepth]
60
61 def st(self, addr, data):
62 self.mem[addr>>self.ddepth] = data & ((1<<self.regwid)-1)
63
64
65 class CompUnitsBase(Elaboratable):
66 """ Computation Unit Base class.
67
68 Amazingly, this class works recursively. It's supposed to just
69 look after some ALUs (that can handle the same operations),
70 grouping them together, however it turns out that the same code
71 can also group *groups* of Computation Units together as well.
72
73 Basically it was intended just to concatenate the ALU's issue,
74 go_rd etc. signals together, which start out as bits and become
75 sequences. Turns out that the same trick works just as well
76 on Computation Units!
77
78 So this class may be used recursively to present a top-level
79 sequential concatenation of all the signals in and out of
80 ALUs, whilst at the same time making it convenient to group
81 ALUs together.
82
83 At the lower level, the intent is that groups of (identical)
84 ALUs may be passed the same operation. Even beyond that,
85 the intent is that that group of (identical) ALUs actually
86 share the *same pipeline* and as such become a "Concurrent
87 Computation Unit" as defined by Mitch Alsup (see section
88 11.4.9.3)
89 """
90 def __init__(self, rwid, units, ldstmode=False):
91 """ Inputs:
92
93 * :rwid: bit width of register file(s) - both FP and INT
94 * :units: sequence of ALUs (or CompUnitsBase derivatives)
95 """
96 self.units = units
97 self.ldstmode = ldstmode
98 self.rwid = rwid
99 self.rwid = rwid
100 if units and isinstance(units[0], CompUnitsBase):
101 self.n_units = 0
102 for u in self.units:
103 self.n_units += u.n_units
104 else:
105 self.n_units = len(units)
106
107 n_units = self.n_units
108
109 # inputs
110 self.issue_i = Signal(n_units, reset_less=True)
111 self.go_rd_i = Signal(n_units, reset_less=True)
112 self.go_wr_i = Signal(n_units, reset_less=True)
113 self.shadown_i = Signal(n_units, reset_less=True)
114 self.go_die_i = Signal(n_units, reset_less=True)
115 if ldstmode:
116 self.go_ad_i = Signal(n_units, reset_less=True)
117
118 # outputs
119 self.busy_o = Signal(n_units, reset_less=True)
120 self.rd_rel_o = Signal(n_units, reset_less=True)
121 self.req_rel_o = Signal(n_units, reset_less=True)
122 if ldstmode:
123 self.adr_rel_o = Signal(n_units, reset_less=True)
124 self.sto_rel_o = Signal(n_units, reset_less=True)
125 self.req_rel_o = Signal(n_units, reset_less=True)
126 self.load_mem_o = Signal(n_units, reset_less=True)
127 self.stwd_mem_o = Signal(n_units, reset_less=True)
128
129 # in/out register data (note: not register#, actual data)
130 self.data_o = Signal(rwid, reset_less=True)
131 self.src1_i = Signal(rwid, reset_less=True)
132 self.src2_i = Signal(rwid, reset_less=True)
133 # input operand
134
135 def elaborate(self, platform):
136 m = Module()
137 comb = m.d.comb
138
139 for i, alu in enumerate(self.units):
140 setattr(m.submodules, "comp%d" % i, alu)
141
142 go_rd_l = []
143 go_wr_l = []
144 issue_l = []
145 busy_l = []
146 req_rel_l = []
147 rd_rel_l = []
148 shadow_l = []
149 godie_l = []
150 for alu in self.units:
151 req_rel_l.append(alu.req_rel_o)
152 rd_rel_l.append(alu.rd_rel_o)
153 shadow_l.append(alu.shadown_i)
154 godie_l.append(alu.go_die_i)
155 go_wr_l.append(alu.go_wr_i)
156 go_rd_l.append(alu.go_rd_i)
157 issue_l.append(alu.issue_i)
158 busy_l.append(alu.busy_o)
159 comb += self.rd_rel_o.eq(Cat(*rd_rel_l))
160 comb += self.req_rel_o.eq(Cat(*req_rel_l))
161 comb += self.busy_o.eq(Cat(*busy_l))
162 comb += Cat(*godie_l).eq(self.go_die_i)
163 comb += Cat(*shadow_l).eq(self.shadown_i)
164 comb += Cat(*go_wr_l).eq(self.go_wr_i)
165 comb += Cat(*go_rd_l).eq(self.go_rd_i)
166 comb += Cat(*issue_l).eq(self.issue_i)
167
168 # connect data register input/output
169
170 # merge (OR) all integer FU / ALU outputs to a single value
171 # bit of a hack: treereduce needs a list with an item named "data_o"
172 if self.units:
173 data_o = treereduce(self.units)
174 comb += self.data_o.eq(data_o)
175
176 for i, alu in enumerate(self.units):
177 comb += alu.src1_i.eq(self.src1_i)
178 comb += alu.src2_i.eq(self.src2_i)
179
180 if not self.ldstmode:
181 return m
182
183 ldmem_l = []
184 stmem_l = []
185 go_ad_l = []
186 adr_rel_l = []
187 sto_rel_l = []
188 for alu in self.units:
189 adr_rel_l.append(alu.adr_rel_o)
190 sto_rel_l.append(alu.sto_rel_o)
191 ldmem_l.append(alu.load_mem_o)
192 stmem_l.append(alu.stwd_mem_o)
193 go_ad_l.append(alu.go_ad_i)
194 comb += self.adr_rel_o.eq(Cat(*adr_rel_l))
195 comb += self.sto_rel_o.eq(Cat(*sto_rel_l))
196 comb += self.load_mem_o.eq(Cat(*ldmem_l))
197 comb += self.stwd_mem_o.eq(Cat(*stmem_l))
198 comb += Cat(*go_ad_l).eq(self.go_ad_i)
199
200 return m
201
202
203 class CompUnitLDSTs(CompUnitsBase):
204
205 def __init__(self, rwid, opwid, mem):
206 """ Inputs:
207
208 * :rwid: bit width of register file(s) - both FP and INT
209 * :opwid: operand bit width
210 """
211 self.opwid = opwid
212
213 # inputs
214 self.oper_i = Signal(opwid, reset_less=True)
215 self.imm_i = Signal(rwid, reset_less=True)
216
217 # Int ALUs
218 add1 = ALU(rwid)
219 add2 = ALU(rwid)
220
221 units = []
222 for alu in [add1, add2]:
223 aluopwid = 4 # see compldst.py for "internal" opcode
224 units.append(LDSTCompUnit(rwid, aluopwid, alu, mem))
225
226 CompUnitsBase.__init__(self, rwid, units, ldstmode=True)
227
228 def elaborate(self, platform):
229 m = CompUnitsBase.elaborate(self, platform)
230 comb = m.d.comb
231
232 # hand the same operation to all units, 4 lower bits though
233 for alu in self.units:
234 comb += alu.oper_i[0:4].eq(self.oper_i)
235 comb += alu.imm_i.eq(self.imm_i)
236 comb += alu.isalu_i.eq(0)
237
238 return m
239
240
241 class CompUnitALUs(CompUnitsBase):
242
243 def __init__(self, rwid, opwid, n_alus):
244 """ Inputs:
245
246 * :rwid: bit width of register file(s) - both FP and INT
247 * :opwid: operand bit width
248 """
249 self.opwid = opwid
250
251 # inputs
252 self.oper_i = Signal(opwid, reset_less=True)
253 self.imm_i = Signal(rwid, reset_less=True)
254
255 # Int ALUs
256 alus = []
257 for i in range(n_alus):
258 alus.append(ALU(rwid))
259
260 units = []
261 for alu in alus:
262 aluopwid = 3 # extra bit for immediate mode
263 units.append(ComputationUnitNoDelay(rwid, aluopwid, alu))
264
265 CompUnitsBase.__init__(self, rwid, units)
266
267 def elaborate(self, platform):
268 m = CompUnitsBase.elaborate(self, platform)
269 comb = m.d.comb
270
271 # hand the same operation to all units, only lower 3 bits though
272 for alu in self.units:
273 comb += alu.oper_i[0:3].eq(self.oper_i)
274 comb += alu.imm_i.eq(self.imm_i)
275
276 return m
277
278
279 class CompUnitBR(CompUnitsBase):
280
281 def __init__(self, rwid, opwid):
282 """ Inputs:
283
284 * :rwid: bit width of register file(s) - both FP and INT
285 * :opwid: operand bit width
286
287 Note: bgt unit is returned so that a shadow unit can be created
288 for it
289 """
290 self.opwid = opwid
291
292 # inputs
293 self.oper_i = Signal(opwid, reset_less=True)
294 self.imm_i = Signal(rwid, reset_less=True)
295
296 # Branch ALU and CU
297 self.bgt = BranchALU(rwid)
298 aluopwid = 3 # extra bit for immediate mode
299 self.br1 = ComputationUnitNoDelay(rwid, aluopwid, self.bgt)
300 CompUnitsBase.__init__(self, rwid, [self.br1])
301
302 def elaborate(self, platform):
303 m = CompUnitsBase.elaborate(self, platform)
304 comb = m.d.comb
305
306 # hand the same operation to all units
307 for alu in self.units:
308 comb += alu.oper_i.eq(self.oper_i)
309 comb += alu.imm_i.eq(self.imm_i)
310
311 return m
312
313
314 class FunctionUnits(Elaboratable):
315
316 def __init__(self, n_regs, n_int_alus):
317 self.n_regs = n_regs
318 self.n_int_alus = n_int_alus
319
320 self.dest_i = Signal(n_regs, reset_less=True) # Dest R# in
321 self.src1_i = Signal(n_regs, reset_less=True) # oper1 R# in
322 self.src2_i = Signal(n_regs, reset_less=True) # oper2 R# in
323
324 self.g_int_rd_pend_o = Signal(n_regs, reset_less=True)
325 self.g_int_wr_pend_o = Signal(n_regs, reset_less=True)
326
327 self.dest_rsel_o = Signal(n_regs, reset_less=True) # dest reg (bot)
328 self.src1_rsel_o = Signal(n_regs, reset_less=True) # src1 reg (bot)
329 self.src2_rsel_o = Signal(n_regs, reset_less=True) # src2 reg (bot)
330
331 self.readable_o = Signal(n_int_alus, reset_less=True)
332 self.writable_o = Signal(n_int_alus, reset_less=True)
333
334 self.go_rd_i = Signal(n_int_alus, reset_less=True)
335 self.go_wr_i = Signal(n_int_alus, reset_less=True)
336 self.go_die_i = Signal(n_int_alus, reset_less=True)
337 self.fn_issue_i = Signal(n_int_alus, reset_less=True)
338
339 # Note: FURegs wr_pend_o is also outputted from here, for use in WaWGrid
340
341 def elaborate(self, platform):
342 m = Module()
343 comb = m.d.comb
344 sync = m.d.sync
345
346 n_intfus = self.n_int_alus
347
348 # Integer FU-FU Dep Matrix
349 intfudeps = FUFUDepMatrix(n_intfus, n_intfus)
350 m.submodules.intfudeps = intfudeps
351 # Integer FU-Reg Dep Matrix
352 intregdeps = FURegDepMatrix(n_intfus, self.n_regs, 2)
353 m.submodules.intregdeps = intregdeps
354
355 comb += self.g_int_rd_pend_o.eq(intregdeps.v_rd_rsel_o)
356 comb += self.g_int_wr_pend_o.eq(intregdeps.v_wr_rsel_o)
357
358 comb += intregdeps.rd_pend_i.eq(intregdeps.v_rd_rsel_o)
359 comb += intregdeps.wr_pend_i.eq(intregdeps.v_wr_rsel_o)
360
361 comb += intfudeps.rd_pend_i.eq(intregdeps.rd_pend_o)
362 comb += intfudeps.wr_pend_i.eq(intregdeps.wr_pend_o)
363 self.wr_pend_o = intregdeps.wr_pend_o # also output for use in WaWGrid
364
365 comb += intfudeps.issue_i.eq(self.fn_issue_i)
366 comb += intfudeps.go_rd_i.eq(self.go_rd_i)
367 comb += intfudeps.go_wr_i.eq(self.go_wr_i)
368 comb += intfudeps.go_die_i.eq(self.go_die_i)
369 comb += self.readable_o.eq(intfudeps.readable_o)
370 comb += self.writable_o.eq(intfudeps.writable_o)
371
372 # Connect function issue / arrays, and dest/src1/src2
373 comb += intregdeps.dest_i.eq(self.dest_i)
374 comb += intregdeps.src_i[0].eq(self.src1_i)
375 comb += intregdeps.src_i[1].eq(self.src2_i)
376
377 comb += intregdeps.go_rd_i.eq(self.go_rd_i)
378 comb += intregdeps.go_wr_i.eq(self.go_wr_i)
379 comb += intregdeps.go_die_i.eq(self.go_die_i)
380 comb += intregdeps.issue_i.eq(self.fn_issue_i)
381
382 comb += self.dest_rsel_o.eq(intregdeps.dest_rsel_o)
383 comb += self.src1_rsel_o.eq(intregdeps.src_rsel_o[0])
384 comb += self.src2_rsel_o.eq(intregdeps.src_rsel_o[1])
385
386 return m
387
388
389 class Scoreboard(Elaboratable):
390 def __init__(self, rwid, n_regs):
391 """ Inputs:
392
393 * :rwid: bit width of register file(s) - both FP and INT
394 * :n_regs: depth of register file(s) - number of FP and INT regs
395 """
396 self.rwid = rwid
397 self.n_regs = n_regs
398
399 # Register Files
400 self.intregs = RegFileArray(rwid, n_regs)
401 self.fpregs = RegFileArray(rwid, n_regs)
402
403 # issue q needs to get at these
404 self.aluissue = IssueUnitGroup(4)
405 self.brissue = IssueUnitGroup(1)
406 self.lsissue = IssueUnitGroup(1)
407 # and these
408 self.alu_oper_i = Signal(4, reset_less=True)
409 self.alu_imm_i = Signal(rwid, reset_less=True)
410 self.br_oper_i = Signal(4, reset_less=True)
411 self.br_imm_i = Signal(rwid, reset_less=True)
412 self.ls_oper_i = Signal(4, reset_less=True)
413 self.ls_imm_i = Signal(rwid, reset_less=True)
414
415 # inputs
416 self.int_dest_i = Signal(max=n_regs, reset_less=True) # Dest R# in
417 self.int_src1_i = Signal(max=n_regs, reset_less=True) # oper1 R# in
418 self.int_src2_i = Signal(max=n_regs, reset_less=True) # oper2 R# in
419 self.reg_enable_i = Signal(reset_less=True) # enable reg decode
420
421 # outputs
422 self.issue_o = Signal(reset_less=True) # instruction was accepted
423 self.busy_o = Signal(reset_less=True) # at least one CU is busy
424
425 # for branch speculation experiment. branch_direction = 0 if
426 # the branch hasn't been met yet. 1 indicates "success", 2 is "fail"
427 # branch_succ and branch_fail are requests to have the current
428 # instruction be dependent on the branch unit "shadow" capability.
429 self.branch_succ_i = Signal(reset_less=True)
430 self.branch_fail_i = Signal(reset_less=True)
431 self.branch_direction_o = Signal(2, reset_less=True)
432
433 def elaborate(self, platform):
434 m = Module()
435 comb = m.d.comb
436 sync = m.d.sync
437
438 m.submodules.intregs = self.intregs
439 m.submodules.fpregs = self.fpregs
440
441 # register ports
442 int_dest = self.intregs.write_port("dest")
443 int_src1 = self.intregs.read_port("src1")
444 int_src2 = self.intregs.read_port("src2")
445
446 fp_dest = self.fpregs.write_port("dest")
447 fp_src1 = self.fpregs.read_port("src1")
448 fp_src2 = self.fpregs.read_port("src2")
449
450 # Int ALUs and BR ALUs
451 n_int_alus = 5
452 cua = CompUnitALUs(self.rwid, 3, n_alus=2)
453 cub = CompUnitBR(self.rwid, 3) # 1 BR ALUs
454
455 # LDST Comp Units
456 n_ldsts = 2
457 cul = CompUnitLDSTs(self.rwid, 4, None)
458
459 # Comp Units
460 m.submodules.cu = cu = CompUnitsBase(self.rwid, [cua, cub, cul])
461 bgt = cub.bgt # get at the branch computation unit
462 br1 = cub.br1
463
464 # Int FUs
465 m.submodules.intfus = intfus = FunctionUnits(self.n_regs, n_int_alus)
466
467 # Memory FUs
468 m.submodules.memfus = memfus = MemFunctionUnits(n_ldsts, 5)
469
470 # Count of number of FUs
471 n_intfus = n_int_alus
472 n_fp_fus = 0 # for now
473
474 # Integer Priority Picker 1: Adder + Subtractor (and LD/ST)
475 intpick1 = GroupPicker(n_intfus) # picks 1 reader and 1 writer to intreg
476 m.submodules.intpick1 = intpick1
477
478 # INT/FP Issue Unit
479 regdecode = RegDecode(self.n_regs)
480 m.submodules.regdecode = regdecode
481 issueunit = IssueUnitArray([self.aluissue, self.brissue, self.lsissue])
482 m.submodules.issueunit = issueunit
483
484 # Shadow Matrix. currently n_intfus shadows, to be used for
485 # write-after-write hazards. NOTE: there is one extra for branches,
486 # so the shadow width is increased by 1
487 m.submodules.shadows = shadows = ShadowMatrix(n_intfus, n_intfus, True)
488 m.submodules.bshadow = bshadow = ShadowMatrix(n_intfus, 1, False)
489
490 # record previous instruction to cast shadow on current instruction
491 prev_shadow = Signal(n_intfus)
492
493 # Branch Speculation recorder. tracks the success/fail state as
494 # each instruction is issued, so that when the branch occurs the
495 # allow/cancel can be issued as appropriate.
496 m.submodules.specrec = bspec = BranchSpeculationRecord(n_intfus)
497
498 #---------
499 # ok start wiring things together...
500 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
501 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
502 #---------
503
504 #---------
505 # Issue Unit is where it starts. set up some in/outs for this module
506 #---------
507 comb += [ regdecode.dest_i.eq(self.int_dest_i),
508 regdecode.src1_i.eq(self.int_src1_i),
509 regdecode.src2_i.eq(self.int_src2_i),
510 regdecode.enable_i.eq(self.reg_enable_i),
511 self.issue_o.eq(issueunit.issue_o)
512 ]
513
514 # take these to outside (issue needs them)
515 comb += cua.oper_i.eq(self.alu_oper_i)
516 comb += cua.imm_i.eq(self.alu_imm_i)
517 comb += cub.oper_i.eq(self.br_oper_i)
518 comb += cub.imm_i.eq(self.br_imm_i)
519 comb += cul.oper_i.eq(self.ls_oper_i)
520 comb += cul.imm_i.eq(self.ls_imm_i)
521
522 # TODO: issueunit.f (FP)
523
524 # and int function issue / busy arrays, and dest/src1/src2
525 comb += intfus.dest_i.eq(regdecode.dest_o)
526 comb += intfus.src1_i.eq(regdecode.src1_o)
527 comb += intfus.src2_i.eq(regdecode.src2_o)
528
529 fn_issue_o = issueunit.fn_issue_o
530
531 comb += intfus.fn_issue_i.eq(fn_issue_o)
532 comb += issueunit.busy_i.eq(cu.busy_o)
533 comb += self.busy_o.eq(cu.busy_o.bool())
534
535 #---------
536 # merge shadow matrices outputs
537 #---------
538
539 # these are explained in ShadowMatrix docstring, and are to be
540 # connected to the FUReg and FUFU Matrices, to get them to reset
541 anydie = Signal(n_intfus, reset_less=True)
542 allshadown = Signal(n_intfus, reset_less=True)
543 shreset = Signal(n_intfus, reset_less=True)
544 comb += allshadown.eq(shadows.shadown_o & bshadow.shadown_o)
545 comb += anydie.eq(shadows.go_die_o | bshadow.go_die_o)
546 comb += shreset.eq(bspec.match_g_o | bspec.match_f_o)
547
548 #---------
549 # connect fu-fu matrix
550 #---------
551
552 # Group Picker... done manually for now.
553 go_rd_o = intpick1.go_rd_o
554 go_wr_o = intpick1.go_wr_o
555 go_rd_i = intfus.go_rd_i
556 go_wr_i = intfus.go_wr_i
557 go_die_i = intfus.go_die_i
558 # NOTE: connect to the shadowed versions so that they can "die" (reset)
559 comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd
560 comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr
561 comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die
562
563 # Connect Picker
564 #---------
565 comb += intpick1.rd_rel_i[0:n_intfus].eq(cu.rd_rel_o[0:n_intfus])
566 comb += intpick1.req_rel_i[0:n_intfus].eq(cu.req_rel_o[0:n_intfus])
567 int_rd_o = intfus.readable_o
568 int_wr_o = intfus.writable_o
569 comb += intpick1.readable_i[0:n_intfus].eq(int_rd_o[0:n_intfus])
570 comb += intpick1.writable_i[0:n_intfus].eq(int_wr_o[0:n_intfus])
571
572 #---------
573 # Shadow Matrix
574 #---------
575
576 comb += shadows.issue_i.eq(fn_issue_o)
577 #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
578 comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
579 #---------
580 # NOTE; this setup is for the instruction order preservation...
581
582 # connect shadows / go_dies to Computation Units
583 comb += cu.shadown_i[0:n_intfus].eq(allshadown)
584 comb += cu.go_die_i[0:n_intfus].eq(anydie)
585
586 # ok connect first n_int_fu shadows to busy lines, to create an
587 # instruction-order linked-list-like arrangement, using a bit-matrix
588 # (instead of e.g. a ring buffer).
589 # XXX TODO
590
591 # when written, the shadow can be cancelled (and was good)
592 for i in range(n_intfus):
593 comb += shadows.s_good_i[i][0:n_intfus].eq(go_wr_o[0:n_intfus])
594
595 # *previous* instruction shadows *current* instruction, and, obviously,
596 # if the previous is completed (!busy) don't cast the shadow!
597 comb += prev_shadow.eq(~fn_issue_o & cu.busy_o)
598 for i in range(n_intfus):
599 comb += shadows.shadow_i[i][0:n_intfus].eq(prev_shadow)
600
601 #---------
602 # ... and this is for branch speculation. it uses the extra bit
603 # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
604 # only needs to set shadow_i, s_fail_i and s_good_i
605
606 # issue captures shadow_i (if enabled)
607 comb += bshadow.reset_i[0:n_intfus].eq(shreset[0:n_intfus])
608
609 bactive = Signal(reset_less=True)
610 comb += bactive.eq((bspec.active_i | br1.issue_i) & ~br1.go_wr_i)
611
612 # instruction being issued (fn_issue_o) has a shadow cast by the branch
613 with m.If(bactive & (self.branch_succ_i | self.branch_fail_i)):
614 comb += bshadow.issue_i.eq(fn_issue_o)
615 for i in range(n_intfus):
616 with m.If(fn_issue_o & (Const(1<<i))):
617 comb += bshadow.shadow_i[i][0].eq(1)
618
619 # finally, we need an indicator to the test infrastructure as to
620 # whether the branch succeeded or failed, plus, link up to the
621 # "recorder" of whether the instruction was under shadow or not
622
623 with m.If(br1.issue_i):
624 sync += bspec.active_i.eq(1)
625 with m.If(self.branch_succ_i):
626 comb += bspec.good_i.eq(fn_issue_o & 0x1f) # XXX MAGIC CONSTANT
627 with m.If(self.branch_fail_i):
628 comb += bspec.fail_i.eq(fn_issue_o & 0x1f) # XXX MAGIC CONSTANT
629
630 # branch is active (TODO: a better signal: this is over-using the
631 # go_write signal - actually the branch should not be "writing")
632 with m.If(br1.go_wr_i):
633 sync += self.branch_direction_o.eq(br1.data_o+Const(1, 2))
634 sync += bspec.active_i.eq(0)
635 comb += bspec.br_i.eq(1)
636 # branch occurs if data == 1, failed if data == 0
637 comb += bspec.br_ok_i.eq(br1.data_o == 1)
638 for i in range(n_intfus):
639 # *expected* direction of the branch matched against *actual*
640 comb += bshadow.s_good_i[i][0].eq(bspec.match_g_o[i])
641 # ... or it didn't
642 comb += bshadow.s_fail_i[i][0].eq(bspec.match_f_o[i])
643
644 #---------
645 # Connect Register File(s)
646 #---------
647 comb += int_dest.wen.eq(intfus.dest_rsel_o)
648 comb += int_src1.ren.eq(intfus.src1_rsel_o)
649 comb += int_src2.ren.eq(intfus.src2_rsel_o)
650
651 # connect ALUs to regfule
652 comb += int_dest.data_i.eq(cu.data_o)
653 comb += cu.src1_i.eq(int_src1.data_o)
654 comb += cu.src2_i.eq(int_src2.data_o)
655
656 # connect ALU Computation Units
657 comb += cu.go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus])
658 comb += cu.go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus])
659 comb += cu.issue_i[0:n_intfus].eq(fn_issue_o[0:n_intfus])
660
661 return m
662
663 def __iter__(self):
664 yield from self.intregs
665 yield from self.fpregs
666 yield self.int_dest_i
667 yield self.int_src1_i
668 yield self.int_src2_i
669 yield self.issue_o
670 yield self.branch_succ_i
671 yield self.branch_fail_i
672 yield self.branch_direction_o
673
674 def ports(self):
675 return list(self)
676
677
678 class IssueToScoreboard(Elaboratable):
679
680 def __init__(self, qlen, n_in, n_out, rwid, opwid, n_regs):
681 self.qlen = qlen
682 self.n_in = n_in
683 self.n_out = n_out
684 self.rwid = rwid
685 self.opw = opwid
686 self.n_regs = n_regs
687
688 mqbits = (int(log(qlen) / log(2))+2, False)
689 self.p_add_i = Signal(mqbits) # instructions to add (from data_i)
690 self.p_ready_o = Signal() # instructions were added
691 self.data_i = Instruction.nq(n_in, "data_i", rwid, opwid)
692
693 self.busy_o = Signal(reset_less=True) # at least one CU is busy
694 self.qlen_o = Signal(mqbits, reset_less=True)
695
696 def elaborate(self, platform):
697 m = Module()
698 comb = m.d.comb
699 sync = m.d.sync
700
701 iq = InstructionQ(self.rwid, self.opw, self.qlen, self.n_in, self.n_out)
702 sc = Scoreboard(self.rwid, self.n_regs)
703 mem = TestMemory(self.rwid, 8) # not too big, takes too long
704 m.submodules.iq = iq
705 m.submodules.sc = sc
706 m.submodules.mem = mem
707
708 # get at the regfile for testing
709 self.intregs = sc.intregs
710
711 # and the "busy" signal and instruction queue length
712 comb += self.busy_o.eq(sc.busy_o)
713 comb += self.qlen_o.eq(iq.qlen_o)
714
715 # link up instruction queue
716 comb += iq.p_add_i.eq(self.p_add_i)
717 comb += self.p_ready_o.eq(iq.p_ready_o)
718 for i in range(self.n_in):
719 comb += eq(iq.data_i[i], self.data_i[i])
720
721 # take instruction and process it. note that it's possible to
722 # "inspect" the queue contents *without* actually removing the
723 # items. items are only removed when the
724
725 # in "waiting" state
726 wait_issue_br = Signal()
727 wait_issue_alu = Signal()
728 wait_issue_ls = Signal()
729
730 with m.If(wait_issue_br | wait_issue_alu | wait_issue_ls):
731 # set instruction pop length to 1 if the unit accepted
732 with m.If(wait_issue_ls & (sc.lsissue.fn_issue_o != 0)):
733 with m.If(iq.qlen_o != 0):
734 comb += iq.n_sub_i.eq(1)
735 with m.If(wait_issue_br & (sc.brissue.fn_issue_o != 0)):
736 with m.If(iq.qlen_o != 0):
737 comb += iq.n_sub_i.eq(1)
738 with m.If(wait_issue_alu & (sc.aluissue.fn_issue_o != 0)):
739 with m.If(iq.qlen_o != 0):
740 comb += iq.n_sub_i.eq(1)
741
742 # see if some instruction(s) are here. note that this is
743 # "inspecting" the in-place queue. note also that on the
744 # cycle following "waiting" for fn_issue_o to be set, the
745 # "resetting" done above (insn_i=0) could be re-ASSERTed.
746 with m.If(iq.qlen_o != 0):
747 # get the operands and operation
748 imm = iq.data_o[0].imm_i
749 dest = iq.data_o[0].dest_i
750 src1 = iq.data_o[0].src1_i
751 src2 = iq.data_o[0].src2_i
752 op = iq.data_o[0].oper_i
753 opi = iq.data_o[0].opim_i # immediate set
754
755 # set the src/dest regs
756 comb += sc.int_dest_i.eq(dest)
757 comb += sc.int_src1_i.eq(src1)
758 comb += sc.int_src2_i.eq(src2)
759 comb += sc.reg_enable_i.eq(1) # enable the regfile
760
761 # choose a Function-Unit-Group
762 with m.If((op & (0x3<<2)) != 0): # branch
763 comb += sc.br_oper_i.eq(Cat(op[0:2], opi))
764 comb += sc.br_imm_i.eq(imm)
765 comb += sc.brissue.insn_i.eq(1)
766 comb += wait_issue_br.eq(1)
767 with m.Elif((op & (0x3<<4)) != 0): # ld/st
768 # see compldst.py
769 # bit 0: ADD/SUB
770 # bit 1: immed
771 # bit 4: LD
772 # bit 5: ST
773 comb += sc.ls_oper_i.eq(Cat(op[0], opi[0], op[4:6]))
774 comb += sc.ls_imm_i.eq(imm)
775 comb += sc.lsissue.insn_i.eq(1)
776 comb += wait_issue_ls.eq(1)
777 with m.Else(): # alu
778 comb += sc.alu_oper_i.eq(Cat(op[0:2], opi))
779 comb += sc.alu_imm_i.eq(imm)
780 comb += sc.aluissue.insn_i.eq(1)
781 comb += wait_issue_alu.eq(1)
782
783 # XXX TODO
784 # these indicate that the instruction is to be made
785 # shadow-dependent on
786 # (either) branch success or branch fail
787 #yield sc.branch_fail_i.eq(branch_fail)
788 #yield sc.branch_succ_i.eq(branch_success)
789
790 return m
791
792 def __iter__(self):
793 yield self.p_ready_o
794 for o in self.data_i:
795 yield from list(o)
796 yield self.p_add_i
797
798 def ports(self):
799 return list(self)
800
801
802 IADD = 0
803 ISUB = 1
804 IMUL = 2
805 ISHF = 3
806 IBGT = 4
807 IBLT = 5
808 IBEQ = 6
809 IBNE = 7
810
811
812 class RegSim:
813 def __init__(self, rwidth, nregs):
814 self.rwidth = rwidth
815 self.regs = [0] * nregs
816
817 def op(self, op, op_imm, imm, src1, src2, dest):
818 maxbits = (1 << self.rwidth) - 1
819 src1 = self.regs[src1] & maxbits
820 if op_imm:
821 src2 = imm
822 else:
823 src2 = self.regs[src2] & maxbits
824 if op == IADD:
825 val = src1 + src2
826 elif op == ISUB:
827 val = src1 - src2
828 elif op == IMUL:
829 val = src1 * src2
830 elif op == ISHF:
831 val = src1 >> (src2 & maxbits)
832 elif op == IBGT:
833 val = int(src1 > src2)
834 elif op == IBLT:
835 val = int(src1 < src2)
836 elif op == IBEQ:
837 val = int(src1 == src2)
838 elif op == IBNE:
839 val = int(src1 != src2)
840 else:
841 return 0 # LD/ST TODO
842 val &= maxbits
843 self.setval(dest, val)
844 return val
845
846 def setval(self, dest, val):
847 print ("sim setval", dest, hex(val))
848 self.regs[dest] = val
849
850 def dump(self, dut):
851 for i, val in enumerate(self.regs):
852 reg = yield dut.intregs.regs[i].reg
853 okstr = "OK" if reg == val else "!ok"
854 print("reg %d expected %x received %x %s" % (i, val, reg, okstr))
855
856 def check(self, dut):
857 for i, val in enumerate(self.regs):
858 reg = yield dut.intregs.regs[i].reg
859 if reg != val:
860 print("reg %d expected %x received %x\n" % (i, val, reg))
861 yield from self.dump(dut)
862 assert False
863
864 def instr_q(dut, op, op_imm, imm, src1, src2, dest,
865 branch_success, branch_fail):
866 instrs = [{'oper_i': op, 'dest_i': dest, 'imm_i': imm, 'opim_i': op_imm,
867 'src1_i': src1, 'src2_i': src2}]
868
869 sendlen = 1
870 for idx in range(sendlen):
871 yield from eq(dut.data_i[idx], instrs[idx])
872 di = yield dut.data_i[idx]
873 print ("senddata %d %x" % (idx, di))
874 yield dut.p_add_i.eq(sendlen)
875 yield
876 o_p_ready = yield dut.p_ready_o
877 while not o_p_ready:
878 yield
879 o_p_ready = yield dut.p_ready_o
880
881 yield dut.p_add_i.eq(0)
882
883
884 def int_instr(dut, op, imm, src1, src2, dest, branch_success, branch_fail):
885 yield from disable_issue(dut)
886 yield dut.int_dest_i.eq(dest)
887 yield dut.int_src1_i.eq(src1)
888 yield dut.int_src2_i.eq(src2)
889 if (op & (0x3<<2)) != 0: # branch
890 yield dut.brissue.insn_i.eq(1)
891 yield dut.br_oper_i.eq(Const(op & 0x3, 2))
892 yield dut.br_imm_i.eq(imm)
893 dut_issue = dut.brissue
894 else:
895 yield dut.aluissue.insn_i.eq(1)
896 yield dut.alu_oper_i.eq(Const(op & 0x3, 2))
897 yield dut.alu_imm_i.eq(imm)
898 dut_issue = dut.aluissue
899 yield dut.reg_enable_i.eq(1)
900
901 # these indicate that the instruction is to be made shadow-dependent on
902 # (either) branch success or branch fail
903 yield dut.branch_fail_i.eq(branch_fail)
904 yield dut.branch_succ_i.eq(branch_success)
905
906 yield
907 yield from wait_for_issue(dut, dut_issue)
908
909
910 def print_reg(dut, rnums):
911 rs = []
912 for rnum in rnums:
913 reg = yield dut.intregs.regs[rnum].reg
914 rs.append("%x" % reg)
915 rnums = map(str, rnums)
916 print ("reg %s: %s" % (','.join(rnums), ','.join(rs)))
917
918
919 def create_random_ops(dut, n_ops, shadowing=False, max_opnums=3):
920 insts = []
921 for i in range(n_ops):
922 src1 = randint(1, dut.n_regs-1)
923 src2 = randint(1, dut.n_regs-1)
924 imm = randint(1, (1<<dut.rwid)-1)
925 dest = randint(1, dut.n_regs-1)
926 op = randint(0, max_opnums)
927 opi = 0 if randint(0, 2) else 1 # set true if random is nonzero
928
929 if shadowing:
930 insts.append((src1, src2, dest, op, opi, imm, (0, 0)))
931 else:
932 insts.append((src1, src2, dest, op, opi, imm))
933 return insts
934
935
936 def wait_for_busy_clear(dut):
937 while True:
938 busy_o = yield dut.busy_o
939 if not busy_o:
940 break
941 print ("busy",)
942 yield
943
944 def disable_issue(dut):
945 yield dut.aluissue.insn_i.eq(0)
946 yield dut.brissue.insn_i.eq(0)
947 yield dut.lsissue.insn_i.eq(0)
948
949
950 def wait_for_issue(dut, dut_issue):
951 while True:
952 issue_o = yield dut_issue.fn_issue_o
953 if issue_o:
954 yield from disable_issue(dut)
955 yield dut.reg_enable_i.eq(0)
956 break
957 print ("busy",)
958 #yield from print_reg(dut, [1,2,3])
959 yield
960 #yield from print_reg(dut, [1,2,3])
961
962 def scoreboard_branch_sim(dut, alusim):
963
964 iseed = 3
965
966 for i in range(1):
967
968 print ("rseed", iseed)
969 seed(iseed)
970 iseed += 1
971
972 yield dut.branch_direction_o.eq(0)
973
974 # set random values in the registers
975 for i in range(1, dut.n_regs):
976 val = 31+i*3
977 val = randint(0, (1<<alusim.rwidth)-1)
978 yield dut.intregs.regs[i].reg.eq(val)
979 alusim.setval(i, val)
980
981 if False:
982 # create some instructions: branches create a tree
983 insts = create_random_ops(dut, 1, True, 1)
984 #insts.append((6, 6, 1, 2, (0, 0)))
985 #insts.append((4, 3, 3, 0, (0, 0)))
986
987 src1 = randint(1, dut.n_regs-1)
988 src2 = randint(1, dut.n_regs-1)
989 #op = randint(4, 7)
990 op = 4 # only BGT at the moment
991
992 branch_ok = create_random_ops(dut, 1, True, 1)
993 branch_fail = create_random_ops(dut, 1, True, 1)
994
995 insts.append((src1, src2, (branch_ok, branch_fail), op, (0, 0)))
996
997 if True:
998 insts = []
999 insts.append( (3, 5, 2, 0, (0, 0)) )
1000 branch_ok = []
1001 branch_fail = []
1002 #branch_ok.append ( (5, 7, 5, 1, (1, 0)) )
1003 branch_ok.append( None )
1004 branch_fail.append( (1, 1, 2, 0, (0, 1)) )
1005 #branch_fail.append( None )
1006 insts.append( (6, 4, (branch_ok, branch_fail), 4, (0, 0)) )
1007
1008 siminsts = deepcopy(insts)
1009
1010 # issue instruction(s)
1011 i = -1
1012 instrs = insts
1013 branch_direction = 0
1014 while instrs:
1015 yield
1016 yield
1017 i += 1
1018 branch_direction = yield dut.branch_direction_o # way branch went
1019 (src1, src2, dest, op, (shadow_on, shadow_off)) = insts.pop(0)
1020 if branch_direction == 1 and shadow_on:
1021 print ("skip", i, src1, src2, dest, op, shadow_on, shadow_off)
1022 continue # branch was "success" and this is a "failed"... skip
1023 if branch_direction == 2 and shadow_off:
1024 print ("skip", i, src1, src2, dest, op, shadow_on, shadow_off)
1025 continue # branch was "fail" and this is a "success"... skip
1026 if branch_direction != 0:
1027 shadow_on = 0
1028 shadow_off = 0
1029 is_branch = op >= 4
1030 if is_branch:
1031 branch_ok, branch_fail = dest
1032 dest = src2
1033 # ok zip up the branch success / fail instructions and
1034 # drop them into the queue, one marked "to have branch success"
1035 # the other to be marked shadow branch "fail".
1036 # one out of each of these will be cancelled
1037 for ok, fl in zip(branch_ok, branch_fail):
1038 if ok:
1039 instrs.append((ok[0], ok[1], ok[2], ok[3], (1, 0)))
1040 if fl:
1041 instrs.append((fl[0], fl[1], fl[2], fl[3], (0, 1)))
1042 print ("instr %d: (%d, %d, %d, %d, (%d, %d))" % \
1043 (i, src1, src2, dest, op, shadow_on, shadow_off))
1044 yield from int_instr(dut, op, src1, src2, dest,
1045 shadow_on, shadow_off)
1046
1047 # wait for all instructions to stop before checking
1048 yield
1049 yield from wait_for_busy_clear(dut)
1050
1051 i = -1
1052 while siminsts:
1053 instr = siminsts.pop(0)
1054 if instr is None:
1055 continue
1056 (src1, src2, dest, op, (shadow_on, shadow_off)) = instr
1057 i += 1
1058 is_branch = op >= 4
1059 if is_branch:
1060 branch_ok, branch_fail = dest
1061 dest = src2
1062 print ("sim %d: (%d, %d, %d, %d, (%d, %d))" % \
1063 (i, src1, src2, dest, op, shadow_on, shadow_off))
1064 branch_res = alusim.op(op, src1, src2, dest)
1065 if is_branch:
1066 if branch_res:
1067 siminsts += branch_ok
1068 else:
1069 siminsts += branch_fail
1070
1071 # check status
1072 yield from alusim.check(dut)
1073 yield from alusim.dump(dut)
1074
1075
1076 def scoreboard_sim(dut, alusim):
1077
1078 seed(0)
1079
1080 for i in range(1):
1081
1082 # set random values in the registers
1083 for i in range(1, dut.n_regs):
1084 val = randint(0, (1<<alusim.rwidth)-1)
1085 #val = 31+i*3
1086 #val = i
1087 yield dut.intregs.regs[i].reg.eq(val)
1088 alusim.setval(i, val)
1089
1090 # create some instructions (some random, some regression tests)
1091 instrs = []
1092 if False:
1093 instrs = create_random_ops(dut, 15, True, 4)
1094
1095 if True: # LD test (with immediate)
1096 instrs.append( (1, 2, 2, 0x10, 1, 20, (0, 0)) )
1097
1098 if False:
1099 instrs.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
1100
1101 if False:
1102 instrs.append( (7, 3, 2, 4, (0, 0)) )
1103 instrs.append( (7, 6, 6, 2, (0, 0)) )
1104 instrs.append( (1, 7, 2, 2, (0, 0)) )
1105
1106 if False:
1107 instrs.append((2, 3, 3, 0, 0, 0, (0, 0)))
1108 instrs.append((5, 3, 3, 1, 0, 0, (0, 0)))
1109 instrs.append((3, 5, 5, 2, 0, 0, (0, 0)))
1110 instrs.append((5, 3, 3, 3, 0, 0, (0, 0)))
1111 instrs.append((3, 5, 5, 0, 0, 0, (0, 0)))
1112
1113 if False:
1114 instrs.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
1115 instrs.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
1116 instrs.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
1117
1118 if False:
1119 instrs.append((5, 6, 2, 1))
1120 instrs.append((2, 2, 4, 0))
1121 #instrs.append((2, 2, 3, 1))
1122
1123 if False:
1124 instrs.append((2, 1, 2, 3))
1125
1126 if False:
1127 instrs.append((2, 6, 2, 1))
1128 instrs.append((2, 1, 2, 0))
1129
1130 if False:
1131 instrs.append((1, 2, 7, 2))
1132 instrs.append((7, 1, 5, 0))
1133 instrs.append((4, 4, 1, 1))
1134
1135 if False:
1136 instrs.append((5, 6, 2, 2))
1137 instrs.append((1, 1, 4, 1))
1138 instrs.append((6, 5, 3, 0))
1139
1140 if False:
1141 # Write-after-Write Hazard
1142 instrs.append( (3, 6, 7, 2) )
1143 instrs.append( (4, 4, 7, 1) )
1144
1145 if False:
1146 # self-read/write-after-write followed by Read-after-Write
1147 instrs.append((1, 1, 1, 1))
1148 instrs.append((1, 5, 3, 0))
1149
1150 if False:
1151 # Read-after-Write followed by self-read-after-write
1152 instrs.append((5, 6, 1, 2))
1153 instrs.append((1, 1, 1, 1))
1154
1155 if False:
1156 # self-read-write sandwich
1157 instrs.append((5, 6, 1, 2))
1158 instrs.append((1, 1, 1, 1))
1159 instrs.append((1, 5, 3, 0))
1160
1161 if False:
1162 # very weird failure
1163 instrs.append( (5, 2, 5, 2) )
1164 instrs.append( (2, 6, 3, 0) )
1165 instrs.append( (4, 2, 2, 1) )
1166
1167 if False:
1168 v1 = 4
1169 yield dut.intregs.regs[5].reg.eq(v1)
1170 alusim.setval(5, v1)
1171 yield dut.intregs.regs[3].reg.eq(5)
1172 alusim.setval(3, 5)
1173 instrs.append((5, 3, 3, 4, (0, 0)))
1174 instrs.append((4, 2, 1, 2, (0, 1)))
1175
1176 if False:
1177 v1 = 6
1178 yield dut.intregs.regs[5].reg.eq(v1)
1179 alusim.setval(5, v1)
1180 yield dut.intregs.regs[3].reg.eq(5)
1181 alusim.setval(3, 5)
1182 instrs.append((5, 3, 3, 4, (0, 0)))
1183 instrs.append((4, 2, 1, 2, (1, 0)))
1184
1185 if False:
1186 instrs.append( (4, 3, 5, 1, 0, (0, 0)) )
1187 instrs.append( (5, 2, 3, 1, 0, (0, 0)) )
1188 instrs.append( (7, 1, 5, 2, 0, (0, 0)) )
1189 instrs.append( (5, 6, 6, 4, 0, (0, 0)) )
1190 instrs.append( (7, 5, 2, 2, 0, (1, 0)) )
1191 instrs.append( (1, 7, 5, 0, 0, (0, 1)) )
1192 instrs.append( (1, 6, 1, 2, 0, (1, 0)) )
1193 instrs.append( (1, 6, 7, 3, 0, (0, 0)) )
1194 instrs.append( (6, 7, 7, 0, 0, (0, 0)) )
1195
1196 # issue instruction(s), wait for issue to be free before proceeding
1197 for i, instr in enumerate(instrs):
1198 src1, src2, dest, op, opi, imm, (br_ok, br_fail) = instr
1199
1200 print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
1201 (i, src1, src2, dest, op, opi, imm))
1202 alusim.op(op, opi, imm, src1, src2, dest)
1203 yield from instr_q(dut, op, opi, imm, src1, src2, dest,
1204 br_ok, br_fail)
1205
1206 # wait for all instructions to stop before checking
1207 while True:
1208 iqlen = yield dut.qlen_o
1209 if iqlen == 0:
1210 break
1211 yield
1212 yield
1213 yield
1214 yield
1215 yield
1216 yield from wait_for_busy_clear(dut)
1217
1218 # check status
1219 yield from alusim.check(dut)
1220 yield from alusim.dump(dut)
1221
1222
1223 def test_scoreboard():
1224 dut = IssueToScoreboard(2, 1, 1, 16, 8, 8)
1225 alusim = RegSim(16, 8)
1226 memsim = MemSim(16, 16)
1227 vl = rtlil.convert(dut, ports=dut.ports())
1228 with open("test_scoreboard6600.il", "w") as f:
1229 f.write(vl)
1230
1231 run_simulation(dut, scoreboard_sim(dut, alusim),
1232 vcd_name='test_scoreboard6600.vcd')
1233
1234 #run_simulation(dut, scoreboard_branch_sim(dut, alusim),
1235 # vcd_name='test_scoreboard6600.vcd')
1236
1237
1238 if __name__ == '__main__':
1239 test_scoreboard()