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

        This routine, "sample", is designed to show you how to interface
        to various hardware functions and how to use scheduler_printer.
        It is provided solely as an example; it is NOT part of the normal
        code involved in building your Operating System.

        Revision History:
	     1.3 July     1992: Initial code written.
	     1.4 December 1992: Add test to size host machine memory.

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

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

void    starting_point_for_new_context( void );

extern BOOL              POP_THE_STACK;

void    sample_code( void )
    {
    INT32       j;                              /* Index                  */

    INT32       time_to_delay;                  /* Used for delay_timer   */

    INT16       disk_id, cylinder, sector;      /* Used for disk requests */
    char        disk_buffer_write[ PGSIZE ];
    char        disk_buffer_read[ PGSIZE ];

    CONTEXT     *context_pointer;               /* Used for context commands*/
    void        *starting_address;
    BOOL        kernel_or_user;

    INT32       time_since_midnight;            /* Used for clock command   */


    /*********************************************************************
                Show the interface to the disk read and write.
                Eventually the disk will interrupt ( in base.c there's
                a handler for this ), but here in sample_code.c we're
                merely showing the interface to start the call.
    *********************************************************************/

    disk_id  = 1;               /* Pick arbitrary disk location             */
    cylinder = 2;
    sector   = 3;
                                /* Put data into the buffer being written   */
    strcpy( disk_buffer_write, "123456789abcdef" );
                                /* Do the hardware call to put data on disk */
    ZCALL( Z502_WRITE_DISK( disk_id, cylinder, sector, disk_buffer_write ) );
                                /* Read data back from the disk             */
    ZCALL( Z502_IDLE() );       /* Wait until the disk "finishes" the write.
                                   the write is an "unpended-io", meaning
                                   the call returns before the work is
                                   completed.  By doing the IDLE here, we
                                   wait for the disk action to complete.    */

    ZCALL( Z502_READ_DISK( disk_id, cylinder, sector, disk_buffer_read ) );
    ZCALL( Z502_IDLE() );       /* Again wait for the disk action to 
                                   complete.                                */

    printf( "\n\nThe disk data written is: %s\n", disk_buffer_write );
    printf( "The disk data read    is: %s\n", disk_buffer_read );

    /*********************************************************************
                Test 2e makes extensive use of the disk system.  In
		fact it puts thousands of items on the disk.  Here we
		test that the system that you're running on has enough
		memory to handle this.
    *********************************************************************/

    printf( "\nThe following test may take a few seconds to execute.\n" );
    printf( "The following test may take a few seconds to execute.\n\n" );
    disk_id = 1;
    cylinder = 0;
    sector = 0;
    for ( j = 0; j < 3 * VIRTUAL_MEM_PGS + 100/* arbitrary # */; j++ )
	{
        ZCALL( Z502_WRITE_DISK(disk_id, cylinder, sector, disk_buffer_write));
        ZCALL( Z502_IDLE() );       
	sector++;
	if ( sector >= NUM_SECTORS )
	    {
	    sector = 0;
	    cylinder++;
	}
	if ( cylinder >= NUM_CYLINDERS )
	    {
	    cylinder = 0;
	    disk_id++;
	}
    }
    printf( "\nIf you got here without the hardware complaining,\n" );
    printf( "then you have approximately enough memory for the disk data.\n");
    printf( "This does NOT account for other memory uses such as code\n" );
    printf( "and other data storage you may do during this project.\n");


    /*********************************************************************
                Show the interface to the delay timer.
                Eventually the timer will interrupt ( in base.c there's
                a handler for this ), but here in sample_code.c wee're
                merely showing the interface to start the call.
    *********************************************************************/

    time_to_delay = 17;                         /* You pick the time units */
    ZCALL( Z502_DELAY_TIMER( time_to_delay ) );

    /*********************************************************************
                Show the interface to memory read and write.
    *********************************************************************/

    /*  It turns out, that though these are hardware calls, the Z502 
        assumes the calls are being made in user mode.  Because the
        process we're running here in "sample" is in kernel mode, 
        the calls don't work correctly.  For working examples of 
        these calls, see test2a.                                            */

    /*********************************************************************
                Show the interface to the CONTEXT calls.
                We aren't going to do a SWITCH_CONTEXT here, because
                that would cause us to start a process is a strange
                place and we might never return here.
    *********************************************************************/

    /* The context_pointer is returned by the MAKE_CONTEXT call.        */

    starting_address = (void *)starting_point_for_new_context;
    kernel_or_user = USER_MODE;
    ZCALL( Z502_MAKE_CONTEXT( &context_pointer, 
                                     starting_address, kernel_or_user ) );
    ZCALL( Z502_DESTROY_CONTEXT( &context_pointer ) );

    /*********************************************************************
                Show the interface to the Z502_CLOCK
    *********************************************************************/

    ZCALL( Z502_CLOCK( &time_since_midnight ));
    printf( "\nThe system says the time is %ld\n\n", time_since_midnight );


    /*********************************************************************
                Show the interface to the scheduler printer.
    *********************************************************************/

    ZCALL( SP_setup( SP_TIME_MODE, 99999 ) );
    ZCALL( SP_setup_action( SP_ACTION_MODE, "CREATE" ) );
    ZCALL( SP_setup( SP_TARGET_MODE, 99L ) );
    ZCALL( SP_setup( SP_RUNNING_MODE, 99L ) );
    for ( j= 0 ; j< SP_MAX_NUMBER_OF_PIDS; j++ )
        ZCALL( SP_setup( SP_READY_MODE, j ) );
    for ( j= 0 ; j< SP_MAX_NUMBER_OF_PIDS; j++ )
        ZCALL( SP_setup( SP_WAITING_MODE, j+20 ) );
    for ( j= 0 ; j< SP_MAX_NUMBER_OF_PIDS; j++ )
        ZCALL( SP_setup( SP_SUSPENDED_MODE, j+40 ) );
    for ( j= 0 ; j< SP_MAX_NUMBER_OF_PIDS; j++ )
        ZCALL( SP_setup( SP_SWAPPED_MODE, j+60 ) );
    for ( j= 0 ; j< SP_MAX_NUMBER_OF_PIDS; j++ )
        ZCALL( SP_setup( SP_TERMINATED_MODE, j+80 ) );
    for ( j= 0 ; j< SP_MAX_NUMBER_OF_PIDS; j++ )
        ZCALL( SP_setup( SP_NEW_MODE, j+50 ) );
    ZCALL( SP_print_header() );
    ZCALL( SP_print_line() );

    /*********************************************************************
                Show the interface to the Z502_HALT.
        Note that the program will end NOW, since we don't return 
        from the command.
    *********************************************************************/

    ZCALL( Z502_HALT( ) );
    
}

void    starting_point_for_new_context( void )
    {
}
