""" # TOP2049 Open Source programming suite # # ZIF socket layout generator # # Copyright (c) 2010 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ from util import * from top_devices import * class LayoutGenerator: "Layout generator baseclass." class MapError(Exception): pass def __init__(self): pass def setProgrammerType(self, programmer="TOP2049"): supportedDevices = { # Map deviceName : layoutModules, ZIF-pin-count "TOP2049" : (top2049.vcc_layouts, top2049.vpp_layouts, top2049.gnd_layouts, 48) } try: (vcc_layouts, vpp_layouts, gnd_layouts, zifPins) = \ supportedDevices[programmer.upper()] except (KeyError), e: raise TOPException("Programmer " + programmer + " not supported") self.vccLayout = vcc_layouts.VCCLayout() self.vppLayout = vpp_layouts.VPPLayout() self.gndLayout = gnd_layouts.GNDLayout() self.zifPins = zifPins def setPins(self, vccPin, vppPins, gndPin): """Load the supply pin locations. vppPins may either be one pin number or a list of pin numbers or None.""" self.vccPin = vccPin if vppPins is None: self.vppPins = [ ] else: try: self.vppPins = list(vppPins) except TypeError: self.vppPins = [ vppPins, ] self.gndPin = gndPin self.verifyPins() def getZifPinForPackagePin(self, packagePin): "Get the ZIF pin number corresponding to the package pin number" return self.mapPin2zif(packagePin, self.result_offset, self.result_upsideDown) def verifyPins(self): pass def maxOffset(self, upsideDown): "Returns the max possible chip offset (in the ZIF socket)" raise TOPException("Reimplement me") def mapToZIF(self, offset, upsideDown): "Tries to map the chip into the ZIF socket" if offset < 0 or offset > self.maxOffset(upsideDown): raise self.MapError() # Find a GND layout zifGndPin = self.mapPin2zif(self.gndPin, offset, upsideDown) self.result_GND = self.__findSingleLayout( self.gndLayout, (1 << (zifGndPin - 1))) # Find a VCC layout zifVccPin = self.mapPin2zif(self.vccPin, offset, upsideDown) self.result_VCC = self.__findSingleLayout( self.vccLayout, (1 << (zifVccPin - 1))) # Find a (possibly cumulative) VPP layout if not self.vppPins: self.result_VPP = None else: zifVppMask = 0 for vppPin in self.vppPins: pin = self.mapPin2zif(vppPin, offset, upsideDown) zifVppMask |= (1 << (pin - 1)) self.result_VPP = self.__findCumulativeLayout( self.vppLayout, zifVppMask) # Also store the chip orientation for later use. self.result_upsideDown = upsideDown self.result_offset = offset def mapPin2zif(self, packagePin, offset, upsideDown): "Map a package pin to a ZIF pin. Returns the ZIF pin number." raise TOPException("Reimplement me") def zifLayoutAsciiArt(self): "Returns nice ascii ART of the mapped ZIF socket" raise TOPException("Reimplement me") def zifPinAssignments(self): "Returns a string describing the pin assignments" vcc = str(self.__bitmask2pinList(self.result_VCC[1])).strip("[]") ret = "VCC ZIF pins: " + vcc + "\n" if self.result_VPP: vppBitmask = 0 for (id, mask) in self.result_VPP: vppBitmask |= mask vpp = str(self.__bitmask2pinList(vppBitmask)).strip("[]") ret += "VPP ZIF pins: " + vpp + "\n" gnd = str(self.__bitmask2pinList(self.result_GND[1])).strip("[]") ret += "GND ZIF pins: " + gnd + "\n" return ret def __bitmask2pinList(self, bitmask): ret = [] bit = 0 while bitmask: if bitmask & (1 << bit): ret.append(bit + 1) bitmask &= ~(1 << bit) bit += 1 return ret def __pinList2Bitmask(self, pinList): bitmask = 0 for pin in pinList: assert(pin >= 1) bitmask |= (1 << (pin - 1)) return bitmask def recalculate(self): "Redo the mapping calculation" for upsideDown in (False, True): offset = self.maxOffset(upsideDown) while offset >= 0: try: self.mapToZIF(offset, upsideDown) except (LayoutGenerator.MapError), e: offset -= 1 continue return raise TOPException("Did not find a possible valid layout for the setup") def getGNDLayout(self): "Get the calculated GND layout ID and mask. Returns a tuple (ID, mask)." return self.result_GND def applyGNDLayout(self, top): "Send the GND layout to hardware" (layoutID, layoutMask) = self.getGNDLayout() top.gnd.setLayoutID(layoutID) def getVCCLayout(self): "Get the calculated VCC layout ID and mask. Returns a tuple (ID, mask)." return self.result_VCC def applyVCCLayout(self, top): "Send the VCC layout to hardware" (layoutID, layoutMask) = self.getVCCLayout() top.vcc.setLayoutID(layoutID) def getVPPLayouts(self): """Get the calculated VPP layout IDs and masks. Returns a list of tuples ((ID, mask), (ID, mask), ...)""" return self.result_VPP def applyVPPLayout(self, top, packagePins=[]): """Send the VPP layout to hardware. packagePins is a list of pins (on the chip package) to activate. If packagePins is not passed, all VPP pins are driven to VPP.""" if packagePins: pins = [] for pin in packagePins: pins.append(self.mapPin2zif(pin, self.result_offset, self.result_upsideDown)) packagePinsMask = self.__pinList2Bitmask(pins) top.vpp.setLayoutMask(0) # Reset layouts = self.getVPPLayouts() if layouts: for (layoutID, mask) in layouts: if packagePins: if mask & packagePinsMask == 0: continue if mask & packagePinsMask != mask: raise TOPException( "Unable to apply partial VPP layout") top.vpp.setLayoutID(layoutID) def __findSingleLayout(self, layoutDefs, zifBitmask): # Returns an (id, mask) tuple for (id, mask) in layoutDefs.supportedLayouts(): if zifBitmask == mask: break else: raise self.MapError() return (id, mask) def __findCumulativeLayout(self, layoutDefs, zifBitmask): # Returns a list of (id, mask) tuples result = [] for (id, mask) in layoutDefs.supportedLayouts(): if zifBitmask == 0: break if mask == 0: continue if mask & zifBitmask == mask: result.append( (id, mask) ) zifBitmask &= ~mask if zifBitmask: raise self.MapError() return result class LayoutGeneratorDIP(LayoutGenerator): "Layout generator for DIP packages." def __init__(self, nrPins): LayoutGenerator.__init__(self) self.nrPins = nrPins def verifyPins(self): LayoutGenerator.verifyPins(self) if self.nrPins < 2 or self.nrPins > self.zifPins or self.nrPins % 2 != 0: raise TOPException("Invalid DIP package") if self.vccPin < 1 or self.vccPin > self.nrPins: raise TOPException("Invalid VCC pin number for the selected package") for vppPin in self.vppPins: if vppPin < 1 or vppPin > self.nrPins: raise TOPException("Invalid VPP pin number for the selected package") if self.gndPin < 1 or self.gndPin > self.nrPins: raise TOPException("Invalid GND pin number for the selected package") def maxOffset(self, upsideDown): return self.zifPins // 2 - self.nrPins // 2 def mapPin2zif(self, dipPin, offset, upsideDown): assert(dipPin >= 1 and dipPin <= self.nrPins) if upsideDown: if dipPin > self.nrPins // 2: # Right side of DIP dipPin -= self.nrPins // 2 return dipPin + offset else: # Left side of DIP return self.zifPins - self.nrPins // 2 + dipPin - offset else: if dipPin > self.nrPins // 2: # Right side of DIP dipPin -= self.nrPins // 2 return self.zifPins - self.nrPins // 2 + dipPin - offset else: # Left side of DIP return dipPin + offset def zifLayoutAsciiArt(self): def line(prefix, content, postfix): return "%3s %s %3s\n" % (prefix, content, postfix) zifGnd = self.getZifPinForPackagePin(self.gndPin) zifVcc = self.getZifPinForPackagePin(self.vccPin) zifVpp = [ self.getZifPinForPackagePin(p) \ for p in self.vppPins ] ret = line("", "T ZIF socket", "") ret += line("", "^--o==============o", "") for zp in range(1, self.zifPins // 2 + 1): prefix, postfix = "", "" if zp == zifGnd: prefix = "GND" if self.zifPins - zp + 1 == zifGnd: postfix = "GND" if zp == zifVcc: prefix = "VCC" if self.zifPins - zp + 1 == zifVcc: postfix = "VCC" if zp in zifVpp: prefix = "VPP" if self.zifPins - zp + 1 in zifVpp: postfix = "VPP" if zp < self.result_offset + 1 or \ zp > self.result_offset + self.nrPins // 2: ret += line(prefix, "%2d |----- || -----| %2d" %\ (zp, self.zifPins + 1 - zp), postfix) else: if zp == self.result_offset + 1 and \ not self.result_upsideDown: ret += line(prefix, "%2d |-- 1##..##o --| %2d" %\ (zp, self.zifPins + 1 - zp), postfix) elif zp == self.result_offset + self.nrPins // 2 and \ self.result_upsideDown: ret += line(prefix, "%2d |-- o##''##1 --| %2d" %\ (zp, self.zifPins + 1 - zp), postfix) else: ret += line(prefix, "%2d |-- o######o --| %2d" %\ (zp, self.zifPins + 1 - zp), postfix) ret += line("", " o==============o", "") return ret def createLayoutGenerator(package): try: for regex in ("DIP(\d+)", "PDIP(\d+)", "SO(\d+)", "TSSOP(\d+)", ): m = re.match(regex, package, re.IGNORECASE) if m: nrPins = int(m.group(1)) return LayoutGeneratorDIP(nrPins) if package.upper() == "PLCC32": # 1:1 adapter return LayoutGeneratorDIP(32) if package.upper() == "PLCC44": # 1:1 adapter return LayoutGeneratorDIP(44) raise ValueError() except (ValueError), e: raise TOPException("Unknown package type " + package)