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

Private GIT Repository
finished testbench generation
[blast.git] / Graph.cpp
1 #include "Graph.h"
2 #include "GroupBlock.h"
3 #include "ReferenceBlock.h"
4 #include "FunctionalBlock.h"
5 #include "SpecialBlock.h"
6 #include "BlockParameter.h"
7 #include "ConnectedInterface.h"
8
9 Graph::Graph() {
10   topGroup = NULL;
11 }
12
13 Graph::~Graph() {
14   
15   delete topGroup;
16 }
17
18 void Graph::createTopGroup(bool createTopGroupIfaces) {
19   topGroup = new GroupBlock(this, NULL, createTopGroupIfaces);
20   topGroup->setName("top group");
21   groups.append(topGroup);
22 }
23
24 QList<AbstractInterface *> Graph::getOutsideInterfaces() {
25   return topGroup->getInterfaces();
26 }
27
28 GroupBlock* Graph::createChildGroupBlock(GroupBlock* parent, bool createGroupIface) {
29   GroupBlock* b = new GroupBlock(this, parent, createGroupIface);
30   groups.append(b);
31   return b;
32 }
33
34 void Graph::removeGroupBlock(GroupBlock *group) {
35   group->removeAllBlocks();
36   GroupBlock* parent = AB_TO_GRP(group->getParent());
37   parent->removeBlock(group);
38   groups.removeAll(group);
39 }
40
41 GroupBlock* Graph::getGroupBlockByName(QString name) {
42   foreach(GroupBlock* group, groups) {
43     if (group->getName() == name) return group;
44   }
45   return NULL;
46 }
47
48 FunctionalBlock* Graph::createFunctionalBlock(GroupBlock* group, ReferenceBlock* ref, bool createIfaces) {
49
50   FunctionalBlock* newBlock = NULL;
51   if (ref->getSpecialType() != SpecialBlock::NotSpecial) {
52     cout << "Graph: create special block from " << qPrintable(ref->getName()) << endl;
53     newBlock = new SpecialBlock(this, ref->getSpecialType(), group,ref, createIfaces);
54   }
55   else {
56     cout << "Graph: create normal block from " << qPrintable(ref->getName()) << endl;
57     newBlock = new FunctionalBlock(this, group,ref, createIfaces);
58   }
59   group->addBlock(newBlock);
60
61   return newBlock;
62 }
63
64 FunctionalBlock* Graph::duplicateFunctionalBlock(FunctionalBlock *block) {
65
66   ReferenceBlock* ref = block->getReference();
67   GroupBlock* group = AB_TO_GRP(block->getParent());
68
69   // adding to the graph
70   FunctionalBlock* newBlock = createFunctionalBlock(group,ref, true);
71   return newBlock;
72 }
73
74
75 bool Graph::removeFunctionalBlock(FunctionalBlock* block) {
76   GroupBlock* group = AB_TO_GRP(block->getParent());
77   group->removeBlock(block);
78   return true;
79 }
80
81 FunctionalBlock* Graph::getFunctionalBlockByName(QString name, GroupBlock* parent) {
82   FunctionalBlock* block = NULL;
83   if (parent != NULL) {
84     block = AB_TO_FUN(parent->getFunctionalBlockByName(name));
85   }
86   else {
87     foreach(GroupBlock* group, groups) {
88       block = AB_TO_FUN(group->getFunctionalBlockByName(name));
89       if (block != NULL) return block;
90     }
91   }
92   return block;
93 }
94
95 FunctionalBlock* Graph::createStimuliBlock(ReferenceBlock* ref, bool createIfaces) {
96   /* A stimuli block is always a special block with idSpecial = 1 */
97
98   FunctionalBlock* newBlock = new SpecialBlock(this, AbstractBlock::Source, NULL,ref, createIfaces);
99   stimulis.append(newBlock);
100   return newBlock;
101 }
102
103 FunctionalBlock* Graph::duplicateStimuliBlock(FunctionalBlock *block) {
104
105   ReferenceBlock* ref = block->getReference();  
106
107   // adding to the graph
108   FunctionalBlock* newBlock = createStimuliBlock(ref, true);
109   return newBlock;
110 }
111
112 FunctionalBlock* Graph::getStimuliBlockByName(QString name) {
113   foreach(FunctionalBlock* block, stimulis) {
114     if (block->getName() == name) return block;
115   }
116   return NULL;
117 }
118
119 bool Graph::removeStimuliBlock(FunctionalBlock *block) {
120   stimulis.removeAll(block);
121   return true;
122 }
123
124 void Graph::createPatterns() throw(Exception) {
125   
126   foreach(AbstractBlock* block, stimulis) {
127     FunctionalBlock* funBlock = AB_TO_FUN(block);
128     try {
129       funBlock->createPatterns();
130     }
131     catch(Exception e) {
132       throw(e);      
133     }
134   }
135   
136   foreach(AbstractBlock* block, groups) {
137     GroupBlock* group = AB_TO_GRP(block);    
138     foreach(AbstractBlock* inBlock, group->getBlocks()) {
139       if (inBlock->isFunctionalBlock()) {
140         FunctionalBlock* funBlock = AB_TO_FUN(inBlock);
141         try {
142           funBlock->createPatterns();
143         }
144         catch(Exception e) {
145           throw(e);
146         }
147       }
148     }
149   }  
150 }
151
152 void Graph::resetPatternComputed() {
153   foreach(AbstractBlock* block, stimulis) {
154     block->setOutputPatternComputed(false);
155     block->resetTraversalLevel();
156   }
157   foreach(AbstractBlock* block, groups) {
158     GroupBlock* group = AB_TO_GRP(block);
159     group->setOutputPatternComputed(false);
160     block->resetTraversalLevel();
161     foreach(AbstractBlock* inBlock, group->getBlocks()) {
162       inBlock->setOutputPatternComputed(false);
163       block->resetTraversalLevel();
164     }
165   }
166 }
167
168 void Graph::computeOutputPatterns(int nbExec) throw(Exception) {
169   
170   try {
171     createPatterns();
172   }
173   catch(Exception e) {
174     throw(e);    
175   }
176
177   resetPatternComputed();
178   // search for all block that are source.
179   QList<FunctionalBlock*> sources;
180   sources.append(stimulis);
181   foreach(AbstractBlock* block, groups) {    
182     GroupBlock* group = AB_TO_GRP(block);    
183     foreach(AbstractBlock* inBlock, group->getBlocks()) {
184       FunctionalBlock* funBlock = AB_TO_FUN(inBlock);
185       if (inBlock->isSourceBlock()) {
186         sources.append(funBlock);
187       }
188     }    
189   }
190   // search for maximum PP length
191   int maxPP = 0;
192   foreach(FunctionalBlock* block, sources) {
193     if (block->getProductionPatternLength() > maxPP) maxPP = block->getProductionPatternLength();
194   }
195   // compute output for generators
196   int maxExecLen = maxPP*nbExec;
197   foreach(FunctionalBlock* block, sources) {
198     int d = block->getProductionPatternLength();
199     block->computeOutputPattern((maxExecLen+d-1)/d);
200   }
201   // compute output for top group
202   try {
203     topGroup->computeOutputPattern();
204   }
205   catch(Exception e) {
206     throw(e);
207   }
208 }
209
210 void Graph::generateVHDL(const QString &path) throw(Exception) {
211   // generating VHDL for stimulis
212   cout << "generating stimulis" << endl;
213   try {
214     foreach(FunctionalBlock* stimuli, stimulis) {
215       stimuli->generateVHDL(path);
216     }
217   }
218   catch(Exception e) {
219     throw(e);
220   }
221   // generating VHDL for top group
222   cout << "generating top group" << endl;
223   try {
224     topGroup->generateVHDL(path);
225   }
226   catch(Exception e) {
227     throw(e);
228   }
229 }
230
231 void Graph::generateTestbench(const QString &projectName, const QString &benchFile) throw(Exception) {
232
233
234   QFile vhdlBench(benchFile);
235
236   if (!vhdlBench.open(QIODevice::WriteOnly)) {
237     throw(Exception(VHDLFILE_NOACCESS));
238   }
239
240   cout << "generate testbench" << endl;
241   QTextStream out(&vhdlBench);
242
243   out << "-------------------------------------------------------------------------------" << endl;
244   out << "-- testbench for " << projectName << endl;
245   out << "-------------------------------------------------------------------------------" << endl << endl;
246   out << "-------------------------------------------------------------------------------" << endl;
247   out << "-- clock generator" << endl;
248   out << "-------------------------------------------------------------------------------" << endl << endl;
249
250   out << "library IEEE;" << endl;
251   out << "use IEEE.STD_LOGIC_1164.all;" << endl;
252   out << "use IEEE.numeric_std.all;" << endl;
253   out << "entity clock_gen is" << endl;
254   out << "  generic (" << endl;
255   out << "    Tps : time                          -- high level width : must be < period" << endl;
256   out << "    );" << endl;
257   out << "  port (" << endl;
258   out << "    phase : out std_logic" << endl;
259   out << "    );" << endl;
260   out << "end entity clock_gen;"  << endl<< endl;
261
262   out << "architecture clock_gen_1 of clock_gen is" << endl;
263   out << "  constant period : time := 2*Tps;" << endl;
264   out << "begin" << endl;
265   out << "  clock_process : process" << endl;
266   out << "  begin" << endl;
267   out << "    phase <= '1', '0' after Tps;" << endl;
268   out << "    wait for period;" << endl;
269   out << "  end process clock_process;" << endl;
270   out << "end architecture clock_gen_1;" << endl << endl;
271
272   out << "-------------------------------------------------------------------------------" << endl;
273   out << "-- testbench" << endl;
274   out << "-------------------------------------------------------------------------------" << endl << endl;
275   out << "library IEEE;" << endl;
276   out << "use IEEE.STD_LOGIC_1164.all;" << endl;
277   out << "use IEEE.numeric_std.all;" << endl;
278   out << "entity " << projectName << "_tb is" << endl;
279   out << "end entity " << projectName << "_tb;" << endl << endl;
280
281   out << "architecture " << projectName << "_tb_1 of " << projectName << "_tb is" << endl << endl;
282
283   out << "  component clock_gen" << endl;
284   out << "    generic (" << endl;
285   out << "      Tps : time" << endl;
286   out << "      );" << endl;
287   out << "    port (" << endl;
288   out << "      phase : out std_logic" << endl;
289   out << "      );" << endl;
290   out << "  end component;" << endl << endl;
291
292   topGroup->generateComponent(out,false);
293   foreach(FunctionalBlock* block, stimulis) {
294     block->generateComponent(out,false);
295   }
296
297   out << "  ----------------------------" << endl;
298   out << "  --  SIGNALS" << endl;
299   out << "  ----------------------------" << endl << endl;
300
301   out << "  -- signals to reset stimulis" << endl;
302   foreach(FunctionalBlock* block, stimulis) {
303     out << "  signal reset_" << block->getName() << " : std_logic;" << endl;
304   }
305   out << endl;
306
307   out << "  -- signals for external clocks/reset" << endl;
308   for(int i=0;i<clocks.size();i++) {
309     out << "  signal ext_clk_" << i << " : std_logic;" << endl;
310     out << "  signal ext_reset_" << i << " : std_logic;" << endl;
311   }
312   out << endl;
313
314   // signals out of stimulis blocks
315   foreach(FunctionalBlock* block, stimulis) {
316     /* NB: normally, a stimuli has at least an input interface of type data
317       that is used to trigger the generation. It is necessarily called start.
318       It may have an additional input that is necessarily called stop.
319      */
320     try {
321       out << "  -- signals from input ports of " << block->getName() << endl;
322       QList<AbstractInterface*> listInputs = block->getInputs();
323       foreach(AbstractInterface* iface, listInputs) {
324         if (iface->getPurpose() == AbstractInterface::Data) {
325           out << "  signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
326         }
327       }
328     }
329     catch(Exception e) {
330       throw(e);
331     }
332     try {
333       out << "  -- signals from output ports of " << block->getName() << endl;
334       QList<AbstractInterface*> listOutputs = block->getOutputs();
335       foreach(AbstractInterface* iface, listOutputs) {
336         if ((iface->getPurpose() == AbstractInterface::Data)||(iface->getPurpose() == AbstractInterface::Control)) {
337           out << "  signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
338         }
339       }
340     }
341     catch(Exception e) {
342       throw(e);
343     }
344     out << endl;
345   }
346   out << endl;
347
348   // signals out of top group
349   try {
350     out << "  -- signals from output ports of " << topGroup->getName() << endl;
351     QList<AbstractInterface*> listOutputs = topGroup->getOutputs();
352     foreach(AbstractInterface* iface, listOutputs) {
353       if ((iface->getPurpose() == AbstractInterface::Data)||(iface->getPurpose() == AbstractInterface::Control)) {
354         out << "  signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
355       }
356     }
357   }
358   catch(Exception e) {
359     throw(e);
360   }
361   out << endl;
362
363   // signals out of top group
364   try {
365     out << "  -- signals from inout ports of " << topGroup->getName() << endl;
366     QList<AbstractInterface*> listBidirs = topGroup->getBidirs();
367     foreach(AbstractInterface* iface, listBidirs) {
368       if (iface->getPurpose() == AbstractInterface::Data) {
369         out << "  signal " << iface->toVHDL(AbstractInterface::Signal,0) << endl;
370       }
371     }
372   }
373   catch(Exception e) {
374     throw(e);
375   }
376   out << endl;
377
378   out << "begin" << endl;
379   // for now assign all external resets to fixed 0 because of clkrstgen in top group
380   for(int i=0;i<clocks.size();i++) {
381     out << "  ext_reset_" << i << " <= '0';" << endl;
382   }
383   out << endl;
384   // generate clock instances
385   for(int i=0;i<clocks.size();i++) {
386     double halfPer = 500.0/clocks.at(i);
387     out << "  clock_" << i << " : clock_gen" << endl;
388     out << "    generic map (" << endl;
389     out << "      Tps => " << halfPer << " ns" << endl;
390     out << "      )" << endl;
391     out << "    port map (" << endl;
392     out << "      phase => ext_clk_" << i << endl;
393     out << "      );" << endl << endl;
394   }
395   // generate instances of stimulis
396   foreach(FunctionalBlock* block, stimulis) {
397     try {
398       out << "  " << block->getName() << "_1 : " << block->getName() << endl;
399
400       QList<BlockParameter*> listGenerics = block->getGenericParameters();
401       QList<AbstractInterface*> listInputs = block->getInputs();
402       QList<AbstractInterface*> listOutputs = block->getOutputs();
403
404       if (!listGenerics.isEmpty()) {
405         out << "    generic map (" << endl;
406         int i;
407         for(i=0;i<listGenerics.size()-1;i++) {
408           out << "      " << listGenerics.at(i)->toVHDL(BlockParameter::Instance, BlockParameter::NoComma) << "," << endl;
409         }
410         out << "      " << listGenerics.at(i)->toVHDL(BlockParameter::Instance,BlockParameter::NoComma) << endl;
411         out << "    )" << endl;
412       }
413
414       out << "    port map (" << endl;
415       QString portMap = "";
416
417       for(int i=0;i<listInputs.size();i++) {
418         ConnectedInterface* connIface = AI_TO_CON(listInputs.at(i));
419         if ( (connIface->getPurpose() == AbstractInterface::Data) || (connIface->getPurpose() == AbstractInterface::Control)) {
420           portMap += "      " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
421         }
422         else if (connIface->getPurpose() == AbstractInterface::Clock) {
423           // get the "fake" clkrstgen from which it is connected
424           ConnectedInterface* fromIface = connIface->getConnectedFrom();
425           QString clkrstName = fromIface->getOwner()->getName();
426           clkrstName.remove(0,10);
427           portMap += "      " + connIface->getName() + " => ext_clk_" + clkrstName + ",\n";
428         }
429         else if (connIface->getPurpose() == AbstractInterface::Reset) {
430           portMap += "      " + connIface->getName() + " => reset_" + block->getName()+",\n";
431         }
432       }
433       for(int i=0;i<listOutputs.size();i++) {
434         ConnectedInterface* connIface = AI_TO_CON(listOutputs.at(i));
435         portMap += "      " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
436       }
437       portMap.chop(2);
438       out << portMap << endl;
439
440
441       out << "    );" << endl;
442     }
443     catch(Exception e) {
444       throw(e);
445     }
446     out << endl;
447   }
448   out << endl;
449   // generate instance of top group
450   try {
451     out << "  " << topGroup->getName() << "_1 : " << topGroup->getName() << endl;
452
453     QList<BlockParameter*> listGenerics = topGroup->getGenericParameters();
454     QList<AbstractInterface*> listInputs = topGroup->getInputs();
455     QList<AbstractInterface*> listOutputs = topGroup->getOutputs();
456     QList<AbstractInterface*> listBidirs = topGroup->getBidirs();
457
458     if (!listGenerics.isEmpty()) {
459       out << "    generic map (" << endl;
460       int i;
461       for(i=0;i<listGenerics.size()-1;i++) {
462         out << "      " << listGenerics.at(i)->toVHDL(BlockParameter::Instance, BlockParameter::NoComma) << "," << endl;
463       }
464       out << "      " << listGenerics.at(i)->toVHDL(BlockParameter::Instance,BlockParameter::NoComma) << endl;
465       out << "    )" << endl;
466     }
467
468     out << "    port map (" << endl;
469     QString portMap = "";
470
471     for(int i=0;i<listInputs.size();i++) {
472       ConnectedInterface* connIface = AI_TO_CON(listInputs.at(i));
473       if ( (connIface->getPurpose() == AbstractInterface::Data) || (connIface->getPurpose() == AbstractInterface::Control)) {
474         ConnectedInterface* fromIface = connIface->getConnectedFrom();
475         portMap += "      " + connIface->getName() + " => " + fromIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
476       }
477       else if ( (connIface->getPurpose() == AbstractInterface::Clock) || (connIface->getPurpose() == AbstractInterface::Reset)) {
478         portMap += "      " + connIface->getName() + " => " + connIface->getName() + ",\n";
479       }
480     }
481     for(int i=0;i<listOutputs.size();i++) {
482       ConnectedInterface* connIface = AI_TO_CON(listOutputs.at(i));
483       portMap += "      " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
484     }
485     for(int i=0;i<listBidirs.size();i++) {
486       ConnectedInterface* connIface = AI_TO_CON(listBidirs.at(i));
487       portMap += "      " + connIface->getName() + " => " + connIface->toVHDL(AbstractInterface::Instance, AbstractInterface::NoComma) + ",\n";
488     }
489     portMap.chop(2);
490     out << portMap << endl;
491
492
493     out << "    );" << endl;
494   }
495   catch(Exception e) {
496     throw(e);
497   }
498   out << endl;
499
500   // generate process for stimulis
501   foreach(FunctionalBlock* block, stimulis) {
502     // getting the start input
503     AbstractInterface* startIface = block->getIfaceFromName("start");
504     if (startIface == NULL) continue;
505     double per = 1000.0/startIface->getClockFrequency();
506     QString startName = block->getName()+"_start";
507     out << "  from_" << block->getName() << " : process" << endl;
508     out << "    variable pclk : time := " << per << " ns;" << endl;
509     out << "  begin" << endl;
510     out << "    reset_" << block->getName() << " <= '0';" << endl;
511     out << "    " << startName << " <= '0';" << endl;
512     out << "    wait for 2*pclk;" << endl;
513     out << "    reset_" << block->getName() << " <= '1';" << endl;
514     out << "    wait for 1*pclk;" << endl;
515     out << "    reset_" << block->getName() << " <= '0';" << endl;
516     out << "    wait for 5*pclk;" << endl;
517     out << "    " << startName << " <= '1';" << endl;
518     out << "    wait for pclk;" << endl;
519     out << "    " << startName << " <= '0';" << endl << endl;
520     out << "    wait for 100000 us;" << endl;
521     out << "  end process from_" << block->getName() << ";" << endl;
522   }
523
524   out << "end architecture " << projectName << "_tb_1;" << endl;
525   vhdlBench.close();
526
527 }
528
529 QList<QString> Graph::getExternalResources() {
530   QList<QString> list = topGroup->getExternalResources();
531   return list;
532 }