/* ------------------------------------------------------------------------------
 *                                                                      
 *                  I N T E L   P R O P R I E T A R Y                   
 *                                                                      
 *     COPYRIGHT (c)  1998-1999 BY  INTEL  CORPORATION.  ALL RIGHTS          
 *     RESERVED.   NO  PART  OF THIS PROGRAM  OR  PUBLICATION  MAY      
 *     BE  REPRODUCED,   TRANSMITTED,   TRANSCRIBED,   STORED  IN  A    
 *     RETRIEVAL SYSTEM, OR TRANSLATED INTO ANY LANGUAGE OR COMPUTER    
 *     LANGUAGE IN ANY FORM OR BY ANY MEANS, ELECTRONIC, MECHANICAL,    
 *     MAGNETIC,  OPTICAL,  CHEMICAL, MANUAL, OR OTHERWISE,  WITHOUT    
 *     THE PRIOR WRITTEN PERMISSION OF :                                
 *                                                                      
 *                        INTEL  CORPORATION                            
 *                                                                     
 *                     2200 MISSION COLLEGE BLVD                        
 *                                                                      
 *               SANTA  CLARA,  CALIFORNIA  95052-8119                  
 *                                                                      
 *------------------------------------------------------------------------------*/

/* rtm.cpp
 *
 *
 * system: SA1200
 * subsystem: Xact_IO
 * author: Don Hooper 1/19/98
 * revisions:
 *		1/21/00		Beta4 Interim	See new SRM Longest Prefix Match section.
 *					1. hi256 table entries now have rt_ptrs. See 
 *					2. delete now supported
 *					3. fixed lost short prefix pointer, reversed bit mask in trie block
 *
 */ 

#include "rtm.h"
#include "rtm_cfg.h"
#include "endian.h"
#if (IOSTYLE != HARDWARE)
#include "Xact_API.h"
#endif
#include "uclo.h"
#include "mem_map.h"
#include "version.h"

#include "hal_sram.h"
#include "hal_sdram.h"

// pointers to sram and sdram
static SramUnit* sram;
static SdramUnit* sdram;

#ifndef STANDALONE
#include "config_1200.h"
#endif //not STANDALONE

/*
	RTM_config is used to hold the RTM configuration, addresses, limits. etc.
 */

RTM_ConfigInfo RTM_config;

/*
	RTM_lookup_cmds
	This is used to determine the sequence of lookups based on the mask value.
	It is an array of 3 x 8 chars. 8 triplets are for the count of mask least 
	significant nibbles = 0. For example, in a 32 bit address if mask is 
	255.255.255.255, the commands will be in the 0th triplet.Each triplet
	consists of a char to indicate initial lookup START_64K, START_256 or 
	START_TRIE, followed by key start bit and end bit.
 */
struct RTM_Cmd RTM_lookup_cmds[9] = {
	{START_64K, 12, 0}, {START_64K, 12, 4}, {START_64K, 12, 8}, {START_64K, 12, 12},
	{START_256, 20, 16}, {START_256, 20, 20}, 
	{START_TRIE, 28, 28}, {START_TRIE, 28, 28}, {START_TRIE, 28, 28}};


/*-----------------------------------------------------------------
	RTM_Init
	Initialize data structures for RTM.
	returns: RTM_SUCCESS or RTM_FAIL
	uses:
	modifies: microengine microcode storage
  -----------------------------------------------------------------*/
