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

🐛 [rtl] fix bug in co-processor monitor #500

Merged
merged 5 commits into from
Feb 18, 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ mimpid = 0x01040312 => Version 01.04.03.12 => v1.4.3.12

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 18.02.2023 | 1.8.0.8 | :bug: fix minor bug in CPU's co-processor monitor; minor VHDL clean-ups and edits; [#500](https://github.com/stnolting/neorv32/pull/500) |
| 13.02.2023 | 1.8.0.7 | minor CPU optimization and fixes; [#497](https://github.com/stnolting/neorv32/pull/497) |
| 11.02.2023 | 1.8.0.6 | :warning: replaced boolean `IO_GPIO_EN` generic by natural `IO_GPIO_NUM` generic to fine-tune GPIO pin number; [#491](https://github.com/stnolting/neorv32/pull/491) |
| 11.02.2023 | 1.8.0.6 | :warning: replace boolean `IO_GPIO_EN` generic by natural `IO_GPIO_NUM` generic to fine-tune GPIO pin number; [#491](https://github.com/stnolting/neorv32/pull/491) |
| 10.02.2023 | 1.8.0.5 | :test_tube: add CPU co-processor monitor (to auto-terminate operation if a co-processor operation takes too long); [#490](https://github.com/stnolting/neorv32/pull/490) |
| 10.02.2023 | 1.8.0.4 | replace CPU-internal control bus by a VHDL `record` (much cleaner code); minor control optimizations; add 6ht CPU co-processor slot (yet unused); [#489](https://github.com/stnolting/neorv32/pull/489) |
| 05.02.2023 | 1.8.0.3 | CPU control optimizations; [#487](https://github.com/stnolting/neorv32/pull/487) |
Expand Down
2 changes: 1 addition & 1 deletion rtl/core/neorv32_cpu_control.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,7 @@ begin
trap_ctrl.instr_il <= (illegal_cmd or alu_exc_i or -- illegal instruction or ALU processing exception
(bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and illegal_reg) or -- illegal register access in E extension
(bool_to_ulogic_f(CPU_EXTENSION_RISCV_C) and execute_engine.is_ici)) -- illegal compressed instruction
when (execute_engine.state = EXECUTE) else '0'; -- evaluate in EXECUTE stage only
when ((execute_engine.state = EXECUTE) or (execute_engine.state = ALU_WAIT)) else '0'; -- evaluate in execution stages only


-- ****************************************************************************************************************************
Expand Down
17 changes: 9 additions & 8 deletions rtl/core/neorv32_cpu_cp_cfu.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -221,16 +221,17 @@ begin
-- as all internal computations have completed, the <control.done> signal has to be set to indicate completion. This will
-- complete CFU instruction operation and will also write the processing result <control.result> back to the CPU register file.
--
-- [NOTE] The <control.done> **has to be set at some time** - otherwise the CPU will get stalled forever.
-- [NOTE] If the <control.done> signal is not set within a bound time window (default = 128 cycles) the CFU operation is
-- automatically terminated by the hardware and an illegal instruction exception is raised. This feature can also be
-- be used to implement custom CFU exceptions.


-- ----------------------------------------------------------------------------------------
-- Final Notes
-- ----------------------------------------------------------------------------------------
-- The <control> record provides something like a "keeper" that ensures correct functionality (we do not want to
-- stall the CPU forever) and also a simple-to-use interface hardware designers can start with. Obviously, the control
-- instance adds one additional cycle of latency. Advanced users can remove this default control instance to obtain
-- maximum throughput.
-- The <control> record provides something like a "keeper" that ensures correct functionality and that also provides a
-- simple-to-use interface hardware designers can start with. However, the control instance adds one additional cycle of
-- latency. Advanced users can remove this default control instance to obtain maximum throughput.


-- ****************************************************************************************************************************
Expand Down Expand Up @@ -300,7 +301,7 @@ begin
control.done <= '1'; -- pure-combinatorial, so we are done "immediately"
when others => -- not implemented
control.result <= (others => '0');
control.done <= '1'; -- set high to prevent permanent CPU stall
control.done <= '0'; -- this will cause an illegal instruction exception after timeout
end case;

-- --------------------------------------------------------
Expand All @@ -318,7 +319,7 @@ begin
control.done <= madd.done; -- iterative, wait for unit to finish
when others => -- not implemented
control.result <= (others => '0');
control.done <= '1'; -- set high to prevent permanent CPU stall
control.done <= '0'; -- this will cause an illegal instruction exception after timeout
end case;

-- --------------------------------------------------------
Expand All @@ -344,7 +345,7 @@ begin
-- --------------------------------------------------------

control.result <= (others => '0');
control.done <= '1'; -- set high to prevent permanent CPU stall
control.done <= '0';

end case;
end process out_select;
Expand Down
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ package neorv32_package is

-- Architecture Constants (do not modify!) ------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080007"; -- NEORV32 version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080008"; -- NEORV32 version
constant archid_c : natural := 19; -- official RISC-V architecture ID

-- Check if we're inside the Matrix -------------------------------------------------------
Expand Down
91 changes: 45 additions & 46 deletions rtl/core/neorv32_sysinfo.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ architecture neorv32_sysinfo_rtl of neorv32_sysinfo is

-- system information ROM --
type info_mem_t is array (0 to 7) of std_ulogic_vector(31 downto 0);
signal sysinfo_mem : info_mem_t;
signal sysinfo : info_mem_t;

begin

Expand All @@ -125,79 +125,78 @@ begin
-- Construct Info ROM ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- SYSINFO(0): Processor (primary) clock frequency --
sysinfo_mem(0) <= std_ulogic_vector(to_unsigned(CLOCK_FREQUENCY, 32));
sysinfo(0) <= std_ulogic_vector(to_unsigned(CLOCK_FREQUENCY, 32));

-- SYSINFO(1): Custom user-defined ID --
sysinfo_mem(1) <= CUSTOM_ID;
sysinfo(1) <= CUSTOM_ID;

-- SYSINFO(2): Implemented processor devices/features --
-- Memory --
sysinfo_mem(2)(00) <= bool_to_ulogic_f(INT_BOOTLOADER_EN); -- processor-internal bootloader implemented?
sysinfo_mem(2)(01) <= bool_to_ulogic_f(MEM_EXT_EN); -- external memory bus interface implemented?
sysinfo_mem(2)(02) <= bool_to_ulogic_f(MEM_INT_IMEM_EN) and bool_to_ulogic_f(boolean(MEM_INT_IMEM_SIZE > 0)); -- processor-internal instruction memory implemented?
sysinfo_mem(2)(03) <= bool_to_ulogic_f(MEM_INT_DMEM_EN) and bool_to_ulogic_f(boolean(MEM_INT_DMEM_SIZE > 0)); -- processor-internal data memory implemented?
sysinfo_mem(2)(04) <= bool_to_ulogic_f(MEM_EXT_BIG_ENDIAN); -- is external memory bus interface using BIG-endian byte-order?
sysinfo_mem(2)(05) <= bool_to_ulogic_f(ICACHE_EN); -- processor-internal instruction cache implemented?
sysinfo(2)(00) <= bool_to_ulogic_f(INT_BOOTLOADER_EN); -- processor-internal bootloader implemented?
sysinfo(2)(01) <= bool_to_ulogic_f(MEM_EXT_EN); -- external memory bus interface implemented?
sysinfo(2)(02) <= bool_to_ulogic_f(MEM_INT_IMEM_EN and (MEM_INT_IMEM_SIZE > 0)); -- processor-internal instruction memory implemented?
sysinfo(2)(03) <= bool_to_ulogic_f(MEM_INT_DMEM_EN and (MEM_INT_DMEM_SIZE > 0)); -- processor-internal data memory implemented?
sysinfo(2)(04) <= bool_to_ulogic_f(MEM_EXT_BIG_ENDIAN); -- is external memory bus interface using BIG-endian byte-order?
sysinfo(2)(05) <= bool_to_ulogic_f(ICACHE_EN); -- processor-internal instruction cache implemented?
--
sysinfo_mem(2)(12 downto 06) <= (others => '0'); -- reserved
sysinfo(2)(12 downto 06) <= (others => '0'); -- reserved
-- Misc --
sysinfo_mem(2)(13) <= bool_to_ulogic_f(is_simulation_c); -- is this a simulation?
sysinfo_mem(2)(14) <= bool_to_ulogic_f(ON_CHIP_DEBUGGER_EN); -- on-chip debugger implemented?
sysinfo(2)(13) <= bool_to_ulogic_f(is_simulation_c); -- is this a simulation?
sysinfo(2)(14) <= bool_to_ulogic_f(ON_CHIP_DEBUGGER_EN); -- on-chip debugger implemented?
--
sysinfo_mem(2)(15) <= '0'; -- reserved
sysinfo(2)(15) <= '0'; -- reserved
-- IO --
sysinfo_mem(2)(16) <= bool_to_ulogic_f(boolean(IO_GPIO_NUM > 0)); -- general purpose input/output port unit (GPIO) implemented?
sysinfo_mem(2)(17) <= bool_to_ulogic_f(IO_MTIME_EN); -- machine system timer (MTIME) implemented?
sysinfo_mem(2)(18) <= bool_to_ulogic_f(IO_UART0_EN); -- primary universal asynchronous receiver/transmitter (UART0) implemented?
sysinfo_mem(2)(19) <= bool_to_ulogic_f(IO_SPI_EN); -- serial peripheral interface (SPI) implemented?
sysinfo_mem(2)(20) <= bool_to_ulogic_f(IO_TWI_EN); -- two-wire interface (TWI) implemented?
sysinfo_mem(2)(21) <= bool_to_ulogic_f(boolean(IO_PWM_NUM_CH > 0)); -- pulse-width modulation unit (PWM) implemented?
sysinfo_mem(2)(22) <= bool_to_ulogic_f(IO_WDT_EN); -- watch dog timer (WDT) implemented?
sysinfo_mem(2)(23) <= bool_to_ulogic_f(IO_CFS_EN); -- custom functions subsystem (CFS) implemented?
sysinfo_mem(2)(24) <= bool_to_ulogic_f(IO_TRNG_EN); -- true random number generator (TRNG) implemented?
sysinfo_mem(2)(25) <= bool_to_ulogic_f(IO_SLINK_EN); -- stream links (SLINK) implemented?
sysinfo_mem(2)(26) <= bool_to_ulogic_f(IO_UART1_EN); -- secondary universal asynchronous receiver/transmitter (UART1) implemented?
sysinfo_mem(2)(27) <= bool_to_ulogic_f(IO_NEOLED_EN); -- NeoPixel-compatible smart LED interface (NEOLED) implemented?
sysinfo_mem(2)(28) <= bool_to_ulogic_f(boolean(IO_XIRQ_NUM_CH > 0)); -- external interrupt controller (XIRQ) implemented?
sysinfo_mem(2)(29) <= bool_to_ulogic_f(IO_GPTMR_EN); -- general purpose timer (GPTMR) implemented?
sysinfo_mem(2)(30) <= bool_to_ulogic_f(IO_XIP_EN); -- execute in place module (XIP) implemented?
sysinfo_mem(2)(31) <= bool_to_ulogic_f(IO_ONEWIRE_EN); -- 1-wire interface (ONEWIRE) implemented?
sysinfo(2)(16) <= bool_to_ulogic_f(IO_GPIO_NUM > 0); -- general purpose input/output port unit (GPIO) implemented?
sysinfo(2)(17) <= bool_to_ulogic_f(IO_MTIME_EN); -- machine system timer (MTIME) implemented?
sysinfo(2)(18) <= bool_to_ulogic_f(IO_UART0_EN); -- primary universal asynchronous receiver/transmitter (UART0) implemented?
sysinfo(2)(19) <= bool_to_ulogic_f(IO_SPI_EN); -- serial peripheral interface (SPI) implemented?
sysinfo(2)(20) <= bool_to_ulogic_f(IO_TWI_EN); -- two-wire interface (TWI) implemented?
sysinfo(2)(21) <= bool_to_ulogic_f(IO_PWM_NUM_CH > 0); -- pulse-width modulation unit (PWM) implemented?
sysinfo(2)(22) <= bool_to_ulogic_f(IO_WDT_EN); -- watch dog timer (WDT) implemented?
sysinfo(2)(23) <= bool_to_ulogic_f(IO_CFS_EN); -- custom functions subsystem (CFS) implemented?
sysinfo(2)(24) <= bool_to_ulogic_f(IO_TRNG_EN); -- true random number generator (TRNG) implemented?
sysinfo(2)(25) <= bool_to_ulogic_f(IO_SLINK_EN); -- stream links (SLINK) implemented?
sysinfo(2)(26) <= bool_to_ulogic_f(IO_UART1_EN); -- secondary universal asynchronous receiver/transmitter (UART1) implemented?
sysinfo(2)(27) <= bool_to_ulogic_f(IO_NEOLED_EN); -- NeoPixel-compatible smart LED interface (NEOLED) implemented?
sysinfo(2)(28) <= bool_to_ulogic_f(IO_XIRQ_NUM_CH > 0); -- external interrupt controller (XIRQ) implemented?
sysinfo(2)(29) <= bool_to_ulogic_f(IO_GPTMR_EN); -- general purpose timer (GPTMR) implemented?
sysinfo(2)(30) <= bool_to_ulogic_f(IO_XIP_EN); -- execute in place module (XIP) implemented?
sysinfo(2)(31) <= bool_to_ulogic_f(IO_ONEWIRE_EN); -- 1-wire interface (ONEWIRE) implemented?

-- SYSINFO(3): Cache configuration --
sysinfo_mem(3)(03 downto 00) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_BLOCK_SIZE), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(block_size_in_bytes)
sysinfo_mem(3)(07 downto 04) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_NUM_BLOCKS), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(number_of_block)
sysinfo_mem(3)(11 downto 08) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_ASSOCIATIVITY), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(associativity)
sysinfo_mem(3)(15 downto 12) <= "0001" when (ICACHE_ASSOCIATIVITY > 1) and (ICACHE_EN = true) else (others => '0'); -- i-cache: replacement strategy (LRU only (yet))
sysinfo(3)(03 downto 00) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_BLOCK_SIZE), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(block_size_in_bytes)
sysinfo(3)(07 downto 04) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_NUM_BLOCKS), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(number_of_block)
sysinfo(3)(11 downto 08) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_ASSOCIATIVITY), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(associativity)
sysinfo(3)(15 downto 12) <= "0001" when (ICACHE_ASSOCIATIVITY > 1) and (ICACHE_EN = true) else (others => '0'); -- i-cache: replacement strategy (LRU only (yet))
--
sysinfo_mem(3)(19 downto 16) <= (others => '0'); -- reserved - d-cache: log2(block_size)
sysinfo_mem(3)(23 downto 20) <= (others => '0'); -- reserved - d-cache: log2(num_blocks)
sysinfo_mem(3)(27 downto 24) <= (others => '0'); -- reserved - d-cache: log2(associativity)
sysinfo_mem(3)(31 downto 28) <= (others => '0'); -- reserved - d-cache: replacement strategy
sysinfo(3)(19 downto 16) <= (others => '0'); -- reserved - d-cache: log2(block_size)
sysinfo(3)(23 downto 20) <= (others => '0'); -- reserved - d-cache: log2(num_blocks)
sysinfo(3)(27 downto 24) <= (others => '0'); -- reserved - d-cache: log2(associativity)
sysinfo(3)(31 downto 28) <= (others => '0'); -- reserved - d-cache: replacement strategy

