URL
https://opencores.org/ocsvn/rv01_riscv_core/rv01_riscv_core/trunk
Subversion Repositories rv01_riscv_core
[/] [rv01_riscv_core/] [trunk/] [VHDL/] [RV01_top.vhd] - Rev 2
Compare with Previous | Blame | View Log
----------------------------------------------------------------- -- -- ----------------------------------------------------------------- -- -- -- Copyright (C) 2015 Stefano Tonello -- -- -- -- This source file may be used and distributed without -- -- restriction provided that this copyright statement is not -- -- removed from the file and that any derivative work contains -- -- the original copyright notice and the associated disclaimer.-- -- -- -- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY -- -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -- -- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -- -- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR -- -- 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. -- -- -- ----------------------------------------------------------------- --------------------------------------------------------------- -- RV01 top-level module --------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use STD.textio.all; library WORK; use work.RV01_CONSTS_PKG.all; use work.RV01_TYPES_PKG.all; use work.RV01_FUNCS_PKG.all; use work.RV01_PLIC_PKG.all; entity RV01_TOP is generic( -- synthesis translate_off ST_FILE : string := "NONE"; WB_FILE : string := "NONE"; -- synthesis translate_on IMEM_SIZE : natural := 1024*32; -- 128Kb DMEM_SIZE : natural := 1024*16; -- 64Kb IOMEM_SIZE : natural := 1024; -- 4Kb IMEM_SIZE_PO2 : std_logic := '1'; DMEM_SIZE_PO2 : std_logic := '1'; IMEM_LOWM : std_logic := '1'; BHT_SIZE : natural := 256; EI_SRC_CNT : natural := 8; EI_TRIG_TYPE : PLIC_TRIG_TYPE := LEVEL; EI_REQ_MAXCNT : natural := 16; CFG_FLAGS : std_logic_vector(16-1 downto 0) := "00000000"&"01100111"; SIMULATION_ONLY : std_logic := '0' ); port( CLK_i : in std_logic; -- clock RST_i : in std_logic; -- reset CHK_ENB_i : in std_logic; -- check-enable -- External Interrupt Request EI_REQ_i : std_logic_vector(EI_SRC_CNT-1 downto 0); -- Host interface MFROMHOST_WE_i : in std_logic; -- MFROMHOST write-enable MFROMHOST_i : in std_logic_vector(SDLEN-1 downto 0); -- MFROMHOST data-in -- Data port DP_WE_i : in std_logic; -- DP write-enable DP_ADR_i : in std_logic_vector(ALEN-1 downto 0); -- DP address DP_DAT_i : in std_logic_vector(SDLEN-1 downto 0); -- DP data-in -- Control port CP_RE_i : in std_logic; -- CP read-enable CP_WE_i : in std_logic; -- CP write-enable CP_ADR_i : in std_logic_vector(17-1 downto 0); -- CP address CP_DAT_i : in std_logic_vector(SDLEN-1 downto 0); -- CP data-in -- Host interface MTOHOST_OE_o : out std_logic; -- MTOHOST output-enable MTOHOST_o : out std_logic_vector(SDLEN-1 downto 0); -- MTOHOST data-out -- Data port DP_DAT_o : out std_logic_vector(SDLEN-1 downto 0); -- DP data-out -- Control port CP_DAT_o : out std_logic_vector(SDLEN-1 downto 0) -- CP data-out ); end RV01_TOP; architecture ARC of RV01_TOP is constant L2IMEM_SIZE : natural := log2(IMEM_SIZE); constant L2DMEM_SIZE : natural := log2(DMEM_SIZE); constant L2IOMEM_SIZE : natural := log2(DMEM_SIZE); constant PARALLEL_EXECUTION_ENABLED : std_logic := CFG_FLAGS(0); constant PLIC_PRESENT : std_logic := CFG_FLAGS(6); constant PLIC_ABASE : natural := DMEM_SIZE; constant PLIC_AWIDTH : natural := log2(EI_SRC_CNT+3); constant PLIC_AMAX : natural := ((EI_SRC_CNT+3)-1); component RV01_CPU_2W is generic( -- synthesis translate_off ST_FILENAME : string := "NONE"; WB_FILENAME : string := "NONE"; -- synthesis translate_on IMEM_SIZE : natural := 1024*32; -- 128Kb DMEM_SIZE : natural := 1024*16; -- 64Kb IMEM_LOWM : std_logic := '1'; BHT_SIZE : natural := 256; CFG_FLAGS : std_logic_vector(16-1 downto 0) := "00000000"&"01100111"; SIMULATION_ONLY : std_logic := '1' ); port( CLK_i : in std_logic; RST_i : in std_logic; -- instruction memory interface INSTR_i : in std_logic_vector(ILEN*2-1 downto 0); -- data memory interface DDAT0_i : in std_logic_vector(SDLEN-1 downto 0); DDAT1_i : in std_logic_vector(SDLEN-1 downto 0); IADR_ERR_i : in std_logic; DADR0_ERR_i : in std_logic; DADR1_ERR_i : in std_logic; IDADR_CFLT_i : in std_logic; -- check-enable (simulation-only) CHK_ENB_i : in std_logic; -- External Interrupt (from PLIC) EXT_INT_i : in std_logic; -- Host interface MFROMHOST_WE_i : in std_logic; MFROMHOST_i : in std_logic_vector(SDLEN-1 downto 0); -- Control port CP_RE_i : in std_logic; CP_WE_i : in std_logic; CP_ADR_i : in std_logic_vector(17-1 downto 0); CP_D_i : in std_logic_vector(SDLEN-1 downto 0); HALT_o : out std_logic; -- instruction memory interface IADR_o : out unsigned(ALEN-1 downto 0); -- data memory interface DRE_o : out std_logic_vector(2-1 downto 0); DBE_o : out std_logic_vector(4-1 downto 0); DWE0_o : out std_logic; DADR0_o : out unsigned(ALEN-1 downto 0); DADR1_o : out unsigned(ALEN-1 downto 0); DIADR0_o : out unsigned(ALEN-1 downto 0); DIADR1_o : out unsigned(ALEN-1 downto 0); DIMS_o : out std_logic_vector(2-1 downto 0); DDAT0_o : out std_logic_vector(SDLEN-1 downto 0); -- Host interface MTOHOST_OE_o : out std_logic; MTOHOST_o : out std_logic_vector(SDLEN-1 downto 0); -- Control port CP_Q_o : out std_logic_vector(SDLEN-1 downto 0) ); end component; component RV01_PLIC is generic( SRC_CNT : natural := 8; TRIG_TYPE : PLIC_TRIG_TYPE := LEVEL; REQ_MAXCNT : natural := 16 ); port( CLK_i : in std_logic; RST_i : in std_logic; REG_A_i : in std_logic_vector(log2(SRC_CNT+1)-1 downto 0); REG_WE_i : in std_logic; REG_D_i : in std_logic_vector(SDLEN-1 downto 0); REQ_i : in std_logic_vector(SRC_CNT-1 downto 0); REG_Q_o : out std_logic_vector(SDLEN-1 downto 0); EIP_o : out std_logic ); end component; component RV01_RAM_1RW1R_BE is generic( -- I/O data bus width DWIDTH : integer := 16; -- word count WCOUNT : integer := 256 ); port( CLK_i : in std_logic; A_i : in unsigned(log2(WCOUNT)-1 downto 0); DPRA_i : in unsigned(log2(WCOUNT)-1 downto 0); D_i : in std_logic_vector(DWIDTH-1 downto 0); BE_i : in std_logic_vector(DWIDTH/8-1 downto 0); WE_i : in std_logic; Q_o : out std_logic_vector(DWIDTH-1 downto 0); DPQ_o : out std_logic_vector(DWIDTH-1 downto 0) ); end component; component RV01_RAM_1RW_BE is generic( -- I/O data bus width DWIDTH : integer := 16; -- word count WCOUNT : integer := 256 ); port( CLK_i : in std_logic; A_i : in unsigned(log2(WCOUNT)-1 downto 0); D_i : in std_logic_vector(DWIDTH-1 downto 0); BE_i : in std_logic_vector(DWIDTH/8-1 downto 0); WE_i : in std_logic; Q_o : out std_logic_vector(DWIDTH-1 downto 0) ); end component; signal HALT : std_logic; signal EXT_INT : std_logic; signal INSTR : std_logic_vector(ILEN*2-1 downto 0); signal DDATI0 : std_logic_vector(SDLEN-1 downto 0); signal DDATI1 : std_logic_vector(SDLEN-1 downto 0); signal IWE0 : std_logic; signal IADR0 : unsigned(ALEN-1 downto 0); signal IADR1 : unsigned(ALEN-1 downto 0); signal IBE : std_logic_vector(4-1 downto 0); signal IDATI : std_logic_vector(ILEN-1 downto 0); signal DWE0 : std_logic; signal DBE : std_logic_vector(4-1 downto 0); signal DRE : std_logic_vector(2-1 downto 0); signal DADR0 : unsigned(ALEN-1 downto 0); signal DADR1 : unsigned(ALEN-1 downto 0); signal DIADR0 : unsigned(ALEN-1 downto 0); signal DIADR1 : unsigned(ALEN-1 downto 0); signal DIMS,DIMS_q : std_logic_vector(2-1 downto 0); signal DDATO : std_logic_vector(SDLEN-1 downto 0); signal IWE0_RAM : std_logic; signal IADR0_RAM : unsigned(log2(IMEM_SIZE)-1 downto 0); signal IADR1_RAM : unsigned(log2(IMEM_SIZE)-1 downto 0); signal IADR0_RAM_PX : unsigned(log2(IMEM_SIZE)-2 downto 0); signal IADR1_RAM_PX : unsigned(log2(IMEM_SIZE)-2 downto 0); signal IBE0_RAM : std_logic_vector(8-1 downto 0); signal IDATI_RAM : std_logic_vector(ILEN*2-1 downto 0); signal DWE0_RAM : std_logic; signal DADR0_RAM : unsigned(log2(DMEM_SIZE)-1 downto 0); signal DADR1_RAM : unsigned(log2(DMEM_SIZE)-1 downto 0); signal DDATI0_RAM : std_logic_vector(SDLEN-1 downto 0); signal DDATI1_RAM : std_logic_vector(SDLEN-1 downto 0); signal DBE_RAM : std_logic_vector(4-1 downto 0); signal IDI_RAM : std_logic_vector(ILEN*2-1 downto 0); signal DDI_RAM : std_logic_vector(SDLEN-1 downto 0); signal DP_ADR_MS : std_logic; signal DP_ADR_MS_q : std_logic; signal DP_IADR : unsigned(ALEN-1 downto 0); signal DP_DADR : unsigned(ALEN-1 downto 0); signal DP_IOADR_MS : std_logic; signal DP_IOADR_MS_q : std_logic; signal DP_IOADR : unsigned(ALEN-1 downto 0); signal IADR_ERR,IADR_ERR_q : std_logic; signal DADR0_ERR,DADR0_ERR_q : std_logic; signal DADR1_ERR,DADR1_ERR_q : std_logic; signal IDADR_CFLT : std_logic; signal IADR0_RAM_WS,IADR0_RAM_WS_q : std_logic; signal IOMS : std_logic_vector(2-1 downto 0); signal IOMS_q : std_logic_vector(2-1 downto 0); signal DADR_IO : unsigned(ALEN-1 downto 0); signal DWE_IO : std_logic; signal DDATI_IO : std_logic_vector(SDLEN-1 downto 0); signal DDATO_IO : std_logic_vector(SDLEN-1 downto 0); signal DADR_PLIC : std_logic_vector(PLIC_AWIDTH-1 downto 0); signal DWE_PLIC : std_logic; signal DDATI_PLIC : std_logic_vector(SDLEN-1 downto 0); signal DDATO_PLIC : std_logic_vector(SDLEN-1 downto 0); begin --------------------------------------------------- -- CPU module --------------------------------------------------- U_CPU : RV01_CPU_2W generic map( -- synthesis translate_off ST_FILENAME => ST_FILE, WB_FILENAME => WB_FILE, -- synthesis translate_on IMEM_SIZE => IMEM_SIZE, DMEM_SIZE => DMEM_SIZE, IMEM_LOWM => IMEM_LOWM, BHT_SIZE => BHT_SIZE, CFG_FLAGS => CFG_FLAGS, SIMULATION_ONLY => SIMULATION_ONLY ) port map( CLK_i => CLK_i, RST_i => RST_i, INSTR_i => INSTR, DDAT0_i => DDATI0, DDAT1_i => DDATI1, IADR_ERR_i => IADR_ERR_q, DADR0_ERR_i => DADR0_ERR_q, DADR1_ERR_i => DADR1_ERR_q, IDADR_CFLT_i => IDADR_CFLT, -- CHK_ENB_i => CHK_ENB_i, -- EXT_INT_i => EXT_INT, -- MFROMHOST_WE_i => MFROMHOST_WE_i, MFROMHOST_i => MFROMHOST_i, -- CP_RE_i => CP_RE_i, CP_WE_i => CP_WE_i, CP_ADR_i => CP_ADR_i, CP_D_i => CP_DAT_i, HALT_o => HALT, -- IRE_o => IRE, -- to be added! IADR_o => IADR1, DRE_o => DRE, DBE_o => DBE, DWE0_o => DWE0, DADR0_o => DADR0, DADR1_o => DADR1, DIADR0_o => DIADR0, DIADR1_o => DIADR1, DIMS_o => DIMS, DDAT0_o => DDATO, -- MTOHOST_OE_o => MTOHOST_OE_o, MTOHOST_o => MTOHOST_o, -- CP_Q_o => CP_DAT_o ); --------------------------------------------------- -- Address space --------------------------------------------------- -- if IMEM_LOWM = '1', instruction memory is located -- on lower portion of address space (starting from -- address zero), with data memory located above it -- (starting from address IMEM_SIZE). -- if IMEM_LOWM = '0', data memory is located -- on lower portion of address space (starting from -- address zero), with instruction memory located -- above it (starting from address DMEM_SIZE). -- I/O memory (when present) is treated as another -- type of data memory and is always located after -- instr. and data memory. -- From the exception processing point of view, I/O -- memory is treated a data one. -- I/O memory differs from instr. and data memories -- because: -- 1) it doesn't support concurrent access from CPU, -- and byte-write. -- 2) no check is performed that actual storage is -- available for a given address (e.g. reads from -- un-mapped addresses return garbage, without -- triggering any exception). --------------------------------------------------- -- Instruction/Data Memory Selection flags --------------------------------------------------- -- Instructions/data memory selection flags tell which -- type of RAM (instruction vs. data) is the target of -- a load/store instruction or a DP operation. -- For load/store instructions these flags are provided -- by CPU using DIMS_o output) while for DP operations -- selection flag is generated here. -- DP_ADR_MS selects between instruction and data memories. -- if DP_ADR_MS = '0', address belong to instr. memory, -- if DP_ADR_MS = '1', address belong to data memory. -- DP_IOADR_MS selects between I/O and data memory. -- if DP_IOADR_MS = '1', address belong to I/O memory, -- if DP_IOADR_MS = '0', address belong to true data memory. -- DP_ADR_MS | DP_IOADR_MS | mem. type -------------------------------------- -- 0 | x | instr. memory -- 1 | 0 | "true" data memory -- 1 | 1 | I/O data memory GL1: if IMEM_LOWM = '1' generate -- instr. memory is located on lower portion of address space, -- I/O memory (if present) is located after data memory. DP_ADR_MS <= '0' when (to_unsigned(DP_ADR_i)/4 < IMEM_SIZE) else '1'; DP_IADR <= to_unsigned(DP_ADR_i); DP_DADR <= to_unsigned(DP_ADR_i) - IMEM_SIZE*4; DP_IOADR_MS <= '0' when (to_unsigned(DP_ADR_i)/4 < IMEM_SIZE+DMEM_SIZE) else '1'; --DP_IOADR <= to_unsigned(DP_ADR_i) - (IMEM_SIZE*4 - DMEM_SIZE*4); end generate; GL0: if IMEM_LOWM = '0' generate -- instr. memory is located on upper portion of address space, -- I/O memory (if present) is located after instr. memory. DP_ADR_MS <= '0' when (to_unsigned(DP_ADR_i)/4 > DMEM_SIZE) else '1'; DP_IADR <= to_unsigned(DP_ADR_i) - DMEM_SIZE*4; DP_DADR <= to_unsigned(DP_ADR_i); DP_IOADR_MS <= '0' when (to_unsigned(DP_ADR_i)/4 < IMEM_SIZE+DMEM_SIZE) else '1'; --DP_IOADR <= to_unsigned(DP_ADR_i) - (IMEM_SIZE*4 - DMEM_SIZE*4); end generate; -- Note: DADR0 and DADR1 are data memory addresses, so there's no need to -- subtract IMEM_SIZE from them! -- I/O memory selection flags GIOM0_GT0: if(IOMEM_SIZE > 0) generate IOMS(0) <= '1' when (DADR0(ALEN-1 downto 2) >= DMEM_SIZE) else '0'; IOMS(1) <= '1' when (DADR1(ALEN-1 downto 2) >= DMEM_SIZE) else '0'; end generate; GIOM0_EQ0: if(IOMEM_SIZE = 0) generate IOMS(0) <= '0'; IOMS(1) <= '0'; end generate; -- Memory Selection flag registers: these registers are -- needed to mux instruction and data RAM's output during -- load or DP read operations (because of synchronous -- behavior of RAM's, output data is available with a -- delay of one cycle, requiring a similarly delayed -- version of selection flags). process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then DP_ADR_MS_q <= DP_ADR_MS; DP_IOADR_MS_q <= DP_IOADR_MS; DIMS_q <= DIMS; IOMS_q <= IOMS; end if; end process; --------------------------------------------------- -- Address error and conflict flags --------------------------------------------------- -- An instruction address triggers an error if it -- simply falls outside of the instruction address space -- given by [0:IMEM_SIZE*4-4) -- A load/store address triggers an error if: -- 1) it targets instruction RAM (DIMS* = '1') and it -- falls outside of the instruction address space -- given by [0:IMEM_SIZE*4-4), OR -- 2) it targets data RAM (DIMS* = '0') and it falls -- outside of the data address space given by -- [0:(DMEM_SIZE+IOMEM_SIZE)*4-4). -- This flag gets asserted if data port #0 address is -- outside of address space. DADR0_ERR <= '1' when ( (DIMS(0) = '0' and DIADR0(ALEN-1 downto 2) >= IMEM_SIZE) or (DIMS(0) = '1' and DADR0(ALEN-1 downto 2) >= DMEM_SIZE + IOMEM_SIZE) ) else '0'; -- This flag gets asserted if data port #1 address is -- outside of address space. DADR1_ERR <= '1' when ( (DIMS(1) = '0' and DIADR1(ALEN-1 downto 2) >= IMEM_SIZE) or (DIMS(1) = '1' and DADR1(ALEN-1 downto 2) >= DMEM_SIZE + IOMEM_SIZE) ) else '0'; -- This flag gets asserted if instruction port address -- is outside of address space. IADR_ERR <= '1' when ( IADR1(ALEN-3 downto 3) >= IMEM_SIZE/2 ) else '0'; -- Error flag pipe registers (added to relax -- timing constraints). process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then IADR_ERR_q <= '0'; DADR0_ERR_q <= '0'; DADR1_ERR_q <= '0'; else IADR_ERR_q <= IADR_ERR; DADR0_ERR_q <= DADR0_ERR; DADR1_ERR_q <= DADR1_ERR; end if; end if; end process; -- This flag gets asserted if a concurrent access from -- data ports is attemped on instruction sub-space or -- on I/O sub-space. IDADR_CFLT <= '1' when ( ( (DIMS(0) = '0' and DRE(0) = '1') and (DIMS(1) = '0' and DRE(1) = '1') ) or ( (DIMS(0) = '0' and DWE0 = '1') and (DIMS(1) = '0' and DRE(1) = '1') ) or ( (IOMS(0) = '1' and DRE(0) = '1') and (IOMS(1) = '1' and DRE(1) = '1') ) or ( (IOMS(0) = '1' and DWE0 = '1') and (IOMS(1) = '1' and DRE(1) = '1') ) ) else '0'; --------------------------------------------------- -- Instruction RAM --------------------------------------------------- -- Instruction RAM is dual-port RAM with 1 read/write -- port and 1 read-only port. -- Read-only port id used for instructions fecthing, -- read/write port is used to access memory through -- load/store operations. GPX0_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate -- Instruction RAM word width is twice data RAM one -- because instructions RAM must provides two -- adjacent instructions per cycle. U_RAMI : RV01_RAM_1RW1R_BE generic map( DWIDTH => ILEN*2, WCOUNT => IMEM_SIZE/2 ) port map( CLK_i => CLK_i, A_i => IADR0_RAM_PX(log2(IMEM_SIZE)-2 downto 0), DPRA_i => IADR1_RAM_PX(log2(IMEM_SIZE)-2 downto 0), D_i => IDI_RAM, WE_i => IWE0_RAM, BE_i => IBE0_RAM, Q_o => IDATI_RAM, DPQ_o => INSTR ); end generate; -- GPX0_1 GPX0_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate -- Instruction RAM word width equals data RAM one -- because instructions RAM must provides one -- instruction per cycle. U_RAMI : RV01_RAM_1RW1R_BE generic map( DWIDTH => ILEN, WCOUNT => IMEM_SIZE ) port map( CLK_i => CLK_i, A_i => IADR0_RAM, DPRA_i => IADR1_RAM, D_i => IDI_RAM(ILEN-1 downto 0), WE_i => IWE0_RAM, BE_i => IBE0_RAM(4-1 downto 0), Q_o => IDATI_RAM(ILEN-1 downto 0), DPQ_o => INSTR(ILEN-1 downto 0) ); IDATI_RAM(ILEN*2-1 downto ILEN) <= (others => '0'); INSTR(ILEN*2-1 downto ILEN) <= (others => '0'); end generate; -- GPX0_0 --------------------------------------------------- -- Instruction memory signals --------------------------------------------------- -- inst. RAM read/write port address GPX5_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate -- Inst. RAM read/write address has three possible -- sources: -- 1) DP port address -- 2) data port #0 address -- 3) data port #1 address GPO_1 : if(IMEM_SIZE_PO2 = '1') generate -- Inst. memory size is a power-of-2: address is generated -- as a simple subset of DIADR0, DIADR0 or DP_IADR. process(DIMS(0),DIMS(1),DRE,DWE0,HALT,DIADR0,DIADR1,DP_IADR,DBE) begin if(HALT = '0') then -- cpu data memory ports address if(DIMS(0) = '0' and (DRE(0) = '1' or DWE0 = '1')) then -- port #0 address IADR0_RAM_PX <= DIADR0(L2IMEM_SIZE+2-1 downto 3); IADR0_RAM_WS <= DIADR0(2); else -- port #1 address IADR0_RAM_PX <= DIADR1(L2IMEM_SIZE+2-1 downto 3); IADR0_RAM_WS <= DIADR1(2); end if; IBE <= DBE; else -- DP port address IADR0_RAM_PX <= DP_IADR(L2IMEM_SIZE+2-1 downto 3); IADR0_RAM_WS <= DP_IADR(2); IBE <= (others => '1'); end if; end process; end generate; -- GPO_1 GPO_0 : if(IMEM_SIZE_PO2 = '0') generate -- Inst. memory size is NOT a power-of-2: address is generated -- as a subset of DIADR0, DIADR0 or DP_IADR, except when it exceeds -- memory size (when this occur, address is forced to all-0). process(DIMS(0),DIMS(1),DRE,DWE0,HALT,DIADR0,DIADR1,DP_IADR,DBE) begin if(HALT = '0') then -- cpu data memory ports address if(DIMS(0) = '0' and (DRE(0) = '1' or DWE0 = '1')) then -- port #0 address if(DIADR0(L2IMEM_SIZE+2-1 downto 3) < IMEM_SIZE/2) then IADR0_RAM_PX <= DIADR0(L2IMEM_SIZE+2-1 downto 3); else IADR0_RAM_PX <= (others => '0'); end if; IADR0_RAM_WS <= DIADR0(2); else -- port #1 address if(DIADR1(L2IMEM_SIZE+2-1 downto 3) < IMEM_SIZE/2) then IADR0_RAM_PX <= DIADR1(L2IMEM_SIZE+2-1 downto 3); else IADR0_RAM_PX <= (others => '0'); end if; IADR0_RAM_WS <= DIADR1(2); end if; IBE <= DBE; else -- DP port address if(DP_IADR(L2IMEM_SIZE+2-1 downto 3) < IMEM_SIZE/2) then IADR0_RAM_PX <= DP_IADR(L2IMEM_SIZE+2-1 downto 3); else IADR0_RAM_PX <= (others => '0'); end if; IADR0_RAM_WS <= DP_IADR(2); IBE <= (others => '1'); end if; end process; end generate; -- GPO_0 end generate; -- GPX5_1 GPX5_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate -- Inst. RAM read/write address has two possible -- sources: -- 1) DP port address -- 2) data port #0 address GPO_1 : if(IMEM_SIZE_PO2 = '1') generate -- Inst. memory size is a power-of-2: address is generated -- as a simple subset of DIADR0, DIADR0 or DP_IADR. process(DIMS(0),DIMS(1),DRE,DWE0,HALT,DIADR0,DIADR1,DP_IADR,DBE) begin if(HALT = '0') then -- cpu data memory ports address if(DIMS(0) = '0' and (DRE(0) = '1' or DWE0 = '1')) then -- port #0 address IADR0_RAM <= DIADR0(L2IMEM_SIZE+2-1 downto 2); else -- port #1 address IADR0_RAM <= DIADR1(L2IMEM_SIZE+2-1 downto 2); end if; IBE <= DBE; else -- DP port address IADR0_RAM <= DP_IADR(L2IMEM_SIZE+2-1 downto 2); IBE <= (others => '1'); end if; IADR0_RAM_WS <= '0'; end process; end generate; -- GPO_1 GPO_0 : if(IMEM_SIZE_PO2 = '0') generate -- Inst. memory size is NOT a power-of-2: address is generated -- as a subset of DIADR0, DIADR0 or DP_IADR, except when it exceeds -- memory size (when this occur, address is forced to all-0). process(DIMS(0),DIMS(1),DRE,DWE0,HALT,DIADR0,DIADR1,DP_IADR,DBE) begin if(HALT = '0') then -- cpu data memory ports address if(DIMS(0) = '0' and (DRE(0) = '1' or DWE0 = '1')) then -- port #0 address if(DIADR0(L2IMEM_SIZE+2-1 downto 2) < IMEM_SIZE) then IADR0_RAM <= DIADR0(L2IMEM_SIZE+2-1 downto 2); else IADR0_RAM <= (others => '0'); end if; else -- port #1 address if(DIADR1(L2IMEM_SIZE+2-1 downto 2) < IMEM_SIZE) then IADR0_RAM <= DIADR1(L2IMEM_SIZE+2-1 downto 2); else IADR0_RAM <= (others => '0'); end if; end if; IBE <= DBE; else -- DP port address if(DP_IADR(L2IMEM_SIZE+2-1 downto 2) < IMEM_SIZE) then IADR0_RAM <= DP_IADR(L2IMEM_SIZE+2-1 downto 2); else IADR0_RAM <= (others => '0'); end if; IBE <= (others => '1'); end if; IADR0_RAM_WS <= '0'; end process; end generate; -- GPO_0 end generate; -- GPX5_0 -- Inst. RAM read/write port WE has two possible -- sources: -- 1) DP port WE -- 2) data port #0 WE -- inst. RAM read/write port write-enable IWE0_RAM <= (DWE0 and not DIMS(0)) when (HALT = '0') else (DP_WE_i and not DP_ADR_MS); -- DP port and data port #0 provide only SDLEN bit -- of data, which are mapped both the lower and upper -- halves of instruction RAM data word, the selection -- of the half to be actually written to memory being -- performed through byte-enable signals. -- inst. RAM data-in IDI_RAM(ILEN-1 downto 0) <= DDATO when (HALT = '0') else DP_DAT_i; GPX1_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate IDI_RAM(ILEN*2-1 downto ILEN) <= DDATO when (HALT = '0') else DP_DAT_i; end generate; -- GPX1_1 GPX1_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate IDI_RAM(ILEN*2-1 downto ILEN) <= (others => '0'); end generate; -- GPX1_0 -- Inst. RAM byte-enable signals, in every cycle only -- the lower 4 bits or the upper 4 bits can be non-zero. -- Mapping of DP port or data port DBE signals on -- lower/upper 4 bits being controlled by DP or data -- port address LSb. GPX2_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate IBE0_RAM(4-1 downto 0) <= IBE when (IADR0_RAM_WS = '0') else (others => '0'); IBE0_RAM(8-1 downto 4) <= IBE when (IADR0_RAM_WS = '1') else (others => '0'); end generate; -- GPX2_1 GPX2_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate IBE0_RAM(4-1 downto 0) <= IBE; IBE0_RAM(8-1 downto 4) <= (others => '0'); end generate; -- GPX2_0 GPX3_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate -- Inst. RAM read-only address (2-word address) IADR1_RAM_PX <= IADR1(L2IMEM_SIZE+2-1 downto 3); end generate; -- GPX3_1 GPX3_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate -- Inst. RAM read-only address (1-word address) IADR1_RAM <= IADR1(L2IMEM_SIZE+2-1 downto 2); end generate; -- GPX3_0 -- Data-out word selector must be latched to account for -- RAM sync. behavior. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then IADR0_RAM_WS_q <= IADR0_RAM_WS; end if; end process; GPX4_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate -- Select word of instruction memory data-out (2 words) -- to be sent to CPU. IDATI <= IDATI_RAM(ILEN*2-1 downto ILEN) when IADR0_RAM_WS_q = '1' else IDATI_RAM(ILEN-1 downto 0); end generate; -- GPX4_1 GPX4_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate IDATI <= IDATI_RAM(ILEN-1 downto 0); end generate; -- GPX4_0 --------------------------------------------------- -- Data memory signals --------------------------------------------------- -- Data RAM port #0 is used for DP and therfore the related -- address, data-in and write-enable signals are driven by -- DP port when DMA-enable signals HALT is asserted. -- Data RAM port #0 is a read-only port and thus doesn't have -- associated data-in and write-enable signals. -- Note: DADR0/1 are byte addresses, while data RAM is accessed -- using word addresses, therefore DADR0/1 LS 2 bits must be -- discarded. GPO2_1: if(DMEM_SIZE_PO2 = '1') generate -- Data memory size is a power-of-2: address is generated -- as a simple subset of DADR0 or DP_ADR. DADR0_RAM <= DADR0(L2DMEM_SIZE+2-1 downto 2) when (HALT = '0') else DP_DADR(L2DMEM_SIZE+2-1 downto 2); GPX_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate DADR1_RAM <= DADR1(L2DMEM_SIZE+2-1 downto 2); end generate; GPX_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate DADR1_RAM <= (others => '0'); end generate; end generate; GPO2_0: if(DMEM_SIZE_PO2 = '0') generate -- Data memory size is NOT a power-of-2: address is generated -- as a subset of DADR0 or DP_ADR, except when it exceeds -- memory size (when this occur, address is forced to all-0). process(DADR0,DP_DADR,HALT) begin if(HALT = '0') then if(DADR0((L2DMEM_SIZE+2)-1 downto 2) < DMEM_SIZE) then DADR0_RAM <= DADR0((L2DMEM_SIZE+2)-1 downto 2); else DADR0_RAM <= (others => '0'); end if; else if(DP_DADR((L2DMEM_SIZE+2)-1 downto 2) < DMEM_SIZE) then DADR0_RAM <= DP_DADR((L2DMEM_SIZE+2)-1 downto 2); else DADR0_RAM <= (others => '0'); end if; end if; end process; GPX_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate process(DADR1) begin if(DADR1((L2DMEM_SIZE+2)-1 downto 2) < DMEM_SIZE) then DADR1_RAM <= DADR1((L2DMEM_SIZE+2)-1 downto 2); else DADR1_RAM <= (others => '0'); end if; end process; end generate; GPX_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate DADR1_RAM <= (others => '0'); end generate; end generate; -- data RAM write-enable DWE0_RAM <= (DWE0 and DIMS(0) and not(IOMS(0))) when (HALT = '0') else (DP_WE_i and DP_ADR_MS and not(DP_IOADR_MS)); -- data RAM data-in DDI_RAM <= DDATO when HALT = '0' else DP_DAT_i; -- CPU data-in (supplied either by instruction memory, data memory -- or some I/O module) DDATI0 <= DDATI0_RAM when (DIMS_q(0) = '1' and IOMS_q(0) = '0') else DDATO_PLIC when (DIMS_q(0) = '1' and IOMS_q(0) = '1') else IDATI; GPX6_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate DDATI1 <= DDATI1_RAM when (DIMS_q(1) = '1' and IOMS_q(1) = '0') else DDATO_PLIC when (DIMS_q(1) = '1' and IOMS_q(1) = '1') else IDATI; end generate; GPX6_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate DDATI1 <= (others => '0'); end generate; DBE_RAM <= DBE when (HALT = '0') else (others => '1'); --------------------------------------------------- -- Data RAM --------------------------------------------------- GPX7_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate -- data RAM is dual-port RAM with 1 read/write port and -- 1 read-only port (two reads, or one read and one write -- can be performed in parallel). U_RAMD : RV01_RAM_1RW1R_BE generic map( DWIDTH => SDLEN, WCOUNT => DMEM_SIZE ) port map( CLK_i => CLK_i, A_i => DADR0_RAM, DPRA_i => DADR1_RAM, D_i => DDI_RAM, WE_i => DWE0_RAM, BE_i => DBE_RAM, Q_o => DDATI0_RAM, DPQ_o => DDATI1_RAM ); end generate; GPX7_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate -- data RAM is single-port RAM with 1 read/write port. U_RAMD : RV01_RAM_1RW_BE generic map( DWIDTH => SDLEN, WCOUNT => DMEM_SIZE ) port map( CLK_i => CLK_i, A_i => DADR0_RAM, D_i => DDI_RAM, WE_i => DWE0_RAM, BE_i => DBE_RAM, Q_o => DDATI0_RAM ); DDATI1_RAM <= (others => '0'); end generate; --------------------------------------------------- -- I/O memory signals --------------------------------------------------- GPX8_1 : if(PARALLEL_EXECUTION_ENABLED = '1') generate process(IOMS,DRE,DWE0,HALT,DADR0,DADR1,DP_ADR_i) begin if(HALT = '0') then -- cpu data memory ports address if(IOMS(0) = '1' and (DRE(0) = '1' or DWE0 = '1')) then -- port #0 address DADR_IO <= DADR0; else -- port #1 address DADR_IO <= DADR1; end if; else -- DP port address DADR_IO <= to_unsigned(DP_ADR_i); end if; end process; end generate; GPX8_0 : if(PARALLEL_EXECUTION_ENABLED = '0') generate process(IOMS,DRE,DWE0,HALT,DADR0,DP_ADR_i) begin if(HALT = '0') then -- port #0 address DADR_IO <= DADR0; else -- DP port address DADR_IO <= to_unsigned(DP_ADR_i); end if; end process; end generate; -- I/O memory write-enable DWE_IO <= (DWE0 and DIMS(0) and IOMS(0)) when (HALT = '0') else (DP_WE_i and DP_ADR_MS and DP_IOADR_MS); -- I/O memory data-in DDATI_IO <= DDATO when HALT = '0' else DP_DAT_i; --------------------------------------------------- -- I/O modules --------------------------------------------------- GPLIC_1 : if(PLIC_PRESENT = '1') generate -- PLIC Module U_PLIC : RV01_PLIC generic map( SRC_CNT => EI_SRC_CNT, TRIG_TYPE => EI_TRIG_TYPE, REQ_MAXCNT => EI_REQ_MAXCNT ) port map( CLK_i => CLK_i, RST_i => RST_i, REG_A_i => DADR_PLIC, REG_WE_i => DWE_PLIC, REG_D_i => DDATI_IO, REQ_i => EI_REQ_i, REG_Q_o => DDATO_PLIC, EIP_o => EXT_INT ); -- PLIC address is a subset of I/O address space. process(DADR_IO) variable TMP : unsigned(ALEN-1 downto 0); begin TMP := DADR_IO/4 - PLIC_ABASE; DADR_PLIC <= to_std_logic_vector(TMP(PLIC_AWIDTH-1 downto 0)); end process; -- PLIC write-enable is set to DWE_IO when I/O address -- falls in PLIC address range. DWE_PLIC <= DWE_IO when (to_unsigned(DADR_PLIC) <= PLIC_AMAX) else '0'; -- PLIC is the only I/O module present, so I/O -- memory data-out is coincident with PLIC data-out. DDATO_IO <= DDATO_PLIC; end generate; -- GPLIC_1 GPLIC_0 : if(PLIC_PRESENT = '0') generate DDATO_PLIC <= (others => '0'); EXT_INT <= '0'; DDATO_IO <= (others => '0'); end generate; -- GPLIC_0 --------------------------------------------------- -- DP port data-out (same as data RAM data-out) --------------------------------------------------- GIOM1_GT0 : if(IOMEM_SIZE > 0) generate DP_DAT_o <= DDATI0_RAM when (DP_ADR_MS_q = '1' and DP_IOADR_MS_q = '0') else DDATO_IO when (DP_ADR_MS_q = '1' and DP_IOADR_MS_q = '1') else IDATI; end generate; GIOM1_EQ0 : if(IOMEM_SIZE = 0) generate DP_DAT_o <= DDATI0_RAM when (DP_ADR_MS_q = '1') else IDATI; end generate; end ARC;