int									// RTM_SUCCESS or RTM_RTM_FAIL
RTM_Init()
{
    int i, j;
    unsigned int baseaddr, val;

// get sram and sdram pointers
	sram = SRAM_Attach();
	sdram = SDRAM_Attach();

/* 
	Initialize the 64K_table.
	This is an SRAM array of 64K 32bit entries. The index to the array is extracted 
	from the msb bits 31:16 of a internet address. The total memory taken 
	by this table is 256KB
*/
	RTM_config.hi64k_base = baseaddr = SRAM_DYNAMIC_LWD_START;		// from mem_map.h
#if (IOSTYLE != HARDWARE)
	// if no hardware, zero this buffer space quickly through XactIo
    if (XactIo_ZeroBuffer(SRAM, 65536, baseaddr) != XACT_SUCCESS) {
	    fprintf(stderr,"fatal error, unable to initialize hi64k table in SRAM\n");
	    return(RTM_FAIL);
	}
#else
	for (i=0; i < 65536 ; i++) {
		sram->write(baseaddr+i, 0);
	}
#endif



/*  
	Initialize the 256_table.
	This is an SRAM array of 256 32 bit entries, to be addressed by 31:24 of the internet  
	address. The total memory taken by this table is 1KB. 
*/
	RTM_config.hi256_base = baseaddr = baseaddr+65536;
#if (IOSTYLE != HARDWARE)
	// if no hardware, zero this buffer space quickly through XactIo
    if (XactIo_ZeroBuffer(SRAM, 256, baseaddr) != XACT_SUCCESS) {
	    perror("RTM_Init(): fatal error, unable to initialize hi256 table in SRAM\n");
	    return(RTM_FAIL);
	}
#else
	for (i=0; i < 256 ; i++) {
		sram->write(baseaddr+i, 0);
	}
#endif

	// initialize side info for hi 256 table
	for(i=0;i<256;i++){
		RTM_config.hi256_info.mask[i] = 0;
	}
	for(j=0;j<128;j++){
		RTM_config.hi256_info.prefix7[j] = 0;
	}
	for(j=0;j<64;j++){
		RTM_config.hi256_info.prefix6[j] = 0;
	}
	for(j=0;j<32;j++){
		RTM_config.hi256_info.prefix5[j] = 0;
	}
	for(j=0;j<16;j++){
		RTM_config.hi256_info.prefix4[j] = 0;
	}
	for(j=0;j<8;j++){
		RTM_config.hi256_info.prefix3[j] = 0;
	}
	for(j=0;j<4;j++){
		RTM_config.hi256_info.prefix2[j] = 0;
	}
	RTM_config.hi256_info.prefix1[0] = 0;
	RTM_config.hi256_info.prefix1[1] = 0;

	
/*
    Initialize the trie_table.
	This is an SRAM array of trie sets, each consisting of sixteen 32 bit unsigned integers.
	These sets are addressed by 4bit nibbles of the internet address.
*/
    RTM_config.trie_base = baseaddr = baseaddr+256;
#if (IOSTYLE != HARDWARE)
	// if no hardware, zero this buffer space quickly through XactIo
    if (XactIo_ZeroBuffer(SRAM, SIZE_OF_TRIE_SET * NUM_TRIE_SETS, baseaddr) != XACT_SUCCESS) {
	    perror("RTM_Init(): fatal error, unable to initialize trie table in SRAM\n");
	    return(RTM_FAIL);
	}
#else
	for (i=0; i < SIZE_OF_TRIE_SET * NUM_TRIE_SETS ; i++) {
		sram->write(baseaddr+i, 0);
	}
#endif

	// initialize side info for trie blocks
	for(i=0;i<NUM_TRIE_SETS;i++){
		RTM_config.trie_info[i].population = 0;
		for(j=0;j<16;j++){
			RTM_config.trie_info[i].mask[j] = 0;
		}
		for(j=0;j<8;j++){
			RTM_config.trie_info[i].prefix3[j] = 0;
		}
		for(j=0;j<4;j++){
			RTM_config.trie_info[i].prefix2[j] = 0;
		}
		RTM_config.trie_info[i].prefix1[0] = 0;
		RTM_config.trie_info[i].prefix1[1] = 0;
	}

	
/*
    Initialize the route table.
	This is an SDRAM array of route entries containing the information about 
	the actual routes. At present each route entry consist eight long 
	words.
*/
    RTM_config.route_table_base = baseaddr = SDRAM_ROUTE_FWD_BASE*2;
#if (IOSTYLE != HARDWARE)
	// if no hardware, zero this buffer space quickly through XactIo
    if (XactIo_ZeroSDBuffer(NUM_ROUTES * SIZE_OF_ROUTE, baseaddr) != XACT_SUCCESS) {
	    perror("RTM_Init(): fatal error, unable to initialize route table in SDRAM\n");
	    return(RTM_FAIL);
	}
#else
	for (i=0; i < NUM_ROUTES * SIZE_OF_ROUTE ; i++) {
		sdram->write(baseaddr+i, 0);
	}
#endif
	// set default location to no route (-1)
	val = -1;
	sdram->write(baseaddr, val);

    // put the size of trie table and route table allocation
    RTM_config.total_trie = NUM_TRIE_SETS;
    RTM_config.total_rt = NUM_ROUTES;

	// initialize trie freelist
	// start at 1, 0 is reserved as default
	RTM_config.next_free_trie = 1;
	for(i=1;i<NUM_TRIE_SETS-1;i++){
		RTM_config.trie_flinks[i].next = i+1;
		RTM_config.trie_flinks[i].index = i;
	}
	RTM_config.trie_flinks[i].next = 0;
	RTM_config.trie_flinks[i].index = i;

	// initialize route freelist
	// start at 1, 0 is reserved as default
	RTM_config.next_free_rt = 1;
	for(i=1;i<(NUM_ROUTES-1);i++){
		RTM_config.rt_flinks[i].next = i+1;
		RTM_config.rt_flinks[i].index = i;
	}
#ifdef DEBUG
	printf("\n");
	printf("route index Flink 1= %d\n",RTM_config.rt_flinks[1].index); 
	printf("Next free route index= %d\n",RTM_config.next_free_rt); 
#endif
	RTM_config.rt_flinks[i].next = 0;
	RTM_config.rt_flinks[i].index = i;


#ifndef STANDALONE
	// bind symbols in system config
	RTM_DelayBindSymbols("receive0");
	RTM_DelayBindSymbols("receive1");
	RTM_DelayBindSymbols("receive2");
	RTM_DelayBindSymbols("receive3");		// some uc configs have 16 receive threads
#endif

	return(RTM_SUCCESS);
} // end of RTM_Init()


#ifndef STANDALONE
/*-----------------------------------------------------------------
	RTM_DelayBindSymbols
	Delay BindSymbols (microcode import variables)for an image in system 
	configuration sysConf, so that each subsequent microcode load will bind 
	the symbols then.
	returns: RTM_SUCCESS or RTM_FAIL
	uses:
	modifies: symbol values in microengine microcode image copy
  -----------------------------------------------------------------*/
int RTM_DelayBindSymbols(char *image_name)
{
	unsigned int baseaddr = RTM_config.hi64k_base;

	SysConf *sysConf = SysConf_Attach();

	// base addresses are defined in mem_map.h
	// bind the sram lookup base
	if (sysConf->BindSymbol(image_name, "hi64k_base", baseaddr)){
		printf("Error; binding symbol 'hi64k_base'\n");
		return(RTM_FAIL);
	}

    // bind the sdram route table base 
	baseaddr = RTM_config.route_table_base/2;
	if (sysConf->BindSymbol(image_name, "route_table_base", baseaddr)){
		printf("Error; binding symbol 'route_table_base'\n");
 		return(RTM_FAIL);
	}

	return(RTM_SUCCESS);

}
#endif //not STANDALONE


/*-----------------------------------------------------------------
	RTM_BindSymbols
	BindSymbols for an image
	returns: RTM_SUCCESS or RTM_FAIL
	uses:
	modifies: symbol values in microengine microcode image copy
  -----------------------------------------------------------------*/
int RTM_BindSymbols(void *objHandle, char *image_name)
{
	unsigned int baseaddr = RTM_config.hi64k_base;

 	// base addresses are defined in mem_map.h
	// bind the sram lookup base
	if((UcLo_BindSymbol(objHandle, image_name, "hi64k_base", baseaddr)) != UCLO_SUCCESS) {
		printf("Warning: could not bind symbol 'hi64k_base' to image  %s\n", image_name);
	}

    // bind the sdram route table base
	baseaddr = RTM_config.route_table_base/2;
    if((UcLo_BindSymbol(objHandle, image_name, "route_table_base", baseaddr)) != UCLO_SUCCESS) {
		printf("Warning: could not bind symbol 'route_table_base' to image  %s\n", image_name);
	}

	return(RTM_SUCCESS);
}

/*-----------------------------------------------------------------
	RTM_InitULookup
	Read microcode image file, bind shared address symbols and write
	image to microengines.
	returns: RTM_SUCCESS or RTM_FAIL
	uses:
	modifies: microengine microcode storage
  -----------------------------------------------------------------*/
int									// RTM_SUCCESS or RTM_FAIL
RTM_InitULookup(char *fnam)
{
 	void *objHandle;

	UcLo_InitLib();
	
	/* Load the uCode image from file */
    if((UcLo_LoadObjFile(&objHandle, fnam)) != UCLO_SUCCESS) {
		printf("Error; loading microcode object file %s\n", fnam);
		return(RTM_FAIL);
	}

	RTM_BindSymbols(objHandle, "receive0");
	RTM_BindSymbols(objHandle, "receive1");
	RTM_BindSymbols(objHandle, "receive2");
	RTM_BindSymbols(objHandle, "receive3");

	/* copy microcode images to fboxes */
    if((UcLo_WriteUimageAll(objHandle)) != UCLO_SUCCESS) {
		printf("Error; failed to write image to uStore\n");
		return(RTM_FAIL);
	}

	return(RTM_SUCCESS);
}


