Compare commits

...

33 Commits

Author SHA1 Message Date
Triss cf8b986772 jtaglib: properly handle USB ram (cannot use quick memory access routines here) 2022-07-31 20:21:51 +02:00
Triss c801faeb80 jtaglib: test previous commit on 0x89 device, properly write the wdt password 2022-07-31 20:09:13 +02:00
Triss 2373d33bbb jtaglib: use context save/restore mechanism to keep track of registers etc. 2022-07-31 19:24:54 +02:00
Triss 8ddf3cb68c mehfet, v3hil: more detailed debugging (optional) 2022-07-31 19:24:54 +02:00
Triss 37aacaca2d jtaglib: Xv2 read/write reg now (finally) working, PC gets reset every so often due to other routines 2022-07-31 19:24:51 +02:00
Triss 649d82b695 jtaglib xv2: memory accesses start to work now 2022-07-31 19:24:31 +02:00
Triss 98c434555f jtaglib cpu16: single step issue fixed 2022-07-31 19:24:31 +02:00
Triss aed67748b1 jtaglib: misc fixes 2022-07-31 19:24:27 +02:00
Triss 2170693f2f jtaglib: getting cpuxv2 stuff to work, very slowly... 2022-07-31 19:24:08 +02:00
Triss 9809da335e jtaglib: proper device identification 2022-07-31 19:24:08 +02:00
Triss ddfffa06fb jtagdev, pif, mehfet: refactor device_class ops to be unified under jtagdev instead of using separate implementations 2022-07-31 19:24:08 +02:00
Triss 0a8ebf4a66 jtaglib: read JTAG ID early enough to know which procedures to use for JTAG access 2022-07-31 19:24:04 +02:00
Triss 5f30c8c217 jtaglib: refactor
In order to support CPUX and Xv2 devices, some refactoring is needed:

* split jtaglib into files concerning low-level JTAG/SBW physical layer
  stuff, and a file containing the actual debug routines. the latter is
  implemented in a separate file per CPU type (CPUX and Xv2 currently empty)
* use a lookup table dependig on the JTAG ID or CPU type to select which
  function to use
* move the 'struct device' dependency in pif and mehfet to jtdev, as it
  is needed everywhere, especially for device identification

In a next step, the following actions can be performed:

* Unify the read and write callbacks in pif and mehfet (used in readmem
  and writemem of struct device) to remove the redundancy
* Unify the init_device function in pif and mehfet to properly detect
  the device type, as done in v3hil. The device base type does query
  this data independenly, however, which feels unwanted.
2022-07-31 19:23:24 +02:00
Triss 924c548c2e ui/cmddb: clarify 'erase' parameters 2022-07-31 19:23:24 +02:00
Triss 39a44095eb ui/devcmd: make sure the 'total size' argument for the 'erase' command makes sense 2022-07-31 19:23:24 +02:00
Triss f1d416944c jtaglib: add 20-bit DR shift function 2022-07-31 19:23:19 +02:00
Triss 985b390ba2 elf32: don't load sections with size zero 2022-05-19 01:48:22 +02:00
Triss 63e2077d5b expr: allow '0X' hex prefix 2022-05-19 01:48:22 +02:00
Triss 9269d22d2b chipinfo db: fix entries 2022-05-19 01:48:22 +02:00
Triss 43f9d7bc54 v3hil: handle new protocol versions 2022-05-19 01:48:19 +02:00
Triss c375f74c51 v3hil: add debug logging 2022-05-19 00:46:45 +02:00
Triss 9484b1cff6 hal_proto, v3hil: add missing command and status IDs 2022-05-19 00:21:45 +02:00
Triss 9d1a2528de hal_proto: handle acknowledgement packets correctly 2022-05-19 00:10:47 +02:00
Daniel Beer 5284713769
Merge pull request #116 from LucasSnatiago/master
[feat] added Arch commands
2022-03-21 15:55:37 +13:00
Lucas Santiago 6332574323 [feat] Arch commands 2022-03-20 10:30:18 -03:00
Daniel Beer 4858be123c
Merge pull request #114 from sorber/fix-hidapi-bug
fixed hidapi compile bug, missing vid/pid arguments
2022-02-13 18:35:03 +13:00
Jacob Sorber 7283b49e13 fixed hidapi compile bug, missing vid/pid arguments 2022-02-11 08:21:27 -05:00
Daniel Beer e39ff3c1d9
Merge pull request #112 from chrissphinx/master
generalize x86-specific trap instruction
2022-01-25 10:14:33 +13:00
chrissphinx f2f763b043 remove statement leftover from debugging 2022-01-24 14:48:30 -05:00
Triss a1a06e7e65 jtaglib: fix register reading on MSP430G2452 and similar chips 2021-10-11 12:34:59 +02:00
Triss 30af3e9483 mehfet: add driver and transport 2021-10-11 12:34:50 +02:00
Triss ab76a0ef3c jtaglib: refactor: allow driver backends to implement higher-level IR/DR-shifts, TMS-sequence, etc. commands instead of requiring a bit-banging interface 2021-10-10 00:05:50 +02:00
Triss c576441fb7 add -V option to specify/override VID and PID of USB device 2021-10-10 00:05:43 +02:00
39 changed files with 5010 additions and 1457 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
*.o
mspdebug
mspdebug.exe
inst/
config.mk

View File

@ -21,6 +21,8 @@ INSTALL = /usr/bin/install
PREFIX ?= /usr/local
LDFLAGS ?= -s
-include config.mk
BINDIR = ${PREFIX}/bin/
MANDIR = ${PREFIX}/share/man/man1
LIBDIR = ${PREFIX}/lib/
@ -171,6 +173,7 @@ OBJ=\
transport/cp210x.o \
transport/cdc_acm.o \
transport/ftdi.o \
transport/mehfet_xport.o \
transport/ti3410.o \
transport/comport.o \
$(BSLHID_OBJ) \
@ -194,6 +197,11 @@ OBJ=\
drivers/jtdev_bus_pirate.o \
drivers/jtdev_gpio.o \
drivers/jtaglib.o \
drivers/jtaglib_cpu16.o \
drivers/jtaglib_cpux.o \
drivers/jtaglib_cpuxv2.o \
drivers/mehfet_proto.o \
drivers/mehfet.o \
drivers/pif.o \
drivers/loadbsl.o \
drivers/loadbsl_fw.o \

7
README
View File

@ -33,7 +33,8 @@ Compiling from source
Ensure that you have the necessary packages to compile programs that use
libusb (on Debian or Ubuntu systems, you might need to do apt-get
install libusb-dev). After that, unpack and compile the source code
install libusb-dev | on Arch systems, you might need to do sudo
pacman -S libusb-compact). After that, unpack and compile the source code
with:
tar xvfz mspdebug-version.tar.gz
@ -41,8 +42,8 @@ with:
make
On Debian Ubuntu systems sudo apt-get install libreadline-dev may be
required. If you don't want GNU readline support, you can invoke make
with:
required. On Arch systems sudo pacman -S readline may be required.
If you don't want GNU readline support, you can invoke make with:
make WITHOUT_READLINE=1

View File

