Sega ST-V: driver, VDP1/VDP2 video and SCU from current MAME, optional SH-2 recompiler and threaded video (#2124)

- Driver, SCU (DMA, interrupts, timers, DSP), SMPC, MINIT/SINIT, EEPROM
  and the protection chips as current MAME; the current MAME sets.
- VDP1/VDP2 video as current MAME's (one stvvid.c), with exact speedups:
  partial redraw of the rotation plane cache, rotation copy, sprite
  passes, window evaluation once per line.
- SH-2 recompiler on the bundled sljit (x86, x86-64, ARM32, ARM64; the
  "SH-2 Dynarec" core option, off by default): blocks with chaining,
  page tables for direct memory access, memory handlers called from the
  blocks; the SGL idle loop is skipped exactly; context switch by
  pointer. Same output as the interpreter on all the sets.
- "ST-V Threaded Video" core option (off by default): the screen drawn
  in strips by 2-4 threads (libretro-common rthreads, where thread-local
  storage is native), same output.

Two more sets of Zen Nippon Pro-Wrestling Featuring Virtua, both on the
Taiwan BIOS (the core selects it):
- znpwfvt: All Japan Pro-Wrestling Featuring Virtua (Taiwan), as in
  current MAME.
- znpwfve: English translation (bootleg) on the Taiwan program, with the
  graphics the English mode left in Japanese redrawn; the ROMs are built
  from the original ones by https://github.com/zanac/znpwfvt


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
zanacandClaude Opus 5.5 authored and GitHub committed 2026-10-30 21:57:04 -04:00
1 parent df60f6466d
commit 273f904d7d
24 files changed
+16280 -5697

No files matched your search

+18
View File
@@ -872,6 +872,24 @@ ifeq ($(HAVE_ARMv6),1)
CFLAGS += -DHAVE_ARMv6
endif
# threads (libretro-common rthreads), as the other libretro cores do (beetle-psx):
# on by default, off where there is no thread library, and on the MSVC builds
# (the ST-V threaded video needs MSVC 2015's thread-local storage, the
# buildbot's MSVC lanes are 2005 and 2010: nothing would use the threads)
HAVE_THREADS ?= 1
ifneq (,$(filter $(platform), emscripten linux-portable ngc wii wiiu ps2 ps3 psl1ght psp1 ctr vita))
HAVE_THREADS = 0
endif
ifneq (,$(findstring msvc,$(platform)))
HAVE_THREADS = 0
endif
ifeq ($(HAVE_THREADS),1)
# pthreads are in the C library on Darwin and Android, Windows uses its own threads
ifeq (,$(findstring msvc,$(platform))$(findstring android,$(platform))$(findstring ios,$(platform))$(findstring tvos,$(platform))$(filter osx win,$(platform)))
LIBS += -lpthread
endif
endif
# include the various .mak files
ifneq (,$(filter $(INCLUDE_DRV),all))
include Makefile.common
+7 -1
View File
@@ -532,7 +532,7 @@ SOURCES_C += \
$(CORE_DIR)/vidhrdw/segavdp.c $(CORE_DIR)/vidhrdw/segac2_vidhrdw.c $(CORE_DIR)/machine/megadriv.c $(CORE_DIR)/drivers/segac2.c $(CORE_DIR)/drivers/megaplay.c $(CORE_DIR)/drivers/megatech.c $(CORE_DIR)/drivers/megadriv_acbl.c $(CORE_DIR)/drivers/megadriv_ybox.c $(CORE_DIR)/drivers/megadriv_sunmix.c \
$(CORE_DIR)/drivers/stv.c $(CORE_DIR)/drivers/stvhacks.c $(CORE_DIR)/machine/stvcd.c \
$(CORE_DIR)/machine/scudsp.c \
$(CORE_DIR)/vidhrdw/stvvdp1_vidhrdw.c $(CORE_DIR)/vidhrdw/stvvdp2_vidhrdw.c \
$(CORE_DIR)/vidhrdw/stvvid.c \
$(CORE_DIR)/vidhrdw/deniam_vidhrdw.c $(CORE_DIR)/drivers/deniam.c \
$(CORE_DIR)/machine/btime_machine.c $(CORE_DIR)/vidhrdw/btime_vidhrdw.c $(CORE_DIR)/drivers/btime.c \
$(CORE_DIR)/machine/decocass_machine.c $(CORE_DIR)/vidhrdw/decocass_vidhrdw.c $(CORE_DIR)/drivers/decocass.c \
@@ -2852,6 +2852,12 @@ SOURCES_C += \
# sljit: run-time code generator of the MIPS recompilers (empty where they are not supported)
SOURCES_C += $(CORE_DIR)/lib/sljit/sljit_mame.c
# threads (libretro-common rthreads, set by the platform: see Makefile): the ST-V threaded video option
ifeq ($(HAVE_THREADS),1)
COREDEFINES += -DHAVE_THREADS
SOURCES_C += $(LIBRETRO_COMM_DIR)/rthreads/rthreads.c
endif
ifeq ($(STATIC_LINKING),1)
else
SOURCES_C += \
+3
View File
@@ -3,6 +3,9 @@ LOCAL_PATH := $(call my-dir)
ROOT_DIR := $(LOCAL_PATH)/..
CORE_DIR := $(ROOT_DIR)/src
# threads: in bionic's C library
HAVE_THREADS := 1
include $(ROOT_DIR)/Makefile.common
COREFLAGS := $(DEFS) $(COREDEFINES) $(CPUDEFS) $(SOUNDDEFS) $(ASMDEFS) $(DBGDEFS) -ffast-math -funroll-loops -DANDROID -DHAVE_ZLIB $(INCFLAGS)
+1300 -133
View File
File diff suppressed because it is too large. Load diff
+158 -99
View File
@@ -147,10 +147,23 @@ typedef struct
int is_slave, cpu_number;
data16_t (*opcode_read)(offs_t pc);
data32_t (*dma_read_hook)(UINT32 src, UINT32 dst, data32_t data, int size);
UINT8 **jit_rpage; /* sh2jit.c: this CPU's page tables for direct reads and writes */
UINT8 **jit_wpage;
} SH2;
int sh2_icount;
static SH2 sh2;
/*
The state of the active SH-2 is its own context buffer: switching
CPUs (every timeslice, many thousand times a frame on the ST-V with
its tight interleave) only moves this pointer instead of copying
the whole state out and in. Each CPU's saved state items point into
its buffer too, so a state save reads it whether it is active or not.
*/
static SH2 sh2_boot; /* before a CPU's buffer is known */
static SH2 *sh2p = &sh2_boot;
#define sh2 (*sh2p)
/* Atrocious hack that makes the soldivid music correct*/
@@ -179,6 +192,16 @@ static void sh2_timer_callback(int data);
#define Rn ((opcode>>8)&15)
#define Rm ((opcode>>4)&15)
#ifdef SH2JIT_VERIFY
extern int sh2_jit_verify_logging;
void sh2_jit_verify_store(UINT32 address, int size);
#define SH2JIT_STORE(A, size) do { if (sh2_jit_verify_logging) sh2_jit_verify_store(A, size); if (sh2_jit_code_present) sh2_jit_ram_written((A) & AM, size); } while (0)
#else
/* a store over translated code flushes the recompiler's cache */
#define SH2JIT_STORE(A, size) do { if (sh2_jit_code_present) sh2_jit_ram_written((A) & AM, size); } while (0)
#endif
static INLINE data8_t RB(offs_t A)
{
if (A >= 0xe0000000)
@@ -233,6 +256,7 @@ static INLINE void WB(offs_t A, data8_t V)
if (A >= 0xc0000000)
{
cpu_writemem32bedw(A,V);
SH2JIT_STORE(A, 1);
return;
}
@@ -240,6 +264,7 @@ static INLINE void WB(offs_t A, data8_t V)
return;
cpu_writemem32bedw(A & AM,V);
SH2JIT_STORE(A, 1);
}
static INLINE void WW(offs_t A, data16_t V)
@@ -253,6 +278,7 @@ static INLINE void WW(offs_t A, data16_t V)
if (A >= 0xc0000000)
{
cpu_writemem32bedw_word(A,V);
SH2JIT_STORE(A, 2);
return;
}
@@ -260,6 +286,7 @@ static INLINE void WW(offs_t A, data16_t V)
return;
cpu_writemem32bedw_word(A & AM,V);
SH2JIT_STORE(A, 2);
}
static INLINE void WL(offs_t A, data32_t V)
@@ -273,6 +300,7 @@ static INLINE void WL(offs_t A, data32_t V)
if (A >= 0xc0000000)
{
cpu_writemem32bedw_dword(A,V);
SH2JIT_STORE(A, 4);
return;
}
@@ -280,6 +308,7 @@ static INLINE void WL(offs_t A, data32_t V)
return;
cpu_writemem32bedw_dword(A & AM,V);
SH2JIT_STORE(A, 4);
}
static INLINE void sh2_exception(const char *message, int irqline)
@@ -2291,6 +2320,61 @@ static INLINE void op1111(UINT16 opcode)
NOP();
}
/* one instruction (in the interpreter's loop and for the recompiler's checks) */
static INLINE void sh2_dispatch(UINT16 opcode)
{
switch ((opcode >> 12) & 15)
{
case 0: op0000(opcode); break;
case 1: op0001(opcode); break;
case 2: op0010(opcode); break;
case 3: op0011(opcode); break;
case 4: op0100(opcode); break;
case 5: op0101(opcode); break;
case 6: op0110(opcode); break;
case 7: op0111(opcode); break;
case 8: op1000(opcode); break;
case 9: op1001(opcode); break;
case 10: op1010(opcode); break;
case 11: op1011(opcode); break;
case 12: op1100(opcode); break;
case 13: op1101(opcode); break;
case 14: op1110(opcode); break;
default: op1111(opcode); break;
}
}
static INLINE void sh2_step(void)
{
UINT32 opcode;
if (sh2.delay)
{
opcode = sh2.opcode_read ? sh2.opcode_read(sh2.delay) : RW(sh2.delay & AM);
change_pc32bedw(sh2.pc & AM);
sh2.pc -= 2;
}
else
opcode = sh2.opcode_read ? sh2.opcode_read(sh2.pc) : RW(sh2.pc & AM);
CALL_MAME_DEBUG;
sh2.delay = 0;
sh2.pc += 2;
sh2.ppc = sh2.pc;
sh2_dispatch(opcode);
if(sh2.test_irq && !sh2.delay)
{
CHECK_PENDING_IRQ("mame_sh2_execute");
sh2.test_irq = 0;
}
sh2_icount--;
}
#include "sh2jit.c"
/*****************************************************************************
* MAME CPU INTERFACE
*****************************************************************************/
@@ -2324,6 +2408,10 @@ void sh2_reset(void *param)
sh2.cpu_number = cpu_getactivecpu();
/* code and memory handlers may differ after a reset */
if (jit_enabled)
jit_flush();
sh2.pc = RL(0);
sh2.r[15] = RL(4);
sh2.sr = I;
@@ -2335,11 +2423,15 @@ void sh2_reset(void *param)
/* Shut down CPU core */
void sh2_exit(void)
{
sh2_jit_set(0);
if (sh2.m)
free(sh2.m);
sh2.m = NULL;
/* the core frees the buffers after this */
sh2p = &sh2_boot;
}
/* Execute cycles - returns number of cycles actually run */
int sh2_execute(int cycles)
{
@@ -2350,49 +2442,10 @@ int sh2_execute(int cycles)
do
{
UINT32 opcode;
if (sh2.delay)
{
opcode = sh2.opcode_read ? sh2.opcode_read(sh2.delay) : RW(sh2.delay & AM);
change_pc32bedw(sh2.pc & AM);
sh2.pc -= 2;
}
else
opcode = sh2.opcode_read ? sh2.opcode_read(sh2.pc) : RW(sh2.pc & AM);
CALL_MAME_DEBUG;
sh2.delay = 0;
sh2.pc += 2;
sh2.ppc = sh2.pc;
switch ((opcode >> 12) & 15)
{
case 0: op0000(opcode); break;
case 1: op0001(opcode); break;
case 2: op0010(opcode); break;
case 3: op0011(opcode); break;
case 4: op0100(opcode); break;
case 5: op0101(opcode); break;
case 6: op0110(opcode); break;
case 7: op0111(opcode); break;
case 8: op1000(opcode); break;
case 9: op1001(opcode); break;
case 10: op1010(opcode); break;
case 11: op1011(opcode); break;
case 12: op1100(opcode); break;
case 13: op1101(opcode); break;
case 14: op1110(opcode); break;
default: op1111(opcode); break;
}
if(sh2.test_irq && !sh2.delay)
{
CHECK_PENDING_IRQ("mame_sh2_execute");
sh2.test_irq = 0;
}
sh2_icount--;
/* a block, when there is one for the PC (no slot or interrupt test pending) */
if (jit_enabled && !sh2.delay && !sh2.test_irq && sh2_jit_run())
continue;
sh2_step();
} while( sh2_icount > 0 );
return cycles - sh2_icount;
@@ -2401,16 +2454,17 @@ int sh2_execute(int cycles)
/* Get registers, return context size */
unsigned sh2_get_context(void *dst)
{
if( dst )
memcpy(dst, &sh2, sizeof(SH2));
if( dst && dst != (void *)sh2p )
memcpy(dst, sh2p, sizeof(SH2));
return sizeof(SH2);
}
/* Set registers */
void sh2_set_context(void *src)
{
/* the core passes a CPU's own buffer: it becomes the live state */
if( src )
memcpy(&sh2, src, sizeof(SH2));
sh2p = (SH2 *)src;
}
static void sh2_timer_resync(void)
@@ -2597,6 +2651,7 @@ static void sh2_dmac_check(int dma)
if(incd == 2)
dst --;
cpu_writemem32bedw(dst, DMA_READ(src, dst, cpu_readmem32bedw(src), 0));
SH2JIT_STORE(dst, 1);
if(incs == 1)
src ++;
if(incd == 1)
@@ -2613,6 +2668,7 @@ static void sh2_dmac_check(int dma)
if(incd == 2)
dst -= 2;
cpu_writemem32bedw_word(dst, DMA_READ(src, dst, cpu_readmem32bedw_word(src), 1));
SH2JIT_STORE(dst, 2);
if(incs == 1)
src += 2;
if(incd == 1)
@@ -2629,6 +2685,7 @@ static void sh2_dmac_check(int dma)
if(incd == 2)
dst -= 4;
cpu_writemem32bedw_dword(dst, DMA_READ(src, dst, cpu_readmem32bedw_dword(src), 2));
SH2JIT_STORE(dst, 4);
if(incs == 1)
src += 4;
if(incd == 1)
@@ -2647,6 +2704,7 @@ static void sh2_dmac_check(int dma)
cpu_writemem32bedw_dword(dst+4, DMA_READ(src+4, dst+4, cpu_readmem32bedw_dword(src+4), 2));
cpu_writemem32bedw_dword(dst+8, DMA_READ(src+8, dst+8, cpu_readmem32bedw_dword(src+8), 2));
cpu_writemem32bedw_dword(dst+12, DMA_READ(src+12, dst+12, cpu_readmem32bedw_dword(src+12), 2));
SH2JIT_STORE(dst, 16);
src += 16;
if(incd == 1)
dst += 16;
@@ -2666,6 +2724,46 @@ static void sh2_dmac_check(int dma)
}
}
/* the division unit, as in current MAME (sh7604.cpp) */
static void sh2_divu_start(INT64 dividend)
{
INT32 divisor = (INT32)sh2.m[0x40];
INT64 remainder;
UINT32 quotient;
int i, negative;
sh2.m[0x41] = (UINT32)dividend;
if (divisor && (dividend != (INT64)((UINT64)1 << 63) || divisor != -1))
{
INT64 q = dividend / divisor;
if (q == (INT32)q)
{
sh2.m[0x45] = (UINT32)q;
sh2.m[0x44] = (UINT32)(dividend % divisor);
return;
}
}
/* overflow (zero divisor or a quotient outside 32 bits): the unit stops after three
steps, leaving the partial remainder in DVDNTH; with OVFIE clear DVDNTL saturates */
remainder = dividend >> 32;
quotient = (UINT32)dividend;
for (i = 0; i < 3; i++)
{
int subtract = (remainder < 0) == (divisor < 0);
remainder = (remainder << 1) | ((quotient >> 31) & 1);
quotient <<= 1;
remainder += subtract ? -(INT64)divisor : (INT64)divisor;
quotient |= ((remainder < 0) == (divisor < 0)) ? 1 : 0;
}
negative = (dividend < 0) != (divisor < 0);
sh2.m[0x44] = (UINT32)remainder;
sh2.m[0x45] = (sh2.m[0x42] & 2) ? quotient : negative ? 0x80000000 : 0x7fffffff;
sh2.m[0x42] |= 1;
sh2_recalc_irq();
}
WRITE32_HANDLER( sh2_internal_w )
{
UINT32 old = sh2.m[offset];
@@ -2728,64 +2826,19 @@ WRITE32_HANDLER( sh2_internal_w )
/* Division box*/
case 0x40: /* DVSR*/
break;
case 0x41: /* DVDNT*/
{
INT32 a = sh2.m[0x41];
INT32 b = sh2.m[0x40];
log_cb(RETRO_LOG_DEBUG, LOGPRE "SH2 #%d div+mod %d/%d\n", cpu_getactivecpu(), a, b);
if (b)
{
sh2.m[0x45] = a / b;
sh2.m[0x44] = a % b;
}
else
{
sh2.m[0x42] |= 0x00010000;
sh2.m[0x45] = 0x7fffffff;
sh2.m[0x44] = 0x7fffffff;
sh2_recalc_irq();
}
break;
}
case 0x42: /* DVCR*/
sh2.m[0x42] = (sh2.m[0x42] & ~0x00001000) | (old & sh2.m[0x42] & 0x00010000);
sh2_recalc_irq();
case 0x41: /* DVDNT: a 32-bit division, the dividend sign-extended into DVDNTH */
sh2_divu_start((INT32)sh2.m[0x41]);
break;
case 0x42: /* DVCR: OVF (bit 0) and OVFIE (bit 1) are plain read/write bits */
break;
case 0x43: /* VCRDIV*/
sh2_recalc_irq();
break;
case 0x44: /* DVDNTH*/
break;
case 0x45: /* DVDNTL*/
{
INT64 a = sh2.m[0x45] | ((UINT64)(sh2.m[0x44]) << 32);
INT64 b = sh2.m[0x40];
log_cb(RETRO_LOG_DEBUG, LOGPRE "SH2 #%d div+mod %08x%08x/%08x\n", cpu_getactivecpu(), sh2.m[0x44], sh2.m[0x45], sh2.m[0x40]);
if (b)
{
INT64 q = a / b;
if (q != (INT32)q)
{
sh2.m[0x42] |= 0x00010000;
sh2.m[0x45] = 0x7fffffff;
sh2.m[0x44] = 0x7fffffff;
sh2_recalc_irq();
}
else
{
sh2.m[0x45] = q;
sh2.m[0x44] = a % b;
}
}
else
{
sh2.m[0x42] |= 0x00010000;
sh2.m[0x45] = 0x7fffffff;
sh2.m[0x44] = 0x7fffffff;
sh2_recalc_irq();
}
break;
}
case 0x45: /* DVDNTL: a 64-bit division of DVDNTH:DVDNTL */
sh2_divu_start((INT64)(((UINT64)sh2.m[0x44] << 32) | sh2.m[0x45]));
break;
/* DMA controller*/
case 0x60: /* SAR0*/
@@ -3096,6 +3149,12 @@ void sh2_init(void)
{
int cpu = cpu_getactivecpu();
/* this CPU's buffer from now on (the core allocated it before the init) */
sh2p = (SH2 *)cpunum_get_context_ptr(cpu);
if (!sh2p)
sh2p = &sh2_boot;
memset(sh2p, 0, sizeof(SH2));
sh2.timer = timer_alloc(sh2_timer_callback);
timer_adjust(sh2.timer, TIME_NEVER, 0, 0);
+11
View File
@@ -69,6 +69,17 @@ struct sh2_config
data32_t (*dma_read_hook)(UINT32 src, UINT32 dst, data32_t data, int size);
};
/* optional recompiler (sh2jit.c): a driver declares the RAM the CPUs run
from and read directly ('base': host memory of 'start', as the memory
system keeps it), then enables it; anything else stays with the
interpreter. Writes the driver makes there by other means than the
CPUs (DMA) must be reported with sh2_jit_ram_written. */
int sh2_jit_available(void);
void sh2_jit_add_fastram(offs_t start, offs_t end, int readonly, void *base);
void sh2_jit_set(int enable);
void sh2_jit_ram_written(UINT32 address, UINT32 bytes);
extern int sh2_jit_code_present;
extern void sh2_init(void);
extern void sh2_reset (void *param); /* Reset registers to the initial values */
extern void sh2_exit (void); /* Shut down CPU core */
+2126
View File
File diff suppressed because it is too large. Load diff
+14 -2
View File
@@ -3576,11 +3576,21 @@ Sep.1994 Quiz Ghost Hunter
DRIVER( rsgun )
DRIVER( sandor )
DRIVER( thunt )
DRIVER( sassisu )
DRIVER( sasissu )
DRIVER( sanjeon )
DRIVER( critcrsh )
DRIVER( tatacot )
DRIVER( danchiq )
DRIVER( micrombc )
DRIVER( patocar )
DRIVER( skychal )
DRIVER( supgoal )
DRIVER( techbowl )
DRIVER( wasafari )
DRIVER( seabass )
DRIVER( shanhigw )
DRIVER( shienryu )
DRIVER( sleague )
DRIVER( smleague )
DRIVER( sokyugrt )
DRIVER( sss )
DRIVER( suikoenb )
@@ -3590,6 +3600,8 @@ Sep.1994 Quiz Ghost Hunter
DRIVER( vmahjong )
DRIVER( winterht )
DRIVER( znpwfv )
DRIVER( znpwfvt )
DRIVER( znpwfve )
DRIVER( danchih )
DRIVER( mausuke )
+1810 -1135
View File
File diff suppressed because it is too large. Load diff
+17 -41
View File
@@ -9,58 +9,34 @@ to be honest i think some of these cause more problems than they're worth ...
extern data32_t *stv_workram_h;
DRIVER_INIT ( stv );
/* Hack the boot vectors .. not right but allows several IC13 games (which fail the checksums before hacking) to boot */
/* the IC13 carts: their program ROM is now loaded as MAME loads it (odd
bytes, mirrored), so they need no boot vector patch */
DRIVER_INIT( ic13 )
{
/* this is WRONG but works for some games */
data32_t *rom = (data32_t *)memory_region(REGION_USER1);
rom[0xf10/4] = (rom[0xf10/4] & 0xff000000)|((rom[0xf10/4]/2)&0x00ffffff);
rom[0xf20/4] = (rom[0xf20/4] & 0xff000000)|((rom[0xf20/4]/2)&0x00ffffff);
rom[0xf30/4] = (rom[0xf30/4] & 0xff000000)|((rom[0xf30/4]/2)&0x00ffffff);
init_stv();
}
/*
06013AE8: MOV.L @($D4,PC),R5
06013AEA: MOV.L @($D8,PC),R0
06013AEC: MOV.W @R5,R5
06013AEE: MOV.L @R0,R0
06013AF0: AND R10,R5
06013AF2: TST R0,R0
06013AF4: BTS $06013B00
06013AF6: EXTS.W R5,R5
06013B00: EXTS.W R5,R5
06013B02: TST R5,R5
06013B04: BF $06013B0A
06013B06: TST R4,R4
06013B08: BT $06013AE8
(loops for 375868 instructions)
Super Major League / Final Arch: each frame the master queues a job for the slave
(the depth sort of the polygons), waits for the slave to take it (the read pointer
at 060ffc44) and then clears the "sort done" flag that the slave sets when the job
is over. The slave is much slower than the master on the real hardware, but in
coarse time slices it can take the job and finish it before the master looks at the
pointer again, so the flag is lost and the game hangs. A tight interleave while the
master polls keeps the order of the real hardware.
*/
READ32_HANDLER( stv_speedup_r )
static READ32_HANDLER( smleague_sync_r )
{
if (activecpu_get_pc()==0x60154b4) cpu_spinuntil_int(); /* bios menus..*/
return stv_workram_h[0x0335d0/4];
/* a slice of 16 SH-2 cycles is enough (a perfect one costs half the speed);
with 64 cycles Super Major League and Final Arch hang again */
cpu_boost_interleave(TIME_IN_HZ(57272720/32), TIME_IN_USEC(20));
return stv_workram_h[0x0ffc44/4];
}
READ32_HANDLER( stv_speedup2_r )
DRIVER_INIT( smleague )
{
if (activecpu_get_pc()==0x6013af0) cpu_spinuntil_int(); /* for use in japan*/
return stv_workram_h[0x0335bc/4];
}
void install_stvbios_speedups(void)
{
/* idle skip bios? .. not 100% sure this is safe .. we'll see */
install_mem_read32_handler(0, 0x60335d0, 0x60335d3, stv_speedup_r );
install_mem_read32_handler(0, 0x60335bc, 0x60335bf, stv_speedup2_r );
install_mem_read32_handler(0, 0x060ffc44, 0x060ffc47, smleague_sync_r);
init_stv();
}
static READ32_HANDLER( shienryu_slave_speedup_r )
+40
View File
@@ -0,0 +1,40 @@
/***************************************************************************
Sega ST-V: interface between the driver and the video (VDP1, VDP2)
***************************************************************************/
#ifndef STV_H
#define STV_H
/* vidhrdw/stvvid.c */
extern UINT16 *vdp2_regs;
extern UINT32 *vdp2_vram;
extern UINT32 *vdp2_cram;
extern UINT32 *vdp1_vram;
extern UINT16 *vdp1_regs;
READ32_HANDLER( stv_vdp1_regs_r );
WRITE32_HANDLER( stv_vdp1_regs_w );
READ32_HANDLER( stv_vdp1_vram_r );
WRITE32_HANDLER( stv_vdp1_vram_w );
READ32_HANDLER( stv_vdp1_framebuffer0_r );
WRITE32_HANDLER( stv_vdp1_framebuffer0_w );
READ32_HANDLER( stv_vdp2_vram_r );
WRITE32_HANDLER( stv_vdp2_vram_w );
READ32_HANDLER( stv_vdp2_cram_r );
WRITE32_HANDLER( stv_vdp2_cram_w );
READ32_HANDLER( stv_vdp2_regs_r );
WRITE32_HANDLER( stv_vdp2_regs_w );
VIDEO_START( stv_vdp2 );
VIDEO_STOP( stv_vdp2 );
VIDEO_UPDATE( stv_vdp2 );
/* frame timing, from the driver's scanline interrupt */
int stv_vdp2_vblank_start_line(void); /* the line vblank-in happens on */
void stv_vdp2_scanline(int line); /* the start of each line, 0 to 262 */
void stv_vdp1_video_update(void); /* at vblank-in: frame change, automatic draw */
void stv_vdp1_vblank_erase(void); /* one line after vblank-in */
#endif
+15 -3
View File
@@ -1,5 +1,6 @@
#include "driver.h"
#include "machine/scudsp.h"
#include "cpu/sh2/sh2.h"
/*SCU DSP functions */
/*V0.03*/
@@ -75,10 +76,13 @@ extern data32_t* stv_scu;
static UINT32 opcode;
static UINT8 update_mul = 0;
#define DEBUG_DSP
/* writes dsp.log in the current directory, for debugging only */
/*#define DEBUG_DSP*/
#ifdef DEBUG_DSP
static char dasm_buffer[100];
static FILE *log_file = NULL;
#endif
void dsp_dasm_opcode( UINT32 op, char *buffer );
@@ -270,8 +274,8 @@ void dsp_prg_ctrl(UINT32 data)
{
if(LEF) dsp_reg.pc = (data & 0xff);
if(EXF) dsp_execute_program();
if(EF && (!(stv_scu[40] & 0x0020)))
cpu_set_irq_line_and_vector(0, 0xa, HOLD_LINE , 0x45);
if(EF)
stv_scu_raise_irq(5); /* DSP end */
}
void dsp_prg_data(UINT32 data)
@@ -630,6 +634,8 @@ static void dsp_dma( void )
for ( counter = 0; counter < transfer_cnt; counter++ )
{
cpu_writemem32bedw_dword( dest, cpu_readmem32bew_word( dsp_get_mem_source_dma( dsp_mem, counter ) ) );
if ( sh2_jit_code_present )
sh2_jit_ram_written( dest, 4 );
dest += add;
}
@@ -698,6 +704,7 @@ static void dsp_loop( void )
}
}
#ifdef DEBUG_DSP
static void dsp_dump_mem( FILE *f )
{
UINT16 i;
@@ -724,12 +731,15 @@ static void dsp_dump_mem( FILE *f )
}
fprintf( f, "}\n" );
}
#endif
void dsp_execute_program()
{
UINT32 cycles_run = 0;
UINT8 cont = 1;
#ifdef DEBUG_DSP
UINT16 i;
#endif
#ifdef DEBUG_DSP
if ( log_file == NULL )
@@ -758,7 +768,9 @@ void dsp_execute_program()
dsp_reg.pc++;
}
#ifdef DEBUG_DSP
dsp_dasm_opcode( opcode, dasm_buffer );
#endif
switch( (opcode & 0xc0000000) >> 30 )
{
+3
View File
@@ -6,3 +6,6 @@ extern void dsp_ram_addr_ctrl(UINT32 data);
extern void dsp_ram_addr_w(UINT32 data);
extern UINT32 dsp_ram_addr_r(void);
extern void dsp_execute_program(void);
/* raise an SCU interrupt source (bit of the status register), drivers/stv.c */
extern void stv_scu_raise_irq(int bit);
+30 -9
View File
@@ -1,11 +1,12 @@
/***************************************************************************
Sega 315-5838 / 317-0229 compression and encryption
(Dead or Alive startup string on Model 2)
(DecAthlete graphics on ST-V, Dead or Alive startup string on Model 2)
Translated to C from current MAME (sega/315-5838_317-0229_comp.cpp,
license BSD-3-Clause), 317-0229 variant only: a fixed word substitution
followed by a programmable prefix decompression.
license BSD-3-Clause): a fixed word substitution followed by a
programmable prefix decompression. The four variants differ only in the
substitution (routing, tables and affine masks).
***************************************************************************/
@@ -16,6 +17,7 @@
#define BITN(x,n) (((x)>>(n))&1)
static UINT16 (*comp_source_r)(UINT32 offset);
static int comp_variant = SEGA315_5838_VARIANT_0229;
static UINT16 m_tree[ 24 ];
static UINT8 m_dictionary[ 256 ];
static int m_tree_words, m_dictionary_bytes, m_upload_dictionary;
@@ -25,14 +27,27 @@ static int m_bits, m_abort;
static UINT16 decipher( UINT16 c )
{
/* 317-0229 */
static const UINT8 routing[ 4 ] = { 3, 2, 0, 1 };
static const UINT8 sboxes[ 4 ][ 8 ] =
/* routing, substitution tables and affine masks of 315-5838, 317-0229, 317-0230, 317-0231 */
static const UINT8 all_routing[ 4 ][ 4 ] = { { 0, 1, 2, 3 }, { 3, 2, 0, 1 }, { 2, 3, 1, 0 }, { 1, 0, 3, 2 } };
static const UINT8 all_sboxes[ 4 ][ 4 ][ 8 ] =
{
{ 6, 0, 5, 4, 7, 2, 1, 3 }, { 5, 6, 1, 3, 7, 0, 4, 2 },
{ 2, 6, 0, 1, 3, 4, 7, 5 }, { 6, 5, 7, 4, 1, 3, 0, 2 }
{ { 6, 7, 2, 0, 5, 1, 3, 4 }, { 5, 3, 7, 2, 1, 6, 4, 0 },
{ 2, 0, 6, 1, 3, 7, 4, 5 }, { 6, 5, 7, 4, 1, 3, 0, 2 } },
{ { 6, 0, 5, 4, 7, 2, 1, 3 }, { 5, 6, 1, 3, 7, 0, 4, 2 },
{ 2, 6, 0, 1, 3, 4, 7, 5 }, { 6, 5, 7, 4, 1, 3, 0, 2 } },
{ { 6, 2, 7, 0, 5, 3, 1, 4 }, { 5, 3, 7, 2, 1, 6, 4, 0 },
{ 2, 1, 3, 5, 6, 0, 4, 7 }, { 6, 1, 3, 5, 7, 0, 2, 4 } },
{ { 6, 0, 5, 4, 7, 2, 1, 3 }, { 5, 1, 6, 3, 7, 4, 0, 2 },
{ 2, 1, 3, 5, 6, 0, 4, 7 }, { 6, 3, 1, 5, 7, 2, 0, 4 } }
};
static const UINT8 affine_masks[ 4 ] = { 0x12, 0x11, 0x04, 0x1a };
static const UINT8 all_affine[ 4 ][ 4 ] =
{
{ 0x14, 0x18, 0x02, 0x15 }, { 0x12, 0x11, 0x04, 0x1a },
{ 0x14, 0x18, 0x02, 0x15 }, { 0x12, 0x11, 0x04, 0x1a }
};
const UINT8 *routing = all_routing[ comp_variant ];
const UINT8 (*sboxes)[ 8 ] = all_sboxes[ comp_variant ];
const UINT8 *affine_masks = all_affine[ comp_variant ];
static const UINT8 output_bits[ 4 ][ 3 ] = { { 0, 1, 7 }, { 2, 5, 9 }, { 4, 10, 13 }, { 6, 11, 15 } };
static const UINT8 affine_bits[ 4 ] = { 3, 8, 12, 14 };
UINT8 lanes[ 4 ];
@@ -62,9 +77,15 @@ static UINT16 decipher( UINT16 c )
return result;
}
void sega315_5838_set_variant( int variant )
{
comp_variant = variant & 3;
}
void sega315_5838_init( UINT16 (*source_r)( UINT32 offset ) )
{
comp_source_r = source_r;
comp_variant = SEGA315_5838_VARIANT_0229;
state_save_register_UINT16( "315_5838", 0, "tree", m_tree, 24 );
state_save_register_UINT8( "315_5838", 0, "dictionary", m_dictionary, 256 );
state_save_register_int( "315_5838", 0, "tree_words", &m_tree_words );
+6 -1
View File
@@ -1,7 +1,12 @@
#ifndef SEGA315_5838_H
#define SEGA315_5838_H
/* Sega 315-5838 / 317-0229 compression and encryption (317-0229 variant) */
/* Sega 315-5838 / 317-0229 compression and encryption */
#define SEGA315_5838_VARIANT_5838 0 /* DecAthlete */
#define SEGA315_5838_VARIANT_0229 1 /* Dead or Alive (the default) */
#define SEGA315_5838_VARIANT_0230 2
#define SEGA315_5838_VARIANT_0231 3
void sega315_5838_set_variant( int variant ); /* after init */
void sega315_5838_init( UINT16 (*source_r)( UINT32 offset ) );
void sega315_5838_reset( void );
void sega315_5838_source_w( UINT32 data );
+25
View File
@@ -876,6 +876,31 @@ static UINT16 do_decrypt( void )
return ( base[ 0 ] << 8 ) | base[ 1 ];
}
void sega315_5881_set_addr_low( UINT16 data )
{
prot_cur_address = ( prot_cur_address & 0xffff0000 ) | data;
enc_ready = 0;
}
void sega315_5881_set_addr_high( UINT16 data )
{
prot_cur_address = ( prot_cur_address & 0x0000ffff ) | ( (UINT32)data << 16 );
enc_ready = 0;
buffer_bit = 7;
buffer_bit2 = 15;
}
void sega315_5881_set_subkey( UINT16 data )
{
subkey = data;
enc_ready = 0;
}
UINT16 sega315_5881_do_decrypt( void )
{
return do_decrypt();
}
/* little endian read: the decrypted word with its bytes swapped */
UINT16 sega315_5881_decrypt_r( void )
{
+7
View File
@@ -10,4 +10,11 @@ void sega315_5881_addrhi_w( UINT16 data );
void sega315_5881_subkey_w( UINT16 data );
UINT16 sega315_5881_decrypt_r( void );
/* ST-V A-Bus interface: the address and sub-key as the cart latches them,
and the decrypted stream word by word (big endian) */
void sega315_5881_set_addr_low( UINT16 data );
void sega315_5881_set_addr_high( UINT16 data );
void sega315_5881_set_subkey( UINT16 data );
UINT16 sega315_5881_do_decrypt( void );
#endif
+4 -1
View File
@@ -154,7 +154,6 @@ enum /* used to index content-specific flags */
{
CONTENT_NEOGEO = 0,
CONTENT_STV,
CONTENT_DIEHARD,
CONTENT_ALT_SOUND,
CONTENT_VECTOR,
CONTENT_DIAL,
@@ -182,6 +181,8 @@ enum /* used to index content-specific flags */
CONTENT_SH3_DYNAREC,
CONTENT_TX1_SCREENS,
CONTENT_CPU_COUNT,
CONTENT_SH2_DYNAREC,
CONTENT_STV_VIDEO_THREADS,
CONTENT_end,
};
@@ -227,6 +228,8 @@ struct GameOptions
bool adsp_dynarec; /* 1 to let drivers enable the ADSP-2100 recompiler */
bool sh3_dynarec; /* 1 to let drivers enable the SH-3 recompiler */
int tx1_screens; /* TX-1 / Buggy Boy: 3 screens side by side, or 1 (the middle one) */
bool sh2_dynarec; /* 1 to let drivers enable the SH-2 recompiler */
int stv_video_threads; /* ST-V: threads drawing the VDP2 screen in bands (0 or 1 = the main thread only) */
bool use_alt_sound; /* 1 to enable alternate ost samples */
float brightness; /* brightness of the display */
+93 -7
View File
@@ -342,6 +342,25 @@ static struct retro_core_option_v2_definition option_def_neogeo_bios = {
"default"
};
/* ST-V games that check the BIOS region and only run with one (as MAME's
default BIOS for them) */
static const char *stv_required_bios(const char *name)
{
static const char *const games[][2] = {
{ "diehard", "us" },
{ "smleague", "us" },
{ "znpwfvt", "taiwan" },
{ "znpwfve", "taiwan" },
{ "critcrsh", "europe" },
{ "tatacot", "japan" },
};
size_t i;
for (i = 0; i < sizeof(games) / sizeof(games[0]); i++)
if (strcmp(name, games[i][0]) == 0)
return games[i][1];
return NULL;
}
static struct retro_core_option_v2_definition option_def_stv_bios = {
APPNAME"_stv_bios",
"Specify Sega ST-V BIOS",
@@ -781,6 +800,38 @@ static struct retro_core_option_v2_definition option_def_mips_dynarec = {
"enabled"
};
static struct retro_core_option_v2_definition option_def_sh2_dynarec = {
APPNAME"_sh2_dynarec",
"SH-2 Dynarec",
NULL,
"Restart core required. Recompile the SH-2 code (offered only for the games that support it, on x86 and ARM hosts, 32 and 64-bit, that allow it); turn it off to use the interpreter.",
NULL,
NULL,
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL },
},
"disabled"
};
static struct retro_core_option_v2_definition option_def_stv_video_threads = {
APPNAME"_stv_video_threads",
"ST-V Threaded Video",
NULL,
"Draw the ST-V screen in horizontal bands on several threads (same picture, faster on multi-core hosts).",
NULL,
NULL,
{
{ "disabled", NULL },
{ "2", NULL },
{ "3", NULL },
{ "4", NULL },
{ NULL, NULL },
},
"disabled"
};
static struct retro_core_option_v2_definition option_def_adsp_dynarec = {
APPNAME"_adsp_dynarec",
"ADSP Dynarec",
@@ -972,6 +1023,8 @@ void init_core_options(void)
default_options[OPT_ADSP_DYNAREC] = option_def_adsp_dynarec;
default_options[OPT_SH3_DYNAREC] = option_def_sh3_dynarec;
default_options[OPT_TX1_SCREENS] = option_def_tx1_screens;
default_options[OPT_SH2_DYNAREC] = option_def_sh2_dynarec;
default_options[OPT_STV_VIDEO_THREADS] = option_def_stv_video_threads;
default_options[OPT_OVERRIDE_AD_STICK] = option_def_override_ad_stick;
default_options[OPT_INPUT_TOGGLE] = option_def_input_toggle;
#if (HAS_CYCLONE || HAS_DRZ80)
@@ -1030,6 +1083,14 @@ static void set_variables(void)
if(!options.content_flags[CONTENT_SH3_DYNAREC])
continue; /* only offered for the games that use the recompiler */
break;
case OPT_SH2_DYNAREC:
if(!options.content_flags[CONTENT_SH2_DYNAREC])
continue; /* only offered for the games that use the recompiler */
break;
case OPT_STV_VIDEO_THREADS:
if(!options.content_flags[CONTENT_STV_VIDEO_THREADS])
continue; /* ST-V only, where threads are compiled in */
break;
case OPT_NEOGEO_BIOS:
if(!options.content_flags[CONTENT_NEOGEO])
continue; /* only offer BIOS selection when it is relevant */
@@ -1203,8 +1264,8 @@ void update_variables(bool first_time)
case OPT_STV_BIOS:
if(!options.content_flags[CONTENT_STV])
break;
if(options.content_flags[CONTENT_DIEHARD]) /* catch required bios for this one game. */
options.bios = "us";
if(stv_required_bios(game_driver->name)) /* a game that only runs with one region's BIOS */
options.bios = stv_required_bios(game_driver->name);
else
options.bios = (strcmp(var.value, "default") == 0) ? NULL : var.value;
break;
@@ -1345,6 +1406,17 @@ void update_variables(bool first_time)
options.mips_dynarec = false;
break;
case OPT_SH2_DYNAREC:
if(strcmp(var.value, "enabled") == 0)
options.sh2_dynarec = true;
else
options.sh2_dynarec = false;
break;
case OPT_STV_VIDEO_THREADS:
options.stv_video_threads = atoi(var.value); /* 0 for "disabled" */
break;
case OPT_ADSP_DYNAREC:
if(strcmp(var.value, "enabled") == 0)
options.adsp_dynarec = true;
@@ -1566,6 +1638,23 @@ void set_content_flags(void)
&& strcmp(game_driver->name, "buggyboyjr") != 0)
options.content_flags[CONTENT_TX1_SCREENS] = true;
/************ SEGA ST-V: SH-2 RECOMPILER ************/
/* the option means nothing where the recompiler is compiled out */
#if (HAS_SH2)
{
extern int sh2_jit_available(void);
if (game_driver->source_file && strstr(game_driver->source_file, "stv.c") && sh2_jit_available())
options.content_flags[CONTENT_SH2_DYNAREC] = true;
}
#endif
#if (HAS_SH2)
{
extern int stv_video_threads_available(void);
if (game_driver->source_file && strstr(game_driver->source_file, "stv.c") && stv_video_threads_available())
options.content_flags[CONTENT_STV_VIDEO_THREADS] = true;
}
#endif
/************ DRIVERS WITH MULTIPLE BIOS OPTIONS ************/
#ifndef SPLIT_CORE
{
@@ -1594,10 +1683,6 @@ void set_content_flags(void)
options.content_flags[CONTENT_MIPS_DYNAREC] = true;
#endif
/************ DIE HARD: ARCADE ************/
if(strcasecmp(game_driver->name, "diehard") == 0)
options.content_flags[CONTENT_DIEHARD] = true;
/************ DRIVERS WITH VECTOR VIDEO DISPLAYS ************/
if(Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)
options.content_flags[CONTENT_VECTOR] = true;
@@ -1766,7 +1851,8 @@ void set_content_flags(void)
if(options.content_flags[CONTENT_NEOGEO]) log_cb(RETRO_LOG_INFO, LOGPRE "* Neo Geo BIOS required.\n");
if(options.content_flags[CONTENT_STV]) log_cb(RETRO_LOG_INFO, LOGPRE "* STV BIOS required.\n");
if(options.content_flags[CONTENT_DIEHARD]) log_cb(RETRO_LOG_INFO, LOGPRE "* Die Hard: Arcade BIOS required.\n");
if(options.content_flags[CONTENT_STV] && stv_required_bios(game_driver->name))
log_cb(RETRO_LOG_INFO, LOGPRE "* ST-V BIOS forced: %s.\n", stv_required_bios(game_driver->name));
if(options.content_flags[CONTENT_ALT_SOUND]) log_cb(RETRO_LOG_INFO, LOGPRE "* Alternative soundtrack available.\n");
if(options.content_flags[CONTENT_VECTOR]) log_cb(RETRO_LOG_INFO, LOGPRE "* Vector display.\n");
+2
View File
@@ -247,6 +247,8 @@ enum CORE_OPTIONS /* controls the order in which core options appear. common, i
OPT_ADSP_DYNAREC,
OPT_SH3_DYNAREC,
OPT_TX1_SCREENS,
OPT_SH2_DYNAREC,
OPT_STV_VIDEO_THREADS,
#if (HAS_CYCLONE || HAS_DRZ80)
OPT_CYCLONE_MODE,
#endif
+36 -15
View File
@@ -163,6 +163,9 @@ struct _SLOT
} udata;
data8_t active; /*this slot is currently playing*/
data8_t *base; /*samples base address*/
data8_t *ram; /*the sound RAM, the samples wrap in it*/
data32_t ram_mask;
data32_t sa; /*samples start, in the RAM*/
data32_t cur_addr; /*current play address (24.8)*/
data32_t step; /*pitch step (24.8)*/
struct _EG EG; /*Envelope*/
@@ -207,6 +210,7 @@ struct _SCSP
struct _SCSPDSP DSP;
int MvolSet; /* MVOL written: the output follows it */
unsigned char *SCSPRAM;
data32_t SCSPRAM_mask;
char Master;
void (*Int68kCB)(int irq);
int stream;
@@ -374,6 +378,9 @@ static void SCSP_StartSlot(struct _SLOT *slot)
{
slot->active=1;
slot->base=SCSP->SCSPRAM+SA(slot);
slot->ram=SCSP->SCSPRAM;
slot->ram_mask=SCSP->SCSPRAM_mask;
slot->sa=SA(slot);
slot->cur_addr=0;
slot->step=SCSP_Step(slot);
Compute_EG(slot);
@@ -402,7 +409,7 @@ static void SCSP_Init(int n, struct SCSPinterface *intf)
for (i = 0; i < n; i++)
{
SCSP = &SCSPs[i];
memset(SCSP,0,sizeof(SCSP));
memset(SCSP,0,sizeof(*SCSP));
if (!i)
{
@@ -414,6 +421,7 @@ static void SCSP_Init(int n, struct SCSPinterface *intf)
}
SCSPs[i].SCSPRAM = memory_region(intf->region[i]);
SCSPs[i].SCSPRAM_mask = memory_region_length(intf->region[i]) - 1;
SCSPDSP_Init(&SCSPs[i].DSP, (UINT16 *)SCSPs[i].SCSPRAM, memory_region_length(intf->region[i]));
SCSPs[i].MvolSet=0;
}
@@ -700,10 +708,14 @@ static void SCSP_w16(unsigned int addr,unsigned short val)
}
else if(addr<0x600)
{
*((unsigned short *) (SCSP->udata.datab+((addr&0xff)))) = val;
if (Machine->sample_rate > 0)
/* the common registers end at 0x42f (writing past them would hit the slots) */
if((addr&0xff)<sizeof(SCSP->udata.datab))
{
SCSP_UpdateReg(addr&0xff);
*((unsigned short *) (SCSP->udata.datab+((addr&0xff)))) = val;
if (Machine->sample_rate > 0)
{
SCSP_UpdateReg(addr&0xff);
}
}
}
else if(addr>=0x700 && addr<0xc00)
@@ -739,11 +751,14 @@ static unsigned short SCSP_r16(unsigned int addr)
}
else if(addr<0x600)
{
if (Machine->sample_rate > 0)
if((addr&0xff)<sizeof(SCSP->udata.datab))
{
SCSP_UpdateRegR(addr&0xff);
if (Machine->sample_rate > 0)
{
SCSP_UpdateRegR(addr&0xff);
}
v= *((unsigned short *) (SCSP->udata.datab+((addr&0xff))));
}
v= *((unsigned short *) (SCSP->udata.datab+((addr&0xff))));
}
else if(addr>=0x700)
{
@@ -836,18 +851,18 @@ SCSPNAME(_8bit,lfo,alfo,loop)\
}\
if(_8bit)\
{\
signed char *p=(signed char *) (slot->base+(slot->cur_addr>>SHIFT));\
/* the address wraps in the sound RAM (garbage slots must not read past it) */\
data32_t o=(slot->sa+(slot->cur_addr>>SHIFT))&slot->ram_mask;\
int s2;\
signed int fpart;\
fpart=slot->cur_addr&((1<<SHIFT)-1);\
s2=(int) p[0]*((1<<SHIFT)-fpart)+(int) p[1]*fpart;\
s2=(int) (signed char) slot->ram[o]*((1<<SHIFT)-fpart)+(int) (signed char) slot->ram[(o+1)&slot->ram_mask]*fpart;\
sample=(s2>>SHIFT)<<8;\
}\
else\
{\
signed short *p=(signed short *) (slot->base+((slot->cur_addr>>(SHIFT-1))&(~1)));\
signed int fpart;\
fpart=slot->cur_addr&((1<<SHIFT)-1);\
data32_t o=(slot->sa+((slot->cur_addr>>(SHIFT-1))&(~1)))&slot->ram_mask&(~1);\
signed short *p=(signed short *) (slot->ram+o);\
sample=p[0];\
}\
slot->cur_addr+=step;\
@@ -1032,7 +1047,7 @@ static void SCSP_DoMasterSamples(int chip, int nsamples)
static void dma_scsp()
{
static UINT16 tmp_dma[2], *scsp_regs;
static UINT16 tmp_dma[3], *scsp_regs;
scsp_regs = (UINT16 *)SCSP->udata.datab;
@@ -1049,11 +1064,13 @@ static void dma_scsp()
tmp_dma[2] = scsp_regs[0x416/2];
}
/* the sound RAM and the registers directly: the CPU that started it may be
any of them (an SH-2 through the SCU), not the sound CPU */
if(scsp_ddir)
{
for(;scsp_dtlg > 0;scsp_dtlg-=2)
{
cpu_writemem24bedw_word(scsp_dmea, cpu_readmem24bedw_word(0x100000|scsp_drga));
*(UINT16 *)(SCSP->SCSPRAM + (scsp_dmea & SCSP->SCSPRAM_mask & ~1)) = SCSP_r16(scsp_drga & 0xffe);
scsp_dmea+=2;
scsp_drga+=2;
}
@@ -1062,7 +1079,7 @@ static void dma_scsp()
{
for(;scsp_dtlg > 0;scsp_dtlg-=2)
{
cpu_writemem24bedw_word(0x100000|scsp_drga,cpu_readmem24bedw_word(scsp_dmea));
SCSP_w16(scsp_drga & 0xffe, *(UINT16 *)(SCSP->SCSPRAM + (scsp_dmea & SCSP->SCSPRAM_mask & ~1)));
scsp_dmea+=2;
scsp_drga+=2;
}
@@ -1148,6 +1165,10 @@ static void SCSP_postload(void)
{
struct _SLOT *slot = &SCSPs[i].Slots[s];
slot->base = SCSPs[i].SCSPRAM ? SCSPs[i].SCSPRAM + SCSP_ss_base[i][s] : NULL;
/* the sample fetch wraps in the sound RAM: rebuild its pointers too */
slot->ram = SCSPs[i].SCSPRAM;
slot->ram_mask = SCSPs[i].SCSPRAM_mask;
slot->sa = SCSP_ss_base[i][s];
slot->PLFO.table = SCSP_lfo_table(SCSP_ss_lfo[i][s][0], 0);
slot->PLFO.scale = PSCALES[SCSP_ss_lfo[i][s][1] & 7];
slot->ALFO.table = SCSP_lfo_table(SCSP_ss_lfo[i][s][2], 1);
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+10555
View File
File diff suppressed because it is too large. Load diff