From 2dc1f0079461e6d7ffd52916dcc68936b352aaf4 Mon Sep 17 00:00:00 2001 From: Qiang Du <QDu@lbl.gov> Date: Fri, 9 Jan 2015 15:55:28 -0800 Subject: [PATCH] Fix flash writting scripts, enable sector erasing. Flash programming partially works --- tools/lib-multiboot/eb/eb.py | 28 ++-- tools/lib-multiboot/eb/etherbone.py | 206 +-------------------------- tools/lib-multiboot/flash_m25p.py | 27 +++- tools/lib-multiboot/mbtest.py | 35 +++-- tools/lib-multiboot/xil_multiboot.py | 30 ++-- 5 files changed, 81 insertions(+), 245 deletions(-) diff --git a/tools/lib-multiboot/eb/eb.py b/tools/lib-multiboot/eb/eb.py index ca05910..76b8643 100644 --- a/tools/lib-multiboot/eb/eb.py +++ b/tools/lib-multiboot/eb/eb.py @@ -16,6 +16,7 @@ import etherbone as eb import sys +import logging class EB: """ access a Etherbone device. """ @@ -40,27 +41,24 @@ class EB: self.socket.close() def write(self, addr, val): + logging.debug('write: 0x%08x'% val) self.device.write(addr, val) def writemregs(self, addr, dlist): - curr_addr = addr - self.cycle = eb.Cycle(self.device, 0, 0) - self.cycle.__enter__() - for i in dlist: - curr_addr += i - self.cycle.write(curr_addr, i) - self.cycle.close() + with eb.Cycle(self.device, 0, 0) as cycle: + for v in dlist: + logging.debug('mwrite: 0x%08x'% v) + cycle.write(addr, v) 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): - curr_addr = addr dlist = [] - self.cycle = eb.Cycle(self.device, 0, 0) - self.cycle.__enter__() - for i in xrange(nrregs): - curr_addr += i - dlist[i] = self.cycle.read(curr_addr) - self.cycle.close() + with eb.Cycle(self.device, 0, 0) as cycle: + for i in nrregs: + dlist.append(cycle.read(addr, v)) + logging.debug('mread: 0x%08x'% dlist[i]) return dlist diff --git a/tools/lib-multiboot/eb/etherbone.py b/tools/lib-multiboot/eb/etherbone.py index 5ecb3e1..16da571 100644 --- a/tools/lib-multiboot/eb/etherbone.py +++ b/tools/lib-multiboot/eb/etherbone.py @@ -37,19 +37,6 @@ eb_device_t = c_uint16 eb_cycle_t = c_uint16 # 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 = { 0: 'EB_OK', -1: 'EB_FAIL', @@ -113,7 +100,7 @@ class Socket(): def __enter__(self): status = self.open(self.port, self.widths, self.socket) if (status != 0): - print 'error opening device, code ', eb_err_code[status] + raise IOError('error opening device, code ', eb_err_code[status]) return self def __exit__(self, type, value, traceback): @@ -155,20 +142,20 @@ class Device(): def __enter__(self): status = self.open(self.socket, self.address, self.widths) if (status != 0): - print 'error opening device, code ', eb_err_code[status] + raise IOError('error opening device, code ', eb_err_code[status]) return self def __exit__(self, type, value, traceback): self.close() - def open(self, socket, ip_port, widths): + def open(self, socket, ip_port, widths, retry=3): """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 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): """close a remote Etherbone device @@ -185,7 +172,7 @@ class 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 Semantically equivalent to cycle_open, cycle_read, cycle_close. @@ -195,19 +182,15 @@ class Device(): The user parameter is passed through uninspected to the callback. """ data = eb_data_t() - user_data = None - callback = None lib.eb_device_read(self.device, address, self.data_format, byref(data), user_data, callback) return data.value - def write(self, address, data): + def write(self, address, data, user_data = None, callback = None): """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. """ - user_data = None - callback = None return lib.eb_device_write(self.device, address, self.data_format, data, user_data, callback) class Cycle(): @@ -226,7 +209,7 @@ class Cycle(): def __enter__(self): status = self.open(self.dev_handle, self.user_data, self.callback) if (status != 0): - print 'error opening device, code ', eb_err_code[status] + raise IOError('error opening device, code ', eb_err_code[status]) return self def __exit__(self, type, value, traceback): @@ -265,178 +248,3 @@ class Cycle(): If the device was read-only, the operation is discarded. """ 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) diff --git a/tools/lib-multiboot/flash_m25p.py b/tools/lib-multiboot/flash_m25p.py index 7d25f0a..d247882 100644 --- a/tools/lib-multiboot/flash_m25p.py +++ b/tools/lib-multiboot/flash_m25p.py @@ -20,6 +20,7 @@ # import sys +import logging import struct sys.path.append("eb") from eb import * @@ -56,7 +57,6 @@ class FlashM25P: # control byte, to be shifted left by 24 ctrl = ((cs << 3) | 0x4) | (nbytes-1) if (self.comm == ELMA_I2C_MULTIBOOT): - # Use appropriate command by type # # write - we send up to three data bytes in one FAR register write @@ -79,6 +79,7 @@ class FlashM25P: wval.append((ctrl << 24) | dat[i]) self.ebone.writemregs(self.mb_base+0x10, wval) + # Read the data and prepare the return value while (retval & (1 << 28) == 0): retval = self.ebone.read(self.mb_base+0x10) @@ -88,14 +89,23 @@ class FlashM25P: # 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] def write(self, addr, dat): - + logging.debug('Writting to address 0x%x' % addr) # write enable cmd self.spi_transfer(1,1,0x06) 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 self.spi_transfer(1,1,0x02) - # send address in reverse order self.spi_transfer(3,1,self.rev_addr(addr)) @@ -139,6 +149,7 @@ class FlashM25P: # It returns the values of the three consecutive flash registers packed into # one 24-bit data value in little-endian order def read(self, addr, nrbytes): + logging.debug('Reading from 0x%x...' % addr) ret = [] self.spi_transfer(1,1,0x0b) @@ -146,7 +157,7 @@ class FlashM25P: self.spi_transfer(3,1,self.rev_addr(addr)) self.spi_transfer(1,1,0) - # Read bytes in groups of three + # Read bytes in groups of one for i in range(nrbytes): ret.append(self.spi_transfer(1,1,0)) self.spi_transfer(1,0,0) @@ -155,12 +166,18 @@ class FlashM25P: # Send a sector erase command def serase(self, addr): + logging.debug('Sector Erasing from 0x%x'% addr) self.spi_transfer(1,1,0x06) self.spi_transfer(1,0,0) self.spi_transfer(1,1,0xD8) # send address in reverse order self.spi_transfer(3,1,self.rev_addr(addr)) 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 def berase(self): @@ -174,6 +191,7 @@ class FlashM25P: self.spi_transfer(1,1,0x05) ret = self.spi_transfer(1,1,0) self.spi_transfer(1,0,0) + logging.debug('Status Register: 0x%x'% ret) return ret def read_id(self): @@ -183,6 +201,7 @@ class FlashM25P: ret.append(self.spi_transfer(1,1,0)) self.spi_transfer(1,0,0) ret_pack = struct.pack('B'*20, *ret) + logging.debug('Flash ID: 0x'+ret_pack.encode('hex')) return ret_pack def rev_addr(self, addr): diff --git a/tools/lib-multiboot/mbtest.py b/tools/lib-multiboot/mbtest.py index 8201cc4..7cc3e4e 100644 --- a/tools/lib-multiboot/mbtest.py +++ b/tools/lib-multiboot/mbtest.py @@ -2,29 +2,42 @@ import os import sys import time import struct +import logging sys.path.append("eb") from eb 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' target = EB(ip) target.open() baseaddr = 0x20800 - mb = XilMultiboot(ETHERBONE, target, baseaddr, "foo_bit") - mb.write(0) + flash_address = 0x10 + flash_length = 0x1f + file_name = 'foo_bit' + mb = XilMultiboot(ETHERBONE, target, baseaddr, file_name) - status = mb.flash.rsr() - print 'Status:' + hex(status) + # read id + 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) - # read id - id = mb.flash.read_id() - print 'ID: 0x' + id.encode('hex') +# mb.flash.serase(flash_address) + + mb.flash.write(flash_address,range(0x15, 0x15 + flash_length)) + status = mb.flash.rsr() + logging.info('Status: 0x%x', status) - #mb.flash.serase(0x0) -# mb.flash.write(0x0,range(0,255)) - dat = mb.flash.read(0x0,0xff) + dat = mb.flash.read(flash_address, flash_length) dat_pack = struct.pack('B'*len(dat), *dat) print 'Flash: 0x' + dat_pack.encode('hex') + +if __name__ == "__main__": + main() diff --git a/tools/lib-multiboot/xil_multiboot.py b/tools/lib-multiboot/xil_multiboot.py index e4a2bbb..5ee09b5 100644 --- a/tools/lib-multiboot/xil_multiboot.py +++ b/tools/lib-multiboot/xil_multiboot.py @@ -19,6 +19,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # +import logging import sys sys.path.append("eb") from eb import * @@ -64,8 +65,7 @@ class XilMultiboot: progress = (float(actual)/float(total)) * 100 if (progress > 100.00): progress = 100.00 - sys.stdout.write("\r %3.2f%% (0x%06x)" % (progress, ca)) - sys.stdout.flush() + logging.info("\r %3.2f%% (0x%06x)" % (progress, ca)) # # Read from flash @@ -76,14 +76,13 @@ class XilMultiboot: f = open(fname,'wb') # 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 = [] for i in range(sa, ea, 256): dat += self.flash.read(i, 256) self._progress(sa, ea, i) i += 256 self._progress(sa, ea, i) - print("") dat = ''.join(map(chr,dat)) f.write(dat) f.close() @@ -93,7 +92,7 @@ class XilMultiboot: # 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 f = open(self.bitstream,'rb') @@ -108,7 +107,7 @@ class XilMultiboot: # Erase on sector boundary if not (addr % 0x10000): - print 'erase sector boundary' + logging.info('erase sector boundary') self.flash.serase(addr) while (self.flash.rsr() & 0x01): pass @@ -122,18 +121,17 @@ class XilMultiboot: addr += 256 self._progress(sta, end, addr) - print("") # Close file handle f.close() - print("DONE!") + logging.info("DONE!") # # Start IPROG sequence # def iprog(self, addr): 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_MBBAR_OFS, addr | (0x0b << 24)) self.elma.write(self.slot, self.mb_base+MB_CR_OFS, 0x10000) @@ -150,13 +148,13 @@ class XilMultiboot: while (1): try: if (time.time() >= t1): - print("Timeout, IPROG unsuccessful!") + logging.error("Timeout, IPROG unsuccessful!") break 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 else: - print("IPROG successful!") + logging.info("IPROG successful!") break except NAckError: continue @@ -165,7 +163,7 @@ class XilMultiboot: # Sequence to read FPGA configuration register # def rdcfgreg(self): - print("Press 'q' to end config reg readout") + logging.info("Press 'q' to end config reg readout") while 1: try: reg = raw_input('Address (hex): ') @@ -176,13 +174,13 @@ class XilMultiboot: 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) if (val & (1 << 16)): - print("REG(0x%02X) = 0x%04X" % (reg, val & 0xffff)) + logging.info("REG(0x%02X) = 0x%04X" % (reg, val & 0xffff)) else: - print("CFGREGIMG invalid!") + logging.error("CFGREGIMG invalid!") except ValueError: if (reg == 'q'): 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 -- GitLab