From b2ddb130d51d9583cd8da3b73fa3dd0a2a1e8569 Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:17:09 +0200 Subject: [PATCH 1/6] [rtl] rework IO module's bus interface --- rtl/core/neorv32_boot_rom.vhd | 26 +++-- rtl/core/neorv32_bus_keeper.vhd | 112 ++++++++++------------ rtl/core/neorv32_busswitch.vhd | 164 +++++++++++++------------------- rtl/core/neorv32_cfs.vhd | 56 +++++------ rtl/core/neorv32_dcache.vhd | 102 ++++++++------------ rtl/core/neorv32_debug_dm.vhd | 46 +++++---- rtl/core/neorv32_dma.vhd | 144 +++++++++++++--------------- rtl/core/neorv32_gpio.vhd | 45 ++++----- rtl/core/neorv32_gptmr.vhd | 58 ++++++----- rtl/core/neorv32_mtime.vhd | 47 +++++---- rtl/core/neorv32_neoled.vhd | 75 +++++++-------- rtl/core/neorv32_onewire.vhd | 59 ++++++------ rtl/core/neorv32_pwm.vhd | 66 ++++++------- rtl/core/neorv32_sdi.vhd | 66 ++++++------- rtl/core/neorv32_spi.vhd | 83 ++++++++-------- rtl/core/neorv32_sysinfo.vhd | 27 +++--- rtl/core/neorv32_trng.vhd | 38 ++++---- rtl/core/neorv32_twi.vhd | 61 ++++++------ rtl/core/neorv32_uart.vhd | 104 ++++++++++---------- rtl/core/neorv32_wdt.vhd | 49 +++++----- rtl/core/neorv32_wishbone.vhd | 63 +++++------- rtl/core/neorv32_xip.vhd | 127 +++++++++++-------------- rtl/core/neorv32_xirq.vhd | 42 ++++---- 23 files changed, 743 insertions(+), 917 deletions(-) diff --git a/rtl/core/neorv32_boot_rom.vhd b/rtl/core/neorv32_boot_rom.vhd index cae1a82e7..e15919e60 100644 --- a/rtl/core/neorv32_boot_rom.vhd +++ b/rtl/core/neorv32_boot_rom.vhd @@ -3,7 +3,7 @@ -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # --- # Copyright (c) 2022, Stephan Nolting. All rights reserved. # +-- # Copyright (c) 2023, Stephan Nolting. All rights reserved. # -- # # -- # Redistribution and use in source and binary forms, with or without modification, are # -- # permitted provided that the following conditions are met: # @@ -45,13 +45,9 @@ entity neorv32_boot_rom is BOOTROM_BASE : std_ulogic_vector(31 downto 0) -- boot ROM base address ); port ( - clk_i : in std_ulogic; -- global clock line - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - addr_i : in std_ulogic_vector(31 downto 0); -- address - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic -- transfer error + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end neorv32_boot_rom; @@ -68,6 +64,7 @@ architecture neorv32_boot_rom_rtl of neorv32_boot_rom is -- local signals -- signal acc_en : std_ulogic; signal rden : std_ulogic; + signal wren : std_ulogic; signal rdata : std_ulogic_vector(31 downto 0); signal addr : std_ulogic_vector(boot_rom_size_index_c-1 downto 0); @@ -87,8 +84,8 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = BOOTROM_BASE(hi_abb_c downto lo_abb_c)) else '0'; - addr <= addr_i(boot_rom_size_index_c+1 downto 2); -- word aligned + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = BOOTROM_BASE(hi_abb_c downto lo_abb_c)) else '0'; + addr <= bus_req_i.addr(boot_rom_size_index_c+1 downto 2); -- word aligned -- Memory Access -------------------------------------------------------------------------- @@ -96,8 +93,8 @@ begin mem_file_access: process(clk_i) begin if rising_edge(clk_i) then - rden <= acc_en and rden_i; - err_o <= acc_en and wren_i; + rden <= acc_en and bus_req_i.re; + wren <= acc_en and bus_req_i.we; if (acc_en = '1') then -- reduce switching activity when not accessed rdata <= mem_rom(to_integer(unsigned(addr))); end if; @@ -105,8 +102,9 @@ begin end process mem_file_access; -- output gate -- - data_o <= rdata when (rden = '1') else (others => '0'); - ack_o <= rden; + bus_rsp_o.data <= rdata when (rden = '1') else (others => '0'); + bus_rsp_o.ack <= rden; + bus_rsp_o.err <= wren; end neorv32_boot_rom_rtl; diff --git a/rtl/core/neorv32_bus_keeper.vhd b/rtl/core/neorv32_bus_keeper.vhd index ad968303a..be512cd41 100644 --- a/rtl/core/neorv32_bus_keeper.vhd +++ b/rtl/core/neorv32_bus_keeper.vhd @@ -45,25 +45,16 @@ use neorv32.neorv32_package.all; entity neorv32_bus_keeper is port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic; -- transfer error - -- bus monitoring -- - bus_addr_i : in std_ulogic_vector(31 downto 0); -- address - bus_rden_i : in std_ulogic; -- read enable - bus_wren_i : in std_ulogic; -- write enable - bus_ack_i : in std_ulogic; -- transfer acknowledge from bus system - bus_err_i : in std_ulogic; -- transfer error from bus system - bus_tmo_i : in std_ulogic; -- transfer timeout (external interface) - bus_ext_i : in std_ulogic; -- external bus access - bus_xip_i : in std_ulogic -- pending XIP access + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset, low-active, async + cpu_req_i : in bus_req_t; -- control request bus + cpu_rsp_o : out bus_rsp_t; -- control response bus + bus_req_i : in bus_req_t; -- monitor request bus + bus_rsp_i : in bus_rsp_t; -- monitor response bus + bus_err_o : out std_ulogic; -- signal bus error to CPU + bus_tmo_i : in std_ulogic; -- transfer timeout (external interface) + bus_ext_i : in std_ulogic; -- external bus access + bus_xip_i : in std_ulogic -- pending XIP access ); end neorv32_bus_keeper; @@ -94,15 +85,14 @@ architecture neorv32_bus_keeper_rtl of neorv32_bus_keeper is constant cnt_width_c : natural := index_size_f(max_proc_int_response_time_c); -- controller -- - type control_t is record + type ctrl_t is record pending : std_ulogic; timeout : std_ulogic_vector(cnt_width_c-1 downto 0); err_type : std_ulogic; bus_err : std_ulogic; ignore : std_ulogic; - expired : std_ulogic; end record; - signal control : control_t; + signal ctrl : ctrl_t; begin @@ -116,9 +106,9 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = buskeeper_base_c(hi_abb_c downto lo_abb_c)) else '0'; - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (cpu_req_i.addr(hi_abb_c downto lo_abb_c) = buskeeper_base_c(hi_abb_c downto lo_abb_c)) else '0'; + wren <= acc_en and cpu_req_i.we; + rden <= acc_en and cpu_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -127,9 +117,9 @@ begin err_flag <= '0'; err_type <= '0'; elsif rising_edge(clk_i) then - if (control.bus_err = '1') then -- sticky error flag + if (ctrl.bus_err = '1') then -- sticky error flag err_flag <= '1'; - err_type <= control.err_type; + err_type <= ctrl.err_type; elsif (wren = '1') or (rden = '1') then -- clear on read or write access err_flag <= '0'; end if; @@ -140,69 +130,67 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= wren or rden; -- bus handshake - data_o <= (others => '0'); + cpu_rsp_o.ack <= wren or rden; -- bus handshake + cpu_rsp_o.data <= (others => '0'); if (rden = '1') then - data_o(ctrl_err_type_c) <= err_type; - data_o(ctrl_err_flag_c) <= err_flag; + cpu_rsp_o.data(ctrl_err_type_c) <= err_type; + cpu_rsp_o.data(ctrl_err_flag_c) <= err_flag; end if; end if; end process read_access; + -- no access error possible -- + cpu_rsp_o.err <= '0'; + -- Monitor -------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- keeper_control: process(rstn_i, clk_i) begin if (rstn_i = '0') then - control.pending <= '0'; - control.bus_err <= '0'; - control.err_type <= '0'; - control.timeout <= (others => '0'); - control.ignore <= '0'; + ctrl.pending <= '0'; + ctrl.bus_err <= '0'; + ctrl.err_type <= '0'; + ctrl.timeout <= (others => '0'); + ctrl.ignore <= '0'; elsif rising_edge(clk_i) then -- defaults -- - control.bus_err <= '0'; + ctrl.bus_err <= '0'; -- IDLE -- - if (control.pending = '0') then - control.timeout <= std_ulogic_vector(to_unsigned(max_proc_int_response_time_c-1, cnt_width_c)); - control.ignore <= '0'; - if (bus_rden_i = '1') or (bus_wren_i = '1') then - control.pending <= '1'; + if (ctrl.pending = '0') then + ctrl.timeout <= std_ulogic_vector(to_unsigned(max_proc_int_response_time_c-1, cnt_width_c)); + ctrl.ignore <= '0'; + if (bus_req_i.re = '1') or (bus_req_i.we = '1') then + ctrl.pending <= '1'; end if; -- PENDING -- else -- countdown timer -- - if (control.expired = '0') then - control.timeout <= std_ulogic_vector(unsigned(control.timeout) - 1); - end if; + ctrl.timeout <= std_ulogic_vector(unsigned(ctrl.timeout) - 1); -- bus keeper shall ignore internal timeout during this access (because it's "external") -- - control.ignore <= control.ignore or (bus_ext_i or bus_xip_i); + ctrl.ignore <= ctrl.ignore or (bus_ext_i or bus_xip_i); -- response handling -- - if (bus_err_i = '1') then -- error termination by bus system - control.err_type <= err_device_c; -- device error - control.bus_err <= '1'; - control.pending <= '0'; - elsif ((control.expired = '1') and (control.ignore = '0')) or -- valid INTERNAL access timeout + if (bus_rsp_i.err = '1') then -- error termination by bus system + ctrl.err_type <= err_device_c; -- device error + ctrl.bus_err <= '1'; + ctrl.pending <= '0'; + elsif ((or_reduce_f(ctrl.timeout) = '0') and (ctrl.ignore = '0')) or -- valid INTERNAL access timeout (bus_tmo_i = '1') then -- EXTERNAL access timeout - control.err_type <= err_timeout_c; -- timeout error - control.bus_err <= '1'; - control.pending <= '0'; - elsif (bus_ack_i = '1') then -- normal termination by bus system - control.err_type <= '0'; -- don't care - control.bus_err <= '0'; - control.pending <= '0'; + ctrl.err_type <= err_timeout_c; -- timeout error + ctrl.bus_err <= '1'; + ctrl.pending <= '0'; + elsif (bus_rsp_i.ack = '1') then -- normal termination by bus system + ctrl.err_type <= '0'; -- don't care + ctrl.bus_err <= '0'; + ctrl.pending <= '0'; end if; end if; end if; end process keeper_control; - -- timeout counter expired? -- - control.expired <= '1' when (or_reduce_f(control.timeout) = '0') else '0'; - -- signal bus error to CPU -- - err_o <= control.bus_err; + bus_err_o <= ctrl.bus_err; end neorv32_bus_keeper_rtl; diff --git a/rtl/core/neorv32_busswitch.vhd b/rtl/core/neorv32_busswitch.vhd index 8c15d0339..f2eecc66b 100644 --- a/rtl/core/neorv32_busswitch.vhd +++ b/rtl/core/neorv32_busswitch.vhd @@ -44,64 +44,33 @@ use neorv32.neorv32_package.all; entity neorv32_busswitch is generic ( - PORT_CA_READ_ONLY : boolean; -- set if controller port A is read-only - PORT_CB_READ_ONLY : boolean -- set if controller port B is read-only + PORT_A_READ_ONLY : boolean; -- set if port A is read-only + PORT_B_READ_ONLY : boolean -- set if port B is read-only ); port ( - -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - -- controller interface a -- - ca_bus_priv_i : in std_ulogic; -- current privilege level - ca_bus_cached_i : in std_ulogic; -- set if cached transfer - ca_bus_src_i : in std_ulogic; -- access source - ca_bus_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - ca_bus_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - ca_bus_wdata_i : in std_ulogic_vector(31 downto 0); -- bus write data - ca_bus_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable - ca_bus_we_i : in std_ulogic; -- write enable - ca_bus_re_i : in std_ulogic; -- read enable - ca_bus_ack_o : out std_ulogic; -- bus transfer acknowledge - ca_bus_err_o : out std_ulogic; -- bus transfer error - -- controller interface b -- - cb_bus_priv_i : in std_ulogic; -- current privilege level - cb_bus_cached_i : in std_ulogic; -- set if cached transfer - cb_bus_src_i : in std_ulogic; -- access source - cb_bus_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - cb_bus_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - cb_bus_wdata_i : in std_ulogic_vector(31 downto 0); -- bus write data - cb_bus_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable - cb_bus_we_i : in std_ulogic; -- write enable - cb_bus_re_i : in std_ulogic; -- read enable - cb_bus_ack_o : out std_ulogic; -- bus transfer acknowledge - cb_bus_err_o : out std_ulogic; -- bus transfer error - -- peripheral bus -- - p_bus_priv_o : out std_ulogic; -- current privilege level - p_bus_cached_o : out std_ulogic; -- set if cached transfer - p_bus_src_o : out std_ulogic; -- access source - p_bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - p_bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - p_bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - p_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - p_bus_we_o : out std_ulogic; -- write enable - p_bus_re_o : out std_ulogic; -- read enable - p_bus_ack_i : in std_ulogic; -- bus transfer acknowledge - p_bus_err_i : in std_ulogic -- bus transfer error + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + a_req_i : in bus_req_t; -- host port A: request bus + a_rsp_o : out bus_rsp_t; -- host port A: response bus + b_req_i : in bus_req_t; -- host port B: request bus + b_rsp_o : out bus_rsp_t; -- host port B: response bus + x_req_o : out bus_req_t; -- device port request bus + x_rsp_i : in bus_rsp_t -- device port response bus ); end neorv32_busswitch; architecture neorv32_busswitch_rtl of neorv32_busswitch is -- access requests -- - signal ca_rd_req_buf, ca_wr_req_buf : std_ulogic; - signal cb_rd_req_buf, cb_wr_req_buf : std_ulogic; - signal ca_req_current, ca_req_pending : std_ulogic; - signal cb_req_current, cb_req_pending : std_ulogic; + signal a_rd_req_buf, a_wr_req_buf : std_ulogic; + signal b_rd_req_buf, b_wr_req_buf : std_ulogic; + signal a_req_current, a_req_pending : std_ulogic; + signal b_req_current, b_req_pending : std_ulogic; -- internal bus lines -- - signal ca_bus_ack, cb_bus_ack : std_ulogic; - signal ca_bus_err, cb_bus_err : std_ulogic; - signal p_bus_we, p_bus_re : std_ulogic; + signal a_bus_ack, b_bus_ack : std_ulogic; + signal a_bus_err, b_bus_err : std_ulogic; + signal x_bus_we, x_bus_re : std_ulogic; -- access arbiter -- type arbiter_state_t is (IDLE, A_BUSY, A_RETIRE, B_BUSY, B_RETIRE); @@ -122,32 +91,32 @@ begin begin if (rstn_i = '0') then arbiter.state <= IDLE; - ca_rd_req_buf <= '0'; - ca_wr_req_buf <= '0'; - cb_rd_req_buf <= '0'; - cb_wr_req_buf <= '0'; + a_rd_req_buf <= '0'; + a_wr_req_buf <= '0'; + b_rd_req_buf <= '0'; + b_wr_req_buf <= '0'; elsif rising_edge(clk_i) then arbiter.state <= arbiter.state_nxt; -- port A requests -- - ca_rd_req_buf <= (ca_rd_req_buf or ca_bus_re_i) and (not (ca_bus_err or ca_bus_ack)); - ca_wr_req_buf <= (ca_wr_req_buf or ca_bus_we_i) and (not (ca_bus_err or ca_bus_ack)) and bool_to_ulogic_f(PORT_CA_READ_ONLY = false); + a_rd_req_buf <= (a_rd_req_buf or a_req_i.re) and (not (a_bus_err or a_bus_ack)); + a_wr_req_buf <= (a_wr_req_buf or a_req_i.we) and (not (a_bus_err or a_bus_ack)) and bool_to_ulogic_f(PORT_A_READ_ONLY = false); -- port B requests -- - cb_rd_req_buf <= (cb_rd_req_buf or cb_bus_re_i) and (not (cb_bus_err or cb_bus_ack)); - cb_wr_req_buf <= (cb_wr_req_buf or cb_bus_we_i) and (not (cb_bus_err or cb_bus_ack)) and bool_to_ulogic_f(PORT_CB_READ_ONLY = false); + b_rd_req_buf <= (b_rd_req_buf or b_req_i.re) and (not (b_bus_err or b_bus_ack)); + b_wr_req_buf <= (b_wr_req_buf or b_req_i.we) and (not (b_bus_err or b_bus_ack)) and bool_to_ulogic_f(PORT_B_READ_ONLY = false); end if; end process arbiter_sync; -- any current requests? -- - ca_req_current <= (ca_bus_re_i or ca_bus_we_i) when (PORT_CA_READ_ONLY = false) else ca_bus_re_i; - cb_req_current <= (cb_bus_re_i or cb_bus_we_i) when (PORT_CB_READ_ONLY = false) else cb_bus_re_i; + a_req_current <= (a_req_i.re or a_req_i.we) when (PORT_A_READ_ONLY = false) else a_req_i.re; + b_req_current <= (b_req_i.re or b_req_i.we) when (PORT_B_READ_ONLY = false) else b_req_i.re; -- any pending requests? -- - ca_req_pending <= (ca_rd_req_buf or ca_wr_req_buf) when (PORT_CA_READ_ONLY = false) else ca_rd_req_buf; - cb_req_pending <= (cb_rd_req_buf or cb_wr_req_buf) when (PORT_CB_READ_ONLY = false) else cb_rd_req_buf; + a_req_pending <= (a_rd_req_buf or a_wr_req_buf) when (PORT_A_READ_ONLY = false) else a_rd_req_buf; + b_req_pending <= (b_rd_req_buf or b_wr_req_buf) when (PORT_B_READ_ONLY = false) else b_rd_req_buf; -- FSM -- - arbiter_comb: process(arbiter, ca_req_current, cb_req_current, ca_req_pending, cb_req_pending, - ca_rd_req_buf, ca_wr_req_buf, cb_rd_req_buf, cb_wr_req_buf, p_bus_ack_i, p_bus_err_i) + arbiter_comb: process(arbiter, a_req_current, b_req_current, a_req_pending, b_req_pending, + a_rd_req_buf, a_wr_req_buf, b_rd_req_buf, b_wr_req_buf, x_rsp_i) begin -- arbiter defaults -- arbiter.state_nxt <= arbiter.state; @@ -160,16 +129,16 @@ begin when IDLE => -- wait for requests -- ------------------------------------------------------------ - if (ca_req_current = '1') then -- current request from port A? + if (a_req_current = '1') then -- current request from port A? arbiter.bus_sel <= '0'; arbiter.state_nxt <= A_BUSY; - elsif (ca_req_pending = '1') then -- pending request from port A? + elsif (a_req_pending = '1') then -- pending request from port A? arbiter.bus_sel <= '0'; arbiter.state_nxt <= A_RETIRE; - elsif (cb_req_current = '1') then -- pending request from port B? + elsif (b_req_current = '1') then -- pending request from port B? arbiter.bus_sel <= '1'; arbiter.state_nxt <= B_BUSY; - elsif (cb_req_pending = '1') then -- current request from port B? + elsif (b_req_pending = '1') then -- current request from port B? arbiter.bus_sel <= '1'; arbiter.state_nxt <= B_RETIRE; end if; @@ -177,9 +146,9 @@ begin when A_BUSY => -- port A pending access -- ------------------------------------------------------------ arbiter.bus_sel <= '0'; -- access from port A - if (p_bus_err_i = '1') or (p_bus_ack_i = '1') then + if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then -- [COMMENT NOTE] Direct return to IDLE to further promote port A access requests. --- if (cb_req_pending = '1') or (cb_req_current = '1') then -- any request from B? +-- if (b_req_pending = '1') or (b_req_current = '1') then -- any request from B? -- arbiter.state_nxt <= B_RETIRE; -- else arbiter.state_nxt <= IDLE; @@ -189,15 +158,15 @@ begin when A_RETIRE => -- retire port A pending access -- ------------------------------------------------------------ arbiter.bus_sel <= '0'; -- access from port A - arbiter.we_trig <= ca_wr_req_buf; - arbiter.re_trig <= ca_rd_req_buf; + arbiter.we_trig <= a_wr_req_buf; + arbiter.re_trig <= a_rd_req_buf; arbiter.state_nxt <= A_BUSY; when B_BUSY => -- port B pending access -- ------------------------------------------------------------ arbiter.bus_sel <= '1'; -- access from port B - if (p_bus_err_i = '1') or (p_bus_ack_i = '1') then - if (ca_req_pending = '1') or (ca_req_current = '1') then -- any request from A? + if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then + if (a_req_pending = '1') or (a_req_current = '1') then -- any request from A? arbiter.state_nxt <= A_RETIRE; else arbiter.state_nxt <= IDLE; @@ -207,8 +176,8 @@ begin when B_RETIRE => -- retire port B pending access -- ------------------------------------------------------------ arbiter.bus_sel <= '1'; -- access from port B - arbiter.we_trig <= cb_wr_req_buf; - arbiter.re_trig <= cb_rd_req_buf; + arbiter.we_trig <= b_wr_req_buf; + arbiter.re_trig <= b_rd_req_buf; arbiter.state_nxt <= B_BUSY; when others => -- undefined @@ -221,37 +190,36 @@ begin -- Peripheral Bus Switch ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - p_bus_addr_o <= ca_bus_addr_i when (arbiter.bus_sel = '0') else cb_bus_addr_i; + x_req_o.addr <= a_req_i.addr when (arbiter.bus_sel = '0') else b_req_i.addr; - p_bus_wdata_o <= cb_bus_wdata_i when (PORT_CA_READ_ONLY = true) else - ca_bus_wdata_i when (PORT_CB_READ_ONLY = true) else - ca_bus_wdata_i when (arbiter.bus_sel = '0') else cb_bus_wdata_i; + x_req_o.data <= b_req_i.data when (PORT_A_READ_ONLY = true) else + a_req_i.data when (PORT_B_READ_ONLY = true) else + a_req_i.data when (arbiter.bus_sel = '0') else b_req_i.data; - p_bus_ben_o <= cb_bus_ben_i when (PORT_CA_READ_ONLY = true) else - ca_bus_ben_i when (PORT_CB_READ_ONLY = true) else - ca_bus_ben_i when (arbiter.bus_sel = '0') else cb_bus_ben_i; + x_req_o.ben <= b_req_i.ben when (PORT_A_READ_ONLY = true) else + a_req_i.ben when (PORT_B_READ_ONLY = true) else + a_req_i.ben when (arbiter.bus_sel = '0') else b_req_i.ben; - p_bus_cached_o <= ca_bus_cached_i when (arbiter.bus_sel = '0') else cb_bus_cached_i; - p_bus_priv_o <= ca_bus_priv_i when (arbiter.bus_sel = '0') else cb_bus_priv_i; - p_bus_src_o <= ca_bus_src_i when (arbiter.bus_sel = '0') else cb_bus_src_i; + x_req_o.priv <= a_req_i.priv when (arbiter.bus_sel = '0') else b_req_i.priv; + x_req_o.src <= a_req_i.src when (arbiter.bus_sel = '0') else b_req_i.src; - p_bus_we <= ca_bus_we_i when (arbiter.bus_sel = '0') else cb_bus_we_i; - p_bus_re <= ca_bus_re_i when (arbiter.bus_sel = '0') else cb_bus_re_i; - p_bus_we_o <= p_bus_we or arbiter.we_trig; - p_bus_re_o <= p_bus_re or arbiter.re_trig; + x_bus_we <= a_req_i.we when (arbiter.bus_sel = '0') else b_req_i.we; + x_bus_re <= a_req_i.re when (arbiter.bus_sel = '0') else b_req_i.re; + x_req_o.we <= x_bus_we or arbiter.we_trig; + x_req_o.re <= x_bus_re or arbiter.re_trig; - ca_bus_rdata_o <= p_bus_rdata_i; - cb_bus_rdata_o <= p_bus_rdata_i; + a_rsp_o.data <= x_rsp_i.data; + b_rsp_o.data <= x_rsp_i.data; - ca_bus_ack <= p_bus_ack_i when (arbiter.bus_sel = '0') else '0'; - cb_bus_ack <= p_bus_ack_i when (arbiter.bus_sel = '1') else '0'; - ca_bus_ack_o <= ca_bus_ack; - cb_bus_ack_o <= cb_bus_ack; + a_bus_ack <= x_rsp_i.ack when (arbiter.bus_sel = '0') else '0'; + b_bus_ack <= x_rsp_i.ack when (arbiter.bus_sel = '1') else '0'; + a_rsp_o.ack <= a_bus_ack; + b_rsp_o.ack <= b_bus_ack; - ca_bus_err <= p_bus_err_i when (arbiter.bus_sel = '0') else '0'; - cb_bus_err <= p_bus_err_i when (arbiter.bus_sel = '1') else '0'; - ca_bus_err_o <= ca_bus_err; - cb_bus_err_o <= cb_bus_err; + a_bus_err <= x_rsp_i.err when (arbiter.bus_sel = '0') else '0'; + b_bus_err <= x_rsp_i.err when (arbiter.bus_sel = '1') else '0'; + a_rsp_o.err <= a_bus_err; + b_rsp_o.err <= b_bus_err; end neorv32_busswitch_rtl; diff --git a/rtl/core/neorv32_cfs.vhd b/rtl/core/neorv32_cfs.vhd index 7b54bd312..c8b061fe1 100644 --- a/rtl/core/neorv32_cfs.vhd +++ b/rtl/core/neorv32_cfs.vhd @@ -10,7 +10,7 @@ -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # --- # Copyright (c) 2022, Stephan Nolting. All rights reserved. # +-- # Copyright (c) 2023, Stephan Nolting. All rights reserved. # -- # # -- # Redistribution and use in source and binary forms, with or without modification, are # -- # permitted provided that the following conditions are met: # @@ -53,25 +53,15 @@ entity neorv32_cfs is CFS_OUT_SIZE : natural -- size of CFS output conduit in bits ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, use as async - priv_i : in std_ulogic; -- current CPU privilege mode - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- word write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic; -- transfer error - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(07 downto 0); -- "clock" inputs - -- interrupt -- irq_o : out std_ulogic; -- interrupt request - -- custom io (conduits) -- - cfs_in_i : in std_ulogic_vector(CFS_IN_SIZE-1 downto 0); -- custom inputs - cfs_out_o : out std_ulogic_vector(CFS_OUT_SIZE-1 downto 0) -- custom outputs + cfs_in_i : in std_ulogic_vector(CFS_IN_SIZE-1 downto 0); -- custom inputs + cfs_out_o : out std_ulogic_vector(CFS_OUT_SIZE-1 downto 0) -- custom outputs ); end neorv32_cfs; @@ -99,10 +89,10 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- This logic is required to handle the CPU accesses - DO NOT MODIFY! - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = cfs_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= cfs_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; -- only full-word write accesses are supported - rden <= acc_en and rden_i; -- read accesses always return a full 32-bit word + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = cfs_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= cfs_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; -- only full-word write accesses are supported + rden <= acc_en and bus_req_i.re; -- read accesses always return a full 32-bit word -- CFS Generics --------------------------------------------------------------------------- @@ -197,7 +187,7 @@ begin -- that can be handled by the application software. Note that the current privilege level should not be exposed to software to -- maintain full virtualization. Hence, CFS-based "privilege escalation" should trigger a bus access exception (e.g. by setting 'err_o'). - err_o <= '0'; -- Tie to zero if not explicitly used. + bus_rsp_o.err <= '0'; -- Tie to zero if not explicitly used. -- Host access example: Read and write access to the interface registers + bus transfer acknowledge. This example only @@ -214,39 +204,39 @@ begin cfs_reg_wr(2) <= (others => '0'); cfs_reg_wr(3) <= (others => '0'); -- - ack_o <= '0'; - data_o <= (others => '0'); + bus_rsp_o.ack <= '0'; + bus_rsp_o.data <= (others => '0'); elsif rising_edge(clk_i) then -- synchronous interface for read and write accesses -- transfer/access acknowledge -- -- default: required for the CPU to check the CFS is answering a bus read OR write request; -- all read and write accesses (to any cfs_reg, even if there is no according physical register implemented) will succeed. - ack_o <= rden or wren; + bus_rsp_o.ack <= rden or wren; -- write access -- if (wren = '1') then -- full-word write access, high for one cycle if there is an actual write access if (addr = cfs_reg0_addr_c) then -- make sure to use the internal "addr" signal for the read/write interface - cfs_reg_wr(0) <= data_i; -- some physical register, for example: control register + cfs_reg_wr(0) <= bus_req_i.data; -- some physical register, for example: control register end if; if (addr = cfs_reg1_addr_c) then - cfs_reg_wr(1) <= data_i; -- some physical register, for example: data in/out fifo + cfs_reg_wr(1) <= bus_req_i.data; -- some physical register, for example: data in/out fifo end if; if (addr = cfs_reg2_addr_c) then - cfs_reg_wr(2) <= data_i; -- some physical register, for example: command fifo + cfs_reg_wr(2) <= bus_req_i.data; -- some physical register, for example: command fifo end if; if (addr = cfs_reg3_addr_c) then - cfs_reg_wr(3) <= data_i; -- some physical register, for example: status register + cfs_reg_wr(3) <= bus_req_i.data; -- some physical register, for example: status register end if; end if; -- read access -- - data_o <= (others => '0'); -- the output HAS TO BE ZERO if there is no actual read access + bus_rsp_o.data <= (others => '0'); -- the output HAS TO BE ZERO if there is no actual read access if (rden = '1') then -- the read access is always 32-bit wide, high for one cycle if there is an actual read access case addr is -- make sure to use the internal 'addr' signal for the read/write interface - when cfs_reg0_addr_c => data_o <= cfs_reg_rd(0); - when cfs_reg1_addr_c => data_o <= cfs_reg_rd(1); - when cfs_reg2_addr_c => data_o <= cfs_reg_rd(2); - when cfs_reg3_addr_c => data_o <= cfs_reg_rd(3); - when others => data_o <= (others => '0'); -- the remaining registers are not implemented and will read as zero + when cfs_reg0_addr_c => bus_rsp_o.data <= cfs_reg_rd(0); + when cfs_reg1_addr_c => bus_rsp_o.data <= cfs_reg_rd(1); + when cfs_reg2_addr_c => bus_rsp_o.data <= cfs_reg_rd(2); + when cfs_reg3_addr_c => bus_rsp_o.data <= cfs_reg_rd(3); + when others => bus_rsp_o.data <= (others => '0'); -- the remaining registers are not implemented and will read as zero end case; end if; end if; diff --git a/rtl/core/neorv32_dcache.vhd b/rtl/core/neorv32_dcache.vhd index 4e31be7aa..52a599611 100644 --- a/rtl/core/neorv32_dcache.vhd +++ b/rtl/core/neorv32_dcache.vhd @@ -49,29 +49,13 @@ entity neorv32_dcache is DCACHE_UC_PBEGIN : std_ulogic_vector(3 downto 0) -- begin of uncached address space (page number) ); port ( - -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - clear_i : in std_ulogic; -- cache clear - -- host controller interface -- - host_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - host_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - host_wdata_i : in std_ulogic_vector(31 downto 0); -- bus write data - host_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable - host_we_i : in std_ulogic; -- write enable - host_re_i : in std_ulogic; -- read enable - host_ack_o : out std_ulogic; -- bus transfer acknowledge - host_err_o : out std_ulogic; -- bus transfer error - -- peripheral bus interface -- - bus_cached_o : out std_ulogic; -- set if cached (!) access in progress - bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - bus_we_o : out std_ulogic; -- write enable - bus_re_o : out std_ulogic; -- read enable - bus_ack_i : in std_ulogic; -- bus transfer acknowledge - bus_err_i : in std_ulogic -- bus transfer error + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + clear_i : in std_ulogic; -- cache clear + cpu_req_i : in bus_req_t; -- request bus + cpu_rsp_o : out bus_rsp_t; -- response bus + bus_req_o : out bus_req_t; -- request bus + bus_rsp_i : in bus_rsp_t -- response bus ); end neorv32_dcache; @@ -175,16 +159,15 @@ begin -- Control Engine FSM Comb ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - ctrl_engine_comb: process(ctrl, cache, clear_i, bus_ack_i, bus_err_i, bus_rdata_i, - host_re_i, host_we_i, host_addr_i, host_wdata_i, host_ben_i) + ctrl_engine_comb: process(ctrl, cache, clear_i, cpu_req_i, bus_rsp_i) begin -- control defaults -- ctrl.state_nxt <= ctrl.state; ctrl.addr_reg_nxt <= ctrl.addr_reg; -- request buffer -- - ctrl.re_buf_nxt <= ctrl.re_buf or host_re_i; - ctrl.we_buf_nxt <= ctrl.we_buf or host_we_i; + ctrl.re_buf_nxt <= ctrl.re_buf or cpu_req_i.re; + ctrl.we_buf_nxt <= ctrl.we_buf or cpu_req_i.we; ctrl.clear_buf_nxt <= ctrl.clear_buf or clear_i; -- cache defaults -- @@ -192,31 +175,33 @@ begin cache.ctrl_addr <= ctrl.addr_reg; cache.ctrl_we <= '0'; cache.ctrl_ben <= "1111"; - cache.ctrl_wdata <= bus_rdata_i; - cache.ctrl_wstat <= bus_err_i; + cache.ctrl_wdata <= bus_rsp_i.data; + cache.ctrl_wstat <= bus_rsp_i.err; -- host interface defaults -- - host_ack_o <= '0'; - host_err_o <= '0'; - host_rdata_o <= cache.host_rdata; + cpu_rsp_o.data <= cache.host_rdata; + cpu_rsp_o.ack <= '0'; + cpu_rsp_o.err <= '0'; -- peripheral bus interface defaults -- - bus_addr_o <= ctrl.addr_reg; - bus_wdata_o <= host_wdata_i; - bus_ben_o <= host_ben_i; - bus_re_o <= '0'; - bus_we_o <= '0'; + bus_req_o.addr <= ctrl.addr_reg; + bus_req_o.data <= cpu_req_i.data; + bus_req_o.ben <= cpu_req_i.ben; + bus_req_o.re <= '0'; + bus_req_o.we <= '0'; + bus_req_o.src <= cpu_req_i.src; + bus_req_o.priv <= cpu_req_i.priv; -- fsm -- case ctrl.state is when S_IDLE => -- wait for host access request or cache control operation -- ------------------------------------------------------------ - ctrl.addr_reg_nxt <= host_addr_i; + ctrl.addr_reg_nxt <= cpu_req_i.addr; if (ctrl.clear_buf = '1') then -- invalidate cache ctrl.state_nxt <= S_CLEAR; - elsif (host_re_i = '1') or (ctrl.re_buf = '1') or (host_we_i = '1') or (ctrl.we_buf = '1') then - if (unsigned(host_addr_i(31 downto 28)) >= unsigned(DCACHE_UC_PBEGIN)) then -- uncached access -> direct access + elsif (cpu_req_i.re = '1') or (ctrl.re_buf = '1') or (cpu_req_i.we = '1') or (ctrl.we_buf = '1') then + if (unsigned(cpu_req_i.addr(31 downto 28)) >= unsigned(DCACHE_UC_PBEGIN)) then -- uncached access -> direct access ctrl.state_nxt <= S_DIRECT_REQ; else -- cached access ctrl.state_nxt <= S_CHECK; @@ -234,9 +219,9 @@ begin ctrl.re_buf_nxt <= '0'; ctrl.we_buf_nxt <= '0'; if (cache.host_rstat = '1') then -- erroneous read access? - host_err_o <= '1'; + cpu_rsp_o.err <= '1'; else - host_ack_o <= '1'; + cpu_rsp_o.ack <= '1'; end if; ctrl.state_nxt <= S_IDLE; else -- cache MISS -> download block @@ -253,12 +238,12 @@ begin when S_DOWNLOAD_REQ => -- download new cache block: request new word -- ------------------------------------------------------------ - bus_re_o <= '1'; -- request new read transfer + bus_req_o.re <= '1'; -- request new read transfer ctrl.state_nxt <= S_DOWNLOAD_WAIT; when S_DOWNLOAD_WAIT => -- download new cache block: wait for bus response -- ------------------------------------------------------------ - if (bus_ack_i = '1') or (bus_err_i = '1') then -- ACK or ERROR -> write to cache and get next word (store ERROR flag in cache) + if (bus_rsp_i.ack = '1') or (bus_rsp_i.err = '1') then -- ACK or ERROR -> write to cache and get next word (store ERROR flag in cache) cache.ctrl_we <= '1'; -- write to cache ctrl.addr_reg_nxt <= std_ulogic_vector(unsigned(ctrl.addr_reg) + 4); if (and_reduce_f(ctrl.addr_reg((cache_offset_size_c+2)-1 downto 2)) = '1') then -- block complete? @@ -271,27 +256,27 @@ begin when S_DIRECT_REQ => -- direct uncached access: request access -- ------------------------------------------------------------ - bus_re_o <= ctrl.re_buf; - bus_we_o <= ctrl.we_buf; + bus_req_o.re <= ctrl.re_buf; + bus_req_o.we <= ctrl.we_buf; ctrl.state_nxt <= S_DIRECT_WAIT; when S_DIRECT_WAIT => -- direct uncached access: wait for bus response -- ------------------------------------------------------------ ctrl.re_buf_nxt <= '0'; ctrl.we_buf_nxt <= '0'; - host_rdata_o <= bus_rdata_i; - if (bus_err_i = '1') then - host_err_o <= '1'; + cpu_rsp_o.data <= bus_rsp_i.data; + if (bus_rsp_i.err = '1') then + cpu_rsp_o.err <= '1'; ctrl.state_nxt <= S_IDLE; - elsif (bus_ack_i = '1') then - host_ack_o <= '1'; + elsif (bus_rsp_i.ack = '1') then + cpu_rsp_o.ack <= '1'; ctrl.state_nxt <= S_IDLE; end if; when S_RESYNC => -- re-sync host/cache access -- ------------------------------------------------------------ - ctrl.addr_reg_nxt <= host_addr_i; -- restore original access address + ctrl.addr_reg_nxt <= cpu_req_i.addr; -- restore original access address if (ctrl.we_buf = '1') then -- write access ctrl.state_nxt <= S_RESYNC_WRITE; else -- read access @@ -300,11 +285,11 @@ begin when S_RESYNC_WRITE => -- finalize cached write access -- ------------------------------------------------------------ - bus_we_o <= '1'; -- trigger bus write access + bus_req_o.we <= '1'; -- trigger bus write access cache.ctrl_we <= '1'; -- write to cache - cache.ctrl_ben <= host_ben_i; - cache.ctrl_addr <= host_addr_i; - cache.ctrl_wdata <= host_wdata_i; + cache.ctrl_ben <= cpu_req_i.ben; + cache.ctrl_addr <= cpu_req_i.addr; + cache.ctrl_wdata <= cpu_req_i.data; cache.ctrl_wstat <= '0'; -- no error possible here ctrl.state_nxt <= S_DIRECT_WAIT; @@ -322,9 +307,6 @@ begin end case; end process ctrl_engine_comb; - -- cached access? -- - bus_cached_o <= '1' when (ctrl.state = S_DOWNLOAD_REQ) or (ctrl.state = S_DOWNLOAD_WAIT) else '0'; - -- Cache Memory --------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -339,7 +321,7 @@ begin clear_i => cache.clear, hit_o => cache.hit, -- host cache access -- - host_addr_i => host_addr_i, + host_addr_i => cpu_req_i.addr, host_rdata_o => cache.host_rdata, host_rstat_o => cache.host_rstat, -- ctrl cache access -- diff --git a/rtl/core/neorv32_debug_dm.vhd b/rtl/core/neorv32_debug_dm.vhd index 7acad94c7..db0315f31 100644 --- a/rtl/core/neorv32_debug_dm.vhd +++ b/rtl/core/neorv32_debug_dm.vhd @@ -60,6 +60,7 @@ entity neorv32_debug_dm is -- global control -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active + cpu_debug_i : in std_ulogic; -- CPU is in debug mode -- debug module interface (DMI) -- dmi_req_valid_i : in std_ulogic; dmi_req_ready_o : out std_ulogic; -- DMI is allowed to make new requests when set @@ -71,14 +72,8 @@ entity neorv32_debug_dm is dmi_rsp_data_o : out std_ulogic_vector(31 downto 0); dmi_rsp_op_o : out std_ulogic_vector(01 downto 0); -- CPU bus access -- - cpu_debug_i : in std_ulogic; -- CPU is in debug mode - cpu_addr_i : in std_ulogic_vector(31 downto 0); -- address - cpu_rden_i : in std_ulogic; -- read enable - cpu_wren_i : in std_ulogic; -- write enable - cpu_ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - cpu_data_i : in std_ulogic_vector(31 downto 0); -- data in - cpu_data_o : out std_ulogic_vector(31 downto 0); -- data out - cpu_ack_o : out std_ulogic; -- transfer acknowledge + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response -- CPU control -- cpu_ndmrstn_o : out std_ulogic; -- soc reset cpu_halt_req_o : out std_ulogic -- request hart to halt (enter debug mode) @@ -685,10 +680,10 @@ begin -- Access Control ------------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (cpu_addr_i(hi_abb_c downto lo_abb_c) = dm_base_c(hi_abb_c downto lo_abb_c)) else '0'; - maddr <= cpu_addr_i(lo_abb_c-1 downto lo_abb_c-2); -- (sub-)module select address - rden <= acc_en and cpu_debug_i and cpu_rden_i; -- allow access only when in debug mode - wren <= acc_en and cpu_debug_i and cpu_wren_i; -- allow access only when in debug mode + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = dm_base_c(hi_abb_c downto lo_abb_c)) else '0'; + maddr <= bus_req_i.addr(lo_abb_c-1 downto lo_abb_c-2); -- (sub-)module select address + rden <= acc_en and cpu_debug_i and bus_req_i.re; -- allow access only when in debug mode + wren <= acc_en and cpu_debug_i and bus_req_i.we; -- allow access only when in debug mode -- Write Access --------------------------------------------------------------------------- @@ -706,7 +701,7 @@ begin if (dci.data_we = '1') then -- DM write access data_buf <= dci.wdata; elsif (maddr = "10") and (wren = '1') then -- CPU write access - data_buf <= cpu_data_i; + data_buf <= bus_req_i.data; end if; -- control and status register CPU write access -- -- NOTE: we only check the individual BYTE ACCESSES - not the actual write data -- @@ -715,16 +710,16 @@ begin dci.execute_ack <= '0'; dci.exception_ack <= '0'; if (maddr = "11") and (wren = '1') then - if (cpu_ben_i(sreg_halt_ack_c/8) = '1') then + if (bus_req_i.ben(sreg_halt_ack_c/8) = '1') then dci.halt_ack <= '1'; end if; - if (cpu_ben_i(sreg_resume_ack_c/8) = '1') then + if (bus_req_i.ben(sreg_resume_ack_c/8) = '1') then dci.resume_ack <= '1'; end if; - if (cpu_ben_i(sreg_execute_ack_c/8) = '1') then + if (bus_req_i.ben(sreg_execute_ack_c/8) = '1') then dci.execute_ack <= '1'; end if; - if (cpu_ben_i(sreg_exception_ack_c/8) = '1') then + if (bus_req_i.ben(sreg_exception_ack_c/8) = '1') then dci.exception_ack <= '1'; end if; end if; @@ -740,23 +735,26 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - cpu_ack_o <= rden or wren; - cpu_data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; + bus_rsp_o.data <= (others => '0'); if (rden = '1') then -- output enable case maddr is -- module select when "00" => -- code ROM - cpu_data_o <= code_rom_file(to_integer(unsigned(cpu_addr_i(5 downto 2)))); + bus_rsp_o.data <= code_rom_file(to_integer(unsigned(bus_req_i.addr(5 downto 2)))); when "01" => -- program buffer - cpu_data_o <= cpu_progbuf(to_integer(unsigned(cpu_addr_i(3 downto 2)))); + bus_rsp_o.data <= cpu_progbuf(to_integer(unsigned(bus_req_i.addr(3 downto 2)))); when "10" => -- data buffer - cpu_data_o <= data_buf; + bus_rsp_o.data <= data_buf; when others => -- control and status register - cpu_data_o(sreg_resume_req_c) <= dci.resume_req; - cpu_data_o(sreg_execute_req_c) <= dci.execute_req; + bus_rsp_o.data(sreg_resume_req_c) <= dci.resume_req; + bus_rsp_o.data(sreg_execute_req_c) <= dci.execute_req; end case; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + end neorv32_debug_dm_rtl; diff --git a/rtl/core/neorv32_dma.vhd b/rtl/core/neorv32_dma.vhd index 16f604ad6..18c6bf503 100644 --- a/rtl/core/neorv32_dma.vhd +++ b/rtl/core/neorv32_dma.vhd @@ -44,30 +44,13 @@ use neorv32.neorv32_package.all; entity neorv32_dma is port ( - -- global control -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - -- peripheral port: configuration and status -- - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- host port: bus access -- - bus_bus_priv_o : out std_ulogic; -- current privilege level - bus_cached_o : out std_ulogic; -- set if cached (!) access in progress - bus_src_o : out std_ulogic; -- access source - bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - bus_we_o : out std_ulogic; -- write enable - bus_re_o : out std_ulogic; -- read enable - bus_ack_i : in std_ulogic; -- bus transfer acknowledge - bus_err_i : in std_ulogic; -- bus transfer error - -- interrupt -- - irq_o : out std_ulogic + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + dma_req_o : out bus_req_t; -- DMA request + dma_rsp_i : in bus_rsp_t; -- DMA response + irq_o : out std_ulogic -- transfer done interrupt ); end neorv32_dma; @@ -134,10 +117,9 @@ architecture neorv32_dma_rtl of neorv32_dma is end record; signal engine : engine_t; - -- data aligner -- + -- data alignment -- signal align_buf : std_ulogic_vector(31 downto 0); signal align_end : std_ulogic_vector(31 downto 0); - signal align_tmp : std_ulogic_vector(31 downto 0); begin @@ -145,9 +127,9 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = dma_base_c(hi_abb_c downto lo_abb_c)) else '0'; - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = dma_base_c(hi_abb_c downto lo_abb_c)) else '0'; + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -165,21 +147,21 @@ begin elsif rising_edge(clk_i) then config.start <= '0'; -- default if (wren = '1') then - if (addr_i(3 downto 2) = "00") then -- control and status register - config.enable <= data_i(ctrl_en_c); + if (bus_req_i.addr(3 downto 2) = "00") then -- control and status register + config.enable <= bus_req_i.data(ctrl_en_c); end if; - if (addr_i(3 downto 2) = "01") then -- source base address - config.src_base <= data_i; + if (bus_req_i.addr(3 downto 2) = "01") then -- source base address + config.src_base <= bus_req_i.data; end if; - if (addr_i(3 downto 2) = "10") then -- destination base address - config.dst_base <= data_i; + if (bus_req_i.addr(3 downto 2) = "10") then -- destination base address + config.dst_base <= bus_req_i.data; end if; - if (addr_i(3 downto 2) = "11") then -- transfer type register - config.num <= data_i(type_num_hi_c downto type_num_lo_c); - config.qsel <= data_i(type_qsel_hi_c downto type_qsel_lo_c); - config.src_inc <= data_i(type_src_inc_c); - config.dst_inc <= data_i(type_dst_inc_c); - config.endian <= data_i(type_endian_c); + if (bus_req_i.addr(3 downto 2) = "11") then -- transfer type register + config.num <= bus_req_i.data(type_num_hi_c downto type_num_lo_c); + config.qsel <= bus_req_i.data(type_qsel_hi_c downto type_qsel_lo_c); + config.src_inc <= bus_req_i.data(type_src_inc_c); + config.dst_inc <= bus_req_i.data(type_dst_inc_c); + config.endian <= bus_req_i.data(type_endian_c); config.start <= '1'; -- trigger DMA operation end if; end if; @@ -190,30 +172,33 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus access acknowledge - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; -- bus access acknowledge + bus_rsp_o.data <= (others => '0'); if (rden = '1') then - case addr_i(3 downto 2) is + case bus_req_i.addr(3 downto 2) is when "00" => -- control and status register - data_o(ctrl_en_c) <= config.enable; - data_o(ctrl_error_rd_c) <= engine.err_rd; - data_o(ctrl_error_wr_c) <= engine.err_wr; - data_o(ctrl_busy_c) <= engine.busy; + bus_rsp_o.data(ctrl_en_c) <= config.enable; + bus_rsp_o.data(ctrl_error_rd_c) <= engine.err_rd; + bus_rsp_o.data(ctrl_error_wr_c) <= engine.err_wr; + bus_rsp_o.data(ctrl_busy_c) <= engine.busy; when "01" => -- address of last read access - data_o <= engine.src_addr; + bus_rsp_o.data <= engine.src_addr; when "10" => -- address of last write access - data_o <= engine.dst_addr; + bus_rsp_o.data <= engine.dst_addr; when others => -- transfer type register - data_o(type_num_hi_c downto type_num_lo_c) <= engine.num; - data_o(type_qsel_hi_c downto type_qsel_lo_c) <= config.qsel; - data_o(type_src_inc_c) <= config.src_inc; - data_o(type_dst_inc_c) <= config.dst_inc; - data_o(type_endian_c) <= config.endian; + bus_rsp_o.data(type_num_hi_c downto type_num_lo_c) <= engine.num; + bus_rsp_o.data(type_qsel_hi_c downto type_qsel_lo_c) <= config.qsel; + bus_rsp_o.data(type_src_inc_c) <= config.src_inc; + bus_rsp_o.data(type_dst_inc_c) <= config.dst_inc; + bus_rsp_o.data(type_endian_c) <= config.endian; end case; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- Bus Access Engine ---------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -227,13 +212,13 @@ begin engine.err_rd <= '0'; engine.err_wr <= '0'; engine.done <= '0'; - bus_re_o <= '0'; - bus_we_o <= '0'; + dma_req_o.re <= '0'; + dma_req_o.we <= '0'; elsif rising_edge(clk_i) then -- defaults -- - engine.done <= '0'; - bus_re_o <= '0'; - bus_we_o <= '0'; + engine.done <= '0'; + dma_req_o.re <= '0'; + dma_req_o.we <= '0'; -- state machine -- case engine.state is @@ -246,28 +231,28 @@ begin if (config.enable = '1') and (config.start = '1') then engine.err_rd <= '0'; engine.err_wr <= '0'; - bus_re_o <= '1'; -- issue read request + dma_req_o.re <= '1'; -- issue read request engine.state <= S_READ; end if; when S_READ => -- pending read access -- ------------------------------------------------------------ - if (bus_err_i = '1') then + if (dma_rsp_i.err = '1') then engine.done <= '1'; engine.err_rd <= '1'; engine.state <= S_IDLE; - elsif (bus_ack_i = '1') then - bus_we_o <= '1'; + elsif (dma_rsp_i.ack = '1') then + dma_req_o.we <= '1'; engine.state <= S_WRITE; end if; when S_WRITE => -- pending write access -- ------------------------------------------------------------ - if (bus_err_i = '1') then + if (dma_rsp_i.err = '1') then engine.done <= '1'; engine.err_wr <= '1'; engine.state <= S_IDLE; - elsif (bus_ack_i = '1') then + elsif (dma_rsp_i.ack = '1') then engine.num <= std_ulogic_vector(unsigned(engine.num) - 1); engine.state <= S_NEXT; end if; @@ -284,7 +269,7 @@ begin if (config.dst_inc = '1') then -- incrementing destination address engine.dst_addr <= std_ulogic_vector(unsigned(engine.dst_addr) + engine.dst_add); end if; - bus_re_o <= '1'; -- issue read request + dma_req_o.re <= '1'; -- issue read request engine.state <= S_READ; end if; @@ -303,10 +288,9 @@ begin irq_o <= engine.done and config.enable; -- bus output -- - bus_bus_priv_o <= priv_mode_m_c; - bus_cached_o <= '0'; - bus_src_o <= '0'; -- data access - bus_addr_o <= engine.src_addr when (engine.state = S_READ) else engine.dst_addr; + dma_req_o.priv <= priv_mode_m_c; + dma_req_o.src <= '0'; -- source = data access + dma_req_o.addr <= engine.src_addr when (engine.state = S_READ) else engine.dst_addr; -- address increment -- address_inc: process(config.qsel) @@ -323,7 +307,7 @@ begin -- ------------------------------------------------------------------------------------------- -- endianness conversion -- - align_end <= bus_rdata_i when (config.endian = '0') else bswap32_f(bus_rdata_i); + align_end <= dma_rsp_i.data when (config.endian = '0') else bswap32_f(dma_rsp_i.data); -- source data alignment -- src_align: process(rstn_i, clk_i) @@ -357,16 +341,16 @@ begin -- destination data alignment -- dst_align: process(config.qsel, align_buf, engine.dst_addr) begin - bus_ben_o <= (others => '0'); -- default + dma_req_o.ben <= (others => '0'); -- default if (config.qsel = qsel_b2b_c) then -- byte - bus_wdata_o(07 downto 00) <= align_buf(7 downto 0); - bus_wdata_o(15 downto 08) <= align_buf(7 downto 0); - bus_wdata_o(23 downto 16) <= align_buf(7 downto 0); - bus_wdata_o(31 downto 24) <= align_buf(7 downto 0); - bus_ben_o(to_integer(unsigned(engine.dst_addr(1 downto 0)))) <= '1'; + dma_req_o.data(07 downto 00) <= align_buf(7 downto 0); + dma_req_o.data(15 downto 08) <= align_buf(7 downto 0); + dma_req_o.data(23 downto 16) <= align_buf(7 downto 0); + dma_req_o.data(31 downto 24) <= align_buf(7 downto 0); + dma_req_o.ben(to_integer(unsigned(engine.dst_addr(1 downto 0)))) <= '1'; else -- word - bus_wdata_o <= align_buf; - bus_ben_o <= "1111"; + dma_req_o.data <= align_buf; + dma_req_o.ben <= "1111"; end if; end process dst_align; diff --git a/rtl/core/neorv32_gpio.vhd b/rtl/core/neorv32_gpio.vhd index 79c932d04..6269857cd 100644 --- a/rtl/core/neorv32_gpio.vhd +++ b/rtl/core/neorv32_gpio.vhd @@ -44,18 +44,12 @@ entity neorv32_gpio is GPIO_NUM : natural -- number of GPIO input/output pairs (0..64) ); port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- parallel io -- - gpio_o : out std_ulogic_vector(63 downto 0); - gpio_i : in std_ulogic_vector(63 downto 0) + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + gpio_o : out std_ulogic_vector(63 downto 0); -- parallel output + gpio_i : in std_ulogic_vector(63 downto 0) -- parallel input ); end neorv32_gpio; @@ -86,10 +80,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = gpio_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= gpio_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = gpio_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= gpio_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -99,10 +93,10 @@ begin elsif rising_edge(clk_i) then if (wren = '1') then if (addr = gpio_out_lo_addr_c) then - dout(31 downto 00) <= data_i; + dout(31 downto 00) <= bus_req_i.data; end if; if (addr = gpio_out_hi_addr_c) then - dout(63 downto 32) <= data_i; + dout(63 downto 32) <= bus_req_i.data; end if; end if; end if; @@ -113,20 +107,23 @@ begin begin if rising_edge(clk_i) then -- bus handshake -- - ack_o <= wren or rden; + bus_rsp_o.ack <= wren or rden; -- read data -- - data_o <= (others => '0'); + bus_rsp_o.data <= (others => '0'); if (rden = '1') then case addr(3 downto 2) is - when "00" => data_o <= din_rd(31 downto 00); - when "01" => data_o <= din_rd(63 downto 32); - when "10" => data_o <= dout_rd(31 downto 00); - when others => data_o <= dout_rd(63 downto 32); + when "00" => bus_rsp_o.data <= din_rd(31 downto 00); + when "01" => bus_rsp_o.data <= din_rd(63 downto 32); + when "10" => bus_rsp_o.data <= dout_rd(31 downto 00); + when others => bus_rsp_o.data <= dout_rd(63 downto 32); end case; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- Physical Pin Mapping ------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_gptmr.vhd b/rtl/core/neorv32_gptmr.vhd index 68f66bd6a..deee5a66b 100644 --- a/rtl/core/neorv32_gptmr.vhd +++ b/rtl/core/neorv32_gptmr.vhd @@ -46,19 +46,12 @@ use neorv32.neorv32_package.all; entity neorv32_gptmr is port ( - -- host access -- clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + rstn_i : in std_ulogic; -- global reset line, low-active + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- interrupt -- + clkgen_i : in std_ulogic_vector(7 downto 0); irq_o : out std_ulogic -- timer match interrupt ); end neorv32_gptmr; @@ -100,10 +93,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = gptmr_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= gptmr_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = gptmr_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= gptmr_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -116,14 +109,14 @@ begin timer.cnt_we <= '0'; -- default if (wren = '1') then if (addr = gptmr_ctrl_addr_c) then -- control register - ctrl(ctrl_en_c) <= data_i(ctrl_en_c); - ctrl(ctrl_prsc0_c) <= data_i(ctrl_prsc0_c); - ctrl(ctrl_prsc1_c) <= data_i(ctrl_prsc1_c); - ctrl(ctrl_prsc2_c) <= data_i(ctrl_prsc2_c); - ctrl(ctrl_mode_c) <= data_i(ctrl_mode_c); + ctrl(ctrl_en_c) <= bus_req_i.data(ctrl_en_c); + ctrl(ctrl_prsc0_c) <= bus_req_i.data(ctrl_prsc0_c); + ctrl(ctrl_prsc1_c) <= bus_req_i.data(ctrl_prsc1_c); + ctrl(ctrl_prsc2_c) <= bus_req_i.data(ctrl_prsc2_c); + ctrl(ctrl_mode_c) <= bus_req_i.data(ctrl_mode_c); end if; if (addr = gptmr_thres_addr_c) then -- threshold register - timer.thres <= data_i; + timer.thres <= bus_req_i.data; end if; if (addr = gptmr_count_addr_c) then -- counter register timer.cnt_we <= '1'; @@ -136,25 +129,28 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus access acknowledge - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; -- bus access acknowledge + bus_rsp_o.data <= (others => '0'); if (rden = '1') then case addr(3 downto 2) is when "00" => -- control register - data_o(ctrl_en_c) <= ctrl(ctrl_en_c); - data_o(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c); - data_o(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c); - data_o(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c); - data_o(ctrl_mode_c) <= ctrl(ctrl_mode_c); + bus_rsp_o.data(ctrl_en_c) <= ctrl(ctrl_en_c); + bus_rsp_o.data(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c); + bus_rsp_o.data(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c); + bus_rsp_o.data(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c); + bus_rsp_o.data(ctrl_mode_c) <= ctrl(ctrl_mode_c); when "01" => -- threshold register - data_o <= timer.thres; + bus_rsp_o.data <= timer.thres; when others => -- counter register - data_o <= timer.count; + bus_rsp_o.data <= timer.count; end case; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- Timer Core ----------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -164,7 +160,7 @@ begin timer.count <= (others => '0'); elsif rising_edge(clk_i) then if (timer.cnt_we = '1') then -- write access - timer.count <= data_i; -- data_i will stay unchanged for min. 1 cycle after WREN has returned to low again + timer.count <= bus_req_i.data; -- data_i will stay unchanged for min. 1 cycle after WREN has returned to low again elsif (ctrl(ctrl_en_c) = '1') and (timer.tick = '1') then -- enabled and clock tick if (timer.match = '1') then if (ctrl(ctrl_mode_c) = '1') then -- reset counter if continuous mode diff --git a/rtl/core/neorv32_mtime.vhd b/rtl/core/neorv32_mtime.vhd index 767af53a9..76084caf1 100644 --- a/rtl/core/neorv32_mtime.vhd +++ b/rtl/core/neorv32_mtime.vhd @@ -44,17 +44,11 @@ use neorv32.neorv32_package.all; entity neorv32_mtime is port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- interrupt -- - irq_o : out std_ulogic -- interrupt request + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + irq_o : out std_ulogic -- interrupt request ); end neorv32_mtime; @@ -92,10 +86,10 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = mtime_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= mtime_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = mtime_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= mtime_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- Write Access --------------------------------------------------------------------------- @@ -114,10 +108,10 @@ begin -- mtimecmp -- if (wren = '1') then if (addr = mtime_cmp_lo_addr_c) then - mtimecmp_lo <= data_i; + mtimecmp_lo <= bus_req_i.data; end if; if (addr = mtime_cmp_hi_addr_c) then - mtimecmp_hi <= data_i; + mtimecmp_hi <= bus_req_i.data; end if; end if; @@ -134,7 +128,7 @@ begin -- mtime low -- if (mtime_lo_we = '1') then -- write access - mtime_lo <= data_i; + mtime_lo <= bus_req_i.data; else -- auto increment mtime_lo <= mtime_lo_nxt(31 downto 0); end if; @@ -142,7 +136,7 @@ begin -- mtime high -- if (mtime_hi_we = '1') then -- write access - mtime_hi <= data_i; + mtime_hi <= bus_req_i.data; else -- auto increment (if mtime.low overflows) mtime_hi <= std_ulogic_vector(unsigned(mtime_hi) + unsigned(mtime_lo_ovfl)); end if; @@ -158,19 +152,22 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus handshake - data_o <= (others => '0'); -- default + bus_rsp_o.ack <= rden or wren; -- bus handshake + bus_rsp_o.data <= (others => '0'); -- default if (rden = '1') then case addr(3 downto 2) is - when "00" => data_o <= mtime_lo; - when "01" => data_o <= mtime_hi; - when "10" => data_o <= mtimecmp_lo; - when others => data_o <= mtimecmp_hi; + when "00" => bus_rsp_o.data <= mtime_lo; + when "01" => bus_rsp_o.data <= mtime_hi; + when "10" => bus_rsp_o.data <= mtimecmp_lo; + when others => bus_rsp_o.data <= mtimecmp_hi; end case; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- Comparator ----------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_neoled.vhd b/rtl/core/neorv32_neoled.vhd index 45b5d10a1..0c371134b 100644 --- a/rtl/core/neorv32_neoled.vhd +++ b/rtl/core/neorv32_neoled.vhd @@ -58,21 +58,13 @@ entity neorv32_neoled is FIFO_DEPTH : natural -- NEOLED FIFO depth, has to be a power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + rstn_i : in std_ulogic; -- global reset line, low-active + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- interrupt -- + clkgen_i : in std_ulogic_vector(7 downto 0); irq_o : out std_ulogic; -- interrupt request - -- NEOLED output -- neoled_o : out std_ulogic -- serial async data line ); end neorv32_neoled; @@ -184,10 +176,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = neoled_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= neoled_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = neoled_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= neoled_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -203,14 +195,14 @@ begin ctrl.t1_high <= (others => '0'); elsif rising_edge(clk_i) then if (wren = '1') and (addr = neoled_ctrl_addr_c) then - ctrl.enable <= data_i(ctrl_en_c); - ctrl.mode <= data_i(ctrl_mode_c); - ctrl.strobe <= data_i(ctrl_strobe_c); - ctrl.clk_prsc <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c); - ctrl.irq_conf <= data_i(ctrl_irq_conf_c); - ctrl.t_total <= data_i(ctrl_t_tot_4_c downto ctrl_t_tot_0_c); - ctrl.t0_high <= data_i(ctrl_t_0h_4_c downto ctrl_t_0h_0_c); - ctrl.t1_high <= data_i(ctrl_t_1h_4_c downto ctrl_t_1h_0_c); + ctrl.enable <= bus_req_i.data(ctrl_en_c); + ctrl.mode <= bus_req_i.data(ctrl_mode_c); + ctrl.strobe <= bus_req_i.data(ctrl_strobe_c); + ctrl.clk_prsc <= bus_req_i.data(ctrl_clksel2_c downto ctrl_clksel0_c); + ctrl.irq_conf <= bus_req_i.data(ctrl_irq_conf_c); + ctrl.t_total <= bus_req_i.data(ctrl_t_tot_4_c downto ctrl_t_tot_0_c); + ctrl.t0_high <= bus_req_i.data(ctrl_t_0h_4_c downto ctrl_t_0h_0_c); + ctrl.t1_high <= bus_req_i.data(ctrl_t_1h_4_c downto ctrl_t_1h_0_c); end if; end if; end process write_access; @@ -219,27 +211,30 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= wren or rden; -- access acknowledge - data_o <= (others => '0'); + bus_rsp_o.ack <= wren or rden; -- access acknowledge + bus_rsp_o.data <= (others => '0'); if (rden = '1') then -- and (addr = neoled_ctrl_addr_c) then - data_o(ctrl_en_c) <= ctrl.enable; - data_o(ctrl_mode_c) <= ctrl.mode; - data_o(ctrl_strobe_c) <= ctrl.strobe; - data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc; - data_o(ctrl_irq_conf_c) <= ctrl.irq_conf or bool_to_ulogic_f(boolean(FIFO_DEPTH = 1)); -- tie to one if FIFO_DEPTH is 1 - data_o(ctrl_bufs_3_c downto ctrl_bufs_0_c) <= std_ulogic_vector(to_unsigned(index_size_f(FIFO_DEPTH), 4)); - data_o(ctrl_t_tot_4_c downto ctrl_t_tot_0_c) <= ctrl.t_total; - data_o(ctrl_t_0h_4_c downto ctrl_t_0h_0_c) <= ctrl.t0_high; - data_o(ctrl_t_1h_4_c downto ctrl_t_1h_0_c) <= ctrl.t1_high; + bus_rsp_o.data(ctrl_en_c) <= ctrl.enable; + bus_rsp_o.data(ctrl_mode_c) <= ctrl.mode; + bus_rsp_o.data(ctrl_strobe_c) <= ctrl.strobe; + bus_rsp_o.data(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc; + bus_rsp_o.data(ctrl_irq_conf_c) <= ctrl.irq_conf or bool_to_ulogic_f(boolean(FIFO_DEPTH = 1)); -- tie to one if FIFO_DEPTH is 1 + bus_rsp_o.data(ctrl_bufs_3_c downto ctrl_bufs_0_c) <= std_ulogic_vector(to_unsigned(index_size_f(FIFO_DEPTH), 4)); + bus_rsp_o.data(ctrl_t_tot_4_c downto ctrl_t_tot_0_c) <= ctrl.t_total; + bus_rsp_o.data(ctrl_t_0h_4_c downto ctrl_t_0h_0_c) <= ctrl.t0_high; + bus_rsp_o.data(ctrl_t_1h_4_c downto ctrl_t_1h_0_c) <= ctrl.t1_high; -- - data_o(ctrl_tx_empty_c) <= not tx_fifo.avail; - data_o(ctrl_tx_half_c) <= tx_fifo.half; - data_o(ctrl_tx_full_c) <= not tx_fifo.free; - data_o(ctrl_tx_busy_c) <= serial.busy; + bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail; + bus_rsp_o.data(ctrl_tx_half_c) <= tx_fifo.half; + bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free; + bus_rsp_o.data(ctrl_tx_busy_c) <= serial.busy; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- enable external clock generator -- clkgen_en_o <= ctrl.enable; @@ -271,7 +266,7 @@ begin tx_fifo.re <= '1' when (serial.state = "100") else '0'; tx_fifo.we <= '1' when (wren = '1') and (addr = neoled_data_addr_c) else '0'; - tx_fifo.wdata <= ctrl.strobe & ctrl.mode & data_i; + tx_fifo.wdata <= ctrl.strobe & ctrl.mode & bus_req_i.data; tx_fifo.clear <= not ctrl.enable; -- IRQ generator -- diff --git a/rtl/core/neorv32_onewire.vhd b/rtl/core/neorv32_onewire.vhd index f8a0b2d36..1a9ec37db 100644 --- a/rtl/core/neorv32_onewire.vhd +++ b/rtl/core/neorv32_onewire.vhd @@ -50,22 +50,14 @@ use neorv32.neorv32_package.all; entity neorv32_onewire is port ( - -- host access -- clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + rstn_i : in std_ulogic; -- global reset line, low-active + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines (require external tri-state drivers) -- + clkgen_i : in std_ulogic_vector(7 downto 0); onewire_i : in std_ulogic; -- 1-wire line state onewire_o : out std_ulogic; -- 1-wire line pull-down - -- interrupt -- irq_o : out std_ulogic -- transfer done IRQ ); end neorv32_onewire; @@ -155,10 +147,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = onewire_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= onewire_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = onewire_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= onewire_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -176,21 +168,21 @@ begin if (wren = '1') then -- control register -- if (addr = onewire_ctrl_addr_c) then - ctrl.enable <= data_i(ctrl_en_c); - ctrl.clk_prsc <= data_i(ctrl_prsc1_c downto ctrl_prsc0_c); - ctrl.clk_div <= data_i(ctrl_clkdiv7_c downto ctrl_clkdiv0_c); + ctrl.enable <= bus_req_i.data(ctrl_en_c); + ctrl.clk_prsc <= bus_req_i.data(ctrl_prsc1_c downto ctrl_prsc0_c); + ctrl.clk_div <= bus_req_i.data(ctrl_clkdiv7_c downto ctrl_clkdiv0_c); end if; -- data register -- if (addr = onewire_data_addr_c) then - tx_data <= data_i(7 downto 0); + tx_data <= bus_req_i.data(7 downto 0); end if; end if; -- operation triggers -- if (wren = '1') and (addr = onewire_ctrl_addr_c) then -- set by host - ctrl.trig_rst <= data_i(ctrl_trig_rst_c); - ctrl.trig_bit <= data_i(ctrl_trig_bit_c); - ctrl.trig_byte <= data_i(ctrl_trig_byte_c); + ctrl.trig_rst <= bus_req_i.data(ctrl_trig_rst_c); + ctrl.trig_bit <= bus_req_i.data(ctrl_trig_bit_c); + ctrl.trig_byte <= bus_req_i.data(ctrl_trig_byte_c); elsif (ctrl.enable = '0') or (serial.state(1) = '1') then -- cleared when disabled or when in RTX/RESET state ctrl.trig_rst <= '0'; ctrl.trig_bit <= '0'; @@ -203,26 +195,29 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus handshake - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; -- bus handshake + bus_rsp_o.data <= (others => '0'); if (rden = '1') then -- control register -- if (addr = onewire_ctrl_addr_c) then - data_o(ctrl_en_c) <= ctrl.enable; - data_o(ctrl_prsc1_c downto ctrl_prsc0_c) <= ctrl.clk_prsc; - data_o(ctrl_clkdiv7_c downto ctrl_clkdiv0_c) <= ctrl.clk_div; + bus_rsp_o.data(ctrl_en_c) <= ctrl.enable; + bus_rsp_o.data(ctrl_prsc1_c downto ctrl_prsc0_c) <= ctrl.clk_prsc; + bus_rsp_o.data(ctrl_clkdiv7_c downto ctrl_clkdiv0_c) <= ctrl.clk_div; -- - data_o(ctrl_sense_c) <= serial.wire_in(1); - data_o(ctrl_presence_c) <= serial.presence; - data_o(ctrl_busy_c) <= serial.busy; + bus_rsp_o.data(ctrl_sense_c) <= serial.wire_in(1); + bus_rsp_o.data(ctrl_presence_c) <= serial.presence; + bus_rsp_o.data(ctrl_busy_c) <= serial.busy; -- data register -- else -- if (addr = onewire_data_addr_c) then - data_o(7 downto 0) <= serial.sreg; + bus_rsp_o.data(7 downto 0) <= serial.sreg; end if; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- Tick Generator ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_pwm.vhd b/rtl/core/neorv32_pwm.vhd index da37b9b5c..7719091fe 100644 --- a/rtl/core/neorv32_pwm.vhd +++ b/rtl/core/neorv32_pwm.vhd @@ -47,20 +47,13 @@ entity neorv32_pwm is NUM_CHANNELS : natural -- number of PWM channels (0..12) ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(07 downto 0); - -- pwm output channels -- - pwm_o : out std_ulogic_vector(11 downto 0) + pwm_o : out std_ulogic_vector(11 downto 0) -- PWM output ); end neorv32_pwm; @@ -108,10 +101,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = pwm_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= pwm_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - rden <= acc_en and rden_i; - wren <= acc_en and wren_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = pwm_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= pwm_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + rden <= acc_en and bus_req_i.re; + wren <= acc_en and bus_req_i.we; -- write access -- write_access: process(rstn_i, clk_i) @@ -124,29 +117,29 @@ begin if (wren = '1') then -- control register -- if (addr = pwm_ctrl_addr_c) then - enable <= data_i(ctrl_enable_c); - prsc <= data_i(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c); + enable <= bus_req_i.data(ctrl_enable_c); + prsc <= bus_req_i.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c); end if; -- duty cycle register 0 -- if (addr = pwm_dc0_addr_c) then - pwm_ch(00) <= data_i(07 downto 00); - pwm_ch(01) <= data_i(15 downto 08); - pwm_ch(02) <= data_i(23 downto 16); - pwm_ch(03) <= data_i(31 downto 24); + pwm_ch(00) <= bus_req_i.data(07 downto 00); + pwm_ch(01) <= bus_req_i.data(15 downto 08); + pwm_ch(02) <= bus_req_i.data(23 downto 16); + pwm_ch(03) <= bus_req_i.data(31 downto 24); end if; -- duty cycle register 1 -- if (addr = pwm_dc1_addr_c) then - pwm_ch(04) <= data_i(07 downto 00); - pwm_ch(05) <= data_i(15 downto 08); - pwm_ch(06) <= data_i(23 downto 16); - pwm_ch(07) <= data_i(31 downto 24); + pwm_ch(04) <= bus_req_i.data(07 downto 00); + pwm_ch(05) <= bus_req_i.data(15 downto 08); + pwm_ch(06) <= bus_req_i.data(23 downto 16); + pwm_ch(07) <= bus_req_i.data(31 downto 24); end if; -- duty cycle register 2 -- if (addr = pwm_dc2_addr_c) then - pwm_ch(08) <= data_i(07 downto 00); - pwm_ch(09) <= data_i(15 downto 08); - pwm_ch(10) <= data_i(23 downto 16); - pwm_ch(11) <= data_i(31 downto 24); + pwm_ch(08) <= bus_req_i.data(07 downto 00); + pwm_ch(09) <= bus_req_i.data(15 downto 08); + pwm_ch(10) <= bus_req_i.data(23 downto 16); + pwm_ch(11) <= bus_req_i.data(31 downto 24); end if; end if; end if; @@ -156,20 +149,23 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus handshake - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; -- bus handshake + bus_rsp_o.data <= (others => '0'); if (rden = '1') then case addr(3 downto 2) is - when "00" => data_o(ctrl_enable_c) <= enable; data_o(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c) <= prsc; - when "01" => data_o <= pwm_ch_rd(03) & pwm_ch_rd(02) & pwm_ch_rd(01) & pwm_ch_rd(00); - when "10" => data_o <= pwm_ch_rd(07) & pwm_ch_rd(06) & pwm_ch_rd(05) & pwm_ch_rd(04); - when "11" => data_o <= pwm_ch_rd(11) & pwm_ch_rd(10) & pwm_ch_rd(09) & pwm_ch_rd(08); - when others => data_o <= (others => '0'); + when "00" => bus_rsp_o.data(ctrl_enable_c) <= enable; bus_rsp_o.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c) <= prsc; + when "01" => bus_rsp_o.data <= pwm_ch_rd(03) & pwm_ch_rd(02) & pwm_ch_rd(01) & pwm_ch_rd(00); + when "10" => bus_rsp_o.data <= pwm_ch_rd(07) & pwm_ch_rd(06) & pwm_ch_rd(05) & pwm_ch_rd(04); + when "11" => bus_rsp_o.data <= pwm_ch_rd(11) & pwm_ch_rd(10) & pwm_ch_rd(09) & pwm_ch_rd(08); + when others => bus_rsp_o.data <= (others => '0'); end case; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- duty cycle read-back -- pwm_dc_rd_gen: process(pwm_ch) begin diff --git a/rtl/core/neorv32_sdi.vhd b/rtl/core/neorv32_sdi.vhd index ed0bfee95..9779ec04e 100644 --- a/rtl/core/neorv32_sdi.vhd +++ b/rtl/core/neorv32_sdi.vhd @@ -47,22 +47,15 @@ entity neorv32_sdi is RTX_FIFO : natural -- RTX fifo depth, has to be a power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- SDI receiver input -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response sdi_csn_i : in std_ulogic; -- low-active chip-select sdi_clk_i : in std_ulogic; -- serial clock sdi_dat_i : in std_ulogic; -- serial data input sdi_dat_o : out std_ulogic; -- serial data output - -- interrupts -- - irq_o : out std_ulogic + irq_o : out std_ulogic -- CPU interrupt ); end neorv32_sdi; @@ -159,10 +152,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = sdi_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= sdi_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = sdi_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= sdi_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -178,13 +171,13 @@ begin ctrl.clr_rx <= '0'; if (wren = '1') then if (addr = sdi_ctrl_addr_c) then -- control register - ctrl.enable <= data_i(ctrl_en_c); - ctrl.clr_rx <= data_i(ctrl_clr_rx_c); + ctrl.enable <= bus_req_i.data(ctrl_en_c); + ctrl.clr_rx <= bus_req_i.data(ctrl_clr_rx_c); -- - ctrl.irq_rx_avail <= data_i(ctrl_irq_rx_avail_c); - ctrl.irq_rx_half <= data_i(ctrl_irq_rx_half_c); - ctrl.irq_rx_full <= data_i(ctrl_irq_rx_full_c); - ctrl.irq_tx_empty <= data_i(ctrl_irq_tx_empty_c); + ctrl.irq_rx_avail <= bus_req_i.data(ctrl_irq_rx_avail_c); + ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c); + ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c); + ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c); end if; end if; end if; @@ -194,31 +187,34 @@ begin read_aceess: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus access acknowledge - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; -- bus access acknowledge + bus_rsp_o.data <= (others => '0'); if (rden = '1') then if (addr = sdi_ctrl_addr_c) then -- control register - data_o(ctrl_en_c) <= ctrl.enable; + bus_rsp_o.data(ctrl_en_c) <= ctrl.enable; -- - data_o(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(RTX_FIFO), 4)); + bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(RTX_FIFO), 4)); -- - data_o(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail; - data_o(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half; - data_o(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full; - data_o(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty; + bus_rsp_o.data(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail; + bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half; + bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full; + bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty; -- - data_o(ctrl_rx_avail_c) <= rx_fifo.avail; - data_o(ctrl_rx_half_c) <= rx_fifo.half; - data_o(ctrl_rx_full_c) <= not rx_fifo.free; - data_o(ctrl_tx_empty_c) <= not tx_fifo.avail; - data_o(ctrl_tx_full_c) <= not tx_fifo.free; + bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail; + bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half; + bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free; + bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail; + bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free; else -- data register - data_o(7 downto 0) <= rx_fifo.rdata; + bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata; end if; end if; end if; end process read_aceess; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- Data FIFO ("Ring Buffer") -------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -249,7 +245,7 @@ begin -- write access (CPU) -- tx_fifo.clear <= not ctrl.enable; - tx_fifo.wdata <= data_i(7 downto 0); + tx_fifo.wdata <= bus_req_i.data(7 downto 0); tx_fifo.we <= '1' when (wren = '1') and (addr = sdi_rtx_addr_c) else '0'; -- read access (SDI) -- diff --git a/rtl/core/neorv32_spi.vhd b/rtl/core/neorv32_spi.vhd index 725077833..8d86768b0 100644 --- a/rtl/core/neorv32_spi.vhd +++ b/rtl/core/neorv32_spi.vhd @@ -44,24 +44,16 @@ entity neorv32_spi is IO_SPI_FIFO : natural -- SPI RTX fifo depth, has to be a power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines -- spi_clk_o : out std_ulogic; -- SPI serial clock spi_dat_o : out std_ulogic; -- controller data out, peripheral data in spi_dat_i : in std_ulogic; -- controller data in, peripheral data out spi_csn_o : out std_ulogic_vector(07 downto 0); -- SPI CS - -- interrupt -- irq_o : out std_ulogic -- transmission done interrupt ); end neorv32_spi; @@ -165,10 +157,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = spi_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= spi_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = spi_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= spi_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -187,16 +179,16 @@ begin elsif rising_edge(clk_i) then if (wren = '1') then if (addr = spi_ctrl_addr_c) then -- control register - ctrl.enable <= data_i(ctrl_en_c); - ctrl.cpha <= data_i(ctrl_cpha_c); - ctrl.cpol <= data_i(ctrl_cpol_c); - ctrl.cs_sel <= data_i(ctrl_cs_sel2_c downto ctrl_cs_sel0_c); - ctrl.cs_en <= data_i(ctrl_cs_en_c); - ctrl.prsc <= data_i(ctrl_prsc2_c downto ctrl_prsc0_c); - ctrl.cdiv <= data_i(ctrl_cdiv3_c downto ctrl_cdiv0_c); - ctrl.irq_rx_avail <= data_i(ctrl_irq_rx_avail_c); - ctrl.irq_tx_empty <= data_i(ctrl_irq_tx_empty_c); - ctrl.irq_tx_nhalf <= data_i(ctrl_irq_tx_nhalf_c); + ctrl.enable <= bus_req_i.data(ctrl_en_c); + ctrl.cpha <= bus_req_i.data(ctrl_cpha_c); + ctrl.cpol <= bus_req_i.data(ctrl_cpol_c); + ctrl.cs_sel <= bus_req_i.data(ctrl_cs_sel2_c downto ctrl_cs_sel0_c); + ctrl.cs_en <= bus_req_i.data(ctrl_cs_en_c); + ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c); + ctrl.cdiv <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c); + ctrl.irq_rx_avail <= bus_req_i.data(ctrl_irq_rx_avail_c); + ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c); + ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c); end if; end if; end if; @@ -206,36 +198,39 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= wren or rden; -- bus access acknowledge - data_o <= (others => '0'); + bus_rsp_o.ack <= wren or rden; -- bus access acknowledge + bus_rsp_o.data <= (others => '0'); if (rden = '1') then if (addr = spi_ctrl_addr_c) then -- control register - data_o(ctrl_en_c) <= ctrl.enable; - data_o(ctrl_cpha_c) <= ctrl.cpha; - data_o(ctrl_cpol_c) <= ctrl.cpol; - data_o(ctrl_cs_sel2_c downto ctrl_cs_sel0_c) <= ctrl.cs_sel; - data_o(ctrl_cs_en_c) <= ctrl.cs_en; - data_o(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc; - data_o(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv; + bus_rsp_o.data(ctrl_en_c) <= ctrl.enable; + bus_rsp_o.data(ctrl_cpha_c) <= ctrl.cpha; + bus_rsp_o.data(ctrl_cpol_c) <= ctrl.cpol; + bus_rsp_o.data(ctrl_cs_sel2_c downto ctrl_cs_sel0_c) <= ctrl.cs_sel; + bus_rsp_o.data(ctrl_cs_en_c) <= ctrl.cs_en; + bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc; + bus_rsp_o.data(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv; -- - data_o(ctrl_rx_avail_c) <= rx_fifo.avail; - data_o(ctrl_tx_empty_c) <= not tx_fifo.avail; - data_o(ctrl_tx_nhalf_c) <= not tx_fifo.half; - data_o(ctrl_tx_full_c) <= not tx_fifo.free; - data_o(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail; - data_o(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty; - data_o(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf; + bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail; + bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail; + bus_rsp_o.data(ctrl_tx_nhalf_c) <= not tx_fifo.half; + bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free; + bus_rsp_o.data(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail; + bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty; + bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf; -- - data_o(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_SPI_FIFO), 4)); + bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_SPI_FIFO), 4)); -- - data_o(ctrl_busy_c) <= rtx_engine.busy or tx_fifo.avail; + bus_rsp_o.data(ctrl_busy_c) <= rtx_engine.busy or tx_fifo.avail; else -- data register (spi_rtx_addr_c) - data_o(7 downto 0) <= rx_fifo.rdata; + bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata; end if; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- direct chip-select (low-active) -- chip_select: process(ctrl) begin @@ -275,7 +270,7 @@ begin tx_fifo.clear <= not ctrl.enable; tx_fifo.we <= '1' when (wren = '1') and (addr = spi_rtx_addr_c) else '0'; - tx_fifo.wdata <= data_i(7 downto 0); + tx_fifo.wdata <= bus_req_i.data(7 downto 0); tx_fifo.re <= '1' when (rtx_engine.state = "100") else '0'; diff --git a/rtl/core/neorv32_sysinfo.vhd b/rtl/core/neorv32_sysinfo.vhd index 7cb3ea21f..873011abc 100644 --- a/rtl/core/neorv32_sysinfo.vhd +++ b/rtl/core/neorv32_sysinfo.vhd @@ -90,14 +90,9 @@ entity neorv32_sysinfo is IO_DMA_EN : boolean -- implement direct memory access controller (DMA)? ); port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic -- transfer error + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end neorv32_sysinfo; @@ -121,10 +116,10 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = sysinfo_base_c(hi_abb_c downto lo_abb_c)) else '0'; - rden <= acc_en and rden_i; -- read access - wren <= acc_en and wren_i; -- write access - addr <= addr_i(index_size_f(sysinfo_size_c)-1 downto 2); + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = sysinfo_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= bus_req_i.addr(index_size_f(sysinfo_size_c)-1 downto 2); + rden <= acc_en and bus_req_i.re; -- read access + wren <= acc_en and bus_req_i.we; -- write access -- Construct Info ROM --------------------------------------------------------------------- @@ -197,11 +192,11 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden; - err_o <= wren; -- read-only! - data_o <= (others => '0'); + bus_rsp_o.ack <= rden; + bus_rsp_o.err <= wren; -- read-only! + bus_rsp_o.data <= (others => '0'); if (rden = '1') then - data_o <= sysinfo(to_integer(unsigned(addr))); + bus_rsp_o.data <= sysinfo(to_integer(unsigned(addr))); end if; end if; end process read_access; diff --git a/rtl/core/neorv32_trng.vhd b/rtl/core/neorv32_trng.vhd index 1d5c76ac8..73700c479 100644 --- a/rtl/core/neorv32_trng.vhd +++ b/rtl/core/neorv32_trng.vhd @@ -48,15 +48,10 @@ entity neorv32_trng is IO_TRNG_FIFO : natural := 1 -- RND fifo depth, has to be a power of two, min 1 ); port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic -- transfer acknowledge + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end neorv32_trng; @@ -137,9 +132,9 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0'; - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0'; + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -150,8 +145,8 @@ begin elsif rising_edge(clk_i) then fifo_clr <= '0'; -- default if (wren = '1') then - enable <= data_i(ctrl_en_c); - fifo_clr <= data_i(ctrl_fifo_clr_c); + enable <= bus_req_i.data(ctrl_en_c); + fifo_clr <= bus_req_i.data(ctrl_fifo_clr_c); end if; end if; end process write_access; @@ -160,19 +155,22 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= wren or rden; -- host bus acknowledge - data_o <= (others => '0'); + bus_rsp_o.ack <= wren or rden; -- host bus acknowledge + bus_rsp_o.data <= (others => '0'); if (rden = '1') then if (fifo.avail = '1') then -- make sure data byte is zero if no valid data available to prevent it is read twice - data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata; + bus_rsp_o.data(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata; end if; - data_o(ctrl_sim_mode_c) <= bool_to_ulogic_f(sim_mode_c); - data_o(ctrl_en_c) <= enable; - data_o(ctrl_valid_c) <= fifo.avail; + bus_rsp_o.data(ctrl_sim_mode_c) <= bool_to_ulogic_f(sim_mode_c); + bus_rsp_o.data(ctrl_en_c) <= enable; + bus_rsp_o.data(ctrl_valid_c) <= fifo.avail; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- neoTRNG True Random Number Generator --------------------------------------------------- -- ------------------------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_twi.vhd b/rtl/core/neorv32_twi.vhd index befbe6e42..c9ec14abc 100644 --- a/rtl/core/neorv32_twi.vhd +++ b/rtl/core/neorv32_twi.vhd @@ -46,24 +46,16 @@ use neorv32.neorv32_package.all; entity neorv32_twi is port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines (require external tri-state drivers) -- twi_sda_i : in std_ulogic; -- serial data line input twi_sda_o : out std_ulogic; -- serial data line output twi_scl_i : in std_ulogic; -- serial clock line input twi_scl_o : out std_ulogic; -- serial clock line output - -- interrupt -- irq_o : out std_ulogic -- transfer done IRQ ); end neorv32_twi; @@ -147,10 +139,10 @@ begin -- Host Access ---------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = twi_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= twi_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = twi_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= twi_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -164,11 +156,11 @@ begin elsif rising_edge(clk_i) then if (wren = '1') then if (addr = twi_ctrl_addr_c) then - ctrl.enable <= data_i(ctrl_en_c); - ctrl.mack <= data_i(ctrl_mack_c); - ctrl.csen <= data_i(ctrl_csen_c); - ctrl.prsc <= data_i(ctrl_prsc2_c downto ctrl_prsc0_c); - ctrl.cdiv <= data_i(ctrl_cdiv3_c downto ctrl_cdiv0_c); + ctrl.enable <= bus_req_i.data(ctrl_en_c); + ctrl.mack <= bus_req_i.data(ctrl_mack_c); + ctrl.csen <= bus_req_i.data(ctrl_csen_c); + ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c); + ctrl.cdiv <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c); end if; end if; end if; @@ -178,26 +170,29 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus handshake - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; -- bus handshake + bus_rsp_o.data <= (others => '0'); if (rden = '1') then if (addr = twi_ctrl_addr_c) then - data_o(ctrl_en_c) <= ctrl.enable; - data_o(ctrl_mack_c) <= ctrl.mack; - data_o(ctrl_csen_c) <= ctrl.csen; - data_o(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc; - data_o(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv; + bus_rsp_o.data(ctrl_en_c) <= ctrl.enable; + bus_rsp_o.data(ctrl_mack_c) <= ctrl.mack; + bus_rsp_o.data(ctrl_csen_c) <= ctrl.csen; + bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc; + bus_rsp_o.data(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv; -- - data_o(ctrl_claimed_c) <= arbiter.claimed; - data_o(ctrl_ack_c) <= not arbiter.rtx_sreg(0); - data_o(ctrl_busy_c) <= arbiter.busy; + bus_rsp_o.data(ctrl_claimed_c) <= arbiter.claimed; + bus_rsp_o.data(ctrl_ack_c) <= not arbiter.rtx_sreg(0); + bus_rsp_o.data(ctrl_busy_c) <= arbiter.busy; else -- twi_rtx_addr_c => - data_o(7 downto 0) <= arbiter.rtx_sreg(8 downto 1); + bus_rsp_o.data(7 downto 0) <= arbiter.rtx_sreg(8 downto 1); end if; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- Clock Generation ----------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -275,15 +270,15 @@ begin arbiter.bitcnt <= (others => '0'); if (wren = '1') then if (addr = twi_ctrl_addr_c) then - if (data_i(ctrl_start_c) = '1') then -- issue START condition + if (bus_req_i.data(ctrl_start_c) = '1') then -- issue START condition arbiter.state_nxt <= "01"; - elsif (data_i(ctrl_stop_c) = '1') then -- issue STOP condition + elsif (bus_req_i.data(ctrl_stop_c) = '1') then -- issue STOP condition arbiter.state_nxt <= "10"; end if; elsif (addr = twi_rtx_addr_c) then -- start a data transmission -- one bit extra for ACK: issued by controller if ctrl_mack_c is set, -- sampled from peripheral if ctrl_mack_c is cleared - arbiter.rtx_sreg <= data_i(7 downto 0) & (not ctrl.mack); + arbiter.rtx_sreg <= bus_req_i.data(7 downto 0) & (not ctrl.mack); arbiter.state_nxt <= "11"; end if; end if; diff --git a/rtl/core/neorv32_uart.vhd b/rtl/core/neorv32_uart.vhd index 9da9b0cce..e6519ca57 100644 --- a/rtl/core/neorv32_uart.vhd +++ b/rtl/core/neorv32_uart.vhd @@ -72,27 +72,18 @@ entity neorv32_uart is UART_TX_FIFO : natural -- TX fifo depth, has to be a power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines -- - uart_txd_o : out std_ulogic; - uart_rxd_i : in std_ulogic; - -- hardware flow control -- + uart_txd_o : out std_ulogic; -- serial TX line + uart_rxd_i : in std_ulogic; -- serial RX line uart_rts_o : out std_ulogic; -- UART.RX ready to receive ("RTR"), low-active, optional uart_cts_i : in std_ulogic; -- UART.TX allowed to transmit, low-active, optional - -- interrupts -- - irq_rx_o : out std_ulogic; -- rx interrupt - irq_tx_o : out std_ulogic -- tx interrupt + irq_rx_o : out std_ulogic; -- RX interrupt + irq_tx_o : out std_ulogic -- TX interrupt ); end neorv32_uart; @@ -231,10 +222,10 @@ begin -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = uart_id_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= uart_id_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = uart_id_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= uart_id_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -253,17 +244,17 @@ begin elsif rising_edge(clk_i) then if (wren = '1') then if (addr = uart_id_ctrl_addr_c) then -- control register - ctrl.enable <= data_i(ctrl_en_c); - ctrl.sim_mode <= data_i(ctrl_sim_en_c); - ctrl.hwfc_en <= data_i(ctrl_hwfc_en_c); - ctrl.prsc <= data_i(ctrl_prsc2_c downto ctrl_prsc0_c); - ctrl.baud <= data_i(ctrl_baud9_c downto ctrl_baud0_c); + ctrl.enable <= bus_req_i.data(ctrl_en_c); + ctrl.sim_mode <= bus_req_i.data(ctrl_sim_en_c); + ctrl.hwfc_en <= bus_req_i.data(ctrl_hwfc_en_c); + ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c); + ctrl.baud <= bus_req_i.data(ctrl_baud9_c downto ctrl_baud0_c); -- - ctrl.irq_rx_nempty <= data_i(ctrl_irq_rx_nempty_c); - ctrl.irq_rx_half <= data_i(ctrl_irq_rx_half_c); - ctrl.irq_rx_full <= data_i(ctrl_irq_rx_full_c); - ctrl.irq_tx_empty <= data_i(ctrl_irq_tx_empty_c); - ctrl.irq_tx_nhalf <= data_i(ctrl_irq_tx_nhalf_c); + ctrl.irq_rx_nempty <= bus_req_i.data(ctrl_irq_rx_nempty_c); + ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c); + ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c); + ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c); + ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c); end if; end if; end if; @@ -273,40 +264,43 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= wren or rden; -- bus access acknowledge - data_o <= (others => '0'); + bus_rsp_o.ack <= wren or rden; -- bus access acknowledge + bus_rsp_o.data <= (others => '0'); if (rden = '1') then if (addr = uart_id_ctrl_addr_c) then -- control register - data_o(ctrl_en_c) <= ctrl.enable; - data_o(ctrl_sim_en_c) <= ctrl.sim_mode; - data_o(ctrl_hwfc_en_c) <= ctrl.hwfc_en; - data_o(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc; - data_o(ctrl_baud9_c downto ctrl_baud0_c) <= ctrl.baud; + bus_rsp_o.data(ctrl_en_c) <= ctrl.enable; + bus_rsp_o.data(ctrl_sim_en_c) <= ctrl.sim_mode; + bus_rsp_o.data(ctrl_hwfc_en_c) <= ctrl.hwfc_en; + bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc; + bus_rsp_o.data(ctrl_baud9_c downto ctrl_baud0_c) <= ctrl.baud; -- - data_o(ctrl_rx_nempty_c) <= rx_fifo.avail; - data_o(ctrl_rx_half_c) <= rx_fifo.half; - data_o(ctrl_rx_full_c) <= not rx_fifo.free; - data_o(ctrl_tx_empty_c) <= not tx_fifo.avail; - data_o(ctrl_tx_nhalf_c) <= not tx_fifo.half; - data_o(ctrl_tx_full_c) <= not tx_fifo.free; + bus_rsp_o.data(ctrl_rx_nempty_c) <= rx_fifo.avail; + bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half; + bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free; + bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail; + bus_rsp_o.data(ctrl_tx_nhalf_c) <= not tx_fifo.half; + bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free; -- - data_o(ctrl_irq_rx_nempty_c) <= ctrl.irq_rx_nempty; - data_o(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half; - data_o(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full; - data_o(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty; - data_o(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf; + bus_rsp_o.data(ctrl_irq_rx_nempty_c) <= ctrl.irq_rx_nempty; + bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half; + bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full; + bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty; + bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf; -- - data_o(ctrl_rx_over_c) <= rx_engine.over; - data_o(ctrl_tx_busy_c) <= tx_engine.busy or tx_fifo.avail; + bus_rsp_o.data(ctrl_rx_over_c) <= rx_engine.over; + bus_rsp_o.data(ctrl_tx_busy_c) <= tx_engine.busy or tx_fifo.avail; else -- data register - data_o(data_rtx_msb_c downto data_rtx_lsb_c) <= rx_fifo.rdata; - data_o(data_rx_fifo_size_msb downto data_rx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_RX_FIFO), 4)); - data_o(data_tx_fifo_size_msb downto data_tx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_TX_FIFO), 4)); + bus_rsp_o.data(data_rtx_msb_c downto data_rtx_lsb_c) <= rx_fifo.rdata; + bus_rsp_o.data(data_rx_fifo_size_msb downto data_rx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_RX_FIFO), 4)); + bus_rsp_o.data(data_tx_fifo_size_msb downto data_tx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_TX_FIFO), 4)); end if; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- UART clock enable -- clkgen_en_o <= ctrl.enable; uart_clk <= clkgen_i(to_integer(unsigned(ctrl.prsc))); @@ -340,7 +334,7 @@ begin ); tx_fifo.clear <= '1' when (ctrl.enable = '0') or (ctrl.sim_mode = '1') else '0'; - tx_fifo.wdata <= data_i(data_rtx_msb_c downto data_rtx_lsb_c); + tx_fifo.wdata <= bus_req_i.data(data_rtx_msb_c downto data_rtx_lsb_c); tx_fifo.we <= '1' when (wren = '1') and (addr = uart_id_rtx_addr_c) else '0'; tx_fifo.re <= '1' when (tx_engine.state = "100") else '0'; @@ -555,7 +549,7 @@ begin (wren = '1') and (addr = uart_id_rtx_addr_c) then -- print lowest byte as ASCII char -- - char_v := to_integer(unsigned(data_i(7 downto 0))); + char_v := to_integer(unsigned(bus_req_i.data(7 downto 0))); if (char_v >= 128) then -- out of range? char_v := 0; end if; @@ -580,7 +574,7 @@ begin -- dump raw data as 8 hex chars to file -- if (sim_data_output_en_c = true) then for x in 7 downto 0 loop - write(line_data_v, to_hexchar_f(data_i(3+x*4 downto 0+x*4))); -- write in hex form + write(line_data_v, to_hexchar_f(bus_req_i.data(3+x*4 downto 0+x*4))); -- write in hex form end loop; writeline(file_uart_data_out, line_data_v); end if; diff --git a/rtl/core/neorv32_wdt.vhd b/rtl/core/neorv32_wdt.vhd index 4cf35af10..c1357a3cf 100644 --- a/rtl/core/neorv32_wdt.vhd +++ b/rtl/core/neorv32_wdt.vhd @@ -49,23 +49,15 @@ use neorv32.neorv32_package.all; entity neorv32_wdt is port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_ext_i : in std_ulogic; -- external reset line, low-active, async rstn_int_i : in std_ulogic; -- internal reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- CPU status -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response cpu_debug_i : in std_ulogic; -- CPU is in debug mode cpu_sleep_i : in std_ulogic; -- CPU is in sleep mode - -- clock generator -- clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(07 downto 0); - -- timeout event -- irq_o : out std_ulogic; -- timeout IRQ rstn_o : out std_ulogic -- timeout reset, low_active, sync ); @@ -123,9 +115,9 @@ begin -- Host Access ---------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = wdt_base_c(hi_abb_c downto lo_abb_c)) else '0'; - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = wdt_base_c(hi_abb_c downto lo_abb_c)) else '0'; + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_int_i, clk_i) @@ -140,13 +132,13 @@ begin elsif rising_edge(clk_i) then ctrl.reset <= '0'; -- default if (wren = '1') then - ctrl.reset <= data_i(ctrl_reset_c); + ctrl.reset <= bus_req_i.data(ctrl_reset_c); if (ctrl.lock = '0') then -- update configuration only if not locked - ctrl.enable <= data_i(ctrl_enable_c); - ctrl.lock <= data_i(ctrl_lock_c) and ctrl.enable; -- lock only if already enabled - ctrl.dben <= data_i(ctrl_dben_c); - ctrl.sen <= data_i(ctrl_sen_c); - ctrl.timeout <= data_i(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c); + ctrl.enable <= bus_req_i.data(ctrl_enable_c); + ctrl.lock <= bus_req_i.data(ctrl_lock_c) and ctrl.enable; -- lock only if already enabled + ctrl.dben <= bus_req_i.data(ctrl_dben_c); + ctrl.sen <= bus_req_i.data(ctrl_sen_c); + ctrl.timeout <= bus_req_i.data(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c); end if; end if; end if; @@ -156,19 +148,22 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; + bus_rsp_o.data <= (others => '0'); if (rden = '1') then - data_o(ctrl_enable_c) <= ctrl.enable; - data_o(ctrl_lock_c) <= ctrl.lock; - data_o(ctrl_dben_c) <= ctrl.dben; - data_o(ctrl_sen_c) <= ctrl.sen; - data_o(ctrl_rcause_c) <= ctrl.rcause; - data_o(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c) <= ctrl.timeout; + bus_rsp_o.data(ctrl_enable_c) <= ctrl.enable; + bus_rsp_o.data(ctrl_lock_c) <= ctrl.lock; + bus_rsp_o.data(ctrl_dben_c) <= ctrl.dben; + bus_rsp_o.data(ctrl_sen_c) <= ctrl.sen; + bus_rsp_o.data(ctrl_rcause_c) <= ctrl.rcause; + bus_rsp_o.data(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c) <= ctrl.timeout; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- reset cause indicator -- reset_cause: process(rstn_ext_i, clk_i) begin diff --git a/rtl/core/neorv32_wishbone.vhd b/rtl/core/neorv32_wishbone.vhd index d3d3f3c3a..c9b27ff75 100644 --- a/rtl/core/neorv32_wishbone.vhd +++ b/rtl/core/neorv32_wishbone.vhd @@ -68,26 +68,15 @@ entity neorv32_wishbone is ASYNC_TX : boolean -- use register buffer for TX data when false ); port ( - -- global control -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - -- host access -- - src_i : in std_ulogic; -- access type (0: data, 1:instruction) - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic; -- transfer error + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response tmo_o : out std_ulogic; -- transfer timeout - priv_i : in std_ulogic; -- current CPU privilege level ext_o : out std_ulogic; -- active external access - -- xip configuration -- xip_en_i : in std_ulogic; -- XIP module enabled xip_page_i : in std_ulogic_vector(03 downto 0); -- XIP memory page - -- wishbone interface -- + -- wb_tag_o : out std_ulogic_vector(02 downto 0); -- request tag wb_adr_o : out std_ulogic_vector(31 downto 0); -- address wb_dat_i : in std_ulogic_vector(31 downto 0); -- read data @@ -163,12 +152,12 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- access to processor-internal IMEM or DMEM? -- - int_imem_acc <= '1' when (addr_i(31 downto index_size_f(MEM_INT_IMEM_SIZE)) = imem_base_c(31 downto index_size_f(MEM_INT_IMEM_SIZE))) and (MEM_INT_IMEM_EN = true) else '0'; - int_dmem_acc <= '1' when (addr_i(31 downto index_size_f(MEM_INT_DMEM_SIZE)) = dmem_base_c(31 downto index_size_f(MEM_INT_DMEM_SIZE))) and (MEM_INT_DMEM_EN = true) else '0'; + int_imem_acc <= '1' when (bus_req_i.addr(31 downto index_size_f(MEM_INT_IMEM_SIZE)) = imem_base_c(31 downto index_size_f(MEM_INT_IMEM_SIZE))) and (MEM_INT_IMEM_EN = true) else '0'; + int_dmem_acc <= '1' when (bus_req_i.addr(31 downto index_size_f(MEM_INT_DMEM_SIZE)) = dmem_base_c(31 downto index_size_f(MEM_INT_DMEM_SIZE))) and (MEM_INT_DMEM_EN = true) else '0'; -- access to processor-internal BOOTROM or IO devices? -- - int_boot_acc <= '1' when (addr_i(31 downto 16) = boot_rom_base_c(31 downto 16)) else '0'; -- hacky! + int_boot_acc <= '1' when (bus_req_i.addr(31 downto 16) = boot_rom_base_c(31 downto 16)) else '0'; -- hacky! -- XIP access? -- - xip_acc <= '1' when (xip_en_i = '1') and (addr_i(31 downto 28) = xip_page_i) else '0'; + xip_acc <= '1' when (xip_en_i = '1') and (bus_req_i.addr(31 downto 28) = xip_page_i) else '0'; -- actual external bus access? -- xbus_access <= (not int_imem_acc) and (not int_dmem_acc) and (not int_boot_acc) and (not xip_acc); @@ -203,12 +192,12 @@ begin -- state machine -- if (ctrl.state = '0') then -- IDLE, waiting for host request -- ------------------------------------------------------------ - if (xbus_access = '1') and ((wren_i or rden_i) = '1') then -- valid external request + if (xbus_access = '1') and ((bus_req_i.we or bus_req_i.re) = '1') then -- valid external request -- buffer (and gate) all outgoing signals -- - ctrl.we <= wren_i; - ctrl.adr <= addr_i; - ctrl.src <= src_i; - ctrl.priv <= priv_i; + ctrl.we <= bus_req_i.we; + ctrl.adr <= bus_req_i.addr; + ctrl.src <= bus_req_i.src; + ctrl.priv <= bus_req_i.priv; ctrl.wdat <= end_wdata; ctrl.sel <= end_byteen; ctrl.state <= '1'; @@ -239,8 +228,8 @@ begin ext_o <= ctrl.state; -- endianness conversion -- - end_wdata <= bswap32_f(data_i) when (BIG_ENDIAN = true) else data_i; - end_byteen <= bit_rev_f(ben_i) when (BIG_ENDIAN = true) else ben_i; + end_wdata <= bswap32_f(bus_req_i.data) when (BIG_ENDIAN = true) else bus_req_i.data; + end_byteen <= bit_rev_f(bus_req_i.ben) when (BIG_ENDIAN = true) else bus_req_i.ben; -- host access -- @@ -248,25 +237,25 @@ begin rdata_gated <= wb_dat_i when (ctrl.state = '1') else (others => '0'); -- CPU read data gate for "async" RX rdata <= ctrl.rdat when (ASYNC_RX = false) else rdata_gated; - data_o <= rdata when (BIG_ENDIAN = false) else bswap32_f(rdata); -- endianness conversion - ack_o <= ctrl.ack when (ASYNC_RX = false) else ack_gated; - err_o <= ctrl.err; - tmo_o <= ctrl.tmo; + bus_rsp_o.data <= rdata when (BIG_ENDIAN = false) else bswap32_f(rdata); -- endianness conversion + bus_rsp_o.ack <= ctrl.ack when (ASYNC_RX = false) else ack_gated; + bus_rsp_o.err <= ctrl.err; + tmo_o <= ctrl.tmo; -- wishbone interface -- - wb_tag_o(0) <= priv_i when (ASYNC_TX = true) else ctrl.priv; -- 0 = unprivileged (U-mode), 1 = privileged (M-mode) + wb_tag_o(0) <= bus_req_i.priv when (ASYNC_TX = true) else ctrl.priv; -- 0 = unprivileged (U-mode), 1 = privileged (M-mode) wb_tag_o(1) <= '0'; -- 0 = secure, 1 = non-secure - wb_tag_o(2) <= src_i when (ASYNC_TX = true) else ctrl.src; -- 0 = data access, 1 = instruction access + wb_tag_o(2) <= bus_req_i.src when (ASYNC_TX = true) else ctrl.src; -- 0 = data access, 1 = instruction access - stb_int <= (xbus_access and (wren_i or rden_i)) when (ASYNC_TX = true) else (ctrl.state and (not ctrl.state_ff)); - cyc_int <= ((xbus_access and (wren_i or rden_i)) or ctrl.state) when (ASYNC_TX = true) else ctrl.state; + stb_int <= (xbus_access and (bus_req_i.we or bus_req_i.re)) when (ASYNC_TX = true) else (ctrl.state and (not ctrl.state_ff)); + cyc_int <= ((xbus_access and (bus_req_i.we or bus_req_i.re)) or ctrl.state) when (ASYNC_TX = true) else ctrl.state; - wb_adr_o <= addr_i when (ASYNC_TX = true) else ctrl.adr; - wb_dat_o <= data_i when (ASYNC_TX = true) else ctrl.wdat; - wb_we_o <= (wren_i or (ctrl.we and ctrl.state)) when (ASYNC_TX = true) else ctrl.we; + wb_adr_o <= bus_req_i.addr when (ASYNC_TX = true) else ctrl.adr; + wb_dat_o <= bus_req_i.data when (ASYNC_TX = true) else ctrl.wdat; + wb_we_o <= (bus_req_i.we or (ctrl.we and ctrl.state)) when (ASYNC_TX = true) else ctrl.we; wb_sel_o <= end_byteen when (ASYNC_TX = true) else ctrl.sel; - wb_stb_o <= stb_int when (PIPE_MODE = true) else cyc_int; + wb_stb_o <= stb_int when (PIPE_MODE = true) else cyc_int; wb_cyc_o <= cyc_int; diff --git a/rtl/core/neorv32_xip.vhd b/rtl/core/neorv32_xip.vhd index 80164ec29..addf24c83 100644 --- a/rtl/core/neorv32_xip.vhd +++ b/rtl/core/neorv32_xip.vhd @@ -47,31 +47,17 @@ use neorv32.neorv32_package.all; entity neorv32_xip is port ( - -- global control -- clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - -- host access: control register access port -- - ct_addr_i : in std_ulogic_vector(31 downto 0); -- address - ct_rden_i : in std_ulogic; -- read enable - ct_wren_i : in std_ulogic; -- write enable - ct_data_i : in std_ulogic_vector(31 downto 0); -- data in - ct_data_o : out std_ulogic_vector(31 downto 0); -- data out - ct_ack_o : out std_ulogic; -- transfer acknowledge - -- host access: transparent SPI access port (read-only) -- - acc_addr_i : in std_ulogic_vector(31 downto 0); -- address - acc_rden_i : in std_ulogic; -- read enable - acc_wren_i : in std_ulogic; -- write enable - acc_data_o : out std_ulogic_vector(31 downto 0); -- data out - acc_ack_o : out std_ulogic; -- transfer acknowledge - acc_err_o : out std_ulogic; -- transfer error - -- status -- + rstn_i : in std_ulogic; -- global reset line, low-active + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + xip_req_i : in bus_req_t; -- XIP request + xip_rsp_o : out bus_rsp_t; -- XIP response xip_en_o : out std_ulogic; -- XIP enable xip_acc_o : out std_ulogic; -- pending XIP access - xip_page_o : out std_ulogic_vector(03 downto 0); -- XIP page - -- clock generator -- + xip_page_o : out std_ulogic_vector(3 downto 0); -- XIP page clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- SPI device interface -- + clkgen_i : in std_ulogic_vector(7 downto 0); spi_csn_o : out std_ulogic; -- chip-select, low-active spi_clk_o : out std_ulogic; -- serial clock spi_dat_i : in std_ulogic; -- device data output @@ -179,10 +165,10 @@ begin -- Access Control (IO/CTRL port) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - ct_acc_en <= '1' when (ct_addr_i(hi_abb_c downto lo_abb_c) = xip_base_c(hi_abb_c downto lo_abb_c)) else '0'; - ct_addr <= xip_base_c(31 downto lo_abb_c) & ct_addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - ct_wren <= ct_acc_en and ct_wren_i; - ct_rden <= ct_acc_en and ct_rden_i; + ct_acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = xip_base_c(hi_abb_c downto lo_abb_c)) else '0'; + ct_addr <= xip_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + ct_wren <= ct_acc_en and bus_req_i.we; + ct_rden <= ct_acc_en and bus_req_i.re; -- Control Write Access ------------------------------------------------------------------- @@ -199,26 +185,26 @@ begin if (ct_wren = '1') then -- only full-word writes! -- control register -- if (ct_addr = xip_ctrl_addr_c) then - ctrl(ctrl_enable_c) <= ct_data_i(ctrl_enable_c); - ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= ct_data_i(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c); - ctrl(ctrl_spi_cpol_c) <= ct_data_i(ctrl_spi_cpol_c); - ctrl(ctrl_spi_cpha_c) <= ct_data_i(ctrl_spi_cpha_c); - ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ct_data_i(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c); - ctrl(ctrl_xip_enable_c) <= ct_data_i(ctrl_xip_enable_c); - ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ct_data_i(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c); - ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ct_data_i(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c); - ctrl(ctrl_page3_c downto ctrl_page0_c) <= ct_data_i(ctrl_page3_c downto ctrl_page0_c); - ctrl(ctrl_spi_csen_c) <= ct_data_i(ctrl_spi_csen_c); - ctrl(ctrl_highspeed_c) <= ct_data_i(ctrl_highspeed_c); - ctrl(ctrl_burst_en_c) <= ct_data_i(ctrl_burst_en_c); + ctrl(ctrl_enable_c) <= bus_req_i.data(ctrl_enable_c); + ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= bus_req_i.data(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c); + ctrl(ctrl_spi_cpol_c) <= bus_req_i.data(ctrl_spi_cpol_c); + ctrl(ctrl_spi_cpha_c) <= bus_req_i.data(ctrl_spi_cpha_c); + ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= bus_req_i.data(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c); + ctrl(ctrl_xip_enable_c) <= bus_req_i.data(ctrl_xip_enable_c); + ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= bus_req_i.data(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c); + ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= bus_req_i.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c); + ctrl(ctrl_page3_c downto ctrl_page0_c) <= bus_req_i.data(ctrl_page3_c downto ctrl_page0_c); + ctrl(ctrl_spi_csen_c) <= bus_req_i.data(ctrl_spi_csen_c); + ctrl(ctrl_highspeed_c) <= bus_req_i.data(ctrl_highspeed_c); + ctrl(ctrl_burst_en_c) <= bus_req_i.data(ctrl_burst_en_c); end if; -- SPI direct data access register lo -- if (ct_addr = xip_data_lo_addr_c) then - spi_data_lo <= ct_data_i; + spi_data_lo <= bus_req_i.data; end if; -- SPI direct data access register hi -- if (ct_addr = xip_data_hi_addr_c) then - spi_data_hi <= ct_data_i; + spi_data_hi <= bus_req_i.data; spi_trigger <= '1'; -- trigger direct SPI transaction end if; end if; @@ -237,35 +223,38 @@ begin ctrl_read_access : process(clk_i) begin if rising_edge(clk_i) then - ct_ack_o <= ct_wren or ct_rden; -- access acknowledge - ct_data_o <= (others => '0'); + bus_rsp_o.ack <= ct_wren or ct_rden; -- access acknowledge + bus_rsp_o.data <= (others => '0'); if (ct_rden = '1') then case ct_addr(3 downto 2) is when "00" => -- 'xip_ctrl_addr_c' - control register - ct_data_o(ctrl_enable_c) <= ctrl(ctrl_enable_c); - ct_data_o(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c); - ct_data_o(ctrl_spi_cpol_c) <= ctrl(ctrl_spi_cpol_c); - ct_data_o(ctrl_spi_cpha_c) <= ctrl(ctrl_spi_cpha_c); - ct_data_o(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c); - ct_data_o(ctrl_xip_enable_c) <= ctrl(ctrl_xip_enable_c); - ct_data_o(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c); - ct_data_o(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c); - ct_data_o(ctrl_page3_c downto ctrl_page0_c) <= ctrl(ctrl_page3_c downto ctrl_page0_c); - ct_data_o(ctrl_spi_csen_c) <= ctrl(ctrl_spi_csen_c); - ct_data_o(ctrl_highspeed_c) <= ctrl(ctrl_highspeed_c); - ct_data_o(ctrl_burst_en_c) <= ctrl(ctrl_burst_en_c); + bus_rsp_o.data(ctrl_enable_c) <= ctrl(ctrl_enable_c); + bus_rsp_o.data(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c); + bus_rsp_o.data(ctrl_spi_cpol_c) <= ctrl(ctrl_spi_cpol_c); + bus_rsp_o.data(ctrl_spi_cpha_c) <= ctrl(ctrl_spi_cpha_c); + bus_rsp_o.data(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c); + bus_rsp_o.data(ctrl_xip_enable_c) <= ctrl(ctrl_xip_enable_c); + bus_rsp_o.data(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c); + bus_rsp_o.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c); + bus_rsp_o.data(ctrl_page3_c downto ctrl_page0_c) <= ctrl(ctrl_page3_c downto ctrl_page0_c); + bus_rsp_o.data(ctrl_spi_csen_c) <= ctrl(ctrl_spi_csen_c); + bus_rsp_o.data(ctrl_highspeed_c) <= ctrl(ctrl_highspeed_c); + bus_rsp_o.data(ctrl_burst_en_c) <= ctrl(ctrl_burst_en_c); -- - ct_data_o(ctrl_phy_busy_c) <= phy_if.busy; - ct_data_o(ctrl_xip_busy_c) <= arbiter.busy; + bus_rsp_o.data(ctrl_phy_busy_c) <= phy_if.busy; + bus_rsp_o.data(ctrl_xip_busy_c) <= arbiter.busy; when "10" => -- 'xip_data_lo_addr_c' - SPI direct data access register lo - ct_data_o <= phy_if.rdata; + bus_rsp_o.data <= phy_if.rdata; when others => -- unavailable (not implemented or write-only) - ct_data_o <= (others => '0'); + bus_rsp_o.data <= (others => '0'); end case; end if; end if; end process ctrl_read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- XIP Address Computation Logic ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -296,8 +285,8 @@ begin arbiter.state <= arbiter.state_nxt; end if; -- address look-ahead -- - if (acc_rden_i = '1') and (acc_addr_i(31 downto 28) = ctrl(ctrl_page3_c downto ctrl_page0_c)) then - arbiter.addr <= acc_addr_i; -- buffer address (reducing fan-out on CPU's address net) + if (xip_req_i.re = '1') and (xip_req_i.addr(31 downto 28) = ctrl(ctrl_page3_c downto ctrl_page0_c)) then + arbiter.addr <= xip_req_i.addr; -- buffer address (reducing fan-out on CPU's address net) end if; arbiter.addr_lookahead <= std_ulogic_vector(unsigned(arbiter.addr) + 4); -- prefetch address of *next* linear access -- pending flash access timeout -- @@ -311,15 +300,15 @@ begin -- FSM - combinatorial part -- - arbiter_comb: process(arbiter, ctrl, xip_addr, phy_if, acc_rden_i, acc_wren_i, acc_addr_i, spi_data_hi, spi_data_lo, spi_trigger) + arbiter_comb: process(arbiter, ctrl, xip_addr, phy_if, xip_req_i, spi_data_hi, spi_data_lo, spi_trigger) begin -- arbiter defaults -- arbiter.state_nxt <= arbiter.state; -- bus interface defaults -- - acc_data_o <= (others => '0'); - acc_ack_o <= '0'; - acc_err_o <= '0'; + xip_rsp_o.data <= (others => '0'); + xip_rsp_o.ack <= '0'; + xip_rsp_o.err <= '0'; -- SPI PHY interface defaults -- phy_if.start <= '0'; @@ -338,10 +327,10 @@ begin when S_IDLE => -- wait for new bus request -- ------------------------------------------------------------ - if (acc_addr_i(31 downto 28) = ctrl(ctrl_page3_c downto ctrl_page0_c)) then - if (acc_rden_i = '1') then + if (xip_req_i.addr(31 downto 28) = ctrl(ctrl_page3_c downto ctrl_page0_c)) then + if (xip_req_i.re = '1') then arbiter.state_nxt <= S_CHECK; - elsif (acc_wren_i = '1') then + elsif (xip_req_i.we = '1') then arbiter.state_nxt <= S_ERROR; end if; end if; @@ -364,15 +353,15 @@ begin when S_BUSY => -- wait for PHY to complete operation -- ------------------------------------------------------------ - acc_data_o <= bswap32_f(phy_if.rdata); -- convert incrementing byte-read to little-endian + xip_rsp_o.data <= bswap32_f(phy_if.rdata); -- convert incrementing byte-read to little-endian if (phy_if.busy = '0') then - acc_ack_o <= '1'; + xip_rsp_o.ack <= '1'; arbiter.state_nxt <= S_IDLE; end if; when S_ERROR => -- access error -- ------------------------------------------------------------ - acc_err_o <= '1'; + xip_rsp_o.err <= '1'; arbiter.state_nxt <= S_IDLE; when others => -- undefined diff --git a/rtl/core/neorv32_xirq.vhd b/rtl/core/neorv32_xirq.vhd index 6929cf322..4d2846ecc 100644 --- a/rtl/core/neorv32_xirq.vhd +++ b/rtl/core/neorv32_xirq.vhd @@ -53,19 +53,12 @@ entity neorv32_xirq is XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- external interrupt lines -- - xirq_i : in std_ulogic_vector(31 downto 0); - -- CPU interrupt -- - cpu_irq_o : out std_ulogic + rstn_i : in std_ulogic; -- global reset line, low-active + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + xirq_i : in std_ulogic_vector(31 downto 0); -- external IRQ channels + cpu_irq_o : out std_ulogic -- CPU interrupt ); end neorv32_xirq; @@ -111,10 +104,10 @@ begin -- Host Access ---------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- access control -- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = xirq_base_c(hi_abb_c downto lo_abb_c)) else '0'; - addr <= xirq_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned - wren <= acc_en and wren_i; - rden <= acc_en and rden_i; + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = xirq_base_c(hi_abb_c downto lo_abb_c)) else '0'; + addr <= xirq_base_c(31 downto lo_abb_c) & bus_req_i.addr(lo_abb_c-1 downto 2) & "00"; -- word aligned + wren <= acc_en and bus_req_i.we; + rden <= acc_en and bus_req_i.re; -- write access -- write_access: process(rstn_i, clk_i) @@ -126,10 +119,10 @@ begin nclr_pending <= (others => '1'); if (wren = '1') then if (addr = xirq_enable_addr_c) then -- channel-enable - irq_enable <= data_i(XIRQ_NUM_CH-1 downto 0); + irq_enable <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); end if; if (addr = xirq_pending_addr_c) then -- clear pending IRQs - nclr_pending <= data_i(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ + nclr_pending <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ end if; end if; end if; @@ -139,18 +132,21 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - ack_o <= rden or wren; -- bus handshake - data_o <= (others => '0'); + bus_rsp_o.ack <= rden or wren; -- bus handshake + bus_rsp_o.data <= (others => '0'); if (rden = '1') then case addr is - when xirq_enable_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable - when xirq_pending_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs - when others => data_o(4 downto 0) <= irq_source; -- IRQ source + when xirq_enable_addr_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable + when xirq_pending_addr_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs + when others => bus_rsp_o.data(4 downto 0) <= irq_source; -- IRQ source end case; end if; end if; end process read_access; + -- no access error possible -- + bus_rsp_o.err <= '0'; + -- IRQ Trigger -------------------------------------------------------------- -- ----------------------------------------------------------------------------- From 9ece83e4ac6c9b74e1b87a8e025f4c291f19fe2c Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:17:51 +0200 Subject: [PATCH 2/6] [rtl] rework memories' bus interface --- rtl/core/mem/neorv32_dmem.default.vhd | 29 +++++++++++++----------- rtl/core/mem/neorv32_dmem.legacy.vhd | 29 +++++++++++++----------- rtl/core/mem/neorv32_imem.default.vhd | 32 +++++++++++++-------------- rtl/core/mem/neorv32_imem.legacy.vhd | 32 +++++++++++++-------------- rtl/core/neorv32_dmem.entity.vhd | 16 ++++++-------- rtl/core/neorv32_imem.entity.vhd | 15 +++++-------- 6 files changed, 77 insertions(+), 76 deletions(-) diff --git a/rtl/core/mem/neorv32_dmem.default.vhd b/rtl/core/mem/neorv32_dmem.default.vhd index 5ea83f648..d19dff252 100644 --- a/rtl/core/mem/neorv32_dmem.default.vhd +++ b/rtl/core/mem/neorv32_dmem.default.vhd @@ -79,8 +79,8 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; - addr <= addr_i(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; + addr <= bus_req_i.addr(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned -- Memory Access -------------------------------------------------------------------------- @@ -91,23 +91,23 @@ begin -- this RAM style should not require "no_rw_check" attributes as the read-after-write behavior -- is intended to be defined implicitly via the if-WRITE-else-READ construct if (acc_en = '1') then -- reduce switching activity when not accessed - if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0 - mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00); + if (bus_req_i.we = '1') and (bus_req_i.ben(0) = '1') then -- byte 0 + mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(07 downto 00); else mem_ram_b0_rd <= mem_ram_b0(to_integer(unsigned(addr))); end if; - if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1 - mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08); + if (bus_req_i.we = '1') and (bus_req_i.ben(1) = '1') then -- byte 1 + mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 08); else mem_ram_b1_rd <= mem_ram_b1(to_integer(unsigned(addr))); end if; - if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2 - mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16); + if (bus_req_i.we = '1') and (bus_req_i.ben(2) = '1') then -- byte 2 + mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16); else mem_ram_b2_rd <= mem_ram_b2(to_integer(unsigned(addr))); end if; - if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3 - mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24); + if (bus_req_i.we = '1') and (bus_req_i.ben(3) = '1') then -- byte 3 + mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24); else mem_ram_b3_rd <= mem_ram_b3(to_integer(unsigned(addr))); end if; @@ -121,8 +121,8 @@ begin bus_feedback: process(clk_i) begin if rising_edge(clk_i) then - rden <= acc_en and rden_i; - ack_o <= acc_en and (rden_i or wren_i); + rden <= acc_en and bus_req_i.re; + bus_rsp_o.ack <= acc_en and (bus_req_i.re or bus_req_i.we); end if; end process bus_feedback; @@ -130,7 +130,10 @@ begin rdata <= mem_ram_b3_rd & mem_ram_b2_rd & mem_ram_b1_rd & mem_ram_b0_rd; -- output gate -- - data_o <= rdata when (rden = '1') else (others => '0'); + bus_rsp_o.data <= rdata when (rden = '1') else (others => '0'); + + -- no access error possible -- + bus_rsp_o.err <= '0'; end neorv32_dmem_rtl; diff --git a/rtl/core/mem/neorv32_dmem.legacy.vhd b/rtl/core/mem/neorv32_dmem.legacy.vhd index 6728f7e5b..51ecc658d 100644 --- a/rtl/core/mem/neorv32_dmem.legacy.vhd +++ b/rtl/core/mem/neorv32_dmem.legacy.vhd @@ -80,8 +80,8 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; - addr <= addr_i(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; + addr <= bus_req_i.addr(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned -- Memory Access -------------------------------------------------------------------------- @@ -91,17 +91,17 @@ begin if rising_edge(clk_i) then addr_ff <= addr; if (acc_en = '1') then -- reduce switching activity when not accessed - if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0 - mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00); + if (bus_req_i.we = '1') and (bus_req_i.ben(0) = '1') then -- byte 0 + mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(07 downto 00); end if; - if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1 - mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08); + if (bus_req_i.we = '1') and (bus_req_i.ben(1) = '1') then -- byte 1 + mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 08); end if; - if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2 - mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16); + if (bus_req_i.we = '1') and (bus_req_i.ben(2) = '1') then -- byte 2 + mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16); end if; - if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3 - mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24); + if (bus_req_i.we = '1') and (bus_req_i.ben(3) = '1') then -- byte 3 + mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24); end if; end if; end if; @@ -119,8 +119,8 @@ begin bus_feedback: process(clk_i) begin if rising_edge(clk_i) then - rden <= acc_en and rden_i; - ack_o <= acc_en and (rden_i or wren_i); + rden <= acc_en and bus_req_i.re; + bus_rsp_o.ack <= acc_en and (bus_req_i.re or bus_req_i.we); end if; end process bus_feedback; @@ -128,7 +128,10 @@ begin rdata <= mem_ram_b3_rd & mem_ram_b2_rd & mem_ram_b1_rd & mem_ram_b0_rd; -- output gate -- - data_o <= rdata when (rden = '1') else (others => '0'); + bus_rsp_o.data <= rdata when (rden = '1') else (others => '0'); + + -- no access error possible -- + bus_rsp_o.err <= '0'; end neorv32_dmem_rtl; diff --git a/rtl/core/mem/neorv32_imem.default.vhd b/rtl/core/mem/neorv32_imem.default.vhd index 83fb6726e..be54c2619 100644 --- a/rtl/core/mem/neorv32_imem.default.vhd +++ b/rtl/core/mem/neorv32_imem.default.vhd @@ -104,8 +104,8 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; - addr <= addr_i(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; + addr <= bus_req_i.addr(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned -- Implement IMEM as pre-initialized ROM -------------------------------------------------- @@ -135,23 +135,23 @@ begin -- this RAM style should not require "no_rw_check" attributes as the read-after-write behavior -- is intended to be defined implicitly via the if-WRITE-else-READ construct if (acc_en = '1') then -- reduce switching activity when not accessed - if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0 - mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00); + if (bus_req_i.we = '1') and (bus_req_i.ben(0) = '1') then -- byte 0 + mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(07 downto 00); else mem_b0_rd <= mem_ram_b0(to_integer(unsigned(addr))); end if; - if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1 - mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08); + if (bus_req_i.we = '1') and (bus_req_i.ben(1) = '1') then -- byte 1 + mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 08); else mem_b1_rd <= mem_ram_b1(to_integer(unsigned(addr))); end if; - if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2 - mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16); + if (bus_req_i.we = '1') and (bus_req_i.ben(2) = '1') then -- byte 2 + mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16); else mem_b2_rd <= mem_ram_b2(to_integer(unsigned(addr))); end if; - if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3 - mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24); + if (bus_req_i.we = '1') and (bus_req_i.ben(3) = '1') then -- byte 3 + mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24); else mem_b3_rd <= mem_ram_b3(to_integer(unsigned(addr))); end if; @@ -168,19 +168,19 @@ begin bus_feedback: process(clk_i) begin if rising_edge(clk_i) then - rden <= acc_en and rden_i; + rden <= acc_en and bus_req_i.re; if (IMEM_AS_IROM = true) then - ack_o <= acc_en and rden_i; - err_o <= acc_en and wren_i; + bus_rsp_o.ack <= acc_en and bus_req_i.re; + bus_rsp_o.err <= acc_en and bus_req_i.we; else - ack_o <= acc_en and (rden_i or wren_i); - err_o <= '0'; + bus_rsp_o.ack <= acc_en and (bus_req_i.re or bus_req_i.we); + bus_rsp_o.err <= '0'; end if; end if; end process bus_feedback; -- output gate -- - data_o <= rdata when (rden = '1') else (others => '0'); + bus_rsp_o.data <= rdata when (rden = '1') else (others => '0'); end neorv32_imem_rtl; diff --git a/rtl/core/mem/neorv32_imem.legacy.vhd b/rtl/core/mem/neorv32_imem.legacy.vhd index ad6e2b529..b09457df5 100644 --- a/rtl/core/mem/neorv32_imem.legacy.vhd +++ b/rtl/core/mem/neorv32_imem.legacy.vhd @@ -105,8 +105,8 @@ begin -- Access Control ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; - addr <= addr_i(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned + acc_en <= '1' when (bus_req_i.addr(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0'; + addr <= bus_req_i.addr(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned -- Implement IMEM as pre-initialized ROM -------------------------------------------------- @@ -135,17 +135,17 @@ begin if rising_edge(clk_i) then addr_ff <= addr; if (acc_en = '1') then -- reduce switching activity when not accessed - if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0 - mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00); + if (bus_req_i.we = '1') and (bus_req_i.ben(0) = '1') then -- byte 0 + mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(07 downto 00); end if; - if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1 - mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08); + if (bus_req_i.we = '1') and (bus_req_i.ben(1) = '1') then -- byte 1 + mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 08); end if; - if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2 - mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16); + if (bus_req_i.we = '1') and (bus_req_i.ben(2) = '1') then -- byte 2 + mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16); end if; - if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3 - mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24); + if (bus_req_i.we = '1') and (bus_req_i.ben(3) = '1') then -- byte 3 + mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24); end if; end if; end if; @@ -165,19 +165,19 @@ begin bus_feedback: process(clk_i) begin if rising_edge(clk_i) then - rden <= acc_en and rden_i; + rden <= acc_en and bus_req_i.re; if (IMEM_AS_IROM = true) then - ack_o <= acc_en and rden_i; - err_o <= acc_en and wren_i; + bus_rsp_o.ack <= acc_en and bus_req_i.re; + bus_rsp_o.err <= acc_en and bus_req_i.we; else - ack_o <= acc_en and (rden_i or wren_i); - err_o <= '0'; + bus_rsp_o.ack <= acc_en and (bus_req_i.re or bus_req_i.we); + bus_rsp_o.err <= '0'; end if; end if; end process bus_feedback; -- output gate -- - data_o <= rdata when (rden = '1') else (others => '0'); + bus_rsp_o.data <= rdata when (rden = '1') else (others => '0'); end neorv32_imem_rtl; diff --git a/rtl/core/neorv32_dmem.entity.vhd b/rtl/core/neorv32_dmem.entity.vhd index 4ca529ca3..8eb6993af 100644 --- a/rtl/core/neorv32_dmem.entity.vhd +++ b/rtl/core/neorv32_dmem.entity.vhd @@ -3,7 +3,7 @@ -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # --- # Copyright (c) 2024, Stephan Nolting. All rights reserved. # +-- # Copyright (c) 2023, Stephan Nolting. All rights reserved. # -- # # -- # Redistribution and use in source and binary forms, with or without modification, are # -- # permitted provided that the following conditions are met: # @@ -36,19 +36,17 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +library neorv32; +use neorv32.neorv32_package.all; + entity neorv32_dmem is generic ( DMEM_BASE : std_ulogic_vector(31 downto 0); -- memory base address DMEM_SIZE : natural -- processor-internal instruction memory size in bytes ); port ( - clk_i : in std_ulogic; -- global clock line - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - addr_i : in std_ulogic_vector(31 downto 0); -- address - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic -- transfer acknowledge + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end neorv32_dmem; diff --git a/rtl/core/neorv32_imem.entity.vhd b/rtl/core/neorv32_imem.entity.vhd index 2c62c51d0..dc82f32a2 100644 --- a/rtl/core/neorv32_imem.entity.vhd +++ b/rtl/core/neorv32_imem.entity.vhd @@ -36,6 +36,9 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +library neorv32; +use neorv32.neorv32_package.all; + entity neorv32_imem is generic ( IMEM_BASE : std_ulogic_vector(31 downto 0); -- memory base address @@ -43,14 +46,8 @@ entity neorv32_imem is IMEM_AS_IROM : boolean -- implement IMEM as pre-initialized read-only memory? ); port ( - clk_i : in std_ulogic; -- global clock line - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - addr_i : in std_ulogic_vector(31 downto 0); -- address - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic -- transfer error + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end neorv32_imem; From 240f462a84cf9dce871b389ce40a13fddbe579ac Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:18:16 +0200 Subject: [PATCH 3/6] [CPU] rework CPU bus interface --- rtl/core/neorv32_cpu.vhd | 173 +++++++++++++++++------------------ rtl/core/neorv32_cpu_bus.vhd | 12 +-- 2 files changed, 89 insertions(+), 96 deletions(-) diff --git a/rtl/core/neorv32_cpu.vhd b/rtl/core/neorv32_cpu.vhd index fc4086421..eebba73b5 100644 --- a/rtl/core/neorv32_cpu.vhd +++ b/rtl/core/neorv32_cpu.vhd @@ -75,35 +75,24 @@ entity neorv32_cpu is ); 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 + 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 + ifence_o : out std_ulogic; -- instruction fence + dfence_o : out std_ulogic; -- data fence + -- interrupts -- + msi_i : in std_ulogic; -- risc-v machine software interrupt + mei_i : in std_ulogic; -- risc-v machine external interrupt + mti_i : in std_ulogic; -- risc-v machine timer interrupt + firq_i : in std_ulogic_vector(15 downto 0); -- custom fast interrupts + dbi_i : in std_ulogic; -- risc-v debug halt request interrupt -- instruction bus interface -- - i_bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - i_bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - i_bus_re_o : out std_ulogic; -- read 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; -- current effective privilege level + ibus_req_o : out bus_req_t; -- request bus + ibus_rsp_i : in bus_rsp_t; -- response bus -- data bus interface -- - d_bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - d_bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - d_bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - d_bus_ben_o : out std_ulogic_vector(3 downto 0); -- byte enable - d_bus_we_o : out std_ulogic; -- write request - d_bus_re_o : out std_ulogic; -- read 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; -- current effective privilege level - -- interrupts -- - msi_i : in std_ulogic; -- risc-v: machine software interrupt - mei_i : in std_ulogic; -- risc-v: machine external interrupt - mti_i : in std_ulogic; -- risc-v: machine timer interrupt - firq_i : in std_ulogic_vector(15 downto 0); -- custom: fast interrupts - db_halt_req_i : in std_ulogic -- risc-v: halt request (debug mode) + dbus_req_o : out bus_req_t; -- request bus + dbus_rsp_i : in bus_rsp_t -- response bus ); end neorv32_cpu; @@ -255,58 +244,65 @@ begin ) port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_i, -- global reset, low-active, async - ctrl_o => ctrl, -- main control bus + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_o => ctrl, -- main control bus -- instruction fetch interface -- - i_bus_addr_o => fetch_pc, -- bus access address - i_bus_rdata_i => i_bus_rdata_i, -- bus read data - i_bus_re_o => i_bus_re_o, -- read enable - i_bus_ack_i => i_bus_ack_i, -- bus transfer acknowledge - i_bus_err_i => i_bus_err_i, -- bus transfer error - i_pmp_fault_i => i_pmp_fault, -- instruction fetch pmp fault + i_bus_addr_o => fetch_pc, -- bus access address + i_bus_rdata_i => ibus_rsp_i.data, -- bus read data + i_bus_re_o => ibus_req_o.re, -- read enable + i_bus_ack_i => ibus_rsp_i.ack, -- bus transfer acknowledge + i_bus_err_i => ibus_rsp_i.err, -- bus transfer error + i_pmp_fault_i => i_pmp_fault, -- instruction fetch pmp fault -- status input -- - alu_cp_done_i => cp_done, -- ALU iterative operation done - alu_exc_i => alu_exc, -- ALU exception - bus_d_wait_i => bus_d_wait, -- wait for bus + alu_cp_done_i => cp_done, -- ALU iterative operation done + alu_exc_i => alu_exc, -- ALU exception + bus_d_wait_i => bus_d_wait, -- wait for bus -- data input -- - cmp_i => alu_cmp, -- comparator status - alu_add_i => alu_add, -- ALU address result - rs1_i => rs1, -- rf source 1 + cmp_i => alu_cmp, -- comparator status + alu_add_i => alu_add, -- ALU address result + rs1_i => rs1, -- rf source 1 -- data output -- - imm_o => imm, -- immediate - curr_pc_o => curr_pc, -- current PC (corresponding to current instruction) - next_pc_o => next_pc, -- next PC (corresponding to next instruction) - csr_rdata_o => csr_rdata, -- CSR read data + imm_o => imm, -- immediate + curr_pc_o => curr_pc, -- current PC (corresponding to current instruction) + next_pc_o => next_pc, -- next PC (corresponding to next instruction) + csr_rdata_o => csr_rdata, -- CSR read data -- FPU interface -- - fpu_flags_i => fpu_flags, -- exception flags + fpu_flags_i => fpu_flags, -- exception flags -- debug mode (halt) request -- - db_halt_req_i => db_halt_req_i, + db_halt_req_i => dbi_i, -- interrupts (risc-v compliant) -- - msi_i => msi_i, -- machine software interrupt - mei_i => mei_i, -- machine external interrupt - mti_i => mti_i, -- machine timer interrupt + msi_i => msi_i, -- machine software interrupt + mei_i => mei_i, -- machine external interrupt + mti_i => mti_i, -- machine timer interrupt -- fast interrupts (custom) -- - firq_i => firq_i, -- fast interrupt trigger + firq_i => firq_i, -- fast interrupt trigger -- physical memory protection -- - pmp_addr_o => pmp_addr, -- addresses - pmp_ctrl_o => pmp_ctrl, -- configs + pmp_addr_o => pmp_addr, -- addresses + pmp_ctrl_o => pmp_ctrl, -- configs -- bus access exceptions -- - mar_i => mar, -- memory address register - ma_load_i => ma_load, -- misaligned load data address - ma_store_i => ma_store, -- misaligned store data address - be_load_i => be_load, -- bus error on load data access - be_store_i => be_store -- bus error on store data access + mar_i => mar, -- memory address register + ma_load_i => ma_load, -- misaligned load data address + ma_store_i => ma_store, -- misaligned store data address + be_load_i => be_load, -- bus error on load data access + be_store_i => be_store -- bus error on store data access ); -- CPU state -- sleep_o <= ctrl.cpu_sleep; -- set when CPU is sleeping (after WFI) debug_o <= ctrl.cpu_debug; -- set when CPU is in debug mode + -- instruction/data fence -- + ifence_o <= ctrl.bus_fencei; + dfence_o <= ctrl.bus_fence; + -- instruction fetch interface -- - i_bus_addr_o <= fetch_pc; - i_bus_fence_o <= ctrl.bus_fencei; - i_bus_priv_o <= ctrl.cpu_priv; + ibus_req_o.addr <= fetch_pc; + ibus_req_o.priv <= ctrl.cpu_priv; + ibus_req_o.data <= (others => '0'); + ibus_req_o.ben <= (others => '0'); + ibus_req_o.we <= '0'; -- read-only + ibus_req_o.src <= '1'; -- source = instruction fetch -- Register File -------------------------------------------------------------------------- @@ -381,37 +377,38 @@ begin ) port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_i, -- global reset, low-active, async - ctrl_i => ctrl, -- main control bus + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_i => ctrl, -- main control bus -- cpu instruction fetch interface -- - fetch_pc_i => fetch_pc, -- PC for instruction fetch - i_pmp_fault_o => i_pmp_fault, -- instruction fetch pmp fault + fetch_pc_i => fetch_pc, -- PC for instruction fetch + i_pmp_fault_o => i_pmp_fault, -- instruction fetch pmp fault -- cpu data access interface -- - addr_i => alu_add, -- ALU.add result -> access address - wdata_i => rs2, -- write data - rdata_o => mem_rdata, -- read data - mar_o => mar, -- current memory address register - d_wait_o => bus_d_wait, -- wait for access to complete - ma_load_o => ma_load, -- misaligned load data address - ma_store_o => ma_store, -- misaligned store data address - be_load_o => be_load, -- bus error on load data access - be_store_o => be_store, -- bus error on store data access + addr_i => alu_add, -- ALU.add result -> access address + wdata_i => rs2, -- write data + rdata_o => mem_rdata, -- read data + mar_o => mar, -- current memory address register + d_wait_o => bus_d_wait, -- wait for access to complete + ma_load_o => ma_load, -- misaligned load data address + ma_store_o => ma_store, -- misaligned store data address + be_load_o => be_load, -- bus error on load data access + be_store_o => be_store, -- bus error on store data access -- physical memory protection -- - pmp_addr_i => pmp_addr, -- addresses - pmp_ctrl_i => pmp_ctrl, -- configurations + pmp_addr_i => pmp_addr, -- addresses + pmp_ctrl_i => pmp_ctrl, -- configurations -- data bus -- - d_bus_addr_o => d_bus_addr_o, -- bus access address - d_bus_rdata_i => d_bus_rdata_i, -- bus read data - d_bus_wdata_o => d_bus_wdata_o, -- bus write data - d_bus_ben_o => d_bus_ben_o, -- byte enable - d_bus_we_o => d_bus_we_o, -- write enable - d_bus_re_o => d_bus_re_o, -- read enable - d_bus_ack_i => d_bus_ack_i, -- bus transfer acknowledge - d_bus_err_i => d_bus_err_i, -- bus transfer error - d_bus_fence_o => d_bus_fence_o, -- fence operation - d_bus_priv_o => d_bus_priv_o -- current effective privilege level + d_bus_addr_o => dbus_req_o.addr, -- bus access address + d_bus_rdata_i => dbus_rsp_i.data, -- bus read data + d_bus_wdata_o => dbus_req_o.data, -- bus write data + d_bus_ben_o => dbus_req_o.ben, -- byte enable + d_bus_we_o => dbus_req_o.we, -- write enable + d_bus_re_o => dbus_req_o.re, -- read enable + d_bus_ack_i => dbus_rsp_i.ack, -- bus transfer acknowledge + d_bus_err_i => dbus_rsp_i.err -- bus transfer error ); + dbus_req_o.priv <= ctrl.bus_priv; + dbus_req_o.src <= '0'; -- source = data access + end neorv32_cpu_rtl; diff --git a/rtl/core/neorv32_cpu_bus.vhd b/rtl/core/neorv32_cpu_bus.vhd index ee9c4d71a..d640ea31a 100644 --- a/rtl/core/neorv32_cpu_bus.vhd +++ b/rtl/core/neorv32_cpu_bus.vhd @@ -75,9 +75,7 @@ entity neorv32_cpu_bus is d_bus_we_o : out std_ulogic; -- write enable d_bus_re_o : out std_ulogic; -- read enable 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; -- fence operation - d_bus_priv_o : out std_ulogic -- current effective privilege level + d_bus_err_i : in std_ulogic -- bus transfer error ); end neorv32_cpu_bus; @@ -276,11 +274,9 @@ begin ma_store_o <= arbiter.pend_wr and misaligned; be_store_o <= arbiter.pend_wr and arbiter.acc_err; - -- data bus control interface (all source signals are driven by registers!) -- - d_bus_re_o <= ctrl_i.bus_req_rd and (not misaligned) and (not arbiter.pmp_r_err); - d_bus_we_o <= ctrl_i.bus_req_wr and (not misaligned) and (not arbiter.pmp_w_err); - d_bus_fence_o <= ctrl_i.bus_fence; - d_bus_priv_o <= ctrl_i.bus_priv; + -- access requests (all source signals are driven by registers!) -- + d_bus_re_o <= ctrl_i.bus_req_rd and (not misaligned) and (not arbiter.pmp_r_err); + d_bus_we_o <= ctrl_i.bus_req_wr and (not misaligned) and (not arbiter.pmp_w_err); -- RISC-V Physical Memory Protection (PMP) ------------------------------------------------ From 5297c05248d8c07b8e18088c9fb2b61c4cb20c32 Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:18:34 +0200 Subject: [PATCH 4/6] [SOC] rework SoC bus system --- rtl/core/neorv32_icache.vhd | 66 +- rtl/core/neorv32_package.vhd | 628 +++++----------- rtl/core/neorv32_top.vhd | 1356 ++++++++++++---------------------- 3 files changed, 718 insertions(+), 1332 deletions(-) diff --git a/rtl/core/neorv32_icache.vhd b/rtl/core/neorv32_icache.vhd index a0e5c9da1..718b2e136 100644 --- a/rtl/core/neorv32_icache.vhd +++ b/rtl/core/neorv32_icache.vhd @@ -49,23 +49,13 @@ entity neorv32_icache is ICACHE_NUM_SETS : natural -- associativity / number of sets (1=direct_mapped), has to be a power of 2 ); port ( - -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - clear_i : in std_ulogic; -- cache clear - -- host controller interface -- - host_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - host_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - host_re_i : in std_ulogic; -- read enable - host_ack_o : out std_ulogic; -- bus transfer acknowledge - host_err_o : out std_ulogic; -- bus transfer error - -- peripheral bus interface -- - bus_cached_o : out std_ulogic; -- set if cached (!) access in progress - bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - bus_re_o : out std_ulogic; -- read enable - bus_ack_i : in std_ulogic; -- bus transfer acknowledge - bus_err_i : in std_ulogic -- bus transfer error + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + clear_i : in std_ulogic; -- cache clear + cpu_req_i : in bus_req_t; -- request bus + cpu_rsp_o : out bus_rsp_t; -- response bus + bus_req_o : out bus_req_t; -- request bus + bus_rsp_i : in bus_rsp_t -- response bus ); end neorv32_icache; @@ -168,31 +158,36 @@ begin -- Control Engine FSM Comb ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - ctrl_engine_fsm_comb: process(ctrl, cache, clear_i, host_addr_i, host_re_i, bus_rdata_i, bus_ack_i, bus_err_i) + ctrl_engine_fsm_comb: process(ctrl, cache, clear_i, cpu_req_i, bus_rsp_i) begin -- control defaults -- ctrl.state_nxt <= ctrl.state; ctrl.addr_reg_nxt <= ctrl.addr_reg; - ctrl.re_buf_nxt <= ctrl.re_buf or host_re_i; + ctrl.re_buf_nxt <= ctrl.re_buf or cpu_req_i.re; ctrl.clear_buf_nxt <= ctrl.clear_buf or clear_i; -- buffer clear request from CPU -- cache defaults -- cache.clear <= '0'; - cache.host_addr <= host_addr_i; + cache.host_addr <= cpu_req_i.addr; cache.ctrl_en <= '0'; cache.ctrl_addr <= ctrl.addr_reg; cache.ctrl_we <= '0'; - cache.ctrl_wdata <= bus_rdata_i; - cache.ctrl_wstat <= bus_err_i; + cache.ctrl_wdata <= bus_rsp_i.data; + cache.ctrl_wstat <= bus_rsp_i.err; -- host interface defaults -- - host_ack_o <= '0'; - host_err_o <= '0'; - host_rdata_o <= cache.host_rdata; + cpu_rsp_o.ack <= '0'; + cpu_rsp_o.err <= '0'; + cpu_rsp_o.data <= cache.host_rdata; -- peripheral bus interface defaults -- - bus_addr_o <= ctrl.addr_reg; - bus_re_o <= '0'; + bus_req_o.data <= (others => '0'); + bus_req_o.ben <= (others => '0'); + bus_req_o.src <= cpu_req_i.src; + bus_req_o.priv <= cpu_req_i.priv; + bus_req_o.addr <= ctrl.addr_reg; + bus_req_o.we <= '0'; + bus_req_o.re <= '0'; -- fsm -- case ctrl.state is @@ -201,23 +196,23 @@ begin -- ------------------------------------------------------------ if (ctrl.clear_buf = '1') then -- cache control operation? ctrl.state_nxt <= S_CLEAR; - elsif (host_re_i = '1') or (ctrl.re_buf = '1') then -- cache access + elsif (cpu_req_i.re = '1') or (ctrl.re_buf = '1') then -- cache access ctrl.state_nxt <= S_CHECK; end if; when S_CHECK => -- finalize host access if cache hit -- ------------------------------------------------------------ -- calculate block base address - in case we need to download it -- - ctrl.addr_reg_nxt <= host_addr_i; + ctrl.addr_reg_nxt <= cpu_req_i.addr; ctrl.addr_reg_nxt((cache_offset_size_c+2)-1 downto 2) <= (others => '0'); -- block-aligned ctrl.addr_reg_nxt(1 downto 0) <= "00"; -- word-aligned -- ctrl.re_buf_nxt <= '0'; if (cache.hit = '1') then -- cache HIT if (cache.host_rstat = '1') then -- data word from cache marked as faulty? - host_err_o <= '1'; + cpu_rsp_o.err <= '1'; else - host_ack_o <= '1'; + cpu_rsp_o.ack <= '1'; end if; ctrl.state_nxt <= S_IDLE; else -- cache MISS @@ -226,13 +221,13 @@ begin when S_DOWNLOAD_REQ => -- download new cache block: request new word -- ------------------------------------------------------------ - bus_re_o <= '1'; -- request new read transfer + bus_req_o.re <= '1'; -- request new read transfer ctrl.state_nxt <= S_DOWNLOAD_GET; when S_DOWNLOAD_GET => -- download new cache block: wait for bus response -- ------------------------------------------------------------ cache.ctrl_en <= '1'; -- cache update operation - if (bus_ack_i = '1') or (bus_err_i = '1') then -- ACK or ERROR = write to cache and get next word (store ERROR flag in cache) + if (bus_rsp_i.ack = '1') or (bus_rsp_i.err = '1') then -- ACK or ERROR = write to cache and get next word (store ERROR flag in cache) cache.ctrl_we <= '1'; -- write to cache if (and_reduce_f(ctrl.addr_reg((cache_offset_size_c+2)-1 downto 2)) = '1') then -- block complete? ctrl.state_nxt <= S_RESYNC; @@ -259,9 +254,6 @@ begin end case; end process ctrl_engine_fsm_comb; - -- cached access? -- - bus_cached_o <= '1' when (ctrl.state = S_DOWNLOAD_REQ) or (ctrl.state = S_DOWNLOAD_GET) else '0'; - -- Cache Memory --------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -278,7 +270,7 @@ begin hit_o => cache.hit, -- host cache access (read-only) -- host_addr_i => cache.host_addr, - host_re_i => host_re_i, + host_re_i => cpu_req_i.re, host_rdata_o => cache.host_rdata, host_rstat_o => cache.host_rstat, -- ctrl cache access (write-only) -- diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 7642a99f1..64010d3c2 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -60,7 +60,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080404"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080405"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width, do not change! @@ -78,44 +78,6 @@ package neorv32_package is -- pragma translate_on ; --- **************************************************************************************************************************** --- Custom Types and Functions --- **************************************************************************************************************************** - - -- Internal Interface Types --------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - type pmp_ctrl_if_t is array (0 to 15) of std_ulogic_vector(07 downto 0); - type pmp_addr_if_t is array (0 to 15) of std_ulogic_vector(33 downto 0); - - -- Internal Memory Types Configuration Types ---------------------------------------------- - -- ------------------------------------------------------------------------------------------- - type mem32_t is array (natural range <>) of std_ulogic_vector(31 downto 0); -- memory with 32-bit entries - type mem8_t is array (natural range <>) of std_ulogic_vector(07 downto 0); -- memory with 8-bit entries - - -- Helper Functions ----------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - function index_size_f(input : natural) return natural; - function cond_sel_natural_f(cond : boolean; val_t : natural; val_f : natural) return natural; - function cond_sel_int_f(cond : boolean; val_t : integer; val_f : integer) return integer; - function cond_sel_stdulogicvector_f(cond : boolean; val_t : std_ulogic_vector; val_f : std_ulogic_vector) return std_ulogic_vector; - function cond_sel_stdulogic_f(cond : boolean; val_t : std_ulogic; val_f : std_ulogic) return std_ulogic; - function cond_sel_string_f(cond : boolean; val_t : string; val_f : string) return string; - function bool_to_ulogic_f(cond : boolean) return std_ulogic; - function bin_to_gray_f(input : std_ulogic_vector) return std_ulogic_vector; - function gray_to_bin_f(input : std_ulogic_vector) return std_ulogic_vector; - function or_reduce_f(a : std_ulogic_vector) return std_ulogic; - function and_reduce_f(a : std_ulogic_vector) return std_ulogic; - function xor_reduce_f(a : std_ulogic_vector) return std_ulogic; - function to_hexchar_f(input : std_ulogic_vector(3 downto 0)) return character; - function to_hstring32_f(input : std_ulogic_vector(31 downto 0)) return string; - function hexchar_to_stdulogicvector_f(input : character) return std_ulogic_vector; - function bit_rev_f(input : std_ulogic_vector) return std_ulogic_vector; - function is_power_of_two_f(input : natural) return boolean; - function bswap32_f(input : std_ulogic_vector) return std_ulogic_vector; - function popcount_f(input : std_ulogic_vector) return natural; - function leading_zeros_f(input : std_ulogic_vector) return natural; - impure function mem32_init_f(init : mem32_t; depth : natural) return mem32_t; - -- **************************************************************************************************************************** -- Processor Address Space Layout -- **************************************************************************************************************************** @@ -342,7 +304,7 @@ package neorv32_package is -- SoC Definitions -- **************************************************************************************************************************** - -- SoC Clock Generator -- + -- SoC Clock Select -- constant clk_div2_c : natural := 0; constant clk_div4_c : natural := 1; constant clk_div8_c : natural := 2; @@ -352,6 +314,38 @@ package neorv32_package is constant clk_div2048_c : natural := 6; constant clk_div4096_c : natural := 7; + -- Internal Memory Types ------------------------------------------------------------------ + -- ------------------------------------------------------------------------------------------- + type mem32_t is array (natural range <>) of std_ulogic_vector(31 downto 0); -- memory with 32-bit entries + type mem8_t is array (natural range <>) of std_ulogic_vector(07 downto 0); -- memory with 8-bit entries + + -- Internal Bus Interface: Request -------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + type bus_req_t is record + addr : std_ulogic_vector(31 downto 0); -- access address + data : std_ulogic_vector(31 downto 0); -- write data + ben : std_ulogic_vector(03 downto 0); -- byte enable + we : std_ulogic; -- write request (single-shot) + re : std_ulogic; -- read request (single-shot) + src : std_ulogic; -- access source (1=instruction fetch, 0=data access) + priv : std_ulogic; -- set if privileged (machine-mode) access + end record; + + -- Internal Bus Interface: Response ------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + type bus_rsp_t is record + data : std_ulogic_vector(31 downto 0); -- read data + ack : std_ulogic; -- access acknowledge (single-shot) + err : std_ulogic; -- access error (single-shot) + end record; + + -- endpoint termination -- + constant rsp_terminate_c : bus_rsp_t := ( + data => (others => '0'), + ack => '0', + err => '0' + ); + -- **************************************************************************************************************************** -- RISC-V ISA Definitions -- **************************************************************************************************************************** @@ -864,6 +858,11 @@ package neorv32_package is cpu_debug => '0' ); + -- PMP Interface -------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + type pmp_ctrl_if_t is array (0 to 15) of std_ulogic_vector(07 downto 0); + type pmp_addr_if_t is array (0 to 15) of std_ulogic_vector(33 downto 0); + -- Comparator Bus ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- constant cmp_equal_c : natural := 0; @@ -1009,6 +1008,32 @@ package neorv32_package is -- constant hpmcnt_event_size_c : natural := 15; -- length of this list +-- **************************************************************************************************************************** +-- Helper Functions +-- **************************************************************************************************************************** + + function index_size_f(input : natural) return natural; + function cond_sel_natural_f(cond : boolean; val_t : natural; val_f : natural) return natural; + function cond_sel_int_f(cond : boolean; val_t : integer; val_f : integer) return integer; + function cond_sel_stdulogicvector_f(cond : boolean; val_t : std_ulogic_vector; val_f : std_ulogic_vector) return std_ulogic_vector; + function cond_sel_stdulogic_f(cond : boolean; val_t : std_ulogic; val_f : std_ulogic) return std_ulogic; + function cond_sel_string_f(cond : boolean; val_t : string; val_f : string) return string; + function bool_to_ulogic_f(cond : boolean) return std_ulogic; + function bin_to_gray_f(input : std_ulogic_vector) return std_ulogic_vector; + function gray_to_bin_f(input : std_ulogic_vector) return std_ulogic_vector; + function or_reduce_f(a : std_ulogic_vector) return std_ulogic; + function and_reduce_f(a : std_ulogic_vector) return std_ulogic; + function xor_reduce_f(a : std_ulogic_vector) return std_ulogic; + function to_hexchar_f(input : std_ulogic_vector(3 downto 0)) return character; + function to_hstring32_f(input : std_ulogic_vector(31 downto 0)) return string; + function hexchar_to_stdulogicvector_f(input : character) return std_ulogic_vector; + function bit_rev_f(input : std_ulogic_vector) return std_ulogic_vector; + function is_power_of_two_f(input : natural) return boolean; + function bswap32_f(input : std_ulogic_vector) return std_ulogic_vector; + function popcount_f(input : std_ulogic_vector) return natural; + function leading_zeros_f(input : std_ulogic_vector) return natural; + impure function mem32_init_f(init : mem32_t; depth : natural) return mem32_t; + -- **************************************************************************************************************************** -- Entity Definitions -- **************************************************************************************************************************** @@ -1217,35 +1242,24 @@ package neorv32_package is ); 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 + 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 + ifence_o : out std_ulogic; -- instruction fence + dfence_o : out std_ulogic; -- data fence + -- interrupts -- + msi_i : in std_ulogic; -- risc-v machine software interrupt + mei_i : in std_ulogic; -- risc-v machine external interrupt + mti_i : in std_ulogic; -- risc-v machine timer interrupt + firq_i : in std_ulogic_vector(15 downto 0); -- custom fast interrupts + dbi_i : in std_ulogic; -- risc-v debug halt request interrupt -- instruction bus interface -- - i_bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - i_bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - i_bus_re_o : out std_ulogic; -- read 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; -- current effective privilege level + ibus_req_o : out bus_req_t; -- request bus + ibus_rsp_i : in bus_rsp_t; -- response bus -- data bus interface -- - d_bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - d_bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - d_bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - d_bus_ben_o : out std_ulogic_vector(3 downto 0); -- byte enable - d_bus_we_o : out std_ulogic; -- write request - d_bus_re_o : out std_ulogic; -- read 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; -- current effective privilege level - -- interrupts -- - msi_i : in std_ulogic; -- risc-v: machine software interrupt - mei_i : in std_ulogic; -- risc-v: machine external interrupt - mti_i : in std_ulogic; -- risc-v: machine timer interrupt - firq_i : in std_ulogic_vector(15 downto 0); -- custom: fast interrupts - db_halt_req_i : in std_ulogic -- risc-v: halt request (debug mode) + dbus_req_o : out bus_req_t; -- request bus + dbus_rsp_i : in bus_rsp_t -- response bus ); end component; @@ -1555,9 +1569,7 @@ package neorv32_package is d_bus_we_o : out std_ulogic; -- write enable d_bus_re_o : out std_ulogic; -- read enable 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; -- fence operation - d_bus_priv_o : out std_ulogic -- current effective privilege level + d_bus_err_i : in std_ulogic -- bus transfer error ); end component; @@ -1565,25 +1577,16 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_bus_keeper is port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic; -- transfer error - -- bus monitoring -- - bus_addr_i : in std_ulogic_vector(31 downto 0); -- address - bus_rden_i : in std_ulogic; -- read enable - bus_wren_i : in std_ulogic; -- write enable - bus_ack_i : in std_ulogic; -- transfer acknowledge from bus system - bus_err_i : in std_ulogic; -- transfer error from bus system - bus_tmo_i : in std_ulogic; -- transfer timeout (external interface) - bus_ext_i : in std_ulogic; -- external bus access - bus_xip_i : in std_ulogic -- pending XIP access + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset, low-active, async + cpu_req_i : in bus_req_t; -- control request bus + cpu_rsp_o : out bus_rsp_t; -- control response bus + bus_req_i : in bus_req_t; -- monitor request bus + bus_rsp_i : in bus_rsp_t; -- monitor response bus + bus_err_o : out std_ulogic; -- signal bus error to CPU + bus_tmo_i : in std_ulogic; -- transfer timeout (external interface) + bus_ext_i : in std_ulogic; -- external bus access + bus_xip_i : in std_ulogic -- pending XIP access ); end component; @@ -1596,23 +1599,13 @@ package neorv32_package is ICACHE_NUM_SETS : natural -- associativity / number of sets (1=direct_mapped), has to be a power of 2 ); port ( - -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - clear_i : in std_ulogic; -- cache clear - -- host controller interface -- - host_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - host_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - host_re_i : in std_ulogic; -- read enable - host_ack_o : out std_ulogic; -- bus transfer acknowledge - host_err_o : out std_ulogic; -- bus transfer error - -- peripheral bus interface -- - bus_cached_o : out std_ulogic; -- set if cached (!) access in progress - bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - bus_re_o : out std_ulogic; -- read enable - bus_ack_i : in std_ulogic; -- bus transfer acknowledge - bus_err_i : in std_ulogic -- bus transfer error + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + clear_i : in std_ulogic; -- cache clear + cpu_req_i : in bus_req_t; -- request bus + cpu_rsp_o : out bus_rsp_t; -- response bus + bus_req_o : out bus_req_t; -- request bus + bus_rsp_i : in bus_rsp_t -- response bus ); end component; @@ -1625,29 +1618,13 @@ package neorv32_package is DCACHE_UC_PBEGIN : std_ulogic_vector(3 downto 0) -- begin of uncached address space (page number) ); port ( - -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - clear_i : in std_ulogic; -- cache clear - -- host controller interface -- - host_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - host_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - host_wdata_i : in std_ulogic_vector(31 downto 0); -- bus write data - host_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable - host_we_i : in std_ulogic; -- write enable - host_re_i : in std_ulogic; -- read enable - host_ack_o : out std_ulogic; -- bus transfer acknowledge - host_err_o : out std_ulogic; -- bus transfer error - -- peripheral bus interface -- - bus_cached_o : out std_ulogic; -- set if cached (!) access in progress - bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - bus_we_o : out std_ulogic; -- write enable - bus_re_o : out std_ulogic; -- read enable - bus_ack_i : in std_ulogic; -- bus transfer acknowledge - bus_err_i : in std_ulogic -- bus transfer error + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + clear_i : in std_ulogic; -- cache clear + cpu_req_i : in bus_req_t; -- request bus + cpu_rsp_o : out bus_rsp_t; -- response bus + bus_req_o : out bus_req_t; -- request bus + bus_rsp_i : in bus_rsp_t -- response bus ); end component; @@ -1655,49 +1632,19 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_busswitch generic ( - PORT_CA_READ_ONLY : boolean; -- set if controller port A is read-only - PORT_CB_READ_ONLY : boolean -- set if controller port B is read-only + PORT_A_READ_ONLY : boolean; -- set if port A is read-only + PORT_B_READ_ONLY : boolean -- set if port B is read-only ); port ( -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - -- controller interface a -- - ca_bus_priv_i : in std_ulogic; -- current privilege level - ca_bus_cached_i : in std_ulogic; -- set if cached transfer - ca_bus_src_i : in std_ulogic; -- access source - ca_bus_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - ca_bus_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - ca_bus_wdata_i : in std_ulogic_vector(31 downto 0); -- bus write data - ca_bus_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable - ca_bus_we_i : in std_ulogic; -- write enable - ca_bus_re_i : in std_ulogic; -- read enable - ca_bus_ack_o : out std_ulogic; -- bus transfer acknowledge - ca_bus_err_o : out std_ulogic; -- bus transfer error - -- controller interface b -- - cb_bus_priv_i : in std_ulogic; -- current privilege level - cb_bus_cached_i : in std_ulogic; -- set if cached transfer - cb_bus_src_i : in std_ulogic; -- access source - cb_bus_addr_i : in std_ulogic_vector(31 downto 0); -- bus access address - cb_bus_rdata_o : out std_ulogic_vector(31 downto 0); -- bus read data - cb_bus_wdata_i : in std_ulogic_vector(31 downto 0); -- bus write data - cb_bus_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable - cb_bus_we_i : in std_ulogic; -- write enable - cb_bus_re_i : in std_ulogic; -- read enable - cb_bus_ack_o : out std_ulogic; -- bus transfer acknowledge - cb_bus_err_o : out std_ulogic; -- bus transfer error - -- peripheral bus -- - p_bus_priv_o : out std_ulogic; -- current privilege level - p_bus_cached_o : out std_ulogic; -- set if cached transfer - p_bus_src_o : out std_ulogic; -- access source: 0 = A, 1 = B - p_bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - p_bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - p_bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - p_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - p_bus_we_o : out std_ulogic; -- write enable - p_bus_re_o : out std_ulogic; -- read enable - p_bus_ack_i : in std_ulogic; -- bus transfer acknowledge - p_bus_err_i : in std_ulogic -- bus transfer error + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + a_req_i : in bus_req_t; -- host port A: request bus + a_rsp_o : out bus_rsp_t; -- host port A: response bus + b_req_i : in bus_req_t; -- host port B: request bus + b_rsp_o : out bus_rsp_t; -- host port B: response bus + x_req_o : out bus_req_t; -- device port request bus + x_rsp_i : in bus_rsp_t -- device port response bus ); end component; @@ -1722,15 +1669,9 @@ package neorv32_package is IMEM_AS_IROM : boolean -- implement IMEM as pre-initialized read-only memory? ); port ( - clk_i : in std_ulogic; -- global clock line - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - addr_i : in std_ulogic_vector(31 downto 0); -- address - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic -- transfer error + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end component; @@ -1742,14 +1683,9 @@ package neorv32_package is DMEM_SIZE : natural -- processor-internal instruction memory size in bytes ); port ( - clk_i : in std_ulogic; -- global clock line - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - addr_i : in std_ulogic_vector(31 downto 0); -- address - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic -- transfer acknowledge + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end component; @@ -1760,31 +1696,21 @@ package neorv32_package is BOOTROM_BASE : std_ulogic_vector(31 downto 0) -- boot ROM base address ); port ( - clk_i : in std_ulogic; -- global clock line - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - addr_i : in std_ulogic_vector(31 downto 0); -- address - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic -- transfer error + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end component; - -- Component: Machine System Timer (mtime) ------------------------------------------------ + -- Component: Machine System Timer (MTIME) ------------------------------------------------ -- ------------------------------------------------------------------------------------------- component neorv32_mtime port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- interrupt -- - irq_o : out std_ulogic -- interrupt request + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + irq_o : out std_ulogic -- interrupt request ); end component; @@ -1795,18 +1721,12 @@ package neorv32_package is GPIO_NUM : natural -- number of GPIO input/output pairs (0..64) ); port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- parallel io -- - gpio_o : out std_ulogic_vector(63 downto 0); - gpio_i : in std_ulogic_vector(63 downto 0) + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + gpio_o : out std_ulogic_vector(63 downto 0); -- parallel output + gpio_i : in std_ulogic_vector(63 downto 0) -- parallel input ); end component; @@ -1814,23 +1734,15 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_wdt port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_ext_i : in std_ulogic; -- external reset line, low-active, async rstn_int_i : in std_ulogic; -- internal reset line, low-active, async - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - addr_i : in std_ulogic_vector(31 downto 0); -- address - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- CPU status -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response cpu_debug_i : in std_ulogic; -- CPU is in debug mode cpu_sleep_i : in std_ulogic; -- CPU is in sleep mode - -- clock generator -- clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- timeout event -- + clkgen_i : in std_ulogic_vector(7 downto 0); irq_o : out std_ulogic; -- timeout IRQ rstn_o : out std_ulogic -- timeout reset, low_active, sync ); @@ -1845,27 +1757,18 @@ package neorv32_package is UART_TX_FIFO : natural -- TX fifo depth, has to be a power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines -- - uart_txd_o : out std_ulogic; - uart_rxd_i : in std_ulogic; - -- hardware flow control -- + clkgen_i : in std_ulogic_vector(7 downto 0); + uart_txd_o : out std_ulogic; -- serial TX line + uart_rxd_i : in std_ulogic; -- serial RX line uart_rts_o : out std_ulogic; -- UART.RX ready to receive ("RTR"), low-active, optional uart_cts_i : in std_ulogic; -- UART.TX allowed to transmit, low-active, optional - -- interrupts -- - irq_rx_o : out std_ulogic; -- rx interrupt - irq_tx_o : out std_ulogic -- tx interrupt + irq_rx_o : out std_ulogic; -- RX interrupt + irq_tx_o : out std_ulogic -- TX interrupt ); end component; @@ -1876,24 +1779,16 @@ package neorv32_package is IO_SPI_FIFO : natural -- SPI RTX fifo depth, has to be power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines -- + clkgen_i : in std_ulogic_vector(7 downto 0); spi_clk_o : out std_ulogic; -- SPI serial clock spi_dat_o : out std_ulogic; -- controller data out, peripheral data in spi_dat_i : in std_ulogic; -- controller data in, peripheral data out - spi_csn_o : out std_ulogic_vector(07 downto 0); -- SPI CS - -- interrupt -- + spi_csn_o : out std_ulogic_vector(7 downto 0); -- SPI CS irq_o : out std_ulogic -- transmission done interrupt ); end component; @@ -1902,24 +1797,16 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_twi port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines (require external tri-state drivers) -- + clkgen_i : in std_ulogic_vector(7 downto 0); twi_sda_i : in std_ulogic; -- serial data line input twi_sda_o : out std_ulogic; -- serial data line output twi_scl_i : in std_ulogic; -- serial clock line input twi_scl_o : out std_ulogic; -- serial clock line output - -- interrupt -- irq_o : out std_ulogic -- transfer done IRQ ); end component; @@ -1931,20 +1818,13 @@ package neorv32_package is NUM_CHANNELS : natural -- number of PWM channels (0..12) ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(07 downto 0); - -- pwm output channels -- - pwm_o : out std_ulogic_vector(11 downto 0) + pwm_o : out std_ulogic_vector(11 downto 0) -- PWM output ); end component; @@ -1955,15 +1835,10 @@ package neorv32_package is IO_TRNG_FIFO : natural := 1 -- RND fifo depth, has to be a power of two, min 1 ); port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic -- transfer acknowledge + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end component; @@ -1985,26 +1860,15 @@ package neorv32_package is ASYNC_TX : boolean -- use register buffer for TX data when false ); port ( - -- global control -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - -- host access -- - src_i : in std_ulogic; -- access type (0: data, 1:instruction) - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic; -- transfer error + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response tmo_o : out std_ulogic; -- transfer timeout - priv_i : in std_ulogic; -- current CPU privilege level ext_o : out std_ulogic; -- active external access - -- xip configuration -- xip_en_i : in std_ulogic; -- XIP module enabled xip_page_i : in std_ulogic_vector(03 downto 0); -- XIP memory page - -- wishbone interface -- + -- wb_tag_o : out std_ulogic_vector(02 downto 0); -- request tag wb_adr_o : out std_ulogic_vector(31 downto 0); -- address wb_dat_i : in std_ulogic_vector(31 downto 0); -- read data @@ -2027,23 +1891,13 @@ package neorv32_package is CFS_OUT_SIZE : natural -- size of CFS output conduit in bits ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, use as async - priv_i : in std_ulogic; -- current CPU privilege mode - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- word write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic; -- transfer error - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); -- "clock" inputs - -- interrupt -- + clkgen_i : in std_ulogic_vector(7 downto 0); -- "clock" inputs irq_o : out std_ulogic; -- interrupt request - -- custom io (conduit) -- cfs_in_i : in std_ulogic_vector(CFS_IN_SIZE-1 downto 0); -- custom inputs cfs_out_o : out std_ulogic_vector(CFS_OUT_SIZE-1 downto 0) -- custom outputs ); @@ -2056,21 +1910,13 @@ package neorv32_package is FIFO_DEPTH : natural -- NEOLED FIFO depth, has to be a power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- interrupt -- + clkgen_i : in std_ulogic_vector(7 downto 0); irq_o : out std_ulogic; -- interrupt request - -- NEOLED output -- neoled_o : out std_ulogic -- serial async data line ); end component; @@ -2084,19 +1930,12 @@ package neorv32_package is XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- external interrupt lines -- - xirq_i : in std_ulogic_vector(31 downto 0); - -- CPU interrupt -- - cpu_irq_o : out std_ulogic + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + xirq_i : in std_ulogic_vector(31 downto 0); -- external IRQ channels + cpu_irq_o : out std_ulogic -- CPU interrupt ); end component; @@ -2104,19 +1943,12 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_gptmr port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- interrupt -- + clkgen_i : in std_ulogic_vector(7 downto 0); irq_o : out std_ulogic -- timer match interrupt ); end component; @@ -2125,31 +1957,17 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_xip port ( - -- globals -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - -- host access: control register access port -- - ct_addr_i : in std_ulogic_vector(31 downto 0); -- address - ct_rden_i : in std_ulogic; -- read enable - ct_wren_i : in std_ulogic; -- write enable - ct_data_i : in std_ulogic_vector(31 downto 0); -- data in - ct_data_o : out std_ulogic_vector(31 downto 0); -- data out - ct_ack_o : out std_ulogic; -- transfer acknowledge - -- host access: transparent SPI access port (read-only) -- - acc_addr_i : in std_ulogic_vector(31 downto 0); -- address - acc_rden_i : in std_ulogic; -- read enable - acc_wren_i : in std_ulogic; -- write enable - acc_data_o : out std_ulogic_vector(31 downto 0); -- data out - acc_ack_o : out std_ulogic; -- transfer acknowledge - acc_err_o : out std_ulogic; -- transfer error - -- status -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + xip_req_i : in bus_req_t; -- XIP request + xip_rsp_o : out bus_rsp_t; -- XIP response xip_en_o : out std_ulogic; -- XIP enable xip_acc_o : out std_ulogic; -- pending XIP access - xip_page_o : out std_ulogic_vector(03 downto 0); -- XIP page - -- clock generator -- + xip_page_o : out std_ulogic_vector(3 downto 0); -- XIP page clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- SPI device interface -- + clkgen_i : in std_ulogic_vector(7 downto 0); spi_csn_o : out std_ulogic; -- chip-select, low-active spi_clk_o : out std_ulogic; -- serial clock spi_dat_i : in std_ulogic; -- device data output @@ -2161,22 +1979,14 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_onewire port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- clock generator -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response clkgen_en_o : out std_ulogic; -- enable clock generator - clkgen_i : in std_ulogic_vector(07 downto 0); - -- com lines (require external tri-state drivers) -- + clkgen_i : in std_ulogic_vector(7 downto 0); onewire_i : in std_ulogic; -- 1-wire line state onewire_o : out std_ulogic; -- 1-wire line pull-down - -- interrupt -- irq_o : out std_ulogic -- transfer done IRQ ); end component; @@ -2188,22 +1998,15 @@ package neorv32_package is RTX_FIFO : natural -- RTX fifo depth, has to be a power of two, min 1 ); port ( - -- host access -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active, async - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- SDI receiver input -- + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response sdi_csn_i : in std_ulogic; -- low-active chip-select sdi_clk_i : in std_ulogic; -- serial clock sdi_dat_i : in std_ulogic; -- serial data input sdi_dat_o : out std_ulogic; -- serial data output - -- interrupts -- - irq_o : out std_ulogic + irq_o : out std_ulogic -- CPU interrupt ); end component; @@ -2211,30 +2014,13 @@ package neorv32_package is -- ------------------------------------------------------------------------------------------- component neorv32_dma port ( - -- global control -- - clk_i : in std_ulogic; -- global clock line - rstn_i : in std_ulogic; -- global reset line, low-active, async - -- peripheral port: configuration and status -- - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_i : in std_ulogic_vector(31 downto 0); -- data in - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - -- host port: bus access -- - bus_bus_priv_o : out std_ulogic; -- current privilege level - bus_cached_o : out std_ulogic; -- set if cached (!) access in progress - bus_src_o : out std_ulogic; -- access source - bus_addr_o : out std_ulogic_vector(31 downto 0); -- bus access address - bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - bus_wdata_o : out std_ulogic_vector(31 downto 0); -- bus write data - bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable - bus_we_o : out std_ulogic; -- write enable - bus_re_o : out std_ulogic; -- read enable - bus_ack_i : in std_ulogic; -- bus transfer acknowledge - bus_err_i : in std_ulogic; -- bus transfer error - -- interrupt -- - irq_o : out std_ulogic + clk_i : in std_ulogic; -- global clock line + rstn_i : in std_ulogic; -- global reset line, low-active, async + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response + dma_req_o : out bus_req_t; -- DMA request + dma_rsp_i : in bus_rsp_t; -- DMA response + irq_o : out std_ulogic -- transfer done interrupt ); end component; @@ -2288,14 +2074,9 @@ package neorv32_package is IO_DMA_EN : boolean -- implement direct memory access controller (DMA)? ); port ( - -- host access -- - clk_i : in std_ulogic; -- global clock line - addr_i : in std_ulogic_vector(31 downto 0); -- address - rden_i : in std_ulogic; -- read enable - wren_i : in std_ulogic; -- write enable - data_o : out std_ulogic_vector(31 downto 0); -- data out - ack_o : out std_ulogic; -- transfer acknowledge - err_o : out std_ulogic -- transfer error + clk_i : in std_ulogic; -- global clock line + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t -- bus response ); end component; @@ -2332,6 +2113,7 @@ package neorv32_package is -- global control -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active + cpu_debug_i : in std_ulogic; -- CPU is in debug mode -- debug module interface (DMI) -- dmi_req_valid_i : in std_ulogic; dmi_req_ready_o : out std_ulogic; -- DMI is allowed to make new requests when set @@ -2343,14 +2125,8 @@ package neorv32_package is dmi_rsp_data_o : out std_ulogic_vector(31 downto 0); dmi_rsp_op_o : out std_ulogic_vector(01 downto 0); -- CPU bus access -- - cpu_debug_i : in std_ulogic; -- CPU is in debug mode - cpu_addr_i : in std_ulogic_vector(31 downto 0); -- address - cpu_rden_i : in std_ulogic; -- read enable - cpu_wren_i : in std_ulogic; -- write enable - cpu_ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable - cpu_data_i : in std_ulogic_vector(31 downto 0); -- data in - cpu_data_o : out std_ulogic_vector(31 downto 0); -- data out - cpu_ack_o : out std_ulogic; -- transfer acknowledge + bus_req_i : in bus_req_t; -- bus request + bus_rsp_o : out bus_rsp_t; -- bus response -- CPU control -- cpu_ndmrstn_o : out std_ulogic; -- soc reset cpu_halt_req_o : out std_ulogic -- request hart to halt (enter debug mode) diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index 5ef1a5281..552619526 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -242,11 +242,8 @@ architecture neorv32_top_rtl of neorv32_top is constant cpu_boot_addr_c : std_ulogic_vector(31 downto 0) := cond_sel_stdulogicvector_f(INT_BOOTLOADER_EN, boot_rom_base_c, ispace_base_c); -- reset generator -- - signal rstn_ext_sreg : std_ulogic_vector(3 downto 0); - signal rstn_int_sreg : std_ulogic_vector(3 downto 0); - signal rstn_ext : std_ulogic; - signal rstn_int : std_ulogic; - signal rstn_wdt : std_ulogic; + signal rstn_ext_sreg, rstn_int_sreg : std_ulogic_vector(3 downto 0); + signal rstn_ext, rstn_int, rstn_wdt : std_ulogic; -- clock generator -- signal clk_div : std_ulogic_vector(11 downto 0); @@ -268,35 +265,10 @@ architecture neorv32_top_rtl of neorv32_top is signal onewire_cg_en : std_ulogic; -- CPU status -- - type cpu_status_t is record - debug : std_ulogic; -- set when in debug mode - sleep : std_ulogic; -- set when in sleep mode - end record; - signal cpu_s : cpu_status_t; - - -- bus interface -- - type bus_interface_t is record - addr : std_ulogic_vector(31 downto 0); -- bus access address - rdata : std_ulogic_vector(31 downto 0); -- bus read data - wdata : std_ulogic_vector(31 downto 0); -- bus write data - ben : std_ulogic_vector(03 downto 0); -- byte enable - we : std_ulogic; -- write request - re : std_ulogic; -- read request - ack : std_ulogic; -- bus transfer acknowledge - err : std_ulogic; -- bus transfer error - src : std_ulogic; -- access source (1=instruction fetch, 0=data access) - cached : std_ulogic; -- cached transfer - priv : std_ulogic; -- set when in privileged machine mode - end record; - signal cpu_i, cpu_d, i_cache, d_cache, core_bus, dma_bus, p_bus : bus_interface_t; - signal d_fence, i_fence : std_ulogic; - - -- bus access error (from BUSKEEPER) -- - signal bus_error : std_ulogic; - - -- debug core interface (DCI) -- - signal dci_ndmrstn : std_ulogic; - signal dci_halt_req : std_ulogic; + signal cpu_debug : std_ulogic; -- cpu is in debug mode + signal cpu_sleep : std_ulogic; -- cpu is in sleep mode + signal i_fence : std_ulogic; -- instruction fence + signal d_fence : std_ulogic; -- data fence -- debug module interface (DMI) -- type dmi_t is record @@ -312,30 +284,34 @@ architecture neorv32_top_rtl of neorv32_top is end record; signal dmi : dmi_t; - -- IO space access -- - signal io_acc : std_ulogic; - signal io_rden : std_ulogic; - signal io_wren : std_ulogic; - - -- module response bus - entry type -- - type resp_bus_entry_t is record - rdata : std_ulogic_vector(31 downto 0); - ack : std_ulogic; - err : std_ulogic; - end record; - - -- module response bus - termination for unused bus endpoints -- - constant resp_bus_entry_terminate_c : resp_bus_entry_t := (rdata => (others => '0'), ack => '0', err => '0'); - - -- module response bus - device ID -- - type resp_bus_id_t is (RESP_BUSKEEPER, RESP_IMEM, RESP_DMEM, RESP_BOOTROM, RESP_WISHBONE, RESP_GPIO, - RESP_MTIME, RESP_UART0, RESP_UART1, RESP_SPI, RESP_TWI, RESP_PWM, RESP_WDT, - RESP_TRNG, RESP_CFS, RESP_NEOLED, RESP_SYSINFO, RESP_OCD, RESP_XIRQ, RESP_GPTMR, - RESP_XIP_CT, RESP_XIP_ACC, RESP_ONEWIRE, RESP_SDI, RESP_DMA); + -- debug core interface (DCI) -- + signal dci_ndmrstn : std_ulogic; + signal dci_halt_req : std_ulogic; - -- module response bus -- - type resp_bus_t is array (resp_bus_id_t) of resp_bus_entry_t; - signal resp_bus : resp_bus_t := (others => resp_bus_entry_terminate_c); + -- internal bus system -- + type device_ids_t is (DEV_BUSKEEPER, DEV_IMEM, DEV_DMEM, DEV_BOOTROM, DEV_WISHBONE, DEV_GPIO, DEV_MTIME, DEV_UART0, + DEV_UART1, DEV_SPI, DEV_TWI, DEV_PWM, DEV_WDT, DEV_TRNG, DEV_CFS, DEV_NEOLED, DEV_SYSINFO, + DEV_OCD, DEV_XIRQ, DEV_GPTMR, DEV_XIP_CT, DEV_XIP_ACC, DEV_ONEWIRE, DEV_SDI, DEV_DMA); + + -- core complex -- + signal cpu_i_req, cpu_d_req : bus_req_t; -- CPU core + signal cpu_i_rsp, cpu_d_rsp : bus_rsp_t; -- CPU core + signal icache_req, dcache_req : bus_req_t; -- CPU caches + signal icache_rsp, dcache_rsp : bus_rsp_t; -- CPU caches + signal core_req : bus_req_t; -- core complex (CPU + caches) + signal core_rsp : bus_rsp_t; -- core complex (CPU + caches) + + -- core complex + DMA -- + signal main_req, dma_req : bus_req_t; -- core complex (CPU + caches + DMA) + signal main_rsp, dma_rsp : bus_rsp_t; -- core complex (CPU + caches + DMA) + + -- SoC bus -- + type response_bus_t is array (device_ids_t) of bus_rsp_t; + signal soc_req : bus_req_t; -- SoC request bus + signal soc_rsp : bus_rsp_t; -- SoC response bus + signal io_req : bus_req_t; -- request bus for internal IO/Peripheral devices only + signal rsp_bus : response_bus_t; -- global response bus + signal bus_error : std_ulogic; -- global bus error -- IRQs -- signal fast_irq : std_ulogic_vector(15 downto 0); @@ -356,6 +332,7 @@ architecture neorv32_top_rtl of neorv32_top is signal dma_irq : std_ulogic; -- misc -- + signal io_acc : std_ulogic; signal ext_timeout : std_ulogic; signal ext_access : std_ulogic; signal xip_access : std_ulogic; @@ -364,7 +341,7 @@ architecture neorv32_top_rtl of neorv32_top is begin - -- Processor IO/Peripherals Configuration ------------------------------------------------- + -- Sanity Checks -------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- assert false report "NEORV32 PROCESSOR CONFIGURATION: " & @@ -396,9 +373,6 @@ begin "" severity note; - - -- Sanity Checks -------------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- -- boot configuration -- assert not (INT_BOOTLOADER_EN = true) report "NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Indirect boot via bootloader (processor-internal BOOTROM)." severity note; @@ -423,7 +397,7 @@ begin -- **************************************************************************************************************************** --- Clock and Reset System +-- Clock and Reset -- **************************************************************************************************************************** -- Reset Generator ------------------------------------------------------------------------ @@ -495,7 +469,7 @@ begin -- **************************************************************************************************************************** --- CPU Core Complex +-- Core Complex -- **************************************************************************************************************************** -- CPU Core ------------------------------------------------------------------------------- @@ -503,100 +477,80 @@ begin neorv32_cpu_inst: neorv32_cpu generic map ( -- General -- - HART_ID => HART_ID, -- hardware thread ID - VENDOR_ID => VENDOR_ID, -- vendor's JEDEC ID - CPU_BOOT_ADDR => cpu_boot_addr_c, -- cpu boot address - CPU_DEBUG_PARK_ADDR => dm_park_entry_c, -- cpu debug mode parking loop entry address - CPU_DEBUG_EXC_ADDR => dm_exc_entry_c, -- cpu debug mode exception entry address + HART_ID => HART_ID, + VENDOR_ID => VENDOR_ID, + CPU_BOOT_ADDR => cpu_boot_addr_c, + CPU_DEBUG_PARK_ADDR => dm_park_entry_c, + CPU_DEBUG_EXC_ADDR => dm_exc_entry_c, -- RISC-V CPU Extensions -- - CPU_EXTENSION_RISCV_B => CPU_EXTENSION_RISCV_B, -- implement bit-manipulation extension? - CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension? - CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension? - CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement mul/div extension? - CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension? - CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT reg!) - CPU_EXTENSION_RISCV_Zicntr => CPU_EXTENSION_RISCV_Zicntr, -- implement base counters? - CPU_EXTENSION_RISCV_Zicond => CPU_EXTENSION_RISCV_Zicond, -- implement conditional operations extension? - CPU_EXTENSION_RISCV_Zihpm => CPU_EXTENSION_RISCV_Zihpm, -- implement hardware performance monitors? - CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.? - CPU_EXTENSION_RISCV_Zmmul => CPU_EXTENSION_RISCV_Zmmul, -- implement multiply-only M sub-extension? - CPU_EXTENSION_RISCV_Zxcfu => CPU_EXTENSION_RISCV_Zxcfu, -- implement custom (instr.) functions unit? - CPU_EXTENSION_RISCV_Sdext => ON_CHIP_DEBUGGER_EN, -- implement external debug mode extension? - CPU_EXTENSION_RISCV_Sdtrig => ON_CHIP_DEBUGGER_EN, -- implement debug mode trigger module extension? + 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_Zicntr => CPU_EXTENSION_RISCV_Zicntr, + CPU_EXTENSION_RISCV_Zicond => CPU_EXTENSION_RISCV_Zicond, + 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_Sdext => ON_CHIP_DEBUGGER_EN, + CPU_EXTENSION_RISCV_Sdtrig => ON_CHIP_DEBUGGER_EN, -- Extension Options -- - FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier - FAST_SHIFT_EN => FAST_SHIFT_EN, -- use barrel shifter for shift operations - CPU_IPB_ENTRIES => CPU_IPB_ENTRIES, -- entries is instruction prefetch buffer, has to be a power of 1 + FAST_MUL_EN => FAST_MUL_EN, + FAST_SHIFT_EN => FAST_SHIFT_EN, + CPU_IPB_ENTRIES => CPU_IPB_ENTRIES, -- Physical Memory Protection (PMP) -- - PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..16) - PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes + PMP_NUM_REGIONS => PMP_NUM_REGIONS, + PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29) - HPM_CNT_WIDTH => HPM_CNT_WIDTH -- total size of HPM counters (0..64) + HPM_NUM_CNTS => HPM_NUM_CNTS, + HPM_CNT_WIDTH => HPM_CNT_WIDTH ) port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_int, -- global reset, low-active, async - sleep_o => cpu_s.sleep, -- cpu is in sleep mode when set - debug_o => cpu_s.debug, -- cpu is in debug mode when set + clk_i => clk_i, + rstn_i => rstn_int, + sleep_o => cpu_sleep, + debug_o => cpu_debug, + ifence_o => i_fence, + dfence_o => d_fence, + -- interrupts -- + msi_i => msw_irq_i, + mei_i => mext_irq_i, + mti_i => mtime_irq, + firq_i => fast_irq, + dbi_i => dci_halt_req, -- instruction bus interface -- - i_bus_addr_o => cpu_i.addr, -- bus access address - i_bus_rdata_i => cpu_i.rdata, -- bus read data - i_bus_re_o => cpu_i.re, -- read request - i_bus_ack_i => cpu_i.ack, -- bus transfer acknowledge - i_bus_err_i => cpu_i.err, -- bus transfer error - i_bus_fence_o => i_fence, -- executed FENCEI operation - i_bus_priv_o => cpu_i.priv, -- current effective privilege level + ibus_req_o => cpu_i_req, + ibus_rsp_i => cpu_i_rsp, -- data bus interface -- - d_bus_addr_o => cpu_d.addr, -- bus access address - d_bus_rdata_i => cpu_d.rdata, -- bus read data - d_bus_wdata_o => cpu_d.wdata, -- bus write data - d_bus_ben_o => cpu_d.ben, -- byte enable - d_bus_we_o => cpu_d.we, -- write request - d_bus_re_o => cpu_d.re, -- read request - d_bus_ack_i => cpu_d.ack, -- bus transfer acknowledge - d_bus_err_i => cpu_d.err, -- bus transfer error - d_bus_fence_o => d_fence, -- executed FENCE operation - d_bus_priv_o => cpu_d.priv, -- current effective privilege level - -- interrupts -- - msi_i => msw_irq_i, -- risc-v: machine software interrupt - mei_i => mext_irq_i, -- risc-v: machine external interrupt - mti_i => mtime_irq, -- risc-v: machine timer interrupt - firq_i => fast_irq, -- custom: fast interrupts - db_halt_req_i => dci_halt_req -- risc-v: halt request (debug mode) + dbus_req_o => cpu_d_req, + dbus_rsp_i => cpu_d_rsp ); - -- initialized but unused -- - cpu_i.wdata <= (others => '0'); - cpu_i.ben <= (others => '0'); - cpu_i.we <= '0'; -- read-only - cpu_i.src <= '1'; -- 1 = instruction fetch - cpu_i.cached <= '0'; - cpu_d.src <= '0'; -- 0 = data access - cpu_d.cached <= '0'; - -- advanced memory control -- - fence_o <= d_fence; -- indicates an executed FENCE operation - fencei_o <= i_fence; -- indicates an executed FENCE.I operation - - -- fast interrupt requests (FIRQs) - triggers are SINGLE-SHOT -- - fast_irq(00) <= wdt_irq; -- HIGHEST PRIORITY - watchdog - fast_irq(01) <= cfs_irq; -- custom functions subsystem - fast_irq(02) <= uart0_rx_irq; -- primary UART (UART0) RX - fast_irq(03) <= uart0_tx_irq; -- primary UART (UART0) TX - fast_irq(04) <= uart1_rx_irq; -- secondary UART (UART1) RX - fast_irq(05) <= uart1_tx_irq; -- secondary UART (UART1) TX - fast_irq(06) <= spi_irq; -- SPI interrupt - fast_irq(07) <= twi_irq; -- TWI transfer done - fast_irq(08) <= xirq_irq; -- external interrupt controller - fast_irq(09) <= neoled_irq; -- NEOLED buffer IRQ - fast_irq(10) <= dma_irq; -- DMA controller - fast_irq(11) <= sdi_irq; -- SDI interrupt - fast_irq(12) <= gptmr_irq; -- general purpose timer match - fast_irq(13) <= onewire_irq; -- ONEWIRE operation done - fast_irq(14) <= '0'; -- reserved - fast_irq(15) <= '0'; -- LOWEST PRIORITY - reserved + fence_o <= d_fence; + fencei_o <= i_fence; + + -- fast interrupt requests (FIRQs) -- + fast_irq(00) <= wdt_irq; -- highest priority + fast_irq(01) <= cfs_irq; + fast_irq(02) <= uart0_rx_irq; + fast_irq(03) <= uart0_tx_irq; + fast_irq(04) <= uart1_rx_irq; + fast_irq(05) <= uart1_tx_irq; + fast_irq(06) <= spi_irq; + fast_irq(07) <= twi_irq; + fast_irq(08) <= xirq_irq; + fast_irq(09) <= neoled_irq; + fast_irq(10) <= dma_irq; + fast_irq(11) <= sdi_irq; + fast_irq(12) <= gptmr_irq; + fast_irq(13) <= onewire_irq; + fast_irq(14) <= '0'; + fast_irq(15) <= '0'; -- lowest priority -- CPU Instruction Cache ------------------------------------------------------------------ @@ -605,47 +559,27 @@ begin if (ICACHE_EN = true) generate neorv32_icache_inst: neorv32_icache generic map ( - ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- number of blocks (min 2), has to be a power of 2 - ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- block size in bytes (min 4), has to be a power of 2 - ICACHE_NUM_SETS => ICACHE_ASSOCIATIVITY -- associativity / number of sets (1=direct_mapped), has to be a power of 2 + ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, + ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, + ICACHE_NUM_SETS => ICACHE_ASSOCIATIVITY ) port map ( - -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_int, -- global reset, low-active, async - clear_i => i_fence, -- cache clear - -- host controller interface -- - host_addr_i => cpu_i.addr, -- bus access address - host_rdata_o => cpu_i.rdata, -- bus read data - host_re_i => cpu_i.re, -- read enable - host_ack_o => cpu_i.ack, -- bus transfer acknowledge - host_err_o => cpu_i.err, -- bus transfer error - -- peripheral bus interface -- - bus_cached_o => i_cache.cached, -- set if cached (!) access in progress - bus_addr_o => i_cache.addr, -- bus access address - bus_rdata_i => i_cache.rdata, -- bus read data - bus_re_o => i_cache.re, -- read enable - bus_ack_i => i_cache.ack, -- bus transfer acknowledge - bus_err_i => i_cache.err -- bus transfer error + clk_i => clk_i, + rstn_i => rstn_int, + clear_i => i_fence, + cpu_req_i => cpu_i_req, + cpu_rsp_o => cpu_i_rsp, + bus_req_o => icache_req, + bus_rsp_i => icache_rsp ); end generate; neorv32_icache_inst_false: if (ICACHE_EN = false) generate - i_cache.cached <= '0'; -- single transfer (uncached) - i_cache.addr <= cpu_i.addr; - cpu_i.rdata <= i_cache.rdata; - i_cache.re <= cpu_i.re; - cpu_i.ack <= i_cache.ack; - cpu_i.err <= i_cache.err; + icache_req <= cpu_i_req; + cpu_i_rsp <= icache_rsp; end generate; - i_cache.wdata <= (others => '0'); - i_cache.ben <= (others => '0'); - i_cache.we <= '0'; - i_cache.priv <= cpu_i.priv; - i_cache.src <= cpu_i.src; - -- CPU Data Cache ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -653,101 +587,44 @@ begin if (DCACHE_EN = true) generate neorv32_dcache_inst: neorv32_dcache generic map ( - DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS, -- number of blocks (min 1), has to be a power of 2 - DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE, -- block size in bytes (min 4), has to be a power of 2 - DCACHE_UC_PBEGIN => "1111" -- begin of uncached address space (page number) + DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS, + DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE, + DCACHE_UC_PBEGIN => "1111" ) port map ( - -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_int, -- global reset, low-active, async - clear_i => d_fence, -- cache clear - -- host controller interface -- - host_addr_i => cpu_d.addr, -- bus access address - host_rdata_o => cpu_d.rdata, -- bus read data - host_wdata_i => cpu_d.wdata, -- bus write data - host_ben_i => cpu_d.ben, -- byte enable - host_we_i => cpu_d.we, -- write enable - host_re_i => cpu_d.re, -- read enable - host_ack_o => cpu_d.ack, -- bus transfer acknowledge - host_err_o => cpu_d.err, -- bus transfer error - -- peripheral bus interface -- - bus_cached_o => d_cache.cached, -- set if cached (!) access in progress - bus_addr_o => d_cache.addr, -- bus access address - bus_rdata_i => d_cache.rdata, -- bus read data - bus_wdata_o => d_cache.wdata, -- bus write data - bus_ben_o => d_cache.ben, -- byte enable - bus_we_o => d_cache.we, -- write enable - bus_re_o => d_cache.re, -- read enable - bus_ack_i => d_cache.ack, -- bus transfer acknowledge - bus_err_i => d_cache.err -- bus transfer error + clk_i => clk_i, + rstn_i => rstn_int, + clear_i => d_fence, + cpu_req_i => cpu_d_req, + cpu_rsp_o => cpu_d_rsp, + bus_req_o => dcache_req, + bus_rsp_i => dcache_rsp ); end generate; neorv32_dcache_inst_false: if (DCACHE_EN = false) generate - d_cache.cached <= '0'; -- single transfer (uncached) - d_cache.addr <= cpu_d.addr; - cpu_d.rdata <= d_cache.rdata; - d_cache.wdata <= cpu_d.wdata; - d_cache.ben <= cpu_d.ben; - d_cache.we <= cpu_d.we; - d_cache.re <= cpu_d.re; - cpu_d.ack <= d_cache.ack; - cpu_d.err <= d_cache.err; + dcache_req <= cpu_d_req; + cpu_d_rsp <= dcache_rsp; end generate; - d_cache.priv <= cpu_d.priv; - d_cache.src <= cpu_d.src; - - -- CPU Bus Switch ------------------------------------------------------------------------- + -- Core Complex Bus Switch ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_core_busswitch_inst: neorv32_busswitch generic map ( - PORT_CA_READ_ONLY => false, -- set if controller port A is read-only - PORT_CB_READ_ONLY => true -- set if controller port B is read-only + PORT_A_READ_ONLY => false, + PORT_B_READ_ONLY => true -- i-fetch is read-only ) port map ( - -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_int, -- global reset, low-active, async - -- controller interface a -- - ca_bus_priv_i => d_cache.priv, -- current privilege level - ca_bus_cached_i => d_cache.cached, -- set if cached transfer - ca_bus_src_i => d_cache.src, -- access source - ca_bus_addr_i => d_cache.addr, -- bus access address - ca_bus_rdata_o => d_cache.rdata, -- bus read data - ca_bus_wdata_i => d_cache.wdata, -- bus write data - ca_bus_ben_i => d_cache.ben, -- byte enable - ca_bus_we_i => d_cache.we, -- write enable - ca_bus_re_i => d_cache.re, -- read enable - ca_bus_ack_o => d_cache.ack, -- bus transfer acknowledge - ca_bus_err_o => d_cache.err, -- bus transfer error - -- controller interface b -- - cb_bus_priv_i => i_cache.priv, -- current privilege level - cb_bus_cached_i => i_cache.cached, -- set if cached transfer - cb_bus_src_i => i_cache.src, -- access source - cb_bus_addr_i => i_cache.addr, -- bus access address - cb_bus_rdata_o => i_cache.rdata, -- bus read data - cb_bus_wdata_i => i_cache.wdata, -- bus write data - cb_bus_ben_i => i_cache.ben, -- byte enable - cb_bus_we_i => i_cache.we, -- write enable - cb_bus_re_i => i_cache.re, -- read enable - cb_bus_ack_o => i_cache.ack, -- bus transfer acknowledge - cb_bus_err_o => i_cache.err, -- bus transfer error - -- peripheral bus -- - p_bus_priv_o => core_bus.priv, -- current privilege level - p_bus_cached_o => core_bus.cached, -- set if cached transfer - p_bus_src_o => core_bus.src, -- access source: 0 = A (data), 1 = B (instructions) - p_bus_addr_o => core_bus.addr, -- bus access address - p_bus_rdata_i => core_bus.rdata, -- bus read data - p_bus_wdata_o => core_bus.wdata, -- bus write data - p_bus_ben_o => core_bus.ben, -- byte enable - p_bus_we_o => core_bus.we, -- write enable - p_bus_re_o => core_bus.re, -- read enable - p_bus_ack_i => core_bus.ack, -- bus transfer acknowledge - p_bus_err_i => core_bus.err -- bus transfer error + clk_i => clk_i, + rstn_i => rstn_int, + a_req_i => dcache_req, + a_rsp_o => dcache_rsp, + b_req_i => icache_req, + b_rsp_o => icache_rsp, + x_req_o => core_req, + x_rsp_i => core_rsp ); @@ -758,102 +635,46 @@ begin -- DMA controller and according bus switch -- neorv32_dma_complex_true: if (IO_DMA_EN = true) generate - -- DMA controller -- + + -- DMA Controller ------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- neorv32_dma_inst: neorv32_dma port map ( - -- global control -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - -- peripheral port: configuration and status -- - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_DMA).rdata, -- data out - ack_o => resp_bus(RESP_DMA).ack, -- transfer acknowledge - -- host port: bus access -- - bus_bus_priv_o => dma_bus.priv, -- current privilege level - bus_cached_o => dma_bus.cached, -- set if cached (!) access in progress - bus_src_o => dma_bus.src, -- access source - bus_addr_o => dma_bus.addr, -- bus access address - bus_rdata_i => dma_bus.rdata, -- bus read data - bus_wdata_o => dma_bus.wdata, -- bus write data - bus_ben_o => dma_bus.ben, -- byte enable - bus_we_o => dma_bus.we, -- write enable - bus_re_o => dma_bus.re, -- read enable - bus_ack_i => dma_bus.ack, -- bus transfer acknowledge - bus_err_i => dma_bus.err, -- bus transfer error - -- interrupt -- - irq_o => dma_irq + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_DMA), + dma_req_o => dma_req, + dma_rsp_i => dma_rsp, + irq_o => dma_irq ); - resp_bus(RESP_DMA).err <= '0'; -- no access error possible - -- bus switch -- + -- DMA Bus Switch ------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- neorv32_dma_busswitch_inst: neorv32_busswitch generic map ( - PORT_CA_READ_ONLY => false, -- set if controller port A is read-only - PORT_CB_READ_ONLY => false -- set if controller port B is read-only + PORT_A_READ_ONLY => false, + PORT_B_READ_ONLY => false ) port map ( - -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_int, -- global reset, low-active, async - -- controller interface a -- - ca_bus_priv_i => core_bus.priv, -- current privilege level - ca_bus_cached_i => core_bus.cached, -- set if cached transfer - ca_bus_src_i => core_bus.src, -- access source - ca_bus_addr_i => core_bus.addr, -- bus access address - ca_bus_rdata_o => core_bus.rdata, -- bus read data - ca_bus_wdata_i => core_bus.wdata, -- bus write data - ca_bus_ben_i => core_bus.ben, -- byte enable - ca_bus_we_i => core_bus.we, -- write enable - ca_bus_re_i => core_bus.re, -- read enable - ca_bus_ack_o => core_bus.ack, -- bus transfer acknowledge - ca_bus_err_o => core_bus.err, -- bus transfer error - -- controller interface b -- - cb_bus_priv_i => dma_bus.priv, -- current privilege level - cb_bus_cached_i => dma_bus.cached, -- set if cached transfer - cb_bus_src_i => dma_bus.src, -- access source - cb_bus_addr_i => dma_bus.addr, -- bus access address - cb_bus_rdata_o => dma_bus.rdata, -- bus read data - cb_bus_wdata_i => dma_bus.wdata, -- bus write data - cb_bus_ben_i => dma_bus.ben, -- byte enable - cb_bus_we_i => dma_bus.we, -- write enable - cb_bus_re_i => dma_bus.re, -- read enable - cb_bus_ack_o => dma_bus.ack, -- bus transfer acknowledge - cb_bus_err_o => dma_bus.err, -- bus transfer error - -- peripheral bus -- - p_bus_priv_o => p_bus.priv, -- current privilege level - p_bus_cached_o => p_bus.cached, -- set if cached transfer - p_bus_src_o => p_bus.src, -- access source: 0 = A (data), 1 = B (instructions) - p_bus_addr_o => p_bus.addr, -- bus access address - p_bus_rdata_i => p_bus.rdata, -- bus read data - p_bus_wdata_o => p_bus.wdata, -- bus write data - p_bus_ben_o => p_bus.ben, -- byte enable - p_bus_we_o => p_bus.we, -- write enable - p_bus_re_o => p_bus.re, -- read enable - p_bus_ack_i => p_bus.ack, -- bus transfer acknowledge - p_bus_err_i => bus_error -- bus transfer error + clk_i => clk_i, + rstn_i => rstn_int, + a_req_i => core_req, + a_rsp_o => core_rsp, + b_req_i => dma_req, + b_rsp_o => dma_rsp, + x_req_o => main_req, + x_rsp_i => main_rsp ); + end generate; - -- route-through -- neorv32_dma_complex_false: if (IO_DMA_EN = false) generate - resp_bus(RESP_DMA) <= resp_bus_entry_terminate_c; - dma_irq <= '0'; - -- - p_bus.priv <= core_bus.priv; - p_bus.cached <= core_bus.cached; - p_bus.src <= core_bus.src; - p_bus.addr <= core_bus.addr; - core_bus.rdata <= p_bus.rdata; - p_bus.wdata <= core_bus.wdata; - p_bus.ben <= core_bus.ben; - p_bus.we <= core_bus.we; - p_bus.re <= core_bus.re; - core_bus.ack <= p_bus.ack; - core_bus.err <= bus_error; + rsp_bus(DEV_DMA) <= rsp_terminate_c; + main_req <= core_req; + core_rsp <= main_rsp; + dma_irq <= '0'; end generate; @@ -861,55 +682,40 @@ begin -- Bus System -- **************************************************************************************************************************** - -- Bus Response --------------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - bus_response: process(resp_bus) - variable rdata_v : std_ulogic_vector(31 downto 0); - variable ack_v : std_ulogic; - variable err_v : std_ulogic; - begin - -- OR all response signals: only the module that has actually been accessed may set its bus output signals - rdata_v := (others => '0'); - ack_v := '0'; - err_v := '0'; - for i in resp_bus'range loop - rdata_v := rdata_v or resp_bus(i).rdata; -- read data - ack_v := ack_v or resp_bus(i).ack; -- acknowledge - err_v := err_v or resp_bus(i).err; -- error - end loop; -- i - p_bus.rdata <= rdata_v; - p_bus.ack <= ack_v; - p_bus.err <= err_v; - end process; - - -- Bus Keeper (BUSKEEPER) ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_bus_keeper_inst: neorv32_bus_keeper port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, use as async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- byte write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_BUSKEEPER).rdata, -- data out - ack_o => resp_bus(RESP_BUSKEEPER).ack, -- transfer acknowledge - err_o => bus_error, -- transfer error - -- bus monitoring -- - bus_addr_i => p_bus.addr, -- address - bus_rden_i => p_bus.re, -- read enable - bus_wren_i => p_bus.we, -- write enable - bus_ack_i => p_bus.ack, -- transfer acknowledge from bus system - bus_err_i => p_bus.err, -- transfer error from bus system - bus_tmo_i => ext_timeout, -- transfer timeout (external interface) - bus_ext_i => ext_access, -- external bus access - bus_xip_i => xip_access -- pending XIP access + clk_i => clk_i, + rstn_i => rstn_int, + cpu_req_i => io_req, + cpu_rsp_o => rsp_bus(DEV_BUSKEEPER), + bus_req_i => soc_req, + bus_rsp_i => soc_rsp, + bus_err_o => bus_error, + bus_tmo_i => ext_timeout, + bus_ext_i => ext_access, + bus_xip_i => xip_access ); - -- unused, BUSKEEPER issues error **directly** to the CPU -- - resp_bus(RESP_BUSKEEPER).err <= '0'; + -- global bus response --- + bus_response: process(rsp_bus) + variable tmp_v : bus_rsp_t; + begin + tmp_v := rsp_terminate_c; + for i in rsp_bus'range loop -- OR all response signals + tmp_v.data := tmp_v.data or rsp_bus(i).data; + tmp_v.ack := tmp_v.ack or rsp_bus(i).ack; + tmp_v.err := tmp_v.err or rsp_bus(i).err; + end loop; + soc_rsp <= tmp_v; + end process; + + -- central SoC bus -- + soc_req <= main_req; + main_rsp.data <= soc_rsp.data; + main_rsp.ack <= soc_rsp.ack; + main_rsp.err <= bus_error; -- global bus error (buskeeper -> core) -- **************************************************************************************************************************** @@ -922,54 +728,41 @@ begin if (MEM_INT_IMEM_EN = true) and (MEM_INT_IMEM_SIZE > 0) generate neorv32_int_imem_inst: neorv32_imem generic map ( - IMEM_BASE => imem_base_c, -- memory base address - IMEM_SIZE => MEM_INT_IMEM_SIZE, -- processor-internal instruction memory size in bytes - IMEM_AS_IROM => not INT_BOOTLOADER_EN -- implement IMEM as pre-initialized read-only memory? + IMEM_BASE => imem_base_c, + IMEM_SIZE => MEM_INT_IMEM_SIZE, + IMEM_AS_IROM => not INT_BOOTLOADER_EN ) port map ( - clk_i => clk_i, -- global clock line - rden_i => p_bus.re, -- read enable - wren_i => p_bus.we, -- write enable - ben_i => p_bus.ben, -- byte write enable - addr_i => p_bus.addr, -- address - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_IMEM).rdata, -- data out - ack_o => resp_bus(RESP_IMEM).ack, -- transfer acknowledge - err_o => resp_bus(RESP_IMEM).err -- transfer error + clk_i => clk_i, + bus_req_i => soc_req, + bus_rsp_o => rsp_bus(DEV_IMEM) ); end generate; neorv32_int_imem_inst_false: if (MEM_INT_IMEM_EN = false) or (MEM_INT_IMEM_SIZE = 0) generate - resp_bus(RESP_IMEM) <= resp_bus_entry_terminate_c; + rsp_bus(DEV_IMEM) <= rsp_terminate_c; end generate; - -- Processor-Internal Data Memory (DMEM) -------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_int_dmem_inst_true: if (MEM_INT_DMEM_EN = true) and (MEM_INT_DMEM_SIZE > 0) generate neorv32_int_dmem_inst: neorv32_dmem generic map ( - DMEM_BASE => dmem_base_c, -- memory base address - DMEM_SIZE => MEM_INT_DMEM_SIZE -- processor-internal data memory size in bytes + DMEM_BASE => dmem_base_c, + DMEM_SIZE => MEM_INT_DMEM_SIZE ) port map ( - clk_i => clk_i, -- global clock line - rden_i => p_bus.re, -- read enable - wren_i => p_bus.we, -- write enable - ben_i => p_bus.ben, -- byte write enable - addr_i => p_bus.addr, -- address - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_DMEM).rdata, -- data out - ack_o => resp_bus(RESP_DMEM).ack -- transfer acknowledge + clk_i => clk_i, + bus_req_i => soc_req, + bus_rsp_o => rsp_bus(DEV_DMEM) ); - resp_bus(RESP_DMEM).err <= '0'; -- no access error possible end generate; neorv32_int_dmem_inst_false: if (MEM_INT_DMEM_EN = false) or (MEM_INT_DMEM_SIZE = 0) generate - resp_bus(RESP_DMEM) <= resp_bus_entry_terminate_c; + rsp_bus(DEV_DMEM) <= rsp_terminate_c; end generate; @@ -979,22 +772,18 @@ begin if (INT_BOOTLOADER_EN = true) generate neorv32_boot_rom_inst: neorv32_boot_rom generic map ( - BOOTROM_BASE => boot_rom_base_c -- boot ROM base address + BOOTROM_BASE => boot_rom_base_c ) port map ( - clk_i => clk_i, -- global clock line - rden_i => p_bus.re, -- read enable - wren_i => p_bus.we, -- write enable - addr_i => p_bus.addr, -- address - data_o => resp_bus(RESP_BOOTROM).rdata, -- data out - ack_o => resp_bus(RESP_BOOTROM).ack, -- transfer acknowledge - err_o => resp_bus(RESP_BOOTROM).err -- transfer error + clk_i => clk_i, + bus_req_i => soc_req, + bus_rsp_o => rsp_bus(DEV_BOOTROM) ); end generate; neorv32_boot_rom_inst_false: if (INT_BOOTLOADER_EN = false) generate - resp_bus(RESP_BOOTROM) <= resp_bus_entry_terminate_c; + rsp_bus(DEV_BOOTROM) <= rsp_terminate_c; end generate; @@ -1005,65 +794,54 @@ begin neorv32_wishbone_inst: neorv32_wishbone generic map ( -- Internal instruction memory -- - MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory - MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes + MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, + MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- Internal data memory -- - MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory - MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes + MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, + MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- Interface Configuration -- - BUS_TIMEOUT => MEM_EXT_TIMEOUT, -- cycles after an UNACKNOWLEDGED bus access triggers a bus fault exception - PIPE_MODE => MEM_EXT_PIPE_MODE, -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode - BIG_ENDIAN => MEM_EXT_BIG_ENDIAN, -- byte order: true=big-endian, false=little-endian - ASYNC_RX => MEM_EXT_ASYNC_RX, -- use register buffer for RX data when false - ASYNC_TX => MEM_EXT_ASYNC_TX -- use register buffer for TX data when false + BUS_TIMEOUT => MEM_EXT_TIMEOUT, + PIPE_MODE => MEM_EXT_PIPE_MODE, + BIG_ENDIAN => MEM_EXT_BIG_ENDIAN, + ASYNC_RX => MEM_EXT_ASYNC_RX, + ASYNC_TX => MEM_EXT_ASYNC_TX ) port map ( -- global control -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - -- host access -- - src_i => p_bus.src, -- access type (0: data, 1:instruction) - addr_i => p_bus.addr, -- address - rden_i => p_bus.re, -- read enable - wren_i => p_bus.we, -- write enable - ben_i => p_bus.ben, -- byte write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_WISHBONE).rdata, -- data out - ack_o => resp_bus(RESP_WISHBONE).ack, -- transfer acknowledge - err_o => resp_bus(RESP_WISHBONE).err, -- transfer error - tmo_o => ext_timeout, -- transfer timeout - priv_i => p_bus.priv, -- current CPU privilege level - ext_o => ext_access, -- active external access - -- xip configuration -- - xip_en_i => xip_enable, -- XIP module enabled - xip_page_i => xip_page, -- XIP memory page - -- wishbone interface -- - wb_tag_o => wb_tag_o, -- request tag - wb_adr_o => wb_adr_o, -- address - wb_dat_i => wb_dat_i, -- read data - wb_dat_o => wb_dat_o, -- write data - wb_we_o => wb_we_o, -- read/write - wb_sel_o => wb_sel_o, -- byte enable - wb_stb_o => wb_stb_o, -- strobe - wb_cyc_o => wb_cyc_o, -- valid cycle - wb_ack_i => wb_ack_i, -- transfer acknowledge - wb_err_i => wb_err_i -- transfer error + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => soc_req, + bus_rsp_o => rsp_bus(DEV_WISHBONE), + tmo_o => ext_timeout, + ext_o => ext_access, + xip_en_i => xip_enable, + xip_page_i => xip_page, + -- + wb_tag_o => wb_tag_o, + wb_adr_o => wb_adr_o, + wb_dat_i => wb_dat_i, + wb_dat_o => wb_dat_o, + wb_we_o => wb_we_o, + wb_sel_o => wb_sel_o, + wb_stb_o => wb_stb_o, + wb_cyc_o => wb_cyc_o, + wb_ack_i => wb_ack_i, + wb_err_i => wb_err_i ); end generate; neorv32_wishbone_inst_false: if (MEM_EXT_EN = false) generate - resp_bus(RESP_WISHBONE) <= resp_bus_entry_terminate_c; + rsp_bus(DEV_WISHBONE) <= rsp_terminate_c; ext_timeout <= '0'; ext_access <= '0'; - -- - wb_adr_o <= (others => '0'); - wb_dat_o <= (others => '0'); - wb_we_o <= '0'; - wb_sel_o <= (others => '0'); - wb_stb_o <= '0'; - wb_cyc_o <= '0'; - wb_tag_o <= (others => '0'); + wb_adr_o <= (others => '0'); + wb_dat_o <= (others => '0'); + wb_we_o <= '0'; + wb_sel_o <= (others => '0'); + wb_stb_o <= '0'; + wb_cyc_o <= '0'; + wb_tag_o <= (others => '0'); end generate; @@ -1074,43 +852,28 @@ begin neorv32_xip_inst: neorv32_xip port map ( -- global control -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - -- host access: control register access port -- - ct_addr_i => p_bus.addr, -- address - ct_rden_i => io_rden, -- read enable - ct_wren_i => io_wren, -- write enable - ct_data_i => p_bus.wdata, -- data in - ct_data_o => resp_bus(RESP_XIP_CT).rdata, -- data out - ct_ack_o => resp_bus(RESP_XIP_CT).ack, -- transfer acknowledge - -- host access: transparent SPI access port (read-only) -- - acc_addr_i => p_bus.addr, -- address - acc_rden_i => p_bus.re, -- read enable - acc_wren_i => p_bus.we, -- write enable - acc_data_o => resp_bus(RESP_XIP_ACC).rdata, -- data out - acc_ack_o => resp_bus(RESP_XIP_ACC).ack, -- transfer acknowledge - acc_err_o => resp_bus(RESP_XIP_ACC).err, -- transfer error - -- status -- - xip_en_o => xip_enable, -- XIP enable - xip_acc_o => xip_access, -- pending XIP access - xip_page_o => xip_page, -- XIP page - -- clock generator -- - clkgen_en_o => xip_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_XIP_CT), + xip_req_i => soc_req, + xip_rsp_o => rsp_bus(DEV_XIP_ACC), + xip_en_o => xip_enable, + xip_acc_o => xip_access, + xip_page_o => xip_page, + clkgen_en_o => xip_cg_en, clkgen_i => clk_gen, - -- SPI device interface -- - spi_csn_o => xip_csn_o, -- chip-select, low-active - spi_clk_o => xip_clk_o, -- serial clock - spi_dat_i => xip_dat_i, -- device data output - spi_dat_o => xip_dat_o -- controller data output + spi_csn_o => xip_csn_o, + spi_clk_o => xip_clk_o, + spi_dat_i => xip_dat_i, + spi_dat_o => xip_dat_o ); - resp_bus(RESP_XIP_CT).err <= '0'; -- no access error possible end generate; neorv32_xip_inst_false: if (IO_XIP_EN = false) generate - resp_bus(RESP_XIP_CT) <= resp_bus_entry_terminate_c; - resp_bus(RESP_XIP_ACC) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_XIP_CT) <= rsp_terminate_c; + rsp_bus(DEV_XIP_ACC) <= rsp_terminate_c; xip_enable <= '0'; xip_access <= '0'; xip_page <= (others => '0'); @@ -1125,11 +888,17 @@ begin -- IO/Peripheral Modules -- **************************************************************************************************************************** - -- IO Access? ----------------------------------------------------------------------------- + -- IO Gateway ----------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - io_acc <= '1' when (p_bus.addr(31 downto index_size_f(io_size_c)) = io_base_c(31 downto index_size_f(io_size_c))) else '0'; - io_rden <= '1' when (io_acc = '1') and (p_bus.re = '1') and (p_bus.src = '0') else '0'; -- PMA: read access only from data interface - io_wren <= '1' when (io_acc = '1') and (p_bus.we = '1') and (p_bus.ben = "1111") else '0'; -- PMA: full-word write accesses only (reduces HW complexity) + io_gateway: process(soc_req, io_acc) + begin + io_req <= soc_req; + io_req.re <= io_acc and soc_req.re and (not soc_req.src); -- PMA: read access only from data interface + io_req.we <= io_acc and soc_req.we and and_reduce_f(soc_req.ben); -- PMA: full-word write accesses only + end process io_gateway; + + -- IO access? -- + io_acc <= '1' when (soc_req.addr(31 downto index_size_f(io_size_c)) = io_base_c(31 downto index_size_f(io_size_c))) else '0'; -- Custom Functions Subsystem (CFS) ------------------------------------------------------- @@ -1138,37 +907,26 @@ begin if (IO_CFS_EN = true) generate neorv32_cfs_inst: neorv32_cfs generic map ( - CFS_CONFIG => IO_CFS_CONFIG, -- custom CFS configuration generic - CFS_IN_SIZE => IO_CFS_IN_SIZE, -- size of CFS input conduit in bits - CFS_OUT_SIZE => IO_CFS_OUT_SIZE -- size of CFS output conduit in bits + CFS_CONFIG => IO_CFS_CONFIG, + CFS_IN_SIZE => IO_CFS_IN_SIZE, + CFS_OUT_SIZE => IO_CFS_OUT_SIZE ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, use as async - priv_i => p_bus.priv, -- current CPU privilege mode - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- word write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_CFS).rdata, -- data out - ack_o => resp_bus(RESP_CFS).ack, -- transfer acknowledge - err_o => resp_bus(RESP_CFS).err, -- access error - -- clock generator -- - clkgen_en_o => cfs_cg_en, -- enable clock generator - clkgen_i => clk_gen, -- "clock" inputs - -- interrupt -- - irq_o => cfs_irq, -- interrupt request - -- custom io (conduit) -- - cfs_in_i => cfs_in_i, -- custom inputs - cfs_out_o => cfs_out_o -- custom outputs + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_CFS), + clkgen_en_o => cfs_cg_en, + clkgen_i => clk_gen, + irq_o => cfs_irq, + cfs_in_i => cfs_in_i, + cfs_out_o => cfs_out_o ); end generate; neorv32_cfs_inst_false: if (IO_CFS_EN = false) generate - resp_bus(RESP_CFS) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_CFS) <= rsp_terminate_c; cfs_cg_en <= '0'; cfs_irq <= '0'; cfs_out_o <= (others => '0'); @@ -1181,33 +939,24 @@ begin if (IO_SDI_EN = true) generate neorv32_SDI_inst: neorv32_sdi generic map ( - RTX_FIFO => IO_SDI_FIFO -- RTX fifo depth, has to be a power of two, min 1 + RTX_FIFO => IO_SDI_FIFO ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_SDI).rdata, -- data out - ack_o => resp_bus(RESP_SDI).ack, -- transfer acknowledge - -- SDI receiver input -- - sdi_csn_i => sdi_csn_i, -- low-active chip-select - sdi_clk_i => sdi_clk_i, -- serial clock - sdi_dat_i => sdi_dat_i, -- serial data input - sdi_dat_o => sdi_dat_o, -- serial data output - -- interrupts -- + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_SDI), + sdi_csn_i => sdi_csn_i, + sdi_clk_i => sdi_clk_i, + sdi_dat_i => sdi_dat_i, + sdi_dat_o => sdi_dat_o, irq_o => sdi_irq ); - resp_bus(RESP_SDI).err <= '0'; -- no access error possible end generate; neorv32_sdi_inst_false: if (IO_SDI_EN = false) generate - resp_bus(RESP_SDI) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_SDI) <= rsp_terminate_c; sdi_dat_o <= '0'; sdi_irq <= '0'; end generate; @@ -1219,29 +968,22 @@ begin if (IO_GPIO_NUM > 0) generate neorv32_gpio_inst: neorv32_gpio generic map ( - GPIO_NUM => IO_GPIO_NUM -- number of GPIO input/output pairs (0..64) + GPIO_NUM => IO_GPIO_NUM ) port map ( -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_GPIO).rdata, -- data out - ack_o => resp_bus(RESP_GPIO).ack, -- transfer acknowledge - -- parallel io -- - gpio_o => gpio_o, - gpio_i => gpio_i + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_GPIO), + gpio_o => gpio_o, + gpio_i => gpio_i ); - resp_bus(RESP_GPIO).err <= '0'; -- no access error possible end generate; neorv32_gpio_inst_false: if (IO_GPIO_NUM = 0) generate - resp_bus(RESP_GPIO) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_GPIO) <= rsp_terminate_c; gpio_o <= (others => '0'); end generate; @@ -1252,33 +994,23 @@ begin if (IO_WDT_EN = true) generate neorv32_wdt_inst: neorv32_wdt port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_ext_i => rstn_ext, -- external reset line, low-active, async - rstn_int_i => rstn_int, -- internal reset line, low-active, async - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - addr_i => p_bus.addr, -- address - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_WDT).rdata, -- data out - ack_o => resp_bus(RESP_WDT).ack, -- transfer acknowledge - -- CPU status -- - cpu_debug_i => cpu_s.debug, -- CPU is in debug mode - cpu_sleep_i => cpu_s.sleep, -- CPU is in sleep mode - -- clock generator -- - clkgen_en_o => wdt_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_ext_i => rstn_ext, + rstn_int_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_WDT), + cpu_debug_i => cpu_debug, + cpu_sleep_i => cpu_sleep, + clkgen_en_o => wdt_cg_en, clkgen_i => clk_gen, - -- timeout event -- - irq_o => wdt_irq, -- timeout IRQ - rstn_o => rstn_wdt -- timeout reset, low_active, sync + irq_o => wdt_irq, + rstn_o => rstn_wdt ); - resp_bus(RESP_WDT).err <= '0'; -- no access error possible end generate; neorv32_wdt_inst_false: if (IO_WDT_EN = false) generate - resp_bus(RESP_WDT) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_WDT) <= rsp_terminate_c; wdt_irq <= '0'; rstn_wdt <= '1'; wdt_cg_en <= '0'; @@ -1291,26 +1023,18 @@ begin if (IO_MTIME_EN = true) generate neorv32_mtime_inst: neorv32_mtime port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_MTIME).rdata, -- data out - ack_o => resp_bus(RESP_MTIME).ack, -- transfer acknowledge - -- interrupt -- - irq_o => mtime_irq -- interrupt request + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_MTIME), + irq_o => mtime_irq ); - resp_bus(RESP_MTIME).err <= '0'; -- no access error possible end generate; neorv32_mtime_inst_false: if (IO_MTIME_EN = false) generate - resp_bus(RESP_MTIME) <= resp_bus_entry_terminate_c; - -- - mtime_irq <= mtime_irq_i; -- use external machine timer interrupt + rsp_bus(DEV_MTIME) <= rsp_terminate_c; + mtime_irq <= mtime_irq_i; end generate; @@ -1320,40 +1044,29 @@ begin if (IO_UART0_EN = true) generate neorv32_uart0_inst: neorv32_uart generic map ( - UART_PRIMARY => true, -- true = primary UART (UART0), false = secondary UART (UART1) - UART_RX_FIFO => IO_UART0_RX_FIFO, -- RX fifo depth, has to be a power of two, min 1 - UART_TX_FIFO => IO_UART0_TX_FIFO -- TX fifo depth, has to be a power of two, min 1 + UART_PRIMARY => true, + UART_RX_FIFO => IO_UART0_RX_FIFO, + UART_TX_FIFO => IO_UART0_TX_FIFO ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_UART0).rdata, -- data out - ack_o => resp_bus(RESP_UART0).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => uart0_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_UART0), + clkgen_en_o => uart0_cg_en, clkgen_i => clk_gen, - -- com lines -- uart_txd_o => uart0_txd_o, uart_rxd_i => uart0_rxd_i, - -- hardware flow control -- - uart_rts_o => uart0_rts_o, -- UART.RX ready to receive ("RTR"), low-active, optional - uart_cts_i => uart0_cts_i, -- UART.TX allowed to transmit, low-active, optional - -- interrupts -- - irq_rx_o => uart0_rx_irq, -- rx interrupt - irq_tx_o => uart0_tx_irq -- tx interrupt + uart_rts_o => uart0_rts_o, + uart_cts_i => uart0_cts_i, + irq_rx_o => uart0_rx_irq, + irq_tx_o => uart0_tx_irq ); - resp_bus(RESP_UART0).err <= '0'; -- no access error possible end generate; neorv32_uart0_inst_false: if (IO_UART0_EN = false) generate - resp_bus(RESP_UART0) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_UART0) <= rsp_terminate_c; uart0_txd_o <= '0'; uart0_rts_o <= '1'; uart0_cg_en <= '0'; @@ -1368,40 +1081,29 @@ begin if (IO_UART1_EN = true) generate neorv32_uart1_inst: neorv32_uart generic map ( - UART_PRIMARY => false, -- true = primary UART (UART0), false = secondary UART (UART1) - UART_RX_FIFO => IO_UART1_RX_FIFO, -- RX fifo depth, has to be a power of two, min 1 - UART_TX_FIFO => IO_UART1_TX_FIFO -- TX fifo depth, has to be a power of two, min 1 + UART_PRIMARY => false, + UART_RX_FIFO => IO_UART1_RX_FIFO, + UART_TX_FIFO => IO_UART1_TX_FIFO ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_UART1).rdata, -- data out - ack_o => resp_bus(RESP_UART1).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => uart1_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_UART1), + clkgen_en_o => uart1_cg_en, clkgen_i => clk_gen, - -- com lines -- uart_txd_o => uart1_txd_o, uart_rxd_i => uart1_rxd_i, - -- hardware flow control -- - uart_rts_o => uart1_rts_o, -- UART.RX ready to receive ("RTR"), low-active, optional - uart_cts_i => uart1_cts_i, -- UART.TX allowed to transmit, low-active, optional - -- interrupts -- - irq_rx_o => uart1_rx_irq, -- rx interrupt - irq_tx_o => uart1_tx_irq -- tx interrupt + uart_rts_o => uart1_rts_o, + uart_cts_i => uart1_cts_i, + irq_rx_o => uart1_rx_irq, + irq_tx_o => uart1_tx_irq ); - resp_bus(RESP_UART1).err <= '0'; -- no access error possible end generate; neorv32_uart1_inst_false: if (IO_UART1_EN = false) generate - resp_bus(RESP_UART1) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_UART1) <= rsp_terminate_c; uart1_txd_o <= '0'; uart1_rts_o <= '1'; uart1_cg_en <= '0'; @@ -1416,39 +1118,29 @@ begin if (IO_SPI_EN = true) generate neorv32_spi_inst: neorv32_spi generic map ( - IO_SPI_FIFO => IO_SPI_FIFO -- SPI RTX fifo depth, has to be a power of two, min 1 + IO_SPI_FIFO => IO_SPI_FIFO ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_SPI).rdata, -- data out - ack_o => resp_bus(RESP_SPI).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => spi_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_SPI), + clkgen_en_o => spi_cg_en, clkgen_i => clk_gen, - -- com lines -- - spi_clk_o => spi_clk_o, -- SPI serial clock - spi_dat_o => spi_dat_o, -- controller data out, peripheral data in - spi_dat_i => spi_dat_i, -- controller data in, peripheral data out - spi_csn_o => spi_csn_o, -- SPI CS - -- interrupt -- - irq_o => spi_irq -- transmission done interrupt + spi_clk_o => spi_clk_o, + spi_dat_o => spi_dat_o, + spi_dat_i => spi_dat_i, + spi_csn_o => spi_csn_o, + irq_o => spi_irq ); - resp_bus(RESP_SPI).err <= '0'; -- no access error possible end generate; neorv32_spi_inst_false: if (IO_SPI_EN = false) generate - resp_bus(RESP_SPI) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_SPI) <= rsp_terminate_c; spi_clk_o <= '0'; spi_dat_o <= '0'; - spi_csn_o <= (others => '1'); -- CS lines are low-active + spi_csn_o <= (others => '1'); spi_cg_en <= '0'; spi_irq <= '0'; end generate; @@ -1460,33 +1152,23 @@ begin if (IO_TWI_EN = true) generate neorv32_twi_inst: neorv32_twi port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_TWI).rdata, -- data out - ack_o => resp_bus(RESP_TWI).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => twi_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_TWI), + clkgen_en_o => twi_cg_en, clkgen_i => clk_gen, - -- com lines (require external tri-state drivers) -- - twi_sda_i => twi_sda_i, -- serial data line input - twi_sda_o => twi_sda_o, -- serial data line output - twi_scl_i => twi_scl_i, -- serial clock line input - twi_scl_o => twi_scl_o, -- serial clock line output - -- interrupt -- - irq_o => twi_irq -- transfer done IRQ + twi_sda_i => twi_sda_i, + twi_sda_o => twi_sda_o, + twi_scl_i => twi_scl_i, + twi_scl_o => twi_scl_o, + irq_o => twi_irq ); - resp_bus(RESP_TWI).err <= '0'; -- no access error possible end generate; neorv32_twi_inst_false: if (IO_TWI_EN = false) generate - resp_bus(RESP_TWI) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_TWI) <= rsp_terminate_c; twi_sda_o <= '1'; twi_scl_o <= '1'; twi_cg_en <= '0'; @@ -1500,31 +1182,22 @@ begin if (IO_PWM_NUM_CH > 0) generate neorv32_pwm_inst: neorv32_pwm generic map ( - NUM_CHANNELS => IO_PWM_NUM_CH -- number of PWM channels (0..12) + NUM_CHANNELS => IO_PWM_NUM_CH ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_PWM).rdata, -- data out - ack_o => resp_bus(RESP_PWM).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => pwm_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_PWM), + clkgen_en_o => pwm_cg_en, clkgen_i => clk_gen, - -- pwm output channels -- pwm_o => pwm_o ); - resp_bus(RESP_PWM).err <= '0'; -- no access error possible end generate; neorv32_pwm_inst_false: if (IO_PWM_NUM_CH = 0) generate - resp_bus(RESP_PWM) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_PWM) <= rsp_terminate_c; pwm_cg_en <= '0'; pwm_o <= (others => '0'); end generate; @@ -1536,25 +1209,19 @@ begin if (IO_TRNG_EN = true) generate neorv32_trng_inst: neorv32_trng generic map ( - IO_TRNG_FIFO => IO_TRNG_FIFO -- RND fifo depth, has to be a power of two, min 1 + IO_TRNG_FIFO => IO_TRNG_FIFO ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_TRNG).rdata, -- data out - ack_o => resp_bus(RESP_TRNG).ack -- transfer acknowledge + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_TRNG) ); - resp_bus(RESP_TRNG).err <= '0'; -- no access error possible end generate; neorv32_trng_inst_false: if (IO_TRNG_EN = false) generate - resp_bus(RESP_TRNG) <= resp_bus_entry_terminate_c; + rsp_bus(DEV_TRNG) <= rsp_terminate_c; end generate; @@ -1564,33 +1231,23 @@ begin if (IO_NEOLED_EN = true) generate neorv32_neoled_inst: neorv32_neoled generic map ( - FIFO_DEPTH => IO_NEOLED_TX_FIFO -- NEOLED FIFO depth, has to be a power of two, min 1 + FIFO_DEPTH => IO_NEOLED_TX_FIFO ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_NEOLED).rdata, -- data out - ack_o => resp_bus(RESP_NEOLED).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => neoled_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_NEOLED), + clkgen_en_o => neoled_cg_en, clkgen_i => clk_gen, - -- interrupt -- - irq_o => neoled_irq, -- interrupt request - -- NEOLED output -- - neoled_o => neoled_o -- serial async data line + irq_o => neoled_irq, + neoled_o => neoled_o ); - resp_bus(RESP_NEOLED).err <= '0'; -- no access error possible end generate; neorv32_neoled_inst_false: if (IO_NEOLED_EN = false) generate - resp_bus(RESP_NEOLED) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_NEOLED) <= rsp_terminate_c; neoled_cg_en <= '0'; neoled_irq <= '0'; neoled_o <= '0'; @@ -1603,32 +1260,24 @@ begin if (XIRQ_NUM_CH > 0) generate neorv32_xirq_inst: neorv32_xirq generic map ( - XIRQ_NUM_CH => XIRQ_NUM_CH, -- number of external IRQ channels (0..32) - XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE, -- trigger type: 0=level, 1=edge - XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge + XIRQ_NUM_CH => XIRQ_NUM_CH, + XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE, + XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY ) port map ( -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_XIRQ).rdata, -- data out - ack_o => resp_bus(RESP_XIRQ).ack, -- transfer acknowledge - -- external interrupt lines -- + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_XIRQ), xirq_i => xirq_i, - -- CPU interrupt -- cpu_irq_o => xirq_irq ); - resp_bus(RESP_XIRQ).err <= '0'; -- no access error possible end generate; neorv32_xirq_inst_false: if (XIRQ_NUM_CH = 0) generate - resp_bus(RESP_XIRQ) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_XIRQ) <= rsp_terminate_c; xirq_irq <= '0'; end generate; @@ -1639,28 +1288,19 @@ begin if (IO_GPTMR_EN = true) generate neorv32_gptmr_inst: neorv32_gptmr port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_GPTMR).rdata, -- data out - ack_o => resp_bus(RESP_GPTMR).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => gptmr_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_GPTMR), + clkgen_en_o => gptmr_cg_en, clkgen_i => clk_gen, - -- interrupt -- - irq_o => gptmr_irq -- timer match interrupt + irq_o => gptmr_irq ); - resp_bus(RESP_GPTMR).err <= '0'; -- no access error possible end generate; neorv32_gptmr_inst_false: if (IO_GPTMR_EN = false) generate - resp_bus(RESP_GPTMR) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_GPTMR) <= rsp_terminate_c; gptmr_cg_en <= '0'; gptmr_irq <= '0'; end generate; @@ -1672,31 +1312,21 @@ begin if (IO_ONEWIRE_EN = true) generate neorv32_onewire_inst: neorv32_onewire port map ( - -- host access -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_int, -- global reset line, low-active, async - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_i => p_bus.wdata, -- data in - data_o => resp_bus(RESP_ONEWIRE).rdata, -- data out - ack_o => resp_bus(RESP_ONEWIRE).ack, -- transfer acknowledge - -- clock generator -- - clkgen_en_o => onewire_cg_en, -- enable clock generator + clk_i => clk_i, + rstn_i => rstn_int, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_ONEWIRE), + clkgen_en_o => onewire_cg_en, clkgen_i => clk_gen, - -- com lines (require external tri-state drivers) -- - onewire_i => onewire_i, -- 1-wire line state - onewire_o => onewire_o, -- 1-wire line pull-down - -- interrupt -- - irq_o => onewire_irq -- transfer done IRQ + onewire_i => onewire_i, + onewire_o => onewire_o, + irq_o => onewire_irq ); - resp_bus(RESP_ONEWIRE).err <= '0'; -- no access error possible end generate; neorv32_onewire_inst_false: if (IO_ONEWIRE_EN = false) generate - resp_bus(RESP_ONEWIRE) <= resp_bus_entry_terminate_c; - -- + rsp_bus(DEV_ONEWIRE) <= rsp_terminate_c; onewire_o <= '1'; onewire_cg_en <= '0'; onewire_irq <= '0'; @@ -1708,59 +1338,54 @@ begin neorv32_sysinfo_inst: neorv32_sysinfo generic map ( -- General -- - CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz - CUSTOM_ID => CUSTOM_ID, -- custom user-defined ID - INT_BOOTLOADER_EN => INT_BOOTLOADER_EN, -- implement processor-internal bootloader? + CLOCK_FREQUENCY => CLOCK_FREQUENCY, + CUSTOM_ID => CUSTOM_ID, + INT_BOOTLOADER_EN => INT_BOOTLOADER_EN, -- Physical memory protection (PMP) -- - PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..16) + PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- internal Instruction memory -- - MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory - MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes + MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, + MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- Internal Data memory -- - MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory - MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes + MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, + MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- Instruction cache -- - ICACHE_EN => ICACHE_EN, -- implement instruction cache - ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- i-cache: number of blocks (min 2), has to be a power of 2 - ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- i-cache: block size in bytes (min 4), has to be a power of 2 - ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY, -- i-cache: associativity (min 1), has to be a power 2 + ICACHE_EN => ICACHE_EN, + ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, + ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, + ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY, -- Data cache -- - DCACHE_EN => DCACHE_EN, -- implement data cache - DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS, -- d-cache: number of blocks (min 2), has to be a power of 2 - DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE, -- d-cache: block size in bytes (min 4), has to be a power of 2 + DCACHE_EN => DCACHE_EN, + DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS, + DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE, -- External memory interface -- - MEM_EXT_EN => MEM_EXT_EN, -- implement external memory bus interface? - MEM_EXT_BIG_ENDIAN => MEM_EXT_BIG_ENDIAN, -- byte order: true=big-endian, false=little-endian + MEM_EXT_EN => MEM_EXT_EN, + MEM_EXT_BIG_ENDIAN => MEM_EXT_BIG_ENDIAN, -- On-Chip Debugger -- - ON_CHIP_DEBUGGER_EN => ON_CHIP_DEBUGGER_EN, -- implement OCD? + ON_CHIP_DEBUGGER_EN => ON_CHIP_DEBUGGER_EN, -- Processor peripherals -- - IO_GPIO_NUM => IO_GPIO_NUM, -- number of GPIO input/output pairs (0..64) - IO_MTIME_EN => IO_MTIME_EN, -- implement machine system timer (MTIME)? - IO_UART0_EN => IO_UART0_EN, -- implement primary universal asynchronous receiver/transmitter (UART0)? - IO_UART1_EN => IO_UART1_EN, -- implement secondary universal asynchronous receiver/transmitter (UART1)? - IO_SPI_EN => IO_SPI_EN, -- implement serial peripheral interface (SPI)? - IO_SDI_EN => IO_SDI_EN, -- implement serial data interface (SDI)? - IO_TWI_EN => IO_TWI_EN, -- implement two-wire interface (TWI)? - IO_PWM_NUM_CH => IO_PWM_NUM_CH, -- number of PWM channels to implement - IO_WDT_EN => IO_WDT_EN, -- implement watch dog timer (WDT)? - IO_TRNG_EN => IO_TRNG_EN, -- implement true random number generator (TRNG)? - IO_CFS_EN => IO_CFS_EN, -- implement custom functions subsystem (CFS)? - IO_NEOLED_EN => IO_NEOLED_EN, -- implement NeoPixel-compatible smart LED interface (NEOLED)? - IO_XIRQ_NUM_CH => XIRQ_NUM_CH, -- number of external interrupt (XIRQ) channels to implement - IO_GPTMR_EN => IO_GPTMR_EN, -- implement general purpose timer (GPTMR)? - IO_XIP_EN => IO_XIP_EN, -- implement execute in place module (XIP)? - IO_ONEWIRE_EN => IO_ONEWIRE_EN, -- implement 1-wire interface (ONEWIRE)? - IO_DMA_EN => IO_DMA_EN -- implement direct memory access controller (DMA)? + IO_GPIO_NUM => IO_GPIO_NUM, + IO_MTIME_EN => IO_MTIME_EN, + IO_UART0_EN => IO_UART0_EN, + IO_UART1_EN => IO_UART1_EN, + IO_SPI_EN => IO_SPI_EN, + IO_SDI_EN => IO_SDI_EN, + IO_TWI_EN => IO_TWI_EN, + IO_PWM_NUM_CH => IO_PWM_NUM_CH, + IO_WDT_EN => IO_WDT_EN, + IO_TRNG_EN => IO_TRNG_EN, + IO_CFS_EN => IO_CFS_EN, + IO_NEOLED_EN => IO_NEOLED_EN, + IO_XIRQ_NUM_CH => XIRQ_NUM_CH, + IO_GPTMR_EN => IO_GPTMR_EN, + IO_XIP_EN => IO_XIP_EN, + IO_ONEWIRE_EN => IO_ONEWIRE_EN, + IO_DMA_EN => IO_DMA_EN ) port map ( - -- host access -- - clk_i => clk_i, -- global clock line - addr_i => p_bus.addr, -- address - rden_i => io_rden, -- read enable - wren_i => io_wren, -- write enable - data_o => resp_bus(RESP_SYSINFO).rdata, -- data out - ack_o => resp_bus(RESP_SYSINFO).ack, -- transfer acknowledge - err_o => resp_bus(RESP_SYSINFO).err -- transfer error + clk_i => clk_i, + bus_req_i => io_req, + bus_rsp_o => rsp_bus(DEV_SYSINFO) ); @@ -1771,51 +1396,18 @@ begin neorv32_neorv32_ocd_inst_true: if (ON_CHIP_DEBUGGER_EN = true) generate - -- On-Chip Debugger - Debug Module (DM) --------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - neorv32_debug_dm_inst: neorv32_debug_dm - port map ( - -- global control -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_ext, -- external reset, low-active - -- debug module interface (DMI) -- - dmi_req_valid_i => dmi.req_valid, - dmi_req_ready_o => dmi.req_ready, - dmi_req_address_i => dmi.req_address, - dmi_req_data_i => dmi.req_data, - dmi_req_op_i => dmi.req_op, - dmi_rsp_valid_o => dmi.rsp_valid, - dmi_rsp_ready_i => dmi.rsp_ready, - dmi_rsp_data_o => dmi.rsp_data, - dmi_rsp_op_o => dmi.rsp_op, - -- CPU bus access -- - cpu_debug_i => cpu_s.debug, -- CPU is in debug mode - cpu_addr_i => p_bus.addr, -- address - cpu_rden_i => p_bus.re, -- read enable - cpu_wren_i => p_bus.we, -- write enable - cpu_ben_i => p_bus.ben, -- byte write enable - cpu_data_i => p_bus.wdata, -- data in - cpu_data_o => resp_bus(RESP_OCD).rdata, -- data out - cpu_ack_o => resp_bus(RESP_OCD).ack, -- transfer acknowledge - -- CPU control -- - cpu_ndmrstn_o => dci_ndmrstn, -- soc reset - cpu_halt_req_o => dci_halt_req -- request hart to halt (enter debug mode) - ); - resp_bus(RESP_OCD).err <= '0'; -- no access error possible - - -- On-Chip Debugger - Debug Transport Module (DTM) ---------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_debug_dtm_inst: neorv32_debug_dtm generic map ( - IDCODE_VERSION => (others => '0'), -- version - IDCODE_PARTID => (others => '0'), -- part number - IDCODE_MANID => (others => '0') -- manufacturer id + IDCODE_VERSION => (others => '0'), + IDCODE_PARTID => (others => '0'), + IDCODE_MANID => (others => '0') ) port map ( -- global control -- - clk_i => clk_i, -- global clock line - rstn_i => rstn_ext, -- external reset, low-active + clk_i => clk_i, + rstn_i => rstn_ext, -- jtag connection -- jtag_trst_i => jtag_trst_i, jtag_tck_i => jtag_tck_i, @@ -1834,14 +1426,40 @@ begin dmi_rsp_op_i => dmi.rsp_op ); + -- On-Chip Debugger - Debug Module (DM) --------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + neorv32_debug_dm_inst: neorv32_debug_dm + port map ( + -- global control -- + clk_i => clk_i, + rstn_i => rstn_ext, + cpu_debug_i => cpu_debug, + -- debug module interface (DMI) -- + dmi_req_valid_i => dmi.req_valid, + dmi_req_ready_o => dmi.req_ready, + dmi_req_address_i => dmi.req_address, + dmi_req_data_i => dmi.req_data, + dmi_req_op_i => dmi.req_op, + dmi_rsp_valid_o => dmi.rsp_valid, + dmi_rsp_ready_i => dmi.rsp_ready, + dmi_rsp_data_o => dmi.rsp_data, + dmi_rsp_op_o => dmi.rsp_op, + -- CPU bus access -- + bus_req_i => soc_req, + bus_rsp_o => rsp_bus(DEV_OCD), + -- CPU control -- + cpu_ndmrstn_o => dci_ndmrstn, + cpu_halt_req_o => dci_halt_req + ); + end generate; neorv32_debug_ocd_inst_false: if (ON_CHIP_DEBUGGER_EN = false) generate - jtag_tdo_o <= jtag_tdi_i; -- JTAG feed-through - resp_bus(RESP_OCD) <= resp_bus_entry_terminate_c; - dci_ndmrstn <= '1'; - dci_halt_req <= '0'; + rsp_bus(DEV_OCD) <= rsp_terminate_c; + jtag_tdo_o <= jtag_tdi_i; -- JTAG feed-through + dci_ndmrstn <= '1'; + dci_halt_req <= '0'; end generate; From 7da96f288540e8d688c2d623230511de56cfaa74 Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:29:52 +0200 Subject: [PATCH 5/6] [CHANGELOG] add v1.8.4.5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64dadaf05..6ab67508e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ mimpid = 0x01080200 => Version 01.08.02.00 => v1.8.2 | Date (*dd.mm.yyyy*) | Version | Comment | |:-------------------:|:-------:|:--------| +| 30.04.2023 | 1.8.4.5 | rework processor-internal bus system; [#607](https://github.com/stnolting/neorv32/pull/607) | | 27.04.2023 | 1.8.4.4 | minor hardware edits and switching activity optimizations of CPU bus unit; [#605](https://github.com/stnolting/neorv32/pull/605) | | 25.04.2023 | 1.8.4.3 | :bug: fix bug in **DMA** (corrupted write-back when there are bus wait cycles - e.g. when no caches are implemented); [#601](https://github.com/stnolting/neorv32/pull/601) | | 24.04.2023 | 1.8.4.2 | minor rtl edits; shorten critical path of d-cache setup; [#599](https://github.com/stnolting/neorv32/pull/599) | From 06db9505baf22d03483f44a95bb159a0ed512b14 Mon Sep 17 00:00:00 2001 From: stnolting <22944758+stnolting@users.noreply.github.com> Date: Sun, 30 Apr 2023 20:05:17 +0200 Subject: [PATCH 6/6] [docs] update section "CPU" & "Bus Interface" --- docs/datasheet/cpu.adoc | 170 ++++++++++------------ docs/figures/cpu_interface_read_long.png | Bin 21169 -> 19908 bytes docs/figures/cpu_interface_write_long.png | Bin 21950 -> 20353 bytes 3 files changed, 76 insertions(+), 94 deletions(-) diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index 493e8a2af..fc1687ffa 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -201,45 +201,35 @@ type of all signals is _std_ulogic_ or _std_ulogic_vector_, respectively. The "D direction as seen from the CPU. .NEORV32 CPU Signal List -[cols="<2,^1,^1,<5"] +[cols="<3,^3,^1,<5"] [options="header", grid="rows"] |======================= -| Signal | Width | Dir | Description +| Signal | Width/Type | Dir | Description 4+^| **Global Signals** -| `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge -| `rstn_i` | 1 | in | Global reset, low-active -| `sleep_o` | 1 | out | CPU is in sleep mode when set -| `debug_o` | 1 | out | CPU is in debug mode when set +| `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge +| `rstn_i` | 1 | in | Global reset, low-active +| `sleep_o` | 1 | out | CPU is in sleep mode when set +| `debug_o` | 1 | out | CPU is in debug mode when set +| `ifence_o` | 1 | out | instruction fence (`fence.i` instruction ) +| `dfence_o` | 1 | out | data fence (`fence` instruction ) +4+^| **Interrupts (<<_traps_exceptions_and_interrupts>>)** +| `msi_i` | 1 | in | RISC-V machine software interrupt +| `mei_i` | 1 | in | RISC-V machine external interrupt +| `mti_i` | 1 | in | RISC-V machine timer interrupt +| `firq_i` | 16 | in | Custom fast interrupt request signals +| `dbi_i` | 1 | in | Request CPU to halt and enter debug mode (RISC-V <<_on_chip_debugger_ocd>>) 4+^| **Instruction <<_bus_interface>>** -| `i_bus_addr_o` | 32 | out | Access address -| `i_bus_rdata_i` | 32 | in | Read data -| `i_bus_re_o` | 1 | out | Read request (one-shot) trigger -| `i_bus_ack_i` | 1 | in | Bus transfer acknowledge from accessed peripheral -| `i_bus_err_i` | 1 | in | Bus transfer terminate from accessed peripheral -| `i_bus_fence_o` | 1 | out | Indicates an executed `fence.i` instruction -| `i_bus_priv_o` | 1 | out | Current _effective_ CPU privilege level (`0` = user, `1` = machine) +| `ibus_req_o` | `bus_req_t` | out | Instruction fetch bus request +| `ibus_rsp_i` | `bus_rsp_t` | in | Instruction fetch bus response 4+^| **Data <<_bus_interface>>** -| `d_bus_addr_o` | 32 | out | Access address -| `d_bus_rdata_i` | 32 | in | Read data -| `d_bus_wdata_o` | 32 | out | Write data -| `d_bus_ben_o` | 4 | out | Byte enable -| `d_bus_we_o` | 1 | out | Write request (one-shot) trigger -| `d_bus_re_o` | 1 | out | Read request (one-shot) trigger -| `d_bus_ack_i` | 1 | in | Bus transfer acknowledge from accessed peripheral -| `d_bus_err_i` | 1 | in | Bus transfer terminate from accessed peripheral -| `d_bus_fence_o` | 1 | out | Indicates an executed `fence` instruction -| `d_bus_priv_o` | 1 | out | Current _effective_ CPU privilege level (`0` = user, `1` = machine) -4+^| **Interrupts (<<_traps_exceptions_and_interrupts>>)** -| `msw_irq_i` | 1 | in | RISC-V machine software interrupt -| `mext_irq_i` | 1 | in | RISC-V machine external interrupt -| `mtime_irq_i` | 1 | in | RISC-V machine timer interrupt -| `firq_i` | 16 | in | Custom fast interrupt request signals -| `db_halt_req_i` | 1 | in | Request CPU to halt and enter debug mode (RISC-V <<_on_chip_debugger_ocd>>) +| `dbus_req_o` | `bus_req_t` | out | Data access (load/store) bus request +| `dbus_rsp_i` | `bus_rsp_t` | in | Data access (load/store) bus response |======================= .Bus Interface Protocol [TIP] -See section <<_bus_interface>> for the instruction fetch and data access interface protocol. +See section <<_bus_interface>> for the instruction fetch and data access interface protocol and the +according interface types (`bus_req_t` and `bus_rsp_t`). <<< @@ -752,29 +742,43 @@ instruction exception _at all_. In both cases bit 0 of the program counter (and :sectnums: ==== Bus Interface -The NEORV32 CPU provides separated instruction and data interfaces making it a **Harvard Architecture**: +The NEORV32 CPU provides separated instruction fetch and data access interfaces making it a **Harvard Architecture**: the instruction fetch interface (`i_bus_*` signals) is used for fetching instructions and the data access interface -(`d_bus_*` signals) is used to access data via load and store operations. Each of these interfaces can access an address space -of up to 2^32^ bytes (4GB). The following table shows the signals of the data and instruction interfaces as seen from the -CPU (`*_o` signals are driven by the CPU / outputs, `*_i` signals are read by the CPU / inputs). +(`d_bus_*` signals) is used to access data via load and store operations. Each of these interfaces can access an address +space of up to 2^32^ bytes (4GB). + +The bus interface uses two custom interface type: `bus_req_t` is used to propagate the bus **requests**. These signals +are driven by the _accessing_ device (i.e. the CPU core). `bus_rsp_t` is used to return the bus **response** and is +driven by the _accessed_ device (i.e. a processor-internal memory or IO device). + +.CPU Bus Interface - Request Bus (`bus_req_t`) +[cols="^1,^1,<6"] +[options="header",grid="rows"] +|======================= +| Signal | Width | Description +| `addr` | 32 | Access address (byte addressing) +| `data` | 32 | Write data +| `ben` | 4 | Byte-enable for each byte in `data` +| `we` | 1 | **Write** request trigger (single-shot) +| `re` | 1 | **Read** request trigger (single-shot) +| `src` | 1 | Access source (`0` = instruction fetch, `1` = data access) +| `priv` | 1 | Set if privileged (M-mode) access +|======================= -.CPU Bus Interface Signals -[cols="<2,^1,^1,<6"] +.CPU Bus Interface - Response Bus (`bus_rsp_t`) +[cols="^1,^1,<6"] [options="header",grid="rows"] |======================= -| Signal | Width | Direction | Description -| `i/d_bus_addr_o` | 32 | out | access address -| `i/d_bus_rdata_i` | 32 | in | data input for read operations -| `d_bus_wdata_o` | 32 | out | data output for write operations -| `d_bus_ben_o` | 4 | out | byte enable signal for write operations -| `d_bus_we_o` | 1 | out | bus write access request (one-shot) -| `i/d_bus_re_o` | 1 | out | bus read access request (one-shot) -| `i/d_bus_ack_i` | 1 | in | accessed peripheral indicates a successful completion of the bus transaction -| `i/d_bus_err_i` | 1 | in | accessed peripheral indicates an error during the bus transaction -| `i/d_bus_fence_o` | 1 | out | this signal is set for one cycle when the CPU executes an instruction/data fence command -| `i/d_bus_priv_o` | 1 | out | shows the effective privilege level of the bus access +| Signal | Width | Description +| `data` | 32 | Read data +| `ack` | 1 | Transfer acknowledge / success (single-shot) +| `err` | 1 | Transfer error / fail (single-shot) |======================= +.SoC Bus System +[NOTE] +This type of bus system is also used to interconnect all the modules of the <<_neorv32_processor_soc>>. + .Pipelined Transfers [NOTE] Currently, pipelined or overlapping operations (within the same bus interface) are not implemented. @@ -787,43 +791,19 @@ unaligned memory access will raise an exception that can be used to handle unali .Signal State [NOTE] -All outgoing bus interface signals (that are driven by the CPU) remain stable until the bus access is completed. +All signals of the request bus interface (except for the read/write transfer triggers) +remain stable until the bus access is completed. :sectnums: ===== Bus Interface Protocol -A new bus request is triggered either by the `*_bus_re_o` signal (for reading data) or by the `*_bus_we_o` signal -(for writing data). In case of a request, the according signal is high for exactly one clock cycle. The transaction is -completed when the accessed peripheral/memory either sets the `*_bus_ack_i` signal (indicating successful completion) or the -`*_bus_err_i` signal (indicating failed completion). These bus response signals have to be also set only for just one cycle. -If a bus request is terminated by the `*_bus_err_i` signal the CPU will raise the according "bus access fault" exception. - - -**Minimal Response Latency** - -The transfer can be completed within in the same cycle as it was initiated (asynchronous response) if the accessed module -directly sets `*_bus_ack_i` or `*_bus_err_i` high for one cycle. However, in order to shorten the critical path such an -"asynchronous" response should be avoided. The default NEORV32 processor-internal modules use a registered response with -exactly **one cycle delay** between initiation and completion of transfers. - - -**Maximal Response Latency** - -The processor-internal modules do not have to respond within one cycle after a bus request has been initiated. -However, the bus transaction has to be completed (= acknowledged) within a certain **response time window**. This time window -is defined by the global `max_proc_int_response_time_c` constant (default = 15 cycles) defined in the processor's VHDL package file -`rtl/neorv32_package.vhd`. It defines the maximum number of cycles after which an _unacknowledged_ (`*_bus_ack_i` or `*_bus_err_i` -signals both not set) transfer will **time out** and will raise a bus access fault exception. The <<_internal_bus_monitor_buskeeper>> -keeps track of all bus transactions to enforce this time window. - -If any bus operations times out - for example when accessing "address space holes" - the BUSKEEPER will issue a bus -error to the CPU (via the according `*_bus_err_i` signal) that will raise the according instruction fetch or data access bus exception. -Note that **the bus keeper does not track external accesses via the external memory bus interface**. However, -the external memory bus interface also provides an _optional_ bus timeout (see section <<_processor_external_memory_interface_wishbone>>). - - -**Exemplary Bus Accesses** +Bus transaction are entirely triggered by the request bus. A new bus request is initiated either by the `re` signal +(= read request) or by the `we` signal (= write request). These signals are mutually exclusive. In case of a request, +the according signal is high for exactly one clock cycle. The transaction is completed when the accessed device returns +a response via the response interface: `ack` is high for exactly one cycle if the transaction was completed successfully. +`err` is high for exactly one cycle if the transaction failed to complete. These two signals are also mutually exclusive. +If a bus request is terminated by the `err` signal the CPU will raise the according "bus access fault" exception. .Example CPU Bus Accesses [cols="^2,^2"] @@ -835,24 +815,26 @@ a| image::cpu_interface_write_long.png[write,300,150] |======================= -**Read and Write Accesses** - -For a write access the according access address (`bus_addr_o`), the data to-be-written (`bus_wdata_o`) and the byte enable -(`bus_ben_o`) are set when `bus_we_o` goes high. These three signals remain unchanged until the transaction is completed. - -For a read access the according access address (`bus_addr_o`) is set when `bus_re_o` goes high. The address remains unchanged -until the transaction is completed. - - -**Access Boundaries** +**Maximal Response Latency** +The processor-internal modules do not have to respond within a fixed cycle amount after a bus request has been initiated. +However, the bus transaction has to be completed (= acknowledged) within a certain **response time window**. This time window +is defined by the global `max_proc_int_response_time_c` constant (default = 15 cycles; the processor's VHDL package file +`rtl/neorv32_package.vhd`). It defines the maximum number of cycles after which a non-responding bus request (i.e. no `ack` +and no `*err` signal) will **time out** and will raise a bus access fault exception. The <<_internal_bus_monitor_buskeeper>> +keeps track of all bus transactions to enforce this time window. If any bus operations times out - for example when +accessing "address space holes" - the BUSKEEPER will issue a bus error to the CPU that will raise the according bus +exception. + +.Access Boundaries +[NOTE] The instruction interface will always access memory on word (= 32-bit) boundaries even if fetching compressed (16-bit) instructions. The data interface can access memory on byte (= 8-bit), half-word (= 16- -bit) and word (= 32-bit) boundaries, but not all processor module support sub-word accesses. - - -**Memory Barriers** +bit) and word (= 32-bit) boundaries, but not all processor module support sub-word accesses. Data access that +are not aligned to their natural size will raise an alignment exception. +.Memory Barriers / Fences +[NOTE] Whenever the CPU executes a `fence` instruction, the according interface signal is set high for one cycle -(`d_bus_fence_o` for a `fence` instruction; `i_bus_fence_o` for a `fence.i` instruction). It is the task of the +(`dfence_o` for a `fence` instruction; `ifence_o` for a `fence.i` instruction). It is the task of the memory system to perform the necessary operations (for example a cache flush/reload). diff --git a/docs/figures/cpu_interface_read_long.png b/docs/figures/cpu_interface_read_long.png index 0a9bc08658ff31378dda5d38a66247e495b80e3c..6d89d9b741ebd81ed54d48e538bd1356f686de52 100644 GIT binary patch literal 19908 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 gRC>5!IAJvd~! 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 V`D>lE8hAPzgQu&X%Q~loCIFxlmS+F} literal 21169 zcmdSBRX|jax(7ORH_{zaQc}_#(j_2BBOt9b4BZV%CDY$yAgGED8=S_8IEmI%$Fo1AiXpqG&seAj z_9^N<+?LAZiaa(+c&kP_Bj^S9S~2gF*BWnZzC^XP!L@iGNqyVOi|t1D?3gy@FHb1& z+2&Zbrn+4BX!$5&&KFKheGVG0=1v-Ym^Q)9SCyiRUT2%T2MZPlbRP^QxXSDoo8|>w zcBfda=us#Q%|b<2Vq#!Ktas0nI*>w&q%D@lwGHRThlYmen3dbQ2#Hr>AgiXngCzAg zaa2d00YzajCcZ>eh_OUe;u18k=dj^WI>a*i%^fdppl^zl_4V~5YHX$}Tx@I}i27~I zJ;8~E!KH%<@JB%r?1~7Bx}X7rBW3(VJ>}(l>ihfqSw7j$Ca#=cWz^O}R?ExF=ij_} z!|E|C1CwrmjB~&M20NLY$oh8>Vl5Y^DsQfLcX#K6imAZ0cs%e4jEU)HJam1rH&Y!k z@ScCw?CUc&!rkdgi^G{}YiXHS85qiHQCh!R>wq50e(EEH_V9@s7|=;)!1YlzO~!?S zvU1b>=qMaLJ-s^XWYJSDJ`N65M35I^A*+)YjPD^ax(#<9hhTx_5^ef5`Vd@KS4IM) z_iK0e#e9xJ65W^k_wO5x7d)X&VmCAx5C^_z%KfysiA-tLTLYI)Qy|F6yc#KR+q!{R zOZ5AghA3ou(EGmoqgQLl4Um-x1}~9CjW7DTB>|r_ud?{*q8ZvVa}zzp9zcS_2^LRJ zPxliO6Z3Yqx3gt)3JQ7-T-gfbLtlSi-x_QSBT`V}@?fTa_b@l(^ALFh z&D1z5;+!M_G1I<#X6EK;eP_VHN4ktqE#Pr9@PgLwL> zGe*L`MZ$M8zRMJC$y_PSFDUT1`8J&8A_JC{MY36JYTUW}zB5RK5hyK-p8183NJbOP z9nx{(g#3I!N*0Qi`z`)Oohp;y-V32I#L(1$`#y85xb#gf^*8;Ep64QlhKB4g1;xcT zH_PoIhKRme%7Kg!Gor7QhGME0z>#V)3NxZIIl*QmW+ZtJon5kEHcW<9GuL|){H@K*Rx^_LUG@V4s6d`EBgn^=V4k{ zwc*Ogj@d{M+6Q4iF>ov>jW&PeW36Ujun-nO$evq%i-nFZ_Tt4>$mr;(O%VA(%t~w5 zhoS3XGF(H4&T=h0!W=5jHJj+i{n0XV5~3~sxk5X9_6yg#o}O2EPfuRh+6JWxx;Cw! zUo}S`wx|k01`r5*7Ed~F0^;i)lHti3{crRtKoPzv(MU(r#HZ0+e-JjJ7?76t(y=Y)g=qP4kn-ar|OBZn%qS-HKcX##X#SY-sNn*4<8rPQPdiKd?I_G3_aMR4pOirse zi9IAPE^e@FHP)#%%!#ElAVzNZVzn@}Eg2pqL76%=Y~cei{VJE2OS3U7r z&CrlCJ|UrXZjQ{nxg~%dpKFcXdvCqz^$W}}cA~^e@3lBt<(qBoX5AQ_BMnd)W^elF zR>MPn{?F*WlvlbDhc8S|RG@1rh|nX-+n3)X*qa!Mg^oJ#-dGH#H4Y%k&j@{7ls zpArM-D{3zGk;+8u3kU_52g#(x1AT6wr{|bV!0DTfv~*{6c6PQtZ;CAkHgZ|UNbL7- zA4nqFKq#*n<3e#Ucgfg!72CSHK8iyLKrO6KyL)a={9ZpL?Fi9oN~Ueg`=YwGGj)A8 z;3eIxcMsspSQH@;B6?`3s0bpYsCi|*0 z(aC|YQS75qS365MmRC*VA+%5k(Ng6XJ0IXXN7xG_!0gvI2HxK?9>P*JZNt{Q=<_-Q z7;m}_&wCTAO-)TNfSHeyZa`#wH}f@r&HRe{h`3QO{}n32w4N5k=%B|^h24v>{9vqC z{C3@y1k?kfqJp#0YXTpYvg==3=09aNc6nc@U78rpX(5`_i%{>f=ilA^xKf*i4(hx^ z;WwJ+L$9ybBy`e~qo94OISrjEkq4DAQ=_!x<0nUd;BU((bZ<2mi(9=Bg<0YUL2y9V zF&7mpmo+mpx)#7)%ePtn9>(_o)S_Z0q*2 zscH$15vl8+964r>e*GFZZ2$Ytq=f0JhN}9j%|nq!QLdx&4!lyuRN*V};))xXmPNRh z$(5r%#%l>nqyo8fPK>&92|TfWCUpvZno{O z6xSkTl^32FJ54CC2b*STWd`jZ!iedB@$g1f4ZOdtx-K>zf@nQWOkfKNcw6!{ZnG1v zuJ*a!PSZTyL-P zh`ME?$^1%6_&yZw+~XOb)#pv$L<3u-w#zv{nMc;k?X9TS&g zQq?gkvR_UwE|I0KBWsS6Wkho11u|l4a0HdzXRvrVn4_?V=3Hi-jHxP{YBI9y^Sy8} zcxA;RqohQc`Jm9y3o|?-RaN^OA4^lC)AZtaW-Bf(W=be`47#E5HJz68b+XvUrocQ~ z>*Tw zf_fFbUme=meJ%!LQ~L*YxX!ppeFR;-Z+)82bkCuBHFkR-U;F;a%PWBmgRC3yVUtnj z3JW{?;`IFdjrJGat{W{AXXwlQ28_6Z;HP_a84}f`Oig%8wte5W!e?e?qyZpQjPfTNebv{ zpLk1j`%Wo#AhjNul#lmzkd)6{1Px?U1tkF$g-%L*z#c@pe}}-)l1f?| z+W2Rd+xs=oMNV@;~U_{gY2c+rz0y~M7LAhCSatuoN+IJnn*lzw}G^r?;(qV(*U!M2o-H=ZZEVD-S{ zSLc$hFfU?8Jxk+kFpnn>*y?$~l(wd3!}$1kHP#U;mb1FkdQU>BVXcGTde9o>wjH8x zlFxZPrMOJ6WEA!K_dvXCRd^{}I+x~Wfix((hYJj8ZurrZx3^S3`I2#a@GWUHPSZ*mdFV)uN=&$WK)Sv)OsBuN+DWCP4K;Y_XO+e>e4o?=pLFL$;kC^ zC+dcj@G^6@Y1ZPuOMXQ3xg=PnKQH;FadP!IG4I6B9BX!s^7be%+50qWZ|jJHI*dC6 z|GurO0MmAoJLhnRI5GHU zjM$yf1k%X)+)O$jHXbxmCydX`pi&GDE_*Isk?s|jkVugaj)kE;r>|$_oGD$v<*PgYZA43{M^h53jnpLsJ_d4WjX;@;^bejb7 z6j9x%xBC+}Wbf84=8I>rxfiGwki%dm1tip>{T~S)cy2@xVe;HIOjg5(RVr6kR~G|g zVOMh0vWc9Sf;Fh+ynFKKlw2J$j8oqxBS#cLLIFNxaoFf1W@N0b^s_QBz`U-xJ#$r6 zEmKrLi*k#ZhG*(3ayO(7hU zP_gUas42cY=BPhtsl+cIe`~n&>PV2+X49H?rDbNG)L9)L6c6<`>_RKokbJQ5po)7C zx%boOM6Z}=C?tlFCH`2=e_;w)z;q{6eyQu>5nOrb%0#k z4lN!8Q(pUec?TS?wh_XLYu*G+^_F0O<}%HR+++;Z%GT{T=;Y?`!}r9_Qhh1ZLW2(F zp6|}q9DF7hbSWd_Za-hSex@xGJMMOHX8S4r&B6qvkBe2+01B(At*wx|zV34rVv+U~ zn!mmM-9ta9VNvlqXnHTjtGz2a3xWm5u01yxw{o#`7V?%!O{AG|uT#K3`&mzMwu&JM zdeF7X#>X~y$rkSP)#s(nZ9L{@4vdH8N}80gzJirIAhAtqX*;V1a_HsvTP!CRijc@i z!2?i?Xw&iP{yr;~nc25#BVi#K1Mn~fb@$PWM_5c7?9TVyy{FyH8AW%HaZ&Yiop4V= zLRXbulMkKe$}xNie;9(Fu}-XP{QWzIq~i(7Bj@d+wWiWiECcs-d#{5=SF!WSufr{b zU-FhO3oarYOm-(XYp`*TbD~$>+uv%-?BPF-Ro%iLnV$E82?}(@Vw{*RtF(lzXr4)A zH@x0aND^ril6eNcZ{j<&5ccVvK?AlGD4Rp$P4|4fx+nh#lS!xEWBUF zK5FTd@Xw{SjP6(o8G}Op$th2 z7G~xWzzNu^n6?S<6Z6GL*x#iLJmm_-%6D?+3sgzXl5;isX+!{|wC`&REU1?dX93(tg;NtA&(#cyC!hfGPC)j@gG)dfoDak-)uUx^4g zoB+PFi;5>AA`|x8e)-{Y051*@Y+oWV6JL0gFu7Nf=ycd{LA)vbfEZM%5O8*OW?iUw z-a7+0CD-r;v`?hP5anXw(NXWy0Sx~>??%Mo5hn=(beD;V>42AyuXO5@tzP)zLCDI= zN=(<6FD@#|%AdYTlOljUsHGax508e!`hQUSJ|o-QRFb|Hi#F3|jULrbk^EPmpRr9< zTN5fOR|v~|_Q`Nv(Mi78QP3{=@|+>sIp&7=JrqGOhs@|=q>m-3BycW20}G_}a#G|a z`G+m!&O zoozPp+w_t~rKR!qaBi_-;pG>f8?-1a^;7t*`o&vUNM6A0guAInA~_$as8IVO2p_+f00e zjM@Zgs}emd2Unfp2qpyR^Y*~R#8P(=3h#(H%IVHLm_I>*`!&TUrM*lU!0I2-oB2(T zlhV=_=0`@3o%Hon;R}AbMFW(r#@~YO!#AD7ETyEsM{YRHNK?pL9D4}?K5N*x`$b); zO3X823&8;e27lp9x5dGR_%LI)#>9}uXU-hjaVYz)T_nI#nS2UqQyRqvIY-BagJjC4e=GLiDqJTd%+ZOkA_?>AXvY%XNPIadx8-o1M#3z!#g zh-dC>s~Wrc4!{j*riv*c1ub!cAfu;2FPbl2$d3BB14Is)=6gDYc%5VEDRDy2!2-_Y zXG16n@5Jt9I$y5E9n0lD2UxDyM$3>Tm&~4TUW_WO-gg0%*UZw!c0;reJ@$FR86s03 zboGu7Wt!ImR_Z3;q?YTAh4f263_Q=KEp8hsD>afux4(V!1wNJsSY&Y&QPy8Qk2F~H zOy(v5iTrGp59*nunU-kC4gXjq1ivE|YH`nxDcuJS!RO8FLrM>IUvWcmN^w1UisI+N?f!mhJPn`|{sqb%IsT5*y{JQC`71A6 z+6Pb@-r4r6vpvt;rX~ZcCn1NpWkQM zPP`9GF;On@{&dX)`)JXjr`N*qR9@=`2B|m0f?lFr@9())5&lj8y}bFj;=+QVX=6~$)~qHrO~?9o_%q+Q+${F*?*-*xOt5`cB8p zQo2~R(LlnFkB_~*k5;6ayuN(GU}j~#aq#fCRCsT4`iuyA|JJP)V7p^=wE8>9VaurW zRBCodiLQFm)imtSO! ztF4HAjr0{ilE$IkqKE0nOQfxqMzGrA=Xt5xp5JK@rpA81`YOr@-Coj!&WL$vDS$FT zM+CAI;Ny9Dx)tf~51W5a_;g5;(y-AZK`Havsp+Y4;#K!PQe2bdNd3p<{mc--MGD|O zU&Tos9-$nOSd~FqyX4ul$8sCO*^nt~F+KQlLr6IGml207ihQLkhoRWJk9oSuQL?Ox{D*_j|^Gctt03I@Ex%))|IH*fbsT=Fm5 zH5w-d`Ipl<_vfhtBh0clVjPH z{HrYDqla_>VryQUt*T;$6$Hgr&J2j_kZT!ELMHDX$x$e6IA8FbCMI^}reSA4s4*x_ zO4aU&e$P>tVO5(mV1qXv0$Li_Mgeh5yUU%D1$jpgc}QBL;F8#GywudwyGlJfb2&>4 zng9F&LJJ1l&%eL+vi-h2P7VhLhej0M)Fd)h`*PKR3fm2-un}O;aF+}CTOB$V6XH0^ zkvEsu1QO2{@rjq?xti1nRRyrRg>@4FzU2Zq>^azA=R zq-0~G@x*09RZJ_?7T`RFhIOxa+?Z{-dz%N(>$;%m%D4VrSEyy+7aIuxNvbIBI%q`# z37^P1bl|6ip-PfYec*qH;|`xdR3`M_Y~EcbO_#n$H=%xSxy1bO9eeV{OsMw%o6)N} zH;e=7eJJK1zm(B6aAYzn4H&mPUnx_#>gZXXUigTpKC}*i4E1O`NAnbjj2gJ}gFbxwzc1;U|B__35Cb zgac1Z?Zv={u~W3^nQpq3|1gfDaD9G})|^!N`noy-`{|13ds9<7O$JqJZFz(;Q&+$n zC;W7rfk@F$%Csfz_3L9hN5_+J+u2V!kQ;ACHa4i6jg8Iu+M1a{=99#2S^~glHtD1# zv9!z!wk%6-5z#I+V7)^Wwj?x{y%~fzZ*0z)E^*+fiN!{7xMlGfIf+%*+_IW#5*BFD ztgNk50sXu9-Xi93YYv_uMKq=V?6lmp3sqiTK06lwA3~Y|O^G8iUgfHwe3s4o7_z^A z9gS_cuN-@KZ{(W5gwjv`V<8f)Mv8&?p^;7i4u(`QsHC?Mu+jPHo zbifN;e#^=N1^~)FS6)5F(@4>HjF9y~|1gN;7BV21Eb$k@_M_pC;3wZ6#6BpfedjwW z+uPH#@W}hRHmdp?t!#8zl(xzxSi}V%p_+QdmnTAX4^#|C_tOF$i&K@wEusCKXPcdu z=UP)$C8V#d&A_u!P{74A zhVJec1N-~?%@1d)nfK&kt2pvyV^8M_b8H4Y@fT5$`E-F8Pk(G-VF3Q|s2;fJpc1=@ z{kge01rRc-n3G{)VYSye@7&ML&4mV8Gz~~xORrBqB=&jVcrPlp3g@G&8Sq-gPDS;Z z$1R6WT4pSoB)ioX>0W1pf`WoM7g^EKm{WDmghYL|Q4plGnr=nwZ zEXc3BHQX`;Ual{$ed-ID!2dw7*q44SLa$t`(`L*aF8uXgsc?S=GXEv+<5=6@bO}0O zFvF`=!_uTLuZ=h{a96X+785u z>_?$E(>uLs%9nE}RBSW}D-Ua+) zHbq@&6ph$1c-b=k>V643g!dqTd$T2zGba=GD?{;WppoB47p?pcjyW~=T3kNdT zP|7h`iZGw02Q%*3^M#Xip0?{;w1L+3ygw>G^KMQ?wlt=lYluqrWz-1rC@+{V4Nk4x z|0B6Z>A~PFA#^CQEdZ)Ai}Ttc?T3!i`vM=v&BK$OVf47q37mRGHP zHiWPqi%6ijv}9k5NW{sv(=F>g7#4WgU|NX@ zDmiZ2>Jhj<_V_u7$_JdKZ2#Gp6<}l!~`M+2F8J+l2QU%B(Zhp$JiG(*@S*> zV^Q@HG=QE~wLz*lfDgpa^13<`t}*SxOboaWMtroiKDg}g-r@5z6)nK!!fI|je zAo{w6x41+Gbw(;O|8Zz=t@M?x01T(kAIx|4^71Nsx%y>UjOq|Gm`F_sBH;PvFl5FZ z2&+bzvMcMakWf)##5yBj@{ zIFIc@{oqYL44GGczV^O-td$4MgHF9qHcth4c@xvcoU;p%zXCb3uXt-%H`T^~(NP3;5S6M{y|EMFD&z|eERmMkQRjUk;jOI}Q@a}_Z2S0^< z(R;Z3Mu%r?noCj4rNKFfC6y++)>2-{^gU5e#&ouiw0}Xf!Al2699zXUq^& zJ9G1m2vEyR>@XpT@s8jvjTi({!SL>c{lT^HJy58qM0gEVM?E;6!)K-AFy+ypp3wAh zl)p*GV$wq{u9)bU7zVB?ApR?}o39JY&(HT+#-^3bDj*t9N<)Z_`|M1})1imGqA!w1 z)!l@LeGD^KW54JKjAkQ#%Qg#NI4S6VGCqW|jHSS8IDBmuZfh)^z*MkMaqgNEqNTf! z-kL5HL@3V@|Hsx??y-Q`gMQaK zW74AcTPL$8f?hP*VTuC~{mfwu{_$QNiH0~QGK0SrbbPluz7${8D~p#}mO{vW-mLdr zi!{7B2#pX5By+9^f?wX>9G{%rP{eGafm)hkb9kl5%FJ;R>|@sSKkx&J9;n4(pGJnp z!y0!qQ?y1lQ4MDzHa*s3QS>nUkG&zIHxoiz4_OWw45RI;FGn&FnWPEuiFsOM^Tr~P z-z57y7f^bqrCAwMLB({IjJvN?^Xb#X^uhvEDXmJC+m_Y86cBp{n}qBJRa|U9rj?VE zL#eEy;uEG3nO2GHvn+!(H<;25(b(zNEM0b++R8sOQADG1lhv>@jezGc zr{=-Kt@&pf8kMVu%kAkV{rT0^_W;N0$b||U;_Die`t7>$a=XxHdT6L+L#(zlAgNF_ zUlVUxW2c*2zb26ifk_PyCnt1EiFmtQ8x61Y!~7BZTDy#+IM^ht6X@x2`kEie5RP2FSw-NET^H(W zqX7&o3c=Gk==9u%ccy zh2o^MBQh=?ZEy zMtxe&%0>VA^L6o>Syom{OKa-@pnKs8(AXYM^~U>4_G&;OBsHcKzVH6n#6&U*r7OFF ze}_`W3o@duqB0rQw@k1FNG4rd4v&;;pOr8a78d3NHvsvmn2O3E8t9Os|LQQx?!gZT zwG~ILF%y(4P8&;$bLc1mZ+GAbzEoSxjq2-upkH^|<9X1Slo}UD{RH@f?*#PuQ;?CY zGSR$hf`Qm+j#B?XW!wULc2qS2N|ek?@^?m8J^~a0k`MS-ud2rjwO!HC(H|JG)&fxv zuie}uGGzFLR$N+Tu$oUCP}0no?~Dhz%F5mS>4%v6`!I|`ny^F)i0_pdxOsTWB_Y`+ zz-1W_5KtZ{_M9FO&QidCgOSrMM;9Az!l-4-sp)k>LUny}^DRvMJSGw**;{KHo705` z_mh{PL%jfmf*i}c(hdPmn5HC#c(2<_yb`VM4+!mWs_rfX~Ih{l@uGI9O#%MVy`acSn(&uCo zBO`UQJ!He%x^S6Ryv^v_Fcip)fW;rcy?Hua7dv2?8r|jpGAG zKYXfJeAj=iCR{Eqp7>A>XQBp0wdGCeJvdJ{1H1ec%YYlN!w1sGH!M%TsO)*)q4^k5 z-cE;aHBnh!c6P(;++2eRfR{|(&6MF05uy~Nq_e{O{L?0^%pX6Mn*+(wM5Km$hwl`6 zLoJ|bbGa-A9uX@7l_k%!UE&6pJ>9seG8BE9J1&5%7O9FftZ_durWD5Hq)Q}L7`U@d zfe;I~jK_MS4+9-NzPxxplB)BI1-v93DZpkJe{+-iRwM1VKvopqXD9WiiGb5eMN+V0vQ0lYSUKjH5EHp*ogDf1BjDT~SfN7fmT@XZqx> z&-yd&FqKssiXjRW01l;E-dj{E#J*NB4-XGl1%=*GAhyC?`lU^KFkkb?Vj$;C6LaKI zl?Uu)dby=d(+b8Ip2nj9l-cs_H9Z5vRfB=Ou8Yej_@3X*)sJfNZy}K;p=PoWh)(Cm zKaK+*(NB(rbHVbpuTMx&L}cG6G&m&0_~!CE<$Uc++BZnlG$Is4#NhiMOyBZ4df=-4Px$(a6K7 zqDH3e#3f5H8k;_UaZ|5eG?tvM1%tjSd-u^btUcB~tGh^v|u<4ZIKxA*?9(ucP2xq%4K@T74u`R=@S z7+NVS4WLTmmF>z$z27w;n@(NW}pTC#nk!NKO#OF8h@K599w zl&sd!{5hmQw}LwnBNH?8Hoxosdv2ex$w?$qpt2}Ug{@=DQ0)YP{|_mhoP(9)))^W+SpNYU~5HMR&(FpXi?@4NdS zKauC_;$BhFgTV~RkO3`C&1VYo@-xpXrxD@&K%~qVN7QwbGgKmq$T(hrGAZ~eHtuXp zb2B3t(A;YnZRld8Gff{#3kXFW7Cx@vM{QN?&k((9$La&(OYL8G9qy{Ihyg!(tBgQ? zPkBa$OqqODTpSz&k5Z2iC;AI6B=0We%&5pvzd-XpDysKiRMb#)Zck?_0AaNuRCOT6 zoc69#gp11m1_+r+N@&Msy ze4r25p#AsXQ{9>)=jP_lg((JcwW@*GU8mY={OfveQWAr~lYAK(z@4Tu(ZuEqOM5u% zdq4{^x+=Uuj3ekT!G{2u>j7+wNk3*LI13SaO7)SAg~f9fa z>sxho0{QWOVUVu2B3On~s-is&uJwy04>*ioZns6S5AL)~kMLr&7l@-VpyH**_y>eI zc=FD`R*IKFDIY5!x$f@L4RdqzS1?BSIiOb(=pO+vmQs>3L!7eA_7+jPk2+8rGm|ML zB@W24>7%2UNGGB~Lg+h_rMKU{M3KHzV~&}_g*yk#_4uVIiPQMU@L-9)$-q|Ed!X=D zo>F@IiqNCt-^jG_FUaIZfg=SL;%K{@+`8o#3X0+;`Sm}FkqILjP$j!w@VCb>h+YU@ z@V4&Yhv;Nyzs4XrOgc8pOxqHk`8uT*c+cf3#q)gMtEnjsLk!4`<#zV)Y~8IJI6I&;B3t@ z#v`*ms~wvCE8yj#hzTh!Ar)iteUA-CLL?_79zJ$a=)CU{NQ3{`3L3!c(KEcQAz7y6 zgr-2+4=cvJ@p2~gJ0W@cLP73-FfR|mWT%%|S79)B_gj#{^w#5XX7Ch#Hni zcN%Jc?jmvVz(SAr2+JF|AMy9*9u{nUP_A`%Kyj82zERh}H8_cSjtZS@|0 z@!1gpe{nIb$oac1K}wwFHzVZL045aXDW~c_Q&pv!W_wy;<^cxE_hc8p z-TXT`f6TdETi-@Wu1@qqtH$$}j~3e3!FdJwjc3Vg z-@Y-fZEOtm_4hxf{CW(+pMOeH1*fwQa?SMNn@Bft&3(ov~QrM2&nvfZnUP$}Pw)I!SPxbX#KhKmI zOMb}9+eG*@%~xt)!GL%QOpNS=a);iUsNChZ`rKfv;+VJRDCMt|7kjKLG>b!tN zDQO^GH2n=AfNn&8C5U?^BE}t*)7WrAz(sOYW&x`Q5M)%a1bCJfs}K>oa@ik`2#(Wz z@mNhwZSb?>X7)waucVM2*005?D7QZh3r$8x6aWL0pH7@H;!ge5WmwD^H>hm20xnZ* z{II3Geb)nIl*;(Fdc{E?b!cp?19SO};?xg0q}vZrC#tWYyS0JLDZs1qbteLTsMPHF z^S%9p1D_VVnsz@pqzw{M(netE$1LyUvR?yFBKgjXqgUt7XY26gMYOYc{@fjtT)^oQ z;PdOMtB5c@#3)DxtZrT5BO;c1_O(I52Z+naek(NMnDc3 z*#FT83V;?N_Ah{(vAT==N*j^wZL1NZ$gv}iwJj^B0So<>Znd(o(E2EmRc|6XDr$Xa zUE2v-wkdXcoaNGdCnEBzk?WMvbt3-zR>wr9zZI!9Aj3@hA0^15hxWHbSWlMN3OH^= zzG-#({HzSvsA&bhaxV-cWr!XY&>UgdoygAE!p|ij5E3e0pIx|V)2?V?Ep>Go7`;mK z{<)SG(Ck3|AhNm*SOyqy)Ik03_hR91nfUekIdJ_q9RPkIhbA5#UYXT+K^(A3#LgFv z`xAVM?nDIe`u~UscjDiGWz(+nM-6%QG(4eMGY6Pcx8g8OQHK~lv7Cy^f!&K2?sa!d z3I8nhRRox2={)#+A5p}ZO2EGZGfnWjn-iEp;?U%4%r_>ywywz!oOhdwXYP#)RlB=3 zDDgjwR^14`YFUh&N5lXjjs^&Ec)y{O6m2j$8)fRtifC%lDGbCE&O0(lK&^xnZDyfbxINBmsfYtEI{Zhob*PW`dRV^8wp)jC7>gbEi--~_N zf*oQ-M4=^A<6uqedn%o-4V@0G+mF3pb8y>!=Fdr@A*oUL9gYh`YZb zr^%o$>(i&R^AIdbZ(@*c7`F+P7P^#5Y&;DOAsLUjdVR^4=;X%4o#BpBi@@yQCqZa; z5?7^|Q?@C(^R7q)dB3xCI0>eI_S_!s6=DmTm}-vFtqru0I$m zf~{yWkE~$|83hhjvv%;D^F9gChI0J-`dI9 z@~?eByA=T(C%lJLO;lSr#Kq?YQ38?Aw153FwOnSNA`l#w`n4|p!5O6}c=OR*CFsDw zK+=?npokNQ2;v6t9$?LC_t&AaqKV>&2Z}V}s;jE~B4gj=qP0tfE1!^x=j%@jyw*s} zX+v-cP|GqnaBj;>D)&6-`d2|Ukn|q~RVIVngB$vE1(fQq)L*?14c12-+?`Idcl}dc z=sf9pd0LSfOpXN@WqFr-COO;Uo&~1twAtOP4Thte0Yw>iFA>9sh1dUrN+W>BKo2*J zldUu1+d~616DSb3fAw4d2lCS=UQ0_$Hw!DPg7;la)3|Ulcf+hLIn0JbU0}Ef$mC3u zl0^T49+>IBpog+TaH0Xi!69`l4(OII8-rkg8$5Q7)o#oeZgM+(+Vz3$j!(6n>)kbX z-7kQQr|1-{j$w1fOkNdi$ogq(}k}3b^#@{cQ1FQ%B7w8Ga z8g86GJTjID{f2hu3f2B`g+d2^G@=9YubUw}RDmdWA4MWKfm!-)LD2W&?kpJgIZ+eb z4QQvJlctpa(R&73C4YN$fJ9w3-SM`*gWxh+Dd5ok&|2sKX*LVxeMp0do9ri%(!X(h zb;IzK_3wg-x5Q*JGodR09V-<6-(Ww)V^TH~tPTFRa!G^%FYDKIgK(M!dmiBZR8wNy z28sZWkJd;WYVfSy#dh=^m&N-?g}+TW96O#v3pig2kd8%%Xhr`E5F?x~sKT&)ziiVI z9S+4bGz!p&f)aqk$iWHs4;YO#3YCCBxJGx+1pt6)+@wF5#}SwkMQ`>a)T^0ce903G zNa$}p=FVVSQb31z!ZJ?m6acolJ$uby(z1(g_76Cfg)1s5wiG-mlwmV$Y7h#)XWErr zIZxe0+WD}m4vGlEhiyr%oZBLFyhBiBcN?^^*oR@PR6s#3CdS(gTJWoA@<<`8HI7zx z>Pz8|b#xgutCn*dP}$9iw`mnRg&;!HAZ$xLsO)VQLvAr5lp|tv4~>)(<@G-H+g=c0 zAWi~K3}<+^;omOb$G;R-xH`fj2?&A-DmzJ9IY#3|Iu-$e@jwHe2(g)}yZj`(0zl2C zl&ZXaug{4ny@LL5X|uf3E^dw8m`Lsq;^iyhvja-$q&Lizr7+qS4&~5LUG|jQEz}H z0i0mPEvW!z04$kle0YFlu9Q;PV{8E1*~zKpY;U%{1VBu5tTtpw;M-D^fCFX_ewVd@ z!T_HM*u9Ntf`Byr0wK(K_eY>r(60Scgek!kOv~1lAQ;w~e~|1e11{~tyM+UjBa52Z z#kqRdgOl&yZCYSefg0OYdk9uDI;dC(nRW@!L|X4HKen+J)Oc|Cu;XDoE3b$n+G};G zHS%iRkWxT`y|Oy3SNTWRR+4UOztH7?vi%#@1# zx_BLWYO5Lljc~O1Gs0v3%;kG@3q<(|?B}JM2J~#WbPIBEH;w4o|3PnYfcj+o9wZW& zd24XSD9Cm&35awQgs=D1`FE^fE9P%0jWY#FLvKH@^9&;!XxFoAdJY>0B#eY6??r1&Sn9kG&JVB66H7XOtH1q|4ZvjTpWn^fI7s0iL(%fCqWaTN^!}8CHOY=H!qqn%D%90^4^PoF zS@LxRvPw_1;~I`S{%Q6yP1rl#h+%3us}kUlm01pF)|?+K8mehHT6Det%VNyzh~_Aq zq8U>Oed4ROVyIKIK|zfmOOzqSJQrRkM@uA3E?nw^OJ_`pS_q?{qSEZKJ(k~zfPkPr z{ucr=p+0;2Q>%qb$aTDYVJD87Tkj7JCgB7MAb4>OXI3v?v+rOgcw{|av_gkf?|EEJ zmc^$7GW=()o+}!lThx4fuI6@j%9mn^=Y;;E87>m4VfJ(7x*u-lM>_zUvOy(WdiO4f zXt#oa{(Ar<3+TnZe)r;sQUj(EhY9n!-=C?31BV&18rZw;QBhZ?E7AB*{$x{mz^K_C zdGhe(e3TF>C-w|Iiu%VxMh)8@Pq)OdLY@$}#Nyzn5(YB3zdgo$J9l^Y=I zeEFWjgaIj&c>WcOR|J<%(wHM*c)k&;h>+4Elk%s+k6Fjm5J#^QolJVIy|h+M{ctz7Ghku_keVJiOX2W?-ET|-*o3A z23)g(eDx|`C){qr(N_ZPj$$y6Y@kY1#@ESTRR~}O2)MA@ewvOkq8Px#JP;go^)LW~ z&LV)?@t3to1`KcqH#+uTeU0C51O!twQvW{=rporbFaJLbrUrQNgMK$CoAUbf=q2p# z1BbE?pS4XMT`JBG@KAm~U_~8RnYp&B@njK{;|=e8ZEdoIhlr~XJGJaGEF`27ADoqy z_LEmya%tsJBc76c;=LsvV zz(W+8|2$yjkgB7tD}eenD?qLZQkpyP=+;AnwPQ~^6e6gk+w!U(kkiubB4*vooVY?x z*UFVx4EcYRO_>b(8NpSPh~Q>BFbOv13ryf9Y}Fag;7!84g-q@a#;iroOu(lE5Px4-4CwE9a}mGq*`E22Bx z`A)nus`YGGzB7$4vFU!qs|P4wmVmWvY5Rl4=H|@YTp8HP7o+!mEG#w^Y|68=QRDeQm@?RE%A{APcE_c<)jK{jLyHnkL|E z^%5u%YJUCe5iCa;c!sfn(a=t+k|WIP6UHFdnlmQ8A;C%$YZ%d0VK1Cjpvo#2LS@V+ zcAVt!mr|PkH%bYxwad+-0i}c+;P+1l@RI6NaWMu73CY5{stx0G`EyHBD}9045@$xu61r(eEPnY#xf`L?@)Z zs0VmhPk3MPPhrTg=<6QPf_2}adQtvsDwXdGxU-8MjSGY2tFe&ScYss5DaP^W%~ct2 z#_4tm?kN8W$A3~wLQkl&!+^h7okp6=Nq>KTCkf)5L$ZBWJGfgg6%16VFquWfz{K1> z6sy67!~IcC2!*A+57)qyYB?DW@K&36(Y(U?aJ|7ndEpkZ(#z>&Db-X^f{8`Va^eH?zH1zAQi;Lag@&qD} z#(jVd;{k_&MQ88-!5L(bd+f)A<>#Dw6F{r$wB9Ozls>07X@A1ahaWb5y7FN~Y1zmral4X|{J z%I#yD?Vj`Rk+R1`7Z2YFSJtgIl=HeXrP%XRwG(g^=K9s39*=l_07K?K?_SGY>zW&Z z3+$?@tEzB%Q5Cpr{f9@XaO+}1Ej zq0qF#i0`BWo{_miH=ZM1jGsA!HaLg%ZQ5eAY}!BWUz}YNW-VC3xy0!1vM=k~qSw}l zRzpS&8C~}E9f?Pr%yo&4jcoyBrF!PJLw&E?Tl%@3Rgw=Kch@zme$QmYo@m z#VyKfA3Tl}S$K>+cDoHT^1)q?l7J_7U4H!dvHyni6LtLg1Oib-wb!2+`~+YmdS{|5J0~T|~EB{OYq8 z6OM$uV+QRwdcy&nFF)YI1Kddh+fl~(wT)Mr$=23Zf5X{*z9GC#vlMt#rYW>WC&}_m zn|CEnhbhNw&&CHWr#duIdmDF<>W(C?7A|Erh8H$VT=H2V?KJKuPtXqa%DJ=Sqj;l3 zf+=XR_M9IZ5?a1G|M;PC3^=Rh=23G;ZPnMeE^8&OcK0K?6(-qj-MV}K{{M!%dF{;Xd}mC}%&PM5?fGfJ@Z)Th{-NAFP-|1x z-pQXwBJlz4Lk8Mz8!`kD_GoboFyt=akR{02wP>`2YX_ diff --git a/docs/figures/cpu_interface_write_long.png b/docs/figures/cpu_interface_write_long.png index 17e64c18f0052ce41e4f53e3850a1dec4a8304b4..ededb03329cc565969dd9be3f2de8782532dd664 100644 GIT binary patch literal 20353 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 b|MNen($nM<{<#Wxv>t<}tDnm{r-UW|lyX{o literal 21950 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
pq1 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