From: thequux Date: Mon, 17 Jan 2011 06:36:10 +0000 (+0000) Subject: Preliminary support for PIC24F chips with tblpag at an odd address; finally updated... X-Git-Url: http://git.rot13.org/?p=goodfet;a=commitdiff_plain;h=7be58170d7eb36a7dc06a65bd065dbf0c03d5317 Preliminary support for PIC24F chips with tblpag at an odd address; finally updated avr docs git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@843 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- diff --git a/client/goodfet.pic b/client/goodfet.pic index 7fb9e9e..40de634 100755 --- a/client/goodfet.pic +++ b/client/goodfet.pic @@ -24,6 +24,14 @@ from intelhex import IntelHex PICAPP = 0x34 MONITORAPP = 0x00 NOK = 0x7E + +VERB_CMDLIST = 0x88 + +# 0x32 is the normal address of the TBLPAG register. On some PICs, +# though, it appears at 0x54 (see DS39970B). Affected PIC families +# include: PIC24FJxxx{DA1,DA2,GB2,GA3}xx +tblpag = 0x32 + dev_table = { 0x00EE : "dsPIC33FJ128GP708", 0x00EF : "dsPIC33FJ128GP710", 0x080A : "PIC24HJ12GP201", @@ -44,7 +52,26 @@ dev_table = { 0x00EE : "dsPIC33FJ128GP708", 0x040C : "PIC24FJ96GA010", 0x0407 : "PIC24FJ128GA006", 0x040A : "PIC24FJ128GA008", - 0x040D : "PIC24FJ128GA010" } + 0x040D : "PIC24FJ128GA010", + 0x4109 : "PIC24FJ128DA106", + 0x410D : "PIC24FJ256DA106", + 0x410B : "PIC24FJ128DA110", + 0x410F : "PIC24FJ256DA110", + 0x4108 : "PIC24FJ128DA206", + 0x410C : "PIC24FJ256DA206", + 0x410A : "PIC24FJ128DA210", + 0x410E : "PIC24FJ256DA210", + 0x46C0 : "PIC24FJ64GA306", + 0x46C4 : "PIC24FJ64GA308", + 0x46C8 : "PIC24FJ64GA310", + 0x46C2 : "PIC24FJ128GA306", + 0x46C6 : "PIC24FJ128GA308", + 0x46CA : "PIC24FJ128GA310", + 0x4100 : "PIC24FJ128GB206", + 0x4104 : "PIC24FJ256GB206", + 0x4102 : "PIC24FJ128GB210", + 0x4106 : "PIC24FJ256GB210", + } cfg_table = { 0xF80000 : "FBS", 0xF80002 : "FSS", 0xF80004 : "FGS", @@ -80,6 +107,84 @@ Assumes ICSP session already started.""" stopICSP() exit(-1) +class PicResponseThunk(object): + """A holder for a response value from the PIC, eg from a REGOUT + command. + + To retrieve the value, simply call the object. If the value has + not yet been retrieved, any pending commands in the command buffer + will be executed. You can determine whether the response has been + recieved by calling the have_response function. + + Objects of this class should only be created by the PicCmdBuffer + class""" + + def __init__(self, cmdbuf): + self.holder = cmdbuf + self.value = None + + def _set_value(self, value): + self.value = value + def have_response(self): + return self.value is not None + def __call__(self): + if self.value is None: + self.holder.force() + assert self.value is not None + return self.value + +class PicCmdBuffer(object): + def __init__(self, client): + self.client = client + self.buffered_commands = [] + self.response_buffer = [] + data = client.writecmd(MONITORAPP, 0xc2) + assert data is not None and len(data) is 2 + # buffer size is the size of the goodfet's recieve buffer, in + # instructions + self.buffer_size = (ord(data[0]) + (ord(data[1]) << 8)) >> 2 + def force(self): + assert len(self.buffered_commands) <= self.buffer_size + command = ''.join(self.buffered_commands) + self.buffered_commands = [] + #print "Running: " + command.encode('hex') + data = self.client.writecmd(PICAPP, VERB_CMDLIST, + len(command), map(ord, command)) + #print "Recieved: " + data.encode('hex') + assert len(data) == (len(self.response_buffer) + 1) * 2 + orig_data = data + checksum = 0 + for resp in self.response_buffer: + wd, data = data[0:2],data[2:] + val = ord(wd[0]) + (ord(wd[1]) << 8) + checksum += val + resp._set_value(val) + assert len(data) == 2 + checksum += ord(data[0]) + (ord(data[1]) << 8) + checksum &= 0xffff + assert checksum == 0 + self.response_buffer = [] + def _add_command(self, command, data): + assert command in (0,1) + assert (data >> 24) == 0 + full_cmd = [chr(command)] + for i in (0,1,2): + full_cmd.append(chr((data >> (8*i)) & 0xff)) + if len(self.buffered_commands) >= self.buffer_size: + self.force() + self.buffered_commands.append(''.join(full_cmd)) + def SIX(self, *insns): + """Run a list of instructions""" + for insn in insns: + self._add_command(0, insn) + return self + def REGOUT(self): + "Read the VISI register. Returns a PicResponseThunk" + thunk = PicResponseThunk(self) + self.response_buffer.append(thunk) + self._add_command(1, 0) + return thunk + def build_instr_stream( cmd_li ): """Given a list of instruction words, returns a list of bytes of the same, in little endian ordering.""" @@ -148,7 +253,7 @@ Returns an instance of IntelHex corresponding to result. Note that we start and stop an ICSP session here! This means an existing session will be broken.""" readpm_cmd_li = [0x200000, # MOV #addr<23:16>, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag << 3, # MOV W0, TBLPAG 0x200006, # MOV #addr<15:0>, W6 0xEB0380, # CLR W7 0x000000, # NOP @@ -259,7 +364,7 @@ Returns [-1] on failure.""" ############# if len(sys.argv) == 1: - print "Usage: %s verb [objects]\n" % sys.argv[0] + print "Usage: %s [-alt_tblpag] verb [objects]\n" % sys.argv[0] print "%s devid" % sys.argv[0] print "%s read 0x$addr" % sys.argv[0] print "%s dump $foo.hex [0x$start 0x$stop] [pretty]" % sys.argv[0] @@ -275,6 +380,7 @@ if len(sys.argv) == 1: print "%s regout" % sys.argv[0] print """ Note: use - for stdout. + use -alt_tblpag for PIC24FJxxx{DA1,DA2,GB2,GA3}xx with tblpag at 0x54 Warning: only formally supports dsPIC33F/PIC24H, but read/write flash memory works with PIC24F ... """ @@ -285,33 +391,58 @@ client = GoodFET() client.verbose = False # Dump activity to terminal client.serInit( timeout=10 ) # UART comm timeout (in seconds) +if sys.argv[1] == "-alt_tblpag": + del sys.argv[1] + tblpag = 0x54 # Handle each possible PIC verb in turn - if sys.argv[1] == "devid": #0x81 print "Requesting Application ID, DEVID and hardware revision..." - data = client.writecmd( PICAPP, 0x81, 0 ) - - if len(data) > 0: - appid = ord(data[0]) - else: - appid = -1 - if len(data) > 2: - devid = ord(data[1]) + (ord(data[2]) << 8) - else: - devid = -1 - if len(data) > 4: - hwrev = ord(data[3]) + (ord(data[4]) << 8) - else: - hwrev = -1 - print "Application ID: 0x%02X" % appid - if dev_table.has_key( devid ): - print "DEVID: 0x%04X (%s)" % ( devid, dev_table[devid] ) - else: - print "DEVID: 0x%04X (unknown)" % devid - print "revision: 0x%04X"% hwrev + startICSP() + cmdbuf = PicCmdBuffer(client) + cmdbuf.SIX(0x040200, # GOTO 0x200 + 0x000000, # NOP + 0x200FF0, # MOV #0xff, W0 + 0x880000 | tblpag << 3, # MOV W0, TBLPAG + 0x200006, # MOV #0x0000, W6 + 0x207847, # MOV #VISI, W7 + 0x000000, # NOP + 0xBA0B96, # TBLRDL [W6],[W7] + 0x000000, # NOP + 0x000000) # NOP + devid = cmdbuf.REGOUT() + cmdbuf.SIX(0x200026, # MOV #0x0002, W6 + 0x000000, # NOP + 0xBA0B96, # TBLRDL [W6],[W7] + 0x000000, # NOP + 0x000000) # NOP + devidrev = cmdbuf.REGOUT() + cmdbuf.SIX(0x200800, # MOV #0x80, W0 + 0x880000 | tblpag << 3, # MOV W0, TBLPAG + 0x207F00, # MOV #0x07F0, W6 + 0x000000, # NOP + 0xBA0B96, # TBLRDL [W6],[W7] + 0x000000, # NOP + 0x000000) # NOP + appid = cmdbuf.REGOUT() + print "Application ID: 0x%02x" % appid() + print "DEVID: 0x%04x (%s)" % ( + devid(), dev_table.get(devid(), "unknown")) + print "Revision: 0x%04x" % devidrev() + stopICSP() #print "\n(Note that -1 indicates failure to read a value.)" +elif sys.argv[1] == "test": + startICSP() + cmdbuf = PicCmdBuffer(client) + cmdbuf.SIX(0x2BEEF6, # MOV #0xBEEF, W6 + 0x000000, + 0x780B86, # MOV W6, [W7] + 0x000000, # NOP + 0x000000) # NOP + assert cmdbuf.REGOUT()() == 0xbeef + stopICSP() + elif sys.argv[1] == "reset": client.writecmd( PICAPP, 0x87, 0 ) @@ -319,7 +450,7 @@ elif sys.argv[1] == "config": # Dump configuration registers prep_cmd_li = [0x040200, # GOTO 0x0200 0x000000, # 0x200F80, # MOV #0x00F8, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag << 3, # MOV W0, TBLPAG 0xEB0300, # CLR W6 0x207847, # MOV #VISI, W7 0x000000] # NOP @@ -366,7 +497,7 @@ elif sys.argv[1] == "program": 0x24001A, # MOV $0x4001, W10 0x883B0A, # MOV W10, NVMCON 0x200000, # + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag << 3, # MOV W0, TBLPAG 0x200007] # + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7 # Load 4 instructions into write latches @@ -458,7 +589,7 @@ elif sys.argv[1] == "program": 0x24000A, # MOV #0x4000, W10 0x883B0A, # MOV W10, NVMCON 0x200F80, # MOV #0xF8, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag<< 3, # MOV W0, TBLPAG 0x200000 + ((proghex[addr]&0x00ff)<<4), # MOV #new_val<7:0>, W0 0xBB0B80, # TBLWTL W0, [W7] 0x000000, # NOP @@ -539,7 +670,7 @@ elif sys.argv[1] == "write": 0x24003A, # MOV $0x4003, W10 0x883B0A, # MOV W10, NVMCON 0x200000 + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag << 3, # MOV W0, TBLPAG 0x200007 + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7 # Here we load the instruction into registers W0:W1 @@ -618,7 +749,7 @@ elif sys.argv[1] == "write_config": 0x24000A, # MOV #0x4000, W10 0x883B0A, # MOV W10, NVMCON 0x200F80, # MOV #0xF8, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag << 3, # MOV W0, TBLPAG 0x200000 + ((new_val&0xffff)<<4), # MOV #, W0 0xBB0B80, # TBLWTL W0, [W7] 0x000000, # NOP @@ -648,7 +779,7 @@ elif sys.argv[1] == "read": # Read an address of program memory readpm_cmd_li = [0x040200, # GOTO 0x0200 0x000000, # 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag << 3, # MOV W0, TBLPAG 0x200006+((addr & 0xffff)<<4), # MOV #addr<15:0>, W6 0xEB0380, # CLR W7 0xEB0080, # CLR W1 @@ -722,7 +853,7 @@ elif sys.argv[1] == "erase": # Bulk (all program memory) or page erase 0x24042A, # MOV $0x4042, W10 0x883B0A, # MOV W10, NVMCON 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0 - 0x880190, # MOV W0, TBLPAG + 0x880000 | tblpag << 3, # MOV W0, TBLPAG 0x200001+((addr&0xffff)<<4), # MOV addr<15:0>, W1 0x000000, # NOP 0xBB0881, # TBLTWL W1, [W1] diff --git a/firmware/apps/pic/pic.c b/firmware/apps/pic/pic.c index 4e25fea..0c8664e 100644 --- a/firmware/apps/pic/pic.c +++ b/firmware/apps/pic/pic.c @@ -1,3 +1,4 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: t -*- */ /*! \file dspic33f.c \author Scott Livingston @@ -14,6 +15,8 @@ #include "pic.h" +#define CYCLE_DELAY() delay_ticks(10); + //! Handle a PIC command; currently assumes dsPIC33F/PIC24H void pic_handle_fn( uint8_t const app, uint8_t const verb, @@ -101,6 +104,10 @@ void pic_handle_fn( uint8_t const app, txdata(app,verb,0); break; + case PIC_CMDLIST: + pic33f_cmdlist(len); // reply is handled by pic33f_cmdlist + break; + default: debugstr( "Verb unimplemented in PIC application." ); txdata(app,NOK,0); @@ -109,6 +116,23 @@ void pic_handle_fn( uint8_t const app, } } +void pic33f_transcmd(unsigned char cmd) { + int i = 0; + DIR_PGD_WR; + CLR_PGC; + for (i = 0; i < 4; i++) { + if (cmd & 0x1) + SET_PGD; + else + CLR_PGD; + CYCLE_DELAY(); + SET_PGC; + cmd >>= 1; + CYCLE_DELAY(); + CLR_PGC; + } + CLR_PGD; +} void pic33f_trans8( unsigned char byte ) { @@ -117,20 +141,19 @@ void pic33f_trans8( unsigned char byte ) unsigned int i; DIR_PGD_WR; // Write mode - i = 1; - while (i & 0xff) { - if (byte & i) { + for (i = 0; i < 8; i++) { + if (byte & 0x01) { SET_PGD; } else { CLR_PGD; } - delay_ticks(10); + CYCLE_DELAY(); SET_PGC; - delay_ticks(10); + byte >>= 1; + CYCLE_DELAY(); CLR_PGC; - delay_ticks(10); - i = i << 1; + //CYCLE_DELAY(); } CLR_PGD; DIR_PGD_RD; // Read mode @@ -152,16 +175,7 @@ void pic33f_six( unsigned int highb, unsigned int loww ) Shift in the instruction. Note that it does not execute until the next 4 clock cycles (which also corresponds to a command receipt time). */ - unsigned int i; - DIR_PGD_WR; - CLR_PGD; - CLR_PGC; - for (i = 0; i < 4; i++) { - SET_PGC; - delay_ticks(10); - CLR_PGC; - delay_ticks(10); - } + pic33f_transcmd(0); pic33f_trans16( loww ); pic33f_trans8( highb ); DIR_PGD_RD; @@ -176,28 +190,14 @@ unsigned int pic33f_regout() DIR_PGD_WR; // Shift in command (REGOUT: 0001b). - SET_PGD; - delay_ticks(10); - SET_PGC; - delay_ticks(10); - CLR_PGC; - delay_ticks(10); - - CLR_PGD; - delay_ticks(10); - for (i = 0; i < 3; i++) { - SET_PGC; - delay_ticks(10); - CLR_PGC; - delay_ticks(10); - } + pic33f_transcmd(1); // Pump clock for 8 cycles, and switch PGD direction to read. for (i = 0; i < 7; i++) { SET_PGC; - delay_ticks(10); + CYCLE_DELAY(); CLR_PGC; - delay_ticks(10); + CYCLE_DELAY(); } DIR_PGD_RD; @@ -206,24 +206,90 @@ unsigned int pic33f_regout() be read) on falling clock edges. */ for (i = 0; i < 16; i++) { SET_PGC; - delay_ticks(10); + CYCLE_DELAY(); CLR_PGC; result |= READ_PGD << i; - delay_ticks(10); + CYCLE_DELAY(); } - +#if 1 /* One last tick apparently is needed here, at least by the dsPIC33FJ128GP708 chip that I am working with. Note that this is not in the flash programming specs. */ SET_PGC; - delay_ticks(10); + CYCLE_DELAY(); CLR_PGC; - delay_ticks(10); + CYCLE_DELAY(); +#endif return result; } +void pic33f_cmdlist(unsigned int list_len) { + /* commands are written as 4-byte little-endian records, where + the low 4 bits of first byte contains the command, and the + next three bytes contain the data. + + Currently this only supports the SIX and REGOUT + instructions. + + SIX instructions return no data. REGOUT instructions return + the 16-bit value read as two bytes, lower byte first. + + The final two bytes of the response are the 2's complement + inverse of the sum of the response words. i.e., if the + response is correctly recieved, the sum of the words should + be 0. + + This is sent when the goodfet is done running the command + list, and is ready for further commands. + */ + + unsigned char cmd; + unsigned int response_word; + unsigned int checksum = 0; + int response_count; + int i; + list_len &= ~3; // truncate to multiple of 4 bytes. + if (list_len > CMDDATALEN) + list_len = CMDDATALEN; + response_count = 1; + for (i = 0; i < list_len; i += 4) { + cmd = cmddata[i]; + if (cmd == 0) + continue; + else if (cmd == 1) + response_count ++; + else + goto error; + } + txhead(PIC, PIC_CMDLIST, response_count << 1); + + for (i = 0; i < list_len; i+= 4) { + cmd = cmddata[i]; + if (cmd == 0) { + // SIX command + pic33f_transcmd(0); + pic33f_trans8(cmddata[i+1]); + pic33f_trans8(cmddata[i+2]); + pic33f_trans8(cmddata[i+3]); + + } else if (cmd == 1) { + // REGOUT command + response_word = pic33f_regout(); + checksum += response_word; + response_count--; + txword(response_word); + } + } + txword(~checksum + 1); + if (response_count != 1) + debugstr("Response count wrong"); + return; + error: + txdata(PIC, NOK, 0); +} +/* This should be replaced by pic33f_cmdlist */ void pic33f_sixlist( unsigned int list_len ) { unsigned int k; @@ -245,6 +311,7 @@ void pic33f_sixlist( unsigned int list_len ) } +/* This is slated to be replaced by pic33f_cmdlist */ unsigned int pic33f_getid() { unsigned int result; @@ -336,9 +403,9 @@ void pic33f_connect() CLR_PGC; for (key_low = 0; key_low < 33; key_low++) { SET_PGC; - delay_us(1); + CYCLE_DELAY(); CLR_PGC; - delay_us(1); + CYCLE_DELAY(); } DIR_PGD_RD; diff --git a/firmware/include/pic.h b/firmware/include/pic.h index e95c054..3bd69f7 100644 --- a/firmware/include/pic.h +++ b/firmware/include/pic.h @@ -69,6 +69,9 @@ unsigned int pic33f_regout(); //! Execute a list of commands on attached dsPIC33F/PIC24H. void pic33f_sixlist( unsigned int list_len ); +//! Execute a list of ICSP commands on attached PIC +void pic33f_cmdlist(unsigned int list_len); + //! Start Enhanced ICSP session with dsPIC33F/PIC24H (assumes Programming Executive is present). void pic33f_eicsp_connect(); @@ -96,6 +99,7 @@ void pic33f_trans8( unsigned char byte ); #define PIC_SIXLIST33F 0x86 /* Buffers list of instructions to MSP430, then executes them over ICSP session with target dsPIC33F/PIC24H chip. */ +#define PIC_CMDLIST 0x88 /* Similar to PIC_SIXLIST33F, but includes ICSP command */ #define PIC_RESET33F 0x87 // Reset attached dsPIC33F/PIC24H chip. #define PIC_START33F 0x84 // Start ICSP session