commit
ba783fddd5
@ -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;
|
||||
|
@ -0,0 +1,30 @@
|
||||
-- Dummy/empty DMI interface to make toplevel happy on unsupported FPGAs
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
entity dmi_dtm is
|
||||
generic(ABITS : INTEGER:=8;
|
||||
DBITS : INTEGER:=32);
|
||||
|
||||
port(sys_clk : in std_ulogic;
|
||||
sys_reset : in std_ulogic;
|
||||
dmi_addr : out std_ulogic_vector(ABITS - 1 downto 0);
|
||||
dmi_din : in std_ulogic_vector(DBITS - 1 downto 0);
|
||||
dmi_dout : out std_ulogic_vector(DBITS - 1 downto 0);
|
||||
dmi_req : out std_ulogic;
|
||||
dmi_wr : out std_ulogic;
|
||||
dmi_ack : in std_ulogic
|
||||
);
|
||||
end entity dmi_dtm;
|
||||
|
||||
architecture behaviour of dmi_dtm is
|
||||
dmi_addr <= (others => '0');
|
||||
dmi_dout <= (others => '0');
|
||||
dmi_req <= '0';
|
||||
dmi_wr <= '0';
|
||||
end architecture behaviour;
|
||||
|
@ -0,0 +1,250 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.common.all;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
library unisim;
|
||||
use unisim.vcomponents.all;
|
||||
|
||||
entity dmi_dtm_tb is
|
||||
end dmi_dtm_tb;
|
||||
|
||||
architecture behave of dmi_dtm_tb is
|
||||
signal clk : std_ulogic;
|
||||
signal rst : std_ulogic;
|
||||
constant clk_period : time := 10 ns;
|
||||
constant jclk_period : time := 30 ns;
|
||||
|
||||
-- DMI debug bus signals
|
||||
signal dmi_addr : std_ulogic_vector(7 downto 0);
|
||||
signal dmi_din : std_ulogic_vector(63 downto 0);
|
||||
signal dmi_dout : std_ulogic_vector(63 downto 0);
|
||||
signal dmi_req : std_ulogic;
|
||||
signal dmi_wr : std_ulogic;
|
||||
signal dmi_ack : std_ulogic;
|
||||
|
||||
-- Global JTAG signals (used by BSCANE2 inside dmi_dtm
|
||||
alias j : glob_jtag_t is glob_jtag;
|
||||
|
||||
-- Wishbone interfaces
|
||||
signal wishbone_ram_in : wishbone_slave_out;
|
||||
signal wishbone_ram_out : wishbone_master_out;
|
||||
|
||||
begin
|
||||
dtm: entity work.dmi_dtm
|
||||
generic map(
|
||||
ABITS => 8,
|
||||
DBITS => 64
|
||||
)
|
||||
port map(
|
||||
sys_clk => clk,
|
||||
sys_reset => rst,
|
||||
dmi_addr => dmi_addr,
|
||||
dmi_din => dmi_din,
|
||||
dmi_dout => dmi_dout,
|
||||
dmi_req => dmi_req,
|
||||
dmi_wr => dmi_wr,
|
||||
dmi_ack => dmi_ack
|
||||
);
|
||||
|
||||
simple_ram_0: entity work.mw_soc_memory
|
||||
generic map(RAM_INIT_FILE => "simple_ram_behavioural.bin",
|
||||
MEMORY_SIZE => 524288)
|
||||
port map(clk => clk, rst => rst,
|
||||
wishbone_in => wishbone_ram_out,
|
||||
wishbone_out => wishbone_ram_in);
|
||||
|
||||
wishbone_debug_0: entity work.wishbone_debug_master
|
||||
port map(clk => clk, rst => rst,
|
||||
dmi_addr => dmi_addr(1 downto 0),
|
||||
dmi_dout => dmi_din,
|
||||
dmi_din => dmi_dout,
|
||||
dmi_wr => dmi_wr,
|
||||
dmi_ack => dmi_ack,
|
||||
dmi_req => dmi_req,
|
||||
wb_in => wishbone_ram_in,
|
||||
wb_out => wishbone_ram_out);
|
||||
|
||||
-- system clock
|
||||
sys_clk: process
|
||||
begin
|
||||
clk <= '1';
|
||||
wait for clk_period / 2;
|
||||
clk <= '0';
|
||||
wait for clk_period / 2;
|
||||
end process sys_clk;
|
||||
|
||||
-- system sim: just reset and wait
|
||||
sys_sim: process
|
||||
begin
|
||||
rst <= '1';
|
||||
wait for clk_period;
|
||||
rst <= '0';
|
||||
wait;
|
||||
end process;
|
||||
|
||||
-- jtag sim process
|
||||
sim_jtag: process
|
||||
procedure clock(count: in INTEGER) is
|
||||
begin
|
||||
for i in 1 to count loop
|
||||
j.tck <= '0';
|
||||
wait for jclk_period/2;
|
||||
j.tck <= '1';
|
||||
wait for jclk_period/2;
|
||||
end loop;
|
||||
end procedure clock;
|
||||
|
||||
procedure shift_out(val: in std_ulogic_vector) is
|
||||
begin
|
||||
for i in 0 to val'length-1 loop
|
||||
j.tdi <= val(i);
|
||||
clock(1);
|
||||
end loop;
|
||||
end procedure shift_out;
|
||||
|
||||
procedure shift_in(val: out std_ulogic_vector) is
|
||||
begin
|
||||
for i in val'length-1 downto 0 loop
|
||||
val := j.tdo & val(val'length-1 downto 1);
|
||||
clock(1);
|
||||
end loop;
|
||||
end procedure shift_in;
|
||||
|
||||
procedure send_command(
|
||||
addr : in std_ulogic_vector(7 downto 0);
|
||||
data : in std_ulogic_vector(63 downto 0);
|
||||
op : in std_ulogic_vector(1 downto 0)) is
|
||||
begin
|
||||
j.capture <= '1';
|
||||
clock(1);
|
||||
j.capture <= '0';
|
||||
clock(1);
|
||||
j.shift <= '1';
|
||||
shift_out(op);
|
||||
shift_out(data);
|
||||
shift_out(addr);
|
||||
j.shift <= '0';
|
||||
j.update <= '1';
|
||||
clock(1);
|
||||
j.update <= '0';
|
||||
clock(1);
|
||||
end procedure send_command;
|
||||
|
||||
procedure read_resp(
|
||||
op : out std_ulogic_vector(1 downto 0);
|
||||
data : out std_ulogic_vector(63 downto 0)) is
|
||||
|
||||
variable addr : std_ulogic_vector(7 downto 0);
|
||||
begin
|
||||
j.capture <= '1';
|
||||
clock(1);
|
||||
j.capture <= '0';
|
||||
clock(1);
|
||||
j.shift <= '1';
|
||||
shift_in(op);
|
||||
shift_in(data);
|
||||
shift_in(addr);
|
||||
j.shift <= '0';
|
||||
j.update <= '1';
|
||||
clock(1);
|
||||
j.update <= '0';
|
||||
clock(1);
|
||||
end procedure read_resp;
|
||||
|
||||
procedure dmi_write(addr : in std_ulogic_vector(7 downto 0);
|
||||
data : in std_ulogic_vector(63 downto 0)) is
|
||||
variable resp_op : std_ulogic_vector(1 downto 0);
|
||||
variable resp_data : std_ulogic_vector(63 downto 0);
|
||||
variable timeout : integer;
|
||||
begin
|
||||
send_command(addr, data, "10");
|
||||
loop
|
||||
read_resp(resp_op, resp_data);
|
||||
case resp_op is
|
||||
when "00" =>
|
||||
return;
|
||||
when "11" =>
|
||||
timeout := timeout + 1;
|
||||
assert timeout < 0
|
||||
report "dmi_write timed out !" severity error;
|
||||
when others =>
|
||||
assert 0 > 1 report "dmi_write got odd status: " &
|
||||
to_hstring(resp_op) severity error;
|
||||
end case;
|
||||
end loop;
|
||||
end procedure dmi_write;
|
||||
|
||||
|
||||
procedure dmi_read(addr : in std_ulogic_vector(7 downto 0);
|
||||
data : out std_ulogic_vector(63 downto 0)) is
|
||||
variable resp_op : std_ulogic_vector(1 downto 0);
|
||||
variable timeout : integer;
|
||||
begin
|
||||
send_command(addr, (others => '0'), "01");
|
||||
loop
|
||||
read_resp(resp_op, data);
|
||||
case resp_op is
|
||||
when "00" =>
|
||||
return;
|
||||
when "11" =>
|
||||
timeout := timeout + 1;
|
||||
assert timeout < 0
|
||||
report "dmi_read timed out !" severity error;
|
||||
when others =>
|
||||
assert 0 > 1 report "dmi_read got odd status: " &
|
||||
to_hstring(resp_op) severity error;
|
||||
end case;
|
||||
end loop;
|
||||
end procedure dmi_read;
|
||||
|
||||
variable data : std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
-- init & reset
|
||||
j.reset <= '1';
|
||||
j.sel <= "0000";
|
||||
j.capture <= '0';
|
||||
j.update <= '0';
|
||||
j.shift <= '0';
|
||||
j.tdi <= '0';
|
||||
j.tms <= '0';
|
||||
j.runtest <= '0';
|
||||
clock(5);
|
||||
j.reset <= '0';
|
||||
clock(5);
|
||||
|
||||
-- select chain 2
|
||||
j.sel <= "0010";
|
||||
clock(1);
|
||||
|
||||
-- send command
|
||||
dmi_read(x"00", data);
|
||||
report "Read addr reg:" & to_hstring(data);
|
||||
report "Writing addr reg to all 1's";
|
||||
dmi_write(x"00", (others => '1'));
|
||||
dmi_read(x"00", data);
|
||||
report "Read addr reg:" & to_hstring(data);
|
||||
|
||||
report "Writing ctrl reg to all 1's";
|
||||
dmi_write(x"02", (others => '1'));
|
||||
dmi_read(x"02", data);
|
||||
report "Read ctrl reg:" & to_hstring(data);
|
||||
|
||||
report "Read memory at 0...\n";
|
||||
dmi_write(x"00", x"0000000000000000");
|
||||
dmi_write(x"02", x"00000000000007ff");
|
||||
dmi_read(x"01", data);
|
||||
report "00:" & to_hstring(data);
|
||||
dmi_read(x"01", data);
|
||||
report "08:" & to_hstring(data);
|
||||
dmi_read(x"01", data);
|
||||
report "10:" & to_hstring(data);
|
||||
dmi_read(x"01", data);
|
||||
report "18:" & to_hstring(data);
|
||||
clock(10);
|
||||
std.env.finish;
|
||||
end process;
|
||||
end behave;
|
@ -0,0 +1,276 @@
|
||||
-- Xilinx internal JTAG to DMI interface
|
||||
--
|
||||
-- DMI bus
|
||||
--
|
||||
-- req : ____/------------\_____
|
||||
-- addr: xxxx< >xxxxx
|
||||
-- dout: xxxx< >xxxxx
|
||||
-- wr : xxxx< >xxxxx
|
||||
-- din : xxxxxxxxxxxx< >xxx
|
||||
-- ack : ____________/------\___
|
||||
--
|
||||
-- * addr/dout set along with req, can be latched on same cycle by slave
|
||||
-- * ack & din remain up until req is dropped by master, the slave must
|
||||
-- provide a stable output on din on reads during that time.
|
||||
-- * req remains low at until at least one sysclk after ack seen down.
|
||||
--
|
||||
-- JTAG (tck) DMI (sys_clk)
|
||||
--
|
||||
-- * jtag_req = 1
|
||||
-- (jtag_req_0) *
|
||||
-- (jtag_req_1) -> * dmi_req = 1 >
|
||||
-- *.../...
|
||||
-- * dmi_ack = 1 <
|
||||
-- * (dmi_ack_0)
|
||||
-- * <- (dmi_ack_1)
|
||||
-- * jtag_req = 0 (and latch dmi_din)
|
||||
-- (jtag_req_0) *
|
||||
-- (jtag_req_1) -> * dmi_req = 0 >
|
||||
-- * dmi_ack = 0 <
|
||||
-- * (dmi_ack_0)
|
||||
-- * <- (dmi_ack_1)
|
||||
--
|
||||
-- jtag_req can go back to 1 when jtag_rsp_1 is 0
|
||||
--
|
||||
-- Questions/TODO:
|
||||
-- - I use 2 flip fops for sync, is that enough ?
|
||||
-- - I treat the jtag_reset as an async reset, is that necessary ?
|
||||
-- - Dbl check reset situation since we have two different resets
|
||||
-- each only resetting part of the logic...
|
||||
-- - Look at optionally removing the synchronizer on the ack path,
|
||||
-- assuming JTAG is always slow enough that ack will have been
|
||||
-- stable long enough by the time CAPTURE comes in.
|
||||
-- - We could avoid the latched request by not shifting while a
|
||||
-- request is in progress (and force TDO to 1 to return a busy
|
||||
-- status).
|
||||
--
|
||||
-- WARNING: This isn't the real DMI JTAG protocol (at least not yet).
|
||||
-- a command while busy will be ignored. A response of "11"
|
||||
-- means the previous command is still going, try again.
|
||||
-- As such We don't implement the DMI "error" status, and
|
||||
-- we don't implement DTMCS yet... This may still all change
|
||||
-- but for now it's easier that way as the real DMI protocol
|
||||
-- requires for a command to work properly that enough TCK
|
||||
-- are sent while IDLE and I'm having trouble getting that
|
||||
-- working with UrJtag and the Xilinx BSCAN2 for now.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
library unisim;
|
||||
use unisim.vcomponents.all;
|
||||
|
||||
entity dmi_dtm is
|
||||
generic(ABITS : INTEGER:=8;
|
||||
DBITS : INTEGER:=32);
|
||||
|
||||
port(sys_clk : in std_ulogic;
|
||||
sys_reset : in std_ulogic;
|
||||
dmi_addr : out std_ulogic_vector(ABITS - 1 downto 0);
|
||||
dmi_din : in std_ulogic_vector(DBITS - 1 downto 0);
|
||||
dmi_dout : out std_ulogic_vector(DBITS - 1 downto 0);
|
||||
dmi_req : out std_ulogic;
|
||||
dmi_wr : out std_ulogic;
|
||||
dmi_ack : in std_ulogic
|
||||
-- dmi_err : in std_ulogic TODO: Add error response
|
||||
);
|
||||
end entity dmi_dtm;
|
||||
|
||||
architecture behaviour of dmi_dtm is
|
||||
|
||||
-- Signals coming out of the BSCANE2 block
|
||||
signal jtag_reset : std_ulogic;
|
||||
signal capture : std_ulogic;
|
||||
signal update : std_ulogic;
|
||||
signal drck : std_ulogic;
|
||||
signal jtag_clk : std_ulogic;
|
||||
signal sel : std_ulogic;
|
||||
signal shift : std_ulogic;
|
||||
signal tdi : std_ulogic;
|
||||
signal tdo : std_ulogic;
|
||||
signal tck : std_ulogic;
|
||||
|
||||
-- ** JTAG clock domain **
|
||||
|
||||
-- Shift register
|
||||
signal shiftr : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
|
||||
|
||||
-- Latched request
|
||||
signal request : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
|
||||
|
||||
-- A request is present
|
||||
signal jtag_req : std_ulogic;
|
||||
|
||||
-- Synchronizer for jtag_rsp (sys clk -> jtag_clk)
|
||||
signal dmi_ack_0 : std_ulogic;
|
||||
signal dmi_ack_1 : std_ulogic;
|
||||
|
||||
-- ** sys clock domain **
|
||||
|
||||
-- Synchronizer for jtag_req (jtag clk -> sys clk)
|
||||
signal jtag_req_0 : std_ulogic;
|
||||
signal jtag_req_1 : std_ulogic;
|
||||
|
||||
-- ** combination signals
|
||||
signal jtag_bsy : std_ulogic;
|
||||
signal op_valid : std_ulogic;
|
||||
signal rsp_op : std_ulogic_vector(1 downto 0);
|
||||
|
||||
-- ** Constants **
|
||||
constant DMI_REQ_NOP : std_ulogic_vector(1 downto 0) := "00";
|
||||
constant DMI_REQ_RD : std_ulogic_vector(1 downto 0) := "01";
|
||||
constant DMI_REQ_WR : std_ulogic_vector(1 downto 0) := "10";
|
||||
constant DMI_RSP_OK : std_ulogic_vector(1 downto 0) := "00";
|
||||
constant DMI_RSP_BSY : std_ulogic_vector(1 downto 0) := "11";
|
||||
|
||||
begin
|
||||
|
||||
-- Implement the Xilinx bscan2 for series 7 devices (TODO: use PoC to
|
||||
-- wrap this if compatibility is required with older devices).
|
||||
bscan : BSCANE2
|
||||
generic map (
|
||||
JTAG_CHAIN => 2
|
||||
)
|
||||
port map (
|
||||
CAPTURE => capture,
|
||||
DRCK => drck,
|
||||
RESET => jtag_reset,
|
||||
RUNTEST => open,
|
||||
SEL => sel,
|
||||
SHIFT => shift,
|
||||
TCK => tck,
|
||||
TDI => tdi,
|
||||
TMS => open,
|
||||
UPDATE => update,
|
||||
TDO => tdo
|
||||
);
|
||||
|
||||
-- Some examples out there suggest buffering the clock so it's
|
||||
-- treated as a proper clock net. This is probably needed when using
|
||||
-- drck (the gated clock) but I'm using the real tck here to avoid
|
||||
-- missing the update phase so maybe not...
|
||||
--
|
||||
clkbuf : BUFG
|
||||
port map (
|
||||
-- I => drck,
|
||||
I => tck,
|
||||
O => jtag_clk
|
||||
);
|
||||
|
||||
|
||||
-- dmi_req synchronization
|
||||
dmi_req_sync : process(sys_clk)
|
||||
begin
|
||||
-- sys_reset is synchronous
|
||||
if rising_edge(sys_clk) then
|
||||
if (sys_reset = '1') then
|
||||
jtag_req_0 <= '0';
|
||||
jtag_req_1 <= '0';
|
||||
else
|
||||
jtag_req_0 <= jtag_req;
|
||||
jtag_req_1 <= jtag_req_0;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
dmi_req <= jtag_req_1;
|
||||
|
||||
-- dmi_ack synchronization
|
||||
dmi_ack_sync: process(jtag_clk, jtag_reset)
|
||||
begin
|
||||
-- jtag_reset is async (see comments)
|
||||
if jtag_reset = '1' then
|
||||
dmi_ack_0 <= '0';
|
||||
dmi_ack_1 <= '0';
|
||||
elsif rising_edge(jtag_clk) then
|
||||
dmi_ack_0 <= dmi_ack;
|
||||
dmi_ack_1 <= dmi_ack_0;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- jtag_bsy indicates whether we can start a new request, we can when
|
||||
-- we aren't already processing one (jtag_req) and the synchronized ack
|
||||
-- of the previous one is 0.
|
||||
--
|
||||
jtag_bsy <= jtag_req or dmi_ack_1;
|
||||
|
||||
-- decode request type in shift register
|
||||
with shiftr(1 downto 0) select op_valid <=
|
||||
'1' when DMI_REQ_RD,
|
||||
'1' when DMI_REQ_WR,
|
||||
'0' when others;
|
||||
|
||||
-- encode response op
|
||||
rsp_op <= DMI_RSP_BSY when jtag_bsy = '1' else DMI_RSP_OK;
|
||||
|
||||
-- Some DMI out signals are directly driven from the request register
|
||||
dmi_addr <= request(ABITS + DBITS + 1 downto DBITS + 2);
|
||||
dmi_dout <= request(DBITS + 1 downto 2);
|
||||
dmi_wr <= '1' when request(1 downto 0) = DMI_REQ_WR else '0';
|
||||
|
||||
-- TDO is wired to shift register bit 0
|
||||
tdo <= shiftr(0);
|
||||
|
||||
-- Main state machine. Handles shift registers, request latch and
|
||||
-- jtag_req latch. Could be split into 3 processes but it's probably
|
||||
-- not worthwhile.
|
||||
--
|
||||
shifter: process(jtag_clk, jtag_reset)
|
||||
begin
|
||||
if jtag_reset = '1' then
|
||||
shiftr <= (others => '0');
|
||||
request <= (others => '0');
|
||||
jtag_req <= '0';
|
||||
elsif rising_edge(jtag_clk) then
|
||||
|
||||
-- Handle jtag "commands" when sel is 1
|
||||
if sel = '1' then
|
||||
-- Shift state, rotate the register
|
||||
if shift = '1' then
|
||||
shiftr <= tdi & shiftr(ABITS + DBITS + 1 downto 1);
|
||||
end if;
|
||||
|
||||
-- Update state (trigger)
|
||||
--
|
||||
-- Latch the request if we aren't already processing one and
|
||||
-- it has a valid command opcode.
|
||||
--
|
||||
if update = '1' and op_valid = '1' then
|
||||
if jtag_bsy = '0' then
|
||||
request <= shiftr;
|
||||
jtag_req <= '1';
|
||||
end if;
|
||||
-- Set the shift register "op" to "busy". This will prevent
|
||||
-- us from re-starting the command on the next update if
|
||||
-- the command completes before that.
|
||||
shiftr(1 downto 0) <= DMI_RSP_BSY;
|
||||
end if;
|
||||
|
||||
-- Request completion.
|
||||
--
|
||||
-- Capture the response data for reads and clear request flag.
|
||||
--
|
||||
-- Note: We clear req (and thus dmi_req) here which relies on tck
|
||||
-- ticking and sel set. This means we are stuck with dmi_req up if
|
||||
-- the jtag interface stops. Slaves must be resilient to this.
|
||||
--
|
||||
if jtag_req = '1' and dmi_ack_1 = '1' then
|
||||
jtag_req <= '0';
|
||||
if request(1 downto 0) = DMI_REQ_RD then
|
||||
request(DBITS + 1 downto 2) <= dmi_din;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Capture state, grab latch content with updated status
|
||||
if capture = '1' then
|
||||
shiftr <= request(ABITS + DBITS + 1 downto 2) & rsp_op;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end architecture behaviour;
|
||||
|
@ -0,0 +1,7 @@
|
||||
CFLAGS = -O2 -g -Wall -std=c99
|
||||
|
||||
all: mw_debug
|
||||
|
||||
mw_debug: mw_debug.c
|
||||
$(CC) -o $@ $^ -lurjtag
|
||||
|
@ -0,0 +1,583 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <urjtag/urjtag.h>
|
||||
|
||||
#define DBG_WB_ADDR 0x00
|
||||
#define DBG_WB_DATA 0x01
|
||||
#define DBG_WB_CTRL 0x02
|
||||
|
||||
#define DBG_CORE_CTRL 0x10
|
||||
#define DBG_CORE_CTRL_STOP (1 << 0)
|
||||
#define DBG_CORE_CTRL_RESET (1 << 1)
|
||||
#define DBG_CORE_CTRL_ICRESET (1 << 2)
|
||||
#define DBG_CORE_CTRL_STEP (1 << 3)
|
||||
#define DBG_CORE_CTRL_START (1 << 4)
|
||||
|
||||
#define DBG_CORE_STAT 0x11
|
||||
#define DBG_CORE_STAT_STOPPING (1 << 0)
|
||||
#define DBG_CORE_STAT_STOPPED (1 << 1)
|
||||
#define DBG_CORE_STAT_TERM (1 << 2)
|
||||
|
||||
#define DBG_CORE_NIA 0x12
|
||||
|
||||
static bool debug;
|
||||
|
||||
struct backend {
|
||||
int (*init)(const char *target);
|
||||
int (*reset)(void);
|
||||
int (*command)(uint8_t op, uint8_t addr, uint64_t *data);
|
||||
};
|
||||
static struct backend *b;
|
||||
|
||||
static void check(int r, const char *failstr)
|
||||
{
|
||||
if (r >= 0)
|
||||
return;
|
||||
fprintf(stderr, "Error %s\n", failstr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* -------------- SIM backend -------------- */
|
||||
|
||||
static int sim_fd = -1;
|
||||
|
||||
static int sim_init(const char *target)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
struct hostent *hp;
|
||||
const char *p, *host;
|
||||
int port, rc;
|
||||
|
||||
if (!target)
|
||||
target = "localhost:13245";
|
||||
p = strchr(target, ':');
|
||||
host = strndup(target, p - target);
|
||||
if (p && *p)
|
||||
p++;
|
||||
else
|
||||
p = "13245";
|
||||
port = strtoul(p, NULL, 10);
|
||||
if (debug)
|
||||
printf("Opening sim backend host '%s' port %d\n", host, port);
|
||||
|
||||
sim_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (sim_fd < 0) {
|
||||
fprintf(stderr, "Error opening socket: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
hp = gethostbyname(host);
|
||||
if (!hp) {
|
||||
fprintf(stderr,"Unknown host '%s'\n", host);
|
||||
return -1;
|
||||
}
|
||||
memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
|
||||
saddr.sin_port = htons(port);
|
||||
saddr.sin_family = PF_INET;
|
||||
rc = connect(sim_fd, (struct sockaddr *)&saddr, sizeof(saddr));
|
||||
if (rc < 0) {
|
||||
close(sim_fd);
|
||||
fprintf(stderr,"Connection to '%s' failed: %s\n",
|
||||
host, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void add_bits(uint8_t **p, int *b, uint64_t d, int c)
|
||||
{
|
||||
uint8_t md = 1 << *b;
|
||||
uint64_t ms = 1;
|
||||
|
||||
while (c--) {
|
||||
if (d & ms)
|
||||
(**p) |= md;
|
||||
ms <<= 1;
|
||||
if (*b == 7) {
|
||||
*b = 0;
|
||||
(*p)++;
|
||||
md = 1;
|
||||
} else {
|
||||
(*b)++;
|
||||
md <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t read_bits(uint8_t **p, int *b, int c)
|
||||
{
|
||||
uint8_t ms = 1 << *b;
|
||||
uint64_t md = 1;
|
||||
uint64_t d = 0;
|
||||
|
||||
while (c--) {
|
||||
if ((**p) & ms)
|
||||
d |= md;
|
||||
md <<= 1;
|
||||
if (*b == 7) {
|
||||
*b = 0;
|
||||
(*p)++;
|
||||
ms = 1;
|
||||
} else {
|
||||
(*b)++;
|
||||
ms <<= 1;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static int sim_command(uint8_t op, uint8_t addr, uint64_t *data)
|
||||
{
|
||||
uint8_t buf[16], *p;
|
||||
uint64_t d = data ? *data : 0;
|
||||
int r, s, b = 0;
|
||||
|
||||
memset(buf, 0, 16);
|
||||
p = buf+1;
|
||||
add_bits(&p, &b, op, 2);
|
||||
add_bits(&p, &b, d, 64);
|
||||
add_bits(&p, &b, addr, 8);
|
||||
if (b)
|
||||
p++;
|
||||
buf[0] = 74;
|
||||
if (0)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<(p-buf); i++)
|
||||
printf("%02x ", buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
write(sim_fd, buf, p - buf);
|
||||
r = read(sim_fd, buf, 127);
|
||||
if (0 && r > 0) {
|
||||
int i;
|
||||
|
||||
for (i=0; i<r; i++)
|
||||
printf("%02x ", buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
p = buf+1;
|
||||
b = 0;
|
||||
r = read_bits(&p, &b, 2);
|
||||
if (data)
|
||||
*data = read_bits(&p, &b, 64);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct backend sim_backend = {
|
||||
.init = sim_init,
|
||||
.reset = sim_reset,
|
||||
.command = sim_command,
|
||||
};
|
||||
|
||||
/* -------------- JTAG backend -------------- */
|
||||
|
||||
static urj_chain_t *jc;
|
||||
|
||||
static int jtag_init(const char *target)
|
||||
{
|
||||
const char *sep;
|
||||
const char *cable;
|
||||
char *params[] = { NULL, };
|
||||
urj_part_t *p;
|
||||
uint32_t id;
|
||||
int rc, part;
|
||||
|
||||
if (!target)
|
||||
target = "DigilentHS1";
|
||||
sep = strchr(target, ':');
|
||||
cable = strndup(target, sep - target);
|
||||
if (sep && *sep) {
|
||||
fprintf(stderr, "jtag cable params not supported yet\n");
|
||||
return -1;
|
||||
}
|
||||
if (debug)
|
||||
printf("Opening jtag backend cable '%s'\n", cable);
|
||||
|
||||
jc = urj_tap_chain_alloc();
|
||||
if (!jc) {
|
||||
fprintf(stderr, "Failed to alloc JTAG\n");
|
||||
return -1;
|
||||
}
|
||||
jc->main_part = 0;
|
||||
|
||||
rc = urj_tap_chain_connect(jc, cable, params);
|
||||
if (rc != URJ_STATUS_OK) {
|
||||
fprintf(stderr, "JTAG cable detect failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XXX Hard wire part 0, that might need to change (use params and detect !) */
|
||||
rc = urj_tap_manual_add(jc, 6);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "JTAG failed to add part !\n");
|
||||
return -1;
|
||||
}
|
||||
if (jc->parts == NULL || jc->parts->len == 0) {
|
||||
fprintf(stderr, "JTAG Something's wrong after adding part !\n");
|
||||
return -1;
|
||||
}
|
||||
urj_part_parts_set_instruction(jc->parts, "BYPASS");
|
||||
|
||||
jc->active_part = part = 0;
|
||||
|
||||
p = urj_tap_chain_active_part(jc);
|
||||
if (!p) {
|
||||
fprintf(stderr, "Failed to get active JTAG part\n");
|
||||
return -1;
|
||||
}
|
||||
rc = urj_part_data_register_define(p, "IDCODE_REG", 32);
|
||||
if (rc != URJ_STATUS_OK) {
|
||||
fprintf(stderr, "JTAG failed to add IDCODE_REG register !\n");
|
||||
return -1;
|
||||
}
|
||||
if (urj_part_instruction_define(p, "IDCODE", "001001", "IDCODE_REG") == NULL) {
|
||||
fprintf(stderr, "JTAG failed to add IDCODE instruction !\n");
|
||||
return -1;
|
||||
}
|
||||
rc = urj_part_data_register_define(p, "USER2_REG", 74);
|
||||
if (rc != URJ_STATUS_OK) {
|
||||
fprintf(stderr, "JTAG failed to add USER2_REG register !\n");
|
||||
return -1;
|
||||
}
|
||||
if (urj_part_instruction_define(p, "USER2", "000011", "USER2_REG") == NULL) {
|
||||
fprintf(stderr, "JTAG failed to add USER2 instruction !\n");
|
||||
return -1;
|
||||
}
|
||||
urj_part_set_instruction(p, "IDCODE");
|
||||
urj_tap_chain_shift_instructions(jc);
|
||||
urj_tap_chain_shift_data_registers(jc, 1);
|
||||
id = urj_tap_register_get_value(p->active_instruction->data_register->out);
|
||||
printf("Found device ID: 0x%08x\n", id);
|
||||
urj_part_set_instruction(p, "USER2");
|
||||
urj_tap_chain_shift_instructions(jc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jtag_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int jtag_command(uint8_t op, uint8_t addr, uint64_t *data)
|
||||
{
|
||||
urj_part_t *p = urj_tap_chain_active_part(jc);
|
||||
urj_part_instruction_t *insn;
|
||||
urj_data_register_t *dr;
|
||||
uint64_t d = data ? *data : 0;
|
||||
int rc;
|
||||
|
||||
if (!p)
|
||||
return -1;
|
||||
insn = p->active_instruction;
|
||||
if (!insn)
|
||||
return -1;
|
||||
dr = insn->data_register;
|
||||
if (!dr)
|
||||
return -1;
|
||||
rc = urj_tap_register_set_value_bit_range(dr->in, op, 1, 0);
|
||||
if (rc != URJ_STATUS_OK)
|
||||
return -1;
|
||||
rc = urj_tap_register_set_value_bit_range(dr->in, d, 65, 2);
|
||||
if (rc != URJ_STATUS_OK)
|
||||
return -1;
|
||||
rc = urj_tap_register_set_value_bit_range(dr->in, addr, 73, 66);
|
||||
if (rc != URJ_STATUS_OK)
|
||||
return -1;
|
||||
rc = urj_tap_chain_shift_data_registers(jc, 1);
|
||||
if (rc != URJ_STATUS_OK)
|
||||
return -1;
|
||||
rc = urj_tap_register_get_value_bit_range(dr->out, 1, 0);
|
||||
if (data)
|
||||
*data = urj_tap_register_get_value_bit_range(dr->out, 65, 2);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct backend jtag_backend = {
|
||||
.init = jtag_init,
|
||||
.reset = jtag_reset,
|
||||
.command = jtag_command,
|
||||
};
|
||||
|
||||
static int dmi_read(uint8_t addr, uint64_t *data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = b->command(1, addr, data);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
for (;;) {
|
||||
rc = b->command(0, 0, data);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc == 0)
|
||||
return 0;
|
||||
if (rc != 3)
|
||||
fprintf(stderr, "Unknown status code %d !\n", rc);
|
||||
}
|
||||
}
|
||||
|
||||
static int dmi_write(uint8_t addr, uint64_t data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = b->command(2, addr, &data);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
for (;;) {
|
||||
rc = b->command(0, 0, NULL);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc == 0)
|
||||
return 0;
|
||||
if (rc != 3)
|
||||
fprintf(stderr, "Unknown status code %d !\n", rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void core_status(void)
|
||||
{
|
||||
uint64_t stat, nia;
|
||||
const char *statstr, *statstr2;
|
||||
|
||||
check(dmi_read(DBG_CORE_STAT, &stat), "reading core status");
|
||||
check(dmi_read(DBG_CORE_NIA, &nia), "reading core NIA");
|
||||
|
||||
if (debug)
|
||||
printf("Core status = 0x%llx\n", (unsigned long long)stat);
|
||||
statstr = "running";
|
||||
statstr2 = "";
|
||||
if (stat & DBG_CORE_STAT_STOPPED) {
|
||||
statstr = "stopped";
|
||||
if (!(stat & DBG_CORE_STAT_STOPPING))
|
||||
statstr2 = " (restarting?)";
|
||||
else if (stat & DBG_CORE_STAT_TERM)
|
||||
statstr2 = " (terminated)";
|
||||
} else if (stat & DBG_CORE_STAT_STOPPING)
|
||||
statstr = "stopping";
|
||||
else if (stat & DBG_CORE_STAT_TERM)
|
||||
statstr = "odd state (TERM but no STOP)";
|
||||
printf("Core: %s%s\n", statstr, statstr2);
|
||||
printf(" NIA: %016llx\n", (unsigned long long)nia);
|
||||
}
|
||||
|
||||
static void core_stop(void)
|
||||
{
|
||||
check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_STOP), "stopping core");
|
||||
}
|
||||
|
||||
static void core_start(void)
|
||||
{
|
||||
check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_START), "starting core");
|
||||
}
|
||||
|
||||
static void core_reset(void)
|
||||
{
|
||||
check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_START), "resetting core");
|
||||
}
|
||||
|
||||
static void core_step(void)
|
||||
{
|
||||
uint64_t stat;
|
||||
|
||||
check(dmi_read(DBG_CORE_STAT, &stat), "reading core status");
|
||||
|
||||
if (!(stat & DBG_CORE_STAT_STOPPED)) {
|
||||
printf("Core not stopped !\n");
|
||||
return;
|
||||
}
|
||||
check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_STEP), "stepping core");
|
||||
}
|
||||
|
||||
static void icache_reset(void)
|
||||
{
|
||||
check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_ICRESET), "resetting icache");
|
||||
}
|
||||
|
||||
static void mem_read(uint64_t addr, uint64_t count)
|
||||
{
|
||||
uint64_t data;
|
||||
int i, rc;
|
||||
|
||||
rc = dmi_write(2, 0x7ff);
|
||||
if (rc < 0)
|
||||
return;
|
||||
rc = dmi_write(0, addr);
|
||||
if (rc < 0)
|
||||
return;
|
||||
for (i = 0; i < count; i++) {
|
||||
rc = dmi_read(1, &data);
|
||||
if (rc < 0)
|
||||
return;
|
||||
printf("%016llx: %016llx\n",
|
||||
(unsigned long long)addr,
|
||||
(unsigned long long)data);
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void load(const char *filename, uint64_t addr)
|
||||
{
|
||||
uint64_t data;
|
||||
int fd, rc, count;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Failed to open '%s': %s\n", filename, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
// XX dumb, do better
|
||||
rc = dmi_write(2, 0x7ff);
|
||||
if (rc < 0)
|
||||
return;
|
||||
rc = dmi_write(0, addr);
|
||||
if (rc < 0)
|
||||
return;
|
||||
count = 0;
|
||||
for (;;) {
|
||||
data = 0;
|
||||
rc = read(fd, &data, 8);
|
||||
if (rc <= 0)
|
||||
break;
|
||||
// if (rc < 8) XXX fixup endian ?
|
||||
dmi_write(1, data);
|
||||
count += 8;
|
||||
if (!(count % 1024))
|
||||
printf("%x...\n", count);
|
||||
}
|
||||
printf("%x done.\n", count);
|
||||
}
|
||||
|
||||
static void usage(const char *cmd)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <command> <args>\n", cmd);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *progname = argv[0];
|
||||
const char *target = NULL;
|
||||
int rc, i = 1;
|
||||
|
||||
b = NULL;
|
||||
|
||||
while(1) {
|
||||
int c, oindex;
|
||||
static struct option lopts[] = {
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "backend", required_argument, 0, 'b' },
|
||||
{ "target", required_argument, 0, 't' },
|
||||
{ "debug", no_argument, 0, 'd' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
c = getopt_long(argc, argv, "dhb:t:", lopts, &oindex);
|
||||
if (c < 0)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(progname);
|
||||
break;
|
||||
case 'b':
|
||||
if (strcmp(optarg, "sim") == 0)
|
||||
b = &sim_backend;
|
||||
else if (strcmp(optarg, "jtag") == 0)
|
||||
b = &jtag_backend;
|
||||
else {
|
||||
fprintf(stderr, "Unknown backend %s\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
target = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
debug = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (b == NULL) {
|
||||
fprintf(stderr, "No backend selected\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rc = b->init(target);
|
||||
if (rc < 0)
|
||||
exit(1);
|
||||
for (i = optind; i < argc; i++) {
|
||||
if (strcmp(argv[i], "dmiread") == 0) {
|
||||
uint8_t addr;
|
||||
uint64_t data;
|
||||
|
||||
if ((i+1) >= argc)
|
||||
usage(argv[0]);
|
||||
addr = strtoul(argv[++i], NULL, 16);
|
||||
dmi_read(addr, &data);
|
||||
printf("%02x: %016llx\n", addr, (unsigned long long)data);
|
||||
} else if (strcmp(argv[i], "dmiwrite") == 0) {
|
||||
uint8_t addr;
|
||||
uint64_t data;
|
||||
|
||||
if ((i+2) >= argc)
|
||||
usage(argv[0]);
|
||||
addr = strtoul(argv[++i], NULL, 16);
|
||||
data = strtoul(argv[++i], NULL, 16);
|
||||
dmi_write(addr, data);
|
||||
} else if (strcmp(argv[i], "creset") == 0) {
|
||||
core_reset();
|
||||
} else if (strcmp(argv[i], "stop") == 0) {
|
||||
core_stop();
|
||||
} else if (strcmp(argv[i], "start") == 0) {
|
||||
core_start();
|
||||
} else if (strcmp(argv[i], "step") == 0) {
|
||||
core_step();
|
||||
} else if (strcmp(argv[i], "quit") == 0) {
|
||||
dmi_write(0xff, 0);
|
||||
} else if (strcmp(argv[i], "status") == 0) {
|
||||
/* do nothing, always done below */
|
||||
} else if (strcmp(argv[i], "mr") == 0) {
|
||||
uint64_t addr, count = 1;
|
||||
|
||||
if ((i+1) >= argc)
|
||||
usage(argv[0]);
|
||||
addr = strtoul(argv[++i], NULL, 16);
|
||||
if (((i+1) < argc) && isdigit(argv[i+1][0]))
|
||||
count = strtoul(argv[++i], NULL, 16);
|
||||
mem_read(addr, count);
|
||||
} else if (strcmp(argv[i], "load") == 0) {
|
||||
const char *filename;
|
||||
uint64_t addr = 0;
|
||||
|
||||
if ((i+1) >= argc)
|
||||
usage(argv[0]);
|
||||
filename = argv[++i];
|
||||
if (((i+1) < argc) && isdigit(argv[i+1][0]))
|
||||
addr = strtoul(argv[++i], NULL, 16);
|
||||
load(filename, addr);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
core_status();
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.ALL;
|
||||
|
||||
library unisim;
|
||||
use unisim.vcomponents.all;
|
||||
|
||||
entity BSCANE2 is
|
||||
generic(jtag_chain: INTEGER);
|
||||
port(capture : out std_logic;
|
||||
drck : out std_logic;
|
||||
reset : out std_logic;
|
||||
runtest : out std_logic;
|
||||
sel : out std_logic;
|
||||
shift : out std_logic;
|
||||
tck : out std_logic;
|
||||
tdi : out std_logic;
|
||||
tms : out std_logic;
|
||||
update : out std_logic;
|
||||
tdo : in std_logic
|
||||
);
|
||||
end BSCANE2;
|
||||
|
||||
architecture behaviour of BSCANE2 is
|
||||
alias j : glob_jtag_t is glob_jtag;
|
||||
begin
|
||||
sel <= j.sel(jtag_chain);
|
||||
tck <= j.tck;
|
||||
drck <= tck and sel and (capture or shift);
|
||||
capture <= j.capture;
|
||||
reset <= j.reset;
|
||||
runtest <= j.runtest;
|
||||
shift <= j.shift; |