From 2019e5afdaf7fd0ad21607848710348bbc3be256 Mon Sep 17 00:00:00 2001
From: stephane Domas <stephane.domas@univ-fcomte.fr>
Date: Fri, 19 May 2017 16:41:28 +0200
Subject: [PATCH 1/1] added admittance computation

---
 FunctionalBlock.cpp                        | 261 ++++++++++++++++-----
 FunctionalBlock.h                          |  20 +-
 Graph.cpp                                  |  10 +-
 blast.creator.user                         |   2 +-
 lib/implementations/generator-cst_impl.xml |   4 +-
 5 files changed, 231 insertions(+), 66 deletions(-)

diff --git a/FunctionalBlock.cpp b/FunctionalBlock.cpp
index 23d43b9..ac27de4 100644
--- a/FunctionalBlock.cpp
+++ b/FunctionalBlock.cpp
@@ -117,10 +117,10 @@ bool FunctionalBlock::createPatterns() {
   
   cout << "create patterns for block " << qPrintable(name) << endl;
   evaluator = new ArithmeticEvaluator();
-  bool ok = true;
-  ok = ok & createDelta();
+  bool ok = true;  
   if (! isGeneratorBlock()) {
-    if (ok) ok = ok & createConsumptionPattern();
+    ok = ok & createDelta();
+    if (ok) ok = ok & createConsumptionPattern();    
     if (ok) ok = ok & createProductionCounter();
   }
   if (ok) ok = ok & createProductionPattern();
@@ -134,8 +134,12 @@ bool FunctionalBlock::createDelta() {
   cout << "call to " << qPrintable(fctName) << endl;
 #endif 
   
-  QString deltaStr = implementation->getDelta();
+  QString deltaStr = implementation->getDelta();  
   cout << "delta for " << qPrintable(name) << " = " << qPrintable(deltaStr) << endl;
+  if (deltaStr.isEmpty()) {
+    delta = -1;
+    return true;
+  }
   
   // look for parameter names
   bool ok = true;
@@ -154,6 +158,7 @@ bool FunctionalBlock::createConsumptionPattern() {
   cout << "call to " << qPrintable(fctName) << endl;
 #endif
   
+  lengthCP = -1;
   bool ok = true; 
   QHash<QString,QString> consPattern = implementation->getConsumptionPattern();  
   
@@ -164,10 +169,15 @@ bool FunctionalBlock::createConsumptionPattern() {
       cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl;
       return false;
     }
-    QList<char>* pattern = expandPattern(consPattern.value(refName),&ok);    
-    
+    QList<char>* pattern = expandPattern(consPattern.value(refName),&ok);        
     if (!ok) return false;
-    consumptionPattern.insert(connIface,pattern);        
+    consumptionPattern.insert(connIface,pattern);
+    if (lengthCP == -1) {
+      lengthCP = pattern->size();
+    }
+    else {
+      if (pattern->size() != lengthCP) return false;
+    }
   }        
   return true;
 }
@@ -178,6 +188,7 @@ bool FunctionalBlock::createProductionPattern() {
   cout << "call to " << qPrintable(fctName) << endl;
 #endif
   
+  lengthPP = -1;
   bool ok = true; 
   QHash<QString,QString> prodPattern = implementation->getProductionPattern();  
   
@@ -190,7 +201,13 @@ bool FunctionalBlock::createProductionPattern() {
     }
     QList<char>* pattern = expandPattern(prodPattern.value(refName),&ok);
     if (!ok) return false;
-    productionPattern.insert(connIface,pattern);    
+    productionPattern.insert(connIface,pattern);
+    if (lengthPP == -1) {
+      lengthPP = pattern->size();
+    }
+    else {
+      if (pattern->size() != lengthPP) return false;
+    }
   }    
   return true;
 }
@@ -379,6 +396,121 @@ double FunctionalBlock::evaluateExpression(const QString& expression, bool* ok)
   return result;
 }
 
