X-Git-Url: https://bilbo.iut-bm.univ-fcomte.fr/and/gitweb/blast.git/blobdiff_plain/f311fbc3e1436bf248c54225f0743cfa671c4bd7..e0eaffd44fc9733bc230a803c80d8d5efd0faca6:/Graph.cpp diff --git a/Graph.cpp b/Graph.cpp index 8cd0f99..2b43baa 100644 --- a/Graph.cpp +++ b/Graph.cpp @@ -2,40 +2,531 @@ #include "GroupBlock.h" #include "ReferenceBlock.h" #include "FunctionalBlock.h" +#include "SpecialBlock.h" +#include "BlockParameter.h" +#include "ConnectedInterface.h" Graph::Graph() { - topGroup = new GroupBlock(NULL); - topGroup->setName("top group"); + 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 Graph::getOutsideInterfaces() { return topGroup->getInterfaces(); } -GroupBlock* Graph::createChildBlock(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; } -FunctionalBlock* Graph::addFunctionalBlock(GroupBlock* group, ReferenceBlock* ref) { +void Graph::removeGroupBlock(GroupBlock *group) { + group->removeAllBlocks(); + GroupBlock* parent = AB_TO_GRP(group->getParent()); + parent->removeBlock(group); + groups.removeAll(group); +} + +GroupBlock* Graph::getGroupBlockByName(QString name) { + foreach(GroupBlock* group, groups) { + if (group->getName() == name) return group; + } + return NULL; +} + +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; } -bool Graph::removeFunctionalBlock(FunctionalBlock* block, GroupBlock *group) { +FunctionalBlock* Graph::duplicateFunctionalBlock(FunctionalBlock *block) { + + ReferenceBlock* ref = block->getReference(); + GroupBlock* group = AB_TO_GRP(block->getParent()); + + // adding to the graph + FunctionalBlock* newBlock = createFunctionalBlock(group,ref, true); + return newBlock; +} + + +bool Graph::removeFunctionalBlock(FunctionalBlock* block) { + GroupBlock* group = AB_TO_GRP(block->getParent()); group->removeBlock(block); + return true; } -bool Graph::removeGroupBlock(GroupBlock *group) { - group->removeAllBlocks(); - GroupBlock* parent = AB_TO_GRP(group->getParent()); - parent->removeBlock(group); +FunctionalBlock* Graph::getFunctionalBlockByName(QString name, GroupBlock* parent) { + FunctionalBlock* block = NULL; + if (parent != NULL) { + block = AB_TO_FUN(parent->getFunctionalBlockByName(name)); + } + else { + foreach(GroupBlock* group, groups) { + block = AB_TO_FUN(group->getFunctionalBlockByName(name)); + if (block != NULL) return block; + } + } + return block; +} + +FunctionalBlock* Graph::createStimuliBlock(ReferenceBlock* ref, bool createIfaces) { + /* A stimuli block is always a special block with idSpecial = 1 */ + + FunctionalBlock* newBlock = new SpecialBlock(this, AbstractBlock::Source, NULL,ref, createIfaces); + stimulis.append(newBlock); + return newBlock; +} + +FunctionalBlock* Graph::duplicateStimuliBlock(FunctionalBlock *block) { + + ReferenceBlock* ref = block->getReference(); + + // adding to the graph + FunctionalBlock* newBlock = createStimuliBlock(ref, true); + return newBlock; +} + +FunctionalBlock* Graph::getStimuliBlockByName(QString name) { + foreach(FunctionalBlock* block, stimulis) { + if (block->getName() == name) return block; + } + return NULL; +} + +bool Graph::removeStimuliBlock(FunctionalBlock *block) { + stimulis.removeAll(block); + return true; +} + +void Graph::createPatterns() throw(Exception) { + + foreach(AbstractBlock* block, stimulis) { + FunctionalBlock* funBlock = AB_TO_FUN(block); + try { + funBlock->createPatterns(); + } + catch(Exception e) { + throw(e); + } + } + + foreach(AbstractBlock* block, groups) { + GroupBlock* group = AB_TO_GRP(block); + foreach(AbstractBlock* inBlock, group->getBlocks()) { + if (inBlock->isFunctionalBlock()) { + FunctionalBlock* funBlock = AB_TO_FUN(inBlock); + try { + funBlock->createPatterns(); + } + catch(Exception e) { + throw(e); + } + } + } + } +} + +void Graph::resetPatternComputed() { + foreach(AbstractBlock* block, stimulis) { + block->setOutputPatternComputed(false); + block->resetTraversalLevel(); + } + foreach(AbstractBlock* block, groups) { + GroupBlock* group = AB_TO_GRP(block); + group->setOutputPatternComputed(false); + block->resetTraversalLevel(); + foreach(AbstractBlock* inBlock, group->getBlocks()) { + inBlock->setOutputPatternComputed(false); + block->resetTraversalLevel(); + } + } +} + +void Graph::computeOutputPatterns(int nbExec) throw(Exception) { + + try { + createPatterns(); + } + catch(Exception e) { + throw(e); + } + + resetPatternComputed(); + // search for all block that are source. + QList 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->isSourceBlock()) { + sources.append(funBlock); + } + } + } + // search for maximum PP length + int maxPP = 0; + foreach(FunctionalBlock* block, sources) { + if (block->getProductionPatternLength() > maxPP) maxPP = block->getProductionPatternLength(); + } + // compute output for generators + int maxExecLen = maxPP*nbExec; + foreach(FunctionalBlock* block, sources) { + int d = block->getProductionPatternLength(); + block->computeOutputPattern((maxExecLen+d-1)/d); + } + // compute output for top group + try { + topGroup->computeOutputPattern(); + } + catch(Exception e) { + 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;igetName() << endl; + QList 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 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 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 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 " << 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 listGenerics = block->getGenericParameters(); + QList listInputs = block->getInputs(); + QList listOutputs = block->getOutputs(); + + if (!listGenerics.isEmpty()) { + out << " generic map (" << endl; + int i; + for(i=0;itoVHDL(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;igetPurpose() == 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;igetName() + " => " + 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 listGenerics = topGroup->getGenericParameters(); + QList listInputs = topGroup->getInputs(); + QList listOutputs = topGroup->getOutputs(); + QList listBidirs = topGroup->getBidirs(); + + if (!listGenerics.isEmpty()) { + out << " generic map (" << endl; + int i; + for(i=0;itoVHDL(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;igetPurpose() == 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;igetName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n"; + } + for(int i=0;igetName() + " => " + 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 Graph::getExternalResources() { + QList list = topGroup->getExternalResources(); + return list; }