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