Initial commit

This commit is contained in:
Barry Harris 2011-12-03 20:27:59 +00:00
commit e4cc7bbf30
811 changed files with 804772 additions and 0 deletions

BIN
fba.chm Normal file

Binary file not shown.

71
makefile Normal file
View File

@ -0,0 +1,71 @@
# Main Makefile for FB Alpha, execute an appropriate system-specific makefile
export
#
# Declare variables
#
# Make a special build, pass the quoted text as comment (use FORCE_UPDATE declaration below to force recompilation of resources)
# SPECIALBUILD = "This text will appear in the property sheet of the .exe file"
#
# Flags. Uncomment any of these declarations to enable their function.
#
# Inluclude Unicode support
UNICODE = 1
# Build A68K ASM 68000 core
BUILD_A68K = 1
# Include x86 Assembly routines
BUILD_X86_ASM = 1
# Build for x64 targets (MinGW64 and MSVC only, this will undefine BUILD_A68K and BUILD_X86_ASM)
#BUILD_X64_EXE = 1
# Include symbols and other debug information in the executable
#SYMBOL = 1
# Include features for debugging drivers
#DEBUG = 1
# Include rom set verifying features (comment this for release builds)
#ROM_VERIFY = 1
# Force recompilation of files that need it (i.e. use __TIME__, __DATE__, SPECIALBUILD).
FORCE_UPDATE = 1
# Use the __fastcall calling convention when interfacing with A68K/Musashi/Doze
FASTCALL = 1
# Compress executable with upx (the DEBUG option ignores this)
# COMPRESS = 1
# Perl is available
PERL = 1
#
# execute an appropriate system-specific makefile
#
mingw345: FORCE
@$(MAKE) -s -f makefile.mingw GCC345=1
mingw452: FORCE
@$(MAKE) -s -f makefile.mingw GCC452=1
mingw461: FORCE
@$(MAKE) -s -f makefile.mingw GCC461=1
sdl: FORCE
@$(MAKE) -s -f makefile.sdl
vc: FORCE
@$(MAKE) -s -f makefile.vc
FORCE:

695
makefile.mingw Normal file
View File

@ -0,0 +1,695 @@
# Makefile for FBA, for use with GNU make & GCC (MinGW)
#
# The first pass makes sure all intermediary targets are present. The second pass updates
# any targets, if necessary. (Intermediary) targets which have their own unique rules
# are generated as required.
unexport
#
# Flags. Uncomment any of these declarations to enable their function.
#
# Check for changes in header files
DEPEND = 1
#
# Declare variables
#
# Specify the name of the executable file, without ".exe"
NAME = fba
ifdef BUILD_X64_EXE
ifdef BUILD_A68K
undefine BUILD_A68K
endif
ifdef BUILD_X86_ASM
undefine BUILD_X86_ASM
endif
endif
ifndef CPUTYPE
CPUTYPE = i686
endif
ifdef BUILD_X86_ASM
MMX = 1
else
MMX = 0
endif
ifndef BUILD_X86_ASM
NAME := $(NAME)n
endif
ifdef BUILD_X64_EXE
NAME = fba64
endif
ifdef DEBUG
NAME := $(NAME)d
endif
ifdef SYMBOL
NAME := $(NAME)s
endif
ifndef UNICODE
NAME := $(NAME)a
endif
ifeq ($(CPUTYPE),i686)
ppro = ppro
else
NAME := $(NAME)$(CPUTYPE)
endif
#
# Specify paths/files
#
ifdef GCC345
objdir = obj/GNU345_WIN32/$(NAME)/
endif
ifdef GCC452
objdir = obj/GNU452_WIN32/$(NAME)/
endif
ifdef GCC461
objdir = obj/GNU461_WIN32/$(NAME)/
endif
srcdir = src/
include makefile.rules
ifdef GCC345
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)depend/generated -I$(srcdir)depend/mingw/include -I- -I$(srcdir)depend/mingw/include/directx9 -I$(srcdir)depend/mingw/include/xaudio2
endif
ifdef GCC452
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)depend/generated -I$(srcdir)depend/mingw/include -I$(srcdir)depend/mingw/include/directx9 -I$(srcdir)depend/mingw/include/xaudio2
endif
ifdef GCC461
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)depend/generated -I$(srcdir)depend/mingw/include -I$(srcdir)depend/mingw/include/directx9 -I$(srcdir)depend/mingw/include/xaudio2
endif
ifdef UNICODE
# lib = -lunicows
endif
# lib += `sdl-config --libs`
lib += -luser32 -lgdi32 -lcomdlg32 -lcomctl32 -lshell32 -lwinmm -lshlwapi \
-ladvapi32 -lsetupapi -lole32 -luuid
depobj += resource.o \
autdep = $(depobj:.o=.d)
ifdef BUILD_A68K
a68k.o = $(objdir)cpu/a68k/a68k.o
endif
app_gnuc.rc = $(srcdir)depend/generated/app_gnuc.rc
license.rtf = $(srcdir)depend/generated/license.rtf
driverlist.h = $(srcdir)depend/generated/driverlist.h
ctv.h = $(srcdir)depend/generated/ctv.h
toa_gp9001_func.h = $(srcdir)depend/generated/toa_gp9001_func.h
neo_sprite_func.h = $(srcdir)depend/generated/neo_sprite_func.h
cave_tile_func.h = $(srcdir)depend/generated/cave_tile_func.h
cave_sprite_func.h = $(srcdir)depend/generated/cave_sprite_func.h
psikyo_tile_func.h = $(srcdir)depend/generated/psikyo_tile_func.h
build_details.h = $(srcdir)depend/generated/build_details.h
allobj = $(objdir)cpu/m68k/m68kcpu.o $(objdir)cpu/m68k/m68kopnz.o $(objdir)cpu/m68k/m68kopdm.o $(objdir)cpu/m68k/m68kopac.o $(objdir)cpu/m68k/m68kops.o \
$(foreach file,$(autobj:.o=.c), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .c,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.cpp), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .cpp,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.asm), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .asm,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.rc), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .rc,.o,$(wildcard $(srcdir)$(dir)/$(file)))))))
ifdef BUILD_A68K
allobj += $(a68k.o)
endif
alldep = $(foreach file,$(autobj:.o=.c), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .c,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.cpp), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .cpp,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.rc), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .rc,.d,$(wildcard $(srcdir)$(dir)/$(file)))))))
#
#
# Specify compiler/linker/assembler
#
#
CC = gcc
CXX = g++
LD = $(CXX)
AS = nasm
LDFLAGS = -static
ifdef GCC345
CFLAGS = -pipe \
-std=gnu99 -march=$(CPUTYPE) -O1 \
-mno-cygwin -mwindows \
-fforce-mem -fforce-addr -finline-limit=1200 -fthread-jumps \
-freduce-all-givs -fmove-all-movables -fexpensive-optimizations \
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
$(DEF) $(incdir) # `sdl-config --cflags`
CXXFLAGS = -pipe \
-march=$(CPUTYPE) -O3 \
-mno-cygwin -mwindows \
-fforce-mem -fforce-addr -finline-limit=1200 -fthread-jumps \
-freduce-all-givs -fmove-all-movables -fexpensive-optimizations \
-fcheck-new \
-Wall -W -pedantic -Wno-long-long \
-Wunknown-pragmas -Wundef -Wconversion -Wno-missing-braces \
-Wuninitialized -Wpointer-arith -Winline -Wno-multichar \
$(DEF) $(incdir) # `sdl-config --cflags`
endif
ifdef GCC452
CFLAGS = -pipe \
-std=gnu99 -march=$(CPUTYPE) -O1 \
-mno-cygwin -mwindows \
-fforce-addr -finline-limit=1200 -fthread-jumps \
-fexpensive-optimizations \
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
-Wno-sequence-point \
$(DEF) $(incdir) # `sdl-config --cflags`
CXXFLAGS = -pipe \
-march=$(CPUTYPE) -O1 \
-mno-cygwin -mwindows \
-fforce-addr -finline-limit=1200 -fthread-jumps \
-fexpensive-optimizations -fcheck-new \
-Wall -W -pedantic -Wshadow -Wno-long-long -Wno-write-strings \
-Wunknown-pragmas -Wundef -Wno-conversion -Wno-missing-braces -Wno-multichar \
-Wuninitialized -Wpointer-arith -Wno-inline -Wno-address -Wno-unused-value \
-Wno-sequence-point \
$(DEF) $(incdir) # `sdl-config --cflags`
endif
ifdef GCC461
CFLAGS = -pipe \
-std=gnu99 -O1 \
-mwindows \
-fforce-addr -finline-limit=1200 -fthread-jumps \
-fexpensive-optimizations \
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
-Wno-sequence-point \
$(DEF) $(incdir) # `sdl-config --cflags`
CXXFLAGS = -pipe \
-O1 \
-mwindows \
-fforce-addr -finline-limit=1200 -fthread-jumps \
-fexpensive-optimizations -fcheck-new \
-Wall -W -pedantic -Wshadow -Wno-long-long -Wno-write-strings \
-Wunknown-pragmas -Wundef -Wno-conversion -Wno-missing-braces -Wno-multichar \
-Wuninitialized -Wpointer-arith -Wno-inline -Wno-address -Wno-unused-value \
-Wno-unused-but-set-variable -Wno-sequence-point \
$(DEF) $(incdir) # `sdl-config --cflags`
ifdef BUILD_X64_EXE
CFLAGS += -m64
CXXFLAGS += -m64
LDFLAGS += -m64
else
CFLAGS += -m32
CXXFLAGS += -m32
LDFLAGS += -m32
endif
endif
ASFLAGS = -O1 -f coff -w-orphan-labels
# D3DUtils & D3DMath need these
# DEF = -Dsinf=\(float\)sin -Dcosf=\(float\)cos -Dasinf=\(float\)asin -Dacosf=\(float\)acos -Dsqrtf=\(float\)sqrt
DEF := -DBUILD_WIN32 -DUSE_SPEEDHACKS -DFILENAME=$(NAME) -DMMX=$(MMX)
ifdef UNICODE
DEF := $(DEF) -D_UNICODE
endif
ifdef SPECIALBUILD
DEF := $(DEF) -DSPECIALBUILD=$(SPECIALBUILD)
endif
ifdef FASTCALL
DEF := $(DEF) -DFASTCALL
endif
ifdef DEBUG
ifdef GCC345
CFLAGS += -mconsole
endif
ifdef GCC452
CFLAGS += -mconsole
endif
DEF := $(DEF) -DFBA_DEBUG
endif
ifdef ROM_VERIFY
DEF := $(DEF) -DROM_VERIFY
endif
ifdef BUILD_A68K
DEF := $(DEF) -DBUILD_A68K
endif
ifdef BUILD_X86_ASM
DEF := $(DEF) -DBUILD_X86_ASM
endif
ifdef BUILD_X64_EXE
DEF := $(DEF) -DBUILD_X64_EXE
endif
ifdef SYMBOL
CFLAGS += -ggdb3
ASFLAGS += -g
DEF := $(DEF) -D_DEBUG
ifdef PROFILE
CFLAGS += -pg
CXXFLAGS += -pg
else
CFLAGS += -fomit-frame-pointer
CXXFLAGS += -fomit-frame-pointer
endif
else
LDFLAGS += -s
endif
ifdef BUILD_X86_ASM
CFLAGS += -mmmx
CXXFLAGS += -mmmx
endif
# For zlib
DEF := $(DEF) -DNO_VIZ -D_LARGEFILE64_SOURCE=0 -D_FILE_OFFSET_BITS=32
#
#
# Specify paths
#
#
vpath %.asm $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.cpp $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.c $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.h $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.rc $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.o $(foreach dir,$(alldir),$(objdir)$(dir)/ )
vpath %.d $(foreach dir,$(alldir),$(objdir)$(dir)/ )
#
#
# Rules
#
#
.PHONY: all init cleandep touch clean
ifeq ($(MAKELEVEL),1)
ifdef DEPEND
all: init $(autdep) $(autobj)
ifdef GCC345
@$(MAKE) -f makefile.mingw -s GCC345=1
endif
ifdef GCC452
@$(MAKE) -f makefile.mingw -s GCC452=1
endif
ifdef GCC461
@$(MAKE) -f makefile.mingw -s GCC461=1
endif
else
all: init $(autobj)
ifdef GCC345
@$(MAKE) -f makefile.mingw -s GCC345=1
endif
ifdef GCC452
@$(MAKE) -f makefile.mingw -s GCC452=1
endif
ifdef GCC461
@$(MAKE) -f makefile.mingw -s GCC461=1
endif
endif
else
all: $(NAME).exe
endif
#
#
# Rule for linking the executable
#
#
ifeq ($(MAKELEVEL),2)
$(NAME).exe: $(allobj)
@echo
@echo Linking executable... $(NAME).exe
@$(LD) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(lib)
ifdef DEBUG
# Don't compress when making a debug build
else
ifdef COMPRESS
@upx --best $@
endif
endif
endif
ifeq ($(MAKELEVEL),1)
ifdef FORCE_UPDATE
$(build_details.h): FORCE
endif
endif
#
# Generate the gamelist
#
burn.o burn.d: driverlist.h
$(driverlist.h): $(drvobj) $(srcdir)depend/scripts/gamelist.pl
ifdef PERL
@$(srcdir)depend/scripts/gamelist.pl -o $@ -l gamelist.txt \
$(filter %.cpp,$(foreach file,$(drvobj:.o=.cpp),$(foreach dir,$(alldir), \
$(firstword $(wildcard $(srcdir)$(dir)/$(file))))))
else
ifeq ($(MAKELEVEL),2)
@echo
@echo Warning: Perl is not available on this system.
@echo $@ cannot be updated or created!
@echo
endif
endif
#
# Verify if driverlist.h needs to be updated
#
#ifeq ($(MAKELEVEL),1)
#ifdef FORCE_UPDATE
#$(driverlist.h): FORCE
#endif
#endif
#
# Fix the .rc file
#
resource.o resource.d: $(app_gnuc.rc) string.rc version.rc version.h $(build_details.h)
$(license.rtf): $(srcdir)license.txt $(srcdir)depend/scripts/license2rtf.pl
ifdef PERL
@$(srcdir)depend/scripts/license2rtf.pl $< -o $(srcdir)depend/generated/$(@F:.rc=.rtf)
else
ifeq ($(MAKELEVEL),2)
@echo
@echo Warning: Perl is not available on this system.
@echo $@ cannot be updated or created!
@echo
endif
endif
$(app_gnuc.rc): app.rc $(license.rc) $(license.rtf) $(srcdir)depend/scripts/fixrc.pl $(srcdir)burner/win32/resource/fba.ico $(srcdir)burner/win32/resource/about.bmp $(srcdir)burner/win32/resource/splash.bmp $(srcdir)burner/win32/resource/misc.bmp
ifdef PERL
@$(srcdir)depend/scripts/fixrc.pl $< -o $@
else
ifeq ($(MAKELEVEL),2)
@echo
@echo Warning: Perl is not available on this system.
@echo $@ cannot be updated or created!
@echo
endif
endif
#
# Generate some info on the build details
#
about.o about.d: $(build_details.h)
$(build_details.h): $(srcdir)depend/scripts/build_details.cpp
@$(CXX) -mconsole $(CXXFLAGS) $(LDFLAGS) $< -o $(objdir)depend/generated/build_details.exe
@$(objdir)depend/generated/build_details.exe >$@
#
# Compile 68000 cores
#
# A68K
ifdef BUILD_A68K
$(a68k.o): fba_make68k.c
@echo Compiling A68K MC68000 core...
@$(CC) -mconsole $(CFLAGS) $(LDFLAGS) -DWIN32 -Wno-unused -Wno-conversion -Wno-missing-prototypes \
-s $< -o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe)
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) $(@:.o=.asm) \
$(@D)/a68k_tab.asm 00 $(ppro)
@echo Assembling A68K MC68000 core...
@$(AS) $(ASFLAGS) $(@:.o=.asm) -o $@
endif
# Musashi
$(objdir)cpu/m68k/m68kcpu.o: $(srcdir)cpu/m68k/m68kcpu.c $(objdir)depend/generated/m68kops.h $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo Compiling Musashi MC680x0 core \(m68kcpu.c\)...
@$(CC) $(CFLAGS) -c $(srcdir)cpu/m68k/m68kcpu.c -o $(objdir)cpu/m68k/m68kcpu.o
$(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kops.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo Compiling Musashi MC680x0 core \(m68kops.c\)...
@$(CC) $(CFLAGS) -c $(objdir)depend/generated/m68kops.c -o $(objdir)cpu/m68k/m68kops.o
$(objdir)cpu/m68k/m68kopac.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kopac.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo Compiling Musashi MC680x0 core \(m68kopac.c\)...
@$(CC) $(CFLAGS) -c $(objdir)depend/generated/m68kopac.c -o $(objdir)cpu/m68k/m68kopac.o
$(objdir)cpu/m68k/m68kopdm.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kopdm.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo Compiling Musashi MC680x0 core \(m68kopdm.c\)...
@$(CC) $(CFLAGS) -c $(objdir)depend/generated/m68kopdm.c -o $(objdir)cpu/m68k/m68kopdm.o
$(objdir)cpu/m68k/m68kopnz.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kopnz.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo Compiling Musashi MC680x0 core \(m68kopnz.c\)...
@$(CC) $(CFLAGS) -c $(objdir)depend/generated/m68kopnz.c -o $(objdir)cpu/m68k/m68kopnz.o
$(objdir)depend/generated/m68kops.h: $(objdir)cpu/m68k/m68kmake.exe $(srcdir)cpu/m68k/m68k_in.c
$(objdir)/cpu/m68k/m68kmake $(objdir)depend/generated/ $(srcdir)cpu/m68k/m68k_in.c
$(objdir)cpu/m68k/m68kmake.exe: $(srcdir)cpu/m68k/m68kmake.c
@echo Compiling Musashi MC680x0 core \(m68kmake.c\)...
@$(CC) $(CFLAGS) $(srcdir)cpu/m68k/m68kmake.c -o $(objdir)cpu/m68k/m68kmake.exe
#
# Extra rules for generated header file cvt.h, needed by ctv.cpp
#
ctv.d ctv.o: $(ctv.h)
$(ctv.h): ctv_make.cpp
@echo Generating $(srcdir)depend/generated/$(@F)...
@$(CC) -mconsole $(CXXFLAGS) $(LDFLAGS) $< \
-o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe)
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
#
# Extra rules for generated header file toa_gp9001_func.h, needed by toa_gp9001.cpp
#
toa_bcu2.d toa_bcu2.o toa_gp9001.d toa_gp9001.o: $(toa_gp9001_func.h)
$(toa_gp9001_func.h): $(srcdir)depend/scripts/toa_gp9001_func.pl
@$(srcdir)depend/scripts/toa_gp9001_func.pl -o $(toa_gp9001_func.h)
#
# Extra rules for generated header file neo_sprite_func.h, needed by neo_sprite.cpp
#
neo_sprite.d neo_sprite.o: $(neo_sprite_func.h)
$(neo_sprite_func.h): $(srcdir)depend/scripts/neo_sprite_func.pl
@$(srcdir)depend/scripts/neo_sprite_func.pl -o $(neo_sprite_func.h)
#
# Extra rules for generated header file cave_tile_func.h, needed by cave_tile.cpp
#
cave_tile.d cave_tile.o: $(cave_tile_func.h)
$(cave_tile_func.h): $(srcdir)depend/scripts/cave_tile_func.pl
@$(srcdir)depend/scripts/cave_tile_func.pl -o $(cave_tile_func.h)
#
# Extra rules for generated header file cave_sprite_func.h, needed by cave_sprite.cpp
#
cave_sprite.d cave_sprite.o: $(cave_sprite_func.h)
$(cave_sprite_func.h): $(srcdir)depend/scripts/cave_sprite_func.pl
@$(srcdir)depend/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
#
# Extra rules for generated header file psikyo_tile_func.h / psikyo_sprite_func.h, needed by psikyo_tile.cpp / psikyo_sprite.cpp
#
psikyo_tile.d psikyo_tile.o psikyosprite.d psikyo_sprite.o: $(psikyo_tile_func.h)
$(psikyo_tile_func.h): $(srcdir)depend/scripts/psikyo_tile_func.pl
$(srcdir)depend/scripts/psikyo_tile_func.pl -o $(psikyo_tile_func.h)
ifeq ($(MAKELEVEL),2)
ifdef DEPEND
include $(alldep)
endif
endif
#
# Generic rule for resource files
#
%.o: %.rc
@echo Compiling resource file $(<F)...
ifdef GCC345
@windres $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
endif
ifdef GCC452
@windres $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
endif
ifdef GCC461
ifdef BUILD_X64_EXE
@windres -F pe-x86-64 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
else
@windres -F pe-i386 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
endif
endif
#
# Generic rules for C/C++ files
#
ifeq ($(MAKELEVEL),1)
%.o: %.cpp
@echo Compiling $<...
@$(CC) $(CXXFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.o: %.c
@echo Compiling $<...
@$(CC) $(CFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.o: %.asm
@echo Assembling $<...
@$(AS) $(ASFLAGS) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
else
%.o: %.c
@echo Compiling $<...
@$(CC) $(CFLAGS) -c $< -o $@
%.o: %.asm
@echo Assembling $<...
@$(AS) $(ASFLAGS) $< -o $@
%.o:
@echo Compiling $<...
@$(CC) $(CXXFLAGS) -c $< -o $@
endif
#
# Generate dependencies for C/C++ files
#
ifdef DEPEND
%.d: %.c
@echo Generating depend file for $<...
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.d: %.cpp
@echo Generating depend file for $<...
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.d: %.rc
@echo Generating depend file for $<...
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
endif
#
# Phony targets
#
init:
ifdef DEBUG
@echo Making debug build...
else
@echo Making normal build...
endif
@echo
@mkdir -p $(foreach dir, $(alldir),$(objdir)$(dir))
@mkdir -p $(srcdir)depend/generated
cleandep:
@echo Removing depend files from $(objdir)...
-@for dir in $(alldir); do rm -f $(objdir)$$dir/*.d; done
touch:
@echo Marking all targets for $(NAME) as uptodate...
-@touch $(NAME).exe
-@touch -c -r $(NAME).exe $(srcdir)/depend/generated/*
-@for dir in $(alldir); do touch -c -r $(NAME).exe $(objdir)$$dir/*; done
clean:
@echo Removing all files from $(objdir)...
-@rm -f -r $(objdir)
-@rm -f -r $(ctv.h)
ifdef PERL
@echo Removing all files generated with perl scripts...
-@rm -f -r $(app_gnuc.rc) $(driverlist)
endif
#
# Rule to force recompilation of any target that depends on it
#
FORCE:

148
makefile.rules Normal file
View File

@ -0,0 +1,148 @@
alldir = burn burn/devices burn/sound burn/drivers burn/drivers/capcom burn/drivers/cave burn/drivers/cps3 \
burn/drivers/galaxian burn/drivers/irem burn/drivers/konami burn/drivers/megadrive burn/drivers/misc_post90s \
burn/drivers/misc_pre90s burn/drivers/neogeo burn/drivers/pgm burn/drivers/psikyo burn/drivers/sega \
burn/drivers/taito burn/drivers/toaplan burner burner/win32 interface interface/scalers interface/win32 cpu \
cpu/a68k cpu/arm cpu/arm7 cpu/h6280 cpu/hd6309 cpu/i8039 cpu/konami cpu/m68k cpu/m6502 cpu/m6800 cpu/m6805 \
cpu/m6809 cpu/nec cpu/s2650 cpu/sh2 cpu/z80 depend/kaillera/client depend/libs/libpng depend/libs/zlib \
depend/generated
drvobj = d_dodonpachi.o d_donpachi.o d_esprade.o d_feversos.o d_gaia.o d_guwange.o d_hotdogst.o d_korokoro.o d_mazinger.o \
d_metmqstr.o d_pwrinst2.o d_sailormn.o d_tjumpman.o d_uopoko.o \
\
d_cps1.o \
\
d_cps2.o \
\
d_cps3.o \
\
d_galaxian.o \
\
d_m62.o d_m63.o d_m72.o d_m90.o d_m92.o \
\
d_88games.o d_ajax.o d_aliens.o d_blockhl.o d_bottom9.o d_contra.o d_crimfght.o d_gbusters.o d_gradius3.o d_hcastle.o \
d_hexion.o d_mainevt.o d_parodius.o d_rollerg.o d_simpsons.o d_spy.o d_surpratk.o d_thunderx.o d_tmnt.o d_twin16.o \
d_ultraman.o d_vendetta.o d_xmen.o \
\
d_neogeo.o \
\
d_pacman.o d_pac2650.o \
\
d_pgm.o \
\
d_psikyo.o d_psikyosh.o \
\
d_hangon.o d_outrun.o d_sys1.o d_sys16a.o d_sys16b.o d_sys18.o d_xbrd.o d_ybrd.o \
\
d_taitob.o d_taitof2.o d_taitox.o d_taitoz.o d_taitomisc.o d_asuka.o d_bublbobl.o d_darius2.o d_othunder.o \
d_slapshot.o d_superchs.o \
\
d_batrider.o d_batsugun.o d_battleg.o d_bbakraid.o d_demonwld.o d_dogyuun.o d_fixeight.o d_ghox.o d_hellfire.o \
d_kbash.o d_kbash2.o d_mahoudai.o d_outzone.o d_pipibibs.o d_rallybik.o d_samesame.o d_shippumd.o d_snowbro2.o \
d_tekipaki.o d_truxton.o d_truxton2.o d_vfive.o d_vimana.o d_zerowing.o \
\
d_4enraya.o d_1942.o d_1943.o d_ambush.o d_angelkds.o d_arabian.o d_arkanoid.o d_armedf.o d_aztarac.o d_bankp.o \
d_baraduke.o d_bionicc.o d_blktiger.o d_blockout.o d_blueprnt.o d_bombjack.o d_chaknpop.o d_commando.o d_dec0.o \
d_dec8.o d_ddragon.o d_dotrikun.o d_dynduke.o d_epos.o d_exedexes.o d_flstory.o d_funkybee.o d_galaga.o d_gauntlet.o \
d_gberet.o d_ginganin.o d_gng.o d_gunsmoke.o d_gyruss.o d_higemaru.o d_ikki.o d_jack.o d_kangaroo.o d_karnov.o \
d_kyugo.o d_ladybug.o d_lkage.o d_lwings.o d_madgear.o d_markham.o d_marineb.o d_meijinsn.o d_minivdr.o d_mitchell.o \
d_mole.o d_mrdo.o d_mrflea.o d_mystston.o d_pkunwar.o d_pooyan.o d_prehisle.o d_quizo.o d_rallyx.o d_renegade.o \
d_retofinv.o d_route16.o d_scotrsht.o d_scregg.o d_sf.o d_skyfox.o d_skykid.o d_snk68.o d_solomon.o d_sonson.o \
d_srumbler.o d_tecmo.o d_tigerheli.o d_tigeroad.o d_toki.o d_tnzs.o d_vaportra.o d_vigilant.o d_vulgus.o d_wallc.o \
d_wc90.o d_wc90b.o d_wwfsstar.o \
\
d_1945kiii.o d_aerofgt.o d_airbustr.o d_aquarium.o d_ashnojoe.o d_backfire.o d_bloodbro.o d_boogwing.o d_cbuster.o \
d_cninja.o d_crospang.o d_crshrace.o d_darkseal.o d_dassault.o d_dcon.o d_deniam.o d_ddragon3.o d_dietgogo.o \
d_diverboy.o d_drtomy.o d_egghunt.o d_esd16.o d_f1gp.o d_fstarfrc.o d_funkyjet.o d_funybubl.o d_fuukifg3.o d_gaelco.o \
d_gaiden.o d_galpanic.o d_gotcha.o d_gumbo.o d_hyperpac.o d_kaneko16.o d_lordgun.o d_mcatadv.o d_midas.o d_mogura.o \
d_mugsmash.o d_news.o d_nmg5.o d_nmk16.o d_ohmygod.o d_pass.o d_pirates.o d_pktgaldx.o d_powerins.o d_pushman.o \
d_raiden.o d_rohga.o d_seta.o d_seta2.o d_shadfrce.o d_silkroad.o d_simpl156.o d_speedspn.o d_suna16.o d_supbtime.o \
d_taotaido.o d_tecmosys.o d_tumbleb.o d_tumblep.o d_unico.o d_vmetal.o d_welltris.o d_wwfwfest.o d_xorworld.o \
d_yunsun16.o d_zerozone.o \
\
d_parent.o \
\
d_megadrive.o
depobj := about.o bzip.o cona.o debugger.o drv.o dwmapi_core.o dynhuff.o fba_kaillera.o image_win32.o inpc.o inpcheat.o inpd.o \
inpdipsw.o inps.o ips_manager.o localise.o main.o mdi.o media.o memcard.o menu.o misc_win32.o neocdlist.o neocdsel.o \
numdial.o numpluscommas.o paletteviewer.o popup_win32.o progress.o replay.o res.o roms.o run.o scrn.o sel.o sfactd.o \
splash.o stated.o support_paths.o systeminfo.o wave.o \
\
conc.o cong.o dat.o gamc.o gami.o image.o misc.o sshot.o state.o statec.o unzip.o zipfn.o \
\
adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o gzwrite.o infback.o inffast.o inflate.o inftrees.o \
trees.o uncompr.o zutil.o \
\
png.o pngerror.o pngget.o pngmem.o pngpread.o pngread.o pngrio.o pngrtran.o pngrutil.o pngset.o pngtrans.o pngwio.o \
pngwrite.o pngwtran.o pngwutil.o \
\
net.o \
\
$(drvobj) \
\
burn.o burn_gun.o burn_led.o burn_memory.o burn_sound.o burn_sound_c.o cheat.o hiscore.o load.o tiles_generic.o \
timer.o vector.o \
\
8255ppi.o eeprom.o pandora.o seibusnd.o timekpr.o \
\
ay8910.o burn_y8950.o burn_ym2151.o burn_ym2203.o burn_ym2413.o burn_ym2608.o burn_ym2610.o burn_ym2612.o \
burn_ym3526.o burn_ym3812.o burn_ymf278b.o dac.o es5506.o es8712.o fm.o fmopl.o ics2115.o iremga20.o k007232.o \
k051649.o k053260.o k054539.o msm5205.o msm6295.o namco_snd.o rf5c68.o saa1099.o samples.o segapcm.o sn76496.o \
upd7759.o x1010.o ym2151.o ym2413.o ymdeltat.o ymf278b.o ymz280b.o \
\
arm7_intf.o arm_intf.o h6280_intf.o hd6309_intf.o konami_intf.o m6502_intf.o m6800_intf.o m6805_intf.o m6809_intf.o \
s2650_intf.o sek.o vez.o zet.o \
\
arm.o arm7.o h6280.o hd6309.o i8039.o konami.o m6502.o m6800.o m6805.o m6809.o nec.o s2650.o sh2.o v25.o z80.o \
z80daisy.o \
\
aud_dsp.o aud_interface.o cd_interface.o inp_interface.o interface.o lowpass2.o prf_interface.o vid_interface.o \
vid_softfx.o vid_support.o \
\
2xpm.o 2xsai.o epx.o hq2xs.o hq2xs_16.o \
\
aud_dsound3.o aud_xaudio2.o cd_isowav.o cdsound.o ddraw_core.o dinput_core.o directx9_core.o dsound_core.o \
inp_dinput.o prf_performance_counter.o vid_d3d.o vid_ddraw.o vid_ddrawfx.o vid_directx9.o vid_directx_support.o \
\
cave.o cave_palette.o cave_sprite.o cave_tile.o \
\
cps2_crpt.o cps.o cps_config.o cps_draw.o cps_mem.o cps_obj.o cps_pal.o cps_run.o cps_rw.o cps_scr.o cpsr.o cpsrd.o \
cpst.o ctv.o kabuki.o ps.o ps_m.o ps_z.o qs.o qs_c.o qs_z.o \
\
cps3run.o cps3snd.o \
\
gal_gfx.o gal_run.o gal_sound.o gal_stars.o \
\
irem_cpu.o \
\
k051316.o k051733.o k051960.o k052109.o k053245.o k053247.o k053251.o k053936.o k054000.o konamiic.o \
\
neo_decrypt.o neo_palette.o neo_run.o neo_sprite.o neo_text.o neo_upd4990a.o neogeo.o \
\
pgm_crypt.o pgm_draw.o pgm_prot.o pgm_run.o \
\
psikyo_palette.o psikyo_sprite.o psikyo_tile.o psikyosh_render.o \
\
fd1089.o fd1094.o genesis_vid.o mc8123.o sys16_fd1094.o sys16_gfx.o sys16_run.o \
\
cchip.o pc080sn.o pc090oj.o taito.o taito_ic.o taito_m68705.o tc0100scn.o tc0110pcr.o tc0140syt.o tc0150rod.o \
tc0180vcu.o tc0220ioc.o tc0280grd.o tc0360pri.o tc0480scp.o tc0510nio.o tc0640fio.o \
\
toa_bcu2.o toa_extratext.o toa_gp9001.o toa_palette.o toaplan1.o toaplan.o \
\
tnzs_prot.o \
\
deco16ic.o nmk004.o \
\
megadrive.o \
\
ifdef DEBUG
depobj += m68kdasm.o
endif
autobj += $(depobj)
ifdef BUILD_X86_ASM
autobj += burn_sound_a.o eagle_fm.o 2xsaimmx.o hq2x32.o hq3x32.o hq4x32.o superscale.o
endif

544
makefile.vc Normal file
View File

@ -0,0 +1,544 @@
# Makefile for FBA, for use with GNU make & Microsoft Visual C++ 2010
#
# The first pass makes sure all intermediary targets are present. The second pass updates
# any targets, if necessary. (Intermediary) targets which have their own unique rules
# are generated as required.
MAKEOS = cygwin
ifeq ($(MAKEOS),)
MAKEOS = $(OSTYPE)
endif
unexport
#
# Declare variables
#
# Specify the name of the executable file, without ".exe"
NAME = fba
ifdef BUILD_X64_EXE
ifdef BUILD_A68K
undefine BUILD_A68K
endif
ifdef BUILD_X86_ASM
undefine BUILD_X86_ASM
endif
endif
ifndef CPUTYPE
CPUTYPE = i686
endif
ifdef BUILD_X86_ASM
MMX = 1
else
MMX = 0
endif
ifndef BUILD_X86_ASM
NAME := $(NAME)n
endif
ifdef BUILD_X64_EXE
NAME = fba64
endif
ifdef DEBUG
NAME := $(NAME)d
endif
ifdef SYMBOL
NAME := $(NAME)s
endif
ifndef UNICODE
NAME := $(NAME)a
endif
cpulevel = 6
ifeq ($(CPUTYPE),i586)
cpulevel = 5
endif
ifeq ($(CPUTYPE),pentium)
cpulevel = 5
endif
ifeq ($(CPUTYPE),k6)
cpulevel = 5
endif
ifeq ($(CPUTYPE),i786)
cpulevel = 7
endif
ifeq ($(CPUTYPE),pentium4)
cpulevel = 7
endif
ifeq ($(CPUTYPE),athlon)
cpulevel = 7
endif
ifeq ($(cpulevel),6)
ppro = ppro
else
NAME := $(NAME)$(CPUTYPE)
endif
#
# Specify paths/files
#
objdir = obj/VC_WIN32/$(NAME)/
srcdir = src/
include makefile.rules
incdir = $(foreach dir,$(alldir),/I$(srcdir)$(dir)) /I$(objdir)depend/generated
ifdef UNICODE
# lib = unicows.lib
endif
lib += user32.lib gdi32.lib comdlg32.lib comctl32.lib shell32.lib winmm.lib ole32.lib shlwapi.lib \
advapi32.lib setupapi.lib
ifdef BUILD_X86_ASM
autobj += hq3xs.o hq_shared32.o
endif
ifdef BUILD_A68K
a68k.o = $(objdir)cpu/a68k/a68k.o
endif
license.rtf = $(srcdir)depend/generated/license.rtf
driverlist.h = $(srcdir)depend/generated/driverlist.h
ctv.h = $(srcdir)depend/generated/ctv.h
toa_gp9001_func.h = $(srcdir)depend/generated/toa_gp9001_func.h
neo_sprite_func.h = $(srcdir)depend/generated/neo_sprite_func.h
cave_tile_func.h = $(srcdir)depend/generated/cave_tile_func.h
cave_sprite_func.h = $(srcdir)depend/generated/cave_sprite_func.h
psikyo_tile_func.h = $(srcdir)depend/generated/psikyo_tile_func.h
# psikyo_sprite_func.h = $(srcdir)depend/generated/psikyo_sprite_func.h
build_details.h = $(srcdir)depend/generated/build_details.h
allobj = $(objdir)cpu/m68k/m68kcpu.o $(objdir)cpu/m68k/m68kopnz.o $(objdir)cpu/m68k/m68kopdm.o $(objdir)cpu/m68k/m68kopac.o $(objdir)cpu/m68k/m68kops.o $(objdir)burner/win32/resource.res \
$(foreach file,$(autobj:.o=.c), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .c,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.cpp), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .cpp,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
$(foreach file,$(autobj:.o=.asm), \
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
$(firstword $(subst .asm,.o,$(wildcard $(srcdir)$(dir)/$(file)))))))
ifdef BUILD_A68K
allobj += $(a68k.o)
endif
#
#
# Specify compiler/linker/assembler
#
#
CC = cl
CXX = cl
LD = link
AS = nasm
incdir += /Isrc\depend\VC\include
ifndef BUILD_X64_EXE
LDFLAGS = /NOLOGO /INCREMENTAL:NO /MACHINE:X86 /LIBPATH:src\VC\lib /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcd.lib # /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:libcp.lib /NODEFAULTLIB:libcpd.lib /NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:libcpmtd.lib
else
LDFLAGS = /NOLOGO /INCREMENTAL:NO /MACHINE:X64 /LIBPATH:src\VC\lib /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcd.lib # /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:libcp.lib /NODEFAULTLIB:libcpd.lib /NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:libcpmtd.lib
endif
ASFLAGS = -O1 -f coff -w-orphan-labels
DEF = /DBUILD_WIN32 /DUSE_SPEEDHACKS /DFILENAME=$(NAME) /DMMX=$(MMX) /DZLIB_WINAPI /DDECL_SPEC=__cdecl
ifdef UNICODE
DEF := $(DEF) /D_UNICODE
endif
ifdef SPECIALBUILD
DEF := $(DEF) /DSPECIALBUILD=$(SPECIALBUILD)
endif
ifdef FASTCALL
DEF := $(DEF) /DFASTCALL
endif
ifdef DEBUG
DEF := $(DEF) /DFBA_DEBUG
endif
ifdef ROM_VERIFY
DEF := $(DEF) /DROM_VERIFY
endif
ifdef BUILD_A68K
DEF := $(DEF) -DBUILD_A68K
endif
ifdef BUILD_X86_ASM
DEF := $(DEF) -DBUILD_X86_ASM
endif
ifdef BUILD_X64_EXE
DEF := $(DEF) -DBUILD_X64_EXE
endif
ifdef SYMBOL
CFLAGS = /nologo /Od /GF /GS /RTC1 /Zi /Zc:forScope /MTd /EHsc /Fp$(objdir)/depend/generated/ # /Wall
ASFLAGS += -g
LDFLAGS += /DEBUG
DEF := $(DEF) /D_DEBUG
ifdef PROFILE
CFLAGS += /Oy
else
CFLAGS += /Oy-
endif
else
CFLAGS = /nologo /w /O2 /Ox /Oi /Ot /Oy /Ob2 /GF /Gs /Gy /GL /Gr /Zc:forScope /MT /EHsc
LDFLAGS += /LTCG:STATUS
endif
# Change the priority of some warnings so they are only shown at warning level 4. They are:
# lvl4 C4127: conditional expression is constant
# lvl4 C4201: nonstandard extension used : nameless struct/union
# lvl1 C4244: 'variable' : conversion from 'type' to 'type', possible loss of data
# 3 'conversion' conversion from 'type1' to 'type2', possible loss of data
# lvl4 C4505: 'function' : unreferenced local function has been removed
# lvl4 C4514: 'function' : unreferenced inline function has been removed
# lvl4 C4611: interaction between 'function' and C++ object destruction is non-portable
# lvl4 C4710: 'function' : function not inlined
# lvl1 C4799: No EMMS at end of function 'function'
# lvl3 C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning)
CFLAGS += /w44201 /w44127 /w44244 /w44505 /w44514 /w44611 /w44710 /w44799 /w44800 $(DEF) $(incdir)
CXXFLAGS = $(CFLAGS)
#
#
# Specify paths
#
#
vpath %.asm $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.cpp $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.c $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.h $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.rc $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
vpath %.o $(foreach dir,$(alldir),$(objdir)$(dir)/ )
vpath %.res $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
#
#
# Rules
#
#
.PHONY: all init cleandep touch clean
ifeq ($(MAKELEVEL),1)
all: init $(autobj) resource.res
$(MAKE) -f makefile.vc
else
all: $(NAME).exe
endif
#
#
# Rule for linking the executable
#
#
ifeq ($(MAKELEVEL),2)
$(NAME).exe: $(allobj)
@echo
@echo Linking executable $(NAME).exe...
$(LD) $(LDFLAGS) /OUT:$@ $^ $(lib)
ifdef DEBUG
# Don't compress when making a debug build
else
ifdef COMPRESS
@upx --best $@
endif
endif
endif
ifeq ($(MAKELEVEL),1)
ifdef FORCE_UPDATE
$(build_details.h): FORCE
endif
endif
#
# Generate the gamelist
#
burn.o burn.d: driverlist.h
$(driverlist.h): $(drvobj) $(srcdir)depend/scripts/gamelist.pl
ifdef PERL
@$(srcdir)depend/scripts/gamelist.pl -o $@ -l gamelist.txt \
$(filter %.cpp,$(foreach file,$(drvobj:.o=.cpp),$(foreach dir,$(alldir), \
$(firstword $(wildcard $(srcdir)$(dir)/$(file))))))
else
ifeq ($(MAKELEVEL),2)
@echo
@echo Warning: Perl is not available on this system.
@echo $@ cannot be updated or created!
@echo
endif
endif
#
# Verify if driverlist.h needs to be updated
#
#ifeq ($(MAKELEVEL),1)
#ifdef FORCE_UPDATE
#$(driverlist.h): FORCE
#endif
#endif
#
# Fix the .rc file
#
resource.res resource.d: app.rc version.rc version.h $(build_details.h) $(license.rtf)
$(license.rtf): $(srcdir)license.txt $(srcdir)depend/scripts/license2rtf.pl
ifdef PERL
$(srcdir)depend/scripts/license2rtf.pl $< -o $(srcdir)depend/generated/$(@F:.rc=.rtf)
else
ifeq ($(MAKELEVEL),2)
@echo
@echo Warning: Perl is not available on this system.
@echo $@ cannot be updated or created!
@echo
endif
endif
resource.rc: app.rc $(license.rc) $(srcdir)burner/win32/resource/fba.ico $(srcdir)burner/win32/resource/about.bmp $(srcdir)burner/win32/resource/splash.bmp $(srcdir)burner/win32/resource/misc.bmp
#
# Generate some info on the build details
#
about.o about.d systeminfo.o systeminfo.d: $(build_details.h)
$(build_details.h): $(srcdir)depend/scripts/build_details.cpp
$(CC) $(CFLAGS) $< /Fo$(objdir)depend/generated/ /Fe$(objdir)depend/generated/build_details.exe
$(objdir)depend/generated/build_details.exe >$@
#
# Compile 68000 cores
#
# A68K
ifdef BUILD_A68K
$(a68k.o): fba_make68k.c
echo "Compiling A68K MC68000 core... "
$(CC) $(CFLAGS) -DWIN32 $< /Fo$(subst $(srcdir),$(objdir),$(<D))/ /Fe$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) /link $(LDFLAGS) /SUBSYSTEM:CONSOLE
$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) $(@:.o=.asm) $(@D)/a68k_tab.asm 00 $(ppro)
@echo Assembling A68K MC68000 core...
$(AS) $(ASFLAGS) $(@:.o=.asm) -o $@
endif
# Musashi
$(objdir)cpu/m68k/m68kcpu.o: $(srcdir)cpu/m68k/m68kcpu.c $(objdir)depend/generated/m68kops.h $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo "Compiling Musashi MC680x0 core... "
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(srcdir)cpu/m68k/m68kcpu.c /Fo$(objdir)cpu/m68k/m68kcpu.o
$(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kops.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo "Compiling Musashi MC680x0 core... "
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)depend/generated/m68kops.c /Fo$(objdir)cpu/m68k/m68kops.o
$(objdir)cpu/m68k/m68kopac.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kopac.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo "Compiling Musashi MC680x0 core... "
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)depend/generated/m68kopac.c /Fo$(objdir)cpu/m68k/m68kopac.o
$(objdir)cpu/m68k/m68kopdm.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kopdm.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo "Compiling Musashi MC680x0 core... "
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)depend/generated/m68kopdm.c /Fo$(objdir)cpu/m68k/m68kopdm.o
$(objdir)cpu/m68k/m68kopnz.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)depend/generated/m68kops.h $(objdir)depend/generated/m68kopnz.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
@echo "Compiling Musashi MC680x0 core... "
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)depend/generated/m68kopnz.c /Fo$(objdir)cpu/m68k/m68kopnz.o
$(objdir)depend/generated/m68kops.h: $(objdir)cpu/m68k/m68kmake.exe $(srcdir)cpu/m68k/m68k_in.c
$(objdir)/cpu/m68k/m68kmake $(objdir)depend/generated/ $(srcdir)cpu/m68k/m68k_in.c
$(objdir)cpu/m68k/m68kmake.exe: $(srcdir)cpu/m68k/m68kmake.c
@echo "Compiling Musashi MC680x0 core... "
$(CC) $(CFLAGS) /DINLINE="__inline static" $(srcdir)cpu/m68k/m68kmake.c /Fo$(objdir)cpu/m68k/ /Fe$(objdir)cpu/m68k/m68kmake.exe /link $(LDFLAGS) /SUBSYSTEM:CONSOLE
#
# Extra rules for generated header file cvt.h, needed by ctv.cpp
#
ctv.o: $(ctv.h)
$(ctv.h): ctv_make.cpp
@echo Generating... $(srcdir)depend/generated/$(@F)
$(CC) $(CXXFLAGS) $< /Fo$(subst $(srcdir),$(objdir),$(<D))/ /Fe$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) /link $(LDFLAGS) /SUBSYSTEM:CONSOLE
$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
#
# Extra rules for generated header file toa_gp9001_func.h, needed by toa_gp9001.cpp
#
toa_bcu2.o toa_gp9001.o: $(toa_gp9001_func.h)
$(toa_gp9001_func.h): $(srcdir)depend/scripts/toa_gp9001_func.pl
$(srcdir)depend/scripts/toa_gp9001_func.pl -o $(toa_gp9001_func.h)
#
# Extra rules for generated header file neo_sprite_func.h, needed by neo_sprite.cpp
#
neo_sprite.o: $(neo_sprite_func.h)
$(neo_sprite_func.h): $(srcdir)depend/scripts/neo_sprite_func.pl
$(srcdir)depend/scripts/neo_sprite_func.pl -o $(neo_sprite_func.h)
#
# Extra rules for generated header file cave_tile_func.h, needed by cave_tile.cpp
#
cave_tile.o: $(cave_tile_func.h)
$(cave_tile_func.h): $(srcdir)depend/scripts/cave_tile_func.pl
$(srcdir)depend/scripts/cave_tile_func.pl -o $(cave_tile_func.h)
#
# Extra rules for generated header file cave_sprite_func.h, needed by cave_sprite.cpp
#
cave_sprite.o: $(cave_sprite_func.h)
$(cave_sprite_func.h): $(srcdir)depend/scripts/cave_sprite_func.pl
$(srcdir)depend/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
#
# Extra rules for generated header file psikyo_tile_func.h / psikyo_sprite_func.h, needed by psikyo_tile.cpp / psikyo_sprite.cpp
#
psikyo_tile.o psikyo_sprite.o: $(psikyo_tile_func.h)
$(psikyo_tile_func.h): $(srcdir)depend/scripts/psikyo_tile_func.pl
$(srcdir)depend/scripts/psikyo_tile_func.pl -o $(psikyo_tile_func.h)
#
# Generic rule for resource files
#
%.res: %.rc
@echo Compiling resource file... $(<F)
rc $(DEF) /n /Fo $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(incdir) $<
#
# Generic rules for C/C++ files
#
ifeq ($(MAKELEVEL),1)
%.o: %.cpp
@echo Compiling $<...
@$(CC) $(CXXFLAGS) /c $< /Fo$(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.o: %.c
@echo Compiling $<...
@$(CC) $(CFLAGS) /c /Dinline=__inline $< /Fo$(subst $(srcdir),$(objdir),$(<D))/$(@F)
%.o: %.asm
@echo Assembling $<...
@$(AS) $(ASFLAGS) $< -o$(subst $(srcdir),$(objdir),$(<D))/$(@F)
else
%.o: %.c
@echo Compiling $<...
@$(CC) $(CFLAGS) /c /Dinline=__inline $< /Fo $@
%.o: %.asm
@echo Assembling $<...
@$(AS) $(ASFLAGS) $< -o $@
%.o:
@echo Compiling $<...
@$(CC) $(CXXFLAGS) /c $< /Fo $@
endif
#
# Phony targets
#
init:
ifdef DEBUG
@echo Making debug build...
else
@echo Making normal build...
endif
@echo
ifeq ($(MAKEOS),cygwin)
@mkdir -p $(foreach dir, $(alldir),$(objdir)$(dir))
@mkdir -p $(srcdir)depend/generated
else
@echo nt
@mkdir $(foreach dir, $(alldir),$(objdir)$(dir))
@mkdir $(srcdir)depend/generated
endif
touch:
@echo Marking all targets for $(NAME) as uptodate...
-@touch $(NAME).exe
-@touch -c -r $(NAME).exe $(srcdir)/depend/generated/*
-@for dir in $(alldir); do touch -c -r $(NAME).exe $(objdir)$$dir/*; done
clean:
@echo Removing all files from $(objdir)...
ifeq ($(MAKEOS),cygwin)
-@rm -f -r $(objdir)
-@rm -f -r $(ctv.h)
else
-@del -f -s $(objdir)
-@del -f -s $(ctv.h)
endif
ifdef PERL
@echo Removing all files generated with perl scripts...
ifeq ($(MAKEOS),cygwin)
-@rm -f -r $(driverlist)
else
-@del -f -s $(driverlist)
endif
endif
#
# Rule to force recompilation of any target that depends on it
#
FORCE:

BIN
preset-example.zip Normal file

Binary file not shown.

100
src/burn/bitswap.h Normal file
View File

@ -0,0 +1,100 @@
#define BITSWAP32(n, \
bit31, bit30, bit29, bit28, bit27, bit26, bit25, bit24, \
bit23, bit22, bit21, bit20, bit19, bit18, bit17, bit16, \
bit15, bit14, bit13, bit12, bit11, bit10, bit09, bit08, \
bit07, bit06, bit05, bit04, bit03, bit02, bit01, bit00) \
(((((n) >> (bit31)) & 1) << 31) | \
((((n) >> (bit30)) & 1) << 30) | \
((((n) >> (bit29)) & 1) << 29) | \
((((n) >> (bit28)) & 1) << 28) | \
((((n) >> (bit27)) & 1) << 27) | \
((((n) >> (bit26)) & 1) << 26) | \
((((n) >> (bit25)) & 1) << 25) | \
((((n) >> (bit24)) & 1) << 24) | \
((((n) >> (bit23)) & 1) << 23) | \
((((n) >> (bit22)) & 1) << 22) | \
((((n) >> (bit21)) & 1) << 21) | \
((((n) >> (bit20)) & 1) << 20) | \
((((n) >> (bit19)) & 1) << 19) | \
((((n) >> (bit18)) & 1) << 18) | \
((((n) >> (bit17)) & 1) << 17) | \
((((n) >> (bit16)) & 1) << 16) | \
((((n) >> (bit15)) & 1) << 15) | \
((((n) >> (bit14)) & 1) << 14) | \
((((n) >> (bit13)) & 1) << 13) | \
((((n) >> (bit12)) & 1) << 12) | \
((((n) >> (bit11)) & 1) << 11) | \
((((n) >> (bit10)) & 1) << 10) | \
((((n) >> (bit09)) & 1) << 9) | \
((((n) >> (bit08)) & 1) << 8) | \
((((n) >> (bit07)) & 1) << 7) | \
((((n) >> (bit06)) & 1) << 6) | \
((((n) >> (bit05)) & 1) << 5) | \
((((n) >> (bit04)) & 1) << 4) | \
((((n) >> (bit03)) & 1) << 3) | \
((((n) >> (bit02)) & 1) << 2) | \
((((n) >> (bit01)) & 1) << 1) | \
((((n) >> (bit00)) & 1) << 0))
#define BITSWAP24(n, \
bit23, bit22, bit21, bit20, bit19, bit18, bit17, bit16, \
bit15, bit14, bit13, bit12, bit11, bit10, bit09, bit08, \
bit07, bit06, bit05, bit04, bit03, bit02, bit01, bit00) \
(((((n) >> (bit23)) & 1) << 23) | \
((((n) >> (bit22)) & 1) << 22) | \
((((n) >> (bit21)) & 1) << 21) | \
((((n) >> (bit20)) & 1) << 20) | \
((((n) >> (bit19)) & 1) << 19) | \
((((n) >> (bit18)) & 1) << 18) | \
((((n) >> (bit17)) & 1) << 17) | \
((((n) >> (bit16)) & 1) << 16) | \
((((n) >> (bit15)) & 1) << 15) | \
((((n) >> (bit14)) & 1) << 14) | \
((((n) >> (bit13)) & 1) << 13) | \
((((n) >> (bit12)) & 1) << 12) | \
((((n) >> (bit11)) & 1) << 11) | \
((((n) >> (bit10)) & 1) << 10) | \
((((n) >> (bit09)) & 1) << 9) | \
((((n) >> (bit08)) & 1) << 8) | \
((((n) >> (bit07)) & 1) << 7) | \
((((n) >> (bit06)) & 1) << 6) | \
((((n) >> (bit05)) & 1) << 5) | \
((((n) >> (bit04)) & 1) << 4) | \
((((n) >> (bit03)) & 1) << 3) | \
((((n) >> (bit02)) & 1) << 2) | \
((((n) >> (bit01)) & 1) << 1) | \
((((n) >> (bit00)) & 1) << 0))
#define BITSWAP16(n, \
bit15, bit14, bit13, bit12, bit11, bit10, bit09, bit08, \
bit07, bit06, bit05, bit04, bit03, bit02, bit01, bit00) \
(((((n) >> (bit15)) & 1) << 15) | \
((((n) >> (bit14)) & 1) << 14) | \
((((n) >> (bit13)) & 1) << 13) | \
((((n) >> (bit12)) & 1) << 12) | \
((((n) >> (bit11)) & 1) << 11) | \
((((n) >> (bit10)) & 1) << 10) | \
((((n) >> (bit09)) & 1) << 9) | \
((((n) >> (bit08)) & 1) << 8) | \
((((n) >> (bit07)) & 1) << 7) | \
((((n) >> (bit06)) & 1) << 6) | \
((((n) >> (bit05)) & 1) << 5) | \
((((n) >> (bit04)) & 1) << 4) | \
((((n) >> (bit03)) & 1) << 3) | \
((((n) >> (bit02)) & 1) << 2) | \
((((n) >> (bit01)) & 1) << 1) | \
((((n) >> (bit00)) & 1) << 0))
#define BITSWAP08(n, \
bit07, bit06, bit05, bit04, bit03, bit02, bit01, bit00) \
(((((n) >> (bit07)) & 1) << 7) | \
((((n) >> (bit06)) & 1) << 6) | \
((((n) >> (bit05)) & 1) << 5) | \
((((n) >> (bit04)) & 1) << 4) | \
((((n) >> (bit03)) & 1) << 3) | \
((((n) >> (bit02)) & 1) << 2) | \
((((n) >> (bit01)) & 1) << 1) | \
((((n) >> (bit00)) & 1) << 0))
#define BYTE_XOR_LE(a) ((a))
#define BIT(x,n) (((x)>>(n))&1)

1091
src/burn/burn.cpp Normal file

File diff suppressed because it is too large Load Diff

507
src/burn/burn.h Normal file
View File

@ -0,0 +1,507 @@
// FB Alpha - Emulator for MC68000/Z80 based arcade games
// Refer to the "license.txt" file for more info
// Burner emulation library
#ifdef __cplusplus
extern "C" {
#endif
#if !defined (_WIN32)
#define __cdecl
#endif
#include <time.h>
#ifndef MAX_PATH
#define MAX_PATH (260)
#endif
extern TCHAR szAppHiscorePath[MAX_PATH];
extern TCHAR szAppSamplesPath[MAX_PATH];
// Enable the MAME logerror() function in debug builds
// #define MAME_USE_LOGERROR
// Give access to the CPUID function for various compilers
#if defined (__GNUC__)
#define CPUID(f,ra,rb,rc,rd) __asm__ __volatile__ ("cpuid" \
: "=a" (ra), "=b" (rb), "=c" (rc), "=d" (rd) \
: "a" (f) \
);
#elif defined (_MSC_VER)
#define CPUID(f,ra,rb,rc,rd) __asm { __asm mov eax, f \
__asm cpuid \
__asm mov ra, eax \
__asm mov rb, ebx \
__asm mov rc, ecx \
__asm mov rd, edx }
#else
#define CPUID(f,ra,rb,rc,rd)
#endif
#ifndef BUILD_X86_ASM
#undef CPUID
#define CPUID(f,ra,rb,rc,rd)
#endif
#ifdef _UNICODE
#define SEPERATOR_1 " \u2022 "
#define SEPERATOR_2 " \u25E6 "
#else
#define SEPERATOR_1 " ~ "
#define SEPERATOR_2 " ~ "
#endif
#ifdef _UNICODE
#define WRITE_UNICODE_BOM(file) { UINT16 BOM[] = { 0xFEFF }; fwrite(BOM, 2, 1, file); }
#else
#define WRITE_UNICODE_BOM(file)
#endif
typedef unsigned char UINT8;
typedef signed char INT8;
typedef unsigned short UINT16;
typedef signed short INT16;
typedef unsigned int UINT32;
typedef signed int INT32;
#ifdef _MSC_VER
typedef signed __int64 INT64;
typedef unsigned __int64 UINT64;
#else
__extension__ typedef unsigned long long UINT64;
__extension__ typedef long long INT64;
#endif
#include "state.h"
#include "cheat.h"
#include "hiscore.h"
extern INT32 nBurnVer; // Version number of the library
enum BurnCartrigeCommand { CART_INIT_START, CART_INIT_END, CART_EXIT };
// ---------------------------------------------------------------------------
// Callbacks
// Application-defined rom loading function
extern INT32 (__cdecl *BurnExtLoadRom)(UINT8* Dest, INT32* pnWrote, INT32 i);
// Application-defined progress indicator functions
extern INT32 (__cdecl *BurnExtProgressRangeCallback)(double dProgressRange);
extern INT32 (__cdecl *BurnExtProgressUpdateCallback)(double dProgress, const TCHAR* pszText, bool bAbs);
// Application-defined catridge initialisation function
extern INT32 (__cdecl *BurnExtCartridgeSetupCallback)(BurnCartrigeCommand nCommand);
// Application-defined colour conversion function
extern UINT32 (__cdecl *BurnHighCol) (INT32 r, INT32 g, INT32 b, INT32 i);
// ---------------------------------------------------------------------------
extern UINT32 nCurrentFrame;
inline static INT32 GetCurrentFrame() {
return nCurrentFrame;
}
inline static void SetCurrentFrame(const UINT32 n) {
nCurrentFrame = n;
}
// ---------------------------------------------------------------------------
// Driver info structures
// ROMs
#define BRF_PRG (1 << 20)
#define BRF_GRA (1 << 21)
#define BRF_SND (1 << 22)
#define BRF_ESS (1 << 24)
#define BRF_BIOS (1 << 25)
#define BRF_SELECT (1 << 26)
#define BRF_OPT (1 << 27)
#define BRF_NODUMP (1 << 28)
struct BurnRomInfo {
char szName[100];
UINT32 nLen;
UINT32 nCrc;
UINT32 nType;
};
struct BurnSampleInfo {
char szName[100];
UINT32 nFlags;
};
// Inputs
#define BIT_DIGITAL (1)
#define BIT_GROUP_ANALOG (4)
#define BIT_ANALOG_REL (4)
#define BIT_ANALOG_ABS (5)
#define BIT_GROUP_CONSTANT (8)
#define BIT_CONSTANT (8)
#define BIT_DIPSWITCH (9)
struct BurnInputInfo {
char* szName;
UINT8 nType;
union {
UINT8* pVal; // Most inputs use a char*
UINT16* pShortVal; // All analog inputs use a short*
};
char* szInfo;
};
// DIPs
struct BurnDIPInfo {
INT32 nInput;
UINT8 nFlags;
UINT8 nMask;
UINT8 nSetting;
char* szText;
};
// ---------------------------------------------------------------------------
extern bool bBurnUseMMX;
extern bool bBurnUseASMCPUEmulation;
extern UINT32 nFramesEmulated;
extern UINT32 nFramesRendered;
extern clock_t starttime; // system time when emulation started and after roms loaded
extern bool bForce60Hz;
extern INT32 nBurnFPS;
extern INT32 nBurnCPUSpeedAdjust;
extern UINT32 nBurnDrvCount; // Count of game drivers
extern UINT32 nBurnDrvActive; // Which game driver is selected
extern UINT32 nBurnDrvSelect[8]; // Which games are selected (i.e. loaded but not necessarily active)
extern INT32 nMaxPlayers;
extern UINT8 *pBurnDraw; // Pointer to correctly sized bitmap
extern INT32 nBurnPitch; // Pitch between each line
extern INT32 nBurnBpp; // Bytes per pixel (2, 3, or 4)
extern UINT8 nBurnLayer; // Can be used externally to select which layers to show
extern UINT8 nSpriteEnable; // Can be used externally to select which Sprites to show
extern INT32 nBurnSoundRate; // Samplerate of sound
extern INT32 nBurnSoundLen; // Length in samples per frame
extern INT16* pBurnSoundOut; // Pointer to output buffer
extern INT32 nInterpolation; // Desired interpolation level for ADPCM/PCM sound
extern INT32 nFMInterpolation; // Desired interpolation level for FM sound
extern UINT32 *pBurnDrvPalette;
#define PRINT_NORMAL (0)
#define PRINT_UI (1)
#define PRINT_IMPORTANT (2)
#define PRINT_ERROR (3)
extern INT32 (__cdecl *bprintf) (INT32 nStatus, TCHAR* szFormat, ...);
INT32 BurnLibInit();
INT32 BurnLibExit();
INT32 BurnDrvInit();
INT32 BurnDrvExit();
INT32 BurnDrvCartridgeSetup(BurnCartrigeCommand nCommand);
INT32 BurnDrvFrame();
INT32 BurnDrvRedraw();
INT32 BurnRecalcPal();
INT32 BurnDrvGetPaletteEntries();
INT32 BurnSetProgressRange(double dProgressRange);
INT32 BurnUpdateProgress(double dProgressStep, const TCHAR* pszText, bool bAbs);
// ---------------------------------------------------------------------------
// Retrieve driver information
#define DRV_NAME (0)
#define DRV_DATE (1)
#define DRV_FULLNAME (2)
//#define DRV_MEDIUMNAME (3)
#define DRV_COMMENT (4)
#define DRV_MANUFACTURER (5)
#define DRV_SYSTEM (6)
#define DRV_PARENT (7)
#define DRV_BOARDROM (8)
#define DRV_SAMPLENAME (9)
#define DRV_NEXTNAME (1 << 8)
#define DRV_ASCIIONLY (1 << 12)
#define DRV_UNICODEONLY (1 << 13)
TCHAR* BurnDrvGetText(UINT32 i);
char* BurnDrvGetTextA(UINT32 i);
INT32 BurnDrvGetZipName(char** pszName, UINT32 i);
INT32 BurnDrvGetRomInfo(struct BurnRomInfo *pri, UINT32 i);
INT32 BurnDrvGetRomName(char** pszName, UINT32 i, INT32 nAka);
INT32 BurnDrvGetInputInfo(struct BurnInputInfo* pii, UINT32 i);
INT32 BurnDrvGetDIPInfo(struct BurnDIPInfo* pdi, UINT32 i);
INT32 BurnDrvGetVisibleSize(INT32* pnWidth, INT32* pnHeight);
INT32 BurnDrvGetVisibleOffs(INT32* pnLeft, INT32* pnTop);
INT32 BurnDrvGetFullSize(INT32* pnWidth, INT32* pnHeight);
INT32 BurnDrvGetAspect(INT32* pnXAspect, INT32* pnYAspect);
INT32 BurnDrvGetHardwareCode();
INT32 BurnDrvGetFlags();
bool BurnDrvIsWorking();
INT32 BurnDrvGetMaxPlayers();
INT32 BurnDrvSetVisibleSize(INT32 pnWidth, INT32 pnHeight);
INT32 BurnDrvSetAspect(INT32 pnXAspect, INT32 pnYAspect);
INT32 BurnDrvGetGenreFlags();
INT32 BurnDrvGetFamilyFlags();
INT32 BurnDrvGetSampleInfo(struct BurnSampleInfo *pri, UINT32 i);
INT32 BurnDrvGetSampleName(char** pszName, UINT32 i, INT32 nAka);
void Reinitialise();
extern bool bDoIpsPatch;
void IpsApplyPatches(UINT8* base, char* rom_name);
// ---------------------------------------------------------------------------
// Flags used with the Burndriver structure
// Flags for the flags member
#define BDF_GAME_WORKING (1 << 0)
#define BDF_ORIENTATION_FLIPPED (1 << 1)
#define BDF_ORIENTATION_VERTICAL (1 << 2)
#define BDF_BOARDROM (1 << 3)
#define BDF_CLONE (1 << 4)
#define BDF_BOOTLEG (1 << 5)
#define BDF_PROTOTYPE (1 << 6)
#define BDF_16BIT_ONLY (1 << 7)
#define BDF_HACK (1 << 8)
#define BDF_HOMEBREW (1 << 9)
#define BDF_DEMO (1 << 10)
#define BDF_HISCORE_SUPPORTED (1 << 11)
// Flags for the hardware member
// Format: 0xDDEEFFFF, where EE: Manufacturer, DD: Hardware platform, FFFF: Flags (used by driver)
#define HARDWARE_PUBLIC_MASK (0xFFFF0000)
#define HARDWARE_PREFIX_CARTRIDGE (0x80000000)
#define HARDWARE_PREFIX_MISC_PRE90S (0x00000000)
#define HARDWARE_PREFIX_CAPCOM (0x01000000)
#define HARDWARE_PREFIX_SEGA (0x02000000)
#define HARDWARE_PREFIX_KONAMI (0x03000000)
#define HARDWARE_PREFIX_TOAPLAN (0x04000000)
#define HARDWARE_PREFIX_SNK (0x05000000)
#define HARDWARE_PREFIX_CAVE (0x06000000)
#define HARDWARE_PREFIX_CPS2 (0x07000000)
#define HARDWARE_PREFIX_IGS_PGM (0x08000000)
#define HARDWARE_PREFIX_CPS3 (0x09000000)
#define HARDWARE_PREFIX_MISC_POST90S (0x0a000000)
#define HARDWARE_PREFIX_TAITO (0x0b000000)
#define HARDWARE_PREFIX_SEGA_MEGADRIVE (0x0c000000)
#define HARDWARE_PREFIX_PSIKYO (0x0d000000)
//#define HARDWARE_PREFIX_KANEKO16 (0x0e000000) // spare
#define HARDWARE_PREFIX_PACMAN (0x0f000000)
#define HARDWARE_PREFIX_GALAXIAN (0x10000000)
#define HARDWARE_PREFIX_IREM (0x20000000)
#define HARDWARE_MISC_PRE90S (HARDWARE_PREFIX_MISC_PRE90S)
#define HARDWARE_MISC_POST90S (HARDWARE_PREFIX_MISC_POST90S)
#define HARDWARE_CAPCOM_CPS1 (HARDWARE_PREFIX_CAPCOM | 0x00010000)
#define HARDWARE_CAPCOM_CPS1_QSOUND (HARDWARE_PREFIX_CAPCOM | 0x00020000)
#define HARDWARE_CAPCOM_CPS1_GENERIC (HARDWARE_PREFIX_CAPCOM | 0x00030000)
#define HARDWARE_CAPCOM_CPSCHANGER (HARDWARE_PREFIX_CAPCOM | 0x00040000)
#define HARDWARE_CAPCOM_CPS2 (HARDWARE_PREFIX_CPS2 | 0x00010000)
#define HARDWARE_CAPCOM_CPS2_SIMM (0x0002)
#define HARDWARE_SEGA_SYSTEMX (HARDWARE_PREFIX_SEGA | 0x00010000)
#define HARDWARE_SEGA_SYSTEMY (HARDWARE_PREFIX_SEGA | 0x00020000)
#define HARDWARE_SEGA_SYSTEM16A (HARDWARE_PREFIX_SEGA | 0x00030000)
#define HARDWARE_SEGA_SYSTEM16B (HARDWARE_PREFIX_SEGA | 0x00040000)
#define HARDWARE_SEGA_SYSTEM16M (HARDWARE_PREFIX_SEGA | 0x00050000)
#define HARDWARE_SEGA_SYSTEM18 (HARDWARE_PREFIX_SEGA | 0x00060000)
#define HARDWARE_SEGA_HANGON (HARDWARE_PREFIX_SEGA | 0x00070000)
#define HARDWARE_SEGA_OUTRUN (HARDWARE_PREFIX_SEGA | 0x00080000)
#define HARDWARE_SEGA_SYSTEM1 (HARDWARE_PREFIX_SEGA | 0x00090000)
#define HARDWARE_SEGA_FD1089A_ENC (0x0001)
#define HARDWARE_SEGA_FD1089B_ENC (0x0002)
#define HARDWARE_SEGA_5358 (0x0004)
#define HARDWARE_SEGA_MC8123_ENC (0x0008)
#define HARDWARE_SEGA_BAYROUTE_MEMMAP (0x0010)
#define HARDWARE_SEGA_ALT_MEMMAP (0x0020)
#define HARDWARE_SEGA_FD1094_ENC (0x0040)
#define HARDWARE_SEGA_SPRITE_LOAD32 (0x0080)
#define HARDWARE_SEGA_YM2203 (0x0100)
#define HARDWARE_SEGA_INVERT_TILES (0x0200)
#define HARDWARE_SEGA_5521 (0x0400)
#define HARDWARE_SEGA_5797 (0x0800)
#define HARDWARE_SEGA_YM2413 (0x1000)
#define HARDWARE_SEGA_FD1094_ENC_CPU2 (0x2000)
#define HARDWARE_SEGA_ISGSM (0x4000)
#define HARDWARE_SEGA_5704_PS2 (0x8000)
#define HARDWARE_KONAMI_68K_Z80 (HARDWARE_PREFIX_KONAMI | 0x00010000)
#define HARDWARE_KONAMI_68K_ONLY (HARDWARE_PREFIX_KONAMI | 0x00020000)
#define HARDWARE_TOAPLAN_RAIZING (HARDWARE_PREFIX_TOAPLAN | 0x00010000)
#define HARDWARE_TOAPLAN_68K_Zx80 (HARDWARE_PREFIX_TOAPLAN | 0x00020000)
#define HARDWARE_TOAPLAN_68K_ONLY (HARDWARE_PREFIX_TOAPLAN | 0x00030000)
#define HARDWARE_SNK_NEOGEO (HARDWARE_PREFIX_SNK | 0x00010000)
#define HARDWARE_SNK_SWAPP (0x0001) // Swap code roms
#define HARDWARE_SNK_SWAPV (0x0002) // Swap sound roms
#define HARDWARE_SNK_SWAPC (0x0004) // Swap sprite roms
#define HARDWARE_SNK_CMC42 (0x0008) // CMC42 encryption chip
#define HARDWARE_SNK_CMC50 (0x0010) // CMC50 encryption chip
#define HARDWARE_SNK_ALTERNATE_TEXT (0x0020) // KOF2000 text layer banks
#define HARDWARE_SNK_SMA_PROTECTION (0x0040) // SMA protection
#define HARDWARE_SNK_KOF2K3 (0x0080) // KOF2K3 hardware
#define HARDWARE_SNK_ENCRYPTED_M1 (0x0100) // M1 encryption
#define HARDWARE_SNK_P32 (0x0200) // SWAP32 P ROMs
#define HARDWARE_SNK_SPRITE32 (0x0400)
#define HARDWARE_SNK_CONTROLMASK (0xF000)
#define HARDWARE_SNK_JOYSTICK (0x0000) // Uses joysticks
#define HARDWARE_SNK_PADDLE (0x1000) // Uses joysticks or paddles
#define HARDWARE_SNK_TRACKBALL (0x2000) // Uses a trackball
#define HARDWARE_SNK_4_JOYSTICKS (0x3000) // Uses 4 joysticks
#define HARDWARE_SNK_MAHJONG (0x4000) // Uses a special mahjong controller
#define HARDWARE_SNK_GAMBLING (0x5000) // Uses gambling controls
#define HARDWARE_SNK_MVS (HARDWARE_PREFIX_SNK | 0x00020000)
#define HARDWARE_SNK_NEOCD (HARDWARE_PREFIX_SNK | 0x00030000)
#define HARDWARE_SNK_DEDICATED_PCB (HARDWARE_PREFIX_SNK | 0x00040000)
#define HARDWARE_CAVE_68K_ONLY (HARDWARE_PREFIX_CAVE)
#define HARDWARE_CAVE_68K_Z80 (HARDWARE_PREFIX_CAVE | 0x0001)
#define HARDWARE_CAVE_M6295 (0x0002)
#define HARDWARE_CAVE_YM2151 (0x0004)
#define HARDWARE_IGS_PGM (HARDWARE_PREFIX_IGS_PGM)
#define HARDWARE_IGS_USE_ARM_CPU (0x0001)
#define HARDWARE_CAPCOM_CPS3 (HARDWARE_PREFIX_CPS3)
#define HARDWARE_CAPCOM_CPS3_NO_CD (0x0001)
#define HARDWARE_TAITO_TAITOZ (HARDWARE_PREFIX_TAITO | 0x00010000)
#define HARDWARE_TAITO_TAITOF2 (HARDWARE_PREFIX_TAITO | 0x00020000)
#define HARDWARE_TAITO_MISC (HARDWARE_PREFIX_TAITO | 0x00030000)
#define HARDWARE_TAITO_TAITOX (HARDWARE_PREFIX_TAITO | 0x00040000)
#define HARDWARE_TAITO_TAITOB (HARDWARE_PREFIX_TAITO | 0x00050000)
#define HARDWARE_IREM_M62 (HARDWARE_PREFIX_IREM | 0x00010000)
#define HARDWARE_IREM_M63 (HARDWARE_PREFIX_IREM | 0x00020000)
#define HARDWARE_IREM_M72 (HARDWARE_PREFIX_IREM | 0x00030000)
#define HARDWARE_IREM_M90 (HARDWARE_PREFIX_IREM | 0x00040000)
#define HARDWARE_IREM_M92 (HARDWARE_PREFIX_IREM | 0x00050000)
#define HARDWARE_SEGA_MEGADRIVE (HARDWARE_PREFIX_SEGA_MEGADRIVE)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SEGA_EEPROM (1)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SEGA_SRAM (2)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SEGA_FRAM (3)
#define HARDWARE_SEGA_MEGADRIVE_PCB_CM_JCART (4)
#define HARDWARE_SEGA_MEGADRIVE_PCB_CM_JCART_SEPROM (5)
#define HARDWARE_SEGA_MEGADRIVE_PCB_CODE_MASTERS (6)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SSF2 (7)
#define HARDWARE_SEGA_MEGADRIVE_PCB_GAME_KANDUME (8)
#define HARDWARE_SEGA_MEGADRIVE_PCB_BEGGAR (9)
#define HARDWARE_SEGA_MEGADRIVE_PCB_NBA_JAM (10)
#define HARDWARE_SEGA_MEGADRIVE_PCB_NBA_JAM_TE (11)
#define HARDWARE_SEGA_MEGADRIVE_PCB_NFL_QB_96 (12)
#define HARDWARE_SEGA_MEGADRIVE_PCB_C_SLAM (13)
#define HARDWARE_SEGA_MEGADRIVE_PCB_EA_NHLPA (14)
#define HARDWARE_SEGA_MEGADRIVE_PCB_LIONK3 (15)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SDK99 (16)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SKINGKONG (17)
#define HARDWARE_SEGA_MEGADRIVE_PCB_REDCL_EN (18)
#define HARDWARE_SEGA_MEGADRIVE_PCB_RADICA (19)
#define HARDWARE_SEGA_MEGADRIVE_PCB_KOF98 (20)
#define HARDWARE_SEGA_MEGADRIVE_PCB_KOF99 (21)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SOULBLAD (22)
#define HARDWARE_SEGA_MEGADRIVE_PCB_MJLOVER (23)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SQUIRRELK (24)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SMOUSE (25)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SMB (26)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SMB2 (27)
#define HARDWARE_SEGA_MEGADRIVE_PCB_KAIJU (28)
#define HARDWARE_SEGA_MEGADRIVE_PCB_CHINFIGHT3 (29)
#define HARDWARE_SEGA_MEGADRIVE_PCB_LIONK2 (30)
#define HARDWARE_SEGA_MEGADRIVE_PCB_BUGSLIFE (31)
#define HARDWARE_SEGA_MEGADRIVE_PCB_ELFWOR (32)
#define HARDWARE_SEGA_MEGADRIVE_PCB_ROCKMANX3 (33)
#define HARDWARE_SEGA_MEGADRIVE_PCB_SBUBBOB (34)
#define HARDWARE_SEGA_MEGADRIVE_PCB_REALTEC (35)
#define HARDWARE_SEGA_MEGADRIVE_PCB_MC_SUP19IN1 (36)
#define HARDWARE_SEGA_MEGADRIVE_PCB_MC_SUP15IN1 (37)
#define HARDWARE_SEGA_MEGADRIVE_PCB_12IN1 (38)
#define HARDWARE_SEGA_MEGADRIVE_PCB_TOPFIGHTER (39)
#define HARDWARE_SEGA_MEGADRIVE_PCB_POKEMON (40)
#define HARDWARE_SEGA_MEGADRIVE_PCB_MULAN (41)
#define HARDWARE_SEGA_MEGADRIVE_SRAM_00400 (0x0100)
#define HARDWARE_SEGA_MEGADRIVE_SRAM_00800 (0x0200)
#define HARDWARE_SEGA_MEGADRIVE_SRAM_01000 (0x0400)
#define HARDWARE_SEGA_MEGADRIVE_SRAM_04000 (0x0800)
#define HARDWARE_SEGA_MEGADRIVE_SRAM_10000 (0x1000)
#define HARDWARE_SEGA_MEGADRIVE_FRAM_00400 (0x2000)
#define HARDWARE_PSIKYO (HARDWARE_PREFIX_PSIKYO)
#define HARDWARE_KANEKO16 (HARDWARE_PREFIX_KANEKO16)
#define HARDWARE_PACMAN (HARDWARE_PREFIX_PACMAN)
#define HARDWARE_GALAXIAN (HARDWARE_PREFIX_GALAXIAN)
// flags for the genre member
#define GBF_HORSHOOT (1 << 0)
#define GBF_VERSHOOT (1 << 1)
#define GBF_SCRFIGHT (1 << 2)
#define GBF_VSFIGHT (1 << 3)
#define GBF_BIOS (1 << 4)
#define GBF_BREAKOUT (1 << 5)
#define GBF_CASINO (1 << 6)
#define GBF_BALLPADDLE (1 << 7)
#define GBF_MAZE (1 << 8)
#define GBF_MINIGAMES (1 << 9)
#define GBF_PINBALL (1 << 10)
#define GBF_PLATFORM (1 << 11)
#define GBF_PUZZLE (1 << 12)
#define GBF_QUIZ (1 << 13)
#define GBF_SPORTSMISC (1 << 14)
#define GBF_SPORTSFOOTBALL (1 << 15)
#define GBF_MISC (1 << 16)
#define GBF_MAHJONG (1 << 17)
#define GBF_RACING (1 << 18)
#define GBF_SHOOT (1 << 19)
// flags for the family member
#define FBF_MSLUG (1 << 0)
#define FBF_SF (1 << 1)
#define FBF_KOF (1 << 2)
#define FBF_DSTLK (1 << 3)
#define FBF_FATFURY (1 << 4)
#define FBF_SAMSHO (1 << 5)
#define FBF_19XX (1 << 6)
#define FBF_SONICWI (1 << 7)
#define FBF_PWRINST (1 << 8)
#ifdef __cplusplus
} // End of extern "C"
#endif

159
src/burn/burn_gun.cpp Normal file
View File

@ -0,0 +1,159 @@
#include "burnint.h"
#include "burn_gun.h"
// Generic Light Gun support for FBA
// written by Barry Harris (Treble Winner) based on the code in Kev's opwolf driver
INT32 nBurnGunNumPlayers = 0;
static bool bBurnGunDrawTargets = true;
static INT32 nBurnGunMaxX = 0;
static INT32 nBurnGunMaxY = 0;
INT32 BurnGunX[MAX_GUNS];
INT32 BurnGunY[MAX_GUNS];
#define P1Colour 0xfc, 0x12, 0xee
#define P2Colour 0x1c, 0xfc, 0x1c
#define P3Colour 0x15, 0x93, 0xfd
#define P4Colour 0xf7, 0xfa, 0x0e
#define a 0,
#define b 1,
UINT8 BurnGunTargetData[18][18] = {
{ a a a a a a a a b a a a a a a a a a },
{ a a a a a a b b b b b a a a a a a a },
{ a a a a b b a a b a a b b a a a a a },
{ a a a b a a a a b a a a a b a a a a },
{ a a b a a a a a b a a a a a b a a a },
{ a a b a a a a b b b a a a a b a a a },
{ a b a a a a b b b b b a a a a b a a },
{ a b a a a b b a a a a b a a a b a a },
{ b b b b b b b a a a b b b b b b b a },
{ a b a a a b b a a a a b b a a b a a },
{ a b a a a a b a b a b b a a a b a a },
{ a a b a a a a b b b b a a a b a a a },
{ a a b a a a a a b b a a a a b a a a },
{ a a a b a a a a b a a a a b a a a a },
{ a a a a b b a a b a a b b a a a a a },
{ a a a a a a b b b b b a a a a a a a },
{ a a a a a a a a b a a a a a a a a a },
{ a a a a a a a a a a a a a a a a a a },
};
#undef b
#undef a
UINT8 BurnGunReturnX(INT32 num)
{
if (num > MAX_GUNS - 1) return 0xff;
float temp = (float)((BurnGunX[num] >> 8) + 8) / nBurnGunMaxX * 0xff;
return (UINT8)temp;
}
UINT8 BurnGunReturnY(INT32 num)
{
if (num > MAX_GUNS - 1) return 0xff;
float temp = (float)((BurnGunY[num] >> 8) + 8) / nBurnGunMaxY * 0xff;
return (UINT8)temp;
}
void BurnGunMakeInputs(INT32 num, INT16 x, INT16 y)
{
if (num > MAX_GUNS - 1) return;
const INT32 MinX = -8 * 0x100;
const INT32 MinY = -8 * 0x100;
BurnGunX[num] += x;
BurnGunY[num] += y;
if (BurnGunX[num] < MinX) BurnGunX[num] = MinX;
if (BurnGunX[num] > MinX + nBurnGunMaxX * 0x100) BurnGunX[num] = MinX + nBurnGunMaxX * 0x100;
if (BurnGunY[num] < MinY) BurnGunY[num] = MinY;
if (BurnGunY[num] > MinY + nBurnGunMaxY * 0x100) BurnGunY[num] = MinY + nBurnGunMaxY * 0x100;
}
void BurnGunInit(INT32 nNumPlayers, bool bDrawTargets)
{
if (nNumPlayers > MAX_GUNS) nNumPlayers = MAX_GUNS;
nBurnGunNumPlayers = nNumPlayers;
bBurnGunDrawTargets = bDrawTargets;
if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
BurnDrvGetVisibleSize(&nBurnGunMaxY, &nBurnGunMaxX);
} else {
BurnDrvGetVisibleSize(&nBurnGunMaxX, &nBurnGunMaxY);
}
for (INT32 i = 0; i < MAX_GUNS; i++) {
BurnGunX[i] = ((nBurnGunMaxX / 2) - 7) << 8;
BurnGunY[i] = ((nBurnGunMaxY / 2) - 8) << 8;
}
}
void BurnGunExit()
{
nBurnGunNumPlayers = 0;
bBurnGunDrawTargets = true;
nBurnGunMaxX = 0;
nBurnGunMaxY = 0;
for (INT32 i = 0; i < MAX_GUNS; i++) {
BurnGunX[i] = 0;
BurnGunY[i] = 0;
}
}
void BurnGunScan()
{
SCAN_VAR(BurnGunX);
SCAN_VAR(BurnGunY);
}
void BurnGunDrawTarget(INT32 num, INT32 x, INT32 y)
{
if (bBurnGunDrawTargets == false) return;
if (num > MAX_GUNS - 1) return;
UINT8* pTile = pBurnDraw + nBurnGunMaxX * nBurnBpp * (y - 1) + nBurnBpp * x;
UINT32 nTargetCol = 0;
if (num == 0) nTargetCol = BurnHighCol(P1Colour, 0);
if (num == 1) nTargetCol = BurnHighCol(P2Colour, 0);
if (num == 2) nTargetCol = BurnHighCol(P3Colour, 0);
if (num == 3) nTargetCol = BurnHighCol(P4Colour, 0);
for (INT32 y2 = 0; y2 < 17; y2++) {
pTile += nBurnGunMaxX * nBurnBpp;
if ((y + y2) < 0 || (y + y2) > nBurnGunMaxY - 1) {
continue;
}
for (INT32 x2 = 0; x2 < 17; x2++) {
if ((x + x2) < 0 || (x + x2) > nBurnGunMaxX - 1) {
continue;
}
if (BurnGunTargetData[y2][x2]) {
if (nBurnBpp == 2) {
((UINT16*)pTile)[x2] = (UINT16)nTargetCol;
} else {
((UINT32*)pTile)[x2] = nTargetCol;
}
}
}
}
}
#undef P1Colour
#undef P2Colour
#undef P3Colour
#undef P4Colour

15
src/burn/burn_gun.h Normal file
View File

@ -0,0 +1,15 @@
#define MAX_GUNS 4
extern INT32 nBurnGunNumPlayers;
extern INT32 BurnGunX[MAX_GUNS];
extern INT32 BurnGunY[MAX_GUNS];
UINT8 BurnGunReturnX(INT32 num);
UINT8 BurnGunReturnY(INT32 num);
extern void BurnGunInit(INT32 nNumPlayers, bool bDrawTargets);
void BurnGunExit();
void BurnGunScan();
extern void BurnGunDrawTarget(INT32 num, INT32 x, INT32 y);
extern void BurnGunMakeInputs(INT32 num, INT16 x, INT16 y);

235
src/burn/burn_led.cpp Normal file
View File

@ -0,0 +1,235 @@
#include "burnint.h"
#include "burn_led.h"
#define MAX_LED 8
static INT32 led_status[MAX_LED];
static INT32 led_count;
static INT32 led_alpha_level;
static INT32 led_alpha_level2;
static INT32 led_color;
static INT32 led_size;
static INT32 led_position0;
static INT32 led_position;
static INT32 led_xpos;
static INT32 led_ypos;
static INT32 led_xadv;
static INT32 led_yadv;
static INT32 nScreenWidth, nScreenHeight;
static INT32 screen_flipped;
static INT32 flipscreen = -1;
static inline UINT32 alpha_blend32(UINT32 d)
{
return (((((led_color & 0xff00ff) * led_alpha_level) + ((d & 0xff00ff) * led_alpha_level2)) & 0xff00ff00) |
((((led_color & 0x00ff00) * led_alpha_level) + ((d & 0x00ff00) * led_alpha_level2)) & 0x00ff0000)) >> 8;
}
static void set_led_draw_position()
{
led_position = led_position0;
if (screen_flipped ^ flipscreen) {
switch (led_position & 3) {
case LED_POSITION_TOP_LEFT: led_position = LED_POSITION_BOTTOM_RIGHT; break;
case LED_POSITION_TOP_RIGHT: led_position = LED_POSITION_BOTTOM_LEFT; break;
case LED_POSITION_BOTTOM_LEFT: led_position = LED_POSITION_TOP_RIGHT; break;
case LED_POSITION_BOTTOM_RIGHT: led_position = LED_POSITION_TOP_LEFT; break;
}
}
if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
BurnDrvGetVisibleSize(&nScreenHeight, &nScreenWidth);
led_xadv = 0;
led_yadv = led_size + 1;
switch (led_position & 3)
{
case LED_POSITION_TOP_LEFT:
led_xpos = (nScreenWidth - 1) - led_size;
led_ypos = 1;
break;
case LED_POSITION_BOTTOM_RIGHT:
led_xpos = 1;
led_ypos = (nScreenHeight - 1) - (led_yadv * led_count);
break;
case LED_POSITION_BOTTOM_LEFT:
led_xpos = 1;
led_ypos = 1;
break;
case LED_POSITION_TOP_RIGHT:
default:
led_xpos = (nScreenWidth - 1) - led_size;
led_ypos = (nScreenHeight - 1) - (led_yadv * led_count);
break;
}
} else {
BurnDrvGetVisibleSize(&nScreenWidth, &nScreenHeight);
led_xadv = led_size + 1;
led_yadv = 0;
switch (led_position & 3)
{
case LED_POSITION_BOTTOM_LEFT:
led_xpos = 1;
led_ypos = (nScreenHeight - 1) - led_size;
// led_ypos;
break;
case LED_POSITION_TOP_RIGHT:
led_xpos = (nScreenWidth - 1) - (led_xadv * led_count);
led_ypos = 1;
break;
case LED_POSITION_TOP_LEFT:
led_xpos = 1;
led_ypos = 1;
break;
case LED_POSITION_BOTTOM_RIGHT:
default:
led_xpos = (nScreenWidth - 1) - (led_xadv * led_count);
led_ypos = (nScreenHeight - 1) - led_size;
break;
}
}
}
void BurnLEDSetFlipscreen(INT32 flip)
{
flip = flip ? 1 : 0;
if (flipscreen != flip) {
flipscreen = flip;
set_led_draw_position();
}
}
void BurnLEDReset()
{
memset (led_status, 0, MAX_LED * sizeof(INT32));
BurnLEDSetFlipscreen(0);
}
void BurnLEDInit(INT32 num, INT32 position, INT32 size, INT32 color, INT32 transparency)
{
if (num >= MAX_LED) num = MAX_LED - 1;
led_count = num;
led_color = color;
led_size = size;
led_position0 = position;
led_alpha_level = (255 * transparency) / 100;
led_alpha_level2 = 256 - led_alpha_level;
screen_flipped = (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) ? 1 : 0;
BurnLEDReset();
}
void BurnLEDSetStatus(INT32 led, UINT32 status)
{
if (led >= led_count) return;
if (screen_flipped ^ flipscreen) {
led = (led_count - 1) - led;
}
led_status[led] = status ? 1 : 0;
}
void BurnLEDExit()
{
BurnLEDReset();
led_count = 0;
led_alpha_level = 0;
led_alpha_level2 = 0;
led_color = 0;
led_size = 0;
led_position = 0;
led_position0 = 0;
led_xpos = 0;
led_ypos = 0;
screen_flipped = 0;
nScreenWidth = 0;
nScreenHeight = 0;
flipscreen = -1;
}
void BurnLEDRender()
{
INT32 xpos = led_xpos;
INT32 ypos = led_ypos;
int color = BurnHighCol((led_color >> 16) & 0xff, (led_color >> 8) & 0xff, (led_color >> 0) & 0xff, 0);
for (INT32 i = 0; i < led_count; i++)
{
if (xpos < 0 || xpos > (nScreenWidth - led_size)) break;
if (led_status[i])
{
for (INT32 y = 0; y < led_size; y++)
{
UINT8 *ptr = pBurnDraw + (((ypos + y) * nScreenWidth) + xpos) * nBurnBpp;
for (INT32 x = 0; x < led_size; x++)
{
if (nBurnBpp >= 4)
{
*((UINT32*)ptr) = alpha_blend32(*((UINT32*)ptr));
}
else if (nBurnBpp == 3)
{
UINT32 t = alpha_blend32((ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
ptr[2] = t >> 16;
ptr[1] = t >> 8;
ptr[0] = t >> 0;
}
else if (nBurnBpp == 2) // alpha blend not supported for 16-bit
{
*((UINT16*)ptr) = color;
}
ptr += nBurnBpp;
}
}
}
xpos += led_xadv;
ypos += led_yadv;
}
}
INT32 BurnLEDScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin != NULL) {
*pnMin = 0x029707;
}
if (nAction & ACB_DRIVER_DATA) {
ba.Data = &led_status;
ba.nLen = led_count * sizeof(INT32);
ba.nAddress = 0;
ba.szName = "Led status";
BurnAcb(&ba);
}
return 0;
}

30
src/burn/burn_led.h Normal file
View File

@ -0,0 +1,30 @@
#define LED_COLOR_RED 0xff0000
#define LED_COLOR_GREEN 0x00ff00
#define LED_COLOR_BLUE 0x0000ff
#define LED_COLOR_WHITE 0xffffff
#define LED_COLOR_YELLOW 0xffff00
#define LED_SIZE_2x2 2
#define LED_SIZE_3x3 3
#define LED_SIZE_4x4 4
#define LED_SIZE_5x5 5
#define LED_SIZE_6x6 6
#define LED_SIZE_7x7 7
#define LED_SIZE_8x8 8
#define LED_POSITION_TOP_LEFT 0
#define LED_POSITION_TOP_RIGHT 1
#define LED_POSITION_BOTTOM_LEFT 2
#define LED_POSITION_BOTTOM_RIGHT 3
// transparency is a percentage 0 - 100
void BurnLEDInit(INT32 num, INT32 position, INT32 size, INT32 color, INT32 transparency);
void BurnLEDReset();
void BurnLEDSetStatus(INT32 led, UINT32 status);
void BurnLEDSetFlipscreen(INT32 flip);
void BurnLEDRender();
void BurnLEDExit();
INT32 BurnLEDScan(INT32 nAction, INT32 *pnMin);

74
src/burn/burn_memory.cpp Normal file
View File

@ -0,0 +1,74 @@
// FB Alpha memory management module
// The purpose of this module is to offer replacement functions for standard C/C++ ones
// that allocate and free memory. This should help deal with the problem of memory
// leaks and non-null pointers on game exit.
#include "burnint.h"
#define MAX_MEM_PTR 0x400 // more than 1024 malloc calls should be insane...
static UINT8 *memptr[MAX_MEM_PTR]; // pointer to allocated memory
// this should be called early on... BurnDrvInit?
void BurnInitMemoryManager()
{
memset (memptr, 0, MAX_MEM_PTR * sizeof(UINT8 **));
}
// should we pass the pointer as a variable here so that we can save a pointer to it
// and then ensure it is NULL'd in BurnFree or BurnExitMemoryManager?
// call instead of 'malloc'
UINT8 *BurnMalloc(INT32 size)
{
for (INT32 i = 0; i < MAX_MEM_PTR; i++)
{
if (memptr[i] == NULL) {
memptr[i] = (UINT8*)malloc(size);
if (memptr[i] == NULL) {
bprintf (0, _T("BurnMalloc failed to allocate %d bytes of memory!\n"), size);
return NULL;
}
memset (memptr[i], 0, size); // set contents to 0
return memptr[i];
}
}
bprintf (0, _T("BurnMalloc called too many times!\n"));
return NULL; // Freak out!
}
// call instead of "free"
void _BurnFree(void *ptr)
{
UINT8 *mptr = (UINT8*)ptr;
for (INT32 i = 0; i < MAX_MEM_PTR; i++)
{
if (memptr[i] == mptr) {
free (memptr[i]);
memptr[i] = NULL;
break;
}
}
}
// call in BurnDrvExit?
void BurnExitMemoryManager()
{
for (INT32 i = 0; i < MAX_MEM_PTR; i++)
{
if (memptr[i] != NULL) {
free (memptr[i]);
memptr[i] = NULL;
}
}
}

23
src/burn/burn_sound.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "burnint.h"
#include "burn_sound.h"
INT16 Precalc[4096 *4];
// Routine used to precalculate the table used for interpolation
INT32 cmc_4p_Precalc()
{
INT32 a, x, x2, x3;
for (a = 0; a < 4096; a++) {
x = a * 4; // x = 0..16384
x2 = x * x / 16384; // pow(x, 2);
x3 = x2 * x / 16384; // pow(x, 3);
Precalc[a * 4 + 0] = (INT16)(-x / 3 + x2 / 2 - x3 / 6);
Precalc[a * 4 + 1] = (INT16)(-x / 2 - x2 + x3 / 2 + 16384);
Precalc[a * 4 + 2] = (INT16)( x + x2 / 2 - x3 / 2);
Precalc[a * 4 + 3] = (INT16)(-x / 6 + x3 / 6);
}
return 0;
}

48
src/burn/burn_sound.h Normal file
View File

@ -0,0 +1,48 @@
// burn_sound.h - General sound support functions
// based on code by Daniel Moreno (ComaC) < comac2k@teleline.es >
#if defined BUILD_X86_ASM
extern "C" {
int __cdecl ChannelMix_QS_A(int* Dest, int nLen,
char* Sample, int LoopEnd,
int* Pos,
int VolL, int VolR,
int LoopLen,
int IncPos,
char* EndBuff);
void __cdecl BurnSoundCopyClamp_A(int* Src, short* Dest, int Len);
void __cdecl BurnSoundCopyClamp_Add_A(int* Src, short* Dest, int Len);
void __cdecl BurnSoundCopyClamp_Mono_A(int* Src, short* Dest, int Len);
void __cdecl BurnSoundCopyClamp_Mono_Add_A(int* Src, short* Dest, int Len);
void __cdecl BurnSoundCopy_FM_A(short* SrcL, short* SrcR, short* Dest, int Len, int VolL, int VolR);
void __cdecl BurnSoundCopy_FM_Add_A(short* SrcL, short* SrcR, short* Dest, int Len, int VolL, int VolR);
/* SrcOPN should have left channel data at SrcOPN, right channel at SrcOPN + 4096, SrcPSG should have all summed channels */
void __cdecl BurnSoundCopy_FM_OPN_A(short* SrcOPN, int* SrcPSG, short* Dest, int Len, int VolPSGL, int VolPSGR);
void __cdecl BurnSoundCopy_FM_OPN_Add_A(short* SrcOPN, int* SrcPSG, short* Dest, int Len, int VolPSGL, int VolPSGR);
}
#endif
void BurnSoundCopyClamp_C(INT32* Src, INT16* Dest, INT32 Len);
void BurnSoundCopyClamp_Add_C(INT32* Src, INT16* Dest, INT32 Len);
void BurnSoundCopyClamp_Mono_C(INT32* Src, INT16* Dest, INT32 Len);
void BurnSoundCopyClamp_Mono_Add_C(INT32* Src, INT16* Dest, INT32 Len);
extern INT32 cmc_4p_Precalc();
#ifdef __ELF__
#define Precalc _Precalc
#endif
extern "C" INT16 Precalc[];
#define INTERPOLATE4PS_8BIT(fp, sN, s0, s1, s2) (((INT32)((sN) * Precalc[(INT32)(fp) * 4 + 0]) + (INT32)((s0) * Precalc[(INT32)(fp) * 4 + 1]) + (INT32)((s1) * Precalc[(INT32)(fp) * 4 + 2]) + (INT32)((s2) * Precalc[(INT32)(fp) * 4 + 3])) / 64)
#define INTERPOLATE4PS_16BIT(fp, sN, s0, s1, s2) (((INT32)((sN) * Precalc[(INT32)(fp) * 4 + 0]) + (INT32)((s0) * Precalc[(INT32)(fp) * 4 + 1]) + (INT32)((s1) * Precalc[(INT32)(fp) * 4 + 2]) + (INT32)((s2) * Precalc[(INT32)(fp) * 4 + 3])) / 16384)
#define INTERPOLATE4PS_CUSTOM(fp, sN, s0, s1, s2, v) (((INT32)((sN) * Precalc[(INT32)(fp) * 4 + 0]) + (INT32)((s0) * Precalc[(INT32)(fp) * 4 + 1]) + (INT32)((s1) * Precalc[(INT32)(fp) * 4 + 2]) + (INT32)((s2) * Precalc[(INT32)(fp) * 4 + 3])) / (INT32)(v))
#define INTERPOLATE4PU_8BIT(fp, sN, s0, s1, s2) (((UINT32)((sN) * Precalc[(INT32)(fp) * 4 + 0]) + (UINT32)((s0) * Precalc[(INT32)(fp) * 4 + 1]) + (UINT32)((s1) * Precalc[(INT32)(fp) * 4 + 2]) + (UINT32)((s2) * Precalc[(INT32)(fp) * 4 + 3])) / 64)
#define INTERPOLATE4PU_16BIT(fp, sN, s0, s1, s2) (((UINT32)((sN) * Precalc[(INT32)(fp) * 4 + 0]) + (UINT32)((s0) * Precalc[(INT32)(fp) * 4 + 1]) + (UINT32)((s1) * Precalc[(INT32)(fp) * 4 + 2]) + (UINT32)((s2) * Precalc[(INT32)(fp) * 4 + 3])) / 16384)
#define INTERPOLATE4PU_CUSTOM(fp, sN, s0, s1, s2, v) (((UINT32)((sN) * Precalc[(INT32)(fp) * 4 + 0]) + (UINT32)((s0) * Precalc[(INT32)(fp) * 4 + 1]) + (UINT32)((s1) * Precalc[(INT32)(fp) * 4 + 2]) + (UINT32)((s2) * Precalc[(INT32)(fp) * 4 + 3])) / (UINT32)(v))

751
src/burn/burn_sound_a.asm Normal file
View File

@ -0,0 +1,751 @@
; MMX general sound support + PCM channel mixing
; based on code by Daniel Moreno (ComaC) - 2001 < comac2k@teleline.es >
; ChannelMix_QS mixes one channel using 4 point, 3rd order interpolation.
; The volume of the resulting audio is 64 times louder, to have extra precision
; when mixing the channels.
;
; The BurnSoundCopy* functions convert a 32-bit (interleaved stereo or mono) buffer
; to interleaved 16-bit stereo, clamping and dividing volume by 256 on the fly.
;
; BurnSoundCopy_FM interleaves 2 16-bit buffers into a single interleaved stereo buffer,
; correcting volume (variable) on the fly
;
; BurnSoundCopy_FM interleaves 2 16-bit buffers into a single interleaved stereo buffer,
; adding a 3rd 32-bit buffer correcting volume on the 3rd buffer (variable) on the fly
[BITS 32]
global ChannelMix_QS_A
global _ChannelMix_QS_A
global ChannelMix_8U_A
global _ChannelMix_8U_A
global BurnSoundCopyClamp_A
global _BurnSoundCopyClamp_A
global BurnSoundCopyClamp_Add_A
global _BurnSoundCopyClamp_Add_A
global _BurnSoundCopyClamp_Mono_A
global BurnSoundCopyClamp_Mono_A
global _BurnSoundCopyClamp_Mono_Add_A
global BurnSoundCopyClamp_Mono_Add_A
global BurnSoundCopy_FM_A
global _BurnSoundCopy_FM_A
global BurnSoundCopy_FM_Add_A
global _BurnSoundCopy_FM_Add_A
global _BurnSoundCopy_FM_OPN_A
global BurnSoundCopy_FM_OPN_A
global _BurnSoundCopy_FM_OPN_Add_A
global BurnSoundCopy_FM_OPN_Add_A
extern _Precalc
section .text
; This macro is used from other functions. It contains the main mixing
; loop for 8 bit samples. At its input it expects:
;
; EAX -> pointer to sample buffer
; EBX -> index inside sample (current position)
; ECX -> index of the first sample that does NOT have to play (LoopEnd)
; ESI -> pointer to destination buffer
; mm3 -> Volumes Low = Left, High = Right
;
; Param 1 -> dword containing position increment
; Param 2 -> dword containing loop length
; Param 3 -> dword containing size of out buffer in samples
; Param 4 -> pointer to enf buffer
; Param 5 -> instructions to do to unpacked samples, or text NONE if none
;
; At exit:
;
; EBX -> next position to play
; EDX -> destroyed
; [Param 2] -> updated acordingly
; [Param 4] -> zero
; mm0 -> destroyed
; mm1 -> destroyed
%macro Mix_Loop 5
%define INCR %1
%define LOOP %2
%define BUFLEN %3
%define ENDBUF %4
cmp EBX, ECX ; Past the end?
jl %%Sigue ; No? -> Continue
%%PassedEnd:
mov EDX, ECX ; We are at or near the end of the sample
add EDX, 0x3000 ; We need to either stop, set the pointer
and EDX, (0xFFFF << 12) ; to the loop point, or render a few samples
cmp EBX, EDX ; from the end buffer
jge %%LoopCheck ;
; We need to render samples from the end buffer
push EBX ; We need to copy EBX to EDX (!!!)
pxor mm0, mm0 ; Zero mm0 (to do zero extension of sample)
add EBX, 0x4000 ; load end buffer in EDX, index in EBX
sub EBX, EDX ;
mov EDX, ENDBUF ;
shr EBX, 12 ;
punpcklbw mm0, [EDX + EBX] ; Load & unpack samples (from the end buffer) to 16 bit
pop EDX ; !!!
jmp %%Interpolate
%%LoopCheck:
cmp LOOP, 0x1000 ; > 0x1000
jg %%SetLoopPoint ; Yes -> Loop Sample
cmp LOOP, 0
je %%EndSample
mov EBX, ECX ; Kludge to work around some situations
add EBX, 0x2000 ; where the QSound hardware is left in
jmp %%End_StayOn ; a non-standard state (e.g. DDTOD, DDSOM)
%%EndSample:
xor EBX, EBX
xor EAX, EAX ; set bKey to zero
jmp %%End ; exit function
%%SetLoopPoint:
sub EBX, LOOP ; Set EBX to the loop point
%%NextSample:
cmp EBX, ECX ; Passed the end?
jge %%PassedEnd
%%Sigue:
mov EDX, EBX
and EBX, (0xFFFF << 12) ; QSound banks are 0x10000 bytes
shr EBX, 12 ; EBX = Integer(nPos)
pxor mm0, mm0 ; Zero mm0 (to do zero extension of sample)
punpcklbw mm0, [EAX + EBX] ; Load & unpack samples to 16 bit
%%Interpolate:
mov EBX, EDX
and EDX, 0x0FFF ; EDX = Decimal(nPos)
; Execute sign adaptation instructions if necessary:
%ifnidni %5, NONE
pxor mm0, %5
%endif
; Interpolate sample
pmaddwd mm0, [_Precalc + EDX*8] ; Get multipliers
movq mm1, mm0 ; We need High(mm0) + Low(mm0)
psrlq mm0, 32 ; mm0 = High(mm0)
paddd mm0, mm1 ; mm0 = Sample interpolated * 16384
psrad mm0, 16 ; Shift samples right
packssdw mm0, mm0 ; Hi(mm0) = sample, Low(mm0) = sample
add EBX, INCR ; Advance counters
pmaddwd mm0, mm3 ; Multiply samples with volume
dec BUFLEN ; 1 sample less left
paddd mm0, [ESI] ; Add to buffer
movq [ESI], mm0 ; Store result on buffer
lea ESI, [ESI + 8]
jnz %%NextSample ; Continue if there are more samples
%%End_StayOn:
mov EAX, 1 ; leave bKey at 1
%%End:
%endmacro
; Parameters to ChannelMix_QS/8U:
%define BuffDest dword [EBP + 8]
%define BuffLen dword [EBP + 12]
%define SampleBuff dword [EBP + 16]
%define LoopEnd dword [EBP + 20]
%define PosPtr dword [EBP + 24]
%define Volumes qword [EBP + 28]
%define LoopLen dword [EBP + 36]
%define IncrPos dword [EBP + 40]
%define EndBuff dword [EBP + 44]
_ChannelMix_QS_A:
ChannelMix_QS_A:
push EBP
mov EBP, ESP
push EBX
push ESI
push EDI
mov EAX, SampleBuff ; EAX = Sample Buffer
mov EBX, PosPtr
movq mm3, Volumes ; mm3 = Volumes
mov EBX, [EBX] ; EBX = Sample Position
mov ECX, LoopEnd ; ECX = LoopEnd
sub ECX, 0x3000
mov ESI, BuffDest ; ESI = destionation buffer
mov EDI, IncrPos ; EDI = IncrPos
Mix_Loop EDI, LoopLen, BuffLen, EndBuff, NONE
mov ECX, PosPtr
pop EDI
pop ESI
mov [ECX], EBX ; Save position
; emms
pop EBX
pop EBP
ret
_ChannelMix_8U_A:
ChannelMix_8U_A:
push EBP
mov EBP, ESP
push EBX
push ESI
push EDI
mov EAX, SampleBuff ; EAX = Sample Buffer
mov EBX, PosPtr
movq mm3, Volumes ; mm3 = Volumes
movq mm4, [XorSign] ; mm4 = Value to xor to adapt sign
dec EAX
mov EBX, [EBX] ; EBX = Sample Position
mov ECX, LoopEnd ; ECX = LoopEnd
mov ESI, BuffDest ; ESI = destionation buffer
mov EDI, IncrPos ; EDI = IncrPos
Mix_Loop EDI, LoopLen, BuffLen, EndBuff, mm4
mov ECX, PosPtr
pop EDI
pop ESI
mov [ECX], EBX ; Save position
; emms
pop EBX
pop EBP
ret
; Parameters to BurnSoundCopyClamp* functions
%define BufSrc [EBP + 8]
%define BufDest [EBP + 12]
%define Len [EBP + 16]
_BurnSoundCopyClamp_A:
BurnSoundCopyClamp_A:
push EBP
mov EBP, ESP
mov ECX, BufSrc ; ECX = Buff Src
mov EDX, BufDest ; EDX = Buff Dest
mov EAX, Len ; EAX = Length
shr EAX, 1
je .LastSample
.Loop:
movq mm0, [ECX] ; Hi(mm0) = SampleR*256, Low(mm0) = SampleL*256
movq mm1, [ECX + 8] ; Load next sample too
psrad mm0, 8 ; Hi(mm0) = Sample1R, Low(mm0) = Sample1L
psrad mm1, 8 ; Hi(mm1) = Sample2R, Low(mm1) = Sample2L
add ECX, byte 16 ; ECX -> next samples
packssdw mm0, mm1 ; We have both samples packed here
dec EAX ; 2 samples less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next sample
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of sample pairs.
; Handle the last sample pair here
movq mm0, [ECX]
psrad mm0, 8
packssdw mm0, mm0
movd [EDX], mm0
.End:
emms ; Done with MMX
pop EBP
ret
_BurnSoundCopyClamp_Add_A:
BurnSoundCopyClamp_Add_A:
push EBP
mov EBP, ESP
mov ECX, BufSrc ; ECX = Buff Src
mov EDX, BufDest ; EDX = Buff Dest
mov EAX, Len ; EAX = Length
shr EAX, 1
je .LastSample
.Loop:
movq mm0, [ECX] ; Hi(mm0) = SampleR*256, Low(mm0) = SampleL*256
movq mm1, [ECX + 8] ; Load next sample too
psrad mm0, 8 ; Hi(mm0) = Sample1R, Low(mm0) = Sample1L
psrad mm1, 8 ; Hi(mm1) = Sample2R, Low(mm1) = Sample2L
add ECX, byte 16 ; ECX -> next samples
packssdw mm0, mm1 ; Here we have the 2 samples packed
paddsw mm0, [EDX] ; Add to the contents of the buffer
dec EAX ; 2 samples less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next 2 samples
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of sample pairs.
; Handle the last sample pair here
movq mm0, [ECX]
psrad mm0, 8
packssdw mm0, mm0
movd mm1, [EDX]
paddsw mm0, mm1
movd [EDX], mm0
.End:
emms ; Done with MMX
pop EBP
ret
_BurnSoundCopyClamp_Mono_A:
BurnSoundCopyClamp_Mono_A:
push EBP
mov EBP, ESP
mov ECX, BufSrc ; ECX = Buff Src
mov EDX, BufDest ; EDX = Buff Dest
mov EAX, Len ; EAX = Length
shr EAX, 1
je .LastSample
.Loop:
movq mm0, [ECX] ; Hi(mm0) = Sample2*256, Low(mm0) = Sample1*256
psrad mm0, 8 ; Hi(mm0) = Sample2, Low(mm0) = Sample1
add ECX, byte 8 ; ECX -> next samples
packssdw mm0, mm0 ; We have both samples packed here
punpcklwd mm0, mm0
dec EAX ; 2 samples less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next sample
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of samples.
; Handle the last sample here
movd mm0, [ECX]
psrad mm0, 8
packssdw mm0, mm0
punpcklwd mm0, mm0
movd [EDX], mm0
.End:
emms ; Done with MMX
pop EBP
ret
_BurnSoundCopyClamp_Mono_Add_A:
BurnSoundCopyClamp_Mono_Add_A:
push EBP
mov EBP, ESP
mov ECX, BufSrc ; ECX = Buff Src
mov EDX, BufDest ; EDX = Buff Dest
mov EAX, Len ; EAX = Length
shr EAX, 1
je .LastSample
.Loop:
movq mm0, [ECX] ; Hi(mm0) = Sample2*256, Low(mm0) = Sample1*256
psrad mm0, 8 ; Hi(mm0) = Sample2, Low(mm0) = Sample1
add ECX, byte 8 ; ECX -> next samples
packssdw mm0, mm0 ; We have both samples packed here
punpcklwd mm0, mm0
paddsw mm0, [EDX] ; Add to the contents of the buffer
dec EAX ; 2 samples less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next 2 samples
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of samples.
; Handle the last sample here
movd mm0, [ECX]
psrad mm0, 8
packssdw mm0, mm0
punpcklwd mm0, mm0
movd mm1, [EDX]
paddsw mm0, mm1
movd [EDX], mm0
.End:
emms ; Done with MMX
pop EBP
ret
; Parameters to BurnSoundCopy_FM
%define BufSrcL dword [EBP + 8]
%define BufSrcR dword [EBP + 12]
%define BufDest dword [EBP + 16]
%define Len dword [EBP + 20]
%define Volumes qword [EBP + 24]
_BurnSoundCopy_FM_A:
BurnSoundCopy_FM_A:
push EBP
mov EBP, ESP
push EBX
movq mm1, Volumes
packssdw mm1, Volumes
; mm1 now holds the volumes as packed words
mov EAX, Len ; EAX = Length
mov EDX, BufDest ; EDX = BufDest
mov ECX, BufSrcR ; ECX = BufSrcR
mov EBX, BufSrcL ; EBX = BufSrcL
shr EAX, 1
je .LastSample
.Loop:
movd mm0, [EBX]
punpcklwd mm0, [ECX]
; mm0 now has SrcR2 - SrcL2 - SrcR1 - SrcL1
pmulhw mm0, mm1 ; Multiply mm0 with volumes
add EBX, byte 4 ; EBX -> next samples
add ECX, byte 4 ; ECX -> next samples
dec EAX ; 2 sample less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next sample
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of sample pairs.
; Handle the last sample pair here
movd mm0, [EBX]
punpcklwd mm0, [ECX]
; mm0 now has ? - ? - SrcR1 - SrcL1
pmulhw mm0, mm1 ; Multiply mm0 with volumes
movd [EDX], mm0 ; Save the result
.End:
emms ; Done with MMX
pop EBX
pop EBP
ret
_BurnSoundCopy_FM_Add_A:
BurnSoundCopy_FM_Add_A:
push EBP
mov EBP, ESP
push EBX
movq mm1, Volumes
packssdw mm1, Volumes
; mm1 now holds the volumes as packed words
mov EAX, Len ; EAX = Length
mov EDX, BufDest ; EDX = BufDest
mov ECX, BufSrcR ; ECX = BufSrcR
mov EBX, BufSrcL ; EBX = BufSrcL
shr EAX, 1
je .LastSample
.Loop:
movd mm0, [EBX]
punpcklwd mm0, [ECX]
; mm0 now has SrcR2 - SrcL2 - SrcR1 - SrcL1
pmulhw mm0, mm1 ; Multiply mm0 with volumes
add EBX, byte 4 ; EBX -> next samples
add ECX, byte 4 ; ECX -> next samples
paddsw mm0, [EDX] ; Add to the contents of the buffer
dec EAX ; 2 sample less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next sample
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of sample pairs.
; Handle the last sample pair here
movd mm0, [EBX]
punpcklwd mm0, [ECX]
; mm0 now has ? - ? - SrcR1 - SrcL1
pmulhw mm0, mm1 ; Multiply mm0 with volumes
movd mm1, [EDX]
paddsw mm0, mm1 ; Add to the contents of the buffer
movd [EDX], mm0 ; Save the result
.End:
emms ; Done with MMX
pop EBX
pop EBP
ret
; Parameters to BurnSoundCopyFM_OPN_A
%define BufSrcOPN dword [EBP + 8]
%define BufSrcPSG dword [EBP + 12]
%define BufDest dword [EBP + 16]
%define Len dword [EBP + 20]
%define Volumes qword [EBP + 24]
_BurnSoundCopy_FM_OPN_A:
BurnSoundCopy_FM_OPN_A:
push EBP
mov EBP, ESP
push EBX
movq mm4, Volumes
packssdw mm4, Volumes
mov EBX, BufSrcOPN ; EBX = Buff Src (OPN)
mov ECX, BufSrcPSG ; ECX = Buff Src (PSG)
mov EDX, BufDest ; EDX = Buff Dest
mov EAX, Len ; EAX = Length
shr EAX, 1
je .LastSample
.Loop:
movq mm0, [ECX] ; Hi(mm0) = Sample2, Low(mm0) = Sample1
add ECX, byte 8 ; ECX -> next samples
packssdw mm0, mm0
movd mm1, [EBX] ; OPN sample left
punpcklwd mm0, mm0
; mm0 now has SrcPSGR2 - SrcPSGL2 - SrcPSGR1 - SrcPSGL1
punpcklwd mm1, [EBX + 8192] ; OPN sample right
; mm1 now has SrcOPNR2 - SrcOPNL2 - SrcOPNR1 - SrcOPNL1
pmulhw mm0, mm4 ; Multiply mm0 with volumes
add EBX, byte 4 ; EBX -> next samples
paddsw mm0, mm1
dec EAX ; 2 samples less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next sample
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of samples.
; Handle the last sample here
movd mm0, [ECX]
packssdw mm0, mm0
movd mm1, [EBX]
punpcklwd mm0, mm0
punpcklwd mm1, [EBX + 8192]
pmulhw mm0, mm4
paddsw mm0, mm1
movd [EDX], mm0
.End:
emms ; Done with MMX
pop EBX
pop EBP
ret
_BurnSoundCopy_FM_OPN_Add_A:
BurnSoundCopy_FM_OPN_Add_A:
push EBP
mov EBP, ESP
push EBX
movq mm4, Volumes
packssdw mm4, Volumes
mov EBX, BufSrcOPN ; EBX = Buff Src (OPN)
mov ECX, BufSrcPSG ; ECX = Buff Src (PSG)
mov EDX, BufDest ; EDX = Buff Dest
mov EAX, Len ; EAX = Length
shr EAX, 1
je .LastSample
.Loop:
movq mm0, [ECX] ; Hi(mm0) = Sample2, Low(mm0) = Sample1
add ECX, byte 8 ; ECX -> next samples
packssdw mm0, mm0
movd mm1, [EBX] ; OPN sample left
punpcklwd mm0, mm0
; mm0 now has SrcPSGR2 - SrcPSGL2 - SrcPSGR1 - SrcPSGL1
punpcklwd mm1, [EBX + 8192] ; OPN sample right
; mm1 now has SrcOPNR2 - SrcOPNL2 - SrcOPNR1 - SrcOPNL1
pmulhw mm0, mm4 ; Multiply mm0 with volumes
add EBX, byte 4 ; EBX -> next samples
paddsw mm0, mm1
paddsw mm0, [EDX] ; Add to the contents of the buffer
dec EAX ; 2 samples less left
movq [EDX], mm0 ; Save the result
lea EDX, [EDX + 8] ; EDX -> next sample
jnz .Loop ; Continue if there are more samples
.LastSample:
mov EAX, Len ; EAX = Length
test EAX, 1
je .End
; We need to handle an odd amount of samples.
; Handle the last sample here
movd mm0, [ECX]
packssdw mm0, mm0
movd mm1, [EBX]
punpcklwd mm0, mm0
punpcklwd mm1, [EBX + 8192]
pmulhw mm0, mm4
paddsw mm0, mm1
movd mm1, [EDX]
paddsw mm0, mm1 ; Add to the contents of the buffer
movd [EDX], mm0
.End:
emms ; Done with MMX
pop EBX
pop EBP
ret
section .data
; Used to xor with the unpacked samples to change sign:
XorSign: dw 0x8000, 0x8000, 0x8000, 0x8000
section .bss
VolMMX: resd 2
ActiveFlag: resb 1

46
src/burn/burn_sound_c.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "burnint.h"
#include "burn_sound.h"
#define CLIP(A) ((A) < -0x8000 ? -0x8000 : (A) > 0x7fff ? 0x7fff : (A))
void BurnSoundCopyClamp_C(INT32 *Src, INT16 *Dest, INT32 Len)
{
Len *= 2;
while (Len--) {
*Dest = CLIP((*Src >> 8));
Src++;
Dest++;
}
}
void BurnSoundCopyClamp_Add_C(INT32 *Src, INT16 *Dest, INT32 Len)
{
Len *= 2;
while (Len--) {
*Dest = CLIP((*Src >> 8) + *Dest);
Src++;
Dest++;
}
}
void BurnSoundCopyClamp_Mono_C(INT32 *Src, INT16 *Dest, INT32 Len)
{
while (Len--) {
Dest[0] = CLIP((*Src >> 8));
Dest[1] = CLIP((*Src >> 8));
Src++;
Dest += 2;
}
}
void BurnSoundCopyClamp_Mono_Add_C(INT32 *Src, INT16 *Dest, INT32 Len)
{
while (Len--) {
Dest[0] = CLIP((*Src >> 8) + Dest[0]);
Dest[1] = CLIP((*Src >> 8) + Dest[1]);
Src++;
Dest += 2;
}
}
#undef CLIP

121
src/burn/burnint.h Normal file
View File

@ -0,0 +1,121 @@
// Burn - Arcade emulator library - internal code
// Standard headers
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "tchar.h"
#include "burn.h"
// ---------------------------------------------------------------------------
// CPU emulation interfaces
// sek.cpp
#include "sek.h"
// zet.cpp
#include "zet.h"
typedef union
{
struct { UINT8 l,h,h2,h3; } b;
struct { UINT16 l,h; } w;
UINT32 d;
} PAIR;
// ---------------------------------------------------------------------------
// Driver information
struct BurnDriver {
char* szShortName; // The filename of the zip file (without extension)
char* szParent; // The filename of the parent (without extension, NULL if not applicable)
char* szBoardROM; // The filename of the board ROMs (without extension, NULL if not applicable)
char* szSampleName; // The filename of the samples zip file (without extension, NULL if not applicable)
char* szDate;
// szFullNameA, szCommentA, szManufacturerA and szSystemA should always contain valid info
// szFullNameW, szCommentW, szManufacturerW and szSystemW should be used only if characters or scripts are needed that ASCII can't handle
char* szFullNameA; char* szCommentA; char* szManufacturerA; char* szSystemA;
wchar_t* szFullNameW; wchar_t* szCommentW; wchar_t* szManufacturerW; wchar_t* szSystemW;
INT32 Flags; // See burn.h
INT32 Players; // Max number of players a game supports (so we can remove single player games from netplay)
INT32 Hardware; // Which type of hardware the game runs on
INT32 Genre;
INT32 Family;
INT32 (*GetZipName)(char** pszName, UINT32 i); // Function to get possible zip names
INT32 (*GetRomInfo)(struct BurnRomInfo* pri, UINT32 i); // Function to get the length and crc of each rom
INT32 (*GetRomName)(char** pszName, UINT32 i, INT32 nAka); // Function to get the possible names for each rom
INT32 (*GetSampleInfo)(struct BurnSampleInfo* pri, UINT32 i); // Function to get the sample flags
INT32 (*GetSampleName)(char** pszName, UINT32 i, INT32 nAka); // Function to get the possible names for each sample
INT32 (*GetInputInfo)(struct BurnInputInfo* pii, UINT32 i); // Function to get the input info for the game
INT32 (*GetDIPInfo)(struct BurnDIPInfo* pdi, UINT32 i); // Function to get the input info for the game
INT32 (*Init)(); INT32 (*Exit)(); INT32 (*Frame)(); INT32 (*Redraw)(); INT32 (*AreaScan)(INT32 nAction, INT32* pnMin);
UINT8* pRecalcPal; UINT32 nPaletteEntries; // Set to 1 if the palette needs to be fully re-calculated
INT32 nWidth, nHeight; INT32 nXAspect, nYAspect; // Screen width, height, x/y aspect
};
#define BurnDriverD BurnDriver // Debug status
#define BurnDriverX BurnDriver // Exclude from build
// Standard functions for dealing with ROM and input info structures
#include "stdfunc.h"
// ---------------------------------------------------------------------------
// burn.cpp
INT32 BurnSetRefreshRate(double dRefreshRate);
INT32 BurnByteswap(UINT8* pm,INT32 nLen);
INT32 BurnClearScreen();
// load.cpp
INT32 BurnLoadRom(UINT8* Dest, INT32 i, INT32 nGap);
INT32 BurnXorRom(UINT8* Dest, INT32 i, INT32 nGap);
INT32 BurnLoadBitField(UINT8* pDest, UINT8* pSrc, INT32 nField, INT32 nSrcLen);
// ---------------------------------------------------------------------------
// Colour-depth independant image transfer
extern UINT16* pTransDraw;
void BurnTransferClear();
INT32 BurnTransferCopy(UINT32* pPalette);
void BurnTransferExit();
INT32 BurnTransferInit();
// ---------------------------------------------------------------------------
// Plotting pixels
inline static void PutPix(UINT8* pPix, UINT32 c)
{
if (nBurnBpp >= 4) {
*((UINT32*)pPix) = c;
} else {
if (nBurnBpp == 2) {
*((UINT16*)pPix) = (UINT16)c;
} else {
pPix[0] = (UINT8)(c >> 0);
pPix[1] = (UINT8)(c >> 8);
pPix[2] = (UINT8)(c >> 16);
}
}
}
// ---------------------------------------------------------------------------
// Setting up cpus for cheats
void CpuCheatRegister(INT32 type, INT32 num);
// burn_memory.cpp
void BurnInitMemoryManager();
UINT8 *BurnMalloc(INT32 size);
void _BurnFree(void *ptr);
#define BurnFree(x) _BurnFree(x); x = NULL;
void BurnExitMemoryManager();
// ---------------------------------------------------------------------------
// Sound clipping macro
#define BURN_SND_CLIP(A) ((A) < -0x8000 ? -0x8000 : (A) > 0x7fff ? 0x7fff : (A))

664
src/burn/cheat.cpp Normal file
View File

@ -0,0 +1,664 @@
// Cheat module
#include "burnint.h"
#include "vez.h"
#include "sh2.h"
#include "m6502_intf.h"
#include "m6809_intf.h"
#include "hd6309_intf.h"
#include "m6800_intf.h"
#include "s2650_intf.h"
#include "konami_intf.h"
#include "arm7_intf.h"
bool bCheatsAllowed;
CheatInfo* pCheatInfo = NULL;
static bool bCheatsEnabled = false;
//----------------------------------------------------
// Cpu interface for cheat application
#define MAX_CHEAT_CPU 8 // enough?
static INT32 nActiveCheatCpus;
struct cheat_subs {
INT32 nCpu; // Which cpu is this? (SekOpen(#), ZetOpen(#))
void (*cpu_open)(INT32);
void (*write)(UINT32, UINT8);
UINT8 (*read)(UINT32);
void (*cpu_close)();
INT32 (*active_cpu)();
UINT32 nMemorySize;
};
struct cheat_subs cheat_sub_block[MAX_CHEAT_CPU];
struct cheat_subs *cheat_subptr;
//---------------------------------------------------
// Dummy handlers
static INT32 CheatDummyGetActive() { return -1; }
static void CheatDummyOpen(INT32) {}
static void CheatDummyClose() {}
static void CheatDummyWriteByte(UINT32, UINT8) {}
static UINT8 CheatDummyReadByte(UINT32) { return 0; }
// -----------------------------------------------
// Set up handlers for cpu cores that aren't totally compatible
#define CHEAT_READ(name,funct) \
static UINT8 name##ReadByteCheat(UINT32 a) { \
return funct; \
}
#define CHEAT_WRITE(name,funct) \
static void name##WriteByteCheat(UINT32 a, UINT8 d) { \
funct; \
}
CHEAT_READ(Sek, SekReadByte(a))
CHEAT_READ(Sh2, Sh2ReadByte(a))
CHEAT_WRITE(Sh2, Sh2WriteByte(a,d))
CHEAT_READ(Zet, ZetReadByte(a))
CHEAT_WRITE(Zet, ZetWriteRom(a,d))
CHEAT_READ(M6800, M6800ReadByte(a))
CHEAT_WRITE(M6800, M6800WriteRom(a,d))
CHEAT_READ(M6809, M6809ReadByte(a))
CHEAT_WRITE(M6809, M6809WriteRom(a,d))
CHEAT_READ(HD6309, HD6309ReadByte(a))
CHEAT_WRITE(HD6309, HD6309WriteRom(a,d))
CHEAT_READ(m6502, M6502ReadByte(a))
CHEAT_WRITE(m6502, M6502WriteRom(a,d))
CHEAT_READ(s2650, s2650_read(a))
CHEAT_WRITE(s2650, s2650_write_rom(a,d))
CHEAT_READ(konami, konami_read(a))
CHEAT_WRITE(konami, konami_write_rom(a,d))
//------------------------------------------------
// Central cpu registry for functions necessary for cheats
void CpuCheatRegister(INT32 type, INT32 nNum)
{
cheat_subptr = &cheat_sub_block[nActiveCheatCpus];
nActiveCheatCpus++;
switch (type)
{
case 0x0000: // m68k
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = SekOpen;
cheat_subptr->cpu_close = SekClose;
cheat_subptr->active_cpu = SekGetActive;
cheat_subptr->write = SekWriteByteROM;
cheat_subptr->read = SekReadByteCheat;
cheat_subptr->nMemorySize = 0x01000000;
}
break;
case 0x0001: // NEC V30 / V33
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = VezOpen;
cheat_subptr->cpu_close = VezClose;
cheat_subptr->active_cpu = VezGetActive;
cheat_subptr->write = cpu_writemem20;
cheat_subptr->read = cpu_readmem20;
cheat_subptr->nMemorySize = 0x00100000;
}
break;
case 0x0002: // SH2
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = Sh2Open;
cheat_subptr->cpu_close = Sh2Close;
cheat_subptr->active_cpu = Sh2GetActive;
cheat_subptr->write = Sh2WriteByteCheat;
cheat_subptr->read = Sh2ReadByteCheat;
cheat_subptr->nMemorySize = 0x02080000; // Good enough for CPS3
}
break;
case 0x0003: // M6502
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = M6502Open;
cheat_subptr->cpu_close = M6502Close;
cheat_subptr->active_cpu = M6502GetActive;
cheat_subptr->write = m6502WriteByteCheat;
cheat_subptr->read = m6502ReadByteCheat;
cheat_subptr->nMemorySize = 0x00010000;
}
break;
case 0x0004: // Z80
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = ZetOpen;
cheat_subptr->cpu_close = ZetClose;
cheat_subptr->active_cpu = ZetGetActive;
cheat_subptr->write = ZetWriteByteCheat;
cheat_subptr->read = ZetReadByteCheat;
cheat_subptr->nMemorySize = 0x00010000;
}
break;
case 0x0005: // M6809
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = M6809Open;
cheat_subptr->cpu_close = M6809Close;
cheat_subptr->active_cpu = M6809GetActive;
cheat_subptr->write = M6809WriteByteCheat;
cheat_subptr->read = M6809ReadByteCheat;
cheat_subptr->nMemorySize = 0x00010000;
}
break;
case 0x0006: // HD6309
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = HD6309Open;
cheat_subptr->cpu_close = HD6309Close;
cheat_subptr->active_cpu = HD6309GetActive;
cheat_subptr->write = HD6309WriteByteCheat;
cheat_subptr->read = HD6309ReadByteCheat;
cheat_subptr->nMemorySize = 0x00010000;
}
break;
case 0x0007: // M6800
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = CheatDummyOpen;
cheat_subptr->cpu_close = CheatDummyClose;
cheat_subptr->active_cpu = CheatDummyGetActive;
cheat_subptr->write = M6800WriteByteCheat;
cheat_subptr->read = M6800ReadByteCheat;
cheat_subptr->nMemorySize = 0x00010000;
}
break;
case 0x0008: // S2650
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = s2650Open;
cheat_subptr->cpu_close = s2650Close;
cheat_subptr->active_cpu = s2650GetActive;
cheat_subptr->write = s2650WriteByteCheat;
cheat_subptr->read = s2650ReadByteCheat;
cheat_subptr->nMemorySize = 0x00010000;
}
break;
case 0x0009: // Konami Custom
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = konamiOpen;
cheat_subptr->cpu_close = konamiClose;
cheat_subptr->active_cpu = konamiGetActive;
cheat_subptr->write = konamiWriteByteCheat;
cheat_subptr->read = konamiReadByteCheat;
cheat_subptr->nMemorySize = 0x00010000;
}
break;
case 0x000a: // ARM7
{
cheat_subptr->nCpu = nNum;
cheat_subptr->cpu_open = Arm7Open;
cheat_subptr->cpu_close = Arm7Close;
cheat_subptr->active_cpu = CheatDummyGetActive;
cheat_subptr->write = Arm7_write_rom_byte;
cheat_subptr->read = Arm7_program_read_byte_32le;
cheat_subptr->nMemorySize = 0x80000000; // enough for PGM...
}
break;
// Just in case the called cpu isn't supported and so MinGW
// doesn't complain about unused functions...
default:
{
cheat_subptr->nCpu = 0;
cheat_subptr->cpu_open = CheatDummyOpen;
cheat_subptr->cpu_close = CheatDummyClose;
cheat_subptr->active_cpu = CheatDummyGetActive;
cheat_subptr->write = CheatDummyWriteByte;
cheat_subptr->read = CheatDummyReadByte;
cheat_subptr->nMemorySize = 0;
}
break;
}
}
INT32 CheatUpdate()
{
bCheatsEnabled = false;
if (bCheatsAllowed) {
CheatInfo* pCurrentCheat = pCheatInfo;
CheatAddressInfo* pAddressInfo;
while (pCurrentCheat) {
if (pCurrentCheat->nStatus > 1) {
pAddressInfo = pCurrentCheat->pOption[pCurrentCheat->nCurrent]->AddressInfo;
if (pAddressInfo->nAddress) {
bCheatsEnabled = true;
}
}
pCurrentCheat = pCurrentCheat->pNext;
}
}
return 0;
}
INT32 CheatEnable(INT32 nCheat, INT32 nOption)
{
INT32 nCurrentCheat = 0;
CheatInfo* pCurrentCheat = pCheatInfo;
CheatAddressInfo* pAddressInfo;
INT32 nOpenCPU = -1;
if (!bCheatsAllowed) {
return 1;
}
if (nOption >= CHEAT_MAX_OPTIONS) {
return 1;
}
cheat_subptr = &cheat_sub_block[0]; // first cpu...
while (pCurrentCheat && nCurrentCheat <= nCheat) {
if (nCurrentCheat == nCheat) {
if (nOption == -1) {
nOption = pCurrentCheat->nDefault;
}
if (pCurrentCheat->nType != 1) {
// Return OK if the cheat is already active with the same option
if (pCurrentCheat->nCurrent == nOption) {
return 0;
}
// Deactivate old option (if any)
pAddressInfo = pCurrentCheat->pOption[nOption]->AddressInfo;
while (pAddressInfo->nAddress) {
if (pAddressInfo->nCPU != nOpenCPU) {
if (nOpenCPU != -1) {
cheat_subptr->cpu_close();
}
nOpenCPU = pAddressInfo->nCPU;
cheat_subptr = &cheat_sub_block[nOpenCPU];
cheat_subptr->cpu_open(cheat_subptr->nCpu);
}
// Write back original values to memory
cheat_subptr->write(pAddressInfo->nAddress, pAddressInfo->nOriginalValue);
pAddressInfo++;
}
}
// Activate new option
pAddressInfo = pCurrentCheat->pOption[nOption]->AddressInfo;
while (pAddressInfo->nAddress) {
if (pAddressInfo->nCPU != nOpenCPU) {
if (nOpenCPU != -1) {
cheat_subptr->cpu_close();
}
nOpenCPU = pAddressInfo->nCPU;
cheat_subptr = &cheat_sub_block[nOpenCPU];
cheat_subptr->cpu_open(cheat_subptr->nCpu);
}
// Copy the original values
pAddressInfo->nOriginalValue = cheat_subptr->read(pAddressInfo->nAddress);
if (pCurrentCheat->nType != 0) {
if (pAddressInfo->nCPU != nOpenCPU) {
if (nOpenCPU != -1) {
cheat_subptr->cpu_close();
}
nOpenCPU = pAddressInfo->nCPU;
cheat_subptr = &cheat_sub_block[nOpenCPU];
cheat_subptr->cpu_open(cheat_subptr->nCpu);
}
// Activate the cheat
cheat_subptr->write(pAddressInfo->nAddress, pAddressInfo->nValue);
}
pAddressInfo++;
}
// Set cheat status and active option
if (pCurrentCheat->nType != 1) {
pCurrentCheat->nCurrent = nOption;
}
if (pCurrentCheat->nType == 0) {
pCurrentCheat->nStatus = 2;
}
if (pCurrentCheat->nType == 2) {
pCurrentCheat->nStatus = 1;
}
break;
}
pCurrentCheat = pCurrentCheat->pNext;
nCurrentCheat++;
}
if (nOpenCPU != -1) {
cheat_subptr->cpu_close();
}
CheatUpdate();
if (nCurrentCheat == nCheat && pCurrentCheat) {
return 0;
}
return 1;
}
INT32 CheatApply()
{
if (!bCheatsEnabled) {
return 0;
}
INT32 nOpenCPU = -1;
CheatInfo* pCurrentCheat = pCheatInfo;
CheatAddressInfo* pAddressInfo;
while (pCurrentCheat) {
if (pCurrentCheat->nStatus > 1) {
pAddressInfo = pCurrentCheat->pOption[pCurrentCheat->nCurrent]->AddressInfo;
while (pAddressInfo->nAddress) {
if (pAddressInfo->nCPU != nOpenCPU) {
if (nOpenCPU != -1) {
cheat_subptr->cpu_close();
}
nOpenCPU = pAddressInfo->nCPU;
cheat_subptr = &cheat_sub_block[nOpenCPU];
cheat_subptr->cpu_open(cheat_subptr->nCpu);
}
cheat_subptr->write(pAddressInfo->nAddress, pAddressInfo->nValue);
pAddressInfo++;
}
}
pCurrentCheat = pCurrentCheat->pNext;
}
if (nOpenCPU != -1) {
cheat_subptr->cpu_close();
}
return 0;
}
INT32 CheatInit()
{
CheatExit();
bCheatsEnabled = false;
return 0;
}
void CheatExit()
{
if (pCheatInfo) {
CheatInfo* pCurrentCheat = pCheatInfo;
CheatInfo* pNextCheat;
do {
pNextCheat = pCurrentCheat->pNext;
for (INT32 i = 0; i < CHEAT_MAX_OPTIONS; i++) {
if (pCurrentCheat->pOption[i]) {
free(pCurrentCheat->pOption[i]);
}
}
if (pCurrentCheat) {
free(pCurrentCheat);
}
} while ((pCurrentCheat = pNextCheat) != 0);
}
nActiveCheatCpus = 0;
for (INT32 i = 0; i < MAX_CHEAT_CPU; i++) {
CpuCheatRegister(-1, i); // set them all to dummy...
}
nActiveCheatCpus = 0;
pCheatInfo = NULL;
}
// Cheat search
static UINT8 *MemoryValues = NULL;
static UINT8 *MemoryStatus = NULL;
static UINT32 nMemorySize = 0;
#define NOT_IN_RESULTS 0
#define IN_RESULTS 1
UINT32 CheatSearchShowResultAddresses[CHEATSEARCH_SHOWRESULTS];
UINT32 CheatSearchShowResultValues[CHEATSEARCH_SHOWRESULTS];
INT32 CheatSearchInit()
{
return 1;
}
void CheatSearchExit()
{
if (MemoryValues) {
free(MemoryValues);
MemoryValues = NULL;
}
if (MemoryStatus) {
free(MemoryStatus);
MemoryStatus = NULL;
}
nMemorySize = 0;
memset(CheatSearchShowResultAddresses, 0, CHEATSEARCH_SHOWRESULTS);
memset(CheatSearchShowResultValues, 0, CHEATSEARCH_SHOWRESULTS);
}
void CheatSearchStart()
{
UINT32 nAddress;
INT32 nActiveCPU = 0;
cheat_subptr = &cheat_sub_block[nActiveCPU]; // first cpu only (ok?)
nActiveCPU = cheat_subptr->active_cpu();
if (nActiveCPU >= 0) cheat_subptr->cpu_close();
cheat_subptr->cpu_open(cheat_subptr->nCpu);
nMemorySize = cheat_subptr->nMemorySize;
MemoryValues = (UINT8*)malloc(nMemorySize);
MemoryStatus = (UINT8*)malloc(nMemorySize);
for (nAddress = 0; nAddress < nMemorySize; nAddress++) {
MemoryValues[nAddress] = cheat_subptr->read(nAddress);
}
cheat_subptr->cpu_close();
if (nActiveCPU >= 0) cheat_subptr->cpu_open(nActiveCPU);
memset(MemoryStatus, IN_RESULTS, nMemorySize);
}
static void CheatSearchGetResults()
{
UINT32 nAddress;
UINT32 nResultsPos = 0;
memset(CheatSearchShowResultAddresses, 0, CHEATSEARCH_SHOWRESULTS);
memset(CheatSearchShowResultValues, 0, CHEATSEARCH_SHOWRESULTS);
for (nAddress = 0; nAddress < nMemorySize; nAddress++) {
if (MemoryStatus[nAddress] == IN_RESULTS) {
CheatSearchShowResultAddresses[nResultsPos] = nAddress;
CheatSearchShowResultValues[nResultsPos] = MemoryValues[nAddress];
nResultsPos++;
}
}
}
UINT32 CheatSearchValueNoChange()
{
UINT32 nMatchedAddresses = 0;
UINT32 nAddress;
INT32 nActiveCPU = 0;
nActiveCPU = cheat_subptr->active_cpu();
if (nActiveCPU >= 0) cheat_subptr->cpu_close();
cheat_subptr->cpu_open(0);
for (nAddress = 0; nAddress < nMemorySize; nAddress++) {
if (MemoryStatus[nAddress] == NOT_IN_RESULTS) continue;
if (cheat_subptr->read(nAddress) == MemoryValues[nAddress]) {
MemoryValues[nAddress] = cheat_subptr->read(nAddress);
nMatchedAddresses++;
} else {
MemoryStatus[nAddress] = NOT_IN_RESULTS;
}
}
cheat_subptr->cpu_close();
if (nActiveCPU >= 0) cheat_subptr->cpu_open(nActiveCPU);
if (nMatchedAddresses <= CHEATSEARCH_SHOWRESULTS) CheatSearchGetResults();
return nMatchedAddresses;
}
UINT32 CheatSearchValueChange()
{
UINT32 nMatchedAddresses = 0;
UINT32 nAddress;
INT32 nActiveCPU = 0;
nActiveCPU = cheat_subptr->active_cpu();
if (nActiveCPU >= 0) cheat_subptr->cpu_close();
cheat_subptr->cpu_open(0);
for (nAddress = 0; nAddress < nMemorySize; nAddress++) {
if (MemoryStatus[nAddress] == NOT_IN_RESULTS) continue;
if (cheat_subptr->read(nAddress) != MemoryValues[nAddress]) {
MemoryValues[nAddress] = cheat_subptr->read(nAddress);
nMatchedAddresses++;
} else {
MemoryStatus[nAddress] = NOT_IN_RESULTS;
}
}
cheat_subptr->cpu_close();
if (nActiveCPU >= 0) cheat_subptr->cpu_open(nActiveCPU);
if (nMatchedAddresses <= CHEATSEARCH_SHOWRESULTS) CheatSearchGetResults();
return nMatchedAddresses;
}
UINT32 CheatSearchValueDecreased()
{
UINT32 nMatchedAddresses = 0;
UINT32 nAddress;
INT32 nActiveCPU = 0;
nActiveCPU = cheat_subptr->active_cpu();
if (nActiveCPU >= 0) cheat_subptr->cpu_close();
cheat_subptr->cpu_open(0);
for (nAddress = 0; nAddress < nMemorySize; nAddress++) {
if (MemoryStatus[nAddress] == NOT_IN_RESULTS) continue;
if (cheat_subptr->read(nAddress) < MemoryValues[nAddress]) {
MemoryValues[nAddress] = cheat_subptr->read(nAddress);
nMatchedAddresses++;
} else {
MemoryStatus[nAddress] = NOT_IN_RESULTS;
}
}
cheat_subptr->cpu_close();
if (nActiveCPU >= 0) cheat_subptr->cpu_open(nActiveCPU);
if (nMatchedAddresses <= CHEATSEARCH_SHOWRESULTS) CheatSearchGetResults();
return nMatchedAddresses;
}
UINT32 CheatSearchValueIncreased()
{
UINT32 nMatchedAddresses = 0;
UINT32 nAddress;
INT32 nActiveCPU = 0;
nActiveCPU = cheat_subptr->active_cpu();
if (nActiveCPU >= 0) cheat_subptr->cpu_close();
cheat_subptr->cpu_open(0);
for (nAddress = 0; nAddress < nMemorySize; nAddress++) {
if (MemoryStatus[nAddress] == NOT_IN_RESULTS) continue;
if (cheat_subptr->read(nAddress) > MemoryValues[nAddress]) {
MemoryValues[nAddress] = cheat_subptr->read(nAddress);
nMatchedAddresses++;
} else {
MemoryStatus[nAddress] = NOT_IN_RESULTS;
}
}
cheat_subptr->cpu_close();
if (nActiveCPU >= 0) cheat_subptr->cpu_open(nActiveCPU);
if (nMatchedAddresses <= CHEATSEARCH_SHOWRESULTS) CheatSearchGetResults();
return nMatchedAddresses;
}
void CheatSearchDumptoFile()
{
FILE *fp = fopen("cheatsearchdump.txt", "wt");
UINT32 nAddress;
if (fp) {
char Temp[256];
for (nAddress = 0; nAddress < nMemorySize; nAddress++) {
if (MemoryStatus[nAddress] == IN_RESULTS) {
sprintf(Temp, "Address %08X Value %02X\n", nAddress, MemoryValues[nAddress]);
fwrite(Temp, 1, strlen(Temp), fp);
}
}
fclose(fp);
}
}
#undef NOT_IN_RESULTS
#undef IN_RESULTS

49
src/burn/cheat.h Normal file
View File

@ -0,0 +1,49 @@
#define CHEAT_MAX_ADDRESS ( 64)
#define CHEAT_MAX_OPTIONS (192)
#define CHEAT_MAX_NAME (128)
extern bool bCheatsAllowed;
struct CheatAddressInfo {
INT32 nCPU;
INT32 nAddress;
UINT32 nValue;
UINT32 nOriginalValue;
};
struct CheatOption {
TCHAR szOptionName[CHEAT_MAX_NAME];
struct CheatAddressInfo AddressInfo[CHEAT_MAX_ADDRESS + 1];
};
struct CheatInfo {
struct CheatInfo* pNext;
struct CheatInfo* pPrevious;
INT32 nType; // Cheat type
INT32 nStatus; // 0 = Inactive
INT32 nCurrent; // Currently selected option
INT32 nDefault; // Default option
TCHAR szCheatName[CHEAT_MAX_NAME];
struct CheatOption* pOption[CHEAT_MAX_OPTIONS];
};
extern CheatInfo* pCheatInfo;
INT32 CheatUpdate();
INT32 CheatEnable(INT32 nCheat, INT32 nOption);
INT32 CheatApply();
INT32 CheatInit();
void CheatExit();
#define CHEATSEARCH_SHOWRESULTS 3
extern UINT32 CheatSearchShowResultAddresses[CHEATSEARCH_SHOWRESULTS];
extern UINT32 CheatSearchShowResultValues[CHEATSEARCH_SHOWRESULTS];
INT32 CheatSearchInit();
void CheatSearchExit();
void CheatSearchStart();
UINT32 CheatSearchValueNoChange();
UINT32 CheatSearchValueChange();
UINT32 CheatSearchValueDecreased();
UINT32 CheatSearchValueIncreased();
void CheatSearchDumptoFile();

View File

@ -0,0 +1,450 @@
#include "burnint.h"
#include "8255ppi.h"
#define MAX_PPIS 3
PPIPortRead PPI0PortReadA;
PPIPortRead PPI0PortReadB;
PPIPortRead PPI0PortReadC;
PPIPortWrite PPI0PortWriteA;
PPIPortWrite PPI0PortWriteB;
PPIPortWrite PPI0PortWriteC;
PPIPortRead PPI1PortReadA;
PPIPortRead PPI1PortReadB;
PPIPortRead PPI1PortReadC;
PPIPortWrite PPI1PortWriteA;
PPIPortWrite PPI1PortWriteB;
PPIPortWrite PPI1PortWriteC;
PPIPortRead PPI2PortReadA;
PPIPortRead PPI2PortReadB;
PPIPortRead PPI2PortReadC;
PPIPortWrite PPI2PortWriteA;
PPIPortWrite PPI2PortWriteB;
PPIPortWrite PPI2PortWriteC;
typedef struct
{
/* mode flags */
UINT8 groupA_mode;
UINT8 groupB_mode;
UINT8 portA_dir;
UINT8 portB_dir;
UINT8 portCH_dir;
UINT8 portCL_dir;
/* handshake signals (1=asserted; 0=non-asserted) */
UINT8 obf_a;
UINT8 obf_b;
UINT8 ibf_a;
UINT8 ibf_b;
UINT8 inte_a;
UINT8 inte_b;
UINT8 in_mask[3]; /* input mask */
UINT8 out_mask[3]; /* output mask */
UINT8 read[3]; /* data read from ports */
UINT8 latch[3]; /* data written to ports */
UINT8 output[3]; /* actual output data */
} ppi8255;
static ppi8255 chips[MAX_PPIS];
static void ppi8255_get_handshake_signals(ppi8255 *chip, UINT8 *result)
{
UINT8 handshake = 0x00;
UINT8 mask = 0x00;
/* group A */
if (chip->groupA_mode == 1)
{
if (chip->portA_dir)
{
handshake |= chip->ibf_a ? 0x20 : 0x00;
handshake |= (chip->ibf_a && chip->inte_a) ? 0x08 : 0x00;
mask |= 0x28;
}
else
{
handshake |= chip->obf_a ? 0x00 : 0x80;
handshake |= (chip->obf_a && chip->inte_a) ? 0x08 : 0x00;
mask |= 0x88;
}
}
else if (chip->groupA_mode == 2)
{
handshake |= chip->inte_a ? 0x08 : 0x00;
handshake |= chip->obf_a ? 0x00 : 0x80;
handshake |= chip->ibf_a ? 0x20 : 0x00;
mask |= 0xA8;
}
/* group B */
if (chip->groupB_mode == 1)
{
if (chip->portA_dir)
{
handshake |= chip->ibf_b ? 0x02 : 0x00;
handshake |= (chip->ibf_b && chip->inte_b) ? 0x01 : 0x00;
mask |= 0x03;
}
else
{
handshake |= chip->obf_b ? 0x00 : 0x02;
handshake |= (chip->obf_b && chip->inte_b) ? 0x01 : 0x00;
mask |= 0x03;
}
}
*result &= ~mask;
*result |= handshake & mask;
}
static void ppi8255_write_port(ppi8255 *chip, INT32 port, INT32 chipnum)
{
UINT8 write_data;
write_data = chip->latch[port] & chip->out_mask[port];
write_data |= 0xFF & ~chip->out_mask[port];
/* write out special port 2 signals */
if (port == 2)
ppi8255_get_handshake_signals(chip, &write_data);
chip->output[port] = write_data;
if (chipnum == 0 && port == 0) {
if (PPI0PortWriteA) PPI0PortWriteA(write_data);
}
if (chipnum == 0 && port == 1) {
if (PPI0PortWriteB) PPI0PortWriteB(write_data);
}
if (chipnum == 0 && port == 2) {
if (PPI0PortWriteC) PPI0PortWriteC(write_data);
}
if (chipnum == 1 && port == 0) {
if (PPI1PortWriteA) PPI1PortWriteA(write_data);
}
if (chipnum == 1 && port == 1) {
if (PPI1PortWriteB) PPI1PortWriteB(write_data);
}
if (chipnum == 1 && port == 2) {
if (PPI1PortWriteC) PPI1PortWriteC(write_data);
}
if (chipnum == 2 && port == 0) {
if (PPI2PortWriteA) PPI2PortWriteA(write_data);
}
if (chipnum == 2 && port == 1) {
if (PPI2PortWriteB) PPI2PortWriteB(write_data);
}
if (chipnum == 2 && port == 2) {
if (PPI2PortWriteC) PPI2PortWriteC(write_data);
}
}
static void ppi8255_input(ppi8255 *chip, INT32 port, UINT8 data, INT32 which)
{
INT32 changed = 0;
chip->read[port] = data;
/* port C is special */
if (port == 2)
{
if (((chip->groupA_mode == 1) && (chip->portA_dir == 0)) || (chip->groupA_mode == 2))
{
/* is !ACKA asserted? */
if (chip->obf_a && !(data & 0x40))
{
chip->obf_a = 0;
changed = 1;
}
}
if ((chip->groupB_mode == 1) && (chip->portB_dir == 0))
{
/* is !ACKB asserted? */
if (chip->obf_b && !(data & 0x04))
{
chip->obf_b = 0;
changed = 1;
}
}
if (changed)
ppi8255_write_port(chip, 2, which);
}
}
static UINT8 ppi8255_read_port(ppi8255 *chip, INT32 port, INT32 chipnum)
{
UINT8 result = 0x00;
if (chip->in_mask[port])
{
if (chipnum == 0 && port == 0) {
ppi8255_input(chip, port, (PPI0PortReadA) ? PPI0PortReadA() : 0, chipnum);
}
if (chipnum == 0 && port == 1) {
ppi8255_input(chip, port, (PPI0PortReadB) ? PPI0PortReadB() : 0, chipnum);
}
if (chipnum == 0 && port == 2) {
ppi8255_input(chip, port, (PPI0PortReadC) ? PPI0PortReadC() : 0, chipnum);
}
if (chipnum == 1 && port == 0) {
ppi8255_input(chip, port, (PPI1PortReadA) ? PPI1PortReadA() : 0, chipnum);
}
if (chipnum == 1 && port == 1) {
ppi8255_input(chip, port, (PPI1PortReadB) ? PPI1PortReadB() : 0, chipnum);
}
if (chipnum == 1 && port == 2) {
ppi8255_input(chip, port, (PPI1PortReadC) ? PPI1PortReadC() : 0, chipnum);
}
if (chipnum == 2 && port == 0) {
ppi8255_input(chip, port, (PPI2PortReadA) ? PPI2PortReadA() : 0, chipnum);
}
if (chipnum == 2 && port == 1) {
ppi8255_input(chip, port, (PPI2PortReadB) ? PPI2PortReadB() : 0, chipnum);
}
if (chipnum == 2 && port == 2) {
ppi8255_input(chip, port, (PPI2PortReadC) ? PPI2PortReadC() : 0, chipnum);
}
result |= chip->read[port] & chip->in_mask[port];
}
result |= chip->latch[port] & chip->out_mask[port];
/* read special port 2 signals */
if (port == 2)
ppi8255_get_handshake_signals(chip, &result);
return result;
}
UINT8 ppi8255_r(INT32 which, INT32 offset)
{
ppi8255 *chip = &chips[which];
UINT8 result = 0;
offset %= 4;
switch(offset)
{
case 0: /* Port A read */
case 1: /* Port B read */
case 2: /* Port C read */
result = ppi8255_read_port(chip, offset, which);
break;
case 3: /* Control word */
result = 0xFF;
break;
}
return result;
}
static void set_mode(INT32 which, INT32 data, INT32 call_handlers)
{
ppi8255 *chip = &chips[which];
INT32 i;
/* parse out mode */
chip->groupA_mode = (data >> 5) & 3;
chip->groupB_mode = (data >> 2) & 1;
chip->portA_dir = (data >> 4) & 1;
chip->portB_dir = (data >> 1) & 1;
chip->portCH_dir = (data >> 3) & 1;
chip->portCL_dir = (data >> 0) & 1;
/* normalize groupA_mode */
if (chip->groupA_mode == 3)
chip->groupA_mode = 2;
/* Port A direction */
if (chip->portA_dir)
chip->in_mask[0] = 0xFF, chip->out_mask[0] = 0x00; /* input */
else
chip->in_mask[0] = 0x00, chip->out_mask[0] = 0xFF; /* output */
/* Port B direction */
if (chip->portB_dir)
chip->in_mask[1] = 0xFF, chip->out_mask[1] = 0x00; /* input */
else
chip->in_mask[1] = 0x00, chip->out_mask[1] = 0xFF; /* output */
/* Port C upper direction */
if (chip->portCH_dir)
chip->in_mask[2] = 0xF0, chip->out_mask[2] = 0x00; /* input */
else
chip->in_mask[2] = 0x00, chip->out_mask[2] = 0xF0; /* output */
/* Port C lower direction */
if (chip->portCL_dir)
chip->in_mask[2] |= 0x0F; /* input */
else
chip->out_mask[2] |= 0x0F; /* output */
/* now depending on the group modes, certain Port C lines may be replaced
* with varying control signals */
switch(chip->groupA_mode)
{
case 0: /* Group A mode 0 */
/* no changes */
break;
case 1: /* Group A mode 1 */
/* bits 5-3 are reserved by Group A mode 1 */
chip->in_mask[2] &= ~0x38;
chip->out_mask[2] &= ~0x38;
break;
case 2: /* Group A mode 2 */
/* bits 7-3 are reserved by Group A mode 2 */
chip->in_mask[2] &= ~0xF8;
chip->out_mask[2] &= ~0xF8;
break;
}
switch(chip->groupB_mode)
{
case 0: /* Group B mode 0 */
/* no changes */
break;
case 1: /* Group B mode 1 */
/* bits 2-0 are reserved by Group B mode 1 */
chip->in_mask[2] &= ~0x07;
chip->out_mask[2] &= ~0x07;
break;
}
/* KT: 25-Dec-99 - 8255 resets latches when mode set */
chip->latch[0] = chip->latch[1] = chip->latch[2] = 0;
if (call_handlers)
{
for (i = 0; i < 3; i++)
ppi8255_write_port(chip, i, which);
}
}
void ppi8255_w(INT32 which, INT32 offset, UINT8 data)
{
ppi8255 *chip = &chips[which];
offset %= 4;
switch( offset )
{
case 0: /* Port A write */
case 1: /* Port B write */
case 2: /* Port C write */
chip->latch[offset] = data;
ppi8255_write_port(chip, offset, which);
switch(offset)
{
case 0:
if (!chip->portA_dir && (chip->groupA_mode != 0))
{
chip->obf_a = 1;
ppi8255_write_port(chip, 2, which);
}
break;
case 1:
if (!chip->portB_dir && (chip->groupB_mode != 0))
{
chip->obf_b = 1;
ppi8255_write_port(chip, 2, which);
}
break;
}
break;
case 3: /* Control word */
if (data & 0x80)
{
set_mode(which, data & 0x7f, 1);
}
else
{
/* bit set/reset */
INT32 bit;
bit = (data >> 1) & 0x07;
if (data & 1)
chip->latch[2] |= (1<<bit); /* set bit */
else
chip->latch[2] &= ~(1<<bit); /* reset bit */
ppi8255_write_port(chip, 2, which);
}
break;
}
}
void ppi8255_init(INT32 num)
{
for (INT32 i = 0; i < num; i++) {
ppi8255 *chip = &chips[i];
memset(chip, 0, sizeof(*chip));
set_mode(i, 0x1b, 0);
}
}
void ppi8255_exit()
{
for (INT32 i = 0; i < MAX_PPIS; i++) {
ppi8255 *chip = &chips[i];
memset(chip, 0, sizeof(*chip));
}
PPI0PortReadA = NULL;
PPI0PortReadB = NULL;
PPI0PortReadC = NULL;
PPI0PortWriteA = NULL;
PPI0PortWriteB = NULL;
PPI0PortWriteC = NULL;
PPI1PortReadA = NULL;
PPI1PortReadB = NULL;
PPI1PortReadC = NULL;
PPI1PortWriteA = NULL;
PPI1PortWriteB = NULL;
PPI1PortWriteC = NULL;
PPI2PortReadA = NULL;
PPI2PortReadB = NULL;
PPI2PortReadC = NULL;
PPI2PortWriteA = NULL;
PPI2PortWriteB = NULL;
PPI2PortWriteC = NULL;
}
void ppi8255_scan()
{
SCAN_VAR(chips);
}
void ppi8255_set_portC( INT32 which, UINT8 data ) { ppi8255_input(&chips[which], 2, data, which); }
#undef MAX_PPIS

View File

@ -0,0 +1,27 @@
typedef UINT8 (*PPIPortRead)();
typedef void (*PPIPortWrite)(UINT8 data);
extern PPIPortRead PPI0PortReadA;
extern PPIPortRead PPI0PortReadB;
extern PPIPortRead PPI0PortReadC;
extern PPIPortWrite PPI0PortWriteA;
extern PPIPortWrite PPI0PortWriteB;
extern PPIPortWrite PPI0PortWriteC;
extern PPIPortRead PPI1PortReadA;
extern PPIPortRead PPI1PortReadB;
extern PPIPortRead PPI1PortReadC;
extern PPIPortWrite PPI1PortWriteA;
extern PPIPortWrite PPI1PortWriteB;
extern PPIPortWrite PPI1PortWriteC;
extern PPIPortRead PPI2PortReadA;
extern PPIPortRead PPI2PortReadB;
extern PPIPortRead PPI2PortReadC;
extern PPIPortWrite PPI2PortWriteA;
extern PPIPortWrite PPI2PortWriteB;
extern PPIPortWrite PPI2PortWriteC;
void ppi8255_init(INT32 num);
void ppi8255_exit();
void ppi8255_scan();
UINT8 ppi8255_r(INT32 which, INT32 offset);
void ppi8255_w(INT32 which, INT32 offset, UINT8 data);
void ppi8255_set_portC( INT32 which, UINT8 data );

328
src/burn/devices/eeprom.cpp Normal file
View File

@ -0,0 +1,328 @@
#include "burnint.h"
#include "eeprom.h"
#define SERIAL_BUFFER_LENGTH 40
#define MEMORY_SIZE 1024
static const eeprom_interface *intf;
static INT32 serial_count;
static UINT8 serial_buffer[SERIAL_BUFFER_LENGTH];
static UINT8 eeprom_data[MEMORY_SIZE];
static INT32 eeprom_data_bits;
static INT32 eeprom_read_address;
static INT32 eeprom_clock_count;
static INT32 latch, reset_line, clock_line, sending;
static INT32 locked;
static INT32 reset_delay;
static INT32 neeprom_available = 0;
static INT32 eeprom_command_match(const char *buf, const char *cmd, INT32 len)
{
if ( cmd == 0 ) return 0;
if ( len == 0 ) return 0;
for (;len>0;)
{
char b = *buf;
char c = *cmd;
if ((b==0) || (c==0))
return (b==c);
switch ( c )
{
case '0':
case '1':
if (b != c) return 0;
case 'X':
case 'x':
buf++;
len--;
cmd++;
break;
case '*':
c = cmd[1];
switch( c )
{
case '0':
case '1':
if (b == c) { cmd++; }
else { buf++; len--; }
break;
default: return 0;
}
}
}
return (*cmd==0);
}
INT32 EEPROMAvailable()
{
return neeprom_available;
}
void EEPROMInit(const eeprom_interface *interface)
{
intf = interface;
if ((1 << intf->address_bits) * intf->data_bits / 8 > MEMORY_SIZE)
{
bprintf(0, _T("EEPROM larger than eeprom allows"));
}
memset(eeprom_data,0xff,(1 << intf->address_bits) * intf->data_bits / 8);
serial_count = 0;
latch = 0;
reset_line = EEPROM_ASSERT_LINE;
clock_line = EEPROM_ASSERT_LINE;
eeprom_read_address = 0;
sending = 0;
if (intf->cmd_unlock) locked = 1;
else locked = 0;
char output[128];
sprintf (output, "config\\games\\%s.nv", BurnDrvGetTextA(DRV_NAME));
neeprom_available = 0;
INT32 len = ((1 << intf->address_bits) * (intf->data_bits >> 3)) & (MEMORY_SIZE-1);
FILE *fz = fopen(output, "rb");
if (fz != NULL) {
neeprom_available = 1;
fread (eeprom_data, len, 1, fz);
fclose (fz);
}
}
void EEPROMExit()
{
char output[128];
sprintf (output, "config\\games\\%s.nv", BurnDrvGetTextA(DRV_NAME));
neeprom_available = 0;
INT32 len = ((1 << intf->address_bits) * (intf->data_bits >> 3)) & (MEMORY_SIZE-1);
FILE *fz = fopen(output, "wb");
fwrite (eeprom_data, len, 1, fz);
fclose (fz);
}
static void eeprom_write(INT32 bit)
{
if (serial_count >= SERIAL_BUFFER_LENGTH-1)
{
bprintf(0, _T("error: EEPROM serial buffer overflow\n"));
return;
}
serial_buffer[serial_count++] = (bit ? '1' : '0');
serial_buffer[serial_count] = 0;
if ( (serial_count > intf->address_bits) &&
eeprom_command_match((char*)serial_buffer,intf->cmd_read,strlen((char*)serial_buffer)-intf->address_bits) )
{
INT32 i,address;
address = 0;
for (i = serial_count-intf->address_bits;i < serial_count;i++)
{
address <<= 1;
if (serial_buffer[i] == '1') address |= 1;
}
if (intf->data_bits == 16)
eeprom_data_bits = (eeprom_data[2*address+0] << 8) + eeprom_data[2*address+1];
else
eeprom_data_bits = eeprom_data[address];
eeprom_read_address = address;
eeprom_clock_count = 0;
sending = 1;
serial_count = 0;
}
else if ( (serial_count > intf->address_bits) &&
eeprom_command_match((char*)serial_buffer,intf->cmd_erase,strlen((char*)serial_buffer)-intf->address_bits) )
{
INT32 i,address;
address = 0;
for (i = serial_count-intf->address_bits;i < serial_count;i++)
{
address <<= 1;
if (serial_buffer[i] == '1') address |= 1;
}
if (locked == 0)
{
if (intf->data_bits == 16)
{
eeprom_data[2*address+0] = 0xff;
eeprom_data[2*address+1] = 0xff;
}
else
eeprom_data[address] = 0xff;
}
else
serial_count = 0;
}
else if ( (serial_count > (intf->address_bits + intf->data_bits)) &&
eeprom_command_match((char*)serial_buffer,intf->cmd_write,strlen((char*)serial_buffer)-(intf->address_bits + intf->data_bits)) )
{
INT32 i,address,data;
address = 0;
for (i = serial_count-intf->data_bits-intf->address_bits;i < (serial_count-intf->data_bits);i++)
{
address <<= 1;
if (serial_buffer[i] == '1') address |= 1;
}
data = 0;
for (i = serial_count-intf->data_bits;i < serial_count;i++)
{
data <<= 1;
if (serial_buffer[i] == '1') data |= 1;
}
if (locked == 0)
{
if (intf->data_bits == 16)
{
eeprom_data[2*address+0] = data >> 8;
eeprom_data[2*address+1] = data & 0xff;
}
else
eeprom_data[address] = data;
}
else
serial_count = 0;
}
else if ( eeprom_command_match((char*)serial_buffer,intf->cmd_lock,strlen((char*)serial_buffer)) )
{
locked = 1;
serial_count = 0;
}
else if ( eeprom_command_match((char*)serial_buffer,intf->cmd_unlock,strlen((char*)serial_buffer)) )
{
locked = 0;
serial_count = 0;
}
}
void EEPROMReset()
{
serial_count = 0;
sending = 0;
reset_delay = intf->reset_delay;
}
void EEPROMWriteBit(INT32 bit)
{
latch = bit;
}
INT32 EEPROMRead()
{
INT32 res;
if (sending)
res = (eeprom_data_bits >> intf->data_bits) & 1;
else
{
if (reset_delay > 0)
{
/* this is needed by wbeachvl */
reset_delay--;
res = 0;
}
else
res = 1;
}
return res;
}
void EEPROMSetCSLine(INT32 state)
{
reset_line = state;
if (reset_line != EEPROM_CLEAR_LINE)
EEPROMReset();
}
void EEPROMSetClockLine(INT32 state)
{
if (state == EEPROM_PULSE_LINE || (clock_line == EEPROM_CLEAR_LINE && state != EEPROM_CLEAR_LINE))
{
if (reset_line == EEPROM_CLEAR_LINE)
{
if (sending)
{
if (eeprom_clock_count == intf->data_bits && intf->enable_multi_read)
{
eeprom_read_address = (eeprom_read_address + 1) & ((1 << intf->address_bits) - 1);
if (intf->data_bits == 16)
eeprom_data_bits = (eeprom_data[2*eeprom_read_address+0] << 8) + eeprom_data[2*eeprom_read_address+1];
else
eeprom_data_bits = eeprom_data[eeprom_read_address];
eeprom_clock_count = 0;
}
eeprom_data_bits = (eeprom_data_bits << 1) | 1;
eeprom_clock_count++;
}
else
eeprom_write(latch);
}
}
clock_line = state;
}
void EEPROMFill(const UINT8 *data, INT32 offset, INT32 length)
{
memcpy(eeprom_data + offset, data, length);
}
void EEPROMScan(INT32 nAction, INT32* pnMin)
{
struct BurnArea ba;
if (nAction & ACB_DRIVER_DATA) {
if (pnMin && *pnMin < 0x020902) {
*pnMin = 0x029705;
}
memset(&ba, 0, sizeof(ba));
ba.Data = serial_buffer;
ba.nLen = SERIAL_BUFFER_LENGTH;
ba.szName = "Serial Buffer";
BurnAcb(&ba);
SCAN_VAR(serial_count);
SCAN_VAR(eeprom_data_bits);
SCAN_VAR(eeprom_read_address);
SCAN_VAR(eeprom_clock_count);
SCAN_VAR(latch);
SCAN_VAR(reset_line);
SCAN_VAR(clock_line);
SCAN_VAR(sending);
SCAN_VAR(locked);
SCAN_VAR(reset_delay);
}
// if (nAction & ACB_NVRAM) {
//
// if (pnMin && (nAction & ACB_TYPEMASK) == ACB_NVRAM) {
// *pnMin = 0x02705;
// }
//
// memset(&ba, 0, sizeof(ba));
// ba.Data = eeprom_data;
// ba.nLen = MEMORY_SIZE;
// ba.szName = "EEPROM memory";
// BurnAcb(&ba);
// }
}

56
src/burn/devices/eeprom.h Normal file
View File

@ -0,0 +1,56 @@
typedef struct _eeprom_interface eeprom_interface;
struct _eeprom_interface
{
INT32 address_bits; /* EEPROM has 2^address_bits cells */
INT32 data_bits; /* every cell has this many bits (8 or 16) */
const char *cmd_read; /* read command string, e.g. "0110" */
const char *cmd_write; /* write command string, e.g. "0111" */
const char *cmd_erase; /* erase command string, or 0 if n/a */
const char *cmd_lock; /* lock command string, or 0 if n/a */
const char *cmd_unlock; /* unlock command string, or 0 if n/a */
INT32 enable_multi_read; /* set to 1 to enable multiple values to be read from one read command */
INT32 reset_delay; /* number of times eeprom_read_bit() should return 0 after a reset, */
/* before starting to return 1. */
};
// default for most in fba
const eeprom_interface eeprom_interface_93C46 =
{
6, // address bits 6
16, // data bits 16
"*110", // read 1 10 aaaaaa
"*101", // write 1 01 aaaaaa dddddddddddddddd
"*111", // erase 1 11 aaaaaa
"*10000xxxx", // lock 1 00 00xxxx
"*10011xxxx", // unlock 1 00 11xxxx
1,
0
};
#define EEPROM_CLEAR_LINE 0
#define EEPROM_ASSERT_LINE 1
#define EEPROM_PULSE_LINE 2
void EEPROMInit(const eeprom_interface *interface);
void EEPROMReset();
void EEPROMExit();
INT32 EEPROMAvailable(); // are we loading an eeprom file?
INT32 EEPROMRead();
// Write each individually
void EEPROMWriteBit(INT32 bit);
void EEPROMSetCSLine(INT32 state);
void EEPROMSetClockLine(INT32 state);
// Or all at once
#define EEPROMWrite(clock, cs, bit) \
EEPROMWriteBit(bit); \
EEPROMSetCSLine(cs ? EEPROM_CLEAR_LINE : EEPROM_ASSERT_LINE); \
EEPROMSetClockLine(clock ? EEPROM_ASSERT_LINE : EEPROM_CLEAR_LINE)
void EEPROMFill(const UINT8 *data, INT32 offset, INT32 length);
void EEPROMScan(INT32 nAction, INT32* pnMin);

View File

@ -0,0 +1,122 @@
// Kaneko Pandora module
#include "tiles_generic.h"
static UINT16 *pandora_temp = NULL;
static UINT8 *pandora_ram = NULL;
static UINT8 *pandora_gfx = NULL;
static INT32 pandora_clear;
static INT32 pandora_xoffset;
static INT32 pandora_yoffset;
static INT32 pandora_color_offset;
INT32 pandora_flipscreen;
void pandora_set_clear(INT32 clear)
{
pandora_clear = clear;
}
void pandora_update(UINT16 *dest)
{
for (INT32 i = 0; i < nScreenWidth * nScreenHeight; i++) {
if (pandora_temp[i]) {
dest[i] = pandora_temp[i] & 0x3ff;
}
}
}
void pandora_buffer_sprites()
{
INT32 sx=0, sy=0, x=0, y=0;
if (pandora_clear) memset (pandora_temp, 0, nScreenWidth * nScreenHeight * sizeof(UINT16));
for (INT32 offs = 0; offs < 0x1000; offs += 8)
{
INT32 attr = pandora_ram[offs+7];
INT32 code = pandora_ram[offs+6] + ((attr & 0x3f) << 8);
INT32 dy = pandora_ram[offs+5];
INT32 dx = pandora_ram[offs+4];
INT32 color = pandora_ram[offs+3];
INT32 flipy = attr & 0x40;
INT32 flipx = attr & 0x80;
if (color & 1) dx |= 0x100;
if (color & 2) dy |= 0x100;
if (color & 4)
{
x += dx;
y += dy;
}
else
{
x = dx;
y = dy;
}
if (pandora_flipscreen)
{
sx = 240 - x;
sy = 240 - y;
flipx = !flipx;
flipy = !flipy;
}
else
{
sx = x;
sy = y;
}
sx = (sx + pandora_xoffset) & 0x1ff;
sy = (sy + pandora_yoffset) & 0x1ff;
if (sx & 0x100) sx -= 0x200;
if (sy & 0x100) sy -= 0x200;
if (sx >= nScreenWidth || sx < -15) continue;
if (sy >= nScreenHeight || sy < -15) continue;
if (flipy) {
if (flipx) {
Render16x16Tile_Mask_FlipXY_Clip(pandora_temp, code, sx, sy, color >> 4, 4, 0, pandora_color_offset, pandora_gfx);
} else {
Render16x16Tile_Mask_FlipY_Clip(pandora_temp, code, sx, sy, color >> 4, 4, 0, pandora_color_offset, pandora_gfx);
}
} else {
if (flipx) {
Render16x16Tile_Mask_FlipX_Clip(pandora_temp, code, sx, sy, color >> 4, 4, 0, pandora_color_offset, pandora_gfx);
} else {
Render16x16Tile_Mask_Clip(pandora_temp, code, sx, sy, color >> 4, 4, 0, pandora_color_offset, pandora_gfx);
}
}
}
}
// must be called after GenericTilesInit()
void pandora_init(UINT8 *ram, UINT8 *gfx, INT32 color_offset, INT32 x, INT32 y)
{
pandora_ram = ram;
pandora_xoffset = x;
pandora_yoffset = y;
pandora_gfx = gfx;
pandora_color_offset = color_offset;
if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
BurnDrvGetVisibleSize(&nScreenHeight, &nScreenWidth);
} else {
BurnDrvGetVisibleSize(&nScreenWidth, &nScreenHeight);
}
pandora_temp = (UINT16*)malloc(nScreenWidth * nScreenHeight * sizeof(UINT16));
pandora_clear = 1;
}
void pandora_exit()
{
if (pandora_temp) {
free (pandora_temp);
pandora_temp = NULL;
}
pandora_ram = pandora_gfx = NULL;
}

View File

@ -0,0 +1,7 @@
extern INT32 pandora_flipscreen;
void pandora_set_clear(INT32 clear);
void pandora_update(UINT16 *dest);
void pandora_buffer_sprites();
void pandora_init(UINT8 *ram, UINT8 *gfx, INT32 color_offset, INT32 x, INT32 y);
void pandora_exit();

View File

@ -0,0 +1,525 @@
//
// FB Alpha Seibu sound hardware module
//
// Games using this hardware:
//
// Dead Angle 2x YM2203 + adpcm -- not implemented
//
// Dynamite Duke 1x YM3812 + 1x M6295
// Toki 1x YM3812 + 1x M6295
// Raiden 1x YM3812 + 1x M6295
// Blood Brothers 1x YM3812 + 1x M6295
// D-Con 1x YM3812 + 1x M6295
// Legionnaire 1x YM3812 + 1x M6295
//
// SD Gundam PSK 1x YM2151 + 1x M6295
// Raiden II 1x YM2151 + 2x M6295
// Raiden DX 1x YM2151 + 2x M6295
// Zero Team 1x YM2151 + 2x M6295
//
// Cross Shooter 1x YM2151 + ?
// Cabal 1x YM2151 + adpcm -- not implemented
//
#include "burnint.h"
#include "burn_ym3812.h"
#include "burn_ym2151.h"
#include "burn_ym2203.h"
#include "msm6295.h"
#include "bitswap.h"
static UINT8 main2sub[2];
static UINT8 sub2main[2];
static INT32 main2sub_pending;
static INT32 sub2main_pending;
static INT32 SeibuSoundBank;
UINT8 *SeibuZ80DecROM;
UINT8 *SeibuZ80ROM;
UINT8 *SeibuZ80RAM;
INT32 seibu_coin_input;
static INT32 seibu_sndcpu_frequency;
static INT32 seibu_snd_type;
static INT32 is_sdgndmps = 0;
enum
{
VECTOR_INIT,
RST10_ASSERT,
RST10_CLEAR,
RST18_ASSERT,
RST18_CLEAR
};
static void update_irq_lines(INT32 param)
{
static INT32 irq1,irq2;
switch(param)
{
case VECTOR_INIT:
irq1 = irq2 = 0xff;
break;
case RST10_ASSERT:
irq1 = 0xd7;
break;
case RST10_CLEAR:
irq1 = 0xff;
break;
case RST18_ASSERT:
irq2 = 0xdf;
break;
case RST18_CLEAR:
irq2 = 0xff;
break;
}
if ((irq1 & irq2) == 0xff) {
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
} else {
if (irq2 == 0xdf) {
ZetSetVector(irq1 & irq2);
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
}
}
}
UINT8 seibu_main_word_read(INT32 offset)
{
offset = (offset >> 1) & 7;
switch (offset)
{
case 2:
case 3:
return sub2main[offset-2];
case 5:
return main2sub_pending ? 1 : 0;
default:
return 0xff;
}
}
void seibu_main_word_write(INT32 offset, UINT8 data)
{
offset = (offset >> 1) & 7;
switch (offset)
{
case 0:
case 1:
main2sub[offset] = data;
break;
case 4:
if (is_sdgndmps) update_irq_lines(RST10_ASSERT);
update_irq_lines(RST18_ASSERT);
break;
case 6:
sub2main_pending = 0;
main2sub_pending = 1;
break;
default:
break;
}
}
void seibu_sound_mustb_write_word(INT32 /*offset*/, UINT8 data)
{
main2sub[0] = data & 0xff;
main2sub[1] = data >> 8;
update_irq_lines(RST18_ASSERT);
}
static void seibu_z80_bank(INT32 data)
{
SeibuSoundBank = data & 1;
ZetMapArea(0x8000, 0xffff, 0, SeibuZ80ROM + 0x10000 + (data & 1) * 0x8000);
ZetMapArea(0x8000, 0xffff, 2, SeibuZ80ROM + 0x10000 + (data & 1) * 0x8000);
}
void __fastcall seibu_sound_write(UINT16 address, UINT8 data)
{
switch (address)
{
case 0x4000:
main2sub_pending = 0;
sub2main_pending = 1;
return;
case 0x4001:
update_irq_lines(VECTOR_INIT);
return;
case 0x4002:
// rst10 ack (unused)
return;
case 0x4003:
update_irq_lines(RST18_CLEAR);
return;
case 0x4007:
seibu_z80_bank(data);
return;
case 0x4008:
switch (seibu_snd_type & 3)
{
case 0:
BurnYM3812Write(0, data);
return;
case 1:
BurnYM2151SelectRegister(data);
return;
case 2:
BurnYM2203Write(0, 0, data);
return;
}
return;
case 0x4009:
switch (seibu_snd_type & 3)
{
case 0:
BurnYM3812Write(1, data);
return;
case 1:
BurnYM2151WriteRegister(data);
return;
case 2:
BurnYM2203Write(0, 1, data);
return;
}
return;
case 0x4018:
case 0x4019:
sub2main[address & 1] = data;
return;
case 0x401b:
// coin counters
return;
case 0x6000:
MSM6295Command(0, data);
return;
case 0x6002:
if (seibu_snd_type & 4) MSM6295Command(1, data);
return;
// type 2
case 0x6008:
case 0x6009:
if (seibu_snd_type == 2) BurnYM2203Write(1, address & 1, data);
return;
}
}
UINT8 __fastcall seibu_sound_read(UINT16 address)
{
switch (address)
{
case 0x4008:
switch (seibu_snd_type & 3)
{
case 0:
return BurnYM3812Read(0);
case 1:
return BurnYM2151ReadStatus();
case 2:
return BurnYM2203Read(0, 0);
}
return 0;
case 0x4009: {
if (seibu_snd_type < 2) return 0;
return BurnYM2203Read(0, 1);
}
case 0x4010:
case 0x4011:
return main2sub[address & 1];
case 0x4012:
return sub2main_pending ? 1 : 0;
case 0x4013:
return seibu_coin_input;
case 0x6000:
return MSM6295ReadStatus(0);
case 0x6002:
if (seibu_snd_type & 4) return MSM6295ReadStatus(0);
}
return 0;
}
static UINT8 decrypt_data(INT32 a,INT32 src)
{
if ( BIT(a,9) & BIT(a,8)) src ^= 0x80;
if ( BIT(a,11) & BIT(a,4) & BIT(a,1)) src ^= 0x40;
if ( BIT(a,11) & ~BIT(a,8) & BIT(a,1)) src ^= 0x04;
if ( BIT(a,13) & ~BIT(a,6) & BIT(a,4)) src ^= 0x02;
if (~BIT(a,11) & BIT(a,9) & BIT(a,2)) src ^= 0x01;
if (BIT(a,13) & BIT(a,4)) src = BITSWAP08(src,7,6,5,4,3,2,0,1);
if (BIT(a, 8) & BIT(a,4)) src = BITSWAP08(src,7,6,5,4,2,3,1,0);
return src;
}
static UINT8 decrypt_opcode(INT32 a,INT32 src)
{
if ( BIT(a,9) & BIT(a,8)) src ^= 0x80;
if ( BIT(a,11) & BIT(a,4) & BIT(a,1)) src ^= 0x40;
if (~BIT(a,13) & BIT(a,12)) src ^= 0x20;
if (~BIT(a,6) & BIT(a,1)) src ^= 0x10;
if (~BIT(a,12) & BIT(a,2)) src ^= 0x08;
if ( BIT(a,11) & ~BIT(a,8) & BIT(a,1)) src ^= 0x04;
if ( BIT(a,13) & ~BIT(a,6) & BIT(a,4)) src ^= 0x02;
if (~BIT(a,11) & BIT(a,9) & BIT(a,2)) src ^= 0x01;
if (BIT(a,13) & BIT(a,4)) src = BITSWAP08(src,7,6,5,4,3,2,0,1);
if (BIT(a, 8) & BIT(a,4)) src = BITSWAP08(src,7,6,5,4,2,3,1,0);
if (BIT(a,12) & BIT(a,9)) src = BITSWAP08(src,7,6,4,5,3,2,1,0);
if (BIT(a,11) & ~BIT(a,6)) src = BITSWAP08(src,6,7,5,4,3,2,1,0);
return src;
}
static void seibu_sound_decrypt(INT32 length)
{
for (INT32 i = 0; i < length; i++)
{
UINT8 src = SeibuZ80ROM[i];
SeibuZ80ROM[i] = decrypt_data(i,src);
SeibuZ80DecROM[i] = decrypt_opcode(i,src);
}
}
static INT32 DrvSynchroniseStream(INT32 nSoundRate)
{
return (INT64)ZetTotalCycles() * nSoundRate / seibu_sndcpu_frequency;
}
static void DrvFMIRQHandler(INT32, INT32 nStatus)
{
if (nStatus) {
update_irq_lines(RST10_ASSERT);
} else {
update_irq_lines(RST10_CLEAR);
}
}
static void Drv2151FMIRQHandler(INT32 nStatus)
{
DrvFMIRQHandler(0, nStatus);
}
static double Drv2203GetTime()
{
return (double)ZetTotalCycles() / seibu_sndcpu_frequency;
}
void seibu_sound_reset()
{
ZetOpen(0);
ZetReset();
update_irq_lines(VECTOR_INIT);
ZetClose();
switch (seibu_snd_type & 3)
{
case 0:
BurnYM3812Reset();
break;
case 1:
BurnYM2151Reset();
break;
case 2:
BurnYM2203Reset();
break;
}
MSM6295Reset(0);
if (seibu_snd_type & 4) MSM6295Reset(1);
memset (main2sub, 0, 2);
memset (sub2main, 0, 2);
main2sub_pending = 0;
sub2main_pending = 0;
seibu_coin_input = 0;
SeibuSoundBank = 0;
}
void seibu_sound_init(INT32 type, INT32 len, INT32 freq0 /*cpu*/, INT32 freq1 /*ym*/, INT32 freq2 /*oki*/)
{
seibu_snd_type = type;
if (len && SeibuZ80DecROM != NULL) {
seibu_sound_decrypt(len);
} else {
SeibuZ80DecROM = SeibuZ80ROM;
}
seibu_sndcpu_frequency = freq0;
ZetInit(1);
ZetOpen(0);
ZetMapArea(0x0000, 0x1fff, 0, SeibuZ80ROM);
ZetMapArea(0x0000, 0x1fff, 2, SeibuZ80DecROM, SeibuZ80ROM);
ZetMapArea(0x2000, 0x27ff, 0, SeibuZ80RAM);
ZetMapArea(0x2000, 0x27ff, 1, SeibuZ80RAM);
ZetMapArea(0x2000, 0x27ff, 2, SeibuZ80RAM);
ZetSetWriteHandler(seibu_sound_write);
ZetSetReadHandler(seibu_sound_read);
ZetMemEnd();
ZetClose();
switch (seibu_snd_type & 3)
{
case 0:
BurnYM3812Init(freq1, &DrvFMIRQHandler, &DrvSynchroniseStream, 0);
BurnTimerAttachZetYM3812(freq0);
break;
case 1:
BurnYM2151Init(freq1, 100.0);
BurnYM2151SetIrqHandler(&Drv2151FMIRQHandler);
break;
case 2:
BurnYM2203Init(2, freq1, DrvFMIRQHandler, DrvSynchroniseStream, Drv2203GetTime, 0);
BurnTimerAttachZet(freq0);
break;
}
MSM6295Init(0, freq2, 100.0, 1);
if (seibu_snd_type & 4) MSM6295Init(1, freq2, 100.0, 1);
// init kludge for sdgndmps
if (!strcmp(BurnDrvGetTextA(DRV_NAME), "sdgndmps")) {
is_sdgndmps = 1;
}
}
void seibu_sound_exit()
{
switch (seibu_snd_type & 3)
{
case 0:
BurnYM3812Exit();
break;
case 1:
BurnYM2151Exit();
break;
case 2:
BurnYM2203Exit();
break;
}
MSM6295Exit(0);
if (seibu_snd_type & 4) MSM6295Exit(1);
ZetExit();
MSM6295ROM = NULL;
SeibuZ80DecROM = NULL;
SeibuZ80ROM = NULL;
SeibuZ80RAM = NULL;
seibu_sndcpu_frequency = 0;
is_sdgndmps = 0;
}
void seibu_sound_update(INT16 *pbuf, INT32 nLen)
{
switch (seibu_snd_type & 3)
{
case 0:
BurnYM3812Update(pbuf, nLen);
break;
case 1:
BurnYM2151Render(pbuf, nLen);
break;
case 2:
BurnYM2203Update(pbuf, nLen);
break;
}
if (seibu_snd_type & 4)
MSM6295Render(1, pbuf, nLen);
MSM6295Render(0, pbuf, nLen);
}
void seibu_sound_scan(INT32 *pnMin, INT32 nAction)
{
if (nAction & ACB_VOLATILE)
{
ZetScan(nAction);
switch (seibu_snd_type & 3)
{
case 0:
BurnYM3812Scan(nAction, pnMin);
break;
case 1:
BurnYM2203Scan(nAction, pnMin);
break;
case 2:
BurnYM2151Scan(nAction);
break;
}
MSM6295Scan(0, nAction);
if (seibu_snd_type & 4) {
MSM6295Scan(1, nAction);
}
SCAN_VAR(main2sub[0]);
SCAN_VAR(main2sub[1]);
SCAN_VAR(sub2main[0]);
SCAN_VAR(sub2main[1]);
SCAN_VAR(main2sub_pending);
SCAN_VAR(sub2main_pending);
SCAN_VAR(SeibuSoundBank);
}
if (nAction & ACB_WRITE)
{
ZetOpen(0);
seibu_z80_bank(SeibuSoundBank);
ZetClose();
}
}

View File

@ -0,0 +1,32 @@
#include "burn_ym3812.h"
#include "burn_ym2151.h"
#include "burn_ym2203.h"
#include "msm6295.h"
extern UINT8 *SeibuZ80DecROM;
extern UINT8 *SeibuZ80ROM;
extern UINT8 *SeibuZ80RAM;
extern INT32 seibu_coin_input;
unsigned char seibu_main_word_read(INT32 offset);
void seibu_main_word_write(INT32 offset, UINT8 data);
void seibu_sound_mustb_write_word(INT32 offset, UINT8 data);
void seibu_sound_reset();
void seibu_sound_update(INT16 *pbuf, INT32 nLen);
/*
Type 0 - YM3812
Type 1 - YM2151
Type 2 - YM2203
all init a single oki6295
add 4 to init a second oki6295
*/
void seibu_sound_init(INT32 type, INT32 encrypted_len, INT32 freq0 /*cpu*/, INT32 freq1 /*ym*/, INT32 freq2 /*oki*/);
void seibu_sound_exit();
void seibu_sound_scan(INT32 *pnMin, INT32 nAction);

View File

@ -0,0 +1,331 @@
#include "burnint.h"
#include "time.h"
#include "timekpr.h"
typedef struct
{
UINT8 control;
UINT8 seconds;
UINT8 minutes;
UINT8 hours;
UINT8 day;
UINT8 date;
UINT8 month;
UINT8 year;
UINT8 century;
UINT8 *data;
INT32 type;
INT32 size;
INT32 offset_control;
INT32 offset_seconds;
INT32 offset_minutes;
INT32 offset_hours;
INT32 offset_day;
INT32 offset_date;
INT32 offset_month;
INT32 offset_year;
INT32 offset_century;
INT32 offset_flags;
} timekeeper_chip;
static timekeeper_chip Chip;
static INT32 AllocatedOwnDataArea = 0;
#define MASK_SECONDS ( 0x7f )
#define MASK_MINUTES ( 0x7f )
#define MASK_HOURS ( 0x3f )
#define MASK_DAY ( 0x07 )
#define MASK_DATE ( 0x3f )
#define MASK_MONTH ( 0x1f )
#define MASK_YEAR ( 0xff )
#define MASK_CENTURY ( 0xff )
#define CONTROL_W ( 0x80 )
#define CONTROL_R ( 0x40 )
#define CONTROL_S ( 0x20 ) /* not emulated */
#define CONTROL_CALIBRATION ( 0x1f ) /* not emulated */
#define SECONDS_ST ( 0x80 )
#define DAY_FT ( 0x40 ) /* not emulated */
#define DAY_CEB ( 0x20 ) /* M48T58 */
#define DAY_CB ( 0x10 ) /* M48T58 */
#define DATE_BLE ( 0x80 ) /* M48T58: not emulated */
#define DATE_BL ( 0x40 ) /* M48T58: not emulated */
#define FLAGS_BL ( 0x10 ) /* MK48T08: not emulated */
static inline UINT8 make_bcd(UINT8 data)
{
return ( ( ( data / 10 ) % 10 ) << 4 ) + ( data % 10 );
}
static inline UINT8 from_bcd(UINT8 data)
{
return ( ( ( data >> 4 ) & 15 ) * 10 ) + ( data & 15 );
}
static INT32 inc_bcd( UINT8 *data, INT32 mask, INT32 min, INT32 max )
{
INT32 bcd;
INT32 carry;
bcd = ( *( data ) + 1 ) & mask;
carry = 0;
if( ( bcd & 0x0f ) > 9 )
{
bcd &= 0xf0;
bcd += 0x10;
if( bcd > max )
{
bcd = min;
carry = 1;
}
}
*( data ) = ( *( data ) & ~mask ) | ( bcd & mask );
return carry;
}
static void counter_to_ram(UINT8 *data, INT32 offset, INT32 counter)
{
if( offset >= 0 )
{
data[ offset ] = counter;
}
}
static void counters_to_ram()
{
counter_to_ram( Chip.data, Chip.offset_control, Chip.control );
counter_to_ram( Chip.data, Chip.offset_seconds, Chip.seconds );
counter_to_ram( Chip.data, Chip.offset_minutes, Chip.minutes );
counter_to_ram( Chip.data, Chip.offset_hours, Chip.hours );
counter_to_ram( Chip.data, Chip.offset_day, Chip.day );
counter_to_ram( Chip.data, Chip.offset_date, Chip.date );
counter_to_ram( Chip.data, Chip.offset_month, Chip.month );
counter_to_ram( Chip.data, Chip.offset_year, Chip.year );
counter_to_ram( Chip.data, Chip.offset_century, Chip.century );
}
static INT32 counter_from_ram(UINT8 *data, INT32 offset)
{
if( offset >= 0 )
{
return data[ offset ];
}
return 0;
}
static void counters_from_ram()
{
Chip.control = counter_from_ram( Chip.data, Chip.offset_control );
Chip.seconds = counter_from_ram( Chip.data, Chip.offset_seconds );
Chip.minutes = counter_from_ram( Chip.data, Chip.offset_minutes );
Chip.hours = counter_from_ram( Chip.data, Chip.offset_hours );
Chip.day = counter_from_ram( Chip.data, Chip.offset_day );
Chip.date = counter_from_ram( Chip.data, Chip.offset_date );
Chip.month = counter_from_ram( Chip.data, Chip.offset_month );
Chip.year = counter_from_ram( Chip.data, Chip.offset_year );
Chip.century = counter_from_ram( Chip.data, Chip.offset_century );
}
UINT8 TimeKeeperRead(UINT32 offset)
{
return Chip.data[offset];
}
void TimeKeeperWrite(INT32 offset, UINT8 data)
{
if( offset == Chip.offset_control )
{
if( ( Chip.control & CONTROL_W ) != 0 &&
( data & CONTROL_W ) == 0 )
{
counters_from_ram();
}
Chip.control = data;
}
else if( Chip.type == TIMEKEEPER_M48T58 && offset == Chip.offset_day )
{
Chip.day = ( Chip.day & ~DAY_CEB ) | ( data & DAY_CEB );
}
else if( Chip.type == TIMEKEEPER_M48T58 && offset == Chip.offset_date )
{
data &= ~DATE_BL;
}
else if( Chip.type == TIMEKEEPER_MK48T08 && offset == Chip.offset_flags )
{
data &= ~FLAGS_BL;
}
Chip.data[ offset ] = data;
}
void TimeKeeperTick()
{
INT32 carry;
if( ( Chip.seconds & SECONDS_ST ) != 0 ||
( Chip.control & CONTROL_W ) != 0 )
{
return;
}
carry = inc_bcd( &Chip.seconds, MASK_SECONDS, 0x00, 0x59 );
if( carry )
{
carry = inc_bcd( &Chip.minutes, MASK_MINUTES, 0x00, 0x59 );
}
if( carry )
{
carry = inc_bcd( &Chip.hours, MASK_HOURS, 0x00, 0x23 );
}
if( carry )
{
UINT8 month;
UINT8 year;
UINT8 maxdays;
static const UINT8 daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 };
inc_bcd( &Chip.day, MASK_DAY, 0x01, 0x07 );
month = from_bcd( Chip.month );
year = from_bcd( Chip.year );
if( month == 2 && ( year % 4 ) == 0 )
{
maxdays = 0x29;
}
else if( month >= 1 && month <= 12 )
{
maxdays = daysinmonth[ month - 1 ];
}
else
{
maxdays = 0x31;
}
carry = inc_bcd( &Chip.date, MASK_DATE, 0x01, maxdays );
}
if( carry )
{
carry = inc_bcd( &Chip.month, MASK_MONTH, 0x01, 0x12 );
}
if( carry )
{
carry = inc_bcd( &Chip.year, MASK_YEAR, 0x00, 0x99 );
}
if( carry )
{
carry = inc_bcd( &Chip.century, MASK_CENTURY, 0x00, 0x99 );
if( Chip.type == TIMEKEEPER_M48T58 && ( Chip.day & DAY_CEB ) != 0 )
{
Chip.day ^= DAY_CB;
}
}
if( ( Chip.control & CONTROL_R ) == 0 )
{
counters_to_ram();
}
}
void TimeKeeperInit(INT32 type, UINT8 *data)
{
time_t rawtime;
struct tm *timeinfo;
Chip.type = type;
switch( Chip.type )
{
case TIMEKEEPER_M48T02:
Chip.offset_control = 0x7f8;
Chip.offset_seconds = 0x7f9;
Chip.offset_minutes = 0x7fa;
Chip.offset_hours = 0x7fb;
Chip.offset_day = 0x7fc;
Chip.offset_date = 0x7fd;
Chip.offset_month = 0x7fe;
Chip.offset_year = 0x7ff;
Chip.offset_century = -1;
Chip.offset_flags = -1;
Chip.size = 0x800;
break;
case TIMEKEEPER_M48T58:
Chip.offset_control = 0x1ff8;
Chip.offset_seconds = 0x1ff9;
Chip.offset_minutes = 0x1ffa;
Chip.offset_hours = 0x1ffb;
Chip.offset_day = 0x1ffc;
Chip.offset_date = 0x1ffd;
Chip.offset_month = 0x1ffe;
Chip.offset_year = 0x1fff;
Chip.offset_century = -1;
Chip.offset_flags = -1;
Chip.size = 0x2000;
break;
case TIMEKEEPER_MK48T08:
Chip.offset_control = 0x1ff8;
Chip.offset_seconds = 0x1ff9;
Chip.offset_minutes = 0x1ffa;
Chip.offset_hours = 0x1ffb;
Chip.offset_day = 0x1ffc;
Chip.offset_date = 0x1ffd;
Chip.offset_month = 0x1ffe;
Chip.offset_year = 0x1fff;
Chip.offset_century = 0x1ff1;
Chip.offset_flags = 0x1ff0;
Chip.size = 0x2000;
break;
}
if( data == NULL )
{
data = (UINT8*)malloc(Chip.size);
memset(data, 0xff, Chip.size );
AllocatedOwnDataArea = 1;
}
Chip.data = data;
time(&rawtime);
timeinfo = localtime(&rawtime);
Chip.control = 0;
Chip.seconds = make_bcd(timeinfo->tm_sec);
Chip.minutes = make_bcd(timeinfo->tm_min);
Chip.hours = make_bcd(timeinfo->tm_hour);
Chip.day = make_bcd(timeinfo->tm_wday + 1 );
Chip.date = make_bcd(timeinfo->tm_mday );
Chip.month = make_bcd(timeinfo->tm_mon + 1 );
Chip.year = make_bcd(timeinfo->tm_year % 100 );
Chip.century = make_bcd(timeinfo->tm_year / 100 );
}
void TimeKeeperExit()
{
if (AllocatedOwnDataArea) {
free (Chip.data);
Chip.data = NULL;
}
AllocatedOwnDataArea = 0;
memset(&Chip, 0, sizeof(Chip));
}
void TimeKeeperScan(INT32 nAction)
{
struct BurnArea ba;
if (nAction & ACB_NVRAM) {
memset(&ba, 0, sizeof(ba));
ba.Data = Chip.data;
ba.nLen = Chip.size;
ba.szName = "Time Keeper RAM";
BurnAcb(&ba);
}
}

View File

@ -0,0 +1,10 @@
#define TIMEKEEPER_M48T58 ( 1 )
#define TIMEKEEPER_M48T02 ( 2 )
#define TIMEKEEPER_MK48T08 ( 3 )
UINT8 TimeKeeperRead(UINT32 offset);
void TimeKeeperWrite(INT32 offset, UINT8 data);
void TimeKeeperTick();
void TimeKeeperInit(INT32 type, UINT8 *data);
void TimeKeeperExit();
void TimeKeeperScan(INT32 nAction);

79
src/burn/driver.h Normal file
View File

@ -0,0 +1,79 @@
/*
* For the MAME sound cores
*/
#ifndef DRIVER_H
#define DRIVER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#if !defined (_WIN32)
#define __cdecl
#endif
#ifndef INLINE
#define INLINE __inline static
#endif
#define FBA
typedef unsigned char UINT8;
typedef signed char INT8;
typedef unsigned short UINT16;
typedef signed short INT16;
typedef unsigned int UINT32;
typedef signed int INT32;
#ifdef _MSC_VER
typedef signed __int64 INT64;
typedef unsigned __int64 UINT64;
#else
__extension__ typedef unsigned long long UINT64;
__extension__ typedef long long INT64;
#endif
#define OSD_CPU_H
/* OPN */
#define HAS_YM2203 1
#define HAS_YM2608 1
#define HAS_YM2610 1
#define HAS_YM2610B 1
#define HAS_YM2612 1
#define HAS_YM3438 1
/* OPL */
#define HAS_YM3812 1
#define HAS_YM3526 1
#define HAS_Y8950 1
enum {
CLEAR_LINE = 0,
ASSERT_LINE,
HOLD_LINE,
PULSE_LINE
};
#define timer_get_time() BurnTimerGetTime()
#define READ8_HANDLER(name) UINT8 name(void)
#define WRITE8_HANDLER(name) void name(UINT8 data)
#ifdef __cplusplus
extern "C" {
#endif
double BurnTimerGetTime(void);
typedef UINT8 (*read8_handler)(UINT32 offset);
typedef void (*write8_handler)(UINT32 offset, UINT32 data);
#ifdef MAME_USE_LOGERROR
void __cdecl logerror(char* szFormat, ...);
#else
#define logerror
#endif
#ifdef __cplusplus
}
#endif
#endif /* DRIVER_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,385 @@
// CPS ----------------------------------
#include "burnint.h"
#include "msm6295.h"
#include "eeprom.h"
#include "timer.h"
// Maximum number of beam-synchronized interrupts to check
#define MAX_RASTER 10
extern UINT32 CpsMProt[4]; // Mprot changes
extern UINT32 CpsBID[3]; // Board ID changes
// cps.cpp
extern INT32 Cps; // 1 = CPS1, 2 = CPS2, 3 = CPS CHanger
extern INT32 Cps1Qs;
extern INT32 Cps1Pic;
extern INT32 nCPS68KClockspeed;
extern INT32 nCpsCycles; // Cycles per frame
extern INT32 nCpsZ80Cycles;
extern UINT8 *CpsGfx; extern UINT32 nCpsGfxLen; // All the graphics
extern UINT8 *CpsRom; extern UINT32 nCpsRomLen; // Program Rom (as in rom)
extern UINT8 *CpsCode; extern UINT32 nCpsCodeLen; // Program Rom (decrypted)
extern UINT8 *CpsZRom; extern UINT32 nCpsZRomLen; // Z80 Roms
extern INT8 *CpsQSam; extern UINT32 nCpsQSamLen; // QSound Sample Roms
extern UINT8 *CpsAd; extern UINT32 nCpsAdLen; // ADPCM Data
extern UINT32 nCpsGfxScroll[4]; // Offset to Scroll tiles
extern UINT32 nCpsGfxMask; // Address mask
extern UINT8* CpsStar;
INT32 CpsInit();
INT32 Cps2Init();
INT32 CpsExit();
INT32 CpsLoadTiles(UINT8 *Tile,INT32 nStart);
INT32 CpsLoadTilesByte(UINT8 *Tile,INT32 nStart);
INT32 CpsLoadTilesForgottn(INT32 nStart);
INT32 CpsLoadTilesForgottnu(INT32 nStart);
INT32 CpsLoadTilesPang(UINT8 *Tile,INT32 nStart);
INT32 CpsLoadTilesHack160(UINT8 *Tile,INT32 nStart);
INT32 CpsLoadTilesBootleg(UINT8 *Tile, INT32 nStart);
INT32 CpsLoadTilesCaptcomb(UINT8 *Tile, INT32 nStart);
INT32 CpsLoadTilesPunipic2(UINT8 *Tile, INT32 nStart);
INT32 CpsLoadTilesSf2ebbl(UINT8 *Tile, INT32 nStart);
INT32 CpsLoadStars(UINT8 *pStar, INT32 nStart);
INT32 CpsLoadStarsByte(UINT8 *pStar, INT32 nStart);
INT32 CpsLoadStarsForgottnAlt(UINT8 *pStar, INT32 nStart);
INT32 Cps2LoadTiles(UINT8 *Tile,INT32 nStart);
INT32 Cps2LoadTilesSIM(UINT8 *Tile,INT32 nStart);
// cps_config.h
#define CPS_B_01 0
#define CPS_B_02 1
#define CPS_B_03 2
#define CPS_B_04 3
#define CPS_B_05 4
#define CPS_B_11 5
#define CPS_B_12 6
#define CPS_B_13 7
#define CPS_B_14 8
#define CPS_B_15 9
#define CPS_B_16 10
#define CPS_B_17 11
#define CPS_B_18 12
#define CPS_B_21_DEF 13
#define CPS_B_21_BT1 14
#define CPS_B_21_BT2 15
#define CPS_B_21_BT3 16
#define CPS_B_21_BT4 17
#define CPS_B_21_BT5 18
#define CPS_B_21_BT6 19
#define CPS_B_21_BT7 20
#define CPS_B_21_QS1 21
#define CPS_B_21_QS2 22
#define CPS_B_21_QS3 23
#define CPS_B_21_QS4 24
#define CPS_B_21_QS5 25
#define HACK_B_1 26
#define HACK_B_2 27
#define HACK_B_3 28
#define HACK_B_4 29
#define GFXTYPE_SPRITES (1<<0)
#define GFXTYPE_SCROLL1 (1<<1)
#define GFXTYPE_SCROLL2 (1<<2)
#define GFXTYPE_SCROLL3 (1<<3)
#define GFXTYPE_STARS (1<<4)
#define mapper_LWCHR 0
#define mapper_LW621 1
#define mapper_DM620 2
#define mapper_ST24M1 3
#define mapper_DM22A 4
#define mapper_DAM63B 5
#define mapper_ST22B 6
#define mapper_TK22B 7
#define mapper_WL24B 8
#define mapper_S224B 9
#define mapper_YI24B 10
#define mapper_AR24B 11
#define mapper_AR22B 12
#define mapper_O224B 13
#define mapper_MS24B 14
#define mapper_CK24B 15
#define mapper_NM24B 16
#define mapper_CA24B 17
#define mapper_CA22B 18
#define mapper_STF29 19
#define mapper_RT24B 20
#define mapper_RT22B 21
#define mapper_KD29B 22
#define mapper_CC63B 23
#define mapper_KR63B 24
#define mapper_S9263B 25
#define mapper_VA63B 26
#define mapper_VA22B 27
#define mapper_Q522B 28
#define mapper_TK263B 29
#define mapper_CD63B 30
#define mapper_PS63B 31
#define mapper_MB63B 32
#define mapper_QD22B 33
#define mapper_QD63B 34
#define mapper_qtono2 35
#define mapper_RCM63B 36
#define mapper_PKB10B 37
#define mapper_pang3 38
#define mapper_sfzch 39
#define mapper_cps2 40
#define mapper_frog 41
extern void SetGfxMapper(INT32 MapperId);
extern INT32 GfxRomBankMapper(INT32 Type, INT32 Code);
extern void SetCpsBId(INT32 CpsBId, INT32 bStars);
// cps_pal.cpp
extern UINT32* CpsPal; // Hicolor version of palette
extern UINT32* CpsObjPal; // Pointer to lagged obj palette
extern INT32 nLagObjectPalettes; // Lag object palettes by one frame if non-zero
INT32 CpsPalInit();
INT32 CpsPalExit();
INT32 CpsPalUpdate(UINT8 *pNewPal,INT32 bRecalcAll);
INT32 CpsStarPalUpdate(UINT8* pNewPal, INT32 nLayer, INT32 bRecalcAll);
// cps_mem.cpp
extern UINT8 *CpsRam90;
extern UINT8 *CpsZRamC0,*CpsZRamF0;
extern UINT8 *CpsSavePal;
extern UINT8 *CpsRam708,*CpsReg,*CpsFrg;
extern UINT8 *CpsSaveReg[MAX_RASTER + 1];
extern UINT8 *CpsSaveFrg[MAX_RASTER + 1];
extern UINT8 *CpsRamFF;
void CpsMapObjectBanks(INT32 nBank);
INT32 CpsMemInit();
INT32 CpsMemExit();
INT32 CpsAreaScan(INT32 nAction,INT32 *pnMin);
// cps_run.cpp
extern UINT8 CpsReset;
extern UINT8 Cpi01A, Cpi01C, Cpi01E;
extern INT32 nIrqLine50, nIrqLine52; // The scanlines at which the interrupts are triggered
extern INT32 CpsDrawSpritesInReverse;
INT32 CpsRunInit();
INT32 CpsRunExit();
INT32 Cps1Frame();
INT32 Cps2Frame();
inline static UINT8* CpsFindGfxRam(INT32 nAddr,INT32 nLen)
{
nAddr&=0xffffff; // 24-bit bus
if (nAddr>=0x900000 && nAddr+nLen<=0x930000) return CpsRam90+nAddr-0x900000;
return NULL;
}
// cps_rw.cpp
// Treble Winner - Added INP(1FD) for sf2ue
#define CPSINPSET INP(000) INP(001) INP(006) INP(007) INP(008) INP(010) INP(011) INP(012) INP(018) INP(019) INP(020) INP(021) INP(029) INP(176) INP(177) INP(179) INP(186) INP(1fd)
// prototype for input bits
#define INP(nnn) extern UINT8 CpsInp##nnn[8];
CPSINPSET
#undef INP
#define INP(nnn) extern UINT8 Inp##nnn;
CPSINPSET
#undef INP
#define CPSINPEX INP(c000) INP(c001) INP(c002) INP(c003)
#define INP(nnnn) extern UINT8 CpsInp##nnnn[8];
CPSINPEX
#undef INP
// For the Forgotten Worlds analog controls
extern UINT16 CpsInp055, CpsInp05d;
extern UINT16 CpsInpPaddle1, CpsInpPaddle2;
extern INT32 PangEEP;
extern INT32 Forgottn;
extern INT32 Cps1QsHack;
extern INT32 Kodh;
extern INT32 Cawingb;
extern INT32 Wofh;
extern INT32 Sf2thndr;
extern INT32 Pzloop2;
extern INT32 Ssf2tb;
extern INT32 Dinopic;
extern INT32 Dinohunt;
extern INT32 Port6SoundWrite;
extern UINT8* CpsEncZRom;
INT32 CpsRwInit();
INT32 CpsRwExit();
INT32 CpsRwGetInp();
UINT8 __fastcall CpsReadByte(UINT32 a);
void __fastcall CpsWriteByte(UINT32 a, UINT8 d);
UINT16 __fastcall CpsReadWord(UINT32 a);
void __fastcall CpsWriteWord(UINT32 a, UINT16 d);
// cps_draw.cpp
extern UINT8 CpsRecalcPal; // Flag - If it is 1, recalc the whole palette
extern INT32 nCpsLcReg; // Address of layer controller register
extern INT32 CpsLayEn[6]; // bits for layer enable
extern INT32 nStartline, nEndline; // specify the vertical slice of the screen to render
extern INT32 nRasterline[MAX_RASTER + 2]; // The lines at which an interrupt occurs
extern INT32 MaskAddr[4];
extern INT32 CpsLayer1XOffs;
extern INT32 CpsLayer2XOffs;
extern INT32 CpsLayer3XOffs;
extern INT32 CpsLayer1YOffs;
extern INT32 CpsLayer2YOffs;
extern INT32 CpsLayer3YOffs;
void DrawFnInit();
INT32 CpsDraw();
INT32 CpsRedraw();
INT32 QsndInit();
void QsndExit();
void QsndReset();
void QsndNewFrame();
void QsndEndFrame();
void QsndSyncZ80();
INT32 QsndScan(INT32 nAction);
// qs_z.cpp
INT32 QsndZInit();
INT32 QsndZExit();
INT32 QsndZScan(INT32 nAction);
// qs_c.cpp
INT32 QscInit(INT32 nRate, INT32 nVolumeShift);
void QscReset();
void QscExit();
INT32 QscScan(INT32 nAction);
void QscNewFrame();
void QscWrite(INT32 a, INT32 d);
INT32 QscUpdate(INT32 nEnd);
// cps_tile.cpp
extern UINT32* CpstPal;
extern UINT32 nCpstType; extern INT32 nCpstX,nCpstY;
extern UINT32 nCpstTile; extern INT32 nCpstFlip;
extern short* CpstRowShift;
extern UINT32 CpstPmsk; // Pixel mask
inline static void CpstSetPal(INT32 nPal)
{
nPal <<= 4;
nPal &= 0x7F0;
CpstPal= CpsPal + nPal;
}
// ctv.cpp
extern INT32 nBgHi;
extern UINT16 ZValue;
extern UINT16 *ZBuf;
extern UINT16 *pZVal;
extern UINT32 nCtvRollX,nCtvRollY;
extern UINT8 *pCtvTile; // Pointer to tile data
extern INT32 nCtvTileAdd; // Amount to add after each tile line
extern UINT8 *pCtvLine; // Pointer to output bitmap
typedef INT32 (*CtvDoFn)();
typedef INT32 (*CpstOneDoFn)();
extern CtvDoFn CtvDoX[0x20];
extern CtvDoFn CtvDoXM[0x20];
extern CtvDoFn CtvDoXB[0x20];
extern CpstOneDoFn CpstOneDoX[3];
extern CpstOneDoFn CpstOneObjDoX[2];
INT32 CtvReady();
// nCpstType constants
// To get size do (nCpstType & 24) + 8
#define CTT_FLIPX ( 1)
#define CTT_CARE ( 2)
#define CTT_ROWS ( 4)
#define CTT_8X8 ( 0)
#define CTT_16X16 ( 8)
#define CTT_32X32 (24)
// cps_obj.cpp
extern INT32 nCpsObjectBank;
extern UINT8 *BootlegSpriteRam;
extern INT32 Sf2Hack;
INT32 CpsObjInit();
INT32 CpsObjExit();
INT32 CpsObjGet();
void CpsObjDrawInit();
INT32 Cps1ObjDraw(INT32 nLevelFrom,INT32 nLevelTo);
INT32 Cps2ObjDraw(INT32 nLevelFrom,INT32 nLevelTo);
// cps_scr.cpp
#define SCROLL_2 0
#define SCROLL_3 1
extern INT32 Ghouls;
extern INT32 Mercs;
extern INT32 Sf2jc;
extern INT32 Ssf2t;
extern INT32 Qad;
extern INT32 Xmcota;
extern INT32 Scroll1TileMask;
extern INT32 Scroll2TileMask;
extern INT32 Scroll3TileMask;
INT32 Cps1Scr1Draw(UINT8 *Base,INT32 sx,INT32 sy);
INT32 Cps1Scr3Draw(UINT8 *Base,INT32 sx,INT32 sy);
INT32 Cps2Scr1Draw(UINT8 *Base,INT32 sx,INT32 sy);
INT32 Cps2Scr3Draw(UINT8 *Base,INT32 sx,INT32 sy);
// cpsr.cpp
extern UINT8 *CpsrBase; // Tile data base
extern INT32 nCpsrScrX,nCpsrScrY; // Basic scroll info
extern UINT16 *CpsrRows; // Row scroll table, 0x400 words long
extern INT32 nCpsrRowStart; // Start of row scroll (can wrap?)
// Information needed to draw a line
struct CpsrLineInfo {
INT32 nStart; // 0-0x3ff - where to start drawing tiles from
INT32 nWidth; // 0-0x400 - width of scroll shifts
// e.g. for no rowscroll at all, nWidth=0
INT32 nTileStart; // Range of tiles which are visible onscreen
INT32 nTileEnd; // (e.g. 0x20 -> 0x50 , wraps around to 0x10)
INT16 Rows[16]; // 16 row scroll values for this line
INT32 nMaxLeft, nMaxRight; // Maximum row shifts left and right
};
extern struct CpsrLineInfo CpsrLineInfo[15];
INT32 Cps1rPrepare();
INT32 Cps2rPrepare();
// cpsrd.cpp
INT32 Cps1rRender();
INT32 Cps2rRender();
// dc_input.cpp
extern struct BurnInputInfo CpsFsi[0x1B];
// ps.cpp
extern UINT8 PsndCode, PsndFade; // Sound code/fade sent to the z80 program
INT32 PsndInit();
INT32 PsndExit();
void PsndNewFrame();
INT32 PsndSyncZ80(INT32 nCycles);
INT32 PsndScan(INT32 nAction);
// ps_z.cpp
INT32 PsndZInit();
INT32 PsndZExit();
INT32 PsndZScan(INT32 nAction);
extern INT32 Kodb;
// ps_m.cpp
extern INT32 bPsmOkay; // 1 if the module is okay
INT32 PsmInit();
INT32 PsmExit();
void PsmNewFrame();
INT32 PsmUpdate(INT32 nEnd);
// kabuki.cpp
void wof_decode();
void dino_decode();
void punisher_decode();
void slammast_decode();
// cps2_crypt.cpp
void cps2_decrypt_game_data();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,490 @@
#include "cps.h"
// CPS - Draw
UINT8 CpsRecalcPal = 0; // Flag - If it is 1, recalc the whole palette
static INT32 LayerCont;
INT32 nStartline, nEndline;
INT32 nRasterline[MAX_RASTER + 2];
INT32 nCpsLcReg = 0; // Address of layer controller register
INT32 CpsLayEn[6] = {0, 0, 0, 0, 0, 0}; // bits for layer enable
INT32 MaskAddr[4] = {0, 0, 0, 0};
INT32 CpsLayer1XOffs = 0;
INT32 CpsLayer2XOffs = 0;
INT32 CpsLayer3XOffs = 0;
INT32 CpsLayer1YOffs = 0;
INT32 CpsLayer2YOffs = 0;
INT32 CpsLayer3YOffs = 0;
static void Cps1Layers();
static void Cps2Layers();
typedef INT32 (*CpsObjDrawDoFn)(INT32,INT32);
typedef INT32 (*CpsScrXDrawDoFn)(UINT8 *,INT32,INT32);
typedef void (*CpsLayersDoFn)();
typedef INT32 (*CpsrPrepareDoFn)();
typedef INT32 (*CpsrRenderDoFn)();
CpsObjDrawDoFn CpsObjDrawDoX;
CpsScrXDrawDoFn CpsScr1DrawDoX;
CpsScrXDrawDoFn CpsScr3DrawDoX;
CpsLayersDoFn CpsLayersDoX;
CpsrPrepareDoFn CpsrPrepareDoX;
CpsrRenderDoFn CpsrRenderDoX;
void DrawFnInit()
{
if(Cps == 2) {
CpsLayersDoX = Cps2Layers;
CpsScr1DrawDoX = Cps2Scr1Draw;
CpsScr3DrawDoX = Cps2Scr3Draw;
CpsObjDrawDoX = Cps2ObjDraw;
CpsrPrepareDoX = Cps2rPrepare;
CpsrRenderDoX = Cps2rRender;
} else {
CpsLayersDoX = Cps1Layers;
CpsScr1DrawDoX = Cps1Scr1Draw;
CpsScr3DrawDoX = Cps1Scr3Draw;
CpsObjDrawDoX = Cps1ObjDraw;
CpsrPrepareDoX = Cps1rPrepare;
CpsrRenderDoX = Cps1rRender;
}
}
static INT32 DrawScroll1(INT32 i)
{
// Draw Scroll 1
INT32 nOff, nScrX, nScrY;
UINT8 *Find;
nOff = *((UINT16 *)(CpsSaveReg[i] + 0x02));
// Get scroll coordinates
nScrX = *((UINT16 *)(CpsSaveReg[i] + 0x0c)); // Scroll 1 X
nScrY = *((UINT16 *)(CpsSaveReg[i] + 0x0e)); // Scroll 1 Y
nScrX += 0x40;
// bprintf(PRINT_NORMAL, _T("1 %x, %x, %x\n"), nOff, nScrX, nScrY);
nScrX += CpsLayer1XOffs;
nScrY += 0x10;
nScrY += CpsLayer1YOffs;
nOff <<= 8;
nOff &= 0xffc000;
Find = CpsFindGfxRam(nOff, 0x4000);
if (Find == NULL) {
return 1;
}
CpsScr1DrawDoX(Find, nScrX, nScrY);
return 0;
}
static INT32 DrawScroll2Init(INT32 i)
{
// Draw Scroll 2
INT32 nScr2Off; INT32 n;
nScr2Off = *((UINT16 *)(CpsSaveReg[i] + 0x04));
// Get scroll coordinates
nCpsrScrX= *((UINT16 *)(CpsSaveReg[i] + 0x10)); // Scroll 2 X
nCpsrScrY= *((UINT16 *)(CpsSaveReg[i] + 0x12)); // Scroll 2 Ytess
// Get row scroll information
n = *((UINT16 *)(CpsSaveReg[i] + 0x22));
nScr2Off <<= 8;
nCpsrScrX += 0x40;
// bprintf(PRINT_NORMAL, _T("2 %x, %x, %x\n"), nScr2Off, nCpsrScrX, nCpsrScrY);
nCpsrScrX += CpsLayer2XOffs;
nCpsrScrX &= 0x03FF;
nCpsrScrY += 0x10;
nCpsrScrY += CpsLayer2YOffs;
nCpsrScrY &= 0x03FF;
nScr2Off &= 0xFFC000;
CpsrBase = CpsFindGfxRam(nScr2Off, 0x4000);
if (CpsrBase == NULL) {
return 1;
}
CpsrRows = NULL;
if (n & 1) {
INT32 nTab, nStart;
// Find row scroll table:
nTab = *((UINT16 *)(CpsSaveReg[i] + 0x08));
nStart = *((UINT16 *)(CpsSaveReg[i] + 0x20));
nTab <<= 8;
nTab &= 0xFFF800; // Vampire - Row scroll effect in VS screen background
CpsrRows = (UINT16 *)CpsFindGfxRam(nTab, 0x0800);
// Find start offset
nCpsrRowStart = nStart + 16;
}
CpsrPrepareDoX();
return 0;
}
inline static INT32 DrawScroll2Exit()
{
CpsrBase = NULL;
nCpsrScrX = 0;
nCpsrScrY = 0;
CpsrRows = NULL;
return 0;
}
inline static INT32 DrawScroll2Do()
{
if (CpsrBase == NULL) {
return 1;
}
CpsrRenderDoX();
return 0;
}
static INT32 DrawScroll3(INT32 i)
{
// Draw Scroll 3
INT32 nOff, nScrX, nScrY;
UINT8 *Find;
nOff = *((UINT16 *)(CpsSaveReg[i] + 0x06));
// Get scroll coordinates
nScrX = *((UINT16 *)(CpsSaveReg[i] + 0x14)); // Scroll 3 X
nScrY = *((UINT16 *)(CpsSaveReg[i] + 0x16)); // Scroll 3 Y
nScrX += 0x40;
// bprintf(PRINT_NORMAL, _T("3 %x, %x, %x\n"), nOff, nScrX, nScrY);
nScrX += CpsLayer3XOffs;
nScrY += 0x10;
nScrY += CpsLayer3YOffs;
nOff <<= 8;
nOff &= 0xffc000;
Find=CpsFindGfxRam(nOff, 0x4000);
if (Find == NULL) {
return 1;
}
CpsScr3DrawDoX(Find, nScrX, nScrY);
return 0;
}
static INT32 DrawStar(INT32 nLayer)
{
INT32 nStar, nStarXPos, nStarYPos, nStarColour;
UINT8* pStar = CpsStar + (nLayer << 12);
for (nStar = 0; nStar < 0x1000; nStar++) {
nStarColour = pStar[nStar];
if (nStarColour != 0x0F) {
nStarXPos = (((nStar >> 8) << 5) - *((INT16*)(CpsSaveReg[0] + 0x18 + (nLayer << 2))) + (nStarColour & 0x1F) - 64) & 0x01FF;
nStarYPos = ((nStar & 0xFF) - *((INT16*)(CpsSaveReg[0] + 0x1A + (nLayer << 2))) - 16) & 0xFF;
if (nStarXPos < 384 && nStarYPos < 224) {
nStarColour = ((nStarColour & 0xE0) >> 1) + ((GetCurrentFrame() >> 4) & 0x0F);
PutPix(pBurnDraw + (nBurnPitch * nStarYPos) + (nBurnBpp * nStarXPos), CpsPal[0x0800 + (nLayer << 9) + nStarColour]);
}
}
}
return 0;
}
static void Cps1Layers()
{
INT32 Draw[4]={-1,-1,-1,-1};
INT32 nDrawMask=0;
INT32 i=0;
nDrawMask=1; // Sprites always on
LayerCont = *((UINT16 *)(CpsSaveReg[0] + nCpsLcReg));
// Get correct bits from Layer Controller
if (LayerCont & CpsLayEn[1]) nDrawMask|=2;
if (LayerCont & CpsLayEn[2]) nDrawMask|=4;
if (LayerCont & CpsLayEn[3]) nDrawMask|=8;
nDrawMask&=nBurnLayer; // User choice of layers to display
// Layer control:
Draw[0]=(LayerCont>>12)&3; // top layer
Draw[1]=(LayerCont>>10)&3;
Draw[2]=(LayerCont>> 8)&3;
Draw[3]=(LayerCont>> 6)&3; // bottom layer (most covered up)
// Check for repeated layers and if there are any, the lower layer is omitted
#define CRP(a,b) if (Draw[a]==Draw[b]) Draw[b]=-1;
CRP(0,1) CRP(0,2) CRP(0,3) CRP(1,2) CRP(1,3) CRP(2,3)
#undef CRP
for (i = 0; i < 2; i++) {
if (LayerCont & CpsLayEn[4 + i]) {
CpsStarPalUpdate(CpsSavePal, i, CpsRecalcPal);
DrawStar(i);
}
}
// prepare layer 2
DrawScroll2Init(0);
// draw layers, bottom -> top
for (i=3;i>=0;i--)
{
INT32 n=Draw[i]; // Find out which layer to draw
if (n==0) {
if (nDrawMask & 1) CpsObjDrawDoX(0,7);
if (!Mercs && !Sf2jc && !Qad) {
nBgHi=1;
switch (Draw[i+1]) {
case 1:
if (nDrawMask & 2) DrawScroll1(0);
break;
case 2:
if (nDrawMask & 4) DrawScroll2Do();
break;
case 3:
if (nDrawMask & 8) DrawScroll3(0);
break;
}
nBgHi=0;
}
}
// Then Draw the scroll layer on top
switch (n) {
case 1:
if (nDrawMask & 2) DrawScroll1(0);
break;
case 2:
if (nDrawMask & 4) DrawScroll2Do();
break;
case 3:
if (nDrawMask & 8) DrawScroll3(0);
break;
}
}
DrawScroll2Exit();
}
static void Cps2Layers()
{
INT32 Draw[MAX_RASTER][4];
INT32 Prio[MAX_RASTER][4];
INT32 nDrawMask[MAX_RASTER];
CpsObjDrawInit();
INT32 nSlice = 0;
do {
LayerCont = *((UINT16 *)(CpsSaveReg[nSlice] + nCpsLcReg));
// Determine which layers are enabled
nDrawMask[nSlice] = 1; // Sprites always on
if (LayerCont & CpsLayEn[1]) nDrawMask[nSlice] |= 2;
if (LayerCont & CpsLayEn[2]) nDrawMask[nSlice] |= 4;
if (LayerCont & CpsLayEn[3]) nDrawMask[nSlice] |= 8;
nDrawMask[nSlice] &= nBurnLayer; // User choice of layers to display
// Determine layerö priority:
Draw[nSlice][3] = (LayerCont >> 12) & 3; // top layer
Draw[nSlice][2] = (LayerCont >> 10) & 3;
Draw[nSlice][1] = (LayerCont >> 8) & 3;
Draw[nSlice][0] = (LayerCont >> 6) & 3; // bottom layer (most covered up)
// Determine layer-sprite priority (layer >= sprites -> layer on top)
INT32 nLayPri = (CpsSaveFrg[nSlice][4] << 8) | CpsSaveFrg[nSlice][5]; // Layer priority register at word (400004)
Prio[nSlice][3] = (nLayPri >> 12) & 7;
Prio[nSlice][2] = (nLayPri >> 8) & 7;
Prio[nSlice][1] = (nLayPri >> 4) & 7;
Prio[nSlice][0] = 0;
// Check for repeated layers (if found, discard the lower layer)
#define CRP(a, b) if (Draw[nSlice][a] == Draw[nSlice][b]) Draw[nSlice][b] = -1;
CRP(3, 2) CRP(3, 1) CRP(2, 1) CRP(3, 0) CRP(2, 0) CRP(1, 0)
#undef CRP
// Pre-process priorities
// Higher priority layers must have higher layer-sprite priorities
// N.B. If this is not the case, masking effects may occur (not emulated)
#if 0
// Raise sprite priorities of top layers if needed
INT32 nHighPrio = 0;
for (INT32 i = 0; i < 4; i++) {
if (Draw[nSlice][i] > 0) {
if (Prio[nSlice][Draw[nSlice][i]] < nHighPrio) {
Prio[nSlice][Draw[nSlice][i]] = nHighPrio;
} else {
nHighPrio = Prio[nSlice][Draw[nSlice][i]];
}
}
}
#else
// Lower sprite priorities of bottom layers if needed
INT32 nHighPrio = 9999;
for (INT32 i = 3; i >= 0; i--) {
if (Draw[nSlice][i] > 0) {
if (Prio[nSlice][Draw[nSlice][i]] > nHighPrio) {
Prio[nSlice][Draw[nSlice][i]] = nHighPrio;
} else {
nHighPrio = Prio[nSlice][Draw[nSlice][i]];
}
}
}
#endif
nSlice++;
} while (nSlice < MAX_RASTER && nRasterline[nSlice]);
INT32 nPrevPrio = -1;
for (INT32 nCurrPrio = 0; nCurrPrio < 8; nCurrPrio++) {
nSlice = 0;
do {
for (INT32 i = 0; i < 4; i++) {
if (Prio[nSlice][Draw[nSlice][i]] == nCurrPrio) {
// Render sprites between the previous layer and this one
if ((nDrawMask[0] & 1) && (nPrevPrio < nCurrPrio)) {
CpsObjDrawDoX(nPrevPrio + 1, nCurrPrio);
nPrevPrio = nCurrPrio;
}
nStartline = nRasterline[nSlice];
nEndline = nRasterline[nSlice + 1];
if (!nEndline) {
nEndline = 224;
}
// Render layer
switch (Draw[nSlice][i]) {
case 1:
if (nDrawMask[nSlice] & 2) {
DrawScroll1(nSlice);
}
break;
case 2:
if (nDrawMask[nSlice] & 4) {
DrawScroll2Init(nSlice);
DrawScroll2Do();
DrawScroll2Exit();
}
break;
case 3:
if (nDrawMask[nSlice] & 8) {
DrawScroll3(nSlice);
}
break;
}
}
}
nSlice++;
} while (nSlice < MAX_RASTER && nRasterline[nSlice]);
}
// Render highest priority sprites
if ((nDrawMask[0] & 1) && (nPrevPrio < 7)) {
CpsObjDrawDoX(nPrevPrio + 1, 7);
}
}
void CpsClearScreen()
{
if (Cps == 1) {
switch (nBurnBpp) {
case 4: {
UINT32* pClear = (UINT32*)pBurnDraw;
UINT32 nColour = CpsPal[0xbff ^ 15];
for (INT32 i = 0; i < 384 * 224 / 8; i++) {
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
}
break;
}
case 3: {
UINT8* pClear = pBurnDraw;
UINT8 r = CpsPal[0xbff ^ 15];
UINT8 g = (r >> 8) & 0xFF;
UINT8 b = (r >> 16) & 0xFF;
r &= 0xFF;
for (INT32 i = 0; i < 384 * 224; i++) {
*pClear++ = r;
*pClear++ = g;
*pClear++ = b;
}
break;
}
case 2: {
UINT32* pClear = (UINT32*)pBurnDraw;
UINT32 nColour = CpsPal[0xbff ^ 15] | CpsPal[0xbff ^ 15] << 16;
for (INT32 i = 0; i < 384 * 224 / 16; i++) {
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
}
break;
}
}
} else {
memset(pBurnDraw, 0, 384 * 224 * nBurnBpp);
}
}
static void DoDraw(INT32 Recalc)
{
CtvReady(); // Point to correct tile drawing functions
// Update Palette
CpsPalUpdate(CpsSavePal, Recalc); // recalc whole palette if needed
CpsClearScreen();
CpsLayersDoX();
}
INT32 CpsDraw()
{
DoDraw(CpsRecalcPal);
CpsRecalcPal = 0;
return 0;
}
INT32 CpsRedraw()
{
DoDraw(1);
CpsRecalcPal = 0;
return 0;
}

View File

@ -0,0 +1,427 @@
#include "cps.h"
// CPS - Memory
UINT32 CpsMProt[4];
UINT32 CpsBID[3];
static UINT8 *CpsMem=NULL,*CpsMemEnd=NULL;
UINT8 *CpsRam90=NULL;
UINT8 *CpsZRamC0=NULL,*CpsZRamF0=NULL,*CpsEncZRom=NULL;
UINT8 *CpsSavePal=NULL;
UINT8 *CpsSaveReg[MAX_RASTER + 1];
UINT8 *CpsSaveFrg[MAX_RASTER + 1];
static UINT8 *CpsSaveRegData = NULL;
static UINT8 *CpsSaveFrgData = NULL;
UINT8 *CpsRam660=NULL,*CpsRam708=NULL,*CpsReg=NULL,*CpsFrg=NULL;
UINT8 *CpsRamFF=NULL;
// This routine is called first to determine how much memory is needed
// and then to set up all the pointers.
static INT32 CpsMemIndex()
{
UINT8* Next; Next = CpsMem;
CpsRam90 = Next; Next += 0x030000; // Video Ram
CpsRamFF = Next; Next += 0x010000; // Work Ram
CpsReg = Next; Next += 0x000100; // Registers
CpsSavePal = Next; Next += 0x002000; // Draw Copy of Correct Palette
if (Cps == 2 || Cps1Qs == 1) {
CpsZRamC0 = Next; Next += 0x001000; // Z80 c000-cfff
CpsZRamF0 = Next; Next += 0x001000; // Z80 f000-ffff
}
if (Cps == 2) {
CpsRam660 = Next; Next += 0x004000; // Extra Memory
CpsRam708 = Next; Next += 0x010000; // Obj Ram
CpsFrg = Next; Next += 0x000010; // 'Four' Registers (Registers at 0x400000)
ZBuf = (UINT16*)Next; Next += 384 * 224 * 2; // Sprite Masking Z buffer
CpsSaveRegData = Next; Next += 0x0100 * (MAX_RASTER + 1); // Draw Copy of registers
CpsSaveFrgData = Next; Next += 0x0010 * (MAX_RASTER + 1); // Draw Copy of 'Four' Registers
for (INT32 i = 0; i < MAX_RASTER + 1; i++) {
CpsSaveReg[i] = CpsSaveRegData + i * 0x0100;
CpsSaveFrg[i] = CpsSaveFrgData + i * 0x0010;
}
} else {
CpsSaveRegData = Next; Next += 0x0100; // Draw Copy of registers
CpsSaveFrgData = Next; Next += 0x0010; // Draw Copy of 'Four' Registers
CpsSaveReg[0] = CpsSaveRegData;
CpsSaveFrg[0] = CpsSaveFrgData;
}
CpsMemEnd = Next;
return 0;
}
static INT32 AllocateMemory()
{
INT32 nLen;
CpsMem = NULL; // Find out how much memory is needed
CpsMemIndex();
nLen = CpsMemEnd - (UINT8*)0;
if ((CpsMem = (UINT8*)malloc(nLen)) == NULL) {
return 1;
}
memset(CpsMem, 0, nLen); // blank all memory
CpsMemIndex(); // Index the allocated memory
return 0;
}
// Map the correct bank of obj memory to the 68000 address space (including mirrors).
void CpsMapObjectBanks(INT32 nBank)
{
if (nBank != nCpsObjectBank) {
nCpsObjectBank = nBank;
if (nCpsObjectBank) {
SekMapMemory(CpsRam708 + 0x8000, 0x708000, 0x709FFF, SM_RAM);
SekMapMemory(CpsRam708 + 0x8000, 0x70A000, 0x70BFFF, SM_RAM);
SekMapMemory(CpsRam708 + 0x8000, 0x70C000, 0x70DFFF, SM_RAM);
SekMapMemory(CpsRam708 + 0x8000, 0x70E000, 0x70FFFF, SM_RAM);
} else {
SekMapMemory(CpsRam708, 0x708000, 0x709FFF, SM_RAM);
SekMapMemory(CpsRam708, 0x70A000, 0x70BFFF, SM_RAM);
SekMapMemory(CpsRam708, 0x70C000, 0x70DFFF, SM_RAM);
SekMapMemory(CpsRam708, 0x70E000, 0x70FFFF, SM_RAM);
}
}
}
INT32 __fastcall CPSResetCallback()
{
// Reset instruction on 68000
if (!Cps1Pic) ZetReset(); // Reset Z80 (CPU #1)
return 0;
}
// ----------------------------------------------------------------------------
UINT8 __fastcall CPSQSoundC0ReadByte(UINT32 sekAddress)
{
// bprintf(PRINT_NORMAL, _T(" QS %06X read\n"), sekAddress);
if (!(sekAddress & 1)) {
return 0xFF;
}
QsndSyncZ80();
sekAddress &= 0x1FFF;
return CpsZRamC0[sekAddress >> 1];
}
void __fastcall CPSQSoundC0WriteByte(UINT32 sekAddress, UINT8 byteValue)
{
// bprintf(PRINT_NORMAL, _T(" QS %06X -> %02X\n"), sekAddress, byteValue);
if (!(sekAddress & 1)) {
return;
}
sekAddress &= 0x1FFF;
#if 1 && defined USE_SPEEDHACKS
// Sync only when the last byte of the sound command is written
if (sekAddress == 0x001F) {
QsndSyncZ80();
}
#else
QsndSyncZ80();
#endif
CpsZRamC0[sekAddress >> 1] = byteValue;
}
UINT8 __fastcall CPSQSoundF0ReadByte(UINT32 sekAddress)
{
// bprintf(PRINT_NORMAL, _T(" QS %06X read\n"), sekAddress);
if (!(sekAddress & 1)) {
return 0xFF;
}
QsndSyncZ80();
sekAddress &= 0x1FFF;
return CpsZRamF0[sekAddress >> 1];
}
void __fastcall CPSQSoundF0WriteByte(UINT32 sekAddress, UINT8 byteValue)
{
// bprintf(PRINT_NORMAL, _T(" QS %06X -> %02X\n"), sekAddress, byteValue);
if (!(sekAddress & 1)) {
return;
}
sekAddress &= 0x1FFF;
#if 1 && defined USE_SPEEDHACKS
// Sync only when the last byte of the sound command is written
if (sekAddress == 0x001F) {
QsndSyncZ80();
}
#else
QsndSyncZ80();
#endif
CpsZRamF0[sekAddress >> 1] = byteValue;
}
// ----------------------------------------------------------------------------
#if 0
UINT8 __fastcall CPSExtraNVRAMReadByte(UINT32 sekAddress)
{
// bprintf(PRINT_NORMAL, _T(" - 0x%06X read.\n"), sekAddress);
sekAddress &= 0x3FFF;
return CpsRam660[sekAddress];
}
void __fastcall CPSExtraNVRAMWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
// bprintf(PRINT_NORMAL, _T(" - 0x%06X -> %02X\n"), sekAddress, byteValue);
sekAddress &= 0x3FFF;
CpsRam660[sekAddress] = byteValue;
}
#endif
// ----------------------------------------------------------------------------
/*
INT32 prevline;
void __fastcall CpsWriteSpriteByte(UINT32 sekAddress, UINT8 byteValue)
{
if (prevline != SekCurrentScanline()) {
prevline = SekCurrentScanline();
// bprintf(PRINT_NORMAL, _T(" - sb (%3i)\n"), prevline);
}
sekAddress &= 0x1FFF;
CpsRam708[sekAddress + nCpsObjectBank * 0x8000] = byteValue;
}
void __fastcall CpsWriteSpriteWord(UINT32 sekAddress, UINT16 wordValue)
{
if (prevline != SekCurrentScanline()) {
prevline = SekCurrentScanline();
// bprintf(PRINT_NORMAL, _T(" - sw (%3i)\n"), prevline);
}
sekAddress &= 0x1FFE;
CpsRam708[sekAddress + nCpsObjectBank * 0x8000 + 1] = wordValue >> 8;
CpsRam708[sekAddress + nCpsObjectBank * 0x8000 + 0] = wordValue & 255;
}
*/
// ----------------------------------------------------------------------------
UINT8 __fastcall haxx0rReadByte(UINT32 sekAddress)
{
sekAddress &= 0xFFFF;
bprintf(PRINT_NORMAL, _T(" QS %06X read (%02X)\n"), sekAddress, CpsEncZRom[sekAddress]);
return CpsEncZRom[sekAddress];
}
INT32 CpsMemInit()
{
if (AllocateMemory()) {
return 1;
}
SekOpen(0);
SekSetResetCallback(CPSResetCallback);
// Map in memory:
// 68000 Rom (as seen as is, through read)
SekMapMemory(CpsRom, 0, nCpsRomLen - 1, SM_READ);
// 68000 Rom (as seen decrypted, through fetch)
if (nCpsCodeLen > 0) {
// Decoded part (up to nCpsCodeLen)
SekMapMemory(CpsCode, 0, nCpsCodeLen - 1, SM_FETCH);
}
if (nCpsRomLen > nCpsCodeLen) {
// The rest (up to nCpsRomLen)
SekMapMemory(CpsRom + nCpsCodeLen, nCpsCodeLen, nCpsRomLen - 1, SM_FETCH);
}
if (Cps == 2) {
nCpsObjectBank = -1;
CpsMapObjectBanks(0);
#if 0
SekMapHandler(3, 0x660000, 0x663FFF, SM_RAM);
SekSetReadByteHandler(3, CPSExtraNVRAMReadByte);
SekSetWriteByteHandler(3, CPSExtraNVRAMWriteByte);
#else
SekMapMemory(CpsRam660, 0x660000, 0x663FFF, SM_RAM);
#endif
// SekMapHandler(4, 0x708000, 0x709FFF, SM_WRITE);
// SekMapHandler(4, 0x70A000, 0x70BFFF, SM_WRITE);
// SekMapHandler(4, 0x70C000, 0x70DFFF, SM_WRITE);
// SekMapHandler(4, 0x70E000, 0x70FFFF, SM_WRITE);
// SekSetWriteByteHandler(4, CpsWriteSpriteByte);
// SekSetWriteWordHandler(4, CpsWriteSpriteWord);
}
SekMapMemory(CpsRam90, 0x900000, 0x92FFFF, SM_RAM); // Gfx Ram
SekMapMemory(CpsRamFF, 0xFF0000, 0xFFFFFF, SM_RAM); // Work Ram
SekSetReadByteHandler(0, CpsReadByte);
SekSetWriteByteHandler(0, CpsWriteByte);
SekSetReadWordHandler(0, CpsReadWord);
SekSetWriteWordHandler(0, CpsWriteWord);
// QSound
if (Cps == 2) {
SekMapHandler(1, 0x618000, 0x619FFF, SM_RAM);
SekSetReadByteHandler(1, CPSQSoundC0ReadByte);
SekSetWriteByteHandler(1, CPSQSoundC0WriteByte);
}
if (Cps1Qs == 1) {
// Map the 1st 32KB of the QSound ROM into the 68K address space
for (INT32 i = 0x7FFF; i >= 0; i--) {
CpsEncZRom[(i << 1) + 0] = CpsEncZRom[i];
CpsEncZRom[(i << 1) + 1] = 0xFF;
}
SekMapMemory(CpsEncZRom, 0xF00000, 0xF0FFFF, SM_ROM);
// QSound shared RAM
SekMapHandler(1, 0xF18000, 0xF19FFF, SM_RAM);
SekMapHandler(2, 0xF1E000, 0xF1FFFF, SM_RAM);
SekSetReadByteHandler(1, CPSQSoundC0ReadByte);
SekSetWriteByteHandler(1, CPSQSoundC0WriteByte);
SekSetReadByteHandler(2, CPSQSoundF0ReadByte);
SekSetWriteByteHandler(2, CPSQSoundF0WriteByte);
}
SekClose();
return 0;
}
INT32 CpsMemExit()
{
#if 0
FILE* fp = fopen("mem.raw", "wb");
if (fp) {
fwrite(CpsRam660, 1, 0x4000, fp);
fclose(fp);
}
#endif
// Deallocate all used memory
if (CpsMem) {
free(CpsMem);
CpsMem = NULL;
}
return 0;
}
static INT32 ScanRam()
{
// scan ram:
struct BurnArea ba;
memset(&ba, 0, sizeof(ba));
ba.Data = CpsRam90; ba.nLen = 0x030000; ba.szName = "CpsRam90"; BurnAcb(&ba);
ba.Data = CpsRamFF; ba.nLen = 0x010000; ba.szName = "CpsRamFF"; BurnAcb(&ba);
ba.Data = CpsReg; ba.nLen = 0x000100; ba.szName = "CpsReg"; BurnAcb(&ba);
if (Cps == 2 || Cps1Qs == 1) {
ba.Data = CpsZRamC0; ba.nLen = 0x001000; ba.szName = "CpsZRamC0"; BurnAcb(&ba);
ba.Data = CpsZRamF0; ba.nLen = 0x001000; ba.szName = "CpsZRamF0"; BurnAcb(&ba);
}
if (Cps == 2) {
ba.Data = CpsRam708; ba.nLen = 0x010000; ba.szName = "CpsRam708"; BurnAcb(&ba);
ba.Data = CpsFrg; ba.nLen = 0x000010; ba.szName = "CpsFrg"; BurnAcb(&ba);
}
return 0;
}
// Scan the current state of the CPS1/2 machine
INT32 CpsAreaScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (CpsMem == NULL) {
return 1;
}
if (pnMin) { // Return minimum compatible version
*pnMin = 0x029521;
}
if (nAction & ACB_MEMORY_ROM) {
memset(&ba, 0, sizeof(ba));
ba.Data = CpsRom;
ba.nLen = nCpsRomLen;
ba.szName = "CpsRom";
BurnAcb(&ba);
ba.Data = CpsZRom;
ba.nLen = nCpsZRomLen;
ba.szName = "CpsZRom";
BurnAcb(&ba);
}
if (Cps == 2 || Cps1Qs == 1 || PangEEP == 1) { // Scan EEPROM
EEPROMScan(nAction, pnMin);
}
if (nAction & ACB_MEMORY_RAM) {
ScanRam();
if (Cps == 2) {
memset(&ba, 0, sizeof(ba));
ba.Data = CpsRam660;
ba.nLen = 0x004000;
ba.szName = "CpsRam660";
BurnAcb(&ba);
}
}
if (nAction & ACB_DRIVER_DATA) { // Scan volatile variables/registers/RAM
SekScan(nAction); // Scan 68000 state
if (nAction & ACB_WRITE) { // Palette could have changed
CpsRecalcPal = 1;
}
}
if (Cps == 2 || Cps1Qs == 1) { // Scan QSound chips
QsndScan(nAction);
} else { // Scan PSound chips
PsndScan(nAction);
}
return 0;
}

View File

@ -0,0 +1,401 @@
#include "cps.h"
// CPS Objs (sprites)
INT32 nCpsObjectBank;
UINT8 *BootlegSpriteRam = NULL;
INT32 Sf2Hack = 0;
// Our copy of the sprite table
static UINT8 *ObjMem = NULL;
static INT32 nMax = 0;
static INT32 nGetNext = 0;
static INT32 nMaxZValue;
static INT32 nMaxZMask;
static INT32 nZOffset;
// Object frames, so you can lag the Objs by nFrameCount-1 frames
struct ObjFrame {
INT32 nShiftX, nShiftY;
UINT8* Obj;
INT32 nCount;
};
static INT32 nFrameCount = 0;
static struct ObjFrame of[3];
INT32 CpsObjInit()
{
nMax = 0x100; // CPS1 has 256 sprites
if (Cps == 2) { // CPS2 has 1024 sprites
nMax = 0x400;
}
nFrameCount = 2; // CPS2 sprites lagged by 1 frame and double buffered
// CPS1 sprites lagged by 1 frame
ObjMem = (UINT8*)malloc((nMax << 3) * nFrameCount);
if (ObjMem == NULL) {
return 1;
}
// Set up the frame buffers
for (INT32 i = 0; i < nFrameCount; i++) {
of[i].Obj = ObjMem + (nMax << 3) * i;
of[i].nCount = 0;
}
nGetNext=0;
if (Cps == 2) {
memset(ZBuf, 0, 384 * 224 * 2);
nMaxZMask = nZOffset = 0;
nMaxZValue = 1;
}
return 0;
}
INT32 CpsObjExit()
{
for (INT32 i = 0; i < nFrameCount; i++) {
of[i].Obj = NULL;
of[i].nCount = 0;
}
if (ObjMem) {
free(ObjMem);
ObjMem = NULL;
}
nFrameCount = 0;
nMax = 0;
return 0;
}
// Get CPS sprites into Obj
INT32 CpsObjGet()
{
INT32 i;
UINT8 *pg, *po;
struct ObjFrame* pof;
UINT8* Get = NULL;
pof = of + nGetNext;
pof->nCount = 0;
po = pof->Obj;
pof->nShiftX = -0x40;
pof->nShiftY = -0x10;
if (Cps == 2) {
Get = CpsRam708 + ((nCpsObjectBank ^ 1) << 15); // Select CPS2 sprite buffer
// Get = CpsRam708 + ((GetCurrentFrame() & 1) << 15); // Select CPS2 sprite buffer
pof->nShiftX = -CpsSaveFrg[0][0x9];
pof->nShiftY = -CpsSaveFrg[0][0xB];
} else {
INT32 nOff = *((UINT16*)(CpsReg + 0x00)) << 8;
nOff &= 0xfff800;
Get = CpsFindGfxRam(nOff, 0x800);
if (Sf2Hack) {
Get = CpsFindGfxRam(0x910000, 0x800);
} else {
if (Dinopic) {
Get = BootlegSpriteRam + 0x1000;
}
}
}
if (Get==NULL) return 1;
// Make a copy of all active sprites in the list
for (pg = Get, i = 0; i < nMax; pg += 8, i++) {
UINT16* ps = (UINT16*)pg;
if (Cps == 2) {
if (ps[1] & 0x8000) { // end of sprite list?
break;
}
if (ps[0] == 0 && ps[1] == 0x0100 && ps[2] == 0 && ps[3] == 0xff00) { // Slammasters end of sprite list?
break;
}
} else {
if (Dinopic) {
if (ps[1] == 0x8000) { // end of sprite list
break;
}
} else {
if (ps[3] == 0xff00) { // end of sprite list
break;
}
}
}
if (Dinopic) {
if (((ps[2] - 461) | ps[1]) == 0) { // sprite blank
continue;
}
} else {
if ((ps[0] | ps[3]) == 0) { // sprite blank
continue;
}
}
// Okay - this sprite is active:
memcpy(po, pg, 8); // copy it over
pof->nCount++;
po += 8;
}
nGetNext++;
if (nGetNext >= nFrameCount) {
nGetNext = 0;
}
return 0;
}
void CpsObjDrawInit()
{
nZOffset = nMaxZMask;
if (nZOffset >= 0xFC00) {
// The Z buffer might moverflow the next fram, so initialise it
memset(ZBuf, 0, 384 * 224 * 2);
nZOffset = 0;
}
nMaxZValue = nZOffset + 1;
nMaxZMask = nZOffset;
return;
}
INT32 Cps1ObjDraw(INT32 nLevelFrom,INT32 nLevelTo)
{
INT32 i; UINT16 *ps; INT32 nPsAdd;
struct ObjFrame *pof;
(void)nLevelFrom; (void)nLevelTo;
// Draw the earliest frame we have in history
pof=of+nGetNext;
// Point to Obj list
ps=(UINT16 *)pof->Obj;
if (!CpsDrawSpritesInReverse) {
ps+=(pof->nCount-1)<<2; nPsAdd=-4; // CPS1 is reversed
} else {
nPsAdd=4;
}
// Go through all the Objs
for (i=0; i<pof->nCount; i++,ps+=nPsAdd) {
INT32 x,y,n,a,bx,by,dx,dy; INT32 nFlip;
if (Dinopic) {
n = ps[0]; a = ps[1]; x = ps[2] - 461; y = 0x2f0 - ps[3];
bx = 1;
by = 1;
} else {
x = ps[0]; y = ps[1]; n = ps[2]; a = ps[3];
// Find out sprite size
bx=((a>> 8)&15)+1;
by=((a>>12)&15)+1;
}
n = GfxRomBankMapper(GFXTYPE_SPRITES, n);
if (n == -1) continue;
n |= (y & 0x6000) << 3; // high bits of address
// CPS1 coords are 9 bit signed?
x&=0x01ff; if (x>=0x1c0) x-=0x200;
y&=0x01ff; y^=0x100; y-=0x100;
x+=pof->nShiftX;
y+=pof->nShiftY;
// Find the palette for the tiles on this sprite
CpstPal = CpsObjPal + ((a & 0x1F) << 4);
nFlip=(a>>5)&3;
// Take care with tiles if the sprite goes off the screen
if (x<0 || y<0 || x+(bx<<4)>384 || y+(by<<4)>224) {
nCpstType=CTT_16X16 | CTT_CARE;
} else {
nCpstType=CTT_16X16;
}
nCpstFlip=nFlip;
for (dy=0;dy<by;dy++) {
for (dx=0;dx<bx;dx++) {
INT32 ex,ey;
if (nFlip&1) ex=(bx-dx-1);
else ex=dx;
if (nFlip&2) ey=(by-dy-1);
else ey=dy;
nCpstX=x+(ex<<4);
nCpstY=y+(ey<<4);
nCpstTile = (n & ~0x0F) + (dy << 4) + ((n + dx) & 0x0F);
nCpstTile <<= 7;
CpstOneObjDoX[0]();
}
}
}
return 0;
}
// Delay sprite drawing by one frame
INT32 Cps2ObjDraw(INT32 nLevelFrom, INT32 nLevelTo)
{
const INT32 nPsAdd = 4;
UINT16 *ps;
struct ObjFrame *pof;
CpstOneDoFn pCpstOne;
INT32 nCount;
bool bMask = 0;
// Draw the earliest frame we have in history
pof = of + nGetNext;
// Point to Obj list
ps = (UINT16*)pof->Obj + nPsAdd * (nMaxZValue - nZOffset - 1);
nCount = nZOffset + pof->nCount;
// Go through all the Objs
for (ZValue = (UINT16)nMaxZValue; ZValue <= nCount; ZValue++, ps += nPsAdd) {
INT32 x, y, n, a, bx, by, dx, dy;
INT32 nFlip;
INT32 v = ps[0] >> 13;
if ((nSpriteEnable & (1 << v)) == 0) {
continue;
}
// Check if sprite is between these levels
if (v > nLevelTo) {
bMask = 1;
continue;
}
if (v < nLevelFrom) {
continue;
}
if (bMask) {
nMaxZMask = ZValue;
} else {
nMaxZValue = ZValue;
}
// Select CpstOne function;
if (bMask || nMaxZMask > nMaxZValue) {
pCpstOne = CpstOneObjDoX[1];
} else {
pCpstOne = CpstOneObjDoX[0];
}
x = ps[0];
y = ps[1];
n = ps[2];
a = ps[3];
if (a & 0x80) { // marvel vs capcom ending sprite off-set
x += CpsSaveFrg[0][0x9];
}
// CPS2 coords are 10 bit signed (-512 to 511)
x &= 0x03FF; x ^= 0x200; x -= 0x200;
y &= 0x03FF; y ^= 0x200; y -= 0x200;
#if 0
// This *MAY* be needed to get correct sprite positions when raster interrups are used.
if (nRasterline[1]) {
for (INT32 i = 1; i < MAX_RASTER; i++) {
if ((y < nRasterline[i]) || (nRasterline[i] == 0)) {
x -= CpsSaveFrg[i - 1][0x09];
y -= CpsSaveFrg[i - 1][0x0B];
break;
}
}
} else {
x -= CpsSaveFrg[0][0x9];
y -= CpsSaveFrg[0][0xB];
}
#else
// Ignore sprite offsets when raster interrupts are used (seems to work for all games).
x += pof->nShiftX;
y += pof->nShiftY;
// x -= CpsSaveFrg[0][0x9];
// y -= CpsSaveFrg[0][0xB];
#endif
n |= (ps[1] & 0x6000) << 3; // high bits of address
// Find the palette for the tiles on this sprite
CpstPal = CpsObjPal + ((a & 0x1F) << 4);
nFlip = (a >> 5) & 3;
// Find out sprite size
bx = ((a >> 8) & 15) + 1;
by = ((a >> 12) & 15) + 1;
// Take care with tiles if the sprite goes off the screen
if (x < 0 || y < 0 || x + (bx << 4) > 383 || y + (by << 4) > 223) {
nCpstType = CTT_16X16 | CTT_CARE;
} else {
nCpstType = CTT_16X16;
}
// if (v == 0) {
// bprintf(PRINT_IMPORTANT, _T(" - %4i: 0x%04X 0x%04X 0x%04X 0x%04X\n"), ZValue - (UINT16)nMaxZValue, ps[0], ps[1], ps[2], ps[3]);
// }
nCpstFlip = nFlip;
for (dy = 0; dy < by; dy++) {
for (dx = 0; dx < bx; dx++) {
INT32 ex, ey;
if (nFlip & 1) {
ex = (bx - dx - 1);
} else {
ex = dx;
}
if (nFlip & 2) {
ey = (by - dy - 1);
} else {
ey = dy;
}
nCpstX = x + (ex << 4);
nCpstY = y + (ey << 4);
// nCpstTile = n + (dy << 4) + dx; // normal version
nCpstTile = (n & ~0x0F) + (dy << 4) + ((n + dx) & 0x0F); // pgear fix
nCpstTile <<= 7; // Find real tile address
pCpstOne();
}
}
}
return 0;
}

View File

@ -0,0 +1,297 @@
#include "cps.h"
// CPS (palette)
static UINT8* CpsPalSrc = NULL; // Copy of current input palette
UINT32* CpsPal = NULL; // Hicolor version of palette
UINT32* CpsObjPal = NULL;
INT32 nLagObjectPalettes;
inline static UINT32 CalcColCPS1(UINT16 a)
{
INT32 r, g, b, f;
const INT32 F_OFFSET = 0x0F;
// Format is FFFF RRRR GGGG BBBB
f = (a & 0xF000) >> 12;
r = (a & 0x0F00) >> 4; // Red
r |= r >> 4;
g = (a & 0x00F0); // Green
g |= g >> 4;
b = (a & 0x000F); // Blue
b |= b << 4;
f += F_OFFSET;
r *= f; r /= F_OFFSET + 0x0F;
g *= f; g /= F_OFFSET + 0x0F;
b *= f; b /= F_OFFSET + 0x0F;
return BurnHighCol(r, g, b, 0);
}
static UINT32 CalcColCPS2(UINT16 a)
{
INT32 r, g, b, f;
const INT32 F_OFFSET = 0x0F;
// Format is FFFF RRRR GGGG BBBB
f = (a & 0xF000) >> 12;
r = (a & 0x0F00) >> 4; // Red
r |= r >> 4;
g = (a & 0x00F0); // Green
g |= g >> 4;
b = (a & 0x000F); // Blue
b |= b << 4;
f += F_OFFSET;
r *= f; r /= F_OFFSET + 0x0F;
g *= f; g /= F_OFFSET + 0x0F;
b *= f; b /= F_OFFSET + 0x0F;
return BurnHighCol(r, g, b, 0);
}
static INT32 CalcAll()
{
UINT16* ps;
if (Cps == 2) {
if (nLagObjectPalettes) {
ps = (UINT16*)CpsPalSrc + 0x0C00;
for (INT32 i = 0x0C00; i < 0x0E00; i++, ps++) {
CpsPal[i ^ 15] = CalcColCPS2(*ps);
}
ps = (UINT16*)CpsPalSrc + 0x0200;
for (INT32 i = 0x0200; i < 0x0800; i++, ps++) {
CpsPal[i ^ 15] = CalcColCPS2(*ps);
}
memcpy(CpsPal + 0x0E00, CpsPal + 0x0C00, 0x0200 << 2);
} else {
ps = (UINT16*)CpsPalSrc;
for (INT32 i = 0x0000; i < 0x0800; i++, ps++) {
CpsPal[i ^ 15] = CalcColCPS2(*ps);
}
}
} else {
ps = (UINT16*)CpsPalSrc;
for (INT32 i = 0x0000; i < 0x0c00; i++, ps++) {
CpsPal[i ^ 15] = CalcColCPS1(*ps);
}
}
return 0;
}
static void CalcAllStar(INT32 nLayer)
{
UINT16* ps = (UINT16*)CpsPalSrc;
INT32 nOffset = 0x0800 + (nLayer << 9);
for (INT32 i = 0; i < 128; i++, ps++) {
CpsPal[(i + nOffset) ^ 15] = CalcColCPS1(*(ps + nOffset));
}
}
INT32 CpsPalInit()
{
INT32 nLen = 0;
nLen = 0x1000 * sizeof(UINT16);
CpsPalSrc = (UINT8*)malloc(nLen);
if (CpsPalSrc == NULL) {
return 1;
}
memset(CpsPalSrc, 0, nLen);
// The star layer palettes are at the end of the normal palette, so double the size
nLen = 0x1000 * sizeof(UINT32);
CpsPal = (UINT32*)malloc(nLen);
if (CpsPal == NULL) {
return 1;
}
// Set CpsPal to initial values
CalcAll();
if (CpsStar) {
CalcAllStar(0);
CalcAllStar(1);
}
if (nLagObjectPalettes) {
CpsObjPal = CpsPal + 0x0C00;
} else {
CpsObjPal = CpsPal;
}
return 0;
}
INT32 CpsPalExit()
{
if (CpsPal) {
free(CpsPal);
CpsPal = NULL;
}
if (CpsPalSrc) {
free(CpsPalSrc);
CpsPalSrc = NULL;
}
return 0;
}
// Update CpsPal with the new palette at pNewPal (length 0x1000 bytes)
INT32 CpsPalUpdate(UINT8* pNewPal, INT32 bRecalcAll)
{
INT32 i;
UINT16 *ps, *pn;
// If we are recalculating the whole palette, just copy to CpsPalSrc
// and recalculate it all
if (bRecalcAll) {
ps = (UINT16*)CpsPalSrc;
pn = (UINT16*)pNewPal;
if (nLagObjectPalettes) {
INT32 nBuffer = 0x0C00 + ((GetCurrentFrame() & 1) << 9);
memcpy(ps + 0x0200, pn + 0x0200, 0x0600 << 1);
memcpy(ps + nBuffer, pn, 0x0200 << 1);
memcpy(ps + 0x0E00, pn, 0x0200 << 1);
CpsObjPal = CpsPal + nBuffer;
} else {
memcpy(ps, pn, 0x0c00 << 1);
}
CalcAll();
return 0;
}
if (Cps == 2) {
if (nLagObjectPalettes) {
INT32 nBuffer = 0x0C00 + ((GetCurrentFrame() & 1) << 9);
ps = (UINT16*)CpsPalSrc + (nBuffer ^ 0x0200);
pn = (UINT16*)pNewPal;
CpsObjPal = CpsPal + (nBuffer ^ 0x0200);
for (i = 0; i < 0x0200; i++, ps++, pn++) {
UINT16 n;
n = *pn;
if (*ps == n) {
continue; // Colour hasn't changed - great!
}
*ps = n; // Update our copy of the palette
CpsObjPal[i ^ 15] = CalcColCPS2(n);
}
ps = (UINT16*)CpsPalSrc + 0x0200;
pn = (UINT16*)pNewPal + 0x0200;
for (i = 0x0200; i < 0x0800; i++, ps++, pn++) {
UINT16 n;
n = *pn;
if (*ps == n) {
continue; // Colour hasn't changed - great!
}
*ps = n; // Update our copy of the palette
CpsPal[i ^ 15] = CalcColCPS2(n);
}
CpsObjPal = CpsPal + nBuffer;
} else {
ps = (UINT16*)CpsPalSrc;
pn = (UINT16*)pNewPal;
for (i = 0x0000; i < 0x0800; i++, ps++, pn++) {
UINT16 n = *pn;
if (*ps == n) {
continue; // Colour hasn't changed - great!
}
*ps = n; // Update our copy of the palette
CpsPal[i ^ 15] = CalcColCPS2(n);
}
}
} else {
ps = (UINT16*)CpsPalSrc;
pn = (UINT16*)pNewPal;
for (i = 0x0000; i < 0x0c00; i++, ps++, pn++) {
UINT16 n = *pn;
if (*ps == n) {
continue; // Colour hasn't changed - great!
}
*ps = n; // Update our copy of the palette
CpsPal[i ^ 15] = CalcColCPS1(n);
}
}
return 0;
}
INT32 CpsStarPalUpdate(UINT8* pNewPal, INT32 nLayer, INT32 bRecalcAll)
{
INT32 i;
UINT16 *ps, *pn;
if (nLayer == 0) {
ps = (UINT16*)CpsPalSrc + 0x0800;
pn = (UINT16*)pNewPal + 0x0800;
if (bRecalcAll) {
memcpy(ps, pn, 256);
CalcAllStar(nLayer);
return 0;
}
// Star layer 0
for (i = 0x0800; i < 0x0880; i++, ps++, pn++) {
UINT16 n = *pn;
if (*ps == n) {
continue; // Colour hasn't changed - great!
}
*ps = n; // Update our copy of the palette
CpsPal[i ^ 15] = CalcColCPS1(n);
}
} else {
ps = (UINT16*)CpsPalSrc + 0x0A00;
pn = (UINT16*)pNewPal + 0x0A00;
if (bRecalcAll) {
memcpy(ps, pn, 256);
CalcAllStar(nLayer);
return 0;
}
// Star layer 1
for (i = 0x0A00; i < 0x0A80; i++, ps++, pn++) {
UINT16 n = *pn;
if (*ps == n) {
continue; // Colour hasn't changed - great!
}
*ps = n; // Update our copy of the palette
CpsPal[i ^ 15] = CalcColCPS1(n);
}
}
return 0;
}

View File

@ -0,0 +1,497 @@
// CPS - Run
#include "cps.h"
// Inputs:
UINT8 CpsReset = 0;
UINT8 Cpi01A = 0, Cpi01C = 0, Cpi01E = 0;
static INT32 nInterrupt;
static INT32 nIrqLine, nIrqCycles;
static bool bEnableAutoIrq50, bEnableAutoIrq52; // Trigger an interrupt every 32 scanlines
static const INT32 nFirstLine = 0x0C; // The first scanline of the display
static const INT32 nVBlank = 0x0106 - 0x0C; // The scanline at which the vblank interrupt is triggered
static INT32 nCpsCyclesExtra;
INT32 CpsDrawSpritesInReverse = 0;
INT32 nIrqLine50, nIrqLine52;
static INT32 DrvReset()
{
// Reset machine
if (Cps == 2 || PangEEP || Cps1Qs == 1) EEPROMReset();
SekOpen(0);
SekReset();
SekClose();
if (!Cps1Pic) {
ZetOpen(0);
ZetReset();
ZetClose();
}
if (Cps == 2) {
// Disable beam-synchronized interrupts
*((UINT16*)(CpsReg + 0x4E)) = 0x0200;
*((UINT16*)(CpsReg + 0x50)) = 0x0106;
*((UINT16*)(CpsReg + 0x52)) = 0x0106;
}
CpsMapObjectBanks(0);
nCpsCyclesExtra = 0;
if (Cps == 2 || Cps1Qs == 1) { // Sound init (QSound)
QsndReset();
}
HiscoreReset();
return 0;
}
static const eeprom_interface qsound_eeprom_interface =
{
7, /* address bits */
8, /* data bits */
"0110", /* read command */
"0101", /* write command */
"0111", /* erase command */
0,
0,
0,
0
};
static const eeprom_interface cps2_eeprom_interface =
{
6, /* address bits */
16, /* data bits */
"0110", /* read command */
"0101", /* write command */
"0111", /* erase command */
0,
0,
0,
0
};
INT32 CpsRunInit()
{
nLagObjectPalettes = 0;
if (Cps == 2) nLagObjectPalettes = 1;
SekInit(0, 0x68000); // Allocate 68000
if (CpsMemInit()) { // Memory init
return 1;
}
if (Cps == 2 || PangEEP) {
EEPROMInit(&cps2_eeprom_interface);
} else {
if (Cps1Qs == 1) {
EEPROMInit(&qsound_eeprom_interface);
}
}
CpsRwInit(); // Registers setup
if (CpsPalInit()) { // Palette init
return 1;
}
if (CpsObjInit()) { // Sprite init
return 1;
}
if ((Cps & 1) && Cps1Qs == 0 && Cps1Pic == 0) { // Sound init (MSM6295 + YM2151)
if (PsndInit()) {
return 1;
}
}
if (Cps == 2 || Cps1Qs == 1) { // Sound init (QSound)
if (QsndInit()) {
return 1;
}
}
if (Cps == 2 || PangEEP || Cps1Qs == 1) EEPROMReset();
DrvReset();
//Init Draw Function
DrawFnInit();
pBurnDrvPalette = CpsPal;
return 0;
}
INT32 CpsRunExit()
{
if (Cps == 2 || PangEEP || Cps1Qs == 1) EEPROMExit();
// Sound exit
if (Cps == 2 || Cps1Qs == 1) QsndExit();
if (Cps != 2 && Cps1Qs == 0) PsndExit();
// Graphics exit
CpsObjExit();
CpsPalExit();
// Sprite Masking exit
ZBuf = NULL;
// Memory exit
CpsRwExit();
CpsMemExit();
SekExit();
return 0;
}
// nStart = 0-3, nCount=1-4
inline static void GetPalette(INT32 nStart, INT32 nCount)
{
// Update Palette (Ghouls points to the wrong place on boot up I think)
INT32 nPal = (*((UINT16*)(CpsReg + 0x0A)) << 8) & 0xFFF800;
UINT8* Find = CpsFindGfxRam(nPal, 0x1000);
if (Find) {
memcpy(CpsSavePal + (nStart << 10), Find + (nStart << 10), nCount << 10);
}
}
static void GetStarPalette()
{
INT32 nPal = (*((UINT16*)(CpsReg + 0x0A)) << 8) & 0xFFF800;
UINT8* Find = CpsFindGfxRam(nPal, 256);
if (Find) {
memcpy(CpsSavePal + 4096, Find + 4096, 256);
memcpy(CpsSavePal + 5120, Find + 5120, 256);
}
}
inline static void CopyCpsReg(INT32 i)
{
memcpy(CpsSaveReg[i], CpsReg, 0x0100);
}
inline static void CopyCpsFrg(INT32 i)
{
memcpy(CpsSaveFrg[i], CpsFrg, 0x0010);
}
// Schedule a beam-synchronized interrupt
static void ScheduleIRQ()
{
INT32 nLine = 0x0106;
if (nIrqLine50 <= nLine) {
nLine = nIrqLine50;
}
if (nIrqLine52 < nLine) {
nLine = nIrqLine52;
}
if (nLine < 0x0106) {
nIrqLine = nLine;
nIrqCycles = (nLine * nCpsCycles / 0x0106) + 1;
} else {
nIrqCycles = nCpsCycles + 1;
}
return;
}
// Execute a beam-synchronised interrupt and schedule the next one
static void DoIRQ()
{
// 0x4E - bit 9 = 1: Beam Synchronized interrupts disabled
// 0x50 - Beam synchronized interrupt #1 occurs at raster line.
// 0x52 - Beam synchronized interrupt #2 occurs at raster line.
// Trigger IRQ and copy registers.
if (nIrqLine >= nFirstLine) {
nInterrupt++;
nRasterline[nInterrupt] = nIrqLine - nFirstLine;
}
SekSetIRQLine(4, SEK_IRQSTATUS_AUTO);
SekRun(nCpsCycles * 0x01 / 0x0106);
if (nRasterline[nInterrupt] < 224) {
CopyCpsReg(nInterrupt);
CopyCpsFrg(nInterrupt);
} else {
nRasterline[nInterrupt] = 0;
}
// Schedule next interrupt
if (!bEnableAutoIrq50) {
if (nIrqLine >= nIrqLine50) {
nIrqLine50 = 0x0106;
}
} else {
if (bEnableAutoIrq50 && nIrqLine == nIrqLine50) {
nIrqLine50 += 32;
}
}
if (!bEnableAutoIrq52 && nIrqLine >= nIrqLine52) {
nIrqLine52 = 0x0106;
} else {
if (bEnableAutoIrq52 && nIrqLine == nIrqLine52) {
nIrqLine52 += 32;
}
}
ScheduleIRQ();
if (nIrqCycles < SekTotalCycles()) {
nIrqCycles = SekTotalCycles() + 1;
}
return;
}
INT32 Cps1Frame()
{
INT32 nDisplayEnd, nNext, i;
if (CpsReset) {
DrvReset();
}
SekNewFrame();
if (Cps1Qs == 1) {
QsndNewFrame();
} else {
if (!Cps1Pic) {
ZetOpen(0);
PsndNewFrame();
}
}
nCpsCycles = (INT32)((INT64)nCPS68KClockspeed * nBurnCPUSpeedAdjust >> 8);
CpsRwGetInp(); // Update the input port values
nDisplayEnd = (nCpsCycles * (nFirstLine + 224)) / 0x0106; // Account for VBlank
SekOpen(0);
SekIdle(nCpsCyclesExtra);
SekRun(nCpsCycles * nFirstLine / 0x0106); // run 68K for the first few lines
if (!CpsDrawSpritesInReverse) {
CpsObjGet(); // Get objects
}
for (i = 0; i < 4; i++) {
nNext = ((i + 1) * nCpsCycles) >> 2; // find out next cycle count to run to
if (SekTotalCycles() < nDisplayEnd && nNext > nDisplayEnd) {
SekRun(nNext - nDisplayEnd); // run 68K
memcpy(CpsSaveReg[0], CpsReg, 0x100); // Registers correct now
GetPalette(0, 6); // Get palette
if (CpsStar) {
GetStarPalette();
}
if (CpsDrawSpritesInReverse) {
if (i == 3) CpsObjGet(); // Get objects
}
SekSetIRQLine(2, SEK_IRQSTATUS_AUTO); // Trigger VBlank interrupt
}
SekRun(nNext - SekTotalCycles()); // run 68K
// if (pBurnDraw) {
// CpsDraw(); // Draw frame
// }
}
if (pBurnDraw) {
CpsDraw(); // Draw frame
}
if (Cps1Qs == 1) {
QsndEndFrame();
} else {
if (!Cps1Pic) {
PsndSyncZ80(nCpsZ80Cycles);
PsmUpdate(nBurnSoundLen);
ZetClose();
}
}
nCpsCyclesExtra = SekTotalCycles() - nCpsCycles;
SekClose();
return 0;
}
INT32 Cps2Frame()
{
INT32 nDisplayEnd, nNext; // variables to keep track of executed 68K cyles
INT32 i;
if (CpsReset) {
DrvReset();
}
// extern INT32 prevline;
// prevline = -1;
SekNewFrame();
QsndNewFrame();
nCpsCycles = (INT32)(((INT64)nCPS68KClockspeed * nBurnCPUSpeedAdjust) / 0x0100);
SekSetCyclesScanline(nCpsCycles / 262);
CpsRwGetInp(); // Update the input port values
nDisplayEnd = nCpsCycles * (nFirstLine + 224) / 0x0106; // Account for VBlank
nInterrupt = 0;
for (i = 0; i < MAX_RASTER + 2; i++) {
nRasterline[i] = 0;
}
// Determine which (if any) of the line counters generates the first IRQ
bEnableAutoIrq50 = bEnableAutoIrq52 = false;
nIrqLine50 = nIrqLine52 = 0x0106;
if (*((UINT16*)(CpsReg + 0x50)) & 0x8000) {
bEnableAutoIrq50 = true;
}
if (bEnableAutoIrq50 || (*((UINT16*)(CpsReg + 0x4E)) & 0x0200) == 0) {
nIrqLine50 = (*((UINT16*)(CpsReg + 0x50)) & 0x01FF);
}
if (*((UINT16*)(CpsReg + 0x52)) & 0x8000) {
bEnableAutoIrq52 = true;
}
if (bEnableAutoIrq52 || (*((UINT16*)(CpsReg + 0x4E)) & 0x0200) == 0) {
nIrqLine52 = (*((UINT16*)(CpsReg + 0x52)) & 0x01FF);
}
ScheduleIRQ();
SekOpen(0);
SekIdle(nCpsCyclesExtra);
if (nIrqCycles < nCpsCycles * nFirstLine / 0x0106) {
SekRun(nIrqCycles);
DoIRQ();
}
nNext = nCpsCycles * nFirstLine / 0x0106;
if (SekTotalCycles() < nNext) {
SekRun(nNext - SekTotalCycles());
}
CopyCpsReg(0); // Get inititial copy of registers
CopyCpsFrg(0); //
if (nIrqLine >= 0x0106 && (*((UINT16*)(CpsReg + 0x4E)) & 0x0200) == 0) {
nIrqLine50 = *((UINT16*)(CpsReg + 0x50)) & 0x01FF;
nIrqLine52 = *((UINT16*)(CpsReg + 0x52)) & 0x01FF;
ScheduleIRQ();
}
GetPalette(0, 4); // Get palettes
CpsObjGet(); // Get objects
for (i = 0; i < 3; i++) {
nNext = ((i + 1) * nDisplayEnd) / 3; // find out next cycle count to run to
while (nNext > nIrqCycles && nInterrupt < MAX_RASTER) {
SekRun(nIrqCycles - SekTotalCycles());
DoIRQ();
}
SekRun(nNext - SekTotalCycles()); // run cpu
}
// nCpsCyclesSegment[0] = (nCpsCycles * nVBlank) / 0x0106;
// nDone += SekRun(nCpsCyclesSegment[0] - nDone);
SekSetIRQLine(2, SEK_IRQSTATUS_AUTO); // VBlank
SekRun(nCpsCycles - SekTotalCycles());
if (pBurnDraw) {
CpsDraw();
}
nCpsCyclesExtra = SekTotalCycles() - nCpsCycles;
QsndEndFrame();
SekClose();
// bprintf(PRINT_NORMAL, _T(" -\n"));
#if 0 && defined FBA_DEBUG
if (nInterrupt) {
bprintf(PRINT_IMPORTANT, _T("Beam synchronized interrupt at line %2X.\r"), nRasterline[nInterrupt]);
} else {
bprintf(PRINT_NORMAL, _T("Beam synchronized interrupt disabled. \r"));
}
extern INT32 counter;
if (counter) {
bprintf(PRINT_NORMAL, _T("\n\nSlices start at: "));
for (i = 0; i < MAX_RASTER + 2; i++) {
bprintf(PRINT_NORMAL, _T("%2X "), nRasterline[i]);
}
bprintf(PRINT_NORMAL, _T("\n"));
for (i = 0; i < 0x80; i++) {
if (*((UINT16*)(CpsSaveReg[0] + i * 2)) != *((UINT16*)(CpsSaveReg[nInterrupt] + i * 2))) {
bprintf(PRINT_NORMAL, _T("Register %2X: %4X -> %4X\n"), i * 2, *((UINT16*)(CpsSaveReg[0] + i * 2)), *((UINT16*)(CpsSaveReg[nInterrupt] + i * 2)));
}
}
bprintf(PRINT_NORMAL, _T("\n"));
for (i = 0; i < 0x010; i++) {
if (CpsSaveFrg[0][i] != CpsSaveFrg[nInterrupt][i]) {
bprintf(PRINT_NORMAL, _T("FRG %X: %02X -> %02X\n"), i, CpsSaveFrg[0][i], CpsSaveFrg[nInterrupt][i]);
}
}
bprintf(PRINT_NORMAL, _T("\n"));
if (((CpsSaveFrg[0][4] << 8) | CpsSaveFrg[0][5]) != ((CpsSaveFrg[nInterrupt][4] << 8) | CpsSaveFrg[nInterrupt][5])) {
bprintf(PRINT_NORMAL, _T("Layer-sprite priority: %04X -> %04X\n"), ((CpsSaveFrg[0][4] << 8) | CpsSaveFrg[0][5]), ((CpsSaveFrg[nInterrupt][4] << 8) | CpsSaveFrg[nInterrupt][5]));
}
bprintf(PRINT_NORMAL, _T("\n"));
for (INT32 j = 0; j <= nInterrupt; j++) {
if (j) {
bprintf(PRINT_NORMAL, _T("IRQ : %i (triggered at line %3i)\n\n"), j, nRasterline[j]);
} else {
bprintf(PRINT_NORMAL, _T("Initial register status\n\n"));
}
for (i = 0; i < 0x080; i+= 8) {
bprintf(PRINT_NORMAL, _T("%2X: %4X %4X %4X %4X %4X %4X %4X %4X\n"), i * 2, *((UINT16*)(CpsSaveReg[j] + 0 + i * 2)), *((UINT16*)(CpsSaveReg[j] + 2 + i * 2)), *((UINT16*)(CpsSaveReg[j] + 4 + i * 2)), *((UINT16*)(CpsSaveReg[j] + 6 + i * 2)), *((UINT16*)(CpsSaveReg[j] + 8 + i * 2)), *((UINT16*)(CpsSaveReg[j] + 10 + i * 2)), *((UINT16*)(CpsSaveReg[j] + 12 + i * 2)), *((UINT16*)(CpsSaveReg[j] + 14 + i * 2)));
}
bprintf(PRINT_NORMAL, _T("\nFRG: "));
for (i = 0; i < 0x010; i++) {
bprintf(PRINT_NORMAL, _T("%02X "), CpsSaveFrg[j][i]);
}
bprintf(PRINT_NORMAL, _T("\n\n"));
}
extern INT32 bRunPause;
bRunPause = 1;
counter = 0;
}
#endif
return 0;
}

View File

@ -0,0 +1,589 @@
#include "cps.h"
// CPS - Read/Write
// Input bits
#define INP(nnn) UINT8 CpsInp##nnn[8];
CPSINPSET
#undef INP
// Bytes to return from ports
#define INP(nnn) UINT8 Inp##nnn;
CPSINPSET
#undef INP
UINT16 CpsInp055 = 0;
UINT16 CpsInp05d = 0;
UINT16 CpsInpPaddle1 = 0;
UINT16 CpsInpPaddle2 = 0;
static INT32 ReadPaddle = 0;
INT32 CpsPaddle1Value = 0;
INT32 CpsPaddle2Value = 0;
INT32 CpsPaddle1 = 0;
INT32 CpsPaddle2 = 0;
static INT32 nDial055, nDial05d;
INT32 PangEEP = 0;
INT32 Forgottn = 0;
INT32 Cps1QsHack = 0;
INT32 Kodh = 0;
INT32 Cawingb = 0;
INT32 Wofh = 0;
INT32 Sf2thndr = 0;
INT32 Pzloop2 = 0;
INT32 Ssf2tb = 0;
INT32 Dinopic = 0;
INT32 Dinohunt = 0;
INT32 Port6SoundWrite = 0;
static INT32 nCalc[2] = {0, 0};
static const bool nCPSExtraNVRAM = false;
static INT32 n664001;
#define INP(nnnn) UINT8 CpsInp##nnnn[8];
CPSINPEX
#undef INP
#define INP(nnnn) static UINT8 Inp##nnnn;
CPSINPEX
#undef INP
// Read input port 0x000-0x1ff
static UINT8 CpsReadPort(const UINT32 ia)
{
UINT8 d = 0xFF;
// bprintf(PRINT_NORMAL, _T("Read Port %x\n"), ia);
if (ia == 0x000) {
d = (UINT8)~Inp000;
if (Pzloop2) {
if (ReadPaddle) {
d -= CpsPaddle2Value;
} else {
d = CpsPaddle2;
}
}
return d;
}
if (ia == 0x001) {
d = (UINT8)~Inp001;
if (Pzloop2) {
if (ReadPaddle) {
d -= CpsPaddle1Value;
} else {
d = CpsPaddle1;
}
}
return d;
}
if (ia == 0x010) {
d = (UINT8)~Inp010;
return d;
}
if (ia == 0x011) {
d = (UINT8)~Inp011;
return d;
}
if (ia == 0x012) {
d = (UINT8)~Inp012;
return d;
}
if (ia == 0x018) {
d = (UINT8)~Inp018;
return d;
}
if (ia == 0x019) {
d = (UINT8)~Inp019;
return d;
}
if (ia == 0x01A) {
d = (UINT8)~Cpi01A;
return d;
}
if (ia == 0x01C) {
d = (UINT8)~Cpi01C;
return d;
}
if (ia == 0x01E) {
d = (UINT8)~Cpi01E;
return d;
}
if (Cps == 2) {
// Used on CPS2 only I think
if (ia == 0x020) {
d = (UINT8)~Inp020;
return d;
}
if (ia == 0x021) {
d = (UINT8)~Inp021;
d &= 0xFE;
d |= EEPROMRead();
return d;
}
// CPS2 Volume control
if (ia == 0x030) {
if (Ssf2tb) {
d = 0x20;
} else {
d = 0xe0;
}
return d;
}
if (ia == 0x031) {
d = 0x21;
return d;
}
if (ia >= 0x0100 && ia < 0x0200) {
static INT32 nRasterLine;
// bprintf(PRINT_NORMAL, _T(" - port 0x%02X (%3i)\n"), ia & 255, SekCurrentScanline());
// The linecounters seem to return the line at which the last IRQ triggered by this counter is scheduled minus the current line
if ((ia & 0x0FE) == 0x50) {
if ((ia & 1) == 0) {
nRasterLine = nIrqLine50 - SekCurrentScanline();
return nRasterLine >> 8;
} else {
return nRasterLine & 0xFF;
}
}
if ((ia & 0x0FE) == 0x52) {
if ((ia & 1) == 0) {
nRasterLine = nIrqLine52 - SekCurrentScanline();
return nRasterLine >> 8;
} else {
return nRasterLine & 0xFF;
}
}
}
} else {
// Board ID
if (ia == 0x100 + CpsBID[0]) {
d = (UINT8)CpsBID[1];
return d;
}
if (ia == 0x100 + (CpsBID[0] + 1)) {
d = (UINT8)CpsBID[2];
return d;
}
if (Sf2thndr) {
// this reads the B-ID from here on startup as well as the normal location in-game
if (ia == 0x1c8) {
d = (UINT8)CpsBID[1];
return d;
}
if (ia == 0x1c9) {
d = (UINT8)CpsBID[2];
return d;
}
}
// CPS1 EEPROM read
if (ia == 0xC007) {
return EEPROMRead();
}
// Pang3 EEPROM
if (PangEEP == 1) {
if (ia == 0x17B) {
return EEPROMRead();
}
}
// Extra Input ports (move from game-to-game)
if (ia == 0x006) {
d = (UINT8)~Inp006;
return d;
}
if (ia == 0x007) {
d = (UINT8)~Inp007;
return d;
}
if (ia == 0x008) {
d = (UINT8)~Inp008;
return d;
}
if (ia == 0x029) {
d = (UINT8)~Inp029;
return d;
}
if (ia == 0x176) {
d = (UINT8)~Inp176;
return d;
}
if (ia == 0x177) {
d = (UINT8)~Inp177;
return d;
}
if (ia == 0x179) {
d = (UINT8)~Inp179;
return d;
}
if (ia == 0x186) {
d = (UINT8)~Inp186;
return d;
}
if (ia == 0x1fd) {
d = (UINT8)~Inp1fd;
return d;
}
if (ia == 0xC000) {
d = (UINT8)~Inpc000;
return d;
}
if (ia == 0xC001) {
d = (UINT8)~Inpc001;
return d;
}
if (ia == 0xC002) {
d = (UINT8)~Inpc002;
return d;
}
if (ia == 0xC003) {
d = (UINT8)~Inpc003;
return d;
}
// Forgotten Worlds Dial
if (Forgottn) {
if (ia == 0x053) {
return (nDial055 >> 8) & 0xFF;
}
if (ia == 0x055) {
return (nDial055 >> 16) & 0xFF;
}
if (ia == 0x05B) {
return (nDial05d >> 8) & 0xFF;
}
if (ia == 0x05D) {
return (nDial05d >> 16) & 0xFF;
}
}
}
return d;
}
// Write output port 0x000-0x1ff
static void CpsWritePort(const UINT32 ia, UINT8 d)
{
if ((Cps & 1) && Cps1Qs == 0) {
// CPS1 sound code
if (ia == 0x181 || (Port6SoundWrite && (ia == 0x006 || ia == 0x007))) {
PsndSyncZ80((INT64)SekTotalCycles() * nCpsZ80Cycles / nCpsCycles);
PsndCode = d;
return;
}
// CPS1 sound fade
if (ia == 0x189) {
PsndSyncZ80((INT64)SekTotalCycles() * nCpsZ80Cycles / nCpsCycles);
PsndFade = d;
return;
}
if (ia == 0x041) {
nDial055 = 0;
}
if (ia == 0x049) {
nDial05d = 0;
}
}
if (Cps == 1 && Cps1QsHack == 1) {
if (ia == 0x181) {
// Pass the Sound Code to the Q-Sound Shared Ram
CpsZRamC0[0x001] = d;
}
}
// CPS registers
if (ia >= 0x100 && ia < 0x200) {
//Pang3 EEPROM
if (PangEEP == 1 && ia == 0x17B) {
EEPROMWrite(d & 0x40, d & 0x80, d & 0x01);
return;
}
CpsReg[(ia ^ 1) & 0xFF] = d;
return;
}
if (Cps == 2) {
if (ia == 0x40) {
EEPROMWrite(d & 0x20, d& 0x40, d & 0x10);
return;
}
// CPS2 object bank select
if ((ia & 0x1FF) == 0x0E1) {
// bprintf(PRINT_NORMAL, _T(" - %2i (%3i)\n"), d & 1, SekCurrentScanline());
// CpsObjGet();
CpsMapObjectBanks(d & 1);
return;
}
if (ia == 0x41 && Pzloop2) {
ReadPaddle = d & 0x02;
}
}
if (Cps1Qs == 1) {
//CPS1 EEPROM write
if (ia == 0xc007) {
EEPROMWrite(d & 0x40, d & 0x80, d & 0x01);
return;
}
}
}
UINT8 __fastcall CpsReadByte(UINT32 a)
{
// Input ports mirrored between 0x800000 and 0x807fff
if ((a & 0xFF8000) == 0x800000) {
return CpsReadPort(a & 0x1FF);
}
if (Cps == 2) {
if ((a & 0xFF8000) == 0x660000) {
if (a == 0x664001) {
return n664001;
}
}
return 0x00;
}
if (a >= 0xF1C000 && a <= 0xF1C007) {
return CpsReadPort(a & 0xC00F);
}
if (Dinohunt && a == 0xfc0001) return (UINT8)~Inpc001;
// bprintf(PRINT_NORMAL, _T("Read Byte %x\n"), a);
return 0x00;
}
void __fastcall CpsWriteByte(UINT32 a,UINT8 d)
{
// Output ports mirrored between 0x800000 and 0x807fff
if ((a & 0xFF8000) == 0x800000) {
CpsWritePort(a & 0x1FF, d);
return;
}
if (Cps == 2) {
// 0x400000 registers
if ((a & 0xFFFFF0) == 0x400000) {
CpsFrg[a & 0x0F] = d;
return;
}
if ((a & 0xFF8000) == 0x660000) {
if (a == 0x664001) {
// bit 1 toggled on/off each frame
n664001 = d;
}
return;
}
return;
}
if (Cps1Qs == 1) {
// CPS1 EEPROM
if (a == 0xf1c007) {
CpsWritePort(a & 0xC00F, d);
return;
}
}
// bprintf(PRINT_NORMAL, _T("Write Byte %x, %x\n"), a, d);
}
UINT16 __fastcall CpsReadWord(UINT32 a)
{
if ((a & 0xFF8FFF) == 0x800100 + CpsMProt[3]) {
return (UINT16)((nCalc[0] * nCalc[1]) >> 16);
}
// ports mirrored between 0x800000 and 0x807fff
if ((a & 0xFF8FFF) == 0x800100 + CpsMProt[2]) {
return (UINT16)((nCalc[0] * nCalc[1]));
}
// bprintf(PRINT_NORMAL, _T("Read Word %x\n"), a);
SEK_DEF_READ_WORD(0, a);
}
void __fastcall CpsWriteWord(UINT32 a, UINT16 d)
{
// ports mirrored between 0x800000 and 0x807fff
if ((a & 0xFF8FFF) == 0x800100 + CpsMProt[0])
nCalc[0] = d;
if ((a & 0xFF8FFF) == 0x800100 + CpsMProt[1])
nCalc[1] = d;
if (a == 0x804040) {
if ((d & 0x0008) == 0) {
ZetReset();
}
}
if (Dinopic && a == 0x800222) {
CpsReg[6] = d & 0xff;
CpsReg[7] = d >> 8;
return;
}
// bprintf(PRINT_NORMAL, _T("Write Word %x, %x\n"), a, d);
SEK_DEF_WRITE_WORD(0, a, d);
}
// Reset all inputs to zero
static INT32 InpBlank()
{
#define INP(nnn) Inp##nnn = 0; memset(CpsInp##nnn, 0, sizeof(CpsInp##nnn));
CPSINPSET
#undef INP
#define INP(nnnn) Inp##nnnn = 0; memset(CpsInp##nnnn, 0, sizeof(CpsInp##nnnn));
CPSINPEX
#undef INP
CpsInp055 = CpsInp05d = 0;
return 0;
}
INT32 CpsRwInit()
{
InpBlank();
return 0;
}
INT32 CpsRwExit()
{
InpBlank();
return 0;
}
inline static void StopOpposite(UINT8* pInput)
{
if ((*pInput & 0x03) == 0x03) {
*pInput &= ~0x03;
}
if ((*pInput & 0x0C) == 0x0C) {
*pInput &= ~0x0C;
}
}
INT32 CpsRwGetInp()
{
// Compile separate buttons into Inpxxx
#define INP(nnn) \
{ INT32 i = 0; Inp##nnn = 0; \
for (i = 0; i < 8; i++) { Inp##nnn |= (CpsInp##nnn[i] & 1) << i; } }
CPSINPSET
#undef INP
#define INP(nnnn) \
{ INT32 i = 0; Inp##nnnn = 0; \
for (i = 0; i < 8; i++) { Inp##nnnn |= (CpsInp##nnnn[i] & 1) << i; } }
CPSINPEX
#undef INP
if (Forgottn) {
// Handle analog controls
nDial055 += (INT32)((INT16)CpsInp055);
nDial05d += (INT32)((INT16)CpsInp05d);
}
if (Pzloop2) {
if (ReadPaddle) {
CpsPaddle1Value = 0;
CpsPaddle2Value = 0;
if (CpsInpPaddle1) {
if (CpsInpPaddle1 > 0x8000) {
CpsPaddle1Value = 2;
}
if (CpsInpPaddle1 < 0x7fff) {
CpsPaddle1Value = 1;
}
}
if (CpsInpPaddle2) {
if (CpsInpPaddle2 > 0x8000) {
CpsPaddle2Value = 2;
}
if (CpsInpPaddle2 < 0x7fff) {
CpsPaddle2Value = 1;
}
}
}
CpsPaddle1 += (CpsInpPaddle1 >> 8) & 0xff;
CpsPaddle2 += (CpsInpPaddle2 >> 8) & 0xff;
}
StopOpposite(&Inp000);
StopOpposite(&Inp001);
// Ghouls uses a 4-way stick
if (Ghouls) {
static UINT8 nPrevInp000, nPrevInp001;
if ((Inp000 & 0x03) && (Inp000 & 0x0C)) {
Inp000 ^= (nPrevInp000 & 0x0F);
} else {
nPrevInp000 = Inp000;
}
if ((Inp001 & 0x03) && (Inp001 & 0x0C)) {
Inp001 ^= (nPrevInp001 & 0x0F);
} else {
nPrevInp001 = Inp001;
}
}
if (nMaxPlayers > 2) {
if (Cps == 2) {
StopOpposite(&Inp011);
if (nMaxPlayers == 4) {
StopOpposite(&Inp010);
}
} else {
StopOpposite(&Inp177);
if (nMaxPlayers == 4) {
StopOpposite(&Inp179);
}
if (Cps1Qs) {
StopOpposite(&Inpc001);
if (nMaxPlayers == 4) {
StopOpposite(&Inpc003);
}
}
}
}
return 0;
}
void CpsSoundCmd(UINT16 sound_code) {
// CpsWritePort(0x181, sound_code);
PsndCode = sound_code;
}

View File

@ -0,0 +1,265 @@
#include "cps.h"
// CPS Scroll (Background Layers)
// Base = 0x4000 long tile map
// sx=Scroll X value, sy=Scroll Y value,
INT32 Ghouls=0;
INT32 Mercs=0;
INT32 Sf2jc=0;
INT32 Ssf2t=0;
INT32 Qad=0;
INT32 Xmcota=0;
INT32 Scroll1TileMask = 0;
INT32 Scroll2TileMask = 0;
INT32 Scroll3TileMask = 0;
INT32 Cps1Scr1Draw(UINT8 *Base,INT32 sx,INT32 sy)
{
INT32 x,y;
INT32 ix,iy;
INT32 nKnowBlank=-1; // The tile we know is blank
ix=(sx>>3)+1; iy=(sy>>3)+1;
sx&=7; sy&=7; sx=8-sx; sy=8-sy;
for (y=-1; y<28; y++)
{
for (x=-1; x<48; x++)
{
INT32 t,a;
UINT16 *pst;
INT32 fx,fy,p;
fx=ix+x; fy=iy+y; // fx/fy= 0 to 63
// Find tile address
p=((fy&0x20)<<8) | ((fx&0x3f)<<7) | ((fy&0x1f)<<2);
p&=0x3fff;
pst=(UINT16 *)(Base + p);
t=pst[0];
if (Scroll1TileMask) t &= Scroll1TileMask;
t = GfxRomBankMapper(GFXTYPE_SCROLL1, t);
if (t == -1) continue;
t<<=6; // Get real tile address
t+=nCpsGfxScroll[1]; // add on offset to scroll tiles
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a=pst[1];
CpstSetPal(0x20 | (a&0x1f));
// Don't need to clip except around the border
if (x<0 || x>=48-1 || y<0 || y>=28-1)
nCpstType=CTT_8X8 | CTT_CARE;
else
nCpstType=CTT_8X8;
nCpstX=sx+(x<<3); nCpstY=sy+(y<<3);
nCpstTile=t; nCpstFlip=(a>>5)&3;
if (nBgHi) {
CpstPmsk = *(UINT16*)(CpsSaveReg[0] + MaskAddr[(a & 0x180) >> 7]);
}
if(CpstOneDoX[nBgHi]()) nKnowBlank=t;
}
}
return 0;
}
INT32 Cps2Scr1Draw(UINT8 *Base, INT32 sx, INT32 sy)
{
INT32 x, y;
INT32 ix, iy;
INT32 nFirstY, nLastY;
INT32 nKnowBlank = -1; // The tile we know is blank
ix = (sx >> 3) + 1;
sx &= 7;
sx = 8 - sx;
iy = (sy >> 3) + 1;
sy &= 7;
nLastY = (nEndline + sy) >> 3;
nFirstY = (nStartline + sy) >> 3;
sy = 8 - sy;
for (y = nFirstY - 1; y < nLastY; y++) {
INT32 nClipY = ((y << 3) < nStartline) | (((y << 3) + 8) >= nEndline);
for (x = -1; x < 48; x++) {
INT32 t, a;
UINT16 *pst;
INT32 fx, fy, p;
fx = ix + x;
fy = iy + y; // 0 <= fx/fy <= 63
// Find tile address
p = ((fy & 0x20) << 8) | ((fx & 0x3F) << 7) | ((fy & 0x1F) << 2);
p &= 0x3FFF;
pst = (UINT16 *)(Base + p);
t = pst[0];
t <<= 6; // Get real tile address
t += nCpsGfxScroll[1]; // add on offset to scroll tiles
if (t != nKnowBlank) { // Draw tile
a = pst[1];
CpstSetPal(0x20 | (a & 0x1F));
nCpstX = sx + (x << 3);
nCpstY = sy + (y << 3);
nCpstTile = t;
nCpstFlip = (a >> 5) & 3;
// Don't need to clip except around the border
if (x < 0 || x >= 48 - 1 || nClipY) {
nCpstType = CTT_8X8 | CTT_CARE;
} else {
nCpstType = CTT_8X8;
}
if (CpstOneDoX[2]()) {
nKnowBlank = t;
}
}
}
}
return 0;
}
INT32 Cps1Scr3Draw(UINT8 *Base,INT32 sx,INT32 sy)
{
INT32 x,y;
INT32 ix,iy;
INT32 nKnowBlank=-1; // The tile we know is blank
ix=(sx>>5)+1; iy=(sy>>5)+1;
sx&=31; sy&=31; sx=32-sx; sy=32-sy;
for (y=-1; y<7; y++)
{
for (x=-1; x<12; x++)
{
INT32 t,a;
UINT16 *pst;
INT32 fx,fy,p;
fx=ix+x; fy=iy+y; // fx/fy= 0 to 63
// Find tile address
p=((fy&0x38)<<8) | ((fx&0x3f)<<5) | ((fy&0x07)<<2);
p&=0x3fff;
pst=(UINT16 *)(Base + p);
t=pst[0];
if (Scroll3TileMask) t &= Scroll3TileMask;
t = GfxRomBankMapper(GFXTYPE_SCROLL3, t);
if (t == -1) continue;
t<<=9; // Get real tile address
t+=nCpsGfxScroll[3]; // add on offset to scroll tiles
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a=pst[1];
CpstSetPal(0x60 | (a&0x1f));
// Don't need to clip except around the border
if (x<0 || x>=12-1 || y<0 || y>=7-1)
nCpstType=CTT_32X32 | CTT_CARE;
else
nCpstType=CTT_32X32;
nCpstX=sx+(x<<5); nCpstY=sy+(y<<5);
nCpstTile=t; nCpstFlip=(a>>5)&3;
if (nBgHi) {
CpstPmsk = *(UINT16*)(CpsSaveReg[0] + MaskAddr[(a & 0x180) >> 7]);
}
if(CpstOneDoX[nBgHi]()) nKnowBlank=t;
}
}
return 0;
}
INT32 Cps2Scr3Draw(UINT8 *Base, INT32 sx, INT32 sy)
{
INT32 x, y;
INT32 ix, iy;
INT32 nFirstY, nLastY;
INT32 nKnowBlank = -1; // The tile we know is blank
ix = (sx >> 5) + 1;
sx &= 31;
sx = 32 - sx;
iy = (sy >> 5) + 1;
sy &= 31;
nLastY = (nEndline + sy) >> 5;
nFirstY = (nStartline + sy) >> 5;
sy = 32 - sy;
for (y = nFirstY - 1; y < nLastY; y++) {
INT32 nClipY = ((y << 5) < nStartline) | (((y << 5) + 32) >= nEndline);
for (x = -1; x < 12; x++) {
INT32 t, a;
UINT16 *pst;
INT32 fx, fy, p;
fx = ix + x;
fy = iy + y; // 0 <= fx/fy <= 63
// Find tile address
p = ((fy & 0x38) << 8) | ((fx & 0x3F) << 5) | ((fy & 0x07) << 2);
p &= 0x3FFF;
pst = (UINT16 *)(Base + p);
t = pst[0];
if(Xmcota && t>=0x5800) t-=0x4000;
else if(Ssf2t && t<0x5600) t+=0x4000;
t <<= 9; // Get real tile address
t += nCpsGfxScroll[3]; // add on offset to scroll tiles
if (t != nKnowBlank) { // Draw tile
a = pst[1];
CpstSetPal(0x60 | (a & 0x1F));
nCpstX = sx + (x << 5);
nCpstY = sy + (y << 5);
nCpstTile = t;
nCpstFlip = (a >> 5) & 3;
// Don't need to clip except around the border
if (x < 0 || x >= 12 - 1 || nClipY) {
nCpstType = CTT_32X32 | CTT_CARE;
} else {
nCpstType = CTT_32X32;
}
if (CpstOneDoX[2]()) {
nKnowBlank = t;
}
}
}
}
return 0;
}

View File

@ -0,0 +1,199 @@
#include "cps.h"
// CPS Scroll2 with Row scroll support
UINT8 *CpsrBase=NULL; // Tile data base
INT32 nCpsrScrX=0,nCpsrScrY=0; // Basic scroll info
UINT16 *CpsrRows=NULL; // Row scroll table, 0x400 words long
int nCpsrRowStart=0; // Start of row scroll (can wrap?)
static INT32 nShiftY=0;
static INT32 EndLineInfo=0;
struct CpsrLineInfo CpsrLineInfo[15];
static void GetRowsRange(INT32 *pnStart,INT32 *pnWidth,INT32 nRowFrom,INT32 nRowTo)
{
INT32 i,nStart,nWidth;
// Get the range of scroll values within nRowCount rows
// Start with zero range
nStart=CpsrRows[nRowFrom&0x3ff]; nStart&=0x3ff; nWidth=0;
for (i=nRowFrom;i<nRowTo;i++)
{
INT32 nViz; INT32 nDiff;
nViz=CpsrRows[i&0x3ff]; nViz&=0x3ff;
// Work out if this is on the left or the right of our
// start point.
nDiff=nViz-nStart;
// clip to 10-bit signed
nDiff=((nDiff+0x200)&0x3ff)-0x200;
if (nDiff>=0)
{
// On the right
if (nDiff>=nWidth) nWidth=nDiff; // expand width to cover it
}
else
{
// On the left
nStart+=nDiff; nStart&=0x3ff;
nWidth-=nDiff; // expand width to cover it
}
}
if (nWidth>0x400) nWidth=0x400;
*pnStart=nStart;
*pnWidth=nWidth;
}
static INT32 PrepareRows()
{
INT32 y; INT32 r;
struct CpsrLineInfo *pli;
// Calculate the amount of pixels to shift each
// row of the tile lines, assuming we draw tile x at
// (x-pli->nTileStart)<<4 - i.e. 0, 16, ...
r=nShiftY-16;
for (y = -1, pli = CpsrLineInfo; y < EndLineInfo; y++, pli++)
{
// Maximum row scroll left and right on this line
INT32 nMaxLeft=0,nMaxRight=0;
INT32 ty; INT16 *pr;
if (CpsrRows==NULL)
{
// No row shift - all the same
INT32 v;
v =(pli->nTileStart<<4)-nCpsrScrX;
nMaxLeft=v; nMaxRight=v;
for (ty=0,pr=pli->Rows; ty<16; ty++,pr++)
{
*pr=(INT16)v;
}
}
else
{
for (ty=0,pr=pli->Rows; ty<16; ty++,pr++,r++)
{
// Get the row offset, if it's in range
if (r>=0 && r<nEndline)
{
INT32 v;
v =(pli->nTileStart<<4)-nCpsrScrX;
v-=CpsrRows[(nCpsrRowStart+r)&0x3ff];
// clip to 10-bit signed
v+=0x200; v&=0x3ff; v-=0x200;
*pr=(INT16)v;
if (v<nMaxLeft) nMaxLeft=v;
else if (v>nMaxRight) nMaxRight=v;
}
else
{
*pr=0;
}
}
}
pli->nMaxLeft =nMaxLeft;
pli->nMaxRight=nMaxRight;
}
return 0;
}
// Prepare to draw Scroll 2 with rows, by seeing how much
// row scroll each tile line uses (pli->nStart/nWidth),
// and finding which tiles are visible onscreen (pli->nTileStart/End).
INT32 Cps1rPrepare()
{
INT32 y; struct CpsrLineInfo *pli;
if (CpsrBase==NULL) return 1;
nEndline = 224;
EndLineInfo = 14;
nShiftY=16-(nCpsrScrY&15);
for (y=-1,pli=CpsrLineInfo; y<EndLineInfo; y++,pli++)
{
INT32 nStart=0,nWidth=0;
if (CpsrRows!=NULL)
{
INT32 nRowFrom,nRowTo;
// Find out which rows we need to check
nRowFrom=(y<<4)+nShiftY;
nRowTo=nRowFrom+16;
if (nRowFrom<0) nRowFrom=0;
if (nRowTo>224) nRowTo=224;
// Shift by row table start offset
nRowFrom+=nCpsrRowStart;
nRowTo +=nCpsrRowStart;
// Find out what range of scroll values there are for this line
GetRowsRange(&nStart,&nWidth,nRowFrom,nRowTo);
}
nStart+=nCpsrScrX;
nStart&=0x3ff;
// Save info in CpsrLineInfo table
pli->nStart=nStart;
pli->nWidth=nWidth;
// Find range of tiles to draw to see whole width:
pli->nTileStart=nStart>>4;
pli->nTileEnd=(nStart+nWidth+0x18f)>>4;
}
PrepareRows();
return 0;
}
INT32 Cps2rPrepare()
{
INT32 y;
struct CpsrLineInfo *pli;
if (CpsrBase==NULL) return 1;
EndLineInfo = ((nEndline + 15) >> 4);
nShiftY=16-(nCpsrScrY&15);
for (y = -1, pli = CpsrLineInfo; y < EndLineInfo; y++, pli++)
{
INT32 nStart=0,nWidth=0;
if (CpsrRows!=NULL)
{
INT32 nRowFrom,nRowTo;
// Find out which rows we need to check
nRowFrom=(y<<4)+nShiftY;
nRowTo=nRowFrom+16;
if (nRowFrom < 0) nRowFrom = 0;
if (nRowTo > nEndline) nRowTo = nEndline;
// Shift by row table start offset
nRowFrom+=nCpsrRowStart;
nRowTo +=nCpsrRowStart;
// Find out what range of scroll values there are for this line
GetRowsRange(&nStart,&nWidth,nRowFrom,nRowTo);
}
nStart+=nCpsrScrX;
nStart&=0x3ff;
// Save info in CpsrLineInfo table
pli->nStart=nStart;
pli->nWidth=nWidth;
// Find range of tiles to draw to see whole width:
pli->nTileStart=nStart>>4;
pli->nTileEnd=(nStart+nWidth+0x18f)>>4;
}
PrepareRows();
return 0;
}

View File

@ -0,0 +1,235 @@
#include "cps.h"
// CPS Scroll2 with Row scroll - Draw
static INT32 nKnowBlank=-1; // The tile we know is blank
static INT32 nFirstY, nLastY;
static INT32 bVCare;
inline static UINT16 *FindTile(INT32 fx,INT32 fy)
{
INT32 p; UINT16 *pst;
// Find tile address
p=((fy&0x30)<<8) | ((fx&0x3f)<<6) | ((fy&0x0f)<<2);
pst=(UINT16 *)(CpsrBase + p);
return pst;
}
// Draw a tile line without Row Shift
static void Cps1TileLine(INT32 y,INT32 sx)
{
INT32 x,ix,iy,sy;
bVCare=0;
if (y<0 || y>=14-1) bVCare=1; // Take care on the edges
ix=(sx>>4)+1; sx&=15; sx=16-sx;
sy=16-(nCpsrScrY&15); iy=(nCpsrScrY>>4)+1;
nCpstY=sy+(y<<4);
for (x=-1; x<24; x++)
{
UINT16 *pst; INT32 t,a;
// Don't need to clip except around the border
if (bVCare || x<0 || x>=24-1) nCpstType=CTT_16X16 | CTT_CARE;
else nCpstType=CTT_16X16;
pst=FindTile(ix+x,iy+y);
t=pst[0];
if (Scroll2TileMask) t &= Scroll2TileMask;
t = GfxRomBankMapper(GFXTYPE_SCROLL2, t);
if (t == -1) continue;
t<<=7; // Get real tile address
t+=nCpsGfxScroll[2]; // add on offset to scroll tile
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a=pst[1];
CpstSetPal(0x40 | (a&0x1f));
nCpstX=sx+(x<<4); nCpstTile=t; nCpstFlip=(a>>5)&3;
if(nBgHi) CpstPmsk=*(UINT16 *)(CpsSaveReg[0] + MaskAddr[(a&0x180)>>7]);
if(CpstOneDoX[nBgHi]()) nKnowBlank=t;
}
}
static void Cps2TileLine(INT32 y,INT32 sx)
{
INT32 x,ix,iy,sy;
ix=(sx>>4)+1; sx&=15; sx=16-sx;
sy=16-(nCpsrScrY&15); iy=(nCpsrScrY>>4)+1;
nCpstY=sy+(y<<4);
for (x=-1; x<24; x++)
{
UINT16 *pst; INT32 t,a;
// Don't need to clip except around the border
if (bVCare || x<0 || x>=24-1) nCpstType=CTT_16X16 | CTT_CARE;
else nCpstType=CTT_16X16;
pst=FindTile(ix+x,iy+y);
t=pst[0];
t<<=7; // Get real tile address
t+=nCpsGfxScroll[2]; // add on offset to scroll tiles
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a=pst[1];
CpstSetPal(0x40 | (a&0x1f));
nCpstX=sx+(x<<4); nCpstTile=t; nCpstFlip=(a>>5)&3;
if(CpstOneDoX[2]()) nKnowBlank=t;
}
}
// Draw a tile line with Row Shift
static void Cps1TileLineRows(INT32 y,struct CpsrLineInfo *pli)
{
INT32 sy,iy,x;
INT32 nTileCount;
INT32 nLimLeft,nLimRight;
bVCare=0;
if (y<0 || y>=14-1) bVCare=1; // Take care on the edges
nTileCount=pli->nTileEnd-pli->nTileStart;
sy=16-(nCpsrScrY&15); iy=(nCpsrScrY>>4)+1;
nCpstY=sy+(y<<4);
CpstRowShift=pli->Rows;
// If these rowshift limits go off the edges, we should take
// care drawing the tile.
nLimLeft =pli->nMaxLeft;
nLimRight=pli->nMaxRight;
for (x=0; x<nTileCount; x++,
nLimLeft+=16, nLimRight+=16)
{
UINT16 *pst; INT32 t,a; INT32 tx; INT32 bCare;
tx=pli->nTileStart+x;
// See if we have to clip vertically anyway
bCare=bVCare;
if (bCare==0) // If we don't...
{
// Check screen limits of this tile
if (nLimLeft < 0) bCare=1; // Will cross left egde
if (nLimRight> 384-16) bCare=1; // Will cross right edge
}
if (bCare) nCpstType=CTT_16X16 | CTT_ROWS | CTT_CARE;
else nCpstType=CTT_16X16 | CTT_ROWS;
pst=FindTile(tx,iy+y);
t=pst[0];
if (Scroll2TileMask) t &= Scroll2TileMask;
t = GfxRomBankMapper(GFXTYPE_SCROLL2, t);
if (t == -1) continue;
t<<=7; // Get real tile address
t+=nCpsGfxScroll[2]; // add on offset to scroll tiles
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a=pst[1];
CpstSetPal(0x40 | (a&0x1f));
nCpstX=x<<4; nCpstTile=t; nCpstFlip=(a>>5)&3;
if (nBgHi) {
CpstPmsk = *(UINT16*)(CpsSaveReg[0] + MaskAddr[(a & 0x180) >> 7]);
}
if(CpstOneDoX[nBgHi]()) nKnowBlank=t;
}
}
static void Cps2TileLineRows(INT32 y,struct CpsrLineInfo *pli)
{
INT32 sy,iy,x;
INT32 nTileCount;
INT32 nLimLeft,nLimRight;
nTileCount=pli->nTileEnd-pli->nTileStart;
sy=16-(nCpsrScrY&15); iy=(nCpsrScrY>>4)+1;
nCpstY=sy+(y<<4);
CpstRowShift=pli->Rows;
// If these rowshift limits go off the edges, we should take
// care drawing the tile.
nLimLeft =pli->nMaxLeft;
nLimRight=pli->nMaxRight;
for (x=0; x<nTileCount; x++,
nLimLeft+=16, nLimRight+=16)
{
UINT16 *pst; INT32 t,a; INT32 tx; INT32 bCare;
tx=pli->nTileStart+x;
// See if we have to clip vertically anyway
bCare=bVCare;
if (bCare==0) // If we don't...
{
// Check screen limits of this tile
if (nLimLeft < 0) bCare=1; // Will cross left egde
if (nLimRight> 384-16) bCare=1; // Will cross right edge
}
if (bCare) nCpstType=CTT_16X16 | CTT_ROWS | CTT_CARE;
else nCpstType=CTT_16X16 | CTT_ROWS;
pst=FindTile(tx,iy+y);
t=pst[0];
t<<=7; // Get real tile address
t+=nCpsGfxScroll[2]; // add on offset to scroll tiles
if (t==nKnowBlank) continue; // Don't draw: we know it's blank
a=pst[1];
CpstSetPal(0x40 | (a&0x1f));
nCpstX=x<<4; nCpstTile=t; nCpstFlip=(a>>5)&3;
if(CpstOneDoX[2]()) nKnowBlank=t;
}
}
INT32 Cps1rRender()
{
INT32 y; struct CpsrLineInfo *pli;
if (CpsrBase==NULL) return 1;
nKnowBlank=-1; // We don't know which tile is blank yet
for (y=-1,pli=CpsrLineInfo; y<14; y++,pli++)
{
if (pli->nWidth==0)
Cps1TileLine(y,pli->nStart); // no rowscroll needed
else
Cps1TileLineRows(y,pli); // row scroll
}
return 0;
}
INT32 Cps2rRender()
{
INT32 y;
struct CpsrLineInfo *pli;
if (CpsrBase==NULL) return 1;
nKnowBlank = -1; // We don't know which tile is blank yet
nLastY = (nEndline + (nCpsrScrY & 15)) >> 4;
nFirstY = (nStartline + (nCpsrScrY & 15)) >> 4;
for (y = nFirstY - 1, pli = CpsrLineInfo + nFirstY; y < nLastY; y++, pli++) {
bVCare = ((y << 4) < nStartline) | (((y << 4) + 16) >= nEndline);
if (pli->nWidth==0) {
Cps2TileLine(y,pli->nStart); // no rowscroll needed
} else {
Cps2TileLineRows(y,pli); // row scroll
}
}
return 0;
}

View File

@ -0,0 +1,192 @@
#include "cps.h"
// CPS Tiles
UINT32 *CpstPal=NULL;
// Arguments for the tile draw function
UINT32 nCpstType = 0;
INT32 nCpstX = 0, nCpstY = 0;
UINT32 nCpstTile = 0;
INT32 nCpstFlip = 0;
INT16 *CpstRowShift = NULL;
UINT32 CpstPmsk = 0; // Pixel mask
INT32 nBgHi = 0;
UINT16 ZValue = 1;
UINT16* ZBuf = NULL;
UINT16* pZVal = NULL;
static INT32 CpstOne();
static INT32 Cps2tOne();
static INT32 CpstOneBgHi();
static INT32 CpstOneObjZ();
CpstOneDoFn CpstOneDoX[3] = { CpstOne, CpstOneBgHi, Cps2tOne};
CpstOneDoFn CpstOneObjDoX[2] = { CpstOne, CpstOneObjZ};
static INT32 CpstOne()
{
INT32 nFun; INT32 nSize;
nSize=(nCpstType&24)+8;
if (nCpstType&CTT_CARE)
{
if ((nCpstType&CTT_ROWS)==0)
{
// Return if not visible at all
if (nCpstX <= -nSize) return 0;
if (nCpstX >= 384) return 0;
if (nCpstY <= -nSize) return 0;
if (nCpstY >= 224) return 0;
}
nCtvRollX=0x4000017f + nCpstX * 0x7fff;
nCtvRollY=0x400000df + nCpstY * 0x7fff;
}
// Clip to loaded graphics data (we have a gap of 0x200 at the end)
nCpstTile&=nCpsGfxMask; if (nCpstTile>=nCpsGfxLen) return 1;
pCtvTile=CpsGfx+nCpstTile;
// Find pLine (pointer to first pixel)
pCtvLine=pBurnDraw + nCpstY*nBurnPitch + nCpstX*nBurnBpp;
if (nSize==32) nCtvTileAdd=16; else nCtvTileAdd=8;
if (nCpstFlip&2)
{
// Flip vertically
if (nSize==16) { nCtvTileAdd= -8; pCtvTile+=15* 8; }
else if (nSize==32) { nCtvTileAdd=-16; pCtvTile+=31*16; }
else { nCtvTileAdd= -8; pCtvTile+= 7* 8; }
}
nFun =nCpstType&0x1e;
nFun|=nCpstFlip&1;
return CtvDoX[nFun]();
}
static INT32 CpstOneBgHi()
{
INT32 nFun; INT32 nSize;
nSize=(nCpstType&24)+8;
if (nCpstType&CTT_CARE)
{
if ((nCpstType&CTT_ROWS)==0)
{
// Return if not visible at all
if (nCpstX<=-nSize) return 0;
if (nCpstX>=384) return 0;
if (nCpstY<=-nSize) return 0;
if (nCpstY>=224) return 0;
}
nCtvRollX=0x4000017f + nCpstX * 0x7fff;
nCtvRollY=0x400000df + nCpstY * 0x7fff;
}
// Clip to loaded graphics data (we have a gap of 0x200 at the end)
nCpstTile&=nCpsGfxMask;
if (nCpstTile>=nCpsGfxLen) return 1;
pCtvTile=CpsGfx+nCpstTile;
// Find pLine (pointer to first pixel)
pCtvLine=pBurnDraw + nCpstY*nBurnPitch + nCpstX*nBurnBpp;
if (nSize==32) nCtvTileAdd=16; else nCtvTileAdd=8;
if (nCpstFlip&2)
{
// Flip vertically
if (nSize==16) { nCtvTileAdd= -8; pCtvTile+=15* 8; }
else if (nSize==32) { nCtvTileAdd=-16; pCtvTile+=31*16; }
else { nCtvTileAdd= -8; pCtvTile+= 7* 8; }
}
nFun =nCpstType&0x1e;
nFun|=nCpstFlip&1;
return CtvDoXB[nFun]();
}
static INT32 Cps2tOne()
{
INT32 nFun; INT32 nSize;
nSize=(nCpstType&24)+8;
if (nCpstType&CTT_CARE)
{
if ((nCpstType&CTT_ROWS)==0)
{
// Return if not visible at all
if (nCpstX <= -nSize) return 0;
if (nCpstX >= 384) return 0;
if (nCpstY <= -nStartline - nSize) return 0;
if (nCpstY >= nEndline) return 0;
}
nCtvRollX=0x4000017f + nCpstX * 0x7fff;
nCtvRollY=0x40000000 + nEndline - nStartline - 1 + (nCpstY - nStartline) * 0x7fff;
}
// Clip to loaded graphics data (we have a gap of 0x200 at the end)
nCpstTile&=nCpsGfxMask; if (nCpstTile>=nCpsGfxLen) return 0;
pCtvTile=CpsGfx+nCpstTile;
// Find pLine (pointer to first pixel)
pCtvLine=pBurnDraw + nCpstY*nBurnPitch + nCpstX*nBurnBpp;
if (nSize==32) nCtvTileAdd=16; else nCtvTileAdd=8;
if (nCpstFlip&2)
{
// Flip vertically
if (nSize==16) { nCtvTileAdd= -8; pCtvTile+=15* 8; }
else if (nSize==32) { nCtvTileAdd=-16; pCtvTile+=31*16; }
else { nCtvTileAdd= -8; pCtvTile+= 7* 8; }
}
nFun =nCpstType&0x1e;
nFun|=nCpstFlip&1;
return CtvDoX[nFun]();
}
static INT32 CpstOneObjZ()
{
INT32 nFun; INT32 nSize;
nSize=(nCpstType&24)+8;
if (nCpstType&CTT_CARE)
{
if ((nCpstType&CTT_ROWS)==0)
{
// Return if not visible at all
if (nCpstX <= -nSize) return 0;
if (nCpstX >= 384) return 0;
if (nCpstY <= -nSize) return 0;
if (nCpstY >= 224) return 0;
}
nCtvRollX=0x4000017f + nCpstX * 0x7fff;
nCtvRollY=0x400000df + nCpstY * 0x7fff;
}
// Clip to loaded graphics data (we have a gap of 0x200 at the end)
nCpstTile&=nCpsGfxMask; if (nCpstTile>=nCpsGfxLen) return 1;
pCtvTile=CpsGfx+nCpstTile;
// Find pLine (pointer to first pixel)
pCtvLine=pBurnDraw + nCpstY*nBurnPitch + nCpstX*nBurnBpp;
pZVal=ZBuf + nCpstY*384 + nCpstX;
if (nSize==32) nCtvTileAdd=16; else nCtvTileAdd=8;
if (nCpstFlip&2)
{
// Flip vertically
if (nSize==16) { nCtvTileAdd= -8; pCtvTile+=15* 8; }
else if (nSize==32) { nCtvTileAdd=-16; pCtvTile+=31*16; }
else { nCtvTileAdd= -8; pCtvTile+= 7* 8; }
}
nFun =nCpstType&0x1e;
nFun|=nCpstFlip&1;
return CtvDoXM[nFun]();
}

View File

@ -0,0 +1,41 @@
#include "cps.h"
// CPS Tile Variants
// horizontal/vertical clip rolls
UINT32 nCtvRollX=0,nCtvRollY=0;
// Add 0x7fff after each pixel/line
// If nRollX/Y&0x20004000 both == 0, you can draw the pixel
UINT8 *pCtvTile=NULL; // Pointer to tile data
INT32 nCtvTileAdd=0; // Amount to add after each tile line
UINT8 *pCtvLine=NULL; // Pointer to output bitmap
// Include all tile variants:
#include "ctv.h"
static INT32 nLastBpp=0;
INT32 CtvReady()
{
// Set up the CtvDoX functions to point to the correct bpp functions.
// Must be called before calling CpstOne
if (nBurnBpp!=nLastBpp)
{
if (nBurnBpp==2) {
memcpy(CtvDoX,CtvDo2,sizeof(CtvDoX));
memcpy(CtvDoXM,CtvDo2m,sizeof(CtvDoXM));
memcpy(CtvDoXB,CtvDo2b,sizeof(CtvDoXB));
}
else if (nBurnBpp==3) {
memcpy(CtvDoX,CtvDo3,sizeof(CtvDoX));
memcpy(CtvDoXM,CtvDo3m,sizeof(CtvDoXM));
memcpy(CtvDoXB,CtvDo3b,sizeof(CtvDoXB));
}
else if (nBurnBpp==4) {
memcpy(CtvDoX,CtvDo4,sizeof(CtvDoX));
memcpy(CtvDoXM,CtvDo4m,sizeof(CtvDoXM));
memcpy(CtvDoXB,CtvDo4b,sizeof(CtvDoXB));
}
}
nLastBpp=nBurnBpp;
return 0;
}

View File

@ -0,0 +1,192 @@
// CPS Tiles (header)
// Draw a nxn tile
// pCtvLine, pTile, nTileAdd are defined
// CU_FLIPX is 1 to flip the tile horizontally
// CU_CARE is 1 to clip output based on nCtvRollX/Y
// CU_ROWS is 1 to shift output based on CpstRowShift
// CU_SIZE is 8, 16 or 32
// CU_BPP is 1 2 3 4 bytes per pixel
// CU_MASK CPS1 BgHi CPS2 Sprite Masking
#ifndef CU_FLIPX
#error "CU_FLIPX wasn\'t defined"
#endif
#ifndef CU_CARE
#error "CU_CARE wasn\'t defined"
#endif
#ifndef CU_ROWS
#error "CU_ROWS wasn\'t defined"
#endif
#ifndef CU_SIZE
#error "CU_SIZE wasn\'t defined"
#endif
#ifndef CU_BPP
#error "CU_BPP wasn\'t defined"
#endif
#ifndef CU_MASK
#error "CU_MASK wasn\'t defined"
#endif
{
INT32 y;
UINT32 *ctp;
UINT32 nBlank = 0;
UINT32 b; // Eight bit-packed pixels (msb) AAAABBBB CCCCDDDD EEEEFFFF GGGGHHHH (lsb)
UINT32 c; // 32-bit colour value
UINT8 *pPix; // Pointer to output bitmap
#if CU_ROWS == 1
INT16 *Rows = CpstRowShift;
#endif
ctp = CpstPal;
for (y = 0; y < CU_SIZE; y++, pCtvLine += nBurnPitch, pCtvTile += nCtvTileAdd
#if CU_ROWS==1
,Rows++
#endif
#if CU_MASK==1
,pZVal += 384
#endif
)
{
#if CU_CARE==1
UINT32 rx = nCtvRollX; // Copy of nCtvRollX
#endif
#if CU_MASK==1
UINT16 *pPixZ;
#endif
#if CU_CARE==1
if (nCtvRollY & 0x20004000) { nCtvRollY += 0x7fff; continue; } else nCtvRollY += 0x7fff; // okay to plot line
#endif
// Point to the line to draw
pPix = pCtvLine;
#if CU_MASK==1
pPixZ = pZVal;
#endif
#if CU_ROWS==1
#if CU_MASK==1
pPixZ += Rows[0];
#endif
pPix += Rows[0] * nBurnBpp;
#if CU_CARE==1
rx += Rows[0] * 0x7fff;
#endif
#endif
// Make macros for plotting c and advancing pPix by one pixel
#if CU_BPP==2
#if CU_MASK==1
#define PLOT { if(*pPixZ < ZValue) { *((UINT16 *)pPix)=(UINT16)c; *pPixZ=ZValue; } }
#define ADV { pPix+=2; pPixZ++; }
#else
#define PLOT { *((UINT16 *)pPix)=(UINT16)c; }
#define ADV pPix+=2
#endif
#elif CU_BPP==3
#if CU_MASK==1
#define PLOT { if(*pPixZ < ZValue) { pPix[0]=(UINT8)c; pPix[1]=(UINT8)(c>>8); pPix[2]=(UINT8)(c>>16); } }
#define ADV { pPix+=3; pPixZ++; }
#else
#define PLOT { pPix[0]=(UINT8)c; pPix[1]=(UINT8)(c>>8); pPix[2]=(UINT8)(c>>16); }
#define ADV pPix+=3
#endif
#elif CU_BPP==4
#if CU_MASK==1
#define PLOT { if(*pPixZ < ZValue) { *((UINT32 *)pPix)=c; *pPixZ=ZValue; } }
#define ADV { pPix+=4; pPixZ++; }
#else
#define PLOT { *((UINT32 *)pPix)=c; }
#define ADV pPix+=4
#endif
#else
#error Unsupported CU_BPP
#endif
// Make macros for plotting the next pixel from 'b' (= 8 packed pixels)
// or skipping the pixel.
#if CU_FLIPX==0
#define NEXTPIXEL ADV; b <<= 4;
#if CU_MASK==2
#define DRAWPIXEL { c = (b >> 28); if (c && CpstPmsk & (1 << (c ^ 15))) { c = ctp[c]; PLOT } }
#else
#define DRAWPIXEL { if (b & 0xf0000000) { c = ctp[b >> 28]; PLOT } }
#endif
#else
#define NEXTPIXEL ADV; b >>= 4;
#if CU_MASK==2
#define DRAWPIXEL { c = (b & 15); if (c && CpstPmsk & (1 << (c ^ 15))) { c = ctp[c]; PLOT } }
#else
#define DRAWPIXEL { if (b & 0x0000000f) { c = ctp[b & 15]; PLOT } }
#endif
#endif
#define EIGHT(x) x x x x x x x x
#if CU_CARE==1
// If we need to clip left or right, check nCtvRollX before plotting
#define DO_PIX if ((rx & 0x20004000) == 0) DRAWPIXEL NEXTPIXEL rx += 0x7fff;
#else
// Always plot
#define DO_PIX DRAWPIXEL NEXTPIXEL
#endif
#define DRAW_8 nBlank |= b; EIGHT(DO_PIX)
#if CU_SIZE==8
// 8x8 tiles
b=*((UINT32 *)(pCtvTile+0)); DRAW_8
#elif CU_SIZE==16
// 16x16 tiles
#if CU_FLIPX==0
b=*((UINT32 *)(pCtvTile+0)); DRAW_8
b=*((UINT32 *)(pCtvTile+4)); DRAW_8
#else
b=*((UINT32 *)(pCtvTile+4)); DRAW_8
b=*((UINT32 *)(pCtvTile+0)); DRAW_8
#endif
#elif CU_SIZE==32
// 32x32 tiles
#if CU_FLIPX==0
b=*((UINT32 *)(pCtvTile+ 0)); DRAW_8
b=*((UINT32 *)(pCtvTile+ 4)); DRAW_8
b=*((UINT32 *)(pCtvTile+ 8)); DRAW_8
b=*((UINT32 *)(pCtvTile+12)); DRAW_8
#else
b=*((UINT32 *)(pCtvTile+12)); DRAW_8
b=*((UINT32 *)(pCtvTile+ 8)); DRAW_8
b=*((UINT32 *)(pCtvTile+ 4)); DRAW_8
b=*((UINT32 *)(pCtvTile+ 0)); DRAW_8
#endif
#else
#error Unsupported CU_SIZE
#endif
#undef DRAW_8
#undef DO_PIX
#undef EIGHT
#undef DRAWPIXEL
#undef NEXTPIXEL
#undef ADV
#undef PLOT
}
return nBlank == 0;
}

View File

@ -0,0 +1,125 @@
#include <stdio.h>
// Create the ctv.h header file
// which includes all combinations of the cps tile drawing functions
int main()
{
int nCuMask=0;
int nCuBpp=0;
int nCuSize=0;
int nCuRows=0;
int nCuCare=0;
int nCuFlipX=0;
for (nCuMask=0; nCuMask<=2; nCuMask++)
{
printf ("#define CU_MASK (%d)\n\n",nCuMask);
for (nCuBpp=2; nCuBpp<=4; nCuBpp++)
{
printf ("#define CU_BPP (%d)\n\n",nCuBpp);
for (nCuSize=8; nCuSize<=32; nCuSize<<=1)
{
printf ("#define CU_SIZE (%d)\n\n",nCuSize);
for (nCuRows=0; nCuRows<2; nCuRows++)
{
printf ("#define CU_ROWS (%d)\n\n",nCuRows);
for (nCuCare=0; nCuCare<2; nCuCare++)
{
printf ("#define CU_CARE (%d)\n",nCuCare);
for (nCuFlipX=0; nCuFlipX<2; nCuFlipX++)
{
printf ("#define CU_FLIPX (%d)\n",nCuFlipX);
if ((nCuRows && (nCuSize != 16) || (nCuRows && nCuMask))) {
printf("// Invalid combination of capabilities.\n");
} else {
printf ("static INT32 ");
printf ("CtvDo");
printf ("%d",nCuBpp);
printf ("%.2d",nCuSize);
if (nCuRows) printf ("r"); else printf ("_");
if (nCuCare) printf ("c"); else printf ("_");
if (nCuFlipX) printf ("f"); else printf ("_");
if (nCuMask==1) printf ("m()\n#include \"ctv_do.h\"\n");
else if (nCuMask==2) printf ("b()\n#include \"ctv_do.h\"\n");
else printf ("_()\n#include \"ctv_do.h\"\n");
}
printf ("#undef CU_FLIPX\n");
}
printf ("#undef CU_CARE\n\n");
}
printf ("#undef CU_ROWS\n\n");
}
printf ("#undef CU_SIZE\n\n");
}
printf ("#undef CU_BPP\n\n");
}
printf ("#undef CU_MASK\n\n");
}
printf ("\n\n");
printf ("// Filler function\n");
printf ("static INT32 CtvDo_______() { return 0; }\n\n\n\n");
for (nCuMask=0; nCuMask<=2; nCuMask++)
{
for (nCuBpp=2; nCuBpp<=4; nCuBpp++)
{
int i=0;
if (nCuMask==1)
{
printf ("// Lookup table for %d bpp with Sprite Masking\n",nCuBpp);
printf ("static CtvDoFn CtvDo%dm[0x20]={\n",nCuBpp);
}
else if (nCuMask==2)
{
printf ("// Lookup table for %d bpp with BgHi\n",nCuBpp);
printf ("static CtvDoFn CtvDo%db[0x20]={\n",nCuBpp);
}
else
{
printf ("// Lookup table for %d bpp\n",nCuBpp);
printf ("static CtvDoFn CtvDo%d[0x20]={\n",nCuBpp);
}
for (i=0;i<0x20;i++)
{
int s;
printf ("CtvDo");
s=(i&24)+8;
if (s!=8 && s!=16 && s!=32) { printf ("_______"); goto End; }
if ((i&4) && (s!=16)) { printf ("_______"); goto End; }
if ((i&4) && nCuMask) { printf ("_______"); goto End; }
printf ("%d",nCuBpp);
printf ("%.2d",s);
if (i&4) printf ("r"); else printf ("_");
if (i&2) printf ("c"); else printf ("_");
if (i&1) printf ("f"); else printf ("_");
if (nCuMask==1) printf ("m");
else if (nCuMask==2) printf ("b");
else printf ("_");
End:
printf (",");
if (((i+1)&3)==0) printf("\n");
}
printf ("};\n");
}
}
printf ("\n\n");
printf ("// Current BPP:\n");
printf ("CtvDoFn CtvDoX[0x20];\n");
printf ("CtvDoFn CtvDoXM[0x20];\n");
printf ("CtvDoFn CtvDoXB[0x20];\n");
printf ("\n\n");
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
// This file is based on the MAME source code (see http://www.mame.net/)
/***************************************************************************
"Kabuki" Z80 encryption
The "Kabuki" is a custom Z80 module which runs encrypted code. The encryption
key is stored in some battery-backed RAM, therefore the chip has the annoying
habit of stopping working every few years, when the battery dies.
Check at the bottom of this text to see a list of all the known games which
use this chip.
How it works:
The base operation is a bit swap which affects couples of adjacent bits.
Each of the 4 couples may or may not be swapped, depending on the address of
the byte and on whether it is an opcode or data.
The decryption consists of these steps:
- bitswap
- ROL
- bitswap
- XOR with a key
- ROL
- bitswap
- ROL
- bitswap
To know how to apply the bit swap, take the address of the byte to decode and:
- if the byte is an opcode, add addr_key to the address
- if the byte is data, XOR the address with 1FC0, add 1, and then add addr_key
You'll get a 16-bit word. The first two bitswaps depend on bits 0-7 of that
word, while the second two on bits 8-15. When a bit in the word is 1, swap the
two bits, oherwise don't. The exact couple of bits affected depends on the
game and is identified in this file with two keys: swap_key1 and swap_key2
(which are just permutations of the numbers 0-7, not full 32-bit integers).
Key space size:
- swap_key1 8! = 40320
- swap_key2 8! = 40320
- addr_key 2^16 = 65536
- xor_key 2^8 = 256
- total 2.7274 * 10^16
Weaknesses:
- 0x00 and 0xff, having all the bits set to the same value, are not affected
by bit permutations after the XOR. Therefore, their encryption is the same
regardless of the high 8 bits of the address, and of the value of
swap_key2. If there is a long stream of 0x00 or 0xff in the original data,
this can be used to find by brute force all the candidates for swap_key1,
xor_key, and for the low 8 bits of addr_key. This is a serious weakness
which dramatically reduces the security of the encryption.
- A 0x00 is always encrypted as a byte with as many 1s as xor_key; a 0xff is
always encrypted as a byte with as many 0s as xor_key has 1s. So you just
need to know one 0x00 or 0xff in the unencrypted data to know how many 1s
there are in xor_key.
- Once you have restricted the range for swap_key1 and you know the number of
1s in the xor_key, you can easily use known plaintext attacks and brute
force to find the remaining keys. Long strings like THIS GAME IS FOR USE IN
and ABCDEFGHIJKLMNOPQRSTUVWXYZ can be found by comparing the number of 1s
in the clear and encrypted data, taking xor_key into account. When you have
found where the string is, use brute force to reduce the key space.
Known games:
swap_key1 swap_key2 addr_key xor_key
Mahjong Gakuen 2 Gakuen-chou no Fukushuu 76543210 01234567 aa55 a5
Poker Ladies " " " " "" ""
Dokaben " " " " "" ""
Dokaben 2 unknown
Pang / Buster Bros / Pomping World 01234567 76543210 6548 24
Capcom Baseball " " " " "" ""
Capcom World 04152637 40516273 5751 43
Adventure Quiz 2 Hatena ? no Dai-Bouken 45670123 45670123 5751 43
Super Pang 45670123 45670123 5852 43
Super Buster Bros 45670123 45670123 2130 12
Super Marukin-Ban 54321076 54321076 4854 4f
Quiz Tonosama no Yabou 12345670 12345670 1111 11
Ashita Tenki ni Naare unknown
Quiz Sangokushi 23456701 23456701 1828 18
Block Block 02461357 64207531 0002 01
Warriors of Fate 01234567 54163072 5151 51
Cadillacs and Dinosaurs 76543210 24601357 4343 43
Punisher 67452103 75316024 2222 22
Slam Masters 54321076 65432107 3131 19
***************************************************************************/
// #include "driver.h"
#include "cps.h"
static INT32 bitswap1(INT32 src,INT32 key,INT32 select)
{
if (select & (1 << ((key >> 0) & 7)))
src = (src & 0xfc) | ((src & 0x01) << 1) | ((src & 0x02) >> 1);
if (select & (1 << ((key >> 4) & 7)))
src = (src & 0xf3) | ((src & 0x04) << 1) | ((src & 0x08) >> 1);
if (select & (1 << ((key >> 8) & 7)))
src = (src & 0xcf) | ((src & 0x10) << 1) | ((src & 0x20) >> 1);
if (select & (1 << ((key >>12) & 7)))
src = (src & 0x3f) | ((src & 0x40) << 1) | ((src & 0x80) >> 1);
return src;
}
static INT32 bitswap2(INT32 src,INT32 key,INT32 select)
{
if (select & (1 << ((key >>12) & 7)))
src = (src & 0xfc) | ((src & 0x01) << 1) | ((src & 0x02) >> 1);
if (select & (1 << ((key >> 8) & 7)))
src = (src & 0xf3) | ((src & 0x04) << 1) | ((src & 0x08) >> 1);
if (select & (1 << ((key >> 4) & 7)))
src = (src & 0xcf) | ((src & 0x10) << 1) | ((src & 0x20) >> 1);
if (select & (1 << ((key >> 0) & 7)))
src = (src & 0x3f) | ((src & 0x40) << 1) | ((src & 0x80) >> 1);
return src;
}
static INT32 bytedecode(INT32 src,INT32 swap_key1,INT32 swap_key2,INT32 xor_key,INT32 select)
{
src = bitswap1(src,swap_key1 & 0xffff,select & 0xff);
src = ((src & 0x7f) << 1) | ((src & 0x80) >> 7);
src = bitswap2(src,swap_key1 >> 16,select & 0xff);
src ^= xor_key;
src = ((src & 0x7f) << 1) | ((src & 0x80) >> 7);
src = bitswap2(src,swap_key2 & 0xffff,select >> 8);
src = ((src & 0x7f) << 1) | ((src & 0x80) >> 7);
src = bitswap1(src,swap_key2 >> 16,select >> 8);
return src;
}
void kabuki_decode(UINT8 *src,UINT8 *dest_op,UINT8 *dest_data,
INT32 base_addr,INT32 length,INT32 swap_key1,INT32 swap_key2,INT32 addr_key,INT32 xor_key)
{
INT32 A;
INT32 select;
for (A = 0;A < length;A++)
{
/* decode opcodes */
select = (A + base_addr) + addr_key;
dest_op[A] = (UINT8)bytedecode(src[A],swap_key1,swap_key2,xor_key,select);
/* decode data */
select = ((A + base_addr) ^ 0x1fc0) + addr_key + 1;
dest_data[A] = (UINT8)bytedecode(src[A],swap_key1,swap_key2,xor_key,select);
}
}
static void cps1_decode(INT32 swap_key1,INT32 swap_key2,INT32 addr_key,INT32 xor_key)
{
UINT8 *rom = CpsZRom;
INT32 diff = nCpsZRomLen / 2;
CpsZRom=rom+diff;
kabuki_decode(rom,rom+diff,rom,0x0000,0x8000, swap_key1,swap_key2,addr_key,xor_key);
}
void wof_decode(void) { cps1_decode(0x01234567,0x54163072,0x5151,0x51); }
void dino_decode(void) { cps1_decode(0x76543210,0x24601357,0x4343,0x43); }
void punisher_decode(void) { cps1_decode(0x67452103,0x75316024,0x2222,0x22); }
void slammast_decode(void) { cps1_decode(0x54321076,0x65432107,0x3131,0x19); }

View File

@ -0,0 +1,86 @@
// PSound (CPS1 sound)
#include "cps.h"
#include "driver.h"
extern "C" {
#include "ym2151.h"
}
UINT8 PsndCode, PsndFade; // Sound code/fade sent to the z80 program
static INT32 nSyncPeriod;
static INT32 nSyncNext;
static INT32 nCyclesDone;
static void drvYM2151IRQHandler(INT32 nStatus)
{
if (nStatus) {
ZetSetIRQLine(0xFF, ZET_IRQSTATUS_ACK);
ZetRun(0x0800);
} else {
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
}
}
INT32 PsndInit()
{
nCpsZ80Cycles = 4000000 * 100 / nBurnFPS;
nSyncPeriod = nCpsZ80Cycles / 32;
// Init PSound z80
if (PsndZInit()!= 0) {
return 1;
}
// Init PSound mixing (not critical if it fails)
PsmInit();
YM2151SetIrqHandler(0, &drvYM2151IRQHandler);
PsndCode = 0; PsndFade = 0;
nCyclesDone = 0;
return 0;
}
INT32 PsndExit()
{
PsmExit();
PsndZExit();
return 0;
}
INT32 PsndScan(INT32 nAction)
{
if (nAction & ACB_DRIVER_DATA) {
SCAN_VAR(nCyclesDone); SCAN_VAR(nSyncNext);
PsndZScan(nAction); // Scan Z80
SCAN_VAR(PsndCode); SCAN_VAR(PsndFade); // Scan sound info
}
return 0;
}
void PsndNewFrame()
{
ZetNewFrame();
PsmNewFrame();
nSyncNext = nSyncPeriod;
ZetIdle(nCyclesDone % nCpsZ80Cycles);
nCyclesDone = 0;
}
INT32 PsndSyncZ80(INT32 nCycles)
{
while (nSyncNext < nCycles) {
PsmUpdate(nSyncNext * nBurnSoundLen / nCpsZ80Cycles);
ZetRun(nSyncNext - ZetTotalCycles());
nSyncNext += nSyncPeriod;
}
nCyclesDone = ZetRun(nCycles - ZetTotalCycles());
return 0;
}

View File

@ -0,0 +1,94 @@
#include "cps.h"
#include "burn_ym2151.h"
// CPS1 sound Mixing
INT32 bPsmOkay = 0; // 1 if the module is okay
static INT16* WaveBuf = NULL;
static INT32 nPos;
INT32 PsmInit()
{
INT32 nMemLen, nRate, nRet;
bPsmOkay = 0; // not OK yet
if (nBurnSoundRate > 0) {
nRate = nBurnSoundRate;
} else {
nRate = 11025;
}
if (BurnYM2151Init(3579540, 50.0)) { // Init FM sound chip
return 1;
}
// Allocate a buffer for the intermediate sound (between YM2151 and pBurnSoundOut)
nMemLen = nBurnSoundLen * 2 * sizeof(INT16);
WaveBuf = (INT16*)malloc(nMemLen);
if (WaveBuf == NULL) {
PsmExit();
return 1;
}
memset(WaveBuf, 0, nMemLen); // Init to silence
// Init ADPCM
MSM6295ROM = CpsAd;
if (Forgottn) {
nRet = MSM6295Init(0, 6061, 21.5, 1);
} else {
nRet = MSM6295Init(0, 7576, 21.5, 1);
}
if (nRet!=0) {
PsmExit(); return 1;
}
bPsmOkay = 1; // OK
return 0;
}
INT32 PsmExit()
{
bPsmOkay = 0;
MSM6295Exit(0);
if (WaveBuf) {
free(WaveBuf);
WaveBuf = NULL;
}
BurnYM2151Exit(); // Exit FM sound chip
return 0;
}
void PsmNewFrame()
{
nPos = 0;
}
INT32 PsmUpdate(INT32 nEnd)
{
if (bPsmOkay == 0 || pBurnSoundOut == NULL) {
return 1;
}
if (nEnd <= nPos) {
return 0;
}
if (nEnd > nBurnSoundLen) {
nEnd = nBurnSoundLen;
}
// Render FM
BurnYM2151Render(pBurnSoundOut + (nPos << 1), nEnd - nPos);
// Render ADPCM
MSM6295Render(0, pBurnSoundOut + (nPos << 1), nEnd - nPos);
nPos = nEnd;
return 0;
}

View File

@ -0,0 +1,208 @@
#include "cps.h"
#include "burn_ym2151.h"
// PSound - Z80
static INT32 nPsndZBank = 0;
static UINT8 *PsndZRam = NULL;
INT32 Kodb = 0;
// Map in the memory for the current 0x8000-0xc000 bank
static INT32 PsndZBankMap()
{
UINT8 *Bank;
UINT32 nOff = (nPsndZBank << 14) + 0x8000;
if (nOff + 0x4000 > nCpsZRomLen) { // End of bank in out of range
nOff = 0;
}
Bank = CpsZRom + nOff;
// Read and fetch the bank
ZetMapArea(0x8000, 0xBFFF, 0, Bank);
ZetMapArea(0x8000, 0xBFFF, 2, Bank);
return 0;
}
// PSound Z80 memory write
void __fastcall PsndZWrite(UINT16 a, UINT8 d)
{
switch (a) {
case 0xF000:
BurnYM2151SelectRegister(d);
// bprintf(PRINT_NORMAL, "YM2151 select -> %02X\n", d);
break;
case 0xF001:
BurnYM2151WriteRegister(d);
// bprintf(PRINT_NORMAL, "YM2151 write -> %02X\n", d);
break;
case 0xF002:
MSM6295Command(0, d);
break;
case 0xF004: {
INT32 nNewBank = d & 0x0f;
if (nPsndZBank != nNewBank) {
nPsndZBank = nNewBank;
PsndZBankMap();
}
break;
}
case 0xF006: // ??? Enable interrupt ???
break;
#ifdef FBA_DEBUG
// default:
// bprintf(PRINT_NORMAL, _T("Z80 address %04X -> %02X.\n"), a, d);
#endif
}
return;
}
void __fastcall kodbZWrite(UINT16 a, UINT8 d)
{
switch (a) {
case 0xE000:
BurnYM2151SelectRegister(d);
break;
case 0xE001:
BurnYM2151WriteRegister(d);
break;
case 0xE400:
MSM6295Command(0, d);
break;
#ifdef FBA_DEBUG
// default:
// bprintf(PRINT_NORMAL, _T("Z80 address %04X -> %02X.\n"), a, d);
#endif
}
return;
}
// PSound Z80 memory read
UINT8 __fastcall PsndZRead(UINT16 a)
{
switch (a) {
case 0xF001:
return BurnYM2151ReadStatus();
case 0xF002:
return MSM6295ReadStatus(0);
case 0xF008:
// bprintf(PRINT_NORMAL, " -- Sound latch read (%i).\n", PsndCode);
return PsndCode;
case 0xF00A:
return PsndFade;
#ifdef FBA_DEBUG
// default:
// bprintf(PRINT_NORMAL, _T("Z80 address %04X read.\n"), a);
#endif
}
return 0;
}
UINT8 __fastcall kodbZRead(UINT16 a)
{
switch (a) {
case 0xE001:
return BurnYM2151ReadStatus();
case 0xE400:
return MSM6295ReadStatus(0);
case 0xE800:
return PsndCode;
#ifdef FBA_DEBUG
// default:
// bprintf(PRINT_NORMAL, _T("Z80 address %04X read.\n"), a);
#endif
}
return 0;
}
INT32 PsndZInit()
{
if (nCpsZRomLen < 0x8000) { // Not enough Z80 Data
return 1;
}
if (CpsZRom == NULL) {
return 1;
}
PsndZRam = (UINT8 *)malloc(0x800);
if (PsndZRam == NULL) {
return 1;
}
ZetInit(1);
if (Kodb) {
ZetSetReadHandler(kodbZRead);
ZetSetWriteHandler(kodbZWrite);
} else {
ZetSetReadHandler(PsndZRead);
ZetSetWriteHandler(PsndZWrite);
}
// Read and fetch first 0x8000 of Rom
ZetMapArea(0x0000,0x7fff,0,CpsZRom);
ZetMapArea(0x0000,0x7fff,2,CpsZRom);
// Map first Bank of Rom to 0x8000-0xc000
nPsndZBank=0;
PsndZBankMap();
// Ram
ZetMapArea(0xd000,0xd7ff,0,PsndZRam);
ZetMapArea(0xd000,0xd7ff,1,PsndZRam);
ZetMapArea(0xd000,0xd7ff,2,PsndZRam);
// Sound chip interfaces
ZetMemCallback(0xf000,0xffff,0);
ZetMemCallback(0xf000,0xffff,1);
// In case it tries to fetch other areas
ZetMapArea(0xc000,0xcfff,2,CpsZRom);
ZetMapArea(0xd800,0xffff,2,CpsZRom);
ZetMemEnd();
ZetClose();
return 0;
}
INT32 PsndZExit()
{
if (PsndZRam) {
free(PsndZRam);
PsndZRam = NULL;
}
ZetExit();
return 0;
}
// Scan the current PSound z80 state
INT32 PsndZScan(INT32 nAction)
{
struct BurnArea ba;
ZetScan(nAction);
MSM6295Scan(0, nAction);
BurnYM2151Scan(nAction);
SCAN_VAR(nPsndZBank);
// Scan Ram
memset(&ba, 0, sizeof(ba));
ba.szName = "Z80 RAM";
ba.Data = PsndZRam;
ba.nLen = 0x800;
BurnAcb(&ba);
return 0;
}

View File

@ -0,0 +1,128 @@
#include "cps.h"
// QSound
static INT32 nQsndCyclesExtra;
static INT32 qsndTimerOver(INT32, INT32)
{
// bprintf(PRINT_NORMAL, _T(" - IRQ -> 1.\n"));
ZetSetIRQLine(0xFF, ZET_IRQSTATUS_AUTO);
return 0;
}
INT32 QsndInit()
{
INT32 nVolumeShift;
INT32 nRate;
// Init QSound z80
if (QsndZInit()) {
return 1;
}
BurnTimerInit(qsndTimerOver, NULL);
if (Cps1Qs == 1) {
nCpsZ80Cycles = 6000000 * 100 / nBurnFPS;
BurnTimerAttachZet(6000000);
} else {
nCpsZ80Cycles = 8000000 * 100 / nBurnFPS;
BurnTimerAttachZet(8000000);
}
if (nBurnSoundRate >= 0) {
nRate = nBurnSoundRate;
} else {
nRate = 11025;
}
nVolumeShift = 0;
// These games are too soft at normal volumes
if (strncmp(BurnDrvGetTextA(DRV_NAME), "csclub", 6) == 0) {
nVolumeShift = -1;
}
#if 0
// These games are loud at normal volumes (no clipping)
if (strncmp(BurnDrvGetTextA(DRV_NAME), "1944", 4) == 0 ||
strcmp( BurnDrvGetTextA(DRV_NAME), "dimahoo" ) == 0 ||
strcmp( BurnDrvGetTextA(DRV_NAME), "gmahoo" ) == 0)
{
nVolumeShift = 1;
}
#endif
// These games are too loud at normal volumes (no clipping)
if (strncmp(BurnDrvGetTextA(DRV_NAME), "sgemf", 5) == 0 ||
strncmp(BurnDrvGetTextA(DRV_NAME), "pfght", 5) == 0 ||
strncmp(BurnDrvGetTextA(DRV_NAME), "mpang", 5) == 0 ||
strncmp(BurnDrvGetTextA(DRV_NAME), "spf2", 4) == 0 ||
strncmp(BurnDrvGetTextA(DRV_NAME), "sfa2", 4) == 0 ||
strncmp(BurnDrvGetTextA(DRV_NAME), "sfa2", 4) == 0)
{
nVolumeShift = 1;
}
// These games are too loud at normal volumes (clipping)
if (strncmp(BurnDrvGetTextA(DRV_NAME), "19xx", 4) == 0 ||
strncmp(BurnDrvGetTextA(DRV_NAME), "ddtod", 5) == 0)
{
nVolumeShift = 2;
}
QscInit(nRate, nVolumeShift); // Init QSound chip
return 0;
}
void QsndReset()
{
BurnTimerReset();
BurnTimerSetRetrig(0, 1.0 / 252.0);
nQsndCyclesExtra = 0;
}
void QsndExit()
{
QscExit(); // Exit QSound chip
QsndZExit();
}
INT32 QsndScan(INT32 nAction)
{
if (nAction & ACB_DRIVER_DATA) {
QsndZScan(nAction); // Scan Z80
QscScan(nAction); // Scan QSound Chip
}
return 0;
}
void QsndNewFrame()
{
ZetNewFrame();
ZetOpen(0);
ZetIdle(nQsndCyclesExtra);
QscNewFrame();
}
void QsndEndFrame()
{
BurnTimerEndFrame(nCpsZ80Cycles);
if (pBurnSoundOut) QscUpdate(nBurnSoundLen);
nQsndCyclesExtra = ZetTotalCycles() - nCpsZ80Cycles;
ZetClose();
}
void QsndSyncZ80()
{
int nCycles = (INT64)SekTotalCycles() * nCpsZ80Cycles / nCpsCycles;
if (nCycles <= ZetTotalCycles()) {
return;
}
BurnTimerUpdate(nCycles);
}

View File

@ -0,0 +1,454 @@
// QSound - emulator for the QSound Chip
#include <math.h>
#include "cps.h"
#include "burn_sound.h"
static const INT32 nQscClock = 4000000;
static const INT32 nQscClockDivider = 166;
static INT32 nQscRate = 0;
static INT32 nQscVolumeShift;
static INT32 Tams = -1;
static INT32* Qs_s = NULL;
static INT32 nPos;
struct QChan {
UINT8 bKey; // 1 if channel is playing
INT8 nBank; // Bank we are currently playing a sample from
INT8* PlayBank; // Pointer to current bank
INT32 nPlayStart; // Start of being played
INT32 nStart; // Start of sample 16.12
INT32 nEnd; // End of sample 16.12
INT32 nLoop; // Loop offset from end
INT32 nPos; // Current position within the bank 16.12
INT32 nAdvance; // Sample size
INT32 nMasterVolume; // Master volume for the channel
INT32 nVolume[2]; // Left & right side volumes (panning)
INT32 nPitch; // Playback frequency
INT8 nEndBuffer[8]; // Buffer to enable correct cubic interpolation
};
static struct QChan QChan[16];
static INT32 PanningVolumes[33];
static void MapBank(struct QChan* pc)
{
UINT32 nBank;
nBank = (pc->nBank & 0x7F) << 16; // Banks are 0x10000 samples long
// Confirm whole bank is in range:
// If bank is out of range use bank 0 instead
if ((nBank + 0x10000) > nCpsQSamLen) {
nBank = 0;
}
pc->PlayBank = (INT8*)CpsQSam + nBank;
}
static void UpdateEndBuffer(struct QChan* pc)
{
if (pc->bKey) {
// prepare a buffer to correctly interpolate the last 4 samples
if (nInterpolation >= 3) {
for (INT32 i = 0; i < 4; i++) {
pc->nEndBuffer[i] = pc->PlayBank[(pc->nEnd >> 12) - 4 + i];
}
if (pc->nLoop) {
for (INT32 i = 0, j = 0; i < 4; i++, j++) {
if (j >= (pc->nLoop >> 12)) {
j = 0;
}
pc->nEndBuffer[i + 4] = pc->PlayBank[((pc->nEnd - pc->nLoop) >> 12) + j];
}
} else {
for (INT32 i = 0; i < 4; i++) {
pc->nEndBuffer[i + 4] = pc->nEndBuffer[3];
}
}
}
}
}
static void CalcAdvance(struct QChan* pc)
{
if (nQscRate) {
pc->nAdvance = (INT64)pc->nPitch * nQscClock / nQscClockDivider / nQscRate;
}
}
void QscReset()
{
memset(QChan, 0, sizeof(QChan));
// Point all to bank 0
for (INT32 i = 0; i < 16; i++) {
QChan[i].PlayBank = (INT8*)CpsQSam;
}
}
void QscExit()
{
nQscRate = 0;
if (Qs_s) {
free(Qs_s);
Qs_s = NULL;
}
Tams = -1;
}
INT32 QscInit(INT32 nRate, INT32 nVolumeShift)
{
nQscRate = nRate;
nQscVolumeShift = 10 + nVolumeShift;
for (INT32 i = 0; i < 33; i++) {
PanningVolumes[i] = (INT32)((256.0 / sqrt(32.0)) * sqrt((double)i));
}
QscReset();
return 0;
}
INT32 QscScan(INT32 nAction)
{
SCAN_VAR(QChan);
if (nAction & ACB_WRITE) {
// Update bank pointers with new banks, and recalc nAdvance
for (INT32 i = 0; i < 16; i++) {
MapBank(QChan + i);
CalcAdvance(QChan + i);
}
}
return 0;
}
void QscNewFrame()
{
nPos = 0;
}
static inline void QscSyncQsnd()
{
if (pBurnSoundOut) QscUpdate(ZetTotalCycles() * nBurnSoundLen / nCpsZ80Cycles);
}
void QscWrite(INT32 a, INT32 d)
{
struct QChan* pc;
INT32 nChanNum, r;
// unknown
if (a >= 0x90) {
// bprintf(PRINT_NORMAL, "QSound: reg 0x%02X -> 0x%02X.\n", a, d);
return;
}
QscSyncQsnd();
if (a >= 0x80) { // Set panning for channel
INT32 nPan;
nChanNum = a & 15;
pc = QChan + nChanNum; // Find channel
nPan = (d - 0x10) & 0x3F; // nPan = 0x00 to 0x20 now
if (nPan > 0x20) {
nPan = 0x20;
}
// bprintf(PRINT_NORMAL, "QSound: ch#%i pan -> 0x%04X\n", nChanNum, d);
pc->nVolume[0] = PanningVolumes[0x20 - nPan];
pc->nVolume[1] = PanningVolumes[0x00 + nPan];
return;
}
// Get channel and register number
nChanNum = (a >> 3) & 15;
r = a & 7;
// Pointer to channel info
pc = QChan + nChanNum;
switch (r) {
case 0: { // Set bank
// Strange but true
pc = QChan + ((nChanNum + 1) & 15);
pc->nBank = d;
MapBank(pc);
UpdateEndBuffer(pc);
break;
}
case 1: { // Set sample start offset
pc->nStart = d << 12;
break;
}
case 2: {
pc->nPitch = d;
CalcAdvance(pc);
if (d == 0) { // Key off; stop playing
pc->bKey = 0;
}
break;
}
#if 0
case 3: {
break;
}
#endif
case 4: { // Set sample loop offset
pc->nLoop = d << 12;
UpdateEndBuffer(pc);
break;
}
case 5: { // Set sample end offset
pc->nEnd = d << 12;
UpdateEndBuffer(pc);
break;
}
case 6: { // Set volume
pc->nMasterVolume = d;
if (d == 0) {
pc->bKey = 0;
} else {
if (pc->bKey == 0) { // Key on; play sample
pc->nPlayStart = pc->nStart;
pc->nPos = 0;
pc->bKey = 3;
UpdateEndBuffer(pc);
}
}
break;
}
#if 0
case 7: {
break;
}
#endif
}
}
INT32 QscUpdate(INT32 nEnd)
{
INT32 nLen;
if (nEnd > nBurnSoundLen) {
nEnd = nBurnSoundLen;
}
nLen = nEnd - nPos;
if (nLen <= 0) {
return 0;
}
if (Tams < nLen) {
if (Qs_s) {
free(Qs_s);
Qs_s = NULL;
}
Tams = nLen;
Qs_s = (INT32*)malloc(sizeof(INT32) * 2 * Tams);
}
memset(Qs_s, 0, nLen * 2 * sizeof(INT32));
if (nInterpolation < 3) {
// Go through all channels
for (INT32 c = 0; c < 16; c++) {
// If the channel is playing, add the samples to the buffer
if (QChan[c].bKey) {
INT32 VolL = (QChan[c].nMasterVolume * QChan[c].nVolume[0]) >> nQscVolumeShift;
INT32 VolR = (QChan[c].nMasterVolume * QChan[c].nVolume[1]) >> nQscVolumeShift;
INT32* pTemp = Qs_s;
INT32 i = nLen;
INT32 s, p;
if (QChan[c].bKey & 2) {
QChan[c].bKey &= ~2;
QChan[c].nPos = QChan[c].nPlayStart;
}
while (i--) {
p = (QChan[c].nPos >> 12) & 0xFFFF;
// Check for end of sample
if (QChan[c].nPos >= (QChan[c].nEnd - 0x01000)) {
if (QChan[c].nLoop) { // Loop sample
if (QChan[c].nPos < QChan[c].nEnd) {
QChan[c].nEndBuffer[0] = QChan[c].PlayBank[(QChan[c].nEnd - QChan[c].nLoop) >> 12];
} else {
QChan[c].nPos = QChan[c].nEnd - QChan[c].nLoop + (QChan[c].nPos & 0x0FFF);
p = (QChan[c].nPos >> 12) & 0xFFFF;
}
} else {
if (QChan[c].nPos < QChan[c].nEnd) {
QChan[c].nEndBuffer[0] = QChan[c].PlayBank[p];
} else {
QChan[c].bKey = 0; // Quit playing
break;
}
}
} else {
QChan[c].nEndBuffer[0] = QChan[c].PlayBank[p + 1];
}
// Interpolate sample
s = QChan[c].PlayBank[p] * (1 << 6) + ((QChan[c].nPos) & ((1 << 12) - 1)) * (QChan[c].nEndBuffer[0] - QChan[c].PlayBank[p]) / (1 << 6);
// Add to the sound currently in the buffer
pTemp[0] += s * VolL;
pTemp[1] += s * VolR;
pTemp += 2;
QChan[c].nPos += QChan[c].nAdvance; // increment sample position based on pitch
}
}
}
if (bBurnUseMMX) {
#if defined BUILD_X86_ASM
BurnSoundCopyClamp_A(Qs_s, pBurnSoundOut + (nPos << 1), nLen);
#endif
} else {
BurnSoundCopyClamp_C(Qs_s, pBurnSoundOut + (nPos << 1), nLen);
}
nPos = nEnd;
return 0;
}
// Go through all channels
for (INT32 c = 0; c < 16; c++) {
// If the channel is playing, add the samples to the buffer
if (QChan[c].bKey) {
INT32 VolL = (QChan[c].nMasterVolume * QChan[c].nVolume[0]) >> nQscVolumeShift;
INT32 VolR = (QChan[c].nMasterVolume * QChan[c].nVolume[1]) >> nQscVolumeShift;
INT32* pTemp = Qs_s;
INT32 i = nLen;
// handle 1st sample
if (QChan[c].bKey & 2) {
while (QChan[c].nPos < 0x1000 && i) {
INT32 p = QChan[c].nPlayStart >> 12;
INT32 s = INTERPOLATE4PS_CUSTOM(QChan[c].nPos,
0,
QChan[c].PlayBank[p + 0],
QChan[c].PlayBank[p + 1],
QChan[c].PlayBank[p + 2],
256);
pTemp[0] += s * VolL;
pTemp[1] += s * VolR;
QChan[c].nPos += QChan[c].nAdvance; // increment sample position based on pitch
pTemp += 2;
i--;
}
if (i > 0) {
QChan[c].bKey &= ~2;
QChan[c].nPos = (QChan[c].nPos & 0x0FFF) + QChan[c].nPlayStart;
}
}
if (bBurnUseMMX && i > 0) {
#if defined BUILD_X86_ASM
QChan[c].bKey = (UINT8)ChannelMix_QS_A(pTemp, i,
(char*)QChan[c].PlayBank,
QChan[c].nEnd,
&(QChan[c].nPos),
VolL,
VolR,
QChan[c].nLoop,
QChan[c].nAdvance,
(char*)QChan[c].nEndBuffer);
#endif
} else {
while (i > 0) {
INT32 s, p;
// Check for end of sample
if (QChan[c].nPos >= (QChan[c].nEnd - 0x3000)) {
if (QChan[c].nPos < QChan[c].nEnd) {
INT32 nIndex = 4 - ((QChan[c].nEnd - QChan[c].nPos) >> 12);
s = INTERPOLATE4PS_CUSTOM((QChan[c].nPos) & ((1 << 12) - 1),
QChan[c].nEndBuffer[nIndex + 0],
QChan[c].nEndBuffer[nIndex + 1],
QChan[c].nEndBuffer[nIndex + 2],
QChan[c].nEndBuffer[nIndex + 3],
256);
} else {
if (QChan[c].nLoop) { // Loop sample
if (QChan[c].nLoop <= 0x1000) { // Don't play, but leave bKey on
QChan[c].nPos = QChan[c].nEnd - 0x1000;
break;
}
QChan[c].nPos -= QChan[c].nLoop;
continue;
} else {
QChan[c].bKey = 0; // Stop playing
break;
}
}
} else {
p = (QChan[c].nPos >> 12) & 0xFFFF;
s = INTERPOLATE4PS_CUSTOM((QChan[c].nPos) & ((1 << 12) - 1),
QChan[c].PlayBank[p + 0],
QChan[c].PlayBank[p + 1],
QChan[c].PlayBank[p + 2],
QChan[c].PlayBank[p + 3],
256);
}
// Add to the sound currently in the buffer
pTemp[0] += s * VolL;
pTemp[1] += s * VolR;
pTemp += 2;
QChan[c].nPos += QChan[c].nAdvance; // increment sample position based on pitch
i--;
}
}
}
}
if (bBurnUseMMX) {
#if defined BUILD_X86_ASM
BurnSoundCopyClamp_A(Qs_s, pBurnSoundOut + (nPos << 1), nLen);
#endif
} else {
BurnSoundCopyClamp_C(Qs_s, pBurnSoundOut + (nPos << 1), nLen);
}
nPos = nEnd;
return 0;
}

View File

@ -0,0 +1,138 @@
#include "cps.h"
// QSound - Z80
static INT32 nQsndZBank = 0;
// Map in the memory for the current 0x8000-0xc000 music bank
static INT32 QsndZBankMap()
{
UINT32 nOff;
UINT8* Bank;
nOff = nQsndZBank << 14;
nOff += 0x8000;
if (Cps1Qs == 0) {
if (nOff + 0x4000 > nCpsZRomLen) { // End of bank is out of range
nOff = 0;
}
Bank = CpsZRom + nOff;
} else {
if (nOff + 0x4000 > (nCpsZRomLen / 2)) {
nOff = 0;
}
Bank = CpsZRom - (nCpsZRomLen / 2) + nOff;
}
// Read and fetch the bank
ZetMapArea(0x8000, 0xbfff, 0, Bank);
if (Cps1Qs == 0) {
ZetMapArea(0x8000, 0xbfff, 2, Bank, CpsZRom + nOff);
} else {
ZetMapArea(0x8000, 0xbfff, 2, Bank);
}
return 0;
}
static UINT8 QscCmd[2] = {0, 0};
void __fastcall QsndZWrite(UINT16 a, UINT8 d)
{
if (a == 0xd000) {
QscCmd[0] = d;
return;
}
if (a == 0xd001) {
QscCmd[1] = d;
return;
}
if (a == 0xd002) {
QscWrite(d, (QscCmd[0] << 8) | QscCmd[1]);
// bprintf(PRINT_NORMAL, _T("QSound command %02X %04X sent.\n"), d, (QscCmd[0] << 8) | QscCmd[1]);
return;
}
if (a == 0xd003) {
INT32 nNewBank = d & 0x0f;
if (nQsndZBank != nNewBank) {
nQsndZBank = nNewBank;
QsndZBankMap();
}
}
}
UINT8 __fastcall QsndZRead(UINT16 a)
{
if (a == 0xd007) { // return ready all the time
return 0x80;
}
return 0;
}
INT32 QsndZInit()
{
if (nCpsZRomLen < 0x8000) { // Not enough Z80 Data
return 1;
}
if (CpsZRom == NULL) {
return 1;
}
ZetInit(1);
ZetSetReadHandler(QsndZRead);
ZetSetWriteHandler(QsndZWrite);
// Read and fetch first 0x8000 of Rom
if (Cps1Qs) {
ZetMapArea(0x0000, 0x7FFF, 0, CpsZRom - (nCpsZRomLen / 2));
ZetMapArea(0x0000, 0x7FFF, 2, CpsZRom, CpsZRom - (nCpsZRomLen / 2)); // If it tries to fetch this area
} else {
ZetMapArea(0x0000, 0x7FFF, 0 ,CpsZRom);
ZetMapArea(0x0000, 0x7FFF, 2, CpsZRom);
}
// Map first Bank of Rom
nQsndZBank = 0;
QsndZBankMap();
ZetMapArea(0xC000, 0xCFFF, 0, CpsZRamC0);
ZetMapArea(0xC000, 0xCFFF, 1, CpsZRamC0);
ZetMapArea(0xC000, 0xCFFF, 2, CpsZRamC0);
ZetMemCallback(0xD000, 0xEFFF, 0);
ZetMemCallback(0xD000, 0xEFFF, 1);
if (Cps1Qs) {
ZetMapArea(0xD000, 0xEFFF, 2, CpsZRom, CpsZRom - (nCpsZRomLen / 2)); // If it tries to fetch this area
} else {
ZetMapArea(0xD000, 0xEFFF, 2, CpsZRom);
}
ZetMapArea(0xF000, 0xFFFF, 0, CpsZRamF0);
ZetMapArea(0xF000, 0xFFFF, 1, CpsZRamF0);
ZetMapArea(0xF000, 0xFFFF, 2, CpsZRamF0);
ZetMemEnd();
ZetClose();
return 0;
}
INT32 QsndZExit()
{
ZetExit();
return 0;
}
// Scan the current QSound z80 state
INT32 QsndZScan(INT32 nAction)
{
ZetScan(nAction); // Scan Z80
SCAN_VAR(nQsndZBank);
if (nAction & ACB_WRITE) { // If write, bank could have changed
QsndZBankMap();
}
return 0;
}

View File

@ -0,0 +1,47 @@
#include "cave.h"
INT32 nCaveXSize = 0, nCaveYSize = 0;
INT32 nCaveXOffset = 0, nCaveYOffset = 0;
INT32 nCaveExtraXOffset = 0, nCaveExtraYOffset = 0;
INT32 nCaveRowModeOffset = 0;
INT32 CaveScanGraphics()
{
SCAN_VAR(nCaveXOffset);
SCAN_VAR(nCaveYOffset);
SCAN_VAR(nCaveTileBank);
SCAN_VAR(nCaveSpriteBank);
SCAN_VAR(nCaveSpriteBankDelay);
for (INT32 i = 0; i < 4; i++) {
SCAN_VAR(CaveTileReg[i][0]);
SCAN_VAR(CaveTileReg[i][1]);
SCAN_VAR(CaveTileReg[i][2]);
}
return 0;
}
// This function fills the screen with the background colour
void CaveClearScreen(UINT32 nColour)
{
if (nColour) {
UINT32* pClear = (UINT32*)pBurnDraw;
nColour = nColour | (nColour << 16);
for (INT32 i = nCaveXSize * nCaveYSize / 16; i > 0 ; i--) {
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
*pClear++ = nColour;
}
} else {
memset(pBurnDraw, 0, nCaveXSize * nCaveYSize * sizeof(INT16));
}
}

View File

@ -0,0 +1,63 @@
#include "burnint.h"
#include "eeprom.h"
#define CAVE_REFRESHRATE (15625.0 / 271.5)
inline static void CaveClearOpposites(UINT16* nJoystickInputs)
{
if ((*nJoystickInputs & 0x0003) == 0x0003) {
*nJoystickInputs &= ~0x0003;
}
if ((*nJoystickInputs & 0x000C) == 0x000C) {
*nJoystickInputs &= ~0x000C;
}
}
// cave.cpp
extern INT32 nCaveXSize, nCaveYSize;
extern INT32 nCaveXOffset, nCaveYOffset;
extern INT32 nCaveExtraXOffset, nCaveExtraYOffset;
extern INT32 nCaveRowModeOffset;
INT32 CaveScanGraphics();
void CaveClearScreen(UINT32 nColour);
// cave_palette.cpp
extern UINT32* CavePalette;
extern UINT8* CavePalSrc;
extern UINT8 CaveRecalcPalette;
INT32 CavePalInit(INT32 nPalSize);
INT32 CavePalExit();
INT32 CavePalUpdate4Bit(INT32 nOffset, INT32 nNumPalettes);
INT32 CavePalUpdate8Bit(INT32 nOffset, INT32 nNumPalettes);
void CavePalWriteByte(UINT32 nAddress, UINT8 byteValue);
void CavePalWriteWord(UINT32 nAddress, UINT16 wordValue);
// cave_tiles.cpp
extern UINT8* CaveTileROM[4];
extern UINT8* CaveTileRAM[4];
extern UINT32 CaveTileReg[4][3];
extern INT32 nCaveTileBank;
INT32 CaveTileRender(INT32 nMode);
void CaveTileExit();
INT32 CaveTileInit();
INT32 CaveTileInitLayer(INT32 nLayer, INT32 nROMSize, INT32 nBitdepth, INT32 nOffset);
// cave_sprite.cpp
extern INT32 CaveSpriteVisibleXOffset;
extern UINT8* CaveSpriteROM;
extern UINT8* CaveSpriteRAM;
extern INT32 nCaveSpriteBank;
extern INT32 nCaveSpriteBankDelay;
extern INT32 (*CaveSpriteBuffer)();
extern INT32 CaveSpriteRender(INT32 nLowPriority, INT32 nHighPriority);
void CaveSpriteExit();
INT32 CaveSpriteInit(INT32 nType, INT32 nROMSize);

View File

@ -0,0 +1,154 @@
#include "cave.h"
UINT8* CavePalSrc;
UINT8 CaveRecalcPalette; // Set to 1 to force recalculation of the entire palette
UINT32* CavePalette = NULL;
static UINT16* CavePalCopy = NULL;
INT32 CavePalInit(INT32 nPalSize)
{
CavePalette = (UINT32*)malloc(nPalSize * sizeof(UINT32));
memset(CavePalette, 0, nPalSize * sizeof(UINT32));
CavePalCopy = (UINT16*)malloc(nPalSize * sizeof(UINT16));
memset(CavePalCopy, 0, nPalSize * sizeof(UINT16));
pBurnDrvPalette = CavePalette;
return 0;
}
INT32 CavePalExit()
{
if (CavePalette) {
free(CavePalette);
CavePalette = NULL;
}
if (CavePalCopy) {
free(CavePalCopy);
CavePalCopy = NULL;
}
return 0;
}
inline static UINT32 CalcCol(UINT16 nColour)
{
INT32 r, g, b;
r = (nColour & 0x03E0) >> 2; // Red
r |= r >> 5;
g = (nColour & 0x7C00) >> 7; // Green
g |= g >> 5;
b = (nColour & 0x001F) << 3; // Blue
b |= b >> 5;
return BurnHighCol(r, g, b, 0);
}
INT32 CavePalUpdate4Bit(INT32 nOffset, INT32 nNumPalettes)
{
INT32 i, j;
UINT16* ps = (UINT16*)CavePalSrc + nOffset;
UINT16* pc;
UINT32* pd;
UINT16 c;
if (CaveRecalcPalette) {
for (i = 0; i < 0 + nNumPalettes; i++) {
pc = CavePalCopy + (i << 8);
pd = CavePalette + (i << 8);
for (j = 0; j < 16; j++, ps++, pc++, pd++) {
c = *ps;
*pc = c;
*pd = CalcCol(c);
}
}
CaveRecalcPalette = 0;
return 0;
}
for (i = 0; i < 0 + nNumPalettes; i++) {
pc = CavePalCopy + (i << 8);
pd = CavePalette + (i << 8);
for (j = 0; j < 16; j++, ps++, pc++, pd++) {
c = *ps;
if (*pc != c) {
*pc = c;
*pd = CalcCol(c);
}
}
}
return 0;
}
INT32 CavePalUpdate8Bit(INT32 nOffset, INT32 nNumPalettes)
{
if (CaveRecalcPalette) {
INT32 i, j;
UINT16* ps = (UINT16*)CavePalSrc + nOffset;
UINT16* pc;
UINT32* pd;
UINT16 c;
for (i = 0; i < nNumPalettes; i++) {
pc = CavePalCopy + nOffset + (i << 8);
pd = CavePalette + nOffset + (i << 8);
for (j = 0; j < 256; j++, ps++, pc++, pd++) {
c = *ps;
*pc = c;
*pd = CalcCol(c);
}
}
CaveRecalcPalette = 0;
}
return 0;
}
// Update the PC copy of the palette on writes to the palette memory
void CavePalWriteByte(UINT32 nAddress, UINT8 byteValue)
{
nAddress ^= 1;
CavePalSrc[nAddress] = byteValue; // write byte
if (*((UINT8*)(CavePalCopy + nAddress)) != byteValue) {
*((UINT8*)(CavePalCopy + nAddress)) = byteValue;
CavePalette[nAddress >> 1] = CalcCol(*(UINT16*)(CavePalSrc + (nAddress & ~0x01)));
}
}
void CavePalWriteWord(UINT32 nAddress, UINT16 wordValue)
{
nAddress >>= 1;
((UINT16*)CavePalSrc)[nAddress] = wordValue; // write word
if (CavePalCopy[nAddress] != wordValue) {
CavePalCopy[nAddress] = wordValue;
CavePalette[nAddress] = CalcCol(wordValue);
}
}

View File

@ -0,0 +1,742 @@
// Cave hardware sprites
#include "cave.h"
INT32 CaveSpriteVisibleXOffset;
UINT8* CaveSpriteROM = NULL;
UINT8* CaveSpriteRAM = NULL;
INT32 nCaveSpriteBank;
INT32 nCaveSpriteBankDelay;
static INT32 nSpriteAddressMask;
struct CaveSprite {
INT8 flip;
INT8 priority;
INT16 palette;
INT32 x; INT32 y;
INT32 xsize; INT32 ysize;
INT32 xzoom; INT32 yzoom;
INT32 address;
};
static CaveSprite* pSpriteList = NULL;
INT32 (*CaveSpriteBuffer)();
static UINT8* pRow;
static UINT8* pPixel;
static UINT32* pSpriteData;
static UINT32* pSpritePalette;
static UINT16* pZBuffer = NULL;
static UINT16* pZRow;
static UINT16* pZPixel;
static INT32 nSpriteRow, nSpriteRowSize;
static INT32 nXPos, nYPos, nZPos;
static INT32 nXSize, nYSize;
static INT32 nSpriteXZoomSize, nSpriteYZoomSize;
static INT32 nSpriteXOffset, nSpriteYOffset;
static INT32 nFirstSprite[4], nLastSprite[4];
static INT32 nTopSprite;
static INT32 nZOffset;
typedef void (*RenderSpriteFunction)();
static RenderSpriteFunction* RenderSprite;
// Include the sprite rendering functions
#include "cave_sprite_func.h"
INT32 CaveSpriteRender(INT32 nLowPriority, INT32 nHighPriority)
{
static INT32 nMaskLeft, nMaskRight, nMaskTop, nMaskBottom;
CaveSprite* pBuffer;
INT32 nPriorityMask = 0;
INT32 nMaxZPos = -1;
INT32 nCurrentZPos = 0x00010000;
INT32 nUseBuffer = 0x00010000;
INT32 nFunction;
if (nLowPriority == 0) {
nZPos = -1;
nTopSprite = -1;
nMaskLeft = nMaskTop = 9999;
nMaskRight = nMaskBottom = -1;
}
if ((nBurnLayer & 1) == 0) {
return 0;
}
if (nHighPriority < 3) {
for (INT32 i = nHighPriority + 1; i < 4; i++) {
if (nUseBuffer > nFirstSprite[i]) {
nUseBuffer = nFirstSprite[i];
}
}
}
for (INT32 i = nLowPriority; i <= nHighPriority; i++) {
if (nCurrentZPos > nFirstSprite[i]) {
nCurrentZPos = nFirstSprite[i];
}
if (nMaxZPos < nLastSprite[i]) {
nMaxZPos = nLastSprite[i];
}
nPriorityMask |= 8 >> i;
}
nPriorityMask &= nSpriteEnable;
if (nPriorityMask == 0) {
return 0;
}
for (pBuffer = pSpriteList + nCurrentZPos; nCurrentZPos <= nMaxZPos; pBuffer++, nCurrentZPos++) {
if ((pBuffer->priority & nPriorityMask) == 0) {
continue;
}
nXPos = pBuffer->x;
nYPos = pBuffer->y;
pSpriteData = (UINT32*)(CaveSpriteROM + ((pBuffer->address << 8) & nSpriteAddressMask));
pSpritePalette = CavePalette + pBuffer->palette;
nXSize = pBuffer->xsize;
nYSize = pBuffer->ysize;
if (pBuffer->xzoom == 0x0100 && pBuffer->yzoom == 0x0100) { // This sprite doesn't use zooming
nSpriteRowSize = pBuffer->xsize >> 2;
if (pBuffer->flip & 1) { // Y Flip
pSpriteData += nSpriteRowSize * (nYSize - 1);
nSpriteRowSize = -nSpriteRowSize;
}
if (nYPos >= 0x0200) {
nYPos -= 0x0400;
}
if (nYPos < 0) {
pSpriteData += nSpriteRowSize * -nYPos;
nYSize += nYPos;
nYPos = 0;
}
if ((nYPos + nYSize) > nCaveYSize) {
nYSize -= (nYPos + nYSize) - nCaveYSize;
}
if (nXPos >= 0x0200) {
nXPos -= 0x0400;
}
if (nXPos < 0) {
if ((pBuffer->flip & 2) == 0) {
pSpriteData += (-nXPos >> 4) << 2;
}
nXSize -= -nXPos & 0xFFF0;
nXPos += -nXPos & 0xFFF0;
}
if (nXPos + nXSize >= nCaveXSize) {
if (pBuffer->flip & 2) {
pSpriteData += ((nXPos + nXSize - nCaveXSize) >> 4) << 2;
}
nXSize -= (nXPos + nXSize - nCaveXSize) & 0xFFF0;
}
pRow = pBurnDraw + (nYPos * nBurnPitch) + (nXPos * nBurnBpp);
nFunction = (pBuffer->flip & 2) << 1; // X Flip
if (nTopSprite > nCurrentZPos) { // Test ZBuffer
if (nXPos < nMaskRight && (nXPos + nXSize) >= nMaskLeft && nYPos < nMaskBottom && (nYPos + nYSize) >= nMaskTop) {
nFunction |= 1;
}
}
if (nUseBuffer < nCurrentZPos) { // Write ZBuffer
nFunction |= 2;
if (nXPos < nMaskLeft) {
nMaskLeft = nXPos;
}
if ((nXPos + nXSize) > nMaskRight) {
nMaskRight = nXPos + nXSize;
}
if (nYPos < nMaskTop) {
nMaskTop = nYPos;
}
if ((nYPos + nYSize) > nMaskBottom) {
nMaskBottom = nYPos + nYSize;
}
}
if (nFunction & 3) {
pZRow = pZBuffer + (nYPos * 320) + nXPos;
nZPos = nCurrentZPos + nZOffset;
}
nXSize = nXSize >> 2;
RenderSprite[nFunction]();
} else { // This sprite uses zooming
nSpriteXZoomSize = 0x01000000; // * zoom factor = size of each screen pixel
nXSize *= pBuffer->xzoom;
nXSize >>= 8; // Round to multiple of whole pixel
if (nXSize < 1) { // Make sure the sprite is at least one pixel wide
nXSize = 1;
} else {
nSpriteXZoomSize /= pBuffer->xzoom;
}
if (nSpriteXZoomSize > (pBuffer->xsize << 16)) {
nSpriteXZoomSize = pBuffer->xsize << 16;
}
nSpriteXOffset = nSpriteXZoomSize >> 1; // Make certain the pixels displayed are centered
if (pBuffer->flip & 2) { // X Flip
nXPos += pBuffer->xsize - nXSize;
nSpriteXOffset = (pBuffer->xsize << 16) - nSpriteXOffset;
nSpriteXZoomSize = -nSpriteXZoomSize;
}
if (nXPos >= 0x0200) {
nXPos -= 0x0400;
}
if (nXPos < 0) {
if (nXPos + nXSize <= 0) {
continue;
}
nXPos = -nXPos;
nSpriteXOffset += nXPos * nSpriteXZoomSize;
nXSize -= nXPos;
nXPos = 0;
}
if (nXPos + nXSize >= nCaveXSize) {
if (nXPos >= nCaveXSize) {
continue;
}
nXSize = nCaveXSize - nXPos;
}
nSpriteRowSize = pBuffer->xsize; // Size of each sprite row in memory
nSpriteYZoomSize = 0x01000000; // * zoom factor = size of each screen pixel
nYSize *= pBuffer->yzoom;
nYSize >>= 8; // Round to multiple of whole pixel
if (nYSize < 1) { // Make certain the sprite is at least one pixel high
nYSize = 1;
} else {
nSpriteYZoomSize /= pBuffer->yzoom;
}
if (nSpriteYZoomSize > (pBuffer->ysize << 16)) {
nSpriteYZoomSize = pBuffer->ysize << 16;
}
nSpriteYOffset = nSpriteYZoomSize >> 1; // Make certain the pixels displayed are centered
if (pBuffer->flip & 1) { // Y Flip
nYPos += pBuffer->ysize - nYSize;
nSpriteYOffset = (pBuffer->ysize << 16) - nSpriteYOffset;
nSpriteYZoomSize = -nSpriteYZoomSize;
}
if (nYPos >= 0x0200) {
nYPos -= 0x0400;
}
if (nYPos < 0) {
if (nYPos + nYSize <= 0) {
continue;
}
nYPos = -nYPos;
nSpriteYOffset += nYPos * nSpriteYZoomSize;
nYSize -= nYPos;
nYPos = 0;
}
if (nYPos + nYSize >= nCaveYSize) {
if (nYPos >= nCaveYSize) {
continue;
}
nYSize = nCaveYSize - nYPos;
}
pRow = pBurnDraw + (nYPos * nBurnPitch) + (nXPos * nBurnBpp);
nFunction = 8;
if (pBuffer->xzoom > 0x0100 || pBuffer->yzoom > 0x0100) {
nFunction |= 4;
}
if (nTopSprite > nCurrentZPos) { // Test ZBuffer
if (nXPos < nMaskRight && nXPos + nXSize >= nMaskLeft && nYPos < nMaskBottom && nYPos + nYSize >= nMaskTop) {
nFunction |= 1;
}
}
if (nUseBuffer < nCurrentZPos) { // Write ZBuffer
nFunction |= 2;
if (nXPos < nMaskLeft) {
nMaskLeft = nXPos;
}
if (nXPos + nXSize > nMaskRight) {
nMaskRight = nXPos + nXSize;
}
if (nYPos < nMaskTop) {
nMaskTop = nYPos;
}
if (nYPos + nYSize > nMaskBottom) {
nMaskBottom = nYPos + nYSize;
}
}
if (nFunction & 3) {
pZRow = pZBuffer + (nYPos * nCaveXSize) + nXPos;
nZPos = nCurrentZPos + nZOffset;
}
nXSize <<= 16;
nYSize <<= 16;
RenderSprite[nFunction]();
}
}
if (nMaxZPos > nTopSprite) {
nTopSprite = nMaxZPos;
}
if (nHighPriority == 3) {
if (nZPos >= 0) {
nZOffset += nTopSprite;
if (nZOffset > 0xFC00) {
memset(pZBuffer, 0, nCaveXSize * nCaveYSize * sizeof(UINT16));
nZOffset = 0;
}
}
}
return 0;
}
// Donpachi/DoDonpachi sprite format (no zooming)
static INT32 CaveSpriteBuffer_NoZoom()
{
UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
CaveSprite* pBuffer = pSpriteList;
INT32 nPriority;
nFirstSprite[0] = 0x00010000;
nFirstSprite[1] = 0x00010000;
nFirstSprite[2] = 0x00010000;
nFirstSprite[3] = 0x00010000;
nLastSprite[0] = -1;
nLastSprite[1] = -1;
nLastSprite[2] = -1;
nLastSprite[3] = -1;
INT16 word;
INT32 x, y, xs, ys;
for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
word = pSprite[4];
xs = (word >> 4) & 0x01F0;
ys = (word << 4) & 0x01F0;
if (ys == 0 || xs == 0) {
continue;
}
#if 0
x = (pSprite[2] + nCaveExtraXOffset) & 0x03FF;
#else
x = (pSprite[2] + CaveSpriteVisibleXOffset) & 0x03FF;
#endif
if (x >= 320) {
if (x + xs <= 0x0400) {
continue;
}
}
#if 0
y = (pSprite[3] + nCaveExtraYOffset) & 0x03FF;
#else
y = pSprite[3] & 0x03FF;
#endif
if (y >= 240) {
if (y + ys <= 0x0400) {
continue;
}
}
// Sprite is both active and onscreen, so add it to the buffer
word = pSprite[0];
nPriority = (word >> 4) & 0x03;
if (nLastSprite[nPriority] == -1) {
nFirstSprite[nPriority] = z;
}
nLastSprite[nPriority] = z;
pBuffer->priority = 8 >> nPriority;
pBuffer->flip = (word >> 2) & 0x03;
pBuffer->palette = word & 0x3F00;
pBuffer->address = pSprite[1] | ((word & 3) << 16);
pBuffer->x = x;
pBuffer->y = y;
pBuffer->xsize = xs;
pBuffer->ysize = ys;
pBuffer++;
z++;
}
return 0;
}
// Normal sprite format (zooming)
static INT32 CaveSpriteBuffer_ZoomA()
{
UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
CaveSprite* pBuffer = pSpriteList;
INT32 nPriority;
nFirstSprite[0] = 0x00010000;
nFirstSprite[1] = 0x00010000;
nFirstSprite[2] = 0x00010000;
nFirstSprite[3] = 0x00010000;
nLastSprite[0] = -1;
nLastSprite[1] = -1;
nLastSprite[2] = -1;
nLastSprite[3] = -1;
INT16 word;
INT32 x, y, xs, ys;
for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
word = pSprite[6];
xs = (word >> 4) & 0x01F0;
ys = (word << 4) & 0x01F0;
if (ys == 0 || xs == 0) {
continue;
}
word = pSprite[2];
nPriority = (word >> 4) & 0x03;
x = ((pSprite[0] >> 6) + CaveSpriteVisibleXOffset) & 0x03FF;
#if 0
y = ((pSprite[1] >> 6) + nCaveExtraYOffset) & 0x03FF;
#else
y = (pSprite[1] >> 6) & 0x03FF;
#endif
if (pSprite[4] <= 0x0100 && pSprite[5] <= 0x0100) {
if (x >= 320) {
if (x + xs <= 0x0400) {
continue;
}
}
if (y >= 240) {
if (y + ys <= 0x0400) {
continue;
}
}
}
// Sprite is active and most likely on screen, so add it to the buffer
if (nLastSprite[nPriority] == -1) {
nFirstSprite[nPriority] = z;
}
nLastSprite[nPriority] = z;
pBuffer->priority = 8 >> nPriority;
pBuffer->xzoom = pSprite[4];
pBuffer->yzoom = pSprite[5];
pBuffer->xsize = xs;
pBuffer->ysize = ys;
pBuffer->x = x;
pBuffer->y = y;
pBuffer->flip = (word >> 2) & 0x03;
pBuffer->palette = word & 0x3F00;
pBuffer->address = pSprite[3] | ((word & 3) << 16);
pBuffer++;
z++;
}
return 0;
}
// Normal sprite format (zooming, alternate position handling)
static INT32 CaveSpriteBuffer_ZoomB()
{
UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
CaveSprite* pBuffer = pSpriteList;
INT32 nPriority;
nFirstSprite[0] = 0x00010000;
nFirstSprite[1] = 0x00010000;
nFirstSprite[2] = 0x00010000;
nFirstSprite[3] = 0x00010000;
nLastSprite[0] = -1;
nLastSprite[1] = -1;
nLastSprite[2] = -1;
nLastSprite[3] = -1;
INT16 word;
INT32 x, y, xs, ys;
for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
word = pSprite[6];
xs = (word >> 4) & 0x01F0;
ys = (word << 4) & 0x01F0;
if (ys == 0 || xs == 0) {
continue;
}
word = pSprite[2];
nPriority = (word >> 4) & 0x03;
#if 0
x = (pSprite[0] + nCaveExtraXOffset) & 0x03FF;
# else
x = (pSprite[0] + CaveSpriteVisibleXOffset) & 0x03FF;
#endif
#if 0
y = (pSprite[1] + nCaveExtraYOffset) & 0x03FF;
#else
y = pSprite[1] & 0x03FF;
#endif
if (pSprite[4] <= 0x0100 && pSprite[5] <= 0x0100) {
if (x >= nCaveXSize) {
if (x + xs <= 0x0400) {
continue;
}
}
if (y >= nCaveYSize) {
if (y + ys <= 0x0400) {
continue;
}
}
}
// Sprite is active and most likely on screen, so add it to the buffer
if (nLastSprite[nPriority] == -1) {
nFirstSprite[nPriority] = z;
}
nLastSprite[nPriority] = z;
pBuffer->priority = 8 >> nPriority;
pBuffer->xzoom = pSprite[4];
pBuffer->yzoom = pSprite[5];
pBuffer->xsize = xs;
pBuffer->ysize = ys;
pBuffer->x = x;
pBuffer->y = y;
pBuffer->flip = (word >> 2) & 0x03;
pBuffer->palette = word & 0x3F00;
pBuffer->address = pSprite[3] | ((word & 3) << 16);
pBuffer++;
z++;
}
return 0;
}
// Power Instinct 2 sprite format (no zooming)
static INT32 CaveSpriteBuffer_PowerInstinct()
{
UINT16* pSprite = (UINT16*)(CaveSpriteRAM + (nCaveSpriteBank << 14));
CaveSprite* pBuffer = pSpriteList;
INT32 nPriority;
nFirstSprite[0] = 0x00010000;
nFirstSprite[1] = 0x00010000;
nFirstSprite[2] = 0x00010000;
nFirstSprite[3] = 0x00010000;
nLastSprite[0] = -1;
nLastSprite[1] = -1;
nLastSprite[2] = -1;
nLastSprite[3] = -1;
INT16 word;
INT32 x, y, xs, ys;
for (INT32 i = 0, z = 0; i < 0x0400; i++, pSprite += 8) {
word = pSprite[4];
xs = (word >> 4) & 0x01F0;
ys = (word << 4) & 0x01F0;
if (ys == 0 || xs == 0) {
continue;
}
x = (pSprite[2] + nCaveExtraXOffset) & 0x03FF;
if (x >= 320) {
if (x + xs <= 0x0400) {
continue;
}
}
y = (pSprite[3] + nCaveExtraYOffset) & 0x03FF;
if (y >= 240) {
if (y + ys <= 0x0400) {
continue;
}
}
// Sprite is both active and onscreen, so add it to the buffer
word = pSprite[0];
nPriority = ((word >> 4) & 0x01) | 2;
if (nLastSprite[nPriority] == -1) {
nFirstSprite[nPriority] = z;
}
nLastSprite[nPriority] = z;
pBuffer->priority = 8 >> nPriority;
pBuffer->flip = (word >> 2) & 0x03;
pBuffer->palette = ((word >> 4) & 0x03F0) + ((word << 5) & 0xC00);
pBuffer->address = pSprite[1] | ((word & 3) << 16);
pBuffer->x = x;
pBuffer->y = y;
pBuffer->xsize = xs;
pBuffer->ysize = ys;
pBuffer++;
z++;
}
return 0;
}
void CaveSpriteExit()
{
if (pSpriteList) {
free(pSpriteList);
pSpriteList = NULL;
}
if (pZBuffer) {
free(pZBuffer);
pZBuffer = NULL;
}
CaveSpriteVisibleXOffset = 0;
return;
}
INT32 CaveSpriteInit(INT32 nType, INT32 nROMSize)
{
if (pSpriteList) {
free(pSpriteList);
}
pSpriteList = (CaveSprite*)malloc(0x0401 * sizeof(CaveSprite));
if (pSpriteList == NULL) {
CaveSpriteExit();
return 1;
}
for (INT32 i = 0; i < 0x0400; i++) {
pSpriteList[i].xzoom = 0x0100;
pSpriteList[i].yzoom = 0x0100;
}
for (INT32 i = 0; i < 4; i++) {
nFirstSprite[i] = 0x00010000;
nLastSprite[i] = -1;
}
if (pZBuffer) {
free(pZBuffer);
}
pZBuffer = (UINT16*)malloc(nCaveXSize * nCaveYSize * sizeof(UINT16));
if (pZBuffer == NULL) {
CaveSpriteExit();
return 1;
}
memset(pZBuffer, 0, nCaveXSize * nCaveYSize * sizeof(UINT16));
nZOffset = 0;
for (nSpriteAddressMask = 1; nSpriteAddressMask < nROMSize; nSpriteAddressMask <<= 1) {}
nSpriteAddressMask--;
switch (nType) {
case 0:
CaveSpriteBuffer = &CaveSpriteBuffer_NoZoom;
break;
case 1:
CaveSpriteBuffer = &CaveSpriteBuffer_ZoomA;
break;
case 2:
CaveSpriteBuffer = &CaveSpriteBuffer_ZoomB;
break;
case 3:
CaveSpriteBuffer = &CaveSpriteBuffer_PowerInstinct;
break;
default:
CaveSpriteExit();
return 1;
}
nCaveSpriteBank = 0;
nCaveSpriteBankDelay = 0;
RenderSprite = RenderSprite_ROT0[(nCaveXSize == 320) ? 0 : 1];
return 0;
}

View File

@ -0,0 +1,281 @@
// Create a unique name for each of the functions
#define FN(a,b,c,d,e,f,g) RenderSprite ## a ## _ ## b ## _ROT ## c ## d ## e ## _CLIPX ## f ## g
#define FUNCTIONNAME(a,b,c,d,e,f,g) FN(a,b,c,d,e,f,g)
#if ROT == 0
#define ADVANCEWORD pPixel += ((BPP >> 3) * 16)
#define ADVANCEROW pRow += ((BPP >> 3) * XSIZE)
#else
#error unsupported rotation angle specified
#endif
#if EIGHTBIT == 0
#define DEPTH _16
#elif EIGHTBIT == 1
#define DEPTH _256
#else
#error illegal eightbit value
#endif
#define TESTCOLOUR(x) x
#if ZBUFFER == 0
#define ZBUF _NOZBUFFER
#define ADVANCEZWORD
#define ADVANCEZROW
#define TESTZBUF(a) 1
#define WRITEZBUF(a)
#elif ZBUFFER == 1
#define ZBUF _RZBUFFER
#define ADVANCEZWORD pZPixel += 16
#define ADVANCEZROW pZRow += XSIZE
#define TESTZBUF(a) (pZPixel[a] <= nZPos)
#define WRITEZBUF(a)
#elif ZBUFFER == 2
#define ZBUF _WZBUFFER
#define ADVANCEZWORD pZPixel += 16
#define ADVANCEZROW pZRow += XSIZE
#define TESTZBUF(a) 1
#define WRITEZBUF(a) pZPixel[a] = nZPos
#elif ZBUFFER == 3
#define ZBUF _RWZBUFFER
#define ADVANCEZWORD pZPixel += 16
#define ADVANCEZROW pZRow += XSIZE
#define TESTZBUF(a) (pZPixel[a] <= nZPos)
#define WRITEZBUF(a) pZPixel[a] = nZPos
#else
#error unsupported zbuffer mode specified.
#endif
#if BPP == 16
#define PLOTPIXEL(a,b) if (TESTCOLOUR(b) && TESTZBUF(a)) { \
WRITEZBUF(a); \
*((UINT16*)(pPixel + a * 2)) = (UINT16)pSpritePalette[b]; \
}
#elif BPP == 24
#define PLOTPIXEL(a,b) if (TESTCOLOUR(b) && TESTZBUF(a)) { \
WRITEZBUF(a); \
UINT32 nRGB = pSpritePalette[b]; \
pPixel[a * 3 + 0] = (UINT8)nRGB; \
pPixel[a * 3 + 1] = (UINT8)(nRGB >> 8); \
pPixel[a * 3 + 2] = (UINT8)(nRGB >> 16); \
}
#elif BPP == 32
#define PLOTPIXEL(a,b) if (TESTCOLOUR(b) && TESTZBUF(a)) { \
WRITEZBUF(a); \
*((UINT32*)(pPixel + a * 4)) = (UINT32)pSpritePalette[b]; \
}
#else
#error unsupported bitdepth specified.
#endif
#if XFLIP == 0
#define FLIP _NOFLIP
#elif XFLIP == 1
#define FLIP _FLIPX
#else
#error illegal XFLIP value
#endif
#if ZOOM == 0
#define ZOOMMODE _NOZOOM
#elif ZOOM == 1
#define ZOOMMODE _ZOOMXY
#else
#error unsupported rowscroll mode specified.
#endif
#if XFLIP == 0
#define OFFSET(a) a
#define CLIP(a,b) if (nColumn >= (XSIZE - a)) { continue; } \
if (nXPos >= (0 - a)) { b }
#else
#define OFFSET(a) (15 - a)
#define CLIP(a,b) if (nColumn >= (0 - a) && nColumn < (XSIZE - a)) { b }
#endif
#if EIGHTBIT == 0
#define PLOT8_CLIP(x) \
CLIP(OFFSET((x + 0)), PLOTPIXEL(OFFSET((x + 0)), nColour & 0x0F)); \
nColour >>= 4; \
CLIP(OFFSET((x + 1)), PLOTPIXEL(OFFSET((x + 1)), nColour & 0x0F)); \
\
nColour >>= 4; \
CLIP(OFFSET((x + 2)), PLOTPIXEL(OFFSET((x + 2)), nColour & 0x0F)); \
nColour >>= 4; \
CLIP(OFFSET((x + 3)), PLOTPIXEL(OFFSET((x + 3)), nColour & 0x0F)); \
\
nColour >>= 4; \
CLIP(OFFSET((x + 4)), PLOTPIXEL(OFFSET((x + 4)), nColour & 0x0F)); \
nColour >>= 4; \
CLIP(OFFSET((x + 5)), PLOTPIXEL(OFFSET((x + 5)), nColour & 0x0F)); \
\
nColour >>= 4; \
CLIP(OFFSET((x + 6)), PLOTPIXEL(OFFSET((x + 6)), nColour & 0x0F)); \
nColour >>= 4; \
CLIP(OFFSET((x + 7)), PLOTPIXEL(OFFSET((x + 7)), nColour & 0x0F));
#define PLOT8_NOCLIP(x) \
PLOTPIXEL(OFFSET((x + 0)), nColour & 0x0F); \
nColour >>= 4; \
PLOTPIXEL(OFFSET((x + 1)), nColour & 0x0F); \
\
nColour >>= 4; \
PLOTPIXEL(OFFSET((x + 2)), nColour & 0x0F); \
nColour >>= 4; \
PLOTPIXEL(OFFSET((x + 3)), nColour & 0x0F); \
\
nColour >>= 4; \
PLOTPIXEL(OFFSET((x + 4)), nColour & 0x0F); \
nColour >>= 4; \
PLOTPIXEL(OFFSET((x + 5)), nColour & 0x0F); \
\
nColour >>= 4; \
PLOTPIXEL(OFFSET((x + 6)), nColour & 0x0F); \
nColour >>= 4; \
PLOTPIXEL(OFFSET((x + 7)), nColour & 0x0F);
#else
#define PLOT4_CLIP(x) \
CLIP(OFFSET((x + 0)), PLOTPIXEL(OFFSET((x + 0)), nColour & 0xFF)); \
nColour >>= 8; \
CLIP(OFFSET((x + 1)), PLOTPIXEL(OFFSET((x + 1)), nColour & 0xFF)); \
nColour >>= 8; \
\
CLIP(OFFSET((x + 2)), PLOTPIXEL(OFFSET((x + 2)), nColour & 0xFF)); \
nColour >>= 8; \
CLIP(OFFSET((x + 3)), PLOTPIXEL(OFFSET((x + 3)), nColour & 0xFF));
#define PLOT4_NOCLIP(x) \
PLOTPIXEL(OFFSET((x + 0)), nColour & 0xFF); \
nColour >>= 8; \
PLOTPIXEL(OFFSET((x + 1)), nColour & 0xFF); \
nColour >>= 8; \
\
PLOTPIXEL(OFFSET((x + 2)), nColour & 0xFF); \
nColour >>= 8; \
PLOTPIXEL(OFFSET((x + 3)), nColour & 0xFF);
#endif
static void FUNCTIONNAME(BPP,XSIZE,ROT,FLIP,ZOOMMODE,ZBUF,DEPTH)()
{
// Create an empty function if unsupported features are requested
#if ROT == 0
INT32 x, nColumn;
INT32 nColour;
#if ZBUFFER == 0
for (nSpriteRow = 0; nSpriteRow < nYSize; ADVANCEROW, nSpriteRow++, pSpriteData += nSpriteRowSize) {
#else
for (nSpriteRow = 0; nSpriteRow < nYSize; ADVANCEROW, ADVANCEZROW, nSpriteRow++, pSpriteData += nSpriteRowSize) {
#endif
nColumn = nXPos;
#if ZBUFFER == 0
#if XFLIP == 0
for (x = (0 << EIGHTBIT), pPixel = pRow; x < nXSize; x += (2 << EIGHTBIT), nColumn += 16, ADVANCEWORD) {
#else
for (x = nXSize - (2 << EIGHTBIT), pPixel = pRow; x >= 0; x -= (2 << EIGHTBIT), nColumn += 16, ADVANCEWORD) {
#endif
#else
#if XFLIP == 0
for (x = 0, pPixel = pRow, pZPixel = pZRow; x < nXSize; x += (2 << EIGHTBIT), nColumn += 16, ADVANCEWORD, ADVANCEZWORD) {
#else
for (x = nXSize - (2 << EIGHTBIT), pPixel = pRow, pZPixel = pZRow; x >= 0; x -= (2 << EIGHTBIT), nColumn += 16, ADVANCEWORD, ADVANCEZWORD) {
#endif
#endif
#if EIGHTBIT == 0
if (nColumn >= 0 && nColumn < (XSIZE - 16)) {
#if XFLIP == 0
nColour = pSpriteData[x];
PLOT8_NOCLIP(0);
nColour = pSpriteData[x + 1];
PLOT8_NOCLIP(8);
#else
nColour = pSpriteData[x + 1];
PLOT8_NOCLIP(8);
nColour = pSpriteData[x];
PLOT8_NOCLIP(0);
#endif
} else {
#if XFLIP == 0
nColour = pSpriteData[x];
PLOT8_CLIP(0);
nColour = pSpriteData[x + 1];
PLOT8_CLIP(8);
#else
nColour = pSpriteData[x + 1];
PLOT8_CLIP(8);
nColour = pSpriteData[x];
PLOT8_CLIP(0);
#endif
#else
if (nColumn >= 0 && nColumn < (XSIZE - 16)) {
#if XFLIP == 0
nColour = pSpriteData[x];
PLOT4_NOCLIP(0);
nColour = pSpriteData[x + 1];
PLOT4_NOCLIP(4);
nColour = pSpriteData[x + 2];
PLOT4_NOCLIP(8);
nColour = pSpriteData[x + 3];
PLOT4_NOCLIP(12);
#else
nColour = pSpriteData[x + 3];
PLOT4_NOCLIP(12);
nColour = pSpriteData[x + 2];
PLOT4_NOCLIP(8);
nColour = pSpriteData[x + 1];
PLOT4_NOCLIP(4);
nColour = pSpriteData[x];
PLOT4_NOCLIP(0);
#endif
} else {
#if XFLIP == 0
nColour = pSpriteData[x];
PLOT4_CLIP(0);
nColour = pSpriteData[x + 1];
PLOT4_CLIP(4);
nColour = pSpriteData[x + 2];
PLOT4_CLIP(8);
nColour = pSpriteData[x + 3];
PLOT4_CLIP(12);
#else
nColour = pSpriteData[x + 3];
PLOT4_CLIP(12);
nColour = pSpriteData[x + 2];
PLOT4_CLIP(8);
nColour = pSpriteData[x + 1];
PLOT4_CLIP(4);
nColour = pSpriteData[x];
PLOT4_CLIP(0);
#endif
#endif
}
}
}
#endif
}
#undef PLOT4_CLIP
#undef PLOT4_NOCLIP
#undef PLOT8_CLIP
#undef PLOT8_NOCLIP
#undef OFFSET
#undef FLIP
#undef PLOTPIXEL
#undef CLIP
#undef TESTCOLOUR
#undef ADVANCEZROW
#undef ADVANCEZWORD
#undef ADVANCEROW
#undef ADVANCEWORD
#undef TESTZBUF
#undef WRITEZBUF
#undef ZBUF
#undef ZOOMMODE
#undef DEPTH
#undef FUNCTIONNAME
#undef FN

View File

@ -0,0 +1,182 @@
// Create a unique name for each of the functions
#define FN(a,b,c,d,e,f,g) RenderSprite ## a ## _ ## b ## _ROT ## c ## d ## e ## _NOCLIP ## f ## g
#define FUNCTIONNAME(a,b,c,d,e,f,g) FN(a,b,c,d,e,f,g)
#if ROT == 0
#define ADVANCECOLUMN pPixel += (BPP >> 3)
#define ADVANCEROW pRow += ((BPP >> 3) * XSIZE)
#else
#error unsupported rotation angle specified
#endif
#if EIGHTBIT == 0
#define DEPTH _16
#elif EIGHTBIT == 1
#define DEPTH _256
#else
#error illegal eightbit value
#endif
#define TESTCOLOUR(x) x
#if ZBUFFER == 0
#define ZBUF _NOZBUFFER
#define ADVANCEZCOLUMN
#define ADVANCEZROW
#define TESTZBUF(a) 1
#define WRITEZBUF(a)
#elif ZBUFFER == 1
#define ZBUF _RZBUFFER
#define ADVANCEZCOLUMN pZPixel += 1
#define ADVANCEZROW pZRow += XSIZE
#define TESTZBUF(a) (pZPixel[a] <= nZPos)
#define WRITEZBUF(a)
#elif ZBUFFER == 2
#define ZBUF _WZBUFFER
#define ADVANCEZCOLUMN pZPixel += 1
#define ADVANCEZROW pZRow += XSIZE
#define TESTZBUF(a) 1
#define WRITEZBUF(a) pZPixel[a] = nZPos
#elif ZBUFFER == 3
#define ZBUF _RWZBUFFER
#define ADVANCEZCOLUMN pZPixel += 1
#define ADVANCEZROW pZRow += XSIZE
#define TESTZBUF(a) (pZPixel[a] <= nZPos)
#define WRITEZBUF(a) pZPixel[a] = nZPos
#else
#error unsupported zbuffer mode specified.
#endif
#if BPP == 16
#define PLOTPIXEL(a,b) if (TESTCOLOUR(b) && TESTZBUF(a)) { \
WRITEZBUF(a); \
*((UINT16*)(pPixel + a * 2)) = (UINT16)pSpritePalette[b]; \
}
#elif BPP == 24
#define PLOTPIXEL(a,b) if (TESTCOLOUR(b) && TESTZBUF(a)) { \
WRITEZBUF(a); \
UINT32 nRGB = pSpritePalette[b]; \
pPixel[a * 3 + 0] = (UINT8)nRGB; \
pPixel[a * 3 + 1] = (UINT8)(nRGB >> 8); \
pPixel[a * 3 + 2] = (UINT8)(nRGB >> 16); \
}
#elif BPP == 32
#define PLOTPIXEL(a,b) if (TESTCOLOUR(b) && TESTZBUF(a)) { \
WRITEZBUF(a); \
*((UINT32*)(pPixel + a * 4)) = (UINT32)pSpritePalette[b]; \
}
#else
#error unsupported bitdepth specified.
#endif
#if XFLIP == 0
#define FLIP _NOFLIP
#elif XFLIP == 1
#define FLIP _FLIPX
#else
#error illegal XFLIP value
#endif
#if ZOOM == 0
#define ZOOMMODE _NOZOOM
#elif ZOOM == 1
#define ZOOMMODE _ZOOMOUT
#elif ZOOM == 2
#define ZOOMMODE _ZOOMIN
#else
#error unsupported zoom mode specified.
#endif
static void FUNCTIONNAME(BPP,XSIZE,ROT,FLIP,ZOOMMODE,ZBUF,DEPTH)()
{
// Create an empty function if unsupported features are requested
#if ROT == 0 && XFLIP == 0 && EIGHTBIT == 1
INT32 nSpriteColumn;
INT32 nSpriteXOffset2;
#if ZOOM == 2
INT32 nPrevSpriteXOffset;
INT32 nPrevSpriteXOffsetStart = nSpriteXOffset & 0xFFFF0000;
INT32 nPrevSpriteYOffset = nSpriteYOffset & 0xFFFF0000;
if (nPrevSpriteXOffsetStart == 0) {
nPrevSpriteXOffsetStart = 0xFEDC1234;
}
if (nPrevSpriteYOffset == 0) {
nPrevSpriteYOffset = 0xFEDC1234;
}
#endif
UINT8* pSpriteRowData = (UINT8*)pSpriteData;
for (nSpriteRow = nYSize; nSpriteRow > 0; nSpriteRow -= 0x00010000, nSpriteYOffset += nSpriteYZoomSize) {
#if ZOOM == 2
if ((nSpriteYOffset & 0xFFFF0000) == (nPrevSpriteYOffset & 0xFFFF0000)) {
ADVANCEROW;
#if ZBUFFER != 0
ADVANCEZROW;
#endif
continue;
}
nPrevSpriteYOffset = nSpriteYOffset;
nPrevSpriteXOffset = nPrevSpriteXOffsetStart;
#endif
pSpriteRowData = ((UINT8*)pSpriteData) + (nSpriteYOffset >> 16) * nSpriteRowSize;
nSpriteXOffset2 = nSpriteXOffset;
#if ZBUFFER != 0
pZPixel = pZRow;
#endif
for (nSpriteColumn = nXSize, pPixel = pRow; nSpriteColumn > 0; nSpriteColumn -= 0x00010000, nSpriteXOffset2 += nSpriteXZoomSize) {
#if ZOOM == 2
if ((nSpriteXOffset2 & 0xFFFF0000) != (nPrevSpriteXOffset & 0xFFFF0000)) {
nPrevSpriteXOffset = nSpriteXOffset2;
#endif
PLOTPIXEL(0, pSpriteRowData[nSpriteXOffset2 >> 16]);
#if ZOOM == 2
}
#endif
ADVANCECOLUMN;
#if ZBUFFER != 0
ADVANCEZCOLUMN;
#endif
}
ADVANCEROW;
#if ZBUFFER != 0
ADVANCEZROW;
#endif
}
#endif
}
#undef OFFSET
#undef FLIP
#undef PLOTPIXEL
#undef TESTCOLOUR
#undef ADVANCEZROW
#undef ADVANCEZCOLUMN
#undef ADVANCEROW
#undef ADVANCECOLUMN
#undef TESTZBUF
#undef WRITEZBUF
#undef ZBUF
#undef ZOOMMODE
#undef DEPTH
#undef FUNCTIONNAME
#undef FN

View File

@ -0,0 +1,981 @@
// Cave hardware tilemaps
#include "cave.h"
struct CaveTile { INT16 x; INT16 y; UINT32 tile; };
static CaveTile* CaveTileQueueMemory[4] = { NULL, };
static CaveTile* CaveTileQueue[4][4];
UINT32 CaveTileReg[4][3];
UINT8* CaveTileROM[4] = { NULL, };
UINT8* CaveTileRAM[4] = { NULL, };
static INT8* CaveTileAttrib[4] = { NULL, };
INT32 nCaveTileBank = 0;
// Used when row-select mode is enabled
static INT32* pRowScroll[4] = { NULL, };
static INT32* pRowSelect[4] = { NULL, };
static INT32 nLayerXOffset[4];
static INT32 nLayerYOffset;
static INT32 nPaletteOffset[4];
static INT32 nPaletteSize[4];
static INT32 CaveTileCount[4];
static INT32 CaveTileMax[4];
static INT32 nTileMask[4];
static UINT8* pTile;
static UINT32* pTileData;
static UINT32* pTilePalette;
static INT32* pTileRowInfo;
typedef void (*RenderTileFunction)();
static RenderTileFunction* RenderTile;
static INT32 nTileXPos, nTileYPos, nRowOffset;
static INT32 nClipX8, nClipX16;
static INT32 nClipY8, nClipY16;
// Include the tile rendering functions
#include "cave_tile_func.h"
static void CaveQueue8x8Layer_Normal(INT32 nLayer)
{
INT32 x, y;
INT32 bx, by, cx, cy, mx;
INT32 nTileColumn, nTileRow;
UINT32 nTileNumber;
UINT8* pTileRAM = CaveTileRAM[nLayer];
UINT32 nTileOffset = 0;
if (nCaveTileBank) {
nTileOffset = 0x040000;
}
mx = (nCaveXSize >> 3) << 2;
bx = CaveTileReg[nLayer][0] - 0x0A + nLayerXOffset[nLayer];
bx &= 0x01FF;
cx = (bx >> 3) << 2;
bx &= 0x0007;
by = CaveTileReg[nLayer][1] + nLayerYOffset;
by &= 0x01FF;
cy = (by >> 3) << 8;
by &= 0x0007;
for (y = 0; y < (31 << 8); y += (1 << 8)) {
nTileRow = (cy + y) & (0x3F << 8);
nTileYPos = (y >> 5) - by;
if (nTileYPos <= -8 || nTileYPos >= nCaveYSize) {
continue;
}
for (x = mx; x >= 0; x -= (1 << 2)) {
nTileColumn = (cx + x) & (0x3F << 2);
nTileNumber = *((UINT16*)(pTileRAM + 0x4000 + nTileRow + nTileColumn)) << 16;
nTileNumber |= *((UINT16*)(pTileRAM + 0x4002 + nTileRow + nTileColumn));
nTileNumber |= nTileOffset;
if (CaveTileAttrib[nLayer][nTileNumber & nTileMask[nLayer]]) {
continue;
}
nTileXPos = (x << 1) - bx;
if (nTileXPos <= -8 || nTileXPos >= nCaveXSize) {
continue;
}
CaveTileQueue[nLayer][nTileNumber >> 30]->x = nTileXPos;
CaveTileQueue[nLayer][nTileNumber >> 30]->y = nTileYPos;
CaveTileQueue[nLayer][nTileNumber >> 30]->tile = nTileNumber;
CaveTileQueue[nLayer][nTileNumber >> 30]++;
}
}
return;
}
static void Cave8x8Layer_Normal(INT32 nLayer, UINT32 nPriority)
{
UINT32 nTileNumber;
UINT32* pPalette = CavePalette + nPaletteOffset[nLayer];
UINT32 nPaletteMask = 0x3F000000;
if (nPaletteSize[nLayer] == 6) {
nPaletteMask = 0x0F000000;
}
INT32 nPaletteShift = 24 - nPaletteSize[nLayer];
CaveTile* TileQueue = CaveTileQueue[nLayer][nPriority];
while ((nTileXPos = TileQueue->x) < 9999) {
nTileYPos = TileQueue->y;
nTileNumber = TileQueue->tile;
pTilePalette = pPalette + ((nTileNumber & nPaletteMask) >> nPaletteShift);
nTileNumber &= nTileMask[nLayer];
pTile = pBurnDraw + (nTileYPos * nBurnPitch) + (nTileXPos * nBurnBpp);
pTileData = (UINT32*)(CaveTileROM[nLayer] + (nTileNumber << 6));
if (nTileYPos < 0 || nTileYPos > nClipY8 || nTileXPos < 0 || nTileXPos > nClipX8) {
RenderTile[1]();
} else {
RenderTile[0]();
}
TileQueue++;
}
return;
}
static void Cave8x8Layer_RowScroll(INT32 nLayer, UINT32 nPriority)
{
INT32 x, y;
INT32 bx, by, cy;
INT32 nTileColumn, nTileRow;
UINT32 nTileNumber;
UINT8* pTileRAM = CaveTileRAM[nLayer];
UINT32* pPalette = CavePalette + nPaletteOffset[nLayer];
INT32 nPaletteShift = 24 - nPaletteSize[nLayer];
INT32* rowscroll = pRowScroll[nLayer];
INT32 count = CaveTileCount[nLayer];
if (count >= (64 * 31)) {
return;
}
UINT32 nTileOffset = 0;
if (nCaveTileBank) {
nTileOffset = 0x040000;
}
bx = CaveTileReg[nLayer][0] - 0x0A + nLayerXOffset[nLayer];
bx &= 0x01FF;
by = CaveTileReg[nLayer][1] + nLayerYOffset;
by &= 0x01FF;
cy = (by >> 3) << 8;
by &= 0x0007;
if (nPriority == 0) {
INT32 dy = CaveTileReg[nLayer][1] + 0x12 - nCaveRowModeOffset;
for (y = 0; y < nCaveYSize; y++) {
rowscroll[y] = *((UINT16*)(pTileRAM + 0x1000 + (((dy + y) & 0x01FF) << 2))) + bx;
}
}
for (y = 0; y < (31 << 8); y += (1 << 8)) {
nTileYPos = (y >> 5) - by;
nTileRow = (cy + y) & (0x3F << 8);
pTileRowInfo = rowscroll + nTileYPos;
for (x = 0; x < (64 << 2); x += (1 << 2)) {
nTileColumn = x & (0x3F << 2);
nTileNumber = *((UINT16*)(pTileRAM + 0x4000 + nTileRow + nTileColumn)) << 16;
if ((nTileNumber >> 30) != nPriority) {
continue;
}
nTileNumber |= *((UINT16*)(pTileRAM + 0x4002 + nTileRow + nTileColumn));
pTilePalette = pPalette + ((nTileNumber & 0x3F000000) >> nPaletteShift);
nTileNumber |= nTileOffset;
nTileNumber &= nTileMask[nLayer];
count++;
if (nTileYPos <= -8 || nTileYPos >= nCaveYSize) {
continue;
}
if (*((UINT32*)(CaveTileAttrib[nLayer] + nTileNumber))) {
continue;
}
nTileXPos = (x << 1);
pTile = pBurnDraw + (nTileYPos * nBurnPitch);
pTileData = (UINT32*)(CaveTileROM[nLayer] + (nTileNumber << 6));
if (nTileYPos < 0 || nTileYPos > nClipY8 || nTileXPos < 0 || nTileXPos > nClipX8) {
RenderTile[3]();
} else {
RenderTile[2]();
}
}
}
if (count >= (64 * 31)) {
CaveTileMax[0] -= 0x0123;
CaveTileMax[1] -= 0x0123;
CaveTileMax[2] -= 0x0123;
CaveTileMax[3] -= 0x0123;
}
CaveTileCount[nLayer] = count;
return;
}
static void CaveQueue16x16Layer_Normal(INT32 nLayer)
{
INT32 x, y;
INT32 bx, by, cx, cy, mx;
INT32 nTileColumn, nTileRow;
UINT32 nTileNumber;
UINT8* pTileRAM = CaveTileRAM[nLayer];
mx = (nCaveXSize >> 4) << 2;
bx = CaveTileReg[nLayer][0] - 0x12 + nLayerXOffset[nLayer];
bx &= 0x01FF;
cx = (bx >> 4) << 2;
bx &= 0x000F;
by = CaveTileReg[nLayer][1] + nLayerYOffset;
by &= 0x01FF;
cy = (by >> 4) << 7;
by &= 0x000F;
for (y = 0; y < (16 << 7); y += (1 << 7)) {
nTileRow = (cy + y) & (0x1F << 7);
nTileYPos = (y >> 3) - by;
if (nTileYPos <= -16 || nTileYPos >= nCaveYSize) {
continue;
}
for (x = mx; x >= 0; x -= (1 << 2)) {
nTileColumn = (cx + x) & (0x1F << 2);
nTileNumber = *((UINT16*)(pTileRAM + 0x0000 + nTileRow + nTileColumn)) << 16;
nTileNumber |= *((UINT16*)(pTileRAM + 0x0002 + nTileRow + nTileColumn));
if (*((UINT32*)(CaveTileAttrib[nLayer] + ((nTileNumber << 2) & nTileMask[nLayer]))) == 0x01010101) {
continue;
}
nTileXPos = (x << 2) - bx;
if (nTileXPos <= -16 || nTileXPos >= nCaveXSize) {
continue;
}
CaveTileQueue[nLayer][nTileNumber >> 30]->x = nTileXPos;
CaveTileQueue[nLayer][nTileNumber >> 30]->y = nTileYPos;
CaveTileQueue[nLayer][nTileNumber >> 30]->tile = nTileNumber;
CaveTileQueue[nLayer][nTileNumber >> 30]++;
}
}
return;
}
static void Cave16x16Layer_Normal(INT32 nLayer, UINT32 nPriority)
{
UINT32 nTileNumber, nAttrib;
UINT32* pTileStart;
UINT32* pPalette = CavePalette + nPaletteOffset[nLayer];
INT32 nPaletteShift = 24 - nPaletteSize[nLayer];
UINT32 nPaletteMask = 0x3F000000;
if (nPaletteSize[nLayer] == 6) {
nPaletteMask = 0x0F000000;
}
CaveTile* TileQueue = CaveTileQueue[nLayer][nPriority];
while ((nTileXPos = TileQueue->x) < 9999) {
nTileYPos = TileQueue->y;
nTileNumber = TileQueue->tile;
pTilePalette = pPalette + ((nTileNumber & nPaletteMask) >> nPaletteShift);
nTileNumber <<= 2;
nTileNumber &= nTileMask[nLayer];
nAttrib = *((UINT32*)(CaveTileAttrib[nLayer] + nTileNumber));
pTile = pBurnDraw + (nTileYPos * nBurnPitch) + (nTileXPos * nBurnBpp);
pTileStart = (UINT32*)(CaveTileROM[nLayer] + (nTileNumber << 6));
if (nTileXPos < 0 || nTileXPos > nClipX16 || nTileYPos < 0 || nTileYPos > nClipY16) {
if ((nAttrib & 0x000000FF) == 0) {
pTileData = pTileStart;
if (nTileXPos > -8 && nTileXPos < nCaveXSize && nTileYPos > -8 && nTileYPos < nCaveYSize) {
if (nTileXPos >= 0 && nTileXPos <= nClipX8 && nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[0]();
} else {
RenderTile[1]();
}
}
}
nTileXPos += 8;
pTile += 8 * nBurnBpp;
if ((nAttrib & 0x0000FF00) == 0) {
if (nTileXPos > -8 && nTileXPos < nCaveXSize && nTileYPos > -8 && nTileYPos < nCaveYSize) {
pTileData = pTileStart + 16;
if (nTileXPos >= 0 && nTileXPos <= nClipX8 && nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[0]();
} else{
RenderTile[1]();
}
}
}
nTileXPos -= 8;
nTileYPos += 8;
pTile = pBurnDraw + (nTileYPos * nBurnPitch) + (nTileXPos * nBurnBpp);
if ((nAttrib & 0x00FF0000) == 0) {
if (nTileXPos > -8 && nTileXPos < nCaveXSize && nTileYPos > -8 && nTileYPos < nCaveYSize) {
pTileData = pTileStart + 32;
if (nTileXPos >= 0 && nTileXPos <= nClipX8 && nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[0]();
} else {
RenderTile[1]();
}
}
}
nTileXPos += 8;
pTile += 8 * nBurnBpp;
if ((nAttrib & 0xFF000000) == 0) {
if (nTileXPos > -8 && nTileXPos < nCaveXSize && nTileYPos > -8 && nTileYPos < nCaveYSize) {
pTileData = pTileStart + 48;
if (nTileXPos >= 0 && nTileXPos <= nClipX8 && nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[0]();
} else {
RenderTile[1]();
}
}
}
} else {
if ((nAttrib & 0x000000FF) == 0) {
pTileData = pTileStart;
RenderTile[0]();
}
nTileXPos += 8;
pTile += 8 * nBurnBpp;
if ((nAttrib & 0x0000FF00) == 0) {
pTileData = pTileStart + 16;
RenderTile[0]();
}
nTileXPos -= 8;
nTileYPos += 8;
pTile = pBurnDraw + (nTileYPos * nBurnPitch) + (nTileXPos * nBurnBpp);
if ((nAttrib & 0x00FF0000) == 0) {
pTileData = pTileStart + 32;
RenderTile[0]();
}
nTileXPos += 8;
pTile += 8 * nBurnBpp;
if ((nAttrib & 0xFF000000) == 0) {
pTileData = pTileStart + 48;
RenderTile[0]();
}
}
TileQueue++;
}
return;
}
static void Cave16x16Layer_RowScroll(INT32 nLayer, UINT32 nPriority)
{
INT32 x, y;
INT32 bx, by, cy;
INT32 nTileColumn, nTileRow;
UINT32 nTileNumber, nAttrib;
UINT32* pTileStart;
UINT8* pTileRAM = CaveTileRAM[nLayer];
UINT32* pPalette = CavePalette + nPaletteOffset[nLayer];
INT32 nPaletteShift = 24 - nPaletteSize[nLayer];
UINT32 nPaletteMask = 0x3F000000;
if (nPaletteSize[nLayer] == 6) {
nPaletteMask = 0x0F000000;
}
INT32* rowscroll = pRowScroll[nLayer];
INT32 count = CaveTileCount[nLayer];
if (count >= (32 * 16)) {
return;
}
bx = CaveTileReg[nLayer][0] - 0x12 + nLayerXOffset[nLayer];
bx &= 0x01FF;
by = CaveTileReg[nLayer][1] + nLayerYOffset;
by &= 0x01FF;
cy = (by >> 4) << 7;
by &= 0x000F;
if (nPriority == 0) {
INT32 dy = CaveTileReg[nLayer][1] + 0x12 - nCaveRowModeOffset;
for (y = 0; y < nCaveYSize; y++) {
rowscroll[y] = *((UINT16*)(pTileRAM + 0x1000 + (((dy + y) & 0x01FF) << 2))) + bx;
}
}
for (y = 0; y < (16 << 7); y += (1 << 7)) {
nTileRow = (cy + y) & (0x1F << 7);
nTileYPos = (y >> 3) - by;
pTileRowInfo = rowscroll + nTileYPos;
for (x = 0; x < (32 << 2); x += (1 << 2)) {
nTileColumn = x & (0x1F << 2);
nTileNumber = *((UINT16*)(pTileRAM + 0x0000 + nTileRow + nTileColumn)) << 16;
if ((nTileNumber >> 30) != nPriority) {
continue;
}
nTileNumber |= *((UINT16*)(pTileRAM + 0x0002 + nTileRow + nTileColumn));
pTilePalette = pPalette + ((nTileNumber & nPaletteMask) >> nPaletteShift);
nTileNumber <<= 2;
nTileNumber &= nTileMask[nLayer];
count++;
nAttrib = *((UINT32*)(CaveTileAttrib[nLayer] + nTileNumber));
if (nAttrib == 0x01010101) {
continue;
}
nTileXPos = (x << 2);
pTile = pBurnDraw + (nTileYPos * nBurnPitch);
pTileStart = (UINT32*)(CaveTileROM[nLayer] + (nTileNumber << 6));
if (nTileYPos < 0 || nTileYPos > nClipY16) {
if ((nAttrib & 0x000000FF) == 0) {
pTileData = pTileStart;
if (nTileYPos > -8 && nTileYPos < nCaveYSize) {
if (nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[2]();
} else {
RenderTile[3]();
}
}
}
nTileXPos += 8;
if ((nAttrib & 0x0000FF00) == 0) {
if (nTileYPos > -8 && nTileYPos < nCaveYSize) {
pTileData = pTileStart + 16;
if (nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[2]();
} else {
RenderTile[3]();
}
}
}
nTileXPos -= 8;
nTileYPos += 8;
pTileRowInfo += 8;
pTile = pBurnDraw + (nTileYPos * nBurnPitch);
if ((nAttrib & 0x00FF0000) == 0) {
if (nTileYPos > -8 && nTileYPos < nCaveYSize) {
pTileData = pTileStart + 32;
if (nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[2]();
} else {
RenderTile[3]();
}
}
}
nTileXPos += 8;
if ((nAttrib & 0xFF000000) == 0) {
if (nTileYPos > -8 && nTileYPos < nCaveYSize) {
pTileData = pTileStart + 48;
if (nTileYPos >= 0 && nTileYPos <= nClipY8) {
RenderTile[2]();
} else {
RenderTile[3]();
}
}
}
} else {
if ((nAttrib & 0x000000FF) == 0) {
pTileData = pTileStart;
RenderTile[2]();
}
nTileXPos += 8;
if ((nAttrib & 0x0000FF00) == 0) {
pTileData = pTileStart + 16;
RenderTile[2]();
}
nTileXPos -= 8;
nTileYPos += 8;
pTileRowInfo += 8;
pTile = pBurnDraw + (nTileYPos * nBurnPitch);
if ((nAttrib & 0x00FF0000) == 0) {
pTileData = pTileStart + 32;
RenderTile[2]();
}
nTileXPos += 8;
if ((nAttrib & 0xFF000000) == 0) {
pTileData = pTileStart + 48;
RenderTile[2]();
}
}
nTileYPos -= 8;
pTileRowInfo -= 8;
}
}
if (count >= (32 * 16)) {
CaveTileMax[0] -= 0x0123;
CaveTileMax[1] -= 0x0123;
CaveTileMax[2] -= 0x0123;
CaveTileMax[3] -= 0x0123;
}
CaveTileCount[nLayer] = count;
return;
}
static void Cave16x16Layer_RowSelect(INT32 nLayer, UINT32 nPriority)
{
INT32 x, y, ry, rx;
INT32 bx, by, mx;
INT32 nTileColumn, nTileRow;
UINT32 nTileNumber;
UINT32* pTileStart;
UINT8* pTileRAM = CaveTileRAM[nLayer];
UINT32* pPalette = CavePalette + nPaletteOffset[nLayer];
INT32 nPaletteShift = 24 - nPaletteSize[nLayer];
UINT32 nPaletteMask = 0x3F000000;
if (nPaletteSize[nLayer] == 6) {
nPaletteMask = 0x0F000000;
}
INT32* rowselect = pRowSelect[nLayer];
INT32* rowscroll = pRowScroll[nLayer];
INT32 count = CaveTileCount[nLayer];
mx = nCaveXSize >> 4;
if (count >= nCaveYSize * (mx + 1)) {
return;
}
bx = CaveTileReg[nLayer][0] - 0x12 + nLayerXOffset[nLayer];
bx &= 0x01FF;
by = CaveTileReg[nLayer][1] + nLayerYOffset;
by &= 0x01FF;
if (nPriority == 0) {
INT32 cy = CaveTileReg[nLayer][1] + 0x12 - nCaveRowModeOffset;
if (CaveTileReg[nLayer][0] & 0x4000) { // Row-scroll mode
for (y = 0; y < nCaveYSize; y++) {
rowselect[y] = *((UINT16*)(pTileRAM + 0x1002 + (((cy + y) & 0x01FF) << 2)));
rowscroll[y] = *((UINT16*)(pTileRAM + 0x1000 + (((cy + y) & 0x01FF) << 2))) + bx;
}
} else {
for (y = 0; y < nCaveYSize; y++) {
rowselect[y] = *((UINT16*)(pTileRAM + 0x1002 + (((cy + y) & 0x01FF) << 2)));
}
}
}
for (y = 0; y < nCaveYSize; y++) {
ry = rowselect[y];
nTileRow = ((ry >> 4) & 0x1F) << 7;
nTileYPos = y;
if (CaveTileReg[nLayer][0] & 0x4000) { // Row-scroll mode
rx = rowscroll[y];
ry = (((ry & 8) << 1) + (ry & 7)) << 1;
for (x = 0; x <= mx; x++) {
nTileColumn = (((rx >> 4) + x) & 0x1F) << 2;
nTileNumber = *((UINT16*)(pTileRAM + 0x0000 + nTileRow + nTileColumn)) << 16;
if ((nTileNumber >> 30) != nPriority) {
continue;
}
nTileNumber |= *((UINT16*)(pTileRAM + 0x0002 + nTileRow + nTileColumn));
pTilePalette = pPalette + ((nTileNumber & nPaletteMask) >> nPaletteShift);
nTileNumber &= nTileMask[nLayer];
count++;
if (((UINT32*)CaveTileAttrib[nLayer])[nTileNumber] == 0x01010101) {
continue;
}
nTileXPos = (x << 4) - (rx & 15);
if (nTileXPos <= -16 || nTileXPos >= nCaveXSize) {
continue;
}
pTile = pBurnDraw + (nTileYPos * nBurnPitch) + (nTileXPos * nBurnBpp);
pTileStart = (UINT32*)(CaveTileROM[nLayer] + (nTileNumber << 8));
pTileStart += ry;
pTileData = pTileStart;
if (nTileXPos >= 0 && nTileXPos <= nClipX8) {
RenderTile[4]();
} else {
RenderTile[5]();
}
nTileXPos += 8;
pTile += (nBurnBpp << 3);
pTileData = pTileStart + 16;
if (nTileXPos >= 0 && nTileXPos <= nClipX16) {
RenderTile[4]();
} else {
RenderTile[5]();
}
}
} else {
nTileXPos = - (bx & 15);
pTile = pBurnDraw + (nTileYPos * nBurnPitch) - ((bx & 15) * nBurnBpp);
ry = (((ry & 8) << 1) + (ry & 7)) << 1;
for (x = 0; x <= mx; x++) {
nTileColumn = (((bx >> 4) + x) & 0x1F) << 2;
nTileNumber = *((UINT16*)(pTileRAM + 0x0000 + nTileRow + nTileColumn)) << 16;
if ((nTileNumber >> 30) != nPriority) {
nTileXPos += 16;
pTile += (nBurnBpp << 4);
continue;
}
nTileNumber |= *((UINT16*)(pTileRAM + 0x0002 + nTileRow + nTileColumn));
pTilePalette = pPalette + ((nTileNumber & nPaletteMask) >> nPaletteShift);
nTileNumber &= nTileMask[nLayer];
count++;
if (((UINT32*)CaveTileAttrib[nLayer])[nTileNumber] == 0x01010101) {
nTileXPos += 16;
pTile += (nBurnBpp << 4);
continue;
}
pTileStart = (UINT32*)(CaveTileROM[nLayer] + (nTileNumber << 8));
pTileStart += ry;
pTileData = pTileStart;
if (nTileXPos >= 0 && nTileXPos <= nClipX8) {
RenderTile[4]();
} else {
RenderTile[5]();
}
nTileXPos += 8;
pTile += (nBurnBpp << 3);
pTileData = pTileStart + 16;
if (nTileXPos >= 0 && nTileXPos <= nClipX8) {
RenderTile[4]();
} else {
RenderTile[5]();
}
nTileXPos += 8;
pTile += (nBurnBpp << 3);
}
}
}
if (count >= nCaveYSize * (mx + 1)) {
CaveTileMax[0] -= 0x0123;
CaveTileMax[1] -= 0x0123;
CaveTileMax[2] -= 0x0123;
CaveTileMax[3] -= 0x0123;
}
CaveTileCount[nLayer] = count;
return;
}
static void Cave16x16Layer(INT32 nLayer, UINT32 nPriority)
{
if (CaveTileReg[nLayer][1] & 0x4000) { // Row-select mode
Cave16x16Layer_RowSelect(nLayer, nPriority);
// bprintf(PRINT_NORMAL, " Layer %d row-select mode enabled (16x16)\n", nLayer);
return;
}
if (CaveTileReg[nLayer][0] & 0x4000) { // Row-scroll mode
Cave16x16Layer_RowScroll(nLayer, nPriority);
// bprintf(PRINT_NORMAL, " Layer %d row-scroll mode enabled (16x16)\n", nLayer);
return;
}
Cave16x16Layer_Normal(nLayer, nPriority);
return;
}
static void Cave8x8Layer(INT32 nLayer, UINT32 nPriority)
{
#if 0
if (CaveTileReg[nLayer][1] & 0x4000) { // Row-select mode
Cave8x8Layer_RowSelect(nLayer, nPriority);
// bprintf(PRINT_NORMAL, " Layer %d row-select mode enabled ( 8x 8)\n", nLayer);
return;
}
#else
if (CaveTileReg[nLayer][1] & 0x4000) {
// bprintf(PRINT_ERROR, " Layer %d row-select mode enabled ( 8x 8, UNSUPPORTED!)\n", nLayer);
}
#endif
if (CaveTileReg[nLayer][0] & 0x4000) { // Row-scroll mode
Cave8x8Layer_RowScroll(nLayer, nPriority);
// bprintf(PRINT_NORMAL, " Layer %d row-scroll mode enabled ( 8x 8)\n", nLayer);
return;
}
Cave8x8Layer_Normal(nLayer, nPriority);
return;
}
INT32 CaveTileRender(INT32 nMode)
{
UINT32 nPriority;
INT32 nLowPriority;
INT32 nLayer;
INT32 nOffset = 0;
CaveTileCount[0] = CaveTileCount[1] = CaveTileCount[2] = CaveTileCount[3] = 0;
CaveTileMax[0] = CaveTileMax[1] = CaveTileMax[2] = CaveTileMax[3] = 0;
nLayerYOffset = 0x12 - nCaveYOffset - nCaveExtraYOffset;
for (nLayer = 0; nLayer < 4; nLayer++) {
nLayerXOffset[nLayer] = nLayer + nOffset - nCaveXOffset - nCaveExtraXOffset;
if ((CaveTileReg[nLayer][2] & 0x0010) == 0) {
for (nPriority = 0; nPriority < 4; nPriority++) {
CaveTileQueue[nLayer][nPriority] = &CaveTileQueueMemory[nLayer][nPriority * 1536];
}
if (nBurnLayer & (8 >> nLayer)) {
if (CaveTileReg[nLayer][1] & 0x2000) {
if (nMode && ((CaveTileReg[nLayer][0] | CaveTileReg[nLayer][1]) & 0x4000)) {
CaveTileMax[0] += 0x0123;
CaveTileMax[1] += 0x0123;
CaveTileMax[2] += 0x0123;
CaveTileMax[3] += 0x0123;
} else {
CaveQueue16x16Layer_Normal(nLayer);
}
} else {
if (nMode && (CaveTileReg[nLayer][0] & 0x4000)) {
CaveTileMax[0] += 0x0123;
CaveTileMax[1] += 0x0123;
CaveTileMax[2] += 0x0123;
CaveTileMax[3] += 0x0123;
} else {
CaveQueue8x8Layer_Normal(nLayer);
}
// nOffset += 8;
}
}
for (nPriority = 0; nPriority < 4; nPriority++) {
CaveTileQueue[nLayer][nPriority]->x = 9999;
CaveTileQueue[nLayer][nPriority] = &CaveTileQueueMemory[nLayer][nPriority * 1536];
if (CaveTileQueue[nLayer][nPriority]->x < 9999) {
CaveTileMax[nPriority] += 0x123;
}
}
}
}
nLowPriority = 0;
for (nPriority = 0; nPriority < 4; nPriority++) {
if (CaveTileMax[nPriority] || nPriority == 3) {
CaveSpriteRender(nLowPriority, nPriority);
nLowPriority = nPriority + 1;
}
for (UINT32 i = 0; i < 4; i++) {
for (nLayer = 0; nLayer < 4; nLayer++) {
if ((CaveTileReg[nLayer][2] & 0x0003) == i) {
if ((CaveTileReg[nLayer][2] & 0x0010) || (nBurnLayer & (8 >> nLayer)) == 0) {
continue;
}
if (CaveTileReg[nLayer][1] & 0x2000) {
if (nMode) {
Cave16x16Layer(nLayer, nPriority);
} else {
Cave16x16Layer_Normal(nLayer, nPriority);
}
} else {
if (nMode) {
Cave8x8Layer(nLayer, nPriority);
} else {
Cave8x8Layer_Normal(nLayer, nPriority);
}
}
}
}
}
}
return 0;
}
void CaveTileExit()
{
for (INT32 nLayer = 0; nLayer < 4; nLayer++) {
if (CaveTileAttrib[nLayer]) {
free(CaveTileAttrib[nLayer]);
CaveTileAttrib[nLayer] = NULL;
}
if (CaveTileQueueMemory[nLayer]) {
free(CaveTileQueueMemory[nLayer]);
CaveTileQueueMemory[nLayer] = NULL;
}
if (pRowScroll[nLayer]) {
free(pRowScroll[nLayer]);
pRowScroll[nLayer] = NULL;
}
if (pRowSelect[nLayer]) {
free(pRowSelect[nLayer]);
pRowSelect[nLayer] = NULL;
}
}
nCaveXOffset = nCaveYOffset = 0;
nCaveRowModeOffset = 0;
nCaveExtraXOffset = nCaveExtraYOffset = 0;
return;
}
INT32 CaveTileInit()
{
for (INT32 nLayer = 0; nLayer < 4; nLayer++) {
CaveTileReg[nLayer][0] = 0x0000;
CaveTileReg[nLayer][1] = 0x0000;
CaveTileReg[nLayer][2] = 0x0010; // Disable layer
}
nCaveTileBank = 0;
BurnDrvGetFullSize(&nCaveXSize, &nCaveYSize);
nClipX8 = nCaveXSize - 8;
nClipX16 = nCaveXSize - 16;
nClipY8 = nCaveYSize - 8;
nClipY16 = nCaveYSize - 16;
RenderTile = RenderTile_ROT0[(nCaveXSize == 320) ? 0 : 1];
return 0;
}
INT32 CaveTileInitLayer(INT32 nLayer, INT32 nROMSize, INT32 nBitdepth, INT32 nOffset)
{
INT32 nTileSize = (8 << 3);
INT32 nNumTiles = nROMSize / nTileSize;
for (nTileMask[nLayer] = 1; nTileMask[nLayer] < nNumTiles; nTileMask[nLayer] <<= 1) { }
nTileMask[nLayer]--;
if (CaveTileAttrib[nLayer]) {
free(CaveTileAttrib[nLayer]);
}
CaveTileAttrib[nLayer] = (INT8*)malloc(nTileMask[nLayer] + 1);
if (CaveTileAttrib[nLayer] == NULL) {
return 1;
}
for (INT32 i = 0; i < nNumTiles; i++) {
bool bTransparent = true;
for (INT32 j = i * nTileSize; j < (i + 1) * nTileSize; j++) {
if (CaveTileROM[nLayer][j]) {
bTransparent = false;
break;
}
}
if (bTransparent) {
CaveTileAttrib[nLayer][i] = 1;
} else {
CaveTileAttrib[nLayer][i] = 0;
}
}
for (INT32 i = nNumTiles; i <= nTileMask[nLayer]; i++) {
CaveTileAttrib[nLayer][i] = 1;
}
if (CaveTileQueueMemory[nLayer]) {
free(CaveTileQueueMemory[nLayer]);
}
CaveTileQueueMemory[nLayer] = (CaveTile*)malloc(4 * 1536 * sizeof(CaveTile));
if (CaveTileQueueMemory[nLayer] == NULL) {
return 1;
}
if (pRowScroll[nLayer]) {
free(pRowScroll[nLayer]);
}
pRowScroll[nLayer] = (INT32*)malloc(nCaveYSize * sizeof(INT32));
if (pRowScroll[nLayer] == NULL) {
return 1;
}
if (pRowSelect[nLayer]) {
free(pRowSelect[nLayer]);
}
pRowSelect[nLayer] = (INT32*)malloc(nCaveYSize * sizeof(INT32));
if (pRowSelect[nLayer] == NULL) {
return 1;
}
nPaletteSize[nLayer] = nBitdepth;
nPaletteOffset[nLayer] = nOffset;
CaveTileReg[nLayer][2] = 0x0000; // Enable layer
return 0;
}

View File

@ -0,0 +1,370 @@
// Graphics format: 8 × 8 pixel tiles, 4/8 bits/pixel.
// Create a unique name for each of the functions
#define FN(a,b,c,d,e,f,g,h) RenderTile ## a ## _ ## b ## _ROT ## c ## d ## e ## f ## g ## h
#define FUNCTIONNAME(a,b,c,d,e,f,g,h) FN(a,b,c,d,e,f,g,h)
#if ROT == 0
#if XFLIP == 0
#define ADVANCECOLUMN pPixel += (BPP >> 3)
#else
#error illegal XFLIP value
#endif
#if YFLIP == 0
#define ADVANCEROW pTileRow += ((BPP >> 3) * XSIZE)
#else
#error illegal YFLIP value
#endif
#else
#error unsupported rotation angle specified
#endif
#if DOCLIP == 0
#define CLIP _NOCLIP
#elif DOCLIP == 1
#define CLIP _CLIP
#else
#error illegal doclip value.
#endif
#if EIGHTBIT == 0
#define DEPTH _16
#elif EIGHTBIT == 1
#define DEPTH _256
#else
#error illegal eightbit value
#endif
#define TESTCOLOUR(x) x
#if BPP == 16
#define PLOTPIXEL(a) if (TESTCOLOUR(a)) { \
*((UINT16*)pPixel) = (UINT16)pTilePalette[a]; \
}
#elif BPP == 24
#define PLOTPIXEL(a) if (TESTCOLOUR(a)) { \
UINT32 nRGB = pTilePalette[a]; \
pPixel[0] = (UINT8)nRGB; \
pPixel[1] = (UINT8)(nRGB >> 8); \
pPixel[2] = (UINT8)(nRGB >> 16); \
}
#elif BPP == 32
#define PLOTPIXEL(a) if (TESTCOLOUR(a)) { \
*((UINT32*)pPixel) = (UINT32)pTilePalette[a]; \
}
#else
#error unsupported bitdepth specified.
#endif
// For decorating the function name
#if XFLIP == 1
#if YFLIP == 1
#define FLIP _FLIPXY
#else
#define FLIP _FLIPX
#endif
#elif YFLIP == 1
#define FLIP _FLIPY
#else
#define FLIP _NOFLIP
#endif
#if ROWSELECT == 0
#define SELECT _NOROWSELECT
#elif ROWSELECT == 1
#define SELECT _ROWSELECT
#else
#error unsupported rowselect mode specified.
#endif
#if ROWSCROLL == 0
#define SCROLL _NOROWSCROLL
#elif ROWSCROLL == 1
#define SCROLL _ROWSCROLL
#else
#error unsupported rowscroll mode specified.
#endif
static void FUNCTIONNAME(BPP,XSIZE,ROT,FLIP,SCROLL,SELECT,CLIP,DEPTH)()
{
// Create an empty function if unsupported features are requested
#if ROT == 0 && XFLIP == 0 && YFLIP == 0 && !(ROWSCROLL == 1 && ROWSELECT == 1) && EIGHTBIT == 1
UINT8 *pTileRow, *pPixel;
INT32 nColour;
#if ROWSELECT == 0
INT32 y;
#endif
#if ROWSELECT == 0
for (y = 0, pTileRow = pTile; y < 8; y++, ADVANCEROW) {
#if DOCLIP == 1
if (nTileYPos + y < 0) {
#if EIGHTBIT == 0
pTileData++;
#else
pTileData += 2;
#endif
continue;
}
if (nTileYPos + y >= nCaveYSize) {
return;
}
#endif
#else
pTileRow = pTile;
#endif
pPixel = pTileRow;
#if ROWSCROLL == 1
nRowOffset = (nTileXPos - pTileRowInfo[y]) & 0x01FF;
if (nRowOffset >= 0x01F8) {
nRowOffset -= 0x0200;
}
if (nRowOffset >= XSIZE) {
#if EIGHTBIT == 0
pTileData++;
#else
pTileData += 2;
#endif
continue;
}
pPixel += (BPP >> 3) * nRowOffset;
#endif
#if ROWSCROLL == 1
#define XPOS nRowOffset
#else
#define XPOS nTileXPos
#endif
#if EIGHTBIT == 0
#if DOCLIP == 1 || ROWSCROLL == 1
nColour = *pTileData++;
if (XPOS <= (XSIZE - 8)) {
if (XPOS < 0) {
nColour >>= -XPOS * 4;
pPixel += -XPOS * (BPP >> 3);
}
switch (XPOS < 0 ? -XPOS : 0) {
case 0:
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
case 1:
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
case 2:
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
case 3:
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
case 4:
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
case 5:
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
case 6:
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
case 7:
PLOTPIXEL(nColour & 0x0F);
}
} else {
#define CLIPPIXEL(a,b) if (XPOS < XSIZE - (a)) { b; }
CLIPPIXEL(0, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(1, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(2, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(3, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(4, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(5, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(6, PLOTPIXEL(nColour & 0xFF));
#undef CLIPPIXEL
}
#else
nColour = *pTileData++;
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
PLOTPIXEL(nColour & 0x0F);
ADVANCECOLUMN;
nColour >>= 4;
PLOTPIXEL(nColour & 0x0F);
#endif
#else
#if DOCLIP == 1 || ROWSCROLL == 1
nColour = pTileData[0];
if (XPOS <= (XSIZE - 8)) {
if (XPOS < 0) {
if (XPOS < -3) {
nColour = pTileData[1];
}
nColour >>= (-XPOS & 3) * 8;
pPixel += -XPOS * (BPP >> 3);
}
switch (XPOS < 0 ? -XPOS : 0) {
case 0:
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
case 1:
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
case 2:
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
case 3:
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour = pTileData[1];
case 4:
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
case 5:
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
case 6:
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
case 7:
PLOTPIXEL(nColour & 0xFF);
}
} else {
#define CLIPPIXEL(a,b) if (XPOS < XSIZE - (a)) { b; }
CLIPPIXEL(0, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(1, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(2, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(3, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour = pTileData[1];
CLIPPIXEL(4, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(5, PLOTPIXEL(nColour & 0xFF));
ADVANCECOLUMN;
nColour >>= 8;
CLIPPIXEL(6, PLOTPIXEL(nColour & 0xFF));
#undef CLIPPIXEL
}
pTileData += 2;
#else
nColour = *pTileData++;
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour = *pTileData++;
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
PLOTPIXEL(nColour & 0xFF);
ADVANCECOLUMN;
nColour >>= 8;
PLOTPIXEL(nColour & 0xFF);
#endif
#endif
#undef XPOS
#if ROWSELECT == 0
}
#endif
#endif
}
#undef FLIP
#undef CLIP
#undef PLOTPIXEL
#undef TESTCLIP
#undef TESTCOLOUR
#undef ADVANCEROW
#undef ADVANCECOLUMN
#undef SCROLL
#undef SELECT
#undef DEPTH
#undef FUNCTIONNAME
#undef FN

View File

@ -0,0 +1,676 @@
// DoDonpachi
#include "cave.h"
#include "ymz280b.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT32 nSpeedhack;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCurrentCPU;
static INT32 nCyclesDone[2];
static INT32 nCyclesTotal[2];
static INT32 nCyclesSegment;
static struct BurnInputInfo ddonpachInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(ddonpach)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall ddonpachReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300002:
case 0x300003: {
return YMZ280BReadStatus();
}
case 0x800000:
case 0x800001: {
UINT8 nRet = 6 | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800002:
case 0x800003:
case 0x800004:
case 0x800005:
case 0x800006:
case 0x800007: {
UINT8 nRet = 6 | nVideoIRQ;
return nRet;
}
case 0xD00000:
return (DrvInput[0] >> 8) ^ 0xFF;
case 0xD00001:
return (DrvInput[0] & 0xFF) ^ 0xFF;
case 0xD00002:
return ((DrvInput[1] >> 8) ^ 0xF7) | (EEPROMRead() << 3);
case 0xD00003:
return (DrvInput[1] & 0xFF) ^ 0xFF;
default: {
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
}
return 0;
}
UINT16 __fastcall ddonpachReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300002: {
return YMZ280BReadStatus();
}
case 0x800000: {
UINT16 nRet = 6 | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800002:
case 0x800004:
case 0x800006: {
UINT16 nRet = 6 | nVideoIRQ;
return nRet;
}
case 0xD00000:
return DrvInput[0] ^ 0xFFFF;
case 0xD00002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
}
return 0;
}
void __fastcall ddonpachWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x300001:
YMZ280BSelectRegister(byteValue);
return;
case 0x300003:
YMZ280BWriteRegister(byteValue);
return;
case 0xE00000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
return;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
}
void __fastcall ddonpachWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x300000:
YMZ280BSelectRegister(wordValue);
return;
case 0x300002:
YMZ280BWriteRegister(wordValue);
return;
case 0x800000:
nCaveXOffset = wordValue;
return;
case 0x800002:
nCaveYOffset = wordValue;
return;
case 0x800008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x900000:
CaveTileReg[0][0] = wordValue;
return;
case 0x900002:
CaveTileReg[0][1] = wordValue;
return;
case 0x900004:
CaveTileReg[0][2] = wordValue;
return;
case 0xA00000:
CaveTileReg[1][0] = wordValue;
return;
case 0xA00002:
CaveTileReg[1][1] = wordValue;
return;
case 0xA00004:
CaveTileReg[1][2] = wordValue;
return;
case 0xB00000:
CaveTileReg[2][0] = wordValue;
return;
case 0xB00002:
CaveTileReg[2][1] = wordValue;
return;
case 0xB00004:
CaveTileReg[2][2] = wordValue;
return;
case 0xE00000:
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
return;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
}
void __fastcall ddonpachWriteBytePalette(UINT32 sekAddress, UINT8 byteValue)
{
CavePalWriteByte(sekAddress & 0xFFFF, byteValue);
}
void __fastcall ddonpachWriteWordPalette(UINT32 sekAddress, UINT16 wordValue)
{
CavePalWriteWord(sekAddress & 0xFFFF, wordValue);
}
static void TriggerSoundIRQ(INT32 nStatus)
{
nSoundIRQ = nStatus ^ 1;
UpdateIRQStatus();
if (nIRQPending && nCurrentCPU != 0) {
nCyclesDone[0] += SekRun(0x0400);
}
}
static INT32 DrvExit()
{
YMZ280BExit();
EEPROMExit();
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
YMZ280BReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
YMZ280BReset();
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate8Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x7F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
#if 1 && defined USE_SPEEDHACKS
INT32 nCurrentPC = SekGetPC(-1) - nSpeedhack;
if (!nIRQPending && nCurrentPC >= 0 && nCurrentPC <= 12) {
return 1;
}
#endif
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// bprintf(PRINT_NORMAL, "\n");
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 10; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nNext;
// Render sound segment
if ((i & 1) == 0) {
if (pBurnSoundOut) {
INT32 nSegmentEnd = nBurnSoundLen * i / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
YMZ280BRender(pSoundBuf, nSegmentEnd - nSoundBufferPos);
nSoundBufferPos = nSegmentEnd;
}
}
// Run 68000
nCurrentCPU = 0;
nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = -1;
}
// Make sure the buffer is entirely filled.
{
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
YMZ280BRender(pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
CaveSpriteROM = Next; Next += 0x1000000;
CaveTileROM[0] = Next; Next += 0x400000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x400000; // Tile layer 1
CaveTileROM[2] = Next; Next += 0x200000; // Tile layer 2
YMZ280BROM = Next; Next += 0x400000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveTileRAM[2] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap2(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[1] = *pOrg & 15;
pDest[0] = *pOrg >> 4;
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 1, 2);
BurnLoadRom(Rom01 + 1, 0, 2);
BurnLoadRom(CaveSpriteROM + 0x000000, 2, 1);
BurnLoadRom(CaveSpriteROM + 0x200000, 3, 1);
BurnLoadRom(CaveSpriteROM + 0x400000, 4, 1);
BurnLoadRom(CaveSpriteROM + 0x600000, 5, 1);
BurnByteswap(CaveSpriteROM, 0x800000);
NibbleSwap2(CaveSpriteROM, 0x800000);
BurnLoadRom(CaveTileROM[0], 6, 1);
NibbleSwap2(CaveTileROM[0], 0x200000);
BurnLoadRom(CaveTileROM[1], 7, 1);
NibbleSwap2(CaveTileROM[1], 0x200000);
UINT8* pTemp = (UINT8*)malloc(0x200000);
BurnLoadRom(pTemp, 8, 1);
for (INT32 i = 0; i < 0x0100000; i++) {
CaveTileROM[2][(i << 1) + 1] = (pTemp[(i << 1) + 0] & 15) | ((pTemp[(i << 1) + 1] & 15) << 4);
CaveTileROM[2][(i << 1) + 0] = (pTemp[(i << 1) + 0] >> 4) | (pTemp[(i << 1) + 1] & 240);
}
if (pTemp) {
free(pTemp);
pTemp = NULL;
}
// Load YMZ280B data
BurnLoadRom(YMZ280BROM + 0x000000, 9, 1);
BurnLoadRom(YMZ280BROM + 0x200000, 10, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction); // scan 68000 states
YMZ280BScan();
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
}
if (nAction & ACB_WRITE) {
CaveRecalcPalette = 1;
}
return 0;
}
static const UINT8 default_eeprom[16] = {0x00,0x0C,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
if (!EEPROMAvailable()) EEPROMFill(default_eeprom,0, sizeof(default_eeprom));
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x0FFFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x400000, 0x40FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x500000, 0x507FFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x600000, 0x607FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2] + 0x4000, 0x700000, 0x703FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2] + 0x4000, 0x704000, 0x707FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2] + 0x4000, 0x708000, 0x70BFFF, SM_RAM);
SekMapMemory(CaveTileRAM[2] + 0x4000, 0x70C000, 0x70FFFF, SM_RAM);
SekMapMemory(CavePalSrc, 0xC00000, 0xC0FFFF, SM_ROM); // Palette RAM (write goes through handler)
SekMapHandler(1, 0xC00000, 0xC0FFFF, SM_WRITE); //
SekSetReadWordHandler(0, ddonpachReadWord);
SekSetReadByteHandler(0, ddonpachReadByte);
SekSetWriteWordHandler(0, ddonpachWriteWord);
SekSetWriteByteHandler(0, ddonpachWriteByte);
SekSetWriteWordHandler(1, ddonpachWriteWordPalette);
SekSetWriteByteHandler(1, ddonpachWriteBytePalette);
SekClose();
}
nCaveRowModeOffset = 1;
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(0, 0x1000000);
CaveTileInitLayer(0, 0x400000, 8, 0x4000);
CaveTileInitLayer(1, 0x400000, 8, 0x4000);
CaveTileInitLayer(2, 0x200000, 8, 0x4000);
YMZ280BInit(16934400, &TriggerSoundIRQ, 3);
bDrawScreen = true;
// US version: 0x0571AC - 0x0571B8
// Japan version: 0x056DF4 - 0x056E00
nSpeedhack = (strcmp(BurnDrvGetTextA(DRV_NAME), "ddonpach") == 0) ? 0x0571AC : 0x056DF4;
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo ddonpachRomDesc[] = {
{ "b1.u27", 0x080000, 0xB5CDC8D3, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "b2.u26", 0x080000, 0x6BBB063A, BRF_ESS | BRF_PRG }, // 1
{ "u50.bin", 0x200000, 0x14B260EC, BRF_GRA }, // 2 Sprite data
{ "u51.bin", 0x200000, 0xE7BA8CCE, BRF_GRA }, // 3
{ "u52.bin", 0x200000, 0x02492EE0, BRF_GRA }, // 4
{ "u53.bin", 0x200000, 0xCB4C10F0, BRF_GRA }, // 5
{ "u60.bin", 0x200000, 0x903096A7, BRF_GRA }, // 6 Layer 0 Tile data
{ "u61.bin", 0x200000, 0xD89B7631, BRF_GRA }, // 7 Layer 1 Tile data
{ "u62.bin", 0x200000, 0x292BFB6B, BRF_GRA }, // 8 Layer 2 Tile data
{ "u6.bin", 0x200000, 0x9DFDAFAF, BRF_SND }, // 9 YMZ280B (AD)PCM data
{ "u7.bin", 0x200000, 0x795B17D5, BRF_SND }, // 10
{ "eeprom-ddonpach.bin", 0x0080, 0x315fb546, BRF_OPT },
};
STD_ROM_PICK(ddonpach)
STD_ROM_FN(ddonpach)
// Rom information
static struct BurnRomInfo ddonpachjRomDesc[] = {
{ "u27.bin", 0x080000, 0x2432FF9B, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "u26.bin", 0x080000, 0x4F3A914A, BRF_ESS | BRF_PRG }, // 1
{ "u50.bin", 0x200000, 0x14B260EC, BRF_GRA }, // 2 Sprite data
{ "u51.bin", 0x200000, 0xE7BA8CCE, BRF_GRA }, // 3
{ "u52.bin", 0x200000, 0x02492EE0, BRF_GRA }, // 4
{ "u53.bin", 0x200000, 0xCB4C10F0, BRF_GRA }, // 5
{ "u60.bin", 0x200000, 0x903096A7, BRF_GRA }, // 6 Layer 0 Tile data
{ "u61.bin", 0x200000, 0xD89B7631, BRF_GRA }, // 7 Layer 1 Tile data
{ "u62.bin", 0x200000, 0x292BFB6B, BRF_GRA }, // 8 Layer 2 Tile data
{ "u6.bin", 0x200000, 0x9DFDAFAF, BRF_SND }, // 9 YMZ280B (AD)PCM data
{ "u7.bin", 0x200000, 0x795B17D5, BRF_SND }, // 10
{ "eeprom-ddonpach.bin", 0x0080, 0x315fb546, BRF_OPT },
};
STD_ROM_PICK(ddonpachj)
STD_ROM_FN(ddonpachj)
struct BurnDriver BurnDrvDoDonpachi = {
"ddonpach", NULL, NULL, NULL, "1997",
"DoDonPachi (International, master ver. 97/02/05)\0", NULL, "Atlus / Cave", "Cave",
L"\u6012\u9996\u9818\u8702 DoDonPachi (International, master ver. 97/02/05)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, ddonpachRomInfo, ddonpachRomName, NULL, NULL, ddonpachInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
struct BurnDriver BurnDrvDoDonpachiJ = {
"ddonpachj", "ddonpach", NULL, NULL, "1997",
"DoDonPachi (Japan, master ver. 97/02/05)\0", NULL, "Atlus / Cave", "Cave",
L"\u6012\u9996\u9818\u8702 DoDonPachi (Japan, master ver. 97/02/05)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, ddonpachjRomInfo, ddonpachjRomName, NULL, NULL, ddonpachInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};

View File

@ -0,0 +1,783 @@
// Donpachi
#include "cave.h"
#include "msm6295.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT32 nBankSize[2] = {0x200000, 0x300000};
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static struct BurnInputInfo donpachiInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(donpachi)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall donpachiReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x900000:
case 0x900001:
case 0x900002:
case 0x900003: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x900004:
case 0x900005: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x900006:
case 0x900007: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xB00001:
return MSM6295ReadStatus(0);
case 0xB00011:
return MSM6295ReadStatus(1);
case 0xC00000:
return (DrvInput[0] >> 8) ^ 0xFF;
case 0xC00001:
return (DrvInput[0] & 0xFF) ^ 0xFF;
case 0xC00002:
return ((DrvInput[1] >> 8) ^ 0xF7) | (EEPROMRead() << 3);
case 0xC00003:
return (DrvInput[1] & 0xFF) ^ 0xFF;
default: {
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
}
return 0;
}
UINT16 __fastcall donpachiReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x900000:
case 0x900002: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x900004: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x900006: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xB00000:
return MSM6295ReadStatus(0);
case 0xB00010:
return MSM6295ReadStatus(1);
case 0xC00000:
return DrvInput[0] ^ 0xFFFF;
case 0xC00002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
}
return 0;
}
void __fastcall donpachiWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0xB00000:
case 0xB00001:
case 0xB00002:
case 0xB00003:
MSM6295Command(0, byteValue);
break;
case 0xB00010:
case 0xB00011:
case 0xB00012:
case 0xB00013:
MSM6295Command(1, byteValue);
break;
case 0xB00020:
case 0xB00021:
case 0xB00022:
case 0xB00023:
case 0xB00024:
case 0xB00025:
case 0xB00026:
case 0xB00027:
case 0xB00028:
case 0xB00029:
case 0xB0002A:
case 0xB0002B:
case 0xB0002C:
case 0xB0002D:
case 0xB0002E:
case 0xB0002F: {
INT32 nBank = (sekAddress >> 1) & 3;
INT32 nChip = (sekAddress >> 3) & 1;
INT32 nAddress = byteValue << 16;
while (nAddress > nBankSize[nChip]) {
nAddress -= nBankSize[nChip];
}
if (nChip == 1) {
MSM6295SampleData[1][nBank] = MSM6295ROM + nAddress;
MSM6295SampleInfo[1][nBank] = MSM6295ROM + nAddress + (nBank << 8);
} else {
MSM6295SampleData[0][nBank] = MSM6295ROM + 0x100000 + nAddress;
if (nBank == 0) {
MSM6295SampleInfo[0][0] = MSM6295ROM + 0x100000 + nAddress + 0x0000;
MSM6295SampleInfo[0][1] = MSM6295ROM + 0x100000 + nAddress + 0x0100;
MSM6295SampleInfo[0][2] = MSM6295ROM + 0x100000 + nAddress + 0x0200;
MSM6295SampleInfo[0][3] = MSM6295ROM + 0x100000 + nAddress + 0x0300;
}
}
break;
}
case 0xD00000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
}
void __fastcall donpachiWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x600000:
CaveTileReg[1][0] = wordValue;
break;
case 0x600002:
CaveTileReg[1][1] = wordValue;
break;
case 0x600004:
CaveTileReg[1][2] = wordValue;
break;
case 0x700000:
CaveTileReg[0][0] = wordValue;
break;
case 0x700002:
CaveTileReg[0][1] = wordValue;
break;
case 0x700004:
CaveTileReg[0][2] = wordValue;
break;
case 0x800000:
CaveTileReg[2][0] = wordValue;
break;
case 0x800002:
CaveTileReg[2][1] = wordValue;
break;
case 0x800004:
CaveTileReg[2][2] = wordValue;
break;
case 0x900000:
nCaveXOffset = wordValue;
return;
case 0x900002:
nCaveYOffset = wordValue;
return;
case 0x900008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0xB00000:
case 0xB00002:
MSM6295Command(0, wordValue);
break;
case 0xB00010:
case 0xB00012:
MSM6295Command(1, wordValue);
break;
case 0xB00020:
case 0xB00021:
case 0xB00022:
case 0xB00023:
case 0xB00024:
case 0xB00025:
case 0xB00026:
case 0xB00027:
case 0xB00028:
case 0xB00029:
case 0xB0002A:
case 0xB0002B:
case 0xB0002C:
case 0xB0002D:
case 0xB0002E:
case 0xB0002F: {
INT32 nBank = (sekAddress >> 1) & 3;
INT32 nChip = (sekAddress >> 3) & 1;
INT32 nAddress = wordValue << 16;
while (nAddress > nBankSize[nChip]) {
nAddress -= nBankSize[nChip];
}
if (nChip == 1) {
MSM6295SampleData[1][nBank] = MSM6295ROM + nAddress;
MSM6295SampleInfo[1][nBank] = MSM6295ROM + nAddress + (nBank << 8);
} else {
MSM6295SampleData[0][nBank] = MSM6295ROM + 0x100000 + nAddress;
if (nBank == 0) {
MSM6295SampleInfo[0][0] = MSM6295ROM + 0x100000 + nAddress + 0x0000;
MSM6295SampleInfo[0][1] = MSM6295ROM + 0x100000 + nAddress + 0x0100;
MSM6295SampleInfo[0][2] = MSM6295ROM + 0x100000 + nAddress + 0x0200;
MSM6295SampleInfo[0][3] = MSM6295ROM + 0x100000 + nAddress + 0x0300;
}
}
break;
}
case 0xD00000:
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
}
static INT32 DrvExit()
{
EEPROMExit();
MSM6295Exit(1);
MSM6295Exit(0);
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
MSM6295Reset(0);
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate4Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x7F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
#if 1 && defined USE_SPEEDHACKS
INT32 nCurrentPC = SekGetPC(-1);
// All versions are the same
if (!nIRQPending && nCurrentPC >= 0x002ED6 && nCurrentPC <= 0x002EE2) {
return 1;
}
#endif
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
INT32 nCyclesTotal[2];
INT32 nCyclesDone[2];
INT32 nCyclesSegment;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 10; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nCurrentCPU = 0;
INT32 nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// Run 68000
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
// Make sure the buffer is entirely filled.
{
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
MSM6295Render(0, pSoundBuf, nSegmentLength);
MSM6295Render(1, pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x080000; // 68K program
CaveSpriteROM = Next; Next += 0x800000;
CaveTileROM[0] = Next; Next += 0x200000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x200000; // Tile layer 1
CaveTileROM[2] = Next; Next += 0x080000; // Tile layer 2
MSM6295ROM = Next; Next += 0x300000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveTileRAM[2] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x001000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap2(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[1] = *pOrg & 15;
pDest[0] = *pOrg >> 4;
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01, 0, 1);
BurnLoadRom(CaveSpriteROM + 0x000000, 1, 1);
BurnLoadRom(CaveSpriteROM + 0x200000, 2, 1);
BurnByteswap(CaveSpriteROM, 0x400000);
NibbleSwap2(CaveSpriteROM, 0x400000);
BurnLoadRom(CaveTileROM[0], 3, 1);
NibbleSwap2(CaveTileROM[0], 0x100000);
BurnLoadRom(CaveTileROM[1], 4, 1);
NibbleSwap2(CaveTileROM[1], 0x100000);
BurnLoadRom(CaveTileROM[2], 5, 1);
NibbleSwap2(CaveTileROM[2], 0x040000);
// Load MSM6295 ADPCM data
BurnLoadRom(MSM6295ROM, 6, 1);
BurnLoadRom(MSM6295ROM + 0x100000, 7, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction); // scan 68000 states
MSM6295Scan(0, nAction);
MSM6295Scan(1, nAction);
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
}
if (nAction & ACB_WRITE) {
CaveRecalcPalette = 1;
}
return 0;
}
static const UINT8 default_eeprom[16] = {0x00,0x0C,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
if (!EEPROMAvailable()) EEPROMFill(default_eeprom,0, sizeof(default_eeprom));
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x07FFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x200000, 0x207FFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x300000, 0x307FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2] + 0x4000, 0x400000, 0x403FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2] + 0x4000, 0x404000, 0x407FFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x500000, 0x50FFFF, SM_RAM);
SekMapMemory(CavePalSrc, 0xA08000, 0xA08FFF, SM_RAM); // Palette RAM
SekSetReadWordHandler(0, donpachiReadWord);
SekSetReadByteHandler(0, donpachiReadByte);
SekSetWriteWordHandler(0, donpachiWriteWord);
SekSetWriteByteHandler(0, donpachiWriteByte);
SekClose();
}
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(0, 0x0800000);
CaveTileInitLayer(0, 0x200000, 8, 0x4000);
CaveTileInitLayer(1, 0x200000, 8, 0x4000);
CaveTileInitLayer(2, 0x080000, 8, 0x4000);
MSM6295Init(0, 8000, 50.0, 0);
MSM6295Init(1, 16000, 50.0, 0);
MSM6295SampleData[0][0] = MSM6295ROM + 0x100000;
MSM6295SampleInfo[0][0] = MSM6295ROM + 0x100000 + 0x0000;
MSM6295SampleData[0][1] = MSM6295ROM + 0x100000;
MSM6295SampleInfo[0][1] = MSM6295ROM + 0x100000 + 0x0100;
MSM6295SampleData[0][2] = MSM6295ROM + 0x100000;
MSM6295SampleInfo[0][2] = MSM6295ROM + 0x100000 + 0x0200;
MSM6295SampleData[0][3] = MSM6295ROM + 0x100000;
MSM6295SampleInfo[0][3] = MSM6295ROM + 0x100000 + 0x0300;
bDrawScreen = true;
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo donpachiRomDesc[] = {
{ "prgu.u29", 0x080000, 0x89C36802, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "atdp.u44", 0x200000, 0x7189E953, BRF_GRA }, // 1 Sprite data
{ "atdp.u45", 0x200000, 0x6984173F, BRF_GRA }, // 2
{ "atdp.u54", 0x100000, 0x6BDA6B66, BRF_GRA }, // 3 Layer 0 Tile data
{ "atdp.u57", 0x100000, 0x0A0E72B9, BRF_GRA }, // 4 Layer 1 Tile data
{ "text.u58", 0x040000, 0x5DBA06E7, BRF_GRA }, // 5 Layer 2 Tile data
{ "atdp.u32", 0x100000, 0x0D89FCCA, BRF_SND }, // 6 MSM6295 #1 ADPCM data
{ "atdp.u33", 0x200000, 0xD749DE00, BRF_SND }, // 7 MSM6295 #0/1 ADPCM data
{ "eeprom-donpachi.u10", 0x0080, 0x315fb546, BRF_OPT },
{ "peel18cv8p-15.u18", 0x0155, 0x3f4787e9, BRF_OPT },
};
STD_ROM_PICK(donpachi)
STD_ROM_FN(donpachi)
static struct BurnRomInfo donpachijRomDesc[] = {
{ "prg.u29", 0x080000, 0x6BE14AF6, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "atdp.u44", 0x200000, 0x7189E953, BRF_GRA }, // 1 Sprite data
{ "atdp.u45", 0x200000, 0x6984173F, BRF_GRA }, // 2
{ "atdp.u54", 0x100000, 0x6BDA6B66, BRF_GRA }, // 3 Layer 0 Tile data
{ "atdp.u57", 0x100000, 0x0A0E72B9, BRF_GRA }, // 4 Layer 1 Tile data
{ "u58.bin", 0x040000, 0x285379FF, BRF_GRA }, // 5 Layer 2 Tile data
{ "atdp.u32", 0x100000, 0x0D89FCCA, BRF_SND }, // 6 MSM6295 #1 ADPCM data
{ "atdp.u33", 0x200000, 0xD749DE00, BRF_SND }, // 7 MSM6295 #0/1 ADPCM data
{ "eeprom-donpachi.bin", 0x0080, 0x315fb546, BRF_OPT },
{ "peel18cv8p-15.u18", 0x0155, 0x3f4787e9, BRF_OPT },
};
STD_ROM_PICK(donpachij)
STD_ROM_FN(donpachij)
static struct BurnRomInfo donpachikrRomDesc[] = {
{ "prgk.u26", 0x080000, 0xBBAF4C8B, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "atdp.u44", 0x200000, 0x7189E953, BRF_GRA }, // 1 Sprite data
{ "atdp.u45", 0x200000, 0x6984173F, BRF_GRA }, // 2
{ "atdp.u54", 0x100000, 0x6BDA6B66, BRF_GRA }, // 3 Layer 0 Tile data
{ "atdp.u57", 0x100000, 0x0A0E72B9, BRF_GRA }, // 4 Layer 1 Tile data
{ "u58.bin", 0x040000, 0x285379FF, BRF_GRA }, // 5 Layer 2 Tile data
{ "atdp.u32", 0x100000, 0x0D89FCCA, BRF_SND }, // 6 MSM6295 #1 ADPCM data
{ "atdp.u33", 0x200000, 0xD749DE00, BRF_SND }, // 7 MSM6295 #0/1 ADPCM data
{ "eeprom-donpachi.bin", 0x0080, 0x315fb546, BRF_OPT },
{ "peel18cv8p-15.u18", 0x0155, 0x3f4787e9, BRF_OPT },
};
STD_ROM_PICK(donpachikr)
STD_ROM_FN(donpachikr)
static struct BurnRomInfo donpachihkRomDesc[] = {
{ "37.u29", 0x080000, 0x71f39f30, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "atdp.u44", 0x200000, 0x7189E953, BRF_GRA }, // 1 Sprite data
{ "atdp.u45", 0x200000, 0x6984173F, BRF_GRA }, // 2
{ "atdp.u54", 0x100000, 0x6BDA6B66, BRF_GRA }, // 3 Layer 0 Tile data
{ "atdp.u57", 0x100000, 0x0A0E72B9, BRF_GRA }, // 4 Layer 1 Tile data
{ "u58.bin", 0x040000, 0x285379ff, BRF_GRA }, // 5 Layer 2 Tile data
{ "atdp.u32", 0x100000, 0x0D89FCCA, BRF_SND }, // 6 MSM6295 #1 ADPCM data
{ "atdp.u33", 0x200000, 0xD749DE00, BRF_SND }, // 7 MSM6295 #0/1 ADPCM data
{ "eeprom-donpachi.bin", 0x0080, 0x315fb546, BRF_OPT },
{ "peel18cv8p-15.u18", 0x0155, 0x3f4787e9, BRF_OPT },
};
STD_ROM_PICK(donpachihk)
STD_ROM_FN(donpachihk)
struct BurnDriver BurnDrvDonpachi = {
"donpachi", NULL, NULL, NULL, "1995",
"DonPachi (USA, ver. 1.12, 95/05/2x)\0", NULL, "Atlus / Cave", "Cave",
L"\u9996\u9818\u8702 DonPachi (USA, ver. 1.12, 95/05/2x)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY | HARDWARE_CAVE_M6295, GBF_VERSHOOT, 0,
NULL, donpachiRomInfo, donpachiRomName, NULL, NULL, donpachiInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
struct BurnDriver BurnDrvDonpachij = {
"donpachij", "donpachi", NULL, NULL, "1995",
"DonPachi (Japan, ver. 1.01, 95/05/11)\0", NULL, "Atlus / Cave", "Cave",
L"\u9996\u9818\u8702 DonPachi (Japan, ver. 1.01, 95/05/11)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY | HARDWARE_CAVE_M6295, GBF_VERSHOOT, 0,
NULL, donpachijRomInfo, donpachijRomName, NULL, NULL, donpachiInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
struct BurnDriver BurnDrvDonpachikr = {
"donpachikr", "donpachi", NULL, NULL, "1995",
"DonPachi (Korea, ver. 1.12, 95/05/2x)\0", NULL, "Atlus / Cave", "Cave",
L"\u9996\u9818\u8702 DonPachi (Korea, ver. 1.12, 95/05/2x)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY | HARDWARE_CAVE_M6295, GBF_VERSHOOT, 0,
NULL, donpachikrRomInfo, donpachikrRomName, NULL, NULL, donpachiInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
struct BurnDriver BurnDrvDonpachihk = {
"donpachihk", "donpachi", NULL, NULL, "1995",
"DonPachi (Hong Kong, ver. 1.10, 95/05/17)\0", NULL, "Atlus / Cave", "Cave",
L"\u9996\u9818\u8702 DonPachi (Hong Kong, ver. 1.10, 95/05/17)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY | HARDWARE_CAVE_M6295, GBF_VERSHOOT, 0,
NULL, donpachihkRomInfo, donpachihkRomName, NULL, NULL, donpachiInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};

View File

@ -0,0 +1,723 @@
// E.S.P. Ra De
#include "cave.h"
#include "ymz280b.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT32 nSpeedhack;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCurrentCPU;
static INT32 nCyclesDone[2];
static INT32 nCyclesTotal[2];
static INT32 nCyclesSegment;
static struct BurnInputInfo espradeInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(esprade)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall espradeReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300003: {
return YMZ280BReadStatus();
}
case 0x800000:
case 0x800001:
case 0x800002:
case 0x800003: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x800004:
case 0x800005: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800006:
case 0x800007: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xD00000:
return (DrvInput[0] >> 8) ^ 0xFF;
case 0xD00001:
return (DrvInput[0] & 0xFF) ^ 0xFF;
case 0xD00002:
return ((DrvInput[1] >> 8) ^ 0xF7) | (EEPROMRead() << 3);
case 0xD00003:
return (DrvInput[1] & 0xFF) ^ 0xFF;
default: {
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
}
return 0;
}
UINT16 __fastcall espradeReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300002: {
return YMZ280BReadStatus();
}
case 0x800000:
case 0x800002: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x800004: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800006: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xD00000:
return DrvInput[0] ^ 0xFFFF;
case 0xD00002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
}
return 0;
}
void __fastcall espradeWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x300001:
YMZ280BSelectRegister(byteValue);
break;
case 0x300003:
YMZ280BWriteRegister(byteValue);
break;
case 0xE00000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
}
void __fastcall espradeWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x300000:
YMZ280BSelectRegister(wordValue);
break;
case 0x300002:
YMZ280BWriteRegister(wordValue);
break;
case 0x800000:
nCaveXOffset = wordValue;
return;
case 0x800002:
nCaveYOffset = wordValue;
return;
case 0x800008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x900000:
CaveTileReg[0][0] = wordValue;
break;
case 0x900002:
CaveTileReg[0][1] = wordValue;
break;
case 0x900004:
CaveTileReg[0][2] = wordValue;
break;
case 0xA00000:
CaveTileReg[1][0] = wordValue;
break;
case 0xA00002:
CaveTileReg[1][1] = wordValue;
break;
case 0xA00004:
CaveTileReg[1][2] = wordValue;
break;
case 0xB00000:
CaveTileReg[2][0] = wordValue;
break;
case 0xB00002:
CaveTileReg[2][1] = wordValue;
break;
case 0xB00004:
CaveTileReg[2][2] = wordValue;
break;
case 0xE00000:
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
}
void __fastcall espradeWriteBytePalette(UINT32 sekAddress, UINT8 byteValue)
{
CavePalWriteByte(sekAddress & 0xFFFF, byteValue);
}
void __fastcall espradeWriteWordPalette(UINT32 sekAddress, UINT16 wordValue)
{
CavePalWriteWord(sekAddress & 0xFFFF, wordValue);
}
static void TriggerSoundIRQ(INT32 nStatus)
{
nSoundIRQ = nStatus ^ 1;
UpdateIRQStatus();
if (nIRQPending && nCurrentCPU != 0) {
nCyclesDone[0] += SekRun(0x0400);
}
}
static INT32 DrvExit()
{
YMZ280BExit();
EEPROMExit();
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
YMZ280BReset();
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate8Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x0000]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
#if 1 && defined USE_SPEEDHACKS
INT32 nCurrentPC = SekGetPC(-1) - nSpeedhack;
if (!nIRQPending && nCurrentPC >= 0 && nCurrentPC <= 12) {
return 1;
}
#endif
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 10; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nNext;
// Render sound segment
if ((i & 1) == 0) {
if (pBurnSoundOut) {
INT32 nSegmentEnd = nBurnSoundLen * i / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
YMZ280BRender(pSoundBuf, nSegmentEnd - nSoundBufferPos);
nSoundBufferPos = nSegmentEnd;
}
}
// Run 68000
nCurrentCPU = 0;
nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = -1;
}
{
// Make sure the buffer is entirely filled.
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
YMZ280BRender(pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
CaveSpriteROM = Next; Next += 0x1000000;
CaveTileROM[0] = Next; Next += 0x800000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x800000; // Tile layer 1
CaveTileROM[2] = Next; Next += 0x400000; // Tile layer 2
YMZ280BROM = Next; Next += 0x400000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveTileRAM[2] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap3(UINT8* pData, INT32 nLen)
{
for (INT32 i = 0; i < nLen; i++, pData += 2) {
UINT8 n1 = pData[0];
UINT8 n2 = pData[1];
pData[0] = (n1 << 4) | (n2 & 0x0F);
pData[1] = (n1 & 0xF0) | (n2 >> 4);
}
return;
}
static void NibbleSwap4(UINT8* pData, INT32 nLen)
{
for (INT32 i = 0; i < nLen; i++, pData += 2) {
UINT8 n1 = pData[0];
UINT8 n2 = pData[1];
pData[1] = (n2 << 4) | (n1 & 0x0F);
pData[0] = (n2 & 0xF0) | (n1 >> 4);
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 1, 2);
BurnLoadRom(Rom01 + 1, 0, 2);
BurnLoadRom(CaveSpriteROM + 0x000000, 2, 2);
BurnLoadRom(CaveSpriteROM + 0x000001, 3, 2);
BurnLoadRom(CaveSpriteROM + 0x800000, 4, 2);
BurnLoadRom(CaveSpriteROM + 0x800001, 5, 2);
NibbleSwap3(CaveSpriteROM, 0x800000);
BurnLoadRom(CaveTileROM[0] + 0x000000, 6, 1);
BurnLoadRom(CaveTileROM[0] + 0x400000, 7, 1);
NibbleSwap4(CaveTileROM[0], 0x400000);
BurnLoadRom(CaveTileROM[1] + 0x000000, 8, 1);
BurnLoadRom(CaveTileROM[1] + 0x400000, 9, 1);
NibbleSwap4(CaveTileROM[1], 0x400000);
BurnLoadRom(CaveTileROM[2] + 0x000000, 10, 1);
NibbleSwap4(CaveTileROM[2], 0x200000);
// Load YMZ280B data
BurnLoadRom(YMZ280BROM, 11, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction); // scan 68000 states
YMZ280BScan();
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
}
if (nAction & ACB_WRITE) {
CaveRecalcPalette = 1;
}
return 0;
}
static const UINT8 default_eeprom[16] = {0x00,0x0C,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
if (!EEPROMAvailable()) EEPROMFill(default_eeprom,0, sizeof(default_eeprom));
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x0FFFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x400000, 0x40FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x500000, 0x507FFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x600000, 0x607FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2], 0x700000, 0x707FFF, SM_RAM);
SekMapMemory(CavePalSrc, 0xC00000, 0xC0FFFF, SM_ROM); // Palette RAM (write goes through handler)
SekMapHandler(1, 0xC00000, 0xC0FFFF, SM_WRITE); //
SekSetReadWordHandler(0, espradeReadWord);
SekSetReadByteHandler(0, espradeReadByte);
SekSetWriteWordHandler(0, espradeWriteWord);
SekSetWriteByteHandler(0, espradeWriteByte);
SekSetWriteWordHandler(1, espradeWriteWordPalette);
SekSetWriteByteHandler(1, espradeWriteBytePalette);
SekClose();
}
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(1, 0x1000000);
CaveTileInitLayer(0, 0x800000, 8, 0x4000);
CaveTileInitLayer(1, 0x800000, 8, 0x4000);
CaveTileInitLayer(2, 0x400000, 8, 0x4000);
YMZ280BInit(16934400, &TriggerSoundIRQ, 3);
bDrawScreen = true;
// 4/22 version: 0x04F37C - 0x04F388
// 4/21 version: 0x04F150 - 0x04F15C
// 4/14 version: 0x04F152 - 0x04F15E
if (strcmp(BurnDrvGetTextA(DRV_NAME), "esprade") == 0) {
nSpeedhack = 0x04F37C;
} else {
if (strcmp(BurnDrvGetTextA(DRV_NAME), "espradej") == 0) {
nSpeedhack = 0x04F152;
} else {
nSpeedhack = 0x04F150;
}
}
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo espradeRomDesc[] = {
{ "u42.int", 0x080000, 0x3B510A73, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "u41.int", 0x080000, 0x97C1B649, BRF_ESS | BRF_PRG }, // 1
{ "esp_u63.u63", 0x400000, 0x2F2FE92C, BRF_GRA }, // 2 Sprite data
{ "esp_u64.u64", 0x400000, 0x491A3DA4, BRF_GRA }, // 3
{ "esp_u65.u65", 0x400000, 0x06563EFE, BRF_GRA }, // 4
{ "esp_u66.u66", 0x400000, 0x7BBE4CFC, BRF_GRA }, // 5
{ "esp_u54.u54", 0x400000, 0xE7CA6936, BRF_GRA }, // 6 Layer 0 Tile data
{ "esp_u55.u55", 0x400000, 0xF53BD94F, BRF_GRA }, // 7
{ "esp_u52.u52", 0x400000, 0xE7ABE7B4, BRF_GRA }, // 8 Layer 1 Tile data
{ "esp_u53.u53", 0x400000, 0x51A0F391, BRF_GRA }, // 9
{ "esp_u51.u51", 0x400000, 0x0B9B875C, BRF_GRA }, // 10 Layer 2 Tile data
{ "esp_u19.u19", 0x400000, 0xF54B1CAB, BRF_SND }, // 11 YMZ280B (AD)PCM data
{ "eeprom-esprade.bin", 0x0080, 0x315fb546, BRF_OPT },
};
STD_ROM_PICK(esprade)
STD_ROM_FN(esprade)
static struct BurnRomInfo espradejRomDesc[] = {
{ "u42_ver.2", 0x080000, 0x75D03C42, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "u41_ver.2", 0x080000, 0x734B3EF0, BRF_ESS | BRF_PRG }, // 1
{ "esp_u63.u63", 0x400000, 0x2F2FE92C, BRF_GRA }, // 2 Sprite data
{ "esp_u64.u64", 0x400000, 0x491A3DA4, BRF_GRA }, // 3
{ "esp_u65.u65", 0x400000, 0x06563EFE, BRF_GRA }, // 4
{ "esp_u66.u66", 0x400000, 0x7BBE4CFC, BRF_GRA }, // 5
{ "esp_u54.u54", 0x400000, 0xE7CA6936, BRF_GRA }, // 6 Layer 0 Tile data
{ "esp_u55.u55", 0x400000, 0xF53BD94F, BRF_GRA }, // 7
{ "esp_u52.u52", 0x400000, 0xE7ABE7B4, BRF_GRA }, // 8 Layer 1 Tile data
{ "esp_u53.u53", 0x400000, 0x51A0F391, BRF_GRA }, // 9
{ "esp_u51.u51", 0x400000, 0x0B9B875C, BRF_GRA }, // 10 Layer 2 Tile data
{ "esp_u19.u19", 0x400000, 0xF54B1CAB, BRF_SND }, // 11 YMZ280B (AD)PCM data
{ "eeprom-esprade.bin", 0x0080, 0x315fb546, BRF_OPT },
};
STD_ROM_PICK(espradej)
STD_ROM_FN(espradej)
static struct BurnRomInfo espradejoRomDesc[] = {
{ "u42.bin", 0x080000, 0x0718C7E5, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "u41.bin", 0x080000, 0xDEF30539, BRF_ESS | BRF_PRG }, // 1
{ "esp_u63.u63", 0x400000, 0x2F2FE92C, BRF_GRA }, // 2 Sprite data
{ "esp_u64.u64", 0x400000, 0x491A3DA4, BRF_GRA }, // 3
{ "esp_u65.u65", 0x400000, 0x06563EFE, BRF_GRA }, // 4
{ "esp_u66.u66", 0x400000, 0x7BBE4CFC, BRF_GRA }, // 5
{ "esp_u54.u54", 0x400000, 0xE7CA6936, BRF_GRA }, // 6 Layer 0 Tile data
{ "esp_u55.u55", 0x400000, 0xF53BD94F, BRF_GRA }, // 7
{ "esp_u52.u52", 0x400000, 0xE7ABE7B4, BRF_GRA }, // 8 Layer 1 Tile data
{ "esp_u53.u53", 0x400000, 0x51A0F391, BRF_GRA }, // 9
{ "esp_u51.u51", 0x400000, 0x0B9B875C, BRF_GRA }, // 10 Layer 2 Tile data
{ "esp_u19.u19", 0x400000, 0xF54B1CAB, BRF_SND }, // 11 YMZ280B (AD)PCM data
{ "eeprom-esprade.bin", 0x0080, 0x315fb546, BRF_OPT },
};
STD_ROM_PICK(espradejo)
STD_ROM_FN(espradejo)
struct BurnDriver BurnDrvEsprade = {
"esprade", NULL, NULL, NULL, "1998",
"ESP Ra.De. - A.D.2018 Tokyo (International, ver. 98/04/22)\0", NULL, "Atlus / Cave", "Cave",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, espradeRomInfo, espradeRomName, NULL, NULL, espradeInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
struct BurnDriver BurnDrvEspradej = {
"espradej", "esprade", NULL, NULL, "1998",
"ESP Ra.De. (Japan, ver. 98/04/21)\0", NULL, "Atlus / Cave", "Cave",
L"ESP Ra.De. \u30A8\u30B9\u30D7\u30EC\u30A4\u30C9 (Japan, ver. 98/04/21)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, espradejRomInfo, espradejRomName, NULL, NULL, espradeInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
struct BurnDriver BurnDrvEspradejo = {
"espradejo", "esprade", NULL, NULL, "1998",
"ESP Ra.De. (Japan, ver. 98/04/14)\0", NULL, "Atlus / Cave", "Cave",
L"ESP Ra.De. \u30A8\u30B9\u30D7\u30EC\u30A4\u30C9 (Japan, ver. 98/04/14)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, espradejoRomInfo, espradejoRomName, NULL, NULL, espradeInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};

View File

@ -0,0 +1,645 @@
// Fever SOS / Dangun Feveron
#include "cave.h"
#include "ymz280b.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01, *Ram02;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT32 nSpeedhack;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCurrentCPU;
static INT32 nCyclesDone[2];
static INT32 nCyclesTotal[2];
static INT32 nCyclesSegment;
static struct BurnInputInfo feversosInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(feversos)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall feversosReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300003: {
return YMZ280BReadStatus();
}
case 0x800000:
case 0x800001:
case 0x800002:
case 0x800003: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x800004:
case 0x800005: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800006:
case 0x800007: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xB00000:
return (DrvInput[0] >> 8) ^ 0xFF;
case 0xB00001:
return (DrvInput[0] & 0xFF) ^ 0xFF;
case 0xB00002:
return ((DrvInput[1] >> 8) ^ 0xF7) | (EEPROMRead() << 3);
case 0xB00003:
return (DrvInput[1] & 0xFF) ^ 0xFF;
default: {
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
}
return 0;
}
UINT16 __fastcall feversosReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300002: {
return YMZ280BReadStatus();
}
case 0x800000:
case 0x800002: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x800004: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800006: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xB00000:
return DrvInput[0] ^ 0xFFFF;
case 0xB00002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
}
return 0;
}
void __fastcall feversosWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x300001:
YMZ280BSelectRegister(byteValue);
break;
case 0x300003:
YMZ280BWriteRegister(byteValue);
break;
case 0xC00000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
}
void __fastcall feversosWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x300000:
YMZ280BSelectRegister(wordValue);
break;
case 0x300002:
YMZ280BWriteRegister(wordValue);
break;
case 0x800000:
nCaveXOffset = wordValue;
return;
case 0x800002:
nCaveYOffset = wordValue;
return;
case 0x800008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x900000:
CaveTileReg[0][0] = wordValue;
break;
case 0x900002:
CaveTileReg[0][1] = wordValue;
break;
case 0x900004:
CaveTileReg[0][2] = wordValue;
break;
case 0xA00000:
CaveTileReg[1][0] = wordValue;
break;
case 0xA00002:
CaveTileReg[1][1] = wordValue;
break;
case 0xA00004:
CaveTileReg[1][2] = wordValue;
break;
case 0xC00000:
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
}
static void TriggerSoundIRQ(INT32 nStatus)
{
nSoundIRQ = nStatus ^ 1;
UpdateIRQStatus();
if (nIRQPending && nCurrentCPU != 0) {
nCyclesDone[0] += SekRun(0x0400);
}
}
static INT32 DrvExit()
{
EEPROMExit();
YMZ280BExit();
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
YMZ280BReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
YMZ280BReset();
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate4Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x3F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
#if 0 && defined USE_SPEEDHACKS
UINT32 nCurrentPC = SekGetPC(-1);
if (!nIRQPending && nCurrentPC >= nSpeedhack && nCurrentPC <= nSpeedhack + 0x18) {
return 1;
}
#endif
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 10; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nNext;
// Render sound segment
if ((i & 1) == 0) {
if (pBurnSoundOut) {
INT32 nSegmentEnd = nBurnSoundLen * i / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
YMZ280BRender(pSoundBuf, nSegmentEnd - nSoundBufferPos);
nSoundBufferPos = nSegmentEnd;
}
}
// Run 68000
nCurrentCPU = 0;
nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = -1;
}
{
// Make sure the buffer is entirely filled.
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
YMZ280BRender(pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
CaveSpriteROM = Next; Next += 0x1000000;
CaveTileROM[0] = Next; Next += 0x400000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x400000; // Tile layer 1
YMZ280BROM = Next; Next += 0x400000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
Ram02 = Next; Next += 0x001000;
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x001000; // palette
// CaveVideoRegisters= Next; Next += 0x000080;
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap2(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[1] = *pOrg & 15;
pDest[0] = *pOrg >> 4;
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 1, 2);
BurnLoadRom(Rom01 + 1, 0, 2);
BurnLoadRom(CaveSpriteROM + 0x000000, 2, 1);
BurnLoadRom(CaveSpriteROM + 0x400000, 3, 1);
NibbleSwap1(CaveSpriteROM, 0x800000);
BurnLoadRom(CaveTileROM[0], 4, 1);
NibbleSwap2(CaveTileROM[0], 0x200000);
BurnLoadRom(CaveTileROM[1], 5, 1);
NibbleSwap2(CaveTileROM[1], 0x200000);
BurnLoadRom(YMZ280BROM, 6, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction); // scan 68000 states
YMZ280BScan();
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
}
if (nAction & ACB_WRITE) {
CaveRecalcPalette = 1;
}
return 0;
}
static const UINT8 default_eeprom[16] = {0x00,0x0C,0x11,0x0D,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x11,0x11,0xFF,0xFF,0xFF,0xFF};
static const UINT8 default_eeprom_feversos[18] = {0x00,0x0C,0x16,0x27,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x11,0x11,0xFF,0xFF,0xFF,0xFF,0x05,0x19}; /* Fever SOS (code checks for the 0x0519 or it won't boot) */
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
if (!strcmp(BurnDrvGetTextA(DRV_NAME), "dfeveron")) {
if (!EEPROMAvailable()) EEPROMFill(default_eeprom,0, sizeof(default_eeprom));
}
if (!strcmp(BurnDrvGetTextA(DRV_NAME), "feversos")) {
if (!EEPROMAvailable()) EEPROMFill(default_eeprom_feversos,0, sizeof(default_eeprom_feversos));
}
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x0FFFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x400000, 0x40FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x500000, 0x507FFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x600000, 0x607FFF, SM_RAM);
SekMapMemory(CavePalSrc, 0x708000, 0x708FFF, SM_RAM); // Palette RAM
SekMapMemory(Ram02, 0x710000, 0x710BFF, SM_ROM);
SekMapMemory(Ram02, 0x710C00, 0x710FFF, SM_RAM);
SekSetReadWordHandler(0, feversosReadWord);
SekSetReadByteHandler(0, feversosReadByte);
SekSetWriteWordHandler(0, feversosWriteWord);
SekSetWriteByteHandler(0, feversosWriteByte);
SekClose();
}
nCaveRowModeOffset = 1;
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(1, 0x1000000);
CaveTileInitLayer(0, 0x400000, 8, 0x4000);
CaveTileInitLayer(1, 0x400000, 8, 0x4000);
YMZ280BInit(16934400, &TriggerSoundIRQ, 3);
bDrawScreen = true;
// Fever SOS: 0x07766C - 0x077684
// Dangun Feveron: 0x0772F2 - 0x07730A
nSpeedhack = (strcmp(BurnDrvGetTextA(DRV_NAME), "feversos") == 0) ? 0x07766C : 0x0772F2;
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo feversosRomDesc[] = {
{ "cv01-u34.sos", 0x080000, 0x24EF3CE6, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "cv01-u33.sos", 0x080000, 0x64FF73FD, BRF_ESS | BRF_PRG }, // 1
{ "cv01-u25.bin", 0x400000, 0xA6F6A95D, BRF_GRA }, // 2 Sprite data
{ "cv01-u26.bin", 0x400000, 0x32EDB62A, BRF_GRA }, // 3
{ "cv01-u50.bin", 0x200000, 0x7A344417, BRF_GRA }, // 4 Layer 0 Tile data
{ "cv01-u49.bin", 0x200000, 0xD21CDDA7, BRF_GRA }, // 5 Layer 1 Tile data
{ "cv01-u19.bin", 0x400000, 0x5F5514DA, BRF_SND }, // 6 YMZ280B (AD)PCM data
{ "eeprom-feversos.bin", 0x0080, 0xd80303aa, BRF_OPT },
};
STD_ROM_PICK(feversos)
STD_ROM_FN(feversos)
static struct BurnRomInfo dfeveronRomDesc[] = {
{ "cv01-u34.bin", 0x080000, 0xBE87F19D, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "cv01-u33.bin", 0x080000, 0xE53A7DB3, BRF_ESS | BRF_PRG }, // 1
{ "cv01-u25.bin", 0x400000, 0xA6F6A95D, BRF_GRA }, // 2 Sprite data
{ "cv01-u26.bin", 0x400000, 0x32EDB62A, BRF_GRA }, // 3
{ "cv01-u50.bin", 0x200000, 0x7A344417, BRF_GRA }, // 4 Layer 0 Tile data
{ "cv01-u49.bin", 0x200000, 0xD21CDDA7, BRF_GRA }, // 5 Layer 1 Tile data
{ "cv01-u19.bin", 0x400000, 0x5F5514DA, BRF_SND }, // 6 YMZ280B (AD)PCM data
{ "eeprom-dfeveron.bin", 0x0080, 0xc3174959, BRF_OPT },
};
STD_ROM_PICK(dfeveron)
STD_ROM_FN(dfeveron)
struct BurnDriver BurnDrvFeverSOS = {
"feversos", NULL, NULL, NULL, "1998",
"Fever SOS (International, ver. 98/09/25)\0", NULL, "Cave / Nihon System inc.", "Cave",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, feversosRomInfo, feversosRomName, NULL, NULL, feversosInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
struct BurnDriver BurnDrvDFeveron = {
"dfeveron", "feversos", NULL, NULL, "1998",
"Dangun Feveron (Japan, ver. 98/09/17)\0", NULL, "Cave / Nihon System inc.", "Cave",
L"\u5F3E\u9283 Feveron \u3060\u3093\u304C\u3093\u30D5\u30A3\u30FC\u30D0\u30ED\u30F3 (Japan, ver. 98/09/17)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, dfeveronRomInfo, dfeveronRomName, NULL, NULL, feversosInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};

View File

@ -0,0 +1,887 @@
// Gaia Crusaders
#include "cave.h"
#include "ymz280b.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[16] = {0, };
static UINT8 DrvJoy2[16] = {0, };
static UINT16 DrvInput[3] = {0, };
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static INT8 nVBlank;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCurrentCPU;
static INT32 nCyclesDone[2];
static INT32 nCyclesTotal[2];
static INT32 nCyclesSegment;
static struct BurnInputInfo gaiaInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy2 + 0, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy2 + 4, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P1 Button 4", BIT_DIGITAL, DrvJoy1 + 7, "p1 fire 4"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 1, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 5, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy1 + 8, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy1 + 9, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy1 + 10, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy1 + 11, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy1 + 12, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy1 + 13, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy1 + 14, "p2 fire 3"},
{"P2 Button 4", BIT_DIGITAL, DrvJoy1 + 15, "p2 fire 4"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy2 + 2, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 3, "service"},
{"DIP A", BIT_DIPSWITCH, (UINT8*)(DrvInput + 2) + 0, "dip"},
{"DIP B", BIT_DIPSWITCH, (UINT8*)(DrvInput + 2) + 1, "dip"},
};
STDINPUTINFO(gaia)
static struct BurnDIPInfo gaiaDIPList[] = {
// Defaults
{0x17, 0xFF, 0xFF, 0x04, NULL},
{0x18, 0xFF, 0xFF, 0x00, NULL},
// DIP 1
{0, 0xFE, 0, 2, "V reverse"},
{0x17, 0x01, 0x01, 0x00, "Off"},
{0x17, 0x01, 0x01, 0x01, "On"},
{0, 0xFE, 0, 2, "Demo sound"},
{0x17, 0x01, 0x02, 0x02, "Off"},
{0x17, 0x01, 0x02, 0x00, "On"},
{0, 0xFE, 0, 2, "Language"},
{0x17, 0x01, 0x04, 0x00, "Japanese"},
{0x17, 0x01, 0x04, 0x04, "English"},
{0, 0xFE, 0, 9, "Coin"},
{0x17, 0x01, 0x78, 0x00, "1 coin 1 credit"},
{0x17, 0x01, 0x78, 0x08, "1 coin 2 credits"},
{0x17, 0x01, 0x78, 0x10, "1 coin 3 credits"},
{0x17, 0x01, 0x78, 0x18, "2 coins 1 credit"},
{0x17, 0x01, 0x78, 0x20, "2 coins 3 credits"},
{0x17, 0x01, 0x78, 0x28, "3 coins 1 credit"},
{0x17, 0x01, 0x78, 0x30, "4 coins 1 credit"},
{0x17, 0x01, 0x78, 0x38, "2 coins 1 credit 1 continue"},
{0x17, 0x01, 0x78, 0x40, "Free play"},
{0x17, 0x01, 0x78, 0x48, "Free play"},
{0x17, 0x01, 0x78, 0x50, "Free play"},
{0x17, 0x01, 0x78, 0x58, "Free play"},
{0x17, 0x01, 0x78, 0x60, "Free play"},
{0x17, 0x01, 0x78, 0x68, "Free play"},
{0x17, 0x01, 0x78, 0x70, "Free play"},
{0x17, 0x01, 0x78, 0x78, "Free play"},
{0, 0xFE, 0, 2, "Continue"},
{0x17, 0x01, 0x80, 0x80, "Off"},
{0x17, 0x01, 0x80, 0x00, "On"},
// DIP 2
{0, 0xFE, 0, 8, "Level"},
{0x18, 0x01, 0xE0, 0x20, "Very easy"},
{0x18, 0x01, 0xE0, 0x40, "Easy"},
{0x18, 0x01, 0xE0, 0x00, "Medium"},
{0x18, 0x01, 0xE0, 0x80, "Medium hard"},
{0x18, 0x01, 0xE0, 0x60, "Hard 1"},
{0x18, 0x01, 0xE0, 0xC0, "Hard 2"},
{0x18, 0x01, 0xE0, 0xA0, "Very hard"},
{0x18, 0x01, 0xE0, 0xE0, "Hardest"},
// Extend condition
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0x00, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/350,000"},
{0x18, 0x00, 0xE0, 0x00, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0x20, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/300,000"},
{0x18, 0x00, 0xE0, 0x20, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0x40, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/350,000"},
{0x18, 0x00, 0xE0, 0x40, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0x60, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/400,000"},
{0x18, 0x00, 0xE0, 0x60, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0x80, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/400,000"},
{0x18, 0x00, 0xE0, 0x80, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0xA0, NULL},
{0x18, 0x02, 0x04, 0x00, "200,000/500,000"},
{0x18, 0x00, 0xE0, 0xA0, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0xC0, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/400,000"},
{0x18, 0x00, 0xE0, 0xC0, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xE0, 0xE0, NULL},
{0x18, 0x02, 0x04, 0x00, "200,000/500,000"},
{0x18, 0x00, 0xE0, 0xE0, NULL},
{0, 0xFE, 0, 4, "Life"},
{0x18, 0x01, 0x03, 0x02, "1 player"},
{0x18, 0x01, 0x03, 0x03, "2 players"},
{0x18, 0x01, 0x03, 0x00, "3 players"},
{0x18, 0x01, 0x03, 0x01, "4 players"},
{0, 0xFE, 0, 4, "Damage"},
{0x18, 0x01, 0x18, 0x00, "+0"},
{0x18, 0x01, 0x18, 0x08, "+1"},
{0x18, 0x01, 0x18, 0x10, "+2"},
{0x18, 0x01, 0x18, 0x18, "+3"},
};
STDDIPINFO(gaia)
static struct BurnDIPInfo theroesDIPList[] = {
// Defaults
{0x17, 0xFF, 0xFF, 0x04, NULL},
{0x18, 0xFF, 0xFF, 0x00, NULL},
// DIP 1
{0, 0xFE, 0, 2, "V reverse"},
{0x17, 0x01, 0x01, 0x00, "Off"},
{0x17, 0x01, 0x01, 0x01, "On"},
{0, 0xFE, 0, 2, "Demo sound"},
{0x17, 0x01, 0x02, 0x02, "Off"},
{0x17, 0x01, 0x02, 0x00, "On"},
{0, 0xFE, 0, 2, "Language"},
{0x17, 0x01, 0x04, 0x00, "Chinese"},
{0x17, 0x01, 0x04, 0x04, "English"},
{0, 0xFE, 0, 9, "Coin"},
{0x17, 0x01, 0x78, 0x00, "1 coin 1 credit"},
{0x17, 0x01, 0x78, 0x08, "1 coin 2 credits"},
{0x17, 0x01, 0x78, 0x10, "1 coin 3 credits"},
{0x17, 0x01, 0x78, 0x18, "2 coins 1 credit"},
{0x17, 0x01, 0x78, 0x20, "2 coins 3 credits"},
{0x17, 0x01, 0x78, 0x28, "3 coins 1 credit"},
{0x17, 0x01, 0x78, 0x30, "4 coins 1 credit"},
{0x17, 0x01, 0x78, 0x38, "2 coins 1 credit 1 continue"},
{0x17, 0x01, 0x78, 0x40, "Free play"},
{0x17, 0x01, 0x78, 0x48, "Free play"},
{0x17, 0x01, 0x78, 0x50, "Free play"},
{0x17, 0x01, 0x78, 0x58, "Free play"},
{0x17, 0x01, 0x78, 0x60, "Free play"},
{0x17, 0x01, 0x78, 0x68, "Free play"},
{0x17, 0x01, 0x78, 0x70, "Free play"},
{0x17, 0x01, 0x78, 0x78, "Free play"},
{0, 0xFE, 0, 2, "Continue"},
{0x17, 0x01, 0x80, 0x80, "Off"},
{0x17, 0x01, 0x80, 0x00, "On"},
// DIP 2
{0, 0xFE, 0, 4, "Level"},
{0x18, 0x01, 0xC0, 0x40, "Very easy"},
{0x18, 0x01, 0xC0, 0x00, "Medium"},
{0x18, 0x01, 0xC0, 0x80, "Medium hard"},
{0x18, 0x01, 0xC0, 0xC0, "Hardest"},
// Extend condition
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xC0, 0x00, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/350,000"},
{0x18, 0x00, 0xC0, 0x00, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xC0, 0x40, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/300,000"},
{0x18, 0x00, 0xC0, 0x40, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xC0, 0x80, NULL},
{0x18, 0x02, 0x04, 0x00, "150,000/400,000"},
{0x18, 0x00, 0xC0, 0x80, NULL},
{0, 0xFE, 0, 2, "Extend"},
{0x18, 0x02, 0x04, 0x04, "Nothing"},
{0x18, 0x00, 0xC0, 0xC0, NULL},
{0x18, 0x02, 0x04, 0x00, "200,000/500,000"},
{0x18, 0x00, 0xC0, 0xC0, NULL},
{0, 0xFE, 0, 4, "Life"},
{0x18, 0x01, 0x03, 0x02, "1 player"},
{0x18, 0x01, 0x03, 0x03, "2 players"},
{0x18, 0x01, 0x03, 0x00, "3 players"},
{0x18, 0x01, 0x03, 0x01, "4 players"},
{0, 0xFE, 0, 4, "Damage"},
{0x18, 0x01, 0x18, 0x00, "+0"},
{0x18, 0x01, 0x18, 0x08, "+1"},
{0x18, 0x01, 0x18, 0x10, "+2"},
{0x18, 0x01, 0x18, 0x18, "+3"},
};
STDDIPINFO(theroes)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall gaiaReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300003: {
return YMZ280BReadStatus();
}
#if 0
case 0x800000:
case 0x800001: {
UINT16 nRet = ((nVBlank ^ 1) << 2) | (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
#else
case 0x800000:
case 0x800001:
#endif
case 0x800002:
case 0x800003: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x800004:
case 0x800005: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800006:
case 0x800007: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xD00010:
return (DrvInput[0] >> 8) ^ 0xFF;
case 0xD00011:
return (DrvInput[0] & 0xFF) ^ 0xFF;
case 0xD00012:
return (DrvInput[1] >> 8) ^ 0xFF;
case 0xD00013:
return (DrvInput[1] & 0xFF) ^ 0xFF;
case 0xD00014:
return (DrvInput[2] >> 8) ^ 0xFF;
case 0xD00015:
return (DrvInput[2] & 0xFF) ^ 0xFF;
default: {
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
}
return 0;
}
UINT16 __fastcall gaiaReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300002: {
return YMZ280BReadStatus();
}
#if 0
case 0x800000: {
UINT16 nRet = ((nVBlank ^ 1) << 2) | (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
#else
case 0x800000:
#endif
case 0x800002: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x800004: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800006: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xD00010:
return DrvInput[0] ^ 0xFFFF;
case 0xD00012:
return DrvInput[1] ^ 0xFFFF;
case 0xD00014:
return DrvInput[2] ^ 0xFFFF;
default: {
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
}
return 0;
}
void __fastcall gaiaWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x300001:
YMZ280BSelectRegister(byteValue);
break;
case 0x300003:
YMZ280BWriteRegister(byteValue);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
}
void __fastcall gaiaWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x300000:
YMZ280BSelectRegister(wordValue);
break;
case 0x300002:
YMZ280BWriteRegister(wordValue);
break;
case 0x800000:
nCaveXOffset = wordValue;
return;
case 0x800002:
nCaveYOffset = wordValue;
return;
case 0x800008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x900000:
CaveTileReg[0][0] = wordValue;
break;
case 0x900002:
CaveTileReg[0][1] = wordValue;
break;
case 0x900004:
CaveTileReg[0][2] = wordValue;
break;
case 0xA00000:
CaveTileReg[1][0] = wordValue;
break;
case 0xA00002:
CaveTileReg[1][1] = wordValue;
break;
case 0xA00004:
CaveTileReg[1][2] = wordValue;
break;
case 0xB00000:
CaveTileReg[2][0] = wordValue;
break;
case 0xB00002:
CaveTileReg[2][1] = wordValue;
break;
case 0xB00004:
CaveTileReg[2][2] = wordValue;
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
}
void __fastcall gaiaWriteBytePalette(UINT32 sekAddress, UINT8 byteValue)
{
CavePalWriteByte(sekAddress & 0xFFFF, byteValue);
}
void __fastcall gaiaWriteWordPalette(UINT32 sekAddress, UINT16 wordValue)
{
CavePalWriteWord(sekAddress & 0xFFFF, wordValue);
}
static void TriggerSoundIRQ(INT32 nStatus)
{
nSoundIRQ = nStatus ^ 1;
UpdateIRQStatus();
if (nIRQPending && nCurrentCPU != 0) {
nCyclesDone[0] += SekRun(0x0400);
}
}
static INT32 DrvExit()
{
YMZ280BExit();
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
YMZ280BReset();
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate8Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x0000]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static void gaiaClearOpposites(UINT8* nJoystickInputs)
{
if ((*nJoystickInputs & 0x03) == 0x03) {
*nJoystickInputs &= ~0x03;
}
if ((*nJoystickInputs & 0x0C) == 0x0C) {
*nJoystickInputs &= ~0xC;
}
}
inline static INT32 CheckSleep(INT32)
{
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 16; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
gaiaClearOpposites(((UINT8*)DrvInput) + 0);
gaiaClearOpposites(((UINT8*)DrvInput) + 1);
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * 58));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 265.5);
nVBlank = 0;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nNext;
// Render sound segment
if ((i & 1) == 0) {
if (pBurnSoundOut) {
INT32 nSegmentEnd = nBurnSoundLen * i / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
YMZ280BRender(pSoundBuf, nSegmentEnd - nSoundBufferPos);
nSoundBufferPos = nSegmentEnd;
}
}
// Run 68000
nCurrentCPU = 0;
nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!nVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
nVBlank = 1;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = -1;
}
{
// Make sure the buffer is entirely filled.
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
YMZ280BRender(pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
CaveSpriteROM = Next; Next += 0x1000000;
CaveTileROM[0] = Next; Next += 0x400000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x400000; // Tile layer 1
CaveTileROM[2] = Next; Next += 0x400000; // Tile layer 2
YMZ280BROM = Next; Next += 0xC00000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
CaveTileRAM[0] = Next; Next += 0x010000;
CaveTileRAM[1] = Next; Next += 0x010000;
CaveTileRAM[2] = Next; Next += 0x010000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap4(UINT8* pData, INT32 nLen)
{
for (INT32 i = 0; i < nLen; i++, pData += 2) {
UINT8 n1 = pData[0];
UINT8 n2 = pData[1];
pData[1] = (n2 << 4) | (n1 & 0x0F);
pData[0] = (n2 & 0xF0) | (n1 >> 4);
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 1, 2);
BurnLoadRom(Rom01 + 1, 0, 2);
BurnLoadRom(CaveSpriteROM + 0x000000, 2, 1);
BurnLoadRom(CaveSpriteROM + 0x400000, 3, 1);
NibbleSwap1(CaveSpriteROM, 0x800000);
BurnLoadRom(CaveTileROM[0] + 0x000000, 4, 1);
NibbleSwap4(CaveTileROM[0], 0x400000);
BurnLoadRom(CaveTileROM[1] + 0x000000, 5, 1);
NibbleSwap4(CaveTileROM[1], 0x400000);
BurnLoadRom(CaveTileROM[2] + 0x000000, 6, 1);
NibbleSwap4(CaveTileROM[2], 0x400000);
// Load YMZ280B data
BurnLoadRom(YMZ280BROM + 0x000000, 7, 1);
BurnLoadRom(YMZ280BROM + 0x400000, 8, 1);
BurnLoadRom(YMZ280BROM + 0x800000, 9, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
if (nAction & ACB_MEMORY_ROM) { // Scan all memory, devices & variables
ba.Data = Rom01;
ba.nLen = 0x00100000;
ba.nAddress = 0;
ba.szName = "68K ROM";
BurnAcb(&ba);
}
if (nAction & ACB_MEMORY_RAM) { // Scan all memory, devices & variables
ba.Data = Ram01;
ba.nLen = 0x00010000;
ba.nAddress = 0;
ba.szName = "68K RAM";
BurnAcb(&ba);
ba.Data = CaveTileRAM[0];
ba.nLen = 0x00010000;
ba.nAddress = 0;
ba.szName = "Tilemap 0";
BurnAcb(&ba);
ba.Data = CaveTileRAM[1];
ba.nLen = 0x00010000;
ba.nAddress = 0;
ba.szName = "Tilemap 1";
BurnAcb(&ba);
ba.Data = CaveTileRAM[2];
ba.nLen = 0x00010000;
ba.nAddress = 0;
ba.szName = "Tile layer 2";
BurnAcb(&ba);
ba.Data = CaveSpriteRAM;
ba.nLen = 0x00010000;
ba.nAddress = 0;
ba.szName = "Sprite tables";
BurnAcb(&ba);
ba.Data = CavePalSrc;
ba.nLen = 0x00010000;
ba.nAddress = 0;
ba.szName = "Palette";
BurnAcb(&ba);
}
if (nAction & ACB_DRIVER_DATA) {
SekScan(nAction); // scan 68000 states
YMZ280BScan();
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(nVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
if (nAction & ACB_WRITE) {
CaveRecalcPalette = 1;
}
}
return 0;
}
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(58.0);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x0FFFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x400000, 0x40FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x500000, 0x50FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x600000, 0x60FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[2], 0x700000, 0x70FFFF, SM_RAM);
SekMapMemory(CavePalSrc, 0xC00000, 0xC0FFFF, SM_ROM); // Palette RAM (write goes through handler)
SekMapHandler(1, 0xC00000, 0xC0FFFF, SM_WRITE); //
SekSetReadWordHandler(0, gaiaReadWord);
SekSetReadByteHandler(0, gaiaReadByte);
SekSetWriteWordHandler(0, gaiaWriteWord);
SekSetWriteByteHandler(0, gaiaWriteByte);
SekSetWriteWordHandler(1, gaiaWriteWordPalette);
SekSetWriteByteHandler(1, gaiaWriteBytePalette);
SekClose();
}
nCaveRowModeOffset = 0;
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(2, 0x1000000);
CaveTileInitLayer(0, 0x400000, 8, 0x4000);
CaveTileInitLayer(1, 0x400000, 8, 0x4000);
CaveTileInitLayer(2, 0x400000, 8, 0x4000);
YMZ280BInit(16000000, &TriggerSoundIRQ, 3);
bDrawScreen = true;
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo gaiaRomDesc[] = {
{ "prg1.127", 0x080000, 0x47B904B2, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "prg2.128", 0x080000, 0x469B7794, BRF_ESS | BRF_PRG }, // 1
{ "obj1.736", 0x400000, 0xF4F84E5D, BRF_GRA }, // 2 Sprite data
{ "obj2.738", 0x400000, 0x15C2A9CE, BRF_GRA }, // 3
{ "bg1.989", 0x400000, 0x013A693D, BRF_GRA }, // 4 Layer 0 Tile data
{ "bg2.995", 0x400000, 0x783CC62F, BRF_GRA }, // 5 Layer 1 Tile data
{ "bg3.998", 0x400000, 0xbcd61d1c, BRF_GRA }, // 6 Layer 2 Tile data
{ "snd1.447", 0x400000, 0x92770A52, BRF_SND }, // 7 YMZ280B (AD)PCM data
{ "snd2.454", 0x400000, 0x329AE1CF, BRF_SND }, // 8
{ "snd3.455", 0x400000, 0x4048D64E, BRF_SND }, // 9
};
STD_ROM_PICK(gaia)
STD_ROM_FN(gaia)
struct BurnDriver BurnDrvGaia = {
"gaia", NULL, NULL, NULL, "1999",
"Gaia Crusaders\0", NULL, "Noise Factory", "Cave",
L"Gaia Crusaders \u5F81\u6226\u8005\0Gaia Crusaders \u30AC\u30A4\u30A2\u30AF\u30EB\u30BB\u30A4\u30C0\u30FC\u30BA\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_SCRFIGHT, 0,
NULL, gaiaRomInfo, gaiaRomName, NULL, NULL, gaiaInputInfo, gaiaDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 320, 224, 4, 3
};
static struct BurnRomInfo theroesRomDesc[] = {
{ "t-hero-epm1.u0127", 0x080000, 0x09db7195, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "t-hero-epm0.u0129", 0x080000, 0x2d4e3310, BRF_ESS | BRF_PRG }, // 1
{ "t-hero-obj1.u0736", 0x400000, 0x35090f7c, BRF_GRA }, // 2 Sprite data
{ "t-hero-obj2.u0738", 0x400000, 0x71605108, BRF_GRA }, // 3
{ "t-hero-bg1.u0999", 0x400000, 0x47b0fb40, BRF_GRA }, // 4 Layer 0 Tile data
{ "t-hero-bg2.u0995", 0x400000, 0xb16237a1, BRF_GRA }, // 5 Layer 1 Tile data
{ "t-hero-bg3.u0998", 0x400000, 0x08eb5604, BRF_GRA }, // 6 Layer 2 Tile data
{ "crvsaders-snd1.u0447", 0x400000, 0x92770A52, BRF_SND }, // 7 YMZ280B (AD)PCM data
{ "crvsaders-snd2.u0454", 0x400000, 0x329AE1CF, BRF_SND }, // 8
{ "t-hero-snd3.u0455", 0x400000, 0x52b0b2c0, BRF_SND }, // 9
};
STD_ROM_PICK(theroes)
STD_ROM_FN(theroes)
struct BurnDriver BurnDrvTheroes = {
"theroes", NULL, NULL, NULL, "2001",
"Thunder Heroes\0", NULL, "Primetec Investments", "Cave",
L"\u9739\u96F3\u82F1\u96C4 Thunder Heroes\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_SCRFIGHT, 0,
NULL, theroesRomInfo, theroesRomName, NULL, NULL, gaiaInputInfo, theroesDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 320, 224, 4, 3
};

View File

@ -0,0 +1,714 @@
// Guwange
#include "cave.h"
#include "ymz280b.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[16] = {0, };
static UINT8 DrvJoy2[16] = {0, };
static UINT16 DrvInput[2] = {0, };
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCurrentCPU;
static INT32 nCyclesDone[2];
static INT32 nCyclesTotal[2];
static INT32 nCyclesSegment;
static struct BurnInputInfo guwangeInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy2 + 0, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 0, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 1, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 2, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 3, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 4, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 7, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 1, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy1 + 8, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy1 + 9, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy1 + 10, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy1 + 11, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy1 + 12, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy1 + 13, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy1 + 14, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy1 + 15, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy2 + 2, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 3, "service"},
};
STDINPUTINFO(guwange)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall guwangeReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x800002:
case 0x800003: {
return YMZ280BReadStatus();
}
case 0x300000:
case 0x300001:
case 0x300002:
case 0x300003: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x300004:
case 0x300005: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x300006:
case 0x300007: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xD00010:
return (DrvInput[0] >> 8) ^ 0xFF;
case 0xD00011:
return (DrvInput[0] & 0xFF) ^ 0xFF;
case 0xD00012:
return (DrvInput[1] >> 8) ^ 0xFF;
case 0xD00013:
return ((DrvInput[1] & 0x7F) ^ 0x7F) | (EEPROMRead() << 7);
default: {
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
}
return 0;
}
UINT16 __fastcall guwangeReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x800002: {
return YMZ280BReadStatus();
}
case 0x300000:
case 0x300002: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x300004: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x300006: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xD00010:
return DrvInput[0] ^ 0xFFFF;
case 0xD00012:
return (DrvInput[1] ^ 0xFF7F) | (EEPROMRead() << 7);
default: {
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
}
return 0;
}
void __fastcall guwangeWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x800000:
case 0x800001:
YMZ280BSelectRegister(byteValue);
break;
case 0x800002:
case 0x800003:
YMZ280BWriteRegister(byteValue);
break;
case 0xD00011:
EEPROMWrite(byteValue & 0x40, byteValue & 0x20, byteValue & 0x80);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
}
void __fastcall guwangeWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x300000:
nCaveXOffset = wordValue;
return;
case 0x300002:
nCaveYOffset = wordValue;
return;
case 0x300008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x800000:
YMZ280BSelectRegister(wordValue & 0xFF);
break;
case 0x800002:
YMZ280BWriteRegister(wordValue & 0xFF);
break;
case 0x900000:
CaveTileReg[0][0] = wordValue;
break;
case 0x900002:
CaveTileReg[0][1] = wordValue;
break;
case 0x900004:
CaveTileReg[0][2] = wordValue;
break;
case 0xA00000:
CaveTileReg[1][0] = wordValue;
break;
case 0xA00002:
CaveTileReg[1][1] = wordValue;
break;
case 0xA00004:
CaveTileReg[1][2] = wordValue;
break;
case 0xB00000:
CaveTileReg[2][0] = wordValue;
break;
case 0xB00002:
CaveTileReg[2][1] = wordValue;
break;
case 0xB00004:
CaveTileReg[2][2] = wordValue;
break;
case 0xD00010:
EEPROMWrite(wordValue & 0x40, wordValue & 0x20, wordValue & 0x80);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
}
void __fastcall guwangeWriteBytePalette(UINT32 sekAddress, UINT8 byteValue)
{
CavePalWriteByte(sekAddress & 0xFFFF, byteValue);
}
void __fastcall guwangeWriteWordPalette(UINT32 sekAddress, UINT16 wordValue)
{
CavePalWriteWord(sekAddress & 0xFFFF, wordValue);
}
static void TriggerSoundIRQ(INT32 nStatus)
{
nSoundIRQ = nStatus ^ 1;
UpdateIRQStatus();
if (nIRQPending && nCurrentCPU != 0) {
nCyclesDone[0] += SekRun(0x0400);
}
}
static INT32 DrvExit()
{
YMZ280BExit();
EEPROMExit();
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
YMZ280BReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
YMZ280BReset();
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate8Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x7F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static void guwangeClearOpposites(UINT8* nJoystickInputs)
{
if ((*nJoystickInputs & 0x06) == 0x06) {
*nJoystickInputs &= ~0x06;
}
if ((*nJoystickInputs & 0x18) == 0x18) {
*nJoystickInputs &= ~0x18;
}
}
inline static INT32 CheckSleep(INT32)
{
#if 1 && defined USE_SPEEDHACKS
INT32 nCurrentPC = SekGetPC(-1);
if (!nIRQPending && nCurrentPC >= 0x06D6DE && nCurrentPC <= 0x06D6F4) {
return 1;
}
#endif
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Joysticks
DrvInput[1] = 0x0000; // Other controls
for (INT32 i = 0; i < 16; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
guwangeClearOpposites(((UINT8*)DrvInput) + 0);
guwangeClearOpposites(((UINT8*)DrvInput) + 1);
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nNext;
// Render sound segment
if ((i & 1) == 0) {
if (pBurnSoundOut) {
INT32 nSegmentEnd = nBurnSoundLen * i / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
YMZ280BRender(pSoundBuf, nSegmentEnd - nSoundBufferPos);
nSoundBufferPos = nSegmentEnd;
}
}
// Run 68000
nCurrentCPU = 0;
nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = -1;
}
// Make sure the buffer is entirely filled.
{
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
YMZ280BRender(pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
CaveSpriteROM = Next; Next += 0x2000000;
CaveTileROM[0] = Next; Next += 0x800000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x400000; // Tile layer 1
CaveTileROM[2] = Next; Next += 0x400000; // Tile layer 2
YMZ280BROM = Next; Next += 0x400000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveTileRAM[2] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap3(UINT8* pData, INT32 nLen)
{
for (INT32 i = 0; i < nLen; i++, pData += 2) {
UINT8 n1 = pData[0];
UINT8 n2 = pData[1];
pData[0] = (n1 << 4) | (n2 & 0x0F);
pData[1] = (n1 & 0xF0) | (n2 >> 4);
}
return;
}
static void NibbleSwap4(UINT8* pData, INT32 nLen)
{
for (INT32 i = 0; i < nLen; i++, pData += 2) {
UINT8 n1 = pData[0];
UINT8 n2 = pData[1];
pData[1] = (n2 << 4) | (n1 & 0x0F);
pData[0] = (n2 & 0xF0) | (n1 >> 4);
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 1, 2);
BurnLoadRom(Rom01 + 1, 0, 2);
BurnLoadRom(CaveSpriteROM + 0x0000000, 2, 2);
BurnLoadRom(CaveSpriteROM + 0x0000001, 3, 2);
BurnLoadRom(CaveSpriteROM + 0x1000000, 4, 2);
BurnLoadRom(CaveSpriteROM + 0x1000001, 5, 2);
NibbleSwap3(CaveSpriteROM, 0xC00000);
#if 1
for (INT32 i = 0; i < 0x100000; i++) {
UINT16 nValue = rand() & 0x0101;
if (nValue & 0x0001) {
nValue |= 0x00FF;
}
if (nValue & 0x0100) {
nValue |= 0xFF00;
}
((UINT16*)(CaveSpriteROM + 0x1800000))[i] = nValue;
((UINT16*)(CaveSpriteROM + 0x1A00000))[i] = nValue;
((UINT16*)(CaveSpriteROM + 0x1C00000))[i] = nValue;
((UINT16*)(CaveSpriteROM + 0x1E00000))[i] = nValue;
}
#else
memcpy(CaveSpriteROM + 0x1800000, CaveSpriteROM + 0x1000000, 0x800000);
#endif
BurnLoadRom(CaveTileROM[0] + 0x000000, 6, 1);
NibbleSwap4(CaveTileROM[0], 0x400000);
BurnLoadRom(CaveTileROM[1] + 0x000000, 7, 1);
NibbleSwap4(CaveTileROM[1], 0x200000);
BurnLoadRom(CaveTileROM[2] + 0x000000, 8, 1);
NibbleSwap4(CaveTileROM[2], 0x200000);
// Load YMZ280B data
BurnLoadRom(YMZ280BROM, 9, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction); // scan 68000 states
YMZ280BScan();
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
}
if (nAction & ACB_WRITE) {
CaveRecalcPalette = 1;
}
return 0;
}
static const UINT8 default_eeprom[16] = {0x00,0x0C,0x11,0x0D,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x11,0x11,0xFF,0xFF,0xFF,0xFF};
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
if (!EEPROMAvailable()) EEPROMFill(default_eeprom,0, sizeof(default_eeprom));
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x0FFFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x200000, 0x20FFFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x400000, 0x40FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x500000, 0x507FFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x600000, 0x607FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2], 0x700000, 0x707FFF, SM_RAM);
SekMapMemory(CavePalSrc, 0xC00000, 0xC0FFFF, SM_ROM); // Palette RAM (write goes through handler)
SekMapHandler(1, 0xC00000, 0xC0FFFF, SM_WRITE); //
SekSetReadWordHandler(0, guwangeReadWord);
SekSetReadByteHandler(0, guwangeReadByte);
SekSetWriteWordHandler(0, guwangeWriteWord);
SekSetWriteByteHandler(0, guwangeWriteByte);
SekSetWriteWordHandler(1, guwangeWriteWordPalette);
SekSetWriteByteHandler(1, guwangeWriteBytePalette);
SekClose();
}
nCaveRowModeOffset = 2;
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(1, 0x2000000);
CaveTileInitLayer(0, 0x800000, 8, 0x4000);
CaveTileInitLayer(1, 0x400000, 8, 0x4000);
CaveTileInitLayer(2, 0x400000, 8, 0x4000);
YMZ280BInit(16934400, &TriggerSoundIRQ, 3);
bDrawScreen = true;
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo guwangeRomDesc[] = {
{ "gu-u0127.bin", 0x080000, 0xF86B5293, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "gu-u0129.bin", 0x080000, 0x6C0E3B93, BRF_ESS | BRF_PRG }, // 1
{ "u083.bin", 0x800000, 0xADC4B9C4, BRF_GRA }, // 2 Sprite data
{ "u082.bin", 0x800000, 0x3D75876C, BRF_GRA }, // 3
{ "u086.bin", 0x400000, 0x188E4F81, BRF_GRA }, // 4
{ "u085.bin", 0x400000, 0xA7D5659E, BRF_GRA }, // 5
{ "u101.bin", 0x800000, 0x0369491F, BRF_GRA }, // 6 Layer 0 Tile data
{ "u10102.bin", 0x400000, 0xE28D6855, BRF_GRA }, // 7 Layer 1 Tile data
{ "u10103.bin", 0x400000, 0x0FE91B8E, BRF_GRA }, // 8 Layer 2 Tile data
{ "u0462.bin", 0x400000, 0xB3D75691, BRF_SND }, // 9 YMZ280B (AD)PCM data
{ "atc05-1.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "u0259.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "u084.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "u108.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "eeprom-guwange.bin", 0x0080, 0xc3174959, BRF_OPT },
};
STD_ROM_PICK(guwange)
STD_ROM_FN(guwange)
struct BurnDriver BurnDrvGuwange = {
"guwange", NULL, NULL, NULL, "1999",
"Guwange (Japan, master ver. 99/06/24)\0", NULL, "Atlus / Cave", "Cave",
L"\u3050\u308F\u3093\u3052 (Japan, master ver. 99/06/24)\0Guwange\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, guwangeRomInfo, guwangeRomName, NULL, NULL, guwangeInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};
static struct BurnRomInfo guwangesRomDesc[] = {
{ "gu-u0127b.bin",0x080000, 0x64667d2e, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "gu-u0129b.bin",0x080000, 0xa99C6b6c, BRF_ESS | BRF_PRG }, // 1
{ "u083.bin", 0x800000, 0xADC4B9C4, BRF_GRA }, // 2 Sprite data
{ "u082.bin", 0x800000, 0x3D75876C, BRF_GRA }, // 3
{ "u086.bin", 0x400000, 0x188E4F81, BRF_GRA }, // 4
{ "u085.bin", 0x400000, 0xA7D5659E, BRF_GRA }, // 5
{ "u101.bin", 0x800000, 0x0369491F, BRF_GRA }, // 6 Layer 0 Tile data
{ "u10102.bin", 0x400000, 0xE28D6855, BRF_GRA }, // 7 Layer 1 Tile data
{ "u10103.bin", 0x400000, 0x0FE91B8E, BRF_GRA }, // 8 Layer 2 Tile data
{ "u0462.bin", 0x400000, 0xB3D75691, BRF_SND }, // 9 YMZ280B (AD)PCM data
{ "atc05-1.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "u0259.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "u084.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "u108.bin", 0x000001, 0x00000000, BRF_NODUMP },
{ "eeprom-guwange.bin", 0x0080, 0xc3174959, BRF_OPT },
};
STD_ROM_PICK(guwanges)
STD_ROM_FN(guwanges)
struct BurnDriver BurnDrvGuwanges = {
"guwanges", "guwange", NULL, NULL, "1999",
"Guwange (Japan, special ver. 00/01/01)\0", NULL, "Atlus / Cave", "Cave",
L"\u3050\u308F\u3093\u3052 (Japan, special ver. 00/01/01)\0Guwange\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_VERSHOOT, 0,
NULL, guwangesRomInfo, guwangesRomName, NULL, NULL, guwangeInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 320, 3, 4
};

View File

@ -0,0 +1,757 @@
// hotdogst
#include "cave.h"
#include "msm6295.h"
#include "burn_ym2203.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01, *RomZ80;
static UINT8 *Ram01, *RamZ80;
static UINT8 *MSM6295ROMSrc;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCyclesTotal[2];
static INT32 nCyclesDone[2];
static UINT16 DrvSoundLatch;
static UINT8 DrvZ80Bank;
static UINT8 DrvOkiBank1;
static UINT8 DrvOkiBank2;
static struct BurnInputInfo hotdogstInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(hotdogst)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall hotdogstReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0xc80002:
return ((DrvInput[1] >> 8) ^ 0xF7) | (EEPROMRead() << 3);
default: {
bprintf(PRINT_NORMAL, _T("Attempt to read byte value of location %x\n"), sekAddress);
}
}
return 0;
}
void __fastcall hotdogstWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
if (~byteValue & 0x0100) {
case 0xd00000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
break;
}
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write byte value %x to location %x\n"), byteValue, sekAddress);
}
}
}
UINT16 __fastcall hotdogstReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0xa80000:
case 0xa80002: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0xa80004: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xa80006: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
// case 0xa8006e: {
// return 0xff;
// }
case 0xc80000:
return DrvInput[0] ^ 0xFFFF;
case 0xC80002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
bprintf(PRINT_NORMAL, _T("Attempt to read word value of location %x\n"), sekAddress);
}
}
return 0;
}
void __fastcall hotdogstWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0xa80000:
nCaveXOffset = wordValue;
return;
case 0xa80002:
nCaveYOffset = wordValue;
return;
case 0xa80008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0xa8006e: {
DrvSoundLatch = wordValue;
ZetNmi();
return;
}
case 0xb00000:
CaveTileReg[0][0] = wordValue;
break;
case 0xb00002:
CaveTileReg[0][1] = wordValue;
break;
case 0xb00004:
CaveTileReg[0][2] = wordValue;
break;
case 0xb80000:
CaveTileReg[1][0] = wordValue;
break;
case 0xb80002:
CaveTileReg[1][1] = wordValue;
break;
case 0xb80004:
CaveTileReg[1][2] = wordValue;
break;
case 0xc00000:
CaveTileReg[2][0] = wordValue;
break;
case 0xc00002:
CaveTileReg[2][1] = wordValue;
break;
case 0xc00004:
CaveTileReg[2][2] = wordValue;
break;
case 0xd00000:
if (~wordValue & 0x0100) {
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
break;
}
case 0xd00002: {
//nop
return;
}
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write word value %x to location %x\n"), wordValue, sekAddress);
}
}
}
UINT8 __fastcall hotdogstZIn(UINT16 nAddress)
{
nAddress &= 0xFF;
switch (nAddress) {
case 0x30: {
return DrvSoundLatch & 0xff;
}
case 0x40: {
return (DrvSoundLatch & 0xff00) >> 8;
}
case 0x50: {
return BurnYM2203Read(0, 0);
}
case 0x60: {
return MSM6295ReadStatus(0);
}
default: {
bprintf(PRINT_NORMAL, _T("Z80 Port Read %x\n"), nAddress);
}
}
return 0;
}
void __fastcall hotdogstZOut(UINT16 nAddress, UINT8 nValue)
{
nAddress &= 0xFF;
switch (nAddress) {
case 0x00: {
DrvZ80Bank = nValue & 0x0f;
ZetMapArea(0x4000, 0x7FFF, 0, RomZ80 + (DrvZ80Bank * 0x4000));
ZetMapArea(0x4000, 0x7FFF, 2, RomZ80 + (DrvZ80Bank * 0x4000));
return;
}
case 0x50: {
BurnYM2203Write(0, 0, nValue);
return;
}
case 0x51: {
BurnYM2203Write(0, 1, nValue);
return;
}
case 0x60: {
MSM6295Command(0, nValue);
return;
}
case 0x70: {
DrvOkiBank1 = (nValue >> 0) & 0x03;
DrvOkiBank2 = (nValue >> 4) & 0x03;
memcpy(MSM6295ROM + 0x00000, MSM6295ROMSrc + 0x20000 * DrvOkiBank1, 0x20000);
memcpy(MSM6295ROM + 0x20000, MSM6295ROMSrc + 0x20000 * DrvOkiBank2, 0x20000);
return;
}
default: {
bprintf(PRINT_NORMAL, _T("Z80 Port Write %x, %x\n"), nAddress, nValue);
}
}
}
UINT8 __fastcall hotdogstZRead(UINT16 a)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 Read => %04X\n"), a);
}
}
return 0;
}
void __fastcall hotdogstZWrite(UINT16 a, UINT8 d)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 Write => %04X, %02X\n"), a, d);
}
}
}
static INT32 DrvExit()
{
EEPROMExit();
MSM6295Exit(0);
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
ZetExit();
BurnYM2203Exit();
DrvSoundLatch = 0;
DrvZ80Bank = 0;
DrvOkiBank1 = 0;
DrvOkiBank2 = 0;
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
ZetOpen(0);
ZetReset();
ZetClose();
BurnYM2203Reset();
MSM6295Reset(0);
EEPROMReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
DrvSoundLatch = 0;
DrvZ80Bank = 0;
DrvOkiBank1 = 0;
DrvOkiBank2 = 0;
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate4Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x3F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 80;
INT32 nSoundBufferPos = 0;
INT32 nCyclesSegment;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 10; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
ZetNewFrame();
SekOpen(0);
ZetOpen(0);
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesTotal[1] = (INT32)(4000000 / CAVE_REFRESHRATE);
nCyclesDone[0] = nCyclesDone[1] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nCurrentCPU = 0;
INT32 nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// Run 68000
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
CaveSpriteBuffer();
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
BurnTimerUpdate(i * (nCyclesTotal[1] / nInterleave));
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
BurnYM2203Update(pSoundBuf, nSegmentLength);
MSM6295Render(0, pSoundBuf, nSegmentLength);
nSoundBufferPos += nSegmentLength;
}
}
SekClose();
BurnTimerEndFrame(nCyclesTotal[1]);
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
BurnYM2203Update(pSoundBuf, nSegmentLength);
MSM6295Render(0, pSoundBuf, nSegmentLength);
}
}
ZetClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
RomZ80 = Next; Next += 0x040000;
CaveSpriteROM = Next; Next += 0x800000;
CaveTileROM[0] = Next; Next += 0x100000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x100000; // Tile layer 1
CaveTileROM[2] = Next; Next += 0x100000; // Tile layer 2
MSM6295ROM = Next; Next += 0x040000;
MSM6295ROMSrc = Next; Next += 0x080000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
RamZ80 = Next; Next += 0x002000;
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveTileRAM[2] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x001000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap2(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[1] = *pOrg & 15;
pDest[0] = *pOrg >> 4;
}
return;
}
static INT32 LoadRoms()
{
BurnLoadRom(Rom01 + 1, 0, 2);
BurnLoadRom(Rom01 + 0, 1, 2);
BurnLoadRom(RomZ80, 2, 1);
BurnLoadRom(CaveSpriteROM + 0x000000, 3, 1);
BurnLoadRom(CaveSpriteROM + 0x200000, 4, 1);
NibbleSwap1(CaveSpriteROM, 0x400000);
BurnLoadRom(CaveTileROM[0], 5, 1);
NibbleSwap2(CaveTileROM[0], 0x080000);
BurnLoadRom(CaveTileROM[1], 6, 1);
NibbleSwap2(CaveTileROM[1], 0x080000);
BurnLoadRom(CaveTileROM[2], 7, 1);
NibbleSwap2(CaveTileROM[2], 0x080000);
// Load MSM6295 ADPCM data
BurnLoadRom(MSM6295ROMSrc, 8, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction);
ZetScan(nAction);
BurnYM2203Scan(nAction, pnMin);
MSM6295Scan(0, nAction);
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
SCAN_VAR(DrvSoundLatch);
SCAN_VAR(DrvZ80Bank);
SCAN_VAR(DrvOkiBank1);
SCAN_VAR(DrvOkiBank2);
}
if (nAction & ACB_WRITE) {
ZetOpen(0);
ZetMapArea(0x4000, 0x7FFF, 0, RomZ80 + (DrvZ80Bank * 0x4000));
ZetMapArea(0x4000, 0x7FFF, 2, RomZ80 + (DrvZ80Bank * 0x4000));
ZetClose();
memcpy(MSM6295ROM + 0x00000, MSM6295ROMSrc + 0x20000 * DrvOkiBank1, 0x20000);
memcpy(MSM6295ROM + 0x20000, MSM6295ROMSrc + 0x20000 * DrvOkiBank2, 0x20000);
CaveRecalcPalette = 1;
}
return 0;
}
static void DrvFMIRQHandler(INT32, INT32 nStatus)
{
if (nStatus & 1) {
ZetSetIRQLine(0xff, ZET_IRQSTATUS_ACK);
} else {
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
}
}
static INT32 DrvSynchroniseStream(INT32 nSoundRate)
{
return (INT64)ZetTotalCycles() * nSoundRate / 4000000;
}
static double DrvGetTime()
{
return (double)ZetTotalCycles() / 4000000;
}
static INT32 drvZInit()
{
ZetInit(1);
ZetOpen(0);
ZetSetInHandler(hotdogstZIn);
ZetSetOutHandler(hotdogstZOut);
ZetSetReadHandler(hotdogstZRead);
ZetSetWriteHandler(hotdogstZWrite);
// ROM bank 1
ZetMapArea (0x0000, 0x3FFF, 0, RomZ80 + 0x0000); // Direct Read from ROM
ZetMapArea (0x0000, 0x3FFF, 2, RomZ80 + 0x0000); // Direct Fetch from ROM
// ROM bank 2
ZetMapArea (0x4000, 0x7FFF, 0, RomZ80 + 0x4000); // Direct Read from ROM
ZetMapArea (0x4000, 0x7FFF, 2, RomZ80 + 0x4000); //
// RAM
ZetMapArea (0xE000, 0xFFFF, 0, RamZ80); // Direct Read from RAM
ZetMapArea (0xE000, 0xFFFF, 1, RamZ80); // Direct Write to RAM
ZetMapArea (0xE000, 0xFFFF, 2, RamZ80); //
ZetMemEnd();
ZetClose();
return 0;
}
static const UINT8 default_eeprom[16] = {0xF3,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
if (!EEPROMAvailable()) EEPROMFill(default_eeprom,0, sizeof(default_eeprom));
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x0FFFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x300000, 0x30FFFF, SM_RAM);
SekMapMemory(CavePalSrc, 0x408000, 0x408FFF, SM_RAM); // Palette RAM
SekMapMemory(CaveTileRAM[0], 0x880000, 0x887FFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x900000, 0x907FFF, SM_RAM);
SekMapMemory(CaveTileRAM[2], 0x980000, 0x987FFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0xf00000, 0xf0fFFF, SM_RAM);
SekSetReadByteHandler(0, hotdogstReadByte);
SekSetWriteByteHandler(0, hotdogstWriteByte);
SekSetReadWordHandler(0, hotdogstReadWord);
SekSetWriteWordHandler(0, hotdogstWriteWord);
SekClose();
}
drvZInit();
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(2, 0x0800000);
CaveTileInitLayer(0, 0x100000, 8, 0);
CaveTileInitLayer(1, 0x100000, 8, 0);
CaveTileInitLayer(2, 0x100000, 8, 0);
nCaveExtraXOffset = -32;
nCaveExtraYOffset = 32;
BurnYM2203Init(1, 4000000, &DrvFMIRQHandler, DrvSynchroniseStream, DrvGetTime, 0);
BurnTimerAttachZet(4000000);
memcpy(MSM6295ROM, MSM6295ROMSrc, 0x40000);
MSM6295Init(0, 1056000 / 132, 50.0, 1);
bDrawScreen = true;
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo hotdogstRomDesc[] = {
{ "mp3.u29", 0x080000, 0x1f4e5479, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "mp4.u28", 0x080000, 0x6f1c3c4b, BRF_ESS | BRF_PRG }, // 1
{ "mp2.u19", 0x040000, 0xff979ebe, BRF_ESS | BRF_PRG }, // 2 Z80 Code
{ "mp9.u55", 0x200000, 0x258d49ec, BRF_GRA }, // 3 Sprite data
{ "mp8.u54", 0x200000, 0xbdb4d7b8, BRF_GRA }, // 4
{ "mp7.u56", 0x080000, 0x87c21c50, BRF_GRA }, // 5 Layer 0 Tile data
{ "mp6.u61", 0x080000, 0x4dafb288, BRF_GRA }, // 6 Layer 1 Tile data
{ "mp5.u64", 0x080000, 0x9b26458c, BRF_GRA }, // 7 Layer 2 Tile data
{ "mp1.u65", 0x080000, 0x4868be1b, BRF_SND }, // 8 MSM6295 #1 ADPCM data
{ "eeprom-hotdogst.bin", 0x0080, 0x12b4f934, BRF_OPT },
};
STD_ROM_PICK(hotdogst)
STD_ROM_FN(hotdogst)
struct BurnDriver BurnDrvhotdogst = {
"hotdogst", NULL, NULL, NULL, "1996",
"Hotdog Storm - The First Supersonics (International)\0", NULL, "Marble / ACE International", "Cave",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_Z80, GBF_VERSHOOT, 0,
NULL, hotdogstRomInfo, hotdogstRomName, NULL, NULL, hotdogstInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 384, 3, 4
};

View File

@ -0,0 +1,734 @@
// Koro Koro Quest & Crusher Makochan
#include "cave.h"
#include "ymz280b.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvDip[1];
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT32 korokoro_hopper = 0;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCurrentCPU;
static INT32 nCyclesDone[2];
static INT32 nCyclesTotal[2];
static INT32 nCyclesSegment;
static const eeprom_interface eeprom_interface_93C46_8bit =
{
7, // address bits 7
8, // data bits 8
"*110", // read 1 10 aaaaaa
"*101", // write 1 01 aaaaaa dddddddddddddddd
"*111", // erase 1 11 aaaaaa
"*10000xxxx", // lock 1 00 00xxxx
"*10011xxxx", // unlock 1 00 11xxxx
1,
0
};
static struct BurnInputInfo KorokoroInputList[] = {
{"Coin 1", BIT_DIGITAL, DrvJoy1 + 0, "p1 coin" },
{"Coin 2", BIT_DIGITAL, DrvJoy1 + 1, "p2 coin" },
{"Coin 3", BIT_DIGITAL, DrvJoy1 + 2, "p3 coin" },
{"Button 1", BIT_DIGITAL, DrvJoy1 + 3, "p1 fire 1" },
{"Button 2", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 2" },
{"Reset", BIT_DIGITAL, &DrvReset, "reset" },
{"Service", BIT_DIGITAL, DrvJoy1 + 14, "service" },
{"Service", BIT_DIGITAL, DrvJoy1 + 12, "service" },
{"Dip A", BIT_DIPSWITCH, DrvDip + 0, "dip" },
};
STDINPUTINFO(Korokoro)
static struct BurnDIPInfo KorokoroDIPList[]=
{
{0x08, 0xff, 0xff, 0x20, NULL },
{0 , 0xfe, 0 , 2, "Service Mode" },
{0x08, 0x01, 0x20, 0x00, "On" },
{0x08, 0x01, 0x20, 0x20, "Off" },
};
STDDIPINFO(Korokoro)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(2, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall korokoroReadByte(UINT32 sekAddress)
{
switch (sekAddress)
{
case 0x1c0000:
case 0x1c0001:
case 0x300000:
case 0x300001:
return (nUnknownIRQ << 1) | nVideoIRQ | (bVBlank ? 0 : 4);
case 0x1c0002:
case 0x1c0003:
case 0x300002:
case 0x300003:
return (nUnknownIRQ << 1) | nVideoIRQ;
case 0x1c0004:
case 0x1c0005:
case 0x300004:
case 0x300005:
nVideoIRQ = 1;
UpdateIRQStatus();
return (nUnknownIRQ << 1) | nVideoIRQ;
case 0x1c0006:
case 0x1c0007:
case 0x300006:
case 0x300007:
nUnknownIRQ = 1;
UpdateIRQStatus();
return (nUnknownIRQ << 1) | nVideoIRQ;
case 0x280000:
return ((DrvInput[0] >> 8) & 0x5F) | (korokoro_hopper ? 0x00 : 0x80) | (DrvDip[0] & 0x20);
case 0x280001:
return DrvInput[0] & 0xFF;
case 0x280002:
return ((DrvInput[1] >> 8) & 0xEF) | (EEPROMRead() ? 0x10 : 0x00);
case 0x280003:
return DrvInput[1] & 0xFF;
// default:
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
return 0;
}
UINT16 __fastcall korokoroReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x1c0000:
case 0x300000:
return (nUnknownIRQ << 1) | nVideoIRQ | (bVBlank ? 4 : 0);
case 0x1c0002:
case 0x300002:
return (nUnknownIRQ << 1) | nVideoIRQ;
case 0x1c0004:
case 0x300004:
nVideoIRQ = 1;
UpdateIRQStatus();
return (nUnknownIRQ << 1) | nVideoIRQ;
case 0x1c0006:
case 0x300006:
nUnknownIRQ = 1;
UpdateIRQStatus();
return (nUnknownIRQ << 1) | nVideoIRQ;
case 0x280000:
return (DrvInput[0] & 0x5FFF) | (korokoro_hopper ? 0x0000 : 0x8000) | ((DrvDip[0] & 0x20) << 8);
case 0x280002:
return (DrvInput[1] & 0xEFFF) | ((EEPROMRead() & 1) ? 0x1000 : 0x0000);
// default:
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
return 0;
}
void __fastcall korokoroWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x240001:
YMZ280BSelectRegister(byteValue);
break;
case 0x240003:
YMZ280BWriteRegister(byteValue);
break;
case 0x280008:
case 0x280009:
// leds
break;
case 0x28000a:
korokoro_hopper = byteValue & 0x01;
EEPROMWrite(byteValue & 0x20, byteValue & 0x10, byteValue & 0x40);
break;
// default:
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
void __fastcall korokoroWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x140000:
CaveTileReg[0][0] = wordValue;
break;
case 0x140002:
CaveTileReg[0][1] = wordValue;
break;
case 0x140004:
CaveTileReg[0][2] = wordValue;
break;
case 0x1c0000:
case 0x300000:
nCaveXOffset = wordValue;
return;
case 0x1c0002:
case 0x300002:
nCaveYOffset = wordValue;
return;
case 0x1c0008:
case 0x300008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x240000:
YMZ280BSelectRegister(wordValue & 0xff);
break;
case 0x240002:
YMZ280BWriteRegister(wordValue & 0xff);
break;
case 0x280008:
return;
case 0x28000a: {
wordValue >>= 8;
korokoro_hopper = wordValue & 0x01;
EEPROMWrite(wordValue & 0x20, wordValue & 0x10, wordValue & 0x40);
break;
}
// default:
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
static void TriggerSoundIRQ(INT32 nStatus)
{
nSoundIRQ = nStatus ^ 1;
UpdateIRQStatus();
if (nIRQPending && nCurrentCPU != 0) {
nCyclesDone[0] += SekRun(0x0400);
}
}
static INT32 DrvExit()
{
YMZ280BExit();
EEPROMExit();
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
BurnFree(Mem);
Mem = NULL;
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
YMZ280BReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
YMZ280BReset();
return 0;
}
inline static UINT32 CalcCol(UINT16 nColour)
{
INT32 r, g, b;
r = (nColour & 0x03E0) >> 2; // Red
r |= r >> 5;
g = (nColour & 0x7C00) >> 7; // Green
g |= g >> 5;
b = (nColour & 0x001F) << 3; // Blue
b |= b >> 5;
return BurnHighCol(r, g, b, 0);
}
static void KorokoroPaletteUpdate()
{
for (INT32 color = 0; color < 0x40; color++) {
for (INT32 pen = 0; pen < 0x10; pen++) {
CavePalette[(color << 8) | pen] = CalcCol(*(UINT16*)(CavePalSrc + ((0x3c00 | (color << 4) | pen)*2)));
}
for (INT32 pen = 0x10; pen < 0x100; pen++) {
CavePalette[(color << 8) | pen] = CalcCol(*(UINT16*)(CavePalSrc + ((0x0000 | (color << 8) | pen)*2)));
}
}
for (INT32 color = 0; color < 0x4000; color++) {
CavePalette[color+0x4000] = CalcCol(*(UINT16*)(CavePalSrc + color*2));
}
pBurnDrvPalette = CavePalette;
}
static INT32 DrvDraw()
{
KorokoroPaletteUpdate(); // Update the palette
CaveClearScreen(CavePalette[0x3F00]);
CaveSpriteBuffer();
if (bDrawScreen) {
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0; // Player 1
DrvInput[1] = 0; // Player 2
for (INT32 i = 0; i < 16; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
DrvInput[0] ^= 0xffff;
DrvInput[1] ^= 0xffff;
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nNext;
// Render sound segment
if ((i & 1) == 0) {
if (pBurnSoundOut) {
INT32 nSegmentEnd = nBurnSoundLen * i / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
YMZ280BRender(pSoundBuf, nSegmentEnd - nSoundBufferPos);
nSoundBufferPos = nSegmentEnd;
}
}
// Run 68000
nCurrentCPU = 0;
nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = -1;
}
{
// Make sure the buffer is entirely filled.
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
YMZ280BRender(pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction); // scan 68000 states
YMZ280BScan();
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
SCAN_VAR(korokoro_hopper);
CaveScanGraphics();
}
return 0;
}
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x080000; // 68K program
CaveSpriteROM = Next; Next += 0x400000;
CaveTileROM[0] = Next; Next += 0x200000; // Tile layer 0
YMZ280BROM = Next; Next += 0x200000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
CaveTileRAM[0] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap2(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[1] = *pOrg & 15;
pDest[0] = *pOrg >> 4;
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 0, 1);
BurnLoadRom(CaveSpriteROM + 0x0000000, 1, 1);
BurnLoadRom(CaveSpriteROM + 0x0100000, 2, 1);
NibbleSwap1(CaveSpriteROM + 0x0000000, 0x180000);
BurnLoadRom(CaveTileROM[0] + 0x000000, 3, 1);
NibbleSwap2(CaveTileROM[0], 0x100000);
// Load YMZ280B data
BurnLoadRom(YMZ280BROM, 4, 1);
return 0;
}
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)BurnMalloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46_8bit);
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x07FFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(CaveTileRAM[0], 0x100000, 0x107FFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x180000, 0x187FFF, SM_RAM);
SekMapMemory(CavePalSrc, 0x200000, 0x207FFF, SM_RAM);
SekMapMemory(Ram01, 0x300000, 0x30FFFF, SM_RAM);
SekSetReadWordHandler(0, korokoroReadWord);
SekSetReadByteHandler(0, korokoroReadByte);
SekSetWriteWordHandler(0, korokoroWriteWord);
SekSetWriteByteHandler(0, korokoroWriteByte);
SekClose();
}
nCaveRowModeOffset = 1;
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(1, 0x300000);
CaveTileInitLayer(0, 0x200000, 4, 0x4400);
YMZ280BInit(16934400, &TriggerSoundIRQ, 3);
bDrawScreen = true;
DrvDoReset(); // Reset machine
return 0;
}
static INT32 crushermLoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 0, 1);
BurnLoadRom(CaveSpriteROM + 0x0000000, 1, 1);
BurnLoadRom(CaveSpriteROM + 0x0100000, 2, 1);
NibbleSwap1(CaveSpriteROM + 0x0000000, 0x200000);
BurnLoadRom(CaveTileROM[0] + 0x000000, 3, 1);
NibbleSwap2(CaveTileROM[0], 0x100000);
// Load YMZ280B data
BurnLoadRom(YMZ280BROM + 0x000000, 4, 1);
BurnLoadRom(YMZ280BROM + 0x100000, 5, 1);
return 0;
}
static INT32 crushermInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)BurnMalloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46_8bit);
// Load the roms into memory
if (crushermLoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x07FFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(CaveTileRAM[0], 0x100000, 0x107FFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x180000, 0x187FFF, SM_RAM);
SekMapMemory(CavePalSrc, 0x200000, 0x207FFF, SM_RAM);
SekMapMemory(Ram01, 0x340000, 0x34FFFF, SM_RAM);
SekSetReadWordHandler(0, korokoroReadWord);
SekSetReadByteHandler(0, korokoroReadByte);
SekSetWriteWordHandler(0, korokoroWriteWord);
SekSetWriteByteHandler(0, korokoroWriteByte);
SekClose();
}
nCaveRowModeOffset = 1;
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(1, 0x400000);
CaveTileInitLayer(0, 0x200000, 4, 0x4400);
YMZ280BInit(16934400, &TriggerSoundIRQ, 3);
bDrawScreen = true;
DrvDoReset(); // Reset machine
return 0;
}
// Koro Koro Quest (Japan)
static struct BurnRomInfo korokoroRomDesc[] = {
{ "mp-001_ver07.u0130", 0x080000, 0x86c7241f, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "mp-001_ver01.u1066", 0x100000, 0xc5c6af7e, BRF_GRA }, // 1 Sprite data
{ "mp-001_ver01.u1051", 0x080000, 0xfe5e28e8, BRF_GRA }, // 2
{ "mp-001_ver01.u1060", 0x100000, 0xec9cf9d8, BRF_GRA }, // 3 layer 0 Tile data
{ "mp-001_ver01.u1186", 0x100000, 0xd16e7c5d, BRF_SND }, // 4 YMZ280B (AD)PCM data
};
STD_ROM_PICK(korokoro)
STD_ROM_FN(korokoro)
struct BurnDriver BurnDrvKorokoro = {
"korokoro", NULL, NULL, NULL, "1999",
"Koro Koro Quest (Japan)\0", NULL, "Takumi", "Cave",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_MISC, 0,
NULL, korokoroRomInfo, korokoroRomName, NULL, NULL, KorokoroInputInfo, KorokoroDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 320, 240, 4, 3
};
// Crusher Makochan (Japan)
static struct BurnRomInfo crushermRomDesc[] = {
{ "mp-003ver01.u0130", 0x080000, 0xa4f56e6b, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "mp-003ver01.u1067", 0x100000, 0x268a4921, BRF_GRA }, // 1 Sprite data
{ "mp-003ver01.u1066", 0x100000, 0x79e77a6e, BRF_GRA }, // 2
{ "mp-003ver01.u1060", 0x100000, 0x7661893e, BRF_GRA }, // 3 layer 0 Tile data
{ "mp-003ver01.u1186", 0x100000, 0xc3aeb745, BRF_SND }, // 4 YMZ280B (AD)PCM data
{ "mp-003ver01.u1187", 0x100000, 0xd9312497, BRF_SND }, // 5
};
STD_ROM_PICK(crusherm)
STD_ROM_FN(crusherm)
struct BurnDriver BurnDrvCrusherm = {
"crusherm", NULL, NULL, NULL, "1999",
"Crusher Makochan (Japan)\0", NULL, "Takumi", "Miscellaneous",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_MISC, 0,
NULL, crushermRomInfo, crushermRomName, NULL, NULL, KorokoroInputInfo, KorokoroDIPInfo,
crushermInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 320, 240, 4, 3
};

View File

@ -0,0 +1,846 @@
// mazinger
#include "cave.h"
#include "msm6295.h"
#include "burn_ym2203.h"
#include "bitswap.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01, *RomZ80;
static UINT8 *Ram01, *RamZ80;
static UINT8 *MSM6295ROMSrc;
static UINT8 *DefEEPROM = NULL;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCyclesTotal[2];
static INT32 nCyclesDone[2];
static INT32 SoundLatch;
static INT32 SoundLatchReply[48];
static INT32 SoundLatchStatus;
static INT32 SoundLatchReplyIndex;
static INT32 SoundLatchReplyMax;
static UINT8 DrvZ80Bank;
static UINT8 DrvOkiBank1;
static UINT8 DrvOkiBank2;
static struct BurnInputInfo mazingerInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(mazinger)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall mazingerReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x800002:
return (DrvInput[1] ^ 0xF7) | (EEPROMRead() << 3);
case 0x800003:
return (DrvInput[1] & 0xFF) ^ 0xFF;
default: {
bprintf(PRINT_NORMAL, _T("Attempt to read byte value of location %x\n"), sekAddress);
}
}
return 0;
}
void __fastcall mazingerWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x900000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
break;
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write byte value %x to location %x\n"), byteValue, sekAddress);
}
}
}
UINT16 __fastcall mazingerReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300000:
case 0x300002: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x300004: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x300006: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x30006E:
if (SoundLatchReplyIndex > SoundLatchReplyMax) {
SoundLatchReplyIndex = 0;
SoundLatchReplyMax = -1;
return 0;
}
return SoundLatchReply[SoundLatchReplyIndex++];
case 0x800000:
return DrvInput[0] ^ 0xFFFF;
case 0x800002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
bprintf(PRINT_NORMAL, _T("Attempt to read word value of location %x\n"), sekAddress);
}
}
return 0;
}
void __fastcall mazingerWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
if (sekAddress >= 0x30000a && sekAddress <= 0x300066) return;
if (sekAddress >= 0x30006a && sekAddress <= 0x30006c) return;
if (sekAddress >= 0x300004 && sekAddress <= 0x300006) return;
switch (sekAddress) {
case 0x300000:
nCaveXOffset = wordValue;
return;
case 0x300002:
nCaveYOffset = wordValue;
return;
case 0x300008:
// CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x30006e:
SoundLatch = wordValue;
SoundLatchStatus |= 0x0C;
ZetNmi();
nCyclesDone[1] += ZetRun(0x0400);
return;
case 0x600000:
CaveTileReg[1][0] = wordValue;
break;
case 0x600002:
CaveTileReg[1][1] = wordValue;
break;
case 0x600004:
CaveTileReg[1][2] = wordValue;
break;
case 0x700000:
CaveTileReg[0][0] = wordValue;
break;
case 0x700002:
CaveTileReg[0][1] = wordValue;
break;
case 0x700004:
CaveTileReg[0][2] = wordValue;
break;
case 0x900000:
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
break;
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write word value %x to location %x\n"), wordValue, sekAddress);
}
}
}
void __fastcall mazingerWriteBytePalette(UINT32 sekAddress, UINT8 byteValue)
{
CavePalWriteByte(sekAddress & 0xffff, byteValue);
}
void __fastcall mazingerWriteWordPalette(UINT32 sekAddress, UINT16 wordValue)
{
CavePalWriteWord(sekAddress & 0xffff, wordValue);
}
UINT8 __fastcall mazingerZIn(UINT16 nAddress)
{
nAddress &= 0xFF;
switch (nAddress) {
case 0x30: {
SoundLatchStatus |= 0x04;
return SoundLatch & 0xFF;
}
case 0x52: {
return BurnYM2203Read(0, 0);
}
default: {
bprintf(PRINT_NORMAL, _T("Z80 Port Read %x\n"), nAddress);
}
}
return 0;
}
void __fastcall mazingerZOut(UINT16 nAddress, UINT8 nValue)
{
nAddress &= 0xFF;
switch (nAddress) {
case 0x00: {
DrvZ80Bank = nValue & 0x07;
ZetMapArea(0x4000, 0x7FFF, 0, RomZ80 + (DrvZ80Bank * 0x4000));
ZetMapArea(0x4000, 0x7FFF, 2, RomZ80 + (DrvZ80Bank * 0x4000));
return;
}
case 0x10:
if (SoundLatchReplyIndex > SoundLatchReplyMax) {
SoundLatchReplyMax = -1;
SoundLatchReplyIndex = 0;
}
SoundLatchReplyMax++;
SoundLatchReply[SoundLatchReplyMax] = nValue;
break;
case 0x50: {
BurnYM2203Write(0, 0, nValue);
return;
}
case 0x51: {
BurnYM2203Write(0, 1, nValue);
return;
}
case 0x70: {
MSM6295Command(0, nValue);
return;
}
case 0x74: {
DrvOkiBank1 = (nValue >> 0) & 0x03;
DrvOkiBank2 = (nValue >> 4) & 0x03;
memcpy(MSM6295ROM + 0x00000, MSM6295ROMSrc + 0x20000 * DrvOkiBank1, 0x20000);
memcpy(MSM6295ROM + 0x20000, MSM6295ROMSrc + 0x20000 * DrvOkiBank2, 0x20000);
return;
}
default: {
bprintf(PRINT_NORMAL, _T("Z80 Port Write %x, %x\n"), nAddress, nValue);
}
}
}
UINT8 __fastcall mazingerZRead(UINT16 a)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 Read => %04X\n"), a);
}
}
return 0;
}
void __fastcall mazingerZWrite(UINT16 a, UINT8 d)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 Write => %04X, %02X\n"), a, d);
}
}
}
static INT32 DrvExit()
{
EEPROMExit();
MSM6295Exit(0);
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
ZetExit();
BurnYM2203Exit();
SoundLatch = 0;
DrvZ80Bank = 0;
DrvOkiBank1 = 0;
DrvOkiBank2 = 0;
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekRun(10000); // Need to run for a bit and reset to make it start - Watchdog would force reset?
SekReset();
SekClose();
ZetOpen(0);
ZetReset();
ZetClose();
BurnYM2203Reset();
MSM6295Reset(0);
EEPROMReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
SoundLatch = 0;
DrvZ80Bank = 0;
DrvOkiBank1 = 0;
DrvOkiBank2 = 0;
SoundLatch = 0;
SoundLatchStatus = 0x0C;
memset(SoundLatchReply, 0, sizeof(SoundLatchReply));
SoundLatchReplyIndex = 0;
SoundLatchReplyMax = -1;
return 0;
}
static INT32 DrvDraw()
{
if (CaveRecalcPalette) {
CavePalUpdate8Bit(0x4400, 12);
CaveRecalcPalette = 1;
}
CavePalUpdate4Bit(0, 64);
CaveClearScreen(CavePalette[0x3F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 80;
INT32 nSoundBufferPos = 0;
INT32 nCyclesSegment;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 10; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
ZetNewFrame();
SekOpen(0);
ZetOpen(0);
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesTotal[1] = (INT32)(4000000 / CAVE_REFRESHRATE);
nCyclesDone[0] = nCyclesDone[1] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nCurrentCPU = 0;
INT32 nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// Run 68000
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
CaveSpriteBuffer();
UINT8 Temp = nCaveSpriteBank;
nCaveSpriteBank = nCaveSpriteBankDelay;
nCaveSpriteBankDelay = Temp;
bVBlank = true;
nVideoIRQ = 0;
nUnknownIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
BurnTimerUpdate(i * (nCyclesTotal[1] / nInterleave));
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
BurnYM2203Update(pSoundBuf, nSegmentLength);
MSM6295Render(0, pSoundBuf, nSegmentLength);
nSoundBufferPos += nSegmentLength;
}
}
SekClose();
BurnTimerEndFrame(nCyclesTotal[1]);
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
BurnYM2203Update(pSoundBuf, nSegmentLength);
MSM6295Render(0, pSoundBuf, nSegmentLength);
}
}
ZetClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
RomZ80 = Next; Next += 0x020000;
CaveSpriteROM = Next; Next += 0x800000;
CaveTileROM[0] = Next; Next += 0x400000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x400000; // Tile layer 1
MSM6295ROM = Next; Next += 0x040000;
MSM6295ROMSrc = Next; Next += 0x080000;
DefEEPROM = Next; Next += 0x000080;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
RamZ80 = Next; Next += 0x001000;
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap2(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[1] = *pOrg & 15;
pDest[0] = *pOrg >> 4;
}
return;
}
static INT32 LoadRoms()
{
BurnLoadRom(Rom01 + 0x00000, 0, 1);
BurnLoadRom(Rom01 + 0x80000, 1, 1);
BurnLoadRom(RomZ80, 2, 1);
UINT8 *pTemp = (UINT8*)malloc(0x400000);
BurnLoadRom(pTemp + 0x000000, 3, 1);
BurnLoadRom(pTemp + 0x200000, 4, 1);
for (INT32 i = 0; i < 0x400000; i++) {
CaveSpriteROM[i ^ 0xdf88] = pTemp[BITSWAP24(i,23,22,21,20,19,9,7,3,15,4,17,14,18,2,16,5,11,8,6,13,1,10,12,0)];
}
if (pTemp) {
free(pTemp);
pTemp = NULL;
}
NibbleSwap1(CaveSpriteROM, 0x400000);
BurnLoadRom(CaveTileROM[0], 5, 1);
NibbleSwap2(CaveTileROM[0], 0x200000);
pTemp = (UINT8*)malloc(0x200000);
BurnLoadRom(pTemp, 6, 1);
for (INT32 i = 0; i < 0x0100000; i++) {
CaveTileROM[1][(i << 1) + 1] = (pTemp[(i << 1) + 0] & 15) | ((pTemp[(i << 1) + 1] & 15) << 4);
CaveTileROM[1][(i << 1) + 0] = (pTemp[(i << 1) + 0] >> 4) | (pTemp[(i << 1) + 1] & 240);
}
if (pTemp) {
free(pTemp);
pTemp = NULL;
}
// Load MSM6295 ADPCM data
BurnLoadRom(MSM6295ROMSrc, 7, 1);
BurnLoadRom(DefEEPROM, 8, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction);
ZetScan(nAction);
BurnYM2203Scan(nAction, pnMin);
MSM6295Scan(0, nAction);
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
SCAN_VAR(SoundLatch);
SCAN_VAR(DrvZ80Bank);
SCAN_VAR(DrvOkiBank1);
SCAN_VAR(DrvOkiBank2);
if (nAction & ACB_WRITE) {
ZetOpen(0);
ZetMapArea(0x4000, 0x7FFF, 0, RomZ80 + (DrvZ80Bank * 0x4000));
ZetMapArea(0x4000, 0x7FFF, 2, RomZ80 + (DrvZ80Bank * 0x4000));
ZetClose();
memcpy(MSM6295ROM + 0x00000, MSM6295ROMSrc + 0x20000 * DrvOkiBank1, 0x20000);
memcpy(MSM6295ROM + 0x20000, MSM6295ROMSrc + 0x20000 * DrvOkiBank2, 0x20000);
CaveRecalcPalette = 1;
}
}
return 0;
}
static void DrvFMIRQHandler(INT32, INT32 nStatus)
{
if (nStatus & 1) {
ZetSetIRQLine(0xff, ZET_IRQSTATUS_ACK);
} else {
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
}
}
static INT32 DrvSynchroniseStream(INT32 nSoundRate)
{
return (INT64)ZetTotalCycles() * nSoundRate / 4000000;
}
static double DrvGetTime()
{
return (double)ZetTotalCycles() / 4000000;
}
static INT32 drvZInit()
{
ZetInit(1);
ZetOpen(0);
ZetSetInHandler(mazingerZIn);
ZetSetOutHandler(mazingerZOut);
ZetSetReadHandler(mazingerZRead);
ZetSetWriteHandler(mazingerZWrite);
// ROM bank 1
ZetMapArea (0x0000, 0x3FFF, 0, RomZ80 + 0x0000); // Direct Read from ROM
ZetMapArea (0x0000, 0x3FFF, 2, RomZ80 + 0x0000); // Direct Fetch from ROM
// ROM bank 2
ZetMapArea (0x4000, 0x7FFF, 0, RomZ80 + 0x4000); // Direct Read from ROM
ZetMapArea (0x4000, 0x7FFF, 2, RomZ80 + 0x4000); //
// RAM
ZetMapArea (0xc000, 0xc7FF, 0, RamZ80 + 0x0000); // Direct Read from RAM
ZetMapArea (0xc000, 0xc7FF, 1, RamZ80 + 0x0000); // Direct Write to RAM
ZetMapArea (0xc000, 0xc7FF, 2, RamZ80 + 0x0000); //
ZetMapArea (0xf800, 0xffFF, 0, RamZ80 + 0x0800); // Direct Read from RAM
ZetMapArea (0xf800, 0xffFF, 1, RamZ80 + 0x0800); // Direct Write to RAM
ZetMapArea (0xf800, 0xffFF, 2, RamZ80 + 0x0800); //
ZetMemEnd();
ZetClose();
return 0;
}
static const UINT8 default_eeprom[16] = {0xED,0xFF,0x00,0x00,0x12,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x07FFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x200000, 0x20FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[1] + 0x4000, 0x400000, 0x403FFF, SM_RAM);
SekMapMemory(CaveTileRAM[1] + 0x4000, 0x404000, 0x407FFF, SM_RAM);
SekMapMemory(CaveTileRAM[0] + 0x4000, 0x500000, 0x503FFF, SM_RAM);
SekMapMemory(CaveTileRAM[0] + 0x4000, 0x504000, 0x507FFF, SM_RAM);
SekMapMemory(CavePalSrc, 0xC08000, 0xc087FF, SM_RAM); // Palette RAM
SekMapMemory(CavePalSrc + 0x8800, 0xC08800, 0xC0FFFF, SM_ROM); // Palette RAM (write goes through handler)
SekMapHandler(1, 0xC08800, 0xC0FFFF, SM_WRITE); //
SekMapMemory(Rom01 + 0x80000, 0xD00000, 0xD7FFFF, SM_ROM); // CPU 0 ROM
SekSetReadByteHandler(0, mazingerReadByte);
SekSetWriteByteHandler(0, mazingerWriteByte);
SekSetReadWordHandler(0, mazingerReadWord);
SekSetWriteWordHandler(0, mazingerWriteWord);
SekSetWriteWordHandler(1, mazingerWriteWordPalette);
SekSetWriteByteHandler(1, mazingerWriteBytePalette);
SekClose();
}
drvZInit();
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(2, 0x0800000);
CaveTileInitLayer(0, 0x400000, 8, 0x0000);
CaveTileInitLayer(1, 0x400000, 6, 0x4400);
BurnYM2203Init(1, 4000000, &DrvFMIRQHandler, DrvSynchroniseStream, DrvGetTime, 0);
BurnTimerAttachZet(4000000);
memcpy(MSM6295ROM, MSM6295ROMSrc, 0x40000);
MSM6295Init(0, 1056000 / 132, 100.0, 1);
EEPROMInit(&eeprom_interface_93C46);
if (!EEPROMAvailable()) EEPROMFill(DefEEPROM,0, 0x80);
bDrawScreen = true;
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo mazingerRomDesc[] = {
{ "mzp-0.u24", 0x080000, 0x43a4279f, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "mzp-1.924", 0x080000, 0xdb40acba, BRF_ESS | BRF_PRG }, // 1
{ "mzs.u21", 0x020000, 0xc5b4f7ed, BRF_ESS | BRF_PRG }, // 2 Z80 Code
{ "bp943a-2.u56", 0x200000, 0x97e13959, BRF_GRA }, // 3 Sprite data
{ "bp943a-3.u55", 0x080000, 0x9c4957dd, BRF_GRA }, // 4
{ "bp943a-1.u60", 0x200000, 0x46327415, BRF_GRA }, // 5 Layer 0 Tile data
{ "bp943a-0.u63", 0x200000, 0xc1fed98a, BRF_GRA }, // 6 Layer 1 Tile data
{ "bp943a-4.u64", 0x080000, 0x3fc7f29a, BRF_SND }, // 7 MSM6295 #1 ADPCM data
{ "mazinger_world.nv", 0x0080, 0x4f6225c6, BRF_OPT },
};
STD_ROM_PICK(mazinger)
STD_ROM_FN(mazinger)
static struct BurnRomInfo mazingerjRomDesc[] = {
{ "mzp-0.u24", 0x080000, 0x43a4279f, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "mzp-1.924", 0x080000, 0xdb40acba, BRF_ESS | BRF_PRG }, // 1
{ "mzs.u21", 0x020000, 0xc5b4f7ed, BRF_ESS | BRF_PRG }, // 2 Z80 Code
{ "bp943a-2.u56", 0x200000, 0x97e13959, BRF_GRA }, // 3 Sprite data
{ "bp943a-3.u55", 0x080000, 0x9c4957dd, BRF_GRA }, // 4
{ "bp943a-1.u60", 0x200000, 0x46327415, BRF_GRA }, // 5 Layer 0 Tile data
{ "bp943a-0.u63", 0x200000, 0xc1fed98a, BRF_GRA }, // 6 Layer 1 Tile data
{ "bp943a-4.u64", 0x080000, 0x3fc7f29a, BRF_SND }, // 7 MSM6295 #1 ADPCM data
{ "mazinger_japan.nv", 0x0080, 0xf84a2a45, BRF_OPT },
};
STD_ROM_PICK(mazingerj)
STD_ROM_FN(mazingerj)
struct BurnDriver BurnDrvmazinger = {
"mazinger", NULL, NULL, NULL, "1994",
"Mazinger Z (World, ver. 94/06/27)\0", NULL, "Banpresto / Dynamic Pl. Toei Animation", "Cave",
L"Mazinger Z\0\u30DE\u30B8\u30F3\u30AC\u30FC \uFF3A (World, ver. 94/06/27)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL |BDF_ORIENTATION_FLIPPED | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_Z80, GBF_VERSHOOT, 0,
NULL, mazingerRomInfo, mazingerRomName, NULL, NULL, mazingerInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 384, 3, 4
};
struct BurnDriver BurnDrvmazingerj = {
"mazingerj", "mazinger", NULL, NULL, "1994",
"Mazinger Z (Japan, ver. 94/06/27)\0", NULL, "Banpresto / Dynamic Pl. Toei Animation", "Cave",
L"Mazinger Z\0\u30DE\u30B8\u30F3\u30AC\u30FC \uFF3A (Japan, ver. 94/06/27)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL |BDF_ORIENTATION_FLIPPED | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_Z80, GBF_VERSHOOT, 0,
NULL, mazingerjRomInfo, mazingerjRomName, NULL, NULL, mazingerInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 240, 384, 3, 4
};

View File

@ -0,0 +1,852 @@
// metmqstr
#include "cave.h"
#include "burn_ym2151.h"
#include "msm6295.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01, *RomZ80;
static UINT8 *Ram01, *RamZ80;
static UINT8 *MSM6295ROMSrc1, *MSM6295ROMSrc2;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCyclesTotal[2];
static INT32 nCyclesDone[2];
static INT32 SoundLatch;
static INT32 SoundLatchReply[48];
static INT32 SoundLatchStatus;
static INT32 SoundLatchReplyIndex;
static INT32 SoundLatchReplyMax;
static UINT8 DrvZ80Bank;
static UINT8 DrvOkiBank1_1;
static UINT8 DrvOkiBank1_2;
static UINT8 DrvOkiBank2_1;
static UINT8 DrvOkiBank2_2;
static struct BurnInputInfo metmqstrInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P1 Button 4", BIT_DIGITAL, DrvJoy1 + 10, "p1 fire 4"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"P2 Button 4", BIT_DIGITAL, DrvJoy2 + 10, "p2 fire 4"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(metmqstr)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall metmqstrReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
default: {
bprintf(PRINT_NORMAL, _T("Attempt to read byte value of location %x\n"), sekAddress);
}
}
return 0;
}
void __fastcall metmqstrWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
if (~byteValue & 0x0100) {
case 0xd00000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
break;
}
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write byte value %x to location %x\n"), byteValue, sekAddress);
}
}
}
UINT16 __fastcall metmqstrReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0xa80000:
case 0xa80002: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0xa80004: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xa80006: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0xa8006C:
if (SoundLatchReplyIndex > SoundLatchReplyMax) {
return 2;
}
return 0;
case 0xa8006E:
if (SoundLatchReplyIndex > SoundLatchReplyMax) {
SoundLatchReplyIndex = 0;
SoundLatchReplyMax = -1;
return 0;
}
return SoundLatchReply[SoundLatchReplyIndex++];
case 0xc80000:
return DrvInput[0] ^ 0xFFFF;
case 0xc80002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
bprintf(PRINT_NORMAL, _T("Attempt to read word value of location %x\n"), sekAddress);
}
}
return 0;
}
void __fastcall metmqstrWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
if (sekAddress >= 0xa8000a && sekAddress <= 0xa80068) return;
if (sekAddress >= 0xa8006a && sekAddress <= 0xa8006c) return;
if (sekAddress >= 0xa80004 && sekAddress <= 0xa80006) return;
switch (sekAddress) {
case 0xa80000:
nCaveXOffset = wordValue;
return;
case 0xa80002:
nCaveYOffset = wordValue;
return;
case 0xa80008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0xa8006E:
SoundLatch = wordValue;
SoundLatchStatus |= 0x0C;
ZetNmi();
nCyclesDone[1] += ZetRun(0x0400);
return;
case 0xb00000:
CaveTileReg[2][0] = wordValue;
break;
case 0xb00002:
CaveTileReg[2][1] = wordValue;
break;
case 0xb00004:
CaveTileReg[2][2] = wordValue;
break;
case 0xb80000:
CaveTileReg[1][0] = wordValue;
break;
case 0xb80002:
CaveTileReg[1][1] = wordValue;
break;
case 0xb80004:
CaveTileReg[1][2] = wordValue;
break;
case 0xc00000:
CaveTileReg[0][0] = wordValue;
break;
case 0xc00002:
CaveTileReg[0][1] = wordValue;
break;
case 0xc00004:
CaveTileReg[0][2] = wordValue;
break;
case 0xd00000:
if (~wordValue & 0x0100) {
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
break;
}
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write word value %x to location %x\n"), wordValue, sekAddress);
}
}
}
UINT8 __fastcall metmqstrZIn(UINT16 nAddress)
{
nAddress &= 0xFF;
switch (nAddress) {
case 0x20: {
return 0;
}
case 0x30:
SoundLatchStatus |= 0x04;
return SoundLatch & 0xFF;
case 0x40:
SoundLatchStatus |= 0x08;
return SoundLatch >> 8;
case 0x51:
return BurnYM2151ReadStatus();
default: {
bprintf(PRINT_NORMAL, _T("Z80 Port Read %x\n"), nAddress);
}
}
return 0;
}
void __fastcall metmqstrZOut(UINT16 nAddress, UINT8 nValue)
{
nAddress &= 0xFF;
switch (nAddress) {
case 0x00: {
DrvZ80Bank = nValue & 0x0f;
ZetMapArea(0x4000, 0x7FFF, 0, RomZ80 + (DrvZ80Bank * 0x4000));
ZetMapArea(0x4000, 0x7FFF, 2, RomZ80 + (DrvZ80Bank * 0x4000));
return;
}
case 0x50:
BurnYM2151SelectRegister(nValue);
break;
case 0x51:
BurnYM2151WriteRegister(nValue);
break;
case 0x60: {
MSM6295Command(0, nValue);
return;
}
case 0x70: {
DrvOkiBank1_1 = (nValue >> 0) & 0x07;
DrvOkiBank1_2 = (nValue >> 4) & 0x07;
memcpy(MSM6295ROM + 0x000000, MSM6295ROMSrc1 + 0x20000 * DrvOkiBank1_1, 0x20000);
memcpy(MSM6295ROM + 0x020000, MSM6295ROMSrc1 + 0x20000 * DrvOkiBank1_2, 0x20000);
return;
}
case 0x80: {
MSM6295Command(1, nValue);
return;
}
case 0x90: {
DrvOkiBank2_1 = (nValue >> 0) & 0x07;
DrvOkiBank2_2 = (nValue >> 4) & 0x07;
memcpy(MSM6295ROM + 0x100000, MSM6295ROMSrc2 + 0x20000 * DrvOkiBank2_1, 0x20000);
memcpy(MSM6295ROM + 0x120000, MSM6295ROMSrc2 + 0x20000 * DrvOkiBank2_2, 0x20000);
return;
}
default: {
bprintf(PRINT_NORMAL, _T("Z80 Port Write %x, %x\n"), nAddress, nValue);
}
}
}
UINT8 __fastcall metmqstrZRead(UINT16 a)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 Read => %04X\n"), a);
}
}
return 0;
}
void __fastcall metmqstrZWrite(UINT16 a, UINT8 d)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 Write => %04X, %02X\n"), a, d);
}
}
}
static INT32 DrvExit()
{
EEPROMExit();
BurnYM2151Exit();
MSM6295Exit(0);
MSM6295Exit(1);
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
ZetExit();
SoundLatch = 0;
DrvZ80Bank = 0;
DrvOkiBank1_1 = 0;
DrvOkiBank1_2 = 0;
DrvOkiBank2_1 = 0;
DrvOkiBank2_2 = 0;
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekRun(10000); // Need to run for a bit and reset to make it start - Watchdog would force reset?
SekReset();
SekClose();
ZetOpen(0);
ZetReset();
ZetClose();
BurnYM2151Reset();
MSM6295Reset(0);
MSM6295Reset(1);
EEPROMReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
SoundLatch = 0;
DrvZ80Bank = 0;
DrvOkiBank1_1 = 0;
DrvOkiBank1_2 = 0;
DrvOkiBank2_1 = 0;
DrvOkiBank2_2 = 0;
SoundLatch = 0;
SoundLatchStatus = 0x0C;
memset(SoundLatchReply, 0, sizeof(SoundLatchReply));
SoundLatchReplyIndex = 0;
SoundLatchReplyMax = -1;
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate4Bit(0, 128);
CaveClearScreen(CavePalette[0x7F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
INT32 nSoundBufferPos = 0;
INT32 nCyclesSegment;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 11; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
ZetNewFrame();
SekOpen(0);
ZetOpen(0);
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesTotal[1] = (INT32)(8000000 / CAVE_REFRESHRATE);
nCyclesDone[0] = nCyclesDone[1] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nCurrentCPU = 0;
INT32 nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// Run 68000
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
UINT8 Temp = nCaveSpriteBank;
nCaveSpriteBank = nCaveSpriteBankDelay;
nCaveSpriteBankDelay = Temp;
bVBlank = true;
nVideoIRQ = 0;
nUnknownIRQ = 0;
UpdateIRQStatus();
}
SekSetIRQLine(1, SEK_IRQSTATUS_AUTO);
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = 1;
nNext = (i + 1) * nCyclesTotal[nCurrentCPU] / nInterleave;
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
nCyclesSegment = ZetRun(nCyclesSegment);
nCyclesDone[nCurrentCPU] += nCyclesSegment;
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
BurnYM2151Render(pSoundBuf, nSegmentLength);
MSM6295Render(0, pSoundBuf, nSegmentLength);
MSM6295Render(1, pSoundBuf, nSegmentLength);
nSoundBufferPos += nSegmentLength;
}
}
// Make sure the buffer is entirely filled.
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
BurnYM2151Render(pSoundBuf, nSegmentLength);
MSM6295Render(0, pSoundBuf, nSegmentLength);
MSM6295Render(1, pSoundBuf, nSegmentLength);
}
}
SekClose();
ZetClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x180000; // 68K program
RomZ80 = Next; Next += 0x040000;
CaveSpriteROM = Next; Next += 0x1000000;
CaveTileROM[0] = Next; Next += 0x400000; // Tile layer 0
CaveTileROM[1] = Next; Next += 0x400000; // Tile layer 1
CaveTileROM[2] = Next; Next += 0x400000; // Tile layer 2
MSM6295ROM = Next; Next += 0x140000;
MSM6295ROMSrc1 = Next; Next += 0x200000;
MSM6295ROMSrc2 = Next; Next += 0x200000;
RamStart = Next;
Ram01 = Next; Next += 0x018000; // CPU #0 work RAM
RamZ80 = Next; Next += 0x002000;
CaveTileRAM[0] = Next; Next += 0x008000;
CaveTileRAM[1] = Next; Next += 0x008000;
CaveTileRAM[2] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap2(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[1] = *pOrg & 15;
pDest[0] = *pOrg >> 4;
}
return;
}
static INT32 LoadRoms()
{
BurnLoadRom(Rom01 + 0x000000, 0, 1);
BurnLoadRom(Rom01 + 0x080000, 1, 1);
BurnLoadRom(Rom01 + 0x100000, 2, 1);
BurnLoadRom(RomZ80, 3, 1);
BurnLoadRom(CaveSpriteROM + 0x000000, 4, 1);
BurnLoadRom(CaveSpriteROM + 0x200000, 5, 1);
BurnLoadRom(CaveSpriteROM + 0x400000, 6, 1);
BurnLoadRom(CaveSpriteROM + 0x600000, 7, 1);
NibbleSwap1(CaveSpriteROM, 0x800000);
BurnLoadRom(CaveTileROM[0], 8, 1);
NibbleSwap2(CaveTileROM[0], 0x200000);
BurnLoadRom(CaveTileROM[1], 9, 1);
NibbleSwap2(CaveTileROM[1], 0x200000);
BurnLoadRom(CaveTileROM[2], 10, 1);
NibbleSwap2(CaveTileROM[2], 0x200000);
// Load MSM6295 ADPCM data
BurnLoadRom(MSM6295ROMSrc1, 11, 1);
BurnLoadRom(MSM6295ROMSrc2, 12, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction);
ZetScan(nAction);
BurnYM2151Scan(nAction);
MSM6295Scan(0, nAction);
MSM6295Scan(1, nAction);
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
SCAN_VAR(SoundLatch);
SCAN_VAR(DrvZ80Bank);
SCAN_VAR(DrvOkiBank1_1);
SCAN_VAR(DrvOkiBank1_2);
SCAN_VAR(DrvOkiBank2_1);
SCAN_VAR(DrvOkiBank2_2);
if (nAction & ACB_WRITE) {
ZetOpen(0);
ZetMapArea(0x4000, 0x7FFF, 0, RomZ80 + (DrvZ80Bank * 0x4000));
ZetMapArea(0x4000, 0x7FFF, 2, RomZ80 + (DrvZ80Bank * 0x4000));
ZetClose();
memcpy(MSM6295ROM + 0x000000, MSM6295ROMSrc1 + 0x20000 * DrvOkiBank1_1, 0x20000);
memcpy(MSM6295ROM + 0x020000, MSM6295ROMSrc1 + 0x20000 * DrvOkiBank1_2, 0x20000);
memcpy(MSM6295ROM + 0x100000, MSM6295ROMSrc2 + 0x20000 * DrvOkiBank2_1, 0x20000);
memcpy(MSM6295ROM + 0x120000, MSM6295ROMSrc2 + 0x20000 * DrvOkiBank2_2, 0x20000);
CaveRecalcPalette = 1;
}
}
return 0;
}
static INT32 drvZInit()
{
ZetInit(1);
ZetOpen(0);
ZetSetInHandler(metmqstrZIn);
ZetSetOutHandler(metmqstrZOut);
ZetSetReadHandler(metmqstrZRead);
ZetSetWriteHandler(metmqstrZWrite);
// ROM bank 1
ZetMapArea (0x0000, 0x3FFF, 0, RomZ80 + 0x0000); // Direct Read from ROM
ZetMapArea (0x0000, 0x3FFF, 2, RomZ80 + 0x0000); // Direct Fetch from ROM
// ROM bank 2
ZetMapArea (0x4000, 0x7FFF, 0, RomZ80 + 0x4000); // Direct Read from ROM
ZetMapArea (0x4000, 0x7FFF, 2, RomZ80 + 0x4000); //
// RAM
ZetMapArea (0xe000, 0xFFFF, 0, RamZ80 + 0x0000); // Direct Read from RAM
ZetMapArea (0xe000, 0xFFFF, 1, RamZ80 + 0x0000); // Direct Write to RAM
ZetMapArea (0xe000, 0xFFFF, 2, RamZ80 + 0x0000); //
ZetMemEnd();
ZetClose();
return 0;
}
static void DrvYM2151IrqHandler(INT32 Irq)
{
if (Irq) {
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
} else {
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
}
}
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x07FFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Rom01 + 0x080000, 0x100000, 0x17FFFF, SM_ROM);
SekMapMemory(Rom01 + 0x100000, 0x200000, 0x27FFFF, SM_ROM);
SekMapMemory(CaveTileRAM[2], 0x880000, 0x887FFF, SM_RAM);
SekMapMemory(Ram01 + 0x00000, 0x888000, 0x88FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[1], 0x900000, 0x907FFF, SM_RAM);
SekMapMemory(Ram01 + 0x08000, 0x908000, 0x90FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x980000, 0x987FFF, SM_RAM);
SekMapMemory(Ram01 + 0x10000, 0x988000, 0x98FFFF, SM_RAM);
SekMapMemory(CavePalSrc, 0x408000, 0x408FFF, SM_RAM); // Palette RAM
SekMapMemory(CaveSpriteRAM, 0xF00000, 0xF0FFFF, SM_RAM);
SekSetReadByteHandler(0, metmqstrReadByte);
SekSetWriteByteHandler(0, metmqstrWriteByte);
SekSetReadWordHandler(0, metmqstrReadWord);
SekSetWriteWordHandler(0, metmqstrWriteWord);
SekClose();
}
drvZInit();
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(2, 0x1000000);
CaveTileInitLayer(0, 0x400000, 8, 0x4000);
CaveTileInitLayer(1, 0x400000, 8, 0x4000);
CaveTileInitLayer(2, 0x400000, 8, 0x4000);
nCaveExtraXOffset = -126;
CaveSpriteVisibleXOffset = -126;
BurnYM2151Init(4000000, 25.0);
BurnYM2151SetIrqHandler(&DrvYM2151IrqHandler);
memcpy(MSM6295ROM, MSM6295ROMSrc1, 0x40000);
memcpy(MSM6295ROM + 0x100000, MSM6295ROMSrc2, 0x40000);
MSM6295Init(0, 2000000 / 132, 100.0, 1);
MSM6295Init(1, 2000000 / 132, 100.0, 1);
bDrawScreen = true;
#if defined FBA_DEBUG && defined USE_SPEEDHACKS
bprintf(PRINT_IMPORTANT, _T(" * Using speed-hacks (detecting idle loops).\n"));
#endif
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo metmqstrRomDesc[] = {
{ "bp947a.u25", 0x080000, 0x0a5c3442, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "bp947a.u28", 0x080000, 0x8c55decf, BRF_ESS | BRF_PRG }, // 1
{ "bp947a.u29", 0x080000, 0xcf0f3f3b, BRF_ESS | BRF_PRG }, // 2
{ "bp947a.u20", 0x040000, 0xa4a36170, BRF_ESS | BRF_PRG }, // 3 Z80 Code
{ "bp947a.u49", 0x200000, 0x09749531, BRF_GRA }, // 4 Sprite data
{ "bp947a.u50", 0x200000, 0x19cea8b2, BRF_GRA }, // 5
{ "bp947a.u51", 0x200000, 0xc19bed67, BRF_GRA }, // 6
{ "bp947a.u52", 0x200000, 0x70c64875, BRF_GRA }, // 7
{ "bp947a.u48", 0x200000, 0x04ff6a3d, BRF_GRA }, // 8 Layer 0 Tile data
{ "bp947a.u47", 0x200000, 0x0de42827, BRF_GRA }, // 9 Layer 2 Tile data
{ "bp947a.u46", 0x200000, 0x0f9c906e, BRF_GRA }, // 10 Layer 2 Tile data
{ "bp947a.u42", 0x200000, 0x2ce8ff2a, BRF_SND }, // 11 MSM6295 #1 ADPCM data
{ "bp947a.u37", 0x200000, 0xc3077c8f, BRF_SND }, // 12 MSM6295 #2 ADPCM data
};
STD_ROM_PICK(metmqstr)
STD_ROM_FN(metmqstr)
static struct BurnRomInfo nmasterRomDesc[] = {
{ "bp947a_n.u25", 0x080000, 0x748cc514, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "bp947a.u28", 0x080000, 0x8c55decf, BRF_ESS | BRF_PRG }, // 1
{ "bp947a.u29", 0x080000, 0xcf0f3f3b, BRF_ESS | BRF_PRG }, // 2
{ "bp947a.u20", 0x040000, 0xa4a36170, BRF_ESS | BRF_PRG }, // 3 Z80 Code
{ "bp947a.u49", 0x200000, 0x09749531, BRF_GRA }, // 4 Sprite data
{ "bp947a.u50", 0x200000, 0x19cea8b2, BRF_GRA }, // 5
{ "bp947a.u51", 0x200000, 0xc19bed67, BRF_GRA }, // 6
{ "bp947a.u52", 0x200000, 0x70c64875, BRF_GRA }, // 7
{ "bp947a.u48", 0x200000, 0x04ff6a3d, BRF_GRA }, // 8 Layer 0 Tile data
{ "bp947a.u47", 0x200000, 0x0de42827, BRF_GRA }, // 9 Layer 2 Tile data
{ "bp947a.u46", 0x200000, 0x0f9c906e, BRF_GRA }, // 10 Layer 2 Tile data
{ "bp947a.u42", 0x200000, 0x2ce8ff2a, BRF_SND }, // 11 MSM6295 #1 ADPCM data
{ "bp947a.u37", 0x200000, 0xc3077c8f, BRF_SND }, // 12 MSM6295 #2 ADPCM data
};
STD_ROM_PICK(nmaster)
STD_ROM_FN(nmaster)
struct BurnDriver BurnDrvmetmqstr = {
"metmqstr", NULL, NULL, NULL, "1995",
"Metamoqester (International)\0", NULL, "Banpresto / Pandorabox", "Cave",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_Z80, GBF_VSFIGHT, 0,
NULL, metmqstrRomInfo, metmqstrRomName, NULL, NULL, metmqstrInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 384, 240, 4, 3
};
struct BurnDriver BurnDrvnmaster = {
"nmaster", "metmqstr", NULL, NULL, "1995",
"Oni - The Ninja Master (Japan)\0", NULL, "Banpresto / Pandorabox", "Cave",
L"\u7A4F\u5FCD - The Ninja Master (Japan)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY | BDF_CLONE, 2, HARDWARE_CAVE_68K_Z80, GBF_VSFIGHT, 0,
NULL, nmasterRomInfo, nmasterRomName, NULL, NULL, metmqstrInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 384, 240, 4, 3
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,583 @@
// Tobikose! Jumpman
#include "cave.h"
#include "msm6295.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[8] = {0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[8] = {0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0, 0};
static UINT8 DrvDip[2] = { 0, 0 };
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset;
static bool bVBlank;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nPrevCoinHack = 0;
static INT32 watchdog;
static INT32 tjumpman_hopper;
static struct BurnInputInfo TjumpmanInputList[] = {
{"Coin", BIT_DIGITAL, DrvJoy2 + 6, "p1 coin" },
{"1 Bet", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 1" },
{"3 Bet", BIT_DIGITAL, DrvJoy2 + 7, "p1 fire 2" },
{"No (not)", BIT_DIGITAL, DrvJoy2 + 4, "p1 start" },
{"Yes (do)", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 4" },
{"Pay Out", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 5" },
{"Go", BIT_DIGITAL, DrvJoy2 + 5, "p1 fire 3" },
{"Reset", BIT_DIGITAL, &DrvReset, "reset" },
{"Dip A", BIT_DIPSWITCH, DrvDip + 0, "dip" },
{"Dip B", BIT_DIPSWITCH, DrvDip + 1, "dip" },
};
STDINPUTINFO(Tjumpman)
static struct BurnDIPInfo TjumpmanDIPList[]=
{
{0x08, 0xff, 0xff, 0x01, NULL },
{0x09, 0xff, 0xff, 0x08, NULL },
{0 , 0xfe, 0 , 2, "Service Mode" },
{0x08, 0x01, 0x01, 0x01, "Off" },
{0x08, 0x01, 0x01, 0x00, "On" },
{0 , 0xfe, 0 , 2, "Self Test" },
{0x09, 0x01, 0x08, 0x08, "Off" },
{0x09, 0x01, 0x08, 0x00, "On" },
};
STDDIPINFO(Tjumpman)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
static INT32 tjumpman_hopper_read()
{
return (tjumpman_hopper && !(nCurrentFrame % 10)) ? 0 : 1;
}
UINT8 __fastcall tjumpmanReadByte(UINT32 sekAddress)
{
switch (sekAddress)
{
case 0x600000:
return 0xff;
case 0x600001:
return ((DrvInput[0] & 0x76) ^ 0x76) | (DrvDip[0] & 1) | ((EEPROMRead() & 1) << 3) | (tjumpman_hopper_read() << 7);
case 0x600002:
return 0xff;
case 0x600003:
return ((DrvInput[1] & 0xF7) ^ 0xF7) | (DrvDip[1] & 8);
case 0x700000:
case 0x700001: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ | (bVBlank ? 4 : 0);
return nRet;
}
case 0x700002:
case 0x700003: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x700004:
case 0x700005: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x700006:
case 0x700007: {
UINT8 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800001:
return MSM6295ReadStatus(0);
default: {
// bprintf(PRINT_NORMAL, _T("Attempt to read byte value of location %x\n"), sekAddress);
}
}
return 0;
}
UINT16 __fastcall tjumpmanReadWord(UINT32 sekAddress)
{
switch (sekAddress)
{
case 0x600000:
return (DrvInput[0] ^ 0xFF76) | (DrvDip[0] & 1) | ((EEPROMRead() & 1) << 3) | (tjumpman_hopper_read() << 7);
case 0x600002:
return (DrvInput[1] ^ 0xFFF7) | (DrvDip[1] & 8);
case 0x700000: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ | (bVBlank ? 4 : 0);
return nRet;
}
case 0x700002: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x700004: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x700006: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x800000:
return MSM6295ReadStatus(0);
default: {
// bprintf(PRINT_NORMAL, _T("Attempt to read word value of location %x\n"), sekAddress);
}
}
return 0;
}
void __fastcall tjumpmanWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress)
{
case 0x800001:
MSM6295Command(0, byteValue);
break;
case 0xc00000:
break;
case 0xc00001:
tjumpman_hopper = byteValue & 0x40;
break;
case 0xe00001:
EEPROMWrite(byteValue & 0x10, byteValue & 0x08, byteValue & 0x20);
break;
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write byte value %x to location %x\n"), byteValue, sekAddress);
}
}
}
void __fastcall tjumpmanWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress)
{
case 0x400000:
CaveTileReg[0][0] = wordValue;
break;
case 0x400002:
CaveTileReg[0][1] = wordValue;
break;
case 0x400004:
CaveTileReg[0][2] = wordValue;
break;
case 0x700000:
nCaveXOffset = wordValue;
return;
case 0x700002:
nCaveYOffset = wordValue;
return;
case 0x700008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x700068:
watchdog = 0;
break;
case 0x800000:
MSM6295Command(0, wordValue);
break;
case 0xc00000:
tjumpman_hopper = wordValue & 0x40;
break;
case 0xe00000:
EEPROMWrite(wordValue & 0x10, wordValue & 0x08, wordValue & 0x20);
break;
default: {
bprintf(PRINT_NORMAL, _T("Attempt to write word value %x to location %x\n"), wordValue, sekAddress);
}
}
}
void __fastcall tjumpmanWriteBytePalette(UINT32 sekAddress, UINT8 byteValue)
{
CavePalWriteByte(sekAddress & 0xFFFF, byteValue);
}
void __fastcall tjumpmanWriteWordPalette(UINT32 sekAddress, UINT16 wordValue)
{
CavePalWriteWord(sekAddress & 0xFFFF, wordValue);
}
static INT32 DrvExit()
{
EEPROMExit();
MSM6295Exit(0);
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit();
BurnFree(Mem);
Mem = NULL;
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
MSM6295Reset(0);
tjumpman_hopper = 0;
watchdog = 0;
// nPrevCoinHack = 0;
return 0;
}
static INT32 DrvDraw()
{
CaveSpriteBuffer();
CavePalUpdate8Bit(0, 128);
CaveClearScreen(CavePalette[0x7F00]);
CaveTileRender(1);
return 0;
}
inline static INT32 CheckSleep(INT32)
{
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
INT32 nCyclesTotal[1];
INT32 nCyclesDone[1];
INT32 nCyclesSegment;
watchdog++;
if (DrvReset || (watchdog > 180)) {
DrvDoReset();
}
DrvInput[0] = 0;
DrvInput[1] = 0;
for (INT32 i = 0; i < 8; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
//if ((nPrevCoinHack != (DrvInput[1] & 0x0040)) && (DrvInput[1] & 0x0040)) {
// Ram01[0x24]++;
// if (Ram01[0x24] > 9) Ram01[0x24] = 9; // ?
//}
nPrevCoinHack = DrvInput[1] & 0x0040;
nCyclesTotal[0] = (INT32)((INT64)14000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nCurrentCPU = 0;
INT32 nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
}
if (pBurnDraw) {
DrvDraw();
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
// end of vblank
if (i == nInterleave) {
bVBlank = false;
nUnknownIRQ = 1;
UpdateIRQStatus();
}
}
if (pBurnSoundOut) {
MSM6295Render(0, pBurnSoundOut, nBurnSoundLen);
}
SekClose();
return 0;
}
static INT32 MemIndex()
{
UINT8* Next;
Next = Mem;
Rom01 = Next; Next += 0x080000;
CaveSpriteROM = Next; Next += 0x200000;
CaveTileROM[0] = Next; Next += 0x100000;
MSM6295ROM = Next; Next += 0x040000;
Ram01 = Next; Next += 0x010000; // work RAM (NV!)
RamStart = Next;
CaveTileRAM[0] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000;
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap4(UINT8* pData, INT32 nLen)
{
for (INT32 i = 0; i < nLen; i++, pData += 2) {
UINT8 n1 = pData[0];
UINT8 n2 = pData[1];
pData[1] = (n2 << 4) | (n1 & 0x0F);
pData[0] = (n2 & 0xF0) | (n1 >> 4);
}
return;
}
static INT32 LoadRoms()
{
BurnLoadRom(Rom01, 0, 1);
BurnLoadRom(CaveSpriteROM + 0x000000, 1, 2);
BurnLoadRom(CaveSpriteROM + 0x000001, 2, 2);
NibbleSwap1(CaveSpriteROM, 0x100000);
BurnLoadRom(CaveTileROM[0] + 0x00000, 3, 2);
BurnLoadRom(CaveTileROM[0] + 0x00001, 4, 2);
NibbleSwap4(CaveTileROM[0], 0x80000);
BurnLoadRom(MSM6295ROM, 5, 1);
return 0;
}
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) {
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin);
if (nAction & ACB_VOLATILE) {
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction);
MSM6295Scan(0, nAction);
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(tjumpman_hopper);
CaveScanGraphics();
}
if (nAction & ACB_NVRAM) {
ba.Data = Ram01;
ba.nLen = 0x010000;
ba.nAddress = 0x100000;
ba.szName = "NV RAM";
BurnAcb(&ba);
}
return 0;
}
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)BurnMalloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen);
MemIndex();
EEPROMInit(&eeprom_interface_93C46);
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000);
SekOpen(0);
SekMapMemory(Rom01, 0x000000, 0x07FFFF, SM_ROM);
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x300000, 0x303FFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x304000, 0x307FFF, SM_RAM); // mirror
SekMapMemory(CaveSpriteRAM, 0x200000, 0x20FFFF, SM_RAM);
SekMapMemory(CavePalSrc, 0x500000, 0x50FFFF, SM_ROM);
SekSetReadWordHandler(0, tjumpmanReadWord);
SekSetReadByteHandler(0, tjumpmanReadByte);
SekSetWriteWordHandler(0, tjumpmanWriteWord);
SekSetWriteByteHandler(0, tjumpmanWriteByte);
SekMapHandler(1, 0x500000, 0x50FFFF, SM_WRITE);
SekSetWriteWordHandler(1, tjumpmanWriteWordPalette);
SekSetWriteByteHandler(1, tjumpmanWriteBytePalette);
SekClose();
}
nCaveExtraXOffset = -128; // bg
CaveSpriteVisibleXOffset = -128; // sprite
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(2, 0x0200000);
CaveTileInitLayer(0, 0x100000, 8, 0x4000);
MSM6295Init(0, 7575, 100.0, 0);
DrvDoReset();
return 0;
}
// Tobikose! Jumpman
static struct BurnRomInfo tjumpmanRomDesc[] = {
{ "tj1_mpr-0c.u41", 0x80000, 0xde3030b8, BRF_PRG | BRF_PRG }, // 0 CPU #0 code
{ "tj1_obj-0a.u52", 0x80000, 0xb42cf8e8, BRF_GRA }, // 1 Sprite data
{ "tj1_obj-1a.u53", 0x80000, 0x5f0124d7, BRF_GRA }, // 2
{ "tj1_cha-0a.u60", 0x40000, 0x8aa08a38, BRF_GRA }, // 3 Layer 0 Tile data
{ "tj1_cha-1a.u61", 0x40000, 0x50072c82, BRF_GRA }, // 4
{ "tj1_voi-0a.u27", 0x40000, 0xb5693aae, BRF_SND }, // 5 MSM6295 #0 ADPCM data
{ "n44u3b.u3", 0x00117, 0x4cd79750, BRF_OPT }, // 6 PLDs
{ "n44u1g.u1", 0x00117, 0xe226ec18, BRF_OPT }, // 7
};
STD_ROM_PICK(tjumpman)
STD_ROM_FN(tjumpman)
struct BurnDriverD BurnDrvTjumpman = {
"tjumpman", NULL, NULL, NULL, "1999",
"Tobikose! Jumpman\0", "Coin input not working?", "Namco", "Cave",
L"\u30E1\u30B0\u30EB\u3092\u3044\u308C\u3066\u306D!\0Tobikose! Jumpman\0", NULL, NULL, NULL,
BDF_16BIT_ONLY, 1, HARDWARE_CAVE_68K_ONLY | HARDWARE_CAVE_M6295, GBF_MISC, 0,
NULL, tjumpmanRomInfo, tjumpmanRomName, NULL, NULL, TjumpmanInputInfo, TjumpmanDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 320, 240, 4, 3
};

View File

@ -0,0 +1,610 @@
// Uo Poko
#include "cave.h"
#include "ymz280b.h"
#define CAVE_VBLANK_LINES 12
static UINT8 DrvJoy1[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT8 DrvJoy2[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static UINT16 DrvInput[2] = {0x0000, 0x0000};
static UINT8 *Mem = NULL, *MemEnd = NULL;
static UINT8 *RamStart, *RamEnd;
static UINT8 *Rom01;
static UINT8 *Ram01;
static UINT8 DrvReset = 0;
static UINT8 bDrawScreen;
static bool bVBlank;
static INT8 nVideoIRQ;
static INT8 nSoundIRQ;
static INT8 nUnknownIRQ;
static INT8 nIRQPending;
static INT32 nCurrentCPU;
static INT32 nCyclesDone[2];
static INT32 nCyclesTotal[2];
static INT32 nCyclesSegment;
static struct BurnInputInfo uopokoInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 8, "p1 coin"},
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 7, "p1 start"},
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 0, "p1 up"},
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 1, "p1 down"},
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 2, "p1 left"},
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 3, "p1 right"},
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 4, "p1 fire 1"},
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 2"},
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 3"},
{"P2 Coin", BIT_DIGITAL, DrvJoy2 + 8, "p2 coin"},
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start"},
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 0, "p2 up"},
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 1, "p2 down"},
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 2, "p2 left"},
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 3, "p2 right"},
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1"},
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2"},
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3"},
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Diagnostics", BIT_DIGITAL, DrvJoy1 + 9, "diag"},
{"Service", BIT_DIGITAL, DrvJoy2 + 9, "service"},
};
STDINPUTINFO(uopoko)
static void UpdateIRQStatus()
{
nIRQPending = (nVideoIRQ == 0 || nSoundIRQ == 0 || nUnknownIRQ == 0);
SekSetIRQLine(1, nIRQPending ? SEK_IRQSTATUS_ACK : SEK_IRQSTATUS_NONE);
}
UINT8 __fastcall uopokoReadByte(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300003: {
return YMZ280BReadStatus();
}
case 0x600000:
case 0x600001:
case 0x600002:
case 0x600003: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x600004:
case 0x600005: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x600006:
case 0x600007: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x900000:
return (DrvInput[0] >> 8) ^ 0xFF;
case 0x900001:
return (DrvInput[0] & 0xFF) ^ 0xFF;
case 0x900002:
return ((DrvInput[1] >> 8) ^ 0xF7) | (EEPROMRead() << 3);
case 0x900003:
return (DrvInput[1] & 0xFF) ^ 0xFF;
default: {
// bprintf(PRINT_NORMAL, "Attempt to read byte value of location %x\n", sekAddress);
}
}
return 0;
}
UINT16 __fastcall uopokoReadWord(UINT32 sekAddress)
{
switch (sekAddress) {
case 0x300002: {
return YMZ280BReadStatus();
}
case 0x600000:
case 0x600002: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
return nRet;
}
case 0x600004: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nVideoIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x600006: {
UINT16 nRet = (nUnknownIRQ << 1) | nVideoIRQ;
nUnknownIRQ = 1;
UpdateIRQStatus();
return nRet;
}
case 0x900000:
return DrvInput[0] ^ 0xFFFF;
case 0x900002:
return (DrvInput[1] ^ 0xF7FF) | (EEPROMRead() << 11);
default: {
// bprintf(PRINT_NORMAL, "Attempt to read word value of location %x\n", sekAddress);
}
}
return 0;
}
void __fastcall uopokoWriteByte(UINT32 sekAddress, UINT8 byteValue)
{
switch (sekAddress) {
case 0x300001:
YMZ280BSelectRegister(byteValue);
break;
case 0x300003:
YMZ280BWriteRegister(byteValue);
break;
case 0xA00000:
EEPROMWrite(byteValue & 0x04, byteValue & 0x02, byteValue & 0x08);
break;
default: {
// bprintf(PRINT_NORMAL, "Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
}
}
}
void __fastcall uopokoWriteWord(UINT32 sekAddress, UINT16 wordValue)
{
switch (sekAddress) {
case 0x300000:
YMZ280BSelectRegister(wordValue);
break;
case 0x300002:
YMZ280BWriteRegister(wordValue);
break;
case 0x600000:
nCaveXOffset = wordValue;
return;
case 0x600002:
nCaveYOffset = wordValue;
return;
case 0x600008:
CaveSpriteBuffer();
nCaveSpriteBank = wordValue;
return;
case 0x700000:
CaveTileReg[0][0] = wordValue;
break;
case 0x700002:
CaveTileReg[0][1] = wordValue;
break;
case 0x700004:
CaveTileReg[0][2] = wordValue;
break;
case 0xA00000: {
wordValue >>= 8;
EEPROMWrite(wordValue & 0x04, wordValue & 0x02, wordValue & 0x08);
break;
}
default: {
// bprintf(PRINT_NORMAL, "Attempt to write word value %x to location %x\n", wordValue, sekAddress);
}
}
}
void __fastcall uopokoWriteBytePalette(UINT32 sekAddress, UINT8 byteValue)
{
CavePalWriteByte(sekAddress & 0xFFFF, byteValue);
}
void __fastcall uopokoWriteWordPalette(UINT32 sekAddress, UINT16 wordValue)
{
CavePalWriteWord(sekAddress & 0xFFFF, wordValue);
}
static void TriggerSoundIRQ(INT32 nStatus)
{
nSoundIRQ = nStatus ^ 1;
UpdateIRQStatus();
if (nIRQPending && nCurrentCPU != 0) {
nCyclesDone[0] += SekRun(0x0400);
}
}
static INT32 DrvExit()
{
YMZ280BExit();
EEPROMExit();
CaveTileExit();
CaveSpriteExit();
CavePalExit();
SekExit(); // Deallocate 68000s
// Deallocate all used memory
if (Mem) {
free(Mem);
Mem = NULL;
}
return 0;
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
EEPROMReset();
YMZ280BReset();
nVideoIRQ = 1;
nSoundIRQ = 1;
nUnknownIRQ = 1;
nIRQPending = 0;
YMZ280BReset();
return 0;
}
static INT32 DrvDraw()
{
CavePalUpdate8Bit(0, 128); // Update the palette
CaveClearScreen(CavePalette[0x7F00]);
if (bDrawScreen) {
// CaveGetBitmap();
CaveTileRender(1); // Render tiles
}
return 0;
}
inline static INT32 CheckSleep(INT32)
{
return 0;
}
static INT32 DrvFrame()
{
INT32 nCyclesVBlank;
INT32 nInterleave = 8;
if (DrvReset) { // Reset machine
DrvDoReset();
}
// Compile digital inputs
DrvInput[0] = 0x0000; // Player 1
DrvInput[1] = 0x0000; // Player 2
for (INT32 i = 0; i < 16; i++) {
DrvInput[0] |= (DrvJoy1[i] & 1) << i;
DrvInput[1] |= (DrvJoy2[i] & 1) << i;
}
CaveClearOpposites(&DrvInput[0]);
CaveClearOpposites(&DrvInput[1]);
SekNewFrame();
nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * CAVE_REFRESHRATE));
nCyclesDone[0] = 0;
nCyclesVBlank = nCyclesTotal[0] - (INT32)((nCyclesTotal[0] * CAVE_VBLANK_LINES) / 271.5);
bVBlank = false;
INT32 nSoundBufferPos = 0;
SekOpen(0);
for (INT32 i = 1; i <= nInterleave; i++) {
INT32 nNext;
// Render sound segment
if ((i & 1) == 0) {
if (pBurnSoundOut) {
INT32 nSegmentEnd = nBurnSoundLen * i / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
YMZ280BRender(pSoundBuf, nSegmentEnd - nSoundBufferPos);
nSoundBufferPos = nSegmentEnd;
}
}
// Run 68000
nCurrentCPU = 0;
nNext = i * nCyclesTotal[nCurrentCPU] / nInterleave;
// See if we need to trigger the VBlank interrupt
if (!bVBlank && nNext > nCyclesVBlank) {
if (nCyclesDone[nCurrentCPU] < nCyclesVBlank) {
nCyclesSegment = nCyclesVBlank - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
}
if (pBurnDraw != NULL) {
DrvDraw(); // Draw screen if needed
}
bVBlank = true;
nVideoIRQ = 0;
UpdateIRQStatus();
}
nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
if (!CheckSleep(nCurrentCPU)) { // See if this CPU is busywaiting
nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
} else {
nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
}
nCurrentCPU = -1;
}
{
// Make sure the buffer is entirely filled.
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
YMZ280BRender(pSoundBuf, nSegmentLength);
}
}
}
SekClose();
return 0;
}
// This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
// and then afterwards to set up all the pointers
static INT32 MemIndex()
{
UINT8* Next; Next = Mem;
Rom01 = Next; Next += 0x100000; // 68K program
CaveSpriteROM = Next; Next += 0x800000;
CaveTileROM[0] = Next; Next += 0x400000; // Tile layer 0
YMZ280BROM = Next; Next += 0x200000;
RamStart = Next;
Ram01 = Next; Next += 0x010000; // CPU #0 work RAM
CaveTileRAM[0] = Next; Next += 0x008000;
CaveSpriteRAM = Next; Next += 0x010000;
CavePalSrc = Next; Next += 0x010000; // palette
RamEnd = Next;
MemEnd = Next;
return 0;
}
static void NibbleSwap1(UINT8* pData, INT32 nLen)
{
UINT8* pOrg = pData + nLen - 1;
UINT8* pDest = pData + ((nLen - 1) << 1);
for (INT32 i = 0; i < nLen; i++, pOrg--, pDest -= 2) {
pDest[0] = *pOrg & 15;
pDest[1] = *pOrg >> 4;
}
return;
}
static void NibbleSwap4(UINT8* pData, INT32 nLen)
{
for (INT32 i = 0; i < nLen; i++, pData += 2) {
UINT8 n1 = pData[0];
UINT8 n2 = pData[1];
pData[1] = (n2 << 4) | (n1 & 0x0F);
pData[0] = (n2 & 0xF0) | (n1 >> 4);
}
return;
}
static INT32 LoadRoms()
{
// Load 68000 ROM
BurnLoadRom(Rom01 + 0, 1, 2);
BurnLoadRom(Rom01 + 1, 0, 2);
BurnLoadRom(CaveSpriteROM + 0x0000000, 2, 1);
NibbleSwap1(CaveSpriteROM, 0x400000);
BurnLoadRom(CaveTileROM[0] + 0x000000, 3, 1);
NibbleSwap4(CaveTileROM[0], 0x200000);
// Load YMZ280B data
BurnLoadRom(YMZ280BROM, 4, 1);
return 0;
}
// Scan ram
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) { // Return minimum compatible version
*pnMin = 0x020902;
}
EEPROMScan(nAction, pnMin); // Scan EEPROM
if (nAction & ACB_VOLATILE) { // Scan volatile ram
memset(&ba, 0, sizeof(ba));
ba.Data = RamStart;
ba.nLen = RamEnd - RamStart;
ba.szName = "RAM";
BurnAcb(&ba);
SekScan(nAction); // scan 68000 states
YMZ280BScan();
SCAN_VAR(nVideoIRQ);
SCAN_VAR(nSoundIRQ);
SCAN_VAR(nUnknownIRQ);
SCAN_VAR(bVBlank);
CaveScanGraphics();
SCAN_VAR(DrvInput);
}
return 0;
}
static const UINT8 default_eeprom[16] = {0x00,0x03,0x08,0x00,0xFF,0xFF,0xFF,0xFF,0x08,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF};
static INT32 DrvInit()
{
INT32 nLen;
BurnSetRefreshRate(CAVE_REFRESHRATE);
// Find out how much memory is needed
Mem = NULL;
MemIndex();
nLen = MemEnd - (UINT8 *)0;
if ((Mem = (UINT8 *)malloc(nLen)) == NULL) {
return 1;
}
memset(Mem, 0, nLen); // blank all memory
MemIndex(); // Index the allocated memory
EEPROMInit(&eeprom_interface_93C46);
if (!EEPROMAvailable()) EEPROMFill(default_eeprom,0, sizeof(default_eeprom));
// Load the roms into memory
if (LoadRoms()) {
return 1;
}
{
SekInit(0, 0x68000); // Allocate 68000
SekOpen(0);
// Map 68000 memory:
SekMapMemory(Rom01, 0x000000, 0x0FFFFF, SM_ROM); // CPU 0 ROM
SekMapMemory(Ram01, 0x100000, 0x10FFFF, SM_RAM);
SekMapMemory(CaveSpriteRAM, 0x400000, 0x40FFFF, SM_RAM);
SekMapMemory(CaveTileRAM[0], 0x500000, 0x507FFF, SM_RAM);
SekMapMemory(CavePalSrc, 0x800000, 0x80FFFF, SM_ROM); // Palette RAM (write goes through handler)
SekMapHandler(1, 0x800000, 0x80FFFF, SM_WRITE); //
SekSetReadWordHandler(0, uopokoReadWord);
SekSetReadByteHandler(0, uopokoReadByte);
SekSetWriteWordHandler(0, uopokoWriteWord);
SekSetWriteByteHandler(0, uopokoWriteByte);
SekSetWriteWordHandler(1,uopokoWriteWordPalette);
SekSetWriteByteHandler(1, uopokoWriteBytePalette);
SekClose();
}
nCaveRowModeOffset = 1;
CavePalInit(0x8000);
CaveTileInit();
CaveSpriteInit(1, 0x800000);
CaveTileInitLayer(0, 0x400000, 8, 0x4000);
YMZ280BInit(16934400, &TriggerSoundIRQ, 3);
bDrawScreen = true;
DrvDoReset(); // Reset machine
return 0;
}
// Rom information
static struct BurnRomInfo uopokoRomDesc[] = {
{ "u26.int", 0x080000, 0xb445c9ac, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "u25.int", 0x080000, 0xa1258482, BRF_ESS | BRF_PRG }, // 1
{ "u33.bin", 0x400000, 0x5D142Ad2, BRF_GRA }, // 2 Sprite data
{ "u49.bin", 0x400000, 0x12FB11BB, BRF_GRA }, // 3 Layer 0 Tile data
{ "u4.bin", 0x200000, 0xA2D0D755, BRF_SND }, // 4 YMZ280B (AD)PCM data
{ "eeprom-uopoko.bin", 0x0080, 0xf4a24b95, BRF_OPT },
};
STD_ROM_PICK(uopoko)
STD_ROM_FN(uopoko)
static struct BurnRomInfo uopokojRomDesc[] = {
{ "u26.bin", 0x080000, 0xE7EEC050, BRF_ESS | BRF_PRG }, // 0 CPU #0 code
{ "u25.bin", 0x080000, 0x68CB6211, BRF_ESS | BRF_PRG }, // 1
{ "u33.bin", 0x400000, 0x5D142Ad2, BRF_GRA }, // 2 Sprite data
{ "u49.bin", 0x400000, 0x12FB11BB, BRF_GRA }, // 3 Layer 0 Tile data
{ "u4.bin", 0x200000, 0xA2D0D755, BRF_SND }, // 4 YMZ280B (AD)PCM data
{ "eeprom-uopoko.bin", 0x0080, 0xf4a24b95, BRF_OPT },
};
STD_ROM_PICK(uopokoj)
STD_ROM_FN(uopokoj)
struct BurnDriver BurnDrvUoPoko = {
"uopoko", NULL, NULL, NULL, "1999",
"Puzzle Uo Poko (International, ver. 98/02/06)\0", NULL, "Cave / Jaleco", "Cave",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_PUZZLE, 0,
NULL, uopokoRomInfo, uopokoRomName, NULL, NULL, uopokoInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 320, 240, 4, 3
};
struct BurnDriver BurnDrvUoPokoj = {
"uopokoj", "uopoko", NULL, NULL, "1999",
"Puzzle Uo Poko (Japan, ver. 98/02/06)\0", NULL, "Cave / Jaleco", "Cave",
L"\u30D1\u30BA\u30EB \u9B5A\u30DD\u30B3 \u3046\u304A\u307D\u3053 (Japan, ver. 98/02/06)\0Puzzle Uo Poko\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_16BIT_ONLY, 2, HARDWARE_CAVE_68K_ONLY, GBF_PUZZLE, 0,
NULL, uopokojRomInfo, uopokojRomName, NULL, NULL, uopokoInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
&CaveRecalcPalette, 0x8000, 320, 240, 4, 3
};

View File

@ -0,0 +1,46 @@
#include "burnint.h"
#ifndef HARDWARE_CAPCOM_CPS3
#define HARDWARE_CAPCOM_CPS3 HARDWARE_MISC_MISC
#endif
#ifndef HARDWARE_CAPCOM_CPS3_NO_CD
#define HARDWARE_CAPCOM_CPS3_NO_CD HARDWARE_CAPCOM_CPS3
#endif
extern UINT8 cps3_reset;
extern UINT8 cps3_palette_change;
extern UINT16 *Cps3CurPal;
extern UINT32 cps3_key1, cps3_key2, cps3_isSpecial;
extern UINT32 cps3_bios_test_hack, cps3_game_test_hack;
extern UINT32 cps3_speedup_ram_address, cps3_speedup_code_address;
extern UINT8 cps3_dip;
extern UINT32 cps3_region_address, cps3_ncd_address;
extern UINT8 Cps3But1[16];
extern UINT8 Cps3But2[16];
extern UINT8 Cps3But3[16];
INT32 cps3Init();
INT32 cps3Exit();
INT32 cps3Frame();
INT32 cps3Scan(INT32 nAction,INT32 *pnMin);
// sound
UINT8 __fastcall cps3SndReadByte(UINT32 addr);
UINT16 __fastcall cps3SndReadWord(UINT32 addr);
UINT32 __fastcall cps3SndReadLong(UINT32 addr);
void __fastcall cps3SndWriteByte(UINT32 addr, UINT8 data);
void __fastcall cps3SndWriteWord(UINT32 addr, UINT16 data);
void __fastcall cps3SndWriteLong(UINT32 addr, UINT32 data);
INT32 cps3SndInit(UINT8 *);
void cps3SndReset();
void cps3SndExit();
void cps3SndUpdate();
INT32 cps3SndScan(INT32);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,215 @@
#include "cps3.h"
#define CPS3_VOICES 16
#define CPS3_SND_INT_RATE (nBurnFPS / 100)
#define CPS3_SND_RATE (42954500 / 3 / 384)
#define CPS3_SND_BUFFER_SIZE (CPS3_SND_RATE / CPS3_SND_INT_RATE)
#define CPS3_SND_LINEAR_SHIFT 12
typedef struct {
UINT16 regs[16];
UINT32 pos;
UINT16 frac;
} cps3_voice;
typedef struct {
cps3_voice voice[CPS3_VOICES];
UINT16 key;
UINT8 * rombase;
UINT32 delta;
} cps3snd_chip;
static cps3snd_chip * chip;
UINT8 __fastcall cps3SndReadByte(UINT32 addr)
{
addr &= 0x000003ff;
bprintf(PRINT_NORMAL, _T("SND Attempt to read byte value of location %8x\n"), addr);
return 0;
}
UINT16 __fastcall cps3SndReadWord(UINT32 addr)
{
addr &= 0x000003ff;
if (addr < 0x200) {
return chip->voice[addr >> 5].regs[(addr>>1) & 0xf];
} else
if (addr == 0x200) {
return chip->key;
} else
bprintf(PRINT_NORMAL, _T("SND Attempt to read word value of location %8x\n"), addr);
return 0;
}
UINT32 __fastcall cps3SndReadLong(UINT32 addr)
{
addr &= 0x000003ff;
bprintf(PRINT_NORMAL, _T("SND Attempt to read long value of location %8x\n"), addr);
return 0;
}
void __fastcall cps3SndWriteByte(UINT32 addr, UINT8 data)
{
addr &= 0x000003ff;
bprintf(PRINT_NORMAL, _T("SND Attempt to write byte value %2x to location %8x\n"), data, addr);
}
void __fastcall cps3SndWriteWord(UINT32 addr, UINT16 data)
{
addr &= 0x000003ff;
if (addr < 0x200) {
chip->voice[addr >> 5].regs[(addr>>1) & 0xf] = data;
//bprintf(PRINT_NORMAL, _T("SND Attempt to write word value %4x to Chip[%02d][%02d] %s\n"), data, addr >> 5, (addr>>2) & 7, (addr & 0x02) ? "lo" : "hi" );
} else
if (addr == 0x200) {
UINT16 key = data;
for (INT32 i = 0; i < CPS3_VOICES; i++) {
// Key off -> Key on
if ((key & (1 << i)) && !(chip->key & (1 << i))) {
chip->voice[i].frac = 0;
chip->voice[i].pos = 0;
}
}
chip->key = key;
} else
bprintf(PRINT_NORMAL, _T("SND Attempt to write word value %4x to location %8x\n"), data, addr);
}
void __fastcall cps3SndWriteLong(UINT32 addr, UINT32 data)
{
//addr &= 0x000003ff;
bprintf(PRINT_NORMAL, _T("SND Attempt to write long value %8x to location %8x\n"), data, addr);
}
INT32 cps3SndInit(UINT8 * sndrom)
{
chip = (cps3snd_chip *) malloc( sizeof(cps3snd_chip) );
if ( chip ) {
memset( chip, 0, sizeof(cps3snd_chip) );
chip->rombase = sndrom;
/*
* CPS-3 Sound chip clock: 42954500 / 3 / 384 = 37286.89
* Sound interupt 80Hz
*/
if (nBurnSoundRate) {
//chip->delta = 37286.9 / nBurnSoundRate;
chip->delta = (CPS3_SND_BUFFER_SIZE << CPS3_SND_LINEAR_SHIFT) / nBurnSoundLen;
//bprintf(0, _T("BurnSnd %08x, %d, %d\n"), chip->delta, chip->burnlen, nBurnSoundLen);
}
return 0;
}
return 1;
}
void cps3SndReset()
{
}
void cps3SndExit()
{
if (chip) {
free( chip );
chip = NULL;
}
}
void cps3SndUpdate()
{
if (!pBurnSoundOut) {
// TODO: ???
// chip->key = 0;
return;
}
memset(pBurnSoundOut, 0, nBurnSoundLen * 2 * 2 );
INT8 * base = (INT8 *)chip->rombase;
cps3_voice *vptr = &chip->voice[0];
for(INT32 i=0; i<CPS3_VOICES; i++, vptr++) {
if (chip->key & (1 << i)) {
UINT32 start = ((vptr->regs[ 3] << 16) | vptr->regs[ 2]) - 0x400000;
UINT32 end = ((vptr->regs[11] << 16) | vptr->regs[10]) - 0x400000;
UINT32 loop = ((vptr->regs[ 9] << 16) | vptr->regs[ 7]) - 0x400000;
UINT32 step = ( vptr->regs[ 6] * chip->delta ) >> CPS3_SND_LINEAR_SHIFT;
//INT32 vol_l = ((signed short)vptr->regs[15] * 12) >> 4;
//INT32 vol_r = ((signed short)vptr->regs[14] * 12) >> 4;
INT32 vol_l = (INT16)vptr->regs[15];
INT32 vol_r = (INT16)vptr->regs[14];
UINT32 pos = vptr->pos;
UINT32 frac = vptr->frac;
/* Go through the buffer and add voice contributions */
INT16 * buffer = (INT16 *)pBurnSoundOut;
for (INT32 j=0; j<nBurnSoundLen; j++) {
INT32 sample;
pos += (frac >> 12);
frac &= 0xfff;
if (start + pos >= end) {
if (vptr->regs[5]) {
pos = loop - start;
} else {
chip->key &= ~(1 << i);
break;
}
}
// 8bit sample store with 16bit bigend ???
sample = base[(start + pos) ^ 1];
frac += step;
#if 1
INT32 sample_l;
sample_l = ((sample * vol_r) >> 8) + buffer[0];
if (sample_l > 32767) buffer[0] = 32767;
else if (sample_l < -32768) buffer[0] = -32768;
else buffer[0] = sample_l;
sample_l = ((sample * vol_l) >> 8) + buffer[1];
if (sample_l > 32767) buffer[1] = 32767;
else if (sample_l < -32768) buffer[1] = -32768;
else buffer[1] = sample_l;
#else
buffer[0] += (sample * (vol_l >> 8));
buffer[1] += (sample * (vol_r >> 8));
#endif
buffer += 2;
}
vptr->pos = pos;
vptr->frac = frac;
}
}
}
INT32 cps3SndScan(INT32 nAction)
{
if (nAction & ACB_DRIVER_DATA) {
SCAN_VAR( chip->voice );
SCAN_VAR( chip->key );
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,343 @@
// A module for keeping parents who have no driver in FBA
#include "burnint.h"
static UINT8 ParentReset = 0;
static struct BurnInputInfo ParentInputList[] = {
{"Reset" , BIT_DIGITAL , &ParentReset , "reset" },
};
STDINPUTINFO(Parent)
static INT32 ParentInit()
{
return 1;
}
static INT32 ParentExit()
{
return 0;
}
static struct BurnRomInfo BagmanRomDesc[] = {
{ "e9_b05.bin", 0x01000, 0xe0156191, BRF_ESS | BRF_PRG },
{ "f9_b06.bin", 0x01000, 0x7b758982, BRF_ESS | BRF_PRG },
{ "f9_b07.bin", 0x01000, 0x302a077b, BRF_ESS | BRF_PRG },
{ "k9_b08.bin", 0x01000, 0xf04293cb, BRF_ESS | BRF_PRG },
{ "m9_b09s.bin", 0x01000, 0x68e83e4f, BRF_ESS | BRF_PRG },
{ "n9_b10.bin", 0x01000, 0x1d6579f7, BRF_ESS | BRF_PRG },
{ "e1_b02.bin", 0x01000, 0x4a0a6b55, BRF_ESS | BRF_PRG },
{ "j1_b04.bin", 0x01000, 0xc680ef04, BRF_ESS | BRF_PRG },
{ "c1_b01.bin", 0x01000, 0x705193b2, BRF_ESS | BRF_PRG },
{ "f1_b03s.bin", 0x01000, 0xdba1eda7, BRF_ESS | BRF_PRG },
{ "p3.bin", 0x00020, 0x2a855523, BRF_GRA },
{ "r3.bin", 0x00020, 0xae6f1019, BRF_GRA },
{ "r6.bin", 0x00020, 0xc58a4f6a, BRF_GRA },
{ "r9_b11.bin", 0x01000, 0x2e0057ff, BRF_SND },
{ "t9_b12.bin", 0x01000, 0xb2120edd, BRF_SND },
};
STD_ROM_PICK(Bagman)
STD_ROM_FN(Bagman)
struct BurnDriver BurnDrvBagman = {
"bagman", NULL, NULL, NULL, "1982",
"Bagman\0", "Parent set for working drivers", "Valadon Automation", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_MAZE, 0,
NULL, BagmanRomInfo, BagmanRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 224, 256, 3, 4
};
static struct BurnRomInfo CkongRomDesc[] = {
{ "falcon7", 0x01000, 0x2171cac3, BRF_ESS | BRF_PRG },
{ "falcon8", 0x01000, 0x88b83ff7, BRF_ESS | BRF_PRG },
{ "falcon9", 0x01000, 0xcff2af47, BRF_ESS | BRF_PRG },
{ "falcon10", 0x01000, 0x6b2ecf23, BRF_ESS | BRF_PRG },
{ "falcon11", 0x01000, 0x327dcadf, BRF_ESS | BRF_PRG },
{ "falcon6", 0x01000, 0xa8916dc8, BRF_GRA },
{ "falcon5", 0x01000, 0xcd3b5dde, BRF_GRA },
{ "falcon4", 0x01000, 0xb62a0367, BRF_GRA },
{ "falcon3", 0x01000, 0x61122c5e, BRF_GRA },
{ "falcon2", 0x00800, 0xf67c80f1, BRF_GRA },
{ "falcon1", 0x00800, 0x80eb517d, BRF_GRA },
{ "ck6v.bin", 0x00020, 0x751c3325, BRF_GRA },
{ "ck6u.bin", 0x00020, 0xab1940fa, BRF_GRA },
{ "ck6t.bin", 0x00020, 0xb4e827a5, BRF_GRA },
{ "falcon13", 0x01000, 0x5f0bcdfb, BRF_SND },
{ "falcon12", 0x01000, 0x9003ffbd, BRF_SND },
};
STD_ROM_PICK(Ckong)
STD_ROM_FN(Ckong)
struct BurnDriver BurnDrvCkong = {
"ckong", NULL, NULL, NULL, "1981",
"Crazy Kong Part II (set 1)\0", "Parent set for working drivers", "Falcon", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_PLATFORM, 0,
NULL, CkongRomInfo, CkongRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 224, 256, 3, 4
};
static struct BurnRomInfo DkongjrRomDesc[] = {
{ "dkj.5b", 0x02000, 0xdea28158, BRF_ESS | BRF_PRG },
{ "dkj.5c", 0x02000, 0x6fb5faf6, BRF_ESS | BRF_PRG },
{ "dkj.5e", 0x02000, 0xd042b6a8, BRF_ESS | BRF_PRG },
{ "c_3h.bin", 0x01000, 0x715da5f8, BRF_ESS | BRF_PRG },
{ "dkj.3n", 0x01000, 0x8d51aca9, BRF_ESS | BRF_PRG },
{ "dkj.3p", 0x01000, 0x4ef64ba5, BRF_ESS | BRF_PRG },
{ "v_7c.bin", 0x00800, 0xdc7f4164, BRF_ESS | BRF_PRG },
{ "v_7d.bin", 0x00800, 0x0ce7dcf6, BRF_ESS | BRF_PRG },
{ "v_7e.bin", 0x00800, 0x24d1ff17, BRF_ESS | BRF_PRG },
{ "v_7f.bin", 0x00800, 0x0f8c083f, BRF_ESS | BRF_PRG },
{ "c-2e.bpr", 0x00100, 0x463dc7ad, BRF_GRA },
{ "c-2f.bpr", 0x00100, 0x47ba0042, BRF_GRA },
{ "v-2n.bpr", 0x00100, 0xdbf185bf, BRF_GRA },
};
STD_ROM_PICK(Dkongjr)
STD_ROM_FN(Dkongjr)
struct BurnDriver BurnDrvDkongjr = {
"dkongjr", NULL, NULL, NULL, "1982",
"Donkey Kong Junior (US)\0", "Parent set for working drivers", "Nintendo of America", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_PLATFORM, 0,
NULL, DkongjrRomInfo, DkongjrRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 224, 256, 3, 4
};
static struct BurnRomInfo DockmanRomDesc[] = {
{ "pe1.19", 0x01000, 0xeef2ec54, BRF_ESS | BRF_PRG },
{ "pe2.18", 0x01000, 0xbc48d16b, BRF_ESS | BRF_PRG },
{ "pe3.17", 0x01000, 0x1c923057, BRF_ESS | BRF_PRG },
{ "pe4.16", 0x01000, 0x23af1cba, BRF_ESS | BRF_PRG },
{ "pe5.15", 0x01000, 0x39dbe429, BRF_ESS | BRF_PRG },
{ "pe7.22", 0x00800, 0xd2094e4a, BRF_ESS | BRF_PRG },
{ "pe6.23", 0x00800, 0x1cf447f4, BRF_ESS | BRF_PRG },
{ "pe8.9", 0x01000, 0x4d8c2974, BRF_GRA },
{ "pe9.8", 0x01000, 0x4e4ea162, BRF_GRA },
{ "mb7051.3", 0x00020, 0x6440dc61, BRF_GRA },
};
STD_ROM_PICK(Dockman)
STD_ROM_FN(Dockman)
struct BurnDriver BurnDrvDockman = {
"dockman", NULL, NULL, NULL, "1982",
"Dock Man\0", "Parent set for working drivers", "Taito Corporation", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_PLATFORM, 0,
NULL, DockmanRomInfo, DockmanRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 224, 256, 3, 4
};
static struct BurnRomInfo EightballactRomDesc[] = {
{ "8b-dk.5e", 0x01000, 0x166c1c9b, BRF_ESS | BRF_PRG },
{ "8b-dk.5c", 0x01000, 0x9ec87baa, BRF_ESS | BRF_PRG },
{ "8b-dk.5b", 0x01000, 0xf836a962, BRF_ESS | BRF_PRG },
{ "8b-dk.5a", 0x01000, 0xd45866d4, BRF_ESS | BRF_PRG },
{ "8b-dk.3h", 0x00800, 0xa8752c60, BRF_ESS | BRF_PRG },
{ "8b-dk.3n", 0x00800, 0x44830867, BRF_GRA },
{ "8b-dk.3p", 0x00800, 0x6148c6f2, BRF_GRA },
{ "8b-dk.7c", 0x00800, 0xe34409f5, BRF_GRA },
{ "8b-dk.7d", 0x00800, 0xb4dc37ca, BRF_GRA },
{ "8b-dk.7e", 0x00800, 0x655af8a8, BRF_GRA },
{ "8b-dk.7f", 0x00800, 0xa29b2763, BRF_GRA },
{ "8b.2e", 0x00100, 0xc7379a12, BRF_GRA },
{ "8b.2f", 0x00100, 0x116612b4, BRF_GRA },
{ "8b.2n", 0x00100, 0x30586988, BRF_GRA },
{ "82s147.prm", 0x00200, 0x46e5bc92, BRF_GRA },
{ "pls153h.bin", 0x000eb, 0x00000000, BRF_NODUMP },
};
STD_ROM_PICK(Eightballact)
STD_ROM_FN(Eightballact)
struct BurnDriver BurnDrvEightballact = {
"8ballact", NULL, NULL, NULL, "1984",
"Eight Ball Action (DK conversion)\0", "Parent set for working drivers", "Seatongrove Ltd (Magic Eletronics USA licence)", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_SPORTSMISC, 0,
NULL, EightballactRomInfo, EightballactRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 256, 224, 4, 3
};
static struct BurnRomInfo HunchbakRomDesc[] = {
{ "hb-gp1.bin", 0x01000, 0xaf801d54, BRF_ESS | BRF_PRG },
{ "hb-gp2.bin", 0x01000, 0xb448cc8e, BRF_ESS | BRF_PRG },
{ "hb-gp3.bin", 0x01000, 0x57c6ea7b, BRF_ESS | BRF_PRG },
{ "hb-gp4.bin", 0x01000, 0x7f91287b, BRF_ESS | BRF_PRG },
{ "hb-gp5.bin", 0x01000, 0x1dd5755c, BRF_ESS | BRF_PRG },
{ "6c.sdp1", 0x01000, 0xf9ba2854, BRF_ESS | BRF_PRG },
{ "8a.sp1", 0x00800, 0xed1cd201, BRF_SND },
{ "11a.cp1", 0x00800, 0xf256b047, BRF_GRA },
{ "10a.cp2", 0x00800, 0xb870c64f, BRF_GRA },
{ "9a.cp3", 0x00800, 0x9a7dab88, BRF_GRA },
{ "5b.bin", 0x00800, 0xf055a624, BRF_SND },
{ "82s185.10h", 0x00800, 0xc205bca6, BRF_GRA },
{ "82s123.10k", 0x00020, 0xb5221cec, BRF_GRA },
};
STD_ROM_PICK(Hunchbak)
STD_ROM_FN(Hunchbak)
struct BurnDriver BurnDrvHunchbak = {
"hunchbak", NULL, NULL, NULL, "1983",
"Hunchback (set 1)\0", "Parent set for working drivers", "Century Electronics", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_PLATFORM, 0,
NULL, HunchbakRomInfo, HunchbakRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 224, 256, 3, 4
};
static struct BurnRomInfo HuncholyRomDesc[] = {
{ "ho-gp1.bin", 0x01000, 0x4f17cda7, BRF_ESS | BRF_PRG },
{ "ho-gp2.bin", 0x01000, 0x70fa52c7, BRF_ESS | BRF_PRG },
{ "ho-gp3.bin", 0x01000, 0x931934b1, BRF_ESS | BRF_PRG },
{ "ho-gp4.bin", 0x01000, 0xaf5cd501, BRF_ESS | BRF_PRG },
{ "ho-gp5.bin", 0x01000, 0x658e8974, BRF_ESS | BRF_PRG },
{ "ho-sdp1.bin", 0x01000, 0x3efb3ffd, BRF_ESS | BRF_PRG },
{ "ho-sp1.bin", 0x01000, 0x3fd39b1e, BRF_SND },
{ "ho-cp1.bin", 0x00800, 0xc6c73d46, BRF_GRA },
{ "ho-cp2.bin", 0x00800, 0xe596371c, BRF_GRA },
{ "ho-cp3.bin", 0x00800, 0x11fae1cf, BRF_GRA },
{ "5b.bin", 0x00800, 0xf055a624, BRF_SND },
{ "82s185.10h", 0x00800, 0xc205bca6, BRF_GRA },
{ "82s123.10k", 0x00020, 0xb5221cec, BRF_GRA },
};
STD_ROM_PICK(Huncholy)
STD_ROM_FN(Huncholy)
struct BurnDriver BurnDrvHuncholy = {
"huncholy", NULL, NULL, NULL, "1984",
"Hunchback Olympic\0", "Parent set for working drivers", "Seatongrove Ltd", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_SPORTSMISC, 0,
NULL, HuncholyRomInfo, HuncholyRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 224, 256, 3, 4
};
static struct BurnRomInfo ManiacsqRomDesc[] = {
{ "d8-d15.1m", 0x20000, 0x9121d1b6, BRF_ESS | BRF_PRG },
{ "d0-d7.1m", 0x20000, 0xa95cfd2a, BRF_ESS | BRF_PRG },
{ "d0-d7.4m", 0x80000, 0xd8551b2f, BRF_GRA },
{ "d8-d15.4m", 0x80000, 0xb269c427, BRF_GRA },
{ "d16-d23.1m", 0x20000, 0xaf4ea5e7, BRF_GRA },
{ "d24-d31.1m", 0x20000, 0x578c3588, BRF_GRA },
};
STD_ROM_PICK(Maniacsq)
STD_ROM_FN(Maniacsq)
struct BurnDriver BurnDrvManiacsq = {
"maniacsq", NULL, NULL, NULL, "1996",
"Maniac Square (unprotected)\0", "Parent set for working drivers", "Gaelco", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_POST90S, GBF_PUZZLE, 0,
NULL, ManiacsqRomInfo, ManiacsqRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 256, 224, 4, 3
};
static struct BurnRomInfo PhoenixRomDesc[] = {
{ "ic45", 0x00800, 0x9f68086b, BRF_ESS | BRF_PRG },
{ "ic46", 0x00800, 0x273a4a82, BRF_ESS | BRF_PRG },
{ "ic47", 0x00800, 0x3d4284b9, BRF_ESS | BRF_PRG },
{ "ic48", 0x00800, 0xcb5d9915, BRF_ESS | BRF_PRG },
{ "h5-ic49.5a", 0x00800, 0xa105e4e7, BRF_ESS | BRF_PRG },
{ "h6-ic50.6a", 0x00800, 0xac5e9ec1, BRF_ESS | BRF_PRG },
{ "h7-ic51.7a", 0x00800, 0x2eab35b4, BRF_ESS | BRF_PRG },
{ "h8-ic52.8a", 0x00800, 0xaff8e9c5, BRF_ESS | BRF_PRG },
{ "ic23.3d", 0x00800, 0x3c7e623f, BRF_GRA },
{ "ic24.4d", 0x00800, 0x59916d3b, BRF_GRA },
{ "b1-ic39.3b", 0x00800, 0x53413e8f, BRF_GRA },
{ "b2-ic40.4b", 0x00800, 0x0be2ba91, BRF_GRA },
{ "mmi6301.ic40", 0x00100, 0x79350b25, BRF_GRA },
{ "mmi6301.ic41", 0x00100, 0xe176b768, BRF_GRA },
};
STD_ROM_PICK(Phoenix)
STD_ROM_FN(Phoenix)
struct BurnDriver BurnDrvPhoenix = {
"phoenix", NULL, NULL, NULL, "1980",
"Phoenix (Amstar)\0", "Parent set for working drivers", "Amstar", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_VERSHOOT, 0,
NULL, PhoenixRomInfo, PhoenixRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 208, 256, 3, 4
};
static struct BurnRomInfo ThepitRomDesc[] = {
{ "pit1.bin", 0x01000, 0x71affecc, BRF_ESS | BRF_PRG },
{ "pit2.bin", 0x01000, 0x894063cd, BRF_ESS | BRF_PRG },
{ "pit3.bin", 0x01000, 0x1b488543, BRF_ESS | BRF_PRG },
{ "pit4.bin", 0x01000, 0xe941e848, BRF_ESS | BRF_PRG },
{ "pit5.bin", 0x01000, 0xe0643c95, BRF_ESS | BRF_PRG },
{ "pit6.bin", 0x00800, 0x1b79dfb6, BRF_ESS | BRF_PRG },
{ "pit8.bin", 0x00800, 0x69502afc, BRF_GRA },
{ "pit7.bin", 0x00800, 0xd901b353, BRF_GRA },
{ "82s123.ic4", 0x00020, 0xa758b567, BRF_GRA },
};
STD_ROM_PICK(Thepit)
STD_ROM_FN(Thepit)
struct BurnDriver BurnDrvThepit = {
"thepit", NULL, NULL, NULL, "1992",
"The Pit\0", "Parent set for working drivers", "Taito", "Miscellaneous",
NULL, NULL, NULL, NULL,
0, 2, HARDWARE_MISC_PRE90S, GBF_PLATFORM, 0,
NULL, ThepitRomInfo, ThepitRomName, NULL, NULL, ParentInputInfo, NULL,
ParentInit, ParentExit, NULL, NULL, NULL,
NULL, 0, 256, 224, 4, 3
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,316 @@
#include "tiles_generic.h"
#include "dac.h"
#include "8255ppi.h"
#include "bitswap.h"
#include "s2650_intf.h"
#include "sn76496.h"
#include "driver.h"
extern "C" {
#include "ay8910.h"
}
// ROM types
#define GAL_ROM_Z80_PROG1 1
#define GAL_ROM_Z80_PROG2 2
#define GAL_ROM_Z80_PROG3 3
#define GAL_ROM_TILES_SHARED 4
#define GAL_ROM_TILES_CHARS 5
#define GAL_ROM_TILES_SPRITES 6
#define GAL_ROM_PROM 7
#define GAL_ROM_S2650_PROG1 8
#define GAL_ROM_OFFSET_Z80_PROG2 GalZ80Rom1Num
#define GAL_ROM_OFFSET_Z80_PROG3 GalZ80Rom1Num + GalZ80Rom2Num
#define GAL_ROM_OFFSET_TILES_SHARED GalZ80Rom1Num + GalZ80Rom2Num + GalZ80Rom3Num
#define GAL_ROM_OFFSET_TILES_CHARS GalZ80Rom1Num + GalZ80Rom2Num + GalZ80Rom3Num + GalTilesSharedRomNum
#define GAL_ROM_OFFSET_TILES_SPRITES GalZ80Rom1Num + GalZ80Rom2Num + GalZ80Rom3Num + GalTilesSharedRomNum + GalTilesCharRomNum
#define GAL_ROM_OFFSET_PROM GalZ80Rom1Num + GalZ80Rom2Num + GalZ80Rom3Num + GalTilesSharedRomNum + GalTilesCharRomNum + GalTilesSpriteRomNum
#define GAL_ROM_OFFSET_S2650_PROG1 GalZ80Rom1Num + GalZ80Rom2Num + GalZ80Rom3Num + GalTilesSharedRomNum + GalTilesCharRomNum + GalTilesSpriteRomNum + GalPromRomNum
// IRQ types
#define GAL_IRQ_TYPE_NMI 1
#define GAL_IRQ_TYPE_IRQ0 2
// Sound hardware types
#define GAL_SOUND_HARDWARE_TYPE_GALAXIAN 1
#define GAL_SOUND_HARDWARE_TYPE_ZIGZAGAY8910 2
#define GAL_SOUND_HARDWARE_TYPE_JUMPBUGAY8910 3
#define GAL_SOUND_HARDWARE_TYPE_CHECKMANAY8910 4
#define GAL_SOUND_HARDWARE_TYPE_CHECKMAJAY8910 5
#define GAL_SOUND_HARDWARE_TYPE_MSHUTTLEAY8910 6
#define GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC 7
#define GAL_SOUND_HARDWARE_TYPE_FROGGERAY8910 8
#define GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910 9
#define GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910 10
#define GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910 11
#define GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC 12
#define GAL_SOUND_HARDWARE_TYPE_BONGOAY8910 13
#define GAL_SOUND_HARDWARE_TYPE_AD2083AY8910 14
#define GAL_SOUND_HARDWARE_TYPE_RACKNROLSN76496 15
#define GAL_SOUND_HARDWARE_TYPE_HEXPOOLASN76496 16
#define GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910 17
// Palette Numbers
#define GAL_PALETTE_NUM_COLOURS_PROM 64
#define GAL_PALETTE_NUM_COLOURS_STARS 64
#define GAL_PALETTE_NUM_COLOURS_BULLETS 8
#define GAL_PALETTE_NUM_COLOURS_BACKGROUND 256
#define GAL_PALETTE_STARS_OFFSET GAL_PALETTE_NUM_COLOURS_PROM
#define GAL_PALETTE_BULLETS_OFFSET GAL_PALETTE_NUM_COLOURS_PROM + GAL_PALETTE_NUM_COLOURS_STARS
#define GAL_PALETTE_BACKGROUND_OFFSET GAL_PALETTE_NUM_COLOURS_PROM + GAL_PALETTE_NUM_COLOURS_STARS + GAL_PALETTE_NUM_COLOURS_BULLETS
// gal_gfx.cpp
extern UINT8 GalFlipScreenX;
extern UINT8 GalFlipScreenY;
extern UINT8 *GalGfxBank;
extern UINT8 GalPaletteBank;
extern UINT8 GalSpriteClipStart;
extern UINT8 GalSpriteClipEnd;
extern UINT8 FroggerAdjust;
extern UINT8 GalBackgroundRed;
extern UINT8 GalBackgroundGreen;
extern UINT8 GalBackgroundBlue;
extern UINT8 GalBackgroundEnable;
extern UINT8 SfxTilemap;
extern UINT8 GalOrientationFlipX;
extern UINT8 GalColourDepth;
extern UINT8 DarkplntBulletColour;
extern UINT8 DambustrBgColour1;
extern UINT8 DambustrBgColour2;
extern UINT8 DambustrBgPriority;
extern UINT8 DambustrBgSplitLine;
extern UINT8 *RockclimTiles;
extern UINT16 RockclimScrollX;
extern UINT16 RockclimScrollY;
extern INT32 CharPlaneOffsets[2];
extern INT32 CharXOffsets[8];
extern INT32 CharYOffsets[8];
extern INT32 SpritePlaneOffsets[2];
extern INT32 SpriteXOffsets[16];
extern INT32 SpriteYOffsets[16];
typedef void (*GalRenderBackground)();
extern GalRenderBackground GalRenderBackgroundFunction;
typedef void (*GalCalcPalette)();
extern GalCalcPalette GalCalcPaletteFunction;
typedef void (*GalDrawBullet)(INT32, INT32, INT32);
extern GalDrawBullet GalDrawBulletsFunction;
typedef void (*GalExtendTileInfo)(UINT16*, INT32*, INT32, INT32);
extern GalExtendTileInfo GalExtendTileInfoFunction;
typedef void (*GalExtendSpriteInfo)(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16*, UINT8*);
extern GalExtendSpriteInfo GalExtendSpriteInfoFunction;
typedef void (*GalRenderFrame)();
extern GalRenderFrame GalRenderFrameFunction;
void UpperExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void UpperExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void PiscesExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void PiscesExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void Batman2ExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void GmgalaxExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void GmgalaxExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void MooncrstExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void MooncrstExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void MoonqsrExtendTileInfo(UINT16 *Code, INT32*, INT32 Attr, INT32);
void MoonqsrExtendSpriteInfo(const UINT8 *Base, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void SkybaseExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void SkybaseExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void RockclimExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void JumpbugExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void JumpbugExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void FroggerExtendTileInfo(UINT16*, INT32 *Colour, INT32, INT32);
void FroggerExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16*, UINT8 *Colour);
void CalipsoExtendSpriteInfo(const UINT8 *Base, INT32*, INT32*, UINT8 *xFlip, UINT8 *yFlip, UINT16 *Code, UINT8*);
void MshuttleExtendTileInfo(UINT16 *Code, INT32*, INT32 Attr, INT32);
void MshuttleExtendSpriteInfo(const UINT8 *Base, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void Fourin1ExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void Fourin1ExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void DkongjrmExtendSpriteInfo(const UINT8 *Base, INT32*, INT32*, UINT8 *xFlip, UINT8*, UINT16 *Code, UINT8*);
void MarinerExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32 x);
void MimonkeyExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32);
void MimonkeyExtendSpriteInfo(const UINT8*, INT32*, INT32*, UINT8*, UINT8*, UINT16 *Code, UINT8*);
void DambustrExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32 x);
void Ad2083ExtendTileInfo(UINT16 *Code, INT32 *Colour, INT32 Attr, INT32);
void Ad2083ExtendSpriteInfo(const UINT8 *Base, INT32*, INT32*, UINT8 *xFlip, UINT8*, UINT16 *Code, UINT8*);
void RacknrolExtendTileInfo(UINT16 *Code, INT32*, INT32, INT32 x);
void HardCodeGalaxianPROM();
void HardCodeMooncrstPROM();
void GalaxianCalcPalette();
void RockclimCalcPalette();
void MarinerCalcPalette();
void StratgyxCalcPalette();
void RescueCalcPalette();
void MinefldCalcPalette();
void DarkplntCalcPalette();
void DambustrCalcPalette();
void GalaxianDrawBackground();
void RockclimDrawBackground();
void JumpbugDrawBackground();
void FroggerDrawBackground();
void TurtlesDrawBackground();
void ScrambleDrawBackground();
void AnteaterDrawBackground();
void MarinerDrawBackground();
void StratgyxDrawBackground();
void RescueDrawBackground();
void MinefldDrawBackground();
void DambustrDrawBackground();
void GalaxianDrawBullets(INT32 Offs, INT32 x, INT32 y);
void TheendDrawBullets(INT32 Offs, INT32 x, INT32 y);
void ScrambleDrawBullets(INT32, INT32 x, INT32 y);
void MoonwarDrawBullets(INT32, INT32 x, INT32 y);
void MshuttleDrawBullets(INT32, INT32 x, INT32 y);
void DarkplntDrawBullets(INT32, INT32 x, INT32 y);
void DambustrDrawBullets(INT32 Offs, INT32 x, INT32 y);
void GalDraw();
void DkongjrmRenderFrame();
void DambustrRenderFrame();
// gal_run.cpp
extern UINT8 GalInputPort0[8];
extern UINT8 GalInputPort1[8];
extern UINT8 GalInputPort2[8];
extern UINT8 GalInputPort3[8];
extern UINT8 GalDip[7];
extern UINT8 GalInput[4];
extern UINT8 GalReset;
extern UINT8 GalFakeDip;
extern INT32 GalAnalogPort0;
extern INT32 GalAnalogPort1;
extern UINT8 *GalMem;
extern UINT8 *GalMemEnd;
extern UINT8 *GalRamStart;
extern UINT8 *GalRamEnd;
extern UINT8 *GalZ80Rom1;
extern UINT8 *GalZ80Rom1Op;
extern UINT8 *GalZ80Rom2;
extern UINT8 *GalZ80Rom3;
extern UINT8 *GalS2650Rom1;
extern UINT8 *GalZ80Ram1;
extern UINT8 *GalZ80Ram2;
extern UINT8 *GalVideoRam;
extern UINT8 *GalVideoRam2;
extern UINT8 *GalSpriteRam;
extern UINT8 *GalScrollVals;
extern UINT8 *GalProm;
extern UINT8 *GalChars;
extern UINT8 *GalSprites;
extern UINT8 *GalTempRom;
extern UINT32 *GalPalette;
extern UINT32 GalZ80Rom1Size;
extern UINT32 GalZ80Rom1Num;
extern UINT32 GalZ80Rom2Size;
extern UINT32 GalZ80Rom2Num;
extern UINT32 GalZ80Rom3Size;
extern UINT32 GalZ80Rom3Num;
extern UINT32 GalS2650Rom1Size;
extern UINT32 GalS2650Rom1Num;
extern UINT32 GalTilesSharedRomSize;
extern UINT32 GalTilesSharedRomNum;
extern UINT32 GalTilesCharRomSize;
extern UINT32 GalTilesCharRomNum;
extern UINT32 GalNumChars;
extern UINT32 GalTilesSpriteRomSize;
extern UINT32 GalTilesSpriteRomNum;
extern UINT32 GalNumSprites;
extern UINT32 GalPromRomSize;
extern UINT32 GalPromRomNum;
typedef void (*GalPostLoadCallback)();
extern GalPostLoadCallback GalPostLoadCallbackFunction;
extern UINT8 GalIrqType;
extern UINT8 GalIrqFire;
extern INT32 nGalCyclesDone[3], nGalCyclesTotal[3];
extern UINT8 ZigzagAYLatch;
extern UINT8 GalSoundLatch;
extern UINT8 GalSoundLatch2;
extern UINT8 KingballSound;
extern UINT8 KonamiSoundControl;
extern UINT8 SfxSampleControl;
extern UINT8 KingballSpeechDip;
extern UINT16 ScrambleProtectionState;
extern UINT8 ScrambleProtectionResult;
extern UINT8 MoonwarPortSelect;
extern UINT8 MshuttleAY8910CS;
extern UINT8 GmgalaxSelectedGame;
extern UINT8 Fourin1Bank;
extern UINT8 GameIsGmgalax;
extern UINT8 CavelonBankSwitch;
extern UINT8 GalVBlank;
UINT8 KonamiPPIReadIN0();
UINT8 KonamiPPIReadIN1();
UINT8 KonamiPPIReadIN2();
UINT8 KonamiPPIReadIN3();
INT32 GalInit();
void MapMooncrst();
void MapJumpbug();
void MapFrogger();
void KonamiPPIInit();
void MapTheend();
void MapTurtles();
void MapScobra();
INT32 GalExit();
INT32 KonamiExit();
INT32 GalFrame();
INT32 GalScan(INT32 nAction, INT32 *pnMin);
// gal_sound.cpp
extern INT16* pFMBuffer;
extern INT16* pAY8910Buffer[9];
extern UINT8 GalSoundType;
extern UINT8 GalSoundVolumeShift;
extern UINT8 HunchbksSoundIrqFire;
extern UINT8 GalLastPort2;
extern UINT8 GalShootEnable;
extern UINT8 GalNoiseEnable;
extern INT32 GalNoiseVolume;
extern double GalShootWavePos;
extern double GalNoiseWavePos;
extern INT32 GalPitch;
extern INT32 GalVol;
extern INT32 GalLfoVolume[3];
extern double GalLfoFreq;
extern double GalLfoFreqFrameVar;
extern INT32 GalLfoBit[4];
void GalSoundReset();
void GalSoundInit();
void GalSoundExit();
void GalSoundScan(INT32 nAction, INT32 *pnMin);
UINT8 CheckmajPortARead(UINT32);
UINT8 BongoDipSwitchRead(UINT32);
UINT8 KonamiSoundLatchRead(UINT32);
UINT8 KonamiSoundTimerRead(UINT32);
UINT8 FroggerSoundTimerRead(UINT32);
UINT8 HunchbksSoundTimerRead(UINT32);
void KonamiSoundLatchWrite(UINT8 d);
void KonamiSoundControlWrite(UINT8 d);
void HunchbksSoundControlWrite(UINT8 d);
void SfxSoundLatch2Write(UINT32, UINT32 d);
void SfxSampleControlWrite(UINT32, UINT32 d);
void FroggerSoundInit();
void FroggerSoundNoEncryptionInit();
void KonamiSoundInit();
void HunchbksSoundInit();
void GalRenderSoundSamples(INT16 *pSoundBuf, INT32 nLength);
void GalaxianSoundWrite(UINT32 Offset, UINT8 d);
void GalaxianLfoFreqWrite(UINT32 Offset, UINT8 d);
void GalaxianSoundUpdateTimers();
// gal_stars.cpp
extern INT32 GalStarsEnable;
extern INT32 GalStarsScrollPos;
extern INT32 GalStarsBlinkState;
extern INT32 GalBlinkTimerStartFrame;
void GalInitStars();
void GalaxianRenderStarLayer();
void JumpbugRenderStarLayer();
void ScrambleRenderStarLayer();
void MarinerRenderStarLayer();
void RescueRenderStarLayer();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,943 @@
#include "gal.h"
INT16* pFMBuffer;
INT16* pAY8910Buffer[9];
UINT8 GalSoundType;
UINT8 GalSoundVolumeShift;
UINT8 HunchbksSoundIrqFire;
#define XTAL 18432000
#define RNG_RATE (XTAL / 3)
#define NOISE_RATE (XTAL / 3 / 192 / 2 / 2)
#define NOISE_LENGTH (NOISE_RATE * 4)
#define NOISE_AMPLITUDE (70 * 256)
#define SHOOT_VOLUME 0.50f
#define SHOOT_SEC 2
#define R41__ 100000
#define R44__ 10000
#define R45__ 22000
#define R46__ 10000
#define R47__ 2200
#define R48__ 2200
#define C25__ 0.000001
#define C27__ 0.00000001
#define C28__ 0.000047
#define C29__ 0.00000001
#define IC8L3_L 0.2
#define IC8L3_H 4.5
#define NOISE_L 0.2
#define NOISE_H 4.5
#define SHOOT_KEYON_TIME 0.1
#define NE555_FM_ADJUST_RATE 0.80
#define TOOTHSAW_LENGTH 16
#define TOOTHSAW_VOLUME 0.36f
#define TOOTHSAW_AMPLITUDE (64*256)
#define V(r0,r1) 2 * TOOTHSAW_AMPLITUDE * (r0) / (r0 + r1) - TOOTHSAW_AMPLITUDE
#define STEPS 16
#define LFO_VOLUME 0.06f
#define MINFREQ (139 - 139 / 3)
#define MAXFREQ (139 + 139 / 3)
static INT16 *GalNoiseWave;
static INT16 *GalShootWave;
static UINT32 GalShootLength;
static UINT32 GalShootRate;
UINT8 GalLastPort2 = 0;
UINT8 GalShootEnable;
UINT8 GalNoiseEnable;
INT32 GalNoiseVolume;
double GalShootWavePos;
double GalNoiseWavePos;
double GalLfoWavePos[3];
INT32 GalPitch;
INT32 GalVol;
static double GalCounter;
static INT32 GalCountDown;
INT32 GalLfoVolume[3];
double GalLfoFreq;
double GalLfoFreqFrameVar;
INT32 GalLfoBit[4];
static INT16 GalToneWave[4][TOOTHSAW_LENGTH];
static const INT16 GalBackgroundWave[32] =
{
0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000,
0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000,
-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,
-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,-0x4000,
};
void GalSoundReset()
{
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_ZIGZAGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_JUMPBUGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMANAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMAJAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_FROGGERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_MSHUTTLEAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_BONGOAY8910) {
AY8910Reset(0);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_AD2083AY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910) {
AY8910Reset(0);
AY8910Reset(1);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910) {
AY8910Reset(0);
AY8910Reset(1);
AY8910Reset(2);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC) {
DACReset();
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_GALAXIAN || GalSoundType == GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC) {
GalLastPort2 = 0;
GalShootEnable = 0;
GalNoiseEnable = 0;
GalNoiseVolume = 0;
GalShootWavePos = 0;
GalNoiseWavePos = 0;
GalLfoWavePos[0] = GalLfoWavePos[1] = GalLfoWavePos[2] = 0;
GalPitch = 0xff;
GalVol = 0;
GalCounter = 0;
GalCountDown = 0;
GalLfoVolume[0] = GalLfoVolume[1] = GalLfoVolume[2] = 0;
GalLfoFreq = MAXFREQ;
GalLfoFreqFrameVar = 0;
GalLfoBit[0] = GalLfoBit[1] = GalLfoBit[2] = GalLfoBit[3] = 0;
}
}
void GalSoundInit()
{
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_ZIGZAGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_JUMPBUGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMANAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMAJAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_FROGGERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_MSHUTTLEAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_BONGOAY8910) {
pFMBuffer = (INT16*)malloc(nBurnSoundLen * 3 * sizeof(INT16));
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_AD2083AY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910) {
pFMBuffer = (INT16*)malloc(nBurnSoundLen * 6 * sizeof(INT16));
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910) {
pFMBuffer = (INT16*)malloc(nBurnSoundLen * 9 * sizeof(INT16));
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_ZIGZAGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMAJAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMANAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_JUMPBUGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_FROGGERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_MSHUTTLEAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_BONGOAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_AD2083AY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910) {
pAY8910Buffer[0] = pFMBuffer + nBurnSoundLen * 0;
pAY8910Buffer[1] = pFMBuffer + nBurnSoundLen * 1;
pAY8910Buffer[2] = pFMBuffer + nBurnSoundLen * 2;
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_AD2083AY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910) {
pAY8910Buffer[3] = pFMBuffer + nBurnSoundLen * 3;
pAY8910Buffer[4] = pFMBuffer + nBurnSoundLen * 4;
pAY8910Buffer[5] = pFMBuffer + nBurnSoundLen * 5;
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910) {
pAY8910Buffer[6] = pFMBuffer + nBurnSoundLen * 6;
pAY8910Buffer[7] = pFMBuffer + nBurnSoundLen * 7;
pAY8910Buffer[8] = pFMBuffer + nBurnSoundLen * 8;
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_ZIGZAGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMANAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_JUMPBUGAY8910) {
AY8910Init(0, 1789750, nBurnSoundRate, NULL, NULL, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_BONGOAY8910) {
AY8910Init(0, 1789750, nBurnSoundRate, &BongoDipSwitchRead, NULL, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMAJAY8910) {
AY8910Init(0, 1620000, nBurnSoundRate, &CheckmajPortARead, NULL, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_MSHUTTLEAY8910) {
// Port A Write - cclimber_sample_select_w
AY8910Init(0, 18432000 / 3 / 4, nBurnSoundRate, NULL, NULL, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_FROGGERAY8910) {
AY8910Init(0, 14318000 / 8, nBurnSoundRate, &KonamiSoundLatchRead, &FroggerSoundTimerRead, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910) {
AY8910Init(0, 14318000 / 8, nBurnSoundRate, NULL, NULL, NULL, NULL);
AY8910Init(1, 14318000 / 8, nBurnSoundRate, &KonamiSoundLatchRead, &KonamiSoundTimerRead, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910) {
AY8910Init(0, 14318000 / 8, nBurnSoundRate, &KonamiSoundTimerRead, NULL, NULL, NULL);
AY8910Init(1, 14318000 / 8, nBurnSoundRate, &KonamiSoundLatchRead, NULL, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910) {
AY8910Init(0, 14318000 / 8, nBurnSoundRate, NULL, NULL, NULL, NULL);
AY8910Init(1, 14318000 / 8, nBurnSoundRate, &KonamiSoundLatchRead, &KonamiSoundTimerRead, NULL, NULL);
AY8910Init(2, 14318000 / 8, nBurnSoundRate, NULL, NULL, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_AD2083AY8910) {
AY8910Init(0, 14318000 / 8, nBurnSoundRate, &KonamiSoundTimerRead, NULL, NULL, NULL);
AY8910Init(1, 14318000 / 8, nBurnSoundRate, &KonamiSoundLatchRead, NULL, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC) {
AY8910Init(0, 14318000 / 8, nBurnSoundRate, NULL, NULL, &SfxSoundLatch2Write, &SfxSampleControlWrite);
AY8910Init(1, 14318000 / 8, nBurnSoundRate, &KonamiSoundLatchRead, &KonamiSoundTimerRead, NULL, NULL);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC) {
DACInit(0, 0, 1);
DACSetVolShift(0, 2);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_HEXPOOLASN76496) {
SN76496Init(0, 18432000 / 3 / 2, 0);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_RACKNROLSN76496) {
SN76496Init(0, 18432000 / 3 / 2, 0);
SN76496Init(1, 18432000 / 3 / 2, 1);
SN76496Init(2, 18432000 / 3 / 2, 1);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910) {
AY8910Init(0, 14318000 / 8, nBurnSoundRate, NULL, NULL, NULL, NULL);
AY8910Init(1, 14318000 / 8, nBurnSoundRate, &KonamiSoundLatchRead, &HunchbksSoundTimerRead, NULL, NULL);
}
GalSoundVolumeShift = 1;
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_GALAXIAN || GalSoundType == GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC) {
GalShootEnable = 0;
GalShootWavePos = 0;
INT32 CountDown, Generator, Bit1, Bit2;
GalNoiseWave = (INT16*)malloc(NOISE_LENGTH * sizeof(INT16));
GalShootRate = 22050;
GalShootLength = SHOOT_SEC * GalShootRate;
GalShootWave = (INT16*)malloc(GalShootLength * sizeof(INT16));
Generator = 0;
CountDown = NOISE_RATE / 2;
for (INT32 i = 0; i < NOISE_LENGTH; i++) {
CountDown -= RNG_RATE;
while (CountDown < 0) {
Generator <<= 1;
Bit1 = (~Generator >> 17) & 1;
Bit2 = (Generator >> 5) & 1;
if (Bit1 ^ Bit2) Generator |= 1;
CountDown += NOISE_RATE;
}
GalNoiseWave[i] = ((Generator >> 17) & 1) ? NOISE_AMPLITUDE : -NOISE_AMPLITUDE;
}
double v = 5.0;
double vK = (GalShootRate) ? exp(-1 / (R41__ * C25__) / GalShootRate) : 0;
double IC8L3 = IC8L3_L;
INT32 IC8Lcnt = (INT32)(SHOOT_KEYON_TIME * GalShootRate);
double c28v = IC8L3_H - (IC8L3_H - (NOISE_H + NOISE_L) / 2) / (R46__ + R47__ + R48__) * R47__;
double c28K = (GalShootRate) ? exp(-1 / (22000 * 0.000047 ) / GalShootRate) : 0;
double c29v = IC8L3_H - (IC8L3_H - (NOISE_H + NOISE_L) / 2) / (R46__ + R47__ + R48__) * (R47__ + R48__);
double c29K1 = (GalShootRate) ? exp(-1 / (22000 * 0.00000001 ) / GalShootRate) : 0;
double c29K2 = (GalShootRate) ? exp(-1 / (100000 * 0.00000001 ) / GalShootRate) : 0;
double ne555cnt = 0;
double ne555step = (GalShootRate) ? ((1.44 / ((R44__ + R45__ * 2) * C27__)) / GalShootRate) : 0;
double ne555duty = (double)(R44__ + R45__) / (R44__ + R45__ * 2);
double ne555sr;
double ncnt = 0.0;
double nstep = (GalShootRate) ? ((double)NOISE_RATE / GalShootRate) : 0;
double noise_sh2;
for (UINT32 i = 0; i < GalShootLength; i++) {
noise_sh2 = GalNoiseWave[(INT32)ncnt % NOISE_LENGTH] == NOISE_AMPLITUDE ? NOISE_H : NOISE_L;
ncnt += nstep;
ne555sr = c29v * NE555_FM_ADJUST_RATE / (5.0 * 2 / 3);
ne555cnt += ne555step;
if (ne555cnt >= ne555sr) ne555cnt -= ne555sr;
if (ne555cnt < ne555sr * ne555duty) {
GalShootWave[i] = (INT16)(v / 5 * 0x7fff);
if(IC8L3 == IC8L3_H) v *= vK;
} else {
GalShootWave[i] = 0;
}
c28v += (IC8L3 - c28v) - (IC8L3 - c28v) * c28K;
c28v += (c29v - c28v) - (c29v - c28v) * c28K;
c29v += (c28v - c29v) - (c28v - c29v) * c29K1;
c29v += (noise_sh2 - c29v) - (noise_sh2 - c29v) * c29K2;
if(IC8L3 == IC8L3_L && --IC8Lcnt == 0) IC8L3 = IC8L3_H;
}
memset(GalToneWave, 0, sizeof(GalToneWave));
for (UINT32 i = 0; i < TOOTHSAW_LENGTH; i++ ) {
double r0a = 1.0 / 1e12, r1a = 1.0 / 1e12;
double r0b = 1.0 / 1e12, r1b = 1.0 / 1e12;
if (i & 1) {
r1a += 1.0 / 33000;
r1b += 1.0 / 33000;
} else {
r0a += 1.0 / 33000;
r0b += 1.0 / 33000;
}
if (i & 4) {
r1a += 1.0 / 22000;
r1b += 1.0 / 22000;
} else {
r0a += 1.0 / 22000;
r0b += 1.0 / 22000;
}
GalToneWave[0][i] = (INT16)(V(1.0 / r0a, 1.0 / r1a));
if (i & 4) {
r1a += 1.0 / 10000;
} else {
r0a += 1.0 / 10000;
}
GalToneWave[1][i] = (INT16)(V(1.0 / r0a, 1.0 / r1a));
if (i & 8) {
r1b += 1.0 / 15000;
} else {
r0b += 1.0 / 15000;
}
GalToneWave[2][i] = (INT16)(V(1.0 / r0b, 1.0 / r1b));
if (i & 4) {
r0b += 1.0 / 10000;
} else {
r1b += 1.0 / 10000;
}
GalToneWave[3][i] = (INT16)(V(1.0 / r0b, 1.0 / r1b));
}
GalPitch = 0xff;
GalVol = 0;
GalLfoFreq = MAXFREQ;
GalLfoFreqFrameVar = 0;
}
}
void GalSoundExit()
{
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_ZIGZAGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_JUMPBUGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMANAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMAJAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_FROGGERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_BONGOAY8910) {
AY8910Exit(0);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_AD2083AY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910) {
AY8910Exit(0);
AY8910Exit(1);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910) {
AY8910Exit(0);
AY8910Exit(1);
AY8910Exit(2);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC) {
DACExit();
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_RACKNROLSN76496 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_HEXPOOLASN76496) {
SN76496Exit();
}
if (pFMBuffer) {
free(pFMBuffer);
pFMBuffer = NULL;
for (INT32 i = 0; i < 9; i++) pAY8910Buffer[i] = NULL;
}
if (GalNoiseWave) {
free(GalNoiseWave);
GalNoiseWave = NULL;
}
if (GalShootWave) {
free(GalShootWave);
GalShootWave = NULL;
}
HunchbksSoundIrqFire = 0;
GalShootLength = 0;
GalShootRate = 0;
GalLastPort2 = 0;
GalShootEnable = 0;
GalNoiseEnable = 0;
GalNoiseVolume = 0;
GalShootWavePos = 0;
GalNoiseWavePos = 0;
GalLfoWavePos[0] = GalLfoWavePos[1] = GalLfoWavePos[2] = 0;
GalPitch = 0;
GalVol = 0;
GalCounter = 0;
GalCountDown = 0;
GalLfoVolume[0] = GalLfoVolume[1] = GalLfoVolume[2] = 0;
GalLfoFreq = 0;
GalLfoFreqFrameVar = 0;
GalLfoBit[0] = GalLfoBit[1] = GalLfoBit[2] = GalLfoBit[3] = 0;
memset(GalToneWave, 0, sizeof(GalToneWave));
}
void GalSoundScan(INT32 nAction, INT32 *pnMin)
{
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_GALAXIAN || GalSoundType == GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC) {
SCAN_VAR(GalLastPort2);
SCAN_VAR(GalShootEnable);
SCAN_VAR(GalNoiseEnable);
SCAN_VAR(GalNoiseVolume);
SCAN_VAR(GalShootWavePos);
SCAN_VAR(GalNoiseWavePos);
SCAN_VAR(GalLfoWavePos);
SCAN_VAR(GalPitch);
SCAN_VAR(GalVol);
SCAN_VAR(GalCounter);
SCAN_VAR(GalCountDown);
SCAN_VAR(GalLfoVolume);
SCAN_VAR(GalLfoFreq);
SCAN_VAR(GalLfoFreqFrameVar);
SCAN_VAR(GalLfoBit);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_ZIGZAGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_JUMPBUGAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMANAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_CHECKMAJAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_FROGGERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_BONGOAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_KONAMIAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_EXPLORERAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_AD2083AY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SCORPIONAY8910 || GalSoundType == GAL_SOUND_HARDWARE_TYPE_HUNCHBACKAY8910) {
AY8910Scan(nAction, pnMin);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_KINGBALLDAC || GalSoundType == GAL_SOUND_HARDWARE_TYPE_SFXAY8910DAC) {
DACScan(nAction, pnMin);
}
if (GalSoundType == GAL_SOUND_HARDWARE_TYPE_RACKNROLSN76496) {
SN76496Scan(nAction, pnMin);
}
}
// AY8910 Port Handlers
UINT8 CheckmajPortARead(UINT32)
{
return GalSoundLatch;
}
UINT8 BongoDipSwitchRead(UINT32)
{
return GalInput[3] | GalDip[3];
}
UINT8 KonamiSoundLatchRead(UINT32)
{
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
return GalSoundLatch;
}
UINT8 KonamiSoundTimerRead(UINT32)
{
INT32 nActiveCPU = ZetGetActive();
UINT32 Cycles;
if (nActiveCPU == 1) {
Cycles = (ZetTotalCycles() * 8) % (UINT64)(16 * 16 * 2 * 8 * 5 * 2);
} else {
ZetClose();
ZetOpen(1);
Cycles = (ZetTotalCycles() * 8) % (UINT64)(16 * 16 * 2 * 8 * 5 * 2);
ZetClose();
ZetOpen(nActiveCPU);
}
UINT8 HiBit = 0;
if (Cycles >= 16 * 16 * 2 * 8 * 5) {
HiBit = 1;
Cycles -= 16 * 16 * 2 * 8 * 5;
}
return (HiBit << 7) | (BIT(Cycles, 14) << 6) | (BIT(Cycles, 13) << 5) | (BIT(Cycles, 11) << 4) | 0x0e;
}
UINT8 FroggerSoundTimerRead(UINT32)
{
UINT8 KonamiValue = KonamiSoundTimerRead(0);
return BITSWAP08(KonamiValue, 7, 6, 3, 4, 5, 2, 1, 0);
}
UINT8 HunchbksSoundTimerRead(UINT32)
{
INT32 nActiveCPU = ZetGetActive();
UINT32 Cycles;
if (nActiveCPU == 0) {
Cycles = (ZetTotalCycles() * 8) % (UINT64)(16 * 16 * 2 * 8 * 5 * 2);
} else {
ZetOpen(0);
Cycles = (ZetTotalCycles() * 8) % (UINT64)(16 * 16 * 2 * 8 * 5 * 2);
ZetClose();
}
UINT8 HiBit = 0;
if (Cycles >= 16 * 16 * 2 * 8 * 5) {
HiBit = 1;
Cycles -= 16 * 16 * 2 * 8 * 5;
}
return (HiBit << 7) | (BIT(Cycles, 14) << 6) | (BIT(Cycles, 13) << 5) | (BIT(Cycles, 11) << 4) | 0x0e;
}
void KonamiSoundLatchWrite(UINT8 d)
{
GalSoundLatch = d;
}
void KonamiSoundControlWrite(UINT8 d)
{
UINT8 Old = KonamiSoundControl;
KonamiSoundControl = d;
if ((Old & 0x08) && !(d & 0x08)) {
INT32 nActiveCPU = ZetGetActive();
if (nActiveCPU == 1) {
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
} else {
ZetClose();
ZetOpen(1);
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
ZetClose();
ZetOpen(nActiveCPU);
}
}
/* bit 4 is sound disable */
// sound_global_enable(~data & 0x10);
}
void HunchbksSoundControlWrite(UINT8 d)
{
UINT8 Old = KonamiSoundControl;
KonamiSoundControl = d;
HunchbksSoundIrqFire = 0;
if ((Old & 0x08) && !(d & 0x08)) {
HunchbksSoundIrqFire = 1;
}
/* bit 4 is sound disable */
// sound_global_enable(~data & 0x10);
}
void SfxSoundLatch2Write(UINT32, UINT32 d)
{
GalSoundLatch2 = d & 0xff;
}
void SfxSampleControlWrite(UINT32, UINT32 d)
{
UINT8 Old = SfxSampleControl;
d &= 0xff;
SfxSampleControl = d;
if ((Old & 0x01) && !(d & 0x01)) {
INT32 nActiveCPU = ZetGetActive();
if (nActiveCPU == 1) {
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
} else {
ZetClose();
ZetOpen(1);
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
ZetClose();
ZetOpen(nActiveCPU);
}
}
}
// Frogger Sound CPU Memory Map
UINT8 __fastcall FroggerSoundZ80Read(UINT16 a)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 #2 Read => %04X\n"), a);
}
}
return 0xff;
}
void __fastcall FroggerSoundZ80Write(UINT16 a, UINT8 d)
{
if (a >= 0x6000 && a <= 0x6fff) {
// konami_sound_filter_w
return;
}
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 #2 Write => %04X, %02X\n"), a, d);
}
}
}
UINT8 __fastcall FroggerSoundZ80PortRead(UINT16 a)
{
a &= 0xff;
UINT8 Result = 0xff;
if (a & 0x40) Result &= AY8910Read(0);
return Result;
}
void __fastcall FroggerSoundZ80PortWrite(UINT16 a, UINT8 d)
{
a &= 0xff;
if (a & 0x40) {
AY8910Write(0, 1, d);
} else {
if (a & 0x80) {
AY8910Write(0, 0, d);
}
}
}
void FroggerSoundNoEncryptionInit()
{
ZetOpen(1);
ZetSetReadHandler(FroggerSoundZ80Read);
ZetSetWriteHandler(FroggerSoundZ80Write);
ZetSetInHandler(FroggerSoundZ80PortRead);
ZetSetOutHandler(FroggerSoundZ80PortWrite);
ZetMapArea(0x0000, GalZ80Rom2Size - 1, 0, GalZ80Rom2);
ZetMapArea(0x0000, GalZ80Rom2Size - 1, 2, GalZ80Rom2);
ZetMapArea(0x4000, 0x43ff, 0, GalZ80Ram2);
ZetMapArea(0x4000, 0x43ff, 1, GalZ80Ram2);
ZetMapArea(0x4000, 0x43ff, 2, GalZ80Ram2);
ZetMemEnd();
ZetClose();
nGalCyclesTotal[1] = (14318000 / 8) / 60;
}
void FroggerSoundInit()
{
FroggerSoundNoEncryptionInit();
for (UINT32 Offset = 0; Offset < 0x0800; Offset++) GalZ80Rom2[Offset] = BITSWAP08(GalZ80Rom2[Offset], 7, 6, 5, 4, 3, 2, 0, 1);
}
// Konami Sound CPU Memory Map
UINT8 __fastcall KonamiSoundZ80Read(UINT16 a)
{
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 #2 Read => %04X\n"), a);
}
}
return 0xff;
}
void __fastcall KonamiSoundZ80Write(UINT16 a, UINT8 d)
{
if (a >= 0x9000 && a <= 0x9fff) {
// konami_sound_filter_w
return;
}
switch (a) {
default: {
bprintf(PRINT_NORMAL, _T("Z80 #2 Write => %04X, %02X\n"), a, d);
}
}
}
UINT8 __fastcall KonamiSoundZ80PortRead(UINT16 a)
{
a &= 0xff;
UINT8 Result = 0xff;
if (a & 0x20) Result &= AY8910Read(0);
if (a & 0x80) Result &= AY8910Read(1);
return Result;
}
void __fastcall KonamiSoundZ80PortWrite(UINT16 a, UINT8 d)
{
a &= 0xff;
if (a & 0x10) {
AY8910Write(0, 0, d);
} else {
if (a & 0x20) {
AY8910Write(0, 1, d);
}
}
if (a & 0x40) {
AY8910Write(1, 0, d);
} else {
if (a & 0x80) {
AY8910Write(1, 1, d);
}
}
}
void KonamiSoundInit()
{
ZetOpen(1);
ZetSetReadHandler(KonamiSoundZ80Read);
ZetSetWriteHandler(KonamiSoundZ80Write);
ZetSetInHandler(KonamiSoundZ80PortRead);
ZetSetOutHandler(KonamiSoundZ80PortWrite);
ZetMapArea(0x0000, GalZ80Rom2Size - 1, 0, GalZ80Rom2);
ZetMapArea(0x0000, GalZ80Rom2Size - 1, 2, GalZ80Rom2);
ZetMapArea(0x8000, 0x83ff, 0, GalZ80Ram2);
ZetMapArea(0x8000, 0x83ff, 1, GalZ80Ram2);
ZetMapArea(0x8000, 0x83ff, 2, GalZ80Ram2);
ZetMemEnd();
ZetClose();
nGalCyclesTotal[1] = (14318000 / 8) / 60;
}
void HunchbksSoundInit()
{
ZetOpen(0);
ZetSetReadHandler(KonamiSoundZ80Read);
ZetSetWriteHandler(KonamiSoundZ80Write);
ZetSetInHandler(KonamiSoundZ80PortRead);
ZetSetOutHandler(KonamiSoundZ80PortWrite);
ZetMapArea(0x0000, GalZ80Rom1Size - 1, 0, GalZ80Rom1);
ZetMapArea(0x0000, GalZ80Rom1Size - 1, 2, GalZ80Rom1);
ZetMapArea(0x8000, 0x83ff, 0, GalZ80Ram1 + 0x400);
ZetMapArea(0x8000, 0x83ff, 1, GalZ80Ram1 + 0x400);
ZetMapArea(0x8000, 0x83ff, 2, GalZ80Ram1 + 0x400);
ZetMapArea(0x8400, 0x87ff, 0, GalZ80Ram1 + 0x400);
ZetMapArea(0x8400, 0x87ff, 1, GalZ80Ram1 + 0x400);
ZetMapArea(0x8400, 0x87ff, 2, GalZ80Ram1 + 0x400);
ZetMapArea(0x8800, 0x8bff, 0, GalZ80Ram1 + 0x400);
ZetMapArea(0x8800, 0x8bff, 1, GalZ80Ram1 + 0x400);
ZetMapArea(0x8800, 0x8bff, 2, GalZ80Ram1 + 0x400);
ZetMapArea(0x8c00, 0x8fff, 0, GalZ80Ram1 + 0x400);
ZetMapArea(0x8c00, 0x8fff, 1, GalZ80Ram1 + 0x400);
ZetMapArea(0x8c00, 0x8fff, 2, GalZ80Ram1 + 0x400);
ZetMemEnd();
ZetClose();
nGalCyclesTotal[1] = (14318000 / 8) / 60;
}
// Galaxian samples
static void GalRenderShootSample(INT16 *pSoundBuf, INT32 nLength)
{
double Addr = GalShootWavePos;
double Step = (double)GalShootRate / nBurnSoundRate;
for (INT32 i = 0; i < nLength; i += 2) {
INT16 Sample = (INT16)(GalShootWave[(INT32)Addr] * SHOOT_VOLUME);
Sample >>= 4;
pSoundBuf[i + 0] += Sample;
pSoundBuf[i + 1] += Sample;
Addr += Step;
}
GalShootWavePos = Addr;
if (GalShootWavePos > GalShootLength) {
GalShootWavePos = 0;
GalShootEnable = 0;
}
}
static void GalRenderNoiseSample(INT16 *pSoundBuf, INT32 nLength)
{
double Addr = GalNoiseWavePos;
double Step = (double)NOISE_RATE / nBurnSoundRate;
for (INT32 i = 0; i < nLength; i += 2) {
INT16 Sample = (INT16)(GalNoiseWave[(INT32)Addr] * (GalNoiseVolume / 100));
Sample >>= 4;
pSoundBuf[i + 0] += Sample;
pSoundBuf[i + 1] += Sample;
Addr += Step;
}
GalNoiseWavePos = Addr;
if (GalNoiseWavePos > NOISE_LENGTH) {
GalNoiseWavePos = 0;
}
}
static void GalRenderToneWave(INT16 *pSoundBuf, INT32 nLength)
{
INT32 i,j;
INT16 *w = GalToneWave[GalVol];
if (GalPitch != 0xff) {
for (i = 0; i < nLength; i += 2) {
INT32 mix = 0;
for (j = 0; j < STEPS; j++) {
if (GalCountDown >= 256) {
GalCounter = GalCounter + ((double)96000 / nBurnSoundRate);
if (GalCounter > TOOTHSAW_LENGTH) GalCounter = 0;
GalCountDown = GalPitch;
}
GalCountDown++;
mix += w[(INT32)GalCounter];
}
INT16 Sample = mix / STEPS;
Sample >>= 4;
pSoundBuf[i + 0] = Sample;
pSoundBuf[i + 1] = Sample;
}
}
}
static void GalRenderLfoWaveSample(INT32 nLfoWave, INT16 *pSoundBuf, INT32 nLength)
{
double Addr = GalLfoWavePos[nLfoWave];
double Step = (double)(sizeof(GalBackgroundWave) * GalLfoFreq * (100 + 2 * 470) / (100 + 2 * 470)) / nBurnSoundRate;
for (INT32 i = 0; i < nLength; i += 2) {
INT16 Sample = (INT16)(GalBackgroundWave[(INT32)Addr] * (GalLfoVolume[nLfoWave] ? LFO_VOLUME : 0));
Sample >>= 4;
pSoundBuf[i + 0] += Sample;
pSoundBuf[i + 1] += Sample;
Addr += Step;
}
GalLfoWavePos[nLfoWave] = Addr;
if (GalLfoWavePos[nLfoWave] > 32) {
GalLfoWavePos[nLfoWave] = 0;
}
}
void GalRenderSoundSamples(INT16 *pSoundBuf, INT32 nLength)
{
memset(pSoundBuf, 0, nLength * 2 * sizeof(INT16));
GalRenderToneWave(pSoundBuf, nLength);
GalRenderNoiseSample(pSoundBuf, nLength);
if (GalShootEnable) GalRenderShootSample(pSoundBuf, nLength);
GalRenderLfoWaveSample(0, pSoundBuf, nLength);
GalRenderLfoWaveSample(1, pSoundBuf, nLength);
GalRenderLfoWaveSample(2, pSoundBuf, nLength);
}
void GalaxianSoundWrite(UINT32 Offset, UINT8 d)
{
d &= 0x01;
switch (Offset & 0x07) {
case 0x00:
case 0x01:
case 0x02: {
GalLfoVolume[Offset] = d;
return;
}
case 0x03: {
GalNoiseEnable = d & 1;
if (GalNoiseEnable) {
GalNoiseVolume = 100;
GalNoiseWavePos = 0;
}
return;
}
case 0x04: {
return;
}
case 0x05: {
if (d & 1 && !(GalLastPort2 & 1) ) {
GalShootEnable = 1;
GalShootWavePos = 0;
}
GalLastPort2 = d;
return;
}
case 0x06:
case 0x07: {
GalVol = (GalVol & ~(1 << (Offset & 0x01))) | ((d & 1) << (Offset & 0x01));
return;
}
}
}
void GalaxianLfoFreqWrite(UINT32 Offset, UINT8 d)
{
double r0, r1, rx = 100000.0;
if ((d & 0x01) == GalLfoBit[Offset]) return;
GalLfoBit[Offset] = d & 0x01;
r0 = 1.0 / 330000;
r1 = 1.0 / 1e12;
if (GalLfoBit[0]) {
r1 += 1.0 / 1000000;
} else {
r0 += 1.0 / 1000000;
}
if (GalLfoBit[1]) {
r1 += 1.0 / 470000;
} else {
r0 += 1.0 / 470000;
}
if (GalLfoBit[2]) {
r1 += 1.0 / 220000;
} else {
r0 += 1.0 / 220000;
}
if (GalLfoBit[3]) {
r1 += 1.0 / 100000;
} else {
r0 += 1.0 / 100000;
}
r0 = 1.0 / r0;
r1 = 1.0 / r1;
rx = rx + 2000000.0 * r0 / (r0 + r1);
GalLfoFreqFrameVar = (1000000000 / ((MAXFREQ - MINFREQ) * 639 * rx)) * 100;
bprintf(PRINT_NORMAL, _T("Offset %x, rx %f, %f\n"), Offset, (MAXFREQ - MINFREQ) * 639 * rx, GalLfoFreqFrameVar);
}
void GalaxianSoundUpdateTimers()
{
if (GetCurrentFrame() % 3) {
if (!GalNoiseEnable && GalNoiseVolume > 0) {
GalNoiseVolume -= (GalNoiseVolume / 10) + 1;
}
}
if (GalLfoFreq > MINFREQ) {
GalLfoFreq -= GalLfoFreqFrameVar;
} else {
GalLfoFreq = MAXFREQ;
}
}

View File

@ -0,0 +1,241 @@
#include "gal.h"
// This module is not accurate to the arcade hardware - it is ported from my previous Galaxian driver for FBA,
// which was based on an old version of MAME. It is considered "good enough" for the purpose of giving the impression
// of the star layers without being totally accurate
struct Star
{
INT32 x, y, Colour;
};
static struct Star Stars[252];
INT32 GalStarsEnable = 0;
INT32 GalStarsScrollPos = 0;
INT32 GalStarsBlinkState = 0;
INT32 GalBlinkTimerStartFrame = 0;
static double GalBlinkEveryFrames = (0.693 * (100000 + 2.0 + 10000) * 0.00001) * (16000.0 / 132 / 2);
void GalInitStars()
{
INT32 nStars, Generator, x, y;
GalStarsEnable = 0;
GalStarsScrollPos = -1;
GalStarsBlinkState = 0;
nStars = 0;
Generator = 0;
for (y = 255; y >= 0; y--) {
for (x = 511; x >= 0; x--) {
INT32 Bit0;
Bit0 = ((~Generator >> 16) & 0x01) ^ ((Generator >> 4) & 0x01);
Generator = (Generator << 1) | Bit0;
if (((~Generator >> 16) & 0x01) && (Generator & 0xff) == 0xff) {
INT32 Colour;
Colour = (~(Generator >> 8)) & 0x3f;
if (Colour) {
Stars[nStars].x = x;
Stars[nStars].y = y;
Stars[nStars].Colour = Colour;
nStars++;
}
}
}
}
}
static INT32 GalCheckStarsBlinkState()
{
INT32 CurrentFrame = GetCurrentFrame();
if ((CurrentFrame - GalBlinkTimerStartFrame) >= (INT32)GalBlinkEveryFrames) {
GalBlinkTimerStartFrame = CurrentFrame;
return 1;
}
return 0;
}
static inline void GalPlotStar(INT32 x, INT32 y, INT32 Colour)
{
if (y >= 0 && y < nScreenHeight && x >= 0 && x < nScreenWidth) {
pTransDraw[(y * nScreenWidth) + x] = Colour + GAL_PALETTE_STARS_OFFSET;
}
}
void GalaxianRenderStarLayer()
{
GalStarsScrollPos++;
for (INT32 Offs = 0; Offs < 252; Offs++) {
INT32 x, y;
x = ((Stars[Offs].x + GalStarsScrollPos) & 0x01ff) >>1;
y = (Stars[Offs].y + ((GalStarsScrollPos + Stars[Offs].x) >> 9)) & 0xff;
if ((y & 0x01) ^ ((x >> 3) & 0x01)) {
if (GalFlipScreenX) x = 255 - x;
if (GalFlipScreenY) y = 255 - y;
y -= 16;
GalPlotStar(x, y, Stars[Offs].Colour);
}
}
}
void JumpbugRenderStarLayer()
{
if (GalCheckStarsBlinkState()) GalStarsBlinkState++;
for (INT32 Offs = 0; Offs < 252; Offs++) {
INT32 x, y;
x = Stars[Offs].x >> 1;
y = Stars[Offs].y >> 1;
if ((y & 0x01) ^ ((x >> 3) & 0x01)) {
switch (GalStarsBlinkState & 0x03) {
case 0: {
if (!(Stars[Offs].Colour & 0x01)) continue;
break;
}
case 1: {
if (!(Stars[Offs].Colour & 0x04)) continue;
break;
}
case 2: {
if (!(Stars[Offs].y & 0x02)) continue;
break;
}
case 3: {
break;
}
}
x = Stars[Offs].x >> 1;
y = Stars[Offs].y & 0xff;
if (x >= 240) continue;
if (GalFlipScreenX) x = 255 - x;
if (GalFlipScreenY) y = 255 - y;
y -= 16;
GalPlotStar(x, y, Stars[Offs].Colour);
}
}
}
void ScrambleRenderStarLayer()
{
if (GalCheckStarsBlinkState()) GalStarsBlinkState++;
for (INT32 Offs = 0; Offs < 252; Offs++) {
INT32 x, y;
x = Stars[Offs].x >> 1;
y = Stars[Offs].y;
if ((y & 0x01) ^ ((x >> 3) & 0x01)) {
switch (GalStarsBlinkState & 0x03) {
case 0: {
if (!(Stars[Offs].Colour & 0x01)) continue;
break;
}
case 1: {
if (!(Stars[Offs].Colour & 0x04)) continue;
break;
}
case 2: {
if (!(Stars[Offs].y & 0x02)) continue;
break;
}
case 3: {
break;
}
}
if (GalFlipScreenX) x = 255 - x;
if (GalFlipScreenY) y = 255 - y;
y -= 16;
GalPlotStar(x, y, Stars[Offs].Colour);
}
}
}
void MarinerRenderStarLayer()
{
UINT8 *Prom = GalProm + 0x120;
GalStarsScrollPos++;
for (INT32 Offs = 0; Offs < 252; Offs++) {
INT32 x, y;
x = ((Stars[Offs].x + GalStarsScrollPos) & 0x01ff) >>1;
y = (Stars[Offs].y + ((GalStarsScrollPos + Stars[Offs].x) >> 9)) & 0xff;
if ((y & 0x01) ^ ((x >> 3) & 0x01)) {
if (GalFlipScreenX) x = 255 - x;
if (GalFlipScreenY) y = 255 - y;
y -= 16;
if (Prom[((x / 8) + 1) & 0x1f] & 0x04) {
GalPlotStar(x, y, Stars[Offs].Colour);
}
}
}
}
void RescueRenderStarLayer()
{
if (GalCheckStarsBlinkState()) GalStarsBlinkState++;
for (INT32 Offs = 0; Offs < 252; Offs++) {
INT32 x, y;
x = Stars[Offs].x >> 1;
y = Stars[Offs].y;
if (x < 128 && ((y & 0x01) ^ ((x >> 3) & 0x01))) {
switch (GalStarsBlinkState & 0x03) {
case 0: {
if (!(Stars[Offs].Colour & 0x01)) continue;
break;
}
case 1: {
if (!(Stars[Offs].Colour & 0x04)) continue;
break;
}
case 2: {
if (!(Stars[Offs].y & 0x02)) continue;
break;
}
case 3: {
break;
}
}
if (GalFlipScreenX) x = 255 - x;
if (GalFlipScreenY) y = 255 - y;
y -= 16;
GalPlotStar(x, y, Stars[Offs].Colour);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,657 @@
/*****************************************************************************
Irem Custom V35+ CPU
-- has internal 256 byte lookup table, handled in realtime. Bomberman
World runs encrypted code from RAM, Risky Challenge expects to be able
to run code in emulation (non-encrypted) mode for some subroutines..
Hasamu Nanao 08J27261A1 011 9102KK700
Gunforce Nanao 08J27261A1 011 9106KK701
Ken-Go Nanao 08J27261A1 011 9102KK701
Bomberman Nanao 08J27261A1 012 9123KK200
Atomic Punk Nanao 08J27291A1 012 9128KK440
Blade Master / Cross Blades! Nanao 08J27291A1 012 9123KK740
Quiz F-1 1,2 Finish Nanao 08J27291A4 014 9147KK700
Gunforce 2 Nanao 08J27291A4 014 9247KK700
Lethal Thunder Nanao 08J27291A4 014 9147KK700
Bomberman World / New Atomic Punk Nanao 08J27291A5 015 9219KK700
Undercover Cops Nanao 08J27291A5 015 9219KK700
Gun Hohki Nanao 08J27291A6 016 9217NK700
Skins Game Nanao 08J27291A7 017
Hook Nanao 08J27291A8 018 9237NK700
R-Type Leo Irem D8000021A1 019 9242NK700
Fire Barrel Irem D8000010A1 019 9243NK700
In The Hunt Irem D8000011A1 020
Risky Challenge/Gussun Oyoyo Irem D8000019A1 022 9331NK700
Match It II/Shisensho II Irem D8000020A1 023 9320NK700
World PK Soccer/Kick for the Goal Irem D8000021A1 024 9335NK701
Ninja Baseball Batman Irem D8000021A1 024 9335NK700
Perfect Soldiers Irem D8000022A1
Dream Soccer '94 Irem D8000023A1 026
Please let me know if you can fill in any of the blanks.
Emulation by Bryan McPhail, mish@tendril.co.uk, thanks to Chris Hardy too!
*****************************************************************************/
#include "burnint.h"
#include "irem_cpu.h"
// CAVEATS:
// 0x80 and 0x82 pre- opcodes can easily be confused. They perform exactly the same
// function when operating on memory, but when working with registers one affects
// byte registers and the other word registers. Gunforce, Blade Master and
// Lethal Thunder had this error.
//double check 0x00 0x22 0x28 0x4a 0x34 in these tables
#define xxxx 0x90/* Unknown */
const UINT8 gunforce_decryption_table[256] = {
0xff,xxxx,xxxx,0x2c,xxxx,xxxx,0x43,0x88, xxxx,0x13,0x0a,0xbd,0xba,0x60,0xea,xxxx, /* 00 */
xxxx,xxxx,0xf2,0x29,0xb3,0x22,xxxx,0x0c, 0xa9,0x5f,0x9d,0x07,xxxx,xxxx,0x0b,0xbb, /* 10 */
0x8a,xxxx,xxxx,xxxx,0x3a,0x3c,0x5a,0x38, 0x99,xxxx,0xf8,0x89,xxxx,0x91,xxxx,0x55, /* 20 */
0xac,0x40,0x73,xxxx,0x59,xxxx,0xfc,xxxx, 0x50,0xfa,xxxx,0x25,xxxx,0x34,0x47,0xb7, /* 30 */
xxxx,xxxx,xxxx,0x49,xxxx,0x0f,0x8b,0x05, 0xc3,0xa5,0xbf,0x83,0x86,0xc5,xxxx,xxxx, /* 40 */
0x28,0x77,0x24,0xb4,xxxx,0x92,xxxx,0x3b, 0x5e,0xb6,0x80,0x0d,0x2e,0xab,0xe7,xxxx, /* 50 */
0x48,xxxx,0xad,0xc0,xxxx,0x1b,0xc6,0xa3, 0x04,xxxx,xxxx,xxxx,0x16,0xb0,0x7d,0x98, /* 60 */
0x87,0x46,0x8c,xxxx,xxxx,0xfe,xxxx,0xcf, xxxx,0x68,0x84,xxxx,0xd2,xxxx,0x18,0x51, /* 70 */
0x76,0xa4,0x36,0x52,0xfb,xxxx,0xb9,xxxx, xxxx,0xb1,0x1c,0x21,0xe6,0xb5,0x17,0x27, /* 80 */
0x3d,0x45,0xbe,0xae,xxxx,0x4a,0x0e,0xe5, xxxx,0x58,0x1f,0x61,0xf3,0x02,xxxx,0xe8, /* 90 */
xxxx,xxxx,xxxx,0xf7,0x56,0x96,xxxx,0xbc, 0x4f,xxxx,xxxx,0x79,0xd0,xxxx,0x2a,0x12, /* A0 */
0x4e,0xb8,xxxx,0x41,xxxx,0x90,0xd3,xxxx, 0x2d,0x33,0xf6,xxxx,xxxx,0x14,xxxx,0x32, /* B0 */
0x5d,0xa8,0x53,0x26,0x2b,0x20,0x81,0x75, 0x7f,0x3e,xxxx,xxxx,0x00,0x93,xxxx,0xb2, /* C0 */
0x57,xxxx,0xa0,xxxx,0x39,xxxx,xxxx,0x72, xxxx,0x01,0x42,0x74,0x9c,0x1e,xxxx,0x5b, /* D0 */
xxxx,0xf9,xxxx,0x2f,0x85,xxxx,0xeb,0xa2, xxxx,0xe2,0x11,xxxx,0x4b,0x7e,xxxx,0x78, /* E0 */
xxxx,xxxx,0x09,0xa1,0x03,xxxx,0x23,0xc1, 0x8e,0xe9,0xd1,0x7c,xxxx,xxxx,0xc7,0x06, /* F0 */
};
// 0x13 (0x29) guess
// 0x18 (0xa9) guess
// 0x50 (0x28) guess
// 0x63 (0xc0) guess
// 0x7e (0x18) opcode is right but arguments could be swapped
// 0xcc (0x00) guess
// 0xea (0x11) guess
// 0x51 (0x77) guess (kengo)
// 0x96 (0x0e) complete guess (kengo), maybe wrong but I don't see what it could be
//double check 22 (boot bomb at 2a000)
//47a7 (46e0 in boot) - hmm
// 0x00 is NOT 0x20 (no context in bomberman)
const UINT8 bomberman_decryption_table[256] = {
xxxx,xxxx,0x79,xxxx,0x9d,0x48,xxxx,xxxx, xxxx,xxxx,0x2e,xxxx,xxxx,0xa5,0x72,xxxx, /* 00 */
0x46,0x5b,0xb1,0x3a,0xc3,xxxx,0x35,xxxx, xxxx,0x23,xxxx,0x99,xxxx,0x05,xxxx,0x3c, /* 10 */
0x3b,0x76,0x11,xxxx,xxxx,0x4b,xxxx,0x92, xxxx,0x32,0x5d,xxxx,0xf7,0x5a,0x9c,xxxx, /* 20 */
0x26,0x40,0x89,xxxx,xxxx,xxxx,xxxx,0x57, xxxx,xxxx,xxxx,xxxx,xxxx,0xba,0x53,0xbb, /* 30 */
0x42,0x59,0x2f,xxxx,0x77,xxxx,xxxx,0x4f, 0xbf,0x4a,0xcb,0x86,0x62,0x7d,xxxx,0xb8, /* 40 */
xxxx,0x34,xxxx,0x5f,xxxx,0x7f,0xf8,0x80, 0xa0,0x84,0x12,0x52,xxxx,xxxx,xxxx,0x47, /* 50 */
xxxx,0x2b,0x88,0xf9,xxxx,0xa3,0x83,xxxx, 0x75,0x87,xxxx,0xab,0xeb,xxxx,0xfe,xxxx, /* 60 */
xxxx,0xaf,0xd0,0x2c,0xd1,0xe6,0x90,0x43, 0xa2,0xe7,0x85,0xe2,0x49,0x22,0x29,xxxx, /* 70 */
0x7c,xxxx,xxxx,0x9a,xxxx,xxxx,0xb9,xxxx, 0x14,0xcf,0x33,0x02,xxxx,xxxx,xxxx,0x73, /* 80 */
xxxx,0xc5,xxxx,xxxx,xxxx,0xf3,0xf6,0x24, xxxx,0x56,0xd3,xxxx,0x09,0x01,xxxx,xxxx, /* 90 */
0x03,0x2d,0x1b,xxxx,0xf5,0xbe,xxxx,xxxx, 0xfb,0x8e,0x21,0x8d,0x0b,xxxx,xxxx,0xb2, /* A0 */
0xfc,0xfa,0xc6,xxxx,0xe8,0xd2,xxxx,0x08, 0x0a,0xa8,0x78,0xff,xxxx,0xb5,xxxx,xxxx, /* B0 */
0xc7,0x06,0x18,xxxx,xxxx,0x1e,0x7e,0xb0, 0x0e,0x0f,xxxx,xxxx,0x0c,0xaa,0x55,xxxx, /* C0 */
xxxx,0x74,0x3d,xxxx,xxxx,0x38,0x27,0x50, xxxx,0xb6,0x5e,0x8b,0x07,0xe5,0x39,0xea, /* D0 */
0xbd,xxxx,0x81,0xb7,xxxx,0x8a,0x0d,xxxx, 0x58,0xa1,0xa9,0x36,xxxx,0xc4,xxxx,0x8f, /* E0 */
0x8c,0x1f,0x51,0x04,0xf2,xxxx,0xb3,0xb4, 0xe9,0x2a,xxxx,xxxx,xxxx,0x25,xxxx,0xbc, /* F0 */
};
// 49 -> 4a (verified in a bombrman PCB)
const UINT8 lethalth_decryption_table[256] = {
0x7f,0x26,0x5d,xxxx,0xba,xxxx,0x1e,0x5e, 0xb8,xxxx,0xbc,0xe8,0x01,xxxx,0x4a,0x25, /* 00 */
// ssss !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
xxxx,0xbd,xxxx,0x22,0x10,xxxx,0x02,0x57, 0x70,xxxx,0x7e,xxxx,0xe7,0x52,xxxx,0xa9, /* 10 */
// !!!! !!!! !!!! ???? !!!! !!!! gggg
xxxx,xxxx,0xc6,0x06,0xa0,0xfe,0xcf,0x8e, 0x43,0x8f,0x2d,xxxx,0xd4,0x85,0x75,0xa2, /* 20 */
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
0x3d,xxxx,xxxx,0x38,0x7c,0x89,0xd1,0x80, 0x3b,0x72,0x07,xxxx,0x42,0x37,0x0a,0x18, /* 30 */
// gggg !!!! ???? !!!! !!!! !!!! !!!! !!!! !!!! ssss !!!!
0x88,0xb4,0x98,0x8b,0xb9,0x9c,0xad,0x0e, 0x2b,xxxx,0xbf,xxxx,0x55,xxxx,0x56,0xb0, /* 40 */
// !!!! pppp !!!! !!!! !!!! !!!! gggg !!!! !!!! !!!! !!!!
0x93,0x91,xxxx,0xeb,xxxx,0x50,0x41,0x29, 0x47,xxxx,xxxx,0x60,xxxx,0xab,xxxx,xxxx, /* 50 */
// pppp !!!! !!!! !!!! !!!! !!!! !!!! !!!!
0xc3,0xe2,0xd0,0xb2,0x11,0x79,xxxx,0x08, xxxx,0xfb,xxxx,0x2c,0x23,xxxx,0x28,0x0d, /* 60 */
// !!!! !!!! !!!! !!!! ???? !!!! !!!!
xxxx,xxxx,xxxx,0x83,0x3c,xxxx,0x1b,0x34, 0x5b,xxxx,0x40,xxxx,xxxx,0x04,0xfc,0xcd, /* 70 */
// !!!! !!!! !!!! !!!! !!!! ssss
0xb1,0xf3,0x8a,xxxx,xxxx,0x87,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,0xbe,0x84,0x1f,0xe6, /* 80 */
// !!!! !!!! !!!! !!!! !!!!
0xff,xxxx,0x12,xxxx,0xb5,0x36,xxxx,0xb3, xxxx,xxxx,xxxx,0xd2,0x4e,xxxx,xxxx,xxxx, /* 90 */
// !!!! !!!! !!!!
0xa5,xxxx,xxxx,0xc7,xxxx,0x27,0x0b,xxxx, 0x20,xxxx,xxxx,xxxx,xxxx,xxxx,0x61,0x7d, /* A0 */
// !!!! !!!! !!!! !!!! ????
xxxx,xxxx,0x86,0x0f,xxxx,0xb7,xxxx,0x4f, xxxx,xxxx,0xc0,0xfd,xxxx,0x39,xxxx,0x77, /* B0 */
// !!!! !!!! !!!! !!!! !!!!
0x05,0x3a,xxxx,0x48,0x92,0x76,0x3e,0x03, xxxx,0xf8,xxxx,0x59,0xa8,0x5f,0xf9,0xbb, /* C0 */
// !!!! !!!! pppp !!!! !!!! !!!! !!!! !!!!
0x81,0xfa,0x9d,0xe9,0x2e,0xa1,0xc1,0x33, xxxx,0x78,xxxx,0x0c,xxxx,0x24,0xaa,0xac, /* D0 */
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! ???? !!!! !!!!
xxxx,0xb6,xxxx,0xea,xxxx,0x73,0xe5,0x58, 0x00,0xf7,xxxx,0x74,xxxx,0x76,xxxx,0xa3, /* E0 */
// !!!! gggg !!!! !!!! !!!! !!!! ???? !!!!
xxxx,0x5a,0xf6,0x32,0x46,0x2a,xxxx,xxxx, 0x53,0x4b,0x90,0x0d,0x51,0x68,0x99,0x13, /* F0 */
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! ???? !!!! !!!!
};
/*
missing opcode:
"!!!!" -> checked against gussun
"gggg" -> very probably
"pppp" -> probably
"ssss" -> sure
"????" -> missing
1a -> (78,7c,7e) ->
34 -> (78,7c,7e) -> 78
65 -> (79,
af -> (79,7d) (strange 71) ->
d9 -> (11e07 from 11de6) (70,78 -> to handle a01ce=000-7d0 -> 0x78
ed -> (p76,78,7c,7e) ->
fb ->
probably:
42 -> 0x98 (083a3)
50 -> 0x93 (083a7)
c5 -> (18d56 - from 1844f) (71,73,76,79,7a,7d,7e) -> to handle level number (a008d=00-0f) -> 0x76
very probably:
48 -> 0x2b
e5 -> 0x73
sure:
00 -> 0x7f
3d -> 0x37
7f -> 0xcd (little machine in the game - 16058)
*/
// 0x2c (0xd4) complete guess
// 0x2d (0x85) complete guess
// 0xc4 (0x92) guess
// 0xbb (0xfd) guess
// 0x46 (0xad) guess - risky challenge use same code
// 0x6e (0x28) guess
// 0x76 (0x1b) guess
// 0x8d (0x84) guess
// 0xa6 (0x0b) guess - risky challenge use same code
// 0xa8 (0x20) guess
// 0xbd (0x39) guess - risky challenge use same code
// 0xc3 (0x48) guess
// and our collection of conditional branches:
// 0xbf (0x7d) >= (monitor test)
// 0x34 (0x7c) < or <= (seems more like <) | these two are used toghether
// 0xaf (0x7f) > or >= (seems more like >) |
// 0xed (0x7e) <= or < (seems more like <=)
// 0x00 (0x7f) > ? | these two are used toghether
// 0x1a (0x7c) < ? | (rowscroll on pink screen on startup)
// 0xc5 (0x7a) completely in the dark (game start after car seelction)
const UINT8 dynablaster_decryption_table[256] = {
0x1f,0x51,0x84,xxxx,0x3d,0x09,0x0d,xxxx, xxxx,0x57,xxxx,xxxx,xxxx,0x32,0x11,xxxx, /* 00 */
xxxx,0x9c,xxxx,xxxx,0x4b,xxxx,xxxx,0x03, xxxx,xxxx,xxxx,0x89,0xb0,xxxx,xxxx,xxxx, /* 10 */
xxxx,0xbb,0x18,0xbe,0x53,0x21,0x55,0x7c, xxxx,xxxx,0x47,0x58,0xf6,xxxx,xxxx,0xb2, /* 20 */
0x06,xxxx,0x2b,xxxx,0x2f,0x0b,0xfc, 0x91 , xxxx,xxxx,0xfa,0x81,0x83,0x40,0x38,xxxx, /* 30 */
xxxx,xxxx,0x49,0x85,0xd1,0xf5,0x07,0xe2, 0x5e,0x1e,xxxx,0x04,xxxx,xxxx,xxxx,0xb1, /* 40 */
0xc7,xxxx,0x96, 0xf2 /*0xaf*/, 0xb6,0xd2,0xc3,xxxx, 0x87,0xba,0xcb,0x88,xxxx,0xb9,0xd0,0xb5, /* 50 */
0x9a,0x80,0xa2,0x72,xxxx,0xb4,xxxx,0xaa, 0x26,0x7d,0x52,0x33,0x2e,0xbc,0x08,0x79, /* 60 */
0x48,xxxx,0x76,0x36,0x02,xxxx,0x5b,0x12, 0x8b,0xe7,xxxx,xxxx,xxxx,0xab,xxxx,0x4f, /* 70 */
xxxx,xxxx,0xa8,0xe5,0x39,0x0e,0xa9,xxxx, xxxx,0x14,xxxx,0xff, 0x7f/*0x75*/ ,xxxx,xxxx,0x27, /* 80 */
xxxx,0x01,xxxx,xxxx,0xe6,0x8a,0xd3,xxxx, xxxx,0x8e,0x56,0xa5,0x92,xxxx,xxxx,0xf9, /* 90 */
0x22,xxxx,0x5f,xxxx,xxxx,0xa1,xxxx,0x74, 0xb8,xxxx,0x46,0x05,0xeb,0xcf,0xbf,0x5d, /* a0 */
0x24,xxxx,0x9d,xxxx,xxxx,xxxx,xxxx,xxxx, 0x59,0x8d,0x3c,0xf8,0xc5,xxxx,0xf3,0x4e, /* b0 */
xxxx,xxxx,0x50,0xc6,0xe9,0xfe,0x0a,xxxx, 0x99,0x86,xxxx,xxxx,0xaf ,0x8c/*0x8e*/,0x42,0xf7, /* c0 */
xxxx,0x41,xxxx,0xa3,xxxx,0x3a,0x2a,0x43, xxxx,0xb3,0xe8,xxxx,0xc4,0x35,0x78,0x25, /* d0 */
0x75,xxxx,0xb7,xxxx,0x23,xxxx, xxxx/*0xe2*/,0x8f, xxxx,xxxx,0x2c,xxxx,0x77,0x7e,xxxx,0x0f, /* e0 */
0x0c,0xa0,0xbd,xxxx,xxxx,0x2d,0x29,0xea, xxxx,0x3b,0x73,xxxx,0xfb,0x20,xxxx,0x5a /* f0 */
};
//double check 0x00/0xa0 AND.
//double check 0x8c (0x7d jg)
//double check 0xfd (0x20 AND) - 9d2 in code
//double check 0xd1 (0x41 INC cw) used in uccops and dynablaster (LOOKS GOOD)
//AND fd (0x20)
//0x37 (91) guess from dynablaster title screen
// BM - 0x61 NOT 82, but instead 0x80 verified in both Atomic Punk and UCCops
// 0x22 is 0x18 (SBB) verified from Gunforce
// 0x5b seems confirmed (previous commented out as 0x36)
// NS I expected 0x32 to be 0x1b (SBB) like in gunforce, but startup tests fail in bbmanw.
// therefore it seems to be 0x2b (SUB)
// NS010718 0xa0 was 0x00 (ADDB), verified to be 0x22 (ANDB)
const UINT8 mysticri_decryption_table[256] = {
xxxx,0x57,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, 0xbf,0x43,xxxx,xxxx,xxxx,xxxx,0xfc,xxxx, /* 00 */
xxxx,xxxx,xxxx,xxxx,xxxx,0x52,0xa3,0x26, xxxx,0xc7,xxxx,0x0f,xxxx,0x0c,xxxx,xxxx, /* 10 */
xxxx,xxxx,0xff,xxxx,xxxx,0x02,xxxx,xxxx, 0x2e,xxxx,0x5f,xxxx,xxxx,xxxx,0x73,0x50, /* 20 */
0xb2,0x3a,xxxx,xxxx,0xbb,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 30 */
xxxx,xxxx,0x8e,0x3c,0x42,xxxx,xxxx,0xb9, xxxx,xxxx,0x2a,xxxx,0x47,0xa0,0x2b,0x03, /* 40 */
0xb5,0x1f,xxxx,0xaa,xxxx,0xfb,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,0x38,xxxx,xxxx,xxxx, /* 50 */
0x2c,xxxx,xxxx,0xc6,xxxx,xxxx,0xb1,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0xa2,xxxx, /* 60 */
0xe9,0xe8,xxxx,xxxx,0x86,xxxx,0x8b,xxxx, xxxx,xxxx,xxxx,xxxx,0x5b,0x72,xxxx,xxxx, /* 70 */
xxxx,xxxx,0x5d,0x0a,xxxx,xxxx,0x89,xxxx, 0xb0,0x88,xxxx,xxxx,xxxx,0x87,0x75,0xbd, /* 80 */
xxxx,0x51,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,0x5a,0x58,xxxx,xxxx,0x56, /* 90 */
xxxx,0x8a,xxxx,0x55,xxxx,xxxx,xxxx,0xb4, 0x08,xxxx,0xf6,xxxx,xxxx,0x9d,xxxx,0xbc, /* A0 */
0x0b,xxxx,xxxx,0x5e,xxxx,xxxx,xxxx,0x22, 0x36,xxxx,0x1e,xxxx,0xb6,0xba,0x23,xxxx, /* B0 */
0x20,xxxx,xxxx,xxxx,0x59,0x53,xxxx,0x04, 0x81,xxxx,xxxx,0xf3,xxxx,xxxx,0x3b,0x06, /* C0 */
xxxx,0x79,0x83,0x9c,xxxx,0x18,0x80,xxxx, 0xc3,xxxx,xxxx,xxxx,0x32,xxxx,0xcf,xxxx, /* D0 */
0xeb,xxxx,xxxx,0x33,xxxx,0xfa,xxxx,xxxx, 0xd2,xxxx,0x24,xxxx,0x74,0x41,0xb8,xxxx, /* E0 */
xxxx,xxxx,0xd0,0x07,xxxx,xxxx,xxxx,xxxx, xxxx,0x46,xxxx,0xea,0xfe,0x78,xxxx,xxxx, /* F0 */
};
// 0xd5 (0x18) opcode is right but arguments could be swapped
// 0x4e (0x2b) not sure, could be 0x1b
const UINT8 majtitl2_decryption_table[256] = {
0x87,xxxx,0x78,0xaa,xxxx,xxxx,xxxx,0x2c, 0x32,0x0a,0x0f,xxxx,0x5e,xxxx,0xc6,0x8a, /* 00 */
0x33,xxxx,xxxx,xxxx,xxxx,0xea,xxxx,0x72, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x24,0x55, /* 10 */
xxxx,xxxx,xxxx,0x89,0xfb,xxxx,0x59,0x02, xxxx,xxxx,0x5d,xxxx,xxxx,xxxx,0x36,xxxx, /* 20 */
xxxx,0x06,0x79,xxxx,xxxx,0x1e,0x07,xxxx, xxxx,xxxx,0x83,xxxx,xxxx,xxxx,xxxx,xxxx, /* 30 */
0x9d,xxxx,xxxx,0x74,xxxx,xxxx,xxxx,0x0c, 0x58,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 40 */
0x3c,xxxx,0x03,xxxx,xxxx,0xfa,0x43,xxxx, 0xbf,xxxx,xxxx,0x75,xxxx,0x88,xxxx,0x80, /* 50 */
xxxx,0xa3,xxxx,0xfe,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,0x3a,xxxx,xxxx,xxxx, /* 60 */
0x2b,xxxx,xxxx,xxxx,xxxx,0xe9,0x5f,xxxx, 0x46,xxxx,0x41,xxxx,0x18,0xb8,xxxx,xxxx, /* 70 */
0xb4,0x5a,0xb1,xxxx,xxxx,0x50,0xe8,0x20, xxxx,0xb2,xxxx,xxxx,xxxx,xxxx,xxxx,0x51, /* 80 */
xxxx,xxxx,xxxx,0x56,xxxx,xxxx,xxxx,xxxx, xxxx,0xcf,xxxx,xxxx,xxxx,0xc3,xxxx,xxxx, /* 90 */
xxxx,xxxx,xxxx,xxxx,0x0b,xxxx,xxxx,0xb5, 0x57,xxxx,xxxx,0xc7,0x3b,xxxx,xxxx,xxxx, /* A0 */
xxxx,xxxx,xxxx,xxxx,0xb6,xxxx,0xeb,xxxx, 0x38,xxxx,0xa0,0x08,xxxx,0x86,0xb0,xxxx, /* B0 */
0x42,0x1f,0x73,xxxx,0xf6,xxxx,xxxx,xxxx, 0x53,xxxx,0x52,xxxx,0x04,0xbd,xxxx,xxxx, /* C0 */
0x26,0xff,0x2e,xxxx,0x81,xxxx,0x47,xxxx, xxxx,xxxx,xxxx,0xd0,0x22,xxxx,xxxx,0xb9, /* D0 */
0x23,xxxx,0xf3,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,0xd2,0x8b,0xba,xxxx,xxxx,xxxx,0x5b, /* E0 */
xxxx,xxxx,0x9c,xxxx,xxxx,xxxx,xxxx,0xfc, 0xbc,0xa2,0x2a,xxxx,xxxx,0x8e,0xbb,xxxx, /* F0 */
};
// 0x7c (0x18) opcode is right but arguments could be swapped
// 0x70 (0x2b) not sure, could be 0x1b
const UINT8 hook_decryption_table[256] = {
0xb6,0x20,0x22,xxxx,0x0f,0x57,0x59,0xc6, 0xeb,xxxx,0xb0,0xbb,0x3b,xxxx,xxxx,xxxx, /* 00 */
0x36,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,0xfe,xxxx,xxxx,xxxx,xxxx,xxxx,0xa0, /* 10 */
0x2e,xxxx,0x0b,xxxx,xxxx,0x58,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,0x80,xxxx,xxxx, /* 20 */
0x33,xxxx,xxxx,0xbf,0x55,xxxx,xxxx,xxxx, 0x53,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 30 */
0x47,0x74,xxxx,0xb1,0xb4,xxxx,xxxx,0x88, xxxx,xxxx,0x38,0xcf,xxxx,0x8e,xxxx,xxxx, /* 40 */
xxxx,0xc7,xxxx,0x32,xxxx,0x52,0x3c,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x83,0x72, /* 50 */
xxxx,0x73,xxxx,0x5a,xxxx,0x43,xxxx,xxxx, xxxx,xxxx,0x41,0xe9,0xbd,xxxx,0xb2,0xd2, /* 60 */
xxxx,0xaa,0xa2,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,0x26,xxxx,xxxx,0x8a,xxxx, /* 70 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x18, xxxx,0x9d,xxxx,xxxx,xxxx,0x5d,xxxx,0x46, /* 80 */
xxxx,xxxx,xxxx,0xf6,0xc3,0xa3,0x1e,0x07, 0x5f,0x81,xxxx,0x0c,xxxx,0xb8,xxxx,0x75, /* 90 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x79, /* A0 */
xxxx,0x5e,xxxx,xxxx,0x06,xxxx,0xff,xxxx, 0x5b,0x24,xxxx,0x2b,xxxx,xxxx,xxxx,0x02, /* B0 */
0x86,xxxx,xxxx,0xfb,xxxx,xxxx,0x50,0xfc, 0x08,xxxx,xxxx,xxxx,0x03,xxxx,0xb9,xxxx, /* C0 */
xxxx,0xbc,0xe8,0x1f,0xfa,0x42,xxxx,xxxx, 0x89,xxxx,0x23,0x87,xxxx,0x2a,xxxx,xxxx, /* D0 */
0x8b,xxxx,0xf3,0xea,0x04,0x2c,0xb5,xxxx, 0x0a,xxxx,0x51,xxxx,xxxx,0x3a,xxxx,0x9c, /* E0 */
xxxx,xxxx,0x78,xxxx,0xba,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,0xd0,0x56,xxxx,xxxx, /* F0 */
};
// 0x87 (0x18) opcode is right but arguments could be swapped
// 0xbb (0x2b) not sure, could be 0x1b
const UINT8 rtypeleo_decryption_table[256] = {
0x5d,xxxx,0xc6,xxxx,xxxx,xxxx,0x2a,0x3a,xxxx,xxxx,xxxx,0x86,xxxx,0x22,xxxx,0xf3, /* 00 */
xxxx,xxxx,xxxx,xxxx,xxxx,0x38,0xf7,0x42,0x04,xxxx,xxxx,0x1f,0x4b,xxxx,xxxx,0x58, /* 10 */
0x57,0x2e,xxxx,xxxx,0x53,xxxx,0xb9,xxxx,xxxx,xxxx,xxxx,xxxx,0x20,0x55,xxxx,0x3d, /* 20 */
0xa0,xxxx,xxxx,0x0c,0x03,xxxx,0x83,xxxx,xxxx,xxxx,0x8a,0x00,xxxx,0xaa,xxxx,xxxx, /* 30 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x41,0x0a,0x26,0x8b,0x56,0x5e,xxxx, /* 40 */
xxxx,0x74,xxxx,xxxx,xxxx,xxxx,0x06,xxxx,xxxx,0x89,0x5b,0xc7,0x43,xxxx,xxxx,xxxx, /* 50 */
xxxx,0xb6,xxxx,0x3b,xxxx,xxxx,xxxx,xxxx,xxxx,0x36,0xea,0x80,xxxx,xxxx,xxxx,0x5f, /* 60 */
xxxx,0x0f,xxxx,xxxx,xxxx,0x46,xxxx,xxxx,0x3c,0x8e,xxxx,0xa3,0x87,xxxx,xxxx,xxxx, /* 70 */
0x2b,0xfb,0x47,0x0b,xxxx,0xfc,0x02,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x72,0x2c, /* 80 */
0x33,xxxx,xxxx,xxxx,xxxx,xxxx,0x9d,0xbd,xxxx,0xb2,xxxx,0x78,0x75,0xb8,xxxx,xxxx, /* 90 */
xxxx,xxxx,xxxx,xxxx,0xcf,0x5a,0x88,xxxx,xxxx,xxxx,0xc3,xxxx,0xeb,0xfa,xxxx,0x32, /* A0 */
xxxx,xxxx,xxxx,0x52,0xb4,xxxx,xxxx,xxxx,xxxx,0xbc,xxxx,xxxx,xxxx,0xb1,0x59,0x50, /* B0 */
xxxx,xxxx,0xb5,xxxx,0x08,0xa2,0xbf,0xbb,0x1e,0x9c,xxxx,0x73,xxxx,0xd0,xxxx,xxxx, /* C0 */
xxxx,xxxx,xxxx,xxxx,0x81,xxxx,0x79,xxxx,xxxx,0x24,0x23,xxxx,xxxx,0xb0,0x07,0xff, /* D0 */
xxxx,0xba,0xf6,0x51,xxxx,xxxx,xxxx,0xfe,xxxx,0x92,xxxx,xxxx,xxxx,xxxx,0xe9,xxxx, /* E0 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0xe8,0xd2,xxxx,0x18,xxxx,xxxx,xxxx,0xd1,xxxx,xxxx, /* F0 */
// ^^^^
};
// 0xf9 (0x18) opcode is right but arguments could be swapped
// 0x80 (0x2b) not sure, could be 0x1b
// 0x16 (0x01) guess (wrong?)
// fixed 0x16 = 0xf7 mapping
// 3d = correct
const UINT8 inthunt_decryption_table[256] = {
0x1f,xxxx,0xbb,0x50,xxxx,0x58,0x42,0x57, xxxx,xxxx,0xe9,xxxx,xxxx,xxxx,xxxx,0x0b, /* 00 */
xxxx,xxxx,0x9d,0x9c,xxxx,xxxx,0x1e,xxxx, xxxx,0xb4,0x5b,xxxx,xxxx,xxxx,xxxx,xxxx, /* 10 */
xxxx,xxxx,0x78,0xc7,xxxx,xxxx,0x83,xxxx, xxxx,0x0c,0xb0,0x04,xxxx,xxxx,xxxx,xxxx, /* 20 */
xxxx,xxxx,xxxx,xxxx,0x3b,0xc3,0xb5,0x47, xxxx,xxxx,xxxx,xxxx,0x59,xxxx,xxxx,xxxx, /* 30 */
xxxx,xxxx,xxxx,0x38,xxxx,xxxx,xxxx,xxxx, 0x5f,0xa3,0xfa,xxxx,0xe8,0x36,0x75,xxxx, /* 40 */
0x88,0x33,xxxx,xxxx,xxxx,xxxx,0x43,xxxx, xxxx,0x87,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 50 */
xxxx,xxxx,xxxx,xxxx,0x8e,0xf3,0x56,xxxx, xxxx,xxxx,xxxx,0x26,0xff,xxxx,xxxx,xxxx, /* 60 */
xxxx,xxxx,xxxx,0x2a,xxxx,0x8a,xxxx,0x18, xxxx,xxxx,0x03,0x89,0x24,xxxx,xxxx,xxxx, /* 70 */
0x0a,xxxx,0xeb,xxxx,0x86,xxxx,xxxx,xxxx, 0x79,0x3a,xxxx,xxxx,xxxx,xxxx,0xa0,xxxx, /* 80 */
0xea,xxxx,xxxx,xxxx,xxxx,xxxx,0x2c,xxxx, 0xc6,xxxx,xxxx,0x46,xxxx,0xaa,0xb6,0x5e, /* 90 */
xxxx,xxxx,xxxx,xxxx,0x8b,xxxx,xxxx,xxxx, xxxx,xxxx,0xba,xxxx,0xb9,0x53,0xa2,xxxx, /* A0 */
xxxx,0x07,xxxx,xxxx,xxxx,0x3c,0x32,xxxx, 0x2b,xxxx,0xb8,xxxx,xxxx,xxxx,xxxx,xxxx, /* B0 */
0xbd,xxxx,xxxx,xxxx,xxxx,0x81,xxxx,0xd0, 0x08,xxxx,0x55,0x06,0xcf,xxxx,xxxx,0xfc, /* C0 */
xxxx,xxxx,xxxx,0xb1,0xbf,xxxx,xxxx,0x51, 0x52,xxxx,0x5d,xxxx,0x5a,xxxx,0xb2,xxxx, /* D0 */
0xfe,xxxx,xxxx,0x22,0x20,0x72,0xf6,0x80, 0x02,0x2e,xxxx,0x74,0x0f,xxxx,xxxx,xxxx, /* E0 */
xxxx,xxxx,xxxx,xxxx,0xbc,0x41,xxxx,0xfb, 0x73,xxxx,xxxx,xxxx,0x23,0xd2,xxxx,xxxx, /* F0 */
};
// 0x77 (0x18) opcode is right but arguments could be swapped
// 0xb8 (0x2b) not sure, could be 0x1b
const UINT8 gussun_decryption_table[256] = {
0x63,xxxx,xxxx,0x36,xxxx,0x52,0xb1,0x5b, 0x68,0xcd,xxxx,xxxx,xxxx,0xa8,xxxx,xxxx, /* 00 */
// gggg gggg gggg gggg
xxxx,xxxx,0x75,0x24,0x08,0x83,0x32,0xe9, xxxx,0x79,xxxx,0x8f,0x22,xxxx,0xac,xxxx, /* 10 */
// pppp pppp gggg
0x5d,0xa5,0x11,0x51,0x0a,0x29,xxxx,xxxx ,0xf8,0x98,0x91,0x40,0x28,0x00,0x03,0x5f, /* 20 */
// gggg gggg gggg gggg gggg gggg pppp
0x26,xxxx,xxxx,0x8b,0x2f,0x02,xxxx,xxxx, 0x8e,0xab,xxxx,xxxx,0xbc,0x90,0xb3,xxxx, /* 30 */
// gggg
0x09,xxxx,0xc6,xxxx,xxxx,0x3a,xxxx,xxxx, xxxx,0x74,0x61,xxxx,0x33,xxxx,xxxx,xxxx, /* 40 */
// gggg
xxxx,0x53,0xa0,0xc0,0xc3,0x41,0xfc,0xe7, xxxx,0x2c,0x7c,0x2b,xxxx,0x4f,0xba,0x2a, /* 50 */
// gggg gggg gggg pppp gggg gggg
0xb0,xxxx,0x21,0x7d,xxxx,xxxx,0xb5,0x07, 0xb9,xxxx,0x27,0x46,0xf9,xxxx,xxxx,xxxx, /* 60 */
// pppp pppp gggg gggg
xxxx,0xea,0x72,0x73,0xad,0xd1,0x3b,0x5e, 0xe5,0x57,xxxx,0x0d,0xfd,xxxx,0x92,0x3c, /* 70 */
// gggg pppp gggg gggg
xxxx,0x86,0x78,0x7f,0x30,0x25,0x2d,xxxx, 0x9a,0xeb,0x04,0x0b,0xa2,0xb8,0xf6,xxxx, /* 80 */
// pppp gggg gggg pppp gggg
xxxx,xxxx,0x9d,xxxx,0xbb,xxxx,xxxx,0xcb, 0xa9,0xcf,xxxx,0x60,0x43,0x56,xxxx,xxxx, /* 90 */
// gggg gggg
xxxx,0xa3,xxxx,xxxx,0x12,xxxx,0xfa,0xb4, xxxx,0x81,0xe6,0x48,0x80,0x8c,0xd4,xxxx, /* a0 */
// gggg gggg pppp gggg gggg
0x42,xxxx,0x84,0xb6,0x77,0x3d,0x3e,xxxx, xxxx,0x0c,0x4b,xxxx,0xa4,xxxx,xxxx,xxxx, /* b0 */
// gggg gggg pppp gggg gggg pppp pppp gggg
xxxx,0xff,0x47,xxxx,0x55,0x1e,xxxx,0x59, 0x93,xxxx,xxxx,xxxx,0x88,0xc1,0x01,0xb2, /* c0 */
// gggg
0x85,0x2e,0x06,0xc7,0x05,xxxx,0x8a,0x5a, 0x58,0xbe,xxxx,0x4e,xxxx,0x1f,0x23,xxxx, /* d0 */
// gggg gggg
0xe8,xxxx,0x89,0xa1,0xd0,xxxx,xxxx,0xe2, 0x38,0xfe,0x50,0x9c,xxxx,xxxx,xxxx,0x49, /* e0 */
// gggg gggg
0xfb,0x20,0xf3,xxxx,xxxx,0x0f,xxxx,xxxx, xxxx,0x76,0xf7,0xbd,0x39,0x7e,0xbf,xxxx, /* f0 */
// pppp gggg gggg gggg
};
/*
missing opcode:
" " -> checked against hasamu (i.e. you can compare gussun from 2002a and hasamu from 54a0)
"gggg" -> very probably
"pppp" -> probably
"????" -> missing
rz probably:
14 -> 08 (2097b 20980 - routine from 2097a) (08 30) to handle the player number -> 08
19 -> 79 (1df45 routine from 1df27 / 2282f - routine from 2281f to 22871) no 70,78,7a,7b,7c,7e,7f(ok) ok 79,7d
5a -> 7c (195eb - (222fc - routine from 222ed to ) (7x j...) no 70,71,79,7a,7b ok (78,7c) -> 7c
63 -> 7d (1df7f, 1df8c, 1df95, 21f08 - routine from 1df27 to ) no 70,78,7a,7b,7c,7e,7f(ok) ok 79,7d
7b -> 0d
82 -> 78 (78,7c) -> 78
86 -> 2d
ab -> 48 (1956f - routine from 194e1 to 19619 - bp 19567) (when the water go up) -> 48
b3 -> b6 (216b6 - 216cf - 16663 (when you rotate a piece) - 175f1 - 17d2a - 17d36) -> b6
b9 -> 0c (21210 - routine from 2117e to ) 2 bytes -> to handle messages in level 0 (learning level)
ba -> 4b (1094d, 10b28 - routine from 10948 to 10b73) one byte -> probably 4b
f1 -> 20 to handle the player number
rz guess:
06 -> b1 (22872 - routine from 22872 to 2289d)
09 -> cd (22a17 - routine from 229ed to 22a1a)
0d -> a8 (
1b -> 8f (1d8f9 - routine from 1d8c7 to 1d8fc) - three bytes (pop instruction for the push in 1d8e6)
22 -> 11 (1deff - routine from 1dee8 to 1df26) -> 11 - to handle sprite animation
25 -> 29 (195a0 - routine from 194e1 to ) (19,29)
28 -> f8 (
29 -> 98 (1df22 - routine from 1dee8 to 1df26) -> 98 - to handle sprite animation
2b -> 40 (1d4d2 1db81 1dba9 - routine from 1d4b2 to 1d4de) -> 40
2c -> 28 (20333 - routine from 2032a to 20366) (18,28)
2d -> 00 (1df1d - routine from 1dee8 to 1df26) -> 00 - to handle sprite animation
34 -> 2f (20381 - routine from 2037b to 20391) - used to handle number of lives and game over
40 -> 09
52 -> a0
55 -> 41
59 -> 2c (220cf - 2037f - routine from 2202f to ) 2bytes (2c,
5b -> 2b (used in "Service Mode" / "CHARACTER menu")
5d -> 4f
62 -> 21 (1cf86 1cfa3 - routine from 1cf61 to 1cff4) (water in level 1) (01 11 19 29)
66 -> b5 (1daaf - routine from 1da61 to 1daca) - two bytes (colors effect)
6a -> 27 (20368 - routine from 20368 to 2037a) - used to limit the max lives number
73 -> 73 (1d4f7 - routine from 1d4df to 1d539) -> (no 70,71,72,74,75,76,77,78,79,7a,7b,7c,7d,7e,7f) - ok 73
7c -> fd
7e -> 92 (1e095 - routine from 1e073 to 1e0cf)
83 -> 7f (194cd - routine from) no 70,78,79,7a,7b,7c,7d,7e ok 77(no) ok 7f
84 -> 08 (1d8f1 - routine from 1d8c7 to 1d8fc) - three bytes (ok 30) (sprite animation) -> 30
88 -> 9a
92 -> 9d
97 -> cb
a4 -> 12 (02,12) - routine from 1d392 -> 12
a7 -> b4 (2029a - routine from 20290 to
ad -> 8c (1d559, 1d8d4 - routine from 1d547 - ; routine from 1d8b8 to 1d8fc) ..............................
ae -> d4 (20215 - ) used when you insert a coin to handle the "coin number" in decimal
b0 -> 42 (routine from 128db)
b2 -> 84 (20a8b - 20acc) 20,21,84,85 (scroll down the object) - to handle the player number
b4 -> 77 (1d03a, 1d57a - routine from 1d4df ) no 70,71,76,78,79,7a,7b,7c,7d,7e,7f ok 77
b6 -> 3e
bc -> a4
c2 -> 47 (22881, 220ff - routine from 22872 to 22885)
d0 -> 85 (routine from 16a3e) (when you rotate a piece)
db -> 4e (18b1a)
eb -> 9c
ef -> 49 (dec CW) (used in "Service Mode" / "CHARACTER menu")
f9 -> 76 (16d02(f 16cfa)-16598-165a1-18de7(f 18dc4) no 71(no),77(no),(icons? 70,76,78,7a,7c,7e),79,7d,7f(no) maybe 76
fb -> bd
fd -> 7e (1d659 - routine from 1d63c to 1d65e) no 70,76,77,78,79,7a,7b, 7c,7d,7e,7f ok 7e
missing V35+ core:
0f 92 -> of 92 not supported (1011d before STI instruction) (for now no effects)
-------------------------------------------------------------------------------------------------------------
AS notes:
0x1e is lodsb not lds,noted from 2344f
0x16 is xor r8,r8 not xor r16,r16
0xc8 not inc aw but xch bw,aw
0xcd is 0xc1 not 0xbd(palette at startup)
0x97 guess,but seems right(228c1),known to *not* be ret %Iw.
0x00 wrong(for sure it needs a one byte operand due to push es called at one point...)
0x19 guess (0x82 PRE)
0xc2 guess,it could be dec iy...
above - c8 (inc aw) guess from stos code
0xc5 -> 1e (push ds) guess (pop ds soon after) right?
0xa9 -> 81 (not 0x82 PRE) guess from 237df
0xcd -> c1 total guess (wrong but 3 bytes)
*/
/*
e0100 palette sub-routine:
12485: 23 push es
12486: 27 C2 mov es,dw
12488: D7 C0 xor aw,aw
1248A: D7 FF xor iy,iy
1248C: 44 00 01 mov cw,$0100
1248F: 81 5D repe stosw
12491: 95 22 06 97 39 mov byte ss:[$3997],$FF
12497: 3A pop es
12498: 60 ret
d1a86
unk
add bw,bw [d8]
add ix,sp [e6]
add iy,sp [e7]
clc
ret
*/
const UINT8 leagueman_decryption_table[256] = {
xxxx,xxxx,xxxx,0x55,0xbb,xxxx,0x23,0x79, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x38,xxxx, /* 00 */
0x01,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, 0x3d,xxxx,xxxx,xxxx,0xba,xxxx,0x1e,xxxx, /* 10 */
0x2c,0x46,xxxx,0xb5,xxxx,0x4b,xxxx,0xfe, xxxx,xxxx,0xfb,0x2e,xxxx,xxxx,0x36,0x04, /* 20 */
0xcf,xxxx,0xf3,0x5a,0x8a,0x0c,0x9c,xxxx, xxxx,xxxx,0xb2,0x50,xxxx,xxxx,xxxx,0x5f, /* 30 */
xxxx,xxxx,0x24,xxxx,xxxx,0x41,0x2b,xxxx, 0xe9,xxxx,0x08,0x3b,xxxx,xxxx,xxxx,xxxx, /* 40 */
xxxx,0xd2,0x51,xxxx,xxxx,xxxx,0x22,xxxx, 0xeb,0x3a,0x5b,0xa2,0xb1,0x80,xxxx,xxxx, /* 50 */
xxxx,xxxx,xxxx,xxxx,0x59,0xb4,0x88,xxxx, xxxx,0xbf,0xd1,xxxx,0xb9,0x57,xxxx,xxxx, /* 60 */
0x72,xxxx,0x73,xxxx,xxxx,xxxx,xxxx,0x0f, xxxx,xxxx,xxxx,xxxx,0x56,xxxx,xxxx,0xc6, /* 70 */
xxxx,xxxx,xxxx,xxxx,xxxx,0x2a,0x8e,xxxx, 0x81,0xa3,0x58,xxxx,0xaa,0x78,0x89,xxxx, /* 80 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0xbd,xxxx, xxxx,xxxx,0xff,xxxx,xxxx,xxxx,0x07,0x53, /* 90 */
0xa0,xxxx,xxxx,0x5e,0xb0,xxxx,0x83,0xf6, xxxx,0x26,0x32,xxxx,xxxx,xxxx,0x74,0x0a, /* A0 */
0x18,xxxx,xxxx,xxxx,0x75,0x03,xxxx,xxxx, 0xb6,0x02,xxxx,xxxx,0x43,xxxx,0xb8,xxxx, /* B0 */
0xe8,xxxx,0xfc,xxxx,0x20,0xc3,xxxx,0x06, xxxx,0x1f,0x86,0x00,xxxx,xxxx,xxxx,0xd0, /* C0 */
0x47,xxxx,0x87,xxxx,xxxx,0x9d,0x3c,0xc7, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* D0 */
xxxx,xxxx,xxxx,0x8b,xxxx,xxxx,0x33,xxxx, xxxx,xxxx,xxxx,xxxx,0xfa,0x42,xxxx,xxxx, /* E0 */
xxxx,xxxx,xxxx,0xea,xxxx,0x52,xxxx,0x5d, xxxx,xxxx,xxxx,xxxx,0xbc,xxxx,xxxx,xxxx, /* F0 */
};
// 0x25 (0x4b) guess
// 0x10 (0x01) guess (wrong?)
const UINT8 psoldier_decryption_table[256] = {
xxxx,xxxx,xxxx,0x8a,xxxx,0xaa,xxxx,xxxx, xxxx,0x20,0x23,0x55,xxxx,0xb5,0x0a,xxxx, /* 00 */
xxxx,0x46,xxxx,0xb6,xxxx,0x74,0x8b,xxxx, xxxx,0xba,0x01,xxxx,xxxx,0x5a,0x86,0xfb, /* 10 */
0xb2,xxxx,0xb0,xxxx,0x42,0x06,0x1e,0x08, 0x22,0x9d,xxxx,xxxx,xxxx,xxxx,xxxx,0x73, /* 20 */
xxxx,xxxx,0x5f,xxxx,xxxx,0xd0,xxxx,0xff, xxxx,xxxx,0xbd,xxxx,0x03,xxxx,0xb9,xxxx, /* 30 */
xxxx,xxxx,xxxx,0x51,0x5e,0x24,xxxx,xxxx, xxxx,xxxx,xxxx,0x58,0x59,xxxx,xxxx,xxxx, /* 40 */
0x52,xxxx,xxxx,xxxx,0xa0,xxxx,xxxx,0x02, 0xd2,xxxx,0x79,0x26,0x3a,0x0f,0xcf,0xb4, /* 50 */
0xf3,xxxx,xxxx,0x50,xxxx,0x75,0xb1,xxxx, 0xd1,0x47,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 60 */
0xc6,xxxx,xxxx,xxxx,xxxx,xxxx,0xbc,xxxx, xxxx,xxxx,xxxx,xxxx,0x53,0x41,xxxx,xxxx, /* 70 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0x04,xxxx, xxxx,xxxx,xxxx,0x2c,xxxx,0xbf,xxxx,xxxx, /* 80 */
xxxx,xxxx,0xe8,xxxx,xxxx,0x78,xxxx,0xbb, xxxx,xxxx,0x1f,0x2b,0x87,xxxx,0x4b,0x56, /* 90 */
0x36,0x33,xxxx,xxxx,xxxx,0x9c,0xc3,xxxx, xxxx,0x81,xxxx,0xe9,xxxx,0xfa,xxxx,xxxx, /* A0 */
xxxx,0x72,xxxx,0xa2,xxxx,xxxx,0xc7,xxxx, xxxx,0x92,xxxx,xxxx,0x88,xxxx,xxxx,xxxx, /* B0 */
0x3b,xxxx,0x0c,xxxx,0x80,xxxx,xxxx,xxxx, xxxx,0x2e,xxxx,xxxx,xxxx,0x57,xxxx,0x8e, /* C0 */
0x07,xxxx,0xa3,xxxx,xxxx,xxxx,0x3d,xxxx, 0xfe,xxxx,xxxx,0xfc,0xea,xxxx,0x38,xxxx, /* D0 */
0x3c,0xf6,xxxx,xxxx,xxxx,0x18,xxxx,xxxx, 0xb8,xxxx,xxxx,xxxx,0x2a,0x5d,0x5b,xxxx, /* E0 */
xxxx,0x43,0x32,xxxx,xxxx,xxxx,0xeb,xxxx, xxxx,xxxx,xxxx,xxxx,0x83,0x89,xxxx,xxxx, /* F0 */
};
// 0x9e (0x4b) guess
// 0x1a (0x01) guess (wrong?)
const UINT8 dsoccr94_decryption_table[256] = {
xxxx,0xd1,xxxx,xxxx,xxxx,0x79,0x2e,xxxx, xxxx,xxxx,0x5a,0x0f,xxxx,xxxx,0x43,xxxx, /* 00 */
xxxx,xxxx,0xe8,0x50,xxxx,xxxx,xxxx,0xa0, 0x5d,0x22,xxxx,xxxx,0xb2,0x3a,xxxx,xxxx, /* 10 */
0xf6,0x8a,0x41,xxxx,xxxx,0x81,xxxx,xxxx, xxxx,xxxx,0x2b,0x58,xxxx,xxxx,xxxx,0xc6, /* 20 */
xxxx,xxxx,0xb9,xxxx,xxxx,0x2a,xxxx,0x3c, xxxx,0x80,0x26,xxxx,0xb0,xxxx,0x47,xxxx, /* 30 */
xxxx,xxxx,0x0a,0x55,xxxx,xxxx,xxxx,0x88, xxxx,xxxx,0x87,xxxx,xxxx,0xb4,0x0c,xxxx, /* 40 */
0x73,0x53,xxxx,xxxx,0x3b,0x1f,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 50 */
0x01,xxxx,xxxx,xxxx,xxxx,0x1e,xxxx,xxxx, 0xc3,xxxx,0xa3,0x74,xxxx,0x32,0x42,0x75, /* 60 */
0xfc,xxxx,0xb8,xxxx,0x33,xxxx,0x5e,xxxx, xxxx,0xaa,xxxx,xxxx,0x04,xxxx,0x9c,0xba, /* 70 */
xxxx,xxxx,0x24,0x89,xxxx,xxxx,0xea,xxxx, 0x23,xxxx,xxxx,xxxx,0xbb,xxxx,xxxx,0xc7, /* 80 */
xxxx,0x8e,xxxx,0x52,xxxx,0x18,xxxx,0x72, xxxx,xxxx,xxxx,xxxx,0xb6,xxxx,xxxx,xxxx, /* 90 */
0xfa,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, 0xb1,xxxx,xxxx,xxxx,xxxx,0x57,0x78,0xa2, /* A0 */
xxxx,0x3d,0x51,xxxx,xxxx,0xbf,0x46,0x2c, xxxx,xxxx,0xfb,xxxx,xxxx,xxxx,xxxx,0x38, /* B0 */
0x56,xxxx,0xcf,xxxx,0x08,xxxx,xxxx,xxxx, 0x5b,0x07,xxxx,xxxx,xxxx,0x20,0x9d,xxxx, /* C0 */
0x03,xxxx,xxxx,xxxx,xxxx,xxxx,0xbc,0x86, 0x59,xxxx,0x02,xxxx,0xff,0xd2,0x8b,xxxx, /* D0 */
xxxx,0xd0,xxxx,xxxx,xxxx,xxxx,xxxx,0xe9, 0x06,xxxx,0x5f,0xf3,xxxx,0xb5,xxxx,xxxx, /* E0 */
0xeb,xxxx,xxxx,xxxx,xxxx,xxxx,0x83,xxxx, 0x36,xxxx,xxxx,xxxx,xxxx,0xbd,0xfe,xxxx, /* F0 */
};
// 0x95 (0x18) opcode is right but arguments could be swapped
// 0x2a (0x2b) not sure, could be 0x1b
// 0x60 (0x01) guess (wrong?)
/* preliminary table by Pierpaolo Prazzoli */
const UINT8 matchit2_decryption_table[256] = {
xxxx,0x86,0x0a,xxxx,0x32,0x01,0x81,0xbe, 0xea,xxxx,0xbb,xxxx,xxxx,xxxx,0xa5,0xf6, /* 00 */
// new new new new new new new new new
0x5d,0x8c,0xf3,0xc4,0x42,0x5a,0x22,0x26, xxxx,0x58,xxxx,0xfd,0x59,0x53,0x80,0x09, /* 10 */
// new new new new !!!! new !!!! new !!!! new new new !!!!
xxxx,0x1e,0x48,0xe2,0x50,xxxx,0xc3,0x23, xxxx,xxxx,0xe9,xxxx,0x40,0x83,0xa3,0x46, /* 20 */
// new new new new new new new new new new
0x49,0xb4,0xa9,xxxx,0xd3,0x8b,0xe8,0xb8, 0xa0,xxxx,xxxx,xxxx,0x84,xxxx,xxxx,xxxx, /* 30 */
// !!!! ???? new !!!! new new new new
xxxx,xxxx,xxxx,xxxx,0x14,xxxx,0x25,xxxx, xxxx,0x5e,xxxx,0x87,0x56,0xb9,0x4a,0x39, /* 40 */
// new new new new new new new new
0x89,xxxx,xxxx,xxxx,xxxx,0x1f,0xa4,xxxx, 0xf8,0x5f,0x21,0xb3,0x5b,xxxx,0x8d,xxxx, /* 50 */
// new new !!!! new new !!!! new new
xxxx,0xc5,0x7c,0x07,xxxx,0x88,0xba,0x47, 0x35,0xfb,xxxx,0x7f,xxxx,xxxx,0xc6,0xeb, /* 60 */
// new !!!! new new new new new new !!!! new
xxxx,0xc7,xxxx,xxxx,0xd2,0xa1,0x72,0x79, 0xfe,0x24,0xab,0x2a,0xbc,0x0d,0x8f,0x7e, /* 70 */
// !!!! new new new new new new new new new !!!!
xxxx,0x7d,xxxx,0xe7,0x2d,xxxx,xxxx,0x57, 0x0b,0xa2,xxxx,0x9d,xxxx,xxxx,0x74,0x85, /* 80 */
// !!!! new new new new new new new new
0xaf,0x2f,0x8a,0xe6,0x08,xxxx,0xff,xxxx, xxxx,0x1c,xxxx,xxxx,0x02,xxxx,xxxx,xxxx, /* 90 */
// new !!!! new new new new !!!! new
0x43,0x04,xxxx,xxxx,0xbf,0x3b,0x93,0x38, xxxx,xxxx,xxxx,0x77,xxxx,0xb0,xxxx,0x3a, /* A0 */
// new new new new new new new new new
0xfc,xxxx,0xb5,xxxx,xxxx,xxxx,xxxx,0x05, 0x52,0x76,0x2b,0xe5,0xbd,xxxx,0x0e,0xb1, /* B0 */
// new new new new new new new new new !!!!
0x73,xxxx,xxxx,0x45,0x92,0x99,xxxx,0xf7, 0x3d,0xd0,0xb6,0x36,0xf9,0xfa,0x0f,xxxx, /* C0 */
// new new new new new new new !!!! new new
0x75,xxxx,0xaa,0x9c,xxxx,0x11,xxxx,xxxx, 0x27,0x4b,xxxx,0x2c,0x51,0x2e,0x4d,xxxx, /* D0 */
// new !!!! new new new new new new new !!!!
0x55,0x3c,xxxx,0xb7,xxxx,0xd1,0x8e,xxxx, 0xb2,xxxx,0x78,xxxx,0x12,xxxx,0x29,0x0c, /* E0 */
// new new new ???? new new new new new new new
0x33,xxxx,0xf2,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,0x03,0x06,0xa8,xxxx,xxxx,0xcf,xxxx, /* F0 */
// new new new new new new
};
/*
Unknown (marked "????")
from shisen 2:
E4 -> pc: b08; f458, 1920 (99% 1 byte at boot and sometimes when a piece is selected)
b65c (after one match is finished with the girl on the background or when you finish some levels in the other modes)
Found (marked "!!!!")
14 -> pc: 8b2a -> 42
16 -> pc: 1714, 1804, 1a70, 1cc3 (00 10 13 1C 20 21 22 34 D4 D5 after a match) -> 22
1B -> pc: 630e (it's used to update the high score) -> FD
1F -> pc: f30, f35, af74, 153a, 6dd8, 674f -> 09
30 -> pc: 19af, 1986 -> 49
31 -> pc: c804, c813, c822, 1358, c303, c312, c321, 1315, 1338 (2 bytes opcode) -> B4
34 -> pc: 42cd -> D3
4E -> pc: 7ac3, 7ae8 (after a 2 players match and in a 2 players match in "stalemate") -> 4a
56 -> pc: 6587 (can be 6C, 6D, 6E, 6F, A4, A6, A7, AA, AC, AD, AE at boot) -> A4
5A -> pc: ae83 (after an item is selected) (00 10 13 15 1B -1C already used- 1D 21 28) -> 21 (it's used to evidence tiles similar to the one selected)
62 -> pc: 5b3f (jump 71, 7C) -> 7C
6B -> pc: 1810, 1936 (jump) -> 7F
74 -> pc: ca75 -> D2
7F -> pc: 6b7e, 51d7, 5a8c, 5a9a, 5996 (jump: 7C, 7E) -> 7E
81 -> pc: 599d (jump: 7D, 7F) -> 7D
91 -> pc: 6e0c, 96ef, 96d0 (1 byte opcode) -> 2F
99 -> pc: 96f7, 9702 (after undo button is pressed) -> 1C (it's used to update the score when the you undo the moves)
BF -> pc: 6af3, 6b01, ca73, ab39 (2 bytes opcode) -> B1
C4 -> pc: deb4 -> 92 from bbmanw
EC -> pc: 966e, 9679 -> 12 from bbmanw
D2 -> pc: 631c (it's used to update the high score) (6C, 6E, A6, AA, AE) -> AA
the ones marked with "new" are checked against dynablst and bomberman tables
*/
const UINT8 test_decryption_table[256] = {
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 00 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 10 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 20 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 30 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 40 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 50 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 60 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 70 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 80 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* 90 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* A0 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* B0 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* C0 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* D0 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* E0 */
xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,xxxx, /* F0 */
};
void irem_cpu_decrypt(INT32 /*cpu*/,const UINT8 *decryption_table, UINT8 *src, UINT8 *dest, INT32 size)
{
for (INT32 A = 0;A < size;A++)
{
dest[A] = decryption_table[src[A]];
}
}

View File

@ -0,0 +1,18 @@
extern const UINT8 gunforce_decryption_table[];
extern const UINT8 bomberman_decryption_table[];
extern const UINT8 lethalth_decryption_table[];
extern const UINT8 dynablaster_decryption_table[];
extern const UINT8 mysticri_decryption_table[];
extern const UINT8 majtitl2_decryption_table[];
extern const UINT8 hook_decryption_table[];
extern const UINT8 rtypeleo_decryption_table[];
extern const UINT8 inthunt_decryption_table[];
extern const UINT8 gussun_decryption_table[];
extern const UINT8 leagueman_decryption_table[];
extern const UINT8 psoldier_decryption_table[];
extern const UINT8 dsoccr94_decryption_table[];
extern const UINT8 matchit2_decryption_table[];
extern const UINT8 test_decryption_table[];
extern void irem_cpu_decrypt(INT32 cpu,const UINT8 *decryption_table, UINT8 *src,UINT8 *dest, INT32 size);

View File

@ -0,0 +1,846 @@
// FB Alpha '88 Games driver module
// Based on MAME driver by Nicola Salmoria
#include "tiles_generic.h"
#include "konami_intf.h"
#include "konamiic.h"
#include "burn_ym2151.h"
#include "UPD7759.h"
static UINT8 *AllMem;
static UINT8 *MemEnd;
static UINT8 *AllRam;
static UINT8 *RamEnd;
static UINT8 *DrvKonROM;
static UINT8 *DrvZ80ROM;
static UINT8 *DrvGfxROM0;
static UINT8 *DrvGfxROM1;
static UINT8 *DrvGfxROM2;
static UINT8 *DrvGfxROMExp0;
static UINT8 *DrvGfxROMExp1;
static UINT8 *DrvGfxROMExp2;
static UINT8 *DrvSndROM0;
static UINT8 *DrvSndROM1;
static UINT8 *DrvBankRAM;
static UINT8 *DrvKonRAM;
static UINT8 *DrvPalRAM;
static UINT8 *DrvZ80RAM;
static UINT8 *DrvNVRAM;
static UINT32 *DrvPalette;
static UINT8 DrvRecalc;
static UINT8 *soundlatch;
static UINT8 *nDrvBank;
static INT32 videobank;
static INT32 zoomreadroms;
static INT32 k88games_priority;
static INT32 UPD7759Device;
static UINT8 DrvJoy1[8];
static UINT8 DrvJoy2[8];
static UINT8 DrvJoy3[8];
static UINT8 DrvDips[3];
static UINT8 DrvInputs[3];
static UINT8 DrvReset;
static struct BurnInputInfo games88InputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 0, "p1 coin" },
{"P1 Start", BIT_DIGITAL, DrvJoy2 + 3, "p1 start" },
{"P1 Button 1", BIT_DIGITAL, DrvJoy2 + 0, "p1 fire 1" },
{"P1 Button 2", BIT_DIGITAL, DrvJoy2 + 1, "p1 fire 2" },
{"P1 Button 3", BIT_DIGITAL, DrvJoy2 + 2, "p1 fire 3" },
{"P2 Coin", BIT_DIGITAL, DrvJoy1 + 1, "p2 coin" },
{"P2 Start", BIT_DIGITAL, DrvJoy2 + 7, "p2 start" },
{"P2 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p2 fire 1" },
{"P2 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 2" },
{"P2 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 3" },
{"P3 Start", BIT_DIGITAL, DrvJoy3 + 3, "p3 start" },
{"P3 Button 1", BIT_DIGITAL, DrvJoy3 + 0, "p3 fire 1" },
{"P3 Button 2", BIT_DIGITAL, DrvJoy3 + 1, "p3 fire 2" },
{"P3 Button 3", BIT_DIGITAL, DrvJoy3 + 2, "p3 fire 3" },
{"P4 Start", BIT_DIGITAL, DrvJoy3 + 7, "p4 start" },
{"P4 Button 1", BIT_DIGITAL, DrvJoy3 + 4, "p4 fire 1" },
{"P4 Button 2", BIT_DIGITAL, DrvJoy3 + 5, "p4 fire 2" },
{"P4 Button 3", BIT_DIGITAL, DrvJoy3 + 6, "p4 fire 3" },
{"Reset", BIT_DIGITAL, &DrvReset, "reset" },
{"Service", BIT_DIGITAL, DrvJoy1 + 2, "service" },
{"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" },
{"Dip B", BIT_DIPSWITCH, DrvDips + 1, "dip" },
{"Dip C", BIT_DIPSWITCH, DrvDips + 2, "dip" },
};
STDINPUTINFO(games88)
static struct BurnDIPInfo games88DIPList[]=
{
{0x14, 0xff, 0xff, 0xf0, NULL },
{0x15, 0xff, 0xff, 0xff, NULL },
{0x16, 0xff, 0xff, 0x7b, NULL },
// {0 , 0xfe, 0 , 2, "Flip Screen" },
// {0x14, 0x01, 0x10, 0x10, "Off" },
// {0x14, 0x01, 0x10, 0x00, "On" },
{0 , 0xfe, 0 , 2, "World Records" },
{0x14, 0x01, 0x20, 0x20, "Don't Erase" },
{0x14, 0x01, 0x20, 0x00, "Erase on Reset" },
{0 , 0xfe, 0 , 2, "Service Mode" },
{0x14, 0x01, 0x40, 0x40, "Off" },
{0x14, 0x01, 0x40, 0x00, "On" },
{0 , 0xfe, 0 , 16, "Coin A" },
{0x15, 0x01, 0x0f, 0x02, "4 Coins 1 Credit" },
{0x15, 0x01, 0x0f, 0x05, "3 Coins 1 Credit" },
{0x15, 0x01, 0x0f, 0x08, "2 Coins 1 Credit" },
{0x15, 0x01, 0x0f, 0x04, "3 Coins 2 Credits" },
{0x15, 0x01, 0x0f, 0x01, "4 Coins 3 Credits" },
{0x15, 0x01, 0x0f, 0x0f, "1 Coin 1 Credit" },
{0x15, 0x01, 0x0f, 0x03, "3 Coins 4 Credits" },
{0x15, 0x01, 0x0f, 0x07, "2 Coins 3 Credits" },
{0x15, 0x01, 0x0f, 0x0e, "1 Coin 2 Credits" },
{0x15, 0x01, 0x0f, 0x06, "2 Coins 5 Credits" },
{0x15, 0x01, 0x0f, 0x0d, "1 Coin 3 Credits" },
{0x15, 0x01, 0x0f, 0x0c, "1 Coin 4 Credits" },
{0x15, 0x01, 0x0f, 0x0b, "1 Coin 5 Credits" },
{0x15, 0x01, 0x0f, 0x0a, "1 Coin 6 Credits" },
{0x15, 0x01, 0x0f, 0x09, "1 Coin 7 Credits" },
{0x15, 0x01, 0x0f, 0x00, "Free Play" },
{0 , 0xfe, 0 , 16, "Coin B" },
{0x15, 0x01, 0xf0, 0x20, "4 Coins 1 Credit" },
{0x15, 0x01, 0xf0, 0x50, "3 Coins 1 Credit" },
{0x15, 0x01, 0xf0, 0x80, "2 Coins 1 Credit" },
{0x15, 0x01, 0xf0, 0x40, "3 Coins 2 Credits" },
{0x15, 0x01, 0xf0, 0x10, "4 Coins 3 Credits" },
{0x15, 0x01, 0xf0, 0xf0, "1 Coin 1 Credit" },
{0x15, 0x01, 0xf0, 0x30, "3 Coins 4 Credits" },
{0x15, 0x01, 0xf0, 0x70, "2 Coins 3 Credits" },
{0x15, 0x01, 0xf0, 0xe0, "1 Coin 2 Credits" },
{0x15, 0x01, 0xf0, 0x60, "2 Coins 5 Credits" },
{0x15, 0x01, 0xf0, 0xd0, "1 Coin 3 Credits" },
{0x15, 0x01, 0xf0, 0xc0, "1 Coin 4 Credits" },
{0x15, 0x01, 0xf0, 0xb0, "1 Coin 5 Credits" },
{0x15, 0x01, 0xf0, 0xa0, "1 Coin 6 Credits" },
{0x15, 0x01, 0xf0, 0x90, "1 Coin 7 Credits" },
{0x15, 0x01, 0xf0, 0x00, "No Coin B" },
// {0 , 0xfe, 0 , 4, "Cabinet" },
// {0x16, 0x01, 0x06, 0x06, "Cocktail" },
// {0x16, 0x01, 0x06, 0x04, "Cocktail (A)" },
// {0x16, 0x01, 0x06, 0x02, "Upright" },
// {0x16, 0x01, 0x06, 0x00, "Upright (D)" },
{0 , 0xfe, 0 , 4, "Difficulty" },
{0x16, 0x01, 0x60, 0x60, "Easy" },
{0x16, 0x01, 0x60, 0x40, "Normal" },
{0x16, 0x01, 0x60, 0x20, "Hard" },
{0x16, 0x01, 0x60, 0x00, "Hardest" },
{0 , 0xfe, 0 , 2, "Demo Sounds" },
{0x16, 0x01, 0x80, 0x80, "Off" },
{0x16, 0x01, 0x80, 0x00, "On" },
};
STDDIPINFO(games88)
void games88_main_write(UINT16 address, UINT8 data)
{
switch (address)
{
case 0x5f84:
zoomreadroms = data & 0x04;
return;
case 0x5f88:
// watchdog
return;
case 0x5f8c:
*soundlatch = data;
return;
case 0x5f90:
ZetSetVector(0xff);
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
return;
}
if ((address & 0xf800) == 0x3800)
{
if (videobank)
DrvBankRAM[address & 0x7ff] = data;
else
K051316Write(0, address & 0x7ff, data);
return;
}
if ((address & 0xfff0) == 0x5fc0) {
K051316WriteCtrl(0, address & 0x0f, data);
return;
}
if ((address & 0xc000) == 0x4000) {
K052109_051960_w(address & 0x3fff, data);
return;
}
}
UINT8 games88_main_read(UINT16 address)
{
switch (address)
{
case 0x5f94:
return (DrvInputs[0] & 0x0f) | (DrvDips[0] & 0xf0);
case 0x5f95:
return DrvInputs[1];
case 0x5f96:
return DrvInputs[2];
case 0x5f97:
return DrvDips[1];
case 0x5f9b:
return DrvDips[2];
}
if ((address & 0xf800) == 0x3800)
{
if (videobank) {
return DrvBankRAM[address & 0x7ff];
} else {
if (zoomreadroms) {
return K051316ReadRom(0, address & 0x7ff); // k051316_rom_0
} else {
return K051316Read(0, address & 0x7ff); // k051316_0
}
}
}
if ((address & 0xc000) == 0x4000) {
return K052109_051960_r(address & 0x3fff);
}
return 0;
}
void __fastcall games88_sound_write(UINT16 address, UINT8 data)
{
switch (address)
{
case 0x9000:
UPD7759PortWrite(UPD7759Device, data);
return;
case 0xc000:
BurnYM2151SelectRegister(data);
return;
case 0xc001:
BurnYM2151WriteRegister(data);
return;
case 0xe000:
UPD7759Device = (data & 4) >> 2;
UPD7759ResetWrite(UPD7759Device, data & 2);
UPD7759StartWrite(UPD7759Device, data & 1);
return;
}
}
UINT8 __fastcall games88_sound_read(UINT16 address)
{
switch (address)
{
case 0xa000:
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
return *soundlatch;
case 0xc000:
case 0xc001:
return BurnYM2151ReadStatus();
}
return 0;
}
static void games88_set_lines(INT32 lines)
{
nDrvBank[0] = lines;
INT32 nBank = 0x10000 + (lines & 0x07) * 0x2000;
konamiMapMemory(DrvKonROM + nBank, 0x0000, 0x0fff, KON_ROM);
if (lines & 8) {
konamiMapMemory(DrvPalRAM, 0x1000, 0x1fff, KON_RAM);
} else {
konamiMapMemory(DrvKonROM + nBank + 0x1000, 0x1000, 0x1fff, KON_ROM);
konamiMapMemory(DrvKonROM + 0x0000, 0x1000, 0x1fff, KON_WRITE); // unmap writes
}
videobank = lines & 0x10;
K052109RMRDLine = lines & 0x20;
k88games_priority = lines & 0x80;
}
static void K052109Callback(INT32 layer, INT32 bank, INT32 *code, INT32 *color, INT32 *, INT32 *)
{
INT32 layer_colorbase[3] = { 64, 0, 16 };
*code |= ((*color & 0x0f) << 8) | (bank << 12);
*color = layer_colorbase[layer] + ((*color & 0xf0) >> 4);
}
static void K051960Callback(INT32 */*code*/, INT32 *color, INT32 *priority, INT32 *)
{
*priority = (*color & 0x20) >> 5;
*color = 32 + (*color & 0x0f);
}
static void K051316Callback(INT32 *code,INT32 *color,INT32 *flags)
{
*flags = *color & 0x40;
*code |= ((*color & 0x07) << 8);
*color = 48 + ((*color & 0x38) >> 3) + ((*color & 0x80) >> 4);
}
static INT32 DrvDoReset()
{
DrvReset = 0;
memset (AllRam, 0, RamEnd - AllRam);
konamiOpen(0);
konamiReset();
konamiClose();
ZetOpen(0);
ZetReset();
ZetClose();
BurnYM2151Reset();
KonamiICReset();
UPD7759Reset();
videobank = 0;
zoomreadroms = 0;
k88games_priority = 0;
UPD7759Device = 0;
return 0;
}
static INT32 MemIndex()
{
UINT8 *Next; Next = AllMem;
DrvKonROM = Next; Next += 0x020000;
DrvZ80ROM = Next; Next += 0x010000;
DrvGfxROM0 = Next; Next += 0x080000;
DrvGfxROM1 = Next; Next += 0x100000;
DrvGfxROM2 = Next; Next += 0x040000;
DrvGfxROMExp0 = Next; Next += 0x100000;
DrvGfxROMExp1 = Next; Next += 0x200000;
DrvGfxROMExp2 = Next; Next += 0x080000;
DrvSndROM0 = Next; Next += 0x020000;
DrvSndROM1 = Next; Next += 0x020000;
DrvPalette = (UINT32*)Next; Next += 0x800 * sizeof(UINT32);
AllRam = Next;
DrvBankRAM = Next; Next += 0x000800;
DrvKonRAM = Next; Next += 0x001000;
DrvPalRAM = Next; Next += 0x001000;
DrvNVRAM = Next; Next += 0x000800;
DrvZ80RAM = Next; Next += 0x000800;
soundlatch = Next; Next += 0x000001;
nDrvBank = Next; Next += 0x000002;
RamEnd = Next;
MemEnd = Next;
return 0;
}
static INT32 DrvGfxDecode()
{
INT32 Plane0[4] = { 0x018, 0x010, 0x008, 0x000 };
INT32 Plane1[4] = { 0x000, 0x008, 0x010, 0x018 };
INT32 XOffs0[16] = { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107 };
INT32 YOffs0[16] = { 0x000, 0x020, 0x040, 0x060, 0x080, 0x0a0, 0x0c0, 0x0e0,
0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0 };
konami_rom_deinterleave_2(DrvGfxROM0, 0x080000);
konami_rom_deinterleave_2(DrvGfxROM1, 0x100000);
GfxDecode(0x04000, 4, 8, 8, Plane0, XOffs0, YOffs0, 0x100, DrvGfxROM0, DrvGfxROMExp0);
GfxDecode(0x02000, 4, 16, 16, Plane1, XOffs0, YOffs0, 0x400, DrvGfxROM1, DrvGfxROMExp1);
return 0;
}
static INT32 DrvInit()
{
AllMem = NULL;
MemIndex();
INT32 nLen = MemEnd - (UINT8 *)0;
if ((AllMem = (UINT8 *)malloc(nLen)) == NULL) return 1;
memset(AllMem, 0, nLen);
MemIndex();
{
if (BurnLoadRom(DrvKonROM + 0x008000, 0, 1)) return 1;
if (BurnLoadRom(DrvKonROM + 0x010000, 1, 1)) return 1;
if (BurnLoadRom(DrvZ80ROM + 0x000000, 2, 1)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x000000, 3, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x000001, 4, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x020000, 5, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x020001, 6, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x040000, 7, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x040001, 8, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x060000, 9, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x060001, 10, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x000000, 11, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x000001, 12, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x020000, 13, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x020001, 14, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x040000, 15, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x040001, 16, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x060000, 17, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x060001, 18, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x080000, 19, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x080001, 20, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0a0000, 21, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0a0001, 22, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0c0000, 23, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0c0001, 24, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0e0000, 25, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0e0001, 26, 2)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x000000, 27, 1)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x010000, 28, 1)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x020000, 29, 1)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x030000, 30, 1)) return 1;
if (BurnLoadRom(DrvSndROM0 + 0x000000, 31, 1)) return 1;
if (BurnLoadRom(DrvSndROM0 + 0x010000, 32, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x000000, 33, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x010000, 34, 1)) return 1;
DrvGfxDecode();
}
konamiInit(1);
konamiOpen(0);
konamiMapMemory(DrvPalRAM + 0x0000, 0x1000, 0x1fff, KON_RAM);
konamiMapMemory(DrvKonRAM, 0x2000, 0x2fff, KON_RAM);
konamiMapMemory(DrvNVRAM, 0x3000, 0x37ff, KON_RAM);
konamiMapMemory(DrvKonROM + 0x8000, 0x8000, 0xffff, KON_ROM);
konamiSetWriteHandler(games88_main_write);
konamiSetReadHandler(games88_main_read);
konamiSetlinesCallback(games88_set_lines);
konamiClose();
ZetInit(1);
ZetOpen(0);
ZetMapArea(0x0000, 0x7fff, 0, DrvZ80ROM);
ZetMapArea(0x0000, 0x7fff, 2, DrvZ80ROM);
ZetMapArea(0x8000, 0x87ff, 0, DrvZ80RAM);
ZetMapArea(0x8000, 0x87ff, 1, DrvZ80RAM);
ZetMapArea(0x8000, 0x87ff, 2, DrvZ80RAM);
ZetSetWriteHandler(games88_sound_write);
ZetSetReadHandler(games88_sound_read);
ZetMemEnd();
ZetClose();
BurnYM2151Init(3579545, 75.0);
UPD7759Init(0, UPD7759_STANDARD_CLOCK, DrvSndROM0);
UPD7759Init(1, UPD7759_STANDARD_CLOCK, DrvSndROM1);
K052109Init(DrvGfxROM0, 0x7ffff);
K052109SetCallback(K052109Callback);
K052109AdjustScroll(0, 0);
K051960Init(DrvGfxROM1, 0xfffff);
K051960SetCallback(K051960Callback);
K051960SetSpriteOffset(0, 0);
K051316Init(0, DrvGfxROM2, DrvGfxROMExp2, 0x3ffff, K051316Callback, 4, 0);
K051316SetOffset(0, -104, -16);
GenericTilesInit();
DrvDoReset();
return 0;
}
static INT32 DrvExit()
{
GenericTilesExit();
KonamiICExit();
konamiExit();
ZetExit();
BurnYM2151Exit();
UPD7759Exit();
if (AllMem) {
free (AllMem);
AllMem = NULL;
}
return 0;
}
static INT32 DrvDraw()
{
if (DrvRecalc) {
KonamiRecalcPal(DrvPalRAM, DrvPalette, 0x1000);
}
K052109UpdateScroll();
if (k88games_priority)
{
K052109RenderLayer(0, 1, DrvGfxROMExp0);
K051960SpritesRender(DrvGfxROMExp1, 1);
K052109RenderLayer(2, 0, DrvGfxROMExp0);
K052109RenderLayer(1, 0, DrvGfxROMExp0);
K051960SpritesRender(DrvGfxROMExp1, 0);
K051316_zoom_draw(0, 4);
}
else
{
K052109RenderLayer(2, 1, DrvGfxROMExp0);
K051316_zoom_draw(0, 4);
K051960SpritesRender(DrvGfxROMExp1, 0);
K052109RenderLayer(1, 0, DrvGfxROMExp0);
K051960SpritesRender(DrvGfxROMExp1, 1);
K052109RenderLayer(0, 0, DrvGfxROMExp0);
}
BurnTransferCopy(DrvPalette);
return 0;
}
static INT32 DrvFrame()
{
if (DrvReset) {
DrvDoReset();
}
{
memset (DrvInputs, 0xff, 3);
for (INT32 i = 0; i < 8; i++) {
DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
DrvInputs[1] ^= (DrvJoy2[i] & 1) << i;
DrvInputs[2] ^= (DrvJoy3[i] & 1) << i;
}
}
konamiNewFrame();
ZetNewFrame();
INT32 nSoundBufferPos = 0;
INT32 nInterleave = 100;
INT32 nCyclesTotal[2] = { (((3000000 / 60) * 133) / 100) /* 33% overclock */, 3579545 / 60 };
INT32 nCyclesDone[2] = { 0, 0 };
ZetOpen(0);
konamiOpen(0);
for (INT32 i = 0; i < nInterleave; i++)
{
INT32 nSegment = (nCyclesTotal[0] / nInterleave) * (i + 1);
nCyclesDone[0] += konamiRun(nSegment - nCyclesDone[0]);
nSegment = (nCyclesTotal[1] / nInterleave) * (i + 1);
nCyclesDone[1] += ZetRun(nSegment - nCyclesDone[1]);
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
BurnYM2151Render(pSoundBuf, nSegmentLength);
UPD7759Update(0, pSoundBuf, nSegmentLength);
UPD7759Update(1, pSoundBuf, nSegmentLength);
nSoundBufferPos += nSegmentLength;
}
}
if (K052109_irq_enabled) konamiSetIrqLine(KONAMI_IRQ_LINE, KONAMI_HOLD_LINE);
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
if (nSegmentLength) {
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
BurnYM2151Render(pSoundBuf, nSegmentLength);
UPD7759Update(0, pSoundBuf, nSegmentLength);
UPD7759Update(1, pSoundBuf, nSegmentLength);
}
}
konamiClose();
ZetClose();
if (pBurnDraw) {
DrvDraw();
}
return 0;
}
static INT32 DrvScan(INT32 nAction,INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) {
*pnMin = 0x029705;
}
if (nAction & ACB_VOLATILE) {
memset(&ba, 0, sizeof(ba));
ba.Data = AllRam;
ba.nLen = RamEnd - AllRam;
ba.szName = "All Ram";
BurnAcb(&ba);
konamiCpuScan(nAction, pnMin);
ZetScan(nAction);
BurnYM2151Scan(nAction);
UPD7759Scan(0, nAction, pnMin);
UPD7759Scan(0, nAction, pnMin);
KonamiICScan(nAction);
SCAN_VAR(videobank);
SCAN_VAR(zoomreadroms);
SCAN_VAR(k88games_priority);
SCAN_VAR(UPD7759Device);
}
if (nAction & ACB_WRITE) {
konamiOpen(0);
games88_set_lines(nDrvBank[0]);
konamiClose();
}
return 0;
}
// '88 Games
static struct BurnRomInfo games88RomDesc[] = {
{ "861m01.k18", 0x08000, 0x4a4e2959, 1 | BRF_PRG | BRF_ESS }, // 0 Konami Custom Cpu
{ "861m02.k16", 0x10000, 0xe19f15f6, 1 | BRF_PRG | BRF_ESS }, // 1
{ "861d01.d9", 0x08000, 0x0ff1dec0, 2 | BRF_PRG | BRF_ESS }, // 2 Z80 Code
{ "861a08.a", 0x10000, 0x77a00dd6, 3 | BRF_GRA }, // 3 K052109 Tiles
{ "861a08.c", 0x10000, 0xb422edfc, 3 | BRF_GRA }, // 4
{ "861a08.b", 0x10000, 0x28a8304f, 3 | BRF_GRA }, // 5
{ "861a08.d", 0x10000, 0xe01a3802, 3 | BRF_GRA }, // 6
{ "861a09.a", 0x10000, 0xdf8917b6, 3 | BRF_GRA }, // 7
{ "861a09.c", 0x10000, 0xf577b88f, 3 | BRF_GRA }, // 8
{ "861a09.b", 0x10000, 0x4917158d, 3 | BRF_GRA }, // 9
{ "861a09.d", 0x10000, 0x2bb3282c, 3 | BRF_GRA }, // 10
{ "861a05.a", 0x10000, 0xcedc19d0, 4 | BRF_GRA }, // 11 K051960 Tiles
{ "861a05.e", 0x10000, 0x725af3fc, 4 | BRF_GRA }, // 12
{ "861a05.b", 0x10000, 0xdb2a8808, 4 | BRF_GRA }, // 13
{ "861a05.f", 0x10000, 0x32d830ca, 4 | BRF_GRA }, // 14
{ "861a05.c", 0x10000, 0xcf03c449, 4 | BRF_GRA }, // 15
{ "861a05.g", 0x10000, 0xfd51c4ea, 4 | BRF_GRA }, // 16
{ "861a05.d", 0x10000, 0x97d78c77, 4 | BRF_GRA }, // 17
{ "861a05.h", 0x10000, 0x60d0c8a5, 4 | BRF_GRA }, // 18
{ "861a06.a", 0x10000, 0x85e2e30e, 4 | BRF_GRA }, // 19
{ "861a06.e", 0x10000, 0x6f96651c, 4 | BRF_GRA }, // 20
{ "861a06.b", 0x10000, 0xce17eaf0, 4 | BRF_GRA }, // 21
{ "861a06.f", 0x10000, 0x88310bf3, 4 | BRF_GRA }, // 22
{ "861a06.c", 0x10000, 0xa568b34e, 4 | BRF_GRA }, // 23
{ "861a06.g", 0x10000, 0x4a55beb3, 4 | BRF_GRA }, // 24
{ "861a06.d", 0x10000, 0xbc70ab39, 4 | BRF_GRA }, // 25
{ "861a06.h", 0x10000, 0xd906b79b, 4 | BRF_GRA }, // 26
{ "861a04.a", 0x10000, 0x092a8b15, 5 | BRF_GRA }, // 27 K051316 Tiles
{ "861a04.b", 0x10000, 0x75744b56, 5 | BRF_GRA }, // 28
{ "861a04.c", 0x10000, 0xa00021c5, 5 | BRF_GRA }, // 29
{ "861a04.d", 0x10000, 0xd208304c, 5 | BRF_GRA }, // 30
{ "861a07.a", 0x10000, 0x5d035d69, 6 | BRF_SND }, // 31 UPD7759 #0 Samples
{ "861a07.b", 0x10000, 0x6337dd91, 6 | BRF_SND }, // 32
{ "861a07.c", 0x10000, 0x5067a38b, 7 | BRF_SND }, // 33 UPD7759 #1 Samples
{ "861a07.d", 0x10000, 0x86731451, 7 | BRF_SND }, // 34
{ "861.g3", 0x00100, 0x429785db, 0 | BRF_OPT }, // 31 Priority Prom
};
STD_ROM_PICK(games88)
STD_ROM_FN(games88)
struct BurnDriver BurnDrvgames88 = {
"88games", NULL, NULL, NULL, "1988",
"'88 Games\0", NULL, "Konami", "GX861",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 4, HARDWARE_PREFIX_KONAMI, GBF_SPORTSMISC, 0,
NULL, games88RomInfo, games88RomName, NULL, NULL, games88InputInfo, games88DIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x800,
304, 224, 4, 3
};
// Konami '88
static struct BurnRomInfo konami88RomDesc[] = {
{ "861.e03", 0x08000, 0x55979bd9, 1 | BRF_PRG | BRF_ESS }, // 0 Konami Custom Cpu
{ "861.e02", 0x10000, 0x5b7e98a6, 1 | BRF_PRG | BRF_ESS }, // 1
{ "861d01.d9", 0x08000, 0x0ff1dec0, 2 | BRF_PRG | BRF_ESS }, // 2 Z80 Code
{ "861a08.a", 0x10000, 0x77a00dd6, 3 | BRF_GRA }, // 3 K052109 Tiles
{ "861a08.c", 0x10000, 0xb422edfc, 3 | BRF_GRA }, // 4
{ "861a08.b", 0x10000, 0x28a8304f, 3 | BRF_GRA }, // 5
{ "861a08.d", 0x10000, 0xe01a3802, 3 | BRF_GRA }, // 6
{ "861a09.a", 0x10000, 0xdf8917b6, 3 | BRF_GRA }, // 7
{ "861a09.c", 0x10000, 0xf577b88f, 3 | BRF_GRA }, // 8
{ "861a09.b", 0x10000, 0x4917158d, 3 | BRF_GRA }, // 9
{ "861a09.d", 0x10000, 0x2bb3282c, 3 | BRF_GRA }, // 10
{ "861a05.a", 0x10000, 0xcedc19d0, 4 | BRF_GRA }, // 11 K051960 Tiles
{ "861a05.e", 0x10000, 0x725af3fc, 4 | BRF_GRA }, // 12
{ "861a05.b", 0x10000, 0xdb2a8808, 4 | BRF_GRA }, // 13
{ "861a05.f", 0x10000, 0x32d830ca, 4 | BRF_GRA }, // 14
{ "861a05.c", 0x10000, 0xcf03c449, 4 | BRF_GRA }, // 15
{ "861a05.g", 0x10000, 0xfd51c4ea, 4 | BRF_GRA }, // 16
{ "861a05.d", 0x10000, 0x97d78c77, 4 | BRF_GRA }, // 17
{ "861a05.h", 0x10000, 0x60d0c8a5, 4 | BRF_GRA }, // 18
{ "861a06.a", 0x10000, 0x85e2e30e, 4 | BRF_GRA }, // 19
{ "861a06.e", 0x10000, 0x6f96651c, 4 | BRF_GRA }, // 20
{ "861a06.b", 0x10000, 0xce17eaf0, 4 | BRF_GRA }, // 21
{ "861a06.f", 0x10000, 0x88310bf3, 4 | BRF_GRA }, // 22
{ "861a06.c", 0x10000, 0xa568b34e, 4 | BRF_GRA }, // 23
{ "861a06.g", 0x10000, 0x4a55beb3, 4 | BRF_GRA }, // 24
{ "861a06.d", 0x10000, 0xbc70ab39, 4 | BRF_GRA }, // 25
{ "861a06.h", 0x10000, 0xd906b79b, 4 | BRF_GRA }, // 26
{ "861a04.a", 0x10000, 0x092a8b15, 5 | BRF_GRA }, // 27 K051316 Tiles
{ "861a04.b", 0x10000, 0x75744b56, 5 | BRF_GRA }, // 28
{ "861a04.c", 0x10000, 0xa00021c5, 5 | BRF_GRA }, // 29
{ "861a04.d", 0x10000, 0xd208304c, 5 | BRF_GRA }, // 30
{ "861a07.a", 0x10000, 0x5d035d69, 6 | BRF_SND }, // 31 UPD7759 #0 Samples
{ "861a07.b", 0x10000, 0x6337dd91, 6 | BRF_SND }, // 32
{ "861a07.c", 0x10000, 0x5067a38b, 7 | BRF_SND }, // 33 UPD7759 #1 Samples
{ "861a07.d", 0x10000, 0x86731451, 7 | BRF_SND }, // 34
{ "861.g3", 0x00100, 0x429785db, 0 | BRF_OPT }, // 31 Priority Prom
};
STD_ROM_PICK(konami88)
STD_ROM_FN(konami88)
struct BurnDriver BurnDrvKonami88 = {
"konami88", "88games", NULL, NULL, "1988",
"Konami '88\0", NULL, "Konami", "GX861",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 4, HARDWARE_PREFIX_KONAMI, GBF_SPORTSMISC, 0,
NULL, konami88RomInfo, konami88RomName, NULL, NULL, games88InputInfo, games88DIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x800,
304, 224, 4, 3
};
// Hyper Sports Special (Japan)
static struct BurnRomInfo hypsptspRomDesc[] = {
{ "861f03.k18", 0x08000, 0x8c61aebd, 1 | BRF_PRG | BRF_ESS }, // 0 Konami Custom Cpu
{ "861f02.k16", 0x10000, 0xd2460c28, 1 | BRF_PRG | BRF_ESS }, // 1
{ "861d01.d9", 0x08000, 0x0ff1dec0, 2 | BRF_PRG | BRF_ESS }, // 2 Z80 Code
{ "861a08.a", 0x10000, 0x77a00dd6, 3 | BRF_GRA }, // 3 K052109 Tiles
{ "861a08.c", 0x10000, 0xb422edfc, 3 | BRF_GRA }, // 4
{ "861a08.b", 0x10000, 0x28a8304f, 3 | BRF_GRA }, // 5
{ "861a08.d", 0x10000, 0xe01a3802, 3 | BRF_GRA }, // 6
{ "861a09.a", 0x10000, 0xdf8917b6, 3 | BRF_GRA }, // 7
{ "861a09.c", 0x10000, 0xf577b88f, 3 | BRF_GRA }, // 8
{ "861a09.b", 0x10000, 0x4917158d, 3 | BRF_GRA }, // 9
{ "861a09.d", 0x10000, 0x2bb3282c, 3 | BRF_GRA }, // 10
{ "861a05.a", 0x10000, 0xcedc19d0, 4 | BRF_GRA }, // 11 K051960 Tiles
{ "861a05.e", 0x10000, 0x725af3fc, 4 | BRF_GRA }, // 12
{ "861a05.b", 0x10000, 0xdb2a8808, 4 | BRF_GRA }, // 13
{ "861a05.f", 0x10000, 0x32d830ca, 4 | BRF_GRA }, // 14
{ "861a05.c", 0x10000, 0xcf03c449, 4 | BRF_GRA }, // 15
{ "861a05.g", 0x10000, 0xfd51c4ea, 4 | BRF_GRA }, // 16
{ "861a05.d", 0x10000, 0x97d78c77, 4 | BRF_GRA }, // 17
{ "861a05.h", 0x10000, 0x60d0c8a5, 4 | BRF_GRA }, // 18
{ "861a06.a", 0x10000, 0x85e2e30e, 4 | BRF_GRA }, // 19
{ "861a06.e", 0x10000, 0x6f96651c, 4 | BRF_GRA }, // 20
{ "861a06.b", 0x10000, 0xce17eaf0, 4 | BRF_GRA }, // 21
{ "861a06.f", 0x10000, 0x88310bf3, 4 | BRF_GRA }, // 22
{ "861a06.c", 0x10000, 0xa568b34e, 4 | BRF_GRA }, // 23
{ "861a06.g", 0x10000, 0x4a55beb3, 4 | BRF_GRA }, // 24
{ "861a06.d", 0x10000, 0xbc70ab39, 4 | BRF_GRA }, // 25
{ "861a06.h", 0x10000, 0xd906b79b, 4 | BRF_GRA }, // 26
{ "861a04.a", 0x10000, 0x092a8b15, 5 | BRF_GRA }, // 27 K051316 Tiles
{ "861a04.b", 0x10000, 0x75744b56, 5 | BRF_GRA }, // 28
{ "861a04.c", 0x10000, 0xa00021c5, 5 | BRF_GRA }, // 29
{ "861a04.d", 0x10000, 0xd208304c, 5 | BRF_GRA }, // 30
{ "861a07.a", 0x10000, 0x5d035d69, 6 | BRF_SND }, // 31 UPD7759 #0 Samples
{ "861a07.b", 0x10000, 0x6337dd91, 6 | BRF_SND }, // 32
{ "861a07.c", 0x10000, 0x5067a38b, 7 | BRF_SND }, // 33 UPD7759 #1 Samples
{ "861a07.d", 0x10000, 0x86731451, 7 | BRF_SND }, // 34
{ "861.g3", 0x00100, 0x429785db, 8 | BRF_OPT }, // 31 Priority Prom
};
STD_ROM_PICK(hypsptsp)
STD_ROM_FN(hypsptsp)
struct BurnDriver BurnDrvHypsptsp = {
"hypsptsp", "88games", NULL, NULL, "1988",
"Hyper Sports Special (Japan)\0", NULL, "Konami", "GX861",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 4, HARDWARE_PREFIX_KONAMI, GBF_SPORTSMISC, 0,
NULL, hypsptspRomInfo, hypsptspRomName, NULL, NULL, games88InputInfo, games88DIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x800,
304, 224, 4, 3
};

View File

@ -0,0 +1,940 @@
// FB Alpha Ajax driver module
// Based on MAME driver by Manuel Abadia
#include "tiles_generic.h"
#include "konami_intf.h"
#include "konamiic.h"
#include "burn_ym2151.h"
#include "k007232.h"
#include "m6809_intf.h"
static UINT8 *AllMem;
static UINT8 *MemEnd;
static UINT8 *AllRam;
static UINT8 *RamEnd;
static UINT8 *DrvKonROM;
static UINT8 *DrvM6809ROM;
static UINT8 *DrvZ80ROM;
static UINT8 *DrvGfxROM0;
static UINT8 *DrvGfxROM1;
static UINT8 *DrvGfxROM2;
static UINT8 *DrvGfxROMExp0;
static UINT8 *DrvGfxROMExp1;
static UINT8 *DrvSndROM0;
static UINT8 *DrvSndROM1;
static UINT8 *DrvShareRAM;
static UINT8 *DrvKonRAM;
static UINT8 *DrvPalRAM;
static UINT8 *DrvZ80RAM;
static UINT32 *DrvPalette;
static UINT8 DrvRecalc;
static UINT8 *soundlatch;
static UINT8 *nDrvBankRom;
static UINT8 DrvInputs[3];
static UINT8 DrvJoy1[8];
static UINT8 DrvJoy2[8];
static UINT8 DrvJoy3[8];
static UINT8 DrvDips[3];
static UINT8 DrvReset;
static INT32 firq_enable;
static INT32 ajax_priority;
static struct BurnInputInfo AjaxInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 0, "p1 coin" },
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 3, "p1 start" },
{"P1 Up", BIT_DIGITAL, DrvJoy2 + 2, "p1 up" },
{"P1 Down", BIT_DIGITAL, DrvJoy2 + 3, "p1 down" },
{"P1 Left", BIT_DIGITAL, DrvJoy2 + 0, "p1 left" },
{"P1 Right", BIT_DIGITAL, DrvJoy2 + 1, "p1 right" },
{"P1 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p1 fire 1" },
{"P1 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p1 fire 2" },
{"P1 Button 3", BIT_DIGITAL, DrvJoy2 + 6, "p1 fire 3" },
{"P2 Coin", BIT_DIGITAL, DrvJoy1 + 1, "p2 coin" },
{"P2 Start", BIT_DIGITAL, DrvJoy1 + 4, "p2 start" },
{"P2 Up", BIT_DIGITAL, DrvJoy3 + 2, "p2 up" },
{"P2 Down", BIT_DIGITAL, DrvJoy3 + 3, "p2 down" },
{"P2 Left", BIT_DIGITAL, DrvJoy3 + 0, "p2 left" },
{"P2 Right", BIT_DIGITAL, DrvJoy3 + 1, "p2 right" },
{"P2 Button 1", BIT_DIGITAL, DrvJoy3 + 4, "p2 fire 1" },
{"P2 Button 2", BIT_DIGITAL, DrvJoy3 + 5, "p2 fire 2" },
{"P2 Button 3", BIT_DIGITAL, DrvJoy3 + 6, "p2 fire 3" },
{"Reset", BIT_DIGITAL, &DrvReset, "reset"},
{"Service", BIT_DIGITAL, DrvJoy1 + 2, "service" },
{"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" },
{"Dip B", BIT_DIPSWITCH, DrvDips + 1, "dip" },
{"Dip C", BIT_DIPSWITCH, DrvDips + 2, "dip" },
};
STDINPUTINFO(Ajax)
static struct BurnDIPInfo AjaxDIPList[]=
{
{0x14, 0xff, 0xff, 0xff, NULL },
{0x15, 0xff, 0xff, 0x52, NULL },
{0x16, 0xff, 0xff, 0xff, NULL },
{0 , 0xfe, 0 , 16, "Coin A" },
{0x14, 0x01, 0x0f, 0x02, "4 Coins 1 Credit" },
{0x14, 0x01, 0x0f, 0x05, "3 Coins 1 Credit" },
{0x14, 0x01, 0x0f, 0x08, "2 Coins 1 Credit" },
{0x14, 0x01, 0x0f, 0x04, "3 Coins 2 Credits" },
{0x14, 0x01, 0x0f, 0x01, "4 Coins 3 Credits" },
{0x14, 0x01, 0x0f, 0x0f, "1 Coin 1 Credit" },
{0x14, 0x01, 0x0f, 0x03, "3 Coins 4 Credits" },
{0x14, 0x01, 0x0f, 0x07, "2 Coins 3 Credits" },
{0x14, 0x01, 0x0f, 0x0e, "1 Coin 2 Credits" },
{0x14, 0x01, 0x0f, 0x06, "2 Coins 5 Credits" },
{0x14, 0x01, 0x0f, 0x0d, "1 Coin 3 Credits" },
{0x14, 0x01, 0x0f, 0x0c, "1 Coin 4 Credits" },
{0x14, 0x01, 0x0f, 0x0b, "1 Coin 5 Credits" },
{0x14, 0x01, 0x0f, 0x0a, "1 Coin 6 Credits" },
{0x14, 0x01, 0x0f, 0x09, "1 Coin 7 Credits" },
{0x14, 0x01, 0x0f, 0x00, "Free Play" },
{0 , 0xfe, 0 , 15, "Coin B" },
{0x14, 0x01, 0xf0, 0x20, "4 Coins 1 Credit" },
{0x14, 0x01, 0xf0, 0x50, "3 Coins 1 Credit" },
{0x14, 0x01, 0xf0, 0x80, "2 Coins 1 Credit" },
{0x14, 0x01, 0xf0, 0x40, "3 Coins 2 Credits" },
{0x14, 0x01, 0xf0, 0x10, "4 Coins 3 Credits" },
{0x14, 0x01, 0xf0, 0xf0, "1 Coin 1 Credit" },
{0x14, 0x01, 0xf0, 0x30, "3 Coins 4 Credits" },
{0x14, 0x01, 0xf0, 0x70, "2 Coins 3 Credits" },
{0x14, 0x01, 0xf0, 0xe0, "1 Coin 2 Credits" },
{0x14, 0x01, 0xf0, 0x60, "2 Coins 5 Credits" },
{0x14, 0x01, 0xf0, 0xd0, "1 Coin 3 Credits" },
{0x14, 0x01, 0xf0, 0xc0, "1 Coin 4 Credits" },
{0x14, 0x01, 0xf0, 0xb0, "1 Coin 5 Credits" },
{0x14, 0x01, 0xf0, 0xa0, "1 Coin 6 Credits" },
{0x14, 0x01, 0xf0, 0x90, "1 Coin 7 Credits" },
{0 , 0xfe, 0 , 4, "Lives" },
{0x15, 0x01, 0x03, 0x03, "2" },
{0x15, 0x01, 0x03, 0x02, "3" },
{0x15, 0x01, 0x03, 0x01, "5" },
{0x15, 0x01, 0x03, 0x00, "7" },
// {0 , 0xfe, 0 , 2, "Cabinet" },
// {0x15, 0x01, 0x04, 0x00, "Upright" },
// {0x15, 0x01, 0x04, 0x04, "Cocktail" },
{0 , 0xfe, 0 , 4, "Bonus Life" },
{0x15, 0x01, 0x18, 0x18, "30000 150000" },
{0x15, 0x01, 0x18, 0x10, "50000 200000" },
{0x15, 0x01, 0x18, 0x08, "30000" },
{0x15, 0x01, 0x18, 0x00, "50000" },
{0 , 0xfe, 0 , 4, "Difficulty" },
{0x15, 0x01, 0x60, 0x60, "Easy" },
{0x15, 0x01, 0x60, 0x40, "Normal" },
{0x15, 0x01, 0x60, 0x20, "Difficult" },
{0x15, 0x01, 0x60, 0x00, "Very Difficult" },
{0 , 0xfe, 0 , 2, "Demo Sounds" },
{0x15, 0x01, 0x80, 0x80, "Off" },
{0x15, 0x01, 0x80, 0x00, "On" },
// {0 , 0xfe, 0 , 2, "Flip Screen" },
// {0x16, 0x01, 0x01, 0x01, "Off" },
// {0x16, 0x01, 0x01, 0x00, "On" },
{0 , 0xfe, 0 , 2, "Upright Controls" },
{0x16, 0x01, 0x02, 0x02, "Single" },
{0x16, 0x01, 0x02, 0x00, "Dual" },
{0 , 0xfe, 0 , 2, "Service Mode" },
{0x16, 0x01, 0x04, 0x04, "Off" },
{0x16, 0x01, 0x04, 0x00, "On" },
{0 , 0xfe, 0 , 2, "Control in 3D Stages" },
{0x16, 0x01, 0x08, 0x08, "Normal" },
{0x16, 0x01, 0x08, 0x00, "Inverted" },
};
STDDIPINFO(Ajax)
static void ajax_main_bankswitch(INT32 data)
{
nDrvBankRom[0] = data;
INT32 nBank = 0x10000 + ((data & 0x80) << 9) + ((data & 7) << 13);
ajax_priority = data & 0x08;
konamiMapMemory(DrvKonROM + nBank, 0x6000, 0x7fff, KON_ROM);
}
void ajax_main_write(UINT16 address, UINT8 data)
{
if (address <= 0x1c0)
{
switch ((address & 0x01c0) >> 6)
{
case 0x0000:
if (address == 0 && firq_enable) {
M6809SetIRQ(1, M6809_IRQSTATUS_AUTO);
}
break;
case 0x0001:
ZetSetIRQLine(0, ZET_IRQSTATUS_ACK);
break;
case 0x0002:
*soundlatch = data;
break;
case 0x0003:
ajax_main_bankswitch(data);
break;
}
}
if ((address & 0xfff8) == 0x0800) {
K051937Write(address & 7, data);
return;
}
if ((address & 0xfc00) == 0x0c00) {
K051960Write(address & 0x3ff, data);
return;
}
}
UINT8 ajax_main_read(UINT16 address)
{
if (address <= 0x01c0) {
switch ((address & 0x1c0) >> 6)
{
case 0x0000:
return konamiTotalCycles() & 0xff; // rand
case 0x0004:
return DrvInputs[2];
case 0x0006:
switch (address & 3) {
case 0:
return DrvInputs[0];
case 1:
return DrvInputs[1];
case 2:
return DrvDips[0];
case 3:
return DrvDips[1];
}
return 0;
case 0x0007:
return DrvDips[2];
}
}
if ((address & 0xfff8) == 0x0800) {
return K051937Read(address & 7);
}
if ((address & 0xfc00) == 0x0c00) {
return K051960Read(address & 0x3ff);
}
return 0;
}
static void ajax_sub_bankswitch(UINT8 data)
{
nDrvBankRom[1] = data;
K052109RMRDLine = data & 0x40;
K051316WrapEnable(0, data & 0x20);
firq_enable = data & 0x10;
INT32 nBank = ((data & 0x0f) << 13) + 0x10000;
M6809MapMemory(DrvM6809ROM + nBank, 0x8000, 0x9fff, M6809_ROM);
}
void ajax_sub_write(UINT16 address, UINT8 data)
{
if ((address & 0xf800) == 0x0000) {
K051316Write(0, address & 0x7ff, data);
return;
}
if ((address & 0xfff0) == 0x0800) {
K051316WriteCtrl(0, address & 0x0f, data);
return;
}
if (address == 0x1800) {
ajax_sub_bankswitch(data);
return;
}
if ((address & 0xc000) == 0x4000) {
K052109Write(address & 0x3fff, data);
return;
}
}
UINT8 ajax_sub_read(UINT16 address)
{
if ((address & 0xf800) == 0x0000) {
return K051316Read(0, address & 0x7ff);
}
if ((address & 0xf800) == 0x1000) {
return K051316ReadRom(0, address & 0x7ff);
}
if ((address & 0xc000) == 0x4000) {
return K052109Read(address & 0x3fff);
}
return 0;
}
void __fastcall ajax_sound_write(UINT16 address, UINT8 data)
{
if ((address & 0xfff0) == 0xa000) {
K007232WriteReg(0, address & 0x0f, data);
return;
}
if ((address & 0xfff0) == 0xb000) {
K007232WriteReg(1, address & 0x0f, data);
return;
}
switch (address)
{
case 0x9000:
k007232_set_bank(0, (data >> 1) & 1, (data >> 0) & 1 );
k007232_set_bank(1, (data >> 4) & 3, (data >> 2) & 3 );
return;
case 0xb80c:
K007232SetVolume(1, 0, (data & 0x0f) * 0x11/2, (data & 0x0f) * 0x11/2);
return;
case 0xc000:
BurnYM2151SelectRegister(data);
return;
case 0xc001:
BurnYM2151WriteRegister(data);
return;
}
}
UINT8 __fastcall ajax_sound_read(UINT16 address)
{
if ((address & 0xfff0) == 0xa000) {
return K007232ReadReg(0, address & 0x0f);
}
if ((address & 0xfff0) == 0xb000) {
return K007232ReadReg(1, address & 0x0f);
}
switch (address)
{
case 0xc000:
case 0xc001:
return BurnYM2151ReadStatus();
case 0xe000:
ZetSetIRQLine(0, ZET_IRQSTATUS_NONE);
return *soundlatch;
}
return 0;
}
static void K052109Callback(INT32 layer, INT32 bank, INT32 *code, INT32 *color, INT32 *, INT32 *)
{
INT32 layer_colorbase[3] = { 64, 0, 32 };
*code |= ((*color & 0x0f) << 8) | (bank << 12);
*code &= 0x3fff;
*color = layer_colorbase[layer] + ((*color & 0xf0) >> 4);
}
static void K051960Callback(INT32 *code, INT32 *color,INT32 *priority, INT32 *)
{
*priority = 0;
if ( *color & 0x10) *priority = 1;
if (~*color & 0x40) *priority = 2;
if ( *color & 0x20) *priority = 3;
*color = 16 + (*color & 0x0f);
*code &= 0x1fff;
}
static void K051316Callback(INT32 *code,INT32 *color,INT32 *)
{
*code |= ((*color & 0x07) << 8);
*code &= 0x7ff;
*color = 6 + ((*color & 0x08) >> 3);
}
static void DrvK007232VolCallback0(INT32 v)
{
K007232SetVolume(0, 0, (v >> 0x4) * 0x11, 0);
K007232SetVolume(0, 1, 0, (v & 0x0f) * 0x11);
}
static void DrvK007232VolCallback1(INT32 v)
{
K007232SetVolume(1, 0, (v & 0x0f) * 0x11/2, (v & 0x0f) * 0x11/2);
}
static INT32 DrvDoReset()
{
DrvReset = 0;
memset (AllRam, 0, RamEnd - AllRam);
konamiOpen(0);
konamiReset();
konamiClose();
M6809Open(0);
M6809Reset();
M6809Close();
ZetOpen(0);
ZetReset();
ZetClose();
BurnYM2151Reset();
KonamiICReset();
firq_enable = 0;
ajax_priority = 0;
return 0;
}
static INT32 MemIndex()
{
UINT8 *Next; Next = AllMem;
DrvKonROM = Next; Next += 0x030000;
DrvM6809ROM = Next; Next += 0x030000;
DrvZ80ROM = Next; Next += 0x010000;
DrvGfxROM0 = Next; Next += 0x080000;
DrvGfxROM1 = Next; Next += 0x100000;
DrvGfxROM2 = Next; Next += 0x080000;
DrvGfxROMExp0 = Next; Next += 0x100000;
DrvGfxROMExp1 = Next; Next += 0x200000;
DrvSndROM0 = Next; Next += 0x040000;
DrvSndROM1 = Next; Next += 0x080000;
DrvPalette = (UINT32*)Next; Next += 0x800 * sizeof(UINT32);
AllRam = Next;
DrvShareRAM = Next; Next += 0x002000;
DrvKonRAM = Next; Next += 0x002000;
DrvPalRAM = Next; Next += 0x001000 + 0x1000;
DrvZ80RAM = Next; Next += 0x000800;
soundlatch = Next; Next += 0x000001;
nDrvBankRom = Next; Next += 0x000002;
RamEnd = Next;
MemEnd = Next;
return 0;
}
static INT32 DrvGfxDecode()
{
INT32 Plane0[4] = { 0x018, 0x010, 0x008, 0x000 };
INT32 Plane1[4] = { 0x000, 0x008, 0x010, 0x018 };
INT32 XOffs0[16] = { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107 };
INT32 YOffs0[16] = { 0x000, 0x020, 0x040, 0x060, 0x080, 0x0a0, 0x0c0, 0x0e0,
0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0 };
konami_rom_deinterleave_2(DrvGfxROM0, 0x080000);
konami_rom_deinterleave_2(DrvGfxROM1, 0x100000);
GfxDecode(0x04000, 4, 8, 8, Plane0, XOffs0, YOffs0, 0x100, DrvGfxROM0, DrvGfxROMExp0);
GfxDecode(0x02000, 4, 16, 16, Plane1, XOffs0, YOffs0, 0x400, DrvGfxROM1, DrvGfxROMExp1);
return 0;
}
static INT32 DrvInit()
{
AllMem = NULL;
MemIndex();
INT32 nLen = MemEnd - (UINT8 *)0;
if ((AllMem = (UINT8 *)malloc(nLen)) == NULL) return 1;
memset(AllMem, 0, nLen);
MemIndex();
{
if (BurnLoadRom(DrvKonROM + 0x020000, 0, 1)) return 1;
if (BurnLoadRom(DrvKonROM + 0x010000, 1, 1)) return 1;
memcpy (DrvKonROM + 0x08000, DrvKonROM + 0x28000, 0x8000);
if (BurnLoadRom(DrvM6809ROM + 0x20000, 2, 1)) return 1;
memcpy (DrvM6809ROM + 0xa000, DrvM6809ROM + 0x22000, 0x6000);
if (BurnLoadRom(DrvM6809ROM + 0x10000, 3, 1)) return 1;
if (BurnLoadRom(DrvZ80ROM + 0x000000, 4, 1)) return 1;
if (strcmp(BurnDrvGetTextA(DRV_NAME), "ajax") == 0) {
if (BurnLoadRom(DrvGfxROM0 + 0x000000, 5, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x000001, 6, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x020000, 7, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x020001, 8, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x040000, 9, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x040001, 10, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x060000, 11, 2)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x060001, 12, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x000000, 13, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x000001, 14, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x020000, 15, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x020001, 16, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x040000, 17, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x040001, 18, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x060000, 19, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x060001, 20, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x080000, 21, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x080001, 22, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0a0000, 23, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0a0001, 24, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0c0000, 25, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0c0001, 26, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0e0000, 27, 2)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x0e0001, 28, 2)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x000000, 29, 1)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x040000, 30, 1)) return 1;
if (BurnLoadRom(DrvSndROM0 + 0x000000, 31, 1)) return 1;
if (BurnLoadRom(DrvSndROM0 + 0x010000, 32, 1)) return 1;
if (BurnLoadRom(DrvSndROM0 + 0x020000, 33, 1)) return 1;
if (BurnLoadRom(DrvSndROM0 + 0x030000, 34, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x000000, 35, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x010000, 36, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x020000, 37, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x030000, 38, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x040000, 39, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x050000, 40, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x060000, 41, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x070000, 42, 1)) return 1;
} else {
if (BurnLoadRom(DrvGfxROM0 + 0x000000, 5, 1)) return 1;
if (BurnLoadRom(DrvGfxROM0 + 0x040000, 6, 1)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x000000, 7, 1)) return 1;
if (BurnLoadRom(DrvGfxROM1 + 0x080000, 8, 1)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x000000, 9, 1)) return 1;
if (BurnLoadRom(DrvGfxROM2 + 0x040000, 10, 1)) return 1;
if (BurnLoadRom(DrvSndROM0 + 0x000000, 11, 1)) return 1;
if (BurnLoadRom(DrvSndROM1 + 0x000000, 12, 1)) return 1;
}
DrvGfxDecode();
}
konamiInit(1);
konamiOpen(0);
konamiMapMemory(DrvPalRAM, 0x1000, 0x1fff, KON_RAM);
konamiMapMemory(DrvShareRAM, 0x2000, 0x3fff, KON_RAM);
konamiMapMemory(DrvKonRAM, 0x4000, 0x5fff, KON_RAM);
konamiMapMemory(DrvKonROM + 0x10000, 0x6000, 0x7fff, KON_ROM);
konamiMapMemory(DrvKonROM + 0x08000, 0x8000, 0xffff, KON_ROM);
konamiSetWriteHandler(ajax_main_write);
konamiSetReadHandler(ajax_main_read);
konamiClose();
M6809Init(1);
M6809Open(0);
M6809MapMemory(DrvShareRAM, 0x2000, 0x3fff, M6809_RAM);
M6809MapMemory(DrvM6809ROM + 0x10000, 0x8000, 0x9fff, M6809_ROM);
M6809MapMemory(DrvM6809ROM + 0x0a000, 0xa000, 0xffff, M6809_ROM);
M6809SetWriteByteHandler(ajax_sub_write);
M6809SetReadByteHandler(ajax_sub_read);
M6809Close();
ZetInit(1);
ZetOpen(0);
ZetMapArea(0x0000, 0x7fff, 0, DrvZ80ROM);
ZetMapArea(0x0000, 0x7fff, 2, DrvZ80ROM);
ZetMapArea(0x8000, 0x87ff, 0, DrvZ80RAM);
ZetMapArea(0x8000, 0x87ff, 1, DrvZ80RAM);
ZetMapArea(0x8000, 0x87ff, 2, DrvZ80RAM);
ZetSetWriteHandler(ajax_sound_write);
ZetSetReadHandler(ajax_sound_read);
ZetMemEnd();
ZetClose();
BurnYM2151Init(3579545, 25.0);
K007232Init(0, 3579545, DrvSndROM0, 0x40000);
K007232SetPortWriteHandler(0, DrvK007232VolCallback0);
K007232Init(1, 3579545, DrvSndROM1, 0x80000);
K007232SetPortWriteHandler(1, DrvK007232VolCallback1);
K052109Init(DrvGfxROM0, 0x7ffff);
K052109SetCallback(K052109Callback);
K052109AdjustScroll(8, 0);
K051960Init(DrvGfxROM1, 0xfffff);
K051960SetCallback(K051960Callback);
K051960SetSpriteOffset(8, 0);
K051316Init(0, DrvGfxROM2, DrvGfxROM2, 0x7ffff, K051316Callback, 7, 0);
K051316SetOffset(0, -112, -16);
GenericTilesInit();
DrvDoReset();
return 0;
}
static INT32 DrvExit()
{
GenericTilesExit();
KonamiICExit();
M6809Exit();
konamiExit();
ZetExit();
K007232Exit();
BurnYM2151Exit();
if (AllMem) {
free (AllMem);
AllMem = NULL;
}
return 0;
}
static INT32 DrvDraw()
{
if (DrvRecalc) {
KonamiRecalcPal(DrvPalRAM, DrvPalette, 0x1000);
}
K052109UpdateScroll();
BurnTransferClear();
if (nBurnLayer & 1) K052109RenderLayer(2, 0, DrvGfxROMExp0);
if (ajax_priority)
{
if (nBurnLayer & 2) K051316_zoom_draw(0, 4);
if (nBurnLayer & 4) K052109RenderLayer(1, 0, DrvGfxROMExp0);
}
else
{
if (nBurnLayer & 4) K052109RenderLayer(1, 0, DrvGfxROMExp0);
if (nBurnLayer & 2) K051316_zoom_draw(0, 4);
}
// needs work...
if (nSpriteEnable & 1) K051960SpritesRender(DrvGfxROMExp1, 3);
if (nSpriteEnable & 2) K051960SpritesRender(DrvGfxROMExp1, 2);
if (nSpriteEnable & 4) K051960SpritesRender(DrvGfxROMExp1, 1);
if (nSpriteEnable & 8) K051960SpritesRender(DrvGfxROMExp1, 0);
if (nBurnLayer & 8) K052109RenderLayer(0, 0, DrvGfxROMExp0);
BurnTransferCopy(DrvPalette);
return 0;
}
static INT32 DrvFrame()
{
if (DrvReset) {
DrvDoReset();
}
{
memset (DrvInputs, 0xff, 3);
for (INT32 i = 0; i < 8; i++) {
DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
DrvInputs[1] ^= (DrvJoy2[i] & 1) << i;
DrvInputs[2] ^= (DrvJoy3[i] & 1) << i;
}
// Clear opposites
if ((DrvInputs[1] & 0x03) == 0) DrvInputs[1] |= 0x03;
if ((DrvInputs[1] & 0x0c) == 0) DrvInputs[1] |= 0x0c;
if ((DrvInputs[2] & 0x03) == 0) DrvInputs[2] |= 0x03;
if ((DrvInputs[2] & 0x0c) == 0) DrvInputs[2] |= 0x0c;
}
INT32 nSoundBufferPos = 0;
INT32 nInterleave = 100;
INT32 nCyclesTotal[3] = { (((3000000 / 60) * 133) / 100) /* 33% overclock */, 3000000 / 60, 3579545 / 60 };
INT32 nCyclesDone[3] = { 0, 0, 0 };
ZetOpen(0);
M6809Open(0);
konamiOpen(0);
for (INT32 i = 0; i < nInterleave; i++)
{
INT32 nSegment = (nCyclesTotal[0] / nInterleave) * (i + 1);
nCyclesDone[0] += konamiRun(nSegment - nCyclesDone[0]);
nCyclesDone[1] += M6809Run(nSegment - nCyclesDone[1]);
nSegment = (nCyclesTotal[2] / nInterleave) * (i + 1);
nCyclesDone[2] += ZetRun(nSegment - nCyclesDone[2]);
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
BurnYM2151Render(pSoundBuf, nSegmentLength);
K007232Update(0, pSoundBuf, nSegmentLength);
K007232Update(1, pSoundBuf, nSegmentLength);
nSoundBufferPos += nSegmentLength;
}
}
if (K051960_irq_enabled) konamiSetIrqLine(KONAMI_IRQ_LINE, KONAMI_HOLD_LINE);
if (pBurnSoundOut) {
INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
if (nSegmentLength) {
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
BurnYM2151Render(pSoundBuf, nSegmentLength);
K007232Update(0, pSoundBuf, nSegmentLength);
K007232Update(1, pSoundBuf, nSegmentLength);
}
}
konamiClose();
M6809Close();
ZetClose();
if (pBurnDraw) {
DrvDraw();
}
return 0;
}
static INT32 DrvScan(INT32 nAction,INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin) {
*pnMin = 0x029705;
}
if (nAction & ACB_VOLATILE) {
memset(&ba, 0, sizeof(ba));
ba.Data = AllRam;
ba.nLen = RamEnd - AllRam;
ba.szName = "All Ram";
BurnAcb(&ba);
konamiCpuScan(nAction, pnMin);
M6809Scan(nAction);
ZetScan(nAction);
BurnYM2151Scan(nAction);
K007232Scan(nAction, pnMin);
KonamiICScan(nAction);
}
if (nAction & ACB_WRITE) {
konamiOpen(0);
ajax_main_bankswitch(nDrvBankRom[0]);
konamiClose();
M6809Open(0);
ajax_sub_bankswitch(nDrvBankRom[1]);
M6809Close();
}
return 0;
}
// Ajax
static struct BurnRomInfo ajaxRomDesc[] = {
{ "770_m01.n11", 0x10000, 0x4a64e53a, 1 | BRF_PRG | BRF_ESS }, // 0 Konami Custom Code
{ "770_l02.n12", 0x10000, 0xad7d592b, 1 | BRF_PRG | BRF_ESS }, // 1
{ "770_l05.i16", 0x08000, 0xed64fbb2, 2 | BRF_PRG | BRF_ESS }, // 2 M6809 Code
{ "770_f04.g16", 0x10000, 0xe0e4ec9c, 2 | BRF_PRG | BRF_ESS }, // 3
{ "770_h03.f16", 0x08000, 0x2ffd2afc, 3 | BRF_PRG | BRF_ESS }, // 4 Z80 Code
{ "770c13-a.f3", 0x10000, 0x4ef6fff2, 4 | BRF_GRA }, // 5 K052109 Tiles
{ "770c13-c.f4", 0x10000, 0x97ffbab6, 4 | BRF_GRA }, // 6
{ "770c13-b.e3", 0x10000, 0x86fdd706, 4 | BRF_GRA }, // 7
{ "770c13-d.e4", 0x10000, 0x7d7acb2d, 4 | BRF_GRA }, // 8
{ "770c12-a.f5", 0x10000, 0x6c0ade68, 4 | BRF_GRA }, // 9
{ "770c12-c.f6", 0x10000, 0x61fc39cc, 4 | BRF_GRA }, // 10
{ "770c12-b.e5", 0x10000, 0x5f221cc6, 4 | BRF_GRA }, // 11
{ "770c12-d.e6", 0x10000, 0xf1edb2f4, 4 | BRF_GRA }, // 12
{ "770c09-a.f8", 0x10000, 0x76690fb8, 5 | BRF_GRA }, // 13 K051960 Tiles
{ "770c09-e.f9", 0x10000, 0x17b482c9, 5 | BRF_GRA }, // 14
{ "770c09-b.e8", 0x10000, 0xcd1709d1, 5 | BRF_GRA }, // 15
{ "770c09-f.e9", 0x10000, 0xcba4b47e, 5 | BRF_GRA }, // 16
{ "770c09-c.d8", 0x10000, 0xbfd080b8, 5 | BRF_GRA }, // 17
{ "770c09-g.d9", 0x10000, 0x77d58ea0, 5 | BRF_GRA }, // 18
{ "770c09-d.c8", 0x10000, 0x6f955600, 5 | BRF_GRA }, // 19
{ "770c09-h.c9", 0x10000, 0x494a9090, 5 | BRF_GRA }, // 20
{ "770c08-a.f10", 0x10000, 0xefd29a56, 5 | BRF_GRA }, // 21
{ "770c08-e.f11", 0x10000, 0x6d43afde, 5 | BRF_GRA }, // 22
{ "770c08-b.e10", 0x10000, 0xf3374014, 5 | BRF_GRA }, // 23
{ "770c08-f.e11", 0x10000, 0xf5ba59aa, 5 | BRF_GRA }, // 24
{ "770c08-c.d10", 0x10000, 0x28e7088f, 5 | BRF_GRA }, // 25
{ "770c08-g.d11", 0x10000, 0x17da8f6d, 5 | BRF_GRA }, // 26
{ "770c08-d.c10", 0x10000, 0x91591777, 5 | BRF_GRA }, // 27
{ "770c08-h.c11", 0x10000, 0xd97d4b15, 5 | BRF_GRA }, // 28
{ "770c06", 0x40000, 0xd0c592ee, 6 | BRF_GRA }, // 29 K051960 Tiles
{ "770c07", 0x40000, 0x0b399fb1, 6 | BRF_GRA }, // 30
{ "770c10-a.a7", 0x10000, 0xe45ec094, 7 | BRF_SND }, // 31 K007232 #0 Samples
{ "770c10-b.a6", 0x10000, 0x349db7d3, 7 | BRF_SND }, // 32
{ "770c10-c.a5", 0x10000, 0x71cb1f05, 7 | BRF_SND }, // 33
{ "770c10-d.a4", 0x10000, 0xe8ab1844, 7 | BRF_SND }, // 34
{ "770c11-a.c6", 0x10000, 0x8cccd9e0, 8 | BRF_SND }, // 35 K007232 #1 Samples
{ "770c11-b.c5", 0x10000, 0x0af2fedd, 8 | BRF_SND }, // 36
{ "770c11-c.c4", 0x10000, 0x7471f24a, 8 | BRF_SND }, // 37
{ "770c11-d.c3", 0x10000, 0xa58be323, 8 | BRF_SND }, // 38
{ "770c11-e.b7", 0x10000, 0xdd553541, 8 | BRF_SND }, // 39
{ "770c11-f.b6", 0x10000, 0x3f78bd0f, 8 | BRF_SND }, // 40
{ "770c11-g.b5", 0x10000, 0x078c51b2, 8 | BRF_SND }, // 41
{ "770c11-h.b4", 0x10000, 0x7300c2e1, 8 | BRF_SND }, // 42
{ "63s241.j11", 0x00200, 0x9bdd719f, 9 | BRF_OPT }, // 43 Timing Prom (unused)
};
STD_ROM_PICK(ajax)
STD_ROM_FN(ajax)
struct BurnDriver BurnDrvAjax = {
"ajax", NULL, NULL, NULL, "1987",
"Ajax\0", NULL, "Konami", "GX770",
L"Ajax\0\u30A8\u30FC\u30B8\u30E3\u30C3\u30AF\u30B9\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED, 2, HARDWARE_PREFIX_KONAMI, GBF_VERSHOOT, 0,
NULL, ajaxRomInfo, ajaxRomName, NULL, NULL, AjaxInputInfo, AjaxDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x800,
224, 288, 3, 4
};
// Typhoon
static struct BurnRomInfo typhoonRomDesc[] = {
{ "770_k01.n11", 0x10000, 0x5ba74a22, 1 | BRF_PRG | BRF_ESS }, // 0 Konami Custom Code
{ "770_k02.n12", 0x10000, 0x3bcf782a, 1 | BRF_PRG | BRF_ESS }, // 1
{ "770_k05.i16", 0x08000, 0x0f1bebbb, 2 | BRF_PRG | BRF_ESS }, // 2 M6809 Code
{ "770_f04.g16", 0x10000, 0xe0e4ec9c, 2 | BRF_PRG | BRF_ESS }, // 3
{ "770_h03.f16", 0x08000, 0x2ffd2afc, 3 | BRF_PRG | BRF_ESS }, // 4 Z80 Code
{ "770c13", 0x40000, 0xb859ca4e, 4 | BRF_GRA }, // 5 K052109 Tiles
{ "770c12", 0x40000, 0x50d14b72, 4 | BRF_GRA }, // 6
{ "770c09", 0x80000, 0x1ab4a7ff, 5 | BRF_GRA }, // 7 K051960 Tiles
{ "770c08", 0x80000, 0xa8e80586, 5 | BRF_GRA }, // 8
{ "770c06", 0x40000, 0xd0c592ee, 6 | BRF_GRA }, // 9 K051960 Tiles
{ "770c07", 0x40000, 0x0b399fb1, 6 | BRF_GRA }, // 10
{ "770c10", 0x40000, 0x7fac825f, 7 | BRF_SND }, // 11 K007232 #0 Samples
{ "770c11", 0x80000, 0x299a615a, 8 | BRF_SND }, // 12 K007232 #1 Samples
{ "63s241.j11", 0x00200, 0x9bdd719f, 9 | BRF_OPT }, // 13 Timing Prom (unused)
};
STD_ROM_PICK(typhoon)
STD_ROM_FN(typhoon)
struct BurnDriver BurnDrvTyphoon = {
"typhoon", "ajax", NULL, NULL, "1987",
"Typhoon\0", NULL, "Konami", "GX770",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED, 2, HARDWARE_PREFIX_KONAMI, GBF_VERSHOOT, 0,
NULL, typhoonRomInfo, typhoonRomName, NULL, NULL, AjaxInputInfo, AjaxDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x800,
224, 288, 3, 4
};
// Ajax (Japan)
static struct BurnRomInfo ajaxjRomDesc[] = {
{ "770_l01.n11", 0x10000, 0x7cea5274, 1 | BRF_PRG | BRF_ESS }, // 0 Konami Custom Code
{ "770_l02.n12", 0x10000, 0xad7d592b, 1 | BRF_PRG | BRF_ESS }, // 1
{ "770_l05.i16", 0x08000, 0xed64fbb2, 2 | BRF_PRG | BRF_ESS }, // 2 M6809 code
{ "770_f04.g16", 0x10000, 0xe0e4ec9c, 2 | BRF_PRG | BRF_ESS }, // 3
{ "770_f03.f16", 0x08000, 0x3fe914fd, 3 | BRF_PRG | BRF_ESS }, // 4 Z80 Code
{ "770c13", 0x40000, 0xb859ca4e, 4 | BRF_GRA }, // 5 K052109 Tiles
{ "770c12", 0x40000, 0x50d14b72, 4 | BRF_GRA }, // 6
{ "770c09", 0x80000, 0x1ab4a7ff, 5 | BRF_GRA }, // 7 K051960 Tiles
{ "770c08", 0x80000, 0xa8e80586, 5 | BRF_GRA }, // 8
{ "770c06", 0x40000, 0xd0c592ee, 6 | BRF_GRA }, // 9 K051960 Tiles
{ "770c07", 0x40000, 0x0b399fb1, 6 | BRF_GRA }, // 10
{ "770c10", 0x40000, 0x7fac825f, 7 | BRF_SND }, // 11 K007232 #0 Samples
{ "770c11", 0x80000, 0x299a615a, 8 | BRF_SND }, // 12 K007232 #1 Samples
{ "63s241.j11", 0x00200, 0x9bdd719f, 9 | BRF_OPT }, // 13 Timing Prom (unused)
};
STD_ROM_PICK(ajaxj)
STD_ROM_FN(ajaxj)
struct BurnDriver BurnDrvAjaxj = {
"ajaxj", "ajax", NULL, NULL, "1987",
"Ajax (Japan)\0", NULL, "Konami", "GX770",
L"Ajax\0\u30A8\u30FC\u30B8\u30E3\u30C3\u30AF\u30B9 (Japan)\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED, 2, HARDWARE_PREFIX_KONAMI, GBF_VERSHOOT, 0,
NULL, ajaxjRomInfo, ajaxjRomName, NULL, NULL, AjaxInputInfo, AjaxDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x800,
224, 288, 3, 4
};

Some files were not shown because too many files have changed in this diff Show More