layout_generator.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. """
  2. # TOP2049 Open Source programming suite
  3. #
  4. # ZIF socket layout generator
  5. #
  6. # Copyright (c) 2010 Michael Buesch <m@bues.ch>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License along
  19. # with this program; if not, write to the Free Software Foundation, Inc.,
  20. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. """
  22. from .util import *
  23. from .top_devices import *
  24. class LayoutGenerator:
  25. "Layout generator baseclass."
  26. class MapError(Exception): pass
  27. def __init__(self):
  28. pass
  29. def setProgrammerType(self, programmer="TOP2049"):
  30. supportedDevices = {
  31. # Map deviceName : layoutModules, ZIF-pin-count
  32. "TOP2049" : (top2049_vcc_layouts, top2049_vpp_layouts,
  33. top2049_gnd_layouts, 48)
  34. }
  35. try:
  36. (vcc_layouts, vpp_layouts, gnd_layouts, zifPins) = \
  37. supportedDevices[programmer.upper()]
  38. except (KeyError) as e:
  39. raise TOPException("Programmer " + programmer + " not supported")
  40. self.vccLayout = vcc_layouts.VCCLayout()
  41. self.vppLayout = vpp_layouts.VPPLayout()
  42. self.gndLayout = gnd_layouts.GNDLayout()
  43. self.zifPins = zifPins
  44. def setPins(self, vccPin, vppPins, gndPin):
  45. """Load the supply pin locations.
  46. vppPins may either be one pin number or a list of pin numbers or None."""
  47. self.vccPin = vccPin
  48. if vppPins is None:
  49. self.vppPins = [ ]
  50. else:
  51. try:
  52. self.vppPins = list(vppPins)
  53. except TypeError:
  54. self.vppPins = [ vppPins, ]
  55. self.gndPin = gndPin
  56. self.verifyPins()
  57. def getZifPinForPackagePin(self, packagePin):
  58. "Get the ZIF pin number corresponding to the package pin number"
  59. return self.mapPin2zif(packagePin, self.result_offset,
  60. self.result_upsideDown)
  61. def verifyPins(self):
  62. pass
  63. def maxOffset(self, upsideDown):
  64. "Returns the max possible chip offset (in the ZIF socket)"
  65. raise TOPException("Reimplement me")
  66. def mapToZIF(self, offset, upsideDown):
  67. "Tries to map the chip into the ZIF socket"
  68. if offset < 0 or offset > self.maxOffset(upsideDown):
  69. raise self.MapError()
  70. # Find a GND layout
  71. zifGndPin = self.mapPin2zif(self.gndPin, offset, upsideDown)
  72. self.result_GND = self.__findSingleLayout(
  73. self.gndLayout,
  74. (1 << (zifGndPin - 1)))
  75. # Find a VCC layout
  76. zifVccPin = self.mapPin2zif(self.vccPin, offset, upsideDown)
  77. self.result_VCC = self.__findSingleLayout(
  78. self.vccLayout,
  79. (1 << (zifVccPin - 1)))
  80. # Find a (possibly cumulative) VPP layout
  81. if not self.vppPins:
  82. self.result_VPP = None
  83. else:
  84. zifVppMask = 0
  85. for vppPin in self.vppPins:
  86. pin = self.mapPin2zif(vppPin, offset, upsideDown)
  87. zifVppMask |= (1 << (pin - 1))
  88. self.result_VPP = self.__findCumulativeLayout(
  89. self.vppLayout,
  90. zifVppMask)
  91. # Also store the chip orientation for later use.
  92. self.result_upsideDown = upsideDown
  93. self.result_offset = offset
  94. def mapPin2zif(self, packagePin, offset, upsideDown):
  95. "Map a package pin to a ZIF pin. Returns the ZIF pin number."
  96. raise TOPException("Reimplement me")
  97. def zifLayoutAsciiArt(self):
  98. "Returns nice ascii ART of the mapped ZIF socket"
  99. raise TOPException("Reimplement me")
  100. def zifPinAssignments(self):
  101. "Returns a string describing the pin assignments"
  102. vcc = str(self.__bitmask2pinList(self.result_VCC[1])).strip("[]")
  103. ret = "VCC ZIF pins: " + vcc + "\n"
  104. if self.result_VPP:
  105. vppBitmask = 0
  106. for (id, mask) in self.result_VPP:
  107. vppBitmask |= mask
  108. vpp = str(self.__bitmask2pinList(vppBitmask)).strip("[]")
  109. ret += "VPP ZIF pins: " + vpp + "\n"
  110. gnd = str(self.__bitmask2pinList(self.result_GND[1])).strip("[]")
  111. ret += "GND ZIF pins: " + gnd + "\n"
  112. return ret
  113. def __bitmask2pinList(self, bitmask):
  114. ret = []
  115. bit = 0
  116. while bitmask:
  117. if bitmask & (1 << bit):
  118. ret.append(bit + 1)
  119. bitmask &= ~(1 << bit)
  120. bit += 1
  121. return ret
  122. def __pinList2Bitmask(self, pinList):
  123. bitmask = 0
  124. for pin in pinList:
  125. assert(pin >= 1)
  126. bitmask |= (1 << (pin - 1))
  127. return bitmask
  128. def recalculate(self):
  129. "Redo the mapping calculation"
  130. for upsideDown in (False, True):
  131. offset = self.maxOffset(upsideDown)
  132. while offset >= 0:
  133. try:
  134. self.mapToZIF(offset, upsideDown)
  135. except (LayoutGenerator.MapError) as e:
  136. offset -= 1
  137. continue
  138. return
  139. raise TOPException("Did not find a possible valid layout for the setup")
  140. def getGNDLayout(self):
  141. "Get the calculated GND layout ID and mask. Returns a tuple (ID, mask)."
  142. return self.result_GND
  143. def applyGNDLayout(self, top):
  144. "Send the GND layout to hardware"
  145. (layoutID, layoutMask) = self.getGNDLayout()
  146. top.gnd.setLayoutID(layoutID)
  147. def getVCCLayout(self):
  148. "Get the calculated VCC layout ID and mask. Returns a tuple (ID, mask)."
  149. return self.result_VCC
  150. def applyVCCLayout(self, top):
  151. "Send the VCC layout to hardware"
  152. (layoutID, layoutMask) = self.getVCCLayout()
  153. top.vcc.setLayoutID(layoutID)
  154. def getVPPLayouts(self):
  155. """Get the calculated VPP layout IDs and masks.
  156. Returns a list of tuples ((ID, mask), (ID, mask), ...)"""
  157. return self.result_VPP
  158. def applyVPPLayout(self, top, packagePins=[]):
  159. """Send the VPP layout to hardware.
  160. packagePins is a list of pins (on the chip package) to activate.
  161. If packagePins is not passed, all VPP pins are driven to VPP."""
  162. if packagePins:
  163. pins = []
  164. for pin in packagePins:
  165. pins.append(self.mapPin2zif(pin, self.result_offset,
  166. self.result_upsideDown))
  167. packagePinsMask = self.__pinList2Bitmask(pins)
  168. top.vpp.setLayoutMask(0) # Reset
  169. layouts = self.getVPPLayouts()
  170. if layouts:
  171. for (layoutID, mask) in layouts:
  172. if packagePins:
  173. if mask & packagePinsMask == 0:
  174. continue
  175. if mask & packagePinsMask != mask:
  176. raise TOPException(
  177. "Unable to apply partial VPP layout")
  178. top.vpp.setLayoutID(layoutID)
  179. def __findSingleLayout(self, layoutDefs, zifBitmask):
  180. # Returns an (id, mask) tuple
  181. for (id, mask) in layoutDefs.supportedLayouts():
  182. if zifBitmask == mask:
  183. break
  184. else:
  185. raise self.MapError()
  186. return (id, mask)
  187. def __findCumulativeLayout(self, layoutDefs, zifBitmask):
  188. # Returns a list of (id, mask) tuples
  189. result = []
  190. for (id, mask) in layoutDefs.supportedLayouts():
  191. if zifBitmask == 0:
  192. break
  193. if mask == 0:
  194. continue
  195. if mask & zifBitmask == mask:
  196. result.append( (id, mask) )
  197. zifBitmask &= ~mask
  198. if zifBitmask:
  199. raise self.MapError()
  200. return result
  201. class LayoutGeneratorDIP(LayoutGenerator):
  202. "Layout generator for DIP packages."
  203. def __init__(self, nrPins):
  204. LayoutGenerator.__init__(self)
  205. self.nrPins = nrPins
  206. def verifyPins(self):
  207. LayoutGenerator.verifyPins(self)
  208. if self.nrPins < 2 or self.nrPins > self.zifPins or self.nrPins % 2 != 0:
  209. raise TOPException("Invalid DIP package")
  210. if self.vccPin < 1 or self.vccPin > self.nrPins:
  211. raise TOPException("Invalid VCC pin number for the selected package")
  212. for vppPin in self.vppPins:
  213. if vppPin < 1 or vppPin > self.nrPins:
  214. raise TOPException("Invalid VPP pin number for the selected package")
  215. if self.gndPin < 1 or self.gndPin > self.nrPins:
  216. raise TOPException("Invalid GND pin number for the selected package")
  217. def maxOffset(self, upsideDown):
  218. return self.zifPins // 2 - self.nrPins // 2
  219. def mapPin2zif(self, dipPin, offset, upsideDown):
  220. assert(dipPin >= 1 and dipPin <= self.nrPins)
  221. if upsideDown:
  222. if dipPin > self.nrPins // 2:
  223. # Right side of DIP
  224. dipPin -= self.nrPins // 2
  225. return dipPin + offset
  226. else:
  227. # Left side of DIP
  228. return self.zifPins - self.nrPins // 2 + dipPin - offset
  229. else:
  230. if dipPin > self.nrPins // 2:
  231. # Right side of DIP
  232. dipPin -= self.nrPins // 2
  233. return self.zifPins - self.nrPins // 2 + dipPin - offset
  234. else:
  235. # Left side of DIP
  236. return dipPin + offset
  237. def zifLayoutAsciiArt(self):
  238. def line(prefix, content, postfix):
  239. return "%3s %s %3s\n" % (prefix, content, postfix)
  240. zifGnd = self.getZifPinForPackagePin(self.gndPin)
  241. zifVcc = self.getZifPinForPackagePin(self.vccPin)
  242. zifVpp = [ self.getZifPinForPackagePin(p) \
  243. for p in self.vppPins ]
  244. ret = line("", "T ZIF socket", "")
  245. ret += line("", "^--o==============o", "")
  246. for zp in range(1, self.zifPins // 2 + 1):
  247. prefix, postfix = "", ""
  248. if zp == zifGnd:
  249. prefix = "GND"
  250. if self.zifPins - zp + 1 == zifGnd:
  251. postfix = "GND"
  252. if zp == zifVcc:
  253. prefix = "VCC"
  254. if self.zifPins - zp + 1 == zifVcc:
  255. postfix = "VCC"
  256. if zp in zifVpp:
  257. prefix = "VPP"
  258. if self.zifPins - zp + 1 in zifVpp:
  259. postfix = "VPP"
  260. if zp < self.result_offset + 1 or \
  261. zp > self.result_offset + self.nrPins // 2:
  262. ret += line(prefix,
  263. "%2d |----- || -----| %2d" %\
  264. (zp, self.zifPins + 1 - zp),
  265. postfix)
  266. else:
  267. if zp == self.result_offset + 1 and \
  268. not self.result_upsideDown:
  269. ret += line(prefix,
  270. "%2d |-- 1##..##o --| %2d" %\
  271. (zp, self.zifPins + 1 - zp),
  272. postfix)
  273. elif zp == self.result_offset + self.nrPins // 2 and \
  274. self.result_upsideDown:
  275. ret += line(prefix,
  276. "%2d |-- o##''##1 --| %2d" %\
  277. (zp, self.zifPins + 1 - zp),
  278. postfix)
  279. else:
  280. ret += line(prefix,
  281. "%2d |-- o######o --| %2d" %\
  282. (zp, self.zifPins + 1 - zp),
  283. postfix)
  284. ret += line("", " o==============o", "")
  285. return ret
  286. def createLayoutGenerator(package):
  287. try:
  288. for regex in ("DIP(\d+)", "PDIP(\d+)", "SO(\d+)", "TSSOP(\d+)", ):
  289. m = re.match(regex, package, re.IGNORECASE)
  290. if m:
  291. nrPins = int(m.group(1))
  292. return LayoutGeneratorDIP(nrPins)
  293. if package.upper() == "PLCC32": # 1:1 adapter
  294. return LayoutGeneratorDIP(32)
  295. if package.upper() == "PLCC44": # 1:1 adapter
  296. return LayoutGeneratorDIP(44)
  297. raise ValueError()
  298. except (ValueError) as e:
  299. raise TOPException("Unknown package type " + package)