drivers/cmsis-dap: speed up sending multiple HID requests
[openocd.git] / src / jtag / drivers / rlink_call.m4
1 m4_divert(`-1')
2 /***************************************************************************
3 * Copyright (C) 2008 Lou Deluxe *
4 * lou.openocd012@fixit.nospammail.net *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20 m4_dnl Setup and hold times depend on SHIFTER_PRESCALER
21 m4_define(`SETUP_DELAY_CYCLES', m4_eval(`('SHIFTER_PRESCALER` + 1) / 2'))
22 m4_define(`HOLD_DELAY_CYCLES', m4_eval(`'SHIFTER_PRESCALER` / 2'))
23
24 m4_dnl Some macros to make nybble handling a little easier
25 m4_define(`m4_high_nybble', `m4_eval(`(($1) >> 4) & 0xf')')
26 m4_define(`m4_low_nybble', `m4_eval(`($1) & 0xf')')
27
28 m4_dnl A macro to generate a number of NOPs depending on the argument
29 m4_define(`m4_0_to_5_nops', `m4_ifelse(m4_eval(`($1) >= 1'), 1, ` NOP
30 'm4_ifelse(m4_eval(`($1) >= 2'), 1, ` NOP
31 'm4_ifelse(m4_eval(`($1) >= 3'), 1, ` NOP
32 'm4_ifelse(m4_eval(`($1) >= 4'), 1, ` NOP
33 'm4_ifelse(m4_eval(`($1) >= 5'), 1, ` NOP
34 ')))))')
35
36
37 m4_dnl Some macros to facilitate bit-banging delays.
38 m4_dnl There are 3 of them. One for self-contained delays, and two for those which must be split between setup and loop to keep from disturbing A at delay time.
39 m4_dnl The argument passed to any of them is the number of cycles which the delay should consume.
40
41 m4_dnl This one is self-contained.
42
43 m4_define(`m4_delay',
44 `; delay (m4_eval($1) cycles)'
45 `m4_ifelse(m4_eval(`('$1`) < 6'), 1,
46 m4_0_to_5_nops($1)
47 ,
48 m4_ifelse(m4_eval(`(('$1`) - 3) % 2'), 1, ` NOP')
49 A.H = m4_high_nybble(`(('$1`) - 3) / 2')
50 A.L = m4_low_nybble(`(('$1`) - 3) / 2')
51 Y = A
52 DECY
53 JP -1
54 )')
55
56
57 m4_dnl These are the setup and loop parts of the split delay.
58 m4_dnl The argument passed to both must match for the result to make sense.
59 m4_dnl The setup does not figure into the delay. It takes 3 cycles when a loop is used and none if nops are used.
60
61 m4_define(`m4_delay_setup',
62 `; delay setup (m4_eval($1) cycles)'
63 `m4_ifelse(m4_eval(`('$1`) < 6'), 0, ` '
64 A.H = m4_high_nybble(`('$1`) / 2')
65 A.L = m4_low_nybble(`('$1`) / 2')
66 Y = A
67 )')
68
69 m4_define(`m4_delay_loop',
70 `; delay loop (m4_eval($1) cycles)'
71 `m4_ifelse(m4_eval(`('$1`) < 6'), 1,
72 m4_0_to_5_nops($1)
73 ,
74 m4_ifelse(m4_eval(`('$1`) % 2'), 1, ` NOP')
75 DECY
76 JP -1
77 )')
78
79 m4_dnl These are utility macros for use with delays. Specifically, there is code below which needs some predictability in code size for relative jumps to reach. The m4_delay macro generates an extra NOP when an even delay is needed, and the m4_delay_loop macro generates an extra NOP when an odd delay is needed. Using this for the argument to the respective macro rounds up the argument so that the extra NOP will not be generated. There is also logic built in to cancel the rounding when the result is small enough that a loop would not be generated.
80
81 m4_define(`m4_delay_loop_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) + 1) / 2 * 2'))')
82 m4_define(`m4_delay_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) / 2 * 2) + 1'))')
83
84
85 m4_divert(`0')m4_dnl
86
87 ;------------------------------------------------------------------------------
88 :opcode_error
89 ; This is at address 0x00 in case of empty LUT entries
90 STATUS STOP ERROR
91
92 ;------------------------------------------------------------------------------
93 ; Command interpreter at address 0x01 because it is branched to a lot and having it be 0x01 means we can use X for it, which is already used for other purposes which want it to be 1.
94 ; Assumes X is 1
95 ; Assumes ADR_BUFFER0 points to the next command byte
96 ; Stores the current command byte in CMP01
97
98 :command_interpreter
99 A = DATA_BUFFER0
100 ADR_BUFFER0 += X
101 CMP01 = A ; store the current command for later
102
103 EXCHANGE ; put MSN into LSN
104 A.H = 0xc ; lookup table at 0x1550 + 0xc0 = 0x1610
105
106 ; branch to address in lookup table
107 Y = A
108 A = <Y>
109 BRANCH
110
111 ;------------------------------------------------------------------------------
112 ; LUT for high nybble
113
114 ;LUT; c0 opcode_error
115 ;LUT; c1 opcode_shift_tdi_andor_tms_bytes
116 ;LUT; c2 opcode_shift_tdi_andor_tms_bytes
117 ;LUT; c3 opcode_shift_tdi_andor_tms_bytes
118 ;LUT; c4 opcode_shift_tdo_bytes
119 ;LUT; c5 opcode_error
120 ;LUT; c6 opcode_shift_tdio_bytes
121 ;LUT; c7 opcode_error
122 ;LUT; c8 opcode_shift_tms_tdi_bit_pair
123 ;LUT; c9 opcode_shift_tms_bits
124 ;LUT; ca opcode_error
125 ;LUT; cb opcode_error
126 ;LUT; cc opcode_error
127 ;LUT; cd opcode_error
128 ;LUT; ce opcode_shift_tdio_bits
129 ;LUT; cf opcode_stop
130
131
132 ;------------------------------------------------------------------------------
133 ; USB/buffer handling
134 ;
135
136 ;ENTRY; download entry_download
137
138 opcode_stop:
139 opcode_next_buffer:
140 ; pointer to completion flag
141 A.H = 0xf
142 A.L = 0xf
143 Y = A
144
145 A = OR_MPEG ; buffer indicator from previous iteration
146 <Y> = A ; either indicator will have bit 0 set
147 BSET 1 ; was buffer 1 previously current?
148 ; A.H = 0 ; already zero from OR_MPEG
149 JP opcode_next_buffer_0
150
151 opcode_next_buffer_1:
152 A.L = 0x1 ; ack buffer 0
153 BUFFER_MNGT = A
154 ; A.H = 0x0 ; already zero from BUFFER_MNGT
155 A.L = 0x3 ; Input buffer 1 = 0x1850 (0x0300)
156 JP +4
157
158 opcode_next_buffer_0:
159 A.L = 0x2 ; ack buffer 1
160 BUFFER_MNGT = A
161 entry_download:
162 A = X ; Input buffer 0 = 0x1650 (0x0100)
163
164 ADR_BUFFER01 = A
165 OR_MPEG = A ; store for next iteration
166
167 A.L = 0x0
168 BUFFER_MNGT = A ; finish acking previous buffer
169 Y = A
170 ADR_BUFFER00 = A
171 ADR_BUFFER11 = A
172
173 A.H = 0x4 ; Output buffer = 0x1590 (0x0040)
174 ADR_BUFFER10 = A
175
176 EXCHANGE ; 0x04
177 X = A ; for the spin loop below
178
179 ; pointer to status in shared memory
180 DECY ; setting to 0 above and decrementing here saves a byte
181
182 ; wait until a command buffer is available
183 A = BUFFER_MNGT ; spin while neither of bits 2 or 3 are set
184 CP A<X ; this is slightly faster and smaller than trying to AND and compare the result, and it lets us just use the nybble-swapped 0x40 from the output buffer setup.
185 JP -2
186 <Y> = A ; update status once done spinning
187
188 ; restore X, since we used it
189 ; A.H = 0 ; high nybble of BUFFER_MNGT will always be 0 the way we use it
190 A.L = 1
191 X = A
192
193 ; go to command interpreter
194 BRANCH
195
196
197 ;;------------------------------------------------------------------------------
198 ;:opcode_stop
199 ;;
200 ;
201 ; ; Ack buffer 0 in download mode
202 ; A.L = 0x1
203 ; BUFFER_MNGT = A
204 ;
205 ; STATUS STOP
206
207
208 ;------------------------------------------------------------------------------
209 :opcode_shift_tdi_andor_tms_bytes
210 ;
211
212 A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
213 A.H = 0
214 Y = A ; loop counter
215
216 A = CMP01
217 EXCHANGE
218 CMP01 = A ; we're interested in bits in the high nybble
219
220 opcode_shift_tdi_andor_tms_bytes__loop:
221
222 ; set tdi to supplied byte or zero
223 A = CMP01
224 BSET 1
225 JP +4
226 A.H = 0
227 A.L = 0
228 JP +3
229 A = DATA_BUFFER0
230 ADR_BUFFER0 += X
231 SHIFT_MPEG = A
232
233 ; set tms to supplied byte or zero
234 A = CMP01
235 BCLR 0
236 JP +5
237 A = DATA_BUFFER0
238 ADR_BUFFER0 += X
239 SHIFT_CARD = A
240 SHIFT CARD OUT=>PIN0
241
242 ; run both shifters as nearly simultaneously as possible
243 SHIFT MPEG OUT=>PIN1
244
245 A = CTRL_FCI
246 EXCHANGE
247 BCLR 3
248 JP -3
249
250 DECY
251 JP opcode_shift_tdi_andor_tms_bytes__loop
252
253 A = X
254 BRANCH
255
256
257 ;------------------------------------------------------------------------------
258 :opcode_shift_tdo_bytes
259 ;
260
261 A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
262 A.H = 0
263 Y = A ; loop counter
264
265 opcode_shift_tdo_bytes__loop:
266 SHIFT MPEG PIN0=>IN
267
268 A = CTRL_FCI
269 EXCHANGE
270 BCLR 3
271 JP -3
272
273 ; put shifted byte into output buffer
274 A = SHIFT_MPEG
275 DATA_BUFFER1 = A
276 ADR_BUFFER1 += X
277
278 DECY
279 JP opcode_shift_tdo_bytes__loop
280
281 A = X
282 BRANCH
283
284
285 ;------------------------------------------------------------------------------
286 :opcode_shift_tdio_bytes
287 ;
288
289 A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
290 A.H = 0
291 CMP10 = A ; byte loop counter
292
293 A.H = opcode_shift_tdio_bytes__sub_return
294 A.L = opcode_shift_tdio_bytes__sub_return
295 CMP00 = A ; return address
296
297 opcode_shift_tdio_bytes__loop:
298 A.H = 0
299 A.L = 7
300 CMP11 = A ; always use 8 bits
301
302 JP sub_shift_tdio_bits
303 opcode_shift_tdio_bytes__sub_return:
304
305 A = CMP10 ; byte loop counter
306 CP A=>X
307 CLC
308 A -= X
309 CMP10 = A
310 JP opcode_shift_tdio_bytes__loop
311
312 A = X
313 ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
314 BRANCH
315
316
317 ;------------------------------------------------------------------------------
318 :opcode_shift_tdio_bits
319 ;
320
321 A = CMP01 ; bits 2..0 contain the number of bits to shift - 1
322 A.H = 0
323 BCLR 3 ; set TMS=1 if bit 3 was set
324 CMP11 = A ; bit loop counter
325
326 A.H = opcode_shift_tdio_bits__sub_return
327 A.L = opcode_shift_tdio_bits__sub_return
328 CMP00 = A ; return address
329
330 JP sub_shift_tdio_bits
331 A.L = 0x1 ; TMS=1
332 DR_CARD = A
333 JP sub_shift_tdio_bits
334 opcode_shift_tdio_bits__sub_return:
335
336 A = X
337 ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
338 BRANCH
339
340
341 ;------------------------------------------------------------------------------
342 :sub_shift_tdio_bits
343 ;
344
345 A = DATA_BUFFER0 ; get byte from input buffer
346 ADR_BUFFER0 += X
347 MASK = A ; put it in MASK where bit routine will use it
348
349 :sub_shift_tdio_bits__loop
350 m4_delay_setup(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
351
352 A = MASK ; shift TDO into and TDI out of MASK via carry
353 A += MASK
354 MASK = A
355
356 ; shifting out TDI
357 A.L = 0x2 ; TCK=0, TDI=1
358 CP CARRY
359 JP +2
360 A.L = 0x0 ; TCK=0, TDI=0
361 DR_MPEG = A
362
363 m4_delay_loop(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
364
365 BSET 2 ; TCK high
366 DR_MPEG = A
367
368 A = DR_MPEG ; set carry bit to TDO
369 CLC
370 BCLR 0
371 JP +2
372 SEC
373
374 m4_delay(HOLD_DELAY_CYCLES - 10)
375
376 A = CMP11 ; bit loop counter
377 Y = A ; use Y to avoid corrupting carry bit with subtract
378 DECY
379 A = Y
380 CMP11 = A
381 JP :sub_shift_tdio_bits__loop
382
383 ; shift last TDO bit into result
384 A = MASK
385 A += MASK
386 DATA_BUFFER1 = A
387 ADR_BUFFER1 += X
388
389 A = CMP00 ; return to caller
390 BRANCH
391
392
393 ;------------------------------------------------------------------------------
394 :opcode_shift_tms_tdi_bit_pair
395 ;
396
397 ; set TMS line manually
398 A = CMP01 ; bits 3..0 contain TDI and TMS bits and whether to return TDO
399 BSET 0 ; TMS bit
400 A.L = 0x1 ; TMS=1
401 JP +2
402 A.L = 0x0 ; TMS=0
403 DR_CARD = A
404
405 ; stuff command buffer with bitmap of single TDI bit
406 A = CMP01
407 BSET 1 ; TDI bit
408 A.H = 0x8 ; TDI=1
409 JP +2
410 A.H = 0x0 ; TDI=0
411 ADR_BUFFER0 -= X
412 DATA_BUFFER0 = A
413
414 A.H = 0
415 A.L = 0
416 CMP11 = A ; bit loop counter (only doing one bit)
417
418 A.H = opcode_shift_tms_tdi_bit_pair__sub_return
419 A.L = opcode_shift_tms_tdi_bit_pair__sub_return
420 CMP00 = A ; return address
421
422 ; jump this way due to relative jump range issues
423 A.H = sub_shift_tdio_bits
424 A.L = sub_shift_tdio_bits
425 BRANCH
426 opcode_shift_tms_tdi_bit_pair__sub_return:
427
428 A = CMP01
429 BSET 3 ; bit says whether to return TDO
430 JP +2
431 ADR_BUFFER1 -= X ; subroutine returns it, so undo that
432
433 A = X
434 DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
435 BRANCH
436
437
438 ;------------------------------------------------------------------------------
439 :opcode_shift_tms_bits
440 ;
441
442 A = CMP01 ; bits 3..0 contain the number of bits to shift - 1 (only 1-8 bits is valid... no checking, just improper operation)
443 A.H = 0
444 CMP11 = A ; bit loop counter
445
446 A = DATA_BUFFER0 ; get byte from input buffer
447 ADR_BUFFER0 += X
448 MASK = A ; The byte we'll be shifting
449
450 :opcode_shift_tms_bits__loop
451 m4_delay_setup(SETUP_DELAY_CYCLES - 1)
452
453 A = MASK ; shift TMS out of MASK via carry
454 A += MASK
455 MASK = A
456
457 ; shifting out TMS
458 A.L = 0x1 ; TCK=0, TDI=0, TMS=1
459 CP CARRY
460 JP +2
461 A.L = 0x0 ; TCK=0, TDI=0, TMS=0
462 DR_CARD = A
463 DR_MPEG = A
464
465 m4_delay_loop(SETUP_DELAY_CYCLES - 1)
466
467 BSET 2 ; TCK high
468 DR_MPEG = A
469
470 m4_delay(HOLD_DELAY_CYCLES - 10)
471
472 A = CMP11 ; bit loop counter
473 CP A=>X
474 CLC
475 A -= X
476 CMP11 = A
477 JP :opcode_shift_tms_bits__loop
478
479 A = X
480 DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
481 BRANCH
482
483

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)