fix printf is a macro in gcc 3
[fw/sdcc] / sim / ucsim / s51.src / uc51.cc
1 /*
2  * Simulator of microcontrollers (uc51.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 <ctype.h>
33 #include <termios.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #if FD_HEADER_OK
40 # include HEADER_FD
41 #endif
42 #include "i_string.h"
43
44 // sim
45 #include "optioncl.h"
46
47 // local
48 #include "uc51cl.h"
49 #include "glob.h"
50 #include "regs51.h"
51 #include "timer0cl.h"
52 #include "timer1cl.h"
53 #include "serialcl.h"
54 #include "portcl.h"
55 #include "interruptcl.h"
56
57
58 /*
59  * Making a new micro-controller and reset it
60  */
61
62 t_uc51::t_uc51(int Itype, int Itech, class cl_sim *asim):
63   cl_uc(asim)
64 {
65   int i;
66   struct termios tattr;
67   
68   type= Itype;
69   technology= Itech;
70
71   debug= asim->app->args->get_iarg('V', 0);
72   stop_at_it= DD_FALSE;
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."));
78
79   serial_in = (FILE*)asim->app->args->get_parg(0, "Ser_in");
80   serial_out= (FILE*)asim->app->args->get_parg(0, "Ser_out");
81   if (serial_in)
82     {
83       // making `serial' unbuffered
84       if (setvbuf(serial_in, NULL, _IONBF, 0))
85         perror("Unbuffer serial input channel");
86       // setting O_NONBLOCK
87       if ((i= fcntl(fileno(serial_in), F_GETFL, 0)) < 0)
88         perror("Get flags of serial input");
89       i|= O_NONBLOCK;
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)))
94         {
95           tcgetattr(fileno(serial_in), &saved_attributes_in);
96           tcgetattr(fileno(serial_in), &tattr);
97           tattr.c_lflag&= ~(ICANON|ECHO);
98           tattr.c_cc[VMIN] = 1;
99           tattr.c_cc[VTIME]= 0;
100           tcsetattr(fileno(serial_in), TCSAFLUSH, &tattr);
101         }
102       else
103         fprintf(stderr, "Warning: serial input interface connected to a "
104                 "non-terminal file.\n");
105     }
106   if (serial_out)
107     {
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");
114       i|= O_NONBLOCK;
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)))
119         {
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);
126         }
127       else
128         fprintf(stderr, "Warning: serial output interface connected to a "
129                 "non-terminal file.\n");
130     }
131
132   for (i= 0; i < 4; i++)
133     port_pins[i]= 0xff;
134   it_sources->add(new cl_it_src(bmEX0, TCON, bmIE0, 0x0003, true,
135                                 "external #0"));
136   it_sources->add(new cl_it_src(bmET0, TCON, bmTF0, 0x000b, true,
137                                 "timer #0"));
138   it_sources->add(new cl_it_src(bmEX1, TCON, bmIE1, 0x0013, true,
139                                 "external #1"));
140   it_sources->add(new cl_it_src(bmET1, TCON, bmTF1, 0x001b, true,
141                                 "timer #1"));
142   it_sources->add(new cl_it_src(bmES , SCON, bmTI , 0x0023, false,
143                                 "serial transmit"));
144   it_sources->add(new cl_it_src(bmES , SCON, bmRI , 0x0023, false,
145                                 "serial receive"));
146 }
147
148
149 /*
150  * Initializing. Virtual calls go here
151  * This method must be called first after object creation.
152  */
153
154 int
155 t_uc51::init(void)
156 {
157   cl_uc::init();
158   reset();
159   return(0);
160 }
161
162 static char id_string_51[100];
163
164 char *
165 t_uc51::id_string(void)
166 {
167   int i;
168
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);
174 }
175
176 void
177 t_uc51::mk_hw_elements(void)
178 {
179   class cl_hw *h;
180
181   hws->add(h= new cl_timer0(this));
182   h->init();
183   hws->add(h= new cl_timer1(this));
184   h->init();
185   hws->add(h= new cl_serial(this));
186   h->init();
187   hws->add(h= new cl_port(this, 0));
188   h->init();
189   hws->add(h= new cl_port(this, 1));
190   h->init();
191   hws->add(h= new cl_port(this, 2));
192   h->init();
193   hws->add(h= new cl_port(this, 3));
194   h->init();
195   hws->add(h= new cl_interrupt(this));
196   h->init();
197 }
198
199 class cl_mem *
200 t_uc51::mk_mem(enum mem_class type, char *class_name)
201 {
202   class cl_mem *m= cl_uc::mk_mem(type, class_name);
203   if (type == MEM_SFR)
204     sfr= m;
205   if (type == MEM_IRAM)
206     iram= m;
207   return(m);
208 }
209
210
211 /*
212  * Destroying the micro-controller object
213  */
214
215 t_uc51::~t_uc51(void)
216 {
217   if (serial_out)
218     {
219       if (isatty(fileno(serial_out)))
220         tcsetattr(fileno(serial_out), TCSANOW, &saved_attributes_out);
221       fclose(serial_out);
222     }
223   if (serial_in)
224     {
225       if (isatty(fileno(serial_in)))
226         tcsetattr(fileno(serial_in), TCSANOW, &saved_attributes_in);
227       fclose(serial_in);
228     }
229 }
230
231
232 /*
233  * Writing data to EROM
234  */
235
236 void
237 t_uc51::write_rom(t_addr addr, ulong data)
238 {
239   if (addr < EROM_SIZE)
240     set_mem(MEM_ROM, addr, data);
241 }
242
243
244 /*
245  * Disassembling an instruction
246  */
247
248 struct dis_entry *
249 t_uc51::dis_tbl(void)
250 {
251   return(disass_51);
252 }
253
254 struct name_entry *
255 t_uc51::sfr_tbl(void)
256 {
257   return(sfr_tab51);
258 }
259
260 struct name_entry *
261 t_uc51::bit_tbl(void)
262 {
263   return(bit_tab51);
264 }
265
266 char *
267 t_uc51::disass(t_addr addr, char *sep)
268 {
269   char work[256], temp[20], c[2];
270   char *buf, *p, *b, *t;
271   t_mem code= get_mem(MEM_ROM, addr);
272
273   p= work;
274   b= dis_tbl()[code].mnemonic;
275   while (*b)
276     {
277       if (*b == '%')
278         {
279           b++;
280           switch (*(b++))
281             {
282             case 'A': // absolute address
283               sprintf(temp, "%04lx",
284                       (addr&0xf800)|
285                       (((code>>5)&0x07)*256 +
286                        get_mem(MEM_ROM, addr+1)));
287               break;
288             case 'l': // long address
289               sprintf(temp, "%04lx",
290                       get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2));
291               break;
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));
295               break;
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));
300               break;
301             case 'b': // bitaddr at 2nd byte
302               if (get_name(get_mem(MEM_ROM, addr+1), bit_tbl(), temp))
303                 break;
304               if (get_name(get_bitidx(get_mem(MEM_ROM, addr+1)),
305                            sfr_tbl(), temp))
306                 {
307                   strcat(temp, ".");
308                   sprintf(c, "%1ld", get_mem(MEM_ROM, addr+1)&0x07);
309                   strcat(temp, c);
310                   break;
311                 }
312               sprintf(temp, "%02x.%ld",
313                       get_bitidx(get_mem(MEM_ROM, addr+1)),
314                       get_mem(MEM_ROM, addr+1)&0x07);
315               break;
316             case 'r': // rel8 address at 2nd byte
317               sprintf(temp, "%04lx",
318                       addr+2+(signed char)(get_mem(MEM_ROM, addr+1)));
319               break;
320             case 'R': // rel8 address at 3rd byte
321               sprintf(temp, "%04lx",
322                       addr+3+(signed char)(get_mem(MEM_ROM, addr+2)));
323               break;
324             case 'd': // data8 at 2nd byte
325               sprintf(temp, "%02lx", get_mem(MEM_ROM, addr+1));
326               break;
327             case 'D': // data8 at 3rd byte
328               sprintf(temp, "%02lx", get_mem(MEM_ROM, addr+2));
329               break;
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));
333               break;
334             default:
335               strcpy(temp, "?");
336               break;
337             }
338           t= temp;
339           while (*t)
340             *(p++)= *(t++);
341         }
342       else
343         *(p++)= *(b++);
344     }
345   *p= '\0';
346
347   p= strchr(work, ' ');
348   if (!p)
349     {
350       buf= strdup(work);
351       return(buf);
352     }
353   if (sep == NULL)
354     buf= (char *)malloc(6+strlen(p)+1);
355   else
356     buf= (char *)malloc((p-work)+strlen(sep)+strlen(p)+1);
357   for (p= work, b= buf; *p != ' '; p++, b++)
358     *b= *p;
359   p++;
360   *b= '\0';
361   if (sep == NULL)
362     {
363       while (strlen(buf) < 6)
364         strcat(buf, " ");
365     }
366   else
367     strcat(buf, sep);
368   strcat(buf, p);
369   return(buf);
370 }
371
372
373 void
374 t_uc51::print_regs(class cl_console *con)
375 {
376   t_addr start;
377   uchar data;
378
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:'.');
386
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)); 
390   eram2xram();
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:'.');
394
395   data= iram->get(iram->get(start+1));
396   con->dd_printf("%06x %02x %c", iram->get(start+1), data,
397                  isprint(data)?data:'.');
398   data= sfr->get(PSW);
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');
402
403   print_disass(PC, con);
404 }
405
406
407 bool
408 t_uc51::extract_bit_address(t_addr bit_address,
409                             class cl_mem **mem,
410                             t_addr *mem_addr,
411                             t_mem *bit_mask)
412 {
413   if (mem)
414     *mem= sfr;
415   if (bit_address > 0xff)
416     return(DD_FALSE);
417   if (bit_mask)
418     *bit_mask= 1 << (bit_address % 8);
419   if (mem_addr)
420     {
421       if (bit_address < 0x80)
422         *mem_addr= bit_address/8 + 0x20;
423       else
424         *mem_addr= bit_address & 0xf8;
425     }
426   return(DD_TRUE);
427 }
428
429
430 /*
431  * Resetting the micro-controller
432  */
433
434 void
435 t_uc51::reset(void)
436 {
437   cl_uc::reset();
438
439   clear_sfr();
440
441   result= resGO;
442
443   was_reti= DD_FALSE;
444
445   s_tr_t1    = 0;
446   s_rec_t1   = 0;
447   s_tr_tick  = 0;
448   s_rec_tick = 0;
449   s_in       = 0;
450   s_out      = 0;
451   s_sending  = DD_FALSE;
452   s_receiving= DD_FALSE;
453   s_rec_bit  = 0;
454   s_tr_bit   = 0;
455 }
456
457
458 /*
459  * Setting up SFR area to reset value
460  */
461
462 void
463 t_uc51::clear_sfr(void)
464 {
465   int i;
466   
467   for (i= 0; i < SFR_SIZE; i++)
468     sfr->set(i, 0);
469   sfr->set(P0, 0xff);
470   sfr->set(P1, 0xff);
471   sfr->set(P2, 0xff);
472   sfr->set(P3, 0xff);
473   sfr->set(SP, 7);
474   prev_p1= port_pins[1] & sfr->get(P1);
475   prev_p3= port_pins[3] & sfr->get(P3);
476 }
477
478
479 /*
480  * Analyzing code and settig up instruction map
481  */
482
483 void
484 t_uc51::analyze(t_addr addr)
485 {
486   uint code;
487   struct dis_entry *tabl;
488
489   code= get_mem(MEM_ROM, addr);
490   tabl= &(dis_tbl()[code]);
491   while (!inst_at(addr) &&
492          code != 0xa5 /* break point */)
493     {
494       set_inst_at(addr);
495       switch (tabl->branch)
496         {
497         case 'a': // acall
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);
502           break;
503         case 'A': // ajmp
504           addr= (addr & 0xf800)|
505             ((get_mem(MEM_ROM, addr+1) & 0x07)*256 + get_mem(MEM_ROM, addr+2));
506           break;
507         case 'l': // lcall
508           analyze(get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2));
509           analyze(addr+tabl->length);
510           break;
511         case 'L': // ljmp
512           addr= get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2);
513           break;
514         case 'r': // reljmp (2nd byte)
515           analyze((addr + (signed char)(get_mem(MEM_ROM, addr+1))) &
516                   (EROM_SIZE - 1));
517           analyze(addr+tabl->length);
518           break;
519         case 'R': // reljmp (3rd byte)
520           analyze((addr+
521                    (signed char)(get_mem(MEM_ROM, addr+2)))&(EROM_SIZE-1));
522           analyze(addr+tabl->length);
523           break;
524         case 's': // sjmp
525           {
526             signed char target;
527             target= get_mem(MEM_ROM, addr+1);
528             addr+= 2;
529             addr= (addr+target)&(EROM_SIZE-1);
530             break;
531           }
532         case '_':
533           return;
534         default:
535           addr= (addr+tabl->length) & (EROM_SIZE - 1);
536           break;
537         }
538       code= get_mem(MEM_ROM, addr);
539       tabl= &(dis_tbl()[code]);
540     }
541 }
542
543
544 /*
545  * Inform hardware elements that `cycles' machine cycles have elapsed
546  */
547
548 int
549 t_uc51::tick(int cycles)
550 {
551   int l;
552
553   cl_uc::tick(cycles);
554   do_hardware(cycles);
555   s_tr_tick+= (l= cycles * clock_per_cycle());
556   s_rec_tick+= l;
557   return(0);
558 }
559
560
561 /*
562  * Correcting direct address
563  *
564  * This function returns address of addressed element which can be an IRAM
565  * or an SFR.
566  */
567
568 uchar *
569 t_uc51::get_direct(t_mem addr, t_addr *ev_i, t_addr *ev_s)
570 {
571   if (addr < SFR_START)
572     {
573       return(&(iram->umem8[*ev_i= addr]));
574       //return(&(MEM(MEM_IRAM)[*ev_i= addr]));
575     }
576   else
577     {
578       return(&(sfr->umem8[*ev_s= addr]));
579       //return(&(MEM(MEM_SFR)[*ev_s= addr]));
580     }
581 }
582
583 /*
584  * Calculating address of indirectly addressed IRAM cell
585  * If CPU is 8051 and addr is over 127, it must be illegal!
586  */
587
588 uchar *
589 t_uc51::get_indirect(uchar addr, int *res)
590 {
591   if (addr >= SFR_START)
592     *res= resINV_ADDR;
593   else
594     *res= resGO;
595   return(&(iram->umem8[addr]));
596   //return(&(MEM(MEM_IRAM)[addr]));
597 }
598
599
600 /*
601  * Calculating address of specified register cell in IRAM
602  */
603
604 uchar *
605 t_uc51::get_reg(uchar regnum)
606 {
607   return(&(iram->umem8[(sfr->get(PSW) & (bmRS0|bmRS1)) |
608                       (regnum & 0x07)]));
609   //return(&(MEM(MEM_IRAM)[(sfr->get(PSW) & (bmRS0|bmRS1)) |
610   //            (regnum & 0x07)]));
611 }
612
613 uchar *
614 t_uc51::get_reg(uchar regnum, t_addr *event)
615 {
616   return(&(iram->umem8[*event= (sfr->get(PSW) & (bmRS0|bmRS1)) |
617                       (regnum & 0x07)]));
618   //return(&(MEM(MEM_IRAM)[*event= (sfr->get(PSW) & (bmRS0|bmRS1)) |
619   //            (regnum & 0x07)]));
620 }
621
622
623 /*
624  * Calculating address of IRAM or SFR cell which contains addressed bit
625  * Next function returns index of cell which contains addressed bit.
626  */
627
628 uchar *
629 t_uc51::get_bit(uchar bitaddr)
630 {
631   if (bitaddr < 128)
632     {
633       return(&(iram->umem8[(bitaddr/8)+32]));
634       //return(&(MEM(MEM_IRAM)[(bitaddr/8)+32]));
635     }
636   return(&(iram->umem8[bitaddr & 0xf8]));
637   //return(&(MEM(MEM_SFR)[bitaddr & 0xf8]));
638 }
639
640 uchar *
641 t_uc51::get_bit(uchar bitaddr, t_addr *ev_i, t_addr *ev_s)
642 {
643   if (bitaddr < 128)
644     {
645       return(&(iram->umem8[*ev_i= (bitaddr/8)+32]));
646       //return(&(MEM(MEM_IRAM)[*ev_i= (bitaddr/8)+32]));
647     }
648   return(&(sfr->umem8[*ev_s= bitaddr & 0xf8]));
649   //return(&(MEM(MEM_SFR)[*ev_s= bitaddr & 0xf8]));
650 }
651
652 uchar
653 t_uc51::get_bitidx(uchar bitaddr)
654 {
655   if (bitaddr < 128)
656     return((bitaddr/8)+32);
657   return(bitaddr & 0xf8);
658 }
659
660
661 /*
662  * Processing write operation to IRAM
663  *
664  * It starts serial transmition if address is in SFR and it is
665  * SBUF. Effect on IE is also checked.
666  */
667
668 void
669 t_uc51::proc_write(uchar *addr)
670 {
671   if (addr == &((sfr->umem8)[SBUF]))
672     {
673       s_out= sfr->get(SBUF);
674       s_sending= DD_TRUE;
675       s_tr_bit = 0;
676       s_tr_tick= 0;
677       s_tr_t1  = 0;
678     }
679   if (addr == &((sfr->umem8)[IE]))
680     was_reti= DD_TRUE;
681 }
682
683 void
684 t_uc51::proc_write_sp(uchar val)
685 {
686   if (val > sp_max)
687     sp_max= val;
688   sp_avg= (sp_avg+val)/2;
689 }
690
691
692 /*
693  * Reading IRAM or SFR, but if address points to a port, it reads
694  * port pins instead of port latches
695  */
696
697 uchar
698 t_uc51::read(uchar *addr)
699 {
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]);
712   return(*addr);
713 }
714
715
716 /*
717  * Fetching one instruction and executing it
718  */
719
720 void
721 t_uc51::pre_inst(void)
722 {
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;
730 }
731
732 int
733 t_uc51::exec_inst(void)
734 {
735   ulong code;
736   int res;
737
738   //pr_inst();
739   if (fetch(&code))
740     return(resBREAKPOINT);
741   tick(1);
742   switch (code)
743     {
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;
873     default:
874       res= inst_unknown(code);
875       break;
876     }
877   //post_inst();
878   return(res);
879 }
880
881
882 /*
883  * Simulating execution of next instruction
884  *
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.
893  */
894
895 int
896 t_uc51::do_inst(int step)
897 {
898   result= resGO;
899   while ((result == resGO) &&
900          (state != stPD) &&
901          (step != 0))
902     {
903       if (step > 0)
904         step--;
905       if (state == stGO)
906         {
907           was_reti= DD_FALSE;
908           pre_inst();
909           result= exec_inst();
910           post_inst();
911           if (result == resGO)
912             result= check_events();
913         }
914       else
915         {
916           // tick hw in idle state
917           post_inst();
918           tick(1);
919         }
920       if (result == resGO)
921         {
922           int res;
923           if ((res= do_interrupt()) != resGO)
924             result= res;
925           else
926             result= idle_pd();
927         }
928       if ((step < 0) &&
929           ((ticks->ticks % 100000) < 50))
930         {
931           if (sim->app->get_commander()->input_avail_on_frozen())
932             {
933               result= resUSER;
934             }
935           else
936             if (sim->app->get_commander()->input_avail())
937               break;
938         }
939       if (((result == resINTERRUPT) &&
940            stop_at_it) ||
941           result >= resSTOP)
942         {
943           sim->stop(result);
944           break;
945         }
946     }
947   if (state == stPD)
948     {
949       //FIXME: tick outsiders eg. watchdog
950       if (sim->app->get_commander()->input_avail_on_frozen())
951         {
952           //fprintf(stderr,"uc: inp avail in PD mode, user stop\n");
953           result= resUSER;
954           sim->stop(result); 
955         }
956     }
957   return(result);
958 }
959
960 void
961 t_uc51::post_inst(void)
962 {
963   uint tcon= sfr->get(TCON);
964   uint p3= sfr->get(P3);
965
966   set_p_flag();
967
968   // Read of SBUF must be serial input data
969   sfr->set(SBUF, s_in);
970
971   // Setting up external interrupt request bits (IEx)
972   if ((tcon & bmIT0))
973     {
974       // IE0 edge triggered
975       if ((prev_p3 & bm_INT0) &&
976           !(p3 & port_pins[3] & bm_INT0))
977         // falling edge on INT0
978         {
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);
983         }
984     }
985   else
986     {
987       // IE0 level triggered
988       if (p3 & port_pins[3] & bm_INT0)
989         sfr->set_bit0(TCON, bmIE0);
990       else
991         sfr->set_bit1(TCON, bmIE0);
992     }
993   if ((tcon & bmIT1))
994     {
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);
1000     }
1001   else
1002     {
1003       // IE1 level triggered
1004       if (p3 & port_pins[3] & bm_INT1)
1005         sfr->set_bit0(TCON, bmIE1);
1006       else
1007         sfr->set_bit1(TCON, bmIE1);
1008     }
1009   prev_p3= p3 & port_pins[3];
1010   prev_p1= p3 & port_pins[1];
1011 }
1012
1013
1014 /*
1015  * Setting up parity flag
1016  */
1017
1018 void
1019 t_uc51::set_p_flag(void)
1020 {
1021   bool p;
1022   int i;
1023   uchar uc;
1024
1025   p = DD_FALSE;
1026   uc= sfr->get(ACC);
1027   for (i= 0; i < 8; i++)
1028     {
1029       if (uc & 1)
1030         p= !p;
1031       uc>>= 1;
1032     }
1033   SET_BIT(p, PSW, bmP);
1034 }
1035
1036 /*
1037  * Simulating hardware elements
1038  */
1039
1040 int
1041 t_uc51::do_hardware(int cycles)
1042 {
1043   int res;
1044
1045   if ((res= do_timers(cycles)) != resGO)
1046     return(res);
1047   if ((res= do_serial(cycles)) != resGO)
1048     return(res);
1049   return(do_wdt(cycles));
1050 }
1051
1052
1053 /*
1054  *
1055  */
1056
1057 int
1058 t_uc51::serial_bit_cnt(int mode)
1059 {
1060   int /*mode,*/ divby= 12;
1061   int *tr_src= 0, *rec_src= 0;
1062
1063   //mode= sfr->get(SCON) >> 6;
1064   switch (mode)
1065     {
1066     case 0:
1067       divby  = 12;
1068       tr_src = &s_tr_tick;
1069       rec_src= &s_rec_tick;
1070       break;
1071     case 1:
1072     case 3:
1073       divby  = (sfr->get(PCON)&bmSMOD)?16:32;
1074       tr_src = &s_tr_t1;
1075       rec_src= &s_rec_t1;
1076       break;
1077     case 2:
1078       divby  = (sfr->get(PCON)&bmSMOD)?16:32;
1079       tr_src = &s_tr_tick;
1080       rec_src= &s_rec_tick;
1081       break;
1082     }
1083   if (s_sending)
1084     {
1085       while (*tr_src >= divby)
1086         {
1087           (*tr_src)-= divby;
1088           s_tr_bit++;
1089         }
1090     }
1091   if (s_receiving)
1092     {
1093       while (*rec_src >= divby)
1094         {
1095           (*rec_src)-= divby;
1096           s_rec_bit++;
1097         }
1098     }
1099   return(0);
1100 }
1101
1102
1103 /*
1104  * Simulating serial line
1105  */
1106
1107 int
1108 t_uc51::do_serial(int cycles)
1109 {
1110   int mode, bits= 8;
1111   char c;
1112   uint scon= sfr->get(SCON);
1113
1114   mode= scon >> 6;
1115   switch (mode)
1116     {
1117     case 0:
1118       bits= 8;
1119       break;
1120     case 1:
1121       bits= 10;
1122       break;
1123     case 2:
1124     case 3:
1125       bits= 11;
1126       break;
1127     }
1128   serial_bit_cnt(mode);
1129   if (s_sending &&
1130       (s_tr_bit >= bits))
1131     {
1132       s_sending= DD_FALSE;
1133       sfr->set_bit1(SCON, bmTI);
1134       if (serial_out)
1135         {
1136           putc(s_out, serial_out);
1137           fflush(serial_out);
1138         }
1139       s_tr_bit-= bits;
1140     }
1141   if ((scon & bmREN) &&
1142       serial_in &&
1143       !s_receiving)
1144     {
1145       fd_set set; static struct timeval timeout= {0,0};
1146       FD_ZERO(&set);
1147       FD_SET(fileno(serial_in), &set);
1148       int i= select(fileno(serial_in)+1, &set, NULL, NULL, &timeout);
1149       if (i > 0 &&
1150           FD_ISSET(fileno(serial_in), &set))
1151         {
1152           s_receiving= DD_TRUE;
1153           s_rec_bit= 0;
1154           s_rec_tick= s_rec_t1= 0;
1155         }
1156     }
1157   if (s_receiving &&
1158       (s_rec_bit >= bits))
1159     {
1160       if (::read(fileno(serial_in), &c, 1) == 1)
1161         {
1162           s_in= c;
1163           sfr->set(SBUF, s_in);
1164           received(c);
1165         }
1166       s_receiving= DD_FALSE;
1167       s_rec_bit-= bits;
1168     }
1169   return(resGO);
1170 }
1171
1172 void
1173 t_uc51::received(int c)
1174 {
1175   sfr->set_bit1(SCON, bmRI);
1176 }
1177
1178
1179 /*
1180  * Simulating timers
1181  */
1182
1183 int
1184 t_uc51::do_timers(int cycles)
1185 {
1186   int res;
1187
1188   if ((res= do_timer0(cycles)) != resGO)
1189     return(res);
1190   return(do_timer1(cycles));
1191 }
1192
1193
1194 /*
1195  * Simulating timer 0
1196  */
1197
1198 int
1199 t_uc51::do_timer0(int cycles)
1200 {
1201   uint tmod= sfr->get(TMOD);
1202   uint tcon= sfr->get(TCON);
1203   uint p3= sfr->get(P3);
1204
1205   if (((tmod & bmGATE0) &&
1206        (p3 & port_pins[3] & bm_INT0)) ||
1207       (tcon & bmTR0))
1208     {
1209       if (!(tmod & bmC_T0) ||
1210           ((prev_p3 & bmT0) &&
1211            !(p3 & port_pins[3] & bmT0)))
1212         {
1213           if (!(tmod & bmM00) &&
1214               !(tmod & bmM10))
1215             {
1216               if (tmod & bmC_T0)
1217                 cycles= 1;
1218               while (cycles--)
1219                 {
1220                   // mod 0, TH= 8 bit t/c, TL= 5 bit precounter
1221                   //(MEM(MEM_SFR)[TL0])++;
1222                   sfr->add(TL0, 1);
1223                   if ((sfr->get(TL0) & 0x1f) == 0)
1224                     {
1225                       //sfr->set_bit0(TL0, ~0x1f);
1226                       sfr->set(TL0, 0);
1227                       if (!/*++(MEM(MEM_SFR)[TH0])*/sfr->add(TH0, 1))
1228                         {
1229                           sfr->set_bit1(TCON, bmTF0);
1230                           t0_overflow();
1231                         }
1232                     }
1233                 }
1234             }
1235           else if ((tmod & bmM00) &&
1236                    !(tmod & bmM10))
1237             {
1238               if (tmod & bmC_T0)
1239                 cycles= 1;
1240               while (cycles--)
1241                 {
1242                   // mod 1 TH+TL= 16 bit t/c
1243                   if (!/*++(MEM(MEM_SFR)[TL0])*/sfr->add(TL0, 1))
1244                     {
1245                       if (!/*++(MEM(MEM_SFR)[TH0])*/sfr->add(TH0, 1))
1246                         {
1247                           sfr->set_bit1(TCON, bmTF0);
1248                           t0_overflow();
1249                         }
1250                     }
1251                 }
1252             }
1253           else if (!(tmod & bmM00) &&
1254                    (tmod & bmM10))
1255             {
1256               if (tmod & bmC_T0)
1257                 cycles= 1;
1258               while (cycles--)
1259                 {
1260                   // mod 2 TL= 8 bit t/c auto reload from TH
1261                   if (!/*++(MEM(MEM_SFR)[TL0])*/sfr->add(TL0, 1))
1262                     {
1263                       sfr->set(TL0, sfr->get(TH0));
1264                       sfr->set_bit1(TCON, bmTF0);
1265                       t0_overflow();
1266                     }
1267                 }
1268             }
1269           else
1270             {
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))
1274                 {
1275                   sfr->set_bit1(TCON, bmTF0);
1276                   t0_overflow();
1277                 }
1278             }
1279         }
1280     }
1281   if ((tmod & bmM00) &&
1282       (tmod & bmM10))
1283     {
1284       if (((tmod & bmGATE1) &&
1285            (p3 & port_pins[3] & bm_INT1)) ||
1286           (tcon & bmTR1))
1287         {
1288           if (!/*++(MEM(MEM_SFR)[TH0])*/sfr->add(TH0, 1))
1289             {
1290               sfr->set_bit1(TCON, bmTF1);
1291               s_tr_t1++;
1292               s_rec_t1++;
1293               t0_overflow();
1294             }
1295         }
1296     }
1297   return(resGO);
1298 }
1299
1300 /*
1301  * Called every time when T0 overflows
1302  */
1303
1304 int
1305 t_uc51::t0_overflow(void)
1306 {
1307   return(0);
1308 }
1309
1310
1311 /*
1312  * Simulating timer 1
1313  */
1314
1315 int
1316 t_uc51::do_timer1(int cycles)
1317 {
1318   uint tmod= sfr->get(TMOD);
1319   uint tcon= sfr->get(TCON);
1320   uint p3= sfr->get(P3);
1321
1322   if (((tmod & bmGATE1) &&
1323        (p3 & port_pins[3] & bm_INT1)) ||
1324       (tcon & bmTR1))
1325     {
1326       if (!(tmod & bmC_T1) ||
1327           ((prev_p3 & bmT1) &&
1328            !(p3 & port_pins[3] & bmT1)))
1329         {
1330           if (!(tmod & bmM01) &&
1331               !(tmod & bmM11))
1332             {
1333               if (tmod & bmC_T0)
1334                 cycles= 1;
1335               while (cycles--)
1336                 {
1337                   // mod 0, TH= 8 bit t/c, TL= 5 bit precounter
1338                   if (/*++(MEM(MEM_SFR)[TL1])*/(sfr->add(TL1, 1) & 0x1f) == 0)
1339                     {
1340                       //sfr->set_bit0(TL1, ~0x1f);
1341                       sfr->set(TL1, 0);
1342                       if (!/*++(MEM(MEM_SFR)[TH1])*/sfr->add(TH1, 1))
1343                         {
1344                           sfr->set_bit1(TCON, bmTF1);
1345                           s_tr_t1++;
1346                           s_rec_t1++;
1347                         }
1348                     }
1349                 }
1350             }
1351           else if ((tmod & bmM01) &&
1352                    !(tmod & bmM11))
1353             {
1354               if (tmod & bmC_T0)
1355                 cycles= 1;
1356               while (cycles--)
1357                 {
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))
1361                       {
1362                         sfr->set_bit1(TCON, bmTF1);
1363                         s_tr_t1++;
1364                         s_rec_t1++;
1365                       }
1366                 }
1367             }
1368           else if (!(tmod & bmM01) &&
1369                    (tmod & bmM11))
1370             {
1371               if (tmod & bmC_T1)
1372                 cycles= 1;
1373               while (cycles--)
1374                 {
1375                   // mod 2 TL= 8 bit t/c auto reload from TH
1376                   if (!/*++(MEM(MEM_SFR)[TL1])*/sfr->add(TL1, 1))
1377                     {
1378                       sfr->set(TL1, sfr->get(TH1));
1379                       sfr->set_bit1(TCON, bmTF1);
1380                       s_tr_t1++;
1381                       s_rec_t1++;
1382                     }
1383                 }
1384             }
1385           else
1386             // mod 3 stop
1387             ;
1388         }
1389     }
1390   return(resGO);
1391 }
1392
1393
1394 /*
1395  * Abstract method to handle WDT
1396  */
1397
1398 int
1399 t_uc51::do_wdt(int cycles)
1400 {
1401   return(resGO);
1402 }
1403
1404
1405 /*
1406  * Checking for interrupt requests and accept one if needed
1407  */
1408
1409 int
1410 t_uc51::do_interrupt(void)
1411 {
1412   int i, ie= 0;
1413
1414   if (was_reti)
1415     {
1416       was_reti= DD_FALSE;
1417       return(resGO);
1418     }
1419   if (!((ie= sfr->get(IE)) & bmEA))
1420     return(resGO);
1421   class it_level *il= (class it_level *)(it_levels->top()), *IL= 0;
1422   for (i= 0; i < it_sources->count; i++)
1423     {
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))
1428         {
1429           int pr= it_priority(is->ie_mask);
1430           if (il->level >= 0 &&
1431               pr <= il->level)
1432             continue;
1433           if (state == stIDLE)
1434             {
1435               state= stGO;
1436               sfr->set_bit0(PCON, bmIDL);
1437               was_reti= 1;
1438               return(resGO);
1439             }
1440           if (is->clr_bit)
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));
1447         }
1448     }
1449   return(resGO);
1450 }
1451
1452 int
1453 t_uc51::it_priority(uchar ie_mask)
1454 {
1455   if (sfr->get(IP) & ie_mask)
1456     return(1);
1457   return(0);
1458 }
1459
1460
1461 /*
1462  * Accept an interrupt
1463  */
1464
1465 int
1466 t_uc51::accept_it(class it_level *il)
1467 {
1468   state= stGO;
1469   sfr->set_bit0(PCON, bmIDL);
1470   it_levels->push(il);
1471   tick(1);
1472   int res= inst_lcall(0, il->addr);
1473   if (res != resGO)
1474     return(res);
1475   else
1476     return(resINTERRUPT);
1477 }
1478
1479
1480 /*
1481  * Checking if Idle or PowerDown mode should be activated
1482  */
1483
1484 int
1485 t_uc51::idle_pd(void)
1486 {
1487   uint pcon= sfr->get(PCON);
1488
1489   if (technology != CPU_CMOS)
1490     return(resGO);
1491   if (pcon & bmIDL)
1492     {
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);
1497       state= stIDLE;
1498       //was_reti= 1;
1499     }
1500   if (pcon & bmPD)
1501     {
1502       if (state != stPD)
1503         sim->app->get_commander()->
1504           debug("%g sec (%d clks): CPU in PowerDown mode\n",
1505                         get_rtime(), ticks->ticks);
1506       state= stPD;
1507     }
1508   return(resGO);
1509 }
1510
1511
1512 /*
1513  * Checking if EVENT break happened
1514  */
1515
1516 int
1517 t_uc51::check_events(void)
1518 {
1519   int i;
1520   class cl_ev_brk *eb;
1521
1522   if (!ebrk->count)
1523     return(resGO);
1524   for (i= 0; i < ebrk->count; i++)
1525     {
1526       eb= (class cl_ev_brk *)(ebrk->at(i));
1527       if (eb->match(&event_at))
1528         return(resBREAKPOINT);
1529     }
1530   return(resGO);
1531 }
1532
1533
1534 /*
1535  * Simulating an unknown instruction
1536  *
1537  * Normally this function is called for unimplemented instructions, because
1538  * every instruction must be known!
1539  */
1540
1541 int
1542 t_uc51::inst_unknown(uchar code)
1543 {
1544   PC--;
1545   if (1)//debug)// && sim->cmd_out())
1546     sim->app->get_commander()->
1547       debug("Unknown instruction %02x at %06x\n", code, PC);
1548   return(resHALT);
1549 }
1550
1551
1552 /*
1553  * 0x00 1 12 NOP
1554  */
1555
1556 int
1557 t_uc51::inst_nop(uchar code)
1558 {
1559   return(resGO);
1560 }
1561
1562
1563 /*
1564  * 0xe4 1 12 CLR A
1565  */
1566
1567 int
1568 t_uc51::inst_clr_a(uchar code)
1569 {
1570   ulong d= 0;
1571
1572   sfr->write(ACC, &d);
1573   return(resGO);
1574 }
1575
1576
1577 /*
1578  * 0xc4 1 1 SWAP A
1579  */
1580
1581 int
1582 t_uc51::inst_swap(uchar code)
1583 {
1584   uchar temp;
1585
1586   temp= (sfr->read(ACC) >> 4) & 0x0f;
1587   sfr->set(ACC, (sfr->get(ACC) << 4) | temp);
1588   return(resGO);
1589 }
1590
1591
1592 /* End of s51.src/uc51.cc */