My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vhdlfile.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  vhdlfile.cpp
3  --------------
4  begin : Sat Apr 15 2006
5  copyright : (C) 2006 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "vhdlfile.h"
19 #include "qucs.h"
20 #include "main.h"
21 #include "schematic.h"
22 
23 #include <qregexp.h>
24 #include <qdir.h>
25 #include <qfileinfo.h>
26 
27 
29 {
31  Description = QObject::tr("VHDL file");
32 
33  Props.append(new Property("File", "sub.vhdl", false,
34  QObject::tr("Name of VHDL file")));
35 
36  Model = "VHDL";
37  Name = "X";
38 
39  // Do NOT call createSymbol() here. But create port to let it rotate.
40  Ports.append(new Port(0, 0));
41 }
42 
43 // -------------------------------------------------------
45 {
46  VHDL_File *p = new VHDL_File();
47  p->Props.getFirst()->Value = Props.getFirst()->Value;
48  p->recreate(0);
49  return p;
50 }
51 
52 // -------------------------------------------------------
53 Element* VHDL_File::info(QString& Name, char* &BitmapFile, bool getNewOne)
54 {
55  Name = QObject::tr("VHDL file");
56  BitmapFile = (char *) "vhdlfile";
57 
58  if(getNewOne) {
59  VHDL_File *p = new VHDL_File();
60  p->recreate(0); // createSymbol() is NOT called in constructor !!!
61  return p;
62  }
63  return 0;
64 }
65 
66 // -------------------------------------------------------
67 QString VHDL_File::vhdlCode(int)
68 {
69  QString s;
70  Port *pp = Ports.first();
71  if(pp) {
72  s = " " + Name + ": entity " + EntityName;
73 
74  // output all generic properties
75  Property *pr = Props.at(1);
76  if (pr) {
77  s += " generic map (";
78  s += pr->Value;
79  for(pr = Props.next(); pr != 0; pr = Props.next())
80  s += ", " + pr->Value;
81  s += ")";
82  }
83 
84  // output all node names
85  s += " port map (";
86  if(pp) s += pp->Connection->Name;
87  for(pp = Ports.next(); pp != 0; pp = Ports.next())
88  s += ", "+pp->Connection->Name; // node names
89  s += ");\n";
90  }
91  return s;
92 }
93 
94 // -------------------------------------------------------
95 // Returns a comma separated list of the port names of the last
96 // entity in this file.
98 {
99  QString File(Props.getFirst()->Value);
100  QFileInfo Info(File);
101  if(Info.isRelative())
102  File = QucsWorkDir.filePath(File);
103 
104  QFile f(File);
105  if(!f.open(IO_ReadOnly))
106  return QString("");
107 
108  QTextStream stream(&f);
109  File = stream.read(); // QString is better for "find" function
110  f.close();
111 
112  // parse ports, i.e. network connections; and generics, i.e. parameters
113  VHDL_File_Info VInfo(File);
114  GenNames = VInfo.GenNames;
115  EntityName = VInfo.EntityName;
116  TypeNames = VInfo.TypeNames;
117  GenTypes = VInfo.GenTypes;
118  GenDefs = VInfo.GenDefs;
119  return VInfo.PortNames;
120 }
121 
122 // -------------------------------------------------------
124 {
125  QFontMetrics metrics(QucsSettings.font); // get size of text
126  int fHeight = metrics.lineSpacing();
127 
128  int No = 0;
129  TypeNames = "";
130  QString tmp, PortNames = loadFile();
131  if(!PortNames.isEmpty())
132  No = PortNames.contains(',') + 1;
133 
134  #define HALFWIDTH 17
135  int h = 30*((No-1)/2) + 15;
136  Lines.append(new Line(-HALFWIDTH, -h, HALFWIDTH, -h,QPen(QPen::darkBlue,2)));
137  Lines.append(new Line( HALFWIDTH, -h, HALFWIDTH, h,QPen(QPen::darkBlue,2)));
138  Lines.append(new Line(-HALFWIDTH, h, HALFWIDTH, h,QPen(QPen::darkBlue,2)));
139  Lines.append(new Line(-HALFWIDTH, -h,-HALFWIDTH, h,QPen(QPen::darkBlue,2)));
140 
141  tmp = QObject::tr("vhdl");
142  int w = metrics.width(tmp);
143  Texts.append(new Text(w/-2, fHeight/-2, tmp));
144 
145  int y = 15-h, i = 0;
146  Port *pp;
147  while(i<No) {
148  Lines.append(new Line(-30, y,-HALFWIDTH, y,QPen(QPen::darkBlue,2)));
149  pp = new Port(-30, y);
150  Ports.append(pp);
151  pp->Type = TypeNames.section(',', i, i);
152  tmp = PortNames.section(',', i, i);
153  w = metrics.width(tmp);
154  Texts.append(new Text(-19-w, y-fHeight-2, tmp));
155  i++;
156 
157  if(i == No) break;
158  Lines.append(new Line(HALFWIDTH, y, 30, y,QPen(QPen::darkBlue,2)));
159  pp = new Port( 30, y);
160  Ports.append(pp);
161  pp->Type = TypeNames.section(',', i, i);
162  tmp = PortNames.section(',', i, i);
163  Texts.append(new Text( 20, y-fHeight-2, tmp));
164  y += 60;
165  i++;
166  }
167 
168  x1 = -30; y1 = -h-2;
169  x2 = 30; y2 = h+2;
170  tx = x1+4;
171  ty = y2+4;
172 
173  // now create/modify properties
174  No = 0;
175  if(!GenNames.isEmpty())
176  No = GenNames.contains(',') + 1;
177  Property * pr = Props.at(1);
178  for(i=0; i<No; i++) {
179  if (!pr) {
180  pr = new Property(GenNames.section(',', i, i),
181  GenDefs.section(',', i, i), true,
182  QObject::tr("generic variable")+
183  " "+QString::number(i+1));
184  Props.append(pr);
185  pr = 0;
186  }
187  else {
188  pr->Description =
189  QObject::tr("generic variable")+" "+QString::number(i+1);
190  pr->Name = GenNames.section(',', i, i);
191  pr = Props.next();
192  }
193  }
194  // remove remaining properties if necessary
195  y=Props.count()-1;
196  for(i=No; i<y; i++) {
197  Props.removeLast();
198  }
199 }
200 
201 // -------------------------------------------------------
203 {
204  // construct full filename
205  QString FileName = Props.getFirst()->Value;
206  return properAbsFileName(FileName);
207 }
208 
209 // -------------------------------------------------------
210 bool VHDL_File::createSubNetlist(QTextStream *stream)
211 {
212  ErrText = "";
213 
214  // check filename
215  QString FileName = Props.getFirst()->Value;
216  if(FileName.isEmpty()) {
217  ErrText += QObject::tr("ERROR: No file name in %1 component \"%2\".").
218  arg(Model).arg(Name);
219  return false;
220  }
221 
222  // construct full filename
223  FileName = getSubcircuitFile();
224 
225  // open file for reading
226  QFile f(FileName);
227  if(!f.open(IO_ReadOnly)) {
228  ErrText += QObject::tr("ERROR: Cannot open %1 file \"%2\".").
229  arg(Model).arg(FileName);
230  return false;
231  }
232 
233  // write the whole VHDL file into the netlist output
234  QByteArray FileContent = f.readAll();
235  f.close();
236  (*stream) << '\n';
237  stream->writeRawBytes(FileContent.data(), FileContent.size());
238  (*stream) << '\n';
239  return true;
240 }
241 
242 // -------------------------------------------------------
244 {
245  EntityName = "";
246  PortNames = "";
247  TypeNames = "";
248  GenTypes = "";
249  GenNames = "";
250  GenDefs = "";
251 }
252 
253 // -------------------------------------------------------
255 {
256  if (isfile) {
257  QFile f(File);
258  if(!f.open(IO_ReadOnly))
259  File = "";
260  else {
261  QByteArray FileContent = f.readAll();
262  File = QString(FileContent);
263  }
264  f.close();
265  }
266 
267  QString s;
268  PortNames = "";
269  int i=0, j, k=0;
270  while((i=File.find("--", i)) >= 0) { // remove all VHDL comments
271  j = File.find('\n', i+2); // This also finds "--" within a ...
272  if(j < 0) // string, but as no strings are ...
273  File = File.left(i); // allowed in entity headers, it ...
274  else // does not matter.
275  File.remove(i, j-i);
276  }
277 
278  QRegExp Expr;
279  Expr.setCaseSensitive(false);
280  for(;;) {
281  k--;
282  Expr.setPattern("\\bentity\\b"); // start of last entity
283  k = File.findRev(Expr, k);
284  if(k < 0)
285  return;
286 
287  Expr.setPattern("\\bend\\b"); // end of last entity
288  i = File.find(Expr, k+7);
289  if(i < 0)
290  return;
291  s = File.mid(k+7, i-k-7); // cut out entity declaration
292 
293  Expr.setPattern("\\b");
294  i = s.find(Expr);
295  if(i < 0)
296  return;
297  j = s.find(Expr, i+1);
298  if(j < 0)
299  return;
300  EntityName = s.mid(i, j-i); // save entity name
301 
302  i = s.find(Expr, j+1);
303  if(i < 0)
304  return;
305  j = s.find(Expr, i+1);
306  if(j < 0)
307  return;
308  if(s.mid(i, j-i).lower() == "is") // really found start of entity ?
309  break;
310 
311  if(k < 1) // already searched the whole text
312  return;
313  }
314 
315  // parse ports, i.e. network connections; and generics, i.e. parameters
316  GenNames = parseGenerics(s,j);
317  PortNames = parsePorts(s,j);
318 }
319 
320 // -------------------------------------------------------
321 QString VHDL_File_Info::parsePorts(QString s, int j)
322 {
323  QRegExp Expr;
324  Expr.setCaseSensitive(false);
325  int i, p, l, k;
326 
327  Expr.setPattern("\\bport\\b"); // start of interface definition
328  i = s.find(Expr, j+1);
329  if(i < 0)
330  return QString("");
331  // find opening (
332  i = s.find('(', i+4) + 1;
333  if(i <= 0)
334  return QString("");
335 
336  // find closing (
337  p = i;
338  j = i-1;
339  do {
340  j = s.find(')', j+1);
341  if(j < 0)
342  return QString("");
343  p = s.find('(', p+1);
344  if(p >= 0 && p > j) p = -1;
345  } while (p >= 0);
346 
347  s = s.mid(i, j-i);
348  s.remove('\n');
349  s.remove('\t');
350 
351  // find port names and types in parameter specification
352  l = i = 0; // remove all VHDL identifiers (e.g. ": out bit;")
353  QString types = "", t;
354  while((i=s.find(':', i)) >= 0) {
355  j = s.find(';', i+2);
356  if(j < 0) {
357  t = s.mid(i+1);
358  t.remove(';');
359  t = t.simplifyWhiteSpace();
360  s = s.left(i);
361  } else {
362  t = s.mid(i+1, j-i);
363  t.remove(';');
364  t = t.simplifyWhiteSpace();
365  s.remove(i, j-i);
366  }
367  if ((k = t.find(' ')) >= 0)
368  t = t.mid(k+1);
369  t = t.simplifyWhiteSpace();
370  k = s.find(';',l+2);
371  k = s.mid(l,k-l).contains(',') + 1;
372  while (k-->0) types = types + t + ",";
373  i--;
374  l = i;
375  }
376 
377  s.remove(' ');
378  s.replace(';', ',');
379  TypeNames=types=types.left(types.length()-1);
380  return s;
381 }
382 
383 // -------------------------------------------------------
384 QString VHDL_File_Info::parseGenerics(QString s, int j)
385 {
386  QRegExp Expr;
387  Expr.setCaseSensitive(false);
388  int i, p, l, k, n;
389 
390  Expr.setPattern("\\bgeneric\\b");
391  i = s.find(Expr, j+1);
392  if(i < 0)
393  return QString("");
394  // find opening (
395  i = s.find('(', i+4) + 1;
396  if(i <= 0)
397  return QString("");
398 
399  // find closing (
400  p = i;
401  j = i-1;
402  do {
403  j = s.find(')', j+1);
404  if(j < 0)
405  return QString("");
406  p = s.find('(', p+1);
407  if(p >= 0 && p > j) p = -1;
408  } while (p >= 0);
409 
410  s = s.mid(i, j-i);
411  s.remove('\n');
412  s.remove('\t');
413 
414  // find generic names, types and defaults in parameter specification
415  l = i = 0;
416  QString types = "", t, defs = "", d;
417  while((i=s.find(':', i)) >= 0) {
418  j = s.find(';', i+2);
419  n = s.find(":=", i+2);
420  d = "";
421  if(n >= 0 && (n < j || j < 0) ) {
422  j = s.find(';', n+2);
423  if(j < 0) {
424  d = s.mid(n+2);
425  d = d.simplifyWhiteSpace();
426  s = s.left(n);
427  } else {
428  d = s.mid(n+2, j-n-1);
429  d.remove(';');
430  d = d.simplifyWhiteSpace();
431  s.remove(n, j-n);
432  }
433  j = s.find(';', n);
434  }
435  if(j < 0) {
436  t = s.mid(i+1);
437  t.remove(';');
438  t = t.simplifyWhiteSpace();
439  s = s.left(i);
440  } else {
441  t = s.mid(i+1, j-i);
442  t.remove(';');
443  t = t.simplifyWhiteSpace();
444  s.remove(i, j-i);
445  }
446  if ((k = t.find(' ')) >= 0)
447  t = t.mid(k+1);
448  t = t.simplifyWhiteSpace();
449  k = s.find(';',l+2);
450  k = s.mid(l,k-l).contains(',') + 1;
451  while (k-->0) {
452  types = types + t + ",";
453  defs = defs + d + ",";
454  }
455  i--;
456  l = i;
457  }
458 
459  s.remove(' ');
460  s.replace(';', ',');
461  GenTypes=types=types.left(types.length()-1);
462  GenDefs=defs=defs.left(defs.length()-1);
463  return s;
464 }