URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/rtl
- from Rev 30 to Rev 31
- ↔ Reverse comparison
Rev 30 → Rev 31
/core/neorv32_cpu.vhd
329,7 → 329,7
ma_instr_o => ma_instr, -- misaligned instruction address |
be_instr_o => be_instr, -- bus error on instruction access |
-- cpu data access interface -- |
addr_i => alu_res, -- ALU result -> access address |
addr_i => alu_res, -- ALU result -> access address |
wdata_i => rs2, -- write data |
rdata_o => rdata, -- read data |
mar_o => mar, -- current memory address register |
/core/neorv32_cpu_bus.vhd
340,7 → 340,7
be_instr_o <= i_arbiter.err_bus; |
|
-- instruction bus (read-only) -- |
i_bus_addr_o <= fetch_pc_i; |
i_bus_addr_o <= fetch_pc_i(data_width_c-1 downto 2) & "00"; -- instruction access is always 4-byte aligned (even for compressed instructions) |
i_bus_wdata_o <= (others => '0'); |
i_bus_ben_o <= (others => '0'); |
i_bus_we_o <= '0'; |
/core/neorv32_cpu_control.vhd
1,9 → 1,10
-- ################################################################################################# |
-- # << NEORV32 - CPU Control >> # |
-- # ********************************************************************************************* # |
-- # CPU operation is split into a fetch engine (responsible for fetching an decompressing instr- # |
-- # uctions), an execute engine (responsible for actually executing the instructions), an inter- # |
-- # rupt and exception handling controller and the RISC-V status and control registers (CSRs). # |
-- # CPU operation is split into a fetch engine (responsible for fetching instruction data), an # |
-- # issue engine (for recoding compressed instructions and for constructing 32-bit instruction # |
-- # words) and an execute engine (responsible for actually executing the instructions), a trap # |
-- # handling controller and the RISC-V status and control register set (CSRs). # |
-- # ********************************************************************************************* # |
-- # BSD 3-Clause License # |
-- # # |
105,49 → 106,68
architecture neorv32_cpu_control_rtl of neorv32_cpu_control is |
|
-- instruction fetch enginge -- |
type fetch_engine_state_t is (IFETCH_RESET, IFETCH_0, IFETCH_1, IFETCH_2); |
type fetch_engine_state_t is (IFETCH_RESET, IFETCH_REQUEST, IFETCH_ISSUE); |
type fetch_engine_t is record |
state : fetch_engine_state_t; |
state_nxt : fetch_engine_state_t; |
i_buf : std_ulogic_vector(33 downto 0); |
i_buf_nxt : std_ulogic_vector(33 downto 0); |
i_buf2 : std_ulogic_vector(33 downto 0); |
i_buf2_nxt : std_ulogic_vector(33 downto 0); |
ci_input : std_ulogic_vector(15 downto 0); -- input to compressed instr. decoder |
i_buf_state : std_ulogic_vector(01 downto 0); |
i_buf_state_nxt : std_ulogic_vector(01 downto 0); |
pc : std_ulogic_vector(data_width_c-1 downto 0); |
pc_add : std_ulogic_vector(data_width_c-1 downto 0); |
reset : std_ulogic; |
bus_err_ack : std_ulogic; |
state : fetch_engine_state_t; |
state_nxt : fetch_engine_state_t; |
pc : std_ulogic_vector(data_width_c-1 downto 0); |
pc_nxt : std_ulogic_vector(data_width_c-1 downto 0); |
reset : std_ulogic; |
bus_err_ack : std_ulogic; |
end record; |
signal fetch_engine : fetch_engine_t; |
|
-- pre-decoder -- |
signal ci_instr32 : std_ulogic_vector(31 downto 0); |
signal ci_illegal : std_ulogic; |
|
-- instrucion prefetch buffer (IPB) -- |
type ipb_dbuf_t is array (0 to ipb_entries_c-1) of std_ulogic_vector(35 downto 0); |
type ipb_data_fifo_t is array (0 to ipb_entries_c-1) of std_ulogic_vector(2+31 downto 0); |
type ipb_t is record |
wdata : std_ulogic_vector(35 downto 0); -- data (+ status) to be written |
we : std_ulogic; -- trigger write |
free : std_ulogic; -- free entry available? |
wdata : std_ulogic_vector(2+31 downto 0); -- write status (bus_error, align_error) + 32-bit instruction data |
we : std_ulogic; -- trigger write |
free : std_ulogic; -- free entry available? |
clear : std_ulogic; -- clear all entries |
-- |
rdata : std_ulogic_vector(35 downto 0); -- read data (+ status) |
re : std_ulogic; -- trigger read |
avail : std_ulogic; -- data available? |
rdata : std_ulogic_vector(2+31 downto 0); -- read data: status (bus_error, align_error) + 32-bit instruction data |
re : std_ulogic; -- read enable |
avail : std_ulogic; -- data available? |
-- |
clear : std_ulogic; -- clear all entries |
w_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- write pointer |
r_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- read pointer |
empty : std_ulogic; |
full : std_ulogic; |
-- |
data : ipb_dbuf_t; -- the data fifo |
w_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- write pointer |
r_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- read pointer |
empty : std_ulogic; |
full : std_ulogic; |
data : ipb_data_fifo_t; -- fifo memory |
end record; |
signal ipb : ipb_t; |
|
-- pre-decoder -- |
signal ci_instr16 : std_ulogic_vector(15 downto 0); |
signal ci_instr32 : std_ulogic_vector(31 downto 0); |
signal ci_illegal : std_ulogic; |
|
-- instruction issue enginge -- |
type issue_engine_state_t is (ISSUE_ACTIVE, ISSUE_REALIGN); |
type issue_engine_t is record |
state : issue_engine_state_t; |
state_nxt : issue_engine_state_t; |
align : std_ulogic; |
align_nxt : std_ulogic; |
buf : std_ulogic_vector(2+15 downto 0); |
buf_nxt : std_ulogic_vector(2+15 downto 0); |
end record; |
signal issue_engine : issue_engine_t; |
|
-- instruction buffer -- |
type i_buf_t is record |
wdata : std_ulogic_vector(35 downto 0); -- 4-bit status + 32-bit instruction |
rdata : std_ulogic_vector(35 downto 0); -- 4-bit status + 32-bit instruction |
status : std_ulogic; |
clear : std_ulogic; |
we : std_ulogic; |
re : std_ulogic; |
free : std_ulogic; |
avail : std_ulogic; |
end record; |
signal i_buf : i_buf_t; |
|
-- instruction execution engine -- |
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, CSR_ACCESS); |
type execute_engine_t is record |
257,16 → 277,16
begin |
|
-- **************************************************************************************************************************** |
-- Instruction Fetch |
-- Instruction Fetch (always fetches aligned 32-bit chunks of data) |
-- **************************************************************************************************************************** |
|
-- Fetch Engine FSM Sync ------------------------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
-- registers that require a specific reset state -- |
fetch_engine_fsm_sync_rst: process(rstn_i, clk_i) |
fetch_engine_fsm_sync: process(rstn_i, clk_i) |
begin |
if (rstn_i = '0') then |
fetch_engine.state <= IFETCH_RESET; |
fetch_engine.pc <= (others => '0'); |
elsif rising_edge(clk_i) then |
if (fetch_engine.reset = '1') then |
fetch_engine.state <= IFETCH_RESET; |
273,114 → 293,55
else |
fetch_engine.state <= fetch_engine.state_nxt; |
end if; |
fetch_engine.pc <= fetch_engine.pc_nxt; |
end if; |
end process fetch_engine_fsm_sync_rst; |
|
|
-- registers that DO NOT require a specific reset state -- |
fetch_engine_fsm_sync: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (fetch_engine.state = IFETCH_RESET) then |
fetch_engine.pc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC |
else |
fetch_engine.pc <= std_ulogic_vector(unsigned(fetch_engine.pc(data_width_c-1 downto 1) & '0') + unsigned(fetch_engine.pc_add(data_width_c-1 downto 1) & '0')); |
end if; |
-- |
fetch_engine.i_buf <= fetch_engine.i_buf_nxt; |
fetch_engine.i_buf2 <= fetch_engine.i_buf2_nxt; |
fetch_engine.i_buf_state <= fetch_engine.i_buf_state_nxt; |
end if; |
end process fetch_engine_fsm_sync; |
|
-- PC output -- |
fetch_pc_o <= fetch_engine.pc(data_width_c-1 downto 1) & '0'; |
fetch_pc_o <= fetch_engine.pc(data_width_c-1 downto 1) & '0'; -- half-word aligned |
|
|
-- Fetch Engine FSM Comb ------------------------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
fetch_engine_fsm_comb: process(fetch_engine, csr, ipb, instr_i, bus_i_wait_i, ci_instr32, ci_illegal, be_instr_i, ma_instr_i) |
fetch_engine_fsm_comb: process(fetch_engine, execute_engine, ipb, instr_i, bus_i_wait_i, be_instr_i, ma_instr_i) |
begin |
-- arbiter defaults -- |
bus_fast_ir <= '0'; |
fetch_engine.state_nxt <= fetch_engine.state; |
fetch_engine.pc_add <= (others => '0'); |
fetch_engine.i_buf_nxt <= fetch_engine.i_buf; |
fetch_engine.i_buf2_nxt <= fetch_engine.i_buf2; |
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state; |
fetch_engine.ci_input <= fetch_engine.i_buf2(15 downto 00); |
fetch_engine.bus_err_ack <= '0'; |
bus_fast_ir <= '0'; |
fetch_engine.state_nxt <= fetch_engine.state; |
fetch_engine.pc_nxt <= fetch_engine.pc; |
fetch_engine.bus_err_ack <= '0'; |
|
-- instruction prefetch buffer interface -- |
ipb.we <= '0'; |
ipb.wdata <= be_instr_i & ma_instr_i & instr_i(31 downto 0); -- store exception info and instruction word |
ipb.clear <= '0'; |
ipb.wdata <= (others => '0'); |
|
-- state machine -- |
case fetch_engine.state is |
|
when IFETCH_RESET => -- reset engine, prefetch buffer, get appilcation PC |
when IFETCH_RESET => -- reset engine and prefetch buffer, get appilcation PC |
-- ------------------------------------------------------------ |
fetch_engine.i_buf_state_nxt <= (others => '0'); |
ipb.clear <= '1'; -- clear instruction prefetch buffer |
fetch_engine.state_nxt <= IFETCH_0; |
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer |
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer |
fetch_engine.pc_nxt <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC |
ipb.clear <= '1'; -- clear prefetch buffer |
fetch_engine.state_nxt <= IFETCH_REQUEST; |
|
when IFETCH_0 => -- output current PC to bus system, request 32-bit word |
when IFETCH_REQUEST => -- output current PC to bus system and request 32-bit (aligned!) instruction data |
-- ------------------------------------------------------------ |
bus_fast_ir <= '1'; -- fast instruction fetch request |
fetch_engine.state_nxt <= IFETCH_1; |
if (ipb.free = '1') then -- free entry in buffer? |
bus_fast_ir <= '1'; -- fast instruction fetch request |
fetch_engine.state_nxt <= IFETCH_ISSUE; |
end if; |
|
when IFETCH_1 => -- store data from memory to buffer(s) |
when IFETCH_ISSUE => -- store instruction data to prefetch buffer |
-- ------------------------------------------------------------ |
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response |
fetch_engine.i_buf_nxt <= be_instr_i & ma_instr_i & instr_i(31 downto 0); -- store data word and exception info |
fetch_engine.i_buf2_nxt <= fetch_engine.i_buf; |
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state(0) & '1'; |
if (fetch_engine.i_buf_state(0) = '1') then -- buffer filled? |
fetch_engine.state_nxt <= IFETCH_2; |
else |
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c)); |
fetch_engine.state_nxt <= IFETCH_0; -- get another instruction word |
end if; |
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer |
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4); |
ipb.we <= '1'; |
fetch_engine.state_nxt <= IFETCH_REQUEST; |
end if; |
|
when IFETCH_2 => -- construct instruction word and issue |
-- ------------------------------------------------------------ |
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer |
if (fetch_engine.pc(1) = '0') or (CPU_EXTENSION_RISCV_C = false) then -- 32-bit aligned |
fetch_engine.ci_input <= fetch_engine.i_buf2(15 downto 00); |
|
if (ipb.free = '1') then -- free entry in buffer? |
ipb.we <= '1'; |
if (fetch_engine.i_buf2(01 downto 00) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed |
ipb.wdata <= '0' & fetch_engine.i_buf2(33 downto 32) & '0' & fetch_engine.i_buf2(31 downto 0); |
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c)); |
fetch_engine.state_nxt <= IFETCH_0; |
else -- compressed |
ipb.wdata <= ci_illegal & fetch_engine.i_buf2(33 downto 32) & '1' & ci_instr32; |
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(2, data_width_c)); |
fetch_engine.state_nxt <= IFETCH_2; -- try to get another 16-bit instruction word in next round |
end if; |
end if; |
|
else -- 16-bit aligned |
fetch_engine.ci_input <= fetch_engine.i_buf2(31 downto 16); |
|
if (ipb.free = '1') then -- free entry in buffer? |
ipb.we <= '1'; |
if (fetch_engine.i_buf2(17 downto 16) = "11") then -- uncompressed and "unaligned" |
ipb.wdata <= '0' & fetch_engine.i_buf(33 downto 32) & '0' & fetch_engine.i_buf(15 downto 00) & fetch_engine.i_buf2(31 downto 16); |
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c)); |
fetch_engine.state_nxt <= IFETCH_0; |
else -- compressed |
ipb.wdata <= ci_illegal & fetch_engine.i_buf(33 downto 32) & '1' & ci_instr32; |
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(2, data_width_c)); |
fetch_engine.state_nxt <= IFETCH_0; |
end if; |
end if; |
end if; |
|
when others => -- undefined |
-- ------------------------------------------------------------ |
fetch_engine.state_nxt <= IFETCH_RESET; |
389,27 → 350,6
end process fetch_engine_fsm_comb; |
|
|
-- Compressed Instructions Recoding ------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
neorv32_cpu_decompressor_inst_true: |
if (CPU_EXTENSION_RISCV_C = true) generate |
neorv32_cpu_decompressor_inst: neorv32_cpu_decompressor |
port map ( |
-- instruction input -- |
ci_instr16_i => fetch_engine.ci_input, -- compressed instruction input |
-- instruction output -- |
ci_illegal_o => ci_illegal, -- is an illegal compressed instruction |
ci_instr32_o => ci_instr32 -- 32-bit decompressed instruction |
); |
end generate; |
|
neorv32_cpu_decompressor_inst_false: |
if (CPU_EXTENSION_RISCV_C = false) generate |
ci_instr32 <= (others => '0'); |
ci_illegal <= '0'; |
end generate; |
|
|
-- **************************************************************************************************************************** |
-- Instruction Prefetch Buffer |
-- **************************************************************************************************************************** |
429,7 → 369,7
elsif (ipb.we = '1') then |
ipb.w_pnt <= std_ulogic_vector(unsigned(ipb.w_pnt) + 1); |
end if; |
-- read port -- |
-- read ports -- |
if (ipb.clear = '1') then |
ipb.r_pnt <= (others => '0'); |
elsif (ipb.re = '1') then |
448,17 → 388,182
end process instr_prefetch_buffer_data; |
|
-- async read -- |
ipb.rdata <= ipb.data(to_integer(unsigned(ipb.r_pnt(ipb.w_pnt'left-1 downto 0)))); |
ipb.rdata <= ipb.data(to_integer(unsigned(ipb.r_pnt(ipb.r_pnt'left-1 downto 0)))); |
|
-- status -- |
ipb.full <= '1' when (ipb.r_pnt(ipb.r_pnt'left) /= ipb.w_pnt(ipb.w_pnt'left)) and (ipb.r_pnt(ipb.r_pnt'left-1 downto 0) = ipb.w_pnt(ipb.w_pnt'left-1 downto 0)) else '0'; |
ipb.empty <= '1' when (ipb.r_pnt(ipb.r_pnt'left) = ipb.w_pnt(ipb.w_pnt'left)) and (ipb.r_pnt(ipb.r_pnt'left-1 downto 0) = ipb.w_pnt(ipb.w_pnt'left-1 downto 0)) else '0'; |
|
|
ipb.free <= not ipb.full; |
ipb.avail <= not ipb.empty; |
|
|
-- **************************************************************************************************************************** |
-- Instruction Issue (recoding of compressed instructions and 32-bit instruction word construction) |
-- **************************************************************************************************************************** |
|
|
-- Issue Engine FSM Sync ------------------------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
issue_engine_fsm_sync: process(rstn_i, clk_i) |
begin |
if (rstn_i = '0') then |
issue_engine.state <= ISSUE_ACTIVE; |
issue_engine.align <= CPU_BOOT_ADDR(1); |
issue_engine.buf <= (others => '0'); |
elsif rising_edge(clk_i) then |
if (ipb.clear = '1') then |
if (CPU_EXTENSION_RISCV_C = true) then |
if (execute_engine.pc(1) = '1') then -- branch to unaligned address? |
issue_engine.state <= ISSUE_REALIGN; |
issue_engine.align <= '1'; -- aligned on 16-bit boundary |
else |
issue_engine.state <= issue_engine.state_nxt; |
issue_engine.align <= '0'; -- aligned on 32-bit boundary |
end if; |
else |
issue_engine.state <= issue_engine.state_nxt; |
issue_engine.align <= '0'; -- always aligned on 32-bit boundaries |
end if; |
else |
issue_engine.state <= issue_engine.state_nxt; |
issue_engine.align <= issue_engine.align_nxt; |
end if; |
issue_engine.buf <= issue_engine.buf_nxt; |
end if; |
end process issue_engine_fsm_sync; |
|
|
-- Issue Engine FSM Comb ------------------------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
issue_engine_fsm_comb: process(issue_engine, ipb, i_buf, execute_engine, ci_illegal, ci_instr32) |
begin |
-- arbiter defaults -- |
issue_engine.state_nxt <= issue_engine.state; |
issue_engine.align_nxt <= issue_engine.align; |
issue_engine.buf_nxt <= issue_engine.buf; |
|
-- instruction prefetch buffer interface defaults -- |
ipb.re <= '0'; |
|
-- instruction buffer interface defaults -- |
i_buf.we <= '0'; |
i_buf.wdata <= '0' & ipb.rdata(33 downto 32) & '0' & ipb.rdata(31 downto 0); |
|
-- state machine -- |
case issue_engine.state is |
|
when ISSUE_ACTIVE => -- issue instruction if available |
-- ------------------------------------------------------------ |
if (ipb.avail = '1') then -- instructions available? |
|
if (issue_engine.align = '0') or (CPU_EXTENSION_RISCV_C = false) then -- begin check in LOW instruction half-word |
if (i_buf.free = '1') then |
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction |
if (ipb.rdata(1 downto 0) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed and "aligned" |
ipb.re <= '1'; |
i_buf.wdata <= '0' & ipb.rdata(33 downto 32) & '0' & ipb.rdata(31 downto 0); |
i_buf.we <= '1'; |
else -- compressed |
ipb.re <= '1'; |
i_buf.wdata <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32; |
i_buf.we <= '1'; |
issue_engine.align_nxt <= '1'; |
end if; |
end if; |
|
else -- begin check in HIGH instruction half-word |
if (i_buf.free = '1') then |
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction |
if (issue_engine.buf(1 downto 0) = "11") then -- uncompressed and "unaligned" |
ipb.re <= '1'; |
i_buf.wdata <= '0' & issue_engine.buf(17 downto 16) & '0' & (ipb.rdata(15 downto 0) & issue_engine.buf(15 downto 0)); |
i_buf.we <= '1'; |
else -- compressed |
--ipb.re <= '1'; |
i_buf.wdata <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32; |
i_buf.we <= '1'; |
issue_engine.align_nxt <= '0'; |
end if; |
end if; |
end if; |
end if; |
|
when ISSUE_REALIGN => -- re-align input fifos after a branch to an unaligned address |
-- ------------------------------------------------------------ |
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); |
if (ipb.avail = '1') then -- instructions available? |
ipb.re <= '1'; |
issue_engine.state_nxt <= ISSUE_ACTIVE; |
end if; |
|
when others => -- undefined |
-- ------------------------------------------------------------ |
issue_engine.state_nxt <= ISSUE_ACTIVE; |
|
end case; |
end process issue_engine_fsm_comb; |
|
-- 16-bit instruction: half-word select -- |
ci_instr16 <= ipb.rdata(15 downto 0) when (issue_engine.align = '0') else issue_engine.buf(15 downto 0); |
|
|
-- Compressed Instructions Recoding ------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
neorv32_cpu_decompressor_inst_true: |
if (CPU_EXTENSION_RISCV_C = true) generate |
neorv32_cpu_decompressor_inst: neorv32_cpu_decompressor |
port map ( |
-- instruction input -- |
ci_instr16_i => ci_instr16, -- compressed instruction input |
-- instruction output -- |
ci_illegal_o => ci_illegal, -- is an illegal compressed instruction |
ci_instr32_o => ci_instr32 -- 32-bit decompressed instruction |
); |
end generate; |
|
neorv32_cpu_decompressor_inst_false: |
if (CPU_EXTENSION_RISCV_C = false) generate |
ci_instr32 <= (others => '0'); |
ci_illegal <= '0'; |
end generate; |
|
|
-- Instruction Buffer --------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
instruction_buffer_ctrl: process(rstn_i, clk_i) |
begin |
if (rstn_i = '0') then |
i_buf.status <= '0'; |
elsif rising_edge(clk_i) then |
if (i_buf.clear = '1') then |
i_buf.status <= '0'; |
elsif (i_buf.we = '1') then |
i_buf.status <= '1'; |
elsif (i_buf.re = '1') then |
i_buf.status <= '0'; |
end if; |
end if; |
end process instruction_buffer_ctrl; |
|
instruction_buffer_data: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (i_buf.we = '1') and (ipb.clear = '0') then |
i_buf.rdata <= i_buf.wdata; |
end if; |
end if; |
end process instruction_buffer_data; |
|
-- status -- |
i_buf.free <= not i_buf.status; |
i_buf.avail <= i_buf.status; |
|
-- clear i_buf when clearing ipb -- |
i_buf.clear <= ipb.clear; |
|
|
-- **************************************************************************************************************************** |
-- Instruction Execution |
-- **************************************************************************************************************************** |
|
584,7 → 689,7
|
-- Execute Engine FSM Comb ---------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl, csr_acc_valid, |
execute_engine_fsm_comb: process(execute_engine, fetch_engine, i_buf, trap_ctrl, csr, ctrl, csr_acc_valid, |
alu_res_i, alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i) |
variable alu_immediate_v : std_ulogic; |
variable rs1_is_r0_v : std_ulogic; |
602,7 → 707,7
|
-- instruction dispatch -- |
fetch_engine.reset <= '0'; |
ipb.re <= '0'; |
i_buf.re <= '0'; |
|
-- trap environment control -- |
trap_ctrl.env_start_ack <= '0'; |
658,28 → 763,28
-- |
execute_engine.state_nxt <= DISPATCH; |
|
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB) |
when DISPATCH => -- Get new command from instruction buffer (I_BUF) |
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= ipb.rdata(instr_rd_msb_c downto instr_rd_lsb_c); -- rd addr |
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= ipb.rdata(instr_rs1_msb_c downto instr_rs1_lsb_c); -- rs1 addr |
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ipb.rdata(instr_rs2_msb_c downto instr_rs2_lsb_c); -- rs2 addr |
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= i_buf.rdata(instr_rd_msb_c downto instr_rd_lsb_c); -- rd addr |
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= i_buf.rdata(instr_rs1_msb_c downto instr_rs1_lsb_c); -- rs1 addr |
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= i_buf.rdata(instr_rs2_msb_c downto instr_rs2_lsb_c); -- rs2 addr |
-- |
if (ipb.avail = '1') then -- instruction available? |
ipb.re <= '1'; |
if (i_buf.avail = '1') then -- instruction available? |
i_buf.re <= '1'; |
-- |
execute_engine.is_ci_nxt <= ipb.rdata(32); -- flag to indicate this is a de-compressed instruction beeing executed |
execute_engine.i_reg_nxt <= ipb.rdata(31 downto 0); |
execute_engine.is_ci_nxt <= i_buf.rdata(32); -- flag to indicate this is a de-compressed instruction beeing executed |
execute_engine.i_reg_nxt <= i_buf.rdata(31 downto 0); |
execute_engine.if_rst_nxt <= '0'; |
-- |
trap_ctrl.instr_ma <= ipb.rdata(33); -- misaligned instruction fetch address |
trap_ctrl.instr_be <= ipb.rdata(34); -- bus access fault during instrucion fetch |
illegal_compressed <= ipb.rdata(35); -- invalid decompressed instruction |
trap_ctrl.instr_ma <= i_buf.rdata(33); -- misaligned instruction fetch address |
trap_ctrl.instr_be <= i_buf.rdata(34); -- bus access fault during instrucion fetch |
illegal_compressed <= i_buf.rdata(35); -- invalid decompressed instruction |
-- |
if (execute_engine.if_rst = '0') then -- if there was NO non-linear PC modification |
execute_engine.pc_nxt <= execute_engine.next_pc; |
end if; |
-- |
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or ((ipb.rdata(33) or ipb.rdata(34)) = '1') then |
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or ((i_buf.rdata(33) or i_buf.rdata(34)) = '1') then |
execute_engine.state_nxt <= TRAP; |
else |
execute_engine.state_nxt <= EXECUTE; |
/core/neorv32_package.vhd
41,7 → 41,7
-- Architecture Constants ----------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
constant data_width_c : natural := 32; -- data width - do not change! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040405"; -- no touchy! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040408"; -- no touchy! |
constant pmp_max_r_c : natural := 8; -- max PMP regions - FIXED! |
|
-- Architecture Configuration ------------------------------------------------------------- |
49,6 → 49,7
constant ispace_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"00000000"; -- default instruction memory address space base address |
constant dspace_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"80000000"; -- default data memory address space base address |
constant bus_timeout_c : natural := 127; -- cycles after which a valid bus access will timeout and triggers an access exception |
constant wb_pipe_mode_c : boolean := false; -- false: classic/standard wishbone mode, true: pipelined wishbone mode (better timing) |
constant ipb_entries_c : natural := 2; -- entries in instruction prefetch buffer, must be a power of 2, default=2 |
constant rf_r0_is_reg_c : boolean := true; -- reg_file.r0 is a physical register that has to be initialized to zero |
|
1057,6 → 1058,7
component neorv32_wishbone |
generic ( |
INTERFACE_REG_STAGES : natural := 2; -- number of interface register stages (0,1,2) |
WB_PIPELINED_MODE : boolean := false; -- false: classic/standard wishbone mode, true: pipelined wishbone mode |
-- Internal instruction memory -- |
MEM_INT_IMEM_USE : boolean := true; -- implement processor-internal instruction memory |
MEM_INT_IMEM_SIZE : natural := 8*1024; -- size of processor-internal instruction memory in bytes |
/core/neorv32_top.vhd
511,6 → 511,7
neorv32_wishbone_inst: neorv32_wishbone |
generic map ( |
INTERFACE_REG_STAGES => MEM_EXT_REG_STAGES, -- number of interface register stages (0,1,2) |
WB_PIPELINED_MODE => wb_pipe_mode_c, -- false: classic/standard wishbone mode, true: pipelined wishbone mode |
-- Internal instruction memory -- |
MEM_INT_IMEM_USE => MEM_INT_IMEM_USE, -- implement processor-internal instruction memory |
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes |
/core/neorv32_wishbone.vhd
3,7 → 3,9
-- # ********************************************************************************************* # |
-- # The interface is either unregistered (INTERFACE_REG_STAGES = 0), only outgoing signals are # |
-- # registered (INTERFACE_REG_STAGES = 1) or incoming and outgoing signals are registered # |
-- # (INTERFACE_REG_STAGES = 2). # |
-- # (INTERFACE_REG_STAGES = 2). This interface supports classic/standard Wishbone transactions # |
-- # (WB_PIPELINED_MODE = false) and also pipelined transactions for improved timing # |
-- # (WB_PIPELINED_MODE = true). # |
-- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # |
-- # All bus accesses from the CPU, which do not target the internal IO region, the internal boot- # |
-- # loader or the internal instruction or data memories (if implemented), are delegated via this # |
50,6 → 52,7
entity neorv32_wishbone is |
generic ( |
INTERFACE_REG_STAGES : natural := 2; -- number of interface register stages (0,1,2) |
WB_PIPELINED_MODE : boolean := false; -- false: classic/standard wishbone mode, true: pipelined wishbone mode |
-- Internal instruction memory -- |
MEM_INT_IMEM_USE : boolean := true; -- implement processor-internal instruction memory |
MEM_INT_IMEM_SIZE : natural := 8*1024; -- size of processor-internal instruction memory in bytes |
95,6 → 98,7
signal rb_en : std_ulogic; |
|
-- bus arbiter -- |
signal wb_we_ff : std_ulogic; |
signal wb_stb_ff0 : std_ulogic; |
signal wb_stb_ff1 : std_ulogic; |
signal wb_cyc_ff : std_ulogic; |
101,6 → 105,10
signal wb_ack_ff : std_ulogic; |
signal wb_err_ff : std_ulogic; |
|
-- wishbone mode: standard / pipelined -- |
signal stb_int_std : std_ulogic; |
signal stb_int_pipe : std_ulogic; |
|
-- data read-back -- |
signal wb_rdata : std_ulogic_vector(31 downto 0); |
|
115,11 → 123,14
-- Access Control ------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
-- access to internal IMEM or DMEM? -- |
int_imem_acc <= '1' when (addr_i >= imem_base_c) and (addr_i < std_ulogic_vector(unsigned(imem_base_c) + MEM_INT_IMEM_SIZE)) else '0'; |
int_dmem_acc <= '1' when (addr_i >= dmem_base_c) and (addr_i < std_ulogic_vector(unsigned(dmem_base_c) + MEM_INT_DMEM_SIZE)) else '0'; |
int_imem_acc <= '1' when (addr_i(31 downto index_size_f(MEM_INT_IMEM_SIZE)) = imem_base_c(31 downto index_size_f(MEM_INT_IMEM_SIZE))) else '0'; |
int_dmem_acc <= '1' when (addr_i(31 downto index_size_f(MEM_INT_DMEM_SIZE)) = dmem_base_c(31 downto index_size_f(MEM_INT_DMEM_SIZE))) else '0'; |
int_imem_acc_real <= int_imem_acc when (MEM_INT_IMEM_USE = true) else '0'; |
int_dmem_acc_real <= int_dmem_acc when (MEM_INT_DMEM_USE = true) else '0'; |
|
-- access to internal BOOTROM or IO devices? -- |
int_boot_acc <= '1' when (addr_i >= boot_rom_base_c) else '0'; -- this also covers access to the IO space |
--int_boot_acc <= '1' when (addr_i(31 downto index_size_f(2*boot_rom_max_size_c)) = boot_rom_base_c(31 downto index_size_f(2*boot_rom_max_size_c))) else '0'; -- this also covers access to the IO space |
--int_io_acc <= '1' when (addr_i >= io_base_c) else '0'; |
|
-- actual external bus access? -- |
131,6 → 142,7
bus_arbiter: process(rstn_i, clk_i) |
begin |
if (rstn_i = '0') then |
wb_we_ff <= '0'; |
wb_cyc_ff <= '0'; |
wb_stb_ff1 <= '0'; |
wb_stb_ff0 <= '0'; |
139,6 → 151,8
wb_access_ff <= '0'; |
wb_access_ff_ff <= '0'; |
elsif rising_edge(clk_i) then |
-- read/write -- |
wb_we_ff <= (wb_we_ff or wren_i) and wb_access and (not wb_ack_i) and (not wb_err_i) and (not cancel_i); |
-- bus cycle -- |
if (INTERFACE_REG_STAGES = 0) then |
wb_cyc_ff <= '0'; -- unused |
162,11 → 176,14
end if; |
end process bus_arbiter; |
|
-- bus cycle -- |
-- valid bus cycle -- |
wb_cyc_o <= wb_access when (INTERFACE_REG_STAGES = 0) else wb_cyc_ff; |
|
-- bus_strobe: rising edge detector -- |
wb_stb_o <= (wb_access and (not wb_stb_ff0)) when (INTERFACE_REG_STAGES = 0) else (wb_stb_ff0 and (not wb_stb_ff1)); |
-- bus strobe -- |
stb_int_std <= wb_access when (INTERFACE_REG_STAGES = 0) else wb_cyc_ff; -- same as wb_cyc |
stb_int_pipe <= (wb_access and (not wb_stb_ff0)) when (INTERFACE_REG_STAGES = 0) else (wb_stb_ff0 and (not wb_stb_ff1)); -- wb_access rising edge detector |
-- |
wb_stb_o <= stb_int_std when (WB_PIPELINED_MODE = false) else stb_int_pipe; -- standard or pipelined mode |
|
-- cpu ack -- |
ack_o <= wb_ack_ff when (INTERFACE_REG_STAGES = 2) else wb_ack_i; |
187,7 → 204,7
wb_adr_o <= addr_i; |
wb_dat_o <= data_i; |
wb_sel_o <= ben_i; |
wb_we_o <= wren_i; |
wb_we_o <= wren_i or wb_we_ff; |
end generate; |
|
interface_reg_level_one: |
199,7 → 216,7
wb_adr_o <= addr_i; |
wb_dat_o <= data_i; |
wb_sel_o <= ben_i; |
wb_we_o <= wren_i; |
wb_we_o <= wren_i or wb_we_ff; |
end if; |
end if; |
end process buffer_stages_one; |
215,7 → 232,7
wb_adr_o <= addr_i; |
wb_dat_o <= data_i; |
wb_sel_o <= ben_i; |
wb_we_o <= wren_i; |
wb_we_o <= wren_i or wb_we_ff; |
end if; |
if (wb_ack_i = '1') then |
wb_rdata <= wb_dat_i; |