/*	Title	All-Pro Diagnostics Execution Control*/
/******************************************************************************/
/*				     Diagexec				      */
/*			       All-pro Diagnostic Editor Support	      */
/*									      */
/* Module ...................... DIAGEXEC				      */
/* Title ....................... All-pro Diagnostic Execution Control	      */
/* Developing Engineer ......... Steven T. Harr 			      */
/* Company ..................... Logical Devices			      */
/* Revision Level .............. 1.00					      */
/* Date of Last Revision ....... 02-26-87				      */
/* Last Revision by ............ STH					      */
/* Developing System .......... IBM PC or compatible			      */
/* Target System .............. IBM PC or compatible			      */
/* Language ................... C					      */
/* Compiler ................... Manx Aztec C v3.20e			      */
/* Compiler Command(s) ........ cc Diagexec				      */
/*									      */
/* Interpreter ................ none					      */
/*									      */
/* Synopsis ................... This module contains the Diagnostic	      */
/*				trouble shooting program execution control.   */
/*									      */
/* Revision History:							      */
/*  v1.00   02-26-87		Original version - STH			      */
/*									      */
/******************************************************************************/
/*	Subttl	Includes*/
#include <stdio.h>
#include <ctype.h>
#include "cmdfile.h"
#include "keybrd.h"
#include "diag2.h"
#include "diagedit.h"
#include "pindrivr.h"
#include "diagpars.h"


#define BIT_ZERO		0x01
#define BIT_SIGN		0x02
#define BIT_CARRY		0x04
#define ERROR_STACK_OVER	1
#define ERROR_STACK_UNDER	2
#define ERR_PSTACK_OVER 	3
#define ERR_PSTACK_UNDER	4
#define STACK_SIZE		10
#define PSTACK_SIZE		10


extern phys_pin_offset;
extern int set_pin_cnf ();
extern int set_pin_dac ();
extern int udi_read_bit ();
extern int read_pin_voltage ();
extern unsigned char analog_id;
extern char key_word_table [MAX_KEY_WORDS] [MAX_COMMAND_SIZE];

int acc_reg;
int flag_reg;
int run_time_error;
int psp = 0;
int pstack [PSTACK_SIZE];
char str_buffer [80];
unsigned char *obj_bffr;


