add msr_o to issuer in microwatt_compat mode
[soc.git] / src / soc / simple / issuer.py
index 2fafc6626b315e84b88ef3e00fd77d068818a3c8..7f1ae097a887d7ae68bc2c832375bb0c2f3e9160 100644 (file)
@@ -285,7 +285,7 @@ class TestIssuerBase(Elaboratable):
         self.state_r_pc = staterf.r_ports['cia']  # PC rd
         self.state_r_sv = staterf.r_ports['sv']  # SVSTATE rd
 
-        self.state_w_msr = staterf.w_ports['msr']  # MSR wr
+        self.state_w_msr = staterf.w_ports['d_wr2']  # MSR wr
         self.state_w_pc = staterf.w_ports['d_wr1']  # PC wr
         self.state_w_sv = staterf.w_ports['sv']  # SVSTATE wr
 
@@ -317,6 +317,19 @@ class TestIssuerBase(Elaboratable):
             self.srcmask = Signal(64)
             self.dstmask = Signal(64)
 
+        # sigh, the wishbone addresses are not wishbone-compliant in microwatt
+        if self.microwatt_compat:
+            self.ibus_adr = Signal(32, name='wishbone_insn_out.adr')
+            self.dbus_adr = Signal(32, name='wishbone_data_out.adr')
+
+        # add an output of the PC and instruction, and whether it was requested
+        # this is for verilator debug purposes
+        if self.microwatt_compat:
+            self.nia = Signal(64)
+            self.msr_o = Signal(64)
+            self.nia_req = Signal(1)
+            self.insn = Signal(32)
+
     def setup_peripherals(self, m):
         comb, sync = m.d.comb, m.d.sync
 
@@ -335,16 +348,32 @@ class TestIssuerBase(Elaboratable):
         # LoadStore1 and is already a submodule of LoadStore1
         if not isinstance(self.imem, ICache):
             m.submodules.imem = imem = csd(self.imem)
-        if self.microwatt_compat:
-            m.submodules.dbg = dbg = self.dbg
-        else:
-            m.submodules.dbg = dbg = dbd(self.dbg)
+        m.submodules.dbg = dbg = dbd(self.dbg)
         if self.jtag_en:
             m.submodules.jtag = jtag = dbd(self.jtag)
             # TODO: UART2GDB mux, here, from external pin
             # see https://bugs.libre-soc.org/show_bug.cgi?id=499
             sync += dbg.dmi.connect_to(jtag.dmi)
 
+        # fixup the clocks in microwatt-compat mode (but leave resets alone
+        # so that microwatt soc.vhdl can pull a reset on the core or DMI
+        # can do it, just like in TestIssuer)
+        if self.microwatt_compat:
+            intclk = ClockSignal(self.core_domain)
+            dbgclk = ClockSignal(self.dbg_domain)
+            if self.core_domain != 'sync':
+                comb += intclk.eq(ClockSignal())
+            if self.dbg_domain != 'sync':
+                comb += dbgclk.eq(ClockSignal())
+
+        # drop the first 3 bits of the incoming wishbone addresses
+        # this can go if using later versions of microwatt (not now)
+        if self.microwatt_compat:
+            ibus = self.imem.ibus
+            dbus = self.core.l0.cmpi.wb_bus()
+            comb += self.ibus_adr.eq(Cat(Const(0, 3), ibus.adr))
+            comb += self.dbus_adr.eq(Cat(Const(0, 3), dbus.adr))
+
         cur_state = self.cur_state
 
         # 4x 4k SRAM blocks.  these simply "exist", they get routed in litex
@@ -653,18 +682,23 @@ class TestIssuerBase(Elaboratable):
     def external_ports(self):
         if self.microwatt_compat:
             ports = [self.core.o.core_terminate_o,
+                     self.ext_irq,
                      self.alt_reset, # not connected yet
+                     self.nia, self.insn, self.nia_req, self.msr_o,
                      ClockSignal(),
                      ResetSignal(),
                     ]
             ports += list(self.dbg.dmi.ports())
             # for dbus/ibus microwatt, exclude err btw and cti
             for name, sig in self.imem.ibus.fields.items():
