14e98e3e1Schristos /* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device. 2*5ba1f45fSchristos Copyright (C) 1999-2024 Free Software Foundation, Inc. 34e98e3e1Schristos Written by Stephane Carrez (stcarrez@worldnet.fr) 44e98e3e1Schristos (From a driver model Contributed by Cygnus Solutions.) 54e98e3e1Schristos 64e98e3e1Schristos This file is part of the program GDB, the GNU debugger. 74e98e3e1Schristos 84e98e3e1Schristos This program is free software; you can redistribute it and/or modify 94e98e3e1Schristos it under the terms of the GNU General Public License as published by 104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 114e98e3e1Schristos (at your option) any later version. 124e98e3e1Schristos 134e98e3e1Schristos This program is distributed in the hope that it will be useful, 144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164e98e3e1Schristos GNU General Public License for more details. 174e98e3e1Schristos 184e98e3e1Schristos You should have received a copy of the GNU General Public License 194e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. 204e98e3e1Schristos 214e98e3e1Schristos */ 224e98e3e1Schristos 234b169a6bSchristos /* This must come before any other includes. */ 244b169a6bSchristos #include "defs.h" 254e98e3e1Schristos 264e98e3e1Schristos #include "sim-main.h" 274e98e3e1Schristos #include "hw-main.h" 284e98e3e1Schristos #include "dv-sockser.h" 294e98e3e1Schristos #include "sim-assert.h" 304e98e3e1Schristos 31*5ba1f45fSchristos #include "m68hc11-sim.h" 324e98e3e1Schristos 334e98e3e1Schristos /* DEVICE 344e98e3e1Schristos 354e98e3e1Schristos m68hc11sio - m68hc11 serial I/O 364e98e3e1Schristos 374e98e3e1Schristos 384e98e3e1Schristos DESCRIPTION 394e98e3e1Schristos 404e98e3e1Schristos Implements the m68hc11 serial I/O controller described in the m68hc11 414e98e3e1Schristos user guide. The serial I/O controller is directly connected to the CPU 424e98e3e1Schristos interrupt. The simulator implements: 434e98e3e1Schristos 444e98e3e1Schristos - baud rate emulation 454e98e3e1Schristos - 8-bits transfers 464e98e3e1Schristos 474e98e3e1Schristos PROPERTIES 484e98e3e1Schristos 494e98e3e1Schristos backend {tcp | stdio} 504e98e3e1Schristos 514e98e3e1Schristos Use dv-sockser TCP-port backend or stdio for backend. Default: stdio. 524e98e3e1Schristos 534e98e3e1Schristos 544e98e3e1Schristos PORTS 554e98e3e1Schristos 564e98e3e1Schristos reset (input) 574e98e3e1Schristos 584e98e3e1Schristos Reset port. This port is only used to simulate a reset of the serial 594e98e3e1Schristos I/O controller. It should be connected to the RESET output of the cpu. 604e98e3e1Schristos 614e98e3e1Schristos */ 624e98e3e1Schristos 634e98e3e1Schristos 644e98e3e1Schristos 654e98e3e1Schristos /* port ID's */ 664e98e3e1Schristos 674e98e3e1Schristos enum 684e98e3e1Schristos { 694e98e3e1Schristos RESET_PORT 704e98e3e1Schristos }; 714e98e3e1Schristos 724e98e3e1Schristos 734e98e3e1Schristos static const struct hw_port_descriptor m68hc11sio_ports[] = 744e98e3e1Schristos { 754e98e3e1Schristos { "reset", RESET_PORT, 0, input_port, }, 764e98e3e1Schristos { NULL, }, 774e98e3e1Schristos }; 784e98e3e1Schristos 794e98e3e1Schristos 804e98e3e1Schristos /* Serial Controller information. */ 814e98e3e1Schristos struct m68hc11sio 824e98e3e1Schristos { 834e98e3e1Schristos enum {sio_tcp, sio_stdio} backend; /* backend */ 844e98e3e1Schristos 854e98e3e1Schristos /* Number of cpu cycles to send a bit on the wire. */ 864e98e3e1Schristos unsigned long baud_cycle; 874e98e3e1Schristos 884e98e3e1Schristos /* Length in bits of characters sent, this includes the 894e98e3e1Schristos start/stop and parity bits. Together with baud_cycle, this 904e98e3e1Schristos is used to find the number of cpu cycles to send/receive a data. */ 914e98e3e1Schristos unsigned int data_length; 924e98e3e1Schristos 934e98e3e1Schristos /* Information about next character to be transmited. */ 944e98e3e1Schristos unsigned char tx_has_char; 954e98e3e1Schristos unsigned char tx_char; 964e98e3e1Schristos 974e98e3e1Schristos unsigned char rx_char; 984e98e3e1Schristos unsigned char rx_clear_scsr; 994e98e3e1Schristos 1004e98e3e1Schristos /* Periodic I/O polling. */ 1014e98e3e1Schristos struct hw_event* tx_poll_event; 1024e98e3e1Schristos struct hw_event* rx_poll_event; 1034e98e3e1Schristos }; 1044e98e3e1Schristos 1054e98e3e1Schristos 1064e98e3e1Schristos 1074e98e3e1Schristos /* Finish off the partially created hw device. Attach our local 1084e98e3e1Schristos callbacks. Wire up our port names etc. */ 1094e98e3e1Schristos 1104e98e3e1Schristos static hw_io_read_buffer_method m68hc11sio_io_read_buffer; 1114e98e3e1Schristos static hw_io_write_buffer_method m68hc11sio_io_write_buffer; 1124e98e3e1Schristos static hw_port_event_method m68hc11sio_port_event; 1134e98e3e1Schristos static hw_ioctl_method m68hc11sio_ioctl; 1144e98e3e1Schristos 1154e98e3e1Schristos #define M6811_SCI_FIRST_REG (M6811_BAUD) 1164e98e3e1Schristos #define M6811_SCI_LAST_REG (M6811_SCDR) 1174e98e3e1Schristos 1184e98e3e1Schristos 1194e98e3e1Schristos static void 1204e98e3e1Schristos attach_m68hc11sio_regs (struct hw *me, 1214e98e3e1Schristos struct m68hc11sio *controller) 1224e98e3e1Schristos { 1234e98e3e1Schristos hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, 1244e98e3e1Schristos M6811_SCI_FIRST_REG, 1254e98e3e1Schristos M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1, 1264e98e3e1Schristos me); 1274e98e3e1Schristos 1284e98e3e1Schristos if (hw_find_property(me, "backend") != NULL) 1294e98e3e1Schristos { 1304e98e3e1Schristos const char *value = hw_find_string_property(me, "backend"); 1314e98e3e1Schristos if(! strcmp(value, "tcp")) 1324e98e3e1Schristos controller->backend = sio_tcp; 1334e98e3e1Schristos else if(! strcmp(value, "stdio")) 1344e98e3e1Schristos controller->backend = sio_stdio; 1354e98e3e1Schristos else 1364e98e3e1Schristos hw_abort (me, "illegal value for backend parameter `%s':" 1374e98e3e1Schristos "use tcp or stdio", value); 1384e98e3e1Schristos } 1394e98e3e1Schristos } 1404e98e3e1Schristos 1414e98e3e1Schristos 1424e98e3e1Schristos static void 1434e98e3e1Schristos m68hc11sio_finish (struct hw *me) 1444e98e3e1Schristos { 1454e98e3e1Schristos struct m68hc11sio *controller; 1464e98e3e1Schristos 1474e98e3e1Schristos controller = HW_ZALLOC (me, struct m68hc11sio); 1484e98e3e1Schristos set_hw_data (me, controller); 1494e98e3e1Schristos set_hw_io_read_buffer (me, m68hc11sio_io_read_buffer); 1504e98e3e1Schristos set_hw_io_write_buffer (me, m68hc11sio_io_write_buffer); 1514e98e3e1Schristos set_hw_ports (me, m68hc11sio_ports); 1524e98e3e1Schristos set_hw_port_event (me, m68hc11sio_port_event); 1534e98e3e1Schristos #ifdef set_hw_ioctl 1544e98e3e1Schristos set_hw_ioctl (me, m68hc11sio_ioctl); 1554e98e3e1Schristos #else 1564e98e3e1Schristos me->to_ioctl = m68hc11sio_ioctl; 1574e98e3e1Schristos #endif 1584e98e3e1Schristos 1594e98e3e1Schristos /* Preset defaults. */ 1604e98e3e1Schristos controller->backend = sio_stdio; 1614e98e3e1Schristos 1624e98e3e1Schristos /* Attach ourself to our parent bus. */ 1634e98e3e1Schristos attach_m68hc11sio_regs (me, controller); 1644e98e3e1Schristos 1654e98e3e1Schristos /* Initialize to reset state. */ 1664e98e3e1Schristos controller->tx_poll_event = NULL; 1674e98e3e1Schristos controller->rx_poll_event = NULL; 1684e98e3e1Schristos controller->tx_char = 0; 1694e98e3e1Schristos controller->tx_has_char = 0; 1704e98e3e1Schristos controller->rx_clear_scsr = 0; 1714e98e3e1Schristos controller->rx_char = 0; 1724e98e3e1Schristos } 1734e98e3e1Schristos 1744e98e3e1Schristos 1754e98e3e1Schristos 1764e98e3e1Schristos /* An event arrives on an interrupt port. */ 1774e98e3e1Schristos 1784e98e3e1Schristos static void 1794e98e3e1Schristos m68hc11sio_port_event (struct hw *me, 1804e98e3e1Schristos int my_port, 1814e98e3e1Schristos struct hw *source, 1824e98e3e1Schristos int source_port, 1834e98e3e1Schristos int level) 1844e98e3e1Schristos { 1854e98e3e1Schristos SIM_DESC sd; 1864e98e3e1Schristos struct m68hc11sio *controller; 1874e98e3e1Schristos sim_cpu *cpu; 188*5ba1f45fSchristos struct m68hc11_sim_cpu *m68hc11_cpu; 1894b169a6bSchristos uint8_t val; 1904e98e3e1Schristos 1914e98e3e1Schristos controller = hw_data (me); 1924e98e3e1Schristos sd = hw_system (me); 1934e98e3e1Schristos cpu = STATE_CPU (sd, 0); 194*5ba1f45fSchristos m68hc11_cpu = M68HC11_SIM_CPU (cpu); 1954e98e3e1Schristos switch (my_port) 1964e98e3e1Schristos { 1974e98e3e1Schristos case RESET_PORT: 1984e98e3e1Schristos { 1994e98e3e1Schristos HW_TRACE ((me, "SCI reset")); 2004e98e3e1Schristos 2014e98e3e1Schristos /* Reset the state of SCI registers. */ 2024e98e3e1Schristos val = 0; 2034e98e3e1Schristos m68hc11sio_io_write_buffer (me, &val, io_map, 2044e98e3e1Schristos (unsigned_word) M6811_BAUD, 1); 2054e98e3e1Schristos m68hc11sio_io_write_buffer (me, &val, io_map, 2064e98e3e1Schristos (unsigned_word) M6811_SCCR1, 1); 2074e98e3e1Schristos m68hc11sio_io_write_buffer (me, &val, io_map, 2084e98e3e1Schristos (unsigned_word) M6811_SCCR2, 1); 2094e98e3e1Schristos 210*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] = M6811_TC | M6811_TDRE; 2114e98e3e1Schristos controller->rx_char = 0; 2124e98e3e1Schristos controller->tx_char = 0; 2134e98e3e1Schristos controller->tx_has_char = 0; 2144e98e3e1Schristos controller->rx_clear_scsr = 0; 2154e98e3e1Schristos if (controller->rx_poll_event) 2164e98e3e1Schristos { 2174e98e3e1Schristos hw_event_queue_deschedule (me, controller->rx_poll_event); 2184e98e3e1Schristos controller->rx_poll_event = 0; 2194e98e3e1Schristos } 2204e98e3e1Schristos if (controller->tx_poll_event) 2214e98e3e1Schristos { 2224e98e3e1Schristos hw_event_queue_deschedule (me, controller->tx_poll_event); 2234e98e3e1Schristos controller->tx_poll_event = 0; 2244e98e3e1Schristos } 2254e98e3e1Schristos 2264e98e3e1Schristos /* In bootstrap mode, initialize the SCI to 1200 bauds to 2274e98e3e1Schristos simulate some initial setup by the internal rom. */ 228*5ba1f45fSchristos if (((m68hc11_cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD) 2294e98e3e1Schristos { 230*5ba1f45fSchristos val = 0x33; 2314e98e3e1Schristos 2324e98e3e1Schristos m68hc11sio_io_write_buffer (me, &val, io_map, 2334e98e3e1Schristos (unsigned_word) M6811_BAUD, 1); 2344e98e3e1Schristos val = 0x12; 2354e98e3e1Schristos m68hc11sio_io_write_buffer (me, &val, io_map, 2364e98e3e1Schristos (unsigned_word) M6811_SCCR2, 1); 2374e98e3e1Schristos } 2384e98e3e1Schristos break; 2394e98e3e1Schristos } 2404e98e3e1Schristos 2414e98e3e1Schristos default: 2424e98e3e1Schristos hw_abort (me, "Event on unknown port %d", my_port); 2434e98e3e1Schristos break; 2444e98e3e1Schristos } 2454e98e3e1Schristos } 2464e98e3e1Schristos 2474e98e3e1Schristos 248796c32c9Schristos static void 2494e98e3e1Schristos m68hc11sio_rx_poll (struct hw *me, void *data) 2504e98e3e1Schristos { 2514e98e3e1Schristos SIM_DESC sd; 2524e98e3e1Schristos struct m68hc11sio *controller; 2534e98e3e1Schristos sim_cpu *cpu; 254*5ba1f45fSchristos struct m68hc11_sim_cpu *m68hc11_cpu; 2554e98e3e1Schristos char cc; 2564e98e3e1Schristos int cnt; 2574e98e3e1Schristos int check_interrupt = 0; 2584e98e3e1Schristos 2594e98e3e1Schristos controller = hw_data (me); 2604e98e3e1Schristos sd = hw_system (me); 2614e98e3e1Schristos cpu = STATE_CPU (sd, 0); 262*5ba1f45fSchristos m68hc11_cpu = M68HC11_SIM_CPU (cpu); 2634e98e3e1Schristos switch (controller->backend) 2644e98e3e1Schristos { 2654e98e3e1Schristos case sio_tcp: 2664e98e3e1Schristos cnt = dv_sockser_read (sd); 2674e98e3e1Schristos if (cnt != -1) 2684e98e3e1Schristos { 2694e98e3e1Schristos cc = (char) cnt; 2704e98e3e1Schristos cnt = 1; 2714e98e3e1Schristos } 2724e98e3e1Schristos break; 2734e98e3e1Schristos 2744e98e3e1Schristos case sio_stdio: 2754e98e3e1Schristos cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1); 2764e98e3e1Schristos break; 2774e98e3e1Schristos 2784e98e3e1Schristos default: 2794e98e3e1Schristos cnt = 0; 2804e98e3e1Schristos break; 2814e98e3e1Schristos } 2824e98e3e1Schristos 2834e98e3e1Schristos if (cnt == 1) 2844e98e3e1Schristos { 2854e98e3e1Schristos /* Raise the overrun flag if the previous character was not read. */ 286*5ba1f45fSchristos if (m68hc11_cpu->ios[M6811_SCSR] & M6811_RDRF) 287*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] |= M6811_OR; 2884e98e3e1Schristos 289*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] |= M6811_RDRF; 2904e98e3e1Schristos controller->rx_char = cc; 2914e98e3e1Schristos controller->rx_clear_scsr = 0; 2924e98e3e1Schristos check_interrupt = 1; 2934e98e3e1Schristos } 2944e98e3e1Schristos else 2954e98e3e1Schristos { 2964e98e3e1Schristos /* handle idle line detect here. */ 2974e98e3e1Schristos ; 2984e98e3e1Schristos } 2994e98e3e1Schristos 3004e98e3e1Schristos if (controller->rx_poll_event) 3014e98e3e1Schristos { 3024e98e3e1Schristos hw_event_queue_deschedule (me, controller->rx_poll_event); 3034e98e3e1Schristos controller->rx_poll_event = 0; 3044e98e3e1Schristos } 3054e98e3e1Schristos 306*5ba1f45fSchristos if (m68hc11_cpu->ios[M6811_SCCR2] & M6811_RE) 3074e98e3e1Schristos { 3084e98e3e1Schristos unsigned long clock_cycle; 3094e98e3e1Schristos 3104e98e3e1Schristos /* Compute CPU clock cycles to wait for the next character. */ 3114e98e3e1Schristos clock_cycle = controller->data_length * controller->baud_cycle; 3124e98e3e1Schristos 3134e98e3e1Schristos controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle, 3144e98e3e1Schristos m68hc11sio_rx_poll, 3154e98e3e1Schristos NULL); 3164e98e3e1Schristos } 3174e98e3e1Schristos 3184e98e3e1Schristos if (check_interrupt) 319*5ba1f45fSchristos interrupts_update_pending (&m68hc11_cpu->cpu_interrupts); 3204e98e3e1Schristos } 3214e98e3e1Schristos 3224e98e3e1Schristos 323796c32c9Schristos static void 3244e98e3e1Schristos m68hc11sio_tx_poll (struct hw *me, void *data) 3254e98e3e1Schristos { 3264e98e3e1Schristos SIM_DESC sd; 3274e98e3e1Schristos struct m68hc11sio *controller; 3284e98e3e1Schristos sim_cpu *cpu; 329*5ba1f45fSchristos struct m68hc11_sim_cpu *m68hc11_cpu; 3304e98e3e1Schristos 3314e98e3e1Schristos controller = hw_data (me); 3324e98e3e1Schristos sd = hw_system (me); 3334e98e3e1Schristos cpu = STATE_CPU (sd, 0); 334*5ba1f45fSchristos m68hc11_cpu = M68HC11_SIM_CPU (cpu); 3354e98e3e1Schristos 336*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] |= M6811_TDRE; 337*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] |= M6811_TC; 3384e98e3e1Schristos 3394e98e3e1Schristos /* Transmitter is enabled and we have something to send. */ 340*5ba1f45fSchristos if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char) 3414e98e3e1Schristos { 342*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] &= ~M6811_TDRE; 343*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] &= ~M6811_TC; 3444e98e3e1Schristos controller->tx_has_char = 0; 3454e98e3e1Schristos switch (controller->backend) 3464e98e3e1Schristos { 3474e98e3e1Schristos case sio_tcp: 3484e98e3e1Schristos dv_sockser_write (sd, controller->tx_char); 3494e98e3e1Schristos break; 3504e98e3e1Schristos 3514e98e3e1Schristos case sio_stdio: 3524b169a6bSchristos sim_io_write_stdout (sd, (const char *)&controller->tx_char, 1); 3534e98e3e1Schristos sim_io_flush_stdout (sd); 3544e98e3e1Schristos break; 3554e98e3e1Schristos 3564e98e3e1Schristos default: 3574e98e3e1Schristos break; 3584e98e3e1Schristos } 3594e98e3e1Schristos } 3604e98e3e1Schristos 3614e98e3e1Schristos if (controller->tx_poll_event) 3624e98e3e1Schristos { 3634e98e3e1Schristos hw_event_queue_deschedule (me, controller->tx_poll_event); 3644e98e3e1Schristos controller->tx_poll_event = 0; 3654e98e3e1Schristos } 3664e98e3e1Schristos 367*5ba1f45fSchristos if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE) 368*5ba1f45fSchristos && ((m68hc11_cpu->ios[M6811_SCSR] & M6811_TC) == 0)) 3694e98e3e1Schristos { 3704e98e3e1Schristos unsigned long clock_cycle; 3714e98e3e1Schristos 3724e98e3e1Schristos /* Compute CPU clock cycles to wait for the next character. */ 3734e98e3e1Schristos clock_cycle = controller->data_length * controller->baud_cycle; 3744e98e3e1Schristos 3754e98e3e1Schristos controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle, 3764e98e3e1Schristos m68hc11sio_tx_poll, 3774e98e3e1Schristos NULL); 3784e98e3e1Schristos } 3794e98e3e1Schristos 380*5ba1f45fSchristos interrupts_update_pending (&m68hc11_cpu->cpu_interrupts); 3814e98e3e1Schristos } 3824e98e3e1Schristos 3834e98e3e1Schristos /* Descriptions of the SIO I/O ports. These descriptions are only used to 3844e98e3e1Schristos give information of the SIO device under GDB. */ 3854e98e3e1Schristos io_reg_desc sccr2_desc[] = { 3864e98e3e1Schristos { M6811_TIE, "TIE ", "Transmit Interrupt Enable" }, 3874e98e3e1Schristos { M6811_TCIE, "TCIE ", "Transmit Complete Interrupt Enable" }, 3884e98e3e1Schristos { M6811_RIE, "RIE ", "Receive Interrupt Enable" }, 3894e98e3e1Schristos { M6811_ILIE, "ILIE ", "Idle Line Interrupt Enable" }, 3904e98e3e1Schristos { M6811_TE, "TE ", "Transmit Enable" }, 3914e98e3e1Schristos { M6811_RE, "RE ", "Receive Enable" }, 3924e98e3e1Schristos { M6811_RWU, "RWU ", "Receiver Wake Up" }, 3934e98e3e1Schristos { M6811_SBK, "SBRK ", "Send Break" }, 3944e98e3e1Schristos { 0, 0, 0 } 3954e98e3e1Schristos }; 3964e98e3e1Schristos 3974e98e3e1Schristos io_reg_desc sccr1_desc[] = { 3984e98e3e1Schristos { M6811_R8, "R8 ", "Receive Data bit 8" }, 3994e98e3e1Schristos { M6811_T8, "T8 ", "Transmit Data bit 8" }, 4004e98e3e1Schristos { M6811_M, "M ", "SCI Character length (0=8-bits, 1=9-bits)" }, 4014e98e3e1Schristos { M6811_WAKE, "WAKE ", "Wake up method select (0=idle, 1=addr mark" }, 4024e98e3e1Schristos { 0, 0, 0 } 4034e98e3e1Schristos }; 4044e98e3e1Schristos 4054e98e3e1Schristos io_reg_desc scsr_desc[] = { 4064e98e3e1Schristos { M6811_TDRE, "TDRE ", "Transmit Data Register Empty" }, 4074e98e3e1Schristos { M6811_TC, "TC ", "Transmit Complete" }, 4084e98e3e1Schristos { M6811_RDRF, "RDRF ", "Receive Data Register Full" }, 4094e98e3e1Schristos { M6811_IDLE, "IDLE ", "Idle Line Detect" }, 4104e98e3e1Schristos { M6811_OR, "OR ", "Overrun Error" }, 4114e98e3e1Schristos { M6811_NF, "NF ", "Noise Flag" }, 4124e98e3e1Schristos { M6811_FE, "FE ", "Framing Error" }, 4134e98e3e1Schristos { 0, 0, 0 } 4144e98e3e1Schristos }; 4154e98e3e1Schristos 4164e98e3e1Schristos io_reg_desc baud_desc[] = { 4174e98e3e1Schristos { M6811_TCLR, "TCLR ", "Clear baud rate (test mode)" }, 4184e98e3e1Schristos { M6811_SCP1, "SCP1 ", "SCI baud rate prescaler select (SCP1)" }, 4194e98e3e1Schristos { M6811_SCP0, "SCP0 ", "SCI baud rate prescaler select (SCP0)" }, 4204e98e3e1Schristos { M6811_RCKB, "RCKB ", "Baur Rate Clock Check (test mode)" }, 4214e98e3e1Schristos { M6811_SCR2, "SCR2 ", "SCI Baud rate select (SCR2)" }, 4224e98e3e1Schristos { M6811_SCR1, "SCR1 ", "SCI Baud rate select (SCR1)" }, 4234e98e3e1Schristos { M6811_SCR0, "SCR0 ", "SCI Baud rate select (SCR0)" }, 4244e98e3e1Schristos { 0, 0, 0 } 4254e98e3e1Schristos }; 4264e98e3e1Schristos 4274e98e3e1Schristos static void 4284e98e3e1Schristos m68hc11sio_info (struct hw *me) 4294e98e3e1Schristos { 4304e98e3e1Schristos SIM_DESC sd; 4314b169a6bSchristos uint16_t base = 0; 4324e98e3e1Schristos sim_cpu *cpu; 433*5ba1f45fSchristos struct m68hc11_sim_cpu *m68hc11_cpu; 4344e98e3e1Schristos struct m68hc11sio *controller; 4354b169a6bSchristos uint8_t val; 4364e98e3e1Schristos long clock_cycle; 4374e98e3e1Schristos 4384e98e3e1Schristos sd = hw_system (me); 4394e98e3e1Schristos cpu = STATE_CPU (sd, 0); 440*5ba1f45fSchristos m68hc11_cpu = M68HC11_SIM_CPU (cpu); 4414e98e3e1Schristos controller = hw_data (me); 4424e98e3e1Schristos 4434e98e3e1Schristos sim_io_printf (sd, "M68HC11 SIO:\n"); 4444e98e3e1Schristos 4454e98e3e1Schristos base = cpu_get_io_base (cpu); 4464e98e3e1Schristos 447*5ba1f45fSchristos val = m68hc11_cpu->ios[M6811_BAUD]; 4484e98e3e1Schristos print_io_byte (sd, "BAUD ", baud_desc, val, base + M6811_BAUD); 4494e98e3e1Schristos sim_io_printf (sd, " (%ld baud)\n", 450*5ba1f45fSchristos (m68hc11_cpu->cpu_frequency / 4) / controller->baud_cycle); 4514e98e3e1Schristos 452*5ba1f45fSchristos val = m68hc11_cpu->ios[M6811_SCCR1]; 4534e98e3e1Schristos print_io_byte (sd, "SCCR1", sccr1_desc, val, base + M6811_SCCR1); 4544e98e3e1Schristos sim_io_printf (sd, " (%d bits) (%dN1)\n", 4554e98e3e1Schristos controller->data_length, controller->data_length - 2); 4564e98e3e1Schristos 457*5ba1f45fSchristos val = m68hc11_cpu->ios[M6811_SCCR2]; 4584e98e3e1Schristos print_io_byte (sd, "SCCR2", sccr2_desc, val, base + M6811_SCCR2); 4594e98e3e1Schristos sim_io_printf (sd, "\n"); 4604e98e3e1Schristos 461*5ba1f45fSchristos val = m68hc11_cpu->ios[M6811_SCSR]; 4624e98e3e1Schristos print_io_byte (sd, "SCSR ", scsr_desc, val, base + M6811_SCSR); 4634e98e3e1Schristos sim_io_printf (sd, "\n"); 4644e98e3e1Schristos 4654e98e3e1Schristos clock_cycle = controller->data_length * controller->baud_cycle; 4664e98e3e1Schristos 4674e98e3e1Schristos if (controller->tx_poll_event) 4684e98e3e1Schristos { 4694b169a6bSchristos int64_t t; 4704e98e3e1Schristos int n; 4714e98e3e1Schristos 4724e98e3e1Schristos t = hw_event_remain_time (me, controller->tx_poll_event); 4734e98e3e1Schristos n = (clock_cycle - t) / controller->baud_cycle; 4744e98e3e1Schristos n = controller->data_length - n; 4754e98e3e1Schristos sim_io_printf (sd, " Transmit finished in %s (%d bit%s)\n", 4764e98e3e1Schristos cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE), 4774e98e3e1Schristos n, (n > 1 ? "s" : "")); 4784e98e3e1Schristos } 4794e98e3e1Schristos if (controller->rx_poll_event) 4804e98e3e1Schristos { 4814b169a6bSchristos int64_t t; 4824e98e3e1Schristos 4834e98e3e1Schristos t = hw_event_remain_time (me, controller->rx_poll_event); 4844e98e3e1Schristos sim_io_printf (sd, " Receive finished in %s\n", 4854e98e3e1Schristos cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE)); 4864e98e3e1Schristos } 4874e98e3e1Schristos 4884e98e3e1Schristos } 4894e98e3e1Schristos 4904e98e3e1Schristos static int 4914e98e3e1Schristos m68hc11sio_ioctl (struct hw *me, 4924e98e3e1Schristos hw_ioctl_request request, 4934e98e3e1Schristos va_list ap) 4944e98e3e1Schristos { 4954e98e3e1Schristos m68hc11sio_info (me); 4964e98e3e1Schristos return 0; 4974e98e3e1Schristos } 4984e98e3e1Schristos 4994e98e3e1Schristos /* generic read/write */ 5004e98e3e1Schristos 5014e98e3e1Schristos static unsigned 5024e98e3e1Schristos m68hc11sio_io_read_buffer (struct hw *me, 5034e98e3e1Schristos void *dest, 5044e98e3e1Schristos int space, 5054e98e3e1Schristos unsigned_word base, 5064e98e3e1Schristos unsigned nr_bytes) 5074e98e3e1Schristos { 5084e98e3e1Schristos SIM_DESC sd; 5094e98e3e1Schristos struct m68hc11sio *controller; 5104e98e3e1Schristos sim_cpu *cpu; 511*5ba1f45fSchristos struct m68hc11_sim_cpu *m68hc11_cpu; 5124b169a6bSchristos uint8_t val; 5134e98e3e1Schristos 5144e98e3e1Schristos HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); 5154e98e3e1Schristos 5164e98e3e1Schristos sd = hw_system (me); 5174e98e3e1Schristos cpu = STATE_CPU (sd, 0); 518*5ba1f45fSchristos m68hc11_cpu = M68HC11_SIM_CPU (cpu); 5194e98e3e1Schristos controller = hw_data (me); 5204e98e3e1Schristos 5214e98e3e1Schristos switch (base) 5224e98e3e1Schristos { 5234e98e3e1Schristos case M6811_SCSR: 524*5ba1f45fSchristos controller->rx_clear_scsr = m68hc11_cpu->ios[M6811_SCSR] 5254e98e3e1Schristos & (M6811_RDRF | M6811_IDLE | M6811_OR | M6811_NF | M6811_FE); 526*5ba1f45fSchristos ATTRIBUTE_FALLTHROUGH; 5274e98e3e1Schristos 5284e98e3e1Schristos case M6811_BAUD: 5294e98e3e1Schristos case M6811_SCCR1: 5304e98e3e1Schristos case M6811_SCCR2: 531*5ba1f45fSchristos val = m68hc11_cpu->ios[base]; 5324e98e3e1Schristos break; 5334e98e3e1Schristos 5344e98e3e1Schristos case M6811_SCDR: 5354e98e3e1Schristos if (controller->rx_clear_scsr) 5364e98e3e1Schristos { 537*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr; 5384e98e3e1Schristos } 5394e98e3e1Schristos val = controller->rx_char; 5404e98e3e1Schristos break; 5414e98e3e1Schristos 5424e98e3e1Schristos default: 5434e98e3e1Schristos return 0; 5444e98e3e1Schristos } 5454b169a6bSchristos *((uint8_t*) dest) = val; 5464e98e3e1Schristos return 1; 5474e98e3e1Schristos } 5484e98e3e1Schristos 5494e98e3e1Schristos static unsigned 5504e98e3e1Schristos m68hc11sio_io_write_buffer (struct hw *me, 5514e98e3e1Schristos const void *source, 5524e98e3e1Schristos int space, 5534e98e3e1Schristos unsigned_word base, 5544e98e3e1Schristos unsigned nr_bytes) 5554e98e3e1Schristos { 5564e98e3e1Schristos SIM_DESC sd; 5574e98e3e1Schristos struct m68hc11sio *controller; 5584e98e3e1Schristos sim_cpu *cpu; 559*5ba1f45fSchristos struct m68hc11_sim_cpu *m68hc11_cpu; 5604b169a6bSchristos uint8_t val; 5614e98e3e1Schristos 5624e98e3e1Schristos HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); 5634e98e3e1Schristos 5644e98e3e1Schristos sd = hw_system (me); 5654e98e3e1Schristos cpu = STATE_CPU (sd, 0); 566*5ba1f45fSchristos m68hc11_cpu = M68HC11_SIM_CPU (cpu); 5674e98e3e1Schristos controller = hw_data (me); 5684e98e3e1Schristos 5694b169a6bSchristos val = *((const uint8_t*) source); 5704e98e3e1Schristos switch (base) 5714e98e3e1Schristos { 5724e98e3e1Schristos case M6811_BAUD: 5734e98e3e1Schristos { 5744e98e3e1Schristos long divisor; 5754e98e3e1Schristos long baud; 5764e98e3e1Schristos 577*5ba1f45fSchristos m68hc11_cpu->ios[M6811_BAUD] = val; 5784e98e3e1Schristos switch (val & (M6811_SCP1|M6811_SCP0)) 5794e98e3e1Schristos { 5804e98e3e1Schristos case M6811_BAUD_DIV_1: 5814e98e3e1Schristos divisor = 1 * 16; 5824e98e3e1Schristos break; 5834e98e3e1Schristos 5844e98e3e1Schristos case M6811_BAUD_DIV_3: 5854e98e3e1Schristos divisor = 3 * 16; 5864e98e3e1Schristos break; 5874e98e3e1Schristos 5884e98e3e1Schristos case M6811_BAUD_DIV_4: 5894e98e3e1Schristos divisor = 4 * 16; 5904e98e3e1Schristos break; 5914e98e3e1Schristos 5924e98e3e1Schristos default: 5934e98e3e1Schristos case M6811_BAUD_DIV_13: 5944e98e3e1Schristos divisor = 13 * 16; 5954e98e3e1Schristos break; 5964e98e3e1Schristos } 5974e98e3e1Schristos val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0); 5984e98e3e1Schristos divisor *= (1 << val); 5994e98e3e1Schristos 600*5ba1f45fSchristos baud = (m68hc11_cpu->cpu_frequency / 4) / divisor; 6014e98e3e1Schristos 6024e98e3e1Schristos HW_TRACE ((me, "divide rate %ld, baud rate %ld", 6034e98e3e1Schristos divisor, baud)); 6044e98e3e1Schristos 6054e98e3e1Schristos controller->baud_cycle = divisor; 6064e98e3e1Schristos } 6074e98e3e1Schristos break; 6084e98e3e1Schristos 6094e98e3e1Schristos case M6811_SCCR1: 6104e98e3e1Schristos { 6114e98e3e1Schristos if (val & M6811_M) 6124e98e3e1Schristos controller->data_length = 11; 6134e98e3e1Schristos else 6144e98e3e1Schristos controller->data_length = 10; 6154e98e3e1Schristos 616*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCCR1] = val; 6174e98e3e1Schristos } 6184e98e3e1Schristos break; 6194e98e3e1Schristos 6204e98e3e1Schristos case M6811_SCCR2: 6214e98e3e1Schristos if ((val & M6811_RE) == 0) 6224e98e3e1Schristos { 6234e98e3e1Schristos val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF); 624*5ba1f45fSchristos val |= (m68hc11_cpu->ios[M6811_SCCR2] 6254e98e3e1Schristos & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF)); 626*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCCR2] = val; 6274e98e3e1Schristos break; 6284e98e3e1Schristos } 6294e98e3e1Schristos 6304e98e3e1Schristos /* Activate reception. */ 6314e98e3e1Schristos if (controller->rx_poll_event == 0) 6324e98e3e1Schristos { 6334e98e3e1Schristos long clock_cycle; 6344e98e3e1Schristos 6354e98e3e1Schristos /* Compute CPU clock cycles to wait for the next character. */ 6364e98e3e1Schristos clock_cycle = controller->data_length * controller->baud_cycle; 6374e98e3e1Schristos 6384e98e3e1Schristos controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle, 6394e98e3e1Schristos m68hc11sio_rx_poll, 6404e98e3e1Schristos NULL); 6414e98e3e1Schristos } 642*5ba1f45fSchristos m68hc11_cpu->ios[M6811_SCCR2] = val; 643*5ba1f45fSchristos interrupts_update_pending (&m68hc11_cpu->cpu_interrupts); 6444e98e3e1Schristos break; 6454e98e3e1Schristos 6464e98e3e1Schristos /* No effect. */ 6474e98e3e1Schristos case M6811_SCSR: 6484e98e3e1Schristos return 1; 6494e98e3e1Schristos 6504e98e3e1Schristos case M6811_SCDR: 651*5ba1f45fSchristos if (!(m68hc11_cpu->ios[M6811_SCSR] & M6811_TDRE)) 6524e98e3e1Schristos { 6534e98e3e1Schristos return 0; 6544e98e3e1Schristos } 6554e98e3e1Schristos 6564e98e3e1Schristos controller->tx_char = val; 6574e98e3e1Schristos controller->tx_has_char = 1; 658*5ba1f45fSchristos if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE) 6594e98e3e1Schristos && controller->tx_poll_event == 0) 6604e98e3e1Schristos { 6614e98e3e1Schristos m68hc11sio_tx_poll (me, NULL); 6624e98e3e1Schristos } 6634e98e3e1Schristos return 1; 6644e98e3e1Schristos 6654e98e3e1Schristos default: 6664e98e3e1Schristos return 0; 6674e98e3e1Schristos } 6684e98e3e1Schristos return nr_bytes; 6694e98e3e1Schristos } 6704e98e3e1Schristos 6714e98e3e1Schristos 6724e98e3e1Schristos const struct hw_descriptor dv_m68hc11sio_descriptor[] = { 6734e98e3e1Schristos { "m68hc11sio", m68hc11sio_finish }, 6744e98e3e1Schristos { "m68hc12sio", m68hc11sio_finish }, 6754e98e3e1Schristos { NULL }, 6764e98e3e1Schristos }; 6774e98e3e1Schristos 678