summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/msx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/msx.c')
-rw-r--r--src/mess/machine/msx.c1184
1 files changed, 1184 insertions, 0 deletions
diff --git a/src/mess/machine/msx.c b/src/mess/machine/msx.c
new file mode 100644
index 00000000000..3b9a0ed6eea
--- /dev/null
+++ b/src/mess/machine/msx.c
@@ -0,0 +1,1184 @@
+/*
+ * msx.c: MSX emulation
+ *
+ * Copyright (C) 2004 Sean Young
+ *
+ * Todo:
+ *
+ * - fix mouse support
+ * - cassette support doesn't work
+ * - Ensure changing cartridge after boot works
+ * - wd2793, nms8255
+ */
+
+#include "includes/msx.h"
+
+#define VERBOSE 0
+
+static void msx_memory_init (running_machine &machine);
+static void msx_memory_set_carts (running_machine &machine);
+
+
+static int msx_probe_type (UINT8* pmem, int size)
+{
+ int kon4, kon5, asc8, asc16, i;
+
+ if (size <= 0x10000) return 0;
+
+ if ( (pmem[0x10] == 'Y') && (pmem[0x11] == 'Z') && (size > 0x18000) )
+ return 6;
+
+ kon4 = kon5 = asc8 = asc16 = 0;
+
+ for (i=0;i<size-3;i++)
+ {
+ if (pmem[i] == 0x32 && pmem[i+1] == 0)
+ {
+ switch (pmem[i+2])
+ {
+ case 0x60:
+ case 0x70:
+ asc16++;
+ asc8++;
+ break;
+ case 0x68:
+ case 0x78:
+ asc8++;
+ asc16--;
+ }
+
+ switch (pmem[i+2])
+ {
+ case 0x60:
+ case 0x80:
+ case 0xa0:
+ kon4++;
+ break;
+ case 0x50:
+ case 0x70:
+ case 0x90:
+ case 0xb0:
+ kon5++;
+ }
+ }
+ }
+
+ if (MAX (kon4, kon5) > MAX (asc8, asc16) )
+ return (kon5 > kon4) ? 2 : 3;
+ else
+ return (asc8 > asc16) ? 4 : 5;
+}
+
+DEVICE_IMAGE_LOAD (msx_cart)
+{
+ msx_state *state = image.device().machine().driver_data<msx_state>();
+ int size;
+ int size_aligned;
+ UINT8 *mem;
+ int type = -1;
+ const char *extra = NULL;
+ char *sramfile;
+ slot_state *st;
+ int id = -1;
+
+ if (strcmp(image.device().tag(),":cart1")==0)
+ id = 0;
+
+ if (strcmp(image.device().tag(),":cart2")==0)
+ id = 1;
+
+ if( id == -1 )
+ {
+ //logerror ("error: invalid cart tag '%s'\n", image->tag);
+ return IMAGE_INIT_FAIL;
+ }
+
+ if ( image.software_entry() != NULL )
+ {
+ /* Load software from software list */
+ /* TODO: Add proper SRAM (size) handling */
+
+ const char *mapper = software_part_get_feature( (software_part*)image.part_entry(), "mapper" );
+ const char *sram = software_part_get_feature( (software_part*)image.part_entry(), "sram" );
+
+ if ( mapper != NULL )
+ {
+ /* TODO: Split out the SRAM recognition code and 8KB/16KB bank configuration */
+ static const struct { const char *mapper_name; bool sram_present; int mapper_type; } mapper_types[] =
+ {
+ { "M60002-0125SP", false, SLOT_ASCII8 },
+ { "M60002-0125SP", true, SLOT_ASCII8_SRAM },
+ { "LZ93A13", false, SLOT_ASCII8 },
+ { "LZ93A13", true, SLOT_ASCII8_SRAM },
+ { "LZ93A13-16", false, SLOT_ASCII16 },
+ { "LZ93A13-16", true, SLOT_ASCII16_SRAM },
+ { "M60002-0125SP-16", false, SLOT_ASCII16 },
+ { "M60002-0125SP-16", true, SLOT_ASCII16_SRAM },
+ { "IREM TAM-S1", false, SLOT_RTYPE },
+ { "MR6401", false, SLOT_ASCII16 },
+ { "NEOS MR6401", false, SLOT_ASCII8 },
+ { "BS6202", false, SLOT_ASCII8 },
+ { "BS6101", false, SLOT_ASCII8 },
+ { "BS6101-16", false, SLOT_ASCII16 },
+ };
+
+ for ( int i = 0; i < ARRAY_LENGTH(mapper_types) && type < 0; i++ )
+ {
+ if ( !mame_stricmp( mapper, mapper_types[i].mapper_name ) )
+ {
+ if ( sram == NULL && ! mapper_types[i].sram_present )
+ type = mapper_types[i].mapper_type;
+
+
+ if ( sram != NULL && mapper_types[i].sram_present )
+ type = mapper_types[i].mapper_type;
+ }
+ }
+
+ if ( -1 == type )
+ logerror( "Mapper '%s' not recognized!\n", mapper );
+ }
+
+ UINT8 *rom_region = image.get_software_region( "rom" );
+ size = size_aligned = image.get_software_region_length( "rom" );
+
+ mem = auto_alloc_array( image.device().machine(), UINT8, size_aligned );
+ memcpy( mem, rom_region, size_aligned );
+ }
+ else
+ {
+ /* Old style image loading */
+
+ size = image.length ();
+ if (size < 0x2000)
+ {
+ logerror ("cart #%d: error: file is smaller than 2kb, too small to be true!\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* allocate memory and load */
+ size_aligned = 0x2000;
+ while (size_aligned < size)
+ size_aligned *= 2;
+
+ mem = auto_alloc_array(image.device().machine(),UINT8,size_aligned);
+ if (!mem)
+ {
+ logerror ("cart #%d: error: failed to allocate memory for cartridge\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (size < size_aligned)
+ memset (mem, 0xff, size_aligned);
+
+ if (image.fread(mem, size) != size)
+ {
+ logerror ("cart #%d: %s: can't read full %d bytes\n", id, image.filename (), size);
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* see if msx.crc will tell us more */
+ extra = hashfile_extrainfo(image);
+
+ if (!extra)
+ {
+ logerror("cart #%d: warning: no information in crc file\n", id);
+ type = -1;
+ }
+ else
+ if ((1 != sscanf(extra, "%d", &type) ) || type < 0 || type > SLOT_LAST_CARTRIDGE_TYPE)
+ {
+ logerror("cart #%d: warning: information in crc file not valid\n", id);
+ type = -1;
+ }
+ else
+ logerror ("cart #%d: info: cart extra info: '%s' = %s\n", id, extra, msx_slot_list[type].name);
+
+ /* if not, attempt autodetection */
+ if (type < 0)
+ {
+ type = msx_probe_type (mem, size);
+
+ if (mem[0] != 'A' || mem[1] != 'B')
+ logerror("cart #%d: %s: May not be a valid ROM file\n", id, image.filename ());
+
+ logerror("cart #%d: Probed cartridge mapper %d/%s\n", id, type, msx_slot_list[type].name);
+ }
+ }
+
+ /* mapper type 0 always needs 64kB */
+ if (!type && size_aligned != 0x10000)
+ {
+ UINT8 *old_mem = mem;
+ int old_size_aligned = size_aligned;
+
+ size_aligned = 0x10000;
+ mem = auto_alloc_array(image.device().machine(),UINT8, 0x10000);
+ if (!mem)
+ {
+ auto_free(image.device().machine(),old_mem);
+ logerror ("cart #%d: error: cannot allocate memory\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (size < 0x10000)
+ memset (mem + size, 0xff, 0x10000 - size);
+
+ if (size > 0x10000)
+ {
+ logerror ("cart #%d: warning: rom truncated to 64kb due to mapperless type (possibly detected)\n", id);
+
+ size = 0x10000;
+ }
+
+ /* Copy old contents to newly claimed memory */
+ memcpy(mem,old_mem,old_size_aligned);
+ auto_free(image.device().machine(),old_mem);
+ }
+
+ /* mapper type 0 (ROM) might need moving around a bit */
+ if (!type)
+ {
+ int i, page = 1;
+
+ /* find the correct page */
+ if (mem[0] == 'A' && mem[1] == 'B')
+ {
+ for (i=2; i<=8; i += 2)
+ {
+ if (mem[i] || mem[i+1])
+ {
+ page = mem[i+1] / 0x40;
+ break;
+ }
+ }
+ }
+
+ if (size <= 0x4000)
+ {
+ if (page == 1 || page == 2)
+ {
+ /* copy to the respective page */
+ memcpy (mem + (page * 0x4000), mem, 0x4000);
+ memset (mem, 0xff, 0x4000);
+ }
+ else
+ {
+ /* memory is repeated 4 times */
+ page = -1;
+ memcpy (mem + 0x4000, mem, 0x4000);
+ memcpy (mem + 0x8000, mem, 0x4000);
+ memcpy (mem + 0xc000, mem, 0x4000);
+ }
+ }
+ else /*if (size <= 0xc000) */
+ {
+ if (page)
+ {
+ /* shift up 16kB; custom memcpy so overlapping memory isn't corrupted. ROM starts in page 1 (0x4000) */
+ UINT8 *m;
+
+ page = 1;
+ i = 0xc000; m = mem + 0xffff;
+ while (i--)
+ {
+ *m = *(m - 0x4000);
+ m--;
+ }
+ memset (mem, 0xff, 0x4000);
+ }
+ }
+
+ if (page)
+ logerror ("cart #%d: info: rom in page %d\n", id, page);
+ else
+ logerror ("cart #%d: info: rom duplicted in all pages\n", id);
+ }
+
+ /* kludge */
+ if (type == 0)
+ type = SLOT_ROM;
+
+ /* allocate and set slot_state for this cartridge */
+ st = auto_alloc(image.device().machine(),slot_state);
+ if (!st)
+ {
+ logerror ("cart #%d: error: cannot allocate memory for cartridge state\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+ memset (st, 0, sizeof (slot_state));
+
+ st->m_type = type;
+ sramfile = auto_alloc_array(image.device().machine(), char, strlen (image.filename () + 1));
+
+ if (sramfile)
+ {
+ char *ext;
+
+ strcpy (sramfile, image.basename ());
+ ext = strrchr (sramfile, '.');
+ if (ext)
+ *ext = 0;
+
+ st->m_sramfile = sramfile;
+ }
+
+ if (msx_slot_list[type].init (image.device().machine(), st, 0, mem, size_aligned))
+ return IMAGE_INIT_FAIL;
+
+ if (msx_slot_list[type].loadsram)
+ msx_slot_list[type].loadsram (image.device().machine(), st);
+
+ state->m_cart_state[id] = st;
+ msx_memory_set_carts (image.device().machine());
+
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_UNLOAD (msx_cart)
+{
+ msx_state *state = image.device().machine().driver_data<msx_state>();
+ int id = -1;
+
+ if (strcmp(image.device().tag(),":cart1")==0)
+ id = 0;
+
+ if (strcmp(image.device().tag(),":cart2")==0)
+ id = 1;
+
+ if( id == -1 )
+ {
+ //logerror ("error: invalid cart tag '%s'\n", image->tag);
+ return;
+ }
+
+ if (msx_slot_list[state->m_cart_state[id]->m_type].savesram)
+ msx_slot_list[state->m_cart_state[id]->m_type].savesram (image.device().machine(), state->m_cart_state[id]);
+}
+
+void msx_vdp_interrupt(device_t *, v99x8_device &device, int i)
+{
+ cputag_set_input_line (device.machine(), "maincpu", 0, (i ? HOLD_LINE : CLEAR_LINE));
+}
+
+void msx_state::msx_ch_reset_core ()
+{
+ msx_memory_reset ();
+ msx_memory_map_all ();
+}
+
+MACHINE_START( msx )
+{
+ MACHINE_START_CALL( msx2 );
+}
+
+MACHINE_START( msx2 )
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ state->m_port_c_old = 0xff;
+ state->m_dsk_stat = 0x7f;
+}
+
+MACHINE_RESET( msx )
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ state->msx_ch_reset_core ();
+}
+
+MACHINE_RESET( msx2 )
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ state->msx_ch_reset_core ();
+}
+
+I8255_INTERFACE( msx_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(msx_state, msx_ppi_port_a_w),
+ DEVCB_DRIVER_MEMBER(msx_state, msx_ppi_port_b_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(msx_state, msx_ppi_port_c_w)
+};
+
+
+static const UINT8 cc_op[0x100] = {
+ 4+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1, 4+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 8+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,12+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1,10+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1, 7+1,11+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1,10+1,13+1, 6+1,11+1,11+1,10+1, 4+1, 7+1,11+1,13+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1, 7+1, 7+1, 7+1, 7+1, 7+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 5+1,10+1,10+1,10+1,10+1,11+1, 7+1,11+1, 5+1,10+1,10+1, 0+0,10+1,17+1, 7+1,11+1,
+ 5+1,10+1,10+1,11+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1,11+1,10+1, 0+0, 7+1,11+1,
+ 5+1,10+1,10+1,19+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1, 4+1,10+1, 0+0, 7+1,11+1,
+ 5+1,10+1,10+1, 4+1,10+1,11+1, 7+1,11+1, 5+1, 6+1,10+1, 4+1,10+1, 0+0, 7+1,11+1
+};
+
+static const UINT8 cc_cb[0x100] = {
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2
+};
+
+static const UINT8 cc_ed[0x100] = {
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
+16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2
+};
+
+static const UINT8 cc_xy[0x100] = {
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2,14+2,20+2,10+2, 9+2, 9+2,11+2, 4+2, 4+2,15+2,20+2,10+2, 9+2, 9+2,11+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2,23+2,23+2,19+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 9+2, 9+2, 9+2, 9+2, 9+2, 9+2,19+2, 9+2, 9+2, 9+2, 9+2, 9+2, 9+2, 9+2,19+2, 9+2,
+19+2,19+2,19+2,19+2,19+2,19+2, 4+2,19+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 0+0, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2,14+2, 4+2,23+2, 4+2,15+2, 4+2, 4+2, 4+2, 8+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,10+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2
+};
+
+static const UINT8 cc_xycb[0x100] = {
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2
+};
+
+/* extra cycles if jr/jp/call taken and 'interrupt latency' on rst 0-7 */
+static const UINT8 cc_ex[0x100] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DJNZ */
+ 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NZ/JR Z */
+ 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NC/JR C */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, /* LDIR/CPIR/INIR/OTIR LDDR/CPDR/INDR/OTDR */
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
+ 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2+1
+};
+
+
+DRIVER_INIT_MEMBER(msx_state,msx)
+{
+ device_set_input_line_vector (machine().device("maincpu"), 0, 0xff);
+
+ msx_memory_init (machine());
+
+ z80_set_cycle_tables( machine().device("maincpu"), cc_op, cc_cb, cc_ed, cc_xy, cc_xycb, cc_ex );
+}
+
+TIMER_DEVICE_CALLBACK( msx2_interrupt )
+{
+ msx_state *state = timer.machine().driver_data<msx_state>();
+ state->m_v9938->set_sprite_limit(timer.machine().root_device().ioport("DSW")->read() & 0x20);
+ state->m_v9938->set_resolution(timer.machine().root_device().ioport("DSW")->read() & 0x03);
+ state->m_v9938->interrupt();
+}
+
+INTERRUPT_GEN( msx_interrupt )
+{
+ msx_state *state = device->machine().driver_data<msx_state>();
+ int i;
+
+ for (i=0; i<2; i++)
+ {
+ state->m_mouse[i] = state->ioport(i ? "MOUSE1" : "MOUSE0")->read();
+ state->m_mouse_stat[i] = -1;
+ }
+}
+
+/*
+** The I/O functions
+*/
+
+
+READ8_MEMBER(msx_state::msx_psg_port_a_r)
+{
+ UINT8 data;
+
+ data = (m_cass->input() > 0.0038 ? 0x80 : 0);
+
+ if ( (m_psg_b ^ ioport("DSW")->read() ) & 0x40)
+ {
+ /* game port 2 */
+ UINT8 inp = ioport("JOY1")->read();
+ if ( !(inp & 0x80) )
+ {
+ /* joystick */
+ data |= ( inp & 0x7f );
+ }
+ else
+ {
+ /* mouse */
+ data |= ( inp & 0x70 );
+ if (m_mouse_stat[1] < 0)
+ data |= 0xf;
+ else
+ data |= ~(m_mouse[1] >> (4*m_mouse_stat[1]) ) & 15;
+ }
+ }
+ else
+ {
+ /* game port 1 */
+ UINT8 inp = ioport("JOY0")->read();
+ if ( !(inp & 0x80) )
+ {
+ /* joystick */
+ data |= ( inp & 0x7f );
+ }
+ else
+ {
+ /* mouse */
+ data |= ( inp & 0x70 );
+ if (m_mouse_stat[0] < 0)
+ data |= 0xf;
+ else
+ data |= ~(m_mouse[0] >> (4*m_mouse_stat[0]) ) & 15;
+ }
+ }
+
+ return data;
+}
+
+READ8_MEMBER(msx_state::msx_psg_port_b_r)
+{
+ return m_psg_b;
+}
+
+WRITE8_MEMBER(msx_state::msx_psg_port_a_w)
+{
+}
+
+WRITE8_MEMBER(msx_state::msx_psg_port_b_w)
+{
+ /* Arabic or kana mode led */
+ if ( (data ^ m_psg_b) & 0x80)
+ set_led_status (machine(), 2, !(data & 0x80) );
+
+ if ( (m_psg_b ^ data) & 0x10)
+ {
+ if (++m_mouse_stat[0] > 3) m_mouse_stat[0] = -1;
+ }
+ if ( (m_psg_b ^ data) & 0x20)
+ {
+ if (++m_mouse_stat[1] > 3) m_mouse_stat[1] = -1;
+ }
+
+ m_psg_b = data;
+}
+
+WRITE8_DEVICE_HANDLER( msx_printer_strobe_w )
+{
+ device->machine().device<centronics_device>("centronics")->strobe_w(BIT(data, 1));
+}
+
+WRITE8_DEVICE_HANDLER( msx_printer_data_w )
+{
+ if (device->machine().root_device().ioport("DSW")->read() & 0x80)
+ /* SIMPL emulation */
+ device->machine().device<dac_device>("dac")->write_signed8(data);
+ else
+ device->machine().device<centronics_device>("centronics")->write(*device->machine().memory().first_space(), 0, data);
+}
+
+READ8_DEVICE_HANDLER( msx_printer_status_r )
+{
+ UINT8 result = 0xfd;
+
+ if (device->machine().root_device().ioport("DSW")->read() & 0x80)
+ return 0xff;
+
+ result |= device->machine().device<centronics_device>("centronics")->busy_r() << 1;
+
+ return result;
+}
+
+WRITE8_MEMBER( msx_state::msx_fmpac_w )
+{
+ if (m_opll_active)
+ {
+ if (offset == 1)
+ ym2413_w (m_ym, 1, data);
+ else
+ ym2413_w (m_ym, 0, data);
+ }
+}
+
+/*
+** RTC functions
+*/
+
+WRITE8_MEMBER( msx_state::msx_rtc_latch_w )
+{
+ m_rtc_latch = data & 15;
+}
+
+WRITE8_MEMBER( msx_state::msx_rtc_reg_w )
+{
+ m_rtc->write(space, m_rtc_latch, data);
+}
+
+READ8_MEMBER( msx_state::msx_rtc_reg_r )
+{
+ return m_rtc->read(space, m_rtc_latch);
+}
+
+/*
+From: erbo@xs4all.nl (erik de boer)
+
+sony and philips have used (almost) the same design
+and this is the memory layout
+but it is not a msx standard !
+
+WD1793 or wd2793 registers
+
+address
+
+7FF8H read status register
+ write command register
+7FF9H r/w track register (r/o on NMS 8245 and Sony)
+7FFAH r/w sector register (r/o on NMS 8245 and Sony)
+7FFBH r/w data register
+
+
+hardware registers
+
+address
+
+7FFCH r/w bit 0 side select
+7FFDH r/w b7>M-on , b6>in-use , b1>ds1 , b0>ds0 (all neg. logic)
+7FFEH not used
+7FFFH read b7>drq , b6>intrq
+
+set on 7FFDH bit 2 always to 0 (some use it as disk change reset)
+
+*/
+
+WRITE_LINE_MEMBER( msx_state::msx_wd179x_intrq_w )
+{
+ if (state)
+ m_dsk_stat &= ~0x40;
+ else
+ m_dsk_stat |= 0x40;
+}
+
+WRITE_LINE_MEMBER( msx_state::msx_wd179x_drq_w )
+{
+ if (state)
+ m_dsk_stat &= ~0x80;
+ else
+ m_dsk_stat |= 0x80;
+}
+
+const wd17xx_interface msx_wd17xx_interface =
+{
+ DEVCB_LINE_VCC,
+ DEVCB_DRIVER_LINE_MEMBER(msx_state, msx_wd179x_intrq_w),
+ DEVCB_DRIVER_LINE_MEMBER(msx_state, msx_wd179x_drq_w),
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+LEGACY_FLOPPY_OPTIONS_START(msx)
+ LEGACY_FLOPPY_OPTION(msx, "dsk", "MSX SS", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([80])
+ SECTORS([9])
+ SECTOR_LENGTH([512])
+ FIRST_SECTOR_ID([1]))
+ LEGACY_FLOPPY_OPTION(msx, "dsk", "MSX DS", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([80])
+ SECTORS([9])
+ SECTOR_LENGTH([512])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+/*
+** The PPI functions
+*/
+
+WRITE8_MEMBER( msx_state::msx_ppi_port_a_w )
+{
+ m_primary_slot = data;
+
+ if (VERBOSE)
+ logerror ("write to primary slot select: %02x\n", m_primary_slot);
+ msx_memory_map_all ();
+}
+
+WRITE8_MEMBER( msx_state::msx_ppi_port_c_w )
+{
+ keylatch = data & 0x0f;
+
+ /* caps lock */
+ if ( BIT(m_port_c_old ^ data, 6) )
+ set_led_status (machine(), 1, !BIT(data, 6) );
+
+ /* key click */
+ if ( BIT(m_port_c_old ^ data, 7) )
+ m_dac->write_signed8(BIT(data, 7) ? 0x7f : 0);
+
+ /* cassette motor on/off */
+ if ( BIT(m_port_c_old ^ data, 4) )
+ m_cass->change_state(BIT(data, 4) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
+
+ /* cassette signal write */
+ if ( BIT(m_port_c_old ^ data, 5) )
+ m_cass->output(BIT(data, 5) ? -1.0 : 1.0);
+
+ m_port_c_old = data;
+}
+
+READ8_MEMBER( msx_state::msx_ppi_port_b_r )
+{
+ UINT8 result = 0xff;
+ int row, data;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5" };
+
+ row = keylatch;
+ if (row <= 10)
+ {
+ data = ioport(keynames[row / 2])->read();
+
+ if (BIT(row, 0))
+ data >>= 8;
+ result = data & 0xff;
+ }
+ return result;
+}
+
+/************************************************************************
+ *
+ * New memory emulation !!
+ *
+ ***********************************************************************/
+
+static void msx_memory_init (running_machine &machine)
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ int prim, sec, page, extent, option;
+ int size = 0;
+ const msx_slot_layout *layout= (msx_slot_layout*)NULL;
+ const msx_slot *slot;
+ const msx_driver_struct *driver;
+ slot_state *st;
+ UINT8 *mem = NULL;
+
+ state->m_empty = auto_alloc_array(machine, UINT8, 0x4000);
+ memset (state->m_empty, 0xff, 0x4000);
+
+ for (prim=0; prim<4; prim++) {
+ for (sec=0; sec<4; sec++) {
+ for (page=0; page<4; page++) {
+ state->m_all_state[prim][sec][page]= (slot_state*)NULL;
+ }
+ }
+ }
+
+ for (driver = msx_driver_list; driver->name[0]; driver++) {
+ if (!strcmp (driver->name, machine.system().name)) {
+ layout = driver->layout;
+ }
+ }
+
+ if (!layout) {
+ logerror ("msx_memory_init: error: missing layout definition in "
+ "msx_driver_list\n");
+ return;
+ }
+
+ state->layout = layout;
+
+ for (; layout->entry != MSX_LAYOUT_LAST; layout++) {
+
+ switch (layout->entry) {
+ case MSX_LAYOUT_SLOT_ENTRY:
+ prim = layout->slot_primary;
+ sec = layout->slot_secondary;
+ page = layout->slot_page;
+ extent = layout->page_extent;
+
+ if (layout->slot_secondary) {
+ state->m_slot_expanded[layout->slot_primary]= TRUE;
+ }
+
+ slot = &msx_slot_list[layout->type];
+ if (slot->slot_type != layout->type) {
+ logerror ("internal error: msx_slot_list[%d].type != %d\n",
+ slot->slot_type, slot->slot_type);
+ }
+
+ size = layout->size;
+ option = layout->option;
+
+ if (VERBOSE)
+ {
+ logerror ("slot %d/%d/%d-%d: type %s, size 0x%x\n",
+ prim, sec, page, page + extent - 1, slot->name, size);
+ }
+
+ st = (slot_state*)NULL;
+ if (layout->type == SLOT_CARTRIDGE1) {
+ st = state->m_cart_state[0];
+ if (!st) {
+ slot = &msx_slot_list[SLOT_SOUNDCARTRIDGE];
+ size = 0x20000;
+ }
+ }
+ if (layout->type == SLOT_CARTRIDGE2) {
+ st = state->m_cart_state[1];
+ if (!st) {
+ /* Check whether the optional FM-PAC rom is present */
+ option = 0x10000;
+ size = 0x10000;
+ mem = machine.root_device().memregion("maincpu")->base() + option;
+ if (machine.root_device().memregion("maincpu")->bytes() >= size + option && mem[0] == 'A' && mem[1] == 'B') {
+ slot = &msx_slot_list[SLOT_FMPAC];
+ }
+ else {
+ slot = &msx_slot_list[SLOT_EMPTY];
+ }
+ }
+ }
+
+ if (!st) {
+ switch (slot->mem_type) {
+
+ case MSX_MEM_HANDLER:
+ case MSX_MEM_ROM:
+ mem = machine.root_device().memregion("maincpu")->base() + option;
+ break;
+ case MSX_MEM_RAM:
+ mem = NULL;
+ break;
+ }
+ st = auto_alloc_clear (machine, slot_state);
+ memset (st, 0, sizeof (slot_state));
+
+ if (slot->init (machine, st, layout->slot_page, mem, size)) {
+ continue;
+ }
+ }
+
+ while (extent--) {
+ if (page > 3) {
+ logerror ("internal error: msx_slot_layout wrong, "
+ "page + extent > 3\n");
+ break;
+ }
+ state->m_all_state[prim][sec][page] = st;
+ page++;
+ }
+ break;
+ case MSX_LAYOUT_KANJI_ENTRY:
+ state->m_kanji_mem = machine.root_device().memregion("maincpu")->base() + layout->option;
+ break;
+ case MSX_LAYOUT_RAMIO_SET_BITS_ENTRY:
+ state->m_ramio_set_bits = (UINT8)layout->option;
+ break;
+ }
+ }
+}
+
+void msx_state::msx_memory_reset ()
+{
+ slot_state *st, *last_st = (slot_state*)NULL;
+ int prim, sec, page;
+
+ m_primary_slot = 0;
+
+ for (prim=0; prim<4; prim++)
+ {
+ m_secondary_slot[prim] = 0;
+ for (sec=0; sec<4; sec++)
+ {
+ for (page=0; page<4; page++)
+ {
+ st = m_all_state[prim][sec][page];
+ if (st && st != last_st)
+ msx_slot_list[st->m_type].reset (machine(), st);
+ last_st = st;
+ }
+ }
+ }
+}
+
+static void msx_memory_set_carts (running_machine &machine)
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ const msx_slot_layout *layout;
+ int page;
+
+ if (!state->layout)
+ return;
+
+ for (layout = state->layout; layout->entry != MSX_LAYOUT_LAST; layout++)
+ {
+ if (layout->entry == MSX_LAYOUT_SLOT_ENTRY)
+ {
+ switch (layout->type)
+ {
+ case SLOT_CARTRIDGE1:
+ for (page=0; page<4; page++)
+ state->m_all_state[layout->slot_primary][layout->slot_secondary][page]
+ = state->m_cart_state[0];
+ break;
+ case SLOT_CARTRIDGE2:
+ for (page=0; page<4; page++)
+ state->m_all_state[layout->slot_primary][layout->slot_secondary][page]
+ = state->m_cart_state[1];
+ break;
+ }
+ }
+ }
+}
+
+void msx_state::msx_memory_map_page (UINT8 page)
+{
+ int slot_primary;
+ int slot_secondary;
+ slot_state *st;
+ const msx_slot *slot;
+
+ slot_primary = (m_primary_slot >> (page * 2)) & 3;
+ slot_secondary = (m_secondary_slot[slot_primary] >> (page * 2)) & 3;
+
+ st = m_all_state[slot_primary][slot_secondary][page];
+ slot = st ? &msx_slot_list[st->m_type] : &msx_slot_list[SLOT_EMPTY];
+ m_state[page] = st;
+ m_slot[page] = slot;
+
+ if (VERBOSE)
+ logerror ("mapping %s in %d/%d/%d\n", slot->name, slot_primary, slot_secondary, page);
+
+ slot->map (machine(), st, page);
+}
+
+void msx_state::msx_memory_map_all ()
+{
+ for (UINT8 i=0; i<4; i++)
+ msx_memory_map_page (i);
+}
+
+WRITE8_MEMBER( msx_state::msx_page0_w )
+{
+ if ( offset == 0 )
+ {
+ m_superloadrunner_bank = data;
+ if (m_slot[2]->slot_type == SLOT_SUPERLOADRUNNER)
+ m_slot[2]->map (machine(), m_state[2], 2);
+ }
+
+ switch (m_slot[0]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[0][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[0]->write (machine(), m_state[0], offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page0_1_w )
+{
+ msx_page0_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page1_w )
+{
+ switch (m_slot[1]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[1][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[1]->write (machine(), m_state[1], 0x4000 + offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page1_1_w )
+{
+ msx_page1_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page1_2_w )
+{
+ msx_page1_w( space, 0x3ff8 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_w )
+{
+ switch (m_slot[2]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[2][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[2]->write (machine(), m_state[2], 0x8000 + offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_1_w )
+{
+ msx_page2_w( space, 0x1800 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_2_w )
+{
+ msx_page2_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_3_w )
+{
+ msx_page2_w( space, 0x3800 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page3_w )
+{
+ switch (m_slot[3]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[3][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[3]->write (machine(), m_state[3], 0xc000 + offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page3_1_w )
+{
+ msx_page3_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_sec_slot_w )
+{
+ int slot = m_primary_slot >> 6;
+ if (m_slot_expanded[slot])
+ {
+ if (VERBOSE)
+ logerror ("write to secondary slot %d select: %02x\n", slot, data);
+
+ m_secondary_slot[slot] = data;
+ msx_memory_map_all ();
+ }
+ else
+ msx_page3_w(space, 0x3fff, data);
+}
+
+READ8_MEMBER( msx_state::msx_sec_slot_r )
+{
+ UINT8 result;
+ int slot = m_primary_slot >> 6;
+
+ if (m_slot_expanded[slot])
+ result = ~m_secondary_slot[slot];
+ else
+ result = m_top_page[0x1fff];
+
+ return result;
+}
+
+WRITE8_MEMBER( msx_state::msx_ram_mapper_w )
+{
+ m_ram_mapper[offset] = data;
+ if (m_slot[offset]->slot_type == SLOT_RAM_MM)
+ m_slot[offset]->map (machine(), m_state[offset], offset);
+}
+
+READ8_MEMBER( msx_state::msx_ram_mapper_r )
+{
+ return m_ram_mapper[offset] | m_ramio_set_bits;
+}
+
+WRITE8_MEMBER( msx_state::msx_90in1_w )
+{
+ m_korean90in1_bank = data;
+ if (m_slot[1]->slot_type == SLOT_KOREAN_90IN1)
+ m_slot[1]->map (machine(), m_state[1], 1);
+
+ if (m_slot[2]->slot_type == SLOT_KOREAN_90IN1)
+ m_slot[2]->map (machine(), m_state[2], 2);
+}
+
+READ8_MEMBER( msx_state::msx_kanji_r )
+{
+ UINT8 result = 0xff;
+
+ if (offset && m_kanji_mem)
+ {
+ int latch = m_kanji_latch;
+ result = m_kanji_mem[latch++];
+
+ m_kanji_latch &= ~0x1f;
+ m_kanji_latch |= latch & 0x1f;
+ }
+ return result;
+}
+
+WRITE8_MEMBER( msx_state::msx_kanji_w )
+{
+ if (offset)
+ m_kanji_latch = (m_kanji_latch & 0x007E0) | ((data & 0x3f) << 11);
+ else
+ m_kanji_latch = (m_kanji_latch & 0x1f800) | ((data & 0x3f) << 5);
+}