Initial commit
This commit is contained in:
		
							
								
								
									
										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; | ||||
		Reference in New Issue
	
	Block a user