/* noss.c     nos supervisor

 */

#include "sx.h"

#define PSW  1			// noss state
#define USER 2

extern int clock;		// sxm.c

int a_activep, a_status, a_psw; // binding to user space
int intflag;			// interrup flag
int dt;					// interrupt timer
int noss_state;
int userp;				// pdes of current user process
int sclock = 0;			// count time spent in switchp
int n_switch = 0;

// save c-state to process descriptor
PRIVATE void saveCstate(int a){
    M[a + 4] = FP;
    M[a + 5] = SP;
    M[a + 6] = PC;
    M[a + 7] = TS;
}

// restore c-state from a process desc.
PRIVATE void restoreCstate(int a){
    FP = M[a + 4];
    SP = M[a + 5];
    PC = M[a + 6];	// cause a jump
    TS = M[a + 7];
}

PRIVATE void stat(void){
    sclock += (clock-dt);
    printf(" * ");
    n_switch++;
}

// event = time_out, stopped, blocked
void noss(int event){
    if(M[a_activep] == 0){		// no process
        runflag = 0;			// stop simulation
        return;
    }
    M[a_status] = event;		// update to nos
    switch(noss_state){
    case PSW:					// run task switcher
        saveCstate(userp);
        restoreCstate(M[a_psw]);
        noss_state = USER;
        break;
    case USER:					// run user process
        userp = M[a_activep];
        restoreCstate(userp);
        intflag = 1;			// enable interrupt
        noss_state = PSW;
        stat();					// collect statistics
    }
    dt = clock;					// reset timer
}

void yield(void){
    if(intflag && (clock-dt) > TIMEOUT)
        noss(time_out);
}

// processor execution
void eval(int ref){
    PC = ref;
    while(runflag ) {
        run3();		// execute one instruction
        yield();
    }
}

void trap(int op, int arg){		// special functions
    switch(op) {
    case icEnd : noss(stopped);	break;
    case icArray: TS = xalloc(TS); break;
    case icSys:
        switch(arg){
        case 1: 				// print ts
            printf("%d",TS);
            popts();
            break;
        case 2 : 				// printc ts
            printf("%c",TS);
            popts();
            break;
        case 13: runflag = 0; break;
        case 20: intflag = 1; break;
        case 21: intflag = 0; break;
        case 22: noss(blocked); break;
        default:
            error("unknown syscall");
        }
        break;
    default:
        error("unknown trap");
    }
}

PRIVATE void boot(void){
    a_activep = searchsym("activep");
    a_status = searchsym("status");
    a_psw = searchsym("psw");
    dt = 0;
    intflag = 0;
    noss_state = USER;
    eval(1);       				// boot nos
}

int main(int argc, char *argv[]){
  if( argc < 2 ) {
    printf("usage : noss objfile\n");
    exit(0);
  }
  loadobj(argv[1]);
  initchip();
  boot();
  return 0;
}

