2 #include "GroupBlock.h"
3 #include "ReferenceBlock.h"
4 #include "FunctionalBlock.h"
5 #include "SpecialBlock.h"
6 #include "BlockParameter.h"
7 #include "ConnectedInterface.h"
18 void Graph::createTopGroup(bool createTopGroupIfaces) {
19 topGroup = new GroupBlock(this, NULL, createTopGroupIfaces);
20 topGroup->setName("top group");
21 groups.append(topGroup);
24 QList<AbstractInterface *> Graph::getOutsideInterfaces() {
25 return topGroup->getInterfaces();
28 GroupBlock* Graph::createChildGroupBlock(GroupBlock* parent, bool createGroupIface) {
29 GroupBlock* b = new GroupBlock(this, parent, createGroupIface);
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);
41 GroupBlock* Graph::getGroupBlockByName(QString name) {
42 foreach(GroupBlock* group, groups) {
43 if (group->getName() == name) return group;
48 FunctionalBlock* Graph::createFunctionalBlock(GroupBlock* group, ReferenceBlock* ref, bool createIfaces) {
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);
56 cout << "Graph: create normal block from " << qPrintable(ref->getName()) << endl;
57 newBlock = new FunctionalBlock(this, group,ref, createIfaces);
59 group->addBlock(newBlock);
64 FunctionalBlock* Graph::duplicateFunctionalBlock(FunctionalBlock *block) {
66 ReferenceBlock* ref = block->getReference();
67 GroupBlock* group = AB_TO_GRP(block->getParent());
69 // adding to the graph
70 FunctionalBlock* newBlock = createFunctionalBlock(group,ref, true);
75 bool Graph::removeFunctionalBlock(FunctionalBlock* block) {
76 GroupBlock* group = AB_TO_GRP(block->getParent());
77 group->removeBlock(block);
81 FunctionalBlock* Graph::getFunctionalBlockByName(QString name, GroupBlock* parent) {
82 FunctionalBlock* block = NULL;
84 block = AB_TO_FUN(parent->getFunctionalBlockByName(name));
87 foreach(GroupBlock* group, groups) {
88 block = AB_TO_FUN(group->getFunctionalBlockByName(name));
89 if (block != NULL) return block;
95 FunctionalBlock* Graph::createStimuliBlock(ReferenceBlock* ref, bool createIfaces) {
96 /* A stimuli block is always a special block with idSpecial = 1 */
98 FunctionalBlock* newBlock = new SpecialBlock(this, AbstractBlock::Source, NULL,ref, createIfaces);
99 stimulis.append(newBlock);
103 FunctionalBlock* Graph::duplicateStimuliBlock(FunctionalBlock *block) {
105 ReferenceBlock* ref = block->getReference();
107 // adding to the graph
108 FunctionalBlock* newBlock = createStimuliBlock(ref, true);
112 FunctionalBlock* Graph::getStimuliBlockByName(QString name) {
113 foreach(FunctionalBlock* block, stimulis) {
114 if (block->getName() == name) return block;
119 bool Graph::removeStimuliBlock(FunctionalBlock *block) {
120 stimulis.removeAll(block);
124 void Graph::createPatterns() throw(Exception) {
126 foreach(AbstractBlock* block, stimulis) {
127 FunctionalBlock* funBlock = AB_TO_FUN(block);
129 funBlock->createPatterns();
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);
142 funBlock->createPatterns();
152 void Graph::resetPatternComputed() {
153 foreach(AbstractBlock* block, stimulis) {
154 block->setOutputPatternComputed(false);
155 block->resetTraversalLevel();
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();
168 void Graph::computeOutputPatterns(int nbExec) throw(Exception) {
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);
190 // search for maximum PP length
192 foreach(FunctionalBlock* block, sources) {
193 if (block->getProductionPatternLength() > maxPP) maxPP = block->getProductionPatternLength();
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);
201 // compute output for top group
203 topGroup->computeOutputPattern();
210 void Graph::generateVHDL(const QString &path) throw(Exception) {
211 // generating VHDL for stimulis
212 cout << "generating stimulis" << endl;
214 foreach(FunctionalBlock* stimuli, stimulis) {
215 stimuli->generateVHDL(path);
221 // generating VHDL for top group
222 cout << "generating top group" << endl;
224 topGroup->generateVHDL(path);
231 void Graph::generateTestbench(const QString &projectName, const QString &benchFile) throw(Exception) {
234 QFile vhdlBench(benchFile);
236 if (!vhdlBench.open(QIODevice::WriteOnly)) {
237 throw(Exception(VHDLFILE_NOACCESS));
240 cout << "generate testbench" << endl;
241 QTextStream out(&vhdlBench);
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;
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;
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;
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;
281 out << "architecture " << projectName << "_tb_1 of " << projectName << "_tb is" << endl << endl;
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;
292 topGroup->generateComponent(out,false);
293 foreach(FunctionalBlock* block, stimulis) {
294 block->generateComponent(out,false);
297 out << " ----------------------------" << endl;
298 out << " -- SIGNALS" << endl;
299 out << " ----------------------------" << endl << endl;
301 out << " -- signals to reset stimulis" << endl;
302 foreach(FunctionalBlock* block, stimulis) {
303 out << " signal reset_" << block->getName() << " : std_logic;" << endl;
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;
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.
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;
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;
348 // signals out of top group
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;
363 // signals out of top group
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;
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;
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;
391 out << " port map (" << endl;
392 out << " phase => ext_clk_" << i << endl;
393 out << " );" << endl << endl;
395 // generate instances of stimulis
396 foreach(FunctionalBlock* block, stimulis) {
398 out << " " << block->getName() << "_1 : " << block->getName() << endl;
400 QList<BlockParameter*> listGenerics = block->getGenericParameters();
401 QList<AbstractInterface*> listInputs = block->getInputs();
402 QList<AbstractInterface*> listOutputs = block->getOutputs();
404 if (!listGenerics.isEmpty()) {
405 out << " generic map (" << endl;
407 for(i=0;i<listGenerics.size()-1;i++) {
408 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance, BlockParameter::NoComma) << "," << endl;
410 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance,BlockParameter::NoComma) << endl;
414 out << " port map (" << endl;
415 QString portMap = "";
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";
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";
429 else if (connIface->getPurpose() == AbstractInterface::Reset) {
430 portMap += " " + connIface->getName() + " => reset_" + block->getName()+",\n";
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";
438 out << portMap << endl;
441 out << " );" << endl;
449 // generate instance of top group
451 out << " " << topGroup->getName() << "_1 : " << topGroup->getName() << endl;
453 QList<BlockParameter*> listGenerics = topGroup->getGenericParameters();
454 QList<AbstractInterface*> listInputs = topGroup->getInputs();
455 QList<AbstractInterface*> listOutputs = topGroup->getOutputs();
456 QList<AbstractInterface*> listBidirs = topGroup->getBidirs();
458 if (!listGenerics.isEmpty()) {
459 out << " generic map (" << endl;
461 for(i=0;i<listGenerics.size()-1;i++) {
462 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance, BlockParameter::NoComma) << "," << endl;
464 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Instance,BlockParameter::NoComma) << endl;
468 out << " port map (" << endl;
469 QString portMap = "";
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";
477 else if ( (connIface->getPurpose() == AbstractInterface::Clock) || (connIface->getPurpose() == AbstractInterface::Reset)) {
478 portMap += " " + connIface->getName() + " => " + connIface->getName() + ",\n";
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";
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";
490 out << portMap << endl;
493 out << " );" << endl;
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;
524 out << "end architecture " << projectName << "_tb_1;" << endl;
529 QList<QString> Graph::getExternalResources() {
530 QList<QString> list = topGroup->getExternalResources();