@ -47335,7 +47335,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -47633,7 +47633,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -47931,7 +47931,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -48229,7 +48229,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -48527,7 +48527,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -48825,7 +48825,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -49123,7 +49123,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -49421,7 +49421,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -49719,7 +49719,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -50017,7 +50017,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -50315,7 +50315,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -50613,7 +50613,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -50911,7 +50911,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -51209,7 +51209,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -51507,7 +51507,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -51805,7 +51805,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -52103,7 +52103,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -52401,7 +52401,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -55325,7 +55325,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -60873,7 +60873,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -61171,7 +61171,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -61469,7 +61469,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -61767,7 +61767,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -62065,7 +62065,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -62363,7 +62363,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -62661,7 +62661,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -62959,7 +62959,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -63257,7 +63257,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -63555,7 +63555,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -63853,7 +63853,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -64151,7 +64151,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -64449,7 +64449,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -64747,7 +64747,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -65045,7 +65045,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -65343,7 +65343,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -65641,7 +65641,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -65939,7 +65939,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -66237,7 +66237,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -78736,7 +78736,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -78933,7 +78933,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -79130,7 +79130,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -79327,7 +79327,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -79524,7 +79524,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -79721,7 +79721,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -79918,7 +79918,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -80115,7 +80115,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -80312,7 +80312,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -80509,7 +80509,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -80706,7 +80706,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -80903,7 +80903,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -81100,7 +81100,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -81297,7 +81297,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -81494,7 +81494,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -81691,7 +81691,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -81888,7 +81888,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -82085,7 +82085,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -85045,7 +85045,7 @@ const struct chipinfo chipinfo_db[] = { {
.id = {
.ver_id = 0x82a1,
.ver_sub_id = 0x0000,
.revision = 0x10,
.revision = 0x21/*0x10*/,
.fab = 0x00,
.self = 0x0000,
.config = 0x00,
@ -85084,7 +85084,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -85314,7 +85314,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -85544,7 +85544,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -85774,7 +85774,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -85971,7 +85971,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -86168,7 +86168,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -86409,7 +86409,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -86650,7 +86650,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -86891,7 +86891,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -87132,7 +87132,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -87373,7 +87373,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -87592,7 +87592,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -87811,7 +87811,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -88030,7 +88030,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -88249,7 +88249,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -88490,7 +88490,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -88731,7 +88731,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -88950,7 +88950,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -90291,7 +90291,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -90906,7 +90906,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -91147,7 +91147,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -91388,7 +91388,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -91629,7 +91629,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -91870,7 +91870,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -93948,7 +93948,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,
@ -94189,7 +94189,7 @@ const struct chipinfo chipinfo_db[] = { {
[0x18] = 0x3f,
[0x19] = 0x3f,
[0x1a] = 0x40,
[0x1c] = 0x50,
[0x1c] = 0x41/*0x50*/,
[0x1d] = 0x42,
[0x1e] = 0x43,
[0x1f] = 0x44,

View File

@ -364,7 +364,8 @@ static device_t bsl_open(const struct device_args *args)
if (args->flags & DEVICE_FLAG_TTY)
dev->serial = comport_open(args->path, 460800);
else
dev->serial = ti3410_open(args->path, args->requested_serial);
dev->serial = ti3410_open(args->path, args->requested_serial,
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
if (!dev->serial) {
free(dev);

View File

@ -75,6 +75,7 @@ struct device_breakpoint {
#define DEVICE_FLAG_DO_FWUPDATE 0x10
#define DEVICE_FLAG_SKIP_CLOSE 0x20
#define DEVICE_FLAG_BSL_NME 0x40 /* BSL no-mass-erase */
#define DEVICE_FLAG_HAS_VID_PID 0x80
struct device_args {
int flags;
@ -88,6 +89,7 @@ struct device_args {
int bsl_gpio_rts;
int bsl_gpio_dtr;
uint8_t bsl_entry_password[32];
uint16_t vid, pid;
};
struct device_class {

View File

@ -44,9 +44,11 @@ static device_t fet_open_rf2500(const struct device_args *args)
}
#if defined(__APPLE__)
trans = rf2500hidapi_open(args->path, args->requested_serial);
trans = rf2500hidapi_open(args->path, args->requested_serial,
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
#else
trans = rf2500_open(args->path, args->requested_serial);
trans = rf2500_open(args->path, args->requested_serial,
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
#endif
if (!trans)
return NULL;
@ -79,8 +81,9 @@ static device_t fet_open_olimex_iso_mk2(const struct device_args *args)
if (args->flags & DEVICE_FLAG_TTY)
trans = comport_open(args->path, 115200);
else
trans = cdc_acm_open(args->path, args->requested_serial,
115200, 0x15ba, 0x0100);
trans = cdc_acm_open(args->path, args->requested_serial, 115200,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0100);
if (!trans)
return NULL;
@ -100,9 +103,9 @@ static device_t fet_open_olimex_iso_mk2(const struct device_args *args)
if (args->flags & DEVICE_FLAG_TTY)
trans = comport_open(args->path, 115200);
else
trans = cdc_acm_open(args->path,
args->requested_serial,
115200, 0x15ba, 0x0100);
trans = cdc_acm_open(args->path, args->requested_serial, 115200,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0100);
if (!trans)
return NULL;
@ -141,8 +144,9 @@ static device_t fet_open_olimex(const struct device_args *args)
if (args->flags & DEVICE_FLAG_TTY)
trans = comport_open(args->path, 115200);
else
trans = cdc_acm_open(args->path, args->requested_serial,
115200, 0x15ba, 0x0031);
trans = cdc_acm_open(args->path, args->requested_serial, 115200,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0031);
if (!trans)
return NULL;
@ -177,8 +181,9 @@ static device_t fet_open_olimex_v1(const struct device_args *args)
if (args->flags & DEVICE_FLAG_TTY)
trans = comport_open(args->path, 500000);
else
trans = cp210x_open(args->path, args->requested_serial,
500000, 0x15ba, 0x0002);
trans = cp210x_open(args->path, args->requested_serial, 500000,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0002);
if (!trans)
return NULL;
@ -213,7 +218,9 @@ static device_t fet_open_olimex_iso(const struct device_args *args)
trans = comport_open(args->path, 200000);
else
trans = ftdi_open(args->path, args->requested_serial,
0x15ba, 0x0008, 200000);
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0008,
200000);
if (!trans)
return NULL;
@ -248,7 +255,8 @@ static device_t fet_open_uif(const struct device_args *args)
if (args->flags & DEVICE_FLAG_TTY)
trans = comport_open(args->path, 460800);
else
trans = ti3410_open(args->path, args->requested_serial);
trans = ti3410_open(args->path, args->requested_serial,
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
if (!trans)
return NULL;

View File

@ -31,6 +31,35 @@ void hal_proto_init(struct hal_proto *p, transport_t trans,
p->ref_id = 0;
}
static int hal_proto_send_common(struct hal_proto *p, hal_proto_type_t type,
uint8_t* buf, size_t len)
{
if (len & 1)
buf[len++] = 0;
if (p->flags & HAL_PROTO_CHECKSUM) {
size_t i;
uint8_t sum_l = 0xff;
uint8_t sum_h = 0xff;
for (i = 0; i < len; i += 2) {
sum_l ^= buf[i];
sum_h ^= buf[i + 1];
}
buf[len++] = sum_l;
buf[len++] = sum_h;
}
if (p->trans->ops->send(p->trans, buf, len) < 0) {
printc_err("hal_proto_send_common: type: 0x%02x\n", type);
return -1;
}
return 0;
}
int hal_proto_send(struct hal_proto *p, hal_proto_type_t type,
const uint8_t *data, int length)
{
@ -52,31 +81,35 @@ int hal_proto_send(struct hal_proto *p, hal_proto_type_t type,
memcpy(buf + len, data, length);
len += length;
if (len & 1)
buf[len++] = 0;
if (p->flags & HAL_PROTO_CHECKSUM) {
size_t i;
uint8_t sum_l = 0xff;
uint8_t sum_h = 0xff;
for (i = 0; i < len; i += 2) {
sum_l ^= buf[i];
sum_h ^= buf[i + 1];
return hal_proto_send_common(p, type, buf, len);
}
buf[len++] = sum_l;
buf[len++] = sum_h;
}
if (p->trans->ops->send(p->trans, buf, len) < 0) {
printc_err("hal_proto_send: type: 0x%02x\n", type);
static int hal_proto_send_ack(struct hal_proto *p, hal_proto_type_t type,
const uint8_t *data, int length)
{
uint8_t buf[512];
size_t len = 0;
if (length > HAL_MAX_PAYLOAD) {
printc_err("hal_proto_send_ack: payload too long: %d\n", length);
return -1;
}
return 0;
buf[len++] = length + 3;
buf[len++] = type;
buf[len++] = (p->ref_id - 1) & 0xff;
buf[len++] = 0;
/*p->ref_id = (p->ref_id + 1) & 0x7f;*/
memcpy(buf + len, data, length);
len += length;
return hal_proto_send_common(p, type, buf, len);
}
int hal_proto_receive(struct hal_proto *p, uint8_t *buf, int max_len)
{
uint8_t rx_buf[512];
@ -147,7 +180,8 @@ int hal_proto_execute(struct hal_proto *p, uint8_t fid,
uint8_t fdata[HAL_MAX_PAYLOAD];
if (len + 2 > HAL_MAX_PAYLOAD) {
printc_err("hal_proto_execute: payload too big: %d\n", len);
printc_err("hal_proto_execute: fid 0x%02x: payload too big: %d\n",
fid, len);
return -1;
}
@ -168,8 +202,8 @@ int hal_proto_execute(struct hal_proto *p, uint8_t fid,
goto fail;
if ((p->type == HAL_PROTO_TYPE_EXCEPTION) && (r >= 2)) {
printc_err("hal_proto_execute: HAL exception: 0x%04x\n",
LE_WORD(p->payload, p->length));
printc_err("hal_proto_execute: fid 0x%02x: HAL exception: 0x%04x\n",
fid, LE_WORD(p->payload, p->length));
goto fail;
}
@ -177,12 +211,12 @@ int hal_proto_execute(struct hal_proto *p, uint8_t fid,
break;
if (p->type != HAL_PROTO_TYPE_DATA) {
printc_err("hal_proto_execute: no data "
"(got type 0x%02x)\n", p->type);
printc_err("hal_proto_execute: fid 0x%02x: no data "
"(got type 0x%02x)\n", fid, p->type);
goto fail;
}
if (hal_proto_send(p, HAL_PROTO_TYPE_ACKNOWLEDGE, NULL, 0) < 0)
if (hal_proto_send_ack(p, HAL_PROTO_TYPE_ACKNOWLEDGE, NULL, 0) < 0)
goto fail;
p->length += r;
@ -191,6 +225,6 @@ int hal_proto_execute(struct hal_proto *p, uint8_t fid,
return 0;
fail:
printc_err("hal_proto_execute: fid: 0x%02x\n", fid);
printc_err("hal_proto_execute: fid: 0x%02x: failed\n", fid);
return -1;
}

View File

@ -37,6 +37,11 @@ typedef enum {
HAL_PROTO_TYPE_DCDC_POWER_DOWN = 0x60,
HAL_PROTO_TYPE_DCDC_SET_VCC = 0x61,
HAL_PROTO_TYPE_DCDC_RESTART = 0x62,
HAL_PROTO_TYPE_CORE_SET_VCC = 0x63,
HAL_PROTO_TYPE_CORE_GET_VCC = 0x64,
HAL_PROTO_TYPE_CORE_SWITCH_FET = 0x65,
HAL_PROTO_TYPE_CMP_VERSIONS = 0x66,
HAL_PROTO_TYPE_CMD_LEGACY = 0x7e,
HAL_PROTO_TYPE_CMD_SYNC = 0x80,
HAL_PROTO_TYPE_CMD_EXECUTE = 0x81,
@ -52,6 +57,9 @@ typedef enum {
HAL_PROTO_TYPE_CMD_COM_RESET = 0x8b,
HAL_PROTO_TYPE_CMD_PAUSE_LOOP = 0x8c,
HAL_PROTO_TYPE_CMD_RESUME_LOOP = 0x8d,
HAL_PROTO_TYPE_CMD_KILL_ALL = 0x8e,
HAL_PROTO_TYPE_CMD_OVER_CURRENT = 0x8f,
HAL_PROTO_TYPE_ACKNOWLEDGE = 0x91,
HAL_PROTO_TYPE_EXCEPTION = 0x92,
HAL_PROTO_TYPE_DATA = 0x93,
@ -63,6 +71,121 @@ typedef enum {
HAL_PROTO_CHECKSUM = 0x01
} hal_proto_flags_t;
typedef enum {
HAL_PROTO_ERR_NONE = 0x00,
HAL_PROTO_ERR_UNDEFINED = 0xffff,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_RAM_START = 0xFFFE,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_RAM_SIZE = 0xFFFD,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_OFFSET = 0xFFFC,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_ADDRESS = 0xFFFB,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_LENGTH = 0xFFFA,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_TYPE = 0xFFF9,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_LOCKA = 0xFFF8,
HAL_PROTO_ERR_EXECUTE_FUNCLET_EXECUTION_TIMEOUT = 0xFFF7,
HAL_PROTO_ERR_EXECUTE_FUNCLET_EXECUTION_ERROR = 0xFFF6,
HAL_PROTO_ERR_WRITE_MEM_WORD_NO_RAM_ADDRESS = 0xFFF5,
HAL_PROTO_ERR_WRITE_MEM_WORD_NO_RAM_SIZE = 0xFFF4,
HAL_PROTO_ERR_WRITE_MEM_WORD_UNKNOWN = 0xFFF3,
HAL_PROTO_ERR_WRITE_MEM_BYTES_NO_RAM_ADDRESS = 0xFFF2,
HAL_PROTO_ERR_WRITE_MEM_BYTES_NO_RAM_SIZE = 0xFFF1,
HAL_PROTO_ERR_WRITE_MEM_BYTES_UNKNOWN = 0xFFF0,
HAL_PROTO_ERR_WRITE_FLASH_WORD_NO_FLASH_ADDRESS = 0xFFEF,
HAL_PROTO_ERR_WRITE_FLASH_WORD_NO_FLASH_SIZE = 0xFFEE,
HAL_PROTO_ERR_WRITE_FLASH_WORD_UNKNOWN = 0xFFED,
HAL_PROTO_ERR_WRITE_FLASH_QUICK_UNKNOWN = 0xFFEC,
HAL_PROTO_ERR_START_JTAG_NO_PROTOCOL = 0xFFEB,
HAL_PROTO_ERR_START_JTAG_PROTOCOL_UNKNOWN = 0xFFEA,
HAL_PROTO_ERR_SET_CHAIN_CONFIGURATION_STREAM = 0xFFE9,
HAL_PROTO_ERR_RESTORECONTEXT_RELEASE_JTAG_NO_WDT_ADDRESS = 0xFFE8,
HAL_PROTO_ERR_RESTORECONTEXT_RELEASE_JTAG_NO_WDT_VALUE = 0xFFE7,
HAL_PROTO_ERR_RESTORECONTEXT_RELEASE_JTAG_NO_PC = 0xFFE6,
HAL_PROTO_ERR_RESTORECONTEXT_RELEASE_JTAG_NO_SR = 0xFFE5,
HAL_PROTO_ERR_RESTORECONTEXT_RELEASE_JTAG_NO_CONTROL_MASK = 0xFFE4,
HAL_PROTO_ERR_RESTORECONTEXT_RELEASE_JTAG_NO_MDB = 0xFFE3,
HAL_PROTO_ERR_READ_MEM_WORD_NO_ADDRESS = 0xFFF2,
HAL_PROTO_ERR_READ_MEM_WORD_NO_SIZE = 0xFFF1,
HAL_PROTO_ERR_READ_MEM_UNKNOWN = 0xFFE0,
HAL_PROTO_ERR_READ_MEM_BYTES_NO_ADDRESS = 0xFFDF,
HAL_PROTO_ERR_READ_MEM_BYTES_NO_SIZE = 0xFFDE,
HAL_PROTO_ERR_PSA_NO_ADDRESS = 0xFFDD,
HAL_PROTO_ERR_PSA_NO_SIZE = 0xFFDC,
HAL_PROTO_ERR_SYNC_JTAG_ASSERT_POR_JTAG_TIMEOUT = 0xFFDB,
HAL_PROTO_ERR_SYNC_JTAG_ASSERT_POR_NO_WDT_ADDRESS = 0xFFDA,
HAL_PROTO_ERR_SYNC_JTAG_ASSERT_POR_NO_WDT_VALUE = 0xFFD9,
HAL_PROTO_ERR_WRITE_ALL_CPU_REGISTERS_STREAM = 0xFFD8,
HAL_PROTO_ERR_WRITE_MEM_WORD_XV2_NO_RAM_ADDRESS = 0xFFD7,
HAL_PROTO_ERR_WRITE_MEM_WORD_XV2_NO_RAM_SIZE = 0xFFD6,
HAL_PROTO_ERR_SECURE_NO_TGT_HAS_TEST_PIN = 0xFFD5,
HAL_PROTO_ERR_SYNC_JTAG_CONDITIONAL_JTAG_TIMEOUT = 0xFFD4,
HAL_PROTO_ERR_SYNC_JTAG_CONDITIONAL_NO_WDT_ADDRESS = 0xFFD3,
HAL_PROTO_ERR_SYNC_JTAG_CONDITIONAL_NO_WDT_VALUE = 0xFFD2,
HAL_PROTO_ERR_INSTRUCTION_BOUNDARY_ERROR = 0xFFD1,
HAL_PROTO_ERR_JTAG_VERSION_MISMATCH = 0xFFD0,
HAL_PROTO_ERR_JTAG_MAILBOX_IN_TIMOUT = 0xFFCF,
HAL_PROTO_ERR_JTAG_PASSWORD_WRONG = 0xFFCE,
HAL_PROTO_ERR_START_JTAG_NO_ACTIVATION_CODE = 0xFFCD,
HAL_PROTO_ERR_SINGLESTEP_WAITFOREEM_TIMEOUT = 0xFFCC,
HAL_PROTO_ERR_CONFIG_NO_PARAMETER = 0xFFCB,
HAL_PROTO_ERR_CONFIG_NO_VALUE = 0xFFCA,
HAL_PROTO_ERR_CONFIG_PARAM_UNKNOWN_PARAMETER = 0xFFC9,
HAL_PROTO_ERR_NO_NUM_BITS = 0xFFC8,
HAL_PROTO_ERR_ARRAY_SIZE_MISMATCH = 0xFFC7,
HAL_PROTO_ERR_NO_COMMAND = 0xFFC6,
HAL_PROTO_ERR_UNKNOWN_COMMAND = 0xFFC5,
HAL_PROTO_ERR_NO_DATA = 0xFFC4,
HAL_PROTO_ERR_NO_BIT_SIZE = 0xFFC3,
HAL_PROTO_ERR_INVALID_BIT_SIZE = 0xFFC2,
HAL_PROTO_ERR_UNLOCK_NO_PASSWORD_LENGTH = 0xFFC1,
HAL_PROTO_ERR_UNLOCK_INVALID_PASSWORD_LENGTH = 0xFFC0,
HAL_PROTO_ERR_EXECUTE_FUNCLET_FINISH_TIMEOUT = 0xFFBF,
HAL_PROTO_ERR_EXECUTE_FUNCLET_NO_MAXRSEL = 0xFFBE,
HAL_PROTO_ERR_API_CALL_NOT_SUPPORTED = 0xFFBD,
HAL_PROTO_ERR_MAGIC_PATTERN = 0xFFBC,
HAL_PROTO_ERR_MAGIC_PATTERN_BOOT_DATA_CRC_WRONG = 0xFFBB,
HAL_PROTO_ERR_DAP_NACK = 0xFFBA,
HAL_PROTO_MESSAGE_NO_RESPONSE = 0x8000,
HAL_PROTO_EXCEPTION_NOT_IMPLEMENT_ERR = 0x8001,
HAL_PROTO_EXCEPTION_MSGID_ERR = 0x8002,
HAL_PROTO_EXCEPTION_CRC_ERR = 0x8003,
HAL_PROTO_EXCEPTION_RX_TIMEOUT_ERR = 0x8004,
HAL_PROTO_EXCEPTION_TX_TIMEOUT_ERR = 0x8005,
HAL_PROTO_EXCEPTION_RX_OVERFLOW_ERR = 0x8006,
HAL_PROTO_EXCEPTION_TX_NO_BUFFER = 0x8007,
HAL_PROTO_EXCEPTION_COM_RESET = 0x8008,
HAL_PROTO_EXCEPTION_RX_NO_BUFFER = 0x8009,
HAL_PROTO_EXCEPTION_RX_TO_SMALL_BUFFER = 0x800A,
HAL_PROTO_EXCEPTION_RX_LENGTH = 0x800B,
} hal_proto_error_t;
#define HAL_MAX_PAYLOAD 253
struct hal_proto {

File diff suppressed because it is too large Load Diff

View File

@ -34,15 +34,56 @@
#ifndef JTAGLIB_H_
#define JTAGLIB_H_
#include <stdbool.h>
#include <stdint.h>
#include "device.h"
#include "jtdev.h"
#include "util.h"
/* Flash erasing modes */
#define JTAG_ERASE_MASS 0xA506
#define JTAG_ERASE_MAIN 0xA504
#define JTAG_ERASE_SGMT 0xA502
/* Colleciton of functions that need different implementation for different
* CPU types (that is, 16-bit vs CPUX vs Xv2) */
struct jtaglib_funcs {
unsigned int (*jlf_get_device)(struct jtdev *p);
uint16_t (*jlf_read_mem)(struct jtdev *p, unsigned int format, address_t address);
void (*jlf_read_mem_quick)(struct jtdev *p, address_t start_address,
unsigned int word_count, uint16_t* data);
void (*jlf_write_mem)(struct jtdev *p, unsigned int format,
address_t address, uint16_t data);
void (*jlf_write_mem_quick)(struct jtdev *p, address_t start_address,
unsigned int word_count, const uint16_t* data);
unsigned int (*jlf_execute_puc)(struct jtdev *p);
void (*jlf_release_device)(struct jtdev *p, address_t address);
int (*jlf_verify_mem)(struct jtdev *p, address_t start_address,
unsigned int length, const uint16_t *data);
int (*jlf_erase_check)(struct jtdev *p, address_t start_address,
unsigned int length);
void (*jlf_write_flash)(struct jtdev *p, address_t start_address,
unsigned int word_count, const uint16_t *data);
void (*jlf_erase_flash)(struct jtdev *p, unsigned int erase_mode,
address_t erase_address);
address_t (*jlf_read_reg)(struct jtdev *p, int reg);
void (*jlf_write_reg)(struct jtdev *p, int reg, address_t value);
void (*jlf_single_step)(struct jtdev *p);
unsigned int (*jlf_set_breakpoint)(struct jtdev *p, int bp_num,
address_t bp_addr);
unsigned int (*jlf_cpu_state)(struct jtdev *p);
int (*jlf_get_config_fuses)(struct jtdev *p);
void (*jlf_context_save)(struct jtdev *p, bool after_puc);
void (*jlf_context_restore)(struct jtdev *p);
void (*jlf_regs_update)(struct jtdev *p);
void (*jlf_regs_flush)(struct jtdev *p);
};
extern const struct jtaglib_funcs jlf_cpu16;
extern const struct jtaglib_funcs jlf_cpux;
extern const struct jtaglib_funcs jlf_cpuxv2;
/* Take target device under JTAG control. */
unsigned int jtag_init(struct jtdev *p);
@ -117,4 +158,35 @@ unsigned int jtag_set_breakpoint(struct jtdev *p,
unsigned int jtag_cpu_state(struct jtdev *p);
int jtag_get_config_fuses(struct jtdev *p);
void jtag_dev_context_save(struct jtdev *p, bool after_puc);
void jtag_dev_context_restore(struct jtdev *p);
void jtag_dev_regs_update(struct jtdev *p);
void jtag_dev_regs_flush(struct jtdev *p);
/* Default low-level JTAG routines for jtdev implementations that don't have
* their own implementations of these routines */
uint8_t jtag_default_ir_shift(struct jtdev *p, uint8_t ir);
uint8_t jtag_default_dr_shift_8(struct jtdev *p, uint8_t dr);
uint16_t jtag_default_dr_shift_16(struct jtdev *p, uint16_t dr);
uint32_t jtag_default_dr_shift_20(struct jtdev *p, uint32_t dr);
void jtag_default_tms_sequence(struct jtdev *p, int bits, unsigned int value);
void jtag_default_init_dap(struct jtdev *p);
void jtag_dev_default_context_save(struct jtdev *p, bool after_puc);
void jtag_dev_default_context_restore(struct jtdev *p);
void jtag_dev_default_regs_update(struct jtdev *p);
void jtag_dev_default_regs_flush(struct jtdev *p);
int jtag_refresh_bps(device_t dev, struct jtdev *p);
int jtag_dev_readmem(device_t dev_base, address_t addr, uint8_t *mem, address_t len);
int jtag_dev_writemem(device_t dev_base, address_t addr, const uint8_t *mem, address_t len);
int jtag_dev_getregs(device_t dev_base, address_t *regs);
int jtag_dev_setregs(device_t dev_base, const address_t *regs);
int jtag_dev_ctl(device_t dev_base, device_ctl_t type);
device_status_t jtag_dev_poll(device_t dev_base);
int jtag_dev_erase(device_t dev_base, device_erase_type_t, address_t addr);
int jtag_dev_getconfigfuses(device_t dev_base);
int jtag_dev_init(struct jtdev *p);
#endif

883
drivers/jtaglib_cpu16.c Normal file
View File

@ -0,0 +1,883 @@
#include "jtaglib.h"
#include "jtaglib_defs.h"
#include "output.h"
#ifdef DEBUG_JTAGLIB
#define dbg_printc(fmt, ...) printc_dbg("jlf16: %s:%d " fmt, __func__, __LINE__, ##__VA_ARGS__)
#else
#define dbg_printc(fmt, ...) do{}while(0)
#endif
/* Set target CPU JTAG state machine into the instruction fetch state
* return: 1 - instruction fetch was set
* 0 - otherwise
*/
static int jlf16_set_instruction_fetch(struct jtdev *p)
{ // SLAU320AJ name: SetInstrFetch / SyncJtag?
unsigned int loop_counter;
// SyncJtag: has CTLR_SIG_16BIT=0x2401 here
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
/* Wait until CPU is in instruction fetch state
* timeout after limited attempts
*/
for (loop_counter = 50; loop_counter > 0; loop_counter--) {
if ((jtag_dr_shift_16(p, 0x0000) & 0x0080) == 0x0080)
return 1;
jtag_tclk_clr(p); /* The TCLK pulse befor jtag_dr_shift_16 leads to */
jtag_tclk_set(p); /* problems at MEM_QUICK_READ, it's from SLAU265 */
}
printc_err("jlf16_set_instruction_fetch: failed\n");
p->failed = 1;
return 0;
}
/* Set the CPU into a controlled stop state */
static void jlf16_halt_cpu(struct jtdev *p)
{ // SLAU320AJ name: HaltCPU
/* Set CPU into instruction fetch mode */
dbg_printc("halt cpu\n");
jlf16_set_instruction_fetch(p);
/* Set device into JTAG mode + read */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2401);
/* Send JMP $ instruction to keep CPU from changing the state */
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_dr_shift_16(p, 0x3FFF);
jtag_tclk_set(p); // TODO: ???
jtag_tclk_clr(p);
/* Set JTAG_HALT bit */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2409);
jtag_tclk_set(p);
}
/* Release the target CPU from the controlled stop state */
static void jlf16_release_cpu(struct jtdev *p)
{ // SLAU320AJ name: ReleaseCPU
dbg_printc("release cpu\n");
jtag_tclk_clr(p);
/* clear the HALT_JTAG bit */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2401);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
jtag_tclk_set(p);
}
/* Compares the computed PSA (Pseudo Signature Analysis) value to the PSA
* value shifted out from the target device. It is used for very fast data
* block write or erasure verification.
* start_address: start of data
* length : number of data
* data : pointer to data, 0 for erase check
* RETURN : 1 - comparison was successful
* 0 - otherwise
*/
static int jlf16_verify_mem(struct jtdev *p,
unsigned int start_address,
unsigned int length,
const uint16_t *data)
{ // SLAU320AJ name: VerifyMem/VerifyPSA
unsigned int psa_value;
unsigned int index;
/* Polynom value for PSA calculation */
unsigned int polynom = 0x0805;
/* Start value for PSA calculation */
unsigned int psa_crc = start_address-2;
dbg_printc("verify: %04x..%04x\n", start_address, start_address+length*2);
jtag_execute_puc(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2401);
jlf16_set_instruction_fetch(p);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_dr_shift_16(p, 0x4030);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_dr_shift_16(p, start_address-2);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
jtag_dr_shift_16(p, 0x0000);
jtag_ir_shift(p, IR_DATA_PSA);
for (index = 0; index < length; index++) {
/* Calculate the PSA value */
if ((psa_crc & 0x8000) == 0x8000) {
psa_crc ^= polynom;
psa_crc <<= 1;
psa_crc |= 0x0001;
} else
psa_crc <<= 1;
if (data == 0)
/* use erase check mask */
psa_crc ^= 0xFFFF;
else
/* use data */
psa_crc ^= data[index];
/* Clock through the PSA */
jtag_tclk_set(p);
/* Go through DR path without shifting data in/out */
jtag_tms_sequence(p, 6, 0x19); /* TMS=1 0 0 1 1 0 ; 6 clocks */
jtag_tclk_clr(p);
}
/* Read out the PSA value */
jtag_ir_shift(p, IR_SHIFT_OUT_PSA);
psa_value = jtag_dr_shift_16(p, 0x0000);
jtag_tclk_set(p);
return (psa_value == psa_crc) ? 1 : 0;
}
/* ------------------------------------------------------------------------- */
static int jlf16_erase_check(struct jtdev *p, unsigned int start_address,
unsigned int length)
{
return jlf16_verify_mem(p, start_address, length, NULL);
}
static unsigned int jlf16_get_device(struct jtdev *p)
{ // SLAU320AJ name: GetDevice
unsigned int jtag_id = 0;
unsigned int loop_counter;
/* Set device into JTAG mode + read */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2401);
/* Wait until CPU is synchronized,
* timeout after a limited number of attempts
*/
jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
for ( loop_counter = 50; loop_counter > 0; loop_counter--) {
if ( (jtag_dr_shift_16(p, 0x0000) & 0x0200) == 0x0200 ) {
break;
}
}
dbg_printc("get device: jtag id=%02x\n", jtag_id);
if (loop_counter == 0) {
printc_err("jlf16_get_device: timed out\n");
p->failed = 1;
/* timeout reached */
return 0;
}
return jtag_id;
}
/* Reads one byte/word from a given address
* format : 8-byte, 16-word
* address: address of memory
* return : content of memory
*/
static uint16_t jlf16_read_mem(struct jtdev *p, unsigned int format, address_t address)
{ // SLAU320AJ name: ReadMem
uint16_t content;
dbg_printc("%dbit %04x\n", format, address);
jlf16_halt_cpu(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
if (format == 16) {
/* set word read */
jtag_dr_shift_16(p, 0x2409);
} else {
/* set byte read */
jtag_dr_shift_16(p, 0x2419);
}
/* set address */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, address);
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* shift out 16 bits */
content = jtag_dr_shift_16(p, 0x0000);
jtag_tclk_set(p); /* is also the first instruction in jtag_release_cpu() */
jlf16_release_cpu(p);
if (format == 8)
content &= 0x00ff;
dbg_printc("%dbit %04x -> %04x\n", format, address, content);
return content;
}
/* Reads an array of words from target memory
* address: address to read from
* length : number of word to read
* data : memory to write to
*/
static void jlf16_read_mem_quick(struct jtdev *p, address_t address,
unsigned int length, uint16_t *data)
{ // SLAU320AJ name: ReadMemQuick
unsigned int index;
address_t pc_bak;
dbg_printc("%04x..%04x\n", address, address+length*2);
pc_bak = jtag_read_reg(p, 0);
/* Initialize reading: */
jtag_write_reg(p, 0, address-4);
jlf16_halt_cpu(p);
jtag_tclk_clr(p);
/* set RW to read */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2409);
jtag_ir_shift(p, IR_DATA_QUICK);
for (index = 0; index < length; index++) {
jtag_tclk_set(p);
jtag_tclk_clr(p); // TODO: ???
/* shift out the data from the target */
data[index] = jtag_dr_shift_16(p, 0x0000);
//jtag_tclk_clr(p); // TODO: ???
}
jtag_tclk_set(p);
jlf16_release_cpu(p);
jtag_write_reg(p, 0, pc_bak);
}
/* Writes one byte/word at a given address
* format : 8-byte, 16-word
* address: address to be written
* data : data to write
*/
static void jlf16_write_mem(struct jtdev *p, unsigned int format,
address_t address, uint16_t data)
{ // SLAU320AJ name: WriteMem
dbg_printc("%dbit %04x <- %04x\n", format, address, data);
jlf16_halt_cpu(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
if (format == 16)
/* Set word write */
jtag_dr_shift_16(p, 0x2408);
else
/* Set byte write */
jtag_dr_shift_16(p, 0x2418);
jtag_ir_shift(p, IR_ADDR_16BIT);
/* Set addr */
jtag_dr_shift_16(p, address);
jtag_ir_shift(p, IR_DATA_TO_ADDR);
/* Shift in 16 bits */
jtag_dr_shift_16(p, data);
jtag_tclk_set(p);
jlf16_release_cpu(p);
}
/* Writes an array of words into target memory
* address: address to write to
* length : number of word to write
* data : data to write
*/
static void jlf16_write_mem_quick(struct jtdev *p, address_t address,
unsigned int length, const uint16_t *data)
{ // SLAU320AJ name: WriteMemQuick
unsigned int index;
dbg_printc("%04x..%04x\n", address, address+length*2);
/* Initialize writing */
jtag_write_reg(p, 0, address-4);
jlf16_halt_cpu(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
/* Set RW to write */
jtag_dr_shift_16(p, 0x2408);
jtag_ir_shift(p, IR_DATA_QUICK);
// TODO: ^ in start of loop?
for (index = 0; index < length; index++) {
/* Write data */
jtag_dr_shift_16(p, data[index]);
/* Increment PC by 2 */
jtag_tclk_set(p);
jtag_tclk_clr(p);
}
jtag_tclk_set(p);
jlf16_release_cpu(p);
}
/* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register
* return: JTAG ID
*/
static unsigned int jlf16_execute_puc(struct jtdev *p)
{ // SLAU320AJ name: ExecutePOR
unsigned int jtag_id;
dbg_printc("\n");
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
/* Apply and remove reset */
jtag_dr_shift_16(p, 0x2C01);
jtag_dr_shift_16(p, 0x2401);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p); // TODO: ???
/* Read jtag id */
jtag_id = jtag_ir_shift(p, IR_ADDR_CAPTURE);
//jtag_tclk_set(p); // TODO: ???
/* Disable watchdog on target device */
//jtag_write_mem(p, 16, 0x0120, 0x5A80); // FIXME
return jtag_id;
}
/* Release the target device from JTAG control
* address: 0xFFFE - perform Reset,
* load Reset Vector into PC
* 0xFFFF - start execution at current
* PC position
* other - load Address into PC
*/
static void jlf16_release_device(struct jtdev *p, address_t address)
{ // SLAU320AJ name: ReleaseDevice
switch (address) {
case 0xffff: /* Nothing to do */
dbg_printc("BOR\n");
break;
case 0xfffe: /* Perform reset */
dbg_printc("SRST\n");
/* delete all breakpoints */
jtag_set_breakpoint(p,-1,0);
/* issue reset */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2C01);
jtag_dr_shift_16(p, 0x2401);
break;
default: /* Set target CPU's PC */
dbg_printc("PC: %04x\n", address);
jtag_write_reg(p, 0, address);
break;
}
jlf16_set_instruction_fetch(p);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE);
jtag_dr_shift_16(p, BREAKREACT + READ);
jtag_dr_shift_16(p, 0x0000);
jtag_ir_shift(p, IR_EMEX_WRITE_CONTROL);
jtag_dr_shift_16(p, 0x000f);
jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE);
}
/* Programs/verifies an array of words into a FLASH by using the
* FLASH controller. The JTAG FLASH register isn't needed.
* start_address: start in FLASH
* length : number of words
* data : pointer to data
*/
static void jlf16_write_flash(struct jtdev *p, address_t start_address,
unsigned int length, const uint16_t *data)
{ // SLAU320AJ name: WriteFLASH
unsigned int index;
unsigned int address;
dbg_printc("%04x..%04x\n", address, address+length*2);
address = start_address;
jlf16_halt_cpu(p);
jtag_tclk_clr(p);
/* Set RW to write */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2408);
/* FCTL1 register */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x0128); // FIXME
/* Enable FLASH write */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA540);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* FCTL2 register */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x012A); // FIXME
/* Select MCLK as source, DIV=1 */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA540);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* FCTL3 register */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x012C); // FIXME
/* Clear FCTL3 register */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA500);
jtag_tclk_set(p);
jtag_tclk_clr(p);
for (index = 0; index < length; index++) {
/* Set RW to write */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2408);
/* Set address */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, address);
/* Set data */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, data[index]);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* Set RW to read */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2409);
/* provide TCLKs
* min. 33 for F149 and F449
*/
p->f->jtdev_tclk_strobe(p, 35);
address += 2;
if (p->failed)
break;
}
/* Set RW to write */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2408);
/* FCTL1 register */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x0128); // FIXME
/* Disable FLASH write */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA500);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* Reset FCTL3 */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x012C); // FIXME
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA510);
jtag_tclk_set(p);
}
/* Performs a mass erase (with and w/o info memory) or a segment erase of a
* FLASH module specified by the given mode and address. Large memory devices
* get additional mass erase operations to meet the spec.
* erase_mode : ERASE_MASS, ERASE_MAIN, ERASE_SGMT
* erase_address: address within the selected segment
*/
static void jlf16_erase_flash(struct jtdev *p, unsigned int erase_mode,
address_t erase_address)
{ // SLAU320AJ name: EraseFLASH
unsigned int number_of_strobes = 4820; /* default for segment erase */
unsigned int loop_counter;
unsigned int max_loop_count = 1; /* erase cycle repeating for mass erase */
dbg_printc("%04x: %04x\n", erase_mode, erase_address);
if ((erase_mode == JTAG_ERASE_MASS) || (erase_mode == JTAG_ERASE_MAIN)) {
number_of_strobes = 5300; /* Larger Flash memories require */
max_loop_count = 19; /* additional cycles for erase. */
erase_address = 0xfffe; /* overwrite given address */
}
for (loop_counter = max_loop_count; loop_counter > 0; loop_counter--) {
jlf16_halt_cpu(p);
jtag_tclk_clr(p);
/* Set RW to write */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2408);
/* FCTL1 address */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x0128); // FIXME
/* Enable erase mode */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, erase_mode); // FIXME?
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* FCTL2 address */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x012A); // FIXME
/* MCLK is source, DIV=1 */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA540);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* FCTL3 address */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x012C); // FIXME
/* Clear FCTL3 */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA500);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* Set erase address */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, erase_address);
/* Dummy write to start erase */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0x55AA);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* Set RW to read */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2409);
/* provide TCLKs */
p->f->jtdev_tclk_strobe(p, number_of_strobes);
/* Set RW to write */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2408);
/* FCTL1 address */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x0128); // FIXME
/* Disable erase */
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA500);
jtag_tclk_set(p);
jtag_tclk_clr(p);
/* Reset FCTL3 */
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_16(p, 0x012C); // FIXME
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, 0xA510);
jtag_tclk_set(p);
jlf16_release_cpu(p);
}
}
/* Reads a register from the target CPU */
static address_t jlf16_read_reg(struct jtdev *p, int reg)
{ // libmsp430 BIOS name: ReadCpuReg
unsigned int value;
dbg_printc("%d\n", reg);
/* Set CPU into instruction fetch mode */
jlf16_set_instruction_fetch(p);
/* CPU controls RW & BYTE */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x3401);
jtag_ir_shift(p, IR_DATA_16BIT);
/* "jmp $-4" instruction */
/* PC - 4 -> PC */
/* needs 2 clock cycles */
jtag_dr_shift_16(p, 0x3ffd);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
/* "mov Rn,&0x01fe" instruction
* Rn -> &0x01fe
* PC is advanced 4 bytes by this instruction
* needs 4 clock cycles
* it's a ROM address, write has no effect, but
* the registers value is placed on the databus
*/
jtag_dr_shift_16(p, 0x4082 | (((unsigned int)reg << 8) & 0x0f00) );
jtag_tclk_clr(p);
//jtag_ir_shift(p, IR_DATA_CAPTURE); // TODO: ???
jtag_tclk_set(p);
//jtag_ir_shift(p, IR_DATA_16BIT); // TODO: ???
jtag_dr_shift_16(p, 0x01fe);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
/* older code did an extra clock cycle -- don't do this! will put the
* current instruction word on the data bus instead of the register value
* on the G2452, making it useless. the clock cycles are still required to
* move to the next instruction, but those should be done later. */
/*jtag_tclk_clr(p);
jtag_tclk_set(p);*/
/* Read databus which contains the registers value */
jtag_ir_shift(p, IR_DATA_CAPTURE);
value = jtag_dr_shift_16(p, 0x0000);
jtag_tclk_clr(p);
/* JTAG controls RW & BYTE */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2401);
jtag_tclk_set(p);
dbg_printc("%d -> %04x\n", reg, value);
/* Return value read from register */
return value;
}
/* Writes a value into a register of the target CPU */
static void jlf16_write_reg(struct jtdev *p, int reg, address_t value)
{ // SLAU320AJ name: SetPC
/* Set CPU into instruction fetch mode */
dbg_printc("%d <- %04x\n", reg, value);
jlf16_set_instruction_fetch(p);
/* CPU controls RW & BYTE */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x3401);
jtag_ir_shift(p, IR_DATA_16BIT);
/* "jmp $-4" instruction */
/* PC - 4 -> PC */
/* needs 4 clock cycles */
jtag_dr_shift_16(p, 0x3ffd);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
/* "mov #value,Rn" instruction
* value -> Rn
* PC is advanced 4 bytes by this instruction
* needs 2 clock cycles
*/
jtag_dr_shift_16(p, 0x4030 | (reg & 0x000f) );
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_dr_shift_16(p, value);
jtag_tclk_clr(p);
jtag_tclk_set(p);
// TODO: ???
//jtag_ir_shift(p, IR_ADDR_CAPTURE);
//jtag_tclk_clr(p);
/* JTAG controls RW & BYTE */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2401);
}
/*----------------------------------------------------------------------------*/
static void jlf16_single_step( struct jtdev *p )
{ // libmsp430 BIOS name: SingleStep
unsigned int loop_counter;
dbg_printc("\n");
jlf16_set_instruction_fetch(p);
/* CPU controls RW & BYTE */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x3401);
/* clock CPU until next instruction fetch cycle */
/* failure after 10 clock cycles */
/* this is more than for the longest instruction */
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
for (loop_counter = 10; loop_counter > 0; loop_counter--) {
jtag_tclk_clr(p);
jtag_tclk_set(p);
if ((jtag_dr_shift_16(p, 0x0000) & 0x0080) == 0x0080) {
break;
}
}
/* JTAG controls RW & BYTE */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x2401);
jlf16_set_instruction_fetch(p);
if (loop_counter == 0) {
/* timeout reached */
printc_err("jtaglib_cpu16: single step failed\n");
p->failed = 1;
}
}
/*----------------------------------------------------------------------------*/
static unsigned int jlf16_set_breakpoint( struct jtdev *p,int bp_num, address_t bp_addr )
{
/* The breakpoint logic is explained in 'SLAU414c EEM.pdf' */
/* A good overview is given with Figure 1-1 */
/* MBx is TBx in EEM_defs.h */
/* CPU Stop is BREAKREACT in EEM_defs.h */
/* State Storage is STOR_REACT in EEM_defs.h */
/* Cycle Counter is EVENT_REACT in EEM_defs.h */
unsigned int breakreact;
if (bp_num >= 8) {
/* there are no more than 8 breakpoints in EEM */
printc_err("jlf16_set_breakpoint: failed setting "
"breakpoint %d at %04x\n", bp_num, bp_addr);
p->failed = 1;
return 0;
}
dbg_printc("num=%d addr=%04x\n", bp_num, bp_addr);
if (bp_num < 0) {
/* disable all breakpoints by deleting the BREAKREACT
* register */
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE);
jtag_dr_shift_16(p, BREAKREACT + WRITE);
jtag_dr_shift_16(p, 0x0000);
return 1;
}
/* set breakpoint */
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE);
jtag_dr_shift_16(p, GENCTRL + WRITE);
jtag_dr_shift_16(p, EEM_EN + CLEAR_STOP + EMU_CLK_EN + EMU_FEAT_EN);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift_16(p, 8*bp_num + MBTRIGxVAL + WRITE);
jtag_dr_shift_16(p, bp_addr);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift_16(p, 8*bp_num + MBTRIGxCTL + WRITE);
jtag_dr_shift_16(p, MAB + TRIG_0 + CMP_EQUAL);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift_16(p, 8*bp_num + MBTRIGxMSK + WRITE);
jtag_dr_shift_16(p, NO_MASK);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift_16(p, 8*bp_num + MBTRIGxCMB + WRITE);
jtag_dr_shift_16(p, 1<<bp_num);
/* read the actual setting of the BREAKREACT register */
/* while reading a 1 is automatically shifted into LSB */
/* this will be undone and the bit for the new breakpoint set */
/* then the updated value is stored back */
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
breakreact = jtag_dr_shift_16(p, BREAKREACT + READ);
breakreact += jtag_dr_shift_16(p, 0x000);
breakreact = (breakreact >> 1) | (1 << bp_num);
jtag_dr_shift_16(p, BREAKREACT + WRITE);
jtag_dr_shift_16(p, breakreact);
return 1;
}
/*----------------------------------------------------------------------------*/
static unsigned int jlf16_cpu_state( struct jtdev *p )
{ // libmsp430 BIOS name: WaitForEem(?)
jtag_ir_shift(p, IR_EMEX_READ_CONTROL);
if ((jtag_dr_shift_16(p, 0x0000) & 0x0080) == 0x0080) {
dbg_printc("halted\n");
return 1; /* halted */
} else {
dbg_printc("running\n");
return 0; /* running */
}
}
/*----------------------------------------------------------------------------*/
static int jlf16_get_config_fuses( struct jtdev *p )
{ // always the same?
jtag_ir_shift(p, IR_CONFIG_FUSES);
return jtag_dr_shift_8(p, 0);
}
/* ------------------------------------------------------------------------- */
const struct jtaglib_funcs jlf_cpu16 = {
.jlf_get_device = jlf16_get_device,
.jlf_read_mem = jlf16_read_mem,
.jlf_read_mem_quick = jlf16_read_mem_quick,
.jlf_write_mem = jlf16_write_mem,
.jlf_write_mem_quick = jlf16_write_mem_quick,
.jlf_execute_puc = jlf16_execute_puc,
.jlf_release_device = jlf16_release_device,
.jlf_verify_mem = jlf16_verify_mem,
.jlf_erase_check = jlf16_erase_check,
.jlf_write_flash = jlf16_write_flash,
.jlf_erase_flash = jlf16_erase_flash,
.jlf_context_save = jtag_dev_default_context_save,
.jlf_context_restore = jtag_dev_default_context_restore,
.jlf_regs_update = jtag_dev_default_regs_update,
.jlf_regs_flush = jtag_dev_default_regs_flush,
.jlf_read_reg = jlf16_read_reg,
.jlf_write_reg = jlf16_write_reg,
.jlf_single_step = jlf16_single_step,
.jlf_set_breakpoint = jlf16_set_breakpoint,
.jlf_cpu_state = jlf16_cpu_state,
.jlf_get_config_fuses = jlf16_get_config_fuses,
};

