From 05d7918e531d86e7dcc67e709b271491151f8bdd Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Wed, 25 Mar 1998 03:44:37 +0000 Subject: [PATCH] * dv-pal.c (hw_pal_countdown, hw_pal_countdown_value, hw_pal_timer, hw_pal_timer_value): Define. (hw_pal_io_read_buffer, hw_pal_io_write_buffer): Add timer support (do_counter_event, do_counter_read, do_counter_value, do_counter_write): new functions. * hw-tree.c (hw_printf): Send tree dump to stderr, same as other trace output. * hw-base.c (hw_create): Stop searching for a device when one is found. --- sim/common/ChangeLog | 16 +++ sim/common/dv-pal.c | 315 ++++++++++++++++++++++++++++++++++--------- sim/common/hw-tree.c | 11 +- 3 files changed, 278 insertions(+), 64 deletions(-) diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog index c98617cd5d3..d64b7b455e5 100644 --- a/sim/common/ChangeLog +++ b/sim/common/ChangeLog @@ -1,3 +1,19 @@ +Wed Mar 25 09:18:34 1998 Andrew Cagney + + * dv-pal.c (hw_pal_countdown, hw_pal_countdown_value, + hw_pal_timer, hw_pal_timer_value): Define. + (hw_pal_io_read_buffer, hw_pal_io_write_buffer): Add timer support + (do_counter_event, do_counter_read, do_counter_value, + do_counter_write): new functions. + +Tue Mar 24 12:24:24 1998 Andrew Cagney + + * hw-tree.c (hw_printf): Send tree dump to stderr, same as other + trace output. + + * hw-base.c (hw_create): Stop searching for a device when one is + found. + Wed Mar 25 12:35:29 1998 Andrew Cagney * configure: Regenerated to track ../common/aclocal.m4 changes. diff --git a/sim/common/dv-pal.c b/sim/common/dv-pal.c index c98ff6860f1..95554aab842 100644 --- a/sim/common/dv-pal.c +++ b/sim/common/dv-pal.c @@ -54,46 +54,70 @@ to gain access to all the things the firmware needs (but the OS doesn't). - The pal contains the following registers. Except for the interrupt - level register, each of the below is 8 bytes in size and must be - accessed using correct alignment. For 16 and 32 bit accesses the - bytes not directed to the register are ignored: - - |0 reset register (write) - |4 processor id register (read) - |8 interrupt port (write) - |9 interrupt level (write) - |12 processor count register (read) - |16 tty input fifo register (read) - |20 tty input status register (read) - |24 tty output fifo register (write) - |28 tty output status register (read) - - Reset register (write) halts the simulator exiting with the - value written. + 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 register (read) returns the processor number (0 - .. N-1) of the processor performing the read. + PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of + the processor performing the read. - The interrupt registers should be accessed as a pair (using a 16 or - 32 bit store). The low byte specifies the interrupt port while the - high byte specifies the level to drive that port at. By + 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 to - be asserted. + (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. - Processor count register (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 input fifo register (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. - Similarly, the TTY output fifo register (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 @@ -102,7 +126,7 @@ reg =
(required) Specify the address (within the parent bus) that this device is to - live. + be located. PORTS @@ -114,6 +138,22 @@ 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. + */ @@ -126,7 +166,11 @@ enum { hw_pal_read_status = 0x14, hw_pal_write_fifo = 0x18, hw_pal_write_status = 0x1a, - hw_pal_address_mask = 0x1f, + hw_pal_countdown = 0x20, + hw_pal_countdown_value = 0x24, + hw_pal_timer = 0x28, + hw_pal_timer_value = 0x2c, + hw_pal_address_mask = 0x2f, }; @@ -135,12 +179,118 @@ typedef struct _hw_pal_console_buffer { int status; } hw_pal_console_buffer; +typedef struct _hw_pal_counter { + 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; } 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, NULL, NULL_CIA); + 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, NULL, NULL_CIA); + } +} + +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 @@ -168,6 +318,7 @@ scan_hw_pal (struct hw *me) } /* write the character to the hw_pal */ + static void write_hw_pal (struct hw *me, char val) @@ -179,6 +330,8 @@ write_hw_pal (struct hw *me, } +/* Reads/writes */ + static unsigned hw_pal_io_read_buffer (struct hw *me, void *dest, @@ -189,44 +342,71 @@ hw_pal_io_read_buffer (struct hw *me, sim_cia cia) { hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me); - unsigned_1 val; + 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 - val = CPU_INDEX (cpu); + *byte = CPU_INDEX (cpu); #else - val = 0; + *byte = 0; #endif - HW_TRACE ((me, "read - cpu-nr %d\n", val)); + HW_TRACE ((me, "read - cpu-nr %d\n", *byte)); break; + case hw_pal_nr_cpu_register: - val = hw_tree_find_integer_property (me, "/openprom/options/smp"); - HW_TRACE ((me, "read - nr-cpu %d\n", val)); + *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: - val = hw_pal->input.buffer; - HW_TRACE ((me, "read - input-fifo %d\n", val)); + *byte = hw_pal->input.buffer; + HW_TRACE ((me, "read - input-fifo %d\n", *byte)); break; + case hw_pal_read_status: scan_hw_pal (me); - val = hw_pal->input.status; - HW_TRACE ((me, "read - input-status %d\n", val)); + *byte = hw_pal->input.status; + HW_TRACE ((me, "read - input-status %d\n", *byte)); break; + case hw_pal_write_fifo: - val = hw_pal->output.buffer; - HW_TRACE ((me, "read - output-fifo %d\n", val)); + *byte = hw_pal->output.buffer; + HW_TRACE ((me, "read - output-fifo %d\n", *byte)); break; + case hw_pal_write_status: - val = hw_pal->output.status; - HW_TRACE ((me, "read - output-status %d\n", val)); + *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: - val = 0; HW_TRACE ((me, "read - ???\n")); + break; + } - memset (dest, 0, nr_bytes); - *(unsigned_1*)dest = val; return nr_bytes; } @@ -241,35 +421,52 @@ hw_pal_io_write_buffer (struct hw *me, sim_cia cia) { hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me); - unsigned_1 *byte = (unsigned_1*) source; + unsigned_1 *byte = (unsigned_1 *) source; switch (addr & hw_pal_address_mask) { + case hw_pal_reset_register: - sim_engine_halt (NULL, cpu, NULL, cia, sim_exited, byte[0]); + sim_engine_halt (hw_system (me), cpu, NULL, cia, sim_exited, byte[0]); break; + case hw_pal_int_register: hw_port_event (me, - byte[0], /*port*/ + INT_PORT + byte[0], /*port*/ (nr_bytes > 1 ? byte[1] : 0), /* val */ cpu, cia); 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; } @@ -335,11 +532,6 @@ hw_pal_create_instance (struct hw *me, } #endif -static const struct hw_port_descriptor hw_pal_ports[] = { - { "int", 0, MAX_NR_PROCESSORS }, - { NULL } -}; - static void hw_pal_attach_address (struct hw *me, @@ -386,7 +578,10 @@ hw_pal_finish (struct hw *hw) set_hw_io_write_buffer (hw, hw_pal_io_write_buffer); set_hw_ports (hw, hw_pal_ports); /* attach ourselves */ - do_hw_attach_regs (me); + do_hw_attach_regs (hw); + + /* tag the periodic timer */ + hw_pal->timer.periodic_p = 1; } diff --git a/sim/common/hw-tree.c b/sim/common/hw-tree.c index 219b75b2860..da9cc57874e 100644 --- a/sim/common/hw-tree.c +++ b/sim/common/hw-tree.c @@ -831,10 +831,13 @@ hw_tree_parse (struct hw *current, char *dest_hw_name = split_value (&spec); struct hw *dest; /* find my name */ - my_port = hw_port_decode (current, my_port_name, - output_port); + if (!hw_finished_p (current)) + hw_finish (current); + my_port = hw_port_decode (current, my_port_name, output_port); /* find the dest device and port */ - dest = split_fill_path(current, dest_hw_name, &dest_spec); + dest = split_fill_path (current, dest_hw_name, &dest_spec); + if (!hw_finished_p (dest)) + hw_finish (dest); dest_port = hw_port_decode (dest, dest_port_name, input_port); /* connect the two */ @@ -981,7 +984,7 @@ hw_printf (struct hw *me, { va_list ap; va_start (ap, fmt); - sim_io_vprintf (hw_system (me), fmt, ap); + sim_io_evprintf (hw_system (me), fmt, ap); va_end (ap); } -- 2.30.2