Merge branch 'main' into rework_bootloader
Some checks failed
Documentation / SW Framework (push) Has been cancelled
Documentation / Datasheet (push) Has been cancelled
Processor / processor simulation (push) Has been cancelled
Documentation / Deploy to Releases and Pages (push) Has been cancelled

This commit is contained in:
stnolting 2025-04-08 20:26:11 +02:00 committed by GitHub
commit c8fa55d13f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 190 additions and 170 deletions

View file

@ -29,6 +29,8 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 07.04.2025 | 1.11.2.6 | :bug: fix SDI input synchronization | [#1227](https://github.com/stnolting/neorv32/pull/1227) |
| 05.04.2025 | 1.11.2.5 | minor rtl edits and optimizations | [#1225](https://github.com/stnolting/neorv32/pull/1225) |
| 01.04.2025 | 1.11.2.4 | :bug: fix bug in PWM clock prescaler | [#1222](https://github.com/stnolting/neorv32/pull/1222) |
| 29.03.2025 | 1.11.2.3 | :sparkles: add optional 32 hardware spinlocks (`HWSPINLOCK` module) | [#1220](https://github.com/stnolting/neorv32/pull/1220) |
| 24.03.2025 | 1.11.2.2 | TWD: add separate RX/TX FIFO configuration; add dummy response (if TX FIFO is empty); add optional no-ACK on read access if TX FIFO is empty | [#1210](https://github.com/stnolting/neorv32/pull/1210) |

View file

@ -8,7 +8,6 @@
| Hardware source files: | neorv32_onewire.vhd |
| Software driver files: | neorv32_onewire.c | link:https://stnolting.github.io/neorv32/sw/neorv32__onewire_8c.html[Online software reference (Doxygen)]
| | neorv32_onewire.h | link:https://stnolting.github.io/neorv32/sw/neorv32__onewire_8h.html[Online software reference (Doxygen)]
| Software reference: | link:https://stnolting.github.io/neorv32/sw/neorv32__onewire_8h.html[Online Doxygen] |
| Top entity ports: | `onewire_i` | 1-bit 1-wire bus sense input
| | `onewire_o` | 1-bit 1-wire bus output (pull low only)
| Configuration generics: | `IO_ONEWIRE_EN` | implement ONEWIRE interface controller when `true`

View file

@ -66,7 +66,7 @@ yet. However, experiments have shown that the SDI module can also deal with both
All SDI operations are clocked by the external `sdi_clk_i` signal. This signal is synchronized to the processor's
clock domain to simplify timing behavior. This clock synchronization requires the external SDI clock
(`sdi_clk_i`) does **not exceed 1/4 of the processor's main clock**.
(`sdi_clk_i`) to not **not exceed 1/4 of the processor's main clock**.
**SDI Interrupt**

View file

@ -3,6 +3,8 @@ page:
margin: [0.8in, 0.67in, 0.75in, 0.67in]
link:
font-color: #edac00
base:
text-align: justify
image:
align: center
caption:

View file

@ -158,7 +158,7 @@ begin
end case;
end process arbiter_fsm;
-- port select --
sel <= '1' when (state = S_CHECK_B) or (state = S_BUSY_B) else '0';
end generate;

View file

@ -96,7 +96,6 @@ architecture neorv32_clint_rtl of neorv32_clint is
-- misc --
signal mtime : std_ulogic_vector(63 downto 0);
signal ack_q : std_ulogic;
signal rdata : std_ulogic_vector(31 downto 0);
begin
@ -187,7 +186,7 @@ begin
mti_v := mti_v or mtimecmp_rd(i);
msi_v := msi_v or mswi_rd(i);
end loop;
rdata <= mtime_rd or mti_v or msi_v;
bus_rsp_o.data <= mtime_rd or mti_v or msi_v;
end process read_back;
@ -198,13 +197,12 @@ begin
if (rstn_i = '0') then
ack_q <= '0';
elsif rising_edge(clk_i) then
ack_q <= bus_req_i.stb;
ack_q <= mtime_en or or_reduce_f(mtimecmp_en) or or_reduce_f(mswi_en);
end if;
end process bus_access;
bus_rsp_o.ack <= ack_q;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= rdata;
end neorv32_clint_rtl;

View file

@ -191,7 +191,7 @@ begin
)
port map (
-- global control --
clk_i => clk_i, -- global clock, rising edge
clk_i => clk_i, -- global clock, rising edge
rstn_i => rstn_i, -- global reset, low-active, async
ctrl_i => ctrl, -- main control bus
-- instruction fetch interface --

View file

@ -518,10 +518,10 @@ begin
when EX_BRANCH => -- update next PC on taken branches and jumps
-- ------------------------------------------------------------
exe_engine_nxt.ra <= exe_engine.pc2(XLEN-1 downto 1) & '0'; -- output return address
ctrl_nxt.rf_wb_en <= opcode(2); -- save return address if link operation (won't happen if exception)
exe_engine_nxt.ra <= exe_engine.pc2(XLEN-1 downto 1) & '0'; -- output return address
ctrl_nxt.rf_wb_en <= opcode(2); -- save return address if link operation (won't happen if exception)
trap_ctrl.instr_ma <= alu_add_i(1) and branch_taken and bool_to_ulogic_f(not RISCV_ISA_C); -- branch destination misaligned?
if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (branch_taken = '1') then -- valid taken branch / jump
trap_ctrl.instr_ma <= alu_add_i(1) and bool_to_ulogic_f(not RISCV_ISA_C); -- branch destination is misaligned?
if_reset <= '1'; -- reset instruction fetch to restart at modified PC
exe_engine_nxt.pc2 <= alu_add_i(XLEN-1 downto 1) & '0';
exe_engine_nxt.state <= EX_BRANCHED; -- shortcut (faster than going to EX_RESTART)
@ -839,59 +839,14 @@ begin
-- Trap Controller
-- ****************************************************************************************************************************
-- Exception Buffer -----------------------------------------------------------------------
-- Trap Buffer ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
exception_buffer: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
trap_ctrl.exc_buf <= (others => '0');
elsif rising_edge(clk_i) then
-- Exception Buffer -----------------------------------------------------
-- If several exception sources trigger at once, all the requests will
-- stay active until the trap environment is started. Only the exception
-- with highest priority will be used to update the MCAUSE CSR. All
-- remaining ones will be discarded.
-- ----------------------------------------------------------------------
-- misaligned load/store/instruction address --
trap_ctrl.exc_buf(exc_lalign_c) <= (trap_ctrl.exc_buf(exc_lalign_c) or lsu_err_i(0)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_salign_c) <= (trap_ctrl.exc_buf(exc_salign_c) or lsu_err_i(2)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_ialign_c) <= (trap_ctrl.exc_buf(exc_ialign_c) or trap_ctrl.instr_ma) and (not trap_ctrl.env_enter);
-- load/store/instruction access fault --
trap_ctrl.exc_buf(exc_laccess_c) <= (trap_ctrl.exc_buf(exc_laccess_c) or lsu_err_i(1)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_saccess_c) <= (trap_ctrl.exc_buf(exc_saccess_c) or lsu_err_i(3)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_iaccess_c) <= (trap_ctrl.exc_buf(exc_iaccess_c) or trap_ctrl.instr_be) and (not trap_ctrl.env_enter);
-- illegal instruction & environment call --
trap_ctrl.exc_buf(exc_ecall_c) <= (trap_ctrl.exc_buf(exc_ecall_c) or trap_ctrl.ecall) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_illegal_c) <= (trap_ctrl.exc_buf(exc_illegal_c) or trap_ctrl.instr_il) and (not trap_ctrl.env_enter);
-- break point --
if RISCV_ISA_Sdext then
trap_ctrl.exc_buf(exc_ebreak_c) <= (not trap_ctrl.env_enter) and (trap_ctrl.exc_buf(exc_ebreak_c) or
(trap_ctrl.hwtrig and (not csr.tdata1_action)) or -- trigger module fires and enter-debug-action is disabled
(trap_ctrl.ebreak and ( csr.prv_level) and (not csr.dcsr_ebreakm) and (not debug_ctrl.run)) or -- enter M-mode handler on ebreak in M-mode
(trap_ctrl.ebreak and (not csr.prv_level) and (not csr.dcsr_ebreaku) and (not debug_ctrl.run))); -- enter M-mode handler on ebreak in U-mode
else
trap_ctrl.exc_buf(exc_ebreak_c) <= (trap_ctrl.exc_buf(exc_ebreak_c) or trap_ctrl.ebreak or (trap_ctrl.hwtrig and (not csr.tdata1_action))) and (not trap_ctrl.env_enter);
end if;
-- debug-mode entry --
trap_ctrl.exc_buf(exc_db_break_c) <= (trap_ctrl.exc_buf(exc_db_break_c) or debug_ctrl.trig_break) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_db_hw_c) <= (trap_ctrl.exc_buf(exc_db_hw_c) or debug_ctrl.trig_hw) and (not trap_ctrl.env_enter);
end if;
end process exception_buffer;
-- Interrupt Buffer -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
interrupt_buffer: process(rstn_i, clk_i)
trap_buffer: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
trap_ctrl.irq_pnd <= (others => '0');
trap_ctrl.irq_buf <= (others => '0');
trap_ctrl.exc_buf <= (others => '0');
elsif rising_edge(clk_i) then
-- Interrupt-Pending Buffer ---------------------------------------------
@ -930,8 +885,43 @@ begin
-- debug-mode entry --
trap_ctrl.irq_buf(irq_db_halt_c) <= debug_ctrl.trig_halt or (trap_ctrl.env_pending and trap_ctrl.irq_buf(irq_db_halt_c));
trap_ctrl.irq_buf(irq_db_step_c) <= debug_ctrl.trig_step or (trap_ctrl.env_pending and trap_ctrl.irq_buf(irq_db_step_c));
-- Exception Buffer -----------------------------------------------------
-- If several exception sources trigger at once, all the requests will
-- stay active until the trap environment is started. Only the exception
-- with highest priority will be used to update the MCAUSE CSR. All
-- remaining ones will be discarded.
-- ----------------------------------------------------------------------
-- misaligned load/store/instruction address --
trap_ctrl.exc_buf(exc_lalign_c) <= (trap_ctrl.exc_buf(exc_lalign_c) or lsu_err_i(0)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_salign_c) <= (trap_ctrl.exc_buf(exc_salign_c) or lsu_err_i(2)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_ialign_c) <= (trap_ctrl.exc_buf(exc_ialign_c) or trap_ctrl.instr_ma) and (not trap_ctrl.env_enter);
-- load/store/instruction access fault --
trap_ctrl.exc_buf(exc_laccess_c) <= (trap_ctrl.exc_buf(exc_laccess_c) or lsu_err_i(1)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_saccess_c) <= (trap_ctrl.exc_buf(exc_saccess_c) or lsu_err_i(3)) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_iaccess_c) <= (trap_ctrl.exc_buf(exc_iaccess_c) or trap_ctrl.instr_be) and (not trap_ctrl.env_enter);
-- illegal instruction & environment call --
trap_ctrl.exc_buf(exc_ecall_c) <= (trap_ctrl.exc_buf(exc_ecall_c) or trap_ctrl.ecall) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_illegal_c) <= (trap_ctrl.exc_buf(exc_illegal_c) or trap_ctrl.instr_il) and (not trap_ctrl.env_enter);
-- break point --
if RISCV_ISA_Sdext then
trap_ctrl.exc_buf(exc_ebreak_c) <= (not trap_ctrl.env_enter) and (trap_ctrl.exc_buf(exc_ebreak_c) or
(trap_ctrl.hwtrig and (not csr.tdata1_action)) or -- trigger module fires and enter-debug-action is disabled
(trap_ctrl.ebreak and ( csr.prv_level) and (not csr.dcsr_ebreakm) and (not debug_ctrl.run)) or -- enter M-mode handler on ebreak in M-mode
(trap_ctrl.ebreak and (not csr.prv_level) and (not csr.dcsr_ebreaku) and (not debug_ctrl.run))); -- enter M-mode handler on ebreak in U-mode
else
trap_ctrl.exc_buf(exc_ebreak_c) <= (trap_ctrl.exc_buf(exc_ebreak_c) or trap_ctrl.ebreak or (trap_ctrl.hwtrig and (not csr.tdata1_action))) and (not trap_ctrl.env_enter);
end if;
-- debug-mode entry --
trap_ctrl.exc_buf(exc_db_break_c) <= (trap_ctrl.exc_buf(exc_db_break_c) or debug_ctrl.trig_break) and (not trap_ctrl.env_enter);
trap_ctrl.exc_buf(exc_db_hw_c) <= (trap_ctrl.exc_buf(exc_db_hw_c) or debug_ctrl.trig_hw) and (not trap_ctrl.env_enter);
end if;
end process interrupt_buffer;
end process trap_buffer;
-- Trap Priority Logic --------------------------------------------------------------------
@ -1389,7 +1379,7 @@ begin
csr.re <= csr.re_nxt and (not trap_ctrl.exc_buf(exc_illegal_c)); -- read if not an illegal instruction
csr.rdata <= (others => '0'); -- default; output all-zero if there is no explicit CSR read operation
if (csr.re = '1') then
case csr.addr is -- address is zero if there is no CSR operation
case csr.addr is
-- --------------------------------------------------------------------
-- floating-point unit

View file

@ -29,8 +29,8 @@ entity neorv32_cpu_frontend is
rstn_i : in std_ulogic; -- global reset, low-active, async
ctrl_i : in ctrl_bus_t; -- main control bus
-- instruction fetch interface --
ibus_req_o : out bus_req_t; -- request
ibus_rsp_i : in bus_rsp_t; -- response
ibus_req_o : out bus_req_t;
ibus_rsp_i : in bus_rsp_t;
-- back-end interface --
frontend_o : out if_bus_t
);
@ -46,7 +46,6 @@ architecture neorv32_cpu_frontend_rtl of neorv32_cpu_frontend is
pc : std_ulogic_vector(XLEN-1 downto 0);
resp : std_ulogic; -- bus response
priv : std_ulogic; -- fetch privilege level
halted : std_ulogic; -- instruction fetch has halted
end record;
signal fetch : fetch_t;
@ -61,15 +60,12 @@ architecture neorv32_cpu_frontend_rtl of neorv32_cpu_frontend is
-- instruction issue engine --
type issue_t is record
align : std_ulogic;
alset : std_ulogic;
alclr : std_ulogic;
algn : std_ulogic;
aset : std_ulogic;
aclr : std_ulogic;
ack : std_ulogic_vector(1 downto 0);
cmd16 : std_ulogic_vector(15 downto 0);
cmd32 : std_ulogic_vector(31 downto 0);
valid : std_ulogic_vector(1 downto 0);
instr : std_ulogic_vector(31 downto 0);
compr : std_ulogic;
error : std_ulogic;
end record;
signal issue : issue_t;
@ -124,11 +120,18 @@ begin
end if;
end process fetch_fsm;
-- PC output for instruction fetch --
ibus_req_o.addr <= fetch.pc(XLEN-1 downto 2) & "00"; -- word aligned
-- instruction fetch (read) request if IPB not full --
ibus_req_o.stb <= '1' when (fetch.state = S_REQUEST) and (ipb.free = "11") else '0';
-- instruction bus request --
ibus_req_o.addr <= fetch.pc(XLEN-1 downto 2) & "00"; -- word aligned
ibus_req_o.stb <= '1' when (fetch.state = S_REQUEST) and (ipb.free = "11") else '0';
ibus_req_o.data <= (others => '0'); -- read-only
ibus_req_o.ben <= (others => '0'); -- read-only
ibus_req_o.rw <= '0'; -- read-only
ibus_req_o.src <= '1'; -- always "instruction fetch" access
ibus_req_o.priv <= fetch.priv; -- current effective privilege level
ibus_req_o.debug <= ctrl_i.cpu_debug; -- CPU is in debug mode
ibus_req_o.amo <= '0'; -- cannot be an atomic memory operation
ibus_req_o.amoop <= (others => '0'); -- cannot be an atomic memory operation
ibus_req_o.fence <= ctrl_i.if_fence; -- fence request, valid without STB being set ("out-of-band" signal)
-- instruction bus response --
fetch.resp <= ibus_rsp_i.ack or ibus_rsp_i.err;
@ -142,28 +145,17 @@ begin
ipb.we(1) <= '1' when (fetch.state = S_PENDING) and (fetch.resp = '1') else '0';
-- instruction fetch has halted --
fetch.halted <= '1' when (fetch.state = S_REQUEST) and (ipb.free /= "11") else '0';
-- bus access meta data --
ibus_req_o.data <= (others => '0'); -- read-only
ibus_req_o.ben <= (others => '0'); -- read-only
ibus_req_o.rw <= '0'; -- read-only
ibus_req_o.src <= '1'; -- always "instruction fetch" access
ibus_req_o.priv <= fetch.priv; -- current effective privilege level
ibus_req_o.debug <= ctrl_i.cpu_debug; -- CPU is in debug mode
ibus_req_o.amo <= '0'; -- cannot be an atomic memory operation
ibus_req_o.amoop <= (others => '0'); -- cannot be an atomic memory operation
ibus_req_o.fence <= ctrl_i.if_fence; -- fence request, valid without STB being set ("out-of-band" signal)
frontend_o.halted <= '1' when (fetch.state = S_REQUEST) and (ipb.free /= "11") else '0';
-- Instruction Prefetch Buffer (FIFO) -----------------------------------------------------
-- -------------------------------------------------------------------------------------------
prefetch_buffer:
for i in 0 to 1 generate -- low half-word + high half-word (incl. status bits)
for i in 0 to 1 generate
prefetch_buffer_inst: entity neorv32.neorv32_fifo
generic map (
FIFO_DEPTH => 2, -- number of IPB entries; has to be a power of two, min 2
FIFO_WIDTH => 17, -- size of data elements in FIFO
FIFO_WIDTH => 17, -- error status & instruction half-word data
FIFO_RSYNC => false, -- we NEED to read data asynchronously
FIFO_SAFE => false, -- no safe access required (ensured by FIFO-external logic)
FULL_RESET => false -- no need for a full hardware reset
@ -186,10 +178,6 @@ begin
);
end generate;
-- read access --
ipb.re(0) <= issue.valid(0) and ctrl_i.if_ack;
ipb.re(1) <= issue.valid(1) and ctrl_i.if_ack;
-- ******************************************************************************************************************
-- Instruction Issue (decompress 16-bit instruction and/or assemble a 32-bit instruction word)
@ -207,7 +195,7 @@ begin
);
-- half-word select --
issue.cmd16 <= ipb.rdata(0)(15 downto 0) when (issue.align = '0') else ipb.rdata(1)(15 downto 0);
issue.cmd16 <= ipb.rdata(0)(15 downto 0) when (issue.algn = '0') else ipb.rdata(1)(15 downto 0);
-- Issue Engine FSM -----------------------------------------------------------------------
@ -215,12 +203,12 @@ begin
issue_fsm_sync: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
issue.align <= '0'; -- start aligned after reset
issue.algn <= '0'; -- start aligned after reset
elsif rising_edge(clk_i) then
if (fetch.restart = '1') then
issue.align <= ctrl_i.pc_nxt(1); -- branch to unaligned address?
issue.algn <= ctrl_i.pc_nxt(1); -- branch to unaligned address?
elsif (ctrl_i.if_ack = '1') then
issue.align <= (issue.align and (not issue.alclr)) or issue.alset; -- alignment "RS flip-flop"
issue.algn <= (issue.algn and (not issue.aclr)) or issue.aset; -- alignment "RS flip-flop"
end if;
end if;
end process issue_fsm_sync;
@ -228,63 +216,62 @@ begin
issue_fsm_comb: process(issue, ipb)
begin
-- defaults --
issue.alset <= '0';
issue.alclr <= '0';
issue.valid <= "00";
issue.aset <= '0';
issue.aclr <= '0';
-- start at LOW half-word --
if (issue.align = '0') then
issue.error <= ipb.rdata(0)(16);
if (ipb.rdata(0)(1 downto 0) /= "11") then -- compressed, use IPB(0) entry
issue.alset <= ipb.avail(0); -- start of next instruction word is NOT 32-bit-aligned
issue.valid <= '0' & ipb.avail(0);
issue.instr <= issue.cmd32;
issue.compr <= '1';
else -- aligned uncompressed
issue.valid <= (others => (ipb.avail(0) and ipb.avail(1)));
issue.instr <= ipb.rdata(1)(15 downto 0) & ipb.rdata(0)(15 downto 0);
issue.compr <= '0';
if (issue.algn = '0') then
frontend_o.error <= ipb.rdata(0)(16);
if (ipb.rdata(0)(1 downto 0) /= "11") then -- compressed, consume IPB(0) entry
issue.aset <= ipb.avail(0); -- start of next instruction word is NOT 32-bit-aligned
issue.ack <= "01";
frontend_o.valid <= ipb.avail(0);
frontend_o.instr <= issue.cmd32;
frontend_o.compr <= '1';
else -- aligned uncompressed, consume both IPB entries
issue.ack <= "11";
frontend_o.valid <= ipb.avail(1) and ipb.avail(0);
frontend_o.instr <= ipb.rdata(1)(15 downto 0) & ipb.rdata(0)(15 downto 0);
frontend_o.compr <= '0';
end if;
-- start at HIGH half-word --
else
issue.error <= ipb.rdata(1)(16);
if (ipb.rdata(1)(1 downto 0) /= "11") then -- compressed, use IPB(1) entry
issue.alclr <= ipb.avail(1); -- start of next instruction word is 32-bit-aligned again
issue.valid <= ipb.avail(1) & '0';
issue.instr <= issue.cmd32;
issue.compr <= '1';
else -- unaligned uncompressed
issue.valid <= (others => (ipb.avail(0) and ipb.avail(1)));
issue.instr <= ipb.rdata(0)(15 downto 0) & ipb.rdata(1)(15 downto 0);
issue.compr <= '0';
frontend_o.error <= ipb.rdata(1)(16);
if (ipb.rdata(1)(1 downto 0) /= "11") then -- compressed, consume IPB(1) entry
issue.aclr <= ipb.avail(1); -- start of next instruction word is 32-bit-aligned again
issue.ack <= "10";
frontend_o.valid <= ipb.avail(1);
frontend_o.instr <= issue.cmd32;
frontend_o.compr <= '1';
else -- unaligned uncompressed, consume both IPB entries
issue.ack <= "11";
frontend_o.valid <= ipb.avail(0) and ipb.avail(1);
frontend_o.instr <= ipb.rdata(0)(15 downto 0) & ipb.rdata(1)(15 downto 0);
frontend_o.compr <= '0';
end if;
end if;
end process issue_fsm_comb;
-- IPB read access --
ipb.re(0) <= issue.ack(0) and ctrl_i.if_ack;
ipb.re(1) <= issue.ack(1) and ctrl_i.if_ack;
end generate; -- /issue_enabled
-- issue engine disabled --
issue_disabled:
if not RVC_EN generate
issue.align <= '0';
issue.alset <= '0';
issue.alclr <= '0';
issue.cmd16 <= (others => '0');
issue.cmd32 <= (others => '0');
issue.valid <= (others => ipb.avail(0)); -- use IPB(0) status flags only
issue.instr <= ipb.rdata(1)(15 downto 0) & ipb.rdata(0)(15 downto 0);
issue.compr <= '0';
issue.error <= ipb.rdata(0)(16);
issue.algn <= '0';
issue.aset <= '0';
issue.aclr <= '0';
issue.cmd16 <= (others => '0');
issue.cmd32 <= (others => '0');
ipb.re <= (others => ctrl_i.if_ack);
frontend_o.valid <= ipb.avail(0);
frontend_o.instr <= ipb.rdata(1)(15 downto 0) & ipb.rdata(0)(15 downto 0);
frontend_o.compr <= '0';
frontend_o.error <= ipb.rdata(0)(16);
end generate;
-- Instruction Interface to CPU Back-End (Execution) --------------------------------------
-- -------------------------------------------------------------------------------------------
frontend_o.valid <= issue.valid(1) or issue.valid(0);
frontend_o.instr <= issue.instr;
frontend_o.compr <= issue.compr;
frontend_o.error <= issue.error;
frontend_o.halted <= fetch.halted;
end neorv32_cpu_frontend_rtl;

View file

@ -29,7 +29,7 @@ package neorv32_package is
-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01110204"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01110206"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width

View file

@ -17,7 +17,7 @@ use neorv32.neorv32_package.all;
entity neorv32_sdi is
generic (
RTX_FIFO : natural range 1 to 2**15 -- RTX fifo depth, has to be a power of two, min 1
RTX_FIFO : natural range 1 to 2**15 -- RTX FIFO depth, has to be a power of two, min 1
);
port (
clk_i : in std_ulogic; -- global clock line
@ -37,16 +37,16 @@ architecture neorv32_sdi_rtl of neorv32_sdi is
-- control register --
constant ctrl_en_c : natural := 0; -- r/w: SDI enable
--
constant ctrl_fifo_size0_c : natural := 4; -- r/-: log2(FIFO size), bit 0 (lsb)
constant ctrl_fifo_size0_c : natural := 4; -- r/-: log2(FIFO size), bit 0 (LSB)
constant ctrl_fifo_size1_c : natural := 5; -- r/-: log2(FIFO size), bit 1
constant ctrl_fifo_size2_c : natural := 6; -- r/-: log2(FIFO size), bit 2
constant ctrl_fifo_size3_c : natural := 7; -- r/-: log2(FIFO size), bit 3 (msb)
constant ctrl_fifo_size3_c : natural := 7; -- r/-: log2(FIFO size), bit 3 (MSB)
--
constant ctrl_irq_rx_avail_c : natural := 15; -- r/w: RX FIFO not empty
constant ctrl_irq_rx_half_c : natural := 16; -- r/w: RX FIFO at least half full
constant ctrl_irq_rx_full_c : natural := 17; -- r/w: RX FIFO full
constant ctrl_irq_tx_empty_c : natural := 18; -- r/w: TX FIFO empty
constant ctrl_irq_tx_nhalf_c : natural := 19; -- r/w: TX FIFO not at least half full
constant ctrl_irq_rx_avail_c : natural := 15; -- r/w: interrupt if RX FIFO not empty
constant ctrl_irq_rx_half_c : natural := 16; -- r/w: interrupt if RX FIFO at least half full
constant ctrl_irq_rx_full_c : natural := 17; -- r/w: interrupt if RX FIFO full
constant ctrl_irq_tx_empty_c : natural := 18; -- r/w: interrupt if TX FIFO empty
constant ctrl_irq_tx_nhalf_c : natural := 19; -- r/w: interrupt if TX FIFO not at least half full
--
constant ctrl_rx_avail_c : natural := 23; -- r/-: RX FIFO not empty
constant ctrl_rx_half_c : natural := 24; -- r/-: RX FIFO at least half full
@ -173,8 +173,8 @@ begin
-- TX --
tx_fifo_inst: entity neorv32.neorv32_fifo
generic map (
FIFO_DEPTH => RTX_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo (32-bit only for simulation)
FIFO_DEPTH => RTX_FIFO, -- number of FIFO entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in FIFO (32-bit only for simulation)
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
@ -208,8 +208,8 @@ begin
-- RX --
rx_fifo_inst: entity neorv32.neorv32_fifo
generic map (
FIFO_DEPTH => RTX_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo (32-bit only for simulation)
FIFO_DEPTH => RTX_FIFO, -- number of FIFO entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in FIFO (32-bit only for simulation)
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
@ -311,7 +311,7 @@ begin
when "110" => -- bit phase A: sample
-- ------------------------------------------------------------
serial.sdi_ff <= sdi_dat_i;
serial.sdi_ff <= sync.sdi;
if (sync.csn = '1') then -- transmission aborted?
serial.state(1 downto 0) <= "00";
elsif (sync.sck = '1') then

View file

@ -106,6 +106,6 @@ begin
when "1100" | "0011" => ahb_hsize_o <= "001"; -- half-word
when others => ahb_hsize_o <= "010"; -- word
end case;
end process data_size
end process data_size;
end xbus2ahblite_bridge_rtl;

View file

@ -336,12 +336,12 @@ begin
onewire <= 'H';
-- SPI/SDI --------------------------------------------------------------------------------
-- SPI/SDI Loop-Back ----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
sdi_clk <= spi_clk after 40 ns; -- echo with propagation delay
sdi_csn <= spi_csn(7) after 40 ns;
sdi_di <= spi_do after 40 ns;
spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do after 40 ns;
sdi_clk <= spi_clk;
sdi_csn <= spi_csn(7);
sdi_di <= spi_do;
spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do;
-- Stream-Link FIFO Buffer ----------------------------------------------------------------

View file

@ -89,6 +89,7 @@ volatile uint8_t core1_stack[512]; // stack for core1
volatile unsigned char constr_src[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
volatile uint32_t constr_res = 0; // for constructor test
volatile uint32_t amo_var = 0; // atomic memory access test
volatile _Atomic int atomic_cnt = 0; // dual core atomic test
/**********************************************************************//**
* Constructor; should be called before entering main.
@ -1527,8 +1528,9 @@ int main() {
cnt_test++;
// configure and enable SDI + SPI
// SDI input clock (= SPI output clock) must be less than 1/4 of the processor clock
neorv32_sdi_setup(1 << SDI_CTRL_IRQ_RX_AVAIL);
neorv32_spi_setup(CLK_PRSC_8, 0, 0, 0, 0);
neorv32_spi_setup(CLK_PRSC_2, 1, 0, 0, 0);
// enable fast interrupt
neorv32_cpu_csr_write(CSR_MIE, 1 << SDI_FIRQ_ENABLE);
@ -2223,26 +2225,31 @@ int main() {
// SMP dual-core test
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, mcause_never_c);
PRINT_STANDARD("[%i] SMP dual-core boot ", cnt_test);
PRINT_STANDARD("[%i] SMP dual-core test ", cnt_test);
if ((NEORV32_SYSINFO->MISC[SYSINFO_MISC_HART] > 1) && // we need at least two cores
if ((NEORV32_SYSINFO->MISC[SYSINFO_MISC_HART] > 1) && // we need two cores
(neorv32_clint_available() != 0)) { // we need the CLINT
cnt_test++;
// initialize _Atomic variable
atomic_cnt = 1;
// enable machine software interrupt
neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MSIE);
// launch core 1
tmp_a = (uint32_t)neorv32_smp_launch(core1_main, (uint8_t*)core1_stack, sizeof(core1_stack));
// wait for software interrupt (issued by core 1) in sleep mode
// sleep until software interrupt (issued by core 1)
neorv32_cpu_sleep();
// disable interrupts and clear software interrupt
neorv32_cpu_csr_write(CSR_MIE, 0);
neorv32_clint_msi_clr(0);
if ((tmp_a == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MSI)) {
if ((tmp_a == 0) && // core 1 has booted
(atomic_cnt == 2) && // AMO access successful
(neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MSI)) { // MSI triggered by core 1
test_ok();
}
else {
@ -2479,6 +2486,9 @@ void test_fail(void) {
**************************************************************************/
int core1_main(void) {
// atomic add
atomic_cnt++; // = amoadd
// trigger software interrupt of core0
neorv32_clint_msi_set(0);

View file

@ -175,16 +175,18 @@ extern "C" {
/**********************************************************************//**
* @name Export linker script symbols
* @name NEORV32 linker symbols
**************************************************************************/
/**@{*/
extern char __heap_start[]; /**< heap start address */
extern char __heap_end[]; /**< heap last address */
extern char __crt0_max_heap[]; /**< heap size in bytes */
extern char __crt0_entry[]; /**< crt0 entry point */
// aliases
#define NEORV32_HEAP_BEGIN ((uint32_t)&__heap_start[0])
#define NEORV32_HEAP_END ((uint32_t)&__heap_end[0])
#define NEORV32_HEAP_SIZE ((uint32_t)&__crt0_max_heap[0])
#define NEORV32_CRT0_ENTRY ((uint32_t)&__crt0_entry[0])
/**@}*/

View file

@ -33,6 +33,20 @@ uint32_t neorv32_cpu_hpm_get_size(void);
/**@}*/
/**********************************************************************//**
* Restart CPU core (jump to boot address).
*
* @warning This is just a "software reset" that uses the in-code reset/boot/entry address linked at compile time.
**************************************************************************/
inline void __attribute__ ((always_inline)) neorv32_cpu_soft_restart(void) {
uint32_t sw_boot_addr = NEORV32_CRT0_ENTRY; // linker symbol
asm volatile ("jalr x0, 0(%[dst])" : : [dst] "r" (sw_boot_addr));
__builtin_unreachable();
while(1); // should never be reached
}
/**********************************************************************//**
* Store unsigned word to address space.
*

View file

@ -62,7 +62,7 @@ enum NEORV32_NEOLED_CTRL_enum {
NEOLED_CTRL_T_ONE_H_3 = 23, /**< NEOLED control register(23) (r/w): pulse-clock ticks per ONE high-time bit 3 */
NEOLED_CTRL_T_ONE_H_4 = 24, /**< NEOLED control register(24) (r/w): pulse-clock ticks per ONE high-time bit 4 */
NEOLED_CTRL_IRQ_CONF = 27, /**< NEOLED control register(27) (r/w): TX FIFO interrupt: 1=IRQ if FIFO is empty, 1=IRQ if FIFO is less than half-full */
NEOLED_CTRL_IRQ_CONF = 27, /**< NEOLED control register(27) (r/w): TX FIFO interrupt: 0=IRQ if FIFO is empty, 1=IRQ if FIFO is less than half-full */
NEOLED_CTRL_TX_EMPTY = 28, /**< NEOLED control register(28) (r/-): TX FIFO is empty */
NEOLED_CTRL_TX_HALF = 29, /**< NEOLED control register(29) (r/-): TX FIFO is at least half-full */
NEOLED_CTRL_TX_FULL = 30, /**< NEOLED control register(30) (r/-): TX FIFO is full */

View file

@ -69,6 +69,7 @@ int neorv32_wdt_available(void);
void neorv32_wdt_setup(uint32_t timeout, int lock, int strict);
int neorv32_wdt_disable(void);
void neorv32_wdt_feed(uint32_t password);
void neorv32_wdt_force_hwreset(void);
int neorv32_wdt_get_cause(void);
/**@}*/

View file

@ -42,7 +42,7 @@ int neorv32_neoled_available(void) {
* @param[in] t_total Number of pre-scaled clock ticks for total bit period (0..31).
* @param[in] t_high_zero Number of pre-scaled clock ticks to generate high-time for sending a '0' (0..31).
* @param[in] t_high_one Number of pre-scaled clock ticks to generate high-time for sending a '1' (0..31).
* @param[in] irq_mode Interrupt condition (1=IRQ if FIFO is empty, 1=IRQ if FIFO is less than half-full).
* @param[in] irq_mode Interrupt condition (0=IRQ if FIFO is empty, 1=IRQ if FIFO is less than half-full).
**************************************************************************/
void neorv32_neoled_setup(uint32_t prsc, uint32_t t_total, uint32_t t_high_zero, uint32_t t_high_one, int irq_mode) {
@ -54,7 +54,7 @@ void neorv32_neoled_setup(uint32_t prsc, uint32_t t_total, uint32_t t_high_zero,
tmp |= (uint32_t)((t_total & 0x1fU) << NEOLED_CTRL_T_TOT_0); // serial data output: total period length for one bit
tmp |= (uint32_t)((t_high_zero & 0x1fU) << NEOLED_CTRL_T_ZERO_H_0); // serial data output: high-time for sending a '0'
tmp |= (uint32_t)((t_high_one & 0x1fU) << NEOLED_CTRL_T_ONE_H_0); // serial data output: high-time for sending a '1'
tmp |= (uint32_t)((irq_mode & 0x01U) << NEOLED_CTRL_EN); // interrupt mode
tmp |= (uint32_t)((irq_mode & 0x01U) << NEOLED_CTRL_IRQ_CONF); // interrupt mode
NEORV32_NEOLED->CTRL = tmp;
}
@ -66,7 +66,7 @@ void neorv32_neoled_setup(uint32_t prsc, uint32_t t_total, uint32_t t_high_zero,
* @note WS2812 timing: T_period = 1.2us, T_high_zero = 0.4us, T_high_one = 0.8us. Change the constants if required.
* @note This function uses the SYSINFO_CLK value (from the SYSINFO HW module) to do the timing computations.
*
* @param[in] irq_mode Interrupt condition (1=IRQ if FIFO is empty, 1=IRQ if FIFO is less than half-full).
* @param[in] irq_mode Interrupt condition (0=IRQ if FIFO is empty, 1=IRQ if FIFO is less than half-full).
**************************************************************************/
void neorv32_neoled_setup_ws2812(int irq_mode) {

View file

@ -90,6 +90,21 @@ void neorv32_wdt_feed(uint32_t password) {
}
/**********************************************************************//**
* Force a hardware reset triggered by the watchdog.
**************************************************************************/
void neorv32_wdt_force_hwreset(void) {
// enable strict mode; if strict mode is already enabled and the WDT
// is locked this will already trigger a hardware reset
NEORV32_WDT->CTRL |= (uint32_t)(1 << WDT_CTRL_STRICT);
// try to reset the WDT using an incorrect password;
// this will finally trigger a hardware reset
NEORV32_WDT->RESET = 0;
}
/**********************************************************************//**
* Get cause of last system reset.
*