OpenCores
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;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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