SXXXXXXX_PyDownloadFwViaSRIO/_OLD/Vecchia_app/FpgaBeamMeUp/bitstreamverifier.cpp
2026-01-22 17:10:05 +01:00

245 lines
6.3 KiB
C++

#include "bitstreamverifier.h"
#include <QFile>
#include <QByteArray>
#include "mydebug.h"
struct xilinx_db_t {
const char* sign;
const char* name;
unsigned int expected_size;
};
static const xilinx_db_t xdb[]=
{
{"xq7z045", "ZynQ", 0},
{"xcku040", "Xilinx/CARRIER", 0},
{0,0, 0}
};
BitstreamVerifier::BitstreamVerifier()
{
}
class BitstreamDecoder
{
public:
BitstreamDecoder(const void* data, unsigned int size):
d((unsigned char*)data),
s(size),
pos(0)
{
}
unsigned int getFieldSize(unsigned int max_size=512)
{
unsigned short l=(d[pos]<<8)+d[pos+1];
if ((l>max_size) || ((pos+l)>s))
{
throw "overrun";
}
skip(2);
return l;
}
void skip(unsigned int len)
{
if ((pos+len)>=s)
throw "overrun";
pos+=len;
}
unsigned char getCode()
{
unsigned char c=d[pos];
skip(1);
return c;
}
const char* str()
{
return (const char*)&d[pos];
}
const unsigned char* d;
unsigned int s;
unsigned int pos;
};
bool BitstreamVerifier::verify(const QString& filename)
{
QFile f(filename);
bool ok=f.open(QIODevice::ReadOnly);
if (!ok)
return false;
QByteArray d=f.read(8*1024);
return verify(d);
}
bool BitstreamVerifier::verify(const QByteArray& d)
{
if (d.size()<8*1024)
return false;
BitstreamDecoder decoder(d.constData(), d.size());
try
{
//Field1: 9 bytes of some sort of header
unsigned int l=decoder.getFieldSize();
if (l!=9)
return false;
decoder.skip(l);
//Field 2: letter 'a'
l=decoder.getFieldSize();
if (l!=1)
return false;
unsigned char c=decoder.getCode();
if (c!='a')
return false;
//Field 3: a string with some info as "name;UserID=...;Version=...\0
l=decoder.getFieldSize();
const char* p=decoder.str();
if (p[l-1]!=0)
{
MyDebug<<"BS:"<<"Unserminated string";
return false;
}
QString name(p);
auto nl=name.split(QChar(';'));
if (nl.size()<1)
return false;
m_info.name=nl[0];
for(int i=1; i<nl.size(); ++i)
{
QString tmp=nl[i];
auto vl=tmp.split(QChar('='));
if (vl.size()==2)
{
if (vl[0]=="UserID")
{
m_info.user=vl[1];
MyDebug<<"BS:"<<"User="<<m_info.user;
}
if (vl[0]=="Version")
{
m_info.generator=vl[1];
MyDebug<<"BS:"<<"Version="<<m_info.generator;
}
}
}
decoder.skip(l);
//Field 4: part num ('b')
c=decoder.getCode();
if (c!='b')
{
return false;
}
l=decoder.getFieldSize();
m_info.partNumber=decoder.str();
MyDebug<<"BS:"<<"P/N"<<m_info.partNumber;
decoder.skip(l);
{//Rep type
for(int i=0; xdb[i].sign; ++i)
{
if (m_info.partNumber.startsWith(xdb[i].sign))
{
m_info.repType=xdb[i].name;
}
}
}
//Field 5: date ('c')
c=decoder.getCode();
if (c!='c')
return true;
l=decoder.getFieldSize();
m_info.date=decoder.str();
decoder.skip(l);
//Filed 6: time ('d')
c=decoder.getCode();
if (c!='d')
return true;
l=decoder.getFieldSize();
m_info.date=m_info.date+" "+decoder.str();
decoder.skip(l);
} catch(...)
{
return false;
}
return true;
}
/*
*
* http://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm
The Xilinx .bit format is pretty simple. It uses keys and lengths to divide the file.
Here is an example. Below is a hex dump from the beginning of a .bit file:
00000000: 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01 61 00 0a .............a..
00000010: 78 66 6f 72 6d 2e 6e 63 64 00 62 00 0c 76 31 30 xform.ncd.b..v10
00000020: 30 30 65 66 67 38 36 30 00 63 00 0b 32 30 30 31 00efg860.c..2001
00000030: 2f 30 38 2f 31 30 00 64 00 09 30 36 3a 35 35 3a /08/10.d..06:55:
00000040: 30 34 00 65 00 0c 28 18 ff ff ff ff aa 99 55 66 04.e..(.......Uf
Field 1
2 bytes length 0x0009 (big endian)
9 bytes some sort of header
Field 2
2 bytes length 0x0001
1 byte key 0x61 (The letter "a")
Field 3
2 bytes length 0x000a (value depends on file name length)
10 bytes string design name "xform.ncd" (including a trailing 0x00)
Field 4
1 byte key 0x62 (The letter "b")
2 bytes length 0x000c (value depends on part name length)
12 bytes string part name "v1000efg860" (including a trailing 0x00)
Field 4
1 byte key 0x63 (The letter "c")
2 bytes length 0x000b
11 bytes string date "2001/08/10" (including a trailing 0x00)
Field 5
1 byte key 0x64 (The letter "d")
2 bytes length 0x0009
9 bytes string time "06:55:04" (including a trailing 0x00)
Field 6
1 byte key 0x65 (The letter "e")
4 bytes length 0x000c9090 (value depends on device type,
and maybe design details)
8233440 bytes raw bit stream starting with 0xffffffff aa995566 sync
word documented below.
Once you get the raw bits, XAPP138 "Virtex FPGA Series Configuration and
Readback" and XAPP139 "Configuration and Readback of Virtex FPGAs using
(JTAG) Boundary-Scan" will tell you what to do with them.
Note the "Enable .bit File Compression" option doesn't change the file
format at all. It only changes how the bitstream is interpreted by the
configuration state machine inside the Xilinx part. (and of course the length of the file)
The following documents at Xilinx are also great evening reading
http://www.xilinx.com/bvdocs/appnotes/xapp138.pdf
http://www.xilinx.com/bvdocs/appnotes/xapp139.pdf
http://www.xilinx.com/bvdocs/appnotes/xapp151.pdf
*/