#include #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, };