73ea3d20f2012cf057ecfca2d3897910eed7b541
[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     {
360       sim->cmd->printf("cl_uc::read_hex_file File name not specified\n");
361       return(-1);
362     }
363   else
364     if ((f= fopen(name, "r")) == NULL)
365       {
366         fprintf(stderr, "Can't open `%s': %s\n", name, strerror(errno));
367         return(-1);
368       }
369
370   //memset(inst_map, '\0', sizeof(inst_map));
371   ok= DD_TRUE;
372   while (ok &&
373          rtyp != 1)
374     {
375       while (((c= getc(f)) != ':') &&
376              (c != EOF)) ;
377       if (c != ':')
378         {fprintf(stderr, ": not found\n");break;}
379       recnum++;
380       dnum= ReadInt(f, &ok, 1);//printf("dnum=%02x",dnum);
381       chk = dnum;
382       addr= ReadInt(f, &ok, 2);//printf("addr=%04x",addr);
383       chk+= (addr & 0xff);
384       chk+= ((addr >> 8) & 0xff);
385       rtyp= ReadInt(f, &ok, 1);//printf("rtyp=%02x ",rtyp);
386       chk+= rtyp;
387       for (i= 0; ok && (i < dnum); i++)
388         {
389           rec[i]= ReadInt(f, &ok, 1);//printf("%02x",rec[i]);
390           chk+= rec[i];
391         }
392       if (ok)
393         {
394           sum= ReadInt(f, &ok, 1);//printf(" sum=%02x\n",sum);
395           if (ok)
396             {
397               if (((sum + chk) & 0xff) == 0)
398                 {
399                   if (rtyp == 0)
400                     {
401                       if (get_mem_width(MEM_ROM) > 8)
402                         addr/= 2;
403                       for (i= 0; i < dnum; i++)
404                         {
405                           if (get_mem_width(MEM_ROM) <= 8)
406                             {
407                               set_mem(MEM_ROM, addr, rec[i]);
408                               addr++;
409                               written++;
410                             }
411                           else if (get_mem_width(MEM_ROM) <= 16)
412                             {
413                               if (get_low)
414                                 {
415                                   low= rec[i];
416                                   get_low= 0;
417                                 }
418                               else
419                                 {
420                                   high= rec[i];
421                                   set_mem(MEM_ROM, addr, (high*256)+low);
422                                   addr++;
423                                   written++;
424                                   get_low= 1;
425                                 }
426                             }
427                         }
428                     }
429                   else
430                     if (sim->get_iarg('V', 0) &&
431                         rtyp != 1)
432                       sim->cmd->printf("Unknown record type %d(0x%x)\n",
433                                        rtyp, rtyp);
434                 }
435               else
436                 if (sim->get_iarg('V', 0))
437                   sim->cmd->printf("Checksum error (%x instead of %x) in "
438                                    "record %ld.\n", chk, sum, recnum);
439             }
440           else
441             if (sim->get_iarg('V', 0))
442               sim->cmd->printf("Read error in record %ld.\n", recnum);
443         }
444     }
445   if (get_mem_width(MEM_ROM) > 8 &&
446       !get_low)
447     set_mem(MEM_ROM, addr, low);
448
449   if (name)
450     fclose(f);
451   if (sim->get_iarg('V', 0))
452     sim->cmd->printf("%ld records have been read\n", recnum);
453   analyze(0);
454   return(written);
455 }
456
457
458 /*
459  * Handling instruction map
460  *
461  * `inst_at' is checking if the specified address is in instruction
462  * map and `set_inst_at' marks the address in the map and
463  * `del_inst_at' deletes the mark. `there_is_inst' cheks if there is
464  * any mark in the map
465  */
466
467 bool
468 cl_uc::inst_at(uint addr)
469 {
470   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
471   
472   if (!rom)
473     return(0);
474   return(rom->inst_map->get(addr));
475 }
476
477 void
478 cl_uc::set_inst_at(uint addr)
479 {
480   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
481   
482   if (rom)
483     rom->inst_map->set(addr);
484 }
485
486 void
487 cl_uc::del_inst_at(uint addr)
488 {
489   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
490   
491   if (rom)
492     rom->inst_map->clear(addr);
493 }
494
495 bool
496 cl_uc::there_is_inst(void)
497 {
498   class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
499   
500   if (!rom)
501     return(0);
502   return(!(rom->inst_map->empty()));
503 }
504
505
506 /*
507  * Manipulating HW elements of the CPU
508  *****************************************************************************
509  */
510
511 /* Register callback hw objects for mem read/write */
512
513 void
514 cl_uc::register_hw_read(enum mem_class type, long addr, class cl_hw *hw)
515 {
516   class cl_mem *m;
517   class cl_memloc *l;
518
519   if ((m= (class cl_mem*)mems->at(type)))
520     {
521       if ((l= m->read_locs->get_loc(addr)) == 0)
522         {
523           l= new cl_memloc(addr);
524           l->init();
525           m->read_locs->add(l);
526         }
527       l->hws->add(hw);
528     }
529   else
530     printf("cl_uc::register_hw_read TROUBLE\n");
531 }
532
533 void
534 cl_uc::register_hw_write(enum mem_class type, long addr, class cl_hw *hw)
535 {
536 }
537
538 /* Looking for a specific HW element */
539
540 class cl_hw *
541 cl_uc::get_hw(enum hw_cath cath, int *idx)
542 {
543   class cl_hw *hw= 0;
544   int i= 0;
545
546   if (idx)
547     i= *idx;
548   for (; i < hws->count; i++)
549     {
550       hw= (class cl_hw *)(hws->at(i));
551       if (hw->cathegory == cath)
552         break;
553     }
554   if (i >= hws->count)
555     return(0);
556   if (idx)
557     *idx= i;
558   return(hw);
559 }
560
561 class cl_hw *
562 cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
563 {
564   class cl_hw *hw;
565   int i= 0;
566
567   if (idx)
568     i= *idx;
569   hw= get_hw(cath, &i);
570   while (hw &&
571          hw->id != hwid)
572     {
573       i++;
574       hw= get_hw(cath, &i);
575     }
576   if (hw && 
577       idx)
578     *idx= i;
579   return(hw);
580 }
581
582
583 /*
584  * Help of the command interpreter
585  */
586
587 struct dis_entry *
588 cl_uc::dis_tbl(void)
589 {
590   static struct dis_entry empty= { 0, 0, 0, 0, NULL };
591   return(&empty);
592 }
593
594 struct name_entry *
595 cl_uc::sfr_tbl(void)
596 {
597   static struct name_entry empty= { 0, 0 };
598   return(&empty);
599 }
600
601 struct name_entry *
602 cl_uc::bit_tbl(void)
603 {
604   static struct name_entry empty= { 0, 0 };
605   return(&empty);
606 }
607
608 char *
609 cl_uc::disass(uint addr, char *sep)
610 {
611   char *buf;
612
613   buf= (char*)malloc(100);
614   strcpy(buf, "uc::do_disass unimplemented\n");
615   return(buf);
616 }
617
618 void
619 cl_uc::print_disass(uint addr, class cl_console *con)
620 {
621   con->printf("uc::print_disass unimplemented\n");
622 }
623
624 void
625 cl_uc::print_regs(class cl_console *con)
626 {
627   con->printf("No registers\n");
628 }
629
630 int
631 cl_uc::inst_length(uint code)
632 {
633   struct dis_entry *tabl= dis_tbl();
634   int i;
635
636   for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
637   return(tabl[i].mnemonic?tabl[i].length:1);     
638 }
639
640 bool
641 cl_uc::get_name(uint addr, struct name_entry tab[], char *buf)
642 {
643   int i;
644
645   i= 0;
646   while (tab[i].name &&
647          (!(tab[i].cpu_type & type) ||
648          (tab[i].addr != addr)))
649     i++;
650   if (tab[i].name)
651     strcpy(buf, tab[i].name);
652   return(tab[i].name != NULL);
653 }
654
655
656 /*
657  * Execution
658  */
659
660 int
661 cl_uc::tick(int cycles)
662 {
663   class cl_hw *hw;
664   int i, cpc= clock_per_cycle();
665
666   // increase time
667   ticks->tick(cycles * cpc);
668   class it_level *il= (class it_level *)(it_levels->top());
669   if (il->level >= 0)
670     isr_ticks->tick(cycles * cpc);
671   if (state == stIDLE)
672     idle_ticks->tick(cycles * cpc);
673   for (i= 0; i < counters->count; i++)
674     {
675       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
676       if (t)
677         {
678           if ((t->options&TICK_INISR) ||
679               il->level < 0)
680             t->tick(cycles * cpc);
681         }
682     }
683
684   // tick hws
685   for (i= 0; i < hws->count; i++)
686     {
687       hw= (class cl_hw *)(hws->at(i));
688       if (hw->flags & HWF_INSIDE)
689         hw->tick(cycles);
690     }
691   return(0);
692 }
693
694 class cl_ticker *
695 cl_uc::get_counter(int nr)
696 {
697   if (nr >= counters->count)
698     return(0);
699   return((class cl_ticker *)(counters->at(nr)));
700 }
701
702 class cl_ticker *
703 cl_uc::get_counter(char *name)
704 {
705   int i;
706
707   if (!name)
708     return(0);
709   for (i= 0; i < counters->count; i++)
710     {
711       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
712       if (t &&
713           t->name &&
714           strcmp(t->name, name) == 0)
715         return(t);
716     }
717   return(0);
718 }
719
720 void
721 cl_uc::add_counter(class cl_ticker *ticker, int nr)
722 {
723   while (counters->count <= nr)
724     counters->add(0);
725   counters->put_at(nr, ticker);
726 }
727
728 void
729 cl_uc::add_counter(class cl_ticker *ticker, char */*name*/)
730 {
731   int i;
732
733   if (counters->count < 1)
734     counters->add(0);
735   for (i= 1; i < counters->count; i++)
736     {
737       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
738       if (!t)
739         {
740           counters->put_at(i, ticker);
741           return;
742         }
743     }
744   counters->add(ticker);
745 }
746
747 void
748 cl_uc::del_counter(int nr)
749 {
750   class cl_ticker *t;
751
752   if (nr >= counters->count)
753     return;
754   if ((t= (class cl_ticker *)(counters->at(0))) != 0)
755     delete t;
756   counters->put_at(nr, 0);
757 }
758
759 void
760 cl_uc::del_counter(char *name)
761 {
762   int i;
763   
764   if (!name)
765     return;
766   for (i= 0; i < counters->count; i++)
767     {
768       class cl_ticker *t= (class cl_ticker *)(counters->at(i));
769       if (t &&
770           t->name &&
771           strcmp(t->name, name) == 0)
772         {
773           delete t;
774           counters->put_at(i, 0);
775           return;
776         }
777     }
778 }
779
780 /*
781  * Fetch without checking for breakpoint hit
782  */
783
784 t_mem
785 cl_uc::fetch(void)
786 {
787   ulong code;
788
789   code= read_mem(MEM_ROM, PC);
790   PC++;
791   if (PC >= get_mem_size(MEM_ROM))
792     PC= 0;
793   return(code);
794 }
795
796 /*
797  * Fetch but checking for breakpoint hit first
798  */
799
800 bool
801 cl_uc::fetch(ulong *code)
802 {
803   class cl_brk *brk;
804   int idx;
805
806   if (!code)
807     return(0);
808   if (sim->state & SIM_GO)
809     {
810       if ((brk= fbrk->get_bp(PC, &idx)) &&
811           (brk->do_hit()))
812         {
813           if (brk->perm == brkDYNAMIC)
814             fbrk->del_bp(PC);
815           return(1);
816         }
817     }
818   *code= fetch();
819   return(0);
820 }
821
822 int
823 cl_uc::do_inst(int step)
824 {
825   int res= resGO;
826
827   if (step < 0)
828     step= 1;
829   while (step-- &&
830          res == resGO)
831     {
832       pre_inst();
833       res= exec_inst();
834       post_inst();
835     }
836   if (res != resGO)
837     sim->stop(res);
838   return(res);
839 }
840
841 void
842 cl_uc::pre_inst(void)
843 {}
844
845 int
846 cl_uc::exec_inst(void)
847 {
848   return(resGO);
849 }
850
851 void
852 cl_uc::post_inst(void)
853 {}
854
855
856 /*
857  * Time related functions
858  */
859
860 double
861 cl_uc::get_rtime(void)
862 {
863   /*  double d;
864
865   d= (double)ticks/xtal;
866   return(d);*/
867   return(ticks->get_rtime(xtal));
868 }
869
870 int
871 cl_uc::clock_per_cycle(void)
872 {
873   return(1);
874 }
875
876
877 /*
878  * Stack tracking system
879  */
880
881 void
882 cl_uc::st_push(class cl_stack_op *op)
883 {
884   st_ops->push(op);
885 }
886
887 void
888 cl_uc::st_call(class cl_stack_op *op)
889 {
890   st_ops->push(op);
891 }
892
893 int
894 cl_uc::st_pop(class cl_stack_op *op)
895 {
896   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
897
898   if (!sop)
899     return(1);
900   return(0);
901 }
902
903 int
904 cl_uc::st_ret(class cl_stack_op *op)
905 {
906   class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
907
908   if (!sop)
909     return(1);
910   return(0);
911 }
912
913
914 /*
915  * Breakpoint handling
916  */
917
918 class cl_fetch_brk *
919 cl_uc::fbrk_at(long addr)
920 {
921   int idx;
922   
923   return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
924 }
925
926 class cl_ev_brk *
927 cl_uc::ebrk_at(t_addr addr, char *id)
928 {
929   int i;
930   class cl_ev_brk *eb;
931
932   for (i= 0; i < ebrk->count; i++)
933     {
934       eb= (class cl_ev_brk *)(ebrk->at(i));
935       if (eb->addr == addr &&
936           !strcmp(eb->id, id))
937         return(eb);
938     }
939   return(0);
940 }
941
942 /*void
943 cl_uc::rm_fbrk(long addr)
944 {
945   fbrk->del_bp(addr);
946 }*/
947
948 void
949 cl_uc::rm_ebrk(t_addr addr, char *id)
950 {
951   int i;
952   class cl_ev_brk *eb;
953
954   for (i= 0; i < ebrk->count; i++)
955     {
956       eb= (class cl_ev_brk *)(ebrk->at(i));
957       if (eb->addr == addr &&
958           !strcmp(eb->id, id))
959         ebrk->free_at(i);
960     }
961 }
962
963 void
964 cl_uc::put_breaks(void)
965 {}
966
967 void
968 cl_uc::remove_breaks(void)
969 {}
970
971
972 /* End of uc.cc */