diff --git a/Makefile b/Makefile index 62e9644..a554529 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ GHDL=ghdl -GHDLFLAGS=--std=08 +GHDLFLAGS=--std=08 -Psim-unisim 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 # 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.o: wishbone_types.o simple_ram_behavioural_helpers.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_types.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 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 $(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))) check: $(tests) test_micropython test_micropython_long @@ -86,4 +98,5 @@ test_micropython_long: core_tb @./scripts/test_micropython_long.py clean: - rm -f *.o work-*cf $(all) + rm -f *.o work-*cf unisim-*cf $(all) + rm -f sim-unisim/*.o sim-unisim/unisim-*cf diff --git a/dmi_dtm_dummy.vhdl b/dmi_dtm_dummy.vhdl new file mode 100644 index 0000000..3cabf38 --- /dev/null +++ b/dmi_dtm_dummy.vhdl @@ -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; + diff --git a/dmi_dtm_tb.vhdl b/dmi_dtm_tb.vhdl new file mode 100644 index 0000000..d872c13 --- /dev/null +++ b/dmi_dtm_tb.vhdl @@ -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; diff --git a/dmi_dtm_xilinx.vhdl b/dmi_dtm_xilinx.vhdl new file mode 100644 index 0000000..bab7ce8 --- /dev/null +++ b/dmi_dtm_xilinx.vhdl @@ -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; + diff --git a/microwatt.core b/microwatt.core index b62aef9..04b9d2c 100644 --- a/microwatt.core +++ b/microwatt.core @@ -46,6 +46,14 @@ filesets: - fpga/firmware.hex : {copyto : firmware.hex, file_type : user} 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: files: - fpga/nexys_a7.xdc : {file_type : xdc} @@ -69,7 +77,7 @@ filesets: targets: nexys_a7: default_tool: vivado - filesets: [core, nexys_a7, soc, fpga] + filesets: [core, nexys_a7, soc, fpga, debug_xilinx] parameters : [memory_size, ram_init_file] tools: vivado: {part : xc7a100tcsg324-1} @@ -77,7 +85,7 @@ targets: nexys_video: default_tool: vivado - filesets: [core, nexys_video, soc, fpga] + filesets: [core, nexys_video, soc, fpga, debug_xilinx] parameters : [memory_size, ram_init_file] tools: vivado: {part : xc7a200tsbg484-1} @@ -85,7 +93,7 @@ targets: arty_a7-35: 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] tools: vivado: {part : xc7a35ticsg324-1L} @@ -93,7 +101,7 @@ targets: cmod_a7-35: 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] tools: vivado: {part : xc7a35tcpg236-1} diff --git a/scripts/mw_debug.py b/scripts/mw_debug.py new file mode 100755 index 0000000..fe48743 --- /dev/null +++ b/scripts/mw_debug.py @@ -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() diff --git a/sim-unisim/BSCANE2.vhdl b/sim-unisim/BSCANE2.vhdl new file mode 100644 index 0000000..15211fa --- /dev/null +++ b/sim-unisim/BSCANE2.vhdl @@ -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; + diff --git a/sim-unisim/BUFG.vhdl b/sim-unisim/BUFG.vhdl new file mode 100644 index 0000000..462017a --- /dev/null +++ b/sim-unisim/BUFG.vhdl @@ -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; diff --git a/sim-unisim/unisim_vcomponents.vhdl b/sim-unisim/unisim_vcomponents.vhdl new file mode 100644 index 0000000..7faebac --- /dev/null +++ b/sim-unisim/unisim_vcomponents.vhdl @@ -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; diff --git a/soc.vhdl b/soc.vhdl index 4ccbc12..735d86c 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -52,10 +52,18 @@ architecture behaviour of soc is signal wb_bram_out : wishbone_slave_out; 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 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 -- Processor core @@ -177,4 +185,25 @@ begin 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;