+void FunctionalBlock::createInputPattern() {
+  lengthIP = -1;
+  foreach(AbstractInterface* iface, getControlInputs()) {      
+    ConnectedInterface* connIface = AI_TO_CON(iface);
+    QList<char>* out = connIface->getConnectedFrom()->getOutputPattern();
+    if (lengthIP == -1) {
+      lengthIP = out->size();
+    }
+    else {
+      if (out->size() < lengthIP) lengthIP = out->size();
+    }
+    if (out->size() > 0) {
+      QList<char>* in = new QList<char>(*out);
+      foreach(char c, *in) {
+        cout << (int)c;
+      }
+      cout << endl;
+
+      inputPattern.insert(connIface,in);
+    }
+    else {
+      inputPattern.insert(connIface,NULL);
+    }      
+  }  
+}
+
+bool FunctionalBlock::createAdmittance(int nbExec) {
+  static QString fctName = "FunctionalBlock::createAdmittance()";
+#ifdef DEBUG_FCTNAME
+  cout << "call to " << qPrintable(fctName) << endl;
+#endif
+  bool ok = true;
+  // firstly, copy CP in AP
+  QMapIterator<AbstractInterface*,QList<char>* > iterC(consumptionPattern);
+  while (iterC.hasNext()) {
+    iterC.next();
+    QList<char>* pattern = new QList<char>(*(iterC.value()));
+    admittance.insert(iterC.key(), pattern);    
+  }
+  lengthAP = lengthCP;
+  int clock = 0;  
+  cout << "trigger 1 at c.c. 0" << endl;
+  for(int i=1;i<nbExec;i++) {
+    // searching for the clock cycle for which a new exec starts
+    int nbGroup = 0;
+    while ((clock < lengthAP) && (nbGroup < delta)) {
+      if (isValidDataGroup(admittance,clock)) nbGroup+=1;
+      clock += 1;
+    }
+    while ((clock < lengthAP) && (! isValidDataGroup(admittance,clock))) clock+=1;
+    cout << "trigger " << (i+1) << " at c.c. " << clock << endl;
+    int sc = clock;
+    // combine CP with AP at sc
+    for(int j=0;j<lengthCP;j++) {
+      // first case : column of CP must be placed beyond AP's end.
+      if (sc == lengthAP) {
+        cout << i << "," << j << " append in AP at " << sc << endl;
+        appendToPattern(consumptionPattern,j,admittance,1);
+        lengthAP += 1;
+        sc += 1;	       
+      }
+      // second case : CP and AP can be combined directly (i.e. no X | 1 to do)
+      else if (canCombinePatterns(consumptionPattern,j,admittance,sc)) {
+        cout << i << "," << j << " combine at " << sc << endl;
+        combinePatterns(consumptionPattern,j,admittance,sc);
+        sc += 1;
+      }
+      // third case : CP has an X column
+      else if (isOnlyXDataGroup(consumptionPattern,j)) {
+        cout << i << "," << j << " shift rigth AP to combine at " << sc << endl;
+        shiftRightPattern(admittance,sc);
+        lengthAP += 1;
+        if (! canCombinePatterns(consumptionPattern,j,admittance,sc)) {
+          cerr << "Abnormal case when combining AP and CP" << endl;
+        }
+        combinePatterns(consumptionPattern,j,admittance,sc);        
+        sc += 1;
+      }
+      // fourth case : AP has an X column
+      else if (isOnlyXDataGroup(admittance,sc)) {
+        cout << i << "," << j << " jump c.c. for CP at " << sc << endl;        
+        sc += 1;
+        j -= 1;
+      }
+      else {
+        cout << "AP and CP are not consistent" << endl;
+        return false;
+      }
+    }
+  }
+  
+  return true;
+}
+
+bool FunctionalBlock::checkInputPatternCompatibility() {
+  static QString fctName = "FunctionalBlock::checkInputPatternCompatibility()";
+#ifdef DEBUG_FCTNAME
+  cout << "call to " << qPrintable(fctName) << endl;
+#endif
+  
+  bool ok = true;
+  // firstly, create input pattern
+  createInputPattern();      
+  // if some patterns are not available, end now, returning false
+  if (lengthIP == 0) {
+    clearInputPattern();
+    return false;
+  }
+  int nbExec = getNumberOfExecution();
+  ok = createAdmittance(nbExec);
+  if (!ok) return false;
+  
+  return true;
+}
+
 bool FunctionalBlock::computeOutputPattern(int nbExec) {
   static QString fctName = "FunctionalBlock::computeOutputPattern()";
 #ifdef DEBUG_FCTNAME
@@ -407,48 +539,23 @@ bool FunctionalBlock::computeOutputPattern(int nbExec) {
   else {
     cout << "computing output pattern of " << qPrintable(name) << endl;
     
-    // collect the input patterns for each input 
-    QMap<AbstractInterface*,QList<char>* > inputPattern;    
-    int minLen = -1;
-    foreach(AbstractInterface* iface, getControlInputs()) {      
-      ConnectedInterface* connIface = AI_TO_CON(iface);
-      QList<char>* out = connIface->getConnectedFrom()->getOutputPattern();
-      if (minLen == -1) {
-        minLen = out->size();
-      }
-      else {
-        if (out->size() < minLen) minLen = out->size();
+    // in case of inputPattern not created, do it
+    if (lengthIP <= 0) {
+      // collect the input patterns for each input    
+      createInputPattern();    
+      // if some patterns are not available, end now, returning false
+      if (lengthIP == 0) {
+        clearInputPattern();
+        return false;
       }
-      if (out->size() > 0) {
-        QList<char>* in = new QList<char>(*out);
-        foreach(char c, *in) {
-          cout << (int)c;
-        }
-        cout << endl;
-
-        inputPattern.insert(connIface,in);
-      }
-      else {
-        inputPattern.insert(connIface,NULL);
-      }      
-    }
-    // if some patterns are not available, end now, returning false
-    if (minLen == 0) {
-      QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);
-      while (iterI.hasNext()) {
-        iterI.next();
-        QList<char>* pattern = iterI.value();        
-        if (pattern != NULL) delete pattern;
-      }     
-      return false;
+      cout << "input pattern array initialized with min. len " << lengthIP << endl;
     }
-    cout << "input pattern array initialized with min. len " << minLen << endl;
     
     // initialize the output pattern    
-    int lengthOP = 0;
+    lengthOP = 0;
     foreach(AbstractInterface* iface, getControlOutputs()) {
       FunctionalInterface* connIface = AI_TO_FUN(iface);      
-      lengthOP = minLen+productionPattern.value(connIface)->size();
+      lengthOP = lengthIP+productionPattern.value(connIface)->size();
       QList<char>* pattern = new QList<char>();
       for(int i=0;i<lengthOP;i++) pattern->append(0);
       connIface->setOutputPattern(pattern);
@@ -459,10 +566,10 @@ bool FunctionalBlock::computeOutputPattern(int nbExec) {
     int clock = 0;
     nbExec = 0;
     // search for the beginning of the first execution.
-    while ((clock < minLen) && (! isValidDataGroup(inputPattern,clock))) clock++;
+    while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;
     cout << "found 1st exec clock: " << clock << endl;
     
-    while (clock < minLen) {
+    while (clock < lengthIP) {
       // initialize counters for current execution.
       int p = 0; // index in production pattern
       int o = 0; // clock+o will give the clock cycle of each output group
@@ -480,7 +587,7 @@ bool FunctionalBlock::computeOutputPattern(int nbExec) {
         int gap = 0; // count the number of extra null columns
         // search for PC(m) valid input group in IP
         while (nip < productionCounter.at(m)) {
-          if (clock+cip < minLen) {
+          if (clock+cip < lengthIP) {
             if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;
             cip += 1;
             gap += 1;
@@ -513,7 +620,7 @@ bool FunctionalBlock::computeOutputPattern(int nbExec) {
       // search for the next exec.
       clock += 1;      
       nip = 0;
-      while ((clock < minLen) && (nip < delta)) {
+      while ((clock < lengthIP) && (nip < delta)) {
         if (isValidDataGroup(inputPattern,clock)) nip += 1;
         if (nip < delta) clock += 1;
       }
@@ -525,13 +632,8 @@ bool FunctionalBlock::computeOutputPattern(int nbExec) {
       lengthOP -= 1;
     }
 
-    // clear input pattern    
-    QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);
-    while (iterI.hasNext()) {
-      iterI.next();
-      QList<char>* pattern = iterI.value();        
-      if (pattern != NULL) delete pattern;
-    }     
+    // clear input pattern
+    clearInputPattern();
   }
   return true;
 }
@@ -598,6 +700,17 @@ void FunctionalBlock::removeDataGroup(QMap<AbstractInterface *, QList<char> *> &
   }
 }
 
+void FunctionalBlock::shiftRightPattern(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
+  QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);  
+  while (iterSrc.hasNext()) {
+    iterSrc.next();    
+    QList<char>* srcPat = iterSrc.value();
+    if (offset < srcPat->size()) {
+      srcPat->insert(offset,0);
+    }
+  }
+}
+
 bool FunctionalBlock::isValidDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);  
   while (iterSrc.hasNext()) {
@@ -627,6 +740,8 @@ void FunctionalBlock::clearConsumptionPattern() {
     QList<char>* pattern = iterP.value();
     if (pattern != NULL) delete pattern;
   }
+  consumptionPattern.clear();
+  lengthCP = -1;      
 }  
 
 void FunctionalBlock::clearProductionPattern() {
@@ -636,4 +751,40 @@ void FunctionalBlock::clearProductionPattern() {
     QList<char>* pattern = iterP.value();
     if (pattern != NULL) delete pattern;
   }
+  productionPattern.clear();
+  lengthPP = -1;
 }  
+
+void FunctionalBlock::clearInputPattern() {
+  
+  QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);
+  while (iterI.hasNext()) {
+    iterI.next();
+    QList<char>* pattern = iterI.value();
+    if (pattern != NULL) delete pattern;
+  }
+  inputPattern.clear();
+  lengthIP = -1;
+}
+
+int FunctionalBlock::getNumberOfExecution() {
+  /* NB: this method returns the number of executions that have been started
+     but not necessary completed.
+  */
+  if (delta <= 0) return 0;
+  int nbExec = 0;
+  int offset = 0;
+  // search for the first exec.
+  while ((offset < lengthIP) && (! isValidDataGroup(inputPattern,offset))) offset++;
+  if (offset == lengthIP) return 0;
+  nbExec = 1;
+  int nbGroup = 0;
+  for(int i = offset;i<lengthIP;i++) {
+    if (isValidDataGroup(inputPattern,offset)) nbGroup++;
+    if (nbGroup == delta+1) {
+      nbExec += 1;
+      nbGroup = 1;
+    }
+  }      
+  return nbExec;  
+}
diff --git a/FunctionalBlock.h b/FunctionalBlock.h
index 2cf9a5a..6f47a00 100644
--- a/FunctionalBlock.h
+++ b/FunctionalBlock.h
@@ -31,6 +31,10 @@ public:
   // getters
   inline ReferenceBlock* getReference() { return reference; }
   inline QList<int> getProductionCounter() { return productionCounter; }
+  inline QMap<AbstractInterface*, QList<char>* > getConsumptionPattern() { return consumptionPattern; }
+  inline QMap<AbstractInterface*, QList<char>* > getProductionPattern() { return productionPattern; }
+  inline int getConsumptionPatternLength() { return lengthCP; }
+  inline int getProductionPatternLength() { return lengthPP; }
   inline int getDelta() { return delta; }
   
   // setters
@@ -57,8 +61,13 @@ public:
   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
+  bool createAdmittance(int nbExec); // initialize a QList<char> from consumption pattern and delta
   void clearConsumptionPattern();
   void clearProductionPattern();
+  void createInputPattern();
+  void clearInputPattern();
+  int getNumberOfExecution(); // compute number of block execution from inputPattern and delta
+  bool checkInputPatternCompatibility();
   bool computeOutputPattern(int nbExec = -1);
   
 private:  
@@ -126,12 +135,17 @@ private:
   void shiftRightPattern(const QMap<AbstractInterface*, QList<char>* >& pattern, int offset);
 
   QMap<AbstractInterface*, QList<char>* > consumptionPattern;
-  QMap<AbstractInterface*, QString > admittance; // the admittance expressed as prologue-cyclic part-eppilogue
-  QMap<AbstractInterface*, QList<char>* > admittanceExpanded; // the admittance expanded by taking into account nb exec.
+  QMap<AbstractInterface*, QString > admittanceCyclic; // the admittance expressed as prologue-cyclic part-eppilogue, deduced from admittance
+  QMap<AbstractInterface*, QList<char>* > admittance; // the admittance taking into account nb exec.
   QMap<AbstractInterface*, QList<char>* > productionPattern;
+  QMap<AbstractInterface*,QList<char>* > inputPattern;
   QMap<AbstractInterface*, QList<char>* > outputPattern; // CAUTION: the QList<char>* must also be stored in the outputPattern attributes of AbstractInterface
   QList<int> productionCounter; //! only usefull for control output interfaces
-  
+  int lengthIP; // for convenience, set in createInputPattern()
+  int lengthCP; // for convenience, set in createConsumptionPattern()
+  int lengthAP; // for convenience, set in createAdmittance()
+  int lengthPP;  // for convenience, set in createProductionPattern()
+  int lengthOP;  // for convenience, set in computeOutputPattern()
   int delta;
     
   ArithmeticEvaluator* evaluator;
diff --git a/Graph.cpp b/Graph.cpp
index 999e72a..eb66dc4 100644
--- a/Graph.cpp
+++ b/Graph.cpp
@@ -158,15 +158,15 @@ bool Graph::computeOutputPatterns(int nbExec) {
       }
     }    
   }
-  // search for maximum delta
-  int maxDelta = 0;
+  // search for maximum PP length
+  int maxPP = 0;
   foreach(FunctionalBlock* block, generators) {    
-    if (block->getDelta() > maxDelta) maxDelta = block->getDelta();
+    if (block->getProductionPatternLength() > maxPP) maxPP = block->getProductionPatternLength();
   }
   // compute output for generators
-  int maxExecLen = maxDelta*nbExec;
+  int maxExecLen = maxPP*nbExec;
   foreach(FunctionalBlock* block, generators) {    
-    int d = block->getDelta();
+    int d = block->getProductionPatternLength();
     block->computeOutputPattern((maxExecLen+d-1)/d);
   }
   // compute output for top group
diff --git a/blast.creator.user b/blast.creator.user
index dc3af4e..acd48e9 100755
--- a/blast.creator.user
+++ b/blast.creator.user
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE QtCreatorProject>
-<!-- Written by QtCreator 3.2.1, 2017-05-18T16:26:09. -->
+<!-- Written by QtCreator 3.2.1, 2017-05-19T16:37:01. -->
 <qtcreator>
  <data>
   <variable>EnvironmentId</variable>
diff --git a/lib/implementations/generator-cst_impl.xml b/lib/implementations/generator-cst_impl.xml
index 0c94e16..9768641 100644
--- a/lib/implementations/generator-cst_impl.xml
+++ b/lib/implementations/generator-cst_impl.xml
@@ -24,11 +24,11 @@
   </architecture>
 
   <patterns>
-    <delta value="$seq_length+$idle_length" />
+    <delta value="$seq_length" />
     <consumption>
     </consumption>
     <production counter="">
-      <output name="data_o_enb" pattern="1{$seq_length}X{$idle_length}" />
+      <output name="data_o_enb" pattern="1{$seq_length}0{$idle_length}" />
     </production>
   </patterns>
 </block_impl>
-- 
2.39.5