OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /neorv32/trunk
    from Rev 24 to Rev 25
    Reverse comparison

Rev 24 → Rev 25

/docs/figures/neorv32_cpu.png Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/docs/figures/neorv32_processor.png Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/docs/NEORV32.pdf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/rtl/core/neorv32_cpu_alu.vhd
127,11 → 127,11
when others => opa <= csr_i;
end case;
-- opb (second ALU input operand) --
case ctrl_i(ctrl_alu_opb_mux_msb_c downto ctrl_alu_opb_mux_lsb_c) is
when "00" => opb <= rs2_i;
when "01" => opb <= imm_i;
when others => opb <= rs1_i;
end case;
if (ctrl_i(ctrl_alu_opb_mux_c) = '0') then
opb <= rs2_i;
else
opb <= imm_i;
end if;
-- opc (second operand for comparison and SUB) --
if (ctrl_i(ctrl_alu_opc_mux_c) = '0') then
opc <= imm_i;
251,7 → 251,7
 
-- ALU Function Select --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
alu_function_mux: process(ctrl_i, opa, opb, add_res, sub_res, cmp_less, shifter)
alu_function_mux: process(ctrl_i, opa, opb, add_res, sub_res, cmp_less, shifter.sreg)
begin
case ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) is
when alu_cmd_xor_c => alu_res <= opa xor opb;
/rtl/core/neorv32_cpu_control.vhd
562,13 → 562,9
 
-- CPU Control Bus Output -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
ctrl_output: process(ctrl, execute_engine, fetch_engine, trap_ctrl, csr, bus_fast_ir)
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, csr, bus_fast_ir)
begin
ctrl_o <= ctrl;
-- direct output of register addresses --
ctrl_o(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c);
ctrl_o(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c);
ctrl_o(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= execute_engine.i_reg(instr_rs2_msb_c downto instr_rs2_lsb_c);
-- fast bus access requests --
ctrl_o(ctrl_bus_if_c) <= ctrl(ctrl_bus_if_c) or bus_fast_ir;
-- bus error control --
582,7 → 578,6
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl, csr_acc_valid,
alu_add_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 alu_operation_v : std_ulogic_vector(2 downto 0);
variable rs1_is_r0_v : std_ulogic;
begin
-- arbiter defaults --
625,8 → 620,11
ctrl_nxt(ctrl_alu_shift_ar_c) <= execute_engine.i_reg(30); -- is arithmetic shift
ctrl_nxt(ctrl_bus_size_lsb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- transfer size lsb (00=byte, 01=half-word)
ctrl_nxt(ctrl_bus_size_msb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- transfer size msb (10=word, 11=?)
ctrl_nxt(ctrl_cp_cmd2_c downto ctrl_cp_cmd0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c); -- CP operation
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- only CP0 (MULDIV) implemented yet
ctrl_nxt(ctrl_cp_cmd2_c downto ctrl_cp_cmd0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c); -- CP operation
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- only CP0 (MULDIV) implemented yet
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= ctrl(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c); -- keep rd addr
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= ctrl(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- keep rs1 addr
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ctrl(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c); -- keep rs2 addr
 
-- is immediate operation? --
alu_immediate_v := '0';
634,24 → 632,6
alu_immediate_v := '1';
end if;
 
-- alu operation re-coding --
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_subadd_c => -- SUB / ADD(I)
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not immediate and funct7 = SUB
alu_operation_v := alu_cmd_sub_c;
else
alu_operation_v := alu_cmd_add_c;
end if;
when funct3_sll_c => alu_operation_v := alu_cmd_shift_c; -- SLL(I)
when funct3_slt_c => alu_operation_v := alu_cmd_slt_c; -- SLT(I)
when funct3_sltu_c => alu_operation_v := alu_cmd_slt_c; -- SLTU(I)
when funct3_xor_c => alu_operation_v := alu_cmd_xor_c; -- XOR(I)
when funct3_sr_c => alu_operation_v := alu_cmd_shift_c; -- SRL(I) / SRA(I)
when funct3_or_c => alu_operation_v := alu_cmd_or_c; -- OR(I)
when funct3_and_c => alu_operation_v := alu_cmd_and_c; -- AND(I)
when others => alu_operation_v := (others => '0'); -- undefined
end case;
 
-- is rs1 = r0? --
rs1_is_r0_v := '0';
if (execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
661,20 → 641,35
-- state machine --
case execute_engine.state is
 
when SYS_WAIT => -- Delay cycle (used to wait for side effects to kick in)
when SYS_WAIT => -- System delay cycle (used to wait for side effects to kick in) ((and to init r0 with zero if it is a physical register))
-- ------------------------------------------------------------
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
-- set reg_file.r0 to zero
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= (others => '0'); -- rd addr = r0
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (results zero since there is no valid CSR_read request)
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- allow write access to r0
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
end if;
--
execute_engine.state_nxt <= DISPATCH;
 
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB)
-- ------------------------------------------------------------
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB)
-- ------------------------------------------------------------
if (ipb.avail = '1') then -- instruction available?
ipb.re <= '1';
--
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
--
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
--
execute_engine.is_ci_nxt <= ipb.rdata(32); -- flag to indicate this is a compressed instruction beeing executed
execute_engine.i_reg_nxt <= ipb.rdata(31 downto 0);
execute_engine.if_rst_nxt <= '0';
--
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;
701,47 → 696,64
-- ------------------------------------------------------------
case execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) is
 
when opcode_alu_c | opcode_alui_c => -- ALU operation
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
ctrl_nxt(ctrl_alu_opb_mux_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
ctrl_nxt(ctrl_alu_opc_mux_c) <= not alu_immediate_v;
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_operation_v; -- actual ALU operation
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
 
-- actual ALU operation (re-coding) --
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_subadd_c => -- ADD(I) / SUB
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not immediate and funct7 => SUB
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_sub_c; -- SUB
else
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- ADD(I)
end if;
when funct3_sll_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SLL(I)
when funct3_slt_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLT(I)
when funct3_sltu_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLTU(I)
when funct3_xor_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_xor_c; -- XOR(I)
when funct3_sr_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SRL(I) / SRA(I)
when funct3_or_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- OR(I)
when funct3_and_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_and_c; -- AND(I)
when others => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= (others => '0'); -- undefined
end case;
 
-- cp access? --
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
end if;
 
-- multi cycle alu operation? --
if (alu_operation_v = alu_cmd_shift_c) or -- shift operation?
((CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
(execute_engine.i_reg(instr_funct7_lsb_c) = '1')) then -- MULDIV?
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) or -- SLL shift operation?
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) or -- SR shift operation?
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (execute_engine.i_reg(instr_funct7_lsb_c) = '1')) then -- MULDIV?
execute_engine.state_nxt <= ALU_WAIT;
else
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
end if;
-- cp access? --
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
end if;
 
when opcode_lui_c | opcode_auipc_c => -- load upper immediate (add to PC)
when opcode_lui_c | opcode_auipc_c => -- load upper immediate / add upper immediate to PC
-- ------------------------------------------------------------
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- force RS1 = r0 (only relevant for LUI)
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_auipc_c(5)) then -- AUIPC
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
else -- LUI
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA ( = 0)
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- ALU.OPA = PC (for AUIPC only)
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_lui_c(5)) then -- LUI
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- ALU.OPA = CSR = 0 (hacky: csr.result is 0 since there was no csr_read_request)
end if;
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation = ADD
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
execute_engine.state_nxt <= DISPATCH;
 
