From 0b68bd6ab9921b07168ccabc9c39ef8b376e3ead Mon Sep 17 00:00:00 2001 From: Ryan Holtz Date: Sat, 19 Sep 2009 21:10:59 +0000 Subject: [PATCH] Ported SPC7110 support from bsnes. [Harmony] Ported ST010 support from bsnes. [Fabio Priuli] --- .gitattributes | 2 + src/mame/machine/snes.c | 87 ++- src/mame/machine/snes7110.c | 1393 +++++++++++++++++++++++++++++++++++ src/mame/machine/snesst10.c | 529 +++++++++++++ src/mame/mame.mak | 4 +- 5 files changed, 2006 insertions(+), 9 deletions(-) create mode 100644 src/mame/machine/snes7110.c create mode 100644 src/mame/machine/snesst10.c diff --git a/.gitattributes b/.gitattributes index 78f27ed7b7d..6f46d96887d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2890,6 +2890,7 @@ src/mame/machine/slapfght.c svneol=native#text/plain src/mame/machine/slapstic.c svneol=native#text/plain src/mame/machine/slikshot.c svneol=native#text/plain src/mame/machine/snes.c svneol=native#text/plain +src/mame/machine/snes7110.c svneol=native#text/plain src/mame/machine/snescx4.c svneol=native#text/plain src/mame/machine/snescx4.h svneol=native#text/plain src/mame/machine/snesdsp1.c svneol=native#text/plain @@ -2900,6 +2901,7 @@ src/mame/machine/snesdsp4.h svneol=native#text/plain src/mame/machine/snesobc1.c svneol=native#text/plain src/mame/machine/snesrtc.c svneol=native#text/plain src/mame/machine/snessdd1.c svneol=native#text/plain +src/mame/machine/snesst10.c svneol=native#text/plain src/mame/machine/spisprit.c svneol=native#text/plain src/mame/machine/starwars.c svneol=native#text/plain src/mame/machine/steppers.c svneol=native#text/plain diff --git a/src/mame/machine/snes.c b/src/mame/machine/snes.c index 0655dfd2e85..d9c127e9e5e 100644 --- a/src/mame/machine/snes.c +++ b/src/mame/machine/snes.c @@ -6,6 +6,7 @@ R. Belmont Anthony Kruize + Harmony Based on the original code by Lee Hammerton (aka Savoury Snax) Thanks to Anomie for invaluable technical information. Thanks to byuu for invaluable technical information. @@ -38,6 +39,7 @@ static emu_timer *snes_hirq_timer; static UINT16 hblank_offset; UINT16 snes_htmult; /* in 512 wide, we run HTOTAL double and halve it on latching */ UINT8 snes_has_addon_chip; +UINT32 snes_rom_size; // full graphic variables static UINT16 vram_fgr_high, vram_fgr_increment, vram_fgr_count, vram_fgr_mask, vram_fgr_shift, vram_read_buffer; @@ -64,6 +66,8 @@ static struct #include "machine/snescx4.c" #include "machine/snesrtc.c" #include "machine/snessdd1.c" +#include "machine/snes7110.c" +#include "machine/snesst10.c" /************************************* @@ -379,6 +383,14 @@ READ8_HANDLER( snes_r_io ) offset += 0x4300; } } + else if(snes_has_addon_chip == HAS_SPC7110 || snes_has_addon_chip == HAS_SPC7110_RTC) + { + UINT16 limit = (snes_has_addon_chip == HAS_SPC7110_RTC) ? 0x4842 : 0x483f; + if(offset >= 0x4800 && offset < limit) + { + return spc7110_mmio_read(space->machine, offset); + } + } /* offset is from 0x000000 */ switch( offset ) @@ -750,6 +762,15 @@ WRITE8_HANDLER( snes_w_io ) offset += 0x4300; } } + else if(snes_has_addon_chip == HAS_SPC7110 || snes_has_addon_chip == HAS_SPC7110_RTC) + { + UINT16 limit = (snes_has_addon_chip == HAS_SPC7110_RTC) ? 0x4842 : 0x483f; + if(offset >= 0x4800 && offset < limit) + { + spc7110_mmio_write(space->machine, (UINT32)offset, data); + return; + } + } /* offset is from 0x000000 */ switch( offset ) @@ -1470,6 +1491,10 @@ READ8_HANDLER( snes_r_bank1 ) value = (address < 0x7000) ? DSP1_getDr() : DSP1_getSr(); else if (snes_has_addon_chip == HAS_CX4) value = CX4_read(address - 0x6000); + else if (snes_has_addon_chip == HAS_SPC7110 || snes_has_addon_chip == HAS_SPC7110_RTC) + { + value = snes_ram[0x306000 + (offset & 0x1fff)]; + } else { logerror( "snes_r_bank1: Unmapped external chip read: %04x\n", address ); @@ -1504,6 +1529,10 @@ READ8_HANDLER( snes_r_bank2 ) value = obc1_read (space, offset); else if (snes_has_addon_chip == HAS_DSP2) value = (address < 0x7000) ? DSP2_read() : 0x00; + else if (snes_has_addon_chip == HAS_SPC7110 || snes_has_addon_chip == HAS_SPC7110_RTC) + { + value = snes_ram[0x306000 + (offset & 0x1fff)]; + } else if ((snes_cart.mode == SNES_MODE_21) && (snes_cart.sram > 0)) { int mask = ((snes_cart.sram * 1024) - 1); /* Limit SRAM size to what's actually present */ @@ -1565,6 +1594,10 @@ READ8_HANDLER( snes_r_bank4 ) { value = snes_ram[0x600000 + offset]; } + else if (snes_has_addon_chip == HAS_ST010 && offset >= 0x80000 && address < 0x1000) + { + value = st010_read(address); + } else if (snes_cart.mode & 5) /* Mode 20 & 22 */ { if (address >= 0x8000) @@ -1627,6 +1660,10 @@ READ8_HANDLER( snes_r_bank6 ) logerror( "snes_r_bank6 hit in Super FX mode, please fix me\n" ); else if (snes_cart.mode != SNES_MODE_25) value = memory_read_byte(space, offset); + else if (snes_has_addon_chip == HAS_CX4) + { + //printf( "R: CX4 hit from 0x800000\n" ); + } else /* Mode 25 has SRAM not mirrored from lower banks */ { if (address < 0x6000) @@ -1672,6 +1709,10 @@ READ8_HANDLER( snes_r_bank7 ) { logerror( "snes_r_bank7 hit in Super FX mode, please fix me\n" ); } + else if (snes_has_addon_chip == HAS_ST010 && offset >= 0x280000 && offset < 0x300000 && address < 0x1000) + { + value = st010_read(address); + } else if (snes_cart.mode & 5) /* Mode 20 & 22 */ { if (address < 0x8000) @@ -1709,6 +1750,10 @@ WRITE8_HANDLER( snes_w_bank1 ) DSP1_setDr(data); else if (snes_has_addon_chip == HAS_CX4) CX4_write(space->machine, address - 0x6000, data); + else if (snes_has_addon_chip == HAS_SPC7110 || snes_has_addon_chip == HAS_SPC7110_RTC) + { + snes_ram[0x306000 + (offset & 0x1fff)] = data; + } else logerror( "snes_w_bank1: Attempt to write to reserved address: %x = %02x\n", offset, data ); } @@ -1737,6 +1782,10 @@ WRITE8_HANDLER( snes_w_bank2 ) obc1_write(space, offset, data); else if (snes_has_addon_chip == HAS_DSP2) DSP2_write(data); + else if (snes_has_addon_chip == HAS_SPC7110 || snes_has_addon_chip == HAS_SPC7110_RTC) + { + snes_ram[0x306000 + (offset & 0x1fff)] = data; + } else if ((snes_cart.mode == SNES_MODE_21) && (snes_cart.sram > 0)) { int mask = ((snes_cart.sram * 1024) - 1); /* Limit SRAM size to what's actually present */ @@ -1767,9 +1816,12 @@ WRITE8_HANDLER( snes_w_bank4 ) if (snes_has_addon_chip == HAS_SUPERFX && cputag_get_cpu(space->machine, "superfx") != NULL) { - //printf( "Writing %02x to %08x\n", data, 0x600000 + offset ); snes_ram[0x600000 + offset] = data; } + else if (snes_has_addon_chip == HAS_ST010 && offset >= 0x80000 && address < 0x1000) + { + st010_write(address, data); + } else if (snes_cart.mode & 5) /* Mode 20 & 22 */ { if (address >= 0x8000) @@ -1830,6 +1882,10 @@ WRITE8_HANDLER( snes_w_bank6 ) { logerror( "snes_w_bank6 hit (RAM) in Super FX mode, please fix me\n" ); } + else if(snes_has_addon_chip == HAS_CX4) + { + //printf( "R: CX4 hit from 0x800000\n" ); + } if (snes_cart.mode != SNES_MODE_25) { if (offset < 0x300000) @@ -1887,6 +1943,10 @@ WRITE8_HANDLER( snes_w_bank7 ) logerror( "snes_w_bank7 hit (RAM) in Super FX mode, please fix me\n" ); } } + else if (snes_has_addon_chip == HAS_ST010 && offset >= 0x280000 && offset < 0x300000 && address < 0x1000) + { + st010_write(address, data); + } else if (snes_cart.mode & 5) /* Mode 20 & 22 */ { if (address < 0x8000) @@ -1993,10 +2053,22 @@ static void snes_init_ram(running_machine *machine) InitDSP4(); break; + case HAS_RTC: + srtc_reset(machine); + break; + + case HAS_SDD1: + sdd1_reset(machine); + break; + case HAS_OBC1: obc1_init(); break; + case HAS_ST010: + st010_reset(); + break; + default: break; } @@ -2059,6 +2131,8 @@ MACHINE_START( snes ) snes_ram[WRDIVH] = 0xff; sdd1_init(machine); + spc7110_init(machine); + st010_init(machine); } MACHINE_RESET( snes ) @@ -2081,9 +2155,6 @@ MACHINE_RESET( snes ) snes_htmult = 1; snes_ppu.interlace = 1; snes_ppu.obj_interlace = 1; - - srtc_reset(machine); - sdd1_reset(machine); } @@ -2095,8 +2166,8 @@ DRIVER_INIT( snes ) UINT8 *rom; rom = memory_region(machine, "user3"); - snes_ram = auto_alloc_array(machine, UINT8, 0x1000000); - memset(snes_ram, 0, 0x1000000); + snes_ram = auto_alloc_array(machine, UINT8, 0x1400000); + memset(snes_ram, 0, 0x1400000); /* all NSS games seem to use MODE 20 */ snes_cart.mode = SNES_MODE_20; @@ -2161,8 +2232,8 @@ DRIVER_INIT( snes_hirom ) UINT8 *rom; rom = memory_region(machine, "user3"); - snes_ram = auto_alloc_array(machine, UINT8, 0x1000000); - memset(snes_ram, 0, 0x1000000); + snes_ram = auto_alloc_array(machine, UINT8, 0x1400000); + memset(snes_ram, 0, 0x1400000); snes_cart.mode = SNES_MODE_21; snes_cart.sram_max = 0x40000; diff --git a/src/mame/machine/snes7110.c b/src/mame/machine/snes7110.c new file mode 100644 index 00000000000..9e0dcadf830 --- /dev/null +++ b/src/mame/machine/snes7110.c @@ -0,0 +1,1393 @@ +static const UINT32 spc7110_decomp_buffer_size = 64; + +static const UINT8 spc7110_evolution_table[53][4] = +{ + { 0x5a, 1, 1, 1 }, + { 0x25, 6, 2, 0 }, + { 0x11, 8, 3, 0 }, + { 0x08, 10, 4, 0 }, + { 0x03, 12, 5, 0 }, + { 0x01, 15, 5, 0 }, + + { 0x5a, 7, 7, 1 }, + { 0x3f, 19, 8, 0 }, + { 0x2c, 21, 9, 0 }, + { 0x20, 22, 10, 0 }, + { 0x17, 23, 11, 0 }, + { 0x11, 25, 12, 0 }, + { 0x0c, 26, 13, 0 }, + { 0x09, 28, 14, 0 }, + { 0x07, 29, 15, 0 }, + { 0x05, 31, 16, 0 }, + { 0x04, 32, 17, 0 }, + { 0x03, 34, 18, 0 }, + { 0x02, 35, 5, 0 }, + + { 0x5a, 20, 20, 1 }, + { 0x48, 39, 21, 0 }, + { 0x3a, 40, 22, 0 }, + { 0x2e, 42, 23, 0 }, + { 0x26, 44, 24, 0 }, + { 0x1f, 45, 25, 0 }, + { 0x19, 46, 26, 0 }, + { 0x15, 25, 27, 0 }, + { 0x11, 26, 28, 0 }, + { 0x0e, 26, 29, 0 }, + { 0x0b, 27, 30, 0 }, + { 0x09, 28, 31, 0 }, + { 0x08, 29, 32, 0 }, + { 0x07, 30, 33, 0 }, + { 0x05, 31, 34, 0 }, + { 0x04, 33, 35, 0 }, + { 0x04, 33, 36, 0 }, + { 0x03, 34, 37, 0 }, + { 0x02, 35, 38, 0 }, + { 0x02, 36, 5, 0 }, + + { 0x58, 39, 40, 1 }, + { 0x4d, 47, 41, 0 }, + { 0x43, 48, 42, 0 }, + { 0x3b, 49, 43, 0 }, + { 0x34, 50, 44, 0 }, + { 0x2e, 51, 45, 0 }, + { 0x29, 44, 46, 0 }, + { 0x25, 45, 24, 0 }, + + { 0x56, 47, 48, 1 }, + { 0x4f, 47, 49, 0 }, + { 0x47, 48, 50, 0 }, + { 0x41, 49, 51, 0 }, + { 0x3c, 50, 52, 0 }, + { 0x37, 51, 43, 0 }, +}; + +static const UINT8 spc7110_mode2_context_table[32][2] = +{ + { 1, 2 }, + + { 3, 8 }, + { 13, 14 }, + + { 15, 16 }, + { 17, 18 }, + { 19, 20 }, + { 21, 22 }, + { 23, 24 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 27, 28 }, + { 29, 30 }, + + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + + { 31, 31 }, +}; + +typedef struct +{ + running_machine *machine; + + UINT32 decomp_mode; + UINT32 decomp_offset; + + UINT8 *decomp_buffer; + UINT32 decomp_buffer_rdoffset; + UINT32 decomp_buffer_wroffset; + UINT32 decomp_buffer_length; + + struct ContextState + { + UINT8 index; + UINT8 invert; + } context[32]; + + UINT32 morton16[2][256]; + UINT32 morton32[4][256]; +} SPC7110Decomp; + +static SPC7110Decomp* SPC7110Decomp_ctor(running_machine *machine); +static void SPC7110Decomp_reset(SPC7110Decomp *thisptr); +static void SPC7110Decomp_init(SPC7110Decomp *thisptr, running_machine *machine, UINT32 mode, UINT32 offset, UINT32 index); +static UINT8 SPC7110Decomp_read(SPC7110Decomp *thisptr); +static void SPC7110Decomp_write(SPC7110Decomp *thisptr, UINT8 data); +static UINT8 SPC7110Decomp_dataread(SPC7110Decomp *thisptr); +static void SPC7110Decomp_mode0(SPC7110Decomp *thisptr, UINT8 init); +static void SPC7110Decomp_mode1(SPC7110Decomp *thisptr, UINT8 init); +static void SPC7110Decomp_mode2(SPC7110Decomp *thisptr, UINT8 init); +static UINT8 SPC7110Decomp_probability(SPC7110Decomp *thisptr, UINT32 n); +static UINT8 SPC7110Decomp_next_lps(SPC7110Decomp *thisptr, UINT32 n); +static UINT8 SPC7110Decomp_next_mps(SPC7110Decomp *thisptr, UINT32 n); +static UINT8 SPC7110Decomp_toggle_invert(SPC7110Decomp *thisptr, UINT32 n); +static UINT32 SPC7110Decomp_morton_2x8(SPC7110Decomp *thisptr, UINT32 data); +static UINT32 SPC7110Decomp_morton_4x8(SPC7110Decomp *thisptr, UINT32 data); + +static SPC7110Decomp* SPC7110Decomp_ctor(running_machine *machine) +{ + UINT32 i; + SPC7110Decomp* newclass = (SPC7110Decomp*)auto_alloc_array(machine, UINT8, sizeof(SPC7110Decomp)); + newclass->decomp_buffer = (UINT8*)auto_alloc_array(machine, UINT8, spc7110_decomp_buffer_size); + SPC7110Decomp_reset(newclass); + + for(i = 0; i < 256; i++) + { + #define map(x, y) (((i >> x) & 1) << y) + //2x8-bit + newclass->morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6) + + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4); + newclass->morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2) + + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0); + //4x8-bit + newclass->morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7) + + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6); + newclass->morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5) + + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4); + newclass->morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3) + + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2); + newclass->morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1) + + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0); + #undef map + } + + return newclass; +} + +static void SPC7110Decomp_reset(SPC7110Decomp *thisptr) +{ + //mode 3 is invalid; this is treated as a special case to always return 0x00 + //set to mode 3 so that reading decomp port before starting first decomp will return 0x00 + thisptr->decomp_mode = 3; + + thisptr->decomp_buffer_rdoffset = 0; + thisptr->decomp_buffer_wroffset = 0; + thisptr->decomp_buffer_length = 0; +} + +static void SPC7110Decomp_init(SPC7110Decomp *thisptr, running_machine *machine, UINT32 mode, UINT32 offset, UINT32 index) +{ + UINT32 i; + + thisptr->machine = machine; + + thisptr->decomp_mode = mode; + thisptr->decomp_offset = offset; + + thisptr->decomp_buffer_rdoffset = 0; + thisptr->decomp_buffer_wroffset = 0; + thisptr->decomp_buffer_length = 0; + + //reset context states + for(i = 0; i < 32; i++) + { + thisptr->context[i].index = 0; + thisptr->context[i].invert = 0; + } + + switch(thisptr->decomp_mode) + { + case 0: SPC7110Decomp_mode0(thisptr, 1); break; + case 1: SPC7110Decomp_mode1(thisptr, 1); break; + case 2: SPC7110Decomp_mode2(thisptr, 1); break; + } + + //decompress up to requested output data index + while(index--) + { + SPC7110Decomp_read(thisptr); + } +} + +static UINT8 SPC7110Decomp_read(SPC7110Decomp *thisptr) +{ + UINT8 data; + + if(thisptr->decomp_buffer_length == 0) { + //decompress at least (spc7110_decomp_buffer_size / 2) bytes to the buffer + switch(thisptr->decomp_mode) { + case 0: + SPC7110Decomp_mode0(thisptr, 0); + break; + + case 1: + SPC7110Decomp_mode1(thisptr, 0); + break; + + case 2: + SPC7110Decomp_mode2(thisptr, 0); + break; + + default: + return 0x00; + } + } + + data = thisptr->decomp_buffer[thisptr->decomp_buffer_rdoffset++]; + thisptr->decomp_buffer_rdoffset &= spc7110_decomp_buffer_size - 1; + thisptr->decomp_buffer_length--; + return data; +} + +static void SPC7110Decomp_write(SPC7110Decomp *thisptr, UINT8 data) +{ + thisptr->decomp_buffer[thisptr->decomp_buffer_wroffset++] = data; + thisptr->decomp_buffer_wroffset &= spc7110_decomp_buffer_size - 1; + thisptr->decomp_buffer_length++; +} + +static UINT8 SPC7110Decomp_dataread(SPC7110Decomp *thisptr) +{ + UINT8 *ROM = memory_region(thisptr->machine, "cart"); + UINT32 size = snes_rom_size - 0x100000; + while(thisptr->decomp_offset >= size) + { + thisptr->decomp_offset -= size; + } + return ROM[0x100000 + thisptr->decomp_offset++]; +} + +static void SPC7110Decomp_mode0(SPC7110Decomp *thisptr, UINT8 init) +{ + static UINT8 val, in, span; + static INT32 out, inverts, lps, in_count; + + if(init == 1) + { + out = inverts = lps = 0; + span = 0xff; + val = SPC7110Decomp_dataread(thisptr); + in = SPC7110Decomp_dataread(thisptr); + in_count = 8; + return; + } + + while(thisptr->decomp_buffer_length < (spc7110_decomp_buffer_size >> 1)) + { + UINT32 bit; + for(bit = 0; bit < 8; bit++) + { + //get context + UINT8 mask = (1 << (bit & 3)) - 1; + UINT8 con = mask + ((inverts & mask) ^ (lps & mask)); + UINT32 prob, mps, flag_lps; + UINT32 shift = 0; + if(bit > 3) + { + con += 15; + } + + //get prob and mps + prob = SPC7110Decomp_probability(thisptr, con); + mps = (((out >> 15) & 1) ^ thisptr->context[con].invert); + + //get bit + if(val <= span - prob) //mps + { + span = span - prob; + out = (out << 1) + mps; + flag_lps = 0; + } + else //lps + { + val = val - (span - (prob - 1)); + span = prob - 1; + out = (out << 1) + 1 - mps; + flag_lps = 1; + } + + //renormalize + while(span < 0x7f) + { + shift++; + + span = (span << 1) + 1; + val = (val << 1) + (in >> 7); + + in <<= 1; + if(--in_count == 0) + { + in = SPC7110Decomp_dataread(thisptr); + in_count = 8; + } + } + + //update processing info + lps = (lps << 1) + flag_lps; + inverts = (inverts << 1) + thisptr->context[con].invert; + + //update context state + if(flag_lps & SPC7110Decomp_toggle_invert(thisptr, con)) + { + thisptr->context[con].invert ^= 1; + } + if(flag_lps) + { + thisptr->context[con].index = SPC7110Decomp_next_lps(thisptr, con); + } + else if(shift) + { + thisptr->context[con].index = SPC7110Decomp_next_mps(thisptr, con); + } + } + + //save byte + SPC7110Decomp_write(thisptr, out); + } +} + +static void SPC7110Decomp_mode1(SPC7110Decomp *thisptr, UINT8 init) +{ + static INT32 pixelorder[4], realorder[4]; + static UINT8 in, val, span; + static INT32 out, inverts, lps, in_count; + + if(init == 1) + { + UINT32 i; + for(i = 0; i < 4; i++) + { + pixelorder[i] = i; + } + out = inverts = lps = 0; + span = 0xff; + val = SPC7110Decomp_dataread(thisptr); + in = SPC7110Decomp_dataread(thisptr); + in_count = 8; + return; + } + + while(thisptr->decomp_buffer_length < (spc7110_decomp_buffer_size >> 1)) + { + UINT8 data; + UINT32 pixel; + for(pixel = 0; pixel < 8; pixel++) + { + //get first symbol context + UINT32 a = ((out >> (1 * 2)) & 3); + UINT32 b = ((out >> (7 * 2)) & 3); + UINT32 c = ((out >> (8 * 2)) & 3); + UINT32 con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); + UINT32 bit; + + //update pixel order + UINT32 m, n; + for(m = 0; m < 4; m++) + { + if(pixelorder[m] == a) + { + break; + } + } + for(n = m; n > 0; n--) + { + pixelorder[n] = pixelorder[n - 1]; + } + pixelorder[0] = a; + + //calculate the real pixel order + for(m = 0; m < 4; m++) + { + realorder[m] = pixelorder[m]; + } + + //rotate reference pixel c value to top + for(m = 0; m < 4; m++) + { + if(realorder[m] == c) + { + break; + } + } + for(n = m; n > 0; n--) + { + realorder[n] = realorder[n - 1]; + } + realorder[0] = c; + + //rotate reference pixel b value to top + for(m = 0; m < 4; m++) + { + if(realorder[m] == b) + { + break; + } + } + for(n = m; n > 0; n--) + { + realorder[n] = realorder[n - 1]; + } + realorder[0] = b; + + //rotate reference pixel a value to top + for(m = 0; m < 4; m++) + { + if(realorder[m] == a) + { + break; + } + } + for(n = m; n > 0; n--) + { + realorder[n] = realorder[n - 1]; + } + realorder[0] = a; + + //get 2 symbols + for(bit = 0; bit < 2; bit++) + { + //get prob + UINT32 prob = SPC7110Decomp_probability(thisptr, con); + UINT32 shift = 0; + + //get symbol + UINT32 flag_lps; + if(val <= span - prob) //mps + { + span = span - prob; + flag_lps = 0; + } + else //lps + { + val = val - (span - (prob - 1)); + span = prob - 1; + flag_lps = 1; + } + + //renormalize + while(span < 0x7f) + { + shift++; + + span = (span << 1) + 1; + val = (val << 1) + (in >> 7); + + in <<= 1; + if(--in_count == 0) + { + in = SPC7110Decomp_dataread(thisptr); + in_count = 8; + } + } + + //update processing info + lps = (lps << 1) + flag_lps; + inverts = (inverts << 1) + thisptr->context[con].invert; + + //update context state + if(flag_lps & SPC7110Decomp_toggle_invert(thisptr, con)) + { + thisptr->context[con].invert ^= 1; + } + if(flag_lps) + { + thisptr->context[con].index = SPC7110Decomp_next_lps(thisptr, con); + } + else if(shift) + { + thisptr->context[con].index = SPC7110Decomp_next_mps(thisptr, con); + } + + //get next context + con = 5 + (con << 1) + ((lps ^ inverts) & 1); + } + + //get pixel + b = realorder[(lps ^ inverts) & 3]; + out = (out << 2) + b; + } + + //turn pixel data into bitplanes + data = SPC7110Decomp_morton_2x8(thisptr, out); + SPC7110Decomp_write(thisptr, data >> 8); + SPC7110Decomp_write(thisptr, data >> 0); + } +} + +static void SPC7110Decomp_mode2(SPC7110Decomp *thisptr, UINT8 init) +{ + static INT32 pixelorder[16], realorder[16]; + static UINT8 bitplanebuffer[16], buffer_index; + static UINT8 in, val, span; + static INT32 out0, out1, inverts, lps, in_count; + + if(init == 1) + { + UINT32 i; + for(i = 0; i < 16; i++) + { + pixelorder[i] = i; + } + buffer_index = 0; + out0 = out1 = inverts = lps = 0; + span = 0xff; + val = SPC7110Decomp_dataread(thisptr); + in = SPC7110Decomp_dataread(thisptr); + in_count = 8; + return; + } + + while(thisptr->decomp_buffer_length < (spc7110_decomp_buffer_size >> 1)) + { + UINT32 data; + UINT32 pixel; + for(pixel = 0; pixel < 8; pixel++) + { + //get first symbol context + UINT32 a = ((out0 >> (0 * 4)) & 15); + UINT32 b = ((out0 >> (7 * 4)) & 15); + UINT32 c = ((out1 >> (0 * 4)) & 15); + UINT32 con = 0; + UINT32 refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); + UINT32 bit; + + //update pixel order + UINT32 m, n; + for(m = 0; m < 16; m++) + { + if(pixelorder[m] == a) + { + break; + } + } + for(n = m; n > 0; n--) + { + pixelorder[n] = pixelorder[n - 1]; + } + pixelorder[0] = a; + + //calculate the real pixel order + for(m = 0; m < 16; m++) + { + realorder[m] = pixelorder[m]; + } + + //rotate reference pixel c value to top + for(m = 0; m < 16; m++) + { + if(realorder[m] == c) + { + break; + } + } + for(n = m; n > 0; n--) + { + realorder[n] = realorder[n - 1]; + } + realorder[0] = c; + + //rotate reference pixel b value to top + for(m = 0; m < 16; m++) + { + if(realorder[m] == b) + { + break; + } + } + for(n = m; n > 0; n--) + { + realorder[n] = realorder[n - 1]; + } + realorder[0] = b; + + //rotate reference pixel a value to top + for(m = 0; m < 16; m++) + { + if(realorder[m] == a) + { + break; + } + } + for(n = m; n > 0; n--) + { + realorder[n] = realorder[n - 1]; + } + realorder[0] = a; + + //get 4 symbols + for(bit = 0; bit < 4; bit++) + { + UINT32 invertbit, shift; + + //get prob + UINT32 prob = SPC7110Decomp_probability(thisptr, con); + + //get symbol + UINT32 flag_lps; + if(val <= span - prob) //mps + { + span = span - prob; + flag_lps = 0; + } + else //lps + { + val = val - (span - (prob - 1)); + span = prob - 1; + flag_lps = 1; + } + + //renormalize + shift = 0; + while(span < 0x7f) + { + shift++; + + span = (span << 1) + 1; + val = (val << 1) + (in >> 7); + + in <<= 1; + if(--in_count == 0) + { + in = SPC7110Decomp_dataread(thisptr); + in_count = 8; + } + } + + //update processing info + lps = (lps << 1) + flag_lps; + invertbit = thisptr->context[con].invert; + inverts = (inverts << 1) + invertbit; + + //update context state + if(flag_lps & SPC7110Decomp_toggle_invert(thisptr, con)) + { + thisptr->context[con].invert ^= 1; + } + if(flag_lps) + { + thisptr->context[con].index = SPC7110Decomp_next_lps(thisptr, con); + } + else if(shift) + { + thisptr->context[con].index = SPC7110Decomp_next_mps(thisptr, con); + } + + //get next context + con = spc7110_mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); + } + + //get pixel + b = realorder[(lps ^ inverts) & 0x0f]; + out1 = (out1 << 4) + ((out0 >> 28) & 0x0f); + out0 = (out0 << 4) + b; + } + + //convert pixel data into bitplanes + data = SPC7110Decomp_morton_4x8(thisptr, out0); + SPC7110Decomp_write(thisptr, data >> 24); + SPC7110Decomp_write(thisptr, data >> 16); + bitplanebuffer[buffer_index++] = data >> 8; + bitplanebuffer[buffer_index++] = data >> 0; + + if(buffer_index == 16) + { + UINT32 i; + for(i = 0; i < 16; i++) + { + SPC7110Decomp_write(thisptr, bitplanebuffer[i]); + } + buffer_index = 0; + } + } +} + +static UINT8 SPC7110Decomp_probability(SPC7110Decomp *thisptr, UINT32 n) +{ + return spc7110_evolution_table[thisptr->context[n].index][0]; +} + +static UINT8 SPC7110Decomp_next_lps(SPC7110Decomp *thisptr, UINT32 n) +{ + return spc7110_evolution_table[thisptr->context[n].index][1]; +} + +static UINT8 SPC7110Decomp_next_mps(SPC7110Decomp *thisptr, UINT32 n) +{ + return spc7110_evolution_table[thisptr->context[n].index][2]; +} + +static UINT8 SPC7110Decomp_toggle_invert(SPC7110Decomp *thisptr, UINT32 n) +{ + return spc7110_evolution_table[thisptr->context[n].index][3]; +} + +static UINT32 SPC7110Decomp_morton_2x8(SPC7110Decomp *thisptr, UINT32 data) +{ + //reverse morton lookup: de-interleave two 8-bit values + //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8 + //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0 + return thisptr->morton16[0][(data >> 0) & 255] + thisptr->morton16[1][(data >> 8) & 255]; +} + +static UINT32 SPC7110Decomp_morton_4x8(SPC7110Decomp *thisptr, UINT32 data) +{ + //reverse morton lookup: de-interleave four 8-bit values + //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24 + //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16 + //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8 + //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0 + return thisptr->morton32[0][(data >> 0) & 255] + thisptr->morton32[1][(data >> 8) & 255] + + thisptr->morton32[2][(data >> 16) & 255] + thisptr->morton32[3][(data >> 24) & 255]; +} + +static void spc7110_mmio_write(running_machine *machine, UINT32 addr, UINT8 data); +static UINT8 spc7110_mmio_read(running_machine *machine, UINT32 addr); + +enum RTC_State +{ + RTCS_Inactive, + RTCS_ModeSelect, + RTCS_IndexSelect, + RTCS_Write +}; + +enum RTC_Mode +{ + RTCM_Linear = 0x03, + RTCM_Indexed = 0x0c +}; + +static const UINT32 spc7110_months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +typedef struct +{ + //================== + //decompression unit + //================== + UINT8 r4801; // compression table low + UINT8 r4802; // compression table high + UINT8 r4803; // compression table bank + UINT8 r4804; // compression table index + UINT8 r4805; // decompression buffer index low + UINT8 r4806; // decompression buffer index high + UINT8 r4807; // ??? + UINT8 r4808; // ??? + UINT8 r4809; // compression length low + UINT8 r480a; // compression length high + UINT8 r480b; // decompression control register + UINT8 r480c; // decompression status + + SPC7110Decomp* decomp; + + UINT8 r4811; // data pointer low + UINT8 r4812; // data pointer high + UINT8 r4813; // data pointer bank + UINT8 r4814; // data adjust low + UINT8 r4815; // data adjust high + UINT8 r4816; // data increment low + UINT8 r4817; // data increment high + UINT8 r4818; // data port control register + + UINT8 r481x; + + UINT8 r4814_latch; + UINT8 r4815_latch; + + //========= + //math unit + //========= + UINT8 r4820; // 16-bit multiplicand B0, 32-bit dividend B0 + UINT8 r4821; // 16-bit multiplicand B1, 32-bit dividend B1 + UINT8 r4822; // 32-bit dividend B2 + UINT8 r4823; // 32-bit dividend B3 + UINT8 r4824; // 16-bit multiplier B0 + UINT8 r4825; // 16-bit multiplier B1 + UINT8 r4826; // 16-bit divisor B0 + UINT8 r4827; // 16-bit divisor B1 + UINT8 r4828; // 32-bit product B0, 32-bit quotient B0 + UINT8 r4829; // 32-bit product B1, 32-bit quotient B1 + UINT8 r482a; // 32-bit product B2, 32-bit quotient B2 + UINT8 r482b; // 32-bit product B3, 32-bit quotient B3 + UINT8 r482c; // 16-bit remainder B0 + UINT8 r482d; // 16-bit remainder B1 + UINT8 r482e; // math control register + UINT8 r482f; // math status + + //=================== + //memory mapping unit + //=================== + UINT8 r4830; // SRAM write enable + UINT8 r4831; // $[d0-df]:[0000-ffff] mapping + UINT8 r4832; // $[e0-ef]:[0000-ffff] mapping + UINT8 r4833; // $[f0-ff]:[0000-ffff] mapping + UINT8 r4834; // ??? + + UINT32 dx_offset; + UINT32 ex_offset; + UINT32 fx_offset; + + //==================== + //real-time clock unit + //==================== + UINT8 r4840; // RTC latch + UINT8 r4841; // RTC index/data port + UINT8 r4842; // RTC status + + UINT32 rtc_state; + UINT32 rtc_mode; + UINT32 rtc_index; + +} _snes_spc7110_t; + +static _snes_spc7110_t snes_spc7110; + +static void spc7110_init(running_machine* machine) +{ + snes_spc7110.r4801 = 0x00; + snes_spc7110.r4802 = 0x00; + snes_spc7110.r4803 = 0x00; + snes_spc7110.r4804 = 0x00; + snes_spc7110.r4805 = 0x00; + snes_spc7110.r4806 = 0x00; + snes_spc7110.r4807 = 0x00; + snes_spc7110.r4808 = 0x00; + snes_spc7110.r4809 = 0x00; + snes_spc7110.r480a = 0x00; + snes_spc7110.r480b = 0x00; + snes_spc7110.r480c = 0x00; + + snes_spc7110.r4811 = 0x00; + snes_spc7110.r4812 = 0x00; + snes_spc7110.r4813 = 0x00; + snes_spc7110.r4814 = 0x00; + snes_spc7110.r4815 = 0x00; + snes_spc7110.r4816 = 0x00; + snes_spc7110.r4817 = 0x00; + snes_spc7110.r4818 = 0x00; + + snes_spc7110.r481x = 0x00; + snes_spc7110.r4814_latch = 0; + snes_spc7110.r4815_latch = 0; + + snes_spc7110.r4820 = 0x00; + snes_spc7110.r4821 = 0x00; + snes_spc7110.r4822 = 0x00; + snes_spc7110.r4823 = 0x00; + snes_spc7110.r4824 = 0x00; + snes_spc7110.r4825 = 0x00; + snes_spc7110.r4826 = 0x00; + snes_spc7110.r4827 = 0x00; + snes_spc7110.r4828 = 0x00; + snes_spc7110.r4829 = 0x00; + snes_spc7110.r482a = 0x00; + snes_spc7110.r482b = 0x00; + snes_spc7110.r482c = 0x00; + snes_spc7110.r482d = 0x00; + snes_spc7110.r482e = 0x00; + snes_spc7110.r482f = 0x00; + + snes_spc7110.r4830 = 0x00; + spc7110_mmio_write(machine, 0x4831, 0); + spc7110_mmio_write(machine, 0x4832, 1); + spc7110_mmio_write(machine, 0x4833, 2); + snes_spc7110.r4834 = 0x00; + + snes_spc7110.r4840 = 0x00; + snes_spc7110.r4841 = 0x00; + snes_spc7110.r4842 = 0x00; + + snes_spc7110.decomp = SPC7110Decomp_ctor(machine); +} + +static UINT32 spc7110_datarom_addr(UINT32 addr) +{ + UINT32 size = snes_rom_size - 0x100000; + while(addr >= size) + { + addr -= size; + } + return addr + 0x100000; +} + +static UINT32 spc7110_data_pointer(void) +{ + return snes_spc7110.r4811 + (snes_spc7110.r4812 << 8) + (snes_spc7110.r4813 << 16); +} + +static UINT32 spc7110_data_adjust(void) +{ + return snes_spc7110.r4814 + (snes_spc7110.r4815 << 8); +} + +static UINT32 spc7110_data_increment(void) +{ + return snes_spc7110.r4816 + (snes_spc7110.r4817 << 8); +} + +static void spc7110_set_data_pointer(UINT32 addr) +{ + snes_spc7110.r4811 = addr; + snes_spc7110.r4812 = addr >> 8; + snes_spc7110.r4813 = addr >> 16; +} + +static void spc7110_set_data_adjust(UINT32 addr) +{ + snes_spc7110.r4814 = addr; + snes_spc7110.r4815 = addr >> 8; +} + +static UINT8 spc7110_mmio_read(running_machine *machine, UINT32 addr) +{ + UINT8 *ROM = memory_region(machine, "cart"); + + addr &= 0xffff; + + switch(addr) + { + //================== + //decompression unit + //================== + + case 0x4800: + { + UINT16 counter = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8)); + counter--; + snes_spc7110.r4809 = counter; + snes_spc7110.r480a = counter >> 8; + return SPC7110Decomp_read(snes_spc7110.decomp); + } + case 0x4801: return snes_spc7110.r4801; + case 0x4802: return snes_spc7110.r4802; + case 0x4803: return snes_spc7110.r4803; + case 0x4804: return snes_spc7110.r4804; + case 0x4805: return snes_spc7110.r4805; + case 0x4806: return snes_spc7110.r4806; + case 0x4807: return snes_spc7110.r4807; + case 0x4808: return snes_spc7110.r4808; + case 0x4809: return snes_spc7110.r4809; + case 0x480a: return snes_spc7110.r480a; + case 0x480b: return snes_spc7110.r480b; + case 0x480c: + { + UINT8 status = snes_spc7110.r480c; + snes_spc7110.r480c &= 0x7f; + return status; + } + + //============== + //data port unit + //============== + + case 0x4810: + { + UINT8 data; + UINT32 addr, adjust, adjustaddr; + + if(snes_spc7110.r481x != 0x07) return 0x00; + + addr = spc7110_data_pointer(); + adjust = spc7110_data_adjust(); + if(snes_spc7110.r4818 & 8) + { + adjust = (INT16)adjust; //16-bit sign extend + } + + adjustaddr = addr; + if(snes_spc7110.r4818 & 2) + { + adjustaddr += adjust; + spc7110_set_data_adjust(adjust + 1); + } + + data = ROM[spc7110_datarom_addr(adjustaddr)]; + if(!(snes_spc7110.r4818 & 2)) + { + UINT32 increment = (snes_spc7110.r4818 & 1) ? spc7110_data_increment() : 1; + if(snes_spc7110.r4818 & 4) + { + increment = (INT16)increment; //16-bit sign extend + } + + if((snes_spc7110.r4818 & 16) == 0) + { + spc7110_set_data_pointer(addr + increment); + } + else + { + spc7110_set_data_adjust(adjust + increment); + } + } + + return data; + } + case 0x4811: return snes_spc7110.r4811; + case 0x4812: return snes_spc7110.r4812; + case 0x4813: return snes_spc7110.r4813; + case 0x4814: return snes_spc7110.r4814; + case 0x4815: return snes_spc7110.r4815; + case 0x4816: return snes_spc7110.r4816; + case 0x4817: return snes_spc7110.r4817; + case 0x4818: return snes_spc7110.r4818; + case 0x481a: + { + UINT8 data; + UINT32 addr, adjust; + if(snes_spc7110.r481x != 0x07) + { + return 0x00; + } + + addr = spc7110_data_pointer(); + adjust = spc7110_data_adjust(); + if(snes_spc7110.r4818 & 8) + { + adjust = (INT16)adjust; //16-bit sign extend + } + + data = ROM[spc7110_datarom_addr(addr + adjust)]; + if((snes_spc7110.r4818 & 0x60) == 0x60) + { + if((snes_spc7110.r4818 & 16) == 0) + { + spc7110_set_data_pointer(addr + adjust); + } + else + { + spc7110_set_data_adjust(adjust + adjust); + } + } + + return data; + } + + //========= + //math unit + //========= + + case 0x4820: return snes_spc7110.r4820; + case 0x4821: return snes_spc7110.r4821; + case 0x4822: return snes_spc7110.r4822; + case 0x4823: return snes_spc7110.r4823; + case 0x4824: return snes_spc7110.r4824; + case 0x4825: return snes_spc7110.r4825; + case 0x4826: return snes_spc7110.r4826; + case 0x4827: return snes_spc7110.r4827; + case 0x4828: return snes_spc7110.r4828; + case 0x4829: return snes_spc7110.r4829; + case 0x482a: return snes_spc7110.r482a; + case 0x482b: return snes_spc7110.r482b; + case 0x482c: return snes_spc7110.r482c; + case 0x482d: return snes_spc7110.r482d; + case 0x482e: return snes_spc7110.r482e; + case 0x482f: + { + UINT8 status = snes_spc7110.r482f; + snes_spc7110.r482f &= 0x7f; + return status; + } + + //=================== + //memory mapping unit + //=================== + + case 0x4830: return snes_spc7110.r4830; + case 0x4831: return snes_spc7110.r4831; + case 0x4832: return snes_spc7110.r4832; + case 0x4833: return snes_spc7110.r4833; + case 0x4834: return snes_spc7110.r4834; + + } + + return 0xff; +} + +static void spc7110_mmio_write(running_machine *machine, UINT32 addr, UINT8 data) +{ + UINT8 *ROM = memory_region(machine, "cart"); + + addr &= 0xffff; + + switch(addr) + { + //================== + //decompression unit + //================== + + case 0x4801: snes_spc7110.r4801 = data; break; + case 0x4802: snes_spc7110.r4802 = data; break; + case 0x4803: snes_spc7110.r4803 = data; break; + case 0x4804: snes_spc7110.r4804 = data; break; + case 0x4805: snes_spc7110.r4805 = data; break; + case 0x4806: + { + UINT32 table, index, length, addr, mode, offset; + snes_spc7110.r4806 = data; + + table = (snes_spc7110.r4801 + (snes_spc7110.r4802 << 8) + (snes_spc7110.r4803 << 16)); + index = (snes_spc7110.r4804 << 2); + length = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8)); + addr = spc7110_datarom_addr(table + index); + mode = (ROM[addr + 0]); + offset = (ROM[addr + 1] << 16) + + (ROM[addr + 2] << 8) + + (ROM[addr + 3] << 0); + + SPC7110Decomp_init(snes_spc7110.decomp, machine, mode, offset, (snes_spc7110.r4805 + (snes_spc7110.r4806 << 8)) << mode); + snes_spc7110.r480c = 0x80; + } break; + + case 0x4807: snes_spc7110.r4807 = data; break; + case 0x4808: snes_spc7110.r4808 = data; break; + case 0x4809: snes_spc7110.r4809 = data; break; + case 0x480a: snes_spc7110.r480a = data; break; + case 0x480b: snes_spc7110.r480b = data; break; + + //============== + //data port unit + //============== + + case 0x4811: snes_spc7110.r4811 = data; snes_spc7110.r481x |= 0x01; break; + case 0x4812: snes_spc7110.r4812 = data; snes_spc7110.r481x |= 0x02; break; + case 0x4813: snes_spc7110.r4813 = data; snes_spc7110.r481x |= 0x04; break; + case 0x4814: + { + snes_spc7110.r4814 = data; + snes_spc7110.r4814_latch = 1; + if(!snes_spc7110.r4815_latch) + { + break; + } + if(!(snes_spc7110.r4818 & 2)) + { + break; + } + if(snes_spc7110.r4818 & 0x10) + { + break; + } + + if((snes_spc7110.r4818 & 0x60) == 0x20) + { + UINT32 increment = spc7110_data_adjust() & 0xff; + if(snes_spc7110.r4818 & 8) + { + increment = (INT8)increment; //8-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + else if((snes_spc7110.r4818 & 0x60) == 0x40) + { + UINT32 increment = spc7110_data_adjust(); + if(snes_spc7110.r4818 & 8) + { + increment = (INT16)increment; //16-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + break; + } + + case 0x4815: + { + snes_spc7110.r4815 = data; + snes_spc7110.r4815_latch = 1; + if(!snes_spc7110.r4814_latch) + { + break; + } + if(!(snes_spc7110.r4818 & 2)) + { + break; + } + if(snes_spc7110.r4818 & 0x10) + { + break; + } + + if((snes_spc7110.r4818 & 0x60) == 0x20) + { + UINT32 increment = spc7110_data_adjust() & 0xff; + if(snes_spc7110.r4818 & 8) + { + increment = (INT8)increment; //8-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + else if((snes_spc7110.r4818 & 0x60) == 0x40) + { + UINT32 increment = spc7110_data_adjust(); + if(snes_spc7110.r4818 & 8) + { + increment = (INT16)increment; //16-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + break; + } + + case 0x4816: snes_spc7110.r4816 = data; break; + case 0x4817: snes_spc7110.r4817 = data; break; + case 0x4818: + { + if(snes_spc7110.r481x != 0x07) break; + + snes_spc7110.r4818 = data; + snes_spc7110.r4814_latch = snes_spc7110.r4815_latch = 0; + break; + } + + //========= + //math unit + //========= + + case 0x4820: snes_spc7110.r4820 = data; break; + case 0x4821: snes_spc7110.r4821 = data; break; + case 0x4822: snes_spc7110.r4822 = data; break; + case 0x4823: snes_spc7110.r4823 = data; break; + case 0x4824: snes_spc7110.r4824 = data; break; + case 0x4825: + { + snes_spc7110.r4825 = data; + + if(snes_spc7110.r482e & 1) { + //signed 16-bit x 16-bit multiplication + INT16 r0 = (INT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8)); + INT16 r1 = (INT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8)); + + INT32 result = r0 * r1; + snes_spc7110.r4828 = result; + snes_spc7110.r4829 = result >> 8; + snes_spc7110.r482a = result >> 16; + snes_spc7110.r482b = result >> 24; + } else { + //unsigned 16-bit x 16-bit multiplication + UINT16 r0 = (UINT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8)); + UINT16 r1 = (UINT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8)); + + UINT32 result = r0 * r1; + snes_spc7110.r4828 = result; + snes_spc7110.r4829 = result >> 8; + snes_spc7110.r482a = result >> 16; + snes_spc7110.r482b = result >> 24; + } + + snes_spc7110.r482f = 0x80; + break; + } + + case 0x4826: snes_spc7110.r4826 = data; break; + case 0x4827: + { + snes_spc7110.r4827 = data; + + if(snes_spc7110.r482e & 1) + { + //signed 32-bit x 16-bit division + INT32 dividend = (INT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24)); + INT16 divisor = (INT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8)); + + INT32 quotient; + INT16 remainder; + + if(divisor) + { + quotient = (INT32)(dividend / divisor); + remainder = (INT32)(dividend % divisor); + } + else + { + //illegal division by zero + quotient = 0; + remainder = dividend & 0xffff; + } + + snes_spc7110.r4828 = quotient; + snes_spc7110.r4829 = quotient >> 8; + snes_spc7110.r482a = quotient >> 16; + snes_spc7110.r482b = quotient >> 24; + + snes_spc7110.r482c = remainder; + snes_spc7110.r482d = remainder >> 8; + } + else + { + //unsigned 32-bit x 16-bit division + UINT32 dividend = (UINT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24)); + UINT16 divisor = (UINT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8)); + + UINT32 quotient; + UINT16 remainder; + + if(divisor) + { + quotient = (UINT32)(dividend / divisor); + remainder = (UINT16)(dividend % divisor); + } + else + { + //illegal division by zero + quotient = 0; + remainder = dividend & 0xffff; + } + + snes_spc7110.r4828 = quotient; + snes_spc7110.r4829 = quotient >> 8; + snes_spc7110.r482a = quotient >> 16; + snes_spc7110.r482b = quotient >> 24; + + snes_spc7110.r482c = remainder; + snes_spc7110.r482d = remainder >> 8; + } + + snes_spc7110.r482f = 0x80; + break; + } + + case 0x482e: + { + //reset math unit + snes_spc7110.r4820 = snes_spc7110.r4821 = snes_spc7110.r4822 = snes_spc7110.r4823 = 0; + snes_spc7110.r4824 = snes_spc7110.r4825 = snes_spc7110.r4826 = snes_spc7110.r4827 = 0; + snes_spc7110.r4828 = snes_spc7110.r4829 = snes_spc7110.r482a = snes_spc7110.r482b = 0; + snes_spc7110.r482c = snes_spc7110.r482d = 0; + + snes_spc7110.r482e = data; + break; + } + + //=================== + //memory mapping unit + //=================== + + case 0x4830: snes_spc7110.r4830 = data; break; + + case 0x4831: + { + snes_spc7110.r4831 = data; + snes_spc7110.dx_offset = spc7110_datarom_addr((data & 7) * 0x100000); + break; + } + + case 0x4832: + { + snes_spc7110.r4832 = data; + snes_spc7110.ex_offset = spc7110_datarom_addr((data & 7) * 0x100000); + break; + } + + case 0x4833: + { + snes_spc7110.r4833 = data; + snes_spc7110.fx_offset = spc7110_datarom_addr((data & 7) * 0x100000); + break; + } + + case 0x4834: snes_spc7110.r4834 = data; break; + } +} diff --git a/src/mame/machine/snesst10.c b/src/mame/machine/snesst10.c new file mode 100644 index 00000000000..8fd67f34d93 --- /dev/null +++ b/src/mame/machine/snesst10.c @@ -0,0 +1,529 @@ +/*************************************************************************** + + snesst10.c + + File to handle emulation of the SNES "Seta ST-010" add-on chip. + + Code based on original work by The Dumper, Matthew Kendora, + Overload and Feather. + This implementation is based on byuu's BSNES C++ version + +***************************************************************************/ + +typedef struct +{ + INT16 x1, y1, quadrant, theta, o1; + UINT8 *ram; +} _snes_st010_t; + +static _snes_st010_t snes_st010; + +static const INT16 st010_sin_table[256] = { + 0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2, + 0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, + 0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, + 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, + 0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6, + 0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504, + 0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3, + 0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5, + 0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d, + 0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b, + 0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23, + 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3, + 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, + 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df, + 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b, + 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324, + 0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2, + -0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, + -0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a, + -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, + -0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6, + -0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504, + -0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3, + -0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5, + -0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d, + -0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b, + -0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23, + -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3, + -0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3, + -0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de, + -0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b, + -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324 +}; + +static const INT16 st010_mode7_scale[176] = { + 0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3, + 0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b, + 0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8, + 0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6, + 0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5, + 0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d, + 0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c, + 0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e, + 0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063, + 0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a, + 0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052, + 0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c, + 0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047, + 0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042, + 0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e, + 0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a, + 0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037, + 0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034, + 0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031, + 0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f, + 0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d, + 0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b +}; + +static const UINT8 st010_arctan[32][32] = { + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, + { 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf }, + { 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd }, + { 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8, + 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc }, + { 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5, + 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb }, + { 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 }, + { 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0, + 0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 }, + { 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae, + 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 }, + { 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac, + 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 }, + { 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa, + 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 }, + { 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 }, + { 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6, + 0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 }, + { 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 }, + { 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 }, + { 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf }, + { 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0, + 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae }, + { 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad }, + { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d, + 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac }, + { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c, + 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab }, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b, + 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa }, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a, + 0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 }, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99, + 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 }, + { 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 }, + { 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98, + 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 }, + { 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 }, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 }, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 }, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 }, + { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 }, + { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 }, + { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 }, + { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 } +}; + + +static INT16 st010_sin( INT16 theta ) +{ + return st010_sin_table[(theta >> 8) & 0xff]; +} + +static INT16 st010_cos( INT16 theta ) +{ + return st010_sin_table[((theta + 0x4000) >> 8) & 0xff]; +} + +static UINT8 st010_readb( UINT16 address ) +{ + return snes_st010.ram[address & 0xfff]; +} + +static UINT16 st010_readw( UINT16 address ) +{ + return (st010_readb(address + 0) << 0) | + (st010_readb(address + 1) << 8); +} + +static UINT32 st010_readd( UINT16 address ) +{ + return (st010_readb(address + 0) << 0) | + (st010_readb(address + 1) << 8) | + (st010_readb(address + 2) << 16) | + (st010_readb(address + 3) << 24); +} + +static void st010_writeb( UINT16 address, UINT8 data ) +{ + snes_st010.ram[address & 0xfff] = data; +} + +static void st010_writew( UINT16 address, UINT16 data ) +{ + st010_writeb(address + 0, data >> 0); + st010_writeb(address + 1, data >> 8); +} + +static void st010_writed( UINT16 address, UINT32 data ) +{ + st010_writeb(address + 0, data >> 0); + st010_writeb(address + 1, data >> 8); + st010_writeb(address + 2, data >> 16); + st010_writeb(address + 3, data >> 24); +} + +// + +static void st010_op_01_do_work(INT16 x0, INT16 y0) { + if((x0 < 0) && (y0 < 0)) { + snes_st010.x1 = -x0; + snes_st010.y1 = -y0; + snes_st010.quadrant = -0x8000; + } else if(x0 < 0) { + snes_st010.x1 = y0; + snes_st010.y1 = -x0; + snes_st010.quadrant = -0x4000; + } else if(y0 < 0) { + snes_st010.x1 = -y0; + snes_st010.y1 = x0; + snes_st010.quadrant = 0x4000; + } else { + snes_st010.x1 = x0; + snes_st010.y1 = y0; + snes_st010.quadrant = 0x0000; + } + + while((snes_st010.x1 > 0x1f) || (snes_st010.y1 > 0x1f)) { + if(snes_st010.x1 > 1) { snes_st010.x1 >>= 1; } + if(snes_st010.y1 > 1) { snes_st010.y1 >>= 1; } + } + + if(snes_st010.y1 == 0) { snes_st010.quadrant += 0x4000; } + + snes_st010.theta = (st010_arctan[snes_st010.y1][snes_st010.x1] << 8) ^ snes_st010.quadrant; +} + +// + +static void st010_op_01( void ) { + INT16 x0 = st010_readw(0x0000); + INT16 y0 = st010_readw(0x0002); + + st010_op_01_do_work(x0, y0); + + st010_writew(0x0000, snes_st010.x1); + st010_writew(0x0002, snes_st010.y1); + st010_writew(0x0004, snes_st010.quadrant); +//st010_writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees + st010_writew(0x0010, snes_st010.theta); +} + +static void st010_op_02( void ) { + INT16 positions = st010_readw(0x0024); + UINT16 *places = (UINT16*)(snes_st010.ram + 0x0040); + UINT16 *drivers = (UINT16*)(snes_st010.ram + 0x0080); + + UINT8 sorted; + UINT16 temp; + int i; + if(positions > 1) { + do { + sorted = 1; + for(i = 0; i < positions - 1; i++) { + if(places[i] < places[i + 1]) { + temp = places[i + 1]; + places[i + 1] = places[i]; + places[i] = temp; + + temp = drivers[i + 1]; + drivers[i + 1] = drivers[i]; + drivers[i] = temp; + + sorted = 0; + } + } + positions--; + } while(!sorted); + } +} + +static void st010_op_03( void ) { + INT16 x0 = st010_readw(0x0000); + INT16 y0 = st010_readw(0x0002); + INT16 multiplier = st010_readw(0x0004); + INT32 x1, y1; + + x1 = x0 * multiplier << 1; + y1 = y0 * multiplier << 1; + + st010_writed(0x0010, x1); + st010_writed(0x0014, y1); +} + +static void st010_op_04( void ) { + INT16 x = st010_readw(0x0000); + INT16 y = st010_readw(0x0002); + INT16 square; + //calculate the vector length of (x,y) + square = sqrt((double)(y * y + x * x)); + + st010_writew(0x0010, square); +} + +// same as op_01_do_work, but we are only interested in the angle! +static void st010_op_05_do_work(INT16 x0, INT16 y0) { + INT16 x1, y1, quadrant; + if((x0 < 0) && (y0 < 0)) { + x1 = -x0; + y1 = -y0; + quadrant = -0x8000; + } else if(x0 < 0) { + x1 = y0; + y1 = -x0; + quadrant = -0x4000; + } else if(y0 < 0) { + x1 = -y0; + y1 = x0; + quadrant = 0x4000; + } else { + x1 = x0; + y1 = y0; + quadrant = 0x0000; + } + + while((x1 > 0x1f) || (y1 > 0x1f)) { + if(x1 > 1) { x1 >>= 1; } + if(y1 > 1) { y1 >>= 1; } + } + + if(y1 == 0) { quadrant += 0x4000; } + + snes_st010.o1 = (st010_arctan[y1][x1] << 8) ^ quadrant; +} + +static void st010_op_05( void ) { + INT32 dx, dy; + UINT16 o1 = 0; + UINT8 wrap = 0; + + //target (x,y) coordinates + INT16 ypos_max = st010_readw(0x00c0); + INT16 xpos_max = st010_readw(0x00c2); + + //current coordinates and direction + INT32 ypos = st010_readd(0x00c4); + INT32 xpos = st010_readd(0x00c8); + UINT16 rot = st010_readw(0x00cc); + + //physics + UINT16 speed = st010_readw(0x00d4); + UINT16 accel = st010_readw(0x00d6); + UINT16 speed_max = st010_readw(0x00d8); + UINT16 old_speed; + + //special condition acknowledgement + INT16 system = st010_readw(0x00da); + INT16 flags = st010_readw(0x00dc); + + //new target coordinates + INT16 ypos_new = st010_readw(0x00de); + INT16 xpos_new = st010_readw(0x00e0); + + //mask upper bit + xpos_new &= 0x7fff; + + //get the current distance + dx = xpos_max - (xpos >> 16); + dy = ypos_max - (ypos >> 16); + + //quirk: clear and move in9 + st010_writew(0x00d2, 0xffff); + st010_writew(0x00da, 0x0000); + + //grab the target angle + st010_op_05_do_work(dy, dx); + o1 = (UINT8)snes_st010.o1; + + //check for wrapping + if(abs(o1 - rot) > 0x8000) { + o1 += 0x8000; + rot += 0x8000; + wrap = 1; + } + + old_speed = speed; + + //special case + if(abs(o1 - rot) == 0x8000) { + speed = 0x100; + } + + //slow down for sharp curves + else if(abs(o1 - rot) >= 0x1000) { + UINT32 slow = abs(o1 - rot); + slow >>= 4; //scaling + speed -= slow; + } + + //otherwise accelerate + else { + speed += accel; + if(speed > speed_max) { + speed = speed_max; //clip speed + } + } + + //prevent negative/positive overflow + if(abs(old_speed - speed) > 0x8000) { + if(old_speed < speed) { speed = 0; } + else speed = 0xff00; + } + + //adjust direction by so many degrees + //be careful of negative adjustments + if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) { + if(o1 < rot) { rot -= 0x280; } + else if(o1 > rot) { rot += 0x280; } + } + + //turn off wrapping + if(wrap) { rot -= 0x8000; } + + //now check the distances (store for later) + dx = (xpos_max << 16) - xpos; + dy = (ypos_max << 16) - ypos; + dx >>= 16; + dy >>= 16; + + //if we're in so many units of the target, signal it + if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) { + //announce our new destination and flag it + xpos_max = xpos_new & 0x7fff; + ypos_max = ypos_new; + flags |= 0x08; + } + + //update position + xpos -= (st010_cos(rot) * 0x400 >> 15) * (speed >> 8) << 1; + ypos -= (st010_sin(rot) * 0x400 >> 15) * (speed >> 8) << 1; + + //quirk: mask upper byte + xpos &= 0x1fffffff; + ypos &= 0x1fffffff; + + st010_writew(0x00c0, ypos_max); + st010_writew(0x00c2, xpos_max); + st010_writed(0x00c4, ypos); + st010_writed(0x00c8, xpos); + st010_writew(0x00cc, rot); + st010_writew(0x00d4, speed); + st010_writew(0x00dc, flags); +} + +static void st010_op_06( void ) { + INT16 multiplicand = st010_readw(0x0000); + INT16 multiplier = st010_readw(0x0002); + INT32 product; + + product = multiplicand * multiplier << 1; + + st010_writed(0x0010, product); +} + +static void st010_op_07( void ) { + INT16 theta = st010_readw(0x0000); + + INT16 data; + int i, offset; + for(i = 0, offset = 0; i < 176; i++) { + data = st010_mode7_scale[i] * st010_cos(theta) >> 15; + st010_writew(0x00f0 + offset, data); + st010_writew(0x0510 + offset, data); + + data = st010_mode7_scale[i] * st010_sin(theta) >> 15; + st010_writew(0x0250 + offset, data); + if(data) { data = ~data; } + st010_writew(0x03b0 + offset, data); + + offset += 2; + } +} + +static void st010_op_08( void ) { + INT16 x0 = st010_readw(0x0000); + INT16 y0 = st010_readw(0x0002); + INT16 theta = st010_readw(0x0004); + INT16 x1, y1; + + x1 = (y0 * st010_sin(theta) >> 15) + (x0 * st010_cos(theta) >> 15); + y1 = (y0 * st010_cos(theta) >> 15) - (x0 * st010_sin(theta) >> 15); + + st010_writew(0x0010, x1); + st010_writew(0x0012, y1); +} + +// init, reset & handlers + +UINT8 st010_read( UINT16 address ) +{ + return st010_readb(address); +} + +void st010_write( UINT16 address, UINT8 data ) +{ + st010_writeb(address, data); + + if ((address & 0xfff) == 0x0021 && (data & 0x80)) + { + switch (snes_st010.ram[0x0020]) + { + case 0x01: st010_op_01(); break; + case 0x02: st010_op_02(); break; + case 0x03: st010_op_03(); break; + case 0x04: st010_op_04(); break; + case 0x05: st010_op_05(); break; + case 0x06: st010_op_06(); break; + case 0x07: st010_op_07(); break; + case 0x08: st010_op_08(); break; + } + + snes_st010.ram[0x0021] &= ~0x80; + } +} + + +void st010_init( running_machine* machine ) +{ + snes_st010.ram = (UINT8*)auto_alloc_array(machine, UINT8, 0x1000); +} + +void st010_reset( void ) +{ + snes_st010.x1 = 0; + snes_st010.y1 = 0; + snes_st010.quadrant = 0; + snes_st010.theta = 0; + memset(snes_st010.ram, 0, 0x1000); +} diff --git a/src/mame/mame.mak b/src/mame/mame.mak index 1d97d16618b..3f0b9427c5d 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -1862,4 +1862,6 @@ $(MACHINE)/snes.o: $(MAMESRC)/machine/snesdsp1.c \ $(MAMESRC)/machine/cx4fn.c \ $(MAMESRC)/machine/cx4data.c \ $(MAMESRC)/machine/snesrtc.c \ - $(MAMESRC)/machine/snessdd1.c + $(MAMESRC)/machine/snessdd1.c \ + $(MAMESRC)/machine/snes7110.c \ + $(MAMESRC)/machine/snesst10.c