7
drivers/jtaglib_cpux.c Normal file
View File

@ -0,0 +1,7 @@
#include "jtaglib.h"
#include "jtaglib_defs.h"
#include "output.h"
const struct jtaglib_funcs jlf_cpux;

889
drivers/jtaglib_cpuxv2.c Normal file
View File

@ -0,0 +1,889 @@
#include <stdbool.h>
#include "jtaglib.h"
#include "jtaglib_defs.h"
#include "output.h"
#define SAFE_FRAM_PC 0x0004
#ifdef DEBUG_JTAGLIB
#define dbg_printc(fmt, ...) printc_dbg("jlfxv2: %s:%d " fmt, __func__, __LINE__, ##__VA_ARGS__)
#else
#define dbg_printc(fmt, ...) do{}while(0)
#endif
static address_t jlfxv2_read_reg(struct jtdev *p, int reg);
static void jlfxv2_write_reg(struct jtdev *p, int reg, address_t value);
// FIXME:
// * context save/restore:
// * pc gets written correctly on single-step
// * pc does NOT get written on 'run'
// * pc does NOT get read properly on run break
// * implement flash write, erase, verify stuff
// * check how ^ works in practice on flash & FRAM devices
// * single step: not working!
// * breakpoints are a big TODO
static int jlfxv2_check_full_emu_state_ex(struct jtdev *p, const char* fnname)
{ // see SLAU320AJ ExecutePOR
uint16_t dr;
uint8_t jtag_id;
for (int i = 0; i < 1/*10*/; ++i) {
jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
if (((dr = jtag_dr_shift_16(p, 0)) & 0x0301) == 0x0301) {
return 1; // OK
}
printc_err("jlfxv2: %s: not in full emu state, while expected!"
" (dr=%04x jid=%02x)\n", fnname, dr, jtag_id);
}
p->failed = 1;
return 0;
}
#define jlfxv2_check_full_emu_state(p) jlfxv2_check_full_emu_state_ex((p), __func__)
static int jlfxv2_wait_sync_ex(struct jtdev *p, const char* fnname) {
uint16_t dr;
uint8_t jtag_id;
jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
for (int i = 0; i < 50; ++i) {
if ((dr = jtag_dr_shift_16(p, 0)) & 0x0200)
return 1;
}
printc_err("jlfxv2: %s: couldn't sync! (dr=%04x jid=%02x)\n", fnname, dr, jtag_id);
return 0;
}
#define jlfxv2_wait_sync(p) jlfxv2_wait_sync_ex((p), __func__)
static uint8_t bitswap_nyb(uint8_t in) {
return ((in >> 3) & 1) | ((in >> 1) & 2) | ((in << 1) & 4) | ((in << 3) & 8);
}
static uint8_t bitswap(uint8_t in) {
return (bitswap_nyb(in&0xf) << 4) | bitswap_nyb(in>>4);
}
static address_t demangle_mab(address_t mab) {
address_t page = mab & 0xf0000;
address_t bot = mab & 0x0ff00;
address_t top = mab & 0x000ff;
address_t ret = page | (bot >> 8) | ((address_t)bitswap(top) << 8);
//dbg_printc("demangle: %05x -> %05x\n", mab, ret);
return ret;
}
static int jlfxv2_set_pc(struct jtdev *p, address_t addr)
{
address_t addr_rb;
dbg_printc("set pc %05x\n", addr);
if (!jlfxv2_wait_sync(p)) return -1;
/*jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_dr_shift_16(p, 0);*/
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_set(p);
jtag_dr_shift_16(p, 0x0080 | ((addr >> 8) & 0x0f00));
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1400);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_dr_shift_16(p, addr & 0xffff);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_dr_shift_16(p, 0x4303);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
addr_rb = demangle_mab(jtag_dr_shift_20(p, 0));
dbg_printc("set pc MAB -> %05x%s\n", addr_rb,
(addr!=addr_rb)?", aieee!":"");
return (addr == addr_rb) ? 0 : -1;
}
/*static address_t jlfxv2_get_pc(struct jtdev *p)
{
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_dr_shift_16(p, 0);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
jtag_dr_shift_20(p, 0);
address_t addr = jtag_dr_shift_20(p, 0);
dbg_printc("get pc %05x\n", addr);
return addr;
}*/
/* Compares the computed PSA (Pseudo Signature Analysis) value to the PSA
* value shifted out from the target device. It is used for very fast data
* block write or erasure verification.
* start_address: start of data
* length : number of data
* data : pointer to data, 0 for erase check
* RETURN : 1 - comparison was successful
* 0 - otherwise
*/
static int jlfxv2_verify_mem(struct jtdev *p,
unsigned int start_address,
unsigned int length,
const uint16_t *data)
{ // SLAU320AJ name: VerifyMem/VerifyPSA
uint16_t crc, psaval;
jtag_execute_puc(p);
crc = start_address - 2;
if (jlfxv2_set_pc(p, start_address) < 0) return -1;
jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_dr_shift_16(p, start_address - 2);
jtag_ir_shift(p, IR_DATA_PSA);
for (unsigned int addr = 0; addr < length; ++addr) {
if (crc & 0x8000) {
crc ^= 0x0805;
crc <<= 1;
crc |= 1;
} else {
crc <<= 1;
}
if (data) crc ^= data[addr];
else crc ^= 0xffff;
jtag_tclk_clr(p);
/* Go through DR path without shifting data in/out */
jtag_tms_sequence(p, 6, 0x19); /* TMS=1 0 0 1 1 0 ; 6 clocks */
jtag_tclk_set(p);
}
jtag_ir_shift(p, IR_SHIFT_OUT_PSA);
psaval = jtag_dr_shift_16(p, 0);
jtag_execute_puc(p);
return (psaval == crc) ? 1 : 0;
}
/* ------------------------------------------------------------------------- */
static int jlfxv2_erase_check(struct jtdev *p, unsigned int start_address,
unsigned int length)
{
return jlfxv2_verify_mem(p, start_address, length, NULL);
}
static unsigned int jlfxv2_get_device(struct jtdev *p)
{ // SLAU320AJ name: GetDevice (and SyncJtag_AssertPor)
unsigned int jtag_id = 0;
int i;
dbg_printc("jlfxv2: get_device\n");
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1501);
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
for (i = 0; i < 50; ++i) {
if ((jtag_dr_shift_16(p, 0) & (1<<9)) == (1<<9))
break;
}
if (i == 50) {
printc_err("jlfxv2_get_device: failed\n");
p->failed = 1;
return 0;
}
jtag_id = jtag_execute_puc(p);
return jtag_id;
}
static void jlfxv2_read_mem_quick(struct jtdev *p, address_t address,
unsigned int length, uint16_t *data);
/* Reads one byte/word from a given address
* format : 8-byte, 16-word
* address: address of memory
* return : content of memory
*/
static uint16_t jlfxv2_read_mem(struct jtdev *p, unsigned int format, address_t address)
{ // SLAU320AJ name: ReadMem
uint16_t r = 0;
dbg_printc("read mem %05x\n", address);
if (!jlfxv2_check_full_emu_state(p))
return 0;
// the code below (an attempt at implementing the real read_mem) doesn't
// work, so let's use read_mem_quick as a backup
jlfxv2_read_mem_quick(p, address ^ (address & 1), 1, &r);
if (format == 8) {
if (address & 1) return (r >> 8) & 0xff;
else return r & 0xff;
} else return r;
/*//jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
//uint16_t dr = jtag_dr_shift_16(p, 0);
jtag_tclk_clr(p);
//jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
//jtag_dr_shift_16(p, (format == 16) ? 0x0501 : 0x0511);
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_20(p, address ^ (address & 1));
//jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_CAPTURE);
r = jtag_dr_shift_16(p, 0);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
if (format == 8) {
if (address & 1) return (r >> 8) & 0xff;
else return r & 0xff;
} else return r;*/
}
/* Reads an array of words from target memory
* address: address to read from
* length : number of word to read
* data : memory to write to
*/
static void jlfxv2_read_mem_quick(struct jtdev *p, address_t address,
unsigned int length, uint16_t *data)
{ // SLAU320AJ name: ReadMemQuick
if (!jlfxv2_check_full_emu_state(p))
return;
dbg_printc("read mem quick %05x..%05x\n", address, address+length*2);
if (jlfxv2_set_pc(p, address) < 0) return;
//jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
jtag_ir_shift(p, IR_DATA_QUICK);
for (unsigned int i = 0; i < length; ++i) {
jtag_tclk_set(p);
jtag_tclk_clr(p);
data[i] = jtag_dr_shift_16(p, 0);
}
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_dr_shift_16(p, 0);
jlfxv2_set_pc(p, SAFE_FRAM_PC);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
}
static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address,
unsigned int length, const uint16_t *data);
/* Writes one byte/word at a given address
* format : 8-byte, 16-word
* address: address to be written
* data : data to write
*/
static void jlfxv2_write_mem(struct jtdev *p, unsigned int format,
address_t address, uint16_t data)
{ // SLAU320AJ name: WriteMem
dbg_printc("write mem: %d %06x <- %04x\n", format, address, data);
if (format == 8) {
p->failed = 1;
printc_err("jlfxv2 write mem: byte access not yet implemented!\n");
return;
}
// same story as with read_mem
jlfxv2_write_mem_quick(p, address, 1, &data);
if (!jlfxv2_check_full_emu_state(p))
return;
/*jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
uint16_t dr = jtag_dr_shift_16(p, 0);
dbg_printc("write mem %d: %06x<-%04x: dr=%04x\n", format, address, data, dr);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, (format == 16) ? 0x0500 : 0x0510);
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_20(p, address);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_dr_shift_16(p, data);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);*/
}
/* Writes an array of words into target memory
* address: address to write to
* length : number of word to write
* data : data to write
*/
static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address,
unsigned int length, const uint16_t *data)
{ // SLAU320AJ name: WriteMemQuick
/*for (unsigned int i = 0; i < length; ++i) {
jlfxv2_write_mem(p, 16, address + i*2, data[i]);
}*/
dbg_printc("write mem quick: %05x..%05x\n", address, address+length*2);
if (!jlfxv2_check_full_emu_state(p))
return;
if (jlfxv2_set_pc(p, address) < 0) return;
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0500);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_DATA_QUICK);
for (unsigned int i = 0; i < length; ++i) {
jtag_tclk_set(p);
jtag_dr_shift_16(p, data[i]);
jtag_tclk_clr(p);
}
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_set(p);
jlfxv2_set_pc(p, SAFE_FRAM_PC);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
}
/* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register
* return: JTAG ID
*/
static unsigned int jlfxv2_execute_puc(struct jtdev *p)
{ // SLAU320AJ name: ExecutePOR
unsigned int jtag_id;
dbg_printc("execute_puc\n");
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1501);
if (!jlfxv2_wait_sync(p)) return -1;
jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
// empty CPU pipeline
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
/* Apply and remove reset */
jtag_dr_shift_16(p, 0x0C01);
delay_ms(40);
jtag_dr_shift_16(p, 0x0401);
if (jtag_id == 0x91 || jtag_id == 0X99 || jtag_id == 0x98) {
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_dr_shift_16(p, SAFE_FRAM_PC);
jtag_tclk_clr(p);
jtag_tclk_set(p);
if (jtag_id == 0x91) {
jtag_tclk_clr(p);
jtag_tclk_set(p);
}
jtag_ir_shift(p, IR_DATA_CAPTURE);
} else { // TODO: this if jtag_id == 0x91, else other branch?
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
}
// two more cycles to release CPU internal POR delay signals
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_clr(p);
jtag_tclk_set(p);
return jtag_id;
}
/* Release the target device from JTAG control
* address: 0xFFFE - perform Reset,
* load Reset Vector into PC
* 0xFFFF - start execution at current
* PC position
* other - load Address into PC
*/
static void jlfxv2_release_device(struct jtdev *p, address_t address)
{ // SLAU320AJ name: ReleaseDevice. from Replicator430 code, not in the PDF
switch (address) {
case 0xffff: // BOR
dbg_printc("jlfxv2: release device: BOR\n");
jtag_ir_shift(p, IR_TEST_REG);
jtag_dr_shift_16(p, 0x0200);
delay_ms(5);
break;
case 0xfffe: // reset
dbg_printc("jlfxv2: release device: SRST\n");
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0C01);
delay_ms(40);
jtag_dr_shift_16(p, 0x0401);
jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE);
break;
default:
dbg_printc("jlfxv2: release device: PC=%05x\n", address);
jlfxv2_set_pc(p, address);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0401);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_tclk_clr(p);
if (jtag_dr_shift_16(p, 0) & 2/*CNTRL_SIG_HALT*/) {
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0403);
}
jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE);
break;
}
}
/* Programs/verifies an array of words into a FLASH by using the
* FLASH controller. The JTAG FLASH register isn't needed.
* start_address: start in FLASH
* length : number of words
* data : pointer to data
*/
static void jlfxv2_write_flash(struct jtdev *p, address_t start_address,
unsigned int length, const uint16_t *data)
{ // SLAU320AJ name: WriteFLASH
// TODO: implement!
}
/* Performs a mass erase (with and w/o info memory) or a segment erase of a
* FLASH module specified by the given mode and address. Large memory devices
* get additional mass erase operations to meet the spec.
* erase_mode : ERASE_MASS, ERASE_MAIN, ERASE_SGMT
* erase_address: address within the selected segment
*/
static void jlfxv2_erase_flash(struct jtdev *p, unsigned int erase_mode,
address_t erase_address)
{ // SLAU320AJ name: EraseFLASH
// TODO: implement!
}
/* Reads a register from the target CPU */
static address_t jlfxv2_read_reg(struct jtdev *p, int reg)
{ // libmsp430 BIOS name: ReadCpuReg
uint16_t reglo, reghi;
uint16_t jtag_id, jmb_addr;
const bool alt_addr = false;//true;
if (reg == 3) return 0; // CG
dbg_printc("read reg %d\n", reg);
if (!jlfxv2_check_full_emu_state(p))
return 0;
jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_set(p);
jtag_dr_shift_16(p, ((reg << 8) & 0x0f00) | 0x0060);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1401);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_clr(p);
jtag_tclk_set(p);
if (alt_addr) {
jtag_dr_shift_16(p, 0x0ff6);
} else {
jmb_addr = (jtag_id == 0x98) ? 0x14c : 0x18c;
jtag_dr_shift_16(p, jmb_addr);
}
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_dr_shift_16(p, 0x3ffd);
jtag_tclk_clr(p);
if (alt_addr) {
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
}
jtag_ir_shift(p, IR_DATA_CAPTURE);
jtag_tclk_set(p);
reglo = jtag_dr_shift_16(p, 0);
jtag_tclk_clr(p);
jtag_tclk_set(p);
reghi = jtag_dr_shift_16(p, 0);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
if (!alt_addr) {
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
}
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_CAPTURE);
jtag_tclk_set(p);
dbg_printc("read reg %d: lo=%04x hi=%04x\n", reg, reglo, reghi);
jlfxv2_set_pc(p, SAFE_FRAM_PC);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
return reglo | ((address_t)reghi << 16);
}
/* Writes a value into a register of the target CPU */
static void jlfxv2_write_reg(struct jtdev *p, int reg, address_t value)
{ // SLAU320AJ name: SetPC
if (reg == 0 || reg == 3) return; // pc, cg
dbg_printc("write reg %d %06x\n", reg, value);
if (!jlfxv2_check_full_emu_state(p)) return;
/*jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_dr_shift_16(p, 0);*/
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_set(p);
jtag_dr_shift_16(p, 0x0080 | ((value >> 8) & 0x0f00) | (reg & 0xf));
//jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1401/*1400*/);
jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_dr_shift_16(p, value & 0xffff);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_dr_shift_16(p, 0x3ffd); // rewind PC
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
jtag_dr_shift_20(p, 0);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_CAPTURE);
jtag_tclk_set(p);
//jtag_dr_shift_20(p, 0);
}
/*----------------------------------------------------------------------------*/
static void jlfxv2_single_step( struct jtdev *p )
{ // libmsp430 BIOS name: SingleStep
int i, timeout;
uint16_t tmp;
dbg_printc("single step\n");
// TODO: fix this. it only performs an instruction fetch but not much else
/*jtag_ir_shift(p, IR_EMEX_READ_CONTROL);
timeout = 3000;
for (i = 0; i < timeout; ++i)
if (jtag_dr_shift_16(p, 0) & EEM_STOPPED)
break;
if (i == timeout) {
printc_err("jlfxv2_single_step: EEM timeout\n");
goto err;
}*/
jtag_ir_shift(p, IR_EMEX_WRITE_CONTROL);
jtag_dr_shift_16(p, EMU_CLK_EN | EEM_EN);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1501);
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
timeout = 50;
for (i = 0; i < timeout; ++i) {
tmp = jtag_dr_shift_16(p, 0);
if (tmp != 0xffff && (tmp & 0x200) == 0x0200)
break;
}
if (i == timeout) {
printc_err("jlfxv2_single_step: JTAG sync timeout\n");
goto err;
}
jtag_ir_shift(p, IR_EMEX_WRITE_CONTROL);
jtag_dr_shift_16(p, EMU_CLK_EN | CLEAR_STOP);
jtag_dr_shift_16(p, EMU_CLK_EN | CLEAR_STOP | EEM_EN);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1501);
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
timeout = 30000;
for (i = 0; i < timeout; ++i) {
if ((jtag_dr_shift_16(p, 0) & 8) == 0) break;
jtag_tclk_clr(p);
jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
}
if (i == timeout) {
printc_err("jlfxv2_single_step: single-step timeout\n");
goto err;
}
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
timeout = 10000;
for (i = 0; i < timeout; ++i) {
jtag_tclk_clr(p);
tmp = jtag_dr_shift_16(p, 0);
jtag_tclk_set(p);
if ((tmp & CNTRL_SIG_CPUSUSP) == CNTRL_SIG_CPUSUSP) break;
}
if (i == timeout) {
printc_err("jlfxv2_single_step: pipeline empty timeout\n");
goto err;
}
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501);
return;
err:
p->failed = 1;
}
/*----------------------------------------------------------------------------*/
static unsigned int jlfxv2_set_breakpoint( struct jtdev *p,int bp_num, address_t bp_addr )
{
/* The breakpoint logic is explained in 'SLAU414c EEM.pdf' */
/* A good overview is given with Figure 1-1 */
/* MBx is TBx in EEM_defs.h */
/* CPU Stop is BREAKREACT in EEM_defs.h */
/* State Storage is STOR_REACT in EEM_defs.h */
/* Cycle Counter is EVENT_REACT in EEM_defs.h */
// TODO: implement
return 0;
}
/*----------------------------------------------------------------------------*/
static unsigned int jlfxv2_cpu_state( struct jtdev *p )
{ // libmsp430 BIOS name: WaitForEem(?)
jtag_ir_shift(p, IR_EMEX_READ_CONTROL);
if ((jtag_dr_shift_16(p, 0x0000) & EEM_STOPPED) == EEM_STOPPED) {
dbg_printc("cpu_state: halted\n");
return 1; /* halted */
} else {
dbg_printc("cpu_state: running\n");
return 0; /* running */
}
}
/*----------------------------------------------------------------------------*/
static int jlfxv2_get_config_fuses( struct jtdev *p )
{ // always the same?
jtag_ir_shift(p, IR_CONFIG_FUSES);
return jtag_dr_shift_8(p, 0);
}
/* ------------------------------------------------------------------------- */
static void jlfxv2_context_save(struct jtdev *p, bool after_puc) {
address_t wdtctl_a = (p->jtag_id == 0x89) ? 0x0120 : 0x015c,
rst_vec = 0x0fffe,
mab, entrypt_addr;
dbg_printc("context save, %s\n", after_puc?"after PUC":"normal");
jtag_ir_shift(p, IR_EMEX_WRITE_CONTROL);
jtag_dr_shift_16(p, EMU_FEAT_EN | EMU_CLK_EN | CLEAR_STOP);
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_dr_shift_16(p, 0);
/* ReadMemWordXv2 */
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_20(p, wdtctl_a);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_CAPTURE);
p->wdtctl = jtag_dr_shift_16(p, 0) & 0xff;
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
dbg_printc("WDTCTL: %04x\n", p->wdtctl);
/* ReadMemWordXv2 */
/* actually not using the result for this, but adding this makes it work
* somehow */
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_20(p, rst_vec);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_CAPTURE);
entrypt_addr = jtag_dr_shift_16(p, 0);
jtag_tclk_set(p);
jtag_tclk_clr(p);
jtag_tclk_set(p);
dbg_printc("ENTRYPOINT: %04x\n", entrypt_addr);
jtag_ir_shift(p, IR_ADDR_CAPTURE);
mab = demangle_mab(jtag_dr_shift_20(p, 0));
dbg_printc("PC MAB: %05x\n", mab);
//mab = rst_vec + 4;
/* back up program counter */
if (after_puc) {
p->regs[0] = rst_vec; /* yeah.. */
} else {
p->regs[0] = mab - 4;
}
if (p->regs[0] == rst_vec) {
p->regs[0] = jtag_read_mem(p, 16, rst_vec);
dbg_printc("ENTRY TRY1: %04x\n", p->regs[0]);
if (p->regs[0] == 0xffff || p->regs[0] == 0x3fff) {
p->regs[0] = jtag_read_mem(p, 16, rst_vec);
dbg_printc("ENTRY TRY2: %04x\n", p->regs[0]);
}
}
/* disable watchdog */
//p->wdtctl = jtag_read_mem(p, 16, wdtctl_a) & 0xff;
dbg_printc("WDTCTL: %04x\n", p->wdtctl);
jtag_write_mem(p, 16, wdtctl_a, p->wdtctl | 0x5a80);
/* also back up stack pointer & status register */
p->regs[1] = jtag_read_reg(p, 1);
p->regs[2] = jtag_read_reg(p, 2);
const static uint16_t data[] = {0x3fff,0x3fff,0x3fff};
jtag_write_mem_quick(p, 0x00004, sizeof(data)/sizeof(*data), data);
}
static void jlfxv2_context_restore(struct jtdev *p) {
dbg_printc("context restore\n");
/* basically the inverse of context_save */
address_t wdtctl_a = (p->jtag_id == 0x89) ? 0x0120 : 0x015c;
jtag_write_reg(p, 1, p->regs[1]);
jtag_write_reg(p, 2, p->regs[2]);
jtag_write_mem(p, 16, wdtctl_a, p->wdtctl | 0x5a00);
jlfxv2_set_pc(p, p->regs[0]);
}
/* ------------------------------------------------------------------------- */
const struct jtaglib_funcs jlf_cpuxv2 = {
.jlf_get_device = jlfxv2_get_device,
.jlf_read_mem = jlfxv2_read_mem,
.jlf_read_mem_quick = jlfxv2_read_mem_quick,
.jlf_write_mem = jlfxv2_write_mem,
.jlf_write_mem_quick = jlfxv2_write_mem_quick,
.jlf_execute_puc = jlfxv2_execute_puc,
.jlf_release_device = jlfxv2_release_device,
.jlf_verify_mem = jlfxv2_verify_mem,
.jlf_erase_check = jlfxv2_erase_check,
.jlf_write_flash = jlfxv2_write_flash,
.jlf_erase_flash = jlfxv2_erase_flash,
.jlf_context_save = jlfxv2_context_save,
.jlf_context_restore = jlfxv2_context_restore,
.jlf_regs_update = jtag_dev_default_regs_update,
.jlf_regs_flush = jtag_dev_default_regs_flush,
.jlf_read_reg = jlfxv2_read_reg,
.jlf_write_reg = jlfxv2_write_reg,
.jlf_single_step = jlfxv2_single_step,
.jlf_set_breakpoint = jlfxv2_set_breakpoint,
.jlf_cpu_state = jlfxv2_cpu_state,
.jlf_get_config_fuses = jlfxv2_get_config_fuses,
};

