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;