execute_program (program_seg)
unsigned char *program_seg;
{
    long crt_get_cur_pos ();
    unsigned char *ip; /* instruction pointer */
    int sp; /* stack pointer */
    int stack [STACK_SIZE];
    int arg [4];
    int end;
    int branch;
    int offset;
    int single_step;
    int temp_acc;
    int key;
    int i;
    int cur_row;
    int cur_col;

    sp = 0;
    obj_bffr = ip = program_seg;

    end = FALSE;
    run_time_error = FALSE;

    printf ("%s","Single step (Y/N)? ");
    if ((key = toupper (keybrd_getc ())) == 'Y')
    {
	single_step = TRUE;
    }
    else
    {
	single_step = FALSE;
    }
    video_clear_screen ();
    crt_pos_cursor (2, 1, 0);
    while ((ip [1] != CMD_BEGIN) && (ip [0] != 0))
    {
	ip += *ip;
    }

    reset_allpro();
    udi_write_bit (DAC_REFERENCE_BIT, ON);
    udi_write_dac (SUPPLY1_POWER_DAC, 2400);
    udi_write_dac (SLEW_RATE_DAC, 50);
    udi_write_dac (PU_CONTROL_DAC, 600);

    while (!end && ip [0] && !run_time_error)
    {
	branch = FALSE;

	if (single_step)
	{
	    temp_acc = (int) (crt_get_cur_pos (0) >> 16);
	    cur_col = temp_acc & 0xff;
	    cur_row = temp_acc / 256;
	    crt_pos_cursor (1, 0, 0);
	    for (i = 0; i < 8; i++)
	    {
		printf ("          ");
	    }
	    crt_pos_cursor (1, 1, 0);
	    printf ("%4x = ", ip - program_seg);
	    printf ("%s ", &key_word_table [ip [1]] [0]);
	    if (ip [1] == CMD_PRINT && ip [2] == ARG_STRING)
	    {
		printf ("  %s", &ip [3]);
	    }
	    else if (ip [1] == ARG_LABEL)
	    {
		printf ("  %s", &ip [2]);
	    }
	    else
	    {
		for (i = 2; i < ip [0]; i++)
		{
		    printf ("%3x", (unsigned char) ip [i]);
		}
	    }
	    printf (" > %4x", (unsigned int) (ip - program_seg) + ip [0]);
	    key = toupper (keybrd_getc ());
	    crt_pos_cursor ( cur_row, cur_col, 0);
	    if (key == 'Q' || key == KEY_ESC)
	    {
		return (1);
	    }
	}
	else if(keyboard_status() != -1)
	{
	    printf("Break (Y/N)? ");
	    key = toupper(keybrd_getc());
	    if(key == 'Y') return(1);
	}

	switch (ip [1])
	{
	    case ARG_LABEL:
	    case CMD_DEFINE:
	    {
		break;
	    }

	    case CMD_WRPIN:
	    {
		switch (ip [6])
		{
		    case ARG_VARIABLE:
		    {
			arg [1] = val (program_seg + val (ip + 7));
			break;
		    }
		    case ARG_NUMBER:
		    {
			arg [1] = val (ip + 7);
			break;
		    }
		    case ARG_SOURCE:
		    {
			arg [1] = SRC_DRIVER_ON;
			break;
		    }
		    case ARG_GROUND:
		    {
			arg [1] = GD_DRIVER_ON;
			break;
		    }
		    case ARG_PULLUP:
		    {
			arg [1] = PU_DRIVER_ON;
			break;
		    }
		    case ARG_TTL_HI:
		    {
			arg [1] = TTL_HI_DRIVER_ON;
			break;
		    }
		    case ARG_TTL_LOW:
		    {
			arg [1] = TTL_HI_DRIVER_ON;
			break;
		    }
		}

		if (ip [3] == ARG_VARIABLE)
		{
		    arg [0] = val (program_seg + val (ip + 4));
		}
		else /* must be immediate number */
		{
		    arg [0] = val (ip + 4);
		}

		if ((arg [0] > 0) && (arg [0] <= MAX_DEVICE_PINS))
		{
		    if (ip [2] == ARG_DAC)
		    {
			set_pin_dac (arg [0], arg [1]);
		    }
		    else /* must be conf */
		    {
			set_pin_cnf (arg [0], arg [1]);
		    }
		}
		break;
	    }

	    case CMD_RDPIN:
	    {
		if (ip [3] == ARG_VARIABLE)
		{
		    arg [0] = val (program_seg + val (ip + 4));
		}
		else
		{
		    arg [0] = val (ip + 4);
		}

		if (ip [2] == ARG_VOLTS)
		{
		    temp_acc = read_pin_voltage (arg [0]);
		}
		else /* must be comparator */
		{
		    temp_acc = udi_read_bit (arg [0] + phys_pin_offset);
		}

		if (ip [6] == ARG_VARIABLE)
		{
		    put_variable (program_seg + val (ip + 7), temp_acc);
		}
		else if (ip [6] == ARG_ACC)
		{
		    acc_reg = temp_acc;
		}
		break;
	    }

	    case CMD_WRCOMM:
	    {
		switch (ip [2])
		{
		    case ARG_THRESH:
		    {
			arg [0] = THRESH_HOLD_DAC;
			break;
		    }
		    case ARG_SLEWRATE:
		    {
			arg [0] = SLEW_RATE_DAC;
			break;
		    }
		    case ARG_POWER:
		    {
			arg [0] = SUPPLY1_POWER_DAC;
			break;
		    }
		    case ARG_PULLUP:
		    {
			arg [0] = PU_CONTROL_DAC;
			break;
		    }
		    case ARG_CURRENT:
		    {
			arg [0] = CURRENT_DAC;
			break;
		    }
		}
		if (ip [3] == ARG_VARIABLE)
		{
		    arg [1] = val (program_seg + val (ip + 4));
		}
		else
		{
		    arg [1] = val (ip + 4);
		}
		udi_write_dac (arg [0], arg [1]);
		break;
	    }
	    case CMD_RDCOMM:
	    {
		if (ip [2] == ARG_ID)
		{
		    get_analog_id ();
		    arg [0] = analog_id;
		}
		else
		{
		    arg [0] = udi_read_ovc ();
		}
		put_variable (program_seg + val (ip + 4), arg [0]);

		break;
	    }
	    case CMD_WRMEM:
	    {
		if (ip [2] == ARG_VARIABLE) arg [0] = val (program_seg + val (ip + 3));
		else arg [0] = val (ip + 3);
		if (ip [5] == ARG_VARIABLE) arg [1] = val (program_seg + val (ip + 6));
		else arg [1] = val (ip + 6);
		udi_write_mem (arg [0], arg [1]);
		break;
	    }
	    case CMD_RDMEM:
	    {
		if (ip [2] == ARG_VARIABLE) arg [0] = val (program_seg + val (ip + 3));
		else arg [0] = val (ip + 3);
		put_variable (program_seg + val (ip + 6), udi_read_mem(arg [0]));
		break;
	    }


	    case CMD_PUSH:
	    {
		break;
	    }

	    case CMD_POP:
	    {
		break;
	    }

	    case CMD_BRA:
	    {
		offset = (ip [4] << 8) + ip [3];
		switch (ip [2])
		{
		    case ARG_EQU:
		    {
			branch = flag_reg & BIT_ZERO;
			break;
		    }
		    case ARG_NEQ:
		    {
			branch = ~flag_reg & BIT_ZERO;
			break;
		    }
		    case ARG_GT:
		    {
			branch = !(flag_reg & (BIT_ZERO | BIT_SIGN));
			break;
		    }
		    case ARG_LT:
		    {
			branch = flag_reg & (BIT_SIGN | BIT_ZERO);
			break;
		    }
		    case ARG_NLT:
		    case ARG_GTE:
		    {
			branch = ~flag_reg & BIT_SIGN;
			break;
		    }
		    case ARG_NGT:
		    case ARG_LTE:
		    {
			branch = flag_reg & (BIT_SIGN | BIT_ZERO);
			break;
		    }
		    case ARG_OVF:
		    {
			break;
		    }
		    case ARG_UNC:
		    {
			branch = TRUE;
			break;
		    }
		}
		break;
	    }
	    case CMD_CALL:
	    {
		if (sp < STACK_SIZE)
		{
		    stack [sp++] = ip - program_seg + ip [0];
		    offset = ip [2] + (ip [3] << 8);
		    branch = TRUE;
		}
		else
		{
		    run_time_error = ERROR_STACK_OVER;
		}
		break;
	    }
	    case CMD_RETURN:
	    case CMD_RET:
	    {
		if (sp)
		{
		    offset = stack [--sp];
		    branch = TRUE;
		}
		else
		{
		    run_time_error = ERROR_STACK_UNDER;
		}
		break;
	    }

	    case CMD_PRINT:
	    {
		unsigned char *pptr;

		pptr = &ip [3];
		for (i = 0; i < ip [2]; i++)
		{
		    if (pptr [0] == ARG_VARIABLE)
		    {
			printf ("%d", val (program_seg + val (pptr + 1)));
			pptr += 2;
		    }
		    else if (pptr [0] == ARG_STRING)
		    {
			if (pptr [1] == 1)
			{
			    printf ("\n");
			}
			else
			{
			    printf ("%s", &pptr [2]);
			}
			pptr += pptr [1] + 2;
		    }
		}
		break;
	    }
	    case CMD_END:
	    {
		end = TRUE;
		if (!single_step)
		{
		    printf ("\nType any key to return to menu");
		    while (keyboard_status () == -1);
		}
		break;
	    }
	    case ARG_CALC:
	    {
		unsigned char *tip;

		tip = &ip [5];

		if (*tip == ARG_VARIABLE)
		{
		    temp_acc = val (program_seg + val (tip + 1));
		    tip += 3;
		}
		else if (*tip == ARG_NUMBER)
		{
		    temp_acc = val (tip + 1);
		    tip += 3;
		}
		else if (*tip == ARG_ACC)
		{
		    temp_acc = acc_reg;
		    tip++;
		}
		else if (*tip == ARG_FLAGS)
		{
		    temp_acc = flag_reg;
		    tip++;
		}
		else
		{
		    temp_acc = 0;
		    tip++;
		}
		while (*tip && !run_time_error)
		{
		    switch (*tip++)
		    {
			case ARG_VARIABLE:
			{
			    push_pstack (temp_acc);
			    temp_acc = val (program_seg + val (tip));
			    tip += 2;
			    break;
			}
			case ARG_NUMBER:
			{
			    push_pstack (temp_acc);
			    temp_acc = val (tip);
			    tip += 2;
			    break;
			}
			case ARG_ACC:
			{
			    push_pstack (temp_acc);
			    temp_acc = acc_reg;
			    break;
			}
			case ARG_FLAGS:
			{
			    push_pstack (temp_acc);
			    temp_acc = flag_reg;
			    break;
			}
			case OPR_ADD:
			{
			    temp_acc += pop_pstack ();
			    break;
			}
			case OPR_SUB:
			{
			    temp_acc = pop_pstack () - temp_acc;
			    break;
			}
			case OPR_MUL:
			{
			    temp_acc *= pop_pstack ();
			    break;
			}
			case OPR_DIV:
			{
			    if (temp_acc)
				temp_acc = pop_pstack () / temp_acc;
			    else
				temp_acc = (0xffff, pop_pstack ()) ;
			    break;
			}
			case OPR_AND:
			{
			    temp_acc &= pop_pstack ();
			    break;
			}
			case OPR_OR:
			{
			    temp_acc |= pop_pstack ();
			    break;
			}
			case OPR_MOD:
			{
			    if (temp_acc)
				temp_acc = pop_pstack () % temp_acc;
			    else
				temp_acc = (0, pop_pstack ());
			    break;
			}
			case OPR_SHR:
			{
			    temp_acc = pop_pstack () >> temp_acc;
			    break;
			}
			case OPR_SHL:
			{
			    temp_acc = pop_pstack () << temp_acc;
			    break;
			}
		    }
		}
		put_variable (program_seg + val (ip + 3), temp_acc);
		break;
	    }
	    case CMD_CMP:
	    {
		flag_reg = 0;

		arg [1] = val (ip + 6);
		if (ip [5] == ARG_VARIABLE)
		{
		    arg [1] = val (program_seg + arg [1]);
		}

		arg [0] = val (ip + 3);
		if (ip [2] == ARG_VARIABLE)
		{
		    arg [0] = val (program_seg + arg [0]);
		}

		if (arg [0] == arg [1])
		{
		    flag_reg |= BIT_ZERO;
		}
		else if (arg [0] < arg [1])
		{
		    flag_reg |= BIT_SIGN;
		    flag_reg |= BIT_CARRY;
		}
		break;
	    }
	    case CMD_PAUSE:
	    {
		while (keyboard_status () == -1);
		break;
	    }
	    case CMD_DELAY:
	    {
		if (ip [3] == ARG_NUMBER)
		{
		    arg [0] = val (ip + 4);
		}
		else
		{
		    arg [0] = val (program_seg + val (ip + 4));
		}

		if (ip [2] == ARG_MS)
		{
		    delay_ms (arg [0]);
		}
		else
		{
		    delay_us (arg [0]);
		}
		break;
	    }
	    case CMD_INPUT:
	    {
		if (ip [2] == ARG_CHAR)
		{
		    arg [0] = keybrd_getc ();
		    printf ("%c",arg [0]);
		}
		else
		{
		    get_input_line (&str_buffer [0]);
		}
		if (ip [2] == ARG_DEC)
		{
		    sscanf (&str_buffer [0], "%d", &arg [0]);
		}
		else if (ip [2] == ARG_HEX)
		{
		    sscanf (&str_buffer [0], "%x", &arg [0]);
		}
		put_variable (program_seg + val (ip + 4), arg [0]);
		break;
	    }
	    default:
	    {
		break;
	    }
	}

	if (!branch)
	{
	    ip += *ip;
	}
	else
	{
	    ip = &program_seg [offset];
	}
    }
    if (run_time_error)
    {
	printf ("\n");
	if (run_time_error == ERROR_STACK_OVER)
	{
	    printf ("%s\n", "Stack runs over");
	}
	else if (run_time_error == ERROR_STACK_UNDER)
	{
	    printf ("%s\n", "Stack runs under");
	}
	else if (run_time_error == ERR_PSTACK_OVER)
	{
	    printf ("%s\n", "Parameter stack runs over");
	}
	else if (run_time_error == ERR_PSTACK_UNDER)
	{
	    printf ("%s\n", "Parameter stack runs under");
	}
	printf ("%s","Press any key to quit");
	keybrd_getc ();
    }
    unpump();
}


