From 5d4e709cb8d460b2efc083e6e7999f1c3a0eb602 Mon Sep 17 00:00:00 2001
From: stephane Domas <stephane.domas@univ-fcomte.fr>
Date: Fri, 12 May 2017 16:46:45 +0200
Subject: [PATCH 1/1] started adding delta comput

---
 AbstractBlock.cpp                        |  75 +++++++++++-------
 AbstractBlock.h                          |   8 +-
 AbstractInterface.h                      |   6 +-
 ArithmeticEvaluator.cpp                  |   8 +-
 BlockImplementation.cpp                  |  90 +++++++++++++++++-----
 BlockImplementation.h                    |  14 +++-
 BlockParameter.cpp                       |  31 ++++++++
 BlockParameter.h                         |   4 +
 BlockParameterUser.cpp                   |   4 +-
 BlockParameterUser.h                     |   2 +-
 BoxItem.cpp                              |   6 +-
 FunctionalBlock.cpp                      |  93 +++++++++++++++++++++--
 FunctionalBlock.h                        |  13 +++-
 Graph.cpp                                |  34 +++++++++
 Graph.h                                  |  10 ++-
 GroupBlock.cpp                           |  61 ++++++++++++++-
 GroupBlock.h                             |   2 +-
 Parameters.cpp                           |  22 ++++--
 ReferenceBlock.cpp                       |   7 +-
 ReferenceBlock.h                         |   2 +-
 blast.creator.user                       |   8 +-
 implementation.xsd                       |   2 +-
 lib/implementations/average-Nx3_impl.xml |   4 +-
 lib/implementations/impls.bmf            | Bin 784 -> 1214 bytes
 lib/references/references.bmf            | Bin 7216 -> 8102 bytes
 25 files changed, 417 insertions(+), 89 deletions(-)

diff --git a/AbstractBlock.cpp b/AbstractBlock.cpp
index c71b2e0..66c8f37 100644
--- a/AbstractBlock.cpp
+++ b/AbstractBlock.cpp
@@ -51,11 +51,12 @@ bool AbstractBlock::isTopGroupBlock() {
 bool AbstractBlock::isSourceBlock() {
   return false;
 }
-
+/* NB: a generator is a block that has no data inputs
+ * and has at least one data output.
+ */
 bool AbstractBlock::isGeneratorBlock() {
-  foreach(AbstractInterface* iface, inputs) {
-    if (iface->getPurpose() == AbstractInterface::Data) return false;
-  }
+  if (getDataInputs().size() > 0) return false;
+  
   return true;
 }
 
@@ -126,42 +127,58 @@ void AbstractBlock::defineBlockParam(BlockParameter *param)
   param->setValue(value);  
 }
 
