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