2 * Simulator of microcontrollers (uc51.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
37 #include <sys/types.h>
55 #include "interruptcl.h"
59 * Making a new micro-controller and reset it
62 t_uc51::t_uc51(int Itype, int Itech, class cl_sim *asim):
71 debug= asim->app->args->get_iarg('V', 0);
73 options->add(new cl_bool_opt(&debug, "verbose", "Verbose flag."));
74 options->add(new cl_bool_opt(&stop_at_it, "stopit",
75 "Stop if interrupt accepted."));
76 options->add(new cl_cons_debug_opt(asim->app, "debug",
77 "Debug messages appears on this console."));
79 serial_in = (FILE*)asim->app->args->get_parg(0, "Ser_in");
80 serial_out= (FILE*)asim->app->args->get_parg(0, "Ser_out");
83 // making `serial' unbuffered
84 if (setvbuf(serial_in, NULL, _IONBF, 0))
85 perror("Unbuffer serial input channel");
87 if ((i= fcntl(fileno(serial_in), F_GETFL, 0)) < 0)
88 perror("Get flags of serial input");
90 if (fcntl(fileno(serial_in), F_SETFL, i) < 0)
91 perror("Set flags of serial input");
92 // switching terminal to noncanonical mode
93 if (isatty(fileno(serial_in)))
95 tcgetattr(fileno(serial_in), &saved_attributes_in);
96 tcgetattr(fileno(serial_in), &tattr);
97 tattr.c_lflag&= ~(ICANON|ECHO);
100 tcsetattr(fileno(serial_in), TCSAFLUSH, &tattr);
103 fprintf(stderr, "Warning: serial input interface connected to a "
104 "non-terminal file.\n");
108 // making `serial' unbuffered
109 if (setvbuf(serial_out, NULL, _IONBF, 0))
110 perror("Unbuffer serial output channel");
111 // setting O_NONBLOCK
112 if ((i= fcntl(fileno(serial_out), F_GETFL, 0)) < 0)
113 perror("Get flags of serial output");
115 if (fcntl(fileno(serial_out), F_SETFL, i) < 0)
116 perror("Set flags of serial output");
117 // switching terminal to noncanonical mode
118 if (isatty(fileno(serial_out)))
120 tcgetattr(fileno(serial_out), &saved_attributes_out);
121 tcgetattr(fileno(serial_out), &tattr);
122 tattr.c_lflag&= ~(ICANON|ECHO);
123 tattr.c_cc[VMIN] = 1;
124 tattr.c_cc[VTIME]= 0;
125 tcsetattr(fileno(serial_out), TCSAFLUSH, &tattr);
128 fprintf(stderr, "Warning: serial output interface connected to a "
129 "non-terminal file.\n");
132 for (i= 0; i < 4; i++)
134 it_sources->add(new cl_it_src(bmEX0, TCON, bmIE0, 0x0003, true,
136 it_sources->add(new cl_it_src(bmET0, TCON, bmTF0, 0x000b, true,
138 it_sources->add(new cl_it_src(bmEX1, TCON, bmIE1, 0x0013, true,
140 it_sources->add(new cl_it_src(bmET1, TCON, bmTF1, 0x001b, true,
142 it_sources->add(new cl_it_src(bmES , SCON, bmTI , 0x0023, false,
144 it_sources->add(new cl_it_src(bmES , SCON, bmRI , 0x0023, false,
150 * Initializing. Virtual calls go here
151 * This method must be called first after object creation.
162 static char id_string_51[100];
165 t_uc51::id_string(void)
169 for (i= 0; cpus_51[i].type_str != NULL && cpus_51[i].type != type; i++) ;
170 sprintf(id_string_51, "%s %s",
171 cpus_51[i].type_str?cpus_51[i].type_str:"51",
172 (technology==CPU_HMOS)?"HMOS":"CMOS");
173 return(id_string_51);
177 t_uc51::mk_hw_elements(void)
181 hws->add(h= new cl_timer0(this));
183 hws->add(h= new cl_timer1(this));
185 hws->add(h= new cl_serial(this));
187 hws->add(h= new cl_port(this, 0));
189 hws->add(h= new cl_port(this, 1));
191 hws->add(h= new cl_port(this, 2));
193 hws->add(h= new cl_port(this, 3));
195 hws->add(h= new cl_interrupt(this));
200 t_uc51::mk_mem(enum mem_class type, char *class_name)
202 class cl_mem *m= cl_uc::mk_mem(type, class_name);
205 if (type == MEM_IRAM)
212 * Destroying the micro-controller object
215 t_uc51::~t_uc51(void)
219 if (isatty(fileno(serial_out)))
220 tcsetattr(fileno(serial_out), TCSANOW, &saved_attributes_out);
225 if (isatty(fileno(serial_in)))
226 tcsetattr(fileno(serial_in), TCSANOW, &saved_attributes_in);
233 * Writing data to EROM
237 t_uc51::write_rom(t_addr addr, ulong data)
239 if (addr < EROM_SIZE)
240 set_mem(MEM_ROM, addr, data);
245 * Disassembling an instruction
249 t_uc51::dis_tbl(void)
255 t_uc51::sfr_tbl(void)
261 t_uc51::bit_tbl(void)
267 t_uc51::disass(t_addr addr, char *sep)
269 char work[256], temp[20], c[2];
270 char *buf, *p, *b, *t;
271 t_mem code= get_mem(MEM_ROM, addr);
274 b= dis_tbl()[code].mnemonic;
282 case 'A': // absolute address
283 sprintf(temp, "%04lx",
285 (((code>>5)&0x07)*256 +
286 get_mem(MEM_ROM, addr+1)));
288 case 'l': // long address
289 sprintf(temp, "%04lx",
290 get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2));
292 case 'a': // addr8 (direct address) at 2nd byte
293 if (!get_name(get_mem(MEM_ROM, addr+1), sfr_tbl(), temp))
294 sprintf(temp, "%02lx", get_mem(MEM_ROM, addr+1));
296 case '8': // addr8 (direct address) at 3rd byte
297 if (!get_name(get_mem(MEM_ROM, addr+2), sfr_tbl(), temp))
298 sprintf(temp, "%02lx", get_mem(MEM_ROM, addr+1));
299 sprintf(temp, "%02lx", get_mem(MEM_ROM, addr+2));
301 case 'b': // bitaddr at 2nd byte
302 if (get_name(get_mem(MEM_ROM, addr+1), bit_tbl(), temp))
304 if (get_name(get_bitidx(get_mem(MEM_ROM, addr+1)),
308 sprintf(c, "%1ld", get_mem(MEM_ROM, addr+1)&0x07);
312 sprintf(temp, "%02x.%ld",
313 get_bitidx(get_mem(MEM_ROM, addr+1)),
314 get_mem(MEM_ROM, addr+1)&0x07);
316 case 'r': // rel8 address at 2nd byte
317 sprintf(temp, "%04lx",
318 addr+2+(signed char)(get_mem(MEM_ROM, addr+1)));
320 case 'R': // rel8 address at 3rd byte
321 sprintf(temp, "%04lx",
322 addr+3+(signed char)(get_mem(MEM_ROM, addr+2)));
324 case 'd': // data8 at 2nd byte
325 sprintf(temp, "%02lx", get_mem(MEM_ROM, addr+1));
327 case 'D': // data8 at 3rd byte
328 sprintf(temp, "%02lx", get_mem(MEM_ROM, addr+2));
330 case '6': // data16 at 2nd(H)-3rd(L) byte
331 sprintf(temp, "%04lx",
332 get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2));
347 p= strchr(work, ' ');
354 buf= (char *)malloc(6+strlen(p)+1);
356 buf= (char *)malloc((p-work)+strlen(sep)+strlen(p)+1);
357 for (p= work, b= buf; *p != ' '; p++, b++)
363 while (strlen(buf) < 6)
374 t_uc51::print_regs(class cl_console *con)
379 start= sfr->get(PSW) & 0x18;
380 //dump_memory(iram, &start, start+7, 8, /*sim->cmd_out()*/con, sim);
381 iram->dump(start, start+7, 8, con);
382 start= sfr->get(PSW) & 0x18;
383 data= iram->get(iram->get(start));
384 con->dd_printf("%06x %02x %c",
385 iram->get(start), data, isprint(data)?data:'.');
387 con->dd_printf(" ACC= 0x%02x %3d %c B= 0x%02x",
388 sfr->get(ACC), sfr->get(ACC),
389 isprint(sfr->get(ACC))?(sfr->get(ACC)):'.', sfr->get(B));
391 data= get_mem(MEM_XRAM, sfr->get(DPH)*256+sfr->get(DPL));
392 con->dd_printf(" DPTR= 0x%02x%02x @DPTR= 0x%02x %3d %c\n", sfr->get(DPH),
393 sfr->get(DPL), data, data, isprint(data)?data:'.');
395 data= iram->get(iram->get(start+1));
396 con->dd_printf("%06x %02x %c", iram->get(start+1), data,
397 isprint(data)?data:'.');
399 con->dd_printf(" PSW= 0x%02x CY=%c AC=%c OV=%c P=%c\n", data,
400 (data&bmCY)?'1':'0', (data&bmAC)?'1':'0',
401 (data&bmOV)?'1':'0', (data&bmP)?'1':'0');
403 print_disass(PC, con);
408 t_uc51::extract_bit_address(t_addr bit_address,
415 if (bit_address > 0xff)
418 *bit_mask= 1 << (bit_address % 8);
421 if (bit_address < 0x80)
422 *mem_addr= bit_address/8 + 0x20;
424 *mem_addr= bit_address & 0xf8;
431 * Resetting the micro-controller
451 s_sending = DD_FALSE;
452 s_receiving= DD_FALSE;
459 * Setting up SFR area to reset value
463 t_uc51::clear_sfr(void)
467 for (i= 0; i < SFR_SIZE; i++)
474 prev_p1= port_pins[1] & sfr->get(P1);
475 prev_p3= port_pins[3] & sfr->get(P3);
480 * Analyzing code and settig up instruction map
484 t_uc51::analyze(t_addr addr)
487 struct dis_entry *tabl;
489 code= get_mem(MEM_ROM, addr);
490 tabl= &(dis_tbl()[code]);
491 while (!inst_at(addr) &&
492 code != 0xa5 /* break point */)
495 switch (tabl->branch)
498 analyze((addr & 0xf800)|
499 ((get_mem(MEM_ROM, addr+1)&0x07)*256+
500 get_mem(MEM_ROM, addr+2)));
501 analyze(addr+tabl->length);
504 addr= (addr & 0xf800)|
505 ((get_mem(MEM_ROM, addr+1) & 0x07)*256 + get_mem(MEM_ROM, addr+2));
508 analyze(get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2));
509 analyze(addr+tabl->length);
512 addr= get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2);
514 case 'r': // reljmp (2nd byte)
515 analyze((addr + (signed char)(get_mem(MEM_ROM, addr+1))) &
517 analyze(addr+tabl->length);
519 case 'R': // reljmp (3rd byte)
521 (signed char)(get_mem(MEM_ROM, addr+2)))&(EROM_SIZE-1));
522 analyze(addr+tabl->length);
527 target= get_mem(MEM_ROM, addr+1);
529 addr= (addr+target)&(EROM_SIZE-1);
535 addr= (addr+tabl->length) & (EROM_SIZE - 1);
538 code= get_mem(MEM_ROM, addr);
539 tabl= &(dis_tbl()[code]);
545 * Inform hardware elements that `cycles' machine cycles have elapsed
549 t_uc51::tick(int cycles)
555 s_tr_tick+= (l= cycles * clock_per_cycle());
562 * Correcting direct address
564 * This function returns address of addressed element which can be an IRAM
569 t_uc51::get_direct(t_mem addr, t_addr *ev_i, t_addr *ev_s)
571 if (addr < SFR_START)
573 return(&(iram->umem8[*ev_i= addr]));
574 //return(&(MEM(MEM_IRAM)[*ev_i= addr]));
578 return(&(sfr->umem8[*ev_s= addr]));
579 //return(&(MEM(MEM_SFR)[*ev_s= addr]));
584 * Calculating address of indirectly addressed IRAM cell
585 * If CPU is 8051 and addr is over 127, it must be illegal!
589 t_uc51::get_indirect(uchar addr, int *res)
591 if (addr >= SFR_START)
595 return(&(iram->umem8[addr]));
596 //return(&(MEM(MEM_IRAM)[addr]));
601 * Calculating address of specified register cell in IRAM
605 t_uc51::get_reg(uchar regnum)
607 return(&(iram->umem8[(sfr->get(PSW) & (bmRS0|bmRS1)) |
609 //return(&(MEM(MEM_IRAM)[(sfr->get(PSW) & (bmRS0|bmRS1)) |
610 // (regnum & 0x07)]));
614 t_uc51::get_reg(uchar regnum, t_addr *event)
616 return(&(iram->umem8[*event= (sfr->get(PSW) & (bmRS0|bmRS1)) |
618 //return(&(MEM(MEM_IRAM)[*event= (sfr->get(PSW) & (bmRS0|bmRS1)) |
619 // (regnum & 0x07)]));
624 * Calculating address of IRAM or SFR cell which contains addressed bit
625 * Next function returns index of cell which contains addressed bit.
629 t_uc51::get_bit(uchar bitaddr)
633 return(&(iram->umem8[(bitaddr/8)+32]));
634 //return(&(MEM(MEM_IRAM)[(bitaddr/8)+32]));
636 return(&(iram->umem8[bitaddr & 0xf8]));
637 //return(&(MEM(MEM_SFR)[bitaddr & 0xf8]));
641 t_uc51::get_bit(uchar bitaddr, t_addr *ev_i, t_addr *ev_s)
645 return(&(iram->umem8[*ev_i= (bitaddr/8)+32]));
646 //return(&(MEM(MEM_IRAM)[*ev_i= (bitaddr/8)+32]));
648 return(&(sfr->umem8[*ev_s= bitaddr & 0xf8]));
649 //return(&(MEM(MEM_SFR)[*ev_s= bitaddr & 0xf8]));
653 t_uc51::get_bitidx(uchar bitaddr)
656 return((bitaddr/8)+32);
657 return(bitaddr & 0xf8);
662 * Processing write operation to IRAM
664 * It starts serial transmition if address is in SFR and it is
665 * SBUF. Effect on IE is also checked.
669 t_uc51::proc_write(uchar *addr)
671 if (addr == &((sfr->umem8)[SBUF]))
673 s_out= sfr->get(SBUF);
679 if (addr == &((sfr->umem8)[IE]))
684 t_uc51::proc_write_sp(uchar val)
688 sp_avg= (sp_avg+val)/2;
693 * Reading IRAM or SFR, but if address points to a port, it reads
694 * port pins instead of port latches
698 t_uc51::read(uchar *addr)
700 //if (addr == &(MEM(MEM_SFR)[P0]))
701 if (addr == &(sfr->umem8[P0]))
702 return(get_mem(MEM_SFR, P0) & port_pins[0]);
703 //if (addr == &(MEM(MEM_SFR)[P1]))
704 if (addr == &(sfr->umem8[P1]))
705 return(get_mem(MEM_SFR, P1) & port_pins[1]);
706 //if (addr == &(MEM(MEM_SFR)[P2]))
707 if (addr == &(sfr->umem8[P2]))
708 return(get_mem(MEM_SFR, P2) & port_pins[2]);
709 //if (addr == &(MEM(MEM_SFR)[P3]))
710 if (addr == &(sfr->umem8[P3]))
711 return(get_mem(MEM_SFR, P3) & port_pins[3]);
717 * Fetching one instruction and executing it
721 t_uc51::pre_inst(void)
723 event_at.wi= (t_addr)-1;
724 event_at.ri= (t_addr)-1;
725 event_at.wx= (t_addr)-1;
726 event_at.rx= (t_addr)-1;
727 event_at.ws= (t_addr)-1;
728 event_at.rs= (t_addr)-1;
729 event_at.rc= (t_addr)-1;
733 t_uc51::exec_inst(void)
740 return(resBREAKPOINT);
744 case 0x00: res= inst_nop(code); break;
745 case 0x01: case 0x21: case 0x41: case 0x61:
746 case 0x81: case 0xa1: case 0xc1: case 0xe1:res=inst_ajmp_addr(code);break;
747 case 0x02: res= inst_ljmp(code); break;
748 case 0x03: res= inst_rr(code); break;
749 case 0x04: res= inst_inc_a(code); break;
750 case 0x05: res= inst_inc_addr(code); break;
751 case 0x06: case 0x07: res= inst_inc_$ri(code); break;
752 case 0x08: case 0x09: case 0x0a: case 0x0b:
753 case 0x0c: case 0x0d: case 0x0e: case 0x0f: res= inst_inc_rn(code); break;
754 case 0x10: res= inst_jbc_bit_addr(code); break;
755 case 0x11: case 0x31: case 0x51: case 0x71:
756 case 0x91: case 0xb1: case 0xd1: case 0xf1:res=inst_acall_addr(code);break;
757 case 0x12: res= inst_lcall(code, 0); break;
758 case 0x13: res= inst_rrc(code); break;
759 case 0x14: res= inst_dec_a(code); break;
760 case 0x15: res= inst_dec_addr(code); break;
761 case 0x16: case 0x17: res= inst_dec_$ri(code); break;
762 case 0x18: case 0x19: case 0x1a: case 0x1b:
763 case 0x1c: case 0x1d: case 0x1e: case 0x1f: res= inst_dec_rn(code); break;
764 case 0x20: res= inst_jb_bit_addr(code); break;
765 case 0x22: res= inst_ret(code); break;
766 case 0x23: res= inst_rl(code); break;
767 case 0x24: res= inst_add_a_$data(code); break;
768 case 0x25: res= inst_add_a_addr(code); break;
769 case 0x26: case 0x27: res= inst_add_a_$ri(code); break;
770 case 0x28: case 0x29: case 0x2a: case 0x2b:
771 case 0x2c: case 0x2d: case 0x2e: case 0x2f:res= inst_add_a_rn(code);break;
772 case 0x30: res= inst_jnb_bit_addr(code); break;
773 case 0x32: res= inst_reti(code); break;
774 case 0x33: res= inst_rlc(code); break;
775 case 0x34: res= inst_addc_a_$data(code); break;
776 case 0x35: res= inst_addc_a_addr(code); break;
777 case 0x36: case 0x37: res= inst_addc_a_$ri(code); break;
778 case 0x38: case 0x39: case 0x3a: case 0x3b:
779 case 0x3c: case 0x3d: case 0x3e: case 0x3f:res= inst_addc_a_rn(code);break;
780 case 0x40: res= inst_jc_addr(code); break;
781 case 0x42: res= inst_orl_addr_a(code); break;
782 case 0x43: res= inst_orl_addr_$data(code); break;
783 case 0x44: res= inst_orl_a_$data(code); break;
784 case 0x45: res= inst_orl_a_addr(code); break;
785 case 0x46: case 0x47: res= inst_orl_a_$ri(code); break;
786 case 0x48: case 0x49: case 0x4a: case 0x4b:
787 case 0x4c: case 0x4d: case 0x4e: case 0x4f: res= inst_orl_a_rn(code);break;
788 case 0x50: res= inst_jnc_addr(code); break;
789 case 0x52: res= inst_anl_addr_a(code); break;
790 case 0x53: res= inst_anl_addr_$data(code); break;
791 case 0x54: res= inst_anl_a_$data(code); break;
792 case 0x55: res= inst_anl_a_addr(code); break;
793 case 0x56: case 0x57: res= inst_anl_a_$ri(code); break;
794 case 0x58: case 0x59: case 0x5a: case 0x5b:
795 case 0x5c: case 0x5d: case 0x5e: case 0x5f: res= inst_anl_a_rn(code);break;
796 case 0x60: res= inst_jz_addr(code); break;
797 case 0x62: res= inst_xrl_addr_a(code); break;
798 case 0x63: res= inst_xrl_addr_$data(code); break;
799 case 0x64: res= inst_xrl_a_$data(code); break;
800 case 0x65: res= inst_xrl_a_addr(code); break;
801 case 0x66: case 0x67: res= inst_xrl_a_$ri(code); break;
802 case 0x68: case 0x69: case 0x6a: case 0x6b:
803 case 0x6c: case 0x6d: case 0x6e: case 0x6f: res= inst_xrl_a_rn(code);break;
804 case 0x70: res= inst_jnz_addr(code); break;
805 case 0x72: res= inst_orl_c_bit(code); break;
806 case 0x73: res= inst_jmp_$a_dptr(code); break;
807 case 0x74: res= inst_mov_a_$data(code); break;
808 case 0x75: res= inst_mov_addr_$data(code); break;
809 case 0x76: case 0x77: res= inst_mov_$ri_$data(code); break;
810 case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c:
811 case 0x7d: case 0x7e: case 0x7f: res=inst_mov_rn_$data(code); break;
812 case 0x80: res= inst_sjmp(code); break;
813 case 0x82: res= inst_anl_c_bit(code); break;
814 case 0x83: res= inst_movc_a_$a_pc(code); break;
815 case 0x84: res= inst_div_ab(code); break;
816 case 0x85: res= inst_mov_addr_addr(code); break;
817 case 0x86: case 0x87: res= inst_mov_addr_$ri(code); break;
818 case 0x88: case 0x89: case 0x8a: case 0x8b:
819 case 0x8c: case 0x8d: case 0x8e: case 0x8f:res=inst_mov_addr_rn(code);break;
820 case 0x90: res= inst_mov_dptr_$data(code); break;
821 case 0x92: res= inst_mov_bit_c(code); break;
822 case 0x93: res= inst_movc_a_$a_dptr(code); break;
823 case 0x94: res= inst_subb_a_$data(code); break;
824 case 0x95: res= inst_subb_a_addr(code); break;
825 case 0x96: case 0x97: res= inst_subb_a_$ri(code); break;
826 case 0x98: case 0x99: case 0x9a: case 0x9b:
827 case 0x9c: case 0x9d: case 0x9e: case 0x9f:res= inst_subb_a_rn(code);break;
828 case 0xa2: res= inst_mov_c_bit(code); break;
829 case 0xa3: res= inst_inc_dptr(code); break;
830 case 0xa4: res= inst_mul_ab(code); break;
831 case 0xa5: res= inst_unknown(code); break;
832 case 0xa6: case 0xa7: res= inst_mov_$ri_addr(code); break;
833 case 0xa8: case 0xa9: case 0xaa: case 0xab:
834 case 0xac: case 0xad: case 0xae: case 0xaf:res=inst_mov_rn_addr(code);break;
835 case 0xb0: res= inst_anl_c_$bit(code); break;
836 case 0xb2: res= inst_cpl_bit(code); break;
837 case 0xb3: res= inst_cpl_c(code); break;
838 case 0xb4: res= inst_cjne_a_$data_addr(code); break;
839 case 0xb5: res= inst_cjne_a_addr_addr(code); break;
840 case 0xb6: case 0xb7: res= inst_cjne_$ri_$data_addr(code); break;
841 case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc:
842 case 0xbd: case 0xbe: case 0xbf: res=inst_cjne_rn_$data_addr(code); break;
843 case 0xc0: res= inst_push(code); break;
844 case 0xc2: res= inst_clr_bit(code); break;
845 case 0xc3: res= inst_clr_c(code); break;
846 case 0xc4: res= inst_swap(code); break;
847 case 0xc5: res= inst_xch_a_addr(code); break;
848 case 0xc6: case 0xc7: res= inst_xch_a_$ri(code); break;
849 case 0xc8: case 0xc9: case 0xca: case 0xcb:
850 case 0xcc: case 0xcd: case 0xce: case 0xcf: res= inst_xch_a_rn(code);break;
851 case 0xd0: res= inst_pop(code); break;
852 case 0xd2: res= inst_setb_bit(code); break;
853 case 0xd3: res= inst_setb_c(code); break;
854 case 0xd4: res= inst_da_a(code); break;
855 case 0xd5: res= inst_djnz_addr_addr(code); break;
856 case 0xd6: case 0xd7: res= inst_xchd_a_$ri(code); break;
857 case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc:
858 case 0xdd: case 0xde: case 0xdf: res=inst_djnz_rn_addr(code); break;
859 case 0xe0: res= inst_movx_a_$dptr(code); break;
860 case 0xe2: case 0xe3: res= inst_movx_a_$ri(code); break;
861 case 0xe4: res= inst_clr_a(code); break;
862 case 0xe5: res= inst_mov_a_addr(code); break;
863 case 0xe6: case 0xe7: res= inst_mov_a_$ri(code); break;
864 case 0xe8: case 0xe9: case 0xea: case 0xeb:
865 case 0xec: case 0xed: case 0xee: case 0xef: res= inst_mov_a_rn(code);break;
866 case 0xf0: res= inst_movx_$dptr_a(code); break;
867 case 0xf2: case 0xf3: res= inst_movx_$ri_a(code); break;
868 case 0xf4: res= inst_cpl_a(code); break;
869 case 0xf5: res= inst_mov_addr_a(code); break;
870 case 0xf6: case 0xf7: res= inst_mov_$ri_a(code); break;
871 case 0xf8: case 0xf9: case 0xfa: case 0xfb:
872 case 0xfc: case 0xfd: case 0xfe: case 0xff: res= inst_mov_rn_a(code);break;
874 res= inst_unknown(code);
883 * Simulating execution of next instruction
885 * This is an endless loop if requested number of steps is negative.
886 * In this case execution is stopped if an instruction results other
887 * status than GO. Execution can be stopped if `cmd_in' is not NULL
888 * and there is input available on that file. It is usefull if the
889 * command console is on a terminal. If input is available then a
890 * complete line is read and dropped out because input is buffered
891 * (inp_avail will be TRUE if ENTER is pressed) and it can confuse
892 * command interepter.
896 t_uc51::do_inst(int step)
899 while ((result == resGO) &&
912 result= check_events();
916 // tick hw in idle state
923 if ((res= do_interrupt()) != resGO)
929 ((ticks->ticks % 100000) < 50))
931 if (sim->app->get_commander()->input_avail_on_frozen())
936 if (sim->app->get_commander()->input_avail())
939 if (((result == resINTERRUPT) &&
949 //FIXME: tick outsiders eg. watchdog
950 if (sim->app->get_commander()->input_avail_on_frozen())
952 //fprintf(stderr,"uc: inp avail in PD mode, user stop\n");
961 t_uc51::post_inst(void)
963 uint tcon= sfr->get(TCON);
964 uint p3= sfr->get(P3);
968 // Read of SBUF must be serial input data
969 sfr->set(SBUF, s_in);
971 // Setting up external interrupt request bits (IEx)
974 // IE0 edge triggered
975 if ((prev_p3 & bm_INT0) &&
976 !(p3 & port_pins[3] & bm_INT0))
977 // falling edge on INT0
979 sim->app->get_commander()->
980 debug("%g sec (%d clks): Falling edge detected on INT0 (P3.2)\n",
981 get_rtime(), ticks->ticks);
982 sfr->set_bit1(TCON, bmIE0);
987 // IE0 level triggered
988 if (p3 & port_pins[3] & bm_INT0)
989 sfr->set_bit0(TCON, bmIE0);
991 sfr->set_bit1(TCON, bmIE0);
995 // IE1 edge triggered
996 if ((prev_p3 & bm_INT1) &&
997 !(p3 & port_pins[3] & bm_INT1))
998 // falling edge on INT1
999 sfr->set_bit1(TCON, bmIE1);
1003 // IE1 level triggered
1004 if (p3 & port_pins[3] & bm_INT1)
1005 sfr->set_bit0(TCON, bmIE1);
1007 sfr->set_bit1(TCON, bmIE1);
1009 prev_p3= p3 & port_pins[3];
1010 prev_p1= p3 & port_pins[1];
1015 * Setting up parity flag
1019 t_uc51::set_p_flag(void)
1027 for (i= 0; i < 8; i++)
1033 SET_BIT(p, PSW, bmP);
1037 * Simulating hardware elements
1041 t_uc51::do_hardware(int cycles)
1045 if ((res= do_timers(cycles)) != resGO)
1047 if ((res= do_serial(cycles)) != resGO)
1049 return(do_wdt(cycles));
1058 t_uc51::serial_bit_cnt(int mode)
1060 int /*mode,*/ divby= 12;
1061 int *tr_src= 0, *rec_src= 0;
1063 //mode= sfr->get(SCON) >> 6;
1068 tr_src = &s_tr_tick;
1069 rec_src= &s_rec_tick;
1073 divby = (sfr->get(PCON)&bmSMOD)?16:32;
1078 divby = (sfr->get(PCON)&bmSMOD)?16:32;
1079 tr_src = &s_tr_tick;
1080 rec_src= &s_rec_tick;
1085 while (*tr_src >= divby)
1093 while (*rec_src >= divby)
1104 * Simulating serial line
1108 t_uc51::do_serial(int cycles)
1112 uint scon= sfr->get(SCON);
1128 serial_bit_cnt(mode);
1132 s_sending= DD_FALSE;
1133 sfr->set_bit1(SCON, bmTI);
1136 putc(s_out, serial_out);
1141 if ((scon & bmREN) &&
1145 fd_set set; static struct timeval timeout= {0,0};
1147 FD_SET(fileno(serial_in), &set);
1148 int i= select(fileno(serial_in)+1, &set, NULL, NULL, &timeout);
1150 FD_ISSET(fileno(serial_in), &set))
1152 s_receiving= DD_TRUE;
1154 s_rec_tick= s_rec_t1= 0;
1158 (s_rec_bit >= bits))
1160 if (::read(fileno(serial_in), &c, 1) == 1)
1163 sfr->set(SBUF, s_in);
1166 s_receiving= DD_FALSE;
1173 t_uc51::received(int c)
1175 sfr->set_bit1(SCON, bmRI);
1184 t_uc51::do_timers(int cycles)
1188 if ((res= do_timer0(cycles)) != resGO)
1190 return(do_timer1(cycles));
1195 * Simulating timer 0
1199 t_uc51::do_timer0(int cycles)
1201 uint tmod= sfr->get(TMOD);
1202 uint tcon= sfr->get(TCON);
1203 uint p3= sfr->get(P3);
1205 if (((tmod & bmGATE0) &&
1206 (p3 & port_pins[3] & bm_INT0)) ||
1209 if (!(tmod & bmC_T0) ||
1210 ((prev_p3 & bmT0) &&
1211 !(p3 & port_pins[3] & bmT0)))
1213 if (!(tmod & bmM00) &&
1220 // mod 0, TH= 8 bit t/c, TL= 5 bit precounter
1221 //(MEM(MEM_SFR)[TL0])++;
1223 if ((sfr->get(TL0) & 0x1f) == 0)
1225 //sfr->set_bit0(TL0, ~0x1f);
1227 if (!/*++(MEM(MEM_SFR)[TH0])*/sfr->add(TH0, 1))
1229 sfr->set_bit1(TCON, bmTF0);
1235 else if ((tmod & bmM00) &&
1242 // mod 1 TH+TL= 16 bit t/c
1243 if (!/*++(MEM(MEM_SFR)[TL0])*/sfr->add(TL0, 1))
1245 if (!/*++(MEM(MEM_SFR)[TH0])*/sfr->add(TH0, 1))
1247 sfr->set_bit1(TCON, bmTF0);
1253 else if (!(tmod & bmM00) &&
1260 // mod 2 TL= 8 bit t/c auto reload from TH
1261 if (!/*++(MEM(MEM_SFR)[TL0])*/sfr->add(TL0, 1))
1263 sfr->set(TL0, sfr->get(TH0));
1264 sfr->set_bit1(TCON, bmTF0);
1271 // mod 3 TL= 8 bit t/c
1272 // TH= 8 bit timer controlled with T1's bits
1273 if (!/*++(MEM(MEM_SFR)[TL0])*/sfr->add(TL0, 1))
1275 sfr->set_bit1(TCON, bmTF0);
1281 if ((tmod & bmM00) &&
1284 if (((tmod & bmGATE1) &&
1285 (p3 & port_pins[3] & bm_INT1)) ||
1288 if (!/*++(MEM(MEM_SFR)[TH0])*/sfr->add(TH0, 1))
1290 sfr->set_bit1(TCON, bmTF1);
1301 * Called every time when T0 overflows
1305 t_uc51::t0_overflow(void)
1312 * Simulating timer 1
1316 t_uc51::do_timer1(int cycles)
1318 uint tmod= sfr->get(TMOD);
1319 uint tcon= sfr->get(TCON);
1320 uint p3= sfr->get(P3);
1322 if (((tmod & bmGATE1) &&
1323 (p3 & port_pins[3] & bm_INT1)) ||
1326 if (!(tmod & bmC_T1) ||
1327 ((prev_p3 & bmT1) &&
1328 !(p3 & port_pins[3] & bmT1)))
1330 if (!(tmod & bmM01) &&
1337 // mod 0, TH= 8 bit t/c, TL= 5 bit precounter
1338 if (/*++(MEM(MEM_SFR)[TL1])*/(sfr->add(TL1, 1) & 0x1f) == 0)
1340 //sfr->set_bit0(TL1, ~0x1f);
1342 if (!/*++(MEM(MEM_SFR)[TH1])*/sfr->add(TH1, 1))
1344 sfr->set_bit1(TCON, bmTF1);
1351 else if ((tmod & bmM01) &&
1358 // mod 1 TH+TL= 16 bit t/c
1359 if (!/*++(MEM(MEM_SFR)[TL1])*/sfr->add(TL1, 1))
1360 if (!/*++(MEM(MEM_SFR)[TH1])*/sfr->add(TH1, 1))
1362 sfr->set_bit1(TCON, bmTF1);
1368 else if (!(tmod & bmM01) &&
1375 // mod 2 TL= 8 bit t/c auto reload from TH
1376 if (!/*++(MEM(MEM_SFR)[TL1])*/sfr->add(TL1, 1))
1378 sfr->set(TL1, sfr->get(TH1));
1379 sfr->set_bit1(TCON, bmTF1);
1395 * Abstract method to handle WDT
1399 t_uc51::do_wdt(int cycles)
1406 * Checking for interrupt requests and accept one if needed
1410 t_uc51::do_interrupt(void)
1419 if (!((ie= sfr->get(IE)) & bmEA))
1421 class it_level *il= (class it_level *)(it_levels->top()), *IL= 0;
1422 for (i= 0; i < it_sources->count; i++)
1424 class cl_it_src *is= (class cl_it_src *)(it_sources->at(i));
1425 if (is->is_active() &&
1426 (ie & is->ie_mask) &&
1427 (sfr->get(is->src_reg) & is->src_mask))
1429 int pr= it_priority(is->ie_mask);
1430 if (il->level >= 0 &&
1433 if (state == stIDLE)
1436 sfr->set_bit0(PCON, bmIDL);
1441 sfr->set_bit0(is->src_reg, is->src_mask);
1442 sim->app->get_commander()->
1443 debug("%g sec (%d clks): Accepting interrupt `%s' PC= 0x%06x\n",
1444 get_rtime(), ticks->ticks, is->name, PC);
1445 IL= new it_level(pr, is->addr, PC, is);
1446 return(accept_it(IL));
1453 t_uc51::it_priority(uchar ie_mask)
1455 if (sfr->get(IP) & ie_mask)
1462 * Accept an interrupt
1466 t_uc51::accept_it(class it_level *il)
1469 sfr->set_bit0(PCON, bmIDL);
1470 it_levels->push(il);
1472 int res= inst_lcall(0, il->addr);
1476 return(resINTERRUPT);
1481 * Checking if Idle or PowerDown mode should be activated
1485 t_uc51::idle_pd(void)
1487 uint pcon= sfr->get(PCON);
1489 if (technology != CPU_CMOS)
1493 if (state != stIDLE)
1494 sim->app->get_commander()->
1495 debug("%g sec (%d clks): CPU in Idle mode\n",
1496 get_rtime(), ticks->ticks);
1503 sim->app->get_commander()->
1504 debug("%g sec (%d clks): CPU in PowerDown mode\n",
1505 get_rtime(), ticks->ticks);
1513 * Checking if EVENT break happened
1517 t_uc51::check_events(void)
1520 class cl_ev_brk *eb;
1524 for (i= 0; i < ebrk->count; i++)
1526 eb= (class cl_ev_brk *)(ebrk->at(i));
1527 if (eb->match(&event_at))
1528 return(resBREAKPOINT);
1535 * Simulating an unknown instruction
1537 * Normally this function is called for unimplemented instructions, because
1538 * every instruction must be known!
1542 t_uc51::inst_unknown(uchar code)
1545 if (1)//debug)// && sim->cmd_out())
1546 sim->app->get_commander()->
1547 debug("Unknown instruction %02x at %06x\n", code, PC);
1557 t_uc51::inst_nop(uchar code)
1568 t_uc51::inst_clr_a(uchar code)
1572 sfr->write(ACC, &d);
1582 t_uc51::inst_swap(uchar code)
1586 temp= (sfr->read(ACC) >> 4) & 0x0f;
1587 sfr->set(ACC, (sfr->get(ACC) << 4) | temp);
1592 /* End of s51.src/uc51.cc */