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