Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚠️ remove BUSKEEPER's status register #635

Merged
merged 4 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mimpid = 0x01080200 => Version 01.08.02.00 => v1.8.2

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 23.06.2023 | 1.8.5.7 | :warning: remove **buskeeper's status register**; [#635](https://github.com/stnolting/neorv32/pull/635) |
| 17.06.2023 | 1.8.5.6 | :sparkles: add new **Cyclic Redundancy Check module (CRC)**; [#632](https://github.com/stnolting/neorv32/pull/632) |
| 03.06.2023 | 1.8.5.5 | :sparkles: re-add (simplified) **Stream Link Interface (SLINK)**; [#628](https://github.com/stnolting/neorv32/pull/628) |
| 03.06.2023 | 1.8.5.4 | :warning: rearrange bits in **SYSINFO**; [#627](https://github.com/stnolting/neorv32/pull/627) |
Expand Down
48 changes: 15 additions & 33 deletions docs/datasheet/soc_buskeeper.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,21 @@

**Theory of Operation**

The Bus Keeper is a fundamental component of the processor's internal bus system that ensures correct bus operations
while maintaining execution safety. It monitors every single bus transactions that is initiated by the CPU.
If an accessed device responds with an error condition or do not respond at all within a specific _access time window_,
an according bus access fault exception is raised. The following exceptions can be raised by the Bus Keeper
(see section <<_traps_exceptions_and_interrupts>> for a list of all available bus access-related exceptions):

* `TRAP_CODE_I_ACCESS`: error during instruction fetch bus access
* `TRAP_CODE_S_ACCESS`: error during data store bus access
* `TRAP_CODE_L_ACCESS`: error during data load bus access

The Bus Keeper is a fundamental component of the processor's internal bus system that ensures correct operations
while maintaining execution safety. It operates transparently for the user by monitoring every single bus transactions
that is initiated by the CPU. If an accessed device responds with an error condition or does not respond at all within
a specific **access time window**, an according bus access fault exception is raised. The following exceptions can be
raised by the bus keeper:

* `TRAP_CODE_I_ACCESS`: error / timeout during instruction fetch bus access
* `TRAP_CODE_S_ACCESS`: error / timeout during data store bus access
* `TRAP_CODE_L_ACCESS`: error / timeout during data load bus access

.Access Time Window
[IMPORTANT]
The **access time window**, in which an accessed device has to respond, is defined by the `max_proc_int_response_time_c`
constant from the processor's VHDL package file (`rtl/neorv32_package.vhd`). The default value is **15 clock cycles**.

In case of a bus access fault exception application software can evaluate the Bus Keeper's control register
`CTRL` to retrieve further details regarding the bus exception. The `BUSKEEPER_ERR_FLAG` bit indicates
that an actual bus access fault has occurred. The bit is sticky once set and is automatically cleared when reading or
writing the `NEORV32_BUSKEEPER.CTRL` register. The `BUSKEEPER_ERR_TYPE` bit defines the type of the bus fault:

* `0` - "Device Error": The bus access exception was cause by the memory-mapped device that
has been accessed (the device asserted it's `err_o`).
* `1` - "Timeout Error": The bus access exception was caused by the Bus Keeper because the
accessed memory-mapped device did not respond within the access time window. Note that this error type can also be raised
by the optional timeout feature of the external bus interface.


**Register Map**

.BUSKEEPER register map (`struct NEORV32_BUSKEEPER`)
[cols="<3,<2,<4,^1,<4"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.2+<| `0xffffff78` .2+<| `CTRL` <|`0` `BUSKEEPER_ERR_TYPE` ^| r/- <| Bus error type, valid if _BUSKEEPER_ERR_FLAG_
<|`31` `BUSKEEPER_ERR_FLAG` ^| r/c <| Sticky error flag, clears after read or write access
| `0xffffff7c` | - | _reserved_ | r/c | _reserved_ (mirrored access to `CTRL`)
|=======================
.Register Map
[NOTE]
The bus keeper does not provide any memory-mapped interface registers at all.
21 changes: 0 additions & 21 deletions docs/datasheet/software_rte.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -199,24 +199,3 @@ obtained from the <<_mcause>> CSR (see <<_neorv32_trap_listing>>). A full list o
| "Fast IRQ 0x0000000f" | `0x8000001f`
| "Unknown trap cause" | undefined
|=======================

===== Bus Access Faults

For bus access faults the RTE default trap handlers also outputs the error code obtained from the
<<_internal_bus_monitor_buskeeper>> to show the cause of the bus fault. One example is shown below.

.RTE Default Trap Handler Output Example (Load Access Bus Fault)
[source]
----
<RTE> Load access fault [TIMEOUT_ERR] @ PC=0x00000150, MTVAL=0xFFFFFF70 </RTE>
----

The additional message encapsulated in `[ ]` shows the actual cause of the bus access fault.
Several different message identifiers are possible here:

* `[TIMEOUT_ERR]`: The accessed memory-mapped module did not respond within the valid access time window.
In Most cases this is caused by accessing a module that has not been implemented or when accessing
"address space holes" via unused/unmapped addresses (see section <<_bus_interface_protocol>>).
* `[DEVICE_ERR]`: The accesses memory-mapped module asserted its error signal to indicate an invalid access.
For example this can be caused by trying to write to read-only registers.
* `[PMP_ERR]`: This indicates an access right violation caused by the <<_pmp_isa_extension>>.
108 changes: 18 additions & 90 deletions rtl/core/neorv32_bus_keeper.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ entity neorv32_bus_keeper is
port (
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
Expand All @@ -60,37 +58,15 @@ end neorv32_bus_keeper;

architecture neorv32_bus_keeper_rtl of neorv32_bus_keeper is

-- IO space: module base address --
constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(buskeeper_size_c); -- low address boundary bit

-- Control register --
constant ctrl_err_type_c : natural := 0; -- r/-: error type: 0=device error, 1=access timeout
constant ctrl_err_flag_c : natural := 31; -- r/c: bus error encountered, sticky

-- error codes --
constant err_device_c : std_ulogic := '0'; -- device access error
constant err_timeout_c : std_ulogic := '1'; -- timeout error

-- sticky error flags --
signal err_flag : std_ulogic;
signal err_type : std_ulogic;

-- access control --
signal acc_en : std_ulogic; -- module access enable
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable

-- timeout counter size --
constant cnt_width_c : natural := index_size_f(max_proc_int_response_time_c);

-- controller --
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;
pending : std_ulogic;
timeout : std_ulogic_vector(cnt_width_c-1 downto 0);
bus_err : std_ulogic;
ignore : std_ulogic;
end record;
signal ctrl : ctrl_t;

Expand All @@ -102,88 +78,40 @@ begin
report "NEORV32 PROCESSOR CONFIG ERROR! Processor-internal bus timeout <max_proc_int_response_time_c> has to >= 2." severity error;


-- Host Access ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------

-- access control --
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)
begin
if (rstn_i = '0') then
err_flag <= '0';
err_type <= '0';
elsif rising_edge(clk_i) then
if (ctrl.bus_err = '1') then -- sticky error flag
err_flag <= '1';
err_type <= ctrl.err_type;
elsif (wren = '1') or (rden = '1') then -- clear on read or write access
err_flag <= '0';
end if;
end if;
end process write_access;

-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
cpu_rsp_o.ack <= wren or rden; -- bus handshake
cpu_rsp_o.data <= (others => '0');
if (rden = '1') then
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
ctrl.pending <= '0';
ctrl.bus_err <= '0';
ctrl.err_type <= '0';
ctrl.timeout <= (others => '0');
ctrl.ignore <= '0';
ctrl.pending <= '0';
ctrl.bus_err <= '0';
ctrl.timeout <= (others => '0');
ctrl.ignore <= '0';
elsif rising_edge(clk_i) then
-- defaults --
ctrl.bus_err <= '0';

-- IDLE --
-- bus idle --
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 --
-- bus access pending --
else
-- countdown timer --
ctrl.timeout <= std_ulogic_vector(unsigned(ctrl.timeout) - 1);
-- bus keeper shall ignore internal timeout during this access (because it's "external") --
ctrl.ignore <= ctrl.ignore or (bus_ext_i or bus_xip_i);
-- response handling --
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
ctrl.err_type <= err_timeout_c; -- timeout error
ctrl.bus_err <= '1';
ctrl.pending <= '0';
-- response check --
if (bus_rsp_i.err = '1') or -- error termination by bus system
(bus_tmo_i = '1') or -- EXTERNAL access timeout
((or_reduce_f(ctrl.timeout) = '0') and (ctrl.ignore = '0')) then -- valid INTERNAL access timeout
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';
ctrl.bus_err <= '0';
ctrl.pending <= '0';
end if;
end if;
end if;
Expand Down
12 changes: 5 additions & 7 deletions rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080506"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080507"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width, do not change!

Expand Down Expand Up @@ -232,9 +232,9 @@ package neorv32_package is
constant onewire_ctrl_addr_c : std_ulogic_vector(31 downto 0) := x"ffffff70";
constant onewire_data_addr_c : std_ulogic_vector(31 downto 0) := x"ffffff74";

-- Bus Access Monitor (BUSKEEPER) --
constant buskeeper_base_c : std_ulogic_vector(31 downto 0) := x"ffffff78"; -- base address
constant buskeeper_size_c : natural := 2*4; -- module's address space size in bytes
---- reserved --
--constant reserved_base_c : std_ulogic_vector(31 downto 0) := x"ffffff78"; -- base address
--constant reserved_size_c : natural := 2*4; -- module's address space size in bytes

-- External Interrupt Controller (XIRQ) --
constant xirq_base_c : std_ulogic_vector(31 downto 0) := x"ffffff80"; -- base address
Expand Down Expand Up @@ -885,7 +885,7 @@ package neorv32_package is
-- -------------------------------------------------------------------------------------------
constant alu_op_add_c : std_ulogic_vector(2 downto 0) := "000"; -- result <= A + B
constant alu_op_sub_c : std_ulogic_vector(2 downto 0) := "001"; -- result <= A - B
constant alu_op_cp_c : std_ulogic_vector(2 downto 0) := "010"; -- result <= co-processor
constant alu_op_cp_c : std_ulogic_vector(2 downto 0) := "010"; -- result <= ALU co-processor
constant alu_op_slt_c : std_ulogic_vector(2 downto 0) := "011"; -- result <= A < B
constant alu_op_movb_c : std_ulogic_vector(2 downto 0) := "100"; -- result <= B
constant alu_op_xor_c : std_ulogic_vector(2 downto 0) := "101"; -- result <= A xor B
Expand Down Expand Up @@ -1594,8 +1594,6 @@ package neorv32_package is
port (
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
Expand Down
6 changes: 2 additions & 4 deletions rtl/core/neorv32_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ architecture neorv32_top_rtl of neorv32_top is
signal dci_halt_req : std_ulogic;

-- 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,
type device_ids_t is (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, DEV_SLINK, DEV_CRC);

-- core complex --
Expand Down Expand Up @@ -705,8 +705,6 @@ begin
port map (
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,
Expand Down
10 changes: 2 additions & 8 deletions sw/example/processor_check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -691,17 +691,14 @@ int main() {

cnt_test++;

tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (1 << BUSKEEPER_ERR_TYPE);

// load from unreachable aligned address
asm volatile ("li %[da], 0xcafe1230 \n" // initialize destination register with known value
"lw %[da], 0(%[ad]) " // must not update destination register to to exception
: [da] "=r" (tmp_b) : [ad] "r" (ADDR_UNREACHABLE));

if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) && // load bus access error exception
(neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_UNREACHABLE) &&
(tmp_b == 0xcafe1230) && // make sure dest. reg is not updated
(NEORV32_BUSKEEPER->CTRL = tmp_a)) { // buskeeper: error flag + timeout error
(tmp_b == 0xcafe1230)) { // make sure dest. reg is not updated
test_ok();
}
else {
Expand Down Expand Up @@ -744,14 +741,11 @@ int main() {

cnt_test++;

tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (0 << BUSKEEPER_ERR_TYPE);

// store to unreachable aligned address
neorv32_cpu_store_unsigned_word(ADDR_READONLY, 0);

if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) && // store bus access error exception
(neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_READONLY) &&
(NEORV32_BUSKEEPER->CTRL == tmp_a)) { // buskeeper: error flag + device error
(neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_READONLY)) {
test_ok();
}
else {
Expand Down
2 changes: 0 additions & 2 deletions sw/lib/include/neorv32.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ enum NEORV32_CLOCK_PRSC_enum {
#define NEORV32_PWM_BASE (0xFFFFFF50U) /**< Pulse Width Modulation Controller (PWM) */
#define NEORV32_GPTMR_BASE (0xFFFFFF60U) /**< General Purpose Timer (GPTMR) */
#define NEORV32_ONEWIRE_BASE (0xFFFFFF70U) /**< 1-Wire Interface Controller (ONEWIRE) */
#define NEORV32_BUSKEEPER_BASE (0xFFFFFF78U) /**< Bus Monitor (BUSKEEPER) */
#define NEORV32_XIRQ_BASE (0xFFFFFF80U) /**< External Interrupt Controller (XIRQ) */
#define NEORV32_MTIME_BASE (0xFFFFFF90U) /**< Machine System Timer (MTIME) */
#define NEORV32_UART0_BASE (0xFFFFFFA0U) /**< Primary Universal Asynchronous Receiver and Transmitter (UART0) */
Expand Down Expand Up @@ -240,7 +239,6 @@ enum NEORV32_CLOCK_PRSC_enum {
#include "neorv32_rte.h"

// IO/peripheral devices
#include "neorv32_buskeeper.h"
#include "neorv32_cfs.h"
#include "neorv32_crc.h"
#include "neorv32_dm.h"
Expand Down
Loading