-QList<AbstractInterface *> AbstractBlock::getInterfaces() {
+QList<AbstractInterface *> AbstractBlock::getInterfaces(int direction, int purpose) {
   QList<AbstractInterface *> list;
-  list.append(inputs);
-  list.append(outputs);
-  list.append(bidirs);
+  bool selIn = false;
+  bool selOut = false;
+  bool selInOut = false;
+  
+  if (direction == AbstractInterface::AnyDirection) {
+    selIn = true;
+    selOut = true;
+    selInOut = true;
+  }
+  else if (direction == AbstractInterface::Input) {
+    selIn = true;    
+  }
+  else if (direction == AbstractInterface::Output) {
+    selOut = true;    
+  }
+  else if (direction == AbstractInterface::InOut) {
+    selInOut = true;    
+  }
+  if (selIn) {
+    foreach(AbstractInterface* iface, inputs) {
+      if ((iface->getPurpose() == purpose) || (purpose == AbstractInterface::AnyPurpose)) list.append(iface);      
+    }
+  }
+  if (selOut) {
+    foreach(AbstractInterface* iface, outputs) {
+      if ((iface->getPurpose() == purpose) || (purpose == AbstractInterface::AnyPurpose)) list.append(iface);      
+    }
+  }
+  if (selInOut) {
+    foreach(AbstractInterface* iface, bidirs) {
+      if ((iface->getPurpose() == purpose) || (purpose == AbstractInterface::AnyPurpose)) list.append(iface);      
+    }
+  }
   return list;
 }
 
 QList<AbstractInterface *> AbstractBlock::getDataInputs() {
-  QList<AbstractInterface *> list;
-  foreach(AbstractInterface* iface, inputs) {
-    if (iface->getPurpose() == AbstractInterface::Data) {
-      list.append(iface);
-    }
-  }
-  return list;
+  return getInterfaces(AbstractInterface::Input, AbstractInterface::Data);  
+}
+
+QList<AbstractInterface *> AbstractBlock::getDataOutputs() {
+  return getInterfaces(AbstractInterface::Output, AbstractInterface::Data);  
 }
 
 QList<AbstractInterface *> AbstractBlock::getControlInputs() {
-  QList<AbstractInterface *> list;
-  foreach(AbstractInterface* iface, inputs) {
-    if (iface->getPurpose() == AbstractInterface::Control) {
-      list.append(iface);
-    }
-  }
-  return list;
+  return getInterfaces(AbstractInterface::Input, AbstractInterface::Control);  
 }
 
 QList<AbstractInterface *> AbstractBlock::getControlOutputs() {
-  QList<AbstractInterface *> list;
-  foreach(AbstractInterface* iface, outputs) {
-    if (iface->getPurpose() == AbstractInterface::Control) {
-      list.append(iface);
-    }
-  }
-  return list;
+  return getInterfaces(AbstractInterface::Output, AbstractInterface::Control);    
 }
 
 AbstractInterface* AbstractBlock::getIfaceFromName(QString name) {
diff --git a/AbstractBlock.h b/AbstractBlock.h
index c8aa023..88e4cb9 100644
--- a/AbstractBlock.h
+++ b/AbstractBlock.h
@@ -5,6 +5,7 @@
 
 #include <QtCore>
 
+#include "AbstractInterface.h"
 class AbstractInterface;
 class BlockParameter;
 
@@ -43,6 +44,7 @@ public:
   virtual void setParent(AbstractBlock* _parent);
   inline void setProductionCounter(QList<int> pattern) { productionCounter = pattern; }
   inline void setDelta(int _delta) { delta = _delta; }
+  inline void setPatternComputed(bool state) { patternComputed = state; }
 
   // testers
   virtual bool isReferenceBlock();
@@ -62,15 +64,16 @@ public:
   void removeAllInterfaces();
   void defineBlockParam(BlockParameter *param);
 
-  QList<AbstractInterface *> getInterfaces(); //! return all interfaces
+  QList<AbstractInterface *> getInterfaces(int direction = AbstractInterface::AnyDirection, int purpose = AbstractInterface::AnyPurpose);
   QList<AbstractInterface *> getDataInputs(); //! return all inputs of type data
+  QList<AbstractInterface *> getDataOutputs(); //! return all inputs of type data
   QList<AbstractInterface *> getControlInputs(); //! return all inputs of type control
   QList<AbstractInterface *> getControlOutputs(); //! return all outputs of type control
   AbstractInterface* getIfaceFromName(QString name);
   BlockParameter* getParameterFromName(QString name);
 
   // patterns
-  virtual void computeOutputPattern(int nbExec = -1) = 0;
+  virtual bool computeOutputPattern(int nbExec = -1) = 0;
   
 protected:
 
@@ -90,6 +93,7 @@ protected:
   // patterns
   QList<int> productionCounter; //! only usefull for output interfaces
   int delta;
+  bool patternComputed;
   
   // NB: only GroupBlock and FunctionalBlock have a real parent, except sources that have no parents
   AbstractBlock* parent;
diff --git a/AbstractInterface.h b/AbstractInterface.h
index e26f5c5..ac47ca9 100644
--- a/AbstractInterface.h
+++ b/AbstractInterface.h
@@ -24,9 +24,9 @@ class AbstractInterface {
 public :
 
   enum IfaceWidthType { Expression = 1, Boolean, Natural, Inherited}; //! Inherited is only for Group interface 
-  enum IfacePurpose { Data = 1, Control, Clock, Reset, Wishbone };
-  enum IfaceDirection { Input = 1, Output = 2, InOut = 3 };  
-  enum IfaceVHDLContext { Entity = 1, Component = 2, Architecture = 3 }; // NB : 3 is when creating an instance of the block that owns this iface
+  enum IfacePurpose { AnyPurpose = 0, Data = 1, Control, Clock, Reset, Wishbone };
+  enum IfaceDirection { AnyDirection = 0, Input = 1, Output = 2, InOut = 3 };  
+  enum IfaceVHDLContext {AnyContext = 0, Entity = 1, Component = 2, Architecture = 3 }; // NB : 3 is when creating an instance of the block that owns this iface
   enum IfaceVHDLFlags { NoComma = 1 };
 
   static int getIntDirection(QString str);  
diff --git a/ArithmeticEvaluator.cpp b/ArithmeticEvaluator.cpp
index 60db08e..dd8081e 100644
--- a/ArithmeticEvaluator.cpp
+++ b/ArithmeticEvaluator.cpp
@@ -165,15 +165,19 @@ double ArithmeticEvaluator::evaluate() throw(int) {
  */
 
 void ArithmeticEvaluator::convert(const QString& _expression) throw(int) {
-  QString expr = _expression;
+  
+  QString expr = _expression;  
+  cout << "converting " << qPrintable(expr) << endl;
   QString result="";
   expr.remove(QChar(' '), Qt::CaseInsensitive);
+  cout << "converting " << qPrintable(expr) << endl;
   foreach(QString func, fctMarkers) {
+    cout << "for " << qPrintable(func) << endl;
     QString rep = QString("\x1b%1").arg(fctMarkers.indexOf(QRegExp(func)));
 
     expr.replace(QRegExp(func),rep);
   }
-  //cout << "packed expr: " << qPrintable(expr) << endl;
+  cout << "packed expr: " << qPrintable(expr) << endl;
 
   int offset = 0;
   try {
diff --git a/BlockImplementation.cpp b/BlockImplementation.cpp
index af06ef3..e6b61ca 100644
--- a/BlockImplementation.cpp
+++ b/BlockImplementation.cpp
@@ -5,10 +5,13 @@
 #include "ReferenceInterface.h"
 #include "FunctionalInterface.h"
 #include "BlockParameter.h"
+#include <QHashIterator>
 
 
 BlockImplementation::BlockImplementation(const QString& _xmlFile) {
-  xmlFile = _xmlFile;  
+  xmlFile = _xmlFile;
+  productionCounter = "";
+  delta = "";
 
   evaluator = new ArithmeticEvaluator;
   evaluator->setVariableMarkers("@$");
@@ -16,32 +19,69 @@ BlockImplementation::BlockImplementation(const QString& _xmlFile) {
 
 BlockImplementation::BlockImplementation(const QString& _xmlFile, const QString &_referenceXml, const QString &_referenceMd5) {
   xmlFile = _xmlFile;  
+  productionCounter = "";
+  delta = "";
   referenceXml = _referenceXml;
   referenceMd5 = _referenceMd5;
 }
 
-void BlockImplementation::assignPatterns(FunctionalBlock *_block) throw(Exception) {
+void BlockImplementation::loadPatterns(QDomElement& root) throw(Exception) {
+    
+  QDomNodeList patternNode = root.elementsByTagName("patterns");
   
-  block = _block;
-
-  QFile implFile(xmlFile);
-
-  // reading in into QDomDocument
-  QDomDocument document("implFile");
-
-  if (!implFile.open(QIODevice::ReadOnly)) {
-    throw(Exception(IMPLFILE_NOACCESS));
-  }
-  if (!document.setContent(&implFile)) {
-    implFile.close();
-    throw(Exception(IMPLFILE_NOACCESS));
+  if (patternNode.isEmpty()) {
+    cout << "impl has no patterns" << endl;
+    return;
   }
-  implFile.close();
-  QDomElement impl = document.documentElement();
-  QDomNodeList patternNode = impl.elementsByTagName("patterns");
-  if (patternNode.isEmpty()) return;
+  
   QDomElement patternElt = patternNode.at(0).toElement();
   
+  QDomElement eltDelta  = patternElt.firstChildElement("delta");
+  delta = eltDelta.attribute("value","none");
+  
+  QDomElement eltCons  = eltDelta.nextSiblingElement("consumption");
+  
+  QDomNodeList listNodeInput = eltCons.elementsByTagName("input");
+  for(int i=0; i<listNodeInput.size(); i++) {
+    QDomNode node = listNodeInput.at(i);    
+    QDomElement elt = node.toElement();    
+    QString nameStr = elt.attribute("name","none");
+    if (nameStr == "none") throw(Exception(IMPLFILE_CORRUPTED));
+    QString patternStr = elt.attribute("pattern","none");    
+    consumptionPattern.insert(nameStr,patternStr);
+  }
+  
+  QDomElement eltProd  = eltCons.nextSiblingElement("production");
+  productionCounter = eltProd.attribute("counter","none");
+  QDomNodeList listNodeOutput = eltCons.elementsByTagName("output");
+  for(int i=0; i<listNodeOutput.size(); i++) {
+    QDomNode node = listNodeOutput.at(i);    
+    QDomElement elt = node.toElement();        
+    QString nameStr = elt.attribute("name","none");
+    if (nameStr == "none") throw(Exception(IMPLFILE_CORRUPTED));
+    QString patternStr = elt.attribute("pattern","none");    
+    productionPattern.insert(nameStr,patternStr);    
+  }
+  cout << "impls patterns read correctly" << endl;
+}
+
+bool BlockImplementation::checkPatterns() {
+  if (reference == NULL) return false;
+  
+  AbstractInterface* iface;  
+  QHashIterator<QString,QString> iterI(consumptionPattern);
+  while (iterI.hasNext()) {
+    iterI.next();
+    iface = reference->getIfaceFromName(iterI.key());
+    if (iface == NULL) return false;
+  }
+  QHashIterator<QString,QString> iterO(productionPattern);
+  while (iterO.hasNext()) {
+    iterO.next();
+    iface = reference->getIfaceFromName(iterO.key());
+    if (iface == NULL) return false;
+  }  
+  return true;  
 }
 
 void BlockImplementation::generateVHDL(FunctionalBlock* _block, const QString &path) throw(Exception) {
@@ -527,7 +567,12 @@ QDataStream& operator<<(QDataStream &out, const BlockImplementation &impl) {
   toWrite << impl.xmlFile;
   toWrite << impl.referenceXml;
   toWrite << impl.referenceMd5;
-
+  // saving patterns
+  toWrite << impl.delta;
+  toWrite << impl.consumptionPattern;
+  toWrite << impl.productionPattern;
+  toWrite << impl.productionCounter;
+  
   out << blockData;
 
   return out;
@@ -544,6 +589,11 @@ QDataStream& operator>>(QDataStream &in, BlockImplementation &impl) {
   in >> impl.xmlFile;
   in >> impl.referenceXml;
   in >> impl.referenceMd5;
+  // loading patterns
+  in >> impl.delta;
+  in >> impl.consumptionPattern;
+  in >> impl.productionPattern;
+  in >> impl.productionCounter;
 
   return in;
 }
diff --git a/BlockImplementation.h b/BlockImplementation.h
index 852cc63..4866e85 100644
--- a/BlockImplementation.h
+++ b/BlockImplementation.h
@@ -28,9 +28,16 @@ public:
   BlockImplementation(const QString& _xmlFile);
   BlockImplementation(const QString& _xmlFile, const QString& _referenceXml, const QString& _referenceMd5);
 
+  // getters  
   inline QString getXmlFile() { return xmlFile; }
   inline QString getReferenceXml() { return referenceXml; }
   inline QString getReferenceMd5() { return referenceMd5; }
+  inline QString getDelta() { return delta; }
+  inline QHash<QString,QString> getConsumptionPattern() { return consumptionPattern; }
+  inline QHash<QString,QString> getProductionPattern() { return productionPattern; }
+  inline QString getProductionCounter() { return productionCounter; }
+  // setters
+  
   QString eval(QString line, QTextStream& out);
   QString evalComplex(QString line, int num);
   QString evalString(QString s);
@@ -40,7 +47,8 @@ public:
 
   inline void setReference(ReferenceBlock* _reference) { reference = _reference; }
 
-  void assignPatterns(FunctionalBlock* _block) throw(Exception); // called during output pattern computation
+  void loadPatterns(QDomElement &root) throw(Exception);
+  bool checkPatterns();
   void generateVHDL(FunctionalBlock* _block, const QString& path) throw(Exception); // main entry to generate the VHDL code
   
 
@@ -53,6 +61,10 @@ private:
   ArithmeticEvaluator* evaluator;
   ReferenceBlock* reference;
   FunctionalBlock* block; // the current functional block for which this implementation is used.
+  QString delta;
+  QHash<QString,QString> consumptionPattern; // key = reference interface name, value = pattern expression
+  QHash<QString,QString> productionPattern; // key = reference interface name, value = pattern expression
+  QString productionCounter;
 
   void generateComments(QDomElement &elt,QString coreFile, QTextStream& out) throw(Exception); // generates comments from <comments> element
   void generateLibraries(QDomElement &elt, QTextStream& out) throw(Exception); // generates libraries from <libraries> element
diff --git a/BlockParameter.cpp b/BlockParameter.cpp
index f8dfcd7..6207148 100644
--- a/BlockParameter.cpp
+++ b/BlockParameter.cpp
@@ -22,6 +22,37 @@ QVariant BlockParameter::getValue() {
   return defaultValue;
 }
 
+bool BlockParameter::getBooleanValue(bool* ok) {
+  if (type == Boolean) {
+    *ok = true;
+    return getValue().toBool();
+  }
+  *ok = false;
+  return false;
+}
+
+int BlockParameter::getIntValue(bool* ok) {
+  if ((type == Natural) || (type == Positive) || (type == Integer)) {
+    *ok = true;
+    return getValue().toInt();
+  }
+  *ok = false;
+  return 0;
+}
+
+double BlockParameter::getDoubleValue(bool* ok) {
+  if ((type == Real) || (type == Natural) || (type == Positive) || (type == Integer)) {
+    *ok = true;
+    return getValue().toDouble();
+  }
+  *ok = false;
+  return 0.0;
+}
+
+QString BlockParameter::getStringValue() {
+  return getValue().toString();
+}
+
 bool BlockParameter::isUserParameter() {
   return false;
 
diff --git a/BlockParameter.h b/BlockParameter.h
index adc8c5d..e8068d4 100644
--- a/BlockParameter.h
+++ b/BlockParameter.h
@@ -44,6 +44,10 @@ public :
   inline int getType() { return type; }
   QString getTypeString();
   virtual QVariant getValue(); // may be overriden
+  int getIntValue(bool* ok);
+  double getDoubleValue(bool* ok);
+  bool getBooleanValue(bool* ok);  
+  QString getStringValue();
   virtual QString getContext() = 0;
 
   // setters
diff --git a/BlockParameterUser.cpp b/BlockParameterUser.cpp
index d0d870f..b6665fa 100644
--- a/BlockParameterUser.cpp
+++ b/BlockParameterUser.cpp
@@ -4,7 +4,7 @@ BlockParameterUser::BlockParameterUser() : BlockParameter() {
   userValue = defaultValue;
 }
 
-BlockParameterUser::BlockParameterUser(AbstractBlock* _owner, const QString &_name, const QString &_value) : BlockParameter(_owner, _name, "string", _value) {
+BlockParameterUser::BlockParameterUser(AbstractBlock* _owner, const QString &_name, const QString &_type, const QString &_value) : BlockParameter(_owner, _name, _type, _value) {
   userValue = defaultValue;
 }
 
@@ -30,7 +30,7 @@ bool BlockParameterUser::isDefaultValue() {
 }
 
 BlockParameter* BlockParameterUser::clone() {
-  BlockParameter* block = new BlockParameterUser(owner,name,defaultValue.toString());
+  BlockParameter* block = new BlockParameterUser(owner,name,getTypeString(), defaultValue.toString());
   return block;
 }
 
diff --git a/BlockParameterUser.h b/BlockParameterUser.h
index 3da12a3..5958981 100644
--- a/BlockParameterUser.h
+++ b/BlockParameterUser.h
@@ -29,7 +29,7 @@ class BlockParameterUser : public BlockParameter {
 public :
 
   BlockParameterUser();
-  BlockParameterUser(AbstractBlock* _owner, const QString& _name, const QString& _value);
+  BlockParameterUser(AbstractBlock* _owner, const QString& _name, const QString& _type, const QString& _value);
 
   // getters
   QVariant getValue();
diff --git a/BoxItem.cpp b/BoxItem.cpp
index 92f89b8..568e946 100644
--- a/BoxItem.cpp
+++ b/BoxItem.cpp
@@ -624,7 +624,11 @@ void BoxItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * event) {
   else if(selectedAction == showWishboneIface) {
     dispatcher->showWishboneIface(this);
   }
-  else if(selectedAction == showParameters){
+  else if(selectedAction == showParameters) {
+    if (refBlock->isFunctionalBlock()) {
+      FunctionalBlock* fun = AB_TO_FUN(refBlock);
+      fun->createDelta();
+    }
     new ParametersWindow(refBlock, params, NULL);
   }    
 }
diff --git a/FunctionalBlock.cpp b/FunctionalBlock.cpp
index 93e8377..5731794 100644
--- a/FunctionalBlock.cpp
+++ b/FunctionalBlock.cpp
@@ -18,7 +18,14 @@ FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference
   nbConsumingPorts = 0;
   productionPattern = NULL;
   lengthPP = 0;
-  nbProducingPorts = 0;  
+  nbProducingPorts = 0;
+  if (reference->getImplementations().isEmpty()) {
+    implementation = NULL;
+    cout << "block has no implementation" << endl;
+  }
+  else {
+    implementation = reference->getImplementations().at(0);
+  }
 }
 
 
@@ -106,7 +113,69 @@ QString FunctionalBlock::getReferenceHashMd5() {
     return ((ReferenceBlock *)reference)->getHashMd5();
 }
 
-void FunctionalBlock::computeOutputPattern(int nbExec) {
+bool FunctionalBlock::createPatterns() {
+  evaluator = new ArithmeticEvaluator();
+  bool ok = true;
+  ok = ok & createDelta();
+  if (ok) ok = ok & createConsumptionPattern();
+  if (ok) ok = ok & createProductionCounter();
+  if (ok) ok = ok & createProductionPattern();
+  delete evaluator;
+  return ok;
+}
+
+bool FunctionalBlock::createDelta() {
+  QString delta = implementation->getDelta();
+  cout << "delta for " << qPrintable(name) << " = " << qPrintable(delta) << endl;
+  
+  // look for parameter names
+  QHash<QString,double> vars;
+  QRegularExpression re("[$][a-zA-Z0-9_]+");
+  QRegularExpressionMatchIterator matcher = re.globalMatch(delta);
+  while(matcher.hasNext()) {
+    QRegularExpressionMatch m = matcher.next();
+    QString var = m.captured(0);
+    cout << qPrintable(var) << endl;
+    vars.insert(var,0.0);    
+  }
+  QHashIterator<QString,double> iterV(vars);
+  while (iterV.hasNext()) {
+    iterV.next();
+    QString var = iterV.key();
+    QString paramName = var.remove(0,1);
+    BlockParameter* param = reference->getParameterFromName(paramName);
+    cout << "param = " << qPrintable(param->getStringValue()) << endl;
+    if (param == NULL) {
+      cerr << "found an unknown parameter in delta"<< endl;
+      return false;
+    }
+    bool ok;
+    int val = param->getIntValue(&ok);
+    vars.insert(var,(double)val);
+  }
+  cout << "set expr " << endl;
+  evaluator->setExpression(delta);
+  cout << "set vars " << endl;
+  evaluator->setVariablesValue(vars);
+  double result = evaluator->evaluate();
+  cout << "delta = " << result << endl;
+   
+  return true;
+}
+
+bool FunctionalBlock::createConsumptionPattern() {
+  return true;
+}
+
+bool FunctionalBlock::createProductionPattern() {
+  return true;
+}
+
+bool FunctionalBlock::createProductionCounter() {
+  return true;
+}
+
+bool FunctionalBlock::computeOutputPattern(int nbExec) {
   
   /* case 1: the block is a generator for which output pattern
      must be computed for a nbExec following executions
@@ -137,11 +206,24 @@ void FunctionalBlock::computeOutputPattern(int nbExec) {
       else {
         if (in.size() < minLen) minLen = in.size();
       }
-      inputPattern[idIface] = new char[in.size()];
-      int i = 0;
-      foreach(char c, in) inputPattern[idIface][i++] = c;
+      if (in.size() > 0) {
+        inputPattern[idIface] = new char[in.size()];
+        int i = 0;
+        foreach(char c, in) inputPattern[idIface][i++] = c;
+      }
+      else {
+        inputPattern[idIface] = NULL;
+      }
       idIface += 1;      
     }
+    // if some patterns are not available, ens now, returning false
+    if (minLen == 0) {
+      for(int i=0;i<nbConsumingPorts; i++) {
+        if (inputPattern[i] != NULL) delete [] inputPattern[i];
+      }
+      delete [] inputPattern;
+      return false;
+    }
     // initialize the output pattern    
     char** outputPattern = NULL;
     outputPattern = new char*[nbProducingPorts];
@@ -237,6 +319,7 @@ void FunctionalBlock::computeOutputPattern(int nbExec) {
     }
     delete [] outputPattern;
   }
+  return true;
 }
 
 bool FunctionalBlock::isValidDataGroup(char** pattern, int nbPorts, int clock) {
diff --git a/FunctionalBlock.h b/FunctionalBlock.h
index 9852eb7..f898990 100644
--- a/FunctionalBlock.h
+++ b/FunctionalBlock.h
@@ -11,6 +11,9 @@ class ReferenceBlock;
 class GroupBlock;
 #include "Exception.h"
 class Exception;
+class BlockImplementation;
+class ArithmeticEvaluator;
+    
 
 
 using namespace std;
@@ -29,6 +32,7 @@ public:
   inline ReferenceBlock* getReference() { return reference; }
 
   // setters
+  inline void setImplementation(BlockImplementation* impl) { implementation = impl; }
 
   // testers
   bool isFunctionalBlock();
@@ -43,6 +47,11 @@ public:
   QString getReferenceHashMd5();
   
   // patterns
+  bool createPatterns();
+  bool createDelta();
+  bool createConsumptionPattern(); // initialize a QList<char> for each interface from patterns defined in implementation
+  bool createProductionPattern(); // initialize a QList<char> for each interface from patterns defined in implementation
+  bool createProductionCounter(); // initialize a QList<int> from counter defined in implementation
   void initConsumptionPattern(); // initialize a char** from patterns defined for each interface
   void initProductionPattern(); // initialize a char** from patterns defined for each interface
   void clearConsumptionPattern();
@@ -50,7 +59,7 @@ public:
   
 private:  
   // patterns
-  void computeOutputPattern(int nbExec = -1);
+  bool computeOutputPattern(int nbExec = -1);
   bool isValidDataGroup(char** pattern, int nbPorts, int clock);
   /*!
    * \brief combinePatterns
@@ -71,8 +80,10 @@ private:
   char** productionPattern;
   int nbProducingPorts;
   int lengthPP;
+  ArithmeticEvaluator* evaluator;
   
   ReferenceBlock* reference;
+  BlockImplementation* implementation;
 
 };
 
diff --git a/Graph.cpp b/Graph.cpp
index a4dd676..d3fd276 100644
--- a/Graph.cpp
+++ b/Graph.cpp
@@ -107,3 +107,37 @@ bool Graph::removeSourceBlock(FunctionalBlock *block) {
   sources.removeAll(block);
   return true;
 }
+
+bool Graph::createPatterns() {
+  bool ok = true;
+  foreach(AbstractBlock* block, sources) {
+    FunctionalBlock* funBlock = AB_TO_FUN(block);
+    ok = funBlock->createPatterns();
+    if (!ok) return false;
+  }
+  
+  foreach(AbstractBlock* block, groups) {
+    GroupBlock* group = AB_TO_GRP(block);    
+    foreach(AbstractBlock* inBlock, group->getBlocks()) {
+      if (inBlock->isFunctionalBlock()) {
+        FunctionalBlock* funBlock = AB_TO_FUN(inBlock);
+        ok = funBlock->createPatterns();
+        if (!ok) return false;
+      }
+    }
+  }
+  return true;
+}
+
+void Graph::resetPatternComputed() {
+  foreach(AbstractBlock* block, sources) {
+    block->setPatternComputed(false);
+  }
+  foreach(AbstractBlock* block, groups) {
+    GroupBlock* group = AB_TO_GRP(block);
+    group->setPatternComputed(false);
+    foreach(AbstractBlock* inBlock, group->getBlocks()) {
+      inBlock->setPatternComputed(false);
+    }
+  }
+}
diff --git a/Graph.h b/Graph.h
index 7be35c2..b2b8078 100644
--- a/Graph.h
+++ b/Graph.h
@@ -43,7 +43,15 @@ public:
   bool removeSourceBlock(FunctionalBlock* block);
   
   // others
-  QList<AbstractInterface *> getOutsideInterfaces();  
+  QList<AbstractInterface *> getOutsideInterfaces();
+  /*!
+   * \brief initPatterns
+   * initPatterns() crosses the graph and for each functional block, it computes
+   * the consumptionPattern, the productionPattern, the production counter and delta
+   * using the parameters fo the block.
+   */
+  bool createPatterns();
+  void resetPatternComputed();
   
   
 private:  
diff --git a/GroupBlock.cpp b/GroupBlock.cpp
index 716cea6..a8a06e6 100644
--- a/GroupBlock.cpp
+++ b/GroupBlock.cpp
@@ -1,6 +1,7 @@
 #include "GroupBlock.h"
 #include "BlockParameterGeneric.h"
 #include "AbstractInterface.h"
+#include "ConnectedInterface.h"
 #include "string.h"
 #include <sstream>
 
@@ -110,13 +111,65 @@ void GroupBlock::initInputPattern() {
   }  
 }
 
-void GroupBlock::computeOutputPattern(int nbExec) {
+bool GroupBlock::computeOutputPattern(int nbExec) {
   
+  bool canCompute = true;
   // get the input pattern on each inputs
   initInputPattern();
-  // find blocks that are connected to that inputs
   
-  foreach(AbstractInterface* iface, getControlOutputs()) {
-    iface->setOutputPattern(iface->getConnectedFrom()->getOutputPattern());    
+  // find blocks that are connected to that inputs and generators
+  QList<AbstractBlock*> fifo;
+  foreach(AbstractBlock* block, blocks) {
+    
+    bool addIt = false;
+    // if a block is a generator and has control outputs, add it
+    if (block->isGeneratorBlock()) {
+      if (block->getControlOutputs().size() > 0) addIt = true;
+    }
+    else {
+      // if the block has a control input connected from an intput of the group, add it too
+      foreach(AbstractInterface* iface, block->getControlInputs()) {
+        ConnectedInterface* conn = (ConnectedInterface*)iface;
+        ConnectedInterface* groupIface = conn->getConnectionFromParentGroup();
+        if (groupIface != NULL) {
+          addIt = true;
+          break;
+        }
+      }
+    }
+    if (addIt) fifo.append(block);    
+  }
+  while (!fifo.isEmpty()) {
+    AbstractBlock* block = fifo.takeFirst();
+    cout << "computing pattern for " << qPrintable(block->getName()) << endl;
+    canCompute = block->computeOutputPattern();
+    if (!canCompute) {
+      cout << "cannot finalize output pattern computation of " << qPrintable(block->getName()) << endl;
+      break;
+    }
+    block->setPatternComputed(true);
+    // add other blocks connected from block to the fifo
+    foreach(AbstractInterface* iface, block->getControlOutputs()) {
+      ConnectedInterface* conn = (ConnectedInterface*)iface;
+      foreach(ConnectedInterface* connTo, conn->getConnectedTo()) {
+        /* if connTo is owned by a functional block
+           or by a group block that is within this, add the block to the fifo.
+         */
+        if (connTo->getOwner()->isFunctionalBlock()) {
+          fifo.append(connTo->getOwner());
+        }
+        else if (connTo->getOwner() != this) {
+          fifo.append(connTo->getOwner());
+        }      
+      }
+    }
+  }
+  
+  if (canCompute) {
+    foreach(AbstractInterface* iface, getControlOutputs()) {
+      iface->setOutputPattern(iface->getConnectedFrom()->getOutputPattern());    
+    }
+    setPatternComputed(true);
   }
+  return canCompute;
 }
diff --git a/GroupBlock.h b/GroupBlock.h
index 0aeb006..547159e 100644
--- a/GroupBlock.h
+++ b/GroupBlock.h
@@ -52,7 +52,7 @@ private:
    * found by taking the output pattern of the connectedFrom interface.
    */   
   void initInputPattern();
-  void computeOutputPattern(int nbExec = -1);
+  bool computeOutputPattern(int nbExec = -1);
   
   bool topGroup;  
   QList<AbstractBlock*> blocks; // contains instances of FunctionalBlock or GroupBlock that are children of this group
diff --git a/Parameters.cpp b/Parameters.cpp
index c12fead..3cc8c14 100644
--- a/Parameters.cpp
+++ b/Parameters.cpp
@@ -683,6 +683,12 @@ void Parameters::loadImplementationsFromXml() throw(Exception) {
       QString refXml = implRoot.attribute("ref_name","none");
       QString refMd5 = implRoot.attribute("ref_md5","none");
       BlockImplementation* impl = new BlockImplementation(fileName,refXml,refMd5);
+      try {
+        impl->loadPatterns(implRoot);
+      }
+      catch(int err) {
+        throw(err);
+      }
       availableImplementations.append(impl);
 
       ReferenceBlock* ref = NULL;
@@ -694,9 +700,12 @@ void Parameters::loadImplementationsFromXml() throw(Exception) {
       }
       if (ref == NULL) {
         cout << "Cannot find a reference block for impl :" << qPrintable(fileName) << endl;
-      }
-      ref->addImplementation(impl);
-      impl->setReference(ref);
+      }      
+      else {          
+        ref->addImplementation(impl);
+        impl->setReference(ref);
+        if (! impl->checkPatterns()) throw(Exception(IMPLFILE_CORRUPTED));
+      }      
       cout << "OK" << endl;
     }
   }
@@ -741,8 +750,11 @@ void Parameters::loadImplementationsFromLib() throw(Exception) {
     if (ref == NULL) {
       cout << "Cannot find a reference block for impl :" << qPrintable(impl->getXmlFile()) << endl;
     }
-    ref->addImplementation(impl);
-    impl->setReference(ref);
+    else {          
+      ref->addImplementation(impl);
+      impl->setReference(ref);
+      if (! impl->checkPatterns()) throw(Exception(IMPLFILE_CORRUPTED));
+    }
   }
   libFile.close();
 }
diff --git a/ReferenceBlock.cpp b/ReferenceBlock.cpp
index ae7f0ce..12db4b4 100644
--- a/ReferenceBlock.cpp
+++ b/ReferenceBlock.cpp
@@ -157,7 +157,7 @@ void ReferenceBlock::loadParameters(QDomElement &elt) throw(Exception) {
         valueStr = "";
     }
     if (contextStr == "user") {
-      param = new BlockParameterUser(this,nameStr,valueStr);
+      param = new BlockParameterUser(this,nameStr,typeStr,valueStr);
     }
     else if (contextStr == "generic") {
       param = new BlockParameterGeneric(this,nameStr,typeStr,valueStr);
@@ -471,7 +471,7 @@ QDataStream& operator>>(QDataStream &in, ReferenceBlock &b) {
     in >> valueStr;
 
     if (contextStr == "user") {
-      p = new BlockParameterUser(&b,nameStr,valueStr);
+      p = new BlockParameterUser(&b,nameStr,typeStr,valueStr);
     }
     else if (contextStr == "generic") {
       p = new BlockParameterGeneric(&b,nameStr,typeStr,valueStr);
@@ -567,6 +567,7 @@ QDataStream& operator>>(QDataStream &in, ReferenceBlock &b) {
   return in;
 }
 
-void ReferenceBlock::computeOutputPattern(int nbExec) {
+bool ReferenceBlock::computeOutputPattern(int nbExec) {
   // does strictly nothing
+  return false;
 }
diff --git a/ReferenceBlock.h b/ReferenceBlock.h
index 2e34984..b10c142 100644
--- a/ReferenceBlock.h
+++ b/ReferenceBlock.h
@@ -68,7 +68,7 @@ public:
   
 private:
   // patterns
-  void computeOutputPattern(int nbExec = -1);
+  bool computeOutputPattern(int nbExec = -1);
 };
 
 #endif // __REFERENCEBLOCK_H__
diff --git a/blast.creator.user b/blast.creator.user
index b9d826a..a4cb21c 100755
--- a/blast.creator.user
+++ b/blast.creator.user
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE QtCreatorProject>
-<!-- Written by QtCreator 3.2.1, 2017-05-11T21:36:51. -->
+<!-- Written by QtCreator 3.2.1, 2017-05-12T16:46:10. -->
 <qtcreator>
  <data>
   <variable>EnvironmentId</variable>
-  <value type="QByteArray">{c8006d66-d34f-42be-ad10-d0207752286d}</value>
+  <value type="QByteArray">{1d077e47-e3a1-47fd-8b12-4de650e39df5}</value>
  </data>
  <data>
   <variable>ProjectExplorer.Project.ActiveTarget</variable>
@@ -60,12 +60,12 @@
   <valuemap type="QVariantMap">
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
-   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{2c9bf876-3476-44eb-8065-1f0844704dda}</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{451ee8a3-56ff-4aba-8a8e-3da882cc142e}</value>
    <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
    <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
    <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
    <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
-    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/sdomas/Projet/Blast/code/blast</value>
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/localhome/sdomas/Projet/Blast/code/blast</value>
     <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
      <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
       <valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
diff --git a/implementation.xsd b/implementation.xsd
index 0dff1f6..c838514 100644
--- a/implementation.xsd
+++ b/implementation.xsd
@@ -135,6 +135,7 @@
 	    <xs:sequence>
 		<xs:element ref="output" minOccurs="0" maxOccurs="unbounded"/>
 	    </xs:sequence>
+	    <xs:attribute ref="counter" />	  	  
 	</xs:complexType>
     </xs:element>
 
@@ -142,7 +143,6 @@
 	<xs:complexType>
 	  <xs:attribute ref="name" />
 	  <xs:attribute ref="pattern" />
-	  <xs:attribute ref="counter" />	  	  
 	</xs:complexType>
     </xs:element>
     
diff --git a/lib/implementations/average-Nx3_impl.xml b/lib/implementations/average-Nx3_impl.xml
index 1ea7a7f..de874d1 100644
--- a/lib/implementations/average-Nx3_impl.xml
+++ b/lib/implementations/average-Nx3_impl.xml
@@ -28,8 +28,8 @@
     <consumption>
       <input name="data_i" pattern="(1){$nb_data}" />
     </consumption>
-    <production>
-      <output name="data_o" pattern="00{$nb_data}" counter="{2:$nb_data+2:1}"/>
+    <production counter="{2:$nb_data+2:1}">
+      <output name="data_o" pattern="00{$nb_data}" />
     </production>
   </patterns>
 </block_impl>
diff --git a/lib/implementations/impls.bmf b/lib/implementations/impls.bmf
index 7fd7598fad1ca6067e30c3313a113855cddb779d..15dfac4ea57ccf0c25326ec2f4d067d82a1d427a 100644
GIT binary patch
literal 1214
zcmc(eJx;?w5QU#5=u#jG3JQb}LZHZmm;#BC10ZgI?AU;jW56*#65<LJloS*k15t7m
z4w7#-DDjdNC0=Qi*?Dg!J8#C)!iS_q>>GPmPZzq<P#NAxsr6&Lo=#M8y9BAZ9jTCs
z8-GANwHZkxS}0cnnp5qXcxJ1XWW-obPHF4Lpl6D7piuW@gzzSnGyd^(n!l?Dkb+lk
zf&Y~=V?zFYf{4f~@B05f@6e#)?dSZ4I;Nj}Z+~lWd|bD$C2gW$LWLB*QB?}C&h&1y
zlUB8@zIOCD$A1DfXB{lk;T+zz(Y_4t6MJq!HM3Vk-J+Fm6PE4XO>kEo(^umJ9WHMz
zyx+{a{F!^r&R0x+V80t*KO1&8{Cu~+J*G9H?hU$_Z>uD;W~aNvb5t=g7ip-0`-Q!<
Ypof`NVYfBql|Btt?7U|jw{NG5G3QFlj{pDw

delta 59
zcmdnTIf0Fbfq@x_8CZb$%0!;)tVe*1SrY|HC+9Nyv91Af`X&k#PhQAm!MX*=nFQh#
Hve*IukQNT|

diff --git a/lib/references/references.bmf b/lib/references/references.bmf
index 7eefb86f5b9c126156af3b149b5029ce13bb34fd..60ea24991a6600f046e574563d7088b2a29e4a9e 100644
GIT binary patch
delta 601
zcmb`EF-yZx6opS)m57TJn}P^-5S)~1tVSI4R|vXjO_LglX>Fpmi`^Vt^9RJiS#j}a
z`4jwJpbnufBH`Y5-hJntdvf2K`+8_et1pt~->tsARv7@7)s?T97^tmOJ=P6*O2E=n
z_Eio2-x-@4>RJ)Z$AXTJLPN)dhi1&q2i>9?>JDs9CnqVL<Lta%8wYSBzMk&kbl_ZQ
zL_Q@#_7PQcZ$ucJ{6}XzHSp9{lwH*q{^X&Ak2&H<`)bO;nWsJNqUn$w1t1^P(iVA#
zbz3ed$ZH+AZq8{*WmU3=()xH&ea4XR+mn%*GnXb7V>IJ5&$pDL8=d9jh<Summ(-`-
io}qcOaNqtJYe8XUsze#**vOu12iZxr`!TdXXTJe!r))$3

delta 22
dcmZ2xzrliofk8%xfq{WzBS(SQ=68}iSOGm<1>67t

-- 
2.39.5