2 /***************************************************************************
3 * Copyright (C) 2008 Lou Deluxe *
4 * lou.openocd012@fixit.nospammail.net *
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. *
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. *
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
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.
44 `; delay (m4_eval($1) cycles)'
45 `m4_ifelse(m4_eval(`('$1`) < 6'), 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')
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')
69 m4_define(`m4_delay_loop',
70 `; delay loop (m4_eval($1) cycles)'
71 `m4_ifelse(m4_eval(`('$1`) < 6'), 1,
74 m4_ifelse(m4_eval(`('$1`) % 2'), 1, ` NOP')
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'))')
87 ;------------------------------------------------------------------------------
89 ; This is at address 0x00 in case of empty LUT entries
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.
95 ; Assumes ADR_BUFFER0 points to the next command byte
96 ; Stores the current command byte in CMP01
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
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
132 ;------------------------------------------------------------------------------
133 ; USB/buffer handling
136 ;ENTRY; download entry_download
140 ; pointer to completion flag
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
154 ; A.H = 0x0 ; already zero from BUFFER_MNGT
155 A.L = 0x3 ; Input buffer 1 = 0x1850 (0x0300)
158 opcode_next_buffer_0:
159 A.L = 0x2 ; ack buffer 1
162 A = X ; Input buffer 0 = 0x1650 (0x0100)
165 OR_MPEG = A ; store for next iteration
168 BUFFER_MNGT = A ; finish acking previous buffer
173 A.H = 0x4 ; Output buffer = 0x1590 (0x0040)
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.
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
193 ; go to command interpreter
197 ;;------------------------------------------------------------------------------
201 ; ; Ack buffer 0 in download mode
208 ;------------------------------------------------------------------------------
209 :opcode_shift_tdi_andor_tms_bytes
212 A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
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
233 ; set tms to supplied byte or zero
242 ; run both shifters as nearly simultaneously as possible
251 JP opcode_shift_tdi_andor_tms_bytes__loop
257 ;------------------------------------------------------------------------------
258 :opcode_shift_tdo_bytes
261 A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
265 opcode_shift_tdo_bytes__loop:
273 ; put shifted byte into output buffer
279 JP opcode_shift_tdo_bytes__loop
285 ;------------------------------------------------------------------------------
286 :opcode_shift_tdio_bytes
289 A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
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:
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
310 JP opcode_shift_tdio_bytes__loop
313 ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
317 ;------------------------------------------------------------------------------
318 :opcode_shift_tdio_bits
321 A = CMP01 ; bits 2..0 contain the number of bits to shift - 1
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
333 JP sub_shift_tdio_bits
334 opcode_shift_tdio_bits__sub_return:
337 ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
341 ;------------------------------------------------------------------------------
345 A = DATA_BUFFER0 ; get byte from input buffer
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
357 A.L = 0x2 ; TCK=0, TDI=1
360 A.L = 0x0 ; TCK=0, TDI=0
363 m4_delay_loop(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
368 A = DR_MPEG ; set carry bit to TDO
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
381 JP :sub_shift_tdio_bits__loop
383 ; shift last TDO bit into result
389 A = CMP00 ; return to caller
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
405 ; stuff command buffer with bitmap of single TDI bit
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
426 opcode_shift_tms_tdi_bit_pair__sub_return:
429 BSET 3 ; bit says whether to return TDO
431 ADR_BUFFER1 -= X ; subroutine returns it, so undo that
434 DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
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)
444 CMP11 = A ; bit loop counter
446 A = DATA_BUFFER0 ; get byte from input buffer
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
458 A.L = 0x1 ; TCK=0, TDI=0, TMS=1
461 A.L = 0x0 ; TCK=0, TDI=0, TMS=0
465 m4_delay_loop(SETUP_DELAY_CYCLES - 1)
470 m4_delay(HOLD_DELAY_CYCLES - 10)
472 A = CMP11 ; bit loop counter
477 JP :opcode_shift_tms_bits__loop
480 DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it