Commit 1c09a3a4 authored by Theodor-Adrian Stana's avatar Theodor-Adrian Stana

Made multiboot bitstream write faster

Signed-off-by: Theodor-Adrian Stana's avatarTheodor Stana <t.stana@cern.ch>
parent b271de9b
conv-ttl-blo-gw @ bfa6c70e
Subproject commit a8a7895b66140533af2e580c9898c4f58dab747f
Subproject commit bfa6c70eec6fe363e70c99ffab3266e0a6bd92a5
......@@ -13,6 +13,8 @@
# dependencies:
#
# references:
# [1] M25P32 32Mb 3V NOR Serial Flash Embedded Memory
# http://cern.ch/go/z7pw
#===============================================================================
# GNU LESSER GENERAL PUBLIC LICENSE
#===============================================================================
......@@ -37,84 +39,132 @@ import sys
import time
sys.path.append("../vbcp")
from vbcp import *
from vbcpexcept import *
def spi_transfer(cs, dat):
# This function handles the OR-ing together of the data bytes and the control
# byte in FAR.
#
# Formatting of data bytes in the FAR register should be done outside this
# function.
def spi_transfer(nbytes, cs, dat):
retval = 0
wval = []
# control byte, to be shifted left by 24
ctrl = ((cs << 3) | 0x4) | (nbytes-1)
# Use appropriate command by type
#
# write - we send up to three data bytes in one FAR register write
# writemregs - we send up to 24 data bytes in eight FAR register writes
if isinstance(dat,int):
ctb.write(0x90, (((cs << 10) | 0x100) | dat))
ctb.write(0x90, (ctrl << 24) | dat)
else:
for i in xrange(len(dat)):
wval.append((((cs << 10) | 0x100) | dat[i]))
wval.append((ctrl << 24) | dat[i])
ctb.writemregs(0x90, wval)
while (retval & (1 << 9) == 0):
# Read the data and prepare the return value
while (retval & (1 << 28) == 0):
retval = ctb.read(0x90)
return retval & 0xFF
# while (retval & (1 << 9) == 0):
# retval = ctb.read(0x90)
# return retval & 0xFF
return retval & 0xFFFFFF
# This function is used to write data bytes to flash. It calls spi_transfer
# 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 flash_write(addr, dat):
spi_transfer(0,0)
spi_transfer(1,0x06)
spi_transfer(0,0)
spi_transfer(1,[0x02,(addr & 0xFF0000) >> 16,(addr & 0xFF00) >> 8, (addr & 0xFF)])
for i in xrange(0, len(dat), 4):
spi_transfer(1,[dat[i],dat[i+1],dat[i+2],dat[i+3]])
spi_transfer(0,0)
# spi_transfer(0,0)
# spi_transfer(1,0x06)
# spi_transfer(0,0)
# spi_transfer(1,0x02)
# spi_transfer(1,(addr & 0xFF0000) >> 16)
# spi_transfer(1,(addr & 0xFF00) >> 8)
# spi_transfer(1,(addr & 0xFF))
# for i in range(len(dat)):
# spi_transfer(1,dat[i])
# spi_transfer(0,0)
# write enable cmd
spi_transfer(1,1,0x06)
spi_transfer(1,0,0)
# write page cmd
spi_transfer(1,1,0x02)
# send address in reverse order
addr = ((addr & 0xff0000) >> 16) | (((addr & 0xff00) >> 8) << 8) | ((addr & 0xff) << 16)
spi_transfer(3,1,addr)
# Now, massage the data array into 3-byte commands sent into 32-bit register,
# in batches of eight registers (writemregs command).
i = 0
l = len(dat)
while (l):
wval = []
# If we have more than 24 bytes left in the data array, we can use the full
# writemregs
if (int(l/24)):
for j in xrange(0, 8):
wval.append((dat[(i+2)+3*j] << 16) | (dat[(i+1)+3*j] << 8) | dat[i+3*j])
spi_transfer(3, 1, wval)
i += 24;
l -= 24;
# When we're left to fewer than 24 bytes in the array, try to use one more
# writemregs with as many regs as possible
elif (int(l/3)):
for j in xrange(0, l/3):
wval.append((dat[(i+2)+3*j] << 16) | (dat[(i+1)+3*j] << 8) | dat[i+3*j])
spi_transfer(3,1,wval);
i += 3 * int(l/3)
l -= 3 * int(l/3)
# When we're down to less than three bytes, just use simple one-byte xfers
elif (l):
for j in xrange(0, l):
spi_transfer(1,1,dat[i])
i += 1
l -= 1
spi_transfer(1,0,0)
# This function is used to read a number of data bytes from the flash memory
# It returns the values of the three consecutive flash registers packed into
# one 24-bit data value in little-endian order
def flash_read(addr, nrbytes):
ret = []
spi_transfer(0,0)
#spi_transfer(1,0x0b)
#spi_transfer(1,(addr & 0xFF0000) >> 16)
#spi_transfer(1,(addr & 0xFF00) >> 8)
#spi_transfer(1,(addr & 0xFF))
spi_transfer(1,[0x0b, (addr & 0xFF0000) >> 16,(addr & 0xFF00) >> 8, (addr & 0xFF)])
spi_transfer(1,0)
spi_transfer(1,1,0x0b)
# send address in reverse order
addr = ((addr & 0xff0000) >> 16) | (((addr & 0xff00) >> 8) << 8) | ((addr & 0xff) << 16)
spi_transfer(3,1,addr)
spi_transfer(1,1,0)
# Read bytes in groups of three
for i in range(nrbytes):
ret.append(spi_transfer(1,0))
spi_transfer(0,0)
ret.append(spi_transfer(3,1,0))
spi_transfer(1,0,0)
return ret
# Send a sector erase command
def flash_serase(addr):
spi_transfer(0,0)
spi_transfer(1,0x06)
spi_transfer(0,0)
#spi_transfer(1,0xd8)
#spi_transfer(1,(addr & 0xFF0000) >> 16)
#spi_transfer(1,(addr & 0xFF00) >> 8)
#spi_transfer(1,(addr & 0xFF))
spi_transfer(1,[0xd8, (addr & 0xFF0000) >> 16,(addr & 0xFF00) >> 8, (addr & 0xFF)])
spi_transfer(0,0)
spi_transfer(1,1,0x06)
spi_transfer(1,0,0)
# send address in reverse order
addr = ((addr & 0xff0000) >> 16) | (((addr & 0xff00) >> 8) << 8) | ((addr & 0xff) << 16)
spi_transfer(3,1,addr)
spi_transfer(1,0,0)
# Send a block erase command
def flash_berase():
spi_transfer(0,0)
spi_transfer(1,0x06)
spi_transfer(0,0)
spi_transfer(1,0xc7)
spi_transfer(0,0)
spi_transfer(1,1,0x06)
spi_transfer(1,0,0)
spi_transfer(1,1,0xc7)
spi_transfer(1,0,0)
# Read status register command
def flash_rsr():
spi_transfer(0,0)
spi_transfer(1,0x05)
ret = spi_transfer(1,0)
spi_transfer(0,0)
spi_transfer(1,1,0x05)
ret = spi_transfer(1,1,0)
spi_transfer(1,0,0)
return ret
# MAIN "FUNCTION"
if __name__ == "__main__":
ip = "192.168.20.22" # raw_input("Crate IP? ")
user = "admin" # raw_input("Username? ")
......@@ -137,60 +187,51 @@ if __name__ == "__main__":
except:
print "Unexpected error: ", sys.exc_info()[0]
# Ask for multiboot address
while 1:
try:
multiboot_addr = raw_input("MultiBoot bitstream address (hex): ")
multiboot_addr = int(multiboot_addr, 16)
print '0x%06x' % multiboot_addr
break
except TypeError as e:
print "Please input a hexadecimal address!"
except KeyboardInterrupt:
sys.exit()
except:
print "Unexpected error: ", sys.exc_info()[0]
ts = time.time()
# Open VBCP connection
ctb.open_conn()
# Init counters
#wexcep_cnt = 0
#rexcep_cnt = 0
#mismatch_cnt = 0
# print "erasing"
#
# flash_berase()
# while (flash_rsr() & 0x01):
# pass
#
# print "done!"
# read from flash
print "BEFORE"
tr0 = time.time()
rd = flash_read(0x000000,256)
rd = flash_read(multiboot_addr,256)
tr1 = time.time()
rd = "".join(["0x%02X " % b for b in rd])
print rd
tr2 = time.time()
rd = flash_read(0x000100,256)
tr3 = time.time()
rd = "".join(["0x%02X " % b for b in rd])
rd = "".join(["0x%06X " % b for b in rd])
print rd
# print "ERASE"
# te1 = time.time()
# flash_serase(0x0010)
# while (flash_rsr() & 0x01):
# pass
# te2 = time.time()
# print "erase time: %2.6f" % (te2-te1)
# Ookay, now we start to write the flash
print "WRITE"
# Prepare time arrays, to calculate average time each operation takes
addr = 0
tdat = []
twr = []
twa = []
te = []
# Open bitstream file
f = open("conv.txt",'r')
# Each line in the input file contains the data for one page
for fdata in f:
print addr
data = []
# Erase on sector boundary
if not (addr % 0x10000):
print 'erase'
te1 = time.time()
......@@ -199,18 +240,26 @@ if __name__ == "__main__":
pass
te2 = time.time()
te.append(te2-te1)
#rd = flash_read(0x000100,256)
#rd = "".join(["0x%02X " % b for b in rd])
#print rd
# Read the hex values from the input file, which contains page data as
# strings of hex values, one hex value (i.e., one character) per nibble
try:
t1 = time.time()
for i in xrange(256):
data.append(int(fdata[0:2],16))
fdata = fdata[2:]
t2 = time.time()
# The last page of the flash will not be filled up with bytes, so
# data.append() above will throw a ValueError; catch this exception
# and use it to mark the end
except ValueError:
print "reached end"
break
# The finally block gets executed no matter what, so we use it to actually
# write data to the flash, one page at a time. After every write, the
# address is incremented to the next page address.
finally:
t3 = time.time()
flash_write(addr, data)
......@@ -232,6 +281,7 @@ if __name__ == "__main__":
# Close file handle
f.close()
# Phew! We're ready, so calculate the mean time it took for each process
print "DONE!"
print "read1 time: %2.6f" % float(tr1-tr0)
print "read2 time: %2.6f" % float(tr3-tr2)
......@@ -240,9 +290,35 @@ if __name__ == "__main__":
print "write time: %2.6f" % float(sum(twr)/len(twr)) #(t4-t3)
print "wait time: %2.6f" % float(sum(twa)/len(twa)) #(t5-t4)
# Finally, issue the reprogramming (IPROG) command
print "Issuing IPROG command..."
try:
ctb.write(0x88, 0x44 | (0x0b << 24))
ctb.write(0x8c, multiboot_addr | (0x0b << 24))
ctb.write(0x80, 0x10000)
ctb.write(0x80, 0x20000)
except NAckError:
pass
# Set timeout to be sixty seconds from now...
t0 = time.time()
t1 = t0 + 60
# and wait for the FPGA to gracefully respond, or die trying
while (1):
try:
if ((ctb.read(0x4) & 0xFFFF) == 0x0201):
print "IPROG successful!"
break
if (time.time() >= t1):
print "Timeout, IPROG unsuccessful!"
break
except NAckError:
continue
# Close VBCP connection and print final values
ctb.close_conn()
# Woohoo!
tf = time.time()
print "run time: %2.6f" % float(tf-ts)
......@@ -28,6 +28,9 @@
#===============================================================================
# last changes:
# 2013-08-13 Theodor Stana t.stana@cern.ch File created
# 2013-10-14 Theodor Stana t.stana@cern.ch Updated VBCP protocol
# with hex addresses
# instead of reg numbers
#===============================================================================
# TODO: -
#===============================================================================
......@@ -76,8 +79,6 @@ class VBCP:
def writemregs(self, addr, val):
self.write_cnt += 1
#reg = addr/4 + 1
#print '%02x' % sl
cmd = "writemregs %d %x %s\r\n" % (self.slot, addr, ' '.join(format(b,'x') for b in val))
#print cmd
self.handle.send(cmd)
......@@ -85,7 +86,7 @@ class VBCP:
def readmregs(self, addr, nrregs):
self.read_cnt += 1
#reg = addr/4 + 1
#addr = addr/4 + 1
cmd = "readmregs %d %x %d\r\n" % (self.slot, addr, nrregs)
self.handle.send(cmd)
resp = _strip_resp(self.handle.recv(30))
......@@ -93,7 +94,7 @@ class VBCP:
def write(self, addr, val):
self.write_cnt += 1
#reg = addr/4 + 1
#addr = addr/4 + 1
cmd = "writereg %d %x %x\r\n" % (self.slot, addr, val)
#print cmd
self.handle.send(cmd)
......@@ -101,7 +102,7 @@ class VBCP:
def read(self, addr):
self.read_cnt += 1
#reg = addr/4 + 1
#addr = addr/4 + 1
cmd = "readreg %d %x\r\n" % (self.slot, addr)
#print cmd
self.handle.send(cmd)
......
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