1 /*$Id: lang_spectre.cc,v 26.137 2010/04/10 02:37:05 al Exp $ -*- C++ -*-
2  * Copyright (C) 2007 Albert Davis
3  * Author: Albert Davis <aldavis@gnu.org>
4  *
5  * This file is part of "Gnucap", the Gnu Circuit Analysis Package
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  */
22 #include "globals.h"
23 #include "c_comand.h"
24 #include "d_dot.h"
25 #include "d_coment.h"
26 #include "d_subckt.h"
27 #include "e_model.h"
28 #include "u_lang.h"
29 /*--------------------------------------------------------------------------*/
30 namespace {
31 /*--------------------------------------------------------------------------*/
32 class LANG_SPECTRE : public LANGUAGE {
33 public:
~LANG_SPECTRE()34   ~LANG_SPECTRE() {itested();}
name() const35   std::string name()const {return "spectre";}
case_insensitive() const36   bool case_insensitive()const {return false;}
units() const37   UNITS units()const {return uSI;}
38 
39 public: // override virtual, used by callback
arg_front() const40   std::string arg_front()const {return " ";}
arg_mid() const41   std::string arg_mid()const {return "=";}
arg_back() const42   std::string arg_back()const {return "";}
43 
44 public: // override virtual, called by commands
45   void		parse_top_item(CS&, CARD_LIST*);
46   DEV_COMMENT*	parse_comment(CS&, DEV_COMMENT*);
47   DEV_DOT*	parse_command(CS&, DEV_DOT*);
48   MODEL_CARD*	parse_paramset(CS&, MODEL_CARD*);
49   MODEL_SUBCKT* parse_module(CS&, MODEL_SUBCKT*);
50   COMPONENT*	parse_instance(CS&, COMPONENT*);
51   std::string	find_type_in_string(CS&);
52 
53 private: // override virtual, called by print_item
54   void print_paramset(OMSTREAM&, const MODEL_CARD*);
55   void print_module(OMSTREAM&, const MODEL_SUBCKT*);
56   void print_instance(OMSTREAM&, const COMPONENT*);
57   void print_comment(OMSTREAM&, const DEV_COMMENT*);
58   void print_command(OMSTREAM& o, const DEV_DOT* c);
59 private: // local
60   void print_args(OMSTREAM&, const CARD*);
61 } lang_spectre;
62 
63 DISPATCHER<LANGUAGE>::INSTALL
64 	d(&language_dispatcher, lang_spectre.name(), &lang_spectre);
65 /*--------------------------------------------------------------------------*/
66 /*--------------------------------------------------------------------------*/
parse_type(CS & cmd,CARD * x)67 static void parse_type(CS& cmd, CARD* x)
68 {
69   assert(x);
70   std::string new_type;
71   cmd >> new_type;
72   x->set_dev_type(new_type);
73 }
74 /*--------------------------------------------------------------------------*/
parse_args(CS & cmd,CARD * x)75 static void parse_args(CS& cmd, CARD* x)
76 {
77   assert(x);
78 
79   unsigned here = 0;
80   while (cmd.more() && !cmd.stuck(&here)) {
81     std::string name  = cmd.ctos("=", "", "");
82     cmd >> '=';
83     std::string value = cmd.ctos("", "(", ")");
84     try{
85       x->set_param_by_name(name, value);
86     }catch (Exception_No_Match&) {untested();
87       cmd.warn(bDANGER, here, x->long_label() + ": bad parameter " + name + " ignored");
88     }
89   }
90 }
91 /*--------------------------------------------------------------------------*/
parse_label(CS & cmd,CARD * x)92 static void parse_label(CS& cmd, CARD* x)
93 {
94   assert(x);
95   std::string my_name;
96   cmd >> my_name;
97   x->set_label(my_name);
98 }
99 /*--------------------------------------------------------------------------*/
parse_ports(CS & cmd,COMPONENT * x)100 static void parse_ports(CS& cmd, COMPONENT* x)
101 {
102   assert(x);
103 
104   if (cmd >> '(') {
105     int index = 0;
106     while (cmd.is_alnum()) {
107       unsigned here = cmd.cursor();
108       try{
109 	std::string value;
110 	cmd >> value;
111 	x->set_port_by_index(index++, value);
112       }catch (Exception_Too_Many& e) {untested();
113 	cmd.warn(bDANGER, here, e.message());
114       }
115     }
116     cmd >> ')';
117   }else{
118     unsigned here = cmd.cursor();
119     OPT::language->find_type_in_string(cmd);
120     unsigned stop = cmd.cursor();
121     cmd.reset(here);
122 
123     int index = 0;
124     while (cmd.cursor() < stop) {
125       here = cmd.cursor();
126       try{
127 	std::string value;
128 	cmd >> value;
129 	x->set_port_by_index(index++, value);
130       }catch (Exception_Too_Many& e) {untested();
131 	cmd.warn(bDANGER, here, e.message());
132       }
133     }
134   }
135 }
136 /*--------------------------------------------------------------------------*/
137 /*--------------------------------------------------------------------------*/
parse_comment(CS & cmd,DEV_COMMENT * x)138 DEV_COMMENT* LANG_SPECTRE::parse_comment(CS& cmd, DEV_COMMENT* x)
139 {
140   assert(x);
141   x->set(cmd.fullstring());
142   return x;
143 }
144 /*--------------------------------------------------------------------------*/
parse_command(CS & cmd,DEV_DOT * x)145 DEV_DOT* LANG_SPECTRE::parse_command(CS& cmd, DEV_DOT* x)
146 {
147   assert(x);
148   x->set(cmd.fullstring());
149   CARD_LIST* scope = (x->owner()) ? x->owner()->subckt() : &CARD_LIST::card_list;
150 
151   cmd.reset().skipbl();
152   if ((cmd >> "model |simulator |parameters |subckt ")) {
153     cmd.reset();
154     CMD::cmdproc(cmd, scope);
155   }else{
156     std::string label;
157     cmd >> label;
158 
159     if (label != "-") {
160       unsigned here = cmd.cursor();
161       std::string command;
162       cmd >> command;
163       cmd.reset(here);
164       std::string file_name = label + '.' + command;
165       std::string s = cmd.tail() + " > " + file_name;
166       CS augmented_cmd(CS::_STRING, s);
167       CMD::cmdproc(augmented_cmd, scope);
168     }else{
169       CMD::cmdproc(cmd, scope);
170     }
171   }
172   delete x;
173   return NULL;
174 }
175 /*--------------------------------------------------------------------------*/
parse_paramset(CS & cmd,MODEL_CARD * x)176 MODEL_CARD* LANG_SPECTRE::parse_paramset(CS& cmd, MODEL_CARD* x)
177 {
178   assert(x);
179   cmd.reset().skipbl();
180   cmd >> "model ";
181   parse_label(cmd, x);
182   parse_type(cmd, x);
183   parse_args(cmd, x);
184   cmd.check(bWARNING, "what's this?");
185   return x;
186 }
187 /*--------------------------------------------------------------------------*/
parse_module(CS & cmd,MODEL_SUBCKT * x)188 MODEL_SUBCKT* LANG_SPECTRE::parse_module(CS& cmd, MODEL_SUBCKT* x)
189 {
190   assert(x);
191 
192   // header
193   cmd.reset().skipbl();
194   cmd >> "subckt ";
195   parse_label(cmd, x);
196   parse_ports(cmd, x);
197 
198   // body
199   for (;;) {
200     cmd.get_line("spectre-subckt>");
201 
202     if (cmd >> "ends ") {
203       break;
204     }else{
205       new__instance(cmd, x, x->subckt());
206     }
207   }
208   return x;
209 }
210 /*--------------------------------------------------------------------------*/
parse_instance(CS & cmd,COMPONENT * x)211 COMPONENT* LANG_SPECTRE::parse_instance(CS& cmd, COMPONENT* x)
212 {
213   cmd.reset();
214   parse_label(cmd, x);
215   parse_ports(cmd, x);
216   parse_type(cmd, x);
217   parse_args(cmd, x);
218   cmd.check(bWARNING, "what's this?");
219   return x;
220 }
221 /*--------------------------------------------------------------------------*/
find_type_in_string(CS & cmd)222 std::string LANG_SPECTRE::find_type_in_string(CS& cmd)
223 {
224   // known to be not always correct
225 
226   cmd.reset().skipbl();
227   unsigned here = 0;
228   std::string type;
229   if ((cmd >> "*|//")) {itested();
230     assert(here == 0);
231     type = "dev_comment";
232   }else if ((cmd >> "model |simulator |parameters |subckt ")) {
233     // type is first, it's a control statement
234     type = cmd.trimmed_last_match();
235   }else if (cmd.reset().skiparg().match1("(") && cmd.scan(")")) {
236     // node list surrounded by parens
237     // type follows
238     here = cmd.cursor();
239     cmd.reset(here);
240     cmd >> type;
241   }else if (cmd.reset().scan("=")) {itested();
242     // back up two, by starting over
243     cmd.reset().skiparg();
244     unsigned here1 = cmd.cursor();
245     cmd.skiparg();
246     unsigned here2 = cmd.cursor();
247     cmd.skiparg();
248     unsigned here3 = cmd.cursor();
249     while (here2 != here3 && !cmd.match1('=')) {
250       cmd.skiparg();
251       here1 = here2;
252       here2 = here3;
253       here3 = cmd.cursor();
254     }
255     here = here1;
256     cmd.reset(here);
257     cmd >> type;
258   }else{
259     // type is second
260     cmd.reset().skiparg();
261     here = cmd.cursor();
262     cmd.reset(here);
263     cmd >> type;
264   }
265   cmd.reset(here);
266   return type;
267 }
268 /*--------------------------------------------------------------------------*/
parse_top_item(CS & cmd,CARD_LIST * Scope)269 void LANG_SPECTRE::parse_top_item(CS& cmd, CARD_LIST* Scope)
270 {
271   cmd.get_line("gnucap-spectre>");
272   new__instance(cmd, NULL, Scope);
273 }
274 /*--------------------------------------------------------------------------*/
275 /*--------------------------------------------------------------------------*/
print_args(OMSTREAM & o,const CARD * x)276 void LANG_SPECTRE::print_args(OMSTREAM& o, const CARD* x)
277 {
278   assert(x);
279   o << ' ';
280   if (x->use_obsolete_callback_print()) {
281     x->print_args_obsolete_callback(o, this);  //BUG//callback//
282   }else{
283     for (int ii = x->param_count() - 1;  ii >= 0;  --ii) {
284       if (x->param_is_printable(ii)) {
285 	std::string arg = " " + x->param_name(ii) + "=" + x->param_value(ii);
286 	o << arg;
287       }else{
288       }
289     }
290   }
291 }
292 /*--------------------------------------------------------------------------*/
print_type(OMSTREAM & o,const COMPONENT * x)293 static void print_type(OMSTREAM& o, const COMPONENT* x)
294 {
295   assert(x);
296   o << ' ' << x->dev_type();
297 }
298 /*--------------------------------------------------------------------------*/
print_label(OMSTREAM & o,const COMPONENT * x)299 static void print_label(OMSTREAM& o, const COMPONENT* x)
300 {
301   assert(x);
302   o << x->short_label();
303 }
304 /*--------------------------------------------------------------------------*/
print_ports(OMSTREAM & o,const COMPONENT * x)305 static void print_ports(OMSTREAM& o, const COMPONENT* x)
306 {
307   assert(x);
308 
309   o << " (";
310   std::string sep = "";
311   for (int ii = 0;  x->port_exists(ii);  ++ii) {
312     o << sep << x->port_value(ii);
313     sep = " ";
314   }
315   for (int ii = 0;  x->current_port_exists(ii);  ++ii) {
316     o << sep << x->current_port_value(ii);
317     sep = " ";
318   }
319   o << ")";
320 }
321 /*--------------------------------------------------------------------------*/
322 /*--------------------------------------------------------------------------*/
print_paramset(OMSTREAM & o,const MODEL_CARD * x)323 void LANG_SPECTRE::print_paramset(OMSTREAM& o, const MODEL_CARD* x)
324 {
325   assert(x);
326   o << "model " << x->short_label() << ' ' << x->dev_type() << ' ';
327   print_args(o, x);
328   o << "\n\n";
329 }
330 /*--------------------------------------------------------------------------*/
print_module(OMSTREAM & o,const MODEL_SUBCKT * x)331 void LANG_SPECTRE::print_module(OMSTREAM& o, const MODEL_SUBCKT* x)
332 {
333   assert(x);
334   assert(x->subckt());
335 
336   o << "subckt " <<  x->short_label();
337   print_ports(o, x);
338   o << "\n";
339 
340   for (CARD_LIST::const_iterator
341 	 ci = x->subckt()->begin(); ci != x->subckt()->end(); ++ci) {
342     print_item(o, *ci);
343   }
344 
345   o << "ends " << x->short_label() << "\n\n";
346 }
347 /*--------------------------------------------------------------------------*/
print_instance(OMSTREAM & o,const COMPONENT * x)348 void LANG_SPECTRE::print_instance(OMSTREAM& o, const COMPONENT* x)
349 {
350   print_label(o, x);
351   print_ports(o, x);
352   print_type(o, x);
353   print_args(o, x);
354   o << "\n";
355 }
356 /*--------------------------------------------------------------------------*/
print_comment(OMSTREAM & o,const DEV_COMMENT * x)357 void LANG_SPECTRE::print_comment(OMSTREAM& o, const DEV_COMMENT* x)
358 {
359   assert(x);
360   o << x->comment() << '\n';
361 }
362 /*--------------------------------------------------------------------------*/
print_command(OMSTREAM & o,const DEV_DOT * x)363 void LANG_SPECTRE::print_command(OMSTREAM& o, const DEV_DOT* x)
364 {
365   assert(x);
366   o << x->s() << '\n';
367 }
368 /*--------------------------------------------------------------------------*/
369 /*--------------------------------------------------------------------------*/
370 class CMD_MODEL : public CMD {
do_it(CS & cmd,CARD_LIST * Scope)371   void do_it(CS& cmd, CARD_LIST* Scope)
372   {
373     // already got "model"
374     std::string my_name, base_name;
375     cmd >> my_name;
376     unsigned here = cmd.cursor();
377     cmd >> base_name;
378 
379     //const MODEL_CARD* p = model_dispatcher[base_name];
380     const CARD* p = lang_spectre.find_proto(base_name, NULL);
381     if (p) {
382       MODEL_CARD* new_card = dynamic_cast<MODEL_CARD*>(p->clone());
383       if (exists(new_card)) {
384 	assert(!new_card->owner());
385 	lang_spectre.parse_paramset(cmd, new_card);
386 	Scope->push_back(new_card);
387       }else{	//BUG// memory leak
388 	cmd.warn(bDANGER, here, "model: base has incorrect type");
389       }
390     }else{
391       cmd.warn(bDANGER, here, "model: no match");
392     }
393   }
394 } p1;
395 DISPATCHER<CMD>::INSTALL d1(&command_dispatcher, "model", &p1);
396 /*--------------------------------------------------------------------------*/
397 class CMD_SUBCKT : public CMD {
do_it(CS & cmd,CARD_LIST * Scope)398   void do_it(CS& cmd, CARD_LIST* Scope)
399   {
400     MODEL_SUBCKT* new_module = new MODEL_SUBCKT;
401     assert(new_module);
402     assert(!new_module->owner());
403     assert(new_module->subckt());
404     assert(new_module->subckt()->is_empty());
405     lang_spectre.parse_module(cmd, new_module);
406     Scope->push_back(new_module);
407   }
408 } p2;
409 DISPATCHER<CMD>::INSTALL d2(&command_dispatcher, "subckt", &p2);
410 /*--------------------------------------------------------------------------*/
411 class CMD_SIMULATOR : public CMD {
do_it(CS & cmd,CARD_LIST * Scope)412   void do_it(CS& cmd, CARD_LIST* Scope)
413   {
414     command("options " + cmd.tail(), Scope);
415   }
416 } p3;
417 DISPATCHER<CMD>::INSTALL d3(&command_dispatcher, "simulator", &p3);
418 /*--------------------------------------------------------------------------*/
419 class CMD_SPECTRE : public CMD {
420 public:
do_it(CS &,CARD_LIST * Scope)421   void do_it(CS&, CARD_LIST* Scope)
422   {
423     command("options lang=spectre", Scope);
424   }
425 } p8;
426 DISPATCHER<CMD>::INSTALL d8(&command_dispatcher, "spectre", &p8);
427 /*--------------------------------------------------------------------------*/
428 }
429 /*--------------------------------------------------------------------------*/
430 /*--------------------------------------------------------------------------*/
431