-- SYSINFO(4): Base address of instruction memory space --
sysinfo_mem(4) <= ispace_base_c; -- defined in neorv32_package.vhd file
sysinfo(4) <= ispace_base_c; -- defined in neorv32_package.vhd file

-- SYSINFO(5): Base address of data memory space --
sysinfo_mem(5) <= dspace_base_c; -- defined in neorv32_package.vhd file
sysinfo(5) <= dspace_base_c; -- defined in neorv32_package.vhd file

-- SYSINFO(6): Size of IMEM in bytes --
sysinfo_mem(6) <= std_ulogic_vector(to_unsigned(MEM_INT_IMEM_SIZE, 32)) when (MEM_INT_IMEM_EN = true) else (others => '0');
sysinfo(6) <= std_ulogic_vector(to_unsigned(MEM_INT_IMEM_SIZE, 32)) when (MEM_INT_IMEM_EN = true) else (others => '0');

-- SYSINFO(7): Size of DMEM in bytes --
sysinfo_mem(7) <= std_ulogic_vector(to_unsigned(MEM_INT_DMEM_SIZE, 32)) when (MEM_INT_DMEM_EN = true) else (others => '0');
sysinfo(7) <= std_ulogic_vector(to_unsigned(MEM_INT_DMEM_SIZE, 32)) when (MEM_INT_DMEM_EN = true) else (others => '0');