/*-----------------------------------------------------------------
	RTM_AllocTrie
	description: get next free trie
	uses: RTM_config
	modifies: RTM_config.next_free_trie
	returns: index of a new trie block, or RTM_NO_TRIE_FREE
  -----------------------------------------------------------------*/
int								// index to new trie block or NO_TRIE_BLOCK_FREE
RTM_AllocTrie()
{
	int new_trie;
	
	if (new_trie = RTM_config.next_free_trie){
		RTM_config.next_free_trie = RTM_config.trie_flinks[new_trie].next;
		return(new_trie<<4);
	} else return(RTM_NO_TRIE_FREE);
}


/*-----------------------------------------------------------------
	RTM_Free_Trie
	Free a Trie set and place a Flink with trie's index at head of RTM_config.next_free_trie
	returns: RTM_SUCCESS
	uses:
	modifies: RTM_config.next_free_trie
  -----------------------------------------------------------------*/
int								// RTM_SUCCESS or RTM_FAIL
RTM_FreeTrie(unsigned int trie_block)
{
	int prev_free, new_free;
#ifdef DEBUG
	printf("Freeing trie block %x\n", trie_block);
#endif
	prev_free = RTM_config.next_free_trie;
	new_free = trie_block>>4;

	RTM_config.trie_flinks[new_free].next = prev_free;
	RTM_config.next_free_trie = new_free;

	return(RTM_SUCCESS);
}


/*-----------------------------------------------------------------
	RTM_AllocRoute
	description: get index to next free route entry
	uses: RTM_config
	modifies: pointer to RTM_config.next_free_rt
	returns: index of new route entry, or RTM_NO_ROUTE_FREE
  -----------------------------------------------------------------*/
int								// index to new trie block or NO_TRIE_BLOCK_FREE
RTM_AllocRoute()
{
	int new_route;
	
	if (new_route = RTM_config.next_free_rt){
		RTM_config.next_free_rt = RTM_config.rt_flinks[new_route].next;
		return(new_route*SIZE_OF_ROUTE);
	} else return(RTM_NO_ROUTE_FREE);
}


/*-----------------------------------------------------------------
	RTM_Free_Route
	Free a Route entry and place a Flink with route's index at head of RTM_config.next_free_rt
	returns: RTM_SUCCESS
	uses:
	modifies: RTM_config.next_free_rt
  -----------------------------------------------------------------*/
int								// RTM_SUCCESS or RTM_FAIL
RTM_FreeRoute(unsigned int route_index)
{
	int i;
	int prev_free, new_free;

	prev_free = RTM_config.next_free_rt;
	new_free = route_index/SIZE_OF_ROUTE;

	RTM_config.rt_flinks[new_free].next = prev_free;
	RTM_config.next_free_rt = new_free;

	for(i = 0; i < SIZE_OF_ROUTE; i++){
		sdram->write(RTM_config.route_table_base+route_index+i, 0);
	}

	return(RTM_SUCCESS);
}

/*-----------------------------------------------------------------
	RTM_WriteRouteEntry
	Write route entry, copying from add_info 
	returns: RTM_SUCCESS
	uses:
  -----------------------------------------------------------------*/
int
RTM_WriteRouteEntry(int route_index, RTM_AddInfo *add_info)
{
	int i;
	int sdram_addr = RTM_config.route_table_base+route_index;

	sdram->write(sdram_addr, add_info->itf);
	sdram->write(sdram_addr+1, add_info->gateway_da_hi32);
	sdram->write(sdram_addr+2, add_info->gateway_da_lo16);
	sdram->write(sdram_addr+3, add_info->destination);
	sdram->write(sdram_addr+4, add_info->netmask);
	sdram->write(sdram_addr+5, add_info->gateway);
	for(i = 0; i < SIZE_OF_REST_ROUTE_ENTRY; i++){
		sdram->write(sdram_addr+6+i, add_info->rest[i]);
	}
	return(RTM_SUCCESS);
}


/* 
    support function for *WriteMultipleRtPtr

*/
void delete_hi256_leaf(unsigned int tindex, unsigned int mask_field)
{
	uint prev_rt, prev_mask, existing_mask, val;

	if(prev_rt = RTM_config.hi256_info.prefix7[tindex>>1]){
		prev_mask = 0xfe;
	} else if (prev_rt = RTM_config.hi256_info.prefix6[tindex>>2]){
		prev_mask = 0xfc;
	} else if(prev_rt = RTM_config.hi256_info.prefix5[tindex>>3]){
		prev_mask = 0xf8;
	} else if(prev_rt = RTM_config.hi256_info.prefix4[tindex>>4]){
		prev_mask = 0xf0;
	} else if(prev_rt = RTM_config.hi256_info.prefix3[tindex>>5]){
		prev_mask = 0xe0;
	} else if(prev_rt = RTM_config.hi256_info.prefix2[tindex>>6]){
		prev_mask = 0xc0;
	} else if(prev_rt = RTM_config.hi256_info.prefix1[tindex>>7]){
		prev_mask = 0x80;
	} else prev_mask = 0;

	existing_mask = RTM_config.hi256_info.mask[tindex];
	if (mask_field >= existing_mask){
		if(mask_field != prev_mask){
			// write prev_rt and prev_mask to leaf
			sram->read(RTM_config.hi256_base+tindex, &val);
#ifdef DEBUG
			printf("writing prev rt ptr to hi256 leaf, prev %x, tindex %x, existing mask %x, new mask %x\n", val, tindex, existing_mask, prev_mask);			
#endif			
			sram->write(RTM_config.hi256_base+tindex, ((prev_rt <<16) | (val &0xffff)));
			RTM_config.hi256_info.mask[tindex] = prev_mask;
		} else {
			// 0 the leaf
			sram->read(RTM_config.hi256_base+tindex, &val);
#ifdef DEBUG
			printf("deleting hi256 leaf rt ptr, prev %x, tindex %x, existing mask %x, new mask %x\n", val, tindex, existing_mask, mask_field);			
#endif			
			sram->write(RTM_config.hi256_base+tindex, val &0xffff);
			RTM_config.hi256_info.mask[tindex] = 0;
		}
	}
	return;
}


void write_rt_ptrs256(uint route_index, uint dest_field, uint mask_field, uint count)
{
	uint tindex, i, val;
	uint masked_index = mask_field & dest_field;

	for (i = 0; i<count; i++) {
		tindex = masked_index+i;

		if (route_index == 0){
			delete_hi256_leaf(tindex, mask_field);
		}
		else if(mask_field >= RTM_config.hi256_info.mask[tindex]){
			sram->read(RTM_config.hi256_base+tindex, &val);

#ifdef DEBUG
			printf("writing hi256 entry, prev %x, tindex %x, existing mask %x\n", val, tindex, RTM_config.hi256_info.mask[tindex]);			
#endif			
			val = (route_index<<16) | (val & 0xffff);
			sram->write(RTM_config.hi256_base+tindex, val);
			RTM_config.hi256_info.mask[tindex] = mask_field;
		}
	}
	return;
}

void delete_trie_leaf(unsigned int trie_block, unsigned int tindex, unsigned int mask_field)
{
	uint prev_rt, prev_mask, existing_mask, val;
	uint trie_block_addr = RTM_config.trie_base+trie_block;

	if(prev_rt = RTM_config.trie_info[trie_block].prefix3[tindex>>1]){
		prev_mask = 0xe;
	} else if (prev_rt = RTM_config.trie_info[trie_block].prefix2[tindex>>2]){
		prev_mask = 0xc;
	} else if(prev_rt = RTM_config.trie_info[trie_block].prefix1[tindex>>3]){
		prev_mask = 0x8;
	} else prev_mask = 0;

	existing_mask = RTM_config.trie_info[trie_block].mask[tindex];

	if (mask_field >= existing_mask){
		if(mask_field != prev_mask){
			// write prev_rt and prev_mask to leaf
			sram->read(trie_block_addr+tindex, &val);
#ifdef DEBUG
			printf("writing prev rt ptr to trie leaf, prev %x, tindex %x, existing mask %x, new mask %x\n", val, tindex, existing_mask, prev_mask);			
#endif			
			sram->write(trie_block_addr+tindex, ((prev_rt <<16) | (val &0xffff)));
			RTM_config.trie_info[trie_block].mask[tindex] = prev_mask;
		} else {
			// 0 the leaf
			sram->read(trie_block_addr+tindex, &val);
#ifdef DEBUG
			printf("deleting trie leaf rt ptr, prev %x, tindex %x, existing mask %x, new mask %x\n", val, tindex, existing_mask, mask_field);			
#endif			
			sram->write(trie_block_addr+tindex, val &0xffff);
			RTM_config.trie_info[trie_block].mask[tindex] = 0;
		}
	}
	return;
}

void write_rt_ptrs16(uint trie_block, uint route_index, uint dest_field, uint mask_field, uint count)
{
	uint tindex, i, val;
	uint masked_index = dest_field & mask_field;
	uint trie_block_addr = RTM_config.trie_base+trie_block;
	
	for (i = 0; i<count; i++) {
		tindex = masked_index+i;

		if (route_index == 0){
			delete_trie_leaf(trie_block, tindex, mask_field);
		} else if (mask_field > RTM_config.trie_info[trie_block].mask[tindex]){
			sram->read(trie_block_addr+tindex, &val);
#ifdef DEBUG
			printf("writing trie entry, prev %x, tindex %x, existing mask %x, new mask %x\n", val, tindex, RTM_config.trie_info[trie_block].mask[tindex], mask_field);			
#endif			
			val = (route_index<<16) | (val & 0xffff);
			sram->write(trie_block_addr+tindex, val);
			RTM_config.trie_info[trie_block].mask[tindex] = mask_field;
		}

	}
	return;
}

/*-----------------------------------------------------------------
	RTM_WriteMultipleRtPtr
	Write route_loc in trie set (16 longwords) at address indicated
	by trie_loc.
	uses: RTM_config
	modifies: trie block and trie block mask
	returns:
  -----------------------------------------------------------------*/
int RTM_WriteMultipleRtPtr(
					RTM_AddInfo *add_info,
					uint trie_block,        // which trie block
					uint dest_field,		// 4 bits of ip dest
					uint mask_field)		// 4 bits of netmask
{
	int route_index;
	uint val;
	uint trie_block_addr = (RTM_config.trie_base + trie_block);

#ifdef DEBUG
	printf("writing multiple entry, trie_block: %x, dest_field %x, local_mask %x\n", trie_block, dest_field, mask_field);
#endif
	switch (mask_field)
	{
	case 0xf:
#ifdef DEBUG
		printf("writing trie block entry, dest_field %x, previous mask %x\n", dest_field, RTM_config.trie_info[trie_block].mask[dest_field]);			
#endif
		if(RTM_config.trie_info[trie_block].mask[dest_field] != 0xf){
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				RTM_config.trie_info[trie_block].population++;
				write_rt_ptrs16(trie_block, route_index, dest_field, mask_field, 1);
			}
		} else {
			sram->read(trie_block_addr+dest_field, &val);
			route_index = val>>16;					// update existing entry
		}
		RTM_WriteRouteEntry(route_index, add_info);

		break;
	case 0xe:
		// if it previously exists, just write the info, not the trie, not alloc
		if(!(route_index = RTM_config.trie_info[trie_block].prefix3[dest_field>>1])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				RTM_config.trie_info[trie_block].population++;
				RTM_config.trie_info[trie_block].prefix3[dest_field>>1] = route_index;
				write_rt_ptrs16(trie_block, route_index, dest_field, mask_field, 2);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0xc:
		if(!(route_index = RTM_config.trie_info[trie_block].prefix2[dest_field>>2])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				RTM_config.trie_info[trie_block].population++;
				RTM_config.trie_info[trie_block].prefix2[dest_field>>2] = route_index;
				write_rt_ptrs16(trie_block, route_index, dest_field, mask_field, 4);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0x8:
		if(!(route_index = RTM_config.trie_info[trie_block].prefix1[dest_field>>3])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				RTM_config.trie_info[trie_block].population++;
				RTM_config.trie_info[trie_block].prefix1[dest_field>>3] = route_index;
				write_rt_ptrs16(trie_block, route_index, dest_field, mask_field, 8);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
		
	default:
		break;
	}
	return(RTM_SUCCESS);
}


/*-----------------------------------------------------------------
	RTM_WriteHi256RtPtr
	Write route_loc in hi256 table
	uses: RTM_config
	modifies: hi256 table and associated mask
	returns:
  -----------------------------------------------------------------*/
int RTM_WriteHi256RtPtr(
					RTM_AddInfo *add_info,
					uint dest_field,			// 8 bits of ip dest
					uint mask_field)			// 8 bits of netmask
{
	uint val;
	uint table_loc = RTM_config.hi256_base;
	int route_index;

#ifdef DEBUG
	printf("writing hi256 entry, dest_field %x, local_mask %x\n", dest_field, mask_field);
#endif

	switch (mask_field)
	{
	case 0xff:
		if(RTM_config.hi256_info.mask[dest_field] != 0xff){
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				write_rt_ptrs256(route_index, dest_field, mask_field, 1);
			}
		} else {
			sram->read(table_loc+dest_field, &val);
			route_index = val>>16;					// update existing entry
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0xfe:
		// if it previously exists, just write the info, not the trie, not alloc
		if(!(route_index = RTM_config.hi256_info.prefix7[dest_field>>1])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				// write the hidden entry
				RTM_config.hi256_info.prefix7[dest_field>>1] = route_index;
				// write multiple trie blocks
				write_rt_ptrs256(route_index, dest_field, mask_field, 2);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0xfc:
		if(!(route_index = RTM_config.hi256_info.prefix6[dest_field>>2])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				// write the hidden entry
				RTM_config.hi256_info.prefix6[dest_field>>2] = route_index;
				write_rt_ptrs256(route_index, dest_field, mask_field, 4);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0xf8:
		if(!(route_index = RTM_config.hi256_info.prefix5[dest_field>>3])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				// write the hidden entry
				RTM_config.hi256_info.prefix5[dest_field>>3] = route_index;
				write_rt_ptrs256(route_index, dest_field, mask_field, 8);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0xf0:
		if(!(route_index = RTM_config.hi256_info.prefix4[dest_field>>4])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				// write the hidden entry
				RTM_config.hi256_info.prefix4[dest_field>>4] = route_index;
				write_rt_ptrs256(route_index, dest_field, mask_field, 16);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0xe0:
		if(!(route_index = RTM_config.hi256_info.prefix3[dest_field>>5])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				// write the hidden entry
				RTM_config.hi256_info.prefix3[dest_field>>5] = route_index;
				write_rt_ptrs256(route_index, dest_field, mask_field, 32);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0xc0:
		if(!(route_index = RTM_config.hi256_info.prefix2[dest_field>>6])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				// write the hidden entry
				RTM_config.hi256_info.prefix2[dest_field>>6] = route_index;
				write_rt_ptrs256(route_index, dest_field, mask_field, 64);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
	case 0x80:
		if(!(route_index = RTM_config.hi256_info.prefix1[dest_field>>7])){
			// if can't alloc return
			if(0 >(route_index = RTM_AllocRoute())){
				return(RTM_FAIL);
			} else {
				// write the hidden entry
				RTM_config.hi256_info.prefix1[dest_field>>7] = route_index;
				write_rt_ptrs256(route_index, dest_field, mask_field, 128);
			}
		}
		RTM_WriteRouteEntry(route_index, add_info);
		break;
		
	default:
		break;
	}

	return(RTM_SUCCESS);
}

/*-----------------------------------------------------------------
	RTM_RtAdd
	Add a route entry to route table and lookup tables
	uses: hi64k, hi256, trie blocks
	modifies: hi64k, hi256, trie blocks, route entry table
	returns:
  -----------------------------------------------------------------*/
int									// RTM_SUCCESS, RTM_NO_TRIE_FREE, RTM_NO_ROUTE_FREE
RTM_RtAdd(
	struct RTM_AddInfo *add_info)		// dest, netmask, gateway, interface
{
    int i,
	start_bit,				// where in destination to trie lookups
	trie_count,
	end_bit;				// trie lookups when we get to this bit
	uint num0nibs,			// number of least significant nibbles that == 0
	start_lookup;			// whether to start in 64K lookup, 256 lookup or trie
	uint loc_64k;			// first whether lookup uses 64k array, later the loc
    uint loc_256;			// first whether lookup uses 256 array, later the loc
	uint val = 0;			// temp value
	uint hi_val = 0;
	uint trie_ptrs[4];		// array to hold writes so they can be done in reverse order
	struct RTM_Cmd cmd_lookup;		// commands for sequence of lookup
	int trie_block;			// temporary index to trie block
    uint local_index;		// temporary index ip_dest nibble
    uint dest = ntohl(add_info->destination);	// ip destination, is shifted to extract index fields
	uint full_mask ntohl(add_info->netmask);		// ip mask, is shifted to extract final 4 bit mask
	uint mask = full_mask;
	int wr_count = 0;		// number of writes to memory
	int alloc_first_trie = 0;	// whether first trie after hi table has been allocated

    if ((dest & mask) == 0 ) {
        fprintf(stderr, "NULL destination & netmask, entry ignored\n");
        return(RTM_FAIL);
    }

    // first find out  how many nibbles of netmask are zero
	// resulting mask is the nibble mask to be used in the redundant trie
    for ( num0nibs = 0; num0nibs <= 8 ; mask = mask >>4, num0nibs++){ 
        if( (mask & 0x0000000f) !=0){
			mask = mask & 0x0000000f;
            break;
        }
    }

	// setup controls for later writes to trie table and lookup array
	//
	cmd_lookup = RTM_lookup_cmds[num0nibs];
	start_lookup = cmd_lookup.look;
	start_bit = cmd_lookup.start;
	end_bit = cmd_lookup.end;
	// resulting trie_count can be 3, 2, 1 or 0
	trie_count = ((start_bit - end_bit) >>2);
    // get index corresponding to dest 31:16
	loc_64k = RTM_config.hi64k_base + ((dest & 0xFFFF0000) >>16);
    // get index corresponding to dest 31:24
	loc_256 = RTM_config.hi256_base + ((dest & 0xFF000000) >>24);

	if (start_lookup == START_64K) {
#ifdef DEBUG
		printf("start_lookup == hi64k\n");
#endif
		// if in64k, see if one is there from before. if so, use it
		sram->read(loc_64k, &hi_val);
		if (!(trie_block = hi_val & 0xffff)){				// if not prev existing
			if (0 >(trie_block = RTM_AllocTrie())){
				printf("Error: RTM_AllocTrie, no trie blocks available\n");
				return(trie_block);
			} else {
#ifdef DEBUG
				printf("allocating first 64k trie, trie_block: %x, trie_count %d\n", trie_block, trie_count); 
#endif
				wr_count++;
				alloc_first_trie = 1;
			}
		}
		trie_ptrs[trie_count] = hi_val | trie_block;
	}
	else if (start_lookup == START_256) {
		// if in256, see if one is there from before. if so, use it
		sram->read(loc_256, &hi_val);
		if (!(trie_block = hi_val & 0xffff)){				// if not prev existing
			if (0 >(trie_block = RTM_AllocTrie())){
				printf("Error: RTM_AllocTrie, no trie blocks available\n");
				return(trie_block);
			} else {
#ifdef DEBUG
				printf("allocating first 256 trie, trie_block: %x, trie_count %d\n", trie_block, trie_count); 
#endif
				wr_count++;
				alloc_first_trie = 1;
			}
		}
		trie_ptrs[trie_count] = hi_val | trie_block;

	} else trie_count = -1;
	// otherwise trie_count == 0, prefix length is 8 or less, we will modify hi256 at end

	if (trie_count >= 0){
#ifdef DEBUG
		printf("walking the tree, trie count = %d\n", trie_count);
#endif
		// for each trie, get lookup offset
		local_index = (dest >> start_bit) & 0x0000000f;
		for(i = trie_count-1; i >= 0; i--){
			// reuse and follow existing one
			sram->read(RTM_config.trie_base+trie_block+local_index, &val);
			if(!(trie_block = val & 0xffff)){			// if not previously existing
				// get a new one if it is 0
				if (0 >(trie_block = RTM_AllocTrie())){
					printf("Error: RTM_AllocTrie, no trie blocks available\n");
					return(trie_block);
				} else {
#ifdef DEBUG
					printf("allocating a new trie, trie_block %x\n", trie_block); 
#endif
					wr_count++;
				}
			}
			trie_ptrs[i] = (val & 0xffff0000) | trie_block;		// keep existing route ptr
			
			start_bit -= 4;
			local_index = (dest >> start_bit) & 0x0000000f;
		}


		// write multiple route entry pointers based on mask and key nibble bits
		if (!RTM_WriteMultipleRtPtr(add_info, (0xffff & trie_block), local_index, mask)){
			printf("Error: RTM_AllocRoute, no route entries available\n");
			return(RTM_NO_ROUTE_FREE);
		}	

		// write lookup keys in reverse order
		end_bit +=4;
		local_index = (dest >> end_bit) & 0x0000000f;
		if (alloc_first_trie == 0) wr_count++;

		for(i = 1; i<wr_count; i++) {
			trie_block = RTM_config.trie_base+(0xffff & trie_ptrs[i]);
			//*trie_loc = trie_ptrs[i-1];
#ifdef DEBUG
			printf("writing trie entry, i: %d, trie_block: %x, local_index: %x, value: %x\n", i, trie_block, local_index, trie_ptrs[i-1]);
#endif
			sram->write(trie_block+local_index, trie_ptrs[i-1]);
			RTM_config.trie_info[(0xffff & trie_ptrs[i])].population++;
			end_bit +=4;
			local_index = (dest >> end_bit) & 0x0000000f;
		}
	}
	
	// lastly, insert inital lookup pointer

	if (start_lookup == START_64K) {
			// write trie_ptr
		if(!(hi_val & 0xffff)){
			sram->write(loc_64k, trie_ptrs[trie_count]);
#ifdef DEBUG
			printf("writing hi64k, index %x, value %x\n", loc_64k, trie_ptrs[trie_count]);	
#endif
		}
	}else if (start_lookup == START_256) {
		// write trie_ptr
		if(!(hi_val & 0xffff)){
			sram->write(loc_256, trie_ptrs[trie_count]);
#ifdef DEBUG
		printf("trie count = %d\n", trie_count);
		printf("writing hi256, index %x, value %x\n", loc_256, trie_ptrs[trie_count]);	
#endif
		}
	} else if (!RTM_WriteHi256RtPtr(add_info, (dest>>24 & 0xff), (full_mask>>24 & 0xff))){
			return(RTM_NO_ROUTE_FREE);
	}

	return(RTM_SUCCESS);

}	// end of RTM_RtAdd()


// support function for RTM_RtLookup
uint next_trie(uint ipaddr, uint lsb, uint lookup, uint *rt_ptr)
{
	uint val;
	uint trie_loc = (RTM_config.trie_base + ((ipaddr >> lsb) & 0xf) + lookup);
	sram->read(trie_loc, &val);
	*rt_ptr = (val & 0xffff0000) ? (val & 0xffff0000) : *rt_ptr;
#ifdef DEBUG
	printf("lookup trie_loc %x, val %x\n", trie_loc, val);
#endif
	
	return(val&0xffff);
}

/*-----------------------------------------------------------------
	RTM_RtLookup
	Get a route from the route table. 
	returns: pointer to the route entry
	uses:
	modifies:
  -----------------------------------------------------------------*/
int										// pointer to route entry
RTM_RtLookup(
				char *destination)			// string ip destination, e.g. "1.1.1.1"
{
	uint dest = inet_addr(destination);
	uint route_loc, lookup_short, lookup_long, rt_ptr_short, rt_ptr_long;
	//convert to little-endian
	dest = ntohl(dest);

	sram->read(RTM_config.hi64k_base + (dest >>16), &rt_ptr_long);
	sram->read(RTM_config.hi256_base + (dest >>24), &rt_ptr_short);

	if ((lookup_short = rt_ptr_short & 0xffff) > 0) {
		if (lookup_short = next_trie(dest, 20, lookup_short, &rt_ptr_short)) {
			lookup_short = next_trie(dest, 16, lookup_short, &rt_ptr_short);
		}
	}

	if ((lookup_long = rt_ptr_long & 0xffff) > 0) {
		if (lookup_long = next_trie(dest, 12, lookup_long, &rt_ptr_long)) {
			if (lookup_long = next_trie(dest, 8, lookup_long, &rt_ptr_long)) {
				if (lookup_long = next_trie(dest, 4, lookup_long, &rt_ptr_long)) {
					lookup_long = next_trie(dest, 0, lookup_long, &rt_ptr_long);
				}
			}
		}
	}
	rt_ptr_long &= 0xffff0000;
	rt_ptr_short &= 0xffff0000;
	if (!(route_loc = rt_ptr_long)) route_loc = rt_ptr_short;


#ifdef DEBUG
	printf("route_loc %x, rt_ptr_short %x, rt_ptr_long %x\n",route_loc, rt_ptr_short, rt_ptr_long); 
#endif

	// route_loc is in bits 31:16 of the entry
	// if this field is 0, it is the default route, first entry of rt table
	return(RTM_config.route_table_base + (route_loc >> 16));
}

void delete_rt_ptrs256(uint dest_field, uint mask_field)
{
	switch (mask_field){
		case 0xff:
			write_rt_ptrs256(0, dest_field, mask_field, 1);
			break;
		case 0xfe:
			write_rt_ptrs256(0, dest_field, mask_field, 2);
			RTM_config.hi256_info.prefix7[dest_field>>1] = 0;
			break;
		case 0xfc:
			write_rt_ptrs256(0, dest_field, mask_field, 4);
			RTM_config.hi256_info.prefix6[dest_field>>2] = 0;
			break;
		case 0xf8:
			write_rt_ptrs256(0, dest_field, mask_field, 8);
			RTM_config.hi256_info.prefix5[dest_field>>3] = 0;
			break;
		case 0xf0:
			write_rt_ptrs256(0, dest_field, mask_field, 16);
			RTM_config.hi256_info.prefix4[dest_field>>4] = 0;
			break;
		case 0xe0:
			write_rt_ptrs256(0, dest_field, mask_field, 32);
			RTM_config.hi256_info.prefix3[dest_field>>5] = 0;
			break;
		case 0xc0:
			write_rt_ptrs256(0, dest_field, mask_field, 64);
			RTM_config.hi256_info.prefix2[dest_field>>6] = 0;
			break;
		default:
			RTM_config.hi256_info.prefix1[dest_field>>7] = 0;

	}
	return;
}






void delete_rt_ptrs16(uint trie_block, uint dest_field, uint mask_field)
{
	switch (mask_field){
		case 0xf:
			write_rt_ptrs16(trie_block, 0, dest_field, mask_field, 1);
			break;
		case 0xe:
			write_rt_ptrs16(trie_block, 0, dest_field, mask_field, 2);
			RTM_config.trie_info[trie_block].prefix3[dest_field>>1] = 0;
			break;
		case 0xc:
			write_rt_ptrs16(trie_block, 0, dest_field, mask_field, 4);
			RTM_config.trie_info[trie_block].prefix2[dest_field>>2] = 0;
			break;
		default:
			RTM_config.trie_info[trie_block].prefix1[dest_field>>3] = 0;
	}
	return;

}

void rem_ptr(uint trie_block, uint index)
{
	unsigned int val;
	sram->read(RTM_config.trie_base + trie_block + index, &val);
	sram->write(RTM_config.trie_base + trie_block + index, val & 0xffff0000);
	return;	
}

/*-----------------------------------------------------------------
	RTM_RtDelete
	Delete a route entry from route table and lookup tables
	uses: hi64k, hi256, trie blocks
	modifies: hi64k, hi256, trie blocks, route entry table
	returns:
  -----------------------------------------------------------------*/
int											// RTM_SUCCESS
RTM_RtDelete(
	struct RTM_DeleteInfo *del_info)			// dest, netmask
{
    uint dest = ntohl(del_info->destination);	// ip destination, is shifted to extract index fields
	uint full_mask ntohl(del_info->netmask);	// ip mask, is shifted to extract final 4 bit mask
	uint hi_lookup;
	uint dest_field, mask_field;
	uint trie_lookup, trie_lookup_p1, trie_lookup_p2, trie_lookup_p3, trie_block;
	uint route_index;

	// route entry index in 256hi table
	if (!(full_mask<<8)) {
		dest_field = dest>>24;
		mask_field = full_mask>>24;
		sram->read(RTM_config.hi256_base + dest_field, &hi_lookup);
		if(!hi_lookup) return(RTM_NOT_FOUND);
		route_index = hi_lookup>>16;
		delete_rt_ptrs256(dest_field, mask_field);

	// route entry index in trie block representing dest 23:20
	} else if (!(full_mask<<12)) {
		sram->read(RTM_config.hi256_base + (dest >>24), &hi_lookup);
		sram->read(RTM_config.trie_base + (hi_lookup & 0xffff) + ((dest>>20) & 0xf), &trie_lookup);
		if(!(trie_block = hi_lookup & 0xffff)) return(RTM_NOT_FOUND);
		route_index = trie_lookup>>16;
		dest_field = (dest>>20)&0xf;
		mask_field = (full_mask>>20)&0xf;
		delete_rt_ptrs16(trie_block, dest_field, mask_field);
		if((--RTM_config.trie_info[trie_block].population) == 0){
			RTM_FreeTrie(trie_block);
			sram->write(RTM_config.hi256_base + (dest >>24), 0);
		}

	// route entry index in trie block representing dest 19:16
	} else if (!(full_mask<<16)) {
		sram->read(RTM_config.hi256_base + (dest >>24), &hi_lookup);
		sram->read(RTM_config.trie_base + (hi_lookup & 0xffff) + ((dest>>20) & 0xf), &trie_lookup_p1);
		sram->read(RTM_config.trie_base + (trie_lookup_p1 & 0xffff) + ((dest>>16) & 0xf), &trie_lookup);
		if(!(trie_block = trie_lookup_p1 & 0xffff)) return(RTM_NOT_FOUND);
		route_index = trie_lookup>>16;
		dest_field = (dest>>16)&0xf;
		mask_field = (full_mask>>16)&0xf;
#ifdef DEBUG
		printf("RtDelete, field 19:16, hi_lookup %x, trie_lookup_p1 %x, trie_lookup %x\n", hi_lookup, trie_lookup_p1, trie_lookup);
		printf("RtDelete, field 19:16, trie_block %x, population %d\n", trie_block, RTM_config.trie_info[trie_block].population);
#endif
		delete_rt_ptrs16(trie_block, dest_field, mask_field);
		if((--RTM_config.trie_info[trie_block].population) == 0){
			RTM_FreeTrie(trie_block);
			trie_block = hi_lookup & 0xffff;
			rem_ptr(trie_block, ((dest>>20) & 0xf));
			if((--RTM_config.trie_info[trie_block].population) == 0){
				RTM_FreeTrie(trie_block);
				sram->write(RTM_config.hi256_base + (dest >>24), 0);
			}
		}

	// route entry index in trie block representing dest 15:12
	} else if (!(full_mask<<20)) {
		sram->read(RTM_config.hi64k_base + (dest >>16), &hi_lookup);
		sram->read(RTM_config.trie_base + (hi_lookup & 0xffff) + ((dest>>12) & 0xf), &trie_lookup);
		if(!(trie_block = hi_lookup & 0xffff)) return(RTM_NOT_FOUND);
		route_index = trie_lookup>>16;
		dest_field = (dest>>12)&0xf;
		mask_field = (full_mask>>12)&0xf;
		delete_rt_ptrs16(trie_block, dest_field, mask_field);
		if((--RTM_config.trie_info[trie_block].population) == 0){
			RTM_FreeTrie(trie_block);
			sram->write(RTM_config.hi64k_base + (dest >>16), 0);
		}

	// route entry index in trie block representing dest 11:8
	} else if (!(full_mask<<24)) {
		sram->read(RTM_config.hi64k_base + (dest >>16), &hi_lookup);
		sram->read(RTM_config.trie_base + (hi_lookup & 0xffff) + ((dest>>12) & 0xf), &trie_lookup_p1);
		sram->read(RTM_config.trie_base + (trie_lookup_p1 & 0xffff) + ((dest>>8) & 0xf), &trie_lookup);
		if(!(trie_block = trie_lookup_p1 & 0xffff)) return(RTM_NOT_FOUND);
		route_index = trie_lookup>>16;
		dest_field = (dest>>8)&0xf;
		mask_field = (full_mask>>8)&0xf;
		delete_rt_ptrs16(trie_block, dest_field, mask_field);
		if((--RTM_config.trie_info[trie_block].population) == 0){
			RTM_FreeTrie(trie_block);
			trie_block = hi_lookup & 0xffff;
			rem_ptr(trie_block, ((dest>>12) & 0xf));
			if((--RTM_config.trie_info[trie_block].population) == 0){
				RTM_FreeTrie(trie_block);
				sram->write(RTM_config.hi64k_base + (dest >>16), 0);
			}
		}
	// route entry index in trie block representing dest 7:4
	} else if (!(full_mask<<28)) {
		sram->read(RTM_config.hi64k_base + (dest >>16), &hi_lookup);
		sram->read(RTM_config.trie_base + (hi_lookup & 0xffff) + ((dest>>12) & 0xf), &trie_lookup_p2);
		sram->read(RTM_config.trie_base + (trie_lookup_p2 & 0xffff) + ((dest>>8) & 0xf), &trie_lookup_p1);
		sram->read(RTM_config.trie_base + (trie_lookup_p1 & 0xffff) + ((dest>>4) & 0xf), &trie_lookup);
		if(!(trie_block = trie_lookup_p1 & 0xffff)) return(RTM_NOT_FOUND);
		route_index = trie_lookup>>16;
		dest_field = (dest>>4)&0xf;
		mask_field = (full_mask>>4)&0xf;
		delete_rt_ptrs16(trie_block, dest_field, mask_field);
		if((--RTM_config.trie_info[trie_block].population) == 0){
			RTM_FreeTrie(trie_block);
			trie_block = trie_lookup_p2 & 0xffff;
			rem_ptr(trie_block, ((dest>>8) & 0xf));
			if((--RTM_config.trie_info[trie_block].population) == 0){
				RTM_FreeTrie(trie_block);
				trie_block = hi_lookup & 0xffff;
				rem_ptr(trie_block, ((dest>>12) & 0xf));
				if((--RTM_config.trie_info[trie_block].population) == 0){
					RTM_FreeTrie(trie_block);
					sram->write(RTM_config.hi64k_base + (dest >>16), 0);
				}
			}
		}
	// route entry index in trie block representing dest 3:0
	} else {
		sram->read(RTM_config.hi64k_base + (dest >>16), &hi_lookup);
		sram->read(RTM_config.trie_base + (hi_lookup & 0xffff) + ((dest>>12) & 0xf), &trie_lookup_p3);
		sram->read(RTM_config.trie_base + (trie_lookup_p3 & 0xffff) + ((dest>>8) & 0xf), &trie_lookup_p2);
		sram->read(RTM_config.trie_base + (trie_lookup_p2 & 0xffff) + ((dest>>4) & 0xf), &trie_lookup_p1);
		sram->read(RTM_config.trie_base + (trie_lookup_p1 & 0xffff) + (dest & 0xf), &trie_lookup);
		if(!(trie_block = trie_lookup_p1 & 0xffff)) return(RTM_NOT_FOUND);
		route_index = trie_lookup>>16;
		dest_field = dest&0xf;
		mask_field = full_mask&0xf;
#ifdef DEBUG
		printf("RtDelete, field 3:0, hi_lookup %x, trie_lookup_p3 %x, trie_lookup_p2 %x, trie_lookup_p1 %x, trie_lookup %x\n", hi_lookup, trie_lookup_p3,trie_lookup_p2, trie_lookup_p1,  trie_lookup);
		printf("RtDelete, field 3:0, trie_block %x, population %d\n", trie_block, RTM_config.trie_info[trie_block].population);
		printf("RtDelete, field 3:0, trie_block_p1 %x, population %d\n", trie_lookup_p1&0xffff, RTM_config.trie_info[trie_lookup_p1&0xffff].population);
		printf("RtDelete, field 3:0, trie_block_p2 %x, population %d\n", trie_lookup_p2&0xffff, RTM_config.trie_info[trie_lookup_p2&0xffff].population);
		printf("RtDelete, field 3:0, trie_block_p3 %x, population %d\n", trie_lookup_p3&0xffff, RTM_config.trie_info[trie_lookup_p3&0xffff].population);
#endif
		delete_rt_ptrs16(trie_block, dest_field, mask_field);

		if((--RTM_config.trie_info[trie_block].population) == 0){
			RTM_FreeTrie(trie_block);										// free the multiple ptr block
			trie_block = trie_lookup_p2 & 0xffff;
			rem_ptr(trie_block, ((dest>>4) & 0xf));
			if((--RTM_config.trie_info[trie_block].population) == 0){
				RTM_FreeTrie(trie_block);
				trie_block = trie_lookup_p3 & 0xffff;
				rem_ptr(trie_block, ((dest>>8) & 0xf));
				if((--RTM_config.trie_info[trie_block].population) == 0){
					RTM_FreeTrie(trie_block);
					trie_block = hi_lookup & 0xffff;
					rem_ptr(trie_block, ((dest>>12) & 0xf));
					if((--RTM_config.trie_info[trie_block].population) == 0){
						RTM_FreeTrie(trie_block);
						sram->write(RTM_config.hi64k_base + (dest >>16), 0);
					}
				}
			}
		}

	}
	

	// free the route entry
	RTM_FreeRoute(route_index);	

	return(RTM_SUCCESS);
}

int
DSTM_WriteReservationEntry(int index, int src, int dst, int rate, int burst)
{
//	#define RESERVATION_TABLE_BASE				0x8000
//	#define TABLE_RECORD_LEN					0x7
//	#define TABLE_COUNT_LOCATION				0x8FFF

	int i;
	int sram_addr = 0x8000+(index*7);

	sram->write(sram_addr, src);
	sram->write(sram_addr+1, dst);
	sram->write(sram_addr+2, rate);
	sram->write(sram_addr+3, burst);
	sram->write(sram_addr+4, 0x0);
	sram->write(sram_addr+5, 0x0);
	sram->write(sram_addr+6, 0x0);

	sram->write(0x8FFF, index+1);

	return(RTM_SUCCESS);
}
