ea2ab95f23d162f073a02730deb1ef7f8c8b955f
[fw/sdcc] / sim / ucsim / s51.src / timer2.cc
1 /*
2  * Simulator of microcontrollers (timer2.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 "timer2cl.h"
29 #include "regs51.h"
30 #include "types51.h"
31
32
33 cl_timer2::cl_timer2(class cl_uc *auc, int aid, char *aid_string,
34                      int afeatures):
35   cl_timer0(auc, /*2*/aid, /*"timer2"*/aid_string)
36 {
37   features= afeatures;
38   exf2it= 0;
39   mask_RCLK= bmRCLK;
40   mask_TCLK= bmTCLK;
41   mask_CP_RL2= bmCP_RL2;
42   make_partner(HW_UART, 0);
43   if (features & (t2_down|t2_clock_out))
44     register_cell(uc->mem(MEM_SFR), T2MOD, &cell_t2mod, wtd_restore_write);
45 }
46
47 int
48 cl_timer2::init(void)
49 {
50   cl_timer0::init();
51   //cell_rcap2l= uc->mem(MEM_SFR)->get_cell(RCAP2L);
52   //cell_rcap2h= uc->mem(MEM_SFR)->get_cell(RCAP2H);
53   use_cell(uc->mem(MEM_SFR), RCAP2L, &cell_rcap2l, wtd_restore);
54   use_cell(uc->mem(MEM_SFR), RCAP2H, &cell_rcap2h, wtd_restore);
55   bit_t2ex= uc->read_mem(MEM_SFR, P1) & bmT2EX;
56   return(0);
57 }
58
59 void
60 cl_timer2::added_to_uc(void)
61 {
62   uc->it_sources->add(new cl_it_src(bmET2, T2CON, bmTF2, 0x002b, false,
63                                     "timer #2 TF2", 7));
64   exf2it= new cl_it_src(bmET2, T2CON, bmEXF2, 0x002b, false,
65                         "timer #2 EXF2", 7);
66   uc->it_sources->add(exf2it);
67 }
68
69 /*void
70 cl_timer2::mem_cell_changed(class cl_mem *mem, t_addr addr)
71 {
72   class cl_mem *sfr= uc->mem(MEM_SFR);
73   class cl_cell *c= 0;
74
75   if (mem && sfr && mem == sfr)
76     {
77       switch (addr)
78         {
79         case T2CON:
80           c= cell_tcon= sfr->get_cell(T2CON);
81           break;
82         }
83       if (c)
84         {
85           t_mem d= c->get();
86           write(c, &d);
87         }
88       if (addr == addr_tl)
89         cell_tl= sfr->get_cell(addr_tl);
90       if (addr == addr_th)
91         cell_th= sfr->get_cell(addr_th);
92       cell_rcap2l= sfr->get_cell(RCAP2L);
93       cell_rcap2h= sfr->get_cell(RCAP2H);
94     }
95 }*/
96
97 /*void
98 cl_timer2::added(class cl_hw *new_hw)
99 {
100   if (new_hw->cathegory == HW_UART)
101     hws_to_inform->add(new_hw);
102 }*/
103
104 void
105 cl_timer2::write(class cl_cell *cell, t_mem *val)
106 {
107   int oldmode= mode;
108   bool oldtr= TR;
109
110   if (exf2it)
111     exf2it->activate();
112   if (cell == cell_tcon)
113     {
114       C_T = *val & mask_C_T;
115       TR  = *val & mask_TR;
116       RCLK= *val & mask_RCLK;
117       TCLK= *val & mask_TCLK;
118       CP_RL2= *val & mask_CP_RL2;
119       EXEN2 = *val & bmEXEN2;
120       if (!(RCLK || TCLK) &&
121           !CP_RL2)
122         mode= T2MODE_RELOAD;
123       else if (!(RCLK || TCLK) &&
124                CP_RL2)
125         mode= T2MODE_CAPTURE;
126       else if (RCLK || TCLK)
127         mode= T2MODE_BAUDRATE;
128       else
129         mode= T2MODE_OFF;
130       if (mode != oldmode)
131         inform_partners(EV_T2_MODE_CHANGED, val);
132     }
133   else if (cell == cell_t2mod)
134     {
135       bit_dcen= (*val & bmDCEN) != 0;
136       bit_t2oe= (*val & bmT2OE) != 0;
137       if ((features & t2_down) &&
138           bit_dcen &&
139           mode == T2MODE_RELOAD)
140         {
141           mode= T2MODE_DOWN;
142           if (exf2it)
143             exf2it->deactivate();
144         }
145       if ((features & t2_clock_out) &&
146           bit_t2oe)
147         mode= T2MODE_CLKOUT;
148     }
149   if (mode != oldmode ||
150       TR && !oldtr ||
151       !TR && oldtr)
152     T_edge= t2ex_edge= 0;
153 }
154
155 int
156 cl_timer2::tick(int cycles)
157
158   switch (mode)
159     {
160     case T2MODE_BAUDRATE:
161       do_t2_baud(cycles);
162       break;
163     case T2MODE_CAPTURE:
164       do_t2_capture(cycles);
165       break;
166     case T2MODE_RELOAD:
167       do_t2_reload(cycles);
168       break;
169     case T2MODE_DOWN:
170       do_t2_down(cycles);
171       break;
172     case T2MODE_CLKOUT:
173       do_t2_clock_out(cycles);
174       break;
175     default: break;
176     }
177   
178   return(resGO);
179 }
180
181 /*
182  * Baud rate generator mode of Timer #2
183  */
184
185 int
186 cl_timer2::do_t2_baud(int cycles)
187 {
188   if (EXEN2 && t2ex_edge)
189     {
190       cell_tcon->set_bit1(bmEXF2);
191       t2ex_edge= 0;
192     }
193
194   if (!TR)
195     return(0);
196
197   if (C_T)
198     (cycles= T_edge), T_edge= 0;
199   else
200     cycles*= 6;
201
202   while (cycles--)
203     {
204       if (!cell_tl->add(1))
205         if (!cell_th->add(1))
206           {
207             cell_th->set(cell_rcap2h->get());
208             cell_tl->set(cell_rcap2l->get());
209             inform_partners(EV_OVERFLOW, 0);
210           }
211     }
212   return(resGO);
213 }
214
215
216 /*
217  * Capture function of Timer #2
218  */
219
220 void
221 cl_timer2::do_t2_capture(int cycles)
222 {
223   if (EXEN2 && t2ex_edge)
224     {
225       cell_tcon->set_bit1(bmEXF2);
226       cell_rcap2h->set(cell_th->get());
227       cell_rcap2l->set(cell_tl->get());
228       t2ex_edge= 0;
229     }
230
231   if (!TR)
232     return;
233
234   if (C_T)
235     (cycles= T_edge), T_edge= 0;
236
237   if (!cell_tl->add(1))
238     {
239       if (!cell_th->add(1))
240         cell_tcon->set_bit1(bmTF2);
241     }
242 }
243
244
245 /*
246  * Auto Reload mode of Timer #2, counting UP
247  */
248
249 void
250 cl_timer2::do_t2_reload(int cycles)
251 {
252   if (EXEN2 && t2ex_edge)
253     {
254       cell_tcon->set_bit1(bmEXF2);
255       cell_th->set(cell_rcap2h->get());
256       cell_tl->set(cell_rcap2l->get());
257       t2ex_edge= 0;
258     }
259
260   if (!TR)
261     return;
262
263   if (C_T)
264     (cycles= T_edge), T_edge= 0;
265
266   if (!cell_tl->add(1))
267     {
268       if (!cell_th->add(1))
269         {
270           cell_tcon->set_bit1(mask_TF);
271           cell_th->set(cell_rcap2h->get());
272           cell_tl->set(cell_rcap2l->get());
273         }
274     }
275 }
276
277 void
278 cl_timer2::do_t2_down(int cycles)
279 {
280   bool toggle= DD_FALSE;
281
282   if (!TR)
283     return;
284
285   if (C_T)
286     (cycles= T_edge), T_edge= 0;
287
288   if (bit_t2ex)
289     // UP
290     while (cycles--)
291       if (!cell_tl->add(1))
292         {
293           if (!cell_th->add(1))
294             {
295               cell_tcon->set_bit1(mask_TF);
296               cell_th->set(cell_rcap2h->get());
297               cell_tl->set(cell_rcap2l->get());
298               toggle= DD_TRUE;
299             }
300         }
301   else
302     // DOWN
303     while (cycles--)
304       {
305         t_mem l, h;
306         if ((l= cell_tl->add(-1)) == 0xff)
307           h= cell_th->add(-1);
308         else
309           h= cell_th->get();
310         if ((TYPE_UWORD)(h*256+l) <
311             (TYPE_UWORD)(cell_rcap2h->get()*256+cell_rcap2l->get()))
312           {
313             cell_tcon->set_bit1(mask_TF);
314             cell_th->set(0xff);
315             cell_tl->set(0xff);
316             toggle= DD_TRUE;
317           }
318       }
319   if (toggle)
320     {
321       class cl_cell *p1= uc->mem(MEM_SFR)->get_cell(P1);
322       p1->set(p1->get() ^ bmEXF2);
323     }
324 }
325
326 void
327 cl_timer2::do_t2_clock_out(int cycles)
328 {
329   if (EXEN2 && t2ex_edge)
330     {
331       cell_tcon->set_bit1(bmEXF2);
332       t2ex_edge= 0;
333     }
334
335   if (!TR)
336     return;
337
338   if (C_T)
339     (cycles= T_edge), T_edge= 0;
340   else
341     cycles*= 6;
342
343   while (cycles--)
344     {
345       if (!cell_tl->add(1))
346         if (!cell_th->add(1))
347           {
348             cell_th->set(cell_rcap2h->get());
349             cell_tl->set(cell_rcap2l->get());
350             inform_partners(EV_OVERFLOW, 0);
351             if (!C_T)
352               {
353                 // toggle T2 on P1
354                 class cl_cell *p1= uc->mem(MEM_SFR)->get_cell(P1);
355                 p1->set(p1->get() ^ bmT2);
356               }
357           }
358     }
359 }
360
361 void
362 cl_timer2::happen(class cl_hw *where, enum hw_event he, void *params)
363 {
364   struct ev_port_changed *ep= (struct ev_port_changed *)params;
365
366   if (where->cathegory == HW_PORT &&
367       he == EV_PORT_CHANGED &&
368       ep->id == 1)
369     {
370       t_mem p1n= ep->new_pins & ep->new_value;
371       t_mem p1o= ep->pins & ep->prev_value;
372       if (!(p1n & mask_T) &&
373           (p1o & mask_T))
374         T_edge++;
375       if (!(p1n & bmT2EX) &&
376           (p1o & bmT2EX))
377         t2ex_edge++;
378       bit_t2ex= p1n & bmT2EX;
379     }
380 }
381
382 void
383 cl_timer2::print_info(class cl_console *con)
384 {
385   int t2con= cell_tcon->get();
386
387   con->dd_printf("%s[%d] 0x%04x", id_string, id,
388                  256*cell_th->get()+cell_tl->get());
389   if (RCLK || TCLK)
390     {
391       con->dd_printf(" baud");
392       if (RCLK)
393         con->dd_printf(" RCLK");
394       if (TCLK)
395         con->dd_printf(" TCLK");
396     }
397   else
398     con->dd_printf(" %s", (CP_RL2)?"capture":"reload");
399   con->dd_printf(" 0x%04x",
400                  256*cell_rcap2h->get()+cell_rcap2l->get());
401   con->dd_printf(" %s", (C_T)?"counter":"timer");
402   con->dd_printf(" %s", (TR)?"ON":"OFF");
403   con->dd_printf(" irq=%c", (t2con&bmTF2)?'1':'0');
404   con->dd_printf(" %s", (uc->get_mem(MEM_SFR, IE)&bmET2)?"en":"dis");
405   con->dd_printf(" prio=%d", uc->it_priority(bmPT2));
406   con->dd_printf("\n");
407 }
408
409
410 /* End of s51.src/timer2.cc */