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
359 f= sim->/*FIXME*/cmd_in();
361 if ((f= fopen(name, "r")) == NULL)
363 fprintf(stderr, "Can't open `%s': %s\n", name, strerror(errno));
367 //memset(inst_map, '\0', sizeof(inst_map));
372 while (((c= getc(f)) != ':') &&
375 {fprintf(stderr, ": not found\n");break;}
377 dnum= ReadInt(f, &ok, 1);//printf("dnum=%02x",dnum);
379 addr= ReadInt(f, &ok, 2);//printf("addr=%04x",addr);
381 chk+= ((addr >> 8) & 0xff);
382 rtyp= ReadInt(f, &ok, 1);//printf("rtyp=%02x ",rtyp);
384 for (i= 0; ok && (i < dnum); i++)
386 rec[i]= ReadInt(f, &ok, 1);//printf("%02x",rec[i]);
391 sum= ReadInt(f, &ok, 1);//printf(" sum=%02x\n",sum);
394 if (((sum + chk) & 0xff) == 0)
398 if (get_mem_width(MEM_ROM) > 8)
400 for (i= 0; i < dnum; i++)
402 if (get_mem_width(MEM_ROM) <= 8)
404 set_mem(MEM_ROM, addr, rec[i]);
408 else if (get_mem_width(MEM_ROM) <= 16)
418 set_mem(MEM_ROM, addr, (high*256)+low);
427 if (sim->get_iarg('V', 0) &&
429 fprintf(sim->cmd_out(),
430 "Unknown record type %d(0x%x)\n", rtyp, rtyp);
433 if (sim->get_iarg('V', 0))
434 fprintf(sim->cmd_out(),
435 "Checksum error (%x instead of %x) in record %ld.\n",
439 if (sim->get_iarg('V', 0))
440 fprintf(sim->cmd_out(), "Read error in record %ld.\n", recnum);
443 if (get_mem_width(MEM_ROM) > 8 &&
445 set_mem(MEM_ROM, addr, low);
449 if (sim->get_iarg('V', 0))
450 fprintf(sim->cmd_out(), "%ld records have been read\n", recnum);
457 * Handling instruction map
459 * `inst_at' is checking if the specified address is in instruction
460 * map and `set_inst_at' marks the address in the map and
461 * `del_inst_at' deletes the mark. `there_is_inst' cheks if there is
462 * any mark in the map
466 cl_uc::inst_at(uint addr)
468 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
472 return(rom->inst_map->get(addr));
476 cl_uc::set_inst_at(uint addr)
478 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
481 rom->inst_map->set(addr);
485 cl_uc::del_inst_at(uint addr)
487 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
490 rom->inst_map->clear(addr);
494 cl_uc::there_is_inst(void)
496 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
500 return(!(rom->inst_map->empty()));
505 * Manipulating HW elements of the CPU
506 *****************************************************************************
509 /* Register callback hw objects for mem read/write */
512 cl_uc::register_hw_read(enum mem_class type, long addr, class cl_hw *hw)
517 if ((m= (class cl_mem*)mems->at(type)))
519 if ((l= m->read_locs->get_loc(addr)) == 0)
521 l= new cl_memloc(addr);
523 m->read_locs->add(l);
528 printf("cl_uc::register_hw_read TROUBLE\n");
532 cl_uc::register_hw_write(enum mem_class type, long addr, class cl_hw *hw)
536 /* Looking for a specific HW element */
539 cl_uc::get_hw(enum hw_cath cath, int *idx)
546 for (; i < hws->count; i++)
548 hw= (class cl_hw *)(hws->at(i));
549 if (hw->cathegory == cath)
560 cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
567 hw= get_hw(cath, &i);
572 hw= get_hw(cath, &i);
582 * Help of the command interpreter
588 static struct dis_entry empty= { 0, 0, 0, 0, NULL };
595 static struct name_entry empty= { 0, 0 };
602 static struct name_entry empty= { 0, 0 };
607 cl_uc::disass(uint addr, char *sep)
611 buf= (char*)malloc(100);
612 strcpy(buf, "uc::do_disass unimplemented\n");
617 cl_uc::print_disass(uint addr, class cl_console *con)
619 con->printf("uc::print_disass unimplemented\n");
623 cl_uc::print_regs(class cl_console *con)
625 con->printf("No registers\n");
629 cl_uc::inst_length(uint code)
631 struct dis_entry *tabl= dis_tbl();
634 for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
635 return(tabl[i].mnemonic?tabl[i].length:1);
639 cl_uc::get_name(uint addr, struct name_entry tab[], char *buf)
644 while (tab[i].name &&
645 (!(tab[i].cpu_type & type) ||
646 (tab[i].addr != addr)))
649 strcpy(buf, tab[i].name);
650 return(tab[i].name != NULL);
659 cl_uc::tick(int cycles)
662 int i, cpc= clock_per_cycle();
665 ticks->tick(cycles * cpc);
666 class it_level *il= (class it_level *)(it_levels->top());
668 isr_ticks->tick(cycles * cpc);
670 idle_ticks->tick(cycles * cpc);
671 for (i= 0; i < counters->count; i++)
673 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
676 if ((t->options&TICK_INISR) ||
678 t->tick(cycles * cpc);
683 for (i= 0; i < hws->count; i++)
685 hw= (class cl_hw *)(hws->at(i));
686 if (hw->flags & HWF_INSIDE)
693 cl_uc::get_counter(int nr)
695 if (nr >= counters->count)
697 return((class cl_ticker *)(counters->at(nr)));
701 cl_uc::get_counter(char *name)
707 for (i= 0; i < counters->count; i++)
709 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
712 strcmp(t->name, name) == 0)
719 cl_uc::add_counter(class cl_ticker *ticker, int nr)
721 while (counters->count <= nr)
723 counters->put_at(nr, ticker);
727 cl_uc::add_counter(class cl_ticker *ticker, char */*name*/)
731 if (counters->count < 1)
733 for (i= 1; i < counters->count; i++)
735 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
738 counters->put_at(i, ticker);
742 counters->add(ticker);
746 cl_uc::del_counter(int nr)
750 if (nr >= counters->count)
752 if ((t= (class cl_ticker *)(counters->at(0))) != 0)
754 counters->put_at(nr, 0);
758 cl_uc::del_counter(char *name)
764 for (i= 0; i < counters->count; i++)
766 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
769 strcmp(t->name, name) == 0)
772 counters->put_at(i, 0);
779 * Fetch without checking for breakpoint hit
787 code= read_mem(MEM_ROM, PC);
789 if (PC >= get_mem_size(MEM_ROM))
795 * Fetch but checking for breakpoint hit first
799 cl_uc::fetch(ulong *code)
806 if (sim->state & SIM_GO)
808 if ((brk= fbrk->get_bp(PC, &idx)) &&
811 if (brk->perm == brkDYNAMIC)
821 cl_uc::do_inst(int step)
840 cl_uc::pre_inst(void)
844 cl_uc::exec_inst(void)
850 cl_uc::post_inst(void)
855 * Time related functions
859 cl_uc::get_rtime(void)
863 d= (double)ticks/xtal;
865 return(ticks->get_rtime(xtal));
869 cl_uc::clock_per_cycle(void)
876 * Stack tracking system
880 cl_uc::st_push(class cl_stack_op *op)
886 cl_uc::st_call(class cl_stack_op *op)
892 cl_uc::st_pop(class cl_stack_op *op)
894 class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
902 cl_uc::st_ret(class cl_stack_op *op)
904 class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
913 * Breakpoint handling
917 cl_uc::fbrk_at(long addr)
921 return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
925 cl_uc::ebrk_at(t_addr addr, char *id)
930 for (i= 0; i < ebrk->count; i++)
932 eb= (class cl_ev_brk *)(ebrk->at(i));
933 if (eb->addr == addr &&
941 cl_uc::rm_fbrk(long addr)
947 cl_uc::rm_ebrk(t_addr addr, char *id)
952 for (i= 0; i < ebrk->count; i++)
954 eb= (class cl_ev_brk *)(ebrk->at(i));
955 if (eb->addr == addr &&
962 cl_uc::put_breaks(void)
966 cl_uc::remove_breaks(void)