rename fu-regs rd/wr sel vector
[soc.git] / src / experiment / score6600.py
index f713b403e77c028a175ae6790fef3380c3824ea0..456bb3ebfa07378682b2a1f4422deeb6b26d4117 100644 (file)
@@ -7,16 +7,57 @@ from scoreboard.fu_fu_matrix import FUFUDepMatrix
 from scoreboard.fu_reg_matrix import FURegDepMatrix
 from scoreboard.global_pending import GlobalPending
 from scoreboard.group_picker import GroupPicker
-from scoreboard.issue_unit import IntFPIssueUnit, RegDecode
+from scoreboard.issue_unit import IssueUnitGroup, IssueUnitArray, RegDecode
 from scoreboard.shadow import ShadowMatrix, BranchSpeculationRecord
+from scoreboard.instruction_q import Instruction, InstructionQ
 
 from compalu import ComputationUnitNoDelay
 
 from alu_hier import ALU, BranchALU
 from nmutil.latch import SRLatch
+from nmutil.nmoperator import eq
 
 from random import randint, seed
 from copy import deepcopy
+from math import log
+
+
+class Memory(Elaboratable):
+    def __init__(self, regwid, addrw):
+        self.ddepth = regwid/8
+        depth = (1<<addrw) / self.ddepth
+        self.adr   = Signal(addrw)
+        self.dat_r = Signal(regwid)
+        self.dat_w = Signal(regwid)
+        self.we    = Signal()
+        self.mem   = Memory(width=regwid, depth=depth, init=range(0, depth))
+
+    def elaborate(self, platform):
+        m = Module()
+        m.submodules.rdport = rdport = self.mem.read_port()
+        m.submodules.wrport = wrport = self.mem.write_port()
+        m.d.comb += [
+            rdport.addr.eq(self.adr[self.ddepth:]), # ignore low bits
+            self.dat_r.eq(rdport.data),
+            wrport.addr.eq(self.adr),
+            wrport.data.eq(self.dat_w),
+            wrport.en.eq(self.we),
+        ]
+        return m
+
+
+class MemSim:
+    def __init__(self, regwid, addrw):
+        self.regwid = regwid
+        self.ddepth = regwid//8
+        depth = (1<<addrw) // self.ddepth
+        self.mem = list(range(0, depth))
+
+    def ld(self, addr):
+        return self.mem[addr>>self.ddepth]
+
+    def st(self, addr, data):
+        self.mem[addr>>self.ddepth] = data & ((1<<self.regwid)-1)
 
 
 class CompUnitsBase(Elaboratable):
@@ -52,6 +93,7 @@ class CompUnitsBase(Elaboratable):
         """
         self.units = units
         self.rwid = rwid
+        self.rwid = rwid
         if units and isinstance(units[0], CompUnitsBase):
             self.n_units = 0
             for u in self.units:
@@ -77,13 +119,13 @@ class CompUnitsBase(Elaboratable):
         self.data_o = Signal(rwid, reset_less=True)
         self.src1_i = Signal(rwid, reset_less=True)
         self.src2_i = Signal(rwid, reset_less=True)
+        # input operand
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
 
         for i, alu in enumerate(self.units):
-            print ("elaborate comp%d" % i, self, alu)
             setattr(m.submodules, "comp%d" % i, alu)
 
         go_rd_l = []
@@ -129,11 +171,17 @@ class CompUnitsBase(Elaboratable):
 
 class CompUnitALUs(CompUnitsBase):
 
-    def __init__(self, rwid):
+    def __init__(self, rwid, opwid):
         """ Inputs:
 
             * :rwid:   bit width of register file(s) - both FP and INT
+            * :opwid:  operand bit width
         """
+        self.opwid = opwid
+
+        # inputs
+        self.oper_i = Signal(opwid, reset_less=True)
+        self.imm_i = Signal(rwid, reset_less=True)
 
         # Int ALUs
         add = ALU(rwid)
@@ -143,52 +191,54 @@ class CompUnitALUs(CompUnitsBase):
 
         units = []
         for alu in [add, sub, mul, shf]:
-            units.append(ComputationUnitNoDelay(rwid, 2, alu))
+            aluopwid = 3 # extra bit for immediate mode
+            units.append(ComputationUnitNoDelay(rwid, aluopwid, alu))
 
-        print ("alu units", units)
         CompUnitsBase.__init__(self, rwid, units)
-        print ("alu base init done")
 
     def elaborate(self, platform):
-        print ("alu elaborate start")
         m = CompUnitsBase.elaborate(self, platform)
-        print ("alu elaborate done")
         comb = m.d.comb
 
-        comb += self.units[0].oper_i.eq(Const(0, 2)) # op=add
-        comb += self.units[1].oper_i.eq(Const(1, 2)) # op=sub
-        comb += self.units[2].oper_i.eq(Const(2, 2)) # op=mul
-        comb += self.units[3].oper_i.eq(Const(3, 2)) # op=shf
+        # hand the same operation to all units, only lower 2 bits though
+        for alu in self.units:
+            comb += alu.oper_i[0:3].eq(self.oper_i)
+            comb += alu.imm_i.eq(self.imm_i)
 
         return m
 
 
 class CompUnitBR(CompUnitsBase):
 
-    def __init__(self, rwid):
+    def __init__(self, rwid, opwid):
         """ Inputs:
 
             * :rwid:   bit width of register file(s) - both FP and INT
