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