📄 dv-m68hc11sio.c
字号:
/* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device. Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. Written by Stephane Carrez (stcarrez@worldnet.fr) (From a driver model Contributed by Cygnus Solutions.) This file is part of the program GDB, the GNU debugger. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "sim-main.h"#include "hw-main.h"#include "dv-sockser.h"#include "sim-assert.h"/* DEVICE m68hc11sio - m68hc11 serial I/O DESCRIPTION Implements the m68hc11 serial I/O controller described in the m68hc11 user guide. The serial I/O controller is directly connected to the CPU interrupt. The simulator implements: - baud rate emulation - 8-bits transfers PROPERTIES backend {tcp | stdio} Use dv-sockser TCP-port backend or stdio for backend. Default: stdio. PORTS reset (input) Reset port. This port is only used to simulate a reset of the serial I/O controller. It should be connected to the RESET output of the cpu. *//* port ID's */enum{ RESET_PORT};static const struct hw_port_descriptor m68hc11sio_ports[] = { { "reset", RESET_PORT, 0, input_port, }, { NULL, },};/* Serial Controller information. */struct m68hc11sio { enum {sio_tcp, sio_stdio} backend; /* backend */ /* Number of cpu cycles to send a bit on the wire. */ unsigned long baud_cycle; /* Length in bits of characters sent, this includes the start/stop and parity bits. Together with baud_cycle, this is used to find the number of cpu cycles to send/receive a data. */ unsigned int data_length; /* Information about next character to be transmited. */ unsigned char tx_has_char; unsigned char tx_char; unsigned char rx_char; unsigned char rx_clear_scsr; /* Periodic I/O polling. */ struct hw_event* tx_poll_event; struct hw_event* rx_poll_event;};/* Finish off the partially created hw device. Attach our local callbacks. Wire up our port names etc. */static hw_io_read_buffer_method m68hc11sio_io_read_buffer;static hw_io_write_buffer_method m68hc11sio_io_write_buffer;static hw_port_event_method m68hc11sio_port_event;static hw_ioctl_method m68hc11sio_ioctl;#define M6811_SCI_FIRST_REG (M6811_BAUD)#define M6811_SCI_LAST_REG (M6811_SCDR)static voidattach_m68hc11sio_regs (struct hw *me, struct m68hc11sio *controller){ hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_SCI_FIRST_REG, M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1, me); if (hw_find_property(me, "backend") != NULL) { const char *value = hw_find_string_property(me, "backend"); if(! strcmp(value, "tcp")) controller->backend = sio_tcp; else if(! strcmp(value, "stdio")) controller->backend = sio_stdio; else hw_abort (me, "illegal value for backend parameter `%s':" "use tcp or stdio", value); }}static voidm68hc11sio_finish (struct hw *me){ struct m68hc11sio *controller; controller = HW_ZALLOC (me, struct m68hc11sio); set_hw_data (me, controller); set_hw_io_read_buffer (me, m68hc11sio_io_read_buffer); set_hw_io_write_buffer (me, m68hc11sio_io_write_buffer); set_hw_ports (me, m68hc11sio_ports); set_hw_port_event (me, m68hc11sio_port_event);#ifdef set_hw_ioctl set_hw_ioctl (me, m68hc11sio_ioctl);#else me->to_ioctl = m68hc11sio_ioctl;#endif /* Preset defaults. */ controller->backend = sio_stdio; /* Attach ourself to our parent bus. */ attach_m68hc11sio_regs (me, controller); /* Initialize to reset state. */ controller->tx_poll_event = NULL; controller->rx_poll_event = NULL; controller->tx_char = 0; controller->tx_has_char = 0; controller->rx_clear_scsr = 0; controller->rx_char = 0;}/* An event arrives on an interrupt port. */static voidm68hc11sio_port_event (struct hw *me, int my_port, struct hw *source, int source_port, int level){ SIM_DESC sd; struct m68hc11sio *controller; sim_cpu *cpu; unsigned8 val; controller = hw_data (me); sd = hw_system (me); cpu = STATE_CPU (sd, 0); switch (my_port) { case RESET_PORT: { HW_TRACE ((me, "SCI reset")); /* Reset the state of SCI registers. */ val = 0; m68hc11sio_io_write_buffer (me, &val, io_map, (unsigned_word) M6811_BAUD, 1); m68hc11sio_io_write_buffer (me, &val, io_map, (unsigned_word) M6811_SCCR1, 1); m68hc11sio_io_write_buffer (me, &val, io_map, (unsigned_word) M6811_SCCR2, 1); cpu->ios[M6811_SCSR] = M6811_TC | M6811_TDRE; controller->rx_char = 0; controller->tx_char = 0; controller->tx_has_char = 0; controller->rx_clear_scsr = 0; if (controller->rx_poll_event) { hw_event_queue_deschedule (me, controller->rx_poll_event); controller->rx_poll_event = 0; } if (controller->tx_poll_event) { hw_event_queue_deschedule (me, controller->tx_poll_event); controller->tx_poll_event = 0; } /* In bootstrap mode, initialize the SCI to 1200 bauds to simulate some initial setup by the internal rom. */ if (((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD) { unsigned char val = 0x33; m68hc11sio_io_write_buffer (me, &val, io_map, (unsigned_word) M6811_BAUD, 1); val = 0x12; m68hc11sio_io_write_buffer (me, &val, io_map, (unsigned_word) M6811_SCCR2, 1); } break; } default: hw_abort (me, "Event on unknown port %d", my_port); break; }}voidm68hc11sio_rx_poll (struct hw *me, void *data){ SIM_DESC sd; struct m68hc11sio *controller; sim_cpu *cpu; char cc; int cnt; int check_interrupt = 0; controller = hw_data (me); sd = hw_system (me); cpu = STATE_CPU (sd, 0); switch (controller->backend) { case sio_tcp: cnt = dv_sockser_read (sd); if (cnt != -1) { cc = (char) cnt; cnt = 1; } break; case sio_stdio: cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1); break; default: cnt = 0; break; } if (cnt == 1) { /* Raise the overrun flag if the previous character was not read. */ if (cpu->ios[M6811_SCSR] & M6811_RDRF) cpu->ios[M6811_SCSR] |= M6811_OR; cpu->ios[M6811_SCSR] |= M6811_RDRF; controller->rx_char = cc; controller->rx_clear_scsr = 0; check_interrupt = 1; } else { /* handle idle line detect here. */ ; } if (controller->rx_poll_event) { hw_event_queue_deschedule (me, controller->rx_poll_event); controller->rx_poll_event = 0; } if (cpu->ios[M6811_SCCR2] & M6811_RE) { unsigned long clock_cycle; /* Compute CPU clock cycles to wait for the next character. */ clock_cycle = controller->data_length * controller->baud_cycle; controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle, m68hc11sio_rx_poll, NULL); } if (check_interrupt) interrupts_update_pending (&cpu->cpu_interrupts);}voidm68hc11sio_tx_poll (struct hw *me, void *data){ SIM_DESC sd; struct m68hc11sio *controller; sim_cpu *cpu; controller = hw_data (me); sd = hw_system (me); cpu = STATE_CPU (sd, 0); cpu->ios[M6811_SCSR] |= M6811_TDRE; cpu->ios[M6811_SCSR] |= M6811_TC; /* Transmitter is enabled and we have something to send. */ if ((cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -