From ac2af484d0a61565864116afc3a9be47f16f5912 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 14 Apr 2012 17:39:41 +0200 Subject: Add "ChipOption" mechanism Signed-off-by: Michael Buesch --- libtoprammer/chip.py | 155 +++++++++++++++++++++++++++++++++++++-------------- libtoprammer/main.py | 13 ++++- toprammer | 32 +++++++++-- 3 files changed, 150 insertions(+), 50 deletions(-) diff --git a/libtoprammer/chip.py b/libtoprammer/chip.py index 0014c05..17b85da 100644 --- a/libtoprammer/chip.py +++ b/libtoprammer/chip.py @@ -72,10 +72,18 @@ class Chip: return flags @classmethod - def createInstance(cls, chipDescription, programmerType): + def createInstance(cls, top, chipDescription, assignedChipOptions=()): instance = cls() + instance.top = top instance.chipDescription = chipDescription - instance.programmerType = programmerType + for acopt in assignedChipOptions: + copt = chipDescription.getChipOption(acopt.name) + if not copt: + raise TOPException("'%s' is not a valid chip option " + "for chip ID '%s'" %\ + (acopt.name, chipDescription.chipID)) + acopt.detectAndVerifyType(copt.optType) + instance.assignedChipOptions = assignedChipOptions instance.generateVoltageLayouts() return instance @@ -91,9 +99,6 @@ class Chip: self.__chipPinsVPP = chipPinsVPP self.__chipPinGND = chipPinGND - def setTOP(self, top): - self.top = top - def printWarning(self, message): self.top.printWarning(self.chipDescription.chipID + ": " + message) @@ -109,7 +114,7 @@ class Chip: def generateVoltageLayouts(self): if self.__chipPackage: self.generator = createLayoutGenerator(self.__chipPackage) - self.generator.setProgrammerType(self.programmerType) + self.generator.setProgrammerType(self.top.getProgrammerType()) self.generator.setPins(vccPin=self.__chipPinVCC, vppPins=self.__chipPinsVPP, gndPin=self.__chipPinGND) @@ -167,6 +172,15 @@ class Chip: self.top.progressMeter(AbstractUserInterface.PROGRESSMETER_CHIPACCESS, step) + def getChipOptionValue(self, name, default=None): + """Get an AssignedChipOption value that was set by the user. + If no such option is found, it returns 'default'.""" + name = name.lower() + for acopt in self.assignedChipOptions: + if acopt.name.lower() == name: + return acopt.value + return default + def shutdownChip(self): # Override me in the subclass, if required. self.printDebug("Default chip shutdown") @@ -243,6 +257,46 @@ class BitDescription: self.bitNr = bitNr self.description = description +class ChipOption(object): + TYPE_UNKNOWN = "unknown" + TYPE_BOOL = "boolean" + + def __init__(self, optType, name, description=""): + self.optType = optType + self.name = name + self.description = description + + def __repr__(self): + return self.name + +class ChipOptionBool(ChipOption): + def __init__(self, name, description=""): + ChipOption.__init__(self, ChipOption.TYPE_BOOL, + name, description) + + def __repr__(self): + desc = " / " + self.description if self.description else "" + return "%s (boolean%s)" % (self.name, desc) + +class AssignedChipOption(ChipOption): + def __init__(self, name, value): + ChipOption.__init__(self, ChipOption.TYPE_UNKNOWN, name) + self.value = value + + def detectAndVerifyType(self, expectType): + assert(expectType != self.TYPE_UNKNOWN) + if self.optType != self.TYPE_UNKNOWN: + return + value = None + if expectType == self.TYPE_BOOL: + value = str2bool(self.value) + if value is None: + raise TOPException("Chip option '%s' type mismatch. " + "Must be '%s'." %\ + (self.name, expectType)) + self.optType = expectType + self.value = value + class ChipDescription: # Possible chip types TYPE_MCU = 0 # Microcontroller @@ -259,6 +313,7 @@ class ChipDescription: chipVendors="Other", description="", fuseDesc=(), lockbitDesc=(), packages=None, comment="", + chipOptions=(), maintainer="Michael Buesch ", broken=False): """Chip implementation class description. @@ -276,6 +331,7 @@ class ChipDescription: packages => List of supported packages. Each entry is a tuple of two strings: ("PACKAGE", "description") comment => Additional comment string. + chipOptions => Tuple of ChipOption instances, if any. maintainer => Maintainer name. broken => Boolean flag to mark the implementation as broken. """ @@ -295,48 +351,43 @@ class ChipDescription: self.lockbitDesc = lockbitDesc self.packages = packages self.comment = comment + self.chipOptions = chipOptions self.maintainer = maintainer self.broken = broken getRegisteredChips().append(self) - @staticmethod - def find(programmerType, chipID, allowBroken=False): - """Find chip implementations by ID and return a list of descriptors - and instances of it.""" - found = [] - for chipDesc in getRegisteredChips(): - if chipDesc.broken and not allowBroken: - continue - if chipDesc.chipID.lower().find(chipID.lower()) >= 0: - instance = chipDesc.chipImplClass.createInstance( - chipDescription = chipDesc, - programmerType = programmerType) - found.append( (chipDesc, instance) ) + @classmethod + def findAll(cls, chipID, allowBroken=False): + "Find all ChipDescriptions by fuzzy chipID match." + found = [ chipDesc for chipDesc in getRegisteredChips() if ( + (not chipDesc.broken or allowBroken) and\ + (chipDesc.chipID.lower().find(chipID.lower()) >= 0) + ) ] return found - @staticmethod - def findOne(programmerType, chipID, allowBroken=False): - """Find a chip implementation and return the descriptor - and an instance of it. If chipID is not unique, this raises - an exception""" - found = ChipDescription.find(programmerType, chipID, allowBroken) + @classmethod + def findOne(cls, chipID, allowBroken=False): + """Find a chip implementation and return the ChipDescriptor. + Raise an exception, if chipID is not unique.""" + found = cls.findAll(chipID, allowBroken) if not found: raise TOPException("Did not find chipID \"%s\"" % chipID) if len(found) != 1: - choices = map(lambda (desc, inst): desc.chipID, found) - raise TOPException("The chipID \"%s\" is not unique. Choices are: %s" %\ + choices = [ desc.chipID for desc in found ] + raise TOPException( + "The chipID \"%s\" is not unique. Choices are: %s" %\ (chipID, ", ".join(choices))) return found[0] - @staticmethod - def dumpAll(fd, verbose=1, showBroken=True): + @classmethod + def dumpAll(cls, fd, verbose=1, showBroken=True): "Dump all supported chips to file fd." count = 0 for chip in getRegisteredChips(): if chip.broken and not showBroken: continue - if chip.chipType == ChipDescription.TYPE_INTERNAL: + if chip.chipType == cls.TYPE_INTERNAL: continue count = count + 1 if count >= 2: @@ -345,29 +396,43 @@ class ChipDescription: def dump(self, fd, verbose=1): "Dump information about a registered chip to file fd." + + def wrline(prefix, content): + # Write a formatted feature line + fd.write("%15s: %s\n" % (prefix, content)) + + banner = "" if self.chipVendors: - fd.write(", ".join(self.chipVendors) + " ") + banner += ", ".join(self.chipVendors) + " " if self.description: - fd.write(self.description) + banner += self.description else: - fd.write(self.bitfile) + banner += self.bitfile extraFlags = [] if not self.maintainer: extraFlags.append("Orphaned") if self.broken: extraFlags.append("Broken implementation") if extraFlags: - fd.write(" (%s)" % "; ".join(extraFlags)) - fd.write("\n") + banner += " (%s)" % "; ".join(extraFlags) + sep = '+' + '-' * (len(banner) + 4) + '+\n' + fd.write(sep + '| ' + banner + ' |\n' + sep) + if verbose >= 1: - fd.write("%25s: %s\n" % ("ChipID", self.chipID)) + wrline("Chip ID", self.chipID) if verbose >= 2: - fd.write("%25s: %s\n" % ("BIT-file", self.bitfile)) + bitfile = self.bitfile + if not bitfile.endswith('.bit'): + bitfile += '.bit' + wrline("BIT file", bitfile) + if verbose >= 1: + for opt in self.chipOptions: + wrline("Chip option", str(opt)) if verbose >= 3 and self.packages: for (package, description) in self.packages: if description: description = " (" + description + ")" - fd.write("%25s: %s%s\n" % ("Supported package", package, description)) + wrline("Chip package", package + description) if verbose >= 4: supportedFeatures = ( (Chip.SUPPORT_ERASE, "Full chip erase"), @@ -387,11 +452,19 @@ class ChipDescription: supportFlags = self.chipImplClass.getSupportFlags() for (flag, description) in supportedFeatures: if flag & supportFlags: - fd.write("%25s: %s\n" % ("Support for", description)) + wrline("Support for", description) if verbose >= 2 and self.comment: - fd.write("%25s: %s\n" % ("Comment", self.comment)) + wrline("Comment", self.comment) if verbose >= 3: maintainer = self.maintainer if not maintainer: maintainer = "NONE" - fd.write("%25s: %s\n" % ("Maintainer", maintainer)) + wrline("Maintainer", maintainer) + + def getChipOption(self, name): + "Get a ChipOption by case insensitive 'name'." + name = name.lower() + for opt in self.chipOptions: + if opt.name.lower() == name: + return opt + return None diff --git a/libtoprammer/main.py b/libtoprammer/main.py index d1a4f76..c2970c7 100644 --- a/libtoprammer/main.py +++ b/libtoprammer/main.py @@ -96,14 +96,21 @@ class TOP: self.initializeProgrammer() - def initializeChip(self, chipID): + def getProgrammerType(self): + "Returns the TYPE_TOPxxxx" + return self.topType + + def initializeChip(self, chipID, assignedChipOptions=()): "Initialize the programmer for a chip" # If a chip is initialized, shut it down first. if self.chip: self.shutdownChip() # Find the implementation of the chip. - (descriptor, self.chip) = ChipDescription.findOne(self.topType, chipID, self.usebroken) - self.chip.setTOP(self) + descriptor = ChipDescription.findOne(chipID, self.usebroken) + self.chip = descriptor.chipImplClass.createInstance( + top = self, + chipDescription = descriptor, + assignedChipOptions = assignedChipOptions) # Find the bitfile for the chip. bitfile = bitfileFind(descriptor.bitfile) if not bitfile: diff --git a/toprammer b/toprammer index b71639d..0c0563d 100755 --- a/toprammer +++ b/toprammer @@ -29,11 +29,15 @@ import getopt def usage(): print "TOP2049 Open Source programming suite v%s" % VERSION print "" - print "Usage: %s [OPTIONS]" % sys.argv[0] + print "Usage: %s [OPTIONS] [ACTIONS]" % sys.argv[0] print "" print " -c|--chip-id The ID of the handled chip. (mandatory)" print " See -t|--list for a list of supported chips." print "" + print "Optional:" + print " -C|--chip-opt NAME=VAL Set a chip-id specific option." + print " Use -c CHIPID -t to get a list of options." + print "" print "Actions:" print " -s|--read-sig FILE Read the signature bytes" print " -x|--erase Erase the chip" @@ -54,7 +58,7 @@ def usage(): print " -r|--read-ram FILE Read the RAM" print " -R|--write-ram FILE Write the RAM" print "" - print "Optional:" + print "Other options:" print " -t|--list Print a list of supported chips and exit." print " Use -V|--verbose to control the list verbosity (1-4)" print " -d|--device BUS.DEV Use the programmer at BUS.DEV" @@ -116,6 +120,7 @@ def main(argv): opt_forceLevel = 0 opt_forceBitfileUpload = False opt_chipID = None + opt_chipOptions = [] opt_device = None opt_action = None opt_file = None @@ -125,19 +130,28 @@ def main(argv): opt_outformat = "bin" try: (opts, args) = getopt.getopt(sys.argv[1:], - "hc:d:V:Qs:xTp:P:e:E:f:F:o:Ul:L:r:R:BtI:O:", + "hc:d:V:Qs:xTp:P:e:E:f:F:o:Ul:L:r:R:BtI:O:C:", [ "help", "chip-id=", "device=", "verbose=", "noqueue", "read-sig=", "erase", "test", "read-prog=", "write-prog=", "read-eeprom=", "write-eeprom=", "read-fuse=", "write-fuse=", "read-lock=", "write-lock=", "read-ram=", "write-ram=", "force=", "force-upload", "broken", "list", - "in-format=", "out-format=", ]) + "in-format=", "out-format=", "chip-opt=", ]) for (o, v) in opts: if o in ("-h", "--help"): usage() return 0 if o in ("-c", "--chip-id"): opt_chipID = v + if o in ("-C", "--chip-opt"): + try: + v = v.split('=') + name, value = v[0], v[1] + except (IndexError, ValueError), e: + print "-C|--chip-opt invalid parameter" + return 1 + copt = AssignedChipOption(name, value) + opt_chipOptions.append(copt) if o in ("-t", "--list"): opt_action = "print-list" if o in ("-d", "--device"): @@ -213,14 +227,20 @@ def main(argv): try: if opt_action == "print-list": - ChipDescription.dumpAll(sys.stdout, verbose=opt_verbose, showBroken=True) + if opt_chipID: + desc = ChipDescription.findOne(opt_chipID, True) + desc.dump(sys.stdout, verbose=opt_verbose) + else: + ChipDescription.dumpAll(sys.stdout, + verbose=opt_verbose, showBroken=True) return 0 top = TOP(busDev = opt_device, verbose = opt_verbose, forceLevel = opt_forceLevel, noqueue = opt_noqueue, usebroken = opt_usebroken, forceBitfileUpload = opt_forceBitfileUpload) - top.initializeChip(opt_chipID) + top.initializeChip(chipID = opt_chipID, + assignedChipOptions = opt_chipOptions) if opt_action == "read-sig": fileOut(opt_file, opt_outformat, top.readSignature()) elif opt_action == "erase": -- cgit v1.2.3