when opcode_load_c | opcode_store_c => -- load/store
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation = ADD
ctrl_nxt(ctrl_bus_mar_we_c) <= '1'; -- write to MAR
ctrl_nxt(ctrl_bus_mdo_we_c) <= '1'; -- write to MDO (only relevant for stores)
execute_engine.state_nxt <= LOADSTORE_0;
749,7 → 761,7
when opcode_branch_c => -- branch instruction
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_opc_mux_c) <= '1'; -- use RS2 as ALU.OPC
execute_engine.state_nxt <= BRANCH;
 
761,7 → 773,7
else -- JALR
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA
end if;
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
-- save return address --
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "10"; -- RF input = next PC (save return address)
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
785,6 → 797,9
when opcode_syscsr_c => -- system/csr access
-- ------------------------------------------------------------
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid access
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= (others => '0'); -- set rs1_addr to r0 (zero)
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ctrl(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- copy rs1_addr to rs2_addr (for CSR mod)
--
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
when funct12_ecall_c => -- ECALL
792,12 → 807,12
when funct12_ebreak_c => -- EBREAK
trap_ctrl.break_point <= '1';
when funct12_mret_c => -- MRET
trap_ctrl.env_end <= '1';
execute_engine.pc_nxt <= csr.mepc;
fetch_engine.reset <= '1';
trap_ctrl.env_end <= '1';
execute_engine.pc_nxt <= csr.mepc;
fetch_engine.reset <= '1';
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
when funct12_wfi_c => -- WFI = "CPU sleep"
execute_engine.sleep_nxt <= '1'; -- good night
when funct12_wfi_c => -- WFI (CPU sleep)
execute_engine.sleep_nxt <= '1'; -- sleep well
when others => -- undefined
NULL;
end case;
814,53 → 829,25
 
when CSR_ACCESS => -- write CSR data to RF, write ALU.res to CSR
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '0'; -- default
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- default
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '0'; -- default
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '0'; -- default
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- default ALU operation = OR
ctrl_nxt(ctrl_alu_opb_mux_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- OPB = rs2 (which is rs1 here) / immediate
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
-- register operations --
when funct3_csrrw_c => -- CSRRW
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- OPA = rs1
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = rs1
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
when funct3_csrrw_c | funct3_csrrwi_c => -- CSRRW(I)
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "00"; -- OPA = rs1 (which is zero here)
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
when funct3_csrrs_c => -- CSRRS
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
when funct3_csrrs_c | funct3_csrrsi_c => -- CSRRS(I)
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "10"; -- OPA = CSR
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
when funct3_csrrc_c => -- CSRRC
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
when others => -- CSRRC(I)
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "10"; -- OPA = CSR
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bclr_c; -- actual ALU operation = bit clear
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
-- immediate operations --
when funct3_csrrwi_c => -- CSRRWI
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- OPA = rs1
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- rs1 = 0
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
when funct3_csrrsi_c => -- CSRRSI
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if UIMM5 is not zero (bits from rs1 filed) and if valid access
when funct3_csrrci_c => -- CSRRCI
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bclr_c; -- actual ALU operation = bit clear
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if UIMM5 is not zero (bits from rs1 filed) and if valid access
when others => -- undefined
NULL;
end case;
-- RF write back --
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH; -- FIXME should be SYS_WAIT? have another cycle to let side-effects kick in
execute_engine.state_nxt <= DISPATCH; -- FIXME? should be SYS_WAIT? have another cycle to let side-effects kick in
 
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
-- ------------------------------------------------------------
929,7 → 916,7
 
-- Illegal CSR Access Check ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
invalid_csr_access_check: process(execute_engine, csr)
invalid_csr_access_check: process(execute_engine, csr.privilege)
variable is_m_mode_v : std_ulogic;
begin
-- are we in machine mode? --
/rtl/core/neorv32_cpu_regfile.vhd
2,7 → 2,9
-- # << NEORV32 - CPU Register File >> #
-- # ********************************************************************************************* #
-- # General purpose data registers. 32 entries for normal mode, 16 entries for embedded mode when #
-- # RISC-V M extension is enabled. x0 output is allways set to zero. #
-- # RISC-V "E" extension is enabled. Register zero (r0/x0) is a normal physical registers, that #
-- # has to be initialized to zero by the CPU control system. For normal operations, x0 cannot be #
-- # written. #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
70,13 → 72,8
signal reg_file_emb : reg_file_emb_t;
signal rf_write_data : std_ulogic_vector(data_width_c-1 downto 0); -- actual write-back data
signal valid_wr : std_ulogic; -- writing not to r0
signal rs1_read : std_ulogic_vector(data_width_c-1 downto 0); -- internal operand rs1
signal rs2_read : std_ulogic_vector(data_width_c-1 downto 0); -- internal operand rs2
 
-- reading from r0? --
signal rs1_clear, rs2_clear : std_ulogic;
 
 
-- attributes - these are *NOT mandatory*; just for footprint / timing optimization --
-- -------------------------------------------------------------------------------- --
 
104,9 → 101,9
end case;
end process input_mux;
 
-- only write if destination is not x0 (pretty irrelevant, but might save some power) --
valid_wr <= or_all_f(ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c)) when (CPU_EXTENSION_RISCV_E = false) else
or_all_f(ctrl_i(ctrl_rf_rd_adr3_c downto ctrl_rf_rd_adr0_c));
-- only write if destination is not x0; except we are forcing a r0 write access --
valid_wr <= or_all_f(ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c)) or ctrl_i(ctrl_rf_r0_we_c) when (CPU_EXTENSION_RISCV_E = false) else
or_all_f(ctrl_i(ctrl_rf_rd_adr3_c downto ctrl_rf_rd_adr0_c)) or ctrl_i(ctrl_rf_r0_we_c);
 
 
-- Register file read/write access --------------------------------------------------------
115,49 → 112,25
begin
if rising_edge(clk_i) then -- sync read and write
if (CPU_EXTENSION_RISCV_E = false) then -- normal register file with 32 entries
-- check if reading from r0 --
rs1_clear <= '0';
rs2_clear <= '0';
if (ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) = "00000") then
rs1_clear <= '1';
end if;
if (ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) = "00000") then
rs2_clear <= '1';
end if;
-- write --
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and (valid_wr = '1') then -- valid write-back
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and ((valid_wr = '1') or (rf_r0_is_reg_c = false)) then -- valid write-back
reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c)))) <= rf_write_data;
end if;
-- read --
rs1_read <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c))));
rs2_read <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c))));
rs1_o <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c))));
rs2_o <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c))));
 
