Version 0.3.2-pre1
[fw/sdcc] / sim / ucsim / sim.src / uc.cc
1 /*
2  * Simulator of microcontrollers (uc.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 <errno.h>
33 #include <ctype.h>
34 #include "i_string.h"
35
36 // prj
37 #include "globals.h"
38 #include "utils.h"
39
40 // cmd.src
41 #include "newcmdcl.h"
42 #include "cmduccl.h"
43 #include "bpcl.h"
44 #include "getcl.h"
45 #include "setcl.h"
46 #include "infocl.h"
47 #include "timercl.h"
48
49 // local, sim.src
50 #include "uccl.h"
51 #include "hwcl.h"
52 #include "memcl.h"
53 #include "simcl.h"
54 #include "itsrccl.h"
55
56
57 /*
58  * Clock counter
59  */
60
61 cl_ticker::cl_ticker(int adir, int in_isr, char *aname)
62 {
63   options= TICK_RUN;
64   if (in_isr)
65     options|= TICK_INISR;
66   dir= adir;
67   ticks= 0;
68   name= aname?strdup(aname):0;
69 }
70
71 cl_ticker::~cl_ticker(void)
72 {
73   if (name)
74     free(name);
75 }
76
77 int
78 cl_ticker::tick(int nr)
79 {
80   if (options&TICK_RUN)
81     ticks+= dir*nr;
82   return(ticks);
83 }
84
85 double
86 cl_ticker::get_rtime(double xtal)
87 {
88   double d;
89
90   d= (double)ticks/xtal;
91   return(d);
92 }
93
94 void
95 cl_ticker::dump(int nr, double xtal, class cl_console *con)
96 {
97   con->printf("timer #%d(\"%s\") %s%s: %g sec (%lu clks)\n",
98               nr, name?name:"unnamed",
99               (options&TICK_RUN)?"ON":"OFF",
100               (options&TICK_INISR)?",ISR":"",
101               get_rtime(xtal), ticks);
102 }
103
104
105 /*
106  * Abstract microcontroller
107  ******************************************************************************
108  */
109
110 cl_uc::cl_uc(class cl_sim *asim):
111   cl_base()
112 {
113   int i;
114   sim = asim;
115   mems= new cl_list(MEM_TYPES, 1);
116   hws = new cl_hws();
117   options= new cl_list(2, 2);
118   for (i= MEM_ROM; i < MEM_TYPES; i++)
119     mems->add(0);
120   ticks= new cl_ticker(+1, 0, "time");
121   isr_ticks= new cl_ticker(+1, TICK_INISR, "isr");
122   idle_ticks= new cl_ticker(+1, TICK_IDLE, "idle");
123   counters= new cl_list(2, 2);
124   it_levels= new cl_list(2, 2);
125   it_sources= new cl_list(2, 2);
126   class it_level *il= new it_level(-1, 0, 0, 0);
127   it_levels->push(il);
128   st_ops= new cl_list(2, 2);
129   sp_max= 0;
130   sp_avg= 0;
131 }
132
133
134 cl_uc::~cl_uc(void)
135 {
136   delete mems;
137   delete hws;
138   delete options;
139   delete ticks;
140   delete isr_ticks;
141   delete idle_ticks;
142   delete counters;
143   delete fbrk;
144   delete ebrk;
145   delete it_levels;
146   delete it_sources;
147   delete st_ops;
148 }
149
150
151 int
152 cl_uc::init(void)
153 {
154   int mc, i;
155
156   cl_base::init();
157   if (!(sim->app->args->arg_avail('X')) ||
158       sim->app->args->get_farg('X', 0) == 0)
159     xtal= 11059200;
160   else
161     xtal= sim->app->args->get_farg('X', 0);
162   for (mc= MEM_ROM; mc < MEM_TYPES; mc++)
163     {
164       class cl_mem *m= mk_mem((enum mem_class)mc,
165                               get_id_string(mem_classes, mc));
166       mems->put_at(mc, m);
167     }
168   ebrk= new brk_coll(2, 2, (class cl_rom *)mem(MEM_ROM));
169   fbrk= new brk_coll(2, 2, (class cl_rom *)mem(MEM_ROM));
170   fbrk->Duplicates= DD_FALSE;
171   brk_counter= 0;
172   mk_hw_elements();
173   reset();
174   class cl_cmdset *cs= sim->app->get_commander()->cmdset;
175   build_cmdset(cs);
176
177   for (i= 0; i < sim->app->in_files->count; i++)
178     {
179       char *fname= (char *)(sim->app->in_files->at(i));
180       long l;
181       if ((l= read_hex_file(fname)) >= 0)
182         {
183           sim->app->get_commander()->all_printf("%ld words read from %s\n",
184                                                 l, fname);
185         }
186     }
187   return(0);
188 }
189
190 char *
191 cl_uc::id_string(void)
192 {
193   return("unknown microcontroller");
194 }
195
196 void
197 cl_uc::reset(void)
198 {
199   class it_level *il;
200
201   PC= 0;
202   state = stGO;
203   ticks->ticks= 0;
204   isr_ticks->ticks= 0;
205   idle_ticks->ticks= 0;
206   /*FIXME should we clear user counters?*/
207   il= (class it_level *)(it_levels->top());
208   while (il &&
209          il->level >= 0)
210     {
211       il= (class it_level *)(it_levels->pop());
212       delete il;
213       il= (class it_level *)(it_levels->top());
214     }
215   sp_max= 0;
216   sp_avg= 0;
217 }
218
219 /*
220  * Making elements
221  */
222
223 class cl_mem *
224 cl_uc::mk_mem(enum mem_class type, char *class_name)
225 {
226   class cl_mem *m;
227
228   if (get_mem_size(type) <= 0)
229     return(0);
230   if (type == MEM_ROM)
231     m= new cl_rom(get_mem_size(type), get_mem_width(type));
232   else
233     m= new cl_mem(type, get_id_string(mem_classes, type),
234                   get_mem_size(type), get_mem_width(type));
235   m->init();
236   return(m);
237 }
238
239 t_addr
240 cl_uc::get_mem_size(enum mem_class type)
241 {
242   switch (type)
243     {
244     case MEM_ROM: return(0x10000);
245     case MEM_XRAM: return(0x10000);
246     case MEM_IRAM: return(0x100);
247     case MEM_SFR: return(0x100);
248     case MEM_TYPES:
249     default: return(0);
250     }
251   return(0);
252 }
253
254 int
255 cl_uc::get_mem_width(enum mem_class type)
256 {
257   return(8);
258 }
259
260 void
261 cl_uc::mk_hw_elements(void)
262 {
263 }
264
265 void
266 cl_uc::build_cmdset(class cl_cmdset *cmdset)
267 {
268   class cl_cmd *cmd;
269   class cl_cmdset *cset;
270
271   cmdset->add(cmd= new cl_state_cmd("state", 0,
272 "state              State of microcontroller",
273 "long help of state"));
274   cmd->init();
275
276   cmdset->add(cmd= new cl_file_cmd("file", 0,
277 "file \"FILE\"        Load FILE into ROM",
278 "long help of file"));
279   cmd->init();
280   cmd->add_name("load");
281
282   cmdset->add(cmd= new cl_dl_cmd("download", 0,
283 "download,dl          Load (intel.hex) data",
284 "long help of download"));
285   cmd->init();
286   cmd->add_name("dl");
287
288   cmdset->add(cmd= new cl_pc_cmd("pc", 0,
289 "pc [addr]          Set/get PC",
290 "long help of pc"));
291   cmd->init();
292
293   cmdset->add(cmd= new cl_reset_cmd("reset", 0,
294 "reset              Reset",
295 "long help of reset"));
296   cmd->init();
297
298   cmdset->add(cmd= new cl_dump_cmd("dump", 0,
299 "dump memory_type [start [stop [bytes_per_line]]]\n"
300 "                   Dump memory of specified type\n"
301 "dump bit...        Dump bits",
302 "long help of dump"));
303   cmd->init();
304
305   cmdset->add(cmd= new cl_di_cmd("di", 0,
306 "di [start [stop]]  Dump Internal RAM",
307 "long help of di"));
308   cmd->init();
309
310   cmdset->add(cmd= new cl_dx_cmd("dx", 0,
311 "dx [start [stop]]  Dump External RAM",
312 "long help of dx"));
313   cmd->init();
314
315   cmdset->add(cmd= new cl_ds_cmd("ds", 0,
316 "ds [start [stop]]  Dump SFR",
317 "long help of ds"));
318   cmd->init();
319
320   cmdset->add(cmd= new cl_dch_cmd("dch", 0,
321 "dch [start [stop]] Dump code in hex form",
322 "long help of dch"));
323   cmd->init();
324
325   cmdset->add(cmd= new cl_dc_cmd("dc", 0,
326 "dc [start [stop]]  Dump code in disass form",
327 "long help of dc"));
328   cmd->init();
329
330   cmdset->add(cmd= new cl_disassemble_cmd("disassemble", 0,
331 "disassemble [start [offset [lines]]]\n"
332 "                   Disassemble code",
333 "long help of disassemble"));
334   cmd->init();
335
336   cmdset->add(cmd= new cl_fill_cmd("fill", 0,
337 "fill memory_type start end data\n"
338 "                   Fill memory region with data",
339 "long help of fill"));
340   cmd->init();
341
342   cmdset->add(cmd= new cl_where_cmd("where", 0,
343 "where memory_type data...\n"
344 "                   Case unsensitive search for data",
345 "long help of where"));
346   cmd->init();
347
348   cmdset->add(cmd= new cl_Where_cmd("Where", 0,
349 "Where memory_type data...\n"
350 "                   Case sensitive search for data",
351 "long help of Where"));
352   cmd->init();
353
354   cmdset->add(cmd= new cl_break_cmd("break", 0,
355 "break addr [hit]   Set fix breakpoint\n"
356 "break mem_type r|w addr [hit]\n"
357 "                   Set fix event breakpoint",
358 "long help of break"));
359   cmd->init();
360
361   cmdset->add(cmd= new cl_tbreak_cmd("tbreak", 0,
362 "tbreak addr [hit]  Set temporary breakpoint\n"
363 "tbreak mem_type r|w addr [hit]\n"
364 "                   Set temporary event breakpoint",
365 "long help of tbreak"));
366   cmd->init();
367
368   cmdset->add(cmd= new cl_clear_cmd("clear", 0,
369 "clear [addr...]    Clear fix breakpoint",
370 "long help of clear"));
371   cmd->init();
372
373   cmdset->add(cmd= new cl_delete_cmd("delete", 0,
374 "delete [nr...]     Delete breakpoint(s)",
375 "long help of clear"));
376   cmd->init();
377
378   {
379     cset= new cl_cmdset();
380     cset->init();
381     cset->add(cmd= new cl_get_sfr_cmd("sfr", 0,
382 "get sfr address...\n"
383 "                   Get value of addressed SFRs",
384 "long help of get sfr"));
385     cmd->init();
386     cset->add(cmd= new cl_get_option_cmd("option", 0,
387 "get option name\n"
388 "                   Get value of an option",
389 "long help of get option"));
390     cmd->init();
391   }
392   cmdset->add(cmd= new cl_super_cmd("get", 0,
393 "get subcommand     Get, see `get' command for more help",
394 "long help of get", cset));
395   cmd->init();
396
397   {
398     cset= new cl_cmdset();
399     cset->init();
400     cset->add(cmd= new cl_set_mem_cmd("memory", 0,
401 "set memory memory_type address data...\n"
402 "                   Place list of data into memory",
403 "long help of set memory"));
404     cmd->init();
405     cset->add(cmd= new cl_set_bit_cmd("bit", 0,
406 "set bit addr 0|1   Set specified bit to 0 or 1",
407 "long help of set bit"));
408     cmd->init();
409     cset->add(cmd= new cl_set_port_cmd("port", 0,
410 "set port hw data   Set data connected to port",
411 "long help of set port"));
412     cmd->init();
413     cset->add(cmd= new cl_set_option_cmd("option", 0,
414 "set option name value\n"
415 "                   Set value of an option",
416 "long help of set option"));
417     cmd->init();
418   }
419   cmdset->add(cmd= new cl_super_cmd("set", 0,
420 "set subcommand     Set, see `set' command for more help",
421 "long help of set", cset));
422   cmd->init();
423
424   {
425     cset= new cl_cmdset();
426     cset->init();
427     cset->add(cmd= new cl_info_bp_cmd("breakpoints", 0, 
428 "info breakpoints   Status of user-settable breakpoints",
429 "long help of info breakpoints"));
430     cmd->add_name("bp");
431     cmd->init();
432     cset->add(cmd= new cl_info_reg_cmd("registers", 0, 
433 "info registers     List of integer registers and their contents",
434 "long help of info registers"));
435     cmd->init();
436     cset->add(cmd= new cl_info_hw_cmd("hardware", 0, 
437 "info hardware cathegory\n"
438 "                   Status of hardware elements of the CPU",
439 "long help of info hardware"));
440     cmd->add_name("h    w");
441     cmd->init();
442   }
443   cmdset->add(cmd= new cl_super_cmd("info", 0,
444 "info subcommand    Information, see `info' command for more help",
445 "long help of info", cset));
446   cmd->init();
447
448   cmdset->add(cmd= new cl_timer_cmd("timer", 0,
449 "timer a|d|g|r|s|v id [direction|value]\n"
450 "                   Timer add|del|get|run|stop|value",
451 "timer add|create|make id [direction] -- create a new timer\n"
452 "timer del id -- delete a timer\n"
453 "timer get id -- list timers\n"
454 "timer run id -- turn a timer ON\n"
455 "timer stop id -- turn a timer OFF\n"
456 "timer value id val -- set value of a timer to `val'"));
457   cmd->init();
458 }
459
460
461 /*
462  * Read/write simulated memory
463  */
464
465 ulong
466 cl_uc::read_mem(enum mem_class type, t_mem addr)
467 {
468   class cl_mem *m;
469
470   if ((m= (class cl_mem*)mems->at(type)))
471     return(m->read(addr));
472   //FIXME
473 fprintf(stderr, "cl_uc::read_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
474   return(0);
475 }
476
477 ulong
478 cl_uc::get_mem(enum mem_class type, t_addr addr)
479 {
480   class cl_mem *m;
481
482   if ((m= (class cl_mem*)mems->at(type)))
483     return(m->get(addr));
484   //FIXME
485 printf("cl_uc::get_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
486   return(0);
487 }
488
489 void
490 cl_uc::write_mem(enum mem_class type, t_addr addr, t_mem val)
491 {
492   class cl_mem *m;
493
494   if ((m= (class cl_mem*)mems->at(type)))
495     {
496       m->write(addr, &val);
497       //m->mem[addr]= val;
498     }
499   //FIXME
500 else printf("cl_uc::write_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
501 }
502
503 void
504 cl_uc::set_mem(enum mem_class type, t_addr addr, t_mem val)
505 {
506   class cl_mem *m;
507
508   if ((m= (class cl_mem*)mems->at(type)))
509     m->set(addr, val);
510   //FIXME
511 else printf("cl_uc::set_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
512 }
513
514 class cl_mem *
515 cl_uc::mem(enum mem_class type)
516 {
517   if (mems->count < type)
518     //FIXME
519 {printf("TROUBLE\n");    return(0);
520 }
521   return((class cl_mem *)(mems->at(type)));
522 }
523
524 class cl_mem *
525 cl_uc::mem(char *class_name)
526 {
527   int i, found= 0;
528   char *mcn, *n, *s;
529
530   if (!class_name)
531     return(0);
532   s= n= strdup(class_name);
533   while (*s)
534     {
535       *s= toupper(*s);
536       s++;
537     }
538   if (!class_name ||
539       !(*class_name))
540     return(0);
541   for (i= 0; !found && i < mems->count; i++)
542     {
543       cl_mem *m= (cl_mem *)(mems->at(i));
544       if (!m ||
545           !m->class_name ||
546           !(*(m->class_name)))
547         continue;
548       s= mcn= strdup(m->class_name);
549       while (*s)
550         {
551           *s= toupper(*s);
552           s++;
553         }
554       if (strstr(/*m->class_name*/mcn,/*class_name*/n) == /*m->class_name*/mcn)
555         found= 1;
556       free(mcn);
557       if (found)
558         {
559           free(n);
560           return(m);
561         }
562     }
563   free(n);
564   return(0);
565 }
566
567 /*TYPE_UBYTE *
568 cl_uc::MEM(enum mem_class type)
569 {
570   class cl_mem *m;
571
572   if ((m= mem(type)) == 0)
573     //FIXME
574 {printf("TROUBLE\n");    return(0);
575 }
576   return((TYPE_UBYTE *)(m->mem));
577 }*/
578
579
580 /* Local function for `read_hex_file' method to read some bytes */
581
582 static long
583 ReadInt(FILE *f, bool *ok, int bytes)
584 {
585   char s2[3];
586   long l= 0;
587
588   *ok= DD_FALSE;
589   while (bytes)
590     {
591       if (fscanf(f, "%2c", &s2[0]) == EOF)
592         return(0);
593       s2[2]= '\0';
594       l= l*256 + strtol(s2, NULL, 16);
595       bytes--;
596     }
597   *ok= DD_TRUE;
598   return(l);
599 }
600
601
602 /* 
603  * Reading intel hexa file into EROM
604  *____________________________________________________________________________
605  *
606  * If parameter is a NULL pointer, this function reads data from `cmd_in'
607  *
608  */
609
610 long
611 cl_uc::read_hex_file(const char *name)
612 {
613   FILE *f;
614   int c;
615   long written= 0, recnum= 0;
616
617   uchar dnum;     // data number
618   uchar rtyp=0;   // record type
619   uint  addr= 0;  // address
620   uchar rec[300]; // data record
621   uchar sum ;     // checksum
622   uchar chk ;     // check
623   int  i;
624   bool ok, get_low= 1;
625   uchar low= 0, high;
626
627   if (!name)
628     {
629       sim->app->get_commander()->
630         printf("cl_uc::read_hex_file File name not specified\n");
631       return(-1);
632     }
633   else
634     if ((f= fopen(name, "r")) == NULL)
635       {
636         fprintf(stderr, "Can't open `%s': %s\n", name, strerror(errno));
637         return(-1);
638       }
639
640   //memset(inst_map, '\0', sizeof(inst_map));
641   ok= DD_TRUE;
642   while (ok &&
643          rtyp != 1)
644     {
645       while (((c= getc(f)) != ':') &&
646              (c != EOF)) ;
647       if (c != ':')
648         {fprintf(stderr, ": not found\n");break;}
649       recnum++;
650       dnum= ReadInt(f, &ok, 1);//printf("dnum=%02x",dnum);
651       chk = dnum;
652       addr= ReadInt(f, &ok, 2);//printf("addr=%04x",addr);
653       chk+= (addr & 0xff);
654       chk+= ((addr >> 8) & 0xff);
655       rtyp= ReadInt(f, &ok, 1);//printf("rtyp=%02x ",rtyp);
656       chk+= rtyp;
657       for (i= 0; ok && (i < dnum); i++)
658         {
659           rec[i]= ReadInt(f, &ok, 1);//printf("%02x",rec[i]);
660           chk+= rec[i];
661         }
662       if (ok)
663         {
664           sum= ReadInt(f, &ok, 1);//printf(" sum=%02x\n",sum);
665           if (ok)
666             {
667               if (((sum + chk) & 0xff) == 0)
668                 {
669                   if (rtyp == 0)
670                     {
671                       if (get_mem_width(MEM_ROM) > 8)
672                         addr/= 2;
673                       for (i= 0; i < dnum; i++)
674                         {
675                           if (get_mem_width(MEM_ROM) <= 8)
676                             {
677                               set_mem(MEM_ROM, addr, rec[i]);
678                               addr++;
679                               written++;
680                             }
681                           else if (get_mem_width(MEM_ROM) <= 16)
682                             {
683                               if (get_low)
684                                 {
685                                   low= rec[i];
686                                   get_low= 0;
687                                 }
688                               else
689                                 {
690                                   high= rec[i];
691                                   set_mem(MEM_ROM, addr, (high*256)+low);
692                                   addr++;
693                                   written++;
694                                   get_low= 1;
695                                 }
696                             }
697                         }
698                     }
699                   else
700                     if (sim->app->args->get_iarg('V', 0) &&
701                         rtyp != 1)
702                       sim->app->get_commander()->
703                         printf("Unknown record type %d(0x%x)\n", rtyp, rtyp);
704                 }
705               else
706                 if (sim->app->args->get_iarg('V', 0))
707                   sim->app->get_commander()->
708                     printf("Checksum error (%x instead of %x) in "
709                            "record %ld.\n", chk, sum, recnum);
710             }
711           else
712             if (sim->app->args->get_iarg('V', 0))
713               sim->app->get_commander()->
714                 printf("Read error in record %ld.\n", recnum);
715         }
716     }
717   if (get_mem_width(MEM_ROM) > 8 &&
718       !get_low)
719     set_mem(MEM_ROM, addr, low);
720
721   if (name)
722     fclose(f);
723   if (sim->app->args->get_iarg('V', 0))
724     sim->app->get_commander()->printf("%ld records have been read\n", recnum);
725   analyze(0);
726   return(written);
727 }
728
729
730 /*
731  * Handling instruction map
732  *
733  * `inst_at' is checking if the specified address is in instruction
734  * map and `set_inst_at' marks the address in the map and
735  * `del_inst_at' deletes the mark. `there_is_inst' cheks if there is
736  * any mark in the map
737  */
738
739 bool
740 cl_uc::inst_at(t_addr addr)
741 {
742   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
743   
744   if (!rom)
745     return(0);
746   return(rom->inst_map->get(addr));
747 }
748
749 void
750 cl_uc::set_inst_at(t_addr addr)
751 {
752   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
753   
754   if (rom)
755     rom->inst_map->set(addr);
756 }
757
758 void
759 cl_uc::del_inst_at(t_addr addr)
760 {
761   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
762   
763   if (rom)
764     rom->inst_map->clear(addr);
765 }
766
767 bool
768 cl_uc::there_is_inst(void)
769 {
770   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
771   
772   if (!rom)
773     return(0);
774   return(!(rom->inst_map->empty()));
775 }
776
777
778 /*
779  * Manipulating HW elements of the CPU
780  *****************************************************************************
781  */
782
783 /* Register callback hw objects for mem read/write */
784
785 void
786 cl_uc::register_hw_read(enum mem_class type, t_addr addr, class cl_hw *hw)
787 {
788   class cl_mem *m;
789   class cl_memloc *l;
790
791   if ((m= (class cl_mem*)mems->at(type)))
792     {
793       if ((l= m->read_locs->get_loc(addr)) == 0)
794         {
795           l= new cl_memloc(addr);
796           l->init();
797           m->read_locs->add(l);
798         }
799       l->hws->add(hw);
800     }
801   else
802     printf("cl_uc::register_hw_read TROUBLE\n");
803 }
804
805 void
806 cl_uc::register_hw_write(enum mem_class type, t_addr addr, class cl_hw *hw)
807 {
808 }
809
810 /* Looking for a specific HW element */
811
812 class cl_hw *
813 cl_uc::get_hw(enum hw_cath cath, int *idx)
814 {
815   class cl_hw *hw= 0;
816   int i= 0;
817
818   if (idx)
819     i= *idx;
820   for (; i < hws->count; i++)
821     {
822       hw= (class cl_hw *)(hws->at(i));
823       if (hw->cathegory == cath)
824         break;
825     }
826   if (i >= hws->count)
827     return(0);
828   if (idx)
829     *idx= i;
830   return(hw);
831 }
832
833 class cl_hw *
834 cl_uc::get_hw(char *id_string, int *idx)
835 {
836   class cl_hw *hw= 0;
837   int i= 0;
838
839   if (idx)
840     i= *idx;
841   for (; i < hws->count; i++)
842     {
843       hw= (class cl_hw *)(hws->at(i));
844       if (strstr(hw->id_string, id_string) == hw->id_string)
845         break;
846     }
847   if (i >= hws->count)
848     return(0);
849   if (idx)
850     *idx= i;
851   return(hw);
852 }
853
854 class cl_hw *
855 cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
856 {
857   class cl_hw *hw;
858   int i= 0;
859
860   if (idx)
861     i= *idx;
862   hw= get_hw(cath, &i);
863   while (hw &&
864          hw->id != hwid)
865     {
866       i++;
867       hw= get_hw(cath, &i);
868     }
869   if (hw && 
870       idx)
871     *idx= i;
872   return(hw);
873 }
874
875 class cl_hw *
876 cl_uc::get_hw(char *id_string, int hwid, int *idx)
877 {
878   class cl_hw *hw;
879   int i= 0;
880
881   if (idx)
882     i= *idx;
883   hw= get_hw(id_string, &i);
884   while (hw &&
885          hw->id != hwid)
886     {
887       i++;
888       hw= get_hw(id_string, &i);
889     }
890   if (hw && 
891       idx)
892     *idx= i;
893   return(hw);
894 }
895
896
897 /*
898  * Help of the command interpreter
899  */
900
901 struct dis_entry *
902 cl_uc::dis_tbl(void)
903 {
904   static struct dis_entry empty= { 0, 0, 0, 0, NULL };
905   return(&empty);
906 }
907
908 struct name_entry *
909 cl_uc::sfr_tbl(void)
910 {
911   static struct name_entry empty= { 0, 0 };
912   return(&empty);
913 }
914
915 struct name_entry *
916 cl_uc::bit_tbl(void)
917 {
918   static struct name_entry empty= { 0, 0 };
919   return(&empty);
920 }
921
922 char *
923 cl_uc::disass(t_addr addr, char *sep)
924 {
925   char *buf;
926
927   buf= (char*)malloc(100);
928   strcpy(buf, "uc::do_disass unimplemented\n");
929   return(buf);
930 }
931
932 void
933 cl_uc::print_disass(t_addr addr, class cl_console *con)
934 {
935   char *dis;
936   class cl_brk *b;
937   int i;
938   class cl_mem *rom= mem(MEM_ROM);
939   t_mem code= get_mem(MEM_ROM, addr);
940
941   if (!rom)
942     return;
943   b= fbrk_at(addr);
944   dis= disass(addr, NULL);
945   if (b)
946     con->printf("%c", (b->perm == brkFIX)?'F':'D');
947   else
948     con->printf(" ");
949   con->printf("%c ", inst_at(addr)?' ':'?');
950   con->printf(rom->addr_format, addr); con->printf(" ");
951   con->printf(rom->data_format, code);
952   for (i= 1; i < inst_length(code); i++)
953     {
954       con->printf(" ");
955       con->printf(rom->data_format, get_mem(MEM_ROM, addr+i));
956     }
957   int li= longest_inst();
958   while (i < li)
959     {
960       int j;
961       j= rom->width/4 + ((rom->width%4)?1:0) + 1;
962       while (j)
963         con->printf(" "), j--;
964       i++;
965     }
966   con->printf(" %s\n", dis);
967   free(dis);
968 }
969
970 void
971 cl_uc::print_regs(class cl_console *con)
972 {
973   con->printf("No registers\n");
974 }
975
976 int
977 cl_uc::inst_length(t_mem code)
978 {
979   struct dis_entry *tabl= dis_tbl();
980   int i;
981
982   for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
983   return(tabl[i].mnemonic?tabl[i].length:1);     
984 }
985
986 int
987 cl_uc::longest_inst(void)
988 {
989   struct dis_entry *de= dis_tbl();
990   int max= 0;
991
992   while (de &&
993          de->mnemonic)
994     {
995       if (de->length > max)
996         max= de->length;
997       de++;
998     }
999   return(max);
1000 }
1001
1002 bool
1003 cl_uc::get_name(t_addr addr, struct name_entry tab[], char *buf)
1004 {
1005   int i;
1006
1007   i= 0;
1008   while (tab[i].name &&
1009          (!(tab[i].cpu_type & type) ||
1010          (tab[i].addr != addr)))
1011     i++;
1012   if (tab[i].name)
1013     strcpy(buf, tab[i].name);
1014   return(tab[i].name != NULL);
1015 }
1016
1017 char *
1018 cl_uc::symbolic_bit_name(t_addr bit_address,
1019                          class cl_mem *mem,
1020                          t_addr mem_addr,
1021                          t_mem bit_mask)
1022 {
1023   char *sym_name= 0;
1024   int i;
1025
1026   i= 0;
1027   while (bit_tbl()[i].name &&
1028          (bit_tbl()[i].addr != bit_address))
1029     i++;
1030   if (bit_tbl()[i].name)
1031     {
1032       sym_name= strdup(bit_tbl()[i].name);
1033       return(sym_name);
1034     }
1035
1036   if (mem &&
1037       mem->class_name &&
1038       strstr(mem->class_name, "sfr") == mem->class_name)
1039     {
1040       i= 0;
1041       while (sfr_tbl()[i].name &&
1042              (sfr_tbl()[i].addr != mem_addr))
1043         i++;
1044       if (sfr_tbl()[i].name)
1045         sym_name= strdup(sfr_tbl()[i].name);
1046       else
1047         sym_name= 0;
1048     }
1049   if (!sym_name)
1050     {
1051       sym_name= (char *)malloc(16);
1052       sprintf(sym_name, mem?(mem->addr_format):"0x%06x", mem_addr);
1053     }
1054   sym_name= (char *)realloc(sym_name, strlen(sym_name)+2);
1055   strcat(sym_name, ".");
1056   i= 0;
1057   while (bit_mask > 1)
1058     {
1059       bit_mask>>=1;
1060       i++;
1061     }
1062   char bitnumstr[10];
1063   sprintf(bitnumstr, "%1d", i);
1064   strcat(sym_name, bitnumstr);
1065   return(sym_name);
1066 }
1067
1068
1069 /*
1070  * Execution
1071  */
1072
1073 int
1074 cl_uc::tick(int cycles)
1075 {
1076   class cl_hw *hw;
1077   int i, cpc= clock_per_cycle();
1078
1079   // increase time
1080   ticks->tick(cycles * cpc);
1081   class it_level *il= (class it_level *)(it_levels->top());
1082   if (il->level >= 0)
1083     isr_ticks->tick(cycles * cpc);
1084   if (state == stIDLE)
1085     idle_ticks->tick(cycles * cpc);
1086   for (i= 0; i < counters->count; i++)
1087     {
1088       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1089       if (t)
1090         {
1091           if ((t->options&TICK_INISR) ||
1092               il->level < 0)
1093             t->tick(cycles * cpc);
1094         }
1095     }
1096
1097   // tick hws
1098   for (i= 0; i < hws->count; i++)
1099     {
1100       hw= (class cl_hw *)(hws->at(i));
1101       if (hw->flags & HWF_INSIDE)
1102         hw->tick(cycles);
1103     }
1104   return(0);
1105 }
1106
1107 class cl_ticker *
1108 cl_uc::get_counter(int nr)
1109 {
1110   if (nr >= counters->count)
1111     return(0);
1112   return((class cl_ticker *)(counters->at(nr)));
1113 }
1114
1115 class cl_ticker *
1116 cl_uc::get_counter(char *name)
1117 {
1118   int i;
1119
1120   if (!name)
1121     return(0);
1122   for (i= 0; i < counters->count; i++)
1123     {
1124       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1125       if (t &&
1126           t->name &&
1127           strcmp(t->name, name) == 0)
1128         return(t);
1129     }
1130   return(0);
1131 }
1132
1133 void
1134 cl_uc::add_counter(class cl_ticker *ticker, int nr)
1135 {
1136   while (counters->count <= nr)
1137     counters->add(0);
1138   counters->put_at(nr, ticker);
1139 }
1140
1141 void
1142 cl_uc::add_counter(class cl_ticker *ticker, char */*name*/)
1143 {
1144   int i;
1145
1146   if (counters->count < 1)
1147     counters->add(0);
1148   for (i= 1; i < counters->count; i++)
1149     {
1150       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1151       if (!t)
1152         {
1153           counters->put_at(i, ticker);
1154           return;
1155         }
1156     }
1157   counters->add(ticker);
1158 }
1159
1160 void
1161 cl_uc::del_counter(int nr)
1162 {
1163   class cl_ticker *t;
1164
1165   if (nr >= counters->count)
1166     return;
1167   if ((t= (class cl_ticker *)(counters->at(0))) != 0)
1168     delete t;
1169   counters->put_at(nr, 0);
1170 }
1171
1172 void
1173 cl_uc::del_counter(char *name)
1174 {
1175   int i;
1176   
1177   if (!name)
1178     return;
1179   for (i= 0; i < counters->count; i++)
1180     {
1181       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1182       if (t &&
1183           t->name &&
1184           strcmp(t->name, name) == 0)
1185         {
1186           delete t;
1187           counters->put_at(i, 0);
1188           return;
1189         }
1190     }
1191 }
1192
1193 /*
1194  * Fetch without checking for breakpoint hit
1195  */
1196
1197 t_mem
1198 cl_uc::fetch(void)
1199 {
1200   ulong code;
1201
1202   code= read_mem(MEM_ROM, PC);
1203   PC++;
1204   if (PC >= get_mem_size(MEM_ROM))
1205     PC= 0;
1206   return(code);
1207 }
1208
1209 /*
1210  * Fetch but checking for breakpoint hit first
1211  */
1212
1213 bool
1214 cl_uc::fetch(t_mem *code)
1215 {
1216   class cl_brk *brk;
1217   int idx;
1218
1219   if (!code)
1220     return(0);
1221   if (sim->state & SIM_GO)
1222     {
1223       if ((brk= fbrk->get_bp(PC, &idx)) &&
1224           (brk->do_hit()))
1225         {
1226           if (brk->perm == brkDYNAMIC)
1227             fbrk->del_bp(PC);
1228           return(1);
1229         }
1230     }
1231   *code= fetch();
1232   return(0);
1233 }
1234
1235 int
1236 cl_uc::do_inst(int step)
1237 {
1238   int res= resGO;
1239
1240   if (step < 0)
1241     step= 1;
1242   while (step-- &&
1243          res == resGO)
1244     {
1245       pre_inst();
1246       res= exec_inst();
1247       post_inst();
1248     }
1249   if (res != resGO)
1250     sim->stop(res);
1251   return(res);
1252 }
1253
1254 void
1255 cl_uc::pre_inst(void)
1256 {}
1257
1258 int
1259 cl_uc::exec_inst(void)
1260 {
1261   return(resGO);
1262 }
1263
1264 void
1265 cl_uc::post_inst(void)
1266 {}
1267
1268
1269 /*
1270  * Time related functions
1271  */
1272
1273 double
1274 cl_uc::get_rtime(void)
1275 {
1276   /*  double d;
1277
1278   d= (double)ticks/xtal;
1279   return(d);*/
1280   return(ticks->get_rtime(xtal));
1281 }
1282
1283 int
1284 cl_uc::clock_per_cycle(void)
1285 {
1286   return(1);
1287 }
1288
1289
1290 /*
1291  * Stack tracking system
1292  */
1293
1294 void
1295 cl_uc::st_push(class cl_stack_op *op)
1296 {
1297   st_ops->push(op);
1298 }
1299
1300 void
1301 cl_uc::st_call(class cl_stack_op *op)
1302 {
1303   st_ops->push(op);
1304 }
1305
1306 int
1307 cl_uc::st_pop(class cl_stack_op *op)
1308 {
1309   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
1310
1311   if (!sop)
1312     return(1);
1313   return(0);
1314 }
1315
1316 int
1317 cl_uc::st_ret(class cl_stack_op *op)
1318 {
1319   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
1320
1321   if (!sop)
1322     return(1);
1323   return(0);
1324 }
1325
1326
1327 /*
1328  * Breakpoint handling
1329  */
1330
1331 class cl_fetch_brk *
1332 cl_uc::fbrk_at(t_addr addr)
1333 {
1334   int idx;
1335   
1336   return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
1337 }
1338
1339 class cl_ev_brk *
1340 cl_uc::ebrk_at(t_addr addr, char *id)
1341 {
1342   int i;
1343   class cl_ev_brk *eb;
1344
1345   for (i= 0; i < ebrk->count; i++)
1346     {
1347       eb= (class cl_ev_brk *)(ebrk->at(i));
1348       if (eb->addr == addr &&
1349           !strcmp(eb->id, id))
1350         return(eb);
1351     }
1352   return(0);
1353 }
1354
1355 /*void
1356 cl_uc::rm_fbrk(long addr)
1357 {
1358   fbrk->del_bp(addr);
1359 }*/
1360
1361 /* Get a breakpoint specified by its number */
1362
1363 class cl_brk *
1364 cl_uc::brk_by_nr(int nr)
1365 {
1366   class cl_brk *bp;
1367
1368   if ((bp= fbrk->get_bp(nr)))
1369     return(bp);
1370   if ((bp= ebrk->get_bp(nr)))
1371     return(bp);
1372   return(0);
1373 }
1374
1375 /* Get a breakpoint from the specified collection by its number */
1376
1377 class cl_brk *
1378 cl_uc::brk_by_nr(class brk_coll *bpcoll, int nr)
1379 {
1380   class cl_brk *bp;
1381
1382   if ((bp= bpcoll->get_bp(nr)))
1383     return(bp);
1384   return(0);
1385 }
1386
1387 /* Remove an event breakpoint specified by its address and id */
1388
1389 void
1390 cl_uc::rm_ebrk(t_addr addr, char *id)
1391 {
1392   int i;
1393   class cl_ev_brk *eb;
1394
1395   for (i= 0; i < ebrk->count; i++)
1396     {
1397       eb= (class cl_ev_brk *)(ebrk->at(i));
1398       if (eb->addr == addr &&
1399           !strcmp(eb->id, id))
1400         ebrk->free_at(i);
1401     }
1402 }
1403
1404 /* Remove a breakpoint specified by its number */
1405
1406 void
1407 cl_uc::rm_brk(int nr)
1408 {
1409   class cl_brk *bp;
1410
1411   if ((bp= brk_by_nr(fbrk, nr)))
1412     fbrk->del_bp(bp->addr);
1413   else if ((bp= brk_by_nr(ebrk, nr)))
1414     ebrk->free_at(ebrk->index_of(bp));
1415 }
1416
1417 void
1418 cl_uc::put_breaks(void)
1419 {}
1420
1421 /* Remove all fetch and event breakpoints */
1422
1423 void
1424 cl_uc::remove_all_breaks(void)
1425 {
1426   while (fbrk->count)
1427     {
1428       class cl_brk *brk= (class cl_brk *)(fbrk->at(0));
1429       fbrk->del_bp(brk->addr);
1430     }
1431   while (ebrk->count)
1432     ebrk->free_at(ebrk->count-1);
1433 }
1434
1435 int
1436 cl_uc::make_new_brknr(void)
1437 {
1438   if (brk_counter == 0)
1439     return(brk_counter= 1);
1440   if (fbrk->count == 0 &&
1441       ebrk->count == 0)
1442     return(brk_counter= 1);
1443   return(++brk_counter);
1444 }
1445
1446 class cl_ev_brk *
1447 cl_uc::mk_ebrk(enum brk_perm perm, class cl_mem *mem,
1448                char op, t_addr addr, int hit)
1449 {
1450   class cl_ev_brk *b;
1451   op= toupper(op);
1452
1453   switch (mem->type)
1454     {
1455     case MEM_ROM:
1456       if (op == 'R')
1457         b= new cl_rc_brk(make_new_brknr(), addr, perm, hit);
1458       else
1459         return(0);
1460       break;
1461     case MEM_IRAM:
1462       if (op == 'R')
1463         b= new cl_ri_brk(make_new_brknr(), addr, perm, hit);
1464       else if (op == 'W')
1465         b= new cl_wi_brk(make_new_brknr(), addr, perm, hit);
1466       else
1467         return(0);
1468       break;
1469     case MEM_XRAM:
1470       if (op == 'R')
1471         b= new cl_rx_brk(make_new_brknr(), addr, perm, hit);
1472       else if (op == 'W')
1473         b= new cl_wx_brk(make_new_brknr(), addr, perm, hit);
1474       else
1475         return(0);
1476       break;
1477     case MEM_SFR:
1478       if (op == 'R')
1479         b= new cl_rs_brk(make_new_brknr(), addr, perm, hit);
1480       else if (op == 'W')
1481         b= new cl_ws_brk(make_new_brknr(), addr, perm, hit);
1482       else
1483         return(0);
1484       break;
1485     default:
1486       return(0);
1487     }
1488   b->init();
1489   return(b);
1490 }
1491
1492
1493 /* End of uc.cc */