-- Read Access ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
ack_o <= rden;
err_o <= wren; -- read-only!
ack_o <= rden;
err_o <= wren; -- read-only!
data_o <= (others => '0');
if (rden = '1') then
data_o <= sysinfo_mem(to_integer(unsigned(addr)));
else
data_o <= (others => '0');
data_o <= sysinfo(to_integer(unsigned(addr)));
end if;
end if;
end process read_access;
Expand Down
16 changes: 15 additions & 1 deletion sw/example/demo_cfu/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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: #
Expand Down Expand Up @@ -208,6 +208,20 @@ int main() {
}


// ----------------------------------------------------------
// Unimplemented (=illegal) R3-type instruction
// ----------------------------------------------------------

neorv32_uart0_printf("\n--- CFU Unimplemented (= illegal) R3-Type ---\n");
for (i=0; i<TESTCASES; i++) {
rs1 = xorshift32();
rs2 = xorshift32();
// this funct3 is NOT implemented by the default CFU hardware causing an illegal instruction exception
neorv32_uart0_printf("%u: neorv32_cfu_r3_instr( funct7=0b0000000, funct3=0b111, [rs1]=0x%x, [rs2]=0x%x ) = ", i, rs1, rs2);
neorv32_uart0_printf("0x%x\n", neorv32_cfu_r3_instr(0b0000000, 0b111, rs1, rs2));
}


neorv32_uart0_printf("\nCFU demo program completed.\n");
return 0;
}