common/recipes-utils/jbi/files/code/jbistub.c (1,911 lines of code) (raw):
/****************************************************************************/
/*																			*/
/*	Module:			jbistub.c												*/
/*																			*/
/*					Copyright (C) Altera Corporation 1997-2001				*/
/*																			*/
/*	Description:	Jam STAPL ByteCode Player main source file				*/
/*																			*/
/*					Supports Altera ByteBlaster hardware download cable		*/
/*					on Windows 95 and Windows NT operating systems.			*/
/*					(A device driver is required for Windows NT.)			*/
/*																			*/
/*					Also supports BitBlaster hardware download cable on		*/
/*					Windows 95, Windows NT, and UNIX platforms.				*/
/*																			*/
/*	Revisions:		1.1 fixed control port initialization for ByteBlaster	*/
/*					2.0 added support for STAPL bytecode format, added code	*/
/*						to get printer port address from Windows registry	*/
/*					2.1 improved messages, fixed delay-calibration bug in	*/
/*						16-bit DOS port, added support for "alternative		*/
/*						cable X", added option to control whether to reset	*/
/*						the TAP after execution, moved porting macros into	*/
/*						jbiport.h											*/
/*					2.2 added support for static memory						*/
/*						fixed /W4 warnings									*/
/*																			*/
/****************************************************************************/
#ifndef NO_ALTERA_STDIO
#define NO_ALTERA_STDIO
#endif
#if ( _MSC_VER >= 800 )
#pragma warning(disable:4115)
#pragma warning(disable:4201)
#pragma warning(disable:4214)
#pragma warning(disable:4514)
#endif
#include "jbiport.h"
#if PORT == WINDOWS
#include <windows.h>
#else
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
#define TRUE 1
#define FALSE 0
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef OPENBMC
#include <io.h>
#endif
#include <fcntl.h>
#ifndef OPENBMC
#include <process.h>
#endif
#if defined(USE_STATIC_MEMORY)
	#define N_STATIC_MEMORY_KBYTES ((unsigned int) USE_STATIC_MEMORY)
	#define N_STATIC_MEMORY_BYTES (N_STATIC_MEMORY_KBYTES * 1024)
	#define POINTER_ALIGNMENT sizeof(DWORD)
#else /* USE_STATIC_MEMORY */
	#include <malloc.h>
	#define POINTER_ALIGNMENT sizeof(BYTE)
#endif /* USE_STATIC_MEMORY */
#include <time.h>
#ifndef OPENBMC
#include <conio.h>
#endif
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef OPENBMC
//#define VERBOSE
//#define DEBUG
#include <openbmc/libgpio.h>
#include <openbmc/hr_nanosleep.h>
#include <openbmc/log.h>
#include <errno.h>
#include <sys/ioctl.h>
#endif
#if PORT == DOS
#include <bios.h>
#endif
#include "jbiexprt.h"
#if PORT == WINDOWS
#define PGDC_IOCTL_GET_DEVICE_INFO_PP 0x00166A00L
#define PGDC_IOCTL_READ_PORT_PP       0x00166A04L
#define PGDC_IOCTL_WRITE_PORT_PP      0x0016AA08L
#define PGDC_IOCTL_PROCESS_LIST_PP    0x0016AA1CL
#define PGDC_READ_INFO                0x0a80
#define PGDC_READ_PORT                0x0a81
#define PGDC_WRITE_PORT               0x0a82
#define PGDC_PROCESS_LIST             0x0a87
#define PGDC_HDLC_NTDRIVER_VERSION    2
#define PORT_IO_BUFFER_SIZE           256
#endif
#if PORT == WINDOWS
#ifdef __BORLANDC__
/* create dummy inp() and outp() functions for Borland 32-bit compile */
WORD inp(WORD address) { address = address; return(0); }
void outp(WORD address, WORD data) { address = address; data = data; }
#else
#pragma intrinsic (inp, outp)
#endif
#endif
/*
*	For Borland C compiler (16-bit), set the stack size
*/
#if PORT == DOS
#ifdef __BORLANDC__
extern unsigned int _stklen = 50000;
#endif
#endif
/************************************************************************
*
*	Global variables
*/
/* file buffer for Jam STAPL ByteCode input file */
#if PORT == DOS
unsigned char **file_buffer = NULL;
#else
unsigned char *file_buffer = NULL;
#endif
long file_pointer = 0L;
long file_length = 0L;
/* delay count for one millisecond delay */
long one_ms_delay = 0L;
/* serial port interface available on all platforms */
BOOL jtag_hardware_initialized = FALSE;
char *serial_port_name = NULL;
BOOL specified_com_port = FALSE;
int com_port = -1;
void initialize_jtag_hardware(void);
void close_jtag_hardware(void);
#ifdef OPENBMC
static int g_swio = 0;
static int g_tck_offset = -1;
static int g_tms_offset = -1;
static int g_tdo_offset = -1;
static int g_tdi_offset = -1;
static const char *g_tck_shadow;
static const char *g_tms_shadow;
static const char *g_tdo_shadow;
static const char *g_tdi_shadow;
static int g_jtag_dev = -1;
static gpio_desc_t *g_gpio_tck;
static gpio_desc_t *g_gpio_tms;
static gpio_desc_t *g_gpio_tdo;
static gpio_desc_t *g_gpio_tdi;
static int g_sysfs_tck_fd = -1;
static int g_sysfs_tms_fd = -1;
static int g_sysfs_tdi_fd = -1;
static int g_sysfs_tdo_fd = -1;
static int (*jtag_io_func)(int, int, int);
#endif
#if defined(USE_STATIC_MEMORY)
	unsigned char static_memory_heap[N_STATIC_MEMORY_BYTES] = { 0 };
#endif /* USE_STATIC_MEMORY */
#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
	unsigned int n_bytes_allocated = 0;
#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
#if defined(MEM_TRACKER)
	unsigned int peak_memory_usage = 0;
	unsigned int peak_allocations = 0;
	unsigned int n_allocations = 0;
#if defined(USE_STATIC_MEMORY)
	unsigned int n_bytes_not_recovered = 0;
#endif /* USE_STATIC_MEMORY */
	const DWORD BEGIN_GUARD = 0x01234567;
	const DWORD END_GUARD = 0x76543210;
