URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 48 to Rev 49
- ↔ Reverse comparison
Rev 48 → Rev 49
/neorv32/trunk/docs/figures/neorv32_processor.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/neorv32/trunk/docs/NEORV32.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/neorv32/trunk/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`. |
/neorv32/trunk/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", |
/neorv32/trunk/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 -- |
/neorv32/trunk/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 |
/neorv32/trunk/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 ------------------------------------------------------------------------- |
/neorv32/trunk/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 => |
/neorv32/trunk/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; |
/neorv32/trunk/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)))); |
/neorv32/trunk/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; |
/neorv32/trunk/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 -- |
/neorv32/trunk/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) |
/neorv32/trunk/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 -- |
/neorv32/trunk/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 -- |
/neorv32/trunk/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; |
/neorv32/trunk/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); |
/neorv32/trunk/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 |
/neorv32/trunk/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> |
/neorv32/trunk/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 -- |
/neorv32/trunk/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; |
} |
|
/neorv32/trunk/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) |
/neorv32/trunk/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" |
/neorv32/trunk/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 |
/neorv32/trunk/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; |
} |
} |
/neorv32/trunk/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)); |
} |
|
|
/neorv32/trunk/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 | |
/neorv32/trunk/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) |
/neorv32/trunk/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 | |