diff --git a/cpu/msp430/buildscripts/Makefile.unix b/cpu/msp430/buildscripts/Makefile.unix new file mode 100644 index 000000000..bf1097601 --- /dev/null +++ b/cpu/msp430/buildscripts/Makefile.unix @@ -0,0 +1,18 @@ +ifndef JTAG + JTAG := $(CONTIKI_CPU)/buildscripts/jtag/pyjtag/jtag.py +endif + +ifndef JTAG_PORT + JTAG_PORT = /dev/ppi0 +endif + +%.u: %.$(TARGET) + $(JTAG) -l $(JTAG_PORT) -e + $(JTAG) -l $(JTAG_PORT) -D -D -S -R 2048 -p $^ + $(JTAG) -l $(JTAG_PORT) -D -r + +r: + $(JTAG) -l $(JTAG_PORT) -r + +erase: + $(JTAG) -l $(JTAG_PORT) -e diff --git a/cpu/msp430/buildscripts/Makefile.win b/cpu/msp430/buildscripts/Makefile.win new file mode 100644 index 000000000..edf3b615d --- /dev/null +++ b/cpu/msp430/buildscripts/Makefile.win @@ -0,0 +1,7 @@ +%.u: %.ihex + msp430-jtag -eI $^ + +#CW=cw23 + +#%.u: %.ihex +# $(CW) -d f430p $^ diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/_parjtag.so b/cpu/msp430/buildscripts/jtag/pyjtag/_parjtag.so new file mode 100755 index 000000000..76fe1ecba Binary files /dev/null and b/cpu/msp430/buildscripts/jtag/pyjtag/_parjtag.so differ diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/elf.py b/cpu/msp430/buildscripts/jtag/pyjtag/elf.py new file mode 100644 index 000000000..2ab16b1c2 --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/elf.py @@ -0,0 +1,318 @@ +#!/usr/bin/env python +import struct + +# ELF object file reader +# (C) 2003 cliechti@gmx.net +# Python license + +# size alignment +# Elf32_Addr 4 4 Unsigned program address +# Elf32_Half 2 2 Unsigned medium integer +# Elf32_Off 4 4 Unsigned file offset +# Elf32_Sword 4 4 Signed large integer +# Elf32_Word 4 4 Unsigned large integer +# unsignedchar 1 1 Unsigned small integer + +#define EI_NIDENT 16 +#~ typedef struct{ + #~ unsigned char e_ident[EI_NIDENT]; + #~ Elf32_Half e_type; + #~ Elf32_Half e_machine; + #~ Elf32_Word e_version; + #~ Elf32_Addr e_entry; + #~ Elf32_Off e_phoff; + #~ Elf32_Off e_shoff; + #~ Elf32_Word e_flags; + #~ Elf32_Half e_ehsize; + #~ Elf32_Half e_phentsize; + #~ Elf32_Half e_phnum; + #~ Elf32_Half e_shentsize; + #~ Elf32_Half e_shnum; + #~ Elf32_Half e_shstrndx; +#~ } Elf32_Ehdr; + + +#Section Header +#~ typedef struct { + #~ Elf32_Word sh_name; + #~ Elf32_Word sh_type; + #~ Elf32_Word sh_flags; + #~ Elf32_Addr sh_addr; + #~ Elf32_Off sh_offset; + #~ Elf32_Word sh_size; + #~ Elf32_Word sh_link; + #~ Elf32_Word sh_info; + #~ Elf32_Word sh_addralign; + #~ Elf32_Word sh_entsize; +#~ } Elf32_Shdr; + +#~ typedef struct { + #~ Elf32_Word p_type; + #~ Elf32_Off p_offset; + #~ Elf32_Addr p_vaddr; + #~ Elf32_Addr p_paddr; + #~ Elf32_Word p_filesz; + #~ Elf32_Word p_memsz; + #~ Elf32_Word p_flags; + #~ Elf32_Word p_align; +#~ } Elf32_Phdr; + + +class ELFException(Exception): pass + +class ELFSection: + """read and store a section""" + Elf32_Shdr = "= section.sh_addr + section.sh_size) \ + and (not (section.sh_flags & ELFSection.SHF_ALLOC and section.sh_type != ELFSection.SHT_NOBITS) \ + or (p.p_offset <= section.sh_offset \ + and (p.p_offset + p.p_filesz >= section.sh_offset + section.sh_size)))): + return section.sh_addr + p.p_paddr - p.p_vaddr + return section.sh_addr + + def getSections(self): + """get sections relevant for the application""" + res = [] + for section in self.sections: + if section.sh_flags & ELFSection.SHF_ALLOC and section.sh_type != ELFSection.SHT_NOBITS: + res.append(section) + return res + + def __str__(self): + """pretty print for debug...""" + return "%s(self.e_type=%r, self.e_machine=%r, self.e_version=%r, sections=%r)" % ( + self.__class__.__name__, + self.e_type, self.e_machine, self.e_version, + [section.name for section in self.sections]) + + +if __name__ == '__main__': + print "This is only a module test!" + elf = ELFObject() + elf.fromFile(open("test.elf")) + if elf.e_type != ELFObject.ET_EXEC: + raise Exception("No executable") + print elf + + #~ print repr(elf.getSection('.text').data) + #~ print [(s.name, hex(s.sh_addr)) for s in elf.getSections()] + print "-"*20 + for p in elf.sections: print p + print "-"*20 + for p in elf.getSections(): print p + print "-"*20 + for p in elf.getProgrammableSections(): print p diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/gen-ihex.py b/cpu/msp430/buildscripts/jtag/pyjtag/gen-ihex.py new file mode 100644 index 000000000..c917ec975 --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/gen-ihex.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +"""Test File generator. +This tool generates a hex file, of given size, ending on address +0xffff. + +USAGE: hen-ihex.py size_in_kilobyte + +The resulting Intel-hex file is output to stdout, use redirection +to save the data to a file. +""" + +#return a string with data in intel hex format +def makeihex(address, data): + out = [] + start = 0 + while start len(data): end = len(data) + out.append(_ihexline(address, [ord(x) for x in data[start:end]])) + start += 16 + address += 16 + out.append(_ihexline(address, [], end=1)) #append no data but an end line + return ''.join(out) + +def _ihexline(address, buffer, end=0): + out = [] + if end: + type = 1 + else: + type = 0 + out.append( ':%02X%04X%02X' % (len(buffer),address&0xffff,type) ) + sum = len(buffer) + ((address>>8)&255) + (address&255) + for b in buffer: + if b == None: b = 0 #substitute nonexistent values with zero + out.append('%02X' % (b&255) ) + sum += b&255 + out.append('%02X\n' %( (-sum)&255)) + return ''.join(out) + +if __name__ == '__main__': + import struct, sys + if len(sys.argv) != 2: + print __doc__ + sys.exit(1) + + size = int(sys.argv[1]) #in kilo + startadr = 0x10000 - 1024*size + data = ''.join([struct.pack(">H", x) for x in range(startadr, startadr+ 1024*size, 2)]) + print makeihex(startadr, data) diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/install-pyjtag.nsi b/cpu/msp430/buildscripts/jtag/pyjtag/install-pyjtag.nsi new file mode 100644 index 000000000..a2cb801b8 --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/install-pyjtag.nsi @@ -0,0 +1,108 @@ +Name "install-pyjtag" +OutFile "install-pyjtag.exe" + +!define SF_SELECTED 1 +!define SF_SUBSEC 2 +!define SF_SUBSECEND 4 +!define SF_BOLD 8 +!define SF_RO 16 +!define SF_EXPAND 32 + +!define SECTION_OFF 0xFFFFFFFE + +LicenseText License +LicenseData license.txt + +SetOverwrite on +SetDateSave on + +; The default installation directory +InstallDir $PROGRAMFILES\mspgcc +; Registry key to check for directory (so if you install again, it will +; overwrite the old one automatically) +InstallDirRegKey HKLM SOFTWARE\mspgcc "rootdir" + +; The text to prompt the user to enter a directory +DirText "This will install the pyjtag executables. You can choose the same \ + directory as for the other mspgcc tools." + +; The text to prompt the user to enter a directory +ComponentText "Select which optional things you want installed." + +Section "msp430-jtag (required)" + SectionIn RO + SetOutPath $INSTDIR + + File /r bin + File /oname=license-pyjtag.txt license.txt + File /oname=readme-pyjtag.txt readme.txt + File /oname=bin\jtag.py jtag.py + + ; Write the installation path into the registry + WriteRegStr HKLM SOFTWARE\mspgcc "rootdir" "$INSTDIR" + ; Write the uninstall keys for Windows + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\mspgcc-pyjtag" "DisplayName" "mspgcc pyjtag (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\mspgcc-pyjtag" "UninstallString" '"$INSTDIR\uninstall-pyjtag.exe"' + WriteUninstaller "uninstall-pyjtag.exe" +SectionEnd + +Section "giveio (needed on Win NT/2k/XP, but NOT on 9x/ME)" + SetOutPath $INSTDIR\bin + File ..\jtag\hardware_access\giveio\giveio.sys + File ..\jtag\hardware_access\giveio\loaddrv.exe + SetOutPath $INSTDIR + nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe install giveio $INSTDIR\bin\giveio.sys' + Pop $0 ;return value/error/timeout + IntCmp $0 2 ext_here ;assume its alredy installed + IntCmp $0 0 0 ext_err ext_err ;if not 0 -> error + nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe start giveio' + Pop $0 ;return value/error/timeout + IntCmp $0 0 0 ext_err ext_err ;if not 0 -> error + nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe starttype giveio auto' + Pop $0 ;return value/error/timeout + IntCmp $0 0 0 ext_err ext_err ;if not 0 -> error + WriteRegStr HKLM SOFTWARE\mspgcc "giveio" "started" + Goto ext_ok +ext_err: + DetailPrint "Error while installing and starting giveio" + MessageBox MB_OK|MB_ICONSTOP "Error while installing and starting giveio" + Goto ext_ok +ext_here: + DetailPrint "Installing giveio gave an error, assuming its already installed" +ext_ok: +SectionEnd + +; special uninstall section. +Section "Uninstall" + ; remove registry keys + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\mspgcc-pyjtag" + DeleteRegKey HKLM SOFTWARE\NSIS_Example2 + ; remove files + Delete $INSTDIR\bin\msp430-jtag.exe + Delete $INSTDIR\bin\_parjtag.pyd + Delete $INSTDIR\bin\jtag.py + Delete $INSTDIR\bin\HIL.dll + Delete $INSTDIR\bin\MSP430mspgcc.dll + ;XXX python22.dll is left installed as it is used by pybsl and other tools + Delete $INSTDIR\license-pyjtag.txt + Delete $INSTDIR\readme-pyjtag.txt + ; giveio + ; if it was started by us, stop it + ReadRegStr $0 HKLM SOFTWARE\mspgcc "giveio" + StrCmp $0 '' no_giveio + nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe stop giveio' + Pop $0 ;return value/error/timeout + IntCmp $0 0 0 giveio_err giveio_err ;if not 0 -> error + nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe remove giveio' + Pop $0 ;return value/error/timeout + IntCmp $0 0 0 giveio_err giveio_err ;if not 0 -> error + Goto no_giveio +giveio_err: + DetailPrint "Error while uninstalling giveio service" + MessageBox MB_OK|MB_ICONSTOP "Error while uninstalling giveio service" +no_giveio: + Delete loaddrv.exe + Delete giveio.sys + ; MUST REMOVE UNINSTALLER, too + Delete $INSTDIR\uninstall-pyjtag.exe +SectionEnd diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/jtag.py b/cpu/msp430/buildscripts/jtag/pyjtag/jtag.py new file mode 100755 index 000000000..0cb556a91 --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/jtag.py @@ -0,0 +1,604 @@ +#!/usr/bin/env python +#Parallel JTAG programmer for the MSP430 embedded proccessor. +# +#(C) 2002 Chris Liechti +#this is distributed under a free software license, see license.txt +# +#Requires Python 2+ and the binary extension _parjtag. + +import sys +import _parjtag + +VERSION = "1.3" + +DEBUG = 0 #disable debug messages by default + + +#frame specific consts +ERASE_MASS = 2 +ERASE_MAIN = 1 +ERASE_SGMT = 0 + +#states +FREERUNNING = 0 +STOPPED = 1 + +#Configurations of the MSP430 driver +VERIFICATION_MODE = 0 #Verify data downloaded to FLASH memories. +RAMSIZE_OPTION = 1 #Change RAM used to download and program flash blocks +DEBUG_OPTION = 2 #Set debug level. Enables debug outputs. + +#enumeration of output formats for uploads +HEX = 0 +INTELHEX = 1 +BINARY = 2 + +#exceptions +class JTAGException(Exception): pass + +#for the use with memread +def hexdump( (adr, memstr) ): + """Print a hex dump of data collected with memread + arg1: tuple with adress, memory + return None""" + count = 0 + ascii = '' + for value in map(ord, memstr): + if not count: print "%04x: " % adr, + print "%02x" % value, + ascii += (32 <= value < 128) and chr(value) or '.' + count += 1 + adr += 1 + if count == 16: + count = 0 + print " ", ascii + ascii = '' + if count < 16: print " "*(16-count), " ", ascii + +def makeihex( (address, data) ): + """work though the data and output lines in inzel hex format. + and end tag is appended""" + start = 0 + while start len(data): end = len(data) + _ihexline(address, [ord(x) for x in data[start:end]]) + start += 16 + address += 16 + _ihexline(address, [], type=1) #append no data but an end line + +def _ihexline(address, buffer, type=0): + """encode one line, output with checksum""" + sys.stdout.write( ':%02X%04X%02X' % (len(buffer), address & 0xffff, type) ) + sum = len(buffer) + ((address >> 8) & 255) + (address & 255) + for b in buffer: + if b == None: b = 0 #substitute nonexistent values with zero + sys.stdout.write('%02X' % (b & 255)) + sum += b&255 + sys.stdout.write('%02X\n' %( (-sum) & 255)) + + +class Segment: + """store a string with memory contents along with its startaddress""" + def __init__(self, startaddress = 0, data=None): + if data is None: + self.data = '' + else: + self.data = data + self.startaddress = startaddress + + def __getitem__(self, index): + return self.data[index] + + def __len__(self): + return len(self.data) + + def __repr__(self): + return "Segment(startaddress = 0x%04x, data=%r)" % (self.startaddress, self.data) + +class Memory: + """represent memory contents. with functions to load files""" + def __init__(self, filename=None): + self.segments = [] + if filename: + self.filename = filename + self.loadFile(filename) + + def append(self, seg): + self.segments.append(seg) + + def __getitem__(self, index): + return self.segments[index] + + def __len__(self): + return len(self.segments) + + def loadIHex(self, file): + """load data from a (opened) file in Intel-HEX format""" + segmentdata = [] + currentAddr = 0 + startAddr = 0 + lines = file.readlines() + for l in lines: + if not l.strip(): continue #skip empty lines + if l[0] != ':': raise Exception("File Format Error\n") + l = l.strip() #fix CR-LF issues... + length = int(l[1:3],16) + address = int(l[3:7],16) + type = int(l[7:9],16) + check = int(l[-2:],16) + if type == 0x00: + if currentAddr != address: + if segmentdata: + self.segments.append( Segment(startAddr, ''.join(segmentdata)) ) + startAddr = currentAddr = address + segmentdata = [] + for i in range(length): + segmentdata.append( chr(int(l[9+2*i:11+2*i],16)) ) + currentAddr = length + currentAddr + elif type == 0x01: + pass + else: + sys.stderr.write("Ignored unknown field (type 0x%02x) in ihex file.\n" % type) + if segmentdata: + self.segments.append( Segment(startAddr, ''.join(segmentdata)) ) + + def loadTIText(self, file): + """load data from a (opened) file in TI-Text format""" + next = 1 + currentAddr = 0 + startAddr = 0 + segmentdata = [] + #Convert data for MSP430, TXT-File is parsed line by line + while next >= 1: + #Read one line + l = file.readline() + if not l: break #EOF + l = l.strip() + if l[0] == 'q': break + elif l[0] == '@': #if @ => new address => send frame and set new addr. + #create a new segment + if segmentdata: + self.segments.append( Segment(startAddr, ''.join(segmentdata)) ) + startAddr = currentAddr = int(l[1:],16) + segmentdata = [] + else: + for i in l.split(): + segmentdata.append(chr(int(i,16))) + if segmentdata: + self.segments.append( Segment(startAddr, ''.join(segmentdata)) ) + + def loadELF(self, file): + """load data from a (opened) file in ELF object format. + File must be seekable""" + import elf + obj = elf.ELFObject() + obj.fromFile(file) + if obj.e_type != elf.ELFObject.ET_EXEC: + raise Exception("No executable") + for section in obj.getSections(): + if DEBUG: + sys.stderr.write("ELF section %s at 0x%04x %d bytes\n" % (section.name, section.lma, len(section.data))) + if len(section.data): + self.segments.append( Segment(section.lma, section.data) ) + + def loadFile(self, filename): + """fill memory with the contents of a file. file type is determined from extension""" + #TODO: do a contents based detection + if filename[-4:].lower() == '.txt': + self.loadTIText(open(filename, "rb")) + elif filename[-4:].lower() in ('.a43', '.hex'): + self.loadIHex(open(filename, "rb")) + else: + self.loadELF(open(filename, "rb")) + + def getMemrange(self, fromadr, toadr): + """get a range of bytes from the memory. unavailable values are filled with 0xff.""" + res = '' + toadr = toadr + 1 #python indxes are excluding end, so include it + while fromadr < toadr: + for seg in self.segments: + segend = seg.startaddress + len(seg.data) + if seg.startaddress <= fromadr and fromadr < segend: + if toadr > segend: #not all data in segment + catchlength = segend-fromadr + else: + catchlength = toadr-fromadr + res = res + seg.data[fromadr-seg.startaddress : fromadr-seg.startaddress+catchlength] + fromadr = fromadr + catchlength #adjust start + if len(res) >= toadr-fromadr: + break #return res + else: #undefined memory is filled with 0xff + res = res + chr(255) + fromadr = fromadr + 1 #adjust start + return res + +class JTAG: + """wrap the _parjtag extension""" + + def __init__(self): + self.showprogess = 0 + + def connect(self, lpt=None): + """connect to specified or default port""" + if lpt is None: + _parjtag.connect() + else: + _parjtag.connect(lpt) + + def close(self): + """release JTAG""" + _parjtag.release() + + def uploadData(self, startaddress, size): + """upload a datablock""" + if DEBUG > 1: sys.stderr.write("* uploadData()\n") + return _parjtag.memread(startaddress, size) + + def actionMassErase(self): + """Erase the flash memory completely (with mass erase command)""" + sys.stderr.write("Mass Erase...\n") + _parjtag.memerase(ERASE_MASS) + + def actionMainErase(self): + """Erase the MAIN flash memory, leave the INFO mem""" + sys.stderr.write("Erase Main Flash...\n") + _parjtag.memerase(ERASE_MAIN, 0xfffe) + + def makeActionSegmentErase(self, address): + """Selective segment erase""" + class SegmentEraser: + def __init__(self, segaddr): + self.address = segaddr + def __call__(self): + sys.stderr.write("Erase Segment @ 0x%04x...\n" % self.address) + _parjtag.memerase(ERASE_SGMT, self.address) + return SegmentEraser(address) + + def actionEraseCheck(self): + """check the erasure of required flash cells.""" + sys.stderr.write("Erase Check by file ...\n") + if self.data is not None: + for seg in self.data: + data = _parjtag.memread(seg.startaddress, len(seg.data)) + if data != '\xff'*len(seg.data): raise JTAGException("Erase check failed") + else: + raise JTAGException("cannot do erase check against data with not knowing the actual data") + + def progess_update(self, count, total): + sys.stderr.write("\r%d%%" % (100*count/total)) + + def actionProgram(self): + """program data into flash memory.""" + if self.data is not None: + sys.stderr.write("Program ...\n") + if self.showprogess: + _parjtag.set_flash_callback(self.progess_update) + bytes = 0 + for seg in self.data: + _parjtag.memwrite(seg.startaddress, seg.data) + bytes += len(seg.data) + if self.showprogess: + sys.stderr.write("\r") + sys.stderr.write("%i bytes programmed.\n" % bytes) + else: + raise JTAGException("programming without data not possible") + + def actionVerify(self): + """Verify programmed data""" + if self.data is not None: + sys.stderr.write("Verify ...\n") + for seg in self.data: + data = _parjtag.memread(seg.startaddress, len(seg.data)) + if data != seg.data: raise JTAGException("Verify failed") + else: + raise JTAGException("verify without data not possible") + + def actionReset(self): + """perform a reset""" + sys.stderr.write("Reset device ...\n") + _parjtag.reset(0, 0) + + def actionRun(self, address): + """start program at specified address""" + raise NotImplementedError + #sys.stderr.write("Load PC with 0x%04x ...\n" % address) + + def funclet(self): + """download and start funclet""" + sys.stderr.write("Download and execute of funclet...\n") + if len(self.data) > 1: + raise JTAGException("don't know how to handle multiple segments in funclets") + _parjtag.funclet(self.data[0].data) + sys.stderr.write("Funclet OK.\n") + +def usage(): + """print some help message""" + sys.stderr.write(""" +USAGE: %s [options] [file] +Version: %s + +If "-" is specified as file the data is read from the stdinput. +A file ending with ".txt" is considered to be in TIText format all +other filenames are considered IntelHex. + +General options: + -h, --help Show this help screen. + -l, --lpt=name Specify an other parallel port. + (defaults to LPT1 (/dev/parport0 on unix) + -D, --debug Increase level of debug messages. This won't be + very useful for the average user... + -I, --intelhex Force fileformat to IntelHex + -T, --titext Force fileformat to be TIText + -f, --funclet The given file is a funclet (a small program to + be run in RAM) + -R, --ramsize Specify the amont of RAM to be used to program + flash (default 256). + +Program Flow Specifiers: + + -e, --masserase Mass Erase (clear all flash memory) + -m, --mainerase Erase main flash memory only + --eraseinfo Erase info flash memory only (0x1000-0x10ff) + --erase=address Selectively erase segment at the specified address + -E, --erasecheck Erase Check by file + -p, --program Program file + -v, --verify Verify by file + +The order of the above options matters! The table is ordered by normal +execution order. For the options "Epv" a file must be specified. +Program flow specifiers default to "p" if a file is given. +Don't forget to specify "e" or "eE" when programming flash! +"p" already verifies the programmed data, "v" adds an additional +verification though uploading the written data for a 1:1 compare. +No default action is taken if "p" and/or "v" is given, say specifying +only "v" does a check by file of a programmed device. + +Data retreiving: + -u, --upload=addr Upload a datablock (see also: -s). + -s, --size=num Size of the data block do upload. (Default is 2) + -x, --hex Show a hexadecimal display of the uploaded data. + (Default) + -b, --bin Get binary uploaded data. This can be used + to redirect the output into a file. + -i, --ihex Uploaded data is output in Intel HEX format. + This can be used to clone a device. + +Do before exit: + -g, --go=address Start programm execution at specified address. + This implies option "w" (wait) + -r, --reset Reset connected MSP430. Starts application. + This is a normal device reset and will start + the programm that is specified in the reset + interrupt vector. (see also -g) + -w, --wait Wait for before closing parallel port. +""" % (sys.argv[0], VERSION)) + +def main(): + global DEBUG + import getopt + filetype = None + filename = None + reset = 0 + wait = 0 + goaddr = None + jtag = JTAG() + toinit = [] + todo = [] + startaddr = None + size = 2 + outputformat= HEX + lpt = None + funclet = None + ramsize = None + + sys.stderr.write("MSP430 parallel JTAG programmer Version: %s\n" % VERSION) + try: + opts, args = getopt.getopt(sys.argv[1:], + "hl:weEmpvrg:Du:d:s:xbiITfR:S", + ["help", "lpt=", "wait" + "masserase", "erasecheck", "mainerase", "program", + "erase=", "eraseinfo", + "verify", "reset", "go=", "debug", + "upload=", "download=", "size=", "hex", "bin", "ihex", + "intelhex", "titext", "funclet", "ramsize=", "progress"] + ) + except getopt.GetoptError: + # print help information and exit: + usage() + sys.exit(2) + + for o, a in opts: + if o in ("-h", "--help"): + usage() + sys.exit() + elif o in ("-l", "--lpt"): + lpt = a + elif o in ("-w", "--wait"): + wait = 1 + elif o in ("-e", "--masserase"): + toinit.append(jtag.actionMassErase) #Erase Flash + elif o in ("-E", "--erasecheck"): + toinit.append(jtag.actionEraseCheck) #Erase Check (by file) + elif o in ("-m", "--mainerase"): + toinit.append(jtag.actionMainErase) #Erase main Flash + elif o == "--erase": + try: + seg = int(a, 0) + toinit.append(jtag.makeActionSegmentErase(seg)) + except ValueError: + sys.stderr.write("segment address must be a valid number in dec, hex or octal\n") + sys.exit(2) + elif o == "--eraseinfo": + toinit.append(jtag.makeActionSegmentErase(0x1000)) + toinit.append(jtag.makeActionSegmentErase(0x1080)) + elif o in ("-p", "--program"): + todo.append(jtag.actionProgram) #Program file + elif o in ("-v", "--verify"): + todo.append(jtag.actionVerify) #Verify file + elif o in ("-r", "--reset"): + reset = 1 + elif o in ("-g", "--go"): + try: + goaddr = int(a, 0) #try to convert decimal + except ValueError: + sys.stderr.write("upload address must be a valid number in dec, hex or octal\n") + sys.exit(2) + elif o in ("-D", "--debug"): + DEBUG = DEBUG + 1 + elif o in ("-u", "--upload"): + try: + startaddr = int(a, 0) #try to convert number of any base + except ValueError: + sys.stderr.write("upload address must be a valid number in dec, hex or octal\n") + sys.exit(2) + elif o in ("-s", "--size"): + try: + size = int(a, 0) + except ValueError: + sys.stderr.write("upload address must be a valid number in dec, hex or octal\n") + sys.exit(2) + #outut formats + elif o in ("-x", "--hex"): + outputformat = HEX + elif o in ("-b", "--bin"): + outputformat = BINARY + elif o in ("-i", "--ihex"): + outputformat = INTELHEX + #input formats + elif o in ("-I", "--intelhex"): + filetype = 0 + elif o in ("-T", "--titext"): + filetype = 1 + #others + elif o in ("-f", "--funclet"): + funclet = 1 + elif o in ("-R", "--ramsize"): + try: + ramsize = int(a, 0) + except ValueError: + sys.stderr.write("ramsize must be a valid number in dec, hex or octal\n") + sys.exit(2) + elif o in ("-S", "--progress"): + jtag.showprogess = 1 + + if len(args) == 0: + sys.stderr.write("Use -h for help\n") + elif len(args) == 1: #a filename is given + if not funclet: + if not todo: #if there are no actions yet + todo.extend([ #add some useful actions... + jtag.actionProgram, + ]) + filename = args[0] + else: #number of args is wrong + usage() + sys.exit(2) + + if DEBUG: #debug infos + sys.stderr.write("debug level set to %d\n" % DEBUG) + _parjtag.configure(DEBUG_OPTION, DEBUG) + sys.stderr.write("python version: %s\n" % sys.version) + + + #sanity check of options + if goaddr and reset: + sys.stderr.write("Warning: option --reset ignored as --go is specified!\n") + reset = 0 + + if startaddr and reset: + sys.stderr.write("Warning: option --reset ignored as --upload is specified!\n") + reset = 0 + + #prepare data to download + jtag.data = Memory() #prepare downloaded data + if filetype is not None: #if the filetype is given... + if filename is None: + raise ValueError("no filename but filetype specified") + if filename == '-': #get data from stdin + file = sys.stdin + else: + file = open(filename,"rb") #or from a file + if filetype == 0: #select load function + jtag.data.loadIHex(file) #intel hex + elif filetype == 1: + jtag.data.loadTIText(file) #TI's format + else: + raise ValueError("illegal filetype specified") + else: #no filetype given... + if filename == '-': #for stdin: + jtag.data.loadIHex(sys.stdin) #assume intel hex + elif filename: + jtag.data.loadFile(filename) #autodetect otherwise + + if DEBUG > 5: sys.stderr.write("File: %r\n" % filename) + + try: + jtag.connect(lpt) #try to open port + except IOError: + raise #do not handle here + else: #continue if open was successful + if ramsize is not None: + _parjtag.configure(RAMSIZE_OPTION, ramsize) + #initialization list + if toinit: #erase and erase check + if DEBUG: sys.stderr.write("Preparing device ...\n") + for f in toinit: f() + + #work list + if todo: + if DEBUG > 0: #debug + #show a nice list of sheduled actions + sys.stderr.write("TODO list:\n") + for f in todo: + try: + sys.stderr.write(" %s\n" % f.func_name) + except AttributeError: + sys.stderr.write(" %r\n" % f) + for f in todo: f() #work through todo list + + if reset: #reset device first if desired + jtag.actionReset() + + if funclet is not None: #download and start funclet + jtag.funclet() + + if goaddr is not None: #start user programm at specified address + jtag.actionRun(goaddr) #load PC and execute + + #upload datablock and output + if startaddr is not None: + if goaddr: #if a program was started... + raise NotImplementedError + #TODO: + #sys.stderr.write("Waiting to device for reconnect for upload: ") + data = jtag.uploadData(startaddr, size) #upload data + if outputformat == HEX: #depending on output format + hexdump( (startaddr, data) ) #print a hex display + elif outputformat == INTELHEX: + makeihex( (startaddr, data) ) #ouput a intel-hex file + else: + sys.stdout.write(data) #binary output w/o newline! + wait = 0 #wait makes no sense as after the upload the device is still stopped + + if wait: #wait at the end if desired + sys.stderr.write("Press ...\n") #display a prompt + raw_input() #wait for newline + + _parjtag.reset(1, 1) #reset and release target + #~ jtag.actionReset() + jtag.close() #Release communication port + +if __name__ == '__main__': + try: + main() + except SystemExit: + raise #let pass exit() calls + except KeyboardInterrupt: + if DEBUG: raise #show full trace in debug mode + sys.stderr.write("user abort.\n") #short messy in user mode + sys.exit(1) #set errorlevel for script usage + except Exception, msg: #every Exception is caught and displayed + if DEBUG: raise #show full trace in debug mode + sys.stderr.write("\nAn error occoured:\n%s\n" % msg) #short messy in user mode + sys.exit(1) #set errorlevel for script usage diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/license.txt b/cpu/msp430/buildscripts/jtag/pyjtag/license.txt new file mode 100644 index 000000000..810a2d24c --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/license.txt @@ -0,0 +1,62 @@ +Copyright (c) 2001-2002 Chris Liechti + +All Rights Reserved. + +This is the Python license. In short, you can use this product in +commercial and non-commercial applications, modify it, redistribute it. +A notification to the author when you use and/or modify it is welcome. + +TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING THIS SOFTWARE +============================================ + +LICENSE AGREEMENT +----------------- + +1. This LICENSE AGREEMENT is between the copyright holder of this +product, and the Individual or Organization ("Licensee") accessing +and otherwise using this product in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, +the copyright holder hereby grants Licensee a nonexclusive, +royalty-free, world-wide license to reproduce, analyze, test, +perform and/or display publicly, prepare derivative works, distribute, +and otherwise use this product alone or in any derivative version, +provided, however, that copyright holders License Agreement and +copyright holders notice of copyright are retained in this product +alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates this product or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to this product. + +4. The copyright holder is making this product available to Licensee +on an "AS IS" basis. THE COPYRIGHT HOLDER MAKES NO REPRESENTATIONS +OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT +LIMITATION, THE COPYRIGHT HOLDER MAKES NO AND DISCLAIMS ANY +REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR +ANY PARTICULAR PURPOSE OR THAT THE USE OF THIS PRODUCT WILL +NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. THE COPYRIGHT HOLDER SHALL NOT BE LIABLE TO LICENSEE OR ANY +OTHER USERS OF THIS PRODUCT FOR ANY INCIDENTAL, SPECIAL, OR +CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, +DISTRIBUTING, OR OTHERWISE USING THIS PRODUCT, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY +THEREOF. + +6. This License Agreement will automatically terminate upon a +material breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between the +copyright holder and Licensee. This License Agreement does not grant +permission to use trademarks or trade names from the copyright holder +in a trademark sense to endorse or promote products or services of +Licensee, or any third party. + +8. By copying, installing or otherwise using this product, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/makefile b/cpu/msp430/buildscripts/jtag/pyjtag/makefile new file mode 100644 index 000000000..5482fa2f1 --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/makefile @@ -0,0 +1,33 @@ + +.PHONY: all FORCE clean windist + +all: windist + +#wrap py to exe and build windows installer +windist: + python setup.py py2exe + rm -r bin + mv dist/jtag/jtag.exe dist/msp430-jtag.exe + mv dist/jtag/* dist/ + rmdir dist/jtag + mv dist bin + rm -r build + + +#generate test files +fill60k.a43: + python gen-ihex.py 60 >$@ +fill48k.a43: + python gen-ihex.py 48 >$@ +fill32k.a43: + python gen-ihex.py 32 >$@ +fill16k.a43: + python gen-ihex.py 16 >$@ +fill8k.a43: + python gen-ihex.py 8 >$@ +fill4k.a43: + python gen-ihex.py 4 >$@ + +#clean up the mess... +clean: + rm -r dist build bin \ No newline at end of file diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/readme.txt b/cpu/msp430/buildscripts/jtag/pyjtag/readme.txt new file mode 100644 index 000000000..bdd3da6c2 --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/readme.txt @@ -0,0 +1,182 @@ +pyJTAG +------ + +Software to talk to the parallel port JTAG PCB as seen with the FET kits. +It is released under a free software license, +see license.txt for more details. + +(C) 2002-2003 Chris Liechti + +Features +-------- + +- understands TI-Text and Intel-hex +- download to Flash and/or RAM, erase, verify +- reset device +- load addres into R0/PC and run +- upload a memory block MSP->PC (output as binary data or hex dump) +- written in Python, runs on Win32, Linux, BSD +- use per command line, or in a Python script + +Requirements +------------ +- Linux, BSD, Un*x or Windows PC +- Python 2.0 or newer, 2.2 recomeded +- Parallel JTAG hardware with an MSP430 device connected + +Installation +------------ +Python installations are available from www.python.org. On Windows simply +use the installer. The win32all package has an installer too. These +installations should run fine with the deafults. + +On Linux just Python is needed. On some distributions is Python 1.5.2 +installed per default. You may meed to change the first line in the script +from "python" to "python2". Maybe Python 2.x is in a separate package that +has to be installed. There are rpm and deb binary packages and a source +tarball available through the Python homepage. + +The pyjtag archive can simply be unpacked to a directory, Windows users +can use WinZip or WinRar among others to extract the gzipped tar file. +If you want to run it from everywhere the directory where the file jtag.py +is, should be added to the PATH. +Look at "~/.profile", "/etc/profile" on Linux, "autoexec.bat" on Win9x/ME, +System Properties/Environment in Win2000/NT/XP. + +_parjtag.so/dll from the jtag archive must be copied to the same directory as +jtag.py. On Windows also MSP430mspgcc.dll and HIL.dll must be located in the +same dir or somewhere in the PATH. + +Short introduction +------------------ +This software uses the JTAG hardware that comes with the FET kits. It is +connected to the parallel port. + +The program can be started by typing "python jtag.py" in a console. Often +it works also with just "jtag.py" or "./jtag.py". + +USAGE: jtag.py [options] [file] +If "-" is specified as file the data is read from the stdinput. +A file ending with ".txt" is considered to be in TIText format all +other filenames are considered IntelHex. + +General options: + -h, --help Show this help screen. + -l, --lpt=name Specify an other parallel port. + (defaults to LPT1 (/dev/parport0 on unix) + -D, --debug Increase level of debug messages. This won't be + very useful for the average user... + -I, --intelhex Force fileformat to IntelHex + -T, --titext Force fileformat to be TIText + -f, --funclet The given file is a funclet (a small program to + be run in RAM) + -R, --ramsize Specify the amont of RAM to be used to program + flash (default 256). + +Program Flow Specifiers: + + -e, --masserase Mass Erase (clear all flash memory) + -m, --mainerase Erase main flash memory only + --eraseinfo Erase info flash memory only (0x1000-0x10ff) + --erase=address Selectively erase segment at the specified address + -E, --erasecheck Erase Check by file + -p, --program Program file + -v, --verify Verify by file + +The order of the above options matters! The table is ordered by normal +execution order. For the options "Epv" a file must be specified. +Program flow specifiers default to "p" if a file is given. +Don't forget to specify "e" or "eE" when programming flash! +"p" already verifies the programmed data, "v" adds an additional +verification though uploading the written data for a 1:1 compare. +No default action is taken if "p" and/or "v" is given, say specifying +only "v" does a check by file of a programmed device. + +Data retreiving: + -u, --upload=addr Upload a datablock (see also: -s). + -s, --size=num Size of the data block do upload. (Default is 2) + -x, --hex Show a hexadecimal display of the uploaded data. + (Default) + -b, --bin Get binary uploaded data. This can be used + to redirect the output into a file. + -i, --ihex Uploaded data is output in Intel HEX format. + This can be used to clone a device. + +Do before exit: + -g, --go=address Start programm execution at specified address. + This implies option "w" (wait) + -r, --reset Reset connected MSP430. Starts application. + This is a normal device reset and will start + the programm that is specified in the reset + interrupt vector. (see also -g) + -w, --wait Wait for before closing parallel port. + + +Examples +-------- +These examples assume that you have added the installation directory to +the PATH. Type the full path to jtag.py otherwise and maybe use +"python jtag.py". Depending on installation it may also appear under the +name "msp430-jtag". + +jtag.py -e + Only erase flash. + +jtag.py -eErw 6port.a43 + Erase flash, erase check, download an executable, run it (reset) + and wait. + +jtag.py -mS -R 2048 6port.a43 + Use ramsize option on a device with 2k RAM to speed up + download. Of course any value from 128B up to the maximum + a device has is allowed. + The progress and mainerase options are also activated. + Only erasing the main memory is useful to keep calibration + data in the information memory. + +jtag.py 6port.a43 + Download of an executable to en empty (new or erased) device. + (Note that in new devices some of the first bytes in the + information memory are random data. If data should be + downloaded there, specify -eE.) + +jtag.py --go=0x220 ramtest.a43 + Download a program into RAM and run it, may not work + with all devices. + +jtag.py -f blinking.a43 + Download a program into RAM and run it. It must be + a special format with "startadr", "entrypoint", + "exitpoint" as the first three words in the data + and it must end on "jmp $". See MSP430debug sources + for more info. + +jtag.py -u 0x0c00 -s 1024 + Get a memory dump in HEX, from the bootstrap loader. + or save the binary in a file: + "python jtag.py -u 0x0c00 -s 1024 -b >dump.bin" + or as an intel-hex file: + "python jtag.py -u 0x0c00 -s 1024 -i >dump.a43" + +jtag.py -r + Just start the user program (with a reset). + +cat 6port.a43|jtag.py -e - + Pipe the data from "cat" to jtag.py to erase and program the + flash. (un*x example, don't forget the dash at the end of the + line) + +History +------- +1.0 public release +1.1 fix of verify error +1.2 use the verification during programming +1.3 meinerase, progress options, ihex output + +References +---------- +- Python: http://www.python.org + +- Texas Instruments MSP430 Homepage, links to Datasheets and Application + Notes: http://www.ti.com/sc/msp430 + diff --git a/cpu/msp430/buildscripts/jtag/pyjtag/setup.py b/cpu/msp430/buildscripts/jtag/pyjtag/setup.py new file mode 100644 index 000000000..982b58340 --- /dev/null +++ b/cpu/msp430/buildscripts/jtag/pyjtag/setup.py @@ -0,0 +1,9 @@ +# setup.py +from distutils.core import setup +import glob +import py2exe + +setup( + name="msp430-jtag", + scripts=["jtag.py"], + ) \ No newline at end of file