cores/cpu/vexriscv: create variants: None and "debug", some cleanup

This commit is contained in:
Florent Kermarrec 2018-07-05 17:31:23 +02:00
parent 59fa71593d
commit c821a0feab
2 changed files with 103 additions and 103 deletions

View File

@ -7,7 +7,8 @@ from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
class VexRiscv(Module, AutoCSR): 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.ibus = i = wishbone.Interface()
self.dbus = d = 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 # Output reset signal -- set to 1 when CPU reset is asserted
self.debug_reset = Signal() self.debug_reset = Signal()
i_debug_bus_cmd_payload_wr = Signal() if variant == None:
i_debug_bus_cmd_payload_address = Signal(8) cpu_reset = ResetSignal()
i_debug_bus_cmd_payload_data = Signal(32) cpu_args = {}
o_debug_bus_cmd_ready = Signal() cpu_filename = "VexRiscv.v"
o_debug_bus_rsp_data = Signal(32) elif variant == "debug":
debug_start_cmd = Signal() 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_bus_cmd_payload_wr = Signal()
# DEBUG_REFRESH: Write 0x00 or 0x04 here to update either CORE or DATA debug_bus_cmd_payload_address = Signal(8)
# DEBUG_COUNT: An incrementing value that can be used to detect packet loss. debug_bus_cmd_payload_data = Signal(32)
# Updated on a successful WRITE to CORE, DATA, or REFRESH. debug_bus_cmd_ready = Signal()
if cpu_debugging: debug_bus_rsp_data = Signal(32)
debug_start_cmd = Signal()
debug_update_pending = Signal() debug_update_pending = Signal()
debug_write_pending = Signal() debug_write_pending = Signal()
self.debug_core_reg = CSRStorage( debug_reset_out = Signal()
32, name="debug_core", write_from_dev=True) debug_reset_counter = Signal(16)
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()
# A bit to indicate whether we're REFRESHing the CORE or DATA register # A bit to indicate whether we're REFRESHing the CORE or DATA register
refreshing_data = Signal() refreshing_data = Signal()
self.sync += [ self.sync += [
# If the core asserts resetOut, set debug_reset for 65535 cycles. # If the core asserts reset_out, set debug_reset for 2**16 cycles.
If(debug_resetOut, debug_resetCounter.eq( If(debug_reset_out,
0), self.debug_reset.eq(1)) debug_reset_counter.eq(0),
.Elif(debug_resetCounter < 65534, debug_resetCounter.eq(debug_resetCounter + 1)) self.debug_reset.eq(1)
.Else(self.debug_reset.eq(0)), ).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 # Reset the CPU if debug_reset is asserted and none of the
# Wishbone buses are in use # Wishbone buses are in use
i_reset.eq((~i.cyc & ~d.cyc & ~d.stb & ~i.stb & cpu_reset.eq((~i.cyc & ~d.cyc & ~d.stb & ~i.stb &
self.debug_reset) | ResetSignal()), self.debug_reset) | ResetSignal()),
# If there's a Wishbone write on the CORE register, write to # If there's a Wishbone write on the CORE register, write to
# debug register address 0. # debug register address 0.
If(self.debug_core_reg.re, If(debug_core.re,
i_debug_bus_cmd_payload_address.eq(0x00), debug_bus_cmd_payload_address.eq(0x00),
i_debug_bus_cmd_payload_data.eq(self.debug_core_reg.storage), 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_start_cmd.eq(1),
debug_write_pending.eq(1), debug_write_pending.eq(1),
self.debug_core_reg.we.eq(0), debug_core.we.eq(0),
self.debug_data_reg.we.eq(0) debug_data.we.eq(0)
# Or, if there's a write to the DATA register, write to # Or, if there's a write to the DATA register, write to
# debug register address 4. # debug register address 4.
).Elif(self.debug_data_reg.re, ).Elif(debug_data.re,
i_debug_bus_cmd_payload_address.eq(0x04), debug_bus_cmd_payload_address.eq(0x04),
i_debug_bus_cmd_payload_data.eq(self.debug_data_reg.storage), 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_start_cmd.eq(1),
debug_write_pending.eq(1), debug_write_pending.eq(1),
self.debug_core_reg.we.eq(0), debug_core.we.eq(0),
self.debug_data_reg.we.eq(0) debug_data.we.eq(0)
# A write to the REFRESH register indicates which register # A write to the REFRESH register indicates which register
# (DATA or CORE) we want to update from the CPU. # (DATA or CORE) we want to update from the CPU.
).Elif(self.debug_refresh_reg.re, ).Elif(debug_refresh.re,
If(self.debug_refresh_reg.storage == 0, If(~debug_refresh.storage,
refreshing_data.eq(0), refreshing_data.eq(0),
i_debug_bus_cmd_payload_address.eq(0) debug_bus_cmd_payload_address.eq(0)
).Else( ).Else(
refreshing_data.eq(1), 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" # 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 # 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), 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. # so set the pending bit to look for it on future cycles.
debug_update_pending.eq(1), debug_update_pending.eq(1),
self.debug_core_reg.we.eq(0), debug_core.we.eq(0),
self.debug_data_reg.we.eq(0) debug_data.we.eq(0)
# If the pending bit is set, check to see if the cmd_ready # 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 # bit from the debug bus is 1, indicating the CPU has finished
# its operation and is in the idle state. # its operation and is in the idle state.
).Elif(debug_update_pending == 1, ).Elif(debug_update_pending,
If(o_debug_bus_cmd_ready == 1, If(debug_bus_cmd_ready,
i_debug_bus_cmd_payload_wr.eq(0), debug_bus_cmd_payload_wr.eq(0),
debug_update_pending.eq(0), debug_update_pending.eq(0),
debug_write_pending.eq(0), debug_write_pending.eq(0),
debug_start_cmd.eq(0), debug_start_cmd.eq(0),
self.debug_packet_counter.status.eq( debug_counter.status.eq(debug_counter.status + 1),
self.debug_packet_counter.status + 1),
# Depending on whether we were asked to update the CORE # Depending on whether we were asked to update the CORE
# or DATA register, copy the response data to the correct CSR. # or DATA register, copy the response data to the correct CSR.
If(refreshing_data == 0, If(~refreshing_data,
self.debug_core_reg.dat_w.eq(o_debug_bus_rsp_data), debug_core.dat_w.eq(debug_bus_rsp_data),
self.debug_core_reg.we.eq(1), debug_core.we.eq(1),
self.debug_data_reg.we.eq(0) debug_data.we.eq(0)
).Else( ).Else(
self.debug_data_reg.dat_w.eq(o_debug_bus_rsp_data), debug_data.dat_w.eq(debug_bus_rsp_data),
self.debug_core_reg.we.eq(0), debug_core.we.eq(0),
self.debug_data_reg.we.eq(1) debug_data.we.eq(1)
) )
) )
# If there's a pending write to CORE or DATA, increment the # If there's a pending write to CORE or DATA, increment the
# packet counter once the operation has finished. # packet counter once the operation has finished.
).Elif(debug_write_pending == 1, ).Elif(debug_write_pending,
If(o_debug_bus_cmd_ready == 1, If(debug_bus_cmd_ready,
# When o_debug_bus_cmd_ready goes 1, # When debug_bus_cmd_ready goes 1,
self.debug_packet_counter.status.eq( debug_counter.status.eq(debug_counter.status + 1),
self.debug_packet_counter.status + 1),
debug_update_pending.eq(0), debug_update_pending.eq(0),
debug_write_pending.eq(0), debug_write_pending.eq(0),
debug_start_cmd.eq(0), debug_start_cmd.eq(0),
self.debug_data_reg.we.eq(0), debug_data.we.eq(0),
self.debug_core_reg.we.eq(0) debug_core.we.eq(0)
) )
# Otherwise, ensure the Write Enable bits on the registers # Otherwise, ensure the Write Enable bits on the registers
# are 0, so we're not constantly loading floating values. # are 0, so we're not constantly loading floating values.
).Else( ).Else(
self.debug_core_reg.we.eq(0), debug_core.we.eq(0),
self.debug_data_reg.we.eq(0) debug_data.we.eq(0)
) )
] ]
kwargs = { cpu_args.update({
'i_debugReset': ResetSignal(), "i_debugReset": ResetSignal(),
'i_debug_bus_cmd_valid': debug_start_cmd, "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_wr": debug_bus_cmd_payload_wr,
'i_debug_bus_cmd_payload_address': i_debug_bus_cmd_payload_address, "i_debug_bus_cmd_payload_address": debug_bus_cmd_payload_address,
'i_debug_bus_cmd_payload_data': i_debug_bus_cmd_payload_data, "i_debug_bus_cmd_payload_data": debug_bus_cmd_payload_data,
'o_debug_bus_cmd_ready': o_debug_bus_cmd_ready, "o_debug_bus_cmd_ready": debug_bus_cmd_ready,
'o_debug_bus_rsp_data': o_debug_bus_rsp_data, "o_debug_bus_rsp_data": debug_bus_rsp_data,
'o_debug_resetOut': debug_resetOut "o_debug_resetOut": debug_reset_out
} })
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)
self.specials += Instance("VexRiscv", self.specials += Instance("VexRiscv",
**cpu_args,
i_clk=ClockSignal(), i_clk=ClockSignal(),
i_reset=i_reset, i_reset=cpu_reset,
i_externalResetVector=cpu_reset_address, i_externalResetVector=cpu_reset_address,
i_externalInterruptArray=self.interrupt, i_externalInterruptArray=self.interrupt,
@ -200,14 +200,13 @@ class VexRiscv(Module, AutoCSR):
o_dBusWishbone_BTE=d.bte, o_dBusWishbone_BTE=d.bte,
i_dBusWishbone_DAT_MISO=d.dat_r, i_dBusWishbone_DAT_MISO=d.dat_r,
i_dBusWishbone_ACK=d.ack, i_dBusWishbone_ACK=d.ack,
i_dBusWishbone_ERR=d.err, i_dBusWishbone_ERR=d.err)
**kwargs)
# add verilog sources # add verilog sources
self.add_sources(platform, source_file) self.add_sources(platform, cpu_filename)
@staticmethod @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") 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) platform.add_verilog_include_path(vdir)

View File

@ -61,7 +61,7 @@ class SoCCore(Module):
"csr": 0x60000000, # (default shadow @0xe0000000) "csr": 0x60000000, # (default shadow @0xe0000000)
} }
def __init__(self, platform, clk_freq, 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_rom_size=0, integrated_rom_init=[],
integrated_sram_size=4096, integrated_sram_size=4096,
integrated_main_ram_size=0, integrated_main_ram_init=[], integrated_main_ram_size=0, integrated_main_ram_init=[],
@ -81,7 +81,6 @@ class SoCCore(Module):
if integrated_rom_size: if integrated_rom_size:
cpu_reset_address = self.mem_map["rom"] cpu_reset_address = self.mem_map["rom"]
self.cpu_reset_address = cpu_reset_address self.cpu_reset_address = cpu_reset_address
self.cpu_debugging = cpu_debugging
self.config["CPU_RESET_ADDR"] = self.cpu_reset_address self.config["CPU_RESET_ADDR"] = self.cpu_reset_address
self.integrated_rom_size = integrated_rom_size self.integrated_rom_size = integrated_rom_size
@ -112,7 +111,7 @@ class SoCCore(Module):
elif cpu_type == "picorv32": elif cpu_type == "picorv32":
self.add_cpu_or_bridge(picorv32.PicoRV32(platform, self.cpu_reset_address, self.cpu_variant)) self.add_cpu_or_bridge(picorv32.PicoRV32(platform, self.cpu_reset_address, self.cpu_variant))
elif cpu_type == "vexriscv": 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: else:
raise ValueError("Unsupported CPU type: {}".format(cpu_type)) raise ValueError("Unsupported CPU type: {}".format(cpu_type))
self.add_wb_master(self.cpu_or_bridge.ibus) self.add_wb_master(self.cpu_or_bridge.ibus)
@ -315,6 +314,8 @@ class SoCCore(Module):
def soc_core_args(parser): def soc_core_args(parser):
parser.add_argument("--cpu-type", default=None, parser.add_argument("--cpu-type", default=None,
help="select CPU: lm32, or1k, riscv32") 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, parser.add_argument("--integrated-rom-size", default=None, type=int,
help="size/enable the integrated (BIOS) ROM") help="size/enable the integrated (BIOS) ROM")
parser.add_argument("--integrated-main-ram-size", default=None, type=int, 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): def soc_core_argdict(args):
r = dict() 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) arg = getattr(args, a)
if arg is not None: if arg is not None:
r[a] = arg r[a] = arg