OpenASIP 2.2
Loading...
Searching...
No Matches
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"
50#include "Program.hh"
51#include "BinaryEncoding.hh"
52#include "MoveSlot.hh"
53#include "ImmediateSlotField.hh"
56#include "NullInstruction.hh"
57#include "AsciiImageWriter.hh"
58#include "MapTools.hh"
59#include "MathTools.hh"
60
61using std::vector;
62using std::string;
63using std::endl;
64using std::pair;
65
69using namespace TPEF;
70
71
73public:
74
75 /**
76 * The constructor
77 */
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 */
97 compress(const string& programName) {
98 if (!dictionaryCreated_) {
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 +=
106 }
107 // add limm fields, if any
108 imemWidth += firstMoveSlotIndex();
109 compressedWidth_ = imemWidth;
111
112 if (Application::verboseLevel() > 0 && dictionary_.size() > 0) {
113 printDetails();
114 }
115 }
116 startNewProgram(programName);
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
155private:
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);
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()) {
224 InstructionBitVector* compressedInstruction =
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++) {
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;
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
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 =
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
#define EXPORT_CODE_COMPRESSOR(PLUGIN_NAME__)
find Finds info of the inner loops in the program
find Finds info of the inner loops in the false
static int verboseLevel()
static std::ostream & logStream()
virtual void writeImage(std::ostream &stream) const
virtual int width(const TCEString &templateName) const
void pushBack(long long unsigned int integer, int size)
Definition BitVector.cc:94
InstructionBitVector * bemBits(const TTAProgram::Program &program)
void setImemWidth(int mau, int widthInMaus=1)
TPEFMap::const_iterator programElement(int index) const
void startNewProgram(const std::string &programName)
int moveSlotWidth(int index) const
std::string indentation(int level)
void addInstruction(const TTAProgram::Instruction &instruction, InstructionBitVector *bits)
TTAProgram::Program & currentProgram() const
const BinaryEncoding & binaryEncoding() const
InstructionBitVector * bemInstructionBits(const TTAProgram::Instruction &)
InstructionBitVector * programBits() const
static KeyType keyForValue(const MapType &aMap, const ValueType &aValue)
static bool containsKey(const MapType &aMap, const KeyType &aKey)
static int requiredBits(unsigned long int number)
virtual void printDescription(std::ostream &stream)
void generateDecompressorSignals(std::ostream &stream, bool &haveLimm)
void generateDecompressorArchitecture(std::ostream &stream, TCEString entityStr)
void evaluateMoveSlotBoundaries(vector< pair< int, int > > &boundaries)
void updateDictionary(const Program &program)
virtual void generateDecompressor(std::ostream &stream, TCEString entityStr)
unsigned int compressedWidth_
Total width of compressed instruction (limm fields + move slots)
vector< Dictionary * > dictionary_
The dictionary.
void addToDictionary(const BitVector &instructionBits, int slotIndex)
void generateDecompressorProcess(std::ostream &stream, bool &haveLimm)
void generateDecompressorEntity(std::ostream &stream, TCEString entityStr)
void generateDictionaryVhdl(std::ostream &stream, TCEString entityStr)
bool dictionaryCreated_
Indicates whether the dictionary has been created.
std::map< BitVector, unsigned int > Dictionary
Map type for dictionary.
void generateDecompressorBody(std::ostream &stream, bool &haveLimm)
virtual InstructionBitVector * compress(const string &programName)
Instruction & nextInstruction(const Instruction &) const
Definition Program.cc:403
Instruction & firstInstruction() const
Definition Program.cc:353