OpenASIP  2.0
MoveSlotDictionary.cc
Go to the documentation of this file.
1 /*
2  Copyright (c) 2002-2009 Tampere University.
3 
4  This file is part of TTA-Based Codesign Environment (TCE).
5 
6  Permission is hereby granted, free of charge, to any person obtaining a
7  copy of this software and associated documentation files (the "Software"),
8  to deal in the Software without restriction, including without limitation
9  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  and/or sell copies of the Software, and to permit persons to whom the
11  Software is furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in
14  all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23  */
24 /**
25  * @file MoveSlotDictionary.cc
26  *
27  * Implementation of move slot dictionary compressor. Warning! This
28  * compressor works correctly only when there is one instruction per
29  * MAU in the final program image. That is, the MAU of the address
30  * space should be the same as the width of the compressed
31  * instructions or wider. Otherwise jump and call addresses are
32  * invalid in the code.
33  *
34  * This compressor creates the dictionary on move slot level. Furthermore
35  * it uses so called vertical compression which creates a separate dictionary
36  * for each move slot.
37  *
38  * @author Otto Esko 2009 (otto.esko-no.spam-tut.fi)
39  * @note rating: red
40  */
41 
42 #include <vector>
43 #include <string>
44 #include <iostream>
45 #include <cmath>
46 #include <boost/format.hpp>
47 
48 #include "CodeCompressor.hh"
49 #include "CodeCompressorPlugin.hh"
50 #include "Program.hh"
51 #include "BinaryEncoding.hh"
52 #include "MoveSlot.hh"
53 #include "ImmediateSlotField.hh"
54 #include "ImmediateControlField.hh"
55 #include "InstructionBitVector.hh"
56 #include "NullInstruction.hh"
57 #include "AsciiImageWriter.hh"
58 #include "MapTools.hh"
59 #include "MathTools.hh"
60 
61 using std::vector;
62 using std::string;
63 using std::endl;
64 using std::pair;
65 
69 using namespace TPEF;
70 
71 
73 public:
74 
75  /**
76  * The constructor
77  */
78  MoveSlotDictionary(): CodeCompressorPlugin(), dictionaryCreated_(false),
79  compressedWidth_(0) {
80  }
81 
82  /**
83  * The destructor
84  */
86  for (unsigned int i = 0; i < dictionary_.size(); i++) {
87  if (dictionary_.at(i) != NULL) {
88  delete dictionary_.at(i);
89  }
90  }
91  }
92 
93  /**
94  * Creates compressed code of the program and returns it in bit vector
95  */
96  virtual InstructionBitVector*
97  compress(const string& programName) {
98  if (!dictionaryCreated_) {
99  createDictionary();
100  // fix imem width (mau == instruction width)
101  int imemWidth = 0;
102  for (unsigned int i = 0; i < dictionary_.size(); i++) {
103  // add dictionary sizes
104  imemWidth +=
105  MathTools::requiredBits(dictionary_.at(i)->size());
106  }
107  // add limm fields, if any
108  imemWidth += firstMoveSlotIndex();
109  compressedWidth_ = imemWidth;
110  setImemWidth(compressedWidth_);
111 
112  if (Application::verboseLevel() > 0 && dictionary_.size() > 0) {
113  printDetails();
114  }
115  }
116  startNewProgram(programName);
117  setAllInstructionsToStartAtBeginningOfMAU();
118  addInstructions();
119  return programBits();
120  }
121 
122  /**
123  * Generates the decompressor in VHDL.
124  *
125  * Note! The programs must be compressed by compress method before
126  * calling this method.
127  *
128  * @param stream The stream to write.
129  */
130  virtual void
131  generateDecompressor(std::ostream& stream, TCEString entityStr) {
132  generateDictionaryVhdl(stream, entityStr);
133  generateDecompressorEntity(stream, entityStr);
134  generateDecompressorArchitecture(stream, entityStr);
135  }
136 
137  /**
138  * Prints the description of the plugin to the given stream.
139  *
140  * @param stream The stream.
141  */
142  virtual void
143  printDescription(std::ostream& stream) {
144  stream << "Generates the program image using move slot based "
145  << "dictionary compression." << endl << endl
146  << "Warning! This compressor works correctly only when "
147  << "there is one instruction per MAU in the final program "
148  << "image. That is, the MAU of the address space should be "
149  << "the same as the width of the compressed instructions or "
150  << "wider. Otherwise jump and call addresses are invalid in "
151  << "the code. This compressor creates the dictionary on the "
152  << "move slot level." << endl << endl;
153  }
154 
155 private:
156 
157  /**
158  * Creates the whole dictionary
159  *
160  */
161  void
163  for (int i = 0; i < moveSlotCount(); i++) {
164  dictionary_.push_back(new Dictionary);
165  }
166 
167  for (int i = 0; i < numberOfPrograms(); i++) {
168  TPEFMap::const_iterator iter = programElement(i);
169  string name = iter->first;
170  startNewProgram(name);
171  setAllInstructionsToStartAtBeginningOfMAU();
172  updateDictionary(currentProgram());
173  }
174 
175  dictionaryCreated_ = true;
176  }
177 
178  /**
179  * Creates dictionary for one program.
180  */
181  void
183  Instruction* instruction = &program.firstInstruction();
184  while (instruction != &NullInstruction::instance()) {
185  InstructionBitVector* instructionBits = bemInstructionBits(
186  *instruction);
187  unsigned int begin = firstMoveSlotIndex();
188  unsigned int end = begin;
189  for (int i = 0; i < moveSlotCount(); i++) {
190  end = begin + moveSlotWidth(i) - 1;
191  BitVector moveSlot(*instructionBits, begin, end);
192  addToDictionary(moveSlot, i);
193  begin = end + 1;
194  }
195  instruction = &program.nextInstruction(*instruction);
196  delete instructionBits;
197  }
198  }
199 
200  /**
201  * Adds the given instruction bits to the move slot dictionary.
202  *
203  * @param instructionBits The instruction bits to add.
204  * @param slotIndex Index of the move slot
205  */
206  void
207  addToDictionary(const BitVector& instructionBits, int slotIndex) {
209  *(dictionary_.at(slotIndex)), instructionBits)) {
210  unsigned int code = dictionary_.at(slotIndex)->size();
211  dictionary_.at(slotIndex)->insert(
212  std::pair<BitVector, unsigned int>(instructionBits, code));
213  }
214  }
215 
216  /**
217  * Adds the compressed instructions to the program.
218  */
219  void
221  Instruction* instruction = &currentProgram().firstInstruction();
222  while (instruction != &NullInstruction::instance()) {
223  InstructionBitVector* bemBits = bemInstructionBits(*instruction);
224  InstructionBitVector* compressedInstruction =
225  new InstructionBitVector();
226  // Take a BitVector pointer to the compressed instruction because
227  // we _need_ to use BitVector pushBack-methods!
228  BitVector* compressPtr =
229  static_cast<BitVector*>(compressedInstruction);
230 
231  // handle limm fields, if any
232  if (firstMoveSlotIndex() != 0) {
233  for (int i = 0; i < firstMoveSlotIndex(); i++) {
234  // false is defined as 0, true is then != 0
235  compressPtr->pushBack(bemBits->at(i) != 0);
236  }
237  }
238  unsigned int begin = firstMoveSlotIndex();
239  unsigned int end = begin;
240  for (int i = 0; i < moveSlotCount(); i++) {
241  end = begin + moveSlotWidth(i)-1;
242  BitVector moveSlot(*bemBits, begin, end);
243  unsigned int code = MapTools::valueForKey<unsigned int>(
244  *(dictionary_.at(i)), moveSlot);
245  // add move slot key to compressed instruction
246  compressPtr->pushBack(
247  code, MathTools::requiredBits(dictionary_.at(i)->size()));
248 
249  begin = end + 1;
250  }
251  addInstruction(*instruction, compressedInstruction);
252  instruction = &currentProgram().nextInstruction(*instruction);
253  delete bemBits;
254  }
255  }
256 
257  void generateDictionaryVhdl(std::ostream& stream, TCEString entityStr) {
258  stream << "library ieee;" << endl;
259  stream << "use ieee.std_logic_1164.all;" << endl;
260  stream << "use ieee.std_logic_arith.all;" << endl << endl;
261 
262  TCEString packageName = entityStr + "_dict_init";
263 
264  stream << "package " << packageName << " is" << endl << endl;
265 
266  for (int i = 0; i < moveSlotCount(); i++) {
267  if (dictionary_.at(i)->size() > 1) {
268  stream << indentation(1)
269  << "type std_logic_dict_matrix_" << i
270  << " is array (natural range <>) "
271  << "of std_logic_vector(" << moveSlotWidth(i)-1
272  << " downto 0);" << endl << endl;
273  }
274  }
275 
276  // write the dictionary contents
277  for (int i = 0; i < moveSlotCount(); i++) {
278  if (dictionary_.at(i)->size() > 1) {
279  stream << indentation(1)
280  << "constant dict_init_slot_" << i
281  << " : std_logic_dict_matrix_" << i << " := (" << endl;
282  for (unsigned int j = 0; j < dictionary_.at(i)->size(); j++) {
283  BitVector instr = MapTools::keyForValue<BitVector>(
284  *(dictionary_.at(i)), j);
285  AsciiImageWriter writer(instr, instr.size());
286  stream << indentation(2) << "\"";
287  writer.writeImage(stream);
288  stream << "\"";
289  if (j+1 < dictionary_.at(i)->size()) {
290  stream << "," << endl;
291  } else {
292  stream << ");" << endl;
293  }
294  }
295  } else {
296  // there's always at least 1 instruction in dictionary
297  unsigned int index = 0;
298  BitVector instr = MapTools::keyForValue<BitVector>(
299  *(dictionary_.at(i)), index);
300  AsciiImageWriter writer(instr, instr.size());
301  stream << indentation(1)
302  << "constant dict_init_slot_" << i
303  << " : std_logic_vector("
304  << moveSlotWidth(i) << "-1 downto 0) := (" << endl
305  << indentation(2) << "\"";
306  writer.writeImage(stream);
307  stream << "\");" << endl;
308  }
309  stream << endl;
310  }
311  stream << "end " << packageName << ";" << endl << endl;
312  }
313 
314  void generateDecompressorEntity(std::ostream& stream, TCEString entityStr) {
315  // write the decompressor entity
316  stream << "library ieee;" << endl;
317  stream << "use ieee.std_logic_1164.all;" << endl;
318  stream << "use ieee.std_logic_arith.all;" << endl;
319  stream << "use work." << entityStr << "_globals.all;" << endl;
320  stream << "use work." << entityStr << "_dict_init.all;" << endl;
321  stream << "use work." << entityStr << "_imem_mau.all;" << endl << endl;
322 
323  stream << "entity " << entityStr << "_decompressor is" << endl;
324  stream << indentation(1) << "port (" << endl;
325  stream << indentation(2) << "fetch_en : out std_logic;" << endl;
326  stream << indentation(2) << "lock : in std_logic;" << endl;
327  stream << indentation(2)
328  << "fetchblock : in std_logic_vector("
329  << "IMEMWIDTHINMAUS*IMEMMAUWIDTH-1 downto 0);" << endl;
330  stream << indentation(2)
331  << "instructionword : out std_logic_vector("
332  << "INSTRUCTIONWIDTH-1 downto 0);" << endl;
333  stream << indentation(2) << "glock : out std_logic;" << endl;
334  stream << indentation(2) << "lock_r : in std_logic;" << endl;
335  stream << indentation(2) << "clk : in std_logic;" << endl;
336  stream << indentation(2) << "rstx : in std_logic);" << endl << endl;
337  stream << "end " << entityStr << "_decompressor;" << endl << endl;
338  }
339 
341  std::ostream& stream, TCEString entityStr) {
342  stream << "architecture move_slot_dict of " << entityStr
343  << "_decompressor is" << endl << endl;
344 
345  bool haveLimm = false;
346  generateDecompressorSignals(stream,haveLimm);
347 
348  generateDecompressorBody(stream, haveLimm);
349 
350  stream << "end move_slot_dict;" << endl;
351  }
352 
353  void generateDecompressorSignals(std::ostream& stream, bool& haveLimm) {
354  // signal types & signals for dictionaries
355  for (int i = 0; i < moveSlotCount(); i++) {
356  if (dictionary_.at(i)->size() > 1) {
357  stream << indentation(1)
358  << "subtype dict_index_"<< i
359  <<" is integer range 0 to "
360  << "dict_init_slot_" << i
361  << "'length-1;" << endl;
362  stream << indentation(1)
363  << "signal dict_line_"
364  << i <<" : dict_index_" << i << ";" << endl;
365  stream << indentation(1)
366  << "constant dict_" << i
367  << " : std_logic_dict_matrix_"
368  << i << "(0 to dict_init_slot_" << i
369  << "'length-1) := dict_init_slot_"
370  << i << ";" << endl << endl;
371  } else {
372  stream << indentation(1)
373  << "constant dict_" << i
374  << " : std_logic_vector("
375  << moveSlotWidth(i)
376  << "-1 downto 0) := dict_init_slot_"
377  << i << ";" << endl << endl;
378  }
379  }
380  // handle limm fields if present
381  int limmEndIndex = 0;
382  if (firstMoveSlotIndex() != 0) {
383  haveLimm = true;
384  limmEndIndex = firstMoveSlotIndex();
385  stream << indentation(1)
386  << "signal limm_field : std_logic_vector("
387  << limmEndIndex << "-1 downto 0);" << endl << endl;
388  }
389  }
390 
391  void generateDecompressorBody(std::ostream& stream, bool& haveLimm) {
392  stream << indentation(1) << "begin" << endl << endl;
393  stream << indentation(1) << "glock <= lock;" << endl;
394  stream << indentation(1) << "fetch_en <= not lock_r;" << endl << endl;
395 
396 
397  if (haveLimm) {
398  int limmEndIndex = firstMoveSlotIndex();
399  stream << indentation(1)
400  << "limm_field <= fetchblock(fetchblock'length-1 downto "
401  << "fetchblock'length-" << limmEndIndex << ");" << endl
402  << endl;
403  }
404  // pair<beginIndex,endIndex>
405  vector<pair<int,int> > moveSlotBoundaries;
406  evaluateMoveSlotBoundaries(moveSlotBoundaries);
407 
408  for (int i = 0; i < moveSlotCount(); i++) {
409  if (dictionary_.at(i)->size() > 1) {
410  stream << indentation(1)
411  << "dict_line_" << i
412  << " <= conv_integer(unsigned(fetchblock("
413  << "fetchblock'length-"
414  << moveSlotBoundaries.at(i).first
415  << " downto fetchblock'length-"
416  << moveSlotBoundaries.at(i).second
417  << ")));" << endl << endl;
418  }
419  }
420 
421  generateDecompressorProcess(stream, haveLimm);
422  }
423 
424  void evaluateMoveSlotBoundaries(vector<pair<int,int> >& boundaries) {
425  for (int i = 0; i < moveSlotCount(); i++) {
426  int temp = 0;
427  if (boundaries.size() == 0) {
428  temp = firstMoveSlotIndex();
429  } else {
430  // end point of previous boundary
431  temp = boundaries.at(boundaries.size()-1).second;
432  }
433  int begin = temp + 1;
434  int end = temp + MathTools::requiredBits(dictionary_.at(i)->size());
435  boundaries.push_back(std::make_pair(begin,end));
436  }
437  }
438 
439  void generateDecompressorProcess(std::ostream& stream, bool& haveLimm) {
440  stream << indentation(1) << "process (";
441  if (haveLimm) {
442  stream << "limm_field, ";
443  }
444  for (int i = 0; i < moveSlotCount(); i++) {
445  if (dictionary_.at(i)->size() > 1) {
446  stream << "dict_line_" << i;
447  if (i+1 < moveSlotCount()
448  && dictionary_.at(i+1)->size() > 1) {
449  stream << ", ";
450  }
451  }
452  }
453  stream << ")" << endl
454  << indentation(1) << "begin" << endl
455  << indentation(2) << "instructionword <= ";
456  if (haveLimm) {
457  stream << "limm_field&";
458  }
459  for (int i = 0; i < moveSlotCount(); i++) {
460  if (dictionary_.at(i)->size() > 1) {
461  stream << "dict_" << i <<"(dict_line_" << i << ")";
462  } else {
463  stream << "dict_" << i;
464  }
465  if (i+1 < moveSlotCount()) {
466  stream << "&";
467  }
468  }
469  stream << ";" << endl
470  << indentation(1) << "end process;" << endl << endl;
471  }
472 
473  void printDetails() {
474  int widthInBytes = static_cast<int>(
475  std::ceil(compressedWidth_ / 8.0));
476  Application::logStream() << "compressed instruction width: "
477  << compressedWidth_ << " ("
478  << widthInBytes << " bytes)" << endl;
479  std::size_t totalSize = 0;
480  for (unsigned int i = 0; i < dictionary_.size(); i++) {
481  std::size_t index = static_cast<std::size_t>(i);
482  std::size_t keyWidth =
483  MathTools::requiredBits(dictionary_.at(i)->size());
484  std::size_t entrySize = binaryEncoding().width();
485  std::size_t entries = dictionary_.at(i)->size();
486  totalSize += entries * entrySize;
488  << (boost::format(
489  "Dictionary %d:\n"
490  "dictionary width: %d bits, entries: %d, "
491  "dictionary size: %d bits (%d bytes)\n")
492  % index % keyWidth % entries % (entries * entrySize)
493  % std::size_t(
494  std::ceil(entries * entrySize / 8.0))).str();
495  }
497  << (boost::format(
498  "Total dictionary size: %d bits (%d bytes)\n\n")
499  % totalSize
500  % std::size_t(std::ceil(totalSize / 8.0))).str();
501  }
502 
503  /// Map type for dictionary.
504  typedef std::map<BitVector, unsigned int> Dictionary;
505 
506  /// The dictionary.
507  vector<Dictionary*> dictionary_;
508 
509  /// Indicates whether the dictionary has been created
511 
512  /// Total width of compressed instruction (limm fields + move slots)
513  unsigned int compressedWidth_;
514 };
515 
AsciiImageWriter.hh
MoveSlotDictionary::dictionary_
vector< Dictionary * > dictionary_
The dictionary.
Definition: MoveSlotDictionary.cc:507
TTAProgram::Program
Definition: Program.hh:63
MoveSlotDictionary::Dictionary
std::map< BitVector, unsigned int > Dictionary
Map type for dictionary.
Definition: MoveSlotDictionary.cc:504
InstructionBitVector.hh
TTAProgram::NullInstruction
Definition: NullInstruction.hh:45
BitVector
Definition: BitVector.hh:44
MoveSlotDictionary::generateDecompressorProcess
void generateDecompressorProcess(std::ostream &stream, bool &haveLimm)
Definition: MoveSlotDictionary.cc:439
TTAProgram::Instruction
Definition: Instruction.hh:57
MapTools.hh
MoveSlotDictionary::generateDecompressor
virtual void generateDecompressor(std::ostream &stream, TCEString entityStr)
Definition: MoveSlotDictionary.cc:131
ImmediateSlotField.hh
CodeCompressor.hh
Application::verboseLevel
static int verboseLevel()
Definition: Application.hh:176
Application::logStream
static std::ostream & logStream()
Definition: Application.cc:155
MoveSlotDictionary::compressedWidth_
unsigned int compressedWidth_
Total width of compressed instruction (limm fields + move slots)
Definition: MoveSlotDictionary.cc:513
MoveSlotDictionary::createDictionary
void createDictionary()
Definition: MoveSlotDictionary.cc:162
MoveSlot.hh
AsciiImageWriter::writeImage
virtual void writeImage(std::ostream &stream) const
Definition: AsciiImageWriter.cc:73
MoveSlotDictionary::compress
virtual InstructionBitVector * compress(const string &programName)
Definition: MoveSlotDictionary.cc:97
MoveSlotDictionary::generateDecompressorEntity
void generateDecompressorEntity(std::ostream &stream, TCEString entityStr)
Definition: MoveSlotDictionary.cc:314
MoveSlotDictionary::updateDictionary
void updateDictionary(const Program &program)
Definition: MoveSlotDictionary.cc:182
MoveSlotDictionary::generateDecompressorBody
void generateDecompressorBody(std::ostream &stream, bool &haveLimm)
Definition: MoveSlotDictionary.cc:391
MoveSlotDictionary::MoveSlotDictionary
MoveSlotDictionary()
Definition: MoveSlotDictionary.cc:78
BitVector::pushBack
void pushBack(long long unsigned int integer, int size)
Definition: BitVector.cc:94
MoveSlotDictionary::addInstructions
void addInstructions()
Definition: MoveSlotDictionary.cc:220
BinaryEncoding.hh
NullInstruction.hh
MoveSlotDictionary::~MoveSlotDictionary
~MoveSlotDictionary()
Definition: MoveSlotDictionary.cc:85
MoveSlotDictionary
Definition: MoveSlotDictionary.cc:72
MathTools::requiredBits
static int requiredBits(unsigned long int number)
MoveSlotDictionary::generateDecompressorArchitecture
void generateDecompressorArchitecture(std::ostream &stream, TCEString entityStr)
Definition: MoveSlotDictionary.cc:340
MoveSlotDictionary::generateDecompressorSignals
void generateDecompressorSignals(std::ostream &stream, bool &haveLimm)
Definition: MoveSlotDictionary.cc:353
ImmediateControlField.hh
MapTools::containsKey
static bool containsKey(const MapType &aMap, const KeyType &aKey)
MoveSlotDictionary::addToDictionary
void addToDictionary(const BitVector &instructionBits, int slotIndex)
Definition: MoveSlotDictionary.cc:207
Program.hh
false
find Finds info of the inner loops in the false
Definition: InnerLoopFinder.cc:81
MoveSlotDictionary::generateDictionaryVhdl
void generateDictionaryVhdl(std::ostream &stream, TCEString entityStr)
Definition: MoveSlotDictionary.cc:257
EXPORT_CODE_COMPRESSOR
#define EXPORT_CODE_COMPRESSOR(PLUGIN_NAME__)
Definition: CodeCompressor.hh:42
MoveSlotDictionary::dictionaryCreated_
bool dictionaryCreated_
Indicates whether the dictionary has been created.
Definition: MoveSlotDictionary.cc:510
AsciiImageWriter
Definition: AsciiImageWriter.hh:45
CodeCompressorPlugin
Definition: CodeCompressorPlugin.hh:84
TCEString
Definition: TCEString.hh:53
MoveSlotDictionary::evaluateMoveSlotBoundaries
void evaluateMoveSlotBoundaries(vector< pair< int, int > > &boundaries)
Definition: MoveSlotDictionary.cc:424
program
find Finds info of the inner loops in the program
Definition: InnerLoopFinder.cc:80
CodeCompressorPlugin.hh
MathTools.hh
MoveSlotDictionary::printDescription
virtual void printDescription(std::ostream &stream)
Definition: MoveSlotDictionary.cc:143
TPEF
Definition: Assembler.hh:43
MoveSlotDictionary::printDetails
void printDetails()
Definition: MoveSlotDictionary.cc:473
InstructionBitVector
Definition: InstructionBitVector.hh:50