]> AND Private Git Repository - blast.git/blobdiff - Graph.cpp
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
finished testbench generation
[blast.git] / Graph.cpp
index a4dd676142370731391ddb74333e256195e6ea90..2b43baa1f8772c2b7e89f1b48ef9ad7ec05d6dc4 100644 (file)
--- a/Graph.cpp
+++ b/Graph.cpp
@@ -2,11 +2,12 @@
 #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");
-  groups.append(topGroup);
+  topGroup = NULL;
 }
 
 Graph::~Graph() {
@@ -14,17 +15,23 @@ 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);
@@ -38,10 +45,17 @@ GroupBlock* Graph::getGroupBlockByName(QString name) {
   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;
@@ -53,7 +67,7 @@ FunctionalBlock* Graph::duplicateFunctionalBlock(FunctionalBlock *block) {
   GroupBlock* group = AB_TO_GRP(block->getParent());
 
   // adding to the graph
-  FunctionalBlock* newBlock = createFunctionalBlock(group,ref);
+  FunctionalBlock* newBlock = createFunctionalBlock(group,ref, true);
   return newBlock;
 }
 
@@ -78,32 +92,441 @@ FunctionalBlock* Graph::getFunctionalBlockByName(QString name, GroupBlock* paren
   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) {
+  
+  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<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->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;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;
+}