/***********************************************************************
	idblock_report.c


	Reports system ID Block information.

 ***********************************************************************


 Instructions:

 1. Compile the program to the target and run it.  The contents of the
    system ID block will be printed (or any errors reported) to stdio.


 ***********************************************************************


 Version History:
 2.00 - Added support for version 5 ID block, corrected and updated
        PowerCore FLEX series' board information.
 1.08 - Added RCM2260, RCM3360, RCM3370, RCM3720, PowerCore Flex board types.
 1.07 - Corrected BL26xx series' board information.
 1.06 - Added BL2600A, BL2600B, BL2600C, BL2600D, RCM3310A board types.
 1.05 - Added RCM3300A, RCM3600H, RCM3610H, RCM3700H, RCM3710H board
        types.
 1.04 - Corrected conditional definition of RC3410A product ID.  Added
        RCM3600A, RCM3610A, RCM3700A, RCM3710A board types.
 1.03 - Added missing compile mode macro checks.
 1.02 - Added a flash type, reorganized the presentation of information,
        eased future flash writeMode type additions.
 1.01 - Updated board and flash information.
 1.00 - Initial version, based on write_idblock.c.


 **********************************************************************/


#class auto


#define VERSION "2.00"
#define PROGRAM_NAME "idblock_report.c"


// check for undefined board types


#ifndef BL1800
	#define BL1800		0x0101
#endif
#ifndef BL1805
	#define BL1805		0x0103
#endif
#ifndef BL1810
	#define BL1810		0x0100
#endif
#ifndef BL1820
	#define BL1820		0x0102
#endif
#ifndef BL2000
	#define BL2000		0x0800
#endif
#ifndef BL2000B
	#define BL2000B	0x0806
#endif
#ifndef BL2010
	#define BL2010		0x0801
#endif
#ifndef BL2010B
	#define BL2010B	0x0805
#endif
#ifndef BL2020
	#define BL2020		0x0802
#endif
#ifndef BL2030
	#define BL2030		0x0803
#endif
#ifndef BL2040
	#define BL2040		0x0804
#endif
#ifndef BL2100
	#define BL2100		0x0B00
#endif
#ifndef BL2101
	#define BL2101		0x0B06
#endif
#ifndef BL2105
	#define BL2105		0x0B04
#endif
#ifndef BL2110
	#define BL2110		0x0B01
#endif
#ifndef BL2111
	#define BL2111		0x0B08
#endif
#ifndef BL2115
	#define BL2115		0x0B05
#endif
#ifndef BL2120
	#define BL2120		0x0B02
#endif
#ifndef BL2121
	#define BL2121		0x0B07
#endif
#ifndef BL2130
	#define BL2130		0x0B03
#endif
#ifndef BL2500A
	#define BL2500A	0x1500
#endif
#ifndef BL2500B
	#define BL2500B	0x1502
#endif
#ifndef BL2500C
	#define BL2500C	0x1504
#endif
#ifndef BL2510A
	#define BL2510A	0x1501
#endif
#ifndef BL2510B
	#define BL2510B	0x1503
#endif
#ifndef BL2600A
	#define BL2600A	0x1700
#endif
#ifndef BL2600B
	#define BL2600B	0x1701
#endif
#ifndef BL2600C
	#define BL2600C	0x1704
#endif
#ifndef BL2610A
	#define BL2610A	0x1702
#endif
#ifndef BL2610B
	#define BL2610B	0x1705
#endif
#ifndef EG2110A
	#define EG2110A	0x0603
#endif
#ifndef EM1500A
	#define EM1500A	0x1800
#endif
#ifndef LP3500
	#define LP3500		0x1200
#endif
#ifndef LP3510
	#define LP3510		0x1201
#endif
#ifndef OP6600
	#define OP6600		0x0300
#endif
#ifndef OP6700
	#define OP6700		0x0302
#endif
#ifndef OP6800
	#define OP6800		0x0D00
#endif
#ifndef OP6805
	#define OP6805		0x0D02
#endif
#ifndef OP6810
	#define OP6810		0x0D01
#endif
#ifndef OP7200
	#define OP7200		0x1100
#endif
#ifndef OP7200B
	#define OP7200B	0x1102
#endif
#ifndef OP7210
	#define OP7210		0x1101
#endif
#ifndef OP7210B
	#define OP7210B	0x1103
#endif
#ifndef RABLINK
	#define RABLINK	0x0601
#endif
#ifndef RCM2000
	#define RCM2000	0x0200
#endif
#ifndef RCM2010
	#define RCM2010	0x0201
#endif
#ifndef RCM2020
	#define RCM2020	0x0202
#endif
#ifndef RCM2100
	#define RCM2100	0x0700
#endif
#ifndef RCM2110
	#define RCM2110	0x0701
#endif
#ifndef RCM2115
	#define RCM2115	0x0704
#endif
#ifndef RCM2120
	#define RCM2120	0x0702
#endif
#ifndef RCM2130
	#define RCM2130	0x0703
#endif
#ifndef RCM2200
	#define RCM2200	0x0900
#endif
#ifndef RCM2210
	#define RCM2210	RCM2200
#endif
#ifndef RCM2250
	#define RCM2250	0x0E00
#endif
#ifndef RCM2260A
	#define RCM2260A	0x0901
#endif
#ifndef RCM2300
	#define RCM2300	0x0A00
#endif
#ifndef RCM3000
	#define RCM3000	0x0F00
#endif
#ifndef RCM3010
	#define RCM3010	0x0F01
#endif
#ifndef RCM3100
	#define RCM3100	0x1000
#endif
#ifndef RCM3110
	#define RCM3110	0x1001
#endif
#ifndef RCM3200
	#define RCM3200	0x1300
#endif
#ifndef RCM3210A
	#define RCM3210A	0x1301
#endif
#ifndef RCM3220A
	#define RCM3220A	0x1302
#endif
#ifndef RCM3300A
	#define RCM3300A	0x1400
#endif
#ifndef RCM3310A
	#define RCM3310A	0x1402
#endif
#ifndef RCM3360A
	#define RCM3360A	0x1403
#endif
#ifndef RCM3360B
	#define RCM3360B	0x1405
#endif
#ifndef RCM3370A
	#define RCM3370A	0x1404
#endif
#ifndef RCM3400A
	#define RCM3400A	0x1600
#endif
#ifndef RCM3410A
	#define RCM3410A	0x1610
#endif
#ifndef RCM3600A
	#define RCM3600A	0x1E00
#endif
#ifndef RCM3600H
	#define RCM3600H	0x1E20
#endif
#ifndef RCM3610A
	#define RCM3610A	0x1E01
#endif
#ifndef RCM3610H
	#define RCM3610H	0x1E21
#endif
#ifndef RCM3700A
	#define RCM3700A	0x1F00
#endif
#ifndef RCM3700H
	#define RCM3700H	0x1F20
#endif
#ifndef RCM3710A
	#define RCM3710A	0x1F01
#endif
#ifndef RCM3710H
	#define RCM3710H	0x1F21
#endif
#ifndef RCM3720A
	#define RCM3720A	0x1F02
#endif
#ifndef RCM3720H
	#define RCM3720H	0x1F22
#endif
#ifndef POWERCOREFLEX
	#define POWERCOREFLEX 0x2300
#endif
#ifndef POWERCOREFLEXA
	#define POWERCOREFLEXA 0x2301
#endif
#ifndef RTDK
	#define RTDK		0x0301
#endif
#ifndef SR9100
	#define SR9100		0x0502
#endif
#ifndef SR9150
	#define SR9150		0x0C00
#endif
#ifndef SR9160
	#define SR9160		0x0C01
#endif


// check for undefined compile mode macros


#ifndef FAST_RAM_COMPILE
 #define FAST_RAM_COMPILE 0
#endif
#ifndef FLASH_COMPILE
 #ifdef _FLASH_
  #define FLASH_COMPILE 1
 #else
  #define FLASH_COMPILE 0
 #endif
#endif
#ifndef __SEPARATE_INST_DATA__
 #define __SEPARATE_INST_DATA__ 0
#endif


// local function prototypes


int GetFlashID(void);
void PrintFlashDescription(char *which, int FlashID, int FlashType);
void PrintProductDescription(int ProductID);
void PrintSysIDBlockInfo(void);
int _GetDevSpecIndex(int n, MemDevSpec *devspec);


/********************************************************************/


void main(void)
{
	printf("%s, version %s.\n", PROGRAM_NAME, VERSION);

	PrintSysIDBlockInfo();
	PrintProductDescription(SysIDBlock.productID);
	PrintFlashDescription("Flash ID", (int) SysIDBlock.flashID,
	                      SysIDBlock.flashType);
	PrintFlashDescription("Flash2 ID", (int) SysIDBlock.flash2ID,
	                      SysIDBlock.flash2Type);
#if FLASH_COMPILE || FAST_RAM_COMPILE
	PrintFlashDescription("GetFlashID() result", GetFlashID(),
	                      _FlashInfo.writeMode);
#endif
}

