/*
* UAE - The Un*x Amiga Emulator
*
* AutoConfig (tm) Expansions (ZorroII/III)
*
* Copyright 1996,1997 Stefan Reinauer <stepan@linux.de>
* Copyright 1997 Brian King <Brian_King@Mitel.com>
*   - added gfxcard code
*
*/

#include "sysconfig.h"
#include "sysdeps.h"

#include "options.h"
#include "uae.h"
#include "traps.h"
#include "memory.h"
#include "rommgr.h"
#include "custom.h"
#include "newcpu.h"
#include "savestate.h"
#include "zfile.h"
#include "catweasel.h"
#include "cdtv.h"
#include "cdtvcr.h"
#include "threaddep/thread.h"
#include "a2091.h"
#include "a2065.h"
#include "gfxboard.h"
#ifdef CD32
#include "cd32_fmv.h"
#endif
#include "ncr_scsi.h"
#include "ncr9x_scsi.h"
#include "scsi.h"
#include "debug.h"
#include "gayle.h"
#include "idecontrollers.h"
#include "cpuboard.h"
#include "sndboard.h"
#include "uae/ppc.h"
#include "autoconf.h"
#include "specialmonitors.h"
#include "inputdevice.h"
#include "pci.h"
#include "x86.h"
#include "filesys.h"
#include "ethernet.h"
#include "sana2.h"
#include "arcadia.h"
#include "devices.h"
#include "dsp3210/dsp_glue.h"


#define CARD_FLAG_CAN_Z3 1
#define CARD_FLAG_CHILD 8
#define CARD_FLAG_UAEROM 16

// More information in first revision HRM Appendix_G
#define BOARD_PROTOAUTOCONFIG 1

#define BOARD_AUTOCONFIG_Z2 2
#define BOARD_AUTOCONFIG_Z3 3
#define BOARD_NONAUTOCONFIG_BEFORE 4
#define BOARD_NONAUTOCONFIG_AFTER_Z2 5
#define BOARD_NONAUTOCONFIG_AFTER_Z3 6
#define BOARD_IGNORE 7

#define KS12_BOOT_HACK 1

#define EXP_DEBUG 0

#define MAX_EXPANSION_BOARD_SPACE 16

/* ********************************************************** */
/* 00 / 02 */
/* er_Type */

#define Z2_MEM_8MB		0x00 /* Size of Memory Block */
#define Z2_MEM_4MB		0x07
#define Z2_MEM_2MB		0x06
#define Z2_MEM_1MB		0x05
#define Z2_MEM_512KB	0x04
#define Z2_MEM_256KB	0x03
#define Z2_MEM_128KB	0x02
#define Z2_MEM_64KB		0x01
/* extended definitions */
#define Z3_MEM_16MB		0x00
#define Z3_MEM_32MB		0x01
#define Z3_MEM_64MB		0x02
#define Z3_MEM_128MB	0x03
#define Z3_MEM_256MB	0x04
#define Z3_MEM_512MB	0x05
#define Z3_MEM_1GB		0x06

#define chainedconfig	0x08 /* Next config is part of the same card */
#define rom_card	0x10 /* ROM vector is valid */
#define add_memory	0x20 /* Link RAM into free memory list */

/* Type of Expansion Card */
#define protoautoconfig 0x40
#define zorroII		0xc0
#define zorroIII	0x80

/* ********************************************************** */
/* 04 - 06 & 10-16 */

/* Manufacturer */
#define commodore_g	 513 /* Commodore Braunschweig (Germany) */
#define commodore	 514 /* Commodore West Chester */
#define gvp		2017 /* GVP */
#define ass		2102 /* Advanced Systems & Software */
#define hackers_id	2011 /* Special ID for test cards */

/* Card Type */
#define commodore_a2091	    3 /* A2091 / A590 Card from C= */
#define commodore_a2091_ram 10 /* A2091 / A590 Ram on HD-Card */
#define commodore_a2232	    70 /* A2232 Multiport Expansion */
#define ass_nexus_scsi	    1 /* Nexus SCSI Controller */

#define gvp_series_2_scsi   11
#define gvp_iv_24_gfx	    32

/* ********************************************************** */
/* 08 - 0A  */
/* er_Flags */
#define Z3_SS_MEM_SAME		0x00
#define Z3_SS_MEM_AUTO		0x01
#define Z3_SS_MEM_64KB		0x02
#define Z3_SS_MEM_128KB		0x03
#define Z3_SS_MEM_256KB		0x04
#define Z3_SS_MEM_512KB		0x05
#define Z3_SS_MEM_1MB		0x06 /* Zorro III card subsize */
#define Z3_SS_MEM_2MB		0x07
#define Z3_SS_MEM_4MB		0x08
#define Z3_SS_MEM_6MB		0x09
#define Z3_SS_MEM_8MB		0x0a
#define Z3_SS_MEM_10MB		0x0b
#define Z3_SS_MEM_12MB		0x0c
#define Z3_SS_MEM_14MB		0x0d
#define Z3_SS_MEM_defunct1	0x0e
#define Z3_SS_MEM_defunct2	0x0f

#define force_z3	0x10 /* *MUST* be set if card is Z3 */
#define ext_size	0x20 /* Use extended size table for bits 0-2 of er_Type */
#define no_shutup	0x40 /* Card cannot receive Shut_up_forever */
#define care_addr	0x80 /* Z2=Adress HAS to be $200000-$9fffff Z3=1->mem,0=io */

/* ********************************************************** */
/* 40-42 */
/* ec_interrupt (unused) */

#define enable_irq	0x01 /* enable Interrupt */
#define reset_card	0x04 /* Reset of Expansion Card - must be 0 */
#define card_int2	0x10 /* READ ONLY: IRQ 2 active */
#define card_irq6	0x20 /* READ ONLY: IRQ 6 active */
#define card_irq7	0x40 /* READ ONLY: IRQ 7 active */
#define does_irq	0x80 /* READ ONLY: Card currently throws IRQ */

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

/* ROM defines (DiagVec) */

#define rom_4bit	(0x00<<14) /* ROM width */
#define rom_8bit	(0x01<<14)
#define rom_16bit	(0x02<<14)

#define rom_never	(0x00<<12) /* Never run Boot Code */
#define rom_install	(0x01<<12) /* run code at install time */
#define rom_binddrv	(0x02<<12) /* run code with binddrivers */

uaecptr ROM_filesys_resname, ROM_filesys_resid;
uaecptr ROM_filesys_diagentry;
uaecptr ROM_hardfile_resname, ROM_hardfile_resid;
uaecptr ROM_hardfile_init;
int uae_boot_rom_type;
int uae_boot_rom_size; /* size = code size only */
static bool chipdone;
static int do_mount;

#define FILESYS_DIAGPOINT 0x01e0
#define FILESYS_BOOTPOINT 0x01f0
#define FILESYS_DIAGAREA 0x2000

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

struct card_data
{
	bool (*initrc)(struct autoconfig_info*);
	bool (*initnum)(struct autoconfig_info*);
	addrbank *(*map)(struct autoconfig_info*);
	struct romconfig *rc;
	const TCHAR *name;
	int flags;
	int zorro;
	uaecptr base;
	uae_u32 size;
	// parsing updated fields
	const struct expansionromtype *ert;
	const struct cpuboardsubtype *cst;
	struct autoconfig_info aci;
};

static struct card_data cards_set[MAX_EXPANSION_BOARD_SPACE];
static struct card_data *cards[MAX_EXPANSION_BOARD_SPACE];

static int ecard, cardno, z3num;
static int restore_cardno;
static addrbank *expamem_bank_current;

static uae_u16 uae_id;

static bool isnonautoconfig(int v)
{
	return v == BOARD_NONAUTOCONFIG_AFTER_Z2 ||
		v == BOARD_NONAUTOCONFIG_AFTER_Z3 ||
		v == BOARD_NONAUTOCONFIG_BEFORE;
}

static bool ks12orolder(void)
{
	/* check if Kickstart version is below 1.3 */
	return kickstart_version && kickstart_version < 34;
}
static bool ks11orolder(void)
{
	return kickstart_version && kickstart_version < 33;
}


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

/* Please note: ZorroIII implementation seems to work different
* than described in the HRM. This claims that ZorroIII config
* address is 0xff000000 while the ZorroII config space starts
* at 0x00e80000. In reality, both, Z2 and Z3 cards are
* configured in the ZorroII config space. Kickstart 3.1 doesn't
* even do a single read or write access to the ZorroIII space.
* The original Amiga include files tell the same as the HRM.
* ZorroIII: If you set ext_size in er_Flags and give a Z2-size
* in er_Type you can very likely add some ZorroII address space
* to a ZorroIII card on a real Amiga. This is not implemented
* yet.
*  -- Stefan
*
* Surprising that 0xFF000000 isn't used. Maybe it depends on the
* ROM. Anyway, the HRM says that Z3 cards may appear in Z2 config
* space, so what we are doing here is correct.
*  -- Bernd
*/

/* Autoconfig address space at 0xE80000 */
static uae_u8 expamem[65536 + 4];
static uae_u8 expamem_write_space[65536 + 4];
#define AUTOMATIC_AUTOCONFIG_MAX_ADDRESS 0x80
static int expamem_autoconfig_mode;
static addrbank*(*expamem_map)(struct autoconfig_info*);

static uae_u8 expamem_lo;
static uae_u16 expamem_hi;
uaecptr expamem_z3_pointer_real, expamem_z3_pointer_uae;
uaecptr expamem_z3_highram_real, expamem_z3_highram_uae;
uaecptr expamem_highmem_pointer;
uae_u32 expamem_board_size;
uaecptr expamem_board_pointer;
static uae_u8 slots_e8[8] = { 0 };
static uae_u8 slots_20[(8 * 1024 * 1024) / 65536] = { 0 };

static int z3hack_override;

void set_expamem_z3_hack_mode(int mode)
{
	z3hack_override = mode;
}

bool expamem_z3hack(struct uae_prefs *p)
{
	if (z3hack_override == Z3MAPPING_UAE)
		return true;
	if (z3hack_override == Z3MAPPING_REAL)
		return false;
	return p->z3_mapping_mode == Z3MAPPING_UAE || cpuboard_memorytype(p) == BOARD_MEMORY_BLIZZARD_12xx;
}

/* Ugly hack for >2M chip RAM in single pool
 * We can't add it any later or early boot menu
 * stops working because it sets kicktag at the end
 * of chip ram...
 */
static void addextrachip (uae_u32 sysbase)
{
	if (currprefs.chipmem.size <= 0x00200000)
		return;
	if (sysbase & 0x80000001)
		return;
	if (!valid_address (sysbase, 1000))
		return;
	uae_u32 ml = get_long (sysbase + 322);
	if (!valid_address (ml, 32))
		return;
	uae_u32 next;
	while ((next = get_long (ml))) {
		if (!valid_address (ml, 32))
			return;
		uae_u32 upper = get_long (ml + 24);
		uae_u32 lower = get_long (ml + 20);
		if (lower & ~0xffff) {
			ml = next;
			continue;
		}
		uae_u16 attr = get_word (ml + 14);
		if ((attr & 0x8002) != 2) {
			ml = next;
			continue;
		}
		if (upper >= currprefs.chipmem.size)
			return;
		uae_u32 added = currprefs.chipmem.size - upper;
		uae_u32 first = get_long (ml + 16);
		put_long (ml + 24, currprefs.chipmem.size); // mh_Upper
		put_long (ml + 28, get_long (ml + 28) + added); // mh_Free
		uae_u32 next = 0;
		while (first) {
			next = first;
			first = get_long (next);
		}
		if (next) {
			uae_u32 bytes = get_long(next + 4);
			if (next + bytes == 0x00200000) {
				put_long(next + 4, currprefs.chipmem.size - next);
			} else {
				put_long(0x00200000 + 0, 0);
				put_long(0x00200000 + 4, added);
				put_long(next, 0x00200000);
			}
		}
		return;
	}
}

addrbank expamem_null, expamem_none;

DECLARE_MEMORY_FUNCTIONS(expamem_write);
addrbank expamem_write_bank = {
	expamem_write_lget, expamem_write_wget, expamem_write_bget,
	expamem_write_lput, expamem_write_wput, expamem_write_bput,
	default_xlate, default_check, NULL, NULL, _T("Autoconfig Z2 WRITE"),
	dummy_lgeti, dummy_wgeti,
	ABFLAG_IO | ABFLAG_SAFE | ABFLAG_PPCIOSPACE, S_READ, S_WRITE
};
DECLARE_MEMORY_FUNCTIONS(expamem);
addrbank expamem_bank = {
	expamem_lget, expamem_wget, expamem_bget,
	expamem_lput, expamem_wput, expamem_bput,
	default_xlate, default_check, NULL, NULL, _T("Autoconfig Z2"),
	dummy_lgeti, dummy_wgeti,
	ABFLAG_IO | ABFLAG_SAFE | ABFLAG_PPCIOSPACE, S_READ, S_WRITE
};
DECLARE_MEMORY_FUNCTIONS(expamemz3);
static addrbank expamemz3_bank = {
	expamemz3_lget, expamemz3_wget, expamemz3_bget,
	expamemz3_lput, expamemz3_wput, expamemz3_bput,
	default_xlate, default_check, NULL, NULL, _T("Autoconfig Z3"),
	dummy_lgeti, dummy_wgeti,
	ABFLAG_IO | ABFLAG_SAFE | ABFLAG_PPCIOSPACE, S_READ, S_WRITE
};

static addrbank *expamem_map_clear (void)
{
	write_log (_T("expamem_map_clear() got called. Shouldn't happen.\n"));
	return NULL;
}

static void expamem_init_clear (void)
{
	memset (expamem, 0xff, sizeof expamem);
	expamem_hi = expamem_lo = 0;
	expamem_map = NULL;
}
/* autoconfig area is "non-existing" after last device */
static void expamem_init_clear_zero (void)
{
	if (currprefs.cpu_model < 68020) {
		map_banks(&dummy_bank, 0xe8, 1, 0);
		if (!currprefs.address_space_24)
			map_banks(&dummy_bank, AUTOCONFIG_Z3 >> 16, 1, 0);
	} else {
		map_banks(&expamem_bank, 0xe8, 1, 0);
		if (!currprefs.address_space_24)
			map_banks(&expamemz3_bank, AUTOCONFIG_Z3 >> 16, 1, 0);
	}
	expamem_bank_current = NULL;
}

static void expamem_init_clear2 (void)
{
	expamem_bank.name = _T("Autoconfig Z2");
	expamemz3_bank.name = _T("Autoconfig Z3");
	expamem_init_clear_zero ();
	ecard = cardno;
}

static addrbank *expamem_init_last (void)
{
	expamem_init_clear2 ();
	write_log (_T("Memory map after autoconfig:\n"));
	memory_map_dump ();
	mman_set_barriers(false);
	return NULL;
}

static uae_u8 REGPARAM2 expamem_read(int addr)
{
	uae_u8 b = (expamem[addr] & 0xf0) | (expamem[addr + 2] >> 4);
	if (addr == 0 || addr == 2 || addr == 0x40 || addr == 0x42)
		return b;
	b = ~b;
	return b;
}

static void REGPARAM2 expamem_write(uaecptr addr, uae_u32 value)
{
	addr &= 0xffff;
	if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
		expamem[addr] = (value & 0xf0);
		expamem[addr + 2] = (value & 0x0f) << 4;
	} else {
		expamem[addr] = ~(value & 0xf0);
		expamem[addr + 2] = ~((value & 0x0f) << 4);
	}
}

static int REGPARAM2 expamem_type (void)
{
	return expamem_read(0) & 0xc0;
}

void expansion_cpu_fallback(void)
{
	if (ecard < cardno) {
		card_data *cd = cards[ecard];
		if (cd->cst && (cd->cst->deviceflags & EXPANSIONTYPE_FALLBACK_DISABLE)) {
			expamem_next(NULL, NULL);
		}
	}
}

static void call_card_init(int index)
{	
	addrbank *ab, *abe;
	bool ok = false;
	card_data *cd = cards[ecard];
	struct autoconfig_info *aci = &cd->aci;

	if (currprefs.address_space_24 && cd->cst && (cd->cst->deviceflags & EXPANSIONTYPE_FALLBACK_DISABLE)) {
		write_log(_T("Card %d: skipping autoconfig (fallback mode)\n"), ecard);
		expamem_next(NULL, NULL);
		return;
	}

	expamem_bank.name = cd->name ? cd->name : _T("None");
	aci->prefs = &currprefs;
	aci->doinit = true;
	aci->devnum = (cd->flags >> 16) & 255;
	aci->ert = cd->ert;
	aci->cst = cd->cst;
	aci->rc = cd->rc;
	aci->zorro = cd->zorro;
	memset(aci->autoconfig_raw, 0xff, sizeof aci->autoconfig_raw);
	if (cd->initnum) {
		ok = cd->initnum(aci);
	} else {
		ok = cd->initrc(aci);
	}
	if (ok) {
		ab = NULL;
		if (!cd->map)
			ab = aci->addrbank;
	} else {
		write_log(_T("Card %d: skipping autoconfig (init failed)\n"), ecard);
		expamem_next(NULL, NULL);
		return;
	}
	if (ab == &expamem_none) {
		write_log(_T("Card %d: skipping autoconfig (none)\n"), ecard);
		expamem_init_clear();
		expamem_init_clear_zero();
		map_banks(&expamem_bank, 0xE8, 1, 0);
		if (!currprefs.address_space_24)
			map_banks(&dummy_bank, AUTOCONFIG_Z3 >> 16, 1, 0);
		expamem_bank_current = NULL;
		return;
	}
	if (ab == &expamem_null || cd->zorro < 1 || cd->zorro > 3 || aci->zorro < 0) {
		write_log(_T("Card %d: skipping autoconfig (not autoconfig)\n"), ecard);
		expamem_next(NULL, NULL);
		return;
	}

	expamem_board_pointer = cd->base;
	expamem_board_size = cd->size;

	abe = ab;
	if (!abe)
		abe = &expamem_bank;
	expamem_autoconfig_mode = 0;
	if (abe != &expamem_bank) {
		if (aci->autoconfig_automatic) {
			if (aci->autoconfigp) {
				memset(expamem, 0xff, AUTOMATIC_AUTOCONFIG_MAX_ADDRESS);
				for (int i = 0; i < 16; i++) {
					expamem_write(i * 4, aci->autoconfig_bytes[i]);
				}
				expamem_autoconfig_mode = 1;
			} else if (aci->autoconfig_bytes) {
				memset(expamem, 0xff, AUTOMATIC_AUTOCONFIG_MAX_ADDRESS);
				for (int i = 0; i < 16; i++) {
					expamem_write(i * 4, aci->autoconfig_bytes[i]);
				}
				expamem_autoconfig_mode = 1;
			} else if (aci->autoconfig_raw) {
				memcpy(expamem, aci->autoconfig_raw, sizeof aci->autoconfig_raw);
			}
		} else {
			for (int i = 0; i < 16 * 4; i++) {
				expamem[i] = abe->sub_banks ? abe->sub_banks[0].bank->bget(i) : abe->bget(i);
			}
		}
	}

	if (aci->write_bank_address && aci->write_bank_address != 0xffffffff) {
		map_banks(&expamem_write_bank, aci->write_bank_address >> 16, aci->size >> 16, 0);
	}

	if (ab) {
		// non-NULL: not using expamem_bank
		expamem_bank_current = ab;
		if ((cd->flags & CARD_FLAG_CAN_Z3) && currprefs.cs_z3autoconfig && !currprefs.address_space_24) {
			map_banks(&expamemz3_bank, AUTOCONFIG_Z3 >> 16, 1, 0);
			map_banks(&dummy_bank, 0xE8, 1, 0);
		} else {
			map_banks(&expamem_bank, 0xE8, 1, 0);
			if (!currprefs.address_space_24)
				map_banks(&dummy_bank, AUTOCONFIG_Z3 >> 16, 1, 0);
		}
	} else {
		if ((cd->flags & CARD_FLAG_CAN_Z3) && currprefs.cs_z3autoconfig && !currprefs.address_space_24) {
			map_banks(&expamemz3_bank, AUTOCONFIG_Z3 >> 16, 1, 0);
			map_banks(&dummy_bank, 0xE8, 1, 0);
			expamem_bank_current = &expamem_bank;
		} else {
			map_banks(&expamem_bank, 0xE8, 1, 0);
			if (!currprefs.address_space_24)
				map_banks(&dummy_bank, AUTOCONFIG_Z3 >> 16, 1, 0);
			expamem_bank_current = NULL;
		}
	}
}

static void boardmessage(addrbank *mapped, bool success)
{
	uae_u8 type = expamem_read(0);
	int size = expamem_board_size;
	TCHAR sizemod = 'K';

	size /= 1024;
	if (size > 8 * 1024) {
		sizemod = 'M';
		size /= 1024;
	}
	write_log (_T("Card %d: Z%d 0x%08x %4d%c %s %s%s\n"),
		ecard + 1, (type & 0xc0) == zorroII ? 2 : ((type & 0xc0) == zorroIII ? 3 : 1),
		expamem_board_pointer, size, sizemod,
		type & rom_card ? _T("ROM") : (type & add_memory ? _T("RAM") : _T("IO ")),
		mapped->name,
		success ? _T("") : _T(" [SHUT UP]"));
#if 0
	for (int i = 0; i < 16; i++) {
		write_log(_T("%s%02X"), i > 0 ? _T(".") : _T(""), expamem_read(i * 4));
	}
	write_log(_T("\n"));
#endif
}

void expamem_shutup(addrbank *mapped)
{
	if (mapped) {
		mapped->start = 0xffffffff;
		boardmessage(mapped, false);
	}
	expamem_next(mapped, NULL);
}

void expamem_next(addrbank *mapped, addrbank *next)
{
	if (mapped)
		boardmessage(mapped, mapped->start != 0xffffffff);

	expamem_init_clear();
	expamem_init_clear_zero();
	for (;;) {
		++ecard;
		if (ecard >= cardno)
			break;
		struct card_data *ec = cards[ecard];
		if (ec->zorro == 3 && ec->base == 0xffffffff) {
			write_log(_T("Autoconfig chain enumeration aborted, 32-bit address space overflow.\n"));
			ecard = cardno;
			break;
		}
		if (ec->initrc && isnonautoconfig(ec->zorro)) {
			struct autoconfig_info aci = { 0 };
			aci.doinit = true;
			aci.prefs = &currprefs;
			aci.rc = cards[ecard]->rc;
			aci.devnum = (ec->flags >> 16) & 255;
			ec->initrc(&aci);
		} else {
			call_card_init(ecard);
			break;
		}
	}
	if (ecard >= cardno) {
		expamem_init_clear2();
		expamem_init_last();
	}
}

static void expamemz3_map(void)
{
	uaecptr addr = ((expamem_hi << 8) | expamem_lo) << 16;
	if (!expamem_z3hack(&currprefs)) {
		expamem_board_pointer = addr;
	} else {
		if (addr != expamem_board_pointer) {
			put_word (regs.regs[11] + 0x20, expamem_board_pointer >> 16);
			put_word (regs.regs[11] + 0x28, expamem_board_pointer >> 16);
		}
	}
}

// only for custom autoconfig device development purposes, not in use in any normal config
static uae_u32 REGPARAM2 expamem_write_lget(uaecptr addr)
{
	addr &= 0xffff;
	return (expamem_write_space[addr + 0] << 24) | (expamem_write_space[addr + 1] << 16) | (expamem_write_space[addr + 2] << 8) | (expamem_write_space[addr + 3] << 0);
}
static uae_u32 REGPARAM2 expamem_write_wget(uaecptr addr)
{
	addr &= 0xffff;
	return (expamem_write_space[addr + 0] << 8) | (expamem_write_space[addr + 1] << 0);
}
static uae_u32 REGPARAM2 expamem_write_bget(uaecptr addr)
{
	addr &= 0xffff;
	return expamem_write_space[addr];
}
static void REGPARAM2 expamem_write_lput(uaecptr addr, uae_u32 value)
{
	addr &= 0xffff;
	expamem_write_space[addr + 0] = value >> 24;
	expamem_write_space[addr + 1] = value >> 16;
	expamem_write_space[addr + 2] = value >>  8;
	expamem_write_space[addr + 3] = value >>  0;
}
static void REGPARAM2 expamem_write_wput(uaecptr addr, uae_u32 value)
{
	addr &= 0xffff;
	expamem_write_space[addr + 0] = value >> 8;
	expamem_write_space[addr + 1] = value;
}
static void REGPARAM2 expamem_write_bput(uaecptr addr, uae_u32 value)
{
	addr &= 0xffff;
	expamem_write_space[addr] = value;
}

static uae_u32 REGPARAM2 expamem_lget (uaecptr addr)
{
	if (expamem_bank_current && expamem_bank_current != &expamem_bank) {
		if (expamem_autoconfig_mode && (addr & 0xffff) < AUTOMATIC_AUTOCONFIG_MAX_ADDRESS) {
			return (expamem_wget(addr) << 16) | expamem_wget(addr + 2);
		}
		return expamem_bank_current->sub_banks ? expamem_bank_current->sub_banks[0].bank->lget(addr) : expamem_bank_current->lget(addr);
	}
	write_log (_T("warning: Z2 READ.L from address $%08x PC=%x\n"), addr, M68K_GETPC);
	return (expamem_wget (addr) << 16) | expamem_wget (addr + 2);
}

static uae_u32 REGPARAM2 expamem_wget (uaecptr addr)
{
	if (expamem_bank_current && expamem_bank_current != &expamem_bank) {
		if (expamem_autoconfig_mode && (addr & 0xffff) < AUTOMATIC_AUTOCONFIG_MAX_ADDRESS) {
			return (expamem_bget(addr) << 8) | expamem_bget(addr + 1);
		}
		return expamem_bank_current->sub_banks ? expamem_bank_current->sub_banks[0].bank->wget(addr) : expamem_bank_current->wget(addr);
	}
	if (expamem_type() != zorroIII) {
		if (expamem_bank_current && expamem_bank_current != &expamem_bank)
			return expamem_bank_current->bget(addr) << 8;
	}
	uae_u32 v = (expamem_bget (addr) << 8) | expamem_bget (addr + 1);
	if (cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8) {
		uae_u32 val = v;
		cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8(addr, &val, 2, false);
		v = val;
	}
	write_log (_T("warning: READ.W from address $%08x=%04x PC=%x\n"), addr, v & 0xffff, M68K_GETPC);
	return v;
}

static uae_u32 REGPARAM2 expamem_bget (uaecptr addr)
{
	uae_u8 b;
	if (!chipdone) {
		chipdone = true;
		addextrachip (get_long (4));
	}
	if (expamem_bank_current && expamem_bank_current != &expamem_bank) {
		if (expamem_autoconfig_mode && (addr & 0xffff) < AUTOMATIC_AUTOCONFIG_MAX_ADDRESS) {
			return expamem[addr & 0xffff];
		}
		return expamem_bank_current->sub_banks ? expamem_bank_current->sub_banks[0].bank->bget(addr) : expamem_bank_current->bget(addr);
	}
	addr &= 0xFFFF;
	b = expamem[addr];
	if (cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8) {
		uae_u32 val = b;
		cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8(addr, &val, 1, false);
		b = val;
	}
#if EXP_DEBUG
	write_log (_T("expamem_bget %x %x\n"), addr, b);
#endif
	return b;
}

static void REGPARAM2 expamem_lput (uaecptr addr, uae_u32 value)
{
	if (expamem_bank_current && expamem_bank_current != &expamem_bank) {
		if (expamem_autoconfig_mode && (addr & 0xffff) < AUTOMATIC_AUTOCONFIG_MAX_ADDRESS) {
			return;
		}
		expamem_bank_current->sub_banks ? expamem_bank_current->sub_banks[0].bank->lput(addr, value) : expamem_bank_current->lput(addr, value);
		return;
	}
	write_log (_T("warning: Z2 WRITE.L to address $%08x : value $%08x\n"), addr, value);
}

static void REGPARAM2 expamem_wput (uaecptr addr, uae_u32 value)
{
#if EXP_DEBUG
	write_log (_T("expamem_wput %x %x\n"), addr, value);
#endif
	value &= 0xffff;
	if (cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8) {
		if (cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8(addr, &value, 2, true))
			return;
	}
	if (ecard >= cardno)
		return;
	card_data *cd = cards[ecard];
	if (!expamem_map)
		expamem_map = cd->map;
	if (expamem_type () != zorroIII) {
		write_log (_T("warning: WRITE.W to address $%08x : value $%x PC=%08x\n"), addr, value, M68K_GETPC);
	}
	switch (addr & 0xff) {
	case 0x48:
		// A2630 boot rom writes WORDs to Z2 boards!
		if (expamem_type() == zorroII) {
			expamem_lo = 0;
			expamem_hi = (value >> 8) & 0xff;
			expamem_board_pointer = (expamem_hi | (expamem_lo >> 4)) << 16;
			if (expamem_map) {
				expamem_next(expamem_map(&cd->aci), NULL);
				return;
			}
			if (expamem_autoconfig_mode) {
				map_banks_z2(cd->aci.addrbank, expamem_board_pointer >> 16, expamem_board_size >> 16);
				cd->aci.postinit = true;
				cd->initrc(&cd->aci);
				expamem_next(cd->aci.addrbank, NULL);
				return;
			}
			if (expamem_bank_current && expamem_bank_current != &expamem_bank) {
				expamem_bank_current->sub_banks ? expamem_bank_current->sub_banks[0].bank->bput(addr, value >> 8) : expamem_bank_current->bput(addr, value >> 8);
				return;
			}
		}
		// Z3 = do nothing
		break;
	case 0x44:
		if (expamem_type() == zorroIII) {
			expamem_hi = (value & 0xff00) >> 8;
			expamem_lo = value & 0x00ff;
			expamemz3_map();
		}
		if (expamem_map) {
			expamem_next(expamem_map(&cd->aci), NULL);
			return;
		}
		if (expamem_autoconfig_mode) {
			map_banks_z3(cd->aci.addrbank, expamem_board_pointer >> 16, expamem_board_size >> 16);
			cd->aci.postinit = true;
			cd->initrc(&cd->aci);
			expamem_next(cd->aci.addrbank, NULL);
			return;
		}
		break;
	case 0x4c:
		if (expamem_map) {
			expamem_next (NULL, NULL);
			return;
		}
		break;
	}
	if (expamem_bank_current && expamem_bank_current != &expamem_bank) {
		expamem_bank_current->sub_banks ? expamem_bank_current->sub_banks[0].bank->wput(addr, value) : expamem_bank_current->wput(addr, value);
	}
}

