/************************************************************************

        This code forms the base of the operating system you will
        build.  It has only the barest rudiments of what you will
        eventually construct; yet it contains the interfaces that
        allow test.c and z502.c to be successfully built together.      

        Revision History:       
                1.0 August 1990
                1.1 December 1990: Portability attempted.
                1.3 July     1992: More Portability enhancements.
                                   Add call to sample_code.
                1.4 December 1992: Limit (temporarily) printout in
                                   interrupt handler.  More portability.
************************************************************************/

#include                 "global.h"
#include                 "syscalls.h"
#include                 "z502.h"
#include                 "protos.h"
#include                 "string.h"

extern char              MEMORY[];  
extern BOOL              POP_THE_STACK;
extern UINT16            *Z502_REG_PAGE_TBL_ADDR;
extern INT16             Z502_REG_PAGE_TBL_LENGTH;
extern INT16             Z502_REG_PROGRAM_COUNTER;
extern INT16             Z502_REG_INTERRUPT_MASK;
extern INT16             Z502_REG_MODE;
extern Z502_ARG          Z502_REG_ARG1;
extern Z502_ARG          Z502_REG_ARG2;
extern Z502_ARG          Z502_REG_ARG3;
extern Z502_ARG          Z502_REG_ARG4;
extern Z502_ARG          Z502_REG_ARG5;
extern Z502_ARG          Z502_REG_ARG6;
extern INT32             Z502_REG_1;
extern INT32             Z502_REG_2;
extern INT32             Z502_REG_3;
extern INT32             Z502_REG_4;
extern INT32             Z502_REG_5;
extern INT32             Z502_REG_6;
extern INT32             Z502_REG_7;
extern INT32             Z502_REG_8;
extern INT32             Z502_REG_9;
extern INT16             STAT_VECTOR[SV_VALUE+1]
                                  [ LARGEST_STAT_VECTOR_INDEX + 1 ];
extern void              *TO_VECTOR [];
extern INT32             CALLING_ARGC;
extern char              **CALLING_ARGV;

char                     *call_names[] = { "mem_read ", "mem_write",
                                "read_mod ", "get_time ", "sleep    ", 
                                "create   ", "get_pid  ", "term_proc", 
                                "suspend  ", "resume   ", "ch_prior ", 
                                "send     ", "receive  ", "disk_read",
                                "disk_wrt ", "def_sh_ar" };

INT16       remove_this_in_your_code = TRUE;   /** TEMP **/
INT16       how_many_interrupt_entries = 0;    /** TEMP **/

void    interrupt_handler( void )
    {
    INT16       index;
    INT16       vector;

    for ( index = 0; index <= LARGEST_STAT_VECTOR_INDEX; index++ )
        if ( STAT_VECTOR[SV_ACTIVE][ index ] != 0 )
            vector = index;

    /** REMOVE THE NEXT TWO LINES **/
    how_many_interrupt_entries++;                         /** TEMP **/
    if ( remove_this_in_your_code && ( how_many_interrupt_entries < 10 ) )
        {
        printf( "Interrupt_handler: Found vector type %d with value %d\n", 
                        vector, STAT_VECTOR[SV_VALUE][vector] );
    }
}                                       /* End of interrupt_handler */

void    fault_handler( void )
    {
    INT16       index;
    INT16       vector;

    for ( index = 0; index <= LARGEST_STAT_VECTOR_INDEX; index++ )
        if ( STAT_VECTOR[SV_ACTIVE][ index ] != 0 )
            vector = index;

    printf( "Fault_handler: Found vector type %d with value %d\n", 
                        vector, STAT_VECTOR[SV_VALUE][vector] );

}                                       /* End of fault_handler */

void    svc( void )
    {
    INT16       call_type;

    call_type = STAT_VECTOR[SV_VALUE][(INT16)SOFTWARE_TRAP];

    printf( "SVC handler: %s %8ld %8ld %8ld %8ld %8ld %8ld\n",
                call_names[call_type], Z502_REG_ARG1.VAL, Z502_REG_ARG2.VAL, 
                Z502_REG_ARG3.VAL, Z502_REG_ARG4.VAL, 
                Z502_REG_ARG5.VAL, Z502_REG_ARG6.VAL );

}                                               /* End of svc       */

void    os_switch_context_complete( void )
    {
    printf( "os_switch_context_complete  called before going to user code.\n");
}                               /* End of os_switch_context_complete */


void    os_init( void )
    {
    CONTEXT             *next_context;
    INT32               i;

    /* Demonstrates how calling arguments are passed thru to here       */

    printf( "Program called with %ld arguments:", CALLING_ARGC );
    for ( i = 0; i < CALLING_ARGC; i++ )
        printf( " %s", CALLING_ARGV[i] );
    printf( "\n" );
    printf( "Calling with argument 'sample' executes the sample program.\n" );

    /*          Setup so handlers will come to code in base.c           */

    TO_VECTOR[TO_VECTOR_INT_HANDLER_ADDR]   = (void *)interrupt_handler;
    TO_VECTOR[TO_VECTOR_FAULT_HANDLER_ADDR] = (void *)fault_handler;
    TO_VECTOR[TO_VECTOR_TRAP_HANDLER_ADDR]  = (void *)svc;

    for ( i = 0; i <= LARGEST_STAT_VECTOR_INDEX; i++ )
        {
        STAT_VECTOR[SV_ACTIVE][i] = 0;
        STAT_VECTOR[SV_VALUE ][i] = 0;
    }

    /*  Determine if the switch was set, and if so go to demo routine.  */

    if (( CALLING_ARGC > 1 ) && ( strcmp( CALLING_ARGV[1], "sample" ) == 0 ) )
        {
        ZCALL( Z502_MAKE_CONTEXT( &next_context, 
                                        (void *)sample_code, KERNEL_MODE ));
        ZCALL( Z502_SWITCH_CONTEXT( SWITCH_CONTEXT_KILL_MODE, &next_context ));
    }                   /* This routine should never return!!           */

    /*  This should be done by a "os_make_process" routine, so that
        test1a runs on a process recognized by the operating system.    */

    ZCALL( Z502_MAKE_CONTEXT( &next_context, (void *)test1a, USER_MODE ));
    ZCALL( Z502_SWITCH_CONTEXT( SWITCH_CONTEXT_KILL_MODE, &next_context ));

}                                               /* End of os_init       */
