703 lines
18 KiB
C
703 lines
18 KiB
C
|
||
#include <stdbool.h>
|
||
|
||
#include "jtaglib.h"
|
||
#include "jtaglib_defs.h"
|
||
#include "output.h"
|
||
|
||
#define SAFE_FRAM_PC 0x0004
|
||
|
||
// FIXME:
|
||
// * read reg (nonsense values)
|
||
// * write reg?
|
||
// * implement flash write, erase, verify stuff
|
||
// * other stuff?
|
||
// * 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;
|
||
}
|
||
|
||
static void jlfxv2_read_mem_quick(struct jtdev *p, address_t address,
|
||
unsigned int length, uint16_t *data);
|
||
|
||
/* Reads one byte/word from a given address
|
||
* format : 8-byte, 16-word
|
||
* address: address of memory
|
||
* return : content of memory
|
||
*/
|
||
static uint16_t jlfxv2_read_mem(struct jtdev *p, unsigned int format, address_t address)
|
||
{ // SLAU320AJ name: ReadMem
|
||
uint16_t r = 0;
|
||
|
||
if (!jlfxv2_check_full_emu_state(p))
|
||
return 0;
|
||
|
||
// the code below (an attempt at implementing the real read_mem) doesn't
|
||
// work, so let's use read_mem_quick as a backup
|
||
jlfxv2_read_mem_quick(p, address ^ (address & 1), 1, &r);
|
||
if (format == 8) {
|
||
if (address & 1) return (r >> 8) & 0xff;
|
||
else return r & 0xff;
|
||
} else return r;
|
||
|
||
/*//jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
|
||
//uint16_t dr = jtag_dr_shift_16(p, 0);
|
||
|
||
jtag_tclk_clr(p);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, (format == 16) ? 0x0501 : 0x0511);
|
||
jtag_ir_shift(p, IR_ADDR_16BIT);
|
||
jtag_dr_shift_20(p, address);
|
||
jtag_ir_shift(p, IR_DATA_TO_ADDR);
|
||
jtag_tclk_set(p);
|
||
jtag_tclk_clr(p);
|
||
jtag_ir_shift(p, IR_DATA_CAPTURE);
|
||
|
||
r = jtag_dr_shift_16(p, 0);
|
||
|
||
jtag_tclk_set(p);
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);
|
||
|
||
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
|
||
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);
|
||
|
||
//jtag_tclk_set(p);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0501);
|
||
jtag_tclk_set(p);
|
||
jtag_ir_shift(p, IR_ADDR_CAPTURE);
|
||
jtag_ir_shift(p, IR_DATA_QUICK);
|
||
|
||
for (unsigned int i = 0; i < length; ++i) {
|
||
jtag_tclk_set(p);
|
||
jtag_tclk_clr(p);
|
||
data[i] = jtag_dr_shift_16(p, 0);
|
||
}
|
||
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
|
||
jtag_dr_shift_16(p, 0);
|
||
|
||
jlfxv2_set_pc(p, SAFE_FRAM_PC);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0501);
|
||
jtag_tclk_set(p);
|
||
jtag_ir_shift(p, IR_ADDR_CAPTURE);
|
||
|
||
//jlfxv2_write_reg(p, 0, pc_bak); // FIXME
|
||
}
|
||
|
||
static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address,
|
||
unsigned int length, const uint16_t *data);
|
||
|
||
/* Writes one byte/word at a given address
|
||
* format : 8-byte, 16-word
|
||
* address: address to be written
|
||
* data : data to write
|
||
*/
|
||
static void jlfxv2_write_mem(struct jtdev *p, unsigned int format,
|
||
address_t address, uint16_t data)
|
||
{ // SLAU320AJ name: WriteMem
|
||
printc_dbg("jlfxv2 write mem: %d %06x <- %04x\n", format, address, data);
|
||
|
||
if (format == 8) {
|
||
p->failed = 1;
|
||
printc_err("jlfxv2 write mem: byte access not yet implemented!\n");
|
||
return;
|
||
}
|
||
|
||
// same story as with read_mem
|
||
jlfxv2_write_mem_quick(p, address, 1, &data);
|
||
|
||
/*if (!jlfxv2_check_full_emu_state(p))
|
||
return;
|
||
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
|
||
uint16_t dr = jtag_dr_shift_16(p, 0);
|
||
|
||
printc_dbg("write mem %d: %06x<-%04x: dr=%04x\n", format, address, data, dr);
|
||
|
||
jtag_tclk_clr(p);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, (format == 16) ? 0x0500 : 0x0510);
|
||
jtag_ir_shift(p, IR_ADDR_16BIT);
|
||
jtag_dr_shift_20(p, address);
|
||
jtag_tclk_set(p);
|
||
jtag_ir_shift(p, IR_DATA_TO_ADDR);
|
||
jtag_dr_shift_16(p, data);
|
||
jtag_tclk_clr(p);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0501);
|
||
|
||
jtag_tclk_set(p);
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);*/
|
||
}
|
||
|
||
/* Writes an array of words into target memory
|
||
* address: address to write to
|
||
* length : number of word to write
|
||
* data : data to write
|
||
*/
|
||
static void jlfxv2_write_mem_quick(struct jtdev *p, address_t address,
|
||
unsigned int length, const uint16_t *data)
|
||
{ // SLAU320AJ name: WriteMemQuick
|
||
uint16_t pc_bak;
|
||
|
||
/*for (unsigned int i = 0; i < length; ++i) {
|
||
jlfxv2_write_mem(p, 16, address + i*2, data[i]);
|
||
}*/
|
||
|
||
if (!jlfxv2_check_full_emu_state(p))
|
||
return;
|
||
|
||
//pc_bak = jlfxv2_read_reg(p, 0); // FIXME
|
||
jlfxv2_set_pc(p, address);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0500);
|
||
jtag_tclk_set(p);
|
||
|
||
jtag_ir_shift(p, IR_DATA_QUICK);
|
||
|
||
|
||
for (unsigned int i = 0; i < length; ++i) {
|
||
jtag_tclk_set(p);
|
||
jtag_dr_shift_16(p, data[i]);
|
||
jtag_tclk_clr(p);
|
||
}
|
||
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0501);
|
||
jtag_tclk_set(p);
|
||
|
||
jlfxv2_set_pc(p, SAFE_FRAM_PC);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0501);
|
||
jtag_tclk_set(p);
|
||
jtag_ir_shift(p, IR_ADDR_CAPTURE);
|
||
|
||
//jlfxv2_write_reg(p, 0, pc_bak);
|
||
}
|
||
|
||
/* 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;
|
||
const bool alt_addr = true;
|
||
|
||
if (reg == 3) return 0; // CG
|
||
|
||
printc_dbg("read reg %d\n", reg);
|
||
if (!jlfxv2_check_full_emu_state(p))
|
||
return 0;
|
||
|
||
jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
|
||
jtag_tclk_clr(p);
|
||
jtag_ir_shift(p, IR_DATA_16BIT);
|
||
jtag_tclk_set(p);
|
||
jtag_dr_shift_16(p, reg);
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x1401);
|
||
jtag_ir_shift(p, IR_DATA_16BIT);
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);
|
||
|
||
if (alt_addr) {
|
||
jtag_dr_shift_16(p, 0x0ff6);
|
||
} else {
|
||
jmb_addr = (jtag_id == 0x98) ? 0x14c : 0x18c;
|
||
jtag_dr_shift_16(p, jmb_addr);
|
||
}
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);
|
||
jtag_dr_shift_16(p, 0x3ffd);
|
||
jtag_tclk_clr(p);
|
||
|
||
if (alt_addr) {
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0501);
|
||
}
|
||
|
||
jtag_ir_shift(p, IR_DATA_CAPTURE);
|
||
jtag_tclk_set(p);
|
||
reglo = jtag_dr_shift_16(p, 0);
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);
|
||
reghi = jtag_dr_shift_16(p, 0);
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);
|
||
jtag_tclk_clr(p);
|
||
jtag_tclk_set(p);
|
||
|
||
if (!alt_addr) {
|
||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||
jtag_dr_shift_16(p, 0x0501);
|
||
}
|
||
|
||
jtag_tclk_clr(p);
|
||
jtag_ir_shift(p, IR_DATA_CAPTURE);
|
||
jtag_tclk_set(p);
|
||
|
||
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,
|
||
};
|
||
|