From 2170693f2f6af93fe8cbd941eb47eabf7ca34929 Mon Sep 17 00:00:00 2001 From: sys64738 Date: Sun, 24 Jul 2022 21:00:07 +0200 Subject: [PATCH] jtaglib: getting cpuxv2 stuff to work, very slowly... --- drivers/jtaglib.c | 53 ++-- drivers/jtaglib_cpu16.c | 91 +++--- drivers/jtaglib_cpuxv2.c | 626 ++++++++++++++++++++++++++++++++++++++- drivers/jtaglib_defs.h | 10 + 4 files changed, 720 insertions(+), 60 deletions(-) diff --git a/drivers/jtaglib.c b/drivers/jtaglib.c index bec3e14..bec7204 100644 --- a/drivers/jtaglib.c +++ b/drivers/jtaglib.c @@ -562,12 +562,6 @@ int jtag_refresh_bps(device_t dev, struct jtdev *p) /* ========================================================================= */ -static int write_ram_word(struct jtdev *p, address_t addr, uint16_t value) -{ - jtag_write_mem(p, 16, addr, value); - - return p->failed ? -1 : 0; -} static int write_flash_block(struct jtdev *p, address_t addr, address_t len, const uint8_t *data) { @@ -591,6 +585,25 @@ 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); + if (len > 2 && !(len & 1)) { + uint16_t* word = malloc((len>>1) * sizeof(*word)); + if (!word) { + pr_error("jtaglib: failed to allocate memory"); + return -1; + } + + jtag_read_mem_quick(p, addr, len >> 1, word); + + for (unsigned int i = 0; i < len/2; i++) { + data[2*i+0] = word[i] & 0xff; + data[2*i+1] = word[i] >> 8; + } + free(word); + + return p->failed ? -1 : len; + } + for (unsigned int index = 0; index < len; index += 2) { unsigned int word = jtag_read_mem(p, 16, addr+index); data[index ] = word & 0x00ff; @@ -605,8 +618,10 @@ static int write_words(device_t dev_base, const struct chipinfo_memory *m, int r; if (m->type != CHIPINFO_MEMTYPE_FLASH) { - len = 2; - r = write_ram_word(p, addr, r16le(data)); + printc_dbg("jtaglib: write_words: ram: len=%d addr=%06x\n", len, addr); + uint16_t value = data[0] | ((uint16_t)data[1] << 8); + jtag_write_mem(p, 16, addr, value); + r = p->failed ? -1 : 0; } else { r = write_flash_block(p, addr, len, data); } @@ -773,11 +788,12 @@ static int idproc_9x(struct jtdev *p, uint32_t dev_id_ptr, struct chipinfo_id *i memset(iddata, 0, sizeof iddata); // read 8 words starting at dev_id_ptr - // 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) { - iddata[i] = jtag_read_mem(p, 16, dev_id_ptr + i*2); - } + // 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]); + }*/ info_len = iddata[0] & 0xff; id->ver_id = iddata[2]; @@ -801,9 +817,7 @@ static int idproc_9x(struct jtdev *p, uint32_t dev_id_ptr, struct chipinfo_id *i tlv_size); return -1; } - for (int i = 0; i < (tlv_size >> 1); ++i) { - w16le(&tlvdata[i*2], jtag_read_mem(p, 16, dev_id_ptr + i*2)); - } + jtag_read_mem_quick(p, dev_id_ptr, tlv_size >> 1, (uint16_t*)tlvdata); /* search TLV for sub-ID */ for (int i = 8; i + 3 < tlv_size; ) { @@ -862,12 +876,13 @@ int jtag_dev_init(struct jtdev *p) { jtag_ir_shift(p, IR_DEVICE_ID); 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", core_ip_id, device_id); - if (device_id != 0) return device_id + 4; - else return 0x0ff0; // ??? + if (device_id != 0 && (device_id & 0xff) != 0x80) + dev_id_addr = device_id + 4; + else dev_id_addr = 0x1a00; // ??? } else { dev_id_addr = 0x0ff0; } diff --git a/drivers/jtaglib_cpu16.c b/drivers/jtaglib_cpu16.c index 1d89548..293fae8 100644 --- a/drivers/jtaglib_cpu16.c +++ b/drivers/jtaglib_cpu16.c @@ -8,9 +8,11 @@ * 0 - otherwise */ static int jlf16_set_instruction_fetch(struct jtdev *p) -{ +{ // SLAU320AJ name: SetInstrFetch / SyncJtag? unsigned int loop_counter; + // SyncJtag: has CTLR_SIG_16BIT=0x2401 here + jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); /* Wait until CPU is in instruction fetch state * timeout after limited attempts @@ -31,7 +33,7 @@ static int jlf16_set_instruction_fetch(struct jtdev *p) /* Set the CPU into a controlled stop state */ static void jlf16_halt_cpu(struct jtdev *p) -{ +{ // SLAU320AJ name: HaltCPU /* Set CPU into instruction fetch mode */ jlf16_set_instruction_fetch(p); @@ -42,7 +44,7 @@ static void jlf16_halt_cpu(struct jtdev *p) /* Send JMP $ instruction to keep CPU from changing the state */ jtag_ir_shift(p, IR_DATA_16BIT); jtag_dr_shift_16(p, 0x3FFF); - jtag_tclk_set(p); + //jtag_tclk_set(p); // TODO: ??? jtag_tclk_clr(p); /* Set JTAG_HALT bit */ @@ -53,7 +55,7 @@ static void jlf16_halt_cpu(struct jtdev *p) /* Release the target CPU from the controlled stop state */ static void jlf16_release_cpu(struct jtdev *p) -{ +{ // SLAU320AJ name: ReleaseCPU jtag_tclk_clr(p); /* clear the HALT_JTAG bit */ @@ -76,7 +78,7 @@ static int jlf16_verify_mem(struct jtdev *p, unsigned int start_address, unsigned int length, const uint16_t *data) -{ +{ // SLAU320AJ name: VerifyMem/VerifyPSA unsigned int psa_value; unsigned int index; @@ -146,7 +148,7 @@ static int jlf16_erase_check(struct jtdev *p, unsigned int start_address, } static unsigned int jlf16_get_device(struct jtdev *p) -{ +{ // SLAU320AJ name: GetDevice unsigned int jtag_id = 0; unsigned int loop_counter; @@ -165,7 +167,7 @@ static unsigned int jlf16_get_device(struct jtdev *p) } if (loop_counter == 0) { - printc_err("jtaglib_cpu16: jtag_get_device: timed out\n"); + printc_err("jlf16_get_device: timed out\n"); p->failed = 1; /* timeout reached */ return 0; @@ -180,7 +182,7 @@ static unsigned int jlf16_get_device(struct jtdev *p) * return : content of memory */ static uint16_t jlf16_read_mem(struct jtdev *p, unsigned int format, address_t address) -{ +{ // SLAU320AJ name: ReadMem uint16_t content; jlf16_halt_cpu(p); @@ -217,7 +219,7 @@ static uint16_t jlf16_read_mem(struct jtdev *p, unsigned int format, address_t a */ static void jlf16_read_mem_quick(struct jtdev *p, address_t address, unsigned int length, uint16_t *data) -{ +{ // SLAU320AJ name: ReadMemQuick unsigned int index; /* Initialize reading: */ @@ -232,9 +234,10 @@ static void jlf16_read_mem_quick(struct jtdev *p, address_t address, for (index = 0; index < length; index++) { jtag_tclk_set(p); - jtag_tclk_clr(p); + //jtag_tclk_clr(p); // TODO: ??? /* shift out the data from the target */ data[index] = jtag_dr_shift_16(p, 0x0000); + jtag_tclk_clr(p); // TODO: ??? } jtag_tclk_set(p); @@ -248,7 +251,7 @@ static void jlf16_read_mem_quick(struct jtdev *p, address_t address, */ static void jlf16_write_mem(struct jtdev *p, unsigned int format, address_t address, uint16_t data) -{ +{ // SLAU320AJ name: WriteMem jlf16_halt_cpu(p); jtag_tclk_clr(p); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); @@ -279,7 +282,7 @@ static void jlf16_write_mem(struct jtdev *p, unsigned int format, */ static void jlf16_write_mem_quick(struct jtdev *p, address_t address, unsigned int length, const uint16_t *data) -{ +{ // SLAU320AJ name: WriteMemQuick unsigned int index; /* Initialize writing */ @@ -288,11 +291,11 @@ static void jlf16_write_mem_quick(struct jtdev *p, address_t address, jtag_tclk_clr(p); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - /* Set RW to write */ - jtag_dr_shift_16(p, 0x2408); - jtag_ir_shift(p, IR_DATA_QUICK); - for (index = 0; index < length; index++) { + /* Set RW to write */ + jtag_dr_shift_16(p, 0x2408); + jtag_ir_shift(p, IR_DATA_QUICK); + /* Write data */ jtag_dr_shift_16(p, data[index]); @@ -309,7 +312,7 @@ static void jlf16_write_mem_quick(struct jtdev *p, address_t address, * return: JTAG ID */ static unsigned int jlf16_execute_puc(struct jtdev *p) -{ +{ // SLAU320AJ name: ExecutePOR unsigned int jtag_id; jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); @@ -322,13 +325,15 @@ static unsigned int jlf16_execute_puc(struct jtdev *p) jtag_tclk_clr(p); jtag_tclk_set(p); jtag_tclk_clr(p); - jtag_tclk_set(p); + //jtag_tclk_set(p); // TODO: ??? /* Read jtag id */ jtag_id = jtag_ir_shift(p, IR_ADDR_CAPTURE); + jtag_tclk_set(p); // TODO: ??? + /* Disable watchdog on target device */ - jtag_write_mem(p, 16, 0x0120, 0x5A80); + jtag_write_mem(p, 16, 0x0120, 0x5A80); // FIXME return jtag_id; } @@ -341,7 +346,7 @@ static unsigned int jlf16_execute_puc(struct jtdev *p) * other - load Address into PC */ static void jlf16_release_device(struct jtdev *p, address_t address) -{ +{ // SLAU320AJ name: ReleaseDevice switch (address) { case 0xffff: /* Nothing to do */ break; @@ -378,7 +383,7 @@ static void jlf16_release_device(struct jtdev *p, address_t address) */ static void jlf16_write_flash(struct jtdev *p, address_t start_address, unsigned int length, const uint16_t *data) -{ +{ // SLAU320AJ name: WriteFLASH unsigned int index; unsigned int address; @@ -392,7 +397,7 @@ static void jlf16_write_flash(struct jtdev *p, address_t start_address, /* FCTL1 register */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x0128); + jtag_dr_shift_16(p, 0x0128); // FIXME /* Enable FLASH write */ jtag_ir_shift(p, IR_DATA_TO_ADDR); @@ -402,7 +407,7 @@ static void jlf16_write_flash(struct jtdev *p, address_t start_address, /* FCTL2 register */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012A); + jtag_dr_shift_16(p, 0x012A); // FIXME /* Select MCLK as source, DIV=1 */ jtag_ir_shift(p, IR_DATA_TO_ADDR); @@ -412,7 +417,7 @@ static void jlf16_write_flash(struct jtdev *p, address_t start_address, /* FCTL3 register */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012C); + jtag_dr_shift_16(p, 0x012C); // FIXME /* Clear FCTL3 register */ jtag_ir_shift(p, IR_DATA_TO_ADDR); @@ -455,7 +460,7 @@ static void jlf16_write_flash(struct jtdev *p, address_t start_address, /* FCTL1 register */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x0128); + jtag_dr_shift_16(p, 0x0128); // FIXME /* Disable FLASH write */ jtag_ir_shift(p, IR_DATA_TO_ADDR); @@ -465,7 +470,7 @@ static void jlf16_write_flash(struct jtdev *p, address_t start_address, /* Reset FCTL3 */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012C); + jtag_dr_shift_16(p, 0x012C); // FIXME jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift_16(p, 0xA510); jtag_tclk_set(p); @@ -479,7 +484,7 @@ static void jlf16_write_flash(struct jtdev *p, address_t start_address, */ static void jlf16_erase_flash(struct jtdev *p, unsigned int erase_mode, address_t erase_address) -{ +{ // SLAU320AJ name: EraseFLASH 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 */ @@ -500,17 +505,17 @@ static void jlf16_erase_flash(struct jtdev *p, unsigned int erase_mode, /* FCTL1 address */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x0128); + jtag_dr_shift_16(p, 0x0128); // FIXME /* Enable erase mode */ jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift_16(p, erase_mode); + jtag_dr_shift_16(p, erase_mode); // FIXME? jtag_tclk_set(p); jtag_tclk_clr(p); /* FCTL2 address */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012A); + jtag_dr_shift_16(p, 0x012A); // FIXME /* MCLK is source, DIV=1 */ jtag_ir_shift(p, IR_DATA_TO_ADDR); @@ -520,7 +525,7 @@ static void jlf16_erase_flash(struct jtdev *p, unsigned int erase_mode, /* FCTL3 address */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012C); + jtag_dr_shift_16(p, 0x012C); // FIXME /* Clear FCTL3 */ jtag_ir_shift(p, IR_DATA_TO_ADDR); @@ -551,7 +556,7 @@ static void jlf16_erase_flash(struct jtdev *p, unsigned int erase_mode, /* FCTL1 address */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x0128); + jtag_dr_shift_16(p, 0x0128); // FIXME /* Disable erase */ jtag_ir_shift(p, IR_DATA_TO_ADDR); @@ -561,7 +566,7 @@ static void jlf16_erase_flash(struct jtdev *p, unsigned int erase_mode, /* Reset FCTL3 */ jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift_16(p, 0x012C); + jtag_dr_shift_16(p, 0x012C); // FIXME jtag_ir_shift(p, IR_DATA_TO_ADDR); jtag_dr_shift_16(p, 0xA510); jtag_tclk_set(p); @@ -572,7 +577,7 @@ static void jlf16_erase_flash(struct jtdev *p, unsigned int erase_mode, /* Reads a register from the target CPU */ static address_t jlf16_read_reg(struct jtdev *p, int reg) -{ +{ // libmsp430 BIOS name: ReadCpuReg unsigned int value; /* Set CPU into instruction fetch mode */ @@ -602,7 +607,9 @@ static address_t jlf16_read_reg(struct jtdev *p, int reg) */ jtag_dr_shift_16(p, 0x4082 | (((unsigned int)reg << 8) & 0x0f00) ); jtag_tclk_clr(p); + jtag_ir_shift(p, IR_DATA_CAPTURE); // TODO: ??? jtag_tclk_set(p); + jtag_ir_shift(p, IR_DATA_16BIT); // TODO: ??? jtag_dr_shift_16(p, 0x01fe); jtag_tclk_clr(p); jtag_tclk_set(p); @@ -633,7 +640,7 @@ static address_t jlf16_read_reg(struct jtdev *p, int reg) /* Writes a value into a register of the target CPU */ static void jlf16_write_reg(struct jtdev *p, int reg, address_t value) -{ +{ // SLAU320AJ name: SetPC /* Set CPU into instruction fetch mode */ jlf16_set_instruction_fetch(p); @@ -664,6 +671,10 @@ static void jlf16_write_reg(struct jtdev *p, int reg, address_t value) jtag_tclk_clr(p); jtag_tclk_set(p); + // TODO: ??? + jtag_ir_shift(p, IR_ADDR_CAPTURE); + jtag_tclk_clr(p); + /* JTAG controls RW & BYTE */ jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_dr_shift_16(p, 0x2401); @@ -671,7 +682,7 @@ static void jlf16_write_reg(struct jtdev *p, int reg, address_t value) /*----------------------------------------------------------------------------*/ static void jlf16_single_step( struct jtdev *p ) -{ +{ // libmsp430 BIOS name: SingleStep unsigned int loop_counter; /* CPU controls RW & BYTE */ @@ -696,7 +707,7 @@ static void jlf16_single_step( struct jtdev *p ) if (loop_counter == 0) { /* timeout reached */ - printc_err("pif: single step failed\n"); + printc_err("jtaglib_cpu16: single step failed\n"); p->failed = 1; } } @@ -715,7 +726,7 @@ static unsigned int jlf16_set_breakpoint( struct jtdev *p,int bp_num, address_t if (bp_num >= 8) { /* there are no more than 8 breakpoints in EEM */ - printc_err("jtag_set_breakpoint: failed setting " + printc_err("jlf16_set_breakpoint: failed setting " "breakpoint %d at %04x\n", bp_num, bp_addr); p->failed = 1; return 0; @@ -766,7 +777,7 @@ static unsigned int jlf16_set_breakpoint( struct jtdev *p,int bp_num, address_t /*----------------------------------------------------------------------------*/ static unsigned int jlf16_cpu_state( struct jtdev *p ) -{ +{ // libmsp430 BIOS name: WaitForEem(?) jtag_ir_shift(p, IR_EMEX_READ_CONTROL); if ((jtag_dr_shift_16(p, 0x0000) & 0x0080) == 0x0080) { @@ -778,7 +789,7 @@ static unsigned int jlf16_cpu_state( struct jtdev *p ) /*----------------------------------------------------------------------------*/ static int jlf16_get_config_fuses( struct jtdev *p ) -{ +{ // always the same? jtag_ir_shift(p, IR_CONFIG_FUSES); return jtag_dr_shift_8(p, 0); diff --git a/drivers/jtaglib_cpuxv2.c b/drivers/jtaglib_cpuxv2.c index 582dc3c..0f6ac30 100644 --- a/drivers/jtaglib_cpuxv2.c +++ b/drivers/jtaglib_cpuxv2.c @@ -1,7 +1,631 @@ +#include + #include "jtaglib.h" #include "jtaglib_defs.h" #include "output.h" -const struct jtaglib_funcs jlf_cpuxv2; +#define SAFE_FRAM_PC 0x0004 + +// FIXME: +// * read mem (broken) +// * read mem quick (consecutive ones break) +// * write mem (no effect) +// * read reg (nonsense values) +// -> also loses FES +// * write reg? +// * single step: check if it works +// * 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; + + 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 void jlfxv2_set_pc(struct jtdev *p, address_t addr) +{ + printc_dbg("set pc %06x\n", addr); + + 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); + jtag_dr_shift_20(p, 0); +} + +/* 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; + jlfxv2_set_pc(p, start_address); + + 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; + + 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; +} + +/* Reads one byte/word from a given address + * format : 8-byte, 16-word + * address: address of memory + * return : content of memory + */ +static void jlfxv2_read_mem_quick(struct jtdev *p, address_t address, + unsigned int length, uint16_t *data); +static uint16_t jlfxv2_read_mem(struct jtdev *p, unsigned int format, address_t address) +{ // SLAU320AJ name: ReadMem + uint16_t r=0; + printc_dbg("read mem %d %06x\n", format, address); + jlfxv2_read_mem_quick(p, address ^ (address & 1), 1, &r); + if (format == 8) { + if (address & 1) return r >> 8; + else return r & 0xff; + } else return r; + + if (!jlfxv2_check_full_emu_state(p)) + return 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); + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + r = jtag_dr_shift_16(p, 0); + + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + + 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; + + jlfxv2_set_pc(p, address); + + //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); + + if (p->jtag_id == 0x99) { + jlfxv2_set_pc(p, SAFE_FRAM_PC); + } + jtag_tclk_set(p); +} + +/* Writes one byte/word at a given address + * format : 8-byte, 16-word + * address: address to be written + * data : data to write + */ +static void jlfxv2_write_mem(struct jtdev *p, unsigned int format, + address_t address, uint16_t data) +{ // SLAU320AJ name: WriteMem + if (!jlfxv2_check_full_emu_state(p)) + return; + + printc_dbg("write mem %d: %06x<-%04x\n", format, address, data); + + 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]); + } +} + +/* 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; + + 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); + 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 + 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_ir_shift(p, IR_DATA_CAPTURE); + 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; +} + +/* 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 + jtag_ir_shift(p, IR_TEST_REG); + jtag_dr_shift_16(p, 0x0200); + delay_ms(5); + break; + case 0xfffe: // reset + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift_16(p, 0x0C01); + jtag_dr_shift_16(p, 0x0401); + jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE); + break; + default: + 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_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 +} + +/* 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 +} + +/* 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; + + if (reg == 3) return 0; // CG + + printc_dbg("read reg %d\n", reg); + if (!jlfxv2_check_full_emu_state(p)) + return 0; + + jtag_tclk_clr(p); + jtag_id = jtag_ir_shift(p, IR_DATA_16BIT); + jtag_tclk_set(p); + jtag_dr_shift_16(p, reg); + 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); + + 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); + + 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); + + 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); + + + printc_dbg("read reg %d: lo=%04x hi=%04x\n", reg, reglo, reghi); + 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 + jlfxv2_check_full_emu_state(p); + printc_dbg("write reg %d %06x\n", reg, value); + + 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)); + + //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, /*0x4303*/0x0501); // insert NOP to be prefetched by the CPU + 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; + printc_dbg("jlfxv2: single step\n"); + + /*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 */ + + 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"); + return 1; /* halted */ + } else { + printc_dbg("jlfxv2_cpu_state: running\n"); + return 0; /* running */ + } +} + +/*----------------------------------------------------------------------------*/ +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); +} + +/* ------------------------------------------------------------------------- */ + +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_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, +}; diff --git a/drivers/jtaglib_defs.h b/drivers/jtaglib_defs.h index 44c9cdb..edc2075 100644 --- a/drivers/jtaglib_defs.h +++ b/drivers/jtaglib_defs.h @@ -30,6 +30,8 @@ /* Instructions for the JTAG Fuse */ #define IR_PREPARE_BLOW 0x44 /* 0x22 */ #define IR_EX_BLOW 0x24 /* 0x24 */ +/* Instructions for the JTAG mailbox */ +#define IR_TEST_REG 0x54 /* 0x2A */ /* Instructions for the Configuration Fuse */ #define IR_CONFIG_FUSES 0x94 /* Bypass instruction */ @@ -39,6 +41,14 @@ #define IR_EMEX_WRITE_CONTROL 0x30 /* 0x0C */ #define IR_EMEX_READ_CONTROL 0xD0 /* 0x0B */ +/* EEM stuff */ +#define EEM_STOPPED 0x0080 +#define EEM_EN 0x0001 +#define CLEAR_STOP 0x0002 +#define EMU_CLK_EN 0x0004 + +#define CNTRL_SIG_CPUSUSP (1<<8) + #define jtag_tms_set(p) p->f->jtdev_tms(p, 1) #define jtag_tms_clr(p) p->f->jtdev_tms(p, 0) #define jtag_tck_set(p) p->f->jtdev_tck(p, 1)