forked from cores/microwatt
Add core debug module
This module adds some simple core controls: reset, stop, start, step along with icache clear and reading the NIA and core status bits Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.orgjtag-port
parent
554b753172
commit
98f0994698
@ -0,0 +1,152 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.common.all;
|
||||
|
||||
entity core_debug is
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst : in std_logic;
|
||||
|
||||
dmi_addr : in std_ulogic_vector(3 downto 0);
|
||||
dmi_din : in std_ulogic_vector(63 downto 0);
|
||||
dmi_dout : out std_ulogic_vector(63 downto 0);
|
||||
dmi_req : in std_ulogic;
|
||||
dmi_wr : in std_ulogic;
|
||||
dmi_ack : out std_ulogic;
|
||||
|
||||
-- Debug actions
|
||||
core_stop : out std_ulogic;
|
||||
core_rst : out std_ulogic;
|
||||
icache_rst : out std_ulogic;
|
||||
|
||||
-- Core status inputs
|
||||
terminate : in std_ulogic;
|
||||
core_stopped : in std_ulogic;
|
||||
nia : in std_ulogic_vector(63 downto 0);
|
||||
|
||||
-- Misc
|
||||
terminated_out : out std_ulogic
|
||||
);
|
||||
end core_debug;
|
||||
|
||||
architecture behave of core_debug is
|
||||
-- DMI needs fixing... make a one clock pulse
|
||||
signal dmi_req_1: std_ulogic;
|
||||
|
||||
-- CTRL register (direct actions, write 1 to act, read back 0)
|
||||
-- bit 0 : Core stop
|
||||
-- bit 1 : Core reset (doesn't clear stop)
|
||||
-- bit 2 : Icache reset
|
||||
-- bit 3 : Single step
|
||||
-- bit 4 : Core start
|
||||
constant DBG_CORE_CTRL : std_ulogic_vector(3 downto 0) := "0000";
|
||||
constant DBG_CORE_CTRL_STOP : integer := 0;
|
||||
constant DBG_CORE_CTRL_RESET : integer := 1;
|
||||
constant DBG_CORE_CTRL_ICRESET : integer := 2;
|
||||
constant DBG_CORE_CTRL_STEP : integer := 3;
|
||||
constant DBG_CORE_CTRL_START : integer := 4;
|
||||
|
||||
-- STAT register (read only)
|
||||
-- bit 0 : Core stopping (wait til bit 1 set)
|
||||
-- bit 1 : Core stopped
|
||||
-- bit 2 : Core terminated (clears with start or reset)
|
||||
constant DBG_CORE_STAT : std_ulogic_vector(3 downto 0) := "0001";
|
||||
constant DBG_CORE_STAT_STOPPING : integer := 0;
|
||||
constant DBG_CORE_STAT_STOPPED : integer := 1;
|
||||
constant DBG_CORE_STAT_TERM : integer := 2;
|
||||
|
||||
-- NIA register (read only for now)
|
||||
constant DBG_CORE_NIA : std_ulogic_vector(3 downto 0) := "0010";
|
||||
|
||||
-- Some internal wires
|
||||
signal stat_reg : std_ulogic_vector(63 downto 0);
|
||||
|
||||
-- Some internal latches
|
||||
signal stopping : std_ulogic;
|
||||
signal do_step : std_ulogic;
|
||||
signal do_reset : std_ulogic;
|
||||
signal do_icreset : std_ulogic;
|
||||
signal terminated : std_ulogic;
|
||||
|
||||
begin
|
||||
-- Single cycle register accesses on DMI
|
||||
dmi_ack <= dmi_req;
|
||||
|
||||
-- Status register read composition
|
||||
stat_reg <= (2 => terminated,
|
||||
1 => core_stopped,
|
||||
0 => stopping,
|
||||
others => '0');
|
||||
|
||||
-- DMI read data mux
|
||||
with dmi_addr select dmi_dout <=
|
||||
stat_reg when DBG_CORE_STAT,
|
||||
nia when DBG_CORE_NIA,
|
||||
(others => '0') when others;
|
||||
|
||||
-- DMI writes
|
||||
reg_write: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if (rst) then
|
||||
stopping <= '0';
|
||||
terminated <= '0';
|
||||
else
|
||||
-- Reset the 1-cycle "do" signals
|
||||
do_step <= '0';
|
||||
do_reset <= '0';
|
||||
do_icreset <= '0';
|
||||
|
||||
-- Edge detect on dmi_req for 1-shot pulses
|
||||
dmi_req_1 <= dmi_req;
|
||||
if dmi_req = '1' and dmi_req_1 = '0' then
|
||||
if dmi_wr = '1' then
|
||||
report("DMI write to " & to_hstring(dmi_addr));
|
||||
|
||||
-- Control register actions
|
||||
if dmi_addr = DBG_CORE_CTRL then
|
||||
if dmi_din(DBG_CORE_CTRL_RESET) = '1' then
|
||||
do_reset <= '1';
|
||||
terminated <= '0';
|
||||
end if;
|
||||
if dmi_din(DBG_CORE_CTRL_STOP) = '1' then
|
||||
stopping <= '1';
|
||||
end if;
|
||||
if dmi_din(DBG_CORE_CTRL_STEP) = '1' then
|
||||
do_step <= '1';
|
||||
terminated <= '0';
|
||||
end if;
|
||||
if dmi_din(DBG_CORE_CTRL_ICRESET) = '1' then
|
||||
do_icreset <= '1';
|
||||
end if;
|
||||
if dmi_din(DBG_CORE_CTRL_START) = '1' then
|
||||
stopping <= '0';
|
||||
terminated <= '0';
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
report("DMI read from " & to_string(dmi_addr));
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Set core stop on terminate. We'll be stopping some time *after*
|
||||
-- the offending instruction, at least until we can do back flushes
|
||||
-- that preserve NIA which we can't just yet.
|
||||
if terminate = '1' then
|
||||
stopping <= '1';
|
||||
terminated <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Core control signals generated by the debug module
|
||||
core_stop <= stopping and not do_step;
|
||||
core_rst <= do_reset;
|
||||
icache_rst <= do_icreset;
|
||||
terminated_out <= terminated;
|
||||
end behave;
|
||||
|
Loading…
Reference in New Issue