/*
 * Copyright (c) 2003-2006 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: infinicam.c 11428 2009-06-23 06:55:26Z vladimir $
 */

/* Endace headers. */
#include "dagapi.h"
#include "dag_platform.h"
#include "dagreg.h"
#include "dagutil.h"
#include "dagclarg.h"

#ifdef _WIN32
#include "strmisc.h"
#endif

/* Endace cam headers */
#include "dagcam/idt75k_interf.h"
#include "dagcam/idt75k_lib.h"

#include "dagcam/infiniband_proto.h"
#include <string.h>

#if HAVE_EDITLINE
#include <editline/readline.h>
#include <histedit.h>
#endif /* HAVE_EDITLINE */
/*This macro is used for things which are related only to the DRB version_LA_VERSION */
#define DRB_LA_VERSION

#define DRB_VERSION 
/*defined for infinicam tests*/
#define SIZE_128K 128 * 1024


/* CVS Header. */
static const char* const kCvsHeader __attribute__ ((unused)) = "$Id: infinicam.c 11428 2009-06-23 06:55:26Z vladimir $";
static const char* const kRevisionString = "$Revision: 11428 $";

#define BUILD_144BIT_ARRAY(a, d0 ,d1, d2, d3)  \
	a[0] = (uint8_t)((d0) >> 28);    a[1] = (uint8_t)((d0) >> 20);   a[2] = (uint8_t)((d0) >> 12);   a[3] = (uint8_t)((d0) >> 4);    \
	a[4] = (uint8_t)(((d0 << 4) & 0xF0) | ((d1 >> 32) & 0x0F));                                                                      \
	a[5] = (uint8_t)((d1) >> 24);    a[6] = (uint8_t)((d1) >> 16);   a[7] = (uint8_t)((d1) >> 8);    a[8] = (uint8_t)((d1));         \
	a[9]  = (uint8_t)((d2) >> 28);   a[10] = (uint8_t)((d2) >> 20);  a[11] = (uint8_t)((d2) >> 12);  a[12] = (uint8_t)((d2) >> 4);   \
	a[13] = (uint8_t)(((d2 << 4) & 0xF0) | ((d3 >> 32) & 0x0F));                                                                     \
	a[14] = (uint8_t)((d3) >> 24);   a[15] = (uint8_t)((d3) >> 16);  a[16] = (uint8_t)((d3) >> 8);   a[17] = (uint8_t)((d3));

#define EXTRACT_64BIT_VALUES(a, d0 ,d1, d2, d3)  \
        d0 = ((uint64_t)a[0] << 28) | ((uint64_t)a[1] << 20) | ((uint64_t)a[2] << 12) | ((uint64_t)a[3] << 4) | ((uint64_t)a[4] >> 4);           \
        d1 = ((uint64_t)(a[4] & 0x0F) << 32) | ((uint64_t)a[5] << 24) | ((uint64_t)a[6] << 16) | ((uint64_t)a[7] << 8) | ((uint64_t)a[8]);       \
        d2 = ((uint64_t)a[9] << 28) | ((uint64_t)a[10] << 20) | ((uint64_t)a[11] << 12) | ((uint64_t)a[12] << 4) | ((uint64_t)a[13] >> 4);       \
        d3 = ((uint64_t)(a[13] & 0x0F) << 32) | ((uint64_t)a[14] << 24) | ((uint64_t)a[15] << 16) | ((uint64_t)a[16] << 8) | ((uint64_t)a[17]);

#define BUILD_144BIT_STRING(s, a) \
	sprintf(s, "0x%02x%02x%02x%02x%01x_%01x%02x%02x%02x%02x_%02x%02x%02x%02x%01x_%01x%02x%02x%02x%02x",   \
		a[0], a[1], a[2], a[3], ((a[4]>>4)&0xf), \
		((a[4]>>0)&0xf), a[5], a[6], a[7], a[8], \
		a[9], a[10], a[11], a[12], ((a[13]>>4)&0xf), \
		((a[13]>>0)&0xf), a[14], a[15], a[16], a[17]);

#define MAXARGV 64
static char *dgetline(char *prompt);
#define BUFFER_SIZE  256
#define DEFAULT_INFINICAM_HISTORY ".hydracam_history"
#define DEFAULT_INFINICAM_RCFILE ".rc_filename_buf"
static char dagname[BUFFER_SIZE];
static int dagstream = 0;

#define COMMAND_BUFSIZE 128
#define FILENAME_BUFSIZE 128
static char g_command_buf[COMMAND_BUFSIZE] = "";
static char g_history_filename_buf[FILENAME_BUFSIZE] = DEFAULT_INFINICAM_HISTORY;
static char g_rc_filename_buf[FILENAME_BUFSIZE] = DEFAULT_INFINICAM_RCFILE;

static int g_uHistoryCount;
static int g_uInteractive = 1; /* the default is to go interactive */
static int g_uHaveReadCommandLine = 0;
static int g_uReadFromKeyboard = 1;
static int g_uSaveHistory = 1;

/* thsi options allows to test the library with no hardware just 
by constructoing the LA or PCI messages and prints it on the screen in hex */
static int g_uEmulation = 0;

static char g_whitespace[] = " \t\n";

/*For cmd decode.*/
static infiniband_filter_rule_t cam_entry_decode;

idt75k_dev_t dev_a = {
	NULL,
	64*1024,
};
idt75k_dev_t dev_b = {
	NULL,
	64*1024,
};
idt75k_dev_t *dev_p_la1= &dev_a;
idt75k_dev_t *dev_p_la2= &dev_b;
idt75k_dev_t *dev_p_la = &dev_a;


/* the IOM pointer for the dag card (if present) */
uint8_t * g_iom_p = NULL;

/* the file descriptor for the dag card (if present) */
static int g_dagfd = -1;




/* Just because I'm feeling mean and horrible, let's obfuscate with some
 * #define-based macros. Saves me having different bugs everywhere I want to
 * perform "common" actions.
 * completely agree with that but would be better even if it was global 
 */
 
/*uint32_t all of these*/
#define unpack_addr(x,y)   (((x)>>4) & 0x3fffffL)
#define unpack_enable(x,y) (((x)>>26) & 0x1)
#define unpack_vld(x,y)    (((x)>>27) & 0x1)
#define unpack_datahi(x,y) ((x) & 0xf)
#define unpack_datalo(x,y) (y)
/*uint64_t here*/
#define unpack_data(x,y)   (((uint64_t)((x) & 0xf) << 32) | (uint64_t)(y))
/*uint32_t all of these*/
#define packhi_addr(x,z)   (((x) & 0xfc00000fL) |(((z) << 4) & 0x3fffffL))
#define packhi_enable(x,z) (((x) & 0xfbffffffL) |(((z) << 26) & 0x1))
#define packhi_vld(x,z)    (((x) & 0xf7ffffffL) |(((z) << 27) & 0x1))
/*uint64_t rval here, uint32_t lval*/
#define packhi_data(x,z)   (((x) & 0xfffffff0L) | (((z) >> 32) & 0xf))
#define packlo_data(x,z)   ((z) & 0xffffffffL)
#define packhi(v,e,a,d)    (((v) << 27) | ((e) << 26) | ((a) << 4) |(((d) >> 32) & 0xf))
#define packlo(d)          ((d) & 0xffffffffL)

#define make18b(x)         ((((x) & 0xffff0000) << 2) | ((x) & 0x0000ffff))


#define cardread(a)        (*((volatile uint32_t*)((uintptr_t)g_iom_p + (a))))
#define cardwrite(a,d)     (*((volatile uint32_t*)((uintptr_t)g_iom_p + (a))) = (d))


static uint32_t g_dbg_base=0x8214;
static uint32_t g_csr_base=0x8210;
static uint32_t g_array_size=16; 
static uint32_t g_have_init=0;

/**
 * Macros to extract fields from the search string.
 *
 */
#define GET_MPLS_LABEL(e)    ( ((uint32_t)(e)[0] << 12) | ((uint32_t)(e)[1] << 4) | (((uint32_t)(e)[2] >> 4) & 0x0F) ) 
#define GET_MPLS_PRESENT(e)  ( ((e)[2] >> 3) & 0x01 ) 
#define GET_MPLS_COUNT(e)    ( ((e)[2] & 0x07) ) 
#define GET_IP_PROTO(e)      ( (e)[3] )
#define GET_IP_SRC_ADDR(e)   ( ((uint32_t)(e)[4] << 24) | ((uint32_t)(e)[5] << 16) | ((uint32_t)(e)[6] << 8) | ((uint32_t)(e)[7] << 0) )
#define GET_IP_DST_ADDR(e)   ( ((uint32_t)(e)[8] << 24) | ((uint32_t)(e)[9] << 16) | ((uint32_t)(e)[10] << 8) | ((uint32_t)(e)[11] << 0) )
#define GET_IP_SRC_PORT(e)   ( ((uint32_t)(e)[12] << 8) | ((uint32_t)(e)[13] << 0) )
#define GET_IP_DST_PORT(e)   ( ((uint32_t)(e)[14] << 8) | ((uint32_t)(e)[15] << 0) )

enum {
	
	CLA_HELP,
	CLA_VERSION,
	CLA_VERBOSE,
	CLA_DEVICE,
	CLA_INTERACTIVE,
	CLA_HISTFILE,
	CLA_NOHIST,
	CLA_RCFILE,
	CLA_CMDLINE,
	CLA_EMULATION
};

/* Incremenatl data and address testing of the TCAM */
/* the first test writes the data the second test reads the data */
void infinicam_test_1(idt75k_dev_t *dev_p);
void infinicam_test_2(idt75k_dev_t *dev_p);
/**
 * Continously writes random values into sequential TCAM entries, this is designed to
 * simulate what an actual loading sequence would be.
 */
void infinicam_test_3 (idt75k_dev_t *dev_p);
void infinicam_test_4 (idt75k_dev_t *dev_p);

/**
 * Tests for production testing
 */
void production_test_1(idt75k_dev_t *dev_p);
void production_test_2(idt75k_dev_t *dev_p);
void production_test_3(idt75k_dev_t *dev_p);
void production_test_4(idt75k_dev_t *dev_p);

static void
print_version(void)
{
	printf("infinicam (%s) %s\n", kDagReleaseVersion, kRevisionString);
}
/*****************************************************************************/

static void
print_usage(ClArgPtr clarg)
{
	print_version();
	printf("infinicam - Endace Infiniband Project TCAM shell.\n");
	printf("Usage: infinicam [-hvin] [-d device] [-t histfile] [-r rcfile] [-c cmdline] [file]\n");
	dagclarg_display_usage(clarg, stdout);
}

static void dag_read_history(const char* filename);
static void dag_write_history(const char* filename);
static void infinicam(void);


