* 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>
* 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
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)
The pal contains the following registers:
Reset register (write) halts the simulator exiting with the
value written.
|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 register (read) returns the total number of
processors active in the current simulation.
PROCESSOR COUNT (read): returns the total number of processors
active in the current simulation.
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 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.
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.
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
@ -102,7 +126,7 @@
reg = <address> <size> (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;
}

View file

@ -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);
}