torc-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Assembler.cpp
Go to the documentation of this file.
1 // Torc - Copyright 2013-2013 University of Southern California. All Rights Reserved.
2 // $HeadURL: https://svn.east.isi.edu/torc/trunk/src/torc/bitstream/assembler/Assembler.cpp $
3 // $Id: Assembler.cpp 1303 2013-02-25 23:18:16Z rsoni $
4 
5 // This program is free software: you can redistribute it and/or modify it under the terms of the
6 // GNU General Public License as published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
11 // the GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License along with this program. If
14 // not, see <http://www.gnu.org/licenses/>.
15 
16 /// \file Assembler.cpp
17 /// \brief Implementation of base class Assembler for Xdl to bitstream conversion
18 
19 #include <iostream>
23 #include "torc/Bitstream.hpp"
26 #include "torc/Physical.hpp"
27 #include <boost/regex.hpp>
28 #include <sstream>
29 
30 using namespace torc::architecture;
31 using namespace torc::physical;
32 using namespace torc::bitstream;
33 
34 namespace torc {
35 namespace bitstream {
36 
37 const string Assembler::sLibraryRelativePath = "torc/bitstream/assembler/libraries";
38 const string Assembler::sConfigOff = "#OFF";
39 const string Assembler::sLibraryExtension = ".ldb";
40 const boost::regex Assembler::sLutConfigRegEx("^(#LUT).*");
41 const boost::regex Assembler::sLutRamOrRomConfigRegEx("^(#RAM:|#ROM).*");
42 const boost::regex Assembler::sRoutethroughRegEx("^_ROUTETHROUGH.*");
43 
44 /// \details Called from constructor to initialize the object.
45 /// Populates mirco-bitstream data from library in a map.
46 void Assembler::initialize(void) {
47 
48  mUnsupportedTileCount = 0;
49  mUnsupportedTileTypeCount = 0;
50  mUnsupportedPipCount = 0;
51  mMissingConfigs = 0;
52  mLibraryPath = torc::common::DirectoryTree::getExecutablePath() / sLibraryRelativePath;
53  if(!boost::filesystem::exists(mLibraryPath)) {
54  std::cerr << "ERROR: Library folder " << mLibraryPath << " does not exist." << std::endl;
55  throw 1;
56  }
57 
58  mBigEndian = isBigEndianMachine();
59 }
60 
61 ///// \details Public function to be called by user to initiate bitstream generation process.
62 ///// The parameter inBaseBitstreamPath will act as base bitstream for micro-bitstream assembly process.
63 ///// This function might be implemented in derived class for additional architecture specific processing.
64 int Assembler::generateBitstream(DesignSharedPtr inDesignPtr,
65  const path inTargetBitstreamPath,
66  EMergeMode inMergeMode,
67  path baseBitstreamPath) {
68 
69  mDesignPtr = inDesignPtr;
70  mMergeMode = inMergeMode;
71  mTargetBitstreamPath = inTargetBitstreamPath;
72 
73  if(mDesignPtr->getDevice() != mDB.getDeviceName()) {
74  std::cout << "Xdl device differs from database device" << std::endl;
75  return -1;
76  }
77  // User hasn't specified base bitstream path
78  if(baseBitstreamPath.empty()) {
79  // Null bitstreams are stored in library folder
80 
81  const string partNumber = mDesignPtr->getDevice();
82  string nullBitFileName = partNumber + ".bit";
83  baseBitstreamPath = mLibraryPath / "null_bitstreams" / nullBitFileName;
84  }
85  if(!boost::filesystem::exists(baseBitstreamPath)) {
86  std::cout << "Base bitstream file - " << baseBitstreamPath.string()
87  << " - does not exist." << std::endl;
88  return -1;
89  }
90  // Load the base bitstream file
91  std::cout << "Loading base bitstream " << baseBitstreamPath << std::endl;
92  std::ifstream baseBitstream;
93  baseBitstream.open(baseBitstreamPath.string().c_str());
94  mBitstreamPtr = torc::bitstream::Factory::newBitstreamPtr(baseBitstreamPath);
95  // Initialize different settings of bitstream object.
96  mBitstreamPtr->setDesignName(mDesignPtr->getName());
97  mBitstreamPtr->initializeDeviceInfo(mBitstreamPtr->getDeviceName());
98  mBitstreamPtr->initializeFrameMaps();
99  return 0;
100 }
101 
102 /// \details Protected function to internally initiate micro-bitstream assembly process.
103 /// This function should be called after design ptr, base bitstream, and library have be initialized.
106 
107  assembleNets();
108 
109  std::cout << "Unsupported tile type count " << mUnsupportedTileTypeSet.size() << std::endl;
110  for(std::set<std::string>::iterator iter = mUnsupportedTileTypeSet.begin(); iter != mUnsupportedTileTypeSet.end(); iter++) {
111  std::cout << " " << *iter << std::endl;
112  }
113  std::cout << "Unsupported tile count : " << mUnsupportedTileCount << std::endl;
114  std::cout << "Unsupported pip count : " << mUnsupportedPipCount << std::endl;
115  std::cout << "Missing configs of supported tiles : " << mMissingConfigs << std::endl;
116 
117 }
118 /// \details Function to assemble micro-bitstreams for instances of Xdl design.
119 /// This function iterates over instances, stores frame blocks and bit offset within for site location,
120 /// and then iterates over config settings of the instance. Ramb instances are handled in separate function.
121 /// Special cases for configurations are - lut equations, lut in ram/rom mode, compound configuration, and
122 /// configuration with hex values.
124 
125  std::cout << "Assembling micro-bitstream for instances... count: " << mDesignPtr->getInstanceCount() <<
126  std::endl;
127  // Get instances begin and end
128  InstanceSharedPtrVector::const_iterator pInstance = mDesignPtr->instancesBegin();
129  InstanceSharedPtrVector::const_iterator eInstance = mDesignPtr->instancesEnd();
130 
131  // Iterate over all the instances
132  while(pInstance != eInstance) {
133 
134  InstanceSharedPtr instancePtr = *pInstance++;
135  string siteType = instancePtr->getType();
136  // Check if instance is placed on supported site type
137  //if(isSiteTypeSupported(siteType) ) {
138 
139  const string &siteName = instancePtr->getSite();
140  if(siteName.empty()) {
141  std::cout << " WARNING: Unplaced instance " << instancePtr->getName() << endl;
142  continue;
143  }
144  const string &tileType = getTiletypeFromSitename(siteName);
145  std::cout << " Processing instance " << instancePtr->getName() << " placed on site "
146  << siteName << " in tile " << tileType << " with " << instancePtr->getConfigCount() << " configs set."
147  << std::endl;
148 
149  getAnnotatedSiteTypeForSlicel(siteType, siteName);
150  if(!tileAndSiteExistInLibrary(tileType, siteType))
151  continue;
152  // Store frame blocks and bit offset for current site location
153  initializeFrameDataForSite(siteName);
154 
155  // RAMB sites are handled in a slightly different manner
156  if(isRambSite(siteType)) {
157  assembleRamb(instancePtr);
158  } else {
159 
160  // Get the element to config map for the given site type
161  SiteTypeToConfigSettings sitetypeToConfigSettings = mLibrary[tileType];
162  ConfigSettingsToValues configSettingToValuesMap = sitetypeToConfigSettings[siteType];
163 
164  // Go over all the configurations of the instance
165  ConfigMap::const_iterator pConfig = instancePtr->configBegin();
166  ConfigMap::const_iterator eConfig = instancePtr->configEnd();
167 
168  while(pConfig != eConfig) {
169 
170  // Ignore routethrough config setting as they don't set bits in bitstream
171  if(isRoutethrough(pConfig->first)) {
172  pConfig++;
173  continue;
174  }
175 
176  // std::cout << "\tWorking on config " << pConfig->first << "::"
177  // << pConfig->second.getValue() << std::endl;
178  // Lut equation has to be handled differently from other config setting.
179  // The boolean operation in the LUT equation have to be performed on the relevant bits.
180  if(isLutEquationSetting(pConfig->second.getValue())) {
181  mergeLutEquationBits(pConfig->first, pConfig->second.getValue(), configSettingToValuesMap);
182  } // LUT ROM and RAM settings also need special care
183  else if(isLutRamOrRomSetting(pConfig->second.getValue())) {
184  mergeLutRamOrRomBits(pConfig->first, pConfig->second.getValue(), configSettingToValuesMap);
185  } // Some elements together effect the bitstream.
186  else if(isCompoundSetting(pConfig->first)) {
187  mergeCompoundSettingBits(pConfig->first, pConfig->second.getValue(),
188  instancePtr, configSettingToValuesMap);
189  } // The DSP MASK and PATTERN have hex values
190  else if(isConfigValHexString(instancePtr->getType(), pConfig->first)) {
191  mergeHexConfigBits(pConfig->first, pConfig->second.getValue(), configSettingToValuesMap);
192  } else {
193  // Merge compressed bitstream to main bitstream if valid setting
194  checkValidityAndMergeBitstream(pConfig->first, pConfig->second.getValue(),
195  configSettingToValuesMap);
196  }
197  //std::cout << "\t------------------" << std::endl;
198  pConfig++;
199  }
200  }
201  // } else {
202  // std::cout << "WARNING: Site " << instancePtr->getType() << " not supported."
203  // << std::endl;
204  // }
205  }
206 
207 }
208 
209 /// \details Function to assemble micro-bitstreams for net of Xdl design.
211  // Get the iterators to nets
212  NetSharedPtrVector::const_iterator pNets = mDesignPtr->netsBegin();
213  NetSharedPtrVector::const_iterator eNets = mDesignPtr->netsEnd();
214 
215  std::cout << "Assembling micro-bitstreams for Nets... count: " << mDesignPtr->getNetCount()
216  << std::endl;
217  // Iterate over nets
218  while(pNets != eNets) {
219 
220  NetSharedPtr netPtr = *pNets;
221  // std::cout << " Processing net: " << netPtr->getName() << std::endl;
222 
223  // Iterate over pips in the net
224  Net::PipConstIterator pPips = netPtr->pipsBegin();
225  Net::PipConstIterator ePips = netPtr->pipsEnd();
226  while(pPips != ePips) {
227  Pip pip = *pPips++;
228  // Store frame blocks and bit offset for this tile
229  TileIndex tileIndex = mTiles.findTileIndex(pip.getTileName());
230  initializeFrameDataForTile(tileIndex);
231 
232  const TileInfo& tileInfo = mTiles.getTileInfo(tileIndex);
233  string tileType = mTiles.getTileTypeName(tileInfo.getTypeIndex());
234  if(!tileAndSiteExistInLibrary(tileType, "routing")) {
235  mUnsupportedPipCount++;
236  continue;
237  }
238  ConfigSettingsToValues configSettingToValuesMap = mLibrary[tileType]["routing"];
239  // std::cout << "\tTile " << tileInfo.getName() << " Src: " << pip.getSourceWireName()
240  // << " Sink: " << pip.getSinkWireName() << std::endl;
242  configSettingToValuesMap);
243 
244  }
245 
246  pNets++;
247  }
248 
249 }
250 
251 /// \brief Different architectures will have different sites supported.
252 /// Derived classes should override this function.
253 bool Assembler::isSiteTypeSupported(const string &inSiteType) {
254  return false;
255 }
256 
257 /// \brief Assemble micro-bitstream for ramb site.
258 /// First the base micro-bitstream is merged. Micro-bitstream info for memory and
259 /// parity init values are gathered from ll files.
260 void Assembler::assembleRamb(InstanceSharedPtr inInstancePtr) {
261  // Get the element to config map for the given site type
262  const string &tileType = getTiletypeFromSitename(inInstancePtr->getSite());
263  ConfigSettingsToValues configSettingToValuesMap = mLibrary[tileType][inInstancePtr->getType()];
264 
265  // Open the RAMBIT memory file and store data in a vector
266  // This file stores memory address to bitstream address map
267  string memoryMapFileName = mParentFamilyName + "-" + tileType + "-map.bits";
268  string rambMemoryMapFilePath = mLibraryPath.string() + "/memory/" + memoryMapFileName;
269  std::ifstream rambMemoryBitFile(rambMemoryMapFilePath.c_str(), std::ios::binary);
270  if(!rambMemoryBitFile.is_open()) {
271  std::cout << "Could not open bram memory map file " << rambMemoryMapFilePath << std::endl;
272  return;
273  }
274 
275  std::vector<uint32_t> bitAddresses;
276  uint32_t count = 0, bitAddress = 0;
277  while(!rambMemoryBitFile.eof()) {
278  // Alternate number is ignored.
279  rambMemoryBitFile.read((char *) &count, 4);
280  rambMemoryBitFile.read((char *) &bitAddress, 4);
281  bitAddress = ntohl(bitAddress);
282  bitAddresses.push_back(bitAddress);
283  }
284  rambMemoryBitFile.close();
285 
286  // Open the RAMB parity bit file and store the data in a vector
287  string parMapFileName = mParentFamilyName + "-" + tileType + "-map-par.bits";
288  string rambParityBitFilePath = mLibraryPath.string() + "/memory/" + parMapFileName;
289  std::ifstream rambParityBitFile(rambParityBitFilePath.c_str(), std::ios::binary);
290  if(!rambParityBitFile.is_open()) {
291  std::cerr << "ERROR: Could not open file " << rambParityBitFilePath << std::endl;
292  return;
293  }
294  std::vector<uint32_t> parityBitAddresses;
295  count = 0, bitAddress = 0;
296  while(!rambParityBitFile.eof()) {
297  rambParityBitFile.read((char *) &count, 4);
298  rambParityBitFile.read((char *) &bitAddress, 4);
299  bitAddress = ntohl(bitAddress);
300  parityBitAddresses.push_back(bitAddress);
301  }
302  rambParityBitFile.close();
303 
304  // Before going over configs, merge the RAMB base bits.
305  mergeWithBaseBitstream(configSettingToValuesMap[inInstancePtr->getType()]["BASE"], 0);
306 
307  // Go over all the configurations of the instance
308  ConfigMap::const_iterator pConfig = inInstancePtr->configBegin();
309  ConfigMap::const_iterator eConfig = inInstancePtr->configEnd();
310  while(pConfig != eConfig) {
311 
312  std::cout << "\tWorking on config " << pConfig->first << "::"
313  << pConfig->second.getValue() << std::endl;
314 
315  // ToDo: Most of the code for memory and parity is same with only the bit address being different.
316  // Try to merge the two if statements.
317  // RAMB memory and parity init values have to be handled differently.
318  if(isMemoryInitSetting(pConfig->first)) {
319 
320  // Get the row number from config name. Last two character are row number in hex form.
321  stringstream ssRow;
322  uint32_t memoryInitRow;
323  ssRow << std::hex << pConfig->first.substr(pConfig->first.length() - 2, 2);
324  ssRow >> memoryInitRow;
325 
326  mergeRambInitBits(pConfig->second.getValue(), memoryInitRow, bitAddresses, 1);
327  } else if(isMemoryParityInitSetting(pConfig->first)) {
328 
329  // Get the row number from config name. Last two character are row number in hex form.
330  stringstream ssRow;
331  uint32_t memoryInitRow;
332  ssRow << std::hex << pConfig->first.substr(pConfig->first.length() - 2, 2);
333  ssRow >> memoryInitRow;
334  mergeRambInitBits(pConfig->second.getValue(), memoryInitRow, parityBitAddresses, 1);
335  } else {
336  // Merge compressed bitstream to main bitstream
337  checkValidityAndMergeBitstream(pConfig->first, pConfig->second.getValue(), configSettingToValuesMap);
338  }
339  pConfig++;
340  }
341 }
342 
343 /// \details Get tile type from site location(name)
344 /// ToDo: A lot of this code is present in initializeFrameDataForSite()
345 string Assembler::getTiletypeFromSitename(const string &inSiteName) {
346  SiteIndex siteIndex = mSites.findSiteIndex(inSiteName);
347  const Site& site = mSites.getSite(siteIndex);
348  TileIndex tileIndex = site.getTileIndex();
349  const TileInfo& tileInfo = mTiles.getTileInfo(tileIndex);
350  string tileType = mTiles.getTileTypeName(tileInfo.getTypeIndex());
351  return tileType;
352 
353 }
354 
355 
356 /// \brief Check if configurations is present in library. If yes, merge the corresponding bits with the bitstream
357 void Assembler::checkValidityAndMergeBitstream(string inElementName, string inConfigVal,
358  const ConfigSettingsToValues &inConfigSettingToValues) {
359 
360  ConfigSettingsToValues::const_iterator pConfigSettings = inConfigSettingToValues.find(inElementName);
361  // If element found in the map
362  if(pConfigSettings != inConfigSettingToValues.end()) {
363  ConfigValuesToBits::const_iterator pConfigValues = pConfigSettings->second.find(inConfigVal);
364  //If config value found in the config to bit map
365  if(pConfigValues != pConfigSettings->second.end()) {
366  // std::cout << " Setting: " << inElementName << " . Config: " << inConfigVal << std::endl;
367  mergeWithBaseBitstream(pConfigValues->second, 0);
368  } else {
369  mMissingConfigs++;
370  std::cout << "WARNING: Config value " << inConfigVal << " for setting " << inElementName
371  << " not found in library." << std::endl;
372  }
373  } else {
374  mMissingConfigs++;
375  std::cout << "WARNING: Config setting " << inElementName << " not found in library." << std::endl;
376  }
377 }
378 /// \brief Returns true if configuration is preseRnt in library
379 bool Assembler::elementAndConfigExistInLibrary(const string &inElementName,
380  const string &inConfigValue, ConfigSettingsToValues &inConfigSettingToValues) {
381  // Check if element exists
382  ConfigSettingsToValues::iterator pConfigSettings = inConfigSettingToValues.find(inElementName);
383  if(pConfigSettings != inConfigSettingToValues.end()) {
384 
385  // Check if config exists
386  ConfigValuesToBits::iterator pConfigValues = pConfigSettings->second.find(inConfigValue);
387  if(pConfigValues != pConfigSettings->second.end())
388  return true;
389  }
390  std::cout << "WARNING: Config setting " << inElementName << " with value " << inConfigValue
391  << " not found in library" << std::endl;
392  return false;
393 }
394 
395 /// \brief If slice site type, annotate type as per even or odd column
396 void Assembler::getAnnotatedSiteTypeForSlicel(string &inOutSiteType, const string &siteLocation) {
397 
398  if(boost::regex_search(inOutSiteType.begin(), inOutSiteType.end(), boost::regex("SLICEL"))){
399  // Get the column number of site location
400  boost::smatch matchResults;
401  boost::regex columnExpr("_X(\\d+)Y");
402  if(boost::regex_search(siteLocation, matchResults, columnExpr)) {
403  // First match is the whole string
404  int column = boost::lexical_cast<int>(matchResults[1]);
405  if(column % 2 == 0)
406  inOutSiteType = inOutSiteType + "E";
407  else
408  inOutSiteType = inOutSiteType + "O";
409  }
410  }
411 }
412 
413 /// \details Merge micro-bitstream for Lut equation.
414 /// The bit operations (AND, OR, etc.) are performed on the micro-bitstreams corresponding to every literal.
415 /// Bit operation NOT is performed by XORing with micro-bitstream for LUT output assigned to 1.
416 /// The lut equation is parsed using bison and flex. When a literal is encountered, the set of frames
417 /// corresponding to literal is pushed on to a stack. When a bit operator is encountered, two set of frames
418 /// is poped from the stack and the bit operations is performed on the two set of frames and result is pushed back
419 /// to stack.
420 void Assembler::mergeLutEquationBits(const string &inElementName, const string &inConfigValue,
421  ConfigSettingsToValues &inConfigSettingToValues) {
422 
423  // Get the right hand side and lefthand side of the LUT equation.
424  std::vector<string> splitVector;
425  boost::algorithm::split(splitVector, inConfigValue, boost::algorithm::is_any_of("="));
426 
427  // The left side tell which output (O5 or O6) is being affected. Store it in a global
428  // so that it can be used by functions called from bison
429  mLutCurrentEquationLhs = splitVector[0];
430  string equationRight = splitVector[1];
431 
432  // Store the frames for LUT setting constant 1. XOR with these frames give NOT functionality.
433  string lutEquationForOne = mLutCurrentEquationLhs + "=1";
434 
435  // Currently all the frames of a LUT setting are not stored. We know only 4 words get affected by LUT setting -
436  // 4 frames and a word in each frame. So instead we store only 4 words and the frame index and word index.
437  if(elementAndConfigExistInLibrary(inElementName, lutEquationForOne, inConfigSettingToValues)) {
438  mCurrentConfigToBitMap = inConfigSettingToValues[inElementName];
439  std::vector<uint32_t> bitAddressesForOne = mCurrentConfigToBitMap[lutEquationForOne];
440 
441  mLutCurrentReferenceFrameIndex = bitAddressesForOne[0] >> 16;
442  mCurrentReferenceWordIndex = (bitAddressesForOne[0] & 0x0000FF00) >> 8;
443 
444  mLutFrameSetForOne.clear();
445  mLutFrameSetForOne.resize(4, uint32_t(0));
446  for(std::vector<uint32_t>::const_iterator bitIter = bitAddressesForOne.begin(); bitIter
447  != bitAddressesForOne.end(); bitIter++) {
448  int32_t bitIndex = (*bitIter) & 0x000000FF;
449  int32_t frameIndex = (*bitIter) >> 16;
450  uint32_t frameWord = 1 << (bitIndex - 1);
451 
452  mLutFrameSetForOne[frameIndex - mLutCurrentReferenceFrameIndex]
453  = mLutFrameSetForOne[frameIndex - mLutCurrentReferenceFrameIndex] | frameWord;
454  }
455 
456  if(!processLut(equationRight.c_str(), inConfigValue)) {
457  std::cout << "ERROR: Error in parsing LUT equation " << inConfigValue << std::endl;
458  /// \todo Do we really want to abort here just because the user has an incorrect expression?
459  exit(-1);
460  }
461 
462  // Build bit addresses out of the last frame in gStackOfFrames
463  std::vector<uint32_t> combinedLUTWords = mLutFrameSetStack[0];
464  std::vector<uint32_t> bitAddresses;
465  uint32_t frameOffset = 0;
466  for(std::vector<uint32_t>::const_iterator wordIter = combinedLUTWords.begin(); wordIter
467  != combinedLUTWords.end(); wordIter++, frameOffset++) {
468 
469  uint32_t tempWord = *wordIter;
470  uint32_t bitIndex = 1;
471  while(tempWord != 0) {
472 
473  // check if the LSB is 1
474  if(tempWord & 1) {
475  // store the combined address
476  bitAddresses.push_back(((mLutCurrentReferenceFrameIndex + frameOffset) << 16)
477  | (mCurrentReferenceWordIndex << 8) | bitIndex);
478  }
479  tempWord = tempWord >> 1;
480  bitIndex++;
481  }
482  }
483 
484  mergeWithBaseBitstream(bitAddresses, 0);
485  mLutFrameSetStack.clear();
486  }
487 }
488 
489 /// \details Merge micro-bitstream for lut in ram/rom mode. The lut ram/rom memory address
490 /// to bit address map is obtained from ll files.
491 void Assembler::mergeLutRamOrRomBits(const string &inElementName, const string &inConfigVal,
492  ConfigSettingsToValues &inConfigSettingToValues) {
493 
494  // Since memory content are similar for SLICEL and SLICEM,
495  // they are stored in library under element name SLICE
496  // ConfigSettingsToValues &configSettingToValuesMap = mLibrary["CLBLM"]["SLICE"];
497 
498  // Get the right hand side and lefthand side of the LUT equation.
499  std::vector<string> splitVector;
500  boost::algorithm::split(splitVector, inConfigVal, boost::algorithm::is_any_of("="));
501  // Remove the first two characters - 0x - from the hex value
502  string memoryValue = splitVector[1].substr(2);
503 
504  if(memoryValue.length() != 8 && memoryValue.length() != 16) {
505  std::cout << "WARNING: Illegal configuration of element " << inElementName << std::endl;
506  return;
507  }
508 
509  // When output O5 of LUT is configured, it has only 8 hex characters in the memory string,
510  // and they belong to the higher memory address of 16 hex characters.
511  if(memoryValue.length() == 8) {
512  memoryValue = "00000000" + memoryValue;
513  }
514 
515  // Get the bit address vector
516  // Since X5LUT and X6LUT use the same memory address to bit address map,
517  // element name is changed to use only 1st letter of the name, viz X (A, B, C or D)
518  // and config name is changed to ROM
519  string elementNameForMemoryMode = inElementName.substr(0, 1);
520  std::vector<uint32_t> bitAddressesForROM;
521 
522  if(!elementAndConfigExistInLibrary(elementNameForMemoryMode, "ROM", inConfigSettingToValues))
523  return;
524 
525  bitAddressesForROM = inConfigSettingToValues[elementNameForMemoryMode]["ROM"];
526  std::vector<uint32_t> bitAddresses;
527  // Iterate over the memory string from left to right
528  for(uint32_t charIndex = 0; charIndex < memoryValue.length(); charIndex++) {
529 
530  stringstream sshexChar;
531  sshexChar << std::hex << memoryValue[charIndex];
532  uint32_t hexDigit;
533  sshexChar >> hexDigit;
534  // Go over the bits of the hex digit from left to right
535  for(int bitIndex = 0; hexDigit != 0; bitIndex++) {
536  if(hexDigit & 8) {
537  uint32_t memoryAddress = (charIndex << 2) + bitIndex;
538  stringstream ssConfigBitIndex;
539  ssConfigBitIndex << memoryAddress;
540  bitAddresses.push_back(bitAddressesForROM[memoryAddress]);
541  }
542  hexDigit = hexDigit << 1;
543  }
544  }
545  mergeWithBaseBitstream(bitAddresses, 0);
546 }
547 
548 /// \details Merge micro-bitstream for compound setting. There are some settings which
549 /// together affect the bitstream.
550 void Assembler::mergeCompoundSettingBits(string inElement1Name, string inConfig1Val,
551  InstanceSharedPtr inInstancePtr, const ConfigSettingsToValues &inConfigSettingToValues) {
552 
553  std::vector<string> compoundElements = getDependantConfigs(inElement1Name);
554  // For now assume there is only on element in the vector, i.e. there is a compound
555  // setting with only two elements.
556  if(compoundElements.size() != 1) {
557  std::cout
558  << "WARNING: Compound setting with more than two configurations not handled currently"
559  << std::endl;
560  } else {
561 
562  // The two element names will be concatenated to form a compound element name Element1Element2.
563  // Similarly two config settings will be concatenated to form a compound config name.
564  std::string element2Name = compoundElements[0];
565  std::string compoundElementName = inElement1Name + element2Name;
566 
567  // Find the 2nd element config in the instance
568  std::string config2Val, config2Name;
569  inInstancePtr->getConfig(element2Name, config2Name, config2Val);
570 
571  // Element 2 config not set
572  if(config2Val.compare(sConfigOff) == 0) {
573  std::cout << "Illegal configuration. Element " << element2Name << " must be set "
574  << " along with element " << inElement1Name << std::endl;
575  return;
576  }
577 
578  // Get compound config val
579  std::string compoundConfigVal = inConfig1Val + config2Val;
580 
581  // Verify setting and merge bits
582  checkValidityAndMergeBitstream(compoundElementName, compoundConfigVal, inConfigSettingToValues);
583  }
584 
585 }
586 
587 /// \details Merge micro-bitstream for configurations with hex values. The hex string is parsed
588 /// character by character and micro-bitstream for every set bit is retrived from library and
589 /// merged with base bitstream.
590 void Assembler::mergeHexConfigBits(string inElementName, string inConfigVal,
591  const ConfigSettingsToValues &inConfigSettingToValues) {
592  std::vector<uint32_t> inBitAddresses;
593 
594  // Go over all the characters of the config val string
595  for(uint32_t charIndex = 0; charIndex < inConfigVal.length(); charIndex++) {
596  stringstream sshexChar;
597  sshexChar << std::hex << inConfigVal[inConfigVal.length() - charIndex - 1];
598  uint32_t hexDigit;
599  sshexChar >> hexDigit;
600  // Go over all the bits of the hex digit
601  for(int bitIndex = 0; hexDigit != 0; bitIndex++) {
602  if(hexDigit & 1) {
603  int configBitIndex = (charIndex << 2) + bitIndex;
604  stringstream ssConfigBitIndex;
605  ssConfigBitIndex << configBitIndex;
606  checkValidityAndMergeBitstream(inElementName, ssConfigBitIndex.str(), inConfigSettingToValues);
607  }
608  hexDigit = hexDigit >> 1;
609  }
610  }
611 }
612 
613 /// \details Merges micro-bitstream for ramb init (both memory and parity) values.
614 void Assembler::mergeRambInitBits(const string &inConfigVal, uint32_t inMemoryInitRow,
615  const vector<uint32_t> &inRamBitAddress, uint32_t inBlock) {
616 
617  vector<uint32_t> bitAddresses; // vector to hold bit addresses of set memory bits
618 
619  uint32_t configValLength = inConfigVal.length();
620  uint32_t numBitsPerConfig = configValLength << 2; // 4 bits every hex character
621 
622  // Go over the memory string from right to left
623  for(uint32_t charIndex = 0; charIndex < configValLength; charIndex++) {
624  //stringstream sshexChar;
625  //sshexChar << std::hex << configVal[configValLength - charIndex - 1];
626  int hexDigit;
627  hexDigit = hexCharacterToDec(inConfigVal[configValLength - charIndex - 1]);
628  //sshexChar >> hexDigit;
629  // Go over the bits of hex digit from right to left
630  for(int bitIndex = 0; hexDigit != 0; bitIndex++) {
631  if(hexDigit & 1) {
632  // Get memory address of set bit taking into account which row of memory is being processed
633  uint32_t configBitIndex = (charIndex << 2) + bitIndex;
634  uint32_t memoryAddress = inMemoryInitRow * numBitsPerConfig + configBitIndex;
635 
636  bitAddresses.push_back(inRamBitAddress[memoryAddress]);
637  }
638  hexDigit = hexDigit >> 1;
639  }
640  }
641  mergeWithBaseBitstream(bitAddresses, inBlock);
642 }
643 
644 /// \details Loads micro-bitstream library from given path and populates the data
645 /// in a map.
647 
648  std::ifstream libDB(inLibDBPath.string().c_str(), std::ios::binary);
649  if(!libDB.good()) {
650  std::cout << "Could not open micro-bitstream DB file " << inLibDBPath.string() << std::endl;
651  libDB.exceptions(std::ios::failbit);
652  exit(-1);
653  }
654  std::cout << "Opened micro-bitstream DB file " << inLibDBPath.string() << std::endl;
655  char buffer[1024];
656  libDB.read(buffer, 16);
657  buffer[16] = '\0';
658  string libDBSanity(buffer);
659  std::cout << "Sanity string " << libDBSanity << std::endl;
660  if(libDBSanity != "<<<<BITLIBDB>>>>") {
661  std::cout << "This file seems to be currupt- " << inLibDBPath.string() << std::endl;
662  exit(-1);
663  }
664  uint32_t tileTypeCount = 0;
665  readWord(libDB, tileTypeCount);
666  std::cout << "Tile type count " << tileTypeCount << std::endl;
667 
668  for(uint32_t tileIndex = 0; tileIndex < tileTypeCount; tileIndex++) {
669  uint32_t tileNameCharCount = 0;
670  readWord(libDB, tileNameCharCount);
671  libDB.read(buffer, tileNameCharCount);
672  buffer[tileNameCharCount] = '\0';
673  string tileType(buffer);
674  uint32_t sitetypeCount = 0;
675  readWord(libDB, sitetypeCount);
676  std::cout << "Tile type: " << tileType << ". Site count: " << sitetypeCount << std::endl;
677 
678  SiteTypeToConfigSettings sitetypeToSettingsMap;
679 
680  // Iterate over the elements
681  for(uint32_t sitetypeIndex = 0; sitetypeIndex < sitetypeCount; sitetypeIndex++) {
682  // Get element name char count
683  uint32_t sitetypeCharCount = 0;
684  readWord(libDB, sitetypeCharCount);
685  libDB.read(buffer, sitetypeCharCount);
686  buffer[sitetypeCharCount] = '\0';
687  string sitetype(buffer);
688 
689  uint32_t configSettingCount = 0;
690  readWord(libDB, configSettingCount);
691  //std::cout << " Site " << sitetype << ". Config setting count " << configSettingCount << std::endl;
692 
693  ConfigSettingsToValues configSettingToValues;
694 
695  // Iterate over configs
696  for(uint32_t configSettingIndex = 0; configSettingIndex < configSettingCount; configSettingIndex++) {
697  uint32_t configSettingCharCount = 0;
698  readWord(libDB, configSettingCharCount);
699  // std::cout << "\tConfig char count " << configSettingCharCount;
700  libDB.read(buffer, configSettingCharCount);
701  buffer[configSettingCharCount] = '\0';
702  string configSetting(buffer);
703  //std::cout << "\t" << configSetting << std::endl;
704 
705  uint32_t configValuesCount = 0;
706  readWord(libDB, configValuesCount);
707 
708  ConfigValuesToBits configMap;
709 
710  for(uint32_t configValueIndex = 0; configValueIndex < configValuesCount; configValueIndex++) {
711  uint32_t configValueCharCount = 0;
712  readWord(libDB, configValueCharCount);
713  libDB.read(buffer, configValueCharCount);
714  buffer[configValueCharCount] = 0;
715  string configValue(buffer);
716  // Read the compressed word count
717  uint32_t wordCount = 0;
718  readWord(libDB, wordCount);
719  std::vector<uint32_t> addresses;
720  uint32_t word;
721  for(uint32_t i = 0; i < wordCount; i++) {
722  readWord(libDB, word);
723  addresses.push_back(word);
724  }
725  configMap[configValue] = addresses;
726  }
727 
728  configSettingToValues[configSetting] = configMap;
729  }
730  sitetypeToSettingsMap[sitetype] = configSettingToValues;
731  }
732  mLibrary[tileType] = sitetypeToSettingsMap;
733  }
734 }
735 
736 /// \details Save the assembled bitstream.
737 void Assembler::saveBitstream() {
738 
739  std::ofstream customBitstreamFile(mTargetBitstreamPath.string().c_str(), std::ios::binary);
740  std::cout << "Writing custom bitstream file " << mTargetBitstreamPath << std::endl;
741  mBitstreamPtr->write(customBitstreamFile);
742 
743  customBitstreamFile.close();
744 }
745 
746 /// \details Perform bit operation on two frame set from stack for lut operation.
747 void Assembler::binaryLutFrameOperation(Assembler::EOperation inOperation) {
748 
749  bool debug = false;
750  if(debug) {
751  std::cout << "In DoBinaryOperation " << inOperation << std::endl;
752  }
753  std::vector<uint32_t> lutWords1 = mLutFrameSetStack.back();
754  std::vector<uint32_t> lutWordsNew;
755  mLutFrameSetStack.pop_back();
756  std::vector<uint32_t> lutWords2;
757  if(inOperation == eOR || inOperation == eAND || inOperation == eXOR) {
758  lutWords2 = mLutFrameSetStack.back();
759  mLutFrameSetStack.pop_back();
760  } else if(inOperation == eNOT) {
761  lutWords2 = mLutFrameSetForOne;
762  } else {
763  cout << "WARNING: Unknown LUT operation " << inOperation << std::endl;
764  return;
765  }
766  std::vector<uint32_t>::const_iterator pWord1 = lutWords1.begin();
767  std::vector<uint32_t>::const_iterator eWord1 = lutWords1.end();
768  std::vector<uint32_t>::const_iterator pWord2 = lutWords2.begin();
769  std::vector<uint32_t>::const_iterator eWord2 = lutWords2.end();
770  if(inOperation == eOR) {
771  while(pWord1 != eWord1 && pWord2 != eWord2) {
772  lutWordsNew.push_back((*pWord1 | *pWord2));
773  pWord1++;
774  pWord2++;
775  }
776  } else if(inOperation == eAND) {
777  while(pWord1 != eWord1) {
778  lutWordsNew.push_back((*pWord1 & *pWord2));
779  pWord1++;
780  pWord2++;
781  }
782  } else if(inOperation == eXOR || inOperation == eNOT) {
783  while(pWord1 != eWord1) {
784  lutWordsNew.push_back((*pWord1 ^ *pWord2));
785  pWord1++;
786  pWord2++;
787  }
788  }
789 
790  if(debug) {
791  std::cout << "LUT frames after the logic " << std::endl;
792  for(std::vector<uint32_t>::const_iterator iter = lutWordsNew.begin(); iter
793  != lutWordsNew.end(); iter++) {
794  std::cout << " " << Hex32(*iter);
795  }
796  std::cout << std::endl;
797  }
798 
799  mLutFrameSetStack.push_back(lutWordsNew);
800 }
801 
802 /// \details Push set of frames corresponding to literal passed for current lut equation.
803 void Assembler::pushLutFrame(string inLiteral) {
804  bool debug = false;
805 
806  if(debug) {
807  std::cout << "In PushFrameToStack " << inLiteral << std::endl;
808  }
809 
810  std::vector<uint32_t> bitAddresses = mCurrentConfigToBitMap[mLutCurrentEquationLhs + "="
811  + inLiteral];
812 
813  /// \todo May need to find a more general to access and push passthrough frame sets
814  // We know LUT bits go across 4 frames and effect the same word in each frame
815  std::vector<uint32_t> lutWords(4, 0);
816  for(std::vector<uint32_t>::const_iterator bitIter = bitAddresses.begin(); bitIter
817  != bitAddresses.end(); bitIter++) {
818  int32_t bitIndex = (*bitIter) & 0x000000FF;
819  int32_t frameIndex = (*bitIter) >> 16;
820  uint32_t frameWord = 1 << (bitIndex - 1);
821 
822  lutWords[frameIndex - mLutCurrentReferenceFrameIndex] |= frameWord;
823  }
824 
825  if(debug) {
826  for(std::vector<uint32_t>::const_iterator iter = lutWords.begin(); iter != lutWords.end(); iter++) {
827  std::cout << " " << Hex32(*iter);
828  }
829  std::cout << std::endl;
830  }
831 
832  mLutFrameSetStack.push_back(lutWords);
833 }
834 
835 bool Assembler::processLut(const string& in, const string& name) {
836  mStreamName = name;
837  istringstream iss(in);
838  mSuccess = true;
839 
840  LutScanner scanner(&iss);
841  scanner.set_debug(mTraceScanning);
842  this->lexer = &scanner;
843  LutParser parser(*this);
844  parser.set_debug_level(mTraceParsing);
845  bool result = parser.parse() == 0;
846  return mSuccess && result;
847 }
848 
849 void Assembler::error(const location& l, const string& m) {
850  failure();
851  cerr << l << ": " << m << std::endl;
852 }
853 
854 void Assembler::error(const string& m) {
855  failure();
856  cerr << m << std::endl;
857 }
858 
859 } // namespace bitstream
860 } // namespace torc
Encapsulation of a tile index in an unsigned 32-bit integer.
virtual int parse()
Definition: LutParser.cpp:242
void assembleInstances(DesignSharedPtr inDesignPtr, Bitstream &outBitstream, const Sites &sites, const Tiles &tiles, TiletypeElementMap &library)
Definition: Xdl2Bit.cpp:247
torc::physical::DesignSharedPtr DesignSharedPtr
Imported type name.
Definition: Assembler.hpp:61
std::map< const string, ConfigValuesToBits > ConfigSettingsToValues
Map from config setting to config values. ConfigSettingsToValues.
Definition: Assembler.hpp:75
Header for the DirectoryTree class.
PipVector::const_iterator PipConstIterator
Constant iterator to Pip objects.
Main torc::bitstream namespace header.
A Bison parser.
Definition: LutParser.hpp:144
void assembleNets(DesignSharedPtr inDesignPtr, Bitstream &outBitstream, const Sites &sites, const Tiles &tiles, TiletypeElementMap &library)
Definition: Xdl2Bit.cpp:418
void convertXdlToBitstream(DesignSharedPtr inDesignPtr, Bitstream &outBitstream, const Sites &sites, const Tiles &tiles, TiletypeElementMap &library)
Definition: Xdl2Bit.cpp:230
Header for the LutScanner class.
bool isMemoryParityInitSetting(const std::string &configName)
Definition: Xdl2Bit.cpp:112
void mergeRambInitBits(const std::string &configVal, uint32_t memoryInitRow, Bitstream &outBitstream, VirtexFrameBlocks &frameBlocks, uint32_t wordOffset, const vector< uint32_t > &bitAddresses, uint32_t block)
Definition: Xdl2Bit.cpp:753
Base class for Xdl to bitstream conversion. This class is abstract but still contains lot of architec...
void mergeCompoundSettingBits(std::string element1Name, std::string config1Val, InstanceSharedPtr instancePtr, const ElementConfigMap &elementMap, VirtexFrameBlocks &frameBlocks, uint32_t wordOffset, Bitstream &outBitstream)
Definition: Xdl2Bit.cpp:686
std::string string
const_iterator const_iterator
Constant iterator to {setting,Config} pairs.
Definition: ConfigMap.hpp:52
EOperation
Permissible operations on LUT frames.
Definition: Assembler.hpp:51
const WireName & getSinkWireName(void) const
Returns the pip sink wire.
Definition: Pip.hpp:77
bool isMemoryInitSetting(const std::string &configName)
Definition: Xdl2Bit.cpp:108
Encapsulation of a device logic site.
Definition: Site.hpp:30
Main torc::physical namespace header.
boost::filesystem::path path
Imported type name.
Definition: Assembler.hpp:67
torc::physical::InstanceSharedPtr InstanceSharedPtr
Imported type name.
Definition: Assembler.hpp:63
Encapsulation of a tile within a device tile map.
Definition: TileInfo.hpp:33
boost::shared_ptr< Net > NetSharedPtr
Shared pointer encapsulation of a Net.
TileIndex getTileIndex(void) const
Returns the index of the containing tile.
Definition: Site.hpp:83
boost::filesystem::path path
const TileTypeIndex & getTypeIndex(void) const
Returns the tile type index for this tile.
Definition: TileInfo.hpp:92
void mergeLutRamOrRomBits(const std::string &elementName, const std::string &configVal, Bitstream &outBitstream, VirtexFrameBlocks &frameBlocks, uint32_t wordOffset, TiletypeElementMap &library)
Definition: Xdl2Bit.cpp:628
const TileName & getTileName(void) const
Returns the pip tile.
Definition: Pip.hpp:73
static BitstreamSharedPtr newBitstreamPtr(const boost::filesystem::path &inPath)
bool isLutRamOrRomSetting(const std::string &configVal)
Definition: Xdl2Bit.cpp:104
Physical design programmable interconnect point.
Definition: Pip.hpp:34
std::map< const string, ConfigSettingsToValues > SiteTypeToConfigSettings
Map from site type to config settings. SiteTypeToConfigSettings.
Definition: Assembler.hpp:77
const WireName & getSourceWireName(void) const
Returns the pip source wire.
Definition: Pip.hpp:75
Encapsulation of a site index in an unsigned 32-bit integer.
bool isSiteTypeSupported(const std::string &siteType)
Definition: Xdl2Bit.cpp:875
bool isRambSite(const std::string &siteType)
Definition: Xdl2Bit.cpp:881
bool isLutEquationSetting(const std::string &configValue)
Definition: Xdl2Bit.cpp:100
Header for the DDB class.
void set_debug(bool b)
Enables or disables debugging output.
bool elementAndConfigExistInLibrary(const std::string &elementName, const std::string &configValue, ElementConfigMap &elementMap)
Definition: Xdl2Bit.cpp:121
static TiletypeElementMap populateLibraryMap(boost::filesystem::path libDBPath)
Definition: Xdl2Bit.cpp:888
void set_debug_level(debug_level_type l)
Set the current debugging level.
Definition: LutParser.cpp:235
static const boost::filesystem::path & getExecutablePath(void)
Returns the absolute path to the executable directory.
void checkValidityAndMergeBitstream(std::string elementName, std::string configVal, const ElementConfigMap &elementMap, VirtexFrameBlocks &frameBlocks, uint32_t wordOffset, Bitstream &outBitstream)
Definition: Xdl2Bit.cpp:495
std::map< const string, std::vector< uint32_t > > ConfigValuesToBits
Map from config value to vector of config bits. ConfigValuesToBits.
Definition: Assembler.hpp:73