fix printf is a macro in gcc 3
[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->dd_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         dd_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                         dd_printf("Unknown record type %d(0x%x)\n",
704                                   rtyp, rtyp);
705                 }
706               else
707                 if (sim->app->args->get_iarg('V', 0))
708                   sim->app->get_commander()->
709                     dd_printf("Checksum error (%x instead of %x) in "
710                               "record %ld.\n", chk, sum, recnum);
711             }
712           else
713             if (sim->app->args->get_iarg('V', 0))
714               sim->app->get_commander()->
715                 dd_printf("Read error in record %ld.\n", recnum);
716         }
717     }
718   if (get_mem_width(MEM_ROM) > 8 &&
719       !get_low)
720     set_mem(MEM_ROM, addr, low);
721
722   if (name)
723     fclose(f);
724   if (sim->app->args->get_iarg('V', 0))
725     sim->app->get_commander()->dd_printf("%ld records have been read\n",
726                                          recnum);
727   analyze(0);
728   return(written);
729 }
730
731
732 /*
733  * Handling instruction map
734  *
735  * `inst_at' is checking if the specified address is in instruction
736  * map and `set_inst_at' marks the address in the map and
737  * `del_inst_at' deletes the mark. `there_is_inst' cheks if there is
738  * any mark in the map
739  */
740
741 bool
742 cl_uc::inst_at(t_addr addr)
743 {
744   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
745   
746   if (!rom)
747     return(0);
748   return(rom->inst_map->get(addr));
749 }
750
751 void
752 cl_uc::set_inst_at(t_addr addr)
753 {
754   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
755   
756   if (rom)
757     rom->inst_map->set(addr);
758 }
759
760 void
761 cl_uc::del_inst_at(t_addr addr)
762 {
763   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
764   
765   if (rom)
766     rom->inst_map->clear(addr);
767 }
768
769 bool
770 cl_uc::there_is_inst(void)
771 {
772   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
773   
774   if (!rom)
775     return(0);
776   return(!(rom->inst_map->empty()));
777 }
778
779
780 /*
781  * Manipulating HW elements of the CPU
782  *****************************************************************************
783  */
784
785 /* Register callback hw objects for mem read/write */
786
787 void
788 cl_uc::register_hw_read(enum mem_class type, t_addr addr, class cl_hw *hw)
789 {
790   class cl_mem *m;
791   class cl_memloc *l;
792
793   if ((m= (class cl_mem*)mems->at(type)))
794     {
795       if ((l= m->read_locs->get_loc(addr)) == 0)
796         {
797           l= new cl_memloc(addr);
798           l->init();
799           m->read_locs->add(l);
800         }
801       l->hws->add(hw);
802     }
803   else
804     printf("cl_uc::register_hw_read TROUBLE\n");
805 }
806
807 void
808 cl_uc::register_hw_write(enum mem_class type, t_addr addr, class cl_hw *hw)
809 {
810 }
811
812 /* Looking for a specific HW element */
813
814 class cl_hw *
815 cl_uc::get_hw(enum hw_cath cath, int *idx)
816 {
817   class cl_hw *hw= 0;
818   int i= 0;
819
820   if (idx)
821     i= *idx;
822   for (; i < hws->count; i++)
823     {
824       hw= (class cl_hw *)(hws->at(i));
825       if (hw->cathegory == cath)
826         break;
827     }
828   if (i >= hws->count)
829     return(0);
830   if (idx)
831     *idx= i;
832   return(hw);
833 }
834
835 class cl_hw *
836 cl_uc::get_hw(char *id_string, int *idx)
837 {
838   class cl_hw *hw= 0;
839   int i= 0;
840
841   if (idx)
842     i= *idx;
843   for (; i < hws->count; i++)
844     {
845       hw= (class cl_hw *)(hws->at(i));
846       if (strstr(hw->id_string, id_string) == hw->id_string)
847         break;
848     }
849   if (i >= hws->count)
850     return(0);
851   if (idx)
852     *idx= i;
853   return(hw);
854 }
855
856 class cl_hw *
857 cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
858 {
859   class cl_hw *hw;
860   int i= 0;
861
862   if (idx)
863     i= *idx;
864   hw= get_hw(cath, &i);
865   while (hw &&
866          hw->id != hwid)
867     {
868       i++;
869       hw= get_hw(cath, &i);
870     }
871   if (hw && 
872       idx)
873     *idx= i;
874   return(hw);
875 }
876
877 class cl_hw *
878 cl_uc::get_hw(char *id_string, int hwid, int *idx)
879 {
880   class cl_hw *hw;
881   int i= 0;
882
883   if (idx)
884     i= *idx;
885   hw= get_hw(id_string, &i);
886   while (hw &&
887          hw->id != hwid)
888     {
889       i++;
890       hw= get_hw(id_string, &i);
891     }
892   if (hw && 
893       idx)
894     *idx= i;
895   return(hw);
896 }
897
898
899 /*
900  * Help of the command interpreter
901  */
902
903 struct dis_entry *
904 cl_uc::dis_tbl(void)
905 {
906   static struct dis_entry empty= { 0, 0, 0, 0, NULL };
907   return(&empty);
908 }
909
910 struct name_entry *
911 cl_uc::sfr_tbl(void)
912 {
913   static struct name_entry empty= { 0, 0 };
914   return(&empty);
915 }
916
917 struct name_entry *
918 cl_uc::bit_tbl(void)
919 {
920   static struct name_entry empty= { 0, 0 };
921   return(&empty);
922 }
923
924 char *
925 cl_uc::disass(t_addr addr, char *sep)
926 {
927   char *buf;
928
929   buf= (char*)malloc(100);
930   strcpy(buf, "uc::do_disass unimplemented\n");
931   return(buf);
932 }
933
934 void
935 cl_uc::print_disass(t_addr addr, class cl_console *con)
936 {
937   char *dis;
938   class cl_brk *b;
939   int i;
940   class cl_mem *rom= mem(MEM_ROM);
941   t_mem code= get_mem(MEM_ROM, addr);
942
943   if (!rom)
944     return;
945   b= fbrk_at(addr);
946   dis= disass(addr, NULL);
947   if (b)
948     con->dd_printf("%c", (b->perm == brkFIX)?'F':'D');
949   else
950     con->dd_printf(" ");
951   con->dd_printf("%c ", inst_at(addr)?' ':'?');
952   con->dd_printf(rom->addr_format, addr); con->dd_printf(" ");
953   con->dd_printf(rom->data_format, code);
954   for (i= 1; i < inst_length(code); i++)
955     {
956       con->dd_printf(" ");
957       con->dd_printf(rom->data_format, get_mem(MEM_ROM, addr+i));
958     }
959   int li= longest_inst();
960   while (i < li)
961     {
962       int j;
963       j= rom->width/4 + ((rom->width%4)?1:0) + 1;
964       while (j)
965         con->dd_printf(" "), j--;
966       i++;
967     }
968   con->dd_printf(" %s\n", dis);
969   free(dis);
970 }
971
972 void
973 cl_uc::print_regs(class cl_console *con)
974 {
975   con->dd_printf("No registers\n");
976 }
977
978 int
979 cl_uc::inst_length(t_mem code)
980 {
981   struct dis_entry *tabl= dis_tbl();
982   int i;
983
984   for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
985   return(tabl[i].mnemonic?tabl[i].length:1);     
986 }
987
988 int
989 cl_uc::longest_inst(void)
990 {
991   struct dis_entry *de= dis_tbl();
992   int max= 0;
993
994   while (de &&
995          de->mnemonic)
996     {
997       if (de->length > max)
998         max= de->length;
999       de++;
1000     }
1001   return(max);
1002 }
1003
1004 bool
1005 cl_uc::get_name(t_addr addr, struct name_entry tab[], char *buf)
1006 {
1007   int i;
1008
1009   i= 0;
1010   while (tab[i].name &&
1011          (!(tab[i].cpu_type & type) ||
1012          (tab[i].addr != addr)))
1013     i++;
1014   if (tab[i].name)
1015     strcpy(buf, tab[i].name);
1016   return(tab[i].name != NULL);
1017 }
1018
1019 char *
1020 cl_uc::symbolic_bit_name(t_addr bit_address,
1021                          class cl_mem *mem,
1022                          t_addr mem_addr,
1023                          t_mem bit_mask)
1024 {
1025   char *sym_name= 0;
1026   int i;
1027
1028   i= 0;
1029   while (bit_tbl()[i].name &&
1030          (bit_tbl()[i].addr != bit_address))
1031     i++;
1032   if (bit_tbl()[i].name)
1033     {
1034       sym_name= strdup(bit_tbl()[i].name);
1035       return(sym_name);
1036     }
1037
1038   if (mem &&
1039       mem->class_name &&
1040       strstr(mem->class_name, "sfr") == mem->class_name)
1041     {
1042       i= 0;
1043       while (sfr_tbl()[i].name &&
1044              (sfr_tbl()[i].addr != mem_addr))
1045         i++;
1046       if (sfr_tbl()[i].name)
1047         sym_name= strdup(sfr_tbl()[i].name);
1048       else
1049         sym_name= 0;
1050     }
1051   if (!sym_name)
1052     {
1053       sym_name= (char *)malloc(16);
1054       sprintf(sym_name, mem?(mem->addr_format):"0x%06x", mem_addr);
1055     }
1056   sym_name= (char *)realloc(sym_name, strlen(sym_name)+2);
1057   strcat(sym_name, ".");
1058   i= 0;
1059   while (bit_mask > 1)
1060     {
1061       bit_mask>>=1;
1062       i++;
1063     }
1064   char bitnumstr[10];
1065   sprintf(bitnumstr, "%1d", i);
1066   strcat(sym_name, bitnumstr);
1067   return(sym_name);
1068 }
1069
1070
1071 /*
1072  * Execution
1073  */
1074
1075 int
1076 cl_uc::tick(int cycles)
1077 {
1078   class cl_hw *hw;
1079   int i, cpc= clock_per_cycle();
1080
1081   // increase time
1082   ticks->tick(cycles * cpc);
1083   class it_level *il= (class it_level *)(it_levels->top());
1084   if (il->level >= 0)
1085     isr_ticks->tick(cycles * cpc);
1086   if (state == stIDLE)
1087     idle_ticks->tick(cycles * cpc);
1088   for (i= 0; i < counters->count; i++)
1089     {
1090       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1091       if (t)
1092         {
1093           if ((t->options&TICK_INISR) ||
1094               il->level < 0)
1095             t->tick(cycles * cpc);
1096         }
1097     }
1098
1099   // tick hws
1100   for (i= 0; i < hws->count; i++)
1101     {
1102       hw= (class cl_hw *)(hws->at(i));
1103       if (hw->flags & HWF_INSIDE)
1104         hw->tick(cycles);
1105     }
1106   return(0);
1107 }
1108
1109 class cl_ticker *
1110 cl_uc::get_counter(int nr)
1111 {
1112   if (nr >= counters->count)
1113     return(0);
1114   return((class cl_ticker *)(counters->at(nr)));
1115 }
1116
1117 class cl_ticker *
1118 cl_uc::get_counter(char *name)
1119 {
1120   int i;
1121
1122   if (!name)
1123     return(0);
1124   for (i= 0; i < counters->count; i++)
1125     {
1126       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1127       if (t &&
1128           t->name &&
1129           strcmp(t->name, name) == 0)
1130         return(t);
1131     }
1132   return(0);
1133 }
1134
1135 void
1136 cl_uc::add_counter(class cl_ticker *ticker, int nr)
1137 {
1138   while (counters->count <= nr)
1139     counters->add(0);
1140   counters->put_at(nr, ticker);
1141 }
1142
1143 void
1144 cl_uc::add_counter(class cl_ticker *ticker, char */*name*/)
1145 {
1146   int i;
1147
1148   if (counters->count < 1)
1149     counters->add(0);
1150   for (i= 1; i < counters->count; i++)
1151     {
1152       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1153       if (!t)
1154         {
1155           counters->put_at(i, ticker);
1156           return;
1157         }
1158     }
1159   counters->add(ticker);
1160 }
1161
1162 void
1163 cl_uc::del_counter(int nr)
1164 {
1165   class cl_ticker *t;
1166
1167   if (nr >= counters->count)
1168     return;
1169   if ((t= (class cl_ticker *)(counters->at(0))) != 0)
1170     delete t;
1171   counters->put_at(nr, 0);
1172 }
1173
1174 void
1175 cl_uc::del_counter(char *name)
1176 {
1177   int i;
1178   
1179   if (!name)
1180     return;
1181   for (i= 0; i < counters->count; i++)
1182     {
1183       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
1184       if (t &&
1185           t->name &&
1186           strcmp(t->name, name) == 0)
1187         {
1188           delete t;
1189           counters->put_at(i, 0);
1190           return;
1191         }
1192     }
1193 }
1194
1195 /*
1196  * Fetch without checking for breakpoint hit
1197  */
1198
1199 t_mem
1200 cl_uc::fetch(void)
1201 {
1202   ulong code;
1203
1204   code= read_mem(MEM_ROM, PC);
1205   PC++;
1206   if (PC >= get_mem_size(MEM_ROM))
1207     PC= 0;
1208   return(code);
1209 }
1210
1211 /*
1212  * Fetch but checking for breakpoint hit first
1213  */
1214
1215 bool
1216 cl_uc::fetch(t_mem *code)
1217 {
1218   class cl_brk *brk;
1219   int idx;
1220
1221   if (!code)
1222     return(0);
1223   if (sim->state & SIM_GO)
1224     {
1225       if ((brk= fbrk->get_bp(PC, &idx)) &&
1226           (brk->do_hit()))
1227         {
1228           if (brk->perm == brkDYNAMIC)
1229             fbrk->del_bp(PC);
1230           return(1);
1231         }
1232     }
1233   *code= fetch();
1234   return(0);
1235 }
1236
1237 int
1238 cl_uc::do_inst(int step)
1239 {
1240   int res= resGO;
1241
1242   if (step < 0)
1243     step= 1;
1244   while (step-- &&
1245          res == resGO)
1246     {
1247       pre_inst();
1248       res= exec_inst();
1249       post_inst();
1250     }
1251   if (res != resGO)
1252     sim->stop(res);
1253   return(res);
1254 }
1255
1256 void
1257 cl_uc::pre_inst(void)
1258 {}
1259
1260 int
1261 cl_uc::exec_inst(void)
1262 {
1263   return(resGO);
1264 }
1265
1266 void
1267 cl_uc::post_inst(void)
1268 {}
1269
1270
1271 /*
1272  * Time related functions
1273  */
1274
1275 double
1276 cl_uc::get_rtime(void)
1277 {
1278   /*  double d;
1279
1280   d= (double)ticks/xtal;
1281   return(d);*/
1282   return(ticks->get_rtime(xtal));
1283 }
1284
1285 int
1286 cl_uc::clock_per_cycle(void)
1287 {
1288   return(1);
1289 }
1290
1291
1292 /*
1293  * Stack tracking system
1294  */
1295
1296 void
1297 cl_uc::st_push(class cl_stack_op *op)
1298 {
1299   st_ops->push(op);
1300 }
1301
1302 void
1303 cl_uc::st_call(class cl_stack_op *op)
1304 {
1305   st_ops->push(op);
1306 }
1307
1308 int
1309 cl_uc::st_pop(class cl_stack_op *op)
1310 {
1311   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
1312
1313   if (!sop)
1314     return(1);
1315   return(0);
1316 }
1317
1318 int
1319 cl_uc::st_ret(class cl_stack_op *op)
1320 {
1321   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
1322
1323   if (!sop)
1324     return(1);
1325   return(0);
1326 }
1327
1328
1329 /*
1330  * Breakpoint handling
1331  */
1332
1333 class cl_fetch_brk *
1334 cl_uc::fbrk_at(t_addr addr)
1335 {
1336   int idx;
1337   
1338   return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
1339 }
1340
1341 class cl_ev_brk *
1342 cl_uc::ebrk_at(t_addr addr, char *id)
1343 {
1344   int i;
1345   class cl_ev_brk *eb;
1346
1347   for (i= 0; i < ebrk->count; i++)
1348     {
1349       eb= (class cl_ev_brk *)(ebrk->at(i));
1350       if (eb->addr == addr &&
1351           !strcmp(eb->id, id))
1352         return(eb);
1353     }
1354   return(0);
1355 }
1356
1357 /*void
1358 cl_uc::rm_fbrk(long addr)
1359 {
1360   fbrk->del_bp(addr);
1361 }*/
1362
1363 /* Get a breakpoint specified by its number */
1364
1365 class cl_brk *
1366 cl_uc::brk_by_nr(int nr)
1367 {
1368   class cl_brk *bp;
1369
1370   if ((bp= fbrk->get_bp(nr)))
1371     return(bp);
1372   if ((bp= ebrk->get_bp(nr)))
1373     return(bp);
1374   return(0);
1375 }
1376
1377 /* Get a breakpoint from the specified collection by its number */
1378
1379 class cl_brk *
1380 cl_uc::brk_by_nr(class brk_coll *bpcoll, int nr)
1381 {
1382   class cl_brk *bp;
1383
1384   if ((bp= bpcoll->get_bp(nr)))
1385     return(bp);
1386   return(0);
1387 }
1388
1389 /* Remove an event breakpoint specified by its address and id */
1390
1391 void
1392 cl_uc::rm_ebrk(t_addr addr, char *id)
1393 {
1394   int i;
1395   class cl_ev_brk *eb;
1396
1397   for (i= 0; i < ebrk->count; i++)
1398     {
1399       eb= (class cl_ev_brk *)(ebrk->at(i));
1400       if (eb->addr == addr &&
1401           !strcmp(eb->id, id))
1402         ebrk->free_at(i);
1403     }
1404 }
1405
1406 /* Remove a breakpoint specified by its number */
1407
1408 void
1409 cl_uc::rm_brk(int nr)
1410 {
1411   class cl_brk *bp;
1412
1413   if ((bp= brk_by_nr(fbrk, nr)))
1414     fbrk->del_bp(bp->addr);
1415   else if ((bp= brk_by_nr(ebrk, nr)))
1416     ebrk->free_at(ebrk->index_of(bp));
1417 }
1418
1419 void
1420 cl_uc::put_breaks(void)
1421 {}
1422
1423 /* Remove all fetch and event breakpoints */
1424
1425 void
1426 cl_uc::remove_all_breaks(void)
1427 {
1428   while (fbrk->count)
1429     {
1430       class cl_brk *brk= (class cl_brk *)(fbrk->at(0));
1431       fbrk->del_bp(brk->addr);
1432     }
1433   while (ebrk->count)
1434     ebrk->free_at(ebrk->count-1);
1435 }
1436
1437 int
1438 cl_uc::make_new_brknr(void)
1439 {
1440   if (brk_counter == 0)
1441     return(brk_counter= 1);
1442   if (fbrk->count == 0 &&
1443       ebrk->count == 0)
1444     return(brk_counter= 1);
1445   return(++brk_counter);
1446 }
1447
1448 class cl_ev_brk *
1449 cl_uc::mk_ebrk(enum brk_perm perm, class cl_mem *mem,
1450                char op, t_addr addr, int hit)
1451 {
1452   class cl_ev_brk *b;
1453   op= toupper(op);
1454
1455   switch (mem->type)
1456     {
1457     case MEM_ROM:
1458       if (op == 'R')
1459         b= new cl_rc_brk(make_new_brknr(), addr, perm, hit);
1460       else
1461         return(0);
1462       break;
1463     case MEM_IRAM:
1464       if (op == 'R')
1465         b= new cl_ri_brk(make_new_brknr(), addr, perm, hit);
1466       else if (op == 'W')
1467         b= new cl_wi_brk(make_new_brknr(), addr, perm, hit);
1468       else
1469         return(0);
1470       break;
1471     case MEM_XRAM:
1472       if (op == 'R')
1473         b= new cl_rx_brk(make_new_brknr(), addr, perm, hit);
1474       else if (op == 'W')
1475         b= new cl_wx_brk(make_new_brknr(), addr, perm, hit);
1476       else
1477         return(0);
1478       break;
1479     case MEM_SFR:
1480       if (op == 'R')
1481         b= new cl_rs_brk(make_new_brknr(), addr, perm, hit);
1482       else if (op == 'W')
1483         b= new cl_ws_brk(make_new_brknr(), addr, perm, hit);
1484       else
1485         return(0);
1486       break;
1487     default:
1488       return(0);
1489     }
1490   b->init();
1491   return(b);
1492 }
1493
1494
1495 /* End of uc.cc */