summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2008-10-09 09:41:12 +0000
committer Aaron Giles <aaron@aarongiles.com>2008-10-09 09:41:12 +0000
commit51098d32cd954e3f1a477a5d242e4559b95f31db (patch)
tree0ff888cb4cf41c7db35e9fc08d55bf52b2b33fe1
parent01d21217d7edab25b9e2070836c2ecb143ebfd98 (diff)
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
-rw-r--r--.gitattributes2
-rw-r--r--src/mame/includes/snes.h25
-rw-r--r--src/mame/machine/snes.c101
-rw-r--r--src/mame/machine/snesdsp2.c363
-rw-r--r--src/mame/machine/snesobc1.c106
5 files changed, 568 insertions, 29 deletions
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;
+}