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

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)