From 2373d33bbba24881f7bcb473003953921430c26a Mon Sep 17 00:00:00 2001 From: sys64738 Date: Sun, 31 Jul 2022 19:20:15 +0200 Subject: [PATCH] jtaglib: use context save/restore mechanism to keep track of registers etc. --- drivers/jtaglib.c | 127 +++++++++++++--- drivers/jtaglib.h | 16 ++ drivers/jtaglib_cpu16.c | 5 + drivers/jtaglib_cpuxv2.c | 316 ++++++++++++++++++++++++++++++--------- drivers/jtdev.h | 3 + 5 files changed, 381 insertions(+), 86 deletions(-) diff --git a/drivers/jtaglib.c b/drivers/jtaglib.c index 26171c9..fdeb832 100644 --- a/drivers/jtaglib.c +++ b/drivers/jtaglib.c @@ -45,6 +45,12 @@ #include "ctrlc.h" #include "device.h" +#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 + /* Reset target JTAG interface and perform fuse-HW check */ static void jtag_default_reset_tap(struct jtdev *p) { @@ -495,13 +501,17 @@ unsigned int jtag_init(struct jtdev *p) return 0; } - /* Perform PUC, includes target watchdog disable */ + /* Perform PUC */ if (jtag_execute_puc(p) != jtag_id) { printc_err("jtag_init: PUC failed\n"); p->failed = 1; return 0; } + /* reset watchdog so we can read TLV & device info */ + address_t wdtctl_a = (jtag_id == 0x89) ? 0x0120 : 0x015c; + jtag_write_mem(p, 16, wdtctl_a, 0x5a80); + return jtag_id; } @@ -537,8 +547,8 @@ int jtag_refresh_bps(device_t dev, struct jtdev *p) for (i = 0; i < dev->max_breakpoints; i++) { bp = &dev->breakpoints[i]; - printc_dbg("jtaglib: refresh breakpoint %d: type=%d " - "addr=%04x flags=%04x\n", i, bp->type, bp->addr, bp->flags); + dbg_printc("refresh breakpoint %d: type=%d addr=%04x flags=%04x\n", + i, bp->type, bp->addr, bp->flags); if ( (bp->flags & DEVICE_BP_DIRTY) && (bp->type == DEVICE_BPTYPE_BREAK) ) { @@ -562,6 +572,65 @@ int jtag_refresh_bps(device_t dev, struct jtdev *p) /* ========================================================================= */ +void jtag_dev_default_context_save(struct jtdev *p, bool after_puc) { + (void)after_puc; + + address_t wdtctl_a = (p->jtag_id == 0x89) ? 0x0120 : 0x015c; + + /* back up program counter */ + p->regs[0] = jtag_read_reg(p, 0); + + /* back up and disable watchdog */ + p->wdtctl = jtag_read_mem(p, 16, wdtctl_a); + jtag_write_mem(p, 16, wdtctl_a, p->wdtctl | 0x0080); + + /* also back up stack pointer & status register */ + p->regs[1] = jtag_read_reg(p, 1); + p->regs[2] = jtag_read_reg(p, 2); +} +void jtag_dev_default_context_restore(struct jtdev *p) { + /* 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); + + jtag_write_reg(p, 0, p->regs[0]); +} + +void jtag_dev_default_regs_update(struct jtdev *p) { + /* here, we only want to read sp and r4-r15 because the others behave + * slightly weird during JTAG ops. pc and sr are saved in context_save, + * cg doesn't really need anything because, well, it's cg. */ + p->regs[1] = jtag_read_reg(p, 1); + + for (int i = 4; i < DEVICE_NUM_REGS; ++i) { + p->regs[i] = jtag_read_reg(p, i); + } +} +void jtag_dev_default_regs_flush(struct jtdev *p) { + jtag_write_reg(p, 1, p->regs[1]); + + for (int i = 4; i < DEVICE_NUM_REGS; ++i) { + jtag_write_reg(p, i, p->regs[i]); + } +} + +void jtag_dev_context_save(struct jtdev *p, bool after_puc) { + get_jlf(p)->jlf_context_save(p, after_puc); +} +void jtag_dev_context_restore(struct jtdev *p) { + get_jlf(p)->jlf_context_restore(p); +} +void jtag_dev_regs_update(struct jtdev *p) { + get_jlf(p)->jlf_regs_update(p); +} +void jtag_dev_regs_flush(struct jtdev *p) { + get_jlf(p)->jlf_regs_flush(p); +} + static int write_flash_block(struct jtdev *p, address_t addr, address_t len, const uint8_t *data) { @@ -585,7 +654,7 @@ static int read_words(device_t dev_base, const struct chipinfo_memory *m, address_t addr, address_t len, uint8_t *data) { struct jtdev *p = (struct jtdev*)dev_base; - printc_dbg("jtaglib: read_words: ram: len=%d addr=%06x\n", len, addr); + dbg_printc("read_words: ram: len=%d addr=%06x\n", len, addr); if (len > 2 && !(len & 1)) { uint16_t* word = malloc((len>>1) * sizeof(*word)); if (!word) { @@ -618,7 +687,7 @@ static int write_words(device_t dev_base, const struct chipinfo_memory *m, int r; if (m->type != CHIPINFO_MEMTYPE_FLASH) { - printc_dbg("jtaglib: write_words: ram: len=%d addr=%06x\n", len, addr); + dbg_printc("write_words: ram: len=%d addr=%06x\n", len, addr); if ((len > 2) && !(len & 1)) { uint16_t* word = malloc((len>>1) * sizeof(*word)); if (!word) { @@ -691,23 +760,29 @@ int jtag_dev_erase(device_t dev_base, device_erase_type_t type, address_t addr) int jtag_dev_getregs(device_t dev_base, address_t *regs) { struct jtdev *p = (struct jtdev*)dev_base; - p->failed = 0; + memcpy(regs, p->regs, sizeof p->regs); + return 0; + + /*p->failed = 0; for (int i = 0; i < DEVICE_NUM_REGS; i++) { regs[i] = jtag_read_reg(p, i); } - return p->failed ? -1 : 0; + return p->failed ? -1 : 0;*/ } int jtag_dev_setregs(device_t dev_base, const address_t *regs) { struct jtdev *p = (struct jtdev*)dev_base; - p->failed = 0; + memcpy(p->regs, regs, sizeof p->regs); + return 0; + + /*p->failed = 0; for (int i = 0; i < DEVICE_NUM_REGS; i++) { jtag_write_reg(p, i, regs[i]); } - return p->failed ? -1 : 0; + return p->failed ? -1 : 0;*/ } int jtag_dev_ctl(device_t dev_base, device_ctl_t type) { @@ -719,25 +794,35 @@ int jtag_dev_ctl(device_t dev_base, device_ctl_t type) { case DEVICE_CTL_RESET: /* perform soft reset */ jtag_execute_puc(p); + jtag_dev_context_save(p, true); + jtag_dev_regs_update(p); break; case DEVICE_CTL_RUN: + jtag_dev_regs_flush(p); /* transfer changed breakpoints to device */ if (jtag_refresh_bps(&p->base, p) < 0) return -1; /* start program execution at current PC */ - jtag_release_device(p, 0xffff); + jtag_dev_context_restore(p); + jtag_release_device(p, p->regs[0]/*0xffff*/); break; case DEVICE_CTL_HALT: /* take device under JTAG control */ jtag_get_device(p); + jtag_dev_context_save(p, false); + jtag_dev_regs_update(p); break; case DEVICE_CTL_STEP: /* execute next instruction at current PC */ + jtag_dev_regs_flush(p); + jtag_dev_context_restore(p); jtag_single_step(p); + jtag_dev_context_save(p, false); + jtag_dev_regs_update(p); break; default: @@ -782,9 +867,10 @@ static int idproc_89(struct jtdev *p, uint32_t id_data_addr, struct chipinfo_id // read 8 words starting at id_data_addr // don't use read_mem_quick because we want to minimize the number of // functions that need special care before the device ID is read - for (int i = 0; i < sizeof(iddata)/sizeof(*iddata); ++i) { + /*for (int i = 0; i < sizeof(iddata)/sizeof(*iddata); ++i) { iddata[i] = jtag_read_mem(p, 16, id_data_addr + i*2); - } + }*/ + jtag_read_mem_quick(p, id_data_addr, 8, iddata); id->ver_id = iddata[0]; id->ver_sub_id = 0; @@ -815,9 +901,9 @@ static int idproc_9x(struct jtdev *p, uint32_t dev_id_ptr, struct chipinfo_id *i // need to use read_mem_quick because apparently it's the only one capable // of reading from TLV... jtag_read_mem_quick(p, dev_id_ptr, sizeof(iddata)/sizeof(*iddata), iddata); - /*for (int i = 0; i < 8; ++i) { - printc_dbg("TLV[%d] = %04x\n", i, iddata[i]); - }*/ + for (int i = 0; i < 8; ++i) { + dbg_printc("TLV[%d] = %04x\n", i, iddata[i]); + } info_len = iddata[0] & 0xff; id->ver_id = iddata[2]; @@ -828,7 +914,7 @@ static int idproc_9x(struct jtdev *p, uint32_t dev_id_ptr, struct chipinfo_id *i id->fuses = 0x55; if (info_len < 1 || info_len > 11) { - printc_dbg("jtaglib: idproc_9x: invalid info length %d\n", info_len); + dbg_printc("idproc_9x: invalid info length %d\n", info_len); return 0; } @@ -901,7 +987,10 @@ int jtag_dev_init(struct jtdev *p) { device_id = jtag_dr_shift_20(p, 0); //device_id = ((device_id & 0xffff) << 4) | (device_id >> 16); - printc_dbg("jtaglib: Xv2: core IP ID=%04x, device ID=%06x\n", + // FIXME: it looks like device_id contains a mangled version of the + // TLV start address (0x01a00), though the fallback code was + // already valid and still works, so, ... + dbg_printc("Xv2: core IP ID=%04x, device ID=%05x\n", core_ip_id, device_id); if (device_id != 0 && (device_id & 0xff) != 0x80) @@ -941,6 +1030,10 @@ int jtag_dev_init(struct jtdev *p) { p->base.chip = chip; } + jtag_execute_puc(p); + jtag_dev_context_save(p, true); /* jtag_init() performs a PUC */ + jtag_dev_regs_update(p); + return 0; } diff --git a/drivers/jtaglib.h b/drivers/jtaglib.h index 4747471..9cb9c82 100644 --- a/drivers/jtaglib.h +++ b/drivers/jtaglib.h @@ -34,6 +34,7 @@ #ifndef JTAGLIB_H_ #define JTAGLIB_H_ +#include #include #include "device.h" @@ -73,6 +74,11 @@ struct jtaglib_funcs { address_t bp_addr); unsigned int (*jlf_cpu_state)(struct jtdev *p); int (*jlf_get_config_fuses)(struct jtdev *p); + + void (*jlf_context_save)(struct jtdev *p, bool after_puc); + void (*jlf_context_restore)(struct jtdev *p); + void (*jlf_regs_update)(struct jtdev *p); + void (*jlf_regs_flush)(struct jtdev *p); }; extern const struct jtaglib_funcs jlf_cpu16; @@ -152,6 +158,11 @@ unsigned int jtag_set_breakpoint(struct jtdev *p, unsigned int jtag_cpu_state(struct jtdev *p); int jtag_get_config_fuses(struct jtdev *p); +void jtag_dev_context_save(struct jtdev *p, bool after_puc); +void jtag_dev_context_restore(struct jtdev *p); +void jtag_dev_regs_update(struct jtdev *p); +void jtag_dev_regs_flush(struct jtdev *p); + /* Default low-level JTAG routines for jtdev implementations that don't have * their own implementations of these routines */ uint8_t jtag_default_ir_shift(struct jtdev *p, uint8_t ir); @@ -161,6 +172,11 @@ uint32_t jtag_default_dr_shift_20(struct jtdev *p, uint32_t dr); void jtag_default_tms_sequence(struct jtdev *p, int bits, unsigned int value); void jtag_default_init_dap(struct jtdev *p); +void jtag_dev_default_context_save(struct jtdev *p, bool after_puc); +void jtag_dev_default_context_restore(struct jtdev *p); +void jtag_dev_default_regs_update(struct jtdev *p); +void jtag_dev_default_regs_flush(struct jtdev *p); + int jtag_refresh_bps(device_t dev, struct jtdev *p); int jtag_dev_readmem(device_t dev_base, address_t addr, uint8_t *mem, address_t len); diff --git a/drivers/jtaglib_cpu16.c b/drivers/jtaglib_cpu16.c index 989fbf3..4c51710 100644 --- a/drivers/jtaglib_cpu16.c +++ b/drivers/jtaglib_cpu16.c @@ -823,6 +823,11 @@ const struct jtaglib_funcs jlf_cpu16 = { .jlf_write_flash = jlf16_write_flash, .jlf_erase_flash = jlf16_erase_flash, + .jlf_context_save = jtag_dev_default_context_save, + .jlf_context_restore = jtag_dev_default_context_restore, + .jlf_regs_update = jtag_dev_default_regs_update, + .jlf_regs_flush = jtag_dev_default_regs_flush, + .jlf_read_reg = jlf16_read_reg, .jlf_write_reg = jlf16_write_reg, .jlf_single_step = jlf16_single_step, diff --git a/drivers/jtaglib_cpuxv2.c b/drivers/jtaglib_cpuxv2.c index 523a496..996a94c 100644 --- a/drivers/jtaglib_cpuxv2.c +++ b/drivers/jtaglib_cpuxv2.c @@ -7,12 +7,23 @@ #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: -// * read reg (nonsense values) -// * write reg? +// * 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 -// * other stuff? -// * single step: check if it works +// * 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) @@ -35,13 +46,47 @@ static int jlfxv2_check_full_emu_state_ex(struct jtdev *p, const char* fnname) } #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; -static void jlfxv2_set_pc(struct jtdev *p, address_t addr) + 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) { - printc_dbg("set pc %06x\n", addr); + address_t addr_rb; - jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); - jtag_dr_shift_16(p, 0); + 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); @@ -62,8 +107,25 @@ static void jlfxv2_set_pc(struct jtdev *p, address_t addr) jtag_dr_shift_16(p, 0x4303); jtag_tclk_clr(p); jtag_ir_shift(p, IR_ADDR_CAPTURE); - jtag_dr_shift_20(p, 0); + 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 @@ -84,7 +146,7 @@ static int jlfxv2_verify_mem(struct jtdev *p, jtag_execute_puc(p); crc = start_address - 2; - jlfxv2_set_pc(p, start_address); + if (jlfxv2_set_pc(p, start_address) < 0) return -1; jtag_tclk_set(p); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); @@ -132,6 +194,7 @@ static unsigned int jlfxv2_get_device(struct jtdev *p) 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); @@ -163,6 +226,7 @@ static uint16_t jlfxv2_read_mem(struct jtdev *p, unsigned int format, address_t { // SLAU320AJ name: ReadMem uint16_t r = 0; + dbg_printc("read mem %05x\n", address); if (!jlfxv2_check_full_emu_state(p)) return 0; @@ -176,13 +240,12 @@ static uint16_t jlfxv2_read_mem(struct jtdev *p, unsigned int format, address_t /*//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_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); - jtag_ir_shift(p, IR_DATA_TO_ADDR); + 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); @@ -193,7 +256,10 @@ static uint16_t jlfxv2_read_mem(struct jtdev *p, unsigned int format, address_t jtag_tclk_clr(p); jtag_tclk_set(p); - return r;*/ + 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 @@ -204,13 +270,11 @@ static uint16_t jlfxv2_read_mem(struct jtdev *p, unsigned int format, address_t static void jlfxv2_read_mem_quick(struct jtdev *p, address_t address, unsigned int length, uint16_t *data) { // SLAU320AJ name: ReadMemQuick - address_t pc_bak; - if (!jlfxv2_check_full_emu_state(p)) return; - //pc_bak = jlfxv2_read_reg(p, 0); // FIXME - jlfxv2_set_pc(p, address); + 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); @@ -233,8 +297,6 @@ static void jlfxv2_read_mem_quick(struct jtdev *p, address_t address, jtag_dr_shift_16(p, 0x0501); jtag_tclk_set(p); jtag_ir_shift(p, IR_ADDR_CAPTURE); - - //jlfxv2_write_reg(p, 0, pc_bak); // FIXME } static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address, @@ -248,7 +310,7 @@ static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address, static void jlfxv2_write_mem(struct jtdev *p, unsigned int format, address_t address, uint16_t data) { // SLAU320AJ name: WriteMem - printc_dbg("jlfxv2 write mem: %d %06x <- %04x\n", format, address, data); + dbg_printc("write mem: %d %06x <- %04x\n", format, address, data); if (format == 8) { p->failed = 1; @@ -259,13 +321,13 @@ static void jlfxv2_write_mem(struct jtdev *p, unsigned int format, // same story as with read_mem jlfxv2_write_mem_quick(p, address, 1, &data); - /*if (!jlfxv2_check_full_emu_state(p)) + if (!jlfxv2_check_full_emu_state(p)) return; - jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); + /*jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); uint16_t dr = jtag_dr_shift_16(p, 0); - printc_dbg("write mem %d: %06x<-%04x: dr=%04x\n", format, address, data, dr); + 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); @@ -292,17 +354,16 @@ static void jlfxv2_write_mem(struct jtdev *p, unsigned int format, static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address, unsigned int length, const uint16_t *data) { // SLAU320AJ name: WriteMemQuick - uint16_t pc_bak; - /*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; - //pc_bak = jlfxv2_read_reg(p, 0); // FIXME - jlfxv2_set_pc(p, address); + 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); @@ -325,8 +386,6 @@ static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address, jtag_dr_shift_16(p, 0x0501); jtag_tclk_set(p); jtag_ir_shift(p, IR_ADDR_CAPTURE); - - //jlfxv2_write_reg(p, 0, pc_bak); } /* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register @@ -336,6 +395,13 @@ 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 @@ -346,52 +412,48 @@ static unsigned int jlfxv2_execute_puc(struct jtdev *p) /* Apply and remove reset */ jtag_dr_shift_16(p, 0x0C01); + delay_ms(40); jtag_dr_shift_16(p, 0x0401); - if (jtag_id == 0x91) { // TODO: is this correct? - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); // two more cycles to release CPU internal POR delay signals - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - } else { // FRAM + 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); + + 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); - jtag_write_mem(p, 16, 0x015c, 0x5a80); // disable WDT - // TODO: disable WDT - // Disable Watchdog Timer on target device now by setting the HOLD signal - // in the WDT_CNTRL register (i.e. by using WriteMem_430Xv2 – note - // different WDT addresses for individual FRAM device groups) - // - // Initialize Test Memory with default values to ensure consistency between - // PC value and MAB (MAB is +2 after sync) – Use WriteMem_430Xv2 to write - // 0x3FFF to addresses 0x06 and 0x08 (this is only applicable for devices - // with JTAG ID 0x91 or 0x99) - return jtag_id; } @@ -406,22 +468,38 @@ 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; } @@ -436,6 +514,7 @@ static void jlfxv2_release_device(struct jtdev *p, address_t address) 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 @@ -447,6 +526,7 @@ static void jlfxv2_write_flash(struct jtdev *p, address_t start_address, 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 */ @@ -456,9 +536,9 @@ static address_t jlfxv2_read_reg(struct jtdev *p, int reg) uint16_t jtag_id, jmb_addr; const bool alt_addr = false;//true; - if (reg == 2 || reg == 3) return 0; // CG + if (reg == 3) return 0; // CG - printc_dbg("read reg %d\n", reg); + dbg_printc("read reg %d\n", reg); if (!jlfxv2_check_full_emu_state(p)) return 0; @@ -511,7 +591,7 @@ static address_t jlfxv2_read_reg(struct jtdev *p, int reg) jtag_ir_shift(p, IR_DATA_CAPTURE); jtag_tclk_set(p); - printc_dbg("read reg %d: lo=%04x hi=%04x\n", reg, reglo, reghi); + 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); @@ -525,8 +605,11 @@ static address_t jlfxv2_read_reg(struct jtdev *p, int reg) /* 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 - jlfxv2_check_full_emu_state(p); - printc_dbg("write reg %d %06x\n", reg, value); + 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);*/ @@ -556,7 +639,7 @@ static void jlfxv2_write_reg(struct jtdev *p, int reg, address_t value) jtag_tclk_set(p); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift_16(p, /*0x4303*/0x0501); // insert NOP to be prefetched by the CPU + jtag_dr_shift_16(p, 0x0501); jtag_tclk_clr(p); jtag_tclk_set(p); jtag_tclk_clr(p); @@ -572,7 +655,9 @@ static void jlfxv2_single_step( struct jtdev *p ) int i, timeout; uint16_t tmp; - printc_dbg("jlfxv2: single step\n"); + 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; @@ -655,20 +740,21 @@ static unsigned int jlfxv2_set_breakpoint( struct jtdev *p,int bp_num, address_t /* 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(?) - // TODO: does this need an update? jtag_ir_shift(p, IR_EMEX_READ_CONTROL); if ((jtag_dr_shift_16(p, 0x0000) & EEM_STOPPED) == EEM_STOPPED) { - printc_dbg("jlfxv2_cpu_state: halted\n"); + dbg_printc("cpu_state: halted\n"); return 1; /* halted */ } else { - printc_dbg("jlfxv2_cpu_state: running\n"); + dbg_printc("cpu_state: running\n"); return 0; /* running */ } } @@ -676,7 +762,6 @@ static unsigned int jlfxv2_cpu_state( struct jtdev *p ) /*----------------------------------------------------------------------------*/ static int jlfxv2_get_config_fuses( struct jtdev *p ) { // always the same? - // TODO: does this need an update? jtag_ir_shift(p, IR_CONFIG_FUSES); return jtag_dr_shift_8(p, 0); @@ -684,6 +769,94 @@ static int jlfxv2_get_config_fuses( struct jtdev *p ) /* ------------------------------------------------------------------------- */ +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); + 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); + dbg_printc("WDTCTL: %04x\n", p->wdtctl); + jtag_write_mem(p, 16, wdtctl_a, p->wdtctl | 0x0080); + + /* 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); + + jlfxv2_set_pc(p, p->regs[0]); +} + +/* ------------------------------------------------------------------------- */ + const struct jtaglib_funcs jlf_cpuxv2 = { .jlf_get_device = jlfxv2_get_device, @@ -701,6 +874,11 @@ const struct jtaglib_funcs jlf_cpuxv2 = { .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, diff --git a/drivers/jtdev.h b/drivers/jtdev.h index 0633e3a..c3f2471 100644 --- a/drivers/jtdev.h +++ b/drivers/jtdev.h @@ -35,6 +35,9 @@ struct jtdev { uint8_t cpu_type; int failed; const struct jtdev_func * f; + + address_t regs[DEVICE_NUM_REGS]; + uint16_t wdtctl; }; struct jtdev_func {