1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
# Copyright 2007 Jeff Epler <jepler@unpythonic.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#
# Info about Xilinx bitfiles:
#
# The format consists of several variable length chunks, preceded by what
# seems to be a constant header (a magic number).
#
# After the header, each "chunk" consists of a one byte "tag", a two or
# four byte length, and "length" bytes of data (the body).
#
# In some chunks, the body is a zero terminated printable string. In
# others it is a blob of binary data. The file format doesn't care.
#
# Standard Xilinx files use 5 chunks: 'a' through 'd' are zero-terminated
# strings with information about the file. 'e' is a large binary blob
# with the actual bitstream in it. Xilinx uses 2 byte lengths for chunks
# 'a' thru 'd', and 4 bytes for chunk 'e'. This library allows other
# chunks, and assume that all have 4 byte lengths, except 'a' thru 'd'.
#
import struct
class BitFile:
MAXCHUNKS = 50
SMALLCHUNKS = "abcd"
MAGIC = "\x00\x09" \
"\x0f\xf0\x0f\xf0" \
"\x0f\xf0\x0f\xf0" \
"\x00\x00\x01"
ORDER = "abcde"
def __init__(self, chunks={}):
self.chunks = dict(chunks)
def __getitem__(self, item):
return self.chunks[item]
def __setitem__(self, item, value):
self.chunks[item] = value
def __delitem__(self, item):
del self.chunks[item]
def chunkorder(self, xxx_todo_changeme):
(tag, value) = xxx_todo_changeme
if tag in self.ORDER:
return self.ORDER.index(tag)
return 256 + ord(tag)
@classmethod
def fromstring(cls, data):
if not data.startswith(cls.MAGIC):
raise ValueError("data does not start with the magic number")
i = len(cls.MAGIC)
chunks = {}
while i < len(data):
tag = data[i]
if tag in cls.SMALLCHUNKS:
chunksize = struct.unpack(">H", data[i+1:i+3])[0]
i = i + 3
else:
chunksize = struct.unpack(">I", data[i+1:i+5])[0]
i = i + 5
chunkdata = data[i:i+chunksize]
if tag in chunks:
raise ValueError("bitfile has chunk %r more than once" % tag)
chunks[tag] = chunkdata
i = i + chunksize
return cls(chunks)
@classmethod
def fromfile(cls, file):
return cls.fromstring(file.read())
@classmethod
def fromfilename(cls, filename):
return cls.fromstring(open(filename, "rb").read())
def tostring(self):
result = self.MAGIC
for tag, chunkdata in sorted(list(self.chunks.items()), key=self.chunkorder):
if len(tag) != 1:
raise ValueError("Tag %r must be a length-1 string" % tag)
result = result + tag
if tag in self.SMALLCHUNKS:
result += struct.pack(">H", len(chunkdata))
else:
result += struct.pack(">I", len(chunkdata))
result += chunkdata
return result
def tofile(self, file):
return file.write(self.tostring())
def tofilename(self, filename):
return open(filename, "wb").write(self.tostring())
if __name__ == '__main__':
import sys
if len(sys.argv) < 2:
c = BitFile()
c['a'] = "hello world"
c['e'] = "goodbye"
c['A'] = "shazam"
s = c.tostring()
print((repr(s)))
d = BitFile.fromstring(s)
print((d.chunks))
assert d.tostring() == s
for bitfile in sys.argv[1:]:
bits = open(bitfile, "rb").read()
c = BitFile.fromstring(bits)
for k, v in sorted(c.chunks.items()):
if k in 'abcd':
print((k, v))
else:
print((k, len(v)))
newbits = c.tostring()
assert bits == newbits # Assuming the original is in canonical order!
print()
|