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