else -- embedded register file with 16 entries
-- check if reading from r0 --
rs1_clear <= '0';
rs2_clear <= '0';
if (ctrl_i(ctrl_rf_rs1_adr3_c downto ctrl_rf_rs1_adr0_c) = "0000") then
rs1_clear <= '1';
end if;
if (ctrl_i(ctrl_rf_rs2_adr3_c downto ctrl_rf_rs2_adr0_c) = "0000") then
rs2_clear <= '1';
end if;
-- write --
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and (valid_wr = '1') then -- valid write-back
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and ((valid_wr = '1') or (rf_r0_is_reg_c = false)) then -- valid write-back
reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rd_adr3_c downto ctrl_rf_rd_adr0_c)))) <= rf_write_data;
end if;
-- read --
rs1_read <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr3_c downto ctrl_rf_rs1_adr0_c))));
rs2_read <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr3_c downto ctrl_rf_rs2_adr0_c))));
rs1_o <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr3_c downto ctrl_rf_rs1_adr0_c))));
rs2_o <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr3_c downto ctrl_rf_rs2_adr0_c))));
end if;
end if;
end process rf_access;
 
 
-- Check if reading from x0 ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
rs1_o <= (others => '0') when ((rs1_clear or ctrl_i(ctrl_rf_clear_rs1_c)) = '1') else rs1_read;
rs2_o <= (others => '0') when (rs2_clear = '1') else rs2_read;
 
 
end neorv32_cpu_regfile_rtl;
/rtl/core/neorv32_mtime.vhd
103,16 → 103,16
wr_access: process(clk_i)
begin
if rising_edge(clk_i) then
-- mtimecmp --
if (wren = '1') then
if (addr = mtime_cmp_lo_addr_c) then -- low
mtimecmp_lo <= data_i;
end if;
if (addr = mtime_cmp_hi_addr_c) then -- high
mtimecmp_hi <= data_i;
end if;
-- mtimecmp low --
if (wren = '1') and (addr = mtime_cmp_lo_addr_c) then
mtimecmp_lo <= data_i;
end if;
 
-- mtimecmp high --
if (wren = '1') and (addr = mtime_cmp_hi_addr_c) then
mtimecmp_hi <= data_i;
end if;
 
