diff options
Diffstat (limited to 'src/emu/memory.c')
-rw-r--r-- | src/emu/memory.c | 3422 |
1 files changed, 3422 insertions, 0 deletions
diff --git a/src/emu/memory.c b/src/emu/memory.c new file mode 100644 index 00000000000..d8fdee22a21 --- /dev/null +++ b/src/emu/memory.c @@ -0,0 +1,3422 @@ +/*************************************************************************** + + memory.c + + Functions which handle the CPU memory access. + + Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + + Caveats: + + * If your driver executes an opcode which crosses a bank-switched + boundary, it will pull the wrong data out of memory. Although not + a common case, you may need to revert to memcpy to work around this. + See machine/tnzs.c for an example. + + To do: + + - Add local banks for RAM/ROM to reduce pressure on banking + - Always mirror everything out to 32 bits so we don't have to mask the address? + - Add the ability to start with another memory map and modify it + - Add fourth memory space for encrypted opcodes + - Automatically mirror program space into data space if no data space + - Get rid of opcode/data separation by using address spaces? + - Add support for internal addressing (maybe just accessors - see TMS3202x) + - Evaluate min/max opcode ranges and do we include a check in cpu_readop? + +**************************************************************************** + + Address map fields and restrictions: + + AM_RANGE(start, end) + Specifies a range of consecutive addresses beginning with 'start' and + ending with 'end' inclusive. An address hits in this bucket if the + 'address' >= 'start' and 'address' <= 'end'. + + AM_SPACE(match, mask) + Specifies at the bit level (closer to real hardware) how to determine + if an address matches a given bit pattern. An address hits in this + bucket if 'address' & 'mask' == 'match' + + AM_MASK(mask) + Specifies a mask for the addresses in the current bucket. This mask + is applied after a positive hit in the bucket specified by AM_RANGE + or AM_SPACE, and is computed before accessing the RAM or calling + through to the read/write handler. If you use AM_SPACE, the mask + is implicitly set equal to the logical NOT of the mask specified in + the AM_SPACE macro. If you use AM_MIRROR, below, the mask is ANDed + implicitly with the logical NOT of the mirror. The mask specified + by this macro is ANDed against any implicit masks. + + AM_MIRROR(mirror) + Specifies mirror addresses for the given bucket. The current bucket + is mapped repeatedly according to the mirror mask, once where each + mirror bit is 0, and once where it is 1. For example, a 'mirror' + value of 0x14000 would map the bucket at 0x00000, 0x04000, 0x10000, + and 0x14000. + + AM_READ(read) + Specifies the read handler for this bucket. All reads will pass + through the given callback handler. Special static values representing + RAM, ROM, or BANKs are also allowed here. + + AM_WRITE(write) + Specifies the write handler for this bucket. All writes will pass + through the given callback handler. Special static values representing + RAM, ROM, or BANKs are also allowed here. + + AM_REGION(region, offs) + Only useful if AM_READ/WRITE point to RAM, ROM, or BANK memory. By + default, memory is allocated to back each bucket. By specifying + AM_REGION, you can tell the memory system to point the base of the + memory backing this bucket to a given memory 'region' at the + specified 'offs'. + + AM_SHARE(index) + Similar to AM_REGION, this specifies that the memory backing the + current bucket is shared with other buckets. The first bucket to + specify the share 'index' will use its memory as backing for all + future buckets that specify AM_SHARE with the same 'index'. + + AM_BASE(base) + Specifies a pointer to a pointer to the base of the memory backing + the current bucket. + + AM_SIZE(size) + Specifies a pointer to a size_t variable which will be filled in + with the size, in bytes, of the current bucket. + +***************************************************************************/ + +#include "driver.h" +#include "profiler.h" +#ifdef MAME_DEBUG +#include "debug/debugcpu.h" +#endif +#include <stdarg.h> + + +#define MEM_DUMP (0) +#define VERBOSE (0) +#define ALLOW_ONLY_AUTO_MALLOC_BANKS 0 + + +#if VERBOSE +#define VPRINTF(x) mame_printf_debug x +#else +#define VPRINTF(x) +#endif + + + +/*************************************************************************** + + Basic theory of memory handling: + + An address with up to 32 bits is passed to a memory handler. First, + an address mask is applied to the address, removing unused bits. + + Next, the address is broken into two halves, an upper half and a + lower half. The number of bits in each half can be controlled via + macros in memory.h, but they default to the upper 18 bits and the + lower 14 bits. The upper half is then used as an index into the + base_lookup table. + + If the value pulled from the table is within the range 192-255, then + the lower half of the address is needed to resolve the final handler. + The value from the table (192-255) is combined with the lower address + bits to form an index into a subtable. + + Table values in the range 0-63 are reserved for internal handling + (such as RAM, ROM, NOP, and banking). Table values between 64 and 192 + are assigned dynamically at startup. + +***************************************************************************/ + +/* macros for the profiler */ +#define MEMREADSTART() do { profiler_mark(PROFILER_MEMREAD); } while (0) +#define MEMREADEND(ret) do { profiler_mark(PROFILER_END); return ret; } while (0) +#define MEMWRITESTART() do { profiler_mark(PROFILER_MEMWRITE); } while (0) +#define MEMWRITEEND(ret) do { (ret); profiler_mark(PROFILER_END); return; } while (0) + +/* helper macros */ +#define HANDLER_IS_RAM(h) ((FPTR)(h) == STATIC_RAM) +#define HANDLER_IS_ROM(h) ((FPTR)(h) == STATIC_ROM) +#define HANDLER_IS_NOP(h) ((FPTR)(h) == STATIC_NOP) +#define HANDLER_IS_BANK(h) ((FPTR)(h) >= STATIC_BANK1 && (FPTR)(h) <= STATIC_BANKMAX) +#define HANDLER_IS_STATIC(h) ((FPTR)(h) < STATIC_COUNT) + +#define HANDLER_TO_BANK(h) ((FPTR)(h)) +#define BANK_TO_HANDLER(b) ((genf *)(FPTR)(b)) + +#define SPACE_SHIFT(s,a) (((s)->ashift < 0) ? ((a) << -(s)->ashift) : ((a) >> (s)->ashift)) +#define SPACE_SHIFT_END(s,a) (((s)->ashift < 0) ? (((a) << -(s)->ashift) | ((1 << -(s)->ashift) - 1)) : ((a) >> (s)->ashift)) +#define INV_SPACE_SHIFT(s,a) (((s)->ashift < 0) ? ((a) >> -(s)->ashift) : ((a) << (s)->ashift)) + +#define SUBTABLE_PTR(tabledata, entry) (&(tabledata)->table[(1 << LEVEL1_BITS) + (((entry) - SUBTABLE_BASE) << LEVEL2_BITS)]) + +#ifdef MAME_DEBUG +#define DEBUG_HOOK_READ(a,b,c) if (debug_hook_read) (*debug_hook_read)(a, b, c) +#define DEBUG_HOOK_WRITE(a,b,c,d) if (debug_hook_write) (*debug_hook_write)(a, b, c, d) +#else +#define DEBUG_HOOK_READ(a,b,c) +#define DEBUG_HOOK_WRITE(a,b,c,d) +#endif + + +/*------------------------------------------------- + TYPE DEFINITIONS +-------------------------------------------------*/ + +typedef struct _memory_block memory_block; +struct _memory_block +{ + UINT8 cpunum; /* which CPU are we associated with? */ + UINT8 spacenum; /* which address space are we associated with? */ + UINT8 isallocated; /* did we allocate this ourselves? */ + offs_t start, end; /* start/end or match/mask for verifying a match */ + UINT8 * data; /* pointer to the data for this block */ +}; + +typedef struct _bank_data bank_data; +struct _bank_data +{ + UINT8 used; /* is this bank used? */ + UINT8 dynamic; /* is this bank allocated dynamically? */ + UINT8 cpunum; /* the CPU it is used for */ + UINT8 spacenum; /* the address space it is used for */ + UINT8 read; /* is this bank used for reads? */ + UINT8 write; /* is this bank used for writes? */ + offs_t base; /* the base offset */ + offs_t end; /* the end offset */ + UINT16 curentry; /* current entry */ + void * entry[MAX_BANK_ENTRIES];/* array of entries for this bank */ + void * entryd[MAX_BANK_ENTRIES];/* array of decrypted entries for this bank */ +}; + +typedef union _rwhandlers rwhandlers; +union _rwhandlers +{ + genf * generic; /* generic handler void */ + read_handlers read; /* read handlers */ + write_handlers write; /* write handlers */ +}; + +/* In memory.h: typedef struct _handler_data handler_data */ +struct _handler_data +{ + rwhandlers handler; /* function pointer for handler */ + offs_t offset; /* base offset for handler */ + offs_t top; /* maximum offset for handler */ + offs_t mask; /* mask against the final address */ + const char * name; /* name of the handler */ +}; + +typedef struct _subtable_data subtable_data; +struct _subtable_data +{ + UINT8 checksum_valid; /* is the checksum valid */ + UINT32 checksum; /* checksum over all the bytes */ + UINT32 usecount; /* number of times this has been used */ +}; + +typedef struct _table_data table_data; +struct _table_data +{ + UINT8 * table; /* pointer to base of table */ + UINT8 subtable_alloc; /* number of subtables allocated */ + subtable_data subtable[SUBTABLE_COUNT]; /* info about each subtable */ + handler_data handlers[ENTRY_COUNT]; /* array of user-installed handlers */ +}; + +typedef struct _addrspace_data addrspace_data; +struct _addrspace_data +{ + UINT8 cpunum; /* CPU index */ + UINT8 spacenum; /* address space index */ + INT8 ashift; /* address shift */ + UINT8 abits; /* address bits */ + UINT8 dbits; /* data bits */ + offs_t rawmask; /* raw address mask, before adjusting to bytes */ + offs_t mask; /* address mask */ + UINT64 unmap; /* unmapped value */ + table_data read; /* memory read lookup table */ + table_data write; /* memory write lookup table */ + data_accessors * accessors; /* pointer to the memory accessors */ + address_map * map; /* original memory map */ + address_map * adjmap; /* adjusted memory map */ +}; + +typedef struct _cpu_data cpu_data; +struct _cpu_data +{ + opbase_handler opbase; /* opcode base handler */ + + void * op_ram; /* dynamic RAM base pointer */ + void * op_rom; /* dynamic ROM base pointer */ + offs_t op_mask; /* dynamic ROM address mask */ + offs_t op_mem_min; /* dynamic ROM/RAM min */ + offs_t op_mem_max; /* dynamic ROM/RAM max */ + UINT8 opcode_entry; /* opcode base handler */ + + UINT8 spacemask; /* mask of which address spaces are used */ + addrspace_data space[ADDRESS_SPACES]; /* info about each address space */ +}; + + +/*------------------------------------------------- + GLOBAL VARIABLES +-------------------------------------------------*/ + +UINT8 * opcode_base; /* opcode base */ +UINT8 * opcode_arg_base; /* opcode argument base */ +offs_t opcode_mask; /* mask to apply to the opcode address */ +offs_t opcode_memory_min; /* opcode memory minimum */ +offs_t opcode_memory_max; /* opcode memory maximum */ +UINT8 opcode_entry; /* opcode readmem entry */ + +address_space active_address_space[ADDRESS_SPACES];/* address space data */ + +static UINT8 * bank_ptr[STATIC_COUNT]; /* array of bank pointers */ +static UINT8 * bankd_ptr[STATIC_COUNT]; /* array of decrypted bank pointers */ +static void * shared_ptr[MAX_SHARED_POINTERS];/* array of shared pointers */ + +static memory_block memory_block_list[MAX_MEMORY_BLOCKS];/* array of memory blocks we are tracking */ +static int memory_block_count = 0; /* number of memory_block[] entries used */ + +static int cur_context; /* current CPU context */ + +static opbase_handler opbasefunc; /* opcode base override */ + +static int debugger_access; /* treat accesses as coming from the debugger */ +static int log_unmap[ADDRESS_SPACES]; /* log unmapped memory accesses */ + +static cpu_data cpudata[MAX_CPU]; /* data gathered for each CPU */ +static bank_data bankdata[STATIC_COUNT]; /* data gathered for each bank */ + +#ifdef MAME_DEBUG +static debug_hook_read_ptr debug_hook_read; /* pointer to debugger callback for memory reads */ +static debug_hook_write_ptr debug_hook_write; /* pointer to debugger callback for memory writes */ +#endif + +static data_accessors memory_accessors[ADDRESS_SPACES][4][2] = +{ + /* program accessors */ + { + { + { program_read_byte_8, NULL, NULL, NULL, program_write_byte_8, NULL, NULL, NULL }, + { program_read_byte_8, NULL, NULL, NULL, program_write_byte_8, NULL, NULL, NULL } + }, + { + { program_read_byte_16le, program_read_word_16le, NULL, NULL, program_write_byte_16le, program_write_word_16le, NULL, NULL }, + { program_read_byte_16be, program_read_word_16be, NULL, NULL, program_write_byte_16be, program_write_word_16be, NULL, NULL } + }, + { + { program_read_byte_32le, program_read_word_32le, program_read_dword_32le, NULL, program_write_byte_32le, program_write_word_32le, program_write_dword_32le, NULL }, + { program_read_byte_32be, program_read_word_32be, program_read_dword_32be, NULL, program_write_byte_32be, program_write_word_32be, program_write_dword_32be, NULL } + }, + { + { program_read_byte_64le, program_read_word_64le, program_read_dword_64le, program_read_qword_64le, program_write_byte_64le, program_write_word_64le, program_write_dword_64le, program_write_qword_64le }, + { program_read_byte_64be, program_read_word_64be, program_read_dword_64be, program_read_qword_64be, program_write_byte_64be, program_write_word_64be, program_write_dword_64be, program_write_qword_64be } + } + }, + + /* data accessors */ + { + { + { data_read_byte_8, NULL, NULL, NULL, data_write_byte_8, NULL, NULL, NULL }, + { data_read_byte_8, NULL, NULL, NULL, data_write_byte_8, NULL, NULL, NULL } + }, + { + { data_read_byte_16le, data_read_word_16le, NULL, NULL, data_write_byte_16le, data_write_word_16le, NULL, NULL }, + { data_read_byte_16be, data_read_word_16be, NULL, NULL, data_write_byte_16be, data_write_word_16be, NULL, NULL } + }, + { + { data_read_byte_32le, data_read_word_32le, data_read_dword_32le, NULL, data_write_byte_32le, data_write_word_32le, data_write_dword_32le, NULL }, + { data_read_byte_32be, data_read_word_32be, data_read_dword_32be, NULL, data_write_byte_32be, data_write_word_32be, data_write_dword_32be, NULL } + }, + { + { data_read_byte_64le, data_read_word_64le, data_read_dword_64le, data_read_qword_64le, data_write_byte_64le, data_write_word_64le, data_write_dword_64le, data_write_qword_64le }, + { data_read_byte_64be, data_read_word_64be, data_read_dword_64be, data_read_qword_64be, data_write_byte_64be, data_write_word_64be, data_write_dword_64be, data_write_qword_64be } + } + }, + + /* I/O accessors */ + { + { + { io_read_byte_8, NULL, NULL, NULL, io_write_byte_8, NULL, NULL, NULL }, + { io_read_byte_8, NULL, NULL, NULL, io_write_byte_8, NULL, NULL, NULL } + }, + { + { io_read_byte_16le, io_read_word_16le, NULL, NULL, io_write_byte_16le, io_write_word_16le, NULL, NULL }, + { io_read_byte_16be, io_read_word_16be, NULL, NULL, io_write_byte_16be, io_write_word_16be, NULL, NULL } + }, + { + { io_read_byte_32le, io_read_word_32le, io_read_dword_32le, NULL, io_write_byte_32le, io_write_word_32le, io_write_dword_32le, NULL }, + { io_read_byte_32be, io_read_word_32be, io_read_dword_32be, NULL, io_write_byte_32be, io_write_word_32be, io_write_dword_32be, NULL } + }, + { + { io_read_byte_64le, io_read_word_64le, io_read_dword_64le, io_read_qword_64le, io_write_byte_64le, io_write_word_64le, io_write_dword_64le, io_write_qword_64le }, + { io_read_byte_64be, io_read_word_64be, io_read_dword_64be, io_read_qword_64be, io_write_byte_64be, io_write_word_64be, io_write_dword_64be, io_write_qword_64be } + } + }, +}; + +const char *address_space_names[ADDRESS_SPACES] = { "program", "data", "I/O" }; + + +/*------------------------------------------------- + FUNCTION PROTOTYPES +-------------------------------------------------*/ + +static void init_cpudata(void); +static void init_addrspace(UINT8 cpunum, UINT8 spacenum); +static void preflight_memory(void); +static void populate_memory(void); +static void install_mem_handler(addrspace_data *space, int iswrite, int databits, int ismatchmask, offs_t start, offs_t end, offs_t mask, offs_t mirror, genf *handler, int isfixed, const char *handler_name); +static genf *assign_dynamic_bank(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mirror, int isfixed, int ismasked); +static UINT8 get_handler_index(handler_data *table, genf *handler, const char *handler_name, offs_t start, offs_t end, offs_t mask); +static void populate_table_range(addrspace_data *space, int iswrite, offs_t start, offs_t stop, UINT8 handler); +static void populate_table_match(addrspace_data *space, int iswrite, offs_t matchval, offs_t matchmask, UINT8 handler); +static UINT8 allocate_subtable(table_data *tabledata); +static void reallocate_subtable(table_data *tabledata, UINT8 subentry); +static int merge_subtables(table_data *tabledata); +static void release_subtable(table_data *tabledata, UINT8 subentry); +static UINT8 *open_subtable(table_data *tabledata, offs_t l1index); +static void close_subtable(table_data *tabledata, offs_t l1index); +static void allocate_memory(void); +static void *allocate_memory_block(int cpunum, int spacenum, offs_t start, offs_t end, void *memory); +static void register_for_save(int cpunum, int spacenum, offs_t start, void *base, size_t numbytes); +static address_map *assign_intersecting_blocks(addrspace_data *space, offs_t start, offs_t end, UINT8 *base); +static void find_memory(void); +static void *memory_find_base(int cpunum, int spacenum, int readwrite, offs_t offset); +static genf *get_static_handler(int databits, int readorwrite, int spacenum, int which); +static void memory_exit(running_machine *machine); + +static void mem_dump(void) +{ + FILE *file; + + if (MEM_DUMP) + { + file = fopen("memdump.log", "w"); + if (file) + { + memory_dump(file); + fclose(file); + } + } +} + + + +/*------------------------------------------------- + memory_init - initialize the memory system +-------------------------------------------------*/ + +void memory_init(running_machine *machine) +{ + int i; + + for (i = 0; i < ADDRESS_SPACES; i++) + log_unmap[i] = 1; + + /* no current context to start */ + cur_context = -1; + + /* reset the shared pointers and bank pointers */ + memset(shared_ptr, 0, sizeof(shared_ptr)); + memset(bank_ptr, 0, sizeof(bank_ptr)); + memset(bankd_ptr, 0, sizeof(bankd_ptr)); + + /* reset our hardcoded and allocated pointer tracking */ + memset(memory_block_list, 0, sizeof(memory_block_list)); + memory_block_count = 0; + + /* init the CPUs */ + init_cpudata(); + add_exit_callback(machine, memory_exit); + + /* preflight the memory handlers and check banks */ + preflight_memory(); + + /* then fill in the tables */ + populate_memory(); + + /* allocate any necessary memory */ + allocate_memory(); + + /* find all the allocated pointers */ + find_memory(); + + /* dump the final memory configuration */ + mem_dump(); +} + + +/*------------------------------------------------- + memory_exit - free memory +-------------------------------------------------*/ + +static void memory_exit(running_machine *machine) +{ + int cpunum, spacenum; + + /* free all the tables */ + for (cpunum = 0; cpunum < MAX_CPU; cpunum++) + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + { + if (cpudata[cpunum].space[spacenum].read.table) + free(cpudata[cpunum].space[spacenum].read.table); + if (cpudata[cpunum].space[spacenum].write.table) + free(cpudata[cpunum].space[spacenum].write.table); + } +} + + +/*------------------------------------------------- + memory_set_context - set the memory context +-------------------------------------------------*/ + +void memory_set_context(int activecpu) +{ + /* remember dynamic RAM/ROM */ + if (cur_context != -1) + { + cpudata[cur_context].op_ram = opcode_arg_base; + cpudata[cur_context].op_rom = opcode_base; + cpudata[cur_context].op_mask = opcode_mask; + cpudata[cur_context].op_mem_min = opcode_memory_min; + cpudata[cur_context].op_mem_max = opcode_memory_max; + cpudata[cur_context].opcode_entry = opcode_entry; + } + cur_context = activecpu; + + opcode_arg_base = cpudata[activecpu].op_ram; + opcode_base = cpudata[activecpu].op_rom; + opcode_mask = cpudata[activecpu].op_mask; + opcode_memory_min = cpudata[activecpu].op_mem_min; + opcode_memory_max = cpudata[activecpu].op_mem_max; + opcode_entry = cpudata[activecpu].opcode_entry; + + /* program address space */ + active_address_space[ADDRESS_SPACE_PROGRAM].addrmask = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].mask; + active_address_space[ADDRESS_SPACE_PROGRAM].readlookup = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].read.table; + active_address_space[ADDRESS_SPACE_PROGRAM].writelookup = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].write.table; + active_address_space[ADDRESS_SPACE_PROGRAM].readhandlers = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].read.handlers; + active_address_space[ADDRESS_SPACE_PROGRAM].writehandlers = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].write.handlers; + active_address_space[ADDRESS_SPACE_PROGRAM].accessors = cpudata[activecpu].space[ADDRESS_SPACE_PROGRAM].accessors; + + /* data address space */ + if (cpudata[activecpu].spacemask & (1 << ADDRESS_SPACE_DATA)) + { + active_address_space[ADDRESS_SPACE_DATA].addrmask = cpudata[activecpu].space[ADDRESS_SPACE_DATA].mask; + active_address_space[ADDRESS_SPACE_DATA].readlookup = cpudata[activecpu].space[ADDRESS_SPACE_DATA].read.table; + active_address_space[ADDRESS_SPACE_DATA].writelookup = cpudata[activecpu].space[ADDRESS_SPACE_DATA].write.table; + active_address_space[ADDRESS_SPACE_DATA].readhandlers = cpudata[activecpu].space[ADDRESS_SPACE_DATA].read.handlers; + active_address_space[ADDRESS_SPACE_DATA].writehandlers = cpudata[activecpu].space[ADDRESS_SPACE_DATA].write.handlers; + active_address_space[ADDRESS_SPACE_DATA].accessors = cpudata[activecpu].space[ADDRESS_SPACE_DATA].accessors; + } + + /* I/O address space */ + if (cpudata[activecpu].spacemask & (1 << ADDRESS_SPACE_IO)) + { + active_address_space[ADDRESS_SPACE_IO].addrmask = cpudata[activecpu].space[ADDRESS_SPACE_IO].mask; + active_address_space[ADDRESS_SPACE_IO].readlookup = cpudata[activecpu].space[ADDRESS_SPACE_IO].read.table; + active_address_space[ADDRESS_SPACE_IO].writelookup = cpudata[activecpu].space[ADDRESS_SPACE_IO].write.table; + active_address_space[ADDRESS_SPACE_IO].readhandlers = cpudata[activecpu].space[ADDRESS_SPACE_IO].read.handlers; + active_address_space[ADDRESS_SPACE_IO].writehandlers = cpudata[activecpu].space[ADDRESS_SPACE_IO].write.handlers; + active_address_space[ADDRESS_SPACE_IO].accessors = cpudata[activecpu].space[ADDRESS_SPACE_IO].accessors; + } + + opbasefunc = cpudata[activecpu].opbase; + +#ifdef MAME_DEBUG + if (activecpu != -1) + debug_get_memory_hooks(activecpu, &debug_hook_read, &debug_hook_write); + else + { + debug_hook_read = NULL; + debug_hook_write = NULL; + } +#endif +} + + +/*------------------------------------------------- + memory_get_map - return a pointer to a CPU's + memory map +-------------------------------------------------*/ + +const address_map *memory_get_map(int cpunum, int spacenum) +{ + return cpudata[cpunum].space[spacenum].map; +} + + +/*------------------------------------------------- + memory_set_opbase_handler - change op-code + memory base +-------------------------------------------------*/ + +opbase_handler memory_set_opbase_handler(int cpunum, opbase_handler function) +{ + opbase_handler old = cpudata[cpunum].opbase; + cpudata[cpunum].opbase = function; + if (cpunum == cpu_getactivecpu()) + opbasefunc = function; + return old; +} + + +/*------------------------------------------------- + memory_set_opbase - generic opcode base changer +-------------------------------------------------*/ + +void memory_set_opbase(offs_t pc) +{ + address_space *space = &active_address_space[ADDRESS_SPACE_PROGRAM]; + + UINT8 *base = NULL, *based = NULL; + handler_data *handlers; + UINT8 entry; + + /* allow overrides */ + if (opbasefunc) + { + pc = (*opbasefunc)(pc); + if (pc == ~0) + return; + } + + /* perform the lookup */ + pc &= space->addrmask; + entry = space->readlookup[LEVEL1_INDEX(pc)]; + if (entry >= SUBTABLE_BASE) + entry = space->readlookup[LEVEL2_INDEX(entry,pc)]; + opcode_entry = entry; + + /* if we don't map to a bank, see if there are any banks we can map to */ + if (entry < STATIC_BANK1 || entry >= STATIC_RAM) + { + /* loop over banks and find a match */ + for (entry = 1; entry < STATIC_COUNT; entry++) + { + bank_data *bdata = &bankdata[entry]; + if (bdata->used && bdata->cpunum == cur_context && bdata->spacenum == ADDRESS_SPACE_PROGRAM && + bdata->base < pc && bdata->end > pc) + break; + } + + /* if nothing was found, leave everything alone */ + if (entry == STATIC_COUNT) + { + logerror("cpu #%d (PC=%08X): warning - op-code execute on mapped I/O\n", + cpu_getactivecpu(), activecpu_get_pc()); + return; + } + } + + /* if no decrypted opcodes, point to the same base */ + base = bank_ptr[entry]; + based = bankd_ptr[entry]; + if (!based) + based = base; + + /* compute the adjusted base */ + handlers = &active_address_space[ADDRESS_SPACE_PROGRAM].readhandlers[entry]; + opcode_mask = handlers->mask; + opcode_arg_base = base - (handlers->offset & opcode_mask); + opcode_base = based - (handlers->offset & opcode_mask); + opcode_memory_min = handlers->offset; + opcode_memory_max = handlers->top; +} + + +/*------------------------------------------------- + memory_set_decrypted_region - sets the + decrypted region for the given CPU +-------------------------------------------------*/ + +void memory_set_decrypted_region(int cpunum, offs_t start, offs_t end, void *base) +{ + int banknum, found = FALSE; + + /* loop over banks looking for a match */ + for (banknum = 0; banknum < STATIC_COUNT; banknum++) + { + bank_data *bdata = &bankdata[banknum]; + if (bdata->used && bdata->cpunum == cpunum && bdata->spacenum == ADDRESS_SPACE_PROGRAM && bdata->read) + { + if (bdata->base >= start && bdata->end <= end) + { + bankd_ptr[banknum] = (UINT8 *)base + bdata->base - start; + found = TRUE; + + /* if this is live, adjust now */ + if (cpu_getactivecpu() >= 0 && cpunum == cur_context && opcode_entry == banknum) + memory_set_opbase(activecpu_get_physical_pc_byte()); + } + else if (bdata->base < end && bdata->end > start) + fatalerror("memory_set_decrypted_region found straddled region %08X-%08X for CPU %d", start, end, cpunum); + } + } + + if (!found) + fatalerror("memory_set_decrypted_region unable to find matching region %08X-%08X for CPU %d", start, end, cpunum); +} + + +/*------------------------------------------------- + memory_get_read_ptr - return a pointer to the + base of RAM associated with the given CPU + and offset +-------------------------------------------------*/ + +void *memory_get_read_ptr(int cpunum, int spacenum, offs_t offset) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + UINT8 entry; + + /* perform the lookup */ + offset &= space->mask; + entry = space->read.table[LEVEL1_INDEX(offset)]; + if (entry >= SUBTABLE_BASE) + entry = space->read.table[LEVEL2_INDEX(entry, offset)]; + + /* 8-bit case: RAM/ROM */ + if (entry >= STATIC_RAM) + return NULL; + offset = (offset - space->read.handlers[entry].offset) & space->read.handlers[entry].mask; + return &bank_ptr[entry][offset]; +} + + +/*------------------------------------------------- + memory_get_write_ptr - return a pointer to the + base of RAM associated with the given CPU + and offset +-------------------------------------------------*/ + +void *memory_get_write_ptr(int cpunum, int spacenum, offs_t offset) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + UINT8 entry; + + /* perform the lookup */ + offset &= space->mask; + entry = space->write.table[LEVEL1_INDEX(offset)]; + if (entry >= SUBTABLE_BASE) + entry = space->write.table[LEVEL2_INDEX(entry, offset)]; + + /* 8-bit case: RAM/ROM */ + if (entry >= STATIC_RAM) + return NULL; + offset = (offset - space->write.handlers[entry].offset) & space->write.handlers[entry].mask; + return &bank_ptr[entry][offset]; +} + + +/*------------------------------------------------- + memory_get_op_ptr - return a pointer to the + base of opcode RAM associated with the given + CPU and offset +-------------------------------------------------*/ + +void *memory_get_op_ptr(int cpunum, offs_t offset, int arg) +{ + addrspace_data *space = &cpudata[cpunum].space[ADDRESS_SPACE_PROGRAM]; + void *ptr = NULL; + UINT8 entry; + + /* if there is a custom mapper, use that */ + if (cpudata[cpunum].opbase != NULL) + { + /* need to save opcode info */ + UINT8 *saved_opcode_base = opcode_base; + UINT8 *saved_opcode_arg_base = opcode_arg_base; + offs_t saved_opcode_mask = opcode_mask; + offs_t saved_opcode_memory_min = opcode_memory_min; + offs_t saved_opcode_memory_max = opcode_memory_max; + UINT8 saved_opcode_entry = opcode_entry; + + /* query the handler */ + offs_t new_offset = (*cpudata[cpunum].opbase)(offset); + + /* if it returns ~0, we use whatever data the handler set */ + if (new_offset == ~0) + ptr = arg ? &opcode_arg_base[offset] : &opcode_base[offset]; + + /* otherwise, we use the new offset in the generic case below */ + else + offset = new_offset; + + /* restore opcode info */ + opcode_base = saved_opcode_base; + opcode_arg_base = saved_opcode_arg_base; + opcode_mask = saved_opcode_mask; + opcode_memory_min = saved_opcode_memory_min; + opcode_memory_max = saved_opcode_memory_max; + opcode_entry = saved_opcode_entry; + + /* if we got our pointer, we're done */ + if (ptr != NULL) + return ptr; + } + + /* perform the lookup */ + offset &= space->mask; + entry = space->read.table[LEVEL1_INDEX(offset)]; + if (entry >= SUBTABLE_BASE) + entry = space->read.table[LEVEL2_INDEX(entry, offset)]; + + /* if a non-RAM area, return NULL */ + if (entry >= STATIC_RAM) + return NULL; + + /* adjust the offset */ + offset = (offset - space->read.handlers[entry].offset) & space->read.handlers[entry].mask; + return (!arg && bankd_ptr[entry]) ? &bankd_ptr[entry][offset] : &bank_ptr[entry][offset]; +} + + +/*------------------------------------------------- + memory_configure_bank - configure the + addresses for a bank +-------------------------------------------------*/ + +void memory_configure_bank(int banknum, int startentry, int numentries, void *base, offs_t stride) +{ + int entrynum; + + /* validation checks */ + if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used) + fatalerror("memory_configure_bank called with invalid bank %d", banknum); + if (bankdata[banknum].dynamic) + fatalerror("memory_configure_bank called with dynamic bank %d", banknum); + if (startentry < 0 || startentry + numentries > MAX_BANK_ENTRIES) + fatalerror("memory_configure_bank called with out-of-range entries %d-%d", startentry, startentry + numentries - 1); + if (!base) + fatalerror("memory_configure_bank called NULL base"); + + /* fill in the requested bank entries */ + for (entrynum = startentry; entrynum < startentry + numentries; entrynum++) + bankdata[banknum].entry[entrynum] = (UINT8 *)base + (entrynum - startentry) * stride; +} + + + +/*------------------------------------------------- + memory_configure_bank_decrypted - configure + the decrypted addresses for a bank +-------------------------------------------------*/ + +void memory_configure_bank_decrypted(int banknum, int startentry, int numentries, void *base, offs_t stride) +{ + int entrynum; + + /* validation checks */ + if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used) + fatalerror("memory_configure_bank called with invalid bank %d", banknum); + if (bankdata[banknum].dynamic) + fatalerror("memory_configure_bank called with dynamic bank %d", banknum); + if (startentry < 0 || startentry + numentries > MAX_BANK_ENTRIES) + fatalerror("memory_configure_bank called with out-of-range entries %d-%d", startentry, startentry + numentries - 1); + if (!base) + fatalerror("memory_configure_bank_decrypted called NULL base"); + + /* fill in the requested bank entries */ + for (entrynum = startentry; entrynum < startentry + numentries; entrynum++) + bankdata[banknum].entryd[entrynum] = (UINT8 *)base + (entrynum - startentry) * stride; +} + + + +/*------------------------------------------------- + memory_set_bank - set the base of a bank +-------------------------------------------------*/ + +void memory_set_bank(int banknum, int entrynum) +{ + /* validation checks */ + if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used) + fatalerror("memory_set_bank called with invalid bank %d", banknum); + if (bankdata[banknum].dynamic) + fatalerror("memory_set_bank called with dynamic bank %d", banknum); + if (entrynum < 0 || entrynum > MAX_BANK_ENTRIES) + fatalerror("memory_set_bank called with out-of-range entry %d", entrynum); + if (!bankdata[banknum].entry[entrynum]) + fatalerror("memory_set_bank called for bank %d with invalid bank entry %d", banknum, entrynum); + + /* set the base */ + bankdata[banknum].curentry = entrynum; + bank_ptr[banknum] = bankdata[banknum].entry[entrynum]; + bankd_ptr[banknum] = bankdata[banknum].entryd[entrynum]; + + /* if we're executing out of this bank, adjust the opbase pointer */ + if (opcode_entry == banknum && cpu_getactivecpu() >= 0) + { + opcode_entry = 0xff; + memory_set_opbase(activecpu_get_physical_pc_byte()); + } +} + + + +/*------------------------------------------------- + memory_set_bankptr - set the base of a bank +-------------------------------------------------*/ + +void memory_set_bankptr(int banknum, void *base) +{ + /* validation checks */ + if (banknum < STATIC_BANK1 || banknum > MAX_EXPLICIT_BANKS || !bankdata[banknum].used) + fatalerror("memory_set_bankptr called with invalid bank %d", banknum); + if (bankdata[banknum].dynamic) + fatalerror("memory_set_bankptr called with dynamic bank %d", banknum); + if (base == NULL) + fatalerror("memory_set_bankptr called NULL base"); + if (ALLOW_ONLY_AUTO_MALLOC_BANKS) + validate_auto_malloc_memory(base, bankdata[banknum].end - bankdata[banknum].base + 1); + + /* set the base */ + bank_ptr[banknum] = base; + + /* if we're executing out of this bank, adjust the opbase pointer */ + if (opcode_entry == banknum && cpu_getactivecpu() >= 0) + { + opcode_entry = 0xff; + memory_set_opbase(activecpu_get_physical_pc_byte()); + } +} + + +/*------------------------------------------------- + memory_set_debugger_access - set debugger access +-------------------------------------------------*/ + +void memory_set_debugger_access(int debugger) +{ + debugger_access = debugger; +} + + +/*------------------------------------------------- + memory_set_log_unmap - sets whether unmapped + memory accesses should be logged or not +-------------------------------------------------*/ + +void memory_set_log_unmap(int spacenum, int log) +{ + log_unmap[spacenum] = log; +} + + +/*------------------------------------------------- + memory_get_log_unmap - gets whether unmapped + memory accesses should be logged or not +-------------------------------------------------*/ + +int memory_get_log_unmap(int spacenum) +{ + return log_unmap[spacenum]; +} + + +/*------------------------------------------------- + memory_install_readX_handler - install dynamic + read handler for X-bit case +-------------------------------------------------*/ + +void *_memory_install_read_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + if ((handler < 0) || (handler >= STATIC_COUNT)) + fatalerror("fatal: can only use static banks with memory_install_read_handler()"); + install_mem_handler(space, 0, space->dbits, 0, start, end, mask, mirror, (genf *)(FPTR)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start)); +} + +UINT8 *_memory_install_read8_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 8, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start)); +} + +UINT16 *_memory_install_read16_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 16, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start)); +} + +UINT32 *_memory_install_read32_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read32_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 32, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start)); +} + +UINT64 *_memory_install_read64_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read64_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 64, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, start)); +} + + +/*------------------------------------------------- + memory_install_writeX_handler - install dynamic + write handler for X-bit case +-------------------------------------------------*/ + +void *_memory_install_write_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + if ((handler < 0) || (handler >= STATIC_COUNT)) + fatalerror("fatal: can only use static banks with memory_install_write_handler()"); + install_mem_handler(space, 1, space->dbits, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start)); +} + +UINT8 *_memory_install_write8_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write8_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 8, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start)); +} + +UINT16 *_memory_install_write16_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write16_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 16, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start)); +} + +UINT32 *_memory_install_write32_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write32_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 32, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start)); +} + +UINT64 *_memory_install_write64_handler(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, write64_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 64, 0, start, end, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, start)); +} + + +/*------------------------------------------------- + memory_install_readX_matchmask_handler - + install dynamic match/mask read handler for + X-bit case +-------------------------------------------------*/ + +void *_memory_install_read_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + if ((handler < 0) || (handler >= STATIC_COUNT)) + fatalerror("fatal: can only use static banks with memory_install_read_matchmask_handler()"); + install_mem_handler(space, 0, space->dbits, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval)); +} + +UINT8 *_memory_install_read8_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read8_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 8, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval)); +} + +UINT16 *_memory_install_read16_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read16_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 16, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval)); +} + +UINT32 *_memory_install_read32_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read32_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 32, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval)); +} + +UINT64 *_memory_install_read64_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, read64_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 0, 64, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 0, SPACE_SHIFT(space, matchval)); +} + + +/*------------------------------------------------- + memory_install_writeX_matchmask_handler - + install dynamic match/mask write handler for + X-bit case +-------------------------------------------------*/ + +void *_memory_install_write_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, FPTR handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + if ((handler < 0) || (handler >= STATIC_COUNT)) + fatalerror("fatal: can only use static banks with memory_install_write_matchmask_handler()"); + install_mem_handler(space, 1, space->dbits, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval)); +} + +UINT8 *_memory_install_write8_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write8_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 8, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval)); +} + +UINT16 *_memory_install_write16_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write16_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 16, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval)); +} + +UINT32 *_memory_install_write32_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write32_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 32, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval)); +} + +UINT64 *_memory_install_write64_matchmask_handler(int cpunum, int spacenum, offs_t matchval, offs_t maskval, offs_t mask, offs_t mirror, write64_handler handler, const char *handler_name) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + install_mem_handler(space, 1, 64, 1, matchval, maskval, mask, mirror, (genf *)handler, 0, handler_name); + mem_dump(); + return memory_find_base(cpunum, spacenum, 1, SPACE_SHIFT(space, matchval)); +} + + +/*------------------------------------------------- + construct_address_map - build address map +-------------------------------------------------*/ + +void construct_address_map(address_map *map, const machine_config *drv, int cpunum, int spacenum) +{ + int cputype = drv->cpu[cpunum].type; + construct_map_t internal_map = (construct_map_t)cputype_get_info_fct(cputype, CPUINFO_PTR_INTERNAL_MEMORY_MAP + spacenum); + + map->flags = AM_FLAGS_END; + + /* start by constructing the internal CPU map */ + if (internal_map) + map = (*internal_map)(map); + + /* construct the standard map */ + if (drv->cpu[cpunum].construct_map[spacenum][0]) + map = (*drv->cpu[cpunum].construct_map[spacenum][0])(map); + if (drv->cpu[cpunum].construct_map[spacenum][1]) + map = (*drv->cpu[cpunum].construct_map[spacenum][1])(map); +} + + +/*------------------------------------------------- + init_cpudata - initialize the cpudata + structure for each CPU +-------------------------------------------------*/ + +static void init_cpudata(void) +{ + int cpunum, spacenum; + + /* zap the cpudata structure */ + memset(&cpudata, 0, sizeof(cpudata)); + + /* loop over CPUs */ + for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++) + { + /* set the RAM/ROM base */ + cpudata[cpunum].op_ram = cpudata[cpunum].op_rom = memory_region(REGION_CPU1 + cpunum); + cpudata[cpunum].op_mem_max = memory_region_length(REGION_CPU1 + cpunum); + cpudata[cpunum].op_mem_min = 0; + cpudata[cpunum].opcode_entry = STATIC_UNMAP; + cpudata[cpunum].opbase = NULL; + + /* TODO: make this dynamic */ + cpudata[cpunum].spacemask = 0; + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + init_addrspace(cpunum, spacenum); + cpudata[cpunum].op_mask = cpudata[cpunum].space[ADDRESS_SPACE_PROGRAM].mask; + } +} + + +/*------------------------------------------------- + adjust_addresses - adjust addresses for a + given address space in a standard fashion +-------------------------------------------------*/ + +INLINE void adjust_addresses(addrspace_data *space, int ismatchmask, offs_t *start, offs_t *end, offs_t *mask, offs_t *mirror) +{ + /* adjust start/end/mask values */ + if (*mask == 0) + *mask = space->rawmask & ~*mirror; + else + *mask &= space->rawmask; + *start &= ~*mirror & space->rawmask; + *end &= ~*mirror & space->rawmask; + + /* adjust to byte values */ + *mask = SPACE_SHIFT(space, *mask); + *start = SPACE_SHIFT(space, *start); + *end = ismatchmask ? SPACE_SHIFT(space, *end) : SPACE_SHIFT_END(space, *end); + *mirror = SPACE_SHIFT(space, *mirror); +} + + +/*------------------------------------------------- + init_addrspace - initialize the address space + data structure +-------------------------------------------------*/ + +static void init_addrspace(UINT8 cpunum, UINT8 spacenum) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + cpu_type cputype = Machine->drv->cpu[cpunum].type; + int abits = cputype_addrbus_width(cputype, spacenum); + int dbits = cputype_databus_width(cputype, spacenum); + int accessorindex = (dbits == 8) ? 0 : (dbits == 16) ? 1 : (dbits == 32) ? 2 : 3; + int entrynum; + + /* determine the address and data bits */ + space->cpunum = cpunum; + space->spacenum = spacenum; + space->ashift = cputype_addrbus_shift(cputype, spacenum); + space->abits = abits - space->ashift; + space->dbits = dbits; + space->rawmask = 0xffffffffUL >> (32 - abits); + space->mask = SPACE_SHIFT_END(space, space->rawmask); + space->accessors = &memory_accessors[spacenum][accessorindex][cputype_endianness(cputype) == CPU_IS_LE ? 0 : 1]; + space->map = NULL; + space->adjmap = NULL; + + /* if there's nothing here, just punt */ + if (space->abits == 0) + return; + cpudata[cpunum].spacemask |= 1 << spacenum; + + /* construct the combined memory map */ + { + /* allocate and clear memory for 2 copies of the map */ + address_map *map = auto_malloc(sizeof(space->map[0]) * MAX_ADDRESS_MAP_SIZE * 4); + memset(map, 0, sizeof(space->map[0]) * MAX_ADDRESS_MAP_SIZE * 4); + + /* make pointers to the standard and adjusted maps */ + space->map = map; + space->adjmap = &map[MAX_ADDRESS_MAP_SIZE * 2]; + + construct_address_map(map, Machine->drv, cpunum, spacenum); + + /* convert implicit ROM entries to map to the memory region */ + if (spacenum == ADDRESS_SPACE_PROGRAM && memory_region(REGION_CPU1 + cpunum)) + for (map = space->map; !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map) && HANDLER_IS_ROM(map->read.handler) && !map->region) + { + offs_t end = SPACE_SHIFT_END(space, map->end); + + /* make sure they fit within the memory region before doing so, however */ + if (end < memory_region_length(REGION_CPU1 + cpunum)) + { + map->region = REGION_CPU1 + cpunum; + map->region_offs = SPACE_SHIFT(space, map->start); + } + } + + /* convert region-relative entries to their memory pointers */ + for (map = space->map; !IS_AMENTRY_END(map); map++) + if (map->region) + map->memory = memory_region(map->region) + map->region_offs; + + /* make the adjusted map */ + memcpy(space->adjmap, space->map, sizeof(space->map[0]) * MAX_ADDRESS_MAP_SIZE * 2); + for (map = space->adjmap; !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map)) + adjust_addresses(space, IS_AMENTRY_MATCH_MASK(map), &map->start, &map->end, &map->mask, &map->mirror); + + /* validate adjusted addresses against implicit regions */ + for (map = space->adjmap; !IS_AMENTRY_END(map); map++) + if (map->region && map->share == 0 && !map->base) + { + UINT8 *base = memory_region(map->region); + offs_t length = memory_region_length(map->region); + + /* validate the region */ + if (!base) + fatalerror("Error: CPU %d space %d memory map entry %X-%X references non-existant region %d", cpunum, spacenum, map->start, map->end, map->region); + if (map->region_offs + (map->end - map->start + 1) > length) + fatalerror("Error: CPU %d space %d memory map entry %X-%X extends beyond region %d size (%X)", cpunum, spacenum, map->start, map->end, map->region, length); + } + } + + /* init the static handlers */ + memset(space->read.handlers, 0, sizeof(space->read.handlers)); + memset(space->write.handlers, 0, sizeof(space->write.handlers)); + for (entrynum = 0; entrynum < ENTRY_COUNT; entrynum++) + { + space->read.handlers[entrynum].handler.generic = get_static_handler(dbits, 0, spacenum, entrynum); + space->read.handlers[entrynum].mask = space->mask; + space->write.handlers[entrynum].handler.generic = get_static_handler(dbits, 1, spacenum, entrynum); + space->write.handlers[entrynum].mask = space->mask; + } + + /* allocate memory */ + space->read.table = malloc_or_die(1 << LEVEL1_BITS); + space->write.table = malloc_or_die(1 << LEVEL1_BITS); + + /* initialize everything to unmapped */ + memset(space->read.table, STATIC_UNMAP, 1 << LEVEL1_BITS); + memset(space->write.table, STATIC_UNMAP, 1 << LEVEL1_BITS); +} + + +/*------------------------------------------------- + preflight_memory - verify the memory structs + and track which banks are referenced +-------------------------------------------------*/ + +static void preflight_memory(void) +{ + int cpunum, spacenum, entrynum; + + /* zap the bank data */ + memset(&bankdata, 0, sizeof(bankdata)); + + /* loop over CPUs */ + for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++) + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + if (cpudata[cpunum].spacemask & (1 << spacenum)) + { + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + const address_map *map; + + /* scan the adjusted map */ + for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++) + { + /* look for extended flags */ + if (IS_AMENTRY_EXTENDED(map)) + { + UINT32 flags = AM_EXTENDED_FLAGS(map); + UINT32 val; + + /* if we specify an address space, make sure it matches the current space */ + if (flags & AMEF_SPECIFIES_SPACE) + { + val = (flags & AMEF_SPACE_MASK) >> AMEF_SPACE_SHIFT; + if (val != spacenum) + fatalerror("cpu #%d has address space %d handlers in place of address space %d handlers!", cpunum, val, spacenum); + } + + /* if we specify an databus width, make sure it matches the current address space's */ + if (flags & AMEF_SPECIFIES_DBITS) + { + val = (flags & AMEF_DBITS_MASK) >> AMEF_DBITS_SHIFT; + val = (val + 1) * 8; + if (val != space->dbits) + fatalerror("cpu #%d uses wrong %d-bit handlers for address space %d (should be %d-bit)!", cpunum, val, spacenum, space->dbits); + } + + /* if we specify an addressbus width, adjust the mask */ + if (flags & AMEF_SPECIFIES_ABITS) + { + space->rawmask = 0xffffffffUL >> (32 - ((flags & AMEF_ABITS_MASK) >> AMEF_ABITS_SHIFT)); + space->mask = SPACE_SHIFT_END(space, space->rawmask); + } + + /* if we specify an unmap value, set it */ + if (flags & AMEF_SPECIFIES_UNMAP) + space->unmap = ((flags & AMEF_UNMAP_MASK) == 0) ? (UINT64)0 : (UINT64)-1; + } + + /* otherwise, just track banks and hardcoded memory pointers */ + else + { + int bank = -1; + + /* look for a bank handler in eithe read or write */ + if (HANDLER_IS_BANK(map->read.handler)) + bank = HANDLER_TO_BANK(map->read.handler); + else if (HANDLER_IS_BANK(map->write.handler)) + bank = HANDLER_TO_BANK(map->write.handler); + + /* if we got one, add the data */ + if (bank >= 1 && bank <= MAX_EXPLICIT_BANKS) + { + bank_data *bdata = &bankdata[bank]; + + /* wire up state saving for the entry the first time we see it */ + if (!bdata->used) + state_save_register_item("memory", bank, bdata->curentry); + + bdata->used = TRUE; + bdata->dynamic = FALSE; + bdata->cpunum = cpunum; + bdata->spacenum = spacenum; + if (bank == HANDLER_TO_BANK(map->read.handler)) + bdata->read = TRUE; + if (bank == HANDLER_TO_BANK(map->write.handler)) + bdata->write = TRUE; + bdata->base = map->start; + bdata->end = map->end; + bdata->curentry = MAX_BANK_ENTRIES; + } + } + } + + /* now loop over all the handlers and enforce the address mask (which may have changed) */ + for (entrynum = 0; entrynum < ENTRY_COUNT; entrynum++) + { + space->read.handlers[entrynum].mask &= space->mask; + space->write.handlers[entrynum].mask &= space->mask; + } + } +} + + +/*------------------------------------------------- + populate_memory - populate the memory mapping + tables with entries +-------------------------------------------------*/ + +static void populate_memory(void) +{ + int cpunum, spacenum; + + /* loop over CPUs and address spaces */ + for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++) + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + if (cpudata[cpunum].spacemask & (1 << spacenum)) + { + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + const address_map *map; + + /* install the handlers, using the original, unadjusted memory map */ + if (space->map != NULL) + { + /* first find the end */ + for (map = space->map; !IS_AMENTRY_END(map); map++) ; + + /* then work backwards, populating the address map */ + for (map--; map >= space->map; map--) + if (!IS_AMENTRY_EXTENDED(map)) + { + int ismatchmask = ((map->flags & AM_FLAGS_MATCH_MASK) != 0); + int isfixed = (map->memory != NULL) || (map->share != 0); + if (map->read.handler != NULL) + install_mem_handler(space, 0, space->dbits, ismatchmask, map->start, map->end, map->mask, map->mirror, map->read.handler, isfixed, map->read_name); + if (map->write.handler != NULL) + install_mem_handler(space, 1, space->dbits, ismatchmask, map->start, map->end, map->mask, map->mirror, map->write.handler, isfixed, map->write_name); + } + } + } +} + + +/*------------------------------------------------- + install_mem_handler - installs a handler for + memory operations +-------------------------------------------------*/ + +static void install_mem_handler(addrspace_data *space, int iswrite, int databits, int ismatchmask, offs_t start, offs_t end, offs_t mask, offs_t mirror, genf *handler, int isfixed, const char *handler_name) +{ + offs_t lmirrorbit[LEVEL2_BITS], lmirrorbits, hmirrorbit[32 - LEVEL2_BITS], hmirrorbits, lmirrorcount, hmirrorcount; + table_data *tabledata = iswrite ? &space->write : &space->read; + UINT8 idx, prev_entry = STATIC_INVALID; + int cur_index, prev_index = 0; + int ismasked = (mask != 0); + int i; + + /* sanity check */ + if (space->dbits != databits) + fatalerror("fatal: install_mem_handler called with a %d-bit handler for a %d-bit address space", databits, space->dbits); + if (start > end) + fatalerror("fatal: install_mem_handler called with start greater than end"); + + /* if we're installing a new bank, make sure we mark it */ + if (HANDLER_IS_BANK(handler)) + { + bank_data *bdata = &bankdata[HANDLER_TO_BANK(handler)]; + + /* if this is the first time we've seen this bank, create a new entry */ + if (!bdata->used) + { + bdata->used = TRUE; + bdata->dynamic = FALSE; + bdata->cpunum = space->cpunum; + bdata->spacenum = space->spacenum; + bdata->base = start; + bdata->end = end; + bdata->curentry = MAX_BANK_ENTRIES; + + /* if we're allowed to, wire up state saving for the entry */ + if (state_save_registration_allowed()) + state_save_register_item("memory", HANDLER_TO_BANK(handler), bdata->curentry); + + VPRINTF(("Allocated new bank %d\n", HANDLER_TO_BANK(handler))); + } + } + + /* adjust the incoming addresses */ + adjust_addresses(space, ismatchmask, &start, &end, &mask, &mirror); + + /* sanity check */ + if (HANDLER_IS_RAM(handler)) + assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "RAM/ROM memory handlers can only be installed at init time"); + + /* translate ROM to RAM/UNMAP here */ + if (HANDLER_IS_ROM(handler)) + handler = iswrite ? (genf *)STATIC_UNMAP : (genf *)MRA8_RAM; + + /* assign banks for RAM/ROM areas */ + if (HANDLER_IS_RAM(handler)) + { + handler = (genf *)assign_dynamic_bank(space->cpunum, space->spacenum, start, end, mirror, isfixed, ismasked); + if (!bank_ptr[HANDLER_TO_BANK(handler)]) + bank_ptr[HANDLER_TO_BANK(handler)] = memory_find_base(space->cpunum, space->spacenum, iswrite, start); + } + + /* if this ended up a bank handler, tag it for reads or writes */ + if (HANDLER_IS_BANK(handler)) + { + bank_data *bdata = &bankdata[HANDLER_TO_BANK(handler)]; + + /* track whether reads or writes are going here */ + if (!iswrite) + bdata->read = TRUE; + else + bdata->write = TRUE; + } + + /* determine the mirror bits */ + hmirrorbits = lmirrorbits = 0; + for (i = 0; i < LEVEL2_BITS; i++) + if (mirror & (1 << i)) + lmirrorbit[lmirrorbits++] = 1 << i; + for (i = LEVEL2_BITS; i < 32; i++) + if (mirror & (1 << i)) + hmirrorbit[hmirrorbits++] = 1 << i; + + /* get the final handler index */ + idx = get_handler_index(tabledata->handlers, handler, handler_name, start, end, mask); + + /* loop over mirrors in the level 2 table */ + for (hmirrorcount = 0; hmirrorcount < (1 << hmirrorbits); hmirrorcount++) + { + /* compute the base of this mirror */ + offs_t hmirrorbase = 0; + for (i = 0; i < hmirrorbits; i++) + if (hmirrorcount & (1 << i)) + hmirrorbase |= hmirrorbit[i]; + + /* if this is not our first time through, and the level 2 entry matches the previous + level 2 entry, just do a quick map and get out; note that this only works for entries + which don't span multiple level 1 table entries */ + cur_index = LEVEL1_INDEX(start + hmirrorbase); + if (cur_index == LEVEL1_INDEX(end + hmirrorbase)) + { + if (hmirrorcount != 0 && prev_entry == tabledata->table[cur_index]) + { + VPRINTF(("Quick mapping subtable at %08X to match subtable at %08X\n", cur_index << LEVEL2_BITS, prev_index << LEVEL2_BITS)); + + /* release the subtable if the old value was a subtable */ + if (tabledata->table[cur_index] >= SUBTABLE_BASE) + release_subtable(tabledata, tabledata->table[cur_index]); + + /* reallocate the subtable if the new value is a subtable */ + if (tabledata->table[prev_index] >= SUBTABLE_BASE) + reallocate_subtable(tabledata, tabledata->table[prev_index]); + + /* set the new value and short-circuit the mapping step */ + tabledata->table[cur_index] = tabledata->table[prev_index]; + continue; + } + prev_index = cur_index; + prev_entry = tabledata->table[cur_index]; + } + + /* loop over mirrors in the level 1 table */ + for (lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++) + { + /* compute the base of this mirror */ + offs_t lmirrorbase = hmirrorbase; + for (i = 0; i < lmirrorbits; i++) + if (lmirrorcount & (1 << i)) + lmirrorbase |= lmirrorbit[i]; + + /* populate the tables */ + if (!ismatchmask) + populate_table_range(space, iswrite, start + lmirrorbase, end + lmirrorbase, idx); + else + populate_table_match(space, iswrite, start + lmirrorbase, end + lmirrorbase, idx); + } + } + + /* if this is being installed to a live CPU, update the context */ + if (space->cpunum == cur_context) + memory_set_context(cur_context); +} + + +/*------------------------------------------------- + assign_dynamic_bank - finds a free or exact + matching bank +-------------------------------------------------*/ + +static genf *assign_dynamic_bank(int cpunum, int spacenum, offs_t start, offs_t end, offs_t mirror, int isfixed, int ismasked) +{ + int bank; + + /* loop over banks, searching for an exact match or an empty */ + for (bank = MAX_BANKS; bank >= 1; bank--) + if (!bankdata[bank].used || (bankdata[bank].dynamic && bankdata[bank].cpunum == cpunum && bankdata[bank].spacenum == spacenum && bankdata[bank].base == start)) + { + bankdata[bank].used = TRUE; + bankdata[bank].dynamic = TRUE; + bankdata[bank].cpunum = cpunum; + bankdata[bank].spacenum = spacenum; + bankdata[bank].base = start; + bankdata[bank].end = end; + VPRINTF(("Assigned bank %d to %d,%d,%08X\n", bank, cpunum, spacenum, start)); + return BANK_TO_HANDLER(bank); + } + + /* if we got here, we failed */ + fatalerror("cpu #%d: ran out of banks for RAM/ROM regions!", cpunum); + return NULL; +} + + +/*------------------------------------------------- + get_handler_index - finds the index of a + handler, or allocates a new one as necessary +-------------------------------------------------*/ + +static UINT8 get_handler_index(handler_data *table, genf *handler, const char *handler_name, offs_t start, offs_t end, offs_t mask) +{ + int i; + + start &= mask; + + /* all static handlers are hardcoded */ + if (HANDLER_IS_STATIC(handler)) + { + i = (FPTR)handler; + if (HANDLER_IS_BANK(handler)) + { + table[i].offset = start; + table[i].top = end; + table[i].mask = mask; + table[i].name = handler_name; + } + return i; + } + + /* otherwise, we have to search */ + for (i = STATIC_COUNT; i < SUBTABLE_BASE; i++) + { + if (table[i].handler.generic == NULL) + { + table[i].handler.generic = handler; + table[i].offset = start; + table[i].top = end; + table[i].mask = mask; + table[i].name = handler_name; + return i; + } + if (table[i].handler.generic == handler && table[i].offset == start && table[i].mask == mask) + return i; + } + return 0; +} + + +/*------------------------------------------------- + populate_table_range - assign a memory handler + to a range of addresses +-------------------------------------------------*/ + +static void populate_table_range(addrspace_data *space, int iswrite, offs_t start, offs_t stop, UINT8 handler) +{ + table_data *tabledata = iswrite ? &space->write : &space->read; + offs_t l2mask = (1 << LEVEL2_BITS) - 1; + offs_t l1start = start >> LEVEL2_BITS; + offs_t l2start = start & l2mask; + offs_t l1stop = stop >> LEVEL2_BITS; + offs_t l2stop = stop & l2mask; + offs_t l1index; + + /* sanity check */ + if (start > stop) + return; + + /* handle the starting edge if it's not on a block boundary */ + if (l2start != 0) + { + UINT8 *subtable = open_subtable(tabledata, l1start); + + /* if the start and stop end within the same block, handle that */ + if (l1start == l1stop) + { + memset(&subtable[l2start], handler, l2stop - l2start + 1); + close_subtable(tabledata, l1start); + return; + } + + /* otherwise, fill until the end */ + memset(&subtable[l2start], handler, (1 << LEVEL2_BITS) - l2start); + close_subtable(tabledata, l1start); + if (l1start != (offs_t)~0) l1start++; + } + + /* handle the trailing edge if it's not on a block boundary */ + if (l2stop != l2mask) + { + UINT8 *subtable = open_subtable(tabledata, l1stop); + + /* fill from the beginning */ + memset(&subtable[0], handler, l2stop + 1); + close_subtable(tabledata, l1stop); + + /* if the start and stop end within the same block, handle that */ + if (l1start == l1stop) + return; + if (l1stop != 0) l1stop--; + } + + /* now fill in the middle tables */ + for (l1index = l1start; l1index <= l1stop; l1index++) + { + /* if we have a subtable here, release it */ + if (tabledata->table[l1index] >= SUBTABLE_BASE) + release_subtable(tabledata, tabledata->table[l1index]); + tabledata->table[l1index] = handler; + } +} + + +/*------------------------------------------------- + populate_table_match - assign a memory handler + to a range of addresses +-------------------------------------------------*/ + +static void populate_table_match(addrspace_data *space, int iswrite, offs_t matchval, offs_t matchmask, UINT8 handler) +{ + table_data *tabledata = iswrite ? &space->write : &space->read; + int lowermask, lowermatch; + int uppermask, uppermatch; + int l1index, l2index; + + /* clear out any ignored bits in the matchval */ + matchval &= matchmask; + + /* compute the lower half of the match/mask pair */ + lowermask = matchmask & ((1<<LEVEL2_BITS)-1); + lowermatch = matchval & ((1<<LEVEL2_BITS)-1); + + /* compute the upper half of the match/mask pair */ + uppermask = matchmask >> LEVEL2_BITS; + uppermatch = matchval >> LEVEL2_BITS; + + /* if the lower bits of the mask are all 0, we can work exclusively at the top level */ + if (lowermask == 0) + { + /* loop over top level matches */ + for (l1index = 0; l1index <= (space->mask >> LEVEL2_BITS); l1index++) + if ((l1index & uppermatch) == uppermask) + { + /* if we have a subtable here, release it */ + if (tabledata->table[l1index] >= SUBTABLE_BASE) + release_subtable(tabledata, tabledata->table[l1index]); + tabledata->table[l1index] = handler; + } + } + + /* okay, we need to work at both levels */ + else + { + /* loop over top level matches */ + for (l1index = 0; l1index <= (space->mask >> LEVEL2_BITS); l1index++) + if ((l1index & uppermatch) == uppermask) + { + UINT8 *subtable = open_subtable(tabledata, l1index); + + /* now loop over lower level matches */ + for (l2index = 0; l2index < (1 << LEVEL2_BITS); l2index++) + if ((l2index & lowermask) == lowermatch) + subtable[l2index] = handler; + close_subtable(tabledata, l1index); + } + } +} + + +/*------------------------------------------------- + allocate_subtable - allocate a fresh subtable + and set its usecount to 1 +-------------------------------------------------*/ + +static UINT8 allocate_subtable(table_data *tabledata) +{ + /* loop */ + while (1) + { + UINT8 subindex; + + /* find a subtable with a usecount of 0 */ + for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++) + if (tabledata->subtable[subindex].usecount == 0) + { + /* if this is past our allocation budget, allocate some more */ + if (subindex >= tabledata->subtable_alloc) + { + tabledata->subtable_alloc += SUBTABLE_ALLOC; + tabledata->table = realloc(tabledata->table, (1 << LEVEL1_BITS) + (tabledata->subtable_alloc << LEVEL2_BITS)); + if (!tabledata->table) + fatalerror("error: ran out of memory allocating memory subtable"); + } + + /* bump the usecount and return */ + tabledata->subtable[subindex].usecount++; + return subindex + SUBTABLE_BASE; + } + + /* merge any subtables we can */ + if (!merge_subtables(tabledata)) + fatalerror("Ran out of subtables!"); + } + + /* hopefully this never happens */ + return 0; +} + + +/*------------------------------------------------- + reallocate_subtable - increment the usecount on + a subtable +-------------------------------------------------*/ + +static void reallocate_subtable(table_data *tabledata, UINT8 subentry) +{ + UINT8 subindex = subentry - SUBTABLE_BASE; + + /* sanity check */ + if (tabledata->subtable[subindex].usecount <= 0) + fatalerror("Called reallocate_subtable on a table with a usecount of 0"); + + /* increment the usecount */ + tabledata->subtable[subindex].usecount++; +} + + +/*------------------------------------------------- + merge_subtables - merge any duplicate + subtables +-------------------------------------------------*/ + +static int merge_subtables(table_data *tabledata) +{ + int merged = 0; + UINT8 subindex; + + VPRINTF(("Merging subtables....\n")); + + /* okay, we failed; update all the checksums and merge tables */ + for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++) + if (!tabledata->subtable[subindex].checksum_valid && tabledata->subtable[subindex].usecount != 0) + { + UINT32 *subtable = (UINT32 *)SUBTABLE_PTR(tabledata, subindex + SUBTABLE_BASE); + UINT32 checksum = 0; + int l2index; + + /* update the checksum */ + for (l2index = 0; l2index < (1 << LEVEL2_BITS)/4; l2index++) + checksum += subtable[l2index]; + tabledata->subtable[subindex].checksum = checksum; + tabledata->subtable[subindex].checksum_valid = 1; + } + + /* see if there's a matching checksum */ + for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++) + if (tabledata->subtable[subindex].usecount != 0) + { + UINT8 *subtable = SUBTABLE_PTR(tabledata, subindex + SUBTABLE_BASE); + UINT32 checksum = tabledata->subtable[subindex].checksum; + UINT8 sumindex; + + for (sumindex = subindex + 1; sumindex < SUBTABLE_COUNT; sumindex++) + if (tabledata->subtable[sumindex].usecount != 0 && + tabledata->subtable[sumindex].checksum == checksum && + !memcmp(subtable, SUBTABLE_PTR(tabledata, sumindex + SUBTABLE_BASE), 1 << LEVEL2_BITS)) + { + int l1index; + + VPRINTF(("Merging subtable %d and %d....\n", subindex, sumindex)); + + /* find all the entries in the L1 tables that pointed to the old one, and point them to the merged table */ + for (l1index = 0; l1index <= (0xffffffffUL >> LEVEL2_BITS); l1index++) + if (tabledata->table[l1index] == sumindex + SUBTABLE_BASE) + { + release_subtable(tabledata, sumindex + SUBTABLE_BASE); + reallocate_subtable(tabledata, subindex + SUBTABLE_BASE); + tabledata->table[l1index] = subindex + SUBTABLE_BASE; + merged++; + } + } + } + + return merged; +} + + +/*------------------------------------------------- + release_subtable - decrement the usecount on + a subtable and free it if we're done +-------------------------------------------------*/ + +static void release_subtable(table_data *tabledata, UINT8 subentry) +{ + UINT8 subindex = subentry - SUBTABLE_BASE; + + /* sanity check */ + if (tabledata->subtable[subindex].usecount <= 0) + fatalerror("Called release_subtable on a table with a usecount of 0"); + + /* decrement the usecount and clear the checksum if we're at 0 */ + tabledata->subtable[subindex].usecount--; + if (tabledata->subtable[subindex].usecount == 0) + tabledata->subtable[subindex].checksum = 0; +} + + +/*------------------------------------------------- + open_subtable - gain access to a subtable for + modification +-------------------------------------------------*/ + +static UINT8 *open_subtable(table_data *tabledata, offs_t l1index) +{ + UINT8 subentry = tabledata->table[l1index]; + + /* if we don't have a subtable yet, allocate a new one */ + if (subentry < SUBTABLE_BASE) + { + UINT8 newentry = allocate_subtable(tabledata); + memset(SUBTABLE_PTR(tabledata, newentry), subentry, 1 << LEVEL2_BITS); + tabledata->table[l1index] = newentry; + tabledata->subtable[newentry - SUBTABLE_BASE].checksum = (subentry + (subentry << 8) + (subentry << 16) + (subentry << 24)) * ((1 << LEVEL2_BITS)/4); + subentry = newentry; + } + + /* if we're sharing this subtable, we also need to allocate a fresh copy */ + else if (tabledata->subtable[subentry - SUBTABLE_BASE].usecount > 1) + { + UINT8 newentry = allocate_subtable(tabledata); + + /* allocate may cause some additional merging -- look up the subentry again */ + /* when we're done; it should still require a split */ + subentry = tabledata->table[l1index]; + assert(subentry >= SUBTABLE_BASE); + assert(tabledata->subtable[subentry - SUBTABLE_BASE].usecount > 1); + + memcpy(SUBTABLE_PTR(tabledata, newentry), SUBTABLE_PTR(tabledata, subentry), 1 << LEVEL2_BITS); + release_subtable(tabledata, subentry); + tabledata->table[l1index] = newentry; + tabledata->subtable[newentry - SUBTABLE_BASE].checksum = tabledata->subtable[subentry - SUBTABLE_BASE].checksum; + subentry = newentry; + } + + /* mark the table dirty */ + tabledata->subtable[subentry - SUBTABLE_BASE].checksum_valid = 0; + + /* return the pointer to the subtable */ + return SUBTABLE_PTR(tabledata, subentry); +} + + +/*------------------------------------------------- + close_subtable - stop access to a subtable +-------------------------------------------------*/ + +static void close_subtable(table_data *tabledata, offs_t l1index) +{ + /* defer any merging until we run out of tables */ +} + + +/*------------------------------------------------- + Return whether a given memory map entry implies + the need of allocating and registering memory +-------------------------------------------------*/ + +static int amentry_needs_backing_store(int cpunum, int spacenum, const address_map *map) +{ + FPTR handler; + + if (IS_AMENTRY_EXTENDED(map)) + return 0; + if (map->base) + return 1; + + handler = (FPTR)map->write.handler; + if (handler >= 0 && handler < STATIC_COUNT) + { + if (handler != STATIC_INVALID && + handler != STATIC_ROM && + handler != STATIC_NOP && + handler != STATIC_UNMAP) + return 1; + } + + handler = (FPTR)map->read.handler; + if (handler >= 0 && handler < STATIC_COUNT) + { + if (handler != STATIC_INVALID && + (handler < STATIC_BANK1 || handler > STATIC_BANK1 + MAX_BANKS - 1) && + (handler != STATIC_ROM || spacenum != ADDRESS_SPACE_PROGRAM || map->start >= memory_region_length(REGION_CPU1 + cpunum)) && + handler != STATIC_NOP && + handler != STATIC_UNMAP) + return 1; + } + + return 0; +} + + +/*------------------------------------------------- + allocate_memory - allocate memory for + CPU address spaces +-------------------------------------------------*/ + +static void allocate_memory(void) +{ + int cpunum, spacenum; + + /* loop over all CPUs and memory spaces */ + for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++) + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + if (cpudata[cpunum].spacemask & (1 << spacenum)) + { + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + address_map *map, *unassigned = NULL; + int start_count = memory_block_count; + int i; + + /* make a first pass over the memory map and track blocks with hardcoded pointers */ + /* we do this to make sure they are found by memory_find_base first */ + for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map) && map->memory != NULL) + { + if (!IS_AMENTRY_MATCH_MASK(map)) + allocate_memory_block(cpunum, spacenum, map->start, map->end, map->memory); + else + allocate_memory_block(cpunum, spacenum, map->start, map->start + map->mask, map->memory); + } + + /* loop over all blocks just allocated and assign pointers from them */ + for (i = start_count; i < memory_block_count; i++) + unassigned = assign_intersecting_blocks(space, memory_block_list[i].start, memory_block_list[i].end, memory_block_list[i].data); + + /* if we don't have an unassigned pointer yet, try to find one */ + if (!unassigned) + unassigned = assign_intersecting_blocks(space, ~0, 0, NULL); + + /* loop until we've assigned all memory in this space */ + while (unassigned) + { + offs_t curstart, curend; + int changed; + void *block; + + /* work in MEMORY_BLOCK_SIZE-sized chunks */ + curstart = unassigned->start / MEMORY_BLOCK_SIZE; + if (!IS_AMENTRY_MATCH_MASK(unassigned)) + curend = unassigned->end / MEMORY_BLOCK_SIZE; + else + curend = (unassigned->start + unassigned->mask) / MEMORY_BLOCK_SIZE; + + /* loop while we keep finding unassigned blocks in neighboring MEMORY_BLOCK_SIZE chunks */ + do + { + changed = 0; + + /* scan for unmapped blocks in the adjusted map */ + for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map) && map->memory == NULL && map != unassigned && amentry_needs_backing_store(cpunum, spacenum, map)) + { + offs_t blockstart, blockend; + + /* get block start/end blocks for this block */ + blockstart = map->start / MEMORY_BLOCK_SIZE; + if (!IS_AMENTRY_MATCH_MASK(map)) + blockend = map->end / MEMORY_BLOCK_SIZE; + else + blockend = (map->start + map->mask) / MEMORY_BLOCK_SIZE; + + /* if we intersect or are adjacent, adjust the start/end */ + if (blockstart <= curend + 1 && blockend >= curstart - 1) + { + if (blockstart < curstart) + curstart = blockstart, changed = 1; + if (blockend > curend) + curend = blockend, changed = 1; + } + } + } while (changed); + + /* we now have a block to allocate; do it */ + curstart = curstart * MEMORY_BLOCK_SIZE; + curend = curend * MEMORY_BLOCK_SIZE + (MEMORY_BLOCK_SIZE - 1); + block = allocate_memory_block(cpunum, spacenum, curstart, curend, NULL); + + /* assign memory that intersected the new block */ + unassigned = assign_intersecting_blocks(space, curstart, curend, block); + } + } +} + + +/*------------------------------------------------- + allocate_memory_block - allocate a single + memory block of data +-------------------------------------------------*/ + +static void *allocate_memory_block(int cpunum, int spacenum, offs_t start, offs_t end, void *memory) +{ + memory_block *block = &memory_block_list[memory_block_count]; + int allocatemem = (memory == NULL); + int region; + + VPRINTF(("allocate_memory_block(%d,%d,%08X,%08X,%08X)\n", cpunum, spacenum, start, end, (UINT32)memory)); + + /* if we weren't passed a memory block, allocate one and clear it to zero */ + if (allocatemem) + { + memory = auto_malloc(end - start + 1); + memset(memory, 0, end - start + 1); + } + + /* register for saving, but only if we're not part of a memory region */ + for (region = 0; region < MAX_MEMORY_REGIONS; region++) + { + UINT8 *region_base = memory_region(region); + UINT32 region_length = memory_region_length(region); + if (region_base != NULL && region_length != 0 && (UINT8 *)memory >= region_base && ((UINT8 *)memory + (end - start + 1)) < region_base + region_length) + { + VPRINTF(("skipping save of this memory block as it is covered by a memory region\n")); + break; + } + } + if (region == MAX_MEMORY_REGIONS) + register_for_save(cpunum, spacenum, start, memory, end - start + 1); + + /* fill in the tracking block */ + block->cpunum = cpunum; + block->spacenum = spacenum; + block->isallocated = allocatemem; + block->start = start; + block->end = end; + block->data = memory; + memory_block_count++; + return memory; +} + + +/*------------------------------------------------- + register_for_save - register a block of + memory for save states +-------------------------------------------------*/ + +static void register_for_save(int cpunum, int spacenum, offs_t start, void *base, size_t numbytes) +{ + int bytes_per_element = cpudata[cpunum].space[spacenum].dbits/8; + char name[256]; + + sprintf(name, "%d.%08x-%08x", spacenum, start, (int)(start + numbytes - 1)); + state_save_register_memory("memory", cpunum, name, base, bytes_per_element, (UINT32)numbytes / bytes_per_element); +} + + +/*------------------------------------------------- + assign_intersecting_blocks - find all + intersecting blocks and assign their pointers +-------------------------------------------------*/ + +static address_map *assign_intersecting_blocks(addrspace_data *space, offs_t start, offs_t end, UINT8 *base) +{ + address_map *map, *unassigned = NULL; + + /* loop over the adjusted map and assign memory to any blocks we can */ + for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map)) + { + /* if we haven't assigned this block yet, do it against the last block */ + if (map->memory == NULL) + { + /* inherit shared pointers first */ + if (map->share && shared_ptr[map->share]) + { + map->memory = shared_ptr[map->share]; + VPRINTF(("memory range %08X-%08X -> shared_ptr[%d] [%08X]\n", map->start, map->end, map->share, (UINT32)map->memory)); + } + + /* otherwise, look for a match in this block */ + else + { + if (!IS_AMENTRY_MATCH_MASK(map)) + { + if (map->start >= start && map->end <= end) + { + map->memory = base + (map->start - start); + VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%08X]\n", map->start, map->end, start, end, (UINT32)map->memory)); + } + } + else + { + if (map->start >= start && map->start + map->mask <= end) + { + map->memory = base + (map->start - start); + VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%08X]\n", map->start, map->end, start, end, (UINT32)map->memory)); + } + } + } + } + + /* if we're the first match on a shared pointer, assign it now */ + if (map->memory != NULL && map->share && !shared_ptr[map->share]) + shared_ptr[map->share] = map->memory; + + /* keep track of the first unassigned entry */ + if (map->memory == NULL && !unassigned && amentry_needs_backing_store(space->cpunum, space->spacenum, map)) + unassigned = map; + } + + return unassigned; +} + + +/*------------------------------------------------- + reattach_banks - reconnect banks after a load +-------------------------------------------------*/ + +static void reattach_banks(void) +{ + int banknum; + + /* once this is done, find the starting bases for the banks */ + for (banknum = 1; banknum <= MAX_BANKS; banknum++) + if (bankdata[banknum].used && !bankdata[banknum].dynamic) + { + /* if this entry has a changed entry, set the appropriate pointer */ + if (bankdata[banknum].curentry != MAX_BANK_ENTRIES) + bank_ptr[banknum] = bankdata[banknum].entry[bankdata[banknum].curentry]; + } +} + + +/*------------------------------------------------- + find_memory - find all the requested pointers + into the final allocated memory +-------------------------------------------------*/ + +static void find_memory(void) +{ + int cpunum, spacenum, banknum; + + /* loop over CPUs and address spaces */ + for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++) + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + if (cpudata[cpunum].spacemask & (1 << spacenum)) + { + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + const address_map *map; + + /* fill in base/size entries, and handle shared memory */ + for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map)) + { + /* assign base/size values */ + if (map->base != NULL) + *map->base = map->memory; + if (map->size) + { + if (!IS_AMENTRY_MATCH_MASK(map)) + *map->size = map->end - map->start + 1; + else + *map->size = map->mask + 1; + } + } + } + + /* once this is done, find the starting bases for the banks */ + for (banknum = 1; banknum <= MAX_BANKS; banknum++) + if (bankdata[banknum].used) + { + address_map *map; + + /* set the initial bank pointer */ + for (map = cpudata[bankdata[banknum].cpunum].space[bankdata[banknum].spacenum].adjmap; map && !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map) && map->start == bankdata[banknum].base) + { + bank_ptr[banknum] = map->memory; + VPRINTF(("assigned bank %d pointer to memory from range %08X-%08X [%08X]\n", banknum, map->start, map->end, (UINT32)map->memory)); + break; + } + + /* if the entry was set ahead of time, override the automatically found pointer */ + if (!bankdata[banknum].dynamic && bankdata[banknum].curentry != MAX_BANK_ENTRIES) + bank_ptr[banknum] = bankdata[banknum].entry[bankdata[banknum].curentry]; + } + + /* request a callback to fix up the banks when done */ + state_save_register_func_postload(reattach_banks); +} + + +/*------------------------------------------------- + memory_find_base - return a pointer to the + base of RAM associated with the given CPU + and offset +-------------------------------------------------*/ + +static void *memory_find_base(int cpunum, int spacenum, int readwrite, offs_t offset) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + address_map *map; + memory_block *block; + int blocknum; + + VPRINTF(("memory_find_base(%d,%d,%d,%08X) -> ", cpunum, spacenum, readwrite, offset)); + + /* look in the adjusted map */ + for (map = space->adjmap; map && !IS_AMENTRY_END(map); map++) + if (!IS_AMENTRY_EXTENDED(map)) + { + offs_t maskoffs = offset & map->mask; + if (!IS_AMENTRY_MATCH_MASK(map)) + { + if (maskoffs >= map->start && maskoffs <= map->end) + { + VPRINTF(("found in entry %08X-%08X [%08X]\n", map->start, map->end, (UINT32)map->memory + (maskoffs - map->start))); + return (UINT8 *)map->memory + (maskoffs - map->start); + } + } + else + { + if ((maskoffs & map->end) == map->start) + { + VPRINTF(("found in entry %08X-%08X [%08X]\n", map->start, map->end, (UINT32)map->memory + (maskoffs - map->start))); + return (UINT8 *)map->memory + (maskoffs - map->start); + } + } + } + + /* if not found there, look in the allocated blocks */ + for (blocknum = 0, block = memory_block_list; blocknum < memory_block_count; blocknum++, block++) + if (block->cpunum == cpunum && block->spacenum == spacenum && block->start <= offset && block->end > offset) + { + VPRINTF(("found in allocated memory block %08X-%08X [%08X]\n", block->start, block->end, (UINT32)block->data + (offset - block->start))); + return block->data + offset - block->start; + } + + VPRINTF(("did not find\n")); + return NULL; +} + + +/*------------------------------------------------- + PERFORM_LOOKUP - common lookup procedure +-------------------------------------------------*/ + +#define PERFORM_LOOKUP(lookup,space,extraand) \ + /* perform lookup */ \ + address &= space.addrmask & extraand; \ + entry = space.lookup[LEVEL1_INDEX(address)]; \ + if (entry >= SUBTABLE_BASE) \ + entry = space.lookup[LEVEL2_INDEX(entry,address)]; \ + + +/*------------------------------------------------- + READBYTE - generic byte-sized read handler +-------------------------------------------------*/ + +#define READBYTE8(name,spacenum) \ +UINT8 name(offs_t original_address) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~0); \ + DEBUG_HOOK_READ(spacenum, 1, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(bank_ptr[entry][address]); \ + \ + /* fall back to the handler */ \ + else \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler8)(address));\ + return 0; \ +} \ + +#define READBYTE(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \ +UINT8 name(offs_t original_address) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~0); \ + DEBUG_HOOK_READ(spacenum, 1, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(bank_ptr[entry][xormacro(address)]); \ + \ + /* fall back to the handler */ \ + else \ + { \ + int shift = 8 * (shiftbytes); \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handlertype)(address >> (ignorebits), ~((masktype)0xff << shift)) >> shift);\ + } \ + return 0; \ +} \ + +#define READBYTE16BE(name,space) READBYTE(name,space,BYTE_XOR_BE, handler16,1,~address & 1,UINT16) +#define READBYTE16LE(name,space) READBYTE(name,space,BYTE_XOR_LE, handler16,1, address & 1,UINT16) +#define READBYTE32BE(name,space) READBYTE(name,space,BYTE4_XOR_BE,handler32,2,~address & 3,UINT32) +#define READBYTE32LE(name,space) READBYTE(name,space,BYTE4_XOR_LE,handler32,2, address & 3,UINT32) +#define READBYTE64BE(name,space) READBYTE(name,space,BYTE8_XOR_BE,handler64,3,~address & 7,UINT64) +#define READBYTE64LE(name,space) READBYTE(name,space,BYTE8_XOR_LE,handler64,3, address & 7,UINT64) + + +/*------------------------------------------------- + READWORD - generic word-sized read handler + (16-bit, 32-bit and 64-bit aligned only!) +-------------------------------------------------*/ + +#define READWORD16(name,spacenum) \ +UINT16 name(offs_t original_address) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~1); \ + DEBUG_HOOK_READ(spacenum, 2, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(*(UINT16 *)&bank_ptr[entry][address]); \ + \ + /* fall back to the handler */ \ + else \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler16)(address >> 1,0));\ + return 0; \ +} \ + +#define READWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \ +UINT16 name(offs_t original_address) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~1); \ + DEBUG_HOOK_READ(spacenum, 2, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(*(UINT16 *)&bank_ptr[entry][xormacro(address)]); \ + \ + /* fall back to the handler */ \ + else \ + { \ + int shift = 8 * (shiftbytes); \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handlertype)(address >> (ignorebits), ~((masktype)0xffff << shift)) >> shift);\ + } \ + return 0; \ +} \ + +#define READWORD32BE(name,space) READWORD(name,space,WORD_XOR_BE, handler32,2,~address & 2,UINT32) +#define READWORD32LE(name,space) READWORD(name,space,WORD_XOR_LE, handler32,2, address & 2,UINT32) +#define READWORD64BE(name,space) READWORD(name,space,WORD2_XOR_BE,handler64,3,~address & 6,UINT64) +#define READWORD64LE(name,space) READWORD(name,space,WORD2_XOR_LE,handler64,3, address & 6,UINT64) + + +/*------------------------------------------------- + READDWORD - generic dword-sized read handler + (32-bit and 64-bit aligned only!) +-------------------------------------------------*/ + +#define READDWORD32(name,spacenum) \ +UINT32 name(offs_t original_address) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~3); \ + DEBUG_HOOK_READ(spacenum, 4, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(*(UINT32 *)&bank_ptr[entry][address]); \ + \ + /* fall back to the handler */ \ + else \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler32)(address >> 2,0));\ + return 0; \ +} \ + +#define READMASKED32(name,spacenum) \ +UINT32 name(offs_t original_address, UINT32 mem_mask) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~3); \ + DEBUG_HOOK_READ(spacenum, 4, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(*(UINT32 *)&bank_ptr[entry][address]); \ + \ + /* fall back to the handler */ \ + else \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler32)(address >> 2, mem_mask));\ + return 0; \ +} \ + +#define READDWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \ +UINT32 name(offs_t original_address) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~3); \ + DEBUG_HOOK_READ(spacenum, 4, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(*(UINT32 *)&bank_ptr[entry][xormacro(address)]); \ + \ + /* fall back to the handler */ \ + else \ + { \ + int shift = 8 * (shiftbytes); \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handlertype)(address >> (ignorebits), ~((masktype)0xffffffff << shift)) >> shift);\ + } \ + return 0; \ +} \ + +#define READDWORD64BE(name,space) READDWORD(name,space,DWORD_XOR_BE,handler64,3,~address & 4,UINT64) +#define READDWORD64LE(name,space) READDWORD(name,space,DWORD_XOR_LE,handler64,3, address & 4,UINT64) + + +/*------------------------------------------------- + READQWORD - generic qword-sized read handler + (64-bit aligned only!) +-------------------------------------------------*/ + +#define READQWORD64(name,spacenum) \ +UINT64 name(offs_t original_address) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~7); \ + DEBUG_HOOK_READ(spacenum, 8, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(*(UINT64 *)&bank_ptr[entry][address]); \ + \ + /* fall back to the handler */ \ + else \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler64)(address >> 3,0));\ + return 0; \ +} \ + +#define READMASKED64(name,spacenum) \ +UINT64 name(offs_t original_address, UINT64 mem_mask) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMREADSTART(); \ + PERFORM_LOOKUP(readlookup,active_address_space[spacenum],~7); \ + DEBUG_HOOK_READ(spacenum, 8, address); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].readhandlers[entry].offset) & active_address_space[spacenum].readhandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMREADEND(*(UINT64 *)&bank_ptr[entry][address]); \ + \ + /* fall back to the handler */ \ + else \ + MEMREADEND((*active_address_space[spacenum].readhandlers[entry].handler.read.handler64)(address >> 3, mem_mask));\ + return 0; \ +} \ + + +/*------------------------------------------------- + WRITEBYTE - generic byte-sized write handler +-------------------------------------------------*/ + +#define WRITEBYTE8(name,spacenum) \ +void name(offs_t original_address, UINT8 data) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~0); \ + DEBUG_HOOK_WRITE(spacenum, 1, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMWRITEEND(bank_ptr[entry][address] = data); \ + \ + /* fall back to the handler */ \ + else \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler8)(address, data));\ +} \ + +#define WRITEBYTE(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \ +void name(offs_t original_address, UINT8 data) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~0); \ + DEBUG_HOOK_WRITE(spacenum, 1, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMWRITEEND(bank_ptr[entry][xormacro(address)] = data); \ + \ + /* fall back to the handler */ \ + else \ + { \ + int shift = 8 * (shiftbytes); \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handlertype)(address >> (ignorebits), (masktype)data << shift, ~((masktype)0xff << shift)));\ + } \ +} \ + +#define WRITEBYTE16BE(name,space) WRITEBYTE(name,space,BYTE_XOR_BE, handler16,1,~address & 1,UINT16) +#define WRITEBYTE16LE(name,space) WRITEBYTE(name,space,BYTE_XOR_LE, handler16,1, address & 1,UINT16) +#define WRITEBYTE32BE(name,space) WRITEBYTE(name,space,BYTE4_XOR_BE,handler32,2,~address & 3,UINT32) +#define WRITEBYTE32LE(name,space) WRITEBYTE(name,space,BYTE4_XOR_LE,handler32,2, address & 3,UINT32) +#define WRITEBYTE64BE(name,space) WRITEBYTE(name,space,BYTE8_XOR_BE,handler64,3,~address & 7,UINT64) +#define WRITEBYTE64LE(name,space) WRITEBYTE(name,space,BYTE8_XOR_LE,handler64,3, address & 7,UINT64) + + +/*------------------------------------------------- + WRITEWORD - generic word-sized write handler + (16-bit, 32-bit and 64-bit aligned only!) +-------------------------------------------------*/ + +#define WRITEWORD16(name,spacenum) \ +void name(offs_t original_address, UINT16 data) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~1); \ + DEBUG_HOOK_WRITE(spacenum, 2, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMWRITEEND(*(UINT16 *)&bank_ptr[entry][address] = data); \ + \ + /* fall back to the handler */ \ + else \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler16)(address >> 1, data, 0));\ +} \ + +#define WRITEWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \ +void name(offs_t original_address, UINT16 data) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~1); \ + DEBUG_HOOK_WRITE(spacenum, 2, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMWRITEEND(*(UINT16 *)&bank_ptr[entry][xormacro(address)] = data); \ + \ + /* fall back to the handler */ \ + else \ + { \ + int shift = 8 * (shiftbytes); \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handlertype)(address >> (ignorebits), (masktype)data << shift, ~((masktype)0xffff << shift)));\ + } \ +} \ + +#define WRITEWORD32BE(name,space) WRITEWORD(name,space,WORD_XOR_BE, handler32,2,~address & 2,UINT32) +#define WRITEWORD32LE(name,space) WRITEWORD(name,space,WORD_XOR_LE, handler32,2, address & 2,UINT32) +#define WRITEWORD64BE(name,space) WRITEWORD(name,space,WORD2_XOR_BE,handler64,3,~address & 6,UINT64) +#define WRITEWORD64LE(name,space) WRITEWORD(name,space,WORD2_XOR_LE,handler64,3, address & 6,UINT64) + + +/*------------------------------------------------- + WRITEDWORD - dword-sized write handler + (32-bit and 64-bit aligned only!) +-------------------------------------------------*/ + +#define WRITEDWORD32(name,spacenum) \ +void name(offs_t original_address, UINT32 data) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~3); \ + DEBUG_HOOK_WRITE(spacenum, 4, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMWRITEEND(*(UINT32 *)&bank_ptr[entry][address] = data); \ + \ + /* fall back to the handler */ \ + else \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler32)(address >> 2, data, 0));\ +} \ + +#define WRITEMASKED32(name,spacenum) \ +void name(offs_t original_address, UINT32 data, UINT32 mem_mask) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~3); \ + DEBUG_HOOK_WRITE(spacenum, 4, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + { \ + UINT32 *dest = (UINT32 *)&bank_ptr[entry][address]; \ + MEMWRITEEND(*dest = (*dest & mem_mask) | (data & ~mem_mask)); \ + } \ + \ + /* fall back to the handler */ \ + else \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler32)(address >> 2, data, mem_mask));\ +} \ + +#define WRITEDWORD(name,spacenum,xormacro,handlertype,ignorebits,shiftbytes,masktype) \ +void name(offs_t original_address, UINT32 data) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~3); \ + DEBUG_HOOK_WRITE(spacenum, 4, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMWRITEEND(*(UINT32 *)&bank_ptr[entry][xormacro(address)] = data); \ + \ + /* fall back to the handler */ \ + else \ + { \ + int shift = 8 * (shiftbytes); \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handlertype)(address >> (ignorebits), (masktype)data << shift, ~((masktype)0xffffffff << shift)));\ + } \ +} \ + +#define WRITEDWORD64BE(name,space) WRITEDWORD(name,space,DWORD_XOR_BE,handler64,3,~address & 4,UINT64) +#define WRITEDWORD64LE(name,space) WRITEDWORD(name,space,DWORD_XOR_LE,handler64,3, address & 4,UINT64) + + +/*------------------------------------------------- + WRITEQWORD - qword-sized write handler + (64-bit aligned only!) +-------------------------------------------------*/ + +#define WRITEQWORD64(name,spacenum) \ +void name(offs_t original_address, UINT64 data) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~7); \ + DEBUG_HOOK_WRITE(spacenum, 8, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + MEMWRITEEND(*(UINT64 *)&bank_ptr[entry][address] = data); \ + \ + /* fall back to the handler */ \ + else \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler64)(address >> 3, data, 0));\ +} \ + +#define WRITEMASKED64(name,spacenum) \ +void name(offs_t original_address, UINT64 data, UINT64 mem_mask) \ +{ \ + offs_t address = original_address; \ + UINT32 entry; \ + MEMWRITESTART(); \ + PERFORM_LOOKUP(writelookup,active_address_space[spacenum],~7); \ + DEBUG_HOOK_WRITE(spacenum, 8, address, data); \ + \ + /* handle banks inline */ \ + address = (address - active_address_space[spacenum].writehandlers[entry].offset) & active_address_space[spacenum].writehandlers[entry].mask;\ + if (entry < STATIC_RAM) \ + { \ + UINT64 *dest = (UINT64 *)&bank_ptr[entry][address]; \ + MEMWRITEEND(*dest = (*dest & mem_mask) | (data & ~mem_mask)); \ + } \ + \ + /* fall back to the handler */ \ + else \ + MEMWRITEEND((*active_address_space[spacenum].writehandlers[entry].handler.write.handler64)(address >> 3, data, mem_mask));\ +} \ + + +/*------------------------------------------------- + Program memory handlers +-------------------------------------------------*/ + + READBYTE8(program_read_byte_8, ADDRESS_SPACE_PROGRAM) + WRITEBYTE8(program_write_byte_8, ADDRESS_SPACE_PROGRAM) + + READBYTE16BE(program_read_byte_16be, ADDRESS_SPACE_PROGRAM) + READWORD16(program_read_word_16be, ADDRESS_SPACE_PROGRAM) + WRITEBYTE16BE(program_write_byte_16be, ADDRESS_SPACE_PROGRAM) + WRITEWORD16(program_write_word_16be, ADDRESS_SPACE_PROGRAM) + + READBYTE16LE(program_read_byte_16le, ADDRESS_SPACE_PROGRAM) + READWORD16(program_read_word_16le, ADDRESS_SPACE_PROGRAM) + WRITEBYTE16LE(program_write_byte_16le, ADDRESS_SPACE_PROGRAM) + WRITEWORD16(program_write_word_16le, ADDRESS_SPACE_PROGRAM) + + READBYTE32BE(program_read_byte_32be, ADDRESS_SPACE_PROGRAM) + READWORD32BE(program_read_word_32be, ADDRESS_SPACE_PROGRAM) + READDWORD32(program_read_dword_32be, ADDRESS_SPACE_PROGRAM) + READMASKED32(program_read_masked_32be, ADDRESS_SPACE_PROGRAM) + WRITEBYTE32BE(program_write_byte_32be, ADDRESS_SPACE_PROGRAM) + WRITEWORD32BE(program_write_word_32be, ADDRESS_SPACE_PROGRAM) + WRITEDWORD32(program_write_dword_32be, ADDRESS_SPACE_PROGRAM) + WRITEMASKED32(program_write_masked_32be,ADDRESS_SPACE_PROGRAM) + + READBYTE32LE(program_read_byte_32le, ADDRESS_SPACE_PROGRAM) + READWORD32LE(program_read_word_32le, ADDRESS_SPACE_PROGRAM) + READDWORD32(program_read_dword_32le, ADDRESS_SPACE_PROGRAM) + READMASKED32(program_read_masked_32le, ADDRESS_SPACE_PROGRAM) + WRITEBYTE32LE(program_write_byte_32le, ADDRESS_SPACE_PROGRAM) + WRITEWORD32LE(program_write_word_32le, ADDRESS_SPACE_PROGRAM) + WRITEDWORD32(program_write_dword_32le, ADDRESS_SPACE_PROGRAM) + WRITEMASKED32(program_write_masked_32le,ADDRESS_SPACE_PROGRAM) + + READBYTE64BE(program_read_byte_64be, ADDRESS_SPACE_PROGRAM) + READWORD64BE(program_read_word_64be, ADDRESS_SPACE_PROGRAM) + READDWORD64BE(program_read_dword_64be, ADDRESS_SPACE_PROGRAM) + READQWORD64(program_read_qword_64be, ADDRESS_SPACE_PROGRAM) + READMASKED64(program_read_masked_64be, ADDRESS_SPACE_PROGRAM) + WRITEBYTE64BE(program_write_byte_64be, ADDRESS_SPACE_PROGRAM) + WRITEWORD64BE(program_write_word_64be, ADDRESS_SPACE_PROGRAM) +WRITEDWORD64BE(program_write_dword_64be, ADDRESS_SPACE_PROGRAM) + WRITEQWORD64(program_write_qword_64be, ADDRESS_SPACE_PROGRAM) + WRITEMASKED64(program_write_masked_64be,ADDRESS_SPACE_PROGRAM) + + READBYTE64LE(program_read_byte_64le, ADDRESS_SPACE_PROGRAM) + READWORD64LE(program_read_word_64le, ADDRESS_SPACE_PROGRAM) + READDWORD64LE(program_read_dword_64le, ADDRESS_SPACE_PROGRAM) + READQWORD64(program_read_qword_64le, ADDRESS_SPACE_PROGRAM) + READMASKED64(program_read_masked_64le, ADDRESS_SPACE_PROGRAM) + WRITEBYTE64LE(program_write_byte_64le, ADDRESS_SPACE_PROGRAM) + WRITEWORD64LE(program_write_word_64le, ADDRESS_SPACE_PROGRAM) +WRITEDWORD64LE(program_write_dword_64le, ADDRESS_SPACE_PROGRAM) + WRITEQWORD64(program_write_qword_64le, ADDRESS_SPACE_PROGRAM) + WRITEMASKED64(program_write_masked_64le,ADDRESS_SPACE_PROGRAM) + + +/*------------------------------------------------- + Data memory handlers +-------------------------------------------------*/ + + READBYTE8(data_read_byte_8, ADDRESS_SPACE_DATA) + WRITEBYTE8(data_write_byte_8, ADDRESS_SPACE_DATA) + + READBYTE16BE(data_read_byte_16be, ADDRESS_SPACE_DATA) + READWORD16(data_read_word_16be, ADDRESS_SPACE_DATA) + WRITEBYTE16BE(data_write_byte_16be, ADDRESS_SPACE_DATA) + WRITEWORD16(data_write_word_16be, ADDRESS_SPACE_DATA) + + READBYTE16LE(data_read_byte_16le, ADDRESS_SPACE_DATA) + READWORD16(data_read_word_16le, ADDRESS_SPACE_DATA) + WRITEBYTE16LE(data_write_byte_16le, ADDRESS_SPACE_DATA) + WRITEWORD16(data_write_word_16le, ADDRESS_SPACE_DATA) + + READBYTE32BE(data_read_byte_32be, ADDRESS_SPACE_DATA) + READWORD32BE(data_read_word_32be, ADDRESS_SPACE_DATA) + READDWORD32(data_read_dword_32be, ADDRESS_SPACE_DATA) + READMASKED32(data_read_masked_32be, ADDRESS_SPACE_DATA) + WRITEBYTE32BE(data_write_byte_32be, ADDRESS_SPACE_DATA) + WRITEWORD32BE(data_write_word_32be, ADDRESS_SPACE_DATA) + WRITEDWORD32(data_write_dword_32be, ADDRESS_SPACE_DATA) + WRITEMASKED32(data_write_masked_32be,ADDRESS_SPACE_DATA) + + READBYTE32LE(data_read_byte_32le, ADDRESS_SPACE_DATA) + READWORD32LE(data_read_word_32le, ADDRESS_SPACE_DATA) + READDWORD32(data_read_dword_32le, ADDRESS_SPACE_DATA) + READMASKED32(data_read_masked_32le, ADDRESS_SPACE_DATA) + WRITEBYTE32LE(data_write_byte_32le, ADDRESS_SPACE_DATA) + WRITEWORD32LE(data_write_word_32le, ADDRESS_SPACE_DATA) + WRITEDWORD32(data_write_dword_32le, ADDRESS_SPACE_DATA) + WRITEMASKED32(data_write_masked_32le,ADDRESS_SPACE_DATA) + + READBYTE64BE(data_read_byte_64be, ADDRESS_SPACE_DATA) + READWORD64BE(data_read_word_64be, ADDRESS_SPACE_DATA) + READDWORD64BE(data_read_dword_64be, ADDRESS_SPACE_DATA) + READQWORD64(data_read_qword_64be, ADDRESS_SPACE_DATA) + READMASKED64(data_read_masked_64be, ADDRESS_SPACE_DATA) + WRITEBYTE64BE(data_write_byte_64be, ADDRESS_SPACE_DATA) + WRITEWORD64BE(data_write_word_64be, ADDRESS_SPACE_DATA) +WRITEDWORD64BE(data_write_dword_64be, ADDRESS_SPACE_DATA) + WRITEQWORD64(data_write_qword_64be, ADDRESS_SPACE_DATA) + WRITEMASKED64(data_write_masked_64be,ADDRESS_SPACE_DATA) + + READBYTE64LE(data_read_byte_64le, ADDRESS_SPACE_DATA) + READWORD64LE(data_read_word_64le, ADDRESS_SPACE_DATA) + READDWORD64LE(data_read_dword_64le, ADDRESS_SPACE_DATA) + READQWORD64(data_read_qword_64le, ADDRESS_SPACE_DATA) + READMASKED64(data_read_masked_64le, ADDRESS_SPACE_DATA) + WRITEBYTE64LE(data_write_byte_64le, ADDRESS_SPACE_DATA) + WRITEWORD64LE(data_write_word_64le, ADDRESS_SPACE_DATA) +WRITEDWORD64LE(data_write_dword_64le, ADDRESS_SPACE_DATA) + WRITEQWORD64(data_write_qword_64le, ADDRESS_SPACE_DATA) + WRITEMASKED64(data_write_masked_64le,ADDRESS_SPACE_DATA) + + +/*------------------------------------------------- + I/O memory handlers +-------------------------------------------------*/ + + READBYTE8(io_read_byte_8, ADDRESS_SPACE_IO) + WRITEBYTE8(io_write_byte_8, ADDRESS_SPACE_IO) + + READBYTE16BE(io_read_byte_16be, ADDRESS_SPACE_IO) + READWORD16(io_read_word_16be, ADDRESS_SPACE_IO) + WRITEBYTE16BE(io_write_byte_16be, ADDRESS_SPACE_IO) + WRITEWORD16(io_write_word_16be, ADDRESS_SPACE_IO) + + READBYTE16LE(io_read_byte_16le, ADDRESS_SPACE_IO) + READWORD16(io_read_word_16le, ADDRESS_SPACE_IO) + WRITEBYTE16LE(io_write_byte_16le, ADDRESS_SPACE_IO) + WRITEWORD16(io_write_word_16le, ADDRESS_SPACE_IO) + + READBYTE32BE(io_read_byte_32be, ADDRESS_SPACE_IO) + READWORD32BE(io_read_word_32be, ADDRESS_SPACE_IO) + READDWORD32(io_read_dword_32be, ADDRESS_SPACE_IO) + READMASKED32(io_read_masked_32be, ADDRESS_SPACE_IO) + WRITEBYTE32BE(io_write_byte_32be, ADDRESS_SPACE_IO) + WRITEWORD32BE(io_write_word_32be, ADDRESS_SPACE_IO) + WRITEDWORD32(io_write_dword_32be, ADDRESS_SPACE_IO) + WRITEMASKED32(io_write_masked_32be,ADDRESS_SPACE_IO) + + READBYTE32LE(io_read_byte_32le, ADDRESS_SPACE_IO) + READWORD32LE(io_read_word_32le, ADDRESS_SPACE_IO) + READDWORD32(io_read_dword_32le, ADDRESS_SPACE_IO) + READMASKED32(io_read_masked_32le, ADDRESS_SPACE_IO) + WRITEBYTE32LE(io_write_byte_32le, ADDRESS_SPACE_IO) + WRITEWORD32LE(io_write_word_32le, ADDRESS_SPACE_IO) + WRITEDWORD32(io_write_dword_32le, ADDRESS_SPACE_IO) + WRITEMASKED32(io_write_masked_32le,ADDRESS_SPACE_IO) + + READBYTE64BE(io_read_byte_64be, ADDRESS_SPACE_IO) + READWORD64BE(io_read_word_64be, ADDRESS_SPACE_IO) + READDWORD64BE(io_read_dword_64be, ADDRESS_SPACE_IO) + READQWORD64(io_read_qword_64be, ADDRESS_SPACE_IO) + READMASKED64(io_read_masked_64be, ADDRESS_SPACE_IO) + WRITEBYTE64BE(io_write_byte_64be, ADDRESS_SPACE_IO) + WRITEWORD64BE(io_write_word_64be, ADDRESS_SPACE_IO) +WRITEDWORD64BE(io_write_dword_64be, ADDRESS_SPACE_IO) + WRITEQWORD64(io_write_qword_64be, ADDRESS_SPACE_IO) + WRITEMASKED64(io_write_masked_64be,ADDRESS_SPACE_IO) + + READBYTE64LE(io_read_byte_64le, ADDRESS_SPACE_IO) + READWORD64LE(io_read_word_64le, ADDRESS_SPACE_IO) + READDWORD64LE(io_read_dword_64le, ADDRESS_SPACE_IO) + READQWORD64(io_read_qword_64le, ADDRESS_SPACE_IO) + READMASKED64(io_read_masked_64le, ADDRESS_SPACE_IO) + WRITEBYTE64LE(io_write_byte_64le, ADDRESS_SPACE_IO) + WRITEWORD64LE(io_write_word_64le, ADDRESS_SPACE_IO) +WRITEDWORD64LE(io_write_dword_64le, ADDRESS_SPACE_IO) + WRITEQWORD64(io_write_qword_64le, ADDRESS_SPACE_IO) + WRITEMASKED64(io_write_masked_64le,ADDRESS_SPACE_IO) + + +/*------------------------------------------------- + safe opcode reading +-------------------------------------------------*/ + +UINT8 cpu_readop_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop_unsafe(offset); +} + +UINT16 cpu_readop16_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop16_unsafe(offset); +} + +UINT32 cpu_readop32_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop32_unsafe(offset); +} + +UINT64 cpu_readop64_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop64_unsafe(offset); +} + +UINT8 cpu_readop_arg_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop_arg_unsafe(offset); +} + +UINT16 cpu_readop_arg16_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop_arg16_unsafe(offset); +} + +UINT32 cpu_readop_arg32_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop_arg32_unsafe(offset); +} + +UINT64 cpu_readop_arg64_safe(offs_t offset) +{ + activecpu_set_opbase(offset); + return cpu_readop_arg64_unsafe(offset); +} + + +/*------------------------------------------------- + unmapped memory handlers +-------------------------------------------------*/ + +static READ8_HANDLER( mrh8_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory byte read from %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset)); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; +} +static READ16_HANDLER( mrh16_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory word read from %08X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*2), mem_mask ^ 0xffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; +} +static READ32_HANDLER( mrh32_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory dword read from %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*4), mem_mask ^ 0xffffffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; +} +static READ64_HANDLER( mrh64_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory qword read from %08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*8), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; +} + +static WRITE8_HANDLER( mwh8_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory byte write to %08X = %02X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset), data); +} +static WRITE16_HANDLER( mwh16_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory word write to %08X = %04X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*2), data, mem_mask ^ 0xffff); +} +static WRITE32_HANDLER( mwh32_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*4), data, mem_mask ^ 0xffffffff); +} +static WRITE64_HANDLER( mwh64_unmap_program ) +{ + if (log_unmap[ADDRESS_SPACE_PROGRAM] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped program memory qword write to %08X = %08X%08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM], offset*8), (int)(data >> 32), (int)(data & 0xffffffff), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff); +} + +static READ8_HANDLER( mrh8_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory byte read from %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset)); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; +} +static READ16_HANDLER( mrh16_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory word read from %08X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*2), mem_mask ^ 0xffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; +} +static READ32_HANDLER( mrh32_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory dword read from %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*4), mem_mask ^ 0xffffffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; +} +static READ64_HANDLER( mrh64_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory qword read from %08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*8), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; +} + +static WRITE8_HANDLER( mwh8_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory byte write to %08X = %02X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset), data); +} +static WRITE16_HANDLER( mwh16_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory word write to %08X = %04X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*2), data, mem_mask ^ 0xffff); +} +static WRITE32_HANDLER( mwh32_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*4), data, mem_mask ^ 0xffffffff); +} +static WRITE64_HANDLER( mwh64_unmap_data ) +{ + if (log_unmap[ADDRESS_SPACE_DATA] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped data memory qword write to %08X = %08X%08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA], offset*8), (int)(data >> 32), (int)(data & 0xffffffff), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff); +} + +static READ8_HANDLER( mrh8_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O byte read from %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset)); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; +} +static READ16_HANDLER( mrh16_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O word read from %08X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*2), mem_mask ^ 0xffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; +} +static READ32_HANDLER( mrh32_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O dword read from %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*4), mem_mask ^ 0xffffffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; +} +static READ64_HANDLER( mrh64_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O qword read from %08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*8), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff); + return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; +} + +static WRITE8_HANDLER( mwh8_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O byte write to %08X = %02X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset), data); +} +static WRITE16_HANDLER( mwh16_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O word write to %08X = %04X & %04X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*2), data, mem_mask ^ 0xffff); +} +static WRITE32_HANDLER( mwh32_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*4), data, mem_mask ^ 0xffffffff); +} +static WRITE64_HANDLER( mwh64_unmap_io ) +{ + if (log_unmap[ADDRESS_SPACE_IO] && !debugger_access) logerror("cpu #%d (PC=%08X): unmapped I/O qword write to %08X = %08X%08X & %08X%08X\n", cpu_getactivecpu(), activecpu_get_pc(), INV_SPACE_SHIFT(&cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO], offset*8), (int)(data >> 32), (int)(data & 0xffffffff), (int)(mem_mask >> 32) ^ 0xffffffff, (int)(mem_mask & 0xffffffff) ^ 0xffffffff); +} + + +/*------------------------------------------------- + no-op memory handlers +-------------------------------------------------*/ + +static READ8_HANDLER( mrh8_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; } +static READ16_HANDLER( mrh16_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; } +static READ32_HANDLER( mrh32_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; } +static READ64_HANDLER( mrh64_nop_program ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_PROGRAM].unmap; } + +static READ8_HANDLER( mrh8_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; } +static READ16_HANDLER( mrh16_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; } +static READ32_HANDLER( mrh32_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; } +static READ64_HANDLER( mrh64_nop_data ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_DATA].unmap; } + +static READ8_HANDLER( mrh8_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; } +static READ16_HANDLER( mrh16_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; } +static READ32_HANDLER( mrh32_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; } +static READ64_HANDLER( mrh64_nop_io ) { return cpudata[cpu_getactivecpu()].space[ADDRESS_SPACE_IO].unmap; } + +static WRITE8_HANDLER( mwh8_nop ) { } +static WRITE16_HANDLER( mwh16_nop ) { } +static WRITE32_HANDLER( mwh32_nop ) { } +static WRITE64_HANDLER( mwh64_nop ) { } + + +/*------------------------------------------------- + get_static_handler - returns points to static + memory handlers +-------------------------------------------------*/ + +static genf *get_static_handler(int databits, int readorwrite, int spacenum, int which) +{ + static const struct + { + UINT8 databits; + UINT8 handlernum; + UINT8 spacenum; + genf * read; + genf * write; + } static_handler_list[] = + { + { 8, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh8_unmap_program, (genf *)mwh8_unmap_program }, + { 8, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh8_unmap_data, (genf *)mwh8_unmap_data }, + { 8, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh8_unmap_io, (genf *)mwh8_unmap_io }, + { 8, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh8_nop_program, (genf *)mwh8_nop }, + { 8, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh8_nop_data, (genf *)mwh8_nop }, + { 8, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh8_nop_io, (genf *)mwh8_nop }, + + { 16, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh16_unmap_program,(genf *)mwh16_unmap_program }, + { 16, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh16_unmap_data, (genf *)mwh16_unmap_data }, + { 16, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh16_unmap_io, (genf *)mwh16_unmap_io }, + { 16, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh16_nop_program, (genf *)mwh16_nop }, + { 16, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh16_nop_data, (genf *)mwh16_nop }, + { 16, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh16_nop_io, (genf *)mwh16_nop }, + + { 32, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh32_unmap_program,(genf *)mwh32_unmap_program }, + { 32, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh32_unmap_data, (genf *)mwh32_unmap_data }, + { 32, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh32_unmap_io, (genf *)mwh32_unmap_io }, + { 32, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh32_nop_program, (genf *)mwh32_nop }, + { 32, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh32_nop_data, (genf *)mwh32_nop }, + { 32, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh32_nop_io, (genf *)mwh32_nop }, + + { 64, STATIC_UNMAP, ADDRESS_SPACE_PROGRAM, (genf *)mrh64_unmap_program,(genf *)mwh64_unmap_program }, + { 64, STATIC_UNMAP, ADDRESS_SPACE_DATA, (genf *)mrh64_unmap_data, (genf *)mwh64_unmap_data }, + { 64, STATIC_UNMAP, ADDRESS_SPACE_IO, (genf *)mrh64_unmap_io, (genf *)mwh64_unmap_io }, + { 64, STATIC_NOP, ADDRESS_SPACE_PROGRAM, (genf *)mrh64_nop_program, (genf *)mwh64_nop }, + { 64, STATIC_NOP, ADDRESS_SPACE_DATA, (genf *)mrh64_nop_data, (genf *)mwh64_nop }, + { 64, STATIC_NOP, ADDRESS_SPACE_IO, (genf *)mrh64_nop_io, (genf *)mwh64_nop }, + }; + int tablenum; + + for (tablenum = 0; tablenum < sizeof(static_handler_list) / sizeof(static_handler_list[0]); tablenum++) + if (static_handler_list[tablenum].databits == databits && static_handler_list[tablenum].handlernum == which) + if (static_handler_list[tablenum].spacenum == 0xff || static_handler_list[tablenum].spacenum == spacenum) + return readorwrite ? static_handler_list[tablenum].write : static_handler_list[tablenum].read; + + return NULL; +} + + +/*------------------------------------------------- + debugging +-------------------------------------------------*/ + +static const char *handler_to_string(const table_data *table, UINT8 entry) +{ + static const char *strings[] = + { + "invalid", "bank 1", "bank 2", "bank 3", + "bank 4", "bank 5", "bank 6", "bank 7", + "bank 8", "bank 9", "bank 10", "bank 11", + "bank 12", "bank 13", "bank 14", "bank 15", + "bank 16", "bank 17", "bank 18", "bank 19", + "bank 20", "bank 21", "bank 22", "bank 23", + "bank 24", "bank 25", "bank 26", "bank 27", + "bank 28", "bank 29", "bank 30", "bank 31", + "bank 32", "ram[33]", "ram[34]", "ram[35]", + "ram[36]", "ram[37]", "ram[38]", "ram[39]", + "ram[40]", "ram[41]", "ram[42]", "ram[43]", + "ram[44]", "ram[45]", "ram[46]", "ram[47]", + "ram[48]", "ram[49]", "ram[50]", "ram[51]", + "ram[52]", "ram[53]", "ram[54]", "ram[55]", + "ram[56]", "ram[57]", "ram[58]", "ram[59]", + "ram[60]", "ram[61]", "ram[62]", "ram[63]", + "ram[64]", "ram[65]", "ram[66]", "ram[67]", + "ram[68]", "rom", "nop", "unmapped" + }; + + /* constant strings for lower entries */ + if (entry < STATIC_COUNT) + return strings[entry]; + else + return table->handlers[entry].name ? table->handlers[entry].name : "???"; +} + +static void dump_map(FILE *file, const addrspace_data *space, const table_data *table) +{ + int l1count = 1 << LEVEL1_BITS; + int l2count = 1 << LEVEL2_BITS; + UINT8 lastentry = STATIC_UNMAP; + int entrymatches = 0; + int i, j; + + /* dump generic information */ + fprintf(file, " Address bits = %d\n", space->abits); + fprintf(file, " Data bits = %d\n", space->dbits); + fprintf(file, " L1 bits = %d\n", LEVEL1_BITS); + fprintf(file, " L2 bits = %d\n", LEVEL2_BITS); + fprintf(file, " Address mask = %X\n", space->mask); + fprintf(file, "\n"); + + /* loop over level 1 entries */ + for (i = 0; i < l1count; i++) + { + UINT8 entry = table->table[i]; + + /* if this entry matches the previous one, just count it */ + if (entry < SUBTABLE_BASE && entry == lastentry) + { + entrymatches++; + continue; + } + + /* otherwise, print accumulated info */ + if (lastentry < SUBTABLE_BASE && lastentry != STATIC_UNMAP) + fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n", + (i - entrymatches) << LEVEL2_BITS, + (i << LEVEL2_BITS) - 1, + lastentry, + handler_to_string(table, lastentry), + table->handlers[lastentry].offset); + + /* start counting with this entry */ + lastentry = entry; + entrymatches = 1; + + /* if we're a subtable, we need to drill down */ + if (entry >= SUBTABLE_BASE) + { + UINT8 lastentry2 = STATIC_UNMAP; + int entry2matches = 0; + + /* loop over level 2 entries */ + entry -= SUBTABLE_BASE; + for (j = 0; j < l2count; j++) + { + UINT8 entry2 = table->table[(1 << LEVEL1_BITS) + (entry << LEVEL2_BITS) + j]; + + /* if this entry matches the previous one, just count it */ + if (entry2 < SUBTABLE_BASE && entry2 == lastentry2) + { + entry2matches++; + continue; + } + + /* otherwise, print accumulated info */ + if (lastentry2 < SUBTABLE_BASE && lastentry2 != STATIC_UNMAP) + fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n", + ((i << LEVEL2_BITS) | (j - entry2matches)), + ((i << LEVEL2_BITS) | (j - 1)), + lastentry2, + handler_to_string(table, lastentry2), + table->handlers[lastentry2].offset); + + /* start counting with this entry */ + lastentry2 = entry2; + entry2matches = 1; + } + + /* flush the last entry */ + if (lastentry2 < SUBTABLE_BASE && lastentry2 != STATIC_UNMAP) + fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n", + ((i << LEVEL2_BITS) | (j - entry2matches)), + ((i << LEVEL2_BITS) | (j - 1)), + lastentry2, + handler_to_string(table, lastentry2), + table->handlers[lastentry2].offset); + } + } + + /* flush the last entry */ + if (lastentry < SUBTABLE_BASE && lastentry != STATIC_UNMAP) + fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n", + (i - entrymatches) << LEVEL2_BITS, + (i << LEVEL2_BITS) - 1, + lastentry, + handler_to_string(table, lastentry), + table->handlers[lastentry].offset); +} + +void memory_dump(FILE *file) +{ + int cpunum, spacenum; + + /* skip if we can't open the file */ + if (!file) + return; + + /* loop over CPUs */ + for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum++) + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + if (cpudata[cpunum].space[spacenum].abits) + { + fprintf(file, "\n\n" + "=========================================\n" + "CPU %d address space %d read handler dump\n" + "=========================================\n", cpunum, spacenum); + dump_map(file, &cpudata[cpunum].space[spacenum], &cpudata[cpunum].space[spacenum].read); + + fprintf(file, "\n\n" + "==========================================\n" + "CPU %d address space %d write handler dump\n" + "==========================================\n", cpunum, spacenum); + dump_map(file, &cpudata[cpunum].space[spacenum], &cpudata[cpunum].space[spacenum].write); + } +} + + +/*------------------------------------------------- + memory_get_handler_string - return a string + describing the handler at a particular offset +-------------------------------------------------*/ + +const char *memory_get_handler_string(int read0_or_write1, int cpunum, int spacenum, offs_t offset) +{ + addrspace_data *space = &cpudata[cpunum].space[spacenum]; + const table_data *table = read0_or_write1 ? &space->write : &space->read; + UINT8 entry; + + /* perform the lookup */ + offset &= space->mask; + entry = table->table[LEVEL1_INDEX(offset)]; + if (entry >= SUBTABLE_BASE) + entry = table->table[LEVEL2_INDEX(entry, offset)]; + + /* 8-bit case: RAM/ROM */ + return handler_to_string(table, entry); +} |