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

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.