* 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:
parent
d89fa2d80a
commit
05d7918e53
3 changed files with 277 additions and 63 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue