diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index 0f905b90e..26ad64f7f 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -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 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") - # 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: + # # # + + 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) diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 5af8f55fb..34016eb9f 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -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