Version 0.3.0
[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 #include "setcl.h"
47 #include "getcl.h"
48 #include "showcl.h"
49 #include "bpcl.h"
50 #include "cmdguicl.h"
51 #include "cmdconfcl.h"
52
53 // local
54 #include "simcl.h"
55
56
57 /*
58  * Simulator
59  */
60
61 cl_sim::cl_sim(class cl_app *the_app,
62                char *more_args, int iargc, char *iargv[]):
63   cl_base()
64 {
65   app= the_app;
66   argc= iargc; argv= iargv;
67   uc= 0;
68   cmd= 0;
69   arguments= new cl_list(2, 2);
70   accept_args= more_args?strdup(more_args):0;
71   in_files= new cl_ustrings(2, 2);
72   gui= new cl_gui(this);
73 }
74
75 int
76 cl_sim::init(void)
77 {
78   int i;
79
80   cl_base::init();
81   proc_arguments(argc, argv);
82   class cl_cmdset *cmdset= new cl_cmdset(this);
83   cmdset->init();
84   build_cmd_set(cmdset);
85   if (!(uc= mk_controller()))
86     return(1);
87   uc->init();
88   cmd= new cl_commander(app, cmdset, this);
89   cmd->init();
90   char *Config= get_sarg(0, "Config");
91   if (Config)
92     {
93       class cl_console *con= cmd->mk_console(Config, 0/*"/dev/tty"*/, this);
94       cmd->add_console(con);
95     }
96   if (cmd->cons->get_count() == 0)
97     {
98       fprintf(stderr, "No command console available.\n");
99       exit(1);
100     }
101   for (i= 0; i < in_files->count; i++)
102     {
103       char *fname= (char *)(in_files->at(i));
104       long l;
105       if ((l= uc->read_hex_file(fname)) >= 0)
106         {
107           cmd->all_printf("%ld words read from %s\n", l, fname);
108           fprintf(stderr, "%ld words read from %s\n", l, fname);
109         }
110       char *prompt;
111       if (arg_avail('P'))
112         cmd->all_print("\0", 1);
113       else
114         cmd->all_printf("%s", (prompt= get_sarg(0, "prompt"))?prompt:"> ") ;
115     }
116   return(0);
117 }
118
119 cl_sim::~cl_sim(void)
120 {
121   if (uc)
122     delete uc;
123 }
124
125 int
126 cl_sim::proc_arguments(int argc, char *argv[])
127 {
128   int i, c;
129   char *opts, *cp;
130
131   opts= (char*)malloc((accept_args?strlen(accept_args):0)+100);
132   strcpy(opts, "c:C:p:PX:vV");
133 #ifdef SOCKET_AVAIL
134   strcat(opts, "Z:r:");
135 #endif
136   if (accept_args)
137     strcat(opts, accept_args);
138   opterr= 0;
139   while((c= getopt(argc, argv, opts)) != -1)
140     switch (c)
141       {
142
143       case 'c':
144         arguments->add(new cl_prg_arg('c', 0, optarg));
145         break;
146
147       case 'C':
148         arguments->add(new cl_prg_arg(0, "Config", optarg));
149         break;
150
151 #ifdef SOCKET_AVAIL
152       case 'Z':
153         // By Sandeep
154         arguments->add(new cl_prg_arg('Z', 0, (long)1));
155         if (!optarg || !isdigit(*optarg))
156           fprintf(stderr, "expected portnumber to follow -Z\n");
157         else {
158           char *p;
159           long l= strtol(optarg, &p, 0);
160           arguments->add(new cl_prg_arg(0, "Zport", l));
161         }
162         break;
163 #endif
164
165       case 'p':
166         arguments->add(new cl_prg_arg(0, "prompt", optarg));
167         break;
168
169       case 'P':
170         arguments->add(new cl_prg_arg('P', 0, (long)1));
171         break;
172
173 #ifdef SOCKET_AVAIL
174       case 'r':
175         arguments->add(new cl_prg_arg('r', 0,
176                                       (long)strtol(optarg, NULL, 0)));
177         break;
178 #endif
179
180       case 'X':
181         {
182           double XTAL;
183           for (cp= optarg; *cp; *cp= toupper(*cp), cp++);
184           XTAL= strtod(optarg, &cp);
185           if (*cp == 'K')
186             XTAL*= 1e3;
187           if (*cp == 'M')
188             XTAL*= 1e6;
189           if (XTAL == 0)
190             {
191               fprintf(stderr, "Xtal frequency must be greather than 0\n");
192               exit(1);
193             }
194           arguments->add(new cl_prg_arg('X', 0, XTAL));
195           break;
196         }
197
198       case 'v':
199         printf("%s: %s\n", argv[0], VERSIONSTR);
200         exit(0);
201         break;
202
203       case 'V':
204         arguments->add(new cl_prg_arg('V', 0, (long)1));
205         break;
206
207       case '?':
208         if ((c= proc_arg(c, optarg)))
209           exit(c);
210         break;
211
212       default:
213         if ((c= proc_arg(c, optarg)))
214           exit(c);
215       }
216   if (!arg_avail("prompt"))
217     arguments->add(new cl_prg_arg(0, "prompt", "> "));
218
219   for (i= optind; i < argc; i++)
220     in_files->add(argv[i]);
221
222   free(opts);
223   return(0);
224 }
225
226 int
227 cl_sim::proc_arg(char arg, char *optarg)
228 {
229   return(0);
230 }
231
232 int
233 cl_sim::arg_avail(char name)
234 {
235   class cl_prg_arg *a;
236   int i;
237
238   for (i= 0; i < arguments->count; i++)
239     {
240       a= (class cl_prg_arg *)(arguments->at(i));
241       if (a->short_name == name)
242         return(1);
243     }
244   return(0);
245 }
246
247 int
248 cl_sim::arg_avail(char *name)
249 {
250   class cl_prg_arg *a;
251   int i;
252
253   for (i= 0; i < arguments->count; i++)
254     {
255       a= (class cl_prg_arg *)(arguments->at(i));
256       if (a->long_name &&
257           strcmp(a->long_name, name) == 0)
258         return(1);
259     }
260   return(0);
261 }
262
263 long long
264 cl_sim::get_iarg(char sname, char *lname)
265 {
266   class cl_prg_arg *a;
267   int i;
268
269   for (i= 0; i < arguments->count; i++)
270     {
271       a= (class cl_prg_arg *)(arguments->at(i));
272       if ((sname && a->short_name == sname) ||
273           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
274         {
275           long iv;
276           if (a->get_ivalue(&iv))
277             return(iv);
278           else
279             //FIXME
280             return(0);
281         }
282     }
283   return(0);
284 }
285
286 char *
287 cl_sim::get_sarg(char sname, char *lname)
288 {
289   class cl_prg_arg *a;
290   int i;
291
292   for (i= 0; i < arguments->count; i++)
293     {
294       a= (class cl_prg_arg *)(arguments->at(i));
295       if ((sname && a->short_name == sname) ||
296           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
297         return(a->get_svalue());
298     }
299   return(0);
300 }
301
302
303 double
304 cl_sim::get_farg(char sname, char *lname)
305 {
306   class cl_prg_arg *a;
307   int i;
308
309   for (i= 0; i < arguments->count; i++)
310     {
311       a= (class cl_prg_arg *)(arguments->at(i));
312       if ((sname && a->short_name == sname) ||
313           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
314         return(a->get_fvalue());
315     }
316   return(0);
317 }
318
319 void *
320 cl_sim::get_parg(char sname, char *lname)
321 {
322   class cl_prg_arg *a;
323   int i;
324
325   for (i= 0; i < arguments->count; i++)
326     {
327       a= (class cl_prg_arg *)(arguments->at(i));
328       if ((sname && a->short_name == sname) ||
329           (lname && a->long_name && strcmp(a->long_name, lname) == 0))
330         return(a->get_pvalue());
331     }
332   return(0);
333 }
334
335 class cl_uc *
336 cl_sim::mk_controller(void)
337 {
338   return(new cl_uc(this));
339 }
340
341 class cl_cmd_arg *
342 cl_sim::mk_cmd_int_arg(long long i)
343 {
344   class cl_cmd_arg *arg= new cl_cmd_int_arg(uc, i);
345   arg->init();
346   return(arg);
347 }
348
349 class cl_cmd_arg *
350 cl_sim::mk_cmd_sym_arg(char *s)
351 {
352   class cl_cmd_arg *arg= new cl_cmd_sym_arg(uc, s);
353   arg->init();
354   return(arg);
355 }
356
357 class cl_cmd_arg *
358 cl_sim::mk_cmd_str_arg(char *s)
359 {
360   class cl_cmd_arg *arg= new cl_cmd_str_arg(uc, s);
361   arg->init();
362   return(arg);
363 }
364
365 class cl_cmd_arg *
366 cl_sim::mk_cmd_bit_arg(class cl_cmd_arg *sfr, class cl_cmd_arg *bit)
367 {
368   class cl_cmd_arg *arg= new cl_cmd_bit_arg(uc, sfr, bit);
369   arg->init();
370   return(arg);
371 }
372
373 class cl_cmd_arg *
374 cl_sim::mk_cmd_array_arg(class cl_cmd_arg *aname, class cl_cmd_arg *aindex)
375 {
376   class cl_cmd_arg *arg= new cl_cmd_array_arg(uc, aname, aindex);
377   arg->init();
378   return(arg);
379 }
380
381
382 /*
383  * Main cycle of the simulator
384  */
385
386 int
387 cl_sim::main(void)
388 {
389   int done= 0;
390
391   while (!done &&
392          (state & SIM_QUIT) == 0)
393     {
394       if (state & SIM_GO)
395         {
396           uc->do_inst(-1);
397           if (cmd->input_avail())
398             {
399               done= cmd->proc_input();
400             }
401         }
402       else
403         {
404           cmd->wait_input();
405           done= cmd->proc_input();
406         }
407     }
408   return(0);
409 }
410
411 /*int
412 cl_sim::do_cmd(char *cmdstr, class cl_console *console)
413 {
414   class cl_cmdline *cmdline;
415   class cl_cmd *cm;
416   int retval= 0;
417
418   cmdline= new cl_cmdline(cmdstr, console);
419   cmdline->init();
420   cm= cmd->cmdset->get_cmd(cmdline);
421   if (cm)
422     retval= cm->work(cmdline, console);
423   delete cmdline;
424   if (cm)
425     return(retval);
426   return(console->interpret(cmdstr));
427 }*/
428
429 void
430 cl_sim::start(class cl_console *con)
431 {
432   state|= SIM_GO;
433   con->flags|= CONS_FROZEN;
434   cmd->frozen_console= con;
435   cmd->set_fd_set();
436 }
437
438 void
439 cl_sim::stop(int reason)
440 {
441   state&= ~SIM_GO;
442   if (cmd->frozen_console)
443     {
444       if (reason == resUSER &&
445           cmd->frozen_console->input_avail())
446         cmd->frozen_console->read_line();
447       cmd->frozen_console->printf("Stop at 0x%06x: (%d) ", uc->PC, reason);
448       switch (reason)
449         {
450         case resHALT:
451           cmd->frozen_console->printf("Halted\n");
452           break;
453         case resINV_ADDR:
454           cmd->frozen_console->printf("Invalid address\n");
455           break;
456         case resSTACK_OV:
457           cmd->frozen_console->printf("Stack overflow\n");
458           break;
459         case resBREAKPOINT:
460           cmd->frozen_console->printf("Breakpoint\n");
461           break;
462         case resINTERRUPT:
463           cmd->frozen_console->printf("Interrupt\n");
464           break;
465         case resWDTRESET:
466           cmd->frozen_console->printf("Watchdog reset\n");
467           break;
468         case resUSER:
469           cmd->frozen_console->printf("User stopped\n");
470           break;
471         case resINV_INST:
472           cmd->frozen_console->printf("Invalid instruction 0x%04x\n",
473                                       uc->get_mem(MEM_ROM, uc->PC));
474           break;
475         default:
476           cmd->frozen_console->printf("Unknown reason\n");
477           break;
478         }
479       cmd->frozen_console->printf("F 0x%06x\n", uc->PC); // for sdcdb
480       //if (cmd->actual_console != cmd->frozen_console)
481       cmd->frozen_console->flags&= ~CONS_FROZEN;
482       cmd->frozen_console->print_prompt();
483       cmd->frozen_console= 0;
484     }
485   cmd->set_fd_set();
486 }
487
488
489 /*
490  */
491
492 void
493 cl_sim::build_cmd_set(class cl_cmdset *cmdset)
494 {
495   class cl_cmd *cmd;
496   class cl_cmdset *cset;
497
498   {
499     cset= new cl_cmdset(this);
500     cset->init();
501     cset->add(cmd= new cl_conf_cmd("_no_parameters_", 0,
502 "conf               Configuration",
503 "long help of conf"));
504     cmd->init();
505     cset->add(cmd= new cl_conf_addmem_cmd("addmem", 0,
506 "conf addmem\n"
507 "                   Make memory",
508 "long help of conf addmem"));
509     cmd->init();
510   }
511   cmdset->add(cmd= new cl_super_cmd("conf", 0,
512 "conf subcommand    Information, see `conf' command for more help",
513 "long help of conf", cset));
514   cmd->init();
515
516   cmdset->add(cmd= new cl_state_cmd("state", 0,
517 "state              State of simulator",
518 "long help of state"));
519   cmd->init();
520
521   cmdset->add(cmd= new cl_file_cmd("file", 0,
522 "file \"FILE\"        Load FILE into ROM",
523 "long help of file"));
524   cmd->init();
525   cmd->add_name("load");
526
527   cmdset->add(cmd= new cl_dl_cmd("download", 0,
528 "download,dl          Load (intel.hex) data",
529 "long help of download"));
530   cmd->init();
531   cmd->add_name("dl");
532
533   {
534     cset= new cl_cmdset(this);
535     cset->init();
536     cset->add(cmd= new cl_info_bp_cmd("breakpoints", 0, 
537 "info breakpoints   Status of user-settable breakpoints",
538 "long help of info breakpoints"));
539     cmd->add_name("bp");
540     cmd->init();
541     cset->add(cmd= new cl_info_reg_cmd("registers", 0, 
542 "info registers     List of integer registers and their contents",
543 "long help of info registers"));
544     cmd->init();
545     cset->add(cmd= new cl_info_hw_cmd("hardware", 0, 
546 "info hardware cathegory\n"
547 "                   Status of hardware elements of the CPU",
548 "long help of info hardware"));
549     cmd->add_name("h    w");
550     cmd->init();
551   }
552   cmdset->add(cmd= new cl_super_cmd("info", 0,
553 "info subcommand    Information, see `info' command for more help",
554 "long help of info", cset));
555   cmd->init();
556
557   {
558     cset= new cl_cmdset(this);
559     cset->init();
560     cset->add(cmd= new cl_get_sfr_cmd("sfr", 0,
561 "get sfr address...\n"
562 "                   Get value of addressed SFRs",
563 "long help of get sfr"));
564     cmd->init();
565     cset->add(cmd= new cl_get_option_cmd("option", 0,
566 "get option name\n"
567 "                   Get value of an option",
568 "long help of get option"));
569     cmd->init();
570   }
571   cmdset->add(cmd= new cl_super_cmd("get", 0,
572 "get subcommand     Get, see `get' command for more help",
573 "long help of get", cset));
574   cmd->init();
575
576   {
577     cset= new cl_cmdset(this);
578     cset->init();
579     cset->add(cmd= new cl_set_mem_cmd("memory", 0,
580 "set memory memory_type address data...\n"
581 "                   Place list of data into memory",
582 "long help of set memory"));
583     cmd->init();
584     cset->add(cmd= new cl_set_bit_cmd("bit", 0,
585 "set bit addr 0|1   Set specified bit to 0 or 1",
586 "long help of set bit"));
587     cmd->init();
588     cset->add(cmd= new cl_set_port_cmd("port", 0,
589 "set port hw data   Set data connected to port",
590 "long help of set port"));
591     cmd->init();
592     cset->add(cmd= new cl_set_option_cmd("option", 0,
593 "set option name value\n"
594 "                   Set value of an option",
595 "long help of set option"));
596     cmd->init();
597   }
598   cmdset->add(cmd= new cl_super_cmd("set", 0,
599 "set subcommand     Set, see `set' command for more help",
600 "long help of set", cset));
601   cmd->init();
602
603   cmdset->add(cmd= new cl_timer_cmd("timer", 0,
604 "timer a|d|g|r|s|v id [direction|value]\n"
605 "                   Timer add|del|get|run|stop|value",
606 "timer add|create|make id [direction] -- create a new timer\n"
607 "timer del id -- delete a timer\n"
608 "timer get id -- list timers\n"
609 "timer run id -- turn a timer ON\n"
610 "timer stop id -- turn a timer OFF\n"
611 "timer value id val -- set value of a timer to `val'"));
612   cmd->init();
613
614   cmdset->add(cmd= new cl_run_cmd("run", 0,
615 "run [start [stop]] Go",
616 "long help of run"));
617   cmd->init();
618   cmd->add_name("go");
619   cmd->add_name("r");
620
621   cmdset->add(cmd= new cl_stop_cmd("stop", 0,
622 "stop               Stop",
623 "long help of stop"));
624   cmd->init();
625
626   cmdset->add(cmd= new cl_step_cmd("step", 0,
627 "step               Step",
628 "long help of step"));
629   cmd->init();
630   cmd->add_name("s");
631
632   cmdset->add(cmd= new cl_next_cmd("next", 0,
633 "next               Next",
634 "long help of next"));
635   cmd->init();
636   cmd->add_name("n");
637
638   cmdset->add(cmd= new cl_pc_cmd("pc", 0,
639 "pc [addr]          Set/get PC",
640 "long help of pc"));
641   cmd->init();
642
643   cmdset->add(cmd= new cl_reset_cmd("reset", 0,
644 "reset              Reset",
645 "long help of reset"));
646   cmd->init();
647
648   cmdset->add(cmd= new cl_dump_cmd("dump", 0,
649 "dump memory_type [start [stop [bytes_per_line]]]\n"
650 "                   Dump memory of specified type\n"
651 "dump bit...        Dump bits",
652 "long help of dump"));
653   cmd->init();
654
655   cmdset->add(cmd= new cl_di_cmd("di", 0,
656 "di [start [stop]]  Dump Internal RAM",
657 "long help of di"));
658   cmd->init();
659
660   cmdset->add(cmd= new cl_dx_cmd("dx", 0,
661 "dx [start [stop]]  Dump External RAM",
662 "long help of dx"));
663   cmd->init();
664
665   cmdset->add(cmd= new cl_ds_cmd("ds", 0,
666 "ds [start [stop]]  Dump SFR",
667 "long help of ds"));
668   cmd->init();
669
670   cmdset->add(cmd= new cl_dch_cmd("dch", 0,
671 "dch [start [stop]] Dump code in hex form",
672 "long help of dch"));
673   cmd->init();
674
675   cmdset->add(cmd= new cl_dc_cmd("dc", 0,
676 "dc [start [stop]]  Dump code in disass form",
677 "long help of dc"));
678   cmd->init();
679
680   cmdset->add(cmd= new cl_disassemble_cmd("disassemble", 0,
681 "disassemble [start [offset [lines]]]\n"
682 "                   Disassemble code",
683 "long help of disassemble"));
684   cmd->init();
685
686   cmdset->add(cmd= new cl_fill_cmd("fill", 0,
687 "fill memory_type start end data\n"
688 "                   Fill memory region with data",
689 "long help of fill"));
690   cmd->init();
691
692   cmdset->add(cmd= new cl_where_cmd("where", 0,
693 "where memory_type data...\n"
694 "                   Case unsensitive search for data",
695 "long help of where"));
696   cmd->init();
697
698   cmdset->add(cmd= new cl_Where_cmd("Where", 0,
699 "Where memory_type data...\n"
700 "                   Case sensitive search for data",
701 "long help of Where"));
702   cmd->init();
703
704   cmdset->add(cmd= new cl_break_cmd("break", 0,
705 "break addr [hit]   Set fix breakpoint\n"
706 "break mem_type r|w addr [hit]\n"
707 "                   Set fix event breakpoint",
708 "long help of break"));
709   cmd->init();
710
711   cmdset->add(cmd= new cl_tbreak_cmd("tbreak", 0,
712 "tbreak addr [hit]  Set temporary breakpoint\n"
713 "tbreak mem_type r|w addr [hit]\n"
714 "                   Set temporary event breakpoint",
715 "long help of tbreak"));
716   cmd->init();
717
718   cmdset->add(cmd= new cl_clear_cmd("clear", 0,
719 "clear [addr...]    Clear fix breakpoint",
720 "long help of clear"));
721   cmd->init();
722
723   cmdset->add(cmd= new cl_delete_cmd("delete", 0,
724 "delete [nr...]     Delete breakpoint(s)",
725 "long help of clear"));
726   cmd->init();
727
728   cmdset->add(cmd= new cl_help_cmd("help", 0,
729 "help [command]     Help about command(s)",
730 "long help of help"));
731   cmd->init();
732   cmd->add_name("?");
733
734   cmdset->add(cmd= new cl_quit_cmd("quit", 0,
735 "quit               Quit",
736 "long help of quit"));
737   cmd->init();
738
739   cmdset->add(cmd= new cl_kill_cmd("kill", 0,
740 "kill               Shutdown simulator",
741 "long help of kill"));
742   cmd->init();
743
744   {
745     cset= new cl_cmdset(this);
746     cset->init();
747     cset->add(cmd= new cl_show_copying_cmd("copying", 0, 
748 "show copying       Conditions for redistributing copies of uCsim",
749 "long help of show copying"));
750     cmd->init();
751     cset->add(cmd= new cl_show_warranty_cmd("warranty", 0, 
752 "show warranty      Various kinds of warranty you do not have",
753 "long help of show warranty"));
754     cmd->init();
755   }
756   cmdset->add(cmd= new cl_super_cmd("show", 0,
757 "show subcommand    Generic command for showing things about the uCsim",
758 "long help of show", cset));
759   cmd->init();
760
761   {
762     cset= new cl_cmdset(this);
763     cset->init();
764     cset->add(cmd= new cl_gui_start_cmd("start", 0, 
765 "gui start          Start interfacing with GUI tool",
766 "long help of gui start"));
767     cmd->init();
768     cset->add(cmd= new cl_gui_stop_cmd("stop", 0, 
769 "gui stop           Stop interfacing with GUI tool",
770 "long help of gui stop"));
771     cmd->init();
772   }
773   cmdset->add(cmd= new cl_super_cmd("gui", 0,
774 "gui subcommand     Operations to support GUI tools",
775 "long help of gui", cset));
776   cmd->init();
777 }
778
779
780 /* End of sim.src/sim.cc */