OpenASIP 2.2
Loading...
Searching...
No Matches
tpef2pasm.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2021 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 tpef2pasm.cc
26 *
27 * Blocks parallel disassembler.
28 *
29 * @author Kanishkan Vadivel 2021 (k.vadivel-no.spam-tue.nl)
30 * @author Barry de Bruin 2021 (e.d.bruin-no.spam-tue.nl)
31 * @note rating: red
32 */
33
34#include <fstream>
35#include <iostream>
36#include <map>
37
38#include "CompilerWarnings.hh"
39
40IGNORE_COMPILER_WARNING("-Wunused-variable")
41
42#include "ADFSerializer.hh"
43#include "Binary.hh"
44#include "BinaryReader.hh"
45#include "BinaryStream.hh"
46#include "CmdLineOptions.hh"
47#include "ControlUnit.hh"
48#include "DataDefinition.hh"
49#include "DataMemory.hh"
51#include "FUPort.hh"
52#include "FileSystem.hh"
53#include "FunctionUnit.hh"
54#include "HWOperation.hh"
55#include "Immediate.hh"
56#include "Instruction.hh"
57#include "Move.hh"
58#include "Operation.hh"
59#include "POMDisassembler.hh"
60#include "Procedure.hh"
61#include "Program.hh"
62#include "RegisterFile.hh"
63#include "TPEFProgramFactory.hh"
64#include "Terminal.hh"
65#include "TerminalImmediate.hh"
66#include "UniversalMachine.hh"
67#include "tce_config.h"
68
69using std::cerr;
70using std::cout;
71using std::endl;
72
73// ASM map: {FU: {operand: asm}}
74typedef std::map<TCEString, std::map<int, TCEString>> PasmPacket;
75
76/**
77 * Commandline options.
78 */
80public:
82 : CmdLineOptions("Usage: tpef2pasm [options] adffile tpeffile") {
84 "outputfile", "Name of the output file.", "o");
85
87 "stdout", "Print to standard output", "s");
88
90 addOption(toStdout);
91 }
92
93 std::string
95 return findOption("outputfile")->String();
96 }
97
98 bool
100 return findOption("outputfile")->isDefined();
101 }
102
103 bool
105 return findOption("stdout")->isFlagOn();
106 }
107
108 void
109 printVersion() const {
110 std::cout << "tcedisasm - OpenASIP TTA parallel disassembler "
111 << Application::TCEVersionString() << std::endl;
112 }
113
115};
116
117/**
118 * Get FunctionUnit object from FU name
119 *
120 * @param machine Machine for the search
121 * @param fuName Name of the FU to search
122 * @return FunctionUnit object
123 */
128 for (int i = 0; i < fuNav.count(); i++) {
129 if (fuNav.item(i)->name().ciEqual(fuName)) return fuNav.item(i);
130 }
131 return nullptr;
132}
133
134/**
135 * Get RegisterFile object from RF name
136 *
137 * @param machine Machine for the search
138 * @param rfName Name of the RF to search
139 * @return RegisterFile object
140 */
145 for (int i = 0; i < rfNav.count(); i++) {
146 if (rfNav.item(i)->name().ciEqual(rfName)) return rfNav.item(i);
147 }
148 return nullptr;
149}
150
151/**
152 * Get RegisterFile object from RF name
153 *
154 * @param pkt PASM instructions in map form
155 * @param fuSet Pasm header, list of FU names
156 * @param label Procedure start label
157 * @param printHeader Name of the RF to search
158 * @return TCEString PASM string
159 */
162 PasmPacket pkt, std::set<TCEString> fuSet, TCEString label = "",
163 bool printHeader = false) {
164 const int width = 32; // column width in spaces
165 TCEString pasm = "";
166 if (printHeader) {
167 // first row with FU names
168 pasm += "|";
169 for (auto& fu : fuSet) {
170 TCEString pasm_col = " " + fu;
171 int ntabs = width/4 - (pasm_col.size()+1)/4; // 1 tab = 4 spaces
172 for (int i = 0; i < ntabs; i++) pasm_col += "\t";
173 pasm += pasm_col + "|";
174 }
175 pasm += "\n";
176
177 // empty row
178 pasm += "|";
179 for (auto& fu : fuSet) {
180 int ntabs = width/4;
181 for (int i = 0; i < ntabs; i++) pasm += "\t";
182 pasm += "|";
183 }
184 pasm += "\n";
185
186 // .text row
187 pasm += "|";
188 for (auto& fu : fuSet) {
189 TCEString pasm_col = " .text";
190 int ntabs = width/4 - (pasm_col.size()+1)/4;
191 for (int i = 0; i < ntabs; i++) pasm_col += "\t";
192 pasm += pasm_col + "|";
193 }
194 pasm += "\n";
195
196 // empty row
197 pasm += "|";
198 for (auto& fu : fuSet) {
199 int ntabs = width/4;
200 for (int i = 0; i < ntabs; i++) pasm += "\t";
201 pasm += "|";
202 }
203 pasm += "\n";
204
205 } else {
206 pasm += "|";
207
208 int col_idx = 0;
209 for (auto& fu : fuSet) {
210 TCEString pasm_col = "";
211
212 if (!pkt.count(fu))
213 pasm_col += " nop";
214 else {
215 pkt[fu][0].replaceString("copy", "pass");
216 if (pkt[fu][0] == "jump" && pkt[fu][1] == fu+".ra") {
217 pkt[fu][0].replaceString("jump", "ret");
218 pkt[fu][1] = "";
219 }
220 TCEString instr = " " + pkt[fu][0] + " ";
221 for (unsigned op = 1; op < pkt[fu].size(); op++) {
222 instr += pkt[fu][op].replaceString(".ra", ".0"); // .ra register is mapped to out0 (non-registered)
223 if (pkt[fu][op] != "" && op < pkt[fu].size() - 1) instr += ", ";
224 }
225 pasm_col += instr;
226 }
227
228 // Add label to first column, when available
229 if (!label.empty() && col_idx++ == 0) {
230 pasm_col += " ; " + label;
231 }
232
233 // Fix length of column
234 int ntabs = width/4 - (pasm_col.size()+1)/4;
235 for (int i = 0; i < ntabs; i++) pasm_col += "\t"; // 1 tab = 4 spaces
236 pasm += pasm_col + "|";
237 }
238 pasm += "\n";
239 }
240 return pasm;
241}
242
243/**
244 * Get FU output Port name for operation
245 *
246 * @param fu FunctionUnit to search for instruction
247 * @param op Instruction name to search
248 * @return TCEString Output port name
249 */
252 TTAMachine::HWOperation* hwOp = fu->operation(op);
253 for (int i = hwOp->operandCount(); i > 0; i--) {
254 TTAMachine::FUPort* p = hwOp->port(i);
255 if (p->isOutput()) return p->name();
256 }
257 return "";
258}
259
260int
261main(int argc, char* argv[]) {
263
264 try {
265 options.parse(argv, argc);
266 } catch (ParserStopRequest const&) {
267 return 0;
268 } catch (IllegalCommandLine& e) {
269 std::cerr << "Error: Illegal commandline: " << e.errorMessage()
270 << endl
271 << endl;
272
274 return 1;
275 }
276
277 if (options.numberOfArguments() != 2) {
278 std::cerr << "Error: Illegal number of parameters." << endl << endl;
280 return 1;
281 }
282
283 std::string inputFileName = options.argument(2);
284 // Load TPEF.
285 TPEF::BinaryStream stream(inputFileName);
286 TPEF::Binary* tpef = NULL;
287 try {
288 tpef = TPEF::BinaryReader::readBinary(stream);
289 } catch (Exception& e) {
290 cerr << "Can't read TPEF binary file: " << options.argument(2) << endl
291 << e.errorMessage() << endl;
292 return 1;
293 }
294
295 // Load machine.
297 ADFSerializer machineReader;
298 machineReader.setSourceFile(options.argument(1));
299 try {
300 machine = machineReader.readMachine();
301 } catch (Exception& e) {
302 cerr << "Error: " << options.argument(1) << " is not a valid ADF File"
303 << endl
304 << e.errorMessage() << endl;
305
306 delete tpef;
307 return 1;
308 }
309
310 // Create blocks instruction packet header
311 std::set<TCEString> blocksFU;
319 for (int i = 0; i < fuNav.count(); i++) {
320 TCEString fuName = fuNav.item(i)->name();
321 blocksFU.insert(fuName.split("_out")[0]);
322 }
323 for (int i = 0; i < rfNav.count(); i++)
324 blocksFU.insert(rfNav.item(i)->name());
325 for (int i = 0; i < immNav.count(); i++)
326 blocksFU.insert(immNav.item(i)->name());
327 blocksFU.insert(abu->name());
328
329 // Create POM.
331
332 try {
334 program = factory.build();
335 } catch (Exception& e) {
336 // Try if mixed code
337 try {
340 program = factory.build();
341 } catch (Exception& e1) {
342 cerr << "Error: " << e.errorMessage() << " and "
343 << e1.errorMessage() << endl;
344 delete tpef;
345 delete machine;
346 return 1;
347 }
348 }
349
350 std::ostream* output = &std::cout;
351 std::fstream file;
352 std::string outputFileName = options.outputFileDefined()
353 ? options.outputFile()
354 : inputFileName + ".pasm";
355 if (!options.printToStdout()) {
359 file.open(
360 outputFileName.c_str(),
361 std::fstream::trunc | std::fstream::out);
362 output = &file;
364 file.open(
365 outputFileName.c_str(),
366 std::fstream::trunc | std::fstream::out);
367 if (file.is_open()) output = &file;
368 }
369 }
370
371 // Write code section disassembly.
372 POMDisassembler disassembler(*program);
373
374 // assumes instruction addresses always start from 0
375 PasmPacket pasmHeader;
376 TCEString pasm = getPasmPacket(pasmHeader, blocksFU, "", true);
377
378 // Write code section disassembly.
379 for (int p = 0; p < program->procedureCount(); p++) {
380 const TTAProgram::Procedure& proc = program->procedureAtIndex(p);
381 TCEString label = proc.name();
382
383 // Process each instruction
384 for (int i = 0; i < proc.instructionCount(); i++) {
386 // ASM map: {FU: {operand: asm}}
387 PasmPacket asmMap;
388
389 // Generate immediates
390 for (int j = 0; j < instr->immediateCount(); j++) {
391 TTAProgram::Immediate& imm = instr->immediate(j);
392 asmMap[imm.destination().immediateUnit().name()][0] = "imm";
393 asmMap[imm.destination().immediateUnit().name()][1] =
394 std::to_string(imm.value().value().intValue()); // signed value
395 }
396
397 // Generate instructions
398 for (int j = 0; j < instr->moveCount(); j++) {
399 TTAProgram::Move& m = instr->move(j);
400 TTAProgram::Terminal& src = m.source();
402
403 // Input source (bypass) of an operation
404 TCEString srcFUName =
405 src.port().parentUnit()->name().split("_out")[0];
406 TCEString srcPortName = src.port().name();
407 srcPortName = srcPortName.replaceString("out", "");
408 TCEString srcPort = srcFUName + "." + srcPortName;
409
410 // Operand port of FU
417
418 if (srcRF) { // found a load
419 if (!asmMap.count(srcRF->name())) {
420 asmMap[srcRF->name()][0] = "lrm";
421 } else if(asmMap[srcRF->name()][0] == "srm") { // if there is already a store
422 asmMap[srcRF->name()][0] = "lrm_srm";
423 }
424 asmMap[srcRF->name()][1] =
425 "r" + src.toString().split(".")[1];
426 }
427
428 if (dstRF) { // found a store
429 if (!asmMap.count(dstRF->name())) {
430 asmMap[dstRF->name()][0] = "srm";
431 } else if (asmMap[dstRF->name()][0] == "lrm") { // if there is already a load
432 asmMap[dstRF->name()][0] = "lrm_srm";
433 }
434 asmMap[dstRF->name()][2] =
435 "r" + dst.toString().split(".")[1];
436 asmMap[dstRF->name()][3] = srcPort;
437 } else if (dstFU) {
438 TCEString dstPort = dst.port().name();
439 dstPort = dstPort.replaceString("in", "");
440 TCEString dstFUName = dstFU->name().split("_out")[0];
441 if (dst.isTriggering()) {
442 TCEString opName = dst.toString().split(".")[2];
443 asmMap[dstFUName][0] = opName;
444 TCEString outPort = getOutputPort(dstFU, opName);
445 if (!outPort.empty())
446 asmMap[dstFUName][0] += " " + outPort + ",";
447 }
448 int inputPortID = std::stoi(dstPort.split("t")[0]);
449 asmMap[dstFUName][inputPortID] = srcPort;
450 } else {
451 // ABU move. Handle it based on Blocks assumptions
452 std::vector<TCEString> abuParm =
453 dst.toString().split(".");
454 TCEString dstFUName = abu->name().split("_out")[0];
455 if (dst.isRA()) {
456 // Convert to store to RF
457 asmMap[dstFUName][0] = "srm";
458 asmMap[dstFUName][1] = "r1"; // $RA
459 asmMap[dstFUName][2] = srcPort;
460 } else if (dst.isTriggering()) {
461 // Handle control flow calls
462 asmMap[dstFUName][0] = abuParm[2];
463 asmMap[dstFUName][1] = srcPort;
464 } else if (abuParm[1].ciEqual("value")) {
465 // Handle additional param
466 asmMap[dstFUName][2] = srcPort;
467 } else {
468 std::cout << "Parsing failed for: " + dst.toString()
469 << std::endl;
470 assert(false && "unknown format for abu op\n");
471 }
472 }
473 }
474 pasm += getPasmPacket(asmMap, blocksFU, label);
475 label.clear();
476 }
477 }
478 *output << pasm;
479 return 0;
480}
#define assert(condition)
#define IGNORE_COMPILER_WARNING(X)
static std::string outputFileName(const std::string &adfFile)
Definition CreateBEM.cc:77
TTAMachine::Machine * machine
the architecture definition of the estimated processor
find Finds info of the inner loops in the program
static MachInfoCmdLineOptions options
Definition MachInfo.cc:46
TTAMachine::Machine * readMachine()
static std::string TCEVersionString()
virtual bool isFlagOn() const
virtual std::string String(int index=0) const
void parse(char *argv[], int argc)
CmdLineOptionParser * findOption(std::string name) const
virtual std::string argument(int index) const
virtual int numberOfArguments() const
void addOption(CmdLineOptionParser *opt)
void printVersion() const
Definition tpef2pasm.cc:109
virtual ~DisasmCmdLineOptions()
Definition tpef2pasm.cc:114
std::string outputFile()
Definition tpef2pasm.cc:94
std::string errorMessage() const
Definition Exception.cc:123
static bool createFile(const std::string &file)
static bool fileIsWritable(const std::string fileName)
static bool fileIsCreatable(const std::string fileName)
static bool fileExists(const std::string fileName)
virtual void printHelp() const
int intValue() const
Definition SimValue.cc:895
TCEString & replaceString(const std::string &old, const std::string &newString)
Definition TCEString.cc:94
std::vector< TCEString > split(const std::string &delim) const
Definition TCEString.cc:114
static Binary * readBinary(BinaryStream &stream)
virtual TCEString name() const
virtual HWOperation * operation(const std::string &name) const
virtual FUPort * port(int operand) const
ComponentType * item(int index) const
virtual RegisterFileNavigator registerFileNavigator() const
Definition Machine.cc:450
virtual FunctionUnitNavigator functionUnitNavigator() const
Definition Machine.cc:380
virtual ImmediateUnitNavigator immediateUnitNavigator() const
Definition Machine.cc:416
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
virtual bool isOutput() const
Definition Port.cc:308
Unit * parentUnit() const
virtual std::string name() const
Definition Port.cc:141
virtual int instructionCount() const
virtual Instruction & instructionAtIndex(int index) const
TerminalImmediate & value() const
Definition Immediate.cc:103
const Terminal & destination() const
Definition Immediate.cc:92
Move & move(int i) const
Immediate & immediate(int i) const
Terminal & source() const
Definition Move.cc:302
Terminal & destination() const
Definition Move.cc:323
TCEString name() const
Definition Procedure.hh:66
virtual SimValue value() const
virtual bool isRA() const
Definition Terminal.cc:129
virtual bool isTriggering() const
Definition Terminal.cc:298
virtual TCEString toString() const =0
virtual const TTAMachine::Port & port() const
Definition Terminal.cc:378
virtual const TTAMachine::ImmediateUnit & immediateUnit() const
Definition Terminal.cc:240
static UniversalMachine & instance()
void setSourceFile(const std::string &fileName)
int main(int argc, char *argv[])
Definition tpef2pasm.cc:261
TCEString getPasmPacket(PasmPacket pkt, std::set< TCEString > fuSet, TCEString label="", bool printHeader=false)
Definition tpef2pasm.cc:161
TCEString getOutputPort(TTAMachine::FunctionUnit *fu, TCEString op)
Definition tpef2pasm.cc:251
std::map< TCEString, std::map< int, TCEString > > PasmPacket
Definition tpef2pasm.cc:74
TTAMachine::RegisterFile * getRegisterFile(TTAMachine::Machine *machine, TCEString rfName)
Definition tpef2pasm.cc:142
TTAMachine::FunctionUnit * getFunctionUnit(TTAMachine::Machine *machine, TCEString fuName)
Definition tpef2pasm.cc:125