/*
 * 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: bfscam.c 11429 2009-06-23 07:14:05Z 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/bfs_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: bfscam.c 11429 2009-06-23 07:14:05Z vladimir $";
static const char* const kRevisionString = "$Revision: 11429 $";

#define BUILD_384BIT_ARRAY(a, d0 ,d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11)  \
a[0]  = (uint32_t)((d0));  \
a[1]  = (uint32_t)((d1));  \
a[2]  = (uint32_t)((d2));  \
a[3]  = (uint32_t)((d3));  \
a[4]  = (uint32_t)((d4));  \
a[5]  = (uint32_t)((d5));  \
a[6]  = (uint32_t)((d6));  \
a[7]  = (uint32_t)((d7));  \
a[8]  = (uint32_t)((d8));  \
a[9]  = (uint32_t)((d9));  \
a[10] = (uint32_t)((d10)); \
a[11] = (uint32_t)((d11)); \

	


#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.*/



BFSStateHeader *header;

/* 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 
 */
enum {
	
	CLA_HELP,
	CLA_VERSION,
	CLA_VERBOSE,
	CLA_DEVICE,
	CLA_INTERACTIVE,
	CLA_HISTFILE,
	CLA_NOHIST,
	CLA_RCFILE,
	CLA_CMDLINE,
	CLA_EMULATION
};

/**
 * Continously writes random values into sequential TCAM entries, this is designed to
 * simulate what an actual loading sequence would be.
 */

/**
 * Tests for production testing
 */

