336 lines
9.9 KiB
C
336 lines
9.9 KiB
C
// vim: set et:
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <hardware/clocks.h>
|
|
#include <hardware/dma.h>
|
|
#include <hardware/gpio.h>
|
|
#include <hardware/pio.h>
|
|
#include <hardware/pio_instructions.h>
|
|
#include <hardware/timer.h>
|
|
|
|
#include "m_isp/pinout.h"
|
|
#include "m_isp/sbw_hw.h"
|
|
|
|
#include "sbw.pio.h"
|
|
|
|
void sbw_preinit(bool nrst) {
|
|
//SLAU320AJ 2.3.1.1 ; SLAS722G p36:
|
|
// TEST/SBWTCK low for >100 us: reset debug state
|
|
// set nRST/NMI/SBWTDIO low: avoid sending an NMI when the debugger detaches
|
|
// TEST/SBWTCK high for >1 us : signal that we want a debugger
|
|
// nRST/NMI/SBWTDIO high: we want SBW
|
|
// TEST low for >0.025us <7us: latch on "we want SBW" signal
|
|
// TEST high again for >1 us: ready to SBW
|
|
|
|
// old impl, doesn't work, don't use
|
|
/*// TCK, TDIO now low
|
|
busy_wait_ms(4);//busy_wait_us_32(150); // reset debug state while keeping CPU in reset
|
|
|
|
gpio_put(PINOUT_SBW_TCK , true ); // we want a debugger
|
|
busy_wait_us_32(1);
|
|
gpio_put(PINOUT_SBW_TDIO, true ); // we want SBW
|
|
busy_wait_ms(20);//busy_wait_us_32(1);
|
|
gpio_put(PINOUT_SBW_TCK , false); // latch "we want SBW"
|
|
busy_wait_us_32(3);
|
|
gpio_put(PINOUT_SBW_TCK , true ); // start SBW stuff
|
|
busy_wait_ms(5);//busy_wait_us_32(100); // wait a bit more*/
|
|
|
|
#if 1
|
|
(void)nrst; // always assumed nrst=false here :/
|
|
// from slau320 sources
|
|
//gpio_put(PINOUT_SBW_TCK , false);
|
|
gpio_put(PINOUT_SBW_TDIO, true ); // FIXME: ummmm TCK ???
|
|
gpio_put(PINOUT_SBW_TDIO, false);
|
|
gpio_set_dir(PINOUT_SBW_TCK , true);
|
|
gpio_set_dir(PINOUT_SBW_TDIO, true);
|
|
gpio_set_function(PINOUT_SBW_TCK , GPIO_FUNC_SIO);
|
|
gpio_set_function(PINOUT_SBW_TDIO, GPIO_FUNC_SIO);
|
|
|
|
gpio_put(PINOUT_SBW_TCK , false);
|
|
gpio_put(PINOUT_SBW_TDIO, true);
|
|
busy_wait_ms(4); // reset TEST logic
|
|
gpio_put(PINOUT_SBW_TDIO, true);
|
|
busy_wait_us_32(1);
|
|
gpio_put(PINOUT_SBW_TCK , true);
|
|
busy_wait_ms(20); // activate TEST logic
|
|
|
|
// "phase 1"
|
|
gpio_put(PINOUT_SBW_TDIO, true);
|
|
busy_wait_us_32(60);
|
|
|
|
// "phase 2"
|
|
gpio_put(PINOUT_SBW_TCK , false);
|
|
|
|
// "phase 3"
|
|
busy_wait_us_32(1);
|
|
|
|
// "phase 4"
|
|
gpio_put(PINOUT_SBW_TCK , true);
|
|
busy_wait_us_32(60);
|
|
|
|
// "phase 5"
|
|
busy_wait_ms(5);
|
|
|
|
|
|
//// new impl:
|
|
#else
|
|
// from MSP430.DLL 'BIOS' (FETUIF?) sources
|
|
// can handle SBW/JTAG selection and nRST stuff
|
|
// ... but it doesn't seem to work
|
|
|
|
// TEST = TCK
|
|
// nRESET = TDIO = NMI
|
|
gpio_put(PINOUT_SBW_TCK , true/*false*/); // tck = test
|
|
gpio_put(PINOUT_SBW_TDIO, nrst/*true*/);
|
|
gpio_set_dir(PINOUT_SBW_TCK , true);
|
|
gpio_set_dir(PINOUT_SBW_TDIO, true);
|
|
gpio_set_function(PINOUT_SBW_TCK , GPIO_FUNC_SIO);
|
|
gpio_set_function(PINOUT_SBW_TDIO, GPIO_FUNC_SIO);
|
|
busy_wait_ms(4/*1*/); // 4?
|
|
|
|
gpio_put(PINOUT_SBW_TDIO, nrst);
|
|
busy_wait_us_32(1);
|
|
gpio_put(PINOUT_SBW_TCK , true);
|
|
// activate test logic
|
|
busy_wait_ms(20/*100*/); // 20 should be ok here I think?
|
|
|
|
// "phase 1"
|
|
gpio_put(PINOUT_SBW_TDIO, true); // false here if you want JTAG
|
|
busy_wait_us_32(40); // 60?
|
|
|
|
// "phase 2"
|
|
gpio_put(PINOUT_SBW_TCK, false); // ??? // true for JTAG?
|
|
|
|
// "phase 3"
|
|
// something (TDIO hi?) to do if RSTLOW & JTAG?
|
|
busy_wait_us_32(1);
|
|
|
|
// "phase 4"
|
|
gpio_put(PINOUT_SBW_TCK , true); // ??? // false for JTAG?
|
|
busy_wait_us_32(40/*60*/); // 40 should be ok here I think?
|
|
|
|
// phase 5
|
|
// something (TDIO hi?) to do if RSTHIGH & JTAG?
|
|
busy_wait_ms(5);
|
|
#endif
|
|
}
|
|
|
|
static int sbw_piosm = -1, sbw_offset = -1;
|
|
|
|
static bool last_tclk = true;
|
|
static uint8_t last_tdi = 0xff, last_tms = 0xff;
|
|
|
|
bool sbw_init(void) {
|
|
if (sbw_piosm >= 0 || sbw_offset >= 0) return false;
|
|
|
|
if (!pio_can_add_program(PINOUT_SBW_PIO, &sbw_program)) return false;
|
|
sbw_offset = pio_add_program(PINOUT_SBW_PIO, &sbw_program);
|
|
|
|
sbw_piosm = pio_claim_unused_sm(PINOUT_SBW_PIO, false);
|
|
if (sbw_piosm < 0) {
|
|
pio_remove_program(PINOUT_SBW_PIO, &sbw_program, sbw_offset);
|
|
sbw_offset = -1;
|
|
return false;
|
|
}
|
|
|
|
// need to start at 50 kHz: fuse check needs TMS cycles with a low phase
|
|
// of at least 5us. 50 kHz is below the required time (the actual maximum
|
|
// frequency would be around 80 kHz), but the exact frequency doesn't
|
|
// matter much as we'll switch to a higher one once the check has been
|
|
// completed
|
|
sbw_pio_init(PINOUT_SBW_PIO, sbw_piosm, sbw_offset, 50e3,
|
|
PINOUT_SBW_TCK, PINOUT_SBW_TDIO);
|
|
|
|
last_tdi = last_tms = 0xff;
|
|
last_tclk = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
void sbw_deinit(void) {
|
|
if (sbw_piosm >= 0) {
|
|
pio_sm_set_enabled(PINOUT_SBW_PIO, sbw_piosm, false);
|
|
pio_sm_unclaim(PINOUT_SBW_PIO, sbw_piosm);
|
|
sbw_piosm = -1;
|
|
}
|
|
|
|
if (sbw_offset >= 0) {
|
|
pio_remove_program(PINOUT_SBW_PIO, &sbw_program, sbw_offset);
|
|
sbw_offset = -1;
|
|
}
|
|
}
|
|
|
|
void sbw_set_freq(bool tclk, float freq) {
|
|
if (tclk) {
|
|
sbw_pio_set_tclkfreq(PINOUT_SBW_PIO, sbw_piosm, freq);
|
|
} else {
|
|
sbw_pio_set_baudrate(PINOUT_SBW_PIO, sbw_piosm, freq);
|
|
}
|
|
}
|
|
|
|
static uint8_t bitswap(uint8_t in) {
|
|
static const uint8_t lut[16] = {
|
|
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
|
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
|
|
};
|
|
|
|
return (lut[in&0xf] << 4) | lut[in>>4];
|
|
}
|
|
|
|
#define piosm_txf(width) (*(io_wo_##width *)&PINOUT_SBW_PIO->txf[sbw_piosm])
|
|
#define piosm_rxf(width) (*(io_ro_##width *)&PINOUT_SBW_PIO->rxf[sbw_piosm])
|
|
#define piosm_txf_wait() while (pio_sm_is_tx_fifo_full(PINOUT_SBW_PIO, sbw_piosm)) tight_loop_contents()
|
|
|
|
bool sbw_get_last_tms(void) { return last_tms; }
|
|
bool sbw_get_last_tdi(void) { return last_tdi; }
|
|
bool sbw_get_last_tclk(void) { return last_tclk; }
|
|
|
|
void sbw_sequence(uint32_t ncyc, bool tms, const uint8_t* tdi, uint8_t* tdo) {
|
|
if (ncyc == 0) return;
|
|
|
|
uint32_t nbytes = (ncyc + 7) >> 3;
|
|
uint32_t last_shift = (8 - ncyc) & 7;
|
|
|
|
uint32_t txremain = nbytes,
|
|
rxremain = last_shift ? nbytes : (nbytes + 1);
|
|
|
|
// initial TMS value in y
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_sety(tms ? 1 : 0);
|
|
|
|
// number of cycles in x
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_outx(32);
|
|
piosm_txf_wait();
|
|
piosm_txf(32) = ncyc - 1;
|
|
|
|
// jmp to correct subroutine
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_jmp(sbw_offset_sbw_seq + sbw_offset);
|
|
|
|
for (size_t oi = 0, ii = 0; txremain || rxremain; tight_loop_contents()) {
|
|
if (txremain && !pio_sm_is_tx_fifo_full(PINOUT_SBW_PIO, sbw_piosm)) {
|
|
piosm_txf(8) = bitswap(tdi ? tdi[ii] : last_tdi);
|
|
--txremain;
|
|
++ii;
|
|
}
|
|
|
|
if (rxremain && !pio_sm_is_rx_fifo_empty(PINOUT_SBW_PIO, sbw_piosm)) {
|
|
uint8_t ov = piosm_rxf(8);
|
|
--rxremain;
|
|
|
|
if (tdo && oi < nbytes) {
|
|
if (last_shift && oi == nbytes - 1) {
|
|
tdo[oi] = bitswap(ov) >> last_shift;
|
|
} else {
|
|
tdo[oi] = bitswap(ov);
|
|
}
|
|
++oi;
|
|
}
|
|
}
|
|
}
|
|
|
|
//while (!sbw_pio_is_idle(PINOUT_SBW_PIO, sbw_piosm, sbw_offset)) tight_loop_contents();
|
|
|
|
if (tdi) last_tdi = (tdi[nbytes - 1] & (1 << (ncyc & 7))) ? 0xff : 0;
|
|
last_tms = tms ? 0xff : 0;
|
|
}
|
|
|
|
void sbw_tms_sequence(uint32_t ncyc, bool tdi, const uint8_t* tms) {
|
|
if (ncyc == 0 || !tms) return;
|
|
|
|
uint32_t nbytes = (ncyc + 7) >> 3;
|
|
uint32_t txremain = nbytes;
|
|
|
|
// initial TDI value in y
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_sety(tdi ? 1 : 0);
|
|
|
|
// number of cycles in x
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_outx(32);
|
|
piosm_txf_wait();
|
|
piosm_txf(32) = ncyc - 1;
|
|
|
|
// jmp to correct subroutine
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_jmp(sbw_offset_sbw_tms_seq + sbw_offset);
|
|
|
|
for (size_t ii = 0; txremain; tight_loop_contents()) {
|
|
if (txremain && !pio_sm_is_tx_fifo_full(PINOUT_SBW_PIO, sbw_piosm)) {
|
|
piosm_txf(8) = bitswap(tms[ii]);
|
|
--txremain;
|
|
++ii;
|
|
}
|
|
}
|
|
|
|
//while (!sbw_pio_is_idle(PINOUT_SBW_PIO, sbw_piosm, sbw_offset)) tight_loop_contents();
|
|
|
|
last_tdi = tdi ? 0xff : 0;
|
|
last_tms = (tms[nbytes - 1] & (1 << (ncyc & 7))) ? 0xff : 0;
|
|
}
|
|
|
|
void sbw_clrset_tclk(bool value) {
|
|
//sbw_pio_loadbearing_set_setpins(PINOUT_SBW_PIO, value ? 1 : 0); // new value
|
|
|
|
// pre-TCLK value
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_sety(last_tclk ? 1 : 0);
|
|
|
|
// only one TCLK
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_setx(0);
|
|
|
|
// jmp to subroutine
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_jmp(sbw_offset_sbw_tclk_burst + sbw_offset);
|
|
|
|
// always use out pins, 1
|
|
piosm_txf_wait();
|
|
piosm_txf(8) = value ? 0xff : 0;
|
|
|
|
// wait until done
|
|
/*while ( sbw_pio_is_idle(PINOUT_SBW_PIO, sbw_piosm, sbw_offset)) tight_loop_contents();
|
|
while (!sbw_pio_is_idle(PINOUT_SBW_PIO, sbw_piosm, sbw_offset)) tight_loop_contents();*/
|
|
|
|
last_tclk = value;
|
|
}
|
|
|
|
void sbw_tclk_burst(uint32_t ncyc) {
|
|
//sbw_pio_loadbearing_set_outpins(PINOUT_SBW_PIO);
|
|
|
|
uint32_t txremain = ((ncyc + 7) >> 3) * 2 - 1;
|
|
|
|
// MSB-first
|
|
uint8_t pattern = last_tclk ? 0x55 : 0xaa;
|
|
|
|
// pre-TCLK value
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_sety(last_tclk ? 1 : 0);
|
|
|
|
// number of TCLK half-cycles in x
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_outx(32);
|
|
piosm_txf_wait();
|
|
piosm_txf(32) = ncyc*2 - 1;
|
|
|
|
// jmp to subroutine
|
|
piosm_txf_wait();
|
|
piosm_txf(16) = sbw_pio_gen_jmp(sbw_offset_sbw_tclk_burst + sbw_offset);
|
|
|
|
for (; txremain; tight_loop_contents()) {
|
|
if (txremain && !pio_sm_is_tx_fifo_full(PINOUT_SBW_PIO, sbw_piosm)) {
|
|
piosm_txf(8) = pattern;
|
|
--txremain;
|
|
}
|
|
}
|
|
|
|
// wait until done
|
|
/*while ( sbw_pio_is_idle(PINOUT_SBW_PIO, sbw_piosm, sbw_offset)) tight_loop_contents();
|
|
while (!sbw_pio_is_idle(PINOUT_SBW_PIO, sbw_piosm, sbw_offset)) tight_loop_contents();*/
|
|
|
|
// last_tclk doesn't change - always an even number of TCLK half-cycles
|
|
}
|
|
|