2013-07-31 22:25:37 +00:00
|
|
|
/*
|
|
|
|
* Used to be
|
|
|
|
* Copyright 1994, Eric A. Edwards
|
|
|
|
* After substantial changes
|
|
|
|
* Copyright 2003, Leonid A. Broukhis
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* service.c - Event handler system and interrupt service.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "defines.h"
|
2019-11-01 15:43:34 +00:00
|
|
|
#include "intl.h"
|
2020-03-06 04:38:46 +00:00
|
|
|
#include "ops.h"
|
2019-11-01 15:43:34 +00:00
|
|
|
|
2013-07-31 22:25:37 +00:00
|
|
|
|
|
|
|
/* Allows up to 32 different HW interrupts,
|
|
|
|
* there can be no more than 1 pending interrupt of each kind.
|
|
|
|
*/
|
|
|
|
unsigned long pending_interrupts = 0;
|
|
|
|
double earliest = 0.0;
|
|
|
|
event events[NUM_PRI];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ev_init() - Initialize the event system.
|
|
|
|
*/
|
|
|
|
|
2019-11-01 14:33:24 +00:00
|
|
|
void ev_init()
|
2013-07-31 22:25:37 +00:00
|
|
|
{
|
|
|
|
pending_interrupts = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ev_register() - Register an event.
|
|
|
|
*/
|
|
|
|
|
2019-11-01 14:33:24 +00:00
|
|
|
|
|
|
|
void ev_register(unsigned priority, int (*handler)(d_word),
|
|
|
|
unsigned long delay, /* in clock ticks */
|
|
|
|
d_word info)
|
2013-07-31 22:25:37 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if (pending_interrupts & (1 << priority)) {
|
|
|
|
/* There is one pending already */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Fill in the info.
|
|
|
|
*/
|
|
|
|
|
|
|
|
events[priority].handler = handler;
|
|
|
|
events[priority].info = info;
|
|
|
|
events[priority].when = ticks + delay;
|
|
|
|
if (!pending_interrupts || ticks + delay < earliest) {
|
|
|
|
earliest = ticks + delay;
|
|
|
|
}
|
|
|
|
pending_interrupts |= 1 << priority;
|
|
|
|
/* fprintf(stderr, "Registering pri %d @ %g\n", priority, earliest); */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ev_fire() - Fire off any pending event by the mask
|
|
|
|
* priority list.
|
|
|
|
*/
|
|
|
|
|
2019-11-01 14:33:24 +00:00
|
|
|
void ev_fire( int priority )
|
2013-07-31 22:25:37 +00:00
|
|
|
{
|
|
|
|
int x;
|
2020-03-06 04:40:57 +00:00
|
|
|
unsigned long mask = 0;
|
2013-07-31 22:25:37 +00:00
|
|
|
switch (priority) {
|
|
|
|
case 0: mask = ~0; break;
|
|
|
|
case 1: mask = ~0; break;
|
|
|
|
case 2: mask = ~0; break;
|
|
|
|
case 3: mask = ~0; break;
|
|
|
|
/* BK-0010 uses MTPS #200 to block keyboard interrupts */
|
|
|
|
case 4: mask = 1; break;
|
|
|
|
case 5: mask = 0; break;
|
|
|
|
case 6: mask = 0; break;
|
|
|
|
case 7: mask = 0; break;
|
|
|
|
}
|
|
|
|
if (!(mask & pending_interrupts) || ticks < earliest) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
earliest = 10.0e38;
|
|
|
|
|
|
|
|
for( x = 0; x < NUM_PRI && (1<<x) <= pending_interrupts; ++x ) {
|
|
|
|
if (mask & pending_interrupts & (1<<x) &&
|
|
|
|
ticks >= events[x].when) {
|
|
|
|
events[x].handler(events[x].info);
|
|
|
|
/* fprintf(stderr, "Firing pri %d\n", x); */
|
|
|
|
pending_interrupts &= ~(1 << x);
|
|
|
|
mask = 0;
|
|
|
|
} else if (pending_interrupts & (1<<x) &&
|
|
|
|
events[x].when < earliest) {
|
|
|
|
earliest = events[x].when;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* fprintf(stderr, "Earliest is %g\n", earliest); */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* service() - Handle a Trap.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2020-03-06 04:37:47 +00:00
|
|
|
service( d_word vector )
|
2013-07-31 22:25:37 +00:00
|
|
|
{
|
|
|
|
register pdp_regs *p = &pdp;
|
|
|
|
int result;
|
|
|
|
d_word oldpsw;
|
|
|
|
d_word oldpc;
|
|
|
|
d_word newpsw;
|
|
|
|
d_word newpc;
|
|
|
|
|
|
|
|
last_branch = p->regs[PC];
|
|
|
|
|
|
|
|
oldpsw = p->psw;
|
|
|
|
oldpc = p->regs[PC];
|
|
|
|
|
|
|
|
/* If we're servicing an interrupt while a WAIT instruction
|
|
|
|
* was executing, we need to return after the WAIT.
|
|
|
|
*/
|
|
|
|
if (in_wait_instr) {
|
|
|
|
oldpc += 2;
|
|
|
|
in_wait_instr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (( result = lc_word( vector, &newpc)) != OK)
|
|
|
|
return result;
|
|
|
|
if (( result = lc_word( vector + 2, &newpsw)) != OK)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// fprintf(stderr, "Int %o to %06o\n", vector, p->regs[PC]);
|
|
|
|
addtocybuf(-vector);
|
|
|
|
|
|
|
|
if (( result = push( p, oldpsw )) != OK )
|
|
|
|
return result;
|
|
|
|
if (( result = push( p, oldpc )) != OK )
|
|
|
|
return result;
|
|
|
|
|
|
|
|
p->psw = newpsw;
|
|
|
|
p->regs[PC] = newpc;
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rti() - Return from Interrupt Instruction.
|
|
|
|
*/
|
|
|
|
|
2019-11-01 14:33:24 +00:00
|
|
|
int rti( p )
|
2013-07-31 22:25:37 +00:00
|
|
|
register pdp_regs *p;
|
|
|
|
{
|
|
|
|
d_word newpsw;
|
|
|
|
d_word newpc;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
last_branch = p->regs[PC];
|
|
|
|
if (( result = pop( p, &newpc )) != OK )
|
|
|
|
return result;
|
|
|
|
if (( result = pop( p, &newpsw )) != OK )
|
|
|
|
return result;
|
|
|
|
|
|
|
|
p->psw = newpsw;
|
|
|
|
p->regs[PC] = newpc;
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rtt() - Return from Interrupt Instruction.
|
|
|
|
*/
|
|
|
|
|
2019-11-01 14:33:24 +00:00
|
|
|
int rtt( p )
|
2013-07-31 22:25:37 +00:00
|
|
|
register pdp_regs *p;
|
|
|
|
{
|
|
|
|
d_word newpsw;
|
|
|
|
d_word newpc;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
last_branch = p->regs[PC];
|
|
|
|
if (( result = pop( p, &newpc )) != OK )
|
|
|
|
return result;
|
|
|
|
if (( result = pop( p, &newpsw )) != OK )
|
|
|
|
return result;
|
|
|
|
|
|
|
|
p->psw = newpsw;
|
|
|
|
p->regs[PC] = newpc;
|
|
|
|
|
|
|
|
return CPU_RTT;
|
|
|
|
}
|