77
drivers/jtaglib_defs.h Normal file
View File

@ -0,0 +1,77 @@
#include "jtaglib.h"
#include "eem_defs.h"
/* Flash erasing modes */
#define JTAG_ERASE_MASS 0xA506
#define JTAG_ERASE_MAIN 0xA504
#define JTAG_ERASE_SGMT 0xA502
#define JTAG_ID_IS_XV2(x) ((x)==0x91||(x)==0x95||(x)==0x98||(x)==0x99)
/* Instructions for the JTAG control signal register in reverse bit order
*/
#define IR_CNTRL_SIG_16BIT 0xC8 /* 0x13 */
#define IR_CNTRL_SIG_CAPTURE 0x28 /* 0x14 */
#define IR_CNTRL_SIG_RELEASE 0xA8 /* 0x15 */
#define IR_COREIP_ID 0xE8 /* 0x17 */
/* Instructions for the JTAG data register */
#define IR_DATA_16BIT 0x82 /* 0x41 */
#define IR_DATA_CAPTURE 0x42 /* 0x42 */
#define IR_DATA_QUICK 0xC2 /* 0x43 */
/* Instructions for the JTAG address register */
#define IR_ADDR_16BIT 0xC1 /* 0x83 */
#define IR_ADDR_CAPTURE 0x21 /* 0x84 */
#define IR_DATA_TO_ADDR 0xA1 /* 0x85 */
#define IR_DEVICE_ID 0xE1 /* 0x87 */
/* Instructions for the JTAG PSA mode */
#define IR_DATA_PSA 0x22 /* 0x44 */
#define IR_SHIFT_OUT_PSA 0x62 /* 0x46 */
/* Instructions for the JTAG Fuse */
#define IR_PREPARE_BLOW 0x44 /* 0x22 */
#define IR_EX_BLOW 0x24 /* 0x24 */
/* Instructions for the JTAG mailbox */
#define IR_TEST_REG 0x54 /* 0x2A */
/* Instructions for the Configuration Fuse */
#define IR_CONFIG_FUSES 0x94
/* Bypass instruction */
#define IR_BYPASS 0xFF /* 0xFF */
/* Instructions for the EEM */
#define IR_EMEX_DATA_EXCHANGE 0x90 /* 0x09 */
#define IR_EMEX_WRITE_CONTROL 0x30 /* 0x0C */
#define IR_EMEX_READ_CONTROL 0xD0 /* 0x0B */
/* EEM stuff */
#define EEM_STOPPED 0x0080
#define EEM_EN 0x0001
#define CLEAR_STOP 0x0002
#define EMU_CLK_EN 0x0004
#define CNTRL_SIG_CPUSUSP (1<<8)
#define jtag_tms_set(p) p->f->jtdev_tms(p, 1)
#define jtag_tms_clr(p) p->f->jtdev_tms(p, 0)
#define jtag_tck_set(p) p->f->jtdev_tck(p, 1)
#define jtag_tck_clr(p) p->f->jtdev_tck(p, 0)
#define jtag_tdi_set(p) p->f->jtdev_tdi(p, 1)
#define jtag_tdi_clr(p) p->f->jtdev_tdi(p, 0)
#define jtag_tclk_set(p) p->f->jtdev_tclk(p, 1)
#define jtag_tclk_clr(p) p->f->jtdev_tclk(p, 0)
#define jtag_rst_set(p) p->f->jtdev_rst(p, 1)
#define jtag_rst_clr(p) p->f->jtdev_rst(p, 0)
#define jtag_tst_set(p) p->f->jtdev_tst(p, 1)
#define jtag_tst_clr(p) p->f->jtdev_tst(p, 0)
#define jtag_led_green_on(p) p->f->jtdev_led_green(p, 1)
#define jtag_led_green_off(p) p->f->jtdev_led_green(p, 0)
#define jtag_led_red_on(p) p->f->jtdev_led_red(p, 1)
#define jtag_led_red_off(p) p->f->jtdev_led_red(p, 0)
#define jtag_ir_shift(p, ir) p->f->jtdev_ir_shift(p, ir)
#define jtag_dr_shift_8(p, dr) p->f->jtdev_dr_shift_8(p, dr)
#define jtag_dr_shift_16(p, dr) p->f->jtdev_dr_shift_16(p, dr)
#define jtag_dr_shift_20(p, dr) p->f->jtdev_dr_shift_20(p, dr)
#define jtag_tms_sequence(p, bits, tms) p->f->jtdev_tms_sequence(p, bits, tms)
#define jtag_init_dap(p) p->f->jtdev_init_dap(p)

View File

@ -22,7 +22,7 @@
*/
#include <stdint.h>
#include "jtdev.h"
#include "jtaglib.h"
#include "output.h"
#if defined(__linux__) || \
@ -354,6 +354,13 @@ const struct jtdev_func jtdev_func_pif = {
.jtdev_tclk_get = jtpif_tclk_get,
.jtdev_tclk_strobe = jtpif_tclk_strobe,
.jtdev_led_green = jtpif_led_green,
.jtdev_led_red = jtpif_led_red
.jtdev_led_red = jtpif_led_red,
.jtdev_ir_shift = jtag_default_ir_shift,
.jtdev_dr_shift_8 = jtag_default_dr_shift_8,
.jtdev_dr_shift_16 = jtag_default_dr_shift_16,
.jtdev_dr_shift_20 = jtag_default_dr_shift_20,
.jtdev_tms_sequence= jtag_default_tms_sequence,
.jtdev_init_dap = jtag_default_init_dap
};

View File

@ -22,13 +22,22 @@
#include <stdint.h>
#include "device.h"
#include "jtaglib_defs.h"
struct jtdev_func;
struct jtdev {
struct device base;
int port;
uint8_t data_register;
uint8_t control_register;
uint8_t jtag_id;
uint8_t cpu_type;
int failed;
const struct jtdev_func * f;
address_t regs[DEVICE_NUM_REGS];
uint16_t wdtctl;
};
struct jtdev_func {
@ -64,6 +73,13 @@ struct jtdev_func{
void (*jtdev_led_green)(struct jtdev *p, int out);
void (*jtdev_led_red)(struct jtdev *p, int out);
/* Optional functions implementing higher-level stuff */
uint8_t (*jtdev_ir_shift)(struct jtdev *p, uint8_t ir);
uint8_t (*jtdev_dr_shift_8)(struct jtdev *p, uint8_t dr);
uint16_t (*jtdev_dr_shift_16)(struct jtdev *p, uint16_t dr);
uint32_t (*jtdev_dr_shift_20)(struct jtdev *p, uint32_t dr);
void (*jtdev_tms_sequence)(struct jtdev *p, int bits, unsigned int value);
void (*jtdev_init_dap)(struct jtdev *p);
};
extern const struct jtdev_func jtdev_func_pif;

View File

@ -22,7 +22,7 @@
*/
#include <stdint.h>
#include "jtdev.h"
#include "jtaglib.h"
#include "output.h"
#if defined(__linux__)
@ -186,7 +186,8 @@ static void jtbp_close(struct jtdev *p)
out_buff = 0x0f;
// Don't care if this fails, user can just power cycle the bus pirate
if(write(p->port, &out_buff, 1));
if(write(p->port, &out_buff, 1))
;
close(p->port);
}
@ -351,6 +352,13 @@ const struct jtdev_func jtdev_func_bp = {
.jtdev_tclk_get = jtbp_tclk_get,
.jtdev_tclk_strobe = jtbp_tclk_strobe,
.jtdev_led_green = jtbp_led_green,
.jtdev_led_red = jtbp_led_red
.jtdev_led_red = jtbp_led_red,
.jtdev_ir_shift = jtag_default_ir_shift,
.jtdev_dr_shift_8 = jtag_default_dr_shift_8,
.jtdev_dr_shift_16 = jtag_default_dr_shift_16,
.jtdev_dr_shift_20 = jtag_default_dr_shift_20,
.jtdev_tms_sequence= jtag_default_tms_sequence,
.jtdev_init_dap = jtag_default_init_dap
};

View File

@ -21,7 +21,7 @@
*/
#include <stdint.h>
#include "jtdev.h"
#include "jtaglib.h"
#include "output.h"
#if defined(__linux__) || \
@ -263,5 +263,12 @@ const struct jtdev_func jtdev_func_gpio = {
.jtdev_tclk_get = jtgpio_tclk_get,
.jtdev_tclk_strobe = jtgpio_tclk_strobe,
.jtdev_led_green = jtgpio_led_green,
.jtdev_led_red = jtgpio_led_red
.jtdev_led_red = jtgpio_led_red,
.jtdev_ir_shift = jtag_default_ir_shift,
.jtdev_dr_shift_8 = jtag_default_dr_shift_8,
.jtdev_dr_shift_16 = jtag_default_dr_shift_16,
.jtdev_dr_shift_20 = jtag_default_dr_shift_20,
.jtdev_tms_sequence= jtag_default_tms_sequence,
.jtdev_init_dap = jtag_default_init_dap
};

379
drivers/mehfet.c Normal file
View File

@ -0,0 +1,379 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2021 sys64738@disroot.org
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "output.h"
#include "ctrlc.h"
#include "jtaglib.h"
#include "mehfet_proto.h"
#include "mehfet_xport.h"
#include "mehfet.h"
struct mehfet_device {
struct jtdev jtag;
transport_t trans;
enum mehfet_conn connstat;
};
/*extern void __builtin_trap(void);*/
#define NO_LL_JTAG_BP 0
#define no_ll_jtag() \
do { \
printc_err("mehfet: %s: low-lewel JTAG function not implemented!\n", __func__); \
p->failed = 1; \
if (NO_LL_JTAG_BP) /*__builtin_trap()*/; \
} while (0) \
#define JTMF_GET_DEV(p) ((struct mehfet_device*)((size_t)(p) - \
offsetof(struct mehfet_device, jtag))) \
static int jtmf_open(struct jtdev* p, const char* device)
{
printc_err("mehfet: %s should not get called.\n", __func__);
p->failed = 1;
return -1;
}
static void jtmf_close(struct jtdev* p)
{
printc_err("mehfet: %s should not get called.\n", __func__);
p->failed = 1;
}
static void jtmf_power_on(struct jtdev* p)
{
printc_err("mehfet: %s should not get called.\n", __func__);
p->failed = 1;
}
static void jtmf_power_off(struct jtdev* p)
{
printc_err("mehfet: %s should not get called.\n", __func__);
p->failed = 1;
}
static void jtmf_connect(struct jtdev* p)
{
printc_err("mehfet: %s should not get called.\n", __func__);
p->failed = 1;
}
static void jtmf_release(struct jtdev* p)
{
printc_err("mehfet: %s should not get called.\n", __func__);
p->failed = 1;
}
static void jtmf_tck(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
static void jtmf_tms(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
static void jtmf_tdi(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
static void jtmf_rst(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
static void jtmf_tst(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
static int jtmf_tdo_get(struct jtdev* p) { no_ll_jtag(); return 0; }
static void jtmf_tclk(struct jtdev* p, int out)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
int r = mehfet_cmd_tclk_edge(d->trans, out);
if (r < 0) p->failed = 1;
}
static int jtmf_tclk_get(struct jtdev* p)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
int ret = 1;
enum mehfet_lines lines = 0;
int r = mehfet_cmd_get_old_lines(d->trans, &lines);
if (r < 0) {
p->failed = 1;
} else {
ret = (lines & mehfet_line_tclk) ? 1 : 0;
}
return ret;
}
static void jtmf_tclk_strobe(struct jtdev* p, unsigned int count)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
int r = mehfet_cmd_tclk_burst(d->trans, count);
if (r < 0) p->failed = 1;
}
/* MehFET has no leds */
static void jtmf_led_green(struct jtdev* p, int out) { (void)p; (void)out; }
static void jtmf_led_red (struct jtdev* p, int out) { (void)p; (void)out; }
static uint8_t jtmf_ir_shift(struct jtdev *p, uint8_t ir)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
uint8_t ret = 0;
int r = mehfet_cmd_irshift(d->trans, ir, &ret);
if (r < 0) p->failed = 1;
return ret;
}
static uint8_t jtmf_dr_shift_8(struct jtdev *p, uint8_t dr)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
uint8_t ret = 0;
int r = mehfet_cmd_drshift(d->trans, 8, &dr, &ret);
if (r < 0) p->failed = 1;
return ret;
}
static uint16_t jtmf_dr_shift_16(struct jtdev *p, uint16_t dr)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
uint8_t inbuf[2] = { dr & 0xff, (dr >> 8) & 0xff };
uint8_t outbuf[2];
int r = mehfet_cmd_drshift(d->trans, 16, inbuf, outbuf);
if (r < 0) p->failed = 1;
return outbuf[0] | ((uint16_t)outbuf[1] << 8);
}
static uint32_t jtmf_dr_shift_20(struct jtdev *p, uint32_t dr)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
uint8_t inbuf[3] = { dr & 0xff, (dr >> 8) & 0xff, (dr >> 16) & 0x0f };
uint8_t outbuf[3];
int r = mehfet_cmd_drshift(d->trans, 20, inbuf, outbuf);
if (r < 0) p->failed = 1;
return outbuf[0] | ((uint32_t)outbuf[1] << 8) | ((uint32_t)outbuf[2] << 16);
}
static void jtmf_tms_sequence(struct jtdev *p, int bits, unsigned int value)
{
struct mehfet_device* d = JTMF_GET_DEV(p);
enum mehfet_lines lines = 0;
int r = mehfet_cmd_get_old_lines(d->trans, &lines);
if (r < 0) {
p->failed = 1;
return;
}
uint8_t dbuf[4] = { value & 0xff, (value >> 8) & 0xff,
(value >> 16) & 0xff, (value >> 24) & 0xff };
r = mehfet_cmd_tms_seq(d->trans, lines & mehfet_line_tdi, bits, dbuf);
if (r < 0) p->failed = 1;
}
static void jtmf_init_dap(struct jtdev *p)
{
struct mehfet_device* dev = JTMF_GET_DEV(p);
enum mehfet_resettap_status stat = 0;
int r = mehfet_cmd_reset_tap(dev->trans, mehfet_rsttap_do_reset
| mehfet_rsttap_fuse_do, &stat);
if (r < 0) p->failed = 1;
}
static const struct jtdev_func jtdev_func_mehfet = {
.jtdev_open = jtmf_open,
.jtdev_close = jtmf_close,
.jtdev_power_on = jtmf_power_on,
.jtdev_power_off = jtmf_power_off,
.jtdev_connect = jtmf_connect,
.jtdev_release = jtmf_release,
.jtdev_tck = jtmf_tck,
.jtdev_tms = jtmf_tms,
.jtdev_tdi = jtmf_tdi,
.jtdev_rst = jtmf_rst,
.jtdev_tst = jtmf_tst,
.jtdev_tdo_get = jtmf_tdo_get,
.jtdev_tclk = jtmf_tclk,
.jtdev_tclk_get = jtmf_tclk_get,
.jtdev_tclk_strobe = jtmf_tclk_strobe,
.jtdev_led_green = jtmf_led_green,
.jtdev_led_red = jtmf_led_red,
.jtdev_ir_shift = jtmf_ir_shift,
.jtdev_dr_shift_8 = jtmf_dr_shift_8,
.jtdev_dr_shift_16 = jtmf_dr_shift_16,
.jtdev_dr_shift_20 = jtmf_dr_shift_20,
.jtdev_tms_sequence= jtmf_tms_sequence,
.jtdev_init_dap = jtmf_init_dap
};
/*---------------------------------------------------------------------------*/
static int check_dev_ok(struct mehfet_device* dev, const struct device_args* args,
enum mehfet_conn* useconn) {
transport_t t = dev->trans;
struct mehfet_info info;
int r;
r = mehfet_cmd_info(t, &info);
if (r < 0) return r;
printc_dbg("mehfet: MehFET %s\n", info.devicename);
free(info.devicename);
if (info.proto_version < MEHFET_PROTO_VER_MIN_SUPPORTED) {
printc_err("mehfet: device has protocol version %04x, "
"need at least %04x\n", info.proto_version,
MEHFET_PROTO_VER_MIN_SUPPORTED);
return -1;
}
if (info.proto_version > MEHFET_PROTO_VER) {
printc_err("mehfet: device has newer protocol version %04x "
"supporting at most %04x\n", info.proto_version,
MEHFET_PROTO_VER);
return -1;
}
if (args->flags & DEVICE_FLAG_JTAG) {
if (!(info.caps & (mehfet_cap_jtag_noentry | mehfet_cap_jtag_entryseq))) {
printc_err("mehfet: Cannot do JTAG, device doesn't have the capability\n");
return -1;
}
// devices that don't need one will probably work when given an entry
// sequence. no good way of doing a proper autodetect sadly
if (info.caps & mehfet_cap_jtag_entryseq)
*useconn = mehfet_conn_jtag_entryseq;
else
*useconn = mehfet_conn_jtag_noentry;
} else {
if (!(info.caps & mehfet_cap_sbw_entryseq)) {
printc_err("mehfet: Cannot do Spy-Bi-Wire, device doesn't have the capability\n");
return -1;
}
*useconn = mehfet_conn_sbw_entryseq;
}
if (args->flags & DEVICE_FLAG_FORCE_RESET)
*useconn |= mehfet_conn_nrstmask;
mehfet_transport_set_buf_size(t, (int)info.packet_buf_size);
return 0;
}
static void mehfet_destroy(device_t dev_base) {
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
if (!dev) return;
#ifdef DEBUG_MEHFET_DRIVER
printc_dbg("mehfet: releasing device & disconnecting\n");
#endif
if (dev->trans) {
jtag_release_device(&dev->jtag, 0xfffe); // 0xfffe=reset address : POR
mehfet_cmd_disconnect(dev->trans);
dev->trans->ops->destroy(dev->trans);
dev->trans = NULL;
}
free(dev);
}
static device_t mehfet_open(const struct device_args* args) {
struct mehfet_device* dev;
int r;
if ((args->flags & DEVICE_FLAG_TTY)) {
printc_err("mehfet: this driver does not support TTY access\n");
return NULL;
}
dev = calloc(1, sizeof(*dev));
if (!dev) {
printc_err("mehfet: malloc: %s\n", last_error());
return NULL;
}
dev->jtag.base.type = &device_mehfet;
dev->jtag.base.max_breakpoints = 2; // TODO
dev->jtag.base.need_probe = 1; // TODO
dev->jtag.f = &jtdev_func_mehfet;
// the MehFET currently doesn't have a designated PID, so we can't really
// default to one.
dev->trans = mehfet_transport_open(args->path,
((args->flags & DEVICE_FLAG_HAS_VID_PID) ? &args->vid : NULL),
((args->flags & DEVICE_FLAG_HAS_VID_PID) ? &args->pid : NULL),
args->requested_serial);
if (!dev->trans) goto FAIL;
enum mehfet_conn useconn;
r = check_dev_ok(dev, args, &useconn);
if (r < 0) goto FAIL;
r = mehfet_cmd_connect(dev->trans, useconn);
if (r < 0) goto FAIL;
r = mehfet_cmd_status(dev->trans, &dev->connstat);
if (r < 0) goto FAIL;
if (dev->connstat != (useconn & mehfet_conn_typemask)) {
printc_err("mehfet: could not create connection to device\n");
goto FAIL;
}
r = jtag_dev_init(&dev->jtag);
if (r < 0) goto FAIL;
// JTAG fuse check has been performed, so we can now switch to a
// higher-speed physical transport suitable for ~350 kHz TCLK strobes used
// in (and required for) flash programming
r = mehfet_cmd_set_clkspeed(dev->trans, true);
if (r < 0) goto FAIL;
#ifdef DEBUG_MEHFET_DRIVER
printc_dbg("mehfet: device opened\n");
#endif
return (device_t)dev;
FAIL:
mehfet_destroy((device_t)dev);
return NULL;
}
const struct device_class device_mehfet = {
.name = "mehfet",
.help = "MehFET USB JTAG/SBW device",
.open = mehfet_open,
.destroy = mehfet_destroy,
.readmem = jtag_dev_readmem,
.writemem = jtag_dev_writemem,
.getregs = jtag_dev_getregs,
.setregs = jtag_dev_setregs,
.ctl = jtag_dev_ctl,
.poll = jtag_dev_poll,
.erase = jtag_dev_erase,
.getconfigfuses = jtag_dev_getconfigfuses
};

