1 /*
2    Copyright (C) 1999 T. Scott Dattalo
3 
4 This file is part of gpsim.
5 
6 gpsim is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 gpsim is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with gpsim; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20 
21 
22 #include <iostream>
23 #include <iomanip>
24 #include <string>
25 #include <vector>
26 
27 #include "command.h"
28 #include "cmd_stimulus.h"
29 #include "../src/pic-processor.h"
30 #include "../src/stimuli.h"
31 #include "../src/symbol.h"
32 
33 
34 static ValueStimulus *last_stimulus=0;
35 cmd_stimulus c_stimulus;
36 
37 #define ASYNCHRONOUS_STIMULUS    1
38 #define SYNCHRONOUS_STIMULUS     2
39 
40 #define  STIM_NOTHING          0
41 #define  STIM_PERIOD          (1 << 0)
42 #define  STIM_PHASE           (1 << 1)
43 #define  STIM_HIGH_TIME       (1 << 2)
44 #define  STIM_INITIAL_STATE   (1 << 3)
45 #define  STIM_START_CYCLE     (1 << 4)
46 #define  STIM_DATA            (1 << 5)
47 
48 #define  STIM_ASY             (1 << 7)
49 #define  STIM_SQW             (1 << 8)
50 #define  STIM_NAME            (1 << 9)
51 #define  STIM_TRI             (1 << 10)
52 #define  STIM_ATTRIBUTE       (1 << 11)
53 #define  STIM_ANALOG          (1 << 12)
54 #define  STIM_DIGITAL         (1 << 13)
55 #define  STIM_DUMP            (1 << 14)
56 
57 const unsigned int
58 SQW_OPTIONS = STIM_SQW | STIM_PERIOD | STIM_PHASE | STIM_HIGH_TIME | STIM_START_CYCLE;
59 const unsigned int
60 ASY_OPTIONS = STIM_ASY | STIM_PERIOD | STIM_PHASE | STIM_HIGH_TIME | STIM_START_CYCLE | STIM_DATA;
61 const unsigned int
62 TRI_OPTIONS = STIM_TRI | STIM_PERIOD | STIM_PHASE | STIM_HIGH_TIME | STIM_START_CYCLE;
63 const unsigned int
64 ATTR_OPTIONS = STIM_ATTRIBUTE | STIM_PERIOD | STIM_PHASE | STIM_HIGH_TIME | STIM_START_CYCLE | STIM_DATA;
65 
66 static cmd_options cmd_stimulus_options[] =
67 {
68   {"asy",                   STIM_ASY,           OPT_TT_SUBTYPE},
69   {"asynchronous_stimulus", STIM_ASY,           OPT_TT_SUBTYPE},
70   {"attr",                  STIM_ATTRIBUTE,     OPT_TT_SUBTYPE},
71   {"attribute_stimulus",    STIM_ATTRIBUTE,     OPT_TT_SUBTYPE},
72   {"period",                STIM_PERIOD,        OPT_TT_NUMERIC},
73   {"phase",                 STIM_PHASE,         OPT_TT_NUMERIC},
74   {"high_time",             STIM_HIGH_TIME,     OPT_TT_NUMERIC},
75   {"initial_state",         STIM_INITIAL_STATE, OPT_TT_NUMERIC},
76   {"start_cycle",           STIM_START_CYCLE,   OPT_TT_NUMERIC},
77   {"start",                 STIM_START_CYCLE,   OPT_TT_NUMERIC},
78   {"name",                  STIM_NAME,          OPT_TT_STRING},
79   {"digital",               STIM_DIGITAL,       OPT_TT_BITFLAG},
80   {"analog",                STIM_ANALOG,        OPT_TT_BITFLAG},
81   {"d",                     STIM_DUMP,          OPT_TT_BITFLAG},
82   {"dump",                  STIM_DUMP,          OPT_TT_BITFLAG},
83   {"sqw",                   STIM_SQW,           OPT_TT_SUBTYPE},
84   {"square_wave",           STIM_SQW,           OPT_TT_SUBTYPE},
85   {"tri",                   STIM_TRI,           OPT_TT_SUBTYPE},
86   {"triangle_wave",         STIM_TRI,           OPT_TT_SUBTYPE},
87 
88  { 0,0,0}
89 };
90 
91 
cmd_stimulus()92 cmd_stimulus::cmd_stimulus()
93   : command("stimulus","stim")
94 {
95 
96   brief_doc = string("Create a stimulus");
97 
98   long_doc = string ("\nstimulus [[type] options]\n"
99 		     "\tstimulus will create a signal that can be tied to a node or an\n"
100 		     "\attribute. Note that in most cases it is easier to create a\n"
101 		     "\tstimulus file then to type this by hand.\n"
102 		     "\n"
103 		     "\t  Supported stimuli:\n"
104 		     "\n"
105 		     //"\tsquare_wave | sqw  [period p] [high_time h] [phase ph] [initial_state i]\n"
106 		     //"\t  port port_name bit_pos end\n"
107 		     //"\t\t  creates a square wave with a period of \"p\" cpu cycles.\n"
108 		     //"\t\t  If the high time is specified then that's the number of cycles\n"
109 		     //"\t\t  the square wave will be high.\n"
110 		     //"\t\t  The phase is with respect to the cpu's cycle counter.\n"
111 		     //"\t\t  The \"port_name\" and \"bit_pos\" describe where the stimulus\n"
112 		     //"\t\t  will be attached.\n"
113 		     "\tasynchronous_stimulus | asy  [period p] [phase ph]  [initial_state i]\n"
114 		     "\t  { c0,e0 [,c1, e1, c2, e2, ... ,cn,en] } [name stim_name] end\n"
115 		     "\t\t  creates an asynchronous square wave with a period of \"p\" cpu\n"
116 		     "\t\t  cycles.  The phase is with respect to the cpu's cycle counter.\n"
117 		     "\t\t  The data is specified as a pair of expressions. The first expression\n"
118 		     "\t\t  is for the cycle time and the second is the data. "
119 		     "\n"
120 		     "\texamples:\n"
121 		     "\n"
122 		     //"\t  stimulus sqw period 200 high_time 20 phase 60 port portb 0 end\n"
123 		     //"\t  create a square wave stimulus that repeats every 200 cpu cycles,\n"
124 		     //"\t  is high for 20 cpu cycles (and low for 200-20=180 cycles). The\n"
125 		     //"\t  first rising edge will occur at cycle\n"
126 		     //"\t  60, the second at 260, . . . Bit 0 of portb will receive the stimulus.\n"
127 
128 		     "\t  # define a stimulus to generate two pulses every 1000 cycles\n"
129 		     "\t  \n"
130 		     "\t  stimulus asynchronous_stimulus \n"
131 		     "\t  \n"
132 		     "\t  # The initial state AND the state the stimulus is when\n"
133 		     "\t  # it rolls over\n"
134 		     "\t  \n"
135 		     "\t  initial_state 0\n"
136 		     "\t  start_cycle 0\n"
137 		     "\t  \n"
138 		     "\t  # the asynchronous stimulus will roll over in 'period'\n"
139 		     "\t  # cycles. Delete this line if you don't want a roll over.\n"
140 		     "\t  \n"
141 		     "\t  period 1000\n"
142 		     "\t  \n"
143 		     "\t  { 100, 1,\n"
144 		     "\t  200, 0,\n"
145 		     "\t  300, 1,\n"
146 		     "\t  400, 0\n"
147 		     "\t  }\n"
148 		     "\t  \n"
149 		     "\t  # Give the stimulus a name:\n"
150 		     "\t  \n"
151 		     "\t  name two_pulse_repeat\n"
152 		     "\t  \n"
153 		     "\t  end\n"
154 		     "\n");
155 
156   op = cmd_stimulus_options;
157 
158   options_entered = 0;
159 
160 }
161 
162 static string table_name;
163 
dumpStimulus(const SymbolEntry_t & sym)164 void dumpStimulus(const SymbolEntry_t &sym)
165 {
166   stimulus *ps = dynamic_cast<stimulus *>(sym.second);
167 
168   if (ps) {
169     cout << table_name << ".";
170     cout << ps->name();
171     ps->show();
172     cout << endl;
173   }
174 }
175 
dumpStimuli(const SymbolTableEntry_t & st)176 void dumpStimuli(const SymbolTableEntry_t &st)
177 {
178   cout << " Symbol Table: " << st.first << endl;
179    table_name = st.first;
180   (st.second)->ForEachSymbolTable(dumpStimulus);
181 }
182 
stimulus()183 void cmd_stimulus::stimulus()
184 {
185   cout << "\nSymbol table\n";
186   globalSymbolTable().ForEachModule(dumpStimuli);
187 }
188 
189 //------------------------------------------------------------------
190 // stimulus(int bit_flag)
191 //
192 // For the bit_flags of SQW, ASY, TRI:
193 //   A new stimulus is dynamically created and a pointer to it is
194 // is assigned to 'last_stimulus'. The last_stimulus also acts like
195 // a flag. If it is non-null then a stimulus is in the process of
196 // being created. When the stimulus 'end' option is specified at the
197 // cli, then 'last_stimulus' is set to NULL. Note the memory for
198 // used by the last stimulus is created here, but destroyed by the
199 // stimulus code in ../src/stimuli.cc .
200 //
stimulus(int bit_flag)201 void cmd_stimulus::stimulus(int bit_flag)
202 {
203 
204   switch(bit_flag)
205     {
206     case STIM_SQW:
207       if(verbose)
208 	cout << "creating sqw stimulus\n";
209       if(!last_stimulus) {
210 	//create_stimulus(NEW_SQW,stim_name);
211 	valid_options = SQW_OPTIONS;
212 	options_entered = STIM_SQW;
213 	//last_stimulus = new square_wave;
214       } else
215 	cout << "warning: ignoring sqw stim creation";
216       break;
217 
218     case STIM_ASY:
219       if(verbose)
220 	cout << "creating asy stimulus\n";
221 
222       if(!last_stimulus) {
223 	//create_stimulus(NEW_ASY,stim_name);
224 	last_stimulus = new ValueStimulus;
225 	valid_options = ASY_OPTIONS;
226 	options_entered = STIM_ASY;
227       }else
228 	cout << "warning: ignoring asy stim creation";
229       break;
230 
231     case STIM_ATTRIBUTE:
232       if(verbose)
233 	cout << "creating asy stimulus\n";
234 
235       if(!last_stimulus) {
236 	last_stimulus = new AttributeStimulus;
237 	valid_options = ATTR_OPTIONS;
238 	options_entered = STIM_ATTRIBUTE;
239       }else
240 	cout << "warning: ignoring asy stim creation";
241       break;
242 
243     case STIM_TRI:
244       if(verbose)
245 	cout << "creating tri stimulus\n";
246 
247       if(!last_stimulus) {
248 	//create_stimulus(NEW_TRI,stim_name);
249 	//last_stimulus = new triangle_wave;
250 	valid_options = TRI_OPTIONS;
251 	options_entered = STIM_TRI;
252       } else
253 	cout << "warning: ignoring tri stim creation";
254       break;
255 
256     case STIM_DUMP:
257       stimulus();      // Display the list of stimuli.
258       return;
259 
260     case STIM_DIGITAL:
261       if(last_stimulus)
262         last_stimulus->set_digital();
263       return;
264 
265     case STIM_ANALOG:
266       if(last_stimulus)
267         last_stimulus->set_analog();
268       return;
269 
270     default:
271       cout << " Invalid stimulus option\n";
272       return;
273     }
274 
275 }
276 
277 
stimulus(cmd_options_expr * coe)278 void cmd_stimulus::stimulus(cmd_options_expr *coe)
279 {
280   /*
281   double dvalue = 0.0;
282   if(coe->expr)
283     dvalue = evaluate(coe->expr);
284 
285   int value = (int) dvalue;
286   */
287 
288   if (!coe || !coe->expr)
289     return;
290 
291   Value *value = toValue(coe->expr);
292 
293   switch(coe->co->value)
294     {
295     case STIM_PHASE:
296       if(verbose)
297 	cout << "stimulus command got the phase " << value << '\n';
298 
299       if(last_stimulus)
300 	last_stimulus->put_phase(value);
301 
302       break;
303 
304     case STIM_PERIOD:
305       if(verbose)
306 	cout << "stimulus command got the period " << value << '\n';
307 
308       if(last_stimulus)
309 	last_stimulus->put_period(value);
310 
311       break;
312 
313     case STIM_HIGH_TIME:
314       if(verbose)
315 	cout << "stimulus command got the high_time " << value << '\n';
316 
317       if(last_stimulus)
318 	last_stimulus->put_duty(value);
319 
320       break;
321 
322     case STIM_INITIAL_STATE:
323       if(verbose)
324 	cout << "stimulus command got the initial_state " << value << '\n';
325 
326       if(last_stimulus)
327 	last_stimulus->put_initial_state(value);
328 
329       break;
330 
331     case STIM_START_CYCLE:
332       if(verbose)
333 	cout << "stimulus command got the start_cycle " << value << '\n';
334 
335       if(last_stimulus)
336 	last_stimulus->put_start_cycle(value);
337 
338       break;
339 
340     default:
341       cout << " Invalid stimulus option\n";
342       return;
343     }
344 
345   options_entered |= coe->co->value;
346   delete coe->expr;
347   delete value;
348 
349 }
350 
351 
stimulus(cmd_options_str * cos)352 void cmd_stimulus::stimulus(cmd_options_str *cos)
353 {
354 
355   if(!last_stimulus) {
356     cout << "warning: Ignoring stimulus (string) option because there's no stimulus defined.\n";
357     return;
358   }
359 
360 
361   switch(cos->co->value)
362     {
363     case STIM_NAME:
364       if(verbose)
365 	cout << "stimulus command got the name " << cos->str << '\n';
366 
367       last_stimulus->new_name(cos->str);
368 
369       break;
370     }
371 
372   options_entered |= cos->co->value;
373 }
374 
stimulus(ExprList_t * eList)375 void cmd_stimulus::stimulus(ExprList_t *eList)
376 {
377   ExprList_itor ei;
378 
379   bool bHaveSample=false;
380   ValueStimulusData sample;
381   sample.time = 0;
382   sample.v = 0;
383 
384   if(last_stimulus) {
385     for(ei = eList->begin(); ei != eList->end(); ++ei) {
386 
387 
388 
389       try {
390 
391 	Value *v = (*ei)->evaluate();
392 
393 	if(!bHaveSample) {
394 	  v->get(sample.time);
395 	  delete v;
396 	  bHaveSample = true;
397 	} else {
398 	  sample.v = v;
399 	  last_stimulus->put_data(sample);
400 	  bHaveSample = false;
401 	  have_data = 1;
402 	}
403 
404       }
405 
406       catch (Error &err) {
407         std::cout << "ERROR:" << err.what() << '\n';
408       }
409 
410     }
411 
412   }
413 
414   eList->clear();
415   delete eList;
416 }
417 
418 //-----------------
419 // end()
420 // All of the stimulus' options have been entered. Now it's time
421 // to create the stimulus.
422 
end()423 void cmd_stimulus::end()
424 {
425   if(!last_stimulus) {
426     cout << "warning: Ignoring stimulus (string) option because there's no stimulus defined.";
427     return;
428   }
429 
430   switch( options_entered & (STIM_SQW | STIM_TRI | STIM_ASY | STIM_ATTRIBUTE))
431     {
432     case STIM_SQW:
433       if(verbose)
434 	cout << "created sqw stimulus\n";
435       break;
436 
437     case STIM_ASY:
438       if(verbose)
439 	cout << "created asy stimulus\n";
440       last_stimulus->start();
441       break;
442 
443     case STIM_ATTRIBUTE:
444       if(verbose)
445 	cout << "created attribute stimulus\n";
446       last_stimulus->start();
447       break;
448 
449     case STIM_TRI:
450       if(verbose)
451 	cout << "creating tri stimulus\n";
452       break;
453 
454     }
455 
456   last_stimulus = 0;
457 }
458