diff --git a/litex/soc/cores/cpu/neorv32/core.py b/litex/soc/cores/cpu/neorv32/core.py index 390a5ccd2..6053a5f8e 100644 --- a/litex/soc/cores/cpu/neorv32/core.py +++ b/litex/soc/cores/cpu/neorv32/core.py @@ -13,7 +13,7 @@ from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 # Variants ----------------------------------------------------------------------------------------- -CPU_VARIANTS = ["standard"] +CPU_VARIANTS = ["minimal", "lite", "standard", "full"] # GCC Flags ---------------------------------------------------------------------------------------- @@ -25,7 +25,10 @@ GCC_FLAGS = { # ||||/--- Single-Precision Floating-Point # |||||/-- Double-Precision Floating-Point # imacfd - "standard": "-march=rv32i -mabi=ilp32", + "minimal": "-march=rv32i -mabi=ilp32", + "lite": "-march=rv32imc -mabi=ilp32", + "standard": "-march=rv32imc -mabi=ilp32", + "full": "-march=rv32imc -mabi=ilp32", } # NEORV32 ------------------------------------------------------------------------------------------ @@ -34,7 +37,6 @@ class NEORV32(CPU): category = "softcore" family = "riscv" name = "neorv32" - human_name = "NEORV32" variants = CPU_VARIANTS data_width = 32 endianness = "little" @@ -53,127 +55,138 @@ class NEORV32(CPU): def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant + self.human_name = f"NEORV32-{variant}" self.reset = Signal() - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() - self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). - self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). + self.ibus = idbus = wishbone.Interface() + self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). + self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). # # # class Open(Signal) : pass - # IBus Adaptations. FIXME: Works but not optimal (latency). - ibus_we = Signal() - ibus_re = Signal() - self.sync += [ - # Clear Cyc/Stb on Ack. - If(ibus.ack, - ibus.cyc.eq(0), - ibus.stb.eq(0), - ), - # Set Cyc/Stb on We/Re. - If(ibus_we | ibus_re, - ibus.cyc.eq(1), - ibus.stb.eq(1), - ibus.we.eq(ibus_we) - ) - ] + # CPU LiteX Core Complex Wrapper + self.specials += Instance("neorv32_litex_core_complex", + # Parameters. + #p_CONFIG = 2, + #p_DEBUG = False, - # DBus Adaptations. FIXME: Works but not optimal (latency). - dbus_we = Signal() - dbus_re = Signal() - self.sync += [ - # Clear Cyc/Stb on Ack. - If(dbus.ack, - dbus.cyc.eq(0), - dbus.stb.eq(0), - ), - # Set Cyc/Stb on We/Re. - If(dbus_we | dbus_re, - dbus.cyc.eq(1), - dbus.stb.eq(1), - dbus.we.eq(dbus_we) - ) - ] + # Clk/Rst. + i_clk_i = ClockSignal("sys"), + i_rstn_i = ~(ResetSignal() | self.reset), - # CPU Instance. - self.specials += Instance("neorv32_cpu_wrapper", - # Global Control. - i_clk_i = ClockSignal("sys"), - i_rstn_i = ~(ResetSignal() | self.reset), - o_sleep_o = Open(), - o_debug_o = Open(), - i_db_halt_req_i = 0, + # JTAG. + i_jtag_trst_i = 0, + i_jtag_tck_i = 0, + i_jtag_tdi_i = 0, + o_jtag_tdo_o = Open(), + i_jtag_tms_i = 0, - # Instruction Bus. - o_i_bus_addr_o = Cat(Signal(2), ibus.adr), - i_i_bus_rdata_i = ibus.dat_r, - o_i_bus_wdata_o = ibus.dat_w, - o_i_bus_ben_o = ibus.sel, - o_i_bus_we_o = ibus_we, - o_i_bus_re_o = ibus_re, - o_i_bus_lock_o = Open(), # FIXME. - i_i_bus_ack_i = ibus.ack, - i_i_bus_err_i = ibus.err, - o_i_bus_fence_o = Open(), # FIXME. - o_i_bus_priv_o = Open(), # FIXME. + # Interrupt. + i_mext_irq_i = 0, - # Data Bus. - o_d_bus_addr_o = Cat(Signal(2), dbus.adr), - i_d_bus_rdata_i = dbus.dat_r, - o_d_bus_wdata_o = dbus.dat_w, - o_d_bus_ben_o = dbus.sel, - o_d_bus_we_o = dbus_we, - o_d_bus_re_o = dbus_re, - o_d_bus_lock_o = Open(), # FIXME. - i_d_bus_ack_i = dbus.ack, - i_d_bus_err_i = dbus.err, - o_d_bus_fence_o = Open(), # FIXME. - o_d_bus_priv_o = Open(), # FIXME. - - # System Time. - i_time_i = 0, # FIXME. - - # Interrupts. - i_msw_irq_i = 0, # FIXME. - i_mext_irq_i = 0, # FIXME. - i_mtime_irq_i = 0, # FIXME. - i_firq_i = 0 # FIXME. + # I/D Wishbone Bus. + o_wb_adr_o = Cat(Signal(2), idbus.adr), + i_wb_dat_i = idbus.dat_r, + o_wb_dat_o = idbus.dat_w, + o_wb_we_o = idbus.we, + o_wb_sel_o = idbus.sel, + o_wb_stb_o = idbus.stb, + o_wb_cyc_o = idbus.cyc, + i_wb_ack_i = idbus.ack, + i_wb_err_i = idbus.err, ) # Add Verilog sources - self.add_sources(platform) + self.add_sources(platform, variant) def set_reset_address(self, reset_address): self.reset_address = reset_address assert reset_address == 0x0000_0000 @staticmethod - def add_sources(platform): + def add_sources(platform, variant): cdir = os.path.abspath(os.path.dirname(__file__)) # List VHDL sources. - sources = [ - "neorv32_package.vhd", # Main CPU & Processor package file. - "neorv32_fifo.vhd", # FIFO. - "neorv32_cpu.vhd", # CPU top entity. - "neorv32_cpu_alu.vhd", # Arithmetic/logic unit. - "neorv32_cpu_cp_bitmanip.vhd", # Bit-manipulation co-processor. - "neorv32_cpu_cp_cfu.vhd", # Custom instructions co-processor. - "neorv32_cpu_cp_fpu.vhd", # Single-precision FPU co-processor. - "neorv32_cpu_cp_muldiv.vhd", # Integer multiplier/divider co-processor. - "neorv32_cpu_cp_shifter.vhd", # Base ISA shifter unit. - "neorv32_cpu_bus.vhd", # Instruction and data bus interface unit. - "neorv32_cpu_control.vhd", # CPU control and CSR system. - "neorv32_cpu_decompressor.vhd", # Compressed instructions decoder. - "neorv32_cpu_regfile.vhd", # Data register file. - "neorv32_cpu_wrapper.vhd", # CPU top entity + default generics. - ] + sources = { + "core" : [ + # CPU & Processors Packages/Cores. + "neorv32_package.vhd", + "neorv32_fifo.vhd", + + # CPU components. + "neorv32_cpu.vhd", + "neorv32_cpu_alu.vhd", + "neorv32_cpu_cp_bitmanip.vhd", + "neorv32_cpu_cp_cfu.vhd", + "neorv32_cpu_cp_fpu.vhd", + "neorv32_cpu_cp_muldiv.vhd", + "neorv32_cpu_cp_shifter.vhd", + "neorv32_cpu_bus.vhd", + "neorv32_cpu_control.vhd", + "neorv32_cpu_decompressor.vhd", + "neorv32_cpu_regfile.vhd", + + # Processor components. + "neorv32_top.vhd", + "neorv32_icache.vhd", + "neorv32_busswitch.vhd", + "neorv32_bus_keeper.vhd", + "neorv32_wishbone.vhd", + "neorv32_mtime.vhd", + "neorv32_sysinfo.vhd", + "neorv32_debug_dm.vhd", + "neorv32_debug_dtm.vhd", + ], + + "core/mem": [ + "neorv32_imem.default.vhd", + "neorv32_dmem.default.vhd", + ], + + "system_integration": [ + "neorv32_litex_core_complex.vhd", + ], + } # Download VHDL sources (if not already present). - for source in sources: - if not os.path.exists(os.path.join(cdir, source)): - os.system(f"wget https://raw.githubusercontent.com/stnolting/neorv32/main/rtl/core/{source} -P {cdir}") + for directory, vhds in sources.items(): + for vhd in vhds: + if not os.path.exists(os.path.join(cdir, vhd)): + os.system(f"wget https://raw.githubusercontent.com/stnolting/neorv32/main/rtl/{directory}/{vhd} -P {cdir}") + + def configure_litex_core_complex(filename, variant): + # Read Wrapper. + lines = [] + f = open(filename) + for l in f: + lines.append(l) + f.close() + + # Configure. + _lines = [] + for l in lines: + if "constant CONFIG" in l: + config = { + "minimal" : "0", + "lite" : "1", + "standard" : "2", + "full" : "3" + }[variant] + l = f"\tconstant CONFIG : natural := {config};\n" + _lines.append(l) + lines = _lines + + # Write Wrapper. + f = open(filename, "w") + for l in lines: + f.write(l) + f.close() + + configure_litex_core_complex( + filename = os.path.join(cdir, "neorv32_litex_core_complex.vhd"), + variant = variant, + ) # Convert VHDL to Verilog through GHDL/Yosys. from litex.build import tools @@ -181,15 +194,16 @@ class NEORV32(CPU): cdir = os.path.dirname(__file__) ys = [] ys.append("ghdl --ieee=synopsys -fexplicit -frelaxed-rules --std=08 --work=neorv32 \\") - for source in sources: - ys.append(os.path.join(cdir, source) + " \\") - ys.append("-e neorv32_cpu_wrapper") + for directory, vhds in sources.items(): + for vhd in vhds: + ys.append(os.path.join(cdir, vhd) + " \\") + ys.append("-e neorv32_litex_core_complex") ys.append("chformal -assert -remove") - ys.append("write_verilog {}".format(os.path.join(cdir, "neorv32.v"))) - tools.write_to_file(os.path.join(cdir, "neorv32.ys"), "\n".join(ys)) - if subprocess.call(["yosys", "-q", "-m", "ghdl", os.path.join(cdir, "neorv32.ys")]): + ys.append("write_verilog {}".format(os.path.join(cdir, "neorv32_litex_core_complex.v"))) + tools.write_to_file(os.path.join(cdir, "neorv32_litex_core_complex.ys"), "\n".join(ys)) + if subprocess.call(["yosys", "-q", "-m", "ghdl", os.path.join(cdir, "neorv32_litex_core_complex.ys")]): raise OSError("Unable to convert NEORV32 CPU to verilog, please check your GHDL-Yosys-plugin install.") - platform.add_source(os.path.join(cdir, "neorv32.v")) + platform.add_source(os.path.join(cdir, "neorv32_litex_core_complex.v")) def do_finalize(self): assert hasattr(self, "reset_address") diff --git a/litex/soc/cores/cpu/neorv32/neorv32_cpu_wrapper.vhd b/litex/soc/cores/cpu/neorv32/neorv32_cpu_wrapper.vhd deleted file mode 100644 index 386f4dd37..000000000 --- a/litex/soc/cores/cpu/neorv32/neorv32_cpu_wrapper.vhd +++ /dev/null @@ -1,151 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library neorv32; -use neorv32.neorv32_package.all; - -entity neorv32_cpu_wrapper is - generic ( - -- General -- - HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit) - CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0) := x"00000000"; -- cpu boot address - CPU_DEBUG_ADDR : std_ulogic_vector(31 downto 0) := x"00000000"; -- cpu debug mode start address - -- RISC-V CPU Extensions -- - CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension? - CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit-manipulation extension? - CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension? - CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension? - CPU_EXTENSION_RISCV_M : boolean := true; -- implement muld/div extension? - CPU_EXTENSION_RISCV_U : boolean := true; -- implement user mode extension? - CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT reg!) - CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system? - CPU_EXTENSION_RISCV_Zicntr : boolean := true; -- implement base counters? - CPU_EXTENSION_RISCV_Zihpm : boolean := false; -- implement hardware performance monitors? - CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.? - CPU_EXTENSION_RISCV_Zmmul : boolean := false; -- implement multiply-only M sub-extension? - CPU_EXTENSION_RISCV_Zxcfu : boolean := false; -- implement custom (instr.) functions unit? - CPU_EXTENSION_RISCV_DEBUG : boolean := false; -- implement CPU debug mode? - -- Extension Options -- - FAST_MUL_EN : boolean := true; -- use DSPs for M extension's multiplier - FAST_SHIFT_EN : boolean := true; -- use barrel shifter for shift operations - CPU_CNT_WIDTH : natural := 32; -- total width of CPU cycle and instret counters (0..64) - CPU_IPB_ENTRIES : natural := 4; -- entries is instruction prefetch buffer, has to be a power of 2 - -- Physical Memory Protection (PMP) -- - PMP_NUM_REGIONS : natural := 4; -- number of regions (0..64) - PMP_MIN_GRANULARITY : natural := 8; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes - -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29) - HPM_CNT_WIDTH : natural := 32 -- total size of HPM counters (0..64) - ); - port ( - -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - sleep_o : out std_ulogic; -- cpu is in sleep mode when set - debug_o : out std_ulogic; -- cpu is in debug mode when set - -- instruction bus interface -- - i_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address - i_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data - i_bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data - i_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - i_bus_we_o : out std_ulogic; -- write enable - i_bus_re_o : out std_ulogic; -- read enable - i_bus_lock_o : out std_ulogic; -- exclusive access request - i_bus_ack_i : in std_ulogic; -- bus transfer acknowledge - i_bus_err_i : in std_ulogic; -- bus transfer error - i_bus_fence_o : out std_ulogic; -- executed FENCEI operation - i_bus_priv_o : out std_ulogic_vector(1 downto 0); -- privilege level - -- data bus interface -- - d_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address - d_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data - d_bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data - d_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - d_bus_we_o : out std_ulogic; -- write enable - d_bus_re_o : out std_ulogic; -- read enable - d_bus_lock_o : out std_ulogic; -- exclusive access request - d_bus_ack_i : in std_ulogic; -- bus transfer acknowledge - d_bus_err_i : in std_ulogic; -- bus transfer error - d_bus_fence_o : out std_ulogic; -- executed FENCE operation - d_bus_priv_o : out std_ulogic_vector(1 downto 0); -- privilege level - -- system time input from MTIME -- - time_i : in std_ulogic_vector(63 downto 0); -- current system time - -- interrupts (risc-v compliant) -- - msw_irq_i : in std_ulogic;-- machine software interrupt - mext_irq_i : in std_ulogic;-- machine external interrupt - mtime_irq_i : in std_ulogic;-- machine timer interrupt - -- fast interrupts (custom) -- - firq_i : in std_ulogic_vector(15 downto 0); - -- debug mode (halt) request -- - db_halt_req_i : in std_ulogic - ); -end neorv32_cpu_wrapper; - -architecture neorv32_cpu_wrapper_rtl of neorv32_cpu_wrapper is - -begin - - neorv32_cpu_inst: neorv32_cpu - generic map ( - HW_THREAD_ID => HW_THREAD_ID , - CPU_BOOT_ADDR => CPU_BOOT_ADDR , - CPU_DEBUG_ADDR => CPU_DEBUG_ADDR , - CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A , - CPU_EXTENSION_RISCV_B => CPU_EXTENSION_RISCV_B , - CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C , - CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E , - CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M , - CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U , - CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx , - CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr , - CPU_EXTENSION_RISCV_Zicntr => CPU_EXTENSION_RISCV_Zicntr , - CPU_EXTENSION_RISCV_Zihpm => CPU_EXTENSION_RISCV_Zihpm , - CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, - CPU_EXTENSION_RISCV_Zmmul => CPU_EXTENSION_RISCV_Zmmul , - CPU_EXTENSION_RISCV_Zxcfu => CPU_EXTENSION_RISCV_Zxcfu , - CPU_EXTENSION_RISCV_DEBUG => CPU_EXTENSION_RISCV_DEBUG , - FAST_MUL_EN => FAST_MUL_EN , - FAST_SHIFT_EN => FAST_SHIFT_EN , - CPU_CNT_WIDTH => CPU_CNT_WIDTH , - CPU_IPB_ENTRIES => CPU_IPB_ENTRIES , - PMP_NUM_REGIONS => PMP_NUM_REGIONS , - PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY , - HPM_NUM_CNTS => HPM_NUM_CNTS , - HPM_CNT_WIDTH => HPM_CNT_WIDTH - ) - port map ( - clk_i => clk_i , - rstn_i => rstn_i , - sleep_o => sleep_o , - debug_o => debug_o , - i_bus_addr_o => i_bus_addr_o , - i_bus_rdata_i => i_bus_rdata_i, - i_bus_wdata_o => i_bus_wdata_o, - i_bus_ben_o => i_bus_ben_o , - i_bus_we_o => i_bus_we_o , - i_bus_re_o => i_bus_re_o , - i_bus_lock_o => i_bus_lock_o , - i_bus_ack_i => i_bus_ack_i , - i_bus_err_i => i_bus_err_i , - i_bus_fence_o => i_bus_fence_o, - i_bus_priv_o => i_bus_priv_o , - d_bus_addr_o => d_bus_addr_o , - d_bus_rdata_i => d_bus_rdata_i, - d_bus_wdata_o => d_bus_wdata_o, - d_bus_ben_o => d_bus_ben_o , - d_bus_we_o => d_bus_we_o , - d_bus_re_o => d_bus_re_o , - d_bus_lock_o => d_bus_lock_o , - d_bus_ack_i => d_bus_ack_i , - d_bus_err_i => d_bus_err_i , - d_bus_fence_o => d_bus_fence_o, - d_bus_priv_o => d_bus_priv_o , - time_i => time_i , - msw_irq_i => msw_irq_i , - mext_irq_i => mext_irq_i , - mtime_irq_i => mtime_irq_i , - firq_i => firq_i , - db_halt_req_i => db_halt_req_i - ); - -end neorv32_cpu_wrapper_rtl;