From 984c06c6028f27ef87d7b9453c8c61045b8d26dd Mon Sep 17 00:00:00 2001 From: travisutk Date: Fri, 4 Feb 2011 01:28:42 +0000 Subject: [PATCH] Spy-Bi-Wire support, from examples by Mark rages. git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@881 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- firmware/Makefile | 3 + firmware/apps/jtag/jtag430.c | 44 +-- firmware/apps/jtag/jtag430x2.c | 2 - firmware/apps/jtag/sbw.c | 590 +++++++++++++++++++++++++++++++-- firmware/include/sbw.h | 15 +- 5 files changed, 601 insertions(+), 53 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 86e794b..fd0fdbf 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -128,6 +128,7 @@ ifeq ($(filter sbw, $(config)), sbw) hdrs+= jtag.h endif apps+= apps/jtag/sbw.o + hdrs+= sbw.h endif # include jtag430 app @@ -227,6 +228,8 @@ ifeq ($(filter avr, $(config)), avr) hdrs+= avr.h endif + + # include pic app ifeq ($(filter pic, $(config)), pic) apps+= apps/pic/pic.o diff --git a/firmware/apps/jtag/jtag430.c b/firmware/apps/jtag/jtag430.c index 88c9f0f..2338847 100644 --- a/firmware/apps/jtag/jtag430.c +++ b/firmware/apps/jtag/jtag430.c @@ -14,19 +14,18 @@ void jtag430_handle_fn(uint8_t const app, // define the jtag430 app's app_t app_t const jtag430_app = { - - /* app number */ - JTAG430, - - /* handle fn */ - jtag430_handle_fn, - - /* name */ - "JTAG430", - - /* desc */ - "\tThe JTAG430 app adds to the basic JTAG app\n" - "\tsupport for JTAG'ing MSP430 devices.\n" + /* app number */ + JTAG430, + + /* handle fn */ + jtag430_handle_fn, + + /* name */ + "JTAG430", + + /* desc */ + "\tThe JTAG430 app adds to the basic JTAG app\n" + "\tsupport for JTAG'ing MSP430 devices.\n" }; unsigned int jtag430mode=MSP430X2MODE; @@ -376,8 +375,8 @@ void jtag430_setinstrfetch(){ //! Handles classic MSP430 JTAG commands. Forwards others to JTAG. void jtag430_handle_fn(uint8_t const app, - uint8_t const verb, - uint32_t const len) + uint8_t const verb, + uint32_t const len) { unsigned long at, l; unsigned int i, val; @@ -472,21 +471,6 @@ void jtag430_handle_fn(uint8_t const app, cmddataword[0]=jtag430_readmem(cmddataword[0]); txdata(app,verb,2); break; - /* - case JTAG430_WRITEFLASH: - - //debugstr("Poking flash memory."); - jtag430_writeflash(cmddataword[0],cmddataword[2]); - - //Try again if failure. - //if(cmddataword[2]!=jtag430_readmem(cmddataword[0])) - // jtag430_writeflash(cmddataword[0],cmddataword[2]); - - //Return result. - cmddataword[0]=jtag430_readmem(cmddataword[0]); - - txdata(app,verb,2); - break; */ case JTAG430_WRITEFLASH: at=cmddataword[0]; diff --git a/firmware/apps/jtag/jtag430x2.c b/firmware/apps/jtag/jtag430x2.c index 16eeb94..1528e7c 100644 --- a/firmware/apps/jtag/jtag430x2.c +++ b/firmware/apps/jtag/jtag430x2.c @@ -175,8 +175,6 @@ void jtag430x2_handle_fn( uint8_t const app, uint8_t const verb, uint32_t const len) { - register char blocks; - unsigned int i,val; unsigned long at, l; diff --git a/firmware/apps/jtag/sbw.c b/firmware/apps/jtag/sbw.c index 9d4dbce..b263b73 100644 --- a/firmware/apps/jtag/sbw.c +++ b/firmware/apps/jtag/sbw.c @@ -10,34 +10,148 @@ #include "platform.h" #include "command.h" -#include "jtag.h" +//#include "jtag.h" +#include "jtag430.h" + +#define SBWREWRITE #include "sbw.h" -void sbwsetup(){ - /* To select the 2-wire SBW mode, the SBWTDIO line is held high and - the first clock is applied on SBWTCK. After this clock, the - normal SBW timings are applied starting with the TMS slot, and - the normal JTAG patterns can be applied, typically starting with - the Tap Reset and Fuse Check sequence. The SBW mode is exited by - holding the TEST/SWBCLK low for more than 100 μs. - */ +// define the sbw app's app_t +app_t const sbw_app = { + /* app number */ + SBW, + + /* handle fn */ + sbw_handler_fn, + + /* name */ + "SBW", + + /* desc */ + "\tThe SBW app adds to the basic JTAG app\n" + "\tsupport for SBW'ing MSP430 devices with two wires.\n" +}; - // tdio up, tck low - P5OUT &= ~SBWTCK; - P5OUT |= SBWTDIO; - P5DIR |= SBWTDIO|SBWTCK; +//! Shift 8 bits in and out. +unsigned char sbwtrans8(unsigned char byte){ + unsigned int bit; + SAVETCLK; + for (bit = 0; bit < 8; bit++) { + /* write MOSI on trailing edge of previous clock */ + if (byte & 0x80) + {SETMOSI;} + else + {CLRMOSI;} + byte <<= 1; + + if(bit==7) + SETTMS;//TMS high on last bit to exit. + + TCKTOCK; + /* read MISO on trailing edge */ + byte |= READMISO; + } + RESTORETCLK; + + // update state + CLRTMS; + TCKTOCK; + + return byte; +} - msdelay(1); - SBWCLK(); +//! Shift n bits in and out. +unsigned long sbwtransn(unsigned long word, + unsigned int bitcount){ + unsigned int bit; + //0x8000 + unsigned long high=0x8000; + + if(bitcount==20) + high=0x80000; + if(bitcount==16) + high= 0x8000; + + SAVETCLK; + + for (bit = 0; bit < bitcount; bit++) { + /* write MOSI on trailing edge of previous clock */ + if (word & high) + {SETMOSI;} + else + {CLRMOSI;} + word <<= 1; + + if(bit==bitcount-1) + SETTMS;//TMS high on last bit to exit. + + TCKTOCK; + /* read MISO on trailing edge */ + word |= READMISO; + } + + if(bitcount==20){ + word = ((word << 16) | (word >> 4)) & 0x000FFFFF; + } + + RESTORETCLK; + + // update state + CLRTMS; + TCKTOCK; + + return word; +} - SBWCLK(); - // now we're in SBW mode + +//! Shift all bits of the DR. +u32 sbw_dr_shift20(unsigned long in){ + // idle + SETTMS; + TCKTOCK; + // select DR + CLRTMS; + TCKTOCK; + // capture IR + TCKTOCK; + + // shift DR, then idle + return(sbwtransn(in,20)); +} + + +//! Shift 16 bits of the DR. +u16 sbw_dr_shift16(unsigned int in){ + // idle + SETTMS; // 1 + TCKTOCK; + // select DR + CLRTMS; // 0 + TCKTOCK; + // capture IR + TCKTOCK; + + // shift DR, then idle + return(sbwtransn(in,16)); } -void sbwhandle(u8 app, u8 verb, u8 len){ - debugstr("Coming soon."); - txdata(app,NOK,0); + +//! Shift 8 bits of the IR. +u8 sbw_ir_shift8(unsigned char in){ + // idle + SETTMS; + TCKTOCK; + // select DR + TCKTOCK; + // select IR + CLRTMS; + TCKTOCK; + // capture IR + TCKTOCK; + + // shift IR, then idle. + return(sbwtrans8(in)); } @@ -103,3 +217,439 @@ void sbwCLRTCLK(){ P5DIR |= SBWTDIO; } + + + +//! Set the program counter. +void sbw430_setpc(unsigned int adr){ + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x3401);// release low byte + sbw_ir_shift8(IR_DATA_16BIT); + sbw_dr_shift16(0x4030);//Instruction to load PC + CLRTCLK; + SETTCLK; + sbw_dr_shift16(adr);// Value for PC + CLRTCLK; + sbw_ir_shift8(IR_ADDR_CAPTURE); + SETTCLK; + CLRTCLK ;// Now PC is set to "PC_Value" + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2401);// low byte controlled by SBW +} + +//! Halt the CPU +void sbw430_haltcpu(){ + //sbw430_setinstrfetch(); + + sbw_ir_shift8(IR_DATA_16BIT); + sbw_dr_shift16(0x3FFF);//JMP $+0 + + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2409);//set SBW_HALT bit + SETTCLK; +} + +//! Release the CPU +void sbw430_releasecpu(){ + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2401); + sbw_ir_shift8(IR_ADDR_CAPTURE); + SETTCLK; +} + +//! Read data from address +unsigned int sbw430_readmem(unsigned int adr){ + unsigned int toret; + sbw430_haltcpu(); + + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + + if(adr>0xFF) + sbw_dr_shift16(0x2409);//word read + else + sbw_dr_shift16(0x2419);//byte read + sbw_ir_shift8(IR_ADDR_16BIT); + sbw_dr_shift16(adr);//address + sbw_ir_shift8(IR_DATA_TO_ADDR); + SETTCLK; + + CLRTCLK; + toret=sbw_dr_shift16(0x0000);//16 bit return + + return toret; +} + +//! Write data to address. +void sbw430_writemem(unsigned int adr, unsigned int data){ + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + if(adr>0xFF) + sbw_dr_shift16(0x2408);//word write + else + sbw_dr_shift16(0x2418);//byte write + sbw_ir_shift8(IR_ADDR_16BIT); + sbw_dr_shift16(adr); + sbw_ir_shift8(IR_DATA_TO_ADDR); + sbw_dr_shift16(data); + SETTCLK; +} + +//! Write data to flash memory. Must be preconfigured. +void sbw430_writeflashword(unsigned int adr, unsigned int data){ + + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2408);//word write + sbw_ir_shift8(IR_ADDR_16BIT); + sbw_dr_shift16(adr); + sbw_ir_shift8(IR_DATA_TO_ADDR); + sbw_dr_shift16(data); + SETTCLK; + + //Return to read mode. + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2409); + + /* + sbw430_writemem(adr,data); + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2409); + */ + + debugstr("ERROR: Haven't got ASM to flash-pulse SBW."); + + //Pulse TCLK + //sbw430_tclk_flashpulses(35); //35 standard +} + +//! Configure flash, then write a word. +void sbw430_writeflash(unsigned int adr, unsigned int data){ + sbw430_haltcpu(); + + //FCTL1=0xA540, enabling flash write + sbw430_writemem(0x0128, 0xA540); + //FCTL2=0xA540, selecting MCLK as source, DIV=1 + sbw430_writemem(0x012A, 0xA540); + //FCTL3=0xA500, should be 0xA540 for Info Seg A on 2xx chips. + sbw430_writemem(0x012C, 0xA500); //all but info flash. + + //Write the word itself. + sbw430_writeflashword(adr,data); + + //FCTL1=0xA500, disabling flash write + sbw430_writemem(0x0128, 0xA500); + + //sbw430_releasecpu(); +} + + + +//! Power-On Reset +void sbw430_por(){ + unsigned int sbwid; + + // Perform Reset + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2C01); // apply + sbw_dr_shift16(0x2401); // remove + CLRTCLK; + SETTCLK; + CLRTCLK; + SETTCLK; + CLRTCLK; + sbwid = sbw_ir_shift8(IR_ADDR_CAPTURE); // get SBW identifier + SETTCLK; + + sbw430_writemem(0x0120, 0x5A80); // Diabled Watchdog +} + + + +#define ERASE_GLOB 0xA50E +#define ERASE_ALLMAIN 0xA50C +#define ERASE_MASS 0xA506 +#define ERASE_MAIN 0xA504 +#define ERASE_SGMT 0xA502 + +//! Configure flash, then write a word. +void sbw430_eraseflash(unsigned int mode, unsigned int adr, unsigned int count){ + sbw430_haltcpu(); + + //FCTL1= erase mode + sbw430_writemem(0x0128, mode); + //FCTL2=0xA540, selecting MCLK as source, DIV=1 + sbw430_writemem(0x012A, 0xA540); + //FCTL3=0xA500, should be 0xA540 for Info Seg A on 2xx chips. + sbw430_writemem(0x012C, 0xA500); + + //Write the erase word. + sbw430_writemem(adr, 0x55AA); + //Return to read mode. + CLRTCLK; + sbw_ir_shift8(IR_CNTRL_SIG_16BIT); + sbw_dr_shift16(0x2409); + + //Send the pulses. + debugstr("ERROR: Haven't got ASM to flash-pulse SBW."); + //sbw430_tclk_flashpulses(count); + + //FCTL1=0xA500, disabling flash write + sbw430_writemem(0x0128, 0xA500); + + //sbw430_releasecpu(); +} + + +//! Reset the TAP state machine. +void sbw430_resettap(){ + int i; + // Settle output + SETTDI; //430X2 + SETTMS; + //SETTDI; //classic + TCKTOCK; + + // Navigate to reset state. + // Should be at least six. + for(i=0;i<4;i++){ + TCKTOCK; + } + + // test-logic-reset + CLRTMS; + TCKTOCK; + + SETTMS; + // idle + + + /* sacred, by spec. + Sometimes this isn't necessary. */ + // fuse check + CLRTMS; + delay(50); + SETTMS; + CLRTMS; + delay(50); + SETTMS; + /**/ + +} + +void sbwsetup(){ + + /* To select the 2-wire SBW mode, the SBWTDIO line is held high and + the first clock is applied on SBWTCK. After this clock, the + normal SBW timings are applied starting with the TMS slot, and + the normal JTAG patterns can be applied, typically starting with + the Tap Reset and Fuse Check sequence. The SBW mode is exited by + holding the TEST/SWBCLK low for more than 100 μs. + */ + + // tdio up, tck low + // + P5OUT &= ~SBWTCK; + P5OUT |= SBWTDIO; + P5DIR |= SBWTDIO|SBWTCK; + + msdelay(5); + SBWCLK(); + + SBWCLK(); + + // now we're in SBW mode +} + + +//! Start SBW, take pins +void sbw430_start(){ + sbwsetup(); + + //Known-good starting position. + //Might be unnecessary. + SETTST; + SETRST; + delay(0xFFFF); + + sbwsetup(); + + //Perform a reset and disable watchdog. + sbw430_por(); + sbw430_writemem(0x120,0x5a80);//disable watchdog + sbw430_haltcpu(); +} + +//! Start normally, not SBW. +void sbw430_stop(){ + debugstr("Exiting SBW."); + sbwsetup(); + + //Known-good starting position. + //Might be unnecessary. + //SETTST; + CLRTST; + SETRST; + delay(0xFFFF); + + //Entry sequence from Page 67 of SLAU265A for 4-wire MSP430 SBW + CLRRST; + delay(0xFFFF); + SETRST; + //P5DIR&=~RST; + //delay(0xFFFF); + +} + +//! Set CPU to Instruction Fetch +void sbw430_setinstrfetch(){ + + sbw_ir_shift8(IR_CNTRL_SIG_CAPTURE); + + // Wait until instruction fetch state. + while(1){ + if (sbw_dr_shift16(0x0000) & 0x0080) + return; + CLRTCLK; + SETTCLK; + } +} + + +//! Stop JTAG, release pins +void sbw_stop(){ + P5OUT=0; + P4OUT=0; +} + + + +//! Handles classic MSP430 SBW commands. Forwards others to SBW. + +void sbw_handler_fn(u8 app, u8 verb, u32 len){ + unsigned long at; + unsigned int i, val; + + + /* FIXME + * Sometimes SBW doesn't init correctly. + * This restarts the connection if the masked-rom + * chip ID cannot be read. Should print warning + * for testing server. + */ + while((i=sbw430_readmem(0xff0))==0xFFFF){ + debugstr("start"); + sbw430_start(); + P1OUT^=1; + } + P1OUT&=~1; + + + //debughex(verb); + switch(verb){ + case SETUP: + sbwsetup(); + txdata(app,verb,0); + break; + case START: + //Enter SBW mode. + sbw430_start(); + //TAP setup, fuse check + sbw430_resettap(); + + cmddata[0]=sbw_ir_shift8(IR_BYPASS); + //cmddata[0]=0x89; //STINT + txdata(app,verb,1); + break; + case STOP: + sbw430_stop(); + txdata(app,verb,0); + break; + case JTAG430_HALTCPU: + sbw430_haltcpu(); + txdata(app,verb,0); + break; + case JTAG430_RELEASECPU: + sbw430_releasecpu(); + txdata(app,verb,0); + break; + case JTAG430_SETINSTRFETCH: + sbw430_setinstrfetch(); + txdata(app,verb,0); + break; + + case JTAG430_READMEM: + case PEEK: + at=cmddatalong[0]; + + //Fetch large blocks for bulk fetches, + //small blocks for individual peeks. + if(len>5) + len=(cmddataword[2]);//always even. + else + len=2; + len&=~1;//clear lsbit + + txhead(app,verb,len); + for(i=0;i>8); + } + break; + case JTAG430_WRITEMEM: + case POKE: + sbw430_haltcpu(); + sbw430_writemem(cmddataword[0],cmddataword[2]); + cmddataword[0]=sbw430_readmem(cmddataword[0]); + txdata(app,verb,2); + break; + + case JTAG430_WRITEFLASH: + at=cmddataword[0]; + + for(i=0;i<(len>>1)-2;i++){ + //debugstr("Poking flash memory."); + sbw430_writeflash(at+(i<<1),cmddataword[i+2]); + //Reflash if needed. Try this twice to save grace? + if(cmddataword[i]!=sbw430_readmem(at)) + sbw430_writeflash(at+(i<<1),cmddataword[i+2]); + } + + //Return result of first write as a word. + cmddataword[0]=sbw430_readmem(cmddataword[0]); + + txdata(app,verb,2); + break; + case JTAG430_ERASEFLASH: + sbw430_eraseflash(ERASE_MASS,0xFFFE,0x3000); + txdata(app,verb,0); + break; + case JTAG430_SETPC: + sbw430_haltcpu(); + sbw430_setpc(cmddataword[0]); + sbw430_releasecpu(); + txdata(app,verb,0); + break; + + case JTAG430_COREIP_ID: + case JTAG430_DEVICE_ID: + cmddataword[0]=0; + cmddataword[1]=0; + txdata(app,verb,4); + break; + + default: + //sbwhandle(app,verb,len); + debugstr("ERROR, classic JTAG instruction in SBW."); + txdata(app,verb,4); + } + //sbw430_resettap(); //DO NOT UNCOMMENT +} diff --git a/firmware/include/sbw.h b/firmware/include/sbw.h index 4bd4f5e..91fcad1 100644 --- a/firmware/include/sbw.h +++ b/firmware/include/sbw.h @@ -6,6 +6,11 @@ #ifndef SBW_H #define SBW_H +#include "app.h" +extern app_t const sbw_app; + +#define SBW 0x17 + #include "platform.h" #include "command.h" #include "app.h" @@ -23,13 +28,21 @@ // I/O Redefintions extern int tms, tdi, tdo; +#undef SETTMS #define SETTMS tms=1 +#undef CLRTMS #define CLRTMS tms=0 +#undef SETTDI #define SETTDI tdi=1 +#undef CLRTDI #define CLRTDI tdi=0 +#undef TCKTOCK #define TCKTOCK clock_sbw() +#undef SETMOSI #define SETMOSI SETTDI +#undef CLRMOSI #define CLRMOSI CLRTDI +#undef READMISO #define READMISO tdo #endif @@ -38,7 +51,7 @@ extern int tms, tdi, tdo; void sbwsetup(); //! Handle a SBW request. -void sbwhandle(u8 app, u8 verb, u8 len); +void sbw_handler_fn(u8 app, u8 verb, u32 len); //! Perform a SBW bit transaction. void clock_sbw(); -- 2.20.1