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 48 to Rev 49
    Reverse comparison

Rev 48 → Rev 49

/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
/riscv-compliance/README.md
33,7 → 33,7
 
* Copy the `rtl`, `sim` and `sw` folders of the NEORV32 into `work/neorv32/` to keep the project's core files clean
* Clone (if not already there) the [riscv-compliance repository](https://github.com/riscv/riscv-compliance) into `work/`
* Install (copy) the custom `neorv32` test target from the ``port-neorv32/framework_v2.0/riscv-target` folder to the compliance test suite's target folder
* Install (copy) the custom `neorv32` test target from the `port-neorv32/framework_v2.0/riscv-target` folder to the compliance test suite's target folder
* Replace the original DMEM VHDL source file of the processor (in `work/neorv32/rtl/core/neorv32_dmem.vhd`) by the simulation-optimized file (`neorv32/sim/rtl_modules/neorv32_dmem.vhd` to allow faster simulation)
* Make a copy of the original IMEM VHDL source file of the processor (in `work/neorv32/rtl/core/neorv32_imem.vhd`) by the simulation-optimized file (`work/neorv32/rtl/core/neorv32_imem.ORIGINAL`); the original IMEM will be overriden by the device makefiles with a simulation-optimized one (`neorv32/sim/rtl_modules/neorv32_imem.vhd`); the original IMEM is required for certain tests that use self-modifying code
* Run the actual compliance tests
47,4 → 47,4
[`port-neorv32/framework_v1.0`](https://github.com/stnolting/neorv32/tree/master/riscv-compliance/port-neorv32/framework_v1.0/riscv-target).
 
:information_source: If the simulation of a test does not generate any signature output at all or if the signature is truncated
try increasing the simulation time by modiying the `SIM_TIME` variable when calling the test makefiles in 'run_compliance_test.sh'.
try increasing the simulation time by modiying the `SIM_TIME` variable when calling the test makefiles in `run_compliance_test.sh`.
/rtl/core/neorv32_application_image.vhd
111,7 → 111,7
00000100 => x"b0050513",
00000101 => x"00112623",
00000102 => x"668000ef",
00000103 => x"105000ef",
00000103 => x"1a1000ef",
00000104 => x"02050063",
00000105 => x"4ac000ef",
00000106 => x"00000513",
132,11 → 132,11
00000121 => x"00812423",
00000122 => x"00112623",
00000123 => x"00000413",
00000124 => x"0c1000ef",
00000124 => x"15d000ef",
00000125 => x"0ff47513",
00000126 => x"0b9000ef",
00000126 => x"155000ef",
00000127 => x"0c800513",
00000128 => x"0e5000ef",
00000128 => x"0cd000ef",
00000129 => x"00140413",
00000130 => x"fedff06f",
00000131 => x"00000000",
688,50 → 688,50
00000677 => x"00140993",
00000678 => x"000c0513",
00000679 => x"f99ff06f",
00000680 => x"fe802503",
00000681 => x"01055513",
00000682 => x"00157513",
00000683 => x"00008067",
00000684 => x"f8a02223",
00000685 => x"00008067",
00000686 => x"ff010113",
00000687 => x"c80026f3",
00000688 => x"c0002773",
00000689 => x"c80027f3",
00000690 => x"fed79ae3",
00000691 => x"00e12023",
00000692 => x"00f12223",
00000693 => x"00012503",
00000694 => x"00412583",
00000695 => x"01010113",
00000696 => x"00008067",
00000697 => x"fe010113",
00000698 => x"00112e23",
00000699 => x"00812c23",
00000700 => x"00912a23",
00000701 => x"00a12623",
00000702 => x"fc1ff0ef",
00000703 => x"00050493",
00000704 => x"fe002503",
00000705 => x"00058413",
00000706 => x"3e800593",
00000707 => x"104000ef",
00000708 => x"00c12603",
00000709 => x"00000693",
00000710 => x"00000593",
00000711 => x"05c000ef",
00000712 => x"009504b3",
00000713 => x"00a4b533",
00000714 => x"00858433",
00000715 => x"00850433",
00000716 => x"f89ff0ef",
00000717 => x"fe85eee3",
00000718 => x"00b41463",
00000719 => x"fe956ae3",
00000720 => x"01c12083",
00000721 => x"01812403",
00000722 => x"01412483",
00000723 => x"02010113",
00000680 => x"ff010113",
00000681 => x"c80026f3",
00000682 => x"c0002773",
00000683 => x"c80027f3",
00000684 => x"fed79ae3",
00000685 => x"00e12023",
00000686 => x"00f12223",
00000687 => x"00012503",
00000688 => x"00412583",
00000689 => x"01010113",
00000690 => x"00008067",
00000691 => x"fe010113",
00000692 => x"00112e23",
00000693 => x"00812c23",
00000694 => x"00912a23",
00000695 => x"00a12623",
00000696 => x"fc1ff0ef",
00000697 => x"00050493",
00000698 => x"fe002503",
00000699 => x"00058413",
00000700 => x"3e800593",
00000701 => x"11c000ef",
00000702 => x"00c12603",
00000703 => x"00000693",
00000704 => x"00000593",
00000705 => x"074000ef",
00000706 => x"009504b3",
00000707 => x"00a4b533",
00000708 => x"00858433",
00000709 => x"00850433",
00000710 => x"f89ff0ef",
00000711 => x"fe85eee3",
00000712 => x"00b41463",
00000713 => x"fe956ae3",
00000714 => x"01c12083",
00000715 => x"01812403",
00000716 => x"01412483",
00000717 => x"02010113",
00000718 => x"00008067",
00000719 => x"fe802503",
00000720 => x"01055513",
00000721 => x"00157513",
00000722 => x"00008067",
00000723 => x"f8a02223",
00000724 => x"00008067",
00000725 => x"00050613",
00000726 => x"00000513",
/rtl/core/neorv32_cfs.vhd
45,7 → 45,7
 
entity neorv32_cfs is
generic (
CFS_CONFIG : std_ulogic_vector(31 downto 0) := (others => '0') -- custom CFS configuration conduit generic
CFS_CONFIG : std_ulogic_vector(31 downto 0) := x"00000000" -- custom CFS configuration conduit generic
);
port (
-- host access --
/rtl/core/neorv32_cpu.vhd
54,8 → 54,8
entity neorv32_cpu is
generic (
-- General --
HW_THREAD_ID : std_ulogic_vector(31 downto 0):= (others => '0'); -- hardware thread id
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= (others => '0'); -- cpu boot address
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= x"00000000"; -- cpu boot address
BUS_TIMEOUT : natural := 63; -- cycles after an UNACKNOWLEDGED bus access triggers a bus fault exception
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
144,9 → 144,9
signal curr_pc : std_ulogic_vector(data_width_c-1 downto 0); -- current pc (for current executed instruction)
 
-- co-processor interface --
signal cp0_data, cp1_data, cp2_data, cp3_data : std_ulogic_vector(data_width_c-1 downto 0);
signal cp0_valid, cp1_valid, cp2_valid, cp3_valid : std_ulogic;
signal cp0_start, cp1_start, cp2_start, cp3_start : std_ulogic;
signal cp_start : std_ulogic_vector(7 downto 0); -- trigger co-processor i
signal cp_valid : std_ulogic_vector(7 downto 0); -- co-processor i done
signal cp_result : cp_data_if_t; -- co-processor result
 
-- pmp interface --
signal pmp_addr : pmp_addr_if_t;
273,7 → 273,6
-- data input --
mem_i => rdata, -- memory read data
alu_i => alu_res, -- ALU result
csr_i => csr_rdata, -- CSR read data
-- data output --
rs1_o => rs1, -- operand 1
rs2_o => rs2, -- operand 2
302,18 → 301,9
res_o => alu_res, -- ALU result
add_o => alu_add, -- address computation result
-- co-processor interface --
cp0_start_o => cp0_start, -- trigger co-processor 0
cp0_data_i => cp0_data, -- co-processor 0 result
cp0_valid_i => cp0_valid, -- co-processor 0 result valid
cp1_start_o => cp1_start, -- trigger co-processor 1
cp1_data_i => cp1_data, -- co-processor 1 result
cp1_valid_i => cp1_valid, -- co-processor 1 result valid
cp2_start_o => cp2_start, -- trigger co-processor 2
cp2_data_i => cp2_data, -- co-processor 2 result
cp2_valid_i => cp2_valid, -- co-processor 2 result valid
cp3_start_o => cp3_start, -- trigger co-processor 3
cp3_data_i => cp3_data, -- co-processor 3 result
cp3_valid_i => cp3_valid, -- co-processor 3 result valid
cp_start_o => cp_start, -- trigger co-processor i
cp_valid_i => cp_valid, -- co-processor i done
cp_result_i => cp_result, -- co-processor result
-- status --
wait_o => alu_wait -- busy due to iterative processing units
);
332,20 → 322,20
clk_i => clk_i, -- global clock, rising edge
rstn_i => rstn_i, -- global reset, low-active, async
ctrl_i => ctrl, -- main control bus
start_i => cp0_start, -- trigger operation
start_i => cp_start(0), -- trigger operation
-- data input --
rs1_i => rs1, -- rf source 1
rs2_i => rs2, -- rf source 2
-- result and status --
res_o => cp0_data, -- operation result
valid_o => cp0_valid -- data output valid
res_o => cp_result(0), -- operation result
valid_o => cp_valid(0) -- data output valid
);
end generate;
 
neorv32_cpu_cp_muldiv_inst_false:
if (CPU_EXTENSION_RISCV_M = false) generate
cp0_data <= (others => '0');
cp0_valid <= cp0_start; -- to make sure CPU does not get stalled if there is an accidental access
cp_result(0) <= (others => '0');
cp_valid(0) <= cp_start(0); -- to make sure CPU does not get stalled if there is an accidental access
end generate;
 
 
352,11 → 342,11
-- Co-Processor 1: Atomic Memory Access ('A' Extension) -----------------------------------
-- -------------------------------------------------------------------------------------------
-- "pseudo" co-processor for atomic operations
-- used to get the result of a store-conditional operation into the data path
-- required to get the result of a store-conditional operation into the data path
atomic_op_cp: process(clk_i)
begin
if rising_edge(clk_i) then
if (cp1_start = '1') then
if (cp_start(1) = '1') then
atomic_sc_res <= not ctrl(ctrl_bus_lock_c);
else
atomic_sc_res <= '0';
365,9 → 355,9
end process atomic_op_cp;
 
-- CP result --
cp1_data(data_width_c-1 downto 1) <= (others => '0');
cp1_data(0) <= atomic_sc_res when (CPU_EXTENSION_RISCV_A = true) else '0';
cp1_valid <= cp1_start; -- always assigned even if A is disabled to make sure CPU does not get stalled if there is an accidental access
cp_result(1)(data_width_c-1 downto 1) <= (others => '0');
cp_result(1)(0) <= atomic_sc_res when (CPU_EXTENSION_RISCV_A = true) else '0';
cp_valid(1) <= cp_start(1); -- always assigned even if A extension is disabled to make sure CPU does not get stalled if there is an accidental access
 
 
-- Co-Processor 2: Bit Manipulation ('B' Extension) ---------------------------------------
380,30 → 370,47
clk_i => clk_i, -- global clock, rising edge
rstn_i => rstn_i, -- global reset, low-active, async
ctrl_i => ctrl, -- main control bus
start_i => cp2_start, -- trigger operation
start_i => cp_start(2), -- trigger operation
-- data input --
cmp_i => comparator, -- comparator status
rs1_i => rs1, -- rf source 1
rs2_i => rs2, -- rf source 2
-- result and status --
res_o => cp2_data, -- operation result
valid_o => cp2_valid -- data output valid
res_o => cp_result(2), -- operation result
valid_o => cp_valid(2) -- data output valid
);
end generate;
 
neorv32_cpu_cp_bitmanip_inst_false:
if (CPU_EXTENSION_RISCV_B = false) generate
cp2_data <= (others => '0');
cp2_valid <= cp2_start; -- to make sure CPU does not get stalled if there is an accidental access
cp_result(2) <= (others => '0');
cp_valid(2) <= cp_start(2); -- to make sure CPU does not get stalled if there is an accidental access
end generate;
 
 
-- Co-Processor 3: Not implemented --------------------------------------------------------
-- Co-Processor 3: CSR (Read) Access ('Zicsr' Extension) ----------------------------------
-- -------------------------------------------------------------------------------------------
cp3_data <= (others => '0');
cp3_valid <= cp3_start; -- to make sure CPU does not get stalled if there is an accidental access
-- "pseudo" co-processor for CSR *read* access operations
-- required to get the CSR read data into the data path
cp_result(3) <= csr_rdata when (CPU_EXTENSION_RISCV_Zicsr = true) else (others => '0');
cp_valid(3) <= cp_start(3); -- always assigned even if Zicsr extension is disabled to make sure CPU does not get stalled if there is an accidental access
 
 
-- Co-Processor 4..7: Not Implemented Yet -------------------------------------------------
-- -------------------------------------------------------------------------------------------
cp_result(4) <= (others => '0');
cp_valid(4) <= '0';
--
cp_result(5) <= (others => '0');
cp_valid(5) <= '0';
--
cp_result(6) <= (others => '0');
cp_valid(6) <= '0';
--
cp_result(7) <= (others => '0');
cp_valid(7) <= '0';
 
 
-- Bus Interface Unit ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_cpu_bus_inst: neorv32_cpu_bus
/rtl/core/neorv32_cpu_alu.vhd
60,18 → 60,9
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
add_o : out std_ulogic_vector(data_width_c-1 downto 0); -- address computation result
-- co-processor interface --
cp0_start_o : out std_ulogic; -- trigger co-processor 0
cp0_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 0 result
cp0_valid_i : in std_ulogic; -- co-processor 0 result valid
cp1_start_o : out std_ulogic; -- trigger co-processor 1
cp1_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 1 result
cp1_valid_i : in std_ulogic; -- co-processor 1 result valid
cp2_start_o : out std_ulogic; -- trigger co-processor 2
cp2_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 2 result
cp2_valid_i : in std_ulogic; -- co-processor 2 result valid
cp3_start_o : out std_ulogic; -- trigger co-processor 3
cp3_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 3 result
cp3_valid_i : in std_ulogic; -- co-processor 3 result valid
cp_start_o : out std_ulogic_vector(7 downto 0); -- trigger co-processor i
cp_valid_i : in std_ulogic_vector(7 downto 0); -- co-processor i done
cp_result_i : in cp_data_if_t; -- co-processor result
-- status --
wait_o : out std_ulogic -- busy due to iterative processing units
);
288,7 → 279,7
cp_ctrl.busy <= '0';
elsif rising_edge(clk_i) then
cp_ctrl.cmd_ff <= cp_ctrl.cmd;
if ((cp0_valid_i or cp1_valid_i or cp2_valid_i or cp3_valid_i) = '1') then -- cp computation done?
if (or_all_f(cp_valid_i) = '1') then -- cp computation done?
cp_ctrl.busy <= '0';
elsif (cp_ctrl.start = '1') then
cp_ctrl.busy <= '1';
301,16 → 292,23
cp_ctrl.start <= '1' when (cp_ctrl.cmd = '1') and (cp_ctrl.cmd_ff = '0') else '0';
 
-- co-processor select --
cp0_start_o <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "00") else '0';
cp1_start_o <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "01") else '0';
cp2_start_o <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "10") else '0';
cp3_start_o <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "11") else '0';
cp_operation_trigger: process(cp_ctrl, ctrl_i)
begin
for i in 0 to 7 loop
if (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = std_ulogic_vector(to_unsigned(i, 3))) then
cp_start_o(i) <= '1';
else
cp_start_o(i) <= '0';
end if;
end loop; -- i
end process;
 
-- co-processor operation (still) running? --
cp_ctrl.halt <= (cp_ctrl.busy and (not (cp0_valid_i or cp1_valid_i or cp2_valid_i or cp3_valid_i))) or cp_ctrl.start;
cp_ctrl.halt <= (cp_ctrl.busy and (not or_all_f(cp_valid_i))) or cp_ctrl.start;
 
-- co-processor result --
cp_res <= cp0_data_i or cp1_data_i or cp2_data_i or cp3_data_i; -- only the *actually selected* co-processor may output data != 0
-- co-processor result - only the *actually selected* co-processor may output data != 0 --
cp_res <= cp_result_i(0) or cp_result_i(1) or cp_result_i(2) or cp_result_i(3) or
cp_result_i(4) or cp_result_i(5) or cp_result_i(6) or cp_result_i(7);
 
 
-- ALU Logic Core -------------------------------------------------------------------------
/rtl/core/neorv32_cpu_control.vhd
48,7 → 48,7
entity neorv32_cpu_control is
generic (
-- General --
HW_THREAD_ID : std_ulogic_vector(31 downto 0):= x"00000000"; -- hardware thread id
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= x"00000000"; -- cpu boot address
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
58,7 → 58,7
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.?
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
-- Physical memory protection (PMP) --
PMP_NUM_REGIONS : natural := 0; -- number of regions (0..64)
PMP_MIN_GRANULARITY : natural := 64*1024; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
176,11 → 176,13
is_atomic_sc : std_ulogic;
is_bitmanip_imm : std_ulogic;
is_bitmanip_reg : std_ulogic;
sys_env_cmd : std_ulogic_vector(11 downto 0);
end record;
signal decode_aux : decode_aux_t;
 
-- instruction execution engine --
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, FENCE_OP, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, SYS_ENV, CSR_ACCESS);
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP_ENTER, TRAP_EXIT, TRAP_EXECUTE, EXECUTE, ALU_WAIT,
BRANCH, FENCE_OP,LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, SYS_ENV, CSR_ACCESS);
type execute_engine_t is record
state : execute_engine_state_t;
state_nxt : execute_engine_state_t;
197,15 → 199,16
--
branch_taken : std_ulogic; -- branch condition fullfilled
pc : std_ulogic_vector(data_width_c-1 downto 0); -- actual PC, corresponding to current executed instruction
pc_mux_sel : std_ulogic_vector(1 downto 0); -- source select for PC update
pc_mux_sel : std_ulogic; -- source select for PC update
pc_we : std_ulogic; -- PC update enabled
next_pc : std_ulogic_vector(data_width_c-1 downto 0); -- next PC, corresponding to next instruction to be executed
next_pc_inc : std_ulogic_vector(data_width_c-1 downto 0); -- increment to get next PC
last_pc : std_ulogic_vector(data_width_c-1 downto 0); -- PC of last executed instruction
--
sleep : std_ulogic; -- CPU in sleep mode
sleep_nxt : std_ulogic;
if_rst : std_ulogic; -- instruction fetch was reset
if_rst_nxt : std_ulogic;
branched : std_ulogic; -- instruction fetch was reset
branched_nxt : std_ulogic;
end record;
signal execute_engine : execute_engine_t;
 
296,9 → 299,9
priv_u_mode : std_ulogic; -- CPU in u-mode
--
mepc : std_ulogic_vector(data_width_c-1 downto 0); -- mepc: machine exception pc (R/W)
mcause : std_ulogic_vector(data_width_c-1 downto 0); -- mcause: machine trap cause (R/W)
mcause : std_ulogic_vector(5 downto 0); -- mcause: machine trap cause (R/W)
mtvec : std_ulogic_vector(data_width_c-1 downto 0); -- mtvec: machine trap-handler base address (R/W), bit 1:0 == 00
mtval : std_ulogic_vector(data_width_c-1 downto 0); -- mtval: machine bad address or isntruction (R/W)
mtval : std_ulogic_vector(data_width_c-1 downto 0); -- mtval: machine bad address or instruction (R/W)
--
mhpmevent : mhpmevent_t; -- mhpmevent*: machine performance-monitoring event selector (R/W)
mhpmevent_rd : mhpmevent_rd_t; -- mhpmevent*: actual read data
387,7 → 390,7
-- state machine --
case fetch_engine.state is
 
when IFETCH_RESET => -- reset engine and prefetch buffer, get appilcation PC
when IFETCH_RESET => -- reset engine and prefetch buffer, get application PC
-- ------------------------------------------------------------
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
fetch_engine.pc_nxt <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
599,10 → 602,10
begin
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
if rising_edge(clk_i) then
if (execute_engine.state = BRANCH) then -- next_PC as immediate for jump-and-link operations (=return address)
if (execute_engine.state = BRANCH) then -- next_PC as immediate for jump-and-link operations (=return address) via ALU.MOV_B
imm_o <= execute_engine.next_pc;
else -- "normal" immediate from instruction
case opcode_v is -- save some bits here, LSBs are always 11 for rv32
else -- "normal" immediate from instruction word
case opcode_v is -- save some bits here, the two LSBs are always "11" for rv32
when opcode_store_c => -- S-immediate
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
663,24 → 666,23
execute_engine_fsm_sync_rst: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
execute_engine.state <= SYS_WAIT;
execute_engine.sleep <= '0';
execute_engine.if_rst <= '1'; -- instruction fetch is reset after system reset
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
execute_engine.state <= SYS_WAIT;
execute_engine.sleep <= '0';
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
elsif rising_edge(clk_i) then
-- PC update --
if (execute_engine.pc_we = '1') then
case execute_engine.pc_mux_sel is
when "00" => execute_engine.pc <= alu_add_i(data_width_c-1 downto 1) & '0'; -- jump/taken_branch
when "01" => execute_engine.pc <= execute_engine.next_pc(data_width_c-1 downto 1) & '0'; -- normal (linear) increment
when "10" => execute_engine.pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
when others => execute_engine.pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
end case;
if (execute_engine.pc_mux_sel = '0') then
execute_engine.pc <= execute_engine.next_pc(data_width_c-1 downto 1) & '0'; -- normal (linear) increment
else
execute_engine.pc <= alu_add_i(data_width_c-1 downto 1) & '0'; -- jump/taken_branch
end if;
end if;
--
execute_engine.state <= execute_engine.state_nxt;
execute_engine.sleep <= execute_engine.sleep_nxt;
execute_engine.if_rst <= execute_engine.if_rst_nxt;
execute_engine.state <= execute_engine.state_nxt;
execute_engine.sleep <= execute_engine.sleep_nxt;
execute_engine.branched <= execute_engine.branched_nxt;
end if;
end process execute_engine_fsm_sync_rst;
 
693,31 → 695,33
execute_engine.i_reg <= execute_engine.i_reg_nxt;
execute_engine.is_ci <= execute_engine.is_ci_nxt;
execute_engine.is_cp_op <= execute_engine.is_cp_op_nxt;
-- next PC (next linear instruction) --
-- PC & IR of "last executed" instruction --
if (execute_engine.state = EXECUTE) then
if (execute_engine.is_ci = '1') then -- compressed instruction?
execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + 2);
else
execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + 4);
end if;
end if;
-- PC & IR of last "executed" instruction --
if (execute_engine.state = EXECUTE) then
execute_engine.last_pc <= execute_engine.pc;
execute_engine.i_reg_last <= execute_engine.i_reg;
end if;
-- next PC --
case execute_engine.state is
when TRAP_ENTER => execute_engine.next_pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
when TRAP_EXIT => execute_engine.next_pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
when EXECUTE => execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + unsigned(execute_engine.next_pc_inc)); -- next linear PC
when others => NULL;
end case;
-- main control bus --
ctrl <= ctrl_nxt;
end if;
end process execute_engine_fsm_sync;
 
-- CSR access address --
csr.addr <= execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c);
-- PC increment for next linear instruction (+2 for compressed instr., +4 otherwise) --
execute_engine.next_pc_inc <= x"00000004" when ((execute_engine.is_ci = '0') or (CPU_EXTENSION_RISCV_C = false)) else x"00000002";
 
-- PC output --
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- PC for ALU ops
 
-- CSR access address --
csr.addr <= execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c);
 
 
-- CPU Control Bus Output -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, atomic_ctrl, bus_fast_ir, execute_engine, csr)
755,6 → 759,7
-- Decoding Helper Logic ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
decode_helper: process(execute_engine)
variable sys_env_cmd_mask_v : std_ulogic_vector(11 downto 0);
begin
-- defaults --
decode_aux.alu_immediate <= '0';
791,7 → 796,7
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101")) or -- RORI
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "00101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0000111")) or -- GORCI.b 7 (orc.b)
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0011000")) then -- GREVI.-8 (rev8)
decode_aux.is_bitmanip_imm <= '1';
decode_aux.is_bitmanip_imm <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B);
end if;
-- register operation --
if ((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110000") and (execute_engine.i_reg(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) = "01")) or -- ROR / ROL
804,8 → 809,11
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "100") -- XORN
)
) then
decode_aux.is_bitmanip_reg <= '1';
decode_aux.is_bitmanip_reg <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B);
end if;
-- system/environment instructions --
sys_env_cmd_mask_v := funct12_ecall_c or funct12_ebreak_c or funct12_mret_c or funct12_wfi_c; -- sum-up set bits
decode_aux.sys_env_cmd(11 downto 0) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) and sys_env_cmd_mask_v; -- set unsued bits to always-zero
end process decode_helper;
 
 
821,9 → 829,9
execute_engine.is_cp_op_nxt <= execute_engine.is_cp_op;
execute_engine.is_ci_nxt <= execute_engine.is_ci;
execute_engine.sleep_nxt <= execute_engine.sleep;
execute_engine.if_rst_nxt <= execute_engine.if_rst;
execute_engine.branched_nxt <= execute_engine.branched;
--
execute_engine.pc_mux_sel <= (others => '0'); -- select "slowest path" as default
execute_engine.pc_mux_sel <= '0';
execute_engine.pc_we <= '0';
 
-- instruction dispatch --
870,8 → 878,9
-- ------------------------------------------------------------
-- set reg_file's r0 to zero --
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (hacky! results zero since there is no valid CSR-read)
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c; -- hacky! CSR read-access CP selected without a valid CSR-read -> results zero
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_csr_rd_c; -- use CSR-READ CP
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
end if;
--
execute_engine.state_nxt <= DISPATCH;
879,22 → 888,23
 
when DISPATCH => -- Get new command from instruction issue engine
-- ------------------------------------------------------------
-- PC update --
execute_engine.pc_mux_sel <= '0'; -- linear next PC
-- IR update --
execute_engine.pc_mux_sel <= "01"; -- linear next PC
execute_engine.is_ci_nxt <= cmd_issue.data(32); -- flag to indicate a de-compressed instruction beeing executed
execute_engine.i_reg_nxt <= cmd_issue.data(31 downto 0);
execute_engine.is_ci_nxt <= cmd_issue.data(32); -- flag to indicate a de-compressed instruction
execute_engine.i_reg_nxt <= cmd_issue.data(31 downto 0);
--
if (cmd_issue.valid = '1') then -- instruction available?
-- PC update --
execute_engine.branched_nxt <= '0';
execute_engine.pc_we <= not execute_engine.branched; -- update PC with linear next_pc if there was no actual branch
-- IR update - exceptions --
trap_ctrl.instr_ma <= cmd_issue.data(33); -- misaligned instruction fetch address
trap_ctrl.instr_be <= cmd_issue.data(34); -- bus access fault during instruction fetch
illegal_compressed <= cmd_issue.data(35); -- invalid decompressed instruction
-- PC update --
execute_engine.if_rst_nxt <= '0';
execute_engine.pc_we <= not execute_engine.if_rst; -- update PC with linear next_pc if there was NO non-linear PC modification
-- any reason to go to trap state? --
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or (trap_ctrl.exc_fire = '1') or ((cmd_issue.data(33) or cmd_issue.data(34)) = '1') then
execute_engine.state_nxt <= TRAP;
execute_engine.state_nxt <= TRAP_ENTER;
else
execute_engine.state_nxt <= EXECUTE;
end if;
901,19 → 911,27
end if;
 
 
when TRAP => -- Start trap environment (also used as cpu sleep state)
when TRAP_ENTER => -- Start trap environment - get MTVEC, stay here for sleep mode
-- ------------------------------------------------------------
execute_engine.pc_mux_sel <= "10"; -- csr.mtvec (trap)
execute_engine.if_rst_nxt <= '1'; -- this will be a non-linear PC modification
if (trap_ctrl.env_start = '1') then -- trap triggered?
trap_ctrl.env_start_ack <= '1';
fetch_engine.reset <= '1';
execute_engine.pc_we <= '1';
execute_engine.sleep_nxt <= '0'; -- waky waky
execute_engine.state_nxt <= SYS_WAIT;
execute_engine.state_nxt <= TRAP_EXECUTE;
end if;
 
when TRAP_EXIT => -- Return from trap environment - get MEPC
-- ------------------------------------------------------------
trap_ctrl.env_end <= '1';
execute_engine.state_nxt <= TRAP_EXECUTE;
 
when TRAP_EXECUTE => -- Start trap environment - jump to MTVEC / return from trap environment - jump to MEPC
-- ------------------------------------------------------------
execute_engine.pc_mux_sel <= '0'; -- next PC (csr.mtvec)
fetch_engine.reset <= '1';
execute_engine.pc_we <= '1';
execute_engine.sleep_nxt <= '0'; -- disable sleep mode
execute_engine.state_nxt <= SYS_WAIT;
 
 
when EXECUTE => -- Decode and execute instruction (control has to be here for excatly 1 cyle in any case!)
-- ------------------------------------------------------------
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; -- save some bits here, LSBs are always 11 for rv32
921,9 → 939,9
 
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_c) <= decode_aux.alu_immediate; -- use IMM as ALU.OPB for immediate operations
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_c) <= decode_aux.alu_immediate; -- use IMM as ALU.OPB for immediate operations
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
 
-- ALU arithmetic operation type and ADD/SUB --
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or
995,9 → 1013,9
else -- AUIPC
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- actual ALU operation = ADD
end if;
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
 
when opcode_load_c | opcode_store_c | opcode_atomic_c => -- load/store / atomic memory access
-- ------------------------------------------------------------
1019,17 → 1037,14
 
when opcode_branch_c | opcode_jal_c | opcode_jalr_c => -- branch / jump and link (with register)
-- ------------------------------------------------------------
-- compute target address --
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- actual ALU operation = ADD
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- actual ALU operation = ADD
-- target address (ALU.ADD) operands --
if (execute_engine.i_reg(instr_opcode_lsb_c+3 downto instr_opcode_lsb_c+2) = opcode_jalr_c(3 downto 2)) then -- JALR
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA (branch target address base)
else -- JAL / branch
else -- JAL
ctrl_nxt(ctrl_alu_opa_mux_c) <= '1'; -- use PC as ALU.OPA (branch target address base)
end if;
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset)
--
execute_engine.state_nxt <= BRANCH;
execute_engine.state_nxt <= BRANCH;
 
when opcode_fence_c => -- fence operations
-- ------------------------------------------------------------
1039,6 → 1054,8
-- ------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zicsr = true) then
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid access, only relevant for CSR-instructions
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c; -- only relevant for CSR-instructions
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_csr_rd_c; -- use CSR-READ CP, only relevant for CSR-instructions
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system/environment
execute_engine.state_nxt <= SYS_ENV;
else -- CSR access
1057,23 → 1074,14
 
when SYS_ENV => -- system environment operation - execution
-- ------------------------------------------------------------
execute_engine.pc_mux_sel <= "11"; -- csr.mepc (only relevant for MRET)
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
when funct12_ecall_c => -- ECALL
trap_ctrl.env_call <= '1';
when funct12_ebreak_c => -- EBREAK
trap_ctrl.break_point <= '1';
when funct12_mret_c => -- MRET
trap_ctrl.env_end <= '1';
execute_engine.pc_we <= '1'; -- update PC from MEPC
fetch_engine.reset <= '1';
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
when funct12_wfi_c => -- WFI
execute_engine.sleep_nxt <= '1'; -- good night
when others => -- undefined
NULL;
execute_engine.state_nxt <= SYS_WAIT;
case decode_aux.sys_env_cmd is -- use a simplified input here (with permanent zeros)
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_wfi_c => execute_engine.sleep_nxt <= '1'; -- WFI
when others => NULL;-- undefined
end case;
execute_engine.state_nxt <= SYS_WAIT;
 
 
when CSR_ACCESS => -- read & write status and control register (CSR)
1088,15 → 1096,16
csr.we_nxt <= '0';
end case;
-- register file 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;
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
 
 
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
-- ------------------------------------------------------------
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back (permanent write-back)
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back (permanent write-back)
-- cp access or alu.shift? --
if (execute_engine.is_cp_op = '1') then
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
1115,15 → 1124,15
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (next_pc from immediate generator = return address)
ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_movb_c; -- MOVB
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c; -- actual ALU operation = MOVB
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= execute_engine.i_reg(instr_opcode_lsb_c+2); -- valid RF write-back? (is jump-and-link?)
-- destination address --
execute_engine.pc_mux_sel <= "00"; -- alu.add = branch/jump destination
execute_engine.pc_mux_sel <= '1'; -- alu.add = branch/jump destination
if (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') or (execute_engine.branch_taken = '1') then -- JAL/JALR or taken branch
execute_engine.pc_we <= '1'; -- update PC
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
execute_engine.state_nxt <= SYS_WAIT;
execute_engine.pc_we <= '1'; -- update PC
execute_engine.branched_nxt <= '1'; -- this is an actual branch
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
execute_engine.state_nxt <= SYS_WAIT;
else
execute_engine.state_nxt <= DISPATCH;
end if;
1134,11 → 1143,11
execute_engine.state_nxt <= SYS_WAIT;
-- FENCE.I --
if (CPU_EXTENSION_RISCV_Zifencei = true) then
execute_engine.pc_mux_sel <= "01"; -- linear next PC = start *new* instruction fetch with next instruction (only relevant for fence.i)
execute_engine.pc_mux_sel <= '0'; -- linear next PC = start *new* instruction fetch with next instruction (only relevant for fence.i)
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) then
execute_engine.pc_we <= '1';
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
fetch_engine.reset <= '1';
execute_engine.pc_we <= '1'; -- update PC
execute_engine.branched_nxt <= '1'; -- this is an actual branch
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
end if;
end if;
1172,11 → 1181,10
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
end if;
-- register file write-back --
ctrl_nxt(ctrl_rf_in_mux_lsb_c) <= '0'; -- RF input = ALU.res or MEM
if (decode_aux.is_atomic_sc = '1') then
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU.res (only relevant for atomic.SC)
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU.res (only relevant for atomic.SC)
else
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
ctrl_nxt(ctrl_rf_in_mux_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
end if;
--
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load operations)
1207,9 → 1215,9
-- ****************************************************************************************************************************
 
 
-- Illegal CSR Access Check ---------------------------------------------------------------
-- CSR Access Check -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
invalid_csr_access_check: process(execute_engine.i_reg, csr)
csr_access_check: process(execute_engine.i_reg, csr)
variable csr_wacc_v : std_ulogic; -- to check access to read-only CSRs
-- variable csr_racc_v : std_ulogic; -- to check access to write-only CSRs
variable csr_mcounteren_hpm_v : std_ulogic_vector(28 downto 0); -- max 29 HPM counters
1364,7 → 1372,7
--
when others => csr_acc_valid <= '0'; -- invalid access
end case;
end process invalid_csr_access_check;
end process csr_access_check;
 
 
-- Illegal Instruction Check --------------------------------------------------------------
1610,8 → 1618,8
end loop;
-- trap control --
if (trap_ctrl.env_start = '0') then -- no started trap handler
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- exception/IRQ detected!
((execute_engine.state = EXECUTE) or (execute_engine.state = TRAP))) then -- sample IRQs in EXECUTE or TRAP state only to continue execution even if permanent IRQ
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- trap triggered!
((execute_engine.state = EXECUTE) or (execute_engine.state = TRAP_ENTER))) then -- fire IRQs in EXECUTE or TRAP state only to continue execution even on permanent IRQ
trap_ctrl.cause <= trap_ctrl.cause_nxt; -- capture source ID for program (for mcause csr)
trap_ctrl.exc_ack <= '1'; -- clear execption
trap_ctrl.irq_ack <= trap_ctrl.irq_ack_nxt; -- clear interrupt with interrupt ACK mask
1801,9 → 1809,9
end process trap_priority;
 
 
-- Atomic Operation Controller ------------------------------------------------------------
-- Atomic Memory Access - Status Controller -----------------------------------------------
-- -------------------------------------------------------------------------------------------
atomics_controller: process(rstn_i, clk_i)
atomic_memacc_controller: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
atomic_ctrl.lock <= '0';
1823,7 → 1831,7
atomic_ctrl.env_end_ff <= '0';
end if;
end if;
end process atomics_controller;
end process atomic_memacc_controller;
 
-- ****************************************************************************************************************************
1870,27 → 1878,25
csr.mtvec <= (others => '0');
csr.mscratch <= x"19880704"; -- :)
csr.mepc <= (others => '0');
-- mcause = TRAP_CODE_RESET (hardware reset, "non-maskable interrupt")
csr.mcause <= (others => '0');
csr.mcause(csr.mcause'left) <= trap_reset_c(trap_reset_c'left);
csr.mcause(trap_reset_c'left-1 downto 0) <= trap_reset_c(trap_reset_c'left-1 downto 0);
csr.mcause <= trap_reset_c; -- mcause = TRAP_CODE_RESET (hardware reset, "non-maskable interrupt")
--
csr.mtval <= (others => '0');
csr.mip_clear <= (others => '0');
csr.mtval <= (others => '0');
csr.mip_clear <= (others => '0');
--
csr.pmpcfg <= (others => (others => '0'));
csr.pmpaddr <= (others => (others => '1'));
csr.pmpcfg <= (others => (others => '0'));
csr.pmpaddr <= (others => (others => '1'));
--
csr.mhpmevent <= (others => (others => '0'));
csr.mhpmevent <= (others => (others => '0'));
--
csr.mcounteren_cy <= '0';
csr.mcounteren_tm <= '0';
csr.mcounteren_ir <= '0';
csr.mcounteren_hpm <= (others => '0');
csr.mcounteren_cy <= '0';
csr.mcounteren_tm <= '0';
csr.mcounteren_ir <= '0';
csr.mcounteren_hpm <= (others => '0');
--
csr.mcountinhibit_cy <= '0';
csr.mcountinhibit_ir <= '0';
csr.mcountinhibit_hpm <= (others => '0');
 
elsif rising_edge(clk_i) then
-- write access? --
csr.we <= csr.we_nxt;
1929,7 → 1935,7
csr.mcounteren_cy <= csr.wdata(0); -- enable user-level access to cycle[h]
csr.mcounteren_tm <= csr.wdata(1); -- enable user-level access to time[h]
csr.mcounteren_ir <= csr.wdata(2); -- enable user-level access to instret[h]
csr.mcounteren_hpm <= csr.wdata(csr.mcounteren_hpm'left+3 downto 3); -- enable user-level access to mhpmcounterx[h]
csr.mcounteren_hpm <= csr.wdata(csr.mcounteren_hpm'left+3 downto 3); -- enable user-level access to hpmcounterx[h]
 
-- machine trap handling --
-- --------------------------------------------------------------------
1938,7 → 1944,6
when csr_mepc_c => -- R/W: mepc - machine exception program counter
csr.mepc <= csr.wdata(data_width_c-1 downto 1) & '0';
when csr_mcause_c => -- R/W: mcause - machine trap cause
csr.mcause <= (others => '0');
csr.mcause(csr.mcause'left) <= csr.wdata(31); -- 1: interrupt, 0: exception
csr.mcause(4 downto 0) <= csr.wdata(4 downto 0); -- identifier
when csr_mtval_c => -- R/W: mtval - machine bad address/instruction
1955,20 → 1960,24
-- --------------------------------------------------------------------
when csr_pmpcfg0_c | csr_pmpcfg1_c | csr_pmpcfg2_c | csr_pmpcfg3_c | csr_pmpcfg4_c | csr_pmpcfg5_c | csr_pmpcfg6_c | csr_pmpcfg7_c |
csr_pmpcfg8_c | csr_pmpcfg9_c | csr_pmpcfg10_c | csr_pmpcfg11_c | csr_pmpcfg12_c | csr_pmpcfg13_c | csr_pmpcfg14_c | csr_pmpcfg15_c =>
for i in 0 to PMP_NUM_REGIONS-1 loop
if (csr.addr(3 downto 0) = std_ulogic_vector(to_unsigned(i, 4))) then
if (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(i)(0) <= csr.wdata((i mod 4)*8+0); -- R (rights.read)
csr.pmpcfg(i)(1) <= csr.wdata((i mod 4)*8+1); -- W (rights.write)
csr.pmpcfg(i)(2) <= csr.wdata((i mod 4)*8+2); -- X (rights.execute)
csr.pmpcfg(i)(3) <= csr.wdata((i mod 4)*8+3) and csr.wdata((i mod 4)*8+4); -- A_L
csr.pmpcfg(i)(4) <= csr.wdata((i mod 4)*8+3) and csr.wdata((i mod 4)*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(i)(5) <= '0'; -- reserved
csr.pmpcfg(i)(6) <= '0'; -- reserved
csr.pmpcfg(i)(7) <= csr.wdata((i mod 4)*8+7); -- L (locked / rights also enforced in m-mode)
if (PMP_NUM_REGIONS > 0) then
for i in 0 to PMP_NUM_REGIONS-1 loop
if (csr.addr(3 downto 0) = std_ulogic_vector(to_unsigned(i, 4))) then
if (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(i)(0) <= csr.wdata((i mod 4)*8+0); -- R (rights.read)
csr.pmpcfg(i)(1) <= csr.wdata((i mod 4)*8+1); -- W (rights.write)
csr.pmpcfg(i)(2) <= csr.wdata((i mod 4)*8+2); -- X (rights.execute)
csr.pmpcfg(i)(3) <= csr.wdata((i mod 4)*8+3) and csr.wdata((i mod 4)*8+4); -- A_L
csr.pmpcfg(i)(4) <= csr.wdata((i mod 4)*8+3) and csr.wdata((i mod 4)*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(i)(5) <= '0'; -- reserved
csr.pmpcfg(i)(6) <= '0'; -- reserved
csr.pmpcfg(i)(7) <= csr.wdata((i mod 4)*8+7); -- L (locked / rights also enforced in m-mode)
end if;
end if;
end if;
end loop; -- i (PMP regions)
end loop; -- i (PMP regions)
else
NULL;
end if;
 
-- physical memory protection: R/W: pmpaddr* - PMP address registers --
-- --------------------------------------------------------------------
1980,13 → 1989,17
csr_pmpaddr40_c | csr_pmpaddr41_c | csr_pmpaddr42_c | csr_pmpaddr43_c | csr_pmpaddr44_c | csr_pmpaddr45_c | csr_pmpaddr46_c | csr_pmpaddr47_c |
csr_pmpaddr48_c | csr_pmpaddr49_c | csr_pmpaddr50_c | csr_pmpaddr51_c | csr_pmpaddr52_c | csr_pmpaddr53_c | csr_pmpaddr54_c | csr_pmpaddr55_c |
csr_pmpaddr56_c | csr_pmpaddr57_c | csr_pmpaddr58_c | csr_pmpaddr59_c | csr_pmpaddr60_c | csr_pmpaddr61_c | csr_pmpaddr62_c | csr_pmpaddr63_c =>
for i in 0 to PMP_NUM_REGIONS-1 loop
pmpaddr_v := std_ulogic_vector(unsigned(csr_pmpaddr0_c(6 downto 0)) + i); -- adapt to *non-aligned* base address (csr_pmpaddr0_c)
if (csr.addr(6 downto 0) = pmpaddr_v) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
csr.pmpaddr(i) <= csr.wdata;
csr.pmpaddr(i)(index_size_f(PMP_MIN_GRANULARITY)-4 downto 0) <= (others => '1');
end if;
end loop; -- i (PMP regions)
if (PMP_NUM_REGIONS > 0) then
for i in 0 to PMP_NUM_REGIONS-1 loop
pmpaddr_v := std_ulogic_vector(unsigned(csr_pmpaddr0_c(6 downto 0)) + i); -- adapt to *non-aligned* base address (csr_pmpaddr0_c)
if (csr.addr(6 downto 0) = pmpaddr_v) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
csr.pmpaddr(i) <= csr.wdata;
csr.pmpaddr(i)(index_size_f(PMP_MIN_GRANULARITY)-4 downto 0) <= (others => '1');
end if;
end loop; -- i (PMP regions)
else
NULL;
end if;
 
-- machine counter setup --
-- --------------------------------------------------------------------
2002,12 → 2015,16
csr_mhpmevent15_c | csr_mhpmevent16_c | csr_mhpmevent17_c | csr_mhpmevent18_c | csr_mhpmevent19_c | csr_mhpmevent20_c |
csr_mhpmevent21_c | csr_mhpmevent22_c | csr_mhpmevent23_c | csr_mhpmevent24_c | csr_mhpmevent25_c | csr_mhpmevent26_c |
csr_mhpmevent27_c | csr_mhpmevent28_c | csr_mhpmevent29_c | csr_mhpmevent30_c | csr_mhpmevent31_c => -- R/W: mhpmevent* - machine performance-monitoring event selector
for i in 0 to HPM_NUM_CNTS-1 loop
if (csr.addr(4 downto 0) = std_ulogic_vector(to_unsigned(i+3, 5))) then
csr.mhpmevent(i) <= csr.wdata(csr.mhpmevent(i)'left downto 0);
csr.mhpmevent(i)(1) <= '0'; -- would be used for "TIME"
end if;
end loop; -- i (CSRs)
if (HPM_NUM_CNTS > 0) then
for i in 0 to HPM_NUM_CNTS-1 loop
if (csr.addr(4 downto 0) = std_ulogic_vector(to_unsigned(i+3, 5))) then
csr.mhpmevent(i) <= csr.wdata(csr.mhpmevent(i)'left downto 0);
csr.mhpmevent(i)(1) <= '0'; -- would be used for "TIME"
end if;
end loop; -- i (CSRs)
else
NULL;
end if;
 
-- undefined --
-- --------------------------------------------------------------------
2025,12 → 2042,11
-- --------------------------------------------------------------------
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
-- trap cause ID code --
csr.mcause <= (others => '0');
csr.mcause(csr.mcause'left) <= trap_ctrl.cause(trap_ctrl.cause'left); -- 1: interrupt, 0: exception
csr.mcause(4 downto 0) <= trap_ctrl.cause(4 downto 0); -- identifier
-- trap PC --
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
else -- for EXCEPTIONS
csr.mepc <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- this is the LAST pc = last executed instruction
end if;
2274,7 → 2290,8
when csr_mepc_c => -- R/W: mepc - machine exception program counter
csr.rdata <= csr.mepc(data_width_c-1 downto 1) & '0';
when csr_mcause_c => -- R/W: mcause - machine trap cause
csr.rdata <= csr.mcause;
csr.rdata(31) <= csr.mcause(csr.mcause'left);
csr.rdata(csr.mcause'left-1 downto 0) <= csr.mcause(csr.mcause'left-1 downto 0);
when csr_mtval_c => -- R/W: mtval - machine bad address or instruction
csr.rdata <= csr.mtval;
when csr_mip_c => -- R/W: mip - machine interrupt pending
2490,13 → 2507,13
when csr_mimpid_c => -- R/-: mimpid - implementation ID
csr.rdata <= hw_version_c; -- NEORV32 hardware version
when csr_mhartid_c => -- R/-: mhartid - hardware thread ID
csr.rdata <= HW_THREAD_ID;
csr.rdata <= std_ulogic_vector(to_unsigned(HW_THREAD_ID, 32));
 
-- custom machine read-only CSRs --
when csr_mzext_c => -- R/-: mzext - available RISC-V Z* extensions
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei
csr.rdata(2) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zbb
csr.rdata(2) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- Zbb
 
-- undefined/unavailable --
when others =>
/rtl/core/neorv32_cpu_decompressor.vhd
1,9 → 1,9
-- #################################################################################################
-- # << NEORV32 - CPU Compressed Instructions (RISC-V C-extension) Decoder >> #
-- # << NEORV32 - CPU: Compressed Instructions Decoder (RISC-V "C" Extension) >> #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
-- # Copyright (c) 2021, 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: #
166,7 → 166,9
ci_instr32_o(instr_rs2_msb_c downto instr_rs2_lsb_c) <= "01" & ci_instr16_i(ci_rs2_3_msb_c downto ci_rs2_3_lsb_c); -- x8 - x15
 
when others => -- undefined
-- ----------------------------------------------------------------------------------------------------------
ci_illegal_o <= '1';
 
end case;
 
when "01" => -- C1: Control Transfer Instructions, Integer Constant-Generation Instructions
338,7 → 340,9
end if;
 
when others => -- undefined
-- ----------------------------------------------------------------------------------------------------------
ci_illegal_o <= '1';
 
end case;
 
when "10" => -- C2: Stack-Pointer-Based Loads and Stores, Control Transfer Instructions
422,10 → 426,13
end if;
 
when others => -- undefined
-- ----------------------------------------------------------------------------------------------------------
ci_illegal_o <= '1';
 
end case;
 
when others => -- not a compressed instruction
-- ----------------------------------------------------------------------------------------------------------
NULL;
 
end case;
/rtl/core/neorv32_cpu_regfile.vhd
60,7 → 60,6
-- data input --
mem_i : in std_ulogic_vector(data_width_c-1 downto 0); -- memory read data
alu_i : in std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
csr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
-- data output --
rs1_o : out std_ulogic_vector(data_width_c-1 downto 0); -- operand 1
rs2_o : out std_ulogic_vector(data_width_c-1 downto 0); -- operand 2
73,16 → 72,15
-- register file --
type reg_file_t is array (31 downto 0) of std_ulogic_vector(data_width_c-1 downto 0);
type reg_file_emb_t is array (15 downto 0) of std_ulogic_vector(data_width_c-1 downto 0);
signal reg_file : reg_file_t;
signal reg_file_emb : reg_file_emb_t;
signal rf_mux_data : std_ulogic_vector(data_width_c-1 downto 0);
signal rf_write_data : std_ulogic_vector(data_width_c-1 downto 0); -- actual write-back data
signal rd_is_r0 : std_ulogic; -- writing to r0?
signal rf_we : std_ulogic;
signal dst_addr : std_ulogic_vector(4 downto 0); -- destination address
signal opa_addr : std_ulogic_vector(4 downto 0); -- rs1/dst address
signal opb_addr : std_ulogic_vector(4 downto 0); -- rs2 address
signal rs1, rs2 : std_ulogic_vector(data_width_c-1 downto 0);
signal reg_file : reg_file_t;
signal reg_file_emb : reg_file_emb_t;
signal rf_wdata : std_ulogic_vector(data_width_c-1 downto 0); -- actual write-back data
signal rd_is_r0 : std_ulogic; -- writing to r0?
signal rf_we : std_ulogic;
signal dst_addr : std_ulogic_vector(4 downto 0); -- destination address
signal opa_addr : std_ulogic_vector(4 downto 0); -- rs1/dst address
signal opb_addr : std_ulogic_vector(4 downto 0); -- rs2 address
signal rs1, rs2 : std_ulogic_vector(data_width_c-1 downto 0);
 
-- comparator --
signal cmp_opx : std_ulogic_vector(data_width_c downto 0);
92,8 → 90,7
 
-- Data Input Mux -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
rf_mux_data <= mem_i when (ctrl_i(ctrl_rf_in_mux_lsb_c) = '0') else csr_i;
rf_write_data <= alu_i when (ctrl_i(ctrl_rf_in_mux_msb_c) = '0') else rf_mux_data;
rf_wdata <= alu_i when (ctrl_i(ctrl_rf_in_mux_c) = '0') else mem_i;
 
 
-- Register File Access -------------------------------------------------------------------
103,13 → 100,13
if rising_edge(clk_i) then -- sync read and write
if (CPU_EXTENSION_RISCV_E = false) then -- normal register file with 32 entries
if (rf_we = '1') then
reg_file(to_integer(unsigned(opa_addr(4 downto 0)))) <= rf_write_data;
reg_file(to_integer(unsigned(opa_addr(4 downto 0)))) <= rf_wdata;
end if;
rs1 <= reg_file(to_integer(unsigned(opa_addr(4 downto 0))));
rs2 <= reg_file(to_integer(unsigned(opb_addr(4 downto 0))));
else -- embedded register file with 16 entries
if (rf_we = '1') then
reg_file_emb(to_integer(unsigned(opa_addr(3 downto 0)))) <= rf_write_data;
reg_file_emb(to_integer(unsigned(opa_addr(3 downto 0)))) <= rf_wdata;
end if;
rs1 <= reg_file_emb(to_integer(unsigned(opa_addr(3 downto 0))));
rs2 <= reg_file_emb(to_integer(unsigned(opb_addr(3 downto 0))));
/rtl/core/neorv32_nco.vhd
0,0 → 1,334
-- #################################################################################################
-- # << NEORV32 - Number-Controlled Oscillator (NCO) >> #
-- # ********************************************************************************************* #
-- # Arbitrary frequency generator based on a number-controlled oscillator (NCO) core with three #
-- # independent channels. The phase accumulators and the tuning words are 20-bit wide (+1 bit for #
-- # the accumulator to detect overflows). See data sheet for more information. #
-- # #
-- # Output frequency for channel i: #
-- # f_out(i) = (f_cpu / clk_prsc(i)) * (tuning_word(i) / 2^21) * 0.5 #
-- # f_cpu := CPU/processors primary clock #
-- # clk_prsc := 3-bit clock prescaler #
-- # tuning_word := channel's 20-bit tuning word #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
-- # Copyright (c) 2021, 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_nco is
port (
-- host access --
clk_i : in std_ulogic; -- global clock line
addr_i : in std_ulogic_vector(31 downto 0); -- address
rden_i : in std_ulogic; -- read enable
wren_i : in std_ulogic; -- write enable
data_i : in std_ulogic_vector(31 downto 0); -- data in
data_o : out std_ulogic_vector(31 downto 0); -- data out
ack_o : out std_ulogic; -- transfer acknowledge
-- clock generator --
clkgen_en_o : out std_ulogic; -- enable clock generator
clkgen_i : in std_ulogic_vector(07 downto 0);
-- NCO output --
nco_o : out std_ulogic_vector(02 downto 0)
);
end neorv32_nco;
 
architecture neorv32_nco_rtl of neorv32_nco is
 
-- NCO configuration --
constant phase_accu_width_c : natural := 20; -- bits, min=1, max=as much as you like, default=20
constant num_channels_c : natural := 3; -- NCO channels, max=3
 
-- IO space: module base address --
constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(nco_size_c); -- low address boundary bit
 
-- access control --
signal acc_en : std_ulogic; -- module access enable
signal addr : std_ulogic_vector(31 downto 0); -- access address
signal wren : std_ulogic; -- word write access
signal rden : std_ulogic; -- read access
 
-- control register bits --
constant ctrl_en_c : natural := 0; -- r/w: global NCO enable
--
constant ctrl_ch0_mode_c : natural := 1; -- r/w: output mode (0=fixed 50% duty cycle; 1=pulse mode)
constant ctrl_ch0_idle_pol_c : natural := 2; -- r/w: output idle polarity (0=low, 1=high)
constant ctrl_ch0_oe_c : natural := 3; -- r/w: enable processor output pin
constant ctrl_ch0_output_c : natural := 4; -- r/-: current channel output state
constant ctrl_ch0_prsc0_c : natural := 5; -- r/w: clock prescaler select bit 0
constant ctrl_ch0_prsc1_c : natural := 6; -- r/w: clock prescaler select bit 1
constant ctrl_ch0_prsc2_c : natural := 7; -- r/w: clock prescaler select bit 2
constant ctrl_ch0_pulse0_c : natural := 8; -- r/w: pulse length select bit 0
constant ctrl_ch0_pulse1_c : natural := 9; -- r/w: pulse length select bit 1
constant ctrl_ch0_pulse2_c : natural := 10; -- r/w: pulse length select bit 2
--
constant ctrl_ch1_mode_c : natural := 21; -- r/w: output mode (0=fixed 50% duty cycle; 1=pulse mode)
constant ctrl_ch1_idle_pol_c : natural := 22; -- r/w: output idle polarity (0=low, 1=high)
constant ctrl_ch1_oe_c : natural := 23; -- r/w: enable processor output pin
constant ctrl_ch1_output_c : natural := 24; -- r/-: current channel output state
constant ctrl_ch1_prsc0_c : natural := 25; -- r/w: clock prescaler select bit 0
constant ctrl_ch1_prsc1_c : natural := 26; -- r/w: clock prescaler select bit 1
constant ctrl_ch1_prsc2_c : natural := 27; -- r/w: clock prescaler select bit 2
constant ctrl_ch1_pulse0_c : natural := 28; -- r/w: pulse length select bit 0
constant ctrl_ch1_pulse1_c : natural := 29; -- r/w: pulse length select bit 1
constant ctrl_ch1_pulse2_c : natural := 20; -- r/w: pulse length select bit 2
--
constant ctrl_ch2_mode_c : natural := 21; -- r/w: output mode (0=fixed 50% duty cycle; 1=pulse mode)
constant ctrl_ch2_idle_pol_c : natural := 22; -- r/w: output idle polarity (0=low, 1=high)
constant ctrl_ch2_oe_c : natural := 23; -- r/w: enable processor output pin
constant ctrl_ch2_output_c : natural := 24; -- r/-: current channel output state
constant ctrl_ch2_prsc0_c : natural := 25; -- r/w: clock prescaler select bit 0
constant ctrl_ch2_prsc1_c : natural := 26; -- r/w: clock prescaler select bit 1
constant ctrl_ch2_prsc2_c : natural := 27; -- r/w: clock prescaler select bit 2
constant ctrl_ch2_pulse0_c : natural := 28; -- r/w: pulse length select bit 0
constant ctrl_ch2_pulse1_c : natural := 29; -- r/w: pulse length select bit 1
constant ctrl_ch2_pulse2_c : natural := 30; -- r/w: pulse length select bit 2
--
constant ctrl_ch_offset_c : natural := 10; -- number of bits for each channel
constant ctrl_size_c : natural := num_channels_c*ctrl_ch_offset_c+1; -- number of bits in primary control register
 
-- accessible regs --
type tuning_word_t is array (0 to num_channels_c-1) of std_ulogic_vector(phase_accu_width_c-1 downto 0);
signal tuning_word : tuning_word_t; -- r/w: tuning word channel i
signal ctrl : std_ulogic_vector(ctrl_size_c-1 downto 0); -- r/w: control register
 
-- nco core --
type nco_sel_t is array (0 to num_channels_c-1) of std_ulogic_vector(2 downto 0);
type pulse_cnt_t is array (0 to num_channels_c-1) of std_ulogic_vector(7 downto 0);
type accu_t is array (0 to num_channels_c-1) of std_ulogic_vector(phase_accu_width_c downto 0); -- +1 bit for overflow detection
--
type nco_core_t is record
-- control --
enable : std_ulogic; -- global enable
prsc_sel : nco_sel_t;
pulse_sel : nco_sel_t;
idle_pol : std_ulogic_vector(num_channels_c-1 downto 0);
output_en : std_ulogic_vector(num_channels_c-1 downto 0);
mode : std_ulogic_vector(num_channels_c-1 downto 0);
-- NCO core --
phase_accu : accu_t;
clk_tick : std_ulogic_vector(num_channels_c-1 downto 0);
ovfl_buf : std_ulogic_vector(num_channels_c-1 downto 0);
overflow : std_ulogic_vector(num_channels_c-1 downto 0); -- phase accu overflow
trigger : std_ulogic_vector(num_channels_c-1 downto 0); -- current NCO output level
-- pulse generator --
pulse_tick : std_ulogic_vector(num_channels_c-1 downto 0);
pulse_trig : std_ulogic_vector(num_channels_c-1 downto 0);
pulse_trig_ff : std_ulogic_vector(num_channels_c-1 downto 0);
pulse_cnt : pulse_cnt_t;
pulse_out : std_ulogic_vector(num_channels_c-1 downto 0);
-- status --
output_nxt : std_ulogic_vector(num_channels_c-1 downto 0);
output : std_ulogic_vector(num_channels_c-1 downto 0); -- current NCO output level
end record;
signal nco : nco_core_t;
 
begin
 
-- Access Control -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = nco_base_c(hi_abb_c downto lo_abb_c)) else '0';
addr <= nco_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
wren <= acc_en and wren_i;
rden <= acc_en and rden_i;
 
 
-- Read/Write Access ----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
rw_access: process(clk_i)
begin
if rising_edge(clk_i) then
ack_o <= wren or rden;
 
-- write access --
if (wren = '1') then
-- control register --
if (addr = nco_ctrl_addr_c) then
ctrl <= data_i(ctrl'left downto 0);
end if;
-- tuning words --
if (addr = nco_ch0_addr_c) then -- channel 0
tuning_word(0) <= data_i(phase_accu_width_c-1 downto 0);
end if;
if (addr = nco_ch1_addr_c) then -- channel 1
tuning_word(1) <= data_i(phase_accu_width_c-1 downto 0);
end if;
if (addr = nco_ch2_addr_c) then -- channel 2
tuning_word(2) <= data_i(phase_accu_width_c-1 downto 0);
end if;
end if;
 
-- read access --
data_o <= (others => '0');
if (rden = '1') then
case addr is
when nco_ctrl_addr_c =>
data_o(ctrl'left downto 0) <= ctrl;
for i in 0 to num_channels_c-1 loop
data_o(ctrl_ch0_output_c + i*ctrl_ch_offset_c) <= nco.output(i);
end loop;
when nco_ch0_addr_c =>
data_o(phase_accu_width_c-1 downto 0) <= tuning_word(0);
when nco_ch1_addr_c =>
data_o(phase_accu_width_c-1 downto 0) <= tuning_word(1);
when nco_ch2_addr_c =>
data_o(phase_accu_width_c-1 downto 0) <= tuning_word(2);
when others =>
data_o <= (others => '0');
end case;
end if;
end if;
end process rw_access;
 
-- enable external clock generator --
clkgen_en_o <= nco.enable;
 
-- control register --
primary_control_register:
for i in 0 to num_channels_c-1 generate
nco.mode(i) <= ctrl(ctrl_ch0_mode_c + i*ctrl_ch_offset_c);
nco.idle_pol(i) <= ctrl(ctrl_ch0_idle_pol_c + i*ctrl_ch_offset_c);
nco.output_en(i) <= ctrl(ctrl_ch0_oe_c + i*ctrl_ch_offset_c);
nco.prsc_sel(i) <= ctrl(ctrl_ch0_prsc2_c + i*ctrl_ch_offset_c downto ctrl_ch0_prsc0_c + i*ctrl_ch_offset_c);
nco.pulse_sel(i) <= ctrl(ctrl_ch0_pulse2_c + i*ctrl_ch_offset_c downto ctrl_ch0_pulse0_c + i*ctrl_ch_offset_c);
end generate; -- i
nco.enable <= ctrl(ctrl_en_c);
 
-- NCO Core -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
nco_core: process(clk_i)
begin
if rising_edge(clk_i) then
for i in 0 to num_channels_c-1 loop
-- clock select --
nco.clk_tick(i) <= clkgen_i(to_integer(unsigned(nco.prsc_sel(i))));
 
-- phase accu & output trigger --
if (nco.enable = '0') then -- disabled
nco.phase_accu(i) <= (others => '0');
nco.trigger(i) <= '0';
else
if (nco.clk_tick(i) = '1') then -- wait for clock enable tick
nco.phase_accu(i) <= std_ulogic_vector(unsigned(nco.phase_accu(i)) + unsigned('0' & tuning_word(i)));
end if;
if (nco.overflow(i) = '1') then -- toggle NCO output trigger on overflow
nco.trigger(i) <= not nco.trigger(i);
end if;
end if;
 
-- buffer for overflow check (edge detector) --
nco.ovfl_buf(i) <= nco.phase_accu(i)(phase_accu_width_c);
end loop; -- i
end if;
end process nco_core;
 
-- phase accu overflow detector --
overflow_detect:
for i in 0 to num_channels_c-1 generate
nco.overflow(i) <= nco.phase_accu(i)(phase_accu_width_c) and (not nco.ovfl_buf(i));
end generate; -- i
 
 
-- Pulse Generator ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
pulse_generator: process(clk_i)
begin
if rising_edge(clk_i) then
for i in 0 to num_channels_c-1 loop
-- phase accu trigger -> edge detector --
nco.pulse_trig_ff(i) <= nco.trigger(i);
 
-- pulse counter --
if (nco.enable = '0') or (nco.mode(i) = '0') or (nco.pulse_trig(i) = '1') then -- disabled or reset
nco.pulse_cnt(i) <= (others => '0');
elsif (nco.clk_tick(i) = '1') then
nco.pulse_cnt(i) <= std_ulogic_vector(unsigned(nco.pulse_cnt(i)) + 1);
end if;
 
-- pulse generator --
if (nco.enable = '0') or (nco.mode(i) = '0') then
nco.pulse_out(i) <= '0';
elsif (nco.pulse_trig(i) = '1') then -- set on phase accu's trigger (rising edge)
nco.pulse_out(i) <= '1';
elsif (nco.pulse_tick(i) = '1') then -- clear after "timeout" from pulse length counter
nco.pulse_out(i) <= '0';
end if;
end loop; -- i
end if;
end process pulse_generator;
 
-- pulse length select --
pulse_length_sel:
for i in 0 to num_channels_c-1 generate
nco.pulse_tick(i) <= nco.pulse_cnt(i)(to_integer(unsigned(nco.pulse_sel(i))));
end generate; -- i
 
-- pulse-set edge detector --
trigger_detect:
for i in 0 to num_channels_c-1 generate
nco.pulse_trig(i) <= nco.trigger(i) and (not nco.pulse_trig_ff(i));
end generate; -- i
 
 
-- Output Configuration -------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
output_generator: process(clk_i)
begin
if rising_edge(clk_i) then
for i in 0 to num_channels_c-1 loop
-- polarity configuration --
if (nco.enable = '1') then -- channel enabled?
nco.output(i) <= nco.output_nxt(i) xor nco.idle_pol(i); -- apply polarity configuration
else
nco.output(i) <= nco.idle_pol(i); -- use *inactive* polarity configuration when disabled
end if;
 
-- output to physical pin --
nco_o(i) <= nco.output(i) and nco.output_en(i);
end loop; -- i
end if;
end process output_generator;
 
-- NCO output mode select --
nco_output_mode:
for i in 0 to num_channels_c-1 generate
nco.output_nxt(i) <= nco.trigger(i) when (nco.mode(i) = '0') else nco.pulse_out(i);
end generate; -- i
 
 
end neorv32_nco_rtl;
/rtl/core/neorv32_package.vhd
60,7 → 60,7
-- Architecture Constants (do not modify!) ------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant data_width_c : natural := 32; -- native data path width - do not change!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01050100"; -- no touchy!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01050104"; -- no touchy!
constant pmp_max_r_c : natural := 8; -- max PMP regions - FIXED!
constant archid_c : natural := 19; -- official NEORV32 architecture ID - hands off!
constant rf_r0_is_reg_c : boolean := true; -- reg_file.r0 is a *physical register* that has to be initialized to zero by the CPU HW
85,6 → 85,7
-- -------------------------------------------------------------------------------------------
type pmp_ctrl_if_t is array (0 to 63) of std_ulogic_vector(07 downto 0);
type pmp_addr_if_t is array (0 to 63) of std_ulogic_vector(33 downto 0);
type cp_data_if_t is array (0 to 7) of std_ulogic_vector(data_width_c-1 downto 0);
 
-- Processor-Internal Address Space Layout ------------------------------------------------
-- -------------------------------------------------------------------------------------------
187,9 → 188,17
constant pwm_ctrl_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFB8";
constant pwm_duty_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFBC";
 
-- Numerically-Controlled Oscillator (NCO) --
constant nco_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFC0"; -- base address
constant nco_size_c : natural := 4*4; -- module's address space in bytes
constant nco_ctrl_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFC0";
constant nco_ch0_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFC4";
constant nco_ch1_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFC8";
constant nco_ch2_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFCC";
 
-- reserved --
--constant reserved_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFC0"; -- base address
--constant reserved_size_c : natural := 8*4; -- module's address space in bytes
--constant reserved_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFD0"; -- base address
--constant reserved_size_c : natural := 4*4; -- module's address space in bytes
 
-- System Information Memory (SYSINFO) --
constant sysinfo_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"FFFFFFE0"; -- base address
198,53 → 207,53
-- Main Control Bus -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- register file --
constant ctrl_rf_in_mux_lsb_c : natural := 0; -- input source select lsb (10=MEM, 11=CSR)
constant ctrl_rf_in_mux_msb_c : natural := 1; -- input source select msb (0-=ALU)
constant ctrl_rf_rs1_adr0_c : natural := 2; -- source register 1 address bit 0
constant ctrl_rf_rs1_adr1_c : natural := 3; -- source register 1 address bit 1
constant ctrl_rf_rs1_adr2_c : natural := 4; -- source register 1 address bit 2
constant ctrl_rf_rs1_adr3_c : natural := 5; -- source register 1 address bit 3
constant ctrl_rf_rs1_adr4_c : natural := 6; -- source register 1 address bit 4
constant ctrl_rf_rs2_adr0_c : natural := 7; -- source register 2 address bit 0
constant ctrl_rf_rs2_adr1_c : natural := 8; -- source register 2 address bit 1
constant ctrl_rf_rs2_adr2_c : natural := 9; -- source register 2 address bit 2
constant ctrl_rf_rs2_adr3_c : natural := 10; -- source register 2 address bit 3
constant ctrl_rf_rs2_adr4_c : natural := 11; -- source register 2 address bit 4
constant ctrl_rf_rd_adr0_c : natural := 12; -- destiantion register address bit 0
constant ctrl_rf_rd_adr1_c : natural := 13; -- destiantion register address bit 1
constant ctrl_rf_rd_adr2_c : natural := 14; -- destiantion register address bit 2
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_r0_we_c : natural := 18; -- force write access and force rd=r0
constant ctrl_rf_in_mux_c : natural := 0; -- input source select lsb (0=MEM, 1=ALU)
constant ctrl_rf_rs1_adr0_c : natural := 1; -- source register 1 address bit 0
constant ctrl_rf_rs1_adr1_c : natural := 2; -- source register 1 address bit 1
constant ctrl_rf_rs1_adr2_c : natural := 3; -- source register 1 address bit 2
constant ctrl_rf_rs1_adr3_c : natural := 4; -- source register 1 address bit 3
constant ctrl_rf_rs1_adr4_c : natural := 5; -- source register 1 address bit 4
constant ctrl_rf_rs2_adr0_c : natural := 6; -- source register 2 address bit 0
constant ctrl_rf_rs2_adr1_c : natural := 7; -- source register 2 address bit 1
constant ctrl_rf_rs2_adr2_c : natural := 8; -- source register 2 address bit 2
constant ctrl_rf_rs2_adr3_c : natural := 9; -- source register 2 address bit 3
constant ctrl_rf_rs2_adr4_c : natural := 10; -- source register 2 address bit 4
constant ctrl_rf_rd_adr0_c : natural := 11; -- destiantion register address bit 0
constant ctrl_rf_rd_adr1_c : natural := 12; -- destiantion register address bit 1
constant ctrl_rf_rd_adr2_c : natural := 13; -- destiantion register address bit 2
constant ctrl_rf_rd_adr3_c : natural := 14; -- destiantion register address bit 3
constant ctrl_rf_rd_adr4_c : natural := 15; -- destiantion register address bit 4
constant ctrl_rf_wb_en_c : natural := 16; -- write back enable
constant ctrl_rf_r0_we_c : natural := 17; -- force write access and force rd=r0
-- alu --
constant ctrl_alu_arith_c : natural := 19; -- ALU arithmetic command
constant ctrl_alu_logic0_c : natural := 20; -- ALU logic command bit 0
constant ctrl_alu_logic1_c : natural := 21; -- ALU logic command bit 1
constant ctrl_alu_func0_c : natural := 22; -- ALU function select command bit 0
constant ctrl_alu_func1_c : natural := 23; -- ALU function select command bit 1
constant ctrl_alu_addsub_c : natural := 24; -- 0=ADD, 1=SUB
constant ctrl_alu_opa_mux_c : natural := 25; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 26; -- operand B select (0=rs2, 1=IMM)
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_arith_c : natural := 18; -- ALU arithmetic command
constant ctrl_alu_logic0_c : natural := 19; -- ALU logic command bit 0
constant ctrl_alu_logic1_c : natural := 20; -- ALU logic command bit 1
constant ctrl_alu_func0_c : natural := 21; -- ALU function select command bit 0
constant ctrl_alu_func1_c : natural := 22; -- ALU function select command bit 1
constant ctrl_alu_addsub_c : natural := 23; -- 0=ADD, 1=SUB
constant ctrl_alu_opa_mux_c : natural := 24; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 25; -- operand B select (0=rs2, 1=IMM)
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_mo_we_c : natural := 35; -- memory address and data output register write enable
constant ctrl_bus_mi_we_c : natural := 36; -- memory data input 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 exceptions
constant ctrl_bus_derr_ack_c : natural := 39; -- acknowledge data access bus exceptions
constant ctrl_bus_fence_c : natural := 40; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 41; -- executed fencei operation
constant ctrl_bus_lock_c : natural := 42; -- locked/exclusive bus access
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_mo_we_c : natural := 34; -- memory address and data output register write enable
constant ctrl_bus_mi_we_c : natural := 35; -- memory data input register write enable
constant ctrl_bus_unsigned_c : natural := 36; -- is unsigned load
constant ctrl_bus_ierr_ack_c : natural := 37; -- acknowledge instruction fetch bus exceptions
constant ctrl_bus_derr_ack_c : natural := 38; -- acknowledge data access bus exceptions
constant ctrl_bus_fence_c : natural := 39; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 40; -- executed fencei operation
constant ctrl_bus_lock_c : natural := 41; -- locked/exclusive bus access
-- co-processors --
constant ctrl_cp_id_lsb_c : natural := 43; -- cp select ID lsb
constant ctrl_cp_id_lsb_c : natural := 42; -- cp select ID lsb
constant ctrl_cp_id_hsb_c : natural := 43; -- cp select ID hsb
constant ctrl_cp_id_msb_c : natural := 44; -- cp select ID msb
-- current privilege level --
constant ctrl_priv_lvl_lsb_c : natural := 45; -- privilege level lsb
655,10 → 664,14
 
-- Co-Processor IDs -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant cp_sel_muldiv_c : std_ulogic_vector(1 downto 0) := "00"; -- multiplication/division operations ('M' extension)
constant cp_sel_atomic_c : std_ulogic_vector(1 downto 0) := "01"; -- atomic operations; success/failure evaluation ('A' extension)
constant cp_sel_bitmanip_c : std_ulogic_vector(1 downto 0) := "10"; -- bit manipulation ('B' extension)
--constant cp_sel_float32_c : std_ulogic_vector(1 downto 0) := "11"; -- reserved -- single-precision floating point operations ('F' extension)
constant cp_sel_muldiv_c : std_ulogic_vector(2 downto 0) := "000"; -- multiplication/division operations ('M' extension)
constant cp_sel_atomic_c : std_ulogic_vector(2 downto 0) := "001"; -- atomic operations; success/failure evaluation ('A' extension)
constant cp_sel_bitmanip_c : std_ulogic_vector(2 downto 0) := "010"; -- bit manipulation ('B' extension)
constant cp_sel_csr_rd_c : std_ulogic_vector(2 downto 0) := "011"; -- CSR read access ('Zicsr' extension)
--constant cp_reserved_c : std_ulogic_vector(2 downto 0) := "100"; -- reserved
--constant cp_reserved_c : std_ulogic_vector(2 downto 0) := "101"; -- reserved
--constant cp_reserved_c : std_ulogic_vector(2 downto 0) := "110"; -- reserved
--constant cp_reserved_c : std_ulogic_vector(2 downto 0) := "111"; -- reserved
 
-- ALU Function Codes ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
794,7 → 807,7
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
BOOTLOADER_EN : boolean := true; -- implement processor-internal bootloader?
USER_CODE : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom user code
HW_THREAD_ID : std_ulogic_vector(31 downto 0) := (others => '0'); -- hardware thread id (hartid)
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
836,13 → 849,14
IO_WDT_EN : boolean := true; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
IO_CFS_EN : boolean := false; -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG : std_ulogic_vector(31 downto 0) := (others => '0') -- custom CFS configuration generic
IO_CFS_CONFIG : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
IO_NCO_EN : boolean := true -- implement numerically-controlled oscillator (NCO)?
);
port (
-- Global control --
clk_i : in std_ulogic := '0'; -- global clock, rising edge
rstn_i : in std_ulogic := '0'; -- global reset, low-active, async
-- Wishbone bus interface --
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
wb_tag_o : out std_ulogic_vector(02 downto 0); -- tag
wb_adr_o : out std_ulogic_vector(31 downto 0); -- address
wb_dat_i : in std_ulogic_vector(31 downto 0) := (others => '0'); -- read data
857,25 → 871,27
-- Advanced memory control signals (available if MEM_EXT_EN = true) --
fence_o : out std_ulogic; -- indicates an executed FENCE operation
fencei_o : out std_ulogic; -- indicates an executed FENCEI operation
-- GPIO --
-- GPIO (available if IO_GPIO_EN = true) --
gpio_o : out std_ulogic_vector(31 downto 0); -- parallel output
gpio_i : in std_ulogic_vector(31 downto 0) := (others => '0'); -- parallel input
-- UART --
-- UART (available if IO_UART_EN = true) --
uart_txd_o : out std_ulogic; -- UART send data
uart_rxd_i : in std_ulogic := '0'; -- UART receive data
-- SPI --
-- SPI (available if IO_SPI_EN = true) --
spi_sck_o : out std_ulogic; -- SPI serial clock
spi_sdo_o : out std_ulogic; -- controller data out, peripheral data in
spi_sdi_i : in std_ulogic := '0'; -- controller data in, peripheral data out
spi_csn_o : out std_ulogic_vector(07 downto 0); -- SPI CS
-- TWI --
-- TWI (available if IO_TWI_EN = true) --
twi_sda_io : inout std_logic; -- twi serial data line
twi_scl_io : inout std_logic; -- twi serial clock line
-- PWM --
-- PWM (available if IO_PWM_EN = true) --
pwm_o : out std_ulogic_vector(03 downto 0); -- pwm channels
-- Custom Functions Subsystem IO --
cfs_in_i : in std_ulogic_vector(31 downto 0) := (others => '0'); -- custom CSF inputs
cfs_out_o : out std_ulogic_vector(31 downto 0); -- custom CSF outputs
-- NCO output (available if IO_NCO_EN = true) --
nco_o : out std_ulogic_vector(02 downto 0); -- numerically-controlled oscillator channels
-- system time input from external MTIME (available if IO_MTIME_EN = false) --
mtime_i : in std_ulogic_vector(63 downto 0) := (others => '0'); -- current system time
-- Interrupts --
891,8 → 907,8
component neorv32_cpu
generic (
-- General --
HW_THREAD_ID : std_ulogic_vector(31 downto 0) := (others => '0'); -- hardware thread id
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0) := (others => '0'); -- cpu boot address
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0) := x"00000000"; -- cpu boot address
BUS_TIMEOUT : natural := 63; -- cycles after an UNACKNOWLEDGED bus access triggers a bus fault exception
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
902,7 → 918,7
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.?
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
-- Extension Options --
FAST_MUL_EN : boolean := false; -- use DSPs for M extension's multiplier
FAST_SHIFT_EN : boolean := false; -- use barrel shifter for shift operations
960,7 → 976,7
component neorv32_cpu_control
generic (
-- General --
HW_THREAD_ID : std_ulogic_vector(31 downto 0):= x"00000000"; -- hardware thread id
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= x"00000000"; -- cpu boot address
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
970,7 → 986,7
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.?
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
-- Physical memory protection (PMP) --
PMP_NUM_REGIONS : natural := 0; -- number of regions (0..64)
PMP_MIN_GRANULARITY : natural := 64*1024; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
1032,7 → 1048,6
-- data input --
mem_i : in std_ulogic_vector(data_width_c-1 downto 0); -- memory read data
alu_i : in std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
csr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
-- data output --
rs1_o : out std_ulogic_vector(data_width_c-1 downto 0); -- operand 1
rs2_o : out std_ulogic_vector(data_width_c-1 downto 0); -- operand 2
1061,18 → 1076,9
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
add_o : out std_ulogic_vector(data_width_c-1 downto 0); -- address computation result
-- co-processor interface --
cp0_start_o : out std_ulogic; -- trigger co-processor 0
cp0_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 0 result
cp0_valid_i : in std_ulogic; -- co-processor 0 result valid
cp1_start_o : out std_ulogic; -- trigger co-processor 1
cp1_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 1 result
cp1_valid_i : in std_ulogic; -- co-processor 1 result valid
cp2_start_o : out std_ulogic; -- trigger co-processor 2
cp2_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 2 result
cp2_valid_i : in std_ulogic; -- co-processor 2 result valid
cp3_start_o : out std_ulogic; -- trigger co-processor 3
cp3_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 3 result
cp3_valid_i : in std_ulogic; -- co-processor 3 result valid
cp_start_o : out std_ulogic_vector(7 downto 0); -- trigger co-processor i
cp_valid_i : in std_ulogic_vector(7 downto 0); -- co-processor i done
cp_result_i : in cp_data_if_t; -- co-processor result
-- status --
wait_o : out std_ulogic -- busy due to iterative processing units
);
1553,7 → 1559,7
-- -------------------------------------------------------------------------------------------
component neorv32_cfs
generic (
CFS_CONFIG : std_ulogic_vector(31 downto 0) := (others => '0') -- custom CFS configuration generic
CFS_CONFIG : std_ulogic_vector(31 downto 0) := x"00000000" -- custom CFS configuration generic
);
port (
-- host access --
1580,6 → 1586,26
);
end component;
 
-- Component: Numerically-Controlled Oscillator (NCO) -------------------------------------
-- -------------------------------------------------------------------------------------------
component neorv32_nco
port (
-- host access --
clk_i : in std_ulogic; -- global clock line
addr_i : in std_ulogic_vector(31 downto 0); -- address
rden_i : in std_ulogic; -- read enable
wren_i : in std_ulogic; -- write enable
data_i : in std_ulogic_vector(31 downto 0); -- data in
data_o : out std_ulogic_vector(31 downto 0); -- data out
ack_o : out std_ulogic; -- transfer acknowledge
-- clock generator --
clkgen_en_o : out std_ulogic; -- enable clock generator
clkgen_i : in std_ulogic_vector(07 downto 0);
-- NCO output --
nco_o : out std_ulogic_vector(02 downto 0)
);
end component;
 
-- Component: System Configuration Information Memory (SYSINFO) ---------------------------
-- -------------------------------------------------------------------------------------------
component neorv32_sysinfo
1611,7 → 1637,8
IO_PWM_EN : boolean := true; -- implement pulse-width modulation unit (PWM)?
IO_WDT_EN : boolean := true; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := true; -- implement true random number generator (TRNG)?
IO_CFS_EN : boolean := true -- implement custom functions subsystem (CFS)?
IO_CFS_EN : boolean := true; -- implement custom functions subsystem (CFS)?
IO_NCO_EN : boolean := true -- implement numerically-controlled oscillator (NCO)?
);
port (
-- host access --
/rtl/core/neorv32_sysinfo.vhd
71,7 → 71,8
IO_PWM_EN : boolean := true; -- implement pulse-width modulation unit (PWM)?
IO_WDT_EN : boolean := true; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := true; -- implement true random number generator (TRNG)?
IO_CFS_EN : boolean := true -- implement custom functions subsystem (CFS)?
IO_CFS_EN : boolean := true; -- implement custom functions subsystem (CFS)?
IO_NCO_EN : boolean := true -- implement numerically-controlled oscillator (NCO)?
);
port (
-- host access --
139,8 → 140,9
sysinfo_mem(2)(22) <= bool_to_ulogic_f(IO_WDT_EN); -- watch dog timer (WDT) implemented?
sysinfo_mem(2)(23) <= bool_to_ulogic_f(IO_CFS_EN); -- custom functions subsystem (CFS) implemented?
sysinfo_mem(2)(24) <= bool_to_ulogic_f(IO_TRNG_EN); -- true random number generator (TRNG) implemented?
sysinfo_mem(2)(25) <= bool_to_ulogic_f(IO_NCO_EN); -- numerically-controlled oscillator (NCO) implemented?
--
sysinfo_mem(2)(31 downto 25) <= (others => '0'); -- reserved
sysinfo_mem(2)(31 downto 26) <= (others => '0'); -- reserved
 
-- SYSINFO(3): Cache configuration --
sysinfo_mem(3)(03 downto 00) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_BLOCK_SIZE), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(block_size_in_bytes)
/rtl/core/neorv32_top.vhd
51,7 → 51,7
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
BOOTLOADER_EN : boolean := true; -- implement processor-internal bootloader?
USER_CODE : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom user code
HW_THREAD_ID : std_ulogic_vector(31 downto 0) := (others => '0'); -- hardware thread id (hartid)
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
93,7 → 93,8
IO_WDT_EN : boolean := true; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
IO_CFS_EN : boolean := false; -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG : std_ulogic_vector(31 downto 0) := (others => '0') -- custom CFS configuration generic
IO_CFS_CONFIG : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
IO_NCO_EN : boolean := true -- implement numerically-controlled oscillator (NCO)?
);
port (
-- Global control --
133,6 → 134,8
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
cfs_in_i : in std_ulogic_vector(31 downto 0) := (others => '0'); -- custom CFS inputs conduit
cfs_out_o : out std_ulogic_vector(31 downto 0); -- custom CFS outputs conduit
-- NCO output (available if IO_NCO_EN = true) --
nco_o : out std_ulogic_vector(02 downto 0); -- numerically-controlled oscillator channels
-- system time input from external MTIME (available if IO_MTIME_EN = false) --
mtime_i : in std_ulogic_vector(63 downto 0) := (others => '0'); -- current system time
-- Interrupts --
176,6 → 179,7
signal twi_cg_en : std_ulogic;
signal pwm_cg_en : std_ulogic;
signal cfs_cg_en : std_ulogic;
signal nco_cg_en : std_ulogic;
 
-- bus interface --
type bus_interface_t is record
229,6 → 233,8
signal cfs_rdata : std_ulogic_vector(data_width_c-1 downto 0);
signal cfs_err : std_ulogic;
signal cfs_ack : std_ulogic;
signal nco_rdata : std_ulogic_vector(data_width_c-1 downto 0);
signal nco_ack : std_ulogic;
signal sysinfo_rdata : std_ulogic_vector(data_width_c-1 downto 0);
signal sysinfo_ack : std_ulogic;
 
315,7 → 321,7
clk_div_ff <= (others => '0');
elsif rising_edge(clk_i) then
-- fresh clocks anyone? --
if ((wdt_cg_en or uart_cg_en or spi_cg_en or twi_cg_en or pwm_cg_en or cfs_cg_en) = '1') then
if ((wdt_cg_en or uart_cg_en or spi_cg_en or twi_cg_en or pwm_cg_en or cfs_cg_en or nco_cg_en) = '1') then
clk_div <= std_ulogic_vector(unsigned(clk_div) + 1);
end if;
clk_div_ff <= clk_div;
540,15 → 546,15
p_bus_err_i => p_bus.err -- bus transfer error
);
 
-- processor bus: CPU data input --
-- processor bus: CPU transfer data input --
p_bus.rdata <= (imem_rdata or dmem_rdata or bootrom_rdata) or wishbone_rdata or (gpio_rdata or mtime_rdata or uart_rdata or
spi_rdata or twi_rdata or pwm_rdata or wdt_rdata or trng_rdata or cfs_rdata or sysinfo_rdata);
spi_rdata or twi_rdata or pwm_rdata or wdt_rdata or trng_rdata or cfs_rdata or nco_rdata or sysinfo_rdata);
 
-- processor bus: CPU data ACK input --
-- processor bus: CPU transfer ACK input --
p_bus.ack <= (imem_ack or dmem_ack or bootrom_ack) or wishbone_ack or (gpio_ack or mtime_ack or uart_ack or
spi_ack or twi_ack or pwm_ack or wdt_ack or trng_ack or cfs_ack or sysinfo_ack);
spi_ack or twi_ack or pwm_ack or wdt_ack or trng_ack or cfs_ack or nco_ack or sysinfo_ack);
 
-- processor bus: CPU data bus error input --
-- processor bus: CPU transfer data bus error input --
p_bus.err <= wishbone_err or cfs_err;
 
-- current CPU privilege level --
992,6 → 998,37
end generate;
 
 
-- Numerically-Controlled Oscillator (NCO) ------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_nco_inst_true:
if (IO_NCO_EN = true) generate
neorv32_nco_inst: neorv32_nco
port map (
-- host access --
clk_i => clk_i, -- global clock line
addr_i => p_bus.addr, -- address
rden_i => io_rden, -- read enable
wren_i => io_wren, -- write enable
data_i => p_bus.wdata, -- data in
data_o => nco_rdata, -- data out
ack_o => nco_ack, -- transfer acknowledge
-- clock generator --
clkgen_en_o => nco_cg_en, -- enable clock generator
clkgen_i => clk_gen,
-- NCO output --
nco_o => nco_o
);
end generate;
 
neorv32_nco_inst_false:
if (IO_NCO_EN = false) generate
nco_rdata <= (others => '0');
nco_ack <= '0';
nco_cg_en <= '0';
nco_o <= (others => '0');
end generate;
 
 
-- True Random Number Generator (TRNG) ----------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_trng_inst_true:
1047,7 → 1084,8
IO_PWM_EN => IO_PWM_EN, -- implement pulse-width modulation unit (PWM)?
IO_WDT_EN => IO_WDT_EN, -- implement watch dog timer (WDT)?
IO_TRNG_EN => IO_TRNG_EN, -- implement true random number generator (TRNG)?
IO_CFS_EN => IO_CFS_EN -- implement custom functions subsystem (CFS)?
IO_CFS_EN => IO_CFS_EN, -- implement custom functions subsystem (CFS)?
IO_NCO_EN => IO_NCO_EN -- implement numerically-controlled oscillator (NCO)?
)
port map (
-- host access --
/rtl/top_templates/neorv32_test_setup.vhd
72,9 → 72,9
CLOCK_FREQUENCY => 100000000, -- clock frequency of clk_i in Hz
BOOTLOADER_EN => true, -- implement processor-internal bootloader?
USER_CODE => x"00000000", -- custom user code
HW_THREAD_ID => x"00000000", -- hardware thread id (hartid)
HW_THREAD_ID => 0, -- hardware thread id (hartid)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A => true, -- implement atomic extension?
CPU_EXTENSION_RISCV_A => false, -- implement atomic extension?
CPU_EXTENSION_RISCV_B => false, -- implement bit manipulation extensions?
CPU_EXTENSION_RISCV_C => true, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => false, -- implement embedded RF extension?
81,7 → 81,7
CPU_EXTENSION_RISCV_M => true, -- implement muld/div extension?
CPU_EXTENSION_RISCV_U => true, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr => true, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => true, -- implement instruction stream sync.?
CPU_EXTENSION_RISCV_Zifencei => false, -- implement instruction stream sync.?
-- Extension Options --
FAST_MUL_EN => false, -- use DSPs for M extension's multiplier
FAST_SHIFT_EN => false, -- use barrel shifter for shift operations
114,13 → 114,14
IO_WDT_EN => true, -- implement watch dog timer (WDT)?
IO_TRNG_EN => false, -- implement true random number generator (TRNG)?
IO_CFS_EN => false, -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG => (others => '0') -- custom CFS configuration generic
IO_CFS_CONFIG => x"00000000", -- custom CFS configuration generic
IO_NCO_EN => false -- implement numerically-controlled oscillator (NCO)?
)
port map (
-- Global control --
clk_i => clk_i, -- global clock, rising edge
rstn_i => rstn_i, -- global reset, low-active, async
-- Wishbone bus interface --
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
wb_tag_o => open, -- tag
wb_adr_o => open, -- address
wb_dat_i => (others => '0'), -- read data
132,28 → 133,30
wb_lock_o => open, -- locked/exclusive bus access
wb_ack_i => '0', -- transfer acknowledge
wb_err_i => '0', -- transfer error
-- Advanced memory control signals --
-- Advanced memory control signals (available if MEM_EXT_EN = true) --
fence_o => open, -- indicates an executed FENCE operation
fencei_o => open, -- indicates an executed FENCEI operation
-- GPIO --
-- GPIO (available if IO_GPIO_EN = true) --
gpio_o => gpio_out, -- parallel output
gpio_i => (others => '0'), -- parallel input
-- UART --
-- UART (available if IO_UART_EN = true) --
uart_txd_o => uart_txd_o, -- UART send data
uart_rxd_i => uart_rxd_i, -- UART receive data
-- SPI --
-- SPI (available if IO_SPI_EN = true) --
spi_sck_o => open, -- SPI serial clock
spi_sdo_o => open, -- controller data out, peripheral data in
spi_sdi_i => '0', -- controller data in, peripheral data out
spi_csn_o => open, -- SPI CS
-- TWI --
-- TWI (available if IO_TWI_EN = true) --
twi_sda_io => open, -- twi serial data line
twi_scl_io => open, -- twi serial clock line
-- PWM --
-- PWM (available if IO_PWM_EN = true) --
pwm_o => open, -- pwm channels
-- Custom Functions Subsystem IO --
cfs_in_i => (others => '0'), -- custom inputs
cfs_out_o => open, -- custom outputs
-- NCO output (available if IO_NCO_EN = true) --
nco_o => open, -- numerically-controlled oscillator channels
-- system time input from external MTIME (available if IO_MTIME_EN = false) --
mtime_i => (others => '0'), -- current system time
-- Interrupts --
/rtl/top_templates/neorv32_top_axi4lite.vhd
1,7 → 1,7
-- #################################################################################################
-- # << NEORV32 - Processor Top Entity with AXI4-Lite Compatible Master Interface >> #
-- # ********************************************************************************************* #
-- # "AXI", "AXI4" and "AXI4-Lite" are trademarks of Arm Holdings plc. #
-- # (c) "AXI", "AXI4" and "AXI4-Lite" are trademarks of Arm Holdings plc. #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
43,11 → 43,14
 
entity neorv32_top_axi4lite is
generic (
-- ------------------------------------------------------------
-- Configuration Generics --
-- ------------------------------------------------------------
-- General --
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
BOOTLOADER_EN : boolean := true; -- implement processor-internal bootloader?
USER_CODE : std_logic_vector(31 downto 0) := x"00000000"; -- custom user code
HW_THREAD_ID : std_logic_vector(31 downto 0) := (others => '0'); -- hardware thread id (hartid)
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
87,10 → 90,13
IO_WDT_EN : boolean := true; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
IO_CFS_EN : boolean := false; -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG : std_logic_vector(31 downto 0) := (others => '0') -- custom CFS configuration generic
IO_CFS_CONFIG : std_logic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
IO_NCO_EN : boolean := true -- implement numerically-controlled oscillator (NCO)?
);
port (
-- AXI Lite-Compatible Master Interface --
-- ------------------------------------------------------------
-- AXI4-Lite-Compatible Master Interface --
-- ------------------------------------------------------------
-- Clock and Reset --
m_axi_aclk : in std_logic;
m_axi_aresetn : in std_logic;
119,25 → 125,29
m_axi_bvalid : in std_logic;
m_axi_bready : out std_logic;
-- ------------------------------------------------------------
-- GPIO --
-- Processor IO --
-- ------------------------------------------------------------
-- GPIO (available if IO_GPIO_EN = 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 --
-- UART (available if IO_UART_EN = true) --
uart_txd_o : out std_logic; -- UART send data
uart_rxd_i : in std_logic := '0'; -- UART receive data
-- SPI --
-- SPI (available if IO_SPI_EN = 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 --
-- TWI (available if IO_TWI_EN = true) --
twi_sda_io : inout std_logic; -- twi serial data line
twi_scl_io : inout std_logic; -- twi serial clock line
-- PWM --
-- PWM (available if IO_PWM_EN = true) --
pwm_o : out std_logic_vector(03 downto 0); -- pwm channels
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
cfs_in_i : in std_logic_vector(31 downto 0); -- custom inputs
cfs_out_o : out std_logic_vector(31 downto 0); -- custom outputs
-- NCO output (available if IO_NCO_EN = true) --
nco_o : out std_logic_vector(02 downto 0); -- numerically-controlled oscillator channels
-- Interrupts --
soc_firq_i : in std_logic_vector(7 downto 0) := (others => '0'); -- fast interrupt channels
mtime_irq_i : in std_logic := '0'; -- machine timer interrupt, available if IO_MTIME_EN = false
150,7 → 160,6
 
-- type conversion --
constant USER_CODE_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(USER_CODE);
constant HW_THREAD_ID_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(HW_THREAD_ID);
constant IO_CFS_CONFIG_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(IO_CFS_CONFIG);
--
signal clk_i_int : std_ulogic;
172,6 → 181,8
signal cfs_in_i_int : std_ulogic_vector(31 downto 0);
signal cfs_out_o_int : std_ulogic_vector(31 downto 0);
--
signal nco_o_int : std_ulogic_vector(02 downto 0);
--
signal soc_firq_i_int : std_ulogic_vector(7 downto 0);
signal mtime_irq_i_int : std_ulogic;
signal msw_irq_i_int : std_ulogic;
219,7 → 230,7
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
BOOTLOADER_EN => BOOTLOADER_EN , -- implement processor-internal bootloader?
USER_CODE => USER_CODE_INT, -- custom user code
HW_THREAD_ID => HW_THREAD_ID_INT, -- hardware thread id (hartid)
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id (hartid)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A, -- implement atomic extension?
CPU_EXTENSION_RISCV_B => CPU_EXTENSION_RISCV_B, -- implement bit manipulation extensions?
261,13 → 272,14
IO_WDT_EN => IO_WDT_EN, -- implement watch dog timer (WDT)?
IO_TRNG_EN => IO_TRNG_EN, -- implement true random number generator (TRNG)?
IO_CFS_EN => IO_CFS_EN, -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG => IO_CFS_CONFIG_INT -- custom CFS configuration generic
IO_CFS_CONFIG => IO_CFS_CONFIG_INT, -- custom CFS configuration generic
IO_NCO_EN => IO_NCO_EN -- implement numerically-controlled oscillator (NCO)?
)
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 --
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
wb_tag_o => wb_core.tag, -- tag
wb_adr_o => wb_core.adr, -- address
wb_dat_i => wb_core.di, -- read data
279,28 → 291,30
wb_lock_o => open, -- locked/exclusive bus access
wb_ack_i => wb_core.ack, -- transfer acknowledge
wb_err_i => wb_core.err, -- transfer error
-- Advanced memory control signals --
-- Advanced memory control signals (available if MEM_EXT_EN = true) --
fence_o => open, -- indicates an executed FENCE operation
fencei_o => open, -- indicates an executed FENCEI operation
-- GPIO --
-- GPIO (available if IO_GPIO_EN = true) --
gpio_o => gpio_o_int, -- parallel output
gpio_i => gpio_i_int, -- parallel input
-- UART --
-- UART (available if IO_UART_EN = true) --
uart_txd_o => uart_txd_o_int, -- UART send data
uart_rxd_i => uart_rxd_i_int, -- UART receive data
-- SPI --
-- SPI (available if IO_SPI_EN = true) --
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 (available if IO_TWI_EN = true) --
twi_sda_io => twi_sda_io, -- twi serial data line
twi_scl_io => twi_scl_io, -- twi serial clock line
-- PWM --
-- PWM available if IO_PWM_EN = true) --
pwm_o => pwm_o_int, -- pwm channels
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
cfs_in_i => cfs_in_i_int, -- custom inputs
cfs_out_o => cfs_out_o_int, -- custom outputs
-- NCO output (available if IO_NCO_EN = true) --
nco_o => nco_o_int, -- numerically-controlled oscillator channels
-- system time input from external MTIME (available if IO_MTIME_EN = false) --
mtime_i => (others => '0'), -- current system time
-- Interrupts --
327,6 → 341,8
cfs_in_i_int <= std_ulogic_vector(cfs_in_i);
cfs_out_o <= std_logic_vector(cfs_out_o_int);
 
nco_o <= std_logic_vector(nco_o_int);
 
soc_firq_i_int <= std_ulogic_vector(soc_firq_i);
msw_irq_i_int <= std_ulogic(msw_irq_i);
mext_irq_i_int <= std_ulogic(mext_irq_i);
350,19 → 366,19
else -- busy
-- "read address received" flag --
if (wb_core.we = '0') then -- pending READ
if (m_axi_arready = '1') then -- read address received?
if (m_axi_arready = '1') then -- read address received by interconnect?
ctrl.radr_received <= '1';
end if;
end if;
-- "write address received" flag --
if (wb_core.we = '1') then -- pending WRITE
if (m_axi_awready = '1') then -- write address received?
if (m_axi_awready = '1') then -- write address received by interconnect?
ctrl.wadr_received <= '1';
end if;
end if;
-- "write data received" flag --
if (wb_core.we = '1') then -- pending WRITE
if (m_axi_wready = '1') then
if (m_axi_wready = '1') then -- write data received by interconnect?
ctrl.wdat_received <= '1';
end if;
end if;
/rtl/top_templates/neorv32_top_stdlogic.vhd
45,7 → 45,7
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
BOOTLOADER_EN : boolean := true; -- implement processor-internal bootloader?
USER_CODE : std_logic_vector(31 downto 0) := x"00000000"; -- custom user code
HW_THREAD_ID : std_logic_vector(31 downto 0) := (others => '0'); -- hardware thread id (hartid)
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
87,7 → 87,8
IO_WDT_EN : boolean := true; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
IO_CFS_EN : boolean := false; -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG : std_logic_vector(31 downto 0) := (others => '0') -- custom CFS configuration generic
IO_CFS_CONFIG : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
IO_NCO_EN : boolean := true -- implement numerically-controlled oscillator (NCO)?
);
port (
-- Global control --
127,6 → 128,8
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
cfs_in_i : in std_logic_vector(31 downto 0); -- custom inputs
cfs_out_o : out std_logic_vector(31 downto 0); -- custom outputs
-- NCO output (available if IO_NCO_EN = true) --
nco_o : out std_logic_vector(02 downto 0); -- numerically-controlled oscillator channels
-- system time input from external MTIME (available if IO_MTIME_EN = false) --
mtime_i : in std_logic_vector(63 downto 0) := (others => '0'); -- current system time
-- Interrupts --
141,7 → 144,6
 
-- type conversion --
constant USER_CODE_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(USER_CODE);
constant HW_THREAD_ID_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(HW_THREAD_ID);
constant IO_CFS_CONFIG_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(IO_CFS_CONFIG);
--
signal clk_i_int : std_ulogic;
178,6 → 180,8
signal cfs_in_i_int : std_ulogic_vector(31 downto 0);
signal cfs_out_o_int : std_ulogic_vector(31 downto 0);
--
signal nco_o_int : std_ulogic_vector(02 downto 0);
--
signal mtime_i_int : std_ulogic_vector(63 downto 0);
--
signal soc_firq_i_int : std_ulogic_vector(7 downto 0);
195,7 → 199,7
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
BOOTLOADER_EN => BOOTLOADER_EN, -- implement processor-internal bootloader?
USER_CODE => USER_CODE_INT, -- custom user code
HW_THREAD_ID => HW_THREAD_ID_INT, -- hardware thread id (hartid)
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id (hartid) (32-bit)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A, -- implement atomic extension?
CPU_EXTENSION_RISCV_B => CPU_EXTENSION_RISCV_B, -- implement bit manipulation extensions?
237,13 → 241,14
IO_WDT_EN => IO_WDT_EN, -- implement watch dog timer (WDT)?
IO_TRNG_EN => IO_TRNG_EN, -- implement true random number generator (TRNG)?
IO_CFS_EN => IO_CFS_EN, -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG => IO_CFS_CONFIG_INT -- custom CFS configuration generic
IO_CFS_CONFIG => IO_CFS_CONFIG_INT, -- custom CFS configuration generic
IO_NCO_EN => IO_NCO_EN -- implement numerically-controlled oscillator (NCO)?
)
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 --
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
wb_tag_o => wb_tag_o_int, -- tag
wb_adr_o => wb_adr_o_int, -- address
wb_dat_i => wb_dat_i_int, -- read data
255,28 → 260,30
wb_lock_o => wb_lock_o_int, -- locked/exclusive bus access
wb_ack_i => wb_ack_i_int, -- transfer acknowledge
wb_err_i => wb_err_i_int, -- transfer error
-- Advanced memory control signals --
-- Advanced memory control signals (available if MEM_EXT_EN = true) --
fence_o => fence_o_int, -- indicates an executed FENCE operation
fencei_o => fencei_o_int, -- indicates an executed FENCEI operation
-- GPIO --
-- GPIO (available if IO_GPIO_EN = true) --
gpio_o => gpio_o_int, -- parallel output
gpio_i => gpio_i_int, -- parallel input
-- UART --
-- UART (available if IO_UART_EN = true) --
uart_txd_o => uart_txd_o_int, -- UART send data
uart_rxd_i => uart_rxd_i_int, -- UART receive data
-- SPI --
-- SPI (available if IO_SPI_EN = true) --
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 (available if IO_TWI_EN = true) --
twi_sda_io => twi_sda_io, -- twi serial data line
twi_scl_io => twi_scl_io, -- twi serial clock line
-- PWM --
-- PWM (available if IO_PWM_EN = true) --
pwm_o => pwm_o_int, -- pwm channels
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
cfs_in_i => cfs_in_i_int, -- custom inputs
cfs_out_o => cfs_out_o_int, -- custom outputs
-- NCO output (available if IO_NCO_EN = true) --
nco_o => nco_o_int, -- numerically-controlled oscillator channels
-- system time input from external MTIME (available if IO_MTIME_EN = false) --
mtime_i => mtime_i_int, -- current system time
-- Interrupts --
321,6 → 328,8
cfs_in_i_int <= std_ulogic_vector(cfs_in_i);
cfs_out_o <= std_logic_vector(cfs_out_o_int);
 
nco_o <= std_logic_vector(nco_o_int);
 
mtime_i_int <= std_ulogic_vector(mtime_i);
 
soc_firq_i_int <= std_ulogic_vector(soc_firq_i);
/sim/ghdl/ghdl_sim.sh
55,6 → 55,7
ghdl -a --work=neorv32 $srcdir_core/neorv32_gpio.vhd
ghdl -a --work=neorv32 $srcdir_core/neorv32_imem.vhd
ghdl -a --work=neorv32 $srcdir_core/neorv32_mtime.vhd
ghdl -a --work=neorv32 $srcdir_core/neorv32_nco.vhd
ghdl -a --work=neorv32 $srcdir_core/neorv32_pwm.vhd
ghdl -a --work=neorv32 $srcdir_core/neorv32_spi.vhd
ghdl -a --work=neorv32 $srcdir_core/neorv32_sysinfo.vhd
/sim/vivado/neorv32_tb_behav.wcfg
12,15 → 12,18
</db_ref>
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="65908200fs"></ZoomStartTime>
<ZoomEndTime time="65943001fs"></ZoomEndTime>
<Cursor1Time time="65991400fs"></Cursor1Time>
<ZoomStartTime time="78970416fs"></ZoomStartTime>
<ZoomEndTime time="79485917fs"></ZoomEndTime>
<Cursor1Time time="79325000fs"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="203"></NameColumnWidth>
<ValueColumnWidth column_width="100"></ValueColumnWidth>
<ValueColumnWidth column_width="88"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="132" />
<WVObjectSize size="133" />
<wave_markers>
<marker time="123675000" label="" />
</wave_markers>
<wvobject type="divider" fp_name="divider273">
<obj_property name="label">CPU: Control.FETCH</obj_property>
<obj_property name="DisplayName">label</obj_property>
114,8 → 117,8
<obj_property name="ObjectShortName">be_store_i</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/ctrl_o" type="array">
<obj_property name="ElementShortName">ctrl_o[61:0]</obj_property>
<obj_property name="ObjectShortName">ctrl_o[61:0]</obj_property>
<obj_property name="ElementShortName">ctrl_o[69:0]</obj_property>
<obj_property name="ObjectShortName">ctrl_o[69:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/ci_instr32" type="array">
<obj_property name="ElementShortName">ci_instr32[31:0]</obj_property>
173,18 → 176,13
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/cnt_event" type="array">
<obj_property name="ElementShortName">cnt_event[12:0]</obj_property>
<obj_property name="ObjectShortName">cnt_event[12:0]</obj_property>
<obj_property name="isExpanded"></obj_property>
<obj_property name="ElementShortName">cnt_event[14:0]</obj_property>
<obj_property name="ObjectShortName">cnt_event[14:0]</obj_property>
</wvobject>
<wvobject type="divider" fp_name="divider139">
<obj_property name="label">CPU: RegFile</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_regfile_inst/reg_file" type="array">
<obj_property name="ElementShortName">reg_file[31:0][31:0]</obj_property>
<obj_property name="ObjectShortName">reg_file[31:0][31:0]</obj_property>
</wvobject>
<wvobject type="divider" fp_name="divider367">
<obj_property name="label">CPU: ALU</obj_property>
<obj_property name="DisplayName">label</obj_property>
205,10 → 203,6
<obj_property name="ElementShortName">imm_i[31:0]</obj_property>
<obj_property name="ObjectShortName">imm_i[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cmp_o" type="array">
<obj_property name="ElementShortName">cmp_o[1:0]</obj_property>
<obj_property name="ObjectShortName">cmp_o[1:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/res_o" type="array">
<obj_property name="ElementShortName">res_o[31:0]</obj_property>
<obj_property name="ObjectShortName">res_o[31:0]</obj_property>
387,10 → 381,6
<obj_property name="label">CPU: MULDIV CP</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_cp_muldiv_inst_true/neorv32_cpu_cp_muldiv_inst/clk_i" type="logic">
<obj_property name="ElementShortName">clk_i</obj_property>
<obj_property name="ObjectShortName">clk_i</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_cp_muldiv_inst_true/neorv32_cpu_cp_muldiv_inst/res_o" type="array">
<obj_property name="ElementShortName">res_o[31:0]</obj_property>
<obj_property name="ObjectShortName">res_o[31:0]</obj_property>
451,14 → 441,6
<obj_property name="label">IO: UART</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_uart_inst_true/neorv32_uart_inst/wr_en" type="logic">
<obj_property name="ElementShortName">wr_en</obj_property>
<obj_property name="ObjectShortName">wr_en</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_uart_inst_true/neorv32_uart_inst/rd_en" type="logic">
<obj_property name="ElementShortName">rd_en</obj_property>
<obj_property name="ObjectShortName">rd_en</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_uart_inst_true/neorv32_uart_inst/uart_txd_o" type="logic">
<obj_property name="ElementShortName">uart_txd_o</obj_property>
<obj_property name="ObjectShortName">uart_txd_o</obj_property>
467,10 → 449,6
<obj_property name="ElementShortName">uart_rxd_i</obj_property>
<obj_property name="ObjectShortName">uart_rxd_i</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_uart_inst_true/neorv32_uart_inst/uart_irq_o" type="logic">
<obj_property name="ElementShortName">uart_irq_o</obj_property>
<obj_property name="ObjectShortName">uart_irq_o</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_uart_inst_true/neorv32_uart_inst/ctrl" type="array">
<obj_property name="ElementShortName">ctrl[31:0]</obj_property>
<obj_property name="ObjectShortName">ctrl[31:0]</obj_property>
484,6 → 462,34
<obj_property name="ObjectShortName">uart_rx</obj_property>
</wvobject>
<wvobject type="divider" fp_name="divider238">
<obj_property name="label">IO: NCO</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_nco_inst_true/neorv32_nco_inst/clkgen_en_o" type="logic">
<obj_property name="ElementShortName">clkgen_en_o</obj_property>
<obj_property name="ObjectShortName">clkgen_en_o</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_nco_inst_true/neorv32_nco_inst/clkgen_i" type="array">
<obj_property name="ElementShortName">clkgen_i[7:0]</obj_property>
<obj_property name="ObjectShortName">clkgen_i[7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_nco_inst_true/neorv32_nco_inst/nco_o" type="array">
<obj_property name="ElementShortName">nco_o[2:0]</obj_property>
<obj_property name="ObjectShortName">nco_o[2:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_nco_inst_true/neorv32_nco_inst/tuning_word" type="array">
<obj_property name="ElementShortName">tuning_word[0:2][19:0]</obj_property>
<obj_property name="ObjectShortName">tuning_word[0:2][19:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_nco_inst_true/neorv32_nco_inst/ctrl" type="array">
<obj_property name="ElementShortName">ctrl[30:0]</obj_property>
<obj_property name="ObjectShortName">ctrl[30:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_nco_inst_true/neorv32_nco_inst/nco" type="array">
<obj_property name="ElementShortName">nco</obj_property>
<obj_property name="ObjectShortName">nco</obj_property>
</wvobject>
<wvobject type="divider" fp_name="divider238">
<obj_property name="label">EXT_MEM Interface</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
/sim/neorv32_tb.vhd
176,7 → 176,7
CLOCK_FREQUENCY => f_clock_c, -- clock frequency of clk_i in Hz
BOOTLOADER_EN => false, -- implement processor-internal bootloader?
USER_CODE => x"12345678", -- custom user code
HW_THREAD_ID => x"00000000", -- hardware thread id (hartid)
HW_THREAD_ID => 0, -- hardware thread id (hartid) (32-bit)
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A => true, -- implement atomic extension?
CPU_EXTENSION_RISCV_B => true, -- implement bit manipulation extensions?
218,13 → 218,14
IO_WDT_EN => true, -- implement watch dog timer (WDT)?
IO_TRNG_EN => false, -- trng cannot be simulated
IO_CFS_EN => true, -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG => (others => '0') -- custom CFS configuration generic
IO_CFS_CONFIG => (others => '0'), -- custom CFS configuration generic
IO_NCO_EN => true -- implement numerically-controlled oscillator (NCO)?
)
port map (
-- Global control --
clk_i => clk_gen, -- global clock, rising edge
rstn_i => rst_gen, -- global reset, low-active, async
-- Wishbone bus interface --
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
wb_tag_o => wb_cpu.tag, -- tag
wb_adr_o => wb_cpu.addr, -- address
wb_dat_i => wb_cpu.rdata, -- read data
236,28 → 237,30
wb_lock_o => wb_cpu.lock, -- locked/exclusive bus access
wb_ack_i => wb_cpu.ack, -- transfer acknowledge
wb_err_i => wb_cpu.err, -- transfer error
-- Advanced memory control signals --
-- Advanced memory control signals (available if MEM_EXT_EN = true) --
fence_o => open, -- indicates an executed FENCE operation
fencei_o => open, -- indicates an executed FENCEI operation
-- GPIO --
-- GPIO (available if IO_GPIO_EN = true) --
gpio_o => gpio, -- parallel output
gpio_i => gpio, -- parallel input
-- UART --
-- UART (available if IO_UART_EN = true) --
uart_txd_o => uart_txd, -- UART send data
uart_rxd_i => uart_txd, -- UART receive data
-- SPI --
-- SPI (available if IO_SPI_EN = true) --
spi_sck_o => open, -- SPI serial clock
spi_sdo_o => spi_data, -- controller data out, peripheral data in
spi_sdi_i => spi_data, -- controller data in, peripheral data out
spi_csn_o => open, -- SPI CS
-- TWI --
-- TWI (available if IO_TWI_EN = true) --
twi_sda_io => twi_sda, -- twi serial data line
twi_scl_io => twi_scl, -- twi serial clock line
-- PWM --
-- PWM (available if IO_PWM_EN = true) --
pwm_o => open, -- pwm channels
-- Custom Functions Subsystem IO --
cfs_in_i => (others => '0'), -- custom CFS inputs
cfs_out_o => open, -- custom CFS outputs
-- NCO output (available if IO_NCO_EN = true) --
nco_o => open, -- numerically-controlled oscillator channels
-- system time input from external MTIME (available if IO_MTIME_EN = false) --
mtime_i => (others => '0'), -- current system time
-- Interrupts --
/sw/example/demo_nco/main.c
0,0 → 1,355
// #################################################################################################
// # << NEORV32 - Numerically-controller oscillator (NCO) demo >> #
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2021, 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 #
// #################################################################################################
 
 
/**********************************************************************//**
* @file demo_nco/main.c
* @author Stephan Nolting
* @brief Interactive NCO configuration program.
**************************************************************************/
 
#include <neorv32.h>
#include <string.h>
 
 
/**********************************************************************//**
* @name User configuration
**************************************************************************/
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE 19200
/**@}*/
 
 
// Prototypes
void nco_setup(void);
void nco_show_config(uint8_t channel);
uint32_t hexstr_to_uint(char *buffer, uint8_t length);
 
 
/**********************************************************************//**
* Demo program to configure the NCO via an interactive UART terminal.
*
* @note This program requires the NCO and the UART modules.
*
* @return Irrelevant.
**************************************************************************/
int main() {
 
char buffer[8];
int length = 0;
 
// setup run-time environment for interrupts and exceptions
neorv32_rte_setup();
 
// init UART at default baud rate, no parity bits
neorv32_uart_setup(BAUD_RATE, 0b00);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
 
// check if NCO unit is implemented at all
if (neorv32_nco_available() == 0) {
neorv32_uart_printf("ERROR! NCO unit not synthesized!\n");
return 0;
}
 
// say hello
neorv32_uart_printf("Interactive NCO configuration console.\n");
 
 
// clear NCO
neorv32_nco_disable(); // disable NCO
neorv32_nco_set_tuning(0, 0); // set tuning word of channel 0 to zero
neorv32_nco_set_tuning(1, 0); // set tuning word of channel 1 to zero
neorv32_nco_set_tuning(2, 0); // set tuning word of channel 2 to zero
neorv32_nco_enable(); // globally enable NCO
 
 
// info
neorv32_uart_printf("This program allows configure each NCO channel.\n"
"Type 'help' to see the help menu.\n\n");
 
// Main menu
for (;;) {
neorv32_uart_printf("NCO:> ");
length = neorv32_uart_scan(buffer, 8, 1);
neorv32_uart_printf("\n");
 
if (!length) // nothing to be done
continue;
 
// decode input and execute command
if (!strcmp(buffer, "help")) {
neorv32_uart_printf("Available commands:\n"
" help - show this text\n"
" setup - configure NCO channel\n"
" info - show current NCO configuration\n"
" on - disable NCO globally\n"
" off - enable NCO globally\n");
}
 
else if (!strcmp(buffer, "setup")) {
nco_setup();
}
 
else if (!strcmp(buffer, "info")) {
nco_show_config(0);
nco_show_config(1);
nco_show_config(2);
}
 
else if (!strcmp(buffer, "on")) {
neorv32_nco_enable();
neorv32_uart_printf("NCO enabled.\n");
}
 
else if (!strcmp(buffer, "off")) {
neorv32_nco_disable();
neorv32_uart_printf("NCO disabled.\n");
}
 
else {
neorv32_uart_printf("Invalid command. Type 'help' to see all commands.\n");
}
}
 
return 0;
}
 
 
 
/**********************************************************************//**
* Configure NCO channel dialog
**************************************************************************/
void nco_setup(void) {
 
char terminal_buffer[16];
 
// get channel number
neorv32_uart_printf("Enter channel number (0,1,2): ");
neorv32_uart_scan(terminal_buffer, 1+1, 1); // 1 hex char plus '\0'
uint32_t nco_channel = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (nco_channel > 3) {
neorv32_uart_printf("\nInvalid channel.\n");
return;
}
 
 
// get clock prescaler
neorv32_uart_printf("\nEnter clock prescaler (0..7): ");
neorv32_uart_scan(terminal_buffer, 1+1, 1); // 1 hex char plus '\0'
uint32_t nco_prsc = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (nco_prsc > 7) {
neorv32_uart_printf("\nInvalid prescaler.\n");
return;
}
 
 
// get idle polarity
neorv32_uart_printf("\nEnter idle polarity (0/1): ");
neorv32_uart_scan(terminal_buffer, 1+1, 1); // 1 hex char plus '\0'
uint32_t nco_idle_pol = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (nco_idle_pol > 1) {
neorv32_uart_printf("\nInvalid polarity.\n");
return;
}
 
 
// get mode
neorv32_uart_printf("\nEnter mode (0/1): ");
neorv32_uart_scan(terminal_buffer, 1+1, 1); // 1 hex char plus '\0'
uint32_t nco_mode = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (nco_mode > 1) {
neorv32_uart_printf("\nInvalid mode.\n");
return;
}
 
// get pulse length
uint32_t nco_pulse = 0;
if (nco_mode) {
neorv32_uart_printf("\nEnter pulse length (0..7): ");
neorv32_uart_scan(terminal_buffer, 1+1, 1); // 1 hex char plus '\0'
nco_pulse = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (nco_pulse > 7) {
neorv32_uart_printf("\nInvalid pulse length.\n");
return;
}
}
 
 
// get tuning word
neorv32_uart_printf("\nEnter tuing word (5 hex chars): 0x");
neorv32_uart_scan(terminal_buffer, 5+1, 1); // 5 hex chars plus '\0'
uint32_t nco_tuning_word = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (nco_tuning_word > 0xffffff) {
neorv32_uart_printf("\nTuning word out of range.\n");
return;
}
 
 
// set configuration
neorv32_nco_setup((uint8_t)nco_channel, (uint8_t)nco_mode, (uint8_t)nco_idle_pol, 1, (uint8_t)nco_prsc, (uint8_t)nco_pulse); // always set output_enable
neorv32_nco_set_tuning((uint8_t)nco_channel, nco_tuning_word);
 
neorv32_uart_printf("\nDone.\n");
 
// show new configuration
nco_show_config((uint8_t)nco_channel);
}
 
 
/**********************************************************************//**
* Show channel configuration.
*
* @param[in] channel Channel number (0,1,2).
**************************************************************************/
void nco_show_config(uint8_t channel) {
 
channel &= 0x03;
neorv32_uart_printf("---------------------------\n");
neorv32_uart_printf("NCO channel %u configuration\n", (uint32_t)channel);
neorv32_uart_printf("---------------------------\n");
 
uint32_t ctrl = NCO_CT;
ctrl >>= channel * NCO_CHX_WIDTH;
 
// mode
uint32_t nco_mode = ctrl >> (NCO_CT_CH0_MODE + channel * NCO_CHX_WIDTH);
nco_mode &= 0x01;
neorv32_uart_printf("Mode: ");
if (nco_mode == 0) {
neorv32_uart_printf("Fixed 50:50 duty cycle mode\n");
}
else {
neorv32_uart_printf("Pulse mode\n");
}
 
// idle polarity
uint32_t nco_idle_pol = ctrl >> (NCO_CT_CH0_IDLE_POL + channel * NCO_CHX_WIDTH);
nco_idle_pol &= 0x01;
neorv32_uart_printf("Idle polarity: ");
if (nco_idle_pol == 1) {
neorv32_uart_printf("High\n");
}
else {
neorv32_uart_printf("Low\n");
}
 
// clock prescaler
uint32_t nco_clock_sel = ctrl >> (NCO_CT_CH0_PRSC0 + channel * NCO_CHX_WIDTH);
nco_clock_sel &= 0x07;
neorv32_uart_printf("Clock: ");
uint32_t nco_clock_prsc;
switch (nco_clock_sel) {
case 0: nco_clock_prsc = 2; break;
case 1: nco_clock_prsc = 4; break;
case 2: nco_clock_prsc = 8; break;
case 3: nco_clock_prsc = 64; break;
case 4: nco_clock_prsc = 128; break;
case 5: nco_clock_prsc = 1024; break;
case 6: nco_clock_prsc = 2048; break;
case 7: nco_clock_prsc = 4096; break;
default: nco_clock_prsc = 0; break;
}
neorv32_uart_printf("f_main / %u = %u Hz\n", nco_clock_prsc, SYSINFO_CLK/nco_clock_prsc);
 
// pulse length prescaler
uint32_t nco_pulse_sel = 0;
uint32_t nco_pulse = 0;
if (nco_mode == 1) {
nco_pulse_sel = ctrl >> (NCO_CT_CH0_PULSE0 + channel * NCO_CHX_WIDTH);
nco_pulse_sel &= 0x07;
neorv32_uart_printf("Pulse length: ");
switch (nco_pulse_sel) {
case 0: nco_pulse = 2; break;
case 1: nco_pulse = 4; break;
case 2: nco_pulse = 8; break;
case 3: nco_pulse = 16; break;
case 4: nco_pulse = 32; break;
case 5: nco_pulse = 64; break;
case 6: nco_pulse = 128; break;
case 7: nco_pulse = 256; break;
default: nco_pulse = 0; break;
}
neorv32_uart_printf("%u NCO clock cycles\n", nco_pulse);
}
 
// tuning word
uint32_t nco_tuning_word = 0;
if (channel == 0) {nco_tuning_word = NCO_TUNE_CH0;}
if (channel == 1) {nco_tuning_word = NCO_TUNE_CH1;}
if (channel == 2) {nco_tuning_word = NCO_TUNE_CH2;}
neorv32_uart_printf("Tuning word: %u\n", nco_tuning_word);
 
// output frequency (integer only)
uint64_t freq = (uint64_t)SYSINFO_CLK;
freq = freq * nco_tuning_word;
freq = freq / nco_clock_prsc;
freq = freq >> 22;
neorv32_uart_printf("Output frequency (integer part only): %u Hz\n", (uint32_t)freq);
}
 
 
/**********************************************************************//**
* Helper function to convert N hex chars string into uint32_T
*
* @param[in,out] buffer Pointer to array of chars to convert into number.
* @param[in,out] length Length of the conversion string.
* @return Converted number.
**************************************************************************/
uint32_t hexstr_to_uint(char *buffer, uint8_t length) {
 
uint32_t res = 0, d = 0;
char c = 0;
 
while (length--) {
c = *buffer++;
 
if ((c >= '0') && (c <= '9'))
d = (uint32_t)(c - '0');
else if ((c >= 'a') && (c <= 'f'))
d = (uint32_t)((c - 'a') + 10);
else if ((c >= 'A') && (c <= 'F'))
d = (uint32_t)((c - 'A') + 10);
else
d = 0;
 
res = res + (d << (length*4));
}
 
return res;
}
 
/sw/example/demo_nco/makefile
0,0 → 1,338
#################################################################################################
# << NEORV32 - Application Makefile >> #
# ********************************************************************************************* #
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. #
# ********************************************************************************************* #
# 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 #
#################################################################################################
 
 
# *****************************************************************************
# USER CONFIGURATION
# *****************************************************************************
# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S)
 
# User's application include folders (don't forget the '-I' before each entry)
APP_INC ?= -I .
# User's application include folders - for assembly files only (don't forget the '-I' before each entry)
ASM_INC ?= -I .
 
# Optimization
EFFORT ?= -Os
 
# Compiler toolchain
RISCV_TOOLCHAIN ?= riscv32-unknown-elf
 
# CPU architecture and ABI
MARCH ?= -march=rv32i
MABI ?= -mabi=ilp32
 
# User flags for additional configuration (will be added to compiler flags)
USER_FLAGS ?=
 
# Serial port for executable upload via bootloer
COM_PORT ?= /dev/ttyUSB0
 
# Relative or absolute path to the NEORV32 home folder
NEORV32_HOME ?= ../../..
# *****************************************************************************
 
 
 
# -----------------------------------------------------------------------------
# NEORV32 framework
# -----------------------------------------------------------------------------
# Path to NEORV32 linker script and startup file
NEORV32_COM_PATH = $(NEORV32_HOME)/sw/common
# Path to main NEORV32 library include files
NEORV32_INC_PATH = $(NEORV32_HOME)/sw/lib/include
# Path to main NEORV32 library source files
NEORV32_SRC_PATH = $(NEORV32_HOME)/sw/lib/source
# Path to NEORV32 executable generator
NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen
# Path to NEORV32 core rtl folder
NEORV32_RTL_PATH = $(NEORV32_HOME)/rtl/core
# Marker file to check for NEORV32 home folder
NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h
 
# Core libraries (peripheral and CPU drivers)
CORE_SRC = $(wildcard $(NEORV32_SRC_PATH)/*.c)
# Application start-up code
CORE_SRC += $(NEORV32_COM_PATH)/crt0.S
 
# Linker script
LD_SCRIPT = $(NEORV32_COM_PATH)/neorv32.ld
 
# Main output files
APP_EXE = neorv32_exe.bin
APP_ASM = main.asm
APP_IMG = neorv32_application_image.vhd
BOOT_IMG = neorv32_bootloader_image.vhd
 
 
# -----------------------------------------------------------------------------
# Sources and objects
# -----------------------------------------------------------------------------
# Define all sources
SRC = $(APP_SRC)
SRC += $(CORE_SRC)
 
# Define all object files
OBJ = $(SRC:%=%.o)
 
 
# -----------------------------------------------------------------------------
# Tools and flags
# -----------------------------------------------------------------------------
# Compiler tools
CC = $(RISCV_TOOLCHAIN)-gcc
OBJDUMP = $(RISCV_TOOLCHAIN)-objdump
OBJCOPY = $(RISCV_TOOLCHAIN)-objcopy
SIZE = $(RISCV_TOOLCHAIN)-size
 
# Host native compiler
CC_X86 = g++ -Wall -O -g
 
# NEORV32 executable image generator
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen
 
# Compiler & linker flags
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled)
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4
CC_OPTS += $(USER_FLAGS)
 
 
# -----------------------------------------------------------------------------
# Application output definitions
# -----------------------------------------------------------------------------
.PHONY: check info help elf_info clean clean_all bootloader
.DEFAULT_GOAL := help
 
# 'compile' is still here for compatibility
exe: $(APP_ASM) $(APP_EXE)
compile: $(APP_ASM) $(APP_EXE)
install: $(APP_ASM) $(APP_IMG)
all: $(APP_ASM) $(APP_EXE) $(APP_IMG)
 
# Check if making bootloader
# Use different base address and legth for instruction memory/"rom" (BOOTMEM instead of IMEM)
# Also define "make_bootloader" for crt0.S
target bootloader: CC_OPTS += -Wl,--defsym=make_bootloader=1 -Dmake_bootloader
 
 
# -----------------------------------------------------------------------------
# Image generator targets
# -----------------------------------------------------------------------------
# install/compile tools
$(IMAGE_GEN): $(NEORV32_EXG_PATH)/image_gen.cpp
@echo Compiling $(IMAGE_GEN)
@$(CC_X86) $< -o $(IMAGE_GEN)
 
 
# -----------------------------------------------------------------------------
# General targets: Assemble, compile, link, dump
# -----------------------------------------------------------------------------
# Compile app *.s sources (assembly)
%.s.o: %.s
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@
 
# Compile app *.S sources (assembly + C pre-processor)
%.S.o: %.S
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@
 
# Compile app *.c sources
%.c.o: %.c
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@
 
# Compile app *.cpp sources
%.cpp.o: %.cpp
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@
 
# Link object files and show memory utilization
main.elf: $(OBJ)
@$(CC) $(CC_OPTS) -T $(LD_SCRIPT) $(OBJ) -o $@
@echo "Memory utilization:"
@$(SIZE) main.elf
 
# Assembly listing file (for debugging)
$(APP_ASM): main.elf
@$(OBJDUMP) -d -S -z $< > $@
 
# Generate final executable from .text + .rodata + .data (in THIS order!)
main.bin: main.elf $(APP_ASM)
@$(OBJCOPY) -I elf32-little $< -j .text -O binary text.bin
@$(OBJCOPY) -I elf32-little $< -j .rodata -O binary rodata.bin
@$(OBJCOPY) -I elf32-little $< -j .data -O binary data.bin
@cat text.bin rodata.bin data.bin > $@
@rm -f text.bin rodata.bin data.bin
 
 
# -----------------------------------------------------------------------------
# Application targets: Generate binary executable, install (as VHDL file)
# -----------------------------------------------------------------------------
# Generate NEORV32 executable image for upload via bootloader
$(APP_EXE): main.bin $(IMAGE_GEN)
@set -e
@$(IMAGE_GEN) -app_bin $< $@ $(shell basename $(CURDIR))
@echo "Executable ($(APP_EXE)) size in bytes:"
@wc -c < $(APP_EXE)
 
# Generate NEORV32 executable VHDL boot image
$(APP_IMG): main.bin $(IMAGE_GEN)
@set -e
@$(IMAGE_GEN) -app_img $< $@ $(shell basename $(CURDIR))
@echo "Installing application image to $(NEORV32_RTL_PATH)/$(APP_IMG)"
@cp $(APP_IMG) $(NEORV32_RTL_PATH)/.
 
 
# -----------------------------------------------------------------------------
# Bootloader targets
# -----------------------------------------------------------------------------
# Create and install bootloader VHDL init image
$(BOOT_IMG): main.bin $(IMAGE_GEN)
@set -e
@$(IMAGE_GEN) -bld_img $< $(BOOT_IMG) $(shell basename $(CURDIR))
@echo "Installing bootloader image to $(NEORV32_RTL_PATH)/$(BOOT_IMG)"
@cp $(BOOT_IMG) $(NEORV32_RTL_PATH)/.
 
# Just an alias that
bootloader: $(BOOT_IMG)
 
 
# -----------------------------------------------------------------------------
# Check toolchain
# -----------------------------------------------------------------------------
check: $(IMAGE_GEN)
@echo "---------------- Check: NEORV32_HOME folder ----------------"
ifneq ($(shell [ -e $(NEORV32_HOME_MARKER) ] && echo 1 || echo 0 ), 1)
$(error NEORV32_HOME folder not found!)
endif
@echo "NEORV32_HOME: $(NEORV32_HOME)"
@echo "---------------- Check: $(CC) ----------------"
@$(CC) -v
@echo "---------------- Check: $(OBJDUMP) ----------------"
@$(OBJDUMP) -V
@echo "---------------- Check: $(OBJCOPY) ----------------"
@$(OBJCOPY) -V
@echo "---------------- Check: $(SIZE) ----------------"
@$(SIZE) -V
@echo "---------------- Check: NEORV32 image_gen ----------------"
@$(IMAGE_GEN) -help
@echo "---------------- Check: Native GCC ----------------"
@$(CC_X86) -v
@echo
@echo "Toolchain check OK"
 
 
# -----------------------------------------------------------------------------
# Upload executable via serial port to bootloader
# -----------------------------------------------------------------------------
upload: $(APP_EXE)
@sh $(NEORV32_EXG_PATH)/uart_upload.sh $(COM_PORT) $(APP_EXE)
 
 
# -----------------------------------------------------------------------------
# Show configuration
# -----------------------------------------------------------------------------
info:
@echo "---------------- Info: Project ----------------"
@echo "Project folder: $(shell basename $(CURDIR))"
@echo "Source files: $(APP_SRC)"
@echo "Include folder(s): $(APP_INC)"
@echo "ASM include folder(s): $(ASM_INC)"
@echo "---------------- Info: NEORV32 ----------------"
@echo "NEORV32 home folder (NEORV32_HOME): $(NEORV32_HOME)"
@echo "IMAGE_GEN: $(IMAGE_GEN)"
@echo "Core source files:"
@echo "$(CORE_SRC)"
@echo "Core include folder:"
@echo "$(NEORV32_INC_PATH)"
@echo "---------------- Info: Objects ----------------"
@echo "Project object files:"
@echo "$(OBJ)"
@echo "---------------- Info: RISC-V CPU ----------------"
@echo "MARCH: $(MARCH)"
@echo "MABI: $(MABI)"
@echo "---------------- Info: Toolchain ----------------"
@echo "Toolchain: $(RISCV_TOLLCHAIN)"
@echo "CC: $(CC)"
@echo "OBJDUMP: $(OBJDUMP)"
@echo "OBJCOPY: $(OBJCOPY)"
@echo "SIZE: $(SIZE)"
@echo "---------------- Info: Compiler Libraries ----------------"
@echo "LIBGCC:"
@$(CC) -print-libgcc-file-name
@echo "SEARCH-DIRS:"
@$(CC) -print-search-dirs
@echo "---------------- Info: Flags ----------------"
@echo "USER_FLAGS: $(USER_FLAGS)"
@echo "CC_OPTS: $(CC_OPTS)"
@echo "---------------- Info: Host Native GCC Flags ----------------"
@echo "CC_X86: $(CC_X86)"
 
 
# -----------------------------------------------------------------------------
# Show final ELF details (just for debugging)
# -----------------------------------------------------------------------------
elf_info: main.elf
@$(OBJDUMP) -x main.elf
 
 
# -----------------------------------------------------------------------------
# Help
# -----------------------------------------------------------------------------
help:
@echo "<<< NEORV32 Application Makefile >>>"
@echo "Make sure to add the bin folder of RISC-V GCC to your PATH variable."
@echo "Targets:"
@echo " help - show this text"
@echo " check - check toolchain"
@echo " info - show makefile/toolchain configuration"
@echo " exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader"
@echo " install - compile, generate and install VHDL IMEM boot image (for application)"
@echo " all - compile and generate <neorv32_exe.bin> executable for upload via bootloader and generate and install VHDL IMEM boot image (for application)"
@echo " clean - clean up project"
@echo " clean_all - clean up project, core libraries and image generator"
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!)"
@echo " upload - upload <neorv32_exe.bin> executable via serial port <COM_PORT> to bootloader"
 
 
# -----------------------------------------------------------------------------
# Clean up
# -----------------------------------------------------------------------------
clean:
@rm -f *.elf *.o *.bin *.out *.asm *.vhd
 
clean_all: clean
@rm -f $(OBJ) $(IMAGE_GEN)
/sw/lib/include/neorv32.h
853,6 → 853,62
 
 
/**********************************************************************//**
* @name IO Device: Numerically-Controlled Oscillator (NCO)
**************************************************************************/
/**@{*/
/** NCO control register (r/w) */
#define NCO_CT (*(IO_REG32 0xFFFFFFC0UL)) // r/w: control register
/** NCO channel 0 tuning word (r/w) */
#define NCO_TUNE_CH0 (*(IO_REG32 0xFFFFFFC4UL)) // r/w: tuning word channel 0
/** NCO channel 1 tuning word (r/w) */
#define NCO_TUNE_CH1 (*(IO_REG32 0xFFFFFFC8UL)) // r/w: tuning word channel 1
/** NCO channel 2 tuning word (r/w) */
#define NCO_TUNE_CH2 (*(IO_REG32 0xFFFFFFCCUL)) // r/w: tuning word channel 2
 
/** NCO control register bits */
enum NEORV32_NCO_CT_enum {
NCO_CT_EN = 0, /**< NCO control register(0) (r/w): NCO global enable */
// channel 0
NCO_CT_CH0_MODE = 1, /**< NCO control register(1) - channel 0 (r/w): Output mode (0=fixed 50% duty cycle; 1=pulse mode) */
NCO_CT_CH0_IDLE_POL = 2, /**< NCO control register(2) - channel 0 (r/w): Output idle polarity (0=low, 1=high) */
NCO_CT_CH0_OE = 3, /**< NCO control register(3) - channel 0 (r/w): Enable processor output pin */
NCO_CT_CH0_OUTPUT = 4, /**< NCO control register(4) - channel 0 (r/-): Current channel output state */
NCO_CT_CH0_PRSC0 = 5, /**< NCO control register(5) - channel 0 (r/w): Clock prescaler select bit 0 */
NCO_CT_CH0_PRSC1 = 6, /**< NCO control register(6) - channel 0 (r/w): Clock prescaler select bit 1 */
NCO_CT_CH0_PRSC2 = 7, /**< NCO control register(7) - channel 0 (r/w): Clock prescaler select bit 2 */
NCO_CT_CH0_PULSE0 = 8, /**< NCO control register(8) - channel 0 (r/w): Pulse-mode: Pulse length select bit 0 */
NCO_CT_CH0_PULSE1 = 9, /**< NCO control register(9) - channel 0 (r/w): Pulse-mode: Pulse length select bit 1 */
NCO_CT_CH0_PULSE2 = 10, /**< NCO control register(10) - channel 0 (r/w): Pulse-mode: Pulse length select bit 2 */
// channel 1
NCO_CT_CH1_MODE = 11, /**< NCO control register(11) - channel 1 (r/w): Output mode (0=fixed 50% duty cycle; 1=pulse mode) */
NCO_CT_CH1_IDLE_POL = 12, /**< NCO control register(12) - channel 1 (r/w): Output idle polarity (0=low, 1=high) */
NCO_CT_CH1_OE = 13, /**< NCO control register(13) - channel 1 (r/w): Enable processor output pin */
NCO_CT_CH1_OUTPUT = 14, /**< NCO control register(14) - channel 1 (r/-): Current channel output state */
NCO_CT_CH1_PRSC0 = 15, /**< NCO control register(15) - channel 1 (r/w): Clock prescaler select bit 0 */
NCO_CT_CH1_PRSC1 = 16, /**< NCO control register(16) - channel 1 (r/w): Clock prescaler select bit 1 */
NCO_CT_CH1_PRSC2 = 17, /**< NCO control register(17) - channel 1 (r/w): Clock prescaler select bit 2 */
NCO_CT_CH1_PULSE0 = 18, /**< NCO control register(18) - channel 1 (r/w): Pulse-mode: Pulse length select bit 0 */
NCO_CT_CH1_PULSE1 = 19, /**< NCO control register(19) - channel 1 (r/w): Pulse-mode: Pulse length select bit 1 */
NCO_CT_CH1_PULSE2 = 20, /**< NCO control register(20) - channel 1 (r/w): Pulse-mode: Pulse length select bit 2 */
// channel 2
NCO_CT_CH2_MODE = 21, /**< NCO control register(21) - channel 2 (r/w): Output mode (0=fixed 50% duty cycle; 1=pulse mode) */
NCO_CT_CH2_IDLE_POL = 22, /**< NCO control register(22) - channel 2 (r/w): Output idle polarity (0=low, 1=high) */
NCO_CT_CH2_OE = 23, /**< NCO control register(23) - channel 2 (r/w): Enable processor output pin */
NCO_CT_CH2_OUTPUT = 24, /**< NCO control register(24) - channel 2 (r/-): Current channel output state */
NCO_CT_CH2_PRSC0 = 25, /**< NCO control register(25) - channel 2 (r/w): Clock prescaler select bit 0 */
NCO_CT_CH2_PRSC1 = 26, /**< NCO control register(26) - channel 2 (r/w): Clock prescaler select bit 1 */
NCO_CT_CH2_PRSC2 = 27, /**< NCO control register(27) - channel 2 (r/w): Clock prescaler select bit 2 */
NCO_CT_CH2_PULSE0 = 28, /**< NCO control register(28) - channel 2 (r/w): Pulse-mode: Pulse length select bit 0 */
NCO_CT_CH2_PULSE1 = 29, /**< NCO control register(29) - channel 2 (r/w): Pulse-mode: Pulse length select bit 1 */
NCO_CT_CH2_PULSE2 = 20 /**< NCO control register(30) - channel 2 (r/w): Pulse-mode: Pulse length select bit 2 */
};
 
/** Size of one "channel entry" in control register in bits */
#define NCO_CHX_WIDTH 10 // Size of one "channel entry" in control register in bits
/**@}*/
 
 
/**********************************************************************//**
* @name IO Device: System Configuration Info Memory (SYSINFO)
**************************************************************************/
/**@{*/
894,7 → 950,8
SYSINFO_FEATURES_IO_PWM = 21, /**< SYSINFO_FEATURES (21) (r/-): Pulse-width modulation unit implemented when 1 (via IO_PWM_EN generic) */
SYSINFO_FEATURES_IO_WDT = 22, /**< SYSINFO_FEATURES (22) (r/-): Watchdog timer implemented when 1 (via IO_WDT_EN generic) */
SYSINFO_FEATURES_IO_CFS = 23, /**< SYSINFO_FEATURES (23) (r/-): Custom functions subsystem implemented when 1 (via IO_CFS_EN generic) */
SYSINFO_FEATURES_IO_TRNG = 24 /**< SYSINFO_FEATURES (24) (r/-): True random number generator implemented when 1 (via IO_TRNG_EN generic) */
SYSINFO_FEATURES_IO_TRNG = 24, /**< SYSINFO_FEATURES (24) (r/-): True random number generator implemented when 1 (via IO_TRNG_EN generic) */
SYSINFO_FEATURES_IO_NCO = 25 /**< SYSINFO_FEATURES (25) (r/-): Numerically-controlled oscillator implemented when 1 (via IO_NCO_EN generic) */
};
 
/**********************************************************************//**
936,6 → 993,7
#include "neorv32_cfs.h"
#include "neorv32_gpio.h"
#include "neorv32_mtime.h"
#include "neorv32_nco.h"
#include "neorv32_pwm.h"
#include "neorv32_spi.h"
#include "neorv32_trng.h"
/sw/lib/include/neorv32_nco.h
0,0 → 1,55
// #################################################################################################
// # << NEORV32: neorv32_nco.h - Numerically-Controlled Oscillator (NCO) HW Driver >> #
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2021, 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 #
// #################################################################################################
 
 
/**********************************************************************//**
* @file neorv32_nco.h
* @author Stephan Nolting
* @brief Numerically-Controlled Oscillator (NCO) HW driver header file.
*
* @note These functions should only be used if the NCO unit was synthesized (IO_NCO_EN = true).
**************************************************************************/
 
#ifndef neorv32_nco_h
#define neorv32_nco_h
 
// prototypes
int neorv32_nco_available(void);
void neorv32_nco_enable(void);
void neorv32_nco_disable(void);
void neorv32_nco_setup(uint8_t channel, uint8_t mode, uint8_t idle_pol, uint8_t oe, uint8_t prsc, uint8_t pulse);
void neorv32_nco_set_tuning(uint8_t channel, uint32_t tune);
uint32_t neorv32_nco_get_output(uint8_t channel);
 
#endif // neorv32_nco_h
/sw/lib/source/neorv32_nco.c
0,0 → 1,171
// #################################################################################################
// # << NEORV32: neorv32_nco.c - Numerically-Controlled Oscillator (NCO) HW Driver >> #
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2021, 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 #
// #################################################################################################
 
 
/**********************************************************************//**
* @file neorv32_nco.c
* @author Stephan Nolting
* @brief Numerically-Controlled Oscillator (NCO) HW driver source file.
*
* @note These functions should only be used if the NCO unit was synthesized (IO_NCO_EN = true).
**************************************************************************/
 
#include "neorv32.h"
#include "neorv32_nco.h"
 
 
/**********************************************************************//**
* Check if NCO unit was synthesized.
*
* @return 0 if NCO was not synthesized, 1 if NCO is available.
**************************************************************************/
int neorv32_nco_available(void) {
 
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_IO_NCO)) {
return 1;
}
else {
return 0;
}
}
 
 
/**********************************************************************//**
* Enable NCO (global).
**************************************************************************/
void neorv32_nco_enable(void) {
 
NCO_CT |= (1<<NCO_CT_EN);
}
 
 
/**********************************************************************//**
* Disable NCO (global).
**************************************************************************/
void neorv32_nco_disable(void) {
 
NCO_CT &= ~(1<<NCO_CT_EN);
}
 
 
/**********************************************************************//**
* Configure NCO channel. The NCO control register bits are listed in #NEORV32_NCO_CT_enum.
*
* @param[in] channel Channel number (0,1,2).
* @param[in] mode Operation mode: 0=normal (50% duty cycle), 1=pulse-mode.
* @param[in] idle_pol Idle polarity (0 or 1).
* @param[in] oe Enable output to processor top pin when set.
* @param[in] prsc Clock select / clock prescaler, see #NEORV32_CLOCK_PRSC_enum.
* @param[in] pulse Select pulse length (in clock-prescaler cycles) for pulse-mode. See data sheet.
**************************************************************************/
void neorv32_nco_setup(uint8_t channel, uint8_t mode, uint8_t idle_pol, uint8_t oe, uint8_t prsc, uint8_t pulse) {
 
uint32_t ctrl = NCO_CT; // get current config
 
// operation mode
uint32_t mode_int = (uint32_t)(mode & 0x01);
mode_int = mode_int << NCO_CT_CH0_MODE;
 
// idle polarity
uint32_t idle_pol_int = (uint32_t)(idle_pol & 0x01);
idle_pol_int = idle_pol_int << NCO_CT_CH0_IDLE_POL;
 
// output enable
uint32_t oe_int = (uint32_t)(oe & 0x01);
oe_int = oe_int << NCO_CT_CH0_OE;
 
// clock select / prescaler
uint32_t prsc_int = (uint32_t)(prsc & 0x07);
prsc_int = prsc_int << NCO_CT_CH0_PRSC0;
 
// pulse mode: pulse length select
uint32_t pulse_int = (uint32_t)(pulse & 0x07);
pulse_int = pulse_int << NCO_CT_CH0_PULSE0;
 
// construct control word
uint32_t config = mode_int | idle_pol_int | oe_int | prsc_int | pulse_int;
 
// mask and align to selected channel
uint32_t mask_clr = (1<<NCO_CHX_WIDTH)-1;
mask_clr = mask_clr << NCO_CT_CH0_MODE;
mask_clr = mask_clr << ( NCO_CHX_WIDTH * (channel & 0x03) );
config = config << ( NCO_CHX_WIDTH * (channel & 0x03) );
 
ctrl &= ~mask_clr; // clear old configuration
ctrl |= config; // set new configuration
 
// update NCO control register
NCO_CT = ctrl;
}
 
 
/**********************************************************************//**
* Set tuning word of NCO channel.
*
* @param[in] channel Channel number (0,1,2).
* @param[in] tune Tuning word.
**************************************************************************/
void neorv32_nco_set_tuning(uint8_t channel, uint32_t tune) {
 
uint8_t channel_int = channel & 0x03;
if (channel_int == 0) {
NCO_TUNE_CH0 = tune;
}
else if (channel_int == 1) {
NCO_TUNE_CH1 = tune;
}
else if (channel_int == 2) {
NCO_TUNE_CH2 = tune;
}
}
 
 
/**********************************************************************//**
* Get current output state of NCO channel.
*
* @param[in] channel Channel number (0,1,2).
* @return Current output state (0 or 1).
**************************************************************************/
uint32_t neorv32_nco_get_output(uint8_t channel) {
 
uint8_t shift = NCO_CT_CH0_OUTPUT + NCO_CHX_WIDTH*(channel & 0x03); // insulate OUTPUT bit of selected channel
uint32_t mask = 1 << shift;
 
if (NCO_CT & mask) {
return 1;
}
else {
return 0;
}
}
/sw/lib/source/neorv32_rte.c
269,10 → 269,16
int i;
char c;
 
neorv32_uart_printf("\n\n<< Hardware Configuration Overview >>\n");
neorv32_uart_printf("\n\n<<< Processor Configuration Overview >>>\n");
 
// Processor - general stuff
neorv32_uart_printf("\n=== << General >> ===\n");
neorv32_uart_printf("Clock: %u Hz\n", SYSINFO_CLK);
neorv32_uart_printf("User ID: 0x%x\n", SYSINFO_USER_CODE);
 
 
// CPU configuration
neorv32_uart_printf("\n---- Central Processing Unit ----\n");
neorv32_uart_printf("\n=== << CPU >> ===\n");
 
// ID
neorv32_uart_printf("Hart ID: 0x%x\n", neorv32_cpu_csr_read(CSR_MHARTID));
285,7 → 291,7
neorv32_uart_printf(" (NEORV32)");
}
 
// HW version
// hardware version
neorv32_uart_printf("\nImplementation ID: 0x%x (", neorv32_cpu_csr_read(CSR_MIMPID));
neorv32_rte_print_hw_version();
neorv32_uart_printf(")\n");
353,14 → 359,8
neorv32_uart_printf("HPM Counters: %u\n", neorv32_cpu_hpm_get_counters());
 
 
// Misc - system
neorv32_uart_printf("\n\n---- Processor - General ----\n");
neorv32_uart_printf("Clock: %u Hz\n", SYSINFO_CLK);
neorv32_uart_printf("User ID: 0x%x\n", SYSINFO_USER_CODE);
 
 
// Memory configuration
neorv32_uart_printf("\n---- Processor - Memory Configuration ----\n");
neorv32_uart_printf("\n=== << Memory Configuration >> ===\n");
 
neorv32_uart_printf("Instr. base address: 0x%x\n", SYSINFO_ISPACE_BASE);
neorv32_uart_printf("Internal IMEM: ");
424,7 → 424,7
}
 
// peripherals
neorv32_uart_printf("\n\n---- Processor - Peripherals ----\n");
neorv32_uart_printf("\n=== << Peripherals >> ===\n");
 
tmp = SYSINFO_FEATURES;
 
454,6 → 454,9
 
neorv32_uart_printf("CFS - ");
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_CFS));
 
neorv32_uart_printf("NCO - ");
__neorv32_rte_print_true_false(tmp & (1 << SYSINFO_FEATURES_IO_NCO));
}
 
 
/CHANGELOG.md
14,6 → 14,9
 
| Date (*dd.mm.yyyy*) | Version | Comment |
|:----------:|:-------:|:--------|
| 13.02.2021 | 1.5.1.4 | `HW_THREAD_ID` generic is now of type `natural`; `mret` instruction now requires an additional cycle to execute; logic optimization of CPU's control logic -> smaller hardware footprint and higher f_max; updated CPU synthesis results; removed top module's generic initialization using `(others => '0')` (targeting [issue #8](https://github.com/stnolting/neorv32/issues/8)) |
| 09.02.2021 | 1.5.1.3 | modified CPU architecture: now using a "pseudo" ALU co-processor to get the result of a CSR read operation into data path, removing one input from register file input mux -> shorter critical path |
| 08.02.2021 | 1.5.1.2 | added new peripheral/IO module: **Numerically-Controlled Oscillator `NCO`**: three independent channels, 20-bit phase accu, 20-bit tuning word, fixed 50% duty cycle mode or pulsed mode; added according HW drivers and example program |
| 07.02.2021 | [**:rocket:1.5.1.0**](https://github.com/stnolting/neorv32/releases/tag/v1.5.1.0) | **New release** |
| 05.02.2021 | 1.5.0.11 | :bug: fixed error in atomic instruction `LR.W` |
| 05.02.2021 | 1.5.0.10 | CPU now provides 16 fast interrupt request lines (`FIRQ0 .. FIRQ15`) with according `mie`/`mip` CSR bits and `mcause` trap codes; removed IRQ enable flags from SPI, UART & TWI; reworked processor-internal interrupt system - assignment/priority list; UART now features individual IRQs for "RX-done" and "TX-done" conditions; changed bit order in TWI control register |
/CONTRIBUTING.md
7,8 → 7,11
 
## Contributing Process
 
1. [Fork](https://github.com/stnolting/neorv32/fork) this repository
2. Create a feature branch in your fork: `git checkout -b cool_new_feature`
3. Commit your modifications: `git commit -am 'This is awesome because ...'`
4. Push to the branch: `git push origin cool_new_feature`
5. Create a new [pull request](https://github.com/stnolting/neorv32/pulls)
0. :star: this repository ;)
1. Check out the project's [code of conduct](https://github.com/stnolting/neorv32/tree/master/CODE_OF_CONDUCT.md)
2. [Fork](https://github.com/stnolting/neorv32/fork) this repository and clone the fork
3. Create a feature branch in your fork: `git checkout -b awesome_new_feature_branch`
4. Create a new remote for the upstream repo: `git remote add upstream https://github.com/stnolting/neorv32`
5. Commit your modifications: `git commit -m "Awesome new feature!"`
6. Push to the branch: `git push origin awesome_new_feature_branch`
7. Create a new [pull request](https://github.com/stnolting/neorv32/pulls)
/README.md
36,9 → 36,9
### Key Features
 
* RISC-V 32-bit `rv32i` [**NEORV32 CPU**](#NEORV32-CPU-Features), compliant to
* Subset of the *Unprivileged ISA Specification* [(Version 2.2)](https://github.com/stnolting/neorv32/blob/master/docs/riscv-privileged.pdf)
* Subset of the *Privileged Architecture Specification* [(Version 1.12-draft)](https://github.com/stnolting/neorv32/blob/master/docs/riscv-spec.pdf)
* Passes the [offcial RISC-V compliance tests](#Status)
* subset of the *Unprivileged ISA Specification* [(Version 2.2)](https://github.com/stnolting/neorv32/blob/master/docs/riscv-privileged.pdf)
* subset of the *Privileged Architecture Specification* [(Version 1.12-draft)](https://github.com/stnolting/neorv32/blob/master/docs/riscv-spec.pdf)
* the [offcial RISC-V compliance tests](#Status) (*passing*)
* Configurable RISC-V-compliant CPU extensions
* [`A`](#Atomic-memory-access-a-extension) - atomic memory access instructions (optional)
* [`B`](#Bit-manipulation-instructions-B-extension) - Bit manipulation instructions (optional)
67,7 → 67,7
* bootloader with UART interface console
* runtime environment
* several example programs
* [doxygen-based](https://github.com/stnolting/neorv32/blob/master/docs/doxygen_makefile_sw) documentation: available on [GitHub pages](https://stnolting.github.io/neorv32/files.html)
* [doxygen-based](https://github.com/stnolting/neorv32/blob/master/docs/doxygen_makefile_sw) software documentation: available on [GitHub pages](https://stnolting.github.io/neorv32/files.html)
* [FreeRTOS port](https://github.com/stnolting/neorv32/blob/master/sw/example/demo_freeRTOS) available
* [**Full-blown data sheet**](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/NEORV32.pdf) (pdf)
* Completely described in behavioral, platform-independent VHDL - no primitives, macros, etc.
98,7 → 98,7
| Project component | CI status |
|:----------------- |:----------|
| [NEORV32 processor](https://github.com/stnolting/neorv32) | [![Processor Check](https://github.com/stnolting/neorv32/workflows/Processor%20Check/badge.svg)](https://github.com/stnolting/neorv32/actions?query=workflow%3A%22Processor+Check%22) |
| [SW Framework Documentation (online)](https://stnolting.github.io/neorv32/files.html) | [![Doc@GitHub-pages](https://github.com/stnolting/neorv32/workflows/Deploy%20SW%20Framework%20Documentation%20to%20GitHub-Pages/badge.svg)](https://stnolting.github.io/neorv32/files.html) |
| [SW Framework Documentation (online @GH-pages)](https://stnolting.github.io/neorv32/files.html) | [![Doc@GitHub-pages](https://github.com/stnolting/neorv32/workflows/Deploy%20SW%20Framework%20Documentation%20to%20GitHub-Pages/badge.svg)](https://stnolting.github.io/neorv32/files.html) |
| [Pre-built toolchains](https://github.com/stnolting/riscv-gcc-prebuilt) | [![Test Toolchains](https://github.com/stnolting/riscv-gcc-prebuilt/workflows/Test%20Toolchains/badge.svg)](https://github.com/stnolting/riscv-gcc-prebuilt/actions?query=workflow%3A%22Test+Toolchains%22) |
| [RISC-V compliance test](https://github.com/stnolting/neorv32/blob/master/riscv-compliance/README.md) | [![RISC-V Compliance](https://github.com/stnolting/neorv32/workflows/RISC-V%20Compliance/badge.svg)](https://github.com/stnolting/neorv32/actions?query=workflow%3A%22RISC-V+Compliance%22) |
 
112,8 → 112,8
* Add data cache?
* Burst mode for the external memory/bus interface?
* RISC-V `F` (using [`Zfinx`](https://github.com/riscv/riscv-zfinx/blob/master/Zfinx_spec.adoc)?) CPU extension (single-precision floating point)
* Add template (HW module + intrinsics skeleton) for custom instructions?
* Implement further RISC-V (or custom) CPU extensions?
* Add template (HW module + SW intrinsics skeleton) for custom instructions?
* Implement further RISC-V CPU extensions?
* More support for FreeRTOS (like *all* traps)?
* Port additional RTOSs (like [Zephyr](https://github.com/zephyrproject-rtos/zephyr) or [RIOT](https://www.riot-os.org))?
* Add debugger ([RISC-V debug spec](https://github.com/riscv/riscv-debug-spec))?
149,6 → 149,7
* PWM controller with 4 channels and 8-bit duty cycle resolution (**PWM**)
* ring-oscillator-based true random number generator (**TRNG**)
* custom functions subsystem (**CFS**) for tightly-coupled custom co-processor extensions
* numerically-controlled oscillator (**NCO**) with three independent channels
* system configuration information memory to check hardware configuration by software (**SYSINFO**, mandatory - not *optional*)
 
 
297,30 → 298,33
a DE0-nano board. The design was synthesized using **Intel Quartus Prime Lite 20.1** ("balanced implementation"). The timing
information is derived from the Timing Analyzer / Slow 1200mV 0C Model. If not otherwise specified, the default configuration
of the CPU's generics is assumed (e.g. no physical memory protection, no hardware performance monitors).
No constraints were used at all. The `u` and `Zifencei` extensions have a negligible impact on the hardware requirements.
No constraints were used at all.
 
Results generated for hardware version [`1.5.0.3`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md).
Results generated for hardware version [`1.5.1.4`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md).
 
| CPU Configuration | LEs | FFs | Memory bits | DSPs | f_max |
|:-----------------------------------------|:----------:|:--------:|:-----------:|:----:|:-------:|
| `rv32i` | 1190 | 512 | 1024 | 0 | 120 MHz |
| `rv32i` + `u` + `Zicsr` + `Zifencei` | 1927 | 903 | 1024 | 0 | 123 MHz |
| `rv32im` + `u` + `Zicsr` + `Zifencei` | 2471 | 1148 | 1024 | 0 | 120 MHz |
| `rv32imc` + `u` + `Zicsr` + `Zifencei` | 2716 | 1165 | 1024 | 0 | 120 MHz |
| `rv32imac` + `u` + `Zicsr` + `Zifencei` | 2736 | 1168 | 1024 | 0 | 120 MHz |
| `rv32imacb` + `u` + `Zicsr` + `Zifencei` | 3045 | 1260 | 1024 | 0 | 116 MHz |
| `rv32i` | 979 | 409 | 1024 | 0 | 123 MHz |
| `rv32i` + `Zicsr` | 1789 | 847 | 1024 | 0 | 122 MHz |
| `rv32im` + `Zicsr` | 2381 | 1125 | 1024 | 0 | 122 MHz |
| `rv32imc` + `Zicsr` | 2608 | 1140 | 1024 | 0 | 122 MHz |
| `rv32imac` + `Zicsr` | 2621 | 1144 | 1024 | 0 | 122 MHz |
| `rv32imacb` + `Zicsr` | 3013 | 1310 | 1024 | 0 | 122 MHz |
| `rv32imacb` + `Zicsr` + `u` | 3031 | 1313 | 1024 | 0 | 122 MHz |
| `rv32imacb` + `Zicsr` + `u` + `Zifencei` | 3050 | 1313 | 1024 | 0 | 116 MHz |
 
Setups with enabled "embedded CPU extension" `E` show the same LUT and FF utilization and identical f_max. However, the size of the register file is cut in half.
Setups with enabled "embedded CPU extension" `E` show the same LUT and FF utilization and identical f_max as the according `I` configuration.
However, the size of the register file is cut in half.
 
 
### NEORV32 Processor-Internal Peripherals and Memories
 
Results generated for hardware version [`1.5.0.3`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md).
Results generated for hardware version [`1.5.1.4`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md).
 
| Module | Description | LEs | FFs | Memory bits | DSPs |
|:----------|:-----------------------------------------------------|----:|----:|------------:|-----:|
| BOOT ROM | Bootloader ROM (default 4kB) | 3 | 1 | 32 768 | 0 |
| BUSSWITCH | Mux for CPU I & D interfaces | 65 | 8 | 0 | 0 |
| BUSSWITCH | Bus mux for CPU instr. & data interfaces | 65 | 8 | 0 | 0 |
| i-CACHE | Proc.-int. nstruction cache (default 1x4x64 bytes) | 234 | 156 | 8 192 | 0 |
| CFS | Custom functions subsystem | - | - | - | - |
| DMEM | Processor-internal data memory (default 8kB) | 6 | 2 | 65 536 | 0 |
327,6 → 331,7
| GPIO | General purpose input/output ports | 67 | 65 | 0 | 0 |
| IMEM | Processor-internal instruction memory (default 16kb) | 6 | 2 | 131 072 | 0 |
| MTIME | Machine system timer | 274 | 166 | 0 | 0 |
| NCO | Numerically-controlled oscillator | 254 | 226 | 0 | 0 |
| PWM | Pulse-width modulation controller | 71 | 69 | 0 | 0 |
| SPI | Serial peripheral interface | 138 | 124 | 0 | 0 |
| SYSINFO | System configuration information memory | 11 | 10 | 0 | 0 |

powered by: WebSVN 2.1.0

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