From ba299e537b567b2b6b1d98038c4d1f0f6401877c Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Fri, 27 Sep 2024 14:44:28 +0200 Subject: [PATCH] fpga: Add NEORV32 as alternative CPU core --- .gitmodules | 3 + fpga/hdl/design/neorv32_top.vhd | 170 ++++++++++++++++++++++++++++++++ fpga/hdl/design/top.vhd | 45 ++++++--- fpga/hdl/neorv32 | 1 + fpga/run.py | 4 + fpga/run_physical.py | 4 + 6 files changed, 216 insertions(+), 11 deletions(-) create mode 100644 fpga/hdl/design/neorv32_top.vhd create mode 160000 fpga/hdl/neorv32 diff --git a/.gitmodules b/.gitmodules index ab92ef6..4358f6a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "fpga/hdl/trashernet"] path = fpga/hdl/trashernet url = https://git.notsyncing.net/fpga/trashernet.git +[submodule "fpga/hdl/neorv32"] + path = fpga/hdl/neorv32 + url = https://github.com/stnolting/neorv32.git diff --git a/fpga/hdl/design/neorv32_top.vhd b/fpga/hdl/design/neorv32_top.vhd new file mode 100644 index 0000000..1840c0a --- /dev/null +++ b/fpga/hdl/design/neorv32_top.vhd @@ -0,0 +1,170 @@ +-- -------------------------------------------------------------------------- -- +-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- +-- -------------------------------------------------------------------------- -- +-- Wrapper for NEORV32 +-- -------------------------------------------------------------------------- -- +-- Author : Markus Koch +-- Contributors : None +-- License : Mozilla Public License (MPL) Version 2 +-- -------------------------------------------------------------------------- -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library generics; +use generics.wishbone_pkg.all; + +library neorv32; +use neorv32.neorv32_package.all; + +entity neorv32_top_vhdl is + port( + clk : in std_logic; -- CPU and bus clock + clr : in std_logic; -- Synchronous clear (CPU reset) + wbi_o : out wishbone_master_out; -- Instruction Wishbone bus (out) + wbi_i : in wishbone_master_in; -- Instruction Wishbone bus (in) + wbd_o : out wishbone_master_out; -- Data Wishbone bus (out) + wbd_i : in wishbone_master_in; -- Data Wishbone bus (in) + irq_timer : in std_logic -- System timer interrupt + ); +end entity neorv32_top_vhdl; + +architecture rtl of neorv32_top_vhdl is + signal ibus_req_o : bus_req_t; + signal ibus_rsp_i : bus_rsp_t; + signal dbus_req_o : bus_req_t; + signal dbus_rsp_i : bus_rsp_t; + + signal wbi_rsp_latched : std_logic; + signal wbd_rsp_latched : std_logic; + + signal ibus_req_mask : std_logic; + signal ibus_rsp_mask : std_logic; + + signal dbus_req_mask : std_logic; + signal dbus_rsp_mask : std_logic; +begin + + neorv32_cpu_inst : entity neorv32.neorv32_cpu + generic map( + HART_ID => x"00000000", + VENDOR_ID => x"00000000", + CPU_BOOT_ADDR => x"00000000", + CPU_DEBUG_PARK_ADDR => x"00000000", + CPU_DEBUG_EXC_ADDR => x"00000000", + CPU_EXTENSION_RISCV_A => false, + CPU_EXTENSION_RISCV_B => false, + CPU_EXTENSION_RISCV_C => false, + CPU_EXTENSION_RISCV_E => false, + CPU_EXTENSION_RISCV_M => false, + CPU_EXTENSION_RISCV_U => false, + CPU_EXTENSION_RISCV_Zbkx => false, + CPU_EXTENSION_RISCV_Zfinx => false, + CPU_EXTENSION_RISCV_Zicntr => false, + CPU_EXTENSION_RISCV_Zicond => false, + CPU_EXTENSION_RISCV_Zihpm => false, + CPU_EXTENSION_RISCV_Zknd => false, + CPU_EXTENSION_RISCV_Zkne => false, + CPU_EXTENSION_RISCV_Zknh => false, + CPU_EXTENSION_RISCV_Zmmul => false, + CPU_EXTENSION_RISCV_Zxcfu => false, + CPU_EXTENSION_RISCV_Sdext => false, + CPU_EXTENSION_RISCV_Sdtrig => false, + CPU_EXTENSION_RISCV_Smpmp => false, + FAST_MUL_EN => false, + FAST_SHIFT_EN => false, + REGFILE_HW_RST => true, + PMP_NUM_REGIONS => 0, + PMP_MIN_GRANULARITY => 0, + PMP_TOR_MODE_EN => false, + PMP_NAP_MODE_EN => false, + HPM_NUM_CNTS => 0, + HPM_CNT_WIDTH => 0 + ) + port map( + clk_i => clk, + clk_aux_i => clk, + rstn_i => not clr, + sleep_o => open, + debug_o => open, + msi_i => '0', + mei_i => '0', + mti_i => irq_timer, + firq_i => x"0000", + dbi_i => '0', + ibus_req_o => ibus_req_o, + ibus_rsp_i => ibus_rsp_i, + dbus_req_o => dbus_req_o, + dbus_rsp_i => dbus_rsp_i + ); + + -- Instruction bus + wbi_o.adr <= wishbone_address(ibus_req_o.addr); + wbi_o.dat <= wishbone_data(ibus_req_o.data); + wbi_o.sel <= wishbone_byte_select(ibus_req_o.ben); + wbi_o.we <= ibus_req_o.rw; -- TODO: We should also buffer this like we do stb, but in the current version the CPU holds it for us, so :shrug: + wbi_o.cyc <= wbi_o.stb; + ibus_rsp_i.data <= std_ulogic_vector(wbi_i.dat); + + wbi_o.stb <= ibus_req_mask; + ibus_rsp_i.ack <= wbi_i.ack and not (ibus_rsp_mask); + ibus_rsp_i.err <= (wbi_i.err or wbi_i.rty) and not (ibus_rsp_mask); + + wb2bus_i : process(clk) is + begin + if rising_edge(clk) then + if ibus_req_o.stb then + ibus_req_mask <= '1'; + assert ibus_req_o.rvso = '0' report "Error: IBus RVSO not implemented but requested!" severity FAILURE; + end if; + if (wbi_i.ack or wbi_i.err or wbi_i.rty) and not ibus_req_o.stb then + ibus_req_mask <= '0'; + ibus_rsp_mask <= '1'; + + else + ibus_rsp_mask <= '0'; + end if; + + if clr then + ibus_req_mask <= '0'; + ibus_rsp_mask <= '0'; + end if; + end if; + end process wb2bus_i; + + -- Data bus + wbd_o.adr <= wishbone_address(dbus_req_o.addr); + wbd_o.dat <= wishbone_data(dbus_req_o.data); + wbd_o.sel <= wishbone_byte_select(dbus_req_o.ben); + wbd_o.we <= dbus_req_o.rw; + wbd_o.cyc <= wbd_o.stb; + dbus_rsp_i.data <= std_ulogic_vector(wbd_i.dat); + + wbd_o.stb <= dbus_req_mask; + dbus_rsp_i.ack <= wbd_i.ack and not (dbus_rsp_mask); + dbus_rsp_i.err <= (wbd_i.err or wbd_i.rty) and not (dbus_rsp_mask); + + wb2bus_d : process(clk) is + begin + if rising_edge(clk) then + if dbus_req_o.stb then + dbus_req_mask <= '1'; + assert dbus_req_o.rvso = '0' report "Error: dbus RVSO not implemented but requested!" severity FAILURE; + end if; + if (wbd_i.ack or wbd_i.err or wbd_i.rty) and not dbus_req_o.stb then + dbus_req_mask <= '0'; + dbus_rsp_mask <= '1'; + + else + dbus_rsp_mask <= '0'; + end if; + + if clr then + dbus_req_mask <= '0'; + dbus_rsp_mask <= '0'; + end if; + end if; + end process wb2bus_d; + +end architecture rtl; diff --git a/fpga/hdl/design/top.vhd b/fpga/hdl/design/top.vhd index 3ee40ba..7ef2cfe 100644 --- a/fpga/hdl/design/top.vhd +++ b/fpga/hdl/design/top.vhd @@ -23,7 +23,8 @@ entity top is F_IN : integer := 50000000; F_CLK : integer := 25000000; F_CLK_PHY : integer := 50000000; - UART_BAUD : integer := 250000 + UART_BAUD : integer := 250000; + CPU : string := "serv" ); port( clk_in : in std_logic; -- System clock @@ -201,16 +202,38 @@ begin end if; end process por; - serv_top_vhdl_inst : entity work.serv_top_vhdl - port map( - clk => clk, - clr => clr, - wbi_o => wbi_o, - wbi_i => wbi_i, - wbd_o => wbd_o, - wbd_i => wbd_i, - irq_timer => irq_timer - ); + cpu_sel : if CPU = "serv" generate + serv_top_vhdl_inst : entity work.serv_top_vhdl + port map( + clk => clk, + clr => clr, + wbi_o => wbi_o, + wbi_i => wbi_i, + wbd_o => wbd_o, + wbd_i => wbd_i, + irq_timer => irq_timer + ); + + elsif CPU = "neorv32" generate + neorv32_top_vhdl_inst : entity work.neorv32_top_vhdl + port map( + clk => clk, + clr => clr, + wbi_o => wbi_o, + wbi_i => wbi_i, + wbd_o => wbd_o, + wbd_i => wbd_i, + irq_timer => irq_timer + ); + + else generate + cpu_sel_err_p : process is + begin + report "ERROR: Selected invalid CPU" severity FAILURE; + wait; + end process cpu_sel_err_p; + + end generate cpu_sel; servant_rom_vhdl_inst : entity work.servant_ram_vhdl generic map( diff --git a/fpga/hdl/neorv32 b/fpga/hdl/neorv32 new file mode 160000 index 0000000..fd79163 --- /dev/null +++ b/fpga/hdl/neorv32 @@ -0,0 +1 @@ +Subproject commit fd79163eb2d49cc57a9d91061a9fd4f6cdc94644 diff --git a/fpga/run.py b/fpga/run.py index 63b5142..32c3f5a 100755 --- a/fpga/run.py +++ b/fpga/run.py @@ -14,6 +14,7 @@ libraries = { "device_models", "generics", "serv", + "neorv32", "trashernet" } } @@ -38,6 +39,9 @@ for base_path in libraries: if library_name == "trashernet": # Special case: Trashernet submodule path = os.path.join(base_path, "hdl", library_name, library_name, "*.vhd") libs[library_name].add_source_files(path) + elif library_name == "neorv32": # Special case: NEORV32 submodule + path = os.path.join(base_path, "hdl", library_name, "rtl", "core", "*.vhd") + libs[library_name].add_source_files(path) elif library_name == "serv": # Special case: SERV submodule print("Skipping SERV. It's Verilog.") else: # Normal lib diff --git a/fpga/run_physical.py b/fpga/run_physical.py index bb69f93..f35fbaa 100755 --- a/fpga/run_physical.py +++ b/fpga/run_physical.py @@ -13,6 +13,7 @@ libraries = { "device_models", "generics", "serv", + "neorv32", "trashernet" } } @@ -37,6 +38,9 @@ for base_path in libraries: if library_name == "trashernet": # Special case: Trashernet submodule path = os.path.join(base_path, "hdl", library_name, library_name, "*.vhd") libs[library_name].add_source_files(path) + elif library_name == "neorv32": # Special case: NEORV32 submodule + path = os.path.join(base_path, "hdl", library_name, "rtl", "core", "*.vhd") + libs[library_name].add_source_files(path) elif library_name == "serv": # Special case: SERV submodule print("Skipping SERV. It's Verilog.") else: # Normal lib