f128e8e7c5823521456470414dee5efdc66a5cd3
[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 "i_string.h"
34
35 #include "uccl.h"
36 #include "hwcl.h"
37 #include "memcl.h"
38 #include "simcl.h"
39 #include "itsrccl.h"
40
41
42 /*
43  * Clock counter
44  */
45
46 cl_ticker::cl_ticker(int adir, int in_isr, char *aname)
47 {
48   options= TICK_RUN;
49   if (in_isr)
50     options|= TICK_INISR;
51   dir= adir;
52   ticks= 0;
53   name= aname?strdup(aname):0;
54 }
55
56 cl_ticker::~cl_ticker(void)
57 {
58   if (name)
59     free(name);
60 }
61
62 int
63 cl_ticker::tick(int nr)
64 {
65   if (options&TICK_RUN)
66     ticks+= dir*nr;
67   return(ticks);
68 }
69
70 double
71 cl_ticker::get_rtime(double xtal)
72 {
73   double d;
74
75   d= (double)ticks/xtal;
76   return(d);
77 }
78
79 void
80 cl_ticker::dump(int nr, double xtal, class cl_console *con)
81 {
82   con->printf("timer #%d(\"%s\") %s%s: %g sec (%lu clks)\n",
83               nr, name?name:"unnamed",
84               (options&TICK_RUN)?"ON":"OFF",
85               (options&TICK_INISR)?",ISR":"",
86               get_rtime(xtal), ticks);
87 }
88
89
90 /*
91  * Abstract microcontroller
92  ******************************************************************************
93  */
94
95 cl_uc::cl_uc(class cl_sim *asim):
96   cl_base()
97 {
98   int i;
99   sim = asim;
100   mems= new cl_list(MEM_TYPES, 1);
101   hws = new cl_list(2, 1);
102   options= new cl_list(2, 2);
103   for (i= MEM_ROM; i < MEM_TYPES; i++)
104     mems->add(0);
105   ticks= new cl_ticker(+1, 0, "time");
106   isr_ticks= new cl_ticker(+1, TICK_INISR, "isr");
107   idle_ticks= new cl_ticker(+1, TICK_IDLE, "idle");
108   counters= new cl_list(2, 2);
109   it_levels= new cl_list(2, 2);
110   it_sources= new cl_list(2, 2);
111   class it_level *il= new it_level(-1, 0, 0, 0);
112   it_levels->push(il);
113   st_ops= new cl_list(2, 2);
114   sp_max= 0;
115   sp_avg= 0;
116 }
117
118
119 cl_uc::~cl_uc(void)
120 {
121   delete mems;
122   delete hws;
123   delete options;
124   delete ticks;
125   delete isr_ticks;
126   delete idle_ticks;
127   delete counters;
128   delete fbrk;
129   delete ebrk;
130   delete it_levels;
131   delete it_sources;
132   delete st_ops;
133 }
134
135
136 int
137 cl_uc::init(void)
138 {
139   int mc;
140
141   cl_base::init();
142   if (!(sim->arg_avail('X')) ||
143       sim->get_farg('X', 0) == 0)
144     xtal= 11059200;
145   else
146     xtal= sim->get_farg('X', 0);
147   for (mc= MEM_ROM; mc < MEM_TYPES; mc++)
148     {
149       class cl_mem *m= mk_mem((enum mem_class)mc);
150       mems->put_at(mc, m);
151     }
152   ebrk= new brk_coll(2, 2, (class cl_rom *)mem(MEM_ROM));
153   fbrk= new brk_coll(2, 2, (class cl_rom *)mem(MEM_ROM));
154   fbrk->Duplicates= DD_FALSE;
155   mk_hw_elements();
156   reset();
157   return(0);
158 }
159
160 char *
161 cl_uc::id_string(void)
162 {
163   return("unknown microcontroller");
164 }
165
166 void
167 cl_uc::reset(void)
168 {
169   class it_level *il;
170
171   PC= 0;
172   state = stGO;
173   ticks->ticks= 0;
174   isr_ticks->ticks= 0;
175   idle_ticks->ticks= 0;
176   /*FIXME should we clear user counters?*/
177   il= (class it_level *)(it_levels->top());
178   while (il &&
179          il->level >= 0)
180     {
181       il= (class it_level *)(it_levels->pop());
182       delete il;
183       il= (class it_level *)(it_levels->top());
184     }
185   sp_max= 0;
186   sp_avg= 0;
187 }
188
189 /*
190  * Making elements
191  */
192
193 class cl_mem *
194 cl_uc::mk_mem(enum mem_class type)
195 {
196   class cl_mem *m;
197
198   if (get_mem_size(type) <= 0)
199     return(0);
200   if (type == MEM_ROM)
201     m= new cl_rom(get_mem_size(type), get_mem_width(type));
202   else
203     m= new cl_mem(type, get_mem_size(type), get_mem_width(type));
204   m->init();
205   return(m);
206 }
207
208 t_addr
209 cl_uc::get_mem_size(enum mem_class type)
210 {
211   switch (type)
212     {
213     case MEM_ROM: return(0x10000);
214     case MEM_XRAM: return(0x10000);
215     case MEM_IRAM: return(0x100);
216     case MEM_SFR: return(0x100);
217     case MEM_TYPES:
218     default: return(0);
219     }
220   return(0);
221 }
222
223 int
224 cl_uc::get_mem_width(enum mem_class type)
225 {
226   return(8);
227 }
228
229 void
230 cl_uc::mk_hw_elements(void)
231 {
232 }
233
234
235 /*
236  * Read/write simulated memory
237  */
238
239 ulong
240 cl_uc::read_mem(enum mem_class type, long addr)
241 {
242   class cl_mem *m;
243
244   if ((m= (class cl_mem*)mems->at(type)))
245     return(m->read(addr));
246   //FIXME
247 fprintf(stderr, "cl_uc::read_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
248   return(0);
249 }
250
251 ulong
252 cl_uc::get_mem(enum mem_class type, long addr)
253 {
254   class cl_mem *m;
255
256   if ((m= (class cl_mem*)mems->at(type)))
257     return(m->get(addr));
258   //FIXME
259 printf("cl_uc::get_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
260   return(0);
261 }
262
263 void
264 cl_uc::write_mem(enum mem_class type, long addr, ulong val)
265 {
266   class cl_mem *m;
267
268   if ((m= (class cl_mem*)mems->at(type)))
269     {
270       m->write(addr, &val);
271       //m->mem[addr]= val;
272     }
273   //FIXME
274 else printf("cl_uc::write_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
275 }
276
277 void
278 cl_uc::set_mem(enum mem_class type, long addr, ulong val)
279 {
280   class cl_mem *m;
281
282   if ((m= (class cl_mem*)mems->at(type)))
283     m->set(addr, val);
284   //FIXME
285 else printf("cl_uc::set_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
286 }
287
288 class cl_mem *
289 cl_uc::mem(enum mem_class type)
290 {
291   if (mems->count < type)
292     //FIXME
293 {printf("TROUBLE\n");    return(0);
294 }
295   return((class cl_mem *)(mems->at(type)));
296 }
297
298 TYPE_UBYTE *
299 cl_uc::MEM(enum mem_class type)
300 {
301   class cl_mem *m;
302
303   if ((m= mem(type)) == 0)
304     //FIXME
305 {printf("TROUBLE\n");    return(0);
306 }
307   return((TYPE_UBYTE *)(m->mem));
308 }
309
310
311 /* Local function for `read_hex_file' method to read some bytes */
312
313 static long
314 ReadInt(FILE *f, bool *ok, int bytes)
315 {
316   char s2[3];
317   long l= 0;
318
319   *ok= DD_FALSE;
320   while (bytes)
321     {
322       if (fscanf(f, "%2c", &s2[0]) == EOF)
323         return(0);
324       s2[2]= '\0';
325       l= l*256 + strtol(s2, NULL, 16);
326       bytes--;
327     }
328   *ok= DD_TRUE;
329   return(l);
330 }
331
332
333 /* 
334  * Reading intel hexa file into EROM
335  *____________________________________________________________________________
336  *
337  * If parameter is a NULL pointer, this function reads data from `cmd_in'
338  *
339  */
340
341 long
342 cl_uc::read_hex_file(const char *name)
343 {
344   FILE *f;
345   char c;
346   long written= 0, recnum= 0;
347
348   uchar dnum;     // data number
349   uchar rtyp=0;   // record type
350   uint  addr= 0;  // address
351   uchar rec[300]; // data record
352   uchar sum ;     // checksum
353   uchar chk ;     // check
354   int  i;
355   bool ok, get_low= 1;
356   uchar low= 0, high;
357
358   if (!name)
359     f= sim->/*FIXME*/cmd_in();
360   else
361     if ((f= fopen(name, "r")) == NULL)
362       {
363         fprintf(stderr, "Can't open `%s': %s\n", name, strerror(errno));
364         return(-1);
365       }
366
367   //memset(inst_map, '\0', sizeof(inst_map));
368   ok= DD_TRUE;
369   while (ok &&
370          rtyp != 1)
371     {
372       while (((c= getc(f)) != ':') &&
373              (c != EOF)) ;
374       if (c != ':')
375         {fprintf(stderr, ": not found\n");break;}
376       recnum++;
377       dnum= ReadInt(f, &ok, 1);//printf("dnum=%02x",dnum);
378       chk = dnum;
379       addr= ReadInt(f, &ok, 2);//printf("addr=%04x",addr);
380       chk+= (addr & 0xff);
381       chk+= ((addr >> 8) & 0xff);
382       rtyp= ReadInt(f, &ok, 1);//printf("rtyp=%02x ",rtyp);
383       chk+= rtyp;
384       for (i= 0; ok && (i < dnum); i++)
385         {
386           rec[i]= ReadInt(f, &ok, 1);//printf("%02x",rec[i]);
387           chk+= rec[i];
388         }
389       if (ok)
390         {
391           sum= ReadInt(f, &ok, 1);//printf(" sum=%02x\n",sum);
392           if (ok)
393             {
394               if (((sum + chk) & 0xff) == 0)
395                 {
396                   if (rtyp == 0)
397                     {
398                       if (get_mem_width(MEM_ROM) > 8)
399                         addr/= 2;
400                       for (i= 0; i < dnum; i++)
401                         {
402                           if (get_mem_width(MEM_ROM) <= 8)
403                             {
404                               set_mem(MEM_ROM, addr, rec[i]);
405                               addr++;
406                               written++;
407                             }
408                           else if (get_mem_width(MEM_ROM) <= 16)
409                             {
410                               if (get_low)
411                                 {
412                                   low= rec[i];
413                                   get_low= 0;
414                                 }
415                               else
416                                 {
417                                   high= rec[i];
418                                   set_mem(MEM_ROM, addr, (high*256)+low);
419                                   addr++;
420                                   written++;
421                                   get_low= 1;
422                                 }
423                             }
424                         }
425                     }
426                   else
427                     if (sim->get_iarg('V', 0) &&
428                         rtyp != 1)
429                       fprintf(sim->cmd_out(),
430                               "Unknown record type %d(0x%x)\n", rtyp, rtyp);
431                 }
432               else
433                 if (sim->get_iarg('V', 0))
434                   fprintf(sim->cmd_out(),
435                           "Checksum error (%x instead of %x) in record %ld.\n",
436                           chk, sum, recnum);
437             }
438           else
439             if (sim->get_iarg('V', 0))
440               fprintf(sim->cmd_out(), "Read error in record %ld.\n", recnum);
441         }
442     }
443   if (get_mem_width(MEM_ROM) > 8 &&
444       !get_low)
445     set_mem(MEM_ROM, addr, low);
446
447   if (name)
448     fclose(f);
449   if (sim->get_iarg('V', 0))
450     fprintf(sim->cmd_out(), "%ld records have been read\n", recnum);
451   analyze(0);
452   return(written);
453 }
454
455
456 /*
457  * Handling instruction map
458  *
459  * `inst_at' is checking if the specified address is in instruction
460  * map and `set_inst_at' marks the address in the map and
461  * `del_inst_at' deletes the mark. `there_is_inst' cheks if there is
462  * any mark in the map
463  */
464
465 bool
466 cl_uc::inst_at(uint addr)
467 {
468   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
469   
470   if (!rom)
471     return(0);
472   return(rom->inst_map->get(addr));
473 }
474
475 void
476 cl_uc::set_inst_at(uint addr)
477 {
478   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
479   
480   if (rom)
481     rom->inst_map->set(addr);
482 }
483
484 void
485 cl_uc::del_inst_at(uint addr)
486 {
487   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
488   
489   if (rom)
490     rom->inst_map->clear(addr);
491 }
492
493 bool
494 cl_uc::there_is_inst(void)
495 {
496   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
497   
498   if (!rom)
499     return(0);
500   return(!(rom->inst_map->empty()));
501 }
502
503
504 /*
505  * Manipulating HW elements of the CPU
506  *****************************************************************************
507  */
508
509 /* Register callback hw objects for mem read/write */
510
511 void
512 cl_uc::register_hw_read(enum mem_class type, long addr, class cl_hw *hw)
513 {
514   class cl_mem *m;
515   class cl_memloc *l;
516
517   if ((m= (class cl_mem*)mems->at(type)))
518     {
519       if ((l= m->read_locs->get_loc(addr)) == 0)
520         {
521           l= new cl_memloc(addr);
522           l->init();
523           m->read_locs->add(l);
524         }
525       l->hws->add(hw);
526     }
527   else
528     printf("cl_uc::register_hw_read TROUBLE\n");
529 }
530
531 void
532 cl_uc::register_hw_write(enum mem_class type, long addr, class cl_hw *hw)
533 {
534 }
535
536 /* Looking for a specific HW element */
537
538 class cl_hw *
539 cl_uc::get_hw(enum hw_cath cath, int *idx)
540 {
541   class cl_hw *hw= 0;
542   int i= 0;
543
544   if (idx)
545     i= *idx;
546   for (; i < hws->count; i++)
547     {
548       hw= (class cl_hw *)(hws->at(i));
549       if (hw->cathegory == cath)
550         break;
551     }
552   if (i >= hws->count)
553     return(0);
554   if (idx)
555     *idx= i;
556   return(hw);
557 }
558
559 class cl_hw *
560 cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
561 {
562   class cl_hw *hw;
563   int i= 0;
564
565   if (idx)
566     i= *idx;
567   hw= get_hw(cath, &i);
568   while (hw &&
569          hw->id != hwid)
570     {
571       i++;
572       hw= get_hw(cath, &i);
573     }
574   if (hw && 
575       idx)
576     *idx= i;
577   return(hw);
578 }
579
580
581 /*
582  * Help of the command interpreter
583  */
584
585 struct dis_entry *
586 cl_uc::dis_tbl(void)
587 {
588   static struct dis_entry empty= { 0, 0, 0, 0, NULL };
589   return(&empty);
590 }
591
592 struct name_entry *
593 cl_uc::sfr_tbl(void)
594 {
595   static struct name_entry empty= { 0, 0 };
596   return(&empty);
597 }
598
599 struct name_entry *
600 cl_uc::bit_tbl(void)
601 {
602   static struct name_entry empty= { 0, 0 };
603   return(&empty);
604 }
605
606 char *
607 cl_uc::disass(uint addr, char *sep)
608 {
609   char *buf;
610
611   buf= (char*)malloc(100);
612   strcpy(buf, "uc::do_disass unimplemented\n");
613   return(buf);
614 }
615
616 void
617 cl_uc::print_disass(uint addr, class cl_console *con)
618 {
619   con->printf("uc::print_disass unimplemented\n");
620 }
621
622 void
623 cl_uc::print_regs(class cl_console *con)
624 {
625   con->printf("No registers\n");
626 }
627
628 int
629 cl_uc::inst_length(uint code)
630 {
631   struct dis_entry *tabl= dis_tbl();
632   int i;
633
634   for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
635   return(tabl[i].mnemonic?tabl[i].length:1);     
636 }
637
638 bool
639 cl_uc::get_name(uint addr, struct name_entry tab[], char *buf)
640 {
641   int i;
642
643   i= 0;
644   while (tab[i].name &&
645          (!(tab[i].cpu_type & type) ||
646          (tab[i].addr != addr)))
647     i++;
648   if (tab[i].name)
649     strcpy(buf, tab[i].name);
650   return(tab[i].name != NULL);
651 }
652
653
654 /*
655  * Execution
656  */
657
658 int
659 cl_uc::tick(int cycles)
660 {
661   class cl_hw *hw;
662   int i, cpc= clock_per_cycle();
663
664   // increase time
665   ticks->tick(cycles * cpc);
666   class it_level *il= (class it_level *)(it_levels->top());
667   if (il->level >= 0)
668     isr_ticks->tick(cycles * cpc);
669   if (state == stIDLE)
670     idle_ticks->tick(cycles * cpc);
671   for (i= 0; i < counters->count; i++)
672     {
673       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
674       if (t)
675         {
676           if ((t->options&TICK_INISR) ||
677               il->level < 0)
678             t->tick(cycles * cpc);
679         }
680     }
681
682   // tick hws
683   for (i= 0; i < hws->count; i++)
684     {
685       hw= (class cl_hw *)(hws->at(i));
686       if (hw->flags & HWF_INSIDE)
687         hw->tick(cycles);
688     }
689   return(0);
690 }
691
692 class cl_ticker *
693 cl_uc::get_counter(int nr)
694 {
695   if (nr >= counters->count)
696     return(0);
697   return((class cl_ticker *)(counters->at(nr)));
698 }
699
700 class cl_ticker *
701 cl_uc::get_counter(char *name)
702 {
703   int i;
704
705   if (!name)
706     return(0);
707   for (i= 0; i < counters->count; i++)
708     {
709       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
710       if (t &&
711           t->name &&
712           strcmp(t->name, name) == 0)
713         return(t);
714     }
715   return(0);
716 }
717
718 void
719 cl_uc::add_counter(class cl_ticker *ticker, int nr)
720 {
721   while (counters->count <= nr)
722     counters->add(0);
723   counters->put_at(nr, ticker);
724 }
725
726 void
727 cl_uc::add_counter(class cl_ticker *ticker, char */*name*/)
728 {
729   int i;
730
731   if (counters->count < 1)
732     counters->add(0);
733   for (i= 1; i < counters->count; i++)
734     {
735       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
736       if (!t)
737         {
738           counters->put_at(i, ticker);
739           return;
740         }
741     }
742   counters->add(ticker);
743 }
744
745 void
746 cl_uc::del_counter(int nr)
747 {
748   class cl_ticker *t;
749
750   if (nr >= counters->count)
751     return;
752   if ((t= (class cl_ticker *)(counters->at(0))) != 0)
753     delete t;
754   counters->put_at(nr, 0);
755 }
756
757 void
758 cl_uc::del_counter(char *name)
759 {
760   int i;
761   
762   if (!name)
763     return;
764   for (i= 0; i < counters->count; i++)
765     {
766       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
767       if (t &&
768           t->name &&
769           strcmp(t->name, name) == 0)
770         {
771           delete t;
772           counters->put_at(i, 0);
773           return;
774         }
775     }
776 }
777
778 /*
779  * Fetch without checking for breakpoint hit
780  */
781
782 t_mem
783 cl_uc::fetch(void)
784 {
785   ulong code;
786
787   code= read_mem(MEM_ROM, PC);
788   PC++;
789   if (PC >= get_mem_size(MEM_ROM))
790     PC= 0;
791   return(code);
792 }
793
794 /*
795  * Fetch but checking for breakpoint hit first
796  */
797
798 bool
799 cl_uc::fetch(ulong *code)
800 {
801   class cl_brk *brk;
802   int idx;
803
804   if (!code)
805     return(0);
806   if (sim->state & SIM_GO)
807     {
808       if ((brk= fbrk->get_bp(PC, &idx)) &&
809           (brk->do_hit()))
810         {
811           if (brk->perm == brkDYNAMIC)
812             fbrk->del_bp(PC);
813           return(1);
814         }
815     }
816   *code= fetch();
817   return(0);
818 }
819
820 int
821 cl_uc::do_inst(int step)
822 {
823   int res= resGO;
824
825   if (step < 0)
826     step= 1;
827   while (step-- &&
828          res == resGO)
829     {
830       pre_inst();
831       res= exec_inst();
832       post_inst();
833     }
834   if (res != resGO)
835     sim->stop(res);
836   return(res);
837 }
838
839 void
840 cl_uc::pre_inst(void)
841 {}
842
843 int
844 cl_uc::exec_inst(void)
845 {
846   return(resGO);
847 }
848
849 void
850 cl_uc::post_inst(void)
851 {}
852
853
854 /*
855  * Time related functions
856  */
857
858 double
859 cl_uc::get_rtime(void)
860 {
861   /*  double d;
862
863   d= (double)ticks/xtal;
864   return(d);*/
865   return(ticks->get_rtime(xtal));
866 }
867
868 int
869 cl_uc::clock_per_cycle(void)
870 {
871   return(1);
872 }
873
874
875 /*
876  * Stack tracking system
877  */
878
879 void
880 cl_uc::st_push(class cl_stack_op *op)
881 {
882   st_ops->push(op);
883 }
884
885 void
886 cl_uc::st_call(class cl_stack_op *op)
887 {
888   st_ops->push(op);
889 }
890
891 int
892 cl_uc::st_pop(class cl_stack_op *op)
893 {
894   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
895
896   if (!sop)
897     return(1);
898   return(0);
899 }
900
901 int
902 cl_uc::st_ret(class cl_stack_op *op)
903 {
904   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
905
906   if (!sop)
907     return(1);
908   return(0);
909 }
910
911
912 /*
913  * Breakpoint handling
914  */
915
916 class cl_fetch_brk *
917 cl_uc::fbrk_at(long addr)
918 {
919   int idx;
920   
921   return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
922 }
923
924 class cl_ev_brk *
925 cl_uc::ebrk_at(t_addr addr, char *id)
926 {
927   int i;
928   class cl_ev_brk *eb;
929
930   for (i= 0; i < ebrk->count; i++)
931     {
932       eb= (class cl_ev_brk *)(ebrk->at(i));
933       if (eb->addr == addr &&
934           !strcmp(eb->id, id))
935         return(eb);
936     }
937   return(0);
938 }
939
940 /*void
941 cl_uc::rm_fbrk(long addr)
942 {
943   fbrk->del_bp(addr);
944 }*/
945
946 void
947 cl_uc::rm_ebrk(t_addr addr, char *id)
948 {
949   int i;
950   class cl_ev_brk *eb;
951
952   for (i= 0; i < ebrk->count; i++)
953     {
954       eb= (class cl_ev_brk *)(ebrk->at(i));
955       if (eb->addr == addr &&
956           !strcmp(eb->id, id))
957         ebrk->free_at(i);
958     }
959 }
960
961 void
962 cl_uc::put_breaks(void)
963 {}
964
965 void
966 cl_uc::remove_breaks(void)
967 {}
968
969
970 /* End of uc.cc */