-- mtime low --
if (wren = '1') and (addr = mtime_time_lo_addr_c) then
mtime_lo_msb_ff <= '0';
140,15 → 140,18
ack_o <= acc_en and (rden_i or wren_i);
data_o <= (others => '0'); -- default
if (rden_i = '1') and (acc_en = '1') then
if (addr = mtime_time_lo_addr_c) then -- mtime LOW
data_o <= mtime_lo(31 downto 00);
elsif (addr = mtime_time_hi_addr_c) then -- mtime HIGH
data_o <= mtime_hi;
elsif (addr = mtime_cmp_lo_addr_c) then -- mtimecmp LOW
data_o <= mtimecmp_lo;
else -- (addr = mtime_cmp_hi_addr_c) then -- mtimecmp HIGH
data_o <= mtimecmp_hi;
end if;
case addr is
when mtime_time_lo_addr_c => -- mtime LOW
data_o <= mtime_lo(31 downto 00);
when mtime_time_hi_addr_c => -- mtime HIGH
data_o <= mtime_hi;
when mtime_cmp_lo_addr_c => -- mtimecmp LOW
data_o <= mtimecmp_lo;
when mtime_cmp_hi_addr_c => -- mtimecmp HIGH
data_o <= mtimecmp_hi;
when others =>
data_o <= (others => '0');
end case;
end if;
end if;
end process rd_access;
/rtl/core/neorv32_package.vhd
40,10 → 40,11
 
-- Architecture Constants/Configuration ---------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant data_width_c : natural := 32; -- data width - FIXED!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040300"; -- no touchy!
constant pmp_max_r_c : natural := 8; -- max PMP regions - FIXED!
constant ipb_entries_c : natural := 2; -- entries in instruction prefetch buffer, must be a power of 2, default=2
constant data_width_c : natural := 32; -- data width - FIXED!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040302"; -- no touchy!
constant pmp_max_r_c : natural := 8; -- max PMP regions - FIXED!
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
 
-- Helper Functions -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
177,7 → 178,7
constant ctrl_rf_rd_adr3_c : natural := 15; -- destiantion register address bit 3
constant ctrl_rf_rd_adr4_c : natural := 16; -- destiantion register address bit 4
constant ctrl_rf_wb_en_c : natural := 17; -- write back enable
constant ctrl_rf_clear_rs1_c : natural := 18; -- force rs1=r0
constant ctrl_rf_r0_we_c : natural := 18; -- allow write access to r0 (zero), also forces dst=r0
-- alu --
constant ctrl_alu_cmd0_c : natural := 19; -- ALU command bit 0
constant ctrl_alu_cmd1_c : natural := 20; -- ALU command bit 1
184,35 → 185,34
constant ctrl_alu_cmd2_c : natural := 21; -- ALU command bit 2
constant ctrl_alu_opa_mux_lsb_c : natural := 22; -- operand A select lsb (00=rs1, 01=PC)
constant ctrl_alu_opa_mux_msb_c : natural := 23; -- operand A select msb (1-=CSR)
constant ctrl_alu_opb_mux_lsb_c : natural := 24; -- operand B select lsb (00=rs2, 01=IMM)
constant ctrl_alu_opb_mux_msb_c : natural := 25; -- operand B select msb (1-=rs1)
constant ctrl_alu_opc_mux_c : natural := 26; -- operand C select (0=IMM, 1=rs2)
constant ctrl_alu_unsigned_c : natural := 27; -- is unsigned ALU operation
constant ctrl_alu_shift_dir_c : natural := 28; -- shift direction (0=left, 1=right)
constant ctrl_alu_shift_ar_c : natural := 29; -- is arithmetic shift
constant ctrl_alu_opb_mux_c : natural := 24; -- operand B select (0=rs2, 1=IMM)
constant ctrl_alu_opc_mux_c : natural := 25; -- operand C select (0=IMM, 1=rs2)
constant ctrl_alu_unsigned_c : natural := 26; -- is unsigned ALU operation
constant ctrl_alu_shift_dir_c : natural := 27; -- shift direction (0=left, 1=right)
constant ctrl_alu_shift_ar_c : natural := 28; -- is arithmetic shift
-- bus interface --
constant ctrl_bus_size_lsb_c : natural := 30; -- transfer size lsb (00=byte, 01=half-word)
constant ctrl_bus_size_msb_c : natural := 31; -- transfer size msb (10=word, 11=?)
constant ctrl_bus_rd_c : natural := 32; -- read data request
constant ctrl_bus_wr_c : natural := 33; -- write data request
constant ctrl_bus_if_c : natural := 34; -- instruction fetch request
constant ctrl_bus_mar_we_c : natural := 35; -- memory address register write enable
constant ctrl_bus_mdo_we_c : natural := 36; -- memory data out register write enable
constant ctrl_bus_mdi_we_c : natural := 37; -- memory data in register write enable
constant ctrl_bus_unsigned_c : natural := 38; -- is unsigned load
constant ctrl_bus_ierr_ack_c : natural := 39; -- acknowledge instruction fetch bus exception
constant ctrl_bus_derr_ack_c : natural := 40; -- acknowledge data access bus exception
constant ctrl_bus_fence_c : natural := 41; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 42; -- executed fencei operation
constant ctrl_bus_size_lsb_c : natural := 29; -- transfer size lsb (00=byte, 01=half-word)
constant ctrl_bus_size_msb_c : natural := 30; -- transfer size msb (10=word, 11=?)
constant ctrl_bus_rd_c : natural := 31; -- read data request
constant ctrl_bus_wr_c : natural := 32; -- write data request
constant ctrl_bus_if_c : natural := 33; -- instruction fetch request
constant ctrl_bus_mar_we_c : natural := 34; -- memory address register write enable
constant ctrl_bus_mdo_we_c : natural := 35; -- memory data out register write enable
constant ctrl_bus_mdi_we_c : natural := 36; -- memory data in register write enable
constant ctrl_bus_unsigned_c : natural := 37; -- is unsigned load
constant ctrl_bus_ierr_ack_c : natural := 38; -- acknowledge instruction fetch bus exception
constant ctrl_bus_derr_ack_c : natural := 39; -- acknowledge data access bus exception
constant ctrl_bus_fence_c : natural := 40; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 41; -- executed fencei operation
-- co-processor --
constant ctrl_cp_use_c : natural := 43; -- is cp operation
constant ctrl_cp_id_lsb_c : natural := 44; -- cp select lsb
constant ctrl_cp_id_msb_c : natural := 45; -- cp select msb
constant ctrl_cp_cmd0_c : natural := 46; -- cp command bit 0
constant ctrl_cp_cmd1_c : natural := 47; -- cp command bit 1
constant ctrl_cp_cmd2_c : natural := 48; -- cp command bit 2
constant ctrl_cp_use_c : natural := 42; -- is cp operation
constant ctrl_cp_id_lsb_c : natural := 43; -- cp select ID lsb
constant ctrl_cp_id_msb_c : natural := 44; -- cp select ID msb
constant ctrl_cp_cmd0_c : natural := 45; -- cp command bit 0
constant ctrl_cp_cmd1_c : natural := 46; -- cp command bit 1
constant ctrl_cp_cmd2_c : natural := 47; -- cp command bit 2
-- control bus size --
constant ctrl_width_c : natural := 49; -- control bus size
constant ctrl_width_c : natural := 48; -- control bus size
 
