/* MSPDebug - debugging tool for MSP430 MCUs * Copyright (C) 2009-2012 Daniel Beer * Copyright (C) 2012 Peter Bägel * * 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 */ /* jtag functions are taken from TIs SLAA149–September 2002 * * 2012-10-03 Peter Bägel (DF5EQ) */ /*===== includes =============================================================*/ #include #include "jtaglib.h" #include "output.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 */ /* Bypass instruction */ #define IR_BYPASS 0xFF /* 0xFF */ #define jtag_tms_set(p) jtdev_tms(p, 1) #define jtag_tms_clr(p) jtdev_tms(p, 0) #define jtag_tck_set(p) jtdev_tck(p, 1) #define jtag_tck_clr(p) jtdev_tck(p, 0) #define jtag_tdi_set(p) jtdev_tdi(p, 1) #define jtag_tdi_clr(p) jtdev_tdi(p, 0) #define jtag_tclk_set(p) jtdev_tclk(p, 1) #define jtag_tclk_clr(p) jtdev_tclk(p, 0) #define jtag_rst_set(p) jtdev_rst(p, 1) #define jtag_rst_clr(p) jtdev_rst(p, 0) #define jtag_tst_set(p) jtdev_tst(p, 1) #define jtag_tst_clr(p) jtdev_tst(p, 0) #define jtag_led_green_on(p) jtdev_led_green(p, 1) #define jtag_led_green_off(p) jtdev_led_green(p, 0) #define jtag_led_red_on(p) jtdev_led_red(p, 1) #define jtag_led_red_off(p) jtdev_led_red(p, 0) /*----------------------------------------------------------------------------*/ static void jtag_reset_tap(struct jtdev *p) /* Reset target JTAG interface and perform fuse-HW check */ { int loop_counter; jtag_tms_set(p); jtag_tck_set(p); /* perform fuse check */ jtag_tms_clr(p); jtag_tms_set(p); jtag_tms_clr(p); jtag_tms_set(p); /* reset JTAG state machine */ for (loop_counter = 6; loop_counter > 0; loop_counter--) { jtag_tck_clr(p); jtag_tck_set(p); if (p->failed) return; } /* set JTAG state machine to Run-Test/IDLE */ jtag_tck_clr(p); jtag_tms_clr(p); jtag_tck_set(p); } /*----------------------------------------------------------------------------*/ static void jtag_tclk_prep (struct jtdev *p) /* This function sets the target JTAG state machine */ /* back into the Run-Test/Idle state after a shift access */ { /* JTAG state = Exit-DR */ jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Update-DR */ jtag_tms_clr(p); jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Run-Test/Idle */ } /*----------------------------------------------------------------------------*/ static unsigned int jtag_shift( struct jtdev *p, unsigned char number_of_bits, unsigned int data_out ) /* shift a value into TDI (MSB first) and simultaneously */ /* shift out a value from TDO (MSB first) */ /* number_of_bits: number of bits to shift */ /* data_out : data to be shifted out */ /* return : scanned TDO value */ { unsigned int data_in; unsigned int mask; unsigned int tclk_save; tclk_save = jtdev_tclk_get(p); data_in = 0; for (mask = (unsigned int)0x0001 << (number_of_bits-1); mask != 0; mask >>= 1) { if ((data_out & mask) != 0) { jtag_tdi_set(p); } else { jtag_tdi_clr(p); } if (mask == 1) { jtag_tms_set(p); } jtag_tck_clr(p); jtag_tck_set(p); if (jtdev_tdo_get(p) == 1) { data_in |= mask; } } jtdev_tclk(p, tclk_save); /* Set JTAG state back to Run-Test/Idle */ jtag_tclk_prep(p); return data_in; } /*----------------------------------------------------------------------------*/ static unsigned int jtag_ir_shift(struct jtdev *p, unsigned int instruction) /* shifts a new instruction into the JTAG instruction register through TDI */ /* MSB first, with interchanged MSB/LSB, to use the shifting function */ /* instruction: 8 bit instruction */ /* return : scanned TDO value */ { /* JTAG state = Run-Test/Idle */ jtag_tms_set(p); jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Select DR-Scan */ jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Select IR-Scan */ jtag_tms_clr(p); jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Capture-IR */ jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Shift-IR, Shift in TDI (8-bit) */ return jtag_shift(p, 8, instruction); /* JTAG state = Run-Test/Idle */ } /*----------------------------------------------------------------------------*/ static unsigned int jtag_dr_shift( struct jtdev *p, unsigned int data ) /* shifts a given 16-bit word into the JTAG data register through TDI. */ /* data : 16 bit data */ /* return: scanned TDO value */ { /* JTAG state = Run-Test/Idle */ jtag_tms_set(p); jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Select DR-Scan */ jtag_tms_clr(p); jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Capture-DR */ jtag_tck_clr(p); jtag_tck_set(p); /* JTAG state = Shift-DR, Shift in TDI (16-bit) */ return jtag_shift(p, 16, data); /* JTAG state = Run-Test/Idle */ } /*----------------------------------------------------------------------------*/ static int jtag_set_instruction_fetch(struct jtdev *p) /* set target CPU JTAG state machine into the instruction fetch state */ /* return: 1 - instruction fetch was set */ /* 0 - otherwise */ { 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(p, 0x0000) & 0x0080) == 0x0080) { return 1; } jtag_tclk_clr(p); /* the TCLK pulse befor jtag_dr_shift 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; } /*----------------------------------------------------------------------------*/ static void jtag_halt_cpu(struct jtdev *p) /* set the CPU into a controlled stop state */ { /* set CPU into instruction fetch mode */ jtag_set_instruction_fetch(p); /* set device into JTAG mode + read */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x2401); /* send JMP $ instruction to keep CPU from changing the state */ jtag_ir_shift(p, IR_DATA_16BIT); jtag_dr_shift(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(p, 0x2409); jtag_tclk_set(p); } /*----------------------------------------------------------------------------*/ static void jtag_release_cpu(struct jtdev *p) /* release the target CPU from the controlled stop state */ { jtag_tclk_clr(p); /* clear the HALT_JTAG bit */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x2401); jtag_ir_shift(p, IR_ADDR_CAPTURE); jtag_tclk_set(p); } /*----------------------------------------------------------------------------*/ static int jtag_verify_psa( struct jtdev *p, unsigned int start_address, unsigned int length, const uint16_t *data ) /* 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 */ { 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(p, 0x2401); jtag_set_instruction_fetch(p); jtag_ir_shift(p, IR_DATA_16BIT); jtag_dr_shift(p, 0x4030); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_dr_shift(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(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); jtag_tck_clr(p); jtag_tms_set(p); jtag_tck_set(p); /* select DR scan */ jtag_tck_clr(p); jtag_tms_clr(p); jtag_tck_set(p); /* capture DR */ jtag_tck_clr(p); jtag_tck_set(p); /* shift DR */ jtag_tck_clr(p); jtag_tms_set(p); jtag_tck_set(p); /* exit DR */ jtag_tck_clr(p); jtag_tck_set(p); jtag_tms_clr(p); jtag_tck_clr(p); jtag_tck_set(p); jtag_tclk_clr(p); } /* read out the PSA value */ jtag_ir_shift(p, IR_SHIFT_OUT_PSA); psa_value = jtag_dr_shift(p, 0x0000); jtag_tclk_set(p); return (psa_value == psa_crc) ? 1 : 0; } /*===== public functions =====================================================*/ unsigned int jtag_init (struct jtdev *p) /* Take target device under JTAG control. */ /* Disable the target watchdog. */ /* return: 0 - fuse is blown */ /* >0 - jtag id */ { unsigned int jtag_id; jtag_rst_clr(p); jtdev_power_on(p); jtag_tst_set(p); jtag_tdi_set(p); jtag_tms_set(p); jtag_tck_set(p); jtag_tclk_set(p); jtag_rst_clr(p); jtdev_connect(p); jtag_rst_set(p); jtag_reset_tap(p); /* check fuse */ if (jtag_is_fuse_blown(p)) { printc_err("jtag_init: fuse is blown\n"); p->failed = 1; return 0; } /* Set device into JTAG mode */ jtag_id = jtag_get_device(p); if ( jtag_id == 0 ) { printc_err("jtag_init: invalid jtag_id: 0x%02x\n", jtag_id); p->failed = 1; return 0; } /* Perform PUC, includes target watchdog disable */ if ( jtag_execute_puc(p) != jtag_id ) { printc_err("jtag_init: PUC failed\n"); p->failed = 1; return 0; } 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(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 && ((jtag_dr_shift(p, 0x0000) & 0x0200) != 0x0200); loop_counter--); 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; } /*----------------------------------------------------------------------------*/ unsigned int jtag_chip_id(struct jtdev *p) /* Read the target chip id. */ /* return: chip id */ { 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; } /*----------------------------------------------------------------------------*/ uint16_t jtag_read_mem( struct jtdev *p, unsigned int format, address_t address ) /* reads one byte/word from a given address */ /* format : 8-byte, 16-word */ /* address: address of memory */ /* return : content of memory */ { 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(p, 0x2409); } else { /* set byte read */ jtag_dr_shift(p, 0x2419); } /* set address */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(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(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; } /*----------------------------------------------------------------------------*/ void jtag_read_mem_quick( struct jtdev *p, address_t address, unsigned int length, uint16_t *data ) /* reads an array of words from target memory */ /* address: address to read from */ /* length : number of word to read */ /* data : memory to write to */ { 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(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(p, 0x0000); } jtag_tclk_set(p); jtag_release_cpu(p); } /*----------------------------------------------------------------------------*/ void jtag_write_mem( struct jtdev *p, unsigned int format, address_t address, 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 */ { 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(p, 0x2408); } else { /* set byte write */ jtag_dr_shift(p, 0x2418); } jtag_ir_shift(p, IR_ADDR_16BIT); /* set addr */ jtag_dr_shift(p, address); jtag_ir_shift(p, IR_DATA_TO_ADDR); /* shift in 16 bits */ jtag_dr_shift(p, data); jtag_tclk_set(p); jtag_release_cpu(p); } /*----------------------------------------------------------------------------*/ void jtag_write_mem_quick( struct jtdev *p, address_t address, unsigned int length, const uint16_t *data ) /* writes an array of words into target memory */ /* address: address to write to */ /* length : number of word to write */ /* data : data to write */ { 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(p, 0x2408); jtag_ir_shift(p, IR_DATA_QUICK); for (index = 0; index < length; index++) { /* write data */ jtag_dr_shift(p, data[index]); /* increment PC by 2 */ jtag_tclk_set(p); jtag_tclk_clr(p); } jtag_tclk_set(p); jtag_release_cpu(p); } /*----------------------------------------------------------------------------*/ int jtag_is_fuse_blown (struct jtdev *p) /* This function checks if the JTAG access security fuse is blown */ /* return: 1 - fuse is blown */ /* 0 - otherwise */ { unsigned int loop_counter; /* First trial could be wrong */ for (loop_counter = 3; loop_counter > 0; loop_counter--) { jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); if (jtag_dr_shift(p, 0xAAAA) == 0x5555) { /* Fuse is blown */ return 1; } } /* fuse is not blown */ return 0; } /*----------------------------------------------------------------------------*/ unsigned int jtag_execute_puc(struct jtdev *p) /* execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register */ /* return: JTAG ID */ { unsigned int jtag_id; jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); /* apply and remove reset */ jtag_dr_shift(p, 0x2C01); jtag_dr_shift(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; } /*----------------------------------------------------------------------------*/ void jtag_release_device( struct jtdev *p, address_t address ) /* 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 */ { jtag_led_green_off(p); switch (address) { case 0xffff: /* nothing to do */ break; case 0xfffe: /* perform reset */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x2C01); jtag_dr_shift(p, 0x2401); break; default: /* set target CPU's PC */ jtag_write_reg(p, 0, address); break; } jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE); } /*----------------------------------------------------------------------------*/ int jtag_verify_mem( struct jtdev *p, address_t start_address, unsigned int length, const uint16_t *data ) /* performs a verification over the given memory range */ /* return: 1 - verification was successful */ /* 0 - otherwise */ { return jtag_verify_psa( p, start_address, length, data ); } /*----------------------------------------------------------------------------*/ int jtag_erase_check( struct jtdev *p, address_t start_address, unsigned int length ) /* performs an erase check over the given memory range */ /* return: 1 - erase check was successful */ /* 0 - otherwise */ { return jtag_verify_psa (p, start_address, length, NULL); } /*----------------------------------------------------------------------------*/ void jtag_write_flash( struct jtdev *p, address_t start_address, unsigned int length, const uint16_t *data ) /* 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 */ { 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(p, 0x2408); /* FCTL1 register */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x0128); /* enable FLASH write */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(p, 0xA540); jtag_tclk_set(p); jtag_tclk_clr(p); /* FCTL2 register */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x012A); /* select MCLK as source, DIV=1 */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(p, 0xA540); jtag_tclk_set(p); jtag_tclk_clr(p); /* FCTL3 register */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x012C); /* clear FCTL3 register */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(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(p, 0x2408); /* set address */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, address); /* set data */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(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(p, 0x2409); /* provide TCLKs */ /* min. 33 for F149 and F449 */ 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(p, 0x2408); /* FCTL1 register */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x0128); /* disable FLASH write */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(p, 0xA500); jtag_tclk_set(p); jtag_release_cpu(p); jtag_led_red_off(p); } /*----------------------------------------------------------------------------*/ void jtag_erase_flash( struct jtdev *p, unsigned int erase_mode, address_t erase_address ) /* 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 */ { 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(p, 0x2408); /* FCTL1 address */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x0128); /* enable erase mode */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(p, erase_mode); jtag_tclk_set(p); jtag_tclk_clr(p); /* FCTL2 address */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x012A); /* MCLK is source, DIV=1 */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(p, 0xA540); jtag_tclk_set(p); jtag_tclk_clr(p); /* FCTL3 address */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x012C); /* clear FCTL3 */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(p, 0xA500); jtag_tclk_set(p); jtag_tclk_clr(p); /* set erase address */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, erase_address); /* dummy write to start erase */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(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(p, 0x2409); /* provide TCLKs */ jtdev_tclk_strobe(p, number_of_strobes); /* set RW to write */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x2408); /* FCTL1 address */ jtag_ir_shift(p, IR_ADDR_16BIT); jtag_dr_shift(p, 0x0128); /* disable erase */ jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift(p, 0xA500); jtag_tclk_set(p); jtag_release_cpu(p); } jtag_led_red_off(p); } /*----------------------------------------------------------------------------*/ address_t jtag_read_reg( struct jtdev *p, int reg ) /* reads a register from the target CPU */ { unsigned int value; /* CPU controls RW & BYTE */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x3401); /* set CPU into instruction fetch mode */ jtag_set_instruction_fetch(p); jtag_ir_shift(p, IR_DATA_16BIT); /* "sub #8,PC" instruction */ /* PC - 8 -> PC */ /* PC is advanced 4 bytes by this instruction */ /* needs 3 clock cycles */ jtag_dr_shift(p, 0x8030); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_dr_shift(p, 0x0008); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_tclk_set(p); jtag_tclk_clr(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(p, 0x4082 | (((unsigned int)reg << 8) & 0x0f00) ); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_dr_shift(p, 0x01fe); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_tclk_set(p); jtag_tclk_clr(p); /* read databus which contains the registers value */ jtag_ir_shift(p, IR_DATA_CAPTURE); value = jtag_dr_shift(p, 0x0000); /* JTAG controls RW & BYTE */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x2401); /* return value read from register */ return value; } /*----------------------------------------------------------------------------*/ void jtag_write_reg( struct jtdev *p, int reg, address_t value ) /* writes a value into a register of the target CPU */ { /* CPU controls RW & BYTE */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x3401); /* set CPU into instruction fetch mode */ jtag_set_instruction_fetch(p); jtag_ir_shift(p, IR_DATA_16BIT); /* "sub #8,PC" instruction */ /* PC-8 -> PC */ /* PC is advanced 4 bytes by this instruction */ /* needs 3 clock cycles */ jtag_dr_shift(p, 0x8030); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_dr_shift(p, 0x0008); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_tclk_set(p); jtag_tclk_clr(p); /* "mov #value,Rn" instruction */ /* value -> Rn */ /* PC is advanced 4 bytes by this instruction */ /* needs 2 clock cycles */ jtag_dr_shift(p, 0x4030 | (reg & 0x000f) ); jtag_tclk_set(p); jtag_tclk_clr(p); jtag_dr_shift(p, reg==0 ? value-4 : value ); jtag_tclk_set(p); jtag_tclk_clr(p); /* JTAG controls RW & BYTE */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift(p, 0x2401); }