URL
https://opencores.org/ocsvn/rv01_riscv_core/rv01_riscv_core/trunk
Subversion Repositories rv01_riscv_core
[/] [rv01_riscv_core/] [trunk/] [VHDL/] [RV01_csru.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 CSR's 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_ARITH_PKG.all; use WORK.RV01_FUNCS_PKG.all; use WORK.RV01_OP_PKG.all; use WORK.RV01_CSR_PKG.all; --use WORK.RV01_CFG_PKG.all; entity RV01_CSRU is generic( PXE : std_logic := '1'; FPU_PRESENT : std_logic := '0'; NW : natural := 2 ); port( CLK_i : in std_logic; RST_i : in std_logic; IX1_V0_i : in std_logic; CS_OP_i : in CS_OP_T; RS1_i : in RID_T; ADR_i : in signed(12-1 downto 0); WE_i : in std_logic; CSRD_i : in SDWORD_T; EXCP_i : in std_logic; EPC_i : in ADR_T; ECAUSE_i : in std_logic_vector(5-1 downto 0); EBADR_i : in ADR_T; ERET_i : in std_logic; IX3_V_i : in std_logic_vector(NW-1 downto 0); NOPR_i : in std_logic; HALT_i : in std_logic; STOPCYCLE_i : in std_logic; STOPTIME_i : in std_logic; -- MFROMHOST_WE_i : in std_logic; MFROMHOST_i : in std_logic_vector(SDLEN-1 downto 0); -- Debug interface DMODE_i : in std_logic; -- debug mode flag DIE_i : in std_logic; -- debug int. enable flag -- Control port CPRE_i : in std_logic; CPWE_i : in std_logic; CPADR_i : in std_logic_vector(17-1 downto 0); CPD_i : in std_logic_vector(SDLEN-1 downto 0); PXE_o : out std_logic; MSTATUS_o : out SDWORD_T; MEPC_o : out ADR_T; MBASE_o : out ADR_T; MBOUND_o : out ADR_T; MIBASE_o : out ADR_T; MIBOUND_o : out ADR_T; MDBASE_o : out ADR_T; MDBOUND_o : out ADR_T; --RSTVA_o : out ADR_T; ETVA_o : out ADR_T; MTOHOST_o : out std_logic_vector(SDLEN-1 downto 0); MTOHOST_OE_o : out std_logic; ILLG_o : out std_logic; SFT_INT_o : out std_logic; TMR_INT_o : out std_logic; FFLAGS_o : out std_logic_vector(5-1 downto 0); FRM_o : out std_logic_vector(3-1 downto 0); IE_o : out std_logic; CSRQ_o : out SDWORD_T; -- Control port CPQ_o : out std_logic_vector(SDLEN-1 downto 0) ); end RV01_CSRU; architecture ARC of RV01_CSRU is constant MAX_CNT : natural := 2147483647; --2**(SDLEN-1)-1; constant MSIP : natural := 3; constant MTIP : natural := 7; constant MSIE : natural := 3; constant MTIE : natural := 7; signal CS_OP_q : CS_OP_T; signal CS_OP_V : std_logic; signal CSRD_q,ICSRD : SDWORD_T; signal RS1_q : RID_T; signal WE_q,IWE : std_logic; signal ADR_q : signed(12-1 downto 0); signal MSTATUS_q : SDWORD_T; signal MTVEC_q : SDWORD_T; signal MIE_q : SDWORD_T; --signal MTIMECMP_q : SDWORD_T; signal MTIMECMP_q : natural range 0 to MAX_CNT; signal MTIME,MTIME_q,MTIME_q2 : natural range 0 to MAX_CNT; signal MTIMEH,MTIMEH_q : natural range 0 to MAX_CNT; signal MTIME_INC,MTIMEH_INC : std_logic; signal MSCRATCH_q : SDWORD_T; signal MEPC_q : SDWORD_T; signal MCAUSE_q : SDWORD_T; signal MBADADDR_q : SDWORD_T; signal MIP_q : SDWORD_T; signal MBASE_q : SDWORD_T; signal MBOUND_q : SDWORD_T; signal MIBASE_q : SDWORD_T; signal MIBOUND_q : SDWORD_T; signal MDBASE_q : SDWORD_T; signal MDBOUND_q : SDWORD_T; signal MTDELEG_q : SDWORD_T; signal MTOHOST_q : SDWORD_T; signal MFROMHOST_q : SDWORD_T; signal MRV01CC_q : SDWORD_T; signal CSRQ,CSRQ_q,CSRQ_q2 : SDWORD_T; signal ILLG,ILLG_q,ILLG_q2 : std_logic; signal ADR_ERR : std_logic; signal TMR_MTCH,TMR_INT,TMR_INT_q : std_logic; signal SFT_INT,SFT_INT_q : std_logic; signal MMODE : std_logic; signal MTOHOST_OE,MTOHOST_OE_q : std_logic; signal UCYCLE,UCYCLE_q,UCYCLE_q2 : natural range 0 to MAX_CNT; signal UCYCLEH,UCYCLEH_q : natural range 0 to MAX_CNT; signal UINSTRET,UINSTRET_q,UINSTRET_q2 : natural range 0 to MAX_CNT; signal UINSTRETH,UINSTRETH_q : natural range 0 to MAX_CNT; signal USTATS_q : SDWORD_T; signal UCYCLEH_INC,UINSTRETH_INC : std_logic; signal UFCSR_q : SDWORD_T; signal UFRM_q : SDWORD_T; signal VM : std_logic_vector(4-1 downto 0); signal IADR,IADR_q : unsigned(12-1 downto 0); --signal RSTVA_q : ADR_T; signal UTRPVA_q : ADR_T; signal MTRPVA_q : ADR_T; signal IBASE : ADR_T; signal DBASE : ADR_T; signal CPQ : SDWORD_T; signal CP_WE_q : std_logic; signal CP_IADR,CP_IADR_q : unsigned(12-1 downto 0); signal CP_D_q : SDWORD_T; function push_stack( S : SDWORD_T; D : std_logic_vector(3-1 downto 0) ) return SDWORD_T is variable TMP : SDWORD_T; begin TMP(SDLEN-1 downto 12) := S(SDLEN-1 downto 12); TMP(12-1 downto 3) := S(9-1 downto 0); TMP(3-1 downto 0) := to_signed(D); return(TMP); end function; function pop_stack( S : SDWORD_T; D : std_logic_vector(3-1 downto 0) ) return SDWORD_T is variable TMP : SDWORD_T; begin TMP(SDLEN-1 downto 12) := S(SDLEN-1 downto 12); TMP(12-1 downto 9) := to_signed(D); TMP(9-1 downto 0) := S(12-1 downto 3); return(TMP); end function; function update_csr( PREVD : SDWORD_T; MSK : SDWORD_T; NEWD : SDWORD_T ) return SDWORD_T is variable TMP1,TMP2,TMP3 : SDWORD_T; begin -- clear new data non-writable bits TMP1 := NEWD and MSK; -- clear previous data writable bits TMP2 := PREVD and not(MSK); -- build merged data TMP3 := TMP1 or TMP2; return(TMP3); end function; begin ---------------------------------------------- IADR <= to_unsigned(ADR_i); process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then WE_q <= '0'; else WE_q <= WE_i; end if; CS_OP_q <= CS_OP_i; IADR_q <= IADR; CSRD_q <= CSRD_i; RS1_q <= RS1_i; end if; end process; IWE <= WE_q and not(HALT_i); ---------------------------------------------- CP_IADR <= to_unsigned(CPADR_i(14-1 downto 2)); process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then CP_WE_q <= '0'; else CP_WE_q <= CPWE_i and CPADR_i(16); end if; end if; end process; process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then CP_IADR_q <= CP_IADR; CP_D_q <= to_signed(CPD_i); end if; end process; ---------------------------------------------- process(CS_OP_q,CSRD_q,RS1_q,CSRQ_q) variable ZXRS1 : SDWORD_T; begin -- zero-extended RS1 ZXRS1(log2(REGNUM)-1 downto 0) := to_signed(RS1_q,log2(REGNUM)); ZXRS1(SDLEN-1 downto log2(REGNUM)) := (others => '0'); case CS_OP_q is when CS_RW => ICSRD <= CSRD_q; when CS_RS => if(RS1_q = 0) then ICSRD <= CSRD_q; else ICSRD <= CSRQ_q or CSRD_q; end if; when CS_RC => if(RS1_q = 0) then ICSRD <= CSRD_q; else ICSRD <= CSRQ_q and not(CSRD_q); end if; when CS_RWI => ICSRD <= ZXRS1; when CS_RSI => if(RS1_q = 0) then ICSRD <= CSRD_q; else ICSRD <= CSRQ_q or ZXRS1; end if; when CS_RCI => if(RS1_q = 0) then ICSRD <= CSRD_q; else ICSRD <= CSRQ_q and not(ZXRS1); end if; when others => ICSRD <= CSRD_q; end case; end process; CS_OP_V <= IX1_V0_i when ( CS_OP_i = CS_RW or CS_OP_i = CS_RS or CS_OP_i = CS_RC or CS_OP_i = CS_RWI or CS_OP_i = CS_RSI or CS_OP_i = CS_RCI ) else '0'; ---------------------------------------------- -- MSTATUS register ---------------------------------------------- -- Note: mode/IE stack is used to handle debug -- mode too, this however works only if supervisor -- and hypervisor modes are not implemented (otherwise -- a mode/IE pair may get deleted). process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MSTATUS_q <= MSTATUS_RST; elsif(CP_WE_q = '1' and CP_IADR_q = MSTATUS_ADR and DMODE_i = '1') then MSTATUS_q <= update_csr(MSTATUS_q,MSTATUS_WMSK,CP_D_q); elsif(IWE = '1' and IADR_q = MSTATUS_ADR and MMODE = '1') then MSTATUS_q <= update_csr(MSTATUS_q,MSTATUS_WMSK,ICSRD); elsif(EXCP_i = '1') then MSTATUS_q <= push_stack(MSTATUS_q,"110"); elsif(ERET_i = '1') then MSTATUS_q <= pop_stack(MSTATUS_q,"001"); end if; end if; end process; -- Machine mode flag MMODE <= '1' when ( MSTATUS_q(2 downto 1) = "11" or DMODE_i = '1' ) else '0'; -- Interrupt Enable flag IE_o <= '0' when ( (DMODE_i = '1') or (DIE_i = '0') ) else MSTATUS_q(0); -- Virtual addressing env. VM <= to_std_logic_vector(MSTATUS_q(21 downto 18)); MSTATUS_o <= MSTATUS_q; ---------------------------------------------- -- MTVEC register ---------------------------------------------- -- MTVEC is a R/W register, but only MTVEC_LO and -- MTVEC_HI patterns can be written to it. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MTVEC_q <= to_signed(MTVEC_LO); elsif(CP_WE_q = '1' and CP_IADR_q = MTVEC_ADR and DMODE_i = '1') then MTVEC_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MTVEC_ADR and MMODE = '1') then if(to_unsigned(ICSRD) = MTVEC_LO) then MTVEC_q <= to_signed(MTVEC_LO); elsif(to_unsigned(ICSRD) = MTVEC_HI) then MTVEC_q <= to_signed(MTVEC_HI); end if; end if; end if; end process; -- Set reset, user mode trap and machine mode trap vectors -- according to mtvec value (at reset, trap vectors location -- is set to "low"). process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then UTRPVA_q <= UTRAP_VA_LO; MTRPVA_q <= MTRAP_VA_LO; elsif(CP_WE_q = '1' and CP_IADR_q = MTVEC_ADR and DMODE_i = '1') then if(to_unsigned(CP_D_q) = MTVEC_LO) then UTRPVA_q <= UTRAP_VA_LO; MTRPVA_q <= MTRAP_VA_LO; elsif(to_unsigned(CP_D_q) = MTVEC_HI) then UTRPVA_q <= UTRAP_VA_HI; MTRPVA_q <= MTRAP_VA_HI; end if; elsif(IWE = '1' and IADR_q = MTVEC_ADR and MMODE = '1') then if(to_unsigned(ICSRD) = MTVEC_LO) then UTRPVA_q <= UTRAP_VA_LO; MTRPVA_q <= MTRAP_VA_LO; elsif(to_unsigned(ICSRD) = MTVEC_HI) then UTRPVA_q <= UTRAP_VA_HI; MTRPVA_q <= MTRAP_VA_HI; end if; end if; end if; end process; -- exception trap vector address ETVA_o <= MTRPVA_q when MMODE = '1' else UTRPVA_q; ---------------------------------------------- -- MTDELEG register ---------------------------------------------- -- This register is not implemented. MTDELEG_q <= (others => '0'); ---------------------------------------------- -- MIE register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MIE_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MIE_ADR and DMODE_i = '1') then MIE_q <= update_csr(MIE_q,MIE_WMSK,CP_D_q); elsif(IWE = '1' and IADR_q = MIE_ADR and MMODE = '1') then MIE_q <= update_csr(MIE_q,MIE_WMSK,ICSRD); end if; end if; end process; ---------------------------------------------- -- MTIMECMP register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MTIMECMP_q <= 0; elsif(CP_WE_q = '1' and CP_IADR_q = MTIMECMP_ADR and DMODE_i = '1') then MTIMECMP_q <= to_integer(CP_D_q); elsif(IWE = '1' and IADR_q = MTIMECMP_ADR and MMODE = '1') then MTIMECMP_q <= to_integer(ICSRD); end if; end if; end process; -- TMR_INT_q remains asserted after an TMR_INT pulse -- until this event can be recorded in MIP register -- (this precaution is needed to insure that TMR_INT -- pulse is not lost because of a write to MIP). TMR_INT <= '1' when (MTIMECMP_q = MTIME_q) else '0'; --process(CLK_i) --begin -- if(CLK_i = '1' and CLK_i'event) then -- if(RST_i = '1') then -- TMR_INT_q <= '0'; -- elsif(TMR_INT_q = '0' and TMR_INT = '1') then -- TMR_INT_q <= '1'; -- elsif(MIP_q(MTIE) = '1') then -- TMR_INT_q <= '0'; -- end if; -- end if; --end process; ---------------------------------------------- -- MTIME register -- (Machine Mode Cycles counter) ---------------------------------------------- -- mcycle register is incremented at every cycle, -- and wraps-up when count reaches MAX_CNT value. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MTIME_q <= 0; elsif(CP_WE_q = '1' and CP_IADR_q = MTIME_ADR and DMODE_i = '1') then MTIME_q <= to_integer(CP_D_q); elsif(IWE = '1' and IADR_q = MTIME_ADR and MMODE = '1') then MTIME_q <= to_integer(ICSRD); else MTIME_q <= MTIME; end if; MTIME_q2 <= MTIME_q; end if; end process; process(MTIME_q) begin if(MTIME_q < MAX_CNT) then MTIME <= MTIME_q + 1; MTIMEH_INC <= '0'; else MTIME <= 0; MTIMEH_INC <= '1'; end if; end process; -- ucycleh register is incremented when ucycle -- one wraps-up. ucycleh wraps-up when count -- reaches MAX_CNT value. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MTIMEH_q <= 0; elsif(CP_WE_q = '1' and CP_IADR_q = MTIMEH_ADR and DMODE_i = '1') then MTIMEH_q <= to_integer(CP_D_q); elsif(IWE = '1' and IADR_q = MTIMEH_ADR and MMODE = '1') then MTIMEH_q <= to_integer(ICSRD); elsif(MTIMEH_INC = '1') then MTIMEH_q <= MTIMEH; end if; end if; end process; process(MTIMEH_q) begin if(MTIMEH_q < MAX_CNT) then MTIMEH <= MTIMEH_q + 1; else MTIMEH <= 0; end if; end process; ---------------------------------------------- -- MSCRATCH register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MSCRATCH_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MSCRATCH_ADR and DMODE_i = '1') then MSCRATCH_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MSCRATCH_ADR and MMODE = '1') then MSCRATCH_q <= ICSRD; --CSRD_q; end if; end if; end process; ---------------------------------------------- -- MEPC register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MEPC_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MEPC_ADR and DMODE_i = '1') then MEPC_q <= update_csr(MEPC_q,MEPC_WMSK,CP_D_q); elsif(IWE = '1' and IADR_q = MEPC_ADR and MMODE = '1') then MEPC_q <= update_csr(MEPC_q,MEPC_WMSK,ICSRD); elsif(EXCP_i = '1') then MEPC_q <= to_signed(EPC_i); end if; end if; end process; -- mepc content must be made available to fetch -- logic when returning from an exception. MEPC_o <= to_unsigned(MEPC_q); ---------------------------------------------- -- MCAUSE register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MCAUSE_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MCAUSE_ADR and DMODE_i = '1') then MCAUSE_q <= update_csr(MCAUSE_q,MCAUSE_WMSK,CP_D_q); elsif(IWE = '1' and IADR_q = MCAUSE_ADR and MMODE = '1') then MCAUSE_q <= update_csr(MCAUSE_q,MCAUSE_WMSK,ICSRD); elsif(EXCP_i = '1') then MCAUSE_q(SDLEN-2 downto 4) <= (others => '0'); if(ECAUSE_i = UMCALL and MMODE = '1') then MCAUSE_q(4-1 downto 0) <= to_signed(MMCALL(4-1 downto 0)); else MCAUSE_q(4-1 downto 0) <= to_signed(ECAUSE_i(4-1 downto 0)); end if; MCAUSE_q(SDLEN-1) <= ECAUSE_i(4); end if; end if; end process; ---------------------------------------------- -- MBADADDR register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MBADADDR_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MBADADDR_ADR and DMODE_i = '1') then MBADADDR_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MBADADDR_ADR and MMODE = '1') then MBADADDR_q <= ICSRD; elsif(EXCP_i = '1') then MBADADDR_q <= to_signed(EBADR_i); end if; end if; end process; ---------------------------------------------- -- MIP register ---------------------------------------------- -- Note: while timer interrupt pending bit is implicilty -- cleared by writing mtimecmp register, software interrupt -- pending bit must be explicitly cleared by writing mip -- register. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MIP_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MIP_ADR and DMODE_i = '1') then MIP_q <= update_csr(MIP_q,MIP_WMSK,CP_D_q); elsif(IWE = '1' and IADR_q = MIP_ADR and MMODE = '1') then -- mip is written as a CSR (even if only MSIP bit is writable) MIP_q <= update_csr(MIP_q,MIP_WMSK,ICSRD); elsif(TMR_INT = '1') then MIP_q(MTIP) <= '1'; elsif( (IWE = '1' and IADR_q = MTIMECMP_ADR and MMODE = '1') or (CP_WE_q = '1' and CP_IADR_q = MTIMECMP_ADR and DMODE_i = '1') ) then -- mip[MTIP] is cleared when mtimecmp register is written MIP_q(MTIP) <= '0'; end if; end if; end process; -- Timer Interrupt exception is actually raised only if: -- 1) mip[MTIP] is set, AND -- 2) timer int's are enabled by mie[MTIE], AND -- 3) exceptions are anabled by mstatus[IE]. TMR_INT_o <= MIP_q(MTIP) and MIE_q(MTIE) and MSTATUS_q(0); --process(CLK_i) --begin -- if(CLK_i = '1' and CLK_i'event) then -- if(RST_i = '1') then -- TMR_INT_q <= '0'; -- else -- TMR_INT_q <= TMR_INT; -- end if; -- end if; --end process; --TMR_INT_o <= TMR_INT_q; -- Soft Interrupt exception is actually raised only if: -- 1) mip[MSIP] is set, AND -- 2) soft int's are enabled by mie[MSIE], AND -- 3) exceptions are anabled by mstatus[IE]. SFT_INT <= MIP_q(MSIP) and MIE_q(MSIE) and MSTATUS_q(0); process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then SFT_INT_q <= '0'; else SFT_INT_q <= SFT_INT; end if; end if; end process; SFT_INT_o <= SFT_INT_q; ---------------------------------------------- -- MBASE register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MBASE_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MBASE_ADR and DMODE_i = '1') then MBASE_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MBASE_ADR and MMODE = '1') then MBASE_q <= ICSRD; end if; end if; end process; MBASE_o <= to_unsigned(MBASE_q); ---------------------------------------------- -- MBOUND register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MBOUND_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MBOUND_ADR and DMODE_i = '1') then MBOUND_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MBOUND_ADR and MMODE = '1') then MBOUND_q <= ICSRD; end if; end if; end process; MBOUND_o <= to_unsigned(MBOUND_q); ---------------------------------------------- -- MIBASE register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MIBASE_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MIBASE_ADR and DMODE_i = '1') then MIBASE_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MIBASE_ADR and MMODE = '1') then MIBASE_q <= ICSRD; elsif( IWE = '1' and IADR_q = MBASE_ADR and MMODE = '1' and VM = MBBID ) then MIBASE_q <= ICSRD; end if; end if; end process; MIBASE_o <= to_unsigned(MIBASE_q); ---------------------------------------------- -- MIBOUND register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MIBOUND_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MIBOUND_ADR and DMODE_i = '1') then MIBOUND_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MIBOUND_ADR and MMODE = '1') then MIBOUND_q <= ICSRD; elsif( IWE = '1' and IADR_q = MBOUND_ADR and MMODE = '1' and VM = MBBID ) then MIBOUND_q <= ICSRD; end if; end if; end process; MIBOUND_o <= to_unsigned(MIBOUND_q); ---------------------------------------------- -- MDBASE register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MDBASE_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MDBASE_ADR and DMODE_i = '1') then MDBASE_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MDBASE_ADR and MMODE = '1') then MDBASE_q <= ICSRD; elsif( IWE = '1' and IADR_q = MBASE_ADR and MMODE = '1' and VM = MBBID ) then MDBASE_q <= ICSRD; end if; end if; end process; MDBASE_o <= to_unsigned(MDBASE_q); ---------------------------------------------- -- MDBOUND register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MDBOUND_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MDBOUND_ADR and DMODE_i = '1') then MDBOUND_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MDBOUND_ADR and MMODE = '1') then MDBOUND_q <= ICSRD; elsif( IWE = '1' and IADR_q = MBOUND_ADR and MMODE = '1' and VM = MBBID ) then MDBOUND_q <= ICSRD; end if; end if; end process; MDBOUND_o <= to_unsigned(MDBOUND_q); ---------------------------------------------- -- MTOHOST register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MTOHOST_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MTOHOST_ADR and DMODE_i = '1') then MTOHOST_q <= CP_D_q; elsif(IWE = '1' and IADR_q = MTOHOST_ADR and MMODE = '1') then MTOHOST_q <= ICSRD; end if; end if; end process; MTOHOST_OE <= IWE when( IADR_q = MTOHOST_ADR and MMODE = '1' ) else '0'; process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MTOHOST_OE_q <= '0'; else MTOHOST_OE_q <= MTOHOST_OE ; end if; end if; end process; MTOHOST_OE_o <= MTOHOST_OE_q; MTOHOST_o <= to_std_logic_vector(MTOHOST_q); ---------------------------------------------- -- MFROMHOST register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MFROMHOST_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = MFROMHOST_ADR and DMODE_i = '1') then MFROMHOST_q <= CP_D_q; elsif(MFROMHOST_WE_i = '1') then MFROMHOST_q <= to_signed(MFROMHOST_i); elsif(IWE = '1' and IADR_q = MFROMHOST_ADR and MMODE = '1') then MFROMHOST_q <= ICSRD; end if; end if; end process; ---------------------------------------------- -- RV01 Core Control register (MRV01CC) ---------------------------------------------- -- This register allows to enable/disable -- implementation dependent features. In the -- this version of RV01 core, the only feature -- that can be enabled/disabled through MRV01CC -- register is parallel execution capability. GPXE_1 : if(PXE = '1') generate process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then MRV01CC_q <= MRV01CC_RST; elsif(CP_WE_q = '1' and CP_IADR_q = MRV01CC_ADR and DMODE_i = '1') then MRV01CC_q <= update_csr(MRV01CC_q,MRV01CC_WMSK,CP_D_q); elsif(IWE = '1' and IADR_q = MRV01CC_ADR and MMODE = '1') then MRV01CC_q <= update_csr(MRV01CC_q,MRV01CC_WMSK,ICSRD); end if; end if; end process; end generate; GPXE_0 : if(PXE = '0') generate MRV01CC_q <= (others => '0'); end generate; PXE_o <= MRV01CC_q(0); ---------------------------------------------- -- UTIME/H registers -- (User Mode Cycles counter) ---------------------------------------------- -- ucycle register is incremented at every cycle, -- and wraps-up when count reaches MAX_CNT value. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then UCYCLE_q <= 0; else UCYCLE_q <= UCYCLE; end if; UCYCLE_q2 <= UCYCLE_q; end if; end process; process(UCYCLE_q,STOPCYCLE_i,STOPTIME_i) begin if(UCYCLE_q < MAX_CNT and STOPCYCLE_i = '0' and STOPTIME_i = '0') then UCYCLE <= UCYCLE_q + 1; UCYCLEH_INC <= '0'; else UCYCLE <= 0; UCYCLEH_INC <= '1'; end if; end process; -- ucycleh register is incremented when ucycle -- one wraps-up. ucycleh wraps-up when count -- reaches MAX_CNT value. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then UCYCLEH_q <= 0; elsif(UCYCLEH_INC = '1' and STOPCYCLE_i = '0' and STOPTIME_i = '0') then UCYCLEH_q <= UCYCLEH; end if; end if; end process; process(UCYCLEH_q) begin if(UCYCLEH_q < MAX_CNT) then UCYCLEH <= UCYCLEH_q + 1; else UCYCLEH <= 0; end if; end process; ---------------------------------------------- -- Retired instructions counter ---------------------------------------------- -- uinstret register is incremented every time -- an instruction is retired (this event may occur -- twice per cycle), and wraps-up when count reaches -- MAX_CNT value. -- Instruction eret is a special case because it -- must be counted as a valid instruction even if -- its valid bit is cleared. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then UINSTRET_q <= 0; else UINSTRET_q <= UINSTRET; end if; UINSTRET_q2 <= UINSTRET_q; end if; end process; process(UINSTRET_q,IX3_V_i,ERET_i,STOPCYCLE_i) begin if(IX3_V_i = "11" and STOPCYCLE_i = '0') then if(UINSTRET_q < MAX_CNT-1) then UINSTRET <= UINSTRET_q + 2; UINSTRETH_INC <= '0'; elsif(UINSTRET_q = MAX_CNT-1) then UINSTRET <= 0; UINSTRETH_INC <= '1'; else UINSTRET <= 1; UINSTRETH_INC <= '1'; end if; elsif((IX3_V_i(0) = '1' or IX3_V_i(1) = '1') and STOPCYCLE_i = '0') then if(UINSTRET_q < MAX_CNT) then UINSTRET <= UINSTRET_q + 1; UINSTRETH_INC <= '0'; else UINSTRET <= 0; UINSTRETH_INC <= '1'; end if; else UINSTRET <= UINSTRET_q; UINSTRETH_INC <= '0'; end if; end process; -- uinstreth register is incremented when uinstret -- one wraps-up. uinstreth wraps-up when count -- reaches MAX_CNT value. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then UINSTRETH_q <= 0; elsif(UINSTRETH_INC = '1' and STOPCYCLE_i = '0') then UINSTRETH_q <= UINSTRETH; end if; end if; end process; process(UINSTRETH_q) begin if(UINSTRETH_q < MAX_CNT) then UINSTRETH <= UINSTRETH_q + 1; else UINSTRETH <= 0; end if; end process; ---------------------------------------------- -- UFCSR, UFFLAGS and UFRM registers ---------------------------------------------- GF0_1 : if(FPU_PRESENT = '1') generate -- UFFLAGS register is implicitly implemented by UFCSR[4:0], -- while UFRM is explicitly implemented. -- A write to UFCSR modifies UFFLAGS[4:0] (implicitly) and -- UFRM[2:0] (explicitly). -- A write to UFFLAGS modifies UFCSR bits [4:0] only. -- A write to UFRM modifies UFRM and UFCSR bits [7:5]. process(CLK_i) variable TMP : SDWORD_T; begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then UFCSR_q <= (others => '0'); elsif(IWE = '1' and IADR_q = UFCSR_ADR) then UFCSR_q <= update_csr(UFCSR_q,UFCSR_WMSK,ICSRD); elsif(IWE = '1' and IADR_q = UFFLAGS_ADR) then UFCSR_q <= update_csr(UFCSR_q,UFFLAGS_WMSK,ICSRD); elsif(IWE = '1' and IADR_q = UFRM_ADR) then TMP := update_csr(UFRM_q,UFRM_WMSK,ICSRD); UFCSR_q <= UFCSR_q(SDLEN-1 downto 8) & TMP(3-1 downto 0) & UFCSR_q(5-1 downto 0) ; end if; end if; end process; process(CLK_i) variable TMP : SDWORD_T; begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then UFRM_q <= (others => '0'); elsif(IWE = '1' and IADR_q = UFCSR_ADR) then TMP := update_csr(UFCSR_q,UFCSR_WMSK,ICSRD); UFRM_q <= UFRM_q(SDLEN-1 downto 3) & TMP(3-1 downto 0); elsif(IWE = '1' and IADR_q = UFRM_ADR) then UFRM_q <= update_csr(UFRM_q,UFRM_WMSK,ICSRD); end if; end if; end process; FFLAGS_o <= to_std_logic_vector(UFCSR_q(5-1 downto 0)); FRM_o <= to_std_logic_vector(UFCSR_q(8-1 downto 5)); end generate; GF0_0 : if(FPU_PRESENT = '0') generate UFCSR_q <= (others => '0'); UFRM_q <= (others => '0'); FFLAGS_o <= (others => '0'); FRM_o <= (others => '0'); end generate; ---------------------------------------------- -- Sodor "Stats" register ---------------------------------------------- -- This register has been added only for partial -- compatibility with Sodor RISC-V core. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(IWE = '1' and IADR_q = USTATS_ADR) then USTATS_q <= ICSRD; end if; end if; end process; ---------------------------------------------- -- CSR output mux ---------------------------------------------- -- Notes: -- 1) utime(h) register is coincident with ucycle(h) register. -- 2) ucycleh and uinstreth are updated with one cycle delay -- with respect to ucycle and uinstret, therefore, in order to -- get consistent read values, one-cycle delayed version of -- ucycle and uinstret are accessed on reads. -- 3) mtime register is implemented as mcycle for a matter of -- uniformity with utime one. -- 4) one-cycle delayed version of mcycle is accessed on reads -- (see note #2). process(IADR,MSTATUS_q,MTVEC_q,MIE_q,MTIMECMP_q,MTIME_q2,MTIMEH_q, MSCRATCH_q,MEPC_q,MCAUSE_q,MBADADDR_q,MIP_q,MBASE_q,MBOUND_q, MIBASE_q,MIBOUND_q,MDBASE_q,MDBOUND_q,MTOHOST_q,MFROMHOST_q, UCYCLE_q2,UINSTRET_q2,UCYCLEH_q,UINSTRETH_q,UFCSR_q,UFRM_q,USTATS_q, MTDELEG_q,MRV01CC_q,VM,WE_i,MMODE ) begin ADR_ERR <= '0'; case IADR is -- User mode CSR's when UCYCLE_ADR => CSRQ <= to_signed(UCYCLE_q2,SDLEN); ADR_ERR <= WE_i; when UTIME_ADR => CSRQ <= to_signed(UCYCLE_q2,SDLEN); ADR_ERR <= WE_i; when UINSTRET_ADR => CSRQ <= to_signed(UINSTRET_q2,SDLEN); ADR_ERR <= WE_i; when UCYCLEH_ADR => CSRQ <= to_signed(UCYCLEH_q,SDLEN); ADR_ERR <= WE_i; when UTIMEH_ADR => CSRQ <= to_signed(UCYCLEH_q,SDLEN); ADR_ERR <= WE_i; when UINSTRETH_ADR => CSRQ <= to_signed(UINSTRETH_q,SDLEN); ADR_ERR <= WE_i; when UFCSR_ADR => CSRQ <= UFCSR_q; when UFFLAGS_ADR => CSRQ(5-1 downto 0) <= UFCSR_q(5-1 downto 0); CSRQ(SDLEN-1 downto 5) <= (others => '0'); when UFRM_ADR => CSRQ <= UFRM_q; when USTATS_ADR => CSRQ <= USTATS_q; -- Machine mode CSR's when MCPUID_ADR => CSRQ <= MCPUID_RO; ADR_ERR <= WE_i or not(MMODE); when MIMPID_ADR => CSRQ <= MIMPID_RO; ADR_ERR <= WE_i or not(MMODE); when MHARTID_ADR => CSRQ <= MHARTID_RO; ADR_ERR <= WE_i or not(MMODE); when MSTATUS_ADR => CSRQ <= MSTATUS_q; ADR_ERR <= not(MMODE); when MTVEC_ADR => CSRQ <= MTVEC_q; ADR_ERR <= not(MMODE); when MTDELEG_ADR => CSRQ <= MTDELEG_q; ADR_ERR <= WE_i or not(MMODE); when MIE_ADR => CSRQ <= MIE_q; ADR_ERR <= not(MMODE); when MTIMECMP_ADR => CSRQ <= to_signed(MTIMECMP_q,SDLEN); ADR_ERR <= not(MMODE); when MTIME_ADR => CSRQ <= to_signed(MTIME_q2,SDLEN); ADR_ERR <= not(MMODE); when MTIMEH_ADR => CSRQ <= to_signed(MTIMEH_q,SDLEN); ADR_ERR <= not(MMODE); when MSCRATCH_ADR => CSRQ <= MSCRATCH_q; ADR_ERR <= not(MMODE); when MEPC_ADR => CSRQ <= MEPC_q; ADR_ERR <= not(MMODE); when MCAUSE_ADR => CSRQ <= MCAUSE_q; ADR_ERR <= not(MMODE); when MBADADDR_ADR => CSRQ <= MBADADDR_q; ADR_ERR <= not(MMODE); when MIP_ADR => CSRQ <= MIP_q; when MBASE_ADR => if(VM = MBBID) then -- is it correct? CSRQ <= MDBASE_q; else CSRQ <= MBASE_q; end if; ADR_ERR <= not(MMODE); when MBOUND_ADR => if(VM = MBBID) then -- is it correct? CSRQ <= MDBOUND_q; else CSRQ <= MBOUND_q; end if; ADR_ERR <= not(MMODE); when MIBASE_ADR => CSRQ <= MIBASE_q; ADR_ERR <= not(MMODE); when MIBOUND_ADR => CSRQ <= MIBOUND_q; ADR_ERR <= not(MMODE); when MDBASE_ADR => CSRQ <= MDBASE_q; ADR_ERR <= not(MMODE); when MDBOUND_ADR => CSRQ <= MDBOUND_q; ADR_ERR <= not(MMODE); --when HTIMEW_ADR => -- CSRQ <= HTIMEW_q; --when HTIMEHW_ADR => -- CSRQ <= HTIMEHW_q; when MRV01CC_ADR => CSRQ <= MRV01CC_q; ADR_ERR <= not(MMODE); -- Host interface CSR's when MTOHOST_ADR => CSRQ <= MTOHOST_q; ADR_ERR <= not(MMODE); when MFROMHOST_ADR => CSRQ <= MFROMHOST_q; ADR_ERR <= not(MMODE); when others => CSRQ <= (others => '0'); ADR_ERR <= '1'; end case; end process; process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then CSRQ_q <= CSRQ; end if; end process; -- Illegal instruction exception must be raised if: -- 1) an un-existent CSR address is specified, OR -- 2) write access is attempted on a read-only CSR, OR -- 3) access is attempted on a CSR without appropriate -- privileges. ILLG <= CS_OP_V when ( ADR_ERR = '1' or -- cases 1,2 (IADR(9 downto 8) = "11" and MMODE = '0') -- case 3 ) else '0'; CSRQ_o <= CSRQ; ILLG_o <= ILLG; ---------------------------------------------- -- Control port output ---------------------------------------------- process(CP_IADR,MSTATUS_q,MTVEC_q,MIE_q,MTIMECMP_q,MTIME_q2,MTIMEH_q, MSCRATCH_q,MEPC_q,MCAUSE_q,MBADADDR_q,MIP_q,MBASE_q,MBOUND_q, MIBASE_q,MIBOUND_q,MDBASE_q,MDBOUND_q,MTOHOST_q,MFROMHOST_q, UCYCLE_q2,UINSTRET_q2,UCYCLEH_q,UINSTRETH_q,UFCSR_q,UFRM_q,USTATS_q, MTDELEG_q,MRV01CC_q,VM ) begin case CP_IADR is -- User mode CSR's when UCYCLE_ADR => CPQ <= to_signed(UCYCLE_q2,SDLEN); when UTIME_ADR => CPQ <= to_signed(UCYCLE_q2,SDLEN); when UINSTRET_ADR => CPQ <= to_signed(UINSTRET_q2,SDLEN); when UCYCLEH_ADR => CPQ <= to_signed(UCYCLEH_q,SDLEN); when UTIMEH_ADR => CPQ <= to_signed(UCYCLEH_q,SDLEN); when UINSTRETH_ADR => CPQ <= to_signed(UINSTRETH_q,SDLEN); when UFCSR_ADR => CPQ <= UFCSR_q; when UFFLAGS_ADR => CPQ(5-1 downto 0) <= UFCSR_q(5-1 downto 0); CPQ(SDLEN-1 downto 5) <= (others => '0'); when UFRM_ADR => CPQ <= UFRM_q; when USTATS_ADR => CPQ <= USTATS_q; -- Machine mode CSR's when MCPUID_ADR => CPQ <= MCPUID_RO; when MIMPID_ADR => CPQ <= MIMPID_RO; when MHARTID_ADR => CPQ <= MHARTID_RO; when MSTATUS_ADR => CPQ <= MSTATUS_q; when MTVEC_ADR => CPQ <= MTVEC_q; when MTDELEG_ADR => CPQ <= MTDELEG_q; when MIE_ADR => CPQ <= MIE_q; when MTIMECMP_ADR => CPQ <= to_signed(MTIMECMP_q,SDLEN); when MTIME_ADR => CPQ <= to_signed(MTIME_q2,SDLEN); when MTIMEH_ADR => CPQ <= to_signed(MTIMEH_q,SDLEN); when MSCRATCH_ADR => CPQ <= MSCRATCH_q; when MEPC_ADR => CPQ <= MEPC_q; when MCAUSE_ADR => CPQ <= MCAUSE_q; when MBADADDR_ADR => CPQ <= MBADADDR_q; when MIP_ADR => CPQ <= MIP_q; when MBASE_ADR => if(VM = MBBID) then -- is it correct? CPQ <= MDBASE_q; else CPQ <= MBASE_q; end if; when MBOUND_ADR => if(VM = MBBID) then -- is it correct? CPQ <= MDBOUND_q; else CPQ <= MBOUND_q; end if; when MIBASE_ADR => CPQ <= MIBASE_q; when MIBOUND_ADR => CPQ <= MIBOUND_q; when MDBASE_ADR => CPQ <= MDBASE_q; when MDBOUND_ADR => CPQ <= MDBOUND_q; when MRV01CC_ADR => CPQ <= MRV01CC_q; -- Host interface CSR's when MTOHOST_ADR => CPQ <= MTOHOST_q; when MFROMHOST_ADR => CPQ <= MFROMHOST_q; when others => CPQ <= (others => '0'); end case; end process; CPQ_o <= to_std_logic_vector(CPQ); end ARC;