static void
print_version(void)
{
	printf("bfscam (%s) %s\n", kDagReleaseVersion, kRevisionString);
}
/*****************************************************************************/
static void
print_usage(ClArgPtr clarg)
{
	print_version();
	printf("bfscam - Endace Infiniband Project TCAM shell.\n");
	printf("Usage: bfscam [-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 bfscam(void);

int
bfscam_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("bfscam");

	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
	 */

	header = (BFSStateHeader*)malloc(sizeof(BFSStateHeader));
	
	memset(header,0,sizeof(BFSStateHeader));

	/* 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 */
			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, DAG_REG_BFSCAM, regs);
			if (count < 1)
			{
		 		dagutil_panic("dag_reg_find failed: \n");	
			}
	  		header-> bfs_register_base = (uint32_t*) (g_iom_p + regs[0].addr);
	#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);
		printf("Emulation Enabled supports only one LA interface \n");
	}
	/*
	 * Initialization
	 */
	if (1 == g_uInteractive)
	{
		int safed;
		FILE *fp;

		/* Display short greeting */
		printf("bfscam 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
		{
			bfscam();
			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 */

	bfscam();
	
	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;
	}
	/*
	 * 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\
	init         - Initialises the CAM. Performs many operations until the cam is ready for learning and searching.\n\
	{rd/sw}db    - reads/swaps the BFS TCAM BANKS (a.k.a DATABASES.).\n\
	{rw}entry    - reads/writes a 389-bit entry in the CAM memory space.\n\
\n\
	{rw}entry_ex - reads/writes a 389-bit entry in the CAM memory space and colour in SRAM.\n\
\n\
	{rw}tag      - 	reads/writes a 16-bit colour entry in the SRAM.\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\
\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_init(int argc, char *argv[])
{
	int res;
	res = bfs_cam_initialise(header);
	if ( res != 0 )
	{
		printf("Definately there is some problem \n");
	}	

	
}


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:
			printf("cmd_test case 1 \n");
			break;
		case 2:
			printf("cmd_test case 1 \n");
			break;
		case 3:
			printf("cmd_test case 1 \n");
			break;

		case 4:
			printf("cmd_test case 1 \n");
			break;

		case 5 :
			printf("cmd_test case 1 \n");
			break;

		case 6 :
			printf("cmd_test case 1 \n");
			break;
		case 7 :
			printf("cmd_test case 1 \n");
			break;
		case 8 :
			printf("cmd_test case 1 \n");
			break;
		default:
			printf ("\tinvalid test number, test aborted\n");
			break;
	}

	return;
}
static void
cmd_wentry(int argc, char *argv[])
{
	int      res;
	uint32_t addr;
	uint32_t db;
	uint32_t  data[13];
	uint32_t  mask[13];
	int temp; 
	
	if (argc < 3 || argv[1][0] == '?')
	{
		printf("wentry <db> <addr>\n\
				db = 1-bit value selecting which database contains the entry to read\n\
				addr = 16-bit value selecting which memory location to read from.(NOT DB relative)");
		return;
	}
	
	printf("Please enter 13 32-bit values of data you want to enter \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7],&data[8],&data[9],&data[10],&data[11],&data[12]);
	
	printf("Please enter 13 32-bit values of mask you want to enter mask \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&mask[0],&mask[1],&mask[2],&mask[3],&mask[4],&mask[5],&mask[6],&mask[7],&mask[8],&mask[9],&mask[10],&mask[11],&mask[12]);
	

	db     = strtoul(argv[1], NULL, 16);
	addr   = strtoul(argv[2], NULL, 16);
	
	addr &= 0xffff;            /* 16 bits */
	db &= 0x1 ;                 /* 1 bits */
	
	/*Here we are not using the wrapper funcitons.We are directly using the F/W interface.
	 *The database is the bank and address are absolute values*/
	
	res = write_bfscam_value(header,db,addr,data,mask);
	if ( res != 0 )
	{
		printf ("\twrite aborted abnormally with the following error code %d\n", res);
		return;
	
	}else
	{
		printf("Data and Mask Written to database(BANK) %d address %d \n",db,addr);
	}
}
static void
cmd_wentry_ex(int argc, char *argv[])
{
	int      res;
	uint32_t addr;
	uint32_t db;
	uint32_t colour;
	uint32_t  data[13];
	uint32_t  mask[13];
	int temp; 

	if (argc < 4 || argv[1][0] == '?')
	{
		printf("wentry_ex <db> <addr> <colour>\n\
				db = 1-bit value selecting which database contains the entry to read\n\
				addr = 16-bit value selecting which memory location to read from.(NOT DB relative)\n\
				colour = SRAM-colour value to be written");
		return;
	}

	
	printf("Please enter 13 32-bit values of data you want to enter \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7],&data[8],&data[9],&data[10],&data[11],&data[12]);
	
	printf("Please enter 13 32-bit values of mask you want to enter mask \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&mask[0],&mask[1],&mask[2],&mask[3],&mask[4],&mask[5],&mask[6],&mask[7],&mask[8],&mask[9],&mask[10],&mask[11],&mask[12]);
	
	db     = strtoul(argv[1], NULL, 16);
	addr   = strtoul(argv[2], NULL, 16);
	colour = strtoul(argv[3], NULL, 16);

	addr &= 0xffff;            /* 16 bits */
	db &= 0x1 ;                 /* 1 bits */
	colour &= 0x3fff;
	
	/*Here we are not using the wrapper funcitons.We are directly using the F/W interface.
	 *The database is the bank and address are absolute values*/
	
	res = write_bfscam_value(header,db,addr,data,mask);
	if ( res != 0 )
	{
		printf ("\twrite aborted abnormally with the following error code %d\n", res);
		return;
	
	}else
	{
		printf("Data and Mask Written to database(BANK) %d address %d \n",db,addr);
		res = bfs_write_sram_entry(header,db,addr,colour);
		if(res == 0)
			printf("Wrote colour value %x to address %d\n",colour,addr);
	}

}

static void
cmd_rentry_ex(int argc, char *argv[])
{
	int               res;
	uint32_t          addr;
	uint32_t          db;
	uint32_t          mask[18];
	uint32_t          data[18];
	uint32_t        colour = 0;
	int temp;

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

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

	addr &= 0xffff;            /* 16 bits */
	db &= 0x1 ;                 /* 1 bits */

	printf("Please enter 13 32-bit values of data you want to enter \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7],&data[8],&data[9],&data[10],&data[11],&data[12]);
	
	printf("Please enter 13 32-bit values of mask you want to enter mask \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&mask[0],&mask[1],&mask[2],&mask[3],&mask[4],&mask[5],&mask[6],&mask[7],&mask[8],&mask[9],&mask[10],&mask[11],&mask[12]);
	
	
	/* First, Mask and Data */
	res = read_verify_bfscam_value(header,db,addr,data,mask);
	if ( res == 0 )
	{
		printf ("\t Verified the value at address %d is correct\n",addr);
		res =  bfs_read_sram_entry(header,db,addr,&colour);
		if(res == 0)
		{
			printf("The associated colour value %x\n",colour);
		}
	}
	else 
	{
		printf("Vefified the value at address %d is incorrect \n",addr);
	}
}



static void
cmd_rentry(int argc, char *argv[])
{
	int               res;
	uint32_t          addr;
	uint32_t          db;
	uint32_t          mask[18];
	uint32_t          data[18];
	int temp; 

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

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

	addr &= 0xffff;            /* 16 bits */
	db &= 0x1 ;                 /* 1 bits */

	printf("Please enter 13 32-bit values of data you want to enter \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7],&data[8],&data[9],&data[10],&data[11],&data[12]);
	
	printf("Please enter 13 32-bit values of mask you want to enter mask \n");
	
	temp = scanf("%x %x %x %x %x %x %x %x %x %x %x %x %x",&mask[0],&mask[1],&mask[2],&mask[3],&mask[4],&mask[5],&mask[6],&mask[7],&mask[8],&mask[9],&mask[10],&mask[11],&mask[12]);
	
	/* First, Mask and Data */
	res = read_verify_bfscam_value(header,db,addr,data,mask);
	if ( res == 0 )
	{
		printf ("\t Verified the value at address %d is correct\n",addr);
	}
	else 
	{
		printf("Vefified the value at address %d is incorrect \n",addr);
	}
}

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

	if (argc < 3 || argv[1][0] == '?')
	{
		printf("rtag <db> <addr>\n\
			db = 1-bit value selecting which database contains the entry to read\n\
			addr = 16-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 = bfs_read_sram_entry(header,db,addr,&tag);
	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;

	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 */
	tag &= 0xffff;              /* 16 bits.*/
	
	if ( addr > MAX_BFS_POSSIBLE_RULES ) 
	{	
		printf("Address out of range\n");
		return ;
	}
	if ( db > 1 )
	{	
		printf("DB out of range\n");
		return ;
	}	

    res = bfs_write_sram_entry(header,db,addr,tag);
	if ( res != 0 )
		printf("\twrite aborted abnormally with the following error code %d\n", res);

}

static void
cmd_read_db(int argc, char *argv[])
{
	 bool db = false;

	if (argc < 1 || argv[1][0] == '?')
	{
		printf("rdb <db>\n\
				db = 1-bit value which shows the inactive to write to \n");
		return;
	}
	db = get_inactive_bank(header);
	if(db)
		printf("Bank 1 is INACTIVE \n");
	else
		printf("Bank 0 is INACTIVE \n");

}

static void
cmd_swap_db(int argc, char *argv[])
{
	swap_active_bank(header);
}

void
production_test_1(int argc, char *argv[])
{
	int      res;
	uint32_t db;
	uint32_t colour;
	uint32_t  data[13];
	uint32_t  mask[13];
	uint32_t out_colour = 0;
	
	int loop = 0;

	if((argc < 1) || argv[1][0] == '?')
	{
		printf("cmd_prod <db> \n\
				addr = database into which to write the values \n");
	}
	
	for(loop = 0; loop < 64; loop ++)
	{
	
		/* generate some random valuesand load them into the TCAM */
		BUILD_384BIT_ARRAY(data, ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()),
								 ((uint32_t)mrand48()));
	
		BUILD_384BIT_ARRAY(mask,((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()),
								((uint32_t)mrand48()));
	
		colour = (loop + 128);
	
		
		db = strtoul(argv[1],NULL,16);
		db &= 0x1 ;                 /* 1 bits */
		colour &= 0x3fff;
	
		/*Here we are not using the wrapper funcitons.We are directly using the F/W interface.
	 	*The database is the bank and address are absolute values*/
	
		res = write_bfscam_value(header,db,loop,(uint32_t*)data,(uint32_t*)mask);
		if ( res != 0 )
		{
			printf ("\twrite aborted abnormally with the following error code %d\n", res);
			return;
	
		}else
		{
			dagutil_verbose("Data and Mask Written to database(BANK) %d address %d \n",db,loop);
			res = bfs_write_sram_entry(header,db,loop,colour);
			if(res == 0)
				dagutil_verbose("Wrote colour value %x to address %d\n",colour,loop);
		}

		/*Reading the core data mask and colour*/
		res = read_verify_bfscam_value(header,db,loop,(uint32_t*)data,(uint32_t*)mask);
		if ( res == 0 )
		{
			res =  bfs_read_sram_entry(header,db,loop,&out_colour);
			if((res == 0) && (out_colour == colour))
			{
				printf("The colour value at address %x is %x \"OK\"\n",loop,out_colour);
			}
		}
		else 
		{
			printf("Vefified the value at address %d is incorrect \n",loop);
		}
	}
}

void
production_test_2(int argc, char* argv[]) 
{
	uint64_t bit;
	int res = 0;
	int loop = 0;
	uint32_t db, entry;
	
	uint32_t data[13], mask[18]; 
	uint32_t datas[12];
	uint64_t one = 0x1;
	uint32_t out_colour;

	
	printf("production test 2\n\t");
	db = strtoul(argv[1],NULL,16);
	printf("Walking ones \n");
	for(loop = 0; loop < 64; loop++) 
	{
		printf(".");
		/* walking 1's */
		for(bit = 0; bit < 389; bit++) 
		{
	
			entry = (loop + 123);
			
			datas[0] = datas[1] = datas[2] = datas[3] = datas[4] = datas[5] = datas[6] = datas[7] = datas[8] = datas[9] = datas[10] = datas[11] = 0;

				
			if     (bit < 32)  datas[0]    =  (one <<  bit);
			else if(bit < 64)  datas[1]    =  (one << (bit-32));
			else if(bit < 96)  datas[2]    =  (one << (bit-64));
			else if(bit < 128) datas[3]    =  (one << (bit-96));
			else if(bit < 160) datas[4]    =  (one << (bit-128));
			else if(bit < 192) datas[5]    =  (one << (bit-160));
			else if(bit < 224) datas[5]    =  (one << (bit-192));
			else if(bit < 256) datas[6]    =  (one << (bit-224));
			else if(bit < 288) datas[7]    =  (one << (bit-256));
			else if(bit < 320) datas[8]    =  (one << (bit-288));
			else if(bit < 352) datas[9]    =  (one << (bit-320));
			else if(bit < 384) datas[10]   =  (one << (bit-352));
			else               datas[11]   =  (one << (bit-384));

			BUILD_384BIT_ARRAY(data, datas[0],  datas[1], datas[2],  datas[3],
									 datas[4],  datas[5], datas[6],  datas[7],
									 datas[8],  datas[9], datas[10], data[11]);
			
			BUILD_384BIT_ARRAY(mask, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
									 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
									 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);

		
			dagutil_verbose_level(2,"data %x %x %x %x %x %x %x %x %x %x %x %x \n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10],data[11]);
			
			res = write_bfscam_value(header,db,entry,data,mask);
			if ( res != 0 )
			{
				printf ("\twrite aborted abnormally with the following error code %d\n", res);
				return;
			}else
			{
				dagutil_verbose("Data and Mask Written to database(BANK) %d address %d \n",db,loop);
				res = bfs_write_sram_entry(header,db,loop,entry);
				if(res == 0)
					dagutil_verbose("Wrote colour value %x to address %d\n",entry,loop);
			}


			/*Reading the core data mask and colour*/
			res = read_verify_bfscam_value(header,db,loop,(uint32_t*)data,(uint32_t*)mask);
			if ( res == 0 )
			{
				res =  bfs_read_sram_entry(header,db,loop,&out_colour);
				if((res == 0) && (out_colour == entry))
				{
					printf("The colour value at address %x is %x \"OK\"\n",loop,out_colour);
				}
			}	
			else 
			{
				printf("Vefified the value at address %d is incorrect \n",loop);
			}
		}
	}
	printf("Walking zeros.\n");
	for(loop = 0; loop < 64; loop++) 
	{	
		/* walking 0's */
		for(bit = 0; bit < 389; bit++) 
		{
			datas[0] = datas[1] = datas[2] = datas[3] = datas[4] = datas[5] = datas[6] = datas[7] = datas[8] = datas[9] = datas[10] = datas[11] = 0;

				
			if     (bit < 32)  datas[0]    =  (~(one <<  bit));
			else if(bit < 64)  datas[1]    =  (~(one << (bit-32)));
			else if(bit < 96)  datas[2]    =  (~(one << (bit-64)));
			else if(bit < 128) datas[3]    =  (~(one << (bit-96)));
			else if(bit < 160) datas[4]    =  (~(one << (bit-128)));
			else if(bit < 192) datas[5]    =  (~(one << (bit-160)));
			else if(bit < 224) datas[5]    =  (~(one << (bit-192)));
			else if(bit < 256) datas[6]    =  (~(one << (bit-224)));
			else if(bit < 288) datas[7]    =  (~(one << (bit-256)));
			else if(bit < 320) datas[8]    =  (~(one << (bit-288)));
			else if(bit < 352) datas[9]    =  (~(one << (bit-320)));
			else if(bit < 384) datas[10]   =  (~(one << (bit-352)));
			else 			   datas[11]   =  (~(one << (bit-384))); 

			BUILD_384BIT_ARRAY(data, datas[0],  datas[1], datas[2],  datas[3],
									 datas[4],  datas[5], datas[6],  datas[7],
									 datas[8],  datas[9], datas[10], data[11]);
			
			BUILD_384BIT_ARRAY(mask, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
									 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
									 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);

			

		 	dagutil_verbose_level(2,"data %x %x %x %x %x %x %x %x %x %x %x %x \n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10],data[11]);

			res = write_bfscam_value(header,db,loop,data,mask);
			if ( res != 0 )
			{
				printf ("\twrite aborted abnormally with the following error code %d\n", res);
				return;
			}else
			{
				dagutil_verbose("Data and Mask Written to database(BANK) %d address %d \n",db,loop);
				res = bfs_write_sram_entry(header,db,loop,entry);
				if(res == 0)
					dagutil_verbose("Wrote colour value %x to address %d\n",entry,loop);
			}
			/*Reading the core data mask and colour*/
			res = read_verify_bfscam_value(header,db,loop,(uint32_t*)data,(uint32_t*)mask);
			if ( res == 0 )
			{
				res =  bfs_read_sram_entry(header,db,loop,&out_colour);
				if((res == 0) && (out_colour == entry))
				{
					printf("The colour value at address %x is %x \"OK\"\n",loop,out_colour);
				}
			}	
			else 
			{
				printf("Vefified the value at address %d is incorrect \n",loop);
			}
		}
	}
	printf("\n\t");
	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},
	{"init", cmd_init},
	{"rddb", cmd_read_db},
	{"swdb", cmd_swap_db},
	{"rtag", cmd_read_tag},
	{"wtag", cmd_write_tag},
	{"wentry", cmd_wentry},
	{"wentry_ex",cmd_wentry_ex},
	{"rentry_ex",cmd_rentry_ex},
	{"rentry", cmd_rentry},
	{"test", cmd_test},
	{"cmd_prod",production_test_1},
#if 0
	//:TODO may need to 
	{"production_test",cmd_production_test},
#endif

	{NULL, 0},
};


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

	for (;;)
	{
		(void) sprintf(prompt, "bfscam:%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);
}

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