mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
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>
215 lines
4.8 KiB
VHDL
215 lines
4.8 KiB
VHDL
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;
|