3c2a4d847569bd4cd3ff97778e3c39931be65221
[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 <unistd.h>
33 #ifdef HAVE_GETOPT_H
34 # include <getopt.h>
35 #endif
36 #ifdef SOCKET_AVAIL
37 #include <sys/socket.h>
38 #endif
39 #include <ctype.h>
40 #include <errno.h>
41 #include "i_string.h"
42
43 // prj
44 #include "utils.h"
45 #include "appcl.h"
46 #include "optioncl.h"
47
48 // sim.src
49 #include "simcl.h"
50
51 // cmd.src
52 #include "cmdsetcl.h"
53 #include "cmdutil.h"
54 #include "cmdconfcl.h"
55 #include "showcl.h"
56 #include "getcl.h"
57 #include "setcl.h"
58
59
60 /*
61  * Program options
62  */
63
64 /*cl_option::cl_option(int atype, char sn, char *ln)
65 {
66   type= atype;
67   short_name= sn;
68   if (!ln)
69     long_name= NULL;
70   else
71     long_name= strdup(ln);
72   values= new cl_ustrings(1, 1);
73 }
74
75 cl_option::~cl_option(void)
76 {
77   if (long_name)
78     free(long_name);
79   delete values;
80 }
81
82 int
83 cl_option::add_value(char *value)
84 {
85   values->add(value);
86   return(values->count - 1);
87 }
88
89 char *
90 cl_option::get_value(int index)
91 {
92   if (index > values->count - 1)
93     return(0);
94   return((char*)(values->at(index)));
95 }*/
96
97 /* List of options */
98
99 /*cl_options::cl_options(void):
100   cl_list(2, 2)
101 {
102 }*/
103
104
105 /*
106  * Application
107  ****************************************************************************
108  */
109
110 cl_app::cl_app(void)
111 {
112   //options= new cl_options();
113   sim= 0;
114   args= new cl_arguments();
115   in_files= new cl_ustrings(2, 2);
116   options= new cl_options();
117   going= 1;
118 }
119
120 cl_app::~cl_app(void)
121 {
122   //delete options;
123   remove_simulator();
124   delete commander;
125   //delete cmdset;
126   delete args;
127   delete in_files;
128   delete options;
129 }
130
131 int
132 cl_app::init(int argc, char *argv[])
133 {
134   cl_base::init();
135   set_name("application");
136   mk_options();
137   proc_arguments(argc, argv);
138   class cl_cmdset *cmdset= new cl_cmdset();
139   cmdset->init();
140   build_cmdset(cmdset);
141   commander= new cl_commander(this, cmdset/*, sim*/);
142   commander->init();
143   return(0);
144 }
145
146 /* Main cycle */
147
148 int
149 cl_app::run(void)
150 {
151   int done= 0;
152
153   while (!done &&
154          going)
155     {
156       if (sim)
157         {
158           if (sim->state & SIM_GO)
159             {
160               if (commander->input_avail())
161                 done= commander->proc_input();
162               else
163                 sim->step();
164             }
165           else
166             {
167               commander->wait_input();
168               done= commander->proc_input();
169             }
170         }
171       else
172         {
173           commander->wait_input();
174           done= commander->proc_input();
175         }
176     }
177   return(0);
178 }
179
180 void
181 cl_app::done(void)
182 {
183 }
184
185
186 /*
187  * Interpretation of parameters
188  */
189
190 static void
191 print_help(char *name)
192 {
193   printf("%s: %s\n", name, VERSIONSTR);
194   printf("Usage: %s [-hHVvP] [-p prompt] [-t CPU] [-X freq[k|M]]\n"
195          "       [-c file] [-s file] [-S optionlist]"
196 #ifdef SOCKET_AVAIL
197          " [-Z portnum] [-k portnum]"
198 #endif
199          "\n"
200          "       [files...]\n", name);
201   printf
202     (
203      "Options:\n"
204      "  -t CPU       Type of CPU: 51, C52, 251, etc.\n"
205      "  -X freq[k|M] XTAL frequency\n"
206      "  -c file      Open command console on `file'\n"
207 #ifdef SOCKET_AVAIL
208      "  -Z portnum   Use localhost:portnumber for command console\n"
209      "  -k portnum   Use localhost:portnum for serial I/O\n"
210 #endif
211      "  -s file      Connect serial interface to `file'\n"
212      "  -S options   `options' is a comma separated list of options according to\n"
213      "               serial interface. Know options are:\n"
214      "                  in=file   serial input will be read from file named `file'\n"
215      "                  out=file  serial output will be written to `file'\n"
216      "  -p prompt    Specify string for prompt\n"
217      "  -P           Prompt is a null ('\\0') character\n"
218      "  -V           Verbose mode\n"
219      "  -v           Print out version number\n"
220      "  -H           Print out types of known CPUs\n"
221      "  -h           Print out this help\n"
222      );
223 }
224
225 enum {
226   SOPT_IN= 0,
227   SOPT_OUT
228 };
229
230 static const char *S_opts[]= {
231   /*[SOPT_IN]=*/ "in",
232   /*[SOPT_OUT]=*/ "out",
233   NULL
234 };
235
236 int
237 cl_app::proc_arguments(int argc, char *argv[])
238 {
239   int i, c;
240   char opts[100], *cp, *subopts, *value;
241   char *cpu_type= NULL;
242
243   strcpy(opts, "c:C:p:PX:vVt:s:S:hHk:");
244 #ifdef SOCKET_AVAIL
245   strcat(opts, "Z:r:");
246 #endif
247   //int opterr= 0;
248   while((c= getopt(argc, argv, opts)) != -1)
249     switch (c)
250       {
251       case 'c':
252         //args->add(new cl_prg_arg('c', 0, optarg));
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         args->add(new cl_prg_arg(0, "Config", optarg));
259         break;
260 #ifdef SOCKET_AVAIL
261       case 'Z':
262         // By Sandeep
263         args->add(new cl_prg_arg('Z', 0, (long)1));
264         if (!optarg || !isdigit(*optarg))
265           fprintf(stderr, "expected portnumber to follow -Z\n");
266         else {
267           char *p;
268           long l= strtol(optarg, &p, 0);
269           args->add(new cl_prg_arg(0, "Zport", l));
270         }
271         break;
272 #endif
273       case 'p': {
274         //args->add(new cl_prg_arg(0, "prompt", optarg));
275         //class cl_option *o= options->get_option("prompt", this);
276         if (/*o*/!options->set_value("prompt", this, optarg))
277             /*o->set_value(optarg);
278               else*/
279           fprintf(stderr, "Warning: No \"prompt\" option found to set "
280                   "parameter of -p as default prompt\n");
281         break;
282       }
283       case 'P':
284         args->add(new cl_prg_arg('P', 0, (long)1));
285         if (!options->set_value("null_prompt", this, bool(DD_TRUE)))
286           fprintf(stderr, "Warning: No \"null_prompt\" option found\n");
287         break;
288 #ifdef SOCKET_AVAIL
289       case 'r':
290         args->add(new cl_prg_arg('r', 0,
291                                  (long)strtol(optarg, NULL, 0)));
292         break;
293 #endif
294       case 'X':
295         {
296           double XTAL;
297           for (cp= optarg; *cp; *cp= toupper(*cp), cp++);
298           XTAL= strtod(optarg, &cp);
299           if (*cp == 'K')
300             XTAL*= 1e3;
301           if (*cp == 'M')
302             XTAL*= 1e6;
303           if (XTAL == 0)
304             {
305               fprintf(stderr, "Xtal frequency must be greather than 0\n");
306               exit(1);
307             }
308           args->add(new cl_prg_arg('X', 0, XTAL));
309           break;
310         }
311       case 'v':
312         printf("%s: %s\n", argv[0], VERSIONSTR);
313         exit(0);
314         break;
315       case 'V':
316         args->add(new cl_prg_arg('V', 0, (long)1));
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         if (cpu_type)
323           free(cpu_type);
324         cpu_type= strdup(optarg);
325         for (cp= cpu_type; *cp; *cp= toupper(*cp), cp++);
326         args->add(new cl_prg_arg('t', 0, cpu_type));
327         break;
328       case 's':
329       {
330         FILE *Ser_in, *Ser_out;
331         if (args->arg_avail('s'))
332           {
333             fprintf(stderr, "-s option can not be used more than once.\n");
334             break;
335           }
336         args->add(new cl_prg_arg('s', 0, (long)1));
337         if ((Ser_in= fopen(optarg, "r")) == NULL)
338           {
339             fprintf(stderr,
340                     "Can't open `%s': %s\n", optarg, strerror(errno));
341             return(4);
342           }
343         args->add(new cl_prg_arg(0, "Ser_in", Ser_in));
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         args->add(new cl_prg_arg(0, "Ser_out", Ser_out));
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 (args->arg_avail("Ser_in")) {
363             fprintf(stderr, "Serial input specified more than once.\n");
364           }
365           if (args->arg_avail("Ser_out")) {
366             fprintf(stderr, "Serial output specified more than once.\n");
367           }
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           args->add(new cl_prg_arg(0, "Ser_in", Ser_in));
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           args->add(new cl_prg_arg(0, "Ser_out", Ser_out));
393           break;
394         }
395 #endif
396       case 'S':
397         subopts= optarg;
398         while (*subopts != '\0')
399           switch (get_sub_opt(&subopts, S_opts, &value))
400             {
401               FILE *Ser_in, *Ser_out;
402             case SOPT_IN:
403               if (value == NULL) {
404                 fprintf(stderr, "No value for -S in\n");
405                 exit(1);
406               }
407               if (args->arg_avail("Ser_in"))
408                 {
409                   fprintf(stderr, "Serial input specified more than once.\n");
410                   break;
411                 }
412               if ((Ser_in= fopen(value, "r")) == NULL)
413                 {
414                   fprintf(stderr,
415                           "Can't open `%s': %s\n", value, strerror(errno));
416                   exit(4);
417                 }
418               args->add(new cl_prg_arg(0, "Ser_in", Ser_in));
419               break;
420             case SOPT_OUT:
421               if (value == NULL) {
422                 fprintf(stderr, "No value for -S out\n");
423                 exit(1);
424               }
425               if (args->arg_avail("Ser_out"))
426                 {
427                   fprintf(stderr, "Serial output specified more than once.\n");
428                   break;
429                 }
430               if ((Ser_out= fopen(value, "w")) == NULL)
431                 {
432                   fprintf(stderr,
433                           "Can't open `%s': %s\n", value, strerror(errno));
434                   exit(4);
435                 }
436               args->add(new cl_prg_arg(0, "Ser_out", Ser_out));
437               break;
438             default:
439               /* Unknown suboption. */
440               fprintf(stderr, "Unknown suboption `%s' for -S\n", value);
441               exit(1);
442               break;
443             }
444         break;
445       case 'h':
446         print_help("s51");
447         exit(0);
448         break;
449       case 'H':
450         /*i= 0;
451         while (cpus_51[i].type_str != NULL)
452           {
453             printf("%s\n", cpus_51[i].type_str);
454             i++;
455             }*/
456         exit(0);
457         break;
458       case '?':
459         if (isprint(optopt))
460           fprintf(stderr, "Unknown option `-%c'.\n", optopt);
461         else
462           fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
463         return(1);
464         break;
465       default:
466         exit(c);
467       }
468   if (!args->arg_avail("prompt"))
469     args->add(new cl_prg_arg(0, "prompt", "> "));
470
471   for (i= optind; i < argc; i++)
472     in_files->add(argv[i]);
473
474   return(0);
475 }
476
477
478 class cl_uc *
479 cl_app::get_uc(void)
480 {
481   if (!sim)
482     return(0);
483   return(sim->get_uc());
484 }
485
486
487 /* Command handling */
488
489 class cl_cmd *
490 cl_app::get_cmd(class cl_cmdline *cmdline)
491 {
492   return(0);
493 }
494
495
496 /*
497  * Messages to broadcast
498  */
499
500 void
501 cl_app::mem_cell_changed(class cl_mem *mem, t_addr addr)
502 {
503   if (sim)
504     sim->mem_cell_changed(mem, addr);
505 }
506
507
508 /* Adding and removing components */
509
510 void
511 cl_app::set_simulator(class cl_sim *simulator)
512 {
513   if (sim)
514     remove_simulator();
515   sim= simulator;
516   
517 }
518
519 void
520 cl_app::remove_simulator(void)
521 {
522   if (!sim)
523     return;
524   delete sim;
525   sim= 0;
526 }
527
528 void
529 cl_app::build_cmdset(class cl_cmdset *cmdset)
530 {
531   class cl_cmd *cmd;
532   class cl_super_cmd *super_cmd;
533   class cl_cmdset *cset;
534
535   {
536     cset= new cl_cmdset();
537     cset->init();
538     cset->add(cmd= new cl_conf_cmd("_no_parameters_", 0,
539 "conf               Configuration",
540 "long help of conf"));
541     cmd->init();
542     cset->add(cmd= new cl_conf_addmem_cmd("addmem", 0,
543 "conf addmem\n"
544 "                   Make memory",
545 "long help of conf addmem"));
546     cmd->init();
547   }
548   cmdset->add(cmd= new cl_super_cmd("conf", 0,
549 "conf subcommand    Information, see `conf' command for more help",
550 "long help of conf", cset));
551   cmd->init();
552
553   cmd= new cl_help_cmd("help", 0,
554 "help [command]     Help about command(s)",
555 "long help of help");
556   cmdset->add(cmd);
557   cmd->init();
558   cmd->add_name("?");
559
560   cmdset->add(cmd= new cl_quit_cmd("quit", 0,
561 "quit               Quit",
562 "long help of quit"));
563   cmd->init();
564
565   cmdset->add(cmd= new cl_kill_cmd("kill", 0,
566 "kill               Shutdown simulator",
567 "long help of kill"));
568   cmd->init();
569
570   cmdset->add(cmd= new cl_exec_cmd("exec", 0,
571 "exec file          Execute commands from file",
572 "long help of exec"));
573   cmd->init();
574
575   {
576     cset= new cl_cmdset();
577     cset->init();
578     cset->add(cmd= new cl_show_copying_cmd("copying", 0, 
579 "show copying       Conditions for redistributing copies of uCsim",
580 "long help of show copying"));
581     cmd->init();
582     cset->add(cmd= new cl_show_warranty_cmd("warranty", 0, 
583 "show warranty      Various kinds of warranty you do not have",
584 "long help of show warranty"));
585     cmd->init();
586     cset->add(cmd= new cl_show_option_cmd("option", 0,
587 "show option [name] Show internal data of options",
588 "long help of show option"));
589     cmd->init();
590   }
591   cmdset->add(cmd= new cl_super_cmd("show", 0,
592 "show subcommand    Generic command for showing things about the uCsim",
593 "long help of show", cset));
594   cmd->init();
595
596   {
597     super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("get"));
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_get_option_cmd("option", 0,
605 "get option [name]  Get value of an option",
606 "long help of get option"));
607     cmd->init();
608   }
609   if (!super_cmd)
610     {
611       cmdset->add(cmd= new cl_super_cmd("get", 0,
612 "get subcommand     Get, see `get' command for more help",
613 "long help of get", cset));
614       cmd->init();
615     }
616
617   {
618     super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("set"));
619     if (super_cmd)
620       cset= super_cmd->commands;
621     else {
622       cset= new cl_cmdset();
623       cset->init();
624     }
625     cset->add(cmd= new cl_set_option_cmd("option", 0,
626 "set option name|nr value\n"
627 "                   Set value of an option",
628 "long help of set option"));
629     cmd->init();
630   }
631   if (!super_cmd)
632     {
633       cmdset->add(cmd= new cl_super_cmd("set", 0,
634 "set subcommand     Set, see `set' command for more help",
635 "long help of set", cset));
636       cmd->init();
637     }
638 }
639
640 void
641 cl_app::mk_options(void)
642 {
643   class cl_option *o;
644
645   options->new_option(o= new cl_bool_option(this, "null_prompt",
646                                             "Use \\0 as prompt (-P)"));
647   o->init();
648   options->new_option(o= new cl_bool_option(this, "stopit",
649                                             "Stop if interrupt accepted"));
650   o->init();
651   options->new_option(o= new cl_string_option(this, "serial_in_file",
652                                               "Input file for serial line (-s)"));
653   o->init();
654   options->new_option(o= new cl_string_option(this, "serial_out_file",
655                                               "Output file for serial line (-s)"));
656   o->init();
657   options->new_option(o= new cl_string_option(this, "prompt",
658                                               "String of prompt (-p)"));
659   o->init();
660   options->new_option(o= new cl_bool_option(this, "debug",
661                                             "Print debug messages (-V)"));
662   o->init();
663   options->new_option(o= new cl_string_option(this, "console_on",
664                                               "Open console on this file (-c)"));
665   o->init();
666   o->hide();
667 }
668
669
670 /* End of app.cc */