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 // sim
46 #include "itsrccl.h"
47 
48 // local
49 #include "clkcl.h"
50 #include "serialcl.h"
51 
52 
53 enum reg_idx {
54   sr	= 0,
55   dr	= 1,
56   brr1	= 2,
57   brr2	= 3,
58   cr1	= 4,
59   cr2	= 5,
60   cr3	= 6,
61   cr4	= 7,
62   cr5	= 8,
63   cr6	= 9,
64   gtr	= 10,
65   pscr	= 11
66 };
67 
68 
cl_serial(class cl_uc * auc,t_addr abase,int ttype,int atxit,int arxit)69 cl_serial::cl_serial(class cl_uc *auc,
70 		     t_addr abase,
71 		     int ttype, int atxit, int arxit):
72   cl_serial_hw(auc, ttype, "uart")
73 {
74   type= ttype;
75   base= abase;
76   txit= atxit;
77   rxit= arxit;
78 }
79 
80 
~cl_serial(void)81 cl_serial::~cl_serial(void)
82 {
83 }
84 
85 int
init(void)86 cl_serial::init(void)
87 {
88   int i;
89   class cl_it_src *is;
90 
91   set_name("stm8_uart");
92   cl_serial_hw::init();
93   clk_enabled= false;
94   for (i= 0; i < 12; i++)
95     {
96       regs[i]= register_cell(uc->rom, base+i);
97     }
98   pick_div();
99   pick_ctrl();
100 
101   uc->it_sources->add(is= new cl_it_src(uc, txit,
102 					regs[cr2], 0x80,
103 					regs[sr], 0x80,
104 					0x8008+txit*4, false, false,
105 					chars("", "usart%d transmit register empty", id), 20*10+1));
106   is->init();
107   uc->it_sources->add(is= new cl_it_src(uc, txit,
108 					regs[cr2], 0x40,
109 					regs[sr], 0x40,
110 					0x8008+txit*4, false, false,
111 					chars("", "usart%d transmit complete", id), 20*10+2));
112   is->init();
113   uc->it_sources->add(is= new cl_it_src(uc, rxit,
114 					regs[cr2], 0x20,
115 					regs[sr], 0x20,
116 					0x8008+rxit*4, false, false,
117 					chars("", "usart%d receive", id), 20*10+3));
118   is->init();
119 
120   sr_read= false;
121 
122   return(0);
123 }
124 
125 
126 void
new_hw_added(class cl_hw * new_hw)127 cl_serial::new_hw_added(class cl_hw *new_hw)
128 {
129 }
130 
131 void
added_to_uc(void)132 cl_serial::added_to_uc(void)
133 {
134 }
135 
136 t_mem
read(class cl_memory_cell * cell)137 cl_serial::read(class cl_memory_cell *cell)
138 {
139   if (cell == regs[dr])
140     {
141       if (sr_read)
142 	regs[sr]->set_bit0(0x1f);
143       regs[sr]->set_bit0(0x20);
144       cfg_set(serconf_able_receive, 1);
145       return s_in;
146     }
147   sr_read= (cell == regs[sr]);
148   conf(cell, NULL);
149   return cell->get();
150 }
151 
152 void
write(class cl_memory_cell * cell,t_mem * val)153 cl_serial::write(class cl_memory_cell *cell, t_mem *val)
154 {
155   if (conf(cell, val))
156     return;
157   if (cell == regs[sr])
158     {
159       u8_t v= cell->get();
160       if ((*val & 0x40) == 0)
161 	{
162 	  v&= ~0x40;
163 	  *val= v;
164 	}
165     }
166   else
167     {
168       cell->set(*val);
169       if ((cell == regs[brr1]) ||
170 	  (cell == regs[brr2]))
171 	{
172 	  pick_div();
173 	}
174       else if ((cell == regs[cr1]) ||
175 	       (cell == regs[cr2]))
176 	{
177 	  pick_ctrl();
178 	}
179 
180       else if (cell == regs[dr])
181 	{
182 	  s_txd= *val;
183 	  s_tx_written= true;
184 	  show_writable(false);
185 	  if (sr_read)
186 	    show_tx_complete(false);
187 	  if (!s_sending)
188 	    {
189 	      start_send();
190 	    }
191 	}
192     }
193 
194   sr_read= false;
195 }
196 
197 t_mem
conf_op(cl_memory_cell * cell,t_addr addr,t_mem * val)198 cl_serial::conf_op(cl_memory_cell *cell, t_addr addr, t_mem *val)
199 {
200   if (addr < serconf_common)
201     return cl_serial_hw::conf_op(cell, addr, val);
202   switch ((enum serial_cfg)addr)
203     {
204       /*
205     case serial_:
206       if (val)
207 	{
208 	  if (*val)
209 	    on= true;
210 	  else
211 	    on= false;
212 	}
213       else
214 	{
215 	  cell->set(on?1:0);
216 	}
217       break;
218       */
219     default:
220       break;
221     }
222   return cell->get();
223 }
224 
225 int
tick(int cycles)226 cl_serial::tick(int cycles)
227 {
228   char c;
229 
230   if (!en ||
231       !clk_enabled)
232     return 0;
233 
234   if ((mcnt+= cycles) >= div)
235     {
236       mcnt-= div;
237       if (ten)
238 	s_tr_bit++;
239       if (ren)
240 	s_rec_bit++;
241     }
242   else
243     return 0;
244 
245   if (s_sending &&
246       (s_tr_bit >= bits))
247     {
248       s_sending= false;
249       //io->dd_printf("%c", s_out);
250       io->write((char*)&s_out, 1);
251       s_tr_bit-= bits;
252       if (s_tx_written)
253 	restart_send();
254       else
255 	finish_send();
256     }
257   if ((ren) &&
258       io->get_fin() &&
259       !s_receiving)
260     {
261       if (cfg_get(serconf_check_often))
262 	{
263 	  if (io->input_avail())
264 	    io->proc_input(0);
265 	}
266       if (input_avail)
267 	{
268 	  s_receiving= true;
269 	  s_rec_bit= 0;
270 	}
271       else
272 	show_idle(true);
273     }
274   if (s_receiving &&
275       (s_rec_bit >= bits))
276     {
277 	{
278 	  c= input;
279 	  input_avail= false;
280 	  s_in= c;
281 	  received();
282 	}
283       s_receiving= false;
284       s_rec_bit-= bits;
285     }
286 
287   return(0);
288 }
289 
290 void
start_send()291 cl_serial::start_send()
292 {
293   if (ten)
294     {
295       s_out= s_txd;
296       s_tx_written= false;
297       s_sending= true;
298       s_tr_bit= 0;
299       show_writable(true);
300     }
301 }
302 
303 void
restart_send()304 cl_serial::restart_send()
305 {
306   if (ten)
307     {
308       s_out= s_txd;
309       s_tx_written= false;
310       s_sending= true;
311       s_tr_bit= 0;
312       show_writable(true);
313     }
314 }
315 
316 void
finish_send()317 cl_serial::finish_send()
318 {
319   show_writable(true);
320   show_tx_complete(true);
321 }
322 
323 void
received()324 cl_serial::received()
325 {
326   set_dr(s_in);
327   cfg_write(serconf_received, s_in);
328   if (regs[sr]->get() & 0x20)
329     regs[sr]->set_bit1(0x08); // overrun
330   show_readable(true);
331 }
332 
333 void
reset(void)334 cl_serial::reset(void)
335 {
336   int i;
337   regs[sr]->set(0xc0);
338   for (i= 2; i < 12; i++)
339     regs[i]->set(0);
340 }
341 
342 void
happen(class cl_hw * where,enum hw_event he,void * params)343 cl_serial::happen(class cl_hw *where, enum hw_event he,
344 		  void *params)
345 {
346   if ((he == EV_CLK_ON) ||
347       (he == EV_CLK_OFF))
348     {
349       cl_clk_event *e= (cl_clk_event *)params;
350       if ((e->cath == HW_UART) &&
351 	  (e->id == id))
352 	clk_enabled= he == EV_CLK_ON;
353     }
354 }
355 
356 void
pick_div()357 cl_serial::pick_div()
358 {
359   u8_t b1= regs[brr1]->get();
360   u8_t b2= regs[brr2]->get();
361   div= ((((b2&0xf0)<<4) + b1)<<4) + (b2&0xf);
362   mcnt= 0;
363 }
364 
365 void
pick_ctrl()366 cl_serial::pick_ctrl()
367 {
368   u8_t c1= regs[cr1]->get();
369   u8_t c2= regs[cr2]->get();
370   en= !(c1 & 0x20);
371   ten= c2 & 0x08;
372   ren= c2 & 0x04;
373   bits= 10;
374   s_rec_bit= s_tr_bit= 0;
375   s_receiving= false;
376   s_tx_written= false;
377 }
378 
379 void
show_writable(bool val)380 cl_serial::show_writable(bool val)
381 {
382   if (val)
383     // TXE=1
384     regs[sr]->write_bit1(0x80);
385   else
386     // TXE=0
387     regs[sr]->write_bit0(0x80);
388 }
389 
390 void
show_readable(bool val)391 cl_serial::show_readable(bool val)
392 {
393   if (val)
394     regs[sr]->write_bit1(0x20);
395   else
396     regs[sr]->write_bit0(0x20);
397 }
398 
399 void
show_tx_complete(bool val)400 cl_serial::show_tx_complete(bool val)
401 {
402   if (val)
403     regs[sr]->write_bit1(0x40);
404   else
405     regs[sr]->write_bit0(0x40);
406 }
407 
408 void
show_idle(bool val)409 cl_serial::show_idle(bool val)
410 {
411   if (val)
412     regs[sr]->write_bit1(0x10);
413   else
414     regs[sr]->write_bit0(0x10);
415 }
416 
417 void
set_dr(t_mem val)418 cl_serial::set_dr(t_mem val)
419 {
420   regs[dr]->set(val);
421 }
422 
423 void
print_info(class cl_console_base * con)424 cl_serial::print_info(class cl_console_base *con)
425 {
426   con->dd_printf("%s[%d] at 0x%06x %s\n", id_string, id, base, on?"on":"off");
427   con->dd_printf("clk %s\n", clk_enabled?"enabled":"disabled");
428   con->dd_printf("Input: ");
429   class cl_f *fin= io->get_fin(), *fout= io->get_fout();
430   if (fin)
431     con->dd_printf("%s/%d ", fin->get_file_name(), fin->file_id);
432   con->dd_printf("Output: ");
433   if (fout)
434     con->dd_printf("%s/%d", fout->get_file_name(), fout->file_id);
435   con->dd_printf("\n");
436   print_cfg_info(con);
437 }
438 
439 
440 /* End of stm8.src/serial.cc */
441