- rlink interface support from Lou Deluxe <lou.openocd012@fixit.nospammail.net>

git-svn-id: svn://svn.berlios.de/openocd/trunk@1258 b42882b7-edfa-0310-969c-e2dbd0fdcd60
This commit is contained in:
kc8apf 2008-12-19 04:25:22 +00:00
parent e873a6d27c
commit 063f4c182c
18 changed files with 3641 additions and 1 deletions

View File

@ -116,6 +116,10 @@ AC_ARG_ENABLE(jlink,
AS_HELP_STRING([--enable-jlink], [Enable building support for the Segger J-Link JTAG Programmer]),
[build_jlink=$enableval], [build_jlink=no])
AC_ARG_ENABLE(rlink,
AS_HELP_STRING([--enable-rlink], [Enable building support for the Raisonance RLink JTAG Programmer]),
[build_rlink=$enableval], [build_rlink=no])
AC_ARG_WITH(ftd2xx,
[AS_HELP_STRING(--with-ftd2xx,
[Where libftd2xx can be found <default=search>])],
@ -286,6 +290,12 @@ else
AC_DEFINE(BUILD_JLINK, 0, [0 if you don't want the J-Link JTAG driver.])
fi
if test $build_rlink = yes; then
AC_DEFINE(BUILD_RLINK, 1, [1 if you want the RLink JTAG driver.])
else
AC_DEFINE(BUILD_RLINK, 0, [0 if you don't want the RLink JTAG driver.])
fi
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(openocd, 1.0)
@ -307,6 +317,7 @@ AM_CONDITIONAL(PRESTO_FTD2XX, test $build_presto_ftd2xx = yes)
AM_CONDITIONAL(USBPROG, test $build_usbprog = yes)
AM_CONDITIONAL(OOCD_TRACE, test $build_oocd_trace = yes)
AM_CONDITIONAL(JLINK, test $build_jlink = yes)
AM_CONDITIONAL(RLINK, test $build_rlink = yes)
AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
AM_CONDITIONAL(IS_MINGW, test $is_mingw = yes)
AM_CONDITIONAL(IS_WIN32, test $is_win32 = yes)

View File

@ -218,6 +218,8 @@ build properly.}
@option{--enable-presto_ftd2xx}
@item
@option{--enable-jlink}
@item
@option{--enable-rlink}
@end itemize
If you want to access the parallel port using the PPDEV interface you have to specify
@ -322,6 +324,18 @@ AT91SAM764 internally.
@* Link: @url{http://www.iar.com/website1/1.0.1.0/369/1/index.php}
@end itemize
@section USB RLINK based
Raisonance has an adapter called @b{RLink}. It exists in a stripped-down form on the STM32 Primer, permanently attached to the JTAG lines. It also exists on the STM32 Primer2, but that is wired for SWD and not JTAG, thus not supported.
@itemize @bullet
@item @b{Raisonance RLink}
@* Link: @url{http://www.raisonance.com/products/RLink.php}
@item @b{STM32 Primer}
@* Link: @url{http://www.stm32circle.com/resources/stm32primer.php}
@item @b{STM32 Primer2}
@* Link: @url{http://www.stm32circle.com/resources/stm32primer2.php}
@end itemize
@section USB Other
@itemize @bullet
@item @b{USBprog}
@ -1017,6 +1031,11 @@ ft2232_vid_pid 0x0403 0xbdc8
# jlink interface
interface jlink
@end verbatim
@b{A Raisonance RLink}
@verbatim
# rlink interface
interface rlink
@end verbatim
@b{Parallel Port}
@verbatim
interface parport
@ -1066,6 +1085,9 @@ libusb.
@item @b{jlink}
@* Segger jlink usb adapter
@item @b{rlink}
@* Raisonance RLink usb adapter
@comment - End parameters
@end itemize
@comment - End Interface
@ -1247,6 +1269,7 @@ pre_reset and post_reset events.
@item ft2232: 6MHz / (@var{number}+1)
@item amt jtagaccel: 8 / 2**@var{number}
@item jlink: maximum speed in kHz (0-12000), 0 will use RTCK
@item rlink: 24MHz / @var{number}, but only for certain values of @var{number}
@comment end speed list.
@end itemize

View File

@ -47,9 +47,13 @@ else
if JLINK
LIBUSB = -lusb
else
if RLINK
LIBUSB = -lusb
else
LIBUSB =
endif
endif
endif
if IS_WIN32
if FTD2XXDIR

View File

@ -99,7 +99,13 @@ else
JLINKFILES =
endif
if RLINK
RLINKFILES = rlink/rlink.c rlink/rlink_speed_table.c
else
RLINKFILES =
endif
libjtag_a_SOURCES = jtag.c $(BITBANGFILES) $(PARPORTFILES) $(DUMMYFILES) $(FT2232FILES) $(AMTJTAGACCELFILES) $(EP93XXFILES) \
$(AT91RM9200FILES) $(GW16012FILES) $(BITQFILES) $(PRESTOFILES) $(USBPROGFILES) $(ECOSBOARDFILES) $(JLINKFILES)
$(AT91RM9200FILES) $(GW16012FILES) $(BITQFILES) $(PRESTOFILES) $(USBPROGFILES) $(ECOSBOARDFILES) $(JLINKFILES) $(RLINKFILES)
noinst_HEADERS = bitbang.h jtag.h

View File

@ -196,6 +196,10 @@ static int hasKHz = 0;
extern jtag_interface_t jlink_interface;
#endif
#if BUILD_RLINK == 1
extern jtag_interface_t rlink_interface;
#endif
jtag_interface_t *jtag_interfaces[] = {
#if BUILD_ECOSBOARD == 1
&zy1000_interface,
@ -232,6 +236,9 @@ jtag_interface_t *jtag_interfaces[] = {
#endif
#if BUILD_JLINK == 1
&jlink_interface,
#endif
#if BUILD_RLINK == 1
&rlink_interface,
#endif
NULL,
};

73
src/jtag/rlink/Makefile Normal file
View File

@ -0,0 +1,73 @@
#***************************************************************************
#* Copyright (C) 2008 Lou Deluxe *
#* lou.openocd012@fixit.nospammail.net *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU General Public License as published by *
#* the Free Software Foundation; either version 2 of the License, or *
#* (at your option) any later version. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU General Public License for more details. *
#* *
#* You should have received a copy of the GNU General Public License *
#* along with this program; if not, write to the *
#* Free Software Foundation, Inc., *
#* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
#***************************************************************************
TOP = ../../..
INTERFACE_NAME = rlink
PERL = perl
M4 = m4
TARGETDIR = ${TOP}/src/target
TOOLSDIR = ${TOP}/tools
MAKE_SPEED_TABLE = ${TOOLSDIR}/rlink_make_speed_table/rlink_make_speed_table
ST7_DTC_AS = ${TOOLSDIR}/st7_dtc_as/st7_dtc_as
OPENOCD = ${TOP}/src/openocd
OPENOCD_CONFIG = -s ${TARGETDIR}
OPENOCD_CONFIG += -f interface/rlink.cfg
OPENOCD_CONFIG += -f board/stm32f10x_128k_eval.cfg
PATCHFILE = /tmp/openocd_${INTERFACE_NAME}.diff.gz
# relative to ${TOP}
SVNADDFILES =
SVNADDFILES += src/target/interface/rlink.cfg
SVNADDFILES += src/jtag/${INTERFACE_NAME}.c
SVNADDFILES += src/jtag/${INTERFACE_NAME}
PRESCALERS = 64 11 8 2
DTCFILES =
DTCFILES += $(addsuffix _init.dtc, ${PRESCALERS})
DTCFILES += $(addsuffix _call.dtc, ${PRESCALERS})
default: rlink_speed_table.c clean
%_init.fsm: init.m4
${M4} -P -DSHIFTER_PRESCALER=`echo "$@" | sed -e's/_.*//'` $< > $@
%_call.fsm: call.m4
${M4} -P -DSHIFTER_PRESCALER=`echo "$@" | sed -e's/_.*//'` $< > $@
%.dtc: %.fsm
${ST7_DTC_AS} -b -o $@ -i $< > /dev/null
rlink_speed_table.c: ${DTCFILES}
${MAKE_SPEED_TABLE} ${PRESCALERS} > $@ || rm $@
clean:
-rm *.dtc *.fsm
distclean: clean
test: default
(cd ${TOP} && (rm src/jtag/${INTERFACE_NAME}.o; ${MAKE}))
${OPENOCD} -d0 ${OPENOCD_CONFIG} -c init -c 'poll off'

485
src/jtag/rlink/call.m4 Normal file
View File

@ -0,0 +1,485 @@
m4_divert(`-1')
/***************************************************************************
* Copyright (C) 2008 Lou Deluxe *
* lou.openocd012@fixit.nospammail.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
m4_dnl Setup and hold times depend on SHIFTER_PRESCALER
m4_define(`SETUP_DELAY_CYCLES', m4_eval(`('SHIFTER_PRESCALER` + 1) / 2'))
m4_define(`HOLD_DELAY_CYCLES', m4_eval(`'SHIFTER_PRESCALER` / 2'))
m4_dnl Some macros to make nybble handling a little easier
m4_define(`m4_high_nybble', `m4_eval(`(($1) >> 4) & 0xf')')
m4_define(`m4_low_nybble', `m4_eval(`($1) & 0xf')')
m4_dnl A macro to generate a number of NOPs depending on the argument
m4_define(`m4_0_to_5_nops', `m4_ifelse(m4_eval(`($1) >= 1'), 1, ` NOP
'm4_ifelse(m4_eval(`($1) >= 2'), 1, ` NOP
'm4_ifelse(m4_eval(`($1) >= 3'), 1, ` NOP
'm4_ifelse(m4_eval(`($1) >= 4'), 1, ` NOP
'm4_ifelse(m4_eval(`($1) >= 5'), 1, ` NOP
')))))')
m4_dnl Some macros to facilitate bit-banging delays.
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.
m4_dnl The argument passed to any of them is the number of cycles which the delay should consume.
m4_dnl This one is self-contained.
m4_define(`m4_delay',
`; delay (m4_eval($1) cycles)'
`m4_ifelse(m4_eval(`('$1`) < 6'), 1,
m4_0_to_5_nops($1)
,
m4_ifelse(m4_eval(`(('$1`) - 3) % 2'), 1, ` NOP')
A.H = m4_high_nybble(`(('$1`) - 3) / 2')
A.L = m4_low_nybble(`(('$1`) - 3) / 2')
Y = A
DECY
JP -1
)')
m4_dnl These are the setup and loop parts of the split delay.
m4_dnl The argument passed to both must match for the result to make sense.
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.
m4_define(`m4_delay_setup',
`; delay setup (m4_eval($1) cycles)'
`m4_ifelse(m4_eval(`('$1`) < 6'), 0, ` '
A.H = m4_high_nybble(`('$1`) / 2')
A.L = m4_low_nybble(`('$1`) / 2')
Y = A
)')
m4_define(`m4_delay_loop',
`; delay loop (m4_eval($1) cycles)'
`m4_ifelse(m4_eval(`('$1`) < 6'), 1,
m4_0_to_5_nops($1)
,
m4_ifelse(m4_eval(`('$1`) % 2'), 1, ` NOP')
DECY
JP -1
)')
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.
m4_define(`m4_delay_loop_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) + 1) / 2 * 2'))')
m4_define(`m4_delay_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) / 2 * 2) + 1'))')
m4_divert(`0')m4_dnl
;------------------------------------------------------------------------------
:opcode_error
; This is at address 0x00 in case of empty LUT entries
STATUS STOP ERROR
;------------------------------------------------------------------------------
; 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.
; Assumes X is 1
; Assumes ADR_BUFFER0 points to the next command byte
; Stores the current command byte in CMP01
:command_interpreter
A = DATA_BUFFER0
ADR_BUFFER0 += X
CMP01 = A ; store the current command for later
EXCHANGE ; put MSN into LSN
A.H = 0xc ; lookup table at 0x1550 + 0xc0 = 0x1610
; branch to address in lookup table
Y = A
A = <Y>
BRANCH
;------------------------------------------------------------------------------
; LUT for high nybble
;LUT; c0 opcode_error
;LUT; c1 opcode_shift_tdi_andor_tms_bytes
;LUT; c2 opcode_shift_tdi_andor_tms_bytes
;LUT; c3 opcode_shift_tdi_andor_tms_bytes
;LUT; c4 opcode_shift_tdo_bytes
;LUT; c5 opcode_error
;LUT; c6 opcode_shift_tdio_bytes
;LUT; c7 opcode_error
;LUT; c8 opcode_shift_tms_tdi_bit_pair
;LUT; c9 opcode_shift_tms_bits
;LUT; ca opcode_error
;LUT; cb opcode_error
;LUT; cc opcode_error
;LUT; cd opcode_error
;LUT; ce opcode_shift_tdio_bits
;LUT; cf opcode_stop
;------------------------------------------------------------------------------
; USB/buffer handling
;
;ENTRY; download entry_download
opcode_stop:
opcode_next_buffer:
; pointer to completion flag
A.H = 0xf
A.L = 0xf
Y = A
A = OR_MPEG ; buffer indicator from previous iteration
<Y> = A ; either indicator will have bit 0 set
BSET 1 ; was buffer 1 previously current?
; A.H = 0 ; already zero from OR_MPEG
JP opcode_next_buffer_0
opcode_next_buffer_1:
A.L = 0x1 ; ack buffer 0
BUFFER_MNGT = A
; A.H = 0x0 ; already zero from BUFFER_MNGT
A.L = 0x3 ; Input buffer 1 = 0x1850 (0x0300)
JP +4
opcode_next_buffer_0:
A.L = 0x2 ; ack buffer 1
BUFFER_MNGT = A
entry_download:
A = X ; Input buffer 0 = 0x1650 (0x0100)
ADR_BUFFER01 = A
OR_MPEG = A ; store for next iteration
A.L = 0x0
BUFFER_MNGT = A ; finish acking previous buffer
Y = A
ADR_BUFFER00 = A
ADR_BUFFER11 = A
A.H = 0x4 ; Output buffer = 0x1590 (0x0040)
ADR_BUFFER10 = A
EXCHANGE ; 0x04
X = A ; for the spin loop below
; pointer to status in shared memory
DECY ; setting to 0 above and decrementing here saves a byte
; wait until a command buffer is available
A = BUFFER_MNGT ; spin while neither of bits 2 or 3 are set
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.
JP -2
<Y> = A ; update status once done spinning
; restore X, since we used it
; A.H = 0 ; high nybble of BUFFER_MNGT will always be 0 the way we use it
A.L = 1
X = A
; go to command interpreter
BRANCH
;;------------------------------------------------------------------------------
;:opcode_stop
;;
;
; ; Ack buffer 0 in download mode
; A.L = 0x1
; BUFFER_MNGT = A
;
; STATUS STOP
;------------------------------------------------------------------------------
:opcode_shift_tdi_andor_tms_bytes
;
A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
A.H = 0
Y = A ; loop counter
A = CMP01
EXCHANGE
CMP01 = A ; we're interested in bits in the high nybble
opcode_shift_tdi_andor_tms_bytes__loop:
; set tdi to supplied byte or zero
A = CMP01
BSET 1
JP +4
A.H = 0
A.L = 0
JP +3
A = DATA_BUFFER0
ADR_BUFFER0 += X
SHIFT_MPEG = A
; set tms to supplied byte or zero
A = CMP01
BCLR 0
JP +5
A = DATA_BUFFER0
ADR_BUFFER0 += X
SHIFT_CARD = A
SHIFT CARD OUT=>PIN0
; run both shifters as nearly simultaneously as possible
SHIFT MPEG OUT=>PIN1
A = CTRL_FCI
EXCHANGE
BCLR 3
JP -3
DECY
JP opcode_shift_tdi_andor_tms_bytes__loop
A = X
BRANCH
;------------------------------------------------------------------------------
:opcode_shift_tdo_bytes
;
A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
A.H = 0
Y = A ; loop counter
opcode_shift_tdo_bytes__loop:
SHIFT MPEG PIN0=>IN
A = CTRL_FCI
EXCHANGE
BCLR 3
JP -3
; put shifted byte into output buffer
A = SHIFT_MPEG
DATA_BUFFER1 = A
ADR_BUFFER1 += X
DECY
JP opcode_shift_tdo_bytes__loop
A = X
BRANCH
;------------------------------------------------------------------------------
:opcode_shift_tdio_bytes
;
A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
A.H = 0
CMP10 = A ; byte loop counter
A.H = opcode_shift_tdio_bytes__sub_return
A.L = opcode_shift_tdio_bytes__sub_return
CMP00 = A ; return address
opcode_shift_tdio_bytes__loop:
A.H = 0
A.L = 7
CMP11 = A ; always use 8 bits
JP sub_shift_tdio_bits
opcode_shift_tdio_bytes__sub_return:
A = CMP10 ; byte loop counter
CP A=>X
CLC
A -= X
CMP10 = A
JP opcode_shift_tdio_bytes__loop
A = X
;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
BRANCH
;------------------------------------------------------------------------------
:opcode_shift_tdio_bits
;
A = CMP01 ; bits 2..0 contain the number of bits to shift - 1
A.H = 0
BCLR 3 ; set TMS=1 if bit 3 was set
CMP11 = A ; bit loop counter
A.H = opcode_shift_tdio_bits__sub_return
A.L = opcode_shift_tdio_bits__sub_return
CMP00 = A ; return address
JP sub_shift_tdio_bits
A.L = 0x1 ; TMS=1
DR_CARD = A
JP sub_shift_tdio_bits
opcode_shift_tdio_bits__sub_return:
A = X
;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
BRANCH
;------------------------------------------------------------------------------
:sub_shift_tdio_bits
;
A = DATA_BUFFER0 ; get byte from input buffer
ADR_BUFFER0 += X
MASK = A ; put it in MASK where bit routine will use it
:sub_shift_tdio_bits__loop
m4_delay_setup(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
A = MASK ; shift TDO into and TDI out of MASK via carry
A += MASK
MASK = A
; shifting out TDI
A.L = 0x2 ; TCK=0, TDI=1
CP CARRY
JP +2
A.L = 0x0 ; TCK=0, TDI=0
DR_MPEG = A
m4_delay_loop(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
BSET 2 ; TCK high
DR_MPEG = A
A = DR_MPEG ; set carry bit to TDO
CLC
BCLR 0
JP +2
SEC
m4_delay(HOLD_DELAY_CYCLES - 10)
A = CMP11 ; bit loop counter
Y = A ; use Y to avoid corrupting carry bit with subtract
DECY
A = Y
CMP11 = A
JP :sub_shift_tdio_bits__loop
; shift last TDO bit into result
A = MASK
A += MASK
DATA_BUFFER1 = A
ADR_BUFFER1 += X
A = CMP00 ; return to caller
BRANCH
;------------------------------------------------------------------------------
:opcode_shift_tms_tdi_bit_pair
;
; set TMS line manually
A = CMP01 ; bits 3..0 contain TDI and TMS bits and whether to return TDO
BSET 0 ; TMS bit
A.L = 0x1 ; TMS=1
JP +2
A.L = 0x0 ; TMS=0
DR_CARD = A
; stuff command buffer with bitmap of single TDI bit
A = CMP01
BSET 1 ; TDI bit
A.H = 0x8 ; TDI=1
JP +2
A.H = 0x0 ; TDI=0
ADR_BUFFER0 -= X
DATA_BUFFER0 = A
A.H = 0
A.L = 0
CMP11 = A ; bit loop counter (only doing one bit)
A.H = opcode_shift_tms_tdi_bit_pair__sub_return
A.L = opcode_shift_tms_tdi_bit_pair__sub_return
CMP00 = A ; return address
; jump this way due to relative jump range issues
A.H = sub_shift_tdio_bits
A.L = sub_shift_tdio_bits
BRANCH
opcode_shift_tms_tdi_bit_pair__sub_return:
A = CMP01
BSET 3 ; bit says whether to return TDO
JP +2
ADR_BUFFER1 -= X ; subroutine returns it, so undo that
A = X
DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
BRANCH
;------------------------------------------------------------------------------
:opcode_shift_tms_bits
;
A = CMP01 ; bits 3..0 contain the number of bits to shift - 1 (only 1-8 bits is valid... no checking, just improper operation)
A.H = 0
CMP11 = A ; bit loop counter
A = DATA_BUFFER0 ; get byte from input buffer
ADR_BUFFER0 += X
MASK = A ; The byte we'll be shifting
:opcode_shift_tms_bits__loop
m4_delay_setup(SETUP_DELAY_CYCLES - 1)
A = MASK ; shift TMS out of MASK via carry
A += MASK
MASK = A
; shifting out TMS
A.L = 0x1 ; TCK=0, TDI=0, TMS=1
CP CARRY
JP +2
A.L = 0x0 ; TCK=0, TDI=0, TMS=0
DR_CARD = A
DR_MPEG = A
m4_delay_loop(SETUP_DELAY_CYCLES - 1)
BSET 2 ; TCK high
DR_MPEG = A
m4_delay(HOLD_DELAY_CYCLES - 10)
A = CMP11 ; bit loop counter
CP A=>X
CLC
A -= X
CMP11 = A
JP :opcode_shift_tms_bits__loop
A = X
DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
BRANCH

66
src/jtag/rlink/dtc_cmd.h Normal file
View File

@ -0,0 +1,66 @@
/***************************************************************************
* Copyright (C) 2008 Lou Deluxe *
* lou.openocd012@fixit.nospammail.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/* A command position with the high nybble of 0x0 is reserved for an error condition. If executed, it stops the DTC and raises the ERROR flag */
#define DTC_CMD_SHIFT_TMS_BYTES(bytes) ((0x1 << 4) | ((bytes) - 1))
/* Shift 1-16 bytes out TMS. TDI is 0. */
/* Bytes to shift follow. */
#define DTC_CMD_SHIFT_TDI_BYTES(bytes) ((0x2 << 4) | ((bytes) - 1))
/* Shift 1-16 bytes out TDI. TMS is 0. */
/* Bytes to shift follow. */
#define DTC_CMD_SHIFT_TDI_AND_TMS_BYTES(bytes) ((0x3 << 4) | ((bytes) - 1))
/* Shift 1-16 byte pairs out TDI and TMS. */
/* Byte pairs to shift follow in TDI, TMS order. */
#define DTC_CMD_SHIFT_TDO_BYTES(bytes) ((0x4 << 4) | ((bytes) - 1))
/* Shift 1-16 bytes in TDO. TMS is unaffected. */
/* Reply buffer contains bytes shifted in. */
#define DTC_CMD_SHIFT_TDIO_BYTES(bytes) ((0x6 << 4) | ((bytes) - 1))
/* Shift 1-16 bytes out TDI and in TDO. TMS is unaffected. */
#define DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(tms, tdi, tdo) ((0x8 << 4) | ( \
(tms) ? (1 << 0) : 0 \
) | ( \
(tdi) ? (1 << 1) : 0 \
) | ( \
(tdo) ? (1 << 3) : 0 \
))
/* Single bit shift. */
/* tms and tdi are the levels shifted out on TMS and TDI, respectively. */
/* tdo indicates whether a byte will be returned in the reply buffer with its least significant bit set to reflect TDO */
/* Care should be taken when tdo is zero, as the underlying code actually does put that byte in the reply buffer. Setting tdo to zero just moves the pointer back. The result is that if this command is executed when the reply buffer is already full, a byte will be written erroneously to memory not belonging to the reply buffer. This could be worked around at the expense of DTC code space and speed. */
#define DTC_CMD_SHIFT_TMS_BITS(bits) ((0x9 << 4) | ((bits) - 1))
/* Shift 1-8 bits out TMS. */
/* Bits to be shifted out are left justified in the following byte. */
#define DTC_CMD_SHIFT_TDIO_BITS(bits) ((0xe << 4) | ((bits) - 1))
/* Shift 1-8 bits out TDI and in TDO, TMS is unaffected. */
/* Bits to be shifted out are left justified in the following byte. */
/* Bits shifted in are right justified in the byte placed in the reply buffer. */
#define DTC_CMD_STOP (0xf << 4)
/* Stop processing the command buffer and wait for the next one. */
/* A shared status byte is updated with bit 0 set when this has happened, and it is cleared when a new command buffer becomes ready. The host can poll that byte to see when it is safe to read a reply. */

57
src/jtag/rlink/ep1_cmd.h Normal file
View File

@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (C) 2008 Lou Deluxe *
* lou.openocd012@fixit.nospammail.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/*
* Command opcodes that can be sent over endpoint 1.
* This codifies information provided by Rob Brown <rob@cobbleware.com>.
* The buffer can contain several of these, but only one which returns data.
* Some of these opcodes have arguments, which follow immediately.
* If shorter than the packet size, trailing positions should be zero-filled.
*/
/* LED update enables:
* When enabled, each LED is updated automatically.
* When not enabled, each LED can be controlled manually with EP1_CMD_SET_PORTD_LEDS.
*/
#define EP1_CMD_LEDUE_BOTH (0x05)
/* EP1_CMD_LEDUE_NONE has the side effect of turning the LEDs on */
#define EP1_CMD_LEDUE_NONE (0x06)
#define EP1_CMD_LEDUE_ERROR (0x17)
#define EP1_CMD_LEDUE_BUSY (0x18)
#define EP1_CMD_DTC_STOP (0x0b)
#define EP1_CMD_DTC_LOAD (0x0c)
#define EP1_CMD_DTC_CALL (0x0d)
#define EP1_CMD_SET_UPLOAD (0x0f)
#define EP1_CMD_SET_DOWNLOAD (0x10)
#define EP1_CMD_DTC_WAIT (0x12)
#define EP1_CMD_DTC_GET_STATUS (0x15)
/* a quick way to just read back one byte */
#define EP1_CMD_DTC_GET_CACHED_STATUS (0x16)
/* Writes upper 2 bits port D with argument */
#define EP1_CMD_SET_PORTD_UPPER (0x19)
/* Writes lower 2 bits (BUSY and ERROR) of port D with argument */
#define EP1_CMD_SET_PORTD_LEDS (0x1a)
#define EP1_CMD_MEMORY_READ (0x28)
#define EP1_CMD_MEMORY_WRITE (0x29)
#define EP1_CMD_GET_FWREV (0xfe)
#define EP1_CMD_GET_SERIAL (0xff)

74
src/jtag/rlink/init.m4 Normal file
View File

@ -0,0 +1,74 @@
m4_divert(`-1')
/***************************************************************************
* Copyright (C) 2008 Lou Deluxe *
* lou.openocd012@fixit.nospammail.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
m4_undefine(`CTRL_MPEG_L')
m4_undefine(`CTRL_CARD_L')
m4_ifelse(SHIFTER_PRESCALER, 1, `
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x0')')
')
m4_ifelse(SHIFTER_PRESCALER, 2, `
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x2')')
m4_define(`CTRL_CARD_L', `m4_eval(`0x8 | 0x1')')
')
m4_ifelse(SHIFTER_PRESCALER, 8, `
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x3')')
')
m4_ifelse(SHIFTER_PRESCALER, 11, `
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x4')')
')
m4_ifelse(SHIFTER_PRESCALER, 64, `
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x7')')
')
m4_ifdef(`CTRL_MPEG_L',,`
m4_errprint(`SHIFTER_PRESCALER was not defined with a supported value
') m4_m4exit(`1')
')
m4_divert(`0')m4_dnl
init:
A.H = 0
A.L = 0
DR_MPEG = A ; TDI and TCK start out low
DR_CARD = A ; TMS starts out low
A.L = 0x6
CTRL_FCI = A ; MPEG and CARD driven by FCI
DDR_MPEG = A ; TDI and TCK are outputs
A.L = 0x1
X = A ; X == 1
DDR_CARD = A ; TMS is output
A.L = CTRL_MPEG_L
CTRL_MPEG = A
m4_ifdef(`CTRL_CARD_L',
` A.L = 'CTRL_CARD_L`
')m4_dnl
CTRL_CARD = A
STATUS STOP

1808
src/jtag/rlink/rlink.c Normal file

File diff suppressed because it is too large Load Diff

33
src/jtag/rlink/rlink.h Normal file
View File

@ -0,0 +1,33 @@
/***************************************************************************
* Copyright (C) 2008 Lou Deluxe *
* lou.openocd012@fixit.nospammail.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "types.h"
#include <sys/types.h>
typedef
struct rlink_speed_table_s {
u8 const *dtc;
u16 dtc_size;
u16 khz;
u8 prescaler;
} rlink_speed_table_t;
extern const rlink_speed_table_t rlink_speed_table[];
extern const size_t rlink_speed_table_size;

View File

@ -0,0 +1,98 @@
/* This file was created automatically by ../../../tools/rlink_make_speed_table/rlink_make_speed_table.pl. */
#include "rlink.h"
#include "st7.h"
static const u8 dtc_64[] = {
0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
191, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42,
42, 73, 0, 88, 0, 160, 189, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119,
110, 108, 111, 97, 100, 2, 226, 7, 219, 39, 137, 51, 172, 130, 192, 96,
175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133,
153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177,
129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39,
154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193,
96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96,
201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105,
193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219,
39, 131, 161, 176, 130, 195, 53, 131, 178, 10, 66, 176, 151, 60, 97, 58,
151, 215, 2, 40, 66, 1, 0, 160, 185, 130, 60, 97, 203, 130, 60, 194, 139,
127, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168,
66, 160, 38, 155, 160, 176, 139, 171, 182, 136, 167, 183, 96, 201, 59,
66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 160, 191, 130, 195,
53, 131, 177, 10, 66, 176, 147, 151, 0, 60, 97, 58, 151, 0, 160, 185, 130,
60, 97, 203, 8, 2, 36, 139, 124, 193, 151, 96
};
static const u8 dtc_11[] = {
0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
188, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42,
42, 73, 0, 88, 0, 154, 183, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119,
110, 108, 111, 97, 100, 2, 213, 7, 219, 39, 137, 51, 172, 130, 192, 96,
175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133,
153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177,
129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39,
154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193,
96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96,
201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105,
193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219,
39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 0, 0, 58, 151, 215,
2, 40, 66, 1, 203, 130, 60, 194, 139, 121, 195, 53, 156, 47, 200, 96, 201,
56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 171,
176, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219,
39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 0, 0, 58, 151,
203, 8, 2, 36, 139, 117, 193, 151, 96
};
static const u8 dtc_8[] = {
0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
187, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42,
42, 73, 0, 88, 0, 152, 181, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119,
110, 108, 111, 97, 100, 2, 209, 7, 219, 39, 137, 51, 172, 130, 192, 96,
175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133,
153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177,
129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39,
154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193,
96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96,
201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105,
193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219,
39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 58, 151, 215, 2,
40, 66, 1, 203, 130, 60, 194, 139, 119, 195, 53, 156, 47, 200, 96, 201,
56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170,
190, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219,
39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 58, 151, 203,
8, 2, 36, 139, 115, 193, 151, 96
};
static const u8 dtc_2[] = {
0, 2, 68, 84, 67, 2, 14, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
186, 143, 185, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0,
42, 42, 42, 73, 0, 88, 0, 149, 178, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100,
111, 119, 110, 108, 111, 97, 100, 2, 203, 7, 219, 39, 137, 51, 172, 130,
192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159,
193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9,
98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176,
67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60,
118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105,
193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36,
138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67,
193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 58, 151, 215,
2, 40, 66, 1, 203, 130, 60, 194, 139, 116, 195, 53, 156, 47, 200, 96, 201,
56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170,
187, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219,
39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 58, 151, 203, 8, 2,
36, 139, 112, 193, 151, 96
};
const rlink_speed_table_t rlink_speed_table[] = {{
dtc_64, sizeof(dtc_64), (ST7_FOSC * 2) / (1000 * 64), 64
}, {
dtc_11, sizeof(dtc_11), (ST7_FOSC * 2) / (1000 * 11), 11
}, {
dtc_8, sizeof(dtc_8), (ST7_FOSC * 2) / (1000 * 8), 8
}, {
dtc_2, sizeof(dtc_2), (ST7_FOSC * 2) / (1000 * 2), 2
}};
const size_t rlink_speed_table_size = sizeof(rlink_speed_table) / sizeof(*rlink_speed_table);

114
src/jtag/rlink/st7.h Normal file
View File

@ -0,0 +1,114 @@
/***************************************************************************
* Copyright (C) 2008 Lou Deluxe *
* lou.openocd012@fixit.nospammail.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#define ST7_FOSC (12 * 1000000)
/* This is not a complete enumeration of ST7 registers, but it is sufficient for this interface driver. */
#define ST7_PADR (0x0000)
#define ST7_PADDR (ST7_PADR + 1)
#define ST7_PAOR (ST7_PADR + 2)
#define ST7_PBDR (0x0003)
#define ST7_PBDDR (ST7_PBDR + 1)
#define ST7_PCDR (0x0006)
#define ST7_PCDDR (ST7_PCDR + 1)
#define ST7_PCOR (ST7_PCDR + 2)
#define ST7_PDDR (0x0009)
#define ST7_PDDDR (ST7_PDDR + 1)
#define ST7_PDOR (ST7_PDDR + 2)
#define ST7_PEDR (0x000c)
#define ST7_PEDDR (ST7_PEDR + 1)
#define ST7_PEOR (ST7_PEDR + 2)
#define ST7_PFDR (0x000f)
#define ST7_PFDDR (ST7_PFDR + 1)
#define ST7_ADCDR (0x0012)
#define ST7_ADCCSR (ST7_ADCDR + 1)
#define ST7_EP2TXR (0x003e)
#define ST7_EP2TXR_STAT_TX0 (1 << 0)
#define ST7_EP2TXR_STAT_TX1 (1 << 1)
#define ST7_EP2TXR_STAT_DISABLED (0)
#define ST7_EP2TXR_STAT_STALL (ST7_EP2TXR_STAT_TX0)
#define ST7_EP2TXR_STAT_VALID (ST7_EP2TXR_STAT_TX1 | ST7_EP2TXR_STAT_TX0)
#define ST7_EP2TXR_STAT_NAK (ST7_EP2TXR_STAT_TX1)
#define ST7_EP2TXR_DTOG_TX (1 << 2)
#define ST7_EP2TXR_CTR_TX (1 << 3)
#define ST7_USB_BUF_EP0OUT (0x1550)
#define ST7_USB_BUF_EP0IN (0x1560)
#define ST7_USB_BUF_EP1OUT (0x1570)
#define ST7_USB_BUF_EP1IN (0x1580)
#define ST7_USB_BUF_EP2UODI (0x1590)
#define ST7_USB_BUF_EP2UIDO (0x1650)
#define ST7_PA0 (1 << 0)
#define ST7_PA1 (1 << 1)
#define ST7_PA2 (1 << 2)
#define ST7_PA3 (1 << 3)
#define ST7_PA4 (1 << 4)
#define ST7_PA5 (1 << 5)
#define ST7_PA6 (1 << 6)
#define ST7_PA7 (1 << 7)
#define ST7_PB0 (1 << 0)
#define ST7_PB1 (1 << 1)
#define ST7_PB2 (1 << 2)
#define ST7_PB3 (1 << 3)
#define ST7_PB4 (1 << 4)
#define ST7_PB5 (1 << 5)
#define ST7_PB6 (1 << 6)
#define ST7_PB7 (1 << 7)
#define ST7_PC0 (1 << 0)
#define ST7_PC1 (1 << 1)
#define ST7_PC2 (1 << 2)
#define ST7_PC3 (1 << 3)
#define ST7_PC4 (1 << 4)
#define ST7_PC5 (1 << 5)
#define ST7_PC6 (1 << 6)
#define ST7_PC7 (1 << 7)
#define ST7_PD0 (1 << 0)
#define ST7_PD1 (1 << 1)
#define ST7_PD2 (1 << 2)
#define ST7_PD3 (1 << 3)
#define ST7_PD4 (1 << 4)
#define ST7_PD5 (1 << 5)
#define ST7_PD6 (1 << 6)
#define ST7_PD7 (1 << 7)
#define ST7_PE0 (1 << 0)
#define ST7_PE1 (1 << 1)
#define ST7_PE2 (1 << 2)
#define ST7_PE3 (1 << 3)
#define ST7_PE4 (1 << 4)
#define ST7_PE5 (1 << 5)
#define ST7_PE6 (1 << 6)
#define ST7_PE7 (1 << 7)
#define ST7_PF0 (1 << 0)
#define ST7_PF1 (1 << 1)
#define ST7_PF2 (1 << 2)
#define ST7_PF3 (1 << 3)
#define ST7_PF4 (1 << 4)
#define ST7_PF5 (1 << 5)
#define ST7_PF6 (1 << 6)
#define ST7_PF7 (1 << 7)

View File

@ -0,0 +1,2 @@
#!/bin/sh
exec perl "$0.pl" $*

View File

@ -0,0 +1,68 @@
#!/bin/perl
#***************************************************************************
#* Copyright (C) 2008 Lou Deluxe *
#* lou.openocd012@fixit.nospammail.net *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU General Public License as published by *
#* the Free Software Foundation; either version 2 of the License, or *
#* (at your option) any later version. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU General Public License for more details. *
#* *
#* You should have received a copy of the GNU General Public License *
#* along with this program; if not, write to the *
#* Free Software Foundation, Inc., *
#* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
#***************************************************************************
# A simple utility to read a list of files (names composed by numeric prescaler arguments) and compose a C source file defining data structures which hold the binary data read from those files.
@speed_table = ();
printf("/* This file was created automatically by %s. */\n\n", $0);
for $i ('rlink', 'st7') {
printf("#include \"$i.h\"\n");
}
printf("\n");
for $prescaler (sort {$b <=> $a} @ARGV) {
my(@ary) = (
byte_array_from_file(${prescaler} . "_init.dtc"),
byte_array_from_file(${prescaler} . "_call.dtc")
);
for $i (@ary) {
$i = sprintf("%d", $i);
}
$bytes = join(', ', @ary);
$bytes =~ s/(^|\s)(.{70}?\S*)/\2\n/go; # break up long lines
$bytes =~ s/\n +/\n/go;
$bytes =~ s/(^|\n)/\1\t/go; # format nicely
printf("static const u8 dtc_%d[] = {\n%s\n};\n\n", $prescaler, $bytes);
push(@speed_table, sprintf("\tdtc_%d, sizeof(dtc_%d), (ST7_FOSC * 2) / (1000 * %d), %d\n", $prescaler, $prescaler, $prescaler, $prescaler));
}
printf("const rlink_speed_table_t rlink_speed_table[] = {{\n%s}};\n\n", join("}, {\n", @speed_table));
printf("const size_t rlink_speed_table_size = sizeof(rlink_speed_table) / sizeof(*rlink_speed_table);\n\n");
sub byte_array_from_file {
my($filename) = @_;
my(@array, $text, $i) = ();
open(IN, '<', $filename) || die "$filename: $!";
undef($/);
$text = <IN>;
close(IN);
for($i = 0; $i < length($text); $i++) {
push(@array, ord(substr($text, $i, 1)));
}
@array;
}

2
tools/st7_dtc_as/st7_dtc_as Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
exec perl "$0.pl" $*

View File

@ -0,0 +1,709 @@
#!/bin/perl
#***************************************************************************
#* Copyright (C) 2008 Lou Deluxe *
#* lou.openocd012@fixit.nospammail.net *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU General Public License as published by *
#* the Free Software Foundation; either version 2 of the License, or *
#* (at your option) any later version. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU General Public License for more details. *
#* *
#* You should have received a copy of the GNU General Public License *
#* along with this program; if not, write to the *
#* Free Software Foundation, Inc., *
#* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
#***************************************************************************
# A rudimentary assembler for DTC code.
# It is not robust, by any means, but it gets the job done.
{package DTC_as;
my($i); # for later loop to generate reverse lookup
sub new {
my($self) = bless{};
$self->{'pagewidth'} = 60;
$self;
}
%status_bit_arg = (
'STOP' => 0x01,
'ERROR' => 0x02,
);
%cp_arg = (
'A=>X' => 0x00,
'A<X' => 0x01,
'CARRY' => 0x02,
'ALWAYS' => 0x03,
'ADR_BUFFER0=>CMP0' => 0x04,
'ADR_BUFFER0<CMP0' => 0x05,
'ADR_BUFFER1=>CMP1' => 0x06,
'ADR_BUFFER1<CMP1' => 0x07,
);
%shift_unit_arg = (
'CARD' => 0x00,
'MPEG' => 0x08,
);
%shift_pin_arg = (
'PIN0=>IN' => 0x00,
'PIN1=>IN' => 0x04,
'OUT=>PIN0' => 0x01,
'OUT=>PIN1' => 0x03,
);
@ld_arg = (
'<Y>',
'X',
'Y',
'MASK',
'ADR_BUFFER00',
'ADR_BUFFER01',
'ADR_BUFFER10',
'ADR_BUFFER11',
'CMP00',
'CMP01',
'CMP10',
'CMP11',
'DATA_FLASH',
'CTRL_FCI',
'CTRL_CARD',
'CTRL_MPEG',
'DR_PARALLEL',
'DDR_PARALLEL',
'OR_PARALLEL',
'DR_CARD',
'DDR_CARD',
'OR_CARD',
'SHIFT_CARD',
'DR_MPEG',
'DDR_MPEG',
'OR_MPEG',
'SHIFT_MPEG',
'DATA_BUFFER0',
'DATA_BUFFER1',
'ECC_CRC',
'TMP_ECC',
'BUFFER_MNGT'
);
for($i = 0; $i < @ld_arg; $i++) {
$ld_arg{$ld_arg[$i]} = $i;
}
# ADDER8 / SUB8
sub alu8 {
my($self) = shift;
my($operand, $i) = shift;
if(defined($ld_arg{$operand})) {
$i = $ld_arg{$operand};
if($i > 0x00 && $i < 0x04) {
return(($i - 0x01) << 3);
}
}
return undef;
}
# ADDER16 / SUB16
sub alu16 {
my($self) = shift;
my($operand, $i) = shift;
$operand .= '0';
if(defined($ld_arg{$operand})) {
$i = $ld_arg{$operand};
if($i > 0x03 && $i < 0x0c) {
return(($i - 0x04) << 2);
}
}
return undef;
}
# BSET / BCLR
sub bsetorclr {
my($self) = shift;
my($ret);
if(@_ < 1) {
return undef;
}
$ret = $_[0];
if(($ret < 0) || ($ret > 3)) {
return undef;
}
return $ret;
}
# Opcode lookup table
%op = (
'NOP' => [
0x0,
],
'SEC' => [
0x1,
],
'CLC' => [
0x2,
],
'RET' => [
0x3,
],
'STATUS' => [
0x4,
sub {
my($self) = shift;
my($ret, $i);
for $i (@_) {
if(!defined($status_bit_arg{"\U$i"})) {
return undef;
}
$ret |= $status_bit_arg{"\U$i"};
}
if($ret < 1) {
return undef;
}
return $ret;
}
],
'CP' => [
0x8,
sub {
my($self) = shift;
if((@_ != 1) || (!defined($cp_arg{"\U$_[0]"}))) {
return undef;
}
return($cp_arg{"\U$_[0]"});
}
],
'SHIFT' => [
0x10,
sub {
my($self) = shift;
my($ret, $i);
if((@_ < 2) || (!defined($shift_unit_arg{"\U$_[0]"}))) {
return undef;
}
$ret = $shift_unit_arg{"\U$_[0]"};
shift;
for $i (@_) {
if(!defined($shift_pin_arg{"\U$i"})) {
return undef;
}
$ret |= $shift_pin_arg{"\U$i"};
}
return $ret;
}
],
'SUB8' => [
0x24,
\&alu8
],
'ADDER8' => [
0x25,
\&alu8
],
'SUB16' => [
0x26,
\&alu16
],
'ADDER16' => [
0x27,
\&alu16
],
'BCLR' => [
0x28,
\&bsetorclr
],
'BSET' => [
0x38,
\&bsetorclr
],
'REVERSE' => [
0x30,
],
'XOR' => [
0x31,
],
'AND' => [
0x32,
],
'EXCHANGE' => [
0x33,
],
'DECY' => [
0x3c,
],
'INCY' => [
0x3d,
],
'JP' => [
0x40,
sub {
my($self) = shift;
my($i);
if(@_ != 1) {
return undef;
}
$i = $_[0];
if(!defined($self->{'label'}{$i})) {
$i =~ s/^://o;
if(!defined($self->{'label'}{$i})) {
# not a defined label
undef $i;
}
}
if(defined($i)) {
$i = $self->{'label'}{$i} - $self->{'pc'};
} else {
$i = $_[0];
}
if($i =~ m/^([+-]?\d+)$/) {
$i = 0 + $1;
if(($i > 31) || ($i < -31)) {
warn "relative jump ($i) out of range";
return undef;
}
if($i < 0) {
return(0x20 - $1);
} else {
return(0x00 + $1);
}
}
return undef;
}
],
'BRANCH' => [
0x60,
],
'LD' => [
0x80,
sub {
my($self) = shift;
my($i);
# print STDERR join(", ", LD, @_), "\n";
if(@_ == 1) {
$_[1] = 'A';
}
if(@_ != 2) {
return undef;
}
if($_[0] =~ m/^([ML])S[BN]$/o) {
# MSB/LSB aka MSN/LSN
if($1 eq 'L') {
$_[0] = 'A.L';
} else {
$_[0] = 'A.H';
}
}
if($_[0] =~ m/^A\.([LH])$/o) {
# A.L/A.H
my($islsb) = ($1 eq 'L') ? 1 : 0;
$i = $_[1];
if($i =~ s/^0x([0-9a-fA-F])$/hex($1)/e) {
# print "$i looks hex\n";
} elsif($i =~ m/^\d+$/) {
# print "$i looks decimal\n";
} elsif(defined($self->{'label'}{$i})) {
# print "label match for $i ($self->{'label'}{$i})\n";
$i = $self->{'label'}{$i};
# print "\$i=$i\n";
# print "\$islsb=$islsb\n";
if($islsb) {
$i = ($i & 0xf);
} else {
$i = ($i >> 4) & 0xf;
}
# print "\$i=$i\n";
} else {
print "no label match for $i\n";
return undef;
}
if(($i < 0) || ($i > 0xf)) {
return undef;
}
if($islsb) {
$i |= 0x10;
};
return(0x20 | $i);
} elsif($_[0] eq 'A') {
if(!defined($ld_arg{$_[1]})) {
return undef;
}
return(0x40 | $ld_arg{$_[1]});
} elsif($_[1] eq 'A') {
if(!defined($ld_arg{$_[0]})) {
return undef;
}
return(0x00 | $ld_arg{$_[0]});
}
return undef;
}
],
);
$op{'JR'} = $op{'JP'};
sub pass {
my($self, $ifh, $ofh, $passnum) = @_;
# passnum=0 for plain parsing pass to populate label values
# passnum=1 for actual pass to assemble
my($line, $oline, $opcd);
if($passnum == 0) {
delete($self->{'label'});
delete($self->{'binary'});
delete($self->{'ENTRY'});
delete($self->{'LUT'});
}
seek($ifh, 0, 0); # rewind
$self->{'pc'} = 0;
$self->{'line_number'} = 0;
while(defined($line = <$ifh>)) {
$self->{'line_number'}++;
$line =~ s/\s+$//so;
$oline = $line;
$line =~ s/;.*//o;
$line =~ s/^\s+//o;
@_ = split(/[\s,]+/, $line);
undef($opcd);
if(@_ > 0) {
if(
($_[0] =~ s/^://o)
||
($_[0] =~ s/:$//o)
) {
if($passnum == 0) {
if(defined($self->{'label'}{$_[0]})) {
die "label redefinition for \"$_[0]\" in line $self->{'line_number'}";
}
$self->{'label'}{$_[0]} = $self->{'pc'};
}
shift(@_);
}
if(@_ > 0) {
if($passnum == 1) {
if((@_ == 3) && ($_[1] eq '=')) {
# convert this = that to LD
$_[1] = $_[0];
$_[0] = 'LD';
}
elsif((@_ == 3) && ($_[1] eq '+=')) {
# convert this += that to ADDER8 or ADDER16
if($_[0] eq 'A') {
@_ = ('ADDER8', $_[2]);
}
elsif($_[2] eq 'X') {
@_ = ('ADDER16', $_[0]);
}
}
elsif((@_ == 3) && ($_[1] eq '-=')) {
# convert this -= that to ADDER8 or ADDER16
if($_[0] eq 'A') {
@_ = ('SUB8', $_[2]);
}
elsif($_[2] eq 'X') {
@_ = ('SUB16', $_[0]);
}
}
elsif((@_ == 1) && ($_[0] =~ m/^(B((SET)|(CLR)))([1-4])$/oi)) {
# convert BSETn or BCLRn to BSET n-1 or BCLR n-1
$_[0] = $1;
$_[1] = $5 - 1;
}
$op = "\U$_[0]";
if(!defined($op{$op})) {
die "unknown instruction: $op in line $self->{'line_number'}";
}
shift(@_);
$op = $op{$op};
$sub = $op->[1];
if(defined($sub)) {
$opcd = &$sub($self, @_);
} else {
$opcd = 0;
}
if(!defined($opcd)) {
die "bad argument(s) in line $self->{'line_number'}";
}
$opcd |= $op->[0];
}
$self->{'pc'}++;
}
} else {
if($passnum == 0) {
if($oline =~ m/^;LUT; (.*)/o) {
my($entry, $label) = split(/\s+/, $1);
$entry =~ s/^0x//o;
$self->{'LUT'}[hex($entry)] = $label;
}
if($oline =~ m/^;ENTRY; (.*)/o) {
my($id, $label) = split(/\s+/, $1);
$self->{'ENTRY'}{$id} = $label;
}
}
}
if($passnum == 1) {
if(defined($opcd)) {
$self->{'binary'} .= chr($opcd);
printf $ofh ("/* 0x%02x */ 0x%02x%s /* %-*s */\n",
$self->{'pc'} - 1,
$opcd,
(
(
($self->{'last pc'} < 0xff)
||
($self->{'last pc'} != $self->{'pc'} - 1)
) ?
','
:
''
),
$self->{'pagewidth'} - 23,
$oline
);
} else {
if($oline ne '') {
print $ofh " /* $oline */\n";
} else {
print $ofh "\n";
}
}
}
}
if($passnum == 0) {
$self->{'last pc'} = $self->{'pc'} - 1;
}
if($passnum == 1) {
while($self->{'pc'} < 0xff) {
printf $ofh ("/* 0x%02x */ 0,\n",
$self->{'pc'}
);
$self->{'pc'}++;
}
if($self->{'pc'} < 0x100) {
printf $ofh ("/* 0x%02x */ 0\n",
$self->{'pc'}
);
$self->{'pc'}++;
}
}
}
} # package DTC_as
use Getopt::Std;
%opt = (
't' => 'unsigned char',
);
# -t type of arrays (defaults to unsigned char)
# -l lookup table array name (no table generated if not provided)
# -d DTC code array name (naked elements if not provided)
# -i input filename (trailing argument if not provided)
# -o output filename (stdout if not provided)
getopts('l:d:i:o:t:b', \%opt);
if(defined($opt{'i'})) {
$infile = $opt{'i'};
} else {
$infile = shift;
}
if(!open(IN, '<', $infile)) {
die "$infile: $!";
}
if($opt{'b'}) {
if(!defined($opt{'o'})) {
die "binary format requires -o";
}
if(!open(OUT, '>&', *STDOUT)) {
die "dup stdout: $!";
}
open(STDOUT, '>&', *STDERR);
} else {
if(defined($opt{'o'})) {
if(!open(OUT, '>', $opt{'o'})) {
die "$opt{'o'}: $!";
}
} else {
if(!open(OUT, '>&', *STDOUT)) {
die "dup stdout: $!";
}
open(STDOUT, '>&', *STDERR);
}
}
$as = new DTC_as;
$as->pass(*IN, *OUT, 0);
if(defined($opt{'d'})) {
print OUT "$opt{'t'} $opt{'d'}", "[0x100] = {\n";
}
$as->pass(*IN, *OUT, 1);
if(defined($opt{'d'})) {
print OUT "};\n\n";
}
close(IN);
if(defined($opt{'l'})) {
print OUT "$opt{'t'} $opt{'l'}", "[0x40] = {\n";
# $end = @{$as->{'LUT'}};
# if($end > 0x100) {
# $end = 0x100;
# }
for($i = 0xc0; $i < 0x100; $i++) {
$label = $as->{'LUT'}[$i];
if(defined($label)) {
if(defined($as->{'label'}{$label})) {
printf OUT ("/* 0x%02x */ 0x%02x%s /* %s */\n",
$i,
$as->{'label'}{$label},
(($i < 0xff) ? ',' : ''),
$label
);
} else {
die "label $label has not been defined";
}
} else {
printf OUT ("/* 0x%02x */ 0%s\n",
$i,
(($i < 0xff) ? ',' : ''),
);
}
}
print OUT "};\n\n";
}
close(OUT);
sub DTCLOAD_COMMENT { 0; }
sub DTCLOAD_ENTRY { 1; }
sub DTCLOAD_LOAD { 2; }
sub DTCLOAD_RUN { 3; }
sub DTCLOAD_LUT_START { 4; }
sub DTCLOAD_LUT { 5; }
if($opt{'b'}) {
open(OUT, ">", $opt{'o'}) || die "$opt{'o'}: $!";
syswrite(OUT, pack('CC', DTCLOAD_LUT_COMMENT, 3 - 1) . 'DTC');
$ref = $as->{'LUT'};
if(@$ref > 0) {
for($start = 0; $start < @$ref && !defined($ref->[$start]); $start++) {}
for($end = 0xff; $end >= $start && !defined($ref->[$end]); $end--) {}
undef($lut);
for($i = $start; $i <= $end; $i++) {
if(!defined($ref->[$i])) {
$lut .= "\0";
next;
}
$label = $ref->[$i];
if(defined($as->{'label'}{$label})) {
$label = $as->{'label'}{$label};
# printf("adding LUT entry 0x%02x\n", $label);
$lut .= chr($label);
} else {
die "label $label has not been defined";
}
}
if(length($lut) > 0) {
syswrite(OUT, pack('CCC', DTCLOAD_LUT_START, 1 - 1, $start));
syswrite(OUT, pack('CC', DTCLOAD_LUT, length($lut) - 1) . $lut);
}
}
while(($key, $label) = each(%{$as->{'ENTRY'}})) {
# print "$key = $label\n";
if(defined($as->{'label'}{$label})) {
$label = $as->{'label'}{$label};
# print "key=$key\n";
# print "label=$label\n";
syswrite(OUT, pack('CCC', DTCLOAD_ENTRY, length($key), $label) . $key);
} else {
die "label $label has not been defined";
}
}
if(length($as->{'binary'})) {
# printf("DTC code size: 0x%x\n", length($as->{'binary'}));
syswrite(OUT, pack('CC',
DTCLOAD_LOAD ,
length($as->{'binary'}) - 1
) . $as->{'binary'});
if(%{$as->{'ENTRY'}} < 1) {
syswrite(OUT, pack('CCC', DTCLOAD_RUN, 1 - 1, 0x00));
}
}
close(OUT);
}
0;