int
infinicam_main(int argc,  char *argv[])
{
	ClArgPtr clarg;
	FILE*    errorfile = NULL;
	int      argindex;
	int      code;
	int      clarg_result;
	char     tcam_namebuf[DAGNAME_BUFSIZE];
#ifdef DRB_VERSION 	
	int count;
	dag_reg_t regs[DAG_REG_MAX_ENTRIES];
#endif 
	
	dagutil_set_progname("infinicam");

	/* Set the default device 
	Note : for hydra is not using the dag0 but /dev/tcam0
	The main difference is that in the hydra all commands are going through a driver 
	while in infiniband we we use direct from the userspace and DRB registers 
	It is possible to use the TCAM driver created by Ben but as a standart DAG card
	not recommended 
	*/
	
	strcpy (tcam_namebuf, "/dev/dag0");


	/* Set up the command line options. */
	clarg = dagclarg_init(argc, (const char* const *) argv);

	dagclarg_add(clarg, "display help (this page).", "--help", 'h', CLA_HELP);
	dagclarg_add_long_option(clarg, CLA_HELP, "--usage");
	dagclarg_add_short_option(clarg, CLA_HELP, '?');
	dagclarg_add(clarg, "display version information.", "--version", 'V', CLA_VERSION);
	dagclarg_add(clarg, "increase verbosity.", "--verbose", 'v', CLA_VERBOSE);
	dagclarg_add_string(clarg, "DAG card to use. default: /dev/dag0.", "--device", 'd', "device", dagname, DAGNAME_BUFSIZE, CLA_DEVICE);
	dagclarg_add(clarg, "interactive, even when reading from a file or command line", "--interactive", 'i', CLA_INTERACTIVE);
	dagclarg_add_string(clarg, "read history file (default is .dagcam_history)", "--history", 't', "histfile", g_history_filename_buf, FILENAME_BUFSIZE, CLA_HISTFILE);
	dagclarg_add(clarg, "no history (turn off reading and writing .dagcam_history)", "--nohistory", 'n', CLA_NOHIST);
	dagclarg_add_string(clarg, "read initial commands from rcfile (default is .rc_filename_buf)", "--rcfile", 'r', "rcfile", g_rc_filename_buf, FILENAME_BUFSIZE, CLA_RCFILE);
	dagclarg_add_string(clarg, "execute cmdline (instead of stdin processing)", "--cmdline", 'c', "cmdline", g_command_buf, COMMAND_BUFSIZE, CLA_CMDLINE);
	dagclarg_add(clarg, "Emulation mode disable access to the card", "--emulation", 'e', CLA_EMULATION);

	clarg_result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	while (1 == clarg_result)
	{
		switch (code)
		{
			case CLA_HELP:
				print_usage(clarg);
				return EXIT_SUCCESS;

			case CLA_VERBOSE:
				dagutil_inc_verbosity();
				errorfile = stderr;
				break;

			case CLA_VERSION:
				print_version();
				return EXIT_SUCCESS;

			case CLA_DEVICE:
			          if (-1 == dag_parse_name(dagname, tcam_namebuf, DAGNAME_BUFSIZE, &dagstream))
				  {
					dagutil_panic("dag_parse_name(%s): %s\n", tcam_namebuf, strerror(errno));
				  }
				  break;

			case CLA_INTERACTIVE:
				g_uInteractive = 1;
				break;

			case CLA_NOHIST:
				g_uSaveHistory = 0;
				break;
			case CLA_EMULATION:
				g_uEmulation = 1;

			case CLA_HISTFILE:
			case CLA_RCFILE:
			case CLA_CMDLINE:
				break;

			default:
			/* Unknown option. */
				dagutil_error("unknown option %s\n", argv[argindex]); 
				print_usage(clarg);
				return EXIT_FAILURE;
		}
		clarg_result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	}


	if (-1 == clarg_result)
	{
		if (argindex < argc)
		{
			dagutil_error("while processing option %s\n", argv[argindex]);

		}
		dagclarg_display_usage(clarg, stderr);
		return EXIT_FAILURE;
	}



	argv = (char **)dagclarg_get_unprocessed_args(clarg, &argc);

	/*
	 * This is the case when a command line argument is taken
	 * as the input when dagcam running as shell interpreter.
	 */
	if (argc)
	{
		if (freopen(argv[0], "r", stdin) != stdin)
			dagutil_panic("cannot open %s: %s\n", argv[0], strerror(errno));
		argc--;
		argv++;
	}

	if (argc)
		dagutil_warning("excessive command line arguments: '%s'%s\n", argv[0], (argc > 1) ? " and further" : "");

	/* A single command line command to execute. */
	if (strlen(g_command_buf) > 0)
	{
		g_uReadFromKeyboard = 1;
		g_uInteractive = 0;
		g_uSaveHistory = 0;
	}

	/*
	 * Multiple commands, either file or interactive
	 */
	if (0 == isatty(fileno(stdin)))
	{
		g_uInteractive = 0;
	}
	
#if HAVE_EDITLINE
	using_history();
#endif /* HAVE_EDITLINE */



	/*
	 * Open the TCAM object
	 * this is not required due we are not using separatly cam and dag drivir
	 */

	memset(dev_p_la1,0,sizeof(idt75k_dev_t));
	memset(dev_p_la2,0,sizeof(idt75k_dev_t));

	/* get the IO memory poniter for the board */
	if ( g_uEmulation == 0 )
	{
	    g_dagfd = dag_open (tcam_namebuf);
    	    if ( g_dagfd < 0 )
	    {
	    	printf("errror\n");
		/* if is not an error if the dag card doesn't exist ... this program can be used without a dag card */
		g_dagfd = -1;
		g_iom_p = NULL;
	    }
	    else
	    {
	    	printf("opened\n");
		/* get an IOM pointer */
	#if 0
		g_iom_p = mmap(NULL, 1024*64, PROT_READ | PROT_WRITE,
					MAP_SHARED, g_dagfd, 0);
	#endif
		g_iom_p = dag_iom(g_dagfd);

		/* this one is only for the DRB version */
		if ( g_iom_p == NULL )
			dagutil_panic ("dag_iom failed\n");
#ifdef DRB_VERSION
		count = dag_reg_find((char *)g_iom_p, 0x6e, regs);
		if (count < 1)
		{
		 	dagutil_panic("dag_reg_find failed: \n");	
		}
		dev_p_la1->mmio_ptr = (void *) (g_iom_p + regs[0].addr);
	#if 0
		if (count < 2 )
		{
		 	dagutil_warning("dag_reg_find failed frodo the second LA interface may be old image : %s\n", strerror(count));	
		} else					
			dev_p_la2->mmio_ptr = (void *) (g_iom_p + regs[1].addr);
	#endif
			
		/* This is the TCAM device ID in case cascaded TCAMS
		 * at the moment we have only one TCAM with ID 0 always
                 */

		dev_p_la->device_id = 0;
#endif
		dagutil_verbose("Loaded Dag Card\n");
	    }
	} else {
	    /* 	TO BE DECIDED will the emulation will be on the lowest level 
	    	or we are going to provide DRB emulation level including we can provide a driver which 
	    	reports each access to a memory */
		g_iom_p = malloc(64*1024);
		dev_p_la1->mmio_ptr = g_iom_p;
		printf("Emulation Enabled supports only one LA interface \n");
	}

	/*
	 * Initialization
	 */
	if (1 == g_uInteractive)
	{
		int safed;
		FILE *fp;

		/* Display short greeting */
		printf("Infinicamcam alive.\n");

		/*
		 * Read in rc file without closing stdin, stdout is untouched.
		 * Since readline is not used here we don't have any problems.
		 */
		safed = dup(STDIN_FILENO);
		if (safed < 0)
			dagutil_panic("cannot duplicate stdin: %s\n", strerror(errno));
		
		if (freopen(g_rc_filename_buf, "r", stdin) != stdin)
		{
			/*
			 * Probably doesn't exist
			 */
			(void) fclose(stdin);	/* paranoia ? */
		}
		else
		{
			infinicam();
			if (fclose(stdin) < 0)
				dagutil_panic("cannot fclose %s on stdin: %s\n", g_rc_filename_buf, strerror(errno));
		}
		
		if (dup(safed) != STDIN_FILENO)
			dagutil_panic("cannot replicate stdin: %s\n", strerror(errno));

		fp = fdopen(STDIN_FILENO, "r");
		
		if (fp == NULL)
			dagutil_panic("fdopen on old stdin failed: %s\n", strerror(errno));

		*stdin = *fp; /* interesting to see that this works */
		
#if HAVE_EDITLINE
		clear_history();
#endif /* HAVE_EDITLINE */

		g_uHaveReadCommandLine = 1;
	}
	else
	{
		g_uSaveHistory = 0;
	}

	dag_read_history(g_history_filename_buf);
	
#if HAVE_EDITLINE
	g_uHistoryCount = where_history();
#endif /* HAVE_EDITLINE */

	infinicam();
	
	dag_write_history(g_history_filename_buf);

	return EXIT_SUCCESS;
}


static void
dag_read_history(const char* filename)
{
#if HAVE_EDITLINE
	if (0 == g_uSaveHistory)
	{
		return;
	}

	(void) read_history(filename);
#endif /* HAVE_EDITLINE */
}


static void
dag_write_history(const char* filename)
{
#if HAVE_EDITLINE
	if (0 == g_uSaveHistory)
	{
		return;
	}

	if (write_history(filename))
	{
		dagutil_warning("couldn't save history file %s: %s\n", filename, strerror(errno));
	}
#endif /* HAVE_EDITLINE */
}

static void
cmd_help(int argc, char *argv[])
{
	if (argc > 1)     /* any argument prints help message. Lazy parsing. */
	{
		printf("help\n\
	Lists available commands.\n");
		return;
	}
	/*
	 * The beginning of most of these lines are TAB characters.
	 * Please ensure your editor does not chew on the tabs.
	 */
	/*
	 * Wouldn't it be nice if this data fit on one 80x25 screen?
	 * Maybe we need to put pauses every 20 lines for slow readers?
	 */
	printf("Usage:\n\
	help         - this page\n\
	quit         - exit program\n\
	reset        - Forces a hardware reset of the CAM. Must be followed with an \"init\" to be useful.\n\
	init         - Initialises the CAM. Performs many operations until the cam is ready for learning and searching.\n\
	flush        - Sets all entries in the CAM to be Invalid.\n\
	{rw}csr      - reads/writes General & Database Configuration Registers.\n\
	{rw}db       - reads/writes Database Configuration Registers.\n\
	{rw}gmr      - reads/writes 144-bits of a Global Mask Registers.\n\
	{rw}entry    - reads/writes a 144-bit entry in the CAM memory space.\n\
	decode       - reads a 144-bit CAM entry and decodes the fields to there.\n\
	sentry       - changes the Valid/Invalid flag on one entry in the CAM memory space. Does not alter the data value.\n\
	search       - searches the TCAM for an value.\n\
\n\
	test         - performs tests on the interface\n\
	production_test	- performs production tests on TCAM and SRAM interfaces\n\
			  NOTE: please run \"init\" after the test to reset GMR\n\
	ident	     - get ident 1 or 2 \n\
	interface    - display or change Firmware interface to use for commands except init and reset \n\
\n\
");
}
/*	
	               Firmware Control Routines:\n\
	interface    - display or change Firmware interface\n\
	frst         - reset Firmware LA-1 interface Not Implemented \n\
	finit        - set Firmware Array to a sensible thing Not Implemented \n\
	fstatus      - pretty-print Firmware LA-1 CSR Not Implemented \n\
	fenable      - enable Firmware LA-1 interface Not Implemented \n\
	               Low Level Firmware Routines: Not Implemented \n\
	llshow       - read entired Firmware Not Implemented\n\
	llset        - set an entry in the Firmware Array\n\
	llwrite      - initiate Firmware LA-1 Transaction Not Implemented\n\
	llread       - initiate Firmware Result Mailbox read Not Implemented\n\
	mlread       - initiate Firmware Result Mailbox reads Not Implemented\n\
	               High Level Firmware Routines: Not Implemented\n\
	f{rw}csr     - reads/writes General & Database Configuration Registers.\n\
	fsvld        - Sets valid on a given CAM entry\n\
	fcvld        - Clears valid on a given CAM entry\n\
	frentry      - Read a given CAM entry, indexes are 36-bit aligned\n\
	fsearch      - Search for a given 144-bit term\n\
	{rw}<command> means preface command with either r for read, or w for write.\n\
	\"<command> ?\" returns the arguments needed for that command, e.g.\n\
	\"rentry ?\" will describe how to use the rentry command.\n\
\n\
");
}
*/


static void
cmd_quit(int argc, char *argv[])
{
	if (argc > 1)
	{
		/* any argument prints help message. Lazy parsing. */
		printf(
			"quit\n"
			"Quits the shell and returns you to your mundane existence.\n");
		return;
	}

	if ( g_dagfd != -1 )
		dag_close(g_dagfd);

	printf("\tGoodbye\n");
	exit(EXIT_SUCCESS);
}


static void
cmd_verbose(int argc, char *argv[])
{
	if ((argc > 1 && argv[1][0] == '?') || (argc > 2))
	{
		printf("verbose [n]\n\
	[n] : if n = 1, enable verbosity. if n = 0 disable verbosity.\
	      if n not specified, print current status.\n");
		return;
	}

	if (argc > 1)
	{
		/* set verbosity */
		if (argv[1][0] == '1')
		{
			dagutil_inc_verbosity();
		}
	}
	else
	{
        	/* print verbosity */
		printf("\tVerbose Debugging is %s\n", (dagutil_get_verbosity()) ? "Enabled" : "disabled");
	}
}


static void
cmd_csr(int argc, char *argv[])
{
	int      res;
	uint32_t rw;
	uint32_t addr = 0;
	uint32_t value = 0;

	rw = (argv[0][0] == 'w') ? 1 : 0;

	if (argc < (int)(2 + rw) || argv[1][0] == '?')     /* read needs 2, write needs 6 */
	{
		if (rw)
			printf("wcsr <addr> <value>\n\
			addr = 19-bit value selecting which CSR (Registers/SMT/Age FIFO) to write to\n\
			value = 32-bit value to write to the selected CSR\n");
		else
			printf("rcsr <addr> \n\
			addr = 19-bit value selecting which CSR (Registers/SMT/Age FIFO) to read from\n\
			displays the 32-bit contents of the selected CSR\n");
		return;
	}

	addr = strtoul(argv[1], NULL, 16);
	if (rw)
	{
		value = strtoul(argv[2], NULL, 16);
	}



	if (rw)
	{
		res = idt75k_write_csr(dev_p_la, addr, value);
		if ( res != 0 )
			printf ("\twriting CSR aborted abnormally with the following error code %d\n", res);
	}
	else
	{
		res = idt75k_read_csr(dev_p_la, addr, &value);
		if ( res != 0 )
			printf ("\treading CSR aborted abnormally with the following error code %d\n", res);
		else
			printf("\tCSR[0x%05x]=0x%08x\n", addr, value);

	}
}


static void
cmd_flush(int argc, char *argv[])
{
	int res;

	if (argc > 1)
	{
		/* any argument prints help message. Lazy parsing. */
		printf("flush\n\
			Marks every entry in the CAM memory space as invalid.\n");
		return;
	}
	res = idt75k_flush_device(dev_p_la);	
	if ( res != 0 )
	{
		printf ("\flushing aborted abnormally with the following error code %d\n", res);
	}
}


static void
cmd_reset(int argc, char *argv[])
{

	if (argc > 1)
	{
		/* any argument prints help message. Lazy parsing. */
		printf("reset\n\
			Issues a hardware reset to the CAM. The contents of any\n\
			Register / Memory Space location after a reset is unpredictable.\n\
			Must be followed by an \"init\" command before the CAM is usable.\n\
			(init also performs a reset, so reset is a kinda pointless operation)\n");
			return;
	}
 
	if(0 != idt75k_reset_device(dev_p_la1, IDT75K_RESET_ALL_INTERFACES)) {
		dagutil_error("failure to reset TCAM\n");
	}

}

static void
cmd_init(int argc, char *argv[])
{
	int res;
	res = tcam_initialise(dev_p_la1,dev_p_la2);
	if ( res != 0 )
	{
		printf ("\tsetting GMR aborted abnormally with the following error code %d\n", res);
	}
	
}


static void
cmd_interface(int argc, char *argv[])
{

	uint32_t value;
	int err;
	if (argc > 2 || (argc >= 2 && argv[1][0] == '?'))
	{
		printf("interface [<if>]\n\
	if = (optional). Which interface to switch to.\n\
	Print current interface if omitted.\n");
		return;
	}

	if( argc == 2 ) {
		if( argv[1][0] == '0' ) {
			printf("Now using Interface 0\n" );
			dev_p_la = dev_p_la1;
			g_csr_base = 0x8210;
			g_dbg_base = 0x8214;
		} else {
			printf("Now using Interface 1\n" );		
			dev_p_la = dev_p_la2;
			g_csr_base = 0x8210;
			g_dbg_base = 0x8224;
		}
		
	} else {
			printf ("Currently using interface %u report by Software %p\n", (dev_p_la == dev_p_la1)?0:1, dev_p_la->mmio_ptr);
		if ( (err = idt75k_read_csr(dev_p_la, NSE_IDENT2_ADDR, &value)) != 0 )
		{
			dagutil_warning("read ident failed errorno:%d, addr=0x%x, value=0x%x\n",errno, NSE_IDENT2_ADDR, value);
			return;
		}
		else
		{
			/* Pretty-print all aspects of the entry read */
			printf ("Currently using interface %u report by TCAM \n", (value & 0x80000000)?1:0);
		}

	}
}


static void
cmd_llshow(int argc, char *argv[])
{
	uint32_t rdwr;
	uint32_t datalo, datahi;
	uint64_t data;
	uint32_t i;

	if( !g_have_init ) {
		g_array_size = (cardread( g_dbg_base) & 0xff00) >> 8;
		g_have_init = 1;
	}
	if (argc != 2|| argv[1][0] == '?')
	{
		printf("llshow <rdwr>\n\
	rdwr = '1' for the Read Array, '0' for the Write Array\n");
		return;
	}

	if( argv[1][0] == '0' ) {
		rdwr = 0;
		printf( "Write Array\n" );
	} else { // assume read
		printf( "Read Array\n" );
		rdwr = 1;
	}

	cardwrite( g_dbg_base, 0x000a0000 | (rdwr << 20) );
	for( i = 0; i<= g_array_size; i++ ) {
		datahi = cardread(g_dbg_base+4);
		datalo = cardread(g_dbg_base+8);
		data=unpack_data(datahi,datalo);
		printf( "Entry %.2x : ", i );
		if( rdwr ) {
			printf( "%svalid", (unpack_vld(datahi,datalo)?"  ":"in") );
		}
		printf( " %sable A=%.6lx D=%.9"PRIu64" (%.4"PRIu64"%.4x)\n",
			(unpack_enable(datahi,datalo)?"dis":" en"),
			unpack_addr(datahi,datalo), 
			data, (data>>18) & 0xffff, datalo&0xffff );
	}
	
}

