From 51098d32cd954e3f1a477a5d242e4559b95f31db Mon Sep 17 00:00:00 2001 From: Aaron Giles Date: Thu, 9 Oct 2008 09:41:12 +0000 Subject: [PATCH] From: Fabio Priuli [mailto:doge.fabio@gmail.com] Sent: Tue 10/7/2008 10:45 AM To: submit@mamedev.org Subject: snes special chips emulation Hi, the attached patch adds emulation for snes special chips DSP-2 & OBC-1. Changes: - added sources snesdsp2.c & snesobc1.c (directly included in machine/snes.c as per Arbee's guidelines). credits mostly goes to byuu, which released to Public Domain his sources - removed special chips detection from MAME (no nss / bootleg carts have special chips so far) and only left a variable has_addon_chip whose possible values are in includes/snes.h (it is initialized to HAS_NONE for MAME games) - modified memory handlers to account for the new chips Regards Fabio --- .gitattributes | 2 + src/mame/includes/snes.h | 25 ++- src/mame/machine/snes.c | 101 +++++++--- src/mame/machine/snesdsp2.c | 363 ++++++++++++++++++++++++++++++++++++ src/mame/machine/snesobc1.c | 106 +++++++++++ 5 files changed, 568 insertions(+), 29 deletions(-) create mode 100644 src/mame/machine/snesdsp2.c create mode 100644 src/mame/machine/snesobc1.c diff --git a/.gitattributes b/.gitattributes index 5ac067d14a8..770bda4e667 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2667,6 +2667,8 @@ 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/snesdsp1.c svneol=native#text/plain +src/mame/machine/snesdsp2.c svneol=native#text/plain +src/mame/machine/snesobc1.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/includes/snes.h b/src/mame/includes/snes.h index 61489dbc785..b1dfe98cd90 100644 --- a/src/mame/includes/snes.h +++ b/src/mame/includes/snes.h @@ -351,6 +351,29 @@ #define DSP_FIR_C6 0x6F #define DSP_FIR_C7 0x7F +/* Special chips, checked at init and used in memory handlers */ +enum +{ +HAS_NONE = 0, +HAS_DSP1, +HAS_DSP2, +HAS_DSP3, +HAS_DSP4, +HAS_SUPERFX, +HAS_SA1, +HAS_SDD1, +HAS_OBC1, +HAS_RTC, +HAS_Z80GB, +HAS_C4, +HAS_ST010, +HAS_ST011, +HAS_ST018, +HAS_SPC7110, +HAS_SPC7110_RTC, +HAS_UNK +}; + /*----------- defined in machine/snes.c -----------*/ extern DRIVER_INIT( snes ); @@ -377,7 +400,7 @@ extern WRITE8_HANDLER( snes_w_bank5 ); extern WRITE8_HANDLER( snes_w_bank6 ); extern WRITE8_HANDLER( snes_w_bank7 ); - +extern UINT8 has_addon_chip; extern void snes_gdma( UINT8 channels ); extern void snes_hdma_init(void); diff --git a/src/mame/machine/snes.c b/src/mame/machine/snes.c index 602b966828e..3f86dc0e1c8 100644 --- a/src/mame/machine/snes.c +++ b/src/mame/machine/snes.c @@ -18,6 +18,8 @@ // add-on chip emulators #include "machine/snesdsp1.c" +#include "machine/snesdsp2.c" +#include "machine/snesobc1.c" /* -- Globals -- */ UINT8 *snes_ram = NULL; /* 65816 ram */ @@ -39,7 +41,7 @@ static emu_timer *snes_nmi_timer; static emu_timer *snes_hirq_timer; static UINT16 hblank_offset; static UINT16 snes_htmult; /* in 512 wide, we run HTOTAL double and halve it on latching */ -static UINT8 has_dsp1; +UINT8 has_addon_chip; // full graphic variables static UINT16 vram_fgr_high, vram_fgr_increment, vram_fgr_count, vram_fgr_mask, vram_fgr_shift, vram_read_buffer; @@ -278,7 +280,6 @@ static TIMER_CALLBACK( snes_hblank_tick ) } - /************************************* Input Handlers @@ -1102,8 +1103,8 @@ WRITE8_HANDLER( snes_w_io ) /* There are at least 4 different kind of boards for SNES carts, which we denote with mode_20, mode_21, mode_22 and mode_25. Below is a layout of the memory for each of -them, as described on the SNES dev manual. Notice we mirror ROM at loading time -where necessary (e.g. banks 0x80 to 0xff at address 0x8000 for mode_20). +them. Notice we mirror ROM at loading time where necessary (e.g. banks 0x80 to 0xff +at address 0x8000 for mode_20). MODE_20 banks 0x00 0x20 0x40 0x60 0x70 0x7e 0x80 0xc0 0xff @@ -1122,10 +1123,10 @@ address | | | | | | | 0x0000 ------------------------------------------------------------------------------- MODE_22 is the same, but banks 0x40 to 0x7e at address 0x000 to 0x7fff contain ROM (of -course mirrored also at 0xc0 to 0xff). Mode 22 is quite similar to the board SHVC-2P3B -shown on SNES Dev manual. It is used also in SDD-1 games (only for the first blocks of -data). DSP data & status can be either at banks 0x20 to 0x40 at address 0x8000 or at -banks 0x60 to 0x6f at address 0x0000. +course mirrored also at 0xc0 to 0xff). Mode 22 is quite similar to the board SHVC-2P3B. +It is used also in SDD-1 games (only for the first blocks of data). DSP data & status +can be either at banks 0x20 to 0x40 at address 0x8000 or at banks 0x60 to 0x6f at address +0x0000. MODE_21 @@ -1168,7 +1169,6 @@ address | | | | | | | */ - /* 0x000000 - 0x2fffff */ READ8_HANDLER( snes_r_bank1 ) { @@ -1181,13 +1181,19 @@ READ8_HANDLER( snes_r_bank1 ) value = snes_r_io(machine, address); else if (address < 0x8000) { - if ((snes_cart.mode == SNES_MODE_21) && has_dsp1 && (offset < 0x100000)) + if (has_addon_chip == HAS_OBC1) + value = obc1_read(machine, offset); + else if ((has_addon_chip == HAS_DSP2) && (offset >= 0x200000)) + value = (address < 0x7000) ? DSP2_read() : 0x00; + else if ((snes_cart.mode == SNES_MODE_21) && (has_addon_chip == HAS_DSP1) && (offset < 0x100000)) value = (address < 0x7000) ? DSP1_getDr() : DSP1_getSr(); else value = 0xff; /* Reserved */ } - else if ((snes_cart.mode == SNES_MODE_20) && has_dsp1 && (offset >= 0x200000)) - value = (address < 0xc000) ? DSP1_getDr() : DSP1_getSr(); /* This is not mentioned in the SNES dev manual, fwiw */ + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP1) && (offset >= 0x200000)) + value = (address < 0xc000) ? DSP1_getDr() : DSP1_getSr(); + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP2) && (offset >= 0x200000)) + value = (address < 0xc000) ? DSP2_read() : 0x00; else value = snes_ram[offset]; @@ -1206,7 +1212,11 @@ READ8_HANDLER( snes_r_bank2 ) value = snes_r_io(machine, address); else if (address < 0x8000) /* SRAM for mode_21, Reserved othewise */ { - if ((snes_cart.mode == SNES_MODE_21) && (snes_cart.sram > 0)) + if (has_addon_chip == HAS_OBC1) + value = obc1_read (machine, offset); + else if (has_addon_chip == HAS_DSP2) + value = (address < 0x7000) ? DSP2_read() : 0x00; + 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 */ offset -= 0x6000; @@ -1216,8 +1226,10 @@ READ8_HANDLER( snes_r_bank2 ) value = 0xff; } /* some dsp1 games use these banks 0x30 to 0x3f at address 0x8000 */ - else if ((snes_cart.mode == SNES_MODE_20) && has_dsp1) + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP1)) value = (address < 0xc000) ? DSP1_getDr() : DSP1_getSr(); + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP2)) + value = (address < 0xc000) ? DSP2_read() : 0x00; else value = snes_ram[0x300000 + offset]; @@ -1246,7 +1258,7 @@ READ8_HANDLER( snes_r_bank3 ) /* 0x600000 - 0x6fffff */ READ8_HANDLER( snes_r_bank4 ) { - UINT8 value = 0; + UINT8 value = 0xff; UINT16 address = offset & 0xffff; if (snes_cart.mode & 5) /* Mode 20 & 22 */ @@ -1254,7 +1266,7 @@ READ8_HANDLER( snes_r_bank4 ) if (address >= 0x8000) value = snes_ram[0x600000 + offset]; /* some other dsp1 games use these banks 0x60 to 0x6f at address 0x0000 */ - else if (has_dsp1) + else if (has_addon_chip == HAS_DSP1) value = (address >= 0x4000) ? DSP1_getSr() : DSP1_getDr(); else value = 0xff; /* Reserved */ @@ -1311,6 +1323,10 @@ READ8_HANDLER( snes_r_bank6 ) value = 0xff; } } + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP1) && (offset >= 0x200000)) + value = (address < 0xc000) ? DSP1_getDr() : DSP1_getSr(); + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP2) && (offset >= 0x200000)) + value = (address < 0xc000) ? DSP2_read() : 0x00; else value = snes_ram[0x800000 + offset]; @@ -1348,13 +1364,19 @@ WRITE8_HANDLER( snes_w_bank1 ) snes_w_io(machine, address, data); else if (address < 0x8000) { - if ((snes_cart.mode == SNES_MODE_21) && has_dsp1 && (offset < 0x100000)) + if (has_addon_chip == HAS_OBC1) + obc1_write(machine, offset, data); + else if ((has_addon_chip == HAS_DSP2) && (offset >= 0x200000)) + DSP2_write(data); + else if ((snes_cart.mode == SNES_MODE_21) && (has_addon_chip == HAS_DSP1) && (offset < 0x100000)) DSP1_setDr(data); else logerror( "Attempt to write to reserved address: %X\n", offset ); } - else if ((snes_cart.mode == SNES_MODE_20) && has_dsp1 && (offset >= 0x200000)) - DSP1_setDr(data); /* This is not mentioned in the SNES dev manual, fwiw */ + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP1) && (offset >= 0x200000)) + DSP1_setDr(data); + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP2) && (offset >= 0x200000) && (address < 0xc000)) + DSP2_write(data); else logerror( "Attempt to write to ROM address: %X\n", offset ); } @@ -1370,7 +1392,11 @@ WRITE8_HANDLER( snes_w_bank2 ) snes_w_io(machine, address, data); else if (address < 0x8000) /* SRAM for mode_21, Reserved othewise */ { - if ((snes_cart.mode == SNES_MODE_21) && (snes_cart.sram > 0)) + if (has_addon_chip == HAS_OBC1) + obc1_write(machine, offset, data); + else if (has_addon_chip == HAS_DSP2) + DSP2_write(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 */ offset -= 0x6000; @@ -1378,10 +1404,12 @@ WRITE8_HANDLER( snes_w_bank2 ) } else logerror("Attempt to write to reserved address: %X\n", offset + 0x300000); - } + } /* some dsp1 games use these banks 0x30 to 0x3f at address 0x8000 */ - else if ((snes_cart.mode == SNES_MODE_20) && has_dsp1) + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP1)) DSP1_setDr(data); + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP2) && (address < 0xc000)) + DSP2_write(data); else logerror("Attempt to write to ROM address: %X\n", offset + 0x300000); } @@ -1395,7 +1423,7 @@ WRITE8_HANDLER( snes_w_bank4 ) { if (address >= 0x8000) logerror("Attempt to write to ROM address: %X\n", offset + 0x600000); - else if (has_dsp1) + else if (has_addon_chip == HAS_DSP1) DSP1_setDr(data); else logerror("Attempt to write to reserved address: %X\n", offset + 0x600000); @@ -1435,7 +1463,7 @@ WRITE8_HANDLER( snes_w_bank6 ) { if (offset < 0x300000) snes_w_bank1(machine, offset, data); - else + else snes_w_bank2(machine, offset - 0x300000, data); } else /* Mode 25 has SRAM not mirrored from lower banks */ @@ -1444,7 +1472,7 @@ WRITE8_HANDLER( snes_w_bank6 ) { if (offset < 0x300000) snes_w_bank1(machine, offset, data); - else + else snes_w_bank2(machine, offset - 0x300000, data); } else if ((offset >= 0x300000) && (snes_cart.sram > 0)) @@ -1454,9 +1482,13 @@ WRITE8_HANDLER( snes_w_bank6 ) snes_ram[0xb06000 + (offset & mask)] = data; } else /* Area in 0x6000-0x8000 && offset < 0x300000 is Reserved! */ - logerror("Attempt to write to reserved address: %X\n", offset + 0x800000); + logerror("Attempt to write to reserved address: %X\n", offset + 0x800000); } } + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP1) && (offset >= 0x200000)) + DSP1_setDr(data); + else if ((snes_cart.mode == SNES_MODE_20) && (has_addon_chip == HAS_DSP2) && (offset >= 0x200000) && (address < 0xc000)) + DSP2_write(data); else logerror("Attempt to write to ROM address: %X\n", offset + 0x800000); } @@ -1548,8 +1580,19 @@ static void snes_init_ram(running_machine *machine) hblank_offset = 268; timer_adjust_oneshot(snes_hblank_timer, video_screen_get_time_until_pos(machine->primary_screen, ((snes_ram[STAT78] & 0x10) == SNES_NTSC) ? SNES_VTOTAL_NTSC-1 : SNES_VTOTAL_PAL-1, hblank_offset), 0); - // check if DSP1 is present (maybe not 100%?) - has_dsp1 = ((snes_r_bank1(machine,0xffd6) >= 3) && (snes_r_bank1(machine,0xffd6) <= 5)) ? 1 : 0; + switch (has_addon_chip) + { + case HAS_DSP2: + DSP2_reset(); + break; + + case HAS_OBC1: + obc1_init(); + break; + + default: + break; + } // init frame counter so first line is 0 if( ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds) >= 59 ) @@ -1643,6 +1686,7 @@ DRIVER_INIT( snes ) /* all NSS games seem to use MODE 20 */ snes_cart.mode = SNES_MODE_20; snes_cart.sram_max = 0x40000; + has_addon_chip = HAS_NONE; /* Find the number of blocks in this ROM */ total_blocks = (memory_region_length(machine, "user3") / 0x8000); @@ -1706,6 +1750,7 @@ DRIVER_INIT( snes_hirom ) snes_cart.mode = SNES_MODE_21; snes_cart.sram_max = 0x40000; + has_addon_chip = HAS_NONE; /* Find the number of blocks in this ROM */ total_blocks = (memory_region_length(machine, "user3") / 0x10000); diff --git a/src/mame/machine/snesdsp2.c b/src/mame/machine/snesdsp2.c new file mode 100644 index 00000000000..060e32ccc30 --- /dev/null +++ b/src/mame/machine/snesdsp2.c @@ -0,0 +1,363 @@ +/*************************************************************************** + + snesdsp2.c + + File to handle emulation of the SNES "DSP-2" add-on chip. + + Original C++ code by byuu, based on research by Overload + + MAME/MESS C conversion by etabeta + +***************************************************************************/ + +int DSP2_waiting_for_command = 0; +int DSP2_command = 0; +int DSP2_in_count = 0, DSP2_in_index = 0; +int DSP2_out_count = 0, DSP2_out_index = 0; + +UINT8 DSP2_parameters[512] = {0}; +UINT8 DSP2_output[512] = {0}; + +UINT8 DSP2_op05transparent = 0; +int DSP2_op05haslen = 0; +int DSP2_op05len = 0; +int DSP2_op06haslen = 0; +int DSP2_op06len = 0; +UINT16 DSP2_op09word1 = 0; +UINT16 DSP2_op09word2 = 0; +int DSP2_op0dhaslen = 0; +int DSP2_op0doutlen = 0; +int DSP2_op0dinlen = 0; + + +//convert bitmap to bitplane tile +void DSP2_op01( void ) +{ +//op01 size is always 32 bytes input and output +//the hardware does strange things if you vary the size + + unsigned char c0, c1, c2, c3; + unsigned char *p1 = DSP2_parameters; + unsigned char *p2a = DSP2_output; + unsigned char *p2b = DSP2_output + 16; //halfway + int j; + +//process 8 blocks of 4 bytes each + for (j = 0; j < 8; j++) + { + c0 = *p1++; + c1 = *p1++; + c2 = *p1++; + c3 = *p1++; + + *p2a++ = (c0 & 0x10) << 3 | + (c0 & 0x01) << 6 | + (c1 & 0x10) << 1 | + (c1 & 0x01) << 4 | + (c2 & 0x10) >> 1 | + (c2 & 0x01) << 2 | + (c3 & 0x10) >> 3 | + (c3 & 0x01); + + *p2a++ = (c0 & 0x20) << 2 | + (c0 & 0x02) << 5 | + (c1 & 0x20) | + (c1 & 0x02) << 3 | + (c2 & 0x20) >> 2 | + (c2 & 0x02) << 1 | + (c3 & 0x20) >> 4 | + (c3 & 0x02) >> 1; + + *p2b++ = (c0 & 0x40) << 1 | + (c0 & 0x04) << 4 | + (c1 & 0x40) >> 1 | + (c1 & 0x04) << 2 | + (c2 & 0x40) >> 3 | + (c2 & 0x04) | + (c3 & 0x40) >> 5 | + (c3 & 0x04) >> 2; + + *p2b++ = (c0 & 0x80) | + (c0 & 0x08) << 3 | + (c1 & 0x80) >> 2 | + (c1 & 0x08) << 1 | + (c2 & 0x80) >> 4 | + (c2 & 0x08) >> 1 | + (c3 & 0x80) >> 6 | + (c3 & 0x08) >> 3; + } +} + +//set transparent color +void DSP2_op03( void ) +{ + DSP2_op05transparent = DSP2_parameters[0]; +} + +//replace bitmap using transparent color +void DSP2_op05( void ) +{ + UINT8 color; +// Overlay bitmap with transparency. +// Input: +// +// Bitmap 1: i[0] <=> i[size-1] +// Bitmap 2: i[size] <=> i[2*size-1] +// +// Output: +// +// Bitmap 3: o[0] <=> o[size-1] +// +// Processing: +// +// Process all 4-bit pixels (nibbles) in the bitmap +// +// if ( BM2_pixel == transparent_color ) +// pixelout = BM1_pixel +// else +// pixelout = BM2_pixel + +// The max size bitmap is limited to 255 because the size parameter is a byte +// I think size=0 is an error. The behavior of the chip on size=0 is to +// return the last value written to DR if you read DR on Op05 with +// size = 0. I don't think it's worth implementing this quirk unless it's +// proven necessary. + + unsigned char c1, c2; + unsigned char *p1 = DSP2_parameters; + unsigned char *p2 = DSP2_parameters + DSP2_op05len; + unsigned char *p3 = DSP2_output; + int n; + + color = DSP2_op05transparent & 0x0f; + + for (n = 0; n < DSP2_op05len; n++) + { + c1 = *p1++; + c2 = *p2++; + *p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) | + ( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f ); + } +} + +//reverse bitmap +void DSP2_op06( void ) +{ +// Input: +// size +// bitmap + int i, j; + for (i = 0, j = DSP2_op06len - 1; i < DSP2_op06len; i++, j--) + { + DSP2_output[j] = (DSP2_parameters[i] << 4) | (DSP2_parameters[i] >> 4); + } +} + +//multiply +void DSP2_op09( void ) +{ + UINT32 r = 0; + DSP2_out_count = 4; + + DSP2_op09word1 = DSP2_parameters[0] | (DSP2_parameters[1] << 8); + DSP2_op09word2 = DSP2_parameters[2] | (DSP2_parameters[3] << 8); + + r = DSP2_op09word1 * DSP2_op09word2; + DSP2_output[0] = r; + DSP2_output[1] = r >> 8; + DSP2_output[2] = r >> 16; + DSP2_output[3] = r >> 24; +} + +//scale bitmap +void DSP2_op0d( void ) +{ +// Bit accurate hardware algorithm - uses fixed point math +// This should match the DSP2 Op0D output exactly +// I wouldn't recommend using this unless you're doing hardware debug. +// In some situations it has small visual artifacts that +// are not readily apparent on a TV screen but show up clearly +// on a monitor. Use Overload's scaling instead. +// This is for hardware verification testing. +// +// One note: the HW can do odd byte scaling but since we divide +// by two to get the count of bytes this won't work well for +// odd byte scaling (in any of the current algorithm implementations). +// So far I haven't seen Dungeon Master use it. +// If it does we can adjust the parameters and code to work with it + + UINT32 multiplier; // Any size int >= 32-bits + UINT32 pixloc; // match size of multiplier + int i, j; + UINT8 pixelarray[512]; + if (DSP2_op0dinlen <= DSP2_op0doutlen) + { + multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1 + } + else + { + multiplier = (DSP2_op0dinlen << 17) / ((DSP2_op0doutlen << 1) + 1); + } + + pixloc = 0; + for (i = 0; i < DSP2_op0doutlen * 2; i++) + { + j = pixloc >> 16; + + if (j & 1) + pixelarray[i] = (DSP2_parameters[j >> 1] & 0x0f); + else + pixelarray[i] = (DSP2_parameters[j >> 1] & 0xf0) >> 4; + + pixloc += multiplier; + } + + for (i = 0; i < DSP2_op0doutlen; i++) + { + DSP2_output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1]; + } +} + + +void DSP2_reset( void ) +{ + DSP2_waiting_for_command = 1; + DSP2_in_count = 0; + DSP2_in_index = 0; + DSP2_out_count = 0; + DSP2_out_index = 0; + + DSP2_op05transparent = 0; + DSP2_op05haslen = 0; + DSP2_op05len = 0; + DSP2_op06haslen = 0; + DSP2_op06len = 0; + DSP2_op09word1 = 0; + DSP2_op09word2 = 0; + DSP2_op0dhaslen = 0; + DSP2_op0doutlen = 0; + DSP2_op0dinlen = 0; +} + +UINT8 DSP2_read( void ) +{ + UINT8 r = 0xff; + if (DSP2_out_count) + { + r = DSP2_output[DSP2_out_index++]; + DSP2_out_index &= 511; + if (DSP2_out_count == DSP2_out_index) + DSP2_out_count = 0; + } + return r; +} + +void DSP2_write(UINT8 data) +{ + if(DSP2_waiting_for_command) + { + DSP2_command = data; + DSP2_in_index = 0; + DSP2_waiting_for_command = 0; + + switch (data) + { + case 0x01: DSP2_in_count = 32; break; + case 0x03: DSP2_in_count = 1; break; + case 0x05: DSP2_in_count = 1; break; + case 0x06: DSP2_in_count = 1; break; + case 0x07: break; + case 0x08: break; + case 0x09: DSP2_in_count = 4; break; + case 0x0d: DSP2_in_count = 2; break; + case 0x0f: DSP2_in_count = 0; break; + } + } + else + { + DSP2_parameters[DSP2_in_index++] = data; + DSP2_in_index &= 511; + } + + if (DSP2_in_count == DSP2_in_index) + { + DSP2_waiting_for_command = 1; + DSP2_out_index = 0; + switch (DSP2_command) + { + case 0x01: + DSP2_out_count = 32; + DSP2_op01(); + break; + + case 0x03: + DSP2_op03(); + break; + + case 0x05: + if (DSP2_op05haslen) + { + DSP2_op05haslen = 0; + DSP2_out_count = DSP2_op05len; + DSP2_op05(); + } + else + { + DSP2_op05len = DSP2_parameters[0]; + DSP2_in_index = 0; + DSP2_in_count = DSP2_op05len * 2; + DSP2_op05haslen = 1; + if (data) + DSP2_waiting_for_command = 0; + } + break; + + case 0x06: + if (DSP2_op06haslen) + { + DSP2_op06haslen = 0; + DSP2_out_count = DSP2_op06len; + DSP2_op06(); + } + else + { + DSP2_op06len = DSP2_parameters[0]; + DSP2_in_index = 0; + DSP2_in_count = DSP2_op06len; + DSP2_op06haslen = 1; + if (data) + DSP2_waiting_for_command = 0; + } + break; + + case 0x07: break; + case 0x08: break; + + case 0x09: + DSP2_op09(); + break; + + case 0x0d: + if (DSP2_op0dhaslen) + { + DSP2_op0dhaslen = 0; + DSP2_out_count = DSP2_op0doutlen; + DSP2_op0d(); + } + else + { + DSP2_op0dinlen = DSP2_parameters[0]; + DSP2_op0doutlen = DSP2_parameters[1]; + DSP2_in_index = 0; + DSP2_in_count = (DSP2_op0dinlen + 1) >> 1; + DSP2_op0dhaslen = 1; + if(data) + DSP2_waiting_for_command = 0; + } + break; + + case 0x0f: + break; + } + } +} diff --git a/src/mame/machine/snesobc1.c b/src/mame/machine/snesobc1.c new file mode 100644 index 00000000000..a8479be1945 --- /dev/null +++ b/src/mame/machine/snesobc1.c @@ -0,0 +1,106 @@ +/*************************************************************************** + + snesobc1.c + + File to handle emulation of the SNES "OBC-1" add-on chip. + + Original C++ code by byuu + + MAME/MESS C conversion by etabeta + +***************************************************************************/ + +#include "includes/snes.h" + +int obc1_address; +int obc1_offset; +int obc1_shift; + +READ8_HANDLER( obc1_read ) +{ + UINT16 address = offset & 0x1fff; + UINT8 value; + + switch (address) + { + case 0x1ff0: + value = snes_ram[obc1_offset + (obc1_address << 2) + 0]; + break; + + case 0x1ff1: + value = snes_ram[obc1_offset + (obc1_address << 2) + 1]; + break; + + case 0x1ff2: + value = snes_ram[obc1_offset + (obc1_address << 2) + 2]; + break; + + case 0x1ff3: + value = snes_ram[obc1_offset + (obc1_address << 2) + 3]; + break; + + case 0x1ff4: + value = snes_ram[obc1_offset + (obc1_address >> 2) + 0x200]; + break; + + default: + value = snes_ram[address]; + break; + } + + return value; +} + + +WRITE8_HANDLER( obc1_write ) +{ + UINT16 address = offset & 0x1fff; + UINT8 temp; + + switch(address) + { + case 0x1ff0: + snes_ram[obc1_offset + (obc1_address << 2) + 0] = data; + break; + + case 0x1ff1: + snes_ram[obc1_offset + (obc1_address << 2) + 1] = data; + break; + + case 0x1ff2: + snes_ram[obc1_offset + (obc1_address << 2) + 2] = data; + break; + + case 0x1ff3: + snes_ram[obc1_offset + (obc1_address << 2) + 3] = data; + break; + + case 0x1ff4: + temp = snes_ram[obc1_offset + (obc1_address >> 2) + 0x200]; + temp = (temp & ~(3 << obc1_shift)) | ((data & 0x03) << obc1_shift); + snes_ram[obc1_offset + (obc1_address >> 2) + 0x200] = temp; + break; + + case 0x1ff5: + obc1_offset = (data & 0x01) ? 0x1800 : 0x1c00; + snes_ram[address & 0x1fff] = data; + break; + + case 0x1ff6: + obc1_address = data & 0x7f; + obc1_shift = (data & 0x03) << 1; + snes_ram[address & 0x1fff] = data; + break; + + default: + snes_ram[address & 0x1fff] = data; + break; + } +} + +void obc1_init( void ) +{ + obc1_offset = (snes_ram[0x1ff5] & 0x01) ? 0x1800 : 0x1c00; + obc1_address = (snes_ram[0x1ff6] & 0x7f); + obc1_shift = (snes_ram[0x1ff6] & 0x03) << 1; +}