OpenCores
URL https://opencores.org/ocsvn/rv01_riscv_core/rv01_riscv_core/trunk

Subversion Repositories rv01_riscv_core

[/] [rv01_riscv_core/] [trunk/] [VHDL/] [RV01_lsu.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 Load/Store Unit
---------------------------------------------------------------
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
 
library work;
use work.RV01_CONSTS_PKG.all;
use work.RV01_TYPES_PKG.all;
use work.RV01_FUNCS_PKG.all;
use work.RV01_ARITH_PKG.all;
use work.RV01_OP_PKG.all;
 
entity RV01_LSU is
  port(
    CLK_i : in std_logic;
    RST_i : in std_logic;
    IV_i : in std_logic;
    LS_OP_i : in LS_OP_T;
    SU_i : in std_logic;
    OPA_i : in SDWORD_T;
    OPB_i : in SDWORD_T;
    IMM_i : in SDWORD_T;
    LDAT_i : in std_logic_vector(SDLEN-1 downto 0);
 
    RE_o : out std_logic;
    WE_o : out std_logic;
    MALGN_o : out std_logic;
    ADR_o : out unsigned(ALEN-1 downto 0);
    SBE_o : out std_logic_vector(4-1 downto 0);
    SDAT_o : out std_logic_vector(SDLEN-1 downto 0);
    LDATV_o : out std_logic;
    LDAT_o : out SDWORD_T
  );
end RV01_LSU;
 
architecture ARC of RV01_LSU is
 
  type SEL_T is (BS,BU,HS,HU);
 
  component RV01_ADDER_F is
    generic(
      LEN1 : integer := 16;
      LEN2 : integer := 16
    );
    port(
      OPA_i : in signed(LEN1+LEN2-1 downto 0);
      OPB_i : in signed(LEN1+LEN2-1 downto 0);
      CI_i : in std_logic;
 
      SUM_o : out signed(LEN1+LEN2-1 downto 0)
    );
  end component;
 
  signal ZERO : std_logic := '0';
  signal RE,WE : std_logic;
  --signal ADR : unsigned(ALEN-1 downto 0);
  signal DDATO : std_logic_vector(SDLEN-1 downto 0);
  signal LDATI_q,LDATI_S : std_logic_vector(16-1 downto 0);
  signal SBE : std_logic_vector(4-1 downto 0);
  signal SDATO : std_logic_vector(SDLEN-1 downto 0);
  signal LDATV_1C : std_logic;
  signal LDATV,LDATV_q,LDATV_q2 : std_logic;
  signal LS_OP_q : LS_OP_T;
  signal SHFT_q : std_logic_vector(2-1 downto 0);
  signal SU_q : std_logic;
  signal SEL,SEL_q : SEL_T;
  signal LDATO : SDWORD_T;
  signal MALGN : std_logic;
  signal ZOPA,ZIMM,ZADR : signed(SDLEN downto 0);
 
begin
 
  ----------------------------------------------
  -- Pipeline organisation
  ----------------------------------------------
 
  -- LSU employs a 3-stage pipeline:
  -- stage 1: load/store address generation.
  -- stage 2: lw data forwarding, lb*/lh* data alignment.
  -- stage 3: lb*/lh* data sign/zero-extension.
 
  -- LSU design is based on the assumption that
  -- lw instructions are far more frequent than
  -- others load instructions and therefore only
  -- their result is made available in second
  -- pipe stage to forwarding logic. Result from
  -- other load instructions is, instead, generated
  -- in third pipe stage and is not avaialble for
  -- forwarding.
 
  -- Note: load/store instructions immediate value
  -- must be provided separately from OPA_i and OPB_i
  -- because OPB_i stores store data!
 
  ----------------------------------------------
  -- 1st pipe stage
  ----------------------------------------------
 
  -- generate load/store address
 
  --process(LS_OP_i,OPA_i,IMM_i)
  --  variable TMP : signed(SDLEN downto 0);
  --begin
  --  -- calculate effective address (extra bit prevents overflow)
  --  TMP := ('0' & OPA_i) + ('0' & IMM_i);
  --  ADR <= to_unsigned(TMP(ALEN-1 downto 0));
  --end process;
 
  ZOPA <= ('0' & OPA_i);
  ZIMM <= ('0' & IMM_i);
 
  U_ADDF : RV01_ADDER_F
    generic map(
      LEN1 => SDLEN/2+1,
      LEN2 => SDLEN/2
    )
    port map(
      OPA_i => ZOPA,
      OPB_i => ZIMM,
      CI_i => ZERO,
      SUM_o => ZADR
    );
 
  -- external memory address
  ADR_o <= to_unsigned(ZADR(ALEN-1 downto 0));
 
  -- generate write-enable flag
  WE <= IV_i when (
    LS_OP_i = LS_SW or
    LS_OP_i = LS_SB or
    LS_OP_i = LS_SH
  ) else '0';
 
  -- external memory write-enable flag
  WE_o <= WE;
 
  -- generate read-enable flag
  RE <= IV_i when (
    LS_OP_i = LS_LB or
    LS_OP_i = LS_LH or
    LS_OP_i = LS_LW
  ) else '0';
 
  -- external memory read-enable flag
  RE_o <= RE;
 
  -- alignment error flag
  process(ZADR,LS_OP_i)
  begin
    case LS_OP_i is
      when LS_SW|LS_LW =>
        MALGN <= ZADR(1) or ZADR(0);
      when LS_SH|LS_LH =>
        MALGN <= ZADR(0);
      when others =>
        MALGN <= '0';
    end case;
  end process;
 
  -- Mis-alignment flag (this flag is used to trigger
  -- exception processing).
 
  MALGN_o <= MALGN;
 
  -- store data alignment and byte-enable flags generation
  process(LS_OP_i,OPB_i,ZADR)
    variable B0,B1,B2,B3 : std_logic_vector(8-1 downto 0);
  begin
    B0 := to_std_logic_vector(OPB_i(8-1 downto 0));
    B1 := to_std_logic_vector(OPB_i(16-1 downto 8));
    B2 := to_std_logic_vector(OPB_i(24-1 downto 16));
    B3 := to_std_logic_vector(OPB_i(32-1 downto 24));
    SBE <= "0000";
    case LS_OP_i is
      when LS_SB =>
        SDATO <= B0 & B0 & B0 & B0;
        case ZADR(2-1 downto 0) is
          when "00" => SBE(0) <= '1';
          when "01" => SBE(1) <= '1';
          when "10" => SBE(2) <= '1';
          when others => SBE(3) <= '1';
        end case;
      when LS_SH =>
        SDATO <= B1 & B0 & B1 & B0;
        if(ZADR(1) = '0') then
          SBE(1 downto 0) <= "11";
        else
          SBE(3 downto 2) <= "11";
        end if;
      when others =>
        SDATO <= B3 & B2 & B1 & B0;
        SBE <= "1111";
    end case;
  end process;
 
  SDAT_o <= SDATO;
  SBE_o <= SBE;
 
  -- lw data valid flag.
  LDATV_1C <= IV_i when (
    LS_OP_i = LS_LW
  ) else '0';
 
  -- lb*/lh* data valid flag
  LDATV <= IV_i when (
    LS_OP_i = LS_LB or
    LS_OP_i = LS_LH
  ) else '0';
 
  -- pipe registers
 
  process(CLK_i)
  begin
    if(CLK_i = '1' and CLK_i'event) then
      if(RST_i = '1') then
        LDATV_q <= '0';
      else
        LDATV_q <= LDATV;
      end if;
      LS_OP_q <= LS_OP_i;
      SU_q <= SU_i;
      SHFT_q <= to_std_logic_vector(ZADR(2-1 downto 0));
    end if;
  end process;
 
  ----------------------------------------------
  -- 2nd pipe stage
  ----------------------------------------------
 
  -- This stage outputs lw data to forward logic
  -- and performs alignment for lb*/lh*.
 
  process(LDAT_i,SHFT_q)  
    variable ZERO24 : std_logic_vector(24-1 downto 0) := (others => '0');
    variable TMP,TMP_S : unsigned(SDLEN-1 downto 0);
  begin
    TMP := to_unsigned(LDAT_i);
    case SHFT_q is
      when "00" => TMP_S := shift_right(TMP,0);
      when "01" => TMP_S := shift_right(TMP,8);
      when "10" => TMP_S := shift_right(TMP,16);
      when others => TMP_S := shift_right(TMP,24);
    end case;
    LDATI_S <= to_std_logic_vector(TMP_S(16-1 downto 0));
  end process;
 
  SEL <=
    BS when (LS_OP_q = LS_LB and SU_q = '1') else
    BU when (LS_OP_q = LS_LB and SU_q = '0') else
    HS when (LS_OP_q = LS_LH and SU_q = '1') else
    HU;
 
  process(CLK_i)
  begin
    if(CLK_i = '1' and CLK_i'event) then
      if(RST_i = '1') then
        LDATV_q2 <= '0';
      else
        LDATV_q2 <= LDATV_q;
      end if;
      LDATI_q <= LDATI_S;
      SEL_q <= SEL;
    end if;
  end process;
 
  ----------------------------------------------
  -- 3rd pipe stage (ls*/lh* data-out)
  ----------------------------------------------
 
  process(LDATI_q,SEL_q)
    variable ZERO16 : signed(16-1 downto 0) := (others => '0');
    variable ZERO24 : signed(24-1 downto 0) := (others => '0');
  begin
    case SEL_q is
      when BS => LDATO <= EXTS32(LDATI_q(8-1 downto 0));
      when BU => LDATO <= ZERO24 & to_signed(LDATI_q(8-1 downto 0));
      when HS => LDATO <= EXTS32(LDATI_q);
      when HU => LDATO <= ZERO16 & to_signed(LDATI_q);
    end case;
  end process;
 
  LDAT_o <= LDATO;
  LDATV_o <= LDATV_q2;
 
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.