-- ALU Comparator Bus ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
331,7 → 331,7
constant alu_cmd_xor_c : std_ulogic_vector(2 downto 0) := "100"; -- r <= A xor B
constant alu_cmd_or_c : std_ulogic_vector(2 downto 0) := "101"; -- r <= A or B
constant alu_cmd_and_c : std_ulogic_vector(2 downto 0) := "110"; -- r <= A and B
constant alu_cmd_bclr_c : std_ulogic_vector(2 downto 0) := "111"; -- r <= A and (not B)
constant alu_cmd_bclr_c : std_ulogic_vector(2 downto 0) := "111"; -- r <= A and (not B)
 
-- Trap ID Codes --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
/rtl/core/neorv32_top.vhd
302,7 → 302,7
generic map (
-- General --
HW_THREAD_ID => (others => '0'), -- hardware thread id
CPU_BOOT_ADDR => cpu_boot_addr_c, -- cpu boot address
CPU_BOOT_ADDR => cpu_boot_addr_c, -- cpu boot address
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
311,13 → 311,13
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
-- Extension Options --
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
-- Physical Memory Protection (PMP) --
PMP_USE => PMP_USE, -- implement PMP?
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (max 8)
PMP_GRANULARITY => PMP_GRANULARITY, -- minimal region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Bus Interface --
BUS_TIMEOUT => MEM_EXT_TIMEOUT -- cycles after which a valid bus access will timeout
BUS_TIMEOUT => MEM_EXT_TIMEOUT -- cycles after which a valid bus access will timeout
)
port map (
-- global control --
/rtl/top_templates/README.md
1,7 → 1,7
## Top Templates
 
The top entity of the NEORV32 processor is `rtl/core/neorv32_top.vhd`. This folder provides additional
top entities, that instantiate the processor's top entity and have a different top interface.
top entities/wrappers that instantiate the processor's top entity to provide a different interface.
 
### `neorv32_test_setup.vhd`
 
8,3 → 8,8
This entity is intended as "FPGA hello world" example for playing with the NEORV32. It uses only some of the
provided peripherals and provides a very simple and basic interface - only the clock, reset, UART and a subset
of the GPIO output port are propagated to the outer world.
 
### `neorv32_top_stdlogic.vhd`
 
Same entity (generics and interface ports) as the default NEORV32 Processor top entity (`rtl/core/neorv32_top.vhd`),
but with _resolved_ port signals: All ports are of type `std_logic` or `std_logic_vector`, respectively.
/rtl/top_templates/neorv32_top_stdlogic.vhd
0,0 → 1,278
-- #################################################################################################
-- # << NEORV32 - Processor Top Entity with Resolved Port Signals (std_logic/std_logic_vector) >> #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
-- # #
-- # Redistribution and use in source and binary forms, with or without modification, are #
-- # permitted provided that the following conditions are met: #
-- # #
-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
-- # conditions and the following disclaimer. #
-- # #
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
-- # conditions and the following disclaimer in the documentation and/or other materials #
-- # provided with the distribution. #
-- # #
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
-- # endorse or promote products derived from this software without specific prior written #
-- # permission. #
-- # #
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
-- # ********************************************************************************************* #
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
-- #################################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library neorv32;
use neorv32.neorv32_package.all;
 
entity neorv32_top_stdlogic is
generic (
-- General --
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
BOOTLOADER_USE : boolean := true; -- implement processor-internal bootloader?
USER_CODE : std_logic_vector(31 downto 0) := x"00000000"; -- custom user code
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Extension Options --
FAST_MUL_EN : boolean := false; -- use DSPs for M extension's multiplier
-- Physical Memory Protection (PMP) --
PMP_USE : boolean := false; -- implement PMP?
PMP_NUM_REGIONS : natural := 4; -- number of regions (max 8)
PMP_GRANULARITY : natural := 14; -- minimal region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Internal Instruction memory --
MEM_INT_IMEM_USE : boolean := true; -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes
MEM_INT_IMEM_ROM : boolean := false; -- implement processor-internal instruction memory as ROM
-- Internal Data memory --
MEM_INT_DMEM_USE : boolean := true; -- implement processor-internal data memory
MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes
-- External memory interface --
MEM_EXT_USE : boolean := false; -- implement external memory bus interface?
MEM_EXT_REG_STAGES : natural := 2; -- number of interface register stages (0,1,2)
MEM_EXT_TIMEOUT : natural := 15; -- cycles after which a valid bus access will timeout
-- Processor peripherals --
IO_GPIO_USE : boolean := true; -- implement general purpose input/output port unit (GPIO)?
IO_MTIME_USE : boolean := true; -- implement machine system timer (MTIME)?
IO_UART_USE : boolean := true; -- implement universal asynchronous receiver/transmitter (UART)?
IO_SPI_USE : boolean := true; -- implement serial peripheral interface (SPI)?
IO_TWI_USE : boolean := true; -- implement two-wire interface (TWI)?
IO_PWM_USE : boolean := true; -- implement pulse-width modulation unit (PWM)?
IO_WDT_USE : boolean := true; -- implement watch dog timer (WDT)?
IO_TRNG_USE : boolean := false; -- implement true random number generator (TRNG)?
IO_DEVNULL_USE : boolean := true; -- implement dummy device (DEVNULL)?
IO_CFU_USE : boolean := false -- implement custom functions unit (CFU)?
);
port (
-- Global control --
clk_i : in std_logic := '0'; -- global clock, rising edge
rstn_i : in std_logic := '0'; -- global reset, low-active, async
-- Wishbone bus interface (available if MEM_EXT_USE = true) --
wb_adr_o : out std_logic_vector(31 downto 0); -- address
wb_dat_i : in std_logic_vector(31 downto 0) := (others => '0'); -- read data
wb_dat_o : out std_logic_vector(31 downto 0); -- write data
wb_we_o : out std_logic; -- read/write
wb_sel_o : out std_logic_vector(03 downto 0); -- byte enable
wb_stb_o : out std_logic; -- strobe
wb_cyc_o : out std_logic; -- valid cycle
wb_ack_i : in std_logic := '0'; -- transfer acknowledge
wb_err_i : in std_logic := '0'; -- transfer error
-- Advanced memory control signals (available if MEM_EXT_USE = true) --
fence_o : out std_logic; -- indicates an executed FENCE operation
fencei_o : out std_logic; -- indicates an executed FENCEI operation
-- GPIO (available if IO_GPIO_USE = true) --
gpio_o : out std_logic_vector(31 downto 0); -- parallel output
gpio_i : in std_logic_vector(31 downto 0) := (others => '0'); -- parallel input
-- UART (available if IO_UART_USE = true) --
uart_txd_o : out std_logic; -- UART send data
uart_rxd_i : in std_logic := '0'; -- UART receive data
-- SPI (available if IO_SPI_USE = true) --
spi_sck_o : out std_logic; -- SPI serial clock
spi_sdo_o : out std_logic; -- controller data out, peripheral data in
spi_sdi_i : in std_logic := '0'; -- controller data in, peripheral data out
spi_csn_o : out std_logic_vector(07 downto 0); -- SPI CS
-- TWI (available if IO_TWI_USE = true) --
twi_sda_io : inout std_logic := 'H'; -- twi serial data line
twi_scl_io : inout std_logic := 'H'; -- twi serial clock line
-- PWM (available if IO_PWM_USE = true) --
pwm_o : out std_logic_vector(03 downto 0); -- pwm channels
-- Interrupts --
msw_irq_i : in std_logic := '0'; -- machine software interrupt
mext_irq_i : in std_logic := '0' -- machine external interrupt
);
end neorv32_top_stdlogic;
 
architecture neorv32_top_stdlogic_rtl of neorv32_top_stdlogic is
 
-- type conversion --
constant USER_CODE_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(USER_CODE);
--
signal clk_i_int : std_ulogic;
signal rstn_i_int : std_ulogic;
--
signal wb_adr_o_int : std_ulogic_vector(31 downto 0);
signal wb_dat_i_int : std_ulogic_vector(31 downto 0);
signal wb_dat_o_int : std_ulogic_vector(31 downto 0);
signal wb_we_o_int : std_ulogic;
signal wb_sel_o_int : std_ulogic_vector(03 downto 0);
signal wb_stb_o_int : std_ulogic;
signal wb_cyc_o_int : std_ulogic;
signal wb_ack_i_int : std_ulogic;
signal wb_err_i_int : std_ulogic;
--
signal fence_o_int : std_ulogic;
signal fencei_o_int : std_ulogic;
--
signal gpio_o_int : std_ulogic_vector(31 downto 0);
signal gpio_i_int : std_ulogic_vector(31 downto 0);
--
signal uart_txd_o_int : std_ulogic;
signal uart_rxd_i_int : std_ulogic;
--
signal spi_sck_o_int : std_ulogic;
signal spi_sdo_o_int : std_ulogic;
signal spi_sdi_i_int : std_ulogic;
signal spi_csn_o_int : std_ulogic_vector(07 downto 0);
--
signal pwm_o_int : std_ulogic_vector(03 downto 0);
--
signal msw_irq_i_int : std_ulogic;
signal mext_irq_i_int : std_ulogic;
 
begin
 
-- The Core Of The Problem ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
BOOTLOADER_USE => BOOTLOADER_USE, -- implement processor-internal bootloader?
USER_CODE => USER_CODE_INT, -- custom user code
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement muld/div extension?
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
-- Extension Options --
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
-- Physical Memory Protection (PMP) --
PMP_USE => PMP_USE, -- implement PMP?
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (max 16)
PMP_GRANULARITY => PMP_GRANULARITY, -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- 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
MEM_INT_IMEM_ROM => MEM_INT_IMEM_ROM, -- implement processor-internal instruction memory as ROM
-- Internal Data memory --
MEM_INT_DMEM_USE => MEM_INT_DMEM_USE, -- implement processor-internal data memory
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
-- External memory interface --
MEM_EXT_USE => MEM_EXT_USE, -- implement external memory bus interface?
MEM_EXT_REG_STAGES => MEM_EXT_REG_STAGES, -- number of interface register stages (0,1,2)
MEM_EXT_TIMEOUT => MEM_EXT_TIMEOUT, -- cycles after which a valid bus access will timeout
-- Processor peripherals --
IO_GPIO_USE => IO_GPIO_USE, -- implement general purpose input/output port unit (GPIO)?
IO_MTIME_USE => IO_MTIME_USE, -- implement machine system timer (MTIME)?
IO_UART_USE => IO_UART_USE, -- implement universal asynchronous receiver/transmitter (UART)?
IO_SPI_USE => IO_SPI_USE, -- implement serial peripheral interface (SPI)?
IO_TWI_USE => IO_TWI_USE, -- implement two-wire interface (TWI)?
IO_PWM_USE => IO_PWM_USE, -- implement pulse-width modulation unit (PWM)?
IO_WDT_USE => IO_WDT_USE, -- implement watch dog timer (WDT)?
IO_TRNG_USE => IO_TRNG_USE, -- implement true random number generator (TRNG)?
IO_DEVNULL_USE => IO_DEVNULL_USE, -- implement dummy device (DEVNULL)?
IO_CFU_USE => IO_CFU_USE -- implement custom functions unit (CFU)?
)
port map (
-- Global control --
clk_i => clk_i_int, -- global clock, rising edge
rstn_i => rstn_i_int, -- global reset, low-active, async
-- Wishbone bus interface --
wb_adr_o => wb_adr_o_int, -- address
wb_dat_i => wb_dat_i_int, -- read data
wb_dat_o => wb_dat_o_int, -- write data
wb_we_o => wb_we_o_int, -- read/write
wb_sel_o => wb_sel_o_int, -- byte enable
wb_stb_o => wb_stb_o_int, -- strobe
wb_cyc_o => wb_cyc_o_int, -- valid cycle
wb_ack_i => wb_ack_i_int, -- transfer acknowledge
wb_err_i => wb_err_i_int, -- transfer error
-- Advanced memory control signals --
fence_o => fence_o_int, -- indicates an executed FENCE operation
fencei_o => fencei_o_int, -- indicates an executed FENCEI operation
-- GPIO --
gpio_o => gpio_o_int, -- parallel output
gpio_i => gpio_i_int, -- parallel input
-- UART --
uart_txd_o => uart_txd_o_int, -- UART send data
uart_rxd_i => uart_rxd_i_int, -- UART receive data
-- SPI --
spi_sck_o => spi_sck_o_int, -- SPI serial clock
spi_sdo_o => spi_sdo_o_int, -- controller data out, peripheral data in
spi_sdi_i => spi_sdi_i_int, -- controller data in, peripheral data out
spi_csn_o => spi_csn_o_int, -- SPI CS
-- TWI --
twi_sda_io => twi_sda_io, -- twi serial data line
twi_scl_io => twi_scl_io, -- twi serial clock line
-- PWM --
pwm_o => pwm_o_int, -- pwm channels
-- Interrupts --
msw_irq_i => msw_irq_i_int, -- machine software interrupt
mext_irq_i => mext_irq_i_int -- machine external interrupt
);
 
