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