123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- """
- # TOP Open Source programming suite
- #
- # TOP853 Lowlevel hardware access
- #
- # Copyright (c) 2022 Michael Buesch <m@bues.ch>
- #
- # 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):
- "TOP853 hardware access"
- 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 8000000
- 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(3) != b"\x69\x0C\x02":
- print("Init: Unexpected status (a)")
- self.runCommandSync(b"\x0E\x2C\x01\x00")
- for i in range(0x18):
- self.queueCommand(b"\x3E" + int2byte(i))
- if self.readBufferReg(4) != b"\x24\x37\x55\x04":
- print("Init: Unexpected status (b)")
- self.setVPPVoltage(0)
- for i in range(0x18):
- self.queueCommand(b"\x3E" + int2byte(i))
- if self.readBufferReg(4) != b"\x24\x37\x55\x04":
- print("Init: Unexpected status (c)")
- self.setVPPVoltage(12)
- self.runCommandSync(b"\x0E\x20\x00\x00")
- self.__delay_10msec(sync=True)
- self.runCommandSync(b"\x0E\x13\x00\x00")
- self.__delay_10msec(sync=True)
- self.runCommandSync(b"\x0A\x1D\x86")
- self.flushCommands()
- self.loadGNDLayout(0)
- self.loadVPPLayout(0)
- self.loadVCCLayout(0)
- for i in range(0x18):
- self.queueCommand(b"\x3E" + int2byte(i))
- if self.readBufferReg(4) != b"\x24\x37\x55\x04":
- print("Init: Unexpected status (c)")
- self.setVPPVoltage(12)
- self.runCommandSync(b"\x0E\x20\x00\x00")
- self.__delay_10msec(sync=True)
- for _ in range(2):
- self.queueCommand(b"\x57\x00\x50")
- if self.readBufferReg(4) != b"\xB0\x37\x55\x04":
- print("Init: Unexpected status (d)")
- for i in range(0x18):
- self.queueCommand(b"\x3E" + int2byte(i))
- if self.readBufferReg(4) != b"\x24\x37\x55\x04":
- print("Init: Unexpected status (c)")
- for i in range(0x20, 0x24):
- self.runCommandSync(b"\x57\x00" + int2byte(i))
- if self.readBufferReg(4) != b"\x80\xBE\x90\x00":
- print("Init: Unexpected status (e)")
- for i in range(0x40, 0x60):
- self.runCommandSync(b"\x57\x00" + int2byte(i))
- if self.readBufferReg(32) != b"\x54\x15\x62\x9E\x6E\xCB\xED\x5D\x15\x32\x70\x81\x05\xF9\x4F\x2E\xB0\x3C\x7E\x7B\x02\x40\x0B\x48\x28\x78\x63\x1D\x0C\x39\x3B\x79":
- print("Init: Unexpected status (f)")
- self.queueCommand(b"\x4F\x02\x00\x00")
- if self.readBufferReg(32) != b"\x48\xFF\x6F\x06\x49\x65\x52\x57\x52\x15\x20\x87\x05\xF9\x4F\x2E\xB0\x3C\x7E\x7B\x02\x40\x0B\x48\x28\x78\x63\x1D\x0C\x39\x3B\x79":
- print("Init: Unexpected status (g)")
- self.runCommandSync(b"\x0E\x10\x00\x00")
- self.runCommandSync(b"\x0E\x2D\x01\x00" + b"\x00\x00" + (b"\x33" * 57))
- self.runCommandSync(b"\x0E\x2D\x02\x00" + (b"\x33" * 56))
- self.runCommandSync(b"\x0E\x2D\x03\x00" + b"\x28" + (b"\x33" * 31) + b"\x00\x00\x00\x00")
- self.loadGNDLayout(20)
- for i in range(0x18):
- self.queueCommand(b"\x3E" + int2byte(i))
- if self.readBufferReg(4) != b"\x24\x37\x55\x04":
- print("Init: Unexpected status (h)")
- self.setVPPVoltage(12)
- # import libtoprammer.top853.sniffer as sniffer
- # sniffer.sniffVPP(self)
- #TODO
- self.flushCommands()
- assert 0#XXX
- def readVersionString(self):
- "Returns the device ID and versioning string."
- self.queueCommand(b"\x0E\x11\x00\x00")
- data = self.readBufferReg(32)
- return data.decode("ASCII", "ignore").replace("\x00", "").strip()
- def getFPGAType(self):
- "Get the FPGA architecture."
- return None # The hardware doesn't have an FPGA.
- def getFPGAMaxConfigChunkSize(self):
- raise NotImplementedError
- def FPGAInitiateConfig(self):
- raise NotImplementedError
- def FPGAUploadConfig(self, offset, data):
- raise NotImplementedError
- def makeFPGAAddr(self, address):
- raise NotImplementedError
- def FPGARead(self, address):
- raise NotImplementedError
- def FPGAWrite(self, address, byte):
- raise NotImplementedError
- def loadGNDLayout(self, layout):
- "Load the GND configuration into the shift registers."
- 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."
- for centivolt in (0, int(voltage * 10)):
- cmd = int2byte(0x0E) + int2byte(0x0F) +\
- 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. This is a no-op. The programmer can only do 5V."
- assert voltage == 0 or voltage == 5
- self.flushCommands()
- 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):
- #TODO
- "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):
- #TODO
- self.queueCommand(int2byte(0x00))
- def __delay_10msec(self, sync=False):
- #TODO
- if sync:
- self.runCommandSync(int2byte(0x1B))
- else:
- 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)
- elif seconds > 0.000255:
- # Need to round up to ten milliseconds
- millisecs = int(math.ceil(seconds * 1e3))
- millisecs = roundup(millisecs, 10)
- for _ in range(millisecs // 10):
- self.__delay_10msec()
- else:
- # Round up to 4 usec boundary
- microsecs = int(math.ceil(seconds * 1e6))
- microsecs = roundup(microsecs, 4)
- for _ in range(microsecs // 4):
- self.__delay_4usec()
|