Skip to content

Commit 1de7221

Browse files
committed
Read firmware revision and build from the bitfile
And print it out at the beginninng of program.py
1 parent 56a2a3b commit 1de7221

File tree

2 files changed

+253
-234
lines changed

2 files changed

+253
-234
lines changed

BitstreamReader.py

Lines changed: 168 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
#
2727
# Consists of an initial 11 bytes of unknown content (???)
2828
# Then 5 fields of the format:
29-
# 1 byte key
30-
# 2 byte, Big Endian Length (EXCEPT: The last field, which has a 4 byte length)
31-
# data (of length specified above ^)
29+
# 1 byte key
30+
# 2 byte, Big Endian Length (EXCEPT: The last field, which has a 4 byte length)
31+
# data (of length specified above ^)
3232
#
3333
# The 5 fields have keys in the sequence a, b, c, d, e
3434
# The data from the first 4 fields are strings:
@@ -39,160 +39,178 @@
3939
import os.path
4040
import cPickle as pickle
4141
import time
42+
from binascii import unhexlify
4243

4344
# Dictionary for looking up idcodes from device names:
4445
idcode_lut = {'6slx150fgg484': 0x401d093, '6slx45csg324': 0x4008093, '6slx150tfgg676': 0x403D093}
4546

4647
class BitFileReadError(Exception):
47-
_corruptFileMessage = "Unable to parse .bit file; header is malformed. Is it really a Xilinx .bit file?"
48-
49-
def __init__(self, value=None):
50-
self.parameter = BitFileReadError._corruptFileMessage if value is None else value
51-
def __str__(self):
52-
return repr(self.parameter)
53-
48+
_corruptFileMessage = "Unable to parse .bit file; header is malformed. Is it really a Xilinx .bit file?"
49+
def __init__(self, value=None):
50+
self.parameter = BitFileReadError._corruptFileMessage if value is None else value
51+
def __str__(self):
52+
return repr(self.parameter)
53+
5454
class BitFileMismatch(Exception):
55-
_mismatchMessage = "Device IDCode does not match bitfile IDCode! Was this bitstream built for this FPGA?"
56-
57-
def __init__(self, value=None):
58-
self.parameter = BitFileReadError._mismatchMessage if value is None else value
59-
def __str__(self):
60-
return repr(self.parameter)
61-
55+
_mismatchMessage = "Device IDCode does not match bitfile IDCode! Was this bitstream built for this FPGA?"
56+
def __init__(self, value=None):
57+
self.parameter = BitFileReadError._mismatchMessage if value is None else value
58+
def __str__(self):
59+
return repr(self.parameter)
60+
61+
class BitFileUnknown(Exception):
62+
_unknownMessage = "Bitfile has an unknown UserID! Was this bitstream built for the X6500?"
63+
def __init__(self, value=None):
64+
self.parameter = BitFileReadError._unknownhMessage if value is None else value
65+
def __str__(self):
66+
return repr(self.parameter)
67+
6268
class Object(object):
63-
pass
69+
pass
6470