static void REGPARAM2 expamem_bput (uaecptr addr, uae_u32 value)
{
#if EXP_DEBUG
	write_log (_T("expamem_bput %x %x\n"), addr, value);
#endif
	value &= 0xff;
	if (cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8) {
		if (cpuboards[currprefs.cpuboard_type].subtypes[currprefs.cpuboard_subtype].e8(addr, &value, 1, true))
			return;
	}
	if (ecard >= cardno)
		return;
	card_data *cd = cards[ecard];
	if (!expamem_map)
		expamem_map = cd->map;
	if (expamem_type() == protoautoconfig) {
		switch (addr & 0xff) {
		case 0x22:
			expamem_hi = value & 0x7f;
			expamem_board_pointer = AUTOCONFIG_Z2 | (expamem_hi * 4096);
			if (expamem_map) {
				expamem_next(expamem_map(&cd->aci), NULL);
				return;
			}
			break;
		}
	} else {
		switch (addr & 0xff) {
		case 0x48:
			if (expamem_type() == zorroII) {
				expamem_hi = value & 0xff;
				expamem_board_pointer = (expamem_hi | (expamem_lo >> 4)) << 16;
				if (expamem_map) {
					expamem_next(expamem_map(&cd->aci), NULL);
					return;
				}
				if (expamem_autoconfig_mode) {
					map_banks_z2(cd->aci.addrbank, expamem_board_pointer >> 16, expamem_board_size >> 16);
					cd->aci.postinit = true;
					cd->initrc(&cd->aci);
					expamem_next(cd->aci.addrbank, NULL);
					return;
				}
			} else {
				expamem_lo = value & 0xff;
			}
			break;
		case 0x44:
			if (expamem_type() == zorroIII) {
				expamem_hi = value & 0xff;
				expamemz3_map();
				if (expamem_map) {
					expamem_next(expamem_map(&cd->aci), NULL);
					return;
				}
				if (expamem_autoconfig_mode) {
					map_banks_z3(cd->aci.addrbank, expamem_board_pointer >> 16, expamem_board_size >> 16);
					cd->aci.postinit = true;
					cd->initrc(&cd->aci);
					expamem_next(cd->aci.addrbank, NULL);
					return;
				}
			}
			break;
		case 0x4a:
			if (expamem_type () == zorroII) {
				expamem_lo = value & 0xff;
			}
			if (expamem_autoconfig_mode)
				return;
			break;

		case 0x4c:
			if (expamem_map) {
				expamem_hi = expamem_lo = 0xff;
				expamem_board_pointer = 0xffffffff;
				addrbank *ab = expamem_map(&cd->aci);
				if (ab)
					ab->start = 0xffffffff;
				expamem_next(ab, NULL);
				return;
			}
			break;
		}
	}
	if (expamem_bank_current && expamem_bank_current != &expamem_bank) {
		expamem_bank_current->sub_banks ? expamem_bank_current->sub_banks[0].bank->bput(addr, value) : expamem_bank_current->bput(addr, value);
	}
}

static uae_u32 REGPARAM2 expamemz3_bget (uaecptr addr)
{
	int reg = addr & 0xff;
	if (!expamem_bank_current)
		return 0;
	if (addr & 0x100)
		reg += 2;
	return expamem_bank_current->bget(reg + 0);
}

static uae_u32 REGPARAM2 expamemz3_wget (uaecptr addr)
{
	uae_u32 v = (expamemz3_bget (addr) << 8) | expamemz3_bget (addr + 1);
	write_log (_T("warning: Z3 READ.W from address $%08x=%04x PC=%x\n"), addr, v & 0xffff, M68K_GETPC);
	return v;
}

static uae_u32 REGPARAM2 expamemz3_lget (uaecptr addr)
{
	write_log (_T("warning: Z3 READ.L from address $%08x PC=%x\n"), addr, M68K_GETPC);
	return (expamemz3_wget (addr) << 16) | expamemz3_wget (addr + 2);
}

static void REGPARAM2 expamemz3_bput (uaecptr addr, uae_u32 value)
{
	int reg = addr & 0xff;
	if (!expamem_bank_current)
		return;
	if (addr & 0x100)
		reg += 2;
	if (reg == 0x48) {
		if (expamem_type() == zorroII) {
			expamem_hi = value & 0xff;
			expamem_board_pointer = (expamem_hi | (expamem_lo >> 4)) << 16;
		} else {
			expamem_lo = value & 0xff;
		}
	} else if (reg == 0x44) {
		if (expamem_type() == zorroIII) {
			expamem_hi = value & 0xff;
			expamemz3_map();
		}
	} else if (reg == 0x4a) {
		if (expamem_type() == zorroII)
			expamem_lo = value & 0xff;
	}
	expamem_bank_current->bput(reg, value);
}

static void REGPARAM2 expamemz3_wput (uaecptr addr, uae_u32 value)
{
	int reg = addr & 0xff;
	if (!expamem_bank_current)
		return;
	if (addr & 0x100)
		reg += 2;
	if (reg == 0x44) {
		if (expamem_type() == zorroIII) {
			expamem_hi = (value & 0xff00) >> 8;
			expamem_lo = value & 0x00ff;
			expamemz3_map();
		}
	}
	expamem_bank_current->wput(reg, value);
}
static void REGPARAM2 expamemz3_lput (uaecptr addr, uae_u32 value)
{
	write_log (_T("warning: Z3 WRITE.L to address $%08x : value $%08x\n"), addr, value);
}

#ifdef CD32

static bool expamem_init_cd32fmv (struct autoconfig_info *aci)
{
	expamem_init_clear ();
	load_rom_rc(aci->rc, ROMTYPE_CD32CART, 262144, 0, expamem, 128, 0);
	memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);
	expamem_map = cd32_fmv_init;
	return true;
}

#endif

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

MEMORY_ARRAY_FUNCTIONS(romboardmem, 0);
MEMORY_ARRAY_FUNCTIONS(romboardmem, 1);
MEMORY_ARRAY_FUNCTIONS(romboardmem, 2);
MEMORY_ARRAY_FUNCTIONS(romboardmem, 3);

static void REGPARAM2 empty_put(uaecptr addr, uae_u32 v)
{
}

addrbank romboardmem_bank[MAX_ROM_BOARDS] =
{
	{
		romboardmem0_lget, romboardmem0_wget, romboardmem0_bget,
		empty_put, empty_put, empty_put,
		romboardmem0_xlate, romboardmem0_check, NULL, _T("*"), _T("ROM board"),
		romboardmem0_lget, romboardmem0_wget,
		ABFLAG_ROM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		romboardmem1_lget, romboardmem1_wget, romboardmem1_bget,
		empty_put, empty_put, empty_put,
		romboardmem1_xlate, romboardmem1_check, NULL, _T("*"), _T("ROM board"),
		romboardmem1_lget, romboardmem1_wget,
		ABFLAG_ROM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		romboardmem2_lget, romboardmem2_wget, romboardmem2_bget,
		empty_put, empty_put, empty_put,
		romboardmem2_xlate, romboardmem2_check, NULL, _T("*"), _T("ROM board"),
		romboardmem2_lget, romboardmem2_wget,
		ABFLAG_ROM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		romboardmem3_lget, romboardmem3_wget, romboardmem3_bget,
		empty_put, empty_put, empty_put,
		romboardmem3_xlate, romboardmem3_check, NULL, _T("*"), _T("ROM board"),
		romboardmem3_lget, romboardmem3_wget,
		ABFLAG_ROM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	}
};

/*
*  Fast Memory
*/


MEMORY_ARRAY_FUNCTIONS(fastmem, 0);
MEMORY_ARRAY_FUNCTIONS(fastmem, 1);
MEMORY_ARRAY_FUNCTIONS(fastmem, 2);
MEMORY_ARRAY_FUNCTIONS(fastmem, 3);

addrbank fastmem_bank[MAX_RAM_BOARDS] =
{
	{
		fastmem0_lget, fastmem0_wget, fastmem0_bget,
		fastmem0_lput, fastmem0_wput, fastmem0_bput,
		fastmem0_xlate, fastmem0_check, NULL, _T("*"), _T("Fast memory"),
		fastmem0_lget, fastmem0_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		fastmem1_lget, fastmem1_wget, fastmem1_bget,
		fastmem1_lput, fastmem1_wput, fastmem1_bput,
		fastmem1_xlate, fastmem1_check, NULL, _T("*"), _T("Fast memory 2"),
		fastmem1_lget, fastmem1_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		fastmem2_lget, fastmem2_wget, fastmem2_bget,
		fastmem2_lput, fastmem2_wput, fastmem2_bput,
		fastmem2_xlate, fastmem2_check, NULL, _T("*"), _T("Fast memory 3"),
		fastmem2_lget, fastmem2_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		fastmem3_lget, fastmem3_wget, fastmem3_bget,
		fastmem3_lput, fastmem3_wput, fastmem3_bput,
		fastmem3_xlate, fastmem3_check, NULL, _T("*"), _T("Fast memory 4"),
		fastmem3_lget, fastmem3_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	}
};

#ifdef CATWEASEL

/*
* Catweasel ZorroII
*/

DECLARE_MEMORY_FUNCTIONS(catweasel);

static uae_u32 catweasel_mask;
static uae_u32 catweasel_start;

static uae_u32 REGPARAM2 catweasel_lget (uaecptr addr)
{
	write_log (_T("catweasel_lget @%08X!\n"),addr);
	return 0;
}

static uae_u32 REGPARAM2 catweasel_wget (uaecptr addr)
{
	write_log (_T("catweasel_wget @%08X!\n"),addr);
	return 0;
}

static uae_u32 REGPARAM2 catweasel_bget (uaecptr addr)
{
	addr -= catweasel_start & catweasel_mask;
	addr &= catweasel_mask;
	return catweasel_do_bget (addr);
}

static void REGPARAM2 catweasel_lput (uaecptr addr, uae_u32 l)
{
	write_log (_T("catweasel_lput @%08X=%08X!\n"),addr,l);
}

static void REGPARAM2 catweasel_wput (uaecptr addr, uae_u32 w)
{
	write_log (_T("catweasel_wput @%08X=%04X!\n"),addr,w);
}

static void REGPARAM2 catweasel_bput (uaecptr addr, uae_u32 b)
{
	addr -= catweasel_start & catweasel_mask;
	addr &= catweasel_mask;
	catweasel_do_bput (addr, b);
}

static int REGPARAM2 catweasel_check (uaecptr addr, uae_u32 size)
{
	return 0;
}

static uae_u8 *REGPARAM2 catweasel_xlate (uaecptr addr)
{
	write_log (_T("catweasel_xlate @%08X size %08X\n"), addr);
	return 0;
}

static addrbank catweasel_bank = {
	catweasel_lget, catweasel_wget, catweasel_bget,
	catweasel_lput, catweasel_wput, catweasel_bput,
	catweasel_xlate, catweasel_check, NULL, NULL, _T("Catweasel"),
	dummy_lgeti, dummy_wgeti,
	ABFLAG_IO, S_READ, S_WRITE
};

static addrbank *expamem_map_catweasel(struct autoconfig_info *aci)
{
	catweasel_start = expamem_board_pointer;
	map_banks_z2(&catweasel_bank, catweasel_start >> 16, 1);
	return &catweasel_bank;
}

static bool expamem_init_catweasel (struct autoconfig_info *aci)
{
	uae_u8 productid = cwc.type >= CATWEASEL_TYPE_MK3 ? 66 : 200;
	uae_u16 vendorid = cwc.type >= CATWEASEL_TYPE_MK3 ? 4626 : 5001;

	catweasel_mask = (cwc.type >= CATWEASEL_TYPE_MK3) ? 0xffff : 0x1ffff;

	expamem_init_clear ();

	expamem_write (0x00, (cwc.type >= CATWEASEL_TYPE_MK3 ? Z2_MEM_64KB : Z2_MEM_128KB) | zorroII);

	expamem_write (0x04, productid);

	expamem_write (0x08, 0);

	expamem_write (0x10, vendorid >> 8);
	expamem_write (0x14, vendorid & 0xff);

	expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
	expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
	expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
	expamem_write (0x24, 0x00); /* ser.no. Byte 3 */

	expamem_write (0x28, 0x00); /* Rom-Offset hi */
	expamem_write (0x2c, 0x00); /* ROM-Offset lo */

	expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/

	memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);

	expamem_map = expamem_map_catweasel;

	return true;
}

#endif

#ifdef FILESYS

/*
* Filesystem device ROM/RAM space
*/

DECLARE_MEMORY_FUNCTIONS(filesys);
addrbank filesys_bank = {
	filesys_lget, filesys_wget, filesys_bget,
	filesys_lput, filesys_wput, filesys_bput,
	filesys_xlate, filesys_check, NULL, _T("*"), _T("Filesystem autoconfig"),
	filesys_lget, filesys_wget,
	ABFLAG_IO | ABFLAG_SAFE | ABFLAG_PPCIOSPACE, S_READ, S_WRITE
};

static bool filesys_write(uaecptr addr)
{
	return addr >= 0x4000;
}

static uae_u32 REGPARAM2 filesys_lget (uaecptr addr)
{
	uae_u8 *m;
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
	m = filesys_bank.baseaddr + addr;
#if EXP_DEBUG
	write_log (_T("filesys_lget %x %x\n"), addr, do_get_mem_long ((uae_u32 *)m));
#endif
	return do_get_mem_long ((uae_u32 *)m);
}

static uae_u32 REGPARAM2 filesys_wget (uaecptr addr)
{
	uae_u8 *m;
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
	m = filesys_bank.baseaddr + addr;
#if EXP_DEBUG
	write_log (_T("filesys_wget %x %x\n"), addr, do_get_mem_word ((uae_u16 *)m));
#endif
	return do_get_mem_word ((uae_u16 *)m);
}

static uae_u32 REGPARAM2 filesys_bget (uaecptr addr)
{
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
#if EXP_DEBUG
	write_log (_T("filesys_bget %x %x\n"), addr, filesys_bank.baseaddr[addr]);
#endif
	return filesys_bank.baseaddr[addr];
}


static void REGPARAM2 filesys_bput(uaecptr addr, uae_u32 b)
{
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
	if (!filesys_write(addr))
		return;
	filesys_bank.baseaddr[addr] = b;
}

static void REGPARAM2 filesys_lput (uaecptr addr, uae_u32 l)
{
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
	if (!filesys_write(addr))
		return;
	filesys_bank.baseaddr[addr + 0] = l >> 24;
	filesys_bank.baseaddr[addr + 1] = l >> 16;
	filesys_bank.baseaddr[addr + 2] = l >> 8;
	filesys_bank.baseaddr[addr + 3] = l >> 0;
}

static void REGPARAM2 filesys_wput (uaecptr addr, uae_u32 w)
{
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
	if (!filesys_write(addr))
		return;
	filesys_bank.baseaddr[addr + 0] = w >> 8;
	filesys_bank.baseaddr[addr + 1] = w & 0xff;
}

static int REGPARAM2 filesys_check(uaecptr addr, uae_u32 size)
{
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
	return (addr + size) <= filesys_bank.allocated_size;
}
static uae_u8 *REGPARAM2 filesys_xlate(uaecptr addr)
{
	addr -= filesys_bank.start & 65535;
	addr &= 65535;
	return filesys_bank.baseaddr + addr;
}

#endif /* FILESYS */

DECLARE_MEMORY_FUNCTIONS(uaeboard);
addrbank uaeboard_bank = {
	uaeboard_lget, uaeboard_wget, uaeboard_bget,
	uaeboard_lput, uaeboard_wput, uaeboard_bput,
	uaeboard_xlate, uaeboard_check, NULL, _T("*"), _T("UAE Board"),
	dummy_lgeti, dummy_wgeti,
	ABFLAG_IO | ABFLAG_SAFE | ABFLAG_PPCIOSPACE, S_READ, S_WRITE
};

uae_u32 uaeboard_base; /* Determined by the OS */
static uae_u32 uaeboard_ram_start;
#define UAEBOARD_WRITEOFFSET 0x4000

uae_u8 *uaeboard_map_ram(uaecptr p)
{
	if (currprefs.uaeboard > 1) {
		p -= uaeboard_base;
		return uaeboard_bank.baseaddr + p;
	} else {
		p -= filesys_bank.start;
		return filesys_bank.baseaddr + p;
	}
}

uaecptr uaeboard_alloc_ram(uae_u32 size)
{
	uaecptr p;
	size += 7;
	size &= ~7;
	if (currprefs.uaeboard > 1) {
		p = uaeboard_ram_start + uaeboard_base;
		memset(uaeboard_bank.baseaddr + uaeboard_ram_start, 0, size);
	} else {
		p = uaeboard_ram_start + filesys_bank.start;
		memset(filesys_bank.baseaddr + uaeboard_ram_start, 0, size);
	}
	uaeboard_ram_start += size;
	return p;
}

static bool uaeboard_write(uaecptr addr)
{
	if (addr >= UAEBOARD_WRITEOFFSET)
		return true;
	return false;
}

static uae_u32 REGPARAM2 uaeboard_wget(uaecptr addr)
{
	uae_u8 *m;
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	m = uaeboard_bank.baseaddr + addr;
	uae_u16 v = do_get_mem_word((uae_u16 *)m);
	return v;
}

static uae_u32 REGPARAM2 uaeboard_lget(uaecptr addr)
{
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	uae_u32 v = uaeboard_wget(addr) << 16;
	v |= uaeboard_wget(addr + 2);
	return v;
}

static uae_u32 REGPARAM2 uaeboard_bget(uaecptr addr)
{
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	return uaeboard_bank.baseaddr[addr];
}

static void REGPARAM2 uaeboard_wput(uaecptr addr, uae_u32 w)
{
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	if (!uaeboard_write(addr))
		return;
	uae_u8 *m = uaeboard_bank.baseaddr + addr;
	put_word_host(m, w);
}

static void REGPARAM2 uaeboard_lput(uaecptr addr, uae_u32 l)
{
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	if (!uaeboard_write(addr))
		return;
	uaeboard_wput(addr, l >> 16);
	uaeboard_wput(addr + 2, l);
}

static void REGPARAM2 uaeboard_bput(uaecptr addr, uae_u32 b)
{
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	if (!uaeboard_write(addr))
		return;
	uaeboard_bank.baseaddr[addr] = b;
}

static int REGPARAM2 uaeboard_check(uaecptr addr, uae_u32 size)
{
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	return (addr + size) <= uaeboard_bank.allocated_size;
}
static uae_u8 *REGPARAM2 uaeboard_xlate(uaecptr addr)
{
	addr -= uaeboard_base & 65535;
	addr &= 65535;
	return uaeboard_bank.baseaddr + addr;
}

static addrbank *expamem_map_uaeboard(struct autoconfig_info *aci)
{
	uaeboard_base = expamem_board_pointer;
	uaeboard_ram_start = UAEBOARD_WRITEOFFSET;
	uaeboard_bank.start = uaeboard_base;
	map_banks_z2(&uaeboard_bank, uaeboard_base >> 16, 1);
	if (currprefs.uaeboard > 1) {
		rtarea_bank.start = uaeboard_base + 65536;
		map_banks_z2(&rtarea_bank, (uaeboard_base + 65536) >> 16, 1);
		ce_cachable[(uaeboard_base + 65536) >> 16] = CACHE_DISABLE_ALLOCATE;
	}
	return &uaeboard_bank;
}

static bool get_params_filesys(struct uae_prefs *prefs, struct expansion_params *p)
{
	p->device_order = prefs->uaeboard_order;
	return true;
}
static bool set_params_filesys(struct uae_prefs *prefs, struct expansion_params *p)
{
	prefs->uaeboard_order = p->device_order;
	return true;
}

static void add_rtarea_pointer(struct autoconfig_info *aci)
{
	if (aci->doinit) {
		uaecptr addr = 0;
		if (aci->prefs->uaeboard > 1) {
			addr = aci->start + 0x10000;
		} else if (aci->prefs->uaeboard == 1) {
			addr = rtarea_base;
		}
		if (addr) {
			expamem[0x48] = addr >> 24;
			expamem[0x49] = addr >> 16;
			expamem[0x4a] = addr >> 8;
			expamem[0x4b] = addr >> 0;
		}
	}
}

static bool expamem_init_uaeboard(struct autoconfig_info *aci)
{
	bool ks12 = ks12orolder();
	struct uae_prefs *p = aci->prefs;
	bool hide = p->uae_hide_autoconfig;
	bool rom = p->uaeboard > 1;

	aci->label = _T("UAE Boot ROM");
	aci->addrbank = &uaeboard_bank;
	aci->get_params = get_params_filesys;
	aci->set_params = set_params_filesys;

	expamem_init_clear();
	expamem_write(0x00, (p->uaeboard > 1 ? Z2_MEM_128KB : Z2_MEM_64KB) | zorroII | (ks12 || !rom || p->uaeboard_nodiag ? 0 : rom_card));

	expamem_write(0x08, no_shutup);

	expamem_write(0x04, 1);
	expamem_write(0x10, 6502 >> 8);
	expamem_write(0x14, 6502 & 0xff);

	expamem_write(0x18, 0x00); /* ser.no. Byte 0 */
	expamem_write(0x1c, 0x00); /* ser.no. Byte 1 */
	expamem_write(0x20, p->uaeboard); /* ser.no. Byte 2 */
	expamem_write(0x24, 0x03); /* ser.no. Byte 3 */

	uae_u8 *ptr = uaeboard_bank.baseaddr;

	add_rtarea_pointer(aci);

	if (rom) {

		int diagoffset = 0x80;
		int diagpoint = 24;
		int bootpoint = diagpoint + 16;
		/* struct DiagArea - the size has to be large enough to store several device ROMTags */
		const uae_u8 diagarea[] = {
			0x90, 0x00, /* da_Config, da_Flags */
			0x03, 0x00, /* da_Size */
			(uae_u8)(diagpoint >> 8), (uae_u8)diagpoint,
			(uae_u8)(bootpoint >> 8), (uae_u8)bootpoint,
			0, (uae_u8)(hide ? 0 : 14), // Name offset
			0, 0, 0, 0,
			(uae_u8)(hide ? 0 : 'U'), (uae_u8)(hide ? 0 : 'A'), (uae_u8)(hide ? 0 : 'E'), 0
		};
		expamem_write(0x28, diagoffset >> 8); /* ROM-Offset hi */
		expamem_write(0x2c, diagoffset & 0xff); /* ROM-Offset lo */
	   /* Build a DiagArea */
		memcpy(expamem + diagoffset, diagarea, sizeof diagarea);
		diagpoint += diagoffset;
		bootpoint += diagoffset;

		if (aci->doinit) {
			put_word_host(expamem + diagpoint + 0, 0x7000 |
				(p->uaeboard > 2 ? 1 : 0) | (p->uae_hide_autoconfig || p->uaeboard > 1 ? 0 : 2)); // MOVEQ #x,D0
			/* Call hwtrap_install */
			put_word_host(expamem + diagpoint + 2, 0x4EB9); /* JSR */
			put_long_host(expamem + diagpoint + 4, filesys_get_entry(9));
			/* Call DiagEntry */
			put_word_host(expamem + diagpoint + 8, 0x4EF9); /* JMP */
			put_long_host(expamem + diagpoint + 10, ROM_filesys_diagentry);

			/* What comes next is a plain bootblock */
			put_word_host(expamem + bootpoint + 0, 0x4EF9); /* JMP */
			put_long_host(expamem + bootpoint + 2, EXPANSION_bootcode);

			put_long_host(rtarea_bank.baseaddr + RTAREA_FSBOARD, uaeboard_bank.start + 0x2000);
		}

	} else {

		expamem_write(0x28, 0x00); /* ROM-Offset hi */
		expamem_write(0x2c, 0x00); /* ROM-Offset lo */

	}

	memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);

	if (!aci->doinit)
		return true;

	memcpy(ptr, expamem, 0x100);

	return true;
}

/*
*  Z3fastmem Memory
*/

MEMORY_ARRAY_FUNCTIONS(z3fastmem, 0);
MEMORY_ARRAY_FUNCTIONS(z3fastmem, 1);
MEMORY_ARRAY_FUNCTIONS(z3fastmem, 2);
MEMORY_ARRAY_FUNCTIONS(z3fastmem, 3);

addrbank z3fastmem_bank[MAX_RAM_BOARDS] =
{
	{
		z3fastmem0_lget, z3fastmem0_wget, z3fastmem0_bget,
		z3fastmem0_lput, z3fastmem0_wput, z3fastmem0_bput,
		z3fastmem0_xlate, z3fastmem0_check, NULL, _T("*"), _T("Zorro III Fast RAM"),
		z3fastmem0_lget, z3fastmem0_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		z3fastmem1_lget, z3fastmem1_wget, z3fastmem1_bget,
		z3fastmem1_lput, z3fastmem1_wput, z3fastmem1_bput,
		z3fastmem1_xlate, z3fastmem1_check, NULL, _T("*"), _T("Zorro III Fast RAM #2"),
		z3fastmem1_lget, z3fastmem1_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		z3fastmem2_lget, z3fastmem2_wget, z3fastmem2_bget,
		z3fastmem2_lput, z3fastmem2_wput, z3fastmem2_bput,
		z3fastmem2_xlate, z3fastmem2_check, NULL, _T("*"), _T("Zorro III Fast RAM #3"),
		z3fastmem2_lget, z3fastmem2_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	},
	{
		z3fastmem3_lget, z3fastmem3_wget, z3fastmem3_bget,
		z3fastmem3_lput, z3fastmem3_wput, z3fastmem3_bput,
		z3fastmem3_xlate, z3fastmem3_check, NULL, _T("*"), _T("Zorro III Fast RAM #4"),
		z3fastmem3_lget, z3fastmem3_wget,
		ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL | ABFLAG_DIRECTACCESS, 0, 0
	}
};

MEMORY_FUNCTIONS(z3chipmem);

addrbank z3chipmem_bank = {
	z3chipmem_lget, z3chipmem_wget, z3chipmem_bget,
	z3chipmem_lput, z3chipmem_wput, z3chipmem_bput,
	z3chipmem_xlate, z3chipmem_check, NULL, _T("*"), _T("MegaChipRAM"),
	z3chipmem_lget, z3chipmem_wget,
	ABFLAG_RAM | ABFLAG_THREADSAFE | ABFLAG_CACHE_ENABLE_ALL, 0, 0
};

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

/*
*     Expansion Card (ZORRO II) for 64/128/256/512KB 1/2/4/8MB of Fast Memory
*/

static addrbank *expamem_map_fastcard(struct autoconfig_info *aci)
{
	int devnum = aci->devnum;
	uae_u32 start = ((expamem_hi | (expamem_lo >> 4)) << 16);
	addrbank *ab = &fastmem_bank[devnum];
	if (start == 0x00ff0000)
		return ab;
	uae_u32 size = ab->allocated_size;
	ab->start = start;
	if (ab->start && size) {
		map_banks_z2(ab, ab->start >> 16, size >> 16);
		initramboard(ab, &currprefs.fastmem[devnum]);
	}
	return ab;
}

static bool fastmem_autoconfig(struct uae_prefs *p, struct autoconfig_info *aci, int zorro, uae_u8 type, uae_u32 serial, int allocated)
{
	uae_u16 mid = 0;
	uae_u8 pid;
	uae_u8 flags = 0;
	DEVICE_MEMORY_CALLBACK dmc = NULL;
	struct romconfig *dmc_rc = NULL;
	uae_u8 ac[16] = { 0 };
	int boardnum = aci->devnum;
	bool canforceac = false;

	if (aci->cst) {
		mid = aci->cst->memory_mid;
		pid = aci->cst->memory_pid;
		serial = aci->cst->memory_serial;
	} else if (aci->ert) {
		const struct expansionromtype *ert = aci->ert;
		struct romconfig *rc = get_device_romconfig(p, ert->romtype, 0);
		if (ert->subtypes) {
			const struct expansionsubromtype *srt = &ert->subtypes[rc->subtype];
			if (srt->memory_mid) {
				mid = srt->memory_mid;
				pid = srt->memory_pid;
				serial = srt->memory_serial;
				if (!srt->memory_after)
					type |= chainedconfig;
			}
		} else {
			canforceac = true;
			if (ert->memory_mid) {
				mid = ert->memory_mid;
				pid = ert->memory_pid;
				serial = ert->memory_serial;
				if (!ert->memory_after)
					type |= chainedconfig;
			}
		}
		dmc = ert->memory_callback;
		dmc_rc = rc;
	}

	uae_u8 *forceac = NULL;
	struct ramboard *rb = NULL;

	if (!mid) {
		if (zorro <= 2) {
			rb = &p->fastmem[boardnum];
			if (rb->autoconfig[0]) {
				forceac = rb->autoconfig;
			} else if (rb->manufacturer) {
				mid = rb->manufacturer;
				pid = rb->product;
				serial = 0;
			} else {
				pid = p->maprom && !p->cpuboard_type ? 1 : 81;
			}
		} else {
			int subsize = (allocated == 0x100000 ? Z3_SS_MEM_1MB
						   : allocated == 0x200000 ? Z3_SS_MEM_2MB
						   : allocated == 0x400000 ? Z3_SS_MEM_4MB
						   : allocated == 0x800000 ? Z3_SS_MEM_8MB
						   : Z3_SS_MEM_SAME);
			rb = &p->z3fastmem[boardnum];
			if (rb->autoconfig[0]) {
				forceac = rb->autoconfig;
			} else if (rb->manufacturer) {
				mid = rb->manufacturer;
				pid = rb->product;
				serial = 0;
			} else {
				pid = p->maprom && !p->cpuboard_type ? 3 : 83;
			}
			flags |= care_addr | force_z3 | (allocated > 0x800000 ? ext_size : subsize);
		}
	} else if (canforceac) {
		if (zorro <= 2) {
			rb = &p->fastmem[boardnum];
		} else if (zorro == 3) {
			rb = &p->z3fastmem[boardnum];
		}
		if (rb && rb->autoconfig[0]) {
			forceac = rb->autoconfig;
		}
	}
	if (!mid) {
		mid = uae_id;
		serial = 1;
	}

	if (forceac) {
		for (int i = 0; i < 16; i++) {
			ac[i] = forceac[i];
			ac[0] &= ~7;
			ac[0] |= type & 7;
			if (flags)
				ac[0x08 / 4] = flags;
		}
	} else {
		ac[0x00 / 4] = type;
		ac[0x04 / 4] = pid;
		ac[0x08 / 4] = flags;
		ac[0x10 / 4] = mid >> 8;
		ac[0x14 / 4] = (uae_u8)mid;
		ac[0x18 / 4] = serial >> 24;
		ac[0x1c / 4] = serial >> 16;
		ac[0x20 / 4] = serial >> 8;
		ac[0x24 / 4] = serial >> 0;
	}

	if (dmc && dmc_rc)
		dmc(dmc_rc, ac, allocated);

	expamem_write(0x00, ac[0x00 / 4]);
	expamem_write(0x04, ac[0x04 / 4]);
	expamem_write(0x08, ac[0x08 / 4]);
	expamem_write(0x10, ac[0x10 / 4]);
	expamem_write(0x14, ac[0x14 / 4]);

	expamem_write(0x18, ac[0x18 / 4]); /* ser.no. Byte 0 */
	expamem_write(0x1c, ac[0x1c / 4]); /* ser.no. Byte 1 */
	expamem_write(0x20, ac[0x20 / 4]); /* ser.no. Byte 2 */
	expamem_write(0x24, ac[0x24 / 4]); /* ser.no. Byte 3 */

	expamem_write(0x28, 0x00); /* ROM-Offset hi */
	expamem_write(0x2c, 0x00); /* ROM-Offset lo */

	expamem_write(0x40, 0x00); /* Ctrl/Statusreg.*/

	if (rb && rb->manual_config) {
		aci->start = rb->start_address;
		aci->size = rb->end_address - rb->start_address + 1;
		memcpy(&aci->autoconfig_bytes, ac, sizeof ac);
		return false;
	}

	return true;
}

static const uae_u8 a2630_autoconfig[] = { 0xe7, 0x51, 0x40, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

static bool megachipram_init(struct autoconfig_info *aci)
{
	aci->zorro = 0;
	aci->start = 0x10000000;
	aci->size = aci->prefs->z3chipmem.size;
	aci->label = _T("32-bit Chip RAM");
	return true;
}

static bool expamem_init_fastcard_2(struct autoconfig_info *aci, int zorro)
{
	struct uae_prefs *p = aci->prefs;
	addrbank *bank = &fastmem_bank[aci->devnum];
	uae_u8 type = add_memory | zorroII;
	int size = p->fastmem[aci->devnum].size;

	aci->label = zorro == 1 ? _T("Z1 Fast RAM") : _T("Z2 Fast RAM");
	aci->zorro = zorro;

	expamem_init_clear ();
	if (size == 65536)
		type |= Z2_MEM_64KB;
	else if (size == 131072)
		type |= Z2_MEM_128KB;
	else if (size == 262144)
		type |= Z2_MEM_256KB;
	else if (size == 524288)
		type |= Z2_MEM_512KB;
	else if (size == 0x100000)
		type |= Z2_MEM_1MB;
	else if (size == 0x200000)
		type |= Z2_MEM_2MB;
	else if (size == 0x400000)
		type |= Z2_MEM_4MB;
	else if (size == 0x800000)
		type |= Z2_MEM_8MB;

	aci->addrbank = bank;
	aci->write_bank_address = p->fastmem[aci->devnum].write_address;

	if (aci->devnum == 0) {
		if (ISCPUBOARDP(p, BOARD_COMMODORE, BOARD_COMMODORE_SUB_A26x0)) {
			expamem_write(1 * 4, p->cpu_model <= 68020 ? 0x50 : 0x51);
			for (int i = 2; i < 16; i++)
				expamem_write(i * 4, a2630_autoconfig[i]);
			type &= 7;
			type |= a2630_autoconfig[0] & ~7;
			expamem_write(0, type);
			memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);
			return true;
		}
	}

	if (!fastmem_autoconfig(p, aci, BOARD_AUTOCONFIG_Z2, type, 1, size)) {
		aci->zorro = -1;
	}

	if (expamem_write_space[0] != 0x00 && expamem_write_space[0] != 0xff && aci->write_bank_address) {
		memcpy(expamem, expamem_write_space, 65536);
		memcpy(bank->baseaddr, expamem_write_space, 65536);
	}

	memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);

	if (p->fastmem[aci->devnum].no_reset_unmap && bank->allocated_size) {
		map_banks_z2(bank, bank->start >> 16, size >> 16);
	}

	return true;
}

static bool expamem_init_fastcard(struct autoconfig_info *aci)
{
	return expamem_init_fastcard_2(aci, 2);
}
static bool expamem_init_fastcard_z1(struct autoconfig_info *aci)
{
	return expamem_init_fastcard_2(aci, 1);
}

bool expansion_is_next_board_fastram(void)
{
	return ecard + 1 < MAX_EXPANSION_BOARD_SPACE && cards[ecard + 1] && cards[ecard + 1]->map == expamem_map_fastcard;
}

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

#ifdef FILESYS

static bool expamem_rtarea_init(struct autoconfig_info *aci)
{
	aci->start = rtarea_base;
	aci->size = 65536;
	aci->addrbank = &rtarea_bank;
	aci->label = _T("UAE Boot ROM");
	return true;
}

/*
* Filesystem device
*/

static void expamem_map_filesys_update(void)
{
	/* 68k code needs to know this. */
	uaecptr a = here();
	org(rtarea_base + RTAREA_FSBOARD);
	dl(filesys_bank.start + 0x2000);
	org(a);
}

static addrbank *expamem_map_filesys (struct autoconfig_info *aci)
{
	// Warn if PPC doing autoconfig and UAE expansion enabled
	static bool warned;
	if (!warned && regs.halted < 0) {
		warned = true;
		// can't show dialogs from PPC thread, deadlock danger.
		regs.halted = -2;
	}
	mapped_free(&filesys_bank);
	filesys_bank.start = expamem_board_pointer;
	filesys_bank.mask = filesys_bank.reserved_size - 1;
	if (expamem_board_pointer == 0xffffffff)
		return &filesys_bank;
	mapped_malloc(&filesys_bank);
	memcpy (filesys_bank.baseaddr, expamem, 0x3000);
	uaeboard_ram_start = UAEBOARD_WRITEOFFSET;
	map_banks_z2(&filesys_bank, filesys_bank.start >> 16, 1);
	expamem_map_filesys_update();
	return &filesys_bank;
}

#if KS12_BOOT_HACK
static uaecptr ks12_resident;
static void set_ks12_boot_hack(void)
{
	uaecptr old = here();
	org(ks12_resident);
	dw(ks12orolder() ? 0x4afc : 0x0000);
	org(ks12_resident + 11);
	db((uae_u8)kickstart_version);
	org(old);
}

void create_ks12_boot(void)
{
	// KS 1.2 boot resident
	uaecptr name = ds(_T("UAE boot"));
	align(2);
	uaecptr code = here();
	// allocate fake diagarea
	dl(0x48e73f3e); // movem.l d2-d7/a2-a6,-(sp)
	dw(0x203c); // move.l #x,d0
	dl(0x0300);
	dw(0x7201); // moveq #1,d1
	dl(0x4eaeff3a); // jsr -0xc6(a6)
	dw(0x2440); // move.l d0,a2 ;diag area
	dw(0x9bcd); // sub.l a5,a5 ;expansionbase
	dw(0x97cb); // sub.l a3,a3 ;configdev
	dw(0x4eb9); // jsr
	dl(ROM_filesys_diagentry);
	dl(0x4cdf7cfc); // movem.l (sp)+,d2-d7/a2-a6
	dw(0x4e75);
	// struct Resident
	ks12_resident = here();
	dw(0x0000);
	dl(ks12_resident);
	dl(ks12_resident + 26);
	db(1); // RTF_COLDSTART
	db((uae_u8)kickstart_version); // version
	db(0); // NT_UNKNOWN
	db(1); // priority
	dl(name);
	dl(name);
	dl(code);
	set_ks12_boot_hack();
}
#endif

// 68060 FPU disable ROM code
void create_68060_nofpu(void)
{
	uaecptr code = here();
	if ((code & 0xffff0000) != 0x00f00000)
		return;
	if (dbg(0xf00000) != 0 || dbg(0xf00001) != 0) {
		org(0xf00000);
		dw(0x0000);
		org(code);
	}
	if (currprefs.cpu_model != 68060)
		return;
	if (currprefs.fpu_model == 0)
		return;
	uae_u32 ptr = filesys_get_entry(12);
	if (ptr - 0xf00004 > 128 || ptr < 0xf00004)
		return;
	// first two words of UAE Boot ROM are normally unused
	org(0xf00000);
	dw(0x1111);
	dw(0x6000 + (ptr - 0xf00004)); // bra.b
	org(code);
}

static bool expamem_init_filesys(struct autoconfig_info *aci)
{
	struct uae_prefs *p = aci->prefs;
	bool ks12 = ks12orolder();
	bool hide = p->uae_hide_autoconfig;
	bool rom = !(ks12 || !do_mount || p->uaeboard_nodiag);

	if (aci) {
		aci->label = ks12 ? _T("Pre-KS 1.3 UAE FS ROM") : _T("UAE FS ROM");
		aci->get_params = get_params_filesys;
		aci->set_params = set_params_filesys;
		aci->addrbank = &filesys_bank;
	}

#if 0
	FILE *f = fopen("d:\\amiga\\amiga\\source\\acap\\autoconf", "rb");
	fread(expamem, 1, 256, f);
	fclose(f);
	memcpy(filesys_bank.baseaddr, expamem, 0x3000);
	return NULL;
#endif

	/* struct DiagArea - the size has to be large enough to store several device ROMTags */
	const uae_u8 diagarea[] = {
		0x90, 0x00, /* da_Config, da_Flags */
		0x02, 0x00, /* da_Size */
		FILESYS_DIAGPOINT >> 8, FILESYS_DIAGPOINT & 0xff,
		FILESYS_BOOTPOINT >> 8, FILESYS_BOOTPOINT & 0xff,
		0, (uae_u8)(hide ? 0 : 14), // Name offset
		0, 0, 0, 0,
		(uae_u8)(hide ? 0 : 'U'), (uae_u8)(hide ? 0 : 'A'), (uae_u8)(hide ? 0 : 'E'), 0
	};

	expamem_init_clear ();
	expamem_write (0x00, Z2_MEM_64KB | zorroII | (rom ? rom_card : 0));

	expamem_write (0x08, no_shutup);

	expamem_write (0x04, p->maprom && !p->cpuboard_type ? 2 : 82);
	expamem_write (0x10, uae_id >> 8);
	expamem_write (0x14, uae_id & 0xff);

	expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
	expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
	expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
	expamem_write (0x24, 0x03); /* ser.no. Byte 3 */

	/* er_InitDiagVec */
	expamem_write (0x28, rom ? 0x20 : 0x00); /* ROM-Offset hi */
	expamem_write (0x2c, 0x00); /* ROM-Offset lo */

	expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/

	add_rtarea_pointer(aci);

	if (aci && !aci->doinit) {
		memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);
		return true;
	}

	/* Build a DiagArea */
	memcpy (expamem + FILESYS_DIAGAREA, diagarea, sizeof diagarea);

	put_word_host(expamem + FILESYS_DIAGAREA + FILESYS_DIAGPOINT + 0,
		0x7000 | (p->uaeboard > 2 ? 1 : 0) | (p->uae_hide_autoconfig || p->uaeboard > 1 ? 0 : 2)); // MOVEQ #x,D0
	/* Call hwtrap_install */
	put_word_host(expamem + FILESYS_DIAGAREA + FILESYS_DIAGPOINT + 2, 0x4EB9); /* JSR */
	put_long_host(expamem + FILESYS_DIAGAREA + FILESYS_DIAGPOINT + 4, filesys_get_entry(9));
	/* Call DiagEntry */
	put_word_host(expamem + FILESYS_DIAGAREA + FILESYS_DIAGPOINT + 8, 0x4EF9); /* JMP */
	put_long_host(expamem + FILESYS_DIAGAREA + FILESYS_DIAGPOINT + 10, ROM_filesys_diagentry);

	/* What comes next is a plain bootblock */
	put_word_host(expamem + FILESYS_DIAGAREA + FILESYS_BOOTPOINT, 0x4EF9); /* JMP */
	put_long_host(expamem + FILESYS_DIAGAREA + FILESYS_BOOTPOINT + 2, EXPANSION_bootcode);

	set_ks12_boot_hack();

	return true;
}

#endif

/*
* Zorro III expansion memory
*/

static addrbank *expamem_map_z3fastmem (struct autoconfig_info *aci)
{
	int devnum = aci->devnum;
	addrbank *ab = &z3fastmem_bank[devnum];
	uaecptr z3fs = expamem_board_pointer;
	uae_u32 size = currprefs.z3fastmem[devnum].size;

	if (ab->allocated_size) {
		map_banks_z3(ab, z3fs >> 16, size >> 16);
		initramboard(ab, &currprefs.z3fastmem[devnum]);
	}
	return ab;
}

static bool expamem_init_z3fastmem(struct autoconfig_info *aci)
{
	addrbank *bank = &z3fastmem_bank[aci->devnum];
	
	uae_u32 size = aci->prefs->z3fastmem[aci->devnum].size;

	aci->label = _T("Z3 Fast RAM");

	int code = (size == 0x100000 ? Z2_MEM_1MB
		: size == 0x200000 ? Z2_MEM_2MB
		: size == 0x400000 ? Z2_MEM_4MB
		: size == 0x800000 ? Z2_MEM_8MB
		: size == 0x1000000 ? Z3_MEM_16MB
		: size == 0x2000000 ? Z3_MEM_32MB
		: size == 0x4000000 ? Z3_MEM_64MB
		: size == 0x8000000 ? Z3_MEM_128MB
		: size == 0x10000000 ? Z3_MEM_256MB
		: size == 0x20000000 ? Z3_MEM_512MB
		: Z3_MEM_1GB);

	if (size < 0x1000000)
		code = Z3_MEM_16MB; /* Z3 physical board size is always at least 16M */

	expamem_init_clear ();
	if (!fastmem_autoconfig(aci->prefs, aci, BOARD_AUTOCONFIG_Z3, add_memory | zorroIII | code, 1, size))
		aci->zorro = -1;

	memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);
	aci->addrbank = bank;

	if (!aci->doinit)
		return true;

	uae_u32 start = bank->start;
	bool alwaysmapz3 = aci->prefs->z3_mapping_mode != Z3MAPPING_REAL || aci->prefs->z3fastmem[aci->devnum].no_reset_unmap;
	if ((alwaysmapz3 || expamem_z3hack(aci->prefs)) && bank->allocated_size) {
		map_banks_z3(bank, start >> 16, size >> 16);
	}
	return true;
}

#ifdef PICASSO96
/*
*  Fake Graphics Card (ZORRO III) - BDK
*/

static addrbank *expamem_map_gfxcard_z3 (struct autoconfig_info *aci)
{
	int devnum = aci->devnum;
	gfxmem_banks[devnum]->start = expamem_board_pointer;
	map_banks_z3(gfxmem_banks[devnum], gfxmem_banks[devnum]->start >> 16, gfxmem_banks[devnum]->allocated_size >> 16);
	return gfxmem_banks[devnum];
}

static addrbank *expamem_map_gfxcard_z2 (struct autoconfig_info *aci)
{
	int devnum = aci->devnum;
	gfxmem_banks[devnum]->start = expamem_board_pointer;
	map_banks_z2(gfxmem_banks[devnum], gfxmem_banks[devnum]->start >> 16, gfxmem_banks[devnum]->allocated_size >> 16);
	return gfxmem_banks[devnum];
}

static bool expamem_init_gfxcard (struct autoconfig_info *aci, bool z3)
{
	int devnum = aci->devnum;
	struct uae_prefs *p = aci->prefs;
	int size = p->rtgboards[devnum].rtgmem_size;
	int code = (size == 0x100000 ? Z2_MEM_1MB
		: size == 0x200000 ? Z2_MEM_2MB
		: size == 0x400000 ? Z2_MEM_4MB
		: size == 0x800000 ? Z2_MEM_8MB
		: size == 0x1000000 ? Z3_MEM_16MB
		: size == 0x2000000 ? Z3_MEM_32MB
		: size == 0x4000000 ? Z3_MEM_64MB
		: size == 0x8000000 ? Z3_MEM_128MB
		: size == 0x10000000 ? Z3_MEM_256MB
		: size == 0x20000000 ? Z3_MEM_512MB
		: Z3_MEM_1GB);
	int subsize = (size == 0x100000 ? Z3_SS_MEM_1MB
		: size == 0x200000 ? Z3_SS_MEM_2MB
		: size == 0x400000 ? Z3_SS_MEM_4MB
		: size == 0x800000 ? Z3_SS_MEM_8MB
		: Z3_SS_MEM_SAME);

	aci->label = _T("UAE RTG");
	aci->direct_vram = true;

	if (size < 0x1000000 && z3)
		code = Z3_MEM_16MB; /* Z3 physical board size is always at least 16M */

	expamem_init_clear ();
	expamem_write (0x00, (z3 ? zorroIII : zorroII) | code);

	expamem_write (0x08, care_addr | (z3 ? (force_z3 | (size > 0x800000 ? ext_size: subsize)) : 0));
	expamem_write (0x04, 96);

	expamem_write (0x10, uae_id >> 8);
	expamem_write (0x14, uae_id & 0xff);

	expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
	expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
	expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
	expamem_write (0x24, 0x01); /* ser.no. Byte 3 */

	expamem_write (0x28, 0x00); /* ROM-Offset hi */
	expamem_write (0x2c, 0x00); /* ROM-Offset lo */

	expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/

	memcpy(aci->autoconfig_raw, expamem, sizeof aci->autoconfig_raw);
	aci->addrbank = gfxmem_banks[devnum];
	return true;
}
static bool expamem_init_gfxcard_z3(struct autoconfig_info *aci)
{
	return expamem_init_gfxcard (aci, true);
}
static bool expamem_init_gfxcard_z2 (struct autoconfig_info *aci)
{
	return expamem_init_gfxcard (aci, false);
}
#endif


#ifdef SAVESTATE
static size_t fast_filepos[MAX_RAM_BOARDS], z3_filepos[MAX_RAM_BOARDS];
static size_t z3_fileposchip, p96_filepos;
#endif

void free_fastmemory (int boardnum)
{
	mapped_free (&fastmem_bank[boardnum]);
}

static bool mapped_malloc_dynamic (uae_u32 *currpsize, uae_u32 *changedpsize, addrbank *bank, int max, const TCHAR *label)
{
	int alloc = *currpsize;

	bank->allocated_size = 0;
	bank->reserved_size = alloc;
	bank->baseaddr = NULL;
	bank->mask = 0;

	if (!alloc)
		return false;

	bank->mask = alloc - 1;
	bank->label = label ? label : _T("*");
	if (mapped_malloc (bank)) {
		*currpsize = alloc;
		*changedpsize = alloc;
		return true;
	}
	write_log (_T("Out of memory for %s, %d bytes.\n"), label ? label : _T("?"), alloc);

	return false;
}

uaecptr expansion_startaddress(struct uae_prefs *p, uaecptr addr, uae_u32 size)
{
	if (!size)
		return addr;
	if (addr < 0x10000000) {
		return (addr + size - 1) & ~(size - 1);
	} else {
		if (size < 16 * 1024 * 1024)
			size = 16 * 1024 * 1024;
		if (!expamem_z3hack(p))
			return (addr + size - 1) & ~(size - 1);
	}
	return addr;
}

static void allocate_expamem (void)
{
	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		memcpy(&currprefs.rtgboards[i], &changed_prefs.rtgboards[i], sizeof(struct rtgboardconfig));
	}
	currprefs.z3chipmem.size = changed_prefs.z3chipmem.size;

	for (int i = 0; i < MAX_RAM_BOARDS; i++) {
		currprefs.fastmem[i].size = changed_prefs.fastmem[i].size;
		currprefs.z3fastmem[i].size = changed_prefs.z3fastmem[i].size;
	}

	for (int i = 0; i < MAX_ROM_BOARDS; i++) {
		struct romboard *rb = &currprefs.romboards[i];
		memcpy(rb, &changed_prefs.romboards[i], sizeof(struct romboard));
		if (romboardmem_bank[i].reserved_size != rb->size) {
			mapped_free(&romboardmem_bank[i]);
			romboardmem_bank[i].reserved_size = rb->size;
			romboardmem_bank[i].mask = romboardmem_bank[i].reserved_size - 1;
			romboardmem_bank[i].start = rb->start_address;
			if (romboardmem_bank[i].reserved_size && romboardmem_bank[i].start != 0xffffffff) {
				mapped_malloc(&romboardmem_bank[i]);
				if (romboardmem_bank[i].baseaddr == 0) {
					write_log(_T("Out of memory for romboard card.\n"));
				}
			}
		}
	}

	z3chipmem_bank.start = Z3BASE_UAE;

	if (currprefs.mbresmem_high.size >= 128 * 1024 * 1024)
		z3chipmem_bank.start += (currprefs.mbresmem_high.size - 128 * 1024 * 1024) + 16 * 1024 * 1024;

	if (currprefs.z3chipmem.size && z3fastmem_bank[0].start - z3chipmem_bank.start < currprefs.z3chipmem.size)
		currprefs.z3chipmem.size = changed_prefs.z3chipmem.size = 0;	

	for (int i = 0; i < MAX_RAM_BOARDS; i++) {
		if (fastmem_bank[i].reserved_size != currprefs.fastmem[i].size) {
			free_fastmemory(i);

			if (fastmem_bank[i].start == 0xffffffff) {
				fastmem_bank[i].reserved_size = 0;
			} else {
				fastmem_bank[i].reserved_size = currprefs.fastmem[i].size;
				fastmem_bank[i].mask = fastmem_bank[i].reserved_size - 1;
				if (currprefs.fastmem[i].manual_config) {
					fastmem_bank[i].start = currprefs.fastmem[i].start_address;
				}
				if (fastmem_bank[i].reserved_size && fastmem_bank[i].start != 0xffffffff) {
					mapped_malloc (&fastmem_bank[i]);
					if (fastmem_bank[i].baseaddr == 0) {
						write_log (_T("Out of memory for fastmem card.\n"));
					}
				}
			}
			memory_hardreset (1);
		}
	}

	if (z3fastmem_bank[0].reserved_size != currprefs.z3fastmem[0].size && !currprefs.z3fastmem[0].manual_config) {
		mapped_free(&z3fastmem_bank[0]);
		mapped_malloc_dynamic(&currprefs.z3fastmem[0].size, &changed_prefs.z3fastmem[0].size, &z3fastmem_bank[0], 1, _T("*"));
		memory_hardreset(1);
	}
	for (int i = 0; i < MAX_RAM_BOARDS; i++) {

		if (i == 0 && !currprefs.z3fastmem[i].manual_config)
			continue;

		if (currprefs.z3fastmem[i].size && z3fastmem_bank[i].start == 0xffffffff) {
			z3fastmem_bank[i].start = expansion_startaddress(&currprefs, z3fastmem_bank[i - 1].start, currprefs.z3fastmem[i - 1].size);
		}
		if (z3fastmem_bank[i].reserved_size != currprefs.z3fastmem[i].size) {
			mapped_free (&z3fastmem_bank[i]);

			if (z3fastmem_bank[i].start == 0xffffffff) {
				z3fastmem_bank[i].reserved_size = 0;
			} else {
				z3fastmem_bank[i].reserved_size = currprefs.z3fastmem[i].size;
				z3fastmem_bank[i].mask = z3fastmem_bank[i].reserved_size - 1;
				if (currprefs.z3fastmem[i].manual_config) {
					z3fastmem_bank[i].start = currprefs.z3fastmem[i].start_address;
				}
				if (z3fastmem_bank[i].reserved_size) {
					mapped_malloc(&z3fastmem_bank[i]);
					if (z3fastmem_bank[i].baseaddr == 0) {
						write_log (_T("Out of memory for 32 bit fast memory #%d.\n"), i);
					}
				}
			}
			memory_hardreset (1);
		}
	}
	if (z3chipmem_bank.reserved_size != currprefs.z3chipmem.size) {
		mapped_free (&z3chipmem_bank);
		mapped_malloc_dynamic (&currprefs.z3chipmem.size, &changed_prefs.z3chipmem.size, &z3chipmem_bank, 16, _T("*"));
		memory_hardreset (1);
	}

#ifdef PICASSO96
	struct rtgboardconfig *rbc = &currprefs.rtgboards[0];
	if (gfxmem_banks[0]->reserved_size != rbc->rtgmem_size) {
		mapped_free (gfxmem_banks[0]);
		if (rbc->rtgmem_type < GFXBOARD_HARDWARE)
			mapped_malloc_dynamic (&rbc->rtgmem_size, &changed_prefs.rtgboards[0].rtgmem_size, gfxmem_banks[0], 1, NULL);
		memory_hardreset (1);
	}
#endif

#ifdef SAVESTATE
	if (savestate_state == STATE_RESTORE) {
		for (int i = 0; i < MAX_RAM_BOARDS; i++) {
			if (fastmem_bank[i].allocated_size > 0) {
				restore_ram (fast_filepos[i], fastmem_bank[i].baseaddr);
				if (!fastmem_bank[i].start) {
					// old statefile compatibility support
					fastmem_bank[i].start = 0x00200000;
				}
				map_banks(&fastmem_bank[i], fastmem_bank[i].start >> 16, currprefs.fastmem[i].size >> 16,
						fastmem_bank[i].allocated_size);
			}
			if (z3fastmem_bank[i].allocated_size > 0) {
				restore_ram (z3_filepos[i], z3fastmem_bank[i].baseaddr);
				map_banks(&z3fastmem_bank[i], z3fastmem_bank[i].start >> 16, currprefs.z3fastmem[i].size >> 16,
					z3fastmem_bank[i].allocated_size);
			}
		}
		if (z3chipmem_bank.allocated_size > 0) {
			restore_ram (z3_fileposchip, z3chipmem_bank.baseaddr);
			map_banks(&z3chipmem_bank, z3chipmem_bank.start >> 16, currprefs.z3chipmem.size >> 16,
				z3chipmem_bank.allocated_size);
			initramboard(&z3chipmem_bank, &currprefs.z3chipmem);
		}
#ifdef PICASSO96
		if (gfxmem_banks[0]->allocated_size > 0 && gfxmem_banks[0]->start > 0) {
			restore_ram (p96_filepos, gfxmem_banks[0]->baseaddr);
			map_banks(gfxmem_banks[0], gfxmem_banks[0]->start >> 16, currprefs.rtgboards[0].rtgmem_size >> 16,
				gfxmem_banks[0]->allocated_size);
		}
#endif
	}
#endif /* SAVESTATE */
}

static uaecptr check_boot_rom (struct uae_prefs *p, int *boot_rom_type)
{
	uaecptr b = RTAREA_DEFAULT;
	addrbank *ab;

	if (p->uaeboard > 1) {
		*boot_rom_type = 2;
		return uaeboard_bank.start ? uaeboard_bank.start + 0x10000 : 0x00eb0000;
	}
	*boot_rom_type = 0;
	if (p->boot_rom == 1)
		return 0;
	*boot_rom_type = 1;
	if (p->cs_cdtvcd || is_device_rom(p, ROMTYPE_CDTVSCSI, 0) >= 0 || p->uae_hide > 1)
		b = RTAREA_BACKUP;
	if (p->cs_mbdmac == 1 || p->cpuboard_type)
		b = RTAREA_BACKUP;
	// CSPPC enables MMU at boot and remaps 0xea0000->0xeffff.
	if (ISCPUBOARDP(p, BOARD_BLIZZARD, BOARD_BLIZZARD_SUB_PPC))
		b = RTAREA_BACKUP_2;
	ab = &get_mem_bank (RTAREA_DEFAULT);
	if (ab) {
		if (valid_address (RTAREA_DEFAULT, 65536))
			b = RTAREA_BACKUP;
	}
	if (nr_directory_units (NULL))
		return b;
	if (nr_directory_units (p))
		return b;
#ifdef WIN32
	if (p->win32_automount_drives || p->win32_automount_cddrives || p->win32_automount_netdrives || p->win32_automount_removable)
		return b;
#endif
	if (p->socket_emu)
		return b;
	if (p->uaeserial)
		return b;
	if (p->scsi == 1)
		return b;
	if (p->sana2)
		return b;
	if (p->input_tablet > 0)
		return b;
	if (p->rtgboards[0].rtgmem_size && p->rtgboards[0].rtgmem_type < GFXBOARD_HARDWARE)
		return b;
	if (p->win32_automount_removable)
		return b;
	if (p->chipmem.size > 2 * 1024 * 1024)
		return b;
	if (p->z3chipmem.size)
		return b;
	if (p->boot_rom >= 3)
		return b;
	if (p->boot_rom == 2 && b == 0xf00000) {
		*boot_rom_type = -1;
		return b;
	}
	*boot_rom_type = 0;
	return 0;
}

uaecptr need_uae_boot_rom (struct uae_prefs *p)
{
	uaecptr v;

	uae_boot_rom_type = 0;
	v = check_boot_rom (p, &uae_boot_rom_type);
	if (!rtarea_base) {
		uae_boot_rom_type = 0;
		v = 0;
	}
	return v;
}

static void add_cpu_expansions(struct uae_prefs *p, int zorro, int *fastmem_nump)
{
	int fastmem_num = MAX_RAM_BOARDS;
	if (fastmem_nump)
		fastmem_num = *fastmem_nump;

	const struct cpuboardsubtype *cst = &cpuboards[p->cpuboard_type].subtypes[p->cpuboard_subtype];
	if (cst->init && cst->initzorro == zorro) {
		int idx;
		struct boardromconfig *brc = get_device_rom(p, ROMTYPE_CPUBOARD, 0, &idx);
		if (brc) {
			struct romconfig *rc = &brc->roms[idx];
			cards_set[cardno].flags = cst->initflag;
			cards_set[cardno].name = cst->name;
			cards_set[cardno].initrc = cst->init;
			cards_set[cardno].rc = rc;
			cards_set[cardno].zorro = zorro;
			cards_set[cardno].cst = cst;
			cards_set[cardno++].map = NULL;
			if (cst->init2) {
				cards_set[cardno].flags = cst->initflag | CARD_FLAG_CHILD;
				cards_set[cardno].name = cst->name;
				cards_set[cardno].initrc = cst->init2;
				cards_set[cardno].zorro = zorro;
				cards_set[cardno].cst = cst;
				cards_set[cardno++].map = NULL;
			}
			if (fastmem_num < MAX_RAM_BOARDS && zorro == 2 && cst->memory_mid && p->fastmem[fastmem_num].size) {
				cards_set[cardno].flags = (fastmem_num << 16) | CARD_FLAG_CHILD;
				cards_set[cardno].name = _T("Z2Fast");
				cards_set[cardno].initnum = expamem_init_fastcard;
				cards_set[cardno].zorro = zorro;
				cards_set[cardno].cst = cst;
				cards_set[cardno++].map = expamem_map_fastcard;
				fastmem_num++;
			}
		}
	}
	if (fastmem_nump)
		*fastmem_nump = fastmem_num;
}

static void add_expansions(struct uae_prefs *p, int zorro, int *fastmem_nump, int mode)
{
	int fastmem_num = MAX_RAM_BOARDS;
	if (fastmem_nump)
		fastmem_num = *fastmem_nump;
	for (int i = 0; expansionroms[i].name; i++) {
		const struct expansionromtype *ert = &expansionroms[i];
		if (ert->zorro == zorro) {
			for (int j = 0; j < MAX_DUPLICATE_EXPANSION_BOARDS; j++) {
				struct romconfig *rc = get_device_romconfig(p, ert->romtype, j);
				if (rc) {
					int mid = ert->memory_mid;
					bool memory_after = ert->memory_after;
					bool added = false;
					if (ert->subtypes) {
						const struct expansionsubromtype *srt = &ert->subtypes[rc->subtype];
						mid = srt->memory_mid;
						memory_after = srt->memory_after;
					}

					if (mode == 1 && ert->memory_mid)
						continue;
					if (mode == 2 && !ert->memory_mid)
						continue;
					if (fastmem_num < MAX_RAM_BOARDS && zorro == 2 && mid && !memory_after && p->fastmem[fastmem_num].size) {
						cards_set[cardno].flags = (fastmem_num << 16);
						cards_set[cardno].name = _T("Z2Fast");
						cards_set[cardno].initnum = expamem_init_fastcard;
						cards_set[cardno].zorro = zorro;
						cards_set[cardno].ert = ert;
						cards_set[cardno++].map = expamem_map_fastcard;
						fastmem_num++;
						added = true;
					}
					if (fastmem_num < MAX_RAM_BOARDS && zorro == 3 && mid && !memory_after && p->z3fastmem[fastmem_num].size) {
						cards_set[cardno].flags = CARD_FLAG_CAN_Z3 | (fastmem_num << 16);
						cards_set[cardno].name = _T("Z3Fast");
						cards_set[cardno].initnum = expamem_init_z3fastmem;
						cards_set[cardno].zorro = zorro;
						cards_set[cardno].ert = ert;
						cards_set[cardno++].map = expamem_map_z3fastmem;
						fastmem_num++;
						added = true;
					}
					cards_set[cardno].flags = added ? CARD_FLAG_CHILD : 0;
					cards_set[cardno].name = ert->name;
					cards_set[cardno].initrc = ert->init;
					cards_set[cardno].rc = rc;
					cards_set[cardno].zorro = zorro;
					cards_set[cardno].ert = ert;
					cards_set[cardno].flags = j << 16;
					cards_set[cardno++].map = NULL;
					if (ert->init2) {
						cards_set[cardno].flags = CARD_FLAG_CHILD;
						cards_set[cardno].name = ert->name;
						cards_set[cardno].initrc = ert->init2;
						cards_set[cardno].rc = rc;
						cards_set[cardno].zorro = zorro;
						cards_set[cardno++].map = NULL;
					}
					if (fastmem_num < MAX_RAM_BOARDS && zorro == 1 && mid && p->fastmem[fastmem_num].size) {
						cards_set[cardno].flags = (fastmem_num << 16) | CARD_FLAG_CHILD;
						cards_set[cardno].name = _T("Z1Fast");
						cards_set[cardno].initnum = expamem_init_fastcard_z1;
						cards_set[cardno].zorro = zorro;
						cards_set[cardno].ert = ert;
						cards_set[cardno++].map = NULL;
						fastmem_num++;
					}
					if (fastmem_num < MAX_RAM_BOARDS && zorro == 2 && mid && memory_after && p->fastmem[fastmem_num].size) {
						cards_set[cardno].flags = (fastmem_num << 16) | CARD_FLAG_CHILD;
						cards_set[cardno].name = _T("Z2Fast");
						cards_set[cardno].initnum = expamem_init_fastcard;
						cards_set[cardno].zorro = zorro;
						cards_set[cardno].ert = ert;
						cards_set[cardno++].map = expamem_map_fastcard;
						fastmem_num++;
					}
					if (fastmem_num < MAX_RAM_BOARDS && zorro == 3 && mid && memory_after && p->z3fastmem[fastmem_num].size) {
						cards_set[cardno].flags = CARD_FLAG_CAN_Z3 | (fastmem_num << 16) | CARD_FLAG_CHILD;
						cards_set[cardno].name = _T("Z3Fast");
						cards_set[cardno].initnum = expamem_init_z3fastmem;
						cards_set[cardno].zorro = zorro;
						cards_set[cardno].ert = ert;
						cards_set[cardno++].map = expamem_map_z3fastmem;
						fastmem_num++;
					}
				}
			}
		}
	}
	if (fastmem_nump)
		*fastmem_nump = fastmem_num;
}

uae_u32 expansion_board_size(addrbank *ab)
{
	uae_u32 size = 0;
	uae_u8 code = (ab->bget(0) & 0xf0) | ((ab->bget(2) & 0xf0) >> 4);
	if ((code & 0xc0) == zorroII) {
		// Z2
		code &= 7;
		if (code == 0)
			size = 8 * 1024 * 1024;
		else
			size = 32768 << code;
	}
	return size;
}

static uae_u8 autoconfig_read(const uae_u8 *autoconfig, int offset)
{
	uae_u8 b = (autoconfig[offset] & 0xf0) | (autoconfig[offset + 2] >> 4);
	if (offset == 0 || offset == 2 || offset == 0x40 || offset == 0x42)
		return b;
	b = ~b;
	return b;
}

static void expansion_parse_autoconfig(struct card_data *cd, const uae_u8 *autoconfig)
{
	uae_u8 code = autoconfig[0];
	uae_u32 expamem_z3_size;

	if ((code & 0xc0) == zorroII) {
		int slotsize;
		// Z2
		cd->zorro = 2;
		code &= 7;
		if (code == 0)
			expamem_board_size = 8 * 1024 * 1024;
		else
			expamem_board_size = 32768 << code;
		slotsize = expamem_board_size / 65536;

		expamem_board_pointer = 0xffffffff;

		for (int slottype = 0; slottype < 2; slottype++)
		{
			uae_u8 *slots = slots_e8;
			int numslots = sizeof slots_e8;
			uaecptr slotaddr = AUTOCONFIG_Z2;
			if (slotsize >= 8 || slottype > 0) {
				slots = slots_20;
				numslots = sizeof slots_20;
				slotaddr = AUTOCONFIG_Z2_MEM;
			}
			for (int i = 0; i < numslots; i++) {
				if (((slotsize - 1) & i) == 0) {
					bool free = true;
					for (int j = 0; j < slotsize && j + i < numslots; j++) {
						if (slots[i + j] != 0) {
							free = false;
							break;
						}
					}
					if (free) {
						for (int j = 0; j < slotsize; j++) {
							slots[i + j] = 1;
						}
						expamem_board_pointer = slotaddr + i * 65536;
						break;
					}
				}
			}
			if (expamem_board_pointer != 0xffffffff || slotsize >= 8)
				break;
		}

	} else if ((code & 0xc0) == zorroIII) {
		// Z3

		cd->zorro = 3;
		code &= 7;
		if (autoconfig[2] & ext_size)
			expamem_z3_size = (16 * 1024 * 1024) << code;
		else
			expamem_z3_size = 16 * 1024 * 1024;

		uaecptr newp = (expamem_z3_pointer_real + expamem_z3_size - 1) & ~(expamem_z3_size - 1);
		if (newp < expamem_z3_pointer_real)
			newp = 0xffffffff;
		expamem_z3_pointer_real = newp;

		expamem_board_pointer = expamem_z3hack(cd->aci.prefs) ? expamem_z3_pointer_uae : expamem_z3_pointer_real;
		expamem_board_size = expamem_z3_size;

	} else if ((code & 0xc0) == 0x40) {
		cd->zorro = 1;
		// 0x40 = "Box without init/diagnostic code"
		// proto autoconfig "box" size.
		//expamem_z2_size = (1 << ((code >> 3) & 7)) * 4096;
		// much easier this way, all old-style boards were made for
		// A1000 and didn't have passthrough connector.
		expamem_board_size = 65536;
		expamem_board_pointer = 0xe90000;
	}

}

static void reset_ac_data(struct uae_prefs *p)
{
	expamem_z3_pointer_real = Z3BASE_REAL;
	expamem_z3_pointer_uae = Z3BASE_UAE;
	expamem_z3_highram_real = 0;
	expamem_z3_highram_uae = 0;

	expamem_highmem_pointer = 0;
	if (p->mbresmem_low.size)
		expamem_highmem_pointer = 0x08000000;
	if (p->mbresmem_high.size)
		expamem_highmem_pointer = 0x08000000 + p->mbresmem_high.size;

	if (p->mbresmem_high.size >= 128 * 1024 * 1024)
		expamem_z3_pointer_uae += (p->mbresmem_high.size - 128 * 1024 * 1024) + 16 * 1024 * 1024;
	expamem_z3_pointer_uae += p->z3chipmem.size;
	expamem_board_pointer = 0;
	expamem_board_size = 0;
	memset(slots_20, 0, sizeof slots_20);
	memset(slots_e8, 0, sizeof slots_e8);
	slots_e8[0] = 1;
}

static void reset_ac(struct uae_prefs *p)
{
	do_mount = 1;

	if (need_uae_boot_rom(p) == 0)
		do_mount = 0;
	if (uae_boot_rom_type <= 0)
		do_mount = 0;

	/* check if Kickstart version is below 1.3 */
	if (ks12orolder() && do_mount && p->uaeboard < 2) {
		/* warn user */
#if KS12_BOOT_HACK
		do_mount = -1;
#else
		write_log(_T("Kickstart version is below 1.3!  Disabling automount devices.\n"));
		do_mount = 0;
#endif
	}

	if (p->uae_hide)
		uae_id = commodore;
	else
		uae_id = hackers_id;

	if (restore_cardno == 0) {
		for (int i = 0; i < MAX_EXPANSION_BOARD_SPACE; i++) {
			memset(&cards_set[i], 0, sizeof(struct card_data));
		}
	}

	ecard = 0;
	cardno = 0;

	reset_ac_data(p);
}

void expansion_generate_autoconfig_info(struct uae_prefs *p)
{
	expansion_scan_autoconfig(p, true);
}

bool alloc_expansion_bank(addrbank *bank, struct autoconfig_info *aci)
{
	bank->start = aci->start;
	bank->reserved_size = aci->size;
	aci->addrbank = bank;
	return mapped_malloc(bank);
}

void free_expansion_bank(addrbank *bank)
{
	mapped_free(bank);
	bank->start = NULL;
	bank->reserved_size = 0;
}

struct autoconfig_info *expansion_get_bank_data(struct uae_prefs *p, uaecptr *addrp)
{
	uaecptr addr = *addrp;
	static struct autoconfig_info acid;
	struct autoconfig_info *aci = NULL;

	if (addr >= 0x01000000 && currprefs.address_space_24) {
		return NULL;
	}
	for (;;) {
		addrbank *ab = &get_mem_bank(addr);
		if (ab && ab != &dummy_bank) {
			aci = expansion_get_autoconfig_by_address(p, addr, 0);
			if (aci && expansion_get_autoconfig_by_address(p, addr - 1, 0) != aci) {
				addrbank *ab2 = ab;
				struct autoconfig_info *aci2;
				int size = 0;
				for (;;) {
					addr += 65536;
					size += 65536;
					ab2 = &get_mem_bank(addr);
					aci2 = expansion_get_autoconfig_by_address(p, addr, 0);
					if (ab != ab2) {
						break;
					}
					if (aci2 != aci) {
						break;
					}
					if (aci->size > 0 && size >= aci->size) {
						break;
					}
				}
				*addrp = addr;
				return aci;
			}
			uaecptr addr2 = addr;
			aci = &acid;
			memset(aci, 0, sizeof(struct autoconfig_info));
			aci->autoconfig_bytes[0] = 0xff;
			if (ab->sub_banks) {
				uaecptr saddr = addr;
				uaecptr saddr1 = saddr;
				uaecptr saddr2 = saddr;
				addrbank *sab1 = get_sub_bank(&saddr1);
				for (;;) {
					saddr2 = saddr1 + 1;
					addrbank *sab2 = get_sub_bank(&saddr2);
					if (sab1 != sab2 || (saddr1 & 65535) == 65535) {
						aci->addrbank = sab1;
						aci->start = addr;
						aci->size = saddr2 - addr;
						if (sab1->name) {
							_tcscpy(aci->name, sab1->name);
						}
						addr = saddr2;
						*addrp = addr;
						break;
					}
					saddr1++;
				}
				if (aci->addrbank == &dummy_bank) {
					addr = saddr2;
					continue;
				}
				return aci;
			} else {
				aci->addrbank = ab;
				aci->start = addr;
				aci->size = ab->allocated_size;
				if (ab->name) {
					_tcscpy(aci->name, ab->name);
				}
				addrbank *ab2 = ab;
				int size = 0;
				for (;;) {
					addr += 65536;
					size += 65536;
					ab2 = &get_mem_bank(addr);
					if (ab != ab2) {
						break;
					}
					if (aci->size > 0 && size >= aci->size) {
						break;
					}
				}
			}
			if (aci->size == 0) {
				aci->size = addr - addr2;
			}
			*addrp = addr;
			return aci;
		}

		for (;;) {
			addr += 65536;
			if (addr >= 0x01000000 && currprefs.address_space_24) {
				return NULL;
			}
			if (addr < 65536) {
				return NULL;
			}
			ab = &get_mem_bank(addr);
			if (ab != NULL && ab != &dummy_bank) {
				break;
			}
		}
	}
}

struct autoconfig_info *expansion_get_autoconfig_data(struct uae_prefs *p, int index)
{
	if (index >= cardno)
		return NULL;
	struct card_data *cd = cards[index];
	return &cd->aci;
}

struct autoconfig_info *expansion_get_autoconfig_by_address(struct uae_prefs *p, uaecptr addr, int index)
{
	if (index >= cardno)
		return NULL;
	for (int i = index; i < cardno; i++) {
		struct card_data *cd = cards[i];
		if (cd && addr >= cd->base && addr < cd->base + cd->size)
			return &cd->aci;
	}
	return NULL;
}

struct autoconfig_info *expansion_get_autoconfig_info(struct uae_prefs *p,int romtype, int devnum)
{
	for (int i = 0; i < cardno; i++) {
		struct card_data *cd = cards[i];
		if (cd->rc) {
			if (cd->rc->back->device_type == romtype && cd->rc->back->device_num == devnum) {
				return &cd->aci;
			}
		} else if (cd->cst) {
			if ((romtype & ROMTYPE_CPUBOARD) && (cd->cst->romtype & ROMTYPE_CPUBOARD))
				return &cd->aci;
		} else {
			// z2 and z3 ram boards are "fake"
			if ((romtype == ROMTYPE_RAMZ2 && !_tcsicmp(cd->name, _T("Z2Fast")))
				|| (romtype == ROMTYPE_RAMZ3 && !_tcsicmp(cd->name, _T("Z3Fast")))
				|| (romtype == ROMTYPE_MEGACHIP && !_tcsicmp(cd->name, _T("MegaChipRAM"))))
			{
				if (((cd->flags >> 16) & 255) == devnum)
					return &cd->aci;
			}
		}
	}
	return NULL;
}

static void expansion_init_cards(struct uae_prefs *p)
{
	reset_ac_data(p);

	for (int i = 0; i < cardno; i++) {
		bool ok;
		struct card_data *cd = &cards_set[i];
		struct autoconfig_info *aci = &cd->aci;
		memset(aci->autoconfig_raw, 0xff, sizeof aci->autoconfig_raw);
		cd->base = 0;
		cd->size = 0;
		aci->devnum = (cd->flags >> 16) & 255;
		aci->prefs = p;
		aci->ert = cd->ert;
		aci->cst = cd->cst;
		aci->start = 0xffffffff;
		aci->zorro = cd->zorro;
		if (cd->initnum) {
			ok = cd->initnum(aci);
		} else {
			aci->rc = cd->rc;
			ok = cd->initrc(aci);
		}
		if (cd->flags & CARD_FLAG_CHILD)
			aci->parent_of_previous = true;
		
		if ((aci->zorro == 1 || aci->zorro == 2 || aci->zorro == 3) && aci->addrbank != &expamem_null && aci->addrbank != &expamem_none && (aci->autoconfig_raw[0] != 0xff || aci->autoconfigp)) {
			uae_u8 ac2[16];
			const uae_u8 *a = aci->autoconfigp;
			if (!a) {
				for (int i = 0; i < 16; i++) {
					ac2[i] = autoconfig_read(aci->autoconfig_raw, i * 4);
				}
				a = ac2;
			}
			expansion_parse_autoconfig(cd, a);
			cd->size = expamem_board_size;
		}
	}
}

static void set_order(struct uae_prefs *p, struct card_data *cd, int order)
{
	if (!cd)
		return;
	if (cd->aci.set_params) {
		struct expansion_params parms = { 0 };
		parms.device_order = order;
		if (cd->aci.set_params(p, &parms))
			return;
	}
	if (cd->zorro <= 0 || cd->zorro >= 4)
		return;
	if (cd->rc) {
		cd->rc->back->device_order = order;
		return;
	}
	int devnum = (cd->flags >> 16) & 255;
	if (!_tcsicmp(cd->name, _T("Z2Fast"))) {
		p->fastmem[devnum].device_order = order;
		return;
	}
	if (!_tcsicmp(cd->name, _T("Z3Fast"))) {
		p->z3fastmem[devnum].device_order = order;
		return;
	}
	if (!_tcsicmp(cd->name, _T("Z3RTG")) || !_tcsicmp(cd->name, _T("Z2RTG"))) {
		p->rtgboards[devnum].device_order = order;
		return;
	}

}

static int get_order(struct uae_prefs *p, struct card_data *cd)
{
	if (!cd)
		return EXPANSION_ORDER_MAX - 1;
	if (cd->cst)
		return -4; // Accelerator must be always first
	if (cd->aci.hardwired)
		return -3;
	if (cd->aci.get_params) {
		struct expansion_params parms;
		if (cd->aci.get_params(p, &parms))
			return parms.device_order;
	}
	if (cd->zorro <= 0)
		return -1;
	if (cd->zorro >= 4)
		return -2;
	if (cd->rc && cd->rc->back)
		return cd->rc->back->device_order;
	int devnum = (cd->flags >> 16) & 255;
	if (!_tcsicmp(cd->name, _T("Z2Fast")))
		return p->fastmem[devnum].device_order;
	if (!_tcsicmp(cd->name, _T("Z3Fast")))
		return p->z3fastmem[devnum].device_order;
	if (!_tcsicmp(cd->name, _T("Z3RTG")) || !_tcsicmp(cd->name, _T("Z2RTG")))
		return p->rtgboards[devnum].device_order;
	if (!_tcsicmp(cd->name, _T("MegaChipRAM")))
		return -1;
	return EXPANSION_ORDER_MAX - 1;
}

bool expansion_can_move(struct uae_prefs *p, int index)
{
	if (index < 0 || index >= cardno)
		return false;
	struct card_data *cd = cards[index];
	if (cd->aci.parent_of_previous)
		return false;
	int order1 = get_order(p, cd);
	if (order1 < 0 || order1 >= EXPANSION_ORDER_MAX - 1)
		return false;
	return true;
}

static void expansion_parse_cards(struct uae_prefs *p, bool log)
{
	if (log)
		write_log(_T("Autoconfig board list:\n"));
	reset_ac_data(p);
	for (int i = 0; i < cardno; i++) {
		bool ok;
		struct card_data *cd = cards[i];
		struct autoconfig_info *aci = &cd->aci;
		memset(aci->autoconfig_raw, 0xff, sizeof aci->autoconfig_raw);
		memset(aci->autoconfig_bytes, 0xff, sizeof aci->autoconfig_bytes);
		cd->base = 0;
		cd->size = 0;
		aci->devnum = (cd->flags >> 16) & 255;
		aci->prefs = p;
		aci->ert = cd->ert;
		aci->cst = cd->cst;
		aci->zorro = cd->zorro;
		aci->start = 0xffffffff;
		if (cd->initnum) {
			ok = cd->initnum(aci);
		} else {
			aci->rc = cd->rc;
			ok = cd->initrc(aci);
		}
		if (aci->last_high_ram > expamem_highmem_pointer) {
			expamem_highmem_pointer = aci->last_high_ram;
			if (log)
				write_log(_T("Non-Autoconfig highmem increased to %08x\n"), expamem_highmem_pointer);
		}
		if (log)
			write_log(_T("Card %02d: "), i + 1);
		if (ok) {
			TCHAR label[MAX_DPATH];
			label[0] = 0;
			if (aci->cst && !label[0]) {
#if 0
				const TCHAR *man = NULL;
				for (int i = 0; cpuboards[i].name && man == NULL; i++) {
					const struct cpuboardtype *cbt = &cpuboards[i];
					if (cbt->subtypes) {
						for (int j = 0; cbt->subtypes[j].name && man == NULL; j++) {
							if (&cbt->subtypes[j] == aci->cst)
								man = cpuboards[i].name;
						}
					}
				}
				_stprintf(label, _T("%s (%s)"), aci->cst->name, man);
#endif
				_tcscpy(label, aci->cst->name);
			}
			if (cd->rc && !label[0] && cd->rc->back) {
				const struct expansionromtype *ert = get_device_expansion_rom(cd->rc->back->device_type);
				if (ert) {
					_tcscpy(label, ert->friendlyname);
				}
			}
			if (!label[0]) {
				if (aci->label) {
					_tcscpy(label, aci->label);
				} else if (aci->addrbank && aci->addrbank->label) {
					_tcscpy(label, aci->addrbank->label);
				} else {
					_tcscpy(label, _T("<no name>"));
				}
			}
			if (aci->devnum > 0) {
				TCHAR *s = label + _tcslen(label);
				_stprintf(s, _T(" [%d]"), aci->devnum + 1);
			}

			if ((aci->zorro == 1 || aci->zorro == 2 || aci->zorro == 3) && aci->addrbank != &expamem_none && (aci->autoconfig_raw[0] != 0xff || aci->autoconfigp)) {
				uae_u8 ac2[16];
				const uae_u8 *a = aci->autoconfigp;
				if (!a) {
					for (int i = 0; i < 16; i++) {
						ac2[i] = autoconfig_read(aci->autoconfig_raw, i * 4);
					}
					a = ac2;
				}
				if (log) {
					write_log(_T("'%s'\n"), label);
					write_log(_T("  %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n"),
						a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
						a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
					write_log(_T("  MID %u (%04x) PID %u (%02x) SER %08x\n"),
						(a[4] << 8) | a[5], (a[4] << 8) | a[5],
						a[1], a[1],
						(a[6] << 24) | (a[7] << 16) | (a[8] << 8) | a[9]);
				}
				expansion_parse_autoconfig(cd, a);
				uae_u32 size = expamem_board_size;
				TCHAR sizemod = 'K';
				uae_u8 type = a[0];
				size /= 1024;
				if (size > 8 * 1024) {
					sizemod = 'M';
					size /= 1024;
				}
				bool z3 = (type & 0xc0) == zorroIII;
				if (log) {
					write_log(_T("  Z%d 0x%08x 0x%08x %4d%c %s %d\n"),
						(type & 0xc0) == zorroII ? 2 : (z3 ? 3 : 1),
						z3 && !currprefs.z3autoconfig_start ? expamem_z3_pointer_real : expamem_board_pointer,
						z3 && !currprefs.z3autoconfig_start ? expamem_z3_pointer_uae : expamem_board_pointer,
						size, sizemod,
						type & rom_card ? _T("ROM") : (type & add_memory ? _T("RAM") : _T("IO ")), get_order(p, cd));
				}
				cd->base = expamem_board_pointer;
				cd->size = expamem_board_size;
				if ((type & 0xc0) == zorroIII) {
					aci->start = expamem_z3hack(p) ? expamem_z3_pointer_uae : expamem_z3_pointer_real;
				} else {
					aci->start = expamem_board_pointer;
				}
				aci->size = cd->size;
				memcpy(aci->autoconfig_bytes, a, sizeof aci->autoconfig_bytes);
				if (aci->addrbank) {
					aci->addrbank->start = expamem_board_pointer;
					if (aci->addrbank->reserved_size == 0 && !(type & add_memory) && expamem_board_size < 524288) {
						aci->addrbank->reserved_size = expamem_board_size;
					}
				}
				aci->zorro = cd->zorro;
				if (cd->zorro == 3) {
					if (expamem_z3_pointer_real + expamem_board_size < expamem_z3_pointer_real) {
						expamem_z3_pointer_real = 0xffffffff;
						expamem_z3_highram_real = 0xffffffff;
					} else {
						expamem_z3_pointer_real += expamem_board_size;
					}
					if (expamem_z3_pointer_uae + expamem_board_size < expamem_z3_pointer_uae) {
						expamem_z3_pointer_uae = 0xffffffff;
						expamem_z3_highram_uae = 0xffffffff;
					} else {
						expamem_z3_pointer_uae += expamem_board_size;
					}
					if (expamem_board_pointer + expamem_board_size < expamem_board_pointer) {
						expamem_board_pointer = 0xffffffff;
					} else {
						expamem_board_pointer += expamem_board_size;
					}
					if ((type & add_memory) || aci->direct_vram) {
						if (expamem_z3_pointer_uae != 0xffffffff && expamem_z3_pointer_uae > expamem_z3_highram_uae)
							expamem_z3_highram_uae = expamem_z3_pointer_uae;
						if (expamem_z3_pointer_real != 0xffffffff && expamem_z3_pointer_real > expamem_z3_highram_real)
							expamem_z3_highram_real = expamem_z3_pointer_real;
					}

				}
			} else {
				cd->base = aci->start;
				cd->size = aci->size;
				if (log)
					write_log(_T("'%s' no autoconfig %08x - %08x.\n"), aci->label ? aci->label : _T("<no name>"), cd->base, cd->base + cd->size - 1);
			}
			_tcscpy(aci->name, label);
			if (cd->flags & CARD_FLAG_CHILD)
				aci->parent_of_previous = true;
		} else {
			if (log)
				write_log(_T("init failed.\n"), i);
		}
	}
	if (log)
		write_log(_T("END\n"));
}

int expansion_autoconfig_move(struct uae_prefs *p, int index, int dir, bool test)
{
	if (index < 0 || index >= cardno)
		return -1;
	if (!dir)
		return -1;
	struct card_data *cd1 = cards[index];
	int order1 = get_order(p, cd1);
	if (order1 < 0 || order1 >= EXPANSION_ORDER_MAX - 1)
		return -1;
	struct card_data *cd2;
	int order2;
	for (;;) {
		if (index + dir < 0 || index + dir >= cardno)
			return -1;
		cd2 = cards[index + dir];
		if (cd1->aci.parent_of_previous && !cd2->aci.parent_of_previous)
			return -1;
		order2 = get_order(p, cd2);
		if (order2 >= 0 && order2 < EXPANSION_ORDER_MAX - 1) {
			if (!cd1->aci.parent_of_previous && !cd2->aci.parent_of_previous)
				break;
		}
		dir += dir < 0 ? -1 : 1;
	}
	if (test) {
		return 0;
	}
	set_order(p, cd1, order2);
	set_order(p, cd2, order1);
	if (p != &currprefs)
		expansion_scan_autoconfig(p, false);
	for (int i = 0; i < cardno; i++) {
		if (cards[i] == cd1)
			return i;
	}
	return -1;
}

static void expansion_recalc_order(struct uae_prefs *p)
{
	int ordermin = 1;
	for (;;) {
		int order = EXPANSION_ORDER_MAX;
		int idx = -1;
		for (int i = 0; i < cardno; i++) {
			struct card_data *cdc = cards[i];
			int o = get_order(p, cdc);
			if (o >= ordermin && order > o) {
				order = o;
				idx = i;
			}
		}
		if (idx < 0)
			break;
		set_order(p, cards[idx], ordermin);
		ordermin++;
	}
}

void expansion_set_autoconfig_sort(struct uae_prefs *p)
{
	for (int i = 0; i < cardno; i++) {
		set_order(p, cards[i], i + 1);
	}
	expansion_recalc_order(p);
}

static bool ischild(struct card_data *cd)
{
	if (cd->aci.parent_name)
		return true;
	if (cd->aci.parent_address_space)
		return true;
	if (cd->aci.parent_of_previous)
		return true;
	if (cd->aci.parent_romtype)
		return true;
	return false;
}

static void check_card_child(int index, bool *inuse, int *new_cardnop)
{
	struct card_data *cd = &cards_set[index];
	int new_cardno = *new_cardnop;
	// address space "conflict" parent?
	for (int i = 0; i < cardno; i++) {
		struct card_data *cdc = &cards_set[i];
		if (inuse[i])
			continue;
		if (!cdc->aci.parent_address_space)
			continue;
		if (cd->aci.start && cd->aci.size && cdc->aci.start >= cd->aci.start && cdc->aci.start < cd->aci.start + cd->aci.size) {
			cards[new_cardno++] = cdc;
			cdc->aci.parent_of_previous = true;
			inuse[i] = true;
		}
	}
	// romtype parent?
	for (int i = 0; i < cardno; i++) {
		struct card_data *cdc = &cards_set[i];
		if (inuse[i])
			continue;
		const int *parent = cdc->aci.parent_romtype;
		if (!parent)
			continue;
		for (int j = 0; parent[j]; j++) {
			if (cd->rc && parent[j] == (cd->rc->back->device_type & ROMTYPE_MASK)) {
				cards[new_cardno++] = cdc;
				cdc->aci.parent_of_previous = true;
				inuse[i] = true;
			}
		}
	}
	// named parent
	for (int i = 0; i < cardno; i++) {
		struct card_data *cdc = &cards_set[i];
		if (inuse[i])
			continue;
		if (cdc->aci.parent_name && cd->name && !_tcsicmp(cdc->aci.parent_name, cd->name)) {
			cards[new_cardno++] = cdc;
			cdc->aci.parent_of_previous = true;
			inuse[i] = true;
		}
	}
	*new_cardnop = new_cardno;
}

static bool add_card_sort(int index, bool *inuse, int *new_cardnop)
{
	struct card_data *cd = &cards_set[index];
	if (ischild(cd))
		return false;
	int new_cardno = *new_cardnop;
	cards[new_cardno++] = cd;
	inuse[index] = true;
	int index2 = index + 1;
	// any children?
	while (index2 < cardno) {
		struct card_data *cdc = &cards_set[index2];
		struct autoconfig_info *aci = &cdc->aci;
		if (inuse[index2])
			break;
		if (!ischild(cdc))
			break;
		if (aci->parent_of_previous) {
			cards[new_cardno++] = cdc;
			inuse[index2] = true;
			check_card_child(index2, inuse, &new_cardno);
		}
		index2++;
	}
	check_card_child(index, inuse, &new_cardno);
	*new_cardnop = new_cardno;
	return true;
}

static void expansion_autoconfig_sort(struct uae_prefs *p)
{
	const int zs[] = { BOARD_NONAUTOCONFIG_BEFORE, 0, BOARD_PROTOAUTOCONFIG, BOARD_AUTOCONFIG_Z2, BOARD_NONAUTOCONFIG_AFTER_Z2, BOARD_AUTOCONFIG_Z3, BOARD_NONAUTOCONFIG_AFTER_Z3, -1 };
	bool inuse[MAX_EXPANSION_BOARD_SPACE];
	struct card_data *tcards[MAX_EXPANSION_BOARD_SPACE];
	int new_cardno = 0;

	// default sort first, sets correct parent/child order
	for (int i = 0; i < cardno; i++) {
		inuse[i] = false;
		cards[i] = NULL;
	}
	cards[cardno] = NULL;
	for (int type = 0; zs[type] >= 0; type++) {
		bool changed = true;
		int z = zs[type];
		bool inuse2[MAX_EXPANSION_BOARD_SPACE];
		memset(inuse2, 0, sizeof inuse2);
		while (changed) {
			changed = false;
			// unmovables first
			int testorder = 0;
			int idx = -1;
			for (int i = 0; i < cardno; i++) {
				if (inuse[i])
					continue;
				if (inuse2[i])
					continue;
				struct card_data *cd = &cards_set[i];
				if (ischild(cd))
					continue;
				if (cd->zorro != z)
					continue;
				int order = get_order(p, cd);
				if (cd->aci.hardwired)
					order = -1;
				if (order >= 0)
					continue;
				if (testorder > order) {
					testorder = order;
					idx = i;
				}
			}
			if (idx >= 0) {
				inuse2[idx] = true;
				add_card_sort(idx, inuse, &new_cardno);
				changed = true;
			}
		}
		changed = true;
		memset(inuse2, 0, sizeof inuse2);
		while (changed) {
			changed = false;
			for (int i = 0; i < cardno; i++) {
				if (inuse[i])
					continue;
				if (inuse2[i])
					continue;
				struct card_data *cd = &cards_set[i];
				if (ischild(cd))
					continue;
				if (cd->zorro != z)
					continue;
				if (get_order(p, cd) < EXPANSION_ORDER_MAX - 1)
					continue;
				inuse2[i] = true;
				add_card_sort(i, inuse, &new_cardno);
				changed = true;
			}
		}
		changed = true;
		memset(inuse2, 0, sizeof inuse2);
		while (changed) {
			// the rest
			changed = false;
			for (int i = 0; i < cardno; i++) {
				if (inuse[i])
					continue;
				if (inuse2[i])
					continue;
				struct card_data *cd = &cards_set[i];
				if (ischild(cd))
					continue;
				if (cd->zorro != z)
					continue;
				inuse2[i] = true;
				add_card_sort(i, inuse, &new_cardno);
				changed = true;
			}
		}
	}
	for (int i = 0; i < cardno; i++) {
		if (inuse[i])
			continue;
		cards[new_cardno++] = &cards_set[i];
	}
	for (int i = 0; i < cardno; i++) {
		struct autoconfig_info *aci = &cards[i]->aci;
		tcards[i] = cards[i];
		tcards[i]->aci.can_sort = !aci->hardwired && !aci->parent_of_previous && get_order(p, cards[i]) < EXPANSION_ORDER_MAX - 1 && get_order(p, cards[i]) >= 0;
	}

	if (!p->autoconfig_custom_sort) {

		new_cardno = 0;

		// accelerator and hardwired first
		for (int idx = 0; idx < cardno; idx++) {
			struct card_data *cd = tcards[idx];
			if (!cd)
				continue;
			if (cd->cst || cd->aci.hardwired) {
				cards[new_cardno++] = cd;
				tcards[idx] = NULL;
				for (int j = idx + 1; j < cardno; j++) {
					struct card_data *cdc = tcards[j];
					if (!cdc || !ischild(cdc))
						break;
					cards[new_cardno++] = cdc;
					tcards[j] = NULL;
				}
			}
		}
		// re-sort by board size
		for (int idx = 0; idx < cardno; idx++) {
			struct card_data *cd = tcards[idx];
			if (!cd)
				continue;
			int z = cd->zorro;
			if ((z != 2 && z != 3 && !ischild(cd)) || cd->cst) {
				cards[new_cardno++] = cd;
				tcards[idx] = NULL;
				for (int j = idx + 1; j < cardno; j++) {
					struct card_data *cdc = tcards[j];
					if (!cdc || !ischild(cdc))
						break;
					cards[new_cardno++] = cdc;
					tcards[j] = NULL;
				}
			}
		}
		for (int z = 2; z <= 3; z++) {
			for (;;) {
				int idx2 = -1;
				uae_u32 size = 0;
				for (int j = 0; j < cardno; j++) {
					struct card_data *cdc = tcards[j];
					if (cdc && cdc->size > size && cdc->zorro == z && !ischild(cdc)) {
						size = cdc->size;
						idx2 = j;
					}
				}
				if (idx2 < 0)
					break;
				cards[new_cardno++] = tcards[idx2];
				tcards[idx2] = NULL;
				for (int j = idx2 + 1; j < cardno; j++) {
					struct card_data *cdc = tcards[j];
					if (!cdc || !ischild(cdc))
						break;
					cards[new_cardno++] = cdc;
					tcards[j] = NULL;
				}
			}
		}

	} else {

		// re-sort by configuration data
		new_cardno = 0;
		for (;;) {
			int order = EXPANSION_ORDER_MAX;
			int idx = -1;
			for (int i = 0; i < cardno; i++) {
				struct card_data *cd = tcards[i];
				if (cd && get_order(p, cd) < order && !cd->aci.parent_of_previous) {
					order = get_order(p, cd);
					idx = i;
				}
			}
			if (idx >= 0) {
				struct card_data *cd = tcards[idx];
				struct autoconfig_info *aci = &cd->aci;
				cards[new_cardno++] = cd;
				tcards[idx] = NULL;
				// sort children, if any
				int child = 0;
				for (int j = idx + 1; j < cardno; j++) {
					struct card_data *cdc = tcards[j];
					if (!cdc || !cdc->aci.parent_of_previous)
						break;
					child++;
				}
				for (;;) {
					order = EXPANSION_ORDER_MAX;
					int cidx = -1;
					for (int j = 0; j < child; j++) {
						struct card_data *cdc = tcards[j + idx + 1];
						if (cdc && get_order(p, cdc) < order) {
							order = get_order(p, cdc);
							cidx = j;
						}
					}
					if (cidx < 0)
						break;
					cards[new_cardno++] = tcards[idx + 1 + cidx];
					tcards[idx + 1 + cidx] = NULL;
				}
				for (int j = 0; j < child; j++) {
					if (tcards[idx + 1 + j]) {
						cards[new_cardno++] = tcards[idx + 1 +j];
					}
				}
			}
			if (idx < 0)
				break;
		}
	}

	for (int i = 0; i < cardno; i++) {
		if (tcards[i]) {
			cards[new_cardno++] = tcards[i];
		}
	}

}

static void expansion_add_autoconfig(struct uae_prefs *p)
{
	int fastmem_num;

	reset_ac(p);

	if (p->cpuboard_type) {
		// This may require first 128k slot.
		cards_set[cardno].flags = 1;
		cards_set[cardno].name = _T("CPUBoard");
		cards_set[cardno].initrc = cpuboard_autoconfig_init;
		cards_set[cardno].zorro = BOARD_NONAUTOCONFIG_BEFORE;
		cards_set[cardno].cst = &cpuboards[p->cpuboard_type].subtypes[p->cpuboard_subtype];;
		cards_set[cardno++].map = NULL;
	}

	if (p->z3chipmem.size) {
		cards_set[cardno].flags = 0;
		cards_set[cardno].name = _T("MegaChipRAM");
		cards_set[cardno].initrc = megachipram_init;
		cards_set[cardno].zorro = BOARD_NONAUTOCONFIG_BEFORE;
		cards_set[cardno++].map = NULL;
	}

	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		struct rtgboardconfig *rbc = &p->rtgboards[i];
		int type = gfxboard_get_configtype(rbc);
		if (rbc->rtgmem_size && rbc->rtgmem_type >= GFXBOARD_HARDWARE && type == BOARD_NONAUTOCONFIG_BEFORE) {
			cards_set[cardno].flags = 4 | (i << 16);
			cards_set[cardno].name = _T("MainBoardRTG");
			cards_set[cardno].zorro = BOARD_NONAUTOCONFIG_BEFORE;
			cards_set[cardno++].initnum = gfxboard_init_memory;
		}
	}

	// add possible non-autoconfig boards
	add_cpu_expansions(p, BOARD_NONAUTOCONFIG_BEFORE, NULL);
	add_expansions(p, BOARD_NONAUTOCONFIG_BEFORE, NULL, 0);

	fastmem_num = 0;
	add_expansions(p, BOARD_PROTOAUTOCONFIG, &fastmem_num, 0);
	add_cpu_expansions(p, BOARD_AUTOCONFIG_Z2, &fastmem_num);
	// immediately after Z2Fast so that it can be emulated as A590/A2091 with fast ram.
	add_expansions(p, BOARD_AUTOCONFIG_Z2, &fastmem_num, 0);

	add_cpu_expansions(p, BOARD_NONAUTOCONFIG_AFTER_Z2, NULL);
	add_expansions(p, BOARD_NONAUTOCONFIG_AFTER_Z2, NULL, 0);

	while (fastmem_num < MAX_RAM_BOARDS) {
		if (p->fastmem[fastmem_num].size) {
			cards_set[cardno].flags = fastmem_num << 16;
			cards_set[cardno].name = _T("Z2Fast");
			cards_set[cardno].zorro = 2;
			cards_set[cardno].initnum = expamem_init_fastcard;
			cards_set[cardno++].map = expamem_map_fastcard;
		}
		fastmem_num++;
	}

#ifdef FILESYS
	if (do_mount && p->uaeboard >= 0 && p->uaeboard < 2) {
		cards_set[cardno].flags = CARD_FLAG_UAEROM;
		cards_set[cardno].name = _T("UAEFS");
		cards_set[cardno].zorro = 2;
		cards_set[cardno].initnum = expamem_init_filesys;
		cards_set[cardno++].map = expamem_map_filesys;
	}
	if (p->uaeboard > 0) {
		cards_set[cardno].flags = CARD_FLAG_UAEROM;
		cards_set[cardno].name = _T("UAEBOARD");
		cards_set[cardno].zorro = 2;
		cards_set[cardno].initnum = expamem_init_uaeboard;
		cards_set[cardno++].map = expamem_map_uaeboard;
	}
	if (do_mount && p->uaeboard < 2) {
		cards_set[cardno].flags = CARD_FLAG_UAEROM;
		cards_set[cardno].name = _T("UAEBOOTROM");
		cards_set[cardno].zorro = BOARD_NONAUTOCONFIG_BEFORE;
		cards_set[cardno].initnum = expamem_rtarea_init;
		cards_set[cardno++].map = NULL;

	}
#endif
#ifdef PICASSO96
	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		struct rtgboardconfig *rbc = &p->rtgboards[i];
		if (rbc->rtgmem_size && rbc->rtgmem_type == GFXBOARD_UAE_Z2) {
			cards_set[cardno].flags = 4 | (i << 16);
			cards_set[cardno].zorro = 2;
			cards_set[cardno].name = _T("Z2RTG");
			cards_set[cardno].initnum = expamem_init_gfxcard_z2;
			cards_set[cardno++].map = expamem_map_gfxcard_z2;
		}
	}
#endif
#ifdef GFXBOARD
	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		struct rtgboardconfig *rbc = &p->rtgboards[i];
		int type = gfxboard_get_configtype(rbc);
		if (rbc->rtgmem_size && rbc->rtgmem_type >= GFXBOARD_HARDWARE && type <= 2) {
			cards_set[cardno].flags = 4 | (i << 16);
			if (gfxboard_get_func(rbc)) {
				cards_set[cardno].name = _T("Z2RTG");
				cards_set[cardno].zorro = 2;
				cards_set[cardno].flags = (i << 16);
				cards_set[cardno++].initnum = gfxboard_init_board;
			} else {
				cards_set[cardno].name = _T("Z2RTG");
				cards_set[cardno].zorro = 2;
				cards_set[cardno++].initnum = gfxboard_init_memory;
				if (gfxboard_num_boards(rbc) == 3) {
					cards_set[cardno].flags = (i << 16) | CARD_FLAG_CHILD;
					cards_set[cardno].name = _T("Gfxboard VRAM Zorro II Extra");
					cards_set[cardno].zorro = 2;
					cards_set[cardno++].initnum = gfxboard_init_memory_p4_z2;
				}
				if (gfxboard_is_registers(rbc)) {
					cards_set[cardno].flags = (i << 16) | CARD_FLAG_CHILD;
					cards_set[cardno].name = _T("Gfxboard Registers");
					cards_set[cardno].zorro = 2;
					cards_set[cardno++].initnum = gfxboard_init_registers;
				}
				if (gfxboard_is_registers(rbc) > 1) {
					cards_set[cardno].flags = (i << 16) | CARD_FLAG_CHILD;
					cards_set[cardno].name = _T("Gfxboard Registers #2");
					cards_set[cardno].zorro = 2;
					cards_set[cardno++].initnum = gfxboard_init_registers2;
				}
			}
		}
	}
#endif
	if (p->monitoremu == MONITOREMU_FIRECRACKER24) {
		cards_set[cardno].flags = 0;
		cards_set[cardno].name = _T("FireCracker24");
		cards_set[cardno].zorro = 2;
		cards_set[cardno++].initnum = specialmonitor_autoconfig_init;
	}

	/* Z3 boards last */

	fastmem_num = 0;

	add_cpu_expansions(p, BOARD_AUTOCONFIG_Z3, &fastmem_num);

	// add combo Z3 boards (something + Z3 RAM)
	add_expansions(p, BOARD_AUTOCONFIG_Z3, &fastmem_num, 2);

	// add remaining RAM boards
	for (int i = fastmem_num; i < MAX_RAM_BOARDS; i++) {
		if (p->z3fastmem[i].size) {
			z3num = 0;
			cards_set[cardno].flags = (2 | CARD_FLAG_CAN_Z3) | (i << 16);
			cards_set[cardno].name = _T("Z3Fast");
			cards_set[cardno].zorro = 3;
			cards_set[cardno].initnum = expamem_init_z3fastmem;
			cards_set[cardno++].map = expamem_map_z3fastmem;
		}
	}
#ifdef PICASSO96
	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		if (p->rtgboards[i].rtgmem_size && p->rtgboards[i].rtgmem_type == GFXBOARD_UAE_Z3) {
			cards_set[cardno].flags = 4 | CARD_FLAG_CAN_Z3 | (i << 16);
			cards_set[cardno].name = _T("Z3RTG");
			cards_set[cardno].zorro = 3;
			cards_set[cardno].initnum = expamem_init_gfxcard_z3;
			cards_set[cardno++].map = expamem_map_gfxcard_z3;
		}
	}
#endif
#ifdef GFXBOARD
	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		struct rtgboardconfig *rbc = &p->rtgboards[i];
		if (rbc->rtgmem_size && rbc->rtgmem_type >= GFXBOARD_HARDWARE && gfxboard_get_configtype(rbc) == 3) {
			cards_set[cardno].flags = 4 | CARD_FLAG_CAN_Z3 | (i << 16);
			cards_set[cardno].name = _T("Z3RTG");
			cards_set[cardno].zorro = 3;
			cards_set[cardno++].initnum = gfxboard_init_memory;
			if (gfxboard_is_registers(rbc)) {
				cards_set[cardno].flags = 1 | (i << 16) | CARD_FLAG_CHILD;
				cards_set[cardno].zorro = 3;
				cards_set[cardno].name = _T("Gfxboard Registers");
				cards_set[cardno++].initnum = gfxboard_init_registers;
			}
		}
	}
#endif

	// add non-memory Z3 boards
	add_expansions(p, BOARD_AUTOCONFIG_Z3, NULL, 1);

	add_cpu_expansions(p,BOARD_NONAUTOCONFIG_AFTER_Z3, NULL);
	add_expansions(p, BOARD_NONAUTOCONFIG_AFTER_Z3, NULL, 0);

}

void expansion_scan_autoconfig(struct uae_prefs *p, bool log)
{
	cfgfile_compatibility_romtype(p);
	expansion_add_autoconfig(p);
	expansion_init_cards(p);
	expansion_autoconfig_sort(p);
	expansion_parse_cards(p, log);
}

void expamem_reset (int hardreset)
{
	reset_ac(&currprefs);

	chipdone = false;

	expamem_init_clear();
	allocate_expamem ();
	expamem_bank.name = _T("Autoconfig [reset]");

	expansion_add_autoconfig(&currprefs);
	expansion_init_cards(&currprefs);
	expansion_autoconfig_sort(&currprefs);
	expansion_parse_cards(&currprefs, true);

	// this also resets all autoconfig devices
	devices_reset_ext(hardreset);

	if (cardno == 0 || savestate_state) {
		expamem_init_clear_zero ();
	} else {

		for (int i = 0; i < cardno; i++) {
			card_data *cd = cards[i];
			if (cd->ert && cd->ert->preinit) {
				struct autoconfig_info *aci = &cd->aci;
				aci->prefs = &currprefs;
				aci->doinit = true;
				aci->devnum = (cd->flags >> 16) & 255;
				aci->ert = cd->ert;
				aci->cst = cd->cst;
				aci->rc = cd->rc;
				aci->zorro = cd->zorro;
				memset(aci->autoconfig_raw, 0xff, sizeof aci->autoconfig_raw);
				cd->ert->preinit(aci);
			}
		}

		set_ks12_boot_hack();
		call_card_init(0);
	}
}

void expansion_init (void)
{
	if (savestate_state != STATE_RESTORE) {

		for (int i = 0; i < MAX_RAM_BOARDS; i++) {
			mapped_free(&fastmem_bank[i]);
			fastmem_bank[i].reserved_size = 0;
			fastmem_bank[i].mask = 0;
			fastmem_bank[i].baseaddr = NULL;
		}

#ifdef PICASSO96
		for (int i = 0; i < MAX_RTG_BOARDS; i++) {
			mapped_free(gfxmem_banks[i]);
			gfxmem_banks[i]->reserved_size = 0;
			gfxmem_banks[i]->mask = 0;
			gfxmem_banks[i]->baseaddr = NULL;
		}
#endif

#ifdef CATWEASEL
		catweasel_mask = catweasel_start = 0;
#endif

		for (int i = 0; i < MAX_RAM_BOARDS; i++) {
			mapped_free(&z3fastmem_bank[i]);
			z3fastmem_bank[i].reserved_size = 0;
			z3fastmem_bank[i].mask = 0;
			z3fastmem_bank[i].baseaddr = NULL;
		}

		mapped_free(&z3chipmem_bank);
		z3chipmem_bank.reserved_size = 0;
		z3chipmem_bank.mask = z3chipmem_bank.start = 0;
		z3chipmem_bank.baseaddr = NULL;
	}

	allocate_expamem ();

	if (currprefs.uaeboard) {
		uaeboard_bank.reserved_size = 0x10000;
		mapped_malloc(&uaeboard_bank);
	}

}

void expansion_cleanup (void)
{
	for (int i = 0; i < MAX_RAM_BOARDS; i++) {
		mapped_free (&fastmem_bank[i]);
		mapped_free (&z3fastmem_bank[i]);
	}
	mapped_free (&z3chipmem_bank);

#ifdef PICASSO96
	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		if (currprefs.rtgboards[i].rtgmem_type < GFXBOARD_HARDWARE) {
			mapped_free (gfxmem_banks[i]);
		}
	}
#endif

#ifdef FILESYS
	mapped_free (&filesys_bank);
#endif
	if (currprefs.uaeboard) {
		mapped_free(&uaeboard_bank);
	}

#ifdef CATWEASEL
	catweasel_free ();
#endif
}

void expansion_map(void)
{
	map_banks(&expamem_bank, 0xE8, 1, 0);
	// map non-autoconfig ram boards
	for (int i = 0; i < MAX_RAM_BOARDS; i++) {
		struct ramboard *rb = &currprefs.fastmem[i];
		if (rb->size) {
			if (rb->manual_config) {
				map_banks(&fastmem_bank[i], rb->start_address >> 16, (rb->end_address - rb->start_address + 1) >> 16, 0);
			} else if (rb->no_reset_unmap && rb->start_address) {
				map_banks(&fastmem_bank[i], rb->start_address >> 16, rb->size >> 16, 0);
			}
			initramboard(&fastmem_bank[i], rb);
		}
		rb = &currprefs.z3fastmem[i];
		if (rb->size) {
			if (rb->manual_config) {
				map_banks(&z3fastmem_bank[i], rb->start_address >> 16, (rb->end_address - rb->start_address + 1) >> 16, 0);
			} else if (rb->no_reset_unmap && rb->start_address) {
				map_banks(&z3fastmem_bank[i], rb->start_address >> 16, rb->size >> 16, 0);
			}
			initramboard(&z3fastmem_bank[i], rb);
		}
	}
	for (int i = 0; i < MAX_ROM_BOARDS; i++) {
		struct romboard *rb = &currprefs.romboards[i];
		if (rb->size) {
			loadboardfile(&romboardmem_bank[i], &rb->lf);
			map_banks(&romboardmem_bank[i], rb->start_address >> 16, rb->size >> 16, 0);
		}
	}
	if (currprefs.z3chipmem.size) {
		map_banks_z3(&z3chipmem_bank, z3chipmem_bank.start >> 16, currprefs.z3chipmem.size >> 16);
	}
	if (do_mount < 0 && ks11orolder()) {
		filesys_bank.start = 0xe90000;
		mapped_free(&filesys_bank);
		mapped_malloc(&filesys_bank);
		map_banks_z2(&filesys_bank, filesys_bank.start >> 16, 1);
		expamem_init_filesys(0);
		expamem_map_filesys_update();
	}
}

static void clear_bank (addrbank *ab)
{
	if (!ab->baseaddr || !ab->allocated_size)
		return;
	memset (ab->baseaddr, 0, ab->allocated_size > 0x800000 ? 0x800000 : ab->allocated_size);
}

void expansion_clear (void)
{
	for (int i = 0; i < MAX_RAM_BOARDS; i++) {
		clear_bank (&fastmem_bank[i]);
		clear_bank (&z3fastmem_bank[i]);
	}
	clear_bank (&z3chipmem_bank);
	for (int i = 0; i < MAX_RTG_BOARDS; i++) {
		clear_bank (gfxmem_banks[i]);
	}
}

#ifdef SAVESTATE

/* State save/restore code.  */

uae_u8 *save_fram(size_t *len, int num)
{
	*len = fastmem_bank[num].allocated_size;
	return fastmem_bank[num].baseaddr;
}

uae_u8 *save_zram(size_t *len, int num)
{
	if (num < 0) {
		*len = z3chipmem_bank.allocated_size;
		return z3chipmem_bank.baseaddr;
	}
	*len = z3fastmem_bank[num].allocated_size;
	return z3fastmem_bank[num].baseaddr;
}

uae_u8 *save_pram(size_t *len)
{
	*len = gfxmem_banks[0]->allocated_size;
	return gfxmem_banks[0]->baseaddr;
}

void restore_fram(int len, size_t filepos, int num)
{
	fast_filepos[num] = filepos;
	changed_prefs.fastmem[num].size = len;
}

void restore_zram(int len, size_t filepos, int num)
{
	if (num == -1) {
		z3_fileposchip = filepos;
		changed_prefs.z3chipmem.size = len;
	} else {
		z3_filepos[num] = filepos;
		changed_prefs.z3fastmem[num].size = len;
	}
}

void restore_pram(int len, size_t filepos)
{
	p96_filepos = filepos;
	changed_prefs.rtgboards[0].rtgmem_size = len;
}

uae_u8 *save_expansion(size_t *len, uae_u8 *dstptr)
{
	uae_u8 *dst, *dstbak;
	if (dstptr)
		dst = dstbak = dstptr;
	else
		dstbak = dst = xmalloc (uae_u8, 6 * 4);
	save_u32 (fastmem_bank[0].start);
	save_u32 (z3fastmem_bank[0].start);
	save_u32 (gfxmem_banks[0]->start);
	save_u32 (rtarea_base);
	save_u32 (fastmem_bank[1].start);
	*len = 4 + 4 + 4 + 4 + 4;
	return dstbak;
}

uae_u8 *restore_expansion(uae_u8 *src)
{
	fastmem_bank[0].start = restore_u32 ();
	z3fastmem_bank[0].start = restore_u32 ();
	gfxmem_banks[0]->start = restore_u32 ();
	rtarea_base = restore_u32 ();
	fastmem_bank[1].start = restore_u32 ();
	if (rtarea_base != 0 && rtarea_base != RTAREA_DEFAULT && rtarea_base != RTAREA_BACKUP && rtarea_base != RTAREA_BACKUP_2 && (rtarea_base < 0xe90000 || rtarea_base >= 0xf00000))
		rtarea_base = 0;
	return src;
}

uae_u8 *save_expansion_boards(size_t *len, uae_u8 *dstptr, int cardnum)
{
	uae_u8 *dst, *dstbak;
	if (cardnum >= cardno)
		return NULL;
	if (dstptr)
		dst = dstbak = dstptr;
	else
		dstbak = dst = xmalloc(uae_u8, 1000);
	save_u32(3);
	save_u32(0);
	save_u32(cardnum);
	struct card_data *ec = cards[cardnum];
	save_u32(ec->base);
	save_u32(ec->size);
	save_u32(ec->flags);
	save_string(ec->name);
	for (int j = 0; j < 16; j++) {
		save_u8(ec->aci.autoconfig_bytes[j]);
	}
	struct romconfig *rc = ec->rc;
	if (rc && rc->back) {
		save_u32(rc->back->device_type);
		save_u32(rc->back->device_num);
		save_string(rc->romfile);
		save_string(rc->romident);
		save_u32(rc->device_id);
		save_u32(rc->device_settings);
		save_string(rc->configtext);
	} else {
		save_u32(0xffffffff);
	}
	*len = dst - dstbak;
	return dstbak;
}

uae_u8 *restore_expansion_boards(uae_u8 *src)
{
	if (!src) {
		restore_cardno = 0;
#if 0
		currprefs.uaeboard = changed_prefs.uaeboard = -1;
#endif
		return NULL;
	}
	TCHAR *s;
	uae_u32 flags = restore_u32();
	if (!(flags & 2))
		return src;
	restore_u32();
	int cardnum = restore_u32();
	restore_cardno = cardnum + 1;
	struct card_data *ec = &cards_set[cardnum];
	cards[cardnum] = ec;

	ec->base = restore_u32();
	ec->size = restore_u32();
	ec->flags = restore_u32();
	s = restore_string();
	xfree(s);
	for (int j = 0; j < 16; j++) {
		ec->aci.autoconfig_bytes[j] = restore_u8();
	}
#if 0
	if (ec->flags & CARD_FLAG_UAEROM) {
		if (ec->base >= 0xe90000 && ec->base < 0xf00000) {
			if (ec->size > 65536) {
				currprefs.uaeboard = changed_prefs.uaeboard = 2;
			} else {
				if (currprefs.uaeboard < 0) {
					currprefs.uaeboard = changed_prefs.uaeboard = 0;
				} else {
					currprefs.uaeboard = changed_prefs.uaeboard = 1;
				}
			}
		} else {
			currprefs.uaeboard = changed_prefs.uaeboard = 0;
		}
	}
#endif
	uae_u32 dev_num = 0;
	uae_u32 romtype = restore_u32();
	if (romtype != 0xffffffff) {
		dev_num = restore_u32();
		ec->aci.devnum = dev_num;
		struct boardromconfig* brc = get_device_rom(&currprefs, romtype, dev_num, NULL);
		if (!brc) {
			brc = get_device_rom_new(&currprefs, romtype, dev_num, NULL);
		}
		struct romconfig *rc = get_device_romconfig(&currprefs, romtype, dev_num);
		if (rc) {
			ec->rc = rc;
			rc->back = brc;
			ec->ert = get_device_expansion_rom(romtype);
			s = restore_string();
			_tcscpy(rc->romfile, s);
			xfree(s);
			s = restore_string();
			_tcscpy(rc->romident, s);
			xfree(s);
			rc->device_id = restore_u32();
			rc->device_settings = restore_u32();
			s = restore_string();
			_tcscpy(rc->configtext, s);
			xfree(s);
		}
	}
	return src;
}

#if 0
// old style
uae_u8 *save_expansion_info_old(int *len, uae_u8 *dstptr)
{
	uae_u8* dst, * dstbak;
	if (dstptr)
		dst = dstbak = dstptr;
	else
		dstbak = dst = xmalloc(uae_u8, 100 + MAX_EXPANSION_BOARD_SPACE * 100);
	save_u32(1);
	save_u32(0);
	save_u32(cardno);
	for (int i = 0; i < cardno; i++) {
		struct card_data* ec = cards[i];
		if (ec->rc) {
			save_u32(ec->rc->back->device_type);
			save_u32(ec->rc->back->device_num);
			save_string(ec->rc->romfile);
			save_string(ec->rc->romident);
		}
		else {
			save_u32(0xffffffff);
		}
		save_u32(ec->base);
		save_u32(ec->size);
		save_u32(ec->flags);
		save_string(ec->name);
	}
	save_u32(0);
	*len = dst - dstbak;
	return dstbak;
}

uae_u8 *restore_expansion_info_old(uae_u8 *src)
{
	if (restore_cardno)
		return src;
	if (restore_u32() != 1)
		return src;
	restore_u32();
	int num = restore_u32();
	for (int i = 0; i < num; i++) {
		int romtype = restore_u32();
		if (romtype != 0xffffffff) {
			restore_u32();
			restore_string();
			restore_string();
		}
		restore_u32();
		restore_u32();
		restore_u32();
		restore_string();
	}
	restore_u32();
	return src;
}
#endif

void restore_expansion_finish(void)
{
	cardno = restore_cardno;
	restore_cardno = 0;
	for (int i = 0; i < cardno; i++) {
		struct card_data *ec = &cards_set[i];
		cards[i] = ec;
		struct romconfig *rc = ec->rc;
		expamem_board_pointer = ec->base;
		// Handle only IO boards, RAM boards are handled differently
		ec->aci.doinit = false;
		ec->aci.start = ec->base;
		ec->aci.size = ec->size;
		ec->aci.prefs = &currprefs;
		ec->aci.ert = ec->ert;
		ec->aci.rc = rc;
		if (rc && ec->ert) {
			_tcscpy(ec->aci.name, ec->ert->friendlyname);
			if (ec->ert->init) {
				if (ec->ert->init(&ec->aci)) {
					if (ec->aci.addrbank) {
						map_banks(ec->aci.addrbank, ec->base >> 16, ec->size >> 16, 0);
					}
				}
			}
			ec->aci.doinit = true;
		}
	}
}


#endif /* SAVESTATE */

#if 0
static const struct expansionsubromtype a2090_sub[] = {
	{
		_T("A2090a"), _T("a2090a"),
		0, 0, 0,
		{ 0 },
	},
	{
		_T("A2090a + 1M RAM"), _T("a2090a_2"),
		0, 0, 0,
		{ 0 },
	},
	{
		NULL
	}
};
#endif

static const struct expansionboardsettings voodoo_settings[] = {
	{
		_T("Direct VRAM access in little endian modes"), _T("directvram")
	},
	{
		NULL
	}
};

static const struct expansionsubromtype a2091_sub[] = {
	{
		_T("DMAC-01"), _T("dmac01"), 0,
		commodore, commodore_a2091_ram, 0, true,
		{ 0 }
	},
	{
		_T("DMAC-02"), _T("dmac02"), 0,
		commodore, commodore_a2091_ram, 0, true,
		{ 0 }
	},
	{
		NULL
	}
};
static const struct expansionsubromtype gvp1_sub[] = {
	{
		_T("Impact A2000-1/X"), _T("a2000-1"), 0,
		1761, 8, 0, false,
		{ 0 }
	},
	{
		_T("Impact A2000-HC"), _T("a2000-hc"), 0,
		1761, 8, 0, false,
		{ 0 }
	},
	{
		_T("Impact A2000-HC+2"), _T("a2000-hc+"), 0,
		1761, 8, 0, false,
		{ 0 }
	},
	{
		NULL
	}
};
static const struct expansionsubromtype masoboshi_sub[] = {
	{
		_T("MC-302"), _T("mc-302"), 0,
		2157, 3, 0, false,
		{ 0 }
	},
	{
		_T("MC-702"), _T("mc-702"), 0,
		2157, 3, 0, false,
		{ 0 }
	},
	{
		NULL
	}
};
static const struct expansionsubromtype rochard_sub[] = {
	{
		_T("IDE"), _T("ide"), 0,
		2144, 2, 0, false,
		{ 0 }
	},
	{
		_T("IDE+SCSI"), _T("scsi"), 0,
		2144, 2, 0, false,
		{ 0 }
	},
	{
		NULL
	}
};

static const struct expansionsubromtype trifecta_sub[] = {
	{
		_T("EC (IDE)"), _T("ec"), 0, // IDE-only
		2071, 32, 0, false,
		{ 0 }
	},
	{
		_T("LX (IDE + SCSI)"), _T("lx"), 0, // IDE+SCSI
		2071, 32, 0, false,
		{ 0 }
	},
	{
		NULL
	}
};
static const struct expansionboardsettings trifecta_settings[] = {
	{
		_T("Boot delay\0") _T("off (A=0,B=0)\0") _T("8s (A=1,B=0)\0") _T("16s (A=0,B=1)\0") _T("24s (A=1,B=1)\0"),
		_T("bootdelay\0") _T("bootdelay0\0") _T("bootdelay8\0") _T("bootdelay16\0") _T("bootdelay24\0"),
		true
	},
	{
		_T("Buffers (C)"), _T("jumper_c")
	},
	{
		_T("Unused (D)"), _T("jumper_d")
	},
	{
		_T("Adspeed (E)"), _T("jumper_e")
	},
	{
		NULL
	}
};

static const struct expansionboardsettings trumpcard_settings[] = {
	{
		_T("Interrupt support"), _T("irq")
	},
	{
		NULL
	}
};


static const struct expansionsubromtype accessx_sub[] = {
	{
		_T("AccessX 500"), _T("accessx500"), ROMTYPE_ACCESSX,
	},
	{
		_T("AccessX 2000"), _T("accessx2000"), ROMTYPE_ACCESSX,
	},
	{
		NULL
	}
};

