Remove FSF address from GPL notices
[openocd.git] / src / jtag / drivers / rlink_call.m4
blobb27f3923860a9893c4d980d2553cba0247fd7d95
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  ***************************************************************************/
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'))
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')')
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 ')))))')
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.
41 m4_dnl This one is self-contained.
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)
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 )')
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.
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 )')
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)
74         m4_ifelse(m4_eval(`('$1`) % 2'), 1, `   NOP')
75         DECY
76         JP -1
77 )')
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.
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'))')
85 m4_divert(`0')m4_dnl
87 ;------------------------------------------------------------------------------
88 :opcode_error
89 ; This is at address 0x00 in case of empty LUT entries
90         STATUS STOP ERROR
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
98 :command_interpreter
99         A = DATA_BUFFER0
100         ADR_BUFFER0 += X
101         CMP01 = A       ; store the current command for later
103         EXCHANGE        ; put MSN into LSN
104         A.H = 0xc       ; lookup table at 0x1550 + 0xc0 = 0x1610
106         ; branch to address in lookup table
107         Y = A
108         A = <Y>
109         BRANCH
111 ;------------------------------------------------------------------------------
112 ; LUT for high nybble
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
132 ;------------------------------------------------------------------------------
133 ; USB/buffer handling
136 ;ENTRY; download entry_download
138 opcode_stop:
139 opcode_next_buffer:
140         ; pointer to completion flag
141         A.H = 0xf
142         A.L = 0xf
143         Y = A
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
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
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)
164         ADR_BUFFER01 = A
165         OR_MPEG = A     ; store for next iteration
167         A.L = 0x0
168         BUFFER_MNGT = A ; finish acking previous buffer
169         Y = A
170         ADR_BUFFER00 = A
171         ADR_BUFFER11 = A
173         A.H = 0x4       ; Output buffer = 0x1590 (0x0040)
174         ADR_BUFFER10 = A
176         EXCHANGE        ; 0x04
177         X = A           ; for the spin loop below
179         ; pointer to status in shared memory
180         DECY            ; setting to 0 above and decrementing here saves a byte
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
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
193         ; go to command interpreter
194         BRANCH
197 ;;------------------------------------------------------------------------------
198 ;:opcode_stop
201 ;       ; Ack buffer 0 in download mode
202 ;       A.L = 0x1
203 ;       BUFFER_MNGT = A
205 ;       STATUS STOP
208 ;------------------------------------------------------------------------------
209 :opcode_shift_tdi_andor_tms_bytes
212         A = CMP01       ; bits 3..0 contain the number of bytes to shift - 1
213         A.H = 0
214         Y = A           ; loop counter
216         A = CMP01
217         EXCHANGE
218         CMP01 = A       ; we're interested in bits in the high nybble
220 opcode_shift_tdi_andor_tms_bytes__loop:
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
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
242 ; run both shifters as nearly simultaneously as possible
243         SHIFT MPEG OUT=>PIN1
245         A = CTRL_FCI
246         EXCHANGE
247         BCLR 3
248         JP -3
250         DECY
251         JP opcode_shift_tdi_andor_tms_bytes__loop
253         A = X
254         BRANCH
257 ;------------------------------------------------------------------------------
258 :opcode_shift_tdo_bytes
261         A = CMP01       ; bits 3..0 contain the number of bytes to shift - 1
262         A.H = 0
263         Y = A           ; loop counter
265 opcode_shift_tdo_bytes__loop:
266         SHIFT MPEG PIN0=>IN
268         A = CTRL_FCI
269         EXCHANGE
270         BCLR 3
271         JP -3
273         ; put shifted byte into output buffer
274         A = SHIFT_MPEG
275         DATA_BUFFER1 = A
276         ADR_BUFFER1 += X
278         DECY
279         JP opcode_shift_tdo_bytes__loop
281         A = X
282         BRANCH
285 ;------------------------------------------------------------------------------
286 :opcode_shift_tdio_bytes
289         A = CMP01       ; bits 3..0 contain the number of bytes to shift - 1
290         A.H = 0
291         CMP10 = A       ; byte loop counter
293         A.H = opcode_shift_tdio_bytes__sub_return
294         A.L = opcode_shift_tdio_bytes__sub_return
295         CMP00 = A       ; return address
297 opcode_shift_tdio_bytes__loop:
298         A.H = 0
299         A.L = 7
300         CMP11 = A               ; always use 8 bits
302         JP sub_shift_tdio_bits
303 opcode_shift_tdio_bytes__sub_return:
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
312         A = X
313 ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
314         BRANCH
317 ;------------------------------------------------------------------------------
318 :opcode_shift_tdio_bits
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
326         A.H = opcode_shift_tdio_bits__sub_return
327         A.L = opcode_shift_tdio_bits__sub_return
328         CMP00 = A       ; return address
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:
336         A = X
337 ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
338         BRANCH
341 ;------------------------------------------------------------------------------
342 :sub_shift_tdio_bits
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
349 :sub_shift_tdio_bits__loop
350 m4_delay_setup(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
352         A = MASK        ; shift TDO into and TDI out of MASK via carry
353         A += MASK
354         MASK = A
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
363 m4_delay_loop(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
365         BSET 2          ; TCK high
366         DR_MPEG = A
368         A = DR_MPEG     ; set carry bit to TDO
369         CLC
370         BCLR 0
371         JP +2
372         SEC
374 m4_delay(HOLD_DELAY_CYCLES - 10)
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
383         ; shift last TDO bit into result
384         A = MASK
385         A += MASK
386         DATA_BUFFER1 = A
387         ADR_BUFFER1 += X
389         A = CMP00       ; return to caller
390         BRANCH
393 ;------------------------------------------------------------------------------
394 :opcode_shift_tms_tdi_bit_pair
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
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
414         A.H = 0
415         A.L = 0
416         CMP11 = A       ; bit loop counter (only doing one bit)
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
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:
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
433         A = X
434         DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
435         BRANCH
438 ;------------------------------------------------------------------------------
439 :opcode_shift_tms_bits
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
446         A = DATA_BUFFER0        ; get byte from input buffer
447         ADR_BUFFER0 += X
448         MASK = A                ; The byte we'll be shifting
450 :opcode_shift_tms_bits__loop
451 m4_delay_setup(SETUP_DELAY_CYCLES - 1)
453         A = MASK        ; shift TMS out of MASK via carry
454         A += MASK
455         MASK = A
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
465 m4_delay_loop(SETUP_DELAY_CYCLES - 1)
467         BSET 2          ; TCK high
468         DR_MPEG = A
470 m4_delay(HOLD_DELAY_CYCLES - 10)
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
479         A = X
480         DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
481         BRANCH