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