hardware_access.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. """
  2. # TOP2049 Open Source programming suite
  3. #
  4. # TOP2049 Lowlevel hardware access
  5. #
  6. # Copyright (c) 2012 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 libtoprammer.util import *
  23. from libtoprammer.hardware_access_usb import *
  24. class HardwareAccess(HardwareAccessUSB):
  25. "TOP2049 hardware access"
  26. ADDR_OK_BIT = 4
  27. def __init__(self, foundUSBDev,
  28. noQueue=False, doRawDump=False):
  29. HardwareAccessUSB.__init__(self,
  30. usbdev = foundUSBDev.usbdev,
  31. maxPacketBytes = 64,
  32. noQueue = noQueue,
  33. doRawDump = doRawDump)
  34. def getOscillatorHz(self):
  35. "Get the 'OSC' frequency."
  36. return 24000000
  37. def getBufferRegSize(self):
  38. "Get the buffer register size, in bytes."
  39. return 64
  40. def readBufferReg(self, nrBytes):
  41. "Reads and returns the buffer register from hardware."
  42. self.queueCommand(int2byte(0x07))
  43. return self.receive(self.getBufferRegSize())[:nrBytes]
  44. def hardwareInit(self):
  45. "Initialize the hardware."
  46. self.queueCommand(b"\x0D")
  47. if self.readBufferReg(4) != b"\x69\x0C\x02\x00":
  48. print("Init: Unexpected status (a)")
  49. self.setVPPVoltage(0)
  50. self.setVPPVoltage(0)
  51. self.queueCommand(b"\x0E\x20\x00\x00")
  52. self.delay(0.01)
  53. self.setVCCVoltage(0)
  54. self.loadGNDLayout(0)
  55. self.loadVPPLayout(0)
  56. self.loadVCCLayout(0)
  57. self.queueCommand(b"\x0E\x20\x00\x00")
  58. self.delay(0.01)
  59. self.queueCommand(b"\x0E\x25\x00\x00")
  60. if self.readBufferReg(4) != b"\x6C\x68\x00\x00":
  61. print("Init: Unexpected status (b)")
  62. self.enableZifPullups(False)
  63. self.flushCommands()
  64. def readVersionString(self):
  65. "Returns the device ID and versioning string."
  66. self.queueCommand(b"\x0E\x11\x00\x00")
  67. data = self.readBufferReg(16)
  68. return data.decode("ASCII", "ignore").strip()
  69. def getFPGAType(self):
  70. "Get the FPGA architecture."
  71. return "xc2s15"
  72. def getFPGAMaxConfigChunkSize(self):
  73. "Maximum config chunk size."
  74. return 60
  75. def FPGAInitiateConfig(self):
  76. "Initiate a configuration sequence on the FPGA."
  77. self.queueCommand(b"\x0E\x21\x00\x00")
  78. stat = byte2int(self.readBufferReg(1))
  79. expected = 0x01
  80. if stat != expected:
  81. raise TOPException("bit-upload: Failed to initiate " +\
  82. "config sequence (got 0x%02X, expected 0x%02X)" %\
  83. (stat, expected))
  84. def FPGAUploadConfig(self, offset, data):
  85. "Upload configuration data into the FPGA."
  86. assert(len(data) <= self.getFPGAMaxConfigChunkSize())
  87. cmd = b"\x0E\x22\x00\x00" + data
  88. cmd += b"\x00" * (64 - len(cmd)) # padding
  89. self.queueCommand(cmd)
  90. def makeFPGAAddr(self, address):
  91. # Set the "address OK" bit
  92. return address | (1 << self.ADDR_OK_BIT)
  93. def FPGARead(self, address):
  94. "Do an FPGA read at 'address'. Data is put into buffer reg."
  95. address = self.makeFPGAAddr(address)
  96. if address == self.makeFPGAAddr(0): # Fast tracked
  97. self.queueCommand(int2byte(0x01))
  98. return
  99. self.queueCommand(int2byte(0x0B) + int2byte(address))
  100. def FPGAWrite(self, address, byte):
  101. "Write 'byte' to FPGA at 'address'."
  102. address = self.makeFPGAAddr(address)
  103. if address == self.makeFPGAAddr(0): # Fast tracked
  104. self.queueCommand(int2byte(0x10) + int2byte(byte))
  105. return
  106. self.queueCommand(int2byte(0x0A) + int2byte(address) +\
  107. int2byte(byte))
  108. def loadGNDLayout(self, layout):
  109. "Load the GND configuration into the H/L shiftregisters."
  110. cmd = int2byte(0x0E) + int2byte(0x16) +\
  111. int2byte(layout) + int2byte(0)
  112. self.queueCommand(cmd)
  113. self.delay(0.01)
  114. self.flushCommands(0.15)
  115. def setVPPVoltage(self, voltage):
  116. "Set the VPP voltage. voltage is a floating point voltage number."
  117. centivolt = int(voltage * 10)
  118. cmd = int2byte(0x0E) + int2byte(0x12) +\
  119. int2byte(centivolt) + int2byte(0)
  120. self.queueCommand(cmd)
  121. self.delay(0.01)
  122. def loadVPPLayout(self, layout):
  123. "Load the VPP configuration into the shift registers."
  124. cmd = int2byte(0x0E) + int2byte(0x14) +\
  125. int2byte(layout) + int2byte(0)
  126. self.queueCommand(cmd)
  127. self.delay(0.01)
  128. self.flushCommands(0.15)
  129. def setVCCVoltage(self, voltage):
  130. "Set the VCC voltage."
  131. centivolt = int(voltage * 10)
  132. cmd = int2byte(0x0E) + int2byte(0x13) +\
  133. int2byte(centivolt) + int2byte(0)
  134. self.queueCommand(cmd)
  135. self.delay(0.01)
  136. def loadVCCLayout(self, layout):
  137. "Load the VCC configuration into the shift registers."
  138. cmd = int2byte(0x0E) + int2byte(0x15) +\
  139. int2byte(layout) + int2byte(0)
  140. self.queueCommand(cmd)
  141. self.delay(0.01)
  142. self.flushCommands(0.15)
  143. def enableZifPullups(self, enable):
  144. "Enable the ZIF socket signal pullups."
  145. param = 1 if enable else 0
  146. cmd = int2byte(0x0E) + int2byte(0x28) +\
  147. int2byte(param) + int2byte(0)
  148. self.queueCommand(cmd)
  149. def __delay_4usec(self):
  150. self.queueCommand(int2byte(0x00))
  151. def __delay_10msec(self):
  152. self.queueCommand(int2byte(0x1B))
  153. def delay(self, seconds):
  154. "Perform an on-device or host delay."
  155. if seconds >= 0.5:
  156. # Perform long delays on the host
  157. self.flushCommands(seconds)
  158. return
  159. if seconds > 0.000255:
  160. # Need to round up to ten milliseconds
  161. millisecs = int(math.ceil(seconds * 1000))
  162. millisecs = roundup(millisecs, 10)
  163. for i in range(0, millisecs // 10):
  164. self.__delay_10msec()
  165. else:
  166. # Round up to 4 usec boundary
  167. microsecs = int(math.ceil(seconds * 1000000))
  168. microsecs = roundup(microsecs, 4)
  169. for i in range(0, microsecs // 4):
  170. self.__delay_4usec()