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