From 5f30c8c2174029d17c3420fb5eae2572e0c0ceeb Mon Sep 17 00:00:00 2001 From: sys64738 Date: Sun, 24 Jul 2022 04:29:48 +0200 Subject: [PATCH] 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. --- Makefile | 5 + drivers/jtaglib.c | 1032 ++++++-------------------------------- drivers/jtaglib.h | 40 ++ drivers/jtaglib_cpu16.c | 830 ++++++++++++++++++++++++++++++ drivers/jtaglib_cpux.c | 7 + drivers/jtaglib_cpuxv2.c | 7 + drivers/jtaglib_defs.h | 61 +++ drivers/jtdev.h | 8 +- drivers/mehfet.c | 9 +- drivers/pif.c | 25 +- 10 files changed, 1138 insertions(+), 886 deletions(-) create mode 100644 drivers/jtaglib_cpu16.c create mode 100644 drivers/jtaglib_cpux.c create mode 100644 drivers/jtaglib_cpuxv2.c create mode 100644 drivers/jtaglib_defs.h diff --git a/Makefile b/Makefile index a5a62bb..31201f3 100644 --- a/Makefile +++ b/Makefile @@ -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/ @@ -195,6 +197,9 @@ 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 \ diff --git a/drivers/jtaglib.c b/drivers/jtaglib.c index 10c2765..8f7bb14 100644 --- a/drivers/jtaglib.c +++ b/drivers/jtaglib.c @@ -37,63 +37,7 @@ #include #include "jtaglib.h" #include "output.h" -#include "eem_defs.h" - -/* JTAG identification value for all existing Flash-based MSP430 devices - */ -#define JTAG_ID 0x89 - -/* 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 */ -/* 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 */ -/* 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 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 */ - -#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_tms_sequence(p, bits, tms) p->f->jtdev_tms_sequence(p, bits, tms) -#define jtag_init_dap(p) p->f->jtdev_init_dap(p) +#include "jtaglib_defs.h" /* Reset target JTAG interface and perform fuse-HW check */ static void jtag_default_reset_tap(struct jtdev *p) @@ -328,140 +272,186 @@ void jtag_default_init_dap(struct jtdev *p) jtag_default_reset_tap(p); } -/* Set target CPU JTAG state machine into the instruction fetch state - * return: 1 - instruction fetch was set +/* ------------------------------------------------------------------------- */ + +static const struct jtaglib_funcs* get_jlf(struct jtdev *p) +{ + // FIXME: this function only looks at the chip ID, while the device info DB + // is more fine-grained about function mapping. so use that instead + // when possible + + static const struct jtaglib_funcs* lut[] = { + NULL, + &jlf_cpu16, + &jlf_cpux, + &jlf_cpuxv2 + }; + + if (p->cpu_type != 0) { + if (p->cpu_type < sizeof(lut)/sizeof(*lut)) { + return lut[p->cpu_type]; + } else { + printc_err("jtaglib: ERROR: bad CPU type %d\n", p->cpu_type); + return NULL; + } + } else { + if (p->jtag_id == 0) { + printc_err("jtaglib: ERROR: no JTAG ID set!\n"); + return NULL; + } else if (p->jtag_id == JTAG_ID_CPU16) { + return &jlf_cpu16; + } else { + // Here, it's hard to predict whether the target is CPUX or Xv2 + // from the JTAG ID alone. However, this is only needed relatively + // little as the actual MCU ID should be read from info memory + // after connecting, so let's just assume Xv2 here, and add some + // extra care to the few functions that will be called before the + // ID readout happens to make it all work + return &jlf_cpuxv2; + } + } +} + +unsigned int jtag_get_device(struct jtdev *p) +{ + // NOTE: this is one of the special functions that have to be called early + // on before chip ID stuff is done + + unsigned int r = get_jlf(p)->jlf_get_device(p); + + if (r != 0) jtag_led_green_on(p); + + return r; +} + +unsigned int jtag_chip_id(struct jtdev *p) +{ + // NOTE: this is one of the special functions that have to be called early + // on before chip ID stuff is done + + return get_jlf(p)->jlf_chip_id(p); +} + +/* Reads one byte/word from a given address */ +uint16_t jtag_read_mem(struct jtdev *p, unsigned int format, address_t address) +{ + // NOTE: this is one of the special functions that have to be called early + // on before chip ID stuff is done + + return get_jlf(p)->jlf_read_mem(p, format, address); +} + +/* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register */ +unsigned int jtag_execute_puc(struct jtdev *p) +{ + // NOTE: this is one of the special functions that have to be called early + // on before chip ID stuff is done + + return get_jlf(p)->jlf_execute_puc(p); +} + +/* Reads an array of words from target memory */ +void jtag_read_mem_quick(struct jtdev *p, address_t start_address, + unsigned int word_count, uint16_t *data) +{ + get_jlf(p)->jlf_read_mem_quick(p, start_address, word_count, data); +} + +/* Writes one byte/word at a given address */ +void jtag_write_mem(struct jtdev *p, unsigned int format, address_t address, + uint16_t data) +{ + get_jlf(p)->jlf_write_mem(p, format, address, data); +} + +/* Writes an array of words into target memory */ +void jtag_write_mem_quick(struct jtdev *p, address_t start_address, + unsigned int word_count, const uint16_t *data) +{ + get_jlf(p)->jlf_write_mem_quick(p, start_address, word_count, data); +} + +/* Release the target device from JTAG control */ +void jtag_release_device(struct jtdev *p, address_t address) +{ + jtag_led_green_off(p); + + get_jlf(p)->jlf_release_device(p, address); +} + +/* Performs a verification over the given memory range + * return: 1 - verification was successful + * 0 - otherwise + */ +int jtag_verify_mem(struct jtdev *p, address_t start_address, + unsigned int length, const uint16_t *data) +{ + return get_jlf(p)->jlf_verify_mem(p, start_address, length, data); +} + +/* Performs an erase check over the given memory range + * return: 1 - erase check was successful * 0 - otherwise */ -static int jtag_set_instruction_fetch(struct jtdev *p) +int jtag_erase_check(struct jtdev *p, + address_t start_address, + unsigned int length) { - unsigned int loop_counter; - - 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("jtag_set_instruction_fetch: failed\n"); - p->failed = 1; - - return 0; + return get_jlf(p)->jlf_erase_check(p, start_address, length); } -/* Set the CPU into a controlled stop state */ -static void jtag_halt_cpu(struct jtdev *p) +/* Programs/verifies an array of words into a FLASH */ +void jtag_write_flash(struct jtdev *p, address_t start_address, + unsigned int word_count, const uint16_t *data) { - /* Set CPU into instruction fetch mode */ - jtag_set_instruction_fetch(p); + jtag_led_red_on(p); - /* Set device into JTAG mode + read */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift_16(p, 0x2401); + get_jlf(p)->jlf_write_flash(p, start_address, word_count, data); - /* 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); - 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); + jtag_led_red_off(p); } -/* Release the target CPU from the controlled stop state */ -static void jtag_release_cpu(struct jtdev *p) +/* Performs a mass erase or a segment erase of a FLASH module */ +void jtag_erase_flash(struct jtdev *p, unsigned int erase_mode, address_t erase_address) { - jtag_tclk_clr(p); + jtag_led_red_on(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); + get_jlf(p)->jlf_erase_flash(p, erase_mode, erase_address); + + jtag_led_red_off(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 jtag_verify_psa(struct jtdev *p, - unsigned int start_address, - unsigned int length, - const uint16_t *data) +/* Reads a register from the target CPU */ +address_t jtag_read_reg(struct jtdev *p, int reg) { - 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; - - jtag_execute_puc(p); - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift_16(p, 0x2401); - jtag_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; + return get_jlf(p)->jlf_read_reg(p, reg); } +/* Writes a value into a register of the target CPU */ +void jtag_write_reg(struct jtdev *p, int reg, address_t value) +{ + get_jlf(p)->jlf_write_reg(p, reg, value); +} +void jtag_single_step(struct jtdev *p) +{ + get_jlf(p)->jlf_single_step(p); +} +unsigned int jtag_set_breakpoint(struct jtdev *p, int bp_num, address_t bp_addr) +{ + return get_jlf(p)->jlf_set_breakpoint(p, bp_num, bp_addr); + +} +unsigned int jtag_cpu_state(struct jtdev *p) +{ + return get_jlf(p)->jlf_cpu_state(p); +} +int jtag_get_config_fuses(struct jtdev *p) +{ + return get_jlf(p)->jlf_get_config_fuses(p); +} + +/* ------------------------------------------------------------------------- */ + /* Take target device under JTAG control. * Disable the target watchdog. * return: 0 - fuse is blown @@ -498,191 +488,6 @@ unsigned int jtag_init(struct jtdev *p) return jtag_id; } -unsigned int jtag_get_device(struct jtdev *p) -{ - 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; - } - } - - if (loop_counter == 0) { - printc_err("jtag_get_device: timed out\n"); - p->failed = 1; - /* timeout reached */ - return 0; - } - - jtag_led_green_on(p); - return jtag_id; -} - -/* Read the target chip id. - * return: chip id - */ -unsigned int jtag_chip_id(struct jtdev *p) -{ - unsigned short chip_id; - - /* Read id from address 0x0ff0 */ - chip_id = jtag_read_mem(p, 16, 0x0FF0); - - /* High / low byte are stored in reverse order */ - chip_id = (chip_id << 8) + (chip_id >> 8); - - return chip_id; -} - -/* Reads one byte/word from a given address - * format : 8-byte, 16-word - * address: address of memory - * return : content of memory - */ -uint16_t jtag_read_mem(struct jtdev *p, - unsigned int format, - address_t address) -{ - uint16_t content; - - jtag_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() */ - jtag_release_cpu(p); - if (format == 8) - content &= 0x00ff; - - 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 - */ -void jtag_read_mem_quick(struct jtdev *p, - address_t address, - unsigned int length, - uint16_t *data) -{ - unsigned int index; - - /* Initialize reading: */ - jtag_write_reg(p, 0,address-4); - jtag_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); - /* shift out the data from the target */ - data[index] = jtag_dr_shift_16(p, 0x0000); - } - - jtag_tclk_set(p); - jtag_release_cpu(p); -} - -/* Writes one byte/word at a given address - * format : 8-byte, 16-word - * address: address to be written - * data : data to write - */ -void jtag_write_mem(struct jtdev *p, - unsigned int format, - address_t address, - uint16_t data) -{ - jtag_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); - jtag_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 - */ -void jtag_write_mem_quick(struct jtdev *p, - address_t address, - unsigned int length, - const uint16_t *data) -{ - unsigned int index; - - /* Initialize writing */ - jtag_write_reg(p, 0, address-4); - jtag_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); - - 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); - jtag_release_cpu(p); -} - /* This function checks if the JTAG access security fuse is blown * return: 1 - fuse is blown * 0 - otherwise @@ -703,514 +508,6 @@ int jtag_is_fuse_blown (struct jtdev *p) return 0; } -/* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register - * return: JTAG ID - */ -unsigned int jtag_execute_puc(struct jtdev *p) -{ - unsigned int jtag_id; - - 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); - - /* Read jtag id */ - jtag_id = jtag_ir_shift(p, IR_ADDR_CAPTURE); - - /* Disable watchdog on target device */ - jtag_write_mem(p, 16, 0x0120, 0x5A80); - - 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 - */ -void jtag_release_device(struct jtdev *p, address_t address) -{ - jtag_led_green_off(p); - - switch (address) { - case 0xffff: /* Nothing to do */ - break; - case 0xfffe: /* Perform reset */ - /* 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 */ - jtag_write_reg(p, 0, address); - break; - } - - jtag_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); -} - -/* Performs a verification over the given memory range - * return: 1 - verification was successful - * 0 - otherwise - */ -int jtag_verify_mem(struct jtdev *p, - address_t start_address, - unsigned int length, - const uint16_t *data) -{ - return jtag_verify_psa(p, start_address, length, data); -} - -/* Performs an erase check over the given memory range - * return: 1 - erase check was successful - * 0 - otherwise - */ -int jtag_erase_check(struct jtdev *p, - address_t start_address, - unsigned int length) -{ - return jtag_verify_psa(p, start_address, length, NULL); -} - -/* 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 - */ -void jtag_write_flash(struct jtdev *p, - address_t start_address, - unsigned int length, - const uint16_t *data) -{ - unsigned int index; - unsigned int address; - - jtag_led_red_on(p); - - address = start_address; - jtag_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); - - /* 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); - - /* 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); - - /* 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); - - /* Disable FLASH write */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift_16(p, 0xA500); - jtag_tclk_set(p); - jtag_release_cpu(p); - - jtag_led_red_off(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 - */ -void jtag_erase_flash(struct jtdev *p, - unsigned int erase_mode, - address_t erase_address) -{ - 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 */ - - jtag_led_red_on(p); - - 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--) { - jtag_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); - - /* Enable erase mode */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift_16(p, erase_mode); - jtag_tclk_set(p); - jtag_tclk_clr(p); - - /* FCTL2 address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012A); - - /* 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); - - /* 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); - - /* Disable erase */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift_16(p, 0xA500); - jtag_tclk_set(p); - jtag_tclk_clr(p); - - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012C); - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift_16(p, 0xA510); - jtag_tclk_set(p); - - jtag_release_cpu(p); - } - - jtag_led_red_off(p); -} - -/* Reads a register from the target CPU */ -address_t jtag_read_reg(struct jtdev *p, int reg) -{ - unsigned int value; - - /* Set CPU into instruction fetch mode */ - jtag_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_tclk_set(p); - 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); - - /* Return value read from register */ - return value; -} - -/* Writes a value into a register of the target CPU */ -void jtag_write_reg(struct jtdev *p, int reg, address_t value) -{ - /* Set CPU into instruction fetch mode */ - jtag_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); - - /* JTAG controls RW & BYTE */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift_16(p, 0x2401); -} - -/*----------------------------------------------------------------------------*/ -void jtag_single_step( struct jtdev *p ) -{ - unsigned int loop_counter; - - /* 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); - - if (loop_counter == 0) { - /* timeout reached */ - printc_err("pif: single step failed\n"); - p->failed = 1; - } -} - -/*----------------------------------------------------------------------------*/ -unsigned int jtag_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("jtag_set_breakpoint: failed setting " - "breakpoint %d at %04x\n", bp_num, bp_addr); - p->failed = 1; - return 0; - } - - 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<> 1) | (1 << bp_num); - jtag_dr_shift_16(p, BREAKREACT + WRITE); - jtag_dr_shift_16(p, breakreact); - return 1; -} - -/*----------------------------------------------------------------------------*/ -unsigned int jtag_cpu_state( struct jtdev *p ) -{ - jtag_ir_shift(p, IR_EMEX_READ_CONTROL); - - if ((jtag_dr_shift_16(p, 0x0000) & 0x0080) == 0x0080) { - return 1; /* halted */ - } else { - return 0; /* running */ - } -} - -/*----------------------------------------------------------------------------*/ -int jtag_get_config_fuses( struct jtdev *p ) -{ - jtag_ir_shift(p, IR_CONFIG_FUSES); - - return jtag_dr_shift_8(p, 0); -} - /*----------------------------------------------------------------------------*/ int jtag_refresh_bps(const char *module, device_t dev, struct jtdev *p) { @@ -1247,3 +544,4 @@ int jtag_refresh_bps(const char *module, device_t dev, struct jtdev *p) return ret; } + diff --git a/drivers/jtaglib.h b/drivers/jtaglib.h index 25a1cdd..5514df9 100644 --- a/drivers/jtaglib.h +++ b/drivers/jtaglib.h @@ -45,6 +45,46 @@ #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); + unsigned int (*jlf_chip_id)(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); +}; + +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); diff --git a/drivers/jtaglib_cpu16.c b/drivers/jtaglib_cpu16.c new file mode 100644 index 0000000..ea59397 --- /dev/null +++ b/drivers/jtaglib_cpu16.c @@ -0,0 +1,830 @@ + +#include "jtaglib.h" +#include "jtaglib_defs.h" +#include "output.h" + +/* 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) +{ + unsigned int loop_counter; + + 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) +{ + /* Set CPU into instruction fetch mode */ + 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); + 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) +{ + 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) +{ + 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; + + 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) +{ + 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; + } + } + + if (loop_counter == 0) { + printc_err("jtaglib_cpu16: jtag_get_device: timed out\n"); + p->failed = 1; + /* timeout reached */ + return 0; + } + + return jtag_id; +} + +/* Read the target chip id. + * return: chip id + */ +static unsigned int jlf16_chip_id(struct jtdev *p) +{ + unsigned short chip_id; + + /* Read id from address 0x0ff0 */ + chip_id = jtag_read_mem(p, 16, 0x0FF0); + + /* High / low byte are stored in reverse order */ + chip_id = (chip_id << 8) + (chip_id >> 8); + + return chip_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) +{ + uint16_t content; + + 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; + + 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) +{ + unsigned int index; + + /* 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); + /* shift out the data from the target */ + data[index] = jtag_dr_shift_16(p, 0x0000); + } + + jtag_tclk_set(p); + jlf16_release_cpu(p); +} + +/* 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) +{ + 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) +{ + unsigned int index; + + /* 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); + + 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) +{ + unsigned int jtag_id; + + 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); + + /* Read jtag id */ + jtag_id = jtag_ir_shift(p, IR_ADDR_CAPTURE); + + /* Disable watchdog on target device */ + jtag_write_mem(p, 16, 0x0120, 0x5A80); + + 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) +{ + switch (address) { + case 0xffff: /* Nothing to do */ + break; + case 0xfffe: /* Perform reset */ + /* 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 */ + 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) +{ + unsigned int index; + unsigned int address; + + 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); + + /* 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); + + /* 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); + + /* 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); + + /* 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); + 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) +{ + 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 */ + + 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); + + /* Enable erase mode */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift_16(p, erase_mode); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* FCTL2 address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift_16(p, 0x012A); + + /* 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); + + /* 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); + + /* 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); + 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) +{ + unsigned int value; + + /* 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_tclk_set(p); + 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); + + /* 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) +{ + /* 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 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); + + /* 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 ) +{ + unsigned int loop_counter; + + /* 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); + + if (loop_counter == 0) { + /* timeout reached */ + printc_err("pif: 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("jtag_set_breakpoint: failed setting " + "breakpoint %d at %04x\n", bp_num, bp_addr); + p->failed = 1; + return 0; + } + + 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<> 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 ) +{ + jtag_ir_shift(p, IR_EMEX_READ_CONTROL); + + if ((jtag_dr_shift_16(p, 0x0000) & 0x0080) == 0x0080) { + return 1; /* halted */ + } else { + return 0; /* running */ + } +} + +/*----------------------------------------------------------------------------*/ +static int jlf16_get_config_fuses( struct jtdev *p ) +{ + 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_chip_id = jlf16_chip_id, + + .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_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, +}; + diff --git a/drivers/jtaglib_cpux.c b/drivers/jtaglib_cpux.c new file mode 100644 index 0000000..a3419cb --- /dev/null +++ b/drivers/jtaglib_cpux.c @@ -0,0 +1,7 @@ + +#include "jtaglib.h" +#include "jtaglib_defs.h" +#include "output.h" + +const struct jtaglib_funcs jlf_cpux; + diff --git a/drivers/jtaglib_cpuxv2.c b/drivers/jtaglib_cpuxv2.c new file mode 100644 index 0000000..582dc3c --- /dev/null +++ b/drivers/jtaglib_cpuxv2.c @@ -0,0 +1,7 @@ + +#include "jtaglib.h" +#include "jtaglib_defs.h" +#include "output.h" + +const struct jtaglib_funcs jlf_cpuxv2; + diff --git a/drivers/jtaglib_defs.h b/drivers/jtaglib_defs.h new file mode 100644 index 0000000..47c8359 --- /dev/null +++ b/drivers/jtaglib_defs.h @@ -0,0 +1,61 @@ + +#include "jtaglib.h" +#include "eem_defs.h" + +/* JTAG identification value for all existing Flash-based MSP430 devices + */ +#define JTAG_ID_CPU16 0x89 + +/* 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 */ +/* 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 */ +/* 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 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 */ + +#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_tms_sequence(p, bits, tms) p->f->jtdev_tms_sequence(p, bits, tms) +#define jtag_init_dap(p) p->f->jtdev_init_dap(p) + + diff --git a/drivers/jtdev.h b/drivers/jtdev.h index f437abc..0633e3a 100644 --- a/drivers/jtdev.h +++ b/drivers/jtdev.h @@ -22,16 +22,22 @@ #include +#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; }; -struct jtdev_func{ +struct jtdev_func { /* Initialize/destroy a parallel-port JTAG interface. jtdev_open() * returns 0 on success or -1 if an error occurs. * diff --git a/drivers/mehfet.c b/drivers/mehfet.c index 30fa3c3..749cbfc 100644 --- a/drivers/mehfet.c +++ b/drivers/mehfet.c @@ -32,7 +32,6 @@ struct mehfet_device { - struct device base; struct jtdev jtag; transport_t trans; enum mehfet_conn connstat; @@ -384,7 +383,7 @@ static int mehfet_ctl(device_t dev_base, device_ctl_t type) printc_dbg("mehfet: set breakpoints\n"); #endif /* transfer changed breakpoints to device */ - if (jtag_refresh_bps("mehfet", &dev->base, &dev->jtag) < 0) return -1; + if (jtag_refresh_bps("mehfet", &dev->jtag.base, &dev->jtag) < 0) return -1; #ifdef DEBUG_MEHFET_DRIVER printc_dbg("mehfet: run @ current PC\n"); @@ -592,9 +591,9 @@ static device_t mehfet_open(const struct device_args* args) { return NULL; } - dev->base.type = &device_mehfet; - dev->base.max_breakpoints = 2; // TODO - dev->base.need_probe = 1; // TODO + 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 diff --git a/drivers/pif.c b/drivers/pif.c index 70bca8b..968fa9a 100644 --- a/drivers/pif.c +++ b/drivers/pif.c @@ -35,7 +35,6 @@ #include "ctrlc.h" struct pif_device { - struct device base; struct jtdev jtag; }; @@ -209,7 +208,7 @@ static int pif_ctl(device_t dev_base, device_ctl_t type) case DEVICE_CTL_RUN: /* transfer changed breakpoints to device */ - if (jtag_refresh_bps("pif", &dev->base, &dev->jtag) < 0) { + if (jtag_refresh_bps("pif", &dev->jtag.base, &dev->jtag) < 0) { return -1; } /* start program execution at current PC */ @@ -307,9 +306,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) { @@ -324,7 +323,7 @@ static device_t pif_open(const struct device_args *args) return NULL; } - return &dev->base; + return &dev->jtag.base; } /*----------------------------------------------------------------------------*/ @@ -351,8 +350,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) { @@ -367,7 +366,7 @@ static device_t gpio_open(const struct device_args *args) return NULL; } - return &dev->base; + return &dev->jtag.base; } /*----------------------------------------------------------------------------*/ @@ -394,9 +393,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) { @@ -411,7 +410,7 @@ static device_t bp_open(const struct device_args *args) return NULL; } - return &dev->base; + return &dev->jtag.base; } /*----------------------------------------------------------------------------*/