1 /*
2  * Simulator of microcontrollers (serial.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 "ddconfig.h"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <sys/time.h>
36 #include <strings.h>
37 
38 // prj
39 #include "globals.h"
40 #include "utils.h"
41 
42 // cmd
43 #include "cmdutil.h"
44 
45 // local
46 #include "serialcl.h"
47 #include "regs51.h"
48 #include "uc51cl.h"
49 
50 
cl_serial(class cl_uc * auc)51 cl_serial::cl_serial(class cl_uc *auc):
52   cl_serial_hw(auc, 0, "uart")
53 {
54 }
55 
~cl_serial(void)56 cl_serial::~cl_serial(void)
57 {
58 }
59 
60 int
init(void)61 cl_serial::init(void)
62 {
63   set_name("mcs51_uart");
64   cl_serial_hw::init();
65   sfr= uc->address_space(MEM_SFR_ID);
66   bas= uc->address_space("bits");
67   if (sfr)
68     {
69       sbuf= register_cell(sfr, SBUF);
70       pcon= register_cell(sfr, PCON);
71       scon= register_cell(sfr, SCON);
72     }
73   int i;
74   for (i= 0; i < 8; i++)
75     {
76       scon_bits[i]= register_cell(bas, SCON+i);
77     }
78 
79   class cl_hw *t2= uc->get_hw(HW_TIMER, 2, 0);
80   if ((there_is_t2= t2 != 0))
81     {
82       t_mem d= sfr->get(T2CON);
83       t2_baud= d & (bmRCLK | bmTCLK);
84     }
85   else
86     t2_baud= false;
87   /*
88   cl_var *v;
89   chars pn(id_string);
90   pn.append("%d_", id);
91   uc->vars->add(v= new cl_var(pn+chars("on"), cfg, serconf_on));
92   uc->vars->add(v= new cl_var(pn+chars("check_often"), cfg, serconf_check_often));
93   v->init();
94   */
95   return(0);
96 }
97 
98 void
new_hw_added(class cl_hw * new_hw)99 cl_serial::new_hw_added(class cl_hw *new_hw)
100 {
101   if (new_hw->cathegory == HW_TIMER &&
102       new_hw->id == 2)
103     {
104       there_is_t2= true;
105       t_mem d= sfr->get(T2CON);
106       t2_baud= d & (bmRCLK | bmTCLK);
107     }
108 }
109 
110 void
added_to_uc(void)111 cl_serial::added_to_uc(void)
112 {
113   class cl_address_space *sfr= uc->address_space(MEM_SFR_ID);
114   class cl_it_src *is;
115 
116   uc->it_sources->add(is= new cl_it_src(uc, bmES,
117 					sfr->get_cell(IE), bmES,
118 					sfr->get_cell(SCON), bmTI,
119 					0x0023, false, false,
120 					"serial transmit", 6));
121   is->init();
122   uc->it_sources->add(is= new cl_it_src(uc, bmES,
123 					sfr->get_cell(IE), bmES,
124 					sfr->get_cell(SCON), bmRI,
125 					0x0023, false, false,
126 					"serial receive", 6));
127   is->init();
128 }
129 
130 t_mem
read(class cl_memory_cell * cell)131 cl_serial::read(class cl_memory_cell *cell)
132 {
133   if (cell == sbuf)
134     {
135       cfg_set(serconf_able_receive, 1);
136       return(s_in);
137     }
138   conf(cell, NULL);
139   return(cell->get());
140 }
141 
142 void
write(class cl_memory_cell * cell,t_mem * val)143 cl_serial::write(class cl_memory_cell *cell, t_mem *val)
144 {
145   t_addr ba;
146   bool b= bas->is_owned(cell, &ba);
147   u8_t n= *val;
148 
149   if (cell == sbuf)
150     {
151       s_out= *val;
152       s_sending= true;
153       s_tr_bit = 0;
154       s_tr_tick= 0;
155       s_tr_t1= 0;
156     }
157   if (b)
158     {
159       n= scon->get();
160       u8_t m= 1 << (ba - SCON);
161       if (*val)
162 	n|= m;
163       else
164 	n&= ~m;
165     }
166   if ((cell == scon) ||
167       b)
168     {
169       _mode= n >> 6;
170       _bmREN= n & bmREN;
171       _bits= 8;
172       switch (_mode)
173 	{
174 	case 0:
175 	  _bits= 8;
176 	  _divby= 12;
177 	  break;
178 	case 1:
179 	  _bits= 10;
180 	  _divby= _bmSMOD?16:32;
181 	  break;
182 	case 2:
183 	  _bits= 11;
184 	  _divby= _bmSMOD?16:32;
185 	  break;
186 	case 3:
187 	  _bits= 11;
188 	  _divby= _bmSMOD?16:32;
189 	  break;
190 	}
191     }
192   else if (cell == pcon)
193     {
194       _bmSMOD= *val & bmSMOD;
195       /*switch (_mode)
196 	{
197 	case 1:
198 	  _divby= _bmSMOD?16:32;
199 	  break;
200 	case 2:
201 	  _divby= _bmSMOD?16:32;
202 	  break;
203 	case 3:
204 	  _divby= _bmSMOD?16:32;
205 	  break;
206 	  }*/
207       if (_mode)
208 	_divby= _bmSMOD?16:32;
209     }
210   else
211     conf(cell, val);
212 }
213 
214 t_mem
conf_op(cl_memory_cell * cell,t_addr addr,t_mem * val)215 cl_serial::conf_op(cl_memory_cell *cell, t_addr addr, t_mem *val)
216 {
217   if (addr < serconf_common)
218     return cl_serial_hw::conf_op(cell, addr, val);
219   switch ((enum serial_cfg)addr)
220     {
221       /*
222     case serial_:
223       if (val)
224 	{
225 	  if (*val)
226 	    on= true;
227 	  else
228 	    on= false;
229 	}
230       else
231 	{
232 	  cell->set(on?1:0);
233 	}
234       break;
235       */
236     default:
237       break;
238     }
239   return cell->get();
240 }
241 
242 int
serial_bit_cnt(void)243 cl_serial::serial_bit_cnt(void)
244 {
245   //int divby= 12;
246   int *tr_src= 0, *rec_src= 0;
247 
248   switch (_mode)
249     {
250     case 0:
251       //divby  = 12;
252       tr_src = &s_tr_tick;
253       rec_src= &s_rec_tick;
254       break;
255     case 1:
256     case 3:
257       //divby  = (/*pcon->get()&bmSMOD*/_bmSMOD)?16:32;
258       tr_src = &s_tr_t1;
259       rec_src= &s_rec_t1;
260       break;
261     case 2:
262       //divby  = (/*pcon->get()&bmSMOD*/_bmSMOD)?16:32;
263       tr_src = &s_tr_tick;
264       rec_src= &s_rec_tick;
265       break;
266     }
267   if (t2_baud)
268     _divby= 16;
269   if (s_sending)
270     {
271       while (*tr_src >= _divby)
272 	{
273 	  (*tr_src)-= _divby;
274 	  s_tr_bit++;
275 	}
276     }
277   if (s_receiving)
278     {
279       while (*rec_src >= _divby)
280 	{
281 	  (*rec_src)-= _divby;
282 	  s_rec_bit++;
283 	}
284     }
285   return(0);
286 }
287 
288 int
tick(int cycles)289 cl_serial::tick(int cycles)
290 {
291   char c;
292 
293   serial_bit_cnt(/*_mode*/);
294   if (s_sending &&
295       (s_tr_bit >= _bits))
296     {
297       s_sending= false;
298       scon->set_bit1(bmTI);
299       io->write((char*)(&s_out), 1);
300       s_tr_bit-= _bits;
301     }
302   if ((_bmREN) &&
303       io->get_fin() &&
304       !s_receiving)
305     {
306       if (cfg_get(serconf_check_often))
307 	{
308 	  if (io->input_avail())
309 	    io->proc_input(0);
310 	}
311       if (/*fin->*/input_avail/*()*/)
312 	{
313 	  s_receiving= true;
314 	  s_rec_bit= 0;
315 	  s_rec_tick= s_rec_t1= 0;
316 	}
317     }
318   if (s_receiving &&
319       (s_rec_bit >= _bits))
320     {
321       //if (fin->read(&c, 1) == 1)
322 	{
323 	  c= input;
324 	  uc->sim->app->debug("UART%d received %d,%c\n", id,
325 			      c,isprint(c)?c:' ');
326 	  input_avail= false;
327 	  s_in= c;
328 	  sbuf->set(s_in);
329 	  received(c);
330 	}
331       s_receiving= false;
332       s_rec_bit-= _bits;
333     }
334 
335   int l;
336   s_tr_tick+= (l= cycles * uc->clock_per_cycle());
337   s_rec_tick+= l;
338   return(0);
339 }
340 
341 void
received(int c)342 cl_serial::received(int c)
343 {
344   scon->set_bit1(bmRI);
345   cfg_write(serconf_received, c);
346 }
347 
348 void
reset(void)349 cl_serial::reset(void)
350 {
351   s_tr_t1    = 0;
352   s_rec_t1   = 0;
353   s_tr_tick  = 0;
354   s_rec_tick = 0;
355   s_in       = 0;
356   s_out      = 0;
357   s_sending  = false;
358   s_receiving= false;
359   s_rec_bit  = 0;
360   s_tr_bit   = 0;
361 }
362 
363 void
happen(class cl_hw * where,enum hw_event he,void * params)364 cl_serial::happen(class cl_hw *where, enum hw_event he, void *params)
365 {
366   if (where->cathegory == HW_TIMER)
367     {
368       if (where->id == 1)
369 	{
370 	  s_rec_t1++;
371 	  s_tr_t1++;
372 	}
373       if (where->id == 2 /*&& there_is_t2*/)
374 	{
375 	  switch (he)
376 	    {
377 	    case EV_T2_MODE_CHANGED:
378 	      {
379 		if (!t2_baud)
380 		  s_rec_t1= s_tr_t1= 0;
381 		t_mem *d= (t_mem *)params;
382 		t2_baud= *d & (bmRCLK | bmTCLK);
383 		break;
384 	      }
385 	    case EV_OVERFLOW:
386 	      s_rec_t1++;
387 	      s_tr_t1++;
388 	      break;
389 	    default: break;
390 	    }
391 	}
392     }
393 }
394 
395 
396 void
print_info(class cl_console_base * con)397 cl_serial::print_info(class cl_console_base *con)
398 {
399   const char *modes[]= { "Shift, fixed clock",
400 			 "8 bit UART timer clocked",
401 			 "9 bit UART fixed clock",
402 			 "9 bit UART timer clocked" };
403   int sc= scon->get();
404 
405   con->dd_printf("%s[%d] %s\n", id_string, id, on?"on":"off");
406   con->dd_printf("Input: ");
407   class cl_f *fin= io->get_fin(), *fout= io->get_fout();
408   if (fin)
409     con->dd_printf("%s/%d ", fin->get_file_name(), fin->file_id);
410   con->dd_printf("Output: ");
411   if (fout)
412     con->dd_printf("%s/%d", fout->get_file_name(), fout->file_id);
413   con->dd_printf("\n");
414   int mode= (sc&(bmSM0|bmSM1))>>6;
415   con->dd_printf("%s", modes[mode]);
416   if (mode == 1 || mode == 2)
417     con->dd_printf(" (timer%d)", (t2_baud)?2:1);
418   con->dd_printf(" MultiProc=%s",
419 		 (mode&2)?((sc&bmSM2)?"ON":"OFF"):"none");
420   con->dd_printf(" irq=%s", (sfr->get(IE)&bmES)?"en":"dis");
421   con->dd_printf(" prio=%d", uc->priority_of(bmPS));
422   con->dd_printf("\n");
423 
424   con->dd_printf("Receiver");
425   con->dd_printf(" %s", (sc&bmREN)?"ON":"OFF");
426   con->dd_printf(" RB8=%c", (sc&bmRB8)?'1':'0');
427   con->dd_printf(" irq=%c", (sc&bmRI)?'1':'0');
428   con->dd_printf("\n");
429 
430   con->dd_printf("Transmitter");
431   con->dd_printf(" TB8=%c", (sc&bmTB8)?'1':'0');
432   con->dd_printf(" irq=%c", (sc&bmTI)?'1':'0');
433   con->dd_printf("\n");
434   /*con->dd_printf("s_rec_t1=%d s_rec_bit=%d s_rec_tick=%d\n",
435 		 s_rec_t1, s_rec_bit, s_rec_tick);
436   con->dd_printf("s_tr_t1=%d s_tr_bit=%d s_tr_tick=%d\n",
437 		 s_tr_t1, s_tr_bit, s_tr_tick);
438 		 con->dd_printf("divby=%d bits=%d\n", _divby, _bits);*/
439   print_cfg_info(con);
440 }
441 
442 
443 /* End of s51.src/serial.cc */
444