2 * Simulator of microcontrollers (uc.cc)
4 * Copyright (C) 1999,99 Drotos Daniel, Talker Bt.
6 * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
10 /* This file is part of microcontroller simulator: ucsim.
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.
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.
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
46 cl_ticker::cl_ticker(int adir, int in_isr, char *aname)
53 name= aname?strdup(aname):0;
56 cl_ticker::~cl_ticker(void)
63 cl_ticker::tick(int nr)
71 cl_ticker::get_rtime(double xtal)
75 d= (double)ticks/xtal;
80 cl_ticker::dump(int nr, double xtal, class cl_console *con)
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);
91 * Abstract microcontroller
92 ******************************************************************************
95 cl_uc::cl_uc(class cl_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++)
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);
113 st_ops= new cl_list(2, 2);
142 if (!(sim->arg_avail('X')) ||
143 sim->get_farg('X', 0) == 0)
146 xtal= sim->get_farg('X', 0);
147 for (mc= MEM_ROM; mc < MEM_TYPES; mc++)
149 class cl_mem *m= mk_mem((enum mem_class)mc);
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;
161 cl_uc::id_string(void)
163 return("unknown microcontroller");
175 idle_ticks->ticks= 0;
176 /*FIXME should we clear user counters?*/
177 il= (class it_level *)(it_levels->top());
181 il= (class it_level *)(it_levels->pop());
183 il= (class it_level *)(it_levels->top());
194 cl_uc::mk_mem(enum mem_class type)
198 if (get_mem_size(type) <= 0)
201 m= new cl_rom(get_mem_size(type), get_mem_width(type));
203 m= new cl_mem(type, get_mem_size(type), get_mem_width(type));
209 cl_uc::get_mem_size(enum mem_class type)
213 case MEM_ROM: return(0x10000);
214 case MEM_XRAM: return(0x10000);
215 case MEM_IRAM: return(0x100);
216 case MEM_SFR: return(0x100);
224 cl_uc::get_mem_width(enum mem_class type)
230 cl_uc::mk_hw_elements(void)
236 * Read/write simulated memory
240 cl_uc::read_mem(enum mem_class type, long addr)
244 if ((m= (class cl_mem*)mems->at(type)))
245 return(m->read(addr));
247 fprintf(stderr, "cl_uc::read_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
252 cl_uc::get_mem(enum mem_class type, long addr)
256 if ((m= (class cl_mem*)mems->at(type)))
257 return(m->get(addr));
259 printf("cl_uc::get_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
264 cl_uc::write_mem(enum mem_class type, long addr, ulong val)
268 if ((m= (class cl_mem*)mems->at(type)))
270 m->write(addr, &val);
274 else printf("cl_uc::write_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
278 cl_uc::set_mem(enum mem_class type, long addr, ulong val)
282 if ((m= (class cl_mem*)mems->at(type)))
285 else printf("cl_uc::set_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
289 cl_uc::mem(enum mem_class type)
291 if (mems->count < type)
293 {printf("TROUBLE\n"); return(0);
295 return((class cl_mem *)(mems->at(type)));
299 cl_uc::MEM(enum mem_class type)
303 if ((m= mem(type)) == 0)
305 {printf("TROUBLE\n"); return(0);
307 return((TYPE_UBYTE *)(m->mem));
311 /* Local function for `read_hex_file' method to read some bytes */
314 ReadInt(FILE *f, bool *ok, int bytes)
322 if (fscanf(f, "%2c", &s2[0]) == EOF)
325 l= l*256 + strtol(s2, NULL, 16);
334 * Reading intel hexa file into EROM
335 *____________________________________________________________________________
337 * If parameter is a NULL pointer, this function reads data from `cmd_in'
342 cl_uc::read_hex_file(const char *name)
346 long written= 0, recnum= 0;
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
360 sim->cmd->printf("cl_uc::read_hex_file File name not specified\n");
364 if ((f= fopen(name, "r")) == NULL)
366 fprintf(stderr, "Can't open `%s': %s\n", name, strerror(errno));
370 //memset(inst_map, '\0', sizeof(inst_map));
375 while (((c= getc(f)) != ':') &&
378 {fprintf(stderr, ": not found\n");break;}
380 dnum= ReadInt(f, &ok, 1);//printf("dnum=%02x",dnum);
382 addr= ReadInt(f, &ok, 2);//printf("addr=%04x",addr);
384 chk+= ((addr >> 8) & 0xff);
385 rtyp= ReadInt(f, &ok, 1);//printf("rtyp=%02x ",rtyp);
387 for (i= 0; ok && (i < dnum); i++)
389 rec[i]= ReadInt(f, &ok, 1);//printf("%02x",rec[i]);
394 sum= ReadInt(f, &ok, 1);//printf(" sum=%02x\n",sum);
397 if (((sum + chk) & 0xff) == 0)
401 if (get_mem_width(MEM_ROM) > 8)
403 for (i= 0; i < dnum; i++)
405 if (get_mem_width(MEM_ROM) <= 8)
407 set_mem(MEM_ROM, addr, rec[i]);
411 else if (get_mem_width(MEM_ROM) <= 16)
421 set_mem(MEM_ROM, addr, (high*256)+low);
430 if (sim->get_iarg('V', 0) &&
432 sim->cmd->printf("Unknown record type %d(0x%x)\n",
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);
441 if (sim->get_iarg('V', 0))
442 sim->cmd->printf("Read error in record %ld.\n", recnum);
445 if (get_mem_width(MEM_ROM) > 8 &&
447 set_mem(MEM_ROM, addr, low);
451 if (sim->get_iarg('V', 0))
452 sim->cmd->printf("%ld records have been read\n", recnum);
459 * Handling instruction map
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
468 cl_uc::inst_at(uint addr)
470 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
474 return(rom->inst_map->get(addr));
478 cl_uc::set_inst_at(uint addr)
480 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
483 rom->inst_map->set(addr);
487 cl_uc::del_inst_at(uint addr)
489 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
492 rom->inst_map->clear(addr);
496 cl_uc::there_is_inst(void)
498 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
502 return(!(rom->inst_map->empty()));
507 * Manipulating HW elements of the CPU
508 *****************************************************************************
511 /* Register callback hw objects for mem read/write */
514 cl_uc::register_hw_read(enum mem_class type, long addr, class cl_hw *hw)
519 if ((m= (class cl_mem*)mems->at(type)))
521 if ((l= m->read_locs->get_loc(addr)) == 0)
523 l= new cl_memloc(addr);
525 m->read_locs->add(l);
530 printf("cl_uc::register_hw_read TROUBLE\n");
534 cl_uc::register_hw_write(enum mem_class type, long addr, class cl_hw *hw)
538 /* Looking for a specific HW element */
541 cl_uc::get_hw(enum hw_cath cath, int *idx)
548 for (; i < hws->count; i++)
550 hw= (class cl_hw *)(hws->at(i));
551 if (hw->cathegory == cath)
562 cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
569 hw= get_hw(cath, &i);
574 hw= get_hw(cath, &i);
584 * Help of the command interpreter
590 static struct dis_entry empty= { 0, 0, 0, 0, NULL };
597 static struct name_entry empty= { 0, 0 };
604 static struct name_entry empty= { 0, 0 };
609 cl_uc::disass(uint addr, char *sep)
613 buf= (char*)malloc(100);
614 strcpy(buf, "uc::do_disass unimplemented\n");
619 cl_uc::print_disass(uint addr, class cl_console *con)
621 con->printf("uc::print_disass unimplemented\n");
625 cl_uc::print_regs(class cl_console *con)
627 con->printf("No registers\n");
631 cl_uc::inst_length(uint code)
633 struct dis_entry *tabl= dis_tbl();
636 for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
637 return(tabl[i].mnemonic?tabl[i].length:1);
641 cl_uc::get_name(uint addr, struct name_entry tab[], char *buf)
646 while (tab[i].name &&
647 (!(tab[i].cpu_type & type) ||
648 (tab[i].addr != addr)))
651 strcpy(buf, tab[i].name);
652 return(tab[i].name != NULL);
661 cl_uc::tick(int cycles)
664 int i, cpc= clock_per_cycle();
667 ticks->tick(cycles * cpc);
668 class it_level *il= (class it_level *)(it_levels->top());
670 isr_ticks->tick(cycles * cpc);
672 idle_ticks->tick(cycles * cpc);
673 for (i= 0; i < counters->count; i++)
675 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
678 if ((t->options&TICK_INISR) ||
680 t->tick(cycles * cpc);
685 for (i= 0; i < hws->count; i++)
687 hw= (class cl_hw *)(hws->at(i));
688 if (hw->flags & HWF_INSIDE)
695 cl_uc::get_counter(int nr)
697 if (nr >= counters->count)
699 return((class cl_ticker *)(counters->at(nr)));
703 cl_uc::get_counter(char *name)
709 for (i= 0; i < counters->count; i++)
711 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
714 strcmp(t->name, name) == 0)
721 cl_uc::add_counter(class cl_ticker *ticker, int nr)
723 while (counters->count <= nr)
725 counters->put_at(nr, ticker);
729 cl_uc::add_counter(class cl_ticker *ticker, char */*name*/)
733 if (counters->count < 1)
735 for (i= 1; i < counters->count; i++)
737 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
740 counters->put_at(i, ticker);
744 counters->add(ticker);
748 cl_uc::del_counter(int nr)
752 if (nr >= counters->count)
754 if ((t= (class cl_ticker *)(counters->at(0))) != 0)
756 counters->put_at(nr, 0);
760 cl_uc::del_counter(char *name)
766 for (i= 0; i < counters->count; i++)
768 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
771 strcmp(t->name, name) == 0)
774 counters->put_at(i, 0);
781 * Fetch without checking for breakpoint hit
789 code= read_mem(MEM_ROM, PC);
791 if (PC >= get_mem_size(MEM_ROM))
797 * Fetch but checking for breakpoint hit first
801 cl_uc::fetch(ulong *code)
808 if (sim->state & SIM_GO)
810 if ((brk= fbrk->get_bp(PC, &idx)) &&
813 if (brk->perm == brkDYNAMIC)
823 cl_uc::do_inst(int step)
842 cl_uc::pre_inst(void)
846 cl_uc::exec_inst(void)
852 cl_uc::post_inst(void)
857 * Time related functions
861 cl_uc::get_rtime(void)
865 d= (double)ticks/xtal;
867 return(ticks->get_rtime(xtal));
871 cl_uc::clock_per_cycle(void)
878 * Stack tracking system
882 cl_uc::st_push(class cl_stack_op *op)
888 cl_uc::st_call(class cl_stack_op *op)
894 cl_uc::st_pop(class cl_stack_op *op)
896 class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
904 cl_uc::st_ret(class cl_stack_op *op)
906 class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
915 * Breakpoint handling
919 cl_uc::fbrk_at(long addr)
923 return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
927 cl_uc::ebrk_at(t_addr addr, char *id)
932 for (i= 0; i < ebrk->count; i++)
934 eb= (class cl_ev_brk *)(ebrk->at(i));
935 if (eb->addr == addr &&
943 cl_uc::rm_fbrk(long addr)
949 cl_uc::rm_ebrk(t_addr addr, char *id)
954 for (i= 0; i < ebrk->count; i++)
956 eb= (class cl_ev_brk *)(ebrk->at(i));
957 if (eb->addr == addr &&
964 cl_uc::put_breaks(void)
968 cl_uc::remove_breaks(void)