+            * :opwid:  operand bit width
 
             Note: bgt unit is returned so that a shadow unit can be created
             for it
-
         """
+        self.opwid = opwid
+
+        # inputs
+        self.oper_i = Signal(opwid, reset_less=True)
+        self.imm_i = Signal(rwid, reset_less=True)
 
         # Branch ALU and CU
         self.bgt = BranchALU(rwid)
-        self.br1 = ComputationUnitNoDelay(rwid, 3, self.bgt)
-        print ("br units", [self.br1])
+        aluopwid = 3 # extra bit for immediate mode
+        self.br1 = ComputationUnitNoDelay(rwid, aluopwid, self.bgt)
         CompUnitsBase.__init__(self, rwid, [self.br1])
-        print ("br base init done")
 
     def elaborate(self, platform):
-        print ("br elaborate start")
         m = CompUnitsBase.elaborate(self, platform)
-        print ("br elaborate done")
         comb = m.d.comb
 
-        comb += self.br1.oper_i.eq(Const(4, 3)) # op=bgt
+        # hand the same operation to all units
+        for alu in self.units:
+            comb += alu.oper_i.eq(self.oper_i)
+            comb += alu.imm_i.eq(self.imm_i)
 
         return m
 
@@ -227,20 +277,20 @@ class FunctionUnits(Elaboratable):
         comb = m.d.comb
         sync = m.d.sync
 
-        n_int_fus = self.n_int_alus
+        n_intfus = self.n_int_alus
 
         # Integer FU-FU Dep Matrix
-        intfudeps = FUFUDepMatrix(n_int_fus, n_int_fus)
+        intfudeps = FUFUDepMatrix(n_intfus, n_intfus)
         m.submodules.intfudeps = intfudeps
         # Integer FU-Reg Dep Matrix
-        intregdeps = FURegDepMatrix(n_int_fus, self.n_regs)
+        intregdeps = FURegDepMatrix(n_intfus, self.n_regs)
         m.submodules.intregdeps = intregdeps
 
-        comb += self.g_int_rd_pend_o.eq(intregdeps.rd_rsel_o)
-        comb += self.g_int_wr_pend_o.eq(intregdeps.wr_rsel_o)
+        comb += self.g_int_rd_pend_o.eq(intregdeps.v_rd_rsel_o)
+        comb += self.g_int_wr_pend_o.eq(intregdeps.v_wr_rsel_o)
 
-        comb += intregdeps.rd_pend_i.eq(intregdeps.rd_rsel_o)
-        comb += intregdeps.wr_pend_i.eq(intregdeps.wr_rsel_o)
+        comb += intregdeps.rd_pend_i.eq(intregdeps.v_rd_rsel_o)
+        comb += intregdeps.wr_pend_i.eq(intregdeps.v_wr_rsel_o)
 
         comb += intfudeps.rd_pend_i.eq(intregdeps.rd_pend_o)
         comb += intfudeps.wr_pend_i.eq(intregdeps.wr_pend_o)
@@ -284,6 +334,15 @@ class Scoreboard(Elaboratable):
         self.intregs = RegFileArray(rwid, n_regs)
         self.fpregs = RegFileArray(rwid, n_regs)
 
+        # issue q needs to get at these
+        self.aluissue = IssueUnitGroup(4)
+        self.brissue = IssueUnitGroup(1)
+        # and these
+        self.alu_oper_i = Signal(4, reset_less=True)
+        self.alu_imm_i = Signal(rwid, reset_less=True)
+        self.br_oper_i = Signal(4, reset_less=True)
+        self.br_imm_i = Signal(rwid, reset_less=True)
+
         # inputs
         self.int_dest_i = Signal(max=n_regs, reset_less=True) # Dest R# in
         self.int_src1_i = Signal(max=n_regs, reset_less=True) # oper1 R# in
@@ -321,8 +380,8 @@ class Scoreboard(Elaboratable):
 
         # Int ALUs and Comp Units
         n_int_alus = 5
-        cua = CompUnitALUs(self.rwid)
-        cub = CompUnitBR(self.rwid)
+        cua = CompUnitALUs(self.rwid, 3)
+        cub = CompUnitBR(self.rwid, 3)
         m.submodules.cu = cu = CompUnitsBase(self.rwid, [cua, cub])
         bgt = cub.bgt # get at the branch computation unit
         br1 = cub.br1
@@ -331,33 +390,32 @@ class Scoreboard(Elaboratable):
         m.submodules.intfus = intfus = FunctionUnits(self.n_regs, n_int_alus)
 
         # Count of number of FUs
-        n_int_fus = n_int_alus
+        n_intfus = n_int_alus
         n_fp_fus = 0 # for now
 
         # Integer Priority Picker 1: Adder + Subtractor
-        intpick1 = GroupPicker(n_int_fus) # picks between add, sub, mul and shf
+        intpick1 = GroupPicker(n_intfus) # picks between add, sub, mul and shf
         m.submodules.intpick1 = intpick1
 
         # INT/FP Issue Unit
         regdecode = RegDecode(self.n_regs)
         m.submodules.regdecode = regdecode
-        issueunit = IntFPIssueUnit(n_int_fus, n_fp_fus)
+        issueunit = IssueUnitArray([self.aluissue, self.brissue])
         m.submodules.issueunit = issueunit
 
-        # Shadow Matrix.  currently n_int_fus shadows, to be used for
+        # Shadow Matrix.  currently n_intfus shadows, to be used for
         # write-after-write hazards.  NOTE: there is one extra for branches,
         # so the shadow width is increased by 1
-        m.submodules.shadows = shadows = ShadowMatrix(n_int_fus, n_int_fus, True)
-        m.submodules.bshadow = bshadow = ShadowMatrix(n_int_fus, 1, False)
+        m.submodules.shadows = shadows = ShadowMatrix(n_intfus, n_intfus, True)
+        m.submodules.bshadow = bshadow = ShadowMatrix(n_intfus, 1, False)
 
         # record previous instruction to cast shadow on current instruction
-        fn_issue_prev = Signal(n_int_fus)
-        prev_shadow = Signal(n_int_fus)
+        prev_shadow = Signal(n_intfus)
 
         # Branch Speculation recorder.  tracks the success/fail state as
         # each instruction is issued, so that when the branch occurs the
         # allow/cancel can be issued as appropriate.
-        m.submodules.specrec = bspec = BranchSpeculationRecord(n_int_fus)
+        m.submodules.specrec = bspec = BranchSpeculationRecord(n_intfus)
 
         #---------
         # ok start wiring things together...
@@ -374,7 +432,12 @@ class Scoreboard(Elaboratable):
                      regdecode.enable_i.eq(self.reg_enable_i),
                      self.issue_o.eq(issueunit.issue_o)
                     ]
-        self.int_insn_i = issueunit.i.insn_i # enabled by instruction decode
+
+        # take these to outside (issue needs them)
+        comb += cua.oper_i.eq(self.alu_oper_i)
+        comb += cua.imm_i.eq(self.alu_imm_i)
+        comb += cub.oper_i.eq(self.br_oper_i)
+        comb += cub.imm_i.eq(self.br_imm_i)
 
         # TODO: issueunit.f (FP)
 
@@ -383,21 +446,21 @@ class Scoreboard(Elaboratable):
         comb += intfus.src1_i.eq(regdecode.src1_o)
         comb += intfus.src2_i.eq(regdecode.src2_o)
 
-        fn_issue_o = issueunit.i.fn_issue_o
+        fn_issue_o = issueunit.fn_issue_o
 
         comb += intfus.fn_issue_i.eq(fn_issue_o)
-        comb += issueunit.i.busy_i.eq(cu.busy_o)
+        comb += issueunit.busy_i.eq(cu.busy_o)
         comb += self.busy_o.eq(cu.busy_o.bool())
 
         #---------
         # merge shadow matrices outputs
         #---------
-        
+
         # these are explained in ShadowMatrix docstring, and are to be
         # connected to the FUReg and FUFU Matrices, to get them to reset
-        anydie = Signal(n_int_fus, reset_less=True)
-        allshadown = Signal(n_int_fus, reset_less=True)
-        shreset = Signal(n_int_fus, reset_less=True)
+        anydie = Signal(n_intfus, reset_less=True)
+        allshadown = Signal(n_intfus, reset_less=True)
+        shreset = Signal(n_intfus, reset_less=True)
         comb += allshadown.eq(shadows.shadown_o & bshadow.shadown_o)
         comb += anydie.eq(shadows.go_die_o | bshadow.go_die_o)
         comb += shreset.eq(bspec.match_g_o | bspec.match_f_o)
@@ -413,32 +476,32 @@ class Scoreboard(Elaboratable):
         go_wr_i = intfus.go_wr_i
         go_die_i = intfus.go_die_i
         # NOTE: connect to the shadowed versions so that they can "die" (reset)
-        comb += go_rd_i[0:n_int_fus].eq(go_rd_o[0:n_int_fus]) # rd
-        comb += go_wr_i[0:n_int_fus].eq(go_wr_o[0:n_int_fus]) # wr
-        comb += go_die_i[0:n_int_fus].eq(anydie[0:n_int_fus]) # die
+        comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd
+        comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr
+        comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die
 
         # Connect Picker
         #---------
-        comb += intpick1.rd_rel_i[0:n_int_fus].eq(cu.rd_rel_o[0:n_int_fus])
-        comb += intpick1.req_rel_i[0:n_int_fus].eq(cu.req_rel_o[0:n_int_fus])
+        comb += intpick1.rd_rel_i[0:n_intfus].eq(cu.rd_rel_o[0:n_intfus])
+        comb += intpick1.req_rel_i[0:n_intfus].eq(cu.req_rel_o[0:n_intfus])
         int_rd_o = intfus.readable_o
         int_wr_o = intfus.writable_o
-        comb += intpick1.readable_i[0:n_int_fus].eq(int_rd_o[0:n_int_fus])
-        comb += intpick1.writable_i[0:n_int_fus].eq(int_wr_o[0:n_int_fus])
+        comb += intpick1.readable_i[0:n_intfus].eq(int_rd_o[0:n_intfus])
+        comb += intpick1.writable_i[0:n_intfus].eq(int_wr_o[0:n_intfus])
 
         #---------
         # Shadow Matrix
         #---------
 
         comb += shadows.issue_i.eq(fn_issue_o)
-        #comb += shadows.reset_i[0:n_int_fus].eq(bshadow.go_die_o[0:n_int_fus])
-        comb += shadows.reset_i[0:n_int_fus].eq(bshadow.go_die_o[0:n_int_fus])
+        #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
+        comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus])
         #---------
         # NOTE; this setup is for the instruction order preservation...
 
         # connect shadows / go_dies to Computation Units
-        comb += cu.shadown_i[0:n_int_fus].eq(allshadown)
-        comb += cu.go_die_i[0:n_int_fus].eq(anydie)
+        comb += cu.shadown_i[0:n_intfus].eq(allshadown)
+        comb += cu.go_die_i[0:n_intfus].eq(anydie)
 
         # ok connect first n_int_fu shadows to busy lines, to create an
         # instruction-order linked-list-like arrangement, using a bit-matrix
@@ -446,26 +509,22 @@ class Scoreboard(Elaboratable):
         # XXX TODO
 
         # when written, the shadow can be cancelled (and was good)
-        for i in range(n_int_fus):
-            comb += shadows.s_good_i[i][0:n_int_fus].eq(go_wr_o[0:n_int_fus])
-
-        # work out the current-activated busy unit (by recording the old one)
-        with m.If(fn_issue_o): # only update prev bit if instruction issued
-            sync += fn_issue_prev.eq(fn_issue_o)
+        for i in range(n_intfus):
+            comb += shadows.s_good_i[i][0:n_intfus].eq(go_wr_o[0:n_intfus])
 
         # *previous* instruction shadows *current* instruction, and, obviously,
         # if the previous is completed (!busy) don't cast the shadow!
         comb += prev_shadow.eq(~fn_issue_o & cu.busy_o)
-        for i in range(n_int_fus):
-            comb += shadows.shadow_i[i][0:n_int_fus].eq(prev_shadow)
+        for i in range(n_intfus):
+            comb += shadows.shadow_i[i][0:n_intfus].eq(prev_shadow)
 
         #---------
         # ... and this is for branch speculation.  it uses the extra bit
-        # tacked onto the ShadowMatrix (hence shadow_wid=n_int_fus+1)
+        # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1)
         # only needs to set shadow_i, s_fail_i and s_good_i
 
         # issue captures shadow_i (if enabled)
-        comb += bshadow.reset_i[0:n_int_fus].eq(shreset[0:n_int_fus])
+        comb += bshadow.reset_i[0:n_intfus].eq(shreset[0:n_intfus])
 
         bactive = Signal(reset_less=True)
         comb += bactive.eq((bspec.active_i | br1.issue_i) & ~br1.go_wr_i)
@@ -473,7 +532,7 @@ class Scoreboard(Elaboratable):
         # instruction being issued (fn_issue_o) has a shadow cast by the branch
         with m.If(bactive & (self.branch_succ_i | self.branch_fail_i)):
             comb += bshadow.issue_i.eq(fn_issue_o)
-            for i in range(n_int_fus):
+            for i in range(n_intfus):
                 with m.If(fn_issue_o & (Const(1<<i))):
                     comb += bshadow.shadow_i[i][0].eq(1)
 
@@ -496,7 +555,7 @@ class Scoreboard(Elaboratable):
             comb += bspec.br_i.eq(1)
             # branch occurs if data == 1, failed if data == 0
             comb += bspec.br_ok_i.eq(br1.data_o == 1)
-            for i in range(n_int_fus):
+            for i in range(n_intfus):
                 # *expected* direction of the branch matched against *actual*
                 comb += bshadow.s_good_i[i][0].eq(bspec.match_g_o[i])
                 # ... or it didn't
@@ -505,7 +564,6 @@ class Scoreboard(Elaboratable):
         #---------
         # Connect Register File(s)
         #---------
-        print ("intregdeps wen len", len(intfus.dest_rsel_o))
         comb += int_dest.wen.eq(intfus.dest_rsel_o)
         comb += int_src1.ren.eq(intfus.src1_rsel_o)
         comb += int_src2.ren.eq(intfus.src2_rsel_o)
@@ -516,13 +574,12 @@ class Scoreboard(Elaboratable):
         comb += cu.src2_i.eq(int_src2.data_o)
 
         # connect ALU Computation Units
-        comb += cu.go_rd_i[0:n_int_fus].eq(go_rd_o[0:n_int_fus])
-        comb += cu.go_wr_i[0:n_int_fus].eq(go_wr_o[0:n_int_fus])
-        comb += cu.issue_i[0:n_int_fus].eq(fn_issue_o[0:n_int_fus])
+        comb += cu.go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus])
+        comb += cu.go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus])
+        comb += cu.issue_i[0:n_intfus].eq(fn_issue_o[0:n_intfus])
 
         return m
 
-
     def __iter__(self):
         yield from self.intregs
         yield from self.fpregs
@@ -537,6 +594,115 @@ class Scoreboard(Elaboratable):
     def ports(self):
         return list(self)
 
+
+class IssueToScoreboard(Elaboratable):
+
+    def __init__(self, qlen, n_in, n_out, rwid, opwid, n_regs):
+        self.qlen = qlen
+        self.n_in = n_in
+        self.n_out = n_out
+        self.rwid = rwid
+        self.opw = opwid
+        self.n_regs = n_regs
+
+        mqbits = (int(log(qlen) / log(2))+2, False)
+        self.p_add_i = Signal(mqbits) # instructions to add (from data_i)
+        self.p_ready_o = Signal() # instructions were added
+        self.data_i = Instruction.nq(n_in, "data_i", rwid, opwid)
+
+        self.busy_o = Signal(reset_less=True) # at least one CU is busy
+        self.qlen_o = Signal(mqbits, reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        sync = m.d.sync
+
+        iq = InstructionQ(self.rwid, self.opw, self.qlen, self.n_in, self.n_out)
+        sc = Scoreboard(self.rwid, self.n_regs)
+        m.submodules.iq = iq
+        m.submodules.sc = sc
+
+        # get at the regfile for testing
+        self.intregs = sc.intregs
+
+        # and the "busy" signal and instruction queue length
+        comb += self.busy_o.eq(sc.busy_o)
+        comb += self.qlen_o.eq(iq.qlen_o)
+
+        # link up instruction queue
+        comb += iq.p_add_i.eq(self.p_add_i)
+        comb += self.p_ready_o.eq(iq.p_ready_o)
+        for i in range(self.n_in):
+            comb += eq(iq.data_i[i], self.data_i[i])
+
+        # take instruction and process it.  note that it's possible to
+        # "inspect" the queue contents *without* actually removing the
+        # items.  items are only removed when the
+
+        # in "waiting" state
+        wait_issue_br = Signal()
+        wait_issue_alu = Signal()
+
+        with m.If(wait_issue_br | wait_issue_alu):
+            # set instruction pop length to 1 if the unit accepted
+            with m.If(wait_issue_br & (sc.brissue.fn_issue_o != 0)):
+                with m.If(iq.qlen_o != 0):
+                    comb += iq.n_sub_i.eq(1)
+            with m.If(wait_issue_alu & (sc.aluissue.fn_issue_o != 0)):
+                with m.If(iq.qlen_o != 0):
+                    comb += iq.n_sub_i.eq(1)
+
+        # see if some instruction(s) are here.  note that this is
+        # "inspecting" the in-place queue.  note also that on the
+        # cycle following "waiting" for fn_issue_o to be set, the
+        # "resetting" done above (insn_i=0) could be re-ASSERTed.
+        with m.If(iq.qlen_o != 0):
+            # get the operands and operation
+            imm = iq.data_o[0].imm_i
+            dest = iq.data_o[0].dest_i
+            src1 = iq.data_o[0].src1_i
+            src2 = iq.data_o[0].src2_i
+            op = iq.data_o[0].oper_i
+            opi = iq.data_o[0].opim_i # immediate set
+
+            # set the src/dest regs
+            comb += sc.int_dest_i.eq(dest)
+            comb += sc.int_src1_i.eq(src1)
+            comb += sc.int_src2_i.eq(src2)
+            comb += sc.reg_enable_i.eq(1) # enable the regfile
+
+            # choose a Function-Unit-Group
+            with m.If((op & (0x3<<2)) != 0): # branch
+                comb += sc.brissue.insn_i.eq(1)
+                comb += sc.br_oper_i.eq(Cat(op[0:2], opi))
+                comb += sc.br_imm_i.eq(imm)
+                comb += wait_issue_br.eq(1)
+            with m.Else():                   # alu
+                comb += sc.aluissue.insn_i.eq(1)
+                comb += sc.alu_oper_i.eq(Cat(op[0:2], opi))
+                comb += sc.alu_imm_i.eq(imm)
+                comb += wait_issue_alu.eq(1)
+
+            # XXX TODO
+            # these indicate that the instruction is to be made
+            # shadow-dependent on
+            # (either) branch success or branch fail
+            #yield sc.branch_fail_i.eq(branch_fail)
+            #yield sc.branch_succ_i.eq(branch_success)
+
+        return m
+
+    def __iter__(self):
+        yield self.p_ready_o
+        for o in self.data_i:
+            yield from list(o)
+        yield self.p_add_i
+
+    def ports(self):
+        return list(self)
+
+
 IADD = 0
 ISUB = 1
 IMUL = 2
@@ -551,10 +717,13 @@ class RegSim:
         self.rwidth = rwidth
         self.regs = [0] * nregs
 
-    def op(self, op, src1, src2, dest):
+    def op(self, op, op_imm, imm, src1, src2, dest):
         maxbits = (1 << self.rwidth) - 1
         src1 = self.regs[src1] & maxbits
-        src2 = self.regs[src2] & maxbits
+        if op_imm:
+            src2 = imm
+        else:
+            src2 = self.regs[src2] & maxbits
         if op == IADD:
             val = src1 + src2
         elif op == ISUB:
@@ -593,13 +762,41 @@ class RegSim:
                 yield from self.dump(dut)
                 assert False
 
-def int_instr(dut, op, src1, src2, dest, branch_success, branch_fail):
-    for i in range(len(dut.int_insn_i)):
-        yield dut.int_insn_i[i].eq(0)
+def instr_q(dut, op, op_imm, imm, src1, src2, dest,
+            branch_success, branch_fail):
+    instrs = [{'oper_i': op, 'dest_i': dest, 'imm_i': imm, 'opim_i': op_imm,
+               'src1_i': src1, 'src2_i': src2}]
+
+    sendlen = 1
+    for idx in range(sendlen):
+        yield from eq(dut.data_i[idx], instrs[idx])
+        di = yield dut.data_i[idx]
+        print ("senddata %d %x" % (idx, di))
+    yield dut.p_add_i.eq(sendlen)
+    yield
+    o_p_ready = yield dut.p_ready_o
+    while not o_p_ready:
+        yield
+        o_p_ready = yield dut.p_ready_o
+
+    yield dut.p_add_i.eq(0)
+
+
+def int_instr(dut, op, imm, src1, src2, dest, branch_success, branch_fail):
+    yield from disable_issue(dut)
     yield dut.int_dest_i.eq(dest)
     yield dut.int_src1_i.eq(src1)
     yield dut.int_src2_i.eq(src2)
-    yield dut.int_insn_i[op].eq(1)
+    if (op & (0x3<<2)) != 0: # branch
+        yield dut.brissue.insn_i.eq(1)
+        yield dut.br_oper_i.eq(Const(op & 0x3, 2))
+        yield dut.br_imm_i.eq(imm)
+        dut_issue = dut.brissue
+    else:
+        yield dut.aluissue.insn_i.eq(1)
+        yield dut.alu_oper_i.eq(Const(op & 0x3, 2))
+        yield dut.alu_imm_i.eq(imm)
+        dut_issue = dut.aluissue
     yield dut.reg_enable_i.eq(1)
 
     # these indicate that the instruction is to be made shadow-dependent on
@@ -607,6 +804,9 @@ def int_instr(dut, op, src1, src2, dest, branch_success, branch_fail):
     yield dut.branch_fail_i.eq(branch_fail)
     yield dut.branch_succ_i.eq(branch_success)
 
+    yield
+    yield from wait_for_issue(dut, dut_issue)
+
 
 def print_reg(dut, rnums):
     rs = []
@@ -622,13 +822,15 @@ def create_random_ops(dut, n_ops, shadowing=False, max_opnums=3):
     for i in range(n_ops):
         src1 = randint(1, dut.n_regs-1)
         src2 = randint(1, dut.n_regs-1)
+        imm = randint(1, (1<<dut.rwid)-1)
         dest = randint(1, dut.n_regs-1)
         op = randint(0, max_opnums)
+        opi = 0 if randint(0, 2) else 1 # set true if random is nonzero
 
         if shadowing:
-            insts.append((src1, src2, dest, op, (0, 0)))
+            insts.append((src1, src2, dest, op, opi, imm, (0, 0)))
         else:
-            insts.append((src1, src2, dest, op))
+            insts.append((src1, src2, dest, op, opi, imm))
     return insts
 
 
@@ -640,16 +842,19 @@ def wait_for_busy_clear(dut):
         print ("busy",)
         yield
 
+def disable_issue(dut):
+    yield dut.aluissue.insn_i.eq(0)
+    yield dut.brissue.insn_i.eq(0)
+
 
-def wait_for_issue(dut):
+def wait_for_issue(dut, dut_issue):
     while True:
-        issue_o = yield dut.issue_o
+        issue_o = yield dut_issue.fn_issue_o
         if issue_o:
-            for i in range(len(dut.int_insn_i)):
-                yield dut.int_insn_i[i].eq(0)
-                yield dut.reg_enable_i.eq(0)
+            yield from disable_issue(dut)
+            yield dut.reg_enable_i.eq(0)
             break
-        #print ("busy",)
+        print ("busy",)
         #yield from print_reg(dut, [1,2,3])
         yield
     #yield from print_reg(dut, [1,2,3])
@@ -691,11 +896,11 @@ def scoreboard_branch_sim(dut, alusim):
 
         if True:
             insts = []
-            #insts.append( (3, 5, 2, 0, (0, 0)) )
+            insts.append( (3, 5, 2, 0, (0, 0)) )
             branch_ok = []
             branch_fail = []
-            branch_ok.append  ( (5, 7, 5, 1, (1, 0)) )
-            #branch_ok.append( None )
+            #branch_ok.append  ( (5, 7, 5, 1, (1, 0)) )
+            branch_ok.append( None )
             branch_fail.append( (1, 1, 2, 0, (0, 1)) )
             #branch_fail.append( None )
             insts.append( (6, 4, (branch_ok, branch_fail), 4, (0, 0)) )
@@ -738,8 +943,6 @@ def scoreboard_branch_sim(dut, alusim):
                             (i, src1, src2, dest, op, shadow_on, shadow_off))
             yield from int_instr(dut, op, src1, src2, dest,
                                  shadow_on, shadow_off)
-            yield
-            yield from wait_for_issue(dut)
 
         # wait for all instructions to stop before checking
         yield
@@ -774,23 +977,40 @@ def scoreboard_sim(dut, alusim):
 
     seed(0)
 
-    for i in range(20):
+    for i in range(50):
 
         # set random values in the registers
         for i in range(1, dut.n_regs):
-            val = 31+i*3
             val = randint(0, (1<<alusim.rwidth)-1)
+            #val = 31+i*3
+            #val = i
             yield dut.intregs.regs[i].reg.eq(val)
             alusim.setval(i, val)
 
         # create some instructions (some random, some regression tests)
         instrs = []
         if True:
-            instrs = create_random_ops(dut, 10, True, 4)
+            instrs = create_random_ops(dut, 15, True, 4)
+
+        if False:
+            instrs.append( (1, 2, 2, 1, 1, 20, (0, 0)) )
+
+        if False:
+            instrs.append( (7, 3, 2, 4, (0, 0)) )
+            instrs.append( (7, 6, 6, 2, (0, 0)) )
+            instrs.append( (1, 7, 2, 2, (0, 0)) )
+
+        if False:
+            instrs.append((2, 3, 3, 0, 0, 0, (0, 0)))
+            instrs.append((5, 3, 3, 1, 0, 0, (0, 0)))
+            instrs.append((3, 5, 5, 2, 0, 0, (0, 0)))
+            instrs.append((5, 3, 3, 3, 0, 0, (0, 0)))
+            instrs.append((3, 5, 5, 0, 0, 0, (0, 0)))
 
         if False:
-            instrs.append((2, 3, 3, 0))
-            instrs.append((5, 3, 3, 1))
+            instrs.append( (3, 3, 4, 0, 0, 13979, (0, 0)))
+            instrs.append( (6, 4, 1, 2, 0, 40976, (0, 0)))
+            instrs.append( (1, 4, 7, 4, 1, 23652, (0, 0)))
 
         if False:
             instrs.append((5, 6, 2, 1))
@@ -860,26 +1080,35 @@ def scoreboard_sim(dut, alusim):
             instrs.append((4, 2, 1, 2, (1, 0)))
 
         if False:
-            instrs.append( (4, 3, 5, 1, (0, 0)) )
-            instrs.append( (5, 2, 3, 1, (0, 0)) )
-            instrs.append( (7, 1, 5, 2, (0, 0)) )
-            instrs.append( (5, 6, 6, 4, (0, 0)) )
-            instrs.append( (7, 5, 2, 2, (1, 0)) )
-            instrs.append( (1, 7, 5, 0, (0, 1)) )
-            instrs.append( (1, 6, 1, 2, (1, 0)) )
-            instrs.append( (1, 6, 7, 3, (0, 0)) )
-            instrs.append( (6, 7, 7, 0, (0, 0)) )
+            instrs.append( (4, 3, 5, 1, 0, (0, 0)) )
+            instrs.append( (5, 2, 3, 1, 0, (0, 0)) )
+            instrs.append( (7, 1, 5, 2, 0, (0, 0)) )
+            instrs.append( (5, 6, 6, 4, 0, (0, 0)) )
+            instrs.append( (7, 5, 2, 2, 0, (1, 0)) )
+            instrs.append( (1, 7, 5, 0, 0, (0, 1)) )
+            instrs.append( (1, 6, 1, 2, 0, (1, 0)) )
+            instrs.append( (1, 6, 7, 3, 0, (0, 0)) )
+            instrs.append( (6, 7, 7, 0, 0, (0, 0)) )
 
         # issue instruction(s), wait for issue to be free before proceeding
-        for i, (src1, src2, dest, op, (br_ok, br_fail)) in enumerate(instrs):
+        for i, instr in enumerate(instrs):
+            src1, src2, dest, op, opi, imm, (br_ok, br_fail) = instr
 
-            print ("instr %d: (%d, %d, %d, %d)" % (i, src1, src2, dest, op))
-            alusim.op(op, src1, src2, dest)
-            yield from int_instr(dut, op, src1, src2, dest, br_ok, br_fail)
-            yield
-            yield from wait_for_issue(dut)
+            print ("instr %d: (%d, %d, %d, %d, %d, %d)" % \
+                    (i, src1, src2, dest, op, opi, imm))
+            alusim.op(op, opi, imm, src1, src2, dest)
+            yield from instr_q(dut, op, opi, imm, src1, src2, dest,
+                               br_ok, br_fail)
 
         # wait for all instructions to stop before checking
+        while True:
+            iqlen = yield dut.qlen_o
+            if iqlen == 0:
+                break
+            yield
+        yield
+        yield
+        yield
         yield
         yield from wait_for_busy_clear(dut)
 
@@ -889,8 +1118,9 @@ def scoreboard_sim(dut, alusim):
 
 
 def test_scoreboard():
-    dut = Scoreboard(16, 8)
+    dut = IssueToScoreboard(2, 1, 1, 16, 8, 8)
     alusim = RegSim(16, 8)
+    memsim = MemSim(16, 16)
     vl = rtlil.convert(dut, ports=dut.ports())
     with open("test_scoreboard6600.il", "w") as f:
         f.write(vl)