OpenASIP 2.2
Loading...
Searching...
No Matches
UniversalFunctionUnit.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 UniversalFunctionUnit.cc
26 *
27 * Implementation of UniversalFunctionUnit class.
28 *
29 * @author Lasse Laasonen 2004 (lasse.laasonen-no.spam-tut.fi)
30 * @author Pekka Jääskeläinen 2006 (pekka.jaaskelainen-no.spam-tut.fi)
31 * @note rating: yellow
32 */
33
35#include "UniversalMachine.hh"
36#include "UniversalFUPort.hh"
37#include "HWOperation.hh"
38#include "SmartHWOperation.hh"
39#include "OperationPool.hh"
40#include "Operation.hh"
41#include "TCEString.hh"
42#include "Conversion.hh"
43
44using std::string;
45using namespace TTAMachine;
46
47const string UniversalFunctionUnit::OC_SETTING_PORT_32 = "OCSetting32";
48const string UniversalFunctionUnit::OC_SETTING_PORT_64 = "OCSetting64";
50 "ADD", "SUB", "LDW", "LDQ", "LDH", "STW", "STQ", "STH", "EQ", "GT",
51 "GTU", "SHL", "SHR", "SHRU", "AND", "IOR", "XOR", "SYS", "JUMP", "CALL",
52 "MIN", "MAX", "MINU", "MAXU", "SXQW", "SXHW", "NEG", "MUL", "DIV",
53 "DIVU", "CFI", "CIF", "ROTL", "ROTR", "ABS", "LDQU", "LDHU"};
54
55
56/**
57 * The constructor.
58 *
59 * @param name Name of the function unit.
60 * @param opPool The operation pool from which the operations are obtained on
61 * demand.
62 * @exception InvalidName If the given name is not a valid component name.
63 */
65 const std::string& name, OperationPool& opPool)
66 : FunctionUnit(name), opPool_(opPool) {}
67
68/**
69 * The destructor.
70 */
73
74
75/**
76 * Tells whether the universal function unit has an operation of the given
77 * name.
78 *
79 * Returns true even if the operation is not loaded yet but it exists in
80 * the operation pool.
81 *
82 * @param name Name of the operation.
83 */
84bool
85UniversalFunctionUnit::hasOperation(const std::string& name) const {
86 return &opPool_.operation(name.c_str()) != &NullOperation::instance();
87}
88
89
90/**
91 * Returns an operation by the given name.
92 *
93 * Adds the operation to the function unit if it doen't exist yet but
94 * exist in the operation pool.
95 *
96 * @param name Name of the operation.
97 * @exception InstanceNotFound If an operation by the given name does not
98 * exist in the operation pool.
99 * @return The operation.
100 */
102UniversalFunctionUnit::operation(const std::string& name) const {
103 const string procName = "UniversalFunctionUnit::operation";
104
107 } else {
108 Operation& oper = opPool_.operation(name.c_str());
109
110 if (&oper == &NullOperation::instance()) {
111 throw InstanceNotFound(__FILE__, __LINE__, procName);
112 } else {
113 // need to take non-const pointer of this FU to call non-const
114 // method addOperation
115 UniversalFunctionUnit* thisFU =
116 const_cast<UniversalFunctionUnit*>(this);
117 SmartHWOperation& hwOper = thisFU->addSupportedOperation(oper);
118 return &hwOper;
119 }
120 }
121}
122
123/**
124 * Aborts the program. It should not be needed to add pipeline
125 * elements to universal function unit.
126 *
127 * @param element Never used.
128 * @exception ComponentAlreadyExists Never thrown.
129 */
130void
132 const string procName = "UniversalFunctionUnit::addPipelineElement";
133 const string errorMsg =
134 "Tried to add pipeline element to UniversalFunctionUnit!";
135 Application::writeToErrorLog(__FILE__, __LINE__, procName, errorMsg);
137}
138
139/**
140 * Aborts the program. It is not allowed to load UniversalFunctionUnit from
141 * an ObjectState instance. DO NOT CALL THIS METHOD!
142 *
143 * @param state Never used.
144 * @exception ObjectStateLoadingException Never thrown.
145 */
146void
148 const string procName = "UniversalFunctionUnit::loadState";
149 const string errorMsg =
150 "Tried to load state of UniversalFunctionUnit from an ObjectState "
151 "tree!";
152 Application::writeToErrorLog(__FILE__, __LINE__, procName, errorMsg);
154}
155
156/**
157 * Returns the number of ports of the given bit width.
158 *
159 * @param width The bit width.
160 * @return The number of ports of the given bit width.
161 * @exception OutOfRange If the given bit width is out of range.
162 */
163int
165 if (width < 1) {
166 const string procName = "UniversalFunctionUnit::portCount";
167 throw OutOfRange(__FILE__, __LINE__, procName);
168 }
169
170 int count(0);
171
172 for (int i = 0; i < FunctionUnit::portCount(); i++) {
173 if (FunctionUnit::port(i)->width() == width) {
174 count++;
175 }
176 }
177
178 return count;
179}
180
181/**
182 * By the given index, returns a port which has the given bit width.
183 *
184 * @param index The index.
185 * @param width The bit width.
186 * @return A port of the given bit width.
187 * @exception OutOfRange If the given bit width or index is out of range.
188 */
189FUPort&
190UniversalFunctionUnit::portWithWidth(int index, int width) const {
191 if (width < 1 || index >= portCountWithWidth(width)) {
192 const string procName = "UniversalFunctionUnit::port";
193 throw OutOfRange(__FILE__, __LINE__, procName);
194 }
195
196 int count(0);
197 int portC = portCount();
198 for (int i = 0; i < portC; i++) {
199 auto p = port(i);
201 dynamic_cast<FUPort*>(p);
202 if (p != nullptr && port->width() == width) {
203 count++;
204 if (count > index) {
205 return *port;
206 }
207 }
208 }
209
210 assert(false);
211
212 // dummy return to avoid compilation warning
213 FUPort* port = NULL;
214 return *port;
215}
216
217/**
218 * Adds the given operation to the function unit.
219 *
220 * Adds input and/or output ports if there is not enough ports for the
221 * operands of the given operation. Operand bindings and pipeline are not
222 * created.
223 *
224 * @param operation The operation to be added.
225 * @return The added operation.
226 */
229
230 int inputCount = operation.numberOfInputs();
231 int outputCount = operation.numberOfOutputs();
232
233 int operandWidth = is32BitOperation(operation.name()) ? 32 : 64;
234
235 ensureInputPorts(operandWidth, inputCount);
236 ensureOutputPorts(operandWidth, outputCount);
237
238 // create the operation
239 SmartHWOperation* hwOper = NULL;
240 try {
241 hwOper = new SmartHWOperation(operation, *this);
242 return *hwOper;
243 } catch (const InvalidName& exception) {
244 const string procName = "UniversalFunctionUnit::addOperation";
245 const string errorMsg =
246 "Operation pool contained an operation with illegal"
247 "name: " + string(operation.name());
248 Application::writeToErrorLog(__FILE__, __LINE__, procName, errorMsg);
250 } catch (...) {
251 assert(false);
252 }
253
254 assert(false);
255
256 // dummy return to avoid compilation warning
257 return *hwOper;
258}
259
260
261/**
262 * Ensures that there is at least the given number of input ports of the
263 * given width.
264 *
265 * Adds input ports if there is not enough ports.
266 *
267 * @param width Bit width of the ports to be ensured.
268 * @param count The number of ports to be ensured.
269 */
270void
272
273 assert(width == 32 || width == 64);
274
275 Socket* inputSocket = machine()->socketNavigator().item(
277
278 int portCount = this->portCountWithWidth(width);
279
280 // create opcode setting port if there are no ports at all
281 if (count > 0 && portCount == 0) {
282 string portName =
284 FUPort* ocPort = new UniversalFUPort(
285 portName, width, *this, true, true);
286 portCount++;
287 ocPort->attachSocket(*inputSocket);
288 }
289
290 // check the amount of matches
291 int matches(1);
292 for (int i = 1; i < portCount; i++) {
293 FUPort& port = this->portWithWidth(i, width);
294 assert(port.width() == width);
295 if (port.inputSocket() != NULL) {
296 matches++;
297 }
298 }
299
300 // create new ports as necessary
301 while (matches < count) {
302 string portName = "i" + Conversion::toString(width) + "_" +
303 Conversion::toString(matches);
304 FUPort* newPort = new UniversalFUPort(
305 portName, width, *this, false, false);
306 newPort->attachSocket(*inputSocket);
307 matches++;
308 }
309}
310
311
312/**
313 * Ensures that there is at least the given number of output ports of the
314 * given width.
315 *
316 * Adds output ports if there is not enough ports.
317 *
318 * @param width Bit width of the ports to be ensured.
319 * @param count The number of ports to be ensured.
320 */
321void
323
324 Socket* outputSocket =
326
327 // check the amount of matches
328 int matches(0);
329 for (int i = 0; i < portCountWithWidth(width); i++) {
330 FUPort& port = this->portWithWidth(i, width);
331 assert(port.width() == width);
332 if (port.outputSocket() != NULL) {
333 matches++;
334 }
335 }
336
337 // create new ports as necessary
338 while (matches < count) {
339 string portName = "output" + Conversion::toString(width) + "_" +
340 Conversion::toString(matches + 1);
341 FUPort* newPort = new UniversalFUPort(
342 portName, width, *this, false, false);
343 newPort->attachSocket(*outputSocket);
344 matches++;
345 }
346}
347
348
349/**
350 * Tells whether operation of the given name has 32 bits wide operands and
351 * return value.
352 *
353 * @param opName Name of the operation.
354 * @return True if the operation has 32 bits wide operands and return value,
355 * otherwise false.
356 */
357bool
358UniversalFunctionUnit::is32BitOperation(const std::string& opName) {
359 int numberOfElements = sizeof(OPERATIONS_OF_32_BITS) / sizeof(string);
360 for (int i = 0; i < numberOfElements; i++) {
361 if (OPERATIONS_OF_32_BITS[i] == opName) {
362 return true;
363 }
364 }
365 return false;
366}
#define assert(condition)
#define UM_OUTPUT_SOCKET_NAME
#define UM_INPUT_SOCKET_NAME
static void abortProgram() __attribute__((noreturn))
static void writeToErrorLog(const std::string fileName, const int lineNumber, const std::string functionName, const std::string message, const int neededVerbosity=0)
static std::string toString(const T &source)
static NullOperation & instance()
Operation & operation(const char *name)
virtual int width() const
virtual Machine * machine() const
virtual TCEString name() const
virtual HWOperation * operation(const std::string &name) const
virtual bool hasOperation(const std::string &name) const
virtual BaseFUPort * port(const std::string &name) const
const std::string & name() const
ComponentType * item(int index) const
virtual SocketNavigator socketNavigator() const
Definition Machine.cc:368
virtual Socket * outputSocket() const
Definition Port.cc:281
virtual void attachSocket(Socket &socket)
Definition Port.cc:191
virtual Socket * inputSocket() const
Definition Port.cc:261
virtual int portCount() const
Definition Unit.cc:135
virtual TTAMachine::HWOperation * operation(const std::string &name) const
static const std::string OPERATIONS_OF_32_BITS[]
Table of names of 32 bit operations.
int portCountWithWidth(int width) const
static const std::string OC_SETTING_PORT_64
Name of the 64 bit wide opcode setting port.
UniversalFunctionUnit(const std::string &name, OperationPool &opPool)
virtual void addPipelineElement(TTAMachine::PipelineElement &element)
static bool is32BitOperation(const std::string &opName)
static const std::string OC_SETTING_PORT_32
Name of the 32 bit wide opcode setting port.
void ensureInputPorts(int width, int count)
OperationPool & opPool_
Operation pool from which the operations are searched.
SmartHWOperation & addSupportedOperation(const Operation &operation)
virtual bool hasOperation(const std::string &name) const
virtual void loadState(const ObjectState *state)
void ensureOutputPorts(int width, int count)
TTAMachine::FUPort & portWithWidth(int index, int width) const