diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
commit | c906108c21474dfb4ed285bcc0ac6fe02cd400cc (patch) | |
tree | a0015aa5cedc19ccbab307251353a41722a3ae13 /sim/common/dv-pal.c | |
parent | cd946cff9ede3f30935803403f06f6ed30cad136 (diff) | |
download | gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.zip gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.gz gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.bz2 |
Initial creation of sourceware repositorygdb-4_18-branchpoint
Diffstat (limited to 'sim/common/dv-pal.c')
-rw-r--r-- | sim/common/dv-pal.c | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/sim/common/dv-pal.c b/sim/common/dv-pal.c new file mode 100644 index 0000000..421bde7 --- /dev/null +++ b/sim/common/dv-pal.c @@ -0,0 +1,605 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996,1998, 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. + + */ + + +#include "hw-main.h" +#include "sim-io.h" + +/* NOTE: pal is naughty and grubs around looking at things outside of + its immediate domain */ +#include "hw-tree.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 + + + pal - glue logic device containing assorted junk + + + DESCRIPTION + + + Typical hardware dependant hack. This device allows the firmware + to gain access to all the things the firmware needs (but the OS + doesn't). + + The pal contains the following registers: + + |0 reset register (write, 8bit) + |4 processor id register (read, 8bit) + |8 interrupt register (8 - port, 9 - level) (write, 16bit) + |12 processor count register (read, 8bit) + + |16 tty input fifo register (read, 8bit) + |20 tty input status register (read, 8bit) + |24 tty output fifo register (write, 8bit) + |28 tty output status register (read, 8bit) + + |32 countdown register (read/write, 32bit, big-endian) + |36 countdown value register (read, 32bit, big-endian) + |40 timer register (read/write, 32bit, big-endian) + |44 timer value register (read, 32bit, big-endian) + + RESET (write): halts the simulator. The value written to the + register is used as an exit status. + + PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of + the processor performing the read. + + INTERRUPT (write): This register must be written using a two byte + store. The low byte specifies a port and the upper byte specifies + the a level. LEVEL is driven on the specified port. By + convention, the pal's interrupt ports (int0, int1, ...) are wired + up to the corresponding processor's level sensative external + interrupt pin. Eg: A two byte write to address 8 of 0x0102 + (big-endian) will result in processor 2's external interrupt pin + being asserted. + + PROCESSOR COUNT (read): returns the total number of processors + active in the current simulation. + + TTY INPUT FIFO (read): if the TTY input status register indicates a + character is available by being nonzero, returns the next available + character from the pal's tty input port. + + TTY OUTPUT FIFO (write): if the TTY output status register + indicates the output fifo is not full by being nonzero, outputs the + character written to the tty's output port. + + COUNDOWN (read/write): The countdown registers provide a + non-repeating timed interrupt source. Writing a 32 bit big-endian + zero value to this register clears the countdown timer. Writing a + non-zero 32 bit big-endian value to this register sets the + countdown timer to expire in VALUE ticks (ticks is target + dependant). Reading the countdown register returns the last value + writen. + + COUNTDOWN VALUE (read): Reading this 32 bit big-endian register + returns the number of ticks remaining until the countdown timer + expires. + + TIMER (read/write): The timer registers provide a periodic timed + interrupt source. Writing a 32 bit big-endian zero value to this + register clears the periodic timer. Writing a 32 bit non-zero + value to this register sets the periodic timer to triger every + VALUE ticks (ticks is target dependant). Reading the timer + register returns the last value written. + + TIMER VALUE (read): Reading this 32 bit big-endian register returns + the number of ticks until the next periodic interrupt. + + + PROPERTIES + + + reg = <address> <size> (required) + + Specify the address (within the parent bus) that this device is to + be located. + + poll? = <boolean> + + If present and true, indicates that the device should poll its + input. + + + PORTS + + + int[0..NR_PROCESSORS] (output) + + Driven as a result of a write to the interrupt-port / + interrupt-level register pair. + + + countdown + + Driven whenever the countdown counter reaches zero. + + + timer + + Driven whenever the timer counter reaches zero. + + + BUGS + + + At present the common simulator framework does not support input + polling. + + */ + + +enum { + hw_pal_reset_register = 0x0, + hw_pal_cpu_nr_register = 0x4, + hw_pal_int_register = 0x8, + hw_pal_nr_cpu_register = 0xa, + hw_pal_read_fifo = 0x10, + hw_pal_read_status = 0x14, + hw_pal_write_fifo = 0x18, + hw_pal_write_status = 0x1a, + hw_pal_countdown = 0x20, + hw_pal_countdown_value = 0x24, + hw_pal_timer = 0x28, + hw_pal_timer_value = 0x2c, + hw_pal_address_mask = 0x3f, +}; + + +typedef struct _hw_pal_console_buffer { + char buffer; + int status; +} hw_pal_console_buffer; + +typedef struct _hw_pal_counter { + struct hw_event *handler; + signed64 start; + unsigned32 delta; + int periodic_p; +} hw_pal_counter; + + +typedef struct _hw_pal_device { + hw_pal_console_buffer input; + hw_pal_console_buffer output; + hw_pal_counter countdown; + hw_pal_counter timer; + struct hw *disk; + do_hw_poll_read_method *reader; +} hw_pal_device; + +enum { + COUNTDOWN_PORT, + TIMER_PORT, + INT_PORT, +}; + +static const struct hw_port_descriptor hw_pal_ports[] = { + { "countdown", COUNTDOWN_PORT, 0, output_port, }, + { "timer", TIMER_PORT, 0, output_port, }, + { "int", INT_PORT, MAX_NR_PROCESSORS, output_port, }, + { NULL } +}; + + +/* countdown and simple timer */ + +static void +do_counter_event (struct hw *me, + void *data) +{ + hw_pal_counter *counter = (hw_pal_counter *) data; + if (counter->periodic_p) + { + HW_TRACE ((me, "timer expired")); + counter->start = hw_event_queue_time (me); + hw_port_event (me, TIMER_PORT, 1); + hw_event_queue_schedule (me, counter->delta, do_counter_event, counter); + } + else + { + HW_TRACE ((me, "countdown expired")); + counter->delta = 0; + hw_port_event (me, COUNTDOWN_PORT, 1); + } +} + +static void +do_counter_read (struct hw *me, + hw_pal_device *pal, + const char *reg, + hw_pal_counter *counter, + unsigned32 *word, + unsigned nr_bytes) +{ + unsigned32 val; + if (nr_bytes != 4) + hw_abort (me, "%s - bad read size must be 4 bytes", reg); + val = counter->delta; + HW_TRACE ((me, "read - %s %ld", reg, (long) val)); + *word = H2BE_4 (val); +} + +static void +do_counter_value (struct hw *me, + hw_pal_device *pal, + const char *reg, + hw_pal_counter *counter, + unsigned32 *word, + unsigned nr_bytes) +{ + unsigned32 val; + if (nr_bytes != 4) + hw_abort (me, "%s - bad read size must be 4 bytes", reg); + if (counter->delta != 0) + val = (counter->start + counter->delta + - hw_event_queue_time (me)); + else + val = 0; + HW_TRACE ((me, "read - %s %ld", reg, (long) val)); + *word = H2BE_4 (val); +} + +static void +do_counter_write (struct hw *me, + hw_pal_device *pal, + const char *reg, + hw_pal_counter *counter, + const unsigned32 *word, + unsigned nr_bytes) +{ + if (nr_bytes != 4) + hw_abort (me, "%s - bad write size must be 4 bytes", reg); + if (counter->handler != NULL) + { + hw_event_queue_deschedule (me, counter->handler); + counter->handler = NULL; + } + counter->delta = BE2H_4 (*word); + counter->start = hw_event_queue_time (me); + HW_TRACE ((me, "write - %s %ld", reg, (long) counter->delta)); + if (counter->delta > 0) + hw_event_queue_schedule (me, counter->delta, do_counter_event, counter); +} + + + + +/* check the console for an available character */ +static void +scan_hw_pal (struct hw *me) +{ + hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me); + char c; + int count; + count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof(c)); + switch (count) + { + case HW_IO_NOT_READY: + case HW_IO_EOF: + hw_pal->input.buffer = 0; + hw_pal->input.status = 0; + break; + default: + hw_pal->input.buffer = c; + hw_pal->input.status = 1; + } +} + +/* write the character to the hw_pal */ + +static void +write_hw_pal (struct hw *me, + char val) +{ + hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me); + sim_io_write_stdout (hw_system (me), &val, 1); + hw_pal->output.buffer = val; + hw_pal->output.status = 1; +} + + +/* Reads/writes */ + +static unsigned +hw_pal_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me); + unsigned_1 *byte = (unsigned_1 *) dest; + memset (dest, 0, nr_bytes); + switch (addr & hw_pal_address_mask) + { + + case hw_pal_cpu_nr_register: +#ifdef CPU_INDEX + *byte = CPU_INDEX (hw_system_cpu (me)); +#else + *byte = 0; +#endif + HW_TRACE ((me, "read - cpu-nr %d\n", *byte)); + break; + + case hw_pal_nr_cpu_register: + if (hw_tree_find_property (me, "/openprom/options/smp") == NULL) + { + *byte = 1; + HW_TRACE ((me, "read - nr-cpu %d (not defined)\n", *byte)); + } + else + { + *byte = hw_tree_find_integer_property (me, "/openprom/options/smp"); + HW_TRACE ((me, "read - nr-cpu %d\n", *byte)); + } + break; + + case hw_pal_read_fifo: + *byte = hw_pal->input.buffer; + HW_TRACE ((me, "read - input-fifo %d\n", *byte)); + break; + + case hw_pal_read_status: + scan_hw_pal (me); + *byte = hw_pal->input.status; + HW_TRACE ((me, "read - input-status %d\n", *byte)); + break; + + case hw_pal_write_fifo: + *byte = hw_pal->output.buffer; + HW_TRACE ((me, "read - output-fifo %d\n", *byte)); + break; + + case hw_pal_write_status: + *byte = hw_pal->output.status; + HW_TRACE ((me, "read - output-status %d\n", *byte)); + break; + + case hw_pal_countdown: + do_counter_read (me, hw_pal, "countdown", + &hw_pal->countdown, dest, nr_bytes); + break; + + case hw_pal_countdown_value: + do_counter_value (me, hw_pal, "countdown-value", + &hw_pal->countdown, dest, nr_bytes); + break; + + case hw_pal_timer: + do_counter_read (me, hw_pal, "timer", + &hw_pal->timer, dest, nr_bytes); + break; + + case hw_pal_timer_value: + do_counter_value (me, hw_pal, "timer-value", + &hw_pal->timer, dest, nr_bytes); + break; + + default: + HW_TRACE ((me, "read - ???\n")); + break; + + } + return nr_bytes; +} + + +static unsigned +hw_pal_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me); + unsigned_1 *byte = (unsigned_1 *) source; + + switch (addr & hw_pal_address_mask) + { + + case hw_pal_reset_register: + hw_halt (me, sim_exited, byte[0]); + break; + + case hw_pal_int_register: + hw_port_event (me, + INT_PORT + byte[0], /*port*/ + (nr_bytes > 1 ? byte[1] : 0)); /* val */ + break; + + case hw_pal_read_fifo: + hw_pal->input.buffer = byte[0]; + HW_TRACE ((me, "write - input-fifo %d\n", byte[0])); + break; + + case hw_pal_read_status: + hw_pal->input.status = byte[0]; + HW_TRACE ((me, "write - input-status %d\n", byte[0])); + break; + + case hw_pal_write_fifo: + write_hw_pal (me, byte[0]); + HW_TRACE ((me, "write - output-fifo %d\n", byte[0])); + break; + + case hw_pal_write_status: + hw_pal->output.status = byte[0]; + HW_TRACE ((me, "write - output-status %d\n", byte[0])); + break; + + case hw_pal_countdown: + do_counter_write (me, hw_pal, "countdown", + &hw_pal->countdown, source, nr_bytes); + break; + + case hw_pal_timer: + do_counter_write (me, hw_pal, "timer", + &hw_pal->timer, source, nr_bytes); + break; + + } + return nr_bytes; +} + + +/* instances of the hw_pal struct hw */ + +#if NOT_YET +static void +hw_pal_instance_delete_callback(hw_instance *instance) +{ + /* nothing to delete, the hw_pal is attached to the struct hw */ + return; +} +#endif + +#if NOT_YET +static int +hw_pal_instance_read_callback (hw_instance *instance, + void *buf, + unsigned_word len) +{ + DITRACE (pal, ("read - %s (%ld)", (const char*) buf, (long int) len)); + return sim_io_read_stdin (buf, len); +} +#endif + +#if NOT_YET +static int +hw_pal_instance_write_callback (hw_instance *instance, + const void *buf, + unsigned_word len) +{ + int i; + const char *chp = buf; + hw_pal_device *hw_pal = hw_instance_data (instance); + DITRACE (pal, ("write - %s (%ld)", (const char*) buf, (long int) len)); + for (i = 0; i < len; i++) + write_hw_pal (hw_pal, chp[i]); + sim_io_flush_stdoutput (); + return i; +} +#endif + +#if NOT_YET +static const hw_instance_callbacks hw_pal_instance_callbacks = { + hw_pal_instance_delete_callback, + hw_pal_instance_read_callback, + hw_pal_instance_write_callback, +}; +#endif + +#if 0 +static hw_instance * +hw_pal_create_instance (struct hw *me, + const char *path, + const char *args) +{ + return hw_create_instance_from (me, NULL, + hw_data (me), + path, args, + &hw_pal_instance_callbacks); +} +#endif + + +static void +hw_pal_attach_address (struct hw *me, + int level, + int space, + address_word addr, + address_word nr_bytes, + struct hw *client) +{ + hw_pal_device *pal = (hw_pal_device*) hw_data (me); + pal->disk = client; +} + + +#if 0 +static hw_callbacks const hw_pal_callbacks = { + { generic_hw_init_address, }, + { hw_pal_attach_address, }, /* address */ + { hw_pal_io_read_buffer_callback, + hw_pal_io_write_buffer_callback, }, + { NULL, }, /* DMA */ + { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */ + { generic_hw_unit_decode, + generic_hw_unit_encode, + generic_hw_address_to_attach_address, + generic_hw_size_to_attach_size }, + hw_pal_create_instance, +}; +#endif + + +static void +hw_pal_finish (struct hw *hw) +{ + /* create the descriptor */ + hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device); + hw_pal->output.status = 1; + hw_pal->output.buffer = '\0'; + hw_pal->input.status = 0; + hw_pal->input.buffer = '\0'; + set_hw_data (hw, hw_pal); + set_hw_attach_address (hw, hw_pal_attach_address); + set_hw_io_read_buffer (hw, hw_pal_io_read_buffer); + set_hw_io_write_buffer (hw, hw_pal_io_write_buffer); + set_hw_ports (hw, hw_pal_ports); + /* attach ourselves */ + do_hw_attach_regs (hw); + /* If so configured, enable polled input */ + if (hw_find_property (hw, "poll?") != NULL + && hw_find_boolean_property (hw, "poll?")) + { + hw_pal->reader = sim_io_poll_read; + } + else + { + hw_pal->reader = sim_io_read; + } + /* tag the periodic timer */ + hw_pal->timer.periodic_p = 1; +} + + +const struct hw_descriptor dv_pal_descriptor[] = { + { "pal", hw_pal_finish, }, + { NULL }, +}; |