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