OpenASIP 2.2
Loading...
Searching...
No Matches
Classes | Public Member Functions | Static Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
FUGen Class Reference

#include <FUGen.hh>

Collaboration diagram for FUGen:
Collaboration graph

Classes

struct  BaseOperation
 
struct  DAGConstant
 
struct  OperandConnection
 
struct  OperationSchedule
 
struct  OutputConnection
 

Public Member Functions

 FUGen ()=delete
 
 FUGen (const FUGen &)=delete
 
FUGenoperator= (const FUGen &)=delete
 
 FUGen (const ProGeOptions &options, std::vector< std::string > globalOptions, IDF::FUGenerated &fug, const TTAMachine::Machine &machine, ProGe::NetlistBlock *core)
 

Static Public Member Functions

static void implement (const ProGeOptions &options, std::vector< std::string > globalOptions, const std::vector< IDF::FUGenerated > &generatetFUs, const TTAMachine::Machine &machine, ProGe::NetlistBlock *core)
 

Private Types

typedef std::pair< std::string, std::string > Replace
 

Private Member Functions

void createOutputPipeline ()
 
void addRegisterIfMissing (std::string name, int width, HDLGenerator::WireType wt=HDLGenerator::WireType::Auto)
 
std::string findAbsolutePath (std::string file)
 
void createFUHeaderComment ()
 
void createMandatoryPorts ()
 
void checkForValidity ()
 
void createExternalInterfaces (bool genIntegrator)
 
void createOperationResources ()
 
void buildOperations ()
 
void finalizeHDL ()
 
void createImplementationFiles ()
 
void copyImplementation (std::string file, std::string format, bool isSynthesizable)
 
void parseOperations ()
 
void scheduleOperations ()
 
void createPortPipeline ()
 
void createShadowRegisters ()
 
OperandConnection subOpConnection (OperationDAG *dag, OperationDAGEdge *edge, bool isOutput)
 
int DAGNodeOperandWidth (OperationDAGNode &node, int id, OperationDAG *dag)
 
void readImplementation (std::string filename, std::string opName, std::deque< std::string > &sink)
 
void prepareSnippet (std::string name, std::deque< std::string > statements, HDLGenerator::CodeBlock &sink, std::set< std::string > &addedStatements)
 
std::deque< std::string > readFile (std::string filename)
 
std::vector< ReplacebuildReplaces (std::string opName)
 
std::string replaceToken (std::string line, Replace replace)
 
bool hasToken (std::string line, std::string token)
 
HDLGenerator::Language selectedLanguage ()
 
std::string opcodeSignal (int stage)
 
std::string triggerSignal (int stage)
 
std::string opcodeConstant (std::string operation)
 
std::string operandSignal (std::string operation, int id)
 
std::string operandPlaceholder (int id)
 
std::string pipelineName (std::string port, int cycle)
 
std::string pipelineValid (std::string port, int cycle)
 
std::string subOpName (OperationNode *node)
 
std::string constantName (ConstantNode *node, OperationDAG *dag)
 
std::string constantName (DAGConstant dag)
 
bool isLSUDataPort (const std::string &portName)
 
ProGe::Signal inferLSUSignal (const std::string &portName) const
 

Private Attributes

int maxLatency_
 
int minLatency_
 
const ProGeOptionsoptions_
 
std::vector< std::string > globalOptions_
 
IDF::FUGeneratedfug_
 
ProGe::NetlistBlockcore_
 
HDLGenerator::Module fu_
 
TTAMachine::FunctionUnitadfFU_
 
std::vector< std::string > operations_
 
int opcodeWidth_
 
std::string moduleName_
 
ProGe::NetlistBlocknetlistBlock_
 
std::unordered_map< std::string, BaseOperationbaseOperations_
 
std::unordered_map< std::string, OperationSchedulescheduledOperations_
 
std::unordered_map< std::string, std::vector< Replace > > replacesPerOp_
 
std::unordered_map< std::string, int > operationCycles_
 
std::unordered_map< std::string, int > implLatency_
 
std::unordered_map< std::string, OperationDAG * > implementapleDAGs_
 
std::unordered_map< std::string, int > subOpCount_
 
std::unordered_map< std::string, int > dagConstantCount_
 
std::unordered_map< std::string, int > resourceCount_
 
std::unordered_map< std::string, int > pipelineLength_
 
std::unordered_map< std::string, ProGe::DirectionportDirection_
 
std::unordered_multimap< std::string, OutputConnectionportInputs_
 
std::unordered_map< int, int > nodeImplementations_
 
std::unordered_map< int, DAGConstantdagConstants_
 
std::vector< std::string > resourceInputs_
 
std::vector< std::string > resourceOutputs_
 
std::unordered_set< std::string > extIfaces_
 
std::set< std::pair< std::string, std::string > > extOutputs_
 
std::unordered_set< std::string > extInputs_
 
std::vector< HDB::VariablerenamedVariables_
 
std::vector< HDB::VariablerenamedGlobalSignals_
 
std::string triggerPort_
 
std::vector< std::string > registers_
 
bool useGlockRequest_ = false
 
bool useGlock_ = false
 
HDLGenerator::Behaviour behaviour_
 
bool frontRegistered_ = false
 
bool middleRegistered_ = false
 
bool backRegistered_ = false
 
int addressWidth_ = 0
 
bool isLSU_ = false
 

Detailed Description

Definition at line 58 of file FUGen.hh.

Member Typedef Documentation

◆ Replace

typedef std::pair<std::string, std::string> FUGen::Replace
private

Definition at line 98 of file FUGen.hh.

Constructor & Destructor Documentation

◆ FUGen() [1/3]

FUGen::FUGen ( )
delete

◆ FUGen() [2/3]

FUGen::FUGen ( const FUGen )
delete

◆ FUGen() [3/3]

FUGen::FUGen ( const ProGeOptions options,
std::vector< std::string >  globalOptions,
IDF::FUGenerated fug,
const TTAMachine::Machine machine,
ProGe::NetlistBlock core 
)
inline

Definition at line 63 of file FUGen.hh.

65 :
67 globalOptions_(globalOptions),
68 fug_(fug),
69 core_(core),
70 fu_(StringTools::stringToLower("fu_" + fug.name())),
74 moduleName_("fu_" + fug_.name()) {
75
76 // Find the netlistblock
77 for (size_t i = 0; i < core_->subBlockCount(); ++i) {
78 std::string name = core_->subBlock(i).moduleName();
81 break;
82 }
83 }
84
85 if (adfFU_->hasAddressSpace()) {
86 auto as = adfFU_->addressSpace();
88 }
89 }
TTAMachine::Machine * machine
the architecture definition of the estimated processor
static MachInfoCmdLineOptions options
Definition MachInfo.cc:46
IDF::FUGenerated & fug_
Definition FUGen.hh:207
std::vector< std::string > globalOptions_
Definition FUGen.hh:205
int opcodeWidth_
Definition FUGen.hh:214
HDLGenerator::Module fu_
Definition FUGen.hh:210
ProGe::NetlistBlock * core_
Definition FUGen.hh:208
const ProGeOptions & options_
Definition FUGen.hh:204
int addressWidth_
Definition FUGen.hh:260
TTAMachine::FunctionUnit * adfFU_
Definition FUGen.hh:211
std::string moduleName_
Definition FUGen.hh:216
std::vector< std::string > operations_
Definition FUGen.hh:213
ProGe::NetlistBlock * netlistBlock_
Definition FUGen.hh:217
std::string name() const
static int requiredBits(unsigned long int number)
const std::string & moduleName() const
virtual size_t subBlockCount() const
NetlistBlock & subBlock(size_t index) override
static std::string stringToLower(const std::string &source)
virtual AddressSpace * addressSpace() const
virtual int operationCount() const
virtual bool hasAddressSpace() const
ComponentType * item(int index) const
virtual FunctionUnitNavigator functionUnitNavigator() const
Definition Machine.cc:380

References TTAMachine::FunctionUnit::addressSpace(), addressWidth_, adfFU_, core_, TTAMachine::FunctionUnit::hasAddressSpace(), ProGe::BaseNetlistBlock::moduleName(), moduleName_, netlistBlock_, MathTools::requiredBits(), StringTools::stringToLower(), ProGe::NetlistBlock::subBlock(), and ProGe::NetlistBlock::subBlockCount().

Here is the call graph for this function:

Member Function Documentation

◆ addRegisterIfMissing()

void FUGen::addRegisterIfMissing ( std::string  name,
int  width,
HDLGenerator::WireType  wt = HDLGenerator::WireType::Auto 
)
private

Definition at line 1377 of file FUGen.cc.

1377 {
1379 fu_ << Register(name, width, wt, ResetOption::Optional);
1380 registers_.emplace_back(name);
1381 }
1382}
static bool containsValue(const ContainerType &aContainer, const ElementType &aKey)
std::vector< std::string > registers_
Definition FUGen.hh:252

References ContainerTools::containsValue(), fu_, and registers_.

Referenced by createOutputPipeline(), and createPortPipeline().

Here is the call graph for this function:

◆ buildOperations()

void FUGen::buildOperations ( )
private

Definition at line 672 of file FUGen.cc.

672 {
673 Asynchronous operationCp("operations_actual_cp");
674 CodeBlock defaultValues;
675 CodeBlock defaultSnippets;
676 CodeBlock triggeredSnippets;
677
678 for (auto&& d : extOutputs_) {
679 operationCp << DefaultAssign(d.first, d.second);
680 }
681
682 for (std::string signal : resourceInputs_) {
683 // Zero initialize this configuration to avoid simulation warnings
684 if (isLSU_ && minLatency_ < 3) {
685 operationCp << DefaultAssign(signal, "0");
686 } else {
687 operationCp << DefaultAssign(signal, "-");
688 }
689 }
690
691 for (auto&& pair : dagConstants_) {
692 auto spec = pair.second;
693 std::string name = constantName(spec);
694 int width = MathTools::requiredBitsSigned(spec.value);
695 fu_ << BinaryConstant(name, width, spec.value);
696 }
697
698 for (std::string signal : resourceOutputs_) {
699 operationCp.reads(signal);
700 }
701
702 for (std::string signal : extInputs_) {
703 operationCp.reads(signal);
704 }
705
706 std::set<std::string> defaultStatements;
707 for (auto&& pair : scheduledOperations_) {
708 auto schedule = pair.second;
709 std::string name = pair.first;
710
711 for (int id : schedule.results) {
712 std::string source = operandSignal(name, id);
713 // Zero initialize this configuration to avoid simulation warnings
714 if (isLSU_ && minLatency_ < 3) {
715 defaultValues.append(DefaultAssign(source, "0"));
716 } else {
717 defaultValues.append(DefaultAssign(source, "-"));
718 }
719 }
720
721 for (auto&& operand : schedule.operands) {
722 int id = operand.id;
723
724 std::string source = operand.signalName;
725 std::string destination = operandSignal(name, id);
726 if (operand.portWidth > operand.operandWidth) {
727 defaultValues.append(Assign(
728 destination,
729 Splice(source, operand.operandWidth - 1, 0)));
730 } else if (operand.portWidth < operand.operandWidth) {
731 defaultValues.append(Assign(
732 destination,
733 Ext(source, operand.operandWidth, operand.portWidth)));
734 } else {
735 defaultValues.append(Assign(destination, LHSSignal(source)));
736 }
737
738 if (!operand.isOutput) {
739 operationCp.reads(destination);
740 }
741 }
742
743 replacesPerOp_[name] = buildReplaces(name);
744
745 std::string baseOp = schedule.baseOp;
746 auto& initial = baseOperations_[baseOp].initial;
747 if (!initial.empty()) {
748 prepareSnippet(name, initial, defaultSnippets, defaultStatements);
749 }
750 }
751
752 for (int cycle = 0; cycle <= maxLatency_; ++cycle) {
753 Switch opSwitch(LHSSignal(opcodeSignal(cycle)));
754 bool emptySwitch = true;
755
756 for (std::string op : operations_) {
757 CodeBlock onTrigger;
758 bool emptyBlock = true;
759 auto schedule = scheduledOperations_[op];
760
761 std::vector<std::string> schedules = schedule.subOperations;
762 schedules.push_back(op);
763
764 for (std::string subop : schedules) {
765 auto schedule = scheduledOperations_[subop];
766 std::string baseOp = schedule.baseOp;
767 if (schedule.initialCycle == cycle) {
768 auto& impl = baseOperations_[baseOp].implementation;
769 if (!impl.empty()) {
770 std::set<std::string> statements;
771 prepareSnippet(subop, impl, onTrigger, statements);
772 }
773 emptyBlock = false;
774 }
775
776 if (schedule.finalCycle == cycle) {
777 auto& postOp = baseOperations_[baseOp].postOp;
778 if (!postOp.empty()) {
779 std::set<std::string> statements;
780 prepareSnippet(subop, postOp, onTrigger, statements);
781 }
782 emptyBlock = false;
783 }
784 }
785
786 if (emptyBlock) {
787 continue;
788 }
789
790 if (operations_.size() > 1) {
791 Case opCase(opcodeConstant(op));
792 opCase << onTrigger;
793 opSwitch.addCase(opCase);
794 emptySwitch = false;
795 } else {
796 If opIf(
797 Equals(
799 onTrigger);
800 triggeredSnippets.append(opIf);
801 }
802 }
803
804 if (!emptySwitch) {
805 opSwitch.addCase(DefaultCase());
806 If opIf(
808 opSwitch);
809 triggeredSnippets.append(opIf);
810 }
811 }
812
813 if (useGlock_) {
814 operationCp.reads("glock_in");
815 }
816
817 if (useGlockRequest_) {
818 defaultValues.append(Assign("glockreq", BinaryLiteral("0")));
819 }
820
821 for (auto&& v : renamedVariables_) {
822 int w = std::stoi(v.width);
823 if (v.type == "Logic") {
824 operationCp.addVariable(LogicVariable(v.name, w));
825 } else if (v.type == "Unsigned") {
826 operationCp.addVariable(UnsignedVariable(v.name, w));
827 } else {
828 operationCp.addVariable(SignedVariable(v.name, w));
829 }
830 // Zero initialize this configuration to avoid simulation warnings
831 if (isLSU_ && minLatency_ < 3) {
832 operationCp << DefaultAssign(v.name, "0");
833 } else {
834 operationCp << DefaultAssign(v.name, "-");
835 }
836 }
837 for (auto&& s : renamedGlobalSignals_) {
838 int w = std::stoi(s.width);
839 fu_ << Wire(s.name, w); // creates the signal declaration
840 operationCp.reads(s.name); // adds it to sensitivity list
841 // Zero initialize this configuration to avoid simulation warnings
842 if (isLSU_ && minLatency_ < 3) {
843 operationCp << DefaultAssign(s.name, "0");
844 } else {
845 operationCp << DefaultAssign(s.name, "-");
846 }
847 }
848
849 operationCp << defaultValues << defaultSnippets << triggeredSnippets;
850 behaviour_ << operationCp;
851}
std::string opcodeSignal(int stage)
Definition FUGen.cc:113
std::unordered_map< std::string, BaseOperation > baseOperations_
Definition FUGen.hh:220
std::vector< Replace > buildReplaces(std::string opName)
Definition FUGen.cc:395
std::vector< std::string > resourceInputs_
Definition FUGen.hh:241
std::vector< HDB::Variable > renamedGlobalSignals_
Definition FUGen.hh:249
int maxLatency_
Definition FUGen.hh:201
bool isLSU_
Definition FUGen.hh:261
std::unordered_set< std::string > extInputs_
Definition FUGen.hh:246
std::string constantName(ConstantNode *node, OperationDAG *dag)
Definition FUGen.cc:178
bool useGlock_
Definition FUGen.hh:255
std::string opcodeConstant(std::string operation)
Definition FUGen.cc:131
HDLGenerator::Behaviour behaviour_
Definition FUGen.hh:256
void prepareSnippet(std::string name, std::deque< std::string > statements, HDLGenerator::CodeBlock &sink, std::set< std::string > &addedStatements)
Definition FUGen.cc:854
int minLatency_
Definition FUGen.hh:202
std::string operandSignal(std::string operation, int id)
Definition FUGen.cc:136
std::unordered_map< std::string, std::vector< Replace > > replacesPerOp_
Definition FUGen.hh:222
std::string triggerSignal(int stage)
Definition FUGen.cc:122
std::vector< std::string > resourceOutputs_
Definition FUGen.hh:242
std::set< std::pair< std::string, std::string > > extOutputs_
Definition FUGen.hh:245
bool useGlockRequest_
Definition FUGen.hh:254
std::unordered_map< int, DAGConstant > dagConstants_
Definition FUGen.hh:239
std::unordered_map< std::string, OperationSchedule > scheduledOperations_
Definition FUGen.hh:221
std::vector< HDB::Variable > renamedVariables_
Definition FUGen.hh:248
static int requiredBitsSigned(SLongWord number)

References HDLGenerator::Switch::addCase(), HDLGenerator::Asynchronous::addVariable(), HDLGenerator::CodeBlock::append(), baseOperations_, behaviour_, buildReplaces(), constantName(), dagConstants_, extInputs_, extOutputs_, fu_, isLSU_, maxLatency_, minLatency_, opcodeConstant(), opcodeSignal(), operandSignal(), operations_, prepareSnippet(), HDLGenerator::Asynchronous::reads(), renamedGlobalSignals_, renamedVariables_, replacesPerOp_, MathTools::requiredBitsSigned(), resourceInputs_, resourceOutputs_, scheduledOperations_, triggerSignal(), useGlock_, and useGlockRequest_.

Referenced by implement().

Here is the call graph for this function:

◆ buildReplaces()

std::vector< FUGen::Replace > FUGen::buildReplaces ( std::string  opName)
private

Definition at line 395 of file FUGen.cc.

395 {
396 OperationSchedule& schedule = scheduledOperations_[name];
397 std::string op = schedule.baseOp;
398 std::vector<FUGen::Replace> replaces;
399
400 replaces.emplace_back("glock", "glock_in");
401 replaces.emplace_back("trigger", triggerSignal(schedule.initialCycle));
402
403 for (auto&& operand : schedule.operands) {
404 int id = operand.id;
405 replaces.emplace_back(
406 operandPlaceholder(id), operandSignal(name, id));
407 }
408 for (int id : schedule.results) {
409 replaces.emplace_back(
410 operandPlaceholder(id), operandSignal(name, id));
411 }
412
413 if (!baseOperations_.count(op)) {
414 return replaces;
415 }
416
417 // Resources
418 for (auto&& r : baseOperations_[op].resources) {
419 std::string rName = StringTools::stringToLower(r.name);
420 if (!schedule.resourceOffsets.count(rName)) {
421 assert(false && "Couldn't find resource offset.");
422 }
423 int offset = schedule.resourceOffsets[rName];
424
425 for (int i = 0; i < r.count; ++i) {
426 int portID = i + 1;
427 int resID = i + offset + 1;
428 std::string file = findAbsolutePath(r.ipxact);
430 for (auto&& p : resource.ports) {
431 std::string pName = StringTools::stringToLower(p.name);
432 std::string replace = pName + "_" + std::to_string(portID);
433 std::string with =
434 rName + "_" + std::to_string(resID) + "_" + pName;
435
436 replaces.emplace_back(replace, with);
437 }
438 }
439 }
440
441 // Variables
442 for (auto&& v : baseOperations_[op].variables) {
443 std::string replica;
444 if (v.rename) {
445 replica = name + "_" + v.name;
446 replaces.emplace_back(v.name, replica);
447 } else {
448 bool nameFound = false;
449 for (auto&& old_var : renamedVariables_) {
450 if (old_var.name == v.name) {
451 nameFound = true;
452 }
453 }
454 if (nameFound) {
455 continue;
456 }
457 replica = v.name;
458 }
459 HDB::Variable var = {replica, v.width, v.type, v.rename};
460 renamedVariables_.emplace_back(var);
461 }
462 // Global signals
463 for (auto&& s : baseOperations_[op].globalsignals) {
464 std::string replica;
465 // Not renaming the signals allows them to be directly shared between
466 // ops
467 if (s.rename) {
468 replica = name + "_" + s.name;
469 replaces.emplace_back(s.name, replica);
470 } else {
471 // don't add the same signal multiple times
472 bool nameFound = false;
473 for (auto&& old_var : renamedGlobalSignals_) {
474 if (old_var.name == s.name) {
475 nameFound = true;
476 }
477 }
478 if (nameFound) {
479 continue;
480 }
481 replica = s.name;
482 }
483
484 HDB::Variable var = {replica, s.width, s.type, s.rename};
485 renamedGlobalSignals_.emplace_back(var);
486 }
487
488 return replaces;
489}
#define assert(condition)
std::string operandPlaceholder(int id)
Definition FUGen.cc:141
std::string findAbsolutePath(std::string file)
Definition FUGen.cc:101
ModuleInfo parseComponent(std::string file)
Definition IPXact.cc:86

References assert, FUGen::OperationSchedule::baseOp, baseOperations_, findAbsolutePath(), FUGen::OperationSchedule::initialCycle, operandPlaceholder(), FUGen::OperationSchedule::operands, operandSignal(), ipxact::parseComponent(), ipxact::ModuleInfo::ports, renamedGlobalSignals_, renamedVariables_, FUGen::OperationSchedule::resourceOffsets, FUGen::OperationSchedule::results, scheduledOperations_, StringTools::stringToLower(), triggerSignal(), and HDB::Variable::width.

Referenced by buildOperations().

Here is the call graph for this function:

◆ checkForValidity()

void FUGen::checkForValidity ( )
private

Definition at line 365 of file FUGen.cc.

365 {
366 // Check that we can implement the FU.
367 // Cannot implement if FU has multioutput operation that has
368 // different latencies for the outputs.
369 for (auto&& op : operations_) {
371 int hwOpOperands = hwOp->operandCount();
372 int prevLatency = -1;
373 for (int operand = 0; operand < hwOpOperands; ++operand) {
374 TTAMachine::FUPort* fuPort = hwOp->port(operand + 1);
375
376 if (!fuPort->isOutput()) {
377 continue;
378 }
379
380 int latency = hwOp->latency(operand + 1);
381 if (prevLatency == -1) {
382 prevLatency = latency;
383 } else if (prevLatency != latency) {
384 // TODO: probably not true anymore, but needs to be tested
385 throw std::runtime_error(
386 "FUGen cannot implement multioutput operations (" + op +
387 ") which have different latencies for"
388 " its outputs.");
389 }
390 }
391 }
392}
virtual HWOperation * operation(const std::string &name) const
virtual FUPort * port(int operand) const
virtual bool isOutput() const
Definition Port.cc:308

References adfFU_, TTAMachine::Port::isOutput(), TTAMachine::HWOperation::latency(), TTAMachine::HWOperation::operandCount(), TTAMachine::FunctionUnit::operation(), operations_, and TTAMachine::HWOperation::port().

Referenced by implement().

Here is the call graph for this function:

◆ constantName() [1/2]

std::string FUGen::constantName ( ConstantNode node,
OperationDAG dag 
)
private

Definition at line 178 of file FUGen.cc.

178 {
179 int id;
180 std::string op = dag->operation().name();
182 if (dagConstants_.count(node->nodeID())) {
183 id = dagConstants_[node->nodeID()].id;
184 } else {
185 if (!dagConstantCount_.count(op)) {
186 dagConstantCount_[op] = 0;
187 }
188 id = dagConstantCount_[op];
189 dagConstantCount_[op] += 1;
190 dagConstants_[node->nodeID()] = {op, node->value(), id};
191 }
192 return constantName(dagConstants_[node->nodeID()]);
193}
virtual long value() const
std::unordered_map< std::string, int > dagConstantCount_
Definition FUGen.hh:227
int nodeID() const
const class OperationPimpl & operation() const
TCEString name() const

References constantName(), dagConstantCount_, dagConstants_, OperationPimpl::name(), GraphNode::nodeID(), OperationDAG::operation(), StringTools::stringToLower(), and ConstantNode::value().

Referenced by buildOperations(), constantName(), and subOpConnection().

Here is the call graph for this function:

◆ constantName() [2/2]

std::string FUGen::constantName ( DAGConstant  dag)
private

Definition at line 196 of file FUGen.cc.

196 {
197 return "dag_" + dagc.operation + "_" + std::to_string(dagc.id) + "_c";
198}

References FUGen::DAGConstant::id, and FUGen::DAGConstant::operation.

◆ copyImplementation()

void FUGen::copyImplementation ( std::string  file,
std::string  format,
bool  isSynthesizable 
)
private

Definition at line 267 of file FUGen.cc.

268 {
269 file = findAbsolutePath(file);
270 const std::string DS = FileSystem::DIRECTORY_SEPARATOR;
271 std::string dir = options_.outputDirectory + DS;
272 if (isSynthesizable) {
273 dir += format == "VHDL" ? "vhdl" : "verilog";
274 } else {
275 dir += "blackbox" + DS;
276 dir += format == "VHDL simulation" ? "vhdl" : "verilog";
277 }
278 std::string target =
280 if (!FileSystem::fileExists(target)) {
282 FileSystem::copy(file, target);
283 }
284}
#define DS
static bool createDirectory(const std::string &path)
static const std::string DIRECTORY_SEPARATOR
static std::string fileOfPath(const std::string pathName)
static void copy(const std::string &source, const std::string &target)
static bool fileExists(const std::string fileName)
std::string outputDirectory

References FileSystem::copy(), FileSystem::createDirectory(), FileSystem::DIRECTORY_SEPARATOR, DS, FileSystem::fileExists(), FileSystem::fileOfPath(), findAbsolutePath(), options_, and ProGeOptions::outputDirectory.

Referenced by createImplementationFiles().

Here is the call graph for this function:

◆ createExternalInterfaces()

void FUGen::createExternalInterfaces ( bool  genIntegrator)
private

Definition at line 568 of file FUGen.cc.

568 {
569 std::set<std::pair<ProGe::NetlistPort*, ProGe::NetlistPort*>> lsuPorts;
570 Replace replaceAddress = {"addrw_c", std::to_string(addressWidth_)};
571 for (auto&& ei : extIfaces_) {
573 for (auto&& port : info.ports) {
574 std::string width = port.width;
575 if (addressWidth_ > 0) {
576 width = replaceToken(width, replaceAddress);
577 }
579 if (port.direction == "out") {
580 fu_ << OutPort(
581 port.name, width, HDLGenerator::WireType::Vector);
582 extOutputs_.emplace(port.name, port.defaultValue);
584 } else {
585 fu_ << InPort(
586 port.name, width, HDLGenerator::WireType::Vector);
587 extInputs_.emplace(port.name);
589 }
590
591 std::string extName = moduleName_ + "_" + port.name;
592 ProGe::NetlistPort* ext = NULL;
594 port.name, width, ProGe::DataType::BIT_VECTOR, dir,
596 if (isLSUDataPort(extName) && !genIntegrator) {
597 ext = new ProGe::NetlistPort(
598 extName, width, ProGe::DataType::BIT_VECTOR, dir, *core_,
599 inferLSUSignal(extName));
600 lsuPorts.insert(std::make_pair(internal, ext));
601 } else {
602 ext = new ProGe::NetlistPort(
603 extName, width, ProGe::DataType::BIT_VECTOR, dir, *core_);
604 core_->netlist().connect(*ext, *internal);
605 }
606 }
607 }
608 if (lsuPorts.empty()) {
609 return;
610 }
611 // Handle LSU data ports.
612 TCEString asName("");
613 if (adfFU_->hasAddressSpace()) {
614 asName = adfFU_->addressSpace()->name();
615 }
616
617 ProGe::NetlistPortGroup* dmemPortGroup = nullptr;
618 for (auto portPair : lsuPorts) {
619 dmemPortGroup =
620 dmemPortGroup
621 ? dmemPortGroup
624 dmemPortGroup->addPort(*portPair.second);
625 core_->netlist().connect(*portPair.first, *portPair.second);
626 }
627 if (dmemPortGroup != nullptr) {
628 core_->addPortGroup(dmemPortGroup);
629 dmemPortGroup = nullptr;
630 }
631}
ProGe::Signal inferLSUSignal(const std::string &portName) const
Definition FUGen.cc:542
std::pair< std::string, std::string > Replace
Definition FUGen.hh:98
std::string replaceToken(std::string line, Replace replace)
Definition FUGen.cc:67
bool isLSUDataPort(const std::string &portName)
Definition FUGen.cc:516
std::unordered_set< std::string > extIfaces_
Definition FUGen.hh:244
void addPortGroup(NetlistPortGroup *portGroup)
virtual const Netlist & netlist() const
void addPort(NetlistPort &port)
bool connect(const NetlistPort &port1, const NetlistPort &port2, int port1FirstBit, int port2FirstBit, int width=1)
Definition Netlist.cc:83
virtual TCEString name() const
@ BIT_VECTOR
Several bits.
Definition ProGeTypes.hh:48
@ BYTEMASKED_SRAM_PORT
Signal group type for one port SRAM having read and write capability and bitmask for writing with sep...
Direction
Direction of the port.
Definition ProGeTypes.hh:52
@ OUT
Output port.
Definition ProGeTypes.hh:54
@ IN
Input port.
Definition ProGeTypes.hh:53
BusInfo parseBus(std::string file)
Definition IPXact.cc:39

References ProGe::NetlistPortGroup::addPort(), ProGe::NetlistBlock::addPortGroup(), TTAMachine::FunctionUnit::addressSpace(), addressWidth_, adfFU_, ProGe::BIT_VECTOR, ProGe::BYTEMASKED_SRAM_PORT, ProGe::Netlist::connect(), core_, extIfaces_, extInputs_, extOutputs_, fu_, TTAMachine::FunctionUnit::hasAddressSpace(), ProGe::IN, inferLSUSignal(), isLSUDataPort(), moduleName_, TTAMachine::Component::name(), ProGe::NetlistBlock::netlist(), netlistBlock_, ProGe::OUT, ipxact::parseBus(), ipxact::BusInfo::ports, replaceToken(), and HDLGenerator::Vector.

Referenced by implement().

Here is the call graph for this function:

◆ createFUHeaderComment()

void FUGen::createFUHeaderComment ( )
private

Creates the header comment for fu.

Definition at line 228 of file FUGen.cc.

228 {
229 fu_.appendToHeader("Function Unit: " + fug_.name());
231 fu_.appendToHeader("Operations:");
232
233 if (adfFU_->operationCount() > 1) {
234 size_t maxOpNameLen = 0;
235 for (int i = 0; i < adfFU_->operationCount(); ++i) {
237 maxOpNameLen = std::max(maxOpNameLen, hwop->name().size());
238 }
239 int opDigits =
240 static_cast<int>(std::ceil(std::log10(adfFU_->operationCount())));
241 for (int i = 0; i < adfFU_->operationCount(); ++i) {
243 operations_.emplace_back(hwop->name());
244 }
245 std::sort(operations_.begin(), operations_.end());
246 int opcode = 0;
247 for (auto&& op : operations_) {
249 std::ostringstream comment;
250 comment << boost::format(
251 " %-" + std::to_string(maxOpNameLen) + "s : %" +
252 std::to_string(opDigits) + "s") %
253 op % std::to_string(opcode);
254 fu_.appendToHeader(comment.str());
255 opcode++;
256 }
257
258 } else {
260 operations_.emplace_back(hwop->name());
261 fu_.appendToHeader(" " + hwop->name() + " : 0");
262 }
264}
void appendToHeader(const std::string &line)
const std::string & name() const

References adfFU_, HDLGenerator::Module::appendToHeader(), fu_, fug_, IDF::FUGenerated::name(), TTAMachine::HWOperation::name(), opcodeConstant(), opcodeWidth_, TTAMachine::FunctionUnit::operation(), TTAMachine::FunctionUnit::operationCount(), and operations_.

Referenced by implement().

Here is the call graph for this function:

◆ createImplementationFiles()

void FUGen::createImplementationFiles ( )
private

Definition at line 290 of file FUGen.cc.

290 {
292 Path dir = Path(options_.outputDirectory) / std::string("vhdl");
293 FileSystem::createDirectory(dir.string());
294 Path file = dir / (fu_.name() + ".vhd");
295 std::ofstream ofs(file);
296 fu_.implement(ofs, Language::VHDL);
297 } else if (options_.language == ProGe::HDL::Verilog) {
298 Path dir = Path(options_.outputDirectory) / std::string("verilog");
299 FileSystem::createDirectory(dir.string());
300 Path file = dir / (fu_.name() + ".v");
301 std::ofstream ofs(file);
302 fu_.implement(ofs, Language::Verilog);
303 }
304
305 // Copy synthesis files and simulation models.
306 for (auto&& opInfo : fug_.operations()) {
307 std::string hdb = opInfo.hdb;
308 hdb = findAbsolutePath(hdb);
311 manager.OperationImplementationByID(opInfo.id);
312 for (auto&& r : opImpl.resources) {
313 for (size_t i = 0; i < r.simFiles.size(); ++i) {
314 copyImplementation(r.simFiles[i], r.simFormats[i], false);
315 }
316 for (size_t i = 0; i < r.synFiles.size(); ++i) {
317 copyImplementation(r.synFiles[i], r.synFormats[i], true);
318 }
319 }
320 }
321}
void copyImplementation(std::string file, std::string format, bool isSynthesizable)
Definition FUGen.cc:267
static CachedHDBManager & instance(const std::string &hdbFile)
OperationImplementation OperationImplementationByID(RowID id) const
const std::string & name() const noexcept
void implement(std::ostream &stream, Language lang, int level=0)
@ Verilog
Verilog.
Definition ProGeTypes.hh:42
@ VHDL
VHDL.
Definition ProGeTypes.hh:41
ProGe::HDL language

