191dd08caaff8c2796118e11451aefa228a9dfea
[fw/sdcc] / sim / ucsim / s51.src / uc51r.cc
1 /*
2  * Simulator of microcontrollers (uc51r.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 "uc51rcl.h"
34 #include "regs51.h"
35
36
37 /*
38  * Making an 8051r CPU object
39  */
40
41 t_uc51r::t_uc51r(int Itype, int Itech, class cl_sim *asim):
42   t_uc52(Itype, Itech, asim)
43 {
44   int i;
45
46   for (i= 0; i < ERAM_SIZE; i++)
47     ERAM[i]= 0;
48   clock_out= 0;
49 }
50
51
52 /*
53  * Resetting of the microcontroller
54  *
55  * Original method is extended with handling of WDT.
56  */
57
58 void
59 t_uc51r::reset(void)
60 {
61   t_uc52::reset();
62   WDT= -1; // Disable WDT
63   wdtrst= 0;
64   MEM(MEM_SFR)[SADDR]= MEM(MEM_SFR)[SADEN]= 0;
65 }
66
67
68 /*
69  * Copying ERAM to XRAM and vice versa
70  *
71  * This two methods are used by command interpreter to make ERAM and
72  * beginning of XRAM to be equivalent.
73  */
74
75 void
76 t_uc51r::eram2xram(void)
77 {
78   int i;
79
80   for (i= 0; i < ERAM_SIZE; i++)
81     set_mem(MEM_XRAM, i, ERAM[i]);
82 }
83
84 void
85 t_uc51r::xram2eram(void)
86 {
87   int i;
88
89   for (i= 0; i < ERAM_SIZE; i++)
90     ERAM[i]= get_mem(MEM_XRAM, i);
91 }
92
93
94 /*
95  * Processing write operation of SFR
96  *
97  * Inherited method is extended with WDT handling.
98  */
99
100 void
101 t_uc51r::proc_write(uchar *addr)
102 {
103   t_uc52::proc_write(addr);
104   // Handling WDT
105   if (addr == &(MEM(MEM_SFR)[WDTRST]))
106     {
107       if ((wdtrst == 0x1e) &&
108           (*addr == 0xe1))
109         {
110           WDT= 0;
111           sim->cmd->debug("%g sec (%d tick): Watchdog timer enabled/reset"
112                           " PC= 0x%06x\n",
113                           get_rtime(), ticks->ticks, PC);
114         }
115       wdtrst= *addr;
116     }
117 }
118
119
120 /*
121  * Simulating timers
122  *
123  * Calling inherited method to simulate timer #0 and #1 and then 
124  * simulating timer #2.
125  */
126
127 int
128 t_uc51r::do_timers(int cycles)
129 {
130   int res;
131
132   if ((res= t_uc51::do_timers(cycles)) != resGO)
133     return(res);
134   return(do_timer2(cycles));
135 }
136
137
138 /*
139  * Simulating timer 2
140  *
141  * It is something wrong: T2MOD is not implemented in 52?!
142  */
143
144 int
145 t_uc51r::do_timer2(int cycles)
146 {
147   bool nocount= DD_FALSE;
148   uint t2mod= get_mem(MEM_SFR, T2MOD);
149   uint t2con= get_mem(MEM_SFR, T2CON);
150   uint p1= get_mem(MEM_SFR, P1);
151
152   exf2it->activate();
153   if (!(t2con & bmTR2))
154     /* Timer OFF */
155     return(resGO);
156
157   if (t2mod & bmT2OE)
158     return(do_t2_clockout(cycles));
159
160   if (t2con & (bmRCLK | bmTCLK))
161     return(do_t2_baud(cycles));
162
163   /* Determining nr of input clocks */
164   if (!(t2con & bmTR2))
165     nocount= DD_TRUE; // Timer OFF
166   else
167     if (t2con & bmC_T2)
168       {
169         // Counter mode, falling edge on P1.0 (T2)
170         if ((prev_p1 & bmT2) &&
171             !(p1 & port_pins[1] & bmT2))
172           cycles= 1;
173         else
174           nocount= DD_TRUE;
175       }
176   /* Counting */
177   while (cycles--)
178     {
179       if (t2con & bmCP_RL2)
180         do_t2_capture(&cycles, nocount);
181       else
182         {
183           int overflow;
184           overflow= 0;
185           /* Auto-Relode mode */
186           if (t2mod & bmDCEN)
187             {
188               /* DCEN= 1 */
189               exf2it->deactivate();
190               if (nocount)
191                 cycles= 0;
192               else
193                 {
194                   if (p1 & port_pins[1] & bmT2EX)
195                     {
196                       // UP
197                       if (!++(MEM(MEM_SFR)[TL2]))
198                         if (!++(MEM(MEM_SFR)[TH2]))
199                           {
200                             overflow++;
201                             MEM(MEM_SFR)[TH2]= MEM(MEM_SFR)[RCAP2H];
202                             MEM(MEM_SFR)[TL2]= MEM(MEM_SFR)[RCAP2L];
203                             mem(MEM_SFR)->set_bit1(T2CON, bmTF2);
204                           }
205                     }
206                   else
207                     {
208                       // DOWN
209                       MEM(MEM_SFR)[TL2]--;
210                       if (MEM(MEM_SFR)[TL2] == 0xff)
211                           MEM(MEM_SFR)[TH2]--;
212                       if (MEM(MEM_SFR)[TH2] == MEM(MEM_SFR)[RCAP2H] &&
213                           MEM(MEM_SFR)[TL2] == MEM(MEM_SFR)[RCAP2L])
214                         {
215                           overflow++;
216                           MEM(MEM_SFR)[TH2]= MEM(MEM_SFR)[TL2]= 0xff;
217                           mem(MEM_SFR)->set_bit1(T2CON, bmTF2);
218                         }
219                     }
220                   while (overflow--)
221                     MEM(MEM_SFR)[P1]^= bmEXF2;
222                 }
223             }
224           else
225             /* DCEN= 0 */
226             do_t2_reload(&cycles, nocount);
227         }
228     }// while cycles
229
230   return(resGO);
231 }
232
233
234 /*
235  * Clock out mode of Timer #2
236  */
237
238 int
239 t_uc51r::do_t2_clockout(int cycles)
240 {
241   uint t2con= get_mem(MEM_SFR, T2CON);
242   uint p1= get_mem(MEM_SFR, P1);
243
244   /* Programmable Clock Out Mode */
245   if ((prev_p1 & bmT2EX) &&
246       !(p1 & port_pins[1] & bmT2EX) &&
247       (t2con & bmEXEN2))
248     mem(MEM_SFR)->set_bit1(T2CON, bmEXF2);
249   if (t2con & bmCP_RL2)
250     return(resGO);
251   if (t2con & bmC_T2)
252     {
253       if ((prev_p1 & bmT2) &&
254           !(p1 & port_pins[1] & bmT2))
255         cycles= 1;
256       else
257         cycles= 0;
258     }
259   else
260     cycles*= 6;
261   if (t2con & bmTR2)
262     while (cycles--)
263       {
264         if (!++(MEM(MEM_SFR)[TL2]))
265           if (!++(MEM(MEM_SFR)[TH2]))
266             {
267               MEM(MEM_SFR)[TH2]= MEM(MEM_SFR)[RCAP2H];
268               MEM(MEM_SFR)[TL2]= MEM(MEM_SFR)[RCAP2L];
269               clock_out++;
270               if (!(t2con & bmC_T2))
271                 {
272                   SET_BIT((clock_out&1), P1, bmT2);
273                 }
274             }
275       }
276   return(resGO);
277 }
278
279
280 /*
281  * Handling serial line
282  */
283
284 int
285 t_uc51r::serial_bit_cnt(int mode)
286 {
287   int divby= 12;
288   int *tr_src= 0, *rec_src= 0;
289
290   switch (mode)
291     {
292     case 0:
293       divby  = 12;
294       tr_src = &s_tr_tick;
295       rec_src= &s_rec_tick;
296       break;
297     case 1:
298     case 3:
299       divby  = (get_mem(MEM_SFR, PCON)&bmSMOD)?16:32;
300       tr_src = (get_mem(MEM_SFR, T2CON)&bmTCLK)?(&s_tr_t2):(&s_tr_t1);
301       rec_src= (get_mem(MEM_SFR, T2CON)&bmTCLK)?(&s_rec_t2):(&s_rec_t1);
302       break;
303     case 2:
304       divby  = (get_mem(MEM_SFR, PCON)&bmSMOD)?16:32;
305       tr_src = &s_tr_tick;
306       rec_src= &s_rec_tick;
307       break;
308     }
309   if (s_sending)
310     {
311       while (*tr_src >= divby)
312         {
313           (*tr_src)-= divby;
314           s_tr_bit++;
315         }
316     }
317   if (s_receiving)
318     {
319       while (*rec_src >= divby)
320         {
321           (*rec_src)-= divby;
322           s_rec_bit++;
323         }
324     }
325   return(0);
326 }
327
328 void
329 t_uc51r::received(int c)
330 {
331   uint br= get_mem(MEM_SFR, SADDR) | get_mem(MEM_SFR, SADEN);
332   int scon= get_mem(MEM_SFR, SCON);
333
334   if ((0 < scon >> 6) &&
335       (scon & bmSM2))
336     {
337       if (
338           /* Check for individual address */
339           ((get_mem(MEM_SFR, SADDR) & get_mem(MEM_SFR, SADEN)) ==
340           (c & get_mem(MEM_SFR, SADEN)))
341           ||
342           /* Check for broadcast address */
343           (br == (br & c))
344           )
345         mem(MEM_SFR)->set_bit1(SCON, bmRI);
346       return;
347     }
348   mem(MEM_SFR)->set_bit1(SCON, bmRI);
349 }
350
351
352 /*
353  * Handling WDT
354  */
355
356 int
357 t_uc51r::do_wdt(int cycles)
358 {
359   if (WDT >= 0)
360     {
361       WDT+= cycles;
362 fprintf(stderr,"WDT=%d\n",WDT);
363       if (WDT & ~(0x3fff))
364         {
365           sim->cmd->debug("%g sec (%d ticks): "
366                           "Watchdog timer resets the CPU, PC= 0x%06x\n",
367                           get_rtime(), ticks->ticks, PC);
368           reset();
369           return(resWDTRESET);
370         }
371     }
372   return(resGO);
373 }
374
375
376 /*
377  * 0xe0 1 24 MOVX A,@DPTR
378  *____________________________________________________________________________
379  *
380  */
381
382 int
383 t_uc51r::inst_movx_a_$dptr(uchar code)
384 {
385   if ((get_mem(MEM_SFR, AUXR) & bmEXTRAM) ||
386       MEM(MEM_SFR)[DPH])
387     MEM(MEM_SFR)[event_at.ws= ACC]= read_mem(MEM_XRAM,
388                                              event_at.rx=
389                                              MEM(MEM_SFR)[DPH]*256+
390                                              MEM(MEM_SFR)[DPL]);
391   else
392     MEM(MEM_SFR)[event_at.ws= ACC]= ERAM[event_at.rx= MEM(MEM_SFR)[DPL]];
393   tick(1);
394   return(resGO);
395 }
396
397
398 /*
399  * 0xe2-0xe3 1 24 MOVX A,@Ri
400  *____________________________________________________________________________
401  *
402  */
403
404 int
405 t_uc51r::inst_movx_a_$ri(uchar code)
406 {
407   uchar *addr;
408   int res;
409
410   addr= get_indirect(*(get_reg(code & 0x01)), &res);
411   if (get_mem(MEM_SFR, AUXR) & bmEXTRAM)
412     MEM(MEM_SFR)[event_at.ws= ACC]=
413       read_mem(MEM_XRAM,
414                event_at.rx= (MEM(MEM_SFR)[P2]&port_pins[2])*256+*addr);
415   else
416     MEM(MEM_SFR)[event_at.ws= ACC]= ERAM[event_at.rx= *addr];
417   tick(1);
418   return(res);
419 }
420
421
422 /*
423  * 0xf0 1 24 MOVX @DPTR,A
424  *____________________________________________________________________________
425  *
426  */
427
428 int
429 t_uc51r::inst_movx_$dptr_a(uchar code)
430 {
431   if ((get_mem(MEM_SFR, AUXR) & bmEXTRAM) ||
432       MEM(MEM_SFR)[DPH])
433     write_mem(MEM_XRAM,
434               event_at.wx= MEM(MEM_SFR)[DPH]*256+MEM(MEM_SFR)[DPL],
435               MEM(MEM_SFR)[event_at.rs= ACC]);
436   else
437     ERAM[event_at.wx= MEM(MEM_SFR)[DPL]]= MEM(MEM_SFR)[event_at.rs= ACC];
438   return(resGO);
439 }
440
441
442 /*
443  * 0xf2-0xf3 1 24 MOVX @Ri,A
444  *____________________________________________________________________________
445  *
446  */
447
448 int
449 t_uc51r::inst_movx_$ri_a(uchar code)
450 {
451   uchar *addr;
452   int res;
453
454   addr= get_indirect(event_at.wi= *(get_reg(code & 0x01)), &res);
455   if (get_mem(MEM_SFR, AUXR) & bmEXTRAM)
456     write_mem(MEM_XRAM,
457               event_at.wx= (MEM(MEM_SFR)[P2] & port_pins[2])*256 + *addr,
458               MEM(MEM_SFR)[ACC]);
459   else
460     ERAM[event_at.wx= *addr]= MEM(MEM_SFR)[ACC];
461   tick(1);
462   return(res);
463 }
464
465
466 /* End of s51.src/uc51r.cc */