version 0.5.2
[fw/sdcc] / sim / ucsim / s51.src / arith.cc
1 /*
2  * Simulator of microcontrollers (arith.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
32 // local
33 #include "uc51cl.h"
34 #include "regs51.h"
35 #include "types51.h"
36
37
38 /*
39  * 0x03 1 12 RR A
40  *____________________________________________________________________________
41  *
42  */
43
44 int
45 cl_51core::inst_rr(uchar code)
46 {
47   uchar ac;
48
49   ac= acc->read(); 
50   if (ac & 0x01)
51     acc->write((ac >> 1) | 0x80);
52   else
53     acc->write(ac >> 1);
54   return(resGO);
55 }
56
57
58 /*
59  * 0x13 1 12 RRC A
60  *____________________________________________________________________________
61  *
62  */
63
64 int
65 cl_51core::inst_rrc(uchar code)
66 {
67   bool cy;
68   uchar ac;
69
70   cy= SFR_GET_C;
71   SFR_SET_C((ac= acc->read()) & 0x01);
72   ac>>= 1;
73   if (cy)
74     ac|= 0x80;
75   sfr->write(ACC, ac);
76   return(resGO);
77 }
78
79
80 /*
81  * 0x23 1 12 RL A
82  *____________________________________________________________________________
83  *
84  */
85
86 int
87 cl_51core::inst_rl(uchar code)
88 {
89   uchar ac;
90
91   ac= acc->read();
92   if (ac & 0x80)
93     acc->write((ac << 1 ) | 0x01);
94   else
95     acc->write(ac << 1);
96   return(resGO);
97 }
98
99
100 /*
101  * 0x24 2 12 ADD A,#data
102  *____________________________________________________________________________
103  *
104  */
105
106 int
107 cl_51core::inst_add_a_Sdata(uchar code)
108 {
109   uchar data, ac;
110   bool newC, newA, c6;
111
112   data= fetch();
113   ac  = acc->read();
114   newC= (((uint)ac+(uint)(data)) > 255)?0x80:0;
115   newA= ((ac&0x0f)+(data&0x0f)) & 0xf0;
116   c6  = ((ac&0x7f)+(data&0x7f)) & 0x80;
117   acc->write(ac+data);
118   SFR_SET_C(newC);
119   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
120   SFR_SET_BIT(newA, PSW, bmAC);
121   return(resGO);
122 }
123
124
125 /*
126  * 0x25 2 12 ADD A,addr
127  *____________________________________________________________________________
128  *
129  */
130
131 int
132 cl_51core::inst_add_a_addr(uchar code)
133 {
134   uchar data, ac;
135   bool newC, newA, c6;
136   class cl_memory_cell *cell;
137   t_addr a;
138
139   cell= get_direct(a= fetch());
140   data= cell->read();
141   ac  = acc->get();
142   newC= (((uint)ac+(uint)(data)) > 255)?0x80:0;
143   newA= ((ac&0x0f)+(data&0x0f)) & 0xf0;
144   c6  = ((ac&0x7f)+(data&0x7f)) & 0x80;
145   acc->write(ac+data);
146   SFR_SET_C(newC);
147   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
148   SFR_SET_BIT(newA, PSW, bmAC);
149   return(resGO);
150 }
151
152
153 /*
154  * 0x26-0x27 1 12 ADD A,@Ri
155  *____________________________________________________________________________
156  *
157  */
158
159 int
160 cl_51core::inst_add_a_Sri(uchar code)
161 {
162   uchar data, ac;
163   bool newC, newA, c6;
164   class cl_memory_cell *cell;
165
166   cell= iram->get_cell(get_reg(code & 0x01)->read());
167   ac  = acc->get();
168   data= cell->read();
169   newC= (((uint)ac+(uint)data) > 255)?0x80:0;
170   newA= ((ac&0x0f)+(data&0x0f)) & 0xf0;
171   c6  = ((ac&0x7f)+(data&0x7f)) & 0x80;
172   acc->write(ac+data);
173   SFR_SET_C(newC);
174   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
175   SFR_SET_BIT(newA, PSW, bmAC);
176   return(resGO);
177 }
178
179
180 /*
181  * 0x28-0x2f 1 12 ADD A,Rn
182  *____________________________________________________________________________
183  *
184  */
185
186 int
187 cl_51core::inst_add_a_rn(uchar code)
188 {
189   uchar data, ac;
190   bool newC, newA, c6;
191
192   data= get_reg(code & 0x07)->read();
193   ac  = acc->get();
194   newC= (((uint)ac+(uint)data) > 255)?0x80:0;
195   newA= ((ac&0x0f)+(data&0x0f)) & 0xf0;
196   c6  = ((ac&0x7f)+(data&0x7f)) & 0x80;
197   acc->write(ac+data);
198   SFR_SET_C(newC);
199   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
200   SFR_SET_BIT(newA, PSW, bmAC);
201   return(resGO);
202 }
203
204
205 /*
206  * 0x33 1 12 RLC A
207  *____________________________________________________________________________
208  *
209  */
210
211 int
212 cl_51core::inst_rlc(uchar code)
213 {
214   bool cy;
215   uchar ac;
216
217   cy= SFR_GET_C;
218   SFR_SET_C((ac= acc->get()) & 0x80);
219   ac<<= 1;
220   if (cy)
221     ac|= 0x01;
222   acc->write(ac);
223   return(resGO);
224 }
225
226
227 /*
228  * 0x34 2 12 ADDC A,#data
229  *____________________________________________________________________________
230  *
231  */
232
233 int
234 cl_51core::inst_addc_a_Sdata(uchar code)
235 {
236   uchar data, ac;
237   bool orgC, newC, newA, c6;
238
239   data= fetch();
240   ac  = acc->get();
241   newC= (((uint)ac+(uint)data+((orgC= SFR_GET_C)?1:0)) > 255)?0x80:0;
242   newA= ((ac&0x0f)+(data&0x0f)+(orgC?1:0)) & 0xf0;
243   c6  = ((ac&0x7f)+(data&0x7f)+(orgC?1:0)) & 0x80;
244   acc->write(ac + data + (orgC?1:0));
245   SFR_SET_C(newC);
246   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
247   SFR_SET_BIT(newA, PSW, bmAC);
248   return(resGO);
249 }
250
251
252 /*
253  * 0x35 2 12 ADDC A,addr
254  *____________________________________________________________________________
255  *
256  */
257
258 int
259 cl_51core::inst_addc_a_addr(uchar code)
260 {
261   uchar data, ac;
262   bool orgC, newC, newA, c6;
263   class cl_memory_cell *cell;
264   t_addr a;
265
266   cell= get_direct(a= fetch());
267   data= cell->read();
268   ac  = acc->get();
269   newC= (((uint)ac+(uint)data+((orgC= SFR_GET_C)?1:0)) > 255)?0x80:0;
270   newA= ((ac&0x0f)+(data&0x0f)+(orgC?1:0)) & 0xf0;
271   c6  = ((ac&0x7f)+(data&0x7f)+(orgC?1:0)) & 0x80;
272   acc->write(ac + data + (orgC?1:0));
273   SFR_SET_C(newC);
274   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
275   SFR_SET_BIT(newA, PSW, bmAC);
276   return(resGO);
277 }
278
279
280 /*
281  * 0x36-0x37 1 12 ADDC A,@Ri
282  *____________________________________________________________________________
283  *
284  */
285
286 int
287 cl_51core::inst_addc_a_Sri(uchar code)
288 {
289   uchar data, ac;
290   bool orgC, newC, newA, c6;
291   class cl_memory_cell *cell;
292   
293   cell= iram->get_cell(get_reg(code & 0x01)->read());
294   ac  = acc->get();
295   data= cell->read();
296   newC= (((uint)ac+(uint)data+((orgC= SFR_GET_C)?1:0)) > 255)?0x80:0;
297   newA= ((ac&0x0f)+(data&0x0f)+(orgC?1:0)) & 0xf0;
298   c6  = ((ac&0x7f)+(data&0x7f)+(orgC?1:0)) & 0x80;
299   acc->write(ac + data + (orgC?1:0));
300   SFR_SET_C(newC);
301   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
302   SFR_SET_BIT(newA, PSW, bmAC);
303   return(resGO);
304 }
305
306
307 /*
308  * 0x38-0x3f 1 12 ADDC A,Rn
309  *____________________________________________________________________________
310  *
311  */
312
313 int
314 cl_51core::inst_addc_a_rn(uchar code)
315 {
316   uchar data, ac;
317   bool orgC, newC, newA, c6;
318
319   data= get_reg(code & 0x07)->read();
320   ac  = acc->get();
321   newC= (((uint)ac+(uint)data+((orgC= SFR_GET_C)?1:0)) > 255)?0x80:0;
322   newA= ((ac&0x0f)+(data&0x0f)+(orgC?1:0)) & 0xf0;
323   c6  = ((ac&0x7f)+(data&0x7f)+(orgC?1:0)) & 0x80;
324   acc->write(ac + data + (orgC?1:0));
325   SFR_SET_C(newC);
326   SFR_SET_BIT(newC ^ c6, PSW, bmOV);
327   SFR_SET_BIT(newA, PSW, bmAC);
328   return(resGO);
329 }
330
331
332 /*
333  * 0x84 1 48 DIV AB
334  *____________________________________________________________________________
335  *
336  */
337
338 int
339 cl_51core::inst_div_ab(uchar code)
340 {
341   uchar temp, pw, b, ac;
342
343   pw= psw->get();
344   pw&= ~bmCY;
345   if (!(b= sfr->get(B)))
346     pw|= bmOV;
347   else
348     {
349       pw&= ~bmOV;
350       temp= (ac= acc->get()) / b;
351       sfr->write(B, ac % b);
352       acc->write(temp);
353     }
354   psw->write(pw);
355   tick(3);
356   return(resGO);
357 }
358
359
360 /*
361  * 0x94 2 12 SUBB A,#data
362  *____________________________________________________________________________
363  *
364  */
365
366 int
367 cl_51core::inst_subb_a_Sdata(uchar code)
368 {
369   uchar data, ac, result, pw, c;
370
371   data= fetch();
372   ac  = acc->get();
373   result= ac-data;
374   pw= psw->get();
375   if ((c= (pw & bmCY)?1:0))
376     result--;
377   acc->write(result);
378   psw->write((pw & ~(bmCY|bmOV|bmAC)) |
379              (((unsigned int)ac < (unsigned int)(data+c))?bmCY:0) |
380              (((ac<0x80 && data>0x7f && result>0x7f) ||
381                (ac>0x7f && data<0x80 && result<0x80))?bmOV:0) |
382              (((ac&0x0f) < ((data+c)&0x0f) ||
383                (c && ((data&0x0f)==0x0f)))?bmAC:0));
384   return(resGO);
385 }
386
387
388 /*
389  * 0x95 2 12 SUBB A,addr
390  *____________________________________________________________________________
391  *
392  */
393
394 int
395 cl_51core::inst_subb_a_addr(uchar code)
396 {
397   uchar data, ac, result, pw, c;
398   class cl_memory_cell *cell;
399   
400   cell= get_direct(fetch());
401   ac  = acc->get();
402   data= cell->read();
403   result= ac-data;
404   pw= psw->get();
405   if ((c= (pw & bmCY)?1:0))
406     result--;
407   acc->write(result);
408   psw->set((pw & ~(bmCY|bmOV|bmAC)) |
409            (((unsigned int)ac < (unsigned int)(data+c))?bmCY:0) |
410            (((ac<0x80 && data>0x7f && result>0x7f) ||
411              (ac>0x7f && data<0x80 && result<0x80))?bmOV:0) |
412            (((ac&0x0f) < ((data+c)&0x0f) ||
413              (c && ((data&0x0f)==0x0f)))?bmAC:0));
414   return(resGO);
415 }
416
417
418 /*
419  * 0x96-0x97 1 12 SUBB A,@Ri
420  *____________________________________________________________________________
421  *
422  */
423
424 int
425 cl_51core::inst_subb_a_Sri(uchar code)
426 {
427   uchar data, ac, result, pw, c;
428   class cl_memory_cell *cell;
429
430   cell= iram->get_cell(get_reg(code & 0x01)->read());
431   data= cell->read();
432   ac  = acc->get();
433   result= ac-data;
434   pw= psw->get();
435   if ((c= (pw & bmCY)?1:0))
436     result--;
437   acc->write(result);
438   psw->write((pw & ~(bmCY|bmOV|bmAC)) |
439              (((unsigned int)ac < (unsigned int)(data+c))?bmCY:0) |
440              (((ac<0x80 && data>0x7f && result>0x7f) ||
441                (ac>0x7f && data<0x80 && result<0x80))?bmOV:0) |
442              (((ac&0x0f) < ((data+c)&0x0f) ||
443                (c && ((data&0x0f)==0x0f)))?bmAC:0));
444   return(resGO);
445 }
446
447
448 /*
449  * 0x98-0x9f 1 12 SUBB A,Rn
450  *____________________________________________________________________________
451  *
452  */
453
454 int
455 cl_51core::inst_subb_a_rn(uchar code)
456 {
457   uchar data, ac, result, pw, c;
458
459   data= get_reg(code & 0x07)->read();
460   ac  = acc->get();
461   result= ac-data;
462   pw= psw->get();
463   if ((c= (pw & bmCY)?1:0))
464     result--;
465   acc->write(result);
466   psw->write((pw & ~(bmCY|bmOV|bmAC)) |
467              (((unsigned int)ac < (unsigned int)(data+c))?bmCY:0) |
468              (((ac<0x80 && data>0x7f && result>0x7f) ||
469                (ac>0x7f && data<0x80 && result<0x80))?bmOV:0) |
470              (((ac&0x0f) < ((data+c)&0x0f) ||
471                (c && ((data&0x0f)==0x0f)))?bmAC:0));
472   return(resGO);
473 }
474
475
476 /*
477  * 0xa4 1 48 MUL AB
478  *____________________________________________________________________________
479  *
480  */
481
482 int
483 cl_51core::inst_mul_ab(uchar code)
484 {
485   uint temp, pw, ac, b, x;
486
487   pw= psw->get();
488   pw&= ~bmCY;
489   temp= (ac= acc->read()) * (b= sfr->get(B));
490   acc->write(temp & 0xff);
491   x= sfr->write(B, (temp >> 8) & 0xff);
492   SFR_SET_BIT(x/*sfr->get(B)*/, PSW, bmOV);
493   SFR_SET_BIT(0, PSW, bmCY);
494   tick(3);
495   return(resGO);
496 }
497
498
499 /*
500  * 0xd4 1 12 DA A
501  *____________________________________________________________________________
502  *
503  */
504
505 int
506 cl_51core::inst_da_a(uchar code)
507 {
508   uchar ac, pw;
509
510   ac= acc->get();
511   pw= psw->get();
512   if ((ac & 0x0f) > 9 ||
513       (pw & bmAC))
514     {
515       if (((uint)ac+(uint)0x06) > 255)
516         pw|= bmCY;
517       ac+= 0x06;
518     }
519   if ((ac & 0xf0) > 0x90 ||
520       (pw & bmCY))
521     {
522       if (((uint)ac+(uint)0x60) > 255)
523         pw|= bmCY;
524       ac+= 0x60;
525     }
526   acc->write(ac);
527   psw->write(pw);
528   return(resGO);
529 }
530
531
532 /* End of s51.src/arith.cc */