OpenASIP 2.2
Loading...
Searching...
No Matches
ProcessorGenerator.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2011 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 ProcessorGenerator.cc
26 *
27 * Implementation of ProcessorGenerator class.
28 *
29 * @author Lasse Laasonen 2005 (lasse.laasonen-no.spam-tut.fi)
30 * @author Esa Määttä 2007 (esa.maatta-no.spam-tut.fi)
31 * @author Otto Esko 2010 (otto.esko-no.spam-tut.fi)
32 * @author Pekka Jääskeläinen 2011
33 * @author Vinogradov Viacheslav(added Verilog generating) 2012
34 * @note rating: red
35 */
36
37#include <algorithm>
38#include <boost/format.hpp>
39#include <cmath>
40#include <fstream>
41#include <iostream>
42#include <list>
43#include <set>
44#include <string>
45
46#include "BlockSourceCopier.hh"
47#include "CUOpcodeGenerator.hh"
49#include "Netlist.hh"
50#include "NetlistBlock.hh"
51#include "NetlistGenerator.hh"
52#include "NetlistPort.hh"
53#include "NetlistPortGroup.hh"
55#include "ProcessorGenerator.hh"
56#include "VHDLNetlistWriter.hh"
57#include "BlockSourceCopier.hh"
58#include "CUOpcodeGenerator.hh"
60
61#include "AddressSpace.hh"
62#include "Application.hh"
63#include "BEMGenerator.hh"
64#include "BinaryEncoding.hh"
65#include "ControlUnit.hh"
66#include "FUPort.hh"
67#include "FUPortCode.hh"
68#include "FunctionUnit.hh"
69#include "HDBManager.hh"
70#include "HDBRegistry.hh"
71#include "HWOperation.hh"
72#include "Machine.hh"
74#include "MachineInfo.hh"
76#include "MachineValidator.hh"
78#include "NetlistFactories.hh"
79#include "NetlistTools.hh"
80#include "ProGeContext.hh"
81#include "RFArchitecture.hh"
82#include "RFEntry.hh"
84
85#include "Environment.hh"
86#include "FileSystem.hh"
87#include "MathTools.hh"
88
89#include "Conversion.hh"
90#include "StringTools.hh"
91
92#include "ProGeOptions.hh"
93
94#include "FUGen.hh"
95
96using boost::format;
97using std::endl;
98using std::set;
99using std::string;
100using namespace TTAMachine;
101using namespace IDF;
102using namespace HDB;
103
104const string CALL = "CALL";
105const string JUMP = "JUMP";
106
107namespace ProGe {
108
110
111/**
112 * The constructor.
113 */
115
116/**
117 * The destructor.
118 */
123
124/**
125 * Generates the processor.
126 *
127 * @see ProGeUI::generateProcessor()
128 */
129void
133 ICDecoderGeneratorPlugin& plugin, int imemWidthInMAUs,
134 std::ostream& errorStream, std::ostream& warningStream,
135 std::ostream& verboseStream) {
136 entityStr_ = options.entityName;
138 machine, implementation, options.outputDirectory,
139 options.sharedOutputDirectory, options.entityName, options.language,
140 imemWidthInMAUs);
141
142 // validate the machine
143 validateMachine(machine, errorStream, warningStream);
144 // check the compatibility of the plugin
145 plugin.verifyCompatibility();
146 // check that IU implementation latencies are compatible with the
147 // IC/GCU plugin
149
150 NetlistGenerator netlistGenerator(*generatorContext_, plugin);
151 coreTopBlock_ = netlistGenerator.generate(
152 options, imemWidthInMAUs, options.entityName, warningStream);
153
154 bool created = FileSystem::createDirectory(options.outputDirectory);
155 if (!created) {
156 string errorMsg =
157 "Unable to create directory " + options.outputDirectory;
158 throw IOException(__FILE__, __LINE__, __func__, errorMsg);
159 }
160
161 string pluginDstDir =
162 options.outputDirectory + FileSystem::DIRECTORY_SEPARATOR + "gcu_ic";
163 created = FileSystem::createDirectory(pluginDstDir);
164 if (!created) {
165 string errorMsg = "Unable to create directory " + pluginDstDir;
166 throw IOException(__FILE__, __LINE__, __func__, errorMsg);
167 }
168
169 plugin.generate(
170 options.language, pluginDstDir, netlistGenerator, implementation,
171 options.entityName);
172
173 // Generate generatable FU implementations.
174 std::vector<std::string> globalOptions;
175 globalOptions.emplace_back("active low reset");
176 globalOptions.emplace_back("asynchronous reset");
177 globalOptions.emplace_back("reset everything");
179 options, globalOptions, generatorContext_->idf().FUGenerations(),
181
182 coreTopBlock_->write(Path(options.outputDirectory), options.language);
183
184 string topLevelDir = options.outputDirectory +
186 (options.language == VHDL ? "vhdl" : "verilog");
187
190 *coreTopBlock_, verboseStream);
191
192 if (!FileSystem::fileExists(options.sharedOutputDirectory)) {
193 if (!FileSystem::createDirectory(options.sharedOutputDirectory)) {
194 string errorMsg = "Unable to create directory " +
195 options.sharedOutputDirectory + ".";
196 throw IOException(__FILE__, __LINE__, __func__, errorMsg);
197 }
198 }
199 BlockSourceCopier copier(
200 implementation, options.entityName, options.language);
201
202 if (machine.isRISCVMachine()) {
204 "decomp-fetchblock-width", "INSTRUCTIONWIDTH");
205 }
206
207 copier.copyShared(options.sharedOutputDirectory);
208 copier.copyProcessorSpecific(options.outputDirectory);
210 options.language, machine,
211 options.outputDirectory + FileSystem::DIRECTORY_SEPARATOR + "gcu_ic");
212
214 options.language, machine, imemWidthInMAUs, topLevelDir, plugin);
215}
216
217/**
218 * Generates the package that defines global constants used in processor
219 * definition files.
220 *
221 * @param language The language of the hardware code, VHDL/Verilog
222 * @param machine The machine.
223 * @param imemWidthInMAUs Width of the instruction memory in MAUs.
224 * @param dstDirectory The destination directory.
225 * @param plugin The ICDecoderGeneratorPlugin, which gives us bem and bit
226 * info
227 * @exception IOException If an IO error occurs.
228 */
229void
231 HDL language, const TTAMachine::Machine& machine, int imemWidthInMAUs,
232 const std::string& dstDirectory, ICDecoderGeneratorPlugin& plugin) {
233 string dstFile = dstDirectory + FileSystem::DIRECTORY_SEPARATOR +
234 entityName() + "_globals_pkg." +
235 ((language == ProGe::VHDL) ? "vhdl" : "vh");
236
237 bool created = FileSystem::createFile(dstFile);
238 if (!created) {
239 string errorMsg = "Unable to create file " + dstFile;
240 throw IOException(__FILE__, __LINE__, __func__, errorMsg);
241 }
242 std::ofstream stream(dstFile.c_str(), std::ofstream::out);
243
244 if (language == ProGe::VHDL) {
245 int bustrace_width = 0;
246 for (int i = 0; i < machine.busNavigator().count(); ++i) {
247 int bus_width = machine.busNavigator().item(i)->width();
248 // Busess are padded to a multiple of 32 bits
249 bus_width = (bus_width + 31) / 32 * 32;
250 bustrace_width += bus_width;
251 }
252
253 stream << "library work;" << endl
254 << "use work." << entityStr_ << "_imem_mau.all;" << endl
255 << endl;
256
257 stream << "package " << entityStr_ << "_globals is" << endl
258 << " -- address width of the instruction memory" << endl
259 << " constant IMEMADDRWIDTH : positive := "
260 << iMemAddressWidth(machine) << ";" << endl
261 << " -- width of the instruction memory in MAUs" << endl
262 << " constant IMEMWIDTHINMAUS : positive := "
263 << imemWidthInMAUs << ";" << endl
264 << " -- width of instruction fetch block." << endl
265 << " constant IMEMDATAWIDTH : positive := "
266 << "IMEMWIDTHINMAUS*IMEMMAUWIDTH;" << endl
267 << " -- clock period" << endl
268 << " constant PERIOD : time := 10 ns;" << endl
269 << " -- number of busses." << endl
270 << " constant BUSTRACE_WIDTH : positive := " << bustrace_width
271 << ";" << endl;
272
273 // Insert plugin specific global package constants
274 plugin.writeGlobalDefinitions(ProGe::VHDL, stream);
275
276 stream << "end " << entityStr_ << "_globals;" << endl;
277
278 } else if (language == ProGe::Verilog) {
279 // todo add IMEMDATAWIDTH constant here too.
280
281 stream << "// address width of the instruction memory" << endl
282 << "parameter IMEMADDRWIDTH = " << iMemAddressWidth(machine)
283 << "," << endl
284 << "// width of the instruction memory in MAUs" << endl
285 << "parameter IMEMWIDTHINMAUS = " << imemWidthInMAUs << ","
286 << endl
287 << "// clock period" << endl
288 << "parameter PERIOD = 10," << endl; // 10 will equal 10ns
289
291
292 } else {
293 abortWithError("Unsupported HDL.");
294 }
295 stream.close();
296}
297
298/**
299 * Generates the package that defines opcodes of Global Control Unit.
300 *
301 * @param language The language of the hardware code, VHDL/Verilog
302 * @param machine The machine.
303 * @param dstDirectory The destination directory.
304 */
305void
307 HDL language, const TTAMachine::Machine& machine,
308 const std::string& dstDirectory) {
309 string dstFile = dstDirectory + FileSystem::DIRECTORY_SEPARATOR +
310 "gcu_opcodes_pkg." +
311 ((language == ProGe::VHDL) ? "vhdl" : "vh");
312 std::ofstream stream(dstFile.c_str(), std::ofstream::out);
313 CUOpcodeGenerator gcuOpcodeGen(machine, entityStr_);
314 gcuOpcodeGen.generateOpcodePackage(language, stream);
315 stream.close();
316}
317
318const NetlistPortGroup*
323
324/**
325 * Validates the machine for compatibility with the given block
326 * implementations.
327 *
328 * If the target architecture contains errors (incomplete definition) or
329 * if its structure is not compatible with this HDL generator, this method
330 * throws IllegalMachine exception. For less serious errors (such as
331 * non-critical bit width discrepancies), warning messages are written to
332 * the given stream.
333 *
334 * @param machine The machine to validate.
335 * @param errorStream Output stream where errors are printed
336 * @param warningStream Output stream where warnings are printed
337 * @exception IllegalMachine If there is a fundamental error in the
338 * machine.
339 */
340void
342 const TTAMachine::Machine& machine, std::ostream& errorStream,
343 std::ostream& warningStream) {
344 MachineValidator validator(machine);
345 set<MachineValidator::ErrorCode> errorsToCheck;
346 errorsToCheck.insert(MachineValidator::GCU_MISSING);
347 errorsToCheck.insert(MachineValidator::GCU_AS_MISSING);
348 errorsToCheck.insert(MachineValidator::USED_IO_NOT_BOUND);
350 errorsToCheck.insert(MachineValidator::PC_PORT_MISSING);
351 errorsToCheck.insert(MachineValidator::RA_PORT_MISSING);
352 errorsToCheck.insert(
354 // we should not check for this as the designer is not supposed to
355 // know the width of these ports before the design has been finalized,
356 // thus we generate them automatically in ProGe
357 // errorsToCheck.insert(
358 // MachineValidator::IMEM_ADDR_WIDTH_DIFFERS_FROM_RA_AND_PC);
359
360 MachineValidatorResults* results = validator.validate(errorsToCheck);
361
362 for (int i = 0; i < results->errorCount(); i++) {
363 MachineValidator::ErrorCode code = results->error(i).first;
364 string errorMsg = results->error(i).second;
365 if (code ==
367 warningStream << "Warning: " << errorMsg
368 << " ProGe uses the value set in the address space."
369 << endl;
370 } else {
371 string msg = "Error: " + errorMsg;
372 errorStream << msg << std::endl;
373 delete results;
374 throw IllegalMachine(__FILE__, __LINE__, __func__, msg);
375 }
376 }
377 delete results;
378}
379
380/**
381 * Checks that the latencies of the HW implementations of the immediate
382 * units are compatible with the given IC/GCU generator plugin.
383 *
384 * @param machine The machine.
385 * @param implementation The machine implementation.
386 * @param plugin The plugin.
387 * @exception InvalidData If the latencies are incompatible.
388 */
389void
393 const ICDecoderGeneratorPlugin& plugin) {
395 for (int i = 0; i < iuNav.count(); i++) {
396 ImmediateUnit* iu = iuNav.item(i);
399
400 RFEntry* entry = NULL;
401 try {
402 HDBManager& manager = HDBRegistry::instance().hdb(impl.hdbFile());
403 entry = manager.rfByEntryID(impl.id());
404 } catch (const KeyNotFound& e) {
405 throw InvalidData(__FILE__, __LINE__, __func__, e.errorMessage());
406 }
407
408 if (!entry->hasArchitecture()) {
409 delete entry;
410 format text(
411 "RF entry %1% does not have architecture defined in HDB "
412 "%2%.");
413 text % impl.id() % impl.hdbFile();
414 throw InvalidData(__FILE__, __LINE__, __func__, text.str());
415 }
416
417 RFArchitecture& architecture = entry->architecture();
418 int implLatency = architecture.latency();
419 std::set<int> requiredLatencies = plugin.requiredRFLatencies(*iu);
420 delete entry;
421
422 if (requiredLatencies.count(implLatency) == 0) {
423 format errorMsg(
424 "Latency of the implementation of immediate "
425 "unit %1% is %2%,"
426 " acceptable latencies are %3%.");
427 errorMsg % iu->name() % implLatency %
428 TCEString::makeString(requiredLatencies);
429 throw InvalidData(__FILE__, __LINE__, __func__, errorMsg.str());
430 }
431 }
432}
433
434/**
435 * Returns the width of the memory address of instruction memory of the
436 * given machine.
437 *
438 * If the memory address width set in machine instruction memory address
439 * space differ from gcu port widths, the value set in the address space
440 * is used. In this case, GCU port widths are changed accordingly.
441 *
442 * @param mach The machine.
443 * @return The bit width.
444 * @exception InvalidData If the GCU of the machine does not have an
445 * address
446 * space.
447 */
448int
450 ControlUnit* gcu = mach.controlUnit();
451 // must have been already caught in main method: generateProcessor
452 assert(gcu != NULL);
453
454 AddressSpace* iMem = gcu->addressSpace();
455 // must have been already caught in main method: generateProcessor
456 assert(iMem != NULL);
457
458 int imemASWidth = MathTools::requiredBits(iMem->end());
459 // if gcu port have different width than imemASWidth, change port
460 // widths
461 if (gcu->hasReturnAddressPort()) {
462 int gcuRAPortWidth = gcu->returnAddressPort()->width();
463 if (gcuRAPortWidth != imemASWidth) {
464 gcu->returnAddressPort()->setWidth(imemASWidth);
465 }
466 }
467 if (gcu->hasOperation(CALL)) {
468 FUPort* pcPort = gcu->operation(CALL)->port(1);
469 if (pcPort != NULL) {
470 if (pcPort->width() != imemASWidth) {
471 pcPort->setWidth(imemASWidth);
472 }
473 }
474 } else if (gcu->hasOperation(JUMP)) {
475 FUPort* pcPort = gcu->operation(JUMP)->port(1);
476 if (pcPort != NULL) {
477 if (pcPort->width() != imemASWidth) {
478 pcPort->setWidth(imemASWidth);
479 }
480 }
481 }
482
483 return imemASWidth;
484}
485
486/**
487 * Returns the width of the instruction memory of the given machine.
488 *
489 * @param mach The machine.
490 * @return The bit width.
491 */
492int
494 const TTAMachine::Machine& mach, int imemWidthInMAUs) {
495 ControlUnit* gcu = mach.controlUnit();
496 // must have been already caught in main method: generateProcessor
497 assert(gcu != NULL);
498
499 AddressSpace* iMem = gcu->addressSpace();
500 // must have been already caught in main method: generateProcessor
501 assert(iMem != NULL);
502
503 return iMem->width() * imemWidthInMAUs;
504}
505
506/**
507 * Returns Toplevel block of the core.
508 */
509const NetlistBlock&
513
514/**
515 * Returns the context (adf, idf, entity name, etc.) that is used in the
516 * processor generation.
517 */
518const ProGeContext&
522
527
528void
530 TTAMachine::Machine& machine, std::ostream& warningStream) {
532 std::list<string> removedSockets;
533 modifier.removeNotConnectedSockets(machine, removedSockets);
534
535 for (std::list<string>::iterator i = removedSockets.begin();
536 i != removedSockets.end(); i++) {
537 warningStream << "Warning: Removed unconnected socket " << *i
538 << std::endl;
539 }
540}
541
542} // namespace ProGe
#define __func__
#define abortWithError(message)
#define assert(condition)
IDF::MachineImplementation * implementation
the implementation definition of the estimated processor
TTAMachine::Machine * machine
the architecture definition of the estimated processor
static MachInfoCmdLineOptions options
Definition MachInfo.cc:46
const string JUMP
const string CALL
const string JUMP
const string CALL
static bool spamVerbose()
std::string errorMessage() const
Definition Exception.cc:123
static void implement(const ProGeOptions &options, std::vector< std::string > globalOptions, const std::vector< IDF::FUGenerated > &generatetFUs, const TTAMachine::Machine &machine, ProGe::NetlistBlock *core)
Definition FUGen.cc:1515
static bool createFile(const std::string &file)
static bool createDirectory(const std::string &path)
static const std::string DIRECTORY_SEPARATOR
static bool fileExists(const std::string fileName)
RFEntry * rfByEntryID(RowID id) const
static HDBRegistry & instance()
CachedHDBManager & hdb(const std::string fileName)
RFArchitecture & architecture() const
Definition RFEntry.cc:145
virtual bool hasArchitecture() const
Definition RFEntry.cc:117
void replacePlaceholder(const std::string &key, const std::string &replacer, bool append=false)
RFImplementationLocation & iuImplementation(const std::string &iu) const
const std::vector< FUGenerated > & FUGenerations() const
void removeNotConnectedSockets(TTAMachine::Machine &mach, std::list< std::string > &removedSocketNames)
MachineValidatorResults * validate(const std::set< ErrorCode > &errorsToCheck) const
ErrorCode
Error codes for different errors.
@ PC_AND_RA_PORTS_HAVE_UNEQUAL_WIDTH
RA and PC ports have unequal width.
@ IMEM_ADDR_WIDTH_DIFFERS_FROM_RA_AND_PC
Instruction memory address width differs from PC/RA port width.
@ GCU_AS_MISSING
Address space missing in GCU.
@ DIFFERENT_PORT_FOR_JUMP_AND_CALL
JUMP and CALL uses different port in GCU.
@ RA_PORT_MISSING
RA port missing in GCU.
@ USED_IO_NOT_BOUND
Pipeline uses an IO which is not bound.
@ GCU_MISSING
GCU missing in machine.
@ PC_PORT_MISSING
PC port missing in GCU.
static int requiredBits(unsigned long int number)
virtual std::vector< const NetlistPortGroup * > portGroupsBy(SignalGroupType type) const
void copyShared(const std::string &dstDirectory)
HDLTemplateInstantiator & getTemplateInstatiator()
void copyProcessorSpecific(const std::string &dstDirectory)
void generateOpcodePackage(HDL language, std::ofstream &stream) const
virtual std::set< int > requiredRFLatencies(const TTAMachine::ImmediateUnit &iu) const =0
virtual void writeGlobalDefinitions(HDL language, std::ostream &pkgStream) const =0
virtual void generate(HDL language, const std::string &destinationDirectory, const NetlistGenerator &generator, const IDF::MachineImplementation &implementation, const std::string &entityString)=0
virtual void verifyCompatibility() const =0
virtual void write(const Path &targetBaseDir, HDL targetLang=VHDL) const override
NetlistBlock * generate(const ProGeOptions &options, int imemWidthInMAUs, TCEString entityNameStr, std::ostream &warningStream)
static void visualizeBlockTree(const BaseNetlistBlock &root, std::ostream &streamOut)
const IDF::MachineImplementation & idf() const
const TTAMachine::Machine & adf() const
const ProGeContext & generatorContext() const
static int iMemWidth(const TTAMachine::Machine &mach, int imemWidthInMAUs)
void generateGCUOpcodesPackage(HDL language, const TTAMachine::Machine &machine, const std::string &dstDirectory)
void generateGlobalsPackage(HDL language, const TTAMachine::Machine &machine, int imemWidthInMAUs, const std::string &dstDirectory, ICDecoderGeneratorPlugin &plugin)
void validateMachine(const TTAMachine::Machine &machine, std::ostream &errorStream, std::ostream &warningStream)
void checkIULatencies(const TTAMachine::Machine &machine, const IDF::MachineImplementation &implementation, const ICDecoderGeneratorPlugin &plugin)
static void removeUnconnectedSockets(TTAMachine::Machine &machine, std::ostream &warningStream)
const NetlistBlock & processorTopLevel() const
static int iMemAddressWidth(const TTAMachine::Machine &mach)
void generateProcessor(const ProGeOptions &options, const TTAMachine::Machine &machine, const IDF::MachineImplementation &implementation, ICDecoderGeneratorPlugin &plugin, int imemWidthInMAUs, std::ostream &errorStream, std::ostream &warningStream, std::ostream &verboseStream)
static const NetlistPortGroup * instructionBus(NetlistBlock &block)
static const TCEString DEFAULT_ENTITY_STR
static std::string makeString(const IterableContainer &container, const std::string &separator=", ")
virtual ULongWord end() const
virtual int width() const
virtual int width() const
void setWidth(int width)
virtual TCEString name() const
SpecialRegisterPort * returnAddressPort() const
bool hasReturnAddressPort() const
virtual AddressSpace * addressSpace() const
virtual HWOperation * operation(const std::string &name) const
virtual bool hasOperation(const std::string &name) const
virtual FUPort * port(int operand) const
ComponentType * item(int index) const
virtual ImmediateUnitNavigator immediateUnitNavigator() const
Definition Machine.cc:416
virtual BusNavigator busNavigator() const
Definition Machine.cc:356
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
bool isRISCVMachine() const
Definition Machine.cc:1057
Definition FUGen.hh:54
@ INSTRUCTION_LINE
Signal group type for serial TTA instruction bus.
HDL
HDLs supported by ProGe.
Definition ProGeTypes.hh:40
@ Verilog
Verilog.
Definition ProGeTypes.hh:42
@ VHDL
VHDL.
Definition ProGeTypes.hh:41