static void
cmd_llset(int argc, char *argv[])
{
	uint32_t rdwr, enable_N;
	uint32_t datalo, datahi;
	uint32_t index, addr;
	uint64_t data;


	if (argc != 6|| argv[1][0] == '?')
	{
		printf("llset <rdwr> <index> <enable_N> <addr> <data>\n\
	rdwr = '1' for the Read Array, '0' for the Write Array\n\
	index = which entry in the array to alter\n\
	enable_N = '0' to drive enable, '1' to ignore enable\n\
	addr = address value (22 bit)\n\
	data = data value (36 bit)\n");
		return;
	}

	if( argv[1][0] == '0' ) {
		rdwr = 0;
	} else { // assume read
		rdwr = 1;
	}
	index = strtoul( argv[2], NULL, 16 ) & 0xff;
	if( argv[3][0] == '0' ) {
		enable_N = 0;
	} else { // assume disabled
		enable_N = 1;
	}
	addr = strtoul( argv[4], NULL, 16 ) & 0x3fffff;
#ifdef _WIN32
	data = _strtoui64( argv[5], NULL, 16 ) & 0xffffffffffLL;
#else
	data = strtoull( argv[5], NULL, 16 ) & 0xffffffffffLL;
#endif
	cardwrite( g_dbg_base, (0x00000000 | (rdwr << 20) | index ));
	datahi = packhi(0,enable_N,addr,data);
	datalo = packlo(data);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
}

static void
finit_i( int rdwr, int first, int count )
{
	int i;
	
	cardwrite( g_dbg_base, 0x000a0000 | (rdwr << 20) | first );
	for( i = first; i<= count; i++ ) {
		cardwrite( g_dbg_base + 4, 0xf7ffffff );
		cardwrite( g_dbg_base + 8, 0xffffffff );
	}
	
}

static void
cmd_finit(int argc, char *argv[])
{
	uint32_t rdwr;
	uint32_t both = 1;


	if (argc > 2 || (argc == 2 && argv[1][0] == '?'))
	{
		printf("finit [<rdwr>]\n\
	rdwr = '1' for the Read Array, '0' for the Write Array, default both\n");
		return;
	}

	if( argc == 2 ) {
		both = 0;
		if( argv[1][0] == '0' ) {
			rdwr = 0;
		} else { // assume read
			rdwr = 1;
		}
	} else {
		both = 1;
		rdwr = 0;
	}

	g_array_size = (cardread( g_dbg_base) & 0xff00) >> 8;
	g_have_init = 1;
	finit_i( rdwr, 0, g_array_size );
	if( both == 1 ) {
		finit_i( 1, 0, g_array_size );
	}

}


static void
cmd_llwrite(int argc, char *argv[])
{
	if (argc != 1) {
		printf("llwrite\n\
	no arguments.\n");
		return;
	}
	cardwrite( g_dbg_base, 0x10000000 );
}

static void
cmd_llbread(int argc, char *argv[])
{
	uint32_t i;
	uint32_t datahi, datalo;
	uint64_t data[256];
	
	if( !g_have_init ) {
		g_array_size = (cardread( g_dbg_base) & 0xff00) >> 8;
		g_have_init = 1;
	}
	if (argc != 1) {
		printf("llbread\n\
	no arguments.\n");
		return;
	}
	cardwrite( g_dbg_base, 0x301a0000 );
	dagutil_nanosleep(2000);
	for( i = 0; i<= g_array_size; i++ ) {
		datahi = cardread(g_dbg_base+4);
		datalo = cardread(g_dbg_base+8);
		data[i]=unpack_data(datahi,datalo);
		printf( "%.2x %.9"PRIu64" (%.4"PRIu64"%.4"PRIu64")\n", i, data[i], (data[i]>>18) & 0xffff, data[i]&0xffff );
	}
	printf("\n");
	
}

static void // shamt magic value. Use 1
smart_read_i( uint32_t context, uint32_t shamt, uint32_t is_search, uint32_t bits )
{
	int k;
	int cnt = 0;
	uint32_t datahi, datalo;
	uint64_t data;
	uint32_t data32;

	if( (bits % 32) != 0) {
		cnt = (bits / 32)+1;
	} else {
		cnt = (bits / 32);
	}
	if( (int)cnt > ((int)g_array_size - (int)shamt) - 1 ) {
		cnt = (g_array_size - shamt) - 1;
		printf( "Reading at most %u words, %u bits.\n", cnt, cnt * 32 );
	}
	cardwrite( g_dbg_base, 0x00110000 );
	for( k = 0; k < 8; k++ ) {
		cardwrite( g_dbg_base + 4, 0xf800000f | (k<<4) | (context<<19) );
	}
	cardwrite( g_dbg_base, 0x201a0000 | shamt );
	dagutil_nanosleep(2000);
	datahi = cardread(g_dbg_base+4);
	datalo = cardread(g_dbg_base+8);
	data=unpack_data(datahi,datalo);
	data32 = (((data >> 18) & 0xffff) << 16) | (data & 0xffff);
	if( is_search ) {
		printf( "%s%s %s (%.8x)   ", ((data32 & (1<<31)) ? "" : "INVLD " ), ((data32 & (1<<30)) ? "HIT " : "miss" ), ((data32 & (1<<29)) ? "MULT" : "sole" ), data32 & 0x1fffffff );
	} else {
		printf( "%s%s ", ((data32 & (1<<31)) ? "" : "INVLD" ), ((data32 & (1<<30)) ? " ERR" : "" ) );
	}
	for( k = 0; k < cnt; k++ ) {
		datahi = cardread(g_dbg_base+4);
		datalo = cardread(g_dbg_base+8);
		data=unpack_data(datahi,datalo);
		data32 = (((data >> 18) & 0xffff) << 16) | (data & 0xffff);
		if( (uint32_t)bits >= (uint32_t)(k+1) * 32 || true ) { // xxxx
			printf( "%.8x ", data32 );
		} else {
			data32 >>= (unsigned)(32 - (bits % 32));
			switch((bits % 32) / 8) {
			case 3:
				printf( "%.8x ", data32 );
				break;
			case 2:
				printf( "%.6x ", data32 );
				break;
			case 1:
				printf( "%.4x ", data32 );
				break;
			case 0:
			default:
				printf( "%.2x ", data32 );
				break;
			}
		}
	}
	printf( "\n" );
	
}

static void
cmd_mlread( int argc, char *argv[] )
{
	uint32_t context, shamt, is_search, bits;
	
	if (argc != 5 || argv[1][0] == '?')
	{
		printf("mlread <context> <shamt> <is_search> <bits>\n\
	context = context to read from.\n\
	shamt = Magic number, use 1.\n\
	is_search = '1' for search, and '0' for indirect transactions.\n\
	bits = number of bits to read\n");
		return;
	}
	context   = strtoul( argv[1], NULL, 16 );
	shamt     = strtoul( argv[2], NULL, 16 );
	if( argv[3][0] == '1' ) {
		is_search = 1;
	} else {
		is_search = 0;
	}
	bits = strtoul( argv[4], NULL, 0 );
	
	smart_read_i( context, 1, is_search, bits);
}

static void
cmd_frcsr( int argc, char *argv[] )
{
	uint32_t addr16;
	uint64_t addr18;
	uint32_t datahi, datalo;
	if (argc != 2 || argv[1][0] == '?')
	{
		printf("frcsr <reg>\n\
	reg = Register to read.\n");
		return;
	}
	addr16 = strtoul( argv[1], NULL, 16 ) & 0x7ffff;
	addr18 = make18b((uint64_t)addr16 | 0x01800000);
	datahi = packhi( 0, 0, 0x06000, addr18);
	datalo = packlo(addr18);
	
	finit_i( 0, 1, g_array_size);
	cardwrite( g_dbg_base, 0x00020000 );
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	cardwrite( g_dbg_base, 0x101a0000 );
	// need a delay here, smart_read_i writes to read_array to initialise '
	// it, so that's our delay.
	printf( "\tCSR[0x%.5x] = ", addr16 );
	smart_read_i( 0, 1, 0, 32);
}

static void
cmd_fwcsr( int argc, char *argv[] )
{
	uint32_t addr16, data16;
	uint64_t addr18, data18;
	uint32_t datahi, datalo;

	if (argc != 3 || argv[1][0] == '?')
	{
		printf("fwcsr <reg> <value>\n\
	reg = Register to target.\n\
	value = 32-bit value to write.\n");
		return;
	}
	addr16 = strtoul( argv[1], NULL, 16 ) & 0x7ffff;
	data16 = strtoul( argv[2], NULL, 16 );
	addr18 = make18b((uint64_t)addr16 | 0x01800000);
	data18 = make18b((uint64_t)data16);
	
	finit_i( 0, 2, g_array_size);
	cardwrite( g_dbg_base, 0x00020000 );
	// Cycle 0, command and more command
	datahi = packhi( 0, 0, 0x06000, addr18);
	datalo = packlo(addr18);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	// Cycle 1 command continuance and data to write
	datahi = packhi( 0, 0, 0x06001, data18);
	datalo = packlo(data18);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	// No cycle 2 for 32-bit write

	cardwrite( g_dbg_base, 0x101a0000 );
	dagutil_nanosleep(2000);
}

static void
cmd_frentry( int argc, char *argv[] )
{
	uint32_t addr16;
	uint64_t addr18;
	uint32_t datahi, datalo;

	if (argc != 2 || argv[1][0] == '?')
	{
		printf("frentry <addr>\n\
	addr  = Location to read from. Reads 72 bits from given address.\n\
	        nb: Addresses are in 32-bit multiples.\n");
		return;
	}
	addr16 = strtoul( argv[1], NULL, 16 ) & 0x7ffff;
	addr18 = make18b((uint64_t)addr16);
	
	finit_i( 0, 2, g_array_size);
	cardwrite( g_dbg_base, 0x00020000 );
	// Cycle 0, command and more command (addr)
	datahi = packhi( 0, 0, 0x06000, addr18);
	datalo = packlo(addr18);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	// No cycle 1
	cardwrite( g_dbg_base, 0x101a0000 );
	// need a delay here, smart_read_i writes to read_array to initialise '
	// it, so that's our delay.
	printf( "\tEntry[0x%.5x] = ", addr16 );
	smart_read_i( 0, 1, 0, 72);

}

static void
cmd_fsearch( int argc, char *argv[] )
{
	uint32_t gmr;
	uint64_t wdat0, wdat1, wdat2, wdat3;
	uint32_t datahi, datalo;

	if (argc < 5 || argc > 6 || argv[1][0] == '?')
	{
		printf("frentry <data0> <data1> <data2> <data3> <data4> [<gmr>]\n\
	data0  = Most Significant 36 bits to search for\n\
	...\n\
	data4  = Least Significant 36 bits to search for\n\
	gmr = (optional) mask to search against. Default = 0x1f, no mask\n\
	        nb: Returned Address is in 32-bit multiples.\n");
		return;
	}
#ifdef _WIN32
	wdat0 = _strtoui64( argv[1], NULL, 16 ) & 0xfffffffffLL;
	wdat1 = _strtoui64( argv[2], NULL, 16 ) & 0xfffffffffLL;
	wdat2 = _strtoui64( argv[3], NULL, 16 ) & 0xfffffffffLL;
	wdat3 = _strtoui64( argv[4], NULL, 16 ) & 0xfffffffffLL;
#else
	wdat0 = strtoull( argv[1], NULL, 16 ) & 0xfffffffffLL;
	wdat1 = strtoull( argv[2], NULL, 16 ) & 0xfffffffffLL;
	wdat2 = strtoull( argv[3], NULL, 16 ) & 0xfffffffffLL;
	wdat3 = strtoull( argv[4], NULL, 16 ) & 0xfffffffffLL;
#endif

	if( argc == 6 ) {
		gmr = strtoul( argv[5], NULL, 16 ) & 0x1f;
	} else {
		gmr = 0x1f;
	}

	finit_i( 0, 4, g_array_size);
	cardwrite( g_dbg_base, 0x000a0000 );
	// Cycle 0 : Command Start, 36-bit search term #0
	datahi = packhi( 0, 0, (gmr<<8), wdat0);
	datalo = packlo(wdat0);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	// Cycle 1 : Command continue, 36-bit search term #1
	datahi = packhi( 0, 0, (gmr<<8) | 1 , wdat1);
	datalo = packlo(wdat1);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	// Cycle 2 : Command continue, 36-bit search term #2
	datahi = packhi( 0, 0, (gmr<<8) | 2 , wdat2);
	datalo = packlo(wdat2);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	// Cycle 3 : Command continue, 36-bit search term #3
	datahi = packhi( 0, 0, (gmr<<8) | 2 , wdat3);
	datalo = packlo(wdat3);
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	// There is no Cycle 4 (thankfully)
	cardwrite( g_dbg_base, 0x101a0000 );
	dagutil_nanosleep(2000); // keep delay. searches are slow
	printf( "Search : " );
	smart_read_i( 0, 1, 1, 32);
	
	
}
static void
cmd_fsetclrvld( int argc, char *argv[] )
{
	uint32_t cmd;
	uint32_t addr16;
	uint64_t addr18;
	uint32_t datahi, datalo;
	if( argv[0][1] == 's' ) {
		cmd=0x5;
	} else {
		cmd=0x6;
	}
	if (argc != 2 || argv[1][0] == '?')
	{
		if( cmd == 0x5 ) {
			printf("fsvld <reg>\n\
	reg = Location to set valid of (nb! addressed in multiples of 36b)\n");
		} else {
			printf("fcvld <reg>\n\
	reg = Location to clear valid of (nb! addressed in multiples of 36b)\n");
		}
			return;
	}
	addr16 = strtoul( argv[1], NULL, 16 );
	addr18 = make18b((uint64_t)addr16 | (cmd<<28) );
	datahi = packhi( 0, 0, 0x06000, addr18);
	datalo = packlo(addr18);
	
	finit_i( 0, 1, g_array_size);
	cardwrite( g_dbg_base, 0x000a0000 );
	cardwrite( g_dbg_base + 4, datahi );
	cardwrite( g_dbg_base + 8, datalo );
	
	cardwrite( g_dbg_base, 0x101a0000 );
	dagutil_nanosleep(2000);
}

