Commit 2dc1f007 authored by Qiang Du's avatar Qiang Du

Fix flash writting scripts, enable sector erasing.

Flash programming partially works
parent 077d77d1
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
import etherbone as eb import etherbone as eb
import sys import sys
import logging
class EB: class EB:
""" access a Etherbone device. """ """ access a Etherbone device. """
...@@ -40,27 +41,24 @@ class EB: ...@@ -40,27 +41,24 @@ class EB:
self.socket.close() self.socket.close()
def write(self, addr, val): def write(self, addr, val):
logging.debug('write: 0x%08x'% val)
self.device.write(addr, val) self.device.write(addr, val)
def writemregs(self, addr, dlist): def writemregs(self, addr, dlist):
curr_addr = addr with eb.Cycle(self.device, 0, 0) as cycle:
self.cycle = eb.Cycle(self.device, 0, 0) for v in dlist:
self.cycle.__enter__() logging.debug('mwrite: 0x%08x'% v)
for i in dlist: cycle.write(addr, v)
curr_addr += i
self.cycle.write(curr_addr, i)
self.cycle.close()
def read(self, addr): def read(self, addr):
return self.device.read(addr) val = self.device.read(addr)
logging.debug('read: 0x%08x'% val)
return val
def readmregs(self, addr, nrregs): def readmregs(self, addr, nrregs):
curr_addr = addr
dlist = [] dlist = []
self.cycle = eb.Cycle(self.device, 0, 0) with eb.Cycle(self.device, 0, 0) as cycle:
self.cycle.__enter__() for i in nrregs:
for i in xrange(nrregs): dlist.append(cycle.read(addr, v))
curr_addr += i logging.debug('mread: 0x%08x'% dlist[i])
dlist[i] = self.cycle.read(curr_addr)
self.cycle.close()
return dlist return dlist
...@@ -37,19 +37,6 @@ eb_device_t = c_uint16 ...@@ -37,19 +37,6 @@ eb_device_t = c_uint16
eb_cycle_t = c_uint16 eb_cycle_t = c_uint16
# status codes # status codes
eb_status_t = c_int
( EB_OK,
EB_FAIL,
EB_ABORT,
EB_ADDRESS,
EB_OVERFLOW,
EB_ENDIAN,
EB_BUSY,
EB_TIMEOUT,
EB_OOM,
EB_ABI,
EB_SEGFAULT) = range(0,-11,-1)
eb_err_code = { eb_err_code = {
0: 'EB_OK', 0: 'EB_OK',
-1: 'EB_FAIL', -1: 'EB_FAIL',
...@@ -113,7 +100,7 @@ class Socket(): ...@@ -113,7 +100,7 @@ class Socket():
def __enter__(self): def __enter__(self):
status = self.open(self.port, self.widths, self.socket) status = self.open(self.port, self.widths, self.socket)
if (status != 0): if (status != 0):
print 'error opening device, code ', eb_err_code[status] raise IOError('error opening device, code ', eb_err_code[status])
return self return self
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
...@@ -155,20 +142,20 @@ class Device(): ...@@ -155,20 +142,20 @@ class Device():
def __enter__(self): def __enter__(self):
status = self.open(self.socket, self.address, self.widths) status = self.open(self.socket, self.address, self.widths)
if (status != 0): if (status != 0):
print 'error opening device, code ', eb_err_code[status] raise IOError('error opening device, code ', eb_err_code[status])
return self return self
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
self.close() self.close()
def open(self, socket, ip_port, widths): def open(self, socket, ip_port, widths, retry=3):
"""open a remote Etherbone device """open a remote Etherbone device
This resolves the address and performs Etherbone end-point discovery. This resolves the address and performs Etherbone end-point discovery.
From the mask of proposed bus widths, one will be selected. From the mask of proposed bus widths, one will be selected.
The default port is taken as 0xEBD0. The default port is taken as 0xEBD0.
""" """
return lib.eb_device_open(socket, ip_port, widths, 3, byref(self.device)) return lib.eb_device_open(socket, ip_port, widths, retry, byref(self.device))
def close(self): def close(self):
"""close a remote Etherbone device """close a remote Etherbone device
...@@ -185,7 +172,7 @@ class Device(): ...@@ -185,7 +172,7 @@ class Device():
""" """
return lib.eb_device_width(self.device) return lib.eb_device_width(self.device)
def read(self, address): def read(self, address, user_data = None, callback = None):
"""perform a single-read wishbone cycle """perform a single-read wishbone cycle
Semantically equivalent to cycle_open, cycle_read, cycle_close. Semantically equivalent to cycle_open, cycle_read, cycle_close.
...@@ -195,19 +182,15 @@ class Device(): ...@@ -195,19 +182,15 @@ class Device():
The user parameter is passed through uninspected to the callback. The user parameter is passed through uninspected to the callback.
""" """
data = eb_data_t() data = eb_data_t()
user_data = None
callback = None
lib.eb_device_read(self.device, address, self.data_format, byref(data), user_data, callback) lib.eb_device_read(self.device, address, self.data_format, byref(data), user_data, callback)
return data.value return data.value
def write(self, address, data): def write(self, address, data, user_data = None, callback = None):
"""perform a single-write wishbone cycle """perform a single-write wishbone cycle
Semantically equivalent to cycle_open, cycle_write, cycle_close. Semantically equivalent to cycle_open, cycle_write, cycle_close.
data is written to the given address on the remote device. data is written to the given address on the remote device.
""" """
user_data = None
callback = None
return lib.eb_device_write(self.device, address, self.data_format, data, user_data, callback) return lib.eb_device_write(self.device, address, self.data_format, data, user_data, callback)
class Cycle(): class Cycle():
...@@ -226,7 +209,7 @@ class Cycle(): ...@@ -226,7 +209,7 @@ class Cycle():
def __enter__(self): def __enter__(self):
status = self.open(self.dev_handle, self.user_data, self.callback) status = self.open(self.dev_handle, self.user_data, self.callback)
if (status != 0): if (status != 0):
print 'error opening device, code ', eb_err_code[status] raise IOError('error opening device, code ', eb_err_code[status])
return self return self
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
...@@ -265,178 +248,3 @@ class Cycle(): ...@@ -265,178 +248,3 @@ class Cycle():
If the device was read-only, the operation is discarded. If the device was read-only, the operation is discarded.
""" """
return lib.eb_cycle_write(self.cycle, address, self.data_format, data) return lib.eb_cycle_write(self.cycle, address, self.data_format, data)
#
# C99 API
#
def eb_socket_open(port, widths, socket):
"""
Open an Etherbone socket for communicating with remote devices.
The port parameter is optional; 0 lets the operating system choose.
After opening the socket, poll must be hooked into an event loop.
Return codes:
OK - successfully open the socket port
FAIL - operating system forbids access
BUSY - specified port is in use (only possible if port != 0)
"""
return lib.eb_socket_open(EB_ABI_CODE, port, widths, socket)
def eb_socket_close(socket):
"""
Close the Etherbone socket.
Any use of the socket after successful close will probably segfault!
Return codes:
OK - successfully closed the socket and freed memory
BUSY - there are open devices on this socket
"""
return lib.eb_socket_close(socket)
def eb_socket_poll(socket):
"""
Poll the Etherbone socket for activity.
This function must be called regularly to receive incoming packets.
Either call poll very often or hook a read listener on its descriptor.
Callback functions are only executed from within the poll function.
Return codes:
OK - poll complete; no further packets to process
FAIL - socket error (probably closed)
"""
return lib.eb_socket_poll(socket)
def eb_socket_block(socket, timeout_us):
"""
Block until the socket is ready to be polled.
This function is useful if your program has no event loop of its own.
It returns the time spent while waiting.
"""
return lib.eb_socket_block(socket, timeout_us)
def eb_socket_descriptor(socket):
"""
Access the underlying file descriptor of the Etherbone socket.
THIS MUST NEVER BE READ, WRITTEN, CLOSED, OR MODIFIED IN ANY WAY!
It may be used to watch for read readiness to call poll.
"""
return lib.eb_socket_descriptor(socket)
def eb_socket_attach(socket, handler):
"""
Add a device to the virtual bus.
This handler receives all reads and writes to the specified address.
NOTE: the address range [0x0, 0x7fff) is reserved for internal use.
Return codes:
OK - the handler has been installed
FAIL - out of memory
ADDRESS - the specified address range overlaps an existing device.
"""
return lib.eb_socket_attach(socket, handler)
def eb_socket_detach(socket, address):
"""
Detach the device from the virtual bus.
Return codes:
OK - the devices has be removed
FAIL - there is no device at the specified address.
"""
return lib.eb_socket_detach(socket, address)
def eb_device_open(socket, ip_port, proposed_widths, result):
"""
Open a remote Etherbone device.
This resolves the address and performs Etherbone end-point discovery.
From the mask of proposed bus widths, one will be selected.
The default port is taken as 0xEBD0.
Return codes:
OK - the remote etherbone device is ready
FAIL - the remote address did not identify itself as etherbone conformant
ADDRESS - the network address could not be parsed
ABORT - could not negotiate an acceptable data bus width
"""
return lib.eb_device_open(socket, ip_port, proposed_widths, result)
def eb_device_width(device):
"""
Recover the negotiated data width of the target device.
"""
return lib.eb_device_width(device)
def eb_device_close(device):
"""
Close a remote Etherbone device.
Return codes:
OK - associated memory has been freed
BUSY - there are outstanding wishbone cycles on this device
"""
return lib.eb_device_close(device)
def eb_device_socket(device):
"""Access the socket backing this device
"""
return lib.eb_device_socket(device)
def eb_cycle_close(cycle):
"""
End a wishbone cycle.
This places the complete cycle at end of the device''s send queue.
"""
return lib.eb_cycle_close(cycle)
def eb_cycle_device(cycle):
"""Access the device targetted by this cycle
"""
return eb_cycle_device(cycle)
def eb_cycle_read(cycle, address):
"""
Prepare a wishbone read phase.
The given address is read from the remote device.
"""
return lib.eb_cycle_read(cycle, address)
def eb_cycle_write(cycle, data):
"""
Perform a wishbone write phase.
data is written to the current cursor on the remote device.
If the device was read-only, the operation is discarded.
"""
return lib.eb_cycle_write(cycle, data)
def eb_device_read(device, address, userdata, cb):
"""
Perform a single-read wishbone cycle.
Semantically equivalent to cycle_open, cycle_read, cycle_close.
The given address is read on the remote device.
The callback cb(user, status, data) is invoked with the result.
The user parameter is passed through uninspected to the callback.
Status codes:
OK - the operation completed successfully
FAIL - the operation failed due to an wishbone ERR_O signal
ABORT - an earlier operation failed and this operation was thus aborted
"""
return lib.eb_device_read(device, address, userdata, cb)
def eb_device_write(device, address, data):
"""
Perform a single-write wishbone cycle.
Semantically equivalent to cycle_open, cycle_write, cycle_close.
data is written to the given address on the remote device.
"""
return lib.eb_device_write(device, address, data)
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
# #
import sys import sys
import logging
import struct import struct
sys.path.append("eb") sys.path.append("eb")
from eb import * from eb import *
...@@ -56,7 +57,6 @@ class FlashM25P: ...@@ -56,7 +57,6 @@ class FlashM25P:
# control byte, to be shifted left by 24 # control byte, to be shifted left by 24
ctrl = ((cs << 3) | 0x4) | (nbytes-1) ctrl = ((cs << 3) | 0x4) | (nbytes-1)
if (self.comm == ELMA_I2C_MULTIBOOT): if (self.comm == ELMA_I2C_MULTIBOOT):
# Use appropriate command by type # Use appropriate command by type
# #
# write - we send up to three data bytes in one FAR register write # write - we send up to three data bytes in one FAR register write
...@@ -79,6 +79,7 @@ class FlashM25P: ...@@ -79,6 +79,7 @@ class FlashM25P:
wval.append((ctrl << 24) | dat[i]) wval.append((ctrl << 24) | dat[i])
self.ebone.writemregs(self.mb_base+0x10, wval) self.ebone.writemregs(self.mb_base+0x10, wval)
# Read the data and prepare the return value
while (retval & (1 << 28) == 0): while (retval & (1 << 28) == 0):
retval = self.ebone.read(self.mb_base+0x10) retval = self.ebone.read(self.mb_base+0x10)
...@@ -88,14 +89,23 @@ class FlashM25P: ...@@ -88,14 +89,23 @@ class FlashM25P:
# and sends the commands to the flash chip. You can follow the logic of this # and sends the commands to the flash chip. You can follow the logic of this
# function by looking at the sequence of the write command in [1] # function by looking at the sequence of the write command in [1]
def write(self, addr, dat): def write(self, addr, dat):
logging.debug('Writting to address 0x%x' % addr)
# write enable cmd # write enable cmd
self.spi_transfer(1,1,0x06) self.spi_transfer(1,1,0x06)
self.spi_transfer(1,0,0) self.spi_transfer(1,0,0)
# check status (WIP, WEL) bits
status = 0
retry = 3
while (status != 0x2):
logging.debug('Flash not ready, status: 0x%x' % status)
if (retry <= 0):
raise IOError('Error writing, status not vaild: 0x%x'% status)
logging.debug('retry = %d' % retry)
retry -= 1
status = self.rsr()
# write page cmd # write page cmd
self.spi_transfer(1,1,0x02) self.spi_transfer(1,1,0x02)
# send address in reverse order # send address in reverse order
self.spi_transfer(3,1,self.rev_addr(addr)) self.spi_transfer(3,1,self.rev_addr(addr))
...@@ -139,6 +149,7 @@ class FlashM25P: ...@@ -139,6 +149,7 @@ class FlashM25P:
# It returns the values of the three consecutive flash registers packed into # It returns the values of the three consecutive flash registers packed into
# one 24-bit data value in little-endian order # one 24-bit data value in little-endian order
def read(self, addr, nrbytes): def read(self, addr, nrbytes):
logging.debug('Reading from 0x%x...' % addr)
ret = [] ret = []
self.spi_transfer(1,1,0x0b) self.spi_transfer(1,1,0x0b)
...@@ -146,7 +157,7 @@ class FlashM25P: ...@@ -146,7 +157,7 @@ class FlashM25P:
self.spi_transfer(3,1,self.rev_addr(addr)) self.spi_transfer(3,1,self.rev_addr(addr))
self.spi_transfer(1,1,0) self.spi_transfer(1,1,0)
# Read bytes in groups of three # Read bytes in groups of one
for i in range(nrbytes): for i in range(nrbytes):
ret.append(self.spi_transfer(1,1,0)) ret.append(self.spi_transfer(1,1,0))
self.spi_transfer(1,0,0) self.spi_transfer(1,0,0)
...@@ -155,12 +166,18 @@ class FlashM25P: ...@@ -155,12 +166,18 @@ class FlashM25P:
# Send a sector erase command # Send a sector erase command
def serase(self, addr): def serase(self, addr):
logging.debug('Sector Erasing from 0x%x'% addr)
self.spi_transfer(1,1,0x06) self.spi_transfer(1,1,0x06)
self.spi_transfer(1,0,0) self.spi_transfer(1,0,0)
self.spi_transfer(1,1,0xD8) self.spi_transfer(1,1,0xD8)
# send address in reverse order # send address in reverse order
self.spi_transfer(3,1,self.rev_addr(addr)) self.spi_transfer(3,1,self.rev_addr(addr))
self.spi_transfer(1,0,0) self.spi_transfer(1,0,0)
# wait until finish
status = 1
while (status != 0x0):
logging.debug('Sector erasing...')
status = self.rsr()
# Send a block erase command # Send a block erase command
def berase(self): def berase(self):
...@@ -174,6 +191,7 @@ class FlashM25P: ...@@ -174,6 +191,7 @@ class FlashM25P:
self.spi_transfer(1,1,0x05) self.spi_transfer(1,1,0x05)
ret = self.spi_transfer(1,1,0) ret = self.spi_transfer(1,1,0)
self.spi_transfer(1,0,0) self.spi_transfer(1,0,0)
logging.debug('Status Register: 0x%x'% ret)
return ret return ret
def read_id(self): def read_id(self):
...@@ -183,6 +201,7 @@ class FlashM25P: ...@@ -183,6 +201,7 @@ class FlashM25P:
ret.append(self.spi_transfer(1,1,0)) ret.append(self.spi_transfer(1,1,0))
self.spi_transfer(1,0,0) self.spi_transfer(1,0,0)
ret_pack = struct.pack('B'*20, *ret) ret_pack = struct.pack('B'*20, *ret)
logging.debug('Flash ID: 0x'+ret_pack.encode('hex'))
return ret_pack return ret_pack
def rev_addr(self, addr): def rev_addr(self, addr):
......
...@@ -2,29 +2,42 @@ import os ...@@ -2,29 +2,42 @@ import os
import sys import sys
import time import time
import struct import struct
import logging
sys.path.append("eb") sys.path.append("eb")
from eb import * from eb import *
from xil_multiboot import * from xil_multiboot import *
if __name__ == "__main__": def main():
log_level = logging.DEBUG
log_level = logging.INFO
logging.basicConfig(level=log_level)
ip = 'rflab2.lbl.gov' ip = 'rflab2.lbl.gov'
target = EB(ip) target = EB(ip)
target.open() target.open()
baseaddr = 0x20800 baseaddr = 0x20800
mb = XilMultiboot(ETHERBONE, target, baseaddr, "foo_bit") flash_address = 0x10
mb.write(0) flash_length = 0x1f
file_name = 'foo_bit'
mb = XilMultiboot(ETHERBONE, target, baseaddr, file_name)
status = mb.flash.rsr() # read id
print 'Status:' + hex(status) id = mb.flash.read_id()
logging.info('Flash ID: 0x' + id.encode('hex'))
#logging.info('Programming file %s'% file_name)
#mb.write(flash_address)
#mb.read(0,0xff) #mb.read(0,0xff)
# read id # mb.flash.serase(flash_address)
id = mb.flash.read_id()
print 'ID: 0x' + id.encode('hex') mb.flash.write(flash_address,range(0x15, 0x15 + flash_length))
status = mb.flash.rsr()
logging.info('Status: 0x%x', status)
#mb.flash.serase(0x0) dat = mb.flash.read(flash_address, flash_length)
# mb.flash.write(0x0,range(0,255))
dat = mb.flash.read(0x0,0xff)
dat_pack = struct.pack('B'*len(dat), *dat) dat_pack = struct.pack('B'*len(dat), *dat)
print 'Flash: 0x' + dat_pack.encode('hex') print 'Flash: 0x' + dat_pack.encode('hex')
if __name__ == "__main__":
main()
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# #
import logging
import sys import sys
sys.path.append("eb") sys.path.append("eb")
from eb import * from eb import *
...@@ -64,8 +65,7 @@ class XilMultiboot: ...@@ -64,8 +65,7 @@ class XilMultiboot:
progress = (float(actual)/float(total)) * 100 progress = (float(actual)/float(total)) * 100
if (progress > 100.00): if (progress > 100.00):
progress = 100.00 progress = 100.00
sys.stdout.write("\r %3.2f%% (0x%06x)" % (progress, ca)) logging.info("\r %3.2f%% (0x%06x)" % (progress, ca))
sys.stdout.flush()
# #
# Read from flash # Read from flash
...@@ -76,14 +76,13 @@ class XilMultiboot: ...@@ -76,14 +76,13 @@ class XilMultiboot:
f = open(fname,'wb') f = open(fname,'wb')
# Read the data and dump to file # Read the data and dump to file
print("Reading flash contents from board in slot %d" % self.slot) logging.info("Reading flash contents from board in slot %d" % self.slot)
dat = [] dat = []
for i in range(sa, ea, 256): for i in range(sa, ea, 256):
dat += self.flash.read(i, 256) dat += self.flash.read(i, 256)
self._progress(sa, ea, i) self._progress(sa, ea, i)
i += 256 i += 256
self._progress(sa, ea, i) self._progress(sa, ea, i)
print("")
dat = ''.join(map(chr,dat)) dat = ''.join(map(chr,dat))
f.write(dat) f.write(dat)
f.close() f.close()
...@@ -93,7 +92,7 @@ class XilMultiboot: ...@@ -93,7 +92,7 @@ class XilMultiboot:
# #
def write(self, addr): def write(self, addr):
print("Writing bitstream to board in slot %d" % self.slot) logging.info("Writing bitstream to board in slot %d" % self.slot)
# Ask for and open bitstream file # Ask for and open bitstream file
f = open(self.bitstream,'rb') f = open(self.bitstream,'rb')
...@@ -108,7 +107,7 @@ class XilMultiboot: ...@@ -108,7 +107,7 @@ class XilMultiboot:
# Erase on sector boundary # Erase on sector boundary
if not (addr % 0x10000): if not (addr % 0x10000):
print 'erase sector boundary' logging.info('erase sector boundary')
self.flash.serase(addr) self.flash.serase(addr)
while (self.flash.rsr() & 0x01): while (self.flash.rsr() & 0x01):
pass pass
...@@ -122,18 +121,17 @@ class XilMultiboot: ...@@ -122,18 +121,17 @@ class XilMultiboot:
addr += 256 addr += 256
self._progress(sta, end, addr) self._progress(sta, end, addr)
print("")
# Close file handle # Close file handle
f.close() f.close()
print("DONE!") logging.info("DONE!")
# #
# Start IPROG sequence # Start IPROG sequence
# #
def iprog(self, addr): def iprog(self, addr):
if (self.comm == ELMA_I2C_MULTIBOOT): if (self.comm == ELMA_I2C_MULTIBOOT):
print("Issuing IPROG command to board in slot %d..." % self.slot) logging.info("Issuing IPROG command to board in slot %d..." % self.slot)
self.elma.write(self.slot, self.mb_base+MB_GBBAR_OFS, 0x44 | (0x0b << 24)) self.elma.write(self.slot, self.mb_base+MB_GBBAR_OFS, 0x44 | (0x0b << 24))
self.elma.write(self.slot, self.mb_base+MB_MBBAR_OFS, addr | (0x0b << 24)) self.elma.write(self.slot, self.mb_base+MB_MBBAR_OFS, addr | (0x0b << 24))
self.elma.write(self.slot, self.mb_base+MB_CR_OFS, 0x10000) self.elma.write(self.slot, self.mb_base+MB_CR_OFS, 0x10000)
...@@ -150,13 +148,13 @@ class XilMultiboot: ...@@ -150,13 +148,13 @@ class XilMultiboot:
while (1): while (1):
try: try:
if (time.time() >= t1): if (time.time() >= t1):
print("Timeout, IPROG unsuccessful!") logging.error("Timeout, IPROG unsuccessful!")
break break
if ((self.elma.read(self.slot, 0x4) & 0xf0) == 0x00): if ((self.elma.read(self.slot, 0x4) & 0xf0) == 0x00):
print("IPROG unsuccessful, fallback to Golden bitstream occured!") logging.info("IPROG unsuccessful, fallback to Golden bitstream occured!")
break break
else: else:
print("IPROG successful!") logging.info("IPROG successful!")
break break
except NAckError: except NAckError:
continue continue
...@@ -165,7 +163,7 @@ class XilMultiboot: ...@@ -165,7 +163,7 @@ class XilMultiboot:
# Sequence to read FPGA configuration register # Sequence to read FPGA configuration register
# #
def rdcfgreg(self): def rdcfgreg(self):
print("Press 'q' to end config reg readout") logging.info("Press 'q' to end config reg readout")
while 1: while 1:
try: try:
reg = raw_input('Address (hex): ') reg = raw_input('Address (hex): ')
...@@ -176,13 +174,13 @@ class XilMultiboot: ...@@ -176,13 +174,13 @@ class XilMultiboot:
self.elma.write(self.slot, self.mb_base+MB_CR_OFS, (1 << 6) | reg) self.elma.write(self.slot, self.mb_base+MB_CR_OFS, (1 << 6) | reg)
val = self.elma.read(self.slot, self.mb_base+MB_SR_OFS) val = self.elma.read(self.slot, self.mb_base+MB_SR_OFS)
if (val & (1 << 16)): if (val & (1 << 16)):
print("REG(0x%02X) = 0x%04X" % (reg, val & 0xffff)) logging.info("REG(0x%02X) = 0x%04X" % (reg, val & 0xffff))
else: else:
print("CFGREGIMG invalid!") logging.error("CFGREGIMG invalid!")
except ValueError: except ValueError:
if (reg == 'q'): if (reg == 'q'):
break break
print("Please input a hex value in the range [0x00, 0x22] or 'q' to quit") logging.error("Please input a hex value in the range [0x00, 0x22] or 'q' to quit")
# #
# Set bitstream file path # Set bitstream file path
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment