62 auto regex = std::regex(
"\\b" + token +
"\\b");
63 return std::regex_search(line, regex);
68 auto regex = std::regex(
"\\b" + replace.first +
"\\b");
69 return std::regex_replace(line, regex, replace.second);
75 return Language::VHDL;
77 return Language::Verilog;
81std::deque<std::string>
83 std::deque<std::string> file;
91 for (std::string line; std::getline(implStream, line);) {
102 if (file.length() > 4 && file.substr(0, 4) ==
"tce:") {
103 file = file.substr(4);
115 return "operation_in";
117 return "operation_" + std::to_string(stage) +
"_r";
126 return "optrig_" + std::to_string(stage) +
"_r";
132 return "op_" + operation +
"_c";
137 return operation +
"_op" + std::to_string(
id);
142 return "op" + std::to_string(
id);
148 return "data_" + port;
150 return "data_" + port +
"_" + std::to_string(cycle) +
"_r";
156 return "data_" + port +
"_" + std::to_string(cycle) +
"_valid_r";
174 return "subop_" + op +
"_" + std::to_string(
id);
197 return "dag_" + dagc.
operation +
"_" + std::to_string(dagc.
id) +
"_c";
210 opName = operation->referencedOperation().name();
211 }
else if (terminal) {
213 }
else if (constant) {
216 assert(
false &&
"Shouldn't be possible to get here.");
234 size_t maxOpNameLen = 0;
237 maxOpNameLen = std::max(maxOpNameLen, hwop->
name().size());
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);
268 std::string file, std::string format,
bool isSynthesizable) {
272 if (isSynthesizable) {
273 dir += format ==
"VHDL" ?
"vhdl" :
"verilog";
275 dir +=
"blackbox" +
DS;
276 dir += format ==
"VHDL simulation" ?
"vhdl" :
"verilog";
295 std::ofstream ofs(file);
301 std::ofstream ofs(file);
307 std::string hdb = opInfo.hdb;
313 for (
size_t i = 0; i < r.simFiles.size(); ++i) {
316 for (
size_t i = 0; i < r.synFiles.size(); ++i) {
328 std::string resetPort;
349 "data_" + adfPort->
name() +
"_in", adfPort->
width(),
354 "data_" + adfPort->
name() +
"_out", adfPort->
width(),
372 int prevLatency = -1;
373 for (
int operand = 0; operand < hwOpOperands; ++operand) {
380 int latency = hwOp->
latency(operand + 1);
381 if (prevLatency == -1) {
382 prevLatency = latency;
383 }
else if (prevLatency != latency) {
385 throw std::runtime_error(
386 "FUGen cannot implement multioutput operations (" + op +
387 ") which have different latencies for"
394std::vector<FUGen::Replace>
397 std::string op = schedule.
baseOp;
398 std::vector<FUGen::Replace> replaces;
400 replaces.emplace_back(
"glock",
"glock_in");
403 for (
auto&& operand : schedule.
operands) {
405 replaces.emplace_back(
408 for (
int id : schedule.
results) {
409 replaces.emplace_back(
421 assert(
false &&
"Couldn't find resource offset.");
425 for (
int i = 0; i < r.count; ++i) {
427 int resID = i + offset + 1;
430 for (
auto&& p : resource.
ports) {
432 std::string replace = pName +
"_" + std::to_string(portID);
434 rName +
"_" + std::to_string(resID) +
"_" + pName;
436 replaces.emplace_back(replace, with);
445 replica = name +
"_" + v.name;
446 replaces.emplace_back(v.name, replica);
448 bool nameFound =
false;
450 if (old_var.name == v.name) {
468 replica = name +
"_" + s.name;
469 replaces.emplace_back(s.name, replica);
472 bool nameFound =
false;
474 if (old_var.name == s.name) {
493 std::string filename, std::string opName, std::deque<std::string>& sink) {
497 for (std::string line; std::getline(implStream, line);) {
503 sink.emplace_back(line);
521 static const std::set<std::string> magicWords{
522 "avalid",
"aready",
"aaddr",
"awren",
"astrb",
523 "rvalid",
"rready",
"rdata",
"adata"};
525 for (
auto magicWord : magicWords) {
526 if (portName.find(magicWord) != std::string::npos) {
545 if (((pos = portName.find(
"avalid")) != std::string::npos)) {
547 }
else if (((pos = portName.find(
"aready")) != std::string::npos)) {
549 }
else if (((pos = portName.find(
"aaddr")) != std::string::npos)) {
551 }
else if (((pos = portName.find(
"awren")) != std::string::npos)) {
553 }
else if (((pos = portName.find(
"astrb")) != std::string::npos)) {
555 }
else if (((pos = portName.find(
"rvalid")) != std::string::npos)) {
557 }
else if (((pos = portName.find(
"rready")) != std::string::npos)) {
559 }
else if (((pos = portName.find(
"rdata")) != std::string::npos)) {
561 }
else if (((pos = portName.find(
"adata")) != std::string::npos)) {
564 return SigT::UNDEFINED;
569 std::set<std::pair<ProGe::NetlistPort*, ProGe::NetlistPort*>> lsuPorts;
573 for (
auto&& port : info.
ports) {
574 std::string width = port.width;
579 if (port.direction ==
"out") {
591 std::string extName =
moduleName_ +
"_" + port.name;
600 lsuPorts.insert(std::make_pair(internal, ext));
608 if (lsuPorts.empty()) {
618 for (
auto portPair : lsuPorts) {
624 dmemPortGroup->
addPort(*portPair.second);
627 if (dmemPortGroup !=
nullptr) {
629 dmemPortGroup =
nullptr;
635 std::map<std::string, int> instantiatedResources;
637 for (
auto&& r : rs.second.resources) {
638 if (!instantiatedResources.count(r.name)) {
639 instantiatedResources[r.name] = 0;
645 for (
int i = instantiatedResources[r.name]; i < rCount; ++i) {
646 auto module = ipxact::parseComponent(file);
647 Module resource(module, i + 1);
650 for (
auto&& p :
module.ports) {
651 std::string wName = StringTools::stringToLower(
652 rName + "_" + std::to_string(i + 1) + "_" + p.name);
659 if (p.direction ==
"in") {
666 instantiatedResources[r.name] = rCount;
692 auto spec = pair.second;
699 operationCp.
reads(signal);
703 operationCp.
reads(signal);
706 std::set<std::string> defaultStatements;
708 auto schedule = pair.second;
709 std::string name = pair.first;
711 for (
int id : schedule.results) {
721 for (
auto&& operand : schedule.operands) {
724 std::string source = operand.signalName;
726 if (operand.portWidth > operand.operandWidth) {
729 Splice(source, operand.operandWidth - 1, 0)));
730 }
else if (operand.portWidth < operand.operandWidth) {
733 Ext(source, operand.operandWidth, operand.portWidth)));
738 if (!operand.isOutput) {
739 operationCp.
reads(destination);
745 std::string baseOp = schedule.baseOp;
747 if (!initial.empty()) {
748 prepareSnippet(name, initial, defaultSnippets, defaultStatements);
752 for (
int cycle = 0; cycle <=
maxLatency_; ++cycle) {
754 bool emptySwitch =
true;
758 bool emptyBlock =
true;
761 std::vector<std::string> schedules = schedule.subOperations;
762 schedules.push_back(op);
764 for (std::string subop : schedules) {
766 std::string baseOp = schedule.baseOp;
767 if (schedule.initialCycle == cycle) {
770 std::set<std::string> statements;
776 if (schedule.finalCycle == cycle) {
778 if (!postOp.empty()) {
779 std::set<std::string> statements;
800 triggeredSnippets.
append(opIf);
809 triggeredSnippets.
append(opIf);
814 operationCp.
reads(
"glock_in");
822 int w = std::stoi(v.width);
823 if (v.type ==
"Logic") {
825 }
else if (v.type ==
"Unsigned") {
838 int w = std::stoi(s.width);
840 operationCp.
reads(s.name);
849 operationCp << defaultValues << defaultSnippets << triggeredSnippets;
855 std::string name, std::deque<std::string> statements,
CodeBlock& sink,
856 std::set<std::string>& addedStatements) {
857 std::deque<std::string> snippet;
858 std::set<std::string> lines;
859 for (std::string line : statements) {
866 if (addedStatements.count(replaced)) {
869 lines.insert(replaced);
871 snippet.push_back(replaced);
881 for (std::string line : lines) {
882 addedStatements.insert(line);
908 std::vector<std::string> dagOperations;
912 opInfo.
name = op.operationName;
921 std::string implFile;
930 const std::string msg =
931 "Cannot generate operation \"" + opInfo.
name +
932 "\" due to missing verilog operation implementation";
933 throw std::runtime_error(msg);
948 if (!ifPath.empty()) {
960 for (
int operand = 0; operand < hwOpOperands; ++operand) {
964 std::string portName = fuPort->
name();
965 int latency = hwOp->
latency(operand + 1);
979 dagOperations.emplace_back(op);
983 for (
auto&& op : dagOperations) {
992 throw std::runtime_error(op +
" has no dags to implement.");
995 bool implementable =
false;
996 for (
int i = 0; i < dagCount; ++i) {
1002 dagPtr = &osalOp->
dag(i);
1009 implementable =
true;
1017 if (!implementable) {
1018 throw std::runtime_error(op +
" has no valid dags to implement.");
1033 auto dstTerminal =
dynamic_cast<TerminalNode*
>(&dstNode);
1042 std::string signalName;
1044 std::string srcOp =
subOpName(operation);
1047 }
else if (terminal) {
1050 srcID = terminal->operandIndex();
1052 }
else if (constant) {
1055 assert(
false &&
"It shouldn't be possible to get here.");
1059 dstID, srcWidth, dstWidth, signalName, isOutput};
1065 std::set<std::string> instantiatedWires;
1083 "Failure likely due to mis-selected operation implementation");
1091 std::string port = fuPort->
name();
1092 int width = osalOperand.
width();
1097 i, fuPort->
width(), width,
1108 width, i, schedule.
finalCycle, accessCycle, op};
1114 "Failure likely due to mis-selected operation "
1118 if (!instantiatedWires.count(newWire)) {
1120 instantiatedWires.insert(newWire);
1134 throw std::runtime_error(
1135 "Unsupported bidirectional port " + port +
1153 std::unordered_map<std::string, int> dagResourceCount;
1155 for (
int n = 0; n < dag->nodeCount(); ++n) {
1162 if (!operationNode) {
1170 std::string name =
subOpName(operationNode);
1172 subopSchedule.
baseOp = subOp;
1181 for (
auto&& input : dag->inEdges(node)) {
1182 int dstID = input->dstOperand();
1184 dag->headNode(*input), dstID, dag);
1187 if (!instantiatedWires.count(newWire)) {
1189 instantiatedWires.insert(newWire);
1196 for (
auto&& output : dag->outEdges(node)) {
1197 int srcID = output->srcOperand();
1199 dag->tailNode(*output), srcID, dag);
1202 if (!instantiatedWires.count(newWire)) {
1204 instantiatedWires.insert(newWire);
1207 subopSchedule.
results.insert(srcID);
1222 if (!dagResourceCount.count(resName)) {
1223 dagResourceCount[resName] = 0;
1226 dagResourceCount[resName];
1227 dagResourceCount[resName] += r.count;
1233 for (
auto&& d : dagResourceCount) {
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;
1252 portWidth[adfPort->
name()] = adfPort->
width();
1255 currentName[adfPort->
name()] =
"data_" + adfPort->
name() +
"_in";
1261 inOperands.emplace_back(adfPort->
name());
1263 registeredInOperands.emplace(adfPort->
name());
1269 currentName[adfPort->
name()] =
"data_" + adfPort->
name() +
"_out";
1274 for (
auto&& p : inOperands) {
1275 std::string newName =
"data_" + p +
"_gated";
1277 Sext(
"load_" + p +
"_in", portWidth[p], 1);
1279 currentName[p] = newName;
1280 fu_ <<
Wire(newName, portWidth[p]);
1284 for (
auto&& p : inOperands) {
1285 std::string dataPort = currentName[p];
1288 registeredInOperands.find(p) != registeredInOperands.end()) {
1289 std::string loadPort =
"load_" + p +
"_in";
1290 std::string shadowReg =
"shadow_" + p +
"_r";
1292 fu_ <<
Register(shadowReg, portWidth[p], ResetOption::Optional);
1301 auto triggerLoad =
Equals(
1305 triggerLoad && portLoad,
1332 pipelineAssignments.
append(
1339 pipelineAssignments.
append(
1347 int width = port->
width();
1352 for (
int i = 0; i < length; ++i) {
1354 std::string nextReg =
pipelineName(port->name(), i + 1);
1359 pipelineAssignments.
append(
1365 If operationTrigger(
1367 pipelineAssignments.
append(operationTrigger);
1370 pipelineAssignments);
1372 pipeline << glock_low;
1379 fu_ <<
Register(name, width, wt, ResetOption::Optional);
1392 int width = port->
width();
1397 auto inputs =
portInputs_.equal_range(port->name());
1398 for (
int cycle = length; cycle >= 0; --cycle) {
1399 bool cycleActive =
false;
1401 std::string nextReg =
pipelineName(port->name(), cycle);
1402 std::string prevReg =
pipelineName(port->name(), cycle + 1);
1406 fu_ <<
Wire(nextReg, width, WireType::Vector);
1415 for (
auto it = inputs.first; it != inputs.second; ++it) {
1416 auto connection = it->second;
1417 if (connection.pipelineStage != cycle) {
1432 width, connection.operandWidth);
1437 triggered,
Assign(nextReg, source));
1440 active,
Assign(nextReg, source));
1445 If(triggered,
Assign(nextReg, source));
1447 validOperations =
If(active,
Assign(nextReg, source));
1453 bool skip_last_assign =
false;
1455 if (cycle != length) {
1456 std::string prevValid =
1465 skip_last_assign =
true;
1476 std::string outReg = nextReg +
"_r";
1481 if (!skip_last_assign) {
1484 lastStage.
append(validOperations);
1486 lastStage.
append(finalStep);
1491 outputPipeline.
append(validOperations);
1495 "data_" + port->name() +
"_out",
1517 const std::vector<IDF::FUGenerated>& generatetFUs,
1520 for (
auto fug : generatetFUs) {
1526 fug.name(),
options.fuFrontRegistered,
false)) {
1529 fug.name(),
options.fuMiddleRegistered,
false)) {
1532 fug.name(),
options.fuBackRegistered,
false)) {
1535 fug.name(),
options.fuFrontRegistered)) {
1538 fug.name(),
options.fuMiddleRegistered)) {
#define assert(condition)
TTAMachine::Machine * machine
the architecture definition of the estimated processor
static MachInfoCmdLineOptions options
virtual Node & headNode(const Edge &edge) const
virtual Node & tailNode(const Edge &edge) const
virtual long value() const
static std::vector< std::string > hdbPaths(bool libraryPathsOnly=false)
ProGe::Signal inferLSUSignal(const std::string &portName) const
void createShadowRegisters()
std::string opcodeSignal(int stage)
std::unordered_map< std::string, BaseOperation > baseOperations_
void scheduleOperations()
void readImplementation(std::string filename, std::string opName, std::deque< std::string > &sink)
void createPortPipeline()
std::unordered_map< std::string, int > pipelineLength_
std::pair< std::string, std::string > Replace
void createExternalInterfaces(bool genIntegrator)
std::vector< Replace > buildReplaces(std::string opName)
std::string pipelineValid(std::string port, int cycle)
std::string operandPlaceholder(int id)
std::vector< std::string > resourceInputs_
std::vector< HDB::Variable > renamedGlobalSignals_
std::vector< std::string > globalOptions_
void createOperationResources()
int DAGNodeOperandWidth(OperationDAGNode &node, int id, OperationDAG *dag)
void addRegisterIfMissing(std::string name, int width, HDLGenerator::WireType wt=HDLGenerator::WireType::Auto)
std::string pipelineName(std::string port, int cycle)
std::string replaceToken(std::string line, Replace replace)
std::unordered_map< std::string, OperationDAG * > implementapleDAGs_
ProGe::NetlistBlock * core_
void copyImplementation(std::string file, std::string format, bool isSynthesizable)
std::deque< std::string > readFile(std::string filename)
std::unordered_set< std::string > extInputs_
std::unordered_map< std::string, int > operationCycles_
OperandConnection subOpConnection(OperationDAG *dag, OperationDAGEdge *edge, bool isOutput)
std::string constantName(ConstantNode *node, OperationDAG *dag)
std::unordered_multimap< std::string, OutputConnection > portInputs_
bool hasToken(std::string line, std::string token)
std::string opcodeConstant(std::string operation)
HDLGenerator::Behaviour behaviour_
std::unordered_map< std::string, int > subOpCount_
std::unordered_map< std::string, int > implLatency_
std::unordered_map< std::string, int > resourceCount_
void prepareSnippet(std::string name, std::deque< std::string > statements, HDLGenerator::CodeBlock &sink, std::set< std::string > &addedStatements)
const ProGeOptions & options_
std::string operandSignal(std::string operation, int id)
std::unordered_map< std::string, std::vector< Replace > > replacesPerOp_
std::unordered_map< std::string, ProGe::Direction > portDirection_
void createMandatoryPorts()
std::string triggerSignal(int stage)
bool isLSUDataPort(const std::string &portName)
HDLGenerator::Language selectedLanguage()
std::vector< std::string > resourceOutputs_
TTAMachine::FunctionUnit * adfFU_
std::set< std::pair< std::string, std::string > > extOutputs_
std::string subOpName(OperationNode *node)
std::string findAbsolutePath(std::string file)
std::vector< std::string > operations_
void createFUHeaderComment()
std::unordered_map< std::string, int > dagConstantCount_
std::vector< std::string > registers_
std::unordered_set< std::string > extIfaces_
std::unordered_map< int, DAGConstant > dagConstants_
std::unordered_map< std::string, OperationSchedule > scheduledOperations_
ProGe::NetlistBlock * netlistBlock_
static void implement(const ProGeOptions &options, std::vector< std::string > globalOptions, const std::vector< IDF::FUGenerated > &generatetFUs, const TTAMachine::Machine &machine, ProGe::NetlistBlock *core)
void createImplementationFiles()
std::unordered_map< int, int > nodeImplementations_
void createOutputPipeline()
std::vector< HDB::Variable > renamedVariables_
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 std::string directoryOfPath(const std::string fileName)
static std::string findFileInSearchPaths(const std::vector< std::string > &searchPaths, const std::string &file)
static bool fileExists(const std::string fileName)
static CachedHDBManager & instance(const std::string &hdbFile)
OperationImplementation OperationImplementationByID(RowID id) const
virtual void reads(const std::string &var) override
const std::string & name() const noexcept
void elseIfClause(LHSValue cls, SS ifBlock)
void elseClause(SS elseBlock)
void implement(std::ostream &stream, Language lang, int level=0)
void appendToHeader(const std::string &line)
void set_prefix(std::string prefix)
std::vector< Info > & operations()
virtual bool isInput() const
virtual int width() const
const class OperationPimpl & operation() const
Operation * effectiveOperation(const TCEString &name)
Operation & referencedOperation() const
Operation & operation(const char *name)
virtual OperationDAG & dag(int index) const
virtual TCEString name() const
virtual int dagCount() const
virtual Operand & operand(int id) const
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)
virtual int width() const
virtual TCEString name() const
virtual bool isTriggering() const
virtual AddressSpace * addressSpace() const
virtual HWOperation * operation(const std::string &name) const
virtual int operationCount() const
virtual bool hasAddressSpace() const
virtual BaseFUPort * port(const std::string &name) const
virtual FUPort * port(int operand) const
const std::string & name() const
virtual bool isInput() const
virtual bool isOutput() const
virtual std::string name() const
virtual int portCount() const
virtual int operandIndex() const
@ BIT_VECTOR
Several bits.
@ 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.
BusInfo parseBus(std::string file)
ModuleInfo parseComponent(std::string file)
std::vector< HDB::OperationImplementationResource > resources
std::deque< std::string > implementation
std::vector< HDB::Variable > globalsignals
std::deque< std::string > postOp
std::vector< HDB::Variable > variables
std::deque< std::string > initial
std::vector< std::string > subOperations
std::vector< OperandConnection > operands
std::map< std::string, int > resourceOffsets
std::string postOpImplFileVhdl
std::vector< Variable > verilogVariables
std::string initialImplFileVerilog
std::string absBusDefFile
std::vector< Variable > vhdlGlobalSignals
std::vector< Variable > verilogGlobalSignals
std::vector< OperationImplementationResource > resources
std::string postOpImplFileVerilog
std::string implFileVerilog
std::string initialImplFileVhdl
std::vector< Variable > vhdlVariables
std::vector< std::string > fuIcGateList
std::string outputDirectory
std::vector< std::string > hdbList
std::vector< Port > ports
std::vector< Port > ports