Automatic date update in version.in
[binutils-gdb.git] / sim / m68hc11 / dv-m68hc11sio.c
blobd5ecbe4f822e424ec1e5cb197645497b285078c5
1 /* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
2 Copyright (C) 1999-2023 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@worldnet.fr)
4 (From a driver model Contributed by Cygnus Solutions.)
6 This file is part of the program GDB, the GNU debugger.
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
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* This must come before any other includes. */
24 #include "defs.h"
26 #include "sim-main.h"
27 #include "hw-main.h"
28 #include "dv-sockser.h"
29 #include "sim-assert.h"
31 #include "m68hc11-sim.h"
33 /* DEVICE
35 m68hc11sio - m68hc11 serial I/O
38 DESCRIPTION
40 Implements the m68hc11 serial I/O controller described in the m68hc11
41 user guide. The serial I/O controller is directly connected to the CPU
42 interrupt. The simulator implements:
44 - baud rate emulation
45 - 8-bits transfers
47 PROPERTIES
49 backend {tcp | stdio}
51 Use dv-sockser TCP-port backend or stdio for backend. Default: stdio.
54 PORTS
56 reset (input)
58 Reset port. This port is only used to simulate a reset of the serial
59 I/O controller. It should be connected to the RESET output of the cpu.
65 /* port ID's */
67 enum
69 RESET_PORT
73 static const struct hw_port_descriptor m68hc11sio_ports[] =
75 { "reset", RESET_PORT, 0, input_port, },
76 { NULL, },
80 /* Serial Controller information. */
81 struct m68hc11sio
83 enum {sio_tcp, sio_stdio} backend; /* backend */
85 /* Number of cpu cycles to send a bit on the wire. */
86 unsigned long baud_cycle;
88 /* Length in bits of characters sent, this includes the
89 start/stop and parity bits. Together with baud_cycle, this
90 is used to find the number of cpu cycles to send/receive a data. */
91 unsigned int data_length;
93 /* Information about next character to be transmited. */
94 unsigned char tx_has_char;
95 unsigned char tx_char;
97 unsigned char rx_char;
98 unsigned char rx_clear_scsr;
100 /* Periodic I/O polling. */
101 struct hw_event* tx_poll_event;
102 struct hw_event* rx_poll_event;
107 /* Finish off the partially created hw device. Attach our local
108 callbacks. Wire up our port names etc. */
110 static hw_io_read_buffer_method m68hc11sio_io_read_buffer;
111 static hw_io_write_buffer_method m68hc11sio_io_write_buffer;
112 static hw_port_event_method m68hc11sio_port_event;
113 static hw_ioctl_method m68hc11sio_ioctl;
115 #define M6811_SCI_FIRST_REG (M6811_BAUD)
116 #define M6811_SCI_LAST_REG (M6811_SCDR)
119 static void
120 attach_m68hc11sio_regs (struct hw *me,
121 struct m68hc11sio *controller)
123 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
124 M6811_SCI_FIRST_REG,
125 M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1,
126 me);
128 if (hw_find_property(me, "backend") != NULL)
130 const char *value = hw_find_string_property(me, "backend");
131 if(! strcmp(value, "tcp"))
132 controller->backend = sio_tcp;
133 else if(! strcmp(value, "stdio"))
134 controller->backend = sio_stdio;
135 else
136 hw_abort (me, "illegal value for backend parameter `%s':"
137 "use tcp or stdio", value);
142 static void
143 m68hc11sio_finish (struct hw *me)
145 struct m68hc11sio *controller;
147 controller = HW_ZALLOC (me, struct m68hc11sio);
148 set_hw_data (me, controller);
149 set_hw_io_read_buffer (me, m68hc11sio_io_read_buffer);
150 set_hw_io_write_buffer (me, m68hc11sio_io_write_buffer);
151 set_hw_ports (me, m68hc11sio_ports);
152 set_hw_port_event (me, m68hc11sio_port_event);
153 #ifdef set_hw_ioctl
154 set_hw_ioctl (me, m68hc11sio_ioctl);
155 #else
156 me->to_ioctl = m68hc11sio_ioctl;
157 #endif
159 /* Preset defaults. */
160 controller->backend = sio_stdio;
162 /* Attach ourself to our parent bus. */
163 attach_m68hc11sio_regs (me, controller);
165 /* Initialize to reset state. */
166 controller->tx_poll_event = NULL;
167 controller->rx_poll_event = NULL;
168 controller->tx_char = 0;
169 controller->tx_has_char = 0;
170 controller->rx_clear_scsr = 0;
171 controller->rx_char = 0;
176 /* An event arrives on an interrupt port. */
178 static void
179 m68hc11sio_port_event (struct hw *me,
180 int my_port,
181 struct hw *source,
182 int source_port,
183 int level)
185 SIM_DESC sd;
186 struct m68hc11sio *controller;
187 sim_cpu *cpu;
188 struct m68hc11_sim_cpu *m68hc11_cpu;
189 uint8_t val;
191 controller = hw_data (me);
192 sd = hw_system (me);
193 cpu = STATE_CPU (sd, 0);
194 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
195 switch (my_port)
197 case RESET_PORT:
199 HW_TRACE ((me, "SCI reset"));
201 /* Reset the state of SCI registers. */
202 val = 0;
203 m68hc11sio_io_write_buffer (me, &val, io_map,
204 (unsigned_word) M6811_BAUD, 1);
205 m68hc11sio_io_write_buffer (me, &val, io_map,
206 (unsigned_word) M6811_SCCR1, 1);
207 m68hc11sio_io_write_buffer (me, &val, io_map,
208 (unsigned_word) M6811_SCCR2, 1);
210 m68hc11_cpu->ios[M6811_SCSR] = M6811_TC | M6811_TDRE;
211 controller->rx_char = 0;
212 controller->tx_char = 0;
213 controller->tx_has_char = 0;
214 controller->rx_clear_scsr = 0;
215 if (controller->rx_poll_event)
217 hw_event_queue_deschedule (me, controller->rx_poll_event);
218 controller->rx_poll_event = 0;
220 if (controller->tx_poll_event)
222 hw_event_queue_deschedule (me, controller->tx_poll_event);
223 controller->tx_poll_event = 0;
226 /* In bootstrap mode, initialize the SCI to 1200 bauds to
227 simulate some initial setup by the internal rom. */
228 if (((m68hc11_cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD)
230 unsigned char val = 0x33;
232 m68hc11sio_io_write_buffer (me, &val, io_map,
233 (unsigned_word) M6811_BAUD, 1);
234 val = 0x12;
235 m68hc11sio_io_write_buffer (me, &val, io_map,
236 (unsigned_word) M6811_SCCR2, 1);
238 break;
241 default:
242 hw_abort (me, "Event on unknown port %d", my_port);
243 break;
248 static void
249 m68hc11sio_rx_poll (struct hw *me, void *data)
251 SIM_DESC sd;
252 struct m68hc11sio *controller;
253 sim_cpu *cpu;
254 struct m68hc11_sim_cpu *m68hc11_cpu;
255 char cc;
256 int cnt;
257 int check_interrupt = 0;
259 controller = hw_data (me);
260 sd = hw_system (me);
261 cpu = STATE_CPU (sd, 0);
262 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
263 switch (controller->backend)
265 case sio_tcp:
266 cnt = dv_sockser_read (sd);
267 if (cnt != -1)
269 cc = (char) cnt;
270 cnt = 1;
272 break;
274 case sio_stdio:
275 cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1);
276 break;
278 default:
279 cnt = 0;
280 break;
283 if (cnt == 1)
285 /* Raise the overrun flag if the previous character was not read. */
286 if (m68hc11_cpu->ios[M6811_SCSR] & M6811_RDRF)
287 m68hc11_cpu->ios[M6811_SCSR] |= M6811_OR;
289 m68hc11_cpu->ios[M6811_SCSR] |= M6811_RDRF;
290 controller->rx_char = cc;
291 controller->rx_clear_scsr = 0;
292 check_interrupt = 1;
294 else
296 /* handle idle line detect here. */
300 if (controller->rx_poll_event)
302 hw_event_queue_deschedule (me, controller->rx_poll_event);
303 controller->rx_poll_event = 0;
306 if (m68hc11_cpu->ios[M6811_SCCR2] & M6811_RE)
308 unsigned long clock_cycle;
310 /* Compute CPU clock cycles to wait for the next character. */
311 clock_cycle = controller->data_length * controller->baud_cycle;
313 controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
314 m68hc11sio_rx_poll,
315 NULL);
318 if (check_interrupt)
319 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
323 static void
324 m68hc11sio_tx_poll (struct hw *me, void *data)
326 SIM_DESC sd;
327 struct m68hc11sio *controller;
328 sim_cpu *cpu;
329 struct m68hc11_sim_cpu *m68hc11_cpu;
331 controller = hw_data (me);
332 sd = hw_system (me);
333 cpu = STATE_CPU (sd, 0);
334 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
336 m68hc11_cpu->ios[M6811_SCSR] |= M6811_TDRE;
337 m68hc11_cpu->ios[M6811_SCSR] |= M6811_TC;
339 /* Transmitter is enabled and we have something to send. */
340 if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char)
342 m68hc11_cpu->ios[M6811_SCSR] &= ~M6811_TDRE;
343 m68hc11_cpu->ios[M6811_SCSR] &= ~M6811_TC;
344 controller->tx_has_char = 0;
345 switch (controller->backend)
347 case sio_tcp:
348 dv_sockser_write (sd, controller->tx_char);
349 break;
351 case sio_stdio:
352 sim_io_write_stdout (sd, (const char *)&controller->tx_char, 1);
353 sim_io_flush_stdout (sd);
354 break;
356 default:
357 break;
361 if (controller->tx_poll_event)
363 hw_event_queue_deschedule (me, controller->tx_poll_event);
364 controller->tx_poll_event = 0;
367 if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE)
368 && ((m68hc11_cpu->ios[M6811_SCSR] & M6811_TC) == 0))
370 unsigned long clock_cycle;
372 /* Compute CPU clock cycles to wait for the next character. */
373 clock_cycle = controller->data_length * controller->baud_cycle;
375 controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle,
376 m68hc11sio_tx_poll,
377 NULL);
380 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
383 /* Descriptions of the SIO I/O ports. These descriptions are only used to
384 give information of the SIO device under GDB. */
385 io_reg_desc sccr2_desc[] = {
386 { M6811_TIE, "TIE ", "Transmit Interrupt Enable" },
387 { M6811_TCIE, "TCIE ", "Transmit Complete Interrupt Enable" },
388 { M6811_RIE, "RIE ", "Receive Interrupt Enable" },
389 { M6811_ILIE, "ILIE ", "Idle Line Interrupt Enable" },
390 { M6811_TE, "TE ", "Transmit Enable" },
391 { M6811_RE, "RE ", "Receive Enable" },
392 { M6811_RWU, "RWU ", "Receiver Wake Up" },
393 { M6811_SBK, "SBRK ", "Send Break" },
394 { 0, 0, 0 }
397 io_reg_desc sccr1_desc[] = {
398 { M6811_R8, "R8 ", "Receive Data bit 8" },
399 { M6811_T8, "T8 ", "Transmit Data bit 8" },
400 { M6811_M, "M ", "SCI Character length (0=8-bits, 1=9-bits)" },
401 { M6811_WAKE, "WAKE ", "Wake up method select (0=idle, 1=addr mark" },
402 { 0, 0, 0 }
405 io_reg_desc scsr_desc[] = {
406 { M6811_TDRE, "TDRE ", "Transmit Data Register Empty" },
407 { M6811_TC, "TC ", "Transmit Complete" },
408 { M6811_RDRF, "RDRF ", "Receive Data Register Full" },
409 { M6811_IDLE, "IDLE ", "Idle Line Detect" },
410 { M6811_OR, "OR ", "Overrun Error" },
411 { M6811_NF, "NF ", "Noise Flag" },
412 { M6811_FE, "FE ", "Framing Error" },
413 { 0, 0, 0 }
416 io_reg_desc baud_desc[] = {
417 { M6811_TCLR, "TCLR ", "Clear baud rate (test mode)" },
418 { M6811_SCP1, "SCP1 ", "SCI baud rate prescaler select (SCP1)" },
419 { M6811_SCP0, "SCP0 ", "SCI baud rate prescaler select (SCP0)" },
420 { M6811_RCKB, "RCKB ", "Baur Rate Clock Check (test mode)" },
421 { M6811_SCR2, "SCR2 ", "SCI Baud rate select (SCR2)" },
422 { M6811_SCR1, "SCR1 ", "SCI Baud rate select (SCR1)" },
423 { M6811_SCR0, "SCR0 ", "SCI Baud rate select (SCR0)" },
424 { 0, 0, 0 }
427 static void
428 m68hc11sio_info (struct hw *me)
430 SIM_DESC sd;
431 uint16_t base = 0;
432 sim_cpu *cpu;
433 struct m68hc11_sim_cpu *m68hc11_cpu;
434 struct m68hc11sio *controller;
435 uint8_t val;
436 long clock_cycle;
438 sd = hw_system (me);
439 cpu = STATE_CPU (sd, 0);
440 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
441 controller = hw_data (me);
443 sim_io_printf (sd, "M68HC11 SIO:\n");
445 base = cpu_get_io_base (cpu);
447 val = m68hc11_cpu->ios[M6811_BAUD];
448 print_io_byte (sd, "BAUD ", baud_desc, val, base + M6811_BAUD);
449 sim_io_printf (sd, " (%ld baud)\n",
450 (m68hc11_cpu->cpu_frequency / 4) / controller->baud_cycle);
452 val = m68hc11_cpu->ios[M6811_SCCR1];
453 print_io_byte (sd, "SCCR1", sccr1_desc, val, base + M6811_SCCR1);
454 sim_io_printf (sd, " (%d bits) (%dN1)\n",
455 controller->data_length, controller->data_length - 2);
457 val = m68hc11_cpu->ios[M6811_SCCR2];
458 print_io_byte (sd, "SCCR2", sccr2_desc, val, base + M6811_SCCR2);
459 sim_io_printf (sd, "\n");
461 val = m68hc11_cpu->ios[M6811_SCSR];
462 print_io_byte (sd, "SCSR ", scsr_desc, val, base + M6811_SCSR);
463 sim_io_printf (sd, "\n");
465 clock_cycle = controller->data_length * controller->baud_cycle;
467 if (controller->tx_poll_event)
469 int64_t t;
470 int n;
472 t = hw_event_remain_time (me, controller->tx_poll_event);
473 n = (clock_cycle - t) / controller->baud_cycle;
474 n = controller->data_length - n;
475 sim_io_printf (sd, " Transmit finished in %s (%d bit%s)\n",
476 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE),
477 n, (n > 1 ? "s" : ""));
479 if (controller->rx_poll_event)
481 int64_t t;
483 t = hw_event_remain_time (me, controller->rx_poll_event);
484 sim_io_printf (sd, " Receive finished in %s\n",
485 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
490 static int
491 m68hc11sio_ioctl (struct hw *me,
492 hw_ioctl_request request,
493 va_list ap)
495 m68hc11sio_info (me);
496 return 0;
499 /* generic read/write */
501 static unsigned
502 m68hc11sio_io_read_buffer (struct hw *me,
503 void *dest,
504 int space,
505 unsigned_word base,
506 unsigned nr_bytes)
508 SIM_DESC sd;
509 struct m68hc11sio *controller;
510 sim_cpu *cpu;
511 struct m68hc11_sim_cpu *m68hc11_cpu;
512 uint8_t val;
514 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
516 sd = hw_system (me);
517 cpu = STATE_CPU (sd, 0);
518 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
519 controller = hw_data (me);
521 switch (base)
523 case M6811_SCSR:
524 controller->rx_clear_scsr = m68hc11_cpu->ios[M6811_SCSR]
525 & (M6811_RDRF | M6811_IDLE | M6811_OR | M6811_NF | M6811_FE);
527 case M6811_BAUD:
528 case M6811_SCCR1:
529 case M6811_SCCR2:
530 val = m68hc11_cpu->ios[base];
531 break;
533 case M6811_SCDR:
534 if (controller->rx_clear_scsr)
536 m68hc11_cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr;
538 val = controller->rx_char;
539 break;
541 default:
542 return 0;
544 *((uint8_t*) dest) = val;
545 return 1;
548 static unsigned
549 m68hc11sio_io_write_buffer (struct hw *me,
550 const void *source,
551 int space,
552 unsigned_word base,
553 unsigned nr_bytes)
555 SIM_DESC sd;
556 struct m68hc11sio *controller;
557 sim_cpu *cpu;
558 struct m68hc11_sim_cpu *m68hc11_cpu;
559 uint8_t val;
561 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
563 sd = hw_system (me);
564 cpu = STATE_CPU (sd, 0);
565 m68hc11_cpu = M68HC11_SIM_CPU (cpu);
566 controller = hw_data (me);
568 val = *((const uint8_t*) source);
569 switch (base)
571 case M6811_BAUD:
573 long divisor;
574 long baud;
576 m68hc11_cpu->ios[M6811_BAUD] = val;
577 switch (val & (M6811_SCP1|M6811_SCP0))
579 case M6811_BAUD_DIV_1:
580 divisor = 1 * 16;
581 break;
583 case M6811_BAUD_DIV_3:
584 divisor = 3 * 16;
585 break;
587 case M6811_BAUD_DIV_4:
588 divisor = 4 * 16;
589 break;
591 default:
592 case M6811_BAUD_DIV_13:
593 divisor = 13 * 16;
594 break;
596 val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0);
597 divisor *= (1 << val);
599 baud = (m68hc11_cpu->cpu_frequency / 4) / divisor;
601 HW_TRACE ((me, "divide rate %ld, baud rate %ld",
602 divisor, baud));
604 controller->baud_cycle = divisor;
606 break;
608 case M6811_SCCR1:
610 if (val & M6811_M)
611 controller->data_length = 11;
612 else
613 controller->data_length = 10;
615 m68hc11_cpu->ios[M6811_SCCR1] = val;
617 break;
619 case M6811_SCCR2:
620 if ((val & M6811_RE) == 0)
622 val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF);
623 val |= (m68hc11_cpu->ios[M6811_SCCR2]
624 & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF));
625 m68hc11_cpu->ios[M6811_SCCR2] = val;
626 break;
629 /* Activate reception. */
630 if (controller->rx_poll_event == 0)
632 long clock_cycle;
634 /* Compute CPU clock cycles to wait for the next character. */
635 clock_cycle = controller->data_length * controller->baud_cycle;
637 controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
638 m68hc11sio_rx_poll,
639 NULL);
641 m68hc11_cpu->ios[M6811_SCCR2] = val;
642 interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
643 break;
645 /* No effect. */
646 case M6811_SCSR:
647 return 1;
649 case M6811_SCDR:
650 if (!(m68hc11_cpu->ios[M6811_SCSR] & M6811_TDRE))
652 return 0;
655 controller->tx_char = val;
656 controller->tx_has_char = 1;
657 if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE)
658 && controller->tx_poll_event == 0)
660 m68hc11sio_tx_poll (me, NULL);
662 return 1;
664 default:
665 return 0;
667 return nr_bytes;
671 const struct hw_descriptor dv_m68hc11sio_descriptor[] = {
672 { "m68hc11sio", m68hc11sio_finish },
673 { "m68hc12sio", m68hc11sio_finish },
674 { NULL },