cores/cpu/vexriscv: create variants: None and "debug", some cleanup
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 5 Jul 2018 15:31:23 +0000 (17:31 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 5 Jul 2018 15:31:23 +0000 (17:31 +0200)
litex/soc/cores/cpu/vexriscv/core.py
litex/soc/integration/soc_core.py

index 0f905b90e1fb6f587ca547c036ace5a2f01f1d8f..26ad64f7f4b320d491e597e8cacb5aab87f2c508 100644 (file)
@@ -7,7 +7,8 @@ from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
 
 
 class VexRiscv(Module, AutoCSR):
-    def __init__(self, platform, cpu_reset_address, cpu_debugging=False):
+    def __init__(self, platform, cpu_reset_address, variant=None):
+        assert variant in (None, "debug"), "Unsupported variant %s" % variant
         self.ibus = i = wishbone.Interface()
         self.dbus = d = wishbone.Interface()
 
@@ -16,163 +17,162 @@ class VexRiscv(Module, AutoCSR):
         # Output reset signal -- set to 1 when CPU reset is asserted
         self.debug_reset = Signal()
 
-        i_debug_bus_cmd_payload_wr = Signal()
-        i_debug_bus_cmd_payload_address = Signal(8)
-        i_debug_bus_cmd_payload_data = Signal(32)
-        o_debug_bus_cmd_ready = Signal()
-        o_debug_bus_rsp_data = Signal(32)
-        debug_start_cmd = Signal()
-
-        # If debugging is requested, create a bus that contains four registers:
-        #   DEBUG_CORE: The contents of the debug core register
-        #   DEBUG_DATA: Write an instruction into the pipeline, or read the result.
-        #   DEBUG_REFRESH: Write 0x00 or 0x04 here to update either CORE or DATA
-        #   DEBUG_COUNT: An incrementing value that can be used to detect packet loss.
-        #               Updated on a successful WRITE to CORE, DATA, or REFRESH.
-        if cpu_debugging:
+        if variant == None:
+            cpu_reset = ResetSignal()
+            cpu_args = {}
+            cpu_filename = "VexRiscv.v"
+        elif variant == "debug":
+            cpu_reset = Signal()
+            cpu_args = {}
+            cpu_filename = "VexRiscv-Debug.v"
+            # Create four debug registers:
+            #   DEBUG_CORE:    The contents of the debug core register
+            #   DEBUG_DATA:    Write an instruction into the pipeline, or read the result.
+            #   DEBUG_REFRESH: Write 0x00 or 0x04 here to update either CORE or DATA
+            #   DEBUG_COUNT:   An incrementing value that can be used to detect packet loss.
+            #                  Updated on a successful WRITE to CORE, DATA, or REFRESH.
+            self.debug_core = debug_core = CSRStorage(32, name="debug_core", write_from_dev=True)
+            self.debug_data = debug_data = CSRStorage(32, name="debug_data", write_from_dev=True)
+            self.debug_refresh = debug_refresh = CSRStorage(8, name="debug_refresh")
+            self.debug_counter = debug_counter = CSRStatus(32, name="debug_counter")
+
+            # # #
+
+            debug_bus_cmd_payload_wr = Signal()
+            debug_bus_cmd_payload_address = Signal(8)
+            debug_bus_cmd_payload_data = Signal(32)
+            debug_bus_cmd_ready = Signal()
+            debug_bus_rsp_data = Signal(32)
+            debug_start_cmd = Signal()
             debug_update_pending = Signal()
             debug_write_pending = Signal()
-            self.debug_core_reg = CSRStorage(
-                32, name="debug_core", write_from_dev=True)
-            self.debug_data_reg = CSRStorage(
-                32, name="debug_data", write_from_dev=True)
-            self.debug_refresh_reg = CSRStorage(8, name="debug_refresh")
-            self.debug_packet_counter = CSRStatus(
-                32, name="debug_counter")
-
-            # OR the global reset together with the result of debug_resetOut.
-            debug_resetOut = Signal()
-            debug_resetCounter = Signal(16)
-            i_reset = Signal()
+            debug_reset_out = Signal()
+            debug_reset_counter = Signal(16)
 
             # A bit to indicate whether we're REFRESHing the CORE or DATA register
             refreshing_data = Signal()
 
             self.sync += [
-                # If the core asserts resetOut, set debug_reset for 65535 cycles.
-                If(debug_resetOut, debug_resetCounter.eq(
-                    0), self.debug_reset.eq(1))
-                .Elif(debug_resetCounter < 65534, debug_resetCounter.eq(debug_resetCounter + 1))
-                .Else(self.debug_reset.eq(0)),
+                # If the core asserts reset_out, set debug_reset for 2**16 cycles.
+                If(debug_reset_out,
+                    debug_reset_counter.eq(0),
+                    self.debug_reset.eq(1)
+                ).Elif(debug_reset_counter != (2**16-1),
+                    debug_reset_counter.eq(debug_reset_counter + 1)
+                ).Else(
+                    self.debug_reset.eq(0)
+                ),
 
                 # Reset the CPU if debug_reset is asserted and none of the
                 # Wishbone buses are in use
-                i_reset.eq((~i.cyc & ~d.cyc & ~d.stb & ~i.stb &
-                            self.debug_reset) | ResetSignal()),
+                cpu_reset.eq((~i.cyc & ~d.cyc & ~d.stb & ~i.stb &
+                             self.debug_reset) | ResetSignal()),
 
                 # If there's a Wishbone write on the CORE register, write to
                 # debug register address 0.
-                If(self.debug_core_reg.re,
-                    i_debug_bus_cmd_payload_address.eq(0x00),
-                    i_debug_bus_cmd_payload_data.eq(self.debug_core_reg.storage),
+                If(debug_core.re,
+                    debug_bus_cmd_payload_address.eq(0x00),
+                    debug_bus_cmd_payload_data.eq(debug_core.storage),
 
-                    i_debug_bus_cmd_payload_wr.eq(1),
+                    debug_bus_cmd_payload_wr.eq(1),
                     debug_start_cmd.eq(1),
                     debug_write_pending.eq(1),
 
-                    self.debug_core_reg.we.eq(0),
-                    self.debug_data_reg.we.eq(0)
+                    debug_core.we.eq(0),
+                    debug_data.we.eq(0)
                 # Or, if there's a write to the DATA register, write to
                 # debug register address 4.
-                ).Elif(self.debug_data_reg.re,
-                    i_debug_bus_cmd_payload_address.eq(0x04),
-                    i_debug_bus_cmd_payload_data.eq(self.debug_data_reg.storage),
+                ).Elif(debug_data.re,
+                    debug_bus_cmd_payload_address.eq(0x04),
+                    debug_bus_cmd_payload_data.eq(debug_data.storage),
 
-                    i_debug_bus_cmd_payload_wr.eq(1),
+                    debug_bus_cmd_payload_wr.eq(1),
                     debug_start_cmd.eq(1),
                     debug_write_pending.eq(1),
 
-                    self.debug_core_reg.we.eq(0),
-                    self.debug_data_reg.we.eq(0)
+                    debug_core.we.eq(0),
+                    debug_data.we.eq(0)
                 # A write to the REFRESH register indicates which register
                 # (DATA or CORE) we want to update from the CPU.
-                ).Elif(self.debug_refresh_reg.re,
-                    If(self.debug_refresh_reg.storage == 0,
+                ).Elif(debug_refresh.re,
+                    If(~debug_refresh.storage,
                         refreshing_data.eq(0),
-                        i_debug_bus_cmd_payload_address.eq(0)
+                        debug_bus_cmd_payload_address.eq(0)
                     ).Else(
                         refreshing_data.eq(1),
-                        i_debug_bus_cmd_payload_address.eq(4)
+                        debug_bus_cmd_payload_address.eq(4)
                     ),
                     # Data can be anything, since it's a "read"
-                    i_debug_bus_cmd_payload_data.eq(0),
+                    debug_bus_cmd_payload_data.eq(0),
 
                     # Start a "Read" command with the "Write" bit set to 0
-                    i_debug_bus_cmd_payload_wr.eq(0),
+                    debug_bus_cmd_payload_wr.eq(0),
                     debug_start_cmd.eq(1),
 
-                    # The data will be ready when o_debug_bus_cmd_ready == 1,
+                    # The data will be ready when debug_bus_cmd_ready == 1,
                     # so set the pending bit to look for it on future cycles.
                     debug_update_pending.eq(1),
 
-                    self.debug_core_reg.we.eq(0),
-                    self.debug_data_reg.we.eq(0)
+                    debug_core.we.eq(0),
+                    debug_data.we.eq(0)
                 # If the pending bit is set, check to see if the cmd_ready
                 # bit from the debug bus is 1, indicating the CPU has finished
                 # its operation and is in the idle state.
-                ).Elif(debug_update_pending == 1,
-                    If(o_debug_bus_cmd_ready == 1,
-                        i_debug_bus_cmd_payload_wr.eq(0),
+                ).Elif(debug_update_pending,
+                    If(debug_bus_cmd_ready,
+                        debug_bus_cmd_payload_wr.eq(0),
                         debug_update_pending.eq(0),
                         debug_write_pending.eq(0),
                         debug_start_cmd.eq(0),
-                        self.debug_packet_counter.status.eq(
-                            self.debug_packet_counter.status + 1),
+                        debug_counter.status.eq(debug_counter.status + 1),
                         # Depending on whether we were asked to update the CORE
                         # or DATA register, copy the response data to the correct CSR.
-                        If(refreshing_data == 0,
-                            self.debug_core_reg.dat_w.eq(o_debug_bus_rsp_data),
-                            self.debug_core_reg.we.eq(1),
-                            self.debug_data_reg.we.eq(0)
+                        If(~refreshing_data,
+                            debug_core.dat_w.eq(debug_bus_rsp_data),
+                            debug_core.we.eq(1),
+                            debug_data.we.eq(0)
                         ).Else(
-                            self.debug_data_reg.dat_w.eq(o_debug_bus_rsp_data),
-                            self.debug_core_reg.we.eq(0),
-                            self.debug_data_reg.we.eq(1)
+                            debug_data.dat_w.eq(debug_bus_rsp_data),
+                            debug_core.we.eq(0),
+                            debug_data.we.eq(1)
                         )
                     )
                 # If there's a pending write to CORE or DATA, increment the
                 # packet counter once the operation has finished.
-                ).Elif(debug_write_pending == 1,
-                    If(o_debug_bus_cmd_ready == 1,
-                        # When o_debug_bus_cmd_ready goes 1,
-                        self.debug_packet_counter.status.eq(
-                            self.debug_packet_counter.status + 1),
+                ).Elif(debug_write_pending,
+                    If(debug_bus_cmd_ready,
+                        # When debug_bus_cmd_ready goes 1,
+                        debug_counter.status.eq(debug_counter.status + 1),
                         debug_update_pending.eq(0),
                         debug_write_pending.eq(0),
                         debug_start_cmd.eq(0),
-                        self.debug_data_reg.we.eq(0),
-                        self.debug_core_reg.we.eq(0)
+                        debug_data.we.eq(0),
+                        debug_core.we.eq(0)
                     )
                 # Otherwise, ensure the Write Enable bits on the registers
                 # are 0, so we're not constantly loading floating values.
                 ).Else(
-                    self.debug_core_reg.we.eq(0),
-                    self.debug_data_reg.we.eq(0)
+                    debug_core.we.eq(0),
+                    debug_data.we.eq(0)
                 )
             ]
 
-            kwargs = {
-                'i_debugReset': ResetSignal(),
-                'i_debug_bus_cmd_valid': debug_start_cmd,
-                'i_debug_bus_cmd_payload_wr': i_debug_bus_cmd_payload_wr,
-                'i_debug_bus_cmd_payload_address': i_debug_bus_cmd_payload_address,
-                'i_debug_bus_cmd_payload_data': i_debug_bus_cmd_payload_data,
-                'o_debug_bus_cmd_ready': o_debug_bus_cmd_ready,
-                'o_debug_bus_rsp_data': o_debug_bus_rsp_data,
-                'o_debug_resetOut': debug_resetOut
-            }
-            source_file = "VexRiscv-Debug.v"
-        else:
-            kwargs = {}
-            source_file = "VexRiscv.v"
-            # Ordinarily this is a reset signal.  However, in debug mode,
-            # this is ORed with the output of debug_resetOut as well.
-            i_reset = ResetSignal()
-            self.comb += self.debug_reset.eq(0)
+            cpu_args.update({
+                "i_debugReset": ResetSignal(),
+                "i_debug_bus_cmd_valid": debug_start_cmd,
+                "i_debug_bus_cmd_payload_wr": debug_bus_cmd_payload_wr,
+                "i_debug_bus_cmd_payload_address": debug_bus_cmd_payload_address,
+                "i_debug_bus_cmd_payload_data": debug_bus_cmd_payload_data,
+                "o_debug_bus_cmd_ready": debug_bus_cmd_ready,
+                "o_debug_bus_rsp_data": debug_bus_rsp_data,
+                "o_debug_resetOut": debug_reset_out
+            })
 
         self.specials += Instance("VexRiscv",
+                **cpu_args,
+
                 i_clk=ClockSignal(),
-                i_reset=i_reset,
+                i_reset=cpu_reset,
 
                 i_externalResetVector=cpu_reset_address,
                 i_externalInterruptArray=self.interrupt,
@@ -200,14 +200,13 @@ class VexRiscv(Module, AutoCSR):
                 o_dBusWishbone_BTE=d.bte,
                 i_dBusWishbone_DAT_MISO=d.dat_r,
                 i_dBusWishbone_ACK=d.ack,
-                i_dBusWishbone_ERR=d.err,
-                **kwargs)
+                i_dBusWishbone_ERR=d.err)
 
         # add verilog sources
-        self.add_sources(platform, source_file)
+        self.add_sources(platform, cpu_filename)
 
     @staticmethod
-    def add_sources(platform, source_file):
+    def add_sources(platform, cpu_filename):
         vdir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "verilog")
-        platform.add_sources(os.path.join(vdir), source_file)
+        platform.add_sources(os.path.join(vdir), cpu_filename)
         platform.add_verilog_include_path(vdir)
index 5af8f55fb2eee78b6a3f58a6f77ae01b4b68b442..34016eb9f7c2dd422d84eafa78f5a975d17cf2a0 100644 (file)
@@ -61,7 +61,7 @@ class SoCCore(Module):
         "csr":      0x60000000,  # (default shadow @0xe0000000)
     }
     def __init__(self, platform, clk_freq,
-                cpu_type="lm32", cpu_reset_address=0x00000000, cpu_variant=None, cpu_debugging=False,
+                cpu_type="lm32", cpu_reset_address=0x00000000, cpu_variant=None,
                 integrated_rom_size=0, integrated_rom_init=[],
                 integrated_sram_size=4096,
                 integrated_main_ram_size=0, integrated_main_ram_init=[],
@@ -81,7 +81,6 @@ class SoCCore(Module):
         if integrated_rom_size:
             cpu_reset_address = self.mem_map["rom"]
         self.cpu_reset_address = cpu_reset_address
-        self.cpu_debugging = cpu_debugging
         self.config["CPU_RESET_ADDR"] = self.cpu_reset_address
 
         self.integrated_rom_size = integrated_rom_size
@@ -112,7 +111,7 @@ class SoCCore(Module):
             elif cpu_type == "picorv32":
                 self.add_cpu_or_bridge(picorv32.PicoRV32(platform, self.cpu_reset_address, self.cpu_variant))
             elif cpu_type == "vexriscv":
-                self.add_cpu_or_bridge(vexriscv.VexRiscv(platform, self.cpu_reset_address, cpu_debugging=self.cpu_debugging))
+                self.add_cpu_or_bridge(vexriscv.VexRiscv(platform, self.cpu_reset_address, self.cpu_variant))
             else:
                 raise ValueError("Unsupported CPU type: {}".format(cpu_type))
             self.add_wb_master(self.cpu_or_bridge.ibus)
@@ -315,6 +314,8 @@ class SoCCore(Module):
 def soc_core_args(parser):
     parser.add_argument("--cpu-type", default=None,
                         help="select CPU: lm32, or1k, riscv32")
+    parser.add_argument("--cpu-variant", default=None,
+                        help="select CPU variant")
     parser.add_argument("--integrated-rom-size", default=None, type=int,
                         help="size/enable the integrated (BIOS) ROM")
     parser.add_argument("--integrated-main-ram-size", default=None, type=int,
@@ -323,7 +324,7 @@ def soc_core_args(parser):
 
 def soc_core_argdict(args):
     r = dict()
-    for a in "cpu_type", "integrated_rom_size", "integrated_main_ram_size":
+    for a in "cpu_type", "cpu_variant", "integrated_rom_size", "integrated_main_ram_size":
         arg = getattr(args, a)
         if arg is not None:
             r[a] = arg