jtaglib: use context save/restore mechanism to keep track of registers etc.

This commit is contained in:
Triss 2022-07-31 19:20:15 +02:00
parent 8ddf3cb68c
commit 2373d33bbb
5 changed files with 381 additions and 86 deletions

View File

@ -45,6 +45,12 @@
#include "ctrlc.h" #include "ctrlc.h"
#include "device.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 */ /* Reset target JTAG interface and perform fuse-HW check */
static void jtag_default_reset_tap(struct jtdev *p) static void jtag_default_reset_tap(struct jtdev *p)
{ {
@ -495,13 +501,17 @@ unsigned int jtag_init(struct jtdev *p)
return 0; return 0;
} }
/* Perform PUC, includes target watchdog disable */ /* Perform PUC */
if (jtag_execute_puc(p) != jtag_id) { if (jtag_execute_puc(p) != jtag_id) {
printc_err("jtag_init: PUC failed\n"); printc_err("jtag_init: PUC failed\n");
p->failed = 1; p->failed = 1;
return 0; 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; 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++) { for (i = 0; i < dev->max_breakpoints; i++) {
bp = &dev->breakpoints[i]; bp = &dev->breakpoints[i];
printc_dbg("jtaglib: refresh breakpoint %d: type=%d " dbg_printc("refresh breakpoint %d: type=%d addr=%04x flags=%04x\n",
"addr=%04x flags=%04x\n", i, bp->type, bp->addr, bp->flags); i, bp->type, bp->addr, bp->flags);
if ( (bp->flags & DEVICE_BP_DIRTY) && if ( (bp->flags & DEVICE_BP_DIRTY) &&
(bp->type == DEVICE_BPTYPE_BREAK) ) { (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, static int write_flash_block(struct jtdev *p, address_t addr,
address_t len, const uint8_t *data) 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) { address_t addr, address_t len, uint8_t *data) {
struct jtdev *p = (struct jtdev*)dev_base; 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)) { if (len > 2 && !(len & 1)) {
uint16_t* word = malloc((len>>1) * sizeof(*word)); uint16_t* word = malloc((len>>1) * sizeof(*word));
if (!word) { if (!word) {
@ -618,7 +687,7 @@ static int write_words(device_t dev_base, const struct chipinfo_memory *m,
int r; int r;
if (m->type != CHIPINFO_MEMTYPE_FLASH) { 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)) { if ((len > 2) && !(len & 1)) {
uint16_t* word = malloc((len>>1) * sizeof(*word)); uint16_t* word = malloc((len>>1) * sizeof(*word));
if (!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) { int jtag_dev_getregs(device_t dev_base, address_t *regs) {
struct jtdev *p = (struct jtdev*)dev_base; 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++) { for (int i = 0; i < DEVICE_NUM_REGS; i++) {
regs[i] = jtag_read_reg(p, 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) { int jtag_dev_setregs(device_t dev_base, const address_t *regs) {
struct jtdev *p = (struct jtdev*)dev_base; 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++) { for (int i = 0; i < DEVICE_NUM_REGS; i++) {
jtag_write_reg(p, i, 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) { 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: case DEVICE_CTL_RESET:
/* perform soft reset */ /* perform soft reset */
jtag_execute_puc(p); jtag_execute_puc(p);
jtag_dev_context_save(p, true);
jtag_dev_regs_update(p);
break; break;
case DEVICE_CTL_RUN: case DEVICE_CTL_RUN:
jtag_dev_regs_flush(p);
/* transfer changed breakpoints to device */ /* transfer changed breakpoints to device */
if (jtag_refresh_bps(&p->base, p) < 0) if (jtag_refresh_bps(&p->base, p) < 0)
return -1; return -1;
/* start program execution at current PC */ /* 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; break;
case DEVICE_CTL_HALT: case DEVICE_CTL_HALT:
/* take device under JTAG control */ /* take device under JTAG control */
jtag_get_device(p); jtag_get_device(p);
jtag_dev_context_save(p, false);
jtag_dev_regs_update(p);
break; break;
case DEVICE_CTL_STEP: case DEVICE_CTL_STEP:
/* execute next instruction at current PC */ /* execute next instruction at current PC */
jtag_dev_regs_flush(p);
jtag_dev_context_restore(p);
jtag_single_step(p); jtag_single_step(p);
jtag_dev_context_save(p, false);
jtag_dev_regs_update(p);
break; break;
default: 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 // read 8 words starting at id_data_addr
// don't use read_mem_quick because we want to minimize the number of // 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 // 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); 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_id = iddata[0];
id->ver_sub_id = 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 // need to use read_mem_quick because apparently it's the only one capable
// of reading from TLV... // of reading from TLV...
jtag_read_mem_quick(p, dev_id_ptr, sizeof(iddata)/sizeof(*iddata), iddata); jtag_read_mem_quick(p, dev_id_ptr, sizeof(iddata)/sizeof(*iddata), iddata);
/*for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
printc_dbg("TLV[%d] = %04x\n", i, iddata[i]); dbg_printc("TLV[%d] = %04x\n", i, iddata[i]);
}*/ }
info_len = iddata[0] & 0xff; info_len = iddata[0] & 0xff;
id->ver_id = iddata[2]; 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; id->fuses = 0x55;
if (info_len < 1 || info_len > 11) { 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; return 0;
} }
@ -901,7 +987,10 @@ int jtag_dev_init(struct jtdev *p) {
device_id = jtag_dr_shift_20(p, 0); device_id = jtag_dr_shift_20(p, 0);
//device_id = ((device_id & 0xffff) << 4) | (device_id >> 16); //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); core_ip_id, device_id);
if (device_id != 0 && (device_id & 0xff) != 0x80) if (device_id != 0 && (device_id & 0xff) != 0x80)
@ -941,6 +1030,10 @@ int jtag_dev_init(struct jtdev *p) {
p->base.chip = chip; 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; return 0;
} }

View File

@ -34,6 +34,7 @@
#ifndef JTAGLIB_H_ #ifndef JTAGLIB_H_
#define JTAGLIB_H_ #define JTAGLIB_H_
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "device.h" #include "device.h"
@ -73,6 +74,11 @@ struct jtaglib_funcs {
address_t bp_addr); address_t bp_addr);
unsigned int (*jlf_cpu_state)(struct jtdev *p); unsigned int (*jlf_cpu_state)(struct jtdev *p);
int (*jlf_get_config_fuses)(struct jtdev *p); int (*jlf_get_config_fuses)(struct jtdev *p);
void (*jlf_context_save)(struct jtdev *p, bool after_puc);
void (*jlf_context_restore)(struct jtdev *p);
void (*jlf_regs_update)(struct jtdev *p);
void (*jlf_regs_flush)(struct jtdev *p);
}; };
extern const struct jtaglib_funcs jlf_cpu16; extern const struct jtaglib_funcs jlf_cpu16;
@ -152,6 +158,11 @@ unsigned int jtag_set_breakpoint(struct jtdev *p,
unsigned int jtag_cpu_state(struct jtdev *p); unsigned int jtag_cpu_state(struct jtdev *p);
int jtag_get_config_fuses(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 /* Default low-level JTAG routines for jtdev implementations that don't have
* their own implementations of these routines */ * their own implementations of these routines */
uint8_t jtag_default_ir_shift(struct jtdev *p, uint8_t ir); 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_tms_sequence(struct jtdev *p, int bits, unsigned int value);
void jtag_default_init_dap(struct jtdev *p); 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_refresh_bps(device_t dev, struct jtdev *p);
int jtag_dev_readmem(device_t dev_base, address_t addr, uint8_t *mem, address_t len); int jtag_dev_readmem(device_t dev_base, address_t addr, uint8_t *mem, address_t len);

View File

@ -823,6 +823,11 @@ const struct jtaglib_funcs jlf_cpu16 = {
.jlf_write_flash = jlf16_write_flash, .jlf_write_flash = jlf16_write_flash,
.jlf_erase_flash = jlf16_erase_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_read_reg = jlf16_read_reg,
.jlf_write_reg = jlf16_write_reg, .jlf_write_reg = jlf16_write_reg,
.jlf_single_step = jlf16_single_step, .jlf_single_step = jlf16_single_step,

View File

@ -7,12 +7,23 @@
#define SAFE_FRAM_PC 0x0004 #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: // FIXME:
// * read reg (nonsense values) // * context save/restore:
// * write reg? // * 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 // * implement flash write, erase, verify stuff
// * other stuff? // * check how ^ works in practice on flash & FRAM devices
// * single step: check if it works // * single step: not working!
// * breakpoints are a big TODO // * breakpoints are a big TODO
static int jlfxv2_check_full_emu_state_ex(struct jtdev *p, const char* fnname) 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__) #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); dbg_printc("set pc %05x\n", addr);
jtag_dr_shift_16(p, 0);
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_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_16BIT); 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_dr_shift_16(p, 0x4303);
jtag_tclk_clr(p); jtag_tclk_clr(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE); 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 /* 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 * 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); jtag_execute_puc(p);
crc = start_address - 2; 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_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); 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; unsigned int jtag_id = 0;
int i; int i;
dbg_printc("jlfxv2: get_device\n");
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x1501); 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 { // SLAU320AJ name: ReadMem
uint16_t r = 0; uint16_t r = 0;
dbg_printc("read mem %05x\n", address);
if (!jlfxv2_check_full_emu_state(p)) if (!jlfxv2_check_full_emu_state(p))
return 0; 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); /*//jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
//uint16_t dr = jtag_dr_shift_16(p, 0); //uint16_t dr = jtag_dr_shift_16(p, 0);
jtag_tclk_clr(p); jtag_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); //jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, (format == 16) ? 0x0501 : 0x0511); //jtag_dr_shift_16(p, (format == 16) ? 0x0501 : 0x0511);
jtag_ir_shift(p, IR_ADDR_16BIT); jtag_ir_shift(p, IR_ADDR_16BIT);
jtag_dr_shift_20(p, address); jtag_dr_shift_20(p, address ^ (address & 1));
jtag_ir_shift(p, IR_DATA_TO_ADDR); //jtag_ir_shift(p, IR_DATA_TO_ADDR);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_tclk_clr(p); jtag_tclk_clr(p);
jtag_ir_shift(p, IR_DATA_CAPTURE); 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_clr(p);
jtag_tclk_set(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 /* 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, static void jlfxv2_read_mem_quick(struct jtdev *p, address_t address,
unsigned int length, uint16_t *data) unsigned int length, uint16_t *data)
{ // SLAU320AJ name: ReadMemQuick { // SLAU320AJ name: ReadMemQuick
address_t pc_bak;
if (!jlfxv2_check_full_emu_state(p)) if (!jlfxv2_check_full_emu_state(p))
return; return;
//pc_bak = jlfxv2_read_reg(p, 0); // FIXME dbg_printc("read mem quick %05x..%05x\n", address, address+length*2);
jlfxv2_set_pc(p, address); if (jlfxv2_set_pc(p, address) < 0) return;
//jtag_tclk_set(p); //jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); 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_dr_shift_16(p, 0x0501);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE); 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, 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, static void jlfxv2_write_mem(struct jtdev *p, unsigned int format,
address_t address, uint16_t data) address_t address, uint16_t data)
{ // SLAU320AJ name: WriteMem { // 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) { if (format == 8) {
p->failed = 1; p->failed = 1;
@ -259,13 +321,13 @@ static void jlfxv2_write_mem(struct jtdev *p, unsigned int format,
// same story as with read_mem // same story as with read_mem
jlfxv2_write_mem_quick(p, address, 1, &data); jlfxv2_write_mem_quick(p, address, 1, &data);
/*if (!jlfxv2_check_full_emu_state(p)) if (!jlfxv2_check_full_emu_state(p))
return; 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); 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_tclk_clr(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); 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, static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address,
unsigned int length, const uint16_t *data) unsigned int length, const uint16_t *data)
{ // SLAU320AJ name: WriteMemQuick { // SLAU320AJ name: WriteMemQuick
uint16_t pc_bak;
/*for (unsigned int i = 0; i < length; ++i) { /*for (unsigned int i = 0; i < length; ++i) {
jlfxv2_write_mem(p, 16, address + i*2, data[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)) if (!jlfxv2_check_full_emu_state(p))
return; return;
//pc_bak = jlfxv2_read_reg(p, 0); // FIXME if (jlfxv2_set_pc(p, address) < 0) return;
jlfxv2_set_pc(p, address);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0500); jtag_dr_shift_16(p, 0x0500);
jtag_tclk_set(p); 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_dr_shift_16(p, 0x0501);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_ir_shift(p, IR_ADDR_CAPTURE); 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 /* 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 { // SLAU320AJ name: ExecutePOR
unsigned int jtag_id; 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); jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
// empty CPU pipeline // empty CPU pipeline
@ -346,52 +412,48 @@ static unsigned int jlfxv2_execute_puc(struct jtdev *p)
/* Apply and remove reset */ /* Apply and remove reset */
jtag_dr_shift_16(p, 0x0C01); jtag_dr_shift_16(p, 0x0C01);
delay_ms(40);
jtag_dr_shift_16(p, 0x0401); jtag_dr_shift_16(p, 0x0401);
if (jtag_id == 0x91) { // TODO: is this correct? if (jtag_id == 0x91 || jtag_id == 0X99 || jtag_id == 0x98) {
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
jtag_ir_shift(p, IR_DATA_16BIT); jtag_ir_shift(p, IR_DATA_16BIT);
jtag_tclk_clr(p); jtag_tclk_clr(p);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_tclk_clr(p); jtag_tclk_clr(p);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_dr_shift_16(p, SAFE_FRAM_PC);
jtag_tclk_clr(p); jtag_dr_shift_16(p, SAFE_FRAM_PC);
jtag_tclk_set(p);
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); 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_clr(p);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_tclk_clr(p); jtag_tclk_clr(p);
jtag_tclk_set(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_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0501); jtag_dr_shift_16(p, 0x0501);
jtag_tclk_clr(p); jtag_tclk_clr(p);
jtag_tclk_set(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; 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 { // SLAU320AJ name: ReleaseDevice. from Replicator430 code, not in the PDF
switch (address) { switch (address) {
case 0xffff: // BOR case 0xffff: // BOR
dbg_printc("jlfxv2: release device: BOR\n");
jtag_ir_shift(p, IR_TEST_REG); jtag_ir_shift(p, IR_TEST_REG);
jtag_dr_shift_16(p, 0x0200); jtag_dr_shift_16(p, 0x0200);
delay_ms(5); delay_ms(5);
break; break;
case 0xfffe: // reset case 0xfffe: // reset
dbg_printc("jlfxv2: release device: SRST\n");
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0C01); jtag_dr_shift_16(p, 0x0C01);
delay_ms(40);
jtag_dr_shift_16(p, 0x0401); jtag_dr_shift_16(p, 0x0401);
jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE); jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE);
break; break;
default: default:
dbg_printc("jlfxv2: release device: PC=%05x\n", address);
jlfxv2_set_pc(p, address); jlfxv2_set_pc(p, address);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift_16(p, 0x0401); jtag_dr_shift_16(p, 0x0401);
jtag_ir_shift(p, IR_ADDR_CAPTURE); 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); jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE);
break; 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, static void jlfxv2_write_flash(struct jtdev *p, address_t start_address,
unsigned int length, const uint16_t *data) unsigned int length, const uint16_t *data)
{ // SLAU320AJ name: WriteFLASH { // SLAU320AJ name: WriteFLASH
// TODO: implement!
} }
/* Performs a mass erase (with and w/o info memory) or a segment erase of a /* 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, static void jlfxv2_erase_flash(struct jtdev *p, unsigned int erase_mode,
address_t erase_address) address_t erase_address)
{ // SLAU320AJ name: EraseFLASH { // SLAU320AJ name: EraseFLASH
// TODO: implement!
} }
/* Reads a register from the target CPU */ /* 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; uint16_t jtag_id, jmb_addr;
const bool alt_addr = false;//true; 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)) if (!jlfxv2_check_full_emu_state(p))
return 0; 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_ir_shift(p, IR_DATA_CAPTURE);
jtag_tclk_set(p); 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); jlfxv2_set_pc(p, SAFE_FRAM_PC);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); 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 */ /* Writes a value into a register of the target CPU */
static void jlfxv2_write_reg(struct jtdev *p, int reg, address_t value) static void jlfxv2_write_reg(struct jtdev *p, int reg, address_t value)
{ // SLAU320AJ name: SetPC { // SLAU320AJ name: SetPC
jlfxv2_check_full_emu_state(p); if (reg == 0 || reg == 3) return; // pc, cg
printc_dbg("write reg %d %06x\n", reg, value);
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_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
jtag_dr_shift_16(p, 0);*/ 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_tclk_set(p);
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); 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_clr(p);
jtag_tclk_set(p); jtag_tclk_set(p);
jtag_tclk_clr(p); jtag_tclk_clr(p);
@ -572,7 +655,9 @@ static void jlfxv2_single_step( struct jtdev *p )
int i, timeout; int i, timeout;
uint16_t tmp; 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); /*jtag_ir_shift(p, IR_EMEX_READ_CONTROL);
timeout = 3000; 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 */ /* State Storage is STOR_REACT in EEM_defs.h */
/* Cycle Counter is EVENT_REACT in EEM_defs.h */ /* Cycle Counter is EVENT_REACT in EEM_defs.h */
// TODO: implement
return 0; return 0;
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static unsigned int jlfxv2_cpu_state( struct jtdev *p ) static unsigned int jlfxv2_cpu_state( struct jtdev *p )
{ // libmsp430 BIOS name: WaitForEem(?) { // libmsp430 BIOS name: WaitForEem(?)
// TODO: does this need an update?
jtag_ir_shift(p, IR_EMEX_READ_CONTROL); jtag_ir_shift(p, IR_EMEX_READ_CONTROL);
if ((jtag_dr_shift_16(p, 0x0000) & EEM_STOPPED) == EEM_STOPPED) { 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 */ return 1; /* halted */
} else { } else {
printc_dbg("jlfxv2_cpu_state: running\n"); dbg_printc("cpu_state: running\n");
return 0; /* running */ 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 ) static int jlfxv2_get_config_fuses( struct jtdev *p )
{ // always the same? { // always the same?
// TODO: does this need an update?
jtag_ir_shift(p, IR_CONFIG_FUSES); jtag_ir_shift(p, IR_CONFIG_FUSES);
return jtag_dr_shift_8(p, 0); 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 = { const struct jtaglib_funcs jlf_cpuxv2 = {
.jlf_get_device = jlfxv2_get_device, .jlf_get_device = jlfxv2_get_device,
@ -701,6 +874,11 @@ const struct jtaglib_funcs jlf_cpuxv2 = {
.jlf_write_flash = jlfxv2_write_flash, .jlf_write_flash = jlfxv2_write_flash,
.jlf_erase_flash = jlfxv2_erase_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_read_reg = jlfxv2_read_reg,
.jlf_write_reg = jlfxv2_write_reg, .jlf_write_reg = jlfxv2_write_reg,
.jlf_single_step = jlfxv2_single_step, .jlf_single_step = jlfxv2_single_step,

View File

@ -35,6 +35,9 @@ struct jtdev {
uint8_t cpu_type; uint8_t cpu_type;
int failed; int failed;
const struct jtdev_func * f; const struct jtdev_func * f;
address_t regs[DEVICE_NUM_REGS];
uint16_t wdtctl;
}; };
struct jtdev_func { struct jtdev_func {