]> git.sur5r.net Git - openocd/blob - src/jtag/drivers/rlink_call.m4
Remove FSF address from GPL notices
[openocd] / 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