diff --git a/CHANGELOG.md b/CHANGELOG.md index c3c49671a..121c4db4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date (*dd.mm.yyyy*) | Version | Comment | |:-------------------:|:-------:|:--------| +| 29.09.2023 | 1.8.9.5 | minor CPU optimizations and code clean-ups; [#694](https://github.com/stnolting/neorv32/pull/694) | | 23.09.2023 | 1.8.9.4 | :sparkles: added vectored trap handling mode of `mtvec` for reduced latency from IRQ to ISR; [#691](https://github.com/stnolting/neorv32/pull/691) | 22.09.2023 | 1.8.9.3 | :lock: **watchdog**: add reset password and optional "strict" mode for increased safety; [#692](https://github.com/stnolting/neorv32/pull/692) | | 15.09.2023 | 1.8.9.2 | :warning: rework CFU CSRs; minor rtl edits; [#690](https://github.com/stnolting/neorv32/pull/690) | diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index 1efb87b4e..c7600b6fb 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -462,7 +462,7 @@ The `I` ISA extensions is the base RISC-V integer ISA that is always enabled. | Jump/call | `jal[r]` | 6 | Load/store | `lb` `lh` `lw` `lbu` `lhu` `sb` `sh` `sw` | 5 | System | `ecall` `ebreak` | 3 -| Data fence | `fence` | 5 +| Data fence | `fence` | 3 | System | `wfi` | 3 | System | `mret` | 5 | Illegal inst. | - | 3 diff --git a/rtl/core/neorv32_cpu.vhd b/rtl/core/neorv32_cpu.vhd index 3106fdf12..03b4fe647 100644 --- a/rtl/core/neorv32_cpu.vhd +++ b/rtl/core/neorv32_cpu.vhd @@ -122,7 +122,7 @@ architecture neorv32_cpu_rtl of neorv32_cpu is signal alu_cmp : std_ulogic_vector(1 downto 0); -- comparator result signal mem_rdata : std_ulogic_vector(XLEN-1 downto 0); -- memory read data signal cp_done : std_ulogic; -- ALU co-processor operation done - signal bus_d_wait : std_ulogic; -- wait for current data bus access + signal lsu_wait : std_ulogic; -- wait for current data bus access signal csr_rdata : std_ulogic_vector(XLEN-1 downto 0); -- csr read data signal mar : std_ulogic_vector(XLEN-1 downto 0); -- memory address register signal ma_load : std_ulogic; -- misaligned load data address @@ -218,47 +218,45 @@ begin ) port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_i, -- global reset, low-active, async - ctrl_o => ctrl, -- main control bus + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_o => ctrl, -- main control bus -- instruction fetch interface -- - i_bus_addr_o => fetch_pc, -- bus access address - i_bus_rdata_i => ibus_rsp_i.data, -- bus read data - i_bus_re_o => ibus_req_o.re, -- read enable - i_bus_ack_i => ibus_rsp_i.ack, -- bus transfer acknowledge - i_bus_err_i => ibus_rsp_i.err, -- bus transfer error - i_pmp_fault_i => pmp_i_fault, -- instruction fetch pmp fault + bus_req_o => ibus_req_o, -- request + bus_rsp_i => ibus_rsp_i, -- response -- status input -- - alu_cp_done_i => cp_done, -- ALU iterative operation done - bus_d_wait_i => bus_d_wait, -- wait for bus + i_pmp_fault_i => pmp_i_fault, -- instruction fetch pmp fault + alu_cp_done_i => cp_done, -- ALU iterative operation done + lsu_wait_i => lsu_wait, -- wait for data bus + cmp_i => alu_cmp, -- comparator status -- data input -- - cmp_i => alu_cmp, -- comparator status - alu_add_i => alu_add, -- ALU address result - rs1_i => rs1, -- rf source 1 + alu_add_i => alu_add, -- ALU address result + rs1_i => rs1, -- rf source 1 -- data output -- - imm_o => imm, -- immediate - curr_pc_o => curr_pc, -- current PC (corresponding to current instruction) - next_pc_o => next_pc, -- next PC (corresponding to next instruction) - csr_rdata_o => csr_rdata, -- CSR read data + imm_o => imm, -- immediate + fetch_pc_o => fetch_pc, -- instruction fetch address + curr_pc_o => curr_pc, -- current PC (corresponding to current instruction) + next_pc_o => next_pc, -- next PC (corresponding to next instruction) + csr_rdata_o => csr_rdata, -- CSR read data -- external CSR interface -- - xcsr_we_o => xcsr_we, -- global write enable - xcsr_addr_o => xcsr_addr, -- address - xcsr_wdata_o => xcsr_wdata, -- write data - xcsr_rdata_i => xcsr_rdata_res, -- read data + xcsr_we_o => xcsr_we, -- global write enable + xcsr_addr_o => xcsr_addr, -- address + xcsr_wdata_o => xcsr_wdata, -- write data + xcsr_rdata_i => xcsr_rdata_res, -- read data -- debug mode (halt) request -- db_halt_req_i => dbi_i, -- interrupts (risc-v compliant) -- - msi_i => msi_i, -- machine software interrupt - mei_i => mei_i, -- machine external interrupt - mti_i => mti_i, -- machine timer interrupt + msi_i => msi_i, -- machine software interrupt + mei_i => mei_i, -- machine external interrupt + mti_i => mti_i, -- machine timer interrupt -- fast interrupts (custom) -- - firq_i => firq_i, -- fast interrupt trigger + firq_i => firq_i, -- fast interrupt trigger -- bus access exceptions -- - mar_i => mar, -- memory address register - ma_load_i => ma_load, -- misaligned load data address - ma_store_i => ma_store, -- misaligned store data address - be_load_i => be_load, -- bus error on load data access - be_store_i => be_store -- bus error on store data access + mar_i => mar, -- memory address register + ma_load_i => ma_load, -- misaligned load data address + ma_store_i => ma_store, -- misaligned store data address + be_load_i => be_load, -- bus error on load data access + be_store_i => be_store -- bus error on store data access ); -- external CSR read-back -- @@ -272,15 +270,6 @@ begin ifence_o <= ctrl.lsu_fencei; dfence_o <= ctrl.lsu_fence; - -- instruction fetch interface -- - ibus_req_o.addr <= fetch_pc; - ibus_req_o.priv <= ctrl.cpu_priv; - ibus_req_o.data <= (others => '0'); -- read-only - ibus_req_o.ben <= (others => '0'); -- read-only - ibus_req_o.we <= '0'; -- read-only - ibus_req_o.src <= '1'; -- source = instruction fetch - ibus_req_o.rvso <= '0'; -- cannot be a reservation set operation - -- Register File -------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -355,37 +344,26 @@ begin ) port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_i, -- global reset, low-active, async - ctrl_i => ctrl, -- main control bus + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_i => ctrl, -- main control bus -- cpu data access interface -- - addr_i => alu_add, -- access address - wdata_i => rs2, -- write data - rdata_o => mem_rdata, -- read data - mar_o => mar, -- memory address register - d_wait_o => bus_d_wait, -- wait for access to complete - ma_load_o => ma_load, -- misaligned load data address - ma_store_o => ma_store, -- misaligned store data address - be_load_o => be_load, -- bus error on load data access - be_store_o => be_store, -- bus error on store data access - pmp_r_fault_i => pmp_r_fault, -- PMP read fault - pmp_w_fault_i => pmp_w_fault, -- PMP write fault + addr_i => alu_add, -- access address + wdata_i => rs2, -- write data + rdata_o => mem_rdata, -- read data + mar_o => mar, -- memory address register + wait_o => lsu_wait, -- wait for access to complete + ma_load_o => ma_load, -- misaligned load data address + ma_store_o => ma_store, -- misaligned store data address + be_load_o => be_load, -- bus error on load data access + be_store_o => be_store, -- bus error on store data access + pmp_r_fault_i => pmp_r_fault, -- PMP read fault + pmp_w_fault_i => pmp_w_fault, -- PMP write fault -- data bus -- - d_bus_addr_o => dbus_req_o.addr, -- bus access address - d_bus_rdata_i => dbus_rsp_i.data, -- bus read data - d_bus_wdata_o => dbus_req_o.data, -- bus write data - d_bus_ben_o => dbus_req_o.ben, -- byte enable - d_bus_we_o => dbus_req_o.we, -- write enable - d_bus_re_o => dbus_req_o.re, -- read enable - d_bus_ack_i => dbus_rsp_i.ack, -- bus transfer acknowledge - d_bus_err_i => dbus_rsp_i.err -- bus transfer error + bus_req_o => dbus_req_o, -- request + bus_rsp_i => dbus_rsp_i -- response ); - -- data access interface -- - dbus_req_o.priv <= ctrl.lsu_priv; - dbus_req_o.src <= '0'; -- source = data access - dbus_req_o.rvso <= ctrl.lsu_rvso when (CPU_EXTENSION_RISCV_A = true) else '0'; -- is LR/SC reservation set operation - -- Physical Memory Protection ------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_cpu_alu.vhd b/rtl/core/neorv32_cpu_alu.vhd index 84ad6cc02..460c6ec55 100644 --- a/rtl/core/neorv32_cpu_alu.vhd +++ b/rtl/core/neorv32_cpu_alu.vhd @@ -140,7 +140,8 @@ begin when alu_op_add_c => res_o <= addsub_res(XLEN-1 downto 0); when alu_op_sub_c => res_o <= addsub_res(XLEN-1 downto 0); when alu_op_cp_c => res_o <= cp_res; - when alu_op_slt_c => res_o <= (others => '0'); res_o(0) <= addsub_res(addsub_res'left); -- carry/borrow + when alu_op_slt_c => res_o(XLEN-1 downto 1) <= (others => '0'); + res_o(0) <= addsub_res(addsub_res'left); -- carry/borrow when alu_op_movb_c => res_o <= opb; when alu_op_xor_c => res_o <= rs1_i xor opb; -- only rs1 is required for logic ops (opa would also contain pc) when alu_op_or_c => res_o <= rs1_i or opb; diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd index eb517a646..1eedfe27b 100644 --- a/rtl/core/neorv32_cpu_control.vhd +++ b/rtl/core/neorv32_cpu_control.vhd @@ -88,21 +88,19 @@ entity neorv32_cpu_control is rstn_i : in std_ulogic; -- global reset, low-active, async ctrl_o : out ctrl_bus_t; -- main control bus -- instruction fetch interface -- - i_bus_addr_o : out std_ulogic_vector(XLEN-1 downto 0); -- bus access address - i_bus_rdata_i : in std_ulogic_vector(31 downto 0); -- bus read data - i_bus_re_o : out std_ulogic; -- read enable - i_bus_ack_i : in std_ulogic; -- bus transfer acknowledge - i_bus_err_i : in std_ulogic; -- bus transfer error - i_pmp_fault_i : in std_ulogic; -- instruction fetch pmp fault + bus_req_o : out bus_req_t; -- request + bus_rsp_i : in bus_rsp_t; -- response -- status input -- + i_pmp_fault_i : in std_ulogic; -- instruction fetch pmp fault alu_cp_done_i : in std_ulogic; -- ALU iterative operation done - bus_d_wait_i : in std_ulogic; -- wait for bus - -- data input -- + lsu_wait_i : in std_ulogic; -- wait for data bus cmp_i : in std_ulogic_vector(1 downto 0); -- comparator status + -- data input -- alu_add_i : in std_ulogic_vector(XLEN-1 downto 0); -- ALU address result rs1_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 1 -- data output -- imm_o : out std_ulogic_vector(XLEN-1 downto 0); -- immediate + fetch_pc_o : out std_ulogic_vector(XLEN-1 downto 0); -- instruction fetch address curr_pc_o : out std_ulogic_vector(XLEN-1 downto 0); -- current PC (corresponding to current instruction) next_pc_o : out std_ulogic_vector(XLEN-1 downto 0); -- next PC (corresponding to next instruction) csr_rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- CSR read data @@ -189,7 +187,7 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is -- instruction execution engine -- -- make sure reset state is the first item in the list (discussion #415) - type execute_engine_state_t is (DISPATCH, TRAP_ENTER, TRAP_EXIT, TRAP_EXECUTE, SLEEP, + type execute_engine_state_t is (DISPATCH, TRAP_ENTER, TRAP_EXIT, TRAP_EXECUTE, FENCE, SLEEP, EXECUTE, ALU_WAIT, BRANCH, BRANCHED, SYSTEM, MEM_REQ, MEM_WAIT); type execute_engine_t is record state : execute_engine_state_t; @@ -329,15 +327,12 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is signal cnt_event : std_ulogic_vector(hpmcnt_event_size_c-1 downto 0); -- debug mode controller -- - type debug_ctrl_state_t is (DEBUG_OFFLINE, DEBUG_ONLINE, DEBUG_LEAVING); type debug_ctrl_t is record - state : debug_ctrl_state_t; running : std_ulogic; -- CPU is in debug mode trig_hw : std_ulogic; -- hardware trigger trig_break : std_ulogic; -- ebreak instruction trigger trig_halt : std_ulogic; -- external request trigger trig_step : std_ulogic; -- single-stepping mode trigger - dret : std_ulogic; -- executed DRET instruction ext_halt_req : std_ulogic; -- external halt request buffer end record; signal debug_ctrl : debug_ctrl_t; @@ -419,27 +414,36 @@ begin end process fetch_engine_fsm; -- PC output for instruction fetch -- - i_bus_addr_o <= fetch_engine.pc & "00"; -- word aligned + bus_req_o.addr <= fetch_engine.pc & "00"; -- word aligned + fetch_pc_o <= fetch_engine.pc & "00"; -- word aligned -- instruction fetch (read) request if IPB not full -- - i_bus_re_o <= '1' when (fetch_engine.state = IF_REQUEST) and (ipb.free = "11") else '0'; + bus_req_o.re <= '1' when (fetch_engine.state = IF_REQUEST) and (ipb.free = "11") else '0'; -- unaligned access error (no alignment exceptions possible when using C-extension) -- fetch_engine.a_err <= '1' when (fetch_engine.unaligned = '1') and (CPU_EXTENSION_RISCV_C = false) else '0'; -- instruction bus response -- -- [NOTE] PMP and alignment errors will keep pending until the triggered bus access request retires - fetch_engine.resp <= '1' when (i_bus_ack_i = '1') or (i_bus_err_i = '1') else '0'; + fetch_engine.resp <= '1' when (bus_rsp_i.ack = '1') or (bus_rsp_i.err = '1') else '0'; -- IPB instruction data and status -- - ipb.wdata(0) <= (i_bus_err_i or i_pmp_fault_i) & fetch_engine.a_err & i_bus_rdata_i(15 downto 00); - ipb.wdata(1) <= (i_bus_err_i or i_pmp_fault_i) & fetch_engine.a_err & i_bus_rdata_i(31 downto 16); + ipb.wdata(0) <= (bus_rsp_i.err or i_pmp_fault_i) & fetch_engine.a_err & bus_rsp_i.data(15 downto 00); + ipb.wdata(1) <= (bus_rsp_i.err or i_pmp_fault_i) & fetch_engine.a_err & bus_rsp_i.data(31 downto 16); -- IPB write enable -- ipb.we(0) <= '1' when (fetch_engine.state = IF_PENDING) and (fetch_engine.resp = '1') and ((fetch_engine.unaligned = '0') or (CPU_EXTENSION_RISCV_C = false)) else '0'; ipb.we(1) <= '1' when (fetch_engine.state = IF_PENDING) and (fetch_engine.resp = '1') else '0'; + -- bus access type -- + bus_req_o.priv <= ctrl.cpu_priv; + bus_req_o.data <= (others => '0'); -- read-only + bus_req_o.ben <= (others => '0'); -- read-only + bus_req_o.we <= '0'; -- read-only + bus_req_o.src <= '1'; -- source = instruction fetch + bus_req_o.rvso <= '0'; -- cannot be a reservation set operation + -- Instruction Prefetch Buffer (FIFO) ----------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -786,7 +790,7 @@ begin -- Execute Engine FSM Comb ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - execute_engine_fsm_comb: process(execute_engine, debug_ctrl, trap_ctrl, decode_aux, fetch_engine, issue_engine, csr, alu_cp_done_i, bus_d_wait_i) + execute_engine_fsm_comb: process(execute_engine, debug_ctrl, trap_ctrl, decode_aux, fetch_engine, issue_engine, csr, alu_cp_done_i, lsu_wait_i) begin -- arbiter defaults -- execute_engine.state_nxt <= execute_engine.state; @@ -806,7 +810,6 @@ begin trap_ctrl.instr_ma <= '0'; trap_ctrl.env_call <= '0'; trap_ctrl.break_point <= '0'; - debug_ctrl.dret <= '0'; -- csr.we_nxt <= '0'; csr.re_nxt <= '0'; @@ -861,7 +864,7 @@ begin end if; - when TRAP_ENTER => -- Start trap environment and get trap vector + when TRAP_ENTER => -- Enter trap environment and get trap vector -- ------------------------------------------------------------ if (trap_ctrl.env_pending = '1') then trap_ctrl.env_enter <= '1'; @@ -873,7 +876,7 @@ begin trap_ctrl.env_exit <= '1'; execute_engine.state_nxt <= TRAP_EXECUTE; - when TRAP_EXECUTE => -- Process trap environment + when TRAP_EXECUTE => -- Process trap enter/exit (update PC) -- ------------------------------------------------------------ execute_engine.pc_mux_sel <= '0'; -- next_pc fetch_engine.reset <= '1'; @@ -884,8 +887,7 @@ begin when EXECUTE => -- Decode and execute instruction (control has to be here for exactly 1 cycle in any case!) -- [NOTE] register file is read in this stage; due to the sync read, data will be available in the _next_ state -- ------------------------------------------------------------ - -- clear branch flipflop -- - execute_engine.branched_nxt <= '0'; + execute_engine.branched_nxt <= '0'; -- clear branch flipflop -- decode instruction class -- case decode_aux.opcode is @@ -954,25 +956,17 @@ begin when opcode_fence_c => -- fence operations -- ------------------------------------------------------------ - if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then - ctrl_nxt.lsu_fencei <= '1'; -- fence.i - execute_engine.state_nxt <= TRAP_EXECUTE; -- used to flush IPB - else - if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then - ctrl_nxt.lsu_fence <= '1'; -- fence - end if; - execute_engine.state_nxt <= DISPATCH; - end if; + execute_engine.state_nxt <= FENCE; when opcode_fop_c => -- FPU: floating-point operations -- ------------------------------------------------------------ ctrl_nxt.alu_cp_trig(cp_sel_fpu_c) <= '1'; -- trigger FPU CP - execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor exception if FPU not implemented + execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor exception if FPU not implemented when opcode_cust0_c | opcode_cust1_c | opcode_cust2_c | opcode_cust3_c => -- CFU: custom RISC-V instructions -- ------------------------------------------------------------ ctrl_nxt.alu_cp_trig(cp_sel_cfu_c) <= '1'; -- trigger CFU CP - execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor exception if CFU not implemented + execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor exception if CFU not implemented when others => -- environment/CSR operation or ILLEGAL opcode -- ------------------------------------------------------------ @@ -991,6 +985,21 @@ begin end if; + when FENCE => -- memory fence + -- ------------------------------------------------------------ + if (trap_ctrl.exc_buf(exc_iillegal_c) = '1') then -- abort if illegal instruction + execute_engine.state_nxt <= DISPATCH; + elsif (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then + ctrl_nxt.lsu_fencei <= '1'; -- instruction fence + execute_engine.state_nxt <= TRAP_EXECUTE; -- used to flush instruction prefetch buffer + elsif (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then + ctrl_nxt.lsu_fence <= '1'; -- fence + execute_engine.state_nxt <= DISPATCH; + else + execute_engine.state_nxt <= DISPATCH; + end if; + + when BRANCH => -- update PC on taken branches and jumps -- ------------------------------------------------------------ ctrl_nxt.rf_mux <= rf_mux_npc_c; -- return address = next PC @@ -1025,7 +1034,6 @@ begin if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2)) then -- atomic operation ctrl_nxt.lsu_req_rd <= not execute_engine.ir(instr_funct7_lsb_c+2); -- LR.W ctrl_nxt.lsu_req_wr <= execute_engine.ir(instr_funct7_lsb_c+2); -- SC.W - ctrl_nxt.lsu_rvso <= '1'; -- this is a reservation set operation else -- normal load/store ctrl_nxt.lsu_req_rd <= not execute_engine.ir(5); -- load ctrl_nxt.lsu_req_wr <= execute_engine.ir(5); -- store @@ -1036,13 +1044,10 @@ begin when MEM_WAIT => -- wait for bus transaction to finish -- ------------------------------------------------------------ ctrl_nxt.rf_mux <= rf_mux_mem_c; -- RF input = memory read data - if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2)) then - ctrl_nxt.lsu_rvso <= '1'; -- this is a reservation set operation - end if; if (trap_ctrl.exc_buf(exc_laccess_c) = '1') or (trap_ctrl.exc_buf(exc_saccess_c) = '1') or -- bus access error (trap_ctrl.exc_buf(exc_lalign_c) = '1') or (trap_ctrl.exc_buf(exc_salign_c) = '1') then -- alignment error execute_engine.state_nxt <= DISPATCH; -- abort - elsif (bus_d_wait_i = '0') then -- bus system has completed the transaction + elsif (lsu_wait_i = '0') then -- bus system has completed the transaction if ((CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2))) or -- atomic operation (execute_engine.ir(instr_opcode_msb_c-1) = '0') then -- normal load ctrl_nxt.rf_wb_en <= '1'; -- allow write-back to register file @@ -1065,11 +1070,10 @@ begin if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) and -- ENVIRONMENT (trap_ctrl.exc_buf(exc_iillegal_c) = '0') then -- and NOT already identified as illegal instruction case execute_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c) is - when funct12_ecall_c => trap_ctrl.env_call <= '1'; -- ecall - when funct12_ebreak_c => trap_ctrl.break_point <= '1'; -- ebreak - when funct12_mret_c => execute_engine.state_nxt <= TRAP_EXIT; -- mret - when funct12_dret_c => execute_engine.state_nxt <= TRAP_EXIT; debug_ctrl.dret <= '1'; -- dret - when others => execute_engine.state_nxt <= SLEEP; -- "funct12_wfi_c" - wfi/sleep + when funct12_ecall_c => trap_ctrl.env_call <= '1'; -- ecall + when funct12_ebreak_c => trap_ctrl.break_point <= '1'; -- ebreak + when funct12_mret_c | funct12_dret_c => execute_engine.state_nxt <= TRAP_EXIT; -- xRET + when others => execute_engine.state_nxt <= SLEEP; -- "funct12_wfi_c" - wfi/sleep end case; else -- CSR ACCESS - no CSR/GPR will be altered if illegal instruction if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or -- CSRRW: always write CSR @@ -1110,7 +1114,6 @@ begin ctrl_o.lsu_fence <= ctrl.lsu_fence; ctrl_o.lsu_fencei <= ctrl.lsu_fencei; ctrl_o.lsu_priv <= csr.mstatus_mpp when (csr.mstatus_mprv = '1') else csr.privilege_eff; -- effective privilege level for loads/stores in M-mode - ctrl_o.lsu_rvso <= ctrl.lsu_rvso; -- instruction word bit fields -- ctrl_o.ir_funct3 <= execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c); @@ -1341,8 +1344,8 @@ begin case execute_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c) is when funct12_ecall_c | funct12_ebreak_c => illegal_cmd <= '0'; -- ECALL, EBREAK when funct12_mret_c => illegal_cmd <= not csr.privilege; -- MRET allowed in M-mode only - when funct12_wfi_c => illegal_cmd <= (not csr.privilege) and csr.mstatus_tw; -- WFI allowed in M-mode or if TW is zero when funct12_dret_c => illegal_cmd <= not debug_ctrl.running; -- DRET allowed in debug mode only + when funct12_wfi_c => illegal_cmd <= (not csr.privilege) and csr.mstatus_tw; -- WFI allowed in M-mode or if TW is zero when others => illegal_cmd <= '1'; end case; else @@ -2317,48 +2320,29 @@ begin -- Debug Control -------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - ocd_true: - if (CPU_EXTENSION_RISCV_Sdext = true) generate - debug_control: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - debug_ctrl.ext_halt_req <= '0'; - debug_ctrl.state <= DEBUG_OFFLINE; - elsif rising_edge(clk_i) then + debug_control: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + debug_ctrl.ext_halt_req <= '0'; + debug_ctrl.running <= '0'; + elsif rising_edge(clk_i) then + if (CPU_EXTENSION_RISCV_Sdext = true) then debug_ctrl.ext_halt_req <= db_halt_req_i; -- external halt request (from Debug Module) - case debug_ctrl.state is -- state machine - - when DEBUG_OFFLINE => -- waiting to start debug mode - if (trap_ctrl.env_enter = '1') and (trap_ctrl.cause(5) = '1') then -- processing trap entry into debug mode - debug_ctrl.state <= DEBUG_ONLINE; - end if; - - when DEBUG_ONLINE => -- we are in debug mode - if (debug_ctrl.dret = '1') then -- DRET instruction - debug_ctrl.state <= DEBUG_LEAVING; - end if; - - when DEBUG_LEAVING => -- leaving debug mode - if (execute_engine.state = TRAP_EXECUTE) then -- processing trap exit (updating PC and status registers) - debug_ctrl.state <= DEBUG_OFFLINE; - end if; - - when others => -- undefined - debug_ctrl.state <= DEBUG_OFFLINE; - - end case; + if (debug_ctrl.running = '0') then -- debug mode OFFLINE - waiting for entry event + if (trap_ctrl.env_enter = '1') and (trap_ctrl.cause(5) = '1') then + debug_ctrl.running <= '1'; + end if; + else -- debug mode ONLINE - waiting for exit event + if (trap_ctrl.env_exit = '1') then + debug_ctrl.running <= '0'; + end if; + end if; + else + debug_ctrl.ext_halt_req <= '0'; + debug_ctrl.running <= '0'; end if; - end process debug_control; - end generate; - - ocd_false: - if (CPU_EXTENSION_RISCV_Sdext = false) generate - debug_ctrl.ext_halt_req <= '0'; - debug_ctrl.state <= DEBUG_OFFLINE; - end generate; - - -- CPU is in debug mode -- - debug_ctrl.running <= '0' when (debug_ctrl.state = DEBUG_OFFLINE) else '1'; + end if; + end process debug_control; -- debug mode entry triggers -- debug_ctrl.trig_hw <= hw_trigger_fire and (not debug_ctrl.running) and csr.tdata1_action and csr.tdata1_dmode; -- enter debug mode by HW trigger module request (only valid if dmode = 1) diff --git a/rtl/core/neorv32_cpu_lsu.vhd b/rtl/core/neorv32_cpu_lsu.vhd index e266d9107..a321474d2 100644 --- a/rtl/core/neorv32_cpu_lsu.vhd +++ b/rtl/core/neorv32_cpu_lsu.vhd @@ -53,7 +53,7 @@ entity neorv32_cpu_lsu is wdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- write data rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- read data mar_o : out std_ulogic_vector(XLEN-1 downto 0); -- current memory address register - d_wait_o : out std_ulogic; -- wait for access to complete + wait_o : out std_ulogic; -- wait for access to complete ma_load_o : out std_ulogic; -- misaligned load data address ma_store_o : out std_ulogic; -- misaligned store data address be_load_o : out std_ulogic; -- bus error on load data access @@ -61,14 +61,8 @@ entity neorv32_cpu_lsu is pmp_r_fault_i : in std_ulogic; -- PMP read fault pmp_w_fault_i : in std_ulogic; -- PMP write fault -- data bus -- - d_bus_addr_o : out std_ulogic_vector(XLEN-1 downto 0); -- bus access address - d_bus_rdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- bus read data - d_bus_wdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- bus write data - d_bus_ben_o : out std_ulogic_vector((XLEN/8)-1 downto 0); -- byte enable - d_bus_we_o : out std_ulogic; -- write enable - d_bus_re_o : out std_ulogic; -- read enable - d_bus_ack_i : in std_ulogic; -- bus transfer acknowledge - d_bus_err_i : in std_ulogic -- bus transfer error + bus_req_o : out bus_req_t; -- request + bus_rsp_i : in bus_rsp_t -- response ); end neorv32_cpu_lsu; @@ -109,8 +103,33 @@ begin end process mem_adr_reg; -- address output -- - d_bus_addr_o <= mar; - mar_o <= mar; -- for MTVAL CSR + bus_req_o.addr <= mar; + mar_o <= mar; -- for MTVAL CSR + + + -- Access Type ---------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + mem_type_reg: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + bus_req_o.priv <= '0'; + bus_req_o.rvso <= '0'; + elsif rising_edge(clk_i) then + if (ctrl_i.lsu_mo_we = '1') then + -- privilege level -- + bus_req_o.priv <= ctrl_i.lsu_priv; + -- reservation set operation -- + if (AMO_LRSC_ENABLE = true) and (ctrl_i.ir_opcode(2) = opcode_amo_c(2)) then + bus_req_o.rvso <= '1'; + else + bus_req_o.rvso <= '0'; + end if; + end if; + end if; + end process mem_type_reg; + + -- source identifier -- + bus_req_o.src <= '0'; -- 0 = data access -- Write Data: Alignment and Byte Enable -------------------------------------------------- @@ -118,29 +137,29 @@ begin mem_do_reg: process(rstn_i, clk_i) begin if (rstn_i = '0') then - d_bus_wdata_o <= (others => '0'); - d_bus_ben_o <= (others => '0'); + bus_req_o.data <= (others => '0'); + bus_req_o.ben <= (others => '0'); elsif rising_edge(clk_i) then if (ctrl_i.lsu_mo_we = '1') then - d_bus_ben_o <= (others => '0'); -- default case ctrl_i.ir_funct3(1 downto 0) is when "00" => -- byte - d_bus_wdata_o(07 downto 00) <= wdata_i(7 downto 0); - d_bus_wdata_o(15 downto 08) <= wdata_i(7 downto 0); - d_bus_wdata_o(23 downto 16) <= wdata_i(7 downto 0); - d_bus_wdata_o(31 downto 24) <= wdata_i(7 downto 0); - d_bus_ben_o(to_integer(unsigned(addr_i(1 downto 0)))) <= '1'; + bus_req_o.data(07 downto 00) <= wdata_i(7 downto 0); + bus_req_o.data(15 downto 08) <= wdata_i(7 downto 0); + bus_req_o.data(23 downto 16) <= wdata_i(7 downto 0); + bus_req_o.data(31 downto 24) <= wdata_i(7 downto 0); + bus_req_o.ben <= (others => '0'); + bus_req_o.ben(to_integer(unsigned(addr_i(1 downto 0)))) <= '1'; when "01" => -- half-word - d_bus_wdata_o(15 downto 00) <= wdata_i(15 downto 0); - d_bus_wdata_o(31 downto 16) <= wdata_i(15 downto 0); + bus_req_o.data(15 downto 00) <= wdata_i(15 downto 0); + bus_req_o.data(31 downto 16) <= wdata_i(15 downto 0); if (addr_i(1) = '0') then - d_bus_ben_o <= "0011"; -- low half-word + bus_req_o.ben <= "0011"; -- low half-word else - d_bus_ben_o <= "1100"; -- high half-word + bus_req_o.ben <= "1100"; -- high half-word end if; when others => -- word - d_bus_wdata_o <= wdata_i; - d_bus_ben_o <= "1111"; + bus_req_o.data <= wdata_i; + bus_req_o.ben <= "1111"; end case; end if; end if; @@ -159,28 +178,28 @@ begin when "00" => -- byte case mar(1 downto 0) is when "00" => -- byte 0 - rdata_o(7 downto 0) <= d_bus_rdata_i(07 downto 00); - rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(07))); -- sign-ext + rdata_o(7 downto 0) <= bus_rsp_i.data(07 downto 00); + rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and bus_rsp_i.data(07))); -- sign-ext when "01" => -- byte 1 - rdata_o(7 downto 0) <= d_bus_rdata_i(15 downto 08); - rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(15))); -- sign-ext + rdata_o(7 downto 0) <= bus_rsp_i.data(15 downto 08); + rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and bus_rsp_i.data(15))); -- sign-ext when "10" => -- byte 2 - rdata_o(7 downto 0) <= d_bus_rdata_i(23 downto 16); - rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(23))); -- sign-ext + rdata_o(7 downto 0) <= bus_rsp_i.data(23 downto 16); + rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and bus_rsp_i.data(23))); -- sign-ext when others => -- byte 3 - rdata_o(7 downto 0) <= d_bus_rdata_i(31 downto 24); - rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(31))); -- sign-ext + rdata_o(7 downto 0) <= bus_rsp_i.data(31 downto 24); + rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and bus_rsp_i.data(31))); -- sign-ext end case; when "01" => -- half-word if (mar(1) = '0') then - rdata_o(15 downto 0) <= d_bus_rdata_i(15 downto 00); -- low half-word - rdata_o(XLEN-1 downto 16) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(15))); -- sign-ext + rdata_o(15 downto 0) <= bus_rsp_i.data(15 downto 00); -- low half-word + rdata_o(XLEN-1 downto 16) <= (others => ((not ctrl_i.ir_funct3(2)) and bus_rsp_i.data(15))); -- sign-ext else - rdata_o(15 downto 0) <= d_bus_rdata_i(31 downto 16); -- high half-word - rdata_o(XLEN-1 downto 16) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(31))); -- sign-ext + rdata_o(15 downto 0) <= bus_rsp_i.data(31 downto 16); -- high half-word + rdata_o(XLEN-1 downto 16) <= (others => ((not ctrl_i.ir_funct3(2)) and bus_rsp_i.data(31))); -- sign-ext end if; when others => -- word - rdata_o(XLEN-1 downto 0) <= d_bus_rdata_i(XLEN-1 downto 0); -- full word + rdata_o(XLEN-1 downto 0) <= bus_rsp_i.data(XLEN-1 downto 0); -- full word end case; end if; end if; @@ -196,11 +215,11 @@ begin arbiter.pend_rd <= '0'; arbiter.pend_wr <= '0'; elsif rising_edge(clk_i) then - arbiter.bus_err <= d_bus_err_i and (arbiter.pend_rd or arbiter.pend_wr); -- bus error during access + arbiter.bus_err <= bus_rsp_i.err and (arbiter.pend_rd or arbiter.pend_wr); -- bus error during access if (arbiter.pend_rd = '0') and (arbiter.pend_wr = '0') then -- idle arbiter.pend_rd <= ctrl_i.lsu_req_rd; arbiter.pend_wr <= ctrl_i.lsu_req_wr; - elsif (d_bus_ack_i = '1') or (ctrl_i.cpu_trap = '1') then -- normal termination or start of trap handling + elsif (bus_rsp_i.ack = '1') or (ctrl_i.cpu_trap = '1') then -- normal termination or start of trap handling arbiter.pend_rd <= '0'; arbiter.pend_wr <= '0'; end if; @@ -208,7 +227,7 @@ begin end process access_arbiter; -- wait for bus response -- - d_wait_o <= not d_bus_ack_i; + wait_o <= not bus_rsp_i.ack; -- output data access/alignment errors to control unit -- ma_load_o <= arbiter.pend_rd and misaligned; @@ -217,8 +236,8 @@ begin be_store_o <= arbiter.pend_wr and (arbiter.bus_err or pmp_w_fault_i); -- access requests (all source signals are driven by registers!) -- - d_bus_re_o <= ctrl_i.lsu_req_rd and (not misaligned) and (not pmp_r_fault_i); - d_bus_we_o <= ctrl_i.lsu_req_wr and (not misaligned) and (not pmp_w_fault_i); + bus_req_o.re <= ctrl_i.lsu_req_rd and (not misaligned) and (not pmp_r_fault_i); + bus_req_o.we <= ctrl_i.lsu_req_wr and (not misaligned) and (not pmp_w_fault_i); end neorv32_cpu_lsu_rtl; diff --git a/rtl/core/neorv32_dma.vhd b/rtl/core/neorv32_dma.vhd index 67d4e2b3d..2a68331ec 100644 --- a/rtl/core/neorv32_dma.vhd +++ b/rtl/core/neorv32_dma.vhd @@ -69,7 +69,7 @@ architecture neorv32_dma_rtl of neorv32_dma is -- control and status register bits -- constant ctrl_en_c : natural := 0; -- r/w: DMA enable - constant ctrl_auto_c : natural := 1; -- r/w: enable FIRQ-triggered transfer + constant ctrl_auto_c : natural := 1; -- r/w: enable FIRQ-triggered transfer -- constant ctrl_error_rd_c : natural := 8; -- r/-: error during read transfer constant ctrl_error_wr_c : natural := 9; -- r/-: error during write transfer diff --git a/rtl/core/neorv32_gpio.vhd b/rtl/core/neorv32_gpio.vhd index 31ade3bed..9b65a5f2e 100644 --- a/rtl/core/neorv32_gpio.vhd +++ b/rtl/core/neorv32_gpio.vhd @@ -55,7 +55,6 @@ end neorv32_gpio; architecture neorv32_gpio_rtl of neorv32_gpio is - -- accessible regs -- signal din, din_rd, dout, dout_rd : std_ulogic_vector(63 downto 0); begin @@ -84,9 +83,7 @@ begin read_access: process(clk_i) begin if rising_edge(clk_i) then - -- bus handshake -- - bus_rsp_o.ack <= bus_req_i.we or bus_req_i.re; - -- read data -- + bus_rsp_o.ack <= bus_req_i.we or bus_req_i.re; bus_rsp_o.data <= (others => '0'); if (bus_req_i.re = '1') then case bus_req_i.addr(3 downto 2) is @@ -116,9 +113,16 @@ begin end loop; end process pin_mapping; - -- IO -- + -- output -- gpio_o <= dout_rd; - din <= gpio_i when rising_edge(clk_i); -- sample buffer to prevent metastability + + -- synchronize input -- + input_sync: process(clk_i) + begin + if rising_edge(clk_i) then + din <= gpio_i; -- to prevent metastability + end if; + end process input_sync; end neorv32_gpio_rtl; diff --git a/rtl/core/neorv32_intercon.vhd b/rtl/core/neorv32_intercon.vhd index d90768285..88f08a820 100644 --- a/rtl/core/neorv32_intercon.vhd +++ b/rtl/core/neorv32_intercon.vhd @@ -164,6 +164,9 @@ begin -- Device Request Switch ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- x_req_o.addr <= a_req_i.addr when (arbiter.host_sel = '0') else b_req_i.addr; + x_req_o.rvso <= a_req_i.rvso when (arbiter.host_sel = '0') else b_req_i.rvso; + x_req_o.priv <= a_req_i.priv when (arbiter.host_sel = '0') else b_req_i.priv; + x_req_o.src <= a_req_i.src when (arbiter.host_sel = '0') else b_req_i.src; x_req_o.data <= b_req_i.data when (PORT_A_READ_ONLY = true) else a_req_i.data when (PORT_B_READ_ONLY = true) else @@ -173,10 +176,6 @@ begin a_req_i.ben when (PORT_B_READ_ONLY = true) else a_req_i.ben when (arbiter.host_sel = '0') else b_req_i.ben; - x_req_o.rvso <= a_req_i.rvso when (arbiter.host_sel = '0') else b_req_i.rvso; - x_req_o.priv <= a_req_i.priv when (arbiter.host_sel = '0') else b_req_i.priv; - x_req_o.src <= a_req_i.src when (arbiter.host_sel = '0') else b_req_i.src; - x_bus_we <= a_req_i.we when (arbiter.host_sel = '0') else b_req_i.we; x_bus_re <= a_req_i.re when (arbiter.host_sel = '0') else b_req_i.re; x_req_o.we <= x_bus_we or arbiter.we_trig; @@ -210,15 +209,14 @@ end neorv32_bus_switch_rtl; -- # << NEORV32 - Processor Bus Infrastructure: Section Gateway >> # -- # ********************************************************************************************* # -- # Bus gateway to distribute the core's access to the processor's main memory sections: # --- # -> IMEM - internal instruction memory [optional], {rwx} # --- # -> DMEM - internal data memory [optional], {rwx} # --- # -> XIP - memory-mapped XIP flash [optional], {r-x} # --- # -> BOOT - internal bootloader ROM [optional], {r-x} # --- # -> IO - internal IO devices [mandatory], {rw-} # +-- # -> IMEM - internal instruction memory [optional] # +-- # -> DMEM - internal data memory [optional] # +-- # -> XIP - memory-mapped XIP flash [optional] # +-- # -> BOOT - internal bootloader ROM [optional] # +-- # -> IO - internal IO devices [mandatory] # -- # All accesses that do not match any of these sections are redirected to the "external" port. # -- # The gateway-internal bus monitor ensures that all processor-internal accesses are completed # -- # within a fixed time window. # --- # This module also enforces the region's PMAs (physical memory attributes). # -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # @@ -349,7 +347,7 @@ begin (EXT_ENABLE = true) else '0'; - -- Bus Request (also enforce PMAs here) --------------------------------------------------- + -- Bus Request ---------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- request: process(main_req_i, port_sel) begin @@ -372,12 +370,12 @@ begin end if; if (XIP_ENABLE = true) then xip_req_o <= main_req_i; - xip_req_o.we <= '0'; -- PMA: read-only + xip_req_o.we <= main_req_i.we and port_sel(port_xip_c); xip_req_o.re <= main_req_i.re and port_sel(port_xip_c); end if; if (BOOT_ENABLE = true) then boot_req_o <= main_req_i; - boot_req_o.we <= '0'; -- PMA: read-only + boot_req_o.we <= main_req_i.we and port_sel(port_boot_c); boot_req_o.re <= main_req_i.re and port_sel(port_boot_c); end if; if (IO_ENABLE = true) then @@ -835,7 +833,7 @@ begin rsvs.state <= "00"; end if; - when others => -- "0-" no active reservation: wait for for new registration request + when others => -- "0-" no active reservation: wait for new registration request -- -------------------------------------------------------------------- if (core_req_i.re = '1') and (core_req_i.rvso = '1') then -- load-reservate instruction rsvs.addr <= core_req_i.addr(31 downto abb_c); diff --git a/rtl/core/neorv32_onewire.vhd b/rtl/core/neorv32_onewire.vhd index 88c0fc175..9b04f3514 100644 --- a/rtl/core/neorv32_onewire.vhd +++ b/rtl/core/neorv32_onewire.vhd @@ -327,8 +327,8 @@ begin when others => -- "0--" OFFLINE: deactivated, reset externally-readable signals -- ------------------------------------------------------------ - serial.sreg <= (others => '0'); - serial.presence <= '0'; + serial.sreg <= (others => '0'); + serial.presence <= '0'; serial.state(1 downto 0) <= "00"; -- stay here, go to IDLE when module is enabled end case; diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 00e30d709..df19a79ad 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -59,7 +59,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080904"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080905"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width, do not change! @@ -534,7 +534,6 @@ package neorv32_package is lsu_fence : std_ulogic; -- fence operation lsu_fencei : std_ulogic; -- fence.i operation lsu_priv : std_ulogic; -- effective privilege level for load/store - lsu_rvso : std_ulogic; -- reservation set operation (atomic LR/SC) -- instruction word -- ir_funct3 : std_ulogic_vector(02 downto 0); -- funct3 bit field ir_funct12 : std_ulogic_vector(11 downto 0); -- funct12 bit field @@ -566,7 +565,6 @@ package neorv32_package is lsu_fence => '0', lsu_fencei => '0', lsu_priv => '0', - lsu_rvso => '0', ir_funct3 => (others => '0'), ir_funct12 => (others => '0'), ir_opcode => (others => '0'), diff --git a/rtl/core/neorv32_twi.vhd b/rtl/core/neorv32_twi.vhd index d79bb4fbd..293df4429 100644 --- a/rtl/core/neorv32_twi.vhd +++ b/rtl/core/neorv32_twi.vhd @@ -90,6 +90,11 @@ architecture neorv32_twi_rtl of neorv32_twi is end record; signal ctrl : ctrl_t; + -- operation triggers -- + signal trig_start : std_ulogic; + signal trig_stop : std_ulogic; + signal trig_data : std_ulogic; + -- clock generator -- type clk_gen_t is record cnt : std_ulogic_vector(3 downto 0); -- clock divider @@ -138,14 +143,26 @@ begin ctrl.csen <= '0'; ctrl.prsc <= (others => '0'); ctrl.cdiv <= (others => '0'); + trig_start <= '0'; + trig_stop <= '0'; + trig_data <= '0'; elsif rising_edge(clk_i) then + -- defaults -- + trig_start <= '0'; + trig_stop <= '0'; + trig_data <= '0'; + -- bus access -- if (bus_req_i.we = '1') then - if (bus_req_i.addr(2) = '0') then + if (bus_req_i.addr(2) = '0') then -- control register ctrl.enable <= bus_req_i.data(ctrl_en_c); ctrl.mack <= bus_req_i.data(ctrl_mack_c); ctrl.csen <= bus_req_i.data(ctrl_csen_c); ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c); ctrl.cdiv <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c); + trig_start <= bus_req_i.data(ctrl_start_c); -- issue START condition + trig_stop <= bus_req_i.data(ctrl_stop_c); -- issue STOP condition + else -- data register + trig_data <= '1'; -- start data transmission end if; end if; end if; @@ -158,7 +175,7 @@ begin bus_rsp_o.ack <= bus_req_i.re or bus_req_i.we; -- bus handshake bus_rsp_o.data <= (others => '0'); if (bus_req_i.re = '1') then - if (bus_req_i.addr(2) = '0') then + if (bus_req_i.addr(2) = '0') then -- control register bus_rsp_o.data(ctrl_en_c) <= ctrl.enable; bus_rsp_o.data(ctrl_mack_c) <= ctrl.mack; bus_rsp_o.data(ctrl_csen_c) <= ctrl.csen; @@ -168,7 +185,7 @@ begin bus_rsp_o.data(ctrl_claimed_c) <= arbiter.claimed; bus_rsp_o.data(ctrl_ack_c) <= not arbiter.rtx_sreg(0); bus_rsp_o.data(ctrl_busy_c) <= arbiter.busy; - else + else -- data register bus_rsp_o.data(7 downto 0) <= arbiter.rtx_sreg(8 downto 1); end if; end if; @@ -210,7 +227,7 @@ begin if rising_edge(clk_i) then clk_gen.phase_gen_ff <= clk_gen.phase_gen; if (arbiter.state(2) = '0') or (arbiter.state(1 downto 0) = "00") then -- offline or idle - clk_gen.phase_gen <= "0001"; -- make sure to start with a new phase, bit stepping: 0-1-2-3 + clk_gen.phase_gen <= "0001"; -- make sure to start with a new phase else if (clk_gen.tick = '1') and (clk_gen.halt = '0') then -- clock tick and no clock stretching detected clk_gen.phase_gen <= clk_gen.phase_gen(2 downto 0) & clk_gen.phase_gen(3); -- rotate left @@ -253,19 +270,16 @@ begin when "100" => -- IDLE: waiting for operation requests -- ------------------------------------------------------------ arbiter.bitcnt <= (others => '0'); - if (bus_req_i.we = '1') then - if (bus_req_i.addr(2) = '0') then - if (bus_req_i.data(ctrl_start_c) = '1') then -- issue START condition - arbiter.state_nxt <= "01"; - elsif (bus_req_i.data(ctrl_stop_c) = '1') then -- issue STOP condition - arbiter.state_nxt <= "10"; - end if; - elsif (bus_req_i.addr(2) = '1') then -- start a data transmission - -- one bit extra for ACK: issued by controller if ctrl_mack_c is set, - -- sampled from peripheral if ctrl_mack_c is cleared - arbiter.rtx_sreg <= bus_req_i.data(7 downto 0) & (not ctrl.mack); - arbiter.state_nxt <= "11"; - end if; + if (trig_start = '1') then -- issue START condition + arbiter.state_nxt <= "01"; + elsif (trig_stop = '1') then -- issue STOP condition + arbiter.state_nxt <= "10"; + elsif (trig_data = '1') then -- start a data transmission + -- one bit extra for ACK: issued by controller if ctrl_mack_c is set, + -- sampled from peripheral if ctrl_mack_c is cleared + -- data_i will stay unchanged for min. 1 cycle after WREN has returned to low again + arbiter.rtx_sreg <= bus_req_i.data(7 downto 0) & (not ctrl.mack); + arbiter.state_nxt <= "11"; end if; -- start operation on next TWI clock pulse -- if (arbiter.state_nxt /= "00") and (clk_gen.tick = '1') then diff --git a/rtl/core/neorv32_wdt.vhd b/rtl/core/neorv32_wdt.vhd index 90d8c9a24..710efe7b8 100644 --- a/rtl/core/neorv32_wdt.vhd +++ b/rtl/core/neorv32_wdt.vhd @@ -175,9 +175,13 @@ begin -- Timeout Counter ------------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - wdt_counter: process(clk_i) + wdt_counter: process(rstn_i, clk_i) begin - if rising_edge(clk_i) then + if (rstn_i = '0') then + cnt_inc_ff <= '0'; + cnt_started <= '0'; + cnt <= (others => '0'); + elsif rising_edge(clk_i) then cnt_inc_ff <= cnt_inc; cnt_started <= ctrl.enable and (cnt_started or prsc_tick); -- start with next clock tick if (ctrl.enable = '0') or (reset_wdt = '1') then -- watchdog disabled or reset with correct password