#endif /* MEM_TRACKER */
#if PORT == WINDOWS || PORT == DOS
/* parallel port interface available on PC only */
BOOL specified_lpt_port = FALSE;
BOOL specified_lpt_addr = FALSE;
int lpt_port = 1;
int initial_lpt_ctrl = 0;
WORD lpt_addr = 0x3bc;
WORD lpt_addr_table[3] = { 0x3bc, 0x378, 0x278 };
BOOL alternative_cable_l = FALSE;
BOOL alternative_cable_x = FALSE;
void write_byteblaster(int port, int data);
int read_byteblaster(int port);
#endif
#if PORT==WINDOWS
#ifndef __BORLANDC__
WORD lpt_addresses_from_registry[4] = { 0 };
#endif
#endif
#if PORT == WINDOWS
/* variables to manage cached I/O under Windows NT */
BOOL windows_nt = FALSE;
int port_io_count = 0;
HANDLE nt_device_handle = INVALID_HANDLE_VALUE;
struct PORT_IO_LIST_STRUCT
{
	USHORT command;
	USHORT data;
} port_io_buffer[PORT_IO_BUFFER_SIZE];
extern void flush_ports(void);
BOOL initialize_nt_driver(void);
#endif
/* function prototypes to allow forward reference */
extern void delay_loop(long count);
/*
*	This structure stores information about each available vector signal
*/
struct VECTOR_LIST_STRUCT
{
	char *signal_name;
	int  hardware_bit;
	int  vector_index;
};
struct VECTOR_LIST_STRUCT vector_list[] =
{
	/* add a record here for each vector signal */
	{ "", 0, -1 }
};
#define VECTOR_SIGNAL_COUNT ((int)(sizeof(vector_list)/sizeof(vector_list[0])))
BOOL verbose = FALSE;
/************************************************************************
*
*	Customized interface functions for Jam STAPL ByteCode Player I/O:
*
*	jbi_jtag_io()
*	jbi_message()
*	jbi_delay()
*/
#ifdef OPENBMC
#define JTAG_CHAR_DEV "/dev/jtag0"
#ifndef JTAG_SYSFS_DIR
#define JTAG_SYSFS_DIR "/sys/devices/platform/ahb/ahb:apb/1e6e4000.jtag/"
#endif
#define JTAG_SYSFS_TDI JTAG_SYSFS_DIR "tdi"
#define JTAG_SYSFS_TDO JTAG_SYSFS_DIR "tdo"
#define JTAG_SYSFS_TMS JTAG_SYSFS_DIR "tms"
#define JTAG_SYSFS_TCK JTAG_SYSFS_DIR "tck"
#define __JTAG_IOCTL_MAGIC 0xb2
#define JTAG_IOCBITBANG _IOW(__JTAG_IOCTL_MAGIC, 6, unsigned int)
struct tck_bitbang {
  unsigned char tms;
  unsigned char tdi;
  unsigned char tdo;
} __attribute__((__packed__));
static void jtag_swio_write(int fd, int value) {
  if (lseek(fd, 0, SEEK_SET) < 0) {
    fprintf(stderr, "%s: lseek failed\n", __func__);
    return;
  }
  if (write(fd, (value) ? "1" : "0", 1) != 1) {
    fprintf(stderr, "%s: write failed\n", __func__);
  }
  return;
}
static int jtag_swio_read(int fd) {
  char buf[8] = {0};
  if (lseek(fd, 0, SEEK_SET) < 0) {
    fprintf(stderr, "%s: lseek failed\n", __func__);
    return -1;
  }
  if (read(fd, buf, sizeof(buf) - 1) < 1) {
    fprintf(stderr, "%s: read failed\n", __func__);
    return -1;
  }
  return (atoi(buf) ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW);
}
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof((_a)[0]))
#endif
static int initialize_jtag_swio(void) {
  int i, fd;
  struct {
    const char *path;
    int flags;
    int *fd;
  } jtag_fds[4] = {
    {JTAG_SYSFS_TDI, O_WRONLY, &g_sysfs_tdi_fd},
    {JTAG_SYSFS_TCK, O_WRONLY, &g_sysfs_tck_fd},
    {JTAG_SYSFS_TMS, O_WRONLY, &g_sysfs_tms_fd},
    {JTAG_SYSFS_TDO, O_RDONLY, &g_sysfs_tdo_fd},
  };
  if ((g_jtag_dev = open(JTAG_CHAR_DEV, O_RDWR)) < 0) {
    OBMC_ERROR(errno, "failed to open jtag device %s", JTAG_CHAR_DEV);
  } else {
    /* Use ioctl(JTAG_IOCBITBANG) if successfully open Kernel 5.6 JTAG driver */
    return 0;
  }
  for (i = 0; i < ARRAY_SIZE(jtag_fds); i++) {
    fd = open(jtag_fds[i].path, jtag_fds[i].flags);
    if (fd < 0) {
      fprintf(stderr, "failed to open %s: %s\n",
              jtag_fds[i].path, strerror(errno));
      goto error;
    }
    *(jtag_fds[i].fd) = fd;
  }
  /* set tck, tms, tdi to low */
  jtag_swio_write(g_sysfs_tck_fd, GPIO_VALUE_LOW);
  jtag_swio_write(g_sysfs_tms_fd, GPIO_VALUE_LOW);
  jtag_swio_write(g_sysfs_tdi_fd, GPIO_VALUE_LOW);
  jbi_delay(1);
  return 0;
error:
  for (i = 0; i < ARRAY_SIZE(jtag_fds); i++) {
    fd = *(jtag_fds[i].fd);
    if (fd >= 0)
      close(fd);
  }
  return -1;
}
static int jbi_jtag_swio(int tms, int tdi, int read_tdo) {
  int tdo = 0;
  struct tck_bitbang bitbang;
  if (!jtag_hardware_initialized) {
    if (initialize_jtag_swio()) {
      fprintf(stderr, "%s: initialize_jtag_swio() failed\n", __func__);
      return -1;
    }
    jtag_hardware_initialized = TRUE;
  }
  if (g_jtag_dev >= 0) {
    bitbang.tms = tms ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW;
    bitbang.tdi = tdi ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW;
    bitbang.tdo = 0;
    if (ioctl(g_jtag_dev, JTAG_IOCBITBANG, &bitbang) < 0) {
      fprintf(stderr, "%s: ioctl(JTAG_IOCBITBANG) failed\n", __func__);
      return -1;
    }
    if (read_tdo) {
      tdo = bitbang.tdo;
    }
  } else {
    jtag_swio_write(g_sysfs_tms_fd, tms ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW);
    jtag_swio_write(g_sysfs_tdi_fd, tdi ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW);
    /*
     * if we need to read data, the data should be ready from the
     * previous clock falling edge. Read it now.
     */
    if (read_tdo && ((tdo = jtag_swio_read(g_sysfs_tdo_fd)) < 0)) {
      fprintf(stderr, "%s: jtag_swio_read() failed\n", __func__);
      return -1;
    }
    /* do rising edge to clock out the data */
    jtag_swio_write(g_sysfs_tck_fd, GPIO_VALUE_HIGH);
    /* do falling edge clocking */
    jtag_swio_write(g_sysfs_tck_fd, GPIO_VALUE_LOW);
  }
  OBMC_DEBUG("tms=%d tdi=%d do_read=%d tdo=%d", tms, tdi, read_tdo, tdo);
  return tdo;
}
static int initialize_jtag_gpios()
{
  int i;
  gpio_desc_t *desc;
  struct {
    const char *shadow;
    int offset;
    gpio_desc_t **desc;
  } jtag_pins[4] = {
    {g_tck_shadow, g_tck_offset, &g_gpio_tck},
    {g_tms_shadow, g_tms_offset, &g_gpio_tms},
    {g_tdi_shadow, g_tdi_offset, &g_gpio_tdi},
    {g_tdo_shadow, g_tdo_offset, &g_gpio_tdo},
  };
  for (i = 0; i < ARRAY_SIZE(jtag_pins); i++) {
    if (jtag_pins[i].shadow != NULL)
      desc = gpio_open_by_shadow(jtag_pins[i].shadow);
    else if (jtag_pins[i].offset >= 0)
      desc = gpio_open_by_offset(GPIO_CHIP_ASPEED, jtag_pins[i].offset);
    else
      goto error;
    if (desc == NULL)
      goto error;
    *(jtag_pins[i].desc) = desc;
  }
  /* change GPIO directions, only TDO is input, all others are output */
  if (gpio_set_direction(g_gpio_tck, GPIO_DIRECTION_OUT)
      || gpio_set_direction(g_gpio_tms, GPIO_DIRECTION_OUT)
      || gpio_set_direction(g_gpio_tdo, GPIO_DIRECTION_IN)
      || gpio_set_direction(g_gpio_tdi, GPIO_DIRECTION_OUT)) {
    goto error;
  }
  /* set tck, tms, tdi to low */
  gpio_set_value(g_gpio_tck, GPIO_VALUE_LOW);
  gpio_set_value(g_gpio_tms, GPIO_VALUE_LOW);
  gpio_set_value(g_gpio_tdi, GPIO_VALUE_LOW);
  jbi_delay(1);
  OBMC_DEBUG("Opened TCK(GPIO %d), TMS(GPIO %d), "
             "TDI(GPIO %d), and TDO(GPIO %d)",
             g_tck_offset, g_tms_offset, g_tdi_offset, g_tdo_offset);
  return 0;
error:
  for (i = 0; i < ARRAY_SIZE(jtag_pins); i++) {
    desc = *(jtag_pins[i].desc);
    if (desc != NULL)
      gpio_close(desc);
  }
}
static int jbi_jtag_gpio(int tms, int tdi, int read_tdo)
{
  int tdo = 0;
  if (!jtag_hardware_initialized) {
    if (initialize_jtag_gpios()) {
      fprintf(stderr, "%s: initialize_jtag_gpios() failed\n", __func__);
      return -1;
    }
    jtag_hardware_initialized = TRUE;
  }
  gpio_set_value(g_gpio_tms, tms ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW);
  gpio_set_value(g_gpio_tdi, tdi ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW);
  /*
   * if we need to read data, the data should be ready from the
   * previous clock falling edge. Read it now.
   */
  if (read_tdo) {
    gpio_value_t val;
    gpio_get_value(g_gpio_tdo, &val);
    tdo = (val == GPIO_VALUE_HIGH ? 1 : 0);
  }
  /* do rising edge to clock out the data */
  gpio_set_value(g_gpio_tck, GPIO_VALUE_HIGH);
  /* do falling edge clocking */
  gpio_set_value(g_gpio_tck, GPIO_VALUE_LOW);
  OBMC_DEBUG("tms=%d tdi=%d do_read=%d tdo=%d",
             tms, tdi, read_tdo, tdo);
  return tdo;
}
int jbi_jtag_io(int tms, int tdi, int read_tdo)
{
  return jtag_io_func(tms, tdi, read_tdo);
}
#else
int jbi_jtag_io(int tms, int tdi, int read_tdo)
{
	int data = 0;
	int tdo = 0;
	int i = 0;
	int result = 0;
	char ch_data = 0;
	if (!jtag_hardware_initialized)
	{
		initialize_jtag_hardware();
		jtag_hardware_initialized = TRUE;
	}
	if (specified_com_port)
	{
		ch_data = (char)
			((tdi ? 0x01 : 0) | (tms ? 0x02 : 0) | 0x60);
		write(com_port, &ch_data, 1);
		if (read_tdo)
		{
			ch_data = 0x7e;
			write(com_port, &ch_data, 1);
			for (i = 0; (i < 100) && (result != 1); ++i)
			{
				result = read(com_port, &ch_data, 1);
			}
			if (result == 1)
			{
				tdo = ch_data & 0x01;
			}
			else
			{
				fprintf(stderr, "Error:  BitBlaster not responding\n");
			}
		}
		ch_data = (char)
			((tdi ? 0x01 : 0) | (tms ? 0x02 : 0) | 0x64);
		write(com_port, &ch_data, 1);
	}
	else
	{
#if PORT == WINDOWS || PORT == DOS
		data = (alternative_cable_l ? ((tdi ? 0x01 : 0) | (tms ? 0x04 : 0)) :
		       (alternative_cable_x ? ((tdi ? 0x01 : 0) | (tms ? 0x04 : 0) | 0x10) :
		       ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0))));
		write_byteblaster(0, data);
		if (read_tdo)
		{
			tdo = read_byteblaster(1);
			tdo = (alternative_cable_l ? ((tdo & 0x40) ? 1 : 0) :
			      (alternative_cable_x ? ((tdo & 0x10) ? 1 : 0) :
			      ((tdo & 0x80) ? 0 : 1)));
		}
		write_byteblaster(0, data | (alternative_cable_l ? 0x02 : (alternative_cable_x ? 0x02: 0x01)));
		write_byteblaster(0, data);
