Initial commit
This commit is contained in:
34
Libs/RiscV/NEORV32/rtl/README.md
Normal file
34
Libs/RiscV/NEORV32/rtl/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
## VHDL Source Folders
|
||||
|
||||
|
||||
### [`core`](https://github.com/stnolting/neorv32/tree/master/rtl/core)
|
||||
|
||||
This folder contains the core VHDL files for the NEORV32 CPU and the NEORV32 Processor.
|
||||
When creating a new synthesis/simulation project make sure that all `*.vhd` files from this folder are added to a
|
||||
*new design library* called `neorv32`.
|
||||
|
||||
:warning: The sub-folder [`core/mem`](https://github.com/stnolting/neorv32/tree/master/rtl/core/mem)
|
||||
contains the _platform-agnostic_ VHDL architectures of the processor-internal memories.
|
||||
You can _replace_ inclusion of these files by platform-optimized memory architectures.
|
||||
|
||||
|
||||
### [`processor_templates`](https://github.com/stnolting/neorv32/tree/master/rtl/processor_templates`)
|
||||
|
||||
Contains pre-configured "SoC" templates that instantiate the processor's top entity from `core`.
|
||||
These templates can be instantiated directly within a FPGA-specific board wrapper.
|
||||
|
||||
|
||||
### [`system_integration`](https://github.com/stnolting/neorv32/tree/master/rtl/system_integration`)
|
||||
|
||||
Top entities in this folder provide the same peripheral/IO signals and configuration generics as the default
|
||||
processor top entity from `core`, but feature a different interface type.
|
||||
For example: an **AXI4-Lite**-compatible bus interface instead of the default Wishbone bus interface
|
||||
or a top entity with _resolved_ port signal types.
|
||||
|
||||
|
||||
### [`test_setups`](https://github.com/stnolting/neorv32/tree/master/rtl/test_setups`)
|
||||
|
||||
Minimal test setups (FPGA- and board-independent) for the processor. See the
|
||||
[README](https://github.com/stnolting/neorv32/tree/master/rtl/test_setups)
|
||||
in that folder for more information. Note that these test setups are used in the
|
||||
[NEORV32 USer Guide](https://stnolting.github.io/neorv32/ug).
|
14
Libs/RiscV/NEORV32/rtl/core/mem/README.md
Normal file
14
Libs/RiscV/NEORV32/rtl/core/mem/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Processor Memory Source Files
|
||||
|
||||
This folder provides the architecture-only VHDL sources for the processor-internal memories
|
||||
(instruction memory "IMEM", data memory "DMEM"). Different implementations are available - but
|
||||
only **one** version of each (IMEM and DMEM) has to be added as actual source files.
|
||||
|
||||
For the first implementation the `*.default.vhd` files should be selected. The HDL style for describing
|
||||
memories used by these files has proven **platform-independence** across several FPGA architectures and toolchains.
|
||||
|
||||
If synthesis fails to infer actual block RAM resources from these default files, try the legacy `*.cyclone2.vhd` files, which
|
||||
provide a different HDL style. These files are intended for legacy support of older Intel/Altera Quartus versions (13.0 and older). However,
|
||||
these files do **not** use platform-specific macros or primitives - so they might also work for other FPGAs and toolchains.
|
||||
|
||||
:warning: Make sure to add the selected files from this folder also to the `neorv32` design library.
|
130
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_dmem.cyclone2.vhd
Normal file
130
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_dmem.cyclone2.vhd
Normal file
@ -0,0 +1,130 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-internal data memory (DMEM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
|
||||
architecture neorv32_dmem_rtl of neorv32_dmem is
|
||||
|
||||
-- IO space: module base address --
|
||||
constant hi_abb_c : natural := 31; -- high address boundary bit
|
||||
constant lo_abb_c : natural := index_size_f(DMEM_SIZE); -- low address boundary bit
|
||||
|
||||
-- local signals --
|
||||
signal acc_en : std_ulogic;
|
||||
signal rdata : std_ulogic_vector(31 downto 0);
|
||||
signal rden : std_ulogic;
|
||||
signal addr : std_ulogic_vector(index_size_f(DMEM_SIZE/4)-1 downto 0);
|
||||
signal addr_ff : std_ulogic_vector(index_size_f(DMEM_SIZE/4)-1 downto 0);
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
-- The memory (RAM) is built from 4 individual byte-wide memories b0..b3, since some synthesis tools have --
|
||||
-- problems with 32-bit memories that provide dedicated byte-enable signals AND/OR with multi-dimensional arrays. --
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
|
||||
-- RAM - not initialized at all --
|
||||
signal mem_ram_b0 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
signal mem_ram_b1 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
signal mem_ram_b2 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
signal mem_ram_b3 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
|
||||
-- read data --
|
||||
signal mem_ram_b0_rd, mem_ram_b1_rd, mem_ram_b2_rd, mem_ram_b3_rd : std_ulogic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using CYCLONE-2-optimized HDL style DMEM." severity note;
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, " & natural'image(DMEM_SIZE) & " bytes)." severity note;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= addr_i(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned
|
||||
|
||||
|
||||
-- Memory Access --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
mem_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
addr_ff <= addr;
|
||||
if (acc_en = '1') then -- reduce switching activity when not accessed
|
||||
if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0
|
||||
mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00);
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1
|
||||
mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08);
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2
|
||||
mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16);
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3
|
||||
mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process mem_access;
|
||||
|
||||
-- sync(!) read - alternative HDL style --
|
||||
mem_ram_b0_rd <= mem_ram_b0(to_integer(unsigned(addr_ff)));
|
||||
mem_ram_b1_rd <= mem_ram_b1(to_integer(unsigned(addr_ff)));
|
||||
mem_ram_b2_rd <= mem_ram_b2(to_integer(unsigned(addr_ff)));
|
||||
mem_ram_b3_rd <= mem_ram_b3(to_integer(unsigned(addr_ff)));
|
||||
|
||||
|
||||
-- Bus Feedback ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
bus_feedback: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
rden <= acc_en and rden_i;
|
||||
ack_o <= acc_en and (rden_i or wren_i);
|
||||
end if;
|
||||
end process bus_feedback;
|
||||
|
||||
-- pack --
|
||||
rdata <= mem_ram_b3_rd & mem_ram_b2_rd & mem_ram_b1_rd & mem_ram_b0_rd;
|
||||
|
||||
-- output gate --
|
||||
data_o <= rdata when (rden = '1') else (others => '0');
|
||||
|
||||
|
||||
end neorv32_dmem_rtl;
|
132
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_dmem.default.vhd
Normal file
132
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_dmem.default.vhd
Normal file
@ -0,0 +1,132 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-internal data memory (DMEM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
|
||||
architecture neorv32_dmem_rtl of neorv32_dmem is
|
||||
|
||||
-- IO space: module base address --
|
||||
constant hi_abb_c : natural := 31; -- high address boundary bit
|
||||
constant lo_abb_c : natural := index_size_f(DMEM_SIZE); -- low address boundary bit
|
||||
|
||||
-- local signals --
|
||||
signal acc_en : std_ulogic;
|
||||
signal rdata : std_ulogic_vector(31 downto 0);
|
||||
signal rden : std_ulogic;
|
||||
signal addr : std_ulogic_vector(index_size_f(DMEM_SIZE/4)-1 downto 0);
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
-- The memory (RAM) is built from 4 individual byte-wide memories b0..b3, since some synthesis tools have --
|
||||
-- problems with 32-bit memories that provide dedicated byte-enable signals AND/OR with multi-dimensional arrays. --
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
|
||||
-- RAM - not initialized at all --
|
||||
signal mem_ram_b0 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
signal mem_ram_b1 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
signal mem_ram_b2 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
signal mem_ram_b3 : mem8_t(0 to DMEM_SIZE/4-1);
|
||||
|
||||
-- read data --
|
||||
signal mem_ram_b0_rd, mem_ram_b1_rd, mem_ram_b2_rd, mem_ram_b3_rd : std_ulogic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using DEFAULT platform-agnostic DMEM." severity note;
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, " & natural'image(DMEM_SIZE) & " bytes)." severity note;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= addr_i(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned
|
||||
|
||||
|
||||
-- Memory Access --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
mem_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- this RAM style should not require "no_rw_check" attributes as the read-after-write behavior
|
||||
-- is intended to be defined implicitly via the if-WRITE-else-READ construct
|
||||
if (acc_en = '1') then -- reduce switching activity when not accessed
|
||||
if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0
|
||||
mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00);
|
||||
else
|
||||
mem_ram_b0_rd <= mem_ram_b0(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1
|
||||
mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08);
|
||||
else
|
||||
mem_ram_b1_rd <= mem_ram_b1(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2
|
||||
mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16);
|
||||
else
|
||||
mem_ram_b2_rd <= mem_ram_b2(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3
|
||||
mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24);
|
||||
else
|
||||
mem_ram_b3_rd <= mem_ram_b3(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process mem_access;
|
||||
|
||||
|
||||
-- Bus Feedback ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
bus_feedback: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
rden <= acc_en and rden_i;
|
||||
ack_o <= acc_en and (rden_i or wren_i);
|
||||
end if;
|
||||
end process bus_feedback;
|
||||
|
||||
-- pack --
|
||||
rdata <= mem_ram_b3_rd & mem_ram_b2_rd & mem_ram_b1_rd & mem_ram_b0_rd;
|
||||
|
||||
-- output gate --
|
||||
data_o <= rdata when (rden = '1') else (others => '0');
|
||||
|
||||
|
||||
end neorv32_dmem_rtl;
|
176
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_imem.cyclone2.vhd
Normal file
176
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_imem.cyclone2.vhd
Normal file
@ -0,0 +1,176 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-internal instruction memory (IMEM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This memory optionally includes the in-place executable image of the application. See the #
|
||||
-- # processor's documentary to get more information. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
use neorv32.neorv32_application_image.all; -- this file is generated by the image generator
|
||||
|
||||
architecture neorv32_imem_rtl of neorv32_imem is
|
||||
|
||||
-- IO space: module base address --
|
||||
constant hi_abb_c : natural := 31; -- high address boundary bit
|
||||
constant lo_abb_c : natural := index_size_f(IMEM_SIZE); -- low address boundary bit
|
||||
|
||||
-- local signals --
|
||||
signal acc_en : std_ulogic;
|
||||
signal rdata : std_ulogic_vector(31 downto 0);
|
||||
signal rden : std_ulogic;
|
||||
signal addr : std_ulogic_vector(index_size_f(IMEM_SIZE/4)-1 downto 0);
|
||||
signal addr_ff : std_ulogic_vector(index_size_f(IMEM_SIZE/4)-1 downto 0);
|
||||
|
||||
-- --------------------------- --
|
||||
-- IMEM as pre-initialized ROM --
|
||||
-- --------------------------- --
|
||||
|
||||
-- application (image) size in bytes --
|
||||
constant imem_app_size_c : natural := (application_init_image'length)*4;
|
||||
|
||||
-- ROM - initialized with executable code --
|
||||
constant mem_rom : mem32_t(0 to IMEM_SIZE/4-1) := mem32_init_f(application_init_image, IMEM_SIZE/4);
|
||||
|
||||
-- read data --
|
||||
signal mem_rom_rd : std_ulogic_vector(31 downto 0);
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
-- The memory (RAM) is built from 4 individual byte-wide memories b0..b3, since some synthesis tools have --
|
||||
-- problems with 32-bit memories that provide dedicated byte-enable signals AND/OR with multi-dimensional arrays. --
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
|
||||
-- RAM - not initialized at all --
|
||||
signal mem_ram_b0 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
signal mem_ram_b1 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
signal mem_ram_b2 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
signal mem_ram_b3 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
|
||||
-- read data --
|
||||
signal mem_b0_rd, mem_b1_rd, mem_b2_rd, mem_b3_rd : std_ulogic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using CYCLONE-2-optimized HDL style IMEM." severity note;
|
||||
assert not (IMEM_AS_IROM = true) report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (" & natural'image(IMEM_SIZE) &
|
||||
" bytes), pre-initialized with application (" & natural'image(imem_app_size_c) & " bytes)." severity note;
|
||||
--
|
||||
assert not (IMEM_AS_IROM = false) report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as blank RAM (" & natural'image(IMEM_SIZE) &
|
||||
" bytes)." severity note;
|
||||
--
|
||||
assert not ((IMEM_AS_IROM = true) and (imem_app_size_c > IMEM_SIZE)) report "NEORV32 PROCESSOR CONFIG ERROR: Application (image = " & natural'image(imem_app_size_c) &
|
||||
" bytes) does not fit into processor-internal IMEM (ROM = " & natural'image(IMEM_SIZE) & " bytes)!" severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= addr_i(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned
|
||||
|
||||
|
||||
-- Implement IMEM as pre-initialized ROM --------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
imem_rom:
|
||||
if (IMEM_AS_IROM = true) generate
|
||||
mem_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (acc_en = '1') then -- reduce switching activity when not accessed
|
||||
mem_rom_rd <= mem_rom(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
end if;
|
||||
end process mem_access;
|
||||
-- read data --
|
||||
rdata <= mem_rom_rd;
|
||||
end generate;
|
||||
|
||||
|
||||
-- Implement IMEM as not-initialized RAM --------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
imem_ram:
|
||||
if (IMEM_AS_IROM = false) generate
|
||||
mem_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
addr_ff <= addr;
|
||||
if (acc_en = '1') then -- reduce switching activity when not accessed
|
||||
if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0
|
||||
mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00);
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1
|
||||
mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08);
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2
|
||||
mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16);
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3
|
||||
mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process mem_access;
|
||||
-- sync(!) read - alternative HDL style --
|
||||
mem_b0_rd <= mem_ram_b0(to_integer(unsigned(addr_ff)));
|
||||
mem_b1_rd <= mem_ram_b1(to_integer(unsigned(addr_ff)));
|
||||
mem_b2_rd <= mem_ram_b2(to_integer(unsigned(addr_ff)));
|
||||
mem_b3_rd <= mem_ram_b3(to_integer(unsigned(addr_ff)));
|
||||
-- pack --
|
||||
rdata <= mem_b3_rd & mem_b2_rd & mem_b1_rd & mem_b0_rd;
|
||||
end generate;
|
||||
|
||||
|
||||
-- Bus Feedback ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
bus_feedback: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
rden <= acc_en and rden_i;
|
||||
if (IMEM_AS_IROM = true) then
|
||||
ack_o <= acc_en and rden_i;
|
||||
else
|
||||
ack_o <= acc_en and (rden_i or wren_i);
|
||||
end if;
|
||||
end if;
|
||||
end process bus_feedback;
|
||||
|
||||
-- output gate --
|
||||
data_o <= rdata when (rden = '1') else (others => '0');
|
||||
|
||||
|
||||
end neorv32_imem_rtl;
|
179
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_imem.default.vhd
Normal file
179
Libs/RiscV/NEORV32/rtl/core/mem/neorv32_imem.default.vhd
Normal file
@ -0,0 +1,179 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-internal instruction memory (IMEM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This memory optionally includes the in-place executable image of the application. See the #
|
||||
-- # processor's documentary to get more information. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
use neorv32.neorv32_application_image.all; -- this file is generated by the image generator
|
||||
|
||||
architecture neorv32_imem_rtl of neorv32_imem is
|
||||
|
||||
-- IO space: module base address --
|
||||
constant hi_abb_c : natural := 31; -- high address boundary bit
|
||||
constant lo_abb_c : natural := index_size_f(IMEM_SIZE); -- low address boundary bit
|
||||
|
||||
-- local signals --
|
||||
signal acc_en : std_ulogic;
|
||||
signal rdata : std_ulogic_vector(31 downto 0);
|
||||
signal rden : std_ulogic;
|
||||
signal addr : std_ulogic_vector(index_size_f(IMEM_SIZE/4)-1 downto 0);
|
||||
|
||||
-- --------------------------- --
|
||||
-- IMEM as pre-initialized ROM --
|
||||
-- --------------------------- --
|
||||
|
||||
-- application (image) size in bytes --
|
||||
constant imem_app_size_c : natural := (application_init_image'length)*4;
|
||||
|
||||
-- ROM - initialized with executable code --
|
||||
constant mem_rom : mem32_t(0 to IMEM_SIZE/4-1) := mem32_init_f(application_init_image, IMEM_SIZE/4);
|
||||
|
||||
-- read data --
|
||||
signal mem_rom_rd : std_ulogic_vector(31 downto 0);
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
-- The memory (RAM) is built from 4 individual byte-wide memories b0..b3, since some synthesis tools have --
|
||||
-- problems with 32-bit memories that provide dedicated byte-enable signals AND/OR with multi-dimensional arrays. --
|
||||
-- -------------------------------------------------------------------------------------------------------------- --
|
||||
|
||||
-- RAM - not initialized at all --
|
||||
signal mem_ram_b0 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
signal mem_ram_b1 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
signal mem_ram_b2 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
signal mem_ram_b3 : mem8_t(0 to IMEM_SIZE/4-1);
|
||||
|
||||
-- read data --
|
||||
signal mem_b0_rd, mem_b1_rd, mem_b2_rd, mem_b3_rd : std_ulogic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using DEFAULT platform-agnostic IMEM." severity note;
|
||||
assert not (IMEM_AS_IROM = true) report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (" & natural'image(IMEM_SIZE) &
|
||||
" bytes), pre-initialized with application (" & natural'image(imem_app_size_c) & " bytes)." severity note;
|
||||
--
|
||||
assert not (IMEM_AS_IROM = false) report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as blank RAM (" & natural'image(IMEM_SIZE) &
|
||||
" bytes)." severity note;
|
||||
--
|
||||
assert not ((IMEM_AS_IROM = true) and (imem_app_size_c > IMEM_SIZE)) report "NEORV32 PROCESSOR CONFIG ERROR: Application (image = " & natural'image(imem_app_size_c) &
|
||||
" bytes) does not fit into processor-internal IMEM (ROM = " & natural'image(IMEM_SIZE) & " bytes)!" severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= addr_i(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned
|
||||
|
||||
|
||||
-- Implement IMEM as pre-initialized ROM --------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
imem_rom:
|
||||
if (IMEM_AS_IROM = true) generate
|
||||
mem_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (acc_en = '1') then -- reduce switching activity when not accessed
|
||||
mem_rom_rd <= mem_rom(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
end if;
|
||||
end process mem_access;
|
||||
-- read data --
|
||||
rdata <= mem_rom_rd;
|
||||
end generate;
|
||||
|
||||
|
||||
-- Implement IMEM as not-initialized RAM --------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
imem_ram:
|
||||
if (IMEM_AS_IROM = false) generate
|
||||
mem_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- this RAM style should not require "no_rw_check" attributes as the read-after-write behavior
|
||||
-- is intended to be defined implicitly via the if-WRITE-else-READ construct
|
||||
if (acc_en = '1') then -- reduce switching activity when not accessed
|
||||
if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0
|
||||
mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00);
|
||||
else
|
||||
mem_b0_rd <= mem_ram_b0(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1
|
||||
mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08);
|
||||
else
|
||||
mem_b1_rd <= mem_ram_b1(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2
|
||||
mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16);
|
||||
else
|
||||
mem_b2_rd <= mem_ram_b2(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3
|
||||
mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24);
|
||||
else
|
||||
mem_b3_rd <= mem_ram_b3(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process mem_access;
|
||||
-- read data --
|
||||
rdata <= mem_b3_rd & mem_b2_rd & mem_b1_rd & mem_b0_rd;
|
||||
end generate;
|
||||
|
||||
|
||||
-- Bus Feedback ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
bus_feedback: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
rden <= acc_en and rden_i;
|
||||
if (IMEM_AS_IROM = true) then
|
||||
ack_o <= acc_en and rden_i;
|
||||
else
|
||||
ack_o <= acc_en and (rden_i or wren_i);
|
||||
end if;
|
||||
end if;
|
||||
end process bus_feedback;
|
||||
|
||||
-- output gate --
|
||||
data_o <= rdata when (rden = '1') else (others => '0');
|
||||
|
||||
|
||||
end neorv32_imem_rtl;
|
883
Libs/RiscV/NEORV32/rtl/core/neorv32_application_image.vhd
Normal file
883
Libs/RiscV/NEORV32/rtl/core/neorv32_application_image.vhd
Normal file
@ -0,0 +1,883 @@
|
||||
-- The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32
|
||||
-- Auto-generated memory init file (for APPLICATION) from source file <blink_led/main.bin>
|
||||
-- Size: 3468 bytes
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
library neorv32;
|
||||
use neorv32.neorv32_package.all;
|
||||
|
||||
package neorv32_application_image is
|
||||
|
||||
constant application_init_image : mem32_t := (
|
||||
00000000 => x"00000037",
|
||||
00000001 => x"80002117",
|
||||
00000002 => x"ff810113",
|
||||
00000003 => x"80000197",
|
||||
00000004 => x"7f418193",
|
||||
00000005 => x"00000517",
|
||||
00000006 => x"12050513",
|
||||
00000007 => x"30551073",
|
||||
00000008 => x"34151073",
|
||||
00000009 => x"30001073",
|
||||
00000010 => x"30401073",
|
||||
00000011 => x"30601073",
|
||||
00000012 => x"ffa00593",
|
||||
00000013 => x"32059073",
|
||||
00000014 => x"b0001073",
|
||||
00000015 => x"b8001073",
|
||||
00000016 => x"b0201073",
|
||||
00000017 => x"b8201073",
|
||||
00000018 => x"00000093",
|
||||
00000019 => x"00000213",
|
||||
00000020 => x"00000293",
|
||||
00000021 => x"00000313",
|
||||
00000022 => x"00000393",
|
||||
00000023 => x"00000713",
|
||||
00000024 => x"00000793",
|
||||
00000025 => x"00000813",
|
||||
00000026 => x"00000893",
|
||||
00000027 => x"00000913",
|
||||
00000028 => x"00000993",
|
||||
00000029 => x"00000a13",
|
||||
00000030 => x"00000a93",
|
||||
00000031 => x"00000b13",
|
||||
00000032 => x"00000b93",
|
||||
00000033 => x"00000c13",
|
||||
00000034 => x"00000c93",
|
||||
00000035 => x"00000d13",
|
||||
00000036 => x"00000d93",
|
||||
00000037 => x"00000e13",
|
||||
00000038 => x"00000e93",
|
||||
00000039 => x"00000f13",
|
||||
00000040 => x"00000f93",
|
||||
00000041 => x"00000417",
|
||||
00000042 => x"d5c40413",
|
||||
00000043 => x"00000497",
|
||||
00000044 => x"f5448493",
|
||||
00000045 => x"00042023",
|
||||
00000046 => x"00440413",
|
||||
00000047 => x"fe941ce3",
|
||||
00000048 => x"80000597",
|
||||
00000049 => x"f4058593",
|
||||
00000050 => x"87418613",
|
||||
00000051 => x"00c5d863",
|
||||
00000052 => x"00058023",
|
||||
00000053 => x"00158593",
|
||||
00000054 => x"ff5ff06f",
|
||||
00000055 => x"00001597",
|
||||
00000056 => x"cb058593",
|
||||
00000057 => x"80000617",
|
||||
00000058 => x"f1c60613",
|
||||
00000059 => x"80000697",
|
||||
00000060 => x"f1468693",
|
||||
00000061 => x"00d65c63",
|
||||
00000062 => x"00058703",
|
||||
00000063 => x"00e60023",
|
||||
00000064 => x"00158593",
|
||||
00000065 => x"00160613",
|
||||
00000066 => x"fedff06f",
|
||||
00000067 => x"00000513",
|
||||
00000068 => x"00000593",
|
||||
00000069 => x"06c000ef",
|
||||
00000070 => x"34051073",
|
||||
00000071 => x"00000093",
|
||||
00000072 => x"00008463",
|
||||
00000073 => x"000080e7",
|
||||
00000074 => x"30047073",
|
||||
00000075 => x"10500073",
|
||||
00000076 => x"ffdff06f",
|
||||
00000077 => x"ff810113",
|
||||
00000078 => x"00812023",
|
||||
00000079 => x"00912223",
|
||||
00000080 => x"34202473",
|
||||
00000081 => x"02044663",
|
||||
00000082 => x"34102473",
|
||||
00000083 => x"00041483",
|
||||
00000084 => x"0034f493",
|
||||
00000085 => x"00240413",
|
||||
00000086 => x"34141073",
|
||||
00000087 => x"00300413",
|
||||
00000088 => x"00941863",
|
||||
00000089 => x"34102473",
|
||||
00000090 => x"00240413",
|
||||
00000091 => x"34141073",
|
||||
00000092 => x"00012403",
|
||||
00000093 => x"00412483",
|
||||
00000094 => x"00810113",
|
||||
00000095 => x"30200073",
|
||||
00000096 => x"00005537",
|
||||
00000097 => x"ff010113",
|
||||
00000098 => x"00000613",
|
||||
00000099 => x"00000593",
|
||||
00000100 => x"b0050513",
|
||||
00000101 => x"00112623",
|
||||
00000102 => x"088000ef",
|
||||
00000103 => x"780000ef",
|
||||
00000104 => x"00050c63",
|
||||
00000105 => x"730000ef",
|
||||
00000106 => x"00001537",
|
||||
00000107 => x"ac850513",
|
||||
00000108 => x"134000ef",
|
||||
00000109 => x"020000ef",
|
||||
00000110 => x"00001537",
|
||||
00000111 => x"aa450513",
|
||||
00000112 => x"124000ef",
|
||||
00000113 => x"00c12083",
|
||||
00000114 => x"00100513",
|
||||
00000115 => x"01010113",
|
||||
00000116 => x"00008067",
|
||||
00000117 => x"ff010113",
|
||||
00000118 => x"00000513",
|
||||
00000119 => x"00000593",
|
||||
00000120 => x"00112623",
|
||||
00000121 => x"00812423",
|
||||
00000122 => x"744000ef",
|
||||
00000123 => x"00000513",
|
||||
00000124 => x"00150413",
|
||||
00000125 => x"00000593",
|
||||
00000126 => x"0ff57513",
|
||||
00000127 => x"730000ef",
|
||||
00000128 => x"0c800513",
|
||||
00000129 => x"164000ef",
|
||||
00000130 => x"00040513",
|
||||
00000131 => x"fe5ff06f",
|
||||
00000132 => x"fe802503",
|
||||
00000133 => x"01255513",
|
||||
00000134 => x"00157513",
|
||||
00000135 => x"00008067",
|
||||
00000136 => x"ff010113",
|
||||
00000137 => x"00812423",
|
||||
00000138 => x"00912223",
|
||||
00000139 => x"00112623",
|
||||
00000140 => x"fa002023",
|
||||
00000141 => x"fe002783",
|
||||
00000142 => x"00058413",
|
||||
00000143 => x"00151593",
|
||||
00000144 => x"00078513",
|
||||
00000145 => x"00060493",
|
||||
00000146 => x"7b0000ef",
|
||||
00000147 => x"01051513",
|
||||
00000148 => x"000017b7",
|
||||
00000149 => x"01055513",
|
||||
00000150 => x"00000713",
|
||||
00000151 => x"ffe78793",
|
||||
00000152 => x"04a7e463",
|
||||
00000153 => x"0034f793",
|
||||
00000154 => x"00347413",
|
||||
00000155 => x"fff50513",
|
||||
00000156 => x"01479793",
|
||||
00000157 => x"01641413",
|
||||
00000158 => x"00f567b3",
|
||||
00000159 => x"0087e7b3",
|
||||
00000160 => x"01871713",
|
||||
00000161 => x"00c12083",
|
||||
00000162 => x"00812403",
|
||||
00000163 => x"00e7e7b3",
|
||||
00000164 => x"10000737",
|
||||
00000165 => x"00e7e7b3",
|
||||
00000166 => x"faf02023",
|
||||
00000167 => x"00412483",
|
||||
00000168 => x"01010113",
|
||||
00000169 => x"00008067",
|
||||
00000170 => x"ffe70693",
|
||||
00000171 => x"0fd6f693",
|
||||
00000172 => x"00069a63",
|
||||
00000173 => x"00355513",
|
||||
00000174 => x"00170713",
|
||||
00000175 => x"0ff77713",
|
||||
00000176 => x"fa1ff06f",
|
||||
00000177 => x"00155513",
|
||||
00000178 => x"ff1ff06f",
|
||||
00000179 => x"00040737",
|
||||
00000180 => x"fa002783",
|
||||
00000181 => x"00e7f7b3",
|
||||
00000182 => x"fe079ce3",
|
||||
00000183 => x"faa02223",
|
||||
00000184 => x"00008067",
|
||||
00000185 => x"ff010113",
|
||||
00000186 => x"00812423",
|
||||
00000187 => x"01212023",
|
||||
00000188 => x"00112623",
|
||||
00000189 => x"00912223",
|
||||
00000190 => x"00050413",
|
||||
00000191 => x"00a00913",
|
||||
00000192 => x"00044483",
|
||||
00000193 => x"00140413",
|
||||
00000194 => x"00049e63",
|
||||
00000195 => x"00c12083",
|
||||
00000196 => x"00812403",
|
||||
00000197 => x"00412483",
|
||||
00000198 => x"00012903",
|
||||
00000199 => x"01010113",
|
||||
00000200 => x"00008067",
|
||||
00000201 => x"01249663",
|
||||
00000202 => x"00d00513",
|
||||
00000203 => x"fa1ff0ef",
|
||||
00000204 => x"00048513",
|
||||
00000205 => x"f99ff0ef",
|
||||
00000206 => x"fc9ff06f",
|
||||
00000207 => x"ff010113",
|
||||
00000208 => x"c81026f3",
|
||||
00000209 => x"c0102773",
|
||||
00000210 => x"c81027f3",
|
||||
00000211 => x"fed79ae3",
|
||||
00000212 => x"00e12023",
|
||||
00000213 => x"00f12223",
|
||||
00000214 => x"00012503",
|
||||
00000215 => x"00412583",
|
||||
00000216 => x"01010113",
|
||||
00000217 => x"00008067",
|
||||
00000218 => x"fd010113",
|
||||
00000219 => x"00a12623",
|
||||
00000220 => x"fe002503",
|
||||
00000221 => x"3e800593",
|
||||
00000222 => x"02112623",
|
||||
00000223 => x"02812423",
|
||||
00000224 => x"02912223",
|
||||
00000225 => x"03212023",
|
||||
00000226 => x"01312e23",
|
||||
00000227 => x"66c000ef",
|
||||
00000228 => x"00c12603",
|
||||
00000229 => x"00000693",
|
||||
00000230 => x"00000593",
|
||||
00000231 => x"5c4000ef",
|
||||
00000232 => x"00050413",
|
||||
00000233 => x"00058993",
|
||||
00000234 => x"f95ff0ef",
|
||||
00000235 => x"00058913",
|
||||
00000236 => x"00050493",
|
||||
00000237 => x"f89ff0ef",
|
||||
00000238 => x"00b96663",
|
||||
00000239 => x"05259263",
|
||||
00000240 => x"04a4f063",
|
||||
00000241 => x"008484b3",
|
||||
00000242 => x"0084b433",
|
||||
00000243 => x"01390933",
|
||||
00000244 => x"01240433",
|
||||
00000245 => x"f69ff0ef",
|
||||
00000246 => x"fe85eee3",
|
||||
00000247 => x"00b41463",
|
||||
00000248 => x"fe956ae3",
|
||||
00000249 => x"02c12083",
|
||||
00000250 => x"02812403",
|
||||
00000251 => x"02412483",
|
||||
00000252 => x"02012903",
|
||||
00000253 => x"01c12983",
|
||||
00000254 => x"03010113",
|
||||
00000255 => x"00008067",
|
||||
00000256 => x"01c99913",
|
||||
00000257 => x"00445413",
|
||||
00000258 => x"00896433",
|
||||
00000259 => x"00040a63",
|
||||
00000260 => x"00040863",
|
||||
00000261 => x"fff40413",
|
||||
00000262 => x"00000013",
|
||||
00000263 => x"ff1ff06f",
|
||||
00000264 => x"fc5ff06f",
|
||||
00000265 => x"00000000",
|
||||
00000266 => x"00000000",
|
||||
00000267 => x"00000000",
|
||||
00000268 => x"fc010113",
|
||||
00000269 => x"02112e23",
|
||||
00000270 => x"02512c23",
|
||||
00000271 => x"02612a23",
|
||||
00000272 => x"02712823",
|
||||
00000273 => x"02a12623",
|
||||
00000274 => x"02b12423",
|
||||
00000275 => x"02c12223",
|
||||
00000276 => x"02d12023",
|
||||
00000277 => x"00e12e23",
|
||||
00000278 => x"00f12c23",
|
||||
00000279 => x"01012a23",
|
||||
00000280 => x"01112823",
|
||||
00000281 => x"01c12623",
|
||||
00000282 => x"01d12423",
|
||||
00000283 => x"01e12223",
|
||||
00000284 => x"01f12023",
|
||||
00000285 => x"34102773",
|
||||
00000286 => x"34071073",
|
||||
00000287 => x"342027f3",
|
||||
00000288 => x"0807c863",
|
||||
00000289 => x"00071683",
|
||||
00000290 => x"00300593",
|
||||
00000291 => x"0036f693",
|
||||
00000292 => x"00270613",
|
||||
00000293 => x"00b69463",
|
||||
00000294 => x"00470613",
|
||||
00000295 => x"34161073",
|
||||
00000296 => x"00b00713",
|
||||
00000297 => x"04f77a63",
|
||||
00000298 => x"6ac00793",
|
||||
00000299 => x"000780e7",
|
||||
00000300 => x"03c12083",
|
||||
00000301 => x"03812283",
|
||||
00000302 => x"03412303",
|
||||
00000303 => x"03012383",
|
||||
00000304 => x"02c12503",
|
||||
00000305 => x"02812583",
|
||||
00000306 => x"02412603",
|
||||
00000307 => x"02012683",
|
||||
00000308 => x"01c12703",
|
||||
00000309 => x"01812783",
|
||||
00000310 => x"01412803",
|
||||
00000311 => x"01012883",
|
||||
00000312 => x"00c12e03",
|
||||
00000313 => x"00812e83",
|
||||
00000314 => x"00412f03",
|
||||
00000315 => x"00012f83",
|
||||
00000316 => x"04010113",
|
||||
00000317 => x"30200073",
|
||||
00000318 => x"00001737",
|
||||
00000319 => x"00279793",
|
||||
00000320 => x"ae470713",
|
||||
00000321 => x"00e787b3",
|
||||
00000322 => x"0007a783",
|
||||
00000323 => x"00078067",
|
||||
00000324 => x"80000737",
|
||||
00000325 => x"ffd74713",
|
||||
00000326 => x"00e787b3",
|
||||
00000327 => x"01c00713",
|
||||
00000328 => x"f8f764e3",
|
||||
00000329 => x"00001737",
|
||||
00000330 => x"00279793",
|
||||
00000331 => x"b1470713",
|
||||
00000332 => x"00e787b3",
|
||||
00000333 => x"0007a783",
|
||||
00000334 => x"00078067",
|
||||
00000335 => x"800007b7",
|
||||
00000336 => x"0007a783",
|
||||
00000337 => x"f69ff06f",
|
||||
00000338 => x"800007b7",
|
||||
00000339 => x"0047a783",
|
||||
00000340 => x"f5dff06f",
|
||||
00000341 => x"800007b7",
|
||||
00000342 => x"0087a783",
|
||||
00000343 => x"f51ff06f",
|
||||
00000344 => x"800007b7",
|
||||
00000345 => x"00c7a783",
|
||||
00000346 => x"f45ff06f",
|
||||
00000347 => x"8101a783",
|
||||
00000348 => x"f3dff06f",
|
||||
00000349 => x"8141a783",
|
||||
00000350 => x"f35ff06f",
|
||||
00000351 => x"8181a783",
|
||||
00000352 => x"f2dff06f",
|
||||
00000353 => x"81c1a783",
|
||||
00000354 => x"f25ff06f",
|
||||
00000355 => x"8201a783",
|
||||
00000356 => x"f1dff06f",
|
||||
00000357 => x"8241a783",
|
||||
00000358 => x"f15ff06f",
|
||||
00000359 => x"8281a783",
|
||||
00000360 => x"f0dff06f",
|
||||
00000361 => x"82c1a783",
|
||||
00000362 => x"f05ff06f",
|
||||
00000363 => x"8301a783",
|
||||
00000364 => x"efdff06f",
|
||||
00000365 => x"8341a783",
|
||||
00000366 => x"ef5ff06f",
|
||||
00000367 => x"8381a783",
|
||||
00000368 => x"eedff06f",
|
||||
00000369 => x"83c1a783",
|
||||
00000370 => x"ee5ff06f",
|
||||
00000371 => x"8401a783",
|
||||
00000372 => x"eddff06f",
|
||||
00000373 => x"8441a783",
|
||||
00000374 => x"ed5ff06f",
|
||||
00000375 => x"8481a783",
|
||||
00000376 => x"ecdff06f",
|
||||
00000377 => x"84c1a783",
|
||||
00000378 => x"ec5ff06f",
|
||||
00000379 => x"8501a783",
|
||||
00000380 => x"ebdff06f",
|
||||
00000381 => x"8541a783",
|
||||
00000382 => x"eb5ff06f",
|
||||
00000383 => x"8581a783",
|
||||
00000384 => x"eadff06f",
|
||||
00000385 => x"85c1a783",
|
||||
00000386 => x"ea5ff06f",
|
||||
00000387 => x"8601a783",
|
||||
00000388 => x"e9dff06f",
|
||||
00000389 => x"8641a783",
|
||||
00000390 => x"e95ff06f",
|
||||
00000391 => x"8681a783",
|
||||
00000392 => x"e8dff06f",
|
||||
00000393 => x"86c1a783",
|
||||
00000394 => x"e85ff06f",
|
||||
00000395 => x"8701a783",
|
||||
00000396 => x"e7dff06f",
|
||||
00000397 => x"00000000",
|
||||
00000398 => x"00000000",
|
||||
00000399 => x"fe010113",
|
||||
00000400 => x"01212823",
|
||||
00000401 => x"00050913",
|
||||
00000402 => x"00001537",
|
||||
00000403 => x"00912a23",
|
||||
00000404 => x"b8850513",
|
||||
00000405 => x"000014b7",
|
||||
00000406 => x"00812c23",
|
||||
00000407 => x"01312623",
|
||||
00000408 => x"00112e23",
|
||||
00000409 => x"01c00413",
|
||||
00000410 => x"c7dff0ef",
|
||||
00000411 => x"d7c48493",
|
||||
00000412 => x"ffc00993",
|
||||
00000413 => x"008957b3",
|
||||
00000414 => x"00f7f793",
|
||||
00000415 => x"00f487b3",
|
||||
00000416 => x"0007c503",
|
||||
00000417 => x"ffc40413",
|
||||
00000418 => x"c45ff0ef",
|
||||
00000419 => x"ff3414e3",
|
||||
00000420 => x"01c12083",
|
||||
00000421 => x"01812403",
|
||||
00000422 => x"01412483",
|
||||
00000423 => x"01012903",
|
||||
00000424 => x"00c12983",
|
||||
00000425 => x"02010113",
|
||||
00000426 => x"00008067",
|
||||
00000427 => x"ff010113",
|
||||
00000428 => x"00112623",
|
||||
00000429 => x"00812423",
|
||||
00000430 => x"00912223",
|
||||
00000431 => x"b55ff0ef",
|
||||
00000432 => x"1c050863",
|
||||
00000433 => x"00001537",
|
||||
00000434 => x"b8c50513",
|
||||
00000435 => x"c19ff0ef",
|
||||
00000436 => x"34202473",
|
||||
00000437 => x"00900713",
|
||||
00000438 => x"00f47793",
|
||||
00000439 => x"03078493",
|
||||
00000440 => x"00f77463",
|
||||
00000441 => x"05778493",
|
||||
00000442 => x"00b00793",
|
||||
00000443 => x"0087ee63",
|
||||
00000444 => x"00001737",
|
||||
00000445 => x"00241793",
|
||||
00000446 => x"d4c70713",
|
||||
00000447 => x"00e787b3",
|
||||
00000448 => x"0007a783",
|
||||
00000449 => x"00078067",
|
||||
00000450 => x"800007b7",
|
||||
00000451 => x"00b78713",
|
||||
00000452 => x"14e40e63",
|
||||
00000453 => x"02876a63",
|
||||
00000454 => x"00378713",
|
||||
00000455 => x"12e40c63",
|
||||
00000456 => x"00778793",
|
||||
00000457 => x"12f40e63",
|
||||
00000458 => x"00001537",
|
||||
00000459 => x"cec50513",
|
||||
00000460 => x"bb5ff0ef",
|
||||
00000461 => x"00040513",
|
||||
00000462 => x"f05ff0ef",
|
||||
00000463 => x"00100793",
|
||||
00000464 => x"08f40c63",
|
||||
00000465 => x"0280006f",
|
||||
00000466 => x"ff07c793",
|
||||
00000467 => x"00f407b3",
|
||||
00000468 => x"00f00713",
|
||||
00000469 => x"fcf76ae3",
|
||||
00000470 => x"00001537",
|
||||
00000471 => x"cdc50513",
|
||||
00000472 => x"b85ff0ef",
|
||||
00000473 => x"00048513",
|
||||
00000474 => x"b65ff0ef",
|
||||
00000475 => x"ffd47413",
|
||||
00000476 => x"00500793",
|
||||
00000477 => x"06f40263",
|
||||
00000478 => x"00001537",
|
||||
00000479 => x"d3050513",
|
||||
00000480 => x"b65ff0ef",
|
||||
00000481 => x"34002573",
|
||||
00000482 => x"eb5ff0ef",
|
||||
00000483 => x"00001537",
|
||||
00000484 => x"d3850513",
|
||||
00000485 => x"b51ff0ef",
|
||||
00000486 => x"34302573",
|
||||
00000487 => x"ea1ff0ef",
|
||||
00000488 => x"00812403",
|
||||
00000489 => x"00c12083",
|
||||
00000490 => x"00412483",
|
||||
00000491 => x"00001537",
|
||||
00000492 => x"d4450513",
|
||||
00000493 => x"01010113",
|
||||
00000494 => x"b2dff06f",
|
||||
00000495 => x"00001537",
|
||||
00000496 => x"b9450513",
|
||||
00000497 => x"b21ff0ef",
|
||||
00000498 => x"fb1ff06f",
|
||||
00000499 => x"00001537",
|
||||
00000500 => x"bb450513",
|
||||
00000501 => x"b11ff0ef",
|
||||
00000502 => x"f7c02783",
|
||||
00000503 => x"0a07d463",
|
||||
00000504 => x"0017f793",
|
||||
00000505 => x"08078a63",
|
||||
00000506 => x"00001537",
|
||||
00000507 => x"d0450513",
|
||||
00000508 => x"fd5ff06f",
|
||||
00000509 => x"00001537",
|
||||
00000510 => x"bd050513",
|
||||
00000511 => x"fc9ff06f",
|
||||
00000512 => x"00001537",
|
||||
00000513 => x"be450513",
|
||||
00000514 => x"fbdff06f",
|
||||
00000515 => x"00001537",
|
||||
00000516 => x"bf050513",
|
||||
00000517 => x"fb1ff06f",
|
||||
00000518 => x"00001537",
|
||||
00000519 => x"c0850513",
|
||||
00000520 => x"fb5ff06f",
|
||||
00000521 => x"00001537",
|
||||
00000522 => x"c1c50513",
|
||||
00000523 => x"f99ff06f",
|
||||
00000524 => x"00001537",
|
||||
00000525 => x"c3850513",
|
||||
00000526 => x"f9dff06f",
|
||||
00000527 => x"00001537",
|
||||
00000528 => x"c4c50513",
|
||||
00000529 => x"f81ff06f",
|
||||
00000530 => x"00001537",
|
||||
00000531 => x"c6c50513",
|
||||
00000532 => x"f75ff06f",
|
||||
00000533 => x"00001537",
|
||||
00000534 => x"c8c50513",
|
||||
00000535 => x"f69ff06f",
|
||||
00000536 => x"00001537",
|
||||
00000537 => x"ca850513",
|
||||
00000538 => x"f5dff06f",
|
||||
00000539 => x"00001537",
|
||||
00000540 => x"cc050513",
|
||||
00000541 => x"f51ff06f",
|
||||
00000542 => x"00001537",
|
||||
00000543 => x"d1450513",
|
||||
00000544 => x"f45ff06f",
|
||||
00000545 => x"00001537",
|
||||
00000546 => x"d2450513",
|
||||
00000547 => x"f39ff06f",
|
||||
00000548 => x"00c12083",
|
||||
00000549 => x"00812403",
|
||||
00000550 => x"00412483",
|
||||
00000551 => x"01010113",
|
||||
00000552 => x"00008067",
|
||||
00000553 => x"01f00793",
|
||||
00000554 => x"02a7e263",
|
||||
00000555 => x"800007b7",
|
||||
00000556 => x"00078793",
|
||||
00000557 => x"00251513",
|
||||
00000558 => x"00a78533",
|
||||
00000559 => x"6ac00793",
|
||||
00000560 => x"00f52023",
|
||||
00000561 => x"00000513",
|
||||
00000562 => x"00008067",
|
||||
00000563 => x"00100513",
|
||||
00000564 => x"00008067",
|
||||
00000565 => x"ff010113",
|
||||
00000566 => x"00112623",
|
||||
00000567 => x"00812423",
|
||||
00000568 => x"00912223",
|
||||
00000569 => x"43000793",
|
||||
00000570 => x"30579073",
|
||||
00000571 => x"00000413",
|
||||
00000572 => x"01d00493",
|
||||
00000573 => x"00040513",
|
||||
00000574 => x"00140413",
|
||||
00000575 => x"0ff47413",
|
||||
00000576 => x"fa5ff0ef",
|
||||
00000577 => x"fe9418e3",
|
||||
00000578 => x"00c12083",
|
||||
00000579 => x"00812403",
|
||||
00000580 => x"00412483",
|
||||
00000581 => x"01010113",
|
||||
00000582 => x"00008067",
|
||||
00000583 => x"fe802503",
|
||||
00000584 => x"01055513",
|
||||
00000585 => x"00157513",
|
||||
00000586 => x"00008067",
|
||||
00000587 => x"fc000793",
|
||||
00000588 => x"00a7a423",
|
||||
00000589 => x"00b7a623",
|
||||
00000590 => x"00008067",
|
||||
00000591 => x"00050613",
|
||||
00000592 => x"00000513",
|
||||
00000593 => x"0015f693",
|
||||
00000594 => x"00068463",
|
||||
00000595 => x"00c50533",
|
||||
00000596 => x"0015d593",
|
||||
00000597 => x"00161613",
|
||||
00000598 => x"fe0596e3",
|
||||
00000599 => x"00008067",
|
||||
00000600 => x"00050313",
|
||||
00000601 => x"ff010113",
|
||||
00000602 => x"00060513",
|
||||
00000603 => x"00068893",
|
||||
00000604 => x"00112623",
|
||||
00000605 => x"00030613",
|
||||
00000606 => x"00050693",
|
||||
00000607 => x"00000713",
|
||||
00000608 => x"00000793",
|
||||
00000609 => x"00000813",
|
||||
00000610 => x"0016fe13",
|
||||
00000611 => x"00171e93",
|
||||
00000612 => x"000e0c63",
|
||||
00000613 => x"01060e33",
|
||||
00000614 => x"010e3833",
|
||||
00000615 => x"00e787b3",
|
||||
00000616 => x"00f807b3",
|
||||
00000617 => x"000e0813",
|
||||
00000618 => x"01f65713",
|
||||
00000619 => x"0016d693",
|
||||
00000620 => x"00eee733",
|
||||
00000621 => x"00161613",
|
||||
00000622 => x"fc0698e3",
|
||||
00000623 => x"00058663",
|
||||
00000624 => x"f7dff0ef",
|
||||
00000625 => x"00a787b3",
|
||||
00000626 => x"00088a63",
|
||||
00000627 => x"00030513",
|
||||
00000628 => x"00088593",
|
||||
00000629 => x"f69ff0ef",
|
||||
00000630 => x"00f507b3",
|
||||
00000631 => x"00c12083",
|
||||
00000632 => x"00080513",
|
||||
00000633 => x"00078593",
|
||||
00000634 => x"01010113",
|
||||
00000635 => x"00008067",
|
||||
00000636 => x"06054063",
|
||||
00000637 => x"0605c663",
|
||||
00000638 => x"00058613",
|
||||
00000639 => x"00050593",
|
||||
00000640 => x"fff00513",
|
||||
00000641 => x"02060c63",
|
||||
00000642 => x"00100693",
|
||||
00000643 => x"00b67a63",
|
||||
00000644 => x"00c05863",
|
||||
00000645 => x"00161613",
|
||||
00000646 => x"00169693",
|
||||
00000647 => x"feb66ae3",
|
||||
00000648 => x"00000513",
|
||||
00000649 => x"00c5e663",
|
||||
00000650 => x"40c585b3",
|
||||
00000651 => x"00d56533",
|
||||
00000652 => x"0016d693",
|
||||
00000653 => x"00165613",
|
||||
00000654 => x"fe0696e3",
|
||||
00000655 => x"00008067",
|
||||
00000656 => x"00008293",
|
||||
00000657 => x"fb5ff0ef",
|
||||
00000658 => x"00058513",
|
||||
00000659 => x"00028067",
|
||||
00000660 => x"40a00533",
|
||||
00000661 => x"00b04863",
|
||||
00000662 => x"40b005b3",
|
||||
00000663 => x"f9dff06f",
|
||||
00000664 => x"40b005b3",
|
||||
00000665 => x"00008293",
|
||||
00000666 => x"f91ff0ef",
|
||||
00000667 => x"40a00533",
|
||||
00000668 => x"00028067",
|
||||
00000669 => x"00008293",
|
||||
00000670 => x"0005ca63",
|
||||
00000671 => x"00054c63",
|
||||
00000672 => x"f79ff0ef",
|
||||
00000673 => x"00058513",
|
||||
00000674 => x"00028067",
|
||||
00000675 => x"40b005b3",
|
||||
00000676 => x"fe0558e3",
|
||||
00000677 => x"40a00533",
|
||||
00000678 => x"f61ff0ef",
|
||||
00000679 => x"40b00533",
|
||||
00000680 => x"00028067",
|
||||
00000681 => x"6f727245",
|
||||
00000682 => x"4e202172",
|
||||
00000683 => x"5047206f",
|
||||
00000684 => x"75204f49",
|
||||
00000685 => x"2074696e",
|
||||
00000686 => x"746e7973",
|
||||
00000687 => x"69736568",
|
||||
00000688 => x"2164657a",
|
||||
00000689 => x"0000000a",
|
||||
00000690 => x"6e696c42",
|
||||
00000691 => x"676e696b",
|
||||
00000692 => x"44454c20",
|
||||
00000693 => x"6d656420",
|
||||
00000694 => x"7270206f",
|
||||
00000695 => x"6172676f",
|
||||
00000696 => x"00000a6d",
|
||||
00000697 => x"0000053c",
|
||||
00000698 => x"00000548",
|
||||
00000699 => x"00000554",
|
||||
00000700 => x"00000560",
|
||||
00000701 => x"0000056c",
|
||||
00000702 => x"00000574",
|
||||
00000703 => x"0000057c",
|
||||
00000704 => x"00000584",
|
||||
00000705 => x"0000058c",
|
||||
00000706 => x"000004a8",
|
||||
00000707 => x"000004a8",
|
||||
00000708 => x"00000594",
|
||||
00000709 => x"0000059c",
|
||||
00000710 => x"000004a8",
|
||||
00000711 => x"000004a8",
|
||||
00000712 => x"000004a8",
|
||||
00000713 => x"000005a4",
|
||||
00000714 => x"000004a8",
|
||||
00000715 => x"000004a8",
|
||||
00000716 => x"000004a8",
|
||||
00000717 => x"000005ac",
|
||||
00000718 => x"000004a8",
|
||||
00000719 => x"000004a8",
|
||||
00000720 => x"000004a8",
|
||||
00000721 => x"000004a8",
|
||||
00000722 => x"000005b4",
|
||||
00000723 => x"000005bc",
|
||||
00000724 => x"000005c4",
|
||||
00000725 => x"000005cc",
|
||||
00000726 => x"000005d4",
|
||||
00000727 => x"000005dc",
|
||||
00000728 => x"000005e4",
|
||||
00000729 => x"000005ec",
|
||||
00000730 => x"000005f4",
|
||||
00000731 => x"000005fc",
|
||||
00000732 => x"00000604",
|
||||
00000733 => x"0000060c",
|
||||
00000734 => x"00000614",
|
||||
00000735 => x"0000061c",
|
||||
00000736 => x"00000624",
|
||||
00000737 => x"0000062c",
|
||||
00000738 => x"00007830",
|
||||
00000739 => x"4554523c",
|
||||
00000740 => x"0000203e",
|
||||
00000741 => x"74736e49",
|
||||
00000742 => x"74637572",
|
||||
00000743 => x"206e6f69",
|
||||
00000744 => x"72646461",
|
||||
00000745 => x"20737365",
|
||||
00000746 => x"6173696d",
|
||||
00000747 => x"6e67696c",
|
||||
00000748 => x"00006465",
|
||||
00000749 => x"74736e49",
|
||||
00000750 => x"74637572",
|
||||
00000751 => x"206e6f69",
|
||||
00000752 => x"65636361",
|
||||
00000753 => x"66207373",
|
||||
00000754 => x"746c7561",
|
||||
00000755 => x"00000000",
|
||||
00000756 => x"656c6c49",
|
||||
00000757 => x"206c6167",
|
||||
00000758 => x"74736e69",
|
||||
00000759 => x"74637572",
|
||||
00000760 => x"006e6f69",
|
||||
00000761 => x"61657242",
|
||||
00000762 => x"696f706b",
|
||||
00000763 => x"0000746e",
|
||||
00000764 => x"64616f4c",
|
||||
00000765 => x"64646120",
|
||||
00000766 => x"73736572",
|
||||
00000767 => x"73696d20",
|
||||
00000768 => x"67696c61",
|
||||
00000769 => x"0064656e",
|
||||
00000770 => x"64616f4c",
|
||||
00000771 => x"63636120",
|
||||
00000772 => x"20737365",
|
||||
00000773 => x"6c756166",
|
||||
00000774 => x"00000074",
|
||||
00000775 => x"726f7453",
|
||||
00000776 => x"64612065",
|
||||
00000777 => x"73657264",
|
||||
00000778 => x"696d2073",
|
||||
00000779 => x"696c6173",
|
||||
00000780 => x"64656e67",
|
||||
00000781 => x"00000000",
|
||||
00000782 => x"726f7453",
|
||||
00000783 => x"63612065",
|
||||
00000784 => x"73736563",
|
||||
00000785 => x"75616620",
|
||||
00000786 => x"0000746c",
|
||||
00000787 => x"69766e45",
|
||||
00000788 => x"6d6e6f72",
|
||||
00000789 => x"20746e65",
|
||||
00000790 => x"6c6c6163",
|
||||
00000791 => x"6f726620",
|
||||
00000792 => x"2d55206d",
|
||||
00000793 => x"65646f6d",
|
||||
00000794 => x"00000000",
|
||||
00000795 => x"69766e45",
|
||||
00000796 => x"6d6e6f72",
|
||||
00000797 => x"20746e65",
|
||||
00000798 => x"6c6c6163",
|
||||
00000799 => x"6f726620",
|
||||
00000800 => x"2d4d206d",
|
||||
00000801 => x"65646f6d",
|
||||
00000802 => x"00000000",
|
||||
00000803 => x"6863614d",
|
||||
00000804 => x"20656e69",
|
||||
00000805 => x"74666f73",
|
||||
00000806 => x"65726177",
|
||||
00000807 => x"746e6920",
|
||||
00000808 => x"75727265",
|
||||
00000809 => x"00007470",
|
||||
00000810 => x"6863614d",
|
||||
00000811 => x"20656e69",
|
||||
00000812 => x"656d6974",
|
||||
00000813 => x"6e692072",
|
||||
00000814 => x"72726574",
|
||||
00000815 => x"00747075",
|
||||
00000816 => x"6863614d",
|
||||
00000817 => x"20656e69",
|
||||
00000818 => x"65747865",
|
||||
00000819 => x"6c616e72",
|
||||
00000820 => x"746e6920",
|
||||
00000821 => x"75727265",
|
||||
00000822 => x"00007470",
|
||||
00000823 => x"74736146",
|
||||
00000824 => x"746e6920",
|
||||
00000825 => x"75727265",
|
||||
00000826 => x"00207470",
|
||||
00000827 => x"6e6b6e55",
|
||||
00000828 => x"206e776f",
|
||||
00000829 => x"70617274",
|
||||
00000830 => x"75616320",
|
||||
00000831 => x"203a6573",
|
||||
00000832 => x"00000000",
|
||||
00000833 => x"49545b20",
|
||||
00000834 => x"554f454d",
|
||||
00000835 => x"52455f54",
|
||||
00000836 => x"00005d52",
|
||||
00000837 => x"45445b20",
|
||||
00000838 => x"45434956",
|
||||
00000839 => x"5252455f",
|
||||
00000840 => x"0000005d",
|
||||
00000841 => x"4d505b20",
|
||||
00000842 => x"52455f50",
|
||||
00000843 => x"00005d52",
|
||||
00000844 => x"50204020",
|
||||
00000845 => x"00003d43",
|
||||
00000846 => x"544d202c",
|
||||
00000847 => x"3d4c4156",
|
||||
00000848 => x"00000000",
|
||||
00000849 => x"522f3c20",
|
||||
00000850 => x"003e4554",
|
||||
00000851 => x"000007bc",
|
||||
00000852 => x"000007cc",
|
||||
00000853 => x"000007f4",
|
||||
00000854 => x"00000800",
|
||||
00000855 => x"0000080c",
|
||||
00000856 => x"00000818",
|
||||
00000857 => x"00000824",
|
||||
00000858 => x"00000830",
|
||||
00000859 => x"0000083c",
|
||||
00000860 => x"00000728",
|
||||
00000861 => x"00000728",
|
||||
00000862 => x"00000848",
|
||||
00000863 => x"33323130",
|
||||
00000864 => x"37363534",
|
||||
00000865 => x"42413938",
|
||||
00000866 => x"46454443"
|
||||
);
|
||||
|
||||
end neorv32_application_image;
|
106
Libs/RiscV/NEORV32/rtl/core/neorv32_boot_rom.vhd
Normal file
106
Libs/RiscV/NEORV32/rtl/core/neorv32_boot_rom.vhd
Normal file
@ -0,0 +1,106 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-internal bootloader ROM (BOOTROM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # BSD 3-Clause License #
|
||||
-- # #
|
||||
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
|
||||
-- # #
|
||||
-- # Redistribution and use in source and binary forms, with or without modification, are #
|
||||
-- # permitted provided that the following conditions are met: #
|
||||
-- # #
|
||||
-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer. #
|
||||
-- # #
|
||||
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer in the documentation and/or other materials #
|
||||
-- # provided with the distribution. #
|
||||
-- # #
|
||||
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
|
||||
-- # endorse or promote products derived from this software without specific prior written #
|
||||
-- # permission. #
|
||||
-- # #
|
||||
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
|
||||
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
|
||||
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
|
||||
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
|
||||
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
|
||||
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
|
||||
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
|
||||
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
|
||||
-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library neorv32;
|
||||
use neorv32.neorv32_package.all;
|
||||
use neorv32.neorv32_bootloader_image.all; -- this file is generated by the image generator
|
||||
|
||||
entity neorv32_boot_rom is
|
||||
generic (
|
||||
BOOTROM_BASE : std_ulogic_vector(31 downto 0) -- boot ROM base address
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rden_i : in std_ulogic; -- read enable
|
||||
addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
data_o : out std_ulogic_vector(31 downto 0); -- data out
|
||||
ack_o : out std_ulogic -- transfer acknowledge
|
||||
);
|
||||
end neorv32_boot_rom;
|
||||
|
||||
architecture neorv32_boot_rom_rtl of neorv32_boot_rom is
|
||||
|
||||
-- determine required ROM size in bytes (expand to next power of two) --
|
||||
constant boot_rom_size_index_c : natural := index_size_f((bootloader_init_image'length)); -- address with (32-bit entries)
|
||||
constant boot_rom_size_c : natural := (2**boot_rom_size_index_c)*4; -- size in bytes
|
||||
|
||||
-- IO space: module base address --
|
||||
constant hi_abb_c : natural := 31; -- high address boundary bit
|
||||
constant lo_abb_c : natural := index_size_f(boot_rom_max_size_c); -- low address boundary bit
|
||||
|
||||
-- local signals --
|
||||
signal acc_en : std_ulogic;
|
||||
signal rden : std_ulogic;
|
||||
signal rdata : std_ulogic_vector(31 downto 0);
|
||||
signal addr : std_ulogic_vector(boot_rom_size_index_c-1 downto 0);
|
||||
|
||||
-- ROM - initialized with executable code --
|
||||
constant mem_rom : mem32_t(0 to boot_rom_size_c/4-1) := mem32_init_f(bootloader_init_image, boot_rom_size_c/4);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Implementing internal bootloader ROM (" & natural'image(boot_rom_size_c) & " bytes)." severity note;
|
||||
assert not (boot_rom_size_c > boot_rom_max_size_c) report "NEORV32 PROCESSOR CONFIG ERROR! Boot ROM size out of range! Max "& natural'image(boot_rom_max_size_c) & " bytes." severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = BOOTROM_BASE(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= addr_i(boot_rom_size_index_c+1 downto 2); -- word aligned
|
||||
|
||||
|
||||
-- Memory Access --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
mem_file_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
rden <= rden_i and acc_en;
|
||||
if (acc_en = '1') then -- reduce switching activity when not accessed
|
||||
rdata <= mem_rom(to_integer(unsigned(addr)));
|
||||
end if;
|
||||
end if;
|
||||
end process mem_file_access;
|
||||
|
||||
-- output gate --
|
||||
data_o <= rdata when (rden = '1') else (others => '0');
|
||||
ack_o <= rden;
|
||||
|
||||
|
||||
end neorv32_boot_rom_rtl;
|
1026
Libs/RiscV/NEORV32/rtl/core/neorv32_bootloader_image.vhd
Normal file
1026
Libs/RiscV/NEORV32/rtl/core/neorv32_bootloader_image.vhd
Normal file
File diff suppressed because it is too large
Load Diff
180
Libs/RiscV/NEORV32/rtl/core/neorv32_bus_keeper.vhd
Normal file
180
Libs/RiscV/NEORV32/rtl/core/neorv32_bus_keeper.vhd
Normal file
@ -0,0 +1,180 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Bus Keeper (BUSKEEPER) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This unit monitors the processor-internal bus. If the accessed module does not respond within #
|
||||
-- # the defined number of cycles (VHDL package: max_proc_int_response_time_c) or issues an ERROR #
|
||||
-- # conditions the BUS KEEPER asserts the error signal to inform the CPU. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_bus_keeper is
|
||||
port (
|
||||
-- host access --
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
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_o : out std_ulogic_vector(31 downto 0); -- data out
|
||||
ack_o : out std_ulogic; -- transfer acknowledge
|
||||
err_o : out std_ulogic; -- transfer error
|
||||
-- bus monitoring --
|
||||
bus_addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
bus_rden_i : in std_ulogic; -- read enable
|
||||
bus_wren_i : in std_ulogic; -- write enable
|
||||
bus_ack_i : in std_ulogic; -- transfer acknowledge from bus system
|
||||
bus_err_i : in std_ulogic; -- transfer error from bus system
|
||||
bus_tmo_i : in std_ulogic; -- transfer timeout (external interface)
|
||||
bus_ext_i : in std_ulogic -- external bus access
|
||||
);
|
||||
end neorv32_bus_keeper;
|
||||
|
||||
architecture neorv32_bus_keeper_rtl of neorv32_bus_keeper is
|
||||
|
||||
-- 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(buskeeper_size_c); -- low address boundary bit
|
||||
|
||||
-- Control register --
|
||||
constant ctrl_err_type_c : natural := 0; -- r/-: error type: 0=device error, 1=access timeout
|
||||
constant ctrl_err_flag_c : natural := 31; -- r/c: bus error encountered, sticky; cleared by writing zero
|
||||
|
||||
-- sticky error flags --
|
||||
signal err_flag : std_ulogic;
|
||||
signal err_type : std_ulogic;
|
||||
|
||||
-- access control --
|
||||
signal acc_en : std_ulogic; -- module access enable
|
||||
signal wren : std_ulogic; -- word write enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- controller --
|
||||
type control_t is record
|
||||
pending : std_ulogic;
|
||||
timeout : std_ulogic_vector(index_size_f(max_proc_int_response_time_c) downto 0);
|
||||
err_type : std_ulogic;
|
||||
bus_err : std_ulogic;
|
||||
end record;
|
||||
signal control : control_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Check --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (max_proc_int_response_time_c < 2) report "NEORV32 PROCESSOR CONFIG ERROR! Processor-internal bus timeout <max_proc_int_response_time_c> has to >= 2." severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = buskeeper_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
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
|
||||
-- bus handshake --
|
||||
ack_o <= wren or rden;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
data_o(ctrl_err_type_c) <= err_type;
|
||||
data_o(ctrl_err_flag_c) <= err_flag;
|
||||
end if;
|
||||
--
|
||||
if (control.bus_err = '1') then -- sticky error flag
|
||||
err_flag <= '1';
|
||||
err_type <= control.err_type;
|
||||
elsif ((wren or rden) = '1') then -- clear on or read or write
|
||||
err_flag <= '0';
|
||||
err_type <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
|
||||
-- Keeper ---------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
keeper_control: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
control.pending <= '0';
|
||||
control.bus_err <= '0';
|
||||
control.err_type <= def_rst_val_c;
|
||||
control.timeout <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
-- defaults --
|
||||
control.bus_err <= '0';
|
||||
|
||||
-- access monitor: IDLE --
|
||||
if (control.pending = '0') then
|
||||
control.timeout <= std_ulogic_vector(to_unsigned(max_proc_int_response_time_c, index_size_f(max_proc_int_response_time_c)+1));
|
||||
if (bus_rden_i = '1') or (bus_wren_i = '1') then
|
||||
control.pending <= '1';
|
||||
end if;
|
||||
-- access monitor: PENDING --
|
||||
else
|
||||
control.timeout <= std_ulogic_vector(unsigned(control.timeout) - 1); -- countdown timer
|
||||
if (bus_err_i = '1') then -- error termination by bus system
|
||||
control.err_type <= '0'; -- device error
|
||||
control.bus_err <= '1';
|
||||
control.pending <= '0';
|
||||
elsif ((or_reduce_f(control.timeout) = '0') and (bus_ext_i = '0')) or -- internal access timeout
|
||||
(bus_tmo_i = '1') then -- external access timeout
|
||||
control.err_type <= '1'; -- timeout error
|
||||
control.bus_err <= '1';
|
||||
control.pending <= '0';
|
||||
elsif (bus_ack_i = '1') then -- normal termination by bus system
|
||||
control.err_type <= '0'; -- don't care
|
||||
control.bus_err <= '0';
|
||||
control.pending <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process keeper_control;
|
||||
|
||||
-- signal bus error to CPU --
|
||||
err_o <= control.bus_err;
|
||||
|
||||
|
||||
end neorv32_bus_keeper_rtl;
|
273
Libs/RiscV/NEORV32/rtl/core/neorv32_busswitch.vhd
Normal file
273
Libs/RiscV/NEORV32/rtl/core/neorv32_busswitch.vhd
Normal file
@ -0,0 +1,273 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Bus Switch >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Allows to access a single peripheral bus ("p_bus") by two controller busses. Controller port #
|
||||
-- # A ("ca_bus") has priority over controller port B ("cb_bus"). #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_busswitch is
|
||||
generic (
|
||||
PORT_CA_READ_ONLY : boolean; -- set if controller port A is read-only
|
||||
PORT_CB_READ_ONLY : boolean -- set if controller port B is read-only
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
-- controller interface a --
|
||||
ca_bus_addr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
ca_bus_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
ca_bus_wdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
ca_bus_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable
|
||||
ca_bus_we_i : in std_ulogic; -- write enable
|
||||
ca_bus_re_i : in std_ulogic; -- read enable
|
||||
ca_bus_lock_i : in std_ulogic; -- exclusive access request
|
||||
ca_bus_ack_o : out std_ulogic; -- bus transfer acknowledge
|
||||
ca_bus_err_o : out std_ulogic; -- bus transfer error
|
||||
-- controller interface b --
|
||||
cb_bus_addr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
cb_bus_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
cb_bus_wdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
cb_bus_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable
|
||||
cb_bus_we_i : in std_ulogic; -- write enable
|
||||
cb_bus_re_i : in std_ulogic; -- read enable
|
||||
cb_bus_lock_i : in std_ulogic; -- exclusive access request
|
||||
cb_bus_ack_o : out std_ulogic; -- bus transfer acknowledge
|
||||
cb_bus_err_o : out std_ulogic; -- bus transfer error
|
||||
-- peripheral bus --
|
||||
p_bus_src_o : out std_ulogic; -- access source: 0 = A, 1 = B
|
||||
p_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
p_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
p_bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
p_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
||||
p_bus_we_o : out std_ulogic; -- write enable
|
||||
p_bus_re_o : out std_ulogic; -- read enable
|
||||
p_bus_lock_o : out std_ulogic; -- exclusive access request
|
||||
p_bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
||||
p_bus_err_i : in std_ulogic -- bus transfer error
|
||||
);
|
||||
end neorv32_busswitch;
|
||||
|
||||
architecture neorv32_busswitch_rtl of neorv32_busswitch is
|
||||
|
||||
-- access requests --
|
||||
signal ca_rd_req_buf, ca_wr_req_buf : std_ulogic;
|
||||
signal cb_rd_req_buf, cb_wr_req_buf : std_ulogic;
|
||||
signal ca_req_current, ca_req_buffered : std_ulogic;
|
||||
signal cb_req_current, cb_req_buffered : std_ulogic;
|
||||
|
||||
-- internal bus lines --
|
||||
signal ca_bus_ack, cb_bus_ack : std_ulogic;
|
||||
signal ca_bus_err, cb_bus_err : std_ulogic;
|
||||
signal p_bus_we, p_bus_re : std_ulogic;
|
||||
|
||||
-- access arbiter --
|
||||
type arbiter_state_t is (IDLE, BUSY, RETIRE, BUSY_SWITCHED, RETIRE_SWITCHED);
|
||||
type arbiter_t is record
|
||||
state : arbiter_state_t;
|
||||
state_nxt : arbiter_state_t;
|
||||
bus_sel : std_ulogic;
|
||||
re_trig : std_ulogic;
|
||||
we_trig : std_ulogic;
|
||||
end record;
|
||||
signal arbiter : arbiter_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Access Buffer --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
access_buffer: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
ca_rd_req_buf <= '0';
|
||||
ca_wr_req_buf <= '0';
|
||||
cb_rd_req_buf <= '0';
|
||||
cb_wr_req_buf <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
|
||||
-- controller A requests --
|
||||
if (ca_rd_req_buf = '0') and (ca_wr_req_buf = '0') then -- idle
|
||||
ca_rd_req_buf <= ca_bus_re_i;
|
||||
ca_wr_req_buf <= ca_bus_we_i;
|
||||
elsif (ca_bus_err = '1') or -- error termination
|
||||
(ca_bus_ack = '1') then -- normal termination
|
||||
ca_rd_req_buf <= '0';
|
||||
ca_wr_req_buf <= '0';
|
||||
end if;
|
||||
|
||||
-- controller B requests --
|
||||
if (cb_rd_req_buf = '0') and (cb_wr_req_buf = '0') then
|
||||
cb_rd_req_buf <= cb_bus_re_i;
|
||||
cb_wr_req_buf <= cb_bus_we_i;
|
||||
elsif (cb_bus_err = '1') or -- error termination
|
||||
(cb_bus_ack = '1') then -- normal termination
|
||||
cb_rd_req_buf <= '0';
|
||||
cb_wr_req_buf <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process access_buffer;
|
||||
|
||||
-- any current requests? --
|
||||
ca_req_current <= (ca_bus_re_i or ca_bus_we_i) when (PORT_CA_READ_ONLY = false) else ca_bus_re_i;
|
||||
cb_req_current <= (cb_bus_re_i or cb_bus_we_i) when (PORT_CB_READ_ONLY = false) else cb_bus_re_i;
|
||||
|
||||
-- any buffered requests? --
|
||||
ca_req_buffered <= (ca_rd_req_buf or ca_wr_req_buf) when (PORT_CA_READ_ONLY = false) else ca_rd_req_buf;
|
||||
cb_req_buffered <= (cb_rd_req_buf or cb_wr_req_buf) when (PORT_CB_READ_ONLY = false) else cb_rd_req_buf;
|
||||
|
||||
|
||||
-- Access Arbiter Sync --------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
arbiter_sync: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
arbiter.state <= IDLE;
|
||||
elsif rising_edge(clk_i) then
|
||||
arbiter.state <= arbiter.state_nxt;
|
||||
end if;
|
||||
end process arbiter_sync;
|
||||
|
||||
|
||||
-- Peripheral Bus Arbiter -----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
arbiter_comb: process(arbiter, ca_req_current, cb_req_current, ca_req_buffered, cb_req_buffered,
|
||||
ca_rd_req_buf, ca_wr_req_buf, cb_rd_req_buf, cb_wr_req_buf, p_bus_ack_i, p_bus_err_i)
|
||||
begin
|
||||
-- arbiter defaults --
|
||||
arbiter.state_nxt <= arbiter.state;
|
||||
arbiter.bus_sel <= '0';
|
||||
arbiter.we_trig <= '0';
|
||||
arbiter.re_trig <= '0';
|
||||
|
||||
-- state machine --
|
||||
case arbiter.state is
|
||||
|
||||
when IDLE => -- Controller a has full bus access
|
||||
-- ------------------------------------------------------------
|
||||
p_bus_src_o <= '0'; -- access from port A
|
||||
if (ca_req_current = '1') then -- current request?
|
||||
arbiter.bus_sel <= '0';
|
||||
arbiter.state_nxt <= BUSY;
|
||||
elsif (ca_req_buffered = '1') then -- buffered request?
|
||||
arbiter.bus_sel <= '0';
|
||||
arbiter.state_nxt <= RETIRE;
|
||||
elsif (cb_req_current = '1') then -- current request from controller b?
|
||||
arbiter.bus_sel <= '1';
|
||||
arbiter.state_nxt <= BUSY_SWITCHED;
|
||||
elsif (cb_req_buffered = '1') then -- buffered request from controller b?
|
||||
arbiter.bus_sel <= '1';
|
||||
arbiter.state_nxt <= RETIRE_SWITCHED;
|
||||
end if;
|
||||
|
||||
when BUSY => -- transaction in progress
|
||||
-- ------------------------------------------------------------
|
||||
p_bus_src_o <= '0'; -- access from port A
|
||||
arbiter.bus_sel <= '0';
|
||||
if (p_bus_err_i = '1') or -- error termination
|
||||
(p_bus_ack_i = '1') then -- normal termination
|
||||
arbiter.state_nxt <= IDLE;
|
||||
end if;
|
||||
|
||||
when RETIRE => -- retire pending access
|
||||
-- ------------------------------------------------------------
|
||||
p_bus_src_o <= '0'; -- access from port A
|
||||
arbiter.bus_sel <= '0';
|
||||
if (PORT_CA_READ_ONLY = false) then
|
||||
arbiter.we_trig <= ca_wr_req_buf;
|
||||
end if;
|
||||
arbiter.re_trig <= ca_rd_req_buf;
|
||||
arbiter.state_nxt <= BUSY;
|
||||
|
||||
when BUSY_SWITCHED => -- switched transaction in progress
|
||||
-- ------------------------------------------------------------
|
||||
p_bus_src_o <= '1'; -- access from port B
|
||||
arbiter.bus_sel <= '1';
|
||||
if (p_bus_err_i = '1') or -- error termination
|
||||
(p_bus_ack_i = '1') then -- normal termination
|
||||
if (ca_req_buffered = '1') or (ca_req_current = '1') then -- any request from A?
|
||||
arbiter.state_nxt <= RETIRE;
|
||||
else
|
||||
arbiter.state_nxt <= IDLE;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when RETIRE_SWITCHED => -- retire pending switched access
|
||||
-- ------------------------------------------------------------
|
||||
p_bus_src_o <= '1'; -- access from port B
|
||||
arbiter.bus_sel <= '1';
|
||||
if (PORT_CB_READ_ONLY = false) then
|
||||
arbiter.we_trig <= cb_wr_req_buf;
|
||||
end if;
|
||||
arbiter.re_trig <= cb_rd_req_buf;
|
||||
arbiter.state_nxt <= BUSY_SWITCHED;
|
||||
|
||||
end case;
|
||||
end process arbiter_comb;
|
||||
|
||||
|
||||
-- Peripheral Bus Switch ------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
p_bus_addr_o <= ca_bus_addr_i when (arbiter.bus_sel = '0') else cb_bus_addr_i;
|
||||
p_bus_wdata_o <= cb_bus_wdata_i when (PORT_CA_READ_ONLY = true) else ca_bus_wdata_i when (PORT_CB_READ_ONLY = true) else
|
||||
ca_bus_wdata_i when (arbiter.bus_sel = '0') else cb_bus_wdata_i;
|
||||
p_bus_ben_o <= cb_bus_ben_i when (PORT_CA_READ_ONLY = true) else ca_bus_ben_i when (PORT_CB_READ_ONLY = true) else
|
||||
ca_bus_ben_i when (arbiter.bus_sel = '0') else cb_bus_ben_i;
|
||||
p_bus_we <= ca_bus_we_i when (arbiter.bus_sel = '0') else cb_bus_we_i;
|
||||
p_bus_re <= ca_bus_re_i when (arbiter.bus_sel = '0') else cb_bus_re_i;
|
||||
p_bus_we_o <= (p_bus_we or arbiter.we_trig);
|
||||
p_bus_re_o <= (p_bus_re or arbiter.re_trig);
|
||||
p_bus_lock_o <= ca_bus_lock_i or cb_bus_lock_i;
|
||||
|
||||
ca_bus_rdata_o <= p_bus_rdata_i;
|
||||
cb_bus_rdata_o <= p_bus_rdata_i;
|
||||
|
||||
ca_bus_ack <= p_bus_ack_i and (not arbiter.bus_sel);
|
||||
cb_bus_ack <= p_bus_ack_i and ( arbiter.bus_sel);
|
||||
ca_bus_ack_o <= ca_bus_ack;
|
||||
cb_bus_ack_o <= cb_bus_ack;
|
||||
|
||||
ca_bus_err <= p_bus_err_i and (not arbiter.bus_sel);
|
||||
cb_bus_err <= p_bus_err_i and ( arbiter.bus_sel);
|
||||
ca_bus_err_o <= ca_bus_err;
|
||||
cb_bus_err_o <= cb_bus_err;
|
||||
|
||||
|
||||
end neorv32_busswitch_rtl;
|
257
Libs/RiscV/NEORV32/rtl/core/neorv32_cfs.vhd
Normal file
257
Libs/RiscV/NEORV32/rtl/core/neorv32_cfs.vhd
Normal file
@ -0,0 +1,257 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Custom Functions Subsystem (CFS) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # For tightly-coupled custom co-processors. Provides 32x32-bit memory-mapped registers. #
|
||||
-- # This is just an "example/illustration template". Modify this file to implement your own #
|
||||
-- # custom design logic. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cfs is
|
||||
generic (
|
||||
CFS_CONFIG : std_ulogic_vector(31 downto 0); -- custom CFS configuration generic
|
||||
CFS_IN_SIZE : positive; -- size of CFS input conduit in bits
|
||||
CFS_OUT_SIZE : positive -- size of CFS output conduit in bits
|
||||
);
|
||||
port (
|
||||
-- host access --
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rstn_i : in std_ulogic; -- global reset line, low-active, use as async
|
||||
addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
rden_i : in std_ulogic; -- read enable
|
||||
wren_i : in std_ulogic; -- word 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
|
||||
err_o : out std_ulogic; -- transfer error
|
||||
-- clock generator --
|
||||
clkgen_en_o : out std_ulogic; -- enable clock generator
|
||||
clkgen_i : in std_ulogic_vector(07 downto 0); -- "clock" inputs
|
||||
-- interrupt --
|
||||
irq_o : out std_ulogic; -- interrupt request
|
||||
-- custom io (conduits) --
|
||||
cfs_in_i : in std_ulogic_vector(CFS_IN_SIZE-1 downto 0); -- custom inputs
|
||||
cfs_out_o : out std_ulogic_vector(CFS_OUT_SIZE-1 downto 0) -- custom outputs
|
||||
);
|
||||
end neorv32_cfs;
|
||||
|
||||
architecture neorv32_cfs_rtl of neorv32_cfs is
|
||||
|
||||
-- IO space: module base address (DO NOT MODIFY!) --
|
||||
constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
|
||||
constant lo_abb_c : natural := index_size_f(cfs_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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- default CFS interface registers --
|
||||
type cfs_regs_t is array (0 to 3) of std_ulogic_vector(31 downto 0); -- just implement 4 registers for this example
|
||||
signal cfs_reg_wr : cfs_regs_t; -- interface registers for WRITE accesses
|
||||
signal cfs_reg_rd : cfs_regs_t; -- interface registers for READ accesses
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- These assignments are required to check if the CFS is accessed at all.
|
||||
-- DO NOT MODIFY this unless you really know what you are doing.
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = cfs_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= cfs_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
||||
wren <= acc_en and wren_i; -- full 32-bit word write enable
|
||||
rden <= acc_en and rden_i; -- the read access is always a full 32-bit word wide; if required, the byte/half-word select/masking is done in the CPU
|
||||
|
||||
-- NOTE: Do not modify the CFS base address or the CFS' occupied address space as this might cause access
|
||||
-- collisions with other modules.
|
||||
|
||||
-- This module provides an ERROR signal to signal a faulty access operation to the CPU.
|
||||
-- It can be used to indicate an invalid access (for example to an unused CFS register address) or to signal
|
||||
-- a faulty state (like "not operational yet"). The error signal can be checked be checked by the applications
|
||||
-- "bus access fault" exception handler (provided by the system's BUSKEEPER module).
|
||||
-- This signal may only be set when the module is actually accessed! Tie to zero if not explicitly used.
|
||||
err_o <= '0';
|
||||
|
||||
|
||||
-- CFS Generics ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- In its default version, the CFS provides the configuration generics. single generic:
|
||||
-- CFS_IN_SIZE configures the size (in bits) of the CFS input conduit cfs_in_i
|
||||
-- CFS_OUT_SIZE configures the size (in bits) of the CFS output conduit cfs_out_o
|
||||
-- CFS_CONFIG is a blank 32-bit generic. It is intended as a "generic conduit" to propagate custom configuration flags from the top entity down to this entiy.
|
||||
|
||||
|
||||
-- CFS IOs --------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- By default, the CFS provides two IO signals (cfs_in_i and cfs_out_o) that are available at the processor top entity.
|
||||
-- These are intended as "conduits" to propagate custom signals this entity <=> processor top entity.
|
||||
|
||||
cfs_out_o <= (others => '0'); -- not used for this minimal example
|
||||
|
||||
|
||||
-- Reset System ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- The CFS can be reset using the global rstn_i signal. This signal should be used as asynchronous reset and is active-low.
|
||||
-- Note that rstn_i can be asserted by an external reset and also by a watchdog-cause reset.
|
||||
--
|
||||
-- Most default peripheral devices of the NEORV32 do NOT use a dedicated reset at all. Instead, these units are reset by writing ZERO
|
||||
-- to a specific "control register" located right at the beginning of the device's address space (so this register is cleared at first).
|
||||
-- The crt0 start-up code write ZERO to every single address in the processor's IO space - including the CFS.
|
||||
-- Make sure that this clearing does not cause any unintended actions in the CFS.
|
||||
|
||||
|
||||
-- Clock System ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- The processor top unit implements a clock generator providing 8 "derived clocks"
|
||||
-- Actually, these signals should not be used as direct clock signals, but as *clock enable* signals.
|
||||
-- clkgen_i is always synchronous to the main system clock (clk_i).
|
||||
--
|
||||
-- The following clock divider rates are available:
|
||||
-- clkgen_i(clk_div2_c) -> MAIN_CLK/2
|
||||
-- clkgen_i(clk_div4_c) -> MAIN_CLK/4
|
||||
-- clkgen_i(clk_div8_c) -> MAIN_CLK/8
|
||||
-- clkgen_i(clk_div64_c) -> MAIN_CLK/64
|
||||
-- clkgen_i(clk_div128_c) -> MAIN_CLK/128
|
||||
-- clkgen_i(clk_div1024_c) -> MAIN_CLK/1024
|
||||
-- clkgen_i(clk_div2048_c) -> MAIN_CLK/2048
|
||||
-- clkgen_i(clk_div4096_c) -> MAIN_CLK/4096
|
||||
--
|
||||
-- For instance, if you want to drive a clock process at MAIN_CLK/8 clock speed you can use the following construct:
|
||||
--
|
||||
-- if (rstn_i = '0') then -- async and low-active reset (if required at all)
|
||||
-- ...
|
||||
-- elsif rising_edge(clk_i) then -- always use the main clock for all clock processes!
|
||||
-- if (clkgen_i(clk_div8_c) = '1') then -- the div8 "clock" is actually a clock enable
|
||||
-- ...
|
||||
-- end if;
|
||||
-- end if;
|
||||
--
|
||||
-- The clkgen_i input clocks are available when at least one IO/peripheral device (for example the SPI) requires the clocks generated by the
|
||||
-- clock generator. The CFS can enable the clock generator by itself by setting the clkgen_en_o signal high.
|
||||
-- The CFS cannot ensure to deactivate the clock generator by setting the clkgen_en_o signal low as other peripherals might still keep the generator activated.
|
||||
-- Make sure to deactivate the CFS's clkgen_en_o if no clocks are required in here to reduce dynamic power consumption.
|
||||
|
||||
clkgen_en_o <= '0'; -- not used for this minimal example
|
||||
|
||||
|
||||
-- Interrupt ------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- The CFS features a single interrupt signal, which is connected to the CPU's "fast interrupt" channel 1.
|
||||
-- The interrupt is triggered by a one-shot rising edge. After triggering, the interrupt appears as "pending" in the CPU's mie register
|
||||
-- ready to trigger execution of the according interrupt handler. The interrupt request signal should be triggered
|
||||
-- whenever an interrupt condition is fulfilled. It is the task of the application to programmer to enable/clear the CFS interrupt
|
||||
-- using the CPU's mie and mip registers when reuqired.
|
||||
|
||||
irq_o <= '0'; -- not used for this minimal example
|
||||
|
||||
|
||||
-- Read/Write Access ----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- Here we are reading/writing from/to the interface registers of the module. Please note that the peripheral/IO
|
||||
-- modules of the NEORV32 can only be written in full word mode (32-bit). Any other write access (half-word or byte)
|
||||
-- will trigger a store bus access fault exception.
|
||||
--
|
||||
-- The CFS provides up to 32 memory-mapped 32-bit interface register. For instance, these could be used to provide
|
||||
-- a <control register> for global control of the unit, a <data register> for reading/writing from/to a data FIFO, a <command register>
|
||||
-- for issuing commands and a <status register> for status information.
|
||||
--
|
||||
-- Following the interface protocol, each read or write access has to be acknowledged in the following cycle using the ack_o signal (or even later
|
||||
-- if the module needs additional time; the maximum latency until an unacknowledged access will trigger a bus exception is defined via the package's
|
||||
-- global "bus_timeout_c" constant). If no ACK is generated at all, the bus access will time out and cause a bus access fault exception.
|
||||
|
||||
-- Host access: Read and write access to the interface registers + bus transfer acknowledge.
|
||||
-- This example only implements four physical r/w register (the four lowest CF register). The remaining addresses of the CFS are not
|
||||
-- associated with any writable or readable register - an access to those is simply ignored but still acknowledged.
|
||||
|
||||
host_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then -- synchronous interface for reads and writes
|
||||
-- transfer/access acknowledge --
|
||||
ack_o <= rden or wren; -- default: required for the CPU to check the CFS is answering a bus read OR write request; all r/w accesses (to any cfs_reg) will succeed
|
||||
-- ack_o <= rden; -- use this construct if your CFS is read-only
|
||||
-- ack_o <= wren; -- use this construct if your CFS is write-only
|
||||
-- ack_o <= ... -- or define the ACK by yourself (example: some registers are read-only, some others can only be written, ...)
|
||||
|
||||
-- write access --
|
||||
if (wren = '1') then -- word-wide write-access only!
|
||||
if (addr = cfs_reg0_addr_c) then -- make sure to use the internal "addr" signal for the read/write interface
|
||||
cfs_reg_wr(0) <= data_i; -- for example: control register
|
||||
end if;
|
||||
if (addr = cfs_reg1_addr_c) then
|
||||
cfs_reg_wr(1) <= data_i; -- for example: data in/out fifo
|
||||
end if;
|
||||
if (addr = cfs_reg2_addr_c) then
|
||||
cfs_reg_wr(2) <= data_i; -- for example: command fifo
|
||||
end if;
|
||||
if (addr = cfs_reg3_addr_c) then
|
||||
cfs_reg_wr(3) <= data_i; -- for example: status register
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0'); -- the output has to be zero if there is no actual read access
|
||||
if (rden = '1') then -- the read access is always a full 32-bit word wide; if required, the byte/half-word select/masking is done in the CPU
|
||||
case addr is -- make sure to use the internal 'addr' signal for the read/write interface
|
||||
when cfs_reg0_addr_c => data_o <= cfs_reg_rd(0);
|
||||
when cfs_reg1_addr_c => data_o <= cfs_reg_rd(1);
|
||||
when cfs_reg2_addr_c => data_o <= cfs_reg_rd(2);
|
||||
when cfs_reg3_addr_c => data_o <= cfs_reg_rd(3);
|
||||
when others => data_o <= (others => '0'); -- the remaining registers are not implemented and will read as zero
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process host_access;
|
||||
|
||||
|
||||
-- CFS Function Core ----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- This is where the actual functionality can be implemented.
|
||||
-- In this example we are just implementing four r/w registers that invert any value written to them.
|
||||
|
||||
cfs_core: process(cfs_reg_wr)
|
||||
begin
|
||||
cfs_reg_rd(0) <= not cfs_reg_wr(0); -- just invert the written value
|
||||
cfs_reg_rd(1) <= not cfs_reg_wr(1);
|
||||
cfs_reg_rd(2) <= not cfs_reg_wr(2);
|
||||
cfs_reg_rd(3) <= not cfs_reg_wr(3);
|
||||
end process cfs_core;
|
||||
|
||||
|
||||
end neorv32_cfs_rtl;
|
444
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu.vhd
Normal file
444
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu.vhd
Normal file
@ -0,0 +1,444 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - CPU Top Entity >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # NEORV32 CPU: #
|
||||
-- # * neorv32_cpu.vhd - CPU top entity #
|
||||
-- # * neorv32_cpu_alu.vhd - Arithmetic/logic unit #
|
||||
-- # * neorv32_cpu_cp_bitmanip.vhd - Bit-manipulation co-processor #
|
||||
-- # * neorv32_cpu_cp_fpu.vhd - Single-precision FPU co-processor #
|
||||
-- # * neorv32_cpu_cp_muldiv.vhd - Integer multiplier/divider co-processor #
|
||||
-- # * neorv32_cpu_cp_shifter.vhd - Base ISA shifter unit #
|
||||
-- # * neorv32_cpu_bus.vhd - Instruction and data bus interface unit #
|
||||
-- # * neorv32_cpu_control.vhd - CPU control and CSR system #
|
||||
-- # * neorv32_cpu_decompressor.vhd - Compressed instructions decoder #
|
||||
-- # * neorv32_cpu_regfile.vhd - Data register file #
|
||||
-- # * neorv32_package.vhd - Main CPU & Processor package file #
|
||||
-- # #
|
||||
-- # Check out the CPU's online documentation for more information: #
|
||||
-- # HQ: https://github.com/stnolting/neorv32 #
|
||||
-- # Data Sheet: https://stnolting.github.io/neorv32 #
|
||||
-- # User Guide: https://stnolting.github.io/neorv32/ug #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu is
|
||||
generic (
|
||||
-- General --
|
||||
HW_THREAD_ID : natural; -- hardware thread id (32-bit)
|
||||
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0); -- cpu boot address
|
||||
CPU_DEBUG_ADDR : std_ulogic_vector(31 downto 0); -- cpu debug mode start address
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A : boolean; -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_B : boolean; -- implement bit-manipulation extension?
|
||||
CPU_EXTENSION_RISCV_C : boolean; -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E : boolean; -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean; -- implement muld/div extension?
|
||||
CPU_EXTENSION_RISCV_U : boolean; -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean; -- implement 32-bit floating-point extension (using INT reg!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean; -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr : boolean; -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm : boolean; -- implement hardware performance monitors?
|
||||
CPU_EXTENSION_RISCV_Zifencei : boolean; -- implement instruction stream sync.?
|
||||
CPU_EXTENSION_RISCV_Zmmul : boolean; -- implement multiply-only M sub-extension?
|
||||
CPU_EXTENSION_RISCV_DEBUG : boolean; -- implement CPU debug mode?
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN : boolean; -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN : boolean; -- use barrel shifter for shift operations
|
||||
CPU_CNT_WIDTH : natural; -- total width of CPU cycle and instret counters (0..64)
|
||||
CPU_IPB_ENTRIES : natural; -- entries is instruction prefetch buffer, has to be a power of 2
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS : natural; -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY : natural; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS : natural; -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH : natural -- total size of HPM counters (0..64)
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
sleep_o : out std_ulogic; -- cpu is in sleep mode when set
|
||||
debug_o : out std_ulogic; -- cpu is in debug mode when set
|
||||
-- instruction bus interface --
|
||||
i_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
i_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
i_bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
i_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
||||
i_bus_we_o : out std_ulogic; -- write enable
|
||||
i_bus_re_o : out std_ulogic; -- read enable
|
||||
i_bus_lock_o : out std_ulogic; -- exclusive access request
|
||||
i_bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
||||
i_bus_err_i : in std_ulogic; -- bus transfer error
|
||||
i_bus_fence_o : out std_ulogic; -- executed FENCEI operation
|
||||
i_bus_priv_o : out std_ulogic_vector(1 downto 0); -- privilege level
|
||||
-- data bus interface --
|
||||
d_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
d_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
d_bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
d_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
||||
d_bus_we_o : out std_ulogic; -- write enable
|
||||
d_bus_re_o : out std_ulogic; -- read enable
|
||||
d_bus_lock_o : out std_ulogic; -- exclusive access request
|
||||
d_bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
||||
d_bus_err_i : in std_ulogic; -- bus transfer error
|
||||
d_bus_fence_o : out std_ulogic; -- executed FENCE operation
|
||||
d_bus_priv_o : out std_ulogic_vector(1 downto 0); -- privilege level
|
||||
-- system time input from MTIME --
|
||||
time_i : in std_ulogic_vector(63 downto 0); -- current system time
|
||||
-- interrupts (risc-v compliant) --
|
||||
msw_irq_i : in std_ulogic;-- machine software interrupt
|
||||
mext_irq_i : in std_ulogic;-- machine external interrupt
|
||||
mtime_irq_i : in std_ulogic;-- machine timer interrupt
|
||||
-- fast interrupts (custom) --
|
||||
firq_i : in std_ulogic_vector(15 downto 0);
|
||||
-- debug mode (halt) request --
|
||||
db_halt_req_i : in std_ulogic
|
||||
);
|
||||
end neorv32_cpu;
|
||||
|
||||
architecture neorv32_cpu_rtl of neorv32_cpu is
|
||||
|
||||
-- local signals --
|
||||
signal ctrl : std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
||||
signal comparator : std_ulogic_vector(1 downto 0); -- comparator result
|
||||
signal imm : std_ulogic_vector(data_width_c-1 downto 0); -- immediate
|
||||
signal instr : std_ulogic_vector(data_width_c-1 downto 0); -- new instruction
|
||||
signal rs1, rs2 : std_ulogic_vector(data_width_c-1 downto 0); -- source registers
|
||||
signal alu_res : std_ulogic_vector(data_width_c-1 downto 0); -- alu result
|
||||
signal alu_add : std_ulogic_vector(data_width_c-1 downto 0); -- alu address result
|
||||
signal mem_rdata : std_ulogic_vector(data_width_c-1 downto 0); -- memory read data
|
||||
signal alu_idone : std_ulogic; -- iterative alu operation done
|
||||
signal bus_i_wait : std_ulogic; -- wait for current bus instruction fetch
|
||||
signal bus_d_wait : std_ulogic; -- wait for current bus data access
|
||||
signal csr_rdata : std_ulogic_vector(data_width_c-1 downto 0); -- csr read data
|
||||
signal mar : std_ulogic_vector(data_width_c-1 downto 0); -- current memory address register
|
||||
signal ma_instr : std_ulogic; -- misaligned instruction address
|
||||
signal ma_load : std_ulogic; -- misaligned load data address
|
||||
signal ma_store : std_ulogic; -- misaligned store data address
|
||||
signal excl_state : std_ulogic; -- atomic/exclusive access lock status
|
||||
signal be_instr : std_ulogic; -- bus error on instruction access
|
||||
signal be_load : std_ulogic; -- bus error on load data access
|
||||
signal be_store : std_ulogic; -- bus error on store data access
|
||||
signal fetch_pc : std_ulogic_vector(data_width_c-1 downto 0); -- pc for instruction fetch
|
||||
signal curr_pc : std_ulogic_vector(data_width_c-1 downto 0); -- current pc (for current executed instruction)
|
||||
signal next_pc : std_ulogic_vector(data_width_c-1 downto 0); -- next pc (for next executed instruction)
|
||||
signal fpu_flags : std_ulogic_vector(4 downto 0); -- FPU exception flags
|
||||
|
||||
-- pmp interface --
|
||||
signal pmp_addr : pmp_addr_if_t;
|
||||
signal pmp_ctrl : pmp_ctrl_if_t;
|
||||
|
||||
begin
|
||||
|
||||
-- CPU ISA Configuration ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert false report
|
||||
"NEORV32 CPU ISA Configuration (MARCH): " &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_E, "RV32E", "RV32I") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_M, "M", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_A, "A", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_C, "C", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_B, "B", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_U, "U", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_Zicsr, "_Zicsr", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_Zicntr, "_Zicntr", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_Zihpm, "_Zihpm", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_Zifencei, "_Zifencei", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_Zfinx, "_Zfinx", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_Zmmul, "_Zmmul", "") &
|
||||
cond_sel_string_f(CPU_EXTENSION_RISCV_DEBUG, "_Debug", "") &
|
||||
""
|
||||
severity note;
|
||||
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- hardware reset notifier --
|
||||
assert not (dedicated_reset_c = false) report "NEORV32 CPU CONFIG NOTE: Implementing NO dedicated hardware reset for uncritical registers (default, might reduce area). Set package constant <dedicated_reset_c> = TRUE to configure a DEFINED reset value for all CPU registers." severity note;
|
||||
assert not (dedicated_reset_c = true) report "NEORV32 CPU CONFIG NOTE: Implementing defined hardware reset for uncritical registers (non-default, reset-to-zero, might increase area)." severity note;
|
||||
assert not ((def_rst_val_c /= '-') and (def_rst_val_c /= '0')) report "NEORV32 CPU CONFIG ERROR! Invalid configuration of package <def_rst_val_c> constant (has to be '-' or '0')." severity error;
|
||||
|
||||
-- CSR system --
|
||||
assert not (CPU_EXTENSION_RISCV_Zicsr = false) report "NEORV32 CPU CONFIG WARNING! No exception/interrupt/trap/privileged features available when <CPU_EXTENSION_RISCV_Zicsr> = false." severity warning;
|
||||
|
||||
-- CPU counters (cycle and instret) --
|
||||
assert not ((CPU_EXTENSION_RISCV_Zicntr = true) and ((CPU_CNT_WIDTH < 0) or (CPU_CNT_WIDTH > 64))) report "NEORV32 CPU CONFIG ERROR! Invalid <CPU_CNT_WIDTH> configuration. Has to be 0..64." severity error;
|
||||
assert not ((CPU_EXTENSION_RISCV_Zicntr = true) and (CPU_CNT_WIDTH < 64)) report "NEORV32 CPU CONFIG WARNING! Implementing CPU <cycle> and <instret> CSRs with reduced size (" & integer'image(CPU_CNT_WIDTH) & "-bit instead of 64-bit). This is not RISC-V compliant and might have unintended SW side effects." severity warning;
|
||||
|
||||
-- U-extension requires Zicsr extension --
|
||||
assert not ((CPU_EXTENSION_RISCV_Zicsr = false) and (CPU_EXTENSION_RISCV_U = true)) report "NEORV32 CPU CONFIG ERROR! User mode requires <CPU_EXTENSION_RISCV_Zicsr> extension to be enabled." severity error;
|
||||
|
||||
-- Instruction prefetch buffer size --
|
||||
assert not (is_power_of_two_f(CPU_IPB_ENTRIES) = false) report "NEORV32 CPU CONFIG ERROR! Number of entries in instruction prefetch buffer <CPU_IPB_ENTRIES> has to be a power of two." severity error;
|
||||
|
||||
-- Co-processor timeout counter (for debugging only) --
|
||||
assert not (cp_timeout_en_c = true) report "NEORV32 CPU CONFIG WARNING! Co-processor timeout counter enabled. This should be used for debugging/simulation only." severity warning;
|
||||
|
||||
-- PMP regions check --
|
||||
assert not (PMP_NUM_REGIONS > 64) report "NEORV32 CPU CONFIG ERROR! Number of PMP regions <PMP_NUM_REGIONS> out of valid range (0..64)." severity error;
|
||||
-- PMP granularity --
|
||||
assert not ((is_power_of_two_f(PMP_MIN_GRANULARITY) = false) and (PMP_NUM_REGIONS > 0)) report "NEORV32 CPU CONFIG ERROR! <PMP_MIN_GRANULARITY> has to be a power of two." severity error;
|
||||
assert not ((PMP_MIN_GRANULARITY < 8) and (PMP_NUM_REGIONS > 0)) report "NEORV32 CPU CONFIG ERROR! <PMP_MIN_GRANULARITY> has to be >= 8 bytes." severity error;
|
||||
assert not ((CPU_EXTENSION_RISCV_Zicsr = false) and (PMP_NUM_REGIONS > 0)) report "NEORV32 CPU CONFIG ERROR! Physical memory protection (PMP) requires <CPU_EXTENSION_RISCV_Zicsr> extension to be enabled." severity error;
|
||||
|
||||
-- HPM counters check --
|
||||
assert not ((CPU_EXTENSION_RISCV_Zihpm = true) and (HPM_NUM_CNTS > 29)) report "NEORV32 CPU CONFIG ERROR! Number of HPM counters <HPM_NUM_CNTS> out of valid range (0..29)." severity error;
|
||||
assert not ((CPU_EXTENSION_RISCV_Zihpm = true) and ((HPM_CNT_WIDTH < 0) or (HPM_CNT_WIDTH > 64))) report "NEORV32 CPU CONFIG ERROR! HPM counter width <HPM_CNT_WIDTH> has to be 0..64 bit." severity error;
|
||||
assert not ((CPU_EXTENSION_RISCV_Zicsr = false) and (CPU_EXTENSION_RISCV_Zihpm = true)) report "NEORV32 CPU CONFIG ERROR! Hardware performance monitors extension <CPU_EXTENSION_RISCV_Zihpm> requires <CPU_EXTENSION_RISCV_Zicsr> extension to be enabled." severity error;
|
||||
|
||||
-- Mul-extension --
|
||||
assert not ((CPU_EXTENSION_RISCV_Zmmul = true) and (CPU_EXTENSION_RISCV_M = true)) report "NEORV32 CPU CONFIG ERROR! <M> and <Zmmul> extensions cannot co-exist!" severity error;
|
||||
|
||||
-- Debug mode --
|
||||
assert not ((CPU_EXTENSION_RISCV_DEBUG = true) and (CPU_EXTENSION_RISCV_Zicsr = false)) report "NEORV32 CPU CONFIG ERROR! Debug mode requires <CPU_EXTENSION_RISCV_Zicsr> extension to be enabled." severity error;
|
||||
assert not ((CPU_EXTENSION_RISCV_DEBUG = true) and (CPU_EXTENSION_RISCV_Zifencei = false)) report "NEORV32 CPU CONFIG ERROR! Debug mode requires <CPU_EXTENSION_RISCV_Zifencei> extension to be enabled." severity error;
|
||||
|
||||
-- fast multiplication option --
|
||||
assert not (FAST_MUL_EN = true) report "NEORV32 CPU CONFIG NOTE: <FAST_MUL_EN> set. Trying to use DSP blocks for base ISA multiplications." severity note;
|
||||
|
||||
-- fast shift option --
|
||||
assert not (FAST_SHIFT_EN = true) report "NEORV32 CPU CONFIG NOTE: <FAST_SHIFT_EN> set. Implementing full-parallel logic / barrel shifters." severity note;
|
||||
|
||||
|
||||
-- Control Unit ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_control_inst: neorv32_cpu_control
|
||||
generic map (
|
||||
-- General --
|
||||
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id
|
||||
CPU_BOOT_ADDR => CPU_BOOT_ADDR, -- cpu boot address
|
||||
CPU_DEBUG_ADDR => CPU_DEBUG_ADDR, -- cpu debug mode start address
|
||||
-- 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 extension?
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT reg!)
|
||||
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => CPU_EXTENSION_RISCV_Zicntr, -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm => CPU_EXTENSION_RISCV_Zihpm, -- implement hardware performance monitors?
|
||||
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
|
||||
CPU_EXTENSION_RISCV_Zmmul => CPU_EXTENSION_RISCV_Zmmul, -- implement multiply-only M sub-extension?
|
||||
CPU_EXTENSION_RISCV_DEBUG => CPU_EXTENSION_RISCV_DEBUG, -- implement CPU debug mode?
|
||||
-- Extension Options --
|
||||
CPU_CNT_WIDTH => CPU_CNT_WIDTH, -- total width of CPU cycle and instret counters (0..64)
|
||||
CPU_IPB_ENTRIES => CPU_IPB_ENTRIES, -- entries is instruction prefetch buffer, has to be a power of 2
|
||||
-- Physical memory protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH => HPM_CNT_WIDTH -- total size of HPM counters
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
ctrl_o => ctrl, -- main control bus
|
||||
-- status input --
|
||||
alu_idone_i => alu_idone, -- ALU iterative operation done
|
||||
bus_i_wait_i => bus_i_wait, -- wait for bus
|
||||
bus_d_wait_i => bus_d_wait, -- wait for bus
|
||||
excl_state_i => excl_state, -- atomic/exclusive access lock status
|
||||
-- data input --
|
||||
instr_i => instr, -- instruction
|
||||
cmp_i => comparator, -- comparator status
|
||||
alu_add_i => alu_add, -- ALU address result
|
||||
rs1_i => rs1, -- rf source 1
|
||||
-- data output --
|
||||
imm_o => imm, -- immediate
|
||||
fetch_pc_o => fetch_pc, -- PC for instruction fetch
|
||||
curr_pc_o => curr_pc, -- current PC (corresponding to current instruction)
|
||||
next_pc_o => next_pc, -- next PC (corresponding to next instruction)
|
||||
csr_rdata_o => csr_rdata, -- CSR read data
|
||||
-- FPU interface --
|
||||
fpu_flags_i => fpu_flags, -- exception flags
|
||||
-- debug mode (halt) request --
|
||||
db_halt_req_i => db_halt_req_i,
|
||||
-- interrupts (risc-v compliant) --
|
||||
msw_irq_i => msw_irq_i, -- machine software interrupt
|
||||
mext_irq_i => mext_irq_i, -- machine external interrupt
|
||||
mtime_irq_i => mtime_irq_i, -- machine timer interrupt
|
||||
-- fast interrupts (custom) --
|
||||
firq_i => firq_i, -- fast interrupt trigger
|
||||
-- system time input from MTIME --
|
||||
time_i => time_i, -- current system time
|
||||
-- physical memory protection --
|
||||
pmp_addr_o => pmp_addr, -- addresses
|
||||
pmp_ctrl_o => pmp_ctrl, -- configs
|
||||
-- bus access exceptions --
|
||||
mar_i => mar, -- memory address register
|
||||
ma_instr_i => ma_instr, -- misaligned instruction address
|
||||
ma_load_i => ma_load, -- misaligned load data address
|
||||
ma_store_i => ma_store, -- misaligned store data address
|
||||
be_instr_i => be_instr, -- bus error on instruction access
|
||||
be_load_i => be_load, -- bus error on load data access
|
||||
be_store_i => be_store -- bus error on store data access
|
||||
);
|
||||
|
||||
-- CPU is sleeping? --
|
||||
sleep_o <= ctrl(ctrl_sleep_c); -- set when CPU is sleeping (after WFI)
|
||||
|
||||
-- CPU is in debug mode? --
|
||||
debug_o <= ctrl(ctrl_debug_running_c);
|
||||
|
||||
|
||||
-- Register File --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_regfile_inst: neorv32_cpu_regfile
|
||||
generic map (
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E -- implement embedded RF extension?
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
ctrl_i => ctrl, -- main control bus
|
||||
-- data input --
|
||||
mem_i => mem_rdata, -- memory read data
|
||||
alu_i => alu_res, -- ALU result
|
||||
-- data output --
|
||||
rs1_o => rs1, -- operand 1
|
||||
rs2_o => rs2 -- operand 2
|
||||
);
|
||||
|
||||
|
||||
-- ALU ------------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_alu_inst: neorv32_cpu_alu
|
||||
generic map (
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_B => CPU_EXTENSION_RISCV_B, -- implement bit-manipulation extension?
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_Zmmul => CPU_EXTENSION_RISCV_Zmmul, -- implement multiply-only M sub-extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT reg!)
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN -- use barrel shifter for shift operations
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
ctrl_i => ctrl, -- main control bus
|
||||
-- data input --
|
||||
rs1_i => rs1, -- rf source 1
|
||||
rs2_i => rs2, -- rf source 2
|
||||
pc_i => curr_pc, -- current PC
|
||||
pc2_i => next_pc, -- next PC
|
||||
imm_i => imm, -- immediate
|
||||
csr_i => csr_rdata, -- CSR read data
|
||||
-- data output --
|
||||
cmp_o => comparator, -- comparator status
|
||||
res_o => alu_res, -- ALU result
|
||||
add_o => alu_add, -- address computation result
|
||||
fpu_flags_o => fpu_flags, -- FPU exception flags
|
||||
-- status --
|
||||
idone_o => alu_idone -- iterative processing units done?
|
||||
);
|
||||
|
||||
|
||||
-- Bus Interface Unit ---------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_bus_inst: neorv32_cpu_bus
|
||||
generic map (
|
||||
CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A, -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
|
||||
-- Physical memory protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
ctrl_i => ctrl, -- main control bus
|
||||
-- cpu instruction fetch interface --
|
||||
fetch_pc_i => fetch_pc, -- PC for instruction fetch
|
||||
instr_o => instr, -- instruction
|
||||
i_wait_o => bus_i_wait, -- wait for fetch to complete
|
||||
--
|
||||
ma_instr_o => ma_instr, -- misaligned instruction address
|
||||
be_instr_o => be_instr, -- bus error on instruction access
|
||||
-- cpu data access interface --
|
||||
addr_i => alu_add, -- ALU.add result -> access address
|
||||
wdata_i => rs2, -- write data
|
||||
rdata_o => mem_rdata, -- read data
|
||||
mar_o => mar, -- current memory address register
|
||||
d_wait_o => bus_d_wait, -- wait for access to complete
|
||||
--
|
||||
excl_state_o => excl_state, -- atomic/exclusive access status
|
||||
ma_load_o => ma_load, -- misaligned load data address
|
||||
ma_store_o => ma_store, -- misaligned store data address
|
||||
be_load_o => be_load, -- bus error on load data access
|
||||
be_store_o => be_store, -- bus error on store data access
|
||||
-- physical memory protection --
|
||||
pmp_addr_i => pmp_addr, -- addresses
|
||||
pmp_ctrl_i => pmp_ctrl, -- configurations
|
||||
-- instruction bus --
|
||||
i_bus_addr_o => i_bus_addr_o, -- bus access address
|
||||
i_bus_rdata_i => i_bus_rdata_i, -- bus read data
|
||||
i_bus_wdata_o => i_bus_wdata_o, -- bus write data
|
||||
i_bus_ben_o => i_bus_ben_o, -- byte enable
|
||||
i_bus_we_o => i_bus_we_o, -- write enable
|
||||
i_bus_re_o => i_bus_re_o, -- read enable
|
||||
i_bus_lock_o => i_bus_lock_o, -- exclusive access request
|
||||
i_bus_ack_i => i_bus_ack_i, -- bus transfer acknowledge
|
||||
i_bus_err_i => i_bus_err_i, -- bus transfer error
|
||||
i_bus_fence_o => i_bus_fence_o, -- fence operation
|
||||
-- data bus --
|
||||
d_bus_addr_o => d_bus_addr_o, -- bus access address
|
||||
d_bus_rdata_i => d_bus_rdata_i, -- bus read data
|
||||
d_bus_wdata_o => d_bus_wdata_o, -- bus write data
|
||||
d_bus_ben_o => d_bus_ben_o, -- byte enable
|
||||
d_bus_we_o => d_bus_we_o, -- write enable
|
||||
d_bus_re_o => d_bus_re_o, -- read enable
|
||||
d_bus_lock_o => d_bus_lock_o, -- exclusive access request
|
||||
d_bus_ack_i => d_bus_ack_i, -- bus transfer acknowledge
|
||||
d_bus_err_i => d_bus_err_i, -- bus transfer error
|
||||
d_bus_fence_o => d_bus_fence_o -- fence operation
|
||||
);
|
||||
|
||||
-- current privilege level --
|
||||
i_bus_priv_o <= ctrl(ctrl_priv_lvl_msb_c downto ctrl_priv_lvl_lsb_c);
|
||||
d_bus_priv_o <= ctrl(ctrl_priv_lvl_msb_c downto ctrl_priv_lvl_lsb_c);
|
||||
|
||||
|
||||
end neorv32_cpu_rtl;
|
349
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_alu.vhd
Normal file
349
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_alu.vhd
Normal file
@ -0,0 +1,349 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Arithmetical/Logical Unit >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Main data and address ALU and co-processor interface/arbiter. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu_alu is
|
||||
generic (
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_B : boolean; -- implement bit-manipulation extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean; -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_Zmmul : boolean; -- implement multiply-only M sub-extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean; -- implement 32-bit floating-point extension (using INT reg!)
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN : boolean; -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN : boolean -- use barrel shifter for shift operations
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
||||
-- data input --
|
||||
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
||||
rs2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 2
|
||||
pc_i : in std_ulogic_vector(data_width_c-1 downto 0); -- current PC
|
||||
pc2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- next PC
|
||||
imm_i : in std_ulogic_vector(data_width_c-1 downto 0); -- immediate
|
||||
csr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
|
||||
-- data output --
|
||||
cmp_o : out std_ulogic_vector(1 downto 0); -- comparator status
|
||||
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
|
||||
fpu_flags_o : out std_ulogic_vector(4 downto 0); -- FPU exception flags
|
||||
-- status --
|
||||
idone_o : out std_ulogic -- iterative processing units done?
|
||||
);
|
||||
end neorv32_cpu_alu;
|
||||
|
||||
architecture neorv32_cpu_cpu_rtl of neorv32_cpu_alu is
|
||||
|
||||
-- comparator --
|
||||
signal cmp_opx : std_ulogic_vector(data_width_c downto 0);
|
||||
signal cmp_opy : std_ulogic_vector(data_width_c downto 0);
|
||||
signal cmp : std_ulogic_vector(1 downto 0); -- comparator status
|
||||
|
||||
-- operands --
|
||||
signal opa, opb : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
|
||||
-- results --
|
||||
signal addsub_res : std_ulogic_vector(data_width_c downto 0);
|
||||
signal alu_res : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal cp_res : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
|
||||
-- co-processor arbiter and interface --
|
||||
type cp_ctrl_t is record
|
||||
cmd : std_ulogic;
|
||||
cmd_ff : std_ulogic;
|
||||
start : std_ulogic;
|
||||
busy : std_ulogic;
|
||||
timeout : std_ulogic_vector(9 downto 0);
|
||||
end record;
|
||||
signal cp_ctrl : cp_ctrl_t;
|
||||
|
||||
-- co-processor interface --
|
||||
signal cp_start : std_ulogic_vector(3 downto 0); -- trigger co-processor i
|
||||
signal cp_valid : std_ulogic_vector(3 downto 0); -- co-processor i done
|
||||
signal cp_result : cp_data_if_t; -- co-processor result
|
||||
|
||||
begin
|
||||
|
||||
-- Comparator Unit (for conditional branches) ---------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
cmp_opx <= (rs1_i(rs1_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs1_i;
|
||||
cmp_opy <= (rs2_i(rs2_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs2_i;
|
||||
|
||||
cmp(cmp_equal_c) <= '1' when (rs1_i = rs2_i) else '0';
|
||||
cmp(cmp_less_c) <= '1' when (signed(cmp_opx) < signed(cmp_opy)) else '0';
|
||||
cmp_o <= cmp;
|
||||
|
||||
|
||||
-- ALU Input Operand Mux ------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
opa <= pc_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand), only required for arithmetic ops
|
||||
opb <= imm_i when (ctrl_i(ctrl_alu_opb_mux_c) = '1') else rs2_i; -- operand b (second ALU input operand)
|
||||
|
||||
|
||||
-- Binary Adder/Subtracter ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
binary_arithmetic_core: process(ctrl_i, opa, opb)
|
||||
variable cin_v : std_ulogic_vector(0 downto 0);
|
||||
variable op_a_v : std_ulogic_vector(data_width_c downto 0);
|
||||
variable op_b_v : std_ulogic_vector(data_width_c downto 0);
|
||||
variable op_y_v : std_ulogic_vector(data_width_c downto 0);
|
||||
variable res_v : std_ulogic_vector(data_width_c downto 0);
|
||||
begin
|
||||
-- operand sign-extension --
|
||||
op_a_v := (opa(opa'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opa;
|
||||
op_b_v := (opb(opb'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opb;
|
||||
-- add/sub(slt) select --
|
||||
if (ctrl_i(ctrl_alu_op0_c) = '1') then -- subtraction
|
||||
op_y_v := not op_b_v;
|
||||
cin_v(0) := '1';
|
||||
else -- addition
|
||||
op_y_v := op_b_v;
|
||||
cin_v(0) := '0';
|
||||
end if;
|
||||
-- adder core --
|
||||
addsub_res <= std_ulogic_vector(unsigned(op_a_v) + unsigned(op_y_v) + unsigned(cin_v(0 downto 0)));
|
||||
end process binary_arithmetic_core;
|
||||
|
||||
-- direct output of adder result --
|
||||
add_o <= addsub_res(data_width_c-1 downto 0);
|
||||
|
||||
|
||||
-- ALU Operation Select -------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
alu_core: process(ctrl_i, addsub_res, rs1_i, opb)
|
||||
begin
|
||||
case ctrl_i(ctrl_alu_op2_c downto ctrl_alu_op0_c) is
|
||||
when alu_op_add_c => alu_res <= addsub_res(data_width_c-1 downto 0); -- (default)
|
||||
when alu_op_sub_c => alu_res <= addsub_res(data_width_c-1 downto 0);
|
||||
-- when alu_op_mova_c => alu_res <= rs1_i; -- FIXME
|
||||
when alu_op_slt_c => alu_res <= (others => '0'); alu_res(0) <= addsub_res(addsub_res'left); -- => carry/borrow
|
||||
when alu_op_movb_c => alu_res <= opb;
|
||||
when alu_op_xor_c => alu_res <= rs1_i xor opb; -- only rs1 required for logic ops (opa would also contain pc)
|
||||
when alu_op_or_c => alu_res <= rs1_i or opb;
|
||||
when alu_op_and_c => alu_res <= rs1_i and opb;
|
||||
when others => alu_res <= addsub_res(data_width_c-1 downto 0);
|
||||
end case;
|
||||
end process alu_core;
|
||||
|
||||
-- ALU Function Select --------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
alu_function_mux: process(ctrl_i, alu_res, pc2_i, csr_i, cp_res)
|
||||
begin
|
||||
case ctrl_i(ctrl_alu_func1_c downto ctrl_alu_func0_c) is
|
||||
when alu_func_core_c => res_o <= alu_res; -- (default)
|
||||
when alu_func_nxpc_c => res_o <= pc2_i;
|
||||
when alu_func_csrr_c => res_o <= csr_i;
|
||||
when alu_func_copro_c => res_o <= cp_res;
|
||||
when others => res_o <= alu_res; -- undefined
|
||||
end case;
|
||||
end process alu_function_mux;
|
||||
|
||||
|
||||
-- **************************************************************************************************************************
|
||||
-- Co-Processors
|
||||
-- **************************************************************************************************************************
|
||||
|
||||
-- Co-Processor Arbiter -------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- Interface:
|
||||
-- Co-processor "valid" signal has to be asserted (for one cycle) one cycle before asserting output data
|
||||
-- Co-processor "output data" has to be always zero unless co-processor was explicitly triggered
|
||||
cp_arbiter: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
cp_ctrl.cmd_ff <= '0';
|
||||
cp_ctrl.busy <= '0';
|
||||
cp_ctrl.timeout <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
cp_ctrl.cmd_ff <= cp_ctrl.cmd;
|
||||
-- timeout counter --
|
||||
if (cp_ctrl.start = '1') then
|
||||
cp_ctrl.busy <= '1';
|
||||
elsif (or_reduce_f(cp_valid) = '1') then
|
||||
cp_ctrl.busy <= '0';
|
||||
end if;
|
||||
if (cp_ctrl.busy = '1') and (cp_timeout_en_c = true) then
|
||||
cp_ctrl.timeout <= std_ulogic_vector(unsigned(cp_ctrl.timeout) + 1);
|
||||
else
|
||||
cp_ctrl.timeout <= (others => '0');
|
||||
end if;
|
||||
if (cp_ctrl.timeout(cp_ctrl.timeout'left) = '1') and (cp_timeout_en_c = true) then -- timeout
|
||||
assert false report "NEORV32 CPU CO-PROCESSOR TIMEOUT ERROR!" severity warning;
|
||||
end if;
|
||||
end if;
|
||||
end process cp_arbiter;
|
||||
|
||||
-- is co-processor operation? --
|
||||
cp_ctrl.cmd <= '1' when (ctrl_i(ctrl_alu_func1_c downto ctrl_alu_func0_c) = alu_func_copro_c) else '0';
|
||||
cp_ctrl.start <= '1' when (cp_ctrl.cmd = '1') and (cp_ctrl.cmd_ff = '0') else '0';
|
||||
|
||||
-- co-processor select / star trigger --
|
||||
cp_start(0) <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "00") else '0';
|
||||
cp_start(1) <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "01") else '0';
|
||||
cp_start(2) <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "10") else '0';
|
||||
cp_start(3) <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "11") else '0';
|
||||
|
||||
-- co-processor operation done? --
|
||||
idone_o <= or_reduce_f(cp_valid);
|
||||
|
||||
-- co-processor result - only the *actually selected* co-processor may output data != 0 --
|
||||
cp_res <= cp_result(0) or cp_result(1) or cp_result(2) or cp_result(3);
|
||||
|
||||
|
||||
-- Co-Processor 0: Shifter (CPU Core ISA) --------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_cp_shifter_inst: neorv32_cpu_cp_shifter
|
||||
generic map (
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN -- use barrel shifter for shift operations
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
ctrl_i => ctrl_i, -- main control bus
|
||||
start_i => cp_start(0), -- trigger operation
|
||||
-- data input --
|
||||
rs1_i => rs1_i, -- rf source 1
|
||||
shamt_i => opb(index_size_f(data_width_c)-1 downto 0), -- shift amount
|
||||
-- result and status --
|
||||
res_o => cp_result(0), -- operation result
|
||||
valid_o => cp_valid(0) -- data output valid
|
||||
);
|
||||
|
||||
|
||||
-- Co-Processor 1: Integer Multiplication/Division ('M' Extension) ------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_cp_muldiv_inst_true:
|
||||
if (CPU_EXTENSION_RISCV_M = true) or (CPU_EXTENSION_RISCV_Zmmul = true) generate
|
||||
neorv32_cpu_cp_muldiv_inst: neorv32_cpu_cp_muldiv
|
||||
generic map (
|
||||
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for faster multiplication
|
||||
DIVISION_EN => CPU_EXTENSION_RISCV_M -- implement divider hardware
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
ctrl_i => ctrl_i, -- main control bus
|
||||
start_i => cp_start(1), -- trigger operation
|
||||
-- data input --
|
||||
rs1_i => rs1_i, -- rf source 1
|
||||
rs2_i => rs2_i, -- rf source 2
|
||||
-- result and status --
|
||||
res_o => cp_result(1), -- operation result
|
||||
valid_o => cp_valid(1) -- data output valid
|
||||
);
|
||||
end generate;
|
||||
|
||||
neorv32_cpu_cp_muldiv_inst_false:
|
||||
if (CPU_EXTENSION_RISCV_M = false) and (CPU_EXTENSION_RISCV_Zmmul = false) generate
|
||||
cp_result(1) <= (others => '0');
|
||||
cp_valid(1) <= cp_start(1); -- to make sure CPU does not get stalled if there is an accidental access
|
||||
end generate;
|
||||
|
||||
|
||||
-- Co-Processor 2: Bit-Manipulation Unit ('B' Extension) ----------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_cp_bitmanip_inst_true:
|
||||
if (CPU_EXTENSION_RISCV_B = true) generate
|
||||
neorv32_cpu_cp_bitmanip_inst: neorv32_cpu_cp_bitmanip
|
||||
generic map (
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN -- use barrel shifter for shift operations
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
ctrl_i => ctrl_i, -- main control bus
|
||||
start_i => cp_start(2), -- trigger operation
|
||||
-- data input --
|
||||
cmp_i => cmp, -- comparator status
|
||||
rs1_i => rs1_i, -- rf source 1
|
||||
rs2_i => rs2_i, -- rf source 2
|
||||
shamt_i => opb(index_size_f(data_width_c)-1 downto 0), -- shift amount
|
||||
-- result and status --
|
||||
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
|
||||
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: Single-Precision Floating-Point Unit ('Zfinx' Extension) ---------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_cpu_cp_fpu_inst_true:
|
||||
if (CPU_EXTENSION_RISCV_Zfinx = true) generate
|
||||
neorv32_cpu_cp_fpu_inst: neorv32_cpu_cp_fpu
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
ctrl_i => ctrl_i, -- main control bus
|
||||
start_i => cp_start(3), -- trigger operation
|
||||
-- data input --
|
||||
cmp_i => cmp, -- comparator status
|
||||
rs1_i => rs1_i, -- rf source 1
|
||||
rs2_i => rs2_i, -- rf source 2
|
||||
-- result and status --
|
||||
res_o => cp_result(3), -- operation result
|
||||
fflags_o => fpu_flags_o, -- exception flags
|
||||
valid_o => cp_valid(3) -- data output valid
|
||||
);
|
||||
end generate;
|
||||
|
||||
neorv32_cpu_cp_fpu_inst_false:
|
||||
if (CPU_EXTENSION_RISCV_Zfinx = false) generate
|
||||
cp_result(3) <= (others => '0');
|
||||
fpu_flags_o <= (others => '0');
|
||||
cp_valid(3) <= cp_start(3); -- to make sure CPU does not get stalled if there is an accidental access
|
||||
end generate;
|
||||
|
||||
|
||||
end neorv32_cpu_cpu_rtl;
|
509
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_bus.vhd
Normal file
509
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_bus.vhd
Normal file
@ -0,0 +1,509 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Bus Interface Unit >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Instruction and data bus interfaces and physical memory protection (PMP). #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu_bus is
|
||||
generic (
|
||||
CPU_EXTENSION_RISCV_A : boolean; -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_C : boolean; -- implement compressed extension?
|
||||
-- Physical memory protection (PMP) --
|
||||
PMP_NUM_REGIONS : natural; -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY : natural -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic := '0'; -- global reset, low-active, async
|
||||
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
||||
-- cpu instruction fetch interface --
|
||||
fetch_pc_i : in std_ulogic_vector(data_width_c-1 downto 0); -- PC for instruction fetch
|
||||
instr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- instruction
|
||||
i_wait_o : out std_ulogic; -- wait for fetch to complete
|
||||
--
|
||||
ma_instr_o : out std_ulogic; -- misaligned instruction address
|
||||
be_instr_o : out std_ulogic; -- bus error on instruction access
|
||||
-- cpu data access interface --
|
||||
addr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- ALU result -> access address
|
||||
wdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- write data
|
||||
rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- read data
|
||||
mar_o : out std_ulogic_vector(data_width_c-1 downto 0); -- current memory address register
|
||||
d_wait_o : out std_ulogic; -- wait for access to complete
|
||||
--
|
||||
excl_state_o : out std_ulogic; -- atomic/exclusive access status
|
||||
ma_load_o : out std_ulogic; -- misaligned load data address
|
||||
ma_store_o : out std_ulogic; -- misaligned store data address
|
||||
be_load_o : out std_ulogic; -- bus error on load data access
|
||||
be_store_o : out std_ulogic; -- bus error on store data access
|
||||
-- physical memory protection --
|
||||
pmp_addr_i : in pmp_addr_if_t; -- addresses
|
||||
pmp_ctrl_i : in pmp_ctrl_if_t; -- configs
|
||||
-- instruction bus --
|
||||
i_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
i_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
i_bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
i_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
||||
i_bus_we_o : out std_ulogic; -- write enable
|
||||
i_bus_re_o : out std_ulogic; -- read enable
|
||||
i_bus_lock_o : out std_ulogic; -- exclusive access request
|
||||
i_bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
||||
i_bus_err_i : in std_ulogic; -- bus transfer error
|
||||
i_bus_fence_o : out std_ulogic; -- fence operation
|
||||
-- data bus --
|
||||
d_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
d_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
d_bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
d_bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
||||
d_bus_we_o : out std_ulogic; -- write enable
|
||||
d_bus_re_o : out std_ulogic; -- read enable
|
||||
d_bus_lock_o : out std_ulogic; -- exclusive access request
|
||||
d_bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
||||
d_bus_err_i : in std_ulogic; -- bus transfer error
|
||||
d_bus_fence_o : out std_ulogic -- fence operation
|
||||
);
|
||||
end neorv32_cpu_bus;
|
||||
|
||||
architecture neorv32_cpu_bus_rtl of neorv32_cpu_bus is
|
||||
|
||||
-- PMP modes --
|
||||
constant pmp_off_mode_c : std_ulogic_vector(1 downto 0) := "00"; -- null region (disabled)
|
||||
--constant pmp_tor_mode_c : std_ulogic_vector(1 downto 0) := "01"; -- top of range
|
||||
--constant pmp_na4_mode_c : std_ulogic_vector(1 downto 0) := "10"; -- naturally aligned four-byte region
|
||||
constant pmp_napot_mode_c : std_ulogic_vector(1 downto 0) := "11"; -- naturally aligned power-of-two region (>= 8 bytes)
|
||||
|
||||
-- PMP granularity --
|
||||
constant pmp_g_c : natural := index_size_f(PMP_MIN_GRANULARITY);
|
||||
|
||||
-- PMP configuration register bits --
|
||||
constant pmp_cfg_r_c : natural := 0; -- read permit
|
||||
constant pmp_cfg_w_c : natural := 1; -- write permit
|
||||
constant pmp_cfg_x_c : natural := 2; -- execute permit
|
||||
constant pmp_cfg_al_c : natural := 3; -- mode bit low
|
||||
constant pmp_cfg_ah_c : natural := 4; -- mode bit high
|
||||
--
|
||||
constant pmp_cfg_l_c : natural := 7; -- locked entry
|
||||
|
||||
-- data interface registers --
|
||||
signal mar, mdo, mdi : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
|
||||
-- data access --
|
||||
signal d_bus_wdata : std_ulogic_vector(data_width_c-1 downto 0); -- write data
|
||||
signal d_bus_rdata : std_ulogic_vector(data_width_c-1 downto 0); -- read data
|
||||
signal rdata_align : std_ulogic_vector(data_width_c-1 downto 0); -- read-data alignment
|
||||
signal d_bus_ben : std_ulogic_vector(3 downto 0); -- write data byte enable
|
||||
|
||||
-- misaligned access? --
|
||||
signal d_misaligned, i_misaligned : std_ulogic;
|
||||
|
||||
-- bus arbiter --
|
||||
type bus_arbiter_t is record
|
||||
rd_req : std_ulogic; -- read access in progress
|
||||
wr_req : std_ulogic; -- write access in progress
|
||||
err_align : std_ulogic; -- alignment error
|
||||
err_bus : std_ulogic; -- bus access error
|
||||
end record;
|
||||
signal i_arbiter, d_arbiter : bus_arbiter_t;
|
||||
|
||||
-- atomic/exclusive access - reservation controller --
|
||||
signal exclusive_lock : std_ulogic;
|
||||
signal exclusive_lock_status : std_ulogic_vector(data_width_c-1 downto 0); -- read data
|
||||
|
||||
-- physical memory protection --
|
||||
type pmp_addr_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(data_width_c-1 downto 0);
|
||||
type pmp_t is record
|
||||
addr_mask : pmp_addr_t;
|
||||
region_base : pmp_addr_t; -- region config base address
|
||||
region_i_addr : pmp_addr_t; -- masked instruction access base address for comparator
|
||||
region_d_addr : pmp_addr_t; -- masked data access base address for comparator
|
||||
i_match : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region match for instruction interface
|
||||
d_match : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region match for data interface
|
||||
if_fault : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for fetch operation
|
||||
ld_fault : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for load operation
|
||||
st_fault : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for store operation
|
||||
end record;
|
||||
signal pmp : pmp_t;
|
||||
|
||||
-- memory control signal buffer (when using PMP) --
|
||||
signal d_bus_we, d_bus_we_buf : std_ulogic;
|
||||
signal d_bus_re, d_bus_re_buf : std_ulogic;
|
||||
signal i_bus_re, i_bus_re_buf : std_ulogic;
|
||||
|
||||
-- pmp faults anyone? --
|
||||
signal if_pmp_fault : std_ulogic; -- pmp instruction access fault
|
||||
signal ld_pmp_fault : std_ulogic; -- pmp load access fault
|
||||
signal st_pmp_fault : std_ulogic; -- pmp store access fault
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (PMP_NUM_REGIONS > pmp_num_regions_critical_c) report "NEORV32 CPU CONFIG WARNING! Number of implemented PMP regions (PMP_NUM_REGIONS = " &
|
||||
integer'image(PMP_NUM_REGIONS) & ") beyond critical limit (pmp_num_regions_critical_c = " & integer'image(pmp_num_regions_critical_c) &
|
||||
"). Inserting another register stage (that will increase memory latency by +1 cycle)." severity warning;
|
||||
|
||||
|
||||
-- Data Interface: Access Address ---------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
mem_adr_reg: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
mar <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
if (ctrl_i(ctrl_bus_mo_we_c) = '1') then
|
||||
mar <= addr_i;
|
||||
end if;
|
||||
end if;
|
||||
end process mem_adr_reg;
|
||||
|
||||
-- read-back for exception controller --
|
||||
mar_o <= mar;
|
||||
|
||||
-- alignment check --
|
||||
misaligned_d_check: process(mar, ctrl_i)
|
||||
begin
|
||||
-- check data access --
|
||||
d_misaligned <= '0'; -- default
|
||||
case ctrl_i(ctrl_bus_size_msb_c downto ctrl_bus_size_lsb_c) is -- data size
|
||||
when "00" => -- byte
|
||||
d_misaligned <= '0';
|
||||
when "01" => -- half-word
|
||||
if (mar(0) /= '0') then
|
||||
d_misaligned <= '1';
|
||||
end if;
|
||||
when others => -- word
|
||||
if (mar(1 downto 0) /= "00") then
|
||||
d_misaligned <= '1';
|
||||
end if;
|
||||
end case;
|
||||
end process misaligned_d_check;
|
||||
|
||||
|
||||
-- Data Interface: Write Data -------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
mem_do_reg: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
mdo <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
if (ctrl_i(ctrl_bus_mo_we_c) = '1') then
|
||||
mdo <= wdata_i; -- memory data output register (MDO)
|
||||
end if;
|
||||
end if;
|
||||
end process mem_do_reg;
|
||||
|
||||
-- byte enable and output data alignment --
|
||||
byte_enable: process(mar, mdo, ctrl_i)
|
||||
begin
|
||||
case ctrl_i(ctrl_bus_size_msb_c downto ctrl_bus_size_lsb_c) is -- data size
|
||||
when "00" => -- byte
|
||||
d_bus_wdata(07 downto 00) <= mdo(07 downto 00);
|
||||
d_bus_wdata(15 downto 08) <= mdo(07 downto 00);
|
||||
d_bus_wdata(23 downto 16) <= mdo(07 downto 00);
|
||||
d_bus_wdata(31 downto 24) <= mdo(07 downto 00);
|
||||
case mar(1 downto 0) is
|
||||
when "00" => d_bus_ben <= "0001";
|
||||
when "01" => d_bus_ben <= "0010";
|
||||
when "10" => d_bus_ben <= "0100";
|
||||
when others => d_bus_ben <= "1000";
|
||||
end case;
|
||||
when "01" => -- half-word
|
||||
d_bus_wdata(31 downto 16) <= mdo(15 downto 00);
|
||||
d_bus_wdata(15 downto 00) <= mdo(15 downto 00);
|
||||
if (mar(1) = '0') then
|
||||
d_bus_ben <= "0011"; -- low half-word
|
||||
else
|
||||
d_bus_ben <= "1100"; -- high half-word
|
||||
end if;
|
||||
when others => -- word
|
||||
d_bus_wdata <= mdo;
|
||||
d_bus_ben <= "1111"; -- full word
|
||||
end case;
|
||||
end process byte_enable;
|
||||
|
||||
|
||||
-- Data Interface: Read Data --------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
mem_di_reg: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
mdi <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
if (ctrl_i(ctrl_bus_mi_we_c) = '1') then
|
||||
mdi <= d_bus_rdata; -- memory data input register (MDI)
|
||||
end if;
|
||||
end if;
|
||||
end process mem_di_reg;
|
||||
|
||||
-- input data alignment and sign extension --
|
||||
read_align: process(mdi, mar, ctrl_i)
|
||||
variable byte_in_v : std_ulogic_vector(07 downto 0);
|
||||
variable hword_in_v : std_ulogic_vector(15 downto 0);
|
||||
begin
|
||||
-- sub-word input --
|
||||
case mar(1 downto 0) is
|
||||
when "00" => byte_in_v := mdi(07 downto 00); hword_in_v := mdi(15 downto 00); -- byte 0 / half-word 0
|
||||
when "01" => byte_in_v := mdi(15 downto 08); hword_in_v := mdi(15 downto 00); -- byte 1 / half-word 0
|
||||
when "10" => byte_in_v := mdi(23 downto 16); hword_in_v := mdi(31 downto 16); -- byte 2 / half-word 1
|
||||
when others => byte_in_v := mdi(31 downto 24); hword_in_v := mdi(31 downto 16); -- byte 3 / half-word 1
|
||||
end case;
|
||||
-- actual data size --
|
||||
case ctrl_i(ctrl_bus_size_msb_c downto ctrl_bus_size_lsb_c) is
|
||||
when "00" => -- byte
|
||||
rdata_align(31 downto 08) <= (others => ((not ctrl_i(ctrl_bus_unsigned_c)) and byte_in_v(7))); -- sign extension
|
||||
rdata_align(07 downto 00) <= byte_in_v;
|
||||
when "01" => -- half-word
|
||||
rdata_align(31 downto 16) <= (others => ((not ctrl_i(ctrl_bus_unsigned_c)) and hword_in_v(15))); -- sign extension
|
||||
rdata_align(15 downto 00) <= hword_in_v; -- high half-word
|
||||
when others => -- word
|
||||
rdata_align <= mdi; -- full word
|
||||
end case;
|
||||
end process read_align;
|
||||
|
||||
-- insert exclusive lock status for SC operations only --
|
||||
rdata_o <= exclusive_lock_status when (CPU_EXTENSION_RISCV_A = true) and (ctrl_i(ctrl_bus_ch_lock_c) = '1') else rdata_align;
|
||||
|
||||
|
||||
-- Data Access Arbiter --------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
data_access_arbiter: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
d_arbiter.wr_req <= '0';
|
||||
d_arbiter.rd_req <= '0';
|
||||
d_arbiter.err_align <= '0';
|
||||
d_arbiter.err_bus <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
-- data access request --
|
||||
if (d_arbiter.wr_req = '0') and (d_arbiter.rd_req = '0') then -- idle
|
||||
d_arbiter.wr_req <= ctrl_i(ctrl_bus_wr_c);
|
||||
d_arbiter.rd_req <= ctrl_i(ctrl_bus_rd_c);
|
||||
d_arbiter.err_align <= d_misaligned;
|
||||
d_arbiter.err_bus <= '0';
|
||||
else -- in progress
|
||||
d_arbiter.err_align <= (d_arbiter.err_align or d_misaligned) and (not ctrl_i(ctrl_bus_derr_ack_c));
|
||||
d_arbiter.err_bus <= (d_arbiter.err_bus or d_bus_err_i or (st_pmp_fault and d_arbiter.wr_req) or (ld_pmp_fault and d_arbiter.rd_req)) and
|
||||
(not ctrl_i(ctrl_bus_derr_ack_c));
|
||||
if (d_bus_ack_i = '1') or (ctrl_i(ctrl_bus_derr_ack_c) = '1') then -- wait for normal termination / CPU abort
|
||||
d_arbiter.wr_req <= '0';
|
||||
d_arbiter.rd_req <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process data_access_arbiter;
|
||||
|
||||
-- wait for bus transaction to finish --
|
||||
d_wait_o <= (d_arbiter.wr_req or d_arbiter.rd_req) and (not d_bus_ack_i);
|
||||
|
||||
-- output data access error to controller --
|
||||
ma_load_o <= d_arbiter.rd_req and d_arbiter.err_align;
|
||||
be_load_o <= d_arbiter.rd_req and d_arbiter.err_bus;
|
||||
ma_store_o <= d_arbiter.wr_req and d_arbiter.err_align;
|
||||
be_store_o <= d_arbiter.wr_req and d_arbiter.err_bus;
|
||||
|
||||
-- data bus (read/write)--
|
||||
d_bus_addr_o <= mar;
|
||||
d_bus_wdata_o <= d_bus_wdata;
|
||||
d_bus_ben_o <= d_bus_ben;
|
||||
d_bus_we <= ctrl_i(ctrl_bus_wr_c) and (not d_misaligned) and (not st_pmp_fault); -- no actual write when misaligned or PMP fault
|
||||
d_bus_re <= ctrl_i(ctrl_bus_rd_c) and (not d_misaligned) and (not ld_pmp_fault); -- no actual read when misaligned or PMP fault
|
||||
d_bus_we_o <= d_bus_we_buf when (PMP_NUM_REGIONS > pmp_num_regions_critical_c) else d_bus_we;
|
||||
d_bus_re_o <= d_bus_re_buf when (PMP_NUM_REGIONS > pmp_num_regions_critical_c) else d_bus_re;
|
||||
d_bus_fence_o <= ctrl_i(ctrl_bus_fence_c);
|
||||
d_bus_rdata <= d_bus_rdata_i;
|
||||
|
||||
-- additional register stage for control signals if using PMP_NUM_REGIONS > pmp_num_regions_critical_c --
|
||||
pmp_dbus_buffer: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
d_bus_we_buf <= '0';
|
||||
d_bus_re_buf <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
d_bus_we_buf <= d_bus_we;
|
||||
d_bus_re_buf <= d_bus_re;
|
||||
end if;
|
||||
end process pmp_dbus_buffer;
|
||||
|
||||
|
||||
-- Reservation Controller (LR/SC [A extension]) -------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
exclusive_access_controller: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
exclusive_lock <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
if (CPU_EXTENSION_RISCV_A = true) then
|
||||
if (ctrl_i(ctrl_trap_c) = '1') or (ctrl_i(ctrl_bus_de_lock_c) = '1') then -- remove lock if entering a trap or executing a non-load-reservate memory access
|
||||
exclusive_lock <= '0';
|
||||
elsif (ctrl_i(ctrl_bus_lock_c) = '1') then -- set new lock
|
||||
exclusive_lock <= '1';
|
||||
end if;
|
||||
else
|
||||
exclusive_lock <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process exclusive_access_controller;
|
||||
|
||||
-- lock status for SC operation --
|
||||
exclusive_lock_status(data_width_c-1 downto 1) <= (others => '0');
|
||||
exclusive_lock_status(0) <= not exclusive_lock;
|
||||
|
||||
-- output reservation status to control unit (to check if SC should write at all) --
|
||||
excl_state_o <= exclusive_lock;
|
||||
|
||||
-- output to memory system --
|
||||
i_bus_lock_o <= '0'; -- instruction fetches cannot be locked
|
||||
d_bus_lock_o <= exclusive_lock;
|
||||
|
||||
|
||||
-- Instruction Fetch Arbiter --------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
ifetch_arbiter: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
i_arbiter.rd_req <= '0';
|
||||
i_arbiter.err_align <= '0';
|
||||
i_arbiter.err_bus <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
-- instruction fetch request --
|
||||
if (i_arbiter.rd_req = '0') then -- idle
|
||||
i_arbiter.rd_req <= ctrl_i(ctrl_bus_if_c);
|
||||
i_arbiter.err_align <= i_misaligned;
|
||||
i_arbiter.err_bus <= '0';
|
||||
else -- in progres
|
||||
i_arbiter.err_align <= (i_arbiter.err_align or i_misaligned) and (not ctrl_i(ctrl_bus_ierr_ack_c));
|
||||
i_arbiter.err_bus <= (i_arbiter.err_bus or i_bus_err_i or if_pmp_fault) and (not ctrl_i(ctrl_bus_ierr_ack_c));
|
||||
if (i_bus_ack_i = '1') or (ctrl_i(ctrl_bus_ierr_ack_c) = '1') then -- wait for normal termination / CPU abort
|
||||
i_arbiter.rd_req <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process ifetch_arbiter;
|
||||
|
||||
i_arbiter.wr_req <= '0'; -- instruction fetch is read-only
|
||||
|
||||
-- wait for bus transaction to finish --
|
||||
i_wait_o <= i_arbiter.rd_req and (not i_bus_ack_i);
|
||||
|
||||
-- output instruction fetch error to controller --
|
||||
ma_instr_o <= i_arbiter.err_align;
|
||||
be_instr_o <= i_arbiter.err_bus;
|
||||
|
||||
-- instruction bus (read-only) --
|
||||
i_bus_addr_o <= fetch_pc_i(data_width_c-1 downto 2) & "00"; -- instruction access is always 4-byte aligned (even for compressed instructions)
|
||||
i_bus_wdata_o <= (others => '0'); -- instruction fetch is read-only
|
||||
i_bus_ben_o <= (others => '0');
|
||||
i_bus_we_o <= '0';
|
||||
i_bus_re <= ctrl_i(ctrl_bus_if_c) and (not i_misaligned) and (not if_pmp_fault); -- no actual read when misaligned or PMP fault
|
||||
i_bus_re_o <= i_bus_re_buf when (PMP_NUM_REGIONS > pmp_num_regions_critical_c) else i_bus_re;
|
||||
i_bus_fence_o <= ctrl_i(ctrl_bus_fencei_c);
|
||||
instr_o <= i_bus_rdata_i;
|
||||
|
||||
-- check instruction access address alignment --
|
||||
i_misaligned <= '0' when (CPU_EXTENSION_RISCV_C = true) else -- no alignment exceptions possible when using C-extension
|
||||
'1' when (fetch_pc_i(1) = '1') else '0'; -- 32-bit accesses only
|
||||
|
||||
-- additional register stage for control signals if using PMP_NUM_REGIONS > pmp_num_regions_critical_c --
|
||||
pmp_ibus_buffer: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
i_bus_re_buf <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
i_bus_re_buf <= i_bus_re;
|
||||
end if;
|
||||
end process pmp_ibus_buffer;
|
||||
|
||||
|
||||
-- Physical Memory Protection (PMP) -------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- compute address masks (ITERATIVE!!!) --
|
||||
pmp_masks: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
pmp.addr_mask <= (others => (others => def_rst_val_c));
|
||||
elsif rising_edge(clk_i) then -- address mask computation (not the actual address check!) has a latency of max +32 cycles
|
||||
for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
|
||||
pmp.addr_mask(r) <= (others => '0');
|
||||
for i in pmp_g_c to data_width_c-1 loop
|
||||
pmp.addr_mask(r)(i) <= pmp.addr_mask(r)(i-1) or (not pmp_addr_i(r)(i-1));
|
||||
end loop; -- i
|
||||
end loop; -- r
|
||||
end if;
|
||||
end process pmp_masks;
|
||||
|
||||
|
||||
-- address access check --
|
||||
pmp_address_check:
|
||||
for r in 0 to PMP_NUM_REGIONS-1 generate -- iterate over all regions
|
||||
pmp.region_i_addr(r) <= fetch_pc_i and pmp.addr_mask(r);
|
||||
pmp.region_d_addr(r) <= mar and pmp.addr_mask(r);
|
||||
pmp.region_base(r) <= pmp_addr_i(r)(data_width_c+1 downto 2) and pmp.addr_mask(r);
|
||||
--
|
||||
pmp.i_match(r) <= '1' when (pmp.region_i_addr(r)(data_width_c-1 downto pmp_g_c) = pmp.region_base(r)(data_width_c-1 downto pmp_g_c)) else '0';
|
||||
pmp.d_match(r) <= '1' when (pmp.region_d_addr(r)(data_width_c-1 downto pmp_g_c) = pmp.region_base(r)(data_width_c-1 downto pmp_g_c)) else '0';
|
||||
end generate; -- r
|
||||
|
||||
|
||||
-- check access type and region's permissions --
|
||||
pmp_check_permission: process(pmp, pmp_ctrl_i, ctrl_i)
|
||||
begin
|
||||
for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
|
||||
if ((ctrl_i(ctrl_priv_lvl_msb_c downto ctrl_priv_lvl_lsb_c) = priv_mode_u_c) or (pmp_ctrl_i(r)(pmp_cfg_l_c) = '1')) and -- user privilege level or locked pmp entry -> enforce permissions also for machine mode
|
||||
(pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) /= pmp_off_mode_c) and -- active entry
|
||||
(ctrl_i(ctrl_debug_running_c) = '0') then -- disable PMP checks when in debug mode
|
||||
pmp.if_fault(r) <= pmp.i_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_x_c)); -- fetch access match no execute permission
|
||||
pmp.ld_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_r_c)); -- load access match no read permission
|
||||
pmp.st_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_w_c)); -- store access match no write permission
|
||||
else
|
||||
pmp.if_fault(r) <= '0';
|
||||
pmp.ld_fault(r) <= '0';
|
||||
pmp.st_fault(r) <= '0';
|
||||
end if;
|
||||
end loop; -- r
|
||||
end process pmp_check_permission;
|
||||
|
||||
|
||||
-- final PMP access fault signals --
|
||||
if_pmp_fault <= or_reduce_f(pmp.if_fault) when (PMP_NUM_REGIONS > 0) else '0';
|
||||
ld_pmp_fault <= or_reduce_f(pmp.ld_fault) when (PMP_NUM_REGIONS > 0) else '0';
|
||||
st_pmp_fault <= or_reduce_f(pmp.st_fault) when (PMP_NUM_REGIONS > 0) else '0';
|
||||
|
||||
|
||||
end neorv32_cpu_bus_rtl;
|
2835
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_control.vhd
Normal file
2835
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_control.vhd
Normal file
File diff suppressed because it is too large
Load Diff
469
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_bitmanip.vhd
Normal file
469
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_bitmanip.vhd
Normal file
@ -0,0 +1,469 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - CPU Co-Processor: Bit-Manipulation Co-Processor Unit (RISC-V "B" Extension) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # The bit manipulation unit is implemented as co-processor that has a processing latency of 1 #
|
||||
-- # cycle for logic/arithmetic operations and 3+shamt (=shift amount) cycles for shift(-related) #
|
||||
-- # operations. Use the FAST_SHIFT_EN option to reduce shift-related instruction's latency to a #
|
||||
-- # fixed value of 3 cycles latency (using barrel shifters). #
|
||||
-- # #
|
||||
-- # Supported sub-extensions (Zb*): #
|
||||
-- # - Zba: Address generation instructions #
|
||||
-- # - Zbb: Basic bit-manipulation instructions #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu_cp_bitmanip is
|
||||
generic (
|
||||
FAST_SHIFT_EN : boolean -- use barrel shifter for shift operations
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
||||
start_i : in std_ulogic; -- trigger operation
|
||||
-- data input --
|
||||
cmp_i : in std_ulogic_vector(1 downto 0); -- comparator status
|
||||
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
||||
rs2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 2
|
||||
shamt_i : in std_ulogic_vector(index_size_f(data_width_c)-1 downto 0); -- shift amount
|
||||
-- result and status --
|
||||
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- operation result
|
||||
valid_o : out std_ulogic -- data output valid
|
||||
);
|
||||
end neorv32_cpu_cp_bitmanip;
|
||||
|
||||
architecture neorv32_cpu_cp_bitmanip_rtl of neorv32_cpu_cp_bitmanip is
|
||||
|
||||
-- Sub-extension configuration --
|
||||
constant zbb_en_c : boolean := true;
|
||||
constant zba_en_c : boolean := true;
|
||||
-- --------------------------- --
|
||||
|
||||
-- commands: Zbb - logic with negate --
|
||||
constant op_andn_c : natural := 0;
|
||||
constant op_orn_c : natural := 1;
|
||||
constant op_xnor_c : natural := 2;
|
||||
-- commands: Zbb - count leading/trailing zero bits --
|
||||
constant op_clz_c : natural := 3;
|
||||
constant op_ctz_c : natural := 4;
|
||||
-- commands: Zbb - count population --
|
||||
constant op_cpop_c : natural := 5;
|
||||
-- commands: Zbb - integer minimum/maximum --
|
||||
constant op_max_c : natural := 6; -- signed/unsigned
|
||||
constant op_min_c : natural := 7; -- signed/unsigned
|
||||
-- commands: Zbb - sign- and zero-extension --
|
||||
constant op_sextb_c : natural := 8;
|
||||
constant op_sexth_c : natural := 9;
|
||||
constant op_zexth_c : natural := 10;
|
||||
-- commands: Zbb - bitwise rotation --
|
||||
constant op_rol_c : natural := 11;
|
||||
constant op_ror_c : natural := 12; -- rori
|
||||
-- commands: Zbb - or-combine --
|
||||
constant op_orcb_c : natural := 13;
|
||||
-- commands: Zbb - byte-reverse --
|
||||
constant op_rev8_c : natural := 14;
|
||||
-- commands: Zba - shifted add --
|
||||
constant op_sh1add_c : natural := 15;
|
||||
constant op_sh2add_c : natural := 16;
|
||||
constant op_sh3add_c : natural := 17;
|
||||
--
|
||||
constant op_width_c : natural := 18;
|
||||
|
||||
-- controller --
|
||||
type ctrl_state_t is (S_IDLE, S_START_SHIFT, S_BUSY_SHIFT);
|
||||
signal ctrl_state : ctrl_state_t;
|
||||
signal cmd, cmd_buf : std_ulogic_vector(op_width_c-1 downto 0);
|
||||
signal valid : std_ulogic;
|
||||
|
||||
-- operand buffers --
|
||||
signal rs1_reg : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal rs2_reg : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal sha_reg : std_ulogic_vector(index_size_f(data_width_c)-1 downto 0);
|
||||
signal less_ff : std_ulogic;
|
||||
|
||||
-- serial shifter --
|
||||
type shifter_t is record
|
||||
start : std_ulogic;
|
||||
run : std_ulogic;
|
||||
bcnt : std_ulogic_vector(index_size_f(data_width_c) downto 0); -- bit counter
|
||||
cnt : std_ulogic_vector(index_size_f(data_width_c) downto 0); -- iteration counter
|
||||
cnt_max : std_ulogic_vector(index_size_f(data_width_c) downto 0);
|
||||
sreg : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
end record;
|
||||
signal shifter : shifter_t;
|
||||
|
||||
-- barrel shifter --
|
||||
type bs_level_t is array (index_size_f(data_width_c) downto 0) of std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal bs_level : bs_level_t;
|
||||
|
||||
-- operation results --
|
||||
type res_t is array (0 to op_width_c-1) of std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal res_int, res_out : res_t;
|
||||
|
||||
-- shifted-add unit --
|
||||
signal adder_core : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sub-Extension Configuration ------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert false report
|
||||
"Implementing bit-manipulation (B) sub-extensions: " &
|
||||
cond_sel_string_f(zbb_en_c, "Zbb", "") &
|
||||
cond_sel_string_f(zba_en_c, "Zba", "") &
|
||||
""
|
||||
severity note;
|
||||
|
||||
|
||||
-- Instruction Decoding (One-Hot) ---------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- a minimal decoding logic is used here -> just to distinguish between B.Zbb instructions
|
||||
-- a more specific decoding and instruction check is done by the CPU control unit
|
||||
|
||||
-- Zbb - Basic bit-manipulation instructions --
|
||||
cmd(op_andn_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "10") and (ctrl_i(ctrl_ir_funct3_1_c downto ctrl_ir_funct3_0_c) = "11") else '0';
|
||||
cmd(op_orn_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "10") and (ctrl_i(ctrl_ir_funct3_1_c downto ctrl_ir_funct3_0_c) = "10") else '0';
|
||||
cmd(op_xnor_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "10") and (ctrl_i(ctrl_ir_funct3_1_c downto ctrl_ir_funct3_0_c) = "00") else '0';
|
||||
--
|
||||
cmd(op_max_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "00") and (ctrl_i(ctrl_ir_funct12_5_c) = '1') and (ctrl_i(ctrl_ir_funct3_1_c) = '1') else '0';
|
||||
cmd(op_min_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "00") and (ctrl_i(ctrl_ir_funct12_5_c) = '1') and (ctrl_i(ctrl_ir_funct3_1_c) = '0') else '0';
|
||||
cmd(op_zexth_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "00") and (ctrl_i(ctrl_ir_funct12_5_c) = '0') else '0';
|
||||
--
|
||||
cmd(op_orcb_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "01") and (ctrl_i(ctrl_ir_funct12_7_c) = '1') else '0';
|
||||
--
|
||||
cmd(op_clz_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct12_2_c downto ctrl_ir_funct12_0_c) = "000") else '0';
|
||||
cmd(op_ctz_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct12_2_c downto ctrl_ir_funct12_0_c) = "001") else '0';
|
||||
cmd(op_cpop_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct12_2_c downto ctrl_ir_funct12_0_c) = "010") else '0';
|
||||
cmd(op_sextb_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct3_2_c) = '0') and (ctrl_i(ctrl_ir_funct12_2_c downto ctrl_ir_funct12_0_c) = "100") else '0';
|
||||
cmd(op_sexth_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct3_2_c) = '0') and (ctrl_i(ctrl_ir_funct12_2_c downto ctrl_ir_funct12_0_c) = "101") else '0';
|
||||
cmd(op_rol_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) = "001") and (ctrl_i(ctrl_ir_opcode7_5_c) = '1') else '0';
|
||||
cmd(op_ror_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) = "101") else '0';
|
||||
cmd(op_rev8_c) <= '1' when (zbb_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "11") and (ctrl_i(ctrl_ir_funct12_7_c) = '1') else '0';
|
||||
|
||||
-- Zba - Address generation instructions --
|
||||
cmd(op_sh1add_c) <= '1' when (zba_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "01") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_1_c) = "01") else '0';
|
||||
cmd(op_sh2add_c) <= '1' when (zba_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "01") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_1_c) = "10") else '0';
|
||||
cmd(op_sh3add_c) <= '1' when (zba_en_c = true) and (ctrl_i(ctrl_ir_funct12_10_c downto ctrl_ir_funct12_9_c) = "01") and (ctrl_i(ctrl_ir_funct12_7_c) = '0') and (ctrl_i(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_1_c) = "11") else '0';
|
||||
|
||||
|
||||
-- Co-Processor Controller ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
coprocessor_ctrl: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
ctrl_state <= S_IDLE;
|
||||
cmd_buf <= (others => def_rst_val_c);
|
||||
rs1_reg <= (others => def_rst_val_c);
|
||||
rs2_reg <= (others => def_rst_val_c);
|
||||
sha_reg <= (others => def_rst_val_c);
|
||||
less_ff <= def_rst_val_c;
|
||||
shifter.start <= '0';
|
||||
valid <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
-- defaults --
|
||||
shifter.start <= '0';
|
||||
valid <= '0';
|
||||
|
||||
-- fsm --
|
||||
case ctrl_state is
|
||||
|
||||
when S_IDLE => -- wait for operation trigger
|
||||
-- ------------------------------------------------------------
|
||||
if (start_i = '1') then
|
||||
less_ff <= cmp_i(cmp_less_c);
|
||||
cmd_buf <= cmd;
|
||||
rs1_reg <= rs1_i;
|
||||
rs2_reg <= rs2_i;
|
||||
sha_reg <= shamt_i;
|
||||
if ((cmd(op_clz_c) or cmd(op_ctz_c) or cmd(op_cpop_c) or cmd(op_ror_c) or cmd(op_rol_c)) = '1') then -- multi-cycle shift operation
|
||||
if (FAST_SHIFT_EN = false) then -- default: iterative computation
|
||||
shifter.start <= '1';
|
||||
ctrl_state <= S_START_SHIFT;
|
||||
else -- full-parallel computation
|
||||
ctrl_state <= S_BUSY_SHIFT;
|
||||
end if;
|
||||
else
|
||||
valid <= '1';
|
||||
ctrl_state <= S_IDLE;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when S_START_SHIFT => -- one cycle delay to start shift operation
|
||||
-- ------------------------------------------------------------
|
||||
ctrl_state <= S_BUSY_SHIFT;
|
||||
|
||||
when S_BUSY_SHIFT => -- wait for multi-cycle shift operation to finish
|
||||
-- ------------------------------------------------------------
|
||||
if (shifter.run = '0') then
|
||||
valid <= '1';
|
||||
ctrl_state <= S_IDLE;
|
||||
end if;
|
||||
|
||||
when others => -- undefined
|
||||
-- ------------------------------------------------------------
|
||||
ctrl_state <= S_IDLE;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
end process coprocessor_ctrl;
|
||||
|
||||
|
||||
-- Shifter Function Core (iterative: small but slow) --------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
serial_shifter:
|
||||
if (FAST_SHIFT_EN = false) generate
|
||||
shifter_unit: process(rstn_i, clk_i)
|
||||
variable new_bit_v : std_ulogic;
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
shifter.cnt <= (others => def_rst_val_c);
|
||||
shifter.sreg <= (others => def_rst_val_c);
|
||||
shifter.cnt_max <= (others => def_rst_val_c);
|
||||
shifter.bcnt <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
if (shifter.start = '1') then -- trigger new shift
|
||||
shifter.cnt <= (others => '0');
|
||||
-- shift operand --
|
||||
if (cmd_buf(op_clz_c) = '1') or (cmd_buf(op_rol_c) = '1') then -- count LEADING zeros / rotate LEFT
|
||||
shifter.sreg <= bit_rev_f(rs1_reg); -- reverse - we can only do right shifts here
|
||||
else -- ctz, cpop, ror
|
||||
shifter.sreg <= rs1_reg;
|
||||
end if;
|
||||
-- max shift amount --
|
||||
if (cmd_buf(op_cpop_c) = '1') then -- population count
|
||||
shifter.cnt_max <= (others => '0');
|
||||
shifter.cnt_max(shifter.cnt_max'left) <= '1';
|
||||
else
|
||||
shifter.cnt_max <= '0' & sha_reg;
|
||||
end if;
|
||||
shifter.bcnt <= (others => '0');
|
||||
elsif (shifter.run = '1') then -- right shifts only
|
||||
new_bit_v := ((cmd_buf(op_ror_c) or cmd_buf(op_rol_c)) and shifter.sreg(0)) or (cmd_buf(op_clz_c) or cmd_buf(op_ctz_c));
|
||||
shifter.sreg <= new_bit_v & shifter.sreg(shifter.sreg'left downto 1); -- ro[r/l]/lsr(for counting)
|
||||
shifter.cnt <= std_ulogic_vector(unsigned(shifter.cnt) + 1); -- iteration counter
|
||||
if (shifter.sreg(0) = '1') then
|
||||
shifter.bcnt <= std_ulogic_vector(unsigned(shifter.bcnt) + 1); -- bit counter
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process shifter_unit;
|
||||
end generate;
|
||||
|
||||
-- run control --
|
||||
serial_shifter_ctrl:
|
||||
if (FAST_SHIFT_EN = false) generate
|
||||
shifter_unit_ctrl: process(cmd_buf, shifter)
|
||||
begin
|
||||
-- keep shifting until ... --
|
||||
if (cmd_buf(op_clz_c) = '1') or (cmd_buf(op_ctz_c) = '1') then -- count leading/trailing zeros
|
||||
shifter.run <= not shifter.sreg(0);
|
||||
else -- population count / rotate
|
||||
if (shifter.cnt = shifter.cnt_max) then
|
||||
shifter.run <= '0';
|
||||
else
|
||||
shifter.run <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end process shifter_unit_ctrl;
|
||||
end generate;
|
||||
|
||||
|
||||
-- Shifter Function Core (parallel: fast but large) ---------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
barrel_shifter_async_sync:
|
||||
if (FAST_SHIFT_EN = true) generate
|
||||
shifter_unit_fast: process(rstn_i, clk_i)
|
||||
variable new_bit_v : std_ulogic;
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
shifter.cnt <= (others => def_rst_val_c);
|
||||
shifter.sreg <= (others => def_rst_val_c);
|
||||
shifter.bcnt <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
-- population count --
|
||||
shifter.bcnt <= std_ulogic_vector(to_unsigned(popcount_f(rs1_reg), shifter.bcnt'length));
|
||||
-- count leading/trailing zeros --
|
||||
if cmd_buf(op_clz_c) = '1' then -- leading
|
||||
shifter.cnt <= std_ulogic_vector(to_unsigned(leading_zeros_f(rs1_reg), shifter.cnt'length));
|
||||
else -- trailing
|
||||
shifter.cnt <= std_ulogic_vector(to_unsigned(leading_zeros_f(bit_rev_f(rs1_reg)), shifter.cnt'length));
|
||||
end if;
|
||||
-- barrel shifter --
|
||||
shifter.sreg <= bs_level(0); -- rol/ror[i]
|
||||
end if;
|
||||
end process shifter_unit_fast;
|
||||
shifter.run <= '0'; -- we are done already!
|
||||
end generate;
|
||||
|
||||
-- barrel shifter array --
|
||||
barrel_shifter_async:
|
||||
if (FAST_SHIFT_EN = true) generate
|
||||
shifter_unit_async: process(rs1_reg, sha_reg, cmd_buf, bs_level)
|
||||
begin
|
||||
-- input level: convert left shifts to right shifts --
|
||||
if (cmd_buf(op_rol_c) = '1') then -- is left shift?
|
||||
bs_level(index_size_f(data_width_c)) <= bit_rev_f(rs1_reg); -- reverse bit order of input operand
|
||||
else
|
||||
bs_level(index_size_f(data_width_c)) <= rs1_reg;
|
||||
end if;
|
||||
|
||||
-- shifter array --
|
||||
for i in index_size_f(data_width_c)-1 downto 0 loop
|
||||
if (sha_reg(i) = '1') then
|
||||
bs_level(i)(data_width_c-1 downto data_width_c-(2**i)) <= bs_level(i+1)((2**i)-1 downto 0);
|
||||
bs_level(i)((data_width_c-(2**i))-1 downto 0) <= bs_level(i+1)(data_width_c-1 downto 2**i);
|
||||
else
|
||||
bs_level(i) <= bs_level(i+1);
|
||||
end if;
|
||||
end loop;
|
||||
end process shifter_unit_async;
|
||||
end generate;
|
||||
|
||||
|
||||
-- Shifted-Add Core -----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
shift_adder: process(rs1_reg, rs2_reg, ctrl_i)
|
||||
variable opb_v : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
begin
|
||||
case ctrl_i(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_1_c) is
|
||||
when "01" => opb_v := rs1_reg(rs1_reg'left-1 downto 0) & '0'; -- << 1
|
||||
when "10" => opb_v := rs1_reg(rs1_reg'left-2 downto 0) & "00"; -- << 2
|
||||
when "11" => opb_v := rs1_reg(rs1_reg'left-3 downto 0) & "000"; -- << 3
|
||||
when others => opb_v := rs1_reg(rs1_reg'left-1 downto 0) & '0'; -- undefined
|
||||
end case;
|
||||
adder_core <= std_ulogic_vector(unsigned(rs2_reg) + unsigned(opb_v));
|
||||
end process shift_adder;
|
||||
|
||||
|
||||
-- Operation Results ----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- logic with negate --
|
||||
res_int(op_andn_c) <= rs1_reg and (not rs2_reg); -- logical and-not
|
||||
res_int(op_orn_c) <= rs1_reg or (not rs2_reg); -- logical or-not
|
||||
res_int(op_xnor_c) <= rs1_reg xor (not rs2_reg); -- logical xor-not
|
||||
|
||||
-- count leading/trailing zeros --
|
||||
res_int(op_clz_c)(data_width_c-1 downto shifter.cnt'left+1) <= (others => '0');
|
||||
res_int(op_clz_c)(shifter.cnt'left downto 0) <= shifter.cnt;
|
||||
res_int(op_ctz_c) <= (others => '0'); -- unused/redundant
|
||||
|
||||
-- count set bits --
|
||||
res_int(op_cpop_c)(data_width_c-1 downto shifter.bcnt'left+1) <= (others => '0');
|
||||
res_int(op_cpop_c)(shifter.bcnt'left downto 0) <= shifter.bcnt;
|
||||
|
||||
-- min/max select --
|
||||
res_int(op_min_c) <= rs1_reg when ((less_ff xor cmd_buf(op_max_c)) = '1') else rs2_reg;
|
||||
res_int(op_max_c) <= (others => '0'); -- unused/redundant
|
||||
|
||||
-- sign-extension --
|
||||
res_int(op_sextb_c)(data_width_c-1 downto 8) <= (others => rs1_reg(7));
|
||||
res_int(op_sextb_c)(7 downto 0) <= rs1_reg(7 downto 0); -- sign-extend byte
|
||||
res_int(op_sexth_c)(data_width_c-1 downto 16) <= (others => rs1_reg(15));
|
||||
res_int(op_sexth_c)(15 downto 0) <= rs1_reg(15 downto 0); -- sign-extend half-word
|
||||
res_int(op_zexth_c)(data_width_c-1 downto 16) <= (others => '0');
|
||||
res_int(op_zexth_c)(15 downto 0) <= rs1_reg(15 downto 0); -- zero-extend half-word
|
||||
|
||||
-- rotate right/left --
|
||||
res_int(op_ror_c) <= shifter.sreg;
|
||||
res_int(op_rol_c) <= bit_rev_f(shifter.sreg); -- reverse to compensate internal right-only shifts
|
||||
|
||||
-- or-combine.byte --
|
||||
or_combine_gen:
|
||||
for i in 0 to (data_width_c/8)-1 generate -- sub-byte loop
|
||||
res_int(op_orcb_c)(i*8+7 downto i*8) <= (others => or_reduce_f(rs1_reg(i*8+7 downto i*8)));
|
||||
end generate; -- i
|
||||
|
||||
-- reversal.8 (byte swap) --
|
||||
res_int(op_rev8_c) <= bswap32_f(rs1_reg);
|
||||
|
||||
-- address generation instructions --
|
||||
res_int(op_sh1add_c) <= adder_core;
|
||||
res_int(op_sh2add_c) <= (others => '0'); -- unused/redundant
|
||||
res_int(op_sh3add_c) <= (others => '0'); -- unused/redundant
|
||||
|
||||
|
||||
-- Output Selector ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
res_out(op_andn_c) <= res_int(op_andn_c) when (cmd_buf(op_andn_c) = '1') else (others => '0');
|
||||
res_out(op_orn_c) <= res_int(op_orn_c) when (cmd_buf(op_orn_c) = '1') else (others => '0');
|
||||
res_out(op_xnor_c) <= res_int(op_xnor_c) when (cmd_buf(op_xnor_c) = '1') else (others => '0');
|
||||
res_out(op_clz_c) <= res_int(op_clz_c) when ((cmd_buf(op_clz_c) or cmd_buf(op_ctz_c)) = '1') else (others => '0');
|
||||
res_out(op_ctz_c) <= (others => '0'); -- unused/redundant
|
||||
res_out(op_cpop_c) <= res_int(op_cpop_c) when (cmd_buf(op_cpop_c) = '1') else (others => '0');
|
||||
res_out(op_min_c) <= res_int(op_min_c) when ((cmd_buf(op_min_c) or cmd_buf(op_max_c)) = '1') else (others => '0');
|
||||
res_out(op_max_c) <= (others => '0'); -- unused/redundant
|
||||
res_out(op_sextb_c) <= res_int(op_sextb_c) when (cmd_buf(op_sextb_c) = '1') else (others => '0');
|
||||
res_out(op_sexth_c) <= res_int(op_sexth_c) when (cmd_buf(op_sexth_c) = '1') else (others => '0');
|
||||
res_out(op_zexth_c) <= res_int(op_zexth_c) when (cmd_buf(op_zexth_c) = '1') else (others => '0');
|
||||
res_out(op_ror_c) <= res_int(op_ror_c) when (cmd_buf(op_ror_c) = '1') else (others => '0');
|
||||
res_out(op_rol_c) <= res_int(op_rol_c) when (cmd_buf(op_rol_c) = '1') else (others => '0');
|
||||
res_out(op_orcb_c) <= res_int(op_orcb_c) when (cmd_buf(op_orcb_c) = '1') else (others => '0');
|
||||
res_out(op_rev8_c) <= res_int(op_rev8_c) when (cmd_buf(op_rev8_c) = '1') else (others => '0');
|
||||
--
|
||||
res_out(op_sh1add_c) <= res_int(op_sh1add_c) when ((cmd_buf(op_sh1add_c) or cmd_buf(op_sh2add_c) or cmd_buf(op_sh3add_c)) = '1') else (others => '0');
|
||||
res_out(op_sh2add_c) <= (others => '0'); -- unused/redundant
|
||||
res_out(op_sh3add_c) <= (others => '0'); -- unused/redundant
|
||||
|
||||
|
||||
-- Output Gate ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
output_gate: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
res_o <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
res_o <= (others => '0');
|
||||
if (valid = '1') then
|
||||
res_o <= res_out(op_andn_c) or res_out(op_orn_c) or res_out(op_xnor_c) or
|
||||
res_out(op_clz_c) or res_out(op_cpop_c) or -- res_out(op_ctz_c) is unused here
|
||||
res_out(op_min_c) or -- res_out(op_max_c) is unused here
|
||||
res_out(op_sextb_c) or res_out(op_sexth_c) or res_out(op_zexth_c) or
|
||||
res_out(op_ror_c) or res_out(op_rol_c) or
|
||||
res_out(op_orcb_c) or res_out(op_rev8_c) or
|
||||
res_out(op_sh1add_c); -- res_out(op_sh2add_c) and res_out(op_sh3add_c) are unused here
|
||||
end if;
|
||||
end if;
|
||||
end process output_gate;
|
||||
|
||||
-- valid output --
|
||||
valid_o <= valid;
|
||||
|
||||
|
||||
end neorv32_cpu_cp_bitmanip_rtl;
|
1847
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_fpu.vhd
Normal file
1847
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_fpu.vhd
Normal file
File diff suppressed because it is too large
Load Diff
343
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_muldiv.vhd
Normal file
343
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_muldiv.vhd
Normal file
@ -0,0 +1,343 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - CPU Co-Processor: Integer Multiplier/Divider Unit (RISC-V "M" Extension) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Multiplier and Divider unit. Implements the RISC-V M CPU extension. #
|
||||
-- # #
|
||||
-- # Multiplier core (signed/unsigned) uses classical serial algorithm. Unit latency: 31+3 cycles #
|
||||
-- # Divider core (unsigned) uses classical serial algorithm. Unit latency: 32+4 cycles #
|
||||
-- # #
|
||||
-- # Multiplications can be mapped to DSP blocks (faster!) when FAST_MUL_EN = true. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu_cp_muldiv is
|
||||
generic (
|
||||
FAST_MUL_EN : boolean; -- use DSPs for faster multiplication
|
||||
DIVISION_EN : boolean -- implement divider hardware
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
||||
start_i : in std_ulogic; -- trigger operation
|
||||
-- data input --
|
||||
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
||||
rs2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 2
|
||||
-- result and status --
|
||||
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- operation result
|
||||
valid_o : out std_ulogic -- data output valid
|
||||
);
|
||||
end neorv32_cpu_cp_muldiv;
|
||||
|
||||
architecture neorv32_cpu_cp_muldiv_rtl of neorv32_cpu_cp_muldiv is
|
||||
|
||||
-- operations --
|
||||
constant cp_op_mul_c : std_ulogic_vector(2 downto 0) := "000"; -- mul
|
||||
constant cp_op_mulh_c : std_ulogic_vector(2 downto 0) := "001"; -- mulh
|
||||
constant cp_op_mulhsu_c : std_ulogic_vector(2 downto 0) := "010"; -- mulhsu
|
||||
constant cp_op_mulhu_c : std_ulogic_vector(2 downto 0) := "011"; -- mulhu
|
||||
constant cp_op_div_c : std_ulogic_vector(2 downto 0) := "100"; -- div
|
||||
constant cp_op_divu_c : std_ulogic_vector(2 downto 0) := "101"; -- divu
|
||||
constant cp_op_rem_c : std_ulogic_vector(2 downto 0) := "110"; -- rem
|
||||
constant cp_op_remu_c : std_ulogic_vector(2 downto 0) := "111"; -- remu
|
||||
|
||||
-- controller --
|
||||
type state_t is (IDLE, DIV_PREPROCESS, PROCESSING, FINALIZE);
|
||||
signal state : state_t;
|
||||
signal cnt : std_ulogic_vector(4 downto 0);
|
||||
signal cp_op : std_ulogic_vector(2 downto 0); -- operation to execute
|
||||
signal cp_op_ff : std_ulogic_vector(2 downto 0); -- operation that was executed
|
||||
signal start_div : std_ulogic;
|
||||
signal start_mul : std_ulogic;
|
||||
signal operation : std_ulogic;
|
||||
signal div_opy : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal rs1_is_signed : std_ulogic;
|
||||
signal rs2_is_signed : std_ulogic;
|
||||
signal opy_is_zero : std_ulogic;
|
||||
signal div_res_corr : std_ulogic;
|
||||
signal out_en : std_ulogic;
|
||||
|
||||
-- divider core --
|
||||
signal remainder : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal quotient : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal div_sub : std_ulogic_vector(data_width_c downto 0);
|
||||
signal div_sign_comp_in : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal div_sign_comp : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal div_res : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
|
||||
-- multiplier core --
|
||||
signal mul_product : std_ulogic_vector(63 downto 0);
|
||||
signal mul_do_add : std_ulogic_vector(data_width_c downto 0);
|
||||
signal mul_sign_cycle : std_ulogic;
|
||||
signal mul_p_sext : std_ulogic;
|
||||
signal mul_op_x : signed(32 downto 0); -- for using DSPs
|
||||
signal mul_op_y : signed(32 downto 0); -- for using DSPs
|
||||
|
||||
begin
|
||||
|
||||
-- Co-Processor Controller ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
coprocessor_ctrl: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
state <= IDLE;
|
||||
div_opy <= (others => def_rst_val_c);
|
||||
cnt <= (others => def_rst_val_c);
|
||||
cp_op_ff <= (others => def_rst_val_c);
|
||||
start_div <= '0';
|
||||
out_en <= '0';
|
||||
valid_o <= '0';
|
||||
div_res_corr <= def_rst_val_c;
|
||||
opy_is_zero <= def_rst_val_c;
|
||||
elsif rising_edge(clk_i) then
|
||||
-- defaults --
|
||||
start_div <= '0';
|
||||
out_en <= '0';
|
||||
valid_o <= '0';
|
||||
|
||||
-- FSM --
|
||||
case state is
|
||||
|
||||
when IDLE =>
|
||||
cp_op_ff <= cp_op;
|
||||
cnt <= "11110";
|
||||
if (start_i = '1') then
|
||||
if (operation = '1') and (DIVISION_EN = true) then -- division
|
||||
start_div <= '1';
|
||||
state <= DIV_PREPROCESS;
|
||||
else -- multiplication
|
||||
if (FAST_MUL_EN = true) then
|
||||
valid_o <= '1';
|
||||
state <= FINALIZE;
|
||||
else
|
||||
state <= PROCESSING;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when DIV_PREPROCESS =>
|
||||
-- check relevant input signs --
|
||||
if (cp_op = cp_op_div_c) then -- result sign compensation for div?
|
||||
div_res_corr <= rs1_i(rs1_i'left) xor rs2_i(rs2_i'left);
|
||||
elsif (cp_op = cp_op_rem_c) then -- result sign compensation for rem?
|
||||
div_res_corr <= rs1_i(rs1_i'left);
|
||||
else
|
||||
div_res_corr <= '0';
|
||||
end if;
|
||||
-- divide by zero? --
|
||||
opy_is_zero <= not or_reduce_f(rs2_i); -- set if rs2 = 0
|
||||
-- abs(rs2) --
|
||||
if ((rs2_i(rs2_i'left) and rs2_is_signed) = '1') then -- signed division?
|
||||
div_opy <= std_ulogic_vector(0 - unsigned(rs2_i)); -- make positive
|
||||
else
|
||||
div_opy <= rs2_i;
|
||||
end if;
|
||||
--
|
||||
state <= PROCESSING;
|
||||
|
||||
when PROCESSING =>
|
||||
cnt <= std_ulogic_vector(unsigned(cnt) - 1);
|
||||
if (cnt = "00000") then
|
||||
valid_o <= '1';
|
||||
state <= FINALIZE;
|
||||
end if;
|
||||
|
||||
when FINALIZE =>
|
||||
out_en <= '1';
|
||||
state <= IDLE;
|
||||
|
||||
when others =>
|
||||
state <= IDLE;
|
||||
end case;
|
||||
end if;
|
||||
end process coprocessor_ctrl;
|
||||
|
||||
-- co-processor command --
|
||||
cp_op <= ctrl_i(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c);
|
||||
|
||||
-- operation: 0=mul, 1=div --
|
||||
operation <= '1' when (cp_op(2) = '1') else '0';
|
||||
|
||||
-- opx (rs1) signed? --
|
||||
rs1_is_signed <= '1' when (cp_op = cp_op_mulh_c) or (cp_op = cp_op_mulhsu_c) or (cp_op = cp_op_div_c) or (cp_op = cp_op_rem_c) else '0';
|
||||
|
||||
-- opy (rs2) signed? --
|
||||
rs2_is_signed <= '1' when (cp_op = cp_op_mulh_c) or (cp_op = cp_op_div_c) or (cp_op = cp_op_rem_c) else '0';
|
||||
|
||||
-- start MUL operation (do it fast!) --
|
||||
start_mul <= '1' when (state = IDLE) and (start_i = '1') and (operation = '0') else '0';
|
||||
|
||||
|
||||
-- Multiplier Core (signed/unsigned) ------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- iterative multiplication (bit-serial) --
|
||||
multiplier_core_serial:
|
||||
if (FAST_MUL_EN = false) generate
|
||||
multiplier_core: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
mul_product <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
if (start_mul = '1') then -- start new multiplication
|
||||
mul_product(63 downto 32) <= (others => '0');
|
||||
mul_product(31 downto 00) <= rs2_i;
|
||||
elsif (state = PROCESSING) or (state = FINALIZE) then -- processing step or sign-finalization step
|
||||
mul_product(63 downto 31) <= mul_do_add(32 downto 0);
|
||||
mul_product(30 downto 00) <= mul_product(31 downto 1);
|
||||
end if;
|
||||
end if;
|
||||
end process multiplier_core;
|
||||
end generate;
|
||||
|
||||
-- parallel multiplication (using DSP blocks) --
|
||||
multiplier_core_dsp:
|
||||
if (FAST_MUL_EN = true) generate
|
||||
multiplier_core: process(clk_i)
|
||||
variable tmp_v : signed(65 downto 0);
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (start_mul = '1') then
|
||||
mul_op_x <= signed((rs1_i(rs1_i'left) and rs1_is_signed) & rs1_i);
|
||||
mul_op_y <= signed((rs2_i(rs2_i'left) and rs2_is_signed) & rs2_i);
|
||||
end if;
|
||||
tmp_v := mul_op_x * mul_op_y;
|
||||
mul_product <= std_ulogic_vector(tmp_v(63 downto 0));
|
||||
--mul_buf_ff <= mul_op_x * mul_op_y;
|
||||
--mul_product <= std_ulogic_vector(mul_buf_ff(63 downto 0)); -- let the register balancing do the magic here
|
||||
end if;
|
||||
end process multiplier_core;
|
||||
end generate;
|
||||
|
||||
-- do another addition (bit-serial) --
|
||||
mul_update: process(mul_product, mul_sign_cycle, mul_p_sext, rs1_is_signed, rs1_i)
|
||||
begin
|
||||
-- current bit of rs2_i to take care of --
|
||||
if (mul_product(0) = '1') then -- multiply with 1
|
||||
if (mul_sign_cycle = '1') then -- for signed operations only: take care of negative weighted MSB -> multiply with -1
|
||||
mul_do_add <= std_ulogic_vector(unsigned(mul_p_sext & mul_product(63 downto 32)) - unsigned((rs1_i(rs1_i'left) and rs1_is_signed) & rs1_i));
|
||||
else -- multiply with +1
|
||||
mul_do_add <= std_ulogic_vector(unsigned(mul_p_sext & mul_product(63 downto 32)) + unsigned((rs1_i(rs1_i'left) and rs1_is_signed) & rs1_i));
|
||||
end if;
|
||||
else -- multiply with 0
|
||||
mul_do_add <= mul_p_sext & mul_product(63 downto 32);
|
||||
end if;
|
||||
end process mul_update;
|
||||
|
||||
-- sign control --
|
||||
mul_sign_cycle <= rs2_is_signed when (state = FINALIZE) else '0';
|
||||
mul_p_sext <= mul_product(mul_product'left) and rs1_is_signed;
|
||||
|
||||
|
||||
-- Divider Core (unsigned) ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
divider_core_serial:
|
||||
if (DIVISION_EN = true) generate
|
||||
divider_core: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
quotient <= (others => def_rst_val_c);
|
||||
remainder <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
if (start_div = '1') then -- start new division
|
||||
if ((rs1_i(rs1_i'left) and rs1_is_signed) = '1') then -- signed division?
|
||||
quotient <= std_ulogic_vector(0 - unsigned(rs1_i)); -- make positive
|
||||
else
|
||||
quotient <= rs1_i;
|
||||
end if;
|
||||
remainder <= (others => '0');
|
||||
elsif (state = PROCESSING) or (state = FINALIZE) then -- running?
|
||||
quotient <= quotient(30 downto 0) & (not div_sub(32));
|
||||
if (div_sub(32) = '0') then -- still overflowing
|
||||
remainder <= div_sub(31 downto 0);
|
||||
else -- underflow
|
||||
remainder <= remainder(30 downto 0) & quotient(31);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process divider_core;
|
||||
|
||||
-- try another subtraction --
|
||||
div_sub <= std_ulogic_vector(unsigned('0' & remainder(30 downto 0) & quotient(31)) - unsigned('0' & div_opy));
|
||||
|
||||
-- result sign compensation --
|
||||
div_sign_comp_in <= quotient when (cp_op = cp_op_div_c) else remainder;
|
||||
div_sign_comp <= std_ulogic_vector(0 - unsigned(div_sign_comp_in));
|
||||
div_res <= div_sign_comp when (div_res_corr = '1') and (opy_is_zero = '0') else div_sign_comp_in;
|
||||
end generate;
|
||||
|
||||
-- no divider --
|
||||
divider_core_serial_none:
|
||||
if (DIVISION_EN = false) generate
|
||||
remainder <= (others => '0');
|
||||
quotient <= (others => '0');
|
||||
div_res <= (others => '0');
|
||||
end generate;
|
||||
|
||||
|
||||
-- Data Output ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
operation_result: process(out_en, cp_op_ff, mul_product, div_res, quotient, opy_is_zero, rs1_i, remainder)
|
||||
begin
|
||||
if (out_en = '1') then
|
||||
case cp_op_ff is
|
||||
when cp_op_mul_c =>
|
||||
res_o <= mul_product(31 downto 00);
|
||||
when cp_op_mulh_c | cp_op_mulhsu_c | cp_op_mulhu_c =>
|
||||
res_o <= mul_product(63 downto 32);
|
||||
when cp_op_div_c =>
|
||||
res_o <= div_res;
|
||||
when cp_op_divu_c =>
|
||||
res_o <= quotient;
|
||||
when cp_op_rem_c =>
|
||||
if (opy_is_zero = '0') then
|
||||
res_o <= div_res;
|
||||
else
|
||||
res_o <= rs1_i;
|
||||
end if;
|
||||
when others => -- cp_op_remu_c
|
||||
res_o <= remainder;
|
||||
end case;
|
||||
else
|
||||
res_o <= (others => '0');
|
||||
end if;
|
||||
end process operation_result;
|
||||
|
||||
|
||||
end neorv32_cpu_cp_muldiv_rtl;
|
181
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_shifter.vhd
Normal file
181
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_cp_shifter.vhd
Normal file
@ -0,0 +1,181 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - CPU Co-Processor: Shifter (CPU Core ISA) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Bit-shift unit for base ISA. #
|
||||
-- # FAST_SHIFT_EN = false (default): Use bit-serial shifter architecture (small but slow) #
|
||||
-- # FAST_SHIFT_EN = true: Use barrel shifter architecture (large but fast) #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu_cp_shifter is
|
||||
generic (
|
||||
FAST_SHIFT_EN : boolean -- use barrel shifter for shift operations
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
||||
start_i : in std_ulogic; -- trigger operation
|
||||
-- data input --
|
||||
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
||||
shamt_i : in std_ulogic_vector(index_size_f(data_width_c)-1 downto 0); -- shift amount
|
||||
-- result and status --
|
||||
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- operation result
|
||||
valid_o : out std_ulogic -- data output valid
|
||||
);
|
||||
end neorv32_cpu_cp_shifter;
|
||||
|
||||
architecture neorv32_cpu_cp_shifter_rtl of neorv32_cpu_cp_shifter is
|
||||
|
||||
-- serial shifter --
|
||||
type shifter_t is record
|
||||
busy : std_ulogic;
|
||||
busy_ff : std_ulogic;
|
||||
done : std_ulogic;
|
||||
cnt : std_ulogic_vector(index_size_f(data_width_c)-1 downto 0);
|
||||
sreg : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
res : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
end record;
|
||||
signal shifter : shifter_t;
|
||||
|
||||
-- barrel shifter --
|
||||
type bs_level_t is array (index_size_f(data_width_c) downto 0) of std_ulogic_vector(data_width_c-1 downto 0);
|
||||
signal bs_level : bs_level_t;
|
||||
signal bs_result : std_ulogic_vector(data_width_c-1 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Iterative Shifter Core (small but slow) ------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
serial_shifter_sync:
|
||||
if (FAST_SHIFT_EN = false) generate
|
||||
shifter_unit_sync: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
shifter.busy <= '0';
|
||||
shifter.busy_ff <= def_rst_val_c;
|
||||
shifter.sreg <= (others => def_rst_val_c);
|
||||
shifter.cnt <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
shifter.busy_ff <= shifter.busy;
|
||||
if (start_i = '1') then
|
||||
shifter.busy <= '1';
|
||||
elsif (shifter.done = '1') then
|
||||
shifter.busy <= '0';
|
||||
end if;
|
||||
--
|
||||
if (start_i = '1') then -- trigger new shift
|
||||
shifter.sreg <= rs1_i; -- shift operand
|
||||
shifter.cnt <= shamt_i; -- shift amount
|
||||
elsif (or_reduce_f(shifter.cnt) = '1') then -- running shift (cnt != 0)
|
||||
shifter.cnt <= std_ulogic_vector(unsigned(shifter.cnt) - 1);
|
||||
if (ctrl_i(ctrl_alu_shift_dir_c) = '0') then -- SLL: shift left logical
|
||||
shifter.sreg <= shifter.sreg(shifter.sreg'left-1 downto 0) & '0';
|
||||
else -- SRL: shift right logical / SRA: shift right arithmetical
|
||||
shifter.sreg <= (shifter.sreg(shifter.sreg'left) and ctrl_i(ctrl_alu_shift_ar_c)) & shifter.sreg(shifter.sreg'left downto 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process shifter_unit_sync;
|
||||
end generate;
|
||||
|
||||
-- shift control/output --
|
||||
serial_shifter_ctrl:
|
||||
if (FAST_SHIFT_EN = false) generate
|
||||
shifter.done <= not or_reduce_f(shifter.cnt(shifter.cnt'left downto 1));
|
||||
valid_o <= shifter.busy and shifter.done;
|
||||
res_o <= shifter.sreg when (shifter.busy = '0') and (shifter.busy_ff = '1') else (others => '0');
|
||||
end generate;
|
||||
|
||||
|
||||
-- Barrel Shifter Core (fast but large) ---------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
barrel_shifter_async:
|
||||
if (FAST_SHIFT_EN = true) generate
|
||||
shifter_unit_async: process(rs1_i, shamt_i, ctrl_i, bs_level)
|
||||
begin
|
||||
-- input level: convert left shifts to right shifts --
|
||||
if (ctrl_i(ctrl_alu_shift_dir_c) = '0') then -- is left shift?
|
||||
bs_level(index_size_f(data_width_c)) <= bit_rev_f(rs1_i); -- reverse bit order of input operand
|
||||
else
|
||||
bs_level(index_size_f(data_width_c)) <= rs1_i;
|
||||
end if;
|
||||
|
||||
-- shifter array --
|
||||
for i in index_size_f(data_width_c)-1 downto 0 loop
|
||||
if (shamt_i(i) = '1') then
|
||||
bs_level(i)(data_width_c-1 downto data_width_c-(2**i)) <= (others => (bs_level(i+1)(data_width_c-1) and ctrl_i(ctrl_alu_shift_ar_c)));
|
||||
bs_level(i)((data_width_c-(2**i))-1 downto 0) <= bs_level(i+1)(data_width_c-1 downto 2**i);
|
||||
else
|
||||
bs_level(i) <= bs_level(i+1);
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
-- re-convert original left shifts --
|
||||
if (ctrl_i(ctrl_alu_shift_dir_c) = '0') then
|
||||
bs_result <= bit_rev_f(bs_level(0));
|
||||
else
|
||||
bs_result <= bs_level(0);
|
||||
end if;
|
||||
end process shifter_unit_async;
|
||||
end generate;
|
||||
|
||||
-- output register --
|
||||
barrel_shifter_sync:
|
||||
if (FAST_SHIFT_EN = true) generate
|
||||
shifter_unit_sync: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
res_o <= (others => '0');
|
||||
if (start_i = '1') then
|
||||
res_o <= bs_result;
|
||||
end if;
|
||||
end if;
|
||||
end process shifter_unit_sync;
|
||||
end generate;
|
||||
|
||||
-- shift control/output --
|
||||
barrel_shifter_ctrl:
|
||||
if (FAST_SHIFT_EN = true) generate
|
||||
valid_o <= start_i;
|
||||
end generate;
|
||||
|
||||
|
||||
end neorv32_cpu_cp_shifter_rtl;
|
453
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_decompressor.vhd
Normal file
453
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_decompressor.vhd
Normal file
@ -0,0 +1,453 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - CPU: Compressed Instructions Decoder (RISC-V "C" Extension) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu_decompressor is
|
||||
port (
|
||||
-- instruction input --
|
||||
ci_instr16_i : in std_ulogic_vector(15 downto 0); -- compressed instruction input
|
||||
-- instruction output --
|
||||
ci_illegal_o : out std_ulogic; -- is an illegal compressed instruction
|
||||
ci_instr32_o : out std_ulogic_vector(31 downto 0) -- 32-bit decompressed instruction
|
||||
);
|
||||
end neorv32_cpu_decompressor;
|
||||
|
||||
architecture neorv32_cpu_decompressor_rtl of neorv32_cpu_decompressor is
|
||||
|
||||
-- compressed instruction layout --
|
||||
constant ci_opcode_lsb_c : natural := 0;
|
||||
constant ci_opcode_msb_c : natural := 1;
|
||||
constant ci_rd_3_lsb_c : natural := 2;
|
||||
constant ci_rd_3_msb_c : natural := 4;
|
||||
constant ci_rd_5_lsb_c : natural := 7;
|
||||
constant ci_rd_5_msb_c : natural := 11;
|
||||
constant ci_rs1_3_lsb_c : natural := 7;
|
||||
constant ci_rs1_3_msb_c : natural := 9;
|
||||
constant ci_rs1_5_lsb_c : natural := 7;
|
||||
constant ci_rs1_5_msb_c : natural := 11;
|
||||
constant ci_rs2_3_lsb_c : natural := 2;
|
||||
constant ci_rs2_3_msb_c : natural := 4;
|
||||
constant ci_rs2_5_lsb_c : natural := 2;
|
||||
constant ci_rs2_5_msb_c : natural := 6;
|
||||
constant ci_funct3_lsb_c : natural := 13;
|
||||
constant ci_funct3_msb_c : natural := 15;
|
||||
|
||||
begin
|
||||
|
||||
-- Compressed Instruction Decoder ---------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
decompressor: process(ci_instr16_i)
|
||||
variable imm20_v : std_ulogic_vector(20 downto 0);
|
||||
variable imm12_v : std_ulogic_vector(12 downto 0);
|
||||
begin
|
||||
-- defaults --
|
||||
ci_illegal_o <= '0';
|
||||
ci_instr32_o <= (others => '0');
|
||||
|
||||
-- helper: 22-bit sign-extended immediate for J/JAL --
|
||||
imm20_v := (others => ci_instr16_i(12)); -- sign extension
|
||||
imm20_v(00):= '0';
|
||||
imm20_v(01):= ci_instr16_i(3);
|
||||
imm20_v(02):= ci_instr16_i(4);
|
||||
imm20_v(03):= ci_instr16_i(5);
|
||||
imm20_v(04):= ci_instr16_i(11);
|
||||
imm20_v(05):= ci_instr16_i(2);
|
||||
imm20_v(06):= ci_instr16_i(7);
|
||||
imm20_v(07):= ci_instr16_i(6);
|
||||
imm20_v(08):= ci_instr16_i(9);
|
||||
imm20_v(09):= ci_instr16_i(10);
|
||||
imm20_v(10):= ci_instr16_i(8);
|
||||
imm20_v(11):= ci_instr16_i(12);
|
||||
|
||||
-- helper: 12-bit sign-extended immediate for branches --
|
||||
imm12_v := (others => ci_instr16_i(12)); -- sign extension
|
||||
imm12_v(00):= '0';
|
||||
imm12_v(01):= ci_instr16_i(3);
|
||||
imm12_v(02):= ci_instr16_i(4);
|
||||
imm12_v(03):= ci_instr16_i(10);
|
||||
imm12_v(04):= ci_instr16_i(11);
|
||||
imm12_v(05):= ci_instr16_i(2);
|
||||
imm12_v(06):= ci_instr16_i(5);
|
||||
imm12_v(07):= ci_instr16_i(6);
|
||||
imm12_v(08):= ci_instr16_i(12);
|
||||
|
||||
-- actual decoder --
|
||||
case ci_instr16_i(ci_opcode_msb_c downto ci_opcode_lsb_c) is
|
||||
|
||||
when "00" => -- C0: Register-Based Loads and Stores
|
||||
case ci_instr16_i(ci_funct3_msb_c downto ci_funct3_lsb_c) is
|
||||
|
||||
when "000" => -- Illegal_instruction, C.ADDI4SPN
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
-- C.ADDI4SPN
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "01" & ci_instr16_i(ci_rd_3_msb_c downto ci_rd_3_lsb_c);
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
|
||||
ci_instr32_o(instr_imm12_msb_c downto instr_imm12_lsb_c) <= (others => '0'); -- zero extend
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= '0';
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= '0';
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= ci_instr16_i(6);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(11);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 5) <= ci_instr16_i(12);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 6) <= ci_instr16_i(7);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 7) <= ci_instr16_i(8);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 8) <= ci_instr16_i(9);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 9) <= ci_instr16_i(10);
|
||||
--
|
||||
ci_illegal_o <= not or_reduce_f(ci_instr16_i(12 downto 2)); -- 12:2 = "00000000000" is official illegal instruction
|
||||
|
||||
when "010" | "011" => -- C.LW / C.FLW
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_load_c;
|
||||
ci_instr32_o(21 downto 20) <= "00";
|
||||
ci_instr32_o(22) <= ci_instr16_i(6);
|
||||
ci_instr32_o(23) <= ci_instr16_i(10);
|
||||
ci_instr32_o(24) <= ci_instr16_i(11);
|
||||
ci_instr32_o(25) <= ci_instr16_i(12);
|
||||
ci_instr32_o(26) <= ci_instr16_i(5);
|
||||
ci_instr32_o(31 downto 27) <= (others => '0');
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_lw_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "01" & ci_instr16_i(ci_rs1_3_msb_c downto ci_rs1_3_lsb_c); -- x8 - x15
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "01" & ci_instr16_i(ci_rd_3_msb_c downto ci_rd_3_lsb_c); -- x8 - x15
|
||||
if (ci_instr16_i(ci_funct3_lsb_c) = '1') then -- C.FLW
|
||||
ci_illegal_o <= '1';
|
||||
end if;
|
||||
|
||||
when "110" | "111" => -- C.SW / C.FSW
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_store_c;
|
||||
ci_instr32_o(08 downto 07) <= "00";
|
||||
ci_instr32_o(09) <= ci_instr16_i(6);
|
||||
ci_instr32_o(10) <= ci_instr16_i(10);
|
||||
ci_instr32_o(11) <= ci_instr16_i(11);
|
||||
ci_instr32_o(25) <= ci_instr16_i(12);
|
||||
ci_instr32_o(26) <= ci_instr16_i(5);
|
||||
ci_instr32_o(31 downto 27) <= (others => '0');
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sw_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "01" & ci_instr16_i(ci_rs1_3_msb_c downto ci_rs1_3_lsb_c); -- x8 - x15
|
||||
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
|
||||
if (ci_instr16_i(ci_funct3_lsb_c) = '1') then -- C.FSW
|
||||
ci_illegal_o <= '1';
|
||||
end if;
|
||||
|
||||
when others => -- undefined
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o <= (others => '-');
|
||||
ci_illegal_o <= '1';
|
||||
|
||||
end case;
|
||||
|
||||
when "01" => -- C1: Control Transfer Instructions, Integer Constant-Generation Instructions
|
||||
|
||||
case ci_instr16_i(ci_funct3_msb_c downto ci_funct3_lsb_c) is
|
||||
when "101" => -- C.J
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_jal_c;
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "00000"; -- discard return address
|
||||
ci_instr32_o(19 downto 12) <= imm20_v(19 downto 12);
|
||||
ci_instr32_o(20) <= imm20_v(11);
|
||||
ci_instr32_o(30 downto 21) <= imm20_v(10 downto 01);
|
||||
ci_instr32_o(31) <= imm20_v(20);
|
||||
|
||||
when "001" => -- C.JAL
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_jal_c;
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "00001"; -- save return address to link register
|
||||
ci_instr32_o(19 downto 12) <= imm20_v(19 downto 12);
|
||||
ci_instr32_o(20) <= imm20_v(11);
|
||||
ci_instr32_o(30 downto 21) <= imm20_v(10 downto 01);
|
||||
ci_instr32_o(31) <= imm20_v(20);
|
||||
|
||||
when "110" => -- C.BEQ
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_branch_c;
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_beq_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "01" & ci_instr16_i(ci_rs1_3_msb_c downto ci_rs1_3_lsb_c);
|
||||
ci_instr32_o(instr_rs2_msb_c downto instr_rs2_lsb_c) <= "00000"; -- x0
|
||||
ci_instr32_o(07) <= imm12_v(11);
|
||||
ci_instr32_o(11 downto 08) <= imm12_v(04 downto 01);
|
||||
ci_instr32_o(30 downto 25) <= imm12_v(10 downto 05);
|
||||
ci_instr32_o(31) <= imm12_v(12);
|
||||
|
||||
when "111" => -- C.BNEZ
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_branch_c;
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_bne_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "01" & ci_instr16_i(ci_rs1_3_msb_c downto ci_rs1_3_lsb_c);
|
||||
ci_instr32_o(instr_rs2_msb_c downto instr_rs2_lsb_c) <= "00000"; -- x0
|
||||
ci_instr32_o(07) <= imm12_v(11);
|
||||
ci_instr32_o(11 downto 08) <= imm12_v(04 downto 01);
|
||||
ci_instr32_o(30 downto 25) <= imm12_v(10 downto 05);
|
||||
ci_instr32_o(31) <= imm12_v(12);
|
||||
|
||||
when "010" => -- C.LI
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00000"; -- x0
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
ci_instr32_o(instr_imm12_msb_c downto instr_imm12_lsb_c) <= (others => ci_instr16_i(12)); -- sign extend
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 5) <= ci_instr16_i(12);
|
||||
|
||||
when "011" => -- C.LUI / C.ADDI16SP
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
if (ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c) = "00010") then -- C.ADDI16SP
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "00010"; -- stack pointer
|
||||
ci_instr32_o(instr_imm12_msb_c downto instr_imm12_lsb_c) <= (others => ci_instr16_i(12)); -- sign extend
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= '0';
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= '0';
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= '0';
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= '0';
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 5) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 6) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 7) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 8) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 9) <= ci_instr16_i(12);
|
||||
|
||||
else -- C.LUI
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_lui_c;
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
ci_instr32_o(instr_imm20_msb_c downto instr_imm20_lsb_c) <= (others => ci_instr16_i(12)); -- sign extend
|
||||
ci_instr32_o(instr_imm20_lsb_c + 0) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm20_lsb_c + 1) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm20_lsb_c + 2) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm20_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm20_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_instr32_o(instr_imm20_lsb_c + 5) <= ci_instr16_i(12);
|
||||
end if;
|
||||
if (ci_instr16_i(6 downto 2) = "00000") and (ci_instr16_i(12) = '0') then -- reserved
|
||||
ci_illegal_o <= '1';
|
||||
end if;
|
||||
|
||||
when "000" => -- C.NOP (rd=0) / C.ADDI
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= ci_instr16_i(ci_rs1_5_msb_c downto ci_rs1_5_lsb_c);
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
ci_instr32_o(instr_imm12_msb_c downto instr_imm12_lsb_c) <= (others => ci_instr16_i(12)); -- sign extend
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 5) <= ci_instr16_i(12);
|
||||
|
||||
when "100" => -- C.SRLI, C.SRAI, C.ANDI, C.SUB, C.XOR, C.OR, C.AND, reserved
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "01" & ci_instr16_i(ci_rs1_3_msb_c downto ci_rs1_3_lsb_c);
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "01" & ci_instr16_i(ci_rs1_3_msb_c downto ci_rs1_3_lsb_c);
|
||||
if (ci_instr16_i(11 downto 10) = "11") then -- register-register operation
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alu_c;
|
||||
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);
|
||||
case ci_instr16_i(6 downto 5) is
|
||||
when "00" => -- C.SUB
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
|
||||
ci_instr32_o(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0100000";
|
||||
when "01" => -- C.XOR
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_xor_c;
|
||||
ci_instr32_o(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0000000";
|
||||
when "10" => -- C.OR
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_or_c;
|
||||
ci_instr32_o(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0000000";
|
||||
when others => -- C.AND
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_and_c;
|
||||
ci_instr32_o(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0000000";
|
||||
end case;
|
||||
else -- register-immediate operation
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
|
||||
case ci_instr16_i(11 downto 10) is
|
||||
when "00" => -- C.SRLI
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sr_c;
|
||||
ci_instr32_o(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0000000";
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_illegal_o <= ci_instr16_i(12);
|
||||
when "01" => -- C.SRAI
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sr_c;
|
||||
ci_instr32_o(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0100000";
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_illegal_o <= ci_instr16_i(12);
|
||||
when "10" => -- C.ANDI
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_and_c;
|
||||
ci_instr32_o(instr_imm12_msb_c downto instr_imm12_lsb_c) <= (others => ci_instr16_i(12)); -- sign extend
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 5) <= ci_instr16_i(12);
|
||||
when others => -- register-register operation
|
||||
NULL;
|
||||
end case;
|
||||
end if;
|
||||
if (ci_instr16_i(12 downto 10) = "111") then -- reserved / undefined
|
||||
ci_illegal_o <= '1';
|
||||
end if;
|
||||
|
||||
when others => -- undefined
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o <= (others => '-');
|
||||
ci_illegal_o <= '1';
|
||||
|
||||
end case;
|
||||
|
||||
when "10" => -- C2: Stack-Pointer-Based Loads and Stores, Control Transfer Instructions
|
||||
case ci_instr16_i(ci_funct3_msb_c downto ci_funct3_lsb_c) is
|
||||
|
||||
when "000" => -- C.SLLI
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= ci_instr16_i(ci_rs1_5_msb_c downto ci_rs1_5_lsb_c);
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rs1_5_msb_c downto ci_rs1_5_lsb_c);
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sll_c;
|
||||
ci_instr32_o(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0000000";
|
||||
ci_instr32_o(instr_imm12_lsb_c + 0) <= ci_instr16_i(2);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 1) <= ci_instr16_i(3);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 2) <= ci_instr16_i(4);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 3) <= ci_instr16_i(5);
|
||||
ci_instr32_o(instr_imm12_lsb_c + 4) <= ci_instr16_i(6);
|
||||
ci_illegal_o <= ci_instr16_i(12);
|
||||
|
||||
when "010" | "011" => -- C.LWSP / C.FLWSP
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_load_c;
|
||||
ci_instr32_o(21 downto 20) <= "00";
|
||||
ci_instr32_o(22) <= ci_instr16_i(4);
|
||||
ci_instr32_o(23) <= ci_instr16_i(5);
|
||||
ci_instr32_o(24) <= ci_instr16_i(6);
|
||||
ci_instr32_o(25) <= ci_instr16_i(12);
|
||||
ci_instr32_o(26) <= ci_instr16_i(2);
|
||||
ci_instr32_o(27) <= ci_instr16_i(3);
|
||||
ci_instr32_o(31 downto 28) <= (others => '0');
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_lw_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
if (ci_instr16_i(ci_funct3_lsb_c) = '1') then -- C.FLWSP
|
||||
ci_illegal_o <= '1';
|
||||
end if;
|
||||
|
||||
when "110" | "111" => -- C.SWSP / C.FSWSP
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_store_c;
|
||||
ci_instr32_o(08 downto 07) <= "00";
|
||||
ci_instr32_o(09) <= ci_instr16_i(9);
|
||||
ci_instr32_o(10) <= ci_instr16_i(10);
|
||||
ci_instr32_o(11) <= ci_instr16_i(11);
|
||||
ci_instr32_o(25) <= ci_instr16_i(12);
|
||||
ci_instr32_o(26) <= ci_instr16_i(7);
|
||||
ci_instr32_o(27) <= ci_instr16_i(8);
|
||||
ci_instr32_o(31 downto 28) <= (others => '0');
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sw_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer
|
||||
ci_instr32_o(instr_rs2_msb_c downto instr_rs2_lsb_c) <= ci_instr16_i(ci_rs2_5_msb_c downto ci_rs2_5_lsb_c);
|
||||
if (ci_instr16_i(ci_funct3_lsb_c) = '1') then -- C.FSWSP
|
||||
ci_illegal_o <= '1';
|
||||
end if;
|
||||
|
||||
when "100" => -- C.JR, C.JALR, C.MV, C.EBREAK, C.ADD
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
if (ci_instr16_i(12) = '0') then -- C.JR, C.MV
|
||||
if (ci_instr16_i(6 downto 2) = "00000") then -- C.JR
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_jalr_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= ci_instr16_i(ci_rs1_5_msb_c downto ci_rs1_5_lsb_c);
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "00000"; -- discard return address
|
||||
else -- C.MV
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alu_c;
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= "000";
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00000"; -- x0
|
||||
ci_instr32_o(instr_rs2_msb_c downto instr_rs2_lsb_c) <= ci_instr16_i(ci_rs2_5_msb_c downto ci_rs2_5_lsb_c);
|
||||
end if;
|
||||
else -- C.EBREAK, C.JALR, C.ADD
|
||||
if (ci_instr16_i(6 downto 2) = "00000") then -- C.EBREAK, C.JALR
|
||||
if (ci_instr16_i(11 downto 7) = "00000") then -- C.EBREAK
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_syscsr_c;
|
||||
ci_instr32_o(instr_funct12_msb_c downto instr_funct12_lsb_c) <= "000000000001";
|
||||
else -- C.JALR
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_jalr_c;
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= ci_instr16_i(ci_rs1_5_msb_c downto ci_rs1_5_lsb_c);
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= "00001"; -- save return address to link register
|
||||
end if;
|
||||
else -- C.ADD
|
||||
ci_instr32_o(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alu_c;
|
||||
ci_instr32_o(instr_funct3_msb_c downto instr_funct3_lsb_c) <= "000";
|
||||
ci_instr32_o(instr_rd_msb_c downto instr_rd_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
ci_instr32_o(instr_rs1_msb_c downto instr_rs1_lsb_c) <= ci_instr16_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
|
||||
ci_instr32_o(instr_rs2_msb_c downto instr_rs2_lsb_c) <= ci_instr16_i(ci_rs2_5_msb_c downto ci_rs2_5_lsb_c);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when others => -- undefined
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o <= (others => '-');
|
||||
ci_illegal_o <= '1';
|
||||
|
||||
end case;
|
||||
|
||||
when others => -- not a compressed instruction
|
||||
-- ----------------------------------------------------------------------------------------------------------
|
||||
ci_instr32_o <= (others => '-');
|
||||
ci_illegal_o <= '0';
|
||||
|
||||
end case;
|
||||
end process decompressor;
|
||||
|
||||
|
||||
end neorv32_cpu_decompressor_rtl;
|
135
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_regfile.vhd
Normal file
135
Libs/RiscV/NEORV32/rtl/core/neorv32_cpu_regfile.vhd
Normal file
@ -0,0 +1,135 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - CPU General Purpose Data Register File >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # General purpose data register file. 32 entries (= 1024 bit) for normal mode (RV32I), #
|
||||
-- # 16 entries (= 512 bit) for embedded mode (RV32E) when RISC-V "E" extension is enabled. #
|
||||
-- # #
|
||||
-- # Register zero (r0/x0) is a "normal" physical register that has to be initialized to zero by #
|
||||
-- # the early boot code. Register zero is always set to zero when written. #
|
||||
-- # #
|
||||
-- # The register file uses synchronous read accesses and a *single* (multiplexed) address port #
|
||||
-- # for writing and reading rd/rs1 and a single read-only port for rs2. Therefore, the whole #
|
||||
-- # register file can be mapped to a single true-dual-port block RAM. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_cpu_regfile is
|
||||
generic (
|
||||
CPU_EXTENSION_RISCV_E : boolean -- implement embedded RF extension?
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
||||
-- 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
|
||||
-- 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
|
||||
);
|
||||
end neorv32_cpu_regfile;
|
||||
|
||||
architecture neorv32_cpu_regfile_rtl of neorv32_cpu_regfile is
|
||||
|
||||
-- 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_wdata : std_ulogic_vector(data_width_c-1 downto 0); -- actual write-back data
|
||||
signal rd_is_r0 : std_ulogic; -- writing to r0?
|
||||
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); -- read data
|
||||
|
||||
begin
|
||||
|
||||
-- Data Input Mux -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
input_mux: process(rd_is_r0, ctrl_i, alu_i, mem_i)
|
||||
begin
|
||||
if (rd_is_r0 = '1') then -- write zero if accessing x0 to "emulate" it is hardwired to zero
|
||||
rf_wdata <= (others => '0');
|
||||
else
|
||||
if (ctrl_i(ctrl_rf_in_mux_c) = '0') then
|
||||
rf_wdata <= alu_i;
|
||||
else
|
||||
rf_wdata <= mem_i;
|
||||
end if;
|
||||
end if;
|
||||
end process input_mux;
|
||||
|
||||
-- check if we are writing to x0 --
|
||||
rd_is_r0 <= (not or_reduce_f(dst_addr(4 downto 0))) when (CPU_EXTENSION_RISCV_E = false) else (not or_reduce_f(dst_addr(3 downto 0)));
|
||||
|
||||
|
||||
-- Register File Access -------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
rf_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then -- sync read and write
|
||||
if (CPU_EXTENSION_RISCV_E = false) then -- normal register file with 32 entries
|
||||
if (ctrl_i(ctrl_rf_wb_en_c) = '1') then
|
||||
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 (ctrl_i(ctrl_rf_wb_en_c) = '1') then
|
||||
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))));
|
||||
end if;
|
||||
end if;
|
||||
end process rf_access;
|
||||
|
||||
-- access addresses --
|
||||
dst_addr <= ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c);
|
||||
opa_addr <= dst_addr when (ctrl_i(ctrl_rf_wb_en_c) = '1') else ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- rd/rs1
|
||||
opb_addr <= ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c); -- rs2
|
||||
|
||||
-- data output --
|
||||
rs1_o <= rs1;
|
||||
rs2_o <= rs2;
|
||||
|
||||
|
||||
end neorv32_cpu_regfile_rtl;
|
728
Libs/RiscV/NEORV32/rtl/core/neorv32_debug_dm.vhd
Normal file
728
Libs/RiscV/NEORV32/rtl/core/neorv32_debug_dm.vhd
Normal file
@ -0,0 +1,728 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - RISC-V-Compatible Debug Module (DM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Compatible to the "Minimal RISC-V External Debug Spec. Version 0.13.2" #
|
||||
-- # -> "Execution-based" debugging scheme #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Key features: #
|
||||
-- # * register access commands only #
|
||||
-- # * auto-execution commands #
|
||||
-- # * for a single hart only #
|
||||
-- # * 2 general purpose program buffer entries #
|
||||
-- # * 1 general purpose data buffer entry #
|
||||
-- # #
|
||||
-- # CPU access: #
|
||||
-- # * ROM for "park loop" code #
|
||||
-- # * program buffer #
|
||||
-- # * data buffer #
|
||||
-- # * control and status register #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_debug_dm is
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rstn_i : in std_ulogic; -- global reset line, low-active
|
||||
-- debug module interface (DMI) --
|
||||
dmi_rstn_i : in std_ulogic;
|
||||
dmi_req_valid_i : in std_ulogic;
|
||||
dmi_req_ready_o : out std_ulogic; -- DMI is allowed to make new requests when set
|
||||
dmi_req_addr_i : in std_ulogic_vector(06 downto 0);
|
||||
dmi_req_op_i : in std_ulogic; -- 0=read, 1=write
|
||||
dmi_req_data_i : in std_ulogic_vector(31 downto 0);
|
||||
dmi_resp_valid_o : out std_ulogic; -- response valid when set
|
||||
dmi_resp_ready_i : in std_ulogic; -- ready to receive respond
|
||||
dmi_resp_data_o : out std_ulogic_vector(31 downto 0);
|
||||
dmi_resp_err_o : out std_ulogic; -- 0=ok, 1=error
|
||||
-- CPU bus access --
|
||||
cpu_addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
cpu_rden_i : in std_ulogic; -- read enable
|
||||
cpu_wren_i : in std_ulogic; -- write enable
|
||||
cpu_data_i : in std_ulogic_vector(31 downto 0); -- data in
|
||||
cpu_data_o : out std_ulogic_vector(31 downto 0); -- data out
|
||||
cpu_ack_o : out std_ulogic; -- transfer acknowledge
|
||||
-- CPU control --
|
||||
cpu_ndmrstn_o : out std_ulogic; -- soc reset
|
||||
cpu_halt_req_o : out std_ulogic -- request hart to halt (enter debug mode)
|
||||
);
|
||||
end neorv32_debug_dm;
|
||||
|
||||
architecture neorv32_debug_dm_rtl of neorv32_debug_dm is
|
||||
|
||||
-- DM configuration --
|
||||
constant nscratch_c : std_ulogic_vector(03 downto 0) := "0001"; -- number of dscratch* registers in CPU = 1
|
||||
constant dataaccess_c : std_ulogic := '1'; -- 1: abstract data is memory-mapped, 0: abstract data is CSR-mapped
|
||||
constant datasize_c : std_ulogic_vector(03 downto 0) := "0001"; -- number of data registers in memory/CSR space = 1
|
||||
constant dataaddr_c : std_ulogic_vector(11 downto 0) := dm_data_base_c(11 downto 0); -- signed base address of data registers in memory/CSR space
|
||||
|
||||
-- available DMI registers --
|
||||
constant addr_data0_c : std_ulogic_vector(6 downto 0) := "000" & x"4";
|
||||
constant addr_dmcontrol_c : std_ulogic_vector(6 downto 0) := "001" & x"0";
|
||||
constant addr_dmstatus_c : std_ulogic_vector(6 downto 0) := "001" & x"1";
|
||||
constant addr_hartinfo_c : std_ulogic_vector(6 downto 0) := "001" & x"2";
|
||||
constant addr_abstractcs_c : std_ulogic_vector(6 downto 0) := "001" & x"6";
|
||||
constant addr_command_c : std_ulogic_vector(6 downto 0) := "001" & x"7";
|
||||
constant addr_abstractauto_c : std_ulogic_vector(6 downto 0) := "001" & x"8";
|
||||
constant addr_nextdm_c : std_ulogic_vector(6 downto 0) := "001" & x"d";
|
||||
constant addr_progbuf0_c : std_ulogic_vector(6 downto 0) := "010" & x"0";
|
||||
constant addr_progbuf1_c : std_ulogic_vector(6 downto 0) := "010" & x"1";
|
||||
constant addr_sbcs_c : std_ulogic_vector(6 downto 0) := "011" & x"8";
|
||||
constant addr_haltsum0_c : std_ulogic_vector(6 downto 0) := "100" & x"0";
|
||||
|
||||
-- RISC-V 32-bit instruction prototypes --
|
||||
constant instr_nop_c : std_ulogic_vector(31 downto 0) := x"00000013"; -- nop
|
||||
constant instr_lw_c : std_ulogic_vector(31 downto 0) := x"00002003"; -- lw zero, 0(zero)
|
||||
constant instr_sw_c : std_ulogic_vector(31 downto 0) := x"00002023"; -- sw zero, 0(zero)
|
||||
constant instr_ebreak_c : std_ulogic_vector(31 downto 0) := x"00100073"; -- ebreak
|
||||
|
||||
-- debug module controller --
|
||||
type dm_ctrl_state_t is (CMD_IDLE, CMD_EXE_CHECK, CMD_EXE_PREPARE, CMD_EXE_TRIGGER, CMD_EXE_BUSY, CMD_EXE_ERROR);
|
||||
type dm_ctrl_t is record
|
||||
-- fsm --
|
||||
state : dm_ctrl_state_t;
|
||||
busy : std_ulogic;
|
||||
ldsw_progbuf : std_ulogic_vector(31 downto 0);
|
||||
pbuf_en : std_ulogic;
|
||||
-- error flags --
|
||||
illegal_state : std_ulogic;
|
||||
illegal_cmd : std_ulogic;
|
||||
cmderr : std_ulogic_vector(02 downto 0);
|
||||
-- hart status --
|
||||
hart_halted : std_ulogic;
|
||||
hart_resume_req : std_ulogic;
|
||||
hart_resume_ack : std_ulogic;
|
||||
hart_reset : std_ulogic;
|
||||
end record;
|
||||
signal dm_ctrl : dm_ctrl_t;
|
||||
|
||||
-- debug module DMI registers / access --
|
||||
type progbuf_t is array (0 to 1) of std_ulogic_vector(31 downto 0);
|
||||
type dm_reg_t is record
|
||||
dmcontrol_ndmreset : std_ulogic;
|
||||
dmcontrol_dmactive : std_ulogic;
|
||||
abstractauto_autoexecdata : std_ulogic;
|
||||
abstractauto_autoexecprogbuf : std_ulogic_vector(01 downto 0);
|
||||
progbuf : progbuf_t;
|
||||
command : std_ulogic_vector(31 downto 0);
|
||||
--
|
||||
halt_req : std_ulogic;
|
||||
resume_req : std_ulogic;
|
||||
reset_ack : std_ulogic;
|
||||
wr_acc_err : std_ulogic;
|
||||
rd_acc_err : std_ulogic;
|
||||
clr_acc_err : std_ulogic;
|
||||
autoexec_wr : std_ulogic;
|
||||
autoexec_rd : std_ulogic;
|
||||
end record;
|
||||
signal dm_reg : dm_reg_t;
|
||||
|
||||
-- cpu program buffer --
|
||||
type cpu_progbuf_t is array (0 to 4) of std_ulogic_vector(31 downto 0);
|
||||
signal cpu_progbuf : cpu_progbuf_t;
|
||||
|
||||
-- **********************************************************
|
||||
-- CPU Bus Interface
|
||||
-- **********************************************************
|
||||
|
||||
-- Debug Core Interface
|
||||
type dci_t is record
|
||||
halt_ack : std_ulogic; -- CPU (re-)entered HALT state (single-shot)
|
||||
resume_req : std_ulogic; -- DM wants the CPU to resume when set
|
||||
resume_ack : std_ulogic; -- CPU starts resuming when set (single-shot)
|
||||
execute_req : std_ulogic; -- DM wants CPU to execute program buffer when set
|
||||
execute_ack : std_ulogic; -- CPU starts executing program buffer when set (single-shot)
|
||||
exception_ack : std_ulogic; -- CPU has detected an exception (single-shot)
|
||||
progbuf : std_ulogic_vector(255 downto 0); -- program buffer, 4 32-bit entries
|
||||
data_we : std_ulogic; -- write abstract data
|
||||
wdata : std_ulogic_vector(31 downto 0); -- abstract write data
|
||||
rdata : std_ulogic_vector(31 downto 0); -- abstract read data
|
||||
end record;
|
||||
signal dci : dci_t;
|
||||
|
||||
-- IO space: module base address --
|
||||
constant hi_abb_c : natural := 31; -- high address boundary bit
|
||||
constant lo_abb_c : natural := index_size_f(dm_size_c); -- low address boundary bit
|
||||
|
||||
-- status and control register - bits --
|
||||
constant sreg_halt_ack_c : natural := 0; -- -/w: CPU is halted in debug mode and waits in park loop
|
||||
constant sreg_resume_req_c : natural := 1; -- r/-: DM requests CPU to resume
|
||||
constant sreg_resume_ack_c : natural := 2; -- -/w: CPU starts resuming
|
||||
constant sreg_execute_req_c : natural := 3; -- r/-: DM requests to execute program buffer
|
||||
constant sreg_execute_ack_c : natural := 4; -- -/w: CPU starts to execute program buffer
|
||||
constant sreg_exception_ack_c : natural := 5; -- -/w: CPU has detected an exception
|
||||
|
||||
-- code ROM containing "park loop" --
|
||||
type code_rom_file_t is array (0 to 31) of std_ulogic_vector(31 downto 0);
|
||||
constant code_rom_file : code_rom_file_t := (
|
||||
00000000 => x"0180006f",
|
||||
00000001 => x"7b241073",
|
||||
00000002 => x"02000413",
|
||||
00000003 => x"98802023",
|
||||
00000004 => x"7b202473",
|
||||
00000005 => x"00100073",
|
||||
00000006 => x"7b241073",
|
||||
00000007 => x"00100413",
|
||||
00000008 => x"98802023",
|
||||
00000009 => x"98002403",
|
||||
00000010 => x"00847413",
|
||||
00000011 => x"02041263",
|
||||
00000012 => x"98002403",
|
||||
00000013 => x"00247413",
|
||||
00000014 => x"00041463",
|
||||
00000015 => x"fe9ff06f",
|
||||
00000016 => x"00400413",
|
||||
00000017 => x"98802023",
|
||||
00000018 => x"7b202473",
|
||||
00000019 => x"7b200073",
|
||||
00000020 => x"01000413",
|
||||
00000021 => x"98802023",
|
||||
00000022 => x"7b202473",
|
||||
00000023 => x"0000100f",
|
||||
00000024 => x"88000067",
|
||||
others => x"00100073" -- ebreak
|
||||
);
|
||||
|
||||
-- global access control --
|
||||
signal acc_en : std_ulogic;
|
||||
signal rden : std_ulogic;
|
||||
signal wren : std_ulogic;
|
||||
signal maddr : std_ulogic_vector(01 downto 0);
|
||||
|
||||
-- data buffer --
|
||||
signal data_buf : std_ulogic_vector(31 downto 0);
|
||||
|
||||
-- program buffer access --
|
||||
type prog_buf_t is array (0 to 3) of std_ulogic_vector(31 downto 0);
|
||||
signal prog_buf : prog_buf_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Debug Module Command Controller --------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
dm_controller: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (dm_reg.dmcontrol_dmactive = '0') or (dmi_rstn_i = '0') then -- DM reset / DM disabled
|
||||
dm_ctrl.state <= CMD_IDLE;
|
||||
dm_ctrl.ldsw_progbuf <= (others => '-');
|
||||
dci.execute_req <= '0';
|
||||
dm_ctrl.pbuf_en <= '-';
|
||||
--
|
||||
dm_ctrl.illegal_cmd <= '-';
|
||||
dm_ctrl.illegal_state <= '-';
|
||||
dm_ctrl.cmderr <= "000";
|
||||
--
|
||||
dm_ctrl.hart_reset <= '0';
|
||||
dm_ctrl.hart_halted <= '0';
|
||||
dm_ctrl.hart_resume_req <= '0';
|
||||
dm_ctrl.hart_resume_ack <= '0';
|
||||
else -- DM active
|
||||
|
||||
-- defaults --
|
||||
dci.execute_req <= '0';
|
||||
dm_ctrl.illegal_cmd <= '0';
|
||||
dm_ctrl.illegal_state <= '0';
|
||||
|
||||
-- command execution fsm --
|
||||
case dm_ctrl.state is
|
||||
|
||||
when CMD_IDLE => -- wait for new abstract command
|
||||
-- ------------------------------------------------------------
|
||||
if (dmi_req_valid_i = '1') and (dmi_req_op_i = '1') then -- valid DM write access
|
||||
if (dmi_req_addr_i = addr_command_c) then
|
||||
if (dm_ctrl.cmderr = "000") then -- only execute if no error
|
||||
dm_ctrl.state <= CMD_EXE_CHECK;
|
||||
end if;
|
||||
end if;
|
||||
elsif (dm_reg.autoexec_rd = '1') or (dm_reg.autoexec_wr = '1') then -- auto execution trigger
|
||||
dm_ctrl.state <= CMD_EXE_CHECK;
|
||||
end if;
|
||||
|
||||
when CMD_EXE_CHECK => -- check if command is valid / supported
|
||||
-- ------------------------------------------------------------
|
||||
if (dm_reg.command(31 downto 24) = x"00") and -- cmdtype: register access
|
||||
(dm_reg.command(23) = '0') and -- reserved
|
||||
(dm_reg.command(22 downto 20) = "010") and -- aarsize: has to be 32-bit
|
||||
(dm_reg.command(19) = '0') and -- aarpostincrement: not supported
|
||||
((dm_reg.command(17) = '0') or (dm_reg.command(15 downto 05) = "00010000000")) then -- regno: only GPRs are supported: 0x1000..0x101f if transfer is set
|
||||
if (dm_ctrl.hart_halted = '1') then -- CPU is halted
|
||||
dm_ctrl.state <= CMD_EXE_PREPARE;
|
||||
else -- error! CPU is still running
|
||||
dm_ctrl.illegal_state <= '1';
|
||||
dm_ctrl.state <= CMD_EXE_ERROR;
|
||||
end if;
|
||||
else -- invalid command
|
||||
dm_ctrl.illegal_cmd <= '1';
|
||||
dm_ctrl.state <= CMD_EXE_ERROR;
|
||||
end if;
|
||||
|
||||
when CMD_EXE_PREPARE => -- setup program buffer
|
||||
-- ------------------------------------------------------------
|
||||
if (dm_reg.command(17) = '1') then -- "transfer"
|
||||
if (dm_reg.command(16) = '0') then -- "write" = 0 -> read from GPR
|
||||
dm_ctrl.ldsw_progbuf <= instr_sw_c;
|
||||
dm_ctrl.ldsw_progbuf(31 downto 25) <= dataaddr_c(11 downto 05); -- destination address
|
||||
dm_ctrl.ldsw_progbuf(24 downto 20) <= dm_reg.command(4 downto 0); -- "regno" = source register
|
||||
dm_ctrl.ldsw_progbuf(11 downto 07) <= dataaddr_c(04 downto 00); -- destination address
|
||||
else -- "write" = 0 -> write to GPR
|
||||
dm_ctrl.ldsw_progbuf <= instr_lw_c;
|
||||
dm_ctrl.ldsw_progbuf(31 downto 20) <= dataaddr_c; -- source address
|
||||
dm_ctrl.ldsw_progbuf(11 downto 07) <= dm_reg.command(4 downto 0); -- "regno" = destination register
|
||||
end if;
|
||||
else
|
||||
dm_ctrl.ldsw_progbuf <= instr_nop_c; -- NOP - do nothing
|
||||
end if;
|
||||
--
|
||||
if (dm_reg.command(18) = '1') then -- "postexec" - execute program buffer
|
||||
dm_ctrl.pbuf_en <= '1';
|
||||
else -- execute all program buffer entries as NOPs
|
||||
dm_ctrl.pbuf_en <= '0';
|
||||
end if;
|
||||
--
|
||||
dm_ctrl.state <= CMD_EXE_TRIGGER;
|
||||
|
||||
when CMD_EXE_TRIGGER => -- request CPU to execute command
|
||||
-- ------------------------------------------------------------
|
||||
dci.execute_req <= '1'; -- request execution
|
||||
if (dci.execute_ack = '1') then -- CPU starts execution
|
||||
dm_ctrl.state <= CMD_EXE_BUSY;
|
||||
end if;
|
||||
|
||||
when CMD_EXE_BUSY => -- wait for CPU to finish
|
||||
-- ------------------------------------------------------------
|
||||
if (dci.halt_ack = '1') then -- CPU is parked (halted) again -> execution done
|
||||
dm_ctrl.state <= CMD_IDLE;
|
||||
end if;
|
||||
|
||||
when CMD_EXE_ERROR => -- delay cycle for error to arrive abstracts.cmderr
|
||||
-- ------------------------------------------------------------
|
||||
dm_ctrl.state <= CMD_IDLE;
|
||||
|
||||
when others => -- undefined
|
||||
-- ------------------------------------------------------------
|
||||
dm_ctrl.state <= CMD_IDLE;
|
||||
|
||||
end case;
|
||||
|
||||
|
||||
-- error flags --
|
||||
-- ------------------------------------------------------------
|
||||
if (dm_ctrl.cmderr = "000") then -- set new error
|
||||
if (dm_ctrl.illegal_state = '1') then -- cannot execute since hart is not in expected state
|
||||
dm_ctrl.cmderr <= "100";
|
||||
elsif (dci.exception_ack = '1') then -- exception during execution
|
||||
dm_ctrl.cmderr <= "011";
|
||||
elsif (dm_ctrl.illegal_cmd = '1') then -- unsupported command
|
||||
dm_ctrl.cmderr <= "010";
|
||||
elsif (dm_reg.rd_acc_err = '1') or (dm_reg.wr_acc_err = '1') then -- invalid read/write while command is executing
|
||||
dm_ctrl.cmderr <= "001";
|
||||
end if;
|
||||
elsif (dm_reg.clr_acc_err = '1') then -- acknowledge/clear error flags
|
||||
dm_ctrl.cmderr <= "000";
|
||||
end if;
|
||||
|
||||
|
||||
-- hart status --
|
||||
-- ------------------------------------------------------------
|
||||
|
||||
-- HALTED --
|
||||
if (dm_reg.dmcontrol_ndmreset = '1') then
|
||||
dm_ctrl.hart_halted <= '0';
|
||||
elsif (dci.halt_ack = '1') then
|
||||
dm_ctrl.hart_halted <= '1';
|
||||
elsif (dci.resume_ack = '1') then
|
||||
dm_ctrl.hart_halted <= '0';
|
||||
end if;
|
||||
|
||||
-- RESUME REQ --
|
||||
if (dm_reg.dmcontrol_ndmreset = '1') then
|
||||
dm_ctrl.hart_resume_req <= '0';
|
||||
elsif (dm_reg.resume_req = '1') then
|
||||
dm_ctrl.hart_resume_req <= '1';
|
||||
elsif (dci.resume_ack = '1') then
|
||||
dm_ctrl.hart_resume_req <= '0';
|
||||
end if;
|
||||
|
||||
-- RESUME ACK --
|
||||
if (dm_reg.dmcontrol_ndmreset = '1') then
|
||||
dm_ctrl.hart_resume_ack <= '0';
|
||||
elsif (dci.resume_ack = '1') then
|
||||
dm_ctrl.hart_resume_ack <= '1';
|
||||
elsif (dm_reg.resume_req = '1') then
|
||||
dm_ctrl.hart_resume_ack <= '0';
|
||||
end if;
|
||||
|
||||
-- hart has been RESET --
|
||||
if (dm_reg.dmcontrol_ndmreset = '1') then
|
||||
dm_ctrl.hart_reset <= '1';
|
||||
elsif (dm_reg.reset_ack = '1') then
|
||||
dm_ctrl.hart_reset <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process dm_controller;
|
||||
|
||||
-- controller busy flag --
|
||||
dm_ctrl.busy <= '0' when (dm_ctrl.state = CMD_IDLE) else '1';
|
||||
|
||||
|
||||
-- Debug Module Interface - Write Access --------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
dmi_write_access: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
dm_reg.dmcontrol_ndmreset <= '0';
|
||||
dm_reg.dmcontrol_dmactive <= '0'; -- DM is in reset state after hardware reset
|
||||
--
|
||||
dm_reg.abstractauto_autoexecdata <= '0';
|
||||
dm_reg.abstractauto_autoexecprogbuf <= "00";
|
||||
--
|
||||
dm_reg.command <= (others => '0');
|
||||
dm_reg.progbuf <= (others => instr_nop_c);
|
||||
--
|
||||
dm_reg.halt_req <= '0';
|
||||
dm_reg.resume_req <= '0';
|
||||
dm_reg.reset_ack <= '0';
|
||||
dm_reg.wr_acc_err <= '0';
|
||||
dm_reg.clr_acc_err <= '0';
|
||||
dm_reg.autoexec_wr <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
|
||||
-- default --
|
||||
dm_reg.resume_req <= '0';
|
||||
dm_reg.reset_ack <= '0';
|
||||
dm_reg.wr_acc_err <= '0';
|
||||
dm_reg.clr_acc_err <= '0';
|
||||
dm_reg.autoexec_wr <= '0';
|
||||
|
||||
-- DMI access --
|
||||
if (dmi_req_valid_i = '1') and (dmi_req_op_i = '1') then -- valid DMI write request
|
||||
|
||||
-- debug module control --
|
||||
if (dmi_req_addr_i = addr_dmcontrol_c) then
|
||||
dm_reg.halt_req <= dmi_req_data_i(31); -- haltreq (-/w): write 1 to request halt; has to be cleared again by debugger
|
||||
dm_reg.resume_req <= dmi_req_data_i(30); -- resumereq (-/w1): write 1 to request resume
|
||||
dm_reg.reset_ack <= dmi_req_data_i(28); -- ackhavereset (-/w1)
|
||||
dm_reg.dmcontrol_ndmreset <= dmi_req_data_i(01); -- ndmreset (r/w): soc reset
|
||||
dm_reg.dmcontrol_dmactive <= dmi_req_data_i(00); -- dmactive (r/w): DM reset
|
||||
end if;
|
||||
|
||||
-- write abstract command --
|
||||
if (dmi_req_addr_i = addr_command_c) then
|
||||
if (dm_ctrl.busy = '0') and (dm_ctrl.cmderr = "000") then -- idle and no errors yet
|
||||
dm_reg.command <= dmi_req_data_i;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- write abstract command autoexec --
|
||||
if (dmi_req_addr_i = addr_abstractauto_c) then
|
||||
if (dm_ctrl.busy = '0') then -- idle and no errors yet
|
||||
dm_reg.abstractauto_autoexecdata <= dmi_req_data_i(00);
|
||||
dm_reg.abstractauto_autoexecprogbuf(0) <= dmi_req_data_i(16);
|
||||
dm_reg.abstractauto_autoexecprogbuf(1) <= dmi_req_data_i(17);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- auto execution trigger --
|
||||
if ((dmi_req_addr_i = addr_data0_c) and (dm_reg.abstractauto_autoexecdata = '1')) or
|
||||
((dmi_req_addr_i = addr_progbuf0_c) and (dm_reg.abstractauto_autoexecprogbuf(0) = '1')) or
|
||||
((dmi_req_addr_i = addr_progbuf1_c) and (dm_reg.abstractauto_autoexecprogbuf(1) = '1')) then
|
||||
dm_reg.autoexec_wr <= '1';
|
||||
end if;
|
||||
|
||||
-- acknowledge command error --
|
||||
if (dmi_req_addr_i = addr_abstractcs_c) then
|
||||
if (dmi_req_data_i(10 downto 8) = "111") then
|
||||
dm_reg.clr_acc_err <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- write program buffer --
|
||||
if (dmi_req_addr_i(dmi_req_addr_i'left downto 1) = addr_progbuf0_c(dmi_req_addr_i'left downto 1)) then
|
||||
if (dm_ctrl.busy = '0') then -- idle
|
||||
if (dmi_req_addr_i(0) = addr_progbuf0_c(0)) then
|
||||
dm_reg.progbuf(0) <= dmi_req_data_i;
|
||||
else
|
||||
dm_reg.progbuf(1) <= dmi_req_data_i;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- invalid access (while command is executing) --
|
||||
if (dm_ctrl.busy = '1') then -- busy
|
||||
if (dmi_req_addr_i = addr_abstractcs_c) or
|
||||
(dmi_req_addr_i = addr_command_c) or
|
||||
(dmi_req_addr_i = addr_abstractauto_c) or
|
||||
(dmi_req_addr_i = addr_data0_c) or
|
||||
(dmi_req_addr_i = addr_progbuf0_c) or
|
||||
(dmi_req_addr_i = addr_progbuf1_c) then
|
||||
dm_reg.wr_acc_err <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process dmi_write_access;
|
||||
|
||||
|
||||
-- Direct Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- write to abstract data register --
|
||||
dci.data_we <= '1' when (dmi_req_valid_i = '1') and (dmi_req_op_i = '1') and (dmi_req_addr_i = addr_data0_c) and (dm_ctrl.busy = '0') else '0';
|
||||
dci.wdata <= dmi_req_data_i;
|
||||
|
||||
-- CPU halt/resume request --
|
||||
cpu_halt_req_o <= dm_reg.halt_req and dm_reg.dmcontrol_dmactive; -- single shot
|
||||
dci.resume_req <= dm_ctrl.hart_resume_req; -- permanent
|
||||
|
||||
-- SoC reset --
|
||||
cpu_ndmrstn_o <= not (dm_reg.dmcontrol_ndmreset and dm_reg.dmcontrol_dmactive);
|
||||
|
||||
-- build program buffer array for cpu access --
|
||||
cpu_progbuf(0) <= dm_ctrl.ldsw_progbuf; -- pseudo program buffer for GPR access
|
||||
cpu_progbuf(1) <= instr_nop_c when (dm_ctrl.pbuf_en = '0') else dm_reg.progbuf(0);
|
||||
cpu_progbuf(2) <= instr_nop_c when (dm_ctrl.pbuf_en = '0') else dm_reg.progbuf(1);
|
||||
cpu_progbuf(3) <= instr_ebreak_c; -- implicit ebreak instruction
|
||||
|
||||
-- DMI status --
|
||||
dmi_resp_err_o <= '0'; -- what can go wrong?
|
||||
dmi_req_ready_o <= '1'; -- always ready for new read/write accesses
|
||||
|
||||
|
||||
-- Debug Module Interface - Read Access ---------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
dmi_read_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
dmi_resp_valid_o <= dmi_req_valid_i; -- DMI transfer ack
|
||||
dmi_resp_data_o <= (others => '0'); -- default
|
||||
dm_reg.rd_acc_err <= '0';
|
||||
dm_reg.autoexec_rd <= '0';
|
||||
|
||||
case dmi_req_addr_i is
|
||||
|
||||
-- debug module status register --
|
||||
when addr_dmstatus_c =>
|
||||
dmi_resp_data_o(31 downto 23) <= (others => '0'); -- reserved (r/-)
|
||||
dmi_resp_data_o(22) <= '1'; -- impebreak (r/-): there is an implicit ebreak instruction after the visible program buffer
|
||||
dmi_resp_data_o(21 downto 20) <= (others => '0'); -- reserved (r/-)
|
||||
dmi_resp_data_o(19) <= dm_ctrl.hart_reset; -- allhavereset (r/-): there is only one hart that can be reset
|
||||
dmi_resp_data_o(18) <= dm_ctrl.hart_reset; -- anyhavereset (r/-): there is only one hart that can be reset
|
||||
dmi_resp_data_o(17) <= dm_ctrl.hart_resume_ack; -- allresumeack (r/-): there is only one hart that can acknowledge resume request
|
||||
dmi_resp_data_o(16) <= dm_ctrl.hart_resume_ack; -- anyresumeack (r/-): there is only one hart that can acknowledge resume request
|
||||
dmi_resp_data_o(15) <= '0'; -- allnonexistent (r/-): there is only one hart that is always existent
|
||||
dmi_resp_data_o(14) <= '0'; -- anynonexistent (r/-): there is only one hart that is always existent
|
||||
dmi_resp_data_o(13) <= dm_reg.dmcontrol_ndmreset; -- allunavail (r/-): there is only one hart that is unavailable during reset
|
||||
dmi_resp_data_o(12) <= dm_reg.dmcontrol_ndmreset; -- anyunavail (r/-): there is only one hart that is unavailable during reset
|
||||
dmi_resp_data_o(11) <= not dm_ctrl.hart_halted; -- allrunning (r/-): there is only one hart that can be RUNNING or HALTED
|
||||
dmi_resp_data_o(10) <= not dm_ctrl.hart_halted; -- anyrunning (r/-): there is only one hart that can be RUNNING or HALTED
|
||||
dmi_resp_data_o(09) <= dm_ctrl.hart_halted; -- allhalted (r/-): there is only one hart that can be RUNNING or HALTED
|
||||
dmi_resp_data_o(08) <= dm_ctrl.hart_halted; -- anyhalted (r/-): there is only one hart that can be RUNNING or HALTED
|
||||
dmi_resp_data_o(07) <= '1'; -- authenticated (r/-): authentication passed since there is no authentication
|
||||
dmi_resp_data_o(06) <= '0'; -- authbusy (r/-): always ready since there is no authentication
|
||||
dmi_resp_data_o(05) <= '0'; -- hasresethaltreq (r/-): halt-on-reset not implemented
|
||||
dmi_resp_data_o(04) <= '0'; -- confstrptrvalid (r/-): no configuration string available
|
||||
dmi_resp_data_o(03 downto 00) <= "0010"; -- version (r/-): compatible to version 0.13
|
||||
|
||||
-- debug module control --
|
||||
when addr_dmcontrol_c =>
|
||||
dmi_resp_data_o(31) <= '0'; -- haltreq (-/w): write-only
|
||||
dmi_resp_data_o(30) <= '0'; -- resumereq (-/w1): write-only
|
||||
dmi_resp_data_o(29) <= '0'; -- hartreset (r/w): not supported
|
||||
dmi_resp_data_o(28) <= '0'; -- ackhavereset (-/w1): write-only
|
||||
dmi_resp_data_o(27) <= '0'; -- reserved (r/-)
|
||||
dmi_resp_data_o(26) <= '0'; -- hasel (r/-) - there is a single currently selected hart
|
||||
dmi_resp_data_o(25 downto 16) <= (others => '0'); -- hartsello (r/-) - there is only one hart
|
||||
dmi_resp_data_o(15 downto 06) <= (others => '0'); -- hartselhi (r/-) - there is only one hart
|
||||
dmi_resp_data_o(05 downto 04) <= (others => '0'); -- reserved (r/-)
|
||||
dmi_resp_data_o(03) <= '0'; -- setresethaltreq (-/w1): halt-on-reset request - halt-on-reset not implemented
|
||||
dmi_resp_data_o(02) <= '0'; -- clrresethaltreq (-/w1): halt-on-reset ack - halt-on-reset not implemented
|
||||
dmi_resp_data_o(01) <= dm_reg.dmcontrol_ndmreset; -- ndmreset (r/w): soc reset
|
||||
dmi_resp_data_o(00) <= dm_reg.dmcontrol_dmactive; -- dmactive (r/w): DM reset
|
||||
|
||||
-- hart info --
|
||||
when addr_hartinfo_c =>
|
||||
dmi_resp_data_o(31 downto 24) <= (others => '0'); -- reserved (r/-)
|
||||
dmi_resp_data_o(23 downto 20) <= nscratch_c; -- nscratch (r/-): number of dscratch CSRs
|
||||
dmi_resp_data_o(19 downto 17) <= (others => '0'); -- reserved (r/-)
|
||||
dmi_resp_data_o(16) <= dataaccess_c; -- dataaccess (r/-): 1: data registers are memory-mapped, 0: data reisters are CSR-mapped
|
||||
dmi_resp_data_o(15 downto 12) <= datasize_c; -- datasize (r/-): number data registers in memory/CSR space
|
||||
dmi_resp_data_o(11 downto 00) <= dataaddr_c; -- dataaddr (r/-): data registers base address (memory/CSR)
|
||||
|
||||
-- abstract control and status --
|
||||
when addr_abstractcs_c =>
|
||||
dmi_resp_data_o(31 downto 24) <= (others => '0'); -- reserved (r/-)
|
||||
dmi_resp_data_o(28 downto 24) <= "00010"; -- progbufsize (r/-): number of words in program buffer = 2
|
||||
dmi_resp_data_o(12) <= dm_ctrl.busy; -- busy (r/-): abstract command in progress (1) / idle (0)
|
||||
dmi_resp_data_o(11) <= '0'; -- reserved (r/-)
|
||||
dmi_resp_data_o(10 downto 08) <= dm_ctrl.cmderr; -- cmderr (r/w1c): any error during execution?
|
||||
dmi_resp_data_o(07 downto 04) <= (others => '0'); -- reserved (r/-)
|
||||
dmi_resp_data_o(03 downto 00) <= "0001"; -- datacount (r/-): number of implemented data registers = 1
|
||||
|
||||
-- -- abstract command (-/w) --
|
||||
-- when addr_command_c =>
|
||||
-- dmi_resp_data_o <= (others => '0'); -- register is write-only
|
||||
|
||||
-- abstract command autoexec (r/w) --
|
||||
when addr_abstractauto_c =>
|
||||
dmi_resp_data_o(00) <= dm_reg.abstractauto_autoexecdata; -- autoexecdata(0): read/write access to data0 triggers execution of program buffer
|
||||
dmi_resp_data_o(16) <= dm_reg.abstractauto_autoexecprogbuf(0); -- autoexecprogbuf(0): read/write access to progbuf0 triggers execution of program buffer
|
||||
dmi_resp_data_o(17) <= dm_reg.abstractauto_autoexecprogbuf(1); -- autoexecprogbuf(1): read/write access to progbuf1 triggers execution of program buffer
|
||||
|
||||
-- -- next debug module (r/-) --
|
||||
-- when addr_nextdm_c =>
|
||||
-- dmi_resp_data_o <= (others => '0'); -- this is the only DM
|
||||
|
||||
-- abstract data 0 (r/w) --
|
||||
when addr_data0_c =>
|
||||
dmi_resp_data_o <= dci.rdata;
|
||||
|
||||
-- program buffer (r/w) --
|
||||
when addr_progbuf0_c =>
|
||||
dmi_resp_data_o <= dm_reg.progbuf(0); -- program buffer 0
|
||||
when addr_progbuf1_c =>
|
||||
dmi_resp_data_o <= dm_reg.progbuf(1); -- program buffer 1
|
||||
|
||||
-- -- system bus access control and status (r/-) --
|
||||
-- when addr_sbcs_c =>
|
||||
-- dmi_resp_data_o <= (others => '0'); -- bus access not implemented
|
||||
|
||||
-- halt summary 0 (r/-) --
|
||||
when addr_haltsum0_c =>
|
||||
dmi_resp_data_o(0) <= dm_ctrl.hart_halted; -- hart is halted
|
||||
|
||||
-- not implemented (r/-) --
|
||||
when others =>
|
||||
dmi_resp_data_o <= (others => '0');
|
||||
end case;
|
||||
|
||||
-- invalid read access (while command is executing)
|
||||
-- ------------------------------------------------------------
|
||||
if (dmi_req_valid_i = '1') and (dmi_req_op_i = '0') then -- valid DMI read request
|
||||
if (dm_ctrl.busy = '1') then -- busy
|
||||
if (dmi_req_addr_i = addr_data0_c) or
|
||||
(dmi_req_addr_i = addr_progbuf0_c) or
|
||||
(dmi_req_addr_i = addr_progbuf1_c) then
|
||||
dm_reg.rd_acc_err <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- auto execution trigger --
|
||||
-- ------------------------------------------------------------
|
||||
if (dmi_req_valid_i = '1') and (dmi_req_op_i = '0') then -- valid DMI read request
|
||||
if ((dmi_req_addr_i = addr_data0_c) and (dm_reg.abstractauto_autoexecdata = '1')) or
|
||||
((dmi_req_addr_i = addr_progbuf0_c) and (dm_reg.abstractauto_autoexecprogbuf(0) = '1')) or
|
||||
((dmi_req_addr_i = addr_progbuf1_c) and (dm_reg.abstractauto_autoexecprogbuf(1) = '1')) then
|
||||
dm_reg.autoexec_rd <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process dmi_read_access;
|
||||
|
||||
|
||||
-- **************************************************************************************************************************
|
||||
-- CPU Bus Interface
|
||||
-- **************************************************************************************************************************
|
||||
|
||||
-- Access Control ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (cpu_addr_i(hi_abb_c downto lo_abb_c) = dm_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
maddr <= cpu_addr_i(lo_abb_c-1 downto lo_abb_c-2); -- (sub-)module select address
|
||||
rden <= acc_en and cpu_rden_i;
|
||||
wren <= acc_en and cpu_wren_i;
|
||||
|
||||
|
||||
-- Write Access ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
write_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- Data buffer --
|
||||
if (dci.data_we = '1') then -- DM write access
|
||||
data_buf <= dci.wdata;
|
||||
elsif (acc_en = '1') and (maddr = "10") and (wren = '1') then -- BUS write access
|
||||
data_buf <= cpu_data_i;
|
||||
end if;
|
||||
-- Control and Status Register --
|
||||
dci.halt_ack <= '0'; -- all writable flags auto-clear
|
||||
dci.resume_ack <= '0';
|
||||
dci.execute_ack <= '0';
|
||||
dci.exception_ack <= '0';
|
||||
if (acc_en = '1') and (maddr = "11") and (wren = '1') then
|
||||
dci.halt_ack <= cpu_data_i(sreg_halt_ack_c);
|
||||
dci.resume_ack <= cpu_data_i(sreg_resume_ack_c);
|
||||
dci.execute_ack <= cpu_data_i(sreg_execute_ack_c);
|
||||
dci.exception_ack <= cpu_data_i(sreg_exception_ack_c);
|
||||
end if;
|
||||
end if;
|
||||
end process write_access;
|
||||
|
||||
-- DM data buffer read access --
|
||||
dci.rdata <= data_buf;
|
||||
|
||||
|
||||
-- Read Access ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
read_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
cpu_ack_o <= rden or wren;
|
||||
cpu_data_o <= (others => '0');
|
||||
if (rden = '1') then -- output gate
|
||||
case maddr is -- module select
|
||||
when "00" => -- code ROM
|
||||
cpu_data_o <= code_rom_file(to_integer(unsigned(cpu_addr_i(6 downto 2))));
|
||||
when "01" => -- program buffer
|
||||
cpu_data_o <= cpu_progbuf(to_integer(unsigned(cpu_addr_i(3 downto 2))));
|
||||
when "10" => -- data buffer
|
||||
cpu_data_o <= data_buf;
|
||||
when others => -- status/control register
|
||||
cpu_data_o(sreg_resume_req_c) <= dci.resume_req;
|
||||
cpu_data_o(sreg_execute_req_c) <= dci.execute_req;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process read_access;
|
||||
|
||||
|
||||
end neorv32_debug_dm_rtl;
|
353
Libs/RiscV/NEORV32/rtl/core/neorv32_debug_dtm.vhd
Normal file
353
Libs/RiscV/NEORV32/rtl/core/neorv32_debug_dtm.vhd
Normal file
@ -0,0 +1,353 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - RISC-V Debug Transport Module (DTM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Provides a JTAG-compatible TAP to access the DMI register interface. #
|
||||
-- # Compatible to the RISC-V debug specification. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # https://github.com/stnolting/riscv-debug-dtm (c) Stephan Nolting #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
entity neorv32_debug_dtm is
|
||||
generic (
|
||||
IDCODE_VERSION : std_ulogic_vector(03 downto 0); -- version
|
||||
IDCODE_PARTID : std_ulogic_vector(15 downto 0); -- part number
|
||||
IDCODE_MANID : std_ulogic_vector(10 downto 0) -- manufacturer id
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rstn_i : in std_ulogic; -- global reset line, low-active
|
||||
-- jtag connection --
|
||||
jtag_trst_i : in std_ulogic;
|
||||
jtag_tck_i : in std_ulogic;
|
||||
jtag_tdi_i : in std_ulogic;
|
||||
jtag_tdo_o : out std_ulogic;
|
||||
jtag_tms_i : in std_ulogic;
|
||||
-- debug module interface (DMI) --
|
||||
dmi_rstn_o : out std_ulogic;
|
||||
dmi_req_valid_o : out std_ulogic;
|
||||
dmi_req_ready_i : in std_ulogic; -- DMI is allowed to make new requests when set
|
||||
dmi_req_addr_o : out std_ulogic_vector(06 downto 0);
|
||||
dmi_req_op_o : out std_ulogic; -- 0=read, 1=write
|
||||
dmi_req_data_o : out std_ulogic_vector(31 downto 0);
|
||||
dmi_resp_valid_i : in std_ulogic; -- response valid when set
|
||||
dmi_resp_ready_o : out std_ulogic; -- ready to receive respond
|
||||
dmi_resp_data_i : in std_ulogic_vector(31 downto 0);
|
||||
dmi_resp_err_i : in std_ulogic -- 0=ok, 1=error
|
||||
);
|
||||
end neorv32_debug_dtm;
|
||||
|
||||
architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is
|
||||
|
||||
-- DMI Configuration (fixed!) --
|
||||
constant dmi_idle_c : std_ulogic_vector(02 downto 0) := "000"; -- no idle cycles required
|
||||
constant dmi_version_c : std_ulogic_vector(03 downto 0) := "0001"; -- version (0.13)
|
||||
constant dmi_abits_c : std_ulogic_vector(05 downto 0) := "000111"; -- number of DMI address bits (7)
|
||||
|
||||
-- tap JTAG signal synchronizer --
|
||||
type tap_sync_t is record
|
||||
-- internal --
|
||||
trst_ff : std_ulogic_vector(2 downto 0);
|
||||
tck_ff : std_ulogic_vector(2 downto 0);
|
||||
tdi_ff : std_ulogic_vector(2 downto 0);
|
||||
tms_ff : std_ulogic_vector(2 downto 0);
|
||||
-- external --
|
||||
trst : std_ulogic;
|
||||
tck_rising : std_ulogic;
|
||||
tck_falling : std_ulogic;
|
||||
tdi : std_ulogic;
|
||||
tdo : std_ulogic;
|
||||
tms : std_ulogic;
|
||||
end record;
|
||||
signal tap_sync : tap_sync_t;
|
||||
|
||||
-- tap controller - fsm --
|
||||
type tap_ctrl_state_t is (LOGIC_RESET, DR_SCAN, DR_CAPTURE, DR_SHIFT, DR_EXIT1, DR_PAUSE, DR_EXIT2, DR_UPDATE,
|
||||
RUN_IDLE, IR_SCAN, IR_CAPTURE, IR_SHIFT, IR_EXIT1, IR_PAUSE, IR_EXIT2, IR_UPDATE);
|
||||
type tap_ctrl_t is record
|
||||
state : tap_ctrl_state_t;
|
||||
state_prev : tap_ctrl_state_t;
|
||||
end record;
|
||||
signal tap_ctrl : tap_ctrl_t;
|
||||
|
||||
-- tap registers --
|
||||
type tap_reg_t is record
|
||||
ireg : std_ulogic_vector(04 downto 0);
|
||||
bypass : std_ulogic;
|
||||
idcode : std_ulogic_vector(31 downto 0);
|
||||
dtmcs, dtmcs_nxt : std_ulogic_vector(31 downto 0);
|
||||
dmi, dmi_nxt : std_ulogic_vector((7+32+2)-1 downto 0); -- 7-bit address + 32-bit data + 2-bit operation
|
||||
end record;
|
||||
signal tap_reg : tap_reg_t;
|
||||
|
||||
-- debug module interface --
|
||||
type dmi_ctrl_state_t is (DMI_IDLE, DMI_READ_WAIT, DMI_READ, DMI_READ_BUSY,
|
||||
DMI_WRITE_WAIT, DMI_WRITE, DMI_WRITE_BUSY);
|
||||
type dmi_ctrl_t is record
|
||||
state : dmi_ctrl_state_t;
|
||||
--
|
||||
dmihardreset : std_ulogic;
|
||||
dmireset : std_ulogic;
|
||||
--
|
||||
err : std_ulogic; -- sticky error
|
||||
rdata : std_ulogic_vector(31 downto 0);
|
||||
wdata : std_ulogic_vector(31 downto 0);
|
||||
addr : std_ulogic_vector(06 downto 0);
|
||||
end record;
|
||||
signal dmi_ctrl : dmi_ctrl_t;
|
||||
|
||||
begin
|
||||
|
||||
-- JTAG Signal Synchronizer ---------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
tap_synchronizer: process(rstn_i, clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
tap_sync.trst_ff <= tap_sync.trst_ff(1 downto 0) & jtag_trst_i;
|
||||
tap_sync.tck_ff <= tap_sync.tck_ff( 1 downto 0) & jtag_tck_i;
|
||||
tap_sync.tdi_ff <= tap_sync.tdi_ff( 1 downto 0) & jtag_tdi_i;
|
||||
tap_sync.tms_ff <= tap_sync.tms_ff( 1 downto 0) & jtag_tms_i;
|
||||
if (tap_sync.tck_falling = '1') then -- update output data TDO on falling edge of TCK
|
||||
jtag_tdo_o <= tap_sync.tdo;
|
||||
end if;
|
||||
end if;
|
||||
end process tap_synchronizer;
|
||||
|
||||
-- JTAG reset --
|
||||
tap_sync.trst <= '0' when (tap_sync.trst_ff(2 downto 1) = "00") else '1';
|
||||
|
||||
-- JTAG clock edge --
|
||||
tap_sync.tck_rising <= '1' when (tap_sync.tck_ff(2 downto 1) = "01") else '0';
|
||||
tap_sync.tck_falling <= '1' when (tap_sync.tck_ff(2 downto 1) = "10") else '0';
|
||||
|
||||
-- JTAG test mode select --
|
||||
tap_sync.tms <= tap_sync.tms_ff(2);
|
||||
|
||||
-- JTAG serial data input --
|
||||
tap_sync.tdi <= tap_sync.tdi_ff(2);
|
||||
|
||||
|
||||
-- Tap Control FSM ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
tap_control: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
tap_ctrl.state <= LOGIC_RESET;
|
||||
tap_ctrl.state_prev <= LOGIC_RESET;
|
||||
elsif rising_edge(clk_i) then
|
||||
tap_ctrl.state_prev <= tap_ctrl.state;
|
||||
if (tap_sync.trst = '0') then -- reset
|
||||
tap_ctrl.state <= LOGIC_RESET;
|
||||
elsif (tap_sync.tck_rising = '1') then -- clock pulse (evaluate TMS on the rising edge of TCK)
|
||||
case tap_ctrl.state is -- JTAG state machine
|
||||
when LOGIC_RESET => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= LOGIC_RESET; end if;
|
||||
when RUN_IDLE => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
|
||||
when DR_SCAN => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_CAPTURE; else tap_ctrl.state <= IR_SCAN; end if;
|
||||
when DR_CAPTURE => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_EXIT1; end if;
|
||||
when DR_SHIFT => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_EXIT1; end if;
|
||||
when DR_EXIT1 => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_PAUSE; else tap_ctrl.state <= DR_UPDATE; end if;
|
||||
when DR_PAUSE => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_PAUSE; else tap_ctrl.state <= DR_EXIT2; end if;
|
||||
when DR_EXIT2 => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_UPDATE; end if;
|
||||
when DR_UPDATE => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
|
||||
when IR_SCAN => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_CAPTURE; else tap_ctrl.state <= LOGIC_RESET; end if;
|
||||
when IR_CAPTURE => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_EXIT1; end if;
|
||||
when IR_SHIFT => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_EXIT1; end if;
|
||||
when IR_EXIT1 => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_PAUSE; else tap_ctrl.state <= IR_UPDATE; end if;
|
||||
when IR_PAUSE => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_PAUSE; else tap_ctrl.state <= IR_EXIT2; end if;
|
||||
when IR_EXIT2 => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_UPDATE; end if;
|
||||
when IR_UPDATE => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
|
||||
when others => tap_ctrl.state <= LOGIC_RESET;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process tap_control;
|
||||
|
||||
|
||||
-- Tap Register Access --------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
reg_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- serial data input --
|
||||
if (tap_sync.tck_rising = '1') then -- clock pulse (evaluate TDI on rising edge of TCK)
|
||||
|
||||
-- instruction register --
|
||||
if (tap_ctrl.state = LOGIC_RESET) or (tap_ctrl.state = IR_CAPTURE) then -- reset or preload phase
|
||||
tap_reg.ireg <= "00001"; -- IDCODE
|
||||
elsif (tap_ctrl.state = IR_SHIFT) then -- access phase
|
||||
tap_reg.ireg <= tap_sync.tdi & tap_reg.ireg(tap_reg.ireg'left downto 1);
|
||||
end if;
|
||||
|
||||
-- data register --
|
||||
if (tap_ctrl.state = DR_CAPTURE) then -- preload phase
|
||||
case tap_reg.ireg is
|
||||
when "00001" => tap_reg.idcode <= IDCODE_VERSION & IDCODE_PARTID & IDCODE_MANID & '1'; -- IDCODE (LSB has to be always set!)
|
||||
when "10000" => tap_reg.dtmcs <= tap_reg.dtmcs_nxt;-- dtmcs
|
||||
when "10001" => tap_reg.dmi <= tap_reg.dmi_nxt; -- dmi
|
||||
when others => tap_reg.bypass <= '0'; -- BYPASS
|
||||
end case;
|
||||
elsif (tap_ctrl.state = DR_SHIFT) then -- access phase
|
||||
case tap_reg.ireg is
|
||||
when "00001" => tap_reg.idcode <= tap_sync.tdi & tap_reg.idcode(tap_reg.idcode'left downto 1); -- IDCODE
|
||||
when "10000" => tap_reg.dtmcs <= tap_sync.tdi & tap_reg.dtmcs(tap_reg.dtmcs'left downto 1); -- dtmcs
|
||||
when "10001" => tap_reg.dmi <= tap_sync.tdi & tap_reg.dmi(tap_reg.dmi'left downto 1); -- dmi
|
||||
when others => tap_reg.bypass <= tap_sync.tdi; -- BYPASS
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- serial data output --
|
||||
if (tap_ctrl.state = IR_SHIFT) then
|
||||
tap_sync.tdo <= tap_reg.ireg(0);
|
||||
else
|
||||
case tap_reg.ireg is
|
||||
when "00001" => tap_sync.tdo <= tap_reg.idcode(0); -- IDCODE
|
||||
when "10000" => tap_sync.tdo <= tap_reg.dtmcs(0); -- dtmcs
|
||||
when "10001" => tap_sync.tdo <= tap_reg.dmi(0); -- dmi
|
||||
when others => tap_sync.tdo <= tap_reg.bypass; -- BYPASS
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process reg_access;
|
||||
|
||||
|
||||
-- Debug Module Interface -----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
dmi_controller: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
dmi_ctrl.state <= DMI_IDLE;
|
||||
dmi_ctrl.dmihardreset <= '1';
|
||||
dmi_ctrl.dmireset <= '1';
|
||||
dmi_ctrl.err <= '0';
|
||||
dmi_ctrl.rdata <= (others => '-');
|
||||
dmi_ctrl.wdata <= (others => '-');
|
||||
dmi_ctrl.addr <= (others => '-');
|
||||
elsif rising_edge(clk_i) then
|
||||
|
||||
-- DMI status and control --
|
||||
dmi_ctrl.dmihardreset <= '0'; -- default
|
||||
dmi_ctrl.dmireset <= '0'; -- default
|
||||
if (tap_ctrl.state = DR_UPDATE) and (tap_ctrl.state_prev /= DR_UPDATE) and (tap_reg.ireg = "10000") then
|
||||
dmi_ctrl.dmireset <= tap_reg.dtmcs(16);
|
||||
dmi_ctrl.dmihardreset <= tap_reg.dtmcs(17);
|
||||
end if;
|
||||
|
||||
-- DMI interface arbiter --
|
||||
if (dmi_ctrl.dmihardreset = '1') then -- DMI hard reset
|
||||
dmi_ctrl.state <= DMI_IDLE;
|
||||
dmi_ctrl.err <= '0';
|
||||
else
|
||||
case dmi_ctrl.state is
|
||||
|
||||
when DMI_IDLE => -- waiting for new request
|
||||
if (tap_ctrl.state = DR_UPDATE) and (tap_ctrl.state_prev /= DR_UPDATE) and (tap_reg.ireg = "10001") then -- update <dmi>
|
||||
if (tap_reg.dmi(1 downto 0) = "01") then -- read
|
||||
dmi_ctrl.state <= DMI_READ_WAIT;
|
||||
elsif (tap_reg.dmi(1 downto 0) = "10") then -- write
|
||||
dmi_ctrl.state <= DMI_WRITE_WAIT;
|
||||
end if;
|
||||
dmi_ctrl.addr <= tap_reg.dmi(40 downto 34);
|
||||
dmi_ctrl.wdata <= tap_reg.dmi(33 downto 02);
|
||||
end if;
|
||||
|
||||
|
||||
when DMI_READ_WAIT => -- wait for DMI to become ready
|
||||
if (dmi_req_ready_i = '1') then
|
||||
dmi_ctrl.state <= DMI_READ;
|
||||
end if;
|
||||
|
||||
when DMI_READ => -- start read access
|
||||
dmi_ctrl.state <= DMI_READ_BUSY;
|
||||
|
||||
when DMI_READ_BUSY => -- pending read access
|
||||
if (dmi_resp_valid_i = '1') then
|
||||
dmi_ctrl.rdata <= dmi_resp_data_i;
|
||||
dmi_ctrl.err <= dmi_ctrl.err or dmi_resp_err_i; -- sticky error
|
||||
dmi_ctrl.state <= DMI_IDLE;
|
||||
end if;
|
||||
|
||||
|
||||
when DMI_WRITE_WAIT => -- wait for DMI to become ready
|
||||
if (dmi_req_ready_i = '1') then
|
||||
dmi_ctrl.state <= DMI_WRITE;
|
||||
end if;
|
||||
|
||||
when DMI_WRITE => -- start write access
|
||||
dmi_ctrl.state <= DMI_WRITE_BUSY;
|
||||
|
||||
when DMI_WRITE_BUSY => -- pending write access
|
||||
if (dmi_resp_valid_i = '1') then
|
||||
dmi_ctrl.err <= dmi_ctrl.err or dmi_resp_err_i; -- sticky error
|
||||
dmi_ctrl.state <= DMI_IDLE;
|
||||
end if;
|
||||
|
||||
|
||||
when others => -- undefined
|
||||
dmi_ctrl.state <= DMI_IDLE;
|
||||
|
||||
end case;
|
||||
-- clear sticky error flag --
|
||||
if (dmi_ctrl.dmireset = '1') then
|
||||
dmi_ctrl.err <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process dmi_controller;
|
||||
|
||||
-- DTM Control and Status Register (dtmcs) --
|
||||
tap_reg.dtmcs_nxt(31 downto 18) <= (others => '0'); -- unused
|
||||
tap_reg.dtmcs_nxt(17) <= '0'; -- dmihardreset, always reads as zero
|
||||
tap_reg.dtmcs_nxt(16) <= '0'; -- dmireset, always reads as zero
|
||||
tap_reg.dtmcs_nxt(15) <= '0'; -- unused
|
||||
tap_reg.dtmcs_nxt(14 downto 12) <= dmi_idle_c; -- minimum number of idle cycles
|
||||
tap_reg.dtmcs_nxt(11 downto 10) <= tap_reg.dmi_nxt(1 downto 0); -- dmistat
|
||||
tap_reg.dtmcs_nxt(09 downto 04) <= dmi_abits_c; -- number of DMI address bits
|
||||
tap_reg.dtmcs_nxt(03 downto 00) <= dmi_version_c; -- version
|
||||
|
||||
-- DMI register read access --
|
||||
tap_reg.dmi_nxt(40 downto 34) <= dmi_ctrl.addr; -- address
|
||||
tap_reg.dmi_nxt(33 downto 02) <= dmi_ctrl.rdata; -- read data
|
||||
tap_reg.dmi_nxt(01 downto 00) <= "11" when (dmi_ctrl.state /= DMI_IDLE) else (dmi_ctrl.err & '0'); -- status
|
||||
|
||||
-- direct DMI output --
|
||||
dmi_rstn_o <= '0' when (dmi_ctrl.dmihardreset = '1') else '1';
|
||||
dmi_req_valid_o <= '1' when (dmi_ctrl.state = DMI_READ) or (dmi_ctrl.state = DMI_WRITE) else '0';
|
||||
dmi_req_op_o <= '1' when (dmi_ctrl.state = DMI_WRITE) or (dmi_ctrl.state = DMI_WRITE_BUSY) else '0';
|
||||
dmi_resp_ready_o <= '1' when (dmi_ctrl.state = DMI_READ_BUSY) or (dmi_ctrl.state = DMI_WRITE_BUSY) else '0';
|
||||
dmi_req_addr_o <= dmi_ctrl.addr;
|
||||
dmi_req_data_o <= dmi_ctrl.wdata;
|
||||
|
||||
|
||||
end neorv32_debug_dtm_rtl;
|
54
Libs/RiscV/NEORV32/rtl/core/neorv32_dmem.entity.vhd
Normal file
54
Libs/RiscV/NEORV32/rtl/core/neorv32_dmem.entity.vhd
Normal file
@ -0,0 +1,54 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-internal data memory (DMEM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
|
||||
entity neorv32_dmem is
|
||||
generic (
|
||||
DMEM_BASE : std_ulogic_vector(31 downto 0); -- memory base address
|
||||
DMEM_SIZE : natural -- processor-internal instruction memory size in bytes
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rden_i : in std_ulogic; -- read enable
|
||||
wren_i : in std_ulogic; -- write enable
|
||||
ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable
|
||||
addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
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
|
||||
);
|
||||
end neorv32_dmem;
|
188
Libs/RiscV/NEORV32/rtl/core/neorv32_fifo.vhd
Normal file
188
Libs/RiscV/NEORV32/rtl/core/neorv32_fifo.vhd
Normal file
@ -0,0 +1,188 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - General Purpose FIFO Component >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_fifo is
|
||||
generic (
|
||||
FIFO_DEPTH : natural; -- number of fifo entries; has to be a power of two; min 1
|
||||
FIFO_WIDTH : natural; -- size of data elements in fifo
|
||||
FIFO_RSYNC : boolean; -- false = async read; true = sync read
|
||||
FIFO_SAFE : boolean -- true = allow read/write only if entry available
|
||||
);
|
||||
port (
|
||||
-- control --
|
||||
clk_i : in std_ulogic; -- clock, rising edge
|
||||
rstn_i : in std_ulogic; -- async reset, low-active
|
||||
clear_i : in std_ulogic; -- sync reset, high-active
|
||||
level_o : out std_ulogic_vector(index_size_f(FIFO_DEPTH) downto 0); -- fill level
|
||||
half_o : out std_ulogic; -- FIFO is at least half full
|
||||
-- write port --
|
||||
wdata_i : in std_ulogic_vector(FIFO_WIDTH-1 downto 0); -- write data
|
||||
we_i : in std_ulogic; -- write enable
|
||||
free_o : out std_ulogic; -- at least one entry is free when set
|
||||
-- read port --
|
||||
re_i : in std_ulogic; -- read enable
|
||||
rdata_o : out std_ulogic_vector(FIFO_WIDTH-1 downto 0); -- read data
|
||||
avail_o : out std_ulogic -- data available when set
|
||||
);
|
||||
end neorv32_fifo;
|
||||
|
||||
architecture neorv32_fifo_rtl of neorv32_fifo is
|
||||
|
||||
-- FIFO --
|
||||
type fifo_data_t is array (0 to FIFO_DEPTH-1) of std_ulogic_vector(FIFO_WIDTH-1 downto 0);
|
||||
type fifo_t is record
|
||||
we : std_ulogic; -- write enable
|
||||
re : std_ulogic; -- read enable
|
||||
w_pnt : std_ulogic_vector(index_size_f(FIFO_DEPTH) downto 0); -- write pointer
|
||||
r_pnt : std_ulogic_vector(index_size_f(FIFO_DEPTH) downto 0); -- read pointer
|
||||
level : std_ulogic_vector(index_size_f(FIFO_DEPTH) downto 0); -- fill count
|
||||
data : fifo_data_t; -- fifo memory
|
||||
datas : std_ulogic_vector(FIFO_WIDTH-1 downto 0);
|
||||
match : std_ulogic;
|
||||
empty : std_ulogic;
|
||||
full : std_ulogic;
|
||||
free : std_ulogic;
|
||||
avail : std_ulogic;
|
||||
end record;
|
||||
signal fifo : fifo_t;
|
||||
|
||||
signal level_diff : std_ulogic_vector(index_size_f(FIFO_DEPTH) downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (FIFO_DEPTH = 0) report "NEORV32 CONFIG ERROR: FIFO depth has to be > 0." severity error;
|
||||
assert not (is_power_of_two_f(FIFO_DEPTH) = false) report "NEORV32 CONFIG ERROR: FIFO depth has to be a power of two." severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
fifo.re <= re_i when (FIFO_SAFE = false) else (re_i and fifo.avail); -- read only if data available
|
||||
fifo.we <= we_i when (FIFO_SAFE = false) else (we_i and fifo.free); -- write only if space left
|
||||
|
||||
|
||||
-- FIFO Control ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
fifo_control: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
fifo.w_pnt <= (others => '0');
|
||||
fifo.r_pnt <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
-- write port --
|
||||
if (clear_i = '1') then
|
||||
fifo.w_pnt <= (others => '0');
|
||||
elsif (fifo.we = '1') then
|
||||
fifo.w_pnt <= std_ulogic_vector(unsigned(fifo.w_pnt) + 1);
|
||||
end if;
|
||||
-- read port --
|
||||
if (clear_i = '1') then
|
||||
fifo.r_pnt <= (others => '0');
|
||||
elsif (fifo.re = '1') then
|
||||
fifo.r_pnt <= std_ulogic_vector(unsigned(fifo.r_pnt) + 1);
|
||||
end if;
|
||||
end if;
|
||||
end process fifo_control;
|
||||
|
||||
-- status --
|
||||
fifo.match <= '1' when (fifo.r_pnt(fifo.r_pnt'left-1 downto 0) = fifo.w_pnt(fifo.w_pnt'left-1 downto 0)) or (FIFO_DEPTH = 1) else '0';
|
||||
fifo.full <= '1' when (fifo.r_pnt(fifo.r_pnt'left) /= fifo.w_pnt(fifo.w_pnt'left)) and (fifo.match = '1') else '0';
|
||||
fifo.empty <= '1' when (fifo.r_pnt(fifo.r_pnt'left) = fifo.w_pnt(fifo.w_pnt'left)) and (fifo.match = '1') else '0';
|
||||
fifo.free <= not fifo.full;
|
||||
fifo.avail <= not fifo.empty;
|
||||
level_diff <= std_ulogic_vector(unsigned(fifo.w_pnt) - unsigned(fifo.r_pnt));
|
||||
fifo.level <= std_ulogic_vector(to_unsigned(FIFO_DEPTH, fifo.level'length)) when (fifo.full = '1') else level_diff;
|
||||
|
||||
-- status output --
|
||||
level_o <= fifo.level;
|
||||
free_o <= fifo.free;
|
||||
avail_o <= fifo.avail;
|
||||
|
||||
fifo_half_level:
|
||||
if (FIFO_DEPTH > 1) generate
|
||||
half_o <= level_diff(level_diff'left-1) or fifo.full;
|
||||
end generate;
|
||||
|
||||
fifo_half_level_simple:
|
||||
if (FIFO_DEPTH = 1) generate
|
||||
half_o <= fifo.full;
|
||||
end generate;
|
||||
|
||||
|
||||
-- FIFO Memory ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
fifo_memory_write: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (fifo.we = '1') then
|
||||
if (FIFO_DEPTH = 1) then
|
||||
fifo.datas <= wdata_i;
|
||||
else
|
||||
fifo.data(to_integer(unsigned(fifo.w_pnt(fifo.w_pnt'left-1 downto 0)))) <= wdata_i;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process fifo_memory_write;
|
||||
|
||||
-- asynchronous read --
|
||||
fifo_read_async:
|
||||
if (FIFO_RSYNC = false) generate
|
||||
rdata_o <= fifo.datas when (FIFO_DEPTH = 1) else fifo.data(to_integer(unsigned(fifo.r_pnt(fifo.r_pnt'left-1 downto 0))));
|
||||
end generate;
|
||||
|
||||
-- synchronous read --
|
||||
fifo_read_sync:
|
||||
if (FIFO_RSYNC = true) generate
|
||||
fifo_memory_read: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (FIFO_DEPTH = 1) then
|
||||
rdata_o <= fifo.datas;
|
||||
else
|
||||
rdata_o <= fifo.data(to_integer(unsigned(fifo.r_pnt(fifo.r_pnt'left-1 downto 0))));
|
||||
end if;
|
||||
end if;
|
||||
end process fifo_memory_read;
|
||||
end generate;
|
||||
|
||||
|
||||
end neorv32_fifo_rtl;
|
126
Libs/RiscV/NEORV32/rtl/core/neorv32_gpio.vhd
Normal file
126
Libs/RiscV/NEORV32/rtl/core/neorv32_gpio.vhd
Normal file
@ -0,0 +1,126 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - General Purpose Parallel Input/Output Port (GPIO) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 64-bit general purpose parallel input & output port unit. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_gpio 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
|
||||
-- parallel io --
|
||||
gpio_o : out std_ulogic_vector(63 downto 0);
|
||||
gpio_i : in std_ulogic_vector(63 downto 0)
|
||||
);
|
||||
end neorv32_gpio;
|
||||
|
||||
architecture neorv32_gpio_rtl of neorv32_gpio is
|
||||
|
||||
-- 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(gpio_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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- accessible regs --
|
||||
signal din_lo, din_hi : std_ulogic_vector(31 downto 0); -- r/-
|
||||
signal dout_lo, dout_hi : std_ulogic_vector(31 downto 0); -- r/w
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = gpio_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= gpio_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
|
||||
-- bus handshake --
|
||||
ack_o <= wren or rden;
|
||||
|
||||
-- write access --
|
||||
if (wren = '1') then
|
||||
if (addr = gpio_out_lo_addr_c) then
|
||||
dout_lo <= data_i;
|
||||
end if;
|
||||
if (addr = gpio_out_hi_addr_c) then
|
||||
dout_hi <= data_i;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- input buffer --
|
||||
din_lo <= gpio_i(31 downto 00);
|
||||
din_hi <= gpio_i(63 downto 32);
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
case addr(3 downto 2) is
|
||||
when "00" => data_o <= din_lo;
|
||||
when "01" => data_o <= din_hi;
|
||||
when "10" => data_o <= dout_lo;
|
||||
when others => data_o <= dout_hi;
|
||||
end case;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
-- output --
|
||||
gpio_o <= dout_hi & dout_lo;
|
||||
|
||||
|
||||
end neorv32_gpio_rtl;
|
203
Libs/RiscV/NEORV32/rtl/core/neorv32_gptmr.vhd
Normal file
203
Libs/RiscV/NEORV32/rtl/core/neorv32_gptmr.vhd
Normal file
@ -0,0 +1,203 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - General Purpose Timer (GPTMR) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 32-bit timer with configurable clock prescaler. The timer fires an interrupt whenever the #
|
||||
-- # counter register value reaches the programmed threshold value. The timer can operate in #
|
||||
-- # single-shot mode (count until it reaches THRESHOLD and stop) or in continuous mode (count #
|
||||
-- # until it reaches THRESHOLD and auto-reset). #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_gptmr 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);
|
||||
-- interrupt --
|
||||
irq_o : out std_ulogic -- transmission done interrupt
|
||||
);
|
||||
end neorv32_gptmr;
|
||||
|
||||
architecture neorv32_gptmr_rtl of neorv32_gptmr is
|
||||
|
||||
-- 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(gptmr_size_c); -- low address boundary bit
|
||||
|
||||
-- control register --
|
||||
constant ctrl_en_c : natural := 0; -- r/w: timer enable
|
||||
constant ctrl_prsc0_c : natural := 1; -- r/w: clock prescaler select bit 0
|
||||
constant ctrl_prsc1_c : natural := 2; -- r/w: clock prescaler select bit 1
|
||||
constant ctrl_prsc2_c : natural := 3; -- r/w: clock prescaler select bit 2
|
||||
constant ctrl_mode_c : natural := 4; -- r/w: mode (0=single-shot, 1=continuous)
|
||||
--
|
||||
signal ctrl : std_ulogic_vector(4 downto 0);
|
||||
|
||||
-- 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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- clock generator --
|
||||
signal gptmr_clk_en : std_ulogic;
|
||||
|
||||
-- timer core --
|
||||
type timer_t is record
|
||||
count : std_ulogic_vector(31 downto 0); -- counter register
|
||||
thres : std_ulogic_vector(31 downto 0); -- threshold value
|
||||
match : std_ulogic; -- count == thres
|
||||
cnt_we : std_ulogic; -- write access to count
|
||||
end record;
|
||||
signal timer : timer_t;
|
||||
|
||||
-- interrupt detector --
|
||||
signal irq_detect : std_ulogic_vector(1 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = gptmr_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= gptmr_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
|
||||
-- bus access acknowledge --
|
||||
ack_o <= rden or wren;
|
||||
|
||||
-- write access --
|
||||
timer.cnt_we <= '0';
|
||||
if (wren = '1') then
|
||||
if (addr = gptmr_ctrl_addr_c) then -- control register
|
||||
ctrl(ctrl_en_c) <= data_i(ctrl_en_c);
|
||||
ctrl(ctrl_prsc0_c) <= data_i(ctrl_prsc0_c);
|
||||
ctrl(ctrl_prsc1_c) <= data_i(ctrl_prsc1_c);
|
||||
ctrl(ctrl_prsc2_c) <= data_i(ctrl_prsc2_c);
|
||||
ctrl(ctrl_mode_c) <= data_i(ctrl_mode_c);
|
||||
end if;
|
||||
if (addr = gptmr_thres_addr_c) then -- threshold register
|
||||
timer.thres <= data_i;
|
||||
end if;
|
||||
if (addr = gptmr_count_addr_c) then -- counter register
|
||||
timer.cnt_we <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
case addr(3 downto 2) is
|
||||
when "00" => -- control register
|
||||
data_o(ctrl_en_c) <= ctrl(ctrl_en_c);
|
||||
data_o(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c);
|
||||
data_o(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c);
|
||||
data_o(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c);
|
||||
data_o(ctrl_mode_c) <= ctrl(ctrl_mode_c);
|
||||
when "01" => -- threshold register
|
||||
data_o <= timer.thres;
|
||||
when others => -- counter register
|
||||
data_o <= timer.count;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
-- clock generator enable --
|
||||
clkgen_en_o <= ctrl(ctrl_en_c);
|
||||
|
||||
-- clock select --
|
||||
gptmr_clk_en <= clkgen_i(to_integer(unsigned(ctrl(ctrl_prsc2_c downto ctrl_prsc0_c))));
|
||||
|
||||
|
||||
-- Timer Core -----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
timer_core: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (timer.cnt_we = '1') then -- write access
|
||||
timer.count <= data_i;
|
||||
elsif (ctrl(ctrl_en_c) = '1') and (gptmr_clk_en = '1') then -- enabled and clock tick
|
||||
if (timer.match = '1') then
|
||||
if (ctrl(ctrl_mode_c) = '1') then -- reset counter if continuous mode
|
||||
timer.count <= (others => '0');
|
||||
end if;
|
||||
else
|
||||
timer.count <= std_ulogic_vector(unsigned(timer.count) + 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process timer_core;
|
||||
|
||||
-- counter = threshold? --
|
||||
timer.match <= '1' when (timer.count = timer.thres) else '0';
|
||||
|
||||
|
||||
-- Interrupt Generator --------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
irq_generator: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (ctrl(ctrl_en_c) = '0') then
|
||||
irq_detect <= "00";
|
||||
else
|
||||
irq_detect <= irq_detect(0) & timer.match;
|
||||
end if;
|
||||
end if;
|
||||
end process irq_generator;
|
||||
|
||||
-- IRQ request to CPU --
|
||||
irq_o <= '1' when (irq_detect = "01") else '0';
|
||||
|
||||
|
||||
end neorv32_gptmr_rtl;
|
589
Libs/RiscV/NEORV32/rtl/core/neorv32_icache.vhd
Normal file
589
Libs/RiscV/NEORV32/rtl/core/neorv32_icache.vhd
Normal file
@ -0,0 +1,589 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-Internal Instruction Cache >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Direct mapped (ICACHE_NUM_SETS = 1) or 2-way set-associative (ICACHE_NUM_SETS = 2). #
|
||||
-- # Least recently used replacement policy (if ICACHE_NUM_SETS > 1). #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_icache is
|
||||
generic (
|
||||
ICACHE_NUM_BLOCKS : natural; -- number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural; -- block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_NUM_SETS : natural -- associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
clear_i : in std_ulogic; -- cache clear
|
||||
-- host controller interface --
|
||||
host_addr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
host_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
host_wdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
host_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable
|
||||
host_we_i : in std_ulogic; -- write enable
|
||||
host_re_i : in std_ulogic; -- read enable
|
||||
host_ack_o : out std_ulogic; -- bus transfer acknowledge
|
||||
host_err_o : out std_ulogic; -- bus transfer error
|
||||
-- peripheral bus interface --
|
||||
bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
||||
bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
||||
bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
||||
bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
||||
bus_we_o : out std_ulogic; -- write enable
|
||||
bus_re_o : out std_ulogic; -- read enable
|
||||
bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
||||
bus_err_i : in std_ulogic -- bus transfer error
|
||||
);
|
||||
end neorv32_icache;
|
||||
|
||||
architecture neorv32_icache_rtl of neorv32_icache is
|
||||
|
||||
-- cache layout --
|
||||
constant cache_offset_size_c : natural := index_size_f(ICACHE_BLOCK_SIZE/4); -- offset addresses full 32-bit words
|
||||
constant cache_index_size_c : natural := index_size_f(ICACHE_NUM_BLOCKS);
|
||||
constant cache_tag_size_c : natural := 32 - (cache_offset_size_c + cache_index_size_c + 2); -- 2 additonal bits for byte offset
|
||||
|
||||
-- cache memory --
|
||||
component neorv32_icache_memory
|
||||
generic (
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 16; -- block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_NUM_SETS : natural := 1 -- associativity; 0=direct-mapped, 1=2-way set-associative
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
invalidate_i : in std_ulogic; -- invalidate whole cache
|
||||
-- host cache access (read-only) --
|
||||
host_addr_i : in std_ulogic_vector(31 downto 0); -- access address
|
||||
host_re_i : in std_ulogic; -- read enable
|
||||
host_rdata_o : out std_ulogic_vector(31 downto 0); -- read data
|
||||
-- access status (1 cycle delay to access) --
|
||||
hit_o : out std_ulogic; -- hit access
|
||||
-- ctrl cache access (write-only) --
|
||||
ctrl_en_i : in std_ulogic; -- control interface enable
|
||||
ctrl_addr_i : in std_ulogic_vector(31 downto 0); -- access address
|
||||
ctrl_we_i : in std_ulogic; -- write enable (full-word)
|
||||
ctrl_wdata_i : in std_ulogic_vector(31 downto 0); -- write data
|
||||
ctrl_tag_we_i : in std_ulogic; -- write tag to selected block
|
||||
ctrl_valid_i : in std_ulogic; -- make selected block valid
|
||||
ctrl_invalid_i : in std_ulogic -- make selected block invalid
|
||||
);
|
||||
end component;
|
||||
|
||||
-- cache interface --
|
||||
type cache_if_t is record
|
||||
clear : std_ulogic; -- cache clear
|
||||
--
|
||||
host_addr : std_ulogic_vector(31 downto 0); -- cpu access address
|
||||
host_rdata : std_ulogic_vector(31 downto 0); -- cpu read data
|
||||
--
|
||||
hit : std_ulogic; -- hit access
|
||||
--
|
||||
ctrl_en : std_ulogic; -- control access enable
|
||||
ctrl_addr : std_ulogic_vector(31 downto 0); -- control access address
|
||||
ctrl_we : std_ulogic; -- control write enable
|
||||
ctrl_wdata : std_ulogic_vector(31 downto 0); -- control write data
|
||||
ctrl_tag_we : std_ulogic; -- control tag write enabled
|
||||
ctrl_valid_we : std_ulogic; -- control valid flag set
|
||||
ctrl_invalid_we : std_ulogic; -- control valid flag clear
|
||||
end record;
|
||||
signal cache : cache_if_t;
|
||||
|
||||
-- control engine --
|
||||
type ctrl_engine_state_t is (S_IDLE, S_CACHE_CLEAR, S_CACHE_CHECK, S_CACHE_MISS, S_BUS_DOWNLOAD_REQ, S_BUS_DOWNLOAD_GET,
|
||||
S_CACHE_RESYNC_0, S_CACHE_RESYNC_1, S_BUS_ERROR);
|
||||
type ctrl_t is record
|
||||
state : ctrl_engine_state_t; -- current state
|
||||
state_nxt : ctrl_engine_state_t; -- next state
|
||||
addr_reg : std_ulogic_vector(31 downto 0); -- address register for block download
|
||||
addr_reg_nxt : std_ulogic_vector(31 downto 0);
|
||||
--
|
||||
re_buf : std_ulogic; -- read request buffer
|
||||
re_buf_nxt : std_ulogic;
|
||||
--
|
||||
clear_buf : std_ulogic; -- clear request buffer
|
||||
clear_buf_nxt : std_ulogic;
|
||||
end record;
|
||||
signal ctrl : ctrl_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- configuration --
|
||||
assert not (is_power_of_two_f(ICACHE_NUM_BLOCKS) = false) report "NEORV32 PROCESSOR CONFIG ERROR! i-cache number of blocks <ICACHE_NUM_BLOCKS> has to be a power of 2." severity error;
|
||||
assert not (is_power_of_two_f(ICACHE_BLOCK_SIZE) = false) report "NEORV32 PROCESSOR CONFIG ERROR! i-cache block size <ICACHE_BLOCK_SIZE> has to be a power of 2." severity error;
|
||||
assert not ((is_power_of_two_f(ICACHE_NUM_SETS) = false)) report "NEORV32 PROCESSOR CONFIG ERROR! i-cache associativity <ICACHE_NUM_SETS> has to be a power of 2." severity error;
|
||||
assert not (ICACHE_NUM_BLOCKS < 1) report "NEORV32 PROCESSOR CONFIG ERROR! i-cache number of blocks <ICACHE_NUM_BLOCKS> has to be >= 1." severity error;
|
||||
assert not (ICACHE_BLOCK_SIZE < 4) report "NEORV32 PROCESSOR CONFIG ERROR! i-cache block size <ICACHE_BLOCK_SIZE> has to be >= 4." severity error;
|
||||
assert not ((ICACHE_NUM_SETS = 0) or (ICACHE_NUM_SETS > 2)) report "NEORV32 PROCESSOR CONFIG ERROR! i-cache associativity <ICACHE_NUM_SETS> has to be 1 (direct-mapped) or 2 (2-way set-associative)." severity error;
|
||||
|
||||
|
||||
-- Control Engine FSM Sync ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- registers that REQUIRE a specific reset state --
|
||||
ctrl_engine_fsm_sync_rst: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
ctrl.state <= S_CACHE_CLEAR;
|
||||
ctrl.re_buf <= '0';
|
||||
ctrl.clear_buf <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
ctrl.state <= ctrl.state_nxt;
|
||||
ctrl.re_buf <= ctrl.re_buf_nxt;
|
||||
ctrl.clear_buf <= ctrl.clear_buf_nxt;
|
||||
end if;
|
||||
end process ctrl_engine_fsm_sync_rst;
|
||||
|
||||
-- registers that do not require a specific reset state --
|
||||
ctrl_engine_fsm_sync: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
ctrl.addr_reg <= ctrl.addr_reg_nxt;
|
||||
end if;
|
||||
end process ctrl_engine_fsm_sync;
|
||||
|
||||
|
||||
-- Control Engine FSM Comb ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
ctrl_engine_fsm_comb: process(ctrl, cache, clear_i, host_addr_i, host_re_i, bus_rdata_i, bus_ack_i, bus_err_i)
|
||||
begin
|
||||
-- control defaults --
|
||||
ctrl.state_nxt <= ctrl.state;
|
||||
ctrl.addr_reg_nxt <= ctrl.addr_reg;
|
||||
ctrl.re_buf_nxt <= ctrl.re_buf or host_re_i;
|
||||
ctrl.clear_buf_nxt <= ctrl.clear_buf or clear_i; -- buffer clear request from CPU
|
||||
|
||||
-- cache defaults --
|
||||
cache.clear <= '0';
|
||||
cache.host_addr <= host_addr_i;
|
||||
cache.ctrl_en <= '0';
|
||||
cache.ctrl_addr <= ctrl.addr_reg;
|
||||
cache.ctrl_we <= '0';
|
||||
cache.ctrl_wdata <= bus_rdata_i;
|
||||
cache.ctrl_tag_we <= '0';
|
||||
cache.ctrl_valid_we <= '0';
|
||||
cache.ctrl_invalid_we <= '0';
|
||||
|
||||
-- host interface defaults --
|
||||
host_ack_o <= '0';
|
||||
host_err_o <= '0';
|
||||
host_rdata_o <= cache.host_rdata;
|
||||
|
||||
-- peripheral bus interface defaults --
|
||||
bus_addr_o <= ctrl.addr_reg;
|
||||
bus_wdata_o <= (others => '0'); -- cache is read-only
|
||||
bus_ben_o <= (others => '0'); -- cache is read-only
|
||||
bus_we_o <= '0'; -- cache is read-only
|
||||
bus_re_o <= '0';
|
||||
|
||||
-- fsm --
|
||||
case ctrl.state is
|
||||
|
||||
when S_IDLE => -- wait for host access request or cache control operation
|
||||
-- ------------------------------------------------------------
|
||||
if (ctrl.clear_buf = '1') then -- cache control operation?
|
||||
ctrl.state_nxt <= S_CACHE_CLEAR;
|
||||
elsif (host_re_i = '1') or (ctrl.re_buf = '1') then -- cache access
|
||||
ctrl.re_buf_nxt <= '0';
|
||||
ctrl.state_nxt <= S_CACHE_CHECK;
|
||||
end if;
|
||||
|
||||
when S_CACHE_CLEAR => -- invalidate all cache entries
|
||||
-- ------------------------------------------------------------
|
||||
ctrl.clear_buf_nxt <= '0';
|
||||
cache.clear <= '1';
|
||||
ctrl.state_nxt <= S_IDLE;
|
||||
|
||||
when S_CACHE_CHECK => -- finalize host access if cache hit
|
||||
-- ------------------------------------------------------------
|
||||
if (cache.hit = '1') then -- cache HIT
|
||||
host_ack_o <= '1';
|
||||
ctrl.state_nxt <= S_IDLE;
|
||||
else -- cache MISS
|
||||
ctrl.state_nxt <= S_CACHE_MISS;
|
||||
end if;
|
||||
|
||||
when S_CACHE_MISS => --
|
||||
-- ------------------------------------------------------------
|
||||
-- compute block base address --
|
||||
ctrl.addr_reg_nxt <= host_addr_i;
|
||||
ctrl.addr_reg_nxt((2+cache_offset_size_c)-1 downto 2) <= (others => '0'); -- block-aligned
|
||||
ctrl.addr_reg_nxt(1 downto 0) <= "00"; -- word-aligned
|
||||
--
|
||||
ctrl.state_nxt <= S_BUS_DOWNLOAD_REQ;
|
||||
|
||||
when S_BUS_DOWNLOAD_REQ => -- download new cache block: request new word
|
||||
-- ------------------------------------------------------------
|
||||
cache.ctrl_en <= '1'; -- we are in cache control mode
|
||||
bus_re_o <= '1'; -- request new read transfer
|
||||
ctrl.state_nxt <= S_BUS_DOWNLOAD_GET;
|
||||
|
||||
when S_BUS_DOWNLOAD_GET => -- download new cache block: wait for bus response
|
||||
-- ------------------------------------------------------------
|
||||
cache.ctrl_en <= '1'; -- we are in cache control mode
|
||||
--
|
||||
if (bus_err_i = '1') then -- bus error
|
||||
ctrl.state_nxt <= S_BUS_ERROR;
|
||||
elsif (bus_ack_i = '1') then -- ACK = write to cache and get next word
|
||||
cache.ctrl_we <= '1'; -- write to cache
|
||||
if (and_reduce_f(ctrl.addr_reg((2+cache_offset_size_c)-1 downto 2)) = '1') then -- block complete?
|
||||
cache.ctrl_tag_we <= '1'; -- current block is valid now
|
||||
cache.ctrl_valid_we <= '1'; -- write tag of current address
|
||||
ctrl.state_nxt <= S_CACHE_RESYNC_0;
|
||||
else -- get next word
|
||||
ctrl.addr_reg_nxt <= std_ulogic_vector(unsigned(ctrl.addr_reg) + 4);
|
||||
ctrl.state_nxt <= S_BUS_DOWNLOAD_REQ;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when S_CACHE_RESYNC_0 => -- re-sync host/cache access: cache read-latency
|
||||
-- ------------------------------------------------------------
|
||||
ctrl.state_nxt <= S_CACHE_RESYNC_1;
|
||||
|
||||
when S_CACHE_RESYNC_1 => -- re-sync host/cache access: finalize CPU request
|
||||
-- ------------------------------------------------------------
|
||||
host_ack_o <= '1';
|
||||
ctrl.state_nxt <= S_IDLE;
|
||||
|
||||
when S_BUS_ERROR => -- bus error during download
|
||||
-- ------------------------------------------------------------
|
||||
host_err_o <= '1';
|
||||
ctrl.state_nxt <= S_IDLE;
|
||||
|
||||
when others => -- undefined
|
||||
-- ------------------------------------------------------------
|
||||
ctrl.state_nxt <= S_IDLE;
|
||||
|
||||
end case;
|
||||
end process ctrl_engine_fsm_comb;
|
||||
|
||||
|
||||
-- Cache Memory ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_icache_memory_inst: neorv32_icache_memory
|
||||
generic map (
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_NUM_SETS => ICACHE_NUM_SETS -- associativity; 0=direct-mapped, 1=2-way set-associative
|
||||
)
|
||||
port map (
|
||||
-- global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
invalidate_i => cache.clear, -- invalidate whole cache
|
||||
-- host cache access (read-only) --
|
||||
host_addr_i => cache.host_addr, -- access address
|
||||
host_re_i => host_re_i, -- read enable
|
||||
host_rdata_o => cache.host_rdata, -- read data
|
||||
-- access status (1 cycle delay to access) --
|
||||
hit_o => cache.hit, -- hit access
|
||||
-- ctrl cache access (write-only) --
|
||||
ctrl_en_i => cache.ctrl_en, -- control interface enable
|
||||
ctrl_addr_i => cache.ctrl_addr, -- access address
|
||||
ctrl_we_i => cache.ctrl_we, -- write enable (full-word)
|
||||
ctrl_wdata_i => cache.ctrl_wdata, -- write data
|
||||
ctrl_tag_we_i => cache.ctrl_tag_we, -- write tag to selected block
|
||||
ctrl_valid_i => cache.ctrl_valid_we, -- make selected block valid
|
||||
ctrl_invalid_i => cache.ctrl_invalid_we -- make selected block invalid
|
||||
);
|
||||
|
||||
end neorv32_icache_rtl;
|
||||
|
||||
|
||||
-- ###########################################################################################################################################
|
||||
-- ###########################################################################################################################################
|
||||
|
||||
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Cache Memory >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Direct mapped (ICACHE_NUM_SETS = 1) or 2-way set-associative (ICACHE_NUM_SETS = 2). #
|
||||
-- # Least recently used replacement policy (if ICACHE_NUM_SETS > 1). #
|
||||
-- # Read-only for host, write-only for control. All output signals have one cycle latency. #
|
||||
-- # #
|
||||
-- # Cache sets are mapped to individual memory components - no multi-dimensional memory arrays #
|
||||
-- # are used as some synthesis tools have problems to map these to actual BRAM primitives. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # BSD 3-Clause License #
|
||||
-- # #
|
||||
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
|
||||
-- # #
|
||||
-- # Redistribution and use in source and binary forms, with or without modification, are #
|
||||
-- # permitted provided that the following conditions are met: #
|
||||
-- # #
|
||||
-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer. #
|
||||
-- # #
|
||||
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer in the documentation and/or other materials #
|
||||
-- # provided with the distribution. #
|
||||
-- # #
|
||||
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
|
||||
-- # endorse or promote products derived from this software without specific prior written #
|
||||
-- # permission. #
|
||||
-- # #
|
||||
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
|
||||
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
|
||||
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
|
||||
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
|
||||
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
|
||||
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
|
||||
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
|
||||
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
|
||||
-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library neorv32;
|
||||
use neorv32.neorv32_package.all;
|
||||
|
||||
entity neorv32_icache_memory is
|
||||
generic (
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 16; -- block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_NUM_SETS : natural := 1 -- associativity; 1=direct-mapped, 2=2-way set-associative
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
invalidate_i : in std_ulogic; -- invalidate whole cache
|
||||
-- host cache access (read-only) --
|
||||
host_addr_i : in std_ulogic_vector(31 downto 0); -- access address
|
||||
host_re_i : in std_ulogic; -- read enable
|
||||
host_rdata_o : out std_ulogic_vector(31 downto 0); -- read data
|
||||
-- access status (1 cycle delay to access) --
|
||||
hit_o : out std_ulogic; -- hit access
|
||||
-- ctrl cache access (write-only) --
|
||||
ctrl_en_i : in std_ulogic; -- control interface enable
|
||||
ctrl_addr_i : in std_ulogic_vector(31 downto 0); -- access address
|
||||
ctrl_we_i : in std_ulogic; -- write enable (full-word)
|
||||
ctrl_wdata_i : in std_ulogic_vector(31 downto 0); -- write data
|
||||
ctrl_tag_we_i : in std_ulogic; -- write tag to selected block
|
||||
ctrl_valid_i : in std_ulogic; -- make selected block valid
|
||||
ctrl_invalid_i : in std_ulogic -- make selected block invalid
|
||||
);
|
||||
end neorv32_icache_memory;
|
||||
|
||||
architecture neorv32_icache_memory_rtl of neorv32_icache_memory is
|
||||
|
||||
-- cache layout --
|
||||
constant cache_offset_size_c : natural := index_size_f(ICACHE_BLOCK_SIZE/4); -- offset addresses full 32-bit words
|
||||
constant cache_index_size_c : natural := index_size_f(ICACHE_NUM_BLOCKS);
|
||||
constant cache_tag_size_c : natural := 32 - (cache_offset_size_c + cache_index_size_c + 2); -- 2 additonal bits for byte offset
|
||||
constant cache_entries_c : natural := ICACHE_NUM_BLOCKS * (ICACHE_BLOCK_SIZE/4); -- number of 32-bit entries (per set)
|
||||
|
||||
-- status flag memory --
|
||||
signal valid_flag_s0 : std_ulogic_vector(ICACHE_NUM_BLOCKS-1 downto 0);
|
||||
signal valid_flag_s1 : std_ulogic_vector(ICACHE_NUM_BLOCKS-1 downto 0);
|
||||
signal valid : std_ulogic_vector(1 downto 0); -- valid flag read data
|
||||
|
||||
-- tag memory --
|
||||
type tag_mem_t is array (0 to ICACHE_NUM_BLOCKS-1) of std_ulogic_vector(cache_tag_size_c-1 downto 0);
|
||||
signal tag_mem_s0 : tag_mem_t;
|
||||
signal tag_mem_s1 : tag_mem_t;
|
||||
type tag_rd_t is array (0 to 1) of std_ulogic_vector(cache_tag_size_c-1 downto 0);
|
||||
signal tag : tag_rd_t; -- tag read data
|
||||
|
||||
-- access status --
|
||||
signal hit : std_ulogic_vector(1 downto 0);
|
||||
|
||||
-- access address decomposition --
|
||||
type acc_addr_t is record
|
||||
tag : std_ulogic_vector(cache_tag_size_c-1 downto 0);
|
||||
index : std_ulogic_vector(cache_index_size_c-1 downto 0);
|
||||
offset : std_ulogic_vector(cache_offset_size_c-1 downto 0);
|
||||
end record;
|
||||
signal host_acc_addr, ctrl_acc_addr : acc_addr_t;
|
||||
|
||||
-- cache data memory --
|
||||
type cache_mem_t is array (0 to cache_entries_c-1) of std_ulogic_vector(31 downto 0);
|
||||
signal cache_data_memory_s0 : cache_mem_t; -- set 0
|
||||
signal cache_data_memory_s1 : cache_mem_t; -- set 1
|
||||
|
||||
-- cache data memory access --
|
||||
type cache_rdata_t is array (0 to 1) of std_ulogic_vector(31 downto 0);
|
||||
signal cache_rdata : cache_rdata_t;
|
||||
signal cache_index : std_ulogic_vector(cache_index_size_c-1 downto 0);
|
||||
signal cache_offset : std_ulogic_vector(cache_offset_size_c-1 downto 0);
|
||||
signal cache_addr : std_ulogic_vector((cache_index_size_c+cache_offset_size_c)-1 downto 0); -- index & offset
|
||||
signal cache_we : std_ulogic; -- write enable (full-word)
|
||||
signal set_select : std_ulogic;
|
||||
|
||||
-- access history --
|
||||
type history_t is record
|
||||
re_ff : std_ulogic;
|
||||
last_used_set : std_ulogic_vector(ICACHE_NUM_BLOCKS-1 downto 0);
|
||||
to_be_replaced : std_ulogic;
|
||||
end record;
|
||||
signal history : history_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Access Address Decomposition -----------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
host_acc_addr.tag <= host_addr_i(31 downto 31-(cache_tag_size_c-1));
|
||||
host_acc_addr.index <= host_addr_i(31-cache_tag_size_c downto 2+cache_offset_size_c);
|
||||
host_acc_addr.offset <= host_addr_i(2+(cache_offset_size_c-1) downto 2); -- discard byte offset
|
||||
|
||||
ctrl_acc_addr.tag <= ctrl_addr_i(31 downto 31-(cache_tag_size_c-1));
|
||||
ctrl_acc_addr.index <= ctrl_addr_i(31-cache_tag_size_c downto 2+cache_offset_size_c);
|
||||
ctrl_acc_addr.offset <= ctrl_addr_i(2+(cache_offset_size_c-1) downto 2); -- discard byte offset
|
||||
|
||||
|
||||
-- Cache Access History -------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
access_history: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
history.re_ff <= host_re_i;
|
||||
if (invalidate_i = '1') then -- invalidate whole cache
|
||||
history.last_used_set <= (others => '1');
|
||||
elsif (history.re_ff = '1') and (or_reduce_f(hit) = '1') and (ctrl_en_i = '0') then -- store last accessed set that caused a hit
|
||||
history.last_used_set(to_integer(unsigned(cache_index))) <= not hit(0);
|
||||
end if;
|
||||
history.to_be_replaced <= history.last_used_set(to_integer(unsigned(cache_index)));
|
||||
end if;
|
||||
end process access_history;
|
||||
|
||||
-- which set is going to be replaced? -> opposite of last used set = least recently used set --
|
||||
set_select <= '0' when (ICACHE_NUM_SETS = 1) else (not history.to_be_replaced);
|
||||
|
||||
|
||||
-- Status flag memory ---------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
status_memory: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- write access --
|
||||
if (invalidate_i = '1') then -- invalidate whole cache
|
||||
valid_flag_s0 <= (others => '0');
|
||||
valid_flag_s1 <= (others => '0');
|
||||
elsif (ctrl_en_i = '1') then
|
||||
if (ctrl_invalid_i = '1') then -- make current block invalid
|
||||
if (set_select = '0') then
|
||||
valid_flag_s0(to_integer(unsigned(cache_index))) <= '0';
|
||||
else
|
||||
valid_flag_s1(to_integer(unsigned(cache_index))) <= '0';
|
||||
end if;
|
||||
elsif (ctrl_valid_i = '1') then -- make current block valid
|
||||
if (set_select = '0') then
|
||||
valid_flag_s0(to_integer(unsigned(cache_index))) <= '1';
|
||||
else
|
||||
valid_flag_s1(to_integer(unsigned(cache_index))) <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
-- read access (sync) --
|
||||
valid(0) <= valid_flag_s0(to_integer(unsigned(cache_index)));
|
||||
valid(1) <= valid_flag_s1(to_integer(unsigned(cache_index)));
|
||||
end if;
|
||||
end process status_memory;
|
||||
|
||||
|
||||
-- Tag memory -----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
tag_memory: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (ctrl_en_i = '1') and (ctrl_tag_we_i = '1') then -- write access
|
||||
if (set_select = '0') then
|
||||
tag_mem_s0(to_integer(unsigned(cache_index))) <= ctrl_acc_addr.tag;
|
||||
else
|
||||
tag_mem_s1(to_integer(unsigned(cache_index))) <= ctrl_acc_addr.tag;
|
||||
end if;
|
||||
end if;
|
||||
tag(0) <= tag_mem_s0(to_integer(unsigned(cache_index)));
|
||||
tag(1) <= tag_mem_s1(to_integer(unsigned(cache_index)));
|
||||
end if;
|
||||
end process tag_memory;
|
||||
|
||||
-- comparator --
|
||||
comparator: process(host_acc_addr, tag, valid)
|
||||
begin
|
||||
hit <= (others => '0');
|
||||
for i in 0 to ICACHE_NUM_SETS-1 loop
|
||||
if (host_acc_addr.tag = tag(i)) and (valid(i) = '1') then
|
||||
hit(i) <= '1';
|
||||
end if;
|
||||
end loop; -- i
|
||||
end process comparator;
|
||||
|
||||
-- global hit --
|
||||
hit_o <= or_reduce_f(hit);
|
||||
|
||||
|
||||
-- Cache Data Memory ----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
cache_mem_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (cache_we = '1') then -- write access from control (full-word)
|
||||
if (set_select = '0') or (ICACHE_NUM_SETS = 1) then
|
||||
cache_data_memory_s0(to_integer(unsigned(cache_addr))) <= ctrl_wdata_i;
|
||||
else
|
||||
cache_data_memory_s1(to_integer(unsigned(cache_addr))) <= ctrl_wdata_i;
|
||||
end if;
|
||||
end if;
|
||||
-- read access from host (full-word) --
|
||||
cache_rdata(0) <= cache_data_memory_s0(to_integer(unsigned(cache_addr)));
|
||||
cache_rdata(1) <= cache_data_memory_s1(to_integer(unsigned(cache_addr)));
|
||||
end if;
|
||||
end process cache_mem_access;
|
||||
|
||||
-- data output --
|
||||
host_rdata_o <= cache_rdata(0) when (hit(0) = '1') or (ICACHE_NUM_SETS = 1) else cache_rdata(1);
|
||||
|
||||
-- cache block ram access address --
|
||||
cache_addr <= cache_index & cache_offset;
|
||||
|
||||
-- cache access select --
|
||||
cache_index <= host_acc_addr.index when (ctrl_en_i = '0') else ctrl_acc_addr.index;
|
||||
cache_offset <= host_acc_addr.offset when (ctrl_en_i = '0') else ctrl_acc_addr.offset;
|
||||
cache_we <= '0' when (ctrl_en_i = '0') else ctrl_we_i;
|
||||
|
||||
|
||||
end neorv32_icache_memory_rtl;
|
58
Libs/RiscV/NEORV32/rtl/core/neorv32_imem.entity.vhd
Normal file
58
Libs/RiscV/NEORV32/rtl/core/neorv32_imem.entity.vhd
Normal file
@ -0,0 +1,58 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor-internal instruction memory (IMEM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This memory optionally includes the in-place executable image of the application. See the #
|
||||
-- # processor's documentary to get more information. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
|
||||
entity neorv32_imem is
|
||||
generic (
|
||||
IMEM_BASE : std_ulogic_vector(31 downto 0); -- memory base address
|
||||
IMEM_SIZE : natural; -- processor-internal instruction memory size in bytes
|
||||
IMEM_AS_IROM : boolean -- implement IMEM as pre-initialized read-only memory?
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rden_i : in std_ulogic; -- read enable
|
||||
wren_i : in std_ulogic; -- write enable
|
||||
ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable
|
||||
addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
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
|
||||
);
|
||||
end neorv32_imem;
|
181
Libs/RiscV/NEORV32/rtl/core/neorv32_mtime.vhd
Normal file
181
Libs/RiscV/NEORV32/rtl/core/neorv32_mtime.vhd
Normal file
@ -0,0 +1,181 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Machine System Timer (MTIME) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Compatible to RISC-V spec's 64-bit MACHINE system timer including "mtime[h]" & "mtimecmp[h]". #
|
||||
-- # Note: The 64-bit counter and compare systems are de-coupled into two 32-bit systems. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_mtime 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
|
||||
-- time output for CPU --
|
||||
time_o : out std_ulogic_vector(63 downto 0); -- current system time
|
||||
-- interrupt --
|
||||
irq_o : out std_ulogic -- interrupt request
|
||||
);
|
||||
end neorv32_mtime;
|
||||
|
||||
architecture neorv32_mtime_rtl of neorv32_mtime is
|
||||
|
||||
-- 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(mtime_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; -- module access enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- time write access buffer --
|
||||
signal mtime_lo_we : std_ulogic;
|
||||
signal mtime_hi_we : std_ulogic;
|
||||
|
||||
-- accessible regs --
|
||||
signal mtimecmp_lo : std_ulogic_vector(31 downto 0);
|
||||
signal mtimecmp_hi : std_ulogic_vector(31 downto 0);
|
||||
signal mtime_lo : std_ulogic_vector(31 downto 0);
|
||||
signal mtime_lo_nxt : std_ulogic_vector(32 downto 0);
|
||||
signal mtime_lo_ovfl : std_ulogic_vector(00 downto 0);
|
||||
signal mtime_hi : std_ulogic_vector(31 downto 0);
|
||||
|
||||
-- comparators --
|
||||
signal cmp_lo_ge : std_ulogic;
|
||||
signal cmp_lo_ge_ff : std_ulogic;
|
||||
signal cmp_hi_eq : std_ulogic;
|
||||
signal cmp_hi_gt : std_ulogic;
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = mtime_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= mtime_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;
|
||||
|
||||
|
||||
-- Write Access ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
wr_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- mtimecmp --
|
||||
if (wren = '1') then
|
||||
if (addr = mtime_cmp_lo_addr_c) then
|
||||
mtimecmp_lo <= data_i;
|
||||
end if;
|
||||
if (addr = mtime_cmp_hi_addr_c) then
|
||||
mtimecmp_hi <= data_i;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- mtime access buffer --
|
||||
-- wdata_buf <= data_i; -- not required, CPU wdata (=data_i) is stable until transfer is acknowledged
|
||||
mtime_lo_we <= wren and bool_to_ulogic_f(boolean(addr = mtime_time_lo_addr_c));
|
||||
mtime_hi_we <= wren and bool_to_ulogic_f(boolean(addr = mtime_time_hi_addr_c));
|
||||
|
||||
-- mtime low --
|
||||
if (mtime_lo_we = '1') then -- write access
|
||||
mtime_lo <= data_i;
|
||||
else -- auto increment
|
||||
mtime_lo <= mtime_lo_nxt(31 downto 0);
|
||||
end if;
|
||||
mtime_lo_ovfl(0) <= mtime_lo_nxt(32); -- overflow (carry)
|
||||
|
||||
-- mtime high --
|
||||
if (mtime_hi_we = '1') then -- write access
|
||||
mtime_hi <= data_i;
|
||||
else -- auto increment (if mtime.low overflows)
|
||||
mtime_hi <= std_ulogic_vector(unsigned(mtime_hi) + unsigned(mtime_lo_ovfl));
|
||||
end if;
|
||||
end if;
|
||||
end process wr_access;
|
||||
|
||||
-- mtime.time_LO increment --
|
||||
mtime_lo_nxt <= std_ulogic_vector(unsigned('0' & mtime_lo) + 1);
|
||||
|
||||
|
||||
-- Read Access ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
rd_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
ack_o <= rden or wren;
|
||||
data_o <= (others => '0'); -- default
|
||||
if (rden = '1') then
|
||||
case addr(3 downto 2) is
|
||||
when "00" => data_o <= mtime_lo; -- mtime LOW
|
||||
when "01" => data_o <= mtime_hi; -- mtime HIGH
|
||||
when "10" => data_o <= mtimecmp_lo; -- mtimecmp LOW
|
||||
when others => data_o <= mtimecmp_hi; -- mtimecmp HIGH
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process rd_access;
|
||||
|
||||
-- system time output for cpu --
|
||||
time_o <= mtime_hi & mtime_lo; -- NOTE: low and high words are not synchronized here!
|
||||
|
||||
|
||||
-- Comparator -----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
cmp_sync: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
cmp_lo_ge_ff <= cmp_lo_ge; -- there is one cycle delay between low (earlier) and high (later) word
|
||||
irq_o <= cmp_hi_gt or (cmp_hi_eq and cmp_lo_ge_ff);
|
||||
end if;
|
||||
end process cmp_sync;
|
||||
|
||||
-- sub-word comparators --
|
||||
cmp_lo_ge <= '1' when (unsigned(mtime_lo) >= unsigned(mtimecmp_lo)) else '0'; -- low-word: greater than or equal
|
||||
cmp_hi_eq <= '1' when (unsigned(mtime_hi) = unsigned(mtimecmp_hi)) else '0'; -- high-word: equal
|
||||
cmp_hi_gt <= '1' when (unsigned(mtime_hi) > unsigned(mtimecmp_hi)) else '0'; -- high-word: greater than
|
||||
|
||||
|
||||
end neorv32_mtime_rtl;
|
420
Libs/RiscV/NEORV32/rtl/core/neorv32_neoled.vhd
Normal file
420
Libs/RiscV/NEORV32/rtl/core/neorv32_neoled.vhd
Normal file
@ -0,0 +1,420 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Smart LED (WS2811/WS2812) Interface (NEOLED) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Hardware interface for direct control of "smart LEDs" using an asynchronous serial data #
|
||||
-- # line. Compatible with the WS2811 and WS2812 LEDs. #
|
||||
-- # #
|
||||
-- # NeoPixel-compatible, RGB (24-bit) and RGBW (32-bit) modes supported (in "parallel") #
|
||||
-- # (TM) "NeoPixel" is a trademark of Adafruit Industries. #
|
||||
-- # #
|
||||
-- # The interface uses a programmable carrier frequency (800 KHz for the WS2812 LEDs) #
|
||||
-- # configurable via the control register's clock prescaler bits (ctrl_clksel*_c) and the period #
|
||||
-- # length configuration bits (ctrl_t_tot_*_c). "high-times" for sending a ZERO or a ONE bit are #
|
||||
-- # configured using the ctrl_t_0h_*_c and ctrl_t_1h_*_c bits, respectively. 32-bit transfers #
|
||||
-- # (for RGBW modules) and 24-bit transfers (for RGB modules) are supported via ctrl_mode__c. #
|
||||
-- # #
|
||||
-- # The device features a TX buffer (FIFO) with <FIFO_DEPTH> entries with configurable interrupt. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_neoled is
|
||||
generic (
|
||||
FIFO_DEPTH : natural -- TX FIFO depth (1..32k, power of two)
|
||||
);
|
||||
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);
|
||||
-- interrupt --
|
||||
irq_o : out std_ulogic; -- interrupt request
|
||||
-- NEOLED output --
|
||||
neoled_o : out std_ulogic -- serial async data line
|
||||
);
|
||||
end neorv32_neoled;
|
||||
|
||||
architecture neorv32_neoled_rtl of neorv32_neoled is
|
||||
|
||||
-- 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(neoled_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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- Control register bits --
|
||||
constant ctrl_en_c : natural := 0; -- r/w: module enable
|
||||
constant ctrl_mode_c : natural := 1; -- r/w: 0 = 24-bit RGB mode, 1 = 32-bit RGBW mode
|
||||
constant ctrl_strobe_c : natural := 2; -- r/w: 0 = send normal data, 1 = send LED strobe command (RESET) on data write
|
||||
--
|
||||
constant ctrl_clksel0_c : natural := 3; -- r/w: prescaler select bit 0
|
||||
constant ctrl_clksel1_c : natural := 4; -- r/w: prescaler select bit 1
|
||||
constant ctrl_clksel2_c : natural := 5; -- r/w: prescaler select bit 2
|
||||
--
|
||||
constant ctrl_bufs_0_c : natural := 6; -- r/-: log2(FIFO_DEPTH) bit 0
|
||||
constant ctrl_bufs_1_c : natural := 7; -- r/-: log2(FIFO_DEPTH) bit 1
|
||||
constant ctrl_bufs_2_c : natural := 8; -- r/-: log2(FIFO_DEPTH) bit 2
|
||||
constant ctrl_bufs_3_c : natural := 9; -- r/-: log2(FIFO_DEPTH) bit 3
|
||||
--
|
||||
constant ctrl_t_tot_0_c : natural := 10; -- r/w: pulse-clock ticks per total period bit 0
|
||||
constant ctrl_t_tot_1_c : natural := 11; -- r/w: pulse-clock ticks per total period bit 1
|
||||
constant ctrl_t_tot_2_c : natural := 12; -- r/w: pulse-clock ticks per total period bit 2
|
||||
constant ctrl_t_tot_3_c : natural := 13; -- r/w: pulse-clock ticks per total period bit 3
|
||||
constant ctrl_t_tot_4_c : natural := 14; -- r/w: pulse-clock ticks per total period bit 4
|
||||
--
|
||||
constant ctrl_t_0h_0_c : natural := 15; -- r/w: pulse-clock ticks per ZERO high-time bit 0
|
||||
constant ctrl_t_0h_1_c : natural := 16; -- r/w: pulse-clock ticks per ZERO high-time bit 1
|
||||
constant ctrl_t_0h_2_c : natural := 17; -- r/w: pulse-clock ticks per ZERO high-time bit 2
|
||||
constant ctrl_t_0h_3_c : natural := 18; -- r/w: pulse-clock ticks per ZERO high-time bit 3
|
||||
constant ctrl_t_0h_4_c : natural := 19; -- r/w: pulse-clock ticks per ZERO high-time bit 4
|
||||
--
|
||||
constant ctrl_t_1h_0_c : natural := 20; -- r/w: pulse-clock ticks per ONE high-time bit 0
|
||||
constant ctrl_t_1h_1_c : natural := 21; -- r/w: pulse-clock ticks per ONE high-time bit 1
|
||||
constant ctrl_t_1h_2_c : natural := 22; -- r/w: pulse-clock ticks per ONE high-time bit 2
|
||||
constant ctrl_t_1h_3_c : natural := 23; -- r/w: pulse-clock ticks per ONE high-time bit 3
|
||||
constant ctrl_t_1h_4_c : natural := 24; -- r/w: pulse-clock ticks per ONE high-time bit 4
|
||||
--
|
||||
constant ctrl_irq_conf_c : natural := 27; -- r/w: interrupt config: 1=IRQ when buffer is empty, 0=IRQ when buffer is half-empty
|
||||
constant ctrl_tx_empty_c : natural := 28; -- r/-: TX FIFO is empty
|
||||
constant ctrl_tx_half_c : natural := 29; -- r/-: TX FIFO is at least half-full
|
||||
constant ctrl_tx_full_c : natural := 30; -- r/-: TX FIFO is full
|
||||
constant ctrl_tx_busy_c : natural := 31; -- r/-: serial TX engine busy when set
|
||||
|
||||
-- control register --
|
||||
type ctrl_t is record
|
||||
enable : std_ulogic;
|
||||
mode : std_ulogic;
|
||||
strobe : std_ulogic;
|
||||
clk_prsc : std_ulogic_vector(2 downto 0);
|
||||
irq_conf : std_ulogic;
|
||||
-- pulse config --
|
||||
t_total : std_ulogic_vector(4 downto 0);
|
||||
t0_high : std_ulogic_vector(4 downto 0);
|
||||
t1_high : std_ulogic_vector(4 downto 0);
|
||||
end record;
|
||||
signal ctrl : ctrl_t;
|
||||
|
||||
-- transmission buffer --
|
||||
type tx_buffer_t is record
|
||||
we : std_ulogic; -- write enable
|
||||
re : std_ulogic; -- read enable
|
||||
clear : std_ulogic; -- sync reset, high-active
|
||||
wdata : std_ulogic_vector(31+2 downto 0); -- write data (excluding mode)
|
||||
rdata : std_ulogic_vector(31+2 downto 0); -- read data (including mode)
|
||||
avail : std_ulogic; -- data available?
|
||||
free : std_ulogic; -- free entry available?
|
||||
half : std_ulogic; -- half full
|
||||
end record;
|
||||
signal tx_buffer : tx_buffer_t;
|
||||
|
||||
-- interrupt generator --
|
||||
type irq_t is record
|
||||
set : std_ulogic;
|
||||
buf : std_ulogic_vector(1 downto 0);
|
||||
end record;
|
||||
signal irq : irq_t;
|
||||
|
||||
-- serial transmission engine --
|
||||
type serial_state_t is (S_IDLE, S_INIT, S_GETBIT, S_PULSE, S_STROBE);
|
||||
type serial_t is record
|
||||
-- state control --
|
||||
state : serial_state_t;
|
||||
mode : std_ulogic;
|
||||
done : std_ulogic;
|
||||
busy : std_ulogic;
|
||||
bit_cnt : std_ulogic_vector(5 downto 0);
|
||||
-- shift register --
|
||||
sreg : std_ulogic_vector(31 downto 0);
|
||||
next_bit : std_ulogic; -- next bit to send
|
||||
-- pulse generator --
|
||||
pulse_clk : std_ulogic; -- pulse cycle "clock"
|
||||
pulse_cnt : std_ulogic_vector(4 downto 0);
|
||||
t_high : std_ulogic_vector(4 downto 0);
|
||||
strobe_cnt : std_ulogic_vector(6 downto 0);
|
||||
tx_out : std_ulogic;
|
||||
end record;
|
||||
signal serial : serial_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not ((is_power_of_two_f(FIFO_DEPTH) = false) or (FIFO_DEPTH < 1) or (FIFO_DEPTH > 32768)) report
|
||||
"NEORV32 PROCESSOR CONFIG ERROR! Invalid <NEOLED.FIFO_DEPTH> buffer size configuration (1..32k)!" severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = neoled_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= neoled_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
|
||||
-- access acknowledge --
|
||||
ack_o <= wren or rden;
|
||||
|
||||
-- write access: control register --
|
||||
if (wren = '1') and (addr = neoled_ctrl_addr_c) then
|
||||
ctrl.enable <= data_i(ctrl_en_c);
|
||||
ctrl.mode <= data_i(ctrl_mode_c);
|
||||
ctrl.strobe <= data_i(ctrl_strobe_c);
|
||||
ctrl.clk_prsc <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c);
|
||||
ctrl.irq_conf <= data_i(ctrl_irq_conf_c);
|
||||
ctrl.t_total <= data_i(ctrl_t_tot_4_c downto ctrl_t_tot_0_c);
|
||||
ctrl.t0_high <= data_i(ctrl_t_0h_4_c downto ctrl_t_0h_0_c);
|
||||
ctrl.t1_high <= data_i(ctrl_t_1h_4_c downto ctrl_t_1h_0_c);
|
||||
end if;
|
||||
|
||||
-- read access: control register --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then -- and (addr = neoled_ctrl_addr_c) then
|
||||
data_o(ctrl_en_c) <= ctrl.enable;
|
||||
data_o(ctrl_mode_c) <= ctrl.mode;
|
||||
data_o(ctrl_strobe_c) <= ctrl.strobe;
|
||||
data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc;
|
||||
data_o(ctrl_irq_conf_c) <= ctrl.irq_conf or bool_to_ulogic_f(boolean(FIFO_DEPTH = 1)); -- tie to one if FIFO_DEPTH is 1
|
||||
data_o(ctrl_bufs_3_c downto ctrl_bufs_0_c) <= std_ulogic_vector(to_unsigned(index_size_f(FIFO_DEPTH), 4));
|
||||
data_o(ctrl_t_tot_4_c downto ctrl_t_tot_0_c) <= ctrl.t_total;
|
||||
data_o(ctrl_t_0h_4_c downto ctrl_t_0h_0_c) <= ctrl.t0_high;
|
||||
data_o(ctrl_t_1h_4_c downto ctrl_t_1h_0_c) <= ctrl.t1_high;
|
||||
--
|
||||
data_o(ctrl_tx_empty_c) <= not tx_buffer.avail;
|
||||
data_o(ctrl_tx_half_c) <= tx_buffer.half;
|
||||
data_o(ctrl_tx_full_c) <= not tx_buffer.free;
|
||||
data_o(ctrl_tx_busy_c) <= serial.busy;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
-- enable external clock generator --
|
||||
clkgen_en_o <= ctrl.enable;
|
||||
|
||||
-- FIFO write access --
|
||||
tx_buffer.we <= '1' when (wren = '1') and (addr = neoled_data_addr_c) else '0';
|
||||
tx_buffer.wdata <= ctrl.strobe & ctrl.mode & data_i;
|
||||
tx_buffer.clear <= not ctrl.enable;
|
||||
|
||||
|
||||
-- IRQ Generator --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
irq_select: process(ctrl, tx_buffer, serial.done)
|
||||
begin
|
||||
if (FIFO_DEPTH = 1) or (ctrl.irq_conf = '1') then
|
||||
irq.set <= tx_buffer.free and serial.done; -- fire IRQ if FIFO is empty
|
||||
else
|
||||
irq.set <= not tx_buffer.half; -- fire IRQ if FIFO is less than half-full
|
||||
end if;
|
||||
end process irq_select;
|
||||
|
||||
-- Interrupt Edge Detector --
|
||||
irq_detect: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (ctrl.enable = '0') then
|
||||
irq.buf <= "00";
|
||||
else
|
||||
irq.buf <= irq.buf(0) & irq.set;
|
||||
end if;
|
||||
end if;
|
||||
end process irq_detect;
|
||||
|
||||
-- IRQ request to CPU --
|
||||
irq_o <= '1' when (irq.buf = "01") else '0';
|
||||
|
||||
|
||||
-- TX Buffer (FIFO) -----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
tx_data_fifo: neorv32_fifo
|
||||
generic map (
|
||||
FIFO_DEPTH => FIFO_DEPTH, -- number of fifo entries; has to be a power of two; min 1
|
||||
FIFO_WIDTH => 32+2, -- size of data elements in fifo
|
||||
FIFO_RSYNC => true, -- sync read
|
||||
FIFO_SAFE => true -- safe access
|
||||
)
|
||||
port map (
|
||||
-- control --
|
||||
clk_i => clk_i, -- clock, rising edge
|
||||
rstn_i => '1', -- async reset, low-active
|
||||
clear_i => tx_buffer.clear, -- sync reset, high-active
|
||||
level_o => open, -- fill level
|
||||
half_o => tx_buffer.half, -- FIFO is at least half full
|
||||
-- write port --
|
||||
wdata_i => tx_buffer.wdata, -- write data
|
||||
we_i => tx_buffer.we, -- write enable
|
||||
free_o => tx_buffer.free, -- at least one entry is free when set
|
||||
-- read port --
|
||||
re_i => tx_buffer.re, -- read enable
|
||||
rdata_o => tx_buffer.rdata, -- read data
|
||||
avail_o => tx_buffer.avail -- data available when set
|
||||
);
|
||||
|
||||
-- try to get new TX data --
|
||||
tx_buffer.re <= '1' when (serial.state = S_IDLE) else '0';
|
||||
|
||||
|
||||
-- Serial TX Engine -----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
serial_engine: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- clock generator --
|
||||
serial.pulse_clk <= clkgen_i(to_integer(unsigned(ctrl.clk_prsc)));
|
||||
|
||||
-- defaults --
|
||||
serial.done <= '0';
|
||||
|
||||
-- FSM --
|
||||
if (ctrl.enable = '0') then -- disabled
|
||||
serial.state <= S_IDLE;
|
||||
else
|
||||
case serial.state is
|
||||
|
||||
when S_IDLE => -- waiting for new TX data
|
||||
-- ------------------------------------------------------------
|
||||
serial.tx_out <= '0';
|
||||
serial.pulse_cnt <= (others => '0');
|
||||
serial.strobe_cnt <= (others => '0');
|
||||
if (tx_buffer.avail = '1') then
|
||||
serial.state <= S_INIT;
|
||||
end if;
|
||||
|
||||
when S_INIT => -- initialize TX shift engine
|
||||
-- ------------------------------------------------------------
|
||||
if (tx_buffer.rdata(33) = '0') then -- send data
|
||||
if (tx_buffer.rdata(32) = '0') then -- mode = "RGB"
|
||||
serial.mode <= '0';
|
||||
serial.bit_cnt <= "011000"; -- total number of bits to send: 3x8=24
|
||||
else -- mode = "RGBW"
|
||||
serial.mode <= '1';
|
||||
serial.bit_cnt <= "100000"; -- total number of bits to send: 4x8=32
|
||||
end if;
|
||||
serial.sreg <= tx_buffer.rdata(31 downto 00);
|
||||
serial.state <= S_GETBIT;
|
||||
else -- send RESET command
|
||||
serial.state <= S_STROBE;
|
||||
end if;
|
||||
|
||||
when S_GETBIT => -- get next TX bit
|
||||
-- ------------------------------------------------------------
|
||||
serial.sreg <= serial.sreg(serial.sreg'left-1 downto 0) & '0'; -- shift left by one position (MSB-first)
|
||||
serial.bit_cnt <= std_ulogic_vector(unsigned(serial.bit_cnt) - 1);
|
||||
serial.pulse_cnt <= (others => '0');
|
||||
if (serial.next_bit = '0') then -- send zero-bit
|
||||
serial.t_high <= ctrl.t0_high;
|
||||
else -- send one-bit
|
||||
serial.t_high <= ctrl.t1_high;
|
||||
end if;
|
||||
if (serial.bit_cnt = "000000") then -- all done?
|
||||
serial.tx_out <= '0';
|
||||
serial.done <= '1'; -- done sending data
|
||||
serial.state <= S_IDLE;
|
||||
else -- send current data MSB
|
||||
serial.tx_out <= '1';
|
||||
serial.state <= S_PULSE; -- transmit single pulse
|
||||
end if;
|
||||
|
||||
when S_PULSE => -- send pulse with specific duty cycle
|
||||
-- ------------------------------------------------------------
|
||||
-- total pulse length = ctrl.t_total
|
||||
-- pulse high time = serial.t_high
|
||||
if (serial.pulse_clk = '1') then
|
||||
serial.pulse_cnt <= std_ulogic_vector(unsigned(serial.pulse_cnt) + 1);
|
||||
-- T_high reached? --
|
||||
if (serial.pulse_cnt = serial.t_high) then
|
||||
serial.tx_out <= '0';
|
||||
end if;
|
||||
-- T_total reached? --
|
||||
if (serial.pulse_cnt = ctrl.t_total) then
|
||||
serial.state <= S_GETBIT; -- get next bit to send
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when S_STROBE => -- strobe LED data ("RESET" command)
|
||||
-- ------------------------------------------------------------
|
||||
-- wait for 127 * ctrl.t_total to _ensure_ RESET
|
||||
if (serial.pulse_clk = '1') then
|
||||
-- T_total reached? --
|
||||
if (serial.pulse_cnt = ctrl.t_total) then
|
||||
serial.pulse_cnt <= (others => '0');
|
||||
serial.strobe_cnt <= std_ulogic_vector(unsigned(serial.strobe_cnt) + 1);
|
||||
else
|
||||
serial.pulse_cnt <= std_ulogic_vector(unsigned(serial.pulse_cnt) + 1);
|
||||
end if;
|
||||
end if;
|
||||
-- number of LOW periods reached for RESET? --
|
||||
if (and_reduce_f(serial.strobe_cnt) = '1') then
|
||||
serial.done <= '1'; -- done sending RESET
|
||||
serial.state <= S_IDLE;
|
||||
end if;
|
||||
|
||||
when others => -- undefined
|
||||
-- ------------------------------------------------------------
|
||||
serial.state <= S_IDLE;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
-- serial data tx_out --
|
||||
neoled_o <= serial.tx_out and ctrl.enable;
|
||||
end if;
|
||||
end process serial_engine;
|
||||
|
||||
-- SREG's TX data: bit 23 for RGB mode (24-bit), bit 31 for RGBW mode (32-bit) --
|
||||
serial.next_bit <= serial.sreg(23) when (serial.mode = '0') else serial.sreg(31);
|
||||
|
||||
-- TX engine status --
|
||||
serial.busy <= '0' when (serial.state = S_IDLE) else '1';
|
||||
|
||||
|
||||
end neorv32_neoled_rtl;
|
2426
Libs/RiscV/NEORV32/rtl/core/neorv32_package.vhd
Normal file
2426
Libs/RiscV/NEORV32/rtl/core/neorv32_package.vhd
Normal file
File diff suppressed because it is too large
Load Diff
200
Libs/RiscV/NEORV32/rtl/core/neorv32_pwm.vhd
Normal file
200
Libs/RiscV/NEORV32/rtl/core/neorv32_pwm.vhd
Normal file
@ -0,0 +1,200 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Pulse Width Modulation Controller (PWM) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Simple PWM controller with 8 bit resolution for the duty cycle and programmable base #
|
||||
-- # frequency. The controller supports up to 60 PWM channels. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_pwm is
|
||||
generic (
|
||||
NUM_CHANNELS : natural -- number of PWM channels (0..60)
|
||||
);
|
||||
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);
|
||||
-- pwm output channels --
|
||||
pwm_o : out std_ulogic_vector(NUM_CHANNELS-1 downto 0)
|
||||
);
|
||||
end neorv32_pwm;
|
||||
|
||||
architecture neorv32_pwm_rtl of neorv32_pwm is
|
||||
|
||||
-- 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(pwm_size_c); -- low address boundary bit
|
||||
|
||||
-- Control register bits --
|
||||
constant ctrl_enable_c : natural := 0; -- r/w: PWM enable
|
||||
constant ctrl_prsc0_bit_c : natural := 1; -- r/w: prescaler select bit 0
|
||||
constant ctrl_prsc1_bit_c : natural := 2; -- r/w: prescaler select bit 1
|
||||
constant ctrl_prsc2_bit_c : natural := 3; -- r/w: prescaler select bit 2
|
||||
|
||||
-- access control --
|
||||
signal acc_en : std_ulogic; -- module access enable
|
||||
signal addr : std_ulogic_vector(31 downto 0); -- access address
|
||||
signal wren : std_ulogic; -- write enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- accessible regs --
|
||||
type pwm_ch_t is array (0 to NUM_CHANNELS-1) of std_ulogic_vector(7 downto 0);
|
||||
signal pwm_ch : pwm_ch_t; -- duty cycle (r/w)
|
||||
signal enable : std_ulogic; -- enable unit (r/w)
|
||||
signal prsc : std_ulogic_vector(2 downto 0); -- clock prescaler (r/w)
|
||||
|
||||
type pwm_ch_rd_t is array (0 to 60-1) of std_ulogic_vector(7 downto 0);
|
||||
signal pwm_ch_rd : pwm_ch_rd_t; -- duty cycle read-back
|
||||
|
||||
-- prescaler clock generator --
|
||||
signal prsc_tick : std_ulogic;
|
||||
|
||||
-- pwm core counter --
|
||||
signal pwm_cnt : std_ulogic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (NUM_CHANNELS > 60) report "NEORV32 PROCESSOR CONFIG ERROR! <IO.PWM> invalid number of channels! Has to be 0..60.!" severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = pwm_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= pwm_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
||||
rden <= acc_en and rden_i;
|
||||
wren <= acc_en and wren_i;
|
||||
|
||||
|
||||
-- Write access ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
wr_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
ack_o <= rden or wren;
|
||||
|
||||
-- write access --
|
||||
if (wren = '1') then
|
||||
-- control register --
|
||||
if (addr = pwm_ctrl_addr_c) then
|
||||
enable <= data_i(ctrl_enable_c);
|
||||
prsc <= data_i(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c);
|
||||
end if;
|
||||
-- duty cycle registers --
|
||||
for i in 0 to NUM_CHANNELS-1 loop -- channel loop
|
||||
if (addr(5 downto 2) = std_ulogic_vector(to_unsigned((i/4)+1, 4))) then -- 4 channels per register; add ctrl reg offset
|
||||
pwm_ch(i) <= data_i((i mod 4)*8+7 downto (i mod 4)*8+0);
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
case addr(5 downto 2) is
|
||||
when x"0" => data_o(ctrl_enable_c) <= enable; data_o(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c) <= prsc;
|
||||
when x"1" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(3) & pwm_ch_rd(2) & pwm_ch_rd(1) & pwm_ch_rd(0); else NULL; end if;
|
||||
when x"2" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(7) & pwm_ch_rd(6) & pwm_ch_rd(5) & pwm_ch_rd(4); else NULL; end if;
|
||||
when x"3" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(11) & pwm_ch_rd(10) & pwm_ch_rd(9) & pwm_ch_rd(8); else NULL; end if;
|
||||
when x"4" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(15) & pwm_ch_rd(14) & pwm_ch_rd(13) & pwm_ch_rd(12); else NULL; end if;
|
||||
when x"5" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(19) & pwm_ch_rd(18) & pwm_ch_rd(17) & pwm_ch_rd(16); else NULL; end if;
|
||||
when x"6" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(23) & pwm_ch_rd(22) & pwm_ch_rd(21) & pwm_ch_rd(20); else NULL; end if;
|
||||
when x"7" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(27) & pwm_ch_rd(26) & pwm_ch_rd(25) & pwm_ch_rd(24); else NULL; end if;
|
||||
when x"8" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(31) & pwm_ch_rd(30) & pwm_ch_rd(29) & pwm_ch_rd(28); else NULL; end if;
|
||||
when x"9" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(35) & pwm_ch_rd(34) & pwm_ch_rd(33) & pwm_ch_rd(32); else NULL; end if;
|
||||
when x"a" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(39) & pwm_ch_rd(38) & pwm_ch_rd(37) & pwm_ch_rd(36); else NULL; end if;
|
||||
when x"b" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(43) & pwm_ch_rd(42) & pwm_ch_rd(41) & pwm_ch_rd(40); else NULL; end if;
|
||||
when x"c" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(47) & pwm_ch_rd(46) & pwm_ch_rd(45) & pwm_ch_rd(44); else NULL; end if;
|
||||
when x"d" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(51) & pwm_ch_rd(50) & pwm_ch_rd(49) & pwm_ch_rd(48); else NULL; end if;
|
||||
when x"e" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(55) & pwm_ch_rd(54) & pwm_ch_rd(53) & pwm_ch_rd(52); else NULL; end if;
|
||||
when x"f" => if (NUM_CHANNELS > 0) then data_o <= pwm_ch_rd(59) & pwm_ch_rd(58) & pwm_ch_rd(57) & pwm_ch_rd(56); else NULL; end if;
|
||||
when others => NULL;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process wr_access;
|
||||
|
||||
-- duty cycle read-back --
|
||||
pwm_dc_rd_gen: process(pwm_ch)
|
||||
begin
|
||||
pwm_ch_rd <= (others => (others => '0'));
|
||||
for i in 0 to NUM_CHANNELS-1 loop
|
||||
pwm_ch_rd(i) <= pwm_ch(i);
|
||||
end loop;
|
||||
end process pwm_dc_rd_gen;
|
||||
|
||||
-- PWM clock select --
|
||||
clkgen_en_o <= enable; -- enable clock generator
|
||||
prsc_tick <= clkgen_i(to_integer(unsigned(prsc)));
|
||||
|
||||
|
||||
-- PWM Core -------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
pwm_core: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- pwm base counter --
|
||||
if (enable = '0') then
|
||||
pwm_cnt <= (others => '0');
|
||||
elsif (prsc_tick = '1') then
|
||||
pwm_cnt <= std_ulogic_vector(unsigned(pwm_cnt) + 1);
|
||||
end if;
|
||||
|
||||
-- channels --
|
||||
for i in 0 to NUM_CHANNELS-1 loop
|
||||
if (unsigned(pwm_cnt) >= unsigned(pwm_ch(i))) or (enable = '0') then
|
||||
pwm_o(i) <= '0';
|
||||
else
|
||||
pwm_o(i) <= '1';
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
end process pwm_core;
|
||||
|
||||
|
||||
end neorv32_pwm_rtl;
|
439
Libs/RiscV/NEORV32/rtl/core/neorv32_slink.vhd
Normal file
439
Libs/RiscV/NEORV32/rtl/core/neorv32_slink.vhd
Normal file
@ -0,0 +1,439 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Stream Link Interface (SLINK) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Up to 8 input (RX) and up to 8 output (TX) stream links are supported. Each link provides an #
|
||||
-- # internal FIFO for buffering. Each stream direction provides a global interrupt to indicate #
|
||||
-- # that a RX link has received new data or that a TX link has finished sending data #
|
||||
-- # (if FIFO_DEPTH = 1) OR if RX/TX link FIFO has become half full (if FIFO_DEPTH > 1). #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_slink is
|
||||
generic (
|
||||
SLINK_NUM_TX : natural; -- number of TX links (0..8)
|
||||
SLINK_NUM_RX : natural; -- number of TX links (0..8)
|
||||
SLINK_TX_FIFO : natural; -- TX fifo depth, has to be a power of two
|
||||
SLINK_RX_FIFO : natural -- RX fifo depth, has to be a power of two
|
||||
);
|
||||
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
|
||||
-- interrupt --
|
||||
irq_tx_o : out std_ulogic; -- transmission done
|
||||
irq_rx_o : out std_ulogic; -- data received
|
||||
-- TX stream interfaces --
|
||||
slink_tx_dat_o : out sdata_8x32_t; -- output data
|
||||
slink_tx_val_o : out std_ulogic_vector(7 downto 0); -- valid output
|
||||
slink_tx_rdy_i : in std_ulogic_vector(7 downto 0); -- ready to send
|
||||
-- RX stream interfaces --
|
||||
slink_rx_dat_i : in sdata_8x32_t; -- input data
|
||||
slink_rx_val_i : in std_ulogic_vector(7 downto 0); -- valid input
|
||||
slink_rx_rdy_o : out std_ulogic_vector(7 downto 0) -- ready to receive
|
||||
);
|
||||
end neorv32_slink;
|
||||
|
||||
architecture neorv32_slink_rtl of neorv32_slink is
|
||||
|
||||
-- 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(slink_size_c); -- low address boundary bit
|
||||
|
||||
-- control register bits --
|
||||
constant ctrl_rx_num_lsb_c : natural := 0; -- r/-: number of implemented RX links
|
||||
constant ctrl_rx_num_msb_c : natural := 3;
|
||||
--
|
||||
constant ctrl_tx_num_lsb_c : natural := 4; -- r/-: number of implemented TX links
|
||||
constant ctrl_tx_num_msb_c : natural := 7;
|
||||
--
|
||||
constant ctrl_rx_size_lsb_c : natural := 8; -- r/-: log2(RX FIFO size)
|
||||
constant ctrl_rx_size_msb_c : natural := 11;
|
||||
--
|
||||
constant ctrl_tx_size_lsb_c : natural := 12; -- r/-: log2(TX FIFO size)
|
||||
constant ctrl_tx_size_msb_c : natural := 15;
|
||||
--
|
||||
constant ctrl_en_c : natural := 31; -- r/w: global enable
|
||||
|
||||
-- interrupt configuration register bits --
|
||||
constant irq_rx_en_lsb_c : natural := 0; -- r/w: enable RX interrupt for link 0..7
|
||||
constant irq_rx_en_msb_c : natural := 7;
|
||||
--
|
||||
constant irq_rx_mode_lsb_c : natural := 8; -- r/w: RX IRQ mode: 0=FIFO at least half-full; 1=FIFO not empty
|
||||
constant irq_rx_mode_msb_c : natural := 15;
|
||||
--
|
||||
constant irq_tx_en_lsb_c : natural := 16; -- r/w: enable TX interrupt for link 0..7
|
||||
constant irq_tx_en_msb_c : natural := 23;
|
||||
--
|
||||
constant irq_tx_mode_lsb_c : natural := 24; -- r/w: TX IRQ mode: 0=FIFO less than half-full; 1=FIFO not full
|
||||
constant irq_tx_mode_msb_c : natural := 31;
|
||||
|
||||
-- status register bits --
|
||||
constant status_rx_avail_lsb_c : natural := 0; -- r/-: set if RX link 0..7 FIFO is NOT empty
|
||||
constant status_rx_avail_msb_c : natural := 7;
|
||||
--
|
||||
constant status_tx_free_lsb_c : natural := 8; -- r/-: set if TX link 0..7 FIFO is NOT full
|
||||
constant status_tx_free_msb_c : natural := 15;
|
||||
--
|
||||
constant status_rx_half_lsb_c : natural := 16; -- r/-: set if RX link 0..7 FIFO fill-level is >= half-full
|
||||
constant status_rx_half_msb_c : natural := 23;
|
||||
--
|
||||
constant status_tx_half_lsb_c : natural := 24; -- r/-: set if TX link 0..7 FIFO fill-level is > half-full
|
||||
constant status_tx_half_msb_c : natural := 31;
|
||||
|
||||
-- bus access control --
|
||||
signal ack_read : std_ulogic;
|
||||
signal ack_write : std_ulogic;
|
||||
signal acc_en : std_ulogic;
|
||||
signal addr : std_ulogic_vector(31 downto 0);
|
||||
signal wren : std_ulogic; -- word write enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- control register --
|
||||
signal enable : std_ulogic; -- global enable
|
||||
|
||||
-- IRQ configuration register --
|
||||
signal irq_rx_en : std_ulogic_vector(7 downto 0);
|
||||
signal irq_rx_mode : std_ulogic_vector(7 downto 0);
|
||||
signal irq_tx_en : std_ulogic_vector(7 downto 0);
|
||||
signal irq_tx_mode : std_ulogic_vector(7 downto 0);
|
||||
|
||||
-- stream link fifo interface --
|
||||
type fifo_data_t is array (0 to 7) of std_ulogic_vector(31 downto 0);
|
||||
signal rx_fifo_rdata : fifo_data_t;
|
||||
signal fifo_clear : std_ulogic;
|
||||
signal link_sel : std_ulogic_vector(7 downto 0);
|
||||
signal tx_fifo_we : std_ulogic_vector(7 downto 0);
|
||||
signal rx_fifo_re : std_ulogic_vector(7 downto 0);
|
||||
signal rx_fifo_avail : std_ulogic_vector(7 downto 0);
|
||||
signal tx_fifo_free : std_ulogic_vector(7 downto 0);
|
||||
signal rx_fifo_half : std_ulogic_vector(7 downto 0);
|
||||
signal tx_fifo_half : std_ulogic_vector(7 downto 0);
|
||||
|
||||
-- interrupt generator --
|
||||
type detect_t is array (0 to 7) of std_ulogic_vector(1 downto 0);
|
||||
type irq_t is record
|
||||
detect : detect_t; -- rising-edge detector
|
||||
trigger : std_ulogic_vector(7 downto 0);
|
||||
set : std_ulogic_vector(7 downto 0);
|
||||
end record;
|
||||
signal rx_irq, tx_irq : irq_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (is_power_of_two_f(SLINK_TX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_TX_FIFO> has to be a power of two." severity error;
|
||||
assert not (SLINK_TX_FIFO > 2**15) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_TX_FIFO> has to be 1..32768." severity error;
|
||||
--
|
||||
assert not (is_power_of_two_f(SLINK_RX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_RX_FIFO> has to be a power of two." severity error;
|
||||
assert not (SLINK_RX_FIFO > 2**15) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_RX_FIFO> has to be 1..32768." severity error;
|
||||
--
|
||||
assert not (SLINK_NUM_RX > 8) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_NUM_RX> has to be 0..8." severity error;
|
||||
assert not (SLINK_NUM_TX > 8) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_NUM_TX> has to be 0..8." severity error;
|
||||
--
|
||||
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Implementing " & integer'image(SLINK_NUM_RX) & " RX and " &
|
||||
integer'image(SLINK_NUM_TX) & " TX stream links." severity note;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = slink_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= slink_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
|
||||
-- write access --
|
||||
ack_write <= '0';
|
||||
if (wren = '1') then
|
||||
if (addr(5) = '0') then -- control/status/irq
|
||||
if (addr(4 downto 3) = "00") then -- control register
|
||||
enable <= data_i(ctrl_en_c);
|
||||
end if;
|
||||
if (addr(4 downto 3) = "01") then -- IRQ configuration register
|
||||
for i in 0 to SLINK_NUM_RX-1 loop
|
||||
irq_rx_en(i) <= data_i(i + irq_rx_en_lsb_c);
|
||||
irq_rx_mode(i) <= data_i(i + irq_rx_mode_lsb_c);
|
||||
end loop;
|
||||
for i in 0 to SLINK_NUM_TX-1 loop
|
||||
irq_tx_en(i) <= data_i(i + irq_tx_en_lsb_c);
|
||||
irq_tx_mode(i) <= data_i(i + irq_tx_mode_lsb_c);
|
||||
end loop;
|
||||
end if;
|
||||
ack_write <= '1';
|
||||
else -- TX links
|
||||
ack_write <= or_reduce_f(link_sel and tx_fifo_free);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
ack_read <= '0';
|
||||
if (rden = '1') then
|
||||
if (addr(5) = '0') then -- control/status registers
|
||||
ack_read <= '1';
|
||||
case addr(4 downto 3) is
|
||||
when "00" => -- control register
|
||||
data_o(ctrl_rx_num_msb_c downto ctrl_rx_num_lsb_c) <= std_ulogic_vector(to_unsigned(SLINK_NUM_RX, 4));
|
||||
data_o(ctrl_tx_num_msb_c downto ctrl_tx_num_lsb_c) <= std_ulogic_vector(to_unsigned(SLINK_NUM_TX, 4));
|
||||
data_o(ctrl_rx_size_msb_c downto ctrl_rx_size_lsb_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_RX_FIFO), 4));
|
||||
data_o(ctrl_tx_size_msb_c downto ctrl_tx_size_lsb_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_TX_FIFO), 4));
|
||||
data_o(ctrl_en_c) <= enable;
|
||||
when "01" => -- IRQ configuration register
|
||||
for i in 0 to SLINK_NUM_RX-1 loop
|
||||
data_o(irq_rx_en_lsb_c + i) <= irq_rx_en(i);
|
||||
data_o(irq_rx_mode_lsb_c + i) <= irq_rx_mode(i) or bool_to_ulogic_f(boolean(SLINK_RX_FIFO = 1)); -- tie to one if SLINK_RX_FIFO is 1
|
||||
end loop;
|
||||
for i in 0 to SLINK_NUM_TX-1 loop
|
||||
data_o(irq_tx_en_lsb_c + i) <= irq_tx_en(i);
|
||||
data_o(irq_tx_mode_lsb_c + i) <= irq_tx_mode(i) or bool_to_ulogic_f(boolean(SLINK_TX_FIFO = 1)); -- tie to one if SLINK_TX_FIFO is 1
|
||||
end loop;
|
||||
when "10" | "11" => -- fifo status register
|
||||
data_o(status_rx_avail_msb_c downto status_rx_avail_lsb_c) <= rx_fifo_avail;
|
||||
data_o(status_tx_free_msb_c downto status_tx_free_lsb_c) <= tx_fifo_free;
|
||||
data_o(status_rx_half_msb_c downto status_rx_half_lsb_c) <= rx_fifo_half;
|
||||
data_o(status_tx_half_msb_c downto status_tx_half_lsb_c) <= tx_fifo_half;
|
||||
when others =>
|
||||
data_o <= (others => '0');
|
||||
end case;
|
||||
else -- RX links
|
||||
data_o <= rx_fifo_rdata(to_integer(unsigned(addr(4 downto 2))));
|
||||
ack_read <= or_reduce_f(link_sel and rx_fifo_avail);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
-- bus access acknowledge --
|
||||
ack_o <= ack_write or ack_read;
|
||||
|
||||
-- link fifo reset (sync) --
|
||||
fifo_clear <= not enable;
|
||||
|
||||
|
||||
-- Interrupt Generator --------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- interrupt trigger type / condition --
|
||||
irq_type: process(irq_rx_mode, rx_fifo_avail, rx_fifo_half, irq_tx_mode, tx_fifo_free, tx_fifo_half, tx_fifo_we)
|
||||
begin
|
||||
-- RX interrupt --
|
||||
rx_irq.trigger <= (others => '0');
|
||||
for i in 0 to SLINK_NUM_RX-1 loop
|
||||
if (SLINK_RX_FIFO = 1) or (irq_rx_mode(i) = '0') then
|
||||
rx_irq.trigger(i) <= rx_fifo_avail(i); -- fire if any RX_FIFO is not empty (= data available)
|
||||
else
|
||||
rx_irq.trigger(i) <= rx_fifo_half(i);
|
||||
end if;
|
||||
end loop;
|
||||
-- TX interrupt --
|
||||
tx_irq.trigger <= (others => '0');
|
||||
for i in 0 to SLINK_NUM_TX-1 loop
|
||||
if (SLINK_TX_FIFO = 1) or (irq_tx_mode(i) = '0') then
|
||||
tx_irq.trigger(i) <= tx_fifo_free(i) and tx_fifo_we(i); -- fire if any TX_FIFO is not full (= free buffer space available)
|
||||
else
|
||||
tx_irq.trigger(i) <= not tx_fifo_half(i);
|
||||
end if;
|
||||
end loop;
|
||||
end process irq_type;
|
||||
|
||||
-- edge detector - sync --
|
||||
irq_edge_detect_sync: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- RX --
|
||||
for i in 0 to SLINK_NUM_RX-1 loop
|
||||
if (enable = '1') and (irq_rx_en(i) = '1') then
|
||||
rx_irq.detect(i) <= rx_irq.detect(i)(0) & rx_irq.trigger(i);
|
||||
else
|
||||
rx_irq.detect(i) <= "00";
|
||||
end if;
|
||||
end loop;
|
||||
-- TX --
|
||||
for i in 0 to SLINK_NUM_TX-1 loop
|
||||
if (enable = '1') and (irq_tx_en(i) = '1') then
|
||||
tx_irq.detect(i) <= tx_irq.detect(i)(0) & tx_irq.trigger(i);
|
||||
else
|
||||
tx_irq.detect(i) <= "00";
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
end process irq_edge_detect_sync;
|
||||
|
||||
-- edge detector - sync --
|
||||
irq_edge_detect_comb: process(rx_irq, irq_rx_en, tx_irq, irq_tx_en)
|
||||
begin
|
||||
-- RX --
|
||||
rx_irq.set <= (others => '0');
|
||||
for i in 0 to SLINK_NUM_RX-1 loop
|
||||
if (rx_irq.detect(i) = "01") then -- rising-edge
|
||||
rx_irq.set(i) <= '1';
|
||||
end if;
|
||||
end loop;
|
||||
-- TX --
|
||||
tx_irq.set <= (others => '0');
|
||||
for i in 0 to SLINK_NUM_TX-1 loop
|
||||
if (tx_irq.detect(i) = "01") then -- rising-edge
|
||||
tx_irq.set(i) <= '1';
|
||||
end if;
|
||||
end loop;
|
||||
end process irq_edge_detect_comb;
|
||||
|
||||
-- interrupt arbiter --
|
||||
irq_generator: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
irq_rx_o <= or_reduce_f(rx_irq.set);
|
||||
irq_tx_o <= or_reduce_f(tx_irq.set);
|
||||
end if;
|
||||
end process irq_generator;
|
||||
|
||||
|
||||
-- Link Select ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
link_select: process(addr)
|
||||
begin
|
||||
case addr(5 downto 2) is -- MSB = data fifo access at all?
|
||||
when "1000" => link_sel <= "00000001";
|
||||
when "1001" => link_sel <= "00000010";
|
||||
when "1010" => link_sel <= "00000100";
|
||||
when "1011" => link_sel <= "00001000";
|
||||
when "1100" => link_sel <= "00010000";
|
||||
when "1101" => link_sel <= "00100000";
|
||||
when "1110" => link_sel <= "01000000";
|
||||
when "1111" => link_sel <= "10000000";
|
||||
when others => link_sel <= "00000000";
|
||||
end case;
|
||||
end process link_select;
|
||||
|
||||
fifo_access_gen:
|
||||
for i in 0 to 7 generate
|
||||
tx_fifo_we(i) <= link_sel(i) and wren;
|
||||
rx_fifo_re(i) <= link_sel(i) and rden;
|
||||
end generate;
|
||||
|
||||
|
||||
-- TX Link FIFOs --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
transmit_fifo_gen:
|
||||
for i in 0 to SLINK_NUM_TX-1 generate
|
||||
transmit_fifo_inst: neorv32_fifo
|
||||
generic map (
|
||||
FIFO_DEPTH => SLINK_TX_FIFO, -- number of fifo entries; has to be a power of two; min 1
|
||||
FIFO_WIDTH => 32, -- size of data elements in fifo
|
||||
FIFO_RSYNC => false, -- async read
|
||||
FIFO_SAFE => true -- safe access
|
||||
)
|
||||
port map (
|
||||
-- control --
|
||||
clk_i => clk_i, -- clock, rising edge
|
||||
rstn_i => '1', -- async reset, low-active
|
||||
clear_i => fifo_clear, -- sync reset, high-active
|
||||
level_o => open, -- fill level
|
||||
half_o => tx_fifo_half(i), -- FIFO is at least half full
|
||||
-- write port --
|
||||
wdata_i => data_i, -- write data
|
||||
we_i => tx_fifo_we(i), -- write enable
|
||||
free_o => tx_fifo_free(i), -- at least one entry is free when set
|
||||
-- read port --
|
||||
re_i => slink_tx_rdy_i(i), -- read enable
|
||||
rdata_o => slink_tx_dat_o(i), -- read data
|
||||
avail_o => slink_tx_val_o(i) -- data available when set
|
||||
);
|
||||
end generate;
|
||||
|
||||
-- terminate unimplemented links --
|
||||
transmit_fifo_gen_terminate:
|
||||
for i in SLINK_NUM_TX to 7 generate
|
||||
tx_fifo_free(i) <= '0';
|
||||
slink_tx_dat_o(i) <= (others => '0');
|
||||
slink_tx_val_o(i) <= '0';
|
||||
tx_fifo_half(i) <= '0';
|
||||
end generate;
|
||||
|
||||
|
||||
-- RX Link FIFOs --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
receive_fifo_gen:
|
||||
for i in 0 to SLINK_NUM_RX-1 generate
|
||||
receive_fifo_inst: neorv32_fifo
|
||||
generic map (
|
||||
FIFO_DEPTH => SLINK_RX_FIFO, -- number of fifo entries; has to be a power of two; min 1
|
||||
FIFO_WIDTH => 32, -- size of data elements in fifo
|
||||
FIFO_RSYNC => false, -- async read
|
||||
FIFO_SAFE => true -- safe access
|
||||
)
|
||||
port map (
|
||||
-- control --
|
||||
clk_i => clk_i, -- clock, rising edge
|
||||
rstn_i => '1', -- async reset, low-active
|
||||
clear_i => fifo_clear, -- sync reset, high-active
|
||||
level_o => open, -- fill level
|
||||
half_o => rx_fifo_half(i), -- FIFO is at least half full
|
||||
-- write port --
|
||||
wdata_i => slink_rx_dat_i(i), -- write data
|
||||
we_i => slink_rx_val_i(i), -- write enable
|
||||
free_o => slink_rx_rdy_o(i), -- at least one entry is free when set
|
||||
-- read port --
|
||||
re_i => rx_fifo_re(i), -- read enable
|
||||
rdata_o => rx_fifo_rdata(i), -- read data
|
||||
avail_o => rx_fifo_avail(i) -- data available when set
|
||||
);
|
||||
end generate;
|
||||
|
||||
-- terminate unimplemented links --
|
||||
receive_fifo_gen_terminate:
|
||||
for i in SLINK_NUM_RX to 7 generate
|
||||
rx_fifo_avail(i) <= '0';
|
||||
slink_rx_rdy_o(i) <= '0';
|
||||
rx_fifo_rdata(i) <= (others => '0');
|
||||
rx_fifo_half(i) <= '0';
|
||||
end generate;
|
||||
|
||||
|
||||
end neorv32_slink_rtl;
|
287
Libs/RiscV/NEORV32/rtl/core/neorv32_spi.vhd
Normal file
287
Libs/RiscV/NEORV32/rtl/core/neorv32_spi.vhd
Normal file
@ -0,0 +1,287 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Serial Peripheral Interface Controller (SPI) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Frame format: 8/16/24/32-bit receive/transmit data, always MSB first, 2 clock modes, #
|
||||
-- # 8 pre-scaled clocks (derived from system clock), 8 dedicated chip-select lines (low-active). #
|
||||
-- # Interrupt: "transfer done" #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_spi 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);
|
||||
-- com lines --
|
||||
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; -- controller data in, peripheral data out
|
||||
spi_csn_o : out std_ulogic_vector(07 downto 0); -- SPI CS
|
||||
-- interrupt --
|
||||
irq_o : out std_ulogic -- transmission done interrupt
|
||||
);
|
||||
end neorv32_spi;
|
||||
|
||||
architecture neorv32_spi_rtl of neorv32_spi is
|
||||
|
||||
-- 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(spi_size_c); -- low address boundary bit
|
||||
|
||||
-- control register --
|
||||
constant ctrl_cs0_c : natural := 0; -- r/w: spi CS 0
|
||||
constant ctrl_cs1_c : natural := 1; -- r/w: spi CS 1
|
||||
constant ctrl_cs2_c : natural := 2; -- r/w: spi CS 2
|
||||
constant ctrl_cs3_c : natural := 3; -- r/w: spi CS 3
|
||||
constant ctrl_cs4_c : natural := 4; -- r/w: spi CS 4
|
||||
constant ctrl_cs5_c : natural := 5; -- r/w: spi CS 5
|
||||
constant ctrl_cs6_c : natural := 6; -- r/w: spi CS 6
|
||||
constant ctrl_cs7_c : natural := 7; -- r/w: spi CS 7
|
||||
--
|
||||
constant ctrl_en_c : natural := 8; -- r/w: spi enable
|
||||
constant ctrl_cpha_c : natural := 9; -- r/w: spi clock phase
|
||||
constant ctrl_prsc0_c : natural := 10; -- r/w: spi prescaler select bit 0
|
||||
constant ctrl_prsc1_c : natural := 11; -- r/w: spi prescaler select bit 1
|
||||
constant ctrl_prsc2_c : natural := 12; -- r/w: spi prescaler select bit 2
|
||||
constant ctrl_size0_c : natural := 13; -- r/w: data size lsb (00: 8-bit, 01: 16-bit)
|
||||
constant ctrl_size1_c : natural := 14; -- r/w: data size msb (10: 24-bit, 11: 32-bit)
|
||||
constant ctrl_cpol_c : natural := 15; -- r/w: spi clock polarity
|
||||
--
|
||||
constant ctrl_busy_c : natural := 31; -- r/-: spi transceiver is busy
|
||||
--
|
||||
signal ctrl : std_ulogic_vector(15 downto 0);
|
||||
|
||||
-- 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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- clock generator --
|
||||
signal spi_clk_en : std_ulogic;
|
||||
|
||||
-- spi transceiver --
|
||||
type rtx_engine_t is record
|
||||
state : std_ulogic_vector(02 downto 0);
|
||||
busy : std_ulogic;
|
||||
start : std_ulogic;
|
||||
sreg : std_ulogic_vector(31 downto 0);
|
||||
bitcnt : std_ulogic_vector(05 downto 0);
|
||||
bytecnt : std_ulogic_vector(02 downto 0);
|
||||
sdi_sync : std_ulogic_vector(01 downto 0);
|
||||
end record;
|
||||
signal rtx_engine : rtx_engine_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = spi_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= spi_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
|
||||
-- bus access acknowledge --
|
||||
ack_o <= rden or wren;
|
||||
|
||||
-- write access --
|
||||
if (wren = '1') then
|
||||
if (addr = spi_ctrl_addr_c) then -- control register
|
||||
ctrl(ctrl_cs0_c) <= data_i(ctrl_cs0_c);
|
||||
ctrl(ctrl_cs1_c) <= data_i(ctrl_cs1_c);
|
||||
ctrl(ctrl_cs2_c) <= data_i(ctrl_cs2_c);
|
||||
ctrl(ctrl_cs3_c) <= data_i(ctrl_cs3_c);
|
||||
ctrl(ctrl_cs4_c) <= data_i(ctrl_cs4_c);
|
||||
ctrl(ctrl_cs5_c) <= data_i(ctrl_cs5_c);
|
||||
ctrl(ctrl_cs6_c) <= data_i(ctrl_cs6_c);
|
||||
ctrl(ctrl_cs7_c) <= data_i(ctrl_cs7_c);
|
||||
--
|
||||
ctrl(ctrl_en_c) <= data_i(ctrl_en_c);
|
||||
ctrl(ctrl_cpha_c) <= data_i(ctrl_cpha_c);
|
||||
ctrl(ctrl_prsc0_c) <= data_i(ctrl_prsc0_c);
|
||||
ctrl(ctrl_prsc1_c) <= data_i(ctrl_prsc1_c);
|
||||
ctrl(ctrl_prsc2_c) <= data_i(ctrl_prsc2_c);
|
||||
ctrl(ctrl_size0_c) <= data_i(ctrl_size0_c);
|
||||
ctrl(ctrl_size1_c) <= data_i(ctrl_size1_c);
|
||||
ctrl(ctrl_cpol_c) <= data_i(ctrl_cpol_c);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
if (addr = spi_ctrl_addr_c) then -- control register
|
||||
data_o(ctrl_cs0_c) <= ctrl(ctrl_cs0_c);
|
||||
data_o(ctrl_cs1_c) <= ctrl(ctrl_cs1_c);
|
||||
data_o(ctrl_cs2_c) <= ctrl(ctrl_cs2_c);
|
||||
data_o(ctrl_cs3_c) <= ctrl(ctrl_cs3_c);
|
||||
data_o(ctrl_cs4_c) <= ctrl(ctrl_cs4_c);
|
||||
data_o(ctrl_cs5_c) <= ctrl(ctrl_cs5_c);
|
||||
data_o(ctrl_cs6_c) <= ctrl(ctrl_cs6_c);
|
||||
data_o(ctrl_cs7_c) <= ctrl(ctrl_cs7_c);
|
||||
--
|
||||
data_o(ctrl_en_c) <= ctrl(ctrl_en_c);
|
||||
data_o(ctrl_cpha_c) <= ctrl(ctrl_cpha_c);
|
||||
data_o(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c);
|
||||
data_o(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c);
|
||||
data_o(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c);
|
||||
data_o(ctrl_size0_c) <= ctrl(ctrl_size0_c);
|
||||
data_o(ctrl_size1_c) <= ctrl(ctrl_size1_c);
|
||||
data_o(ctrl_cpol_c) <= ctrl(ctrl_cpol_c);
|
||||
--
|
||||
data_o(ctrl_busy_c) <= rtx_engine.busy;
|
||||
else -- data register (spi_rtx_addr_c)
|
||||
data_o <= rtx_engine.sreg;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
-- direct chip-select (CS), output is low-active --
|
||||
spi_csn_o(7 downto 0) <= not ctrl(ctrl_cs7_c downto ctrl_cs0_c);
|
||||
|
||||
-- trigger new SPI transmission --
|
||||
rtx_engine.start <= '1' when (wren = '1') and (addr = spi_rtx_addr_c) else '0';
|
||||
|
||||
|
||||
-- Clock Selection ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
clkgen_en_o <= ctrl(ctrl_en_c); -- clock generator enable
|
||||
spi_clk_en <= clkgen_i(to_integer(unsigned(ctrl(ctrl_prsc2_c downto ctrl_prsc0_c)))); -- clock select
|
||||
|
||||
|
||||
-- Transmission Data Size -----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
data_size: process(ctrl)
|
||||
begin
|
||||
case ctrl(ctrl_size1_c downto ctrl_size0_c) is
|
||||
when "00" => rtx_engine.bytecnt <= "001"; -- 1-byte mode
|
||||
when "01" => rtx_engine.bytecnt <= "010"; -- 2-byte mode
|
||||
when "10" => rtx_engine.bytecnt <= "011"; -- 3-byte mode
|
||||
when others => rtx_engine.bytecnt <= "100"; -- 4-byte mode
|
||||
end case;
|
||||
end process data_size;
|
||||
|
||||
|
||||
-- SPI Transceiver ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
spi_rtx_unit: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- input (sdi) synchronizer --
|
||||
rtx_engine.sdi_sync <= rtx_engine.sdi_sync(0) & spi_sdi_i;
|
||||
|
||||
-- output (sdo) buffer --
|
||||
case ctrl(ctrl_size1_c downto ctrl_size0_c) is
|
||||
when "00" => spi_sdo_o <= rtx_engine.sreg(07); -- 8-bit mode
|
||||
when "01" => spi_sdo_o <= rtx_engine.sreg(15); -- 16-bit mode
|
||||
when "10" => spi_sdo_o <= rtx_engine.sreg(23); -- 24-bit mode
|
||||
when others => spi_sdo_o <= rtx_engine.sreg(31); -- 32-bit mode
|
||||
end case;
|
||||
|
||||
-- defaults --
|
||||
spi_sck_o <= ctrl(ctrl_cpol_c);
|
||||
irq_o <= '0';
|
||||
|
||||
-- serial engine --
|
||||
rtx_engine.state(2) <= ctrl(ctrl_en_c);
|
||||
case rtx_engine.state is
|
||||
|
||||
when "100" => -- enabled but idle, waiting for new transmission trigger
|
||||
-- ------------------------------------------------------------
|
||||
rtx_engine.bitcnt <= (others => '0');
|
||||
if (rtx_engine.start = '1') then -- trigger new transmission
|
||||
rtx_engine.sreg <= data_i;
|
||||
rtx_engine.state(1 downto 0) <= "01";
|
||||
end if;
|
||||
|
||||
when "101" => -- start with next new clock pulse
|
||||
-- ------------------------------------------------------------
|
||||
if (spi_clk_en = '1') then
|
||||
rtx_engine.state(1 downto 0) <= "10";
|
||||
end if;
|
||||
|
||||
when "110" => -- first half of bit transmission
|
||||
-- ------------------------------------------------------------
|
||||
spi_sck_o <= ctrl(ctrl_cpha_c) xor ctrl(ctrl_cpol_c);
|
||||
if (spi_clk_en = '1') then
|
||||
rtx_engine.bitcnt <= std_ulogic_vector(unsigned(rtx_engine.bitcnt) + 1);
|
||||
rtx_engine.state(1 downto 0) <= "11";
|
||||
end if;
|
||||
|
||||
when "111" => -- second half of bit transmission
|
||||
-- ------------------------------------------------------------
|
||||
spi_sck_o <= ctrl(ctrl_cpha_c) xnor ctrl(ctrl_cpol_c);
|
||||
if (spi_clk_en = '1') then
|
||||
rtx_engine.sreg <= rtx_engine.sreg(30 downto 0) & rtx_engine.sdi_sync(rtx_engine.sdi_sync'left);
|
||||
if (rtx_engine.bitcnt(5 downto 3) = rtx_engine.bytecnt) then -- all bits transferred?
|
||||
irq_o <= '1'; -- interrupt!
|
||||
rtx_engine.state(1 downto 0) <= "00"; -- transmission done
|
||||
else
|
||||
rtx_engine.state(1 downto 0) <= "10";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when others => -- "0--": SPI deactivated
|
||||
-- ------------------------------------------------------------
|
||||
rtx_engine.state(1 downto 0) <= "00";
|
||||
|
||||
end case;
|
||||
end if;
|
||||
end process spi_rtx_unit;
|
||||
|
||||
-- busy flag --
|
||||
rtx_engine.busy <= '0' when (rtx_engine.state(1 downto 0) = "00") else '1';
|
||||
|
||||
|
||||
end neorv32_spi_rtl;
|
227
Libs/RiscV/NEORV32/rtl/core/neorv32_sysinfo.vhd
Normal file
227
Libs/RiscV/NEORV32/rtl/core/neorv32_sysinfo.vhd
Normal file
@ -0,0 +1,227 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - System/Processor Configuration Information Memory (SYSINFO) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This unit provides information regarding the NEORV32 processor system configuration - #
|
||||
-- # mostly derived from the top's configuration generics. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_sysinfo is
|
||||
generic (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY : natural; -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN : boolean; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean; -- implement 32-bit floating-point extension (using INT reg!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean; -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr : boolean; -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm : boolean; -- implement hardware performance monitors?
|
||||
CPU_EXTENSION_RISCV_Zifencei : boolean; -- implement instruction stream sync.?
|
||||
CPU_EXTENSION_RISCV_Zmmul : boolean; -- implement multiply-only M sub-extension?
|
||||
CPU_EXTENSION_RISCV_DEBUG : boolean; -- implement CPU debug mode?
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN : boolean; -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN : boolean; -- use barrel shifter for shift operations
|
||||
CPU_CNT_WIDTH : natural; -- total width of CPU cycle and instret counters (0..64)
|
||||
-- Physical memory protection (PMP) --
|
||||
PMP_NUM_REGIONS : natural; -- number of regions (0..64)
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN : boolean; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural; -- size of processor-internal instruction memory in bytes
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN : boolean; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural; -- size of processor-internal data memory in bytes
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN : boolean; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural; -- i-cache: number of blocks (min 2), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY : natural; -- i-cache: associativity (min 1), has to be a power 2
|
||||
-- External memory interface --
|
||||
MEM_EXT_EN : boolean; -- implement external memory bus interface?
|
||||
MEM_EXT_BIG_ENDIAN : boolean; -- byte order: true=big-endian, false=little-endian
|
||||
-- On-Chip Debugger --
|
||||
ON_CHIP_DEBUGGER_EN : boolean; -- implement OCD?
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN : boolean; -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN : boolean; -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN : boolean; -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART1_EN : boolean; -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_SPI_EN : boolean; -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN : boolean; -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH : natural; -- number of PWM channels to implement
|
||||
IO_WDT_EN : boolean; -- implement watch dog timer (WDT)?
|
||||
IO_TRNG_EN : boolean; -- implement true random number generator (TRNG)?
|
||||
IO_CFS_EN : boolean; -- implement custom functions subsystem (CFS)?
|
||||
IO_SLINK_EN : boolean; -- implement stream link interface?
|
||||
IO_NEOLED_EN : boolean; -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
IO_XIRQ_NUM_CH : natural; -- number of external interrupt (XIRQ) channels to implement
|
||||
IO_GPTMR_EN : boolean -- implement general purpose timer (GPTMR)?
|
||||
);
|
||||
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
|
||||
data_o : out std_ulogic_vector(31 downto 0); -- data out
|
||||
ack_o : out std_ulogic -- transfer acknowledge
|
||||
);
|
||||
end neorv32_sysinfo;
|
||||
|
||||
architecture neorv32_sysinfo_rtl of neorv32_sysinfo is
|
||||
|
||||
-- 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(sysinfo_size_c); -- low address boundary bit
|
||||
|
||||
-- access control --
|
||||
signal acc_en : std_ulogic; -- module access enable
|
||||
signal addr : std_ulogic_vector(31 downto 0);
|
||||
signal rden : std_ulogic;
|
||||
signal info_addr : std_ulogic_vector(02 downto 0);
|
||||
|
||||
-- system information ROM --
|
||||
type info_mem_t is array (0 to 7) of std_ulogic_vector(31 downto 0);
|
||||
signal sysinfo_mem : info_mem_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = sysinfo_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
rden <= acc_en and rden_i; -- valid read access
|
||||
addr <= sysinfo_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
||||
info_addr <= addr(index_size_f(sysinfo_size_c)-1 downto 2);
|
||||
|
||||
|
||||
-- Construct Info ROM ---------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
|
||||
-- SYSINFO(0): Processor (primary) clock frequency --
|
||||
sysinfo_mem(0) <= std_ulogic_vector(to_unsigned(CLOCK_FREQUENCY, 32));
|
||||
|
||||
-- SYSINFO(1): CPU configuration --
|
||||
sysinfo_mem(1)(00) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr
|
||||
sysinfo_mem(1)(01) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei
|
||||
sysinfo_mem(1)(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zmmul); -- Zmmul
|
||||
--
|
||||
sysinfo_mem(1)(04 downto 03) <= (others => '0'); -- reserved
|
||||
--
|
||||
sysinfo_mem(1)(05) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zfinx); -- Zfinx ("F-alternative")
|
||||
sysinfo_mem(1)(06) <= bool_to_ulogic_f(boolean(CPU_CNT_WIDTH /= 64)); -- reduced-size CPU counters (Zxscnt)
|
||||
sysinfo_mem(1)(07) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicntr); -- base CPU counter
|
||||
sysinfo_mem(1)(08) <= bool_to_ulogic_f(boolean(PMP_NUM_REGIONS > 0)); -- PMP (physical memory protection)
|
||||
sysinfo_mem(1)(09) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zihpm); -- HPM (hardware performance monitors)
|
||||
sysinfo_mem(1)(10) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_DEBUG); -- RISC-V debug mode
|
||||
--
|
||||
sysinfo_mem(1)(29 downto 11) <= (others => '0'); -- reserved
|
||||
-- misc --
|
||||
sysinfo_mem(1)(30) <= bool_to_ulogic_f(FAST_MUL_EN); -- DSP-based multiplication (M extension only)
|
||||
sysinfo_mem(1)(31) <= bool_to_ulogic_f(FAST_SHIFT_EN); -- parallel logic for shifts (like barrel shifters)
|
||||
|
||||
-- SYSINFO(2): Implemented processor devices/features --
|
||||
-- Memory --
|
||||
sysinfo_mem(2)(00) <= bool_to_ulogic_f(INT_BOOTLOADER_EN); -- processor-internal bootloader implemented?
|
||||
sysinfo_mem(2)(01) <= bool_to_ulogic_f(MEM_EXT_EN); -- external memory bus interface implemented?
|
||||
sysinfo_mem(2)(02) <= bool_to_ulogic_f(MEM_INT_IMEM_EN) and bool_to_ulogic_f(boolean(MEM_INT_IMEM_SIZE > 0)); -- processor-internal instruction memory implemented?
|
||||
sysinfo_mem(2)(03) <= bool_to_ulogic_f(MEM_INT_DMEM_EN) and bool_to_ulogic_f(boolean(MEM_INT_DMEM_SIZE > 0)); -- processor-internal data memory implemented?
|
||||
sysinfo_mem(2)(04) <= bool_to_ulogic_f(MEM_EXT_BIG_ENDIAN); -- is external memory bus interface using BIG-endian byte-order?
|
||||
sysinfo_mem(2)(05) <= bool_to_ulogic_f(ICACHE_EN); -- processor-internal instruction cache implemented?
|
||||
--
|
||||
sysinfo_mem(2)(12 downto 06) <= (others => '0'); -- reserved
|
||||
-- Misc --
|
||||
sysinfo_mem(2)(13) <= bool_to_ulogic_f(is_simulation_c); -- is this a simulation?
|
||||
sysinfo_mem(2)(14) <= bool_to_ulogic_f(ON_CHIP_DEBUGGER_EN); -- on-chip debugger implemented?
|
||||
sysinfo_mem(2)(15) <= bool_to_ulogic_f(dedicated_reset_c); -- dedicated hardware reset of all core registers?
|
||||
-- IO --
|
||||
sysinfo_mem(2)(16) <= bool_to_ulogic_f(IO_GPIO_EN); -- general purpose input/output port unit (GPIO) implemented?
|
||||
sysinfo_mem(2)(17) <= bool_to_ulogic_f(IO_MTIME_EN); -- machine system timer (MTIME) implemented?
|
||||
sysinfo_mem(2)(18) <= bool_to_ulogic_f(IO_UART0_EN); -- primary universal asynchronous receiver/transmitter (UART0) implemented?
|
||||
sysinfo_mem(2)(19) <= bool_to_ulogic_f(IO_SPI_EN); -- serial peripheral interface (SPI) implemented?
|
||||
sysinfo_mem(2)(20) <= bool_to_ulogic_f(IO_TWI_EN); -- two-wire interface (TWI) implemented?
|
||||
sysinfo_mem(2)(21) <= bool_to_ulogic_f(boolean(IO_PWM_NUM_CH > 0)); -- pulse-width modulation unit (PWM) implemented?
|
||||
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_SLINK_EN); -- stream links (SLINK) implemented?
|
||||
sysinfo_mem(2)(26) <= bool_to_ulogic_f(IO_UART1_EN); -- secondary universal asynchronous receiver/transmitter (UART1) implemented?
|
||||
sysinfo_mem(2)(27) <= bool_to_ulogic_f(IO_NEOLED_EN); -- NeoPixel-compatible smart LED interface (NEOLED) implemented?
|
||||
sysinfo_mem(2)(28) <= bool_to_ulogic_f(boolean(IO_XIRQ_NUM_CH > 0)); -- external interrupt controller (XIRQ) implemented?
|
||||
sysinfo_mem(2)(29) <= bool_to_ulogic_f(IO_GPTMR_EN); -- general purpose timer (GPTMR) implemented?
|
||||
--
|
||||
sysinfo_mem(2)(31 downto 30) <= (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)
|
||||
sysinfo_mem(3)(07 downto 04) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_NUM_BLOCKS), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(number_of_block)
|
||||
sysinfo_mem(3)(11 downto 08) <= std_ulogic_vector(to_unsigned(index_size_f(ICACHE_ASSOCIATIVITY), 4)) when (ICACHE_EN = true) else (others => '0'); -- i-cache: log2(associativity)
|
||||
sysinfo_mem(3)(15 downto 12) <= "0001" when (ICACHE_ASSOCIATIVITY > 1) and (ICACHE_EN = true) else (others => '0'); -- i-cache: replacement strategy (LRU only (yet))
|
||||
--
|
||||
sysinfo_mem(3)(19 downto 16) <= (others => '0'); -- reserved - d-cache: log2(block_size)
|
||||
sysinfo_mem(3)(23 downto 20) <= (others => '0'); -- reserved - d-cache: log2(num_blocks)
|
||||
sysinfo_mem(3)(27 downto 24) <= (others => '0'); -- reserved - d-cache: log2(associativity)
|
||||
sysinfo_mem(3)(31 downto 28) <= (others => '0'); -- reserved - d-cache: replacement strategy
|
||||
|
||||
-- SYSINFO(4): Base address of instruction memory space --
|
||||
sysinfo_mem(4) <= ispace_base_c; -- defined in neorv32_package.vhd file
|
||||
|
||||
-- SYSINFO(5): Base address of data memory space --
|
||||
sysinfo_mem(5) <= dspace_base_c; -- defined in neorv32_package.vhd file
|
||||
|
||||
-- SYSINFO(6): Size of IMEM in bytes --
|
||||
sysinfo_mem(6) <= std_ulogic_vector(to_unsigned(MEM_INT_IMEM_SIZE, 32)) when (MEM_INT_IMEM_EN = true) else (others => '0');
|
||||
|
||||
-- SYSINFO(7): Size of DMEM in bytes --
|
||||
sysinfo_mem(7) <= std_ulogic_vector(to_unsigned(MEM_INT_DMEM_SIZE, 32)) when (MEM_INT_DMEM_EN = true) else (others => '0');
|
||||
|
||||
|
||||
-- Read Access ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
read_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
ack_o <= rden;
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
data_o <= sysinfo_mem(to_integer(unsigned(info_addr)));
|
||||
end if;
|
||||
end if;
|
||||
end process read_access;
|
||||
|
||||
|
||||
end neorv32_sysinfo_rtl;
|
1563
Libs/RiscV/NEORV32/rtl/core/neorv32_top.vhd
Normal file
1563
Libs/RiscV/NEORV32/rtl/core/neorv32_top.vhd
Normal file
File diff suppressed because it is too large
Load Diff
550
Libs/RiscV/NEORV32/rtl/core/neorv32_trng.vhd
Normal file
550
Libs/RiscV/NEORV32/rtl/core/neorv32_trng.vhd
Normal file
@ -0,0 +1,550 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - True Random Number Generator (TRNG) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This processor module instantiates the "neoTRNG" true random number generator. #
|
||||
-- # See the neoTRNG's documentation for more information: https://github.com/stnolting/neoTRNG #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_trng 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
|
||||
);
|
||||
end neorv32_trng;
|
||||
|
||||
architecture neorv32_trng_rtl of neorv32_trng is
|
||||
|
||||
-- neoTRNG Configuration -------------------------------------------------------------------------------------------
|
||||
constant num_cells_c : natural := 3; -- total number of ring-oscillator cells
|
||||
constant num_inv_start_c : natural := 3; -- number of inverters in first cell (short path), has to be odd
|
||||
constant num_inv_inc_c : natural := 2; -- number of additional inverters in next cell (short path), has to be even
|
||||
constant num_inv_delay_c : natural := 2; -- additional inverters to form cell's long path, has to be even
|
||||
-- -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- control register bits --
|
||||
constant ctrl_data_lsb_c : natural := 0; -- r/-: Random data byte LSB
|
||||
constant ctrl_data_msb_c : natural := 7; -- r/-: Random data byte MSB
|
||||
constant ctrl_en_c : natural := 30; -- r/w: TRNG enable
|
||||
constant ctrl_valid_c : natural := 31; -- r/-: Output data valid
|
||||
|
||||
-- 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(trng_size_c); -- low address boundary bit
|
||||
|
||||
-- access control --
|
||||
signal acc_en : std_ulogic; -- module access enable
|
||||
signal wren : std_ulogic; -- full word write enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- Component: neoTRNG true random number generator --
|
||||
component neoTRNG
|
||||
generic (
|
||||
NUM_CELLS : natural; -- total number of ring-oscillator cells
|
||||
NUM_INV_START : natural; -- number of inverters in first cell (short path), has to be odd
|
||||
NUM_INV_INC : natural; -- number of additional inverters in next cell (short path), has to be even
|
||||
NUM_INV_DELAY : natural -- additional inverters to form cell's long path, has to be even
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
enable_i : in std_ulogic; -- unit enable (high-active), reset unit when low
|
||||
data_o : out std_ulogic_vector(7 downto 0); -- random data byte output
|
||||
valid_o : out std_ulogic -- data_o is valid when set
|
||||
);
|
||||
end component;
|
||||
|
||||
-- TRNG interface --
|
||||
signal trng_data : std_ulogic_vector(7 downto 0);
|
||||
signal trng_valid : std_ulogic;
|
||||
|
||||
-- arbiter --
|
||||
signal enable : std_ulogic;
|
||||
signal valid : std_ulogic;
|
||||
signal rnd_reg : std_ulogic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
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
|
||||
-- host bus acknowledge --
|
||||
ack_o <= wren or rden;
|
||||
|
||||
-- write access --
|
||||
if (wren = '1') then
|
||||
enable <= data_i(ctrl_en_c);
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= rnd_reg;
|
||||
data_o(ctrl_en_c) <= enable;
|
||||
data_o(ctrl_valid_c) <= valid;
|
||||
end if;
|
||||
|
||||
-- sample --
|
||||
if (trng_valid = '1') then
|
||||
rnd_reg <= trng_data;
|
||||
end if;
|
||||
|
||||
-- data valid? --
|
||||
if (enable = '0') then -- disabled
|
||||
valid <= '0';
|
||||
else
|
||||
if (trng_valid = '1') then
|
||||
valid <= '1';
|
||||
elsif (rden = '1') then
|
||||
valid <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
|
||||
-- neoTRNG --------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neoTRNG_inst: neoTRNG
|
||||
generic map (
|
||||
NUM_CELLS => num_cells_c,
|
||||
NUM_INV_START => num_inv_start_c,
|
||||
NUM_INV_INC => num_inv_inc_c,
|
||||
NUM_INV_DELAY => num_inv_delay_c
|
||||
)
|
||||
port map (
|
||||
clk_i => clk_i,
|
||||
enable_i => enable,
|
||||
data_o => trng_data,
|
||||
valid_o => trng_valid
|
||||
);
|
||||
|
||||
|
||||
end neorv32_trng_rtl;
|
||||
|
||||
|
||||
-- ############################################################################################################################
|
||||
-- ############################################################################################################################
|
||||
|
||||
|
||||
-- #################################################################################################
|
||||
-- # << neoTRNG - A Tiny and Platform-Independent True Random Number Generator for any FPGA >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This generator is based on entropy cells, which implement simple ring-oscillators. Each ring- #
|
||||
-- # oscillator features a short and a long delay path that is dynamically selected defining the #
|
||||
-- # primary oscillation frequency. The cells are cascaded so that the random data output of a #
|
||||
-- # cell controls the delay path of the next cell (which has the next-larger inverter chain). #
|
||||
-- # #
|
||||
-- # The random data outputs of all cells are XOR-ed and de-biased using a von Neumann randomness #
|
||||
-- # extractor (converting edges into bits). The resulting bit is sampled in chunks of 8 bits to #
|
||||
-- # provide the final random data output. No further internal post-processing is applied. Hence, #
|
||||
-- # the TRNG produces simple de-biased *RAW* data. #
|
||||
-- # #
|
||||
-- # The entropy cell architecture uses individually-controlled latches and inverters to create #
|
||||
-- # the inverter chain in a platform-agnostic style that can be implemented for any FPGA without #
|
||||
-- # requiring primitive instantiation or technology-specific attributes. #
|
||||
-- # #
|
||||
-- # See the neoTRNG's documentation for more information: https://github.com/stnolting/neoTRNG #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # neoTRNG - https://github.com/stnolting/neoTRNG (c) Stephan Nolting #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity neoTRNG is
|
||||
generic (
|
||||
NUM_CELLS : natural; -- total number of ring-oscillator cells
|
||||
NUM_INV_START : natural; -- number of inverters in first cell (short path), has to be odd
|
||||
NUM_INV_INC : natural; -- number of additional inverters in next cell (short path), has to be even
|
||||
NUM_INV_DELAY : natural -- additional inverters to form cell's long path, has to be even
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
enable_i : in std_ulogic; -- unit enable (high-active), reset unit when low
|
||||
data_o : out std_ulogic_vector(7 downto 0); -- random data byte output
|
||||
valid_o : out std_ulogic -- data_o is valid when set
|
||||
);
|
||||
end neoTRNG;
|
||||
|
||||
architecture neoTRNG_rtl of neoTRNG is
|
||||
|
||||
-- Component: neoTRNG entropy cell --
|
||||
component neoTRNG_cell
|
||||
generic (
|
||||
NUM_INV_S : natural; -- number of inverters in short path
|
||||
NUM_INV_L : natural -- number of inverters in long path
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic; -- system clock
|
||||
select_i : in std_ulogic; -- delay select
|
||||
enable_i : in std_ulogic; -- enable chain input
|
||||
enable_o : out std_ulogic; -- enable chain output
|
||||
data_o : out std_ulogic -- sync random bit
|
||||
);
|
||||
end component;
|
||||
|
||||
-- ring-oscillator array interconnect --
|
||||
type cell_array_t is record
|
||||
en_in : std_ulogic_vector(NUM_CELLS-1 downto 0);
|
||||
en_out : std_ulogic_vector(NUM_CELLS-1 downto 0);
|
||||
rnd : std_ulogic_vector(NUM_CELLS-1 downto 0);
|
||||
sel : std_ulogic_vector(NUM_CELLS-1 downto 0);
|
||||
end record;
|
||||
signal cell_array : cell_array_t;
|
||||
|
||||
-- global cell-XOR --
|
||||
signal rnd_bit : std_ulogic;
|
||||
|
||||
-- von-Neumann de-biasing --
|
||||
type debiasing_t is record
|
||||
sreg : std_ulogic_vector(1 downto 0);
|
||||
state : std_ulogic; -- process de-biasing every second cycle
|
||||
valid : std_ulogic; -- de-biased data
|
||||
data : std_ulogic; -- de-biased data valid
|
||||
end record;
|
||||
signal deb : debiasing_t;
|
||||
|
||||
-- control unit --
|
||||
type ctrl_t is record
|
||||
enable : std_ulogic;
|
||||
run : std_ulogic;
|
||||
cnt : std_ulogic_vector(2 downto 0); -- bit counter
|
||||
sreg : std_ulogic_vector(7 downto 0); -- data shift register
|
||||
end record;
|
||||
signal ctrl : ctrl_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (NUM_CELLS < 2) report "neoTRNG config ERROR: Total number of ring-oscillator cells <NUM_CELLS> has to be >= 2." severity error;
|
||||
assert not ((NUM_INV_START mod 2) = 0) report "neoTRNG config ERROR: Number of inverters in first cell <NUM_INV_START> has to be odd." severity error;
|
||||
assert not ((NUM_INV_INC mod 2) /= 0) report "neoTRNG config ERROR: Inverter increment for each next cell <NUM_INV_INC> has to be even." severity error;
|
||||
assert not ((NUM_INV_DELAY mod 2) /= 0) report "neoTRNG config ERROR: Inverter increment to form long path <NUM_INV_DELAY> has to be even." severity error;
|
||||
|
||||
|
||||
-- Entropy Source -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neoTRNG_cell_inst:
|
||||
for i in 0 to NUM_CELLS-1 generate
|
||||
neoTRNG_cell_inst_i: neoTRNG_cell
|
||||
generic map (
|
||||
NUM_INV_S => NUM_INV_START + (i*NUM_INV_INC), -- number of inverters in short chain
|
||||
NUM_INV_L => NUM_INV_START + (i*NUM_INV_INC) + NUM_INV_DELAY -- number of inverters in long chain
|
||||
)
|
||||
port map (
|
||||
clk_i => clk_i,
|
||||
select_i => cell_array.sel(i),
|
||||
enable_i => cell_array.en_in(i),
|
||||
enable_o => cell_array.en_out(i),
|
||||
data_o => cell_array.rnd(i) -- SYNC data output
|
||||
);
|
||||
end generate;
|
||||
|
||||
-- path select chain --
|
||||
cell_array.sel(0) <= cell_array.rnd(NUM_CELLS-1); -- use output of last cell to select path of first cell
|
||||
cell_array.sel(NUM_CELLS-1 downto 1) <= cell_array.rnd(NUM_CELLS-2 downto 0); -- i+1 <= i
|
||||
|
||||
-- enable chain --
|
||||
cell_array.en_in(0) <= ctrl.enable; -- start of chain
|
||||
cell_array.en_in(NUM_CELLS-1 downto 1) <=cell_array.en_out(NUM_CELLS-2 downto 0); -- i+1 <= i
|
||||
|
||||
|
||||
-- XOR All Cell's Outputs -----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
cell_xor: process(cell_array.rnd)
|
||||
variable tmp_v : std_ulogic;
|
||||
begin
|
||||
tmp_v := '0';
|
||||
for i in 0 to NUM_CELLS-1 loop
|
||||
tmp_v := tmp_v xor cell_array.rnd(i);
|
||||
end loop; -- i
|
||||
rnd_bit <= tmp_v;
|
||||
end process cell_xor;
|
||||
|
||||
|
||||
-- John von Neumann Randomness Extractor --------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
debiasing_sync: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
deb.sreg <= deb.sreg(0) & rnd_bit;
|
||||
-- start operation when last cell is enabled and process in every second cycle --
|
||||
deb.state <= (not deb.state) and cell_array.en_out(NUM_CELLS-1);
|
||||
end if;
|
||||
end process debiasing_sync;
|
||||
|
||||
-- edge detector --
|
||||
debiasing_comb: process(deb)
|
||||
variable tmp_v : std_ulogic_vector(2 downto 0);
|
||||
begin
|
||||
tmp_v := deb.state & deb.sreg(1 downto 0); -- check groups of two non-overlapping bits from the input stream
|
||||
case tmp_v is
|
||||
when "101" => deb.valid <= '1'; deb.data <= '0'; -- rising edge = '0'
|
||||
when "110" => deb.valid <= '1'; deb.data <= '1'; -- falling edge = '1'
|
||||
when others => deb.valid <= '0'; deb.data <= '-'; -- no valid data
|
||||
end case;
|
||||
end process debiasing_comb;
|
||||
|
||||
|
||||
-- Control Unit ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
control_unit: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- make sure enable is sync --
|
||||
ctrl.enable <= enable_i;
|
||||
|
||||
-- sample chunks of 8 bit --
|
||||
if (ctrl.enable = '0') then
|
||||
ctrl.cnt <= (others => '0');
|
||||
ctrl.run <= '0';
|
||||
elsif (deb.valid = '1') then -- valid random sample?
|
||||
ctrl.cnt <= std_ulogic_vector(unsigned(ctrl.cnt) + 1);
|
||||
ctrl.run <= '1';
|
||||
end if;
|
||||
|
||||
-- sample shift register --
|
||||
if (deb.valid = '1') then
|
||||
ctrl.sreg <= ctrl.sreg(ctrl.sreg'left-1 downto 0) & deb.data;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process control_unit;
|
||||
|
||||
-- random byte output --
|
||||
data_o <= ctrl.sreg;
|
||||
|
||||
-- data valid? --
|
||||
valid_o <= '1' when (ctrl.cnt = "000") and (ctrl.run = '1') else '0';
|
||||
|
||||
|
||||
end neoTRNG_rtl;
|
||||
|
||||
|
||||
-- ############################################################################################################################
|
||||
-- ############################################################################################################################
|
||||
|
||||
|
||||
-- #################################################################################################
|
||||
-- # << neoTRNG - A Tiny and Platform-Independent True Random Number Generator for any FPGA >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # neoTRNG Entropy Cell #
|
||||
-- # #
|
||||
-- # The cell consists of two ring-oscillators build from inverter chains. The short chain uses #
|
||||
-- # NUM_INV_S inverters and oscillates at a "high" frequency and the long chain uses NUM_INV_L #
|
||||
-- # inverters and oscillates at a "low" frequency. The select_i input selects which chain is #
|
||||
-- # actually used. #
|
||||
-- # #
|
||||
-- # Each inverter chain is constructed as an "asynchronous" shift register. The single inverters #
|
||||
-- # are connected via latches that are used to enable/disable the TRNG. Also, these latches are #
|
||||
-- # used as additional delay element. By using unique enable signals for each latch, the #
|
||||
-- # synthesis tool cannot "optimize" (=remove) any of the inverters out of the design making the #
|
||||
-- # design platform-agnostic. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # neoTRNG - https://github.com/stnolting/neoTRNG (c) Stephan Nolting #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
entity neoTRNG_cell is
|
||||
generic (
|
||||
NUM_INV_S : natural; -- number of inverters in short path
|
||||
NUM_INV_L : natural -- number of inverters in long path
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic; -- system clock
|
||||
select_i : in std_ulogic; -- delay select
|
||||
enable_i : in std_ulogic; -- enable chain input
|
||||
enable_o : out std_ulogic; -- enable chain output
|
||||
data_o : out std_ulogic -- sync random bit
|
||||
);
|
||||
end neoTRNG_cell;
|
||||
|
||||
architecture neoTRNG_cell_rtl of neoTRNG_cell is
|
||||
|
||||
signal inv_chain_s : std_ulogic_vector(NUM_INV_S-1 downto 0); -- short oscillator chain
|
||||
signal inv_chain_l : std_ulogic_vector(NUM_INV_L-1 downto 0); -- long oscillator chain
|
||||
signal feedback : std_ulogic; -- cell feedback/output
|
||||
signal enable_sreg_s : std_ulogic_vector(NUM_INV_S-1 downto 0); -- enable shift register for short chain
|
||||
signal enable_sreg_l : std_ulogic_vector(NUM_INV_L-1 downto 0); -- enable shift register for long chain
|
||||
signal sync_ff : std_ulogic_vector(1 downto 0); -- output signal synchronizer
|
||||
|
||||
begin
|
||||
|
||||
-- Ring Oscillators -----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- Each cell provides a short inverter chain (high frequency) and a long oscillator chain (low frequency).
|
||||
-- The select_i signals defines which chain is enabled.
|
||||
-- NOTE: All signals that control a inverter-latch element have to be registered to ensure a single element
|
||||
-- is mapped to a single LUT (or LUT + FF(latch-mode)).
|
||||
|
||||
-- short oscillator chain --
|
||||
ring_osc_short: process(enable_i, enable_sreg_s, feedback, inv_chain_s)
|
||||
begin
|
||||
for i in 0 to NUM_INV_S-1 loop -- inverters in short chain
|
||||
if (enable_i = '0') then -- start with a defined state (latch reset)
|
||||
inv_chain_s(i) <= '0';
|
||||
elsif (enable_sreg_s(i) = '1') then
|
||||
if (i = NUM_INV_S-1) then -- left-most inverter?
|
||||
inv_chain_s(i) <= not feedback;
|
||||
else
|
||||
inv_chain_s(i) <= not inv_chain_s(i+1);
|
||||
end if;
|
||||
end if;
|
||||
end loop; -- i
|
||||
end process ring_osc_short;
|
||||
|
||||
-- long oscillator chain --
|
||||
ring_osc_long: process(enable_i, enable_sreg_l, feedback, inv_chain_l)
|
||||
begin
|
||||
for i in 0 to NUM_INV_L-1 loop -- inverters in long chain
|
||||
if (enable_i = '0') then -- start with a defined state (latch reset)
|
||||
inv_chain_l(i) <= '0';
|
||||
elsif (enable_sreg_l(i) = '1') then
|
||||
if (i = NUM_INV_L-1) then -- left-most inverter?
|
||||
inv_chain_l(i) <= not feedback;
|
||||
else
|
||||
inv_chain_l(i) <= not inv_chain_l(i+1);
|
||||
end if;
|
||||
end if;
|
||||
end loop; -- i
|
||||
end process ring_osc_long;
|
||||
|
||||
-- length select --
|
||||
feedback <= inv_chain_l(0) when (select_i = '0') else inv_chain_s(0);
|
||||
|
||||
|
||||
-- Control --------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- Using individual enable signals for each inverter from a shift register to prevent the synthesis tool
|
||||
-- from removing all but one inverter (since they implement "logical identical functions" (='toggle')).
|
||||
-- This makes the TRNG platform independent (since we do not need to use primitives to ensure a correct architecture).
|
||||
ctrl_unit: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- enable sreg --
|
||||
enable_sreg_s <= enable_sreg_s(enable_sreg_s'left-1 downto 0) & enable_i;
|
||||
enable_sreg_l <= enable_sreg_l(enable_sreg_l'left-1 downto 0) & enable_sreg_s(enable_sreg_s'left);
|
||||
-- data output sync - no metastability beyond this point --
|
||||
sync_ff <= sync_ff(0) & feedback;
|
||||
end if;
|
||||
end process ctrl_unit;
|
||||
|
||||
-- output for "enable chain" --
|
||||
enable_o <= enable_sreg_l(enable_sreg_l'left);
|
||||
|
||||
-- random data output --
|
||||
data_o <= sync_ff(1);
|
||||
|
||||
|
||||
end neoTRNG_cell_rtl;
|
290
Libs/RiscV/NEORV32/rtl/core/neorv32_twi.vhd
Normal file
290
Libs/RiscV/NEORV32/rtl/core/neorv32_twi.vhd
Normal file
@ -0,0 +1,290 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Two-Wire Interface Controller (TWI) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Supports START and STOP conditions, 8 bit data + ACK/NACK transfers and clock stretching. #
|
||||
-- # Supports ACKs by the controller. No multi-controller support and no peripheral mode support #
|
||||
-- # yet. Interrupt: "operation done" #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_twi 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);
|
||||
-- com lines --
|
||||
twi_sda_io : inout std_logic; -- serial data line
|
||||
twi_scl_io : inout std_logic; -- serial clock line
|
||||
-- interrupt --
|
||||
irq_o : out std_ulogic -- transfer done IRQ
|
||||
);
|
||||
end neorv32_twi;
|
||||
|
||||
architecture neorv32_twi_rtl of neorv32_twi is
|
||||
|
||||
-- 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(twi_size_c); -- low address boundary bit
|
||||
|
||||
-- control register --
|
||||
constant ctrl_en_c : natural := 0; -- r/w: TWI enable
|
||||
constant ctrl_start_c : natural := 1; -- -/w: Generate START condition
|
||||
constant ctrl_stop_c : natural := 2; -- -/w: Generate STOP condition
|
||||
constant ctrl_prsc0_c : natural := 3; -- r/w: CLK prsc bit 0
|
||||
constant ctrl_prsc1_c : natural := 4; -- r/w: CLK prsc bit 1
|
||||
constant ctrl_prsc2_c : natural := 5; -- r/w: CLK prsc bit 2
|
||||
constant ctrl_mack_c : natural := 6; -- r/w: generate ACK by controller for transmission
|
||||
--
|
||||
constant ctrl_ack_c : natural := 30; -- r/-: Set if ACK received
|
||||
constant ctrl_busy_c : natural := 31; -- r/-: Set if TWI unit is busy
|
||||
--
|
||||
signal ctrl : std_ulogic_vector(6 downto 0); -- unit's control register
|
||||
|
||||
-- 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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- twi clocking --
|
||||
signal twi_clk : std_ulogic;
|
||||
signal twi_phase_gen : std_ulogic_vector(3 downto 0);
|
||||
signal twi_clk_phase : std_ulogic_vector(3 downto 0);
|
||||
|
||||
-- twi clock stretching --
|
||||
signal twi_clk_halt : std_ulogic;
|
||||
|
||||
-- twi transceiver core --
|
||||
signal arbiter : std_ulogic_vector(2 downto 0);
|
||||
signal bitcnt : std_ulogic_vector(3 downto 0);
|
||||
signal rtx_sreg : std_ulogic_vector(8 downto 0); -- main rx/tx shift reg
|
||||
|
||||
-- tri-state I/O --
|
||||
signal twi_sda_in_ff : std_ulogic_vector(1 downto 0); -- SDA input sync
|
||||
signal twi_scl_in_ff : std_ulogic_vector(1 downto 0); -- SCL input sync
|
||||
signal twi_sda_in : std_ulogic;
|
||||
signal twi_scl_in : std_ulogic;
|
||||
signal twi_sda_out : std_ulogic;
|
||||
signal twi_scl_out : std_ulogic;
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = twi_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= twi_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 <= rden or wren;
|
||||
-- write access --
|
||||
if (wren = '1') then
|
||||
if (addr = twi_ctrl_addr_c) then
|
||||
ctrl <= data_i(ctrl'left downto 0);
|
||||
end if;
|
||||
end if;
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
if (addr = twi_ctrl_addr_c) then
|
||||
data_o(ctrl_en_c) <= ctrl(ctrl_en_c);
|
||||
data_o(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c);
|
||||
data_o(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c);
|
||||
data_o(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c);
|
||||
data_o(ctrl_mack_c) <= ctrl(ctrl_mack_c);
|
||||
--
|
||||
data_o(ctrl_ack_c) <= not rtx_sreg(0);
|
||||
data_o(ctrl_busy_c) <= arbiter(1) or arbiter(0);
|
||||
else -- twi_rtx_addr_c =>
|
||||
data_o(7 downto 0) <= rtx_sreg(8 downto 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
|
||||
-- Clock Generation -----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- clock generator enable --
|
||||
clkgen_en_o <= ctrl(ctrl_en_c);
|
||||
|
||||
-- twi clock select --
|
||||
twi_clk <= clkgen_i(to_integer(unsigned(ctrl(ctrl_prsc2_c downto ctrl_prsc0_c))));
|
||||
|
||||
-- generate four non-overlapping clock ticks at twi_clk/4 --
|
||||
clock_phase_gen: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (arbiter(2) = '0') or (arbiter(1 downto 0) = "00") then -- offline or idle
|
||||
twi_phase_gen <= "0001"; -- make sure to start with a new phase, bit 0,1,2,3 stepping
|
||||
elsif (twi_clk = '1') and (twi_clk_halt = '0') then -- enabled and no clock stretching detected
|
||||
twi_phase_gen <= twi_phase_gen(2 downto 0) & twi_phase_gen(3); -- rotate left
|
||||
end if;
|
||||
end if;
|
||||
end process clock_phase_gen;
|
||||
|
||||
-- TWI bus signals are set/sampled using 4 clock phases --
|
||||
twi_clk_phase(0) <= twi_phase_gen(0) and twi_clk; -- first step
|
||||
twi_clk_phase(1) <= twi_phase_gen(1) and twi_clk;
|
||||
twi_clk_phase(2) <= twi_phase_gen(2) and twi_clk;
|
||||
twi_clk_phase(3) <= twi_phase_gen(3) and twi_clk; -- last step
|
||||
|
||||
|
||||
-- TWI Transceiver ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
twi_rtx_unit: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- input synchronizer & sampler --
|
||||
twi_sda_in_ff <= twi_sda_in_ff(0) & twi_sda_in;
|
||||
twi_scl_in_ff <= twi_scl_in_ff(0) & twi_scl_in;
|
||||
|
||||
-- defaults --
|
||||
irq_o <= '0';
|
||||
|
||||
-- serial engine --
|
||||
arbiter(2) <= ctrl(ctrl_en_c); -- still activated?
|
||||
case arbiter is
|
||||
|
||||
when "100" => -- IDLE: waiting for requests, bus might be still claimed by this controller if no STOP condition was generated
|
||||
bitcnt <= (others => '0');
|
||||
if (wren = '1') then
|
||||
if (addr = twi_ctrl_addr_c) then
|
||||
if (data_i(ctrl_start_c) = '1') then -- issue START condition
|
||||
arbiter(1 downto 0) <= "01";
|
||||
elsif (data_i(ctrl_stop_c) = '1') then -- issue STOP condition
|
||||
arbiter(1 downto 0) <= "10";
|
||||
end if;
|
||||
elsif (addr = twi_rtx_addr_c) then -- start a data transmission
|
||||
-- one bit extra for ack, issued by controller if ctrl_mack_c is set,
|
||||
-- sampled from peripheral if ctrl_mack_c is cleared
|
||||
rtx_sreg <= data_i(7 downto 0) & (not ctrl(ctrl_mack_c));
|
||||
arbiter(1 downto 0) <= "11";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when "101" => -- START: generate START condition
|
||||
if (twi_clk_phase(0) = '1') then
|
||||
twi_sda_out <= '1';
|
||||
elsif (twi_clk_phase(1) = '1') then
|
||||
twi_sda_out <= '0';
|
||||
end if;
|
||||
--
|
||||
if (twi_clk_phase(0) = '1') then
|
||||
twi_scl_out <= '1';
|
||||
elsif (twi_clk_phase(3) = '1') then
|
||||
twi_scl_out <= '0';
|
||||
irq_o <= '1'; -- Interrupt!
|
||||
arbiter(1 downto 0) <= "00"; -- go back to IDLE
|
||||
end if;
|
||||
|
||||
when "110" => -- STOP: generate STOP condition
|
||||
if (twi_clk_phase(0) = '1') then
|
||||
twi_sda_out <= '0';
|
||||
elsif (twi_clk_phase(3) = '1') then
|
||||
twi_sda_out <= '1';
|
||||
irq_o <= '1'; -- Interrupt!
|
||||
arbiter(1 downto 0) <= "00"; -- go back to IDLE
|
||||
end if;
|
||||
--
|
||||
if (twi_clk_phase(0) = '1') then
|
||||
twi_scl_out <= '0';
|
||||
elsif (twi_clk_phase(1) = '1') then
|
||||
twi_scl_out <= '1';
|
||||
end if;
|
||||
|
||||
when "111" => -- TRANSMISSION: transmission in progress
|
||||
if (twi_clk_phase(0) = '1') then
|
||||
bitcnt <= std_ulogic_vector(unsigned(bitcnt) + 1);
|
||||
twi_scl_out <= '0';
|
||||
twi_sda_out <= rtx_sreg(8); -- MSB first
|
||||
elsif (twi_clk_phase(1) = '1') then -- first half + second half of valid data strobe
|
||||
twi_scl_out <= '1';
|
||||
elsif (twi_clk_phase(3) = '1') then
|
||||
rtx_sreg <= rtx_sreg(7 downto 0) & twi_sda_in_ff(twi_sda_in_ff'left); -- sample and shift left
|
||||
twi_scl_out <= '0';
|
||||
end if;
|
||||
--
|
||||
if (bitcnt = "1010") then -- 8 data bits + 1 bit for ACK + 1 tick delay
|
||||
irq_o <= '1'; -- Interrupt!
|
||||
arbiter(1 downto 0) <= "00"; -- go back to IDLE
|
||||
end if;
|
||||
|
||||
when others => -- "0--" OFFLINE: TWI deactivated
|
||||
twi_sda_out <= '1';
|
||||
twi_scl_out <= '1';
|
||||
arbiter(1 downto 0) <= "00"; -- stay here, go to idle when activated
|
||||
|
||||
end case;
|
||||
end if;
|
||||
end process twi_rtx_unit;
|
||||
|
||||
|
||||
-- Clock Stretching Detector --------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- controller wants to pull SCL high, but SCL is pulled low by peripheral --
|
||||
twi_clk_halt <= '1' when (twi_scl_out = '1') and (twi_scl_in_ff(twi_scl_in_ff'left) = '0') else '0';
|
||||
|
||||
|
||||
-- Tri-State Driver -----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- SDA and SCL need to be of type std_logic to be correctly resolved in simulation
|
||||
twi_sda_io <= '0' when (twi_sda_out = '0') else 'Z';
|
||||
twi_scl_io <= '0' when (twi_scl_out = '0') else 'Z';
|
||||
|
||||
-- read-back --
|
||||
twi_sda_in <= std_ulogic(twi_sda_io);
|
||||
twi_scl_in <= std_ulogic(twi_scl_io);
|
||||
|
||||
|
||||
end neorv32_twi_rtl;
|
648
Libs/RiscV/NEORV32/rtl/core/neorv32_uart.vhd
Normal file
648
Libs/RiscV/NEORV32/rtl/core/neorv32_uart.vhd
Normal file
@ -0,0 +1,648 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Universal Asynchronous Receiver and Transmitter (UART0/1) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Frame configuration: 1 start bit, 8 bit data, parity bit (none/even/odd), 1 stop bit, #
|
||||
-- # programmable BAUD rate via clock pre-scaler and 12-bit BAUD value configuration register, #
|
||||
-- # optional configurable RX and TX FIFOs. #
|
||||
-- # #
|
||||
-- # Interrupts: Configurable RX and TX interrupt (both triggered by specific FIFO fill-levels) #
|
||||
-- # #
|
||||
-- # Support for RTS("RTR")/CTS hardware flow control: #
|
||||
-- # * uart_rts_o = 0: RX is ready to receive a new char, enabled via CTRL.ctrl_rts_en_c #
|
||||
-- # * uart_cts_i = 0: TX is allowed to send a new char, enabled via CTRL.ctrl_cts_en_c #
|
||||
-- # #
|
||||
-- # UART0 / UART1: #
|
||||
-- # This module is used for implementing UART0 and UART1. The UART_PRIMARY generic configures the #
|
||||
-- # interface register addresses and simulation outputs for UART0 (UART_PRIMARY = true) or UART1 #
|
||||
-- # (UART_PRIMARY = false). #
|
||||
-- # #
|
||||
-- # SIMULATION MODE: #
|
||||
-- # When the simulation mode is enabled (setting the ctrl.ctrl_sim_en_c bit) any write #
|
||||
-- # access to the TX register will not trigger any UART activity. Instead, the written data is #
|
||||
-- # output to the simulation environment. The lowest 8 bits of the written data are printed as #
|
||||
-- # ASCII char to the simulator console. #
|
||||
-- # This char is also stored to the file "neorv32.uartX.sim_mode.text.out" (where X = 0 for UART0 #
|
||||
-- # and X = 1 for UART1). The full 32-bit write data is also stored as 8-digit hexadecimal value #
|
||||
-- # to the file "neorv32.uartX.sim_mode.data.out" (where X = 0 for UART0 and X = 1 for UART1). #
|
||||
-- # No interrupts are triggered when in SIMULATION MODE. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
use std.textio.all;
|
||||
|
||||
entity neorv32_uart is
|
||||
generic (
|
||||
UART_PRIMARY : boolean; -- true = primary UART (UART0), false = secondary UART (UART1)
|
||||
UART_RX_FIFO : natural; -- RX fifo depth, has to be a power of two, min 1
|
||||
UART_TX_FIFO : natural -- TX fifo depth, has to be a power of two, min 1
|
||||
);
|
||||
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);
|
||||
-- com lines --
|
||||
uart_txd_o : out std_ulogic;
|
||||
uart_rxd_i : in std_ulogic;
|
||||
-- hardware flow control --
|
||||
uart_rts_o : out std_ulogic; -- UART.RX ready to receive ("RTR"), low-active, optional
|
||||
uart_cts_i : in std_ulogic; -- UART.TX allowed to transmit, low-active, optional
|
||||
-- interrupts --
|
||||
irq_rxd_o : out std_ulogic; -- uart data received interrupt
|
||||
irq_txd_o : out std_ulogic -- uart transmission done interrupt
|
||||
);
|
||||
end neorv32_uart;
|
||||
|
||||
architecture neorv32_uart_rtl of neorv32_uart is
|
||||
|
||||
-- interface configuration for UART0 / UART1 --
|
||||
constant uart_id_base_c : std_ulogic_vector(data_width_c-1 downto 0) := cond_sel_stdulogicvector_f(UART_PRIMARY, uart0_base_c, uart1_base_c);
|
||||
constant uart_id_size_c : natural := cond_sel_natural_f( UART_PRIMARY, uart0_size_c, uart1_size_c);
|
||||
constant uart_id_ctrl_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := cond_sel_stdulogicvector_f(UART_PRIMARY, uart0_ctrl_addr_c, uart1_ctrl_addr_c);
|
||||
constant uart_id_rtx_addr_c : std_ulogic_vector(data_width_c-1 downto 0) := cond_sel_stdulogicvector_f(UART_PRIMARY, uart0_rtx_addr_c, uart1_rtx_addr_c);
|
||||
|
||||
-- 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(uart_id_size_c); -- low address boundary bit
|
||||
|
||||
-- simulation output configuration --
|
||||
constant sim_screen_output_en_c : boolean := true; -- output lowest byte as char to simulator console when enabled
|
||||
constant sim_text_output_en_c : boolean := true; -- output lowest byte as char to text file when enabled
|
||||
constant sim_data_output_en_c : boolean := true; -- dump 32-bit TX word to file when enabled
|
||||
constant sim_uart_text_file_c : string := cond_sel_string_f(UART_PRIMARY, "neorv32.uart0.sim_mode.text.out", "neorv32.uart1.sim_mode.text.out");
|
||||
constant sim_uart_data_file_c : string := cond_sel_string_f(UART_PRIMARY, "neorv32.uart0.sim_mode.data.out", "neorv32.uart1.sim_mode.data.out");
|
||||
|
||||
-- control register --
|
||||
signal ctrl : std_ulogic_vector(31 downto 0);
|
||||
|
||||
-- control register bits --
|
||||
constant ctrl_baud00_c : natural := 0; -- r/w: baud config bit 0
|
||||
constant ctrl_baud01_c : natural := 1; -- r/w: baud config bit 1
|
||||
constant ctrl_baud02_c : natural := 2; -- r/w: baud config bit 2
|
||||
constant ctrl_baud03_c : natural := 3; -- r/w: baud config bit 3
|
||||
constant ctrl_baud04_c : natural := 4; -- r/w: baud config bit 4
|
||||
constant ctrl_baud05_c : natural := 5; -- r/w: baud config bit 5
|
||||
constant ctrl_baud06_c : natural := 6; -- r/w: baud config bit 6
|
||||
constant ctrl_baud07_c : natural := 7; -- r/w: baud config bit 7
|
||||
constant ctrl_baud08_c : natural := 8; -- r/w: baud config bit 8
|
||||
constant ctrl_baud09_c : natural := 9; -- r/w: baud config bit 9
|
||||
constant ctrl_baud10_c : natural := 10; -- r/w: baud config bit 10
|
||||
constant ctrl_baud11_c : natural := 11; -- r/w: baud config bit 11
|
||||
constant ctrl_sim_en_c : natural := 12; -- r/w: UART <<SIMULATION MODE>> enable
|
||||
constant ctrl_rx_empty_c : natural := 13; -- r/-: RX FIFO is empty
|
||||
constant ctrl_rx_half_c : natural := 14; -- r/-: RX FIFO is at least half-full
|
||||
constant ctrl_rx_full_c : natural := 15; -- r/-: RX FIFO is full
|
||||
constant ctrl_tx_empty_c : natural := 16; -- r/-: TX FIFO is empty
|
||||
constant ctrl_tx_half_c : natural := 17; -- r/-: TX FIFO is at least half-full
|
||||
constant ctrl_tx_full_c : natural := 18; -- r/-: TX FIFO is full
|
||||
-- ...
|
||||
constant ctrl_rts_en_c : natural := 20; -- r/w: enable hardware flow control: assert rts_o if ready to receive
|
||||
constant ctrl_cts_en_c : natural := 21; -- r/w: enable hardware flow control: send only if cts_i is asserted
|
||||
constant ctrl_pmode0_c : natural := 22; -- r/w: Parity config (0=even; 1=odd)
|
||||
constant ctrl_pmode1_c : natural := 23; -- r/w: Enable parity bit
|
||||
constant ctrl_prsc0_c : natural := 24; -- r/w: baud prsc bit 0
|
||||
constant ctrl_prsc1_c : natural := 25; -- r/w: baud prsc bit 1
|
||||
constant ctrl_prsc2_c : natural := 26; -- r/w: baud prsc bit 2
|
||||
constant ctrl_cts_c : natural := 27; -- r/-: current state of CTS input
|
||||
constant ctrl_en_c : natural := 28; -- r/w: UART enable
|
||||
constant ctrl_rx_irq_c : natural := 29; -- r/w: RX IRQ mode: 1=FIFO at least half-full; 0=FIFO not empty
|
||||
constant ctrl_tx_irq_c : natural := 30; -- r/w: TX IRQ mode: 1=FIFO less than half-full; 0=FIFO not full
|
||||
constant ctrl_tx_busy_c : natural := 31; -- r/-: UART transmitter is busy
|
||||
|
||||
-- data register flags --
|
||||
constant data_lsb_c : natural := 0; -- r/-: received char LSB
|
||||
constant data_msb_c : natural := 7; -- r/-: received char MSB
|
||||
-- ...
|
||||
constant data_rx_perr_c : natural := 28; -- r/-: RX parity error
|
||||
constant data_rx_ferr_c : natural := 29; -- r/-: RX frame error
|
||||
constant data_rx_overr_c : natural := 30; -- r/-: RX data overrun
|
||||
constant data_rx_avail_c : natural := 31; -- r/-: RX data available
|
||||
|
||||
-- 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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- clock generator --
|
||||
signal uart_clk : std_ulogic;
|
||||
|
||||
-- numbers of bits in transmission frame --
|
||||
signal num_bits : std_ulogic_vector(3 downto 0);
|
||||
|
||||
-- hardware flow-control IO buffer --
|
||||
signal uart_cts_ff : std_ulogic_vector(1 downto 0);
|
||||
signal uart_rts : std_ulogic;
|
||||
|
||||
-- UART transmitter --
|
||||
type tx_state_t is (S_TX_IDLE, S_TX_GET, S_TX_CHECK, S_TX_TRANSMIT, S_TX_SIM);
|
||||
type tx_engine_t is record
|
||||
state : tx_state_t;
|
||||
busy : std_ulogic;
|
||||
done : std_ulogic;
|
||||
bitcnt : std_ulogic_vector(03 downto 0);
|
||||
sreg : std_ulogic_vector(10 downto 0);
|
||||
baud_cnt : std_ulogic_vector(11 downto 0);
|
||||
cts : std_ulogic; -- allow new transmission when 1
|
||||
end record;
|
||||
signal tx_engine : tx_engine_t;
|
||||
|
||||
-- UART receiver --
|
||||
type rx_state_t is (S_RX_IDLE, S_RX_RECEIVE);
|
||||
type rx_engine_t is record
|
||||
state : rx_state_t;
|
||||
done : std_ulogic;
|
||||
sync : std_ulogic_vector(04 downto 0);
|
||||
bitcnt : std_ulogic_vector(03 downto 0);
|
||||
sreg : std_ulogic_vector(09 downto 0);
|
||||
baud_cnt : std_ulogic_vector(11 downto 0);
|
||||
overr : std_ulogic;
|
||||
rtr : std_ulogic; -- ready to receive when 1
|
||||
end record;
|
||||
signal rx_engine : rx_engine_t;
|
||||
|
||||
-- TX FIFO --
|
||||
type tx_buffer_t is record
|
||||
we : std_ulogic; -- write enable
|
||||
re : std_ulogic; -- read enable
|
||||
clear : std_ulogic; -- sync reset, high-active
|
||||
wdata : std_ulogic_vector(31 downto 0); -- write data
|
||||
rdata : std_ulogic_vector(31 downto 0); -- read data
|
||||
avail : std_ulogic; -- data available?
|
||||
free : std_ulogic; -- free entry available?
|
||||
half : std_ulogic; -- half full
|
||||
end record;
|
||||
signal tx_buffer : tx_buffer_t;
|
||||
|
||||
-- RX FIFO --
|
||||
type rx_buffer_t is record
|
||||
we : std_ulogic; -- write enable
|
||||
re : std_ulogic; -- read enable
|
||||
clear : std_ulogic; -- sync reset, high-active
|
||||
wdata : std_ulogic_vector(9 downto 0); -- write data
|
||||
rdata : std_ulogic_vector(9 downto 0); -- read data
|
||||
avail : std_ulogic; -- data available?
|
||||
free : std_ulogic; -- free entry available?
|
||||
half : std_ulogic; -- half full
|
||||
end record;
|
||||
signal rx_buffer : rx_buffer_t;
|
||||
|
||||
-- interrupt generator --
|
||||
type irq_t is record
|
||||
set : std_ulogic;
|
||||
buf : std_ulogic_vector(1 downto 0);
|
||||
end record;
|
||||
signal rx_irq, tx_irq : irq_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (is_power_of_two_f(UART_RX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: UART" &
|
||||
cond_sel_string_f(UART_PRIMARY, "0", "1") & " <UART_RX_FIFO> has to be a power of two." severity error;
|
||||
assert not (is_power_of_two_f(UART_TX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: UART" &
|
||||
cond_sel_string_f(UART_PRIMARY, "0", "1") & " <UART_TX_FIFO> has to be a power of two." severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = uart_id_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= uart_id_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
|
||||
-- bus access acknowledge --
|
||||
ack_o <= wren or rden;
|
||||
|
||||
-- write access --
|
||||
if (wren = '1') then
|
||||
if (addr = uart_id_ctrl_addr_c) then
|
||||
ctrl <= (others => '0');
|
||||
ctrl(ctrl_baud11_c downto ctrl_baud00_c) <= data_i(ctrl_baud11_c downto ctrl_baud00_c);
|
||||
ctrl(ctrl_sim_en_c) <= data_i(ctrl_sim_en_c);
|
||||
ctrl(ctrl_pmode1_c downto ctrl_pmode0_c) <= data_i(ctrl_pmode1_c downto ctrl_pmode0_c);
|
||||
ctrl(ctrl_prsc2_c downto ctrl_prsc0_c) <= data_i(ctrl_prsc2_c downto ctrl_prsc0_c);
|
||||
ctrl(ctrl_rts_en_c) <= data_i(ctrl_rts_en_c);
|
||||
ctrl(ctrl_cts_en_c) <= data_i(ctrl_cts_en_c);
|
||||
ctrl(ctrl_rx_irq_c) <= data_i(ctrl_rx_irq_c);
|
||||
ctrl(ctrl_tx_irq_c) <= data_i(ctrl_tx_irq_c);
|
||||
ctrl(ctrl_en_c) <= data_i(ctrl_en_c);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
if (addr = uart_id_ctrl_addr_c) then
|
||||
data_o(ctrl_baud11_c downto ctrl_baud00_c) <= ctrl(ctrl_baud11_c downto ctrl_baud00_c);
|
||||
data_o(ctrl_sim_en_c) <= ctrl(ctrl_sim_en_c);
|
||||
data_o(ctrl_pmode1_c downto ctrl_pmode0_c) <= ctrl(ctrl_pmode1_c downto ctrl_pmode0_c);
|
||||
data_o(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl(ctrl_prsc2_c downto ctrl_prsc0_c);
|
||||
data_o(ctrl_rts_en_c) <= ctrl(ctrl_rts_en_c);
|
||||
data_o(ctrl_cts_en_c) <= ctrl(ctrl_cts_en_c);
|
||||
data_o(ctrl_rx_empty_c) <= not rx_buffer.avail;
|
||||
data_o(ctrl_rx_half_c) <= rx_buffer.half;
|
||||
data_o(ctrl_rx_full_c) <= not rx_buffer.free;
|
||||
data_o(ctrl_tx_empty_c) <= not tx_buffer.avail;
|
||||
data_o(ctrl_tx_half_c) <= tx_buffer.half;
|
||||
data_o(ctrl_tx_full_c) <= not tx_buffer.free;
|
||||
data_o(ctrl_en_c) <= ctrl(ctrl_en_c);
|
||||
data_o(ctrl_rx_irq_c) <= ctrl(ctrl_rx_irq_c) and bool_to_ulogic_f(boolean(UART_RX_FIFO > 1)); -- tie to zero if UART_RX_FIFO = 1
|
||||
data_o(ctrl_tx_irq_c) <= ctrl(ctrl_tx_irq_c) and bool_to_ulogic_f(boolean(UART_TX_FIFO > 1)); -- tie to zero if UART_TX_FIFO = 1
|
||||
data_o(ctrl_tx_busy_c) <= tx_engine.busy;
|
||||
data_o(ctrl_cts_c) <= uart_cts_ff(1);
|
||||
else -- uart_id_rtx_addr_c
|
||||
data_o(data_msb_c downto data_lsb_c) <= rx_buffer.rdata(7 downto 0);
|
||||
data_o(data_rx_perr_c) <= rx_buffer.rdata(8);
|
||||
data_o(data_rx_ferr_c) <= rx_buffer.rdata(9);
|
||||
data_o(data_rx_overr_c) <= rx_engine.overr;
|
||||
data_o(data_rx_avail_c) <= rx_buffer.avail; -- data available (valid?)
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
-- number of bits to be sampled --
|
||||
-- if parity flag is ENABLED: 11 bit -> "1011" (1 start bit + 8 data bits + 1 parity bit + 1 stop bit)
|
||||
-- if parity flag is DISABLED: 10 bit -> "1010" (1 start bit + 8 data bits + 1 stop bit)
|
||||
num_bits <= "1011" when (ctrl(ctrl_pmode1_c) = '1') else "1010";
|
||||
|
||||
|
||||
-- Clock Selection ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- clock enable --
|
||||
clkgen_en_o <= ctrl(ctrl_en_c);
|
||||
|
||||
-- uart clock select --
|
||||
uart_clk <= clkgen_i(to_integer(unsigned(ctrl(ctrl_prsc2_c downto ctrl_prsc0_c))));
|
||||
|
||||
|
||||
-- TX FIFO --------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
tx_engine_fifo_inst: neorv32_fifo
|
||||
generic map (
|
||||
FIFO_DEPTH => UART_TX_FIFO, -- number of fifo entries; has to be a power of two; min 1
|
||||
FIFO_WIDTH => 32, -- size of data elements in fifo (32-bit only for simulation)
|
||||
FIFO_RSYNC => false, -- async read
|
||||
FIFO_SAFE => true -- safe access
|
||||
)
|
||||
port map (
|
||||
-- control --
|
||||
clk_i => clk_i, -- clock, rising edge
|
||||
rstn_i => '1', -- async reset, low-active
|
||||
clear_i => tx_buffer.clear, -- sync reset, high-active
|
||||
level_o => open,
|
||||
half_o => tx_buffer.half, -- FIFO at least half-full
|
||||
-- write port --
|
||||
wdata_i => tx_buffer.wdata, -- write data
|
||||
we_i => tx_buffer.we, -- write enable
|
||||
free_o => tx_buffer.free, -- at least one entry is free when set
|
||||
-- read port --
|
||||
re_i => tx_buffer.re, -- read enable
|
||||
rdata_o => tx_buffer.rdata, -- read data
|
||||
avail_o => tx_buffer.avail -- data available when set
|
||||
);
|
||||
|
||||
-- control --
|
||||
tx_buffer.clear <= not ctrl(ctrl_en_c);
|
||||
|
||||
-- write access --
|
||||
tx_buffer.we <= '1' when (wren = '1') and (addr = uart_id_rtx_addr_c) else '0';
|
||||
tx_buffer.wdata <= data_i;
|
||||
|
||||
|
||||
-- UART Transmitter Engine ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
uart_tx_engine: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- defaults --
|
||||
uart_txd_o <= '1'; -- keep TX line idle (=high) if waiting for permission to start sending (->CTS)
|
||||
tx_buffer.re <= '0';
|
||||
tx_engine.done <= '0';
|
||||
|
||||
-- FSM --
|
||||
if (ctrl(ctrl_en_c) = '0') then -- disabled
|
||||
tx_engine.state <= S_TX_IDLE;
|
||||
else
|
||||
case tx_engine.state is
|
||||
|
||||
when S_TX_IDLE => -- wait for new data to send
|
||||
-- ------------------------------------------------------------
|
||||
if (tx_buffer.avail = '1') then -- new data available
|
||||
if (ctrl(ctrl_sim_en_c) = '0') then -- normal mode
|
||||
tx_engine.state <= S_TX_GET;
|
||||
else -- simulation mode
|
||||
tx_engine.state <= S_TX_SIM;
|
||||
end if;
|
||||
tx_buffer.re <= '1';
|
||||
end if;
|
||||
|
||||
when S_TX_GET => -- get new data from buffer and prepare transmission
|
||||
-- ------------------------------------------------------------
|
||||
tx_engine.baud_cnt <= ctrl(ctrl_baud11_c downto ctrl_baud00_c);
|
||||
tx_engine.bitcnt <= num_bits;
|
||||
if (ctrl(ctrl_pmode1_c) = '1') then -- add parity flag
|
||||
-- stop bit & parity bit & data (8-bit) & start bit
|
||||
tx_engine.sreg <= '1' & (xor_reduce_f(tx_buffer.rdata(7 downto 0)) xor ctrl(ctrl_pmode0_c)) & tx_buffer.rdata(7 downto 0) & '0';
|
||||
else
|
||||
-- (dummy fill-bit &) stop bit & data (8-bit) & start bit
|
||||
tx_engine.sreg <= '1' & '1' & tx_buffer.rdata(7 downto 0) & '0';
|
||||
end if;
|
||||
tx_engine.state <= S_TX_CHECK;
|
||||
|
||||
when S_TX_CHECK => -- check if allowed to send
|
||||
-- ------------------------------------------------------------
|
||||
if (tx_engine.cts = '1') then -- clear to send
|
||||
tx_engine.state <= S_TX_TRANSMIT;
|
||||
end if;
|
||||
|
||||
when S_TX_TRANSMIT => -- transmit data
|
||||
-- ------------------------------------------------------------
|
||||
if (uart_clk = '1') then
|
||||
if (or_reduce_f(tx_engine.baud_cnt) = '0') then -- bit done?
|
||||
tx_engine.baud_cnt <= ctrl(ctrl_baud11_c downto ctrl_baud00_c);
|
||||
tx_engine.bitcnt <= std_ulogic_vector(unsigned(tx_engine.bitcnt) - 1);
|
||||
tx_engine.sreg <= '1' & tx_engine.sreg(tx_engine.sreg'left downto 1);
|
||||
else
|
||||
tx_engine.baud_cnt <= std_ulogic_vector(unsigned(tx_engine.baud_cnt) - 1);
|
||||
end if;
|
||||
end if;
|
||||
uart_txd_o <= tx_engine.sreg(0);
|
||||
if (or_reduce_f(tx_engine.bitcnt) = '0') then -- all bits send?
|
||||
tx_engine.done <= '1'; -- sending done
|
||||
tx_engine.state <= S_TX_IDLE;
|
||||
end if;
|
||||
|
||||
when S_TX_SIM => -- simulation mode output
|
||||
-- ------------------------------------------------------------
|
||||
tx_engine.state <= S_TX_IDLE;
|
||||
|
||||
when others => -- undefined
|
||||
-- ------------------------------------------------------------
|
||||
tx_engine.state <= S_TX_IDLE;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process uart_tx_engine;
|
||||
|
||||
-- transmitter busy --
|
||||
tx_engine.busy <= '0' when (tx_engine.state = S_TX_IDLE) else '1';
|
||||
|
||||
|
||||
-- UART Receiver Engine -------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
uart_rx_engine: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- input synchronizer --
|
||||
rx_engine.sync <= uart_rxd_i & rx_engine.sync(rx_engine.sync'left downto 1);
|
||||
|
||||
-- default --
|
||||
rx_engine.done <= '0';
|
||||
|
||||
-- FSM --
|
||||
if (ctrl(ctrl_en_c) = '0') then -- disabled
|
||||
rx_engine.overr <= '0';
|
||||
rx_engine.state <= S_RX_IDLE;
|
||||
else
|
||||
case rx_engine.state is
|
||||
|
||||
when S_RX_IDLE => -- idle; prepare receive
|
||||
-- ------------------------------------------------------------
|
||||
rx_engine.baud_cnt <= '0' & ctrl(ctrl_baud11_c downto ctrl_baud01_c); -- half baud delay at the beginning to sample in the middle of each bit
|
||||
rx_engine.bitcnt <= num_bits;
|
||||
if (rx_engine.sync(3 downto 0) = "0011") then -- start bit? (falling edge)
|
||||
rx_engine.state <= S_RX_RECEIVE;
|
||||
end if;
|
||||
|
||||
when S_RX_RECEIVE => -- receive data
|
||||
-- ------------------------------------------------------------
|
||||
if (uart_clk = '1') then
|
||||
if (or_reduce_f(rx_engine.baud_cnt) = '0') then -- bit done
|
||||
rx_engine.baud_cnt <= ctrl(ctrl_baud11_c downto ctrl_baud00_c);
|
||||
rx_engine.bitcnt <= std_ulogic_vector(unsigned(rx_engine.bitcnt) - 1);
|
||||
rx_engine.sreg <= rx_engine.sync(2) & rx_engine.sreg(rx_engine.sreg'left downto 1);
|
||||
else
|
||||
rx_engine.baud_cnt <= std_ulogic_vector(unsigned(rx_engine.baud_cnt) - 1);
|
||||
end if;
|
||||
end if;
|
||||
if (or_reduce_f(rx_engine.bitcnt) = '0') then -- all bits received?
|
||||
rx_engine.done <= '1'; -- receiving done
|
||||
rx_engine.state <= S_RX_IDLE;
|
||||
end if;
|
||||
|
||||
when others => -- undefined
|
||||
-- ------------------------------------------------------------
|
||||
rx_engine.state <= S_RX_IDLE;
|
||||
|
||||
end case;
|
||||
|
||||
-- overrun flag --
|
||||
if (rden = '1') and (addr = uart_id_rtx_addr_c) then -- clear when reading data register
|
||||
rx_engine.overr <= '0';
|
||||
elsif (rx_buffer.we = '1') and (rx_buffer.free = '0') then -- write to full FIFO
|
||||
rx_engine.overr <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process uart_rx_engine;
|
||||
|
||||
-- RX engine ready for a new char? --
|
||||
rx_engine.rtr <= '1' when (rx_engine.state = S_RX_IDLE) and (ctrl(ctrl_en_c) = '1') else '0';
|
||||
|
||||
|
||||
-- RX FIFO --------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
rx_engine_fifo_inst: neorv32_fifo
|
||||
generic map (
|
||||
FIFO_DEPTH => UART_RX_FIFO, -- number of fifo entries; has to be a power of two; min 1
|
||||
FIFO_WIDTH => 10, -- size of data elements in fifo
|
||||
FIFO_RSYNC => false, -- async read
|
||||
FIFO_SAFE => true -- safe access
|
||||
)
|
||||
port map (
|
||||
-- control --
|
||||
clk_i => clk_i, -- clock, rising edge
|
||||
rstn_i => '1', -- async reset, low-active
|
||||
clear_i => rx_buffer.clear, -- sync reset, high-active
|
||||
level_o => open,
|
||||
half_o => rx_buffer.half, -- FIFO at least half-full
|
||||
-- write port --
|
||||
wdata_i => rx_buffer.wdata, -- write data
|
||||
we_i => rx_buffer.we, -- write enable
|
||||
free_o => rx_buffer.free, -- at least one entry is free when set
|
||||
-- read port --
|
||||
re_i => rx_buffer.re, -- read enable
|
||||
rdata_o => rx_buffer.rdata, -- read data
|
||||
avail_o => rx_buffer.avail -- data available when set
|
||||
);
|
||||
|
||||
-- control --
|
||||
rx_buffer.clear <= not ctrl(ctrl_en_c);
|
||||
|
||||
-- read/write access --
|
||||
rx_buffer.wdata(7 downto 0) <= rx_engine.sreg(7 downto 0) when (ctrl(ctrl_pmode1_c) = '1') else rx_engine.sreg(8 downto 1); -- RX data
|
||||
rx_buffer.wdata(8) <= ctrl(ctrl_pmode1_c) and (xor_reduce_f(rx_engine.sreg(8 downto 0)) xor ctrl(ctrl_pmode0_c)); -- parity error flag
|
||||
rx_buffer.wdata(9) <= not rx_engine.sreg(9); -- frame error flag: check stop bit (error if not set)
|
||||
rx_buffer.we <= '1' when (rx_engine.bitcnt = "0000") and (rx_engine.state = S_RX_RECEIVE) else '0'; -- RX complete
|
||||
rx_buffer.re <= '1' when (rden = '1') and (addr = uart_id_rtx_addr_c) else '0';
|
||||
|
||||
|
||||
-- Hardware Flow Control ------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
tx_engine.cts <= (not uart_cts_ff(1)) when (ctrl(ctrl_cts_en_c) = '1') else '1'; -- input is low-active, internal signal is high-active
|
||||
uart_rts <= (not rx_engine.rtr) when (ctrl(ctrl_rts_en_c) = '1') else '0'; -- output is low-active
|
||||
|
||||
-- flow-control input/output synchronizer --
|
||||
flow_control_buffer: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then -- should be mapped to IOBs
|
||||
uart_cts_ff <= uart_cts_ff(0) & uart_cts_i;
|
||||
uart_rts_o <= uart_rts;
|
||||
end if;
|
||||
end process flow_control_buffer;
|
||||
|
||||
|
||||
-- Interrupt Generator --------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
irq_type: process(ctrl, tx_buffer, rx_buffer, tx_engine.done)
|
||||
begin
|
||||
-- TX interrupt --
|
||||
if (UART_TX_FIFO = 1) or (ctrl(ctrl_tx_irq_c) = '0') then
|
||||
tx_irq.set <= tx_buffer.free and tx_engine.done; -- fire IRQ if FIFO is not full
|
||||
else
|
||||
tx_irq.set <= (not tx_buffer.half) and tx_engine.done; -- fire IRQ if FIFO is less than half-full
|
||||
end if;
|
||||
-- RX interrupt --
|
||||
if (UART_RX_FIFO = 1) or (ctrl(ctrl_rx_irq_c) = '0') then
|
||||
rx_irq.set <= rx_buffer.avail; -- fire IRQ if FIFO is not empty
|
||||
else
|
||||
rx_irq.set <= rx_buffer.half; -- fire IRQ if FIFO is at least half-full
|
||||
end if;
|
||||
end process irq_type;
|
||||
|
||||
-- interrupt edge detector --
|
||||
irq_detect: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (ctrl(ctrl_en_c) = '0') then
|
||||
tx_irq.buf <= "00";
|
||||
rx_irq.buf <= "00";
|
||||
else
|
||||
tx_irq.buf <= tx_irq.buf(0) & tx_irq.set;
|
||||
rx_irq.buf <= rx_irq.buf(0) & rx_irq.set;
|
||||
end if;
|
||||
end if;
|
||||
end process irq_detect;
|
||||
|
||||
-- IRQ requests to CPU --
|
||||
irq_txd_o <= '1' when (tx_irq.buf = "01") else '0';
|
||||
irq_rxd_o <= '1' when (rx_irq.buf = "01") else '0';
|
||||
|
||||
|
||||
-- SIMULATION Transmitter -----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- pragma translate_off
|
||||
-- synthesis translate_off
|
||||
-- RTL_SYNTHESIS OFF
|
||||
sim_output: process(clk_i) -- for SIMULATION ONLY!
|
||||
file file_uart_text_out : text open write_mode is sim_uart_text_file_c;
|
||||
file file_uart_data_out : text open write_mode is sim_uart_data_file_c;
|
||||
variable char_v : integer;
|
||||
variable line_screen_v : line; -- we need several line variables here since "writeline" seems to flush the source variable
|
||||
variable line_text_v : line;
|
||||
variable line_data_v : line;
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (tx_engine.state = S_TX_SIM) then -- UART simulation mode
|
||||
|
||||
-- print lowest byte as ASCII char --
|
||||
char_v := to_integer(unsigned(tx_buffer.rdata(7 downto 0)));
|
||||
if (char_v >= 128) then -- out of range?
|
||||
char_v := 0;
|
||||
end if;
|
||||
|
||||
if (char_v /= 10) and (char_v /= 13) then -- skip line breaks - they are issued via "writeline"
|
||||
if (sim_screen_output_en_c = true) then
|
||||
write(line_screen_v, character'val(char_v));
|
||||
end if;
|
||||
if (sim_text_output_en_c = true) then
|
||||
write(line_text_v, character'val(char_v));
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if (char_v = 10) then -- line break: write to screen and text file
|
||||
if (sim_screen_output_en_c = true) then
|
||||
writeline(output, line_screen_v);
|
||||
end if;
|
||||
if (sim_text_output_en_c = true) then
|
||||
writeline(file_uart_text_out, line_text_v);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- dump raw data as 8 hex chars to file --
|
||||
if (sim_data_output_en_c = true) then
|
||||
for x in 7 downto 0 loop
|
||||
write(line_data_v, to_hexchar_f(tx_buffer.rdata(3+x*4 downto 0+x*4))); -- write in hex form
|
||||
end loop; -- x
|
||||
writeline(file_uart_data_out, line_data_v);
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process sim_output;
|
||||
-- RTL_SYNTHESIS ON
|
||||
-- synthesis translate_on
|
||||
-- pragma translate_on
|
||||
|
||||
end neorv32_uart_rtl;
|
244
Libs/RiscV/NEORV32/rtl/core/neorv32_wdt.vhd
Normal file
244
Libs/RiscV/NEORV32/rtl/core/neorv32_wdt.vhd
Normal file
@ -0,0 +1,244 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Watch Dog Timer (WDT) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Watchdog counter to trigger an action if the CPU gets stuck. #
|
||||
-- # The internal counter is 20-bit wide. If this counter overflows one of two possible actions is #
|
||||
-- # triggered: Generate an IRQ or force a hardware reset of the system. #
|
||||
-- # A WDT action can also be triggered manually at any time by setting the FORCE bit. #
|
||||
-- # #
|
||||
-- # Access to the control register can be permanently locked by setting the lock bit. This bit #
|
||||
-- # can only be cleared by a hardware reset (external or caused by the watchdog itself). #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_wdt is
|
||||
generic (
|
||||
DEBUG_EN : boolean -- CPU debug mode implemented?
|
||||
);
|
||||
port (
|
||||
-- host access --
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rstn_i : in std_ulogic; -- global reset line, low-active
|
||||
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
|
||||
-- CPU in debug mode? --
|
||||
cpu_debug_i : in std_ulogic;
|
||||
-- clock generator --
|
||||
clkgen_en_o : out std_ulogic; -- enable clock generator
|
||||
clkgen_i : in std_ulogic_vector(07 downto 0);
|
||||
-- timeout event --
|
||||
irq_o : out std_ulogic; -- timeout IRQ
|
||||
rstn_o : out std_ulogic -- timeout reset, low_active, use as async
|
||||
);
|
||||
end neorv32_wdt;
|
||||
|
||||
architecture neorv32_wdt_rtl of neorv32_wdt is
|
||||
|
||||
-- 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(wdt_size_c); -- low address boundary bit
|
||||
|
||||
-- Control register bits --
|
||||
constant ctrl_enable_c : natural := 0; -- r/w: WDT enable
|
||||
constant ctrl_clksel0_c : natural := 1; -- r/w: prescaler select bit 0
|
||||
constant ctrl_clksel1_c : natural := 2; -- r/w: prescaler select bit 1
|
||||
constant ctrl_clksel2_c : natural := 3; -- r/w: prescaler select bit 2
|
||||
constant ctrl_mode_c : natural := 4; -- r/w: 0: WDT timeout triggers interrupt, 1: WDT timeout triggers hard reset
|
||||
constant ctrl_rcause_c : natural := 5; -- r/-: cause of last action (reset/IRQ): 0=external reset, 1=watchdog overflow
|
||||
constant ctrl_reset_c : natural := 6; -- -/w: reset WDT if set
|
||||
constant ctrl_force_c : natural := 7; -- -/w: force WDT action
|
||||
constant ctrl_lock_c : natural := 8; -- r/w: lock access to control register when set
|
||||
constant ctrl_dben_c : natural := 9; -- r/w: allow WDT to continue operation even when in debug mode
|
||||
constant ctrl_half_c : natural := 10; -- r/-: set if at least half of the max. timeout counter value has been reached
|
||||
|
||||
-- access control --
|
||||
signal acc_en : std_ulogic; -- module access enable
|
||||
signal wren : std_ulogic;
|
||||
signal rden : std_ulogic;
|
||||
|
||||
-- control register --
|
||||
type ctrl_t is record
|
||||
enable : std_ulogic; -- 1=WDT enabled
|
||||
clk_sel : std_ulogic_vector(2 downto 0);
|
||||
mode : std_ulogic; -- 0=trigger IRQ on overflow; 1=trigger hard reset on overflow
|
||||
rcause : std_ulogic; -- cause of last system reset: '0' = external, '1' = watchdog
|
||||
reset : std_ulogic; -- reset WDT
|
||||
enforce : std_ulogic; -- force action
|
||||
lock : std_ulogic; -- lock control register
|
||||
dben : std_ulogic; -- allow operation also in debug mode
|
||||
end record;
|
||||
signal ctrl : ctrl_t;
|
||||
|
||||
-- prescaler clock generator --
|
||||
signal prsc_tick : std_ulogic;
|
||||
|
||||
-- WDT core --
|
||||
signal wdt_cnt : std_ulogic_vector(20 downto 0);
|
||||
signal hw_rst : std_ulogic;
|
||||
signal rst_gen : std_ulogic_vector(03 downto 0);
|
||||
signal cnt_en : std_ulogic;
|
||||
|
||||
-- internal reset (sync, low-active) --
|
||||
signal rstn_sync : std_ulogic;
|
||||
|
||||
begin
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = wdt_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
wren <= acc_en and wren_i;
|
||||
rden <= acc_en and rden_i;
|
||||
|
||||
|
||||
-- Write Access ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
write_access: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
ctrl.reset <= '1'; -- reset counter on start-up
|
||||
ctrl.enforce <= '0';
|
||||
ctrl.enable <= '0'; -- disable WDT
|
||||
ctrl.mode <= '0';
|
||||
ctrl.clk_sel <= (others => '0');
|
||||
ctrl.lock <= '0';
|
||||
ctrl.dben <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
if (rstn_sync = '0') then -- internal reset
|
||||
ctrl.reset <= '1'; -- reset counter on start-up
|
||||
ctrl.enforce <= '0';
|
||||
ctrl.enable <= '0'; -- disable WDT
|
||||
ctrl.mode <= '0';
|
||||
ctrl.clk_sel <= (others => '0');
|
||||
ctrl.lock <= '0';
|
||||
ctrl.dben <= '0';
|
||||
else
|
||||
-- auto-clear WDT reset and WDT force flags --
|
||||
ctrl.reset <= '0';
|
||||
ctrl.enforce <= '0';
|
||||
-- actual write access --
|
||||
if (wren = '1') then
|
||||
ctrl.reset <= data_i(ctrl_reset_c);
|
||||
ctrl.enforce <= data_i(ctrl_force_c);
|
||||
if (ctrl.lock = '0') then -- update configuration only if not locked
|
||||
ctrl.enable <= data_i(ctrl_enable_c);
|
||||
ctrl.mode <= data_i(ctrl_mode_c);
|
||||
ctrl.clk_sel <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c);
|
||||
ctrl.lock <= data_i(ctrl_lock_c);
|
||||
ctrl.dben <= data_i(ctrl_dben_c) and bool_to_ulogic_f(DEBUG_EN);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process write_access;
|
||||
|
||||
-- clock generator --
|
||||
clkgen_en_o <= ctrl.enable; -- enable clock generator
|
||||
prsc_tick <= clkgen_i(to_integer(unsigned(ctrl.clk_sel))); -- clock enable tick
|
||||
|
||||
|
||||
-- Watchdog Counter -----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
wdt_counter: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if (ctrl.reset = '1') then -- watchdog reset
|
||||
wdt_cnt <= (others => '0');
|
||||
elsif (cnt_en = '1') then
|
||||
wdt_cnt <= std_ulogic_vector(unsigned('0' & wdt_cnt(wdt_cnt'left-1 downto 0)) + 1);
|
||||
end if;
|
||||
end if;
|
||||
end process wdt_counter;
|
||||
|
||||
-- WDT counter enable --
|
||||
cnt_en <= ctrl.enable and prsc_tick and ((not cpu_debug_i) or ctrl.dben);
|
||||
|
||||
-- action trigger --
|
||||
irq_o <= ctrl.enable and (wdt_cnt(wdt_cnt'left) or ctrl.enforce) and (not ctrl.mode); -- mode 0: IRQ
|
||||
hw_rst <= ctrl.enable and (wdt_cnt(wdt_cnt'left) or ctrl.enforce) and ( ctrl.mode); -- mode 1: RESET
|
||||
|
||||
|
||||
-- Reset Generator & Action Cause Indicator -----------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
reset_generator: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
ctrl.rcause <= '0';
|
||||
rst_gen <= (others => '1'); -- do NOT fire on reset!
|
||||
rstn_sync <= '1';
|
||||
elsif rising_edge(clk_i) then
|
||||
ctrl.rcause <= ctrl.rcause or hw_rst; -- sticky-set on WDT timeout/force
|
||||
if (hw_rst = '1') then
|
||||
rst_gen <= (others => '0');
|
||||
else
|
||||
rst_gen <= rst_gen(rst_gen'left-1 downto 0) & '1';
|
||||
end if;
|
||||
rstn_sync <= rst_gen(rst_gen'left);
|
||||
end if;
|
||||
end process reset_generator;
|
||||
|
||||
-- system reset --
|
||||
rstn_o <= rst_gen(rst_gen'left);
|
||||
|
||||
|
||||
-- Read Access ----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
read_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
ack_o <= rden or wren;
|
||||
if (rden = '1') then
|
||||
data_o(ctrl_enable_c) <= ctrl.enable;
|
||||
data_o(ctrl_mode_c) <= ctrl.mode;
|
||||
data_o(ctrl_rcause_c) <= ctrl.rcause;
|
||||
data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_sel;
|
||||
data_o(ctrl_lock_c) <= ctrl.lock;
|
||||
data_o(ctrl_dben_c) <= ctrl.dben;
|
||||
data_o(ctrl_half_c) <= wdt_cnt(wdt_cnt'left-1);
|
||||
else
|
||||
data_o <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
end process read_access;
|
||||
|
||||
|
||||
end neorv32_wdt_rtl;
|
274
Libs/RiscV/NEORV32/rtl/core/neorv32_wishbone.vhd
Normal file
274
Libs/RiscV/NEORV32/rtl/core/neorv32_wishbone.vhd
Normal file
@ -0,0 +1,274 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - External Bus Interface (WISHBONE) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # All bus accesses from the CPU, which do not target the internal IO region / the internal #
|
||||
-- # bootloader / the internal instruction or data memories (if implemented), are delegated via #
|
||||
-- # this Wishbone gateway to the external bus interface. Accessed peripherals can have a response #
|
||||
-- # latency of up to BUS_TIMEOUT - 1 cycles. #
|
||||
-- # #
|
||||
-- # Even when all processor-internal memories and IO devices are disabled, the EXTERNAL address #
|
||||
-- # space ENDS at address 0xffff0000 (begin of internal BOOTROM address space). #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_wishbone is
|
||||
generic (
|
||||
-- Internal instruction memory --
|
||||
MEM_INT_IMEM_EN : boolean; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural; -- size of processor-internal instruction memory in bytes
|
||||
-- Internal data memory --
|
||||
MEM_INT_DMEM_EN : boolean; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural; -- size of processor-internal data memory in bytes
|
||||
-- Interface Configuration --
|
||||
BUS_TIMEOUT : natural; -- cycles after an UNACKNOWLEDGED bus access triggers a bus fault exception
|
||||
PIPE_MODE : boolean; -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode
|
||||
BIG_ENDIAN : boolean; -- byte order: true=big-endian, false=little-endian
|
||||
ASYNC_RX : boolean -- use register buffer for RX data when false
|
||||
);
|
||||
port (
|
||||
-- global control --
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
rstn_i : in std_ulogic; -- global reset line, low-active
|
||||
-- host access --
|
||||
src_i : in std_ulogic; -- access type (0: data, 1:instruction)
|
||||
addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
rden_i : in std_ulogic; -- read enable
|
||||
wren_i : in std_ulogic; -- write enable
|
||||
ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable
|
||||
data_i : in std_ulogic_vector(31 downto 0); -- data in
|
||||
data_o : out std_ulogic_vector(31 downto 0); -- data out
|
||||
lock_i : in std_ulogic; -- exclusive access request
|
||||
ack_o : out std_ulogic; -- transfer acknowledge
|
||||
err_o : out std_ulogic; -- transfer error
|
||||
tmo_o : out std_ulogic; -- transfer timeout
|
||||
priv_i : in std_ulogic_vector(01 downto 0); -- current CPU privilege level
|
||||
ext_o : out std_ulogic; -- active external access
|
||||
-- wishbone interface --
|
||||
wb_tag_o : out std_ulogic_vector(02 downto 0); -- request tag
|
||||
wb_adr_o : out std_ulogic_vector(31 downto 0); -- address
|
||||
wb_dat_i : in std_ulogic_vector(31 downto 0); -- read data
|
||||
wb_dat_o : out std_ulogic_vector(31 downto 0); -- write data
|
||||
wb_we_o : out std_ulogic; -- read/write
|
||||
wb_sel_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
||||
wb_stb_o : out std_ulogic; -- strobe
|
||||
wb_cyc_o : out std_ulogic; -- valid cycle
|
||||
wb_lock_o : out std_ulogic; -- exclusive access request
|
||||
wb_ack_i : in std_ulogic; -- transfer acknowledge
|
||||
wb_err_i : in std_ulogic -- transfer error
|
||||
);
|
||||
end neorv32_wishbone;
|
||||
|
||||
architecture neorv32_wishbone_rtl of neorv32_wishbone is
|
||||
|
||||
-- timeout enable --
|
||||
constant timeout_en_c : boolean := boolean(BUS_TIMEOUT /= 0); -- timeout enabled if BUS_TIMEOUT > 0
|
||||
|
||||
-- access control --
|
||||
signal int_imem_acc : std_ulogic;
|
||||
signal int_dmem_acc : std_ulogic;
|
||||
signal int_boot_acc : std_ulogic;
|
||||
signal xbus_access : std_ulogic;
|
||||
|
||||
-- bus arbiter
|
||||
type ctrl_state_t is (IDLE, BUSY);
|
||||
type ctrl_t is record
|
||||
state : ctrl_state_t;
|
||||
state_ff : ctrl_state_t;
|
||||
we : std_ulogic;
|
||||
adr : std_ulogic_vector(31 downto 0);
|
||||
wdat : std_ulogic_vector(31 downto 0);
|
||||
rdat : std_ulogic_vector(31 downto 0);
|
||||
sel : std_ulogic_vector(03 downto 0);
|
||||
ack : std_ulogic;
|
||||
err : std_ulogic;
|
||||
tmo : std_ulogic;
|
||||
timeout : std_ulogic_vector(index_size_f(BUS_TIMEOUT) downto 0);
|
||||
src : std_ulogic;
|
||||
lock : std_ulogic;
|
||||
priv : std_ulogic_vector(01 downto 0);
|
||||
end record;
|
||||
signal ctrl : ctrl_t;
|
||||
signal stb_int : std_ulogic;
|
||||
signal cyc_int : std_ulogic;
|
||||
signal rdata : std_ulogic_vector(31 downto 0);
|
||||
|
||||
-- async RX mode --
|
||||
signal ack_gated : std_ulogic;
|
||||
signal rdata_gated : std_ulogic_vector(31 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- protocol --
|
||||
assert not (PIPE_MODE = false) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing STANDARD Wishbone protocol." severity note;
|
||||
assert not (PIPE_MODE = true) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing PIEPLINED Wishbone protocol." severity note;
|
||||
|
||||
-- bus timeout --
|
||||
assert not (BUS_TIMEOUT /= 0) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing auto-timeout (" & integer'image(BUS_TIMEOUT) & " cycles)." severity note;
|
||||
assert not (BUS_TIMEOUT = 0) report "NEORV32 PROCESSOR CONFIG WARNING: External Bus Interface - Implementing NO auto-timeout (can cause permanent CPU stall!)." severity warning;
|
||||
|
||||
-- endianness --
|
||||
assert not (BIG_ENDIAN = false) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing LITTLE-endian byte order." severity note;
|
||||
assert not (BIG_ENDIAN = true) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing BIG-endian byte." severity note;
|
||||
|
||||
-- async RX --
|
||||
assert not (ASYNC_RX = false) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing registered RX path." severity note;
|
||||
assert not (ASYNC_RX = true) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing ASYNC RX path." severity note;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- access to processor-internal IMEM or DMEM? --
|
||||
int_imem_acc <= '1' when (addr_i(31 downto index_size_f(MEM_INT_IMEM_SIZE)) = imem_base_c(31 downto index_size_f(MEM_INT_IMEM_SIZE))) and (MEM_INT_IMEM_EN = true) else '0';
|
||||
int_dmem_acc <= '1' when (addr_i(31 downto index_size_f(MEM_INT_DMEM_SIZE)) = dmem_base_c(31 downto index_size_f(MEM_INT_DMEM_SIZE))) and (MEM_INT_DMEM_EN = true) else '0';
|
||||
-- access to processor-internal BOOTROM or IO devices? --
|
||||
int_boot_acc <= '1' when (addr_i(31 downto 16) = boot_rom_base_c(31 downto 16)) else '0'; -- hacky!
|
||||
-- actual external bus access? --
|
||||
xbus_access <= (not int_imem_acc) and (not int_dmem_acc) and (not int_boot_acc);
|
||||
|
||||
|
||||
-- Bus Arbiter -----------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
bus_arbiter: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
ctrl.state <= IDLE;
|
||||
ctrl.state_ff <= IDLE;
|
||||
ctrl.we <= def_rst_val_c;
|
||||
ctrl.adr <= (others => def_rst_val_c);
|
||||
ctrl.wdat <= (others => def_rst_val_c);
|
||||
ctrl.rdat <= (others => def_rst_val_c);
|
||||
ctrl.sel <= (others => def_rst_val_c);
|
||||
ctrl.timeout <= (others => def_rst_val_c);
|
||||
ctrl.ack <= def_rst_val_c;
|
||||
ctrl.err <= def_rst_val_c;
|
||||
ctrl.tmo <= def_rst_val_c;
|
||||
ctrl.src <= def_rst_val_c;
|
||||
ctrl.lock <= def_rst_val_c;
|
||||
ctrl.priv <= (others => def_rst_val_c);
|
||||
elsif rising_edge(clk_i) then
|
||||
-- defaults --
|
||||
ctrl.state_ff <= ctrl.state;
|
||||
ctrl.rdat <= (others => '0'); -- required for internal output gating
|
||||
ctrl.ack <= '0';
|
||||
ctrl.err <= '0';
|
||||
ctrl.tmo <= '0';
|
||||
ctrl.timeout <= std_ulogic_vector(to_unsigned(BUS_TIMEOUT, index_size_f(BUS_TIMEOUT)+1));
|
||||
|
||||
-- state machine --
|
||||
case ctrl.state is
|
||||
|
||||
when IDLE => -- waiting for host request
|
||||
-- ------------------------------------------------------------
|
||||
-- buffer all outgoing signals --
|
||||
ctrl.we <= wren_i;
|
||||
ctrl.adr <= addr_i;
|
||||
if (BIG_ENDIAN = true) then -- big-endian
|
||||
ctrl.wdat <= bswap32_f(data_i);
|
||||
ctrl.sel <= bit_rev_f(ben_i);
|
||||
else -- little-endian
|
||||
ctrl.wdat <= data_i;
|
||||
ctrl.sel <= ben_i;
|
||||
end if;
|
||||
ctrl.src <= src_i;
|
||||
ctrl.lock <= lock_i;
|
||||
ctrl.priv <= priv_i;
|
||||
-- valid new or buffered read/write request --
|
||||
if ((xbus_access and (wren_i or rden_i)) = '1') then
|
||||
ctrl.state <= BUSY;
|
||||
end if;
|
||||
|
||||
when BUSY => -- transfer in progress
|
||||
-- ------------------------------------------------------------
|
||||
ctrl.rdat <= wb_dat_i;
|
||||
if (wb_err_i = '1') then -- abnormal bus termination
|
||||
ctrl.err <= '1';
|
||||
ctrl.state <= IDLE;
|
||||
elsif (timeout_en_c = true) and (or_reduce_f(ctrl.timeout) = '0') then -- enabled timeout
|
||||
ctrl.tmo <= '1';
|
||||
ctrl.state <= IDLE;
|
||||
elsif (wb_ack_i = '1') then -- normal bus termination
|
||||
ctrl.ack <= '1';
|
||||
ctrl.state <= IDLE;
|
||||
end if;
|
||||
-- timeout counter --
|
||||
if (timeout_en_c = true) then
|
||||
ctrl.timeout <= std_ulogic_vector(unsigned(ctrl.timeout) - 1); -- timeout counter
|
||||
end if;
|
||||
|
||||
when others => -- undefined
|
||||
-- ------------------------------------------------------------
|
||||
ctrl.state <= IDLE;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
end process bus_arbiter;
|
||||
|
||||
-- host access --
|
||||
ack_gated <= wb_ack_i when (ctrl.state = BUSY) else '0'; -- CPU ack gate for "async" RX
|
||||
rdata_gated <= wb_dat_i when (ctrl.state = BUSY) else (others => '0'); -- CPU read data gate for "async" RX
|
||||
rdata <= ctrl.rdat when (ASYNC_RX = false) else rdata_gated;
|
||||
|
||||
ext_o <= '1' when (ctrl.state = BUSY) else '0'; -- active external access
|
||||
|
||||
data_o <= rdata when (BIG_ENDIAN = false) else bswap32_f(rdata); -- endianness conversion
|
||||
ack_o <= ctrl.ack when (ASYNC_RX = false) else ack_gated;
|
||||
err_o <= ctrl.err;
|
||||
tmo_o <= ctrl.tmo;
|
||||
|
||||
-- wishbone interface --
|
||||
wb_tag_o(0) <= '0' when (ctrl.priv = priv_mode_u_c) else '1'; -- unprivileged access when in user mode
|
||||
wb_tag_o(1) <= '0'; -- 0 = secure, 1 = non-secure
|
||||
wb_tag_o(2) <= ctrl.src; -- 0 = data access, 1 = instruction access
|
||||
|
||||
wb_lock_o <= ctrl.lock; -- 1 = exclusive access request
|
||||
|
||||
wb_adr_o <= ctrl.adr;
|
||||
wb_dat_o <= ctrl.wdat;
|
||||
wb_we_o <= ctrl.we;
|
||||
wb_sel_o <= ctrl.sel;
|
||||
wb_stb_o <= stb_int when (PIPE_MODE = true) else cyc_int;
|
||||
wb_cyc_o <= cyc_int;
|
||||
|
||||
stb_int <= '1' when (ctrl.state = BUSY) and (ctrl.state_ff /= BUSY) else '0';
|
||||
cyc_int <= '1' when (ctrl.state = BUSY) else '0';
|
||||
|
||||
|
||||
end neorv32_wishbone_rtl;
|
229
Libs/RiscV/NEORV32/rtl/core/neorv32_xirq.vhd
Normal file
229
Libs/RiscV/NEORV32/rtl/core/neorv32_xirq.vhd
Normal file
@ -0,0 +1,229 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - External Interrupt Controller (XIRQ) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # Simple interrupt controller for platform (processor-external) interrupts. Up to 32 channels #
|
||||
-- # are supported that get (optionally) prioritized into a single CPU interrupt. #
|
||||
-- # #
|
||||
-- # The actual trigger configuration has to be done BEFORE synthesis using the XIRQ_TRIGGER_TYPE #
|
||||
-- # and XIRQ_TRIGGER_POLARITY generics. These allow to configure channel-independent low-level, #
|
||||
-- # high-level, falling-edge and rising-edge triggers. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_xirq is
|
||||
generic (
|
||||
XIRQ_NUM_CH : natural; -- number of external IRQ channels (0..32)
|
||||
XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0); -- trigger type: 0=level, 1=edge
|
||||
XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
|
||||
);
|
||||
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
|
||||
-- external interrupt lines --
|
||||
xirq_i : in std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
|
||||
-- CPU interrupt --
|
||||
cpu_irq_o : out std_ulogic
|
||||
);
|
||||
end neorv32_xirq;
|
||||
|
||||
architecture neorv32_xirq_rtl of neorv32_xirq is
|
||||
|
||||
-- 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(xirq_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 enable
|
||||
signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- control registers --
|
||||
signal irq_enable : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: interrupt enable
|
||||
signal clr_pending : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: clear pending IRQs
|
||||
signal irq_src : std_ulogic_vector(4 downto 0); -- r/w: source IRQ, ACK on any write
|
||||
|
||||
-- interrupt trigger --
|
||||
signal irq_sync : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
|
||||
signal irq_sync2 : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
|
||||
signal irq_trig : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
|
||||
|
||||
-- interrupt buffer --
|
||||
signal irq_buf : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
|
||||
signal irq_fire : std_ulogic;
|
||||
|
||||
-- interrupt source --
|
||||
signal irq_src_nxt : std_ulogic_vector(4 downto 0);
|
||||
|
||||
-- arbiter --
|
||||
signal irq_run : std_ulogic;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not ((XIRQ_NUM_CH < 0) or (XIRQ_NUM_CH > 32)) report "NEORV32 PROCESSOR CONFIG ERROR: Number of XIRQ inputs <XIRQ_NUM_CH> has to be 0..32." severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = xirq_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
addr <= xirq_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
|
||||
-- bus handshake --
|
||||
ack_o <= rden or wren;
|
||||
|
||||
-- write access --
|
||||
clr_pending <= (others => '1');
|
||||
if (wren = '1') then
|
||||
-- channel-enable --
|
||||
if (addr = xirq_enable_addr_c) then
|
||||
irq_enable <= data_i(XIRQ_NUM_CH-1 downto 0);
|
||||
end if;
|
||||
-- clear pending IRQs --
|
||||
if (addr = xirq_pending_addr_c) then
|
||||
clr_pending <= data_i(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- read access --
|
||||
data_o <= (others => '0');
|
||||
if (rden = '1') then
|
||||
case addr is
|
||||
when xirq_enable_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
|
||||
when xirq_pending_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_buf; -- pending IRQs
|
||||
when xirq_source_addr_c => data_o(4 downto 0) <= irq_src; -- source IRQ
|
||||
when others => NULL;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
|
||||
-- IRQ Trigger --------------------------------------------------------------
|
||||
-- -----------------------------------------------------------------------------
|
||||
irq_trigger: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
irq_sync <= xirq_i;
|
||||
irq_sync2 <= irq_sync;
|
||||
end if;
|
||||
end process irq_trigger;
|
||||
|
||||
irq_trigger_comb: process(irq_sync, irq_sync2)
|
||||
variable sel_v : std_ulogic_vector(1 downto 0);
|
||||
begin
|
||||
for i in 0 to XIRQ_NUM_CH-1 loop
|
||||
sel_v := XIRQ_TRIGGER_TYPE(i) & XIRQ_TRIGGER_POLARITY(i);
|
||||
case sel_v is
|
||||
when "00" => irq_trig(i) <= not irq_sync(i); -- low-level
|
||||
when "01" => irq_trig(i) <= irq_sync(i); -- high-level
|
||||
when "10" => irq_trig(i) <= (not irq_sync(i)) and irq_sync2(i); -- falling-edge
|
||||
when "11" => irq_trig(i) <= irq_sync(i) and (not irq_sync2(i)); -- rising-edge
|
||||
when others => irq_trig(i) <= '0';
|
||||
end case;
|
||||
end loop;
|
||||
end process irq_trigger_comb;
|
||||
|
||||
|
||||
-- IRQ Buffer ---------------------------------------------------------------
|
||||
-- -----------------------------------------------------------------------------
|
||||
irq_buffer: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
irq_buf <= (irq_buf or (irq_trig and irq_enable)) and clr_pending;
|
||||
end if;
|
||||
end process irq_buffer;
|
||||
|
||||
-- anyone firing? --
|
||||
irq_fire <= or_reduce_f(irq_buf);
|
||||
|
||||
|
||||
-- IRQ Priority Encoder -----------------------------------------------------
|
||||
-- -----------------------------------------------------------------------------
|
||||
irq_priority: process(irq_buf)
|
||||
begin
|
||||
irq_src_nxt <= (others => '0');
|
||||
if (XIRQ_NUM_CH > 1) then
|
||||
for i in 0 to XIRQ_NUM_CH-1 loop
|
||||
if (irq_buf(i) = '1') then
|
||||
irq_src_nxt(index_size_f(XIRQ_NUM_CH)-1 downto 0) <= std_ulogic_vector(to_unsigned(i, index_size_f(XIRQ_NUM_CH)));
|
||||
exit;
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
end process irq_priority;
|
||||
|
||||
|
||||
-- IRQ Arbiter --------------------------------------------------------------
|
||||
-- -----------------------------------------------------------------------------
|
||||
irq_arbiter: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
cpu_irq_o <= '0';
|
||||
if (irq_run = '0') then -- no active IRQ
|
||||
if (irq_fire = '1') then
|
||||
cpu_irq_o <= '1';
|
||||
irq_run <= '1';
|
||||
irq_src <= irq_src_nxt;
|
||||
end if;
|
||||
else -- active IRQ, wait for CPU to acknowledge
|
||||
if (wren = '1') and (addr = xirq_source_addr_c) then -- write _any_ value to acknowledge
|
||||
irq_run <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process irq_arbiter;
|
||||
|
||||
|
||||
end neorv32_xirq_rtl;
|
35
Libs/RiscV/NEORV32/rtl/processor_templates/README.md
Normal file
35
Libs/RiscV/NEORV32/rtl/processor_templates/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# SoC/Processor Templates
|
||||
|
||||
This folder provides exemplary templates that wrap the processor top entity and provide a simplified
|
||||
set of configuration generics and IOs. These setups are intended to allow beginner an easy start by
|
||||
hiding much of the processor's configuration complexity. Furthermore, these setups are used by many
|
||||
of the provided [example setups](https://github.com/stnolting/neorv32/tree/master/setups).
|
||||
|
||||
Alternatively, you can directly instantiate the processor's top entity
|
||||
[`rtl/core/neorv32_top.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/core/neorv32_top.vhd)
|
||||
to have full access to _all_ features.
|
||||
|
||||
### [`neorv32_ProcessorTop_Minimal.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/processor_templates/neorv32_ProcessorTop_Minimal.vhd)
|
||||
|
||||
This setup used the ["Direct Boot Configuration"](https://stnolting.github.io/neorv32/#_boot_configuration).
|
||||
Application software is installed directly into the processor-internal instruction memory (IMEM) during
|
||||
synthesis. This memory is implemented as ROM and these is no bootloader available. Hence, the executable
|
||||
remains unchangeable is executed right after reset.
|
||||
|
||||
The setup only provides 3 PWM channels as IO.
|
||||
|
||||
### [`neorv32_ProcessorTop_MinimalBoot.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/processor_templates/neorv32_ProcessorTop_MinimalBoot.vhd)
|
||||
|
||||
This setup used the ["Indirect Boot Configuration"](https://stnolting.github.io/neorv32/#_boot_configuration).
|
||||
The NEORV32 bootloader is enabled in this setup allowing to upload new application software at any time
|
||||
via a UART connection.
|
||||
|
||||
The setup provides 8 GPIO outputs and the UART communication lines as IO.
|
||||
|
||||
### [`neorv32_ProcessorTop_UP5KDemo.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/processor_templates/neorv32_ProcessorTop_UP5KDemo.vhd)
|
||||
|
||||
This is a more complex template that implements a small microcontroller-like NEORV32.
|
||||
It was originally designed for _UPDuino V3_ board, which features a Lattice iCE40up5k FPGA, but has
|
||||
also been ported to other boards that provide the same FPGA.
|
||||
|
||||
This setup provides a rich set of IOs including GPIO, SPI, TWI and PWM.
|
@ -0,0 +1,246 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Minimal setup without a bootloader >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
|
||||
entity neorv32_ProcessorTop_Minimal is
|
||||
generic (
|
||||
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
|
||||
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_C : boolean := false; -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean := false; -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT regs!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
||||
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
|
||||
CPU_CNT_WIDTH : natural := 34; -- total width of CPU cycle and instret counters (0..64)
|
||||
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS : natural := 0; -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY : natural := 8*1024; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64)
|
||||
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural := 8*1024; -- size of processor-internal instruction memory in bytes
|
||||
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural := 64*1024; -- size of processor-internal data memory in bytes
|
||||
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN : boolean := false; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY : natural := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_MTIME_EN : boolean := false; -- implement machine system timer (MTIME)?
|
||||
IO_PWM_NUM_CH : natural := 3; -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
IO_WDT_EN : boolean := false -- implement watch dog timer (WDT)?
|
||||
);
|
||||
port (
|
||||
clk_i : in std_logic;
|
||||
rstn_i : in std_logic;
|
||||
|
||||
-- PWM (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o : out std_ulogic_vector(IO_PWM_NUM_CH-1 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture neorv32_ProcessorTop_Minimal_rtl of neorv32_ProcessorTop_Minimal is
|
||||
|
||||
begin
|
||||
|
||||
-- The core of the problem ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_inst: entity neorv32.neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id (32-bit)
|
||||
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN => false, -- implement on-chip debugger?
|
||||
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A, -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT regs!)
|
||||
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => true, -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
|
||||
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN, -- use barrel shifter for shift operations
|
||||
CPU_CNT_WIDTH => CPU_CNT_WIDTH, -- total width of CPU cycle and instret counters (0..64)
|
||||
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH => HPM_CNT_WIDTH, -- total size of HPM counters (1..64)
|
||||
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
|
||||
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
|
||||
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN => ICACHE_EN, -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY, -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
|
||||
-- External memory interface --
|
||||
MEM_EXT_EN => false, -- implement external memory bus interface?
|
||||
MEM_EXT_TIMEOUT => 0, -- cycles after a pending bus access auto-terminates (0 = disabled)
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => false, -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN => IO_MTIME_EN, -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN => false, -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART1_EN => false, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_SPI_EN => false, -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN => false, -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH => IO_PWM_NUM_CH, -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
IO_WDT_EN => IO_WDT_EN, -- 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 => x"00000000", -- custom CFS configuration generic
|
||||
IO_CFS_IN_SIZE => 32, -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE => 32, -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN => false -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i => '0', -- low-active TAP reset (optional)
|
||||
jtag_tck_i => '0', -- serial clock
|
||||
jtag_tdi_i => '0', -- serial data input
|
||||
jtag_tdo_o => open, -- serial data output
|
||||
jtag_tms_i => '0', -- mode select
|
||||
|
||||
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
|
||||
wb_tag_o => open, -- request tag
|
||||
wb_adr_o => open, -- address
|
||||
wb_dat_i => (others => '0'), -- read data
|
||||
wb_dat_o => open, -- write data
|
||||
wb_we_o => open, -- read/write
|
||||
wb_sel_o => open, -- byte enable
|
||||
wb_stb_o => open, -- strobe
|
||||
wb_cyc_o => open, -- valid cycle
|
||||
wb_lock_o => open, -- exclusive access request
|
||||
wb_ack_i => '0', -- transfer acknowledge
|
||||
wb_err_i => '0', -- transfer error
|
||||
|
||||
-- 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 (available if IO_GPIO_EN = true) --
|
||||
gpio_o => open, -- parallel output
|
||||
gpio_i => (others => '0'), -- parallel input
|
||||
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o => open, -- UART0 send data
|
||||
uart0_rxd_i => '0', -- UART0 receive data
|
||||
uart0_rts_o => open, -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i => '0', -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o => open, -- UART1 send data
|
||||
uart1_rxd_i => '0', -- UART1 receive data
|
||||
uart1_rts_o => open, -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i => '0', -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- 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 (available if IO_TWI_EN = true) --
|
||||
twi_sda_io => open, -- twi serial data line
|
||||
twi_scl_io => open, -- twi serial clock line
|
||||
|
||||
-- PWM (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o => pwm_o, -- pwm channels
|
||||
|
||||
-- Custom Functions Subsystem IO --
|
||||
cfs_in_i => (others => '0'), -- custom CFS inputs conduit
|
||||
cfs_out_o => open, -- custom CFS outputs conduit
|
||||
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o => open, -- async serial data line
|
||||
|
||||
-- System time --
|
||||
mtime_i => (others => '0'), -- current system time from ext. MTIME (if IO_MTIME_EN = false)
|
||||
mtime_o => open, -- current system time from int. MTIME (if IO_MTIME_EN = true)
|
||||
|
||||
-- Interrupts --
|
||||
mtime_irq_i => '0', -- machine timer interrupt, available if IO_MTIME_EN = false
|
||||
msw_irq_i => '0', -- machine software interrupt
|
||||
mext_irq_i => '0' -- machine external interrupt
|
||||
);
|
||||
|
||||
end architecture;
|
@ -0,0 +1,267 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Minimal setup with the bootloader enabled >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
|
||||
entity neorv32_ProcessorTop_MinimalBoot is
|
||||
generic (
|
||||
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN : boolean := true; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
|
||||
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A : boolean := true; -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_C : boolean := true; -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean := true; -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT regs!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
||||
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
|
||||
CPU_CNT_WIDTH : natural := 34; -- total width of CPU cycle and instret counters (0..64)
|
||||
|
||||
-- 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
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64)
|
||||
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural := 64*1024; -- size of processor-internal instruction memory in bytes
|
||||
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural := 64*1024; -- size of processor-internal data memory in bytes
|
||||
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN : boolean := false; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY : natural := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN : boolean := true; -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN : boolean := true; -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN : boolean := true; -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_PWM_NUM_CH : natural := 3; -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
IO_WDT_EN : boolean := true -- implement watch dog timer (WDT)?
|
||||
);
|
||||
port (
|
||||
clk_i : in std_logic;
|
||||
rstn_i : in std_logic;
|
||||
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o : out std_ulogic_vector(3 downto 0);
|
||||
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart_txd_o : out std_ulogic; -- UART0 send data
|
||||
uart_rxd_i : in std_ulogic := '0'; -- UART0 receive data
|
||||
uart_rts_o : out std_ulogic; -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart_cts_i : in std_ulogic := '0'; -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- PWM (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o : out std_ulogic_vector(IO_PWM_NUM_CH-1 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture neorv32_ProcessorTop_MinimalBoot_rtl of neorv32_ProcessorTop_MinimalBoot is
|
||||
|
||||
-- internal IO connection --
|
||||
signal con_gpio_o : std_ulogic_vector(63 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- IO Connection --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
|
||||
-- GPIO --
|
||||
gpio_o <= con_gpio_o(3 downto 0);
|
||||
|
||||
-- The core of the problem ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_inst: entity neorv32.neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN => INT_BOOTLOADER_EN,-- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id (32-bit)
|
||||
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN => false, -- implement on-chip debugger?
|
||||
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A, -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT regs!)
|
||||
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => true, -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
|
||||
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN, -- use barrel shifter for shift operations
|
||||
CPU_CNT_WIDTH => CPU_CNT_WIDTH, -- total width of CPU cycle and instret counters (0..64)
|
||||
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH => HPM_CNT_WIDTH, -- total size of HPM counters (1..64)
|
||||
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
|
||||
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
|
||||
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN => ICACHE_EN, -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY, -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
|
||||
-- External memory interface --
|
||||
MEM_EXT_EN => false, -- implement external memory bus interface?
|
||||
MEM_EXT_TIMEOUT => 0, -- cycles after a pending bus access auto-terminates (0 = disabled)
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => IO_GPIO_EN, -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN => IO_MTIME_EN, -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN => IO_UART0_EN, -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART1_EN => false, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_SPI_EN => false, -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN => false, -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH => IO_PWM_NUM_CH, -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
IO_WDT_EN => IO_WDT_EN, -- 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 => x"00000000", -- custom CFS configuration generic
|
||||
IO_CFS_IN_SIZE => 32, -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE => 32, -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN => false -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i => '0', -- low-active TAP reset (optional)
|
||||
jtag_tck_i => '0', -- serial clock
|
||||
jtag_tdi_i => '0', -- serial data input
|
||||
jtag_tdo_o => open, -- serial data output
|
||||
jtag_tms_i => '0', -- mode select
|
||||
|
||||
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
|
||||
wb_tag_o => open, -- request tag
|
||||
wb_adr_o => open, -- address
|
||||
wb_dat_i => (others => '0'), -- read data
|
||||
wb_dat_o => open, -- write data
|
||||
wb_we_o => open, -- read/write
|
||||
wb_sel_o => open, -- byte enable
|
||||
wb_stb_o => open, -- strobe
|
||||
wb_cyc_o => open, -- valid cycle
|
||||
wb_lock_o => open, -- exclusive access request
|
||||
wb_ack_i => '0', -- transfer acknowledge
|
||||
wb_err_i => '0', -- transfer error
|
||||
|
||||
-- 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 (available if IO_GPIO_EN = true) --
|
||||
gpio_o => con_gpio_o, -- parallel output
|
||||
gpio_i => (others => '0'), -- parallel input
|
||||
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o => uart_txd_o, -- UART0 send data
|
||||
uart0_rxd_i => uart_rxd_i, -- UART0 receive data
|
||||
uart0_rts_o => uart_rts_o, -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i => uart_cts_i, -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o => open, -- UART1 send data
|
||||
uart1_rxd_i => '0', -- UART1 receive data
|
||||
uart1_rts_o => open, -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i => '0', -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- 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 (available if IO_TWI_EN = true) --
|
||||
twi_sda_io => open, -- twi serial data line
|
||||
twi_scl_io => open, -- twi serial clock line
|
||||
|
||||
-- PWM (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o => pwm_o, -- pwm channels
|
||||
|
||||
-- Custom Functions Subsystem IO --
|
||||
cfs_in_i => (others => '0'), -- custom CFS inputs conduit
|
||||
cfs_out_o => open, -- custom CFS outputs conduit
|
||||
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o => open, -- async serial data line
|
||||
|
||||
-- System time --
|
||||
mtime_i => (others => '0'), -- current system time from ext. MTIME (if IO_MTIME_EN = false)
|
||||
mtime_o => open, -- current system time from int. MTIME (if IO_MTIME_EN = true)
|
||||
|
||||
-- Interrupts --
|
||||
mtime_irq_i => '0', -- machine timer interrupt, available if IO_MTIME_EN = false
|
||||
msw_irq_i => '0', -- machine software interrupt
|
||||
mext_irq_i => '0' -- machine external interrupt
|
||||
);
|
||||
|
||||
end architecture;
|
@ -0,0 +1,307 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Example setup for boards with UP5K devices >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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;
|
||||
|
||||
entity neorv32_ProcessorTop_UP5KDemo is
|
||||
generic (
|
||||
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
|
||||
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
|
||||
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN : boolean := false; -- implement on-chip debugger?
|
||||
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A : boolean := true; -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_C : boolean := true; -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean := true; -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT regs!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
||||
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
|
||||
CPU_CNT_WIDTH : natural := 34; -- total width of CPU cycle and instret counters (0..64)
|
||||
|
||||
-- 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
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64)
|
||||
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural := 64*1024; -- size of processor-internal instruction memory in bytes
|
||||
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural := 64*1024; -- size of processor-internal data memory in bytes
|
||||
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN : boolean := false; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY : natural := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN : boolean := true; -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN : boolean := true; -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN : boolean := true; -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_SPI_EN : boolean := true; -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN : boolean := true; -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH : natural := 3; -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
IO_WDT_EN : boolean := true -- implement watch dog timer (WDT)?
|
||||
);
|
||||
port (
|
||||
clk_i : in std_logic;
|
||||
rstn_i : in std_logic;
|
||||
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_i : in std_ulogic_vector(3 downto 0);
|
||||
gpio_o : out std_ulogic_vector(3 downto 0);
|
||||
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart_txd_o : out std_ulogic; -- UART0 send data
|
||||
uart_rxd_i : in std_ulogic := '0'; -- UART0 receive data
|
||||
uart_rts_o : out std_ulogic; -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart_cts_i : in std_ulogic := '0'; -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- SPI to on-board flash --
|
||||
flash_sck_o : out std_ulogic;
|
||||
flash_sdo_o : out std_ulogic;
|
||||
flash_sdi_i : in std_ulogic;
|
||||
flash_csn_o : out std_ulogic; -- NEORV32.SPI_CS(0)
|
||||
|
||||
-- SPI (available if IO_SPI_EN = true) --
|
||||
spi_sck_o : out std_ulogic;
|
||||
spi_sdo_o : out std_ulogic;
|
||||
spi_sdi_i : in std_ulogic;
|
||||
spi_csn_o : out std_ulogic; -- NEORV32.SPI_CS(1)
|
||||
|
||||
-- TWI (available if IO_TWI_EN = true) --
|
||||
twi_sda_io : inout std_logic;
|
||||
twi_scl_io : inout std_logic;
|
||||
|
||||
-- PWM (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o : out std_ulogic_vector(IO_PWM_NUM_CH-1 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture neorv32_ProcessorTop_UP5KDemo_rtl of neorv32_ProcessorTop_UP5KDemo is
|
||||
|
||||
-- internal IO connection --
|
||||
signal con_gpio_o : std_ulogic_vector(63 downto 0);
|
||||
signal con_gpio_i : std_ulogic_vector(63 downto 0);
|
||||
signal con_spi_sck : std_ulogic;
|
||||
signal con_spi_sdi : std_ulogic;
|
||||
signal con_spi_sdo : std_ulogic;
|
||||
signal con_spi_csn : std_ulogic_vector(07 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- IO Connection --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
|
||||
-- SPI: on-board flash --
|
||||
flash_sck_o <= con_spi_sck;
|
||||
flash_sdo_o <= con_spi_sdo;
|
||||
flash_csn_o <= con_spi_csn(0);
|
||||
|
||||
-- SPI: user port --
|
||||
spi_sck_o <= con_spi_sck;
|
||||
spi_sdo_o <= con_spi_sdo;
|
||||
spi_csn_o <= con_spi_csn(1);
|
||||
|
||||
con_spi_sdi <= flash_sdi_i when (con_spi_csn(0) = '0') else spi_sdi_i;
|
||||
|
||||
-- GPIO --
|
||||
gpio_o <= con_gpio_o(3 downto 0);
|
||||
con_gpio_i(03 downto 0) <= gpio_i;
|
||||
con_gpio_i(63 downto 4) <= (others => '0');
|
||||
|
||||
-- The core of the problem ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_inst: entity neorv32.neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN => true, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id (32-bit)
|
||||
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN => ON_CHIP_DEBUGGER_EN, -- implement on-chip debugger?
|
||||
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A, -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT regs!)
|
||||
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => true, -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
|
||||
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN, -- use barrel shifter for shift operations
|
||||
CPU_CNT_WIDTH => CPU_CNT_WIDTH, -- total width of CPU cycle and instret counters (0..64)
|
||||
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH => HPM_CNT_WIDTH, -- total size of HPM counters (1..64)
|
||||
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
|
||||
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
|
||||
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN => ICACHE_EN, -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY, -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
|
||||
-- External memory interface --
|
||||
MEM_EXT_EN => false, -- implement external memory bus interface?
|
||||
MEM_EXT_TIMEOUT => 0, -- cycles after a pending bus access auto-terminates (0 = disabled)
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => IO_GPIO_EN, -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN => IO_MTIME_EN, -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN => IO_UART0_EN, -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART1_EN => false, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_SPI_EN => IO_SPI_EN, -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN => IO_TWI_EN, -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH => IO_PWM_NUM_CH, -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
IO_WDT_EN => IO_WDT_EN, -- 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 => x"00000000", -- custom CFS configuration generic
|
||||
IO_CFS_IN_SIZE => 32, -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE => 32, -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN => false -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i => '0', -- low-active TAP reset (optional)
|
||||
jtag_tck_i => '0', -- serial clock
|
||||
jtag_tdi_i => '0', -- serial data input
|
||||
jtag_tdo_o => open, -- serial data output
|
||||
jtag_tms_i => '0', -- mode select
|
||||
|
||||
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
|
||||
wb_tag_o => open, -- request tag
|
||||
wb_adr_o => open, -- address
|
||||
wb_dat_i => (others => '0'), -- read data
|
||||
wb_dat_o => open, -- write data
|
||||
wb_we_o => open, -- read/write
|
||||
wb_sel_o => open, -- byte enable
|
||||
wb_stb_o => open, -- strobe
|
||||
wb_cyc_o => open, -- valid cycle
|
||||
wb_lock_o => open, -- exclusive access request
|
||||
wb_ack_i => '0', -- transfer acknowledge
|
||||
wb_err_i => '0', -- transfer error
|
||||
|
||||
-- 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 (available if IO_GPIO_EN = true) --
|
||||
gpio_o => con_gpio_o, -- parallel output
|
||||
gpio_i => con_gpio_i, -- parallel input
|
||||
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o => uart_txd_o, -- UART0 send data
|
||||
uart0_rxd_i => uart_rxd_i, -- UART0 receive data
|
||||
uart0_rts_o => uart_rts_o, -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i => uart_cts_i, -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o => open, -- UART1 send data
|
||||
uart1_rxd_i => '0', -- UART1 receive data
|
||||
uart1_rts_o => open, -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i => '0', -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- SPI (available if IO_SPI_EN = true) --
|
||||
spi_sck_o => con_spi_sck, -- SPI serial clock
|
||||
spi_sdo_o => con_spi_sdo, -- controller data out, peripheral data in
|
||||
spi_sdi_i => con_spi_sdi, -- controller data in, peripheral data out
|
||||
spi_csn_o => con_spi_csn, -- SPI CS
|
||||
|
||||
-- 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 (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o => pwm_o, -- pwm channels
|
||||
|
||||
-- Custom Functions Subsystem IO --
|
||||
cfs_in_i => (others => '0'), -- custom CFS inputs conduit
|
||||
cfs_out_o => open, -- custom CFS outputs conduit
|
||||
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o => open, -- async serial data line
|
||||
|
||||
-- System time --
|
||||
mtime_i => (others => '0'), -- current system time from ext. MTIME (if IO_MTIME_EN = false)
|
||||
mtime_o => open, -- current system time from int. MTIME (if IO_MTIME_EN = true)
|
||||
|
||||
-- Interrupts --
|
||||
mtime_irq_i => '0', -- machine timer interrupt, available if IO_MTIME_EN = false
|
||||
msw_irq_i => '0', -- machine software interrupt
|
||||
mext_irq_i => '0' -- machine external interrupt
|
||||
);
|
||||
|
||||
end architecture;
|
@ -0,0 +1,486 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor Top Entity with Resolved Port Signals (std_logic/std_logic_vector) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_ProcessorTop_stdlogic is
|
||||
generic (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN : boolean := true; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN : boolean := false; -- implement on-chip debugger
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit-manipulation extension?
|
||||
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
|
||||
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT reg!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr : boolean := true; -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm : boolean := false; -- implement hardware performance monitors?
|
||||
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
|
||||
CPU_CNT_WIDTH : natural := 64; -- total width of CPU cycle and instret counters (0..64)
|
||||
-- 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
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64)
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN : boolean := false; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY : natural := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
-- External memory interface --
|
||||
MEM_EXT_EN : boolean := false; -- implement external memory bus interface?
|
||||
MEM_EXT_TIMEOUT : natural := 255; -- cycles after a pending bus access auto-terminates (0 = disabled)
|
||||
MEM_EXT_PIPE_MODE : boolean := false; -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode
|
||||
MEM_EXT_BIG_ENDIAN : boolean := false; -- byte order: true=big-endian, false=little-endian
|
||||
MEM_EXT_ASYNC_RX : boolean := false; -- use register buffer for RX data when false
|
||||
-- Stream link interface --
|
||||
SLINK_NUM_TX : natural := 0; -- number of TX links (0..8)
|
||||
SLINK_NUM_RX : natural := 0; -- number of TX links (0..8)
|
||||
SLINK_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two
|
||||
SLINK_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two
|
||||
-- External Interrupts Controller (XIRQ) --
|
||||
XIRQ_NUM_CH : natural := 0; -- number of external IRQ channels (0..32)
|
||||
XIRQ_TRIGGER_TYPE : std_logic_vector(31 downto 0) := (others => '1'); -- trigger type: 0=level, 1=edge
|
||||
XIRQ_TRIGGER_POLARITY : std_logic_vector(31 downto 0) := (others => '1'); -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN : boolean := true; -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN : boolean := true; -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN : boolean := true; -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART0_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART0_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_EN : boolean := true; -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_UART1_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_SPI_EN : boolean := true; -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN : boolean := true; -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH : natural := 4; -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
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); -- custom CFS configuration generic
|
||||
IO_CFS_IN_SIZE : positive := 32; -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE : positive := 32; -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN : boolean := true; -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
IO_GPTMR_EN : boolean := false -- implement general purpose timer (GPTMR)?
|
||||
);
|
||||
port (
|
||||
-- Global control --
|
||||
clk_i : in std_logic := '0'; -- global clock, rising edge
|
||||
rstn_i : in std_logic := '0'; -- global reset, low-active, async
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i : in std_logic := '0'; -- low-active TAP reset (optional)
|
||||
jtag_tck_i : in std_logic := '0'; -- serial clock
|
||||
jtag_tdi_i : in std_logic := '0'; -- serial data input
|
||||
jtag_tdo_o : out std_logic; -- serial data output
|
||||
jtag_tms_i : in std_logic := '0'; -- mode select
|
||||
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
|
||||
wb_tag_o : out std_logic_vector(02 downto 0); -- tag
|
||||
wb_adr_o : out std_logic_vector(31 downto 0); -- address
|
||||
wb_dat_i : in std_logic_vector(31 downto 0) := (others => '0'); -- read data
|
||||
wb_dat_o : out std_logic_vector(31 downto 0); -- write data
|
||||
wb_we_o : out std_logic; -- read/write
|
||||
wb_sel_o : out std_logic_vector(03 downto 0); -- byte enable
|
||||
wb_stb_o : out std_logic; -- strobe
|
||||
wb_cyc_o : out std_logic; -- valid cycle
|
||||
wb_lock_o : out std_logic; -- exclusive access request
|
||||
wb_ack_i : in std_logic := '0'; -- transfer acknowledge
|
||||
wb_err_i : in std_logic := '0'; -- transfer error
|
||||
-- Advanced memory control signals (available if MEM_EXT_EN = true) --
|
||||
fence_o : out std_logic; -- indicates an executed FENCE operation
|
||||
fencei_o : out std_logic; -- indicates an executed FENCEI operation
|
||||
-- TX stream interfaces (available if SLINK_NUM_TX > 0) --
|
||||
slink_tx_dat_o : out sdata_8x32r_t; -- output data
|
||||
slink_tx_val_o : out std_logic_vector(7 downto 0); -- valid output
|
||||
slink_tx_rdy_i : in std_logic_vector(7 downto 0) := (others => '0'); -- ready to send
|
||||
-- RX stream interfaces (available if SLINK_NUM_RX > 0) --
|
||||
slink_rx_dat_i : in sdata_8x32r_t := (others => (others => '0')); -- input data
|
||||
slink_rx_val_i : in std_logic_vector(7 downto 0) := (others => '0'); -- valid input
|
||||
slink_rx_rdy_o : out std_logic_vector(7 downto 0); -- ready to receive
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o : out std_logic_vector(63 downto 0); -- parallel output
|
||||
gpio_i : in std_logic_vector(63 downto 0) := (others => '0'); -- parallel input
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o : out std_logic; -- UART0 send data
|
||||
uart0_rxd_i : in std_logic := '0'; -- UART0 receive data
|
||||
uart0_rts_o : out std_logic; -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i : in std_logic := '0'; -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o : out std_logic; -- UART1 send data
|
||||
uart1_rxd_i : in std_logic := '0'; -- UART1 receive data
|
||||
uart1_rts_o : out std_logic; -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i : in std_logic := '0'; -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
-- 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 (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 (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o : out std_logic_vector(IO_PWM_NUM_CH-1 downto 0); -- pwm channels
|
||||
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
|
||||
cfs_in_i : in std_logic_vector(IO_CFS_IN_SIZE-1 downto 0); -- custom inputs
|
||||
cfs_out_o : out std_logic_vector(IO_CFS_OUT_SIZE-1 downto 0); -- custom outputs
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o : out std_logic; -- async serial data line
|
||||
-- System time --
|
||||
mtime_i : in std_logic_vector(63 downto 0) := (others => '0'); -- current system time from ext. MTIME (if IO_MTIME_EN = false)
|
||||
mtime_o : out std_logic_vector(63 downto 0); -- current system time from int. MTIME (if IO_MTIME_EN = true)
|
||||
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
|
||||
xirq_i : in std_logic_vector(XIRQ_NUM_CH-1 downto 0) := (others => '0'); -- IRQ channels
|
||||
-- CPU Interrupts --
|
||||
mtime_irq_i : in std_logic := '0'; -- machine timer interrupt, available if IO_MTIME_EN = false
|
||||
msw_irq_i : in std_logic := '0'; -- machine software interrupt
|
||||
mext_irq_i : in std_logic := '0' -- machine external interrupt
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture neorv32_ProcessorTop_stdlogic_rtl of neorv32_ProcessorTop_stdlogic is
|
||||
|
||||
-- type conversion --
|
||||
constant IO_CFS_CONFIG_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(IO_CFS_CONFIG);
|
||||
constant XIRQ_TRIGGER_TYPE_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(XIRQ_TRIGGER_TYPE);
|
||||
constant XIRQ_TRIGGER_POLARITY_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(XIRQ_TRIGGER_POLARITY);
|
||||
--
|
||||
signal clk_i_int : std_ulogic;
|
||||
signal rstn_i_int : std_ulogic;
|
||||
--
|
||||
signal jtag_trst_i_int :std_ulogic;
|
||||
signal jtag_tck_i_int :std_ulogic;
|
||||
signal jtag_tdi_i_int :std_ulogic;
|
||||
signal jtag_tdo_o_int :std_ulogic;
|
||||
signal jtag_tms_i_int :std_ulogic;
|
||||
--
|
||||
signal wb_tag_o_int : std_ulogic_vector(02 downto 0);
|
||||
signal wb_adr_o_int : std_ulogic_vector(31 downto 0);
|
||||
signal wb_dat_i_int : std_ulogic_vector(31 downto 0);
|
||||
signal wb_dat_o_int : std_ulogic_vector(31 downto 0);
|
||||
signal wb_we_o_int : std_ulogic;
|
||||
signal wb_sel_o_int : std_ulogic_vector(03 downto 0);
|
||||
signal wb_stb_o_int : std_ulogic;
|
||||
signal wb_cyc_o_int : std_ulogic;
|
||||
signal wb_lock_o_int : std_ulogic;
|
||||
signal wb_ack_i_int : std_ulogic;
|
||||
signal wb_err_i_int : std_ulogic;
|
||||
--
|
||||
signal fence_o_int : std_ulogic;
|
||||
signal fencei_o_int : std_ulogic;
|
||||
--
|
||||
signal slink_tx_dat_o_int : sdata_8x32_t;
|
||||
signal slink_tx_val_o_int : std_logic_vector(7 downto 0);
|
||||
signal slink_tx_rdy_i_int : std_logic_vector(7 downto 0);
|
||||
signal slink_rx_dat_i_int : sdata_8x32_t;
|
||||
signal slink_rx_val_i_int : std_logic_vector(7 downto 0);
|
||||
signal slink_rx_rdy_o_int : std_logic_vector(7 downto 0);
|
||||
--
|
||||
signal gpio_o_int : std_ulogic_vector(63 downto 0);
|
||||
signal gpio_i_int : std_ulogic_vector(63 downto 0);
|
||||
--
|
||||
signal uart0_txd_o_int : std_ulogic;
|
||||
signal uart0_rxd_i_int : std_ulogic;
|
||||
signal uart0_rts_o_int : std_ulogic;
|
||||
signal uart0_cts_i_int : std_ulogic;
|
||||
--
|
||||
signal uart1_txd_o_int : std_ulogic;
|
||||
signal uart1_rxd_i_int : std_ulogic;
|
||||
signal uart1_rts_o_int : std_ulogic;
|
||||
signal uart1_cts_i_int : std_ulogic;
|
||||
--
|
||||
signal spi_sck_o_int : std_ulogic;
|
||||
signal spi_sdo_o_int : std_ulogic;
|
||||
signal spi_sdi_i_int : std_ulogic;
|
||||
signal spi_csn_o_int : std_ulogic_vector(07 downto 0);
|
||||
--
|
||||
signal pwm_o_int : std_ulogic_vector(IO_PWM_NUM_CH-1 downto 0);
|
||||
--
|
||||
signal cfs_in_i_int : std_ulogic_vector(IO_CFS_IN_SIZE-1 downto 0);
|
||||
signal cfs_out_o_int : std_ulogic_vector(IO_CFS_OUT_SIZE-1 downto 0);
|
||||
--
|
||||
signal neoled_o_int : std_ulogic;
|
||||
--
|
||||
signal mtime_i_int : std_ulogic_vector(63 downto 0);
|
||||
signal mtime_o_int : std_ulogic_vector(63 downto 0);
|
||||
--
|
||||
signal xirq_i_int : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
|
||||
--
|
||||
signal mtime_irq_i_int : std_ulogic;
|
||||
signal msw_irq_i_int : std_ulogic;
|
||||
signal mext_irq_i_int : std_ulogic;
|
||||
|
||||
begin
|
||||
|
||||
-- The Core Of The Problem ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_top_inst: neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN => INT_BOOTLOADER_EN, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id (hartid) (32-bit)
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN => ON_CHIP_DEBUGGER_EN, -- implement on-chip debugger
|
||||
-- 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 extension?
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement muld/div extension?
|
||||
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT reg!)
|
||||
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => CPU_EXTENSION_RISCV_Zicntr, -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm => CPU_EXTENSION_RISCV_Zihpm, -- implement hardware performance monitors?
|
||||
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN, -- use barrel shifter for shift operations
|
||||
CPU_CNT_WIDTH => CPU_CNT_WIDTH, -- total width of CPU cycle and instret counters (0..64)
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH => HPM_CNT_WIDTH, -- total size of HPM counters (0..64)
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN => ICACHE_EN, -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY, -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
-- External memory interface --
|
||||
MEM_EXT_EN => MEM_EXT_EN, -- implement external memory bus interface?
|
||||
MEM_EXT_TIMEOUT => MEM_EXT_TIMEOUT, -- cycles after a pending bus access auto-terminates (0 = disabled)
|
||||
MEM_EXT_PIPE_MODE => MEM_EXT_PIPE_MODE, -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode
|
||||
MEM_EXT_BIG_ENDIAN => MEM_EXT_BIG_ENDIAN, -- byte order: true=big-endian, false=little-endian
|
||||
MEM_EXT_ASYNC_RX => MEM_EXT_ASYNC_RX, -- use register buffer for RX data when false
|
||||
-- Stream link interface --
|
||||
SLINK_NUM_TX => SLINK_NUM_TX, -- number of TX links (0..8)
|
||||
SLINK_NUM_RX => SLINK_NUM_RX, -- number of TX links (0..8)
|
||||
SLINK_TX_FIFO => SLINK_TX_FIFO, -- TX fifo depth, has to be a power of two
|
||||
SLINK_RX_FIFO => SLINK_RX_FIFO, -- RX fifo depth, has to be a power of two
|
||||
-- External Interrupts Controller (XIRQ) --
|
||||
XIRQ_NUM_CH => XIRQ_NUM_CH, -- number of external IRQ channels (0..32)
|
||||
XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE_INT, -- trigger type: 0=level, 1=edge
|
||||
XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY_INT, -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => IO_GPIO_EN, -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN => IO_MTIME_EN, -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN => IO_UART0_EN, -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART0_RX_FIFO => IO_UART0_RX_FIFO, -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART0_TX_FIFO => IO_UART0_TX_FIFO, -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_EN => IO_UART1_EN, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_UART1_RX_FIFO => IO_UART1_RX_FIFO, -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_TX_FIFO => IO_UART1_TX_FIFO, -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_SPI_EN => IO_SPI_EN, -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN => IO_TWI_EN, -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH => IO_PWM_NUM_CH, -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
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_IN_SIZE => IO_CFS_IN_SIZE, -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE => IO_CFS_OUT_SIZE, -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN => IO_NEOLED_EN, -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
IO_GPTMR_EN => IO_GPTMR_EN -- implement general purpose timer (GPTMR)?
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i_int, -- global clock, rising edge
|
||||
rstn_i => rstn_i_int, -- global reset, low-active, async
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i => jtag_trst_i_int, -- low-active TAP reset (optional)
|
||||
jtag_tck_i => jtag_tck_i_int, -- serial clock
|
||||
jtag_tdi_i => jtag_tdi_i_int, -- serial data input
|
||||
jtag_tdo_o => jtag_tdo_o_int, -- serial data output
|
||||
jtag_tms_i => jtag_tms_i_int, -- mode select
|
||||
-- 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
|
||||
wb_dat_o => wb_dat_o_int, -- write data
|
||||
wb_we_o => wb_we_o_int, -- read/write
|
||||
wb_sel_o => wb_sel_o_int, -- byte enable
|
||||
wb_stb_o => wb_stb_o_int, -- strobe
|
||||
wb_cyc_o => wb_cyc_o_int, -- valid cycle
|
||||
wb_lock_o => wb_lock_o_int, -- exclusive access request
|
||||
wb_ack_i => wb_ack_i_int, -- transfer acknowledge
|
||||
wb_err_i => wb_err_i_int, -- transfer error
|
||||
-- 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
|
||||
-- TX stream interfaces (available if SLINK_NUM_TX > 0) --
|
||||
slink_tx_dat_o => slink_tx_dat_o_int, -- output data
|
||||
slink_tx_val_o => slink_tx_val_o_int, -- valid output
|
||||
slink_tx_rdy_i => slink_tx_rdy_i_int, -- ready to send
|
||||
-- RX stream interfaces (available if SLINK_NUM_RX > 0) --
|
||||
slink_rx_dat_i => slink_rx_dat_i_int, -- input data
|
||||
slink_rx_val_i => slink_rx_val_i_int, -- valid input
|
||||
slink_rx_rdy_o => slink_rx_rdy_o_int, -- ready to receive
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o => gpio_o_int, -- parallel output
|
||||
gpio_i => gpio_i_int, -- parallel input
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o => uart0_txd_o_int, -- UART0 send data
|
||||
uart0_rxd_i => uart0_rxd_i_int, -- UART0 receive data
|
||||
uart0_rts_o => uart0_rts_o_int, -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i => uart0_cts_i_int, -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o => uart1_txd_o_int, -- UART1 send data
|
||||
uart1_rxd_i => uart1_rxd_i_int, -- UART1 receive data
|
||||
uart1_rts_o => uart1_rts_o_int, -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i => uart1_cts_i_int, -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
-- 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 (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 (available if IO_PWM_NUM_CH > 0) --
|
||||
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
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o => neoled_o_int, -- async serial data line
|
||||
-- System time --
|
||||
mtime_i => mtime_i_int, -- current system time from ext. MTIME (if IO_MTIME_EN = false)
|
||||
mtime_o => mtime_o_int, -- current system time from int. MTIME (if IO_MTIME_EN = true)
|
||||
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
|
||||
xirq_i => xirq_i_int, -- IRQ channels
|
||||
-- CPU Interrupts --
|
||||
mtime_irq_i => mtime_irq_i_int, -- machine timer interrupt, available if IO_MTIME_EN = false
|
||||
msw_irq_i => msw_irq_i_int, -- machine software interrupt
|
||||
mext_irq_i => mext_irq_i_int -- machine external interrupt
|
||||
);
|
||||
|
||||
-- type conversion --
|
||||
clk_i_int <= std_ulogic(clk_i);
|
||||
rstn_i_int <= std_ulogic(rstn_i);
|
||||
|
||||
jtag_trst_i_int <= std_ulogic(jtag_trst_i);
|
||||
jtag_tck_i_int <= std_ulogic(jtag_tck_i);
|
||||
jtag_tdi_i_int <= std_ulogic(jtag_tdi_i);
|
||||
jtag_tdo_o <= std_logic(jtag_tdo_o_int);
|
||||
jtag_tms_i_int <= std_ulogic(jtag_tms_i);
|
||||
|
||||
wb_tag_o <= std_logic_vector(wb_tag_o_int);
|
||||
wb_adr_o <= std_logic_vector(wb_adr_o_int);
|
||||
wb_dat_i_int <= std_ulogic_vector(wb_dat_i);
|
||||
wb_dat_o <= std_logic_vector(wb_dat_o_int);
|
||||
wb_we_o <= std_logic(wb_we_o_int);
|
||||
wb_sel_o <= std_logic_vector(wb_sel_o_int);
|
||||
wb_stb_o <= std_logic(wb_stb_o_int);
|
||||
wb_cyc_o <= std_logic(wb_cyc_o_int);
|
||||
wb_lock_o <= std_logic(wb_lock_o_int);
|
||||
wb_ack_i_int <= std_ulogic(wb_ack_i);
|
||||
wb_err_i_int <= std_ulogic(wb_err_i);
|
||||
|
||||
fence_o <= std_logic(fence_o_int);
|
||||
fencei_o <= std_logic(fencei_o_int);
|
||||
|
||||
slink_tx_val_o <= std_logic_vector(slink_tx_val_o_int);
|
||||
slink_tx_rdy_i_int <= std_ulogic_vector(slink_tx_rdy_i);
|
||||
slink_rx_val_i_int <= std_ulogic_vector(slink_rx_val_i);
|
||||
slink_rx_rdy_o <= std_logic_vector(slink_rx_rdy_o_int);
|
||||
|
||||
slink_conv:
|
||||
for i in 0 to 7 generate
|
||||
slink_tx_dat_o(i) <= std_logic_vector(slink_tx_dat_o_int(i));
|
||||
slink_rx_dat_i_int(i) <= std_ulogic_vector(slink_rx_dat_i(i));
|
||||
end generate;
|
||||
|
||||
gpio_o <= std_logic_vector(gpio_o_int);
|
||||
gpio_i_int <= std_ulogic_vector(gpio_i);
|
||||
|
||||
uart0_txd_o <= std_logic(uart0_txd_o_int);
|
||||
uart0_rxd_i_int <= std_ulogic(uart0_rxd_i);
|
||||
uart0_rts_o <= std_logic(uart0_rts_o_int);
|
||||
uart0_cts_i_int <= std_ulogic(uart0_cts_i);
|
||||
uart1_txd_o <= std_logic(uart1_txd_o_int);
|
||||
uart1_rxd_i_int <= std_ulogic(uart1_rxd_i);
|
||||
uart1_rts_o <= std_logic(uart1_rts_o_int);
|
||||
uart1_cts_i_int <= std_ulogic(uart1_cts_i);
|
||||
|
||||
spi_sck_o <= std_logic(spi_sck_o_int);
|
||||
spi_sdo_o <= std_logic(spi_sdo_o_int);
|
||||
spi_sdi_i_int <= std_ulogic(spi_sdi_i);
|
||||
spi_csn_o <= std_logic_vector(spi_csn_o_int);
|
||||
|
||||
pwm_o <= std_logic_vector(pwm_o_int);
|
||||
|
||||
cfs_in_i_int <= std_ulogic_vector(cfs_in_i);
|
||||
cfs_out_o <= std_logic_vector(cfs_out_o_int);
|
||||
|
||||
neoled_o <= std_logic(neoled_o_int);
|
||||
|
||||
mtime_i_int <= std_ulogic_vector(mtime_i);
|
||||
mtime_o <= std_logic_vector(mtime_o_int);
|
||||
|
||||
xirq_i_int <= std_ulogic_vector(xirq_i);
|
||||
|
||||
msw_irq_i_int <= std_ulogic(msw_irq_i);
|
||||
mext_irq_i_int <= std_ulogic(mext_irq_i);
|
||||
|
||||
|
||||
end architecture;
|
@ -0,0 +1,423 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor Top Entity with AvalonMM Compatible Master Interface >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # (c) "AvalonMM", "NIOS-2", "Qsys", "MegaWizard" and "Platform Designer" #
|
||||
-- # are trademarks of Intel #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_top_avalonmm is
|
||||
generic (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY : natural; -- clock frequency of clk_i in Hz
|
||||
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
|
||||
INT_BOOTLOADER_EN : boolean := false; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN : boolean := false; -- implement on-chip debugger
|
||||
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit-manipulation extension?
|
||||
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean := false; -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT regs!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr : boolean := true; -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm : boolean := false; -- implement hardware performance monitors?
|
||||
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
|
||||
CPU_EXTENSION_RISCV_Zmmul : boolean := false; -- implement multiply-only M sub-extension?
|
||||
|
||||
-- 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
|
||||
CPU_CNT_WIDTH : natural := 64; -- total width of CPU cycle and instret counters (0..64)
|
||||
CPU_IPB_ENTRIES : natural := 2; -- entries is instruction prefetch buffer, has to be a power of 2
|
||||
|
||||
-- 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
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64)
|
||||
|
||||
-- Internal Instruction memory (IMEM) --
|
||||
MEM_INT_IMEM_EN : boolean := false; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes
|
||||
|
||||
-- Internal Data memory (DMEM) --
|
||||
MEM_INT_DMEM_EN : boolean := false; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes
|
||||
|
||||
-- Internal Cache memory (iCACHE) --
|
||||
ICACHE_EN : boolean := false; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY : natural := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
|
||||
-- Stream link interface (SLINK) --
|
||||
SLINK_NUM_TX : natural := 0; -- number of TX links (0..8)
|
||||
SLINK_NUM_RX : natural := 0; -- number of TX links (0..8)
|
||||
SLINK_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two
|
||||
SLINK_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two
|
||||
|
||||
-- External Interrupts Controller (XIRQ) --
|
||||
XIRQ_NUM_CH : natural := 0; -- number of external IRQ channels (0..32)
|
||||
XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0) := x"ffffffff"; -- trigger type: 0=level, 1=edge
|
||||
XIRQ_TRIGGER_POLARITY : std_ulogic_vector(31 downto 0) := x"ffffffff"; -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN : boolean := false; -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN : boolean := false; -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN : boolean := false; -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART0_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART0_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_EN : boolean := false; -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_UART1_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_SPI_EN : boolean := false; -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN : boolean := false; -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH : natural := 0; -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
IO_WDT_EN : boolean := false; -- 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) := x"00000000"; -- custom CFS configuration generic
|
||||
IO_CFS_IN_SIZE : positive := 32; -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE : positive := 32; -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN : boolean := false; -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
IO_NEOLED_TX_FIFO : natural := 1; -- NEOLED TX FIFO depth, 1..32k, has to be a power of two
|
||||
IO_GPTMR_EN : boolean := false -- implement general purpose timer (GPTMR)?
|
||||
);
|
||||
port (
|
||||
-- Global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i : in std_ulogic := 'U'; -- low-active TAP reset (optional)
|
||||
jtag_tck_i : in std_ulogic := 'U'; -- serial clock
|
||||
jtag_tdi_i : in std_ulogic := 'U'; -- serial data input
|
||||
jtag_tdo_o : out std_ulogic; -- serial data output
|
||||
jtag_tms_i : in std_ulogic := 'U'; -- mode select
|
||||
|
||||
-- AvalonMM interface
|
||||
read_o : out std_logic;
|
||||
write_o : out std_logic;
|
||||
waitrequest_i : in std_logic := '0';
|
||||
byteenable_o : out std_logic_vector(3 downto 0);
|
||||
address_o : out std_logic_vector(31 downto 0);
|
||||
writedata_o : out std_logic_vector(31 downto 0);
|
||||
readdata_i : in std_logic_vector(31 downto 0) := (others => '0');
|
||||
|
||||
-- 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
|
||||
|
||||
-- TX stream interfaces (available if SLINK_NUM_TX > 0) --
|
||||
slink_tx_dat_o : out sdata_8x32_t; -- output data
|
||||
slink_tx_val_o : out std_ulogic_vector(7 downto 0); -- valid output
|
||||
slink_tx_rdy_i : in std_ulogic_vector(7 downto 0) := (others => 'L'); -- ready to send
|
||||
|
||||
-- RX stream interfaces (available if SLINK_NUM_RX > 0) --
|
||||
slink_rx_dat_i : in sdata_8x32_t := (others => (others => 'U')); -- input data
|
||||
slink_rx_val_i : in std_ulogic_vector(7 downto 0) := (others => 'L'); -- valid input
|
||||
slink_rx_rdy_o : out std_ulogic_vector(7 downto 0); -- ready to receive
|
||||
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o : out std_ulogic_vector(63 downto 0); -- parallel output
|
||||
gpio_i : in std_ulogic_vector(63 downto 0) := (others => 'U'); -- parallel input
|
||||
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o : out std_ulogic; -- UART0 send data
|
||||
uart0_rxd_i : in std_ulogic := 'U'; -- UART0 receive data
|
||||
uart0_rts_o : out std_ulogic; -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i : in std_ulogic := 'L'; -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o : out std_ulogic; -- UART1 send data
|
||||
uart1_rxd_i : in std_ulogic := 'U'; -- UART1 receive data
|
||||
uart1_rts_o : out std_ulogic; -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i : in std_ulogic := 'L'; -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
|
||||
-- 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 := 'U'; -- controller data in, peripheral data out
|
||||
spi_csn_o : out std_ulogic_vector(07 downto 0); -- chip-select
|
||||
|
||||
-- TWI (available if IO_TWI_EN = true) --
|
||||
twi_sda_io : inout std_logic := 'U'; -- twi serial data line
|
||||
twi_scl_io : inout std_logic := 'U'; -- twi serial clock line
|
||||
|
||||
-- PWM (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o : out std_ulogic_vector(IO_PWM_NUM_CH-1 downto 0); -- pwm channels
|
||||
|
||||
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
|
||||
cfs_in_i : in std_ulogic_vector(IO_CFS_IN_SIZE-1 downto 0) := (others => 'U'); -- custom CFS inputs conduit
|
||||
cfs_out_o : out std_ulogic_vector(IO_CFS_OUT_SIZE-1 downto 0); -- custom CFS outputs conduit
|
||||
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o : out std_ulogic; -- async serial data line
|
||||
|
||||
-- System time --
|
||||
mtime_i : in std_ulogic_vector(63 downto 0) := (others => 'U'); -- current system time from ext. MTIME (if IO_MTIME_EN = false)
|
||||
mtime_o : out std_ulogic_vector(63 downto 0); -- current system time from int. MTIME (if IO_MTIME_EN = true)
|
||||
|
||||
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
|
||||
xirq_i : in std_ulogic_vector(XIRQ_NUM_CH-1 downto 0) := (others => 'L'); -- IRQ channels
|
||||
|
||||
-- CPU interrupts --
|
||||
mtime_irq_i : in std_ulogic := 'L'; -- machine timer interrupt, available if IO_MTIME_EN = false
|
||||
msw_irq_i : in std_ulogic := 'L'; -- machine software interrupt
|
||||
mext_irq_i : in std_ulogic := 'L' -- machine external interrupt
|
||||
);
|
||||
end neorv32_top_avalonmm;
|
||||
|
||||
architecture neorv32_top_avalonmm_rtl of neorv32_top_avalonmm is
|
||||
|
||||
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
|
||||
signal wb_tag_o : std_ulogic_vector(02 downto 0); -- request tag
|
||||
signal wb_adr_o : std_ulogic_vector(31 downto 0); -- address
|
||||
signal wb_dat_i : std_ulogic_vector(31 downto 0) := (others => 'U'); -- read data
|
||||
signal wb_dat_o : std_ulogic_vector(31 downto 0); -- write data
|
||||
signal wb_we_o : std_ulogic; -- read/write
|
||||
signal wb_sel_o : std_ulogic_vector(03 downto 0); -- byte enable
|
||||
signal wb_stb_o : std_ulogic; -- strobe
|
||||
signal wb_cyc_o : std_ulogic; -- valid cycle
|
||||
signal wb_lock_o : std_ulogic; -- exclusive access request
|
||||
signal wb_ack_i : std_ulogic := 'L'; -- transfer acknowledge
|
||||
signal wb_err_i : std_ulogic := 'L'; -- transfer error
|
||||
|
||||
begin
|
||||
|
||||
neorv32_top_map : neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY,
|
||||
HW_THREAD_ID => HW_THREAD_ID,
|
||||
INT_BOOTLOADER_EN => INT_BOOTLOADER_EN,
|
||||
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN => ON_CHIP_DEBUGGER_EN,
|
||||
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A => CPU_EXTENSION_RISCV_A,
|
||||
CPU_EXTENSION_RISCV_B => CPU_EXTENSION_RISCV_B,
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C,
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E,
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M,
|
||||
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U,
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx,
|
||||
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr,
|
||||
CPU_EXTENSION_RISCV_Zicntr => CPU_EXTENSION_RISCV_Zicntr,
|
||||
CPU_EXTENSION_RISCV_Zihpm => CPU_EXTENSION_RISCV_Zihpm,
|
||||
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei,
|
||||
CPU_EXTENSION_RISCV_Zmmul => CPU_EXTENSION_RISCV_Zmmul,
|
||||
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN => FAST_MUL_EN,
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN,
|
||||
CPU_CNT_WIDTH => CPU_CNT_WIDTH,
|
||||
CPU_IPB_ENTRIES => CPU_IPB_ENTRIES,
|
||||
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS,
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY,
|
||||
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS => HPM_NUM_CNTS,
|
||||
HPM_CNT_WIDTH => HPM_CNT_WIDTH,
|
||||
|
||||
-- Internal Instruction memory (IMEM) --
|
||||
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN,
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE,
|
||||
|
||||
-- Internal Data memory (DMEM) --
|
||||
MEM_INT_DMEM_EN => MEM_INT_IMEM_EN,
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE,
|
||||
|
||||
-- Internal Cache memory (iCACHE) --
|
||||
ICACHE_EN => ICACHE_EN,
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS,
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE,
|
||||
ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY,
|
||||
|
||||
-- External memory interface (WISHBONE) --
|
||||
MEM_EXT_EN => true,
|
||||
MEM_EXT_TIMEOUT => 0,
|
||||
MEM_EXT_PIPE_MODE => false,
|
||||
MEM_EXT_BIG_ENDIAN => false,
|
||||
MEM_EXT_ASYNC_RX => false,
|
||||
|
||||
-- Stream link interface (SLINK) --
|
||||
SLINK_NUM_TX => SLINK_NUM_TX,
|
||||
SLINK_NUM_RX => SLINK_NUM_RX,
|
||||
SLINK_TX_FIFO => SLINK_TX_FIFO,
|
||||
SLINK_RX_FIFO => SLINK_RX_FIFO,
|
||||
|
||||
-- External Interrupts Controller (XIRQ) --
|
||||
XIRQ_NUM_CH => XIRQ_NUM_CH,
|
||||
XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE,
|
||||
XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY,
|
||||
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => IO_GPIO_EN,
|
||||
IO_MTIME_EN => IO_MTIME_EN,
|
||||
IO_UART0_EN => IO_UART0_EN,
|
||||
IO_UART0_RX_FIFO => IO_UART0_RX_FIFO,
|
||||
IO_UART0_TX_FIFO => IO_UART0_TX_FIFO,
|
||||
IO_UART1_EN => IO_UART1_EN,
|
||||
IO_UART1_RX_FIFO => IO_UART1_RX_FIFO,
|
||||
IO_UART1_TX_FIFO => IO_UART1_TX_FIFO,
|
||||
IO_SPI_EN => IO_SPI_EN,
|
||||
IO_TWI_EN => IO_TWI_EN,
|
||||
IO_PWM_NUM_CH => IO_PWM_NUM_CH,
|
||||
IO_WDT_EN => IO_WDT_EN,
|
||||
IO_TRNG_EN => IO_TRNG_EN,
|
||||
IO_CFS_EN => IO_CFS_EN,
|
||||
IO_CFS_CONFIG => IO_CFS_CONFIG,
|
||||
IO_CFS_IN_SIZE => IO_CFS_IN_SIZE,
|
||||
IO_CFS_OUT_SIZE => IO_CFS_OUT_SIZE,
|
||||
IO_NEOLED_EN => IO_NEOLED_EN,
|
||||
IO_NEOLED_TX_FIFO => IO_NEOLED_TX_FIFO,
|
||||
IO_GPTMR_EN => IO_GPTMR_EN
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i,
|
||||
rstn_i => rstn_i,
|
||||
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i => jtag_trst_i,
|
||||
jtag_tck_i => jtag_tck_i,
|
||||
jtag_tdi_i => jtag_tdi_i,
|
||||
jtag_tdo_o => jtag_tdo_o,
|
||||
jtag_tms_i => jtag_tms_i,
|
||||
|
||||
-- Wishbone bus interface (available if MEM_EXT_EN = true) --
|
||||
wb_tag_o => wb_tag_o,
|
||||
wb_adr_o => wb_adr_o,
|
||||
wb_dat_i => wb_dat_i,
|
||||
wb_dat_o => wb_dat_o,
|
||||
wb_we_o => wb_we_o,
|
||||
wb_sel_o => wb_sel_o,
|
||||
wb_stb_o => wb_stb_o,
|
||||
wb_cyc_o => wb_cyc_o,
|
||||
wb_lock_o => wb_lock_o,
|
||||
wb_ack_i => wb_ack_i,
|
||||
wb_err_i => wb_err_i,
|
||||
|
||||
-- Advanced memory control signals (available if MEM_EXT_EN = true) --
|
||||
fence_o => fence_o,
|
||||
fencei_o => fencei_o,
|
||||
|
||||
-- TX stream interfaces (available if SLINK_NUM_TX > 0) --
|
||||
slink_tx_dat_o => slink_tx_dat_o,
|
||||
slink_tx_val_o => slink_tx_val_o,
|
||||
slink_tx_rdy_i => slink_tx_rdy_i,
|
||||
|
||||
-- RX stream interfaces (available if SLINK_NUM_RX > 0) --
|
||||
slink_rx_dat_i => slink_rx_dat_i,
|
||||
slink_rx_val_i => slink_rx_val_i,
|
||||
slink_rx_rdy_o => slink_rx_rdy_o,
|
||||
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o => gpio_o,
|
||||
gpio_i => gpio_i,
|
||||
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o => uart0_txd_o,
|
||||
uart0_rxd_i => uart0_rxd_i,
|
||||
uart0_rts_o => uart0_rts_o,
|
||||
uart0_cts_i => uart0_cts_i,
|
||||
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o => uart1_txd_o,
|
||||
uart1_rxd_i => uart1_rxd_i,
|
||||
uart1_rts_o => uart1_rts_o,
|
||||
uart1_cts_i => uart1_cts_i,
|
||||
|
||||
-- SPI (available if IO_SPI_EN = true) --
|
||||
spi_sck_o => spi_sck_o,
|
||||
spi_sdo_o => spi_sdo_o,
|
||||
spi_sdi_i => spi_sdi_i,
|
||||
spi_csn_o => spi_csn_o,
|
||||
|
||||
-- TWI (available if IO_TWI_EN = true) --
|
||||
twi_sda_io => twi_sda_io,
|
||||
twi_scl_io => twi_scl_io,
|
||||
|
||||
-- PWM (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o => pwm_o,
|
||||
|
||||
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
|
||||
cfs_in_i => cfs_in_i,
|
||||
cfs_out_o => cfs_out_o,
|
||||
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o => neoled_o,
|
||||
|
||||
-- System time --
|
||||
mtime_i => mtime_i,
|
||||
mtime_o => mtime_o,
|
||||
|
||||
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
|
||||
xirq_i => xirq_i,
|
||||
|
||||
-- CPU interrupts --
|
||||
mtime_irq_i => mtime_irq_i,
|
||||
msw_irq_i => msw_irq_i,
|
||||
mext_irq_i => mext_irq_i
|
||||
);
|
||||
|
||||
-- Wishbone to AvalonMM bridge
|
||||
read_o <= '1' when (wb_stb_o = '1' and wb_we_o = '0') else '0';
|
||||
write_o <= '1' when (wb_stb_o = '1' and wb_we_o = '1') else '0';
|
||||
address_o <= std_logic_vector(wb_adr_o);
|
||||
writedata_o <= std_logic_vector(wb_dat_o);
|
||||
byteenable_o <= std_logic_vector(wb_sel_o);
|
||||
|
||||
wb_dat_i <= std_ulogic_vector(readdata_i);
|
||||
wb_ack_i <= not(waitrequest_i);
|
||||
wb_err_i <= '0';
|
||||
|
||||
end neorv32_top_avalonmm_rtl;
|
@ -0,0 +1,532 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Processor Top Entity with AXI4-Lite Compatible Master Interface >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # (c) "AXI", "AXI4" and "AXI4-Lite" are trademarks of Arm Holdings plc. #
|
||||
-- # Note: External MTIME is not supported. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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_SystemTop_axi4lite is
|
||||
generic (
|
||||
-- ------------------------------------------------------------
|
||||
-- Configuration Generics --
|
||||
-- ------------------------------------------------------------
|
||||
-- General --
|
||||
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN : boolean := true; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN : boolean := false; -- implement on-chip debugger
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
||||
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit-manipulation extension?
|
||||
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
|
||||
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT reg!)
|
||||
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr : boolean := true; -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm : boolean := false; -- implement hardware performance monitors?
|
||||
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
|
||||
CPU_CNT_WIDTH : natural := 64; -- total width of CPU cycle and instret counters (0..64)
|
||||
-- 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
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64)
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN : boolean := false; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural := 4; -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY : natural := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
-- External Interrupts Controller (XIRQ) --
|
||||
XIRQ_NUM_CH : natural := 0; -- number of external IRQ channels (0..32)
|
||||
XIRQ_TRIGGER_TYPE : std_logic_vector(31 downto 0) := x"FFFFFFFF"; -- trigger type: 0=level, 1=edge
|
||||
XIRQ_TRIGGER_POLARITY : std_logic_vector(31 downto 0) := x"FFFFFFFF"; -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN : boolean := true; -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN : boolean := true; -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN : boolean := true; -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART0_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART0_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_EN : boolean := true; -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_UART1_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_SPI_EN : boolean := true; -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN : boolean := true; -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH : natural := 4; -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
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 := false; -- implement custom functions subsystem (CFS)?
|
||||
IO_CFS_CONFIG : std_logic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
|
||||
IO_CFS_IN_SIZE : positive := 32; -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE : positive := 32; -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN : boolean := true; -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
IO_NEOLED_TX_FIFO : natural := 1; -- NEOLED TX FIFO depth, 1..32k, has to be a power of two
|
||||
IO_GPTMR_EN : boolean := false -- implement general purpose timer (GPTMR)?
|
||||
);
|
||||
port (
|
||||
-- ------------------------------------------------------------
|
||||
-- AXI4-Lite-Compatible Master Interface --
|
||||
-- ------------------------------------------------------------
|
||||
-- Clock and Reset --
|
||||
m_axi_aclk : in std_logic;
|
||||
m_axi_aresetn : in std_logic;
|
||||
-- Write Address Channel --
|
||||
m_axi_awaddr : out std_logic_vector(31 downto 0);
|
||||
m_axi_awprot : out std_logic_vector(2 downto 0);
|
||||
m_axi_awvalid : out std_logic;
|
||||
m_axi_awready : in std_logic;
|
||||
-- Write Data Channel --
|
||||
m_axi_wdata : out std_logic_vector(31 downto 0);
|
||||
m_axi_wstrb : out std_logic_vector(3 downto 0);
|
||||
m_axi_wvalid : out std_logic;
|
||||
m_axi_wready : in std_logic;
|
||||
-- Read Address Channel --
|
||||
m_axi_araddr : out std_logic_vector(31 downto 0);
|
||||
m_axi_arprot : out std_logic_vector(2 downto 0);
|
||||
m_axi_arvalid : out std_logic;
|
||||
m_axi_arready : in std_logic;
|
||||
-- Read Data Channel --
|
||||
m_axi_rdata : in std_logic_vector(31 downto 0);
|
||||
m_axi_rresp : in std_logic_vector(1 downto 0);
|
||||
m_axi_rvalid : in std_logic;
|
||||
m_axi_rready : out std_logic;
|
||||
-- Write Response Channel --
|
||||
m_axi_bresp : in std_logic_vector(1 downto 0);
|
||||
m_axi_bvalid : in std_logic;
|
||||
m_axi_bready : out std_logic;
|
||||
-- ------------------------------------------------------------
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
-- ------------------------------------------------------------
|
||||
jtag_trst_i : in std_logic := '0'; -- low-active TAP reset (optional)
|
||||
jtag_tck_i : in std_logic := '0'; -- serial clock
|
||||
jtag_tdi_i : in std_logic := '0'; -- serial data input
|
||||
jtag_tdo_o : out std_logic; -- serial data output
|
||||
jtag_tms_i : in std_logic := '0'; -- mode select
|
||||
-- ------------------------------------------------------------
|
||||
-- Processor IO --
|
||||
-- ------------------------------------------------------------
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o : out std_logic_vector(63 downto 0); -- parallel output
|
||||
gpio_i : in std_logic_vector(63 downto 0) := (others => '0'); -- parallel input
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o : out std_logic; -- UART0 send data
|
||||
uart0_rxd_i : in std_logic := '0'; -- UART0 receive data
|
||||
uart0_rts_o : out std_logic; -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i : in std_logic := '0'; -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o : out std_logic; -- UART1 send data
|
||||
uart1_rxd_i : in std_logic := '0'; -- UART1 receive data
|
||||
uart1_rts_o : out std_logic; -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i : in std_logic := '0'; -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
-- 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 (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 (available if IO_PWM_NUM_CH > 0) --
|
||||
pwm_o : out std_logic_vector(IO_PWM_NUM_CH-1 downto 0); -- pwm channels
|
||||
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
|
||||
cfs_in_i : in std_logic_vector(IO_CFS_IN_SIZE-1 downto 0); -- custom inputs
|
||||
cfs_out_o : out std_logic_vector(IO_CFS_OUT_SIZE-1 downto 0); -- custom outputs
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o : out std_logic; -- async serial data line
|
||||
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
|
||||
xirq_i : in std_logic_vector(XIRQ_NUM_CH-1 downto 0) := (others => '0'); -- IRQ channels
|
||||
-- CPU Interrupts --
|
||||
msw_irq_i : in std_logic := '0'; -- machine software interrupt
|
||||
mext_irq_i : in std_logic := '0' -- machine external interrupt
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture neorv32_SystemTop_axi4lite_rtl of neorv32_SystemTop_axi4lite is
|
||||
|
||||
-- type conversion --
|
||||
constant IO_CFS_CONFIG_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(IO_CFS_CONFIG);
|
||||
constant XIRQ_TRIGGER_TYPE_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(XIRQ_TRIGGER_TYPE);
|
||||
constant XIRQ_TRIGGER_POLARITY_INT : std_ulogic_vector(31 downto 0) := std_ulogic_vector(XIRQ_TRIGGER_POLARITY);
|
||||
--
|
||||
signal clk_i_int : std_ulogic;
|
||||
signal rstn_i_int : std_ulogic;
|
||||
--
|
||||
signal jtag_trst_i_int :std_ulogic;
|
||||
signal jtag_tck_i_int :std_ulogic;
|
||||
signal jtag_tdi_i_int :std_ulogic;
|
||||
signal jtag_tdo_o_int :std_ulogic;
|
||||
signal jtag_tms_i_int :std_ulogic;
|
||||
--
|
||||
signal gpio_o_int : std_ulogic_vector(63 downto 0);
|
||||
signal gpio_i_int : std_ulogic_vector(63 downto 0);
|
||||
--
|
||||
signal uart0_txd_o_int : std_ulogic;
|
||||
signal uart0_rxd_i_int : std_ulogic;
|
||||
signal uart0_rts_o_int : std_ulogic;
|
||||
signal uart0_cts_i_int : std_ulogic;
|
||||
--
|
||||
signal uart1_txd_o_int : std_ulogic;
|
||||
signal uart1_rxd_i_int : std_ulogic;
|
||||
signal uart1_rts_o_int : std_ulogic;
|
||||
signal uart1_cts_i_int : std_ulogic;
|
||||
--
|
||||
signal spi_sck_o_int : std_ulogic;
|
||||
signal spi_sdo_o_int : std_ulogic;
|
||||
signal spi_sdi_i_int : std_ulogic;
|
||||
signal spi_csn_o_int : std_ulogic_vector(07 downto 0);
|
||||
--
|
||||
signal pwm_o_int : std_ulogic_vector(IO_PWM_NUM_CH-1 downto 0);
|
||||
--
|
||||
signal cfs_in_i_int : std_ulogic_vector(IO_CFS_IN_SIZE-1 downto 0);
|
||||
signal cfs_out_o_int : std_ulogic_vector(IO_CFS_OUT_SIZE-1 downto 0);
|
||||
--
|
||||
signal neoled_o_int : std_ulogic;
|
||||
--
|
||||
signal xirq_i_int : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
|
||||
--
|
||||
signal msw_irq_i_int : std_ulogic;
|
||||
signal mext_irq_i_int : std_ulogic;
|
||||
|
||||
-- internal wishbone bus --
|
||||
type wb_bus_t is record
|
||||
adr : std_ulogic_vector(31 downto 0); -- address
|
||||
di : std_ulogic_vector(31 downto 0); -- processor input data
|
||||
do : std_ulogic_vector(31 downto 0); -- processor output data
|
||||
we : std_ulogic; -- write enable
|
||||
sel : std_ulogic_vector(03 downto 0); -- byte enable
|
||||
stb : std_ulogic; -- strobe
|
||||
cyc : std_ulogic; -- valid cycle
|
||||
ack : std_ulogic; -- transfer acknowledge
|
||||
err : std_ulogic; -- transfer error
|
||||
tag : std_ulogic_vector(02 downto 0); -- tag
|
||||
lock : std_ulogic; -- exclusive access request
|
||||
end record;
|
||||
signal wb_core : wb_bus_t;
|
||||
|
||||
-- AXI bridge control --
|
||||
type ctrl_t is record
|
||||
radr_received : std_ulogic;
|
||||
wadr_received : std_ulogic;
|
||||
wdat_received : std_ulogic;
|
||||
end record;
|
||||
signal ctrl : ctrl_t;
|
||||
|
||||
signal ack_read, ack_write : std_ulogic; -- normal transfer termination
|
||||
signal err_read, err_write : std_ulogic; -- error transfer termination
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (CPU_EXTENSION_RISCV_A = true) report "NEORV32 PROCESSOR CONFIG WARNING: AXI4-Lite provides NO support for atomic memory operations. LR/SC access via AXI will raise a bus exception." severity warning;
|
||||
|
||||
|
||||
-- The Core Of The Problem ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_top_inst: neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN => INT_BOOTLOADER_EN, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id (hartid)
|
||||
-- On-Chip Debugger (OCD) --
|
||||
ON_CHIP_DEBUGGER_EN => ON_CHIP_DEBUGGER_EN, -- implement on-chip debugger
|
||||
-- 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 extension?
|
||||
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
|
||||
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement muld/div extension?
|
||||
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
|
||||
CPU_EXTENSION_RISCV_Zfinx => CPU_EXTENSION_RISCV_Zfinx, -- implement 32-bit floating-point extension (using INT reg!)
|
||||
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => CPU_EXTENSION_RISCV_Zicntr, -- implement base counters?
|
||||
CPU_EXTENSION_RISCV_Zihpm => CPU_EXTENSION_RISCV_Zihpm, -- implement hardware performance monitors?
|
||||
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
|
||||
-- Extension Options --
|
||||
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN, -- use barrel shifter for shift operations
|
||||
CPU_CNT_WIDTH => CPU_CNT_WIDTH, -- total width of CPU cycle and instret counters (0..64)
|
||||
-- Physical Memory Protection (PMP) --
|
||||
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..64)
|
||||
PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
||||
-- Hardware Performance Monitors (HPM) --
|
||||
HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29)
|
||||
HPM_CNT_WIDTH => HPM_CNT_WIDTH, -- total size of HPM counters (0..64)
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN => ICACHE_EN, -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY, -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2
|
||||
-- External memory interface --
|
||||
MEM_EXT_EN => true, -- implement external memory bus interface?
|
||||
MEM_EXT_TIMEOUT => 0, -- cycles after a pending bus access auto-terminates (0 = disabled)
|
||||
MEM_EXT_PIPE_MODE => false, -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode
|
||||
MEM_EXT_BIG_ENDIAN => false, -- byte order: true=big-endian, false=little-endian
|
||||
MEM_EXT_ASYNC_RX => false, -- use register buffer for RX data when false
|
||||
-- External Interrupts Controller (XIRQ) --
|
||||
XIRQ_NUM_CH => XIRQ_NUM_CH, -- number of external IRQ channels (0..32)
|
||||
XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE_INT, -- trigger type: 0=level, 1=edge
|
||||
XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY_INT, -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => IO_GPIO_EN, -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN => IO_MTIME_EN, -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN => IO_UART0_EN, -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
IO_UART0_RX_FIFO => IO_UART0_RX_FIFO, -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART0_TX_FIFO => IO_UART0_TX_FIFO, -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_EN => IO_UART1_EN, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
|
||||
IO_UART1_RX_FIFO => IO_UART1_RX_FIFO, -- RX fifo depth, has to be a power of two, min 1
|
||||
IO_UART1_TX_FIFO => IO_UART1_TX_FIFO, -- TX fifo depth, has to be a power of two, min 1
|
||||
IO_SPI_EN => IO_SPI_EN, -- implement serial peripheral interface (SPI)?
|
||||
IO_TWI_EN => IO_TWI_EN, -- implement two-wire interface (TWI)?
|
||||
IO_PWM_NUM_CH => IO_PWM_NUM_CH, -- number of PWM channels to implement (0..60); 0 = disabled
|
||||
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_IN_SIZE => IO_CFS_IN_SIZE, -- size of CFS input conduit in bits
|
||||
IO_CFS_OUT_SIZE => IO_CFS_OUT_SIZE, -- size of CFS output conduit in bits
|
||||
IO_NEOLED_EN => IO_NEOLED_EN, -- implement NeoPixel-compatible smart LED interface (NEOLED)?
|
||||
IO_NEOLED_TX_FIFO => IO_NEOLED_TX_FIFO, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two
|
||||
IO_GPTMR_EN => IO_GPTMR_EN -- implement general purpose timer (GPTMR)?
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i_int, -- global clock, rising edge
|
||||
rstn_i => rstn_i_int, -- global reset, low-active, async
|
||||
-- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
|
||||
jtag_trst_i => jtag_trst_i_int, -- low-active TAP reset (optional)
|
||||
jtag_tck_i => jtag_tck_i_int, -- serial clock
|
||||
jtag_tdi_i => jtag_tdi_i_int, -- serial data input
|
||||
jtag_tdo_o => jtag_tdo_o_int, -- serial data output
|
||||
jtag_tms_i => jtag_tms_i_int, -- mode select
|
||||
-- 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
|
||||
wb_dat_o => wb_core.do, -- write data
|
||||
wb_we_o => wb_core.we, -- read/write
|
||||
wb_sel_o => wb_core.sel, -- byte enable
|
||||
wb_stb_o => wb_core.stb, -- strobe
|
||||
wb_cyc_o => wb_core.cyc, -- valid cycle
|
||||
wb_lock_o => wb_core.lock, -- exclusive access request
|
||||
wb_ack_i => wb_core.ack, -- transfer acknowledge
|
||||
wb_err_i => wb_core.err, -- transfer error
|
||||
-- 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 (available if IO_GPIO_EN = true) --
|
||||
gpio_o => gpio_o_int, -- parallel output
|
||||
gpio_i => gpio_i_int, -- parallel input
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o => uart0_txd_o_int, -- UART0 send data
|
||||
uart0_rxd_i => uart0_rxd_i_int, -- UART0 receive data
|
||||
uart0_rts_o => uart0_rts_o_int, -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
|
||||
uart0_cts_i => uart0_cts_i_int, -- hw flow control: UART0.TX allowed to transmit, low-active, optional
|
||||
-- secondary UART1 (available if IO_UART1_EN = true) --
|
||||
uart1_txd_o => uart1_txd_o_int, -- UART1 send data
|
||||
uart1_rxd_i => uart1_rxd_i_int, -- UART1 receive data
|
||||
uart1_rts_o => uart1_rts_o_int, -- hw flow control: UART1.RX ready to receive ("RTR"), low-active, optional
|
||||
uart1_cts_i => uart1_cts_i_int, -- hw flow control: UART1.TX allowed to transmit, low-active, optional
|
||||
-- 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 (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 available if IO_PWM_NUM_CH > 0) --
|
||||
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
|
||||
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
|
||||
neoled_o => neoled_o_int, -- async serial data line
|
||||
-- System time --
|
||||
mtime_i => (others => '0'), -- current system time from ext. MTIME (if IO_MTIME_EN = false)
|
||||
mtime_o => open, -- current system time from int. MTIME (if IO_MTIME_EN = true)
|
||||
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
|
||||
xirq_i => xirq_i_int, -- IRQ channels
|
||||
-- CPU Interrupts --
|
||||
mtime_irq_i => '0', -- machine timer interrupt, available if IO_MTIME_EN = false
|
||||
msw_irq_i => msw_irq_i_int, -- machine software interrupt
|
||||
mext_irq_i => mext_irq_i_int -- machine external interrupt
|
||||
);
|
||||
|
||||
-- type conversion --
|
||||
gpio_o <= std_logic_vector(gpio_o_int);
|
||||
gpio_i_int <= std_ulogic_vector(gpio_i);
|
||||
|
||||
jtag_trst_i_int <= std_ulogic(jtag_trst_i);
|
||||
jtag_tck_i_int <= std_ulogic(jtag_tck_i);
|
||||
jtag_tdi_i_int <= std_ulogic(jtag_tdi_i);
|
||||
jtag_tdo_o <= std_logic(jtag_tdo_o_int);
|
||||
jtag_tms_i_int <= std_ulogic(jtag_tms_i);
|
||||
|
||||
uart0_txd_o <= std_logic(uart0_txd_o_int);
|
||||
uart0_rxd_i_int <= std_ulogic(uart0_rxd_i);
|
||||
uart0_rts_o <= std_logic(uart0_rts_o_int);
|
||||
uart0_cts_i_int <= std_ulogic(uart0_cts_i);
|
||||
uart1_txd_o <= std_logic(uart1_txd_o_int);
|
||||
uart1_rxd_i_int <= std_ulogic(uart1_rxd_i);
|
||||
uart1_rts_o <= std_logic(uart1_rts_o_int);
|
||||
uart1_cts_i_int <= std_ulogic(uart1_cts_i);
|
||||
|
||||
spi_sck_o <= std_logic(spi_sck_o_int);
|
||||
spi_sdo_o <= std_logic(spi_sdo_o_int);
|
||||
spi_sdi_i_int <= std_ulogic(spi_sdi_i);
|
||||
spi_csn_o <= std_logic_vector(spi_csn_o_int);
|
||||
|
||||
pwm_o <= std_logic_vector(pwm_o_int);
|
||||
|
||||
cfs_in_i_int <= std_ulogic_vector(cfs_in_i);
|
||||
cfs_out_o <= std_logic_vector(cfs_out_o_int);
|
||||
|
||||
neoled_o <= std_logic(neoled_o_int);
|
||||
|
||||
xirq_i_int <= std_ulogic_vector(xirq_i);
|
||||
|
||||
msw_irq_i_int <= std_ulogic(msw_irq_i);
|
||||
mext_irq_i_int <= std_ulogic(mext_irq_i);
|
||||
|
||||
|
||||
-- Wishbone to AXI4-Lite Bridge -----------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
|
||||
-- access arbiter --
|
||||
axi_access_arbiter: process(rstn_i_int, clk_i_int)
|
||||
begin
|
||||
if (rstn_i_int = '0') then
|
||||
ctrl.radr_received <= '0';
|
||||
ctrl.wadr_received <= '0';
|
||||
ctrl.wdat_received <= '0';
|
||||
elsif rising_edge(clk_i_int) then
|
||||
if (wb_core.cyc = '0') then -- idle
|
||||
ctrl.radr_received <= '0';
|
||||
ctrl.wadr_received <= '0';
|
||||
ctrl.wdat_received <= '0';
|
||||
else -- busy
|
||||
-- "read address received" flag --
|
||||
if (wb_core.we = '0') then -- pending READ
|
||||
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 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 -- write data received by interconnect?
|
||||
ctrl.wdat_received <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process axi_access_arbiter;
|
||||
|
||||
|
||||
-- AXI4-Lite Global Signals --
|
||||
clk_i_int <= std_ulogic(m_axi_aclk);
|
||||
rstn_i_int <= std_ulogic(m_axi_aresetn);
|
||||
|
||||
|
||||
-- AXI4-Lite Read Address Channel --
|
||||
m_axi_araddr <= std_logic_vector(wb_core.adr);
|
||||
m_axi_arvalid <= std_logic((wb_core.cyc and (not wb_core.we)) and (not ctrl.radr_received));
|
||||
--m_axi_arprot <= "000"; -- recommended by Xilinx
|
||||
m_axi_arprot(0) <= wb_core.tag(0); -- 0:unprivileged access, 1:privileged access
|
||||
m_axi_arprot(1) <= wb_core.tag(1); -- 0:secure access, 1:non-secure access
|
||||
m_axi_arprot(2) <= wb_core.tag(2); -- 0:data access, 1:instruction access
|
||||
|
||||
-- AXI4-Lite Read Data Channel --
|
||||
m_axi_rready <= std_logic(wb_core.cyc and (not wb_core.we));
|
||||
wb_core.di <= std_ulogic_vector(m_axi_rdata);
|
||||
ack_read <= std_ulogic(m_axi_rvalid);
|
||||
err_read <= '0' when (m_axi_rresp = "00") else '1'; -- read response = ok? check this signal only when m_axi_rvalid = '1'
|
||||
|
||||
|
||||
-- AXI4-Lite Write Address Channel --
|
||||
m_axi_awaddr <= std_logic_vector(wb_core.adr);
|
||||
m_axi_awvalid <= std_logic((wb_core.cyc and wb_core.we) and (not ctrl.wadr_received));
|
||||
--m_axi_awprot <= "000"; -- recommended by Xilinx
|
||||
m_axi_awprot(0) <= wb_core.tag(0); -- 0:unprivileged access, 1:privileged access
|
||||
m_axi_awprot(1) <= wb_core.tag(1); -- 0:secure access, 1:non-secure access
|
||||
m_axi_awprot(2) <= wb_core.tag(2); -- 0:data access, 1:instruction access
|
||||
|
||||
-- AXI4-Lite Write Data Channel --
|
||||
m_axi_wdata <= std_logic_vector(wb_core.do);
|
||||
m_axi_wvalid <= std_logic((wb_core.cyc and wb_core.we) and (not ctrl.wdat_received));
|
||||
m_axi_wstrb <= std_logic_vector(wb_core.sel); -- byte-enable
|
||||
|
||||
-- AXI4-Lite Write Response Channel --
|
||||
m_axi_bready <= std_logic(wb_core.cyc and wb_core.we);
|
||||
ack_write <= std_ulogic(m_axi_bvalid);
|
||||
err_write <= '0' when (m_axi_bresp = "00") else '1'; -- write response = ok? check this signal only when m_axi_bvalid = '1'
|
||||
|
||||
|
||||
-- Wishbone transfer termination --
|
||||
wb_core.ack <= ack_read or ack_write;
|
||||
wb_core.err <= (ack_read and err_read) or (ack_write and err_write) or wb_core.lock;
|
||||
|
||||
|
||||
end architecture;
|
52
Libs/RiscV/NEORV32/rtl/test_setups/README.md
Normal file
52
Libs/RiscV/NEORV32/rtl/test_setups/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# Test Setups
|
||||
|
||||
This folder contains very simple test setups that are intended for project beginners
|
||||
to setup a minimal NEORV32 SoC. These setups are used in the :books:
|
||||
[NEORV32 User Guide](https://stnolting.github.io/neorv32/ug/).
|
||||
Note that these setups provides a minimalistic configuration to keep
|
||||
things at a simple level at first. Additional CPU ISA extensions, performance options and
|
||||
optional peripheral modules can be enabled by specifying the according :book:
|
||||
[configuration generics](https://stnolting.github.io/neorv32/#_processor_top_entity_generics).
|
||||
|
||||
|
||||
### Setup's Top Entity
|
||||
|
||||
#### Clocking and Reset
|
||||
|
||||
All test setups require an external clock (via `clk_i` signal) and an external
|
||||
low-active reset (via `rstn_i` signal).
|
||||
|
||||
#### Configuration Generics
|
||||
|
||||
Each setup provides three elementary generics that can/should be adapted to fit
|
||||
your FPGA/board.
|
||||
|
||||
* The clock speed in Hz **has to be specified** via the `CLOCK_SPEED` generic to fit your clock source.
|
||||
* The processor-internal instruction memory (IMEM) size _can be modified_ via the `MEM_INT_IMEM_SIZE` generic.
|
||||
* The processor-internal data memory (DMEM) size _can be modified_ via the `MEM_INT_DMEM_SIZE` generic.
|
||||
Note that this might require adaption of the NEORV32 linker script.
|
||||
|
||||
|
||||
### [`neorv32_test_setup_approm.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/test_setups/neorv32_test_setup_approm.vhd)
|
||||
|
||||
This setup configures a `rv32imc_Zicsr` CPU with 16kB IMEM (as pre-initialized ROM),
|
||||
8kB DMEM and includes the GPIO module to drive 8 external signals (`gpio_o`)
|
||||
and the MTIME module for generating timer interrupts.
|
||||
The setup uses the ["indirect boot"](https://stnolting.github.io/neorv32/#_indirect_boot)
|
||||
configuration, so software applications are "installed" directly into the
|
||||
processor-internal IMEM during synthesis.
|
||||
|
||||
:books: See User Guide section [_Installing an Executable Directly Into Memory_](https://stnolting.github.io/neorv32/ug/#_installing_an_executable_directly_into_memory).
|
||||
|
||||
|
||||
### [`neorv32_test_setup_bootloader.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/test_setups/neorv32_test_setup_bootloader.vhd)
|
||||
|
||||
This setup configures a `rv32imc_Zicsr` CPU with 16kB IMEM (as RAM), 8kB DMEM
|
||||
and includes the GPIO module to drive 8 external signals (`gpio_o`), the MTIME
|
||||
module for generating timer interrupts and UART0 to interface with the bootloader
|
||||
(via `uart0_txd_o` and `uart0_rxd_i`) via a serial terminal.
|
||||
The setup uses the ["direct boot"](https://stnolting.github.io/neorv32/#_direct_boot)
|
||||
configuration, so software applications can be uploaded and run at any timer via a serial terminal.
|
||||
|
||||
:books: See User Guide section
|
||||
[_Uploading and Starting of a Binary Executable Image via UART_](https://stnolting.github.io/neorv32/ug/#_uploading_and_starting_of_a_binary_executable_image_via_uart).
|
@ -0,0 +1,98 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Test Setup using the internal IMEM as ROM to run pre-installed executables >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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 RISC-V Processor - https://github.com/stnolting/neorv32 #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library neorv32;
|
||||
use neorv32.neorv32_package.all;
|
||||
|
||||
entity neorv32_test_setup_approm is
|
||||
generic (
|
||||
-- adapt these for your setup --
|
||||
CLOCK_FREQUENCY : natural := 100000000; -- clock frequency of clk_i in Hz
|
||||
MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes
|
||||
MEM_INT_DMEM_SIZE : natural := 8*1024 -- size of processor-internal data memory in bytes
|
||||
);
|
||||
port (
|
||||
-- Global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
-- GPIO --
|
||||
gpio_o : out std_ulogic_vector(7 downto 0) -- parallel output
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture neorv32_test_setup_approm_rtl of neorv32_test_setup_approm is
|
||||
|
||||
signal con_gpio_o : std_ulogic_vector(63 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- The Core Of The Problem ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_top_inst: neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_C => true, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_M => true, -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_Zicsr => true, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => true, -- implement base counters?
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN => true, -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => true, -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN => true -- implement machine system timer (MTIME)?
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o => con_gpio_o -- parallel output
|
||||
);
|
||||
|
||||
-- GPIO output --
|
||||
gpio_o <= con_gpio_o(7 downto 0);
|
||||
|
||||
|
||||
end architecture;
|
@ -0,0 +1,105 @@
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - Test Setup using the UART-Bootloader to upload and run executables >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # 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 RISC-V Processor - https://github.com/stnolting/neorv32 #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library neorv32;
|
||||
use neorv32.neorv32_package.all;
|
||||
|
||||
entity neorv32_test_setup_bootloader is
|
||||
generic (
|
||||
-- adapt these for your setup --
|
||||
CLOCK_FREQUENCY : natural := 100000000; -- clock frequency of clk_i in Hz
|
||||
MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes
|
||||
MEM_INT_DMEM_SIZE : natural := 8*1024 -- size of processor-internal data memory in bytes
|
||||
);
|
||||
port (
|
||||
-- Global control --
|
||||
clk_i : in std_ulogic; -- global clock, rising edge
|
||||
rstn_i : in std_ulogic; -- global reset, low-active, async
|
||||
-- GPIO --
|
||||
gpio_o : out std_ulogic_vector(7 downto 0); -- parallel output
|
||||
-- UART0 --
|
||||
uart0_txd_o : out std_ulogic; -- UART0 send data
|
||||
uart0_rxd_i : in std_ulogic -- UART0 receive data
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture neorv32_test_setup_bootloader_rtl of neorv32_test_setup_bootloader is
|
||||
|
||||
signal con_gpio_o : std_ulogic_vector(63 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- The Core Of The Problem ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_top_inst: neorv32_top
|
||||
generic map (
|
||||
-- General --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
|
||||
INT_BOOTLOADER_EN => true, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
|
||||
-- RISC-V CPU Extensions --
|
||||
CPU_EXTENSION_RISCV_C => true, -- implement compressed extension?
|
||||
CPU_EXTENSION_RISCV_M => true, -- implement mul/div extension?
|
||||
CPU_EXTENSION_RISCV_Zicsr => true, -- implement CSR system?
|
||||
CPU_EXTENSION_RISCV_Zicntr => true, -- implement base counters?
|
||||
-- Internal Instruction memory --
|
||||
MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
|
||||
-- Internal Data memory --
|
||||
MEM_INT_DMEM_EN => true, -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- size of processor-internal data memory in bytes
|
||||
-- Processor peripherals --
|
||||
IO_GPIO_EN => true, -- implement general purpose input/output port unit (GPIO)?
|
||||
IO_MTIME_EN => true, -- implement machine system timer (MTIME)?
|
||||
IO_UART0_EN => true -- implement primary universal asynchronous receiver/transmitter (UART0)?
|
||||
)
|
||||
port map (
|
||||
-- Global control --
|
||||
clk_i => clk_i, -- global clock, rising edge
|
||||
rstn_i => rstn_i, -- global reset, low-active, async
|
||||
-- GPIO (available if IO_GPIO_EN = true) --
|
||||
gpio_o => con_gpio_o, -- parallel output
|
||||
-- primary UART0 (available if IO_UART0_EN = true) --
|
||||
uart0_txd_o => uart0_txd_o, -- UART0 send data
|
||||
uart0_rxd_i => uart0_rxd_i -- UART0 receive data
|
||||
);
|
||||
|
||||
-- GPIO output --
|
||||
gpio_o <= con_gpio_o(7 downto 0);
|
||||
|
||||
|
||||
end architecture;
|
Reference in New Issue
Block a user