-                if name not in ['err', 'bte', 'cti']:
+                if name not in ['err', 'bte', 'cti', 'adr']:
                     ports.append(sig)
             for name, sig in self.core.l0.cmpi.wb_bus().fields.items():
-                if name not in ['err', 'bte', 'cti']:
+                if name not in ['err', 'bte', 'cti', 'adr']:
                     ports.append(sig)
+            # microwatt non-compliant with wishbone
+            ports.append(self.ibus_adr)
+            ports.append(self.dbus_adr)
             return ports
 
         ports = self.pc_i.ports()
@@ -702,71 +736,28 @@ class TestIssuerBase(Elaboratable):
         return list(self)
 
 
+class TestIssuerInternal(TestIssuerBase):
+    """TestIssuer - reads instructions from TestMemory and issues them
 
-# Fetch Finite State Machine.
-# WARNING: there are currently DriverConflicts but it's actually working.
-# TODO, here: everything that is global in nature, information from the
-# main TestIssuerInternal, needs to move to either ispec() or ospec().
-# not only that: TestIssuerInternal.imem can entirely move into here
-# because imem is only ever accessed inside the FetchFSM.
-class FetchFSM(ControlBase):
-    def __init__(self, allow_overlap, svp64_en, imem, core_rst,
-                 pdecode2, cur_state,
-                 dbg, core, svstate, nia, is_svp64_mode):
-        self.allow_overlap = allow_overlap
-        self.svp64_en = svp64_en
-        self.imem = imem
-        self.core_rst = core_rst
-        self.pdecode2 = pdecode2
-        self.cur_state = cur_state
-        self.dbg = dbg
-        self.core = core
-        self.svstate = svstate
-        self.nia = nia
-        self.is_svp64_mode = is_svp64_mode
-
-        # set up pipeline ControlBase and allocate i/o specs
-        # (unusual: normally done by the Pipeline API)
-        super().__init__(stage=self)
-        self.p.i_data, self.n.o_data = self.new_specs(None)
-        self.i, self.o = self.p.i_data, self.n.o_data
-
-    # next 3 functions are Stage API Compliance
-    def setup(self, m, i):
-        pass
-
-    def ispec(self):
-        return FetchInput()
-
-    def ospec(self):
-        return FetchOutput()
+    efficiency and speed is not the main goal here: functional correctness
+    and code clarity is.  optimisations (which almost 100% interfere with
+    easy understanding) come later.
+    """
 
-    def elaborate(self, platform):
+    def fetch_fsm(self, m, dbg, core, pc, msr, svstate, nia, is_svp64_mode,
+                        fetch_pc_o_ready, fetch_pc_i_valid,
+                        fetch_insn_o_valid, fetch_insn_i_ready):
         """fetch FSM
 
         this FSM performs fetch of raw instruction data, partial-decodes
         it 32-bit at a time to detect SVP64 prefixes, and will optionally
         read a 2nd 32-bit quantity if that occurs.
         """
-        m = super().elaborate(platform)
-
-        dbg = self.dbg
-        core = self.core
-        pc = self.i.pc
-        msr = self.i.msr
-        svstate = self.svstate
-        nia = self.nia
-        is_svp64_mode = self.is_svp64_mode
-        fetch_pc_o_ready = self.p.o_ready
-        fetch_pc_i_valid = self.p.i_valid
-        fetch_insn_o_valid = self.n.o_valid
-        fetch_insn_i_ready = self.n.i_ready
-
         comb = m.d.comb
         sync = m.d.sync
         pdecode2 = self.pdecode2
         cur_state = self.cur_state
-        dec_opcode_o = pdecode2.dec.raw_opcode_in  # raw opcode
+        dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode
 
         # also note instruction fetch failed
         if hasattr(core, "icache"):
@@ -849,7 +840,7 @@ class FetchFSM(ControlBase):
                             with m.If(~svp64.is_svp64_mode):
                                 # with no prefix, store the instruction
                                 # and hand it directly to the next FSM
