Beispiel #1
1
	def __init__(self, ft232r, chain, logger):
		self.jobqueue = Queue()
		self.ft232r = ft232r
		self.chain = chain
		self.jtag = JTAG(ft232r, chain)
		self.logger = logger
		self.id = -1
		
		self.current_job = None
		self.last_job = 0
		
		self.nonce_count = 0
		self.valid_count = 0
		self.invalid_count = 0
		self.accepted_count = 0
		self.rejected_count = 0
		self.recent_valids = 0
		
		self.asleep = True

		self.firmware_rev = 0
		self.firmware_build = 0
Beispiel #2
1
    logger.fpga_list = fpga_list
    rpcclient.fpga_list = fpga_list

    for id, fpga in enumerate(fpga_list):
        fpga.id = id
        logger.reportDebug("Discovering FPGA %d..." % id, False)
        fpga.detect()

        logger.reportDebug(
            "Found %i device%s:" % (fpga.jtag.deviceCount, "s" if fpga.jtag.deviceCount != 1 else ""), False
        )

        if len(fpga.jtag.idcodes) > 0:
            idcode = fpga.jtag.idcodes[-1]
            msg = " FPGA" + str(id) + ": "
            msg += JTAG.decodeIdcode(idcode)
            msg += " - Firmware: rev " + str(fpga.firmware_rev)
            msg += ", build " + str(fpga.firmware_build)
            logger.reportDebug(msg, False)

    logger.log("Connected to %d FPGAs" % len(fpga_list), False)

    if settings.overclock is not None:
        for fpga in fpga_list:
            fpga.setClockSpeed(settings.overclock)

    for fpga in fpga_list:
        clock_speed = fpga.readClockSpeed()

        clock_speed = "???" if clock_speed is None else str(clock_speed)
Beispiel #3
1
    fpga.id = id
    logger.reportDebug("Discovering FPGA %d ..." % id, False)
    fpga.detect()
    
    logger.reportDebug("Found %i device%s:" % (fpga.jtag.deviceCount,
      's' if fpga.jtag.deviceCount != 1 else ''), False)
    
    if fpga.jtag.deviceCount > 1:
      logger.log("Warning:", False)
      logger.log("This software currently supports only one device per chain.", False)
      logger.log("Only the last part will be programmed.", False)

    if fpga.jtag.deviceCount > 0:
      idcode = fpga.jtag.idcodes[-1]
      msg = " FPGA" + str(id) + ": "
      msg += JTAG.decodeIdcode(idcode)
      logger.reportDebug(msg, False)
      if idcode & 0x0FFFFFFF != bitfile.idcode:
        raise BitFileMismatch
  
  logger.log("Connected to %d FPGAs" % len(fpga_list), False)
  
  if settings.chain == 2:
    jtag = JTAG(ft232r, settings.chain)
    jtag.deviceCount = 1
    jtag.idcodes = [bitfile.idcode]
    jtag._processIdcodes()
  else:
    jtag = fpga_list[0].jtag
  
  if bitfile.processed[settings.chain]:
Beispiel #4
1
class FPGA:
	def __init__(self, ft232r, chain, logger):
		self.jobqueue = Queue()
		self.ft232r = ft232r
		self.chain = chain
		self.jtag = JTAG(ft232r, chain)
		self.logger = logger
		self.id = -1
		
		self.current_job = None
		self.last_job = 0
		
		self.nonce_count = 0
		self.valid_count = 0
		self.invalid_count = 0
		self.accepted_count = 0
		self.rejected_count = 0
		self.recent_valids = 0
		
		self.asleep = True

		self.firmware_rev = 0
		self.firmware_build = 0
	
	def detect(self):
		with self.ft232r.lock:
			self.jtag.detect()

			# Always use the last part in the chain
			if self.jtag.deviceCount > 0:
				self.jtag.part(self.jtag.deviceCount-1)

				usercode = self._readUserCode()

				if usercode == 0xFFFFFFFF:
					self.firmware_rev = 0
					self.firmware_build = 0
				else:
					self.firmware_rev = (usercode >> 8) & 0xFF
					self.firmware_build = usercode & 0xFF

	# Read the FPGA's USERCODE register, which gets set by the firmware
	# In our case this should be 0xFFFFFFFF for all old firmware revs,
	# and 0x4224???? for newer revs. The 2nd byte determines firmware rev/version,
	# and the 1st byte determines firmware build.
	def _readUserCode(self):
		with self.ft232r.lock:
			if self.asleep: self.wake()
			self.jtag.tap.reset()
			self.jtag.instruction(USERCODE)
			self.jtag.shift_ir()
			usercode = bits2int(self.jtag.read_dr(int2bits(0, 32)))

		return usercode

	# Old JTAG Comm:
	def _readByte(self):
		bits = int2bits(0, 13)
		byte = bits2int(self.jtag.read_dr(bits))
		return byte

	# New JTAG Comm
	# Read a 32-bit register
	def _readRegister(self, address):
		address = address & 0xF

		with self.ft232r.lock:
			if self.asleep: self.wake()
			self.jtag.tap.reset()
			self.jtag.instruction(USER_INSTRUCTION)
			self.jtag.shift_ir()

			# Tell the FPGA what address we would like to read
			data = int2bits(address, 5)
			data = data + jtagcomm_checksum(data)
			self.jtag.shift_dr(data)

			# Now read back the register
			data = self.jtag.read_dr(int2bits(0, 32))
			data = bits2int(data)

			self.jtag.tap.reset()

		return data

	# Write a single 32-bit register
	# If doing multiple writes, this won't be as efficient
	def _writeRegister(self, address, data):
		address = address & 0xF
		data = data & 0xFFFFFFFF

		with self.ft232r.lock:
			if self.asleep: self.wake()
			self.jtag.tap.reset()
			self.jtag.instruction(USER_INSTRUCTION)
			self.jtag.shift_ir()

			# Tell the FPGA what address we would like to write
			# and the data.
			data = int2bits(data, 32) + int2bits(address, 4) + [1]
			data = data + jtagcomm_checksum(data)
			self.jtag.shift_dr(data)

			self.jtag.tap.reset()
			self.ft232r.flush()
	
	def _burstWriteHelper(self, address, data):
		address = address & 0xF
		x = int2bits(data, 32)
		x += int2bits(address, 4)
		x += [1]
		x = x + jtagcomm_checksum(x)

		self.jtag.shift_dr(x)

	
	# Writes multiple 32-bit registers.
	# data should be an array of 32-bit values
	# address is the starting address.
	# TODO: Implement readback of some kind to ensure all our writes succeeded.
	# TODO: This is difficult, because reading back data will slow things down.
	# TODO: If the JTAG class let us read data back after a shift, we could probably
	# TODO: use that at the end of the burst write.
	def _burstWrite(self, address, data):
		with self.ft232r.lock:
			if self.asleep: self.wake()
			self.jtag.tap.reset()
			self.jtag.instruction(USER_INSTRUCTION)
			self.jtag.shift_ir()

			for offset in range(len(data)):
				self._burstWriteHelper(address + offset, data[offset])

			self.jtag.tap.reset()
			self.ft232r.flush()

		return True
	
	# TODO: Remove backwards compatibility in a future rev.
	def _old_readNonce(self):
		with self.ft232r.lock:
			if self.asleep: self.wake()
			self.jtag.tap.reset()
			self.jtag.instruction(USER_INSTRUCTION)
			self.jtag.shift_ir()
			self.asleep = False

			# Sync to the beginning of a nonce.
			# The MSB is a VALID flag. If 0, data is invalid (queue empty).
			# The next 4-bits indicate which byte of the nonce we got.
			# 1111 is LSB, and then 0111, 0011, 0001.
			byte = None
			while True:
				byte = self._readByte()

				# check data valid bit:
				if byte < 0x1000:
					self.jtag.tap.reset()
					return None
				
				#self.logger.reportDebug("%d: Read: %04x" % (self.id, byte))
				
				# check byte counter:
				if (byte & 0xF00) == 0xF00:
					break
			
			# We now have the first byte
			nonce = byte & 0xFF
			count = 1
			#self.logger.reportDebug("%d: Potential nonce, reading the rest..." % self.id)
			while True:
				byte = self._readByte()
				
				#self.logger.reportDebug("%d: Read: %04x" % (self.id, byte))
				
				# check data valid bit:
				if byte < 0x1000:
					self.jtag.tap.reset()
					return None
				
				# check byte counter:
				if (byte & 0xF00) >> 8 != (0xF >> count):
					self.jtag.tap.reset()
					return None
				
				nonce |= (byte & 0xFF) << (count * 8)
				count += 1
				
				if (byte & 0xF00) == 0x100:
					break

			self.jtag.tap.reset()

		#self.logger.reportDebug("%d: Nonce completely read: %08x" % (self.id, nonce))

		return nonce
	
	# TODO: This may not actually clear the queue, but should be correct most of the time.
	def _old_clearQueue(self):
		with self.ft232r.lock:
			if self.asleep: self.wake()
			self.jtag.tap.reset()
			self.jtag.instruction(USER_INSTRUCTION)
			self.jtag.shift_ir()
			self.asleep = False
			
			self.logger.reportDebug("%d: Clearing queue..." % self.id)
			while True:
				if self._readByte() < 0x1000:
					break
			self.jtag.tap.reset()
		
		self.logger.reportDebug("%d: Queue cleared" % self.id)
	
	def _old_writeJob(self, job):
		# We need the 256-bit midstate, and 12 bytes from data.
		# The first 64 bytes of data are already hashed (hence midstate),
		# so we skip that. Of the last 64 bytes, 52 bytes are constant and
		# not needed by the FPGA.
		
		start_time = time.time()
		
		midstate = hexstr2array(job.midstate)
		data = hexstr2array(job.data)[64:64+12]

		# Job's hex strings are LSB first, and the FPGA wants them MSB first.
		midstate.reverse()
		data.reverse()

		with self.ft232r.lock:
			#self.logger.reportDebug("%d: Loading job data..." % self.id)
			
			if self.asleep: self.wake()
			self.jtag.tap.reset()
			self.jtag.instruction(USER_INSTRUCTION)
			self.jtag.shift_ir()

			data = midstate + data + [0]

			for i in range(len(data)):
				x = data[i]

				if i != 0:
					x = 0x100 | x
					
				self.jtag.shift_dr(int2bits(x, 13))
			
			self.jtag.tap.reset()

			self.ft232r.flush()
		
		#self.logger.reportDebug("%d: Job data loaded in %.3f seconds" % (self.id, time.time() - start_time))
		self.logger.reportDebug("%d: Job data loaded" % self.id)
	
	def _readNonce(self):
		nonce = self._readRegister(0xE)

		if nonce == 0xFFFFFFFF:
			return None
		return nonce
	
	def _clearQueue(self):
		self.logger.reportDebug("%d: Clearing queue..." % self.id)
		while True:
			if self.readNonce() is None:
				break
		
		self.logger.reportDebug("%d: Queue cleared" % self.id)
	
	def _writeJob(self, job):
		# We need the 256-bit midstate, and 12 bytes from data.
		# The first 64 bytes of data are already hashed (hence midstate),
		# so we skip that. Of the last 64 bytes, 52 bytes are constant and
		# not needed by the FPGA.
		
		start_time = time.time()
		
		midstate = hexstr2array(job.midstate)
		data = hexstr2array(job.data)[64:64+12]
		data = midstate + data

		words = []

		for i in range(11):
			word = data[i*4] | (data[i*4+1] << 8) | (data[i*4+2] << 16) | (data[i*4+3] << 24)
			words.append(word)

		if not self._burstWrite(1, words):
			self.logger.reportDebug("%d: ERROR: Loading job data failed; readback failure" % self.id)
			return
		
		self.logger.reportDebug("%d: Job data loaded in %.3f seconds" % (self.id, time.time() - start_time))
		#self.logger.reportDebug("%d: Job data loaded" % self.id)
	
	# Read the FPGA's current clock speed, in MHz
	# NOTE: This is currently just what we've written into the clock speed
	# register, so it does NOT take into account hard limits in the firmware.
	def readClockSpeed(self):
		if self.firmware_rev == 0:
			return None
		
		frequency = self._readRegister(0xD)

		return frequency

	# Set the FPGA's clock speed, in MHz
	# NOTE: Be VERY careful not to set the clock speed too high!!!
	def setClockSpeed(self, speed):
		if self.firmware_rev == 0:
			return False

		return self._writeRegister(0xD, speed)
	
	def readNonce(self):
		if self.firmware_rev == 0:
			return self._old_readNonce()
		else:
			return self._readNonce()
	
	def clearQueue(self):
		if self.firmware_rev == 0:
			return self._old_clearQueue()
		else:
			return self._clearQueue()
	
	def writeJob(self, job):
		if self.firmware_rev == 0:
			return self._old_writeJob(job)
		else:
			return self._writeJob(job)
	
	def getJob(self):
		try:
			#logger.reportDebug("%d: Checking for new job..." % fpga.id)
			return self.jobqueue.get(False)
		except Empty:
			return None
	
	def putJob(self, work):
		job = Object()
		job.midstate = work['midstate']
		job.data = work['data']
		job.target = work['target']
		self.jobqueue.put(job)
		#self.logger.reportDebug("%d: jobqueue loaded (%d)" % (fpga.id, self.jobqueue.qsize()))
	
	def sleep(self):
		with self.ft232r.lock:
			self.logger.reportDebug("%d: Going to sleep..." % self.id)
			
			self.jtag.tap.reset()
			self.jtag.instruction(JSHUTDOWN)
			self.jtag.shift_ir()
			self.jtag.runtest(24)
			self.jtag.tap.reset()
			
			self.ft232r.flush()
		
		self.asleep = True
	
	def wake(self):
		with self.ft232r.lock:
			self.logger.reportDebug("%d: Waking up..." % self.id)
		
			self.jtag.tap.reset()
			self.jtag.instruction(JSTART)
			self.jtag.shift_ir()
			self.jtag.runtest(24)
			self.jtag.instruction(BYPASS)
			self.jtag.shift_ir()
			self.jtag.instruction(BYPASS)
			self.jtag.shift_ir()
			self.jtag.instruction(JSTART)
			self.jtag.shift_ir()
			self.jtag.runtest(24)
			self.jtag.tap.reset()
			
			self.ft232r.flush()
		
		self.asleep = False
	
	@staticmethod
	def programBitstream(ft232r, jtag, logger, processed_bitstream):
		with ft232r.lock:
			# Select the device
			jtag.reset()
			jtag.part(jtag.deviceCount-1)
			
			jtag.instruction(BYPASS) 
			jtag.shift_ir()

			jtag.instruction(JPROGRAM)
			jtag.shift_ir()

			jtag.instruction(CFG_IN)
			jtag.shift_ir()

			# Clock TCK for 10000 cycles
			jtag.runtest(10000)

			jtag.instruction(CFG_IN)
			jtag.shift_ir()
			jtag.shift_dr([0]*32)
			jtag.instruction(CFG_IN)
			jtag.shift_ir()

			ft232r.flush()
			
			# Load bitstream into CFG_IN
			jtag.load_bitstream(processed_bitstream, logger.updateProgress)

			jtag.instruction(JSTART)
			jtag.shift_ir()

			# Let the device start
			jtag.runtest(24)
			
			jtag.instruction(BYPASS)
			jtag.shift_ir()
			jtag.instruction(BYPASS)
			jtag.shift_ir()

			jtag.instruction(JSTART)
			jtag.shift_ir()

			jtag.runtest(24)
			
			# Check done pin
			#jtag.instruction(BYPASS)
			# TODO: Figure this part out. & 0x20 should equal 0x20 to check the DONE pin ... ???
			#print jtag.read_ir() # & 0x20 == 0x21
			#jtag.instruction(BYPASS)
			#jtag.shift_ir()
			#jtag.shift_dr([0])

			ft232r.flush()