static void // shamt magic value. Use 1
fread_smart_i( int shamt )
{
	uint32_t i, j, k, l;
	uint32_t datahi, datalo;
	uint64_t data;
	uint32_t data32, context;
	
	if( !g_have_init ) {
		g_array_size = (cardread( g_dbg_base) & 0xff00) >> 8;
		g_have_init = 1;
	}
	if( (cardread(g_csr_base) & (1<<7)) == 0 ) {
		printf( "fread.smart: No results pending at this time\n" );
		return;
	}
	
	for( l = 0; l < 4; l++ ) {
		// Init to clear array. (except zero, this time)
		finit_i( 1, 1, g_array_size );
		
		// Command read RSR[0]
		cardwrite( g_dbg_base, 0x00110000 );
		cardwrite( g_dbg_base + 4, 0xf800000f | ((l+8) << 4) );
		cardwrite( g_dbg_base, 0x201a0000 | shamt );
		dagutil_nanosleep(2000);
		datahi = cardread(g_dbg_base+4);
		datalo = cardread(g_dbg_base+8);
		if( unpack_vld(datahi,datalo) ) {
			// Get data as a 32-bit number
			data=unpack_data(datahi,datalo);
			context = (((data >> 18) & 0xffff) << 16) | (data & 0xffff);
			dagutil_verbose( "fread.smart: RSR[%u] say %.8x. %s\n", l, context, (l==0)?"(nb: additional words read contain garbage)":"" );
			
			// For each bit set in the register, loop.
			for( i=0, j=1; i < 32; i++, j<<=1  ) {
				if( context & j ) {
					cardwrite( g_dbg_base, 0x00110000 );
					for( k = 0; k < 8; k++ ) {
						cardwrite( g_dbg_base + 4, 0xf800000f | (k<<4) | ((i + 32 * l) <<19)  );
					}
					cardwrite( g_dbg_base, 0x201a0000 | shamt );
					dagutil_nanosleep(2000);
					datahi = cardread(g_dbg_base+4);
					datalo = cardread(g_dbg_base+8);
					data=unpack_data(datahi,datalo);
					data32 = (((data >> 18) & 0xffff) << 16) | (data & 0xffff);
					printf( "context %.3i: %s%s%s (%.8x)   ", i + 32 * l, ((data32 & (1<<31)) ? "VLD" : "INVLD" ), ((data32 & (1<<30)) ? " ERR/HIT" : "" ), ((data32 & (1<<29)) ? " MULT" : "" ), data32 & 0x1fffffff );
					for( k = 0; k < 7; k++ ) {
						datahi = cardread(g_dbg_base+4);
						datalo = cardread(g_dbg_base+8);
						data=unpack_data(datahi,datalo);
						data32 = (((data >> 18) & 0xffff) << 16) | (data & 0xffff);
						printf( "%.8x ", data32 );
					}
					printf( "\n" );
				}
			}
		} else {
			printf( "fread.smart: RSR[%u] returned %.8x %.8x, which is wrong wrongity wrong. Terminating transaction.\n", l, datahi, datalo );
		}
		if( (cardread(g_csr_base) & (1<<7)) == 0 ) {
			printf("\n");
			return;
		}

		}
		printf("\n");
}

static void
cmd_llread(int argc, char *argv[])
{
	uint32_t i;
	uint32_t datahi, datalo;
	uint32_t shamt, smart;
	uint64_t data;
	
	if( !g_have_init ) {
		g_array_size = (cardread( g_dbg_base) & 0xff00) >> 8;
		g_have_init = 1;
	}
	if (argc > 2 || (argc >=2 && argv[1][0] == '?')) {
		printf("llread [<fw_debug_factor>]\n\
	fw_debug_factor = (optional) If provided, perform a \"smart\" read.\n\
	If not provided (default) perform a dumb read.\n\
	Suggeseted value for fw_debug_factor is 1\n");
		return;
	}
	if( argc == 2 ) {
		smart = 1;
		shamt = strtoul(argv[1], NULL, 16);
	} else {
		smart = 0;
		shamt = 1;
	}
	    
	if( g_array_size < 8 && smart == 1 ) {
		printf( "Insufficient registers (%u) for smart read. Dumb read mode engaged.\n", g_array_size );
		smart = 0;
	}
	if( smart == 1 ) { // Smart Parsed Read
		fread_smart_i( shamt );
		
	} else { // Legacy, Dumb Less-parsed Read
		cardwrite( g_dbg_base, 0x201a0000 );
		dagutil_nanosleep(2000);
		for( i = 0; i<= g_array_size; i++ ) {
			datahi = cardread(g_dbg_base+4);
			datalo = cardread(g_dbg_base+8);
			data=unpack_data(datahi,datalo);
			printf( "%.2x %.9"PRIu64" (%.4"PRIu64"%.4"PRIu64")\n", i, data, (data>>18) & 0xffff, data&0xffff );
		}
		printf("\n");
	}
	
}

static void
cmd_llshotgun(int argc, char *argv[])
{
	uint32_t i;
	uint32_t addr;
	uint32_t datahi, datalo, datae;
	uint64_t data[256];
	
	if( !g_have_init ) {
		g_array_size = (cardread( g_dbg_base) & 0xff00) >> 8;
		g_have_init = 1;
	}
	if (argc != 2|| argv[1][0] == '?')
	{
		printf("llbhotgun <addr>\n\
	addr = location to read from. Damages both read and write arrays.\n");
		return;
	}
	addr = strtoul( argv[1], NULL, 16 );	

	datahi = packhi(0,1,addr,0xffffffffffLL);
	datalo = 0xffffffff;
	datae = datahi & 0xfbffffff;
	cardwrite( g_dbg_base, 0x000a0000 );
	for( i = 0; i<= g_array_size; i++ ) {
		cardwrite(g_dbg_base+4, datahi ); // write array
		cardwrite(g_dbg_base+8, datalo );
	}
	cardwrite( g_dbg_base, 0x001a0000 );
	for( i = 0; i<= g_array_size; i++ ) {
		if (i <1 || i >3 ) {
			cardwrite(g_dbg_base+4, datahi ); // read array
		} else {
			cardwrite(g_dbg_base+4, datae ); // read enabled
		}
		cardwrite(g_dbg_base+8, datalo );
	}
	
	// go go go!
	cardwrite( g_dbg_base, 0x301a0000 );
	dagutil_nanosleep(2000);
	for( i = 0; i<= g_array_size; i++ ) {
	  datahi = cardread(g_dbg_base+4);
	  datalo = cardread(g_dbg_base+8);
	  data[i]=unpack_data(datahi,datalo);
	  printf( "%.2x %.9"PRIu64" (%.4"PRIu64"%.4"PRIu64")\n", i, data[i], (data[i]>>18) & 0xffff, data[i]&0xffff );
	}
	printf("\n");
	
}

static void
cmd_fstatus(int argc, char *argv[])
{
	uint32_t tmp;

	if (argc != 1) {
	  printf("fstatus\n\
	no arguments.\n");
	  return;
	}
	tmp = cardread(g_csr_base);

	printf( "LA#0 dp_rst:%u cal_pending:%u cal_started:%u FW_enabled:%u CQ_seen:%u idly_rdy:%u result:%u tap:%.2x=%u\n",
		(tmp & (1<<31))?1:0, // dp_rst
		(tmp & (1<<29))?1:0, // cal_pending
		(tmp & (1<<27))?1:0, // cal_started
		(tmp & (1<<25))?1:0, // fw_enabled
		(tmp & (1<<23))?1:0, // CQ_seen
		(tmp & (1<<21))?1:0, // idly_rdy
		(tmp & (1<<15))?1:0, // result
		((tmp >> 8) & 0x7f), // tap
		(tmp & (1<<17)?1:0)?1:0 ); // centre_value
	printf( "LA#1 dp_rst:%u cal_pending:%u cal_started:%u FW_enabled:%u CQ_seen:%u idly_rdy:%u result:%u tap:%.2x=%u\n",
		(tmp & (1<<30))?1:0, // dp_rst
		(tmp & (1<<28))?1:0, // cal_pending
		(tmp & (1<<26))?1:0, // cal_started
		(tmp & (1<<24))?1:0, // fw_enabled
		(tmp & (1<<22))?1:0, // CQ_seen
		(tmp & (1<<21))?1:0, // idly_rdy
		(tmp & (1<<7))?1:0, // result
		(tmp & 0x7f), // tap
		(tmp & (1<<16)?1:0)?1:0 ); // centre_value
	// 0 and aaa00000 = 02a00000
	// 1 and 55600000 = 01600000
	if( (tmp & 0xaaa00000) != 0x02a00000 ) {
		printf("LA#0 sad\n");
	}
	if( (tmp & 0x55500000) != 0x01600000 ) {
		printf("LA#1 sad\n");
	}
}

static void
cmd_frst(int argc, char *argv[])
{

	if (argc != 1) {
	  printf("frst\n\
	no arguments.\n");
	  return;
	}
	cardwrite(g_csr_base, 0xc0000000);
	
}

static void
cmd_fenable(int argc, char *argv[])
{

	if (argc != 1) {
	  printf("fenable\n\
	no arguments.\n");
	  return;
	}
	cardwrite(g_csr_base, 0x03000000);
	
}



static void
cmd_test(int argc, char *argv[])
{
	uint32_t test_num;
	if (argc < 2 || argv[1][0] == '?')
	{
		printf("test <num>\n\
	num = the number of the test to perform, possible tests are listed below\n\
	test 1: fill all database entries with incrementing values, the mask, value and\n\
	        associated data are written with the same incrementing value. This test\n\
	        first configures database to 15 to contain all tcam entries.\n\
	test 2: same as test 1 but after finishing writing all entries it reads them back\n\
	        to verify the contents.\n\
	test 3: TBD\n\
	test 4: performs a full set of unit style tests on the TCAM driver interface, these tests\n\
	        were orignally written to use the boost C++ testing framework, but have since\n\
			been ported to this program.\n\
			\n");
		return;
	}

	test_num = strtoul(argv[1], NULL, 10);
	switch (test_num)
	{
		case 1:
			//TESTME:
			printf("cmd_test case 1 \n");
			infinicam_test_1(dev_p_la);
			break;
		case 2:
			infinicam_test_2(dev_p_la);
			break;
		case 3:
			infinicam_test_3(dev_p_la);
			break;

		case 4:
			infinicam_test_4(dev_p_la);
			break;

		case 5 :
			production_test_1(dev_p_la);
			break;

		case 6 :
			production_test_2(dev_p_la);
			break;
		case 7 :
			production_test_3(dev_p_la);
			break;
		case 8 :
			production_test_4(dev_p_la);
			break;
		default:
			printf ("\tinvalid test number, test aborted\n");
			break;
	}

	return;
}

static void
cmd_production_test(int argc, char *argv[])
{
	if (argc > 1)
	{
		printf("production_test\n\
	production_test : performs a full production set of unit style tests on the TCAM and LA and SRAM  interface, \n\
			\n");
		return;
	}
	production_test_1(dev_p_la);
	production_test_2(dev_p_la);
	production_test_3(dev_p_la);
	production_test_4(dev_p_la);

	return;
}

/**
 * Test data bus of tcam associate SRAM. Writing walking 1 and 0
 * patterns to SRAM location 0x0 and read back to check correctness.
 */
void
production_test_1(idt75k_dev_t *dev_p) {
	idt75k_write_sram_t  wr_sram;
	idt75k_read_sram_t   rd_sram;
	int err, i, j, write_failure, read_failure, miss_match;

	write_failure = read_failure = miss_match = 0;
	printf("production test 1\n\t");
	memset (&wr_sram, 0x00, sizeof(wr_sram));
	wr_sram.db_num = 0;
	wr_sram.address = 0x0;

	memset (&rd_sram, 0x00, sizeof(rd_sram));
	rd_sram.db_num = 0;
	rd_sram.address = 0x0;

	for(j = 0; j < 2; j++) {
		if(j == 1) { /* test the last db and sram location */
			wr_sram.db_num = 0xF;
			wr_sram.address = 128*1024 -1;
			rd_sram.db_num = 0xF;
			rd_sram.address = 128*1024 -1;
		}
		/* walking 1's */
		for(i = 0; i < 32; i++) {
			printf(".");
			wr_sram.sram_entry[0] = (0x1 << i);
				
			err = idt75k_write_sram(dev_p, wr_sram.db_num, wr_sram.address, wr_sram.sram_entry);
			if(err == -1) {
				write_failure++;
				dagutil_error("%s: write error\n", __func__);
				return;
			}
			err = idt75k_read_sram(dev_p, rd_sram.db_num, rd_sram.address, rd_sram.sram_entry);
			dagutil_verbose("%s: read %08X\n", __func__, rd_sram.sram_entry[0]);
			if(err == -1) {
				dagutil_error("%s: read error\n", __func__);
				return;
			}
			if(rd_sram.sram_entry[0] != wr_sram.sram_entry[0]) {
				miss_match++;
				dagutil_error("%s: error on %d bit.\n", __func__, i);
			}
		}
		printf("\n\t");
		/* walking 0's */
		for(i = 0; i < 32; i++) {
			printf(".");
			wr_sram.sram_entry[0] = ~(0x1 << (i));
				
			err = idt75k_write_sram(dev_p, wr_sram.db_num, wr_sram.address, wr_sram.sram_entry);
			if(err == -1) {
				write_failure++;
				dagutil_error("%s: write error\n", __func__);
				return;
			}
			err = idt75k_read_sram(dev_p, rd_sram.db_num, rd_sram.address, rd_sram.sram_entry);
			dagutil_verbose("%s read %08X\n", __func__, rd_sram.sram_entry[0]);
			if(err == -1) {
				dagutil_error("%s: read_error\n", __func__);
				return;
			}
			if(rd_sram.sram_entry[0] != wr_sram.sram_entry[0]) {
				miss_match++;
				dagutil_error("%s: error on %d bit.\n", __func__, i);
			}
		}
		printf("\n\t");
	}

	printf("Write failure count: %d\n", write_failure);
	printf("\tRead failure count: %d\n", read_failure);
	printf("\tMiss match count: %d\n", miss_match);
	if(!write_failure && !read_failure && !miss_match)
		printf("test 1 status: PASSED\n\n");
	else
		printf("test 1 status: FAILED\n\n");

	return;
}

