#!/usr/bin/env python """ # TOP2049 Open Source programming suite # # Copyright (c) 2009-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 bitfile import * import sys import getopt import time try: import usb except (ImportError), e: print "Python USB support module not found. Please install python-usb." sys.exit(1) def dumpMem(mem): def toAscii(char): if char >= 32 and char <= 126: return chr(char) return "." ascii = "" for i in range(0, len(mem)): if i % 16 == 0 and i != 0: sys.stdout.write(" " + ascii + "\n") ascii = "" if i % 16 == 0: sys.stdout.write("0x%04X: " % i) c = ord(mem[i]) sys.stdout.write("%02X" % c) if (i % 2 != 0): sys.stdout.write(" ") ascii += toAscii(c) sys.stdout.write(" " + ascii + "\n\n") class TOPException(Exception): pass class TOP: # Configurable voltage lines. VOLTAGE_VPP = 0x12 VOLTAGE_VCCX = 0x13 def __init__(self, bitfileName, busDev=None): """bitfileName is the path to the .bit file. busDev is a tuple (BUSID, DEVID) or None.""" self.bitfile = Bitfile() self.bitfile.parseFile(bitfileName) # Find the device for bus in usb.busses(): if busDev and bus.dirname != "%03d" % busDev[0]: continue for dev in bus.devices: if busDev and dev.filename != "%03d" % busDev[1]: continue if self.__isTOP(dev): break if busDev: raise TOPException( "Device %03d.%03d is not a TOP device" %\ (busDev[0], busDev[1])) else: continue break else: raise TOPException("TOP programmer device not found!") self.usbbus = bus self.usbdev = dev self.bulkOut = None self.bulkIn = None # Set up the USB interface try: self.usbh = self.usbdev.open() config = self.usbdev.configurations[0] interface = config.interfaces[0][0] # Find the endpoints for ep in interface.endpoints: if not self.bulkIn and \ ep.type == usb.ENDPOINT_TYPE_BULK and \ (ep.address & usb.ENDPOINT_IN) != 0: self.bulkIn = ep if not self.bulkOut and \ ep.type == usb.ENDPOINT_TYPE_BULK and \ (ep.address & usb.ENDPOINT_IN) == 0: self.bulkOut = ep if not self.bulkIn or not self.bulkOut: raise TOPException("Did not find all USB EPs") self.usbh.setConfiguration(config) self.usbh.claimInterface(interface) self.usbh.setAltInterface(interface) self.usbh.clearHalt(self.bulkOut.address) self.usbh.clearHalt(self.bulkIn.address) except (usb.USBError), e: raise TOPException("USB error: " + str(e)) self.__initialize() @staticmethod def __isTOP(usbdev): ids = ( (0x2471, 0x0853), ) return (usbdev.idVendor, usbdev.idProduct) in ids def __initialize(self): "Initialize the hardware" ver = self.cmdRequestVersion() print "Detected a", ver self.__send("\x0D") stat = self.cmdReadStatusReg() # What to do with the status? self.__send("\x0A\x1B\xFF") self.cmdSetVoltage(TOP.VOLTAGE_VPP, 0) self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VPP, 0) self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VPP, 0) self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VPP, 12) self.cmdFlush() self.__send("\x0E\x20\x00\x00") self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VCCX, 0) self.cmdFlush() self.__send("\x0A\x1D\x86") self.cmdSetGNDPin(0) self.cmdLoadVPPLayout(0) self.cmdLoadVCCXLayout(0) self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VPP, 0) self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VPP, 12) self.cmdFlush() self.__send("\x0E\x20\x00\x00") self.cmdFlush() self.__send("\x0E\x25\x00\x00") stat = self.cmdReadStatusReg() # What to do with the status? self.__bitfileUpload() self.__initVoltageLayouts() def __bitfileUpload(self): self.__send("\x0A\x1B\x00") self.__send("\x0E\x21\x00\x00") stat = self.cmdReadStatusReg() # What to do with the status? data = self.bitfile.getPayload() for i in range(0, len(data), 60): self.cmdFPGAUploadData(data[i : i + 60]) def __initVoltageLayouts(self): # FIXME: This depends on the selected chip self.cmdSetGNDPin(18) self.cmdSetVoltage(TOP.VOLTAGE_VCCX, 5) self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VPP, 0) self.cmdFlush() self.cmdSetVoltage(TOP.VOLTAGE_VPP, 12) def cmdFlush(self, count=1): """Send 'count' flush requests.""" assert(count >= 1) self.__send(chr(0x1B) * count) def cmdReadStatusReg(self): """Read the status register. Returns 64 bytes.""" self.__send(chr(0x07)) return self.__receive(64) def cmdRequestVersion(self): """Returns the device ID and versioning string.""" self.__send("\x0E\x11\x00\x00") data = self.cmdReadStatusReg() return data[0:16].strip() def cmdFPGAUploadData(self, data): """Upload data into the FPGA.""" assert(len(data) <= 60) cmd = "\x0E\x22\x00\x00" + data cmd += "\x00" * (64 - len(cmd)) # padding self.__send(cmd) def cmdSetGNDPin(self, zifPin): """Assign GND to a ZIF socket pin. 0=none""" valid = (0, 5, 14, 15, 16, 17, 18, 19, 20, 24, 26, 27, 28, 29, 33, 34, 35) assert(zifPin in valid) if zifPin != 0: zifPin -= 4 cmd = chr(0x0E) + chr(0x16) + chr(zifPin) + chr(0) self.__send(cmd) def cmdLoadVPPLayout(self, layout): """Load the VPP configuration into the shift registers.""" cmd = chr(0x0E) + chr(0x14) + chr(layout) + chr(0) self.__send(cmd) def cmdLoadVCCXLayout(self, layout): """Load the VCCX configuration into the shift registers.""" cmd = chr(0x0E) + chr(0x15) + chr(layout) + chr(0) self.__send(cmd) def cmdSetVoltage(self, line, voltage): """Set the voltage of a line. line is a VOLTAGE_xxx idenitifier. voltage is a floating point number.""" centivolt = int(voltage * 10) cmd = chr(0x0E) + chr(line) + chr(centivolt) + chr(0) self.__send(cmd) def __send(self, command): try: ep = self.bulkOut.address self.usbh.bulkWrite(ep, command) except (usb.USBError), e: raise TOPException("USB bulk write error: " + str(e)) def __receive(self, size): try: ep = self.bulkIn.address data = "" for c in self.usbh.bulkRead(ep, size): data += chr(c) dumpMem(data)#XXX except (usb.USBError), e: raise TOPException("USB bulk read error: " + str(e)) return data def usage(): print "TOP2049 Open Source programming suite" print "" print "Usage: %s [OPTIONS]" % sys.argv[0] print "" print " -b|--bitfile Path to the *.bit file (mandatory)" print "" print " -d|--device BUS.DEV Use the programmer at BUS.DEV" print " First found programmer is used, if not given." def main(argv): opt_bitfile = None opt_device = None try: (opts, args) = getopt.getopt(sys.argv[1:], "hb:d:", [ "help", "bitfile=", "device=", ]) except getopt.GetoptError: usage() return 1 for (o, v) in opts: if o in ("-h", "--help"): usage() return 0 if o in ("-b", "--bitfile"): opt_bitfile = v if o in ("-d", "--device"): try: v = v.split(".") opt_device = (int(v[0]), int(v[1])) except (IndexError, ValueError), e: print "-d|--device invalid BUS.DEV id." return 1 if not opt_bitfile: print "-b|--bitfile is mandatory!" return 1 try: top = TOP(opt_bitfile, opt_device) except (TOPException, BitfileException), e: print e return 1 return 0 if __name__ == "__main__": sys.exit(main(sys.argv))