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