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