Version 0.3.2-pre1
[fw/sdcc] / sim / ucsim / sim.src / 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
46 // local, sim.src
47 #include "appcl.h"
48 #include "simcl.h"
49
50 // cmd.src
51 #include "cmdsetcl.h"
52 #include "cmdutil.h"
53 #include "cmdconfcl.h"
54 #include "showcl.h"
55
56
57 /*
58  * Program options
59  */
60
61 /*cl_option::cl_option(int atype, char sn, char *ln)
62 {
63   type= atype;
64   short_name= sn;
65   if (!ln)
66     long_name= NULL;
67   else
68     long_name= strdup(ln);
69   values= new cl_ustrings(1, 1);
70 }
71
72 cl_option::~cl_option(void)
73 {
74   if (long_name)
75     free(long_name);
76   delete values;
77 }
78
79 int
80 cl_option::add_value(char *value)
81 {
82   values->add(value);
83   return(values->count - 1);
84 }
85
86 char *
87 cl_option::get_value(int index)
88 {
89   if (index > values->count - 1)
90     return(0);
91   return((char*)(values->at(index)));
92 }*/
93
94 /* List of options */
95
96 /*cl_options::cl_options(void):
97   cl_list(2, 2)
98 {
99 }*/
100
101
102 /*
103  * Application
104  ****************************************************************************
105  */
106
107 cl_app::cl_app(void)
108 {
109   //options= new cl_options();
110   sim= 0;
111   args= new cl_arguments();
112   in_files= new cl_ustrings(2, 2);
113   going= 1;
114 }
115
116 cl_app::~cl_app(void)
117 {
118   //delete options;
119   remove_simulator();
120   delete commander;
121   //delete cmdset;
122   delete args;
123   delete in_files;
124 }
125
126 int
127 cl_app::init(int argc, char *argv[])
128 {
129   cl_base::init();
130   proc_arguments(argc, argv);
131   class cl_cmdset *cmdset= new cl_cmdset();
132   cmdset->init();
133   build_cmdset(cmdset);
134   commander= new cl_commander(this, cmdset/*, sim*/);
135   commander->init();
136   return(0);
137 }
138
139 /* Main cycle */
140
141 int
142 cl_app::run(void)
143 {
144   int done= 0;
145
146   while (!done &&
147          going)
148     {
149       if (sim)
150         {
151           if (sim->state & SIM_GO)
152             {
153               if (commander->input_avail())
154                 done= commander->proc_input();
155               else
156                 sim->step();
157             }
158           else
159             {
160               commander->wait_input();
161               done= commander->proc_input();
162             }
163         }
164       else
165         {
166           commander->wait_input();
167           done= commander->proc_input();
168         }
169     }
170   return(0);
171 }
172
173 void
174 cl_app::done(void)
175 {
176 }
177
178
179 /*
180  * Interpretation of parameters
181  */
182
183 static void
184 print_help(char *name)
185 {
186   printf("%s: %s\n", name, VERSIONSTR);
187   printf("Usage: %s [-hHVvP] [-p prompt] [-t CPU] [-X freq[k|M]]\n"
188          "       [-c file] [-s file] [-S optionlist]"
189 #ifdef SOCKET_AVAIL
190          " [-Z portnum] [-k portnum]"
191 #endif
192          "\n"
193          "       [files...]\n", name);
194   printf
195     (
196      "Options:\n"
197      "  -t CPU       Type of CPU: 51, C52, 251, etc.\n"
198      "  -X freq[k|M] XTAL frequency\n"
199      "  -c file      Open command console on `file'\n"
200 #ifdef SOCKET_AVAIL
201      "  -Z portnum   Use localhost:portnumber for command console\n"
202      "  -k portnum   Use localhost:portnum for serial I/O\n"
203 #endif
204      "  -s file      Connect serial interface to `file'\n"
205      "  -S options   `options' is a comma separated list of options\n"
206      "               according to serial interface. Know options are:\n"
207      "                  in=file   serial input will be read from file named `file'\n"
208      "                  out=file  serial output will be written to `file'\n"
209      "  -p prompt    Specify string for prompt\n"
210      "  -P           Prompt is a null ('\\0') character\n"
211      "  -V           Verbose mode\n"
212      "  -v           Print out version number\n"
213      "  -H           Print out types of known CPUs\n"
214      "  -h           Print out this help\n"
215      );
216 }
217
218 enum {
219   SOPT_IN= 0,
220   SOPT_OUT
221 };
222
223 static const char *S_opts[]= {
224   /*[SOPT_IN]=*/ "in",
225   /*[SOPT_OUT]=*/ "out",
226   NULL
227 };
228
229 int
230 cl_app::proc_arguments(int argc, char *argv[])
231 {
232   int i, c;
233   char opts[100], *cp, *subopts, *value;
234   char *cpu_type= NULL;
235
236   strcpy(opts, "c:C:p:PX:vVt:s:S:hHk:");
237 #ifdef SOCKET_AVAIL
238   strcat(opts, "Z:r:");
239 #endif
240   //int opterr= 0;
241   while((c= getopt(argc, argv, opts)) != -1)
242     switch (c)
243       {
244       case 'c':
245         args->add(new cl_prg_arg('c', 0, optarg));
246         break;
247       case 'C':
248         args->add(new cl_prg_arg(0, "Config", optarg));
249         break;
250 #ifdef SOCKET_AVAIL
251       case 'Z':
252         // By Sandeep
253         args->add(new cl_prg_arg('Z', 0, (long)1));
254         if (!optarg || !isdigit(*optarg))
255           fprintf(stderr, "expected portnumber to follow -Z\n");
256         else {
257           char *p;
258           long l= strtol(optarg, &p, 0);
259           args->add(new cl_prg_arg(0, "Zport", l));
260         }
261         break;
262 #endif
263       case 'p':
264         args->add(new cl_prg_arg(0, "prompt", optarg));
265         break;
266       case 'P':
267         args->add(new cl_prg_arg('P', 0, (long)1));
268         break;
269 #ifdef SOCKET_AVAIL
270       case 'r':
271         args->add(new cl_prg_arg('r', 0,
272                                  (long)strtol(optarg, NULL, 0)));
273         break;
274 #endif
275       case 'X':
276         {
277           double XTAL;
278           for (cp= optarg; *cp; *cp= toupper(*cp), cp++);
279           XTAL= strtod(optarg, &cp);
280           if (*cp == 'K')
281             XTAL*= 1e3;
282           if (*cp == 'M')
283             XTAL*= 1e6;
284           if (XTAL == 0)
285             {
286               fprintf(stderr, "Xtal frequency must be greather than 0\n");
287               exit(1);
288             }
289           args->add(new cl_prg_arg('X', 0, XTAL));
290           break;
291         }
292       case 'v':
293         printf("%s: %s\n", argv[0], VERSIONSTR);
294         exit(0);
295         break;
296       case 'V':
297         args->add(new cl_prg_arg('V', 0, (long)1));
298         break;
299       case 't':
300         if (cpu_type)
301           free(cpu_type);
302         cpu_type= strdup(optarg);
303         for (cp= cpu_type; *cp; *cp= toupper(*cp), cp++);
304         args->add(new cl_prg_arg('t', 0, cpu_type));
305         break;
306       case 's':
307       {
308         FILE *Ser_in, *Ser_out;
309         if (args->arg_avail('s'))
310           {
311             fprintf(stderr, "-s option can not be used more than once.\n");
312             break;
313           }
314         args->add(new cl_prg_arg('s', 0, (long)1));
315         if ((Ser_in= fopen(optarg, "r")) == NULL)
316           {
317             fprintf(stderr,
318                     "Can't open `%s': %s\n", optarg, strerror(errno));
319             return(4);
320           }
321         args->add(new cl_prg_arg(0, "Ser_in", Ser_in));
322         if ((Ser_out= fopen(optarg, "w")) == NULL)
323           {
324             fprintf(stderr,
325                     "Can't open `%s': %s\n", optarg, strerror(errno));
326             return(4);
327           }
328         args->add(new cl_prg_arg(0, "Ser_out", Ser_out));
329         break;
330       }
331 #ifdef SOCKET_AVAIL
332       // socket serial I/O by Alexandre Frey <Alexandre.Frey@trusted-logic.fr>
333       case 'k':
334         {
335           FILE *Ser_in, *Ser_out;
336           int  sock;
337           unsigned short serverport;
338           int client_sock;
339
340           if (args->arg_avail("Ser_in")) {
341             fprintf(stderr, "Serial input specified more than once.\n");
342           }
343           if (args->arg_avail("Ser_out")) {
344             fprintf(stderr, "Serial output specified more than once.\n");
345           }
346
347           serverport = atoi(optarg);
348           sock= make_server_socket(serverport);
349           if (listen(sock, 1) < 0) {
350             fprintf(stderr, "Listen on port %d: %s\n", serverport,
351                     strerror(errno));
352             return (4);
353           }
354           fprintf(stderr, "Listening on port %d for a serial connection.\n",
355                   serverport);
356           if ((client_sock= accept(sock, NULL, NULL)) < 0) {
357             fprintf(stderr, "accept: %s\n", strerror(errno));
358           }
359           fprintf(stderr, "Serial connection established.\n");
360
361           if ((Ser_in= fdopen(client_sock, "r")) == NULL) {
362             fprintf(stderr, "Can't create input stream: %s\n", strerror(errno));
363             return (4);
364           }
365           args->add(new cl_prg_arg(0, "Ser_in", Ser_in));
366           if ((Ser_out= fdopen(client_sock, "w")) == NULL) {
367             fprintf(stderr, "Can't create output stream: %s\n", strerror(errno));
368             return (4);
369           }
370           args->add(new cl_prg_arg(0, "Ser_out", Ser_out));
371           break;
372         }
373 #endif
374       case 'S':
375         subopts= optarg;
376         while (*subopts != '\0')
377           switch (get_sub_opt(&subopts, S_opts, &value))
378             {
379               FILE *Ser_in, *Ser_out;
380             case SOPT_IN:
381               if (value == NULL) {
382                 fprintf(stderr, "No value for -S in\n");
383                 exit(1);
384               }
385               if (args->arg_avail("Ser_in"))
386                 {
387                   fprintf(stderr, "Serial input specified more than once.\n");
388                   break;
389                 }
390               if ((Ser_in= fopen(value, "r")) == NULL)
391                 {
392                   fprintf(stderr,
393                           "Can't open `%s': %s\n", value, strerror(errno));
394                   exit(4);
395                 }
396               args->add(new cl_prg_arg(0, "Ser_in", Ser_in));
397               break;
398             case SOPT_OUT:
399               if (value == NULL) {
400                 fprintf(stderr, "No value for -S out\n");
401                 exit(1);
402               }
403               if (args->arg_avail("Ser_out"))
404                 {
405                   fprintf(stderr, "Serial output specified more than once.\n");
406                   break;
407                 }
408               if ((Ser_out= fopen(value, "w")) == NULL)
409                 {
410                   fprintf(stderr,
411                           "Can't open `%s': %s\n", value, strerror(errno));
412                   exit(4);
413                 }
414               args->add(new cl_prg_arg(0, "Ser_out", Ser_out));
415               break;
416             default:
417               /* Unknown suboption. */
418               fprintf(stderr, "Unknown suboption `%s' for -S\n", value);
419               exit(1);
420               break;
421             }
422         break;
423       case 'h':
424         print_help("s51");
425         exit(0);
426         break;
427       case 'H':
428         /*i= 0;
429         while (cpus_51[i].type_str != NULL)
430           {
431             printf("%s\n", cpus_51[i].type_str);
432             i++;
433             }*/
434         exit(0);
435         break;
436       case '?':
437         if (isprint(optopt))
438           fprintf(stderr, "Unknown option `-%c'.\n", optopt);
439         else
440           fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
441         return(1);
442         break;
443       default:
444         exit(c);
445       }
446   if (!args->arg_avail("prompt"))
447     args->add(new cl_prg_arg(0, "prompt", "> "));
448
449   for (i= optind; i < argc; i++)
450     in_files->add(argv[i]);
451
452   return(0);
453 }
454
455
456 /* Command handling */
457
458 class cl_cmd *
459 cl_app::get_cmd(class cl_cmdline *cmdline)
460 {
461   return(0);
462 }
463
464
465 /* Adding and removing comonents */
466
467 void
468 cl_app::set_simulator(class cl_sim *simulator)
469 {
470   if (sim)
471     remove_simulator();
472   sim= simulator;
473   
474 }
475
476 void
477 cl_app::remove_simulator(void)
478 {
479   if (!sim)
480     return;
481   delete sim;
482   sim= 0;
483 }
484
485 void
486 cl_app::build_cmdset(class cl_cmdset *cmdset)
487 {
488   class cl_cmd *cmd;
489   class cl_cmdset *cset;
490
491   {
492     cset= new cl_cmdset();
493     cset->init();
494     cset->add(cmd= new cl_conf_cmd("_no_parameters_", 0,
495 "conf               Configuration",
496 "long help of conf"));
497     cmd->init();
498     cset->add(cmd= new cl_conf_addmem_cmd("addmem", 0,
499 "conf addmem\n"
500 "                   Make memory",
501 "long help of conf addmem"));
502     cmd->init();
503   }
504   cmdset->add(cmd= new cl_super_cmd("conf", 0,
505 "conf subcommand    Information, see `conf' command for more help",
506 "long help of conf", cset));
507   cmd->init();
508
509   cmd= new cl_help_cmd("help", 0,
510 "help [command]     Help about command(s)",
511 "long help of help");
512   cmdset->add(cmd);
513   cmd->init();
514   cmd->add_name("?");
515
516   cmdset->add(cmd= new cl_quit_cmd("quit", 0,
517 "quit               Quit",
518 "long help of quit"));
519   cmd->init();
520
521   cmdset->add(cmd= new cl_kill_cmd("kill", 0,
522 "kill               Shutdown simulator",
523 "long help of kill"));
524   cmd->init();
525
526   {
527     cset= new cl_cmdset();
528     cset->init();
529     cset->add(cmd= new cl_show_copying_cmd("copying", 0, 
530 "show copying       Conditions for redistributing copies of uCsim",
531 "long help of show copying"));
532     cmd->init();
533     cset->add(cmd= new cl_show_warranty_cmd("warranty", 0, 
534 "show warranty      Various kinds of warranty you do not have",
535 "long help of show warranty"));
536     cmd->init();
537   }
538   cmdset->add(cmd= new cl_super_cmd("show", 0,
539 "show subcommand    Generic command for showing things about the uCsim",
540 "long help of show", cset));
541   cmd->init();
542 }
543
544
545 /* End of sim.src/app.cc */