References copyImplementation(), FileSystem::createDirectory(), findAbsolutePath(), fu_, fug_, HDLGenerator::Module::implement(), HDB::CachedHDBManager::instance(), ProGeOptions::language, HDLGenerator::Generatable::name(), HDB::HDBManager::OperationImplementationByID(), IDF::FUGenerated::operations(), options_, ProGeOptions::outputDirectory, HDB::OperationImplementation::resources, ProGe::Verilog, and ProGe::VHDL.

Referenced by implement().

Here is the call graph for this function:

◆ createMandatoryPorts()

void FUGen::createMandatoryPorts ( )
private

Definition at line 327 of file FUGen.cc.

327 {
328 std::string resetPort;
329 if (ProGeTools::findInOptionList("active low reset", globalOptions_)) {
330 resetPort = "rstx";
331 } else {
332 resetPort = "rst";
333 }
334
335 fu_ << InPort("clk") << InPort(resetPort) << InPort("glock_in")
336 << OutPort("glockreq_out");
337
338 if (adfFU_->operationCount() > 1) {
339 fu_ << InPort("operation_in", opcodeWidth_, WireType::Vector);
340 }
341
342 // operand ports.
343 for (int i = 0; i < adfFU_->portCount(); ++i) {
344 TTAMachine::FUPort* adfPort =
345 static_cast<TTAMachine::FUPort*>(adfFU_->port(i));
346
347 if (adfPort->isInput()) {
348 fu_ << InPort(
349 "data_" + adfPort->name() + "_in", adfPort->width(),
350 WireType::Vector);
351 fu_ << InPort("load_" + adfPort->name() + "_in");
352 } else {
353 fu_ << OutPort(
354 "data_" + adfPort->name() + "_out", adfPort->width(),
355 WireType::Vector);
356 }
357 }
358
359 if (addressWidth_ > 0) {
360 fu_ << IntegerConstant("addrw_c", addressWidth_);
361 }
362}
virtual int width() const
virtual BaseFUPort * port(const std::string &name) const
virtual bool isInput() const
Definition Port.cc:298
virtual std::string name() const
Definition Port.cc:141
virtual int portCount() const
Definition Unit.cc:135
bool findInOptionList(const std::string &option, std::vector< std::string > list, bool enableAll=true)