/*
*
* The SRAM address bus test write a different value in two one bit inverse 
* address then read back to verify. if read back value get the same value 
* with written, this mean one bit failure at two one bit inverse locations. 
* if they got the differnet value, that means they are correct. 
*/
void production_test_2(idt75k_dev_t *dev_p) {
	idt75k_write_sram_t  wr_sram_1;
	idt75k_write_sram_t  wr_sram_2;
	idt75k_read_sram_t   rd_sram_1;
	idt75k_read_sram_t   rd_sram_2;
	int err, i, write_failure, read_failure, match;
	int patterns[2];
	
	patterns[0] = 0xFFFF0000;
	patterns[1] = 0x0000FFFF;
	write_failure = read_failure = match = 0;
	printf("production test 2\n\t");
	/* initialise read and write struct */
	memset (&wr_sram_1, 0x00, sizeof(wr_sram_1));
	memset (&wr_sram_2, 0x00, sizeof(wr_sram_2));
	memset (&rd_sram_1, 0x00, sizeof(rd_sram_1));
	memset (&rd_sram_2, 0x00, sizeof(rd_sram_2));
	
	wr_sram_1.db_num = wr_sram_2.db_num = 
		rd_sram_1.db_num = rd_sram_2.db_num = 0x0;
	wr_sram_1.sram_entry[0] = patterns[0];
	wr_sram_2.sram_entry[1] = patterns[1];

	wr_sram_1.address = rd_sram_1.address = 128*1024 -1;

	for(i = 0; i < 17; i++) {
		printf(".");
		// flip 1 bit in address
		wr_sram_2.address = (0x1 << i) ^ wr_sram_1.address;
		rd_sram_2.address = (0x1 << i) ^ rd_sram_1.address;
		dagutil_verbose("%s: 1st addresses %X\n", __func__, wr_sram_1.address);
		dagutil_verbose("%s: 2nd addresses %X\n", __func__, wr_sram_2.address);
		
		// write
		err = idt75k_write_sram(dev_p, wr_sram_1.db_num, wr_sram_1.address, wr_sram_1.sram_entry);
		if(err == -1) {
			write_failure++;
			dagutil_error("%s: write error\n", __func__);
			return;
		}
		err = idt75k_write_sram(dev_p, wr_sram_2.db_num, wr_sram_2.address, wr_sram_2.sram_entry);
		if(err == -1) {
			write_failure++;
			dagutil_error("%s: write error\n", __func__);
			return;
		}
		
		// read
		err = idt75k_read_sram(dev_p, rd_sram_1.db_num, rd_sram_1.address, rd_sram_1.sram_entry);
		if(err == -1) {
			read_failure++;
			dagutil_error("%s: read error\n", __func__);
			return;
		}
		err = idt75k_read_sram(dev_p, rd_sram_2.db_num, rd_sram_2.address, rd_sram_2.sram_entry);
		if(err == -1) {
			read_failure++;
			dagutil_error("%s: read error\n", __func__);
			return;
		}
		if(rd_sram_1.sram_entry[0] == rd_sram_2.sram_entry[0]) {
			match++;
			dagutil_error("%s: Identical results which not suppose to\n", __func__);
		}
	}
	printf("\n");

	printf("\tWrite failure count: %d\n", write_failure);
	printf("\tRead failure count: %d\n", read_failure);
	printf("\tIdentical read back count: %d\n", match);
	if(!write_failure && !read_failure && !match)
		printf("test 2 status: PASSED\n\n");
	else
		printf("test 2 status: FAILED\n\n");

	return;
}

/*
*
* 	The interface test which fill all database entries with shift each bit.
* 	This test the 32 segments are used for database 0. which is set increment 
*	value of segment and then write generated pattern into core entry and 
*	read back to correctness of each entry value. 
*
*	This test must executed before the test 2 because test 2 set the gmr.  
*
*/
void
production_test_3(idt75k_dev_t *dev_p) {
	int i, j, k, err;
	uint64_t bit;
	uint32_t db, entry, tag;
	int read_failure, write_failure, miss_match, state;
	uint32_t test_entries[3];
	uint8_t data[18], mask[18], rdata[18], rmask[18];
	uint64_t datas[4];
	uint64_t one = 0x1;

	test_entries[0] = 0x0;
	test_entries[1] = 0x1FFFF;
	test_entries[2] = 0x1000;

	printf("production test 3\n\t");
	db = 0;
	read_failure = write_failure = miss_match = 0;
	for(j = 0; j < 3; j++) {
		entry = test_entries[j];
		for(i = 0; i < 32; i++) {
			printf(".");
			tcam_set_database_sectors(dev_p, db, (0x1 << i));
			/* walking 1's */
			for(bit = 0; bit < 144; bit++) {
				datas[0] = datas[1] = datas[2] = datas[3] = 0;
				if     (bit < 36) datas[3] = (one <<  bit);
				else if(bit < 72) datas[2] = (one << (bit-36));
				else if(bit <108) datas[1] = (one << (bit-72));
				else              datas[0] = (one << (bit-108));
				BUILD_144BIT_ARRAY(data, datas[0], datas[1], datas[2], datas[3]);
				BUILD_144BIT_ARRAY(mask, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL);
				err = tcam_write_cam_entry(dev_p,db, entry, data, mask, (uint32_t)0x0, false);

				if(err == -1) {
					write_failure++;
					dagutil_error("%s: write error!\n", __func__);
				}
				
				err = tcam_read_cam_entry(dev_p,db, entry, rdata, rmask, &tag, &state);
				if(err == -1) {
					read_failure++;
					dagutil_error("%s: read error!\n", __func__);
				}
				err = 0;
				for(k = 0; k < 18; k++) {
					if(rdata[k] != data[k])
						err++;
				}
				if(err != 0) {
					miss_match++;
					dagutil_error("%s: Miss match result! %d %d %"PRIu64"\n", __func__, j, i, bit);
				}
			}

			/* walking 0's */
			for(bit = 0; bit < 144; bit++) {
				datas[0] = datas[1] = datas[2] = datas[3] = 0;
				if     (bit < 36) datas[3] = (~(one <<  bit     ) & 0xFFFFFFFFFLL);
				else if(bit < 72) datas[2] = (~(one << (bit- 36)) & 0xFFFFFFFFFLL);
				else if(bit <108) datas[1] = (~(one << (bit- 72)) & 0xFFFFFFFFFLL);
				else              datas[0] = (~(one << (bit-108)) & 0xFFFFFFFFFLL);
				BUILD_144BIT_ARRAY(data, datas[0], datas[1], datas[2], datas[3]);
				BUILD_144BIT_ARRAY(mask, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL);
				err = tcam_write_cam_entry(dev_p,db, entry, data, mask, (uint32_t)0x0, false);

				if(err == -1) {
					write_failure++;
					dagutil_error("%s: write error!\n", __func__);
				}
				
				err = tcam_read_cam_entry(dev_p,db, entry, rdata, rmask, &tag, &state);
				if(err == -1) {
					read_failure++;
					dagutil_error("%s: read error!\n", __func__);
				}
				err = 0;
				for(k = 0; k < 18; k++) {
					if(rdata[k] != data[k])
						err++;
				}
				if(err != 0) {
					miss_match++;
					dagutil_error("%s: Miss match result! %d %d %"PRIu64"\n", __func__, j, i, bit);
				}
			}

		}
		printf("\n\t");
	}

	printf("Write failure count: %d\n", write_failure);
	printf("\tRead failure count: %d\n", read_failure);
	printf("\tMiss match count: %d\n", miss_match);
	if(!write_failure && !read_failure && !miss_match)
		printf("test 3 status: PASSED\n\n");
	else
		printf("test 3 status: FAILED\n\n");

	return;

}


/*
*
* 	The interface test which test 32 global mask register and then fill
*	database entries with set GMR. This test is same as test3, but it set 
* 	global mask register before writing to core and mask entry
*
*/
void
production_test_4(idt75k_dev_t *dev_p) {
	uint64_t gmr_masks[31][4] = {   {0xFFFFFFFFFLL, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL},
					{0x000000000LL, 0x000000000LL, 0x000000000LL, 0x000000000LL},
					{0xFFFFFFFFFLL, 0xFFFFFFFFFLL, 0x000000000LL, 0x000000000LL},
					{0x000000000LL, 0x000000000LL, 0xFFFFFFFFFLL, 0xFFFFFFFFFLL},
					{0xAAAAAAAAALL, 0xAAAAAAAAALL, 0xAAAAAAAAALL, 0xAAAAAAAAALL},
					{0x555555555LL, 0x555555555LL, 0x555555555LL, 0x555555555LL},
					{0x999999999LL, 0x999999999LL, 0x999999999LL, 0x999999999LL},
					{0x666666666LL, 0x666666666LL, 0x666666666LL, 0x666666666LL},
					{0x100000000LL, 0x000000000LL, 0x100000000LL, 0x000000000LL},
					{0x010000000LL, 0x000000000LL, 0x010000000LL, 0x000000000LL},
					{0x001000000LL, 0x000000000LL, 0x001000000LL, 0x000000000LL},
					{0x000100000LL, 0x000000000LL, 0x000100000LL, 0x000000000LL},
					{0x000010000LL, 0x000000000LL, 0x000010000LL, 0x000000000LL},
					{0x000001000LL, 0x000000000LL, 0x000001000LL, 0x000000000LL},
					{0x000000100LL, 0x000000000LL, 0x000000100LL, 0x000000000LL},
					{0x000000010LL, 0x000000000LL, 0x000000010LL, 0x000000000LL},
					{0x000000001LL, 0x000000000LL, 0x000000001LL, 0x000000000LL},
					{0x000000000LL, 0x100000000LL, 0x000000000LL, 0x100000000LL},
					{0x000000000LL, 0x010000000LL, 0x000000000LL, 0x010000000LL},
					{0x000000000LL, 0x001000000LL, 0x000000000LL, 0x001000000LL},
					{0x000000000LL, 0x000100000LL, 0x000000000LL, 0x000100000LL},
					{0x000000000LL, 0x000010000LL, 0x000000000LL, 0x000010000LL},
					{0x000000000LL, 0x000001000LL, 0x000000000LL, 0x000001000LL},
					{0x000000000LL, 0x000000100LL, 0x000000000LL, 0x000000100LL},
					{0x000000000LL, 0x000000010LL, 0x000000000LL, 0x000000010LL},
					{0x000000000LL, 0x000000001LL, 0x000000000LL, 0x000000001LL},
					{0x200000000LL, 0x000000000LL, 0x200000000LL, 0x000000000LL},
					{0x020000000LL, 0x000000000LL, 0x020000000LL, 0x000000000LL},
					{0x002000000LL, 0x000000000LL, 0x002000000LL, 0x000000000LL},
					{0x000200000LL, 0x000000000LL, 0x000200000LL, 0x000000000LL},
					{0x000020000LL, 0x000000000LL, 0x000020000LL, 0x000000000LL}
				};
	int err, j, state;
	int gmr_write_failure, write_failure, miss_match, read_failure;
	uint32_t i, tag;
	uint8_t gmask[18], rdata[18], rmask[18], zero[18], one[18];
	idt75k_write_entry_t  wr_entry;

	gmr_write_failure = write_failure = miss_match = read_failure = 0;
	zero [0] = zero [1] = zero [2] = zero [3] = zero [4] = zero [5] =
	zero [6] = zero [7] = zero [8] = zero [9] = zero[10] = zero[11] =
	zero[12] = zero[13] = zero[14] = zero[15] = zero[16] = zero[17] = 0;
	one [0] = one [1] = one [2] = one [3] = one [4] = one [5] =
	one [6] = one [7] = one [8] = one [9] = one[10] = one[11] =
	one[12] = one[13] = one[14] = one[15] = one[16] = one[17] = 0xff;
	
	printf("production test 4\n");
	/* clear gmr and core entry */
	memset (&wr_entry, 0x00, sizeof(idt75k_write_entry_t));
	printf("\tinitialise GMRs\n\t");
	for(i = 0; i < 31; i++) {
		printf(".");
		for (j=0; j<18; j++) {
			wr_entry.mask[j] = 0xFF;
		}
		wr_entry.db_num = 0;
		wr_entry.address = i;
		wr_entry.validate = 1;
		wr_entry.gmask = i;
		err = tcam_set_global_mask_reg(dev_p, i, one);
		err = tcam_write_cam_entry_new (dev_p,wr_entry.db_num, wr_entry.address, zero, wr_entry.mask,0,wr_entry.validate,wr_entry.gmask);
	}
	printf("\n\twriting patterns to gmr\n\t");
	/* write 32 different GMRs */
	for(i = 0; i < 31; i++) {
		printf(".");
		BUILD_144BIT_ARRAY(gmask, gmr_masks[i][0], gmr_masks[i][1], gmr_masks[i][2], gmr_masks[i][3]);
		err = tcam_set_global_mask_reg(dev_p, i, gmask);
		if(err == -1) {
			gmr_write_failure++;
			dagutil_error("%s: Failure on write GMR %d\n", __func__, i);
		}
	}
	printf("\n\t");
	/* write different pattern to cam entry with different GMR */
	memset (&wr_entry, 0x00, sizeof(idt75k_write_entry_t));
	for(j = 0; j < 31; j++) {
		printf(".");
		wr_entry.db_num = 0;
		wr_entry.address = j;
		wr_entry.validate = 1;
		wr_entry.gmask = j;

		for (i=0; i<18; i++) {
			wr_entry.mask[i] = 0xFF;
			wr_entry.data[i] = 0xFF;
		}
		
		err = tcam_write_cam_entry_new (dev_p,wr_entry.db_num, wr_entry.address, zero, wr_entry.mask,0,wr_entry.validate,wr_entry.gmask);
		err = tcam_write_cam_entry_new (dev_p,wr_entry.db_num, wr_entry.address, wr_entry.data, wr_entry.mask,0,wr_entry.validate,wr_entry.gmask);
		if ( err != 0 ) {
			write_failure++;
			dagutil_error("%s: write failure.\n", __func__);
			return;
		}
		err = tcam_read_cam_entry(dev_p,0, j, rdata, rmask, &tag, &state);
		if(err != 0) {
			read_failure++;
		}
		dagutil_verbose("%s: read %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n", __func__,
			rdata[0], rdata[1], rdata[2], rdata[3], rdata[4], rdata[5], rdata[6], rdata[7], rdata[8],
			rdata[9], rdata[10], rdata[11], rdata[12], rdata[13], rdata[14], rdata[15], rdata[16], rdata[17]);
		
		err = 0;
		BUILD_144BIT_ARRAY(gmask, gmr_masks[j][0], gmr_masks[j][1], gmr_masks[j][2], gmr_masks[j][3]);
		dagutil_verbose("%s: mask %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n", __func__,
			gmask[0], gmask[1], gmask[2], gmask[3], gmask[4], gmask[5], gmask[6], gmask[7], gmask[8],
			gmask[9], gmask[10], gmask[11], gmask[12], gmask[13], gmask[14], gmask[15], gmask[16], gmask[17]);
		for(i = 0; i < 18; i++) {
			if(rdata[i] != gmask[i]) err++;
		}
		if(err)	{
			dagutil_error("%s: Miss Match at GMR %d\n", __func__, j);
			miss_match++;
		}
	}
	
	printf("\n\tWrite failure count: %d\n", write_failure);
	printf("\tRead failure count: %d\n", read_failure);
	printf("\tMiss match count: %d\n", miss_match);
	if(!write_failure && !read_failure && !miss_match)
		printf("test 4 status: PASSED\n\n");
	else
		printf("test 4 status: FAILED\n\n");

	return;

}



