/*************************************************************************
* *
* Modulo di gestione degli interrupt *
* *
* realizzato dal Gruppo 17 di Lab2 Anno Accademico 1995/96 *
* *
* Lorenzo Claudio Valerio Riccardo Emiliano *
* Coronati Lanconelli Paolini Solmi Trentini *
* *
**************************************************************************/
/*
* Alle routine di gestione viene passato in R4 l'indirizzo dell'area old
* del relativo interrupt ed in R3 il tipo di interrupt
*/
#include "../h/types.h"
#include "../h/nucconst.h"
#include "../h/scheduler.e"
#include "../h/sendrecv.e"
#include "../h/globals.e"
/* gestore interruzione non definito */
onBadIO()
{
panic("invalid interrupt");
}
#ifdef NUC_PROFILE
int clk_slice = 0;
int clk_tick = 0;
int clk_null = 0;
#endif
/* gestore interruzione timer */
onClock()
{
register state_t *sts; /* R4 */
#ifdef NUC_PROFILE
register int r3, r2 = 0;
#endif
/*
* evita che il tempo di esecuzione della routine venga addebitato al
* processo in esecuzione
*/
ACCOUNT();
if (time_now >= next_clock)
{
#ifdef NUC_PROFILE
r2 = 1;
clk_tick++;
#endif
/*
* caso in cui l'interrupt indica l'avvenuto pseudoclock
* tick. Se vi e` una richiesta pendente di WAITCLOCK allora
* in clock_reply e` memorizzato il thread richiedente, e
* quindi lo risvegliamo mandandogli un messaggio.
*/
if (clock_reply != NULL)
{
no_wait--;
msgSend(SSI, clock_reply, EMPTYMSG);
clock_reply = NULL;
}
next_clock += CLOCKINTERVAL;
}
/*
* nel caso in cui sia esaurito il time-slice del thread in
* esecuzione oppure sia in esecuzione il thread vuoto, richiama lo
* scheduler
*/
if (time_left <= 0 || run_proc == NULL)
{
#ifdef NUC_PROFILE
r2 = 1;
clk_slice++;
#endif
SAVESTATE();
schedule();
NEWSTATE();
}
#ifdef NUC_PROFILE
if (r2 == 0)
clk_null++;
STCK(&last_start);
intr_time += last_start - time_now;
#endif
LOADTIMER();
DISPATCH();
}
/*
* utilizzato per ricavare l'indirizzo del device register dal tipo
* di dispositivo
*/
HIDDEN devreg_t *dev_addr[] = {
BEGINDEVREG + TERM0 * sizeof(devreg_t), /* 01400 */
BEGINDEVREG + PRINT0 * sizeof(devreg_t), /* 01520 */
BEGINDEVREG + DISK0 * sizeof(devreg_t), /* 01560 */
BEGINDEVREG + DRUM0 * sizeof(devreg_t) /* 01660 */
};
#ifdef NUC_PROFILE
int io_prima = 0;
int io_dopo = 0;
#endif
#define DEVTYPE ((int)devp)
/* gestore degli interrupt causati dai dispositivi di I/O */
void
onDevIO()
{
register state_t *sts; /* R4 */
register devreg_t *devp;/* R3 in ingresso e` presente il dev.type */
register ioreply_t *iorp; /* R2 */
/*
* evita che il tempo di esecuzione della routine venga addebitato al
* processo in esecuzione
*/
ACCOUNT();
devp = dev_addr[DEVTYPE] + sts->s_ps2.p2_int.in_dno;
iorp = io_reply + DEVNO(devp);
/*
* controlliamo se c'e` una richiesta pendente di WAITIO
*/
if (iorp->status == WAIT)
{
#ifdef NUC_PROFILE
io_dopo++;
#endif
/*
* risvegliamo il thread richiedente mandandogli lo stato dei
* registri del dispositivo
*/
no_wait--;
iorp->u.r.msg->d.sts = devp->d_stat;
iorp->u.r.msg->d.len = devp->d_amnt;
iorp->status = NONE;
/*
* si finge l'SSI poiche' il thread richiedente si e' messo
* in attesa dell'SSI e deve essere risvegliato da
* quest'ultimo
*/
msgSend(SSI, iorp->u.r.sender, iorp->u.r.msg);
/*
* se non c'era nessun thread in esecuzione scheduliamo il
* thread risvegliato
*/
if (run_proc == NULL)
{
schedule();
NEWSTATE();
}
}
else
{
#ifdef NUC_PROFILE
io_prima++;
#endif
#ifdef NUC_DEBUG
if (iorp->status == INTR)
error("interrupt without any WaitIO");
#endif
/* memorizziamo l'interrupt avvenuto per la prossima WAITIO */
iorp->u.d.sts = devp->d_stat;
iorp->u.d.len = devp->d_amnt;
iorp->status = INTR;
}
#ifdef NUC_PROFILE
STCK(&last_start);
intr_time += last_start - time_now;
#endif
LOADTIMER();
DISPATCH();
}