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
50 cl_ticker::cl_ticker(int adir, int in_isr, char *aname)
57 name= aname?strdup(aname):0;
60 cl_ticker::~cl_ticker(void)
67 cl_ticker::tick(int nr)
75 cl_ticker::get_rtime(double xtal)
79 d= (double)ticks/xtal;
84 cl_ticker::dump(int nr, double xtal, class cl_console *con)
86 con->printf("timer #%d(\"%s\") %s%s: %g sec (%lu clks)\n",
87 nr, name?name:"unnamed",
88 (options&TICK_RUN)?"ON":"OFF",
89 (options&TICK_INISR)?",ISR":"",
90 get_rtime(xtal), ticks);
95 * Abstract microcontroller
96 ******************************************************************************
99 cl_uc::cl_uc(class cl_sim *asim):
104 mems= new cl_list(MEM_TYPES, 1);
105 hws = new cl_list(2, 1);
106 options= new cl_list(2, 2);
107 for (i= MEM_ROM; i < MEM_TYPES; i++)
109 ticks= new cl_ticker(+1, 0, "time");
110 isr_ticks= new cl_ticker(+1, TICK_INISR, "isr");
111 idle_ticks= new cl_ticker(+1, TICK_IDLE, "idle");
112 counters= new cl_list(2, 2);
113 it_levels= new cl_list(2, 2);
114 it_sources= new cl_list(2, 2);
115 class it_level *il= new it_level(-1, 0, 0, 0);
117 st_ops= new cl_list(2, 2);
146 if (!(sim->arg_avail('X')) ||
147 sim->get_farg('X', 0) == 0)
150 xtal= sim->get_farg('X', 0);
151 for (mc= MEM_ROM; mc < MEM_TYPES; mc++)
153 class cl_mem *m= mk_mem((enum mem_class)mc,
154 get_id_string(mem_classes, mc));
157 ebrk= new brk_coll(2, 2, (class cl_rom *)mem(MEM_ROM));
158 fbrk= new brk_coll(2, 2, (class cl_rom *)mem(MEM_ROM));
159 fbrk->Duplicates= DD_FALSE;
167 cl_uc::id_string(void)
169 return("unknown microcontroller");
181 idle_ticks->ticks= 0;
182 /*FIXME should we clear user counters?*/
183 il= (class it_level *)(it_levels->top());
187 il= (class it_level *)(it_levels->pop());
189 il= (class it_level *)(it_levels->top());
200 cl_uc::mk_mem(enum mem_class type, char *class_name)
204 if (get_mem_size(type) <= 0)
207 m= new cl_rom(get_mem_size(type), get_mem_width(type));
209 m= new cl_mem(type, get_id_string(mem_classes, type),
210 get_mem_size(type), get_mem_width(type));
216 cl_uc::get_mem_size(enum mem_class type)
220 case MEM_ROM: return(0x10000);
221 case MEM_XRAM: return(0x10000);
222 case MEM_IRAM: return(0x100);
223 case MEM_SFR: return(0x100);
231 cl_uc::get_mem_width(enum mem_class type)
237 cl_uc::mk_hw_elements(void)
243 * Read/write simulated memory
247 cl_uc::read_mem(enum mem_class type, t_mem addr)
251 if ((m= (class cl_mem*)mems->at(type)))
252 return(m->read(addr));
254 fprintf(stderr, "cl_uc::read_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
259 cl_uc::get_mem(enum mem_class type, t_addr addr)
263 if ((m= (class cl_mem*)mems->at(type)))
264 return(m->get(addr));
266 printf("cl_uc::get_mem(type= %d, 0x%06lx) TROUBLE\n", type, addr);
271 cl_uc::write_mem(enum mem_class type, t_addr addr, t_mem val)
275 if ((m= (class cl_mem*)mems->at(type)))
277 m->write(addr, &val);
281 else printf("cl_uc::write_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
285 cl_uc::set_mem(enum mem_class type, t_addr addr, t_mem val)
289 if ((m= (class cl_mem*)mems->at(type)))
292 else printf("cl_uc::set_mem(type= %d, 0x%06lx, 0x%lx) TROUBLE\n", type, addr, val);
296 cl_uc::mem(enum mem_class type)
298 if (mems->count < type)
300 {printf("TROUBLE\n"); return(0);
302 return((class cl_mem *)(mems->at(type)));
306 cl_uc::mem(char *class_name)
313 s= n= strdup(class_name);
322 for (i= 0; !found && i < mems->count; i++)
324 cl_mem *m= (cl_mem *)(mems->at(i));
329 s= mcn= strdup(m->class_name);
335 if (strstr(/*m->class_name*/mcn,/*class_name*/n) == /*m->class_name*/mcn)
349 cl_uc::MEM(enum mem_class type)
353 if ((m= mem(type)) == 0)
355 {printf("TROUBLE\n"); return(0);
357 return((TYPE_UBYTE *)(m->mem));
361 /* Local function for `read_hex_file' method to read some bytes */
364 ReadInt(FILE *f, bool *ok, int bytes)
372 if (fscanf(f, "%2c", &s2[0]) == EOF)
375 l= l*256 + strtol(s2, NULL, 16);
384 * Reading intel hexa file into EROM
385 *____________________________________________________________________________
387 * If parameter is a NULL pointer, this function reads data from `cmd_in'
392 cl_uc::read_hex_file(const char *name)
396 long written= 0, recnum= 0;
398 uchar dnum; // data number
399 uchar rtyp=0; // record type
400 uint addr= 0; // address
401 uchar rec[300]; // data record
402 uchar sum ; // checksum
410 sim->cmd->printf("cl_uc::read_hex_file File name not specified\n");
414 if ((f= fopen(name, "r")) == NULL)
416 fprintf(stderr, "Can't open `%s': %s\n", name, strerror(errno));
420 //memset(inst_map, '\0', sizeof(inst_map));
425 while (((c= getc(f)) != ':') &&
428 {fprintf(stderr, ": not found\n");break;}
430 dnum= ReadInt(f, &ok, 1);//printf("dnum=%02x",dnum);
432 addr= ReadInt(f, &ok, 2);//printf("addr=%04x",addr);
434 chk+= ((addr >> 8) & 0xff);
435 rtyp= ReadInt(f, &ok, 1);//printf("rtyp=%02x ",rtyp);
437 for (i= 0; ok && (i < dnum); i++)
439 rec[i]= ReadInt(f, &ok, 1);//printf("%02x",rec[i]);
444 sum= ReadInt(f, &ok, 1);//printf(" sum=%02x\n",sum);
447 if (((sum + chk) & 0xff) == 0)
451 if (get_mem_width(MEM_ROM) > 8)
453 for (i= 0; i < dnum; i++)
455 if (get_mem_width(MEM_ROM) <= 8)
457 set_mem(MEM_ROM, addr, rec[i]);
461 else if (get_mem_width(MEM_ROM) <= 16)
471 set_mem(MEM_ROM, addr, (high*256)+low);
480 if (sim->get_iarg('V', 0) &&
482 sim->cmd->printf("Unknown record type %d(0x%x)\n",
486 if (sim->get_iarg('V', 0))
487 sim->cmd->printf("Checksum error (%x instead of %x) in "
488 "record %ld.\n", chk, sum, recnum);
491 if (sim->get_iarg('V', 0))
492 sim->cmd->printf("Read error in record %ld.\n", recnum);
495 if (get_mem_width(MEM_ROM) > 8 &&
497 set_mem(MEM_ROM, addr, low);
501 if (sim->get_iarg('V', 0))
502 sim->cmd->printf("%ld records have been read\n", recnum);
509 * Handling instruction map
511 * `inst_at' is checking if the specified address is in instruction
512 * map and `set_inst_at' marks the address in the map and
513 * `del_inst_at' deletes the mark. `there_is_inst' cheks if there is
514 * any mark in the map
518 cl_uc::inst_at(t_addr addr)
520 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
524 return(rom->inst_map->get(addr));
528 cl_uc::set_inst_at(t_addr addr)
530 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
533 rom->inst_map->set(addr);
537 cl_uc::del_inst_at(t_addr addr)
539 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
542 rom->inst_map->clear(addr);
546 cl_uc::there_is_inst(void)
548 class cl_rom *rom= (class cl_rom *)mem(MEM_ROM);
552 return(!(rom->inst_map->empty()));
557 * Manipulating HW elements of the CPU
558 *****************************************************************************
561 /* Register callback hw objects for mem read/write */
564 cl_uc::register_hw_read(enum mem_class type, t_addr addr, class cl_hw *hw)
569 if ((m= (class cl_mem*)mems->at(type)))
571 if ((l= m->read_locs->get_loc(addr)) == 0)
573 l= new cl_memloc(addr);
575 m->read_locs->add(l);
580 printf("cl_uc::register_hw_read TROUBLE\n");
584 cl_uc::register_hw_write(enum mem_class type, t_addr addr, class cl_hw *hw)
588 /* Looking for a specific HW element */
591 cl_uc::get_hw(enum hw_cath cath, int *idx)
598 for (; i < hws->count; i++)
600 hw= (class cl_hw *)(hws->at(i));
601 if (hw->cathegory == cath)
612 cl_uc::get_hw(char *id_string, int *idx)
619 for (; i < hws->count; i++)
621 hw= (class cl_hw *)(hws->at(i));
622 if (strstr(hw->id_string, id_string) == hw->id_string)
633 cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
640 hw= get_hw(cath, &i);
645 hw= get_hw(cath, &i);
654 cl_uc::get_hw(char *id_string, int hwid, int *idx)
661 hw= get_hw(id_string, &i);
666 hw= get_hw(id_string, &i);
676 * Help of the command interpreter
682 static struct dis_entry empty= { 0, 0, 0, 0, NULL };
689 static struct name_entry empty= { 0, 0 };
696 static struct name_entry empty= { 0, 0 };
701 cl_uc::disass(t_addr addr, char *sep)
705 buf= (char*)malloc(100);
706 strcpy(buf, "uc::do_disass unimplemented\n");
711 cl_uc::print_disass(t_addr addr, class cl_console *con)
716 class cl_mem *rom= mem(MEM_ROM);
717 t_mem code= get_mem(MEM_ROM, addr);
722 dis= disass(addr, NULL);
724 con->printf("%c", (b->perm == brkFIX)?'F':'D');
727 con->printf("%c ", inst_at(addr)?' ':'?');
728 con->printf(rom->addr_format, addr); con->printf(" ");
729 con->printf(rom->data_format, code);
730 for (i= 1; i < inst_length(code); i++)
733 con->printf(rom->data_format, get_mem(MEM_ROM, addr+i));
735 int li= longest_inst();
739 j= rom->width/4 + ((rom->width%4)?1:0) + 1;
741 con->printf(" "), j--;
744 con->printf(" %s\n", dis);
749 cl_uc::print_regs(class cl_console *con)
751 con->printf("No registers\n");
755 cl_uc::inst_length(t_mem code)
757 struct dis_entry *tabl= dis_tbl();
760 for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
761 return(tabl[i].mnemonic?tabl[i].length:1);
765 cl_uc::longest_inst(void)
767 struct dis_entry *de= dis_tbl();
773 if (de->length > max)
781 cl_uc::get_name(t_addr addr, struct name_entry tab[], char *buf)
786 while (tab[i].name &&
787 (!(tab[i].cpu_type & type) ||
788 (tab[i].addr != addr)))
791 strcpy(buf, tab[i].name);
792 return(tab[i].name != NULL);
796 cl_uc::symbolic_bit_name(t_addr bit_address,
805 while (bit_tbl()[i].name &&
806 (bit_tbl()[i].addr != bit_address))
808 if (bit_tbl()[i].name)
810 sym_name= strdup(bit_tbl()[i].name);
816 strstr(mem->class_name, "sfr") == mem->class_name)
819 while (sfr_tbl()[i].name &&
820 (sfr_tbl()[i].addr != mem_addr))
822 if (sfr_tbl()[i].name)
823 sym_name= strdup(sfr_tbl()[i].name);
829 sym_name= (char *)malloc(16);
830 sprintf(sym_name, mem?(mem->addr_format):"0x%06x", mem_addr);
832 sym_name= (char *)realloc(sym_name, strlen(sym_name)+2);
833 strcat(sym_name, ".");
841 sprintf(bitnumstr, "%1d", i);
842 strcat(sym_name, bitnumstr);
852 cl_uc::tick(int cycles)
855 int i, cpc= clock_per_cycle();
858 ticks->tick(cycles * cpc);
859 class it_level *il= (class it_level *)(it_levels->top());
861 isr_ticks->tick(cycles * cpc);
863 idle_ticks->tick(cycles * cpc);
864 for (i= 0; i < counters->count; i++)
866 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
869 if ((t->options&TICK_INISR) ||
871 t->tick(cycles * cpc);
876 for (i= 0; i < hws->count; i++)
878 hw= (class cl_hw *)(hws->at(i));
879 if (hw->flags & HWF_INSIDE)
886 cl_uc::get_counter(int nr)
888 if (nr >= counters->count)
890 return((class cl_ticker *)(counters->at(nr)));
894 cl_uc::get_counter(char *name)
900 for (i= 0; i < counters->count; i++)
902 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
905 strcmp(t->name, name) == 0)
912 cl_uc::add_counter(class cl_ticker *ticker, int nr)
914 while (counters->count <= nr)
916 counters->put_at(nr, ticker);
920 cl_uc::add_counter(class cl_ticker *ticker, char */*name*/)
924 if (counters->count < 1)
926 for (i= 1; i < counters->count; i++)
928 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
931 counters->put_at(i, ticker);
935 counters->add(ticker);
939 cl_uc::del_counter(int nr)
943 if (nr >= counters->count)
945 if ((t= (class cl_ticker *)(counters->at(0))) != 0)
947 counters->put_at(nr, 0);
951 cl_uc::del_counter(char *name)
957 for (i= 0; i < counters->count; i++)
959 class cl_ticker *t= (class cl_ticker *)(counters->at(i));
962 strcmp(t->name, name) == 0)
965 counters->put_at(i, 0);
972 * Fetch without checking for breakpoint hit
980 code= read_mem(MEM_ROM, PC);
982 if (PC >= get_mem_size(MEM_ROM))
988 * Fetch but checking for breakpoint hit first
992 cl_uc::fetch(t_mem *code)
999 if (sim->state & SIM_GO)
1001 if ((brk= fbrk->get_bp(PC, &idx)) &&
1004 if (brk->perm == brkDYNAMIC)
1014 cl_uc::do_inst(int step)
1033 cl_uc::pre_inst(void)
1037 cl_uc::exec_inst(void)
1043 cl_uc::post_inst(void)
1048 * Time related functions
1052 cl_uc::get_rtime(void)
1056 d= (double)ticks/xtal;
1058 return(ticks->get_rtime(xtal));
1062 cl_uc::clock_per_cycle(void)
1069 * Stack tracking system
1073 cl_uc::st_push(class cl_stack_op *op)
1079 cl_uc::st_call(class cl_stack_op *op)
1085 cl_uc::st_pop(class cl_stack_op *op)
1087 class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
1095 cl_uc::st_ret(class cl_stack_op *op)
1097 class cl_stack_op *sop= (class cl_stack_op *)(st_ops->pop());
1106 * Breakpoint handling
1109 class cl_fetch_brk *
1110 cl_uc::fbrk_at(t_addr addr)
1114 return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
1118 cl_uc::ebrk_at(t_addr addr, char *id)
1121 class cl_ev_brk *eb;
1123 for (i= 0; i < ebrk->count; i++)
1125 eb= (class cl_ev_brk *)(ebrk->at(i));
1126 if (eb->addr == addr &&
1127 !strcmp(eb->id, id))
1134 cl_uc::rm_fbrk(long addr)
1139 /* Get a breakpoint specified by its number */
1142 cl_uc::brk_by_nr(int nr)
1146 if ((bp= fbrk->get_bp(nr)))
1148 if ((bp= ebrk->get_bp(nr)))
1153 /* Get a breakpoint from the specified collection by its number */
1156 cl_uc::brk_by_nr(class brk_coll *bpcoll, int nr)
1160 if ((bp= bpcoll->get_bp(nr)))
1165 /* Remove an event breakpoint specified by its address and id */
1168 cl_uc::rm_ebrk(t_addr addr, char *id)
1171 class cl_ev_brk *eb;
1173 for (i= 0; i < ebrk->count; i++)
1175 eb= (class cl_ev_brk *)(ebrk->at(i));
1176 if (eb->addr == addr &&
1177 !strcmp(eb->id, id))
1182 /* Remove a breakpoint specified by its number */
1185 cl_uc::rm_brk(int nr)
1189 if ((bp= brk_by_nr(fbrk, nr)))
1190 fbrk->del_bp(bp->addr);
1191 else if ((bp= brk_by_nr(ebrk, nr)))
1192 ebrk->free_at(ebrk->index_of(bp));
1196 cl_uc::put_breaks(void)
1199 /* Remove all fetch and event breakpoints */
1202 cl_uc::remove_all_breaks(void)
1206 class cl_brk *brk= (class cl_brk *)(fbrk->at(0));
1207 fbrk->del_bp(brk->addr);
1210 ebrk->free_at(ebrk->count-1);
1214 cl_uc::make_new_brknr(void)
1216 if (brk_counter == 0)
1217 return(brk_counter= 1);
1218 if (fbrk->count == 0 &&
1220 return(brk_counter= 1);
1221 return(++brk_counter);
1225 cl_uc::mk_ebrk(enum brk_perm perm, class cl_mem *mem,
1226 char op, t_addr addr, int hit)
1235 b= new cl_rc_brk(make_new_brknr(), addr, perm, hit);
1241 b= new cl_ri_brk(make_new_brknr(), addr, perm, hit);
1243 b= new cl_wi_brk(make_new_brknr(), addr, perm, hit);
1249 b= new cl_rx_brk(make_new_brknr(), addr, perm, hit);
1251 b= new cl_wx_brk(make_new_brknr(), addr, perm, hit);
1257 b= new cl_rs_brk(make_new_brknr(), addr, perm, hit);
1259 b= new cl_ws_brk(make_new_brknr(), addr, perm, hit);