27
drivers/mehfet.h Normal file
View File

@ -0,0 +1,27 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2021, sys64738@disroot.org
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MEHFET_H_
#define MEHFET_H_
#include "device.h"
extern const struct device_class device_mehfet;
#endif

561
drivers/mehfet_proto.c Normal file
View File

@ -0,0 +1,561 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2021 sys64738@disroot.org
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "mehfet_xport.h"
#include "output.h"
#include "util.h"
#include "mehfet_proto.h"
// TODO: replace '64' by transport buf size
int mehfet_cmd_info(transport_t t, struct mehfet_info* info) {
if (!info) return -1;
uint8_t buf[64];
int r;
r = mehfet_send_raw(t, mehfet_info, 0, NULL);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("Info", stat, len, buf);
if (r < 0) return r;
if (len < 8) {
printc_err("mehfet: Info response too short: %d < 8\n", len);
return -1;
}
info->caps = buf[0] | ((uint32_t)buf[1] << 8)
| ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24);
info->proto_version = buf[4] | ((uint16_t)buf[5] << 8);
info->packet_buf_size = 1u << buf[6];
// buf[7]: reserved
if (len > 9) { // len includes the null terminator
char* str = calloc(len - 8, 1);
memcpy(str, &buf[8], len - 8);
str[len - 9] = 0;
info->devicename = str;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: Info(): '%s' caps=0x%x, protover=0x%04x, pktsize=0x%x\n",
info->devicename ? info->devicename : "<none>",
info->caps, info->proto_version, info->packet_buf_size);
#endif
return 0;
}
int mehfet_cmd_status(transport_t t, enum mehfet_conn* ret) {
if (!ret) return -1;
uint8_t buf[64];
int r;
r = mehfet_send_raw(t, mehfet_status, 0, NULL);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("Status", stat, len, buf);
if (r < 0) return r;
if (len != 1) {
printc_err("mehfet: Status response wrong length: %d != 1\n", len);
return -1;
}
*ret = buf[0];
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: Status(): %hhu\n", *ret);
#endif
return 0;
}
int mehfet_cmd_connect(transport_t t, enum mehfet_conn conn) {
uint8_t buf[64];
int r;
buf[0] = conn;
r = mehfet_send_raw(t, mehfet_connect, 1, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("Connect", stat, len, buf);
if (r < 0) return r;
if (len != 0) {
printc_err("mehfet: Connect response wrong length: %d != 0\n", len);
return -1;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: Connect(0x%x)\n", conn);
#endif
return 0;
}
int mehfet_cmd_disconnect(transport_t t) {
uint8_t buf[64];
int r;
r = mehfet_send_raw(t, mehfet_disconnect, 0, NULL);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("Disconnect", stat, len, buf);
if (r < 0) return r;
if (len != 0) {
printc_err("mehfet: Disconnect response wrong length: %d != 0\n", len);
return -1;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: Disconnect()\n");
#endif
return 0;
}
int mehfet_cmd_delay(transport_t t, bool us, bool exact, uint32_t time) {
if (time >= (1u << 30)) return -1; // too large
uint8_t buf[64];
int r;
for (size_t i = 0; i < 4; ++i) buf[i] = (time >> (i*8)) & 0xff;
if (us) buf[3] |= 0x40;
if (exact) buf[3] |= 0x80;
r = mehfet_send_raw(t, mehfet_delay, 4, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("Delay", stat, len, buf);
if (r < 0) return r;
if (len != 0) {
printc_err("mehfet: Delay response wrong length: %d != 0\n", len);
return -1;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: Delay(us=%c exact=%c time=%u)\n",
us?'t':'f', exact?'t':'f', time);
#endif
return 0;
}
int mehfet_cmd_set_clkspeed(transport_t t, bool fast) {
uint8_t buf[64];
int r;
buf[0] = fast ? 0xff : 0;
r = mehfet_send_raw(t, mehfet_set_clkspeed, 1, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("SetClkSpeed", stat, len, buf);
if (r < 0) return r;
if (len != 0) {
printc_err("mehfet: SetClkSpeed response wrong length: %d != 0\n", len);
return -1;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: SetClkSpeed(%s)\n", fast?"fast":"slow");
#endif
return 0;
}
int mehfet_cmd_get_old_lines(transport_t t, enum mehfet_lines* lines) {
if (!lines) return -1;
uint8_t buf[64];
int r;
r = mehfet_send_raw(t, mehfet_get_old_lines, 0, NULL);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("GetOldLines", stat, len, buf);
if (r < 0) return r;
if (len != 1) {
printc_err("mehfet: GetOldLines response wrong length: %d != 1\n", len);
return -1;
}
*lines = buf[0];
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: GetOldLines(): 0x%x\n", *lines);
#endif
return 0;
}
int mehfet_cmd_tdio_seq(transport_t t, uint32_t nbits, bool tms, const uint8_t* tdi, uint8_t* tdo) {
if (!tdi || !tdo || !nbits) return -1;
int r;
uint32_t nbytes = (nbits + 7) >> 3;
uint8_t buf[(nbytes + 5) < 64 ? 64 : (nbytes + 5)]; // need min for recv
for (size_t i = 0; i < 4; ++i) buf[i] = (nbits >> (i*8)) & 0xff;
buf[4] = tms ? 0xff : 0;
memcpy(&buf[5], tdi, nbytes);
r = mehfet_send_raw(t, mehfet_tdio_seq, nbytes + 5, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf; // is a max len
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("TdioSequence", stat, len, buf);
if (r < 0) return r;
if (len != nbytes) {
printc_err("mehfet: TdioSequence response wrong length: %d != %d\n",
len, nbytes);
return -1;
}
memcpy(tdo, buf, nbytes);
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: TdioSequence(%u, TMS=%c):\n", nbits, tms?'1':'0');
debug_hexdump("\tTDI", tdi, nbytes);
debug_hexdump("\tTDO", tdo, nbytes);
#endif
return 0;
}
int mehfet_cmd_tms_seq(transport_t t, uint32_t nbits, bool tdi, const uint8_t* tms) {
if (!tms || !nbits) return -1;
int r;
uint32_t nbytes = (nbits + 7) >> 3;
uint8_t buf[(nbytes + 5) < 64 ? 64 : (nbytes + 5)]; // need min for recv
for (size_t i = 0; i < 4; ++i) buf[i] = (nbits >> (i*8)) & 0xff;
buf[4] = tdi ? 0xff : 0;
memcpy(&buf[5], tms, nbytes);
r = mehfet_send_raw(t, mehfet_tdio_seq, sizeof buf, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf; // is a max len
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("TmsSequence", stat, len, buf);
if (r < 0) return r;
if (len != 0) {
printc_err("mehfet: TmsSequence response wrong length: %d != 0\n", len);
return -1;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: TmsSequence(%u, TDI=%c):\n", nbits, tdi?'1':'0');
debug_hexdump("\tTMS", tms, nbytes);
#endif
return 0;
}
int mehfet_cmd_tclk_edge(transport_t t, bool newtclk) {
uint8_t buf[64];
int r;
buf[0] = newtclk ? 0xff : 0;
r = mehfet_send_raw(t, mehfet_tclk_edge, 1, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("TclkEdge", stat, len, buf);
if (r < 0) return r;
if (len != 0) {
printc_err("mehfet: TclkEdge response wrong length: %d != 0\n", len);
return -1;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: TclkEdge(TCLK=%c)\n", newtclk?'H':'L');
#endif
return 0;
}
int mehfet_cmd_tclk_burst(transport_t t, uint32_t ncyc) {
uint8_t buf[64];
int r;
for (size_t i = 0; i < 4; ++i) buf[i] = (ncyc >> (i*8)) & 0xff;
r = mehfet_send_raw(t, mehfet_tclk_burst, 4, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("TclkBurst", stat, len, buf);
if (r < 0) return r;
if (len != 0) {
printc_err("mehfet: TclkBurst response wrong length: %d != 0\n", len);
return -1;
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: TclkBurst(ncyc=%u)\n", ncyc);
#endif
return 0;
}
int mehfet_cmd_reset_tap(transport_t t, enum mehfet_resettap_flags flags,
enum mehfet_resettap_status* tstat) {
if (!tstat) return -1;
uint8_t buf[64];
int r;
buf[0] = flags;
r = mehfet_send_raw(t, mehfet_reset_tap, 1, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("ResetTAP", stat, len, buf);
if (r < 0) return r;
if (len != 1) {
printc_err("mehfet: ResetTAP response wrong length: %d != 1\n", len);
return -1;
}
*tstat = buf[0];
#ifdef DEBUG_MEHFET_PROTO_DRIVER
printc_dbg("mehfet: ResetTAP(flags=0x%x) = 0x%x\n", flags, *tstat);
#endif
return 0;
}
static uint8_t bitswap_nyb(uint8_t in) {
return ((in >> 3) & 1) | ((in >> 1) & 2) | ((in << 1) & 4) | ((in << 3) & 8);
}
static uint8_t bitswap(uint8_t in) {
return (bitswap_nyb(in&0xf) << 4) | bitswap_nyb(in>>4);
}
#ifdef DEBUG_MEHFET_PROTO_DRIVER
static const char* get_ir_name(uint8_t ir) {
switch (ir) {
case 0x09: return "EMEX_DATA_EXCHANGE";
case 0x0a: return "EMEX_READ_TRIGGER";
case 0x0b: return "EMEX_READ_CONTROL";
case 0x0c: return "EMEX_WRITE_CONTROL";
case 0x0d: return "EMEX_READ_CONTROL_2";
case 0x0e: return "EMEX_WRITE_CONTROL_2";
case 0x11: return "CNTRL_SIG_HIGH_BYTE";
case 0x12: return "CNTRL_SIG_LOW_BYTE";
case 0x13: return "CNTRL_SIG_16BIT";
case 0x14: return "CNTRL_SIG_CAPTURE";
case 0x15: return "CNTRL_SIG_RELEASE";
case 0x17: return "COREIP_ID";
case 0x19: return "FLASH_16BIT_UPDATE";
case 0x1a: return "FLASH_CAPTURE";
case 0x1b: return "FLASH_16BIT_IN";
case 0x1c: return "FLASH_UPDATE";
case 0x21: return "CNTRL";
case 0x22: return "PREPARE_BLOW";
case 0x24: return "EX_BLOX";
case 0x29: return "CONFIG_FUSES";
case 0x2a: return "TEST_REG";
case 0x2f: return "TEST_3V_REG";
case 0x31: return "DUAL_8BIT";
case 0x32: return "DUAL_CAPTURE";
case 0x33: return "SELECT_MAIN";
case 0x34: return "SELECT_ESP";
case 0x41: return "DATA_16BIT";
case 0x42: return "DATA_CAPTURE";
case 0x43: return "DATA_QUICK";
case 0x44: return "DATA_PSA";
case 0x45: return "DATA_16BIT_OPT";
case 0x46: return "SHIFT_OUT_PSA";
case 0x47: return "DTA";
case 0x59: return "ACCEPT_KEY";
case 0x61: return "JMB_EXCHANGE";
case 0x62: return "JSTATE_ID";
case 0x64: return "TDO_EVENT";
case 0x65: return "TDO_EVENT_CTL";
case 0x81: return "ADDR_HIGH_BYTE";
case 0x82: return "ADDR_LOW_BYTE";
case 0x83: return "ADDR_16BIT";
case 0x84: return "ADDR_CAPTURE";
case 0x85: return "DATA_TO_ADDR";
case 0x86: return "CAPTURE_CPU_REG";
case 0x87: return "DEVICE_ID";
case 0x88: return "JMB_WRITE_32BIT_MODE";
case 0xFF: return "BYPASS";
default: return NULL;
}
}
#endif
int mehfet_cmd_irshift(transport_t t, uint8_t newir, uint8_t* oldir) {
if (!oldir) return -1;
// NOTE: jtaglib.c uses bitswapped IR values, while MehFET uses values from
// the SLAU320 PDF, so we need to perform a bitswap here
newir = bitswap(newir);
uint8_t buf[64];
int r;
buf[0] = newir;
r = mehfet_send_raw(t, mehfet_irshift, 1, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("IRshift", stat, len, buf);
if (r < 0) return r;
if (len != 1) {
printc_err("mehfet: IRshift response wrong length: %d != 1\n", len);
return -1;
}
*oldir = buf[0];
#ifdef DEBUG_MEHFET_PROTO_DRIVER
const char* s = get_ir_name(newir);
if (s) {
printc_dbg("mehfet: IRshift(new=IR_%s) = 0x%02x\n", s, *oldir);
} else {
printc_dbg("mehfet: IRshift(new=0x%02x) = 0x%02x\n", newir, *oldir);
}
#endif
return 0;
}
int mehfet_cmd_drshift(transport_t t, uint32_t nbits, const uint8_t* newdr, uint8_t* olddr) {
if (!newdr || !olddr) return -1;
uint32_t nbytes = (nbits + 7) >> 3;
uint8_t buf[(nbytes + 4) < 64 ? 64 : (nbytes + 4)];
int r;
for (size_t i = 0; i < 4; ++i) buf[i] = (nbits >> (i * 8)) & 0xff;
memcpy(&buf[4], newdr, nbytes);
r = mehfet_send_raw(t, mehfet_drshift, nbytes + 4, buf);
if (r < 0) return r;
uint8_t stat = 0;
int len = sizeof buf;
r = mehfet_recv_raw(t, &stat, &len, buf);
if (r < 0) return r;
r = mehfet_err_on_stat("DRshift", stat, len, buf);
if (r < 0) return r;
if (len != (int)nbytes) {
printc_err("mehfet: DRshift response wrong length: %d != %u\n", len, nbytes);
return -1;
}
memcpy(olddr, buf, nbytes);
#ifdef DEBUG_MEHFET_PROTO_DRIVER
if (nbits == 16) {
uint16_t in, out;
in = newdr[0] | ((uint16_t)newdr[1] << 8);
out= olddr[0] | ((uint16_t)olddr[1] << 8);
printc_dbg("mehfet: DRshift(nbits=%u): in: %04x, out: %04x\n", nbits, in, out);
} else if (nbits == 20) {
uint32_t in, out;
in = newdr[0] | ((uint32_t)newdr[1] << 8) | ((uint32_t)newdr[2] << 16);
out= olddr[0] | ((uint32_t)olddr[1] << 8) | ((uint32_t)olddr[2] << 16);
printc_dbg("mehfet: DRshift(nbits=%u): in: %05x, out: %05x\n", nbits, in, out);
} else if (nbits == 32) {
uint32_t in, out;
in = newdr[0] | ((uint32_t)newdr[1] << 8) | ((uint32_t)newdr[2] << 16) | ((uint32_t)newdr[3] << 24);
out= olddr[0] | ((uint32_t)olddr[1] << 8) | ((uint32_t)olddr[2] << 16) | ((uint32_t)olddr[3] << 24);
printc_dbg("mehfet: DRshift(nbits=%u): in: %08x, out: %08x\n", nbits, in, out);
} else {
printc_dbg("mehfet: DRshift(nbits=%u):\n", nbits);
debug_hexdump("\tin ", newdr, nbytes);
debug_hexdump("\tout", olddr, nbytes);
}
#endif
return 0;
}

108
drivers/mehfet_proto.h Normal file
View File

@ -0,0 +1,108 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2021 sys64738@disroot.org
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MEHFET_PROTO_H_
#define MEHFET_PROTO_H_
#include "transport.h"
#define MEHFET_PROTO_VER 0x0001
#define MEHFET_PROTO_VER_MIN_SUPPORTED 0x0001
enum mehfet_cmd {
mehfet_info = 0x01,
mehfet_status = 0x02,
mehfet_connect = 0x03,
mehfet_disconnect = 0x04,
mehfet_delay = 0x05,
mehfet_set_clkspeed = 0x06,
mehfet_get_old_lines = 0x07,
mehfet_tdio_seq = 0x08,
mehfet_tms_seq = 0x09,
mehfet_tclk_edge = 0x0a,
mehfet_tclk_burst = 0x0b,
mehfet_reset_tap = 0x0c,
mehfet_irshift = 0x0d,
mehfet_drshift = 0x0e,
};
enum mehfet_caps {
mehfet_cap_jtag_noentry = 1<<0,
mehfet_cap_jtag_entryseq = 1<<1,
mehfet_cap_sbw_entryseq = 1<<2,
mehfet_cap_has_reset_tap = 1<< 8,
mehfet_cap_has_irshift = 1<< 9,
mehfet_cap_has_drshift = 1<<10,
mehfet_cap_has_loop = 1<<11,
};
enum mehfet_conn {
mehfet_conn_none = 0,
mehfet_conn_auto = 0,
mehfet_conn_jtag_noentry = 1,
mehfet_conn_jtag_entryseq = 2,
mehfet_conn_sbw_entryseq = 3,
mehfet_conn_typemask = 0x7f,
mehfet_conn_nrstmask = 0x80
};
enum mehfet_lines {
mehfet_line_tclk = 1<<0,
mehfet_line_tms = 1<<1,
mehfet_line_tdi = 1<<2
};
enum mehfet_resettap_flags {
mehfet_rsttap_do_reset = 1<<0, // reset TAP to run-test/idle state
mehfet_rsttap_fuse_do = 1<<1, // perform fuse check procedure (TMS pulses) on target
mehfet_rsttap_fuse_read = 1<<2, // check whether the JTAG fuse has been blown
};
enum mehfet_resettap_status {
mehfet_rsttap_fuse_blown = 0x80
};
struct mehfet_info {
char* devicename;
enum mehfet_caps caps;
uint32_t packet_buf_size;
uint16_t proto_version;
};
int mehfet_cmd_info(transport_t t, struct mehfet_info* info);
int mehfet_cmd_status(transport_t t, enum mehfet_conn* stat);
int mehfet_cmd_connect(transport_t t, enum mehfet_conn conn);
int mehfet_cmd_disconnect(transport_t t);
int mehfet_cmd_delay(transport_t t, bool us, bool exact, uint32_t time);
int mehfet_cmd_set_clkspeed(transport_t t, bool fast);
int mehfet_cmd_get_old_lines(transport_t t, enum mehfet_lines* lines);
int mehfet_cmd_tdio_seq(transport_t t, uint32_t nbits, bool tms, const uint8_t* tdi, uint8_t* tdo);
int mehfet_cmd_tms_seq(transport_t t, uint32_t nbits, bool tdi, const uint8_t* tms);
int mehfet_cmd_tclk_edge(transport_t t, bool newtclk);
int mehfet_cmd_tclk_burst(transport_t t, uint32_t ncyc);
int mehfet_cmd_reset_tap(transport_t t, enum mehfet_resettap_flags flags, enum mehfet_resettap_status* stat);
int mehfet_cmd_irshift(transport_t t, uint8_t newir, uint8_t* oldir);
int mehfet_cmd_drshift(transport_t t, uint32_t nbits, const uint8_t* newdr, uint8_t* olddr);
#endif

View File

@ -35,293 +35,10 @@
#include "ctrlc.h"
struct pif_device {
struct device base;
struct jtdev jtag;
};
/*============================================================================*/
/* pif MSP430 JTAG operations */
/*----------------------------------------------------------------------------*/
/* Read a word-aligned block from any kind of memory
* returns the number of bytes read or -1 on failure
*/
static int read_words(device_t dev, const struct chipinfo_memory *m,
address_t addr, address_t len, uint8_t *data)
{
struct pif_device *pif = (struct pif_device *)dev;
struct jtdev *p = &pif->jtag;
unsigned int index;
unsigned int word;
for ( index = 0; index < len; index += 2 ) {
word = jtag_read_mem( p, 16, addr+index );
data[index] = word & 0x00ff;
data[index+1] = (word >> 8) & 0x00ff;
}
return p->failed ? -1 : len;
}
/*----------------------------------------------------------------------------*/
/* Write a word to RAM */
static int write_ram_word( struct jtdev *p, address_t addr,
uint16_t value )
{
jtag_write_mem( p, 16, addr, value );
return p->failed ? -1 : 0;
}
/*----------------------------------------------------------------------------*/
/* Write a word-aligned flash block. */
/* The starting address must be within the flash memory range. */
static int write_flash_block( struct jtdev *p, address_t addr,
address_t len,
const uint8_t *data)
{
unsigned int i;
uint16_t *word;
word = malloc( len / 2 * sizeof(*word) );
if (!word) {
pr_error("pif: failed to allocate memory");
return -1;
}
for(i = 0; i < len/2; i++) {
word[i]=data[2*i] + (((uint16_t)data[2*i+1]) << 8);
}
jtag_write_flash( p, addr, len/2, word );
free(word);
return p->failed ? -1 : 0;
}
/* Write a word-aligned block to any kind of memory.
* returns the number of bytes written or -1 on failure
*/
static int write_words(device_t dev, const struct chipinfo_memory *m,
address_t addr, address_t len, const uint8_t *data)
{
struct pif_device *pif = (struct pif_device *)dev;
struct jtdev *p = &pif->jtag;
int r;
if (m->type != CHIPINFO_MEMTYPE_FLASH) {
len = 2;
r = write_ram_word(p, addr, r16le(data));
} else {
r = write_flash_block(p, addr, len, data);
}
if (r < 0) {
printc_err("pif: write_words at address 0x%x failed\n", addr);
return -1;
}
return len;
}
/*----------------------------------------------------------------------------*/
static int init_device(struct jtdev *p)
{
unsigned int jtag_id;
printc_dbg("Starting JTAG\n");
jtag_id = jtag_init(p);
printc("JTAG ID: 0x%02x\n", jtag_id);
if (jtag_id != 0x89 && jtag_id != 0x91) {
printc_err("pif: unexpected JTAG ID: 0x%02x\n", jtag_id);
jtag_release_device(p, 0xfffe);
return -1;
}
return 0;
}
/*===== MSPDebug Device interface ============================================*/
/*----------------------------------------------------------------------------*/
static int refresh_bps(struct pif_device *dev)
{
int i;
int ret;
struct device_breakpoint *bp;
address_t addr;
ret = 0;
for (i = 0; i < dev->base.max_breakpoints; i++) {
bp = &dev->base.breakpoints[i];
printc_dbg("refresh breakpoint %d: type=%d "
"addr=%04x flags=%04x\n",
i, bp->type, bp->addr, bp->flags);
if ( (bp->flags & DEVICE_BP_DIRTY) &&
(bp->type == DEVICE_BPTYPE_BREAK) ) {
addr = bp->addr;
if ( !(bp->flags & DEVICE_BP_ENABLED) ) {
addr = 0;
}
if ( jtag_set_breakpoint (&dev->jtag, i, addr) == 0) {
printc_err("pif: failed to refresh "
"breakpoint #%d\n", i);
ret = -1;
} else {
bp->flags &= ~DEVICE_BP_DIRTY;
}
}
}
return ret;
}
/*----------------------------------------------------------------------------*/
static int pif_readmem( device_t dev_base,
address_t addr,
uint8_t* mem,
address_t len )
{
struct pif_device *dev = (struct pif_device *)dev_base;
dev->jtag.failed = 0;
return readmem(dev_base, addr, mem, len, read_words);
}
/*----------------------------------------------------------------------------*/
static int pif_writemem( device_t dev_base,
address_t addr,
const uint8_t* mem,
address_t len )
{
struct pif_device *dev = (struct pif_device *)dev_base;
dev->jtag.failed = 0;
return writemem(dev_base, addr, mem, len, write_words, read_words);
}
/*----------------------------------------------------------------------------*/
static int pif_getregs(device_t dev_base, address_t *regs)
{
struct pif_device *dev = (struct pif_device *)dev_base;
int i;
dev->jtag.failed = 0;
for (i = 0; i < DEVICE_NUM_REGS; i++)
regs[i] = jtag_read_reg(&dev->jtag, i);
return dev->jtag.failed ? -1 : 0;
}
/*----------------------------------------------------------------------------*/
static int pif_setregs( device_t dev_base, const address_t* regs )
{
struct pif_device *dev = (struct pif_device *)dev_base;
int i;
dev->jtag.failed = 0;
for (i = 0; i < DEVICE_NUM_REGS; i++) {
jtag_write_reg( &dev->jtag, i, regs[i] );
}
return dev->jtag.failed ? -1 : 0;
}
/*----------------------------------------------------------------------------*/
static int pif_ctl(device_t dev_base, device_ctl_t type)
{
struct pif_device *dev = (struct pif_device *)dev_base;
dev->jtag.failed = 0;
switch (type) {
case DEVICE_CTL_RESET:
/* perform soft reset */
jtag_execute_puc(&dev->jtag);
break;
case DEVICE_CTL_RUN:
/* transfer changed breakpoints to device */
if (refresh_bps(dev) < 0) {
return -1;
}
/* start program execution at current PC */
jtag_release_device(&dev->jtag, 0xffff);
break;
case DEVICE_CTL_HALT:
/* take device under JTAG control */
jtag_get_device(&dev->jtag);
break;
case DEVICE_CTL_STEP:
/* execute next instruction at current PC */
jtag_single_step(&dev->jtag);
break;
default:
printc_err("pif: unsupported operation\n");
return -1;
}
return dev->jtag.failed ? -1 : 0;
}
/*----------------------------------------------------------------------------*/
static device_status_t pif_poll(device_t dev_base)
{
struct pif_device *dev = (struct pif_device *)dev_base;
if (delay_ms(100) < 0 || ctrlc_check())
return DEVICE_STATUS_INTR;
if (jtag_cpu_state(&dev->jtag) == 1) {
return DEVICE_STATUS_HALTED;
}
return DEVICE_STATUS_RUNNING;
}
/*----------------------------------------------------------------------------*/
static int pif_erase( device_t dev_base,
device_erase_type_t type,
address_t addr )
{
struct pif_device *dev = (struct pif_device *)dev_base;
dev->jtag.failed = 0;
switch(type) {
case DEVICE_ERASE_MAIN:
jtag_erase_flash ( &dev->jtag, JTAG_ERASE_MAIN, addr );
break;
case DEVICE_ERASE_ALL:
jtag_erase_flash ( &dev->jtag, JTAG_ERASE_MASS, addr );
break;
case DEVICE_ERASE_SEGMENT:
jtag_erase_flash ( &dev->jtag, JTAG_ERASE_SGMT, addr );
break;
default:
return -1;
}
return dev->jtag.failed ? -1 : 0;
}
/*----------------------------------------------------------------------------*/
static int pif_getconfigfuses(device_t dev_base)
{
struct pif_device *dev = (struct pif_device *)dev_base;
return jtag_get_config_fuses(&dev->jtag);
}
/*----------------------------------------------------------------------------*/
static device_t pif_open(const struct device_args *args)
{
@ -344,9 +61,9 @@ static device_t pif_open(const struct device_args *args)
}
memset(dev, 0, sizeof(*dev));
dev->base.type = &device_pif;
dev->base.max_breakpoints = 2; //supported by all devices
dev->base.need_probe = 1;
dev->jtag.base.type = &device_pif;
dev->jtag.base.max_breakpoints = 2; //supported by all devices
dev->jtag.base.need_probe = 1;
(&dev->jtag)->f = &jtdev_func_pif;
if ((&dev->jtag)->f->jtdev_open(&dev->jtag, args->path) < 0) {
@ -355,13 +72,13 @@ static device_t pif_open(const struct device_args *args)
return NULL;
}
if (init_device(&dev->jtag) < 0) {
if (jtag_dev_init(&dev->jtag) < 0) {
printc_err("pif: initialization failed\n");
free(dev);
return NULL;
}
return &dev->base;
return &dev->jtag.base;
}
/*----------------------------------------------------------------------------*/
@ -388,8 +105,8 @@ static device_t gpio_open(const struct device_args *args)
}
memset(dev, 0, sizeof(*dev));
dev->base.type = &device_pif;
dev->base.max_breakpoints = 0;
dev->jtag.base.type = &device_pif;
dev->jtag.base.max_breakpoints = 0;
(&dev->jtag)->f = &jtdev_func_gpio;
if ((&dev->jtag)->f->jtdev_open(&dev->jtag, args->path) < 0) {
@ -398,13 +115,13 @@ static device_t gpio_open(const struct device_args *args)
return NULL;
}
if (init_device(&dev->jtag) < 0) {
if (jtag_dev_init(&dev->jtag) < 0) {
printc_err("gpio: initialization failed\n");
free(dev);
return NULL;
}
return &dev->base;
return &dev->jtag.base;
}
/*----------------------------------------------------------------------------*/
@ -431,9 +148,9 @@ static device_t bp_open(const struct device_args *args)
}
memset(dev, 0, sizeof(*dev));
dev->base.type = &device_pif;
dev->base.max_breakpoints = 2; //supported by all devices
dev->base.need_probe = 1;
dev->jtag.base.type = &device_pif;
dev->jtag.base.max_breakpoints = 2; //supported by all devices
dev->jtag.base.need_probe = 1;
(&dev->jtag)->f = &jtdev_func_bp;
if ((&dev->jtag)->f->jtdev_open(&dev->jtag, args->path) < 0) {
@ -442,13 +159,13 @@ static device_t bp_open(const struct device_args *args)
return NULL;
}
if (init_device(&dev->jtag) < 0) {
if (jtag_dev_init(&dev->jtag) < 0) {
printc_err("bp: initialization failed\n");
free(dev);
return NULL;
}
return &dev->base;
return &dev->jtag.base;
}
/*----------------------------------------------------------------------------*/
@ -469,14 +186,14 @@ const struct device_class device_pif = {
.help = "Parallel Port JTAG",
.open = pif_open,
.destroy = pif_destroy,
.readmem = pif_readmem,
.writemem = pif_writemem,
.getregs = pif_getregs,
.setregs = pif_setregs,
.ctl = pif_ctl,
.poll = pif_poll,
.erase = pif_erase,
.getconfigfuses = pif_getconfigfuses
.readmem = jtag_dev_readmem,
.writemem = jtag_dev_writemem,
.getregs = jtag_dev_getregs,
.setregs = jtag_dev_setregs,
.ctl = jtag_dev_ctl,
.poll = jtag_dev_poll,
.erase = jtag_dev_erase,
.getconfigfuses = jtag_dev_getconfigfuses
};
const struct device_class device_gpio = {
@ -484,14 +201,14 @@ const struct device_class device_gpio = {
.help = "/sys/class/gpio direct connect",
.open = gpio_open,
.destroy = pif_destroy,
.readmem = pif_readmem,
.writemem = pif_writemem,
.getregs = pif_getregs,
.setregs = pif_setregs,
.ctl = pif_ctl,
.poll = pif_poll,
.erase = pif_erase,
.getconfigfuses = pif_getconfigfuses
.readmem = jtag_dev_readmem,
.writemem = jtag_dev_writemem,
.getregs = jtag_dev_getregs,
.setregs = jtag_dev_setregs,
.ctl = jtag_dev_ctl,
.poll = jtag_dev_poll,
.erase = jtag_dev_erase,
.getconfigfuses = jtag_dev_getconfigfuses
};
const struct device_class device_bp = {
@ -499,12 +216,12 @@ const struct device_class device_bp = {
.help = "Bus Pirate JTAG, MISO-TDO, MOSI-TDI, CS-TMS, AUX-RESET, CLK-TCK",
.open = bp_open,
.destroy = pif_destroy,
.readmem = pif_readmem,
.writemem = pif_writemem,
.getregs = pif_getregs,
.setregs = pif_setregs,
.ctl = pif_ctl,
.poll = pif_poll,
.erase = pif_erase,
.getconfigfuses = pif_getconfigfuses
.readmem = jtag_dev_readmem,
.writemem = jtag_dev_writemem,
.getregs = jtag_dev_getregs,
.setregs = jtag_dev_setregs,
.ctl = jtag_dev_ctl,
.poll = jtag_dev_poll,
.erase = jtag_dev_erase,
.getconfigfuses = jtag_dev_getconfigfuses
};

View File

@ -16,6 +16,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdbool.h>
#include <string.h>
#include "bytes.h"
#include "v3hil.h"
@ -23,6 +24,12 @@
#include "output.h"
#include "opdb.h"
#ifdef DEBUG_V3HIL
#define dbg_printc(fmt, ...) printc_dbg("v3hil: %s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__)
#else
#define dbg_printc(fmt, ...) do{}while(0)
#endif
/* HAL function IDs */
typedef enum {
HAL_PROTO_FID_INIT = 0x01,
@ -41,73 +48,99 @@ typedef enum {
HAL_PROTO_FID_SET_CHAIN_CONFIGURATION = 0x0e,
HAL_PROTO_FID_GET_NUM_DEVICES = 0x0f,
HAL_PROTO_FID_GET_INTERFACE_MODE = 0x10,
HAL_PROTO_FID_SJ_ASSERT_POR_SC = 0x11,
HAL_PROTO_FID_SJ_CONDITIONAL_SC = 0x12,
HAL_PROTO_FID_RC_RELEASE_JTAG = 0x13,
HAL_PROTO_FID_READ_MEM_BYTES = 0x14,
HAL_PROTO_FID_READ_MEM_WORDS = 0x15,
HAL_PROTO_FID_READ_MEM_QUICK = 0x16,
HAL_PROTO_FID_WRITE_MEM_BYTES = 0x17,
HAL_PROTO_FID_WRITE_MEM_WORDS = 0x18,
HAL_PROTO_FID_EEM_DX = 0x19,
HAL_PROTO_FID_EEM_DX_AFE2XX = 0x1a,
HAL_PROTO_FID_SINGLE_STEP = 0x1b,
HAL_PROTO_FID_READ_ALL_CPU_REGS = 0x1c,
HAL_PROTO_FID_WRITE_ALL_CPU_REGS = 0x1d,
HAL_PROTO_FID_PSA = 0x1e,
HAL_PROTO_FID_EXECUTE_FUNCLET = 0x1f,
HAL_PROTO_FID_EXECUTE_FUNCLET_JTAG = 0x20,
HAL_PROTO_FID_GET_DCO_FREQUENCY = 0x21,
HAL_PROTO_FID_GET_DCO_FREQUENCY_JTAG = 0x22,
HAL_PROTO_FID_GET_FLL_FREQUENCY = 0x23,
HAL_PROTO_FID_GET_FLL_FREQUENCY_JTAG = 0x24,
HAL_PROTO_FID_WAIT_FOR_STORAGE = 0x25,
HAL_PROTO_FID_SJ_ASSERT_POR_SC_X = 0x26,
HAL_PROTO_FID_SJ_CONDITIONAL_SC_X = 0x27,
HAL_PROTO_FID_RC_RELEASE_JTAG_X = 0x28,
HAL_PROTO_FID_READ_MEM_BYTES_X = 0x29,
HAL_PROTO_FID_READ_MEM_WORDS_X = 0x2a,
HAL_PROTO_FID_READ_MEM_QUICK_X = 0x2b,
HAL_PROTO_FID_WRITE_MEM_BYTES_X = 0x2c,
HAL_PROTO_FID_WRITE_MEM_WORDS_X = 0x2d,
HAL_PROTO_FID_EEM_DX_X = 0x2e,
HAL_PROTO_FID_SINGLE_STEP_X = 0x2f,
HAL_PROTO_FID_READ_ALL_CPU_REGS_X = 0x30,
HAL_PROTO_FID_WRITE_ALL_CPU_REGS_X = 0x31,
HAL_PROTO_FID_PSA_X = 0x32,
HAL_PROTO_FID_EXECUTE_FUNCLET_X = 0x33,
HAL_PROTO_FID_GET_DCO_FREQUENCY_X = 0x34,
HAL_PROTO_FID_GET_FLL_FREQUENCY_X = 0x35,
HAL_PROTO_FID_WAIT_FOR_STORAGE_X = 0x36,
HAL_PROTO_FID_BLOW_FUSE_XV2 = 0x37,
HAL_PROTO_FID_BLOW_FUSE_FRAM = 0x38,
HAL_PROTO_FID_SJ_ASSERT_POR_SC_XV2 = 0x39,
HAL_PROTO_FID_SJ_CONDITIONAL_SC_XV2 = 0x3a,
HAL_PROTO_FID_RC_RELEASE_JTAG_XV2 = 0x3b,
HAL_PROTO_FID_READ_MEM_WORDS_XV2 = 0x3c,
HAL_PROTO_FID_READ_MEM_QUICK_XV2 = 0x3d,
HAL_PROTO_FID_WRITE_MEM_WORDS_XV2 = 0x3e,
HAL_PROTO_FID_EEM_DX_XV2 = 0x3f,
HAL_PROTO_FID_SINGLE_STEP_XV2 = 0x40,
HAL_PROTO_FID_READ_ALL_CPU_REGS_XV2 = 0x41,
HAL_PROTO_FID_WRITE_ALL_CPU_REGS_XV2 = 0x42,
HAL_PROTO_FID_PSA_XV2 = 0x43,
HAL_PROTO_FID_EXECUTE_FUNCLET_XV2 = 0x44,
HAL_PROTO_FID_UNLOCK_DEVICE_XV2 = 0x45,
HAL_PROTO_FID_MAGIC_PATTERN = 0x46,
HAL_PROTO_FID_UNLOCK_C092 = 0x47,
HAL_PROTO_FID_HIL_COMMAND = 0x48,
HAL_PROTO_FID_POLL_JSTATE_REG = 0x49,
HAL_PROTO_FID_POLL_JSTATE_REG_FR57XX = 0x4a,
HAL_PROTO_FID_IS_JTAG_FUSE_BLOWN = 0x4b,
HAL_PROTO_FID_RESET_XV2 = 0x4c,
HAL_PROTO_FID_WRITE_FRAM_QUICK_XV2 = 0x4d,
HAL_PROTO_FID_SEND_JTAG_MAILBOX_XV2 = 0x4e,
HAL_PROTO_FID_SINGLE_STEP_JSTATE_XV2 = 0x4f,
HAL_PROTO_FID_POLL_JSTATE_REG_ET8 = 0x50,
HAL_PROTO_FID_RESET_STATIC_GLOBAL_VARS = 0x51,
HAL_PROTO_FID_RESET_430I = 0x52,
HAL_PROTO_FID_POLL_JSTATE_REG_430I = 0x53
HAL_PROTO_FID_GET_DEVICE_ID_PTR = 0x11,
HAL_PROTO_FID_SJ_ASSERT_POR_SC ,
HAL_PROTO_FID_SJ_CONDITIONAL_SC ,
HAL_PROTO_FID_RC_RELEASE_JTAG ,
HAL_PROTO_FID_READ_MEM_BYTES ,
HAL_PROTO_FID_READ_MEM_WORDS ,
HAL_PROTO_FID_READ_MEM_QUICK ,
HAL_PROTO_FID_WRITE_MEM_BYTES ,
HAL_PROTO_FID_WRITE_MEM_WORDS ,
HAL_PROTO_FID_EEM_DX ,
HAL_PROTO_FID_EEM_DX_AFE2XX ,
HAL_PROTO_FID_SINGLE_STEP ,
HAL_PROTO_FID_READ_ALL_CPU_REGS ,
HAL_PROTO_FID_WRITE_ALL_CPU_REGS ,
HAL_PROTO_FID_PSA ,
HAL_PROTO_FID_EXECUTE_FUNCLET , /* 0x20 */
HAL_PROTO_FID_EXECUTE_FUNCLET_JTAG ,
HAL_PROTO_FID_GET_DCO_FREQUENCY ,
HAL_PROTO_FID_GET_DCO_FREQUENCY_JTAG ,
HAL_PROTO_FID_GET_FLL_FREQUENCY ,
HAL_PROTO_FID_GET_FLL_FREQUENCY_JTAG ,
HAL_PROTO_FID_WAIT_FOR_STORAGE ,
HAL_PROTO_FID_SJ_ASSERT_POR_SC_X ,
HAL_PROTO_FID_SJ_CONDITIONAL_SC_X ,
HAL_PROTO_FID_RC_RELEASE_JTAG_X ,
HAL_PROTO_FID_READ_MEM_BYTES_X ,
HAL_PROTO_FID_READ_MEM_WORDS_X ,
HAL_PROTO_FID_READ_MEM_QUICK_X ,
HAL_PROTO_FID_WRITE_MEM_BYTES_X ,
HAL_PROTO_FID_WRITE_MEM_WORDS_X ,
HAL_PROTO_FID_EEM_DX_X ,
HAL_PROTO_FID_SINGLE_STEP_X ,
HAL_PROTO_FID_READ_ALL_CPU_REGS_X ,
HAL_PROTO_FID_WRITE_ALL_CPU_REGS_X , /* 0x30 */
HAL_PROTO_FID_PSA_X ,
HAL_PROTO_FID_EXECUTE_FUNCLET_X ,
HAL_PROTO_FID_GET_DCO_FREQUENCY_X ,
HAL_PROTO_FID_GET_FLL_FREQUENCY_X ,
HAL_PROTO_FID_WAIT_FOR_STORAGE_X ,
HAL_PROTO_FID_BLOW_FUSE_XV2 ,
HAL_PROTO_FID_BLOW_FUSE_FRAM ,
HAL_PROTO_FID_SJ_ASSERT_POR_SC_XV2 ,
HAL_PROTO_FID_SJ_CONDITIONAL_SC_XV2 ,
HAL_PROTO_FID_RC_RELEASE_JTAG_XV2 ,
HAL_PROTO_FID_READ_MEM_WORDS_XV2 ,
HAL_PROTO_FID_READ_MEM_QUICK_XV2 ,
HAL_PROTO_FID_WRITE_MEM_WORDS_XV2 ,
HAL_PROTO_FID_EEM_DX_XV2 ,
HAL_PROTO_FID_SINGLE_STEP_XV2 , /* 0x40 */
HAL_PROTO_FID_READ_ALL_CPU_REGS_XV2 ,
HAL_PROTO_FID_WRITE_ALL_CPU_REGS_XV2 ,
HAL_PROTO_FID_PSA_XV2 ,
HAL_PROTO_FID_EXECUTE_FUNCLET_XV2 ,
HAL_PROTO_FID_UNLOCK_DEVICE_XV2 ,
HAL_PROTO_FID_MAGIC_PATTERN ,
HAL_PROTO_FID_UNLOCK_C092 ,
HAL_PROTO_FID_HIL_COMMAND ,
HAL_PROTO_FID_POLL_JSTATE_REG ,
HAL_PROTO_FID_POLL_JSTATE_REG_FR57XX ,
HAL_PROTO_FID_IS_JTAG_FUSE_BLOWN ,
HAL_PROTO_FID_RESET_XV2 ,
HAL_PROTO_FID_WRITE_FRAM_QUICK_XV2 ,
HAL_PROTO_FID_SEND_JTAG_MAILBOX_XV2 ,
HAL_PROTO_FID_SINGLE_STEP_JSTATE_XV2 ,
HAL_PROTO_FID_POLL_JSTATE_REG_ET8 ,
HAL_PROTO_FID_RESET_STATIC_GLOBAL_VARS , /* 0x50 */
HAL_PROTO_FID_RESET_430I ,
HAL_PROTO_FID_POLL_JSTATE_REG_430I ,
HAL_PROTO_FID_POLL_JSTATE_REG_20 ,
HAL_PROTO_FID_SWITCH_MOSFET ,
HAL_PROTO_FID_RESET_L092 ,
HAL_PROTO_FID_DUMMY_MACRO ,
HAL_PROTO_FID_RESET_5438XV2 ,
HAL_PROTO_FID_LEA_SYNC_COND ,
HAL_PROTO_FID_GET_JTAG_ID_CODE_ARM ,
HAL_PROTO_FID_SCAN_AP_ARM ,
HAL_PROTO_FID_MEM_AP_TRANSACTION_ARM ,
HAL_PROTO_FID_READ_ALL_CPU_REGS_ARM ,
HAL_PROTO_FID_WRITE_ALL_CPU_REGS_ARM ,
HAL_PROTO_FID_ENABLE_DEBUG_ARM ,
HAL_PROTO_FID_DISABLE_DEBUG_ARM ,
HAL_PROTO_FID_RUN_ARM , /* 0x60 */
HAL_PROTO_FID_HALT_ARM ,
HAL_PROTO_FID_RESET_ARM ,
HAL_PROTO_FID_SINGLE_STEP_ARM ,
HAL_PROTO_FID_WAIT_FOR_DEBUG_HALT_ARM ,
HAL_PROTO_FID_MEM_AP_TRANSACTION_ARM_SWD,
HAL_PROTO_FID_GET_ITF_MODE_ARM ,
HAL_PROTO_FID_POLL_DSTATE_PCREG_ET ,
HAL_PROTO_FID_GET_CPU_ID_ARM ,
HAL_PROTO_FID_CHECK_DAP_LOCK_ARM ,
HAL_PROTO_FID_UNLOCK_DAP ,
HAL_PROTO_FID_USS_SYNC_COND , /* 0x6b */
} hal_proto_fid_t;
/* Argument types for HAL_PROTO_FID_CONFIGURE */
@ -126,14 +159,41 @@ typedef enum {
HAL_PROTO_CONFIG_SFLLDEH = 0x0c,
HAL_PROTO_CONFIG_NO_BSL = 0x0d,
HAL_PROTO_CONFIG_ALT_ROM_ADDR_FOR_CPU_READ = 0x0e,
HAL_PROTO_CONFIG_ASSERT_BSL_VALID_BIT = 0x0f
HAL_PROTO_CONFIG_ASSERT_BSL_VALID_BIT = 0x0f,
HAL_PROTO_CONFIG_POWER_TESTREG_DEFAULT = 0x10,
HAL_PROTO_CONFIG_POWER_TESTREGV3_DEFAULT = 0x11,
HAL_PROTO_CONFIG_WDT_ADDRESS_5XX = 0x12,
HAL_PROTO_CONFIG_SCS_BASE_ADDRESS = 0x13,
HAL_PROTO_CONFIG_FPB_BASE_ADDRESS = 0x14,
HAL_PROTO_CONFIG_INTERRUPT_OPTIONS = 0x15,
HAL_PROTO_CONFIG_ULP_MSP432 = 0x16,
HAL_PROTO_CONFIG_JTAG_LOCK_5XX = 0x17,
} hal_proto_config_t;
static hal_proto_fid_t map_ver(const struct v3hil *h, hal_proto_fid_t src)
{
hal_proto_fid_t dst;
if (h->proto_ver < 0x0300 && src > HAL_PROTO_FID_GET_DEVICE_ID_PTR) {
dst = src - 1;
} else {
dst = src;
}
dbg_printc("map ver: %02x -> %02x\n", src, dst);
return dst;
}
static hal_proto_fid_t map_fid(const struct v3hil *h, hal_proto_fid_t src)
{
hal_proto_fid_t dst = h->chip->v3_functions[src];
return dst ? dst : src;
if (dst == 0) {
dst = src;
}
dbg_printc("map fid: %02x -> %02x\n", src, dst);
return map_ver(h, dst);
}
void v3hil_init(struct v3hil *h, transport_t trans,
@ -148,7 +208,8 @@ int v3hil_set_vcc(struct v3hil *h, int vcc_mv)
uint8_t data[2];
w16le(data, vcc_mv);
return hal_proto_execute(&h->hal, HAL_PROTO_FID_SET_VCC, data, 2);
dbg_printc("Setting VCC...\n");
return hal_proto_execute(&h->hal, map_ver(h, HAL_PROTO_FID_SET_VCC), data, 2);
}
int v3hil_comm_init(struct v3hil *h)
@ -163,6 +224,43 @@ int v3hil_comm_init(struct v3hil *h)
return -1;
if (h->hal.length < 8) {
printc_err("warning: v3hil: short reply to version request\n");
} else if (h->hal.length == 40) {
#ifdef DEBUG_V3HIL
printc_dbg("v3hil: Version:");
for (int i = 0; i < h->hal.length; i++)
printc_dbg(" %02x", h->hal.payload[i]);
printc_dbg("\n");
#endif
const uint16_t sw_version = r32le(h->hal.payload + 0);
const uint16_t sw_build = r32le(h->hal.payload + 2);
const uint32_t hw_thing = r32le(h->hal.payload + 4);
const uint32_t tool_id = r16le(h->hal.payload + 8);
const uint16_t core_version = r16le(h->hal.payload + 10);
const uint16_t hil_version = r16le(h->hal.payload + 12);
const uint16_t dcdc_layer_version = r16le(h->hal.payload + 14);
const uint16_t dcdc_mcu_version = r16le(h->hal.payload + 16);
const uint16_t com_version = r16le(h->hal.payload + 18);
const uint16_t hil_crc = r16le(h->hal.payload + 20);
const uint16_t hal_crc = r16le(h->hal.payload + 22);
const uint16_t dcdc_crc = r16le(h->hal.payload + 24);
const uint16_t core_crc = r16le(h->hal.payload + 26);
const uint16_t com_crc = r16le(h->hal.payload + 28);
const uint16_t fpga_version = r16le(h->hal.payload + 30);
const uint16_t n_rx_queues = r16le(h->hal.payload + 32);
const uint16_t rx_queue_size = r16le(h->hal.payload + 34);
const uint8_t major = (sw_version >> 14) + 1;
const uint8_t minor = (sw_version >> 8) & 0x3f;
const uint8_t patch = sw_version & 0xff;
const uint8_t build = sw_build;
printc_dbg("Version: %d.%d.%d.%d Core version: 0x%02x, HIL version: 0x%02x, HW: 0x%04x\n",
major, minor, patch, build,
core_version, hil_version, hw_thing);
h->proto_ver = (major << 8) | minor;
} else {
const uint8_t major = h->hal.payload[1] >> 6;
const uint8_t minor = h->hal.payload[1] & 0x3f;
@ -172,11 +270,13 @@ int v3hil_comm_init(struct v3hil *h)
printc_dbg("Version: %d.%d.%d.%d, HW: 0x%04x\n",
major, minor, patch, flavour,
r32le(h->hal.payload + 4));
h->proto_ver = (major << 8) | minor;
}
printc_dbg("Reset firmware...\n");
if (hal_proto_execute(&h->hal,
HAL_PROTO_FID_RESET_STATIC_GLOBAL_VARS, NULL, 0) < 0)
map_ver(h, HAL_PROTO_FID_RESET_STATIC_GLOBAL_VARS), NULL, 0) < 0)
return -1;
return 0;
@ -187,7 +287,8 @@ int v3hil_start_jtag(struct v3hil *h, v3hil_jtag_type_t type)
uint8_t data = type;
uint8_t chain_id[2] = {0, 0};
if (hal_proto_execute(&h->hal, HAL_PROTO_FID_START_JTAG,
dbg_printc("Start JTAG...\n");
if (hal_proto_execute(&h->hal, map_ver(h, HAL_PROTO_FID_START_JTAG),
&data, 1) < 0)
return -1;
@ -202,18 +303,30 @@ int v3hil_start_jtag(struct v3hil *h, v3hil_jtag_type_t type)
}
printc_dbg("Device count: %d\n", h->hal.payload[0]);
return hal_proto_execute(&h->hal, HAL_PROTO_FID_SET_DEVICE_CHAIN_INFO,
chain_id, 2);
return hal_proto_execute(&h->hal,
map_ver(h, HAL_PROTO_FID_SET_DEVICE_CHAIN_INFO), chain_id, 2);
}
int v3hil_stop_jtag(struct v3hil *h)
{
return hal_proto_execute(&h->hal, HAL_PROTO_FID_STOP_JTAG, NULL, 0);
dbg_printc("Stop JTAG...\n");
if (hal_proto_execute(&h->hal, map_ver(h, HAL_PROTO_FID_STOP_JTAG), NULL, 0) < 0)
return -1;
dbg_printc("Reset communications...\n");
h->hal.ref_id = 0;
if (hal_proto_send(&h->hal, HAL_PROTO_TYPE_EXCEPTION, NULL, 0) < 0) {
h->hal.ref_id = 0;
return -1;
}
h->hal.ref_id = 0;
return 0;
}
int v3hil_sync(struct v3hil *h)
{
uint8_t data[32];
uint8_t data[32], datalen = 21;
h->cal.is_cal = 0;
@ -228,8 +341,21 @@ int v3hil_sync(struct v3hil *h)
if (h->chip) {
int i;
for (i = 0; i < 16; i++)
data[i + 20 - i] = h->chip->clock_map[i].value;
for (i = 0; i < 16; i++) {
dbg_printc("clock map %d = %02x -> %d\n",
i, h->chip->clock_map[i].value, 20-i);
data[16 + 4 - i] = h->chip->clock_map[i].value;
}
if (h->proto_ver >= 0x0308) {
datalen = 21+16;
for (i = 16; i < 32; i++) {
dbg_printc("clock map2 %d = %02x -> %d\n",
i, h->chip->clock_map[i].value, 16+4+16*2 - i);
data[16+4+16*2 - i] = h->chip->clock_map[i].value;
}
}
} else {
data[5] = 1;
data[15] = 40;
@ -238,12 +364,36 @@ int v3hil_sync(struct v3hil *h)
/* We can't use map_fid() because h->chip might be NULL -- this
* function will be called before identification is complete.
*/
if (hal_proto_execute(&h->hal,
(h->jtag_id == 0x89)
hal_proto_fid_t cmdid = (h->jtag_id == 0x89/*0x90*/)
? HAL_PROTO_FID_SJ_ASSERT_POR_SC
: HAL_PROTO_FID_SJ_ASSERT_POR_SC_XV2,
data, 21) < 0)
: HAL_PROTO_FID_SJ_ASSERT_POR_SC_XV2;
dbg_printc("Sync: assert POR\n");
if (h->chip) {
if (hal_proto_execute(&h->hal, map_fid(h, cmdid), data, datalen) < 0) {
return -1;
}
} else {
/* Need to do something for X/Xv2 devices, so try each in turn... */
cmdid = map_ver(h, cmdid);
if (hal_proto_execute(&h->hal, cmdid, data, datalen) < 0) {
cmdid = map_ver(h, HAL_PROTO_FID_SJ_ASSERT_POR_SC_X);
if (hal_proto_execute(&h->hal, cmdid, data, datalen) < 0) {
cmdid = map_ver(h, HAL_PROTO_FID_SJ_ASSERT_POR_SC_XV2);
if (hal_proto_execute(&h->hal, cmdid, data, datalen) < 0) {
return -1;
}
}
}
}
#ifdef DEBUG_V3HIL
printc_dbg("v3hil: POR result: (len %d) ", h->hal.length);
for (int i = 0; i < h->hal.length; ++i) {
printc_dbg("%02x%s", h->hal.payload[i],
(i == h->hal.length - 1) ? "\n" : " ");
}
#endif
if (h->hal.length < 8) {
printc_err("v3hil: short reply: %d\n", h->hal.length);
@ -274,6 +424,7 @@ int v3hil_read(struct v3hil *h, address_t addr,
w32le(req + 4, (m->bits == 8) ? size : (size >> 1));
w32le(req + 8, h->regs[MSP430_REG_PC]);
dbg_printc("do read\n");
if (hal_proto_execute(&h->hal,
map_fid(h, (m->bits == 8) ? HAL_PROTO_FID_READ_MEM_BYTES :
HAL_PROTO_FID_READ_MEM_WORDS),
@ -332,6 +483,7 @@ static int calibrate_dco(struct v3hil *h, uint8_t max_bcs)
w16le(data, ram->offset);
w16le(data + 2, max_bcs);
dbg_printc("calibrate dco: get freq\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_GET_DCO_FREQUENCY),
data, 6) < 0)
@ -350,6 +502,7 @@ static int calibrate_dco(struct v3hil *h, uint8_t max_bcs)
mem_write[9] = data[2]; /* BCS1 */
mem_write[10] = data[4]; /* BCS2 */
mem_write[11] = 0; /* pad */
dbg_printc("calibrate dco: write\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_WRITE_MEM_BYTES),
mem_write, 12) < 0) {
@ -378,6 +531,7 @@ static int calibrate_fll(struct v3hil *h)
w16le(data, ram->offset);
w16le(data + 2, 0);
dbg_printc("calibrate fll: get dco freq\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_GET_DCO_FREQUENCY),
data, 10) < 0)
@ -399,6 +553,7 @@ static int calibrate_fll(struct v3hil *h)
mem_write[12] = data[8]; /* FLLCTL1 */
mem_write[13] = 0; /* pad */
dbg_printc("calibrate fll: write\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_WRITE_MEM_BYTES),
mem_write, 14) < 0) {
@ -470,6 +625,7 @@ static int upload_funclet(struct v3hil *h,
for (i = 0; i < n; i++)
w16le(data + 8 + i * 2, code[i]);
dbg_printc("upload funclet: %d\n", n);
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_WRITE_MEM_WORDS),
data, n * 2 + 8) < 0) {
@ -503,8 +659,10 @@ static int write_flash(struct v3hil *h, address_t addr,
return -1;
}
dbg_printc("write flash: calibrate\n");
if (calibrate(h) < 0)
return -1;
dbg_printc("write flash: upload funclet\n");
if (upload_funclet(h, ram, f) < 0)
return -1;
@ -529,6 +687,7 @@ static int write_flash(struct v3hil *h, address_t addr,
w16le(data + 20, h->cal.cal1);
memcpy(data + 22, mem, size);
dbg_printc("exec write flash funclet\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_EXECUTE_FUNCLET),
data, size + 22) < 0) {
@ -544,16 +703,24 @@ static int write_ram(struct v3hil *h, const struct chipinfo_memory *m,
address_t addr, const uint8_t *mem, address_t size)
{
uint8_t data[256];
bool fram = false;
if (h->chip->features & CHIPINFO_FEATURE_FRAM) {
if (!strcmp(m->name, "Main") || !strcmp(m->name, "Info")) {
dbg_printc("write ram: to FRAM!\n");
fram = true;
}
}
w32le(data, addr);
w32le(data + 4, (m->bits == 8) ? size : (size >> 1));
w32le(data + 4, (m->bits == 8 || fram) ? size : (size >> 1));
memcpy(data + 8, mem, size);
if (hal_proto_execute(&h->hal,
map_fid(h, (m->bits == 8) ? HAL_PROTO_FID_WRITE_MEM_BYTES
: HAL_PROTO_FID_WRITE_MEM_WORDS),
data, size + 8) < 0) {
dbg_printc("write ram\n");
hal_proto_fid_t fid = (m->bits == 8) ? HAL_PROTO_FID_WRITE_MEM_BYTES
: HAL_PROTO_FID_WRITE_MEM_WORDS;
if (fram) fid = HAL_PROTO_FID_WRITE_FRAM_QUICK_XV2;
if (hal_proto_execute(&h->hal, map_fid(h, fid), data, size + 8) < 0) {
printc_err("v3hil: failed writing %d bytes to 0x%05x\n",
size, addr);
return -1;
@ -576,9 +743,12 @@ int v3hil_write(struct v3hil *h, address_t addr,
if (size > 128)
size = 128;
if (m->type == CHIPINFO_MEMTYPE_FLASH)
if (m->type == CHIPINFO_MEMTYPE_FLASH) {
dbg_printc("write: call write flash\n");
return write_flash(h, addr, mem, size);
}
dbg_printc("write: call write ram\n");
return write_ram(h, m, addr, mem, size);
}
@ -603,6 +773,7 @@ static int call_erase(struct v3hil *h,
w16le(data + 20, h->cal.cal1);
w32le(data + 22, 0xdeadbeef);
dbg_printc("erase: call funclet\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_EXECUTE_FUNCLET),
data, 26) < 0) {
@ -636,8 +807,10 @@ int v3hil_erase(struct v3hil *h, address_t segment)
if (!flash)
printc_err("v3hil: can't find appropriate flash region\n");
dbg_printc("erase: calibrate\n");
if (calibrate(h) < 0)
return -1;
dbg_printc("erase: upload funclet\n");
if (upload_funclet(h, ram, f) < 0)
return -1;
@ -648,10 +821,13 @@ int v3hil_erase(struct v3hil *h, address_t segment)
if (flash->banks)
bank_size /= flash->banks;
for (i = flash->banks; i >= 0; i--)
for (i = flash->banks; i >= 0; i--) {
dbg_printc("Erase bank %d\n", i);
if (call_erase(h, ram, f,
flash->offset + i * bank_size - 2, 0xa502) < 0)
return -1;
}
} else {
segment &= ~(flash->seg_size - 1);
segment |= flash->seg_size - 2;
@ -665,12 +841,15 @@ int v3hil_erase(struct v3hil *h, address_t segment)
int v3hil_update_regs(struct v3hil *h)
{
const hal_proto_fid_t fid =
map_fid(h, HAL_PROTO_FID_READ_ALL_CPU_REGS);
const int reg_size = (fid == HAL_PROTO_FID_READ_ALL_CPU_REGS) ? 2 : 3;
const hal_proto_fid_t fid = map_fid(h, HAL_PROTO_FID_READ_ALL_CPU_REGS);
const int reg_size = (fid == HAL_PROTO_FID_READ_ALL_CPU_REGS
|| fid == HAL_PROTO_FID_READ_ALL_CPU_REGS - 1)
? 2 : 3;
int i;
int sptr = 0;
dbg_printc("Read regs\n");
if (hal_proto_execute(&h->hal, fid, NULL, 0) < 0) {
printc_err("v3hil: can't read CPU registers\n");
return -1;
@ -702,9 +881,10 @@ int v3hil_update_regs(struct v3hil *h)
int v3hil_flush_regs(struct v3hil *h)
{
const hal_proto_fid_t fid =
map_fid(h, HAL_PROTO_FID_WRITE_ALL_CPU_REGS);
const int reg_size = (fid == HAL_PROTO_FID_WRITE_ALL_CPU_REGS) ? 2 : 3;
const hal_proto_fid_t fid = map_fid(h, HAL_PROTO_FID_WRITE_ALL_CPU_REGS);
const int reg_size = (fid == HAL_PROTO_FID_WRITE_ALL_CPU_REGS
|| fid == HAL_PROTO_FID_WRITE_ALL_CPU_REGS - 1)
? 2 : 3;
int i;
int dptr = 0;
uint8_t data[64];
@ -724,6 +904,7 @@ int v3hil_flush_regs(struct v3hil *h)
}
}
dbg_printc("Write regs\n");
if (hal_proto_execute(&h->hal, fid, data, reg_size * 13) < 0) {
printc_err("v3hil: can't write CPU registers\n");
return -1;
@ -747,6 +928,7 @@ int v3hil_context_restore(struct v3hil *h, int free)
data[10] = free ? 7 : 6;
data[14] = free ? 1 : 0;
dbg_printc("Context restore\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_RC_RELEASE_JTAG),
data, 18) < 0) {
@ -769,6 +951,7 @@ int v3hil_context_save(struct v3hil *h)
data[2] = h->wdtctl | 0x80;
data[3] = 0x5a; /* WDTPW */
dbg_printc("Context save\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_SJ_CONDITIONAL_SC),
data, 8) < 0)
@ -800,6 +983,7 @@ int v3hil_single_step(struct v3hil *h)
data[9] = h->regs[MSP430_REG_SR] >> 8;
data[10] = 7;
dbg_printc("Single-stepping...\n");
if (hal_proto_execute(&h->hal,
map_fid(h, HAL_PROTO_FID_SINGLE_STEP),
data, 18) < 0) {
@ -834,7 +1018,9 @@ static int set_param(struct v3hil *fet, hal_proto_config_t cfg,
}
data[0] = cfg;
if (hal_proto_execute(&fet->hal, HAL_PROTO_FID_CONFIGURE,
dbg_printc("Set param 0x%02x to 0x%08x\n", cfg, value);
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_CONFIGURE),
data, 8) < 0) {
printc_err("v3hil: can't set param 0x%02x to 0x%08x\n",
cfg, value);
@ -854,7 +1040,7 @@ static int idproc_89(struct v3hil *fet, uint32_t id_data_addr,
memset(data, 0, 8);
w32le(data, id_data_addr);
data[4] = 8;
if (hal_proto_execute(&fet->hal, HAL_PROTO_FID_READ_MEM_WORDS,
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_READ_MEM_WORDS),
data, 8) < 0)
return -1;
if (fet->hal.length < 16) {
@ -870,7 +1056,7 @@ static int idproc_89(struct v3hil *fet, uint32_t id_data_addr,
id->config = fet->hal.payload[13] & 0x7f;
printc_dbg("Read fuses...\n");
if (hal_proto_execute(&fet->hal, HAL_PROTO_FID_GET_FUSES, NULL, 0) < 0)
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_GET_FUSES), NULL, 0) < 0)
return -1;
if (!fet->hal.length) {
printc_err("v3hil: short reply: %d\n", fet->hal.length);
@ -894,7 +1080,7 @@ static int idproc_9x(struct v3hil *fet, uint32_t dev_id_ptr,
memset(data, 0, 8);
w32le(data, dev_id_ptr);
data[4] = 4;
if (hal_proto_execute(&fet->hal, HAL_PROTO_FID_READ_MEM_QUICK_XV2,
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_READ_MEM_QUICK_XV2),
data, 8) < 0)
return -1;
if (fet->hal.length < 8) {
@ -918,7 +1104,7 @@ static int idproc_9x(struct v3hil *fet, uint32_t dev_id_ptr,
w32le(data, dev_id_ptr);
w32le(data + 4, tlv_size >> 1);
w32le(data + 8, fet->regs[MSP430_REG_PC]);
if (hal_proto_execute(&fet->hal, HAL_PROTO_FID_READ_MEM_QUICK_XV2,
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_READ_MEM_QUICK_XV2),
data, 8) < 0)
return -1;
if (fet->hal.length < tlv_size) {
@ -935,8 +1121,11 @@ static int idproc_9x(struct v3hil *fet, uint32_t dev_id_ptr,
if (tag == 0xff)
break;
if ((tag == 0x14) && (len >= 2))
if ((tag == 0x14) && (len >= 2)) {
// FIXME: this looks like it's reading from the wrong address?
id->ver_sub_id = r16le(fet->hal.payload);
// FIXME: break here?
}
i += len;
}
@ -952,26 +1141,56 @@ int v3hil_identify(struct v3hil *fet)
int i;
printc_dbg("Fetching JTAG ID...\n");
if (hal_proto_execute(&fet->hal, HAL_PROTO_FID_GET_JTAG_ID,
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_GET_JTAG_ID),
NULL, 0) < 0)
return -1;
if (fet->hal.length < 12) {
printc_err("v3hil: short reply: %d\n", fet->hal.length);
return -1;
}
printc_dbg("ID:");
for (i = 0; i < fet->hal.length; i++)
printc_dbg(" %02x", fet->hal.payload[i]);
printc_dbg("\n");
if (fet->hal.length < 12) {
if (fet->hal.length == 2) {
fet->jtag_id = fet->hal.payload[0];
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_GET_DEVICE_ID_PTR),
NULL, 0) < 0)
return -1;
#ifdef DEBUG_V3HIL
dbg_printc("len: %d\n", fet->hal.length);
printc_dbg("v3hil: IDPtr:");
for (i = 0; i < fet->hal.length; i++)
printc_dbg(" %02x", fet->hal.payload[i]);
printc_dbg("\n");
#endif
if (fet->hal.length < 10) {
printc_err("v3hil: short reply: %d\n", fet->hal.length);
return -1;
} else {
dev_id_ptr = r32le(fet->hal.payload + 0);
if (dev_id_ptr == 0) {
/* welp sometimes it's this instead (JTAG ID == 0x89?) */
dev_id_ptr = r32le(fet->hal.payload + 4);
}
id_data_addr = dev_id_ptr; /* idk */
}
} else {
printc_err("v3hil: short reply: %d\n", fet->hal.length);
return -1;
}
} else {
/* Byte at 0 is JTAG ID. 0x91, 0x95, 0x99 means CPUxV2. 0x89
* means old CPU.
*/
fet->jtag_id = fet->hal.payload[0];
dev_id_ptr = r32le(fet->hal.payload + 4);
id_data_addr = r32le(fet->hal.payload + 8);
}
/* Pick fail-safe configuration */
printc_dbg("Reset parameters...\n");
@ -982,12 +1201,12 @@ int v3hil_identify(struct v3hil *fet)
set_param(fet, HAL_PROTO_CONFIG_PSA_TCKL_HIGH, 0) < 0 ||
set_param(fet, HAL_PROTO_CONFIG_POWER_TESTREG_MASK, 0) < 0 ||
set_param(fet, HAL_PROTO_CONFIG_POWER_TESTREG3V_MASK, 0) < 0 ||
set_param(fet, HAL_PROTO_CONFIG_NO_BSL, 0) < 0 ||
set_param(fet, HAL_PROTO_CONFIG_ALT_ROM_ADDR_FOR_CPU_READ, 0) < 0)
return -1;
set_param(fet, HAL_PROTO_CONFIG_NO_BSL, 0); /* is allowed to fail */
printc_dbg("Check JTAG fuse...\n");
if (hal_proto_execute(&fet->hal, HAL_PROTO_FID_IS_JTAG_FUSE_BLOWN,
if (hal_proto_execute(&fet->hal, map_ver(fet, HAL_PROTO_FID_IS_JTAG_FUSE_BLOWN),
NULL, 0) < 0)
return -1;
if ((fet->hal.length >= 2) &&
@ -1056,13 +1275,13 @@ int v3hil_configure(struct v3hil *fet)
fet->chip->power.enable_lpm5_3v) < 0 ||
set_param(fet, HAL_PROTO_CONFIG_TESTREG3V_DISABLE_LPMX5,
fet->chip->power.disable_lpm5_3v) < 0 ||
set_param(fet, HAL_PROTO_CONFIG_NO_BSL,
(fet->chip->features &
CHIPINFO_FEATURE_NO_BSL) ? 1 : 0) < 0 ||
set_param(fet, HAL_PROTO_CONFIG_ALT_ROM_ADDR_FOR_CPU_READ,
(fet->chip->features &
CHIPINFO_FEATURE_1337) ? 1 : 0) < 0)
return -1;
/* is allowed to fail */
set_param(fet, HAL_PROTO_CONFIG_NO_BSL,
(fet->chip->features & CHIPINFO_FEATURE_NO_BSL) ? 1 : 0);
return 0;
}

View File

@ -44,6 +44,9 @@ struct v3hil {
/* Lower 8 bits of saved WDTCTL */
uint8_t wdtctl;
/* Is this a v2 or v3 firmware running on the eZ-FET? */
uint16_t proto_ver;
/* Register cache: this must be flushed before restoring context
* and updated after saving context.
*/

View File

@ -247,8 +247,10 @@ static int feed_section(struct elf32_info *info,
ch.data = buf;
ch.len = len;
if (cb(user_data, &ch) < 0)
if (cb(user_data, &ch) < 0) {
pr_error("elf32: misc error");
return -1;
}
size -= len;
offset += len;
@ -331,7 +333,7 @@ int elf32_extract(FILE *in, binfile_imgcb_t cb, void *user_data)
Elf32_Shdr *s = &info.file_shdrs[i];
if ((s->sh_type == SHT_PROGBITS || s->sh_type == SHT_INIT_ARRAY) &&
s->sh_flags & SHF_ALLOC &&
(s->sh_flags & SHF_ALLOC) && s->sh_size > 0 &&
feed_section(&info, in, s, cb, user_data) < 0) {
ret = -1;
break;

View File

@ -52,6 +52,10 @@ section \fBDRIVERS\fR below for details.
.IP "\-U \fIbus\fR:\fIdevice\fR"
Specify a particular USB device to connect to. Without this option,
the first device of the appropriate type is opened.
.IP "\-V \fIvid\fR:\fIpid\fR"
Specify a VID and PID of the USB device to connect to, or override the
default VID and PID. Some drives, such as \fBmehfet\fR, require this option,
while others have a default VID and PID which can be overridden.
.IP "\-s \fIserial\fR"
Specify a particular USB device serial number to connect to. Use this
option to distinguish between multiple devices of the same type.
@ -230,6 +234,13 @@ There are reports of this operation causing an erase of info A in some
devices. Use at your own risk.
.IP "\fBbus-pirate\fR"
Raw JTAG using Bus Pirate devices.
.IP "\fBmehfet\fR"
Connect to a MehFET USB-based debugging protocol-capable device. It can
support both JTAG and Spy-Bi-Wire. For now, only 16-bit CPUs (that is,
non-430X or Xv2) are suppored, as with the \fBpif\fR, \fBgpio\fR,
\fBbus-pirate\fR and \fBgoodfet\fR rivers.
For documentation on the USB protocol, see the \fBSEE ALSO\fR section.
.SH COMMANDS
MSPDebug can accept commands either through an interactive prompt, or
non-interactively when specified on the command line. The supported
@ -826,6 +837,9 @@ Firmware image for the TI3410 USB interface chip. This file is only
required for raw USB access to FET430UIF or eZ430 devices.
.SH SEE ALSO
\fBnm\fR(1), \fBgdb\fR(1), \fBobjcopy\fR(1)
\fBmehfet\fR protocol documentation can be found at the following URL:
https://git.lain.faith/sys64738/DragonProbe/wiki/MehFET-USB-protocol
.SH BUGS
If you find any bugs, you should report them to the author at
dlbeer@gmail.com. It would help if you could include a transcript

406
transport/mehfet_xport.c Normal file
View File

@ -0,0 +1,406 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2021 sys64738@disroot.org
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include "mehfet_xport.h"
#include "util.h"
#include "usbutil.h"
#include "output.h"
struct mehfet_transport {
struct transport base;
struct usb_dev_handle *handle;
int epin, epout;
int buf_size;
};
#define TIMEOUT_S 30
#define REQ_TIMEOUT_MS 100
static int open_device(struct mehfet_transport *tr, struct usb_device *dev)
{
#ifdef __linux__
int driver;
char drv_name[128];
#endif
// first, find the right interface (and associated endpoints) of the USB device
int config = 0, itf = 0;
bool has = false;
for (config = 0; config < dev->descriptor.bNumConfigurations; ++config) {
struct usb_config_descriptor* cd = &dev->config[config];
for (itf = 0; itf < cd->bNumInterfaces; ++itf) {
struct usb_interface_descriptor* id = &cd->interface[itf].altsetting[0];
if (id->bInterfaceClass == USB_CLASS_VENDOR_SPEC
&& id->bInterfaceSubClass == '4'
&& id->bInterfaceProtocol == '3') {
// here I'd like to check for the "MehFET" substring in the
// interface's iInterface string, but I can't really figure out
// how to do that, so I'll just assume this is enough checking.
if (id->bNumEndpoints != 2) continue; // this should be 2
for (size_t i = 0; i < id->bNumEndpoints; ++i) {
struct usb_endpoint_descriptor* ed = &id->endpoint[i];
if ((ed->bmAttributes & USB_ENDPOINT_TYPE_MASK)
!= USB_ENDPOINT_TYPE_BULK)
break;
if (ed->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
tr->epin = ed->bEndpointAddress; // input endpoint
else
tr->epout = ed->bEndpointAddress; // output endpoint
}
if (tr->epin != 0 && tr->epout != 0) {
has = true;
goto break_outer;
}
}
}
}
break_outer:
if (!has) {
printc_err("mehfet transport: USB device %s has no MehFET interface.\n",
dev->filename);
return -1;
}
printc_dbg("mehfet transport: trying to open %s\n", dev->filename);
tr->handle = usb_open(dev);
if (!tr->handle) {
printc_err("mehfet transport: can't open device: %s\n",
usb_strerror());
return -1;
}
#ifdef __linux__
driver = usb_get_driver_np(tr->handle, itf, drv_name, sizeof(drv_name));
if (driver >= 0) {
printc_dbg("Detaching kernel driver \"%s\"\n", drv_name);
if (usb_detach_kernel_driver_np(tr->handle, itf) < 0)
printc_err("warning: mehfet transport: can't detach "
"kernel driver: %s\n", usb_strerror());
}
#endif
#ifdef __Windows__
if (usb_set_configuration(tr->handle, config) < 0) {
printc_err("mehfet transport: can't set configuration: %s\n",
usb_strerror());
usb_close(tr->handle);
return -1;
}
#endif
if (usb_claim_interface(tr->handle, itf) < 0) {
printc_err("mehfet transport: can't claim interface: %s\n",
usb_strerror());
usb_close(tr->handle);
return -1;
}
return 0;
}
static void tr_destroy(transport_t tr_base)
{
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
usb_close(tr->handle);
free(tr);
}
static int tr_recv(transport_t tr_base, uint8_t *databuf, int max_len)
{
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
time_t deadline = time(NULL) + TIMEOUT_S;
char tmpbuf[tr->buf_size];
if (max_len > tr->buf_size)
max_len = tr->buf_size;
while (time(NULL) < deadline) {
int r = usb_bulk_read(tr->handle, tr->epin,
tmpbuf, max_len,
TIMEOUT_S * 1000);
if (r <= 0) {
printc_err("mehfet transport: usb_bulk_read: %s\n",
usb_strerror());
return -1;
}
memcpy(databuf, tmpbuf, r);
#ifdef DEBUG_MEHFET_TRANSPORT
printc_dbg("mehfet transport: tr_recv: flags = %02x %02x\n",
tmpbuf[0], tmpbuf[1]);
debug_hexdump("mehfet transport: tr_recv", databuf, r);
#endif
return r;
}
printc_err("mehfet transport: timed out while receiving data\n");
return -1;
}
static int tr_send(transport_t tr_base, const uint8_t *databuf, int len)
{
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
#ifdef DEBUG_MEHFET
debug_hexdump("mehfet transport: tr_send", databuf, len);
#endif
while (len) {
int r = usb_bulk_write(tr->handle, tr->epout,
(char *)databuf, len,
TIMEOUT_S * 1000);
if (r <= 0) {
printc_err("mehfet transport: usb_bulk_write: %s\n",
usb_strerror());
return -1;
}
databuf += r;
len -= r;
}
return 0;
}
static int tr_flush(transport_t tr_base)
{
(void)tr_base;
return 0;
}
static int tr_set_modem(transport_t tr_base, transport_modem_t state)
{
(void)tr_base; (void)state;
return 0;
}
static const struct transport_class mehfet_class = {
.destroy = tr_destroy,
.send = tr_send,
.recv = tr_recv,
.flush = tr_flush,
.set_modem = tr_set_modem
};
transport_t mehfet_transport_open(const char *devpath,
const uint16_t* vendor, const uint16_t* product,
const char *requested_serial)
{
struct mehfet_transport *tr = malloc(sizeof(*tr));
struct usb_device *dev = NULL;
if (!tr) {
pr_error("mehfet transport: can't allocate memory");
return NULL;
}
tr->base.ops = &mehfet_class;
usb_init();
usb_find_busses();
usb_find_devices();
if (devpath)
dev = usbutil_find_by_loc(devpath);
else if (vendor && product)
dev = usbutil_find_by_id(*vendor, *product, requested_serial);
if (!dev) {
printc_err("mehfet: no USB device found.%s\n",
vendor ? "" : " (Did you forget to specify a VID:PID?)");
free(tr);
return NULL;
}
tr->buf_size = 64; // initial conservative value, will get updated later
if (open_device(tr, dev) < 0) {
printc_err("mehfet: failed to open device\n");
free(tr);
return NULL;
}
return &tr->base;
}
void mehfet_transport_set_buf_size(transport_t tr_base, int buf_size)
{
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
tr->buf_size = buf_size;
}
int mehfet_transport_get_buf_size(transport_t tr_base)
{
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
return tr->buf_size;
}
int mehfet_send_raw(transport_t xport, uint8_t cmd, int datalen, const void* data) {
if (datalen < 0) return -1;
if (data && !datalen) return -1;
if (!data && datalen) return -1;
uint8_t buf[1+4+datalen];
buf[0] = cmd;
int i, len2;
for (i = 0, len2 = datalen; i < 4 && len2; ++i, len2 >>= 7) {
buf[0] |= 0x80; // command has payload data
if (i == 3) {
buf[i+1] = len2;
} else {
buf[i+1] = len2 & 0x7f;
if (len2 >> 7) buf[i+1] |= 0x80;
}
}
if (data && datalen) memcpy(&buf[i+1], data, datalen);
return xport->ops->send(xport, buf, datalen + 1 + i);
}
int mehfet_recv_raw(transport_t xport, uint8_t* stat, int* datalen, void* data) {
struct mehfet_transport *tr = (struct mehfet_transport *)xport;
uint8_t rawbuf[tr->buf_size];
int nmax = 5, ndata = 0, nfetch;
if (datalen) {
ndata = *datalen;
nmax = ndata + 5;
}
nfetch = nmax;
if (nmax > tr->buf_size) {
nmax = tr->buf_size;
/*printc_err("mehfet transport: bug: asking for more data (%d) than "
"in the device buffer size (%d)\n", nmax, tr->buf_size);
return -1;*/
}
int r = xport->ops->recv(xport, rawbuf, nfetch);
if (r < 0) return r;
if (r < 1) {
printc_err("mehfet transport: no status byte received\n");
return -1;
}
assert(r <= nfetch);
uint8_t statv = rawbuf[0];
uint32_t reallen = 0;
uint8_t lastbyte = statv;
int i;
for (i = 0; i < 4 && (lastbyte & 0x80) /*&& i + 1 < r*/; ++i) {
if (r < i + 2) {
printc_err("mehfet transport: not enough lenght bytes received (%d)\n", r);
return -1;
}
lastbyte = rawbuf[i + 1];
uint8_t mask = (i == 3) ? 0xff : 0x7f;
reallen |= (lastbyte & mask) << (i * 7);
}
if ((int)reallen > nmax && data) {
printc_err("mehfet transport: too much data returned (%d vs %d)\n",
(int)reallen, nmax);
return -1;
}
int nrecvdata = r - 1 - i;
assert(nrecvdata >= 0);
if (nrecvdata && data) memcpy(data, &rawbuf[i+1], nrecvdata);
// now we can use rawbuf for other purposes
int off = r;
int ntodo = (int)reallen - nrecvdata;
while (ntodo > 0) { // more data bytes following in this logical packet
int thisblock = tr->buf_size;
if (thisblock > ntodo) thisblock = ntodo;
r = xport->ops->recv(xport, rawbuf, thisblock);
if (r < 0) return r;
assert(r < thisblock);
memcpy(&((char*)data)[off], rawbuf, thisblock);
ntodo -= r;
off += r;
}
if (stat) *stat = statv & 0x7f;
if (datalen) *datalen = (int)reallen;
return (int)reallen;
}
int mehfet_err_on_stat(const char* pre, uint8_t stat, int datalen, const void* data) {
if (stat == mehfet_ok) return 0;
const char* d = (const char*)data;
switch (stat) {
case mehfet_badargs:
printc_err("mehfet: %s: %s\n", pre,
datalen ? d : "bad argument sent to command");
break;
case mehfet_nocaps:
printc_err("mehfet: %s: %s\n", pre,
datalen ? d : "device doesn't have the command capability");
break;
case mehfet_badstate:
printc_err("mehfet: %s: %s\n", pre,
datalen ? d : "device in wrong state to execute command");
break;
case mehfet_invalidcmd:
printc_err("mehfet: %s: %s\n", pre,
datalen ? d : "invalid command");
break;
case mehfet_error:
printc_err("mehfet: %s: %s\n", pre, datalen ? d : "unspecified error");
break;
default:
printc_err("mehfet: %s: unknown error %hhu\n", pre, stat);
break;
}
return -1;
}

52
transport/mehfet_xport.h Normal file
View File

@ -0,0 +1,52 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2021 sys64738@disroot.org
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MEHFET_TRANSPORT_H_
#define MEHFET_TRANSPORT_H_
#include "transport.h"
enum mehfet_status {
mehfet_ok = 0x00,
mehfet_badargs = 0x7b,
mehfet_nocaps = 0x7c,
mehfet_badstate = 0x7d,
mehfet_invalidcmd = 0x7e,
mehfet_error = 0x7f
};
/* Search the USB bus for the first MehFET device and initialize it.
* If successful, return a transport object. Otherwise, return NULL.
*
* A particular USB device or serial number may be specified.
*/
transport_t mehfet_transport_open(const char *usb_device,
const uint16_t* vendor, const uint16_t* product,
const char *requested_serial);
int mehfet_transport_get_buf_size(transport_t xport);
void mehfet_transport_set_buf_size(transport_t xport, int buf_size);
int mehfet_send_raw(transport_t xport, uint8_t cmd, int datalen, const void* data);
int mehfet_recv_raw(transport_t xport, uint8_t* stat, int* datalen, void* data);
int mehfet_err_on_stat(const char* pre, uint8_t stat, int datalen, const void* data);
#endif

View File

@ -228,7 +228,8 @@ static const struct transport_class rf2500_transport = {
.set_modem = usbtr_set_modem
};
transport_t rf2500_open(const char *devpath, const char *requested_serial)
transport_t rf2500_open(const char *devpath, const char *requested_serial,
int has_vid_pid, uint16_t vid, uint16_t pid)
{
struct rf2500_transport *tr = malloc(sizeof(*tr));
struct usb_device *dev;
@ -248,7 +249,8 @@ transport_t rf2500_open(const char *devpath, const char *requested_serial)
if (devpath)
dev = usbutil_find_by_loc(devpath);
else
dev = usbutil_find_by_id(USB_FET_VENDOR, USB_FET_PRODUCT,
dev = usbutil_find_by_id(has_vid_pid ? vid : USB_FET_VENDOR,
has_vid_pid ? pid : USB_FET_PRODUCT,
requested_serial);
if (!dev) {

View File

@ -27,7 +27,9 @@
*
* A particular device may be specified in bus:dev form.
*/
transport_t rf2500_open(const char *dev_path, const char *requested_serial);
transport_t rf2500hidapi_open(const char *dev_path, const char *requested_serial);
transport_t rf2500_open(const char *dev_path, const char *requested_serial,
int has_vid_pid, uint16_t vid, uint16_t pid);
transport_t rf2500hidapi_open(const char *dev_path, const char *requested_serial,
int has_vid_pid, uint16_t vid, uint16_t pid);
#endif

View File

@ -161,7 +161,8 @@ static const wchar_t * get_wc(const char *c)
return wc;
}
transport_t rf2500hidapi_open(const char *devpath, const char *requested_serial)
transport_t rf2500hidapi_open(const char *devpath, const char *requested_serial,
int has_vid_pid, uint16_t vid, uint16_t pid)
{
struct rf2500_transport *tr = malloc(sizeof(*tr));
hid_device *handle;
@ -186,7 +187,9 @@ transport_t rf2500hidapi_open(const char *devpath, const char *requested_serial)
} else {
wc_serial = NULL;
}
handle = hid_open(USB_FET_VENDOR, USB_FET_PRODUCT, wc_serial);
handle = hid_open(has_vid_pid ? vid : USB_FET_VENDOR,
has_vid_pid ? pid : USB_FET_PRODUCT, wc_serial);
if ( wc_serial ) {
free((wchar_t *)wc_serial);
}
@ -197,7 +200,7 @@ transport_t rf2500hidapi_open(const char *devpath, const char *requested_serial)
free(tr);
hid_exit();
printc_err("rf2500: fallback to libusb backend\n");
return rf2500_open(devpath, requested_serial);
return rf2500_open(devpath, requested_serial, has_vid_pid, vid, pid);
}
tr->handle = handle;

View File

@ -559,7 +559,8 @@ static const struct transport_class ti3410_transport = {
.set_modem = ti3410_set_modem
};
transport_t ti3410_open(const char *devpath, const char *requested_serial)
transport_t ti3410_open(const char *devpath, const char *requested_serial,
int has_vid_pid, uint16_t vid, uint16_t pid)
{
struct ti3410_transport *tr = malloc(sizeof(*tr));
struct usb_device *dev;
@ -578,7 +579,8 @@ transport_t ti3410_open(const char *devpath, const char *requested_serial)
if (devpath)
dev = usbutil_find_by_loc(devpath);
else
dev = usbutil_find_by_id(USB_FET_VENDOR, USB_FET_PRODUCT,
dev = usbutil_find_by_id(has_vid_pid ? vid : USB_FET_VENDOR,
has_vid_pid ? pid : USB_FET_PRODUCT,
requested_serial);
if (!dev) {

View File

@ -24,6 +24,8 @@
/* This function is for opening an eZ430-F2013 or FET430UIF device via
* libusb.
*/
transport_t ti3410_open(const char *dev_path, const char *requested_serial);
transport_t ti3410_open(const char *dev_path, const char *requested_serial,
int has_vid_pid, uint16_t vid, uint16_t pid);
#endif

View File

@ -190,11 +190,12 @@ const struct cmddb_record commands[] = {
.func = cmd_erase,
.help =
"erase [all|segment] [address]\n"
"erase segrange <address> <size> <seg-size>\n"
"erase segrange <address> <total-size> <seg-size>\n"
" Erase the device under test. With no arguments, erases all of main\n"
" memory. Specify arguments to perform a mass erase, or to erase\n"
" individual segments. The \"segrange\" mode is used to erase an\n"
" address range via a series of segment erases.\n"
" address range via a series of segment erases, 'total-size' being"
" a multiple of 'seg-size'.\n"
},
{
.name = "step",

View File

@ -207,6 +207,12 @@ int cmd_erase(char **arg)
"0x%x\n", segment_size);
return -1;
}
if (total_size % segment_size != 0) {
printc_err("erase: total size must be a multiple of the "
"segment size!\n");
return -1;
}
} else {
printc_err("erase: unknown erase type: %s\n",
type_text);

View File

@ -58,6 +58,7 @@
#include "fet3.h"
#include "rom_bsl.h"
#include "chipinfo.h"
#include "mehfet.h"
#ifdef __CYGWIN__
#include <sys/cygwin.h>
@ -92,7 +93,8 @@ static const struct device_class *const driver_table[] = {
&device_loadbsl,
&device_ezfet,
&device_rom_bsl,
&device_bp
&device_bp,
&device_mehfet
};
static const char *version_text =
@ -114,6 +116,9 @@ static void usage(const char *progname)
" Connect via the given tty device, rather than USB.\n"
" -U bus:dev\n"
" Specify a particular USB device to connect to.\n"
" -V vid:pid\n"
" Specify a particular vid:pid par of a USB to connect to, instead of\n"
" a driver-specific default.\n"
" -s serial\n"
" Specify a particular device serial number to connect to.\n"
" -j\n"
@ -328,7 +333,7 @@ static int parse_cmdline_args(int argc, char **argv,
int opt;
int want_usb = 0;
while ((opt = getopt_long(argc, argv, "d:jv:nU:s:qC:",
while ((opt = getopt_long(argc, argv, "d:jv:nUV:s:qC:",
longopts, NULL)) >= 0)
switch (opt) {
case 'C':
@ -398,6 +403,18 @@ static int parse_cmdline_args(int argc, char **argv,
want_usb = 1;
break;
case 'V':
/* optarg is in "vid:pid" format, which we now need to parse */
if (sscanf(optarg, "%04hx:%04hx", &args->devarg.vid, &args->devarg.pid) == 2) {
args->devarg.flags |= DEVICE_FLAG_HAS_VID_PID;
want_usb = 1;
} else {
printc("Invalid -V option specified: %s."
"Format should be '<vid>:<pid>'\n", optarg);
exit(1);
}
break;
case 's':
args->devarg.requested_serial = optarg;
break;

View File

@ -54,7 +54,7 @@ static int addr_exp_data(struct addr_exp_state *s, const char *text)
}
/* Hex value */
if (*text == '0' && text[1] == 'x') {
if (*text == '0' && (text[1] == 'x' || text[1] == 'X')) {
value = strtoul(text + 2, NULL, 16);
} else if (*text == '0' && text[1] == 'd') {
value = atoi(text + 2);