-                                sync += dec_opcode_o.eq(insn)
+                                sync += dec_opcode_i.eq(insn)
                                 m.next = "INSN_READY"
                             with m.Else():
                                 # fetch the rest of the instruction from memory
@@ -860,7 +851,13 @@ class FetchFSM(ControlBase):
                         else:
                             # not SVP64 - 32-bit only
                             sync += nia.eq(cur_state.pc + 4)
-                            sync += dec_opcode_o.eq(insn)
+                            sync += dec_opcode_i.eq(insn)
+                            if self.microwatt_compat:
+                                # for verilator debug purposes
+                                comb += self.insn.eq(insn)
+                                comb += self.nia.eq(cur_state.pc)
+                                comb += self.msr_o.eq(cur_state.msr)
+                                comb += self.nia_req.eq(1)
                             m.next = "INSN_READY"
 
             with m.State("INSN_READ2"):
@@ -875,7 +872,7 @@ class FetchFSM(ControlBase):
                         insn = self.imem.f_instr_o
                     else:
                         insn = get_insn(self.imem.f_instr_o, cur_state.pc+4)
-                    sync += dec_opcode_o.eq(insn)
+                    sync += dec_opcode_i.eq(insn)
                     m.next = "INSN_READY"
                     # TODO: probably can start looking at pdecode2.rm_dec
                     # here or maybe even in INSN_READ state, if svp64_mode
@@ -899,20 +896,6 @@ class FetchFSM(ControlBase):
                 with m.If(fetch_insn_i_ready):
                     m.next = "IDLE"
 
-        # whatever was done above, over-ride it if core reset is held
-        with m.If(self.core_rst):
-            sync += nia.eq(0)
-
-        return m
-
-
-class TestIssuerInternal(TestIssuerBase):
-    """TestIssuer - reads instructions from TestMemory and issues them
-
-    efficiency and speed is not the main goal here: functional correctness
-    and code clarity is.  optimisations (which almost 100% interfere with
-    easy understanding) come later.
-    """
 
     def fetch_predicate_fsm(self, m,
                             pred_insn_i_valid, pred_insn_o_ready,
@@ -1543,21 +1526,10 @@ class TestIssuerInternal(TestIssuerBase):
         # Issue is where the VL for-loop # lives.  the ready/valid
         # signalling is used to communicate between the four.
 
-        # set up Fetch FSM
-        fetch = FetchFSM(self.allow_overlap, self.svp64_en,
-                         self.imem, core_rst, pdecode2, cur_state,
-                         dbg, core,
-                         dbg.state.svstate, # combinatorially same
-                         nia, is_svp64_mode)
-        m.submodules.fetch = fetch
-        # connect up in/out data to existing Signals
-        comb += fetch.p.i_data.pc.eq(dbg.state.pc)   # combinatorially same
-        comb += fetch.p.i_data.msr.eq(dbg.state.msr) # combinatorially same
-        # and the ready/valid signalling
-        comb += fetch_pc_o_ready.eq(fetch.p.o_ready)
-        comb += fetch.p.i_valid.eq(fetch_pc_i_valid)
-        comb += fetch_insn_o_valid.eq(fetch.n.o_valid)
-        comb += fetch.n.i_ready.eq(fetch_insn_i_ready)
+        self.fetch_fsm(m, dbg, core, dbg.state.pc, dbg.state.msr,
+                       dbg.state.svstate, nia, is_svp64_mode,
+                       fetch_pc_o_ready, fetch_pc_i_valid,
+                       fetch_insn_o_valid, fetch_insn_i_ready)
 
         self.issue_fsm(m, core, nia,
                        dbg, core_rst, is_svp64_mode,
@@ -1577,6 +1549,10 @@ class TestIssuerInternal(TestIssuerBase):
                          exec_insn_i_valid, exec_insn_o_ready,
                          exec_pc_o_valid, exec_pc_i_ready)
 
+        # whatever was done above, over-ride it if core reset is held
+        with m.If(core_rst):
+            sync += nia.eq(0)
+
         return m