X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Fmn10300%2Fdv-mn103ser.c;h=02d0aa54c766a3547586a9b260308fffba2bdc91;hb=d768f160a99558a07a2463899c8bfeec0f0a67a7;hp=041cf7a40b174e8f1004a4fcfc422e01e2a994f6;hpb=e98fe4f7b54cbdf29aef9287bbb1bea8801dd05a;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/mn10300/dv-mn103ser.c b/sim/mn10300/dv-mn103ser.c index 041cf7a40b..02d0aa54c7 100644 --- a/sim/mn10300/dv-mn103ser.c +++ b/sim/mn10300/dv-mn103ser.c @@ -1,26 +1,27 @@ /* This file is part of the program GDB, the GNU debugger. - Copyright (C) 1998 Free Software Foundation, Inc. + Copyright (C) 1998-2020 Free Software Foundation, Inc. Contributed by Cygnus Solutions. 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 + 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, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + along with this program. If not, see . */ #include "sim-main.h" #include "hw-main.h" +#include "dv-sockser.h" + /* DEVICE @@ -55,25 +56,40 @@ struct mn103ser_block { enum serial_register_types { SC0CTR, - SC0ICR, - SC0TXB, - SC0RXB, - SC0STR, SC1CTR, - SC1ICR, - SC1TXB, - SC1RXB, - SC1STR, SC2CTR, + SC0ICR, + SC1ICR, SC2ICR, + SC0TXB, + SC1TXB, SC2TXB, + SC0RXB, + SC1RXB, SC2RXB, + SC0STR, + SC1STR, SC2STR, + SC2TIM, }; +#define NR_SERIAL_DEVS 3 +#define SIO_STAT_RRDY 0x0010 + +typedef struct _mn10300_serial { + unsigned16 status, control; + unsigned8 txb, rxb, intmode; + struct hw_event *event; +} mn10300_serial; + + + struct mn103ser { struct mn103ser_block block; + mn10300_serial device[NR_SERIAL_DEVS]; + unsigned8 serial2_timer_reg; + do_hw_poll_read_method *reader; }; /* output port ID's */ @@ -81,10 +97,10 @@ struct mn103ser { /* for mn103002 */ enum { SERIAL0_RECEIVE, - SERIAL0_SEND, SERIAL1_RECEIVE, - SERIAL1_SEND, SERIAL2_RECEIVE, + SERIAL0_SEND, + SERIAL1_SEND, SERIAL2_SEND, }; @@ -92,10 +108,10 @@ enum { static const struct hw_port_descriptor mn103ser_ports[] = { { "serial-0-receive", SERIAL0_RECEIVE, 0, output_port, }, - { "serial-0-transmit", SERIAL0_SEND, 0, output_port, }, { "serial-1-receive", SERIAL1_RECEIVE, 0, output_port, }, - { "serial-1-transmit", SERIAL1_SEND, 0, output_port, }, { "serial-2-receive", SERIAL2_RECEIVE, 0, output_port, }, + { "serial-0-transmit", SERIAL0_SEND, 0, output_port, }, + { "serial-1-transmit", SERIAL1_SEND, 0, output_port, }, { "serial-2-transmit", SERIAL2_SEND, 0, output_port, }, { NULL, }, @@ -154,7 +170,27 @@ mn103ser_finish (struct hw *me) /* Attach ourself to our parent bus */ attach_mn103ser_regs (me, serial); + /* If so configured, enable polled input */ + if (hw_find_property (me, "poll?") != NULL + && hw_find_boolean_property (me, "poll?")) + { + serial->reader = sim_io_poll_read; + } + else + { + serial->reader = sim_io_read; + } + /* Initialize the serial device registers. */ + for ( i=0; idevice[i].txb = 0; + serial->device[i].rxb = 0; + serial->device[i].status = 0; + serial->device[i].control = 0; + serial->device[i].intmode = 0; + serial->device[i].event = NULL; + } } @@ -167,7 +203,6 @@ decode_addr (struct hw *me, { unsigned_word offset; offset = address - serial->block.base; - switch (offset) { case 0x00: return SC0CTR; @@ -185,6 +220,7 @@ decode_addr (struct hw *me, case 0x28: return SC2TXB; case 0x29: return SC2RXB; case 0x2C: return SC2STR; + case 0x2D: return SC2TIM; default: { hw_abort (me, "bad address"); @@ -193,53 +229,231 @@ decode_addr (struct hw *me, } } +static void +do_polling_event (struct hw *me, + void *data) +{ + SIM_DESC sd = hw_system (me); + struct mn103ser *serial = hw_data(me); + long serial_reg = (long) data; + char c; + int count, status; + + status = dv_sockser_status (sd); + if (!(status & DV_SOCKSER_DISCONNECTED)) + { + int rd; + rd = dv_sockser_read (sd); + if(rd != -1) + { + c = (char) rd; + count = 1; + } + else + { + count = HW_IO_NOT_READY; + } + } + else + { + count = do_hw_poll_read (me, serial->reader, + 0/*STDIN*/, &c, sizeof(c)); + } + + + switch (count) + { + case HW_IO_NOT_READY: + case HW_IO_EOF: + serial->device[serial_reg].rxb = 0; + serial->device[serial_reg].status &= ~SIO_STAT_RRDY; + break; + default: + serial->device[serial_reg].rxb = c; + serial->device[serial_reg].status |= SIO_STAT_RRDY; + hw_port_event (me, serial_reg+SERIAL0_RECEIVE, 1); + } + + /* Schedule next polling event */ + serial->device[serial_reg].event + = hw_event_queue_schedule (me, 1000, + do_polling_event, (void *)serial_reg); + +} + static void read_control_reg (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, void *dest, unsigned nr_bytes) { + /* really allow 1 byte read, too */ + if ( nr_bytes == 2 ) + { + *(unsigned16 *)dest = H2LE_2 (serial->device[serial_reg].control); + } + else + { + hw_abort (me, "bad read size of %d bytes from SC%dCTR.", nr_bytes, + serial_reg); + } } static void read_intmode_reg (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, void *dest, unsigned nr_bytes) { + if ( nr_bytes == 1 ) + { + *(unsigned8 *)dest = serial->device[serial_reg].intmode; + } + else + { + hw_abort (me, "bad read size of %d bytes from SC%dICR.", nr_bytes, + serial_reg); + } } static void read_txb (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, void *dest, unsigned nr_bytes) { + if ( nr_bytes == 1 ) + { + *(unsigned8 *)dest = serial->device[serial_reg].txb; + } + else + { + hw_abort (me, "bad read size of %d bytes from SC%dTXB.", nr_bytes, + serial_reg); + } } static void read_rxb (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, void *dest, unsigned nr_bytes) { + if ( nr_bytes == 1 ) + { + *(unsigned8 *)dest = serial->device[serial_reg].rxb; + /* Reception buffer is now empty. */ + serial->device[serial_reg].status &= ~SIO_STAT_RRDY; + } + else + { + hw_abort (me, "bad read size of %d bytes from SC%dRXB.", nr_bytes, + serial_reg); + } } static void read_status_reg (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, void *dest, unsigned nr_bytes) { + char c; + int count; + + if ( (serial->device[serial_reg].status & SIO_STAT_RRDY) == 0 ) + { + SIM_DESC sd = hw_system (me); + int status; + + /* FIFO is empty */ + /* Kill current poll event */ + if ( NULL != serial->device[serial_reg].event ) + { + hw_event_queue_deschedule (me, serial->device[serial_reg].event); + serial->device[serial_reg].event = NULL; + } + + status = dv_sockser_status (sd); + if (!(status & DV_SOCKSER_DISCONNECTED)) + { + int rd; + rd = dv_sockser_read (sd); + if(rd != -1) + { + c = (char) rd; + count = 1; + } + else + { + count = HW_IO_NOT_READY; + } + } + else + { + count = do_hw_poll_read (me, serial->reader, + 0/*STDIN*/, &c, sizeof(c)); + } + + switch (count) + { + case HW_IO_NOT_READY: + case HW_IO_EOF: + serial->device[serial_reg].rxb = 0; + serial->device[serial_reg].status &= ~SIO_STAT_RRDY; + break; + default: + serial->device[serial_reg].rxb = c; + serial->device[serial_reg].status |= SIO_STAT_RRDY; + hw_port_event (me, serial_reg+SERIAL0_RECEIVE, 1); + } + + /* schedule polling event */ + serial->device[serial_reg].event + = hw_event_queue_schedule (me, 1000, + do_polling_event, + (void *) (long) serial_reg); + } + + if ( nr_bytes == 1 ) + { + *(unsigned8 *)dest = (unsigned8)serial->device[serial_reg].status; + } + else if ( nr_bytes == 2 && serial_reg != SC2STR ) + { + *(unsigned16 *)dest = H2LE_2 (serial->device[serial_reg].status); + } + else + { + hw_abort (me, "bad read size of %d bytes from SC%dSTR.", nr_bytes, + serial_reg); + } +} + + +static void +read_serial2_timer_reg (struct hw *me, + struct mn103ser *serial, + void *dest, + unsigned nr_bytes) +{ + if ( nr_bytes == 1 ) + { + * (unsigned8 *) dest = (unsigned8) serial->serial2_timer_reg; + } + else + { + hw_abort (me, "bad read size of %d bytes to SC2TIM.", nr_bytes); + } } @@ -261,35 +475,50 @@ mn103ser_io_read_buffer (struct hw *me, case SC0CTR: case SC1CTR: case SC2CTR: - read_control_reg(me, serial, base, dest, nr_bytes); + read_control_reg(me, serial, serial_reg-SC0CTR, dest, nr_bytes); + HW_TRACE ((me, "read - ctrl reg%d has 0x%x\n", serial_reg-SC0CTR, + *(unsigned8 *)dest)); break; /* interrupt mode registers */ case SC0ICR: case SC1ICR: case SC2ICR: - read_intmode_reg(me, serial, base, dest, nr_bytes); + read_intmode_reg(me, serial, serial_reg-SC0ICR, dest, nr_bytes); + HW_TRACE ((me, "read - intmode reg%d has 0x%x\n", serial_reg-SC0ICR, + *(unsigned8 *)dest)); break; /* transmission buffers */ case SC0TXB: case SC1TXB: case SC2TXB: - read_txb(me, serial, base, dest, nr_bytes); + read_txb(me, serial, serial_reg-SC0TXB, dest, nr_bytes); + HW_TRACE ((me, "read - txb%d has %c\n", serial_reg-SC0TXB, + *(char *)dest)); break; /* reception buffers */ case SC0RXB: case SC1RXB: case SC2RXB: - read_rxb(me, serial, base, dest, nr_bytes); + read_rxb(me, serial, serial_reg-SC0RXB, dest, nr_bytes); + HW_TRACE ((me, "read - rxb%d has %c\n", serial_reg-SC0RXB, + *(char *)dest)); break; /* status registers */ case SC0STR: case SC1STR: case SC2STR: - read_status_reg(me, serial, base, dest, nr_bytes); + read_status_reg(me, serial, serial_reg-SC0STR, dest, nr_bytes); + HW_TRACE ((me, "read - status reg%d has 0x%x\n", serial_reg-SC0STR, + *(unsigned8 *)dest)); + break; + + case SC2TIM: + read_serial2_timer_reg(me, serial, dest, nr_bytes); + HW_TRACE ((me, "read - serial2 timer reg %d\n", *(unsigned8 *)dest)); break; default: @@ -303,50 +532,112 @@ mn103ser_io_read_buffer (struct hw *me, static void write_control_reg (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, const void *source, unsigned nr_bytes) { + unsigned16 val = LE2H_2 (*(unsigned16 *)source); + + /* really allow 1 byte write, too */ + if ( nr_bytes == 2 ) + { + if ( serial_reg == 2 && (val & 0x0C04) != 0 ) + { + hw_abort(me, "Cannot write to read-only bits of SC2CTR."); + } + else + { + serial->device[serial_reg].control = val; + } + } + else + { + hw_abort (me, "bad read size of %d bytes from SC%dSTR.", nr_bytes, + serial_reg); + } } static void write_intmode_reg (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, const void *source, unsigned nr_bytes) { -} - +unsigned8 val = *(unsigned8 *)source; -static void -write_txb (struct hw *me, - struct mn103ser *serial, - unsigned_word addr, - const void *source, - unsigned nr_bytes) -{ + if ( nr_bytes == 1 ) + { + /* Check for attempt to write to read-only bits of register. */ + if ( ( serial_reg == 2 && (val & 0xCA) != 0 ) + || ( serial_reg != 2 && (val & 0x4A) != 0 ) ) + { + hw_abort(me, "Cannot write to read-only bits of SC%dICR.", + serial_reg); + } + else + { + serial->device[serial_reg].intmode = val; + } + } + else + { + hw_abort (me, "bad write size of %d bytes to SC%dICR.", nr_bytes, + serial_reg); + } } static void -write_rxb (struct hw *me, +write_txb (struct hw *me, struct mn103ser *serial, - unsigned_word addr, + unsigned_word serial_reg, const void *source, unsigned nr_bytes) { + if ( nr_bytes == 1 ) + { + SIM_DESC sd = hw_system (me); + int status; + + serial->device[serial_reg].txb = *(unsigned8 *)source; + + status = dv_sockser_status (sd); + if (!(status & DV_SOCKSER_DISCONNECTED)) + { + dv_sockser_write(sd, * (char*) source); + } + else + { + sim_io_write_stdout(sd, (char *)source, 1); + sim_io_flush_stdout(sd); + } + + hw_port_event (me, serial_reg+SERIAL0_SEND, 1); + } + else + { + hw_abort (me, "bad write size of %d bytes to SC%dTXB.", nr_bytes, + serial_reg); + } } static void -write_status_reg (struct hw *me, - struct mn103ser *serial, - unsigned_word addr, - const void *source, - unsigned nr_bytes) +write_serial2_timer_reg (struct hw *me, + struct mn103ser *serial, + const void *source, + unsigned nr_bytes) { + if ( nr_bytes == 1 ) + { + serial->serial2_timer_reg = *(unsigned8 *)source; + } + else + { + hw_abort (me, "bad write size of %d bytes to SC2TIM.", nr_bytes); + } } @@ -368,35 +659,47 @@ mn103ser_io_write_buffer (struct hw *me, case SC0CTR: case SC1CTR: case SC2CTR: - write_control_reg(me, serial, base, source, nr_bytes); + HW_TRACE ((me, "write - ctrl reg%d has 0x%x, nrbytes=%d.\n", + serial_reg-SC0CTR, *(unsigned8 *)source, nr_bytes)); + write_control_reg(me, serial, serial_reg-SC0CTR, source, nr_bytes); break; /* interrupt mode registers */ case SC0ICR: case SC1ICR: case SC2ICR: - write_intmode_reg(me, serial, base, source, nr_bytes); + HW_TRACE ((me, "write - intmode reg%d has 0x%x, nrbytes=%d.\n", + serial_reg-SC0ICR, *(unsigned8 *)source, nr_bytes)); + write_intmode_reg(me, serial, serial_reg-SC0ICR, source, nr_bytes); break; /* transmission buffers */ case SC0TXB: case SC1TXB: case SC2TXB: - write_txb(me, serial, base, source, nr_bytes); + HW_TRACE ((me, "write - txb%d has %c, nrbytes=%d.\n", + serial_reg-SC0TXB, *(char *)source, nr_bytes)); + write_txb(me, serial, serial_reg-SC0TXB, source, nr_bytes); break; /* reception buffers */ case SC0RXB: case SC1RXB: case SC2RXB: - write_rxb(me, serial, base, source, nr_bytes); + hw_abort(me, "Cannot write to reception buffer."); break; /* status registers */ case SC0STR: case SC1STR: case SC2STR: - write_status_reg(me, serial, base, source, nr_bytes); + hw_abort(me, "Cannot write to status register."); + break; + + case SC2TIM: + HW_TRACE ((me, "read - serial2 timer reg %d (nrbytes=%d)\n", + *(unsigned8 *)source, nr_bytes)); + write_serial2_timer_reg(me, serial, source, nr_bytes); break; default: