-------------------------------------------------------------------------------------------------------- -- Debug Unit -- -- -- Author(s): Gianmarco Cerutti -- -- Abdallah Cheikh abdallah.cheikh@uniroma1.it (abdallah93.as@gmail.com) -- -- -- -- Date Modified: 17-11-2019 -- -------------------------------------------------------------------------------------------------------- -- Debug Unit halts and sigle steps the core, it can read the current and next program counters, -- -- The register file can also be accessed by the debug unit. -- -------------------------------------------------------------------------------------------------------- -- ieee packages ------------ library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_misc.all; use ieee.numeric_std.all; use std.textio.all; -- local packages ------------ use work.riscv_klessydra.all; --use work.klessydra_parameters.all; entity Debug_UNIT is generic( THREAD_POOL_SIZE : integer; LUTRAM_RF : natural; ACCL_NUM : natural; RF_SIZE : natural ); port( set_branch_condition : in std_logic; ie_except_condition : in std_logic; ls_except_condition : in std_logic; dsp_except_condition : in std_logic_vector(ACCL_NUM-1 downto 0); set_except_condition : in std_logic; set_mret_condition : in std_logic; served_irq : in std_logic_vector(THREAD_POOL_SIZE-1 downto 0); irq_pending : in std_logic_vector(THREAD_POOL_SIZE-1 downto 0); taken_branch_pc_lat : in array_2D(THREAD_POOL_SIZE-1 downto 0)(31 downto 0); incremented_pc : in array_2D(THREAD_POOL_SIZE-1 downto 0)(31 downto 0); MTVEC : in array_2D(THREAD_POOL_SIZE-1 downto 0)(31 downto 0); MIP : in array_2D(THREAD_POOL_SIZE-1 downto 0)(31 downto 0); MSTATUS : in array_2d(THREAD_POOL_SIZE-1 downto 0)(1 downto 0); MCAUSE : in array_2D(THREAD_POOL_SIZE-1 downto 0)(31 downto 0); mepc_incremented_pc : in array_2D(THREAD_POOL_SIZE-1 downto 0)(31 downto 0) := (others => (others => '0')); mepc_interrupt_pc : in array_2D(THREAD_POOL_SIZE-1 downto 0)(31 downto 0) := (others => (others => '0')); regfile : in array_3d(THREAD_POOL_SIZE-1 downto 0)(RF_SIZE-1 downto 0)(31 downto 0); pc_IE : in std_logic_vector (31 downto 0); pc_ID : in std_logic_vector (31 downto 0); harc_ID : in integer range THREAD_POOL_SIZE-1 downto 0; ebreak_instr : in std_logic; dbg_ack_i : in std_logic; taken_branch : in std_logic; taken_branch_pending : in std_logic_vector(THREAD_POOL_SIZE-1 downto 0); dbg_req_o : out std_logic; clk_i : in std_logic; rst_ni : in std_logic; debug_req_i : in std_logic; debug_gnt_o : out std_logic; debug_rvalid_o : out std_logic; debug_addr_i : in std_logic_vector(14 downto 0); debug_we_i : in std_logic; debug_wdata_i : in std_logic_vector(31 downto 0); debug_rdata_o : out std_logic_vector(31 downto 0); debug_halted_o : out std_logic; debug_halt_i : in std_logic; debug_resume_i : in std_logic ); end entity; architecture DBG of Debug_Unit is type fsm_DBU_states is (RUNNING, HALT_REQ, HALT, SINGLE_STEP_REQ, SINGLE_STEP); signal state_DBU : fsm_DBU_states; signal nextstate_DBU : fsm_DBU_states; signal dbg_halt_req : std_logic; signal dbg_resume_core : std_logic; signal dbg_ssh : std_logic; signal dbg_sse : std_logic; -- wire only signals (For Synopsis Comaptibility) signal dbg_halted_o_wire : std_logic; begin debug_halted_o <= dbg_halted_o_wire; --DEBUG_UNIT-- --There are two processes, one handle the minterface between the external and the core, and one memorize the debug state. DBU_interface_handler : process(clk_i, rst_ni) begin if(rst_ni = '0') then debug_rvalid_o <= '0'; debug_rdata_o <= (others => '0'); dbg_halt_req <= '0'; dbg_sse <= '0'; dbg_ssh <= '1'; dbg_resume_core <= '0'; elsif rising_edge(clk_i) then dbg_ssh <= '1'; if (debug_req_i = '1') then debug_rvalid_o <= '1'; if(debug_we_i = '0') then --read access case debug_addr_i(13 downto 8) is when "000000" => --debug register always accessible case debug_addr_i(6 downto 2) is when "00000" => debug_rdata_o <= (0 => dbg_halted_o_wire, 16 => dbg_sse, others => '0'); when "00001" => debug_rdata_o <= (0 => dbg_ssh, others => '0'); when others => null; end case; when "100000" => --debug regster accessible only when core is halted, that's why there is a condition on dbg_halted_o_wire if dbg_halted_o_wire = '1' then case debug_addr_i(2) is when '1' => --previous pc debug_rdata_o <= pc_ie; when '0' => -- next pc debug_rdata_o <= pc_id; when others => null; end case; end if; when "000100" => --Read the GPR if LUTRAM_RF = 0 then debug_rdata_o <= regfile(harc_ID)(to_integer(unsigned(debug_addr_i(6 downto 2)))); end if; when others => null; end case; else -- write access debug_rvalid_o <= '0'; case debug_addr_i(13 downto 8) is when "000000" => --debug register always accessible case debug_addr_i(6 downto 2) is when "00000" => -- debug control if (debug_wdata_i(16) = '1') then if dbg_halted_o_wire = '0' then dbg_halt_req <= '1'; else dbg_halt_req <= '0'; end if; else if dbg_halted_o_wire = '1' then dbg_resume_core <= '1'; dbg_halt_req <= '0'; end if; end if; if(debug_wdata_i(0) = '1') then dbg_sse <= '1'; else dbg_sse <= '0'; end if; when "00001" => -- debug hit if (debug_wdata_i(0) = '0') then if dbg_sse = '1' and dbg_halted_o_wire = '1' then dbg_ssh <= '0'; end if; end if; when others => null; end case; when others => null; end case; end if; end if; end if; end process; DBU_combination_access : process (all) begin if (debug_req_i = '1') then debug_gnt_o <= '1'; else debug_gnt_o <= '0'; end if; end process; --DEBUG_UNIT_NEXTSTATE fsm_Debug_Unit_nextstate : process(all) begin dbg_req_o <= '0'; dbg_halted_o_wire <= '0'; nextstate_DBU <= RUNNING; case state_DBU is when RUNNING => if ebreak_instr = '1' then if dbg_sse = '1' then nextstate_DBU <= SINGLE_STEP; else nextstate_DBU <= HALT; end if; elsif dbg_halt_req = '1' then dbg_req_o <= '1'; if dbg_sse = '1' then nextstate_DBU <= SINGLE_STEP_REQ; else nextstate_DBU <= HALT_REQ; end if; end if; when HALT_REQ => dbg_req_o <= '1'; if dbg_ack_i = '1' then nextstate_DBU <= HALT; else if dbg_resume_core = '0' then if dbg_sse = '1' then nextstate_DBU <= SINGLE_STEP_REQ; else nextstate_DBU <= HALT_REQ; end if; end if; end if; --dbg_ack_i when HALT => dbg_req_o <= '1'; dbg_halted_o_wire <= '1'; if dbg_resume_core = '0' then if dbg_sse = '1' then nextstate_DBU <= SINGLE_STEP; else nextstate_DBU <= HALT; end if; end if; when SINGLE_STEP_REQ => dbg_req_o <= '1'; if dbg_ack_i = '1' then nextstate_DBU <= SINGLE_STEP; else if dbg_sse = '0' then nextstate_DBU <= HALT_REQ; else nextstate_DBU <= SINGLE_STEP_REQ; end if; end if; when SINGLE_STEP => if dbg_sse = '0' then if dbg_resume_core = '0' then dbg_req_o <= '1'; dbg_halted_o_wire <= '1'; nextstate_DBU <= HALT; end if; elsif dbg_ssh = '0' then -- when a signle step is hit, the debug halt is stopped for one exact cycle nextstate_DBU <= SINGLE_STEP_REQ; else dbg_req_o <= '1'; dbg_halted_o_wire <= '1'; nextstate_DBU <= SINGLE_STEP; end if; when others => null; end case; end process; fsm_DBU_register_state : process(clk_i, rst_ni) begin if rst_ni = '0' then state_DBU <= RUNNING; elsif rising_edge(clk_i) then state_DBU <= nextstate_DBU; end if; end process; ------------------------------------------------------------------------ end of DBG Unit --------- -------------------------------------------------------------------------------------------------- end DBG; -------------------------------------------------------------------------------------------------- -- END of DBG Unit architecture ----------------------------------------------------------------- --------------------------------------------------------------------------------------------------