mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 14:17:51 -04:00
Merge branch 'main' into rework_bootloader
This commit is contained in:
commit
c8fa55d13f
20 changed files with 190 additions and 170 deletions
|
@ -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) |
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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**
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 --
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ----------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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])
|
||||
/**@}*/
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
/**@}*/
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue