#define DEVICE_LOAD(name)  int device_load_##name(mess_image *image, mame_file *file)

#define ADDRESS_MAP_START(_name,_space,_bits)							\
address_map *construct_map_##_name(address_map *map)					\
{																		\
	typedef read##_bits##_handler _rh_t;								\
	typedef write##_bits##_handler _wh_t;								\
	_rh_t read;															\
	_wh_t write;														\
	UINT##_bits **base;													\
																		\
	(void)read; (void)write; (void)base;								\
	map->flags = AM_FLAGS_EXTENDED;										\
	map->start = AMEF_DBITS(_bits) | AMEF_SPACE(_space);				\

#define ADDRESS_MAP_FLAGS(_flags)										\
	map++;																\
	map->flags = AM_FLAGS_EXTENDED;										\
	map->start = (_flags);												\

#define ADDRESS_MAP_END													\
	map++;																\
	map->flags = AM_FLAGS_END;											\
	return map;															\
}																		\

/* ----- each map entry begins with one of these ----- */
#define AM_RANGE(_start,_end)											\
	map++;																\
	map->flags = 0;														\
	map->start = (_start);												\
	map->end = (_end);													\

#define AM_SPACE(_match,_mask)											\
	map++;																\
	map->flags = AM_FLAGS_MATCH_MASK;									\
	map->start = (_match);												\
	map->end = (_mask);													\


#define INPUT_PORTS_START(name)										\
 	void construct_ipt_##name(input_port_init_params *param)		\
	{																\
 		const char *modify_tag = NULL;								\
 		input_port_entry *port;										\
		int seq_index[3];											\
		int key;													\
		(void) port; (void) seq_index; (void) key; (void)modify_tag;\

/* end of table */
#define INPUT_PORTS_END												\
	}																\

#define PORT_START_TAG(tag_)										\
	modify_tag = NULL;												\
	port = input_port_initialize(param, IPT_PORT, NULL, 0);			\
	port->start.tag = (tag_);										\

/* start of a new input port */
#define PORT_START													\
	PORT_START_TAG(NULL)											\

/* modify an existing port */
#define PORT_MODIFY(tag_)											\
	modify_tag = (tag_);											\

/* input bit definition */
#define PORT_BIT(mask_,default_,type_) 								\
	port = input_port_initialize(param, (type_), modify_tag, (mask_));\
	port->mask = (mask_);											\
	port->default_value = (default_);								\
	seq_index[0] = seq_index[1] = seq_index[2] = key = 0;			\

/* new technique to append a code */
#define PORT_CODE_SEQ(code_,seq_,si_)								\
	if ((code_) < __code_max)										\
	{																\
		if (seq_index[si_] > 0)										\
			port->seq_.code[seq_index[si_]++] = CODE_OR;			\
		port->seq_.code[seq_index[si_]++] = (code_);				\
	}																\

#define PORT_CODE(code) PORT_CODE_SEQ(code,seq,0)
#define PORT_CODE_DEC(code)	PORT_CODE_SEQ(code,analog.decseq,1)
#define PORT_CODE_INC(code)	PORT_CODE_SEQ(code,analog.incseq,2)

#define PORT_2WAY													\
	port->four_way = FALSE;											\

#define PORT_4WAY													\
	port->four_way = TRUE;											\

#define PORT_8WAY													\
	port->four_way = FALSE;											\

#define PORT_PLAYER(player_)										\
	port->player = (player_) - 1;									\

#define PORT_COCKTAIL												\
	port->cocktail = TRUE;											\
	port->player = TRUE;											\

#define PORT_TOGGLE													\
	port->toggle = TRUE;											\

#define PORT_NAME(name_)											\
	port->name = (name_);											\

#define PORT_IMPULSE(duration_)										\
	port->impulse = (duration_);									\

#define PORT_REVERSE												\
	port->analog.reverse = TRUE;									\

#define PORT_RESET													\
	port->analog.reset = TRUE;										\

#define PORT_MINMAX(min_,max_)										\
	port->analog.min = (min_);										\
	port->analog.max = (max_);										\

#define PORT_SENSITIVITY(sensitivity_)								\
	port->analog.sensitivity = (sensitivity_);						\

#define PORT_KEYDELTA(delta_)										\
	port->analog.delta = port->analog.centerdelta = (delta_);		\

/* note that PORT_CENTERDELTA must appear after PORT_KEYDELTA */
#define PORT_CENTERDELTA(delta_)									\
	port->analog.centerdelta = (delta_);							\

#define PORT_UNUSED													\
	port->unused = TRUE;											\

#define PORT_CUSTOM(callback_, param_)								\
	port->custom = callback_;										\
	port->custom_param = (void *)(param_);							\


/* dip switch definition */
#define PORT_DIPNAME(mask,default,name)								\
	PORT_BIT(mask, default, IPT_DIPSWITCH_NAME) PORT_NAME(name)		\

#define PORT_DIPSETTING(default,name)								\
	PORT_BIT(0, default, IPT_DIPSWITCH_SETTING) PORT_NAME(name)		\

/* physical location, of the form: name:sw,[name:]sw,... */
/* note that these are specified LSB-first */
#define PORT_DIPLOCATION(location_)									\
	input_port_parse_diplocation(port, location_);					\

#define PALETTE_INIT(name)		void palette_init_##name(UINT16 *colortable, const UINT8 *color_prom)


#define MACHINE_DRIVER_START(game) 										\
	void construct_##game(machine_config *machine)						\
	{																	\
		cpu_config *cpu = NULL;											\
		sound_config *sound = NULL;										\
		screen_config *screen = &machine->screen[0];					\
		(void)cpu;														\
		(void)sound;													\
		(void)screen;													\

#define MACHINE_DRIVER_END 												\
	}																	\

#define MDRV_IMPORT_FROM(game) 											\
	construct_##game(machine); 											\


