mirror of
https://github.com/holub/mame
synced 2025-05-22 21:58:57 +03:00
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:
parent
01d21217d7
commit
51098d32cd
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
363
src/mame/machine/snesdsp2.c
Normal 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
106
src/mame/machine/snesobc1.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user