* 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.
This commit is contained in:
Andrew Cagney 1998-03-25 03:44:37 +00:00
parent d89fa2d80a
commit 05d7918e53
3 changed files with 277 additions and 63 deletions

View file

@ -1,3 +1,19 @@
Wed Mar 25 09:18:34 1998 Andrew Cagney <cagney@b1.cygnus.com>
* 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 <cagney@b1.cygnus.com>
* 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 <cagney@b1.cygnus.com> Wed Mar 25 12:35:29 1998 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes. * configure: Regenerated to track ../common/aclocal.m4 changes.

View file

@ -54,46 +54,70 @@
to gain access to all the things the firmware needs (but the OS to gain access to all the things the firmware needs (but the OS
doesn't). doesn't).
The pal contains the following registers. Except for the interrupt The pal contains the following registers:
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 |0 reset register (write, 8bit)
value written. |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 PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of
.. N-1) of the processor performing the read. the processor performing the read.
The interrupt registers should be accessed as a pair (using a 16 or INTERRUPT (write): This register must be written using a two byte
32 bit store). The low byte specifies the interrupt port while the store. The low byte specifies a port and the upper byte specifies
high byte specifies the level to drive that port at. By the a level. LEVEL is driven on the specified port. By
convention, the pal's interrupt ports (int0, int1, ...) are wired convention, the pal's interrupt ports (int0, int1, ...) are wired
up to the corresponding processor's level sensative external up to the corresponding processor's level sensative external
interrupt pin. Eg: A two byte write to address 8 of 0x0102 interrupt pin. Eg: A two byte write to address 8 of 0x0102
(big-endian) will result in processor 2's external interrupt pin to (big-endian) will result in processor 2's external interrupt pin
be asserted. being asserted.
Processor count register (read) returns the total number of PROCESSOR COUNT (read): returns the total number of processors
processors active in the current simulation. active in the current simulation.
TTY input fifo register (read), if the TTY input status register TTY INPUT FIFO (read): if the TTY input status register indicates a
indicates a character is available by being nonzero, returns the character is available by being nonzero, returns the next available
next available character from the pal's tty input port. character from the pal's tty input port.
Similarly, the TTY output fifo register (write), if the TTY output TTY OUTPUT FIFO (write): if the TTY output status register
status register indicates the output fifo is not full by being indicates the output fifo is not full by being nonzero, outputs the
nonzero, outputs the character written to the tty's output port. 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 PROPERTIES
@ -102,7 +126,7 @@
reg = <address> <size> (required) reg = <address> <size> (required)
Specify the address (within the parent bus) that this device is to Specify the address (within the parent bus) that this device is to
live. be located.
PORTS PORTS
@ -114,6 +138,22 @@
interrupt-level register pair. 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_read_status = 0x14,
hw_pal_write_fifo = 0x18, hw_pal_write_fifo = 0x18,
hw_pal_write_status = 0x1a, 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; int status;
} hw_pal_console_buffer; } 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 { typedef struct _hw_pal_device {
hw_pal_console_buffer input; hw_pal_console_buffer input;
hw_pal_console_buffer output; hw_pal_console_buffer output;
hw_pal_counter countdown;
hw_pal_counter timer;
struct hw *disk; struct hw *disk;
} hw_pal_device; } 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 */ /* check the console for an available character */
static void static void
@ -168,6 +318,7 @@ scan_hw_pal (struct hw *me)
} }
/* write the character to the hw_pal */ /* write the character to the hw_pal */
static void static void
write_hw_pal (struct hw *me, write_hw_pal (struct hw *me,
char val) char val)
@ -179,6 +330,8 @@ write_hw_pal (struct hw *me,
} }
/* Reads/writes */
static unsigned static unsigned
hw_pal_io_read_buffer (struct hw *me, hw_pal_io_read_buffer (struct hw *me,
void *dest, void *dest,
@ -189,44 +342,71 @@ hw_pal_io_read_buffer (struct hw *me,
sim_cia cia) sim_cia cia)
{ {
hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me); 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) switch (addr & hw_pal_address_mask)
{ {
case hw_pal_cpu_nr_register: case hw_pal_cpu_nr_register:
#ifdef CPU_INDEX #ifdef CPU_INDEX
val = CPU_INDEX (cpu); *byte = CPU_INDEX (cpu);
#else #else
val = 0; *byte = 0;
#endif #endif
HW_TRACE ((me, "read - cpu-nr %d\n", val)); HW_TRACE ((me, "read - cpu-nr %d\n", *byte));
break; break;
case hw_pal_nr_cpu_register: case hw_pal_nr_cpu_register:
val = hw_tree_find_integer_property (me, "/openprom/options/smp"); *byte = hw_tree_find_integer_property (me, "/openprom/options/smp");
HW_TRACE ((me, "read - nr-cpu %d\n", val)); HW_TRACE ((me, "read - nr-cpu %d\n", *byte));
break; break;
case hw_pal_read_fifo: case hw_pal_read_fifo:
val = hw_pal->input.buffer; *byte = hw_pal->input.buffer;
HW_TRACE ((me, "read - input-fifo %d\n", val)); HW_TRACE ((me, "read - input-fifo %d\n", *byte));
break; break;
case hw_pal_read_status: case hw_pal_read_status:
scan_hw_pal (me); scan_hw_pal (me);
val = hw_pal->input.status; *byte = hw_pal->input.status;
HW_TRACE ((me, "read - input-status %d\n", val)); HW_TRACE ((me, "read - input-status %d\n", *byte));
break; break;
case hw_pal_write_fifo: case hw_pal_write_fifo:
val = hw_pal->output.buffer; *byte = hw_pal->output.buffer;
HW_TRACE ((me, "read - output-fifo %d\n", val)); HW_TRACE ((me, "read - output-fifo %d\n", *byte));
break; break;
case hw_pal_write_status: case hw_pal_write_status:
val = hw_pal->output.status; *byte = hw_pal->output.status;
HW_TRACE ((me, "read - output-status %d\n", val)); HW_TRACE ((me, "read - output-status %d\n", *byte));
break; 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: default:
val = 0;
HW_TRACE ((me, "read - ???\n")); HW_TRACE ((me, "read - ???\n"));
break;
} }
memset (dest, 0, nr_bytes);
*(unsigned_1*)dest = val;
return nr_bytes; return nr_bytes;
} }
@ -241,35 +421,52 @@ hw_pal_io_write_buffer (struct hw *me,
sim_cia cia) sim_cia cia)
{ {
hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me); 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) switch (addr & hw_pal_address_mask)
{ {
case hw_pal_reset_register: 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; break;
case hw_pal_int_register: case hw_pal_int_register:
hw_port_event (me, hw_port_event (me,
byte[0], /*port*/ INT_PORT + byte[0], /*port*/
(nr_bytes > 1 ? byte[1] : 0), /* val */ (nr_bytes > 1 ? byte[1] : 0), /* val */
cpu, cia); cpu, cia);
break; break;
case hw_pal_read_fifo: case hw_pal_read_fifo:
hw_pal->input.buffer = byte[0]; hw_pal->input.buffer = byte[0];
HW_TRACE ((me, "write - input-fifo %d\n", byte[0])); HW_TRACE ((me, "write - input-fifo %d\n", byte[0]));
break; break;
case hw_pal_read_status: case hw_pal_read_status:
hw_pal->input.status = byte[0]; hw_pal->input.status = byte[0];
HW_TRACE ((me, "write - input-status %d\n", byte[0])); HW_TRACE ((me, "write - input-status %d\n", byte[0]));
break; break;
case hw_pal_write_fifo: case hw_pal_write_fifo:
write_hw_pal (me, byte[0]); write_hw_pal (me, byte[0]);
HW_TRACE ((me, "write - output-fifo %d\n", byte[0])); HW_TRACE ((me, "write - output-fifo %d\n", byte[0]));
break; break;
case hw_pal_write_status: case hw_pal_write_status:
hw_pal->output.status = byte[0]; hw_pal->output.status = byte[0];
HW_TRACE ((me, "write - output-status %d\n", byte[0])); HW_TRACE ((me, "write - output-status %d\n", byte[0]));
break; 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; return nr_bytes;
} }
@ -335,11 +532,6 @@ hw_pal_create_instance (struct hw *me,
} }
#endif #endif
static const struct hw_port_descriptor hw_pal_ports[] = {
{ "int", 0, MAX_NR_PROCESSORS },
{ NULL }
};
static void static void
hw_pal_attach_address (struct hw *me, 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_io_write_buffer (hw, hw_pal_io_write_buffer);
set_hw_ports (hw, hw_pal_ports); set_hw_ports (hw, hw_pal_ports);
/* attach ourselves */ /* attach ourselves */
do_hw_attach_regs (me); do_hw_attach_regs (hw);
/* tag the periodic timer */
hw_pal->timer.periodic_p = 1;
} }

View file

@ -831,10 +831,13 @@ hw_tree_parse (struct hw *current,
char *dest_hw_name = split_value (&spec); char *dest_hw_name = split_value (&spec);
struct hw *dest; struct hw *dest;
/* find my name */ /* find my name */
my_port = hw_port_decode (current, my_port_name, if (!hw_finished_p (current))
output_port); hw_finish (current);
my_port = hw_port_decode (current, my_port_name, output_port);
/* find the dest device and 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, dest_port = hw_port_decode (dest, dest_port_name,
input_port); input_port);
/* connect the two */ /* connect the two */
@ -981,7 +984,7 @@ hw_printf (struct hw *me,
{ {
va_list ap; va_list ap;
va_start (ap, fmt); va_start (ap, fmt);
sim_io_vprintf (hw_system (me), fmt, ap); sim_io_evprintf (hw_system (me), fmt, ap);
va_end (ap); va_end (ap);
} }