-- type conversion --
clk_i_int <= std_ulogic(clk_i);
rstn_i_int <= std_ulogic(rstn_i);
 
wb_adr_o <= std_logic_vector(wb_adr_o_int);
wb_dat_i_int <= std_ulogic_vector(wb_dat_i);
wb_dat_o <= std_logic_vector(wb_dat_o_int);
wb_we_o <= std_logic(wb_we_o_int);
wb_sel_o <= std_logic_vector(wb_sel_o_int);
wb_stb_o <= std_logic(wb_stb_o_int);
wb_cyc_o <= std_logic(wb_cyc_o_int);
wb_ack_i_int <= std_ulogic(wb_ack_i);
wb_err_i_int <= std_ulogic(wb_err_i);
 
fence_o <= std_logic(fence_o_int);
fencei_o <= std_logic(fencei_o_int);
 
gpio_o <= std_logic_vector(gpio_o_int);
gpio_i_int <= std_ulogic_vector(gpio_i);
 
uart_txd_o <= std_logic(uart_txd_o_int);
uart_rxd_i_int <= std_ulogic(uart_rxd_i);
 
spi_sck_o <= std_logic(spi_sck_o_int);
spi_sdo_o <= std_logic(spi_sdo_o_int);
spi_sdi_i_int <= std_ulogic(spi_sdi_i);
spi_csn_o <= std_logic_vector(spi_csn_o_int);
 
