URL
https://opencores.org/ocsvn/rv01_riscv_core/rv01_riscv_core/trunk
Subversion Repositories rv01_riscv_core
[/] [rv01_riscv_core/] [trunk/] [VHDL/] [RV01_dbgu.vhd] - Rev 2
Compare with Previous | Blame | View Log
----------------------------------------------------------------- -- -- ----------------------------------------------------------------- -- -- -- Copyright (C) 2017 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 Debug 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_DBGU is generic( NW : natural := 2 ); port( CLK_i : in std_logic; RST_i : in std_logic; HPC_i : in ADR_T; MMODE_i : in std_logic; NOPR_i : in std_logic; -- Debug interface HALT_i : in std_logic; -- debug halt 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); RST_o : out std_logic; HLTRQ_o : out std_logic; RSM_o : out std_logic; DPC_o : out ADR_T; DMODE_o : out std_logic; DIE_o : out std_logic; HALTD_o : out std_logic; STOPTIME_o : out std_logic; STOPCYCLE_o : out std_logic; SI_o : out std_logic_vector(SDLEN-1 downto 0); HOBRK_o : out std_logic; STEP_o : out std_logic; FRCSI_o : out std_logic; -- Control port CPQ_o : out std_logic_vector(SDLEN-1 downto 0) ); end RV01_DBGU; architecture ARC of RV01_DBGU is constant MAX_CNT : natural := 2147483647; --2**(SDLEN-1)-1; constant CCS_NDRESET : natural := 27; constant CCS_FULLRESET : natural := 26; constant CCS_STOPCYCLE : natural := 25; constant CCS_STOPTIME : natural := 24; constant CCS_HALTED : natural := 19; constant CCS_HALT : natural := 17; constant CCS_RESUME : natural := 16; constant DTMIA_CDISABLE : natural := 16; constant DCS_DEBUG : natural := 7; constant DCS_EBREAKM : natural := 3; constant DCS_EBREAKU : natural := 0; constant DCS_CAUSE_NODEBUG : signed(3-1 downto 0) := "000"; constant DCS_CAUSE_SWBREAK : signed(3-1 downto 0) := "001"; constant DCS_CAUSE_HWBREAK : signed(3-1 downto 0) := "010"; constant DCS_CAUSE_CCSHALT : signed(3-1 downto 0) := "011"; constant DCS_CAUSE_STEP : signed(3-1 downto 0) := "100"; type DS_T is ( DS_IDLE, DS_DBGHLT, DS_STEP, DS_EXSI1, DS_EXSI2, DS_DBG ); signal DS,DS_q : DS_T; signal CCS_q : SDWORD_T; signal DTMIA_q : SDWORD_T; signal DCS_q : SDWORD_T; signal PCS_q : SDWORD_T; signal SI_q : SDWORD_T; signal DJ_q : SDWORD_T; signal PC_q : SDWORD_T; signal CPQ,CPQ_q : SDWORD_T; signal CP_RE_q : std_logic; signal CP_WE_q : std_logic; signal CP_IADR,CP_IADR_q : unsigned(17-1 downto 0); signal CP_D_q : SDWORD_T; signal ND_RST : std_logic; signal FULL_RST : std_logic; signal RSM,RSM_q : std_logic; signal DMODE,DMODE_q : std_logic; signal IE,IE_q : std_logic; signal HALTD,HALTD_q : std_logic; signal SIW,SIW_q : std_logic; signal DJW,DJW_q : std_logic; signal DJX : std_logic; signal CPW : std_logic; signal HLTRQ,HLTRQ_q : std_logic; signal HOBRK,HOBRK_q : std_logic; signal STEP,STEP_q : std_logic; signal STEP_PLS,STEP_PLS_q : std_logic; signal HALT_q : std_logic; signal DPC,DPC_q : ADR_T; signal FRCSI,FRCSI_q : std_logic; signal PCLE : std_logic; 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 ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1' or FULL_RST = '1') then CP_RE_q <= '0'; CP_WE_q <= '0'; else CP_RE_q <= CPRE_i; CP_WE_q <= CPWE_i; end if; end if; end process; CP_IADR <= to_unsigned(CPADR_i); 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; ---------------------------------------------- -- Note: CCS register ndrst, fullrst and resume bits -- are write-only and therefore, on a write operation, -- they're not actually written to CCS register. -- Non-debug logic reset flag ND_RST <= CP_WE_q when ( CP_IADR_q = '0' & CCS_ADR and CP_D_q(CCS_NDRESET) = '1' ) else '0'; -- Full reset flag FULL_RST <= CP_WE_q when ( CP_IADR_q = '0' & CCS_ADR and CP_D_q(CCS_FULLRESET) = '1' ) else '0'; RST_o <= ND_RST or FULL_RST; ---------------------------------------------- -- This register "holds" HALT_i while -- store buffer gets emptied. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1' or FULL_RST = '1') then HALT_q <= '0'; elsif(HALT_i = '1' and NOPR_i = '0') then HALT_q <= '1'; elsif(HALT_q = '1' and NOPR_i = '1') then HALT_q <= '0'; end if; end if; end process; -- Halt request is generated when: -- 1) CCS[halt] is written to 1, -- 2) CCS[resume] is written to 1 and CCS[halt] is set to 1. -- Request remains pending until a valid instruction -- is retired (halting must occur on an instruction -- boundary). -- Halt request is also triggered by a non-debug logic -- reset, to insure processor enters debug mode on first -- instruction. HLTRQ <= CP_WE_q when ( (CP_IADR_q = '0' & CCS_ADR) and ( (CP_D_q(CCS_HALT) = '1') or (CP_D_q(CCS_RESUME) = '1' and CCS_q(CCS_HALT) = '1') ) ) else '0'; -- Halt request flag process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1' or FULL_RST = '1') then HLTRQ_q <= '0'; elsif(HALT_i = '1' or ND_RST = '1') then HLTRQ_q <= '0'; elsif(HLTRQ = '1' or SIW = '1') then HLTRQ_q <= '1'; end if; end if; end process; HLTRQ_o <= HLTRQ_q; -- Resume request is generated when CCS[resume] is written -- to 1, and remain pending until a valid instruction -- is retired (resuming occurs on an instruction -- boundary). This choice allows to treat the instrucion -- where resuming occurs like an eret instruction. -- Resume flag RSM <= CP_WE_q when ( CP_IADR_q = '0' & CCS_ADR and CP_D_q(CCS_RESUME) = '1' ) else '0'; process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1' or FULL_RST = '1') then RSM_q <= '0'; else RSM_q <= RSM or DJW or SIW; end if; end if; end process; RSM_o <= RSM_q; ---------------------------------------------- -- Debug FSM ---------------------------------------------- -- Note: at reset the cpu is in DEBUG+HALT state! process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1' or FULL_RST = '1') then DMODE_q <= '1'; HALTD_q <= '1'; HOBRK_q <= '0'; STEP_q <= '0'; STEP_PLS_q <= '0'; IE_q <= '1'; FRCSI_q <= '0'; DS_q <= DS_DBGHLT; else DMODE_q <= DMODE; HALTD_q <= HALTD; HOBRK_q <= HOBRK; STEP_q <= STEP; STEP_PLS_q <= STEP_PLS; IE_q <= IE; DS_q <= DS; FRCSI_q <= FRCSI; end if; end if; end process; process(DS_q,HALT_i,HALT_q,NOPR_i,RSM_q,CCS_q,SIW,DJW) begin DMODE <= '0'; HALTD <= '0'; HOBRK <= '0'; STEP <= '0'; STEP_PLS <= '0'; IE <= '1'; DJX <= '0'; FRCSI <= '0'; PCLE <= '1'; case DS_q is -- normal inst. execution when DS_IDLE => if((HALT_i = '1' or HALT_q = '1') and NOPR_i = '1') then -- if there're pending reads in store buffer, -- debug mode entry is delayed until they're all -- committed. DMODE <= '1'; HALTD <= '1'; IE <= '0'; DS <= DS_DBGHLT; else DS <= DS_IDLE; end if; -- debug mode + halted when DS_DBGHLT => if(RSM_q = '1' and CCS_q(CCS_HALT) = '0') then -- resume inst. execution DS <= DS_IDLE; elsif(RSM_q = '1' and CCS_q(CCS_HALT) = '1') then -- single step STEP <= '1'; STEP_PLS <= '1'; IE <= '0'; DS <= DS_STEP; elsif(SIW = '1') then -- execute instruction in Stuff Instruction -- register DMODE <= '1'; HALTD <= '1'; IE <= '0'; FRCSI <= '1'; DS <= DS_EXSI1; elsif(DJW = '1') then -- jump to address in Debug Jump register. DMODE <= '1'; IE <= '0'; DJX <= '1'; HOBRK <= '1'; DS <= DS_DBG; else -- stay in debug mode + halted HALTD <= '1'; IE <= '0'; DS <= DS_DBGHLT; end if; -- single-step when DS_STEP => if(HALT_i = '1') then -- re-enter degug mode DS <= DS_DBGHLT; else STEP <= '1'; IE <= '0'; DS <= DS_STEP; end if; -- execute stuff instruction when DS_EXSI1 => DMODE <= '1'; HALTD <= '1'; IE <= '0'; STEP <= '1'; STEP_PLS <= '1'; FRCSI <= '1'; DS <= DS_EXSI2; -- execute stuff instruction when DS_EXSI2 => if(HALT_i = '1') then DMODE <= '1'; HALTD <= '1'; IE <= '0'; -- PC latch disable PCLE <= '0'; -- re-enter degug mode DS <= DS_DBGHLT; else DMODE <= '1'; HALTD <= '1'; IE <= '0'; STEP <= '1'; DS <= DS_EXSI2; end if; -- debug jump when DS_DBG => if(HALT_i = '1') then DMODE <= '1'; HALTD <= '1'; IE <= '0'; DS <= DS_DBGHLT; else DMODE <= '1'; IE <= '0'; HOBRK <= '1'; DS <= DS_DBG; end if; when others => DS <= DS_DBGHLT; end case; end process; -- Debug Mode flag DMODE_o <= DMODE_q; -- Debug interrupt enable flag DIE_o <= IE_q; -- Halted flag HALTD_o <= HALTD_q; -- Halt-on-break flag HOBRK_o <= HOBRK_q or (DCS_q(DCS_EBREAKM) and MMODE_i) or (DCS_q(DCS_EBREAKU) and not(MMODE_i)); -- Step flag STEP_o <= STEP_PLS_q; -- Force-SI flag FRCSI_o <= FRCSI_q; ---------------------------------------------- -- Component Control & Status register ---------------------------------------------- -- Note: here un-registred RSM and DJW are used -- to reset CCS[halted]. -- Note: CCS[halted] is reset when a debug jump -- is performed. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then CCS_q <= CCS_RST; elsif( CP_WE_q = '1' and CP_IADR_q = '0' & CCS_ADR ) then CCS_q <= update_csr(CCS_q,CCS_WMSK,CP_D_q); end if; if(HALT_i = '1') then CCS_q(CCS_HALTED) <= '1'; elsif(RSM = '1' or DJW = '1') then CCS_q(CCS_HALTED) <= '0'; end if; end if; end process; STOPTIME_o <= CCS_q(CCS_STOPTIME) and CCS_q(CCS_HALTED); STOPCYCLE_o <= CCS_q(CCS_STOPCYCLE) and CCS_q(CCS_HALTED); ---------------------------------------------- -- DTM Interrupt Address register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then DTMIA_q <= (others => '0'); elsif(CP_WE_q = '1' and CP_IADR_q = '0' & DTMIA_ADR) then DTMIA_q <= CP_D_q; end if; end if; end process; ---------------------------------------------- -- Debug Control & Status register ---------------------------------------------- -- Note: here un-registred RSM is used -- to reset CCS[halted]. process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1') then DCS_q <= DCS_RST; elsif(CP_WE_q = '1' and CP_IADR_q = '0' & DCS_ADR) then DCS_q <= update_csr(DCS_q,DCS_WMSK,CP_D_q); end if; if(HALT_i = '1') then DCS_q(DCS_DEBUG) <= '1'; elsif(RSM = '1') then DCS_q(DCS_DEBUG) <= '0'; end if; if(HALT_i = '1') then if(CCS_q(CCS_HALT)= '1') then DCS_q(6 downto 4) <= DCS_CAUSE_CCSHALT; elsif(HOBRK_q = '1') then DCS_q(6 downto 4) <= DCS_CAUSE_SWBREAK; elsif(STEP_q = '1') then DCS_q(6 downto 4) <= DCS_CAUSE_STEP; end if; elsif(RSM = '1' and CCS_q(CCS_HALT)= '0') then DCS_q(6 downto 4) <= DCS_CAUSE_NODEBUG; end if; end if; end process; ---------------------------------------------- -- PC Sample register ---------------------------------------------- process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then PCS_q <= to_signed(HPC_i); end if; end process; ---------------------------------------------- -- Stuff Instruction register ---------------------------------------------- SIW <= (CP_WE_q and CCS_q(CCS_HALTED)) when ( CP_IADR_q = '0' & SI_ADR ) else '0'; process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(SIW = '1') then SI_q <= CP_D_q; end if; end if; end process; SI_o <= to_std_logic_vector(SI_q); ---------------------------------------------- -- Debug Jump register ---------------------------------------------- DJW <= (CP_WE_q and CCS_q(CCS_HALTED)) when ( CP_IADR_q = '0' & DJ_ADR ) else '0'; process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(DJW = '1') then DJ_q <= CP_D_q; end if; end if; end process; ---------------------------------------------- -- PC register ---------------------------------------------- CPW <= (CP_WE_q and CCS_q(CCS_HALTED)) when ( CP_IADR_q = '0' & PC_ADR ) else '0'; process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then if(RST_i = '1' or FULL_RST = '1') then PC_q <= to_signed(RESET_VA_LO); elsif(HALT_i = '1' and PCLE = '1') then PC_q <= to_signed(HPC_i); elsif(CPW = '1') then PC_q <= CP_D_q; end if; end if; end process; DPC <= to_unsigned(PC_q) when (DJX = '0') else to_unsigned(CP_D_q); process(CLK_i) begin if(CLK_i = '1' and CLK_i'event) then DPC_q <= DPC; end if; end process; DPC_o <= DPC_q; ---------------------------------------------- -- Debug CSR output mux ---------------------------------------------- process(CP_IADR,CCS_q,DTMIA_q,DCS_q,PCS_q, DS_q,DJ_q,PC_q ) begin case CP_IADR(17-2 downto 0) is when CCS_ADR => CPQ <= CCS_q; when DTMIA_ADR => CPQ <= DTMIA_q; when DCS_ADR => CPQ <= DCS_q; when PCS_ADR => CPQ <= PCS_q; when SI_ADR => CPQ <= SI_q; when DJ_ADR => CPQ <= DJ_q; when PC_ADR => CPQ <= PC_q; when others => CPQ <= (others => '0'); end case; end process; CPQ_o <= to_std_logic_vector(CPQ); end ARC;