]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11sio.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11sio.c
CommitLineData
e0709f50 1/* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
8acc9f48 2 Copyright (C) 1999-2013 Free Software Foundation, Inc.
e0709f50
AC
3 Written by Stephane Carrez (stcarrez@worldnet.fr)
4 (From a driver model Contributed by Cygnus Solutions.)
5
6 This file is part of the program GDB, the GNU debugger.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
4744ac1b 10 the Free Software Foundation; either version 3 of the License, or
e0709f50 11 (at your option) any later version.
4744ac1b 12
e0709f50
AC
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
4744ac1b 17
e0709f50 18 You should have received a copy of the GNU General Public License
4744ac1b 19 along with this program. If not, see <http://www.gnu.org/licenses/>.
e0709f50
AC
20
21 */
22
23
24#include "sim-main.h"
25#include "hw-main.h"
26#include "dv-sockser.h"
27#include "sim-assert.h"
28
29
30/* DEVICE
31
32 m68hc11sio - m68hc11 serial I/O
33
34
35 DESCRIPTION
36
37 Implements the m68hc11 serial I/O controller described in the m68hc11
38 user guide. The serial I/O controller is directly connected to the CPU
39 interrupt. The simulator implements:
40
41 - baud rate emulation
42 - 8-bits transfers
43
44 PROPERTIES
45
46 backend {tcp | stdio}
47
48 Use dv-sockser TCP-port backend or stdio for backend. Default: stdio.
49
50
51 PORTS
52
53 reset (input)
54
55 Reset port. This port is only used to simulate a reset of the serial
56 I/O controller. It should be connected to the RESET output of the cpu.
57
58 */
59
60
61
62/* port ID's */
63
64enum
65{
66 RESET_PORT
67};
68
69
70static const struct hw_port_descriptor m68hc11sio_ports[] =
71{
72 { "reset", RESET_PORT, 0, input_port, },
73 { NULL, },
74};
75
76
77/* Serial Controller information. */
78struct m68hc11sio
79{
80 enum {sio_tcp, sio_stdio} backend; /* backend */
81
82 /* Number of cpu cycles to send a bit on the wire. */
83 unsigned long baud_cycle;
84
85 /* Length in bits of characters sent, this includes the
86 start/stop and parity bits. Together with baud_cycle, this
87 is used to find the number of cpu cycles to send/receive a data. */
88 unsigned int data_length;
89
90 /* Information about next character to be transmited. */
91 unsigned char tx_has_char;
92 unsigned char tx_char;
93
94 unsigned char rx_char;
95 unsigned char rx_clear_scsr;
96
97 /* Periodic I/O polling. */
98 struct hw_event* tx_poll_event;
99 struct hw_event* rx_poll_event;
100};
101
102
103
104/* Finish off the partially created hw device. Attach our local
105 callbacks. Wire up our port names etc. */
106
107static hw_io_read_buffer_method m68hc11sio_io_read_buffer;
108static hw_io_write_buffer_method m68hc11sio_io_write_buffer;
109static hw_port_event_method m68hc11sio_port_event;
110static hw_ioctl_method m68hc11sio_ioctl;
111
112#define M6811_SCI_FIRST_REG (M6811_BAUD)
113#define M6811_SCI_LAST_REG (M6811_SCDR)
114
115
116static void
117attach_m68hc11sio_regs (struct hw *me,
118 struct m68hc11sio *controller)
119{
63348d04 120 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
e0709f50
AC
121 M6811_SCI_FIRST_REG,
122 M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1,
123 me);
124
125 if (hw_find_property(me, "backend") != NULL)
126 {
127 const char *value = hw_find_string_property(me, "backend");
128 if(! strcmp(value, "tcp"))
129 controller->backend = sio_tcp;
130 else if(! strcmp(value, "stdio"))
131 controller->backend = sio_stdio;
132 else
133 hw_abort (me, "illegal value for backend parameter `%s':"
134 "use tcp or stdio", value);
135 }
136}
137
138
139static void
140m68hc11sio_finish (struct hw *me)
141{
142 struct m68hc11sio *controller;
143
144 controller = HW_ZALLOC (me, struct m68hc11sio);
e0709f50
AC
145 set_hw_data (me, controller);
146 set_hw_io_read_buffer (me, m68hc11sio_io_read_buffer);
147 set_hw_io_write_buffer (me, m68hc11sio_io_write_buffer);
148 set_hw_ports (me, m68hc11sio_ports);
149 set_hw_port_event (me, m68hc11sio_port_event);
150#ifdef set_hw_ioctl
151 set_hw_ioctl (me, m68hc11sio_ioctl);
152#else
153 me->to_ioctl = m68hc11sio_ioctl;
154#endif
155
156 /* Preset defaults. */
157 controller->backend = sio_stdio;
158
159 /* Attach ourself to our parent bus. */
160 attach_m68hc11sio_regs (me, controller);
161
162 /* Initialize to reset state. */
163 controller->tx_poll_event = NULL;
164 controller->rx_poll_event = NULL;
165 controller->tx_char = 0;
166 controller->tx_has_char = 0;
167 controller->rx_clear_scsr = 0;
168 controller->rx_char = 0;
169}
170
171
172
173/* An event arrives on an interrupt port. */
174
175static void
176m68hc11sio_port_event (struct hw *me,
177 int my_port,
178 struct hw *source,
179 int source_port,
180 int level)
181{
182 SIM_DESC sd;
183 struct m68hc11sio *controller;
184 sim_cpu *cpu;
185 unsigned8 val;
186
187 controller = hw_data (me);
188 sd = hw_system (me);
189 cpu = STATE_CPU (sd, 0);
190 switch (my_port)
191 {
192 case RESET_PORT:
193 {
194 HW_TRACE ((me, "SCI reset"));
195
196 /* Reset the state of SCI registers. */
197 val = 0;
198 m68hc11sio_io_write_buffer (me, &val, io_map,
199 (unsigned_word) M6811_BAUD, 1);
200 m68hc11sio_io_write_buffer (me, &val, io_map,
201 (unsigned_word) M6811_SCCR1, 1);
202 m68hc11sio_io_write_buffer (me, &val, io_map,
203 (unsigned_word) M6811_SCCR2, 1);
204
205 cpu->ios[M6811_SCSR] = M6811_TC | M6811_TDRE;
206 controller->rx_char = 0;
207 controller->tx_char = 0;
208 controller->tx_has_char = 0;
209 controller->rx_clear_scsr = 0;
210 if (controller->rx_poll_event)
211 {
212 hw_event_queue_deschedule (me, controller->rx_poll_event);
213 controller->rx_poll_event = 0;
214 }
215 if (controller->tx_poll_event)
216 {
217 hw_event_queue_deschedule (me, controller->tx_poll_event);
218 controller->tx_poll_event = 0;
219 }
220
221 /* In bootstrap mode, initialize the SCI to 1200 bauds to
222 simulate some initial setup by the internal rom. */
223 if (((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD)
224 {
225 unsigned char val = 0x33;
226
227 m68hc11sio_io_write_buffer (me, &val, io_map,
228 (unsigned_word) M6811_BAUD, 1);
229 val = 0x12;
230 m68hc11sio_io_write_buffer (me, &val, io_map,
231 (unsigned_word) M6811_SCCR2, 1);
232 }
233 break;
234 }
235
236 default:
237 hw_abort (me, "Event on unknown port %d", my_port);
238 break;
239 }
240}
241
242
243void
244m68hc11sio_rx_poll (struct hw *me, void *data)
245{
246 SIM_DESC sd;
247 struct m68hc11sio *controller;
248 sim_cpu *cpu;
249 char cc;
250 int cnt;
251 int check_interrupt = 0;
252
253 controller = hw_data (me);
254 sd = hw_system (me);
255 cpu = STATE_CPU (sd, 0);
256 switch (controller->backend)
257 {
258 case sio_tcp:
259 cnt = dv_sockser_read (sd);
260 if (cnt != -1)
261 {
262 cc = (char) cnt;
263 cnt = 1;
264 }
265 break;
266
267 case sio_stdio:
268 cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1);
269 break;
270
271 default:
272 cnt = 0;
273 break;
274 }
275
276 if (cnt == 1)
277 {
278 /* Raise the overrun flag if the previous character was not read. */
279 if (cpu->ios[M6811_SCSR] & M6811_RDRF)
280 cpu->ios[M6811_SCSR] |= M6811_OR;
281
282 cpu->ios[M6811_SCSR] |= M6811_RDRF;
283 controller->rx_char = cc;
284 controller->rx_clear_scsr = 0;
285 check_interrupt = 1;
286 }
287 else
288 {
289 /* handle idle line detect here. */
290 ;
291 }
292
293 if (controller->rx_poll_event)
294 {
295 hw_event_queue_deschedule (me, controller->rx_poll_event);
296 controller->rx_poll_event = 0;
297 }
298
299 if (cpu->ios[M6811_SCCR2] & M6811_RE)
300 {
301 unsigned long clock_cycle;
302
303 /* Compute CPU clock cycles to wait for the next character. */
304 clock_cycle = controller->data_length * controller->baud_cycle;
305
306 controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
307 m68hc11sio_rx_poll,
308 NULL);
309 }
310
311 if (check_interrupt)
312 interrupts_update_pending (&cpu->cpu_interrupts);
313}
314
315
316void
317m68hc11sio_tx_poll (struct hw *me, void *data)
318{
319 SIM_DESC sd;
320 struct m68hc11sio *controller;
321 sim_cpu *cpu;
e0709f50
AC
322
323 controller = hw_data (me);
324 sd = hw_system (me);
325 cpu = STATE_CPU (sd, 0);
326
327 cpu->ios[M6811_SCSR] |= M6811_TDRE;
328 cpu->ios[M6811_SCSR] |= M6811_TC;
329
11115521 330 /* Transmitter is enabled and we have something to send. */
e0709f50
AC
331 if ((cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char)
332 {
333 cpu->ios[M6811_SCSR] &= ~M6811_TDRE;
334 cpu->ios[M6811_SCSR] &= ~M6811_TC;
335 controller->tx_has_char = 0;
e0709f50
AC
336 switch (controller->backend)
337 {
338 case sio_tcp:
339 dv_sockser_write (sd, controller->tx_char);
340 break;
341
342 case sio_stdio:
343 sim_io_write_stdout (sd, &controller->tx_char, 1);
344 sim_io_flush_stdout (sd);
345 break;
346
347 default:
348 break;
349 }
350 }
351
352 if (controller->tx_poll_event)
353 {
354 hw_event_queue_deschedule (me, controller->tx_poll_event);
355 controller->tx_poll_event = 0;
356 }
357
358 if ((cpu->ios[M6811_SCCR2] & M6811_TE)
359 && ((cpu->ios[M6811_SCSR] & M6811_TC) == 0))
360 {
361 unsigned long clock_cycle;
362
363 /* Compute CPU clock cycles to wait for the next character. */
364 clock_cycle = controller->data_length * controller->baud_cycle;
365
366 controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle,
367 m68hc11sio_tx_poll,
368 NULL);
369 }
370
11115521 371 interrupts_update_pending (&cpu->cpu_interrupts);
e0709f50
AC
372}
373
374/* Descriptions of the SIO I/O ports. These descriptions are only used to
375 give information of the SIO device under GDB. */
376io_reg_desc sccr2_desc[] = {
377 { M6811_TIE, "TIE ", "Transmit Interrupt Enable" },
378 { M6811_TCIE, "TCIE ", "Transmit Complete Interrupt Enable" },
379 { M6811_RIE, "RIE ", "Receive Interrupt Enable" },
380 { M6811_ILIE, "ILIE ", "Idle Line Interrupt Enable" },
381 { M6811_TE, "TE ", "Transmit Enable" },
382 { M6811_RE, "RE ", "Receive Enable" },
383 { M6811_RWU, "RWU ", "Receiver Wake Up" },
384 { M6811_SBK, "SBRK ", "Send Break" },
385 { 0, 0, 0 }
386};
387
388io_reg_desc sccr1_desc[] = {
389 { M6811_R8, "R8 ", "Receive Data bit 8" },
390 { M6811_T8, "T8 ", "Transmit Data bit 8" },
391 { M6811_M, "M ", "SCI Character length (0=8-bits, 1=9-bits)" },
392 { M6811_WAKE, "WAKE ", "Wake up method select (0=idle, 1=addr mark" },
393 { 0, 0, 0 }
394};
395
396io_reg_desc scsr_desc[] = {
397 { M6811_TDRE, "TDRE ", "Transmit Data Register Empty" },
398 { M6811_TC, "TC ", "Transmit Complete" },
399 { M6811_RDRF, "RDRF ", "Receive Data Register Full" },
400 { M6811_IDLE, "IDLE ", "Idle Line Detect" },
401 { M6811_OR, "OR ", "Overrun Error" },
402 { M6811_NF, "NF ", "Noise Flag" },
403 { M6811_FE, "FE ", "Framing Error" },
404 { 0, 0, 0 }
405};
406
407io_reg_desc baud_desc[] = {
408 { M6811_TCLR, "TCLR ", "Clear baud rate (test mode)" },
409 { M6811_SCP1, "SCP1 ", "SCI baud rate prescaler select (SCP1)" },
410 { M6811_SCP0, "SCP0 ", "SCI baud rate prescaler select (SCP0)" },
411 { M6811_RCKB, "RCKB ", "Baur Rate Clock Check (test mode)" },
412 { M6811_SCR2, "SCR2 ", "SCI Baud rate select (SCR2)" },
413 { M6811_SCR1, "SCR1 ", "SCI Baud rate select (SCR1)" },
414 { M6811_SCR0, "SCR0 ", "SCI Baud rate select (SCR0)" },
415 { 0, 0, 0 }
416};
417
418static void
419m68hc11sio_info (struct hw *me)
420{
421 SIM_DESC sd;
422 uint16 base = 0;
423 sim_cpu *cpu;
424 struct m68hc11sio *controller;
425 uint8 val;
426 long clock_cycle;
427
428 sd = hw_system (me);
429 cpu = STATE_CPU (sd, 0);
430 controller = hw_data (me);
431
432 sim_io_printf (sd, "M68HC11 SIO:\n");
433
434 base = cpu_get_io_base (cpu);
435
436 val = cpu->ios[M6811_BAUD];
437 print_io_byte (sd, "BAUD ", baud_desc, val, base + M6811_BAUD);
438 sim_io_printf (sd, " (%ld baud)\n",
439 (cpu->cpu_frequency / 4) / controller->baud_cycle);
440
441 val = cpu->ios[M6811_SCCR1];
442 print_io_byte (sd, "SCCR1", sccr1_desc, val, base + M6811_SCCR1);
443 sim_io_printf (sd, " (%d bits) (%dN1)\n",
444 controller->data_length, controller->data_length - 2);
445
446 val = cpu->ios[M6811_SCCR2];
447 print_io_byte (sd, "SCCR2", sccr2_desc, val, base + M6811_SCCR2);
448 sim_io_printf (sd, "\n");
449
450 val = cpu->ios[M6811_SCSR];
451 print_io_byte (sd, "SCSR ", scsr_desc, val, base + M6811_SCSR);
452 sim_io_printf (sd, "\n");
453
454 clock_cycle = controller->data_length * controller->baud_cycle;
455
456 if (controller->tx_poll_event)
457 {
458 signed64 t;
459 int n;
460
461 t = hw_event_remain_time (me, controller->tx_poll_event);
462 n = (clock_cycle - t) / controller->baud_cycle;
463 n = controller->data_length - n;
2990a9f4 464 sim_io_printf (sd, " Transmit finished in %s (%d bit%s)\n",
a685700c
SC
465 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE),
466 n, (n > 1 ? "s" : ""));
e0709f50
AC
467 }
468 if (controller->rx_poll_event)
469 {
470 signed64 t;
471
472 t = hw_event_remain_time (me, controller->rx_poll_event);
2990a9f4 473 sim_io_printf (sd, " Receive finished in %s\n",
a685700c 474 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
e0709f50
AC
475 }
476
477}
478
479static int
480m68hc11sio_ioctl (struct hw *me,
481 hw_ioctl_request request,
482 va_list ap)
483{
484 m68hc11sio_info (me);
485 return 0;
486}
487
488/* generic read/write */
489
490static unsigned
491m68hc11sio_io_read_buffer (struct hw *me,
492 void *dest,
493 int space,
494 unsigned_word base,
495 unsigned nr_bytes)
496{
497 SIM_DESC sd;
498 struct m68hc11sio *controller;
499 sim_cpu *cpu;
500 unsigned8 val;
501
502 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
503
504 sd = hw_system (me);
505 cpu = STATE_CPU (sd, 0);
506 controller = hw_data (me);
507
508 switch (base)
509 {
510 case M6811_SCSR:
511 controller->rx_clear_scsr = cpu->ios[M6811_SCSR]
512 & (M6811_RDRF | M6811_IDLE | M6811_OR | M6811_NF | M6811_FE);
513
514 case M6811_BAUD:
515 case M6811_SCCR1:
516 case M6811_SCCR2:
517 val = cpu->ios[base];
518 break;
519
520 case M6811_SCDR:
521 if (controller->rx_clear_scsr)
522 {
523 cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr;
524 }
525 val = controller->rx_char;
526 break;
527
528 default:
529 return 0;
530 }
531 *((unsigned8*) dest) = val;
532 return 1;
533}
534
535static unsigned
536m68hc11sio_io_write_buffer (struct hw *me,
537 const void *source,
538 int space,
539 unsigned_word base,
540 unsigned nr_bytes)
541{
542 SIM_DESC sd;
543 struct m68hc11sio *controller;
544 sim_cpu *cpu;
545 unsigned8 val;
546
547 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
548
549 sd = hw_system (me);
550 cpu = STATE_CPU (sd, 0);
551 controller = hw_data (me);
552
553 val = *((const unsigned8*) source);
554 switch (base)
555 {
556 case M6811_BAUD:
557 {
558 long divisor;
559 long baud;
560
561 cpu->ios[M6811_BAUD] = val;
562 switch (val & (M6811_SCP1|M6811_SCP0))
563 {
564 case M6811_BAUD_DIV_1:
565 divisor = 1 * 16;
566 break;
567
568 case M6811_BAUD_DIV_3:
569 divisor = 3 * 16;
570 break;
571
572 case M6811_BAUD_DIV_4:
573 divisor = 4 * 16;
574 break;
575
576 default:
577 case M6811_BAUD_DIV_13:
578 divisor = 13 * 16;
579 break;
580 }
581 val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0);
582 divisor *= (1 << val);
583
584 baud = (cpu->cpu_frequency / 4) / divisor;
585
586 HW_TRACE ((me, "divide rate %ld, baud rate %ld",
587 divisor, baud));
588
589 controller->baud_cycle = divisor;
590 }
591 break;
592
593 case M6811_SCCR1:
594 {
595 if (val & M6811_M)
596 controller->data_length = 11;
597 else
598 controller->data_length = 10;
599
600 cpu->ios[M6811_SCCR1] = val;
601 }
602 break;
603
604 case M6811_SCCR2:
605 if ((val & M6811_RE) == 0)
606 {
607 val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF);
608 val |= (cpu->ios[M6811_SCCR2]
609 & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF));
610 cpu->ios[M6811_SCCR2] = val;
611 break;
612 }
613
614 /* Activate reception. */
615 if (controller->rx_poll_event == 0)
616 {
617 long clock_cycle;
618
619 /* Compute CPU clock cycles to wait for the next character. */
620 clock_cycle = controller->data_length * controller->baud_cycle;
621
622 controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
623 m68hc11sio_rx_poll,
624 NULL);
625 }
626 cpu->ios[M6811_SCCR2] = val;
627 interrupts_update_pending (&cpu->cpu_interrupts);
628 break;
629
630 /* No effect. */
631 case M6811_SCSR:
632 return 1;
633
634 case M6811_SCDR:
635 if (!(cpu->ios[M6811_SCSR] & M6811_TDRE))
636 {
637 return 0;
638 }
639
640 controller->tx_char = val;
641 controller->tx_has_char = 1;
642 if ((cpu->ios[M6811_SCCR2] & M6811_TE)
643 && controller->tx_poll_event == 0)
644 {
645 m68hc11sio_tx_poll (me, NULL);
646 }
647 return 1;
648
649 default:
650 return 0;
651 }
652 return nr_bytes;
653}
654
655
656const struct hw_descriptor dv_m68hc11sio_descriptor[] = {
b93775f5
SC
657 { "m68hc11sio", m68hc11sio_finish },
658 { "m68hc12sio", m68hc11sio_finish },
e0709f50
AC
659 { NULL },
660};
661