Some fixes towards 0.2.37-pre5
[fw/sdcc] / sim / ucsim / sim.src / sim.cc
1 /*
2  * Simulator of microcontrollers (sim.cc)
3  *
4  * Copyright (C) 1999,99 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 #include <errno.h>
34 #include <ctype.h>
35 #ifdef HAVE_GETOPT_H
36 # include <getopt.h>
37 #endif
38 #include "i_string.h"
39
40 // prj
41 #include "globals.h"
42
43 // cmd
44 #include "cmdsetcl.h"
45 #include "infocl.h"
46
47 // local
48 #include "simcl.h"
49
50
51 /*
52  * Simulator
53  */
54
55 cl_sim::cl_sim(char *more_args, int iargc, char *iargv[]):
56   cl_base()
57 {
58   argc= iargc; argv= iargv;
59   uc= 0;
60   cmd= 0;
61   arguments= new cl_list(2, 2);
62   accept_args= more_args?strdup(more_args):0;
63   in_files= new cl_ustrings(2, 2);
64 }
65
66 int
67 cl_sim::init(void)
68 {
69   int i;
70
71   cl_base::init();
72   proc_arguments(argc, argv);
73   cmdset= mk_cmdset();
74   cmdset->init();
75   build_cmd_set();
76   if (!(uc= mk_controller()))
77     return(1);
78   uc->init();
79   cmd= mk_commander();
80   cmd->init();
81   if (cmd->cons->get_count() == 0)
82     {
83       fprintf(stderr, "No command console available.\n");
84       exit(1);
85     }
86   for (i= 0; i < in_files->count; i++)
87     {
88       char *fname= (char *)(in_files->at(i));
89       long l;
90       if ((l= uc->read_hex_file(fname)) >= 0)
91         {
92           cmd->all_printf("%ld words read from %s\n", l, fname);
93           fprintf(stderr, "%ld words read from %s\n", l, fname);
94         }
95       char *prompt;
96       if (arg_avail('P'))
97         cmd->all_print("\0", 1);
98       else
99         cmd->all_printf("%s", (prompt= get_sarg(0, "prompt"))?prompt:"> ") ;
100     }
101   return(0);
102 }
103
104 cl_sim::~cl_sim(void)
105 {
106   if (uc)
107     delete uc;
108 }
109
110 int
111 cl_sim::proc_arguments(int argc, char *argv[])
112 {
113   int i, c;
114   char *opts, *cp;
115
116   opts= (char*)malloc((accept_args?strlen(accept_args):0)+100);
117   strcpy(opts, "c:p:PX:vV");
118 #ifdef SOCKET_AVAIL
119   strcat(opts, "Z:r:");
120 #endif
121   if (accept_args)
122     strcat(opts, accept_args);
123   opterr= 0;
124   while((c= getopt(argc, argv, opts)) != -1)
125     switch (c)
126       {
127
128       case 'c':
129         arguments->add(new cl_prg_arg('c', 0, optarg));
130         break;
131
132 #ifdef SOCKET_AVAIL
133       case 'Z':
134         // By Sandeep
135         arguments->add(new cl_prg_arg('Z', 0, (long long)1));
136         if (!optarg || !isdigit(*optarg))
137           fprintf(stderr, "expected portnumber to follow -Z\n");
138         else {
139           char *p;
140           long long l= strtol(optarg, &p, 0);
141           arguments->add(new cl_prg_arg(0, "Zport", l));
142         }
143         break;
144 #endif
145
146       case 'p':
147         arguments->add(new cl_prg_arg(0, "prompt", optarg));
148         break;
149
150       case 'P':
151         arguments->add(new cl_prg_arg('P', 0, (long long)1));
152         break;
153
154 #ifdef SOCKET_AVAIL
155       case 'r':
156         arguments->add(new cl_prg_arg('r', 0,
157                                       (long long)strtol(optarg, NULL, 0)));
158         break;
159 #endif
160
161       case 'X':
162         {
163           double XTAL;
164           for (cp= optarg; *cp; *cp= toupper(*cp), cp++);
165           XTAL= strtod(optarg, &cp);
166           if (*cp == 'K')
167             XTAL*= 1e3;
168           if (*cp == 'M')
169             XTAL*= 1e6;
170           if (XTAL == 0)
171             {
172               fprintf(stderr, "Xtal frequency must be greather than 0\n");
173               exit(1);
174             }
175           arguments->add(new cl_prg_arg('X', 0, XTAL));
176           break;
177         }
178
179       case 'v':
180         printf("%s: %s\n", argv[0], VERSIONSTR);
181         exit(0);
182         break;
183
184       case 'V':
185         arguments->add(new cl_prg_arg('V', 0, (long long)1));
186         break;
187
188       case '?':
189         if ((c= proc_arg(c, optarg)))
190           exit(c);
191         break;
192
193       default:
194         if ((c= proc_arg(c, optarg)))
195           exit(c);
196       }
197   if (!arg_avail("prompt"))
198     arguments->add(new cl_prg_arg(0, "prompt", "> "));
199
200   for (i= optind; i < argc; i++)
201     in_files->add(argv[i]);
202
203   free(opts);
204   return(0);
205 }
206
207 int
208 cl_sim::proc_arg(char arg, char *optarg)
209 {
210   return(0);
211 }
212
213 int
214 cl_sim::arg_avail(char name)
215 {
216   class cl_prg_arg *a;
217   int i;
218
219   for (i= 0; i < arguments->count; i++)
220     {
221       a= (class cl_prg_arg *)(arguments->at(i));
222       if (a->short_name == name)
223         return(1);
224     }
225   return(0);
226 }
227
228 int
229 cl_sim::arg_avail(char *name)
230 {
231   class cl_prg_arg *a;
232   int i;
233
234   for (i= 0; i < arguments->count; i++)
235     {
236       a= (class cl_prg_arg *)(arguments->at(i));
237       if (a->long_name &&
238           strcmp(a->long_name, name) == 0)
239         return(1);
240     }
241   return(0);
242 }
243
244 long long
245 cl_sim::get_iarg(char sname, char *lname)
246 {
247   class cl_prg_arg *a;
248   int i;
249
250   for (i= 0; i < arguments->count; i++)
251     {
252       a= (class cl_prg_arg *)(arguments->at(i));
253       if ((sname && a->short_name == sname) ||
254           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
255         return(a->get_ivalue());
256     }
257   return(0);
258 }
259
260 char *
261 cl_sim::get_sarg(char sname, char *lname)
262 {
263   class cl_prg_arg *a;
264   int i;
265
266   for (i= 0; i < arguments->count; i++)
267     {
268       a= (class cl_prg_arg *)(arguments->at(i));
269       if ((sname && a->short_name == sname) ||
270           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
271         return(a->get_svalue());
272     }
273   return(0);
274 }
275
276
277 double
278 cl_sim::get_farg(char sname, char *lname)
279 {
280   class cl_prg_arg *a;
281   int i;
282
283   for (i= 0; i < arguments->count; i++)
284     {
285       a= (class cl_prg_arg *)(arguments->at(i));
286       if ((sname && a->short_name == sname) ||
287           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
288         return(a->get_fvalue());
289     }
290   return(0);
291 }
292
293 void *
294 cl_sim::get_parg(char sname, char *lname)
295 {
296   class cl_prg_arg *a;
297   int i;
298
299   for (i= 0; i < arguments->count; i++)
300     {
301       a= (class cl_prg_arg *)(arguments->at(i));
302       if ((sname && a->short_name == sname) ||
303           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
304         return(a->get_pvalue());
305     }
306   return(0);
307 }
308
309 class cl_commander *
310 cl_sim::mk_commander()
311 {
312   class cl_commander *cmd= new cl_commander(this);
313   return(cmd);
314 }
315
316 class cl_uc *
317 cl_sim::mk_controller(void)
318 {
319   return(new cl_uc(this));
320 }
321
322 class cl_cmdset *
323 cl_sim::mk_cmdset(void)
324 {
325   return(new cl_cmdset(this));
326 }
327
328 class cl_cmd_arg *
329 cl_sim::mk_cmd_int_arg(long long i)
330 {
331   class cl_cmd_arg *arg= new cl_cmd_int_arg(i);
332   arg->init();
333   return(arg);
334 }
335
336 class cl_cmd_arg *
337 cl_sim::mk_cmd_sym_arg(char *s)
338 {
339   class cl_cmd_arg *arg= new cl_cmd_sym_arg(s);
340   arg->init();
341   return(arg);
342 }
343
344 class cl_cmd_arg *
345 cl_sim::mk_cmd_str_arg(char *s)
346 {
347   class cl_cmd_arg *arg= new cl_cmd_str_arg(s);
348   arg->init();
349   return(arg);
350 }
351
352 class cl_cmd_arg *
353 cl_sim::mk_cmd_bit_arg(class cl_cmd_arg *sfr, class cl_cmd_arg *bit)
354 {
355   class cl_cmd_arg *arg= new cl_cmd_bit_arg(sfr, bit);
356   arg->init();
357   return(arg);
358 }
359
360
361 /*
362  * Main cycle of the simulator
363  */
364
365 int
366 cl_sim::main(void)
367 {
368   int done= 0;
369
370   while (!done &&
371          (state & SIM_QUIT) == 0)
372     {
373       if (state & SIM_GO)
374         {
375           uc->do_inst(-1);
376           if (cmd->input_avail())
377             done= cmd->proc_input();
378         }
379       else
380         {
381           cmd->wait_input();
382           done= cmd->proc_input();
383         }
384     }
385   return(0);
386 }
387
388 int
389 cl_sim::do_cmd(char *cmdstr, class cl_console *console)
390 {
391   class cl_cmdline *cmdline;
392   class cl_cmd *cmd;
393   int retval= 0;
394
395   cmdline= new cl_cmdline(cmdstr);
396   cmdline->init();
397   if (console->old_command(cmdline))
398     return(console->interpret(cmdstr));
399   cmd= cmdset->get_cmd(cmdline);
400   if (cmd)
401     retval= cmd->work(cmdline, console);
402   delete cmdline;
403   if (cmd)
404     return(retval);
405   return(console->interpret(cmdstr));
406 }
407
408 void
409 cl_sim::start(class cl_console *con)
410 {
411   state|= SIM_GO;
412   con->flags|= CONS_FROZEN;
413   cmd->frozen_console= con;
414 }
415
416 void
417 cl_sim::stop(int reason)
418 {
419   state&= ~SIM_GO;
420   if (cmd->frozen_console)
421     {
422       if (reason == resUSER &&
423           cmd->frozen_console->input_avail())
424         cmd->frozen_console->read_line();
425       cmd->frozen_console->printf("Stop at 0x%06x: (%d) ", uc->PC, reason);
426       switch (reason)
427         {
428         case resHALT:
429           cmd->frozen_console->printf("Halted\n");
430           break;
431         case resINV_ADDR:
432           cmd->frozen_console->printf("Invalid address\n");
433           break;
434         case resSTACK_OV:
435           cmd->frozen_console->printf("Stack overflow\n");
436           break;
437         case resBREAKPOINT:
438           cmd->frozen_console->printf("Breakpoint\n");
439           break;
440         case resINTERRUPT:
441           cmd->frozen_console->printf("Interrupt\n");
442           break;
443         case resWDTRESET:
444           cmd->frozen_console->printf("Watchdog reset\n");
445           break;
446         case resUSER:
447           cmd->frozen_console->printf("User stopped\n");
448           break;
449         case resINV_INST:
450           cmd->frozen_console->printf("Invalid instruction 0x%04x\n",
451                                       uc->get_mem(MEM_ROM, uc->PC));
452           break;
453         default:
454           cmd->frozen_console->printf("Unknown reason\n");
455           break;
456         }
457       cmd->frozen_console->printf("F 0x%06x\n", uc->PC); // for sdcdb
458       //if (cmd->actual_console != cmd->frozen_console)
459       cmd->frozen_console->flags&= ~CONS_FROZEN;
460       cmd->frozen_console->print_prompt();
461       cmd->frozen_console= 0;
462     }
463 }
464
465
466 /*
467  * Obsolete methods for old commander
468  */
469
470 FILE *
471 cl_sim::cmd_in(void)
472 {
473   if (!cmd ||
474       cmd->cons->get_count() == 0)
475     return(stdin);
476   if (cmd->actual_console)
477     return(cmd->actual_console->in?cmd->actual_console->in:stdin);
478   class cl_console *con= (class cl_console *)(cmd->cons->at(0));
479   return(con->in?con->in:stdin);
480 }
481
482 FILE *
483 cl_sim::cmd_out(void)
484 {
485   if (!cmd ||
486       cmd->cons->get_count() == 0)
487     return(stdout);
488   if (cmd->actual_console)
489     return(cmd->actual_console->out?cmd->actual_console->out:stdout);
490   class cl_console *con= (class cl_console *)(cmd->cons->at(0));
491   return(con->out?con->out:stdout);
492 }
493
494
495 /*
496  */
497
498 void
499 cl_sim::build_cmd_set(void)
500 {
501   class cl_cmd *cmd;
502   class cl_cmdset *cset;
503
504   cmdset->add(cmd= new cl_conf_cmd(this, "conf", 0,
505 "conf               Configuration",
506 "long help of conf"));
507   cmd->init();
508
509   cmdset->add(cmd= new cl_state_cmd(this, "state", 0,
510 "state              State of simulator",
511 "long help of state"));
512   cmd->init();
513
514   cmdset->add(cmd= new cl_file_cmd(this, "file", 0,
515 "file \"FILE\"        Load FILE into ROM",
516 "long help of file"));
517   cmd->init();
518   cmd->add_name("load");
519
520   cmdset->add(cmd= new cl_dl_cmd(this, "download", 0,
521 "download,dl          Load (intel.hex) data",
522 "long help of download"));
523   cmd->init();
524   cmd->add_name("dl");
525
526   cset= new cl_cmdset(this);
527   cset->init();
528   cset->add(cmd= new cl_info_bp_cmd(this, "breakpoints", 0, 
529 "info breakpoints   Status of user-settable breakpoints",
530 "long help of info breakpoints"));
531   cmd->add_name("bp");
532   cmd->init();
533   cset->add(cmd= new cl_info_reg_cmd(this, "registers", 0, 
534 "info registers     List of integer registers and their contents",
535 "long help of info registers"));
536   cmd->init();
537   cset->add(cmd= new cl_info_hw_cmd(this, "hardware", 0, 
538 "info hardware cathegory\n"
539 "                   Status of hardware elements of the CPU",
540 "long help of info hardware"));
541   cmd->add_name("hw");
542   cmd->init();
543
544   cmdset->add(cmd= new cl_super_cmd(this, "info", 0,
545 "info subcommand    Information, see `info' command for more help",
546 "long help of info", cset));
547   cmd->init();
548
549   cmdset->add(cmd= new cl_get_cmd(this, "get", 0,
550 "get                Get",
551 "long help of get"));
552   cmd->init();
553
554   cmdset->add(cmd= new cl_set_cmd(this, "set", 0,
555 "set                Set",
556 "long help of set"));
557   cmd->init();
558
559   cmdset->add(cmd= new cl_timer_cmd(this, "timer", 0,
560 "timer a|d|g|r|s|v id [direction|value]\n"
561 "                   Timer add|del|get|run|stop|value",
562 "timer add|create|make id [direction] -- create a new timer\n"
563 "timer del id -- delete a timer\n"
564 "timer get id -- list timers\n"
565 "timer run id -- turn a timer ON\n"
566 "timer stop id -- turn a timer OFF\n"
567 "timer value id val -- set value of a timer to `val'"));
568   cmd->init();
569
570   cmdset->add(cmd= new cl_run_cmd(this, "run", 0,
571 "run                Go",
572 "long help of run"));
573   cmd->init();
574   //cmd->add_name("g");
575
576   cmdset->add(cmd= new cl_step_cmd(this, "step", 0,
577 "step               Step",
578 "long help of step"));
579   cmd->init();
580   cmd->add_name("s");
581
582   cmdset->add(cmd= new cl_reset_cmd(this, "reset", 0,
583 "reset              Reset",
584 "long help of reset"));
585   cmd->init();
586
587   cmdset->add(cmd= new cl_dump_cmd(this, "dump", 0,
588 "dump i|x|r|s [start [stop]]\n"
589 "                   Dump memory",
590 "long help of dump"));
591   cmd->init();
592
593   cmdset->add(cmd= new cl_di_cmd(this, "di", 0,
594 "di [start [stop]]  Dump Internal RAM",
595 "long help of di"));
596   cmd->init();
597
598   cmdset->add(cmd= new cl_dx_cmd(this, "dx", 0,
599 "dx [start [stop]]  Dump External RAM",
600 "long help of dx"));
601   cmd->init();
602
603   cmdset->add(cmd= new cl_ds_cmd(this, "ds", 0,
604 "ds [start [stop]]  Dump SFR",
605 "long help of ds"));
606   cmd->init();
607
608   cmdset->add(cmd= new cl_dch_cmd(this, "dch", 0,
609 "dch [start [stop]] Dump code in hex form",
610 "long help of dch"));
611   cmd->init();
612
613   cmdset->add(cmd= new cl_dc_cmd(this, "dc", 0,
614 "dc [start [stop]]  Dump code in disass form",
615 "long help of dc"));
616   cmd->init();
617
618   cmdset->add(cmd= new cl_break_cmd(this, "break", 0,
619 "break addr [hit]   Set fix breakpoint",
620 "long help of break"));
621   cmd->init();
622
623   cmdset->add(cmd= new cl_tbreak_cmd(this, "tbreak", 0,
624 "tbreak addr [hit]  Set temporary breakpoint",
625 "long help of tbreak"));
626   cmd->init();
627
628   cmdset->add(cmd= new cl_clear_cmd(this, "clear", 0,
629 "clear [addr...]    Clear fix breakpoint",
630 "long help of clear"));
631   cmd->init();
632
633   cmdset->add(cmd= new cl_help_cmd(this, "help", 0,
634 "help               Help",
635 "long help of help"));
636   cmd->init();
637   cmd->add_name("?");
638
639   cmdset->add(cmd= new cl_quit_cmd(this, "quit", 0,
640 "quit               Quit",
641 "long help of quit"));
642   cmd->init();
643
644   cmdset->add(cmd= new cl_kill_cmd(this, "kill", 0,
645 "kill               Shutdown simulator",
646 "long help of kill"));
647   cmd->init();
648 }
649
650
651 /* End of sim.src/sim.cc */