""" # TOP2049 Open Source programming suite # # TOP2049 Lowlevel hardware access # # Copyright (c) 2012 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 libtoprammer.util import * from libtoprammer.hardware_access_usb import * class HardwareAccess(HardwareAccessUSB): "TOP2049 hardware access" ADDR_OK_BIT = 4 def __init__(self, foundUSBDev, noQueue=False, doRawDump=False): HardwareAccessUSB.__init__(self, usbdev = foundUSBDev.usbdev, maxPacketBytes = 64, noQueue = noQueue, doRawDump = doRawDump) def getOscillatorHz(self): "Get the 'OSC' frequency." return 24000000 def getBufferRegSize(self): "Get the buffer register size, in bytes." return 64 def readBufferReg(self, nrBytes): "Reads and returns the buffer register from hardware." self.queueCommand(int2byte(0x07)) return self.receive(self.getBufferRegSize())[:nrBytes] def hardwareInit(self): "Initialize the hardware." self.queueCommand(b"\x0D") if self.readBufferReg(4) != b"\x69\x0C\x02\x00": print("Init: Unexpected status (a)") self.setVPPVoltage(0) self.setVPPVoltage(0) self.queueCommand(b"\x0E\x20\x00\x00") self.delay(0.01) self.setVCCVoltage(0) self.loadGNDLayout(0) self.loadVPPLayout(0) self.loadVCCLayout(0) self.queueCommand(b"\x0E\x20\x00\x00") self.delay(0.01) self.queueCommand(b"\x0E\x25\x00\x00") if self.readBufferReg(4) != b"\x6C\x68\x00\x00": print("Init: Unexpected status (b)") self.enableZifPullups(False) self.flushCommands() def readVersionString(self): "Returns the device ID and versioning string." self.queueCommand(b"\x0E\x11\x00\x00") data = self.readBufferReg(16) return data.strip() def getFPGAType(self): "Get the FPGA architecture." return "xc2s15" def getFPGAMaxConfigChunkSize(self): "Maximum config chunk size." return 60 def FPGAInitiateConfig(self): "Initiate a configuration sequence on the FPGA." self.queueCommand(b"\x0E\x21\x00\x00") stat = byte2int(self.readBufferReg(1)) expected = 0x01 if stat != expected: raise TOPException("bit-upload: Failed to initiate " +\ "config sequence (got 0x%02X, expected 0x%02X)" %\ (stat, expected)) def FPGAUploadConfig(self, offset, data): "Upload configuration data into the FPGA." assert(len(data) <= self.getFPGAMaxConfigChunkSize()) cmd = b"\x0E\x22\x00\x00" + data cmd += b"\x00" * (64 - len(cmd)) # padding self.queueCommand(cmd) def makeFPGAAddr(self, address): # Set the "address OK" bit return address | (1 << self.ADDR_OK_BIT) def FPGARead(self, address): "Do an FPGA read at 'address'. Data is put into buffer reg." address = self.makeFPGAAddr(address) if address == self.makeFPGAAddr(0): # Fast tracked self.queueCommand(int2byte(0x01)) return self.queueCommand(int2byte(0x0B) + int2byte(address)) def FPGAWrite(self, address, byte): "Write 'byte' to FPGA at 'address'." address = self.makeFPGAAddr(address) if address == self.makeFPGAAddr(0): # Fast tracked self.queueCommand(int2byte(0x10) + int2byte(byte)) return self.queueCommand(int2byte(0x0A) + int2byte(address) +\ int2byte(byte)) def loadGNDLayout(self, layout): "Load the GND configuration into the H/L shiftregisters." cmd = int2byte(0x0E) + int2byte(0x16) +\ int2byte(layout) + int2byte(0) self.queueCommand(cmd) self.delay(0.01) self.flushCommands(0.15) def setVPPVoltage(self, voltage): "Set the VPP voltage. voltage is a floating point voltage number." centivolt = int(voltage * 10) cmd = int2byte(0x0E) + int2byte(0x12) +\ int2byte(centivolt) + int2byte(0) self.queueCommand(cmd) self.delay(0.01) def loadVPPLayout(self, layout): "Load the VPP configuration into the shift registers." cmd = int2byte(0x0E) + int2byte(0x14) +\ int2byte(layout) + int2byte(0) self.queueCommand(cmd) self.delay(0.01) self.flushCommands(0.15) def setVCCVoltage(self, voltage): "Set the VCC voltage." centivolt = int(voltage * 10) cmd = int2byte(0x0E) + int2byte(0x13) +\ int2byte(centivolt) + int2byte(0) self.queueCommand(cmd) self.delay(0.01) def loadVCCLayout(self, layout): "Load the VCC configuration into the shift registers." cmd = int2byte(0x0E) + int2byte(0x15) +\ int2byte(layout) + int2byte(0) self.queueCommand(cmd) self.delay(0.01) self.flushCommands(0.15) def enableZifPullups(self, enable): "Enable the ZIF socket signal pullups." param = 1 if enable else 0 cmd = int2byte(0x0E) + int2byte(0x28) +\ int2byte(param) + int2byte(0) self.queueCommand(cmd) def __delay_4usec(self): self.queueCommand(int2byte(0x00)) def __delay_10msec(self): self.queueCommand(int2byte(0x1B)) def delay(self, seconds): "Perform an on-device or host delay." if seconds >= 0.5: # Perform long delays on the host self.flushCommands(seconds) return if seconds > 0.000255: # Need to round up to ten milliseconds millisecs = int(math.ceil(seconds * 1000)) millisecs = roundup(millisecs, 10) for i in range(0, millisecs // 10): self.__delay_10msec() else: # Round up to 4 usec boundary microsecs = int(math.ceil(seconds * 1000000)) microsecs = roundup(microsecs, 4) for i in range(0, microsecs // 4): self.__delay_4usec()