diff options
Diffstat (limited to 'sim/ppc/hw_com.c')
-rw-r--r-- | sim/ppc/hw_com.c | 559 |
1 files changed, 0 insertions, 559 deletions
diff --git a/sim/ppc/hw_com.c b/sim/ppc/hw_com.c deleted file mode 100644 index ff8afe7..0000000 --- a/sim/ppc/hw_com.c +++ /dev/null @@ -1,559 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> - - 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. - - */ - - -#ifndef _HW_COM_C_ -#define _HW_COM_C_ - -#ifndef STATIC_INLINE_HW_COM -#define STATIC_INLINE_HW_COM STATIC_INLINE -#endif - -#include "device_table.h" - -#ifdef HAVE_STRING_H -#include <string.h> -#else -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif - -/* DEVICE - - - com - '550 compatible serial device - - - DESCRIPTION - - - Models the basics of the 8 register '550 serial device. The model - includes an interrupt line, input and output fifos, and status - information. - - Independent configuration of the devices input and output streams is - allowed: use either the console or a file (buffered or unbuffered) as - the data source/sink; specify the real-time delay between each character - transfer. - - When the devices input stream is being taken from a file, the end of - file is signaled by a loss of carrier (the loss of carrier may be - incorrectly proceeded by a single null character). - - - PROPERTIES - - - reg = <address> <size> ... (optional - note 1) - - List of <address> <size> pairs. Each pair specifies an address for - the devices 8 registers. The address should be 8 byte aligned. - - - alternate-reg = <address> <size> ... (optional - note 1) - - Alternative addreses for the registers. - - - assigned-addresses = <address> <size> ... (optional - note 1) - - On a PCI bus, this property specifies the addresses assigned to the - device. The values reflect the devices configuration base registers. - - Note 1: At least one of "assigned-addresses", "reg" or "alternative-reg" - must be specified. If "assigned-addresses" is specified the other - address specifications are ignored. - - - input-file = <file-name> (optional) - - File to take all serial port input from (instead of the simulation - console). - - - output-file = <file-name> (optional) - - File to send all output to (instead of the simulation console). - - - input-buffering = "unbuffered" (optional) - - Specifying "unbuffered" buffering disables buffering on the serial - devices input stream (all data is immediatly read). In the future, - this option may be used to provide input buffering alternatives. - - - output-buffering = "unbuffered" (optional) - - Specifying "unbuffered" buffering disables buffering on the serial - devices output stream (all data is immediatly written). In the future, - this option may be extended to include other buffering alternatives. - - - input-delay = <integer-delay> (optional) - - Specify the number of ticks after the current character has been - read from the serial port that the next character becomes - available. - - - output-delay = <integer-delay> (optional) - - Specify the number of ticks after a character has been written to - the empty output fifo that the fifo finishes draining. Any - characters written to the output fifo before it has drained will - not be lost and will still be displayed. - - - EXAMPLES - - - | /iobus@0xf0000000/com@0x3000/reg 0x3000 8 - - Create a simple console device at address <<0x3000>> within - <<iobus>>. Since iobus starts at address <<0xf0000000>> the - absolute address of the serial port will be <<0xf0003000>>. - - The device will always be ready for I/O (no delay properties specified) - and both the input and output streams will use the simulation console - (no file properties). - - - | $ psim \ - | -o '/cpus/cpu@0' \ - | -o '/iobus@0xf0000000/com@0x4000/reg 0x4000 8' \ - | -o '/iobus@0xf0000000/com@0x4000/input-file /etc/passwd' \ - | -o '/iobus@0xf0000000/com@0x4000/input-delay 1000' \ - | -o '/iobus@0xf0000000/com@0x4000 > 0 int /cpus/cpu@0x0' \ - | psim-test/hw-com/cat.be 0xf0004000 - - The serial port (at address <<0xf0004000>> is configured so that it - takes its input from the file <</etc/passwd>> while its output is - allowed to appear on the simulation console. - - The node <</cpus/cpu@0>> was explicitly specified to ensure that it had - been created before any interrupts were attached to it. - - The program <<psim-test/hw-com/cat>> copies any characters on the serial - port's input (<</etc/passwd>>) to its output (the console). - Consequently, the aove program will display the contents of the file - <</etc/passwd>> on the screen. - - - BUGS - - - IEEE 1275 requires that a device on a PCI bus have, as its first reg - entry, the address of its configuration space registers. Currently, - this device does not even implement configuration registers. - - This model does not attempt to model the '550's input and output fifos. - Instead, the input fifo is limited to a single character at a time, - while the output fifo is effectivly infinite. Consequently, unlike the - '550, this device will not discard output characters once a stream of 16 - have been written to the data output register. - - The input and output can only be taken from a file (or the current - terminal device). In the future, the <<com>> device should allow the - specification of other data streams (such as an xterm or TK window). - - The input blocks if no data is available. - - Interrupts have not been tested. - - */ - -enum { - max_hw_com_registers = 8, -}; - -typedef struct _com_port { - int ready; - int delay; - int interrupting; - FILE *file; -} com_port; - -typedef struct _com_modem { - int carrier; - int carrier_changed; - int interrupting; -} com_modem; - -typedef struct _hw_com_device { - com_port input; - com_port output; - com_modem modem; - char dlab[2]; - char reg[max_hw_com_registers]; - int interrupting; -} hw_com_device; - - -static void -hw_com_device_init_data(device *me) -{ - hw_com_device *com = (hw_com_device*)device_data(me); - /* clean up */ - if (com->output.file != NULL) - fclose(com->output.file); - if (com->input.file != NULL) - fclose(com->input.file); - memset(com, 0, sizeof(hw_com_device)); - - /* the fifo speed */ - com->output.delay = (device_find_property(me, "output-delay") != NULL - ? device_find_integer_property(me, "output-delay") - : 0); - com->input.delay = (device_find_property(me, "input-delay") != NULL - ? device_find_integer_property(me, "input-delay") - : 0); - - /* the data source/sink */ - if (device_find_property(me, "input-file") != NULL) { - const char *input_file = device_find_string_property(me, "input-file"); - com->input.file = fopen(input_file, "r"); - if (com->input.file == NULL) - device_error(me, "Problem opening input file %s\n", input_file); - if (device_find_property(me, "input-buffering") != NULL) { - const char *buffering = device_find_string_property(me, "input-buffering"); - if (strcmp(buffering, "unbuffered") == 0) - setbuf(com->input.file, NULL); - } - } - if (device_find_property(me, "output-file") != NULL) { - const char *output_file = device_find_string_property(me, "output-file"); - com->output.file = fopen(output_file, "w"); - if (com->output.file == NULL) - device_error(me, "Problem opening output file %s\n", output_file); - if (device_find_property(me, "output-buffering") != NULL) { - const char *buffering = device_find_string_property(me, "output-buffering"); - if (strcmp(buffering, "unbuffered") == 0) - setbuf(com->output.file, NULL); - } - } - - /* ready from the start */ - com->input.ready = 1; - com->modem.carrier = 1; - com->output.ready = 1; -} - - -static void -update_com_interrupts(device *me, - hw_com_device *com) -{ - int interrupting; - com->modem.interrupting = (com->modem.carrier_changed && (com->reg[1] & 0x80)); - com->input.interrupting = (com->input.ready && (com->reg[1] & 0x1)); - com->output.interrupting = (com->output.ready && (com->reg[1] & 0x2)); - interrupting = (com->input.interrupting - || com->output.interrupting - || com->modem.interrupting); - - if (interrupting) { - if (!com->interrupting) { - device_interrupt_event(me, 0 /*port*/, 1 /*value*/, NULL, 0); - } - } - else /*!interrupting*/ { - if (com->interrupting) - device_interrupt_event(me, 0 /*port*/, 0 /*value*/, NULL, 0); - } - com->interrupting = interrupting; -} - - -static void -make_read_ready(void *data) -{ - device *me = (device*)data; - hw_com_device *com = (hw_com_device*)device_data(me); - com->input.ready = 1; - update_com_interrupts(me, com); -} - -static void -read_com(device *me, - hw_com_device *com, - unsigned_word a, - char val[1]) -{ - unsigned_word addr = a % 8; - - /* the divisor latch is special */ - if (com->reg[3] & 0x8 && addr < 2) { - *val = com->dlab[addr]; - return; - } - - switch (addr) { - - case 0: - /* fifo */ - if (!com->modem.carrier) - *val = '\0'; - if (com->input.ready) { - /* read the char in */ - if (com->input.file == NULL) { - if (sim_io_read_stdin(val, 1) < 0) - com->modem.carrier_changed = 1; - } - else { - if (fread(val, 1, 1, com->input.file) == 0) - com->modem.carrier_changed = 1; - } - /* setup for next read */ - if (com->modem.carrier_changed) { - /* once lost carrier, never ready */ - com->modem.carrier = 0; - com->input.ready = 0; - *val = '\0'; - } - else if (com->input.delay > 0) { - com->input.ready = 0; - device_event_queue_schedule(me, com->input.delay, make_read_ready, me); - } - } - else { - /* discard it? */ - /* overflow input fifo? */ - *val = '\0'; - } - break; - - case 2: - /* interrupt ident */ - if (com->interrupting) { - if (com->input.interrupting) - *val = 0x4; - else if (com->output.interrupting) - *val = 0x2; - else if (com->modem.interrupting == 0) - *val = 0; - else - device_error(me, "bad elif for interrupts\n"); - } - else - *val = 0x1; - break; - - case 5: - /* line status */ - *val = ((com->input.ready ? 0x1 : 0) - | (com->output.ready ? 0x60 : 0) - ); - break; - - case 6: - /* modem status */ - *val = ((com->modem.carrier_changed ? 0x08 : 0) - | (com->modem.carrier ? 0x80 : 0) - ); - com->modem.carrier_changed = 0; - break; - - default: - *val = com->reg[addr]; - break; - - } - update_com_interrupts(me, com); -} - -static unsigned -hw_com_io_read_buffer_callback(device *me, - void *dest, - int space, - unsigned_word addr, - unsigned nr_bytes, - cpu *processor, - unsigned_word cia) -{ - hw_com_device *com = device_data(me); - int i; - for (i = 0; i < nr_bytes; i++) { - read_com(me, com, addr + i, &((char*)dest)[i]); - } - return nr_bytes; -} - - -static void -make_write_ready(void *data) -{ - device *me = (device*)data; - hw_com_device *com = (hw_com_device*)device_data(me); - com->output.ready = 1; - update_com_interrupts(me, com); -} - -static void -write_com(device *me, - hw_com_device *com, - unsigned_word a, - char val) -{ - unsigned_word addr = a % 8; - - /* the divisor latch is special */ - if (com->reg[3] & 0x8 && addr < 2) { - com->dlab[addr] = val; - return; - } - - switch (addr) { - - case 0: - /* fifo */ - if (com->output.file == NULL) { - sim_io_write_stdout(&val, 1); - } - else { - fwrite(&val, 1, 1, com->output.file); - } - /* setup for next write */ - if (com->output.ready && com->output.delay > 0) { - com->output.ready = 0; - device_event_queue_schedule(me, com->output.delay, make_write_ready, me); - } - break; - - default: - com->reg[addr] = val; - break; - - } - update_com_interrupts(me, com); -} - -static unsigned -hw_com_io_write_buffer_callback(device *me, - const void *source, - int space, - unsigned_word addr, - unsigned nr_bytes, - cpu *processor, - unsigned_word cia) -{ - hw_com_device *com = device_data(me); - int i; - for (i = 0; i < nr_bytes; i++) { - write_com(me, com, addr + i, ((char*)source)[i]); - } - return nr_bytes; -} - - -/* instances of the hw_com device */ - -static void -hw_com_instance_delete(device_instance *instance) -{ - /* nothing to delete, the hw_com is attached to the device */ - return; -} - -static int -hw_com_instance_read(device_instance *instance, - void *buf, - unsigned_word len) -{ - device *me = device_instance_device(instance); - hw_com_device *com = device_data(me); - if (com->input.file == NULL) - return sim_io_read_stdin(buf, len); - else { - return fread(buf, 1, len, com->input.file); - } -} - -static int -hw_com_instance_write(device_instance *instance, - const void *buf, - unsigned_word len) -{ - device *me = device_instance_device(instance); - hw_com_device *com = device_data(me); - if (com->output.file == NULL) - return sim_io_write_stdout(buf, len); - else { - return fwrite(buf, 1, len, com->output.file); - } -} - -static const device_instance_callbacks hw_com_instance_callbacks = { - hw_com_instance_delete, - hw_com_instance_read, - hw_com_instance_write, -}; - -static device_instance * -hw_com_create_instance(device *me, - const char *path, - const char *args) -{ - /* point an instance directly at the device */ - return device_create_instance_from(me, NULL, - device_data(me), - path, args, - &hw_com_instance_callbacks); -} - - -static device_callbacks const hw_com_callbacks = { - { generic_device_init_address, - hw_com_device_init_data }, - { NULL, }, /* address */ - { hw_com_io_read_buffer_callback, - hw_com_io_write_buffer_callback, }, - { NULL, }, /* DMA */ - { NULL, }, /* interrupt */ - { NULL, }, /* unit */ - hw_com_create_instance, -}; - - -static void * -hw_com_create(const char *name, - const device_unit *unit_address, - const char *args) -{ - /* create the descriptor */ - hw_com_device *hw_com = ZALLOC(hw_com_device); - return hw_com; -} - - -const device_descriptor hw_com_device_descriptor[] = { - { "com", hw_com_create, &hw_com_callbacks }, - { NULL }, -}; - -#endif /* _HW_COM_C_ */ |