d6c2c00bd09b92cf2063aa9f8b911146c6464559
[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 // prj
45 #include "utils.h"
46
47 // sim
48 #include "optioncl.h"
49
50 // local
51 #include "uc51cl.h"
52 #include "glob.h"
53 #include "regs51.h"
54 #include "timer0cl.h"
55 #include "timer1cl.h"
56 #include "serialcl.h"
57 #include "portcl.h"
58 #include "interruptcl.h"
59 #include "types51.h"
60
61
62 /*
63  * Making a new micro-controller and reset it
64  */
65
66 t_uc51::t_uc51(int Itype, int Itech, class cl_sim *asim):
67   cl_uc(asim)
68 {
69   //int i;
70   /*
71   struct termios tattr;
72   */  
73   type= Itype;
74   technology= Itech;
75
76   debug= asim->app->args->get_iarg('V', 0);
77   stop_at_it= DD_FALSE;
78   /*class cl_option *opt;
79   options->add(opt= new cl_bool_opt("verbose", "Verbose flag."));
80   opt->init();
81   opt->set_value((bool)debug);
82   options->add(opt= new cl_bool_opt("stopit", "Stop if interrupt accepted."));
83   opt->init();
84   opt->set_value((bool)stop_at_it);
85   options->add(new cl_cons_debug_opt(asim->app, "debug",
86   "Debug messages appears on this console."));*/
87
88   /*
89   serial_in = (FILE*)asim->app->args->get_parg(0, "Ser_in");
90   serial_out= (FILE*)asim->app->args->get_parg(0, "Ser_out");
91   if (serial_in)
92     {
93       // making `serial' unbuffered
94       if (setvbuf(serial_in, NULL, _IONBF, 0))
95         perror("Unbuffer serial input channel");
96       // setting O_NONBLOCK
97       if ((i= fcntl(fileno(serial_in), F_GETFL, 0)) < 0)
98         perror("Get flags of serial input");
99       i|= O_NONBLOCK;
100       if (fcntl(fileno(serial_in), F_SETFL, i) < 0)
101         perror("Set flags of serial input");
102       // switching terminal to noncanonical mode
103       if (isatty(fileno(serial_in)))
104         {
105           tcgetattr(fileno(serial_in), &saved_attributes_in);
106           tcgetattr(fileno(serial_in), &tattr);
107           tattr.c_lflag&= ~(ICANON|ECHO);
108           tattr.c_cc[VMIN] = 1;
109           tattr.c_cc[VTIME]= 0;
110           tcsetattr(fileno(serial_in), TCSAFLUSH, &tattr);
111         }
112       else
113         fprintf(stderr, "Warning: serial input interface connected to a "
114                 "non-terminal file.\n");
115     }
116   if (serial_out)
117     {
118       // making `serial' unbuffered
119       if (setvbuf(serial_out, NULL, _IONBF, 0))
120         perror("Unbuffer serial output channel");
121       // setting O_NONBLOCK
122       if ((i= fcntl(fileno(serial_out), F_GETFL, 0)) < 0)
123         perror("Get flags of serial output");
124       i|= O_NONBLOCK;
125       if (fcntl(fileno(serial_out), F_SETFL, i) < 0)
126         perror("Set flags of serial output");
127       // switching terminal to noncanonical mode
128       if (isatty(fileno(serial_out)))
129         {
130           tcgetattr(fileno(serial_out), &saved_attributes_out);
131           tcgetattr(fileno(serial_out), &tattr);
132           tattr.c_lflag&= ~(ICANON|ECHO);
133           tattr.c_cc[VMIN] = 1;
134           tattr.c_cc[VTIME]= 0;
135           tcsetattr(fileno(serial_out), TCSAFLUSH, &tattr);
136         }
137       else
138         fprintf(stderr, "Warning: serial output interface connected to a "
139                 "non-terminal file.\n");
140     }
141   */
142
143   /*for (i= 0; i < 4; i++)
144     port_pins[i]= 0xff;*/
145   /*it_sources->add(new cl_it_src(bmEX0, TCON, bmIE0, 0x0003, true,
146     "external #0"));*/
147   /*it_sources->add(new cl_it_src(bmET0, TCON, bmTF0, 0x000b, true,
148     "timer #0"));*/
149   /*it_sources->add(new cl_it_src(bmEX1, TCON, bmIE1, 0x0013, true,
150     "external #1"));*/
151   /*it_sources->add(new cl_it_src(bmET1, TCON, bmTF1, 0x001b, true,
152     "timer #1"));*/
153   /*it_sources->add(new cl_it_src(bmES , SCON, bmTI , 0x0023, false,
154                                 "serial transmit"));
155   it_sources->add(new cl_it_src(bmES , SCON, bmRI , 0x0023, false,
156   "serial receive"));*/
157 }
158
159
160 /*
161  * Initializing. Virtual calls go here
162  * This method must be called first after object creation.
163  */
164
165 int
166 t_uc51::init(void)
167 {
168   cl_uc::init();
169   reset();
170   return(0);
171 }
172
173 static char id_string_51[100];
174
175 char *
176 t_uc51::id_string(void)
177 {
178   int i;
179
180   for (i= 0; cpus_51[i].type_str != NULL && cpus_51[i].type != type; i++) ;
181   sprintf(id_string_51, "%s %s",
182           cpus_51[i].type_str?cpus_51[i].type_str:"51",
183           (technology==CPU_HMOS)?"HMOS":"CMOS");
184   return(id_string_51);
185 }
186
187 void
188 t_uc51::mk_hw_elements(void)
189 {
190   class cl_hw *h;
191
192   acc= sfr->get_cell(ACC);
193   psw= sfr->get_cell(PSW);
194
195   hws->add(h= new cl_timer0(this, 0, "timer0"));
196   h->init();
197   hws->add(h= new cl_timer1(this, 1, "timer1"));
198   h->init();
199   hws->add(h= new cl_serial(this));
200   h->init();
201   hws->add(h= new cl_port(this, 0));
202   h->init();
203   hws->add(h= new cl_port(this, 1));
204   h->init();
205   hws->add(h= new cl_port(this, 2));
206   h->init();
207   hws->add(h= new cl_port(this, 3));
208   h->init();
209   hws->add(interrupt= new cl_interrupt(this));
210   interrupt->init();
211   hws->add(h= new cl_uc51_dummy_hw(this));
212   h->init();
213   /*
214   acc= sfr->get_cell(ACC);
215   psw= sfr->get_cell(PSW);
216   */
217 }
218
219 class cl_mem *
220 t_uc51::mk_mem(enum mem_class type, char *class_name)
221 {
222   class cl_mem *m= cl_uc::mk_mem(type, class_name);
223   if (type == MEM_SFR)
224     sfr= m;
225   if (type == MEM_IRAM)
226     iram= m;
227   return(m);
228 }
229
230
231 /*
232  * Destroying the micro-controller object
233  */
234
235 t_uc51::~t_uc51(void)
236 {
237   /*
238   if (serial_out)
239     {
240       if (isatty(fileno(serial_out)))
241         tcsetattr(fileno(serial_out), TCSANOW, &saved_attributes_out);
242       fclose(serial_out);
243     }
244   if (serial_in)
245     {
246       if (isatty(fileno(serial_in)))
247         tcsetattr(fileno(serial_in), TCSANOW, &saved_attributes_in);
248       fclose(serial_in);
249     }
250   */
251 }
252
253
254 /*
255  * Writing data to EROM
256  */
257
258 void
259 t_uc51::write_rom(t_addr addr, ulong data)
260 {
261   if (addr < EROM_SIZE)
262     set_mem(MEM_ROM, addr, data);
263 }
264
265
266 /*
267  * Disassembling an instruction
268  */
269
270 struct dis_entry *
271 t_uc51::dis_tbl(void)
272 {
273   return(disass_51);
274 }
275
276 struct name_entry *
277 t_uc51::sfr_tbl(void)
278 {
279   return(sfr_tab51);
280 }
281
282 struct name_entry *
283 t_uc51::bit_tbl(void)
284 {
285   return(bit_tab51);
286 }
287
288 char *
289 t_uc51::disass(t_addr addr, char *sep)
290 {
291   char work[256], temp[20], c[2];
292   char *buf, *p, *b, *t;
293   t_mem code= get_mem(MEM_ROM, addr);
294
295   p= work;
296   b= dis_tbl()[code].mnemonic;
297   while (*b)
298     {
299       if (*b == '%')
300         {
301           b++;
302           switch (*(b++))
303             {
304             case 'A': // absolute address
305               sprintf(temp, "%04"_A_"x",
306                       t_addr((addr&0xf800)|
307                              (((code>>5)&0x07)*256 +
308                               get_mem(MEM_ROM, addr+1))));
309               break;
310             case 'l': // long address
311               sprintf(temp, "%04"_A_"x",
312                       t_addr(get_mem(MEM_ROM, addr+1)*256 +
313                              get_mem(MEM_ROM, addr+2)));
314               break;
315             case 'a': // addr8 (direct address) at 2nd byte
316               if (!get_name(get_mem(MEM_ROM, addr+1), sfr_tbl(), temp))
317                 sprintf(temp, "%02"_M_"x", get_mem(MEM_ROM, addr+1));
318               break;
319             case '8': // addr8 (direct address) at 3rd byte
320               if (!get_name(get_mem(MEM_ROM, addr+2), sfr_tbl(), temp))
321                 sprintf(temp, "%02"_M_"x", get_mem(MEM_ROM, addr+2));
322               //sprintf(temp, "%02"_M_"x", get_mem(MEM_ROM, addr+2));
323               break;
324             case 'b': // bitaddr at 2nd byte
325               {
326                 t_addr ba= get_mem(MEM_ROM, addr+1);
327                 if (get_name(ba, bit_tbl(), temp))
328                   break;
329                 if (get_name((ba<128)?((ba/8)+32):(ba&0xf8), sfr_tbl(), temp))
330                   {
331                     strcat(temp, ".");
332                     sprintf(c, "%1"_M_"d", ba & 0x07);
333                     strcat(temp, c);
334                     break;
335                   }
336                 sprintf(temp, "%02x.%"_M_"d", (ba<128)?((ba/8)+32):(ba&0xf8),
337                         ba & 0x07);
338                 break;
339               }
340             case 'r': // rel8 address at 2nd byte
341               sprintf(temp, "%04"_A_"x",
342                       t_addr(addr+2+(signed char)(get_mem(MEM_ROM, addr+1))));
343               break;
344             case 'R': // rel8 address at 3rd byte
345               sprintf(temp, "%04"_A_"x",
346                       t_addr(addr+3+(signed char)(get_mem(MEM_ROM, addr+2))));
347               break;
348             case 'd': // data8 at 2nd byte
349               sprintf(temp, "%02"_M_"x", get_mem(MEM_ROM, addr+1));
350               break;
351             case 'D': // data8 at 3rd byte
352               sprintf(temp, "%02"_M_"x", get_mem(MEM_ROM, addr+2));
353               break;
354             case '6': // data16 at 2nd(H)-3rd(L) byte
355               sprintf(temp, "%04"_A_"x",
356                       t_addr(get_mem(MEM_ROM, addr+1)*256 +
357                              get_mem(MEM_ROM, addr+2)));
358               break;
359             default:
360               strcpy(temp, "?");
361               break;
362             }
363           t= temp;
364           while (*t)
365             *(p++)= *(t++);
366         }
367       else
368         *(p++)= *(b++);
369     }
370   *p= '\0';
371
372   p= strchr(work, ' ');
373   if (!p)
374     {
375       buf= strdup(work);
376       return(buf);
377     }
378   if (sep == NULL)
379     buf= (char *)malloc(6+strlen(p)+1);
380   else
381     buf= (char *)malloc((p-work)+strlen(sep)+strlen(p)+1);
382   for (p= work, b= buf; *p != ' '; p++, b++)
383     *b= *p;
384   p++;
385   *b= '\0';
386   if (sep == NULL)
387     {
388       while (strlen(buf) < 6)
389         strcat(buf, " ");
390     }
391   else
392     strcat(buf, sep);
393   strcat(buf, p);
394   return(buf);
395 }
396
397
398 void
399 t_uc51::print_regs(class cl_console *con)
400 {
401   t_addr start;
402   uchar data;
403
404   start= psw->get() & 0x18;
405   //dump_memory(iram, &start, start+7, 8, /*sim->cmd_out()*/con, sim);
406   iram->dump(start, start+7, 8, con);
407   start= psw->get() & 0x18;
408   data= iram->get(iram->get(start));
409   con->dd_printf("%06x %02x %c",
410               iram->get(start), data, isprint(data)?data:'.');
411
412   con->dd_printf("  ACC= 0x%02x %3d %c  B= 0x%02x", sfr->get(ACC), sfr->get(ACC),
413               isprint(sfr->get(ACC))?(sfr->get(ACC)):'.', sfr->get(B)); 
414   eram2xram();
415   data= get_mem(MEM_XRAM, sfr->get(DPH)*256+sfr->get(DPL));
416   con->dd_printf("   DPTR= 0x%02x%02x @DPTR= 0x%02x %3d %c\n", sfr->get(DPH),
417               sfr->get(DPL), data, data, isprint(data)?data:'.');
418
419   data= iram->get(iram->get(start+1));
420   con->dd_printf("%06x %02x %c", iram->get(start+1), data,
421               isprint(data)?data:'.');
422   data= psw->get();
423   con->dd_printf("  PSW= 0x%02x CY=%c AC=%c OV=%c P=%c\n", data,
424               (data&bmCY)?'1':'0', (data&bmAC)?'1':'0',
425               (data&bmOV)?'1':'0', (data&bmP)?'1':'0');
426
427   print_disass(PC, con);
428 }
429
430
431 /*
432  * Converting bit address into real memory
433  */
434
435 class cl_mem *
436 t_uc51::bit2mem(t_addr bitaddr, t_addr *memaddr, t_mem *bitmask)
437 {
438   class cl_mem *m;
439   t_addr ma;
440
441   bitaddr&= 0xff;
442   if (bitaddr < 128)
443     {
444       m= iram;
445       ma= bitaddr/8 + 0x20;
446     }
447   else
448     {
449       m= sfr;
450       ma= bitaddr & 0xf8;
451     }
452   if (memaddr)
453     *memaddr= ma;
454   if (bitmask)
455     *bitmask= 1 << (bitaddr & 0x7);
456   return(m);
457 }
458
459
460 /*
461  * Resetting the micro-controller
462  */
463
464 void
465 t_uc51::reset(void)
466 {
467   cl_uc::reset();
468
469   clear_sfr();
470
471   result= resGO;
472
473   //was_reti= DD_FALSE;
474 }
475
476
477 /*
478  * Setting up SFR area to reset value
479  */
480
481 void
482 t_uc51::clear_sfr(void)
483 {
484   int i;
485   
486   for (i= 0; i < SFR_SIZE; i++)
487     sfr->set(i, 0);
488   sfr->/*set*/write(P0, 0xff);
489   sfr->/*set*/write(P1, 0xff);
490   sfr->/*set*/write(P2, 0xff);
491   sfr->/*set*/write(P3, 0xff);
492   sfr->/*set*/write(SP, 7);
493   prev_p1= /*port_pins[1] &*/ sfr->/*get*/read(P1);
494   prev_p3= /*port_pins[3] &*/ sfr->/*get*/read(P3);
495   sfr->set_nuof_writes(0);
496   sfr->set_nuof_reads(0);
497 }
498
499
500 /*
501  * Analyzing code and settig up instruction map
502  */
503
504 void
505 t_uc51::analyze(t_addr addr)
506 {
507   uint code;
508   struct dis_entry *tabl;
509
510   code= get_mem(MEM_ROM, addr);
511   tabl= &(dis_tbl()[code]);
512   while (!inst_at(addr) &&
513          code != 0xa5 /* break point */)
514     {
515       set_inst_at(addr);
516       switch (tabl->branch)
517         {
518         case 'a': // acall
519           analyze((addr & 0xf800)|
520                   ((get_mem(MEM_ROM, addr+1)&0x07)*256+
521                    get_mem(MEM_ROM, addr+2)));
522           analyze(addr+tabl->length);
523           break;
524         case 'A': // ajmp
525           addr= (addr & 0xf800)|
526             ((get_mem(MEM_ROM, addr+1) & 0x07)*256 + get_mem(MEM_ROM, addr+2));
527           break;
528         case 'l': // lcall
529           analyze(get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2));
530           analyze(addr+tabl->length);
531           break;
532         case 'L': // ljmp
533           addr= get_mem(MEM_ROM, addr+1)*256 + get_mem(MEM_ROM, addr+2);
534           break;
535         case 'r': // reljmp (2nd byte)
536           analyze((addr + (signed char)(get_mem(MEM_ROM, addr+1))) &
537                   (EROM_SIZE - 1));
538           analyze(addr+tabl->length);
539           break;
540         case 'R': // reljmp (3rd byte)
541           analyze((addr+
542                    (signed char)(get_mem(MEM_ROM, addr+2)))&(EROM_SIZE-1));
543           analyze(addr+tabl->length);
544           break;
545         case 's': // sjmp
546           {
547             signed char target;
548             target= get_mem(MEM_ROM, addr+1);
549             addr+= 2;
550             addr= (addr+target)&(EROM_SIZE-1);
551             break;
552           }
553         case '_':
554           return;
555         default:
556           addr= (addr+tabl->length) & (EROM_SIZE - 1);
557           break;
558         }
559       code= get_mem(MEM_ROM, addr);
560       tabl= &(dis_tbl()[code]);
561     }
562 }
563
564
565 /*
566  * Inform hardware elements that `cycles' machine cycles have elapsed
567  */
568
569 /*int
570 t_uc51::tick_hw(int cycles)
571 {
572   cl_uc::tick_hw(cycles);
573   //do_hardware(cycles);
574   return(0);
575 }*/
576
577 /*int
578 t_uc51::tick(int cycles)
579 {
580   cl_uc::tick(cycles);
581   //do_hardware(cycles);
582   return(0);
583 }*/
584
585
586 /*
587  * Correcting direct address
588  *
589  * This function returns address of addressed element which can be an IRAM
590  * or an SFR.
591  */
592
593 class cl_cell *
594 t_uc51::get_direct(t_mem addr)
595 {
596   if (addr < SFR_START)
597     return(iram->get_cell(addr));
598   else
599     return(sfr->get_cell(addr));
600 }
601
602
603 /*
604  * Calculating address of specified register cell in IRAM
605  */
606
607 class cl_cell *
608 t_uc51::get_reg(uchar regnum)
609 {
610   t_addr a= (psw->get() & (bmRS0|bmRS1)) | (regnum & 0x07);
611   return(iram->get_cell(a));
612 }
613
614
615 /*
616  * Fetching one instruction and executing it
617  */
618
619 int
620 t_uc51::exec_inst(void)
621 {
622   t_mem code;
623   int res;
624
625   //pr_inst();
626   instPC= PC;
627   if (fetch(&code))
628     return(resBREAKPOINT);
629   //tick_hw(1);
630   tick(1);
631   switch (code)
632     {
633     case 0x00: res= inst_nop(code); break;
634     case 0x01: case 0x21: case 0x41: case 0x61:
635     case 0x81: case 0xa1: case 0xc1: case 0xe1:res=inst_ajmp_addr(code);break;
636     case 0x02: res= inst_ljmp(code); break;
637     case 0x03: res= inst_rr(code); break;
638     case 0x04: res= inst_inc_a(code); break;
639     case 0x05: res= inst_inc_addr(code); break;
640     case 0x06: case 0x07: res= inst_inc_Sri(code); break;
641     case 0x08: case 0x09: case 0x0a: case 0x0b:
642     case 0x0c: case 0x0d: case 0x0e: case 0x0f: res= inst_inc_rn(code); break;
643     case 0x10: res= inst_jbc_bit_addr(code); break;
644     case 0x11: case 0x31: case 0x51: case 0x71:
645     case 0x91: case 0xb1: case 0xd1: case 0xf1:res=inst_acall_addr(code);break;
646     case 0x12: res= inst_lcall(code, 0); break;
647     case 0x13: res= inst_rrc(code); break;
648     case 0x14: res= inst_dec_a(code); break;
649     case 0x15: res= inst_dec_addr(code); break;
650     case 0x16: case 0x17: res= inst_dec_Sri(code); break;
651     case 0x18: case 0x19: case 0x1a: case 0x1b:
652     case 0x1c: case 0x1d: case 0x1e: case 0x1f: res= inst_dec_rn(code); break;
653     case 0x20: res= inst_jb_bit_addr(code); break;
654     case 0x22: res= inst_ret(code); break;
655     case 0x23: res= inst_rl(code); break;
656     case 0x24: res= inst_add_a_Sdata(code); break;
657     case 0x25: res= inst_add_a_addr(code); break;
658     case 0x26: case 0x27: res= inst_add_a_Sri(code); break;
659     case 0x28: case 0x29: case 0x2a: case 0x2b:
660     case 0x2c: case 0x2d: case 0x2e: case 0x2f:res= inst_add_a_rn(code);break;
661     case 0x30: res= inst_jnb_bit_addr(code); break;
662     case 0x32: res= inst_reti(code); break;
663     case 0x33: res= inst_rlc(code); break;
664     case 0x34: res= inst_addc_a_Sdata(code); break;
665     case 0x35: res= inst_addc_a_addr(code); break;
666     case 0x36: case 0x37: res= inst_addc_a_Sri(code); break;
667     case 0x38: case 0x39: case 0x3a: case 0x3b:
668     case 0x3c: case 0x3d: case 0x3e: case 0x3f:res= inst_addc_a_rn(code);break;
669     case 0x40: res= inst_jc_addr(code); break;
670     case 0x42: res= inst_orl_addr_a(code); break;
671     case 0x43: res= inst_orl_addr_Sdata(code); break;
672     case 0x44: res= inst_orl_a_Sdata(code); break;
673     case 0x45: res= inst_orl_a_addr(code); break;
674     case 0x46: case 0x47: res= inst_orl_a_Sri(code); break;
675     case 0x48: case 0x49: case 0x4a: case 0x4b:
676     case 0x4c: case 0x4d: case 0x4e: case 0x4f: res= inst_orl_a_rn(code);break;
677     case 0x50: res= inst_jnc_addr(code); break;
678     case 0x52: res= inst_anl_addr_a(code); break;
679     case 0x53: res= inst_anl_addr_Sdata(code); break;
680     case 0x54: res= inst_anl_a_Sdata(code); break;
681     case 0x55: res= inst_anl_a_addr(code); break;
682     case 0x56: case 0x57: res= inst_anl_a_Sri(code); break;
683     case 0x58: case 0x59: case 0x5a: case 0x5b:
684     case 0x5c: case 0x5d: case 0x5e: case 0x5f: res= inst_anl_a_rn(code);break;
685     case 0x60: res= inst_jz_addr(code); break;
686     case 0x62: res= inst_xrl_addr_a(code); break;
687     case 0x63: res= inst_xrl_addr_Sdata(code); break;
688     case 0x64: res= inst_xrl_a_Sdata(code); break;
689     case 0x65: res= inst_xrl_a_addr(code); break;
690     case 0x66: case 0x67: res= inst_xrl_a_Sri(code); break;
691     case 0x68: case 0x69: case 0x6a: case 0x6b:
692     case 0x6c: case 0x6d: case 0x6e: case 0x6f: res= inst_xrl_a_rn(code);break;
693     case 0x70: res= inst_jnz_addr(code); break;
694     case 0x72: res= inst_orl_c_bit(code); break;
695     case 0x73: res= inst_jmp_Sa_dptr(code); break;
696     case 0x74: res= inst_mov_a_Sdata(code); break;
697     case 0x75: res= inst_mov_addr_Sdata(code); break;
698     case 0x76: case 0x77: res= inst_mov_Sri_Sdata(code); break;
699     case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c:
700     case 0x7d: case 0x7e: case 0x7f: res=inst_mov_rn_Sdata(code); break;
701     case 0x80: res= inst_sjmp(code); break;
702     case 0x82: res= inst_anl_c_bit(code); break;
703     case 0x83: res= inst_movc_a_Sa_pc(code); break;
704     case 0x84: res= inst_div_ab(code); break;
705     case 0x85: res= inst_mov_addr_addr(code); break;
706     case 0x86: case 0x87: res= inst_mov_addr_Sri(code); break;
707     case 0x88: case 0x89: case 0x8a: case 0x8b:
708     case 0x8c: case 0x8d: case 0x8e: case 0x8f:res=inst_mov_addr_rn(code);break;
709     case 0x90: res= inst_mov_dptr_Sdata(code); break;
710     case 0x92: res= inst_mov_bit_c(code); break;
711     case 0x93: res= inst_movc_a_Sa_dptr(code); break;
712     case 0x94: res= inst_subb_a_Sdata(code); break;
713     case 0x95: res= inst_subb_a_addr(code); break;
714     case 0x96: case 0x97: res= inst_subb_a_Sri(code); break;
715     case 0x98: case 0x99: case 0x9a: case 0x9b:
716     case 0x9c: case 0x9d: case 0x9e: case 0x9f:res= inst_subb_a_rn(code);break;
717     case 0xa2: res= inst_mov_c_bit(code); break;
718     case 0xa3: res= inst_inc_dptr(code); break;
719     case 0xa4: res= inst_mul_ab(code); break;
720     case 0xa5: res= inst_unknown(code); break;
721     case 0xa6: case 0xa7: res= inst_mov_Sri_addr(code); break;
722     case 0xa8: case 0xa9: case 0xaa: case 0xab:
723     case 0xac: case 0xad: case 0xae: case 0xaf:res=inst_mov_rn_addr(code);break;
724     case 0xb0: res= inst_anl_c_Sbit(code); break;
725     case 0xb2: res= inst_cpl_bit(code); break;
726     case 0xb3: res= inst_cpl_c(code); break;
727     case 0xb4: res= inst_cjne_a_Sdata_addr(code); break;
728     case 0xb5: res= inst_cjne_a_addr_addr(code); break;
729     case 0xb6: case 0xb7: res= inst_cjne_Sri_Sdata_addr(code); break;
730     case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc:
731     case 0xbd: case 0xbe: case 0xbf: res=inst_cjne_rn_Sdata_addr(code); break;
732     case 0xc0: res= inst_push(code); break;
733     case 0xc2: res= inst_clr_bit(code); break;
734     case 0xc3: res= inst_clr_c(code); break;
735     case 0xc4: res= inst_swap(code); break;
736     case 0xc5: res= inst_xch_a_addr(code); break;
737     case 0xc6: case 0xc7: res= inst_xch_a_Sri(code); break;
738     case 0xc8: case 0xc9: case 0xca: case 0xcb:
739     case 0xcc: case 0xcd: case 0xce: case 0xcf: res= inst_xch_a_rn(code);break;
740     case 0xd0: res= inst_pop(code); break;
741     case 0xd2: res= inst_setb_bit(code); break;
742     case 0xd3: res= inst_setb_c(code); break;
743     case 0xd4: res= inst_da_a(code); break;
744     case 0xd5: res= inst_djnz_addr_addr(code); break;
745     case 0xd6: case 0xd7: res= inst_xchd_a_Sri(code); break;
746     case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc:
747     case 0xdd: case 0xde: case 0xdf: res=inst_djnz_rn_addr(code); break;
748     case 0xe0: res= inst_movx_a_Sdptr(code); break;
749     case 0xe2: case 0xe3: res= inst_movx_a_Sri(code); break;
750     case 0xe4: res= inst_clr_a(code); break;
751     case 0xe5: res= inst_mov_a_addr(code); break;
752     case 0xe6: case 0xe7: res= inst_mov_a_Sri(code); break;
753     case 0xe8: case 0xe9: case 0xea: case 0xeb:
754     case 0xec: case 0xed: case 0xee: case 0xef: res= inst_mov_a_rn(code);break;
755     case 0xf0: res= inst_movx_Sdptr_a(code); break;
756     case 0xf2: case 0xf3: res= inst_movx_Sri_a(code); break;
757     case 0xf4: res= inst_cpl_a(code); break;
758     case 0xf5: res= inst_mov_addr_a(code); break;
759     case 0xf6: case 0xf7: res= inst_mov_Sri_a(code); break;
760     case 0xf8: case 0xf9: case 0xfa: case 0xfb:
761     case 0xfc: case 0xfd: case 0xfe: case 0xff: res= inst_mov_rn_a(code);break;
762     default:
763       res= inst_unknown(code);
764       break;
765     }
766   //post_inst();
767   return(res);
768 }
769
770
771 /*
772  * Simulating execution of next instruction
773  *
774  * This is an endless loop if requested number of steps is negative.
775  * In this case execution is stopped if an instruction results other
776  * status than GO. Execution can be stopped if `cmd_in' is not NULL
777  * and there is input available on that file. It is usefull if the
778  * command console is on a terminal. If input is available then a
779  * complete line is read and dropped out because input is buffered
780  * (inp_avail will be TRUE if ENTER is pressed) and it can confuse
781  * command interepter.
782  */
783
784 int
785 t_uc51::do_inst(int step)
786 {
787   result= resGO;
788   while ((result == resGO) &&
789          (state != stPD) &&
790          (step != 0))
791     {
792       if (step > 0)
793         step--;
794       if (state == stGO)
795         {
796           interrupt->was_reti= DD_FALSE;
797           pre_inst();
798           result= exec_inst();
799           post_inst();
800           /*if (result == resGO)
801             result= check_events();*/
802         }
803       else
804         {
805           // tick hw in idle state
806           post_inst();
807           tick(1);
808         }
809       if (result == resGO)
810         {
811           int res;
812           if ((res= do_interrupt()) != resGO)
813             result= res;
814           else
815             result= idle_pd();
816         }
817       if ((step < 0) &&
818           ((ticks->ticks % 100000) < 50))
819         {
820           if (sim->app->get_commander()->input_avail_on_frozen())
821             {
822               result= resUSER;
823             }
824           else
825             if (sim->app->get_commander()->input_avail())
826               break;
827         }
828       if (((result == resINTERRUPT) &&
829            stop_at_it) ||
830           result >= resSTOP)
831         {
832           sim->stop(result);
833           break;
834         }
835     }
836   if (state == stPD)
837     {
838       //FIXME: tick outsiders eg. watchdog
839       if (sim->app->get_commander()->input_avail_on_frozen())
840         {
841           //fprintf(stderr,"uc: inp avail in PD mode, user stop\n");
842           result= resUSER;
843           sim->stop(result); 
844         }
845     }
846   return(result);
847 }
848
849 /*void
850 t_uc51::post_inst(void)
851 {*/
852   //uint tcon= sfr->get(TCON);
853   //uint p3= sfr->read(P3);
854
855   //cl_uc::post_inst();
856   //set_p_flag();
857
858   // Setting up external interrupt request bits (IEx)
859   /*if ((tcon & bmIT0))
860     {
861       // IE0 edge triggered
862       if (p3_int0_edge)
863         {
864           // falling edge on INT0
865           sim->app->get_commander()->
866             debug("%g sec (%d clks): Falling edge detected on INT0 (P3.2)\n",
867                           get_rtime(), ticks->ticks);
868           sfr->set_bit1(TCON, bmIE0);
869           p3_int0_edge= 0;
870         }
871     }
872   else
873     {
874       // IE0 level triggered
875       if (p3 & bm_INT0)
876         sfr->set_bit0(TCON, bmIE0);
877       else
878         sfr->set_bit1(TCON, bmIE0);
879     }
880   if ((tcon & bmIT1))
881     {
882       // IE1 edge triggered
883       if (p3_int1_edge)
884         {
885           // falling edge on INT1
886           sfr->set_bit1(TCON, bmIE1);
887           p3_int1_edge= 0;
888         }
889     }
890   else
891     {
892       // IE1 level triggered
893       if (p3 & bm_INT1)
894         sfr->set_bit0(TCON, bmIE1);
895       else
896         sfr->set_bit1(TCON, bmIE1);
897         }*/
898   //prev_p3= p3 & port_pins[3];
899   //prev_p1= p3 & port_pins[1];
900 //}
901
902
903 /*
904  * Abstract method to handle WDT
905  */
906
907 /*int
908 t_uc51::do_wdt(int cycles)
909 {
910   return(resGO);
911 }*/
912
913
914 /*
915  * Checking for interrupt requests and accept one if needed
916  */
917
918 int
919 t_uc51::do_interrupt(void)
920 {
921   int i, ie= 0;
922
923   if (interrupt->was_reti)
924     {
925       interrupt->was_reti= DD_FALSE;
926       return(resGO);
927     }
928   if (!((ie= sfr->get(IE)) & bmEA))
929     return(resGO);
930   class it_level *il= (class it_level *)(it_levels->top()), *IL= 0;
931   for (i= 0; i < it_sources->count; i++)
932     {
933       class cl_it_src *is= (class cl_it_src *)(it_sources->at(i));
934       if (is->is_active() &&
935           (ie & is->ie_mask) &&
936           (sfr->get(is->src_reg) & is->src_mask))
937         {
938           int pr= it_priority(is->ie_mask);
939           if (il->level >= 0 &&
940               pr <= il->level)
941             continue;
942           if (state == stIDLE)
943             {
944               state= stGO;
945               sfr->set_bit0(PCON, bmIDL);
946               interrupt->was_reti= DD_TRUE;
947               return(resGO);
948             }
949           if (is->clr_bit)
950             sfr->set_bit0(is->src_reg, is->src_mask);
951           sim->app->get_commander()->
952             debug("%g sec (%d clks): Accepting interrupt `%s' PC= 0x%06x\n",
953                           get_rtime(), ticks->ticks, object_name(is), PC);
954           IL= new it_level(pr, is->addr, PC, is);
955           return(accept_it(IL));
956         }
957     }
958   return(resGO);
959 }
960
961 int
962 t_uc51::it_priority(uchar ie_mask)
963 {
964   if (sfr->get(IP) & ie_mask)
965     return(1);
966   return(0);
967 }
968
969
970 /*
971  * Accept an interrupt
972  */
973
974 int
975 t_uc51::accept_it(class it_level *il)
976 {
977   state= stGO;
978   sfr->set_bit0(PCON, bmIDL);
979   it_levels->push(il);
980   tick(1);
981   int res= inst_lcall(0, il->addr);
982   if (res != resGO)
983     return(res);
984   else
985     return(resINTERRUPT);
986 }
987
988
989 /*
990  * Checking if Idle or PowerDown mode should be activated
991  */
992
993 int
994 t_uc51::idle_pd(void)
995 {
996   uint pcon= sfr->get(PCON);
997
998   if (technology != CPU_CMOS)
999     return(resGO);
1000   if (pcon & bmIDL)
1001     {
1002       if (state != stIDLE)
1003         sim->app->get_commander()->
1004           debug("%g sec (%d clks): CPU in Idle mode\n",
1005                 get_rtime(), ticks->ticks);
1006       state= stIDLE;
1007       //was_reti= 1;
1008     }
1009   if (pcon & bmPD)
1010     {
1011       if (state != stPD)
1012         sim->app->get_commander()->
1013           debug("%g sec (%d clks): CPU in PowerDown mode\n",
1014                         get_rtime(), ticks->ticks);
1015       state= stPD;
1016     }
1017   return(resGO);
1018 }
1019
1020
1021 /*
1022  * Checking if EVENT break happened
1023  */
1024
1025 /*int
1026 t_uc51::check_events(void)
1027 {
1028   int i;
1029   class cl_ev_brk *eb;
1030
1031   if (!ebrk->count)
1032     return(resGO);
1033   for (i= 0; i < ebrk->count; i++)
1034     {
1035       eb= (class cl_ev_brk *)(ebrk->at(i));
1036       if (eb->match(&event_at))
1037         return(resBREAKPOINT);
1038     }
1039   return(resGO);
1040 }*/
1041
1042
1043 /*
1044  */
1045
1046 void
1047 t_uc51::mem_cell_changed(class cl_mem *mem, t_addr addr)
1048 {
1049   if (mem == sfr)
1050     switch (addr)
1051       {
1052       case ACC: acc= mem->get_cell(ACC); break;
1053       case PSW: psw= mem->get_cell(PSW); break;
1054       }
1055   cl_uc::mem_cell_changed(mem, addr);
1056 }
1057
1058
1059 /*
1060  * Simulating an unknown instruction
1061  *
1062  * Normally this function is called for unimplemented instructions, because
1063  * every instruction must be known!
1064  */
1065
1066 int
1067 t_uc51::inst_unknown(uchar code)
1068 {
1069   PC--;
1070   if (1)//debug)// && sim->cmd_out())
1071     sim->app->get_commander()->
1072       debug("Unknown instruction %02x at %06x\n", code, PC);
1073   return(resHALT);
1074 }
1075
1076
1077 /*
1078  * 0x00 1 12 NOP
1079  */
1080
1081 int
1082 t_uc51::inst_nop(uchar code)
1083 {
1084   return(resGO);
1085 }
1086
1087
1088 /*
1089  * 0xe4 1 12 CLR A
1090  */
1091
1092 int
1093 t_uc51::inst_clr_a(uchar code)
1094 {
1095   acc->write(0);
1096   return(resGO);
1097 }
1098
1099
1100 /*
1101  * 0xc4 1 1 SWAP A
1102  */
1103
1104 int
1105 t_uc51::inst_swap(uchar code)
1106 {
1107   uchar temp;
1108
1109   temp= (acc->read() >> 4) & 0x0f;
1110   sfr->write(ACC, (acc->get() << 4) | temp);
1111   return(resGO);
1112 }
1113
1114
1115 /*
1116  */
1117
1118 cl_uc51_dummy_hw::cl_uc51_dummy_hw(class cl_uc *auc):
1119   cl_hw(auc, HW_DUMMY, 0, "_51_dummy")
1120 {
1121   //uc51= (class t_uc51 *)uc;
1122 }
1123
1124 int
1125 cl_uc51_dummy_hw::init(void)
1126 {
1127   class cl_mem *sfr= uc->mem(MEM_SFR);
1128   if (!sfr)
1129     {
1130       fprintf(stderr, "No SFR to register %s[%d] into\n", id_string, id);
1131     }
1132   //acc= sfr->register_hw(ACC, this, 0);
1133   //sp = sfr->register_hw(SP , this, 0);
1134   use_cell(sfr, PSW, &cell_psw, wtd_restore);
1135   register_cell(sfr, ACC, &cell_acc, wtd_restore_write);
1136   register_cell(sfr, SP , &cell_sp , wtd_restore);
1137   return(0);
1138 }
1139
1140 void
1141 cl_uc51_dummy_hw::write(class cl_cell *cell, t_mem *val)
1142 {
1143   if (cell == cell_acc)
1144     {
1145       bool p;
1146       int i;
1147       uchar uc;
1148
1149       p = DD_FALSE;
1150       uc= *val;
1151       for (i= 0; i < 8; i++)
1152         {
1153           if (uc & 1)
1154             p= !p;
1155           uc>>= 1;
1156         }
1157       if (p)
1158         cell_psw->set_bit1(bmP);
1159       else
1160         cell_psw->set_bit0(bmP);
1161     }
1162   else if (cell == cell_sp)
1163     {
1164       if (*val > uc->sp_max)
1165         uc->sp_max= *val;
1166       uc->sp_avg= (uc->sp_avg+(*val))/2;
1167     }
1168 }
1169
1170 /*void
1171 cl_uc51_dummy_hw::happen(class cl_hw *where, enum hw_event he, void *params)
1172 {
1173   struct ev_port_changed *ep= (struct ev_port_changed *)params;
1174
1175   if (where->cathegory == HW_PORT &&
1176       he == EV_PORT_CHANGED &&
1177       ep->id == 3)
1178     {
1179       t_mem p3o= ep->pins & ep->prev_value;
1180       t_mem p3n= ep->new_pins & ep->new_value;
1181       if ((p3o & bm_INT0) &&
1182           !(p3n & bm_INT0))
1183         uc51->p3_int0_edge++;
1184       if ((p3o & bm_INT1) &&
1185           !(p3n & bm_INT1))
1186         uc51->p3_int1_edge++;
1187     }
1188 }*/
1189
1190
1191 /* End of s51.src/uc51.cc */