References addressWidth_, adfFU_, ProGeTools::findInOptionList(), fu_, globalOptions_, TTAMachine::Port::isInput(), TTAMachine::Port::name(), opcodeWidth_, TTAMachine::FunctionUnit::operationCount(), TTAMachine::FunctionUnit::port(), TTAMachine::Unit::portCount(), and TTAMachine::BaseFUPort::width().

Referenced by implement().

Here is the call graph for this function:

◆ createOperationResources()

void FUGen::createOperationResources ( )
private

Definition at line 634 of file FUGen.cc.

634 {
635 std::map<std::string, int> instantiatedResources;
636 for (auto&& rs : baseOperations_) {
637 for (auto&& r : rs.second.resources) {
638 if (!instantiatedResources.count(r.name)) {
639 instantiatedResources[r.name] = 0;
640 }
641 std::string file = findAbsolutePath(r.ipxact);
642 std::string rName = StringTools::stringToLower(r.name);
643 int rCount = resourceCount_[rName];
644
645 for (int i = instantiatedResources[r.name]; i < rCount; ++i) {
646 auto module = ipxact::parseComponent(file);
647 Module resource(module, i + 1);
648 resource.set_prefix(rName);
649 fu_ << resource;
650 for (auto&& p : module.ports) {
651 std::string wName = StringTools::stringToLower(
652 rName + "_" + std::to_string(i + 1) + "_" + p.name);
653 if (p.vector) {
654 fu_ << Wire(wName, p.width);
655 } else {
656 fu_ << Wire(wName);
657 }
658
659 if (p.direction == "in") {
660 resourceInputs_.emplace_back(wName);
661 } else {
662 resourceOutputs_.emplace_back(wName);
663 }
664 }
665 }
666 instantiatedResources[r.name] = rCount;
667 }
668 }
669}
std::unordered_map< std::string, int > resourceCount_
Definition FUGen.hh:230

References baseOperations_, findAbsolutePath(), fu_, resourceCount_, resourceInputs_, resourceOutputs_, HDLGenerator::Module::set_prefix(), and StringTools::stringToLower().

Referenced by implement().

Here is the call graph for this function:

◆ createOutputPipeline()

void FUGen::createOutputPipeline ( )
private

Definition at line 1385 of file FUGen.cc.

1385 {
1386 CodeBlock outputPipeline;
1387 CodeBlock lastStage;
1388
1389 for (int i = 0; i < adfFU_->portCount(); ++i) {
1390 auto port = adfFU_->port(i);
1391 int length = pipelineLength_[port->name()];
1392 int width = port->width();
1393 if (portDirection_[port->name()] != ProGe::Direction::OUT) {
1394 continue;
1395 }
1396
1397 auto inputs = portInputs_.equal_range(port->name());
1398 for (int cycle = length; cycle >= 0; --cycle) {
1399 bool cycleActive = false;
1400
1401 std::string nextReg = pipelineName(port->name(), cycle);
1402 std::string prevReg = pipelineName(port->name(), cycle + 1);
1403 std::string valid = pipelineValid(port->name(), cycle);
1404
1405 if (cycle == 0) {
1406 fu_ << Wire(nextReg, width, WireType::Vector);
1407 } else {
1408 outputPipeline.append(Assign(valid, BinaryLiteral("1")));
1409 addRegisterIfMissing(nextReg, width, WireType::Vector);
1410 addRegisterIfMissing(valid, 1);
1411 }
1412
1413 // TODO: build a mux if all operations come from the same cycle
1414 If validOperations(BinaryLiteral("1"), DefaultAssign("dummy"));
1415 for (auto it = inputs.first; it != inputs.second; ++it) {
1416 auto connection = it->second;
1417 if (connection.pipelineStage != cycle) {
1418 continue;
1419 }
1420
1421 Equals triggered(
1422 LHSSignal(triggerSignal(connection.sourceCycle)),
1423 BinaryLiteral("1"));
1424 LogicalAnd active(
1425 Equals(
1426 LHSSignal(opcodeSignal(connection.sourceCycle)),
1427 LHSSignal(opcodeConstant(connection.operation))),
1428 triggered);
1429
1430 Ext source(
1431 operandSignal(connection.operation, connection.operandID),
1432 width, connection.operandWidth);
1433
1434 if (cycleActive) {
1435 if (operations_.size() == 1) {
1436 validOperations.elseIfClause(
1437 triggered, Assign(nextReg, source));
1438 } else {
1439 validOperations.elseIfClause(
1440 active, Assign(nextReg, source));
1441 }
1442 } else {
1443 if (operations_.size() == 1) {
1444 validOperations =
1445 If(triggered, Assign(nextReg, source));
1446 } else {
1447 validOperations = If(active, Assign(nextReg, source));
1448 }
1449 }
1450 cycleActive = true;
1451 }
1452
1453 bool skip_last_assign = false;
1454 // No need for this on first cycle
1455 if (cycle != length) {
1456 std::string prevValid =
1457 pipelineValid(port->name(), cycle + 1);
1458
1459 Equals isValid(LHSSignal(prevValid), BinaryLiteral("1"));
1460 if (cycleActive) {
1461 validOperations.elseIfClause(
1462 isValid, Assign(nextReg, LHSSignal(prevReg)));
1463 } else {
1464 if (cycle == 0) {
1465 skip_last_assign = true;
1466 lastStage.append(Assign(nextReg, LHSSignal(prevReg)));
1467 } else {
1468 validOperations =
1469 If(isValid, Assign(nextReg, LHSSignal(prevReg)));
1470 }
1471 }
1472 cycleActive = true;
1473 }
1474
1475 if (cycle == 0) {
1476 std::string outReg = nextReg + "_r";
1477 addRegisterIfMissing(outReg, width, WireType::Vector);
1478 outputPipeline.append(Assign(outReg, LHSSignal(nextReg)));
1479
1480 Assign finalStep(nextReg, LHSSignal(outReg));
1481 if (!skip_last_assign) {
1482 if (cycleActive) {
1483 validOperations.elseClause(finalStep);
1484 lastStage.append(validOperations);
1485 } else {
1486 lastStage.append(finalStep);
1487 }
1488 }
1489 } else {
1490 validOperations.elseClause(Assign(valid, BinaryLiteral("0")));
1491 outputPipeline.append(validOperations);
1492 }
1493 }
1494 lastStage.append(Assign(
1495 "data_" + port->name() + "_out",
1496 LHSSignal(pipelineName(port->name(), 0))));
1497 }
1498
1499 Synchronous sync("output_pipeline_sp");
1500 sync << If(
1501 Equals(LHSSignal("glock_in"), BinaryLiteral("0")), outputPipeline);
1502 behaviour_ << sync;
1503
1504 Asynchronous async("output_pipeline_cp");
1505 async << lastStage;
1506 behaviour_ << async;
1507}
std::unordered_map< std::string, int > pipelineLength_
Definition FUGen.hh:233
std::string pipelineValid(std::string port, int cycle)
Definition FUGen.cc:155
void addRegisterIfMissing(std::string name, int width, HDLGenerator::WireType wt=HDLGenerator::WireType::Auto)
Definition FUGen.cc:1377
std::string pipelineName(std::string port, int cycle)
Definition FUGen.cc:146
std::unordered_multimap< std::string, OutputConnection > portInputs_
Definition FUGen.hh:235
std::unordered_map< std::string, ProGe::Direction > portDirection_
Definition FUGen.hh:234

References addRegisterIfMissing(), adfFU_, HDLGenerator::CodeBlock::append(), behaviour_, HDLGenerator::If::elseClause(), HDLGenerator::If::elseIfClause(), fu_, opcodeConstant(), opcodeSignal(), operandSignal(), operations_, ProGe::OUT, pipelineLength_, pipelineName(), pipelineValid(), TTAMachine::FunctionUnit::port(), TTAMachine::Unit::portCount(), portDirection_, portInputs_, triggerSignal(), and TTAMachine::BaseFUPort::width().

Referenced by implement().

Here is the call graph for this function:

◆ createPortPipeline()

void FUGen::createPortPipeline ( )
private

Definition at line 1317 of file FUGen.cc.

1317 {
1318 CodeBlock pipelineAssignments;
1319 CodeBlock firstStage;
1320
1321 // Pipeline for opcode and trigger
1322 // TODO: This might generate some unnecessary registers for some FUs,
1323 // but these should be removed by the synthesis tool
1324 for (int i = 0; i < maxLatency_; ++i) {
1325 if (operations_.size() > 1) {
1326 std::string prevOpcode = opcodeSignal(i);
1327 std::string nextOpcode = opcodeSignal(i + 1);
1328 addRegisterIfMissing(nextOpcode, opcodeWidth_, WireType::Vector);
1329 if (i == 0) {
1330 firstStage.append(Assign(nextOpcode, LHSSignal(prevOpcode)));
1331 } else {
1332 pipelineAssignments.append(
1333 Assign(nextOpcode, LHSSignal(prevOpcode)));
1334 }
1335 }
1336 std::string prevTrigger = triggerSignal(i);
1337 std::string nextTrigger = triggerSignal(i + 1);
1338 addRegisterIfMissing(nextTrigger, 1);
1339 pipelineAssignments.append(
1340 Assign(nextTrigger, LHSSignal(prevTrigger)));
1341 }
1342
1343 // Pipelines for operand data
1344 for (int i = 0; i < adfFU_->portCount(); ++i) {
1345 auto port = adfFU_->port(i);
1346 int length = pipelineLength_[port->name()];
1347 int width = port->width();
1348 if (portDirection_[port->name()] != ProGe::Direction::IN) {
1349 continue;
1350 }
1351
1352 for (int i = 0; i < length; ++i) {
1353 std::string prevReg = pipelineName(port->name(), i);
1354 std::string nextReg = pipelineName(port->name(), i + 1);
1355 addRegisterIfMissing(nextReg, width, WireType::Vector);
1356 if (i == 0) {
1357 firstStage.append(Assign(nextReg, LHSSignal(prevReg)));
1358 } else {
1359 pipelineAssignments.append(
1360 Assign(nextReg, LHSSignal(prevReg)));
1361 }
1362 }
1363 }
1364
1365 If operationTrigger(
1366 Equals(LHSSignal(triggerSignal(0)), BinaryLiteral("1")), firstStage);
1367 pipelineAssignments.append(operationTrigger);
1368 If glock_low(
1369 Equals(LHSSignal("glock_in"), BinaryLiteral("0")),
1370 pipelineAssignments);
1371 Synchronous pipeline("input_pipeline_sp");
1372 pipeline << glock_low;
1373 behaviour_ << pipeline;
1374}

