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