pwm_o <= std_logic_vector(pwm_o_int);
 
msw_irq_i_int <= std_ulogic(msw_irq_i);
mext_irq_i_int <= std_ulogic(mext_irq_i);
 
end neorv32_top_stdlogic_rtl;
/sim/ghdl/ghdl_sim.sh
13,6 → 13,7
# The directories of the hw source files
srcdir_core=$homedir/rtl/core
srcdir_sim=$homedir/sim
srcdir_top_templates=$homedir/rtl/top_templates
 
# Show GHDL version
ghdl -v
26,6 → 27,7
echo "Simulation source files:"
ls -l $srcdir_core
ls -l $srcdir_sim
ls -l $srcdir_top_templates
 
# Just a hint
echo ""
62,6 → 64,9
ghdl -a --work=neorv32 $srcdir_core/neorv32_wdt.vhd
ghdl -a --work=neorv32 $srcdir_core/neorv32_wishbone.vhd
#
ghdl -a --work=neorv32 $srcdir_top_templates/neorv32_test_setup.vhd
ghdl -a --work=neorv32 $srcdir_top_templates/neorv32_top_stdlogic.vhd
#
ghdl -a --work=neorv32 $srcdir_sim/*.vhd
 
# Prepare simulation output files
/README.md
132,7 → 132,7
- Optional universal asynchronous receiver and transmitter (**UART**)
- Optional 8/16/24/32-bit serial peripheral interface controller (**SPI**) with 8 dedicated chip select lines
- Optional two wire serial interface controller (**TWI**), compatible to the I²C standard
- Optional general purpose parallel IO port (**GPIO**), 16xOut & 16xIn, with pin-change interrupt
- Optional general purpose parallel IO port (**GPIO**), 32xOut & 32xIn, with pin-change interrupt
- Optional 32-bit external bus interface, Wishbone b4 compliant (**WISHBONE**)
- Optional watchdog timer (**WDT**)
- Optional PWM controller with 4 channels and 8-bit duty cycle resolution (**PWM**)
172,7 → 172,7
* ALU instructions: `C.ADDI4SPN` `C.ADDI` `C.ADD` `C.ADDI16SP` `C.LI` `C.LUI` `C.SLLI` `C.SRLI` `C.SRAI` `C.ANDI` `C.SUB` `C.XOR` `C.OR` `C.AND` `C.MV` `C.NOP`
* Jump and branch instructions: `C.J` `C.JAL` `C.JR` `C.JALR` `C.BEQZ` `C.BNEZ`
* Memory instructions: `C.LW` `C.SW` `C.LWSP` `C.SWSP`
* Misc instructions: `C.EBREAK` (only with `Zicsr` extension)
* System instructions: `C.EBREAK` (only with `Zicsr` extension)
 
**Embedded CPU version** (`E` extension):
* Reduced register file (only the 16 lowest registers)
255,23 → 255,23
 
Results generated for hardware version: `1.3.6.5`
 
| Module | Description | LEs | FFs | Memory bits | DSPs |
|:----------|:------------------------------------------------|:---:|:---:|:-----------:|:----:|
| BOOT ROM | Bootloader ROM (4kB) | 4 | 1 | 32 768 | 0 |
| BUSSWITCH | Mux for CPU I & D interfaces | 62 | 8 | 0 | 0 |
| CFU | Custom functions unit | - | - | - | - |
| DEVNULL | Dummy device | 3 | 1 | 0 | 0 |
| DMEM | Processor-internal data memory (8kB) | 12 | 2 | 65 536 | 0 |
| GPIO | General purpose input/output ports | 40 | 33 | 0 | 0 |
| IMEM | Processor-internal instruction memory (16kb) | 7 | 2 | 131 072 | 0 |
| MTIME | Machine system timer | 266 | 166 | 0 | 0 |
| PWM | Pulse-width modulation controller | 72 | 69 | 0 | 0 |
| SPI | Serial peripheral interface | 198 | 125 | 0 | 0 |
| SYSINFO | System configuration information memory | 10 | 9 | 0 | 0 |
| TRNG | True random number generator | 105 | 93 | 0 | 0 |
| TWI | Two-wire interface | 75 | 44 | 0 | 0 |
| UART | Universal asynchronous receiver/transmitter | 153 | 108 | 0 | 0 |
| WDT | Watchdog timer | 59 | 45 | 0 | 0 |
| Module | Description | LEs | FFs | Memory bits | DSPs |
|:----------|:-----------------------------------------------------|:---:|:---:|:-----------:|:----:|
| BOOT ROM | Bootloader ROM (default 4kB) | 4 | 1 | 32 768 | 0 |
| BUSSWITCH | Mux for CPU I & D interfaces | 62 | 8 | 0 | 0 |
| CFU | Custom functions unit | - | - | - | - |
| DEVNULL | Dummy device | 3 | 1 | 0 | 0 |
| DMEM | Processor-internal data memory (default 8kB) | 12 | 2 | 65 536 | 0 |
| GPIO | General purpose input/output ports | 40 | 33 | 0 | 0 |
| IMEM | Processor-internal instruction memory (default 16kb) | 7 | 2 | 131 072 | 0 |
| MTIME | Machine system timer | 266 | 166 | 0 | 0 |
| PWM | Pulse-width modulation controller | 72 | 69 | 0 | 0 |
| SPI | Serial peripheral interface | 198 | 125 | 0 | 0 |
| SYSINFO | System configuration information memory | 10 | 9 | 0 | 0 |
| TRNG | True random number generator | 105 | 93 | 0 | 0 |
| TWI | Two-wire interface | 75 | 44 | 0 | 0 |
| UART | Universal asynchronous receiver/transmitter | 153 | 108 | 0 | 0 |
| WDT | Watchdog timer | 59 | 45 | 0 | 0 |
 
 
### NEORV32 Processor - Exemplary FPGA Setups
566,7 → 566,7
[`rtl/top_templates`](https://github.com/stnolting/neorv32/blob/master/rtl/top_templates) folder) as top entity.
 
This test setup instantiates the processor and implements most of the peripherals and some ISA extensions. Only the UART lines, clock, reset and some GPIO output sginals are
propagated as actual entity signals. Basically, its a FPGA "hello world" example:
propagated as actual entity signals. Basically, it is a FPGA "hello world" example:
 
```vhdl
entity neorv32_test_setup is

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.