* sim/ucsim/configure, sim/ucsim/cmd.src/newcmdcl.h,
[fw/sdcc] / sim / ucsim / app.cc
1 /*
2  * Simulator of microcontrollers (app.cc)
3  *
4  * Copyright (C) 2001,01 Drotos Daniel, Talker Bt.
5  * 
6  * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
7  *
8  */
9
10 /* This file is part of microcontroller simulator: ucsim.
11
12 UCSIM is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 UCSIM is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with UCSIM; see the file COPYING.  If not, write to the Free
24 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 02111-1307, USA. */
26 /*@1@*/
27
28 #include "ddconfig.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #ifdef HAVE_GETOPT_H
37 # include <getopt.h>
38 #endif
39 #ifdef SOCKET_AVAIL
40 # include HEADER_SOCKET
41 #endif
42 #include <ctype.h>
43 #include <errno.h>
44 #include "i_string.h"
45
46 // prj
47 #include "utils.h"
48 #include "appcl.h"
49 #include "optioncl.h"
50 #include "globals.h"
51
52 // sim.src
53 #include "simcl.h"
54
55 // cmd.src
56 #include "cmdsetcl.h"
57 #include "cmdutil.h"
58 #include "cmdconfcl.h"
59 #include "showcl.h"
60 #include "getcl.h"
61 #include "setcl.h"
62
63
64 /*
65  * Program options
66  */
67
68 /*cl_option::cl_option(int atype, char sn, char *ln)
69 {
70   type= atype;
71   short_name= sn;
72   if (!ln)
73     long_name= NULL;
74   else
75     long_name= strdup(ln);
76   values= new cl_ustrings(1, 1);
77 }
78
79 cl_option::~cl_option(void)
80 {
81   if (long_name)
82     free(long_name);
83   delete values;
84 }
85
86 int
87 cl_option::add_value(char *value)
88 {
89   values->add(value);
90   return(values->count - 1);
91 }
92
93 char *
94 cl_option::get_value(int index)
95 {
96   if (index > values->count - 1)
97     return(0);
98   return((char*)(values->at(index)));
99 }*/
100
101 /* List of options */
102
103 /*cl_options::cl_options(void):
104   cl_list(2, 2)
105 {
106 }*/
107
108
109 /*
110  * Application
111  ****************************************************************************
112  */
113
114 cl_app::cl_app(void)
115 {
116   sim= 0;
117   in_files= new cl_ustrings(2, 2, "input files");
118   options= new cl_options();
119   going= 1;
120 }
121
122 cl_app::~cl_app(void)
123 {
124   remove_simulator();
125   delete commander;
126   delete in_files;
127   delete options;
128 }
129
130 int
131 cl_app::init(int argc, char *argv[])
132 {
133   cl_base::init();
134   set_name("application");
135   mk_options();
136   proc_arguments(argc, argv);
137   class cl_cmdset *cmdset= new cl_cmdset();
138   cmdset->init();
139   build_cmdset(cmdset);
140   commander= new cl_commander(this, cmdset/*, sim*/);
141   commander->init();
142   return(0);
143 }
144
145 /* Main cycle */
146
147 int
148 cl_app::run(void)
149 {
150   int done= 0;
151
152   while (!done &&
153          going)
154     {
155       if (sim)
156         {
157           if (sim->state & SIM_GO)
158             {
159               if (commander->input_avail())
160                 done= commander->proc_input();
161               else
162                 sim->step();
163             }
164           else
165             {
166               commander->wait_input();
167               done= commander->proc_input();
168             }
169         }
170       else
171         {
172           commander->wait_input();
173           done= commander->proc_input();
174         }
175     }
176   return(0);
177 }
178
179 void
180 cl_app::done(void)
181 {
182 }
183
184
185 /*
186  * Interpretation of parameters
187  */
188
189 static void
190 print_help(char *name)
191 {
192   printf("%s: %s\n", name, VERSIONSTR);
193   printf("Usage: %s [-hHVvP] [-p prompt] [-t CPU] [-X freq[k|M]]\n"
194          "       [-c file] [-s file] [-S optionlist]"
195 #ifdef SOCKET_AVAIL
196          " [-Z portnum] [-k portnum]"
197 #endif
198          "\n"
199          "       [files...]\n", name);
200   printf
201     (
202      "Options:\n"
203      "  -t CPU       Type of CPU: 51, C52, 251, etc.\n"
204      "  -X freq[k|M] XTAL frequency\n"
205      "  -c file      Open command console on `file'\n"
206 #ifdef SOCKET_AVAIL
207      "  -Z portnum   Use localhost:portnumber for command console\n"
208      "  -k portnum   Use localhost:portnum for serial I/O\n"
209 #endif
210      "  -s file      Connect serial interface to `file'\n"
211      "  -S options   `options' is a comma separated list of options according to\n"
212      "               serial interface. Know options are:\n"
213      "                  in=file   serial input will be read from file named `file'\n"
214      "                  out=file  serial output will be written to `file'\n"
215      "  -p prompt    Specify string for prompt\n"
216      "  -P           Prompt is a null ('\\0') character\n"
217      "  -V           Verbose mode\n"
218      "  -v           Print out version number\n"
219      "  -H           Print out types of known CPUs\n"
220      "  -h           Print out this help\n"
221      );
222 }
223
224 enum {
225   SOPT_IN= 0,
226   SOPT_OUT
227 };
228
229 static const char *S_opts[]= {
230   /*[SOPT_IN]=*/ "in",
231   /*[SOPT_OUT]=*/ "out",
232   NULL
233 };
234
235 int
236 cl_app::proc_arguments(int argc, char *argv[])
237 {
238   int i, c;
239   char opts[100], *cp, *subopts, *value;
240   char *cpu_type= NULL;
241   bool s_done= DD_FALSE, k_done= DD_FALSE;
242   bool S_i_done= DD_FALSE, S_o_done= DD_FALSE;
243
244   strcpy(opts, "c:C:p:PX:vVt:s:S:hHk:");
245 #ifdef SOCKET_AVAIL
246   strcat(opts, "Z:r:");
247 #endif
248
249   while((c= getopt(argc, argv, opts)) != -1)
250     switch (c)
251       {
252       case 'c':
253         if (!options->set_value("console_on", this, optarg))
254           fprintf(stderr, "Warning: No \"console_on\" option found "
255                   "to set by -c\n");
256         break;
257       case 'C':
258         if (!options->set_value("config_file", this, optarg))
259           fprintf(stderr, "Warning: No \"config_file\" option found to set "
260                   "parameter of -C as config file\n");
261         break;
262 #ifdef SOCKET_AVAIL
263       case 'Z': case 'r':
264         {
265           // By Sandeep
266           // Modified by DD
267           class cl_option *o;
268           options->new_option(o= new cl_number_option(this, "port_number",
269                                                       "Listen on port (-Z)"));
270           o->init();
271           o->hide();
272           if (!options->set_value("port_number", this, strtol(optarg, NULL, 0)))
273             fprintf(stderr, "Warning: No \"port_number\" option found"
274                     " to set parameter of -Z as pot number to listen on\n");
275           break;
276         }
277 #endif
278       case 'p': {
279         if (!options->set_value("prompt", this, optarg))
280           fprintf(stderr, "Warning: No \"prompt\" option found to set "
281                   "parameter of -p as default prompt\n");
282         break;
283       }
284       case 'P':
285         if (!options->set_value("null_prompt", this, bool(DD_TRUE)))
286           fprintf(stderr, "Warning: No \"null_prompt\" option found\n");
287         break;
288       case 'X':
289         {
290           double XTAL;
291           for (cp= optarg; *cp; *cp= toupper(*cp), cp++);
292           XTAL= strtod(optarg, &cp);
293           if (*cp == 'K')
294             XTAL*= 1e3;
295           if (*cp == 'M')
296             XTAL*= 1e6;
297           if (XTAL == 0)
298             {
299               fprintf(stderr, "Xtal frequency must be greather than 0\n");
300               exit(1);
301             }
302           if (!options->set_value("xtal", this, XTAL))
303             fprintf(stderr, "Warning: No \"xtal\" option found to set "
304                     "parameter of -X as XTAL frequency\n");
305           break;
306         }
307       case 'v':
308         printf("%s: %s\n", argv[0], VERSIONSTR);
309         exit(0);
310         break;
311       case 'V':
312         if (!options->set_value("debug", this, (bool)DD_TRUE))
313           fprintf(stderr, "Warning: No \"debug\" option found to set "
314                   "by -V parameter\n"); 
315         break;
316       case 't':
317         {
318           if (cpu_type)
319             free(cpu_type);
320           cpu_type= case_string(case_upper, optarg);
321           if (!options->set_value("cpu_type", this, /*optarg*/cpu_type))
322             fprintf(stderr, "Warning: No \"cpu_type\" option found to set "
323                     "parameter of -t as type of controller\n"); 
324           break;
325         }
326       case 's':
327       {
328         FILE *Ser_in, *Ser_out;
329         if (s_done)
330           {
331             fprintf(stderr, "-s option can not be used more than once.\n");
332             break;
333           }
334         s_done= DD_TRUE;
335         if ((Ser_in= fopen(optarg, "r")) == NULL)
336           {
337             fprintf(stderr,
338                     "Can't open `%s': %s\n", optarg, strerror(errno));
339             return(4);
340           }
341         if (!options->set_value("serial_in_file", this, (void*)Ser_in))
342           fprintf(stderr, "Warning: No \"serial_in_file\" option found to set "
343                   "parameter of -s as serial input file\n");
344         if ((Ser_out= fopen(optarg, "w")) == NULL)
345           {
346             fprintf(stderr,
347                     "Can't open `%s': %s\n", optarg, strerror(errno));
348             return(4);
349           }
350         if (!options->set_value("serial_out_file", this, Ser_out))
351           fprintf(stderr, "Warning: No \"serial_out_file\" option found "
352                   "to set parameter of -s as serial output file\n");
353         break;
354       }
355 #ifdef SOCKET_AVAIL
356       // socket serial I/O by Alexandre Frey <Alexandre.Frey@trusted-logic.fr>
357       case 'k':
358         {
359           FILE *Ser_in, *Ser_out;
360           int  sock;
361           unsigned short serverport;
362           int client_sock;
363           
364           if (k_done) {
365             fprintf(stderr, "Serial input specified more than once.\n");
366           }
367           k_done= DD_TRUE;
368
369           serverport = atoi(optarg);
370           sock= make_server_socket(serverport);
371           if (listen(sock, 1) < 0) {
372             fprintf(stderr, "Listen on port %d: %s\n", serverport,
373                     strerror(errno));
374             return (4);
375           }
376           fprintf(stderr, "Listening on port %d for a serial connection.\n",
377                   serverport);
378           if ((client_sock= accept(sock, NULL, NULL)) < 0) {
379             fprintf(stderr, "accept: %s\n", strerror(errno));
380           }
381           fprintf(stderr, "Serial connection established.\n");
382
383           if ((Ser_in= fdopen(client_sock, "r")) == NULL) {
384             fprintf(stderr, "Can't create input stream: %s\n", strerror(errno));
385             return (4);
386           }
387           if (!options->set_value("serial_in_file", this, (void*)Ser_in))
388             fprintf(stderr, "Warning: No \"serial_in_file\" option found to "
389                     "set parameter of -s as serial input file\n");
390           if ((Ser_out= fdopen(client_sock, "w")) == NULL) {
391             fprintf(stderr, "Can't create output stream: %s\n", strerror(errno));
392             return (4);
393           }
394           if (!options->set_value("serial_out_file", this, Ser_out))
395             fprintf(stderr, "Warning: No \"serial_out_file\" option found "
396                     "to set parameter of -s as serial output file\n");
397           break;
398         }
399 #endif
400       case 'S':
401         subopts= optarg;
402         while (*subopts != '\0')
403           switch (get_sub_opt(&subopts, S_opts, &value))
404             {
405               FILE *Ser_in, *Ser_out;
406             case SOPT_IN:
407               if (value == NULL) {
408                 fprintf(stderr, "No value for -S in\n");
409                 exit(1);
410               }
411               if (S_i_done)
412                 {
413                   fprintf(stderr, "Serial input specified more than once.\n");
414                   break;
415                 }
416               S_i_done= DD_TRUE;
417               if ((Ser_in= fopen(value, "r")) == NULL)
418                 {
419                   fprintf(stderr,
420                           "Can't open `%s': %s\n", value, strerror(errno));
421                   exit(4);
422                 }
423               if (!options->set_value("serial_in_file", this, (void*)Ser_in))
424                 fprintf(stderr, "Warning: No \"serial_in_file\" option found "
425                         "to set parameter of -s as serial input file\n");
426               break;
427             case SOPT_OUT:
428               if (value == NULL) {
429                 fprintf(stderr, "No value for -S out\n");
430                 exit(1);
431               }
432               if (S_o_done)
433                 {
434                   fprintf(stderr, "Serial output specified more than once.\n");
435                   break;
436                 }
437               if ((Ser_out= fopen(value, "w")) == NULL)
438                 {
439                   fprintf(stderr,
440                           "Can't open `%s': %s\n", value, strerror(errno));
441                   exit(4);
442                 }
443               if (!options->set_value("serial_out_file", this, Ser_out))
444                 fprintf(stderr, "Warning: No \"serial_out_file\" option found "
445                         "to set parameter of -s as serial output file\n");
446               break;
447             default:
448               /* Unknown suboption. */
449               fprintf(stderr, "Unknown suboption `%s' for -S\n", value);
450               exit(1);
451               break;
452             }
453         break;
454       case 'h':
455         print_help("s51");
456         exit(0);
457         break;
458       case 'H':
459         {
460           if (!cpus)
461             {
462               fprintf(stderr, "CPU type is not selectable\n");
463               exit(0);
464             }
465           i= 0;
466           while (cpus[i].type_str != NULL)
467             {
468               printf("%s\n", cpus[i].type_str);
469               i++;
470             }
471           exit(0);
472           break;
473         }
474       case '?':
475         if (isprint(optopt))
476           fprintf(stderr, "Unknown option `-%c'.\n", optopt);
477         else
478           fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
479         return(1);
480         break;
481       default:
482         exit(c);
483       }
484
485   for (i= optind; i < argc; i++)
486     in_files->add(argv[i]);
487
488   return(0);
489 }
490
491
492 class cl_uc *
493 cl_app::get_uc(void)
494 {
495   if (!sim)
496     return(0);
497   return(sim->get_uc());
498 }
499
500
501 /* Command handling */
502
503 class cl_cmd *
504 cl_app::get_cmd(class cl_cmdline *cmdline)
505 {
506   return(0);
507 }
508
509
510 /*
511  * Messages to broadcast
512  */
513
514 /*
515 void
516 cl_app::mem_cell_changed(class cl_m *mem, t_addr addr)
517 {
518   if (sim)
519     sim->mem_cell_changed(mem, addr);
520 }
521 */
522
523
524 /* Adding and removing components */
525
526 void
527 cl_app::set_simulator(class cl_sim *simulator)
528 {
529   if (sim)
530     remove_simulator();
531   sim= simulator;
532   
533 }
534
535 void
536 cl_app::remove_simulator(void)
537 {
538   if (!sim)
539     return;
540   delete sim;
541   sim= 0;
542 }
543
544 void
545 cl_app::build_cmdset(class cl_cmdset *cmdset)
546 {
547   class cl_cmd *cmd;
548   class cl_super_cmd *super_cmd;
549   class cl_cmdset *cset;
550
551   {
552     cset= new cl_cmdset();
553     cset->init();
554     cset->add(cmd= new cl_conf_cmd("_no_parameters_", 0,
555 "conf               Configuration",
556 "long help of conf"));
557     cmd->init();
558     cset->add(cmd= new cl_conf_objects_cmd("objects", 0, 
559 "conf objects       Show object tree",
560 "long help of conf objects"));
561     cmd->init();
562   }
563   cmdset->add(cmd= new cl_super_cmd("conf", 0,
564 "conf subcommand    Information, see `conf' command for more help",
565 "long help of conf", cset));
566   cmd->init();
567
568   cmd= new cl_help_cmd("help", 0,
569 "help [command]     Help about command(s)",
570 "long help of help");
571   cmdset->add(cmd);
572   cmd->init();
573   cmd->add_name("?");
574
575   cmdset->add(cmd= new cl_quit_cmd("quit", 0,
576 "quit               Quit",
577 "long help of quit"));
578   cmd->init();
579
580   cmdset->add(cmd= new cl_kill_cmd("kill", 0,
581 "kill               Shutdown simulator",
582 "long help of kill"));
583   cmd->init();
584
585   cmdset->add(cmd= new cl_exec_cmd("exec", 0,
586 "exec file          Execute commands from file",
587 "long help of exec"));
588   cmd->init();
589
590   cmdset->add(cmd= new cl_expression_cmd("expression", 0,
591 "expression expr    Evaluate the expression",
592 "long help of expression "));
593   cmd->init();
594   cmd->add_name("let");
595
596   {
597     super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("show"));
598     if (super_cmd)
599       cset= super_cmd->commands;
600     else {
601       cset= new cl_cmdset();
602       cset->init();
603     }
604     cset->add(cmd= new cl_show_copying_cmd("copying", 0, 
605 "show copying       Conditions for redistributing copies of uCsim",
606 "long help of show copying"));
607     cmd->init();
608     cset->add(cmd= new cl_show_warranty_cmd("warranty", 0, 
609 "show warranty      Various kinds of warranty you do not have",
610 "long help of show warranty"));
611     cmd->init();
612     cset->add(cmd= new cl_show_option_cmd("option", 0,
613 "show option [name] Show internal data of options",
614 "long help of show option"));
615     cmd->init();
616     cset->add(cmd= new cl_show_error_cmd("error", 0,
617 "show error         Show class of errors",
618 "long help of show error"));
619     cmd->init();
620   }
621   if (!super_cmd)
622     {
623       cmdset->add(cmd= new cl_super_cmd("show", 0,
624 "show subcommand    Generic command for showing things about the uCsim",
625 "long help of show", cset));
626       cmd->init();
627     }
628
629   {
630     super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("get"));
631     if (super_cmd)
632       cset= super_cmd->commands;
633     else {
634       cset= new cl_cmdset();
635       cset->init();
636     }
637     cset->add(cmd= new cl_get_option_cmd("option", 0,
638 "get option [name]  Get value of an option",
639 "long help of get option"));
640     cmd->init();
641   }
642   if (!super_cmd)
643     {
644       cmdset->add(cmd= new cl_super_cmd("get", 0,
645 "get subcommand     Get, see `get' command for more help",
646 "long help of get", cset));
647       cmd->init();
648     }
649
650   {
651     super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("set"));
652     if (super_cmd)
653       cset= super_cmd->commands;
654     else {
655       cset= new cl_cmdset();
656       cset->init();
657     }
658     cset->add(cmd= new cl_set_option_cmd("option", 0,
659 "set option name|nr value\n"
660 "                   Set value of an option",
661 "long help of set option"));
662     cmd->init();
663     cset->add(cmd= new cl_set_error_cmd("error", 0,
664 "set error error_name on|off|unset\n"
665 "                   Set value of an error",
666 "long help of set error"));
667     cmd->init();
668   }
669   if (!super_cmd)
670     {
671       cmdset->add(cmd= new cl_super_cmd("set", 0,
672 "set subcommand     Set, see `set' command for more help",
673 "long help of set", cset));
674       cmd->init();
675     }
676 }
677
678 void
679 cl_app::mk_options(void)
680 {
681   class cl_option *o;
682
683   options->new_option(o= new cl_bool_option(this, "null_prompt",
684                                             "Use \\0 as prompt (-P)"));
685   o->init();
686
687   options->new_option(o= new cl_pointer_option(this, "serial_in_file",
688                                                "Input file for serial line (-s)"));
689   o->init();
690   o->hide();
691
692   options->new_option(o= new cl_pointer_option(this, "serial_out_file",
693                                                "Output file for serial line (-s)"));
694   o->init();
695   o->hide();
696
697   options->new_option(o= new cl_string_option(this, "prompt",
698                                               "String of prompt (-p)"));
699   o->init();
700
701   options->new_option(o= new cl_bool_option(this, "debug",
702                                             "Print debug messages (-V)"));
703   o->init();
704
705   options->new_option(o= new cl_string_option(this, "console_on",
706                                               "Open console on this file (-c)"));
707   o->init();
708   o->hide();
709
710   options->new_option(o= new cl_string_option(this, "config_file",
711                                               "Execute this file at startup (-C)"));
712   o->init();
713   o->hide();
714
715   options->new_option(o= new cl_float_option(this, "xtal",
716                                              "Frequency of XTAL in Hz"));
717   o->init();
718   o->set_value(11059200.0);
719
720   options->new_option(o= new cl_string_option(this, "cpu_type",
721                                               "Type of controller (-t)"));
722   o->init();
723   o->hide();
724 }
725
726
727 int
728 cl_app::dd_printf(char *format, ...)
729 {
730   va_list ap;
731
732   if (!commander)
733     return(0);
734
735   va_start(ap, format);
736   int i= commander->dd_printf(format, ap);
737   va_end(ap);
738   return(i);
739 }
740
741 int
742 cl_app::debug(char *format, ...)
743 {
744   va_list ap;
745
746   if (!commander)
747     return(0);
748
749   va_start(ap, format);
750   int i= commander->debug(format, ap);
751   va_end(ap);
752   return(i);
753 }
754
755
756 /* End of app.cc */