References addRegisterIfMissing(), adfFU_, HDLGenerator::CodeBlock::append(), behaviour_, ProGe::IN, maxLatency_, opcodeSignal(), opcodeWidth_, operations_, pipelineLength_, pipelineName(), TTAMachine::FunctionUnit::port(), TTAMachine::Unit::portCount(), portDirection_, triggerSignal(), and TTAMachine::BaseFUPort::width().

Referenced by implement().

Here is the call graph for this function:

◆ createShadowRegisters()

void FUGen::createShadowRegisters ( )
private

Definition at line 1243 of file FUGen.cc.

1243 {
1244 std::vector<std::string> inOperands;
1245 std::unordered_set<std::string> registeredInOperands;
1246 std::unordered_map<std::string, std::string> currentName;
1247 std::unordered_map<std::string, int> portWidth;
1248
1249 for (int i = 0; i < adfFU_->portCount(); ++i) {
1250 TTAMachine::FUPort* adfPort =
1251 static_cast<TTAMachine::FUPort*>(adfFU_->port(i));
1252 portWidth[adfPort->name()] = adfPort->width();
1253
1254 if (adfPort->isInput()) {
1255 currentName[adfPort->name()] = "data_" + adfPort->name() + "_in";
1256
1257 if (adfPort->isTriggering()) {
1258 triggerPort_ = adfPort->name();
1259 }
1260
1261 inOperands.emplace_back(adfPort->name());
1262 if (!adfPort->noRegister()) {
1263 registeredInOperands.emplace(adfPort->name());
1264 }
1265
1266 std::string name = pipelineName(adfPort->name(), 0);
1267 fu_ << Wire(name, adfPort->width());
1268 } else {
1269 currentName[adfPort->name()] = "data_" + adfPort->name() + "_out";
1270 }
1271 }
1272
1274 for (auto&& p : inOperands) {
1275 std::string newName = "data_" + p + "_gated";
1276 auto gate = LHSSignal(currentName[p]) &
1277 Sext("load_" + p + "_in", portWidth[p], 1);
1278 behaviour_ << Assign(newName, gate);
1279 currentName[p] = newName;
1280 fu_ << Wire(newName, portWidth[p]);
1281 }
1282 }
1283
1284 for (auto&& p : inOperands) {
1285 std::string dataPort = currentName[p];
1286 std::string output = pipelineName(p, 0);
1287 if (p != triggerPort_ &&
1288 registeredInOperands.find(p) != registeredInOperands.end()) {
1289 std::string loadPort = "load_" + p + "_in";
1290 std::string shadowReg = "shadow_" + p + "_r";
1291
1292 fu_ << Register(shadowReg, portWidth[p], ResetOption::Optional);
1293
1294 auto noLock = Equals(LHSSignal("glock_in"), BinaryLiteral("0"));
1295 auto portLoad = Equals(LHSSignal(loadPort), BinaryLiteral("1"));
1296 If iffi(
1297 noLock && portLoad, Assign(shadowReg, LHSSignal(dataPort)));
1298
1299 behaviour_ << (Synchronous("shadow_" + p + "_sp") << iffi);
1300
1301 auto triggerLoad = Equals(
1302 LHSSignal("load_" + triggerPort_ + "_in"),
1303 BinaryLiteral("1"));
1304 If cpIf(
1305 triggerLoad && portLoad,
1306 Assign(output, LHSSignal("data_" + p + "_in")));
1307 cpIf.elseClause(Assign(output, LHSSignal(shadowReg)));
1308
1309 behaviour_ << (Asynchronous("shadow_" + p + "_cp") << cpIf);
1310 } else {
1311 behaviour_ << Assign(output, LHSSignal(dataPort));
1312 }
1313 }
1314}
std::string triggerPort_
Definition FUGen.hh:250
virtual bool isTriggering() const
Definition FUPort.cc:182
bool noRegister() const
Definition FUPort.cc:469
std::vector< std::string > fuIcGateList

References adfFU_, behaviour_, HDLGenerator::If::elseClause(), ProGeTools::findInOptionList(), fu_, fug_, ProGeOptions::fuIcGateList, TTAMachine::Port::isInput(), TTAMachine::FUPort::isTriggering(), IDF::FUGenerated::name(), TTAMachine::Port::name(), TTAMachine::FUPort::noRegister(), options_, pipelineName(), TTAMachine::FunctionUnit::port(), TTAMachine::Unit::portCount(), triggerPort_, and TTAMachine::BaseFUPort::width().

Referenced by implement().

Here is the call graph for this function:

◆ DAGNodeOperandWidth()

int FUGen::DAGNodeOperandWidth ( OperationDAGNode node,
int  id,
OperationDAG dag 
)
private

Definition at line 201 of file FUGen.cc.

202 {
203 auto operation = dynamic_cast<OperationNode*>(&node);
204 auto terminal = dynamic_cast<TerminalNode*>(&node);
205 auto constant = dynamic_cast<ConstantNode*>(&node);
206
207 OperationPool opPool;
208 std::string opName;
209 if (operation) {
210 opName = operation->referencedOperation().name();
211 } else if (terminal) {
212 opName = dag->operation().name();
213 } else if (constant) {
214 return MathTools::requiredBitsSigned(constant->value());
215 } else {
216 assert(false && "Shouldn't be possible to get here.");
217 }
218
219 opName = StringTools::stringToLower(opName);
220 Operation& op = opPool.operation(opName.c_str());
221 return op.operand(id).width();
222}
virtual int width() const
Definition Operand.cc:318
Operation & operation(const char *name)
virtual Operand & operand(int id) const
Definition Operation.cc:541

References assert, OperationPimpl::name(), Operation::operand(), OperationDAG::operation(), OperationPool::operation(), MathTools::requiredBitsSigned(), StringTools::stringToLower(), and Operand::width().

Referenced by scheduleOperations(), and subOpConnection().

Here is the call graph for this function:

◆ finalizeHDL()

void FUGen::finalizeHDL ( )
private

Definition at line 889 of file FUGen.cc.

889 {
890 // Create lock request wires
891 if (useGlockRequest_) {
892 fu_ << Wire("glockreq");
893 behaviour_ << Assign("glockreq_out", LHSSignal("glockreq"));
894 } else {
895 behaviour_ << Assign("glockreq_out", BinaryLiteral("0"));
896 }
897
898 // Finalize and set global options.
899 fu_ << behaviour_;
900 for (auto&& option : globalOptions_) {
901 fu_ << Option(option);
902 }
903}

References behaviour_, fu_, globalOptions_, and useGlockRequest_.

Referenced by implement().

◆ findAbsolutePath()

std::string FUGen::findAbsolutePath ( std::string  file)
private

Searches for file in TCE folders and makes the path absolute.

Definition at line 101 of file FUGen.cc.

101 {
102 if (file.length() > 4 && file.substr(0, 4) == "tce:") {
103 file = file.substr(4);
104 }
105 std::vector<std::string> paths = Environment::hdbPaths();
106 for (auto file : options_.hdbList) {
107 paths.emplace_back(FileSystem::directoryOfPath(file));
108 }
109 return FileSystem::findFileInSearchPaths(paths, file);
110}
static std::vector< std::string > hdbPaths(bool libraryPathsOnly=false)
static std::string directoryOfPath(const std::string fileName)
Definition FileSystem.cc:79
static std::string findFileInSearchPaths(const std::vector< std::string > &searchPaths, const std::string &file)

References FileSystem::directoryOfPath(), FileSystem::findFileInSearchPaths(), ProGeOptions::hdbList, Environment::hdbPaths(), and options_.

Referenced by buildReplaces(), copyImplementation(), createImplementationFiles(), createOperationResources(), parseOperations(), readFile(), and readImplementation().

Here is the call graph for this function:

◆ hasToken()

bool FUGen::hasToken ( std::string  line,
std::string  token 
)
private

Definition at line 61 of file FUGen.cc.

61 {
62 auto regex = std::regex("\\b" + token + "\\b");
63 return std::regex_search(line, regex);
64}

Referenced by prepareSnippet().

◆ implement()

void FUGen::implement ( const ProGeOptions options,
std::vector< std::string >  globalOptions,
const std::vector< IDF::FUGenerated > &  generatetFUs,
const TTAMachine::Machine machine,
ProGe::NetlistBlock core 
)
static

Generate all FUGen FUs.

Definition at line 1515 of file FUGen.cc.

1518 {
1519 // Generate FU innards.
1520 for (auto fug : generatetFUs) {
1521 FUGen fugen(options, globalOptions, fug, machine, core);
1522
1523 // Some repetition to have named FUs override an "all"
1524 // e.g. --fu-front-register=all --fu-back-register=lsu
1526 fug.name(), options.fuFrontRegistered, false)) {
1527 fugen.frontRegistered_ = true;
1529 fug.name(), options.fuMiddleRegistered, false)) {
1530 fugen.middleRegistered_ = true;
1532 fug.name(), options.fuBackRegistered, false)) {
1533 fugen.backRegistered_ = true;
1535 fug.name(), options.fuFrontRegistered)) {
1536 fugen.frontRegistered_ = true;
1538 fug.name(), options.fuMiddleRegistered)) {
1539 fugen.middleRegistered_ = true;
1540 } else { // Default to back-register
1541 fugen.backRegistered_ = true;
1542 }
1543
1544 fugen.createFUHeaderComment();
1545 fugen.checkForValidity();
1546
1547 fugen.parseOperations();
1548 fugen.scheduleOperations();
1549 fugen.createMandatoryPorts();
1550 fugen.createExternalInterfaces(!options.integratorName.empty());
1551 fugen.createOperationResources();
1552
1553 fugen.createShadowRegisters();
1554 fugen.createPortPipeline();
1555 fugen.buildOperations();
1556 fugen.createOutputPipeline();
1557
1558 fugen.finalizeHDL();
1559 fugen.createImplementationFiles();
1560 }
1561}
Definition FUGen.hh:58

References backRegistered_, buildOperations(), checkForValidity(), createExternalInterfaces(), createFUHeaderComment(), createImplementationFiles(), createMandatoryPorts(), createOperationResources(), createOutputPipeline(), createPortPipeline(), createShadowRegisters(), finalizeHDL(), ProGeTools::findInOptionList(), frontRegistered_, machine, middleRegistered_, options, parseOperations(), and scheduleOperations().

Referenced by ProGe::ProcessorGenerator::generateProcessor().

Here is the call graph for this function:

◆ inferLSUSignal()

ProGe::Signal FUGen::inferLSUSignal ( const std::string &  portName) const
private

(Ugly) heuristics for mapping FUGen generated LSU signal types

Parameters
portNameName of the port
Returns
SignalType

Definition at line 542 of file FUGen.cc.

