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