Imported Upstream version 2.9.0
[debian/cc1111] / sim / ucsim / s51.src / pca.cc
1 /*
2  * Simulator of microcontrollers (pca.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 <ctype.h>
29
30 // sim.src
31 #include "itsrccl.h"
32
33 // local
34 #include "pcacl.h"
35 #include "regs51.h"
36 #include "types51.h"
37
38
39 cl_pca::cl_pca(class cl_uc *auc, int aid):
40   cl_hw(auc, HW_PCA, aid, "pca")
41 {
42   t0_overflows= ECI_edge= 0;
43   int i;
44   for (i= 0; i < 5; cex_pos[i]= cex_neg[i]= DD_FALSE, i++) ;
45 }
46
47 int
48 cl_pca::init(void)
49 {
50   sfr= uc->address_space(MEM_SFR_ID);
51   //t_addr CCAPL[5]= {CCAPL[0], CCAPL[1], CCAPL[2], CCAPL[3], CCAPL[4]};
52   //t_addr CCAPH[5]= {CCAPH[0], CCAPH[1], CCAPH[2], CCAPH[3], CCAPH[4]};
53   //t_addr CCAPM[5]= {CCAPM[0], CCAPM[1], CCAPM[2], CCAPM[3], CCAPM[4]};
54   t_addr CCAPL[5]= {CCAP0L, CCAP1L, CCAP2L, CCAP3L, CCAP4L};
55   t_addr CCAPH[5]= {CCAP0H, CCAP1H, CCAP2H, CCAP3H, CCAP4H};
56   t_addr CCAPM[5]= {CCAPM0, CCAPM1, CCAPM2, CCAPM3, CCAPM4};
57   int i;
58
59   if (!sfr)
60     {
61       fprintf(stderr, "No SFR to register PCA[%d] into\n", id);
62     }
63   register_cell(sfr, CMOD, &cell_cmod, wtd_restore_write);
64   register_cell(sfr, CCON, &cell_ccon, wtd_restore_write);
65   for (i= 0; i < 5; i++)
66     {
67       use_cell(sfr, CCAPL[i], &cell_ccapl[i], wtd_restore);
68       use_cell(sfr, CCAPH[i], &cell_ccaph[i], wtd_restore);
69       register_cell(sfr, CCAPM[i], &cell_ccapm[i], wtd_restore_write);
70     }
71   use_cell(sfr, CL, &cell_cl, wtd_restore);
72   use_cell(sfr, CH, &cell_ch, wtd_restore);
73   return(0);
74 }
75
76 void
77 cl_pca::added_to_uc(void)
78 {
79   uc->it_sources->add_at(4, new cl_it_src(bmEC, CCON, bmCCF4, 0x0033, false,
80                                           "PCA module #4", 5));
81   uc->it_sources->add_at(4, new cl_it_src(bmEC, CCON, bmCCF3, 0x0033, false,
82                                           "PCA module #3", 5));
83   uc->it_sources->add_at(4, new cl_it_src(bmEC, CCON, bmCCF2, 0x0033, false,
84                                           "PCA module #2", 5));
85   uc->it_sources->add_at(4, new cl_it_src(bmEC, CCON, bmCCF1, 0x0033, false,
86                                           "PCA module #1", 5));
87   uc->it_sources->add_at(4, new cl_it_src(bmEC, CCON, bmCCF0, 0x0033, false,
88                                           "PCA module #0", 5));
89   uc->it_sources->add_at(4, new cl_it_src(bmEC, CCON, bmCF, 0x0033, false,
90                                           "PCA counter", 5));
91 }
92
93 void
94 cl_pca::write(class cl_memory_cell *cell, t_mem *val)
95 {
96   //uchar bmCEX[5]= {bmCEX0, bmCEX1, bmCEX2, bmCEX3, bmCEX4};
97   //uchar bmCCF[5]= {bmCCF0, bmCCF1, bmCCF2, bmCCF3, bmCCF4};
98
99   if (cell == cell_cmod)
100     {
101       bit_CIDL= *val & bmCIDL;
102       bit_WDTE= *val & bmWDTE;
103       bit_ECF = *val & bmECF;
104       t_mem o= clk_source;
105       if ((clk_source= *val & (bmCPS1|bmCPS0)) != o)
106         t0_overflows= ECI_edge= 0;
107     }
108   else if (cell == cell_ccon)
109     {
110       bit_CR= *val & bmCR;
111     }
112   else
113     {
114       int i;
115       for (i= 0; i < 5; i++)
116         {
117           if (cell == cell_ccapm[i])
118             {
119               t_mem o= ccapm[i];
120               ccapm[i]= *val & 0xff;
121               if (o != ccapm[i])
122                 cex_neg[i]= cex_pos[i]= DD_FALSE;
123             }
124           else
125             {
126               if (ccapm[i] & (bmMAT|bmTOG))
127               {
128                 if (cell == cell_ccapl[i])
129                   {
130                     cell_ccapm[i]->set_bit0(bmECOM);
131                     ccapm[i]= cell_ccapm[i]->get();
132                   }
133                 else if (cell == cell_ccaph[i])
134                   {
135                     cell_ccapm[i]->set_bit1(bmECOM);
136                     ccapm[i]= cell_ccapm[i]->get();
137                   }
138               }
139             }
140         }
141     }
142 }
143
144 /*void
145 cl_pca::mem_cell_changed(class cl_m *mem, t_addr addr)
146 {
147   class cl_m *sfr= uc->mem(MEM_SFR);
148
149   if (mem && sfr && mem == sfr)
150     {
151       if (addr == addr_ccapXl)
152         ccapXl= sfr->get_cell(addr_ccapXl);
153       else if (addr == addr_ccapXh)
154         ccapXh= sfr->get_cell(addr_ccapXh);
155       else if (addr == addr_ccapmX)
156         ccapmX= sfr->get_cell(addr_ccapmX);
157     }
158 }*/
159
160 int
161 cl_pca::tick(int cycles)
162 {
163   int ret= resGO;
164
165   if (!bit_CR)
166     return(resGO);
167   if (uc->state == stIDLE &&
168       bit_CIDL)
169     return(resGO);
170
171   switch (clk_source)
172     {
173     case 0:
174       do_pca_counter(cycles);
175       break;
176     case bmCPS0:
177       do_pca_counter(cycles*3);
178       break;
179     case bmCPS1:
180       do_pca_counter(t0_overflows);
181       t0_overflows= 0;
182       break;
183     case (bmCPS0|bmCPS1):
184       do_pca_counter(ECI_edge);
185       ECI_edge= 0;
186       break;
187     }
188   return(ret);
189 }
190
191 void
192 cl_pca::do_pca_counter(int cycles)
193 {
194   //class cl_m *sfr= uc->mem(MEM_SFR);
195
196   while (cycles--)
197     {
198       if (cell_cl->add(1) == 0)
199         {
200           int i;
201           for (i= 0; i < 5; i++)
202             if (ccapm[i] & bmPWM)
203               cell_ccapl[i]->set(cell_ccaph[i]->get());
204           if (cell_ch->add(1) == 0)
205             {
206               // CH,CL overflow
207               cell_ccon->set_bit1(bmCF);
208               do_pca_module(0);
209               do_pca_module(1);
210               do_pca_module(2);
211               do_pca_module(3);
212               do_pca_module(4);
213             }
214         }
215     }
216 }
217
218 void
219 cl_pca::do_pca_module(int nr)
220 {
221   uchar bmCEX[5]= {bmCEX0, bmCEX1, bmCEX2, bmCEX3, bmCEX4};
222   uchar bmCCF[5]= {bmCCF0, bmCCF1, bmCCF2, bmCCF3, bmCCF4};
223   //uint p1= sfr->get(P1);
224
225   bool capture= DD_FALSE;
226   if ((ccapm[nr] & bmCAPP) &&
227       cex_pos[nr])
228     {
229       capture= DD_TRUE;
230       cex_pos[nr]= DD_FALSE;
231     }
232   if ((ccapm[nr] & bmCAPN) &&
233       cex_neg[nr])
234     {
235       capture= DD_TRUE;
236       cex_pos[nr]= DD_FALSE;
237     }
238   if (capture)
239     {
240       // Capture
241       cell_ccapl[nr]->set(cell_cl->get());
242       cell_ccaph[nr]->set(cell_ch->get());
243       cell_ccon->set_bit1(bmCCF[nr]);
244     }
245
246   if (ccapm[nr] & bmECOM)
247     {
248       // Comparator enabled
249       if (cell_cl->get() == cell_ccapl[nr]->get() &&
250           cell_ch->get() == cell_ccaph[nr]->get())
251         {
252           // Match
253           if (nr == 4 &&
254               (bit_WDTE))
255             {
256               reset();
257               return;
258             }
259           cell_ccon->set_bit1(bmCCF[nr]);
260           if (ccapm[nr] & bmTOG)
261             {
262               // Toggle
263               sfr->set(P1, sfr->get(P1) ^ bmCEX[nr]);
264             }
265         }
266       if (ccapm[nr] & bmPWM)
267         {
268           // PWM
269           /*if (cell_cl->get() == 0)
270             cell_ccapl[nr]->set(cell_ccaph[nr]->get());*/
271           if (cell_cl->get() < cell_ccapl[nr]->get())
272             //sfr->set(P1, sfr->get(P1) & ~(bmCEX[nr]));
273             sfr->set_bit1(P1, bmCEX[nr]);
274           else
275             sfr->set_bit1(P1, bmCEX[nr]);
276         }
277     }
278 }
279
280 void
281 cl_pca::reset(void)
282 {
283   t0_overflows= ECI_edge= 0;
284   int i;
285   for (i= 0; i < 5; cex_pos[i]= cex_neg[i]= DD_FALSE, i++) ;
286 }
287
288 void
289 cl_pca::happen(class cl_hw *where, enum hw_event he, void *params)
290 {
291   struct ev_port_changed *ep= (struct ev_port_changed *)params;
292   uchar bmCEX[5]= {bmCEX0, bmCEX1, bmCEX2, bmCEX3, bmCEX4};
293
294   if (where->cathegory == HW_PORT &&
295       he == EV_PORT_CHANGED &&
296       ep->id == 1)
297     {
298       t_mem p1n= ep->new_pins & ep->new_value;
299       t_mem p1o= ep->pins & ep->prev_value;
300       if (!(p1n & bmECI) &&
301           (p1o & bmECI))
302         ECI_edge++;
303       int i;
304       for (i= 0; i < 5; i++)
305         {
306           if (!(p1n & bmCEX[i]) &&
307               (p1o & bmCEX[i]))
308             cex_neg[i]= DD_TRUE;
309           else if ((p1n & bmCEX[i]) &&
310                    !(p1o & bmCEX[i]))
311             cex_pos[i]= DD_TRUE;
312         }
313     }
314   else if (where->cathegory == HW_TIMER &&
315            he == EV_OVERFLOW &&
316            where->id == 0)
317     {
318       t0_overflows++;
319     }
320 }
321
322
323 void
324 cl_pca::print_info(class cl_console_base *con)
325 {
326   con->dd_printf("%s[%d] FIXME\n", id_string, id);
327 }
328
329
330 /* End of s51.src/pca.cc */