pico430prog/src/msp430dbg.c

502 lines
12 KiB
C

#include <stddef.h>
#include <stdio.h>
#include "pio_sbw.h"
#include "tap.h"
#include "msp430dbg.h"
bool msp430_check_fuse_blown(void) {
for (size_t i = 0; i < 3; ++i) {
sbw_tap_shift_ir(msp430_ir_ctrl_sig_capture);
uint16_t dr = sbw_tap_shift_dr(0xaaaa);
//printf("fuse dr=%04x\n", dr);
if (dr == 0x5555) return true;
}
return false;
}
bool msp430_insn_fetch(void) {
sbw_tap_shift_ir(msp430_ir_ctrl_sig_capture);
// shouldn't it set the insn fetch bit here?
for (size_t i = 0; i < 50; ++i) {
uint16_t dr = sbw_tap_read_dr();
//printf("[%zu] wait fetch dr=%04x\n", i, dr);
if (dr & 0x0080) return true;
sbw_clr_tclk();
sbw_set_tclk();
}
return false;
}
void msp430_cpu_halt(void) {
if (!msp430_insn_fetch()) ;//printf("aaa no fetch\n");
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr(0x3fff); // "jmp ."
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2409); // JTAG halt
sbw_set_tclk();
}
void msp430_cpu_release(void) {
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2401);
sbw_tap_shift_ir(msp430_ir_addr_capture);
sbw_set_tclk();
}
bool msp430_cpu_reset(void) {
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2C01);
sbw_tap_shift_dr(0x2401);
sbw_clr_tclk();
sbw_set_tclk();
sbw_clr_tclk();
sbw_set_tclk();
sbw_clr_tclk();
uint8_t jtagid = sbw_tap_shift_ir(msp430_ir_addr_capture);
sbw_set_tclk();
//printf("reset: watchdog disable\n");
msp430_memory_write(16, 0x0120, 0x5A80); // disable watchdog
return jtagid == MSP430_JTAG_TAP_ID;
}
void msp430_pc_set(uint16_t pc) {
if (!msp430_insn_fetch()) ;//printf("aaa no fetch\n");
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x3401);
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr(0x4030); // "load pc"
sbw_clr_tclk();
sbw_set_tclk();
sbw_tap_shift_dr(pc);
sbw_clr_tclk();
sbw_set_tclk();
sbw_tap_shift_ir(msp430_ir_addr_capture);
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2401);
}
void msp430_device_release(uint16_t addr) {
if (addr == 0xfffe) { // reset vector
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2c01);
sbw_tap_shift_dr(0x2401);
} else {
msp430_pc_set(addr);
}
sbw_tap_shift_ir(msp430_ir_ctrl_sig_release);
}
uint16_t msp430_memory_read16(uint16_t addr) {
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2409); // 2419 for 8bit
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(addr);
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_set_tclk();
sbw_clr_tclk();
uint16_t r = sbw_tap_read_dr();
//printf("read16 result=%04x\n", r);
msp430_cpu_release();
return r;
}
uint8_t msp430_memory_read8 (uint16_t addr) {
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2419); // 2409 for 16bit
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(addr);
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_set_tclk();
sbw_clr_tclk();
uint16_t r = sbw_tap_read_dr();
msp430_cpu_release();
return r;
}
void msp430_memory_write16(uint16_t addr, uint16_t value) {
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2408); // 2418 for 8bit
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(addr);
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(value);
sbw_set_tclk();
msp430_cpu_release();
}
void msp430_memory_write8 (uint16_t addr, uint8_t value) {
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2418);
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(addr);
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(value);
sbw_set_tclk();
msp430_cpu_release();
}
void msp430_memory_read_block(uint16_t srcaddr, uint16_t num, uint16_t* dest) {
msp430_pc_set(srcaddr - 4);
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2409);
sbw_tap_shift_ir(msp430_ir_data_quick);
for (size_t i = 0; i < num; ++i) {
sbw_set_tclk();
dest[i] = sbw_tap_read_dr();
sbw_clr_tclk();
}
msp430_cpu_release();
}
void msp430_memory_write_block(uint16_t dstaddr, uint16_t num, const uint16_t* src) {
msp430_pc_set(dstaddr - 4);
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2408);
sbw_tap_shift_ir(msp430_ir_data_quick);
for (size_t i = 0; i < num; ++i) {
sbw_tap_shift_dr(src[i]);
sbw_set_tclk();
sbw_clr_tclk();
}
msp430_cpu_release();
}
bool msp430_memory_verify(uint16_t startaddr, uint16_t length, const uint16_t* copy) {
const uint16_t poly = 0x0805;
msp430_cpu_reset();
if (false/*device has enhanced verify*/) {
msp430_pc_set(startaddr - 4);
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr(startaddr - 2);
} else {
msp430_pc_set(startaddr - 2);
sbw_set_tclk();
sbw_clr_tclk();
}
sbw_tap_shift_ir(msp430_ir_data_psa);
for (size_t i = 0; i < length; ++i) {
sbw_set_tclk();
const uint8_t tms_seq = 0x19; // 100110
// go through drscan/capturedr/shiftdr/updatedr without actually shifting data
sbw_tms_sequence(6, true, &tms_seq);
sbw_clr_tclk();
}
sbw_tap_shift_ir(msp430_ir_shift_out_psa);
uint16_t psa_out = sbw_tap_read_dr();
sbw_set_tclk();
if (false/*device has enhanced verify*/) {
msp430_cpu_release();
}
msp430_cpu_reset();
uint16_t psa_crc = startaddr - 2;
for (size_t i = 0; i < length; ++i) {
if (psa_crc & 0x8000) {
psa_crc ^= poly;
psa_crc <<= 1;
psa_crc |= 1;
} else psa_crc <<= 1;
if (copy) psa_crc ^= copy[i];
else psa_crc ^= 0xffff;
}
return psa_out == psa_crc;
}
uint32_t msp430_device_get(float freq) {
uint8_t jtagid = 0;
for (size_t i = 0; i < 7; ++i) {
sbw_preinit();
bool s = sbw_init();
if (!s) return 0xff<<24;
sbw_tap_reset();
sbw_check_fuse();
jtagid = sbw_tap_shift_ir(msp430_ir_bypass);
//printf("[%zu] get jtag id= %02x\n", i, jtagid);
if (jtagid == MSP430_JTAG_TAP_ID) break;
sbw_deinit();
}
if (jtagid != MSP430_JTAG_TAP_ID) return 0<<24;
if (msp430_check_fuse_blown()) return 1<<24;
//sbw_set_freq(false, freq); // TODO: store freq? for programming stuff (needs different baudrate for tclk)
sbw_set_freq(true, 350e3);
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
uint16_t dr = sbw_tap_shift_dr(0x2401); // JTAG mode, read
//printf("olddr=%04x\n", dr);
if (sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit) != jtagid) {
return 2<<24;
}
uint16_t devid = 0;
for (size_t i = 0; i < 50; ++i) {
dr = sbw_tap_read_dr();
//printf("[%zu] wait jtag sync: dr=%04x\n", i, dr);
if (dr & 0x0200) {
devid = msp430_memory_read(16, 0x0FF0);
break;
}
}
if (devid == 0) return 3<<24;
if (!msp430_cpu_reset()) return 4<<24;
return ((uint32_t)jtagid << 24) | devid;
}
// TODO
void msp430_flash_write(uint16_t startaddr, uint16_t num, const uint16_t* src) {
msp430_cpu_halt();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2408);
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x0128); // FCTL1
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa540); // enable flash write
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x012a); // FCTL2
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa540); // MCLK source, DIV=1
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x012c); // FCTL3
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa540); // unlock
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
//sbw_set_freq(true, 350e3);
for (uint16_t i = 0, addr = startaddr; i < num; ++i, addr += 2) {
sbw_tap_shift_dr(0x2408);
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(addr);
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(src[i]);
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2409);
sbw_tclk_burst(35*4);
printf("%04x gets %04x\n", addr, src[i]);
}
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2408);
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x0128); // FCTL1
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa500); // disable flash write
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x012c); // FCTL3
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa550); // set lock
sbw_set_tclk();
msp430_cpu_release();
}
void msp430_flash_erase_seg(uint16_t startaddr, bool is_infosegA) {
(void)is_infosegA;
msp430_cpu_halt();
sbw_clr_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2408);
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x0128); // FCTL1
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa502); // enable flash erase, single segment
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x012a); // FCTL2
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa540); // MCLK source, DIV=1
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x012c); // FCTL3
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa500); // unlock
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(startaddr);
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0x55aa);
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2409);
sbw_tclk_burst(4820);
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2408);
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x0128); // FCTL1
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa500); // lock flash
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_addr_16bit);
sbw_tap_shift_dr(0x012c); // FCTL3
sbw_tap_shift_ir(msp430_ir_data_to_addr);
sbw_tap_shift_dr(0xa510); // set lock
sbw_set_tclk();
msp430_cpu_release();
}
void msp430_flash_erase_mass(bool withinfomem) {
uint16_t addr = withinfomem ? 0x1002 : 0xfffe;
uint16_t mode = withinfomem ? 0xa506 : 0xa504;
(void)addr; (void)mode; // nah, not yet
}
// mwhahahah
// TODO
/*uint16_t msp430_read_jmb(void) {
return 0;
}
void msp430_write_jmb(uint16_t v) {
}*/
uint16_t msp430_cpureg_read(short regid) {
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x3401);
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr((regid & 0xf) << 8 | 0x4082);
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_data_capture);
sbw_set_tclk();
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr(0x00fe);
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_data_capture);
sbw_set_tclk();
sbw_clr_tclk();
sbw_set_tclk();
uint16_t reg = sbw_tap_read_dr();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2401);
sbw_set_tclk();
return reg;
}
void msp430_cpureg_write(short regid, uint16_t value) {
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x3401);
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr((regid & 0xf) | 0x4030);
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_data_capture);
sbw_set_tclk();
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr(value);
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_data_capture);
sbw_set_tclk();
sbw_tap_shift_ir(msp430_ir_data_16bit);
sbw_tap_shift_dr(0x3ffd);
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_data_capture);
sbw_set_tclk();
sbw_clr_tclk();
sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
sbw_tap_shift_dr(0x2401);
sbw_set_tclk();
}