#include "GroupBlock.h"
#include "ReferenceBlock.h"
#include "FunctionalBlock.h"
-#include "Exception.h"
+#include "SpecialBlock.h"
+#include "BlockParameter.h"
+#include "ConnectedInterface.h"
Graph::Graph() {
- topGroup = new GroupBlock(NULL);
- topGroup->setName("top group");
- groups.append(topGroup);
+ topGroup = NULL;
}
Graph::~Graph() {
delete topGroup;
}
+void Graph::createTopGroup(bool createTopGroupIfaces) {
+ topGroup = new GroupBlock(this, NULL, createTopGroupIfaces);
+ topGroup->setName("top group");
+ groups.append(topGroup);
+}
+
QList<AbstractInterface *> Graph::getOutsideInterfaces() {
return topGroup->getInterfaces();
}
-GroupBlock* Graph::createChildGroupBlock(GroupBlock* parent) {
- GroupBlock* b = new GroupBlock(parent);
+GroupBlock* Graph::createChildGroupBlock(GroupBlock* parent, bool createGroupIface) {
+ GroupBlock* b = new GroupBlock(this, parent, createGroupIface);
groups.append(b);
return b;
}
-bool Graph::removeGroupBlock(GroupBlock *group) {
+void Graph::removeGroupBlock(GroupBlock *group) {
group->removeAllBlocks();
GroupBlock* parent = AB_TO_GRP(group->getParent());
parent->removeBlock(group);
return NULL;
}
-FunctionalBlock* Graph::createFunctionalBlock(GroupBlock* group, ReferenceBlock* ref) {
+FunctionalBlock* Graph::createFunctionalBlock(GroupBlock* group, ReferenceBlock* ref, bool createIfaces) {
- FunctionalBlock* newBlock = new FunctionalBlock(group,ref);
- newBlock->populate();
+ FunctionalBlock* newBlock = NULL;
+ if (ref->getSpecialType() != SpecialBlock::NotSpecial) {
+ cout << "Graph: create special block from " << qPrintable(ref->getName()) << endl;
+ newBlock = new SpecialBlock(this, ref->getSpecialType(), group,ref, createIfaces);
+ }
+ else {
+ cout << "Graph: create normal block from " << qPrintable(ref->getName()) << endl;
+ newBlock = new FunctionalBlock(this, group,ref, createIfaces);
+ }
group->addBlock(newBlock);
return newBlock;
GroupBlock* group = AB_TO_GRP(block->getParent());
// adding to the graph
- FunctionalBlock* newBlock = createFunctionalBlock(group,ref);
+ FunctionalBlock* newBlock = createFunctionalBlock(group,ref, true);
return newBlock;
}
return block;
}
-FunctionalBlock* Graph::createSourceBlock(ReferenceBlock* ref) {
+FunctionalBlock* Graph::createStimuliBlock(ReferenceBlock* ref, bool createIfaces) {
+ /* A stimuli block is always a special block with idSpecial = 1 */
- FunctionalBlock* newBlock = new FunctionalBlock(NULL,ref);
- newBlock->populate();
- sources.append(newBlock);
+ FunctionalBlock* newBlock = new SpecialBlock(this, AbstractBlock::Source, NULL,ref, createIfaces);
+ stimulis.append(newBlock);
return newBlock;
}
-FunctionalBlock* Graph::duplicateSourceBlock(FunctionalBlock *block) {
+FunctionalBlock* Graph::duplicateStimuliBlock(FunctionalBlock *block) {
- ReferenceBlock* ref = block->getReference();
- GroupBlock* group = AB_TO_GRP(block->getParent());
+ ReferenceBlock* ref = block->getReference();
// adding to the graph
- FunctionalBlock* newBlock = createSourceBlock(ref);
+ FunctionalBlock* newBlock = createStimuliBlock(ref, true);
return newBlock;
}
-FunctionalBlock* Graph::getSourceBlockByName(QString name) {
- foreach(FunctionalBlock* block, sources) {
+FunctionalBlock* Graph::getStimuliBlockByName(QString name) {
+ foreach(FunctionalBlock* block, stimulis) {
if (block->getName() == name) return block;
}
return NULL;
}
-bool Graph::removeSourceBlock(FunctionalBlock *block) {
- sources.removeAll(block);
+bool Graph::removeStimuliBlock(FunctionalBlock *block) {
+ stimulis.removeAll(block);
return true;
}
void Graph::createPatterns() throw(Exception) {
- bool ok = true;
- foreach(AbstractBlock* block, sources) {
+
+ foreach(AbstractBlock* block, stimulis) {
FunctionalBlock* funBlock = AB_TO_FUN(block);
try {
funBlock->createPatterns();
}
void Graph::resetPatternComputed() {
- foreach(AbstractBlock* block, sources) {
- block->setPatternComputed(false);
+ foreach(AbstractBlock* block, stimulis) {
+ block->setOutputPatternComputed(false);
+ block->resetTraversalLevel();
}
foreach(AbstractBlock* block, groups) {
GroupBlock* group = AB_TO_GRP(block);
- group->setPatternComputed(false);
+ group->setOutputPatternComputed(false);
+ block->resetTraversalLevel();
foreach(AbstractBlock* inBlock, group->getBlocks()) {
- inBlock->setPatternComputed(false);
+ inBlock->setOutputPatternComputed(false);
+ block->resetTraversalLevel();
}
}
}
-bool Graph::computeOutputPatterns(int nbExec) {
+void Graph::computeOutputPatterns(int nbExec) throw(Exception) {
try {
createPatterns();
}
catch(Exception e) {
- cerr << qPrintable(e.getMessage()) << endl;
- return false;
+ throw(e);
}
- resetPatternComputed();
- // search for all block that are generators.
- QList<FunctionalBlock*> generators;
- generators.append(sources);
+ resetPatternComputed();
+ // search for all block that are source.
+ QList<FunctionalBlock*> sources;
+ sources.append(stimulis);
foreach(AbstractBlock* block, groups) {
GroupBlock* group = AB_TO_GRP(block);
foreach(AbstractBlock* inBlock, group->getBlocks()) {
FunctionalBlock* funBlock = AB_TO_FUN(inBlock);
- if ((inBlock->isFunctionalBlock()) && (inBlock->isGeneratorBlock())) {
- generators.append(funBlock);
+ if (inBlock->isSourceBlock()) {
+ sources.append(funBlock);
}
}
}
// search for maximum PP length
int maxPP = 0;
- foreach(FunctionalBlock* block, generators) {
+ foreach(FunctionalBlock* block, sources) {
if (block->getProductionPatternLength() > maxPP) maxPP = block->getProductionPatternLength();
}
// compute output for generators
int maxExecLen = maxPP*nbExec;
- foreach(FunctionalBlock* block, generators) {
+ foreach(FunctionalBlock* block, sources) {
int d = block->getProductionPatternLength();
block->computeOutputPattern((maxExecLen+d-1)/d);
}
topGroup->computeOutputPattern();
}
catch(Exception e) {
- cerr << qPrintable(e.getMessage()) << endl;
- return false;
+ throw(e);
+ }
+}
+
+void Graph::generateVHDL(const QString &path) throw(Exception) {
+ // generating VHDL for stimulis
+ cout << "generating stimulis" << endl;
+ try {
+ foreach(FunctionalBlock* stimuli, stimulis) {
+ stimuli->generateVHDL(path);
+ }
+ }
+ catch(Exception e) {
+ throw(e);
+ }
+ // generating VHDL for top group
+ cout << "generating top group" << endl;
+ try {
+ topGroup->generateVHDL(path);
+ }
+ catch(Exception e) {
+ throw(e);
+ }
+}
+
+void Graph::generateTestbench(const QString &projectName, const QString &benchFile) throw(Exception) {
+
+
+ QFile vhdlBench(benchFile);
+
+ if (!vhdlBench.open(QIODevice::WriteOnly)) {
+ throw(Exception(VHDLFILE_NOACCESS));
+ }
+
+ cout << "generate testbench" << endl;
+ QTextStream out(&vhdlBench);
+
+ out << "-------------------------------------------------------------------------------" << endl;
+ out << "-- testbench for " << projectName << endl;
+ out << "-------------------------------------------------------------------------------" << endl << endl;
+ out << "-------------------------------------------------------------------------------" << endl;
+ out << "-- clock generator" << endl;
+ out << "-------------------------------------------------------------------------------" << endl << endl;
+
+ out << "library IEEE;" << endl;
+ out << "use IEEE.STD_LOGIC_1164.all;" << endl;
+ out << "use IEEE.numeric_std.all;" << endl;
+ out << "entity clock_gen is" << endl;
+ out << " generic (" << endl;
+ out << " Tps : time -- high level width : must be < period" << endl;
+ out << " );" << endl;
+ out << " port (" << endl;
+ out << " phase : out std_logic" << endl;
+ out << " );" << endl;
+ out << "end entity clock_gen;" << endl<< endl;
+
+ out << "architecture clock_gen_1 of clock_gen is" << endl;
+ out << " constant period : time := 2*Tps;" << endl;
+ out << "begin" << endl;
+ out << " clock_process : process" << endl;
+ out << " begin" << endl;
+ out << " phase <= '1', '0' after Tps;" << endl;
+ out << " wait for period;" << endl;
+ out << " end process clock_process;" << endl;
+ out << "end architecture clock_gen_1;" << endl << endl;
+
+ out << "-------------------------------------------------------------------------------" << endl;
+ out << "-- testbench" << endl;
+ out << "-------------------------------------------------------------------------------" << endl << endl;
+ out << "library IEEE;" << endl;
+ out << "use IEEE.STD_LOGIC_1164.all;" << endl;
+ out << "use IEEE.numeric_std.all;" << endl;
+ out << "entity " << projectName << "_tb is" << endl;
+ out << "end entity " << projectName << "_tb;" << endl << endl;
+
+ out << "architecture " << projectName << "_tb_1 of " << projectName << "_tb is" << endl << endl;
+
+ out << " component clock_gen" << endl;
+ out << " generic (" << endl;
+ out << " Tps : time" << endl;
+ out << " );" << endl;
+ out << " port (" << endl;
+ out << " phase : out std_logic" << endl;
+ out << " );" << endl;
+ out << " end component;" << endl << endl;
+
+ topGroup->generateComponent(out,false);
+ foreach(FunctionalBlock* block, stimulis) {
+ block->generateComponent(out,false);
+ }
+
+ out << " ----------------------------" << endl;
+ out << " -- SIGNALS" << endl;
+ out << " ----------------------------" << endl << endl;
+
+ out << " -- signals to reset stimulis" << endl;
+ foreach(FunctionalBlock* block, stimulis) {
+ out << " signal reset_" << block->getName() << " : std_logic;" << endl;
+ }
+ out << endl;
+
+ out << " -- signals for external clocks/reset" << endl;
+ for(int i=0;i<clocks.size();i++) {
+ out << " signal ext_clk_" << i << " : std_logic;" << endl;
+ out << " signal ext_reset_" << i << " : std_logic;" << endl;
+ }
+ out << endl;
+
+ // signals out of stimulis blocks
+ foreach(FunctionalBlock* block, stimulis) {
+ /* NB: normally, a stimuli has at least an input interface of type data
+ that is used to trigger the generation. It is necessarily called start.
+ It may have an additional input that is necessarily called stop.
+ */
+ try {
+ out << " -- signals from input ports of " << block->getName() << endl;
+ QList<AbstractInterface*> listInputs = block->getInputs();
+ foreach(AbstractInterface* iface, listInputs) {
+ if (iface->getPurpose() == AbstractInterface::Data) {
+ out << " signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
+ }
+ }
+ }
+ catch(Exception e) {
+ throw(e);
+ }
+ try {
+ out << " -- signals from output ports of " << block->getName() << endl;
+ QList<AbstractInterface*> listOutputs = block->getOutputs();
+ foreach(AbstractInterface* iface, listOutputs) {
+ if ((iface->getPurpose() == AbstractInterface::Data)||(iface->getPurpose() == AbstractInterface::Control)) {
+ out << " signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
+ }
+ }
+ }
+ catch(Exception e) {
+ throw(e);
+ }
+ out << endl;
+ }
+ out << endl;
+
+ // signals out of top group
+ try {
+ out << " -- signals from output ports of " << topGroup->getName() << endl;
+ QList<AbstractInterface*> listOutputs = topGroup->getOutputs();
+ foreach(AbstractInterface* iface, listOutputs) {
+ if ((iface->getPurpose() == AbstractInterface::Data)||(iface->getPurpose() == AbstractInterface::Control)) {
+ out << " signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
+ }
+ }
+ }
+ catch(Exception e) {
+ throw(e);
+ }
+ out << endl;
+
+ // signals out of top group
+ try {
+ out << " -- signals from inout ports of " << topGroup->getName() << endl;
+ QList<AbstractInterface*> listBidirs = topGroup->getBidirs();
+ foreach(AbstractInterface* iface, listBidirs) {
+ if (iface->getPurpose() == AbstractInterface::Data) {
+ out << " signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
+ }
+ }
+ }
+ catch(Exception e) {
+ throw(e);
}
+ out << endl;
+
+ out << "begin" << endl;
+ // for now assign all external resets to fixed 0 because of clkrstgen in top group
+ for(int i=0;i<clocks.size();i++) {
+ out << " ext_reset_" << i << " <= '0';" << endl;
+ }
+ out << endl;
+ // generate clock instances
+ for(int i=0;i<clocks.size();i++) {
+ double halfPer = 500.0/clocks.at(i);
+ out << " clock_" << i << " : clock_gen" << endl;
+ out << " generic map (" << endl;
+ out << " Tps => " << halfPer << " ns" << endl;
+ out << " )" << endl;
+ out << " port map (" << endl;
+ out << " phase => ext_clk_" << i << endl;
+ out << " );" << endl << endl;
+ }
+ // generate instances of stimulis
+ foreach(FunctionalBlock* block, stimulis) {
+ try {
+ out << " " << block->getName() << "_1 : " << block->getName() << endl;
+
+ QList<BlockParameter*> listGenerics = block->getGenericParameters();
+ QList<AbstractInterface*> listInputs = block->getInputs();
+ QList<AbstractInterface*> listOutputs = block->getOutputs();
+
+ if (!listGenerics.isEmpty()) {
+ out << " generic map (" << endl;
+ int i;
+ for(i=0;i<listGenerics.size()-1;i++) {
+ out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance, BlockParameter::NoComma) << "," << endl;
+ }
+ out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance,BlockParameter::NoComma) << endl;
+ out << " )" << endl;
+ }
+
+ out << " port map (" << endl;
+ QString portMap = "";
+
+ for(int i=0;i<listInputs.size();i++) {
+ ConnectedInterface* connIface = AI_TO_CON(listInputs.at(i));
+ if ( (connIface->getPurpose() == AbstractInterface::Data) || (connIface->getPurpose() == AbstractInterface::Control)) {
+ portMap += " " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
+ }
+ else if (connIface->getPurpose() == AbstractInterface::Clock) {
+ // get the "fake" clkrstgen from which it is connected
+ ConnectedInterface* fromIface = connIface->getConnectedFrom();
+ QString clkrstName = fromIface->getOwner()->getName();
+ clkrstName.remove(0,10);
+ portMap += " " + connIface->getName() + " => ext_clk_" + clkrstName + ",\n";
+ }
+ else if (connIface->getPurpose() == AbstractInterface::Reset) {
+ portMap += " " + connIface->getName() + " => reset_" + block->getName()+",\n";
+ }
+ }
+ for(int i=0;i<listOutputs.size();i++) {
+ ConnectedInterface* connIface = AI_TO_CON(listOutputs.at(i));
+ portMap += " " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
+ }
+ portMap.chop(2);
+ out << portMap << endl;
+
+
+ out << " );" << endl;
+ }
+ catch(Exception e) {
+ throw(e);
+ }
+ out << endl;
+ }
+ out << endl;
+ // generate instance of top group
+ try {
+ out << " " << topGroup->getName() << "_1 : " << topGroup->getName() << endl;
+
+ QList<BlockParameter*> listGenerics = topGroup->getGenericParameters();
+ QList<AbstractInterface*> listInputs = topGroup->getInputs();
+ QList<AbstractInterface*> listOutputs = topGroup->getOutputs();
+ QList<AbstractInterface*> listBidirs = topGroup->getBidirs();
+
+ if (!listGenerics.isEmpty()) {
+ out << " generic map (" << endl;
+ int i;
+ for(i=0;i<listGenerics.size()-1;i++) {
+ out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance, BlockParameter::NoComma) << "," << endl;
+ }
+ out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance,BlockParameter::NoComma) << endl;
+ out << " )" << endl;
+ }
+
+ out << " port map (" << endl;
+ QString portMap = "";
+
+ for(int i=0;i<listInputs.size();i++) {
+ ConnectedInterface* connIface = AI_TO_CON(listInputs.at(i));
+ if ( (connIface->getPurpose() == AbstractInterface::Data) || (connIface->getPurpose() == AbstractInterface::Control)) {
+ ConnectedInterface* fromIface = connIface->getConnectedFrom();
+ portMap += " " + connIface->getName() + " => " + fromIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
+ }
+ else if ( (connIface->getPurpose() == AbstractInterface::Clock) || (connIface->getPurpose() == AbstractInterface::Reset)) {
+ portMap += " " + connIface->getName() + " => " + connIface->getName() + ",\n";
+ }
+ }
+ for(int i=0;i<listOutputs.size();i++) {
+ ConnectedInterface* connIface = AI_TO_CON(listOutputs.at(i));
+ portMap += " " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
+ }
+ for(int i=0;i<listBidirs.size();i++) {
+ ConnectedInterface* connIface = AI_TO_CON(listBidirs.at(i));
+ portMap += " " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
+ }
+ portMap.chop(2);
+ out << portMap << endl;
+
+
+ out << " );" << endl;
+ }
+ catch(Exception e) {
+ throw(e);
+ }
+ out << endl;
+
+ // generate process for stimulis
+ foreach(FunctionalBlock* block, stimulis) {
+ // getting the start input
+ AbstractInterface* startIface = block->getIfaceFromName("start");
+ if (startIface == NULL) continue;
+ double per = 1000.0/startIface->getClockFrequency();
+ QString startName = block->getName()+"_start";
+ out << " from_" << block->getName() << " : process" << endl;
+ out << " variable pclk : time := " << per << " ns;" << endl;
+ out << " begin" << endl;
+ out << " reset_" << block->getName() << " <= '0';" << endl;
+ out << " " << startName << " <= '0';" << endl;
+ out << " wait for 2*pclk;" << endl;
+ out << " reset_" << block->getName() << " <= '1';" << endl;
+ out << " wait for 1*pclk;" << endl;
+ out << " reset_" << block->getName() << " <= '0';" << endl;
+ out << " wait for 5*pclk;" << endl;
+ out << " " << startName << " <= '1';" << endl;
+ out << " wait for pclk;" << endl;
+ out << " " << startName << " <= '0';" << endl << endl;
+ out << " wait for 100000 us;" << endl;
+ out << " end process from_" << block->getName() << ";" << endl;
+ }
+
+ out << "end architecture " << projectName << "_tb_1;" << endl;
+ vhdlBench.close();
+
+}
+
+QList<QString> Graph::getExternalResources() {
+ QList<QString> list = topGroup->getExternalResources();
+ return list;
}