Beispiel #5
0
    def __init__(self, ft232r, chain, logger):
        self.jobqueue = Queue()
        self.ft232r = ft232r
        self.chain = chain
        self.jtag = JTAG(ft232r, chain)
        self.logger = logger
        self.id = -1

        self.current_job = None
        self.last_job = 0

        self.nonce_count = 0
        self.valid_count = 0
        self.invalid_count = 0
        self.accepted_count = 0
        self.rejected_count = 0
        self.recent_valids = 0

        self.asleep = True

        self.firmware_rev = 0
        self.firmware_build = 0
Beispiel #6
0
        logger.reportDebug(
            "Found %i device%s:" %
            (fpga.jtag.deviceCount, 's' if fpga.jtag.deviceCount != 1 else ''),
            False)

        if fpga.jtag.deviceCount > 1:
            logger.log("Warning:", False)
            logger.log(
                "This software currently supports only one device per chain.",
                False)
            logger.log("Only the last part will be programmed.", False)

        if fpga.jtag.deviceCount > 0:
            idcode = fpga.jtag.idcodes[-1]
            msg = " FPGA" + str(id) + ": "
            msg += JTAG.decodeIdcode(idcode)
            logger.reportDebug(msg, False)
            if idcode & 0x0FFFFFFF != bitfile.idcode:
                raise BitFileMismatch

    logger.log("Connected to %d FPGAs" % len(fpga_list), False)

    if settings.chain == 2:
        jtag = JTAG(ft232r, settings.chain)
        jtag.deviceCount = 1
        jtag.idcodes = [bitfile.idcode]
        jtag._processIdcodes()
    else:
        jtag = fpga_list[0].jtag

    if bitfile.processed[settings.chain]:
Beispiel #7
0
    rpcclient.fpga_list = fpga_list

    for id, fpga in enumerate(fpga_list):
        fpga.id = id
        logger.reportDebug("Discovering FPGA %d..." % id, False)
        fpga.detect()

        logger.reportDebug(
            "Found %i device%s:" %
            (fpga.jtag.deviceCount, 's' if fpga.jtag.deviceCount != 1 else ''),
            False)

        if len(fpga.jtag.idcodes) > 0:
            idcode = fpga.jtag.idcodes[-1]
            msg = " FPGA" + str(id) + ": "
            msg += JTAG.decodeIdcode(idcode)
            msg += " - Firmware: rev " + str(fpga.firmware_rev)
            msg += ", build " + str(fpga.firmware_build)
            logger.reportDebug(msg, False)

    logger.log("Connected to %d FPGAs" % len(fpga_list), False)

    if settings.overclock is not None:
        for fpga in fpga_list:
            fpga.setClockSpeed(settings.overclock)

    for fpga in fpga_list:
        clock_speed = fpga.readClockSpeed()

        clock_speed = "???" if clock_speed is None else str(clock_speed)
Beispiel #8
0
class FPGA:
    def __init__(self, ft232r, chain, logger):
        self.jobqueue = Queue()
        self.ft232r = ft232r
        self.chain = chain
        self.jtag = JTAG(ft232r, chain)
        self.logger = logger
        self.id = -1

        self.current_job = None
        self.last_job = 0

        self.nonce_count = 0
        self.valid_count = 0
        self.invalid_count = 0
        self.accepted_count = 0
        self.rejected_count = 0
        self.recent_valids = 0

        self.asleep = True

        self.firmware_rev = 0
        self.firmware_build = 0

    def detect(self):
        with self.ft232r.lock:
            self.jtag.detect()

            # Always use the last part in the chain
            if self.jtag.deviceCount > 0:
                self.jtag.part(self.jtag.deviceCount - 1)

                usercode = self._readUserCode()

                if usercode == 0xFFFFFFFF:
                    self.firmware_rev = 0
                    self.firmware_build = 0
                else:
                    self.firmware_rev = (usercode >> 8) & 0xFF
                    self.firmware_build = usercode & 0xFF

    # Read the FPGA's USERCODE register, which gets set by the firmware
    # In our case this should be 0xFFFFFFFF for all old firmware revs,
    # and 0x4224???? for newer revs. The 2nd byte determines firmware rev/version,
    # and the 1st byte determines firmware build.
    def _readUserCode(self):
        with self.ft232r.lock:
            if self.asleep: self.wake()
            self.jtag.tap.reset()
            self.jtag.instruction(USERCODE)
            self.jtag.shift_ir()
            usercode = bits2int(self.jtag.read_dr(int2bits(0, 32)))

        return usercode

    # Old JTAG Comm:
    def _readByte(self):
        bits = int2bits(0, 13)
        byte = bits2int(self.jtag.read_dr(bits))
        return byte

    # New JTAG Comm
    # Read a 32-bit register
    def _readRegister(self, address):
        address = address & 0xF

        with self.ft232r.lock:
            if self.asleep: self.wake()
            self.jtag.tap.reset()
            self.jtag.instruction(USER_INSTRUCTION)
            self.jtag.shift_ir()

            # Tell the FPGA what address we would like to read
            data = int2bits(address, 5)
            data = data + jtagcomm_checksum(data)
            self.jtag.shift_dr(data)

            # Now read back the register
            data = self.jtag.read_dr(int2bits(0, 32))
            data = bits2int(data)

            self.jtag.tap.reset()

        return data

    # Write a single 32-bit register
    # If doing multiple writes, this won't be as efficient
    def _writeRegister(self, address, data):
        address = address & 0xF
        data = data & 0xFFFFFFFF

        with self.ft232r.lock:
            if self.asleep: self.wake()
            self.jtag.tap.reset()
            self.jtag.instruction(USER_INSTRUCTION)
            self.jtag.shift_ir()

            # Tell the FPGA what address we would like to write
            # and the data.
            data = int2bits(data, 32) + int2bits(address, 4) + [1]
            data = data + jtagcomm_checksum(data)
            self.jtag.shift_dr(data)

            self.jtag.tap.reset()
            self.ft232r.flush()

    def _burstWriteHelper(self, address, data):
        address = address & 0xF
        x = int2bits(data, 32)
        x += int2bits(address, 4)
        x += [1]
        x = x + jtagcomm_checksum(x)

        self.jtag.shift_dr(x)

    # Writes multiple 32-bit registers.
    # data should be an array of 32-bit values
    # address is the starting address.
    # TODO: Implement readback of some kind to ensure all our writes succeeded.
    # TODO: This is difficult, because reading back data will slow things down.
    # TODO: If the JTAG class let us read data back after a shift, we could probably
    # TODO: use that at the end of the burst write.
    def _burstWrite(self, address, data):
        with self.ft232r.lock:
            if self.asleep: self.wake()
            self.jtag.tap.reset()
            self.jtag.instruction(USER_INSTRUCTION)
            self.jtag.shift_ir()

            for offset in range(len(data)):
                self._burstWriteHelper(address + offset, data[offset])

            self.jtag.tap.reset()
            self.ft232r.flush()

        return True

    # TODO: Remove backwards compatibility in a future rev.
    def _old_readNonce(self):
        with self.ft232r.lock:
            if self.asleep: self.wake()
            self.jtag.tap.reset()
            self.jtag.instruction(USER_INSTRUCTION)
            self.jtag.shift_ir()
            self.asleep = False

            # Sync to the beginning of a nonce.
            # The MSB is a VALID flag. If 0, data is invalid (queue empty).
            # The next 4-bits indicate which byte of the nonce we got.
            # 1111 is LSB, and then 0111, 0011, 0001.
            byte = None
            while True:
                byte = self._readByte()

                # check data valid bit:
                if byte < 0x1000:
                    self.jtag.tap.reset()
                    return None

                #self.logger.reportDebug("%d: Read: %04x" % (self.id, byte))

                # check byte counter:
                if (byte & 0xF00) == 0xF00:
                    break

            # We now have the first byte
            nonce = byte & 0xFF
            count = 1
            #self.logger.reportDebug("%d: Potential nonce, reading the rest..." % self.id)
            while True:
                byte = self._readByte()

                #self.logger.reportDebug("%d: Read: %04x" % (self.id, byte))

                # check data valid bit:
                if byte < 0x1000:
                    self.jtag.tap.reset()
                    return None

                # check byte counter:
                if (byte & 0xF00) >> 8 != (0xF >> count):
                    self.jtag.tap.reset()
                    return None

                nonce |= (byte & 0xFF) << (count * 8)
                count += 1

                if (byte & 0xF00) == 0x100:
                    break

            self.jtag.tap.reset()

        #self.logger.reportDebug("%d: Nonce completely read: %08x" % (self.id, nonce))

        return nonce

    # TODO: This may not actually clear the queue, but should be correct most of the time.
    def _old_clearQueue(self):
        with self.ft232r.lock:
            if self.asleep: self.wake()
            self.jtag.tap.reset()
            self.jtag.instruction(USER_INSTRUCTION)
            self.jtag.shift_ir()
            self.asleep = False

            self.logger.reportDebug("%d: Clearing queue..." % self.id)
            while True:
                if self._readByte() < 0x1000:
                    break
            self.jtag.tap.reset()

        self.logger.reportDebug("%d: Queue cleared" % self.id)

    def _old_writeJob(self, job):
        # We need the 256-bit midstate, and 12 bytes from data.
        # The first 64 bytes of data are already hashed (hence midstate),
        # so we skip that. Of the last 64 bytes, 52 bytes are constant and
        # not needed by the FPGA.

        start_time = time.time()

        midstate = hexstr2array(job.midstate)
        data = hexstr2array(job.data)[64:64 + 12]

        # Job's hex strings are LSB first, and the FPGA wants them MSB first.
        midstate.reverse()
        data.reverse()

        with self.ft232r.lock:
            #self.logger.reportDebug("%d: Loading job data..." % self.id)

            if self.asleep: self.wake()
            self.jtag.tap.reset()
            self.jtag.instruction(USER_INSTRUCTION)
            self.jtag.shift_ir()

            data = midstate + data + [0]

            for i in range(len(data)):
                x = data[i]

                if i != 0:
                    x = 0x100 | x

                self.jtag.shift_dr(int2bits(x, 13))

            self.jtag.tap.reset()

            self.ft232r.flush()

        #self.logger.reportDebug("%d: Job data loaded in %.3f seconds" % (self.id, time.time() - start_time))
        self.logger.reportDebug("%d: Job data loaded" % self.id)

    def _readNonce(self):
        nonce = self._readRegister(0xE)

        if nonce == 0xFFFFFFFF:
            return None
        return nonce

    def _clearQueue(self):
        self.logger.reportDebug("%d: Clearing queue..." % self.id)
        while True:
            if self.readNonce() is None:
                break

        self.logger.reportDebug("%d: Queue cleared" % self.id)

    def _writeJob(self, job):
        # We need the 256-bit midstate, and 12 bytes from data.
        # The first 64 bytes of data are already hashed (hence midstate),
        # so we skip that. Of the last 64 bytes, 52 bytes are constant and
        # not needed by the FPGA.

        start_time = time.time()

        # blakecoin DEBUG
        #midstatehex = ''
        #proc = subprocess.Popen(['./midstate',job.data],stdout=subprocess.PIPE)	# OK for linux and windows
        #while True:
        #	msline = proc.stdout.readline()
        #	if (msline != ''):
        #		midstatehex = msline.rstrip()
        #	else:
        #		break

        #print "\nmidstatehex=", midstatehex
        #midstate1 = hexstr2array(midstatehex)
        #print (midstate1)

        midstate_blake8 = BLAKE(256).midstate(
            struct.pack("<16I",
                        *struct.unpack(">16I",
                                       job.data.decode('hex')[:64])))
        # print('\nmidstate_blake8 %s' % (hexlify(midstate_blake8).decode()))
        midstate_blake8_swap = struct.pack(
            "<8I", *struct.unpack(">8I", midstate_blake8))
        # print('\nmidswap_blake8  %s' % (hexlify(midstate_blake8_swap).decode()))

        # midstate = hexstr2array(job.midstate)		// ORIGINAL
        midstate = hexstr2array(hexlify(midstate_blake8_swap).decode())
        # print (midstate)
        data = hexstr2array(job.data)[64:64 + 12]
        data = midstate + data

        words = []

        for i in range(11):
            word = data[i * 4] | (data[i * 4 + 1] << 8) | (
                data[i * 4 + 2] << 16) | (data[i * 4 + 3] << 24)
            words.append(word)

        if not self._burstWrite(1, words):
            self.logger.reportDebug(
                "%d: ERROR: Loading job data failed; readback failure" %
                self.id)
            return

        self.logger.reportDebug("%d: Job data loaded in %.3f seconds" %
                                (self.id, time.time() - start_time))
        #self.logger.reportDebug("%d: Job data loaded" % self.id)

    # Read the FPGA's current clock speed, in MHz
    # NOTE: This is currently just what we've written into the clock speed
    # register, so it does NOT take into account hard limits in the firmware.
    def readClockSpeed(self):
        if self.firmware_rev == 0:
            return None

        frequency = self._readRegister(0xD)

        return frequency

    # Set the FPGA's clock speed, in MHz
    # NOTE: Be VERY careful not to set the clock speed too high!!!
    def setClockSpeed(self, speed):
        if self.firmware_rev == 0:
            return False

        return self._writeRegister(0xD, speed)

    def readNonce(self):
        if self.firmware_rev == 0:
            return self._old_readNonce()
        else:
            return self._readNonce()

    def clearQueue(self):
        if self.firmware_rev == 0:
            return self._old_clearQueue()
        else:
            return self._clearQueue()

    def writeJob(self, job):
        if self.firmware_rev == 0:
            return self._old_writeJob(job)
        else:
            return self._writeJob(job)

    def getJob(self):
        try:
            #logger.reportDebug("%d: Checking for new job..." % fpga.id)
            return self.jobqueue.get(False)
        except Empty:
            return None

    def putJob(self, work):
        job = Object()
        # Commented out midstate as pool does not supply it, which causes getwork error
        # (its not needed as midstate is calculated locally)
        # job.midstate = work['midstate']
        job.data = work['data']
        job.target = work['target']
        self.jobqueue.put(job)
        #self.logger.reportDebug("%d: jobqueue loaded (%d)" % (fpga.id, self.jobqueue.qsize()))

    def sleep(self):
        with self.ft232r.lock:
            self.logger.reportDebug("%d: Going to sleep..." % self.id)

            self.jtag.tap.reset()
            self.jtag.instruction(JSHUTDOWN)
            self.jtag.shift_ir()
            self.jtag.runtest(24)
            self.jtag.tap.reset()

            self.ft232r.flush()

        self.asleep = True

    def wake(self):
        with self.ft232r.lock:
            self.logger.reportDebug("%d: Waking up..." % self.id)

            self.jtag.tap.reset()
            self.jtag.instruction(JSTART)
            self.jtag.shift_ir()
            self.jtag.runtest(24)
            self.jtag.instruction(BYPASS)
            self.jtag.shift_ir()
            self.jtag.instruction(BYPASS)
            self.jtag.shift_ir()
            self.jtag.instruction(JSTART)
            self.jtag.shift_ir()
            self.jtag.runtest(24)
            self.jtag.tap.reset()

            self.ft232r.flush()

        self.asleep = False

    @staticmethod
    def programBitstream(ft232r, jtag, logger, processed_bitstream):
        with ft232r.lock:
            # Select the device
            jtag.reset()
            jtag.part(jtag.deviceCount - 1)

            jtag.instruction(BYPASS)
            jtag.shift_ir()

            jtag.instruction(JPROGRAM)
            jtag.shift_ir()

            jtag.instruction(CFG_IN)
            jtag.shift_ir()

            # Clock TCK for 10000 cycles
            jtag.runtest(10000)

            jtag.instruction(CFG_IN)
            jtag.shift_ir()
            jtag.shift_dr([0] * 32)
            jtag.instruction(CFG_IN)
            jtag.shift_ir()

            ft232r.flush()

            # Load bitstream into CFG_IN
            jtag.load_bitstream(processed_bitstream, logger.updateProgress)

            jtag.instruction(JSTART)
            jtag.shift_ir()

            # Let the device start
            jtag.runtest(24)

            jtag.instruction(BYPASS)
            jtag.shift_ir()
            jtag.instruction(BYPASS)
            jtag.shift_ir()

            jtag.instruction(JSTART)
            jtag.shift_ir()

            jtag.runtest(24)

            # Check done pin
            #jtag.instruction(BYPASS)
            # TODO: Figure this part out. & 0x20 should equal 0x20 to check the DONE pin ... ???
            #print jtag.read_ir() # & 0x20 == 0x21
            #jtag.instruction(BYPASS)
            #jtag.shift_ir()
            #jtag.shift_dr([0])

            ft232r.flush()