/* add/modify/remove/replace CPUs */
#define MDRV_CPU_ADD_TAG(tag, type, clock)								\
	cpu = driver_add_cpu(machine, (tag), CPU_##type, (clock));			\

#define MDRV_CPU_ADD(type, clock)										\
	MDRV_CPU_ADD_TAG(NULL, type, clock)									\

#define MDRV_CPU_MODIFY(tag)											\
	cpu = driver_find_cpu(machine, tag);								\

#define MDRV_CPU_REMOVE(tag)											\
	driver_remove_cpu(machine, tag);									\
	cpu = NULL;															\

#define MDRV_CPU_REPLACE(tag, type, clock)								\
	cpu = driver_find_cpu(machine, tag);								\
	if (cpu)															\
	{																	\
		cpu->cpu_type = (CPU_##type);									\
		cpu->cpu_clock = (clock);										\
	}																	\


/* CPU parameters */
#define MDRV_CPU_FLAGS(flags)											\
	if (cpu)															\
		cpu->cpu_flags = (flags);										\

#define MDRV_CPU_CONFIG(config)											\
	if (cpu)															\
		cpu->reset_param = &(config);									\

#define MDRV_CPU_PROGRAM_MAP(readmem, writemem)							\
	if (cpu)															\
	{																	\
		cpu->construct_map[ADDRESS_SPACE_PROGRAM][0] = (construct_map_##readmem); \
		cpu->construct_map[ADDRESS_SPACE_PROGRAM][1] = (construct_map_##writemem); \
	}																	\

#define MDRV_CPU_DATA_MAP(readmem, writemem)							\
	if (cpu)															\
	{																	\
		cpu->construct_map[ADDRESS_SPACE_DATA][0] = (construct_map_##readmem); \
		cpu->construct_map[ADDRESS_SPACE_DATA][1] = (construct_map_##writemem); \
	}																	\

#define MDRV_CPU_IO_MAP(readmem, writemem)								\
	if (cpu)															\
	{																	\
		cpu->construct_map[ADDRESS_SPACE_IO][0] = (construct_map_##readmem); \
		cpu->construct_map[ADDRESS_SPACE_IO][1] = (construct_map_##writemem); \
	}																	\

#define MDRV_CPU_VBLANK_INT(func, rate)									\
	if (cpu)															\
	{																	\
		cpu->vblank_interrupt = func;									\
		cpu->vblank_interrupts_per_frame = (rate);						\
	}																	\

#define MDRV_CPU_PERIODIC_INT(func, rate)								\
	if (cpu)															\
	{																	\
		cpu->timed_interrupt = func;									\
		cpu->timed_interrupt_period = (rate);							\
	}																	\


/* core parameters */
#define MDRV_INTERLEAVE(interleave)										\
	machine->cpu_slices_per_frame = (interleave);						\

#define MDRV_WATCHDOG_VBLANK_INIT(watch_count)							\
	machine->watchdog_vblank_count = (watch_count);						\

#define MDRV_WATCHDOG_TIME_INIT(time)									\
	machine->watchdog_time = (time);									\


/* core functions */
#define MDRV_MACHINE_START(name)										\
	machine->machine_start = machine_start_##name;						\

#define MDRV_MACHINE_RESET(name)										\
	machine->machine_reset = machine_reset_##name;						\

#define MDRV_NVRAM_HANDLER(name)										\
	machine->nvram_handler = nvram_handler_##name;						\

#define MDRV_MEMCARD_HANDLER(name)										\
	machine->memcard_handler = memcard_handler_##name;					\


/* core video parameters */
#define MDRV_VIDEO_ATTRIBUTES(flags)									\
	machine->video_attributes = (flags);								\

#define MDRV_GFXDECODE(gfx)												\
	machine->gfxdecodeinfo = (gfx);										\

#define MDRV_PALETTE_LENGTH(length)										\
	machine->total_colors = (length);									\

#define MDRV_COLORTABLE_LENGTH(length)									\
	machine->color_table_len = (length);								\

#define MDRV_DEFAULT_LAYOUT(layout)										\
	machine->default_layout = &(layout)[0];								\


/* core video functions */
#define MDRV_PALETTE_INIT(name)											\
	machine->init_palette = palette_init_##name;						\

#define MDRV_VIDEO_START(name)											\
	machine->video_start = video_start_##name;							\

#define MDRV_VIDEO_RESET(name)											\
	machine->video_reset = video_reset_##name;							\

#define MDRV_VIDEO_EOF(name)											\
	machine->video_eof = video_eof_##name;								\

#define MDRV_VIDEO_UPDATE(name)											\
	machine->video_update = video_update_##name;						\


/* add/remove screens */
#define MDRV_SCREEN_ADD(tag, palbase)									\
	screen = driver_add_screen(machine, (tag), (palbase));				\

#define MDRV_SCREEN_REMOVE(tag)											\
	driver_remove_screen(machine, tag);									\

#define MDRV_SCREEN_MODIFY(tag)											\
	screen = driver_find_screen(machine, tag);							\

#define MDRV_SCREEN_REFRESH_RATE(rate)									\
	screen->refresh_rate = (rate);										\

#define MDRV_SCREEN_VBLANK_TIME(time)									\
	screen->vblank_time = (time);										\

#define MDRV_SCREEN_MAXSIZE(width, height)								\
	screen->maxwidth = (width);											\
	screen->maxheight = (height);										\

#define MDRV_SCREEN_VISIBLE_AREA(minx, maxx, miny, maxy)				\
	screen->default_visible_area.min_x = (minx);						\
	screen->default_visible_area.max_x = (maxx);						\
	screen->default_visible_area.min_y = (miny);						\
	screen->default_visible_area.max_y = (maxy);						\


/* video backwards compatibility */
#define MDRV_FRAMES_PER_SECOND(rate)									\
	MDRV_SCREEN_REFRESH_RATE(rate)										\

#define MDRV_VBLANK_DURATION(duration)									\
	MDRV_SCREEN_VBLANK_TIME(TIME_IN_USEC(duration))						\

#define MDRV_SCREEN_SIZE(width, height)									\
	MDRV_SCREEN_MAXSIZE(width, height)									\

#define MDRV_VISIBLE_AREA(minx, maxx, miny, maxy)						\
	MDRV_SCREEN_VISIBLE_AREA(minx, maxx, miny, maxy)					\


/* add/remove speakers */
#define MDRV_SPEAKER_ADD(tag, x, y, z)									\
	driver_add_speaker(machine, (tag), (x), (y), (z));					\

#define MDRV_SPEAKER_REMOVE(tag)										\
	driver_remove_speaker(machine, (tag));								\

#define MDRV_SPEAKER_STANDARD_MONO(tag)									\
	MDRV_SPEAKER_ADD(tag, 0.0, 0.0, 1.0)								\

#define MDRV_SPEAKER_STANDARD_STEREO(tagl, tagr)						\
	MDRV_SPEAKER_ADD(tagl, -0.2, 0.0, 1.0)								\
	MDRV_SPEAKER_ADD(tagr, 0.2, 0.0, 1.0)								\


/* core sound functions */
#define MDRV_SOUND_START(name)											\
	machine->sound_start = sound_start_##name;							\

#define MDRV_SOUND_RESET(name)											\
	machine->sound_reset = sound_reset_##name;							\


/* add/remove/replace sounds */
#define MDRV_SOUND_ADD_TAG(tag, type, clock)							\
	sound = driver_add_sound(machine, (tag), SOUND_##type, (clock));	\

#define MDRV_SOUND_ADD(type, clock)										\
	MDRV_SOUND_ADD_TAG(NULL, type, clock)								\

#define MDRV_SOUND_REMOVE(tag)											\
	driver_remove_sound(machine, tag);									\

#define MDRV_SOUND_MODIFY(tag)											\
	sound = driver_find_sound(machine, tag);							\
	if (sound)															\
		sound->routes = 0;												\

#define MDRV_SOUND_CONFIG(_config)										\
	if (sound)															\
		sound->config = &(_config);										\

#define MDRV_SOUND_REPLACE(tag, type, _clock)							\
	sound = driver_find_sound(machine, tag);							\
	if (sound)															\
	{																	\
		sound->sound_type = SOUND_##type;								\
		sound->clock = (_clock);										\
		sound->config = NULL;											\
		sound->routes = 0;												\
	}																	\

#define MDRV_SOUND_ROUTE(_output, _target, _gain)						\
	if (sound)															\
	{																	\
		sound->route[sound->routes].output = (_output);					\
		sound->route[sound->routes].target = (_target);					\
		sound->route[sound->routes].gain = (_gain);						\
		sound->routes++;												\
	}																	\


#define ROM_START(name)								static const rom_entry rom_##name[] = {
#define ROM_END										{ ROMENTRY_END, 0, 0, 0, NULL } };
#define SYSTEM_BIOS_START(name)						static const bios_entry system_bios_##name[] = {
#define SYSTEM_BIOS_END								{ 0, NULL } };


/* ----- ROM region macros ----- */
#define ROM_REGION(length,type,flags)				{ ROMENTRY_REGION, 0, length, flags, (const char*)type },
#define ROM_REGION16_LE(length,type,flags)			ROM_REGION(length, type, (flags) | ROMREGION_16BIT | ROMREGION_LE)
#define ROM_REGION16_BE(length,type,flags)			ROM_REGION(length, type, (flags) | ROMREGION_16BIT | ROMREGION_BE)
#define ROM_REGION32_LE(length,type,flags)			ROM_REGION(length, type, (flags) | ROMREGION_32BIT | ROMREGION_LE)
#define ROM_REGION32_BE(length,type,flags)			ROM_REGION(length, type, (flags) | ROMREGION_32BIT | ROMREGION_BE)
#define ROM_REGION64_LE(length,type,flags)			ROM_REGION(length, type, (flags) | ROMREGION_64BIT | ROMREGION_LE)
#define ROM_REGION64_BE(length,type,flags)			ROM_REGION(length, type, (flags) | ROMREGION_64BIT | ROMREGION_BE)


/* ----- core ROM loading macros ----- */
#define ROMMD5_LOAD(name,offset,length,hash,flags)	{ name, offset, length, flags, hash },
#define ROMX_LOAD(name,offset,length,hash,flags)	{ name, offset, length, flags, hash },
#define ROM_LOAD(name,offset,length,hash)			ROMX_LOAD(name, offset, length, hash, 0)
#define ROM_LOAD_OPTIONAL(name,offset,length,hash)	ROMX_LOAD(name, offset, length, hash, ROM_OPTIONAL)
#define ROM_CONTINUE(offset,length)					ROMX_LOAD(ROMENTRY_CONTINUE, offset, length, 0, ROM_INHERITFLAGS)
#define ROM_RELOAD(offset,length)					ROMX_LOAD(ROMENTRY_RELOAD, offset, length, 0, ROM_INHERITFLAGS)
#define ROM_FILL(offset,length,value)				ROM_LOAD(ROMENTRY_FILL, offset, length, (const char*)value)
#define ROM_COPY(rgn,srcoffset,offset,length)		ROMX_LOAD(ROMENTRY_COPY, offset, length, (const char*)srcoffset, (rgn) << 24)


/* ----- specialized loading macros ----- */
#define ROM_LOAD_NIB_HIGH(name,offset,length,hash)	ROMX_LOAD(name, offset, length, hash, ROM_NIBBLE | ROM_SHIFT_NIBBLE_HI)
#define ROM_LOAD_NIB_LOW(name,offset,length,hash)	ROMX_LOAD(name, offset, length, hash, ROM_NIBBLE | ROM_SHIFT_NIBBLE_LO)
#define ROM_LOAD16_BYTE(name,offset,length,hash)	ROMX_LOAD(name, offset, length, hash, ROM_SKIP(1))
#define ROM_LOAD16_WORD(name,offset,length,hash)	ROM_LOAD(name, offset, length, hash)
#define ROM_LOAD16_WORD_SWAP(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_REVERSE)
#define ROM_LOAD32_BYTE(name,offset,length,hash)	ROMX_LOAD(name, offset, length, hash, ROM_SKIP(3))
#define ROM_LOAD32_WORD(name,offset,length,hash)	ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_SKIP(2))
#define ROM_LOAD32_WORD_SWAP(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2))
#define ROM_LOAD32_DWORD(name,offset,length,hash)	ROMX_LOAD(name, offset, length, hash, ROM_GROUPDWORD)

#define SYSTEM_CONFIG_START(name)															\
	static void construct_sysconfig_##name(struct SystemConfigurationParamBlock *cfg)		\
	{																						\

#define SYSTEM_CONFIG_END																	\
	}																						\

#define CONFIG_IMPORT_FROM(name)															\
		construct_sysconfig_##name(cfg);													\

#define CONFIG_RAM(ram)																		\
	if (cfg->max_ram_options > 0)															\
	{																						\
		assert(cfg->actual_ram_options < cfg->max_ram_options);								\
		assert(cfg->ram_options);															\
		cfg->ram_options[cfg->actual_ram_options++] = (ram);								\
	}																						\

#define CONFIG_RAM_DEFAULT(ram)																\
	if (cfg->max_ram_options > 0)															\
	{																						\
		cfg->default_ram_option = cfg->actual_ram_options;									\
		CONFIG_RAM(ram);																	\
	}																						\

#define CONFIG_DEVICE(getinfo)										\
	if (cfg->device_position < cfg->device_slotcount)				\
	{																\
		cfg->device_handlers[cfg->device_position++] = (getinfo);	\
	}																\

#define CONFIG_DEVICE_COUNT(getinfo, count)							\
	if (cfg->device_position < cfg->device_slotcount)				\
	{																\
		cfg->device_handlers[cfg->device_position] = (getinfo);		\
		cfg->device_countoverrides[cfg->device_position] = (count);	\
		cfg->device_position++;										\
	}																\


/******************************************************************************
 * MESS' version of the GAME() macros of MAME
 * CONS is for consoles
 * COMP is for computers
 ******************************************************************************/
#define CONS(YEAR,NAME,PARENT,COMPAT,MACHINE,INPUT,INIT,CONFIG,COMPANY,FULLNAME,FLAGS)	\
extern const game_driver driver_##PARENT;   \
extern const game_driver driver_##COMPAT;   \
extern const game_driver driver_##NAME;   \
const game_driver driver_##NAME = 	\
{											\
	__FILE__,								\
	#PARENT,								\
	#NAME,									\
	system_bios_0,							\
	FULLNAME,								\
	#YEAR,									\
	COMPANY,								\
	construct_##MACHINE,					\
	construct_ipt_##INPUT,					\
	init_##INIT,							\
	rom_##NAME,								\
	construct_sysconfig_##CONFIG,			\
	&driver_##COMPAT,						\
	ROT0|(FLAGS),							\
	NULL									\
};

#define CONSB(YEAR,NAME,PARENT,BIOS,COMPAT,MACHINE,INPUT,INIT,CONFIG,COMPANY,FULLNAME,FLAGS)	\
extern const game_driver driver_##PARENT;   \
extern const game_driver driver_##COMPAT;   \
extern const game_driver driver_##NAME;   \
const game_driver driver_##NAME = 	\
{											\
	__FILE__,								\
	#PARENT,								\
	#NAME,									\
	system_bios_##BIOS,						\
	FULLNAME,								\
	#YEAR,									\
	COMPANY,								\
	construct_##MACHINE,					\
	construct_ipt_##INPUT,					\
	init_##INIT,							\
	rom_##NAME,								\
	construct_sysconfig_##CONFIG,			\
	&driver_##COMPAT,						\
	ROT0|(FLAGS),							\
	NULL									\
};

#define COMP(YEAR,NAME,PARENT,COMPAT,MACHINE,INPUT,INIT,CONFIG,COMPANY,FULLNAME,FLAGS)	\
extern const game_driver driver_##PARENT;   \
extern const game_driver driver_##COMPAT;   \
extern const game_driver driver_##NAME;   \
const game_driver driver_##NAME = 	\
{											\
	__FILE__,								\
	#PARENT,								\
	#NAME,									\
	system_bios_0,							\
	FULLNAME,								\
	#YEAR,									\
	COMPANY,								\
	construct_##MACHINE,					\
	construct_ipt_##INPUT,					\
	init_##INIT,							\
	rom_##NAME,								\
	construct_sysconfig_##CONFIG,			\
	&driver_##COMPAT,						\
	ROT0|GAME_COMPUTER|(FLAGS),				\
	NULL									\
};

#define COMPB(YEAR,NAME,PARENT,BIOS,COMPAT,MACHINE,INPUT,INIT,CONFIG,COMPANY,FULLNAME,FLAGS)	\
extern const game_driver driver_##PARENT;   \
extern const game_driver driver_##COMPAT;   \
extern const game_driver driver_##NAME;   \
const game_driver driver_##NAME = 	\
{											\
	__FILE__,								\
	#PARENT,								\
	#NAME,									\
	system_bios_##BIOS,						\
	FULLNAME,								\
	#YEAR,									\
	COMPANY,								\
	construct_##MACHINE,					\
	construct_ipt_##INPUT,					\
	init_##INIT,							\
	rom_##NAME,								\
	construct_sysconfig_##CONFIG,			\
	&driver_##COMPAT,						\
	ROT0|GAME_COMPUTER|(FLAGS),				\
	NULL									\
};

#define CONFIG_TYPE_INIT			0		/* opportunity to initialize things first */
#define CONFIG_TYPE_CONTROLLER		1		/* loading from controller file */
#define CONFIG_TYPE_DEFAULT			2		/* loading from default.cfg */
#define CONFIG_TYPE_GAME			3		/* loading from game.cfg */
#define CONFIG_TYPE_FINAL			4		/* opportunity to finish initialization */

void mess_config_init(void);

//void config_register(const char *nodename, config_callback load, config_callback save);