/******************************************************************************
 * wait.c - Chapter 6 sample code                                             *
 *                                                                            *
 * To be used with mach64 sample code                                         *
 * This module contains primitives for mach64 engine FIFO discipline.         *
 * Included are functions to wait for engine idle and FIFO entries.           *
 *                                                                            *
 * Copyright (c) 1994-1997 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <dos.h>
#include "atim64.h"
#include "defines.h"
#include "main.h"

unsigned long fifo_stat;
unsigned long gui_stat;

/******************************************************************************
 * wait_for_idle - wait until engine active bit is idle.                      *
 *  Function: This function uses the DOS tick counter to serve as a           *
 *            timeout clock. If the engine is in a lockup condition,          *
 *            the busy bit may stay set. In this case, a timeout will         *
 *            occur, an error message will occur, and the program will        *
 *            terminate.                                                      *
 *    Inputs: NONE                                                            *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void wait_for_idle (void)
{
    unsigned int starttick, endtick;

    // Insure FIFO is empty before waiting for engine idle.
    wait_for_fifo (16);

    starttick = *((unsigned int *) (DOS_TICK_ADDRESS));
    endtick = starttick;
    while ((regr (GUI_STAT) & ENGINE_BUSY) != ENGINE_IDLE)
    {
        endtick = *((unsigned int *) (DOS_TICK_ADDRESS));
        if (abs (endtick - starttick) > IDLE_TIMEOUT)
        {
            fifo_stat = regr (FIFO_STAT);
            gui_stat = regr (GUI_STAT);
            terminate (BAD_IDLE);
        } // if
    } // while

    return;

} // wait_for_idle


/******************************************************************************
 * wait_for_fifo - wait n empty FIFO entries.                                 *
 *  Function: The FIFO contains upto 16 empty entries. The 'entries'          *
 *            value must be 1 to 16. This function implements the same        *
 *            timeout mechanism as the Waitforidle() function.                *
 *    Inputs: entries - number of entries spaces to wait for. Max - 16        *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void wait_for_fifo (int entries)
{
    unsigned int starttick, endtick;

    starttick = *((unsigned int *) (DOS_TICK_ADDRESS));
    endtick = starttick;
    while ((regr (FIFO_STAT) & 0xFFFF) > ((unsigned int) (0x8000 >> entries)))
    {
        endtick = *((unsigned int *) (DOS_TICK_ADDRESS));
        if (abs (endtick - starttick) > FIFO_TIMEOUT)
        {
            fifo_stat = regr (FIFO_STAT);
            gui_stat = regr (GUI_STAT);
            terminate (BAD_FIFO);
        } // if
    } // while

    return;

} // wait_for_fifo


/******************************************************************************
 * terminate                                                                  *
 *  Function: terminates the program due to a timeout from wait_for_idle      *
 *            or wait_for_fifo.                                               *
 *    Inputs: idle_problem - error code defined in defines.h                  *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void terminate (int idle_problem)
{
    // Disable accelerator and switch back to VGA mode.
    set_old_mode ();

    // Print error message.
    if (idle_problem == BAD_IDLE)
    {
        printf ("Error. Timeout exceeded for engine idle.\n");
    }
    else
    {
        // BAD_FIFO.
        printf ("Error. Timeout exceeded for engine fifo.\n");
    }

    printf ("Status at error:\n");
    printf ("  Idle status  : %08lx\n", gui_stat & 1);
    printf ("  Fifo status  : %08lx\n", fifo_stat & 0xFFFF);
    printf ("  Fifo overflow: %08lx\n", fifo_stat >> 31);

    exit (1);

} // terminate