get_input_line (buffer_ptr)
char *buffer_ptr;
{
    char *tmp;

    tmp = buffer_ptr;
    while ((*tmp = keybrd_getc ()) != KEY_CR)
    {
	if ((*tmp >= 0x20) && (*tmp <= 0x7e))
	{
	    printf ("%c", *tmp);
	}
	if (*tmp == 8)
	{
	    if (tmp > buffer_ptr)
	    {
		printf ("%c", 0x08);
		printf ("%c", ' ');
		printf ("%c", 0x08);
		*tmp-- = '\0';
	    }
	}
	else
	{
	    tmp++;
	}
    }
    *tmp = '\0';
}

push_pstack (arg)
int arg;
{
    if (psp < PSTACK_SIZE)
    {
	pstack [psp++] = arg;
    }
    else
    {
	run_time_error = ERR_PSTACK_OVER;
    }
}


pop_pstack ()
{
    if (psp)
    {
	return (pstack [--psp]);
    }
    run_time_error = ERR_PSTACK_UNDER;
    return (0);
}


put_variable (var_adr, var_val)
unsigned char *var_adr;
int var_val;
{
    var_adr [0] = (unsigned char) (var_val & 0xff);
    var_adr [1] = (unsigned char) (var_val / 256);
}



val (ch_ptr)
unsigned char *ch_ptr;
{
    return (*ch_ptr + ((unsigned int) ch_ptr [1] << 8));
}