static const struct expansionsubromtype supra_sub[] = {
	{
		_T("A500 ByteSync/XP"), _T("bytesync"), ROMTYPE_NONE | ROMTYPE_SUPRA,
		1056, 9, 0, false, 0,
		{ 0xd1, 13, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("A2000 Word Sync"), _T("wordsync"), ROMTYPE_NONE | ROMTYPE_SUPRA,
		1056, 9, 0, false, 0,
		{ 0xd1, 12, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("A500 Autoboot"), _T("500"), ROMTYPE_NONE | ROMTYPE_SUPRA,
		1056, 5, 0, false, 0,
		{ 0xd1, 8, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("Non Autoboot (4x4)"), _T("4x4"), ROMTYPE_NOT | ROMTYPE_SUPRA,
		1056, 2, 0, false, 0,
		{ 0xc1, 1, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	},
	{
		_T("2000 DMA"), _T("dma"), ROMTYPE_NONE | ROMTYPE_SUPRA,
		1056, 2, 0, false, EXPANSIONTYPE_DMA24,
		{ 0xd1, 3, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00 },
	},
	{
		NULL
	}
};
static const struct expansionsubromtype comspec_sub[] = {
	{
		_T("Comspec SA-1000"), _T("comspec1000"), ROMTYPE_NONE | ROMTYPE_COMSPEC,
	},
	{
		_T("Comspec SA-2000"), _T("comspec2000"), ROMTYPE_NONE | ROMTYPE_COMSPEC,
	},
	{
		NULL
	} 
};

static const struct expansionsubromtype mediator_sub[] = {
	{
		_T("1200"), _T("1200"), ROMTYPE_NOT | ROMTYPE_MEDIATOR
	},
	{
		_T("1200SX"), _T("1200sx"), ROMTYPE_NOT | ROMTYPE_MEDIATOR
	},
	{
		_T("1200TX"), _T("1200tx"), ROMTYPE_NOT | ROMTYPE_MEDIATOR
	},
	{
		_T("4000MK2"), _T("4000mkii"), ROMTYPE_NOT | ROMTYPE_MEDIATOR
	},
	{
		NULL
	}
};

static const struct expansionboardsettings mediator_settings[] = {
	{
		_T("Full PCI DMA"),
		_T("fulldma")
	},
	{
		_T("Win Size"),
		_T("winsize")
	},
	{
		_T("Swap Config"),
		_T("swapconfig")
	},
	{
		NULL
	}
};
static const struct expansionboardsettings bridge_settings[] = {
	{
		_T("Full PCI DMA"),
		_T("fulldma")
	},
	{
		NULL
	}
};

static const struct expansionboardsettings x86vga_settings[] = {
	{
		_T("Chipset\0") _T("CL-GD5426\0") _T("CL-GD5429\0"),
		_T("chipset\0") _T("cl-gd5426\0") _T("cl-gd5429\0"),
		true
	},
	{
		NULL
	}
};


static const struct expansionboardsettings x86at286_bridge_settings[] = {
	{
		// 13
		_T("PC Speaker emulation"),
		_T("speaker"),
		false, false, 13
	},
	{
		// 14
		_T("Default video\0") _T("Monochrome\0") _T("Color\0"),
		_T("video\0") _T("mono\0") _T("color\0"),
		true
	},
	{
		// 15
		_T("Keyboard lock"),
		_T("keylock"),
		false
	},
	{	// 16 - 18
		_T("Memory\0") _T("1M\0") _T("2M\0") _T("4M\0") _T("8M\0") _T("16M\0"),
		_T("memory\0") _T("1M\0") _T("2M\0") _T("4M\0") _T("8M\0") _T("16M\0"),
		true, false, 0
	},
	{
		// 19
		_T("FPU"),
		_T("fpu"),
	},
	{
		_T("Emulator config\0"),
		_T("config\0"),
		2, false, 0
	},
	{
		NULL
	}
};

static const struct expansionboardsettings x86at386_bridge_settings[] = {
	{
		// 13
		_T("PC Speaker emulation"),
		_T("speaker"),
		false, false, 13
	},
	{
		// 15
		_T("Keyboard lock"),
		_T("keylock"),
		false, false, 15 - 14
	},
	{	// 16 - 18
		_T("Memory\0") _T("1M\0") _T("2M\0") _T("4M\0") _T("8M\0") _T("16M\0") _T("32M\0") _T("64M\0"),
		_T("memory\0") _T("1M\0") _T("2M\0") _T("4M\0") _T("8M\0") _T("16M\0") _T("32M\0") _T("64M\0"),
		true, false, 0
	},
	{
		// 19
		_T("FPU"),
		_T("fpu"),
	},
	{
		_T("Emulator config\0"),
		_T("config\0"),
		2, false, 0
	},
	{
		NULL
	}
};

// A2088/A2088T
static const struct expansionboardsettings x86_bridge_settings[] = {
	{
		// 2-3
		_T("Memory (SW1:3-4)\0") _T("128K\0") _T("256K\0") _T("512K\0") _T("640K\0"),
		_T("memory\0") _T("128k\0") _T("256k\0") _T("512k\0") _T("640k\0"),
		true, false, 2
	},
	{
		// 4-5
		_T("Default video (J1)\0") _T("Monochrome\0") _T("Color 40x25\0") _T("Color 80x25\0") _T("None\0"),
		_T("video\0") _T("mono\0") _T("color40\0") _T("color80\0") _T("none\0"),
		true, false, 0
	},
	{
		// 13
		_T("PC Speaker emulation"),
		_T("speaker"),
		false, false, 13 - 6
	},
	{
		// 19
		_T("FPU"),
		_T("fpu"),
		false, false, 19 - 14
	},
	{
		_T("Emulator config\0"),
		_T("config\0"),
		2, false, 0
	},
	{
		NULL
	}
};

static const struct expansionboardsettings x86_bridge_sidecar_settings[] = {
	{
		// 0
		_T("System Diagnostics (SW1:1)"),
		_T("diagnostics"),
	},
	{
		// 1
		_T("8087 installed (SW1:2)"),
		_T("fpu"),
	},
	{
		// 2-3
		_T("Memory (SW1:3-4)\0") _T("128K\0") _T("256K\0") _T("512K\0") _T("640K\0"),
		_T("memory\0") _T("128k\0") _T("256k\0") _T("512k\0") _T("640k\0"),
		true
	},
	{
		// 4-5
		_T("Default video (SW1:5-6)\0") _T("Monochrome\0") _T("Color 40x25\0") _T("Color 80x25\0") _T("None\0"),
		_T("video\0") _T("mono\0") _T("color40\0") _T("color80\0") _T("none\0"),
		true
	},
	{
		// 6-7
		_T("Floppy drives (SW1:7-8)\0") _T("1\0") _T("2\0") _T("3\0") _T("4\0"),
		_T("floppy\0") _T("floppy1\0") _T("floppy2\0") _T("floppy3\0") _T("floppy4\0"),
		true
	},
	{
		// 8
		_T("Disable mono video emulation (SW2:1)"),
		_T("mono_card")
	},
	{
		// 9
		_T("Disable color video emulation (SW2:2)"),
		_T("color_card")
	},
	{
		// 10-11
		_T("Address sector (SW2:3-4)\0") _T("A0000-AFFFF (1)\0") _T("A0000-AFFFF (2)\0") _T("D0000-DFFFF\0") _T("E0000-EFFFF\0"),
		_T("memory\0") _T("sector_a0000_1\0") _T("sector_a0000_2\0") _T("sector_d0000\0") _T("sector_e0000\0"),
		true
	},
	{
		// 12
		_T("Disable parallel port emulation (J11)"),
		_T("parport_card")
	},
	{
		// 13
		_T("PC Speaker emulation"),
		_T("speaker")
	},
	{
		// 19
		_T("FPU"),
		_T("fpu"),
		false, false, 19 - 14
	},
	{
		_T("Emulator config\0"),
		_T("config\0"),
		2, false, 0
	},
	{
		NULL
	}
};

static const struct expansionboardsettings toccata_soundcard_settings[] = {
	{
		_T("Paula/CD audio mixer"),
		_T("mixer")
	},
	{
		NULL
	}
};

static const struct expansionboardsettings x86_athdxt_settings[] = {
	{
		_T("ROM address\0") _T("0xCC000\0") _T("0xDC000\0") _T("0xEC000\0"),
		_T("baseaddress\0") _T("0xcc000\0") _T("0xdc000\0") _T("0xec000\0"),
		true
	},
	{
		NULL
	}
};

static const struct expansionboardsettings x86_rt1000_settings[] = {
	{
		_T("Base address\0") _T("0xC8000\0") _T("0xCC000\0") _T("0xD0000\0") _T("0xD4000\0") _T("0xD8000\0") _T("0xDC000 (*)\0") _T("0xE0000\0") _T("0xE4000\0"),
		_T("baseaddress\0") _T("0xc8000\0") _T("0xcc000\0") _T("0xd0000\0") _T("0xd4000\0") _T("0xd8000\0") _T("0xdc000\0") _T("0xe0000\0") _T("0xe4000\0"),
		true
	},
	{
		NULL
	}
};

static const struct expansionboardsettings harlequin_settings[] = {
	{
		_T("Model\0") _T("Harlequin (PAL)\0") _T("Harlequin (NTSC)\0") _T("Harlequin Plus (PAL)\0") _T("Harlequin Plus (NTSC)\0"),
		_T("model\0") _T("pal\0") _T("ntsc\0") _T("pluspal\0") _T("plusntsc\0"),
		true
	},
	{
		_T("VRAM\0") _T("1.5M\0") _T("2M\0") _T("3M\0") _T("4M\0"),
		_T("vram\0") _T("1.5m\0") _T("2m\0") _T("3m\0") _T("4m\0"),
		true
	},
	{
		_T("Genlock"),
		_T("genlock")
	},
	{
		NULL
	}
};

static const struct expansionboardsettings cubo_settings[] = {
	{
		_T("DIP1 #1"),
		_T("dip_1_1")
	},
	{
		_T("DIP1 #2"),
		_T("dip_1_2")
	},
	{
		_T("DIP1 #3"),
		_T("dip_1_3")
	},
	{
		_T("DIP1 #4"),
		_T("dip_1_4")
	},
	{
		_T("DIP1 #5"),
		_T("dip_1_5")
	},
	{
		_T("DIP1 #6"),
		_T("dip_1_6")
	},
	{
		_T("DIP1 #7"),
		_T("dip_1_7")
	},
	{
		_T("DIP1 #8"),
		_T("dip_1_8")
	},
	{
		_T("DIP2 #1"),
		_T("dip_2_1")
	},
	{
		_T("DIP2 #2"),
		_T("dip_2_2")
	},
	{
		_T("DIP2 #3"),
		_T("dip_2_3")
	},
	{
		_T("DIP2 #4"),
		_T("dip_2_4")
	},
	{
		_T("DIP2 #5"),
		_T("dip_2_5")
	},
	{
		_T("DIP2 #6"),
		_T("dip_2_6")
	},
	{
		_T("DIP2 #7"),
		_T("dip_2_7")
	},
	{
		_T("DIP2 #8"),
		_T("dip_2_8")
	},
	{
		_T("NVRAM installed"),
		_T("nvram")
	},
	{
		_T("RTC installed"),
		_T("rtc")
	},
	{
		_T("Touchscreen installed"),
		_T("ts")
	},
	{
		_T("PIC configuration (AB:KEY)\0"),
		_T("pic\0"),
		2, false, 0
	},
	{
		NULL
	}
};

static struct expansionboardsettings x86_mouse_settings[] = {
	{
		_T("Amiga port\0") _T("1\0") _T("2\0"),
		_T("port\0") _T("1\0") _T("2\0"),
		true
	},
	{
		_T("Mouse type\0") _T("Serial (COM1)\0") _T("PS/2 (2-Button)\0") _T("PS/2 (Intellimouse)"),
		_T("type\0") _T("serial\0") _T("ps2\0") _T("im\0"),
		true, false, 1
	},
	{
		NULL
	}
};

static struct expansionboardsettings sb_isa_settings[] = {
	{
		_T("Model\0") _T("Sound Blaster v1.0\0") _T("Sound Blaster v1.5\0") _T("Sound Blaster v2.0\0") _T("Sound Blaster Pro v1\0") _T("Sound Blaster Pro v2\0") _T("Sound Blaster 16\0"),
		_T("model\0") _T("SB1\0") _T("SB15\0") _T("SB2\0") _T("SBP1\0") _T("SBP2\0") _T("SB16\0"),
		true, false, 
	},
	{
		_T("IO\0") _T("210\0") _T("220 (*)\0") _T("230\0") _T("240\0") _T("250\0") _T("260\0") _T("270\0") _T("280\0"),
		_T("io\0") _T("210\0") _T("220\0") _T("230\0") _T("240\0") _T("250\0") _T("260\0") _T("270\0") _T("280\0"),
		true, false,
	},
	{
		_T("IRQ (SB16: not used)\0") _T("2\0") _T("3\0") _T("5\0") _T("7 (*)\0") _T("10 (SB Pro)\0"),
		_T("irq\0") _T("irq2\0") _T("irq3\0") _T("irq5\0") _T("irq7\0") _T("irq10\0"),
		true, false,
	},
	{
		_T("DMA (SB16: not used)\0") _T("1 (*)\0") _T("3\0"),
		_T("dma\0") _T("dma1\0") _T("dma3\0"),
		true, false,
	},
	{
		_T("OPL EMU (SB Pro v2+)\0") _T("DBOPL\0") _T("NukedOPL\0"),
		_T("opl_emu\0") _T("dbopl\0") _T("nukedopl\0"),
		true, false, 0
	},
	{
		NULL
	}
};

static struct expansionboardsettings ne2k_isa_settings[] = {
	{
		_T("IO\0") _T("240\0") _T("260\0") _T("280\0") _T("2A0\0") _T("300\0") _T("320\0") _T("340\0") _T("360\0"),
		_T("io\0") _T("240\0") _T("260\0") _T("280\0") _T("2A0\0") _T("300\0") _T("320\0") _T("340\0") _T("360\0"),
		true, false, 0
	},
	{
		_T("IRQ\0") _T("3\0") _T("4\0") _T("5\0") _T("7\0") _T("9\0") _T("10\0") _T("11\0") _T("12\0") _T("15\0"),
		_T("irq\0") _T("3\0") _T("4\0") _T("5\0") _T("7\0") _T("9\0") _T("10\0") _T("11\0") _T("12\0") _T("15\0"),
		true, false, 0
	},
	{
		_T("MAC (xx:xx:xx:xx:xx:xx)\0"),
		_T("mac\0"),
		2, false, 0
	},
	{
		NULL, NULL,
		true, false, 16 - (4 + 3)
	},
	{
		NULL
	}
};

static struct expansionboardsettings lanrover_settings[] ={
	{
		_T("Interrupt level\0") _T("2\0") _T("6\0"),
		_T("irq\0") _T("2\0") _T("6\0"),
		true, false, 0
	},
	{
		_T("MAC (xx:xx:xx:xx:xx:xx)\0"),
		_T("mac\0"),
		2, false, 0
	},
	{
		NULL, NULL,
		true, false, 15
	},
	{
		NULL
	}
};
static struct expansionboardsettings ethernet_settings[] = {
	{
		_T("MAC (xx:xx:xx:xx:xx:xx)\0"),
		_T("mac\0"),
		2, false, 0
	},
	{
		NULL, NULL,
		true, false, 16
	},
	{
		NULL
	}
};

static struct expansionboardsettings *netsettings[] = {
	ethernet_settings,
	lanrover_settings,
	ne2k_isa_settings,
	NULL
};

struct netdriverdata **target_ethernet_enumerate(void);

uae_u32 ethernet_getselection(const TCHAR *name)
{
	struct netdriverdata **ndd = target_ethernet_enumerate();
	if (!ndd)
		return 0;
	for (int i = 0; ndd && i < MAX_TOTAL_NET_DEVICES; i++) {
		if (ndd[i] && !_tcsicmp(ndd[i]->name, name))
			return i << 16;
	}
	return 0;
}

const TCHAR *ethernet_getselectionname(uae_u32 settings)
{
	struct netdriverdata **ndd = target_ethernet_enumerate();
	if (!ndd)
		return 0;
	settings = (settings >> 16) & 255;
	for (int i = 0; ndd && i < MAX_TOTAL_NET_DEVICES; i++) {
		if (i == settings)
			return ndd[i]->name;
	}
	return _T("slirp");
}

void ethernet_updateselection(void)
{
	static int updated;
	if (updated)
		return;
	updated = 1;
	struct netdriverdata **ndd = target_ethernet_enumerate();
	if (!ndd)
		return;
	static TCHAR tmp1[MAX_DPATH];
	static TCHAR tmp2[MAX_DPATH];
	_tcscpy(tmp1, _T("Network mode"));
	_tcscpy(tmp2, _T("netmode"));
	TCHAR *p1 = tmp1 + _tcslen(tmp1) + 1;
	TCHAR *p2 = tmp2 + _tcslen(tmp2) + 1;
	for (int i = 0; ndd && i < MAX_TOTAL_NET_DEVICES; i++) {
		if (ndd[i]) {
			TCHAR mac[20];
			mac[0] = 0;
			if (ndd[i]->type == UAENET_SLIRP || ndd[i]->type == UAENET_SLIRP_INBOUND) {
				_stprintf(mac, _T(" xx:xx:xx:%02X:%02X:%02X"),
					ndd[i]->mac[3], ndd[i]->mac[4], ndd[i]->mac[5]);
			}
			_stprintf(p1, _T("%s%s"), ndd[i]->desc, mac[0] ? mac : _T(""));
			p1 += _tcslen(p1) + 1;
			_tcscpy(p2, ndd[i]->name);
			p2 += _tcslen(p2) + 1;
		}
	}
	*p1 = 0;
	*p2 = 0;
	for (int i = 0; netsettings[i]; i++) {
		struct expansionboardsettings *ebs = netsettings[i];
		int j;
		for (j = 0; ebs[j].name; j++);
		ebs[j].name = tmp1;
		ebs[j].configname = tmp2;
	}
}

static void fastlane_memory_callback(struct romconfig *rc, uae_u8 *ac, int size)
{
	struct zfile *z = read_device_from_romconfig(rc, NULL);
	if (z) {
		// load autoconfig data from rom file
		uae_u8 act[16] = { 0 };
		zfile_fseek(z, 0x80, SEEK_SET);
		zfile_fread(act, 1, 16, z);
		zfile_fclose(z);
		for(int i = 1; i < 16; i++) {
			ac[i] = ~act[i];
			act[i] = ~act[i];
		}
		// don't overwrite uae configured memory size
		ac[0] = (ac[0] & 7) | (act[0] & 0xf8);
		ac[2] = (ac[2] & 0x0f) | (act[2] & 0xf0);
	}
}
static void hda506_memory_callback(struct romconfig *rc, uae_u8 *ac, int size)
{
	if (currprefs.cs_a1000ram)
		ac[1] = 1;
	else
		ac[1] = 2;
}
static void nexus_memory_callback(struct romconfig *rc, uae_u8 *ac, int size)
{
	if (rc->device_settings & 1)
		ac[0] &= ~(1 << 5);
	if (size <= 2 * 1024 * 1024)
		ac[1] = 2;
	else if (size <= 4 * 1024 * 1024)
		ac[1] = 4;
	else
		ac[1] = 8;
}
static const struct expansionboardsettings inmate_settings[] = {
	{
		_T("M0"), _T("m0")
	},
	{
		_T("M1"), _T("m1")
	},
	{
		_T("AMEM"), _T("amem")
	},
	{
		_T("BTIME"), _T("btime")
	},
	{
		_T("ABOOT"), _T("aboot")
	},
	{
		_T("FPU"), _T("fpu")
	},
	{
		_T("MAP 4/8"), _T("map48")
	},
	{
		NULL
	}
};

static const struct expansionboardsettings golemfast_settings[] = {
	{
		_T("IDE"),
		_T("ide")
	},
	{
		NULL
	}
};
static const struct expansionboardsettings nexus_settings[] = {
	{
		_T("MEM TEST"),
		_T("memtest")
	},
	{
		NULL
	}
};
static const struct expansionboardsettings buddha_settings[] = {
	{
		_T("Model\0") _T("Buddha\0") _T("Buddha plus one\0") _T("Catweasel Z2\0"),
		_T("model\0") _T("buddha\0") _T("buddhaplusone\0") _T("cwz2\0"),
		true, false, 0
	},
	{
		NULL
	}
};
static const struct expansionboardsettings fastata_settings[] = {
	{
		_T("Model\0") _T("MK I\0") _T("MK II/III\0"),
		_T("model\0") _T("mk1\0") _T("mk2\0"),
		true, false, 0
	},
	{
		NULL
	}
};
static const struct expansionboardsettings adscsi2000_settings[] = {
	{
		_T("Cache (B)"),
		_T("B")
	},
	{
		NULL
	}
};
static const struct expansionboardsettings warpengine_settings[] = {
	{
		_T("Jumper H"),
		_T("jumper_h")
	},
	{
		_T("Jumper J"),
		_T("jumper_j")
	},
	{
		_T("Jumper K"),
		_T("jumper_k")
	},
	{
		NULL
	}
};
static const struct expansionboardsettings comspec_settings[] = {
	{
		_T("RTC"),
		_T("rtc"),
	},
	{
		NULL
	}
};
static const struct expansionboardsettings a2090a_settings[] = {
	{
		_T("Disable ST-506 support"),
		_T("nost506"),
	},
	{
		NULL
	}
};
static const struct expansionboardsettings a4091_settings[] = {
	{
		_T("Fast Bus"),
		_T("fastbus"),
	},
	{
		_T("Delayed autoboot"),
		_T("delayedautoboot")
	},
	{
		_T("Syncronous mode"),
		_T("syncmode")
	},
	{
		_T("Termination"),
		_T("term")
	},
	{
		_T("LUN"),
		_T("lun")
	},
	{
		NULL
	}
};
static const struct expansionboardsettings dataflyersplus_settings[] = {
	{
		_T("Configuration\0") _T("SCSI+IDE\0") _T("SCSI\0") _T("IDE\0"),
		_T("config\0") _T("scsiide\0") _T("scsi\0") _T("ide\0"),
		true
	},
	{
		NULL
	}
};
static const struct expansionboardsettings alf3_settings[] = {
	{
		_T("Parity (J6)"),
		_T("j6"),
	},
	{
		_T("LUN (J7)"),
		_T("j7"),
	},
	{
		_T("Disconnect/Reconnect (J8)"),
		_T("j8"),
	},
	{
		_T("Login screen (J9)"),
		_T("j9"),
	},
	{
		_T("Login screen (J10)"),
		_T("j10"),
	},
	{
		_T("Interrupt level (J11)\0") _T("6\0") _T("2\0"),
		_T("j11\0") _T("6\0") _T("2\0"),
		true
	},
	{
		NULL
	}
};
static const struct expansionboardsettings dev_hd_settings[] = {
	{
		_T("Base address"),
		_T("base")
	},
	{
		_T("Register spacing"),
		_T("spacing")
	},
	{
		_T("Data port address"),
		_T("dataport")
	},
	{
		_T("Alternate register base address"),
		_T("altbase")
	}
};

static const struct expansionboardsettings cdtvsram_settings[] = {
	{
		_T("SRAM size\0") _T("64k\0") _T("128k\0") _T("256k\0"),
		_T("sram\0") _T("64k\0") _T("128k\0") _T("256k\0"),
		true
	},
	{
		NULL
	}
};


const struct expansionromtype expansionroms[] = {
	{
		_T("cpuboard"), _T("Accelerator"), _T("Accelerator"),
		NULL, NULL, NULL, add_cpuboard_unit, ROMTYPE_CPUBOARD, 0, 0, 0, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_IDE
	},

	/* built-in controllers */
	{
		_T("cd32fmv"), _T("CD32 FMV"), _T("Commodore"),
		NULL, expamem_init_cd32fmv, NULL, NULL, ROMTYPE_CD32CART, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL
	},
	{
		_T("cdtvdmac"), _T("CDTV DMAC"), _T("Commodore"),
		NULL, cdtv_init, NULL, NULL, ROMTYPE_CDTVDMAC | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL | EXPANSIONTYPE_DMA24
	},
	{
		_T("cdtvscsi"), _T("CDTV SCSI"), _T("Commodore"),
		NULL, cdtvscsi_init, NULL, cdtv_add_scsi_unit, ROMTYPE_CDTVSCSI | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_AFTER_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL | EXPANSIONTYPE_SCSI
	},
	{
		_T("cdtvsram"), _T("CDTV SRAM"), _T("Commodore"),
		NULL, cdtvsram_init, NULL, NULL, ROMTYPE_CDTVSRAM | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL,
		0, 0, 0, false, NULL,
		false, 0, cdtvsram_settings
	},
	{
		_T("cdtvcr"), _T("CDTV-CR"), _T("Commodore"),
		NULL, cdtvcr_init, NULL, NULL, ROMTYPE_CDTVCR | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_AFTER_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL | EXPANSIONTYPE_DMA24
	},
	{
		_T("scsi_a3000"), _T("A3000 SCSI"), _T("Commodore"),
		NULL, a3000scsi_init, NULL, a3000_add_scsi_unit, ROMTYPE_SCSI_A3000 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_AFTER_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL | EXPANSIONTYPE_SCSI
	},
	{
		_T("scsi_a4000t"), _T("A4000T SCSI"), _T("Commodore"),
		NULL, a4000t_scsi_init, NULL, a4000t_add_scsi_unit, ROMTYPE_SCSI_A4000T | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL | EXPANSIONTYPE_SCSI
	},
	{
		_T("ide_mb"), _T("A600/A1200/A4000 IDE"), _T("Commodore"),
		NULL, gayle_ide_init, NULL, gayle_add_ide_unit, ROMTYPE_MB_IDE | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL | EXPANSIONTYPE_IDE,
		0, 0, 0, false, NULL, false, 1
	},
	{
		_T("pcmcia_mb"), _T("A600/A1200 PCMCIA"), _T("Commodore"),
		NULL, gayle_init_pcmcia, NULL, NULL, ROMTYPE_MB_PCMCIA | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL
	},
#ifdef WITH_DSP
	{
		_T("dsp3210"), _T("DSP3210"), _T("AT&T"),
		NULL, dsp_init, NULL, NULL, ROMTYPE_DSP3210 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_INTERNAL
	},
#endif

	/* PCI Bridgeboards */

	{
		_T("grex"), _T("G-REX"), _T("DCE"),
		NULL, grex_init, NULL, NULL, ROMTYPE_GREX | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_PCI_BRIDGE
	},
	{
		_T("mediator"), _T("Mediator"), _T("Elbox"),
		NULL, mediator_init, mediator_init2, NULL, ROMTYPE_MEDIATOR | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		mediator_sub, 0,
		false, EXPANSIONTYPE_PCI_BRIDGE,
		0, 0, 0, false, NULL,
		false, 0, mediator_settings
	},
	{
		_T("prometheus"), _T("Prometheus"), _T("Matay"),
		NULL, prometheus_init, NULL, NULL, ROMTYPE_PROMETHEUS | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z3, false,
		NULL, 0,
		false, EXPANSIONTYPE_PCI_BRIDGE,
		0, 0, 0, false, NULL,
		false, 0, bridge_settings
	},

	/* SCSI/IDE expansion */

	{
		_T("pcmciaide"), _T("PCMCIA IDE"), NULL,
		NULL, gayle_init_board_io_pcmcia, NULL, NULL, ROMTYPE_PCMCIAIDE | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_IDE | EXPANSIONTYPE_PCMCIA,
	},
	{
		_T("apollo"), _T("Apollo 500/2000"), _T("3-State"),
		NULL, apollo_init_hd, NULL, apollo_add_scsi_unit, ROMTYPE_APOLLOHD, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_IDE,
		8738, 0, 0
	},
	{
		_T("add500"), _T("ADD-500"), _T("Archos"),
		NULL, add500_init, NULL, add500_add_scsi_unit, ROMTYPE_ADD500, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		8498, 27, 0, true, NULL
	},
	{
		_T("overdrivehd"), _T("Overdrive HD"), _T("Archos"),
		NULL, gayle_init_board_common_pcmcia, NULL, NULL, ROMTYPE_ARCHOSHD, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_IDE | EXPANSIONTYPE_PCMCIA,
	},
	{
		_T("addhard"), _T("AddHard"), _T("Ashcom Design"),
		NULL, addhard_init, NULL, addhard_add_scsi_unit, ROMTYPE_ADDHARD, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 0x30, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("blizzardscsikitiii"), _T("SCSI Kit III"), _T("Phase 5"),
		NULL, NULL, NULL, cpuboard_ncr9x_add_scsi_unit, ROMTYPE_BLIZKIT3, 0, 0, 0, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI
	},
	{
		_T("blizzardscsikitiv"), _T("SCSI Kit IV"), _T("Phase 5"),
		NULL, NULL, NULL, cpuboard_ncr9x_add_scsi_unit, ROMTYPE_BLIZKIT4, 0, 0, 0, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI
	},
	{
		_T("csmk1cyberscsi"), _T("CyberSCSI module"), _T("Phase 5"),
		NULL, NULL, NULL, cpuboard_ncr9x_add_scsi_unit, ROMTYPE_CSMK1SCSI, 0, 0, 0, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI
	},
	{
		_T("accessx"), _T("AccessX"), _T("Breitfeld Computersysteme"),
		NULL, accessx_init, NULL, accessx_add_ide_unit, ROMTYPE_ACCESSX, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		accessx_sub, 0,
		true, EXPANSIONTYPE_IDE,
		0, 0, 0, true, NULL,
		false, 2
	},
	{
		_T("oktagon2008"), _T("Oktagon 2008"), _T("BSC/Alfa Data"),
		NULL, ncr_oktagon_autoconfig_init, NULL, oktagon_add_scsi_unit, ROMTYPE_OKTAGON, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI
	},
	{
		_T("alfapower"), _T("AlfaPower/AT-Bus 2008"), _T("BSC/Alfa Data"),
		NULL, alf_init, NULL, alf_add_ide_unit, ROMTYPE_ALFA, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_IDE,
		2092, 8, 0
	},
	{
		_T("alfapowerplus"), _T("AlfaPower Plus"), _T("BSC/Alfa Data"),
		NULL, alf_init, NULL, alf_add_ide_unit, ROMTYPE_ALFAPLUS, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_IDE,
		2092, 8, 0
	},
	{
		_T("tandem"), _T("Tandem"), _T("BSC"),
		NULL, tandem_init, NULL, tandem_add_ide_unit, ROMTYPE_TANDEM | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_IDE,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xc1, 6, 0x00, 0x00, 0x08, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	},
	{
		_T("malibu"), _T("Malibu"), _T("California Access"),
		NULL, malibu_init, NULL, malibu_add_scsi_unit, ROMTYPE_MALIBU, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 0x01, 0x00, 0x00, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00 },
	},
	{
		_T("cltda1000scsi"), _T("A1000/A2000 SCSI"), _T("C-Ltd"),
		NULL, cltda1000scsi_init, NULL, cltda1000scsi_add_scsi_unit, ROMTYPE_CLTDSCSI | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xc1, 0x0c, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	},
	{
		_T("a2090a"), _T("A2090a"), _T("Commodore"),
		NULL, a2090_init, NULL, a2090_add_scsi_unit, ROMTYPE_A2090 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_CUSTOM_SECONDARY | EXPANSIONTYPE_DMA24,
		0, 0, 0, false, NULL,
		false, 0, a2090a_settings
	},
	{
		_T("a2090b"), _T("A2090 Combitec"), _T("Commodore"),
		a2090b_preinit, a2090b_init, NULL, a2090_add_scsi_unit, ROMTYPE_A2090B | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_CUSTOM_SECONDARY | EXPANSIONTYPE_DMA24,
		0, 0, 0, false, NULL,
		false, 0, a2090a_settings
	},
	{
		_T("a2091"), _T("A590/A2091"), _T("Commodore"),
		NULL, a2091_init, NULL, a2091_add_scsi_unit, ROMTYPE_A2091 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		a2091_sub, 1,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_CUSTOM_SECONDARY | EXPANSIONTYPE_DMA24,
		commodore, commodore_a2091, 0, true, NULL
	},
	{
		_T("a4091"), _T("A4091"), _T("Commodore"),
		NULL, ncr710_a4091_autoconfig_init, NULL, a4091_add_scsi_unit, ROMTYPE_A4091, 0, 0, BOARD_AUTOCONFIG_Z3, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		true, 0, a4091_settings
	},
	{
		_T("comspec"), _T("SA series"), _T("Comspec Communications"),
		comspec_preinit, comspec_init, NULL, comspec_add_scsi_unit, ROMTYPE_COMSPEC, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		comspec_sub, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_DMA24,
		0, 0, 0, false, NULL,
		false, 0, comspec_settings
	},
	{
		_T("rapidfire"), _T("RapidFire/SpitFire"), _T("DKB"),
		NULL, ncr_rapidfire_init, NULL, rapidfire_add_scsi_unit, ROMTYPE_RAPIDFIRE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		2012, 1, 0, true, NULL,
		true, 0, NULL,
		{ 0xd2, 0x0f ,0x00, 0x00, 0x07, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 },
	},
	{
		_T("fastata4000"), _T("FastATA 4000"), _T("Elbox"),
		NULL, fastata4k_init, NULL, fastata4k_add_ide_unit, ROMTYPE_FASTATA4K, 0, 0, BOARD_AUTOCONFIG_Z3, false,
		NULL, 0,
		false, EXPANSIONTYPE_IDE,
		0, 0, 0, true, NULL,
		true, 2, fastata_settings,
		{ 0x90, 0, 0x10, 0x00, 0x08, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 },
	},
	{
		_T("elsathd"), _T("Mega Ram HD"), _T("Elsat"),
		NULL, elsathd_init, NULL, elsathd_add_ide_unit, ROMTYPE_ELSATHD, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_IDE,
		17740, 1, 0
	},
	{
		_T("eveshamref"), _T("Reference 40/100"), _T("Evesham Micros"),
		NULL, eveshamref_init, NULL, eveshamref_add_scsi_unit, ROMTYPE_EVESHAMREF, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		8504, 2, 0
	},
	{
		_T("dataflyerscsiplus"), _T("DataFlyer SCSI+"), _T("Expansion Systems"),
		NULL, dataflyer_init, NULL, dataflyer_add_scsi_unit, ROMTYPE_DATAFLYERP | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI
	},
	{
		_T("dataflyerplus"), _T("DataFlyer Plus"), _T("Expansion Systems"),
		NULL, dataflyerplus_init, NULL, dataflyerplus_add_idescsi_unit, ROMTYPE_DATAFLYER, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_IDE,
		0, 0, 0, false, NULL,
		false, 0, dataflyersplus_settings
	},
	{
		_T("arriba"), _T("Arriba"), _T("Gigatron"),
		NULL, arriba_init, NULL, arriba_add_ide_unit, ROMTYPE_ARRIBA | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_IDE,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 0x01, 0x00, 0x00, 0x08, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 },
	},
	{
		_T("gvp1"), _T("GVP Series I"), _T("Great Valley Products"),
		NULL, gvp_init_s1, NULL, gvp_s1_add_scsi_unit, ROMTYPE_GVPS1 | ROMTYPE_NONE, ROMTYPE_GVPS12, 0, BOARD_AUTOCONFIG_Z2, false,
		gvp1_sub, 1,
		true, EXPANSIONTYPE_SCSI
	},
	{
		_T("gvp"), _T("GVP Series II"), _T("Great Valley Products"),
		NULL, gvp_init_s2, NULL, gvp_s2_add_scsi_unit, ROMTYPE_GVPS2 | ROMTYPE_NONE, ROMTYPE_GVPS12, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_DMA24,
		2017, 10, 0
	},
	{
		_T("gvpa1208"), _T("GVP A1208"), _T("Great Valley Products"),
		NULL, gvp_init_a1208, NULL, gvp_a1208_add_scsi_unit, ROMTYPE_GVPA1208 | ROMTYPE_NONE, ROMTYPE_GVPS2, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_DMA24,
		2017, 9, 0
	},
	{
		_T("dotto"), _T("Dotto"), _T("Hardital"),
		NULL, dotto_init, NULL, dotto_add_ide_unit, ROMTYPE_DOTTO, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_IDE
	},
	{
		_T("synthesis"), _T("Synthesis"), _T("Hardital"),
		NULL, synthesis_init, NULL, synthesis_add_scsi_unit, ROMTYPE_SYNTHESIS, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		256, 0, 0
	},
	{
		_T("vector"), _T("Vector Falcon 8000"), _T("HK-Computer"),
		NULL, vector_init, NULL, vector_add_scsi_unit, ROMTYPE_VECTOR, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI
	},
	{
		_T("surfsquirrel"), _T("Surf Squirrel"), _T("HiSoft"),
		NULL, gayle_init_board_io_pcmcia, NULL, NULL, ROMTYPE_SSQUIRREL | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_PCMCIA,
	},
	{
		_T("adide"), _T("AdIDE"), _T("ICD"),
		NULL, adide_init, NULL, adide_add_ide_unit, ROMTYPE_ADIDE | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_IDE
	},
	{
		_T("adscsi2000"), _T("AdSCSI Advantage 2000/2080"), _T("ICD"),
		NULL, adscsi_init, NULL, adscsi_add_scsi_unit, ROMTYPE_ADSCSI, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		2071, 4, 0, false, NULL,
		true, 0, adscsi2000_settings
	},
	{
		_T("trifecta"), _T("Trifecta"), _T("ICD"),
		NULL, trifecta_init, NULL, trifecta_add_idescsi_unit, ROMTYPE_TRIFECTA | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		trifecta_sub, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_IDE | EXPANSIONTYPE_DMA24,
		2071, 32, 0, false, NULL,
		true, 0, trifecta_settings,
		{ 0xd1, 0x23, 0x40, 0x00, 0x08, 0x17, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00 }
	},
	{
		_T("buddha"), _T("Buddha"), _T("Individual Computers"),
		NULL, buddha_init, NULL, buddha_add_ide_unit, ROMTYPE_BUDDHA | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_IDE,
		0, 0, 0, false, NULL,
		false, 4, buddha_settings,
		{ 0xd1, 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00 },
	},
	{
		_T("trumpcard"), _T("Trumpcard"), _T("IVS"),
		NULL, trumpcard_init, NULL, trumpcard_add_scsi_unit, ROMTYPE_IVSTC, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		2112, 4, 0, false, NULL,
		true, 0, trumpcard_settings,
		{  0xd1, 0x30, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("trumpcardpro"), _T("Grand Slam"), _T("IVS"),
		NULL, trumpcardpro_init, NULL, trumpcardpro_add_scsi_unit, ROMTYPE_IVSTPRO, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		2112, 4, 0, false, NULL,
		true, 0, NULL,
		{  0xd1, 0x34, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("trumpcardat"), _T("Trumpcard 500AT"), _T("IVS"),
		NULL, trumpcard500at_init, NULL, trumpcard500at_add_ide_unit, ROMTYPE_IVST500AT, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_IDE,
		2112, 4, 0, false, NULL,
		true, 0, NULL,
		{ 0xd1, 0x31, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("kommos"), _T("Kommos A500/A2000 SCSI"), _T("Jürgen Kommos"),
		NULL, kommos_init, NULL, kommos_add_scsi_unit, ROMTYPE_KOMMOS, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI
	},
	{
		_T("golem"), _T("HD3000"), _T("Kupke"),
		NULL, hd3000_init, NULL, hd3000_add_scsi_unit, ROMTYPE_GOLEMHD3000, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("golem"), _T("Golem SCSI II"), _T("Kupke"),
		NULL, golem_init, NULL, golem_add_scsi_unit, ROMTYPE_GOLEM, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		2079, 3, 0
	},
	{
		_T("golemfast"), _T("Golem Fast SCSI/IDE"), _T("Kupke"),
		NULL, golemfast_init, NULL, golemfast_add_idescsi_unit, ROMTYPE_GOLEMFAST, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_IDE,
		0, 0, 0, false, NULL,
		true, 0, golemfast_settings
	},
	{
		_T("multievolution"), _T("Multi Evolution 500/2000"), _T("MacroSystem"),
		NULL, ncr_multievolution_init, NULL, multievolution_add_scsi_unit, ROMTYPE_MEVOLUTION, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		18260, 8, 0, true
	},
	{
		_T("mastfb"), _T("Fireball"), _T("M.A.S.T."),
		NULL, fireball_init, NULL, fireball_add_scsi_unit, ROMTYPE_MASTFB, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 8, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00 }
	},
	{
		_T("scram8490"), _T("SCRAM (DP8490V)"), _T("MegaMicro"),
		NULL, scram5380_init, NULL, scram5380_add_scsi_unit, ROMTYPE_SCRAM5380, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		4096, 4, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 3, 0x40, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00 }
	},
	{
		_T("scram5394"), _T("SCRAM (NCR53C94)"), _T("MegaMicro"),
		NULL, ncr_scram5394_init, NULL, scram5394_add_scsi_unit, ROMTYPE_SCRAM5394, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		4096, 4, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 7, 0x40, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00 }
	},
	{
		_T("paradox"), _T("Paradox SCSI"), _T("Mainhattan Data"),
		NULL, paradox_init, NULL, paradox_add_scsi_unit, ROMTYPE_PARADOX | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_PARALLEL_ADAPTER
	},
	{
		_T("ateam"), _T("A-Team"), _T("Mainhattan Data"),
		NULL, ateam_init, NULL, ateam_add_ide_unit, ROMTYPE_ATEAM, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_IDE
	},
	{
		_T("mtecat"), _T("AT 500"), _T("M-Tec"),
		NULL, mtec_init, NULL, mtec_add_ide_unit, ROMTYPE_MTEC, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_IDE
	},
	{
		_T("mtecmastercard"), _T("Mastercard"), _T("M-Tec"),
		NULL, ncr_mtecmastercard_init, NULL, mtecmastercard_add_scsi_unit, ROMTYPE_MASTERCARD, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI
	},
	{
		_T("masoboshi"), _T("MasterCard"), _T("Masoboshi"),
		NULL, masoboshi_init, NULL, masoboshi_add_idescsi_unit, ROMTYPE_MASOBOSHI | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		masoboshi_sub, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_IDE | EXPANSIONTYPE_DMA24
	},
	{
		_T("hardframe"), _T("HardFrame"), _T("Microbotics"),
		NULL, hardframe_init, NULL, hardframe_add_scsi_unit, ROMTYPE_HARDFRAME, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_DMA24,
		0, 0, 0, false, NULL,
		true
	},
	{
		_T("stardrive"), _T("StarDrive"), _T("Microbotics"),
		NULL, stardrive_init, NULL, stardrive_add_scsi_unit, ROMTYPE_STARDRIVE | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		1010, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xc1, 2, 0x00, 0x00, 0x03, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },

	},
	{
		_T("filecard2000"), _T("Filecard 2000/OSSI 500"), _T("Otronic"),
		NULL, ossi_init, NULL, ossi_add_scsi_unit, ROMTYPE_OSSI, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xc1, 1, 0x00, 0x00, 0x07, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("pacificoverdrive"), _T("Overdrive"), _T("Pacific Peripherals/IVS"),
		NULL, overdrive_init, NULL, overdrive_add_scsi_unit, ROMTYPE_OVERDRIVE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 16, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }
	},
	{
		_T("fastlane"), _T("Fastlane"), _T("Phase 5"),
		NULL, ncr_fastlane_autoconfig_init, NULL, fastlane_add_scsi_unit, ROMTYPE_FASTLANE, 0, 0, BOARD_AUTOCONFIG_Z3, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		8512, 10, 0, false, fastlane_memory_callback
	},
	{
		_T("phoenixboard"), _T("Phoenix Board SCSI"), _T("Phoenix Microtechnologies"),
		NULL, phoenixboard_init, NULL, phoenixboard_add_scsi_unit, ROMTYPE_PHOENIXB, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
	},
	{
		_T("ptnexus"), _T("Nexus"), _T("Preferred Technologies"),
		NULL, ptnexus_init, NULL, ptnexus_add_scsi_unit, ROMTYPE_PTNEXUS | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		2102, 4, 0, false, nexus_memory_callback,
		false, 0, nexus_settings,
		{ 0xd1, 0x01, 0x00, 0x00, 0x08, 0x36, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("profex"), _T("HD 3300"), _T("Profex Electronics"),
		NULL, profex_init, NULL, profex_add_scsi_unit, ROMTYPE_PROFEX, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		true, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("protar"), _T("A500 HD"), _T("Protar"),
		NULL, protar_init, NULL, protar_add_ide_unit, ROMTYPE_PROTAR, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		4149, 51, 0
	},
	{
		_T("rochard"), _T("RocHard RH800C"), _T("Roctec"),
		NULL, rochard_init, NULL, rochard_add_idescsi_unit, ROMTYPE_ROCHARD | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		rochard_sub, 0,
		true, EXPANSIONTYPE_IDE | EXPANSIONTYPE_SCSI,
		2144, 2, 0, false, NULL,
		false, 2, NULL
	},
	{
		_T("inmate"), _T("InMate"), _T("Spirit Technology"),
		NULL, inmate_init, NULL, inmate_add_scsi_unit, ROMTYPE_INMATE | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, inmate_settings
	},
	{
		_T("supradrive"), _T("SupraDrive"), _T("Supra Corporation"),
		NULL, supra_init, NULL, supra_add_scsi_unit, ROMTYPE_SUPRA | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		supra_sub, 0,
		true, EXPANSIONTYPE_SCSI
	},
	{
		_T("emplant"), _T("Emplant (SCSI only)"), _T("Utilities Unlimited"),
		NULL, emplant_init, NULL, emplant_add_scsi_unit, ROMTYPE_EMPLANT | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 0x15, 0x40, 0x00, 0x08, 0x7b, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00 },
	},
#if 0 /* driver is MIA, 3rd party ScottDevice driver is not enough for full implementation. */
	{
		NULL, _T("microforge"), _T("Hard Disk"), _T("Micro Forge"),
		microforge_init, NULL, microforge_add_scsi_unit, ROMTYPE_MICROFORGE | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SASI | EXPANSIONTYPE_SCSI
	},
#endif

	{
		_T("omtiadapter"), _T("OMTI-Adapter"), _T("C't"),
		NULL, omtiadapter_init, NULL, omtiadapter_add_scsi_unit, ROMTYPE_OMTIADAPTER | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("hd20a"), _T("HD 20 A/HD 40 A"), _T("Combitec"),
		NULL, hd20_init, NULL, hd20_add_scsi_unit, ROMTYPE_HD20A, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("alf1"), _T("A.L.F."), _T("Elaborate Bytes"),
		NULL, alf1_init, NULL, alf1_add_scsi_unit, ROMTYPE_ALF1 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("alf2"), _T("A.L.F.2"), _T("Elaborate Bytes"),
		NULL, alf2_init, NULL, alf2_add_scsi_unit, ROMTYPE_ALF2, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("alf3"), _T("A.L.F.3"), _T("Elaborate Bytes"),
		NULL, ncr_alf3_autoconfig_init, NULL, alf3_add_scsi_unit, ROMTYPE_ALF3 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		true, 0, alf3_settings
	},
	{
		_T("promigos"), _T("Promigos"), _T("Flesch und Hörnemann"),
		NULL, promigos_init, NULL, promigos_add_scsi_unit, ROMTYPE_PROMIGOS | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("wedge"), _T("Wedge"), _T("Reiter Software"),
		wedge_preinit, wedge_init, NULL, wedge_add_scsi_unit, ROMTYPE_WEDGE | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("tecmar"), _T("T-Card/T-Disk"), _T("Tecmar"),
		NULL, tecmar_init, NULL, tecmar_add_scsi_unit, ROMTYPE_TECMAR | ROMTYPE_NOT, 0, 0, BOARD_PROTOAUTOCONFIG, true,
		NULL, 0,
		false, EXPANSIONTYPE_SASI | EXPANSIONTYPE_SCSI,
		1001, 1, 0
	},
	{
		_T("system2000"), _T("System 2000"), _T("Vortex"),
		system2000_preinit, system2000_init, NULL, system2000_add_scsi_unit, ROMTYPE_SYSTEM2000 | ROMTYPE_NONE, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI
	},
	{
		_T("xebec"), _T("9720H"), _T("Xebec"),
		NULL, xebec_init, NULL, xebec_add_scsi_unit, ROMTYPE_XEBEC | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SASI | EXPANSIONTYPE_SCSI
	},
	{
		_T("kronos"), _T("Kronos"), _T("C-Ltd"),
		NULL, kronos_init, NULL, kronos_add_scsi_unit, ROMTYPE_KRONOS, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		false, EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xd1, 0x04, 0x40, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
	},
	{
		_T("hda506"), _T("HDA-506"), _T("Spirit Technology"),
		NULL, hda506_init, NULL, hda506_add_scsi_unit, ROMTYPE_HDA506 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xc1, 0x04, 0x00, 0x00, 0x07, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("fasttrak"), _T("FastTrak"), _T("Xetec"),
		NULL, fasttrak_init, NULL, fasttrak_add_scsi_unit, ROMTYPE_FASTTRAK, 0, 0, BOARD_AUTOCONFIG_Z2, false,
		NULL, 0,
		true, EXPANSIONTYPE_SCSI,
		2022, 2, 0
	},
	{
		_T("amax"), _T("AMAX ROM dongle"), _T("ReadySoft"),
		NULL, NULL, NULL, NULL, ROMTYPE_AMAX | ROMTYPE_NONE, 0, 0, 0, false
	},
	{
		_T("x86athdprimary"), _T("AT IDE Primary"), NULL,
		NULL, x86_at_hd_init_1, NULL, x86_add_at_hd_unit_1, ROMTYPE_X86_AT_HD1 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_AFTER_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_EXPANSION | EXPANSIONTYPE_IDE,
	},
	{
		_T("x86athdxt"), _T("XTIDE Universal BIOS HD"), NULL,
		NULL, x86_at_hd_init_xt, NULL, x86_add_at_hd_unit_xt, ROMTYPE_X86_XT_IDE | ROMTYPE_NONE, 0, 0, BOARD_NONAUTOCONFIG_AFTER_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_EXPANSION | EXPANSIONTYPE_IDE,
		0, 0, 0, false, NULL,
		false, 0, x86_athdxt_settings
	},
	{
		_T("x86rt1000"), _T("Rancho RT1000"), NULL,
		NULL, x86_rt1000_init, NULL, x86_rt1000_add_unit, ROMTYPE_X86_RT1000 | ROMTYPE_NONE, 0, 0, BOARD_NONAUTOCONFIG_AFTER_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_EXPANSION | EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, x86_rt1000_settings

	},
#ifndef NDEBUG
	{
		_T("dev_ide"), _T("DEV IDE"), NULL,
		NULL, dev_hd_init, NULL, dev_hd_add_ide_unit, ROMTYPE_DEVHD | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_IDE | EXPANSIONTYPE_SCSI,
		0, 0, 0, false, NULL,
		false, 0, dev_hd_settings

	},
#endif

	/* PC Bridgeboards */

	{
		_T("a1060"), _T("A1060 Sidecar"), _T("Commodore"),
		NULL, a1060_init, NULL, NULL, ROMTYPE_A1060 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_BRIDGE,
		0, 0, 0, false, NULL,
		false, 0, x86_bridge_sidecar_settings
	},
	{
		_T("a2088"), _T("A2088"), _T("Commodore"),
		NULL, a2088xt_init, NULL, NULL, ROMTYPE_A2088 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_BRIDGE,
		0, 0, 0, false, NULL,
		false, 0, x86_bridge_settings
	},
	{
		_T("a2088t"), _T("A2088T"), _T("Commodore"),
		NULL, a2088t_init, NULL, NULL, ROMTYPE_A2088T | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_BRIDGE,
		0, 0, 0, false, NULL,
		false, 0, x86_bridge_settings
	},
	{
		_T("a2286"), _T("A2286"), _T("Commodore"),
		NULL, a2286_init, NULL, NULL, ROMTYPE_A2286 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_BRIDGE,
		0, 0, 0, false, NULL,
		false, 0, x86at286_bridge_settings
	},
	{
		_T("a2386"), _T("A2386SX"), _T("Commodore"),
		NULL, a2386_init, NULL, NULL, ROMTYPE_A2386 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_BRIDGE,
		0, 0, 0, false, NULL,
		false, 0, x86at386_bridge_settings
	},

	// only here for rom selection and settings
	{
		_T("picassoiv"), _T("Picasso IV"), _T("Village Tronic"),
		NULL, NULL, NULL, NULL, ROMTYPE_PICASSOIV | ROMTYPE_NONE, 0, 0, BOARD_IGNORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_RTG
	},
	{
		_T("vooodoo3_3k"), _T("Voodoo 3 3000"), _T("3dfx"),
		NULL, NULL, NULL, NULL, ROMTYPE_VOODOO3 | ROMTYPE_NONE, 0, 0, BOARD_IGNORE, false,
		NULL, 0,
		false, EXPANSIONTYPE_RTG,
		0, 0, 0, false, NULL,
		false, 0, voodoo_settings
	},
#if 0
	{
		_T("vooodoo5_5k"), _T("Voodoo 5 5500"), _T("3dfx"),
		NULL, NULL, NULL, NULL, ROMTYPE_VOODOO5 | ROMTYPE_NONE, 0, 0, BOARD_IGNORE, false,
		NULL, 0,
		false, EXPANSIONTYPE_RTG,
		0, 0, 0, false, NULL,
		false, 0, voodoo_settings
	},
#endif
	{
		_T("s3virge"), _T("Virge"), _T("S3"),
		NULL, NULL, NULL, NULL, ROMTYPE_S3VIRGE | ROMTYPE_NONE, 0, 0, BOARD_IGNORE, false,
		NULL, 0,
		false, EXPANSIONTYPE_RTG
	},
	{
		_T("x86vga"), _T("x86 VGA"), NULL,
		NULL, NULL, NULL, NULL, ROMTYPE_x86_VGA | ROMTYPE_NONE, 0, 0, BOARD_IGNORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_EXPANSION,
		0, 0, 0, false, NULL,
		false, 0, x86vga_settings
	},
	{
		_T("harlequin"), _T("Harlequin"), _T("ACS"),
		NULL, NULL, NULL, NULL, ROMTYPE_HARLEQUIN | ROMTYPE_NOT, 0, 0, BOARD_IGNORE, false,
		NULL, 0,
		false, EXPANSIONTYPE_RTG,
		0, 0, 0, false, NULL,
		false, 0, harlequin_settings
	},

	/* Sound Cards */
	{
		_T("prelude"), _T("Prelude"), _T("Albrecht Computer Technik"),
		NULL, prelude_init, NULL, NULL, ROMTYPE_PRELUDE | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND,
		0, 0, 0, false, NULL,
		false, 0, toccata_soundcard_settings,
		{ 0xc1, 1, 0, 0, 0x42, 0x31, 0, 0, 0, 3 }
	},
	{
		_T("prelude1200"), _T("Prelude 1200"), _T("Albrecht Computer Technik"),
		NULL, prelude1200_init, NULL, NULL, ROMTYPE_PRELUDE1200 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND | EXPANSIONTYPE_CLOCKPORT,
		0, 0, 0, false, NULL,
		false, 0, toccata_soundcard_settings
	},
	{
		_T("toccata"), _T("Toccata"), _T("MacroSystem"),
		NULL, toccata_init, NULL, NULL, ROMTYPE_TOCCATA | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND,
		0, 0, 0, false, NULL,
		false, 0, toccata_soundcard_settings,
		{ 0xc1, 12, 0, 0, 18260 >> 8, 18260 & 255 }
	},
	{
		_T("es1370"), _T("ES1370 PCI"), _T("Ensoniq"),
		NULL, pci_expansion_init, NULL, NULL, ROMTYPE_ES1370 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND
	},
	{
		_T("fm801"), _T("FM801 PCI"), _T("Fortemedia"),
		NULL, pci_expansion_init, NULL, NULL, ROMTYPE_FM801 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND
	},
	{
		_T("uaesnd_z2"), _T("UAESND Z2"), NULL,
		NULL, uaesndboard_init_z2, NULL, NULL, ROMTYPE_UAESNDZ2 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xc1, 2, 0x00, 0x00, 6502 >> 8, 6502 & 255, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("uaesnd_z3"), _T("UAESND Z3"), NULL,
		NULL, uaesndboard_init_z3, NULL, NULL, ROMTYPE_UAESNDZ3 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z3, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0x80, 2, 0x10, 0x00, 6502 >> 8, 6502 & 255, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("sb_isa"), _T("SoundBlaster ISA (Creative)"), NULL,
		NULL, isa_expansion_init, NULL, NULL, ROMTYPE_SBISA | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_EXPANSION | EXPANSIONTYPE_SOUND,
		0, 0, 0, false, NULL,
		false, 0, sb_isa_settings
	},


#if 0
	{
		_T("pmx"), _T("pmx"), NULL,
		NULL, pmx_init, NULL, NULL, ROMTYPE_PMX | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_SOUND,
		0, 0, 0, false, NULL,
		false, 0, NULL,
		{ 0xc1, 0x30, 0x00, 0x00, 0x0e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
#endif

		/* Network */
	{
		_T("a2065"), _T("A2065"), _T("Commodore"),
		NULL, a2065_init, NULL, NULL, ROMTYPE_A2065 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
		{ 0xc1, 0x70, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("ariadne"), _T("Ariadne"), _T("Village Tronic"),
		NULL, ariadne_init, NULL, NULL, ROMTYPE_ARIADNE | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
		{ 0xc1, 0xc9, 0x00, 0x00, 2167 >> 8, 2167 & 255, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("ariadne2"), _T("Ariadne II"), _T("Village Tronic"),
		NULL, ariadne2_init, NULL, NULL, ROMTYPE_ARIADNE2 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
		{ 0xc1, 0xca, 0x00, 0x00, 2167 >> 8, 2167 & 255, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("hydra"), _T("AmigaNet"), _T("Hydra Systems"),
		NULL, hydra_init, NULL, NULL, ROMTYPE_HYDRA | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
		{ 0xc1, 0x01, 0x00, 0x00, 2121 >> 8, 2121 & 255, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("eb920"), _T("LAN Rover/EB920"), _T("ASDG"),
		NULL, lanrover_init, NULL, NULL, ROMTYPE_LANROVER | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, lanrover_settings,
		{ 0xc1, 0xfe, 0x00, 0x00, 1023 >> 8, 1023 & 255, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("xsurf"), _T("X-Surf"), _T("Individual Computers"),
		NULL, xsurf_init, NULL, NULL, ROMTYPE_XSURF | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
		{ 0xc1, 0x17, 0x00, 0x00, 4626 >> 8, 4626 & 255, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
	},
	{
		_T("xsurf100z2"), _T("X-Surf-100 Z2"), _T("Individual Computers"),
		NULL, xsurf100_init, NULL, NULL, ROMTYPE_XSURF100Z2 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
		{ 0xc1, 0x64, 0x10, 0x00, 4626 >> 8, 4626 & 255, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00 }
	},
	{
		_T("xsurf100z3"), _T("X-Surf-100 Z3"), _T("Individual Computers"),
		NULL, xsurf100_init, NULL, NULL, ROMTYPE_XSURF100Z3 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z3, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
		{ 0x82, 0x64, 0x32, 0x00, 4626 >> 8, 4626 & 255, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00 }
	},
	{
		_T("ne2000pcmcia"), _T("RTL8019 PCMCIA (NE2000 compatible)"), NULL,
		NULL, gayle_init_board_io_pcmcia, NULL, NULL, ROMTYPE_NE2KPCMCIA | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET | EXPANSIONTYPE_PCMCIA,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
	},
	{
		_T("ne2000_pci"), _T("RTL8029 PCI (NE2000 compatible)"), NULL,
		NULL, pci_expansion_init, NULL, NULL, ROMTYPE_NE2KPCI | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET,
		0, 0, 0, false, NULL,
		false, 0, ethernet_settings,
	},
	{
		_T("ne2000_isa"), _T("RTL8019 ISA (NE2000 compatible)"), NULL,
		NULL, isa_expansion_init, NULL, NULL, ROMTYPE_NE2KISA | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_NET | EXPANSIONTYPE_X86_EXPANSION,
		0, 0, 0, false, NULL,
		false, 0, ne2k_isa_settings
	},

		/* Catweasel */
	{
		_T("catweasel"), _T("Catweasel"), _T("Individual Computers"),
		NULL, expamem_init_catweasel, NULL, NULL, ROMTYPE_CATWEASEL | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_FLOPPY
	},

	// misc

	{
		_T("pcmciasram"), _T("PCMCIA SRAM"), NULL,
		NULL, gayle_init_board_common_pcmcia, NULL, NULL, ROMTYPE_PCMCIASRAM | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM | EXPANSIONTYPE_PCMCIA | EXPANSIONTYPE_CUSTOMDISK,
	},
	{
		_T("uaeboard_z2"), _T("UAEBOARD Z2"), NULL,
		NULL, uaesndboard_init_z2, NULL, NULL, ROMTYPE_UAEBOARDZ2 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z2, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM
	},
	{
		_T("uaeboard_z3"), _T("UAEBOARD Z3"), NULL,
		NULL, uaesndboard_init_z3, NULL, NULL, ROMTYPE_UAEBOARDZ3 | ROMTYPE_NOT, 0, 0, BOARD_AUTOCONFIG_Z3, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM
	},
	{
		_T("cubo"), _T("Cubo CD32"), NULL,
		NULL, cubo_init, NULL, NULL, ROMTYPE_CUBO | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_CUSTOM,
		0, 0, 0, false, NULL,
		false, 0, cubo_settings,
	},
	{
		_T("x86_mouse"), _T("x86 Bridgeboard mouse"), NULL,
		NULL, isa_expansion_init, NULL, NULL, ROMTYPE_X86MOUSE | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true,
		NULL, 0,
		false, EXPANSIONTYPE_X86_EXPANSION,
		0, 0, 0, false, NULL,
		false, 0, x86_mouse_settings
	},


	{
		NULL
	}
};

static const struct expansionboardsettings blizzardboard_settings[] = {
	{
		_T("MapROM"),
		_T("maprom")
	},
	{
		NULL
	}
};

static const struct expansionboardsettings blizzardboard_settings_mk2[] = {
	{
		_T("MapROM"),
		_T("maprom")
	},
	{
		_T("SCSI Kit II"),
		_T("scsikitii")
	},
	{
		NULL
	}
};

static const struct expansionboardsettings gvpa1230s2_settings[] = {
	{
		_T("Board disable (J5)"),
		_T("disabled")
	},
	{
		_T("SCSI Disable (J6)"),
		_T("scsidisabled")
	},
	{
		NULL
	}
};



static const struct cpuboardsubtype gvpboard_sub[] = {
	{
		_T("A3001 Series I"),
		_T("A3001SI"),
		ROMTYPE_CB_A3001S1, 0, 3,
		gvp_add_ide_unit, EXPANSIONTYPE_IDE | EXPANSIONTYPE_24BIT,
		BOARD_MEMORY_Z2,
		8 * 1024 * 1024,
		0,
		gvp_ide_rom_autoconfig_init, NULL, BOARD_AUTOCONFIG_Z2, 0
	},
	{
		_T("A3001 Series II"),
		_T("A3001SII"),
		0, 0, 3,
		gvp_add_ide_unit, EXPANSIONTYPE_IDE | EXPANSIONTYPE_24BIT,
		BOARD_MEMORY_Z2,
		8 * 1024 * 1024,
		0,
		gvp_ide_rom_autoconfig_init, gvp_ide_controller_autoconfig_init, BOARD_AUTOCONFIG_Z2, 0
	},
	{
		_T("A530"),
		_T("GVPA530"),
		ROMTYPE_GVPS2, 0, 3,
		gvp_s2_add_accelerator_scsi_unit, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_24BIT,
		BOARD_MEMORY_Z2,
		8 * 1024 * 1024,
		0,
		gvp_init_accelerator, NULL, BOARD_AUTOCONFIG_Z2, 1,
		NULL, NULL,
		2017, 9, 0, false
	},
	{
		_T("G-Force 030"),
		_T("GVPGFORCE030"),
		ROMTYPE_GVPS2, ROMTYPE_GVPS12, 3,
		gvp_s2_add_accelerator_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_25BITMEM,
		128 * 1024 * 1024,
		0,
		gvp_init_accelerator, NULL, BOARD_AUTOCONFIG_Z2, 1
	},
	{
		_T("G-Force 040"),
		_T("GVPGFORCE040"),
		ROMTYPE_GVPS2, ROMTYPE_GVPS12, 4,
		gvp_s2_add_accelerator_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_25BITMEM,
		128 * 1024 * 1024,
		0,
		gvp_init_accelerator, NULL, BOARD_AUTOCONFIG_Z2, 1
	},
	{
		_T("Tek Magic 2040/2060"),
		_T("TekMagic"),
		ROMTYPE_CB_TEKMAGIC, 0, 4,
		tekmagic_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024
	},
	{
		_T("A1230 Turbo+"),
		_T("A1230SI"),
		ROMTYPE_CB_A1230S1, 0, 3,
		NULL, 0,
		BOARD_MEMORY_25BITMEM,
		32 * 1024 * 1024
	},
	{
		_T("A1230 Turbo+ Series II"),
		_T("A1230SII"),
		ROMTYPE_CB_A1230S2, 0, 3,
		gvp_s2_add_accelerator_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_25BITMEM,
		32 * 1024 * 1024,
		0,
		gvp_init_accelerator, NULL, BOARD_AUTOCONFIG_Z2, 1,
		gvpa1230s2_settings, NULL,
		2017, 9, 0, false
	},
	{
		_T("QuikPak XP"),
		_T("quikpakxp"),
		ROMTYPE_CB_QUIKPAK, 0, 6,
		quikpak_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype blizzardboard_sub[] = {
	{
		_T("Blizzard 1230 I/II"),
		_T("Blizzard1230II"),
		ROMTYPE_CB_B1230MK2, 0, 3,
		cpuboard_ncr9x_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_BLIZZARD_12xx,
		64 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		blizzardboard_settings_mk2
	},
	{
		_T("Blizzard 1230 III"),
		_T("Blizzard1230III"),
		ROMTYPE_CB_B1230MK3, 0, 3,
		NULL, 0,
		BOARD_MEMORY_BLIZZARD_12xx,
		32 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		blizzardboard_settings
	},
	{
		_T("Blizzard 1230 IV"),
		_T("Blizzard1230IV"),
		ROMTYPE_CB_BLIZ1230, 0, 3,
		NULL, EXPANSIONTYPE_FALLBACK_DISABLE | EXPANSIONTYPE_HAS_FALLBACK,
		BOARD_MEMORY_BLIZZARD_12xx,
		256 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		blizzardboard_settings
	},
	{
		_T("Blizzard 1260"),
		_T("Blizzard1260"),
		ROMTYPE_CB_BLIZ1260, 0, 6,
		NULL, EXPANSIONTYPE_FALLBACK_DISABLE | EXPANSIONTYPE_HAS_FALLBACK,
		BOARD_MEMORY_BLIZZARD_12xx,
		256 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		blizzardboard_settings
	},
	{
		_T("Blizzard 2060"),
		_T("Blizzard2060"),
		ROMTYPE_CB_BLIZ2060, 0, 6,
		cpuboard_ncr9x_add_scsi_unit, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_FALLBACK_DISABLE | EXPANSIONTYPE_HAS_FALLBACK,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		blizzardboard_settings
	},
	{
		_T("Blizzard PPC"),
		_T("BlizzardPPC"),
		ROMTYPE_CB_BLIZPPC, 0, 4,
		blizzardppc_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_BLIZZARD_PPC,
		256 * 1024 * 1024
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype cyberstormboard_sub[] = {
	{
		_T("CyberStorm MK I"),
		_T("CyberStormMK1"),
		ROMTYPE_CB_CSMK1 | ROMTYPE_NONE, 0, 4,
		NULL, 0,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		NULL
	},
	{
		_T("CyberStorm MK II"),
		_T("CyberStormMK2"),
		ROMTYPE_CB_CSMK2, 0, 4,
		cpuboard_ncr9x_add_scsi_unit, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_FALLBACK_DISABLE | EXPANSIONTYPE_HAS_FALLBACK,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024
	},
	{
		_T("CyberStorm MK III"),
		_T("CyberStormMK3"),
		ROMTYPE_CB_CSMK3, 0, 4,
		cyberstorm_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024
	},
	{
		_T("CyberStorm PPC"),
		_T("CyberStormPPC"),
		ROMTYPE_CB_CSPPC, 0, 4,
		cyberstorm_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024
	},
	{
		NULL
	}
};
static const struct expansionboardsettings draco_settings[] = {
	{
		// 0/1
		_T("Revision\0") _T("3\0") _T("4\0"),
		_T("hwrev\0") _T("3\0") _T("4\0"),
		true, false, 0
	},
	{
		// 2
		_T("CIA-A (Rev3 always includes CIA-A)"),
		_T("ciaa"),
		false, false, 1
	},
	{
		// 3
		_T("CIA-B (Optional)"),
		_T("ciab"),
		false, false, 0
	},
	{
		// 4
		_T("PC keyboard connected"),
		_T("pckbd"),
		false, false, 0
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype macrosystem_sub[] = {
	{
		_T("Warp Engine A4000"),
		_T("WarpEngineA4000"),
		ROMTYPE_CB_WENGINE, 0, 4,
		warpengine_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
		0x01000000,
		ncr710_warpengine_autoconfig_init, NULL, BOARD_AUTOCONFIG_Z3, 1,
		warpengine_settings
	},
	{
		_T("Falcon 040"),
		_T("Falcon040"),
		ROMTYPE_CB_FALCON40, 0,
		NULL, 0,
		0,
		128 * 1024 * 1024,
	},
	{
		_T("DraCo"),
		_T("draco"),
		ROMTYPE_CB_DRACO | ROMTYPE_NONE, 0, 4,
		draco_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
		0,
		ncr710_draco_init, NULL, BOARD_NONAUTOCONFIG_BEFORE, 1,
		draco_settings
	},
	{
		_T("Casablanca"),
		_T("casablanca"),
		ROMTYPE_CB_CASAB | ROMTYPE_NONE, 0, 4,
		draco_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
		0,
		NULL, NULL, BOARD_NONAUTOCONFIG_BEFORE, 1,
	},
	{
		NULL
	}
};
static const struct expansionboardsettings mtec_settings[] = {
	{
		_T("SCSI disabled"),
		_T("scsioff")
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype mtec_sub[] = {
	{
		_T("E-Matrix 530"),
		_T("e-matrix530"),
		ROMTYPE_CB_EMATRIX, 0, 3,
		ematrix_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_CUSTOM_32,
		128 * 1024 * 1024,
		0,
		ncr_ematrix_autoconfig_init, NULL, BOARD_AUTOCONFIG_Z2, 1,
		mtec_settings
	},
	{
		NULL
	}
};

static const struct expansionboardsettings ivsvector_settings[] = {
	{
		// 0/1
		_T("Memory (JP12)\0") _T("4M\0") _T("8M\0") _T("16M\0") _T("32M\0"),
		_T("memory\0") _T("4m\0") _T("8m\0") _T("16m\0") _T("32m\0"),
		true, false, 0
	},
	{
		// 3
		_T("Disable FastROM (JP17)"),
		_T("disfastrom"),
		false, false, 1
	},
	{
		// 4
		_T("Autoboot (JP20)"),
		_T("autoboot"),
		false, false, 0
	},
	{
		// 5
		_T("Dis68kRAM (JP14)"),
		_T("dis68kram"),
		false, false, 1
	},
	{
		// 6
		_T("Burst (JP13)"),
		_T("burst"),
		false, false, 1
	},
	{
		NULL
	}
};


static const struct expansionboardsettings a26x0board_settings[] = {
	{
		_T("OSMODE (J304)"),
		_T("j304")
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype commodore_sub[] = {
	{
		_T("A2620/A2630"),
		_T("A2630"),
		ROMTYPE_CB_A26x0, 0, 2,
		NULL, 0,
		BOARD_MEMORY_25BITMEM,
		128 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		a26x0board_settings,
		cpuboard_io_special
	},
	{
		NULL
	}
};

static const struct expansionboardsettings cpuboard_dkb_cobra_settings[] = {
	{
		_T("SCSI (Ferret)"),
		_T("scsi")
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype dbk_sub[] = {
	{
		_T("1230/1240/Cobra"),
		_T("DKB12x0"),
		ROMTYPE_CB_DKB, 0, 3,
		cpuboard_dkb_add_scsi_unit, EXPANSIONTYPE_SCSI,
		0,
		128 * 1024 * 1024,
		0,
		ncr_dkb_autoconfig_init, NULL, BOARD_AUTOCONFIG_Z2, 0,
		cpuboard_dkb_cobra_settings
	},
	{
		_T("Wildfire"),
		_T("wildfire"),
		ROMTYPE_CB_DBK_WF, 0, 4,
		wildfire_add_scsi_unit, EXPANSIONTYPE_SCSI | EXPANSIONTYPE_HAS_FALLBACK,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
		0,
		dkb_wildfire_pci_init, NULL, BOARD_NONAUTOCONFIG_BEFORE, 0
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype hardital_sub[] = {
	{
		_T("TQM"),
		_T("tqm"),
		ROMTYPE_CB_TQM, 0,
		NULL, 0,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
	},
	{
		NULL
	}
};

static const struct cpuboardsubtype fusionforty_sub[] = {
	{
		_T("Fusion Forty"),
		_T("FusionForty"),
		ROMTYPE_CB_FUSION, 0, 4,
		NULL, 0,
		0,
		32 * 1024 * 1024
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype ivs_sub[] = {
	{
		_T("Vector"),
		_T("Vector"),
		ROMTYPE_CB_VECTOR, 0, 3,
		ivsvector_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		32 * 1024 * 1024,
		0,
		ivsvector_init, NULL, BOARD_AUTOCONFIG_Z2, 1,
		ivsvector_settings, NULL,
		2112, 240, 0, false
	},
	{
		NULL
	}
};

static const struct expansionboardsettings magnum40_settings[] = {
	{
		_T("Autoboot disable"),
		_T("autoboot")
	},
	{
		NULL
	}
};
static const struct expansionboardsettings zeus040_settings[] = {
	{
		_T("Autoboot disable (A3)"),
		_T("autoboot")
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype pps_sub[] = {
	{
		_T("Zeus 040"),
		_T("Zeus"),
		ROMTYPE_CB_ZEUS040, 0, 4,
		zeus040_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		64 * 1024 * 1024,
		0,
		ncr710_zeus040_autoconfig_init, NULL, BOARD_AUTOCONFIG_Z2, 1,
		zeus040_settings, NULL,
		2016, 150, 0, false
	},
	{
		NULL
	}
};

static const struct cpuboardsubtype csa_sub[] = {
	{
		_T("Magnum 40/4"),
		_T("Magnum40"),
		ROMTYPE_CB_MAGNUM40, 0, 4,
		magnum40_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_HIGHMEM,
		128 * 1024 * 1024,
		0,
		ncr710_magnum40_autoconfig_init, NULL, BOARD_AUTOCONFIG_Z2, 1,
		magnum40_settings, NULL
	},
	{
		_T("Twelve Gauge"),
		_T("twelvegauge"),
		ROMTYPE_CB_12GAUGE, 0, 3,
		twelvegauge_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_CUSTOM_32,
		32 * 1024 * 1024,
		0,
		twelvegauge_init, NULL, BOARD_AUTOCONFIG_Z2, 1,
		NULL, NULL
	},
	{
		NULL
	}
};

static const struct expansionboardsettings apollo_settings[] = {
	{
		_T("SCSI module installed"),
		_T("scsi")
	},
	{
		_T("Memory disable"),
		_T("memory")
	},
	{
		NULL
	}
};

static const struct cpuboardsubtype apollo_sub[] = {
	{
		_T("Apollo 1240/1260"),
		_T("Apollo"),
		ROMTYPE_CB_APOLLO, 0, 4,
		apollo_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_CUSTOM_32,
		64 * 1024 * 1024,
		0,
		apollo_init_cpu, NULL, 2, 0,
		apollo_settings
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype kupkeboard_sub[] = {
	{
		_T("Golem 030"),
		_T("golem030"),
		ROMTYPE_CB_GOLEM030, 0, 3,
		NULL, 0,
		BOARD_MEMORY_25BITMEM,
		16 * 1024 * 1024
	},
	{
		NULL
	}
};
static const struct cpuboardsubtype dceboard_sub[] = {
	{
		_T("SX32 Pro"),
		_T("sx32pro"),
		ROMTYPE_CB_SX32PRO, 0, 3,
		NULL, 0,
		BOARD_MEMORY_CUSTOM_32,
		128 * 1024 * 1024
	},
	{
		_T("Typhoon MK2"),
		_T("typhoon2"),
		ROMTYPE_CB_TYPHOON2, 0, 3,
		typhoon2scsi_add_scsi_unit, EXPANSIONTYPE_SCSI,
		BOARD_MEMORY_CUSTOM_32,
		128 * 1024 * 1024,
		0,
		typhoon2scsi_init, NULL, BOARD_AUTOCONFIG_Z2, 1
	},
	{
		NULL
	}
};

static const struct cpuboardsubtype harms_sub[] = {
	{
		_T("Professional 3000"),
		_T("harms3kp"),
		ROMTYPE_CB_HARMS3KP, 0, 2,
		NULL, 0,
		BOARD_MEMORY_25BITMEM,
		128 * 1024 * 1024,
		0,
		NULL, NULL, 0, 0,
		NULL, //a26x0board_settings,
		cpuboard_io_special
	},
	{
		NULL
	}
};

static const struct cpuboardsubtype dummy_sub[] = {
	{ NULL }
};

const struct cpuboardtype cpuboards[] = {
	{
		-1,
		_T("-"),
		dummy_sub, 0
	},
	{
		BOARD_ACT,
		_T("ACT"),
		apollo_sub, 0
	},
	{
		BOARD_COMMODORE,
		_T("Commodore"),
		commodore_sub, 0
	},
	{
		BOARD_DCE,
		_T("DCE"),
		dceboard_sub, 0
	},
	{
		BOARD_DKB,
		_T("DKB"),
		dbk_sub, 0
	},
	{
		BOARD_GVP,
		_T("Great Valley Products"),
		gvpboard_sub, 0
	},
	{
		BOARD_KUPKE,
		_T("Kupke"),
		kupkeboard_sub, 0
	},
	{
		BOARD_MACROSYSTEM,
		_T("MacroSystem"),
		macrosystem_sub, 0
	},
	{
		BOARD_MTEC,
		_T("M-Tec"),
		mtec_sub, 0
	},
	{
		BOARD_BLIZZARD,
		_T("Phase 5 - Blizzard"),
		blizzardboard_sub, 0
	},
	{
		BOARD_CYBERSTORM,
		_T("Phase 5 - CyberStorm"),
		cyberstormboard_sub, 0
	},
	{
		BOARD_RCS,
		_T("RCS Management"),
		fusionforty_sub, 0
	},
	{
		BOARD_IVS,
		_T("Interactive Video Systems"),
		ivs_sub, 0
	},
	{
		BOARD_PPS,
		_T("Progressive Peripherals & Software"),
		pps_sub, 0
	},
	{
		BOARD_CSA,
		_T("Computer System Associates"),
		csa_sub, 0
	},
	{
		BOARD_HARDITAL,
		_T("Hardital"),
		hardital_sub, 0
	},
	{
		BOARD_HARMS,
		_T("Harms"),
		harms_sub, 0
	},
	{
		NULL
	}
};

const struct memoryboardtype memoryboards[]
{
	// z2
	{
		_T("UAE"), _T("0xf00000 RAM"),
		2, 0xf00000, 0xffff, 0xff
	},
	{
		_T("DKB"), _T("Insider I/II"),
		2, 0x800000, 0xffff, 0xff
	},
	{
		_T("GVP"), _T("Impact A2000-RAM8"),
		2, 0, 2077, 9
	},
	{
		_T("Kupke"), _T("Golem RAM-Card"),
		2, 0, 2073, 3
	},
	{
		_T("Supra"), _T("SupraRAM 500RX"),
		2, 0, 1056, 10
	},
	{
		_T("Supra"), _T("SupraRAM 2000"),
		2, 0, 1056, 9
	},
	// z3
	{
		_T("E3B"), _T("ZorRAM"),
		3, 0, 3643, 32
	},


	{
		NULL
	} 
};