542 {
543 size_t pos = 0;
544 using SigT = ProGe::SignalType;
545 if (((pos = portName.find("avalid")) != std::string::npos)) {
546 return SigT::AVALID;
547 } else if (((pos = portName.find("aready")) != std::string::npos)) {
548 return SigT::AREADY;
549 } else if (((pos = portName.find("aaddr")) != std::string::npos)) {
550 return SigT::AADDR;
551 } else if (((pos = portName.find("awren")) != std::string::npos)) {
552 return SigT::AWREN;
553 } else if (((pos = portName.find("astrb")) != std::string::npos)) {
554 return SigT::ASTRB;
555 } else if (((pos = portName.find("rvalid")) != std::string::npos)) {
556 return SigT::RVALID;
557 } else if (((pos = portName.find("rready")) != std::string::npos)) {
558 return SigT::RREADY;
559 } else if (((pos = portName.find("rdata")) != std::string::npos)) {
560 return SigT::RDATA;
561 } else if (((pos = portName.find("adata")) != std::string::npos)) {
562 return SigT::ADATA;
563 }
564 return SigT::UNDEFINED;
565}

Referenced by createExternalInterfaces().

◆ isLSUDataPort()

bool FUGen::isLSUDataPort ( const std::string &  portName)
private

(Ugly) heuristics for identifying an LSU data memory port.

The identification is made by partial match of the port's name.

Parameters
portNameThe port name given in HDB.
Returns
True if the port is LSU data memory port.

Definition at line 516 of file FUGen.cc.

516 {
517 if (!adfFU_->hasAddressSpace()) {
518 return false;
519 }
520
521 static const std::set<std::string> magicWords{
522 "avalid", "aready", "aaddr", "awren", "astrb",
523 "rvalid", "rready", "rdata", "adata"};
524
525 for (auto magicWord : magicWords) {
526 if (portName.find(magicWord) != std::string::npos) {
527 //Assume the FU is an LSU
528 isLSU_ = true;
529 return true;
530 }
531 }
532
533 return false;
534}

References adfFU_, TTAMachine::FunctionUnit::hasAddressSpace(), and isLSU_.

Referenced by createExternalInterfaces().

Here is the call graph for this function:

◆ opcodeConstant()

std::string FUGen::opcodeConstant ( std::string  operation)
private

Definition at line 131 of file FUGen.cc.

131 {
132 return "op_" + operation + "_c";
133}

Referenced by buildOperations(), createFUHeaderComment(), and createOutputPipeline().

◆ opcodeSignal()

std::string FUGen::opcodeSignal ( int  stage)
private

Definition at line 113 of file FUGen.cc.

113 {
114 if (stage == 0) {
115 return "operation_in";
116 } else {
117 return "operation_" + std::to_string(stage) + "_r";
118 }
119}

Referenced by buildOperations(), createOutputPipeline(), and createPortPipeline().

◆ operandPlaceholder()

std::string FUGen::operandPlaceholder ( int  id)
private

Definition at line 141 of file FUGen.cc.

141 {
142 return "op" + std::to_string(id);
143}

Referenced by buildReplaces().

◆ operandSignal()

std::string FUGen::operandSignal ( std::string  operation,
int  id 
)
private

Definition at line 136 of file FUGen.cc.

136 {
137 return operation + "_op" + std::to_string(id);
138}

Referenced by buildOperations(), buildReplaces(), createOutputPipeline(), scheduleOperations(), and subOpConnection().

◆ operator=()

FUGen & FUGen::operator= ( const FUGen )
delete

◆ parseOperations()

void FUGen::parseOperations ( )
private

Definition at line 906 of file FUGen.cc.

906 {
907 OperationPool opPool;
908 std::vector<std::string> dagOperations;
909
910 for (auto&& op : fug_.operations()) {
911 BaseOperation opInfo;
912 opInfo.name = op.operationName;
913 opInfo.latency = op.latency;
914
915 std::string opHDB = findAbsolutePath(op.hdb);
916 HDB::CachedHDBManager& manager =
919 manager.OperationImplementationByID(op.id);
920
921 std::string implFile;
923 opInfo.variables = opImpl.vhdlVariables;
924 opInfo.globalsignals = opImpl.vhdlGlobalSignals;
925 opInfo.implementation = readFile(opImpl.implFileVhdl);
926 opInfo.initial = readFile(opImpl.initialImplFileVhdl);
927 opInfo.postOp = readFile(opImpl.postOpImplFileVhdl);
928 } else {
929 if (opImpl.implFileVerilog == "") {
930 const std::string msg =
931 "Cannot generate operation \"" + opInfo.name +
932 "\" due to missing verilog operation implementation";
933 throw std::runtime_error(msg);
934 }
935 opInfo.variables = opImpl.verilogVariables;
936 opInfo.globalsignals = opImpl.verilogGlobalSignals;
937 opInfo.implementation = readFile(opImpl.implFileVerilog);
938 opInfo.initial = readFile(opImpl.initialImplFileVerilog);
939 opInfo.postOp = readFile(opImpl.postOpImplFileVerilog);
940 }
941 opInfo.resources = opImpl.resources;
942
943 implLatency_[opInfo.name] = op.latency;
944
945 baseOperations_.emplace(opInfo.name, opInfo);
946
947 std::string ifPath = opImpl.absBusDefFile;
948 if (!ifPath.empty()) {
949 extIfaces_.insert(findAbsolutePath(ifPath));
950 }
951 }
952
953 maxLatency_ = 0;
954 minLatency_ = INT_MAX;
955 for (auto&& op : operations_) {
957 int hwOpOperands = hwOp->operandCount();
958 OperationPool opPool;
959
960 for (int operand = 0; operand < hwOpOperands; ++operand) {
961 TTAMachine::FUPort* fuPort = hwOp->port(operand + 1);
962
963 if (fuPort->isOutput()) {
964 std::string portName = fuPort->name();
965 int latency = hwOp->latency(operand + 1);
966
967 auto search = operationCycles_.find(op);
968 if (search != operationCycles_.end()) {
969 operationCycles_[op] = std::max(search->second, latency);
970 } else {
971 operationCycles_[op] = latency;
972 }
973 maxLatency_ = std::max(maxLatency_, latency);
974 minLatency_ = std::min(minLatency_, latency);
975 }
976 }
977
978 if (baseOperations_.find(op) == baseOperations_.end()) {
979 dagOperations.emplace_back(op);
980 }
981 }
982
983 for (auto&& op : dagOperations) {
984 int dagCount;
985 {
986 OperationPool opPool;
987 Operation& osalOp = opPool.operation(op.c_str());
988 dagCount = osalOp.dagCount();
989 }
990
991 if (dagCount < 1) {
992 throw std::runtime_error(op + " has no dags to implement.");
993 }
994
995 bool implementable = false;
996 for (int i = 0; i < dagCount; ++i) {
997 OperationDAG* dagPtr;
998 {
999 OperationPool opPool;
1000 OperationIndex& index = opPool.index();
1001 Operation* osalOp = index.effectiveOperation(op);
1002 dagPtr = &osalOp->dag(i);
1003 }
1004
1006 *dagPtr, fug_.operations(), nullptr)) {
1007 continue;
1008 } else {
1009 implementable = true;
1010 implementapleDAGs_[op] = dagPtr;
1011 implLatency_[op] =
1013 break;
1014 }
1015 }
1016
1017 if (!implementable) {
1018 throw std::runtime_error(op + " has no valid dags to implement.");
1019 }
1020 }
1021}
std::unordered_map< std::string, OperationDAG * > implementapleDAGs_
Definition FUGen.hh:225
std::deque< std::string > readFile(std::string filename)
Definition FUGen.cc:82
std::unordered_map< std::string, int > operationCycles_
Definition FUGen.hh:223
std::unordered_map< std::string, int > implLatency_
Definition FUGen.hh:224
std::vector< Info > & operations()
Operation * effectiveOperation(const TCEString &name)
OperationIndex & index()
virtual OperationDAG & dag(int index) const
Definition Operation.cc:148
virtual int dagCount() const
Definition Operation.cc:134
int dagLatency(const OperationDAG &dag, const std::unordered_map< std::string, int > &maxOpLatency)
bool canGenerateFromDAG(const OperationDAG &dag, const std::vector< IDF::FUGenerated::Info > infos, std::vector< IDF::FUGenerated::Info > *subops)
std::vector< Variable > verilogVariables
std::vector< Variable > vhdlGlobalSignals
std::vector< Variable > verilogGlobalSignals
std::vector< OperationImplementationResource > resources
std::vector< Variable > vhdlVariables

References HDB::OperationImplementation::absBusDefFile, adfFU_, baseOperations_, ProGeTools::canGenerateFromDAG(), Operation::dag(), Operation::dagCount(), ProGeTools::dagLatency(), OperationIndex::effectiveOperation(), extIfaces_, findAbsolutePath(), fug_, FUGen::BaseOperation::globalsignals, implementapleDAGs_, FUGen::BaseOperation::implementation, HDB::OperationImplementation::implFileVerilog, HDB::OperationImplementation::implFileVhdl, implLatency_, OperationPool::index(), FUGen::BaseOperation::initial, HDB::OperationImplementation::initialImplFileVerilog, HDB::OperationImplementation::initialImplFileVhdl, HDB::CachedHDBManager::instance(), TTAMachine::Port::isOutput(), ProGeOptions::language, FUGen::BaseOperation::latency, TTAMachine::HWOperation::latency(), maxLatency_, minLatency_, FUGen::BaseOperation::name, TTAMachine::Port::name(), TTAMachine::HWOperation::operandCount(), OperationPool::operation(), TTAMachine::FunctionUnit::operation(), operationCycles_, HDB::HDBManager::OperationImplementationByID(), IDF::FUGenerated::operations(), operations_, options_, TTAMachine::HWOperation::port(), FUGen::BaseOperation::postOp, HDB::OperationImplementation::postOpImplFileVerilog, HDB::OperationImplementation::postOpImplFileVhdl, readFile(), HDB::OperationImplementation::resources, FUGen::BaseOperation::resources, FUGen::BaseOperation::variables, HDB::OperationImplementation::verilogGlobalSignals, HDB::OperationImplementation::verilogVariables, ProGe::VHDL, HDB::OperationImplementation::vhdlGlobalSignals, and HDB::OperationImplementation::vhdlVariables.

Referenced by implement().

Here is the call graph for this function:

◆ pipelineName()

std::string FUGen::pipelineName ( std::string  port,
int  cycle 
)
private

Definition at line 146 of file FUGen.cc.

146 {
147 if (cycle == 0) {
148 return "data_" + port;
149 } else {
150 return "data_" + port + "_" + std::to_string(cycle) + "_r";
151 }
152}

Referenced by createOutputPipeline(), createPortPipeline(), createShadowRegisters(), and scheduleOperations().

◆ pipelineValid()

std::string FUGen::pipelineValid ( std::string  port,
int  cycle 
)
private

Definition at line 155 of file FUGen.cc.

155 {
156 return "data_" + port + "_" + std::to_string(cycle) + "_valid_r";
157}

Referenced by createOutputPipeline().

◆ prepareSnippet()

void FUGen::prepareSnippet ( std::string  name,
std::deque< std::string >  statements,
HDLGenerator::CodeBlock sink,
std::set< std::string > &  addedStatements 
)
private

Definition at line 854 of file FUGen.cc.

