mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-21 04:42:53 +08:00
1d506c26d9
This commit is the result of the following actions: - Running gdb/copyright.py to update all of the copyright headers to include 2024, - Manually updating a few files the copyright.py script told me to update, these files had copyright headers embedded within the file, - Regenerating gdbsupport/Makefile.in to refresh it's copyright date, - Using grep to find other files that still mentioned 2023. If these files were updated last year from 2022 to 2023 then I've updated them this year to 2024. I'm sure I've probably missed some dates. Feel free to fix them up as you spot them.
678 lines
18 KiB
C
678 lines
18 KiB
C
/* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
|
|
Copyright (C) 1999-2024 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
/* This must come before any other includes. */
|
|
#include "defs.h"
|
|
|
|
#include "sim-main.h"
|
|
#include "hw-main.h"
|
|
#include "dv-sockser.h"
|
|
#include "sim-assert.h"
|
|
|
|
#include "m68hc11-sim.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 void
|
|
attach_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 void
|
|
m68hc11sio_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 void
|
|
m68hc11sio_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;
|
|
struct m68hc11_sim_cpu *m68hc11_cpu;
|
|
uint8_t val;
|
|
|
|
controller = hw_data (me);
|
|
sd = hw_system (me);
|
|
cpu = STATE_CPU (sd, 0);
|
|
m68hc11_cpu = M68HC11_SIM_CPU (cpu);
|
|
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);
|
|
|
|
m68hc11_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 (((m68hc11_cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
m68hc11sio_rx_poll (struct hw *me, void *data)
|
|
{
|
|
SIM_DESC sd;
|
|
struct m68hc11sio *controller;
|
|
sim_cpu *cpu;
|
|
struct m68hc11_sim_cpu *m68hc11_cpu;
|
|
char cc;
|
|
int cnt;
|
|
int check_interrupt = 0;
|
|
|
|
controller = hw_data (me);
|
|
sd = hw_system (me);
|
|
cpu = STATE_CPU (sd, 0);
|
|
m68hc11_cpu = M68HC11_SIM_CPU (cpu);
|
|
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 (m68hc11_cpu->ios[M6811_SCSR] & M6811_RDRF)
|
|
m68hc11_cpu->ios[M6811_SCSR] |= M6811_OR;
|
|
|
|
m68hc11_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 (m68hc11_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 (&m68hc11_cpu->cpu_interrupts);
|
|
}
|
|
|
|
|
|
static void
|
|
m68hc11sio_tx_poll (struct hw *me, void *data)
|
|
{
|
|
SIM_DESC sd;
|
|
struct m68hc11sio *controller;
|
|
sim_cpu *cpu;
|
|
struct m68hc11_sim_cpu *m68hc11_cpu;
|
|
|
|
controller = hw_data (me);
|
|
sd = hw_system (me);
|
|
cpu = STATE_CPU (sd, 0);
|
|
m68hc11_cpu = M68HC11_SIM_CPU (cpu);
|
|
|
|
m68hc11_cpu->ios[M6811_SCSR] |= M6811_TDRE;
|
|
m68hc11_cpu->ios[M6811_SCSR] |= M6811_TC;
|
|
|
|
/* Transmitter is enabled and we have something to send. */
|
|
if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char)
|
|
{
|
|
m68hc11_cpu->ios[M6811_SCSR] &= ~M6811_TDRE;
|
|
m68hc11_cpu->ios[M6811_SCSR] &= ~M6811_TC;
|
|
controller->tx_has_char = 0;
|
|
switch (controller->backend)
|
|
{
|
|
case sio_tcp:
|
|
dv_sockser_write (sd, controller->tx_char);
|
|
break;
|
|
|
|
case sio_stdio:
|
|
sim_io_write_stdout (sd, (const char *)&controller->tx_char, 1);
|
|
sim_io_flush_stdout (sd);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (controller->tx_poll_event)
|
|
{
|
|
hw_event_queue_deschedule (me, controller->tx_poll_event);
|
|
controller->tx_poll_event = 0;
|
|
}
|
|
|
|
if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE)
|
|
&& ((m68hc11_cpu->ios[M6811_SCSR] & M6811_TC) == 0))
|
|
{
|
|
unsigned long clock_cycle;
|
|
|
|
/* Compute CPU clock cycles to wait for the next character. */
|
|
clock_cycle = controller->data_length * controller->baud_cycle;
|
|
|
|
controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle,
|
|
m68hc11sio_tx_poll,
|
|
NULL);
|
|
}
|
|
|
|
interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
|
|
}
|
|
|
|
/* Descriptions of the SIO I/O ports. These descriptions are only used to
|
|
give information of the SIO device under GDB. */
|
|
io_reg_desc sccr2_desc[] = {
|
|
{ M6811_TIE, "TIE ", "Transmit Interrupt Enable" },
|
|
{ M6811_TCIE, "TCIE ", "Transmit Complete Interrupt Enable" },
|
|
{ M6811_RIE, "RIE ", "Receive Interrupt Enable" },
|
|
{ M6811_ILIE, "ILIE ", "Idle Line Interrupt Enable" },
|
|
{ M6811_TE, "TE ", "Transmit Enable" },
|
|
{ M6811_RE, "RE ", "Receive Enable" },
|
|
{ M6811_RWU, "RWU ", "Receiver Wake Up" },
|
|
{ M6811_SBK, "SBRK ", "Send Break" },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
io_reg_desc sccr1_desc[] = {
|
|
{ M6811_R8, "R8 ", "Receive Data bit 8" },
|
|
{ M6811_T8, "T8 ", "Transmit Data bit 8" },
|
|
{ M6811_M, "M ", "SCI Character length (0=8-bits, 1=9-bits)" },
|
|
{ M6811_WAKE, "WAKE ", "Wake up method select (0=idle, 1=addr mark" },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
io_reg_desc scsr_desc[] = {
|
|
{ M6811_TDRE, "TDRE ", "Transmit Data Register Empty" },
|
|
{ M6811_TC, "TC ", "Transmit Complete" },
|
|
{ M6811_RDRF, "RDRF ", "Receive Data Register Full" },
|
|
{ M6811_IDLE, "IDLE ", "Idle Line Detect" },
|
|
{ M6811_OR, "OR ", "Overrun Error" },
|
|
{ M6811_NF, "NF ", "Noise Flag" },
|
|
{ M6811_FE, "FE ", "Framing Error" },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
io_reg_desc baud_desc[] = {
|
|
{ M6811_TCLR, "TCLR ", "Clear baud rate (test mode)" },
|
|
{ M6811_SCP1, "SCP1 ", "SCI baud rate prescaler select (SCP1)" },
|
|
{ M6811_SCP0, "SCP0 ", "SCI baud rate prescaler select (SCP0)" },
|
|
{ M6811_RCKB, "RCKB ", "Baur Rate Clock Check (test mode)" },
|
|
{ M6811_SCR2, "SCR2 ", "SCI Baud rate select (SCR2)" },
|
|
{ M6811_SCR1, "SCR1 ", "SCI Baud rate select (SCR1)" },
|
|
{ M6811_SCR0, "SCR0 ", "SCI Baud rate select (SCR0)" },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
static void
|
|
m68hc11sio_info (struct hw *me)
|
|
{
|
|
SIM_DESC sd;
|
|
uint16_t base = 0;
|
|
sim_cpu *cpu;
|
|
struct m68hc11_sim_cpu *m68hc11_cpu;
|
|
struct m68hc11sio *controller;
|
|
uint8_t val;
|
|
long clock_cycle;
|
|
|
|
sd = hw_system (me);
|
|
cpu = STATE_CPU (sd, 0);
|
|
m68hc11_cpu = M68HC11_SIM_CPU (cpu);
|
|
controller = hw_data (me);
|
|
|
|
sim_io_printf (sd, "M68HC11 SIO:\n");
|
|
|
|
base = cpu_get_io_base (cpu);
|
|
|
|
val = m68hc11_cpu->ios[M6811_BAUD];
|
|
print_io_byte (sd, "BAUD ", baud_desc, val, base + M6811_BAUD);
|
|
sim_io_printf (sd, " (%ld baud)\n",
|
|
(m68hc11_cpu->cpu_frequency / 4) / controller->baud_cycle);
|
|
|
|
val = m68hc11_cpu->ios[M6811_SCCR1];
|
|
print_io_byte (sd, "SCCR1", sccr1_desc, val, base + M6811_SCCR1);
|
|
sim_io_printf (sd, " (%d bits) (%dN1)\n",
|
|
controller->data_length, controller->data_length - 2);
|
|
|
|
val = m68hc11_cpu->ios[M6811_SCCR2];
|
|
print_io_byte (sd, "SCCR2", sccr2_desc, val, base + M6811_SCCR2);
|
|
sim_io_printf (sd, "\n");
|
|
|
|
val = m68hc11_cpu->ios[M6811_SCSR];
|
|
print_io_byte (sd, "SCSR ", scsr_desc, val, base + M6811_SCSR);
|
|
sim_io_printf (sd, "\n");
|
|
|
|
clock_cycle = controller->data_length * controller->baud_cycle;
|
|
|
|
if (controller->tx_poll_event)
|
|
{
|
|
int64_t t;
|
|
int n;
|
|
|
|
t = hw_event_remain_time (me, controller->tx_poll_event);
|
|
n = (clock_cycle - t) / controller->baud_cycle;
|
|
n = controller->data_length - n;
|
|
sim_io_printf (sd, " Transmit finished in %s (%d bit%s)\n",
|
|
cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE),
|
|
n, (n > 1 ? "s" : ""));
|
|
}
|
|
if (controller->rx_poll_event)
|
|
{
|
|
int64_t t;
|
|
|
|
t = hw_event_remain_time (me, controller->rx_poll_event);
|
|
sim_io_printf (sd, " Receive finished in %s\n",
|
|
cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
|
|
}
|
|
|
|
}
|
|
|
|
static int
|
|
m68hc11sio_ioctl (struct hw *me,
|
|
hw_ioctl_request request,
|
|
va_list ap)
|
|
{
|
|
m68hc11sio_info (me);
|
|
return 0;
|
|
}
|
|
|
|
/* generic read/write */
|
|
|
|
static unsigned
|
|
m68hc11sio_io_read_buffer (struct hw *me,
|
|
void *dest,
|
|
int space,
|
|
unsigned_word base,
|
|
unsigned nr_bytes)
|
|
{
|
|
SIM_DESC sd;
|
|
struct m68hc11sio *controller;
|
|
sim_cpu *cpu;
|
|
struct m68hc11_sim_cpu *m68hc11_cpu;
|
|
uint8_t val;
|
|
|
|
HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
|
|
|
|
sd = hw_system (me);
|
|
cpu = STATE_CPU (sd, 0);
|
|
m68hc11_cpu = M68HC11_SIM_CPU (cpu);
|
|
controller = hw_data (me);
|
|
|
|
switch (base)
|
|
{
|
|
case M6811_SCSR:
|
|
controller->rx_clear_scsr = m68hc11_cpu->ios[M6811_SCSR]
|
|
& (M6811_RDRF | M6811_IDLE | M6811_OR | M6811_NF | M6811_FE);
|
|
ATTRIBUTE_FALLTHROUGH;
|
|
|
|
case M6811_BAUD:
|
|
case M6811_SCCR1:
|
|
case M6811_SCCR2:
|
|
val = m68hc11_cpu->ios[base];
|
|
break;
|
|
|
|
case M6811_SCDR:
|
|
if (controller->rx_clear_scsr)
|
|
{
|
|
m68hc11_cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr;
|
|
}
|
|
val = controller->rx_char;
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
*((uint8_t*) dest) = val;
|
|
return 1;
|
|
}
|
|
|
|
static unsigned
|
|
m68hc11sio_io_write_buffer (struct hw *me,
|
|
const void *source,
|
|
int space,
|
|
unsigned_word base,
|
|
unsigned nr_bytes)
|
|
{
|
|
SIM_DESC sd;
|
|
struct m68hc11sio *controller;
|
|
sim_cpu *cpu;
|
|
struct m68hc11_sim_cpu *m68hc11_cpu;
|
|
uint8_t val;
|
|
|
|
HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
|
|
|
|
sd = hw_system (me);
|
|
cpu = STATE_CPU (sd, 0);
|
|
m68hc11_cpu = M68HC11_SIM_CPU (cpu);
|
|
controller = hw_data (me);
|
|
|
|
val = *((const uint8_t*) source);
|
|
switch (base)
|
|
{
|
|
case M6811_BAUD:
|
|
{
|
|
long divisor;
|
|
long baud;
|
|
|
|
m68hc11_cpu->ios[M6811_BAUD] = val;
|
|
switch (val & (M6811_SCP1|M6811_SCP0))
|
|
{
|
|
case M6811_BAUD_DIV_1:
|
|
divisor = 1 * 16;
|
|
break;
|
|
|
|
case M6811_BAUD_DIV_3:
|
|
divisor = 3 * 16;
|
|
break;
|
|
|
|
case M6811_BAUD_DIV_4:
|
|
divisor = 4 * 16;
|
|
break;
|
|
|
|
default:
|
|
case M6811_BAUD_DIV_13:
|
|
divisor = 13 * 16;
|
|
break;
|
|
}
|
|
val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0);
|
|
divisor *= (1 << val);
|
|
|
|
baud = (m68hc11_cpu->cpu_frequency / 4) / divisor;
|
|
|
|
HW_TRACE ((me, "divide rate %ld, baud rate %ld",
|
|
divisor, baud));
|
|
|
|
controller->baud_cycle = divisor;
|
|
}
|
|
break;
|
|
|
|
case M6811_SCCR1:
|
|
{
|
|
if (val & M6811_M)
|
|
controller->data_length = 11;
|
|
else
|
|
controller->data_length = 10;
|
|
|
|
m68hc11_cpu->ios[M6811_SCCR1] = val;
|
|
}
|
|
break;
|
|
|
|
case M6811_SCCR2:
|
|
if ((val & M6811_RE) == 0)
|
|
{
|
|
val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF);
|
|
val |= (m68hc11_cpu->ios[M6811_SCCR2]
|
|
& (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF));
|
|
m68hc11_cpu->ios[M6811_SCCR2] = val;
|
|
break;
|
|
}
|
|
|
|
/* Activate reception. */
|
|
if (controller->rx_poll_event == 0)
|
|
{
|
|
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);
|
|
}
|
|
m68hc11_cpu->ios[M6811_SCCR2] = val;
|
|
interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
|
|
break;
|
|
|
|
/* No effect. */
|
|
case M6811_SCSR:
|
|
return 1;
|
|
|
|
case M6811_SCDR:
|
|
if (!(m68hc11_cpu->ios[M6811_SCSR] & M6811_TDRE))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
controller->tx_char = val;
|
|
controller->tx_has_char = 1;
|
|
if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE)
|
|
&& controller->tx_poll_event == 0)
|
|
{
|
|
m68hc11sio_tx_poll (me, NULL);
|
|
}
|
|
return 1;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
return nr_bytes;
|
|
}
|
|
|
|
|
|
const struct hw_descriptor dv_m68hc11sio_descriptor[] = {
|
|
{ "m68hc11sio", m68hc11sio_finish },
|
|
{ "m68hc12sio", m68hc11sio_finish },
|
|
{ NULL },
|
|
};
|
|
|