static void
cmd_gmr(int argc, char *argv[])
{
	int      res;
	uint32_t rw;
	uint32_t addr = 0;
	uint64_t data_0 = 0;
	uint64_t data_1 = 0;
	uint64_t data_2 = 0;
	uint64_t data_3 = 0;
	uint8_t  data[18];
	char     data_str[64];

	rw = (argv[0][0] == 'w') ? 1 : 0;

	if (argc < (int)(2 + rw * 4) || argv[1][0] == '?')     /* read needs 2, write needs 6 */
	{
		if (rw)
			printf("wgmr <addr> <data_0> <data_1> <data_2> <data_3>\n\
	addr = 5-bit value selecting which GMR to write to\n\
	data_0 = Lower  36-bit value to write to the selected Entry Mask Register\n\
	data_1 = Second 36-bit value to write to the selected Entry Mask Register\n\
	data_2 = Third  36-bit value to write to the selected Entry Mask Register\n\
	data_3 = Upper  36-bit value to write to the selected Entry Mask Register\n");
		else
			printf("rgmr <addr> \n\
	addr = 5-bit value selecting which GMR to read from\n\
	displays the four 36-bit contents of the selected Entry Mask Register\n");
		return;
	}

	addr = strtoul(argv[1], NULL, 16);
	if (rw)
	{
#ifdef _WIN32
		data_0 = _strtoui64(argv[2], NULL, 16);
		data_1 = _strtoui64(argv[3], NULL, 16);
		data_2 = _strtoui64(argv[4], NULL, 16);
		data_3 = _strtoui64(argv[5], NULL, 16);
#else
		data_0 = strtoull(argv[2], NULL, 16);
		data_1 = strtoull(argv[3], NULL, 16);
		data_2 = strtoull(argv[4], NULL, 16);
		data_3 = strtoull(argv[5], NULL, 16);
#endif
	}

	addr &= 0x1f;
	data_0 &= 0xfffffffffLL;
	data_1 &= 0xfffffffffLL;
	data_2 &= 0xfffffffffLL;
	data_3 &= 0xfffffffffLL;

	if (rw)
	{
		/* write gmr */
		BUILD_144BIT_ARRAY(data, data_0, data_1, data_2, data_3);


		res = tcam_set_global_mask_reg (dev_p_la, addr, data);

		if ( res != 0 )
		{
			printf ("\tsetting GMR aborted abnormally with the following error code %d\n", res);
		}
	}
	else
	{
		/* read gmr */

		res = tcam_get_global_mask_reg(dev_p_la,addr, data);
		if ( res != 0 )
		{
			printf ("\tgetting the GMR aborted abnormally with the following error code %d\n", res);
		}
		else
		{
			BUILD_144BIT_STRING(data_str, data);
			printf("\tGMR[%2u]=%s\n", addr, data_str);
		}
	}
}



static void
cmd_smt(int argc, char *argv[])
{
	uint32_t rw;
	uint32_t addr = 0;
	uint32_t data = 0;
	int err;

	rw = (argv[0][0] == 'w') ? 1 : 0;

	if (argc < (int)(2 + rw) || argv[1][0] == '?')     /* read needs 2, write needs 3 */
	{
		if (rw)
			printf("wsmt <addr> <data>\n\
			addr = 8-bit value selecting which SMT register to write to\n\
			data = 32-bit value to write into a Segment Mapping Table (SMT) Register\n");
		else
			printf("rsmt <addr> \n\
			addr = 8-bit value selecting which SMT register to read from\n\
			displays the 32-bit contents of the selected Segment Mapping Table (SMT) Register\n");
		return;
	}

	addr = strtoul(argv[1], NULL, 16);
	if (rw)
		data = strtoul(argv[2], NULL, 16);


	addr &= 0xff;

	if (rw)
	{
		/* write smt */
		idt75k_write_smt_t  wr_smt;
		memset (&wr_smt, 0x00, sizeof(wr_smt));

		wr_smt.addr = addr;
		wr_smt.value = data;

		if ( (err = idt75k_write_smt(dev_p_la, wr_smt.addr, wr_smt.value) ) == 1  )
			printf ("\twrite aborted abnormally with the following error code %d\n", errno);
	}
	else
	{
		/* read smt */
		idt75k_read_smt_t  rd_smt;
		memset (&rd_smt, 0x00, sizeof(rd_smt));

		rd_smt.addr = addr;

		if ( ( err = idt75k_read_smt(dev_p_la, rd_smt.addr, &rd_smt.value) ) == 1 ) 
		{
			printf ("\twrite aborted abnormally with the following error code %d\n", errno);
		}
		else
		{
			printf ("\t[SMT:0x%02X] 0x%08X  { base:0x%06X shift:0x%X result_type:%d }\n", addr, rd_smt.value,
					((rd_smt.value >> 6) & 0x3FFFF), ((rd_smt.value >> 2) & 0x0F), (rd_smt.value & 0x01));
		}
	}
}



static void
cmd_sentry(int argc, char *argv[])
{
	bool     valid;
	int      res;
	uint32_t addr;
	uint32_t db;

	if (argc < 4 || argv[1][0] == '?')
	{
		printf("sentry <db> <valid> <addr>\n\
			db = 4-bit value selecting which database contains the entry to change\n\
			valid = either \"valid\" or \"invalid\" to set the altered entry\n\
			to Valid or Invalid respectively. May be shortened to 'v' or 'i'\n\
			addr = 19-bit value selecting which memory location to alter\n\
			Marks the selected CAM Memory entry as either Valid or Invalid.\n\
			Does not alter the 144-bit mask or data values at that location.\n");
		return;
	}

	db = strtoul(argv[1], NULL, 16);
	valid = (argv[2][0] == 'v') ? true : false;
	addr = strtoul(argv[3], NULL, 16);

	db &= 0xf;                  /* 4 bits */
	addr &= 0x1ffff;            /* 17 bits */


	if ( valid )
	{
		res = id75k_set_cam_entry_state(dev_p_la, db, addr, 1);
	}
	else
	{
		res = id75k_set_cam_entry_state(dev_p_la, db, addr, 0);
	}
				

	if ( res != 0 )
	{
		printf ("\tsetting valid state aborted abnormally with the following error code %d\n", res);
	}

}



static void
cmd_wentry(int argc, char *argv[])
{
	bool     valid;
	int      res;
	uint32_t tag;
	uint32_t addr;
	uint32_t db;
	uint64_t data_0;
	uint64_t data_1;
	uint64_t data_2;
	uint64_t data_3;
	uint8_t  data[18];
	uint64_t mask_0;
	uint64_t mask_1;
	uint64_t mask_2;
	uint64_t mask_3;
	uint8_t  mask[18];




	if (argc < 12 || argv[1][0] == '?')
	{
		printf("wentry <db> <valid> <addr> <data_3> <data_2> <data_1> <data_0> <mask_3> <mask_2> <mask_1> <mask_0> [<tag>]\n\
		db     = 4-bit value selecting which database contains the entry to write\n\
		valid  = either \"valid\" or \"invalid\" to set the altered entry\n\
	         	 to Valid or Invalid respectively. May be shortened to 'v' or 'i'\n\
		addr   = 19-bit value selecting which memory location to write to\n\
		mask_3 = Upper  36-bit mask value to write\n\
		mask_2 = Third  36-bit mask value to write\n\
		mask_1 = Second 36-bit mask value to write\n\
		mask_0 = Lower  36-bit mask value to write\n\
		data_3 = Upper  36-bit data value to write\n\
		data_2 = Third  36-bit data value to write\n\
		data_1 = Second 36-bit data value to write\n\
		data_0 = Lower  36-bit data value to write\n\
		tag = sets the associated data tag for the entry, defaults to 0\n");
		return;
	}

	db     = strtoul(argv[1], NULL, 16);
	
	valid  = (argv[2][0] == 'v') ? true : false;
	addr   = strtoul(argv[3], NULL, 16);
#ifdef _WIN32
	data_3 = _strtoui64(argv[4], NULL, 16);
	data_2 = _strtoui64(argv[5], NULL, 16);
	data_1 = _strtoui64(argv[6], NULL, 16);
	data_0 = _strtoui64(argv[7], NULL, 16);
	mask_3 = _strtoui64(argv[8], NULL, 16);
	mask_2 = _strtoui64(argv[9], NULL, 16);
	mask_1 = _strtoui64(argv[10], NULL, 16);
	mask_0 = _strtoui64(argv[11], NULL, 16);
#else
	data_3 = strtoull(argv[4], NULL, 16);
	data_2 = strtoull(argv[5], NULL, 16);
	data_1 = strtoull(argv[6], NULL, 16);
	data_0 = strtoull(argv[7], NULL, 16);
	mask_3 = strtoull(argv[8], NULL, 16);
	mask_2 = strtoull(argv[9], NULL, 16);
	mask_1 = strtoull(argv[10], NULL, 16);
	mask_0 = strtoull(argv[11], NULL, 16);
#endif

	if ( argc > 12 )
		tag = strtoul(argv[12], NULL, 16);
	else
		tag = 0;

	db &= 0xf;                      /*  4 bits */
	addr &= 0x1ffff;                /* 17 bits */
	data_0 &= 0xfffffffffLL;        /* 36 bits */
	data_1 &= 0xfffffffffLL;        /* 36 bits */
	data_2 &= 0xfffffffffLL;        /* 36 bits */
	data_3 &= 0xfffffffffLL;        /* 36 bits */
	mask_0 &= 0xfffffffffLL;        /* 36 bits */
	mask_1 &= 0xfffffffffLL;        /* 36 bits */
	mask_2 &= 0xfffffffffLL;        /* 36 bits */
	mask_3 &= 0xfffffffffLL;        /* 36 bits */


	/* Write the entry to the device */
	BUILD_144BIT_ARRAY(data, data_3, data_2, data_1, data_0);
	BUILD_144BIT_ARRAY(mask, mask_3, mask_2, mask_1, mask_0);
	res = tcam_write_cam_entry (dev_p_la,db, addr, data, mask, tag, valid );
	if ( res != 0 )
	{
		printf ("\twrite aborted abnormally with the following error code %d\n", res);
		return;
	}


	{
		char              mask_str[64];
		char              data_str[64];
		BUILD_144BIT_STRING(mask_str, mask);
		BUILD_144BIT_STRING(data_str, data);
		printf("\tWrite[%.5x] %s, data:%s mask:%s tag:0x%08x)\n", addr, valid ? "valid" : "invalid", data_str, mask_str, tag);
	}
}

static void
cmd_rentry(int argc, char *argv[])
{
	int               res;
	uint32_t          addr;
	uint32_t          db;
	uint32_t          tag;
	uint8_t           mask[18];
	uint8_t           data[18];
	char              mask_str[64];
	char              data_str[64];
	int              state;


	if (argc < 3 || argv[1][0] == '?')
	{
		printf("rentry <db> <addr>\n\
		db = 4-bit value selecting which database contains the entry to read\n\
		addr = 19-bit value selecting which memory location to read from (NOT DB relative)\n\
		       displays the 144-bit contents of the given CAM memory space location,\n\
		       including the associated tag and the 144-bit mask in use.\n");
		return;
	}

	db = strtoul(argv[1], NULL, 16);
	addr = strtoul(argv[2], NULL, 16);

	addr &= 0x1ffff;            /* 17 bits */
	db &= 0xf ;                 /* 4 bits */


	/* First, Mask and Data */
	
	res = tcam_read_cam_entry (dev_p_la,db, addr,data,mask,&tag,&state);
	if ( res != 0 )
	{
		printf ("\tread aborted abnormally with the following error code %d\n", res);
	}
	else
	{
	
		BUILD_144BIT_STRING(mask_str, mask);
		BUILD_144BIT_STRING(data_str, data);

		/* Pretty-print all aspects of the entry read */
		printf("\tEntry[%05x] Value | %s\n"
		       "\t             Mask  | %s\n"
			   "\t             Sram  | 0x%08X\n"
			   "\t             State | %s\n",
			   addr, data_str, mask_str, tag, state ? "valid  " : "invalid");
	}
}
static void
cmd_decode(int argc, char *argv[])
{
	int               res;
	uint32_t          addr;
	uint32_t          db;
	uint32_t          tag;
	uint8_t           mask[18];
	uint8_t           data[18];
	int              state;


	if (argc < 3 || argv[1][0] == '?')
	{
		printf("decode <db> <addr>\n\
			db = 4-bit value selecting which database contains the entry to read\n\
			addr = 19-bit value selecting which memory location to read from (NOT DB relative)\n\
			displays the contents of a TCAM entry, decoded into its respective fields.\n");
			return;
	}

	db = strtoul(argv[1], NULL, 16);
	addr = strtoul(argv[2], NULL, 16);

	addr &= 0x1ffff;            /* 17 bits */
	db &= 0xf ;                 /* 4 bits */


	/* First, Mask and Data */

	res = tcam_read_cam_entry (dev_p_la,db, addr, data, mask, &tag,&state);
	if ( res != 0 )
	{
		printf ("\tread aborted abnormally with the following error code %d\n", res);
	}
	else
	{
				
		
			/*BIT 108 - BIT 111 4 bits*/
			cam_entry_decode.service_level.data = ((data[4] & 0xf0) >> 4 );  
		
			/*The user tag. from the SRAM*/
			cam_entry_decode.user_tag = tag >> 4; 
		
			/*BIT 106 - BIT 107 2 bits */
			cam_entry_decode.lnh.data = ((data[4] & 0x0c) >> 2);
			
			/*BIT 128 - BIT 143 16 bits*/
			cam_entry_decode.src_local_id.data  = ((data[0] << 8) | (data[1]));
	
			/*BIT 112 - BIT 127 16 bits*/
			cam_entry_decode.dest_local_id.data = ((data[2] << 8) | (data[3]));	

			/*BIT98 - BIT105*/
			cam_entry_decode.opcode.data = ((data[4] & 0x03) << 6) | ((data[5] & 0xFC) >> 2);	 

			/*BIT 74 - BIT 97  24 bits*/
			cam_entry_decode.dest_qp.data = ((data[5] & 0x3) << 22) | (data[6] << 14) | (data[7] << 6) | ((data[8] & 0xfc) >> 2);
			
			/*BIT 50 - BIT 73  24 bits*/				
			cam_entry_decode.src_qp.data = (((data[8] & 0x03)) << 22) | (data[9] << 14) | (data[10] << 6) | ((data[11] & 0xfc) >> 2); 

			/*BIT 108 - BIT 111 4 bits*/
			cam_entry_decode.service_level.mask = ((mask[4] & 0xf0) >> 4);  
		
			/*The user tag. from the SRAM*/
			cam_entry_decode.user_tag = tag; 
			/*The action filed accept or reject*/
			cam_entry_decode.action = (tag & 0x4) >> 2; 
			/*The action filed accept or reject*/
			cam_entry_decode.user_class = (tag & 0x3); 
		
			/*BIT 106 - BIT 107 2 bits */
			cam_entry_decode.lnh.mask = ((mask[4] & 0x0c) >> 2);
			
			/*BIT 128 - BIT 143 16 bits*/
			cam_entry_decode.src_local_id.mask  = ((mask[0] << 8) | (mask[1]));
	
			/*BIT 112 - BIT 127 16 bits*/
			cam_entry_decode.dest_local_id.mask = ((mask[2] << 8) | (mask[3]));	

			/*BIT 98 - BIT 105 16 bits*/
			cam_entry_decode.opcode.mask = ((mask[4] & 0x03) << 6) | ((mask[5] & 0xFC) >> 2);	
			
			/*BIT 75 - BIT 97  24 bits*/
			cam_entry_decode.dest_qp.mask = ((mask[5] & 0x3) << 22) | (mask[6] << 14) | (mask[7] << 6) | ((mask[8] & 0xfc) >> 2);
			
			/*BIT 50 - BIT 74  24 bits*/
			cam_entry_decode.src_qp.mask = ((mask[8] & 0x03) << 22) | (mask[9] << 14) | (mask[10] << 6) | ((mask[11]& 0xfc) >> 2); 


			fprintf( stdout, "User tag: %d, action: %s, steering: %d \n\n",
                        	cam_entry_decode.user_tag, (cam_entry_decode.action == 0)?"through":"drop" , cam_entry_decode.user_class );
                	fprintf( stdout, "service_level data: 0x%01x, service_level mask: 0x%01x \n\n",
                        	cam_entry_decode.service_level.data,cam_entry_decode.service_level.mask );
                	fprintf( stdout, "lnh.data: 0x%01x, lnh.mask: 0x%01x \n\n",
                        	cam_entry_decode.lnh.data, cam_entry_decode.lnh.mask);
                	fprintf(stdout, "src_local_id.data: 0x%04x, src_local_id.mask: 0x%04x \n\n",
                        	cam_entry_decode.src_local_id.data, cam_entry_decode.src_local_id.mask);
                	fprintf( stdout, "dest_local_id.data: 0x%04x, dest_local_id.mask: 0x%04x \n\n",
                        	cam_entry_decode.dest_local_id.data, cam_entry_decode.dest_local_id.mask);
                	fprintf( stdout, "opcode.data: 0x%01x, opcode.mask: 0x%01x \n\n",
                        	cam_entry_decode.opcode.data, cam_entry_decode.opcode.mask);
                	fprintf( stdout, "dest_qp.data: 0x%06x, dest_qp.mask: 0x%06x \n\n",
                        	cam_entry_decode.dest_qp.data, cam_entry_decode.dest_qp.mask);
        		/* DETH Header classification fields */
                	fprintf(stdout, "src_qp.data: 0x%06x, src_qp.mask: 0x%06x \n\n",
                        	cam_entry_decode.src_qp.data, cam_entry_decode.src_qp.mask);


	
	}
}


static void
cmd_read_tag(int argc, char *argv[])
{
	int               res;
	uint32_t          addr;
	uint32_t          db;
	uint32_t          tag;
	uint32_t 	sram_entry[4];

	if (argc < 3 || argv[1][0] == '?')
	{
		printf("rtag <db> <addr>\n\
			db = 4-bit value selecting which database contains the entry to read\n\
			addr = 19-bit value selecting which memory location to read from (NOT DB relative)\n\
			displays the 32-bit tag associated with the given database entry.\n");
			return;
	}

	db = strtoul(argv[1], NULL, 16);
	addr = strtoul(argv[2], NULL, 16);

	addr &= 0x1ffff;            /* 17 bits */
	db &= 0xf ;                 /* 4 bits */


	/* First, Mask and Data */

	res = idt75k_read_sram(dev_p_la, db, addr, sram_entry);
	tag = sram_entry[0];
	if ( res != 0 )
	{
		printf ("\tread aborted abnormally with the following error code %d\n", res);
	}
	else
	{
		/* Pretty-print all aspects of the entry read */
		printf("\tEntry[%.5x] tag:0x%08x\n", addr, tag);
	}
}




static void
cmd_write_tag(int argc, char *argv[])
{
	int               res;
	uint32_t          addr;
	uint32_t          db;
	uint32_t          tag;
	idt75k_write_sram_t   wr_sram;

	if (argc < 4 || argv[1][0] == '?')
	{
		printf("wtag <db> <addr> <tag>\n\
			db = 4-bit value selecting which database contains the entry to read\n\
			addr = 19-bit value selecting which memory location to read from (NOT DB relative)\n\
			tag = 32-bit value to write into the tag\n\
			writes the 32-bit tag associated with the given database entry.\n");
			return;
	}

	db = strtoul(argv[1], NULL, 16);
	addr = strtoul(argv[2], NULL, 16);
	tag = strtoul(argv[3], NULL, 16);

	addr &= 0x1ffff;            /* 17 bits */
	db &= 0xf;                  /* 4 bits */

	
	if ( addr > (128 * 1024) )
	{	
		printf("Address out of range\n");
		return ;
	}
	if ( db > 15 )
	{	
		printf("DB out of range\n");
		return ;
	}	

	memset (&wr_sram, 0x00, sizeof(wr_sram));
	wr_sram.db_num = db;
	//convert address into 72 bit width addressing 
	wr_sram.address = (addr << 2);
	wr_sram.sram_entry[0] = tag;
	
	/* First, Mask and Data */

        wr_sram.sram_entry[0] = 0x00000000;
       
        res = idt75k_write_sram(dev_p_la, wr_sram.db_num, wr_sram.address, wr_sram.sram_entry);
	if ( res != 0 )
		printf("\twrite aborted abnormally with the following error code %d\n", res);
	wr_sram.sram_entry[0] = tag;	
	res = idt75k_write_sram(dev_p_la, wr_sram.db_num, wr_sram.address, wr_sram.sram_entry);

	if ( res != 0 )
		printf ("\twrite aborted abnormally with the following error code %d\n", res);
		
}



static void
cmd_read_sram(int argc, char *argv[])
{
	idt75k_read_sram_t  rd_sram;
	int err;


	if (argc < 3 || argv[1][0] == '?')
	{
		printf("rsram <db> <addr>\n\
	db = 4-bit value selecting which database contains the entry to read\n\
	addr = 19-bit value selecting which memory location to read from (NOT DB relative)\n\
	displays the 32-bit tag associated with the given database entry.\n");
		return;
	}

	memset (&rd_sram, 0x00, sizeof(rd_sram));

	rd_sram.db_num = strtoul(argv[1], NULL, 16);
	rd_sram.address = strtoul(argv[2], NULL, 16);

	rd_sram.address &= 0x1ffff;            /* 17 bits */
	rd_sram.db_num &= 0xf;                 /* 4 bits */

	if ( (err = idt75k_read_sram(dev_p_la, rd_sram.db_num, rd_sram.address, rd_sram.sram_entry) ) == 1)
	{
		printf ("\tread aborted abnormally with the following error code %d\n", errno);
	}
	else
	{
		/* Pretty-print all aspects of the entry read */
		printf("\tEntry[%.5x] tag: 0x%08x 0x%08x 0x%08x 0x%08x\n", rd_sram.address, rd_sram.sram_entry[0], rd_sram.sram_entry[1], rd_sram.sram_entry[2], rd_sram.sram_entry[3] );
	}
}

static void
cmd_read_ident(int argc, char *argv[])
{

	int err;
	uint32_t value;
	uint32_t addr;
	int ident_register_no;

	ident_register_no = strtoul(argv[1], NULL, 16);
	if (argc < 2 || argv[1][0] == '?' || (ident_register_no < 1) || (ident_register_no > 2))
	{
		printf("ident <n> \n\
			n = 1 or 2 select which ident register to get \n\
			displays the contents of ident register 1 or 2.\n");
		return;
	}

	addr = (ident_register_no == 1 ) ? NSE_IDENT1_ADDR : NSE_IDENT2_ADDR;
	if ( (err = idt75k_read_csr(dev_p_la, addr, &value)) != 0 )
	{
		dagutil_warning("read ident failed errorno:%d, addr=0x%x, value=0x%x\n",errno,addr, value);
		return;
	}
	else
	{
		/* Pretty-print all aspects of the entry read */
		printf("\t IDENT REGISTER %d value: 0x%08x at addr: 0x%08x\n", ident_register_no, value, addr);
	}
}




static void
cmd_write_sram(int argc, char *argv[])
{

	idt75k_write_sram_t wr_sram;
	int err;


	if (argc < 7 || argv[1][0] == '?')
	{
		printf("wsram <db> <addr> <data_0> <data_1> <data_2> <data_3>\n\
			db = 4-bit value selecting which database contains the entry to read\n\
			addr = 19-bit value selecting which memory location to read from (NOT DB relative)\n\
			data_0 = 32-bit value to write into the first byte the asscoiated sram\n\
			data_0 = 32-bit value to write into the first byte the asscoiated sram\n\
			data_0 = 32-bit value to write into the first byte the asscoiated sram\n\
			writes the four 32-bit values into SRAM associated with a DB entry.\n");
		return;
	}

	wr_sram.db_num = strtoul(argv[1], NULL, 16);
	wr_sram.address = strtoul(argv[2], NULL, 16);

	memset (&wr_sram, 0x00, sizeof(wr_sram));

	wr_sram.address &= 0x1ffff;            /* 17 bits */
	wr_sram.db_num &= 0xf;                 /* 4 bits */

        wr_sram.sram_entry[0] = 0;
	wr_sram.sram_entry[1] = 0;
	wr_sram.sram_entry[2] = 0;
	wr_sram.sram_entry[3] = 0;

        if ( ( err = idt75k_write_sram(dev_p_la, wr_sram.db_num, wr_sram.address, wr_sram.sram_entry) ) == 1)
	{
	      printf ("\twrite aborted abnormally with the following error code %d\n", errno);
	}

        wr_sram.sram_entry[0] = strtoul(argv[3], NULL, 16);
	wr_sram.sram_entry[1] = strtoul(argv[4], NULL, 16);
	wr_sram.sram_entry[2] = strtoul(argv[5], NULL, 16);
	wr_sram.sram_entry[3] = strtoul(argv[6], NULL, 16);
	
       
	if ( ( err = idt75k_write_sram(dev_p_la, wr_sram.db_num, wr_sram.address, wr_sram.sram_entry) ) == 1)
	{
		printf ("\twrite aborted abnormally with the following error code %d\n", errno);
	}
}


static void
cmd_copy_sram(int argc, char *argv[])
{
	
	idt75k_copy_sram_t  cp_sram;
	int err;


	if (argc < 4 || argv[1][0] == '?')
	{
		printf("wsram <db> <src_addr> <dst_addr>\n\
			db = 4-bit value selecting which database contains the entry to read\n\
			src_addr = 19-bit value selecting which memory location to read from (NOT DB relative)\n\
			dst_addr = 19-bit value selecting which memory location to write to (NOT DB relative)\n");
		return;
	}


	memset (&cp_sram, 0x00, sizeof(cp_sram));

	cp_sram.db_num   = strtoul(argv[1], NULL, 16);
	cp_sram.src_addr = strtoul(argv[2], NULL, 16) & 0x0007FFFF;
	cp_sram.dst_addr = strtoul(argv[3], NULL, 16) & 0x0007FFFF;



	if ( ( err = idt75k_copy_sram(dev_p_la, cp_sram.db_num, cp_sram.dst_addr, cp_sram.src_addr) ) == 1 )
	{
		printf ("\tcopy aborted abnormally with the following error code %d\n", errno);
	}

};


static void
cmd_search(int argc, char *argv[])
{
	uint32_t db;
	uint32_t gmr;
	bool     hit;
	uint32_t tag;
	uint32_t addr;
	uint8_t  data[18];
	uint64_t data_0;
	uint64_t data_1;
	uint64_t data_2;
	uint64_t data_3;
	int      res;


	if (argc < 7 || argv[1][0] == '?')
	{
		printf("search <db> <gmr> <data_3> <data_2> <data_1> <data_0>\n\
		db = 4-bit value selecting which database to search in\n\
		gmr = 5-bit value selecting which GMR to mask the data against\n\
		data_3 = Upper  36-bit value to lookup\n\
		data_2 = Third  36-bit value to lookup\n\
		data_1 = Second 36-bit value to lookup\n\
		data_0 = Lower  36-bit value to lookup\n");
		return;
	}

	db = strtoul(argv[1], NULL, 16);
	gmr = strtoul(argv[2], NULL, 16);
#ifdef _WIN32
	data_3 = _strtoui64(argv[3], NULL, 16);
	data_2 = _strtoui64(argv[4], NULL, 16);
	data_1 = _strtoui64(argv[5], NULL, 16);
	data_0 = _strtoui64(argv[6], NULL, 16);
#else
	data_3 = strtoull(argv[3], NULL, 16);
	data_2 = strtoull(argv[4], NULL, 16);
	data_1 = strtoull(argv[5], NULL, 16);
	data_0 = strtoull(argv[6], NULL, 16);
#endif

	db &= 0xf;                      /*  4 bits */
	gmr &= 0x1f;                    /*  5 bits */
	data_0 &= 0xfffffffffLL;        /* 36 bits */
	data_1 &= 0xfffffffffLL;        /* 36 bits */
	data_2 &= 0xfffffffffLL;        /* 36 bits */
	data_3 &= 0xfffffffffLL;        /* 36 bits */

	BUILD_144BIT_ARRAY(data, data_3, data_2, data_1, data_0);


	res = tcam_lookup(dev_p_la,db, data, gmr, &hit, &addr, &tag);
	if ( res != 0 )
	{
		printf ("\tsearch aborted abnormally with the following error code %d\n", res);
	}
	else
	{
		if (hit)
			printf("hit  index:%d  tag:%x\n", (addr >> 2), tag);
		else
			printf("miss \n");

	}
}



static void
cmd_read_db(int argc, char *argv[])
{
	uint32_t db;
	uint32_t addr;
	uint32_t db_conf1;
	uint32_t db_conf2;
	uint32_t db_conf3;
	int      res;


	if (argc < 2 || argv[1][0] == '?')
	{
		printf("rdb <db>\n\
		db = 4-bit value selecting which database to read the configuration details\n");
		return;
	}

	db = strtoul(argv[1], NULL, 16);

	db &= 0xf;
	addr = (0x0100 | (db << 4));

	res =  idt75k_read_csr(dev_p_la, addr,  &db_conf1);

	if ( res != 0 )
	{
		printf ("\treading DB_CONF[0x%04X] aborted abnormally with the following error code %d\n", addr, res);
		return;
	}

	addr = (0x0101 | (db << 4));
	
	res =  idt75k_read_csr(dev_p_la, addr,  &db_conf2);
	if ( res != 0 )
	{
		printf ("\treading DB_CONF[0x%04X] aborted abnormally with the following error code %d\n", addr, res);
		return;
	}

	addr = (0x0102 | (db << 4));
	
	res =  idt75k_read_csr(dev_p_la, addr,  &db_conf3);
	if ( res != 0 )
	{
		printf ("\treading DB_CONF[0x%04X] aborted abnormally with the following error code %d\n", addr, res);
		return;
	}
	

	printf("\tDB_CONF1=0x%08X\n", db_conf1);
	printf("\tDB_CONF2=0x%08X\n", db_conf2);
	printf("\tDB_CONF3=0x%08X\n", db_conf3);

}


