From 46060f6ffd72fe43a3d273ccec0a637c6b628bc0 Mon Sep 17 00:00:00 2001 From: alexeybb Date: Thu, 17 Nov 2011 02:47:33 +0000 Subject: [PATCH] Added support for Silicon Lab's c8051 MCUs. git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@1064 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- client/GoodFETSLC2.py | 40 +++ client/Makefile | 4 + client/goodfet.slc2 | 36 +++ firmware/apps/slc2/slc2.c | 520 ++++++++++++++++++++++++++++++++++++++ firmware/config.mk | 3 +- firmware/include/slc2.h | 92 +++++++ 6 files changed, 694 insertions(+), 1 deletion(-) create mode 100644 client/GoodFETSLC2.py create mode 100644 client/goodfet.slc2 create mode 100644 firmware/apps/slc2/slc2.c create mode 100644 firmware/include/slc2.h diff --git a/client/GoodFETSLC2.py b/client/GoodFETSLC2.py new file mode 100644 index 0000000..dac5067 --- /dev/null +++ b/client/GoodFETSLC2.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# GoodFET Client Library + +import sys; +import binascii; + +from GoodFET import GoodFET; + +class GoodFETSLC2(GoodFET): + """GoodFET variant for the Silicon lab C2 protocol""" + APP=0x06; + + def setup(self): + """Setup the SLC2 protocol""" + self.writecmd(0x06, 0x10, 0); + + def reset(self): + self.writecmd(0x06, 0x84, 0); + + def peekblock(self, addr, len): + """Grab block from FLASH at address addr""" + dat= [addr&0xFF, (addr&0xFF00)>>8]; + self.writecmd(0x06, 0x02, 2, dat); + return self.data; + + def pokeblock(self, addr, len, data): + d = [len, data]; + self.writecmd(0x06, 0x03, len, d); + + def getdevid(self): + return self.writecmd(0x06, 0x80, 0, []); + + def getrevid(self): + return self.writecmd(0x06, 0x81, 0, []); + + def page_erase(self, addr): + self.writecmd(0x06, 0x82, 1, addr); + + def device_erase(self): + self.writecmd(0x06, 0x83, 0, []); diff --git a/client/Makefile b/client/Makefile index c2241b6..d0b4c5f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -67,6 +67,10 @@ py2exe: sed s/PYTHONCONSOLE/goodfet.spi25c/ setup.py python setup.py py2exe mv dist/goodfet.exe dist/gfspi25.exe +#Silicon Labs C2 + sed s/PYTHONCONSOLE/goodfet.slc2/ setup.py + python setup.py py2exe + mv dist/goodfet.exe dist/gfslc2.exe #Goodfet. This must be last. sed s/PYTHONCONSOLE/goodfet/ setup.py diff --git a/client/goodfet.slc2 b/client/goodfet.slc2 new file mode 100644 index 0000000..d76aa45 --- /dev/null +++ b/client/goodfet.slc2 @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# GoodFET - Silicon Lab C2 + +import sys; +import binascii; +import array; +import pdb; +import time; + +from GoodFETSLC2 import GoodFETSLC2; +from intelhex import IntelHex; + + + +#Initialize FET and set baud rate +#pdb.set_trace(); +client=GoodFETSLC2(); +client.serInit(); + +if(sys.argv[1]=="devid"): + client.setup(); + data = client.getrevid(); + #pdb.set_trace(); + print "dumping contents of 8051 FLASH in dump.txt"; + file = open("dump.bin", mode='wb') + address = 0; + while address < 65535: + data = client.peekblock(address,2); + address+= 2; + for j in data: + print j; + file.write(j); + file.close(); + + diff --git a/firmware/apps/slc2/slc2.c b/firmware/apps/slc2/slc2.c new file mode 100644 index 0000000..66b2fdd --- /dev/null +++ b/firmware/apps/slc2/slc2.c @@ -0,0 +1,520 @@ +/*! \file slc2.c + \author Alexey Borisenko + \brief Silicon Labs C2 Debug interface + */ + +#include "command.h" + +#ifdef __MSPGCC__ +#include +#else +#include +#include +#include +#endif + +#include "slc2.h" + +#include "platform.h" + + +//----------------------------------------------------------------------------------- +// Global VARIABLES +//----------------------------------------------------------------------------------- +unsigned char NUM_BYTES; +unsigned int FLASH_ADDR; +unsigned char *C2_PTR; + +//! Handles a monitor command. +void slc2_handle_fn( uint8_t const app, + uint8_t const verb, + uint32_t const len); + +// define the spi app's app_t +app_t const slc2_app = { + + /* app number */ + SLC2, + + /* handle fn */ + slc2_handle_fn, + + /* name */ + "Silicon Labs C2", + + /* desc */ + "\tThis app handles Silicon Lab's C2 debugging protocol.\n" +}; + +//----------------------------------------------------------------------------------- +// FLASH Programming Routines (High Level) +//----------------------------------------------------------------------------------- +// +// These high-level routines perform the FLASH Programming Interface (FPI) +// command sequences. +//----------------------------------------------------------------------------------- +// C2_Init() +//----------------------------------------------------------------------------------- +// - Initializes the C2 Interface for FLASH programming +// +void C2_Init() +{ + C2CKOUTPUT; + C2D_DriverOff; + C2_Reset(); // Reset the target device + delay_us(2); // Delay for at least 2us + C2_WriteAR(FPCTL); // Target the C2 FLASH Programming +// Control register (FPCTL) for C2 Data +// register accesses + C2_WriteDR(0x02); // Write the first key code to enable +// C2 FLASH programming + C2_WriteDR(0x01); // Write the second key code to enable +// C2 FLASH programming + delay_us(20000); // Delay for at least 20ms to ensure the +// target is ready for C2 FLASH programming +} +//----------------------------------------------------------------------------------- +// C2_GetDevID() +//----------------------------------------------------------------------------------- +// - Reads the target Devcie ID register and Revision ID register +// +unsigned char C2_GetDevID() +{ + C2_WriteAR(DEVICEID); // Select DeviceID regsiter for C2 Data +// register accesses + return C2_ReadDR(); // Read and return the DeviceID register +} + +//----------------------------------------------------------------------------------- +// C2_GetDevID() +//----------------------------------------------------------------------------------- +// - Reads the target Devcie ID register and Revision ID register +// +unsigned char C2_GetRevID() +{ + C2_WriteAR(REVID); // Select DeviceID regsiter for C2 Data +// register accesses + return C2_ReadDR(); // Read and return the DeviceID register +} + +//----------------------------------------------------------------------------------- +// C2_BlockRead() +//----------------------------------------------------------------------------------- +// - Reads a block of FLASH memory starting at +// - The size of the block is defined by +// - Stores the read data at the location targeted by the pointer +// - Assumes that FLASH accesses via C2 have been enabled prior to the function call +// - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful +// +char C2_BlockRead() +{ + unsigned char i; // Counter + unsigned char status; // FPI status information holder + C2_WriteAR(FPDAT); // Select the FLASH Programming Data register +// for C2 Data register accesses + C2_WriteDR(BLOCK_READ); // Send FLASH block read command + Poll_InBusy; // Wait for input acknowledge +// Check status before starting FLASH access sequence + Poll_OutReady; // Wait for status information + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error + C2_WriteDR(FLASH_ADDR >> 8); // Send address high byte to FPDAT + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(FLASH_ADDR & 0x00FF); // Send address low byte to FPDAT + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(NUM_BYTES); // Send block size + Poll_InBusy; // Wait for input acknowledge +// Check status before reading FLASH block + Poll_OutReady; // Wait for status information + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error +// Read FLASH block + for (i=0; i +// - The size of the block is defined by +// - Writes the block stored at the location targetted by +// - Assumes that FLASH accesses via C2 have been enabled prior to the function call +// - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful +// +char C2_BlockWrite() +{ + unsigned char i; // Counter + unsigned char status; // FPI status information holder + C2_WriteAR(FPDAT); // Select the FLASH Programming Data register +// for C2 Data register accesses + C2_WriteDR(BLOCK_WRITE); // Send FLASH block write command + Poll_InBusy; // Wait for input acknowledge +// Check status before starting FLASH access sequence + Poll_OutReady; // Wait for status information + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error + C2_WriteDR(FLASH_ADDR >> 8); // Send address high byte to FPDAT + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(FLASH_ADDR & 0x00FF); // Send address low byte to FPDAT + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(NUM_BYTES); // Send block size + Poll_InBusy; // Wait for input acknolwedge + +// Check status before starting FLASH access sequence + Poll_OutReady; // Wait for status information + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error + C2_WriteDR(FLASH_ADDR >> 8); // Send address high byte to FPDAT + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(FLASH_ADDR & 0x00FF); // Send address low byte to FPDAT + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(NUM_BYTES); // Send block size + Poll_InBusy; // Wait for input acknolwedge +// Check status before writing FLASH block + Poll_OutReady; // Wait for status information + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error +// Write FLASH block + for (i=0; i +// - Assumes that FLASH accesses via C2 have been enabled prior to the function call +// - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful +// +char C2_PageErase() +{ + unsigned char page; // Target FLASH page + unsigned char status; // FPI status information holder + + page = (unsigned char)(FLASH_ADDR >> 9); +// is the 512-byte sector containing +// the target . + if (page >= NUM_PAGES - 1) // Check that target page is within range +// (NUM_PAGES minus 1 for reserved area) + return 0; // Indicate error if out of range + C2_WriteAR(FPDAT); // Select the FLASH Programming Data register +// for C2 Data register accesses + C2_WriteDR(PAGE_ERASE); // Send FLASH page erase command + Poll_InBusy; // Wait for input acknowledge +// Check status before starting FLASH access sequence + Poll_OutReady; // Wait for status information + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error + C2_WriteDR(page); // Send FLASH page number + Poll_InBusy; // Wait for input acknowledge + Poll_OutReady; // Wait for ready indicator + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error + C2_WriteDR(0x00); // Dummy write to initiate erase + Poll_InBusy; // Wait for input acknowledge + Poll_OutReady; // Wait for erase operation to complete + return 1; // Exit and indicate success +} +//----------------------------------------------------------------------------------- +// C2_Device_Erase() +//----------------------------------------------------------------------------------- +// - Erases the entire FLASH memory space +// - Assumes that FLASH accesses via C2 have been enabled prior to the function call +// - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful +// +char C2_DeviceErase() +{ + unsigned char status; // FPI status information holder + C2_WriteAR(FPDAT); // Select the FLASH Programming Data register +// for C2 Data register accesses + C2_WriteDR(DEVICE_ERASE); // Send Device Erase command + Poll_InBusy; // Wait for input acknowledge +// Check status before starting FLASH access sequence + Poll_OutReady; // Wait for status information + status = C2_ReadDR(); // Read FLASH programming interface status + if (status != COMMAND_OK) + return 0; // Exit and indicate error +// Send a three-byte arming sequence to enable the device erase. If the sequence +// is not received correctly, the command will be ignored. +// Sequence: 0xDE, 0xAD, 0xA5. + + C2_WriteDR(0xDE); // Arming sequence command 1 + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(0xAD); // Arming sequence command 2 + Poll_InBusy; // Wait for input acknowledge + C2_WriteDR(0xA5); // Arming sequence command 3 + Poll_InBusy; // Wait for input acknowledge + Poll_OutReady; // Wait for erase operation to complete + return 1; // Exit and indicate success +} +//----------------------------------------------------------------------------------- +// Primitive C2 Command Routines +//----------------------------------------------------------------------------------- +// +// These routines perform the low-level C2 commands: +// 1. Address Read +// 2. Address Write +// 3. Data Read +// 4. Data Write +// 5. Device Reset +//----------------------------------------------------------------------------------- +// C2_ReadAR() +//----------------------------------------------------------------------------------- +// - Performs a C2 Address register read +// - Returns the 8-bit register content +// +unsigned char C2_ReadAR() +{ + unsigned char i; // Bit counter + unsigned char addr; // Address register read content +// START field + StrobeC2CK; // Strobe C2CK with C2D driver disabled +// INS field (10b, LSB first) + CLRC2D; + C2D_DriverOn; // Enable C2D driver (output) + StrobeC2CK; + SETC2D; + StrobeC2CK; + C2D_DriverOff; // Disable C2D driver (input) +// ADDRESS field + addr = 0; + for (i=0; i<8; i++) // Shift in 8 bit ADDRESS field + { // LSB-first + addr >>= 1; + StrobeC2CK; + if (READC2D) + addr |= 0x80; + } +// STOP field + StrobeC2CK; // Strobe C2CK with C2D driver disabled + + return addr; // Return Address register read value +} +//----------------------------------------------------------------------------------- +// C2_WriteAR() +//----------------------------------------------------------------------------------- +// - Performs a C2 Address register write (writes the input +// to Address register) +// +void C2_WriteAR(unsigned char addr) +{ + unsigned char i; // Bit counter +// START field + StrobeC2CK; // Strobe C2CK with C2D driver disabled +// INS field (11b, LSB first) + SETC2D; + C2D_DriverOn; // Enable C2D driver (output) + StrobeC2CK; + SETC2D; + StrobeC2CK; +// ADDRESS field + for(i=0; i<8; i++) // Shift out 8-bit ADDRESS field + { + if(addr & 0x01) + SETC2D; + else + CLRC2D; + StrobeC2CK; + addr >>= 1; + } +// STOP field + C2D_DriverOff; // Disable C2D driver + StrobeC2CK; // Strobe C2CK with C2D driver disabled + return; +} +//----------------------------------------------------------------------------------- +// C2_ReadDR() +//----------------------------------------------------------------------------------- +// - Performs a C2 Data register read +// - Returns the 8-bit register content +// +unsigned char C2_ReadDR() +{ + unsigned char i; // Bit counter + unsigned char dat; // Data register read content +// START field + StrobeC2CK; // Strobe C2CK with C2D driver disabled +// INS field (00b, LSB first) + CLRC2D; + C2D_DriverOn; // Enable C2D driver (output) + StrobeC2CK; + CLRC2D; + StrobeC2CK; + +// LENGTH field (00b -> 1 byte) + CLRC2D; + StrobeC2CK; + CLRC2D; + StrobeC2CK; +// WAIT field + C2D_DriverOff; // Disable C2D driver for input + do + { + StrobeC2CK; + } + while (!READC2D); // Strobe C2CK until target transmits a ‘1’ +// DATA field + dat = 0; + for (i=0; i<8; i++) // Shift in 8-bit DATA field + { // LSB-first + dat >>= 1; + StrobeC2CK; + if (READC2D) + dat |= 0x80; + } +// STOP field + StrobeC2CK; // Strobe C2CK with C2D driver disabled + return dat; +} + +//----------------------------------------------------------------------------------- +// C2_WriteDR() +//----------------------------------------------------------------------------------- +// - Performs a C2 Data register write (writes input to data register) +// +void C2_WriteDR(unsigned char dat) +{ + unsigned char i; // Bit counter +// START field + StrobeC2CK; // Strobe C2CK with C2D driver disabled +// INS field (01b, LSB first) + SETC2D; + C2D_DriverOn; // Enable C2D driver + StrobeC2CK; + CLRC2D; + StrobeC2CK; +// LENGTH field (00b -> 1 byte) + CLRC2D; + StrobeC2CK; + CLRC2D; + StrobeC2CK; +// DATA field + for (i=0; i<8; i++) // Shift out 8-bit DATA field + { // LSB-first + if(dat & 0x01) + SETC2D; + else + CLRC2D; + StrobeC2CK; + dat >>= 1; + } +// WAIT field + C2D_DriverOff; // Disable C2D driver for input + do + { + StrobeC2CK; // Strobe C2CK until target transmits a ‘1’ + } + while (!READC2D); +// STOP field + StrobeC2CK; // Strobe C2CK with C2D driver disabled + return; +} + +//----------------------------------------------------------------------------------- +// C2_Reset() +//----------------------------------------------------------------------------------- +// - Performs a target device reset by pulling the C2CK pin low for >20us +// +void C2_Reset() +{ + CLRC2CK; // Put target device in reset state by pulling + delay_us(20); // C2CK low for >20us + SETC2CK; // Release target device from reset +} + + + +//! Handles a monitor command. +void slc2_handle_fn( uint8_t const app, + uint8_t const verb, + uint32_t const len) +{ + prep_timer(); + unsigned char dev_id = 0; + unsigned char rev_id = 0; + switch(verb) + { + case PEEK: + //C2_Reset(); + //C2_Init(); + NUM_BYTES = 2; + FLASH_ADDR = (cmddata[1] << 8) + cmddata[0]; + C2_PTR = cmddata; //cmddata + 2; + //slc2_init();//// + if(C2_BlockRead()) { + txdata(app, verb, 2); + }else{ + txdata(app, NOK, 0); + } + break; + + case POKE: + NUM_BYTES = len; + FLASH_ADDR = (cmddata[1] << 8) + cmddata[0]; + C2_PTR = cmddata + 2; + if(C2_BlockWrite()) { + txhead(app, OK, 0); + }else{ + txhead(app, NOK, 0); + } + break; + + case SETUP: + C2_Reset(); + C2_Init(); + txdata(app,verb,0); + break; + + case GETDEVID: + dev_id = C2_GetDevID(); + cmddata[0] = dev_id; + txdata(app, verb, 1); + break; + + case GETREVID: + rev_id = C2_GetRevID(); + cmddata[0] = rev_id; + txdata(app, verb, 1); + break; + + case PERASE: + FLASH_ADDR = (cmddata[1] << 8) + cmddata[0]; + if(C2_PageErase()) { + txhead(app, OK, 0); + }else{ + txhead(app, NOK, 0); + } + break; + + case DERASE: + if(C2_DeviceErase()) { + txhead(app, OK, 0); + }else{ + txhead(app, NOK, 0); + } + break; + case VRESET: + C2_Reset(); + txdata(app,verb,0); + break; + default: + txdata(app, NOK, 0); + break; + } +} diff --git a/firmware/config.mk b/firmware/config.mk index 0660f25..196e1d8 100644 --- a/firmware/config.mk +++ b/firmware/config.mk @@ -62,7 +62,7 @@ $(error Please define board, as explained in the README) endif platform := $(board) -AVAILABLE_APPS = monitor spi jtag sbw jtag430 jtag430x2 i2c jtagarm7 ejtag jtagxscale openocd chipcon avr pic adc nrf ccspi glitch smartcard ps2 +AVAILABLE_APPS = monitor spi jtag sbw jtag430 jtag430x2 i2c jtagarm7 ejtag jtagxscale openocd chipcon avr pic adc nrf ccspi glitch smartcard ps2 slc2 CONFIG_sbw = y @@ -87,6 +87,7 @@ CONFIG_ccspi ?= y CONFIG_glitch ?= n CONFIG_smartcard ?= n CONFIG_ps2 ?= n +CONFIG_slc2 ?= n #The CONFIG_foo vars are only interpreted if $(config) is unset. ifeq ($(config),undef) diff --git a/firmware/include/slc2.h b/firmware/include/slc2.h new file mode 100644 index 0000000..8cded5c --- /dev/null +++ b/firmware/include/slc2.h @@ -0,0 +1,92 @@ +/*! \file slc2.h + \author Alexey Borisenko + \brief Definitions for Silicon Lab C2 debugging application + NOTE: FPDAT register address can be different, based on the device + Current address is meant for the 8051f34x +*/ + +#ifndef SLC2_H +#define SLC2_H + +#include "app.h" + +#define SLC2 0x06 + +//Pins and I/O +#define C2CK BIT7 +#define C2D BIT6 + +#define SETC2CK P3OUT |= C2CK +#define CLRC2CK P3OUT &= ~C2CK +#define SETC2D P3OUT |= C2D +#define CLRC2D P3OUT &= ~C2D + +#define READC2D (P3IN&C2D?1:0) + +#define C2CKOUTPUT P3DIR|=C2CK +#define C2D_DriverOff P3DIR&=~C2D +#define C2D_DriverOn P3DIR|=C2D + +#define DATA_READ 0x00 +#define ADDR_READ 0x02 +#define DATA_WRITE 0x01 +#define ADDR_WRITE 0x03 + +// FLASH information +#define FLASH_SIZE 65536 // FLASH size in bytes +#define NUM_PAGES FLASH_SIZE/512 // Number of 512-byte FLASH pages + +// C2 status return codes +#define INVALID_COMMAND 0x00 +#define COMMAND_FAILED 0x02 +#define COMMAND_OK 0x0D + +// C2 interface commands +#define GET_VERSION 0x01 +#define BLOCK_READ 0x06 +#define BLOCK_WRITE 0x07 +#define PAGE_ERASE 0x08 +#define DEVICE_ERASE 0x03 + +// C2 Registers +#define FPDAT 0xAD +#define FPCTL 0x02 +#define DEVICEID 0x00 +#define REVID 0x01 + +// Program MACROS +#define Poll_OutReady while(!(C2_ReadAR()&0x01)) +#define Poll_InBusy while((C2_ReadAR()&0x02)) +#define StrobeC2CK CLRC2CK; SETC2CK + +// C2 verbs +#define GETDEVID 0x80 +#define GETREVID 0x81 +#define PERASE 0x82 +#define DERASE 0x83 +#define VRESET 0x84 + +void slc2_handle_fn( uint8_t const app, + uint8_t const verb, + uint32_t const len); + +extern app_t const slc2_app; + +// FLASH programming functions +void C2_Init(); +unsigned char C2_GetDevID(void); +char C2_BlockRead(void); +char C2_BlockWrite(void); +char C2_PageErase(void); +char C2_DeviceErase(void); +// Primitive C2 functions +void C2_Reset(void); +void C2_WriteAR(unsigned char); +unsigned char C2_ReadAR(void); +void C2_WriteDR(unsigned char); +unsigned char C2_ReadDR(void); +unsigned char C2_ReadDeviceID(void); +unsigned char C2_ReadRevID(void); + + +#endif -- 2.20.1