Add a debug (DMI) bus and a JTAG interface to it on Xilinx FPGAs

This adds a simple bus that can be mastered from an external
system via JTAG, which will be used to hookup various debug
modules.

It's loosely based on the RiscV model (hence the DMI name).

The module currently only supports hooking up to a Xilinx BSCANE2
but it shouldn't be too hard to adapt it to support different TAPs
if necessary.

The JTAG protocol proper is not exactly the RiscV one at this point,
though I might still change it.

This comes with some sim variants of Xilinx BSCANE2 and BUFG and a
test bench.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
jtag-port
Benjamin Herrenschmidt 5 years ago
parent 1206dfe18c
commit ee52fd4d80

@ -1,8 +1,9 @@
GHDL=ghdl GHDL=ghdl
GHDLFLAGS=--std=08 GHDLFLAGS=--std=08 -Psim-unisim
CFLAGS=-O2 -Wall CFLAGS=-O2 -Wall


all = core_tb simple_ram_behavioural_tb soc_reset_tb icache_tb multiply_tb all = core_tb simple_ram_behavioural_tb soc_reset_tb icache_tb multiply_tb dmi_dtm_tb

# XXX # XXX
# loadstore_tb fetch_tb # loadstore_tb fetch_tb


@ -40,10 +41,18 @@ simple_ram_behavioural_helpers.o:
simple_ram_behavioural_tb.o: wishbone_types.o simple_ram_behavioural.o simple_ram_behavioural_tb.o: wishbone_types.o simple_ram_behavioural.o
simple_ram_behavioural.o: wishbone_types.o simple_ram_behavioural_helpers.o simple_ram_behavioural.o: wishbone_types.o simple_ram_behavioural_helpers.o
sim_uart.o: wishbone_types.o sim_console.o sim_uart.o: wishbone_types.o sim_console.o
soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o simple_ram_behavioural.o soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o simple_ram_behavioural.o dmi_dtm_xilinx.o
wishbone_arbiter.o: wishbone_types.o wishbone_arbiter.o: wishbone_types.o
wishbone_types.o: wishbone_types.o:
writeback.o: common.o writeback.o: common.o
dmi_dtm_tb.o: dmi_dtm_xilinx.o
dmi_dtm_xilinx.o: sim-unisim/unisim_vcomponents.o

UNISIM_BITS = sim-unisim/unisim_vcomponents.vhdl sim-unisim/BSCANE2.vhdl sim-unisim/BUFG.vhdl
sim-unisim/unisim_vcomponents.o: $(UNISIM_BITS)
$(GHDL) -a $(GHDLFLAGS) --work=unisim --workdir=sim-unisim $^


fpga/soc_reset_tb.o: fpga/soc_reset.o fpga/soc_reset_tb.o: fpga/soc_reset.o