static void
cmd_write_db(int argc, char *argv[])
{
	uint32_t db;
	uint32_t addr;
	uint32_t db_conf1;
	uint32_t db_conf2;
	uint32_t db_conf3;
	int      res;


	if (argc < 5 || argv[1][0] == '?')
	{
		printf("wdb <db> <config_1> <config_2> <config_3>\n\
		db = 4-bit value selecting which database to read the configuration details\n\
		config_1 = 32-bit value to write into the first configuration register\n\
		config_2 = 32-bit value to write into the second configuration register\n\
		config_3 = 32-bit value to write into the third configuration register\n");
		return;
	}

	db = strtoul(argv[1], NULL, 16);
	db &= 0xf;
	db_conf1 = strtoul(argv[2], NULL, 16);
	db_conf2 = strtoul(argv[3], NULL, 16);
	db_conf3 = strtoul(argv[4], NULL, 16);


	addr = (0x0100 | (db << 4));
	
	res =  idt75k_write_csr(dev_p_la, addr,  db_conf1);
	if ( res != 0 )
	{
		printf ("\twriting DB_CONF[0x%04X] aborted abnormally with the following error code %d\n", addr, res);
		return;
	}

	addr = (0x0101 | (db << 4));

	res =  idt75k_write_csr(dev_p_la, addr,  db_conf2);
	if ( res != 0 )
	{
		printf ("\twriting DB_CONF[0x%04X] aborted abnormally with the following error code %d\n", addr, res);
		return;
	}

	addr = (0x0102 | (db << 4));
	
	res =  idt75k_write_csr(dev_p_la, addr,  db_conf3);
	if ( res != 0 )
	{
		printf ("\twriting DB_CONF[0x%04X] aborted abnormally with the following error code %d\n", addr, res);
		return;
	}
	
}




typedef struct cmd
{
	char *name;
	void (*func) (int argc, char *argv[]);

} cmd_t;


static cmd_t cmdtab[] =
{
	{"help", cmd_help},
	{"?", cmd_help},
	{"quit", cmd_quit},
	{"verbose", cmd_verbose},
	{"reset", cmd_reset},
	{"init", cmd_init},
	{"flush", cmd_flush},
	{"rcsr", cmd_csr},
	{"wcsr", cmd_csr},
	{"rdb", cmd_read_db},
	{"wdb", cmd_write_db},
	{"rtag", cmd_read_tag},
	{"wtag", cmd_write_tag},
	{"rsram", cmd_read_sram},
	{"wsram", cmd_write_sram},
	{"cpsram", cmd_copy_sram},
	{"rgmr", cmd_gmr},
	{"wgmr", cmd_gmr},
	{"rsmt", cmd_smt},
	{"wsmt", cmd_smt},
	{"wentry", cmd_wentry},
	{"sentry", cmd_sentry},
	{"rentry", cmd_rentry},
	{"search", cmd_search},
	{"test", cmd_test},
	{"production_test",cmd_production_test},
	{"decode", cmd_decode},
	{"fenable", cmd_fenable},
	{"finit", cmd_finit},
	{"frst", cmd_frst},
	{"fstatus", cmd_fstatus},
	{"llread", cmd_llread},
	{"llbread", cmd_llbread},
	{"mlread", cmd_mlread},
	{"llshotgun", cmd_llshotgun},
	{"llwrite", cmd_llwrite},
	{"llset", cmd_llset},
	{"llshow", cmd_llshow},
	
	{"frcsr", cmd_frcsr},
	{"fwcsr", cmd_fwcsr},
	{"fsvld", cmd_fsetclrvld},
	{"fcvld", cmd_fsetclrvld},
	{"fsearch", cmd_fsearch},
	{"frentry", cmd_frentry},
	{"ident", cmd_read_ident},
	
	{"interface", cmd_interface},

	{NULL, 0},
};


static void
infinicam(void)
{
	char prompt[64];
	char* line;
	char* tok;
	char* remain;
	cmd_t* cmdp;
	char** ap;
	char* argv[MAXARGV];
	int temp;

	for (;;)
	{
		(void) sprintf(prompt, "hydracam:%d> ", g_uHistoryCount + 1);
		
		line = dgetline(prompt);
		if (line == NULL)
			break;

		/*
		 * It's a bit of a mess here, since we would like to
		 * parse the line only once for spaces and the first
		 * token but we need the line in complete form for
		 * history and shell commands.
		 */
		remain = line + strspn(line, g_whitespace);
		if ((tok = strchr(remain, '#')) != NULL)
			*tok = '\0';

		if (*remain == '\0')
			goto done;

#if HAVE_EDITLINE
		add_history(remain);
#endif /* HAVE_EDITLINE */
		g_uHistoryCount++;
		for (tok = strsep(&remain, ";"); tok != NULL; tok = strsep(&remain, ";"))
		{
			tok += strspn(tok, g_whitespace);
			switch (*tok)
			{
				case '!':
					temp = system(tok + 1);
					continue;
					
				case '\0':
					continue;
					
				default:
					break;
			}

			for (ap = argv; (*ap = strsep(&tok, g_whitespace)) != NULL;)
			{
				if (**ap != '\0')
					if (++ap >= &argv[MAXARGV])
					{
						*--ap = NULL;
						dagutil_warning("too many arguments for command %s\n", argv[0]);
						break;
					}
			}


			for (cmdp = cmdtab; cmdp->name != NULL; cmdp++)
			{
				if (0 == strncmp(argv[0], cmdp->name, strlen(argv[0])))
				{
					(*cmdp->func) (ap - argv, argv);
					break;
				}
			}

			if (cmdp->name == NULL)
				printf("%s: unknown command\n", argv[0]);
		}

	done:
		dagutil_free(line);
	}
}

/*
 * This is a wrapper around readline which cannot handle changing
 * stdin in any way.
 */
static char *
dgetline(char *prompt)
{
	static char *buf;

	if (1 == g_uReadFromKeyboard)
	{
		if (0 < strlen(g_command_buf))
		{
			/* Use the -c parameter from the command line */
			if (0 == g_uHaveReadCommandLine)
			{
				g_uHaveReadCommandLine = 1;
				
				/* Return a malloc()d string so all strings returned by dgetline are malloc()d. */
				return (char*) dagutil_strdup((const char*) g_command_buf);
			}
			else
			{
				/* Already read the command line option */
				return NULL;
			}
		}
		else
		{
#if HAVE_EDITLINE
			/* Get the next line from readline(). */
			return readline(prompt);
#else
			/* Get the next line via standard I/O. */
			printf("%s", prompt);
#endif /* HAVE_EDITLINE */
		}
	}

	/* Note: do _not_ prompt or echo here. */
	//modified by karthik
	buf = (char*)dagutil_malloc(FILENAME_BUFSIZE);
	if (buf == NULL)
		dagutil_panic("dgetline: out of memory\n");

	return fgets(buf, FILENAME_BUFSIZE, stdin);
}
/*Test InfiniCam*/
/*InfiniCam Test 1 */
void infinicam_test_1(idt75k_dev_t *dev_p)
{
	const uint32_t    db = 15;
        int               res;
        uint8_t           mask[72];//mask[18];
        uint8_t           data[72];//data[18];
	uint32_t 	  ad_value[4];
        int               failures = 0;
	uint32_t          i = 0;

	
        /*The i is used to address the TCAM entries in 144 bit word width*/
	for (i=0; i<SIZE_128K; i++)
        {
                if ( (i & 0x0FFF) == 0x0000 )
                {
                        tcam_set_database_sectors(dev_p, db, (1 << (i >> 12)));
			
                        printf (".");
                        fflush (stdout);
                }

                BUILD_144BIT_ARRAY(data, (uint64_t)i, 0LL, 0LL, 0LL);
                BUILD_144BIT_ARRAY(mask, (uint64_t)i, 0LL, 0LL, 0LL);

		ad_value[0] = i;
                res = tcam_write_cam_entry(dev_p,db, i, data, mask, ad_value[0],1);
                if ( res != 0 )
                        failures++;
        }
	printf (" done\n\twrite failures: %d\n", failures);
}
/*InfiniCam Test 2*/
void infinicam_test_2(idt75k_dev_t *dev_p)
{


        const uint32_t    db = 15;
        int               res;
        uint8_t           mask[18];
        uint8_t           data[18];
        int              state;
        uint32_t          tag;
        uint64_t          data_0, data_1, data_2, data_3;
        uint64_t          mask_0, mask_1, mask_2, mask_3;
        int               data_failures = 0;
        int               mask_failures = 0;
        int               tag_failures  = 0;
	uint32_t 	  i;
        /* perform test 1 to populate the tcam */
        infinicam_test_1 (dev_p);

	/* read back the values */
        for (i=1; i<SIZE_128K; i++)
        {
                if ( (i & 0x0FFF) == 0x0000 )
                {
                        tcam_set_database_sectors(dev_p, db, (1 << (i >> 12)));

                        printf ("setting db 15 sectors : 0x%08X\n", (1 << (i >> 12)));
                        printf (".");
                        fflush (stdout);
                }
		
                res = tcam_read_cam_entry(dev_p,db, i, data,mask,&tag,&state);
                if ( res != 0 )
                {
                        printf ("\tread aborted abnormally when reading entry %d, with the following error code %d\n", i, res);
                        break;
                }

                
                EXTRACT_64BIT_VALUES(data, data_0, data_1, data_2, data_3);
                EXTRACT_64BIT_VALUES(mask, mask_0, mask_1, mask_2, mask_3);

                /* check the values */
                if ( (data_0 != i) || (data_1 != 0) || (data_2 != 0) || (data_3 != 0) )
                        data_failures++;
                if ( (mask_0 != i) || (mask_1 != 0) || (mask_2 != 0) || (mask_3 != 0) )
                        mask_failures++;
                if (tag != i )
                        tag_failures++;
        }

        printf (" done\n\tread mask failures: %d\n"
                                   "\tread data failures: %d\n"
                                   "\ttag data failures:  %d\n", mask_failures, data_failures, tag_failures);
}

/**
 * Continously writes random values into sequential TCAM entries, this is designed to
 * simulate what an actual loading sequence would be.
 *
 *
 *
 */
void infinicam_test_3 (idt75k_dev_t *dev_p)
{
	const uint32_t    db = 15;
	int               res;
	uint8_t           mask_out[18], mask_in[18];
	uint8_t           data_out[18], data_in[18];
	int              state;
	uint32_t          tag_in, tag_out;
	int               data_failures = 0;
	int               mask_failures = 0;
	int               tag_failures  = 0;
	int               tag_ok  = 0;
	int               state_failures  = 0;
	char              mask_str[64];
	char              data_str[64];
	uint64_t data_0,data_1,data_2,data_3;
	
	uint32_t i;


	printf ("\tperforming test .");
tag_in = 0x77;	
	//skipping 0 
tag_out=0x0;	
	for ( i=0; i<SIZE_128K; i++)
	{
		if ( (i & 0x0FFF) == 0x0000 )
		{
                        tcam_set_database_sectors(dev_p, db, (1 << (i >> 12)));
                        printf ("setting db 15 sectors : 0x%08X\n", (1 << (i >> 12)));
                        printf (".");
			printf (".");
			fflush (stdout);
		}


		/* generate some random valuesand load them into the TCAM */
		BUILD_144BIT_ARRAY(data_out,(uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()),
		                            (uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()),
		                            (uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()),
		                            (uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()));
		BUILD_144BIT_ARRAY(mask_out,(uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()),
		                            (uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()),
		                            (uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()),
		                            (uint64_t)(((uint64_t)mrand48()) << 32) | ((uint64_t)mrand48()));

                res = tcam_write_cam_entry(dev_p,db, i, data_out, mask_out, tag_out,1);
		if ( res != 0 )
		{
			printf ("\twrite aborted abnormally when writing entry %d, with the following error code %d\n", (i & 0x0FFF), res);
			break;
		}
              
		/* read back the entry and verify */
                res = tcam_read_cam_entry(dev_p,db, i, data_in,mask_in,&tag_in,&state);
		if ( res != 0 )
		{
			printf ("\tread aborted abnormally when reading entry %d, with the following error code %d\n", (i & 0x0FFF), res);
			break;
		}


		/* check the values */
		if ( memcmp(data_out, data_in, 16) != 0 )
		{
			printf("data_out: ");
			for(i =0; i<16; i++)
				printf ("%02x ",data_out[i]);
			printf("\n");
			printf("data_in : ");
			for(i =0; i<16; i++)
				printf ("%02x ",data_in[i]);
			printf("\n");
		BUILD_144BIT_STRING(mask_str, mask_in);
		BUILD_144BIT_STRING(data_str, data_in);
                EXTRACT_64BIT_VALUES(data_in, data_0, data_1, data_2, data_3);
		

		/* Pretty-print all aspects of the entry read */
		printf("\tEntry[%05x] Value | %s\n"
		       "\t             Mask  | %s\n"
			   "\t             Sram  | 0x%08X\n"
			   "\t             State | %s\n",
			   i, data_str, mask_str, tag_in, state ? "valid  " : "invalid");
			
			data_failures++;
		printf("extracted 64bit data: %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n",data_0,data_1,data_2,data_3);
		}	
		
		if ( memcmp(mask_out, mask_in, 16) != 0 )
			mask_failures++;
		if ( tag_in != tag_out )
			{
				printf ("ADDRESS: %d TAG: 0x%08x -> 0x%08x\n",(i), tag_out,tag_in);
				tag_failures++;
			}
		else 
			{
				tag_ok++;
			};
		if ( state != true )
			state_failures++;
	}

	printf (" done\n\tread mask failures: %d\n"
				   "\tread data failures: %d\n"
				   "\ttag data failures:  %d oks: %d \n"
				   "\tstate failures:     %d\n", mask_failures, data_failures, tag_failures, tag_ok, state_failures);
}


/*Test InfiniCam*/
/*InfiniCam Test 1 */
void infinicam_test_4(idt75k_dev_t *dev_p)
{
	const uint32_t    db = 1;
        int               res;
        uint8_t           mask[72];
        uint8_t           data[72];
	uint32_t 	  ad_value[4];
        int               failures = 0;
	uint32_t          i = 0;
	uint32_t          gmr = 0;
	uint32_t tag = 0;
	bool     hit = false;
	uint32_t addr = 0;
	int hit_count = 0;
	int miss_count = 0;
	for (i = 0;i < 18;i++)
	{
		mask[i] = 0xff;	
	}
	for (i=0; i<SIZE_128K; i++)
        {
                BUILD_144BIT_ARRAY(data, (uint64_t)i, 0LL, 0LL, 0LL);

		ad_value[0] = i;
                res = tcam_write_cam_entry(dev_p,db, i, data, mask, ad_value[0],1);
                if ( res != 0 )
                        failures++;

		
		res = tcam_lookup(dev_p,db, data, gmr, &hit, &addr, &tag);
		if ( res != 0 )
		{
			printf ("\tsearch aborted abnormally with the following error code %d\n", res);
		}
		else
		{
			if (hit)
			{
				hit_count++;
			}
			else
			{
				miss_count++;
				
			}

		}
	}
	printf (" done\n\tHit Count: %d Miss Count: %d\n",hit_count,miss_count);
}

#ifndef ENDACE_UNIT_TEST
int
main(int argc, const char* const * argv)
{
	return infinicam_main(argc, (char**) argv);
}
#endif /* ENDACE_UNIT_TEST */
