initial commit of JTAGToDMI debug interface translated from
[soc.git] / src / soc / experiment / dmi_dtm_xilinx.py
1 """JTAGToDMI
2
3 based on Anton Blanchard microwatt dmi_dtm_xilinx.vhdl
4
5 """
6
7 from enum import Enum, unique
8 from nmigen import (Module, Signal, Elaboratable, Cat, Signal)
9 from nmigen.cli import main
10 from nmigen.cli import rtlil
11 from nmutil.iocontrol import RecordObject
12 from nmutil.byterev import byte_reverse
13 from nmutil.mask import Mask
14 from nmigen.util import log2_int
15
16 # -- Xilinx internal JTAG to DMI interface
17 # --
18 # -- DMI bus
19 # --
20 # -- req : ____/------------\_____
21 # -- addr: xxxx< >xxxxx
22 # -- dout: xxxx< >xxxxx
23 # -- wr : xxxx< >xxxxx
24 # -- din : xxxxxxxxxxxx< >xxx
25 # -- ack : ____________/------\___
26 # --
27 # -- * addr/dout set along with req, can be latched on same cycle by slave
28 # -- * ack & din remain up until req is dropped by master, the slave must
29 # -- provide a stable output on din on reads during that time.
30 # -- * req remains low at until at least one sysclk after ack seen down.
31 # --
32 # -- JTAG (tck) DMI (sys_clk)
33 # --
34 # -- * jtag_req = 1
35 # -- (jtag_req_0) *
36 # -- (jtag_req_1) -> * dmi_req = 1 >
37 # -- *.../...
38 # -- * dmi_ack = 1 <
39 # -- * (dmi_ack_0)
40 # -- * <- (dmi_ack_1)
41 # -- * jtag_req = 0 (and latch dmi_din)
42 # -- (jtag_req_0) *
43 # -- (jtag_req_1) -> * dmi_req = 0 >
44 # -- * dmi_ack = 0 <
45 # -- * (dmi_ack_0)
46 # -- * <- (dmi_ack_1)
47 # --
48 # -- jtag_req can go back to 1 when jtag_rsp_1 is 0
49 # --
50 # -- Questions/TODO:
51 # -- - I use 2 flip fops for sync, is that enough ?
52 # -- - I treat the jtag_reset as an async reset, is that necessary ?
53 # -- - Dbl check reset situation since we have two different resets
54 # -- each only resetting part of the logic...
55 # -- - Look at optionally removing the synchronizer on the ack path,
56 # -- assuming JTAG is always slow enough that ack will have been
57 # -- stable long enough by the time CAPTURE comes in.
58 # -- - We could avoid the latched request by not shifting while a
59 # -- request is in progress (and force TDO to 1 to return a busy
60 # -- status).
61 # --
62 # -- WARNING: This isn't the real DMI JTAG protocol (at least not yet).
63 # -- a command while busy will be ignored. A response of "11"
64 # -- means the previous command is still going, try again.
65 # -- As such We don't implement the DMI "error" status, and
66 # -- we don't implement DTMCS yet... This may still all change
67 # -- but for now it's easier that way as the real DMI protocol
68 # -- requires for a command to work properly that enough TCK
69 # -- are sent while IDLE and I'm having trouble getting that
70 # -- working with UrJtag and the Xilinx BSCAN2 for now.
71 #
72 # library ieee;
73 # use ieee.std_logic_1164.all;
74 # use ieee.math_real.all;
75 #
76 # library work;
77 # use work.wishbone_types.all;
78 #
79 # library unisim;
80 # use unisim.vcomponents.all;
81 #
82 # entity dmi_dtm is
83 # generic(ABITS : INTEGER:=8;
84 # DBITS : INTEGER:=32);
85 #
86 # port(sys_clk : in std_ulogic;
87 # sys_reset : in std_ulogic;
88 # dmi_addr : out std_ulogic_vector(ABITS - 1 downto 0);
89 # dmi_din : in std_ulogic_vector(DBITS - 1 downto 0);
90 # dmi_dout : out std_ulogic_vector(DBITS - 1 downto 0);
91 # dmi_req : out std_ulogic;
92 # dmi_wr : out std_ulogic;
93 # dmi_ack : in std_ulogic
94 # -- dmi_err : in std_ulogic TODO: Add error response
95 # );
96 # end entity dmi_dtm;
97 #
98 # architecture behaviour of dmi_dtm is
99 #
100 # -- Signals coming out of the BSCANE2 block
101 # signal jtag_reset : std_ulogic;
102 # signal capture : std_ulogic;
103 # signal update : std_ulogic;
104 # signal drck : std_ulogic;
105 # signal jtag_clk : std_ulogic;
106 # signal sel : std_ulogic;
107 # signal shift : std_ulogic;
108 # signal tdi : std_ulogic;
109 # signal tdo : std_ulogic;
110 # signal tck : std_ulogic;
111 #
112 # -- ** JTAG clock domain **
113 #
114 # -- Shift register
115 # signal shiftr : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
116 #
117 # -- Latched request
118 # signal request : std_ulogic_vector(ABITS + DBITS + 1 downto 0);
119 #
120 # -- A request is present
121 # signal jtag_req : std_ulogic;
122 #
123 # -- Synchronizer for jtag_rsp (sys clk -> jtag_clk)
124 # signal dmi_ack_0 : std_ulogic;
125 # signal dmi_ack_1 : std_ulogic;
126 #
127 # -- ** sys clock domain **
128 #
129 # -- Synchronizer for jtag_req (jtag clk -> sys clk)
130 # signal jtag_req_0 : std_ulogic;
131 # signal jtag_req_1 : std_ulogic;
132 #
133 # -- ** combination signals
134 # signal jtag_bsy : std_ulogic;
135 # signal op_valid : std_ulogic;
136 # signal rsp_op : std_ulogic_vector(1 downto 0);
137 #
138 # -- ** Constants **
139 # constant DMI_REQ_NOP : std_ulogic_vector(1 downto 0) := "00";
140 # constant DMI_REQ_RD : std_ulogic_vector(1 downto 0) := "01";
141 # constant DMI_REQ_WR : std_ulogic_vector(1 downto 0) := "10";
142 # constant DMI_RSP_OK : std_ulogic_vector(1 downto 0) := "00";
143 # constant DMI_RSP_BSY : std_ulogic_vector(1 downto 0) := "11";
144 #
145 # attribute ASYNC_REG : string;
146 # attribute ASYNC_REG of jtag_req_0: signal is "TRUE";
147 # attribute ASYNC_REG of jtag_req_1: signal is "TRUE";
148 # attribute ASYNC_REG of dmi_ack_0: signal is "TRUE";
149 # attribute ASYNC_REG of dmi_ack_1: signal is "TRUE";
150 # begin
151 #
152 # -- Implement the Xilinx bscan2 for series 7 devices (TODO: use PoC
153 # -- to wrap this if compatibility is required with older devices).
154 # bscan : BSCANE2
155 # generic map (
156 # JTAG_CHAIN => 2
157 # )
158 # port map (
159 # CAPTURE => capture,
160 # DRCK => drck,
161 # RESET => jtag_reset,
162 # RUNTEST => open,
163 # SEL => sel,
164 # SHIFT => shift,
165 # TCK => tck,
166 # TDI => tdi,
167 # TMS => open,
168 # UPDATE => update,
169 # TDO => tdo
170 # );
171 #
172 # -- Some examples out there suggest buffering the clock so it's
173 # -- treated as a proper clock net. This is probably needed when using
174 # -- drck (the gated clock) but I'm using the real tck here to avoid
175 # -- missing the update phase so maybe not...
176 # --
177 # clkbuf : BUFG
178 # port map (
179 # -- I => drck,
180 # I => tck,
181 # O => jtag_clk
182 # );
183 #
184 # -- dmi_req synchronization
185 # dmi_req_sync : process(sys_clk)
186 # begin
187 # -- sys_reset is synchronous
188 # if rising_edge(sys_clk) then
189 # if (sys_reset = '1') then
190 # jtag_req_0 <= '0';
191 # jtag_req_1 <= '0';
192 # else
193 # jtag_req_0 <= jtag_req;
194 # jtag_req_1 <= jtag_req_0;
195 # end if;
196 # end if;
197 # end process;
198 # dmi_req <= jtag_req_1;
199 #
200 # -- dmi_ack synchronization
201 # dmi_ack_sync: process(jtag_clk, jtag_reset)
202 # begin
203 # -- jtag_reset is async (see comments)
204 # if jtag_reset = '1' then
205 # dmi_ack_0 <= '0';
206 # dmi_ack_1 <= '0';
207 # elsif rising_edge(jtag_clk) then
208 # dmi_ack_0 <= dmi_ack;
209 # dmi_ack_1 <= dmi_ack_0;
210 # end if;
211 # end process;
212 #
213 # -- jtag_bsy indicates whether we can start a new request,
214 # -- we can when we aren't already processing one (jtag_req)
215 # -- and the synchronized ack of the previous one is 0.
216 # --
217 # jtag_bsy <= jtag_req or dmi_ack_1;
218 #
219 # -- decode request type in shift register
220 # with shiftr(1 downto 0) select op_valid <=
221 # '1' when DMI_REQ_RD,
222 # '1' when DMI_REQ_WR,
223 # '0' when others;
224 #
225 # -- encode response op
226 # rsp_op <= DMI_RSP_BSY when jtag_bsy = '1' else DMI_RSP_OK;
227 #
228 # -- Some DMI out signals are directly driven from the request register
229 # dmi_addr <= request(ABITS + DBITS + 1 downto DBITS + 2);
230 # dmi_dout <= request(DBITS + 1 downto 2);
231 # dmi_wr <= '1' when request(1 downto 0) = DMI_REQ_WR else '0';
232 #
233 # -- TDO is wired to shift register bit 0
234 # tdo <= shiftr(0);
235 #
236 # -- Main state machine. Handles shift registers, request latch and
237 # -- jtag_req latch. Could be split into 3 processes but it's probably
238 # -- not worthwhile.
239 # --
240 # shifter: process(jtag_clk, jtag_reset)
241 # begin
242 # if jtag_reset = '1' then
243 # shiftr <= (others => '0');
244 # jtag_req <= '0';
245 # elsif rising_edge(jtag_clk) then
246 #
247 # -- Handle jtag "commands" when sel is 1
248 # if sel = '1' then
249 # -- Shift state, rotate the register
250 # if shift = '1' then
251 # shiftr <= tdi & shiftr(ABITS + DBITS + 1 downto 1);
252 # end if;
253 #
254 # -- Update state (trigger)
255 # --
256 # -- Latch the request if we aren't already processing
257 # -- one and it has a valid command opcode.
258 # --
259 # if update = '1' and op_valid = '1' then
260 # if jtag_bsy = '0' then
261 # request <= shiftr;
262 # jtag_req <= '1';
263 # end if;
264 # -- Set the shift register "op" to "busy".
265 # -- This will prevent us from re-starting
266 # -- the command on the next update if
267 # -- the command completes before that.
268 # shiftr(1 downto 0) <= DMI_RSP_BSY;
269 # end if;
270 #
271 # -- Request completion.
272 # --
273 # -- Capture the response data for reads and
274 # -- clear request flag.
275 # --
276 # -- Note: We clear req (and thus dmi_req) here which
277 # -- relies on tck ticking and sel set. This means we
278 # -- are stuck with dmi_req up if the jtag interface stops.
279 # -- Slaves must be resilient to this.
280 # --
281 # if jtag_req = '1' and dmi_ack_1 = '1' then
282 # jtag_req <= '0';
283 # if request(1 downto 0) = DMI_REQ_RD then
284 # request(DBITS + 1 downto 2) <= dmi_din;
285 # end if;
286 # end if;
287 #
288 # -- Capture state, grab latch content with updated status
289 # if capture = '1' then
290 # shiftr <= request(ABITS + DBITS + 1 downto 2) & rsp_op;
291 # end if;
292 #
293 # end if;
294 # end if;
295 # end process;
296 # end architecture behaviour;