soc_reset_tb: fpga/soc_reset_tb.o fpga/soc_reset.o soc_reset_tb: fpga/soc_reset_tb.o fpga/soc_reset.o
@ -70,6 +79,9 @@ simple_ram_tb: simple_ram_tb.o
simple_ram_behavioural_tb: simple_ram_behavioural_helpers_c.o simple_ram_behavioural_tb.o simple_ram_behavioural_tb: simple_ram_behavioural_helpers_c.o simple_ram_behavioural_tb.o
$(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@ $(GHDL) -e $(GHDLFLAGS) -Wl,simple_ram_behavioural_helpers_c.o $@


dmi_dtm_tb: dmi_dtm_tb.o
$(GHDL) -e $(GHDLFLAGS) $@

tests = $(sort $(patsubst tests/%.out,%,$(wildcard tests/*.out))) tests = $(sort $(patsubst tests/%.out,%,$(wildcard tests/*.out)))


check: $(tests) test_micropython test_micropython_long check: $(tests) test_micropython test_micropython_long
@ -86,4 +98,5 @@ test_micropython_long: core_tb
@./scripts/test_micropython_long.py @./scripts/test_micropython_long.py


clean: clean:
rm -f *.o work-*cf $(all) rm -f *.o work-*cf unisim-*cf $(all)
rm -f sim-unisim/*.o sim-unisim/unisim-*cf

@ -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,214 @@
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
);

-- Dummy loopback until a debug module is present
dmi_din <= dmi_dout;
dmi_ack <= dmi_ack;

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

@ -46,6 +46,14 @@ filesets:
- fpga/firmware.hex : {copyto : firmware.hex, file_type : user} - fpga/firmware.hex : {copyto : firmware.hex, file_type : user}
file_type : vhdlSource-2008 file_type : vhdlSource-2008


debug_xilinx:
files:
- dmi_dtm_xilinx.vhdl : {file_type : vhdlSource-2008}

debug_dummy:
files:
- dmi_dtm_dummy.vhdl : {file_type : vhdlSource-2008}

nexys_a7: nexys_a7:
files: files:
- fpga/nexys_a7.xdc : {file_type : xdc} - fpga/nexys_a7.xdc : {file_type : xdc}
@ -69,7 +77,7 @@ filesets:
targets: targets:
nexys_a7: nexys_a7:
default_tool: vivado default_tool: vivado
filesets: [core, nexys_a7, soc, fpga] filesets: [core, nexys_a7, soc, fpga, debug_xilinx]
parameters : [memory_size, ram_init_file] parameters : [memory_size, ram_init_file]
tools: tools:
vivado: {part : xc7a100tcsg324-1} vivado: {part : xc7a100tcsg324-1}
@ -77,7 +85,7 @@ targets:


nexys_video: nexys_video:
default_tool: vivado default_tool: vivado
filesets: [core, nexys_video, soc, fpga] filesets: [core, nexys_video, soc, fpga, debug_xilinx]
parameters : [memory_size, ram_init_file] parameters : [memory_size, ram_init_file]
tools: tools:
vivado: {part : xc7a200tsbg484-1} vivado: {part : xc7a200tsbg484-1}
@ -85,7 +93,7 @@ targets:


arty_a7-35: arty_a7-35:
default_tool: vivado default_tool: vivado
filesets: [core, arty_a7-35, soc, fpga] filesets: [core, arty_a7-35, soc, fpga, debug_xilinx]
parameters : [memory_size, ram_init_file] parameters : [memory_size, ram_init_file]
tools: tools:
vivado: {part : xc7a35ticsg324-1L} vivado: {part : xc7a35ticsg324-1L}
@ -93,7 +101,7 @@ targets:


cmod_a7-35: cmod_a7-35:
default_tool: vivado default_tool: vivado
filesets: [core, cmod_a7-35, soc, fpga] filesets: [core, cmod_a7-35, soc, fpga, debug_xilinx]
parameters : [memory_size, ram_init_file, reset_low=false] parameters : [memory_size, ram_init_file, reset_low=false]
tools: tools:
vivado: {part : xc7a35tcpg236-1} vivado: {part : xc7a35tcpg236-1}

@ -0,0 +1,62 @@
#!/usr/bin/python3

import urjtag;

def do_command(urc, op, addr, data):
urc.set_dr_in(op,1,0)
urc.set_dr_in(data,65,2)
urc.set_dr_in(addr,73,66)
# print("Sending:", urc.get_dr_in_string())
urc.shift_dr()
urc.set_dr_in(0x0,73,0)
for x in range(5):
urc.shift_dr()
# print("Received:", urc.get_dr_out_string())
rsp_code = urc.get_dr_out(1,0)
if rsp_code == 0:
return urc.get_dr_out(65,2)
if rsp_code != 3:
print("Weird response ! rsp=%x" % rsp_code);
print("Timeout sending command !")

def do_read(urc, addr):
return do_command(urc, 1, addr, 0)

def do_write(urc, addr, val):
do_command(urc, 2, addr, val)

def main():
# Init jtag
#urjtag.loglevel( urjtag.URJ_LOG_LEVEL_ALL )

urc = urjtag.chain()
urc.cable("DigilentHS1")
print('Cable frequency:', urc.get_frequency())
#urc.tap_detect()
#length = urc.len()
#for i in range(0,urc.len()):
# idcode = urc.partid(0)
# print('[%d] 0x%08x' % (i, idcode))
urc.addpart(6);
print("Part ID: ", urc.partid(0))
#urc.part(0)
#urc.reset();
urc.add_register("USER2_REG", 74);
urc.add_instruction("USER2", "000011", "USER2_REG");
urc.add_register("IDCODE_REG", 32);
urc.add_instruction("IDCODE", "001001", "IDCODE_REG");
# Send test command
urc.set_instruction("IDCODE")
urc.shift_ir()
urc.shift_dr()
print("Got:", hex(urc.get_dr_out()))

urc.set_instruction("USER2")
urc.shift_ir()

print("Reading 0x00: %x" % do_read(urc, 0))
print("Reading 0xaa: %x" % do_read(urc, 0xaa))

if __name__ == "__main__":
main()

@ -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;
tdi <= j.tdi;
tms <= j.tms;
update <= j.update;
j.tdo <= tdo;
end architecture behaviour;

@ -0,0 +1,12 @@
library IEEE;
use IEEE.std_logic_1164.all;

entity BUFG is
port(I : in std_logic;
O : out std_logic
);
end BUFG;
architecture behaviour of BUFG is
begin
O <= I;
end architecture behaviour;

@ -0,0 +1,45 @@
library IEEE;
use IEEE.std_logic_1164.all;

package vcomponents is

-- Global JTAG signals. Xilinx implementation hooks that up to
-- their internal JTAG tap, we just expose them for the testbench
-- to use. These are used by our BSCANE2 block.
--
type glob_jtag_t is record
reset : std_logic;
tck : std_logic;
tdo : std_logic;
tdi : std_logic;
tms : std_logic;
sel : std_logic_vector(4 downto 1);
capture : std_logic;
shift : std_logic;
update : std_logic;
runtest : std_logic;
end record glob_jtag_t;
signal glob_jtag : glob_jtag_t;

component 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 component BSCANE2;
component BUFG is
port(I : in std_logic;
O : out std_logic
);
end component BUFG;
end package vcomponents;

@ -52,10 +52,18 @@ architecture behaviour of soc is
signal wb_bram_out : wishbone_slave_out; signal wb_bram_out : wishbone_slave_out;
constant mem_adr_bits : positive := positive(ceil(log2(real(MEMORY_SIZE)))); constant mem_adr_bits : positive := positive(ceil(log2(real(MEMORY_SIZE))));


-- Debug signals (used in SIM only) -- Core debug signals (used in SIM only)
signal registers : regfile; signal registers : regfile;
signal terminate : std_ulogic; signal terminate : std_ulogic;


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

begin begin


-- Processor core -- Processor core
@ -177,4 +185,25 @@ begin
wishbone_out => wb_bram_out wishbone_out => wb_bram_out
); );


-- DMI(debug bus) <-> JTAG bridge
dtm: entity work.dmi_dtm
generic map(
ABITS => 8,
DBITS => 64
)
port map(
sys_clk => system_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
);

-- Dummy loopback until a debug module is present
dmi_din <= dmi_dout;
dmi_ack <= dmi_ack;

end architecture behaviour; end architecture behaviour;

Loading…
Cancel
Save