856 {
857 std::deque<std::string> snippet;
858 std::set<std::string> lines;
859 for (std::string line : statements) {
860 std::string replaced = StringTools::stringToLower(line);
861 for (Replace rep : replacesPerOp_[name]) {
862 replaced = replaceToken(replaced, rep);
863 }
864
865 // Cosmetic improvement: do not repeat statements in the same context
866 if (addedStatements.count(replaced)) {
867 continue;
868 }
869 lines.insert(replaced);
870
871 snippet.push_back(replaced);
872
873 if (hasToken(line, "glockreq")) {
874 useGlockRequest_ = true;
875 }
876 if (hasToken(line, "glock")) {
877 useGlock_ = true;
878 }
879 }
880
881 for (std::string line : lines) {
882 addedStatements.insert(line);
883 }
884
885 sink.append(HDLOperation(name, snippet, selectedLanguage()));
886}
bool hasToken(std::string line, std::string token)
Definition FUGen.cc:61
HDLGenerator::Language selectedLanguage()
Definition FUGen.cc:73

References HDLGenerator::CodeBlock::append(), hasToken(), replacesPerOp_, replaceToken(), selectedLanguage(), StringTools::stringToLower(), useGlock_, and useGlockRequest_.

Referenced by buildOperations().

Here is the call graph for this function:

◆ readFile()

std::deque< std::string > FUGen::readFile ( std::string  filename)
private

Definition at line 82 of file FUGen.cc.

82 {
83 std::deque<std::string> file;
84 // replace temps in operation implmentations and keep track of
85 // read temps.
86 if (filename == "") {
87 return file;
88 }
89
90 std::ifstream implStream(findAbsolutePath(filename));
91 for (std::string line; std::getline(implStream, line);) {
92 file.emplace_back(StringTools::stringToLower(line));
93 }
94 return file;
95}

References findAbsolutePath(), and StringTools::stringToLower().

Referenced by parseOperations().

Here is the call graph for this function:

◆ readImplementation()

void FUGen::readImplementation ( std::string  filename,
std::string  opName,
std::deque< std::string > &  sink 
)
private

Definition at line 492 of file FUGen.cc.

493 {
494 // replace temps in operation implmentations and keep track of
495 // read temps.
496 std::ifstream implStream(findAbsolutePath(filename));
497 for (std::string line; std::getline(implStream, line);) {
498 line = StringTools::stringToLower(line);
499 for (auto&& p : replacesPerOp_[opName]) {
500 line = replaceToken(line, p);
501 }
502
503 sink.emplace_back(line);
504 }
505}

References findAbsolutePath(), replacesPerOp_, replaceToken(), and StringTools::stringToLower().

Here is the call graph for this function:

◆ replaceToken()

std::string FUGen::replaceToken ( std::string  line,
Replace  replace 
)
private

Definition at line 67 of file FUGen.cc.

67 {
68 auto regex = std::regex("\\b" + replace.first + "\\b");
69 return std::regex_replace(line, regex, replace.second);
70}

Referenced by createExternalInterfaces(), prepareSnippet(), and readImplementation().

◆ scheduleOperations()

void FUGen::scheduleOperations ( )
private

Definition at line 1064 of file FUGen.cc.

1064 {
1065 std::set<std::string> instantiatedWires;
1066 for (auto&& op : operations_) {
1067 OperationSchedule schedule;
1068 schedule.baseOp = op;
1069
1070 if (frontRegistered_) {
1071 schedule.initialCycle = operationCycles_[op] - implLatency_[op];
1072 schedule.finalCycle = operationCycles_[op];
1073 } else if (middleRegistered_) {
1074 schedule.initialCycle =
1075 operationCycles_[op] - implLatency_[op] - 1;
1076 schedule.finalCycle = schedule.initialCycle + implLatency_[op];
1077 } else { // Back-registered
1078 schedule.initialCycle = 0;
1079 schedule.finalCycle = implLatency_[op];
1080 }
1081 assert(
1082 schedule.initialCycle >= 0 &&
1083 "Failure likely due to mis-selected operation implementation");
1084
1085 OperationPool opPool;
1086 Operation& osalOp = opPool.operation(op.c_str());
1088 for (int i = 1; i <= hwOp->operandCount(); ++i) {
1089 Operand& osalOperand = osalOp.operand(i);
1090 TTAMachine::FUPort* fuPort = hwOp->port(i);
1091 std::string port = fuPort->name();
1092 int width = osalOperand.width();
1093 int accessCycle;
1094 ProGe::Direction dir;
1095
1096 OperandConnection oper = {
1097 i, fuPort->width(), width,
1098 pipelineName(port, schedule.initialCycle), false};
1099 if (osalOperand.isInput()) {
1100 accessCycle = schedule.initialCycle;
1101 schedule.operands.push_back(oper);
1103 } else {
1104 accessCycle = operationCycles_[op] - schedule.finalCycle;
1105 schedule.results.insert(i);
1107 OutputConnection out = {
1108 width, i, schedule.finalCycle, accessCycle, op};
1109 portInputs_.emplace(port, out);
1110 }
1111
1112 assert(
1113 accessCycle >= 0 &&
1114 "Failure likely due to mis-selected operation "
1115 "implementation");
1116
1117 std::string newWire = operandSignal(op, i);
1118 if (!instantiatedWires.count(newWire)) {
1119 fu_ << Wire(newWire, width);
1120 instantiatedWires.insert(newWire);
1121 }
1122
1123 if (pipelineLength_.find(port) == pipelineLength_.end()) {
1124 pipelineLength_[port] = accessCycle;
1125 } else {
1126 pipelineLength_[port] =
1127 std::max(accessCycle, pipelineLength_[port]);
1128 }
1129
1130 if (portDirection_.find(port) == portDirection_.end()) {
1131 portDirection_[port] = dir;
1132 } else {
1133 if (portDirection_[port] != dir) {
1134 throw std::runtime_error(
1135 "Unsupported bidirectional port " + port +
1136 ", aborting.");
1137 }
1138 }
1139 }
1140
1141 if (baseOperations_.find(op) != baseOperations_.end()) {
1142 // No need to arbitrate between suboperations here,
1143 // just use the first resource
1144 for (auto&& res : baseOperations_[op].resources) {
1145 std::string resName = StringTools::stringToLower(res.name);
1146 schedule.resourceOffsets[resName] = 0;
1147 resourceCount_[res.name] =
1148 std::max(resourceCount_[res.name], res.count);
1149 }
1150 } else {
1151 assert(implementapleDAGs_.find(op) != implementapleDAGs_.end());
1152 auto dag = implementapleDAGs_[op];
1153 std::unordered_map<std::string, int> dagResourceCount;
1154
1155 for (int n = 0; n < dag->nodeCount(); ++n) {
1156 OperationSchedule subopSchedule;
1157 OperationDAGNode& node = dag->node(n);
1158
1159 OperationNode* operationNode =
1160 dynamic_cast<OperationNode*>(&node);
1161
1162 if (!operationNode) {
1163 continue;
1164 }
1165
1166 std::string subOp =
1167 operationNode->referencedOperation().name();
1168 subOp = StringTools::stringToLower(subOp);
1169
1170 std::string name = subOpName(operationNode);
1171 schedule.subOperations.push_back(name);
1172 subopSchedule.baseOp = subOp;
1173 // Start counting subopcycles from the upper op's initCycle.
1174 subopSchedule.initialCycle =
1175 schedule.initialCycle +
1177 *dag, node, implLatency_, false);
1178 subopSchedule.finalCycle =
1179 subopSchedule.initialCycle + implLatency_[subOp];
1180
1181 for (auto&& input : dag->inEdges(node)) {
1182 int dstID = input->dstOperand();
1183 int width = DAGNodeOperandWidth(
1184 dag->headNode(*input), dstID, dag);
1185
1186 std::string newWire = operandSignal(name, dstID);
1187 if (!instantiatedWires.count(newWire)) {
1188 fu_ << Wire(newWire, width);
1189 instantiatedWires.insert(newWire);
1190 }
1191
1192 subopSchedule.operands.push_back(
1193 subOpConnection(dag, input, false));
1194 }
1195
1196 for (auto&& output : dag->outEdges(node)) {
1197 int srcID = output->srcOperand();
1198 int width = DAGNodeOperandWidth(
1199 dag->tailNode(*output), srcID, dag);
1200
1201 std::string newWire = operandSignal(name, srcID);
1202 if (!instantiatedWires.count(newWire)) {
1203 fu_ << Wire(newWire, width);
1204 instantiatedWires.insert(newWire);
1205 }
1206
1207 subopSchedule.results.insert(srcID);
1208
1209 auto terminal =
1210 dynamic_cast<TerminalNode*>(&dag->headNode(*output));
1211
1212 if (terminal) {
1213 schedule.operands.push_back(
1214 subOpConnection(dag, output, true));
1215 }
1216 }
1217
1218 // TODO: make sure same resource doesn't get used by different
1219 // operations on _different_ pipeline cycles
1220 for (auto&& r : baseOperations_[subOp].resources) {
1221 std::string resName = StringTools::stringToLower(r.name);
1222 if (!dagResourceCount.count(resName)) {
1223 dagResourceCount[resName] = 0;
1224 }
1225 subopSchedule.resourceOffsets[resName] =
1226 dagResourceCount[resName];
1227 dagResourceCount[resName] += r.count;
1228 }
1229
1230 scheduledOperations_[name] = subopSchedule;
1231 }
1232
1233 for (auto&& d : dagResourceCount) {
1234 resourceCount_[d.first] =
1235 std::max(resourceCount_[d.first], d.second);
1236 }
1237 }
1238 scheduledOperations_[op] = schedule;
1239 }
1240}
int DAGNodeOperandWidth(OperationDAGNode &node, int id, OperationDAG *dag)
Definition FUGen.cc:201
OperandConnection subOpConnection(OperationDAG *dag, OperationDAGEdge *edge, bool isOutput)
Definition FUGen.cc:1024
bool middleRegistered_
Definition FUGen.hh:258
std::string subOpName(OperationNode *node)
Definition FUGen.cc:160
bool frontRegistered_
Definition FUGen.hh:257
virtual bool isInput() const
Definition Operand.cc:145
Operation & referencedOperation() const
virtual TCEString name() const
Definition Operation.cc:93
int maxLatencyToNode(const OperationDAG &dag, OperationDAGNode &node, const std::unordered_map< std::string, int > &maxOpLatency, bool allowDifference=true)

References adfFU_, assert, FUGen::OperationSchedule::baseOp, baseOperations_, DAGNodeOperandWidth(), FUGen::OperationSchedule::finalCycle, frontRegistered_, fu_, implementapleDAGs_, implLatency_, ProGe::IN, FUGen::OperationSchedule::initialCycle, Operand::isInput(), ProGeTools::maxLatencyToNode(), middleRegistered_, TTAMachine::Port::name(), Operation::name(), Operation::operand(), TTAMachine::HWOperation::operandCount(), FUGen::OperationSchedule::operands, operandSignal(), OperationPool::operation(), TTAMachine::FunctionUnit::operation(), operationCycles_, operations_, ProGe::OUT, pipelineLength_, pipelineName(), TTAMachine::HWOperation::port(), portDirection_, portInputs_, OperationNode::referencedOperation(), resourceCount_, FUGen::OperationSchedule::resourceOffsets, FUGen::OperationSchedule::results, scheduledOperations_, StringTools::stringToLower(), subOpConnection(), FUGen::OperationSchedule::subOperations, subOpName(), TTAMachine::BaseFUPort::width(), and Operand::width().

Referenced by implement().

Here is the call graph for this function:

◆ selectedLanguage()

Language FUGen::selectedLanguage ( )
private

Definition at line 73 of file FUGen.cc.

73 {
75 return Language::VHDL;
76 } else {
77 return Language::Verilog;
78 }
79}