6571
class BitFile:
66-
"""Read a .bit file and return a BitFile object."""
67-
@staticmethod
68-
def read(name):
69-
with open(name, 'rb') as f:
70-
bitfile = BitFile()
71-
72-
# 11 bytes of unknown data
73-
if BitFile._readLength(f) != 9:
74-
raise BitFileReadError()
75-
76-
BitFile._readOrDie(f, 11)
77-
78-
bitfile.designname = BitFile._readField(f, 'a').rstrip('\0')
79-
bitfile.part = BitFile._readField(f, 'b').rstrip('\0')
80-
bitfile.date = BitFile._readField(f, 'c').rstrip('\0')
81-
bitfile.time = BitFile._readField(f, 'd').rstrip('\0')
82-
bitfile.idcode = idcode_lut[bitfile.part]
83-
84-
if BitFile._readOrDie(f, 1) != 'e':
85-
raise BitFileReadError()
86-
87-
length = BitFile._readLength4(f)
88-
bitfile.bitstream = BitFile._readOrDie(f, length)
89-
90-
bitfile.processed = [False]*3
91-
92-
for i in range(3):
93-
processed_name = name + '.' + str(i)
94-
if os.path.isfile(processed_name):
95-
bitfile.processed[i] = True
96-
97-
return bitfile
98-
99-
@staticmethod
100-
def pre_process(bitstream, jtag, chain, progressCallback=None):
101-
CHUNK_SIZE = 4096*4
102-
chunk = ""
103-
chunks = []
104-
105-
bytetotal = len(bitstream)
106-
start_time = time.time()
107-
last_update = 0
108-
written = 0
109-
110-
for b in bitstream[:-1]:
111-
d = ord(b)
112-
113-
for i in range(7, -1, -1):
114-
x = (d >> i) & 1
115-
chunk += jtag._formatJtagClock(tdi=x)
116-
117-
if len(chunk) >= CHUNK_SIZE:
118-
chunks.append(chunk)
119-
chunk = ""
120-
121-
written += 1
122-
if time.time() > (last_update + 1) and progressCallback:
123-
progressCallback(start_time, time.time(), written, bytetotal)
124-
last_update = time.time()
125-
126-
if len(chunk) > 0:
127-
chunks.append(chunk)
128-
129-
last_bits = []
130-
d = ord(bitstream[-1])
131-
for i in range(7, -1, -1):
132-
last_bits.append((d >> i) & 1)
133-
134-
progressCallback(start_time, time.time(), bytetotal, bytetotal)
135-
136-
#for i in range(self.current_part):
137-
# last_bits.append(0)
138-
139-
processed_bitstream = Object()
140-
processed_bitstream.chunks = chunks
141-
processed_bitstream.last_bits = last_bits
142-
143-
return processed_bitstream
144-
145-
@staticmethod
146-
def save_processed(name, processed_bitstream, chain):
147-
processed_name = name.split('.')[0] + ".bit." + str(chain)
148-
if processed_bitstream is not None:
149-
pickle.dump(processed_bitstream, open(processed_name, "wb"), pickle.HIGHEST_PROTOCOL)
150-
151-
@staticmethod
152-
def load_processed(name, chain):
153-
processed_name = name + "." + str(chain)
154-
return pickle.load(open(processed_name, "rb"))
155-
156-
# Read a 2-byte, unsigned, Big Endian length.
157-
@staticmethod
158-
def _readLength(filestream):
159-
length = BitFile._readOrDie(filestream, 2)
160-
161-
return (ord(length[0]) << 8) | ord(length[1])
162-
163-
@staticmethod
164-
def _readLength4(filestream):
165-
length = BitFile._readOrDie(filestream, 4)
166-
167-
return (ord(length[0]) << 24) | (ord(length[1]) << 16) | (ord(length[2]) << 8) | ord(length[3])
168-
169-
# Read length bytes, or throw an exception
170-
@staticmethod
171-
def _readOrDie(filestream, length):
172-
data = filestream.read(length)
173-
174-
if len(data) < length:
175-
raise BitFileReadError()
176-
177-
return data
178-
179-
@staticmethod
180-
def _readField(filestream, key):
181-
if BitFile._readOrDie(filestream, 1) != key:
182-
raise BitFileReadError()
183-
184-
length = BitFile._readLength(filestream)
185-
data = BitFile._readOrDie(filestream, length)
186-
187-
return data
188-
189-
190-
def __init__(self):
191-
self.designname = None
192-
self.part = None
193-
self.date = None
194-
self.time = None
195-
self.length = None
196-
self.idcode = None
197-
self.bitstream = None
72+
"""Read a .bit file and return a BitFile object."""
73+
@staticmethod
74+
def read(name):
75+
with open(name, 'rb') as f:
76+
bitfile = BitFile()
77+
78+
# 11 bytes of unknown data
79+
if BitFile._readLength(f) != 9:
80+
raise BitFileReadError()
81+
82+
BitFile._readOrDie(f, 11)
83+
84+
# the designname field should look something like:
85+
# fpgaminer_top.ncd;HW_TIMEOUT=FALSE;UserID=0xFFFFFFFF
86+
bitfile.designname = BitFile._readField(f, 'a').rstrip('\0')
87+
bitfile.userid = int(bitfile.designname.split(';')[-1].split('=')[-1], base=16)
88+
if bitfile.userid == 0xFFFFFFFF:
89+
bitfile.rev = 0
90+
bitfile.build = 0
91+
elif (bitfile.userid >> 16) & 0xFFFF == 0x4224:
92+
bitfile.rev = (bitfile.userid >> 8) & 0xFF
93+
bitfile.build = bitfile.userid & 0xFF
94+
else:
95+
raise BitFileReadError()
96+
97+
bitfile.part = BitFile._readField(f, 'b').rstrip('\0')
98+
bitfile.date = BitFile._readField(f, 'c').rstrip('\0')
99+
bitfile.time = BitFile._readField(f, 'd').rstrip('\0')
100+
bitfile.idcode = idcode_lut[bitfile.part]
101+
102+
if BitFile._readOrDie(f, 1) != 'e':
103+
raise BitFileReadError()
104+
105+
length = BitFile._readLength4(f)
106+
bitfile.bitstream = BitFile._readOrDie(f, length)
107+
108+
bitfile.processed = [False]*3
109+
110+
for i in range(3):
111+
processed_name = name + '.' + str(i)
112+
if os.path.isfile(processed_name):
113+
bitfile.processed[i] = True
114+
115+
return bitfile
116+
117+
@staticmethod
118+
def pre_process(bitstream, jtag, chain, progressCallback=None):
119+
CHUNK_SIZE = 4096*4
120+
chunk = ""
121+
chunks = []
122+
123+
bytetotal = len(bitstream)
124+
start_time = time.time()
125+
last_update = 0
126+
written = 0
127+
128+
for b in bitstream[:-1]:
129+
d = ord(b)
130+
131+
for i in range(7, -1, -1):
132+
x = (d >> i) & 1
133+
chunk += jtag._formatJtagClock(tdi=x)
134+
135+
if len(chunk) >= CHUNK_SIZE:
136+
chunks.append(chunk)
137+
chunk = ""
138+
139+
written += 1
140+
if time.time() > (last_update + 1) and progressCallback:
141+
progressCallback(start_time, time.time(), written, bytetotal)
142+
last_update = time.time()
143+
144+
if len(chunk) > 0:
145+
chunks.append(chunk)
146+
147+
last_bits = []
148+
d = ord(bitstream[-1])
149+
for i in range(7, -1, -1):
150+
last_bits.append((d >> i) & 1)
151+
152+
progressCallback(start_time, time.time(), bytetotal, bytetotal)
153+
154+
#for i in range(self.current_part):
155+
# last_bits.append(0)
156+
157+
processed_bitstream = Object()
158+
processed_bitstream.chunks = chunks
159+
processed_bitstream.last_bits = last_bits
160+
161+
return processed_bitstream
162+
163+
@staticmethod
164+
def save_processed(name, processed_bitstream, chain):
165+
processed_name = name.split('.')[0] + ".bit." + str(chain)
166+
if processed_bitstream is not None:
167+
pickle.dump(processed_bitstream, open(processed_name, "wb"), pickle.HIGHEST_PROTOCOL)
168+
169+
@staticmethod
170+
def load_processed(name, chain):
171+
processed_name = name + "." + str(chain)
172+
return pickle.load(open(processed_name, "rb"))
173+
174+
# Read a 2-byte, unsigned, Big Endian length.
175+
@staticmethod
176+
def _readLength(filestream):
177+
length = BitFile._readOrDie(filestream, 2)
178+
179+
return (ord(length[0]) << 8) | ord(length[1])
180+
181+
@staticmethod
182+
def _readLength4(filestream):
183+
length = BitFile._readOrDie(filestream, 4)
184+
185+
return (ord(length[0]) << 24) | (ord(length[1]) << 16) | (ord(length[2]) << 8) | ord(length[3])
186+
187+
# Read length bytes, or throw an exception
188+
@staticmethod
189+
def _readOrDie(filestream, length):
190+
data = filestream.read(length)
191+
192+
if len(data) < length:
193+
raise BitFileReadError()
194+
195+
return data
196+
197+
@staticmethod
198+
def _readField(filestream, key):
199+
if BitFile._readOrDie(filestream, 1) != key:
200+
raise BitFileReadError()
201+
202+
length = BitFile._readLength(filestream)
203+
data = BitFile._readOrDie(filestream, length)
204+
205+
return data
206+
207+
208+
def __init__(self):
209+
self.designname = None
210+
self.part = None
211+
self.date = None
212+
self.time = None
213+
self.length = None
214+
self.idcode = None
215+
self.bitstream = None
198216

0 commit comments

Comments
 (0)