experimenting with overlapping instructions, bit of a mess
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 18 Nov 2021 22:52:34 +0000 (22:52 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 18 Nov 2021 22:52:34 +0000 (22:52 +0000)
src/soc/simple/core.py
src/soc/simple/issuer.py

index b7e64c39afd5bc6dbe07cdbf9c4a59026c820c5e..bea7060a87243503faa07fb56598c342e79d8866 100644 (file)
@@ -247,6 +247,7 @@ class NonProductionCore(ControlBase):
         # or if the instruction could not be delivered, keep dropping the
         # latched copy into ireg
         ilatch = self.ispec()
+        instruction_active = Signal()
 
         # enable/busy-signals for each FU, get one bit for each FU (by name)
         fu_enable = Signal(len(fus), reset_less=True)
@@ -289,7 +290,7 @@ class NonProductionCore(ControlBase):
                 fnunit = fu.fnunit.value
                 en_req = Signal(name="issue_en_%s" % funame, reset_less=True)
                 fnmatch = (self.ireg.e.do.fn_unit & fnunit).bool()
-                comb += en_req.eq(fnmatch & ~fu.busy_o & self.p.i_valid)
+                comb += en_req.eq(fnmatch & ~fu.busy_o & instruction_active)
                 i_l.append(en_req) # store in list for doing the Cat-trick
                 # picker output, gated by enable: store in fu_bitdict
                 po = Signal(name="o_issue_pick_"+funame) # picker output
@@ -315,6 +316,9 @@ class NonProductionCore(ControlBase):
         comb += self.ireg.eq(self.i)
         # always say "ready" except if overridden
         comb += self.p.o_ready.eq(1)
+        comb += instruction_active.eq(1)
+
+        l_issue_conflict = Signal()
 
         with m.FSM():
             with m.State("READY"):
@@ -353,31 +357,39 @@ class NonProductionCore(ControlBase):
                             with m.If(~fu_found):
                                 # latch copy of instruction
                                 sync += ilatch.eq(self.i)
+                                sync += l_issue_conflict.eq(issue_conflict)
                                 comb += self.p.o_ready.eq(1) # accept
+                                comb += busy_o.eq(1)
                                 m.next = "WAITING"
 
             with m.State("WAITING"):
+                comb += instruction_active.eq(1)
+                with m.If(fu_found):
+                    sync += l_issue_conflict.eq(0)
                 comb += self.p.o_ready.eq(0)
+                comb += busy_o.eq(1)
                 # using copy of instruction, keep waiting until an FU is free
                 comb += self.ireg.eq(ilatch)
-                # connect instructions. only one enabled at a time
-                for funame, fu in fus.items():
-                    do = self.des[funame]
-                    enable = fu_bitdict[funame]
-
-                    # run this FunctionUnit if enabled route op,
-                    # issue, busy, read flags and mask to FU
-                    with m.If(enable):
-                        # operand comes from the *local*  decoder
-                        comb += fu.oper_i.eq_from(do)
-                        comb += fu.issue_i.eq(1) # issue when valid
-                        # rdmask, which is for registers,
-                        # needs to come
-                        # from the *main* decoder
-                        rdmask = get_rdflags(self.ireg.e, fu)
-                        comb += fu.rdmaskn.eq(~rdmask)
-                        comb += self.p.o_ready.eq(1)
-                        m.next = "READY"
+                with m.If(~l_issue_conflict): # wait for conflict to clear
+                    # connect instructions. only one enabled at a time
+                    for funame, fu in fus.items():
+                        do = self.des[funame]
+                        enable = fu_bitdict[funame]
+
+                        # run this FunctionUnit if enabled route op,
+                        # issue, busy, read flags and mask to FU
+                        with m.If(enable):
+                            # operand comes from the *local*  decoder
+                            comb += fu.oper_i.eq_from(do)
+                            comb += fu.issue_i.eq(1) # issue when valid
+                            # rdmask, which is for registers,
+                            # needs to come
+                            # from the *main* decoder
+                            rdmask = get_rdflags(self.ireg.e, fu)
+                            comb += fu.rdmaskn.eq(~rdmask)
+                            comb += self.p.o_ready.eq(1)
+                            comb += busy_o.eq(0)
+                            m.next = "READY"
 
         print ("core: overlap allowed", self.allow_overlap)
         if not self.allow_overlap:
@@ -385,10 +397,6 @@ class NonProductionCore(ControlBase):
             # busy output for core.
             busys = map(lambda fu: fu.busy_o, fus.values())
             comb += busy_o.eq(Cat(*busys).bool())
-        else:
-            # for the overlap case, only set busy if an FU is not found,
-            # and an FU will not be found if the write hazards are blocked
-            comb += busy_o.eq(~fu_found | issue_conflict)
 
         # return both the function unit "enable" dict as well as the "busy".
         # the "busy-or-issued" can be passed in to the Read/Write port
index 24830149a606a981f08e697e489a658fd7cea892..049cdb2d57e778f51d4934d0605746ce16193346 100644 (file)
@@ -861,7 +861,7 @@ class TestIssuerInternal(Elaboratable):
         pdecode2 = self.pdecode2
 
         # temporaries
-        core_busy_o = ~core.p.o_ready | core.n.o_data.busy_o # core is busy
+        core_busy_o = core.n.o_data.busy_o # core is busy
         core_ivalid_i = core.p.i_valid              # instruction is valid
 
         with m.FSM(name="exec_fsm"):
@@ -873,7 +873,8 @@ class TestIssuerInternal(Elaboratable):
                     comb += core_ivalid_i.eq(1)  # instruction is valid/issued
                     sync += sv_changed.eq(0)
                     sync += pc_changed.eq(0)
-                    m.next = "INSN_ACTIVE"  # move to "wait completion"
+                    with m.If(core.p.o_ready): # only move if accepted
+                        m.next = "INSN_ACTIVE"  # move to "wait completion"
 
             # instruction started: must wait till it finishes
             with m.State("INSN_ACTIVE"):