version 0.5.2
[fw/sdcc] / sim / ucsim / s51.src / timer0.cc
1 /*
2  * Simulator of microcontrollers (timer0.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 "timer0cl.h"
29 #include "regs51.h"
30 #include "types51.h"
31
32
33 cl_timer0::cl_timer0(class cl_uc *auc, int aid, char *aid_string):
34   cl_hw(auc, HW_TIMER, aid, aid_string)
35 {
36   cell_tmod= cell_tcon= 0;
37   if (aid == 0)
38     {
39       mask_M0  = bmM00;
40       mask_M1  = bmM10;
41       mask_C_T = bmC_T0;
42       mask_GATE= bmGATE0;
43       mask_TR  = bmTR0;
44       mask_INT = bm_INT0;
45       mask_TF  = bmTF0;
46       mask_T   = bmT0;
47       addr_tl  = TL0;
48       addr_th  = TH0;
49     }
50   else if (aid == 1)
51     {
52       mask_M0  = bmM01;
53       mask_M1  = bmM11;
54       mask_C_T = bmC_T1;
55       mask_GATE= bmGATE1;
56       mask_TR  = bmTR1;
57       mask_INT = bm_INT1;
58       mask_TF  = bmTF1;
59       mask_T   = bmT1;
60       addr_tl  = TL1;
61       addr_th  = TH1;
62     }
63   else if (aid == 2)
64     {
65       addr_tl  = TL2;
66       addr_th  = TH2;
67       mask_T   = bmT2;
68       mask_C_T = bmC_T2;
69       mask_TR  = bmTR2;
70       mask_TF  = bmTF2;
71       mask_M0= mask_M1= mask_GATE= mask_INT= 0;
72     }
73   else {}
74   make_partner(HW_PCA, 0);
75   make_partner(HW_PCA, 1);
76   make_partner(HW_PCA, 2);
77   make_partner(HW_PCA, 3);
78   make_partner(HW_PCA, 4);
79 }
80
81 int
82 cl_timer0::init(void)
83 {
84   class cl_address_space *sfr= uc->address_space(MEM_SFR_ID);
85
86   if (sfr)
87     {
88       //t_mem d;
89       if (id == 0 || id == 1)
90         {
91           //cell_tmod= sfr->register_hw(TMOD, this, 0);
92           register_cell(sfr, TMOD, &cell_tmod, wtd_restore_write);
93           //d= cell_tmod->get(); write(cell_tmod, &d);
94           //cell_tcon= sfr->register_hw(TCON, this, 0);
95           register_cell(sfr, TCON, &cell_tcon, wtd_restore_write);
96           //d= cell_tcon->get(); write(cell_tcon, &d);
97           INT= sfr->read(P3) & mask_INT;
98         }
99       else if (id == 2)
100         {
101           cell_tmod= 0;
102           //cell_tcon= sfr->register_hw(T2CON, this, 0);
103           register_cell(sfr, T2CON, &cell_tcon, wtd_restore_write);
104           //d= cell_tcon->get(); write(cell_tcon, &d);
105         }
106       //cell_tl= sfr->get_cell(addr_tl);
107       //cell_th= sfr->get_cell(addr_th);
108       use_cell(sfr, addr_tl, &cell_tl, wtd_restore);
109       use_cell(sfr, addr_th, &cell_th, wtd_restore);
110     }
111   return(0);
112 }
113
114 void
115 cl_timer0::added_to_uc(void)
116 {
117   if (id == 0)
118     uc->it_sources->add(new cl_it_src(bmET0, TCON, bmTF0, 0x000b, true,
119                                       "timer #0", 2));
120   else if (id == 1)
121     uc->it_sources->add(new cl_it_src(bmET1, TCON, bmTF1, 0x001b, true,
122                                       "timer #1", 4));
123 }
124
125 /*t_mem
126 cl_timer0::read(class cl_cell *cell)
127 {
128   return(cell->get());
129 }*/
130
131 void
132 cl_timer0::write(class cl_memory_cell *cell, t_mem *val)
133 {
134   if (cell == cell_tmod)
135     {
136       t_mem md= *val & (mask_M0|mask_M1);
137       if (md == mask_M0)
138         mode= 1;
139       else if (md == mask_M1)
140         mode= 2;
141       else if (md == (mask_M0|mask_M1))
142         mode= 3;
143       else
144         mode= 0;
145       GATE= *val & mask_GATE;
146       C_T = *val & mask_C_T;
147       T_edge= 0;
148     }
149   else if (cell == cell_tcon)
150     {
151       TR= *val & mask_TR;
152       T_edge= 0;
153     }
154 }
155
156 /*void
157 cl_timer0::mem_cell_changed(class cl_m *mem, t_addr addr)
158 {
159   //class cl_m *sfr= uc->mem(MEM_SFR);
160   //t_mem d;
161
162   cl_hw::mem_cell_changed(mem, addr);
163
164   //d= cell_tmod->get();
165   //write(cell_tmod, &d);
166   //d= cell_tcon->get();
167   //write(cell_tcon, &d);
168   //if (addr == addr_tl) cell_tl= sfr->get_cell(addr_tl);
169   //if (addr == addr_th) cell_th= sfr->get_cell(addr_th);
170 }*/
171
172 int
173 cl_timer0::tick(int cycles)
174 {
175   switch (mode)
176     {
177     case 0: do_mode0(cycles); break;
178     case 1: do_mode1(cycles); break;
179     case 2: do_mode2(cycles); break;
180     case 3: do_mode3(cycles); break;
181     }
182   return(resGO);
183 }
184
185 int
186 cl_timer0::do_mode0(int cycles)
187 {
188   if (!TR)
189     return(0);
190
191   //t_mem p3= uc->mem(MEM_SFR)->get(P3);
192   if (GATE)
193     {
194       if ((/*p3 & mask_*/INT) == 0)
195         return(0);
196     }
197
198   if (C_T)
199     {
200       /*cycles= 0;
201       if ((uc51->prev_p3 & mask_T) &&
202           !(p3 & uc51->port_pins[3] & mask_T))
203           cycles= 1;*/
204       cycles= T_edge;
205       T_edge= 0;
206     }
207   while (cycles--)
208     {
209       // mod 0, TH= 8 bit t/c, TL= 5 bit precounter
210       t_mem tl= cell_tl->add(1);
211       if ((tl & 0x1f) == 0)
212         {
213           cell_tl->set(0);
214           if (!cell_th->add(1))
215             {
216               cell_tcon->set_bit1(mask_TF);
217               overflow();
218             }
219         }
220     }
221
222   return(0);
223 }
224
225 int
226 cl_timer0::do_mode1(int cycles)
227 {
228   if (!TR)
229     return(0);
230
231   //t_mem p3= uc->mem(MEM_SFR)->get(P3);
232   if (GATE)
233     {
234       if ((/*p3 & mask_*/INT) == 0)
235         return(0);
236     }
237
238   if (C_T)
239     {
240       /*cycles= 0;
241       if ((uc51->prev_p3 & mask_T) &&
242           !(p3 & uc51->port_pins[3] & mask_T))
243           cycles= 1;*/
244       cycles= T_edge;
245       T_edge= 0;
246     }
247
248   while (cycles--)
249     {
250       // mod 1 TH+TL= 16 bit t/c
251       if (!cell_tl->add(1))
252         {
253           if (!cell_th->add(1))
254             {
255               cell_tcon->set_bit1(mask_TF);
256               overflow();
257             }
258         }
259     }
260
261   return(0);
262 }
263
264 int
265 cl_timer0::do_mode2(int cycles)
266 {
267   if (!TR)
268     return(0);
269
270   //t_mem p3= uc->mem(MEM_SFR)->get(P3);
271   if (GATE)
272     {
273       if ((/*p3 & mask_*/INT) == 0)
274         return(0);
275     }
276
277   if (C_T)
278     {
279       /*cycles= 0;
280       if ((uc51->prev_p3 & mask_T) &&
281           !(p3 & uc51->port_pins[3] & mask_T))
282           cycles= 1;*/
283       cycles= T_edge;
284       T_edge= 0;
285     }
286
287   //unsigned long startt= uc->ticks->ticks-(cycles*12);int i=0;
288   while (cycles--)
289     {
290       // mod 2 TL= 8 bit t/c auto reload from TH
291       if (!cell_tl->add(1))
292         {
293           cell_tl->set(cell_th->get());
294           cell_tcon->set_bit1(mask_TF);
295           //printf("timer%d overflow %d (%d) %d\n",id,uc->ticks->ticks,i,startt+(i*12));
296           overflow();
297         }
298       //i++;
299     }
300   return(0);
301 }
302
303 int
304 cl_timer0::do_mode3(int cycles)
305 {
306   int cyc= cycles;
307   //t_mem p3= uc->mem(MEM_SFR)->get(P3);
308
309   if (!TR)
310     goto do_th;
311
312   if (GATE)
313     {
314       if ((/*p3 & mask_*/INT) == 0)
315         goto do_th;
316     }
317
318   if (C_T)
319     {
320       /*cycles= 0;
321       if ((uc51->prev_p3 & mask_T) &&
322           !(p3 & uc51->port_pins[3] & mask_T))
323           cycles= 1;*/
324       cycles= T_edge;
325       T_edge= 0;
326     }
327
328   while (cycles--)
329     {
330       if (!cell_tl->add(1))
331         {
332           cell_tcon->set_bit1(mask_TF);
333           overflow();
334         }
335     }
336
337  do_th:
338   if ((cell_tcon->get() & bmTR1) != 0)
339     while (cyc--)
340       {
341         if (!cell_th->add(1))
342           cell_tcon->set_bit1(bmTF1);
343       }
344   return(0);
345 }
346
347 void
348 cl_timer0::overflow(void)
349 {
350   inform_partners(EV_OVERFLOW, 0);
351 }
352
353 void
354 cl_timer0::happen(class cl_hw *where, enum hw_event he, void *params)
355 {
356   struct ev_port_changed *ep= (struct ev_port_changed *)params;
357
358   if (where->cathegory == HW_PORT &&
359       he == EV_PORT_CHANGED &&
360       ep->id == 3)
361     {
362       t_mem p3n= ep->new_pins & ep->new_value;
363       t_mem p3o= ep->pins & ep->prev_value;
364       if ((p3n & mask_T) &&
365           !(p3o & mask_T))
366         T_edge++;
367       INT= p3n & mask_INT;
368       //printf("timer%d p%dchanged (%02x,%02x->%02x,%02x) INT=%d(%02x) edge=%d(%02x)\n",id,where->id,ep->prev_value,ep->pins,ep->new_value,ep->new_pins,INT,mask_INT,T_edge,mask_T);
369     }
370 }
371
372 void
373 cl_timer0::print_info(class cl_console *con)
374 {
375   char *modes[]= { "13 bit", "16 bit", "8 bit autoreload", "2x8 bit" };
376   //t_mem tmod= cell_tmod->get();
377   int on;
378   class cl_address_space *sfr= uc->address_space(MEM_SFR_ID);
379
380   con->dd_printf("%s[%d] 0x%04x", id_string, id,
381                  256*cell_th->get()+cell_tl->get());
382   //int mode= tmod & (bmM00|bmM10);
383   con->dd_printf(" %s", modes[mode]);
384   con->dd_printf(" %s", (/*tmod&bm*/C_T/*0*/)?"counter":"timer");
385   if (/*tmod&bm*/GATE/*0*/)
386     {
387       con->dd_printf(" gated");
388       on= INT;
389     }
390   else
391     on= TR;
392   con->dd_printf(" %s", on?"ON":"OFF");
393   con->dd_printf(" irq=%c", (cell_tcon->get()&mask_TF)?'1':'0');
394   con->dd_printf(" %s", sfr?"?":((sfr->get(IE)&bmET0)?"en":"dis"));
395   con->dd_printf(" prio=%d", uc->it_priority(bmPT0));
396   con->dd_printf("\n");
397 }
398
399
400 /* End of s51.src/timer0.cc */