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