#else
		/* parallel port interface not available */
		tdo = 0;
#endif
	}
	return (tdo);
}
#endif
void jbi_message(char *message_text)
{
	puts(message_text);
	fflush(stdout);
}
void jbi_export_integer(char *key, long value)
{
	if (verbose)
	{
		printf("Export: key = \"%s\", value = %ld\n", key, value);
		fflush(stdout);
	}
}
#define HEX_LINE_CHARS 72
#define HEX_LINE_BITS (HEX_LINE_CHARS * 4)
char conv_to_hex(unsigned long value)
{
	char c;
	if (value > 9)
	{
		c = (char) (value + ('A' - 10));
	}
	else
	{
		c = (char) (value + '0');
	}
	return (c);
}
void jbi_export_boolean_array(char *key, unsigned char *data, long count)
{
	char string[HEX_LINE_CHARS + 1];
	long i, offset;
	unsigned long size, line, lines, linebits, value, j, k;
	if (verbose)
	{
		if (count > HEX_LINE_BITS)
		{
			printf("Export: key = \"%s\", %ld bits, value = HEX\n", key, count);
			lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS;
			for (line = 0; line < lines; ++line)
			{
				if (line < (lines - 1))
				{
					linebits = HEX_LINE_BITS;
					size = HEX_LINE_CHARS;
					offset = count - ((line + 1) * HEX_LINE_BITS);
				}
				else
				{
					linebits = count - ((lines - 1) * HEX_LINE_BITS);
					size = (linebits + 3) / 4;
					offset = 0L;
				}
				string[size] = '\0';
				j = size - 1;
				value = 0;
				for (k = 0; k < linebits; ++k)
				{
					i = k + offset;
					if (data[i >> 3] & (1 << (i & 7))) value |= (1 << (i & 3));
					if ((i & 3) == 3)
					{
						string[j] = conv_to_hex(value);
						value = 0;
						--j;
					}
				}
				if ((k & 3) > 0) string[j] = conv_to_hex(value);
				printf("%s\n", string);
			}
			fflush(stdout);
		}
		else
		{
			size = (count + 3) / 4;
			string[size] = '\0';
			j = size - 1;
			value = 0;
			for (i = 0; i < count; ++i)
			{
				if (data[i >> 3] & (1 << (i & 7))) value |= (1 << (i & 3));
				if ((i & 3) == 3)
				{
					string[j] = conv_to_hex(value);
					value = 0;
					--j;
				}
			}
			if ((i & 3) > 0) string[j] = conv_to_hex(value);
			printf("Export: key = \"%s\", %ld bits, value = HEX %s\n",
				key, count, string);
			fflush(stdout);
		}
	}
}
void jbi_delay(long microseconds)
{
#if PORT == WINDOWS
	/* if Windows NT, flush I/O cache buffer before delay loop */
	if (windows_nt && (port_io_count > 0)) flush_ports();
#endif
#ifdef OPENBMC
	hr_nanosleep(microseconds * 1000);
#else
	delay_loop(microseconds *
		((one_ms_delay / 1000L) + ((one_ms_delay % 1000L) ? 1 : 0)));
#endif
}
int jbi_vector_map
(
	int signal_count,
	char **signals
)
{
	int signal, vector, ch_index, diff;
	int matched_count = 0;
	char l, r;
	for (vector = 0; (vector < VECTOR_SIGNAL_COUNT); ++vector)
	{
		vector_list[vector].vector_index = -1;
	}
	for (signal = 0; signal < signal_count; ++signal)
	{
		diff = 1;
		for (vector = 0; (diff != 0) && (vector < VECTOR_SIGNAL_COUNT);
			++vector)
		{
			if (vector_list[vector].vector_index == -1)
			{
				ch_index = 0;
				do
				{
					l = signals[signal][ch_index];
					r = vector_list[vector].signal_name[ch_index];
					diff = (((l >= 'a') && (l <= 'z')) ? (l - ('a' - 'A')) : l)
						- (((r >= 'a') && (r <= 'z')) ? (r - ('a' - 'A')) : r);
					++ch_index;
				}
				while ((diff == 0) && (l != '\0') && (r != '\0'));
				if (diff == 0)
				{
					vector_list[vector].vector_index = signal;
					++matched_count;
				}
			}
		}
	}
	return (matched_count);
}
int jbi_vector_io
(
	int signal_count,
	long *dir_vect,
	long *data_vect,
	long *capture_vect
)
{
	int signal, vector, bit;
	int matched_count = 0;
	int data = 0;
	int mask = 0;
	int dir = 0;
	int i = 0;
	int result = 0;
	char ch_data = 0;
	if (!jtag_hardware_initialized)
	{
		initialize_jtag_hardware();
		jtag_hardware_initialized = TRUE;
	}
	/*
	*	Collect information about output signals
	*/
	for (vector = 0; vector < VECTOR_SIGNAL_COUNT; ++vector)
	{
		signal = vector_list[vector].vector_index;
		if ((signal >= 0) && (signal < signal_count))
		{
			bit = (1 << vector_list[vector].hardware_bit);
			mask |= bit;
			if (data_vect[signal >> 5] & (1L << (signal & 0x1f))) data |= bit;
			if (dir_vect[signal >> 5] & (1L << (signal & 0x1f))) dir |= bit;
			++matched_count;
		}
	}
	/*
	*	Write outputs to hardware interface, if any
	*/
	if (dir != 0)
	{
		if (specified_com_port)
		{
			ch_data = (char) (((data >> 6) & 0x01) | (data & 0x02) |
					  ((data << 2) & 0x04) | ((data << 3) & 0x08) | 0x60);
			write(com_port, &ch_data, 1);
		}
		else
		{
#if PORT == WINDOWS || PORT == DOS
			write_byteblaster(0, data);
#endif
		}
	}
	/*
	*	Read the input signals and save information in capture_vect[]
	*/
	if ((dir != mask) && (capture_vect != NULL))
	{
		if (specified_com_port)
		{
			ch_data = 0x7e;
			write(com_port, &ch_data, 1);
			for (i = 0; (i < 100) && (result != 1); ++i)
			{
				result = read(com_port, &ch_data, 1);
			}
			if (result == 1)
			{
				data = ((ch_data << 7) & 0x80) | ((ch_data << 3) & 0x10);
			}
			else
			{
				fprintf(stderr, "Error:  BitBlaster not responding\n");
			}
		}
		else
		{
#if PORT == WINDOWS || PORT == DOS
			data = read_byteblaster(1) ^ 0x80; /* parallel port inverts bit 7 */
#endif
		}
		for (vector = 0; vector < VECTOR_SIGNAL_COUNT; ++vector)
		{
			signal = vector_list[vector].vector_index;
			if ((signal >= 0) && (signal < signal_count))
			{
				bit = (1 << vector_list[vector].hardware_bit);
				if ((dir & bit) == 0)	/* if it is an input signal... */
				{
					if (data & bit)
					{
						capture_vect[signal >> 5] |= (1L << (signal & 0x1f));
					}
					else
					{
						capture_vect[signal >> 5] &= ~(unsigned long)
							(1L << (signal & 0x1f));
					}
				}
			}
		}
	}
	return (matched_count);
}
void *jbi_malloc(unsigned int size)
{
	unsigned int n_bytes_to_allocate =
#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
		sizeof(unsigned int) +
#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
#if defined(MEM_TRACKER)
		(2 * sizeof(DWORD)) +
#endif /* MEM_TRACKER */
		(POINTER_ALIGNMENT * ((size + POINTER_ALIGNMENT - 1) / POINTER_ALIGNMENT));
	unsigned char *ptr = 0;
#if defined(MEM_TRACKER)
	if ((n_bytes_allocated + n_bytes_to_allocate) > peak_memory_usage)
	{
		peak_memory_usage = n_bytes_allocated + n_bytes_to_allocate;
	}
	if ((n_allocations + 1) > peak_allocations)
	{
		peak_allocations = n_allocations + 1;
	}
#endif /* MEM_TRACKER */
#if defined(USE_STATIC_MEMORY)
	if ((n_bytes_allocated + n_bytes_to_allocate) <= N_STATIC_MEMORY_BYTES)
	{
		ptr = (&(static_memory_heap[n_bytes_allocated]));
	}
#else /* USE_STATIC_MEMORY */
	ptr = (unsigned char *) malloc(n_bytes_to_allocate);
#endif /* USE_STATIC_MEMORY */
#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
	if (ptr != 0)
	{
		unsigned int i = 0;
#if defined(MEM_TRACKER)
		for (i = 0; i < sizeof(DWORD); ++i)
		{
			*ptr = (unsigned char) (BEGIN_GUARD >> (8 * i));
			++ptr;
		}
#endif /* MEM_TRACKER */
		for (i = 0; i < sizeof(unsigned int); ++i)
		{
			*ptr = (unsigned char) (size >> (8 * i));
			++ptr;
		}
#if defined(MEM_TRACKER)
		for (i = 0; i < sizeof(DWORD); ++i)
		{
			*(ptr + size + i) = (unsigned char) (END_GUARD >> (8 * i));
			/* don't increment ptr */
		}
		++n_allocations;
#endif /* MEM_TRACKER */
		n_bytes_allocated += n_bytes_to_allocate;
	}
#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
	return ptr;
}
void jbi_free(void *ptr)
{
	if
	(
#if defined(MEM_TRACKER)
		(n_allocations > 0) &&
#endif /* MEM_TRACKER */
		(ptr != 0)
	)
	{
		unsigned char *tmp_ptr = (unsigned char *) ptr;
#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
		unsigned int n_bytes_to_free = 0;
		unsigned int i = 0;
		unsigned int size = 0;
#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
#if defined(MEM_TRACKER)
		DWORD begin_guard = 0;
		DWORD end_guard = 0;
		tmp_ptr -= sizeof(DWORD);
#endif /* MEM_TRACKER */
#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
		tmp_ptr -= sizeof(unsigned int);
#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
		ptr = tmp_ptr;
#if defined(MEM_TRACKER)
		for (i = 0; i < sizeof(DWORD); ++i)
		{
			begin_guard |= (((DWORD)(*tmp_ptr)) << (8 * i));
			++tmp_ptr;
		}
#endif /* MEM_TRACKER */
#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
		for (i = 0; i < sizeof(unsigned int); ++i)
		{
			size |= (((unsigned int)(*tmp_ptr)) << (8 * i));
			++tmp_ptr;
		}
#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
#if defined(MEM_TRACKER)
		tmp_ptr += size;
		for (i = 0; i < sizeof(DWORD); ++i)
		{
			end_guard |= (((DWORD)(*tmp_ptr)) << (8 * i));
			++tmp_ptr;
		}
		if ((begin_guard != BEGIN_GUARD) || (end_guard != END_GUARD))
		{
			fprintf(stderr, "Error: memory corruption detected for allocation #%d... bad %s guard\n",
				n_allocations, (begin_guard != BEGIN_GUARD) ? "begin" : "end");
		}
		--n_allocations;
#endif /* MEM_TRACKER */
#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
		n_bytes_to_free =
#if defined(MEM_TRACKER)
		(2 * sizeof(DWORD)) +
#endif /* MEM_TRACKER */
		sizeof(unsigned int) +
		(POINTER_ALIGNMENT * ((size + POINTER_ALIGNMENT - 1) / POINTER_ALIGNMENT));
#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
#if defined(USE_STATIC_MEMORY)
		if ((((unsigned long) ptr - (unsigned long) static_memory_heap) + n_bytes_to_free) == (unsigned long) n_bytes_allocated)
		{
			n_bytes_allocated -= n_bytes_to_free;
		}
#if defined(MEM_TRACKER)
		else
		{
			n_bytes_not_recovered += n_bytes_to_free;
		}
#endif /* MEM_TRACKER */
#else /* USE_STATIC_MEMORY */
#if defined(MEM_TRACKER)
		n_bytes_allocated -= n_bytes_to_free;
#endif /* MEM_TRACKER */
		free(ptr);
#endif /* USE_STATIC_MEMORY */
	}
#if defined(MEM_TRACKER)
	else
	{
		if (ptr != 0)
		{
			fprintf(stderr, "Error: attempt to free unallocated memory\n");
		}
	}
#endif /* MEM_TRACKER */
}
/************************************************************************
*
*	get_tick_count() -- Get system tick count in milliseconds
*
*	for DOS, use BIOS function _bios_timeofday()
*	for WINDOWS use GetTickCount() function
*	for UNIX use clock() system function
*/
DWORD get_tick_count(void)
{
	DWORD tick_count = 0L;
#if PORT == WINDOWS
	tick_count = GetTickCount();
#elif PORT == DOS
	_bios_timeofday(_TIME_GETCLOCK, (long *)&tick_count);
	tick_count *= 55L;	/* convert to milliseconds */
#else
	/* assume clock() function returns microseconds */
	tick_count = (DWORD) (clock() / 1000L);
#endif
	return (tick_count);
}
#define DELAY_SAMPLES 10
#define DELAY_CHECK_LOOPS 10000
void calibrate_delay(void)
{
	int sample = 0;
	int count = 0;
	DWORD tick_count1 = 0L;
	DWORD tick_count2 = 0L;
	one_ms_delay = 0L;
#if PORT == WINDOWS || PORT == DOS || defined(OPENBMC)
	for (sample = 0; sample < DELAY_SAMPLES; ++sample)
	{
		count = 0;
		tick_count1 = get_tick_count();
		while ((tick_count2 = get_tick_count()) == tick_count1) {};
		do { delay_loop(DELAY_CHECK_LOOPS); count++; } while
			((tick_count1 = get_tick_count()) == tick_count2);
		one_ms_delay += ((DELAY_CHECK_LOOPS * (DWORD)count) /
			(tick_count1 - tick_count2));
	}
	one_ms_delay /= DELAY_SAMPLES;
#else
	/* This is system-dependent!  Update this number for target system */
	one_ms_delay = 1000L;
#endif
}
char *error_text[] =
{
/* JBIC_SUCCESS            0 */ "success",
/* JBIC_OUT_OF_MEMORY      1 */ "out of memory",
/* JBIC_IO_ERROR           2 */ "file access error",
/* JAMC_SYNTAX_ERROR       3 */ "syntax error",
/* JBIC_UNEXPECTED_END     4 */ "unexpected end of file",
/* JBIC_UNDEFINED_SYMBOL   5 */ "undefined symbol",
/* JAMC_REDEFINED_SYMBOL   6 */ "redefined symbol",
/* JBIC_INTEGER_OVERFLOW   7 */ "integer overflow",
/* JBIC_DIVIDE_BY_ZERO     8 */ "divide by zero",
/* JBIC_CRC_ERROR          9 */ "CRC mismatch",
/* JBIC_INTERNAL_ERROR    10 */ "internal error",
/* JBIC_BOUNDS_ERROR      11 */ "bounds error",
/* JAMC_TYPE_MISMATCH     12 */ "type mismatch",
/* JAMC_ASSIGN_TO_CONST   13 */ "assignment to constant",
/* JAMC_NEXT_UNEXPECTED   14 */ "NEXT unexpected",
/* JAMC_POP_UNEXPECTED    15 */ "POP unexpected",
/* JAMC_RETURN_UNEXPECTED 16 */ "RETURN unexpected",
/* JAMC_ILLEGAL_SYMBOL    17 */ "illegal symbol name",
/* JBIC_VECTOR_MAP_FAILED 18 */ "vector signal name not found",
/* JBIC_USER_ABORT        19 */ "execution cancelled",
/* JBIC_STACK_OVERFLOW    20 */ "stack overflow",
/* JBIC_ILLEGAL_OPCODE    21 */ "illegal instruction code",
/* JAMC_PHASE_ERROR       22 */ "phase error",
/* JAMC_SCOPE_ERROR       23 */ "scope error",
/* JBIC_ACTION_NOT_FOUND  24 */ "action not found",
};
#define MAX_ERROR_CODE (int)((sizeof(error_text)/sizeof(error_text[0]))+1)
/************************************************************************/
int main(int argc, char **argv)
{
	BOOL help = FALSE;
	BOOL error = FALSE;
	char *filename = NULL;
	long offset = 0L;
	long error_address = 0L;
	JBI_RETURN_TYPE crc_result = JBIC_SUCCESS;
	JBI_RETURN_TYPE exec_result = JBIC_SUCCESS;
	unsigned short expected_crc = 0;
	unsigned short actual_crc = 0;
	char key[33] = {0};
	char value[257] = {0};
	int exit_status = 0;
	int arg = 0;
	int exit_code = 0;
	int format_version = 0;
	time_t start_time = 0;
	time_t end_time = 0;
	int time_delta = 0;
	char *workspace = NULL;
	char *action = NULL;
	char *init_list[10];
	int init_count = 0;
	FILE *fp = NULL;
	struct stat sbuf;
	long workspace_size = 0;
	char *exit_string = NULL;
	int reset_jtag = 1;
	int execute_program = 1;
	int action_count = 0;
	int procedure_count = 0;
	int index = 0;
	char *action_name = NULL;
	char *description = NULL;
	JBI_PROCINFO *procedure_list = NULL;
	JBI_PROCINFO *procptr = NULL;
	char *endptr;
	verbose = FALSE;
	init_list[0] = NULL;
	/* print out the version string and copyright message */
	fprintf(stderr, "Jam STAPL ByteCode Player Version 2.2\nCopyright (C) 1998-2001 Altera Corporation\n\n");
	for (arg = 1; arg < argc; arg++)
	{
#if PORT == UNIX
		if (argv[arg][0] == '-')
#else
		if ((argv[arg][0] == '-') || (argv[arg][0] == '/'))
#endif
		{
			switch(toupper(argv[arg][1]))
			{
			case 'A':				/* set action name */
				if (action == NULL)
				{
					action = &argv[arg][2];
				}
				else
				{
					error = TRUE;
				}
				break;
#if PORT == WINDOWS || PORT == DOS
			case 'C':				/* Use alternative ISP download cable */
				if(toupper(argv[arg][2]) == 'L')
					alternative_cable_l = TRUE;
				else if(toupper(argv[arg][2]) == 'X')
					alternative_cable_x = TRUE;
				break;
#endif
			case 'D':				/* initialization list */
				if (argv[arg][2] == '"')
				{
					init_list[init_count] = &argv[arg][3];
				}
				else
				{
					init_list[init_count] = &argv[arg][2];
				}
				init_list[++init_count] = NULL;
				break;
#if PORT == WINDOWS || PORT == DOS
			case 'P':				/* set LPT port address */
				specified_lpt_port = TRUE;
				if (sscanf(&argv[arg][2], "%d", &lpt_port) != 1) error = TRUE;
				if ((lpt_port < 1) || (lpt_port > 3)) error = TRUE;
				if (error)
				{
					if (sscanf(&argv[arg][2], "%x", &lpt_port) == 1)
					{
						if ((lpt_port == 0x3bc) ||
							(lpt_port == 0x378) ||
							(lpt_port == 0x278))
						{
							error = FALSE;
							specified_lpt_addr = TRUE;
							lpt_addr = (WORD) lpt_port;
							lpt_port = 1;
						}
					}
				}
				break;
#endif
			case 'R':		/* don't reset the JTAG chain after use */
				reset_jtag = 0;
				break;
#ifdef OPENBMC
			case 'G':				/* GPIO directory */
				switch (toupper(argv[arg][2])) {
				case 'C':
					g_tck_offset = strtol(&argv[arg][3], &endptr, 0);
					if (endptr == &argv[arg][3])
						g_tck_shadow = &argv[arg][3];
					break;
				case 'S':
					g_tms_offset = strtol(&argv[arg][3], &endptr, 0);
					if (endptr == &argv[arg][3])
						g_tms_shadow = &argv[arg][3];
					break;
				case 'I':
					g_tdi_offset = strtol(&argv[arg][3], &endptr, 0);
					if (endptr == &argv[arg][3])
						g_tdi_shadow = &argv[arg][3];
					break;
				case 'O':
					g_tdo_offset = strtol(&argv[arg][3], &endptr, 0);
					if (endptr == &argv[arg][3])
						g_tdo_shadow = &argv[arg][3];
					break;
				}
				jtag_io_func = jbi_jtag_gpio;
				break;
			case 'W':				/* use software mode to control jtag pins */
				g_swio = 1;
				jtag_io_func = jbi_jtag_swio;
				break;
#else
			case 'S':				/* set serial port address */
				serial_port_name = &argv[arg][2];
				specified_com_port = TRUE;
				break;
#endif
			case 'M':				/* set memory size */
				if (sscanf(&argv[arg][2], "%ld", &workspace_size) != 1)
					error = TRUE;
				if (workspace_size == 0) error = TRUE;
				break;
			case 'H':				/* help */
				help = TRUE;
				break;
			case 'V':				/* verbose */
				verbose = TRUE;
				break;
			case 'I':				/* show info only, do not execute */
				verbose = TRUE;
				execute_program = 0;
				break;
			default:
				error = TRUE;
				break;
			}
		}
		else
		{
			/* it's a filename */
			if (filename == NULL)
			{
				filename = argv[arg];
			}
			else
			{
				/* error -- we already found a filename */
				error = TRUE;
			}
		}
		if (error)
		{
			fprintf(stderr, "Illegal argument: \"%s\"\n", argv[arg]);
			help = TRUE;
			error = FALSE;
		}
	}
#if PORT == WINDOWS || PORT == DOS
	if (specified_lpt_port && specified_com_port)
	{
		fprintf(stderr, "Error:  -s and -p options may not be used together\n\n");
		help = TRUE;
	}
#endif
#ifdef OPENBMC
  if (execute_program) {
    int pins = 0;
    if (g_tck_shadow != NULL || g_tck_offset >= 0)
      pins++;
    if (g_tms_shadow != NULL || g_tms_offset >= 0)
      pins++;
    if (g_tdi_shadow != NULL || g_tdi_offset >= 0)
      pins++;
    if (g_tdo_shadow != NULL || g_tdo_offset >= 0)
      pins++;
    if (!g_swio && (pins < 4)) {
      fprintf(stderr, "Error:  -gc, -gs, -gi, and -go must be specified\n");
      help = TRUE;
    }
  }
#endif
	if (help || (filename == NULL))
	{
		fprintf(stderr, "Usage:  jbi [options] <filename>\n");
		fprintf(stderr, "\nAvailable options:\n");
		fprintf(stderr, "    -h          : show help message\n");
		fprintf(stderr, "    -v          : show verbose messages\n");
		fprintf(stderr, "    -i          : show file info only - does not execute any action\n");
		fprintf(stderr, "    -a<action>  : specify an action name (Jam STAPL)\n");
		fprintf(stderr, "    -d<var=val> : initialize variable to specified value (Jam 1.1)\n");
		fprintf(stderr, "    -d<proc=1>  : enable optional procedure (Jam STAPL)\n");
		fprintf(stderr, "    -d<proc=0>  : disable recommended procedure (Jam STAPL)\n");
#if PORT == WINDOWS || PORT == DOS
		fprintf(stderr, "    -p<port>    : parallel port number or address (for ByteBlaster)\n");
		fprintf(stderr, "    -c<cable>   : alternative download cable compatibility: -cl or -cx\n");
#endif
#ifdef OPENBMC
		fprintf(stderr, "    -gc<clock>  : GPIO directory for TCK\n");
		fprintf(stderr, "    -gs<clock>  : GPIO directory for TMS\n");
		fprintf(stderr, "    -gi<clock>  : GPIO directory for TDI\n");
		fprintf(stderr, "    -go<clock>  : GPIO directory for TDO\n");
#else
		fprintf(stderr, "    -s<port>    : serial port name (for BitBlaster)\n");
#endif
		fprintf(stderr, "    -r          : don't reset JTAG TAP after use\n");
		exit_status = 1;
	}
	else if ((workspace_size > 0) &&
		((workspace = (char *) jbi_malloc((size_t) workspace_size)) == NULL))
	{
		fprintf(stderr, "Error: can't allocate memory (%d Kbytes)\n",
			(int) (workspace_size / 1024L));
		exit_status = 1;
	}
	else if (access(filename, 0) != 0)
	{
		fprintf(stderr, "Error: can't access file \"%s\"\n", filename);
		exit_status = 1;
	}
	else
	{
		/* get length of file */
		if (stat(filename, &sbuf) == 0) file_length = sbuf.st_size;
		if ((fp = fopen(filename, "rb")) == NULL)
		{
			fprintf(stderr, "Error: can't open file \"%s\"\n", filename);
			exit_status = 1;
		}
		else
		{
			/*
			*	Read entire file into a buffer
			*/
#if PORT == DOS
			int pages = 1 + (int) (file_length >> 14L);
			int page;
			file_buffer = (unsigned char **) jbi_malloc(
				(size_t) (pages * sizeof(char *)));
			for (page = 0; page < pages; ++page)
			{
				/* allocate enough 16K blocks to store the file */
				file_buffer[page] = (unsigned char *) jbi_malloc (0x4000);
				if (file_buffer[page] == NULL)
				{
					/* flag error and break out of loop */
					file_buffer = NULL;
					page = pages;
				}
			}
#else
			file_buffer = (unsigned char *) jbi_malloc((size_t) file_length);
#endif
			if (file_buffer == NULL)
			{
				fprintf(stderr, "Error: can't allocate memory (%d Kbytes)\n",
					(int) (file_length / 1024L));
				exit_status = 1;
			}
			else
			{
#if PORT == DOS
				int pages = 1 + (int) (file_length >> 14L);
				int page;
				size_t page_size = 0x4000;
				for (page = 0; (page < pages) && (exit_status == 0); ++page)
				{
					if (page == (pages - 1))
					{
						/* last page may not be full 16K bytes */
						page_size = (size_t) (file_length & 0x3fffL);
					}
					if (fread(file_buffer[page], 1, page_size, fp) != page_size)
					{
						fprintf(stderr, "Error reading file \"%s\"\n", filename);
						exit_status = 1;
					}
				}
#else
				if (fread(file_buffer, 1, (size_t) file_length, fp) !=
					(size_t) file_length)
				{
					fprintf(stderr, "Error reading file \"%s\"\n", filename);
					exit_status = 1;
				}
#endif
			}
			fclose(fp);
		}
		if (exit_status == 0)
		{
			/*
			*	Get Operating System type
			*/
#if PORT == WINDOWS
			windows_nt = !(GetVersion() & 0x80000000);
#endif
			/*
			*	Calibrate the delay loop function
			*/
			calibrate_delay();
			/*
			*	Check CRC
			*/
			crc_result = jbi_check_crc(file_buffer, file_length,
				&expected_crc, &actual_crc);
			if (verbose || (crc_result == JBIC_CRC_ERROR))
			{
				switch (crc_result)
				{
				case JBIC_SUCCESS:
					printf("CRC matched: CRC value = %04X\n", actual_crc);
					break;
				case JBIC_CRC_ERROR:
					printf("CRC mismatch: expected %04X, actual %04X\n",
						expected_crc, actual_crc);
					break;
				case JBIC_UNEXPECTED_END:
					printf("Expected CRC not found, actual CRC value = %04X\n",
						actual_crc);
					break;
				case JBIC_IO_ERROR:
					printf("Error: File format is not recognized.\n");
					exit(1);
					break;
				default:
					printf("CRC function returned error code %d\n", crc_result);
					break;
				}
			}
			if (verbose)
			{
				/*
				*	Display file format version
				*/
				jbi_get_file_info(file_buffer, file_length,
					&format_version, &action_count, &procedure_count);
				printf("File format is %s ByteCode format\n",
					(format_version == 2) ? "Jam STAPL" : "pre-standardized Jam 1.1");
				/*
				*	Dump out NOTE fields
				*/
				while (jbi_get_note(file_buffer, file_length,
					&offset, key, value, 256) == 0)
				{
					printf("NOTE \"%s\" = \"%s\"\n", key, value);
				}
				/*
				*	Dump the action table
				*/
				if ((format_version == 2) && (action_count > 0))
				{
					printf("\nActions available in this file:\n");
					for (index = 0; index < action_count; ++index)
					{
						jbi_get_action_info(file_buffer, file_length,
							index, &action_name, &description, &procedure_list);
						if (description == NULL)
						{
							printf("%s\n", action_name);
						}
						else
						{
							printf("%s \"%s\"\n", action_name, description);
						}
#if PORT == DOS
						if (action_name != NULL) jbi_free(action_name);
						if (description != NULL) jbi_free(description);
#endif
						procptr = procedure_list;
						while (procptr != NULL)
						{
							if (procptr->attributes != 0)
							{
								printf("    %s (%s)\n", procptr->name,
									(procptr->attributes == 1) ?
									"optional" : "recommended");
							}
#if PORT == DOS
							if (procptr->name != NULL) jbi_free(procptr->name);
#endif
							procedure_list = procptr->next;
							jbi_free(procptr);
							procptr = procedure_list;
						}
					}
					/* add a blank line before execution messages */
					if (execute_program) printf("\n");
				}
			}
			if (execute_program)
			{
				/*
				*	Execute the Jam STAPL ByteCode program
				*/
				time(&start_time);
				exec_result = jbi_execute(file_buffer, file_length, workspace,
					workspace_size, action, init_list, reset_jtag,
					&error_address, &exit_code, &format_version);
				time(&end_time);
				if (exec_result == JBIC_SUCCESS)
				{
					if (format_version == 2)
					{
						switch (exit_code)
						{
						case  0: exit_string = "Success"; break;
						case  1: exit_string = "Checking chain failure"; break;
						case  2: exit_string = "Reading IDCODE failure"; break;
						case  3: exit_string = "Reading USERCODE failure"; break;
						case  4: exit_string = "Reading UESCODE failure"; break;
						case  5: exit_string = "Entering ISP failure"; break;
						case  6: exit_string = "Unrecognized device"; break;
						case  7: exit_string = "Device revision is not supported"; break;
						case  8: exit_string = "Erase failure"; break;
						case  9: exit_string = "Device is not blank"; break;
						case 10: exit_string = "Device programming failure"; break;
						case 11: exit_string = "Device verify failure"; break;
						case 12: exit_string = "Read failure"; break;
						case 13: exit_string = "Calculating checksum failure"; break;
						case 14: exit_string = "Setting security bit failure"; break;
						case 15: exit_string = "Querying security bit failure"; break;
						case 16: exit_string = "Exiting ISP failure"; break;
						case 17: exit_string = "Performing system test failure"; break;
						default: exit_string = "Unknown exit code"; break;
						}
					}
					else
					{
						switch (exit_code)
						{
						case 0: exit_string = "Success"; break;
						case 1: exit_string = "Illegal initialization values"; break;
						case 2: exit_string = "Unrecognized device"; break;
						case 3: exit_string = "Device revision is not supported"; break;
						case 4: exit_string = "Device programming failure"; break;
						case 5: exit_string = "Device is not blank"; break;
						case 6: exit_string = "Device verify failure"; break;
						case 7: exit_string = "SRAM configuration failure"; break;
						default: exit_string = "Unknown exit code"; break;
						}
					}
					printf("Exit code = %d... %s\n", exit_code, exit_string);
				}
				else if ((format_version == 2) &&
					(exec_result == JBIC_ACTION_NOT_FOUND))
				{
					if ((action == NULL) || (*action == '\0'))
					{
						printf("Error: no action specified for Jam STAPL file.\nProgram terminated.\n");
					}
					else
					{
						printf("Error: action \"%s\" is not supported for this Jam STAPL file.\nProgram terminated.\n", action);
					}
				}
				else if (exec_result < MAX_ERROR_CODE)
				{
					printf("Error at address %ld: %s.\nProgram terminated.\n",
						error_address, error_text[exec_result]);
				}
				else
				{
					printf("Unknown error code %ld\n", exec_result);
				}
				/*
				*	Print out elapsed time
				*/
				if (verbose)
				{
					time_delta = (int) (end_time - start_time);
					printf("Elapsed time = %02u:%02u:%02u\n",
						time_delta / 3600,			/* hours */
						(time_delta % 3600) / 60,	/* minutes */
						time_delta % 60);			/* seconds */
				}
			}
		}
	}
	if (jtag_hardware_initialized) close_jtag_hardware();
	if (workspace != NULL) jbi_free(workspace);
	if (file_buffer != NULL) jbi_free(file_buffer);
#if defined(MEM_TRACKER)
	if (verbose)
	{
#if defined(USE_STATIC_MEMORY)
		fprintf(stdout, "Memory Usage Info: static memory size = %ud (%dKB)\n", N_STATIC_MEMORY_BYTES, N_STATIC_MEMORY_KBYTES);
#endif /* USE_STATIC_MEMORY */
		fprintf(stdout, "Memory Usage Info: peak memory usage = %ud (%dKB)\n", peak_memory_usage, (peak_memory_usage + 1023) / 1024);
		fprintf(stdout, "Memory Usage Info: peak allocations = %d\n", peak_allocations);
#if defined(USE_STATIC_MEMORY)
		if ((n_bytes_allocated - n_bytes_not_recovered) != 0)
		{
			fprintf(stdout, "Memory Usage Info: bytes still allocated = %d (%dKB)\n", (n_bytes_allocated - n_bytes_not_recovered), ((n_bytes_allocated - n_bytes_not_recovered) + 1023) / 1024);
		}
#else /* USE_STATIC_MEMORY */
		if (n_bytes_allocated != 0)
		{
			fprintf(stdout, "Memory Usage Info: bytes still allocated = %d (%dKB)\n", n_bytes_allocated, (n_bytes_allocated + 1023) / 1024);
		}
#endif /* USE_STATIC_MEMORY */
		if (n_allocations != 0)
		{
			fprintf(stdout, "Memory Usage Info: allocations not freed = %d\n", n_allocations);
		}
	}
#endif /* MEM_TRACKER */
	return (exit_status);
}
#if PORT==WINDOWS
#ifndef __BORLANDC__
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
*	SEARCH_DYN_DATA
*
*	Searches recursively in Windows 95/98 Registry for parallel port info
*	under HKEY_DYN_DATA registry key.  Called by search_local_machine().
*/
void search_dyn_data
(
	char *dd_path,
	char *hardware_key,
	int lpt
)
{
	DWORD index;
	DWORD size;
	DWORD type;
	LONG result;
	HKEY key;
	int length;
	WORD address;
	char buffer[1024];
	FILETIME last_write = {0};
	WORD *word_ptr;
	int i;
	length = strlen(dd_path);
	if (RegOpenKeyEx(
		HKEY_DYN_DATA,
		dd_path,
		0L,
		KEY_READ,
		&key)
		== ERROR_SUCCESS)
	{
		size = 1023;
		if (RegQueryValueEx(
			key,
			"HardWareKey",
			NULL,
			&type,
			(unsigned char *) buffer,
			&size)
			== ERROR_SUCCESS)
		{
			if ((type == REG_SZ) && (stricmp(buffer, hardware_key) == 0))
			{
				size = 1023;
				if (RegQueryValueEx(
					key,
					"Allocation",
					NULL,
					&type,
					(unsigned char *) buffer,
					&size)
					== ERROR_SUCCESS)
				{
					/*
					*	By "inspection", I have found five cases: size 32, 48,
					*	56, 60, and 80 bytes.  The port address seems to be
					*	located at different offsets in the buffer for these
					*	five cases, as shown below.  If a valid port address
					*	is not found, or the size is not one of these known
					*	sizes, then I search through the entire buffer and
					*	look for a value which is a valid port address.
					*/
					word_ptr = (WORD *) buffer;
					if ((type == REG_BINARY) && (size == 32))
					{
						address = word_ptr[10];
					}
					else if ((type == REG_BINARY) && (size == 48))
					{
						address = word_ptr[18];
					}
					else if ((type == REG_BINARY) && (size == 56))
					{
						address = word_ptr[22];
					}
					else if ((type == REG_BINARY) && (size == 60))
					{
						address = word_ptr[24];
					}
					else if ((type == REG_BINARY) && (size == 80))
					{
						address = word_ptr[24];
					}
					else address = 0;
					/* if not found, search through entire buffer */
					i = 0;
					while ((i < (int) (size / 2)) &&
						(address != 0x278) &&
						(address != 0x27C) &&
						(address != 0x378) &&
						(address != 0x37C) &&
						(address != 0x3B8) &&
						(address != 0x3BC))
					{
						if ((word_ptr[i] == 0x278) ||
							(word_ptr[i] == 0x27C) ||
							(word_ptr[i] == 0x378) ||
							(word_ptr[i] == 0x37C) ||
							(word_ptr[i] == 0x3B8) ||
							(word_ptr[i] == 0x3BC))
						{
							address = word_ptr[i];
						}
						++i;
					}
					if ((address == 0x278) ||
						(address == 0x27C) ||
						(address == 0x378) ||
						(address == 0x37C) ||
						(address == 0x3B8) ||
						(address == 0x3BC))
					{
						lpt_addresses_from_registry[lpt] = address;
					}
				}
			}
		}
		index = 0;
		do
		{
			size = 1023;
			result = RegEnumKeyEx(
				key,
				index++,
				buffer,
				&size,
				NULL,
				NULL,
				NULL,
				&last_write);
			if (result == ERROR_SUCCESS)
			{
				dd_path[length] = '\\';
				dd_path[length + 1] = '\0';
				strcpy(&dd_path[length + 1], buffer);
				search_dyn_data(dd_path, hardware_key, lpt);
				dd_path[length] = '\0';
			}
		}
		while (result == ERROR_SUCCESS);
		RegCloseKey(key);
	}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
*	SEARCH_LOCAL_MACHINE
*
*	Searches recursively in Windows 95/98 Registry for parallel port info
*	under HKEY_LOCAL_MACHINE\Enum.  When parallel port is found, calls
*	search_dyn_data() to get the port address.
*/
void search_local_machine
(
	char *lm_path,
	char *dd_path
)
{
	DWORD index;
	DWORD size;
	DWORD type;
	LONG result;
	HKEY key;
	int length;
	char buffer[1024];
	FILETIME last_write = {0};
	length = strlen(lm_path);
	if (RegOpenKeyEx(
		HKEY_LOCAL_MACHINE,
		lm_path,
		0L,
		KEY_READ,
		&key)
		== ERROR_SUCCESS)
	{
		size = 1023;
		if (RegQueryValueEx(
			key,
			"PortName",
			NULL,
			&type,
			(unsigned char *) buffer,
			&size)
			== ERROR_SUCCESS)
		{
			if ((type == REG_SZ) &&
				(size == 5) &&
				(buffer[0] == 'L') &&
				(buffer[1] == 'P') &&
				(buffer[2] == 'T') &&
				(buffer[3] >= '1') &&
				(buffer[3] <= '4') &&
				(buffer[4] == '\0'))
			{
				/* we found the entry in HKEY_LOCAL_MACHINE, now we need to */
				/* find the corresponding entry under HKEY_DYN_DATA.  */
				/* add 5 to lm_path to skip over "Enum" and backslash */
				search_dyn_data(dd_path, &lm_path[5], (buffer[3] - '1'));
			}
		}
		index = 0;
		do
		{
			size = 1023;
			result = RegEnumKeyEx(
				key,
				index++,
				buffer,
				&size,
				NULL,
				NULL,
				NULL,
				&last_write);
			if (result == ERROR_SUCCESS)
			{
				lm_path[length] = '\\';
				lm_path[length + 1] = '\0';
				strcpy(&lm_path[length + 1], buffer);
				search_local_machine(lm_path, dd_path);
				lm_path[length] = '\0';
			}
		}
		while (result == ERROR_SUCCESS);
		RegCloseKey(key);
	}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
*	GET_LPT_ADDRESSES_FROM_REGISTRY
*
*	Searches Win95/98 registry recursively to get I/O port addresses for
*	parallel ports.
*/
void get_lpt_addresses_from_registry()
{
	char lm_path[1024];
	char dd_path[1024];
	strcpy(lm_path, "Enum");
	strcpy(dd_path, "Config Manager");
	search_local_machine(lm_path, dd_path);
}
#endif
#endif
void initialize_jtag_hardware()
{
	if (specified_com_port)
	{
		com_port = open(serial_port_name, O_RDWR);
		if (com_port == -1)
		{
			fprintf(stderr, "Error: can't open serial port \"%s\"\n",
				serial_port_name);
		}
		else
		{
			int i = 0, result = 0;
			char data = 0;
			data = 0x7e;
			write(com_port, &data, 1);
			for (i = 0; (i < 100) && (result != 1); ++i)
			{
				result = read(com_port, &data, 1);
			}
			if (result == 1)
			{
				data = 0x70; write(com_port, &data, 1); /* TDO echo off */
				data = 0x72; write(com_port, &data, 1); /* auto LEDs off */
				data = 0x74; write(com_port, &data, 1); /* ERROR LED off */
				data = 0x76; write(com_port, &data, 1); /* DONE LED off */
				data = 0x60; write(com_port, &data, 1); /* signals low */
			}
			else
			{
				fprintf(stderr, "Error: BitBlaster is not responding on %s\n",
					serial_port_name);
				close(com_port);
				com_port = -1;
			}
		}
	}
	else
	{
#if PORT == WINDOWS || PORT == DOS
#if PORT == WINDOWS
		if (windows_nt)
		{
			initialize_nt_driver();
		}
		else
		{
#ifdef __BORLANDC__
			fprintf(stderr, "Error: parallel port access is not available\n");
#else
			if (!specified_lpt_addr)
			{
				get_lpt_addresses_from_registry();
				lpt_addr = 0;
				if (specified_lpt_port)
				{
					lpt_addr = lpt_addresses_from_registry[lpt_port - 1];
				}
				if (lpt_addr == 0)
				{
					if (lpt_addresses_from_registry[3] != 0)
						lpt_addr = lpt_addresses_from_registry[3];
					if (lpt_addresses_from_registry[2] != 0)
						lpt_addr = lpt_addresses_from_registry[2];
					if (lpt_addresses_from_registry[1] != 0)
						lpt_addr = lpt_addresses_from_registry[1];
					if (lpt_addresses_from_registry[0] != 0)
						lpt_addr = lpt_addresses_from_registry[0];
				}
				if (lpt_addr == 0)
				{
					if (specified_lpt_port)
					{
						lpt_addr = lpt_addr_table[lpt_port - 1];
					}
					else
					{
						lpt_addr = lpt_addr_table[0];
					}
				}
			}
			initial_lpt_ctrl = windows_nt ? 0x0c : read_byteblaster(2);
#endif
		}
#endif
#if PORT == DOS
		/*
		*	Read word at specific memory address to get the LPT port address
		*/
		WORD *bios_address = (WORD *) 0x00400008;
		if (!specified_lpt_addr)
		{
			lpt_addr = bios_address[lpt_port - 1];
			if ((lpt_addr != 0x278) &&
				(lpt_addr != 0x27c) &&
				(lpt_addr != 0x378) &&
				(lpt_addr != 0x37c) &&
				(lpt_addr != 0x3b8) &&
				(lpt_addr != 0x3bc))
			{
				lpt_addr = lpt_addr_table[lpt_port - 1];
			}
		}
		initial_lpt_ctrl = read_byteblaster(2);
#endif
		/* set AUTO-FEED low to enable ByteBlaster (value to port inverted) */
		/* set DIRECTION low for data output from parallel port */
		write_byteblaster(2, (initial_lpt_ctrl | 0x02) & 0xDF);
#endif
	}
}
void close_jtag_hardware()
{
	if (specified_com_port)
	{
		if (com_port != -1) close(com_port);
	}
	else
	{
#if PORT == WINDOWS || PORT == DOS
		/* set AUTO-FEED high to disable ByteBlaster */
		write_byteblaster(2, initial_lpt_ctrl & 0xfd);
#if PORT == WINDOWS
		if (windows_nt && (nt_device_handle != INVALID_HANDLE_VALUE))
		{
			if (port_io_count > 0) flush_ports();
			CloseHandle(nt_device_handle);
		}
#endif
#endif
#ifdef OPENBMC
		if (g_sysfs_tck_fd >= 0)
			close(g_sysfs_tck_fd);
		if (g_sysfs_tms_fd >= 0)
			close(g_sysfs_tms_fd);
		if (g_sysfs_tdo_fd >= 0)
			close(g_sysfs_tdo_fd);
		if (g_sysfs_tdi_fd >= 0)
			close(g_sysfs_tdi_fd);
		if (g_jtag_dev >= 0)
			close(g_jtag_dev);
#endif
	}
}
#if PORT == WINDOWS
/**************************************************************************/
/*                                                                        */
BOOL initialize_nt_driver()
/*                                                                        */
/*  Uses CreateFile() to open a connection to the Windows NT device       */
/*  driver.                                                               */
/*                                                                        */
/**************************************************************************/
{
	BOOL status = FALSE;
	ULONG buffer[1];
	ULONG returned_length = 0;
	char nt_lpt_str[] = { '\\', '\\', '.', '\\',
		'A', 'L', 'T', 'L', 'P', 'T', '1', '\0' };
	nt_lpt_str[10] = (char) ('1' + (lpt_port - 1));
	nt_device_handle = CreateFile(
		nt_lpt_str,
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (nt_device_handle == INVALID_HANDLE_VALUE)
	{
		fprintf(stderr,
			"I/O error:  cannot open device %s\nCheck port number and device driver installation",
			nt_lpt_str);
	}
	else
	{
		if (DeviceIoControl(
			nt_device_handle,			/* Handle to device */
			PGDC_IOCTL_GET_DEVICE_INFO_PP,	/* IO Control code */
			(ULONG *)NULL,					/* Buffer to driver. */
			0,								/* Length of buffer in bytes. */
			&buffer,						/* Buffer from driver. */
			sizeof(ULONG),					/* Length of buffer in bytes. */
			&returned_length,				/* Bytes placed in data_buffer. */
			NULL))							/* Wait for operation to complete */
		{
			if (returned_length == sizeof(ULONG))
			{
				if (buffer[0] == PGDC_HDLC_NTDRIVER_VERSION)
				{
					status = TRUE;
				}
				else
				{
					fprintf(stderr,
						"I/O error:  device driver %s is not compatible\n(Driver version is %lu, expected version %lu.\n",
						nt_lpt_str,
						(unsigned long) buffer[0],
						(unsigned long) PGDC_HDLC_NTDRIVER_VERSION);
				}
			}
			else
			{
				fprintf(stderr, "I/O error:  device driver %s is not compatible.\n",
					nt_lpt_str);
			}
		}
		if (!status)
		{
			CloseHandle(nt_device_handle);
			nt_device_handle = INVALID_HANDLE_VALUE;
		}
	}
	if (!status)
	{
		/* error message already given */
		exit(1);
	}
	return (status);
}
#endif
#if PORT == WINDOWS || PORT == DOS
/**************************************************************************/
/*                                                                        */
void write_byteblaster
(
	int port,
	int data
)
/*                                                                        */
/**************************************************************************/
{
#if PORT == WINDOWS
	BOOL status = FALSE;
	int returned_length = 0;
	int buffer[2];
	if (windows_nt)
	{
		/*
		*	On Windows NT, access hardware through device driver
		*/
		if (port == 0)
		{
			port_io_buffer[port_io_count].data = (USHORT) data;
			port_io_buffer[port_io_count].command = PGDC_WRITE_PORT;
			++port_io_count;
			if (port_io_count >= PORT_IO_BUFFER_SIZE) flush_ports();
		}
		else
		{
			if (port_io_count > 0) flush_ports();
			buffer[0] = port;
			buffer[1] = data;
			status = DeviceIoControl(
				nt_device_handle,			/* Handle to device */
				PGDC_IOCTL_WRITE_PORT_PP,	/* IO Control code for write */
				(ULONG *)&buffer,			/* Buffer to driver. */
				2 * sizeof(int),			/* Length of buffer in bytes. */
				(ULONG *)NULL,				/* Buffer from driver.  Not used. */
				0,							/* Length of buffer in bytes. */
				(ULONG *)&returned_length,	/* Bytes returned.  Should be zero. */
				NULL);						/* Wait for operation to complete */
			if ((!status) || (returned_length != 0))
			{
				fprintf(stderr, "I/O error:  Cannot access ByteBlaster hardware\n");
				CloseHandle(nt_device_handle);
				exit(1);
			}
		}
	}
	else
#endif
	{
		/*
		*	On Windows 95, access hardware directly
		*/
		outp((WORD)(port + lpt_addr), (WORD)data);
	}
}
/**************************************************************************/
/*                                                                        */
int read_byteblaster
(
	int port
)
/*                                                                        */
/**************************************************************************/
{
	int data = 0;
#if PORT == WINDOWS
	BOOL status = FALSE;
	int returned_length = 0;
	if (windows_nt)
	{
		/* flush output cache buffer before reading from device */
		if (port_io_count > 0) flush_ports();
		/*
		*	On Windows NT, access hardware through device driver
		*/
		status = DeviceIoControl(
			nt_device_handle,			/* Handle to device */
			PGDC_IOCTL_READ_PORT_PP,	/* IO Control code for Read */
			(ULONG *)&port,				/* Buffer to driver. */
			sizeof(int),				/* Length of buffer in bytes. */
			(ULONG *)&data,				/* Buffer from driver. */
			sizeof(int),				/* Length of buffer in bytes. */
			(ULONG *)&returned_length,	/* Bytes placed in data_buffer. */
			NULL);						/* Wait for operation to complete */
		if ((!status) || (returned_length != sizeof(int)))
		{
			fprintf(stderr, "I/O error:  Cannot access ByteBlaster hardware\n");
			CloseHandle(nt_device_handle);
			exit(1);
		}
	}
	else
#endif
	{
		/*
		*	On Windows 95, access hardware directly
		*/
		data = inp((WORD)(port + lpt_addr));
	}
	return (data & 0xff);
}
#if PORT == WINDOWS
void flush_ports(void)
{
	ULONG n_writes = 0L;
	BOOL status;
	status = DeviceIoControl(
		nt_device_handle,			/* handle to device */
		PGDC_IOCTL_PROCESS_LIST_PP,	/* IO control code */
		(LPVOID)port_io_buffer,		/* IN buffer (list buffer) */
		port_io_count * sizeof(struct PORT_IO_LIST_STRUCT),/* length of IN buffer in bytes */
		(LPVOID)port_io_buffer,	/* OUT buffer (list buffer) */
		port_io_count * sizeof(struct PORT_IO_LIST_STRUCT),/* length of OUT buffer in bytes */
		&n_writes,					/* number of writes performed */
		0);							/* wait for operation to complete */
	if ((!status) || ((port_io_count * sizeof(struct PORT_IO_LIST_STRUCT)) != n_writes))
	{
		fprintf(stderr, "I/O error:  Cannot access ByteBlaster hardware\n");
		CloseHandle(nt_device_handle);
		exit(1);
	}
	port_io_count = 0;
}
#endif /* PORT == WINDOWS */
#endif /* PORT == WINDOWS || PORT == DOS */
#if !defined (DEBUG)
#pragma optimize ("ceglt", off)
#endif
void delay_loop(long count)
{
	while (count != 0L) count--;
}