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
This commit is contained in:
Aaron Giles 2008-10-09 09:41:12 +00:00
parent 01d21217d7
commit 51098d32cd
5 changed files with 568 additions and 29 deletions

2
.gitattributes vendored
View File

@ -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

View File

@ -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);

View File

@ -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);

363
src/mame/machine/snesdsp2.c Normal file
View File

@ -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;
}
}
}

106
src/mame/machine/snesobc1.c Normal file
View File

@ -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;
}