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. */
28 #include "dv-sockser.h"
29 #include "sim-assert.h"
31 #include "m68hc11-sim.h"
35 m68hc11sio - m68hc11 serial I/O
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:
51 Use dv-sockser TCP-port backend or stdio for backend. Default: stdio.
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.
73 static const struct hw_port_descriptor m68hc11sio_ports
[] =
75 { "reset", RESET_PORT
, 0, input_port
, },
80 /* Serial Controller information. */
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)
120 attach_m68hc11sio_regs (struct hw
*me
,
121 struct m68hc11sio
*controller
)
123 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
, io_map
,
125 M6811_SCI_LAST_REG
- M6811_SCI_FIRST_REG
+ 1,
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
;
136 hw_abort (me
, "illegal value for backend parameter `%s':"
137 "use tcp or stdio", value
);
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
);
154 set_hw_ioctl (me
, m68hc11sio_ioctl
);
156 me
->to_ioctl
= m68hc11sio_ioctl
;
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. */
179 m68hc11sio_port_event (struct hw
*me
,
186 struct m68hc11sio
*controller
;
188 struct m68hc11_sim_cpu
*m68hc11_cpu
;
191 controller
= hw_data (me
);
193 cpu
= STATE_CPU (sd
, 0);
194 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
199 HW_TRACE ((me
, "SCI reset"));
201 /* Reset the state of SCI registers. */
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);
235 m68hc11sio_io_write_buffer (me
, &val
, io_map
,
236 (unsigned_word
) M6811_SCCR2
, 1);
242 hw_abort (me
, "Event on unknown port %d", my_port
);
249 m68hc11sio_rx_poll (struct hw
*me
, void *data
)
252 struct m68hc11sio
*controller
;
254 struct m68hc11_sim_cpu
*m68hc11_cpu
;
257 int check_interrupt
= 0;
259 controller
= hw_data (me
);
261 cpu
= STATE_CPU (sd
, 0);
262 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
263 switch (controller
->backend
)
266 cnt
= dv_sockser_read (sd
);
275 cnt
= sim_io_poll_read (sd
, 0 /* stdin */, &cc
, 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;
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
,
319 interrupts_update_pending (&m68hc11_cpu
->cpu_interrupts
);
324 m68hc11sio_tx_poll (struct hw
*me
, void *data
)
327 struct m68hc11sio
*controller
;
329 struct m68hc11_sim_cpu
*m68hc11_cpu
;
331 controller
= hw_data (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
)
348 dv_sockser_write (sd
, controller
->tx_char
);
352 sim_io_write_stdout (sd
, (const char *)&controller
->tx_char
, 1);
353 sim_io_flush_stdout (sd
);
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
,
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" },
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" },
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" },
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)" },
428 m68hc11sio_info (struct hw
*me
)
433 struct m68hc11_sim_cpu
*m68hc11_cpu
;
434 struct m68hc11sio
*controller
;
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
)
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
)
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
));
491 m68hc11sio_ioctl (struct hw
*me
,
492 hw_ioctl_request request
,
495 m68hc11sio_info (me
);
499 /* generic read/write */
502 m68hc11sio_io_read_buffer (struct hw
*me
,
509 struct m68hc11sio
*controller
;
511 struct m68hc11_sim_cpu
*m68hc11_cpu
;
514 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
517 cpu
= STATE_CPU (sd
, 0);
518 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
519 controller
= hw_data (me
);
524 controller
->rx_clear_scsr
= m68hc11_cpu
->ios
[M6811_SCSR
]
525 & (M6811_RDRF
| M6811_IDLE
| M6811_OR
| M6811_NF
| M6811_FE
);
530 val
= m68hc11_cpu
->ios
[base
];
534 if (controller
->rx_clear_scsr
)
536 m68hc11_cpu
->ios
[M6811_SCSR
] &= ~controller
->rx_clear_scsr
;
538 val
= controller
->rx_char
;
544 *((uint8_t*) dest
) = val
;
549 m68hc11sio_io_write_buffer (struct hw
*me
,
556 struct m68hc11sio
*controller
;
558 struct m68hc11_sim_cpu
*m68hc11_cpu
;
561 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
564 cpu
= STATE_CPU (sd
, 0);
565 m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
566 controller
= hw_data (me
);
568 val
= *((const uint8_t*) source
);
576 m68hc11_cpu
->ios
[M6811_BAUD
] = val
;
577 switch (val
& (M6811_SCP1
|M6811_SCP0
))
579 case M6811_BAUD_DIV_1
:
583 case M6811_BAUD_DIV_3
:
587 case M6811_BAUD_DIV_4
:
592 case M6811_BAUD_DIV_13
:
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",
604 controller
->baud_cycle
= divisor
;
611 controller
->data_length
= 11;
613 controller
->data_length
= 10;
615 m68hc11_cpu
->ios
[M6811_SCCR1
] = val
;
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
;
629 /* Activate reception. */
630 if (controller
->rx_poll_event
== 0)
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
,
641 m68hc11_cpu
->ios
[M6811_SCCR2
] = val
;
642 interrupts_update_pending (&m68hc11_cpu
->cpu_interrupts
);
650 if (!(m68hc11_cpu
->ios
[M6811_SCSR
] & M6811_TDRE
))
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
);
671 const struct hw_descriptor dv_m68hc11sio_descriptor
[] = {
672 { "m68hc11sio", m68hc11sio_finish
},
673 { "m68hc12sio", m68hc11sio_finish
},