byteman  1.3 (Build #225)
Bitstream relocation and manipulation tool
inlineInput.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2022 Kristiyan Manev (University of Manchester)
3  *
4  * Licensed under the Apache License, Version 2.0(the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16 
17 /**************************************************************************/
24 inline void parseBITheader(std::ifstream& fin, Endianness e)
25 {
26  //.bit header c0nstant:
27  int headerConstTextLength = FileIO::read16(fin, e);
28  std::string headerConstText = FileIO::readString(fin, headerConstTextLength, e);
29  int headerConstText2Length = FileIO::read16(fin, e);
30  std::string headerConstText2 = FileIO::readString(fin, headerConstText2Length, e);
31  if((!((9 == headerConstTextLength) && ("\x0F\xF0\x0F\xF0\x0F\xF0\x0F\xF0" == headerConstText) && (1 == headerConstText2Length) && ("a" == headerConstText2))))
32  warn(".bit c0nstant header differs from expected.");
33  //.bit header vars:
34  int headerDesignNameLength = FileIO::read16(fin, e);
35  designName = FileIO::readString(fin, headerDesignNameLength, e);
36  log("Name of design: " + designName);
37  for(int headerDone = 0 ; !headerDone ; ){
38  int key = FileIO::readNative8(fin);
39  switch(key){
40  case 'b': {
41  int headerAttrLength = FileIO::read16(fin, e);
42  partName = FileIO::readString(fin, headerAttrLength, e);
43  log("FPGA part: " + partName);
44  break;
45  }
46  case 'c': {
47  int headerAttrLength = FileIO::read16(fin, e);
48  fileDate = FileIO::readString(fin, headerAttrLength, e);
49  log("Date: " + fileDate);
50  break;
51  }
52  case 'd': {
53  int headerAttrLength = FileIO::read16(fin, e);
54  fileTime = FileIO::readString(fin, headerAttrLength, e);
55  log("Time: " + fileTime);
56  break;
57  }
58  case 'e': {
59  headerDone = 1;//last attribute in a .bit header
60  int reportedRemainingFileLength = FileIO::read32(fin, e);
61  int tmpPos = (int)fin.tellg();
62  fin.seekg (0, fin.end);
63  int fileSize = (int)fin.tellg();
64  fin.seekg (tmpPos, fin.beg);
65  if(fileSize != (tmpPos + reportedRemainingFileLength))
66  warn(".bit header contained inaccurate file length field.");
67  break;
68  }
69  default: {
70  warn(".bit header contained unknown file field type.");
71  }
72  }
73  }
74 }
75 
76 /**************************************************************************/
83 inline Endianness parseBitstreamEndianness(std::ifstream& fin)
84 {
85  std::streamoff fileOffset = fin.tellg();
86  //Optional bitstream header
87 
88  //Follow some 0xFF's and the bus width detection c0nstant "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x44\x00\x22\x11\xBB\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
89  //However we don't care about reading those
90  Endianness returnVal;
91  //Find sync
92  for(int syncDetectionDone = 0 ; !syncDetectionDone ; ){
93  if(!fin.good())
94  throw std::runtime_error("Was unable to find input bitstream's SYNC command.");
95  int wordOld4 = FileIO::read32(fin, Endianness::NATIVE);
96  int wordOld3 = FileIO::read32(fin, Endianness::NATIVE);
97  int wordOld2 = FileIO::read32(fin, Endianness::NATIVE);
98  int wordOld1 = FileIO::read32(fin, Endianness::NATIVE);
99  int word = FileIO::read32(fin, Endianness::NATIVE);
100  if(wordOld4 == 0x000000BB && wordOld3 == 0x11220044 && wordOld2 == 0xFFFFFFFF && wordOld1 == 0xFFFFFFFF && word == XCAP_getSyncInstruction()){
101  returnVal = Endianness::NATIVE;
102  syncDetectionDone++;
103  } else if(wordOld4 == (Endian::NativeToBigEndian32(0x000000BB)) && wordOld3 == (Endian::NativeToBigEndian32(0x11220044)) && wordOld2 == 0xFFFFFFFF && wordOld1 == 0xFFFFFFFF && word == (Endian::NativeToBigEndian32(XCAP_getSyncInstruction()))){
104  returnVal = Endianness::BE;
105  syncDetectionDone++;
106  } else if(wordOld4 == (Endian::NativeToLittleEndian32(0x000000BB)) && wordOld3 == (Endian::NativeToLittleEndian32(0x11220044)) && wordOld2 == 0xFFFFFFFF && wordOld1 == 0xFFFFFFFF && word == (Endian::NativeToLittleEndian32(XCAP_getSyncInstruction()))){
107  returnVal = Endianness::LE;
108  syncDetectionDone++;
109  } else if(wordOld4 == (Endian::NativeToBigEndian32(0x000000BB)) && wordOld3 == (Endian::NativeToBigEndian32(0x11220044)) && wordOld2 == 0xFFFFFFFF && wordOld1 == 0xFFFFFFFF && word == (Endian::NativeToBigEndian32(XCAP_getSyncInstruction()))){
110  returnVal = Endianness::BE_BS;
111  syncDetectionDone++;
112  } else if(wordOld4 == Endian::BitSwap32((Endian::NativeToLittleEndian32(0x000000BB))) && wordOld3 == Endian::BitSwap32((Endian::NativeToLittleEndian32(0x11220044))) && wordOld2 == 0xFFFFFFFF && wordOld1 == 0xFFFFFFFF && word == Endian::BitSwap32((Endian::NativeToLittleEndian32(XCAP_getSyncInstruction())))){
113  returnVal = Endianness::LE_BS;
114  syncDetectionDone++;
115  } else
116  fin.seekg(-19, std::ios::cur);
117  }
118  log("Detected file endianess: " + Endian::to_string(returnVal));
119 
120  fin.seekg(fileOffset, fin.beg);
121  return returnVal;
122 }
123 
124 /**************************************************************************/
131 bool findBitstreamSyncWord(std::ifstream& fin, Endianness e)
132 {
133  //Follow some 0xFF's and the bus width detection c0nstant "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x44\x00\x22\x11\xBB\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
134  //However we don't care about reading those
135  for( ; ; ){
136  if(!fin.good())
137  return false;
138  int word = FileIO::read32(fin, e);
139  if(word == XCAP_getSyncInstruction()){
140  return true;
141  } else
142  fin.seekg(-3, std::ios::cur);
143  }
144  return false; //not going to be reached.
145 }
146 
147 /**************************************************************************/
154 bool findBitstreamSyncSequence(std::ifstream& fin, Endianness e)
155 {
156  //Follow some 0xFF's and the bus width detection c0nstant "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x44\x00\x22\x11\xBB\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
157  //However we don't care about reading those
158  for( ; ; ){
159  if(!fin.good())
160  return false;
161  int wordOld4 = FileIO::read32(fin, e);
162  int wordOld3 = FileIO::read32(fin, e);
163  int wordOld2 = FileIO::read32(fin, e);
164  int wordOld1 = FileIO::read32(fin, e);
165  int word = FileIO::read32(fin, e);
166  if(wordOld4 == 0x000000BB && wordOld3 == 0x11220044 && wordOld2 == 0xFFFFFFFF && wordOld1 == 0xFFFFFFFF && word == XCAP_getSyncInstruction()){
167  return true;
168  } else
169  fin.seekg(-19, std::ios::cur);
170  }
171  return false; //not going to be reached.
172 }
173 
174 /**************************************************************************/
181 inline uint32_t parseBitstreamIDCODE(std::ifstream& fin, Endianness e)
182 {
183  std::streamoff fileOffset = fin.tellg();
184  //Optional bitstream header
186  uint32_t returnVal;
187  //Find sync
188  for(int syncDetectionDone = 0 ; !syncDetectionDone ; ){
189  if(!fin.good())
190  throw std::runtime_error("Was unable to find input bitstream's IDCODE command.");
191  int word = FileIO::read32(fin, e);
192  if(XCAP_IDCODEInstruction() == word){
193  returnVal = FileIO::read32(fin, e);
194  syncDetectionDone++;
195  } else
196  fin.seekg(-3, std::ios::cur);
197  }
198 
199  fin.seekg(fileOffset, fin.beg);
200  return returnVal;
201 }
202 
203 inline void readBitstreamMain(std::ifstream& fin, Endianness bitstreamFileEndianness)
204 {
205  int slr = 0;
207  int wordCount = 0;
208  char shadowFrame[WORDS_PER_FRAME*4];
209  bool shadowFrameValid = false;
210  int b = 7, r = 0, c = 0, m = 0;
211  bool aligned = false;
212  bool synched = false;
213 
214  if(bitstreamHasValidData){
215  ensureSelectedEndianness(bitstreamFileEndianness);
216  }
217  loadedBitstreamEndianness = bitstreamFileEndianness;
218  //Parse bitstream
219  for( ; ; ){
220  if(!synched){
221  if(!aligned){//if not aligned, we search for the whole sync sequence, otherwise, just the sync word
222  if(findBitstreamSyncSequence(fin, loadedBitstreamEndianness)){
223  synched = true;
224  aligned = true;
225  } else {
226  break;// done with the bitstream
227  }
228  } else {
229  if(findBitstreamSyncWord(fin, loadedBitstreamEndianness)){
230  synched = true;
231  } else {
232  break;// done with the bitstream
233  }
234  }
235  } else {
236  uint32_t instruction = FileIO::read32(fin, loadedBitstreamEndianness);
237  if(!fin.good()){
238  break; // done with the bitstream
239  } else {
240  int instructionType = XCAP_getInstructionType(instruction);
241  XCAP::Operation instructionOPCODE = XCAP_getInstructionOperation(instruction);
242  int instructionPayload = XCAP_getInstructionPayload(instruction);
243  if(instructionType == 1) {
244  regAddr = XCAP_getInstructionRegister(instruction);
245  wordCount = XCAP_getInstructionWordCount(instruction);
246  } else if(instructionType == 2) {
247  wordCount = instructionPayload;
248  } else {
249  throw std::runtime_error("Bitstream has invalid instruction (" + std::to_string(instruction) + " @ " + std::to_string(fin.tellg()) + ") (invalid type).");
250  }
251  if(regAddr == XCAP::Register::MAGIC1){
252  slr++;
253  wordCount = 0;
254  shadowFrameValid = false;
255  synched = false; //TODO: do this recursively and not rely on large continous blocks of MAGIC1 command
256  aligned = false;
257  }
258  if(instructionOPCODE == XCAP::Operation::WRITE){ //Write register
259  for( ; wordCount > 0 ; ){
260  if(regAddr == XCAP::Register::FAR){
261  uint32_t farValue = FileIO::read32(fin, loadedBitstreamEndianness);
262  wordCount--;
263  XCAP_parseFAR(farValue, slr, b, r, c, m);
264  /*
265  if(shadowFrameValid){
266  if(b == BLOCKTYPE_LOGIC){
267  memcpy(&bitstreamCLB[r][c][m*WORDS_PER_FRAME], &shadowFrame, WORDS_PER_FRAME*4);
268  } else if(b == BLOCKTYPE_BLOCKRAM) {
269  memcpy(&bitstreamBRAM[r][c][m*WORDS_PER_FRAME], &shadowFrame, WORDS_PER_FRAME*4);
270  }
271  XCAP_IncrementFAR(slr, b, r, c, m);
272  shadowFrameValid = false;
273  }
274  */
275  } else if(regAddr == XCAP::Register::FDRI){
276  if(wordCount % WORDS_PER_FRAME != 0)
277  throw std::runtime_error("FDRI write of a partial frame was detected, which is currently not supported.");
278  if(shadowFrameValid){
279  throwingAssert(b, <, BLOCKTYPE_MAX);
280  throwingAssertPrintVar_1(r, >=, SLRinfo[slr].fromRow, slr);
281  throwingAssertPrintVar_1(r, <=, SLRinfo[slr].toRow, slr);
282  throwingAssertPrintVar_1(c, <, numberOfCols[r], r);
283  if(b == BLOCKTYPE_LOGIC){
284  throwingAssertPrintVar_3(m, <, LUT_numberOfFramesForResourceLetter[(uint8_t)resourceString[r][c]], r, c, (int)resourceString[r][c]);
285  memcpy(&bitstreamCLB[r][c][m*WORDS_PER_FRAME], &shadowFrame, WORDS_PER_FRAME*4);
286  } else if(b == BLOCKTYPE_BLOCKRAM) {
287  throwingAssert(m, <, FRAMES_PER_BRAM_CONTENT_COLUMN);
288  memcpy(&bitstreamBRAM[r][c][m*WORDS_PER_FRAME], &shadowFrame, WORDS_PER_FRAME*4);
289  } else {
290  warn("Unknown BlockType(" + std::to_string(b) + ") written while reading bitstream file.");
291  }
292  XCAP_IncrementFAR(slr, b, r, c, m);
293  }
294  int forwardShadowReg = (wordCount/WORDS_PER_FRAME) - 1;//skip shadow reg for certain number of frames
295  if(forwardShadowReg > 0){
296  if(b == BLOCKTYPE_LOGIC){ // CLB
297  fin.read((char*)&bitstreamCLB[r][c][m*WORDS_PER_FRAME], forwardShadowReg * WORDS_PER_FRAME * 4);
298  } else if(b == BLOCKTYPE_BLOCKRAM){
299  fin.read((char*)&bitstreamBRAM[r][c][m*WORDS_PER_FRAME], forwardShadowReg * WORDS_PER_FRAME * 4);
300  } else {
301  fin.ignore(forwardShadowReg * WORDS_PER_FRAME * 4);
302  warn("Unknown BlockType(" + std::to_string(b) + ") written while reading bitstream file.");
303  }
304  for(int i = 0 ; i < forwardShadowReg ; i++){
305  XCAP_IncrementFAR(slr, b, r, c, m);
306  }
307  }
308  wordCount -= forwardShadowReg * WORDS_PER_FRAME;
309  shadowFrameValid = true;
310  fin.read((char*)&shadowFrame, WORDS_PER_FRAME*4);
311  wordCount -= WORDS_PER_FRAME;
312  } else if(regAddr == XCAP::Register::CMD){
313  XCAP::Command command = static_cast<XCAP::Command>(FileIO::read32(fin, loadedBitstreamEndianness));
314  wordCount--;
315  if(command == XCAP::Command::WCFG){
316  shadowFrameValid = false;
317  }
318  if(command == XCAP::Command::DESYNC){
319  synched = false;//but aligned remains true
320  shadowFrameValid = false;
321  }
322  } else {
323  uint32_t scrap = FileIO::read32(fin, loadedBitstreamEndianness);
324  wordCount--;
325  }
326  }//Write register count for loop
327  }//Write register instruction
328  }// not end of file
329  }
330  }// for loop parsing the rest of the bitstream
331  bitstreamHasValidData = true;
332 }
333 
334 inline void readBitstreamBIT(std::ifstream& fin)
335 {
336  Endianness bitstreamFileEndianness = parseBitstreamEndianness(fin);
337 
338  parseBITheader(fin, bitstreamFileEndianness);
339  setDeviceByPartNameOrThrow();
340  ensureInitializedBitstreamArrays();//initialize bitstream arrays before writing
341 
342  readBitstreamMain(fin, bitstreamFileEndianness);
343 }
344 
345 
346 inline void readBitstreamBIN(std::ifstream& fin)
347 {
348  Endianness bitstreamFileEndianness = parseBitstreamEndianness(fin);
349 
350  uint32_t idcode = parseBitstreamIDCODE(fin, bitstreamFileEndianness);
351  setDeviceByIDCODEOrThrow(idcode);
352  ensureInitializedBitstreamArrays();//initialize bitstream arrays before writing
353 
354  readBitstreamMain(fin, bitstreamFileEndianness);
355 }
356 
357 inline void readBitstreamRBDMain(std::ifstream& fin, Endianness bitstreamFileEndianness)
358 {
359  //int slr = 0;
361  if(bitstreamHasValidData){
362  ensureSelectedEndianness(bitstreamFileEndianness);
363  }
364  loadedBitstreamEndianness = bitstreamFileEndianness;
365  //Parse RBD
366  std::string str;
367  for(int i = 0 ; i < WORDS_PER_FRAME ; i++)//dump first frame.
368  std::getline(fin, str);
369  uint32_t* fromPtr = bitstreamBegin;
370  uint32_t* toPtr = bitstreamEnd;
371  for(uint32_t* bitstreamLoc = fromPtr ; bitstreamLoc < toPtr ; bitstreamLoc++){
372  std::getline(fin, str);
373  uint32_t val = (uint32_t)(std::stoll(str, nullptr, 2) & 0xFFFFFFFF);
374  bitstreamLoc[0] = Endian::NativeToAnyEndianness32(val, loadedBitstreamEndianness);
375  }
376  bitstreamHasValidData = true;
377 }
378 
379 inline void readBitstreamRBD(std::ifstream& fin)
380 {
381  Endianness bitstreamFileEndianness = Endianness::BE;
382 
383  ensureInitializedBitstreamArrays();//initialize bitstream arrays before writing
384 
385  readBitstreamRBDMain(fin, bitstreamFileEndianness);
386 }
Endianness
< Endianness in byteman is represented not only by big/little endian, but also by potential bit swapp...
Definition: Endianness.h:47
@ BE_BS
Big endian with bit swaps inside each byte.
@ LE_BS
Little endian with bit swaps inside each byte.
@ LE
Little endian ("LE" instead of full-er name, so it does not conflict with linux's reserved endianess ...
@ BE
Big endian ("BE" instead of full-er name, so it does not conflict with linux's reserved endianess wor...
@ NATIVE
System native will always be the fastest endianess to process.
#define throwingAssertPrintVar_1(left, operator,right, var1)
Definition: assert.h:33
#define throwingAssert(left, operator,right)
Definition: assert.h:32
#define throwingAssertPrintVar_3(left, operator,right, var1, var2, var3)
Definition: assert.h:35
XCAP::Register XCAP_getInstructionRegister(uint32_t instruction)
Parses and returns instruction register. This is the register being addressed if the instruction is o...
Definition: inlineCAP.h:271
XCAP::Operation XCAP_getInstructionOperation(uint32_t instruction)
Parses and returns instruction operation. Most Xil instructions will NOP or write.
Definition: inlineCAP.h:259
uint32_t XCAP_getInstructionPayload(uint32_t instruction)
Parses and returns instruction payload. This is the immediate value after instruction type and operat...
Definition: inlineCAP.h:265
uint32_t XCAP_getInstructionWordCount(uint32_t instruction)
Parses and returns instruction word count. This is the number of words to be read/written if the inst...
Definition: inlineCAP.h:277
uint32_t XCAP_getSyncInstruction()
Generate and return the encoding for a SYNC instruction.
Definition: inlineCAP.h:430
uint32_t XCAP_IDCODEInstruction()
Generate and return the encoding for a IDCODE writing instruction.
Definition: inlineCAP.h:424
uint32_t XCAP_getInstructionType(uint32_t instruction)
Parses and returns instruction type. Valid Xil instructions will be of types 1 and 2.
Definition: inlineCAP.h:253
void ensureSelectedEndianness(Endianness newEndianness)
Definition: inlineChange.h:17
void XCAP_parseFAR(int farValue, int slr, int &blockType, int &globalRowAddress, int &columnAddress, int &minorAddress)
Definition: inlineFAR.h:153
void XCAP_IncrementFAR(int slrID, int &blockType, int &globalRowAddress, int &columnAddress, int &minorAddress)
Definition: inlineFAR.h:144
Endianness parseBitstreamEndianness(std::ifstream &fin)
Definition: inlineInput.h:83
void readBitstreamBIN(std::ifstream &fin)
Definition: inlineInput.h:346
void readBitstreamRBD(std::ifstream &fin)
Definition: inlineInput.h:379
void parseBITheader(std::ifstream &fin, Endianness e)
Definition: inlineInput.h:24
void readBitstreamMain(std::ifstream &fin, Endianness bitstreamFileEndianness)
Definition: inlineInput.h:203
bool findBitstreamSyncSequence(std::ifstream &fin, Endianness e)
Definition: inlineInput.h:154
void readBitstreamBIT(std::ifstream &fin)
Definition: inlineInput.h:334
bool findBitstreamSyncWord(std::ifstream &fin, Endianness e)
Definition: inlineInput.h:131
void readBitstreamRBDMain(std::ifstream &fin, Endianness bitstreamFileEndianness)
Definition: inlineInput.h:357
uint32_t parseBitstreamIDCODE(std::ifstream &fin, Endianness e)
Definition: inlineInput.h:181
uint32_t NativeToLittleEndian32(uint32_t x)
Definition: Endianness.h:169
uint32_t NativeToAnyEndianness32(uint32_t x, Endianness e)
Definition: Endianness.h:246
uint32_t NativeToBigEndian32(uint32_t x)
Definition: Endianness.h:152
std::string to_string(Endianness e)
Definition: Endianness.h:56
uint32_t BitSwap32(uint32_t x)
Definition: Endianness.h:220
uint8_t readNative8(std::ifstream &fin)
Definition: FileIO.h:46
std::string readString(std::ifstream &fin, int stringSize)
Definition: FileIO.h:176
uint16_t read16(std::ifstream &fin, Endianness e=Endianness::NATIVE)
Definition: FileIO.h:143
uint32_t read32(std::ifstream &fin, Endianness e=Endianness::NATIVE)
Definition: FileIO.h:131
Operation
Definition: XCAP.h:69
Register
Definition: XCAP.h:20
Command
Definition: XCAP.h:46
Definition: iff.h:29