#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/devices.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/expansion_protos.h>
#include <libraries/dosextens.h>
#include <libraries/configregs.h>
#include <libraries/configvars.h>

static void copyromdata(UBYTE bustype, UBYTE *rom, int offset, UBYTE *out, int size)
{
	switch (bustype & 0xc0)
	{
	case 0x00: // nibble
		while (size-- > 0) {
			*out++ = (rom[offset * 4 + 0] & 0xf0) | ((rom[offset * 4 + 2] & 0xf0) >> 4);
			offset++;
		}
		break;
	case 0x40: // byte
		while (size-- > 0) {
			*out++ = rom[offset * 2];
			offset++;
		}
		break;
	case 0x80: // word
	default:
		while (size-- > 0) {
			*out++ = rom[offset];
			offset++;
		}
		break;
	}
}

static void outputstring(UBYTE bustype, UBYTE *rom, UWORD offset)
{
	int i = 0;
	if (offset == 0 || offset == 0xffff)
		return;
	printf("'");
	for (i = 0; i < 256; i++) {
		UBYTE ch;
		copyromdata(bustype, rom, offset, &ch, 1);
		if (ch < 32)
			break;
		if (ch > 127)
			ch = '.';
		printf("%c", ch);
		offset++;
	}
	printf("'\n");

}

int main(int argc,char *argv[])
{
	struct ConfigDev *cd = NULL;
	BOOL romdump = FALSE;
	
	if (argc > 1 && !stricmp(argv[1], "-rom"))
		romdump = TRUE;
	
	while (cd = FindConfigDev(cd, -1, -1)) {
		struct ExpansionRom *er = &cd->cd_Rom;
		UBYTE *erp = (UBYTE*)er;
		int i;
		printf("BoardAddr       : %08x\n", cd->cd_BoardAddr);
		printf("BoardSize       : %08x\n", cd->cd_BoardSize);
		printf("er_Type         : %02x\n", er->er_Type);
		printf("er_Product      : %02x\n", er->er_Product);
		printf("er_Flags        : %02x\n", er->er_Flags);
		printf("er_Reserved03   : %02x\n", er->er_Reserved03);
		printf("er_Manufacturer : %04x\n", er->er_Manufacturer);
		printf("er_SerialNumber : %08x\n", er->er_SerialNumber);
		printf("er_InitDiagVec  : %04x\n", er->er_InitDiagVec);
		printf("{");
		for (i = 0; i < 12; i++) {
			if (i > 0)
				printf(",");
			printf("0x%02x", erp[i]);
		}
		printf("}\n");
		if (romdump && (er->er_Type & ERTF_DIAGVALID)) {
			struct DiagArea *da;
			UWORD outrom[8];
			UBYTE *rom = (UBYTE*)cd->cd_BoardAddr + er->er_InitDiagVec;
			UBYTE romtype = rom[0] & 0xf0;
			printf(" ROM: %08x\n", rom);
			copyromdata(romtype, rom, 0, (UBYTE*)outrom, 16);
			da = (struct DiagArea*)outrom;
			printf(" da_Config      : %02x\n", da->da_Config);
			printf(" da_Flags       : %02x\n", da->da_Flags);
			printf(" da_Size        : %04x\n", da->da_Size);
			printf(" da_DiagPoint   : %04x\n", da->da_DiagPoint);
			printf(" da_BootPoint   : %04x\n", da->da_BootPoint);
			printf(" da_Name        : %04x\n", da->da_Name);
			printf(" da_Reserved01  : %04x\n", da->da_Reserved01);
			printf(" da_Reserved02  : %04x\n", da->da_Reserved02);
			printf("{");
			for (i = 0; i < 14; i++) {
				if (i > 0)
					printf(",");
				printf("0x%02x", ((UBYTE*)outrom)[i]);
			}
			printf("}\n");
			printf(" Name: ");
			outputstring(romtype, rom, da->da_Name);
		}
		printf("\n\n");
	}

	return 0;	
}