#if FLASH_COMPILE || FAST_RAM_COMPILE
int GetFlashID(void)
{
	static int id;

#asm
#if __SEPARATE_INST_DATA__ && FLASH_COMPILE
	; Only if separate I&D space is enabled AND the program runs in
	;  flash do we need to call the run-in-data-RAM function this way.
	ld		hl, _GetFlashID
	lcall	_CallRAMFunction
#else
	call	_GetFlashID
#endif
	ld		(id), hl
#endasm
	return(id);
}
#endif

struct _FlashDescription {
	int fType;
	char *fDesc;
};

const struct _FlashDescription FlashDesc[] = {
	{1, "small sector, sector erase (0x30) byte write"},
	{2, "small sector, sector write"},
	{3, "small page, page erase (0x50) byte write"},
	{4, "small sector, sector erase (0x20) byte write"},
	{0x11, "large sector (128/96/8/8/16), sector erase (0x30) byte write"},
	{0x12, "large sector (16/8/8/96/128), sector erase (0x30) byte write"},
	{0x13, "large sector (16*7/4/4/8), sector erase (0x30) byte write"},
	{0x14, "large sector (8/4/4/16*7), sector erase (0x30) byte write"},
	{0x15, "large sector (64*3/32/8/8/16), sector erase (0x30) byte write"},
	{0x16, "large sector (16/8/8/32/64*3), sector erase (0x30) byte write"},
	{0x17, "large sector (64*7/32/8/8/16), sector erase (0x30) byte write"},
	{0x18, "large sector (16/8/8/32/64*7), sector erase (0x30) byte write"},
	{0x19, "large sector (64*8), sector erase (0x30) byte write"},
	{0x1A, "large sector (64*8), sector erase (0x30) byte write"},
	{0x1B, "large sector (64*4), sector erase (0x30) byte write"},
	{0x1C, "large sector (64*4), sector erase (0x30) byte write"},
	{0x1D, "large sector (128/96/8/8), sector erase (0x30) byte write"},
	{0x1E, "large sector (32*8), sector erase (0x30) byte write"},
	{0x1F, "large sector (8/4/4/16*7), sector erase (0x30) byte write"},
	{0x20, "large sector (16*8), sector erase (0x30) byte write"},
	{0x21, "large sector (16*8), sector erase (0x30) byte write"},
	{0, "unknown.\n  If valid, a description should be added herein"}
};

struct _Flash {
	int fID;
	char *name;
};

const struct _Flash Flash[] = {
	{0x0134, "n AMD AM29F002BB"},
	{0x0140, "n AMD AM29LV002BT"},
	{0x016D, "n AMD AM29LV001BB"},
	{0x0177, "n AMD AM29F004BT"},
	{0x017B, "n AMD AM29F004BB"},
	{0x01A4, "n AMD AM29F040B"},
	{0x01B0, "n AMD AM29F002BT"},
	{0x01B5, "n AMD AM29LV004BT"},
	{0x01B6, "n AMD AM29LV004BB"},
	{0x01C2, "n AMD AM29LV002BB"},
	{0x01ED, "n AMD AM29LV001BT"},

	{0x0434, " Fujitsu MBM29F002BC"},
	{0x04B0, " Fujitsu MBM29F002TC"},

	{0x1F07, "n Atmel AT49F002"},
	{0x1F08, "n Atmel AT49F002T"},
	{0x1F25, "n Atmel AT29C1024"},
	{0x1F26, "n Atmel AT29LV1024"},
	{0x1F35, "n Atmel AT29LV010 / AT29BV010A"},
	{0x1FA4, "n Atmel AT29C040"},
	{0x1FBA, "n Atmel AT29LV020 / AT29BV020"},
	{0x1FC4, "n Atmel AT29LV040 / AT29BV040"},
	{0x1FD5, "n Atmel AT29C010"},
	{0x1FDA, "n Atmel AT29C020"},

	{0x2023, "n STMicroelectronics M29W010B"},
	{0x20E2, "n STMicroelectronics M29F040B"},
	{0x20E3, "n STMicroelectronics M29W040B"},

	{0x4001, " Mosel/Vitelic V29C51001T"},
	{0x4002, " Mosel/Vitelic V29C51002T"},
	{0x4003, " Mosel/Vitelic V29C51004T"},
	{0x4060, " Mosel/Vitelic V29LC51001"},
	{0x4063, " Mosel/Vitelic V29C31004T"},
	{0x4073, " Mosel/Vitelic V29C31004B"},
	{0x4082, " Mosel/Vitelic V29LC51002"},
	{0x40A1, " Mosel/Vitelic V29C51001B"},
	{0x40A2, " Mosel/Vitelic V29C51002B"},
	{0x40A3, " Mosel/Vitelic V29C51004B"},

	{0xAD34, " Hyundai HY29F002B"},
	{0xADB0, " Hynix/Hyundai HY29F002T"},

	{0xBF07, "n SST SST29EE010"},
	{0xBF08, "n SST SST29LE010 / SST29VE010"},
	{0xBF10, "n SST SST29EE020"},
	{0xBF12, "n SST SST29LE020 / SST29VE020"},
	{0xBF13, "n SST SST29SF040"},
	{0xBF14, "n SST SST29VF040"},
	{0xBF20, "n SST SST29SF512"},
	{0xBF21, "n SST SST29VF512"},
	{0xBF22, "n SST SST29SF010"},
	{0xBF23, "n SST SST29VF010"},
	{0xBF24, "n SST SST29SF020"},
	{0xBF25, "n SST SST29VF020"},
	{0xBF3D, "n SST SST29LE512 / SST29VE512"},
	{0xBF5D, "n SST SST29EE512"},
	{0xBFB4, "n SST SST39SF512"},
	{0xBFB5, "n SST SST39SF010"},
	{0xBFB6, "n SST SST39SF020"},
	{0xBFB7, "n SST SST39SF040"},
	{0xBFD4, "n SST SST39LF512 / SST39VF512"},
	{0xBFD5, "n SST SST39LF010 / SST39VF010"},
	{0xBFD6, "n SST SST39LF020 / SST39VF020"},
	{0xBFD7, "n SST SST39LF040 / SST39VF040"},

	{0xC234, " Macronix MX29F002B"},
	{0xC2B0, " Macronix MX29F02T"},

	{0xDA45, " Winbond W29C020CT"},
	{0xDA46, " Winbond W29C040"},
	{0xDAB5, " Winbond W39L020"},
	{0xDAC1, " Winbond W29EE011"},

	{0, "n unlisted type.\n  If valid, a description should be added herein"}
};

void PrintFlashDescription(char *which, int FlashID, int FlashType)
{
	int i;

	i = 0;
	while (Flash[i].fID) {
		if (Flash[i].fID == FlashID) {
			break;
		}
		i++;
	}
	printf("\n\n%s 0x%04X is a%s.\n", which, FlashID, Flash[i].name);

	i = 0;
	while (FlashDesc[i].fType) {
		if (FlashDesc[i].fType == FlashType) {
			break;
		}
		i++;
	}
	printf("  Type 0x%04X is %s.\n", FlashType, FlashDesc[i].fDesc);
}

struct _Product {
	int pID;
	char *name;
	char *description;
};

const struct _Product Product[] = {
//*** RabbitCore Modules ***//

	{RCM2000, "n RCM2000", "25MHz R2000, 256K flash, 512k SRAM"},
	{RCM2010, "n RCM2010", "25MHz R2000, 256K flash, 128k SRAM"},
	{RCM2020, "n RCM2020", "18MHz R2000, 256K flash, 128K SRAM"},

	{RCM2100, "n RCM2100", "22MHz R2000, 2x256K flash, 512K SRAM, ethernet"},
	{RCM2110, "n RCM2110", "22MHz R2000, 256K flash, 128K SRAM, ethernet"},
	{RCM2115, "n RCM2115",
	 "22MHz R2000, 256K flash, 128K SRAM, ethernet (no RJ45)"},
	{RCM2120, "n RCM2120", "22MHz R2000, 2x256K flash, 512K SRAM"},
	{RCM2130, "n RCM2130", "22MHz R2000, 256K flash, 128K SRAM"},

	{RCM2200, "n RCM2200", "22MHz R2000, 256K flash, 128K SRAM, ethernet"},
	{RCM2210, "n RCM2210",
	 "22MHz R2000, 256K flash, 128K SRAM, ethernet (no RJ45)"},
	{RCM2250, "n RCM2250", "22MHz R2000, 2x256K flash, 512K SRAM, ethernet"},
	{RCM2260A, "n RCM2260",
	 "22MHz R2000, 2x256K flash, 512K SRAM, ethernet (no RJ45)"},

	{RCM2300, "n RCM2300", "22MHz R2000, 256K flash, 128K SRAM"},

	{RCM3000, "n RCM3000", "29MHz R3000, 2x256K flash, 512K SRAM, ethernet"},
	{RCM3010, "n RCM3010", "29MHz R3000, 256K flash, 128K SRAM, ethernet"},

	{RCM3100, "n RCM3100", "29MHz R3000, 2x256K flash, 512K SRAM"},
	{RCM3110, "n RCM3110", "29MHz R3000, 256K flash, 128K SRAM"},

	{RCM3200, "n RCM3200", "44MHz R3000, 512K flash, 256K+512K SRAM, ethernet"},
	{RCM3210A, "n RCM3210", "29MHz R3000, 256K flash, 128K SRAM, ethernet"},
	{RCM3220A, "n RCM3220", "44MHz R3000, 512K flash, 256K+512K SRAM"},

	{RCM3300A, "n RCM3300",
	 "44MHz R3000, 512K flash, 512K+512K SRAM, ethernet, 8M serial flash"},
	{RCM3310A, "n RCM3310",
	 "44MHz R3000, 512K flash, 512K+512K SRAM, ethernet, 4M serial flash"},
	{RCM3360A, "n RCM3360",
	 "44MHz R3000, 512K flash, 512K+512K SRAM, ethernet, 16M nand flash+socket"},
	{RCM3360B, "n RCM3360",
	 "44MHz R3000, 512K flash, 512K+512K SRAM, ethernet, 16M nand flash"},
	{RCM3370A, "n RCM3370",
	 "44MHz R3000, 512K flash, 512K+512K SRAM, ethernet, nand flash socket"},

	{RCM3400A, "n RCM3400",
	 "29MHz R3000, 512K flash, 512K SRAM, ethernet on PB, analog"},
	{RCM3410A, "n RCM3410",
	 "29MHz R3000, 256K flash, 256K SRAM, ethernet on PB, analog"},

//TinyCore
	{RCM3600A, "n RCM3600", "22MHz R3000, 512K flash, 512K SRAM"},
	{RCM3610A, "n RCM3610", "22MHz R3000, 256K flash, 128K SRAM"},
// Hobby
	{RCM3600H, "n RCM3600", "22MHz R3000, 512K flash, 512K SRAM"},
	{RCM3610H, "n RCM3610", "22MHz R3000, 256K flash, 128K SRAM"},

//Ethernet TinyCore
	{RCM3700A, "n RCM3700",
	 "22MHz R3000, 512K flash, 512K SRAM, ethernet, 1M serial flash"},
	{RCM3710A, "n RCM3710",
	 "22MHz R3000, 256K flash, 128K SRAM, ethernet, 1M serial flash"},
	{RCM3720A, "n RCM3720",
	 "22MHz R3000, 512K flash, 256K SRAM, ethernet, 1M serial flash"},
//Hobby Ethernet
	{RCM3700H, "n RCM3700",
	 "22MHz R3000, 512K flash, 512K SRAM, ethernet, 1M serial flash"},
	{RCM3710H, "n RCM3710",
	 "22MHz R3000, 256K flash, 128K SRAM, ethernet, 1M serial flash"},
	{RCM3720H, "n RCM3720",
	 "22MHz R3000, 512K flash, 256K SRAM, ethernet, 1M serial flash"},

//PowerCore
	{POWERCOREFLEX,  " PowerCore FLEX", "Varies"},
	{POWERCOREFLEXA, " PowerCore FLEX", "Varies"},


//*** Single Board Computers ***//

//Jackrabbit
	{BL1800, " BL1800", "29MHz R2000, 256K flash, 128K SRAM, RS485, battery"},
	{BL1805, " BL1805", "29MHz R2000, 256K flash, 512K SRAM, RS485, battery"},
	{BL1810, " BL1810", "14MHz R2000, 128K flash, 128K SRAM, RS485, battery"},
	{BL1820, " BL1820", "14MHz R2000, 128K flash, 128k SRAM"},

//Wildcat
	{BL2000, " BL2000",
	 "22MHz R2000, 256K flash, 128K SRAM, ethernet, high-quality analog"},
	{BL2000B, " BL2000",
	 "22MHz R2000, 512K flash, 512K SRAM, ethernet, high-quality analog"},
	{BL2010, " BL2010", "22MHz R2000, 256K flash, 128K SRAM, ethernet, analog"},
	{BL2010B, " BL2010", "22MHz R2000, 256K flash, 512K SRAM, ethernet, analog"},

	{BL2020, " BL2020",
	 "22MHz R2000, 256K flash, 128K SRAM, high-quality analog"},
	{BL2030, " BL2030", "22MHz R2000, 256K flash, 128K SRAM, analog"},
	{BL2040, " BL2040", "22MHz R2000, 256K flash, 128K SRAM"},

//Smart Cat
	{BL2100, " BL2100",
	 "22MHz RCM2200, 256K flash, 128K SRAM, ethernet, analog"},
	{BL2101, " BL2101",
	 "22MHz RCM2200, 256K flash, 128K SRAM, ethernet, 10V analog"},
	{BL2105, " BL2105",
	 "22MHz RCM2250, 2x256K flash, 512K SRAM, ethernet, analog"},
	{BL2110, " BL2110", "22MHz RCM2200, 256K flash, 128K SRAM, ethernet"},
	{BL2111, " BL2111",
	 "22MHz RCM2250, 2x256K flash, 512K SRAM, ethernet, 10V analog"},
	{BL2115, " BL2115", "22MHz RCM2250, 2x256K flash, 512K SRAM, ethernet"},
	{BL2120, " BL2120", "22MHz RCM2300, 256K flash, 128K SRAM, analog"},
	{BL2121, " BL2121", "22MHz RCM2300, 256K flash, 128K SRAM, 10V analog"},
	{BL2130, " BL2130", "22MHz RCM2300, 256K flash, 128K SRAM"},

//RabbitNet
	{BL2500A, " BL2500", "29MHz RCM3010, 256K flash, 128K SRAM, ethernet"},
	{BL2500B, " BL2500", "29MHz RCM3000, 2x256K flash, 512K SRAM, ethernet"},
	{BL2500C, " BL2500", "44MHz RCM3200, 512K flash, 256K+512K SRAM, ethernet"},
	{BL2510A, " BL2510", "29MHz RCM3110, 256K flash, 128K SRAM"},
	{BL2510B, " BL2510", "29MHz RCM3100, 2x256K flash, 512K SRAM"},

	{BL2600A, " BL2600", "44MHz RCM3200, 512K flash, 256K+512K SRAM, ethernet"},
	{BL2600B, " BL2600", "29MHz RCM3000, 2x256K flash, 512K SRAM, ethernet"},
	{BL2600C, " BL2600", "29MHz RCM3010, 256K flash, 128K SRAM, ethernet"},
	{BL2610A, " BL2610", "29MHz RCM3100, 2x256K flash, 512K SRAM"},
	{BL2610B, " BL2610", "29MHz RCM3110, 256K flash, 128K SRAM"},

//Fox Low-Power Controller
	{LP3500, "n LP3500", "7MHz R3000, 2x256K flash, 512K SRAM, analog, relay"},
	{LP3510, "n LP3510", "7MHz R3000, 256K flash, 128K SRAM"},


//*** Embedded Control Systems ***//

//SmartStar
	{SR9100, "n SR9100", "29MHz R2000, 2x256K flash, 128K SRAM"},

//MiniStar
	{SR9150, "n SR9150", "22MHz R2000, 2x256K flash, 128K SRAM, ethernet"},
	{SR9160, "n SR9160", "22MHz R2000, 2x256K flash, 128K SRAM"},


//*** Operator Interfaces ***//

//Intellicom
	{OP6600, "n OP6600", "18MHz R2000, 256K flash, 128K SRAM"},
	{OP6700, "n OP6700", "18MHz R2000, 2x256K flash, 256K SRAM, ethernet"},

//Minicom
	{OP6800, "n OP6800", "22MHz RCM2200, 256K flash, 128K SRAM, ethernet"},
	{OP6805, "n OP6805", "22MHz RCM2250, 2x256K flash, 512K SRAM, ethernet"},
	{OP6810, "n OP6810", "22MHz RCM2300, 256K flash, 128K SRAM"},

//eDisplay
	{OP7200, "n OP7200",
	 "22MHz RCM2200, 256K flash, 128K SRAM, ethernet, analog, touchscreen"},
	{OP7200B, "n OP7200",
	 "22MHZ RCM2250, 2x256K flash, 512K SRAM, ethernet, analog, touchscreen"},
	{OP7210, "n OP7210", "22MHz RCM2300, 256K flash, 128K SRAM"},
	{OP7210B, "n OP7210", "22MHz RCM2250, 2x256K flash, 512K SRAM, ethernet"},


//*** Other Products ***//

//Ethernet Modem
	{EM1500A, "n EM1500",
	 "44MHz RCM3200, 512K flash, 256K+512K SRAM, ethernet"},

//RabbitLink
	{EG2110A, "n EG2110", "22MHz R2000, 2x256K flash, 128K SRAM, ethernet, 3V"},
	{RABLINK, " RABLINK", "22MHz R2000, 2x256K flash, 128K SRAM, ethernet"},

//TCP/IP Development Kit
	{RTDK, "n RTDK", "18MHz R2000, 2x256K flash, 128K SRAM, ethernet"},


	{0, "n unlisted type", "If valid, a description should be added herein"}
};

void PrintProductDescription(int ProductID)
{
	int i;

	i = 0;
	while (Product[i].pID) {
		if (Product[i].pID == ProductID) {
			break;
		}
		i++;
	}
	printf("\n\nProduct ID 0x%04X is a%s.\n", ProductID, Product[i].name);
	printf("  %s.\n", Product[i].description);
}

void PrintSysIDBlockInfo(void)
{
	auto int i;
   auto char buf[SYS_MACRO_LENGTH];
   auto unsigned long value;
   auto MemDevSpec devspec;

	printf("\n\nSystem ID Block content:\n\n");
	printf("  tableVersion =  %d\n", SysIDBlock.tableVersion);
	printf("  productID =     0x%04X\n", SysIDBlock.productID);
	printf("  vendorID =      %d\n", SysIDBlock.vendorID);
	printf("  timestamp =     %02d/%02d/%02d%02d  %02d:%02d:%02d\n\n",
		SysIDBlock.timestamp[2], SysIDBlock.timestamp[3],
		SysIDBlock.timestamp[0], SysIDBlock.timestamp[1],
			SysIDBlock.timestamp[4], SysIDBlock.timestamp[5],
			SysIDBlock.timestamp[6]);

	printf("  flashID =       0x%08LX\n", SysIDBlock.flashID);
	printf("  flashType =     0x%04X\n", SysIDBlock.flashType);
	printf("  flashSize =     %d Kbytes\n", SysIDBlock.flashSize * 4);
	printf("  sectorSize =    %d bytes\n", SysIDBlock.sectorSize);
	printf("  numSectors =    %d\n", SysIDBlock.numSectors);
	printf("  flashSpeed =    %d nS\n\n", SysIDBlock.flashSpeed);

	printf("  flash2ID =      0x%08LX\n", SysIDBlock.flash2ID);
	printf("  flash2Type =    0x%04X\n", SysIDBlock.flash2Type);
	printf("  flash2Size =    %d Kbytes\n", SysIDBlock.flash2Size * 4);
	printf("  sector2Size =   %d bytes\n", SysIDBlock.sector2Size);
	printf("  num2Sectors =   %d\n", SysIDBlock.num2Sectors);
	printf("  flash2Speed =   %d nS\n\n", SysIDBlock.flash2Speed);

	printf("  ramID =         0x%08LX\n", SysIDBlock.ramID);
	printf("  ramSize =       %d Kbytes\n", SysIDBlock.ramSize * 4);
	printf("  ramSpeed =      %d nS\n\n", SysIDBlock.ramSpeed);

	printf("  cpuID =         Rabbit %u (rev. %u)\n",
	       ((SysIDBlock.cpuID >> 8) & 0xFF) * 1000 + 2000,
	       SysIDBlock.cpuID & 0xFF);
	printf("  crystalFreq =   %.4f MHz\n\n", SysIDBlock.crystalFreq * 1.0e-6);

	printf("  macAddr =       %02X:%02X:%02X:%02X:%02X:%02X\n",
	       SysIDBlock.macAddr[0], SysIDBlock.macAddr[1], SysIDBlock.macAddr[2],
	       SysIDBlock.macAddr[3], SysIDBlock.macAddr[4], SysIDBlock.macAddr[5]);
	printf("  serialNumber =  '%s'\n", SysIDBlock.serialNumber);
	printf("  productName =   '%s'\n\n", SysIDBlock.productName);

   if (SysIDBlock.tableVersion >= 5)
   {
  	   printf("  flashMBC =      0x%02X\n", SysIDBlock.idBlock2.flashMBC);
  	   printf("  flash2MBC =     0x%02X\n", SysIDBlock.idBlock2.flash2MBC);
  	   printf("  ramMBC =        0x%02X\n", SysIDBlock.idBlock2.ramMBC);
  	   printf("  devSpecLoc =    0x%08LX\n", SysIDBlock.idBlock2.devSpecLoc);
  	   printf("  macrosLoc =     0x%08LX\n", SysIDBlock.idBlock2.macrosLoc);
	   printf("  driversLoc =    0x%08LX\n", SysIDBlock.idBlock2.driversLoc);
	   printf("  ioDescLoc =     0x%08LX\n", SysIDBlock.idBlock2.ioDescLoc);
	   printf("  ioPermLoc =     0x%08LX\n", SysIDBlock.idBlock2.ioPermLoc);
	   printf("  persBlockLoc =  0x%08LX\n", SysIDBlock.idBlock2.persBlockLoc);
	   printf("  userBlockSiz2 = 0x%04X\n", SysIDBlock.idBlock2.userBlockSiz2);
	   printf("  idBlockCRC2 =   0x%04X\n", SysIDBlock.idBlock2.idBlockCRC2);
   }
	printf("  reserved[0] =   0x%02X\n\n", SysIDBlock.reserved[0]);
	printf("  idBlockSize =   0x%08LX bytes\n", SysIDBlock.idBlockSize);
	printf("  userBlockSize = 0x%04X\n", SysIDBlock.userBlockSize);
	printf("  userBlockLoc =  0x%04X\n\n", SysIDBlock.userBlockLoc);

  	printf("  idBlockCRC =    0x%04X\n", SysIDBlock.idBlockCRC);
	printf("  marker =        %02X %02X %02X %02X %02X %02X\n",
	       SysIDBlock.marker[0], SysIDBlock.marker[1], SysIDBlock.marker[2],
	       SysIDBlock.marker[3], SysIDBlock.marker[4], SysIDBlock.marker[5]);

   if (SysIDBlock.tableVersion >= 5)
   {
     	printf("\nSystem Macro Table contents:\n");
   	if(SysIDBlock.idBlock2.macrosLoc) {
   		i = 0;
      	while(_GetSysMacroIndex(i, buf, &value) == 0) {
	         printf("%09s =		0x%08LX\n", buf, value);
            i++;
         }
      }
      else {
			printf("No entries.\n");
      }
     	printf("\nDevice Specification Table contents:\n");
   	if(SysIDBlock.idBlock2.devSpecLoc) {
   		i = 0;
      	while(_GetDevSpecIndex(i, &devspec) == 0) {
   			printf("  Dev ID = 	     0x%08LX\n", devspec.ID);
	         printf("  Dev Type =      0x%04X\n", devspec.type);
	         printf("  Dev Speed =     %d Kbytes\n", devspec.devSize * 4);
	         printf("  sectorSize =    %d bytes\n", devspec.sectorSize);
	         printf("  numSectors =    %d\n", devspec.numSectors);
	         printf("  Dev Speed =     %d nS\n", devspec.devSpeed);
            printf("  Dev MBC =       0x%02X\n", devspec.MBC);
            i++;
         }
      }
      else {
			printf("No entries.\n");
      }
   }
}

int _GetDevSpecIndex(int n, MemDevSpec *devspec) {
   auto long devspecloc;
   auto uint16 len;
   auto int i;

   // Calculate location of macro table
	devspecloc = IDBlockAddr - SysIDBlock.idBlock2.devSpecLoc;
   // Get the length of the macro table
   len = xgetint(devspecloc);
   // End of macro table is used to terminate loop below
   devspecloc += 2;

   // Check that id block is defined, that macro table is version 0
   // and that the length of the table is appropriate
   if(IDBlockAddr == 0 || (char)xgetint(devspecloc) != 0 || len > 256) {
   	return -2;
   }
   devspecloc++;

	// Calculate number of dev spec entries in table (-3 for is header of table)
   len = (len - 3)/sizeof(MemDevSpec);

   n = n * sizeof(MemDevSpec);
   if(n > len) {
   	return -1;
   }

   devspecloc += n;
   xmem2root(devspec, devspecloc, sizeof(MemDevSpec));

   return 0;
}