References ProGeOptions::language, options_, and ProGe::VHDL.

Referenced by prepareSnippet().

◆ subOpConnection()

FUGen::OperandConnection FUGen::subOpConnection ( OperationDAG dag,
OperationDAGEdge edge,
bool  isOutput 
)
private

Definition at line 1024 of file FUGen.cc.

1025 {
1026 OperationDAGNode& srcNode = dag->tailNode(*edge);
1027 int srcID = edge->srcOperand();
1028 int srcWidth = DAGNodeOperandWidth(srcNode, srcID, dag);
1029
1030 OperationDAGNode& dstNode = dag->headNode(*edge);
1031 int dstID = edge->dstOperand();
1032 int dstWidth = DAGNodeOperandWidth(dstNode, dstID, dag);
1033 auto dstTerminal = dynamic_cast<TerminalNode*>(&dstNode);
1034 if (dstTerminal) {
1035 dstID = dstTerminal->operandIndex();
1036 }
1037
1038 auto operation = dynamic_cast<OperationNode*>(&srcNode);
1039 auto terminal = dynamic_cast<TerminalNode*>(&srcNode);
1040 auto constant = dynamic_cast<ConstantNode*>(&srcNode);
1041
1042 std::string signalName;
1043 if (operation) {
1044 std::string srcOp = subOpName(operation);
1045 srcOp = StringTools::stringToLower(srcOp);
1046 signalName = operandSignal(srcOp, srcID);
1047 } else if (terminal) {
1048 std::string srcOp = dag->operation().name();
1049 srcOp = StringTools::stringToLower(srcOp);
1050 srcID = terminal->operandIndex();
1051 signalName = operandSignal(srcOp, srcID);
1052 } else if (constant) {
1053 signalName = constantName(constant, dag);
1054 } else {
1055 assert(false && "It shouldn't be possible to get here.");
1056 }
1057
1059 dstID, srcWidth, dstWidth, signalName, isOutput};
1060 return conn;
1061}
virtual Node & headNode(const Edge &edge) const
virtual Node & tailNode(const Edge &edge) const
virtual int operandIndex() const

References assert, constantName(), DAGNodeOperandWidth(), OperationDAGEdge::dstOperand(), BoostGraph< GraphNode, GraphEdge >::headNode(), OperationPimpl::name(), TerminalNode::operandIndex(), operandSignal(), OperationDAG::operation(), OperationDAGEdge::srcOperand(), StringTools::stringToLower(), subOpName(), and BoostGraph< GraphNode, GraphEdge >::tailNode().

Referenced by scheduleOperations().

Here is the call graph for this function:

◆ subOpName()

std::string FUGen::subOpName ( OperationNode node)
private

Definition at line 160 of file FUGen.cc.

160 {
161 int id;
162 std::string op = node->referencedOperation().name();
164 if (nodeImplementations_.count(node->nodeID())) {
165 id = nodeImplementations_[node->nodeID()];
166 } else {
167 if (!subOpCount_.count(op)) {
168 subOpCount_[op] = 0;
169 }
170 id = subOpCount_[op];
171 subOpCount_[op] += 1;
172 nodeImplementations_[node->nodeID()] = id;
173 }
174 return "subop_" + op + "_" + std::to_string(id);
175}
std::unordered_map< std::string, int > subOpCount_
Definition FUGen.hh:226
std::unordered_map< int, int > nodeImplementations_
Definition FUGen.hh:238

References Operation::name(), GraphNode::nodeID(), nodeImplementations_, OperationNode::referencedOperation(), StringTools::stringToLower(), and subOpCount_.

Referenced by scheduleOperations(), and subOpConnection().

Here is the call graph for this function:

◆ triggerSignal()

std::string FUGen::triggerSignal ( int  stage)
private

Definition at line 122 of file FUGen.cc.

122 {
123 if (stage == 0) {
124 return "load_" + triggerPort_ + "_in";
125 } else {
126 return "optrig_" + std::to_string(stage) + "_r";
127 }
128}

References triggerPort_.

Referenced by buildOperations(), buildReplaces(), createOutputPipeline(), and createPortPipeline().

Member Data Documentation

◆ addressWidth_

int FUGen::addressWidth_ = 0
private

Definition at line 260 of file FUGen.hh.

Referenced by createExternalInterfaces(), createMandatoryPorts(), and FUGen().

◆ adfFU_

TTAMachine::FunctionUnit* FUGen::adfFU_
private

◆ backRegistered_

bool FUGen::backRegistered_ = false
private

Definition at line 259 of file FUGen.hh.

Referenced by implement().

◆ baseOperations_

std::unordered_map<std::string, BaseOperation> FUGen::baseOperations_
private

◆ behaviour_

HDLGenerator::Behaviour FUGen::behaviour_
private

◆ core_

ProGe::NetlistBlock* FUGen::core_
private

Definition at line 208 of file FUGen.hh.

Referenced by createExternalInterfaces(), and FUGen().

◆ dagConstantCount_

std::unordered_map<std::string, int> FUGen::dagConstantCount_
private

Definition at line 227 of file FUGen.hh.

Referenced by constantName().

◆ dagConstants_

std::unordered_map<int, DAGConstant> FUGen::dagConstants_
private

Definition at line 239 of file FUGen.hh.

Referenced by buildOperations(), and constantName().

◆ extIfaces_

std::unordered_set<std::string> FUGen::extIfaces_
private

Definition at line 244 of file FUGen.hh.

Referenced by createExternalInterfaces(), and parseOperations().

◆ extInputs_

std::unordered_set<std::string> FUGen::extInputs_
private

Definition at line 246 of file FUGen.hh.

Referenced by buildOperations(), and createExternalInterfaces().

◆ extOutputs_

std::set<std::pair<std::string, std::string> > FUGen::extOutputs_
private

Definition at line 245 of file FUGen.hh.

Referenced by buildOperations(), and createExternalInterfaces().

◆ frontRegistered_

bool FUGen::frontRegistered_ = false
private

Definition at line 257 of file FUGen.hh.

Referenced by implement(), and scheduleOperations().

◆ fu_

HDLGenerator::Module FUGen::fu_
private

◆ fug_

IDF::FUGenerated& FUGen::fug_
private

◆ globalOptions_

std::vector<std::string> FUGen::globalOptions_
private

Definition at line 205 of file FUGen.hh.

Referenced by createMandatoryPorts(), and finalizeHDL().

◆ implementapleDAGs_

std::unordered_map<std::string, OperationDAG*> FUGen::implementapleDAGs_
private

Definition at line 225 of file FUGen.hh.

Referenced by parseOperations(), and scheduleOperations().

◆ implLatency_

std::unordered_map<std::string, int> FUGen::implLatency_
private

Definition at line 224 of file FUGen.hh.

Referenced by parseOperations(), and scheduleOperations().

◆ isLSU_

bool FUGen::isLSU_ = false
private

Definition at line 261 of file FUGen.hh.

Referenced by buildOperations(), and isLSUDataPort().

◆ maxLatency_

int FUGen::maxLatency_
private

Definition at line 201 of file FUGen.hh.

Referenced by buildOperations(), createPortPipeline(), and parseOperations().

◆ middleRegistered_

bool FUGen::middleRegistered_ = false
private

Definition at line 258 of file FUGen.hh.

Referenced by implement(), and scheduleOperations().

◆ minLatency_

int FUGen::minLatency_
private

Definition at line 202 of file FUGen.hh.

Referenced by buildOperations(), and parseOperations().

◆ moduleName_

std::string FUGen::moduleName_
private

Definition at line 216 of file FUGen.hh.

Referenced by createExternalInterfaces(), and FUGen().

◆ netlistBlock_

ProGe::NetlistBlock* FUGen::netlistBlock_
private

Definition at line 217 of file FUGen.hh.

Referenced by createExternalInterfaces(), and FUGen().

◆ nodeImplementations_

std::unordered_map<int, int> FUGen::nodeImplementations_
private

Definition at line 238 of file FUGen.hh.

Referenced by subOpName().

◆ opcodeWidth_

int FUGen::opcodeWidth_
private

Definition at line 214 of file FUGen.hh.

Referenced by createFUHeaderComment(), createMandatoryPorts(), and createPortPipeline().

◆ operationCycles_

std::unordered_map<std::string, int> FUGen::operationCycles_
private

Definition at line 223 of file FUGen.hh.

Referenced by parseOperations(), and scheduleOperations().

◆ operations_

std::vector<std::string> FUGen::operations_
private

◆ options_

const ProGeOptions& FUGen::options_
private

◆ pipelineLength_

std::unordered_map<std::string, int> FUGen::pipelineLength_
private

Definition at line 233 of file FUGen.hh.

Referenced by createOutputPipeline(), createPortPipeline(), and scheduleOperations().

◆ portDirection_

std::unordered_map<std::string, ProGe::Direction> FUGen::portDirection_
private

Definition at line 234 of file FUGen.hh.

Referenced by createOutputPipeline(), createPortPipeline(), and scheduleOperations().

◆ portInputs_

std::unordered_multimap<std::string, OutputConnection> FUGen::portInputs_
private

Definition at line 235 of file FUGen.hh.

Referenced by createOutputPipeline(), and scheduleOperations().

◆ registers_

std::vector<std::string> FUGen::registers_
private

Definition at line 252 of file FUGen.hh.

Referenced by addRegisterIfMissing().

◆ renamedGlobalSignals_

std::vector<HDB::Variable> FUGen::renamedGlobalSignals_
private

Definition at line 249 of file FUGen.hh.

Referenced by buildOperations(), and buildReplaces().

◆ renamedVariables_

std::vector<HDB::Variable> FUGen::renamedVariables_
private

Definition at line 248 of file FUGen.hh.

Referenced by buildOperations(), and buildReplaces().

◆ replacesPerOp_

std::unordered_map<std::string, std::vector<Replace> > FUGen::replacesPerOp_
private

Definition at line 222 of file FUGen.hh.

Referenced by buildOperations(), prepareSnippet(), and readImplementation().

◆ resourceCount_

std::unordered_map<std::string, int> FUGen::resourceCount_
private

Definition at line 230 of file FUGen.hh.

Referenced by createOperationResources(), and scheduleOperations().

◆ resourceInputs_

std::vector<std::string> FUGen::resourceInputs_
private

Definition at line 241 of file FUGen.hh.

Referenced by buildOperations(), and createOperationResources().

◆ resourceOutputs_

std::vector<std::string> FUGen::resourceOutputs_
private

Definition at line 242 of file FUGen.hh.

Referenced by buildOperations(), and createOperationResources().

◆ scheduledOperations_

std::unordered_map<std::string, OperationSchedule> FUGen::scheduledOperations_
private

Definition at line 221 of file FUGen.hh.

Referenced by buildOperations(), buildReplaces(), and scheduleOperations().

◆ subOpCount_

std::unordered_map<std::string, int> FUGen::subOpCount_
private

Definition at line 226 of file FUGen.hh.

Referenced by subOpName().

◆ triggerPort_

std::string FUGen::triggerPort_
private

Definition at line 250 of file FUGen.hh.

Referenced by createShadowRegisters(), and triggerSignal().

◆ useGlock_

bool FUGen::useGlock_ = false
private

Definition at line 255 of file FUGen.hh.

Referenced by buildOperations(), and prepareSnippet().

◆ useGlockRequest_

bool FUGen::useGlockRequest_ = false
private

Definition at line 254 of file FUGen.hh.

Referenced by buildOperations(), finalizeHDL(), and prepareSnippet().


The documentation for this class was generated from the following files: