diff --git a/bsnes.exe b/bsnes.exe deleted file mode 100644 index c503c46b..00000000 Binary files a/bsnes.exe and /dev/null differ diff --git a/cart.db b/cart.db deleted file mode 100644 index a489d594..00000000 Binary files a/cart.db and /dev/null differ diff --git a/license.txt b/license.txt deleted file mode 100644 index 08c2ad76..00000000 --- a/license.txt +++ /dev/null @@ -1,35 +0,0 @@ -bsnes License: --------------- -You are free to redistribute this software, and its source code; provided -there is no charge for the software, nor any charge for the medium used to -distribute the software. You are also free to use and modify the source code -as you desire for personal use only. No publically-released derivative works -of this program nor its source code are permitted without my permission, -though I will likely grant you permission if you ask me. You must also abide -by the terms of any additional source code licenses contained within this -program. - -Simple DirectMedia Layer License: ---------------------------------- -The Simple DirectMedia Layer (SDL for short) is a cross-platform library -designed to make it easy to write multi-media software, such as games and -emulators. - -The Simple DirectMedia Layer library source code is available from: -http://www.libsdl.org/ - -This library is distributed under the terms of the GNU LGPL: -http://www.gnu.org/copyleft/lesser.html - -JMA License: ------------- -JMA is licensed under the GNU GPL. I have received special exemption from -Nach to use this library in bsnes. - -Licensing Exemptions: ---------------------- -libco, the cooperative multithreading library used by bsnes, is public domain. -You may obtain the latest version at: http://byuu.org/ - -Richard Bannister has asked for and received my permission to distribute -a binary-only port of bsnes on the Mac OS X platform. diff --git a/readme.txt b/readme.txt deleted file mode 100644 index 93926220..00000000 --- a/readme.txt +++ /dev/null @@ -1,98 +0,0 @@ -bsnes -Version 0.019 -Author: byuu - - -General -------- -bsnes is a Super Nintendo / Super Famicom emulator that began on -October 14th, 2004. - -The latest version can be downloaded from: -http://byuu.org/ - -Please see license.txt for important licensing information. - - -Known Limitations ------------------ -S-CPU -- Invalid DMA / HDMA transfers (eg WRAM<>WRAM) not fully emulated -- Multiply / Divide register delays not implemented - -S-SMP -- Cycle breakdown of opcodes is theoretical, but mostly correct - -S-PPU -- Uses scanline-based renderer. This is very inaccurate, but very - few games rely on mid-scanline writes to function correctly -- Does not support FirstSprite+Y priority -- OAM / CGRAM accesses during active display not supported correctly -- RTO flags are not calculated on frames that are skipped when frameskipping - is enabled. This provides a major speedup, however it will cause in issues - in games that test these flags, eg the SNES Test Program Electronics Test. - Turning frameskipping off will allow RTO flag calculation on every frame - -S-DSP -- Runs at 32khz. Hardware S-DSP likely runs at 1.024mhz to perform - multiple reads / writes per sample. Sound is still output at 32khz, - of course - -Hardware Bugs -- CPUr1 HDMA crashing bug not emulated -- CPU<>APU communication bus conflicts not emulated - - -Unsupported Hardware --------------------- -SA-1 -Coprocessor used in many popular games, including: -- Dragon Ball Z Hyper Dimension -- Kirby Super Star -- Kirby's Dreamland 3 -- Marvelous -- SD Gundam G-NEXT -- Super Mario RPG - -Super FX -Coprocessor used in many popular games, including: -- Doom -- Star Fox -- Star Fox 2 (unreleased beta) -- Super Mario World 2: Yoshi's Island - -SPC7110 -Coprocessor used only by the following games: -- Far East of Eden Zero -- Far East of Eden Zero: Shounen Jump no Shou -- Momotarou Densetsu Happy -- Super Power League 4 - -DSP-3 -Coprocessor used only by SD Gundam GX - -DSP-4 -Coprocessor used only by Top Gear 3000 - -ST010 / ST011 / ST018 -SETA coprocessors used by very few games - -BS-X (Broadcast Satellite) -Add-on unit sold only in Japan that played specially-made games that -were downloaded via satellite - -BS-X Flashcart -Flash cartridge used by BS-X, as well as some standalone games by -Asciisoft - -Super Gameboy -Cartridge passthrough used for playing Gameboy games - - -Unsupported controllers ------------------------ -Mouse -Super Scope -Justifier -Multitap (4-port) -Multitap (5-port) diff --git a/src/Makefile b/src/Makefile index 637da689..04b5389b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -13,19 +13,23 @@ endif ifeq ($(PLATFORM),x-gcc-lui) OS = unix CC = gcc -CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0` `sdl-config --cflags` +CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0` AS = nasm ASFLAGS = -f elf -LIBS = `pkg-config --libs gtk+-2.0` `sdl-config --libs` -lXv -lao +LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao +LIBCO = libco_x86 +LIBUI = libui_gtk endif -ifeq ($(PLATFORM),x-gcc-sdl) +ifeq ($(PLATFORM),x-gcc-lui-x64) OS = unix CC = gcc -CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_SDL `sdl-config --cflags` -AS = nasm -ASFLAGS = -f elf -LIBS = `sdl-config --libs` -lao +CFLAGS = -O3 -fomit-frame-pointer -ffast-math -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_LUI `pkg-config --cflags gtk+-2.0` +AS = yasm +ASFLAGS = -f elf64 +LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao +LIBCO = libco_x86_64 +LIBUI = libui_gtk endif ifeq ($(PLATFORM),win-visualc-lui) @@ -35,44 +39,32 @@ CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR AS = nasm ASFLAGS = -f win32 -DWIN32 LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib +LIBCO = libco_x86 +LIBUI = libui_win endif -ifeq ($(PLATFORM),win-visualc) +ifeq ($(PLATFORM),win-visualc-lui-pgi) OS = win CC = cl -CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_WIN -AS = nasm -ASFLAGS = -f win32 -DWIN32 -LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib -endif - -ifeq ($(PLATFORM),win-visualc-pgi) -OS = win -CC = cl -CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_WIN +CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI AS = nasm ASFLAGS = -f win32 -DWIN32 LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib LINK = /link /PGD:bsnes.pgd /LTCG:PGINSTRUMENT +LIBCO = libco_x86 +LIBUI = libui_win endif -ifeq ($(PLATFORM),win-visualc-pgo) +ifeq ($(PLATFORM),win-visualc-lui-pgo) OS = win CC = cl -CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_WIN +CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI AS = nasm ASFLAGS = -f win32 -DWIN32 LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib LINK = /link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE -endif - -ifeq ($(PLATFORM),win-visualc-sdl) -OS = win -CC = cl -CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_SDL -AS = nasm -ASFLAGS = -f win32 -DWIN32 -LIBS = sdlmain.lib sdl.lib dsound.lib +LIBCO = libco_x86 +LIBUI = libui_win endif ##################################### @@ -99,6 +91,10 @@ ifeq ($(AS),nasm) ASARGS = $< -o $@ endif +ifeq ($(AS),yasm) +ASARGS = $< -o $@ +endif + ################### ### OS switches ### ################### @@ -110,14 +106,15 @@ endif ifeq ($(OS),win) OUT := $(OUT).exe RM = del -LIBS += kernel32.lib user32.lib gdi32.lib winmm.lib comdlg32.lib comctl32.lib +LIBS += kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib endif #################################### ### main target and dependencies ### #################################### -OBJECTS = main.$(OBJ) libco_x86.$(OBJ) libstring.$(OBJ) libconfig.$(OBJ) \ +OBJECTS = main.$(OBJ) $(LIBCO).$(OBJ) $(LIBUI).$(OBJ) \ + libstring.$(OBJ) \ reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) bmemory.$(OBJ) \ cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \ bppu.$(OBJ) snes.$(OBJ) srtc.$(OBJ) sdd1.$(OBJ) c4.$(OBJ) dsp1.$(OBJ) \ @@ -160,16 +157,25 @@ all: $(OBJECTS) ######################### main.$(OBJ): ui/main.cpp config/* ui/* ui/video/* ui/audio/* ui/input/* \ ui/lui/* ui/lui/settings/* \ -ui/win/* ui/win/settings/* ui/win/debugger/* \ -ui/sdl/* +ui/win/* ui/win/settings/* ui/win/debugger/* bsnes.res : ui/bsnes.rc ; rc /r /fobsnes.res ui/bsnes.rc +############# +### libco ### +############# +libco_x86.$(OBJ) : lib/libco_x86.asm lib/* +libco_x86_64.$(OBJ): lib/libco_x86_64.asm lib/* + +############# +### libui ### +############# +libui_gtk.$(OBJ): lib/libui_gtk.cpp lib/* +libui_win.$(OBJ): lib/libui_win.cpp lib/* + ################# ### libraries ### ################# -libco_x86.$(OBJ): lib/libco_x86.asm lib/* libstring.$(OBJ): lib/libstring.cpp lib/* -libconfig.$(OBJ): lib/libconfig.cpp lib/* ################# ### utilities ### @@ -199,6 +205,7 @@ ssmp.$(OBJ): smp/ssmp/ssmp.cpp smp/ssmp/* smp/ssmp/core/* smp/ssmp/memory/* smp/ ########### ### dsp ### ########### +adsp.$(OBJ): dsp/adsp/adsp.cpp dsp/adsp/* bdsp.$(OBJ): dsp/bdsp/bdsp.cpp dsp/bdsp/* ########### @@ -210,7 +217,7 @@ bppu.$(OBJ): ppu/bppu/bppu.cpp ppu/bppu/* ############ ### snes ### ############ -snes.$(OBJ): snes/snes.cpp snes/* snes/video/* snes/audio/* snes/input/* +snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/* ##################### ### special chips ### diff --git a/src/base.h b/src/base.h index ef91c2d6..27403a25 100644 --- a/src/base.h +++ b/src/base.h @@ -1,4 +1,4 @@ -#define BSNES_VERSION "0.019.09" +#define BSNES_VERSION "0.020" #define BSNES_TITLE "bsnes v" BSNES_VERSION #define MEMCORE bMemBus @@ -17,36 +17,32 @@ //(allow runtime cpu/smp/dsp/ppu/bus selection, ~10% speed hit) //#define POLYMORPHISM +#include "lib/libbase.h" + #if defined(PROCESSOR_X86) #define ARCH_LSB + #include "lib/libco_x86.h" #elif defined(PROCESSOR_X86_64) #define ARCH_LSB + #include "lib/libco_x86_64.h" #elif defined(PROCESSOR_G5) #define ARCH_MSB #else #error "unsupported processor" #endif -#include "lib/libbase.h" +#include "lib/libinterp.h" #include "lib/libsort.h" -#include "lib/libco_x86.h" #include "lib/libarray.h" #include "lib/libvector.h" +#include "lib/libfile.h" #include "lib/libstring.h" #include "lib/libconfig.h" -inline uint16 read16(uint8 *addr, uint pos) { -#ifdef ARCH_LSB - return *((uint16*)(addr + pos)); -#else - return (addr[pos]) | (addr[pos + 1] << 8); -#endif -} - //platform-specific global functions -void alert(char *, ...); -void dprintf(char *, ...); -void dprintf(uint, char *, ...); +void alert(char*, ...); +void dprintf(char*, ...); +void dprintf(uint, char*, ...); namespace source { enum { diff --git a/src/bsnes.lnk b/src/bsnes.lnk index 36540493..8a244e95 100644 Binary files a/src/bsnes.lnk and b/src/bsnes.lnk differ diff --git a/src/bsnes_lui.cfg b/src/bsnes_lui.cfg deleted file mode 100644 index ada80bf5..00000000 --- a/src/bsnes_lui.cfg +++ /dev/null @@ -1,181 +0,0 @@ -# Default path to look for ROM files in ("" = use default directory) -# (default = "") -path.rom = "/dos/Documents and Settings/byuu/Desktop/snes_testroms" - -# Default path for all save RAM and cheat files ("" = use current directory) -# (default = "") -path.save = "" - -# Path where BIOS file(s) are located -# Supported BIOS files: -# stbios.bin - Bandai Sufami Turbo -# (default = "./bios") -path.bios = "./bios" - -# Extension to be used for all save RAM files -# (default = "srm") -path.save_ext = "srm" - -# Use precalculated TV-style gamma ramp -# (default = true) -snes.colorfilter.gamma_ramp = true - -# Convert color to sepia tone -# (default = false) -snes.colorfilter.sepia = false - -# Convert color to grayscale tone -# (default = false) -snes.colorfilter.grayscale = false - -# Invert output image colors -# (default = false) -snes.colorfilter.invert = false - -# Contrast -# (default = 0) -snes.colorfilter.contrast = 0 - -# Brightness -# (default = 0) -snes.colorfilter.brightness = 0 - -# Gamma -# (default = 80) -snes.colorfilter.gamma = 80 - -# Merge fields in NTSC video filter -# Set to true if using filter at any refresh rate other than 60hz -# -# (default = true) -snes.ntsc_merge_fields = true - -# Mutes SNES audio output when enabled -# (default = false) -snes.mute = false - -# Controller attached to SNES port 1 -# (default = 1) -snes.controller_port_1 = 1 - -# Controller attached to SNES port 2 -# (default = 2) -snes.controller_port_2 = 2 - -# NTSC S-CPU clock rate (in hz) -# (default = 21477272) -cpu.ntsc_clock_rate = 21477272 - -# PAL S-CPU clock rate (in hz) -# (default = 21281370) -cpu.pal_clock_rate = 21281370 - -# NTSC S-SMP clock rate (in hz) -# (default = 24606720) -smp.ntsc_clock_rate = 24606720 - -# PAL S-SMP clock rate (in hz) -# (default = 24606720) -smp.pal_clock_rate = 24606720 - -# Approximate HCLOCK position to render at for scanline-based renderers -# (default = 512) -ppu.hack.render_scanline_position = 512 - -# Cache OAM OBJ attributes one scanline before rendering -# This is technically closer to the actual operation of the SNES, -# but can cause problems in many games if enabled -# (default = false) -ppu.hack.obj_cache = false - -# Video hardware interface -# (default = "") -system.video = "" - -# Audio hardware interface -# (default = "") -system.audio = "" - -# Input hardware interface -# (default = "") -system.input = "" - -# Regulate speed to 60hz (NTSC) / 50hz (PAL) -# (default = true) -system.regulate_speed = true - -# Slowest speed setting (in hz) -# (default = 16000) -system.speed_slowest = 16000 - -# Slow speed setting -# (default = 24000) -system.speed_slow = 24000 - -# Normal speed setting -# (default = 32000) -system.speed_normal = 32000 - -# Fast speed setting -# (default = 48000) -system.speed_fast = 48000 - -# Fastest speed setting -# (default = 64000) -system.speed_fastest = 64000 - -# Windowed video profile configuration -# If available, please use bsnes GUI configuration editor to modify video profile settings -# Format: software_filter;hardware_filter;video_standard;multiplier;correct_aspect_ratio; -# enable_scanlines;manual_render_size;render_width;render_height; -# triple_buffering;resolution_width;resolution_height;refresh_rate -# (default = "0;1;0;2;true;false;false;595;448;false;0;0;0") -video.profile_win = "0;1;0;2;true;false;false;595;448;false;0;0;0" - -# Fullscreen video profile configuration -# (default = "0;1;0;2;true;false;false;595;448;false;0;0;0") -video.profile_full = "0;1;0;2;true;false;false;595;448;false;0;0;0" - -# Use Video RAM instead of System RAM -# (default = true) -video.use_vram = true - -# Progressive scanline intensity -# Value is percentage of intensity from 0 to 100 -# (default = 30) -video.pscanline_intensity = 30 - -# Interlace scanline intensity -# (default = 50) -video.iscanline_intensity = 50 - -# Axis resistance for all analog joypads -# Affects responsiveness of analog stick movement by specifying what percentage -# in any given direction the axis must be pressed to trigger a button press. -# In other words, this determines how hard you have to press the analog stick to -# simulate pressing e.g. left or right on a digital joypad. -# Value is a percentage, from 0 (axis will trigger with virtually any axis movement) -# up to 100 (axis must be pressed fully to given corner). -# Value affects all four directions of the axis equally. -# Note: Values below 10 or above 90 are not recommended and may not work at all. -# (default = 75) -input.axis_resistance = 75 - -# Allow up+down and left+right key combinations for joypad 1 (not recommended) -# (default = false) -input.joypad1.allow_invalid_input = false - -# Joypad 1 button map -# Format: Up; Down; Left; Right; A; B; X; Y; L; R; Select; Start -# (default = "up | joypad0.up; down | joypad0.down; left | joypad0.left; right | joypad0.right; x | joypad0.button3; z | joypad0.button2; s | joypad0.button1; a | joypad0.button0; d | joypad0.button6; c | joypad0.button7; rshift | joypad0.button4; enter | joypad0.button5") -input.joypad1.map = "up | joypad0.up; down | joypad0.down; left | joypad0.left; right | joypad0.right; x | joypad0.button3; z | joypad0.button2; s | joypad0.button1; a | joypad0.button0; d | joypad0.button6; c | joypad0.button7; rshift | joypad0.button4; enter | joypad0.button5" - -# Allow up+down and left+right key combinations for joypad 2 (not recommended) -# (default = false) -input.joypad2.allow_invalid_input = false - -# Joypad 2 button map -# Format: Up; Down; Left; Right; A; B; X; Y; L; R; Select; Start -# (default = "t | joypad1.up; g | joypad1.down; f | joypad1.left; h | joypad1.right; k | joypad1.button3; j | joypad1.button2; i | joypad1.button1; u | joypad1.button0; o | joypad1.button6; l | joypad1.button7; lbracket | joypad1.button4; rbracket | joypad1.button5") -input.joypad2.map = "t | joypad1.up; g | joypad1.down; f | joypad1.left; h | joypad1.right; k | joypad1.button3; j | joypad1.button2; i | joypad1.button1; u | joypad1.button0; o | joypad1.button6; l | joypad1.button7; lbracket | joypad1.button4; rbracket | joypad1.button5" - diff --git a/src/cart/cart.cpp b/src/cart/cart.cpp index f868d984..ac1a6026 100644 --- a/src/cart/cart.cpp +++ b/src/cart/cart.cpp @@ -128,8 +128,8 @@ bool Cartridge::unload() { } break; } - SafeFree(rom); - SafeFree(ram); + safe_free(rom); + safe_free(ram); if(cheat.count() > 0 || fexists(file.cheat_name) == true) { cheat.save(file.cheat_name); diff --git a/src/cc.bat b/src/cc.bat index 2457be0e..9ddfe888 100644 --- a/src/cc.bat +++ b/src/cc.bat @@ -1,3 +1,3 @@ -@make -r PLATFORM=win-visualc +@make -r PLATFORM=win-visualc-lui @move bsnes.exe ../bsnes.exe>nul @pause \ No newline at end of file diff --git a/src/cc.sh b/src/cc.sh index 6c958cef..49c6608f 100644 --- a/src/cc.sh +++ b/src/cc.sh @@ -1,2 +1,2 @@ #!/bin/sh -gmake PLATFORM=x-gcc-lui +make PLATFORM=x-gcc-lui \ No newline at end of file diff --git a/src/cheat/cheat.cpp b/src/cheat/cheat.cpp index e5506c1a..8726c684 100644 --- a/src/cheat/cheat.cpp +++ b/src/cheat/cheat.cpp @@ -277,7 +277,7 @@ uint8 *raw_data = rf.read(); stringarray data, line; raw_data[rf.size()] = 0; strcpy(data, (char*)raw_data); - SafeFree(raw_data); + safe_free(raw_data); replace(data, "\r\n", "\n"); split(line, "\n", data); diff --git a/src/chip/sdd1/sdd1emu.h b/src/chip/sdd1/sdd1emu.h index 94b723da..a9ff01fe 100644 --- a/src/chip/sdd1/sdd1emu.h +++ b/src/chip/sdd1/sdd1emu.h @@ -28,6 +28,7 @@ understood. ************************************************************************/ +typedef uint8_t bool8; class SDD1_IM { //Input Manager diff --git a/src/clean.bat b/src/clean.bat index c63abd8d..134107c6 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -1 +1 @@ -@make PLATFORM=win-visualc clean +@make PLATFORM=win-visualc-lui clean diff --git a/src/clean.sh b/src/clean.sh index 5cf78518..0b82ddb6 100644 --- a/src/clean.sh +++ b/src/clean.sh @@ -1,2 +1,2 @@ #!/bin/sh -gmake PLATFORM=x-gcc-lui clean +make PLATFORM=x-gcc-lui clean \ No newline at end of file diff --git a/src/config/config.cpp b/src/config/config.cpp index 3a045834..9ba34a87 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -25,83 +25,83 @@ stringarray part; return path; } -Setting Path::base(0, "fs.base_path", +StringSetting Path::base(0, "fs.base_path", "Path that bsnes resides in", ""); -Setting Path::rom(&config_file, "path.rom", +StringSetting Path::rom(&config_file, "path.rom", "Default path to look for ROM files in (\"\" = use default directory)", ""); -Setting Path::save(&config_file, "path.save", +StringSetting Path::save(&config_file, "path.save", "Default path for all save RAM and cheat files (\"\" = use current directory)", ""); -Setting Path::bios(&config_file, "path.bios", +StringSetting Path::bios(&config_file, "path.bios", "Path where BIOS file(s) are located\n" "Supported BIOS files:\n" "stbios.bin - Bandai Sufami Turbo" "", "./bios"); -Setting Path::save_ext(&config_file, "path.save_ext", +StringSetting Path::save_ext(&config_file, "path.save_ext", "Extension to be used for all save RAM files", "srm"); -Setting SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp", - "Use precalculated TV-style gamma ramp", true, Setting::BOOL); -Setting SNES::sepia(&config_file, "snes.colorfilter.sepia", - "Convert color to sepia tone", false, Setting::BOOL); -Setting SNES::grayscale(&config_file, "snes.colorfilter.grayscale", - "Convert color to grayscale tone", false, Setting::BOOL); -Setting SNES::invert(&config_file, "snes.colorfilter.invert", - "Invert output image colors", false, Setting::BOOL); -Setting SNES::contrast(&config_file, "snes.colorfilter.contrast", - "Contrast", 0, Setting::DEC); -Setting SNES::brightness(&config_file, "snes.colorfilter.brightness", - "Brightness", 0, Setting::DEC); -Setting SNES::gamma(&config_file, "snes.colorfilter.gamma", - "Gamma", 80, Setting::DEC); +IntegerSetting SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp", + "Use precalculated TV-style gamma ramp", IntegerSetting::Boolean, true); +IntegerSetting SNES::sepia(&config_file, "snes.colorfilter.sepia", + "Convert color to sepia tone", IntegerSetting::Boolean, false); +IntegerSetting SNES::grayscale(&config_file, "snes.colorfilter.grayscale", + "Convert color to grayscale tone", IntegerSetting::Boolean, false); +IntegerSetting SNES::invert(&config_file, "snes.colorfilter.invert", + "Invert output image colors", IntegerSetting::Boolean, false); +IntegerSetting SNES::contrast(&config_file, "snes.colorfilter.contrast", + "Contrast", IntegerSetting::Decimal, 0); +IntegerSetting SNES::brightness(&config_file, "snes.colorfilter.brightness", + "Brightness", IntegerSetting::Decimal, 0); +IntegerSetting SNES::gamma(&config_file, "snes.colorfilter.gamma", + "Gamma", IntegerSetting::Decimal, 80); -Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields", +IntegerSetting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields", "Merge fields in NTSC video filter\n" "Set to true if using filter at any refresh rate other than 60hz\n" - "", true, Setting::BOOL); + "", IntegerSetting::Boolean, true); -Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled", - false, Setting::BOOL); +IntegerSetting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled", + IntegerSetting::Boolean, false); -Setting SNES::controller_port0(&config_file, "snes.controller_port_1", - "Controller attached to SNES port 1", ::SNES::DEVICEID_JOYPAD1, Setting::DEC); -Setting SNES::controller_port1(&config_file, "snes.controller_port_2", - "Controller attached to SNES port 2", ::SNES::DEVICEID_JOYPAD2, Setting::DEC); +IntegerSetting SNES::controller_port0(&config_file, "snes.controller_port_1", + "Controller attached to SNES port 1", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD1); +IntegerSetting SNES::controller_port1(&config_file, "snes.controller_port_2", + "Controller attached to SNES port 2", IntegerSetting::Decimal, ::SNES::DEVICEID_JOYPAD2); -Setting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate", - "NTSC S-CPU clock rate (in hz)", 21477272, Setting::DEC); -Setting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate", - "PAL S-CPU clock rate (in hz)", 21281370, Setting::DEC); +IntegerSetting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate", + "NTSC S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21477272); +IntegerSetting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate", + "PAL S-CPU clock rate (in hz)", IntegerSetting::Decimal, 21281370); -Setting CPU::hdma_enable(0, "cpu.hdma_enable", - "Enable HDMA effects", true, Setting::BOOL); +IntegerSetting CPU::hdma_enable(0, "cpu.hdma_enable", + "Enable HDMA effects", IntegerSetting::Boolean, true); -Setting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate", - "NTSC S-SMP clock rate (in hz)", 24606720, Setting::DEC); -Setting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate", - "PAL S-SMP clock rate (in hz)", 24606720, Setting::DEC); +IntegerSetting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate", + "NTSC S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720); +IntegerSetting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate", + "PAL S-SMP clock rate (in hz)", IntegerSetting::Decimal, 24606720); -Setting PPU::Hack::render_scanline_position(&config_file, "ppu.hack.render_scanline_position", +IntegerSetting PPU::Hack::render_scanline_position(&config_file, "ppu.hack.render_scanline_position", "Approximate HCLOCK position to render at for scanline-based renderers", - 512, Setting::DEC); -Setting PPU::Hack::obj_cache(&config_file, "ppu.hack.obj_cache", + IntegerSetting::Decimal, 512); +IntegerSetting PPU::Hack::obj_cache(&config_file, "ppu.hack.obj_cache", "Cache OAM OBJ attributes one scanline before rendering\n" "This is technically closer to the actual operation of the SNES,\n" - "but can cause problems in many games if enabled", - false, Setting::BOOL); + "but can cause problems in some games if enabled", + IntegerSetting::Boolean, false); -Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::BOOL); -Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::BOOL); -Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::BOOL); -Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::BOOL); -Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::BOOL); -Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::BOOL); -Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::BOOL); -Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::BOOL); -Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::BOOL); -Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::BOOL); -Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::BOOL); -Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::BOOL); -Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::BOOL); +IntegerSetting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", IntegerSetting::Boolean, true); +IntegerSetting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", IntegerSetting::Boolean, true); +IntegerSetting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", IntegerSetting::Boolean, true); +IntegerSetting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", IntegerSetting::Boolean, true); +IntegerSetting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", IntegerSetting::Boolean, true); +IntegerSetting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", IntegerSetting::Boolean, true); }; diff --git a/src/config/config.h b/src/config/config.h index d0c4baba..6cc53222 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -5,40 +5,40 @@ namespace config { string file_updatepath(const char *, const char *); extern struct Path { - static Setting base, rom, save, bios; - static Setting save_ext; + static StringSetting base, rom, save, bios; + static StringSetting save_ext; } path; extern struct SNES { - static Setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma; - static Setting ntsc_merge_fields; - static Setting mute; - static Setting controller_port0; - static Setting controller_port1; + static IntegerSetting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma; + static IntegerSetting ntsc_merge_fields; + static IntegerSetting mute; + static IntegerSetting controller_port0; + static IntegerSetting controller_port1; } snes; extern struct CPU { - static Setting ntsc_clock_rate, pal_clock_rate; - static Setting hdma_enable; + static IntegerSetting ntsc_clock_rate, pal_clock_rate; + static IntegerSetting hdma_enable; } cpu; extern struct SMP { - static Setting ntsc_clock_rate, pal_clock_rate; + static IntegerSetting ntsc_clock_rate, pal_clock_rate; } smp; extern struct PPU { struct Hack { - static Setting render_scanline_position; - static Setting obj_cache; + static IntegerSetting render_scanline_position; + static IntegerSetting obj_cache; } hack; - static Setting opt_enable; - static Setting bg1_pri0_enable, bg1_pri1_enable; - static Setting bg2_pri0_enable, bg2_pri1_enable; - static Setting bg3_pri0_enable, bg3_pri1_enable; - static Setting bg4_pri0_enable, bg4_pri1_enable; - static Setting oam_pri0_enable, oam_pri1_enable; - static Setting oam_pri2_enable, oam_pri3_enable; + static IntegerSetting opt_enable; + static IntegerSetting bg1_pri0_enable, bg1_pri1_enable; + static IntegerSetting bg2_pri0_enable, bg2_pri1_enable; + static IntegerSetting bg3_pri0_enable, bg3_pri1_enable; + static IntegerSetting bg4_pri0_enable, bg4_pri1_enable; + static IntegerSetting oam_pri0_enable, oam_pri1_enable; + static IntegerSetting oam_pri2_enable, oam_pri3_enable; } ppu; }; diff --git a/src/cpu/cpuregs.h b/src/cpu/cpuregs.h index 8a7e8754..5b502044 100644 --- a/src/cpu/cpuregs.h +++ b/src/cpu/cpuregs.h @@ -3,7 +3,7 @@ public: union { uint8 data; struct { - uint8 order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1); + bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1); }; }; diff --git a/src/cpu/scpu/core/core.cpp b/src/cpu/scpu/core/core.cpp index b8981f41..aea39dd1 100644 --- a/src/cpu/scpu/core/core.cpp +++ b/src/cpu/scpu/core/core.cpp @@ -1,33 +1,31 @@ #include "opfn.cpp" -void sCPU::enter() { - for(;;) { - if(event.irq) { - event.irq = false; - if(status.nmi_pending == true) { - status.nmi_pending = false; - event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa; - } else if(status.irq_pending == true) { - status.irq_pending = false; - event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe; - } - op_irq(); +#include "op_read.cpp" +#include "op_write.cpp" +#include "op_rmw.cpp" +#include "op_pc.cpp" +#include "op_misc.cpp" + +void sCPU::enter() { loop: + if(event.irq) { + event.irq = false; + if(status.nmi_pending == true) { + status.nmi_pending = false; + event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa; + } else if(status.irq_pending == true) { + status.irq_pending = false; + event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe; } - - tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled) - - status.in_opcode = true; - - switch(op_readpc()) { - #include "op_read.cpp" - #include "op_write.cpp" - #include "op_rmw.cpp" - #include "op_pc.cpp" - #include "op_misc.cpp" - } - - status.in_opcode = false; + op_irq(); } + + tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled) + + status.in_opcode = true; + (this->*optbl[op_readpc()])(); + status.in_opcode = false; + + goto loop; } void sCPU::op_irq() { diff --git a/src/cpu/scpu/core/core.h b/src/cpu/scpu/core/core.h index ce2b6794..9097197f 100644 --- a/src/cpu/scpu/core/core.h +++ b/src/cpu/scpu/core/core.h @@ -1,4 +1,4 @@ -//void (sCPU::*optbl[256])(); +void (sCPU::*optbl[256])(); CPUReg24 aa, rd; uint8 dp, sp; @@ -54,4 +54,4 @@ uint8 dp, sp; void op_io_cond4(uint16 x, uint16 y); void op_io_cond6(uint16 addr); -//#include "op.h" +#include "op.h" diff --git a/src/cpu/scpu/core/op.h b/src/cpu/scpu/core/op.h new file mode 100644 index 00000000..aea4a5a7 --- /dev/null +++ b/src/cpu/scpu/core/op.h @@ -0,0 +1,256 @@ +void op_adc_const(); +void op_and_const(); +void op_cmp_const(); +void op_cpx_const(); +void op_cpy_const(); +void op_eor_const(); +void op_lda_const(); +void op_ldx_const(); +void op_ldy_const(); +void op_ora_const(); +void op_sbc_const(); +void op_adc_addr(); +void op_and_addr(); +void op_bit_addr(); +void op_cmp_addr(); +void op_cpx_addr(); +void op_cpy_addr(); +void op_eor_addr(); +void op_lda_addr(); +void op_ldx_addr(); +void op_ldy_addr(); +void op_ora_addr(); +void op_sbc_addr(); +void op_adc_addrx(); +void op_and_addrx(); +void op_bit_addrx(); +void op_cmp_addrx(); +void op_eor_addrx(); +void op_lda_addrx(); +void op_ldy_addrx(); +void op_ora_addrx(); +void op_sbc_addrx(); +void op_adc_addry(); +void op_and_addry(); +void op_cmp_addry(); +void op_eor_addry(); +void op_lda_addry(); +void op_ldx_addry(); +void op_ora_addry(); +void op_sbc_addry(); +void op_adc_long(); +void op_and_long(); +void op_cmp_long(); +void op_eor_long(); +void op_lda_long(); +void op_ora_long(); +void op_sbc_long(); +void op_adc_longx(); +void op_and_longx(); +void op_cmp_longx(); +void op_eor_longx(); +void op_lda_longx(); +void op_ora_longx(); +void op_sbc_longx(); +void op_adc_dp(); +void op_and_dp(); +void op_bit_dp(); +void op_cmp_dp(); +void op_cpx_dp(); +void op_cpy_dp(); +void op_eor_dp(); +void op_lda_dp(); +void op_ldx_dp(); +void op_ldy_dp(); +void op_ora_dp(); +void op_sbc_dp(); +void op_adc_dpx(); +void op_and_dpx(); +void op_bit_dpx(); +void op_cmp_dpx(); +void op_eor_dpx(); +void op_lda_dpx(); +void op_ldy_dpx(); +void op_ora_dpx(); +void op_sbc_dpx(); +void op_ldx_dpy(); +void op_adc_idp(); +void op_and_idp(); +void op_cmp_idp(); +void op_eor_idp(); +void op_lda_idp(); +void op_ora_idp(); +void op_sbc_idp(); +void op_adc_idpx(); +void op_and_idpx(); +void op_cmp_idpx(); +void op_eor_idpx(); +void op_lda_idpx(); +void op_ora_idpx(); +void op_sbc_idpx(); +void op_adc_idpy(); +void op_and_idpy(); +void op_cmp_idpy(); +void op_eor_idpy(); +void op_lda_idpy(); +void op_ora_idpy(); +void op_sbc_idpy(); +void op_adc_ildp(); +void op_and_ildp(); +void op_cmp_ildp(); +void op_eor_ildp(); +void op_lda_ildp(); +void op_ora_ildp(); +void op_sbc_ildp(); +void op_adc_ildpy(); +void op_and_ildpy(); +void op_cmp_ildpy(); +void op_eor_ildpy(); +void op_lda_ildpy(); +void op_ora_ildpy(); +void op_sbc_ildpy(); +void op_adc_sr(); +void op_and_sr(); +void op_cmp_sr(); +void op_eor_sr(); +void op_lda_sr(); +void op_ora_sr(); +void op_sbc_sr(); +void op_adc_isry(); +void op_and_isry(); +void op_cmp_isry(); +void op_eor_isry(); +void op_lda_isry(); +void op_ora_isry(); +void op_sbc_isry(); +void op_bit_const(); +void op_sta_addr(); +void op_stx_addr(); +void op_sty_addr(); +void op_stz_addr(); +void op_sta_addrx(); +void op_stz_addrx(); +void op_sta_addry(); +void op_sta_long(); +void op_sta_longx(); +void op_sta_dp(); +void op_stx_dp(); +void op_sty_dp(); +void op_stz_dp(); +void op_sta_dpx(); +void op_sty_dpx(); +void op_stz_dpx(); +void op_stx_dpy(); +void op_sta_idp(); +void op_sta_ildp(); +void op_sta_idpx(); +void op_sta_idpy(); +void op_sta_ildpy(); +void op_sta_sr(); +void op_sta_isry(); +void op_inc(); +void op_inx(); +void op_iny(); +void op_dec(); +void op_dex(); +void op_dey(); +void op_asl(); +void op_lsr(); +void op_rol(); +void op_ror(); +void op_inc_addr(); +void op_dec_addr(); +void op_asl_addr(); +void op_lsr_addr(); +void op_rol_addr(); +void op_ror_addr(); +void op_trb_addr(); +void op_tsb_addr(); +void op_inc_addrx(); +void op_dec_addrx(); +void op_asl_addrx(); +void op_lsr_addrx(); +void op_rol_addrx(); +void op_ror_addrx(); +void op_inc_dp(); +void op_dec_dp(); +void op_asl_dp(); +void op_lsr_dp(); +void op_rol_dp(); +void op_ror_dp(); +void op_trb_dp(); +void op_tsb_dp(); +void op_inc_dpx(); +void op_dec_dpx(); +void op_asl_dpx(); +void op_lsr_dpx(); +void op_rol_dpx(); +void op_ror_dpx(); +void op_bcc(); +void op_bcs(); +void op_bne(); +void op_beq(); +void op_bpl(); +void op_bmi(); +void op_bvc(); +void op_bvs(); +void op_bra(); +void op_brl(); +void op_jmp_addr(); +void op_jmp_long(); +void op_jmp_iaddr(); +void op_jmp_iaddrx(); +void op_jmp_iladdr(); +void op_jsr_addr(); +void op_jsr_long(); +void op_jsr_iaddrx(); +void op_rti(); +void op_rts(); +void op_rtl(); +void op_nop(); +void op_wdm(); +void op_xba(); +void op_mvn(); +void op_mvp(); +void op_brk(); +void op_cop(); +void op_stp(); +void op_wai(); +void op_xce(); +void op_clc(); +void op_cld(); +void op_cli(); +void op_clv(); +void op_sec(); +void op_sed(); +void op_sei(); +void op_rep(); +void op_sep(); +void op_tax(); +void op_tay(); +void op_txa(); +void op_txy(); +void op_tya(); +void op_tyx(); +void op_tcd(); +void op_tcs(); +void op_tdc(); +void op_tsc(); +void op_tsx(); +void op_txs(); +void op_pha(); +void op_phx(); +void op_phy(); +void op_phd(); +void op_phb(); +void op_phk(); +void op_php(); +void op_pla(); +void op_plx(); +void op_ply(); +void op_pld(); +void op_plb(); +void op_plp(); +void op_pea(); +void op_pei(); +void op_per(); diff --git a/src/cpu/scpu/core/op_misc.b b/src/cpu/scpu/core/op_misc.b index e6f6b3ab..ab96bff9 100644 --- a/src/cpu/scpu/core/op_misc.b +++ b/src/cpu/scpu/core/op_misc.b @@ -62,14 +62,14 @@ stp(0xdb) { } wai(0xcb) { -1:op_io(); - event.wai = true; -2:last_cycle(); - op_io(); -3:while(event.wai) { +//last_cycle() will set event.wai to false +//once an NMI / IRQ edge is reached +1:event.wai = true; + while(event.wai) { last_cycle(); op_io(); } +2:op_io(); } xce(0xfb) { diff --git a/src/cpu/scpu/core/op_misc.cpp b/src/cpu/scpu/core/op_misc.cpp index e96bd0c9..05440942 100644 --- a/src/cpu/scpu/core/op_misc.cpp +++ b/src/cpu/scpu/core/op_misc.cpp @@ -1,17 +1,14 @@ -//nop -case 0xea: { +void sCPU::op_nop() { last_cycle(); op_io(); -} break; +} -//wdm -case 0x42: { +void sCPU::op_wdm() { last_cycle(); op_readpc(); -} break; +} -//xba -case 0xeb: { +void sCPU::op_xba() { op_io(); last_cycle(); op_io(); @@ -20,10 +17,9 @@ case 0xeb: { regs.a.l ^= regs.a.h; regs.p.n = !!(regs.a.l & 0x80); regs.p.z = (regs.a.l == 0); -} break; +} -//mvn -case 0x54: { +void sCPU::op_mvn() { dp = op_readpc(); sp = op_readpc(); regs.db = dp; @@ -40,10 +36,9 @@ case 0x54: { last_cycle(); op_io(); if(regs.a.w--)regs.pc.w -= 3; -} break; +} -//mvp -case 0x44: { +void sCPU::op_mvp() { dp = op_readpc(); sp = op_readpc(); regs.db = dp; @@ -60,10 +55,9 @@ case 0x44: { last_cycle(); op_io(); if(regs.a.w--)regs.pc.w -= 3; -} break; +} -//brk -case 0x00: { +void sCPU::op_brk() { op_readpc(); if(!regs.e)op_writestack(regs.pc.b); op_writestack(regs.pc.h); @@ -76,10 +70,9 @@ case 0x00: { last_cycle(); rd.h = op_readlong((regs.e) ? 0xffff : 0xffe7); regs.pc.w = rd.w; -} break; +} -//cop -case 0x02: { +void sCPU::op_cop() { op_readpc(); if(!regs.e)op_writestack(regs.pc.b); op_writestack(regs.pc.h); @@ -92,29 +85,26 @@ case 0x02: { last_cycle(); rd.h = op_readlong((regs.e) ? 0xfff5 : 0xffe5); regs.pc.w = rd.w; -} break; +} -//stp -case 0xdb: { +void sCPU::op_stp() { op_io(); last_cycle(); while(1) { op_io(); } -} break; +} -//wai -case 0xcb: { - op_io(); +void sCPU::op_wai() { + //last_cycle() will set event.wai to false +//once an NMI / IRQ edge is reached event.wai = true; - last_cycle(); - op_io(); while(event.wai) { last_cycle(); op_io(); } -} break; + op_io(); +} -//xce -case 0xfb: { +void sCPU::op_xce() { last_cycle(); op_io(); bool carry = regs.p.c; @@ -128,59 +118,51 @@ bool carry = regs.p.c; regs.x.h = 0x00; regs.y.h = 0x00; } -} break; +} -//clc -case 0x18: { +void sCPU::op_clc() { last_cycle(); op_io(); regs.p.c = 0; -} break; +} -//cld -case 0xd8: { +void sCPU::op_cld() { last_cycle(); op_io(); regs.p.d = 0; -} break; +} -//cli -case 0x58: { +void sCPU::op_cli() { last_cycle(); op_io(); regs.p.i = 0; -} break; +} -//clv -case 0xb8: { +void sCPU::op_clv() { last_cycle(); op_io(); regs.p.v = 0; -} break; +} -//sec -case 0x38: { +void sCPU::op_sec() { last_cycle(); op_io(); regs.p.c = 1; -} break; +} -//sed -case 0xf8: { +void sCPU::op_sed() { last_cycle(); op_io(); regs.p.d = 1; -} break; +} -//sei -case 0x78: { +void sCPU::op_sei() { last_cycle(); op_io(); regs.p.i = 1; -} break; +} -//rep -case 0xc2: { +void sCPU::op_rep() { rd.l = op_readpc(); last_cycle(); op_io(); @@ -190,10 +172,9 @@ case 0xc2: { regs.x.h = 0x00; regs.y.h = 0x00; } -} break; +} -//sep -case 0xe2: { +void sCPU::op_sep() { rd.l = op_readpc(); last_cycle(); op_io(); @@ -203,10 +184,9 @@ case 0xe2: { regs.x.h = 0x00; regs.y.h = 0x00; } -} break; +} -//tax -case 0xaa: { +void sCPU::op_tax() { last_cycle(); op_io(); if(regs.p.x) { @@ -218,10 +198,9 @@ case 0xaa: { regs.p.n = !!(regs.x.w & 0x8000); regs.p.z = (regs.x.w == 0); } -} break; +} -//tay -case 0xa8: { +void sCPU::op_tay() { last_cycle(); op_io(); if(regs.p.x) { @@ -233,10 +212,9 @@ case 0xa8: { regs.p.n = !!(regs.y.w & 0x8000); regs.p.z = (regs.y.w == 0); } -} break; +} -//txa -case 0x8a: { +void sCPU::op_txa() { last_cycle(); op_io(); if(regs.p.m) { @@ -248,10 +226,9 @@ case 0x8a: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//txy -case 0x9b: { +void sCPU::op_txy() { last_cycle(); op_io(); if(regs.p.x) { @@ -263,10 +240,9 @@ case 0x9b: { regs.p.n = !!(regs.y.w & 0x8000); regs.p.z = (regs.y.w == 0); } -} break; +} -//tya -case 0x98: { +void sCPU::op_tya() { last_cycle(); op_io(); if(regs.p.m) { @@ -278,10 +254,9 @@ case 0x98: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//tyx -case 0xbb: { +void sCPU::op_tyx() { last_cycle(); op_io(); if(regs.p.x) { @@ -293,36 +268,32 @@ case 0xbb: { regs.p.n = !!(regs.x.w & 0x8000); regs.p.z = (regs.x.w == 0); } -} break; +} -//tcd -case 0x5b: { +void sCPU::op_tcd() { last_cycle(); op_io(); regs.d.w = regs.a.w; regs.p.n = !!(regs.d.w & 0x8000); regs.p.z = (regs.d.w == 0); -} break; +} -//tcs -case 0x1b: { +void sCPU::op_tcs() { last_cycle(); op_io(); regs.s.w = regs.a.w; if(regs.e)regs.s.h = 0x01; -} break; +} -//tdc -case 0x7b: { +void sCPU::op_tdc() { last_cycle(); op_io(); regs.a.w = regs.d.w; regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); -} break; +} -//tsc -case 0x3b: { +void sCPU::op_tsc() { last_cycle(); op_io(); regs.a.w = regs.s.w; @@ -333,10 +304,9 @@ case 0x3b: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//tsx -case 0xba: { +void sCPU::op_tsx() { last_cycle(); op_io(); if(regs.p.x) { @@ -348,10 +318,9 @@ case 0xba: { regs.p.n = !!(regs.x.w & 0x8000); regs.p.z = (regs.x.w == 0); } -} break; +} -//txs -case 0x9a: { +void sCPU::op_txs() { last_cycle(); op_io(); if(regs.e) { @@ -359,64 +328,56 @@ case 0x9a: { } else { regs.s.w = regs.x.w; } -} break; +} -//pha -case 0x48: { +void sCPU::op_pha() { op_io(); if(!regs.p.m)op_writestack(regs.a.h); last_cycle(); op_writestack(regs.a.l); -} break; +} -//phx -case 0xda: { +void sCPU::op_phx() { op_io(); if(!regs.p.x)op_writestack(regs.x.h); last_cycle(); op_writestack(regs.x.l); -} break; +} -//phy -case 0x5a: { +void sCPU::op_phy() { op_io(); if(!regs.p.x)op_writestack(regs.y.h); last_cycle(); op_writestack(regs.y.l); -} break; +} -//phd -case 0x0b: { +void sCPU::op_phd() { op_io(); op_writestackn(regs.d.h); last_cycle(); op_writestackn(regs.d.l); if(regs.e)regs.s.h = 0x01; -} break; +} -//phb -case 0x8b: { +void sCPU::op_phb() { op_io(); last_cycle(); op_writestack(regs.db); -} break; +} -//phk -case 0x4b: { +void sCPU::op_phk() { op_io(); last_cycle(); op_writestack(regs.pc.b); -} break; +} -//php -case 0x08: { +void sCPU::op_php() { op_io(); last_cycle(); op_writestack(regs.p); -} break; +} -//pla -case 0x68: { +void sCPU::op_pla() { op_io(); op_io(); if(regs.p.m)last_cycle(); @@ -424,16 +385,15 @@ case 0x68: { if(regs.p.m) { regs.p.n = !!(regs.a.l & 0x80); regs.p.z = (regs.a.l == 0); - break; + return; } last_cycle(); regs.a.h = op_readstack(); regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); -} break; +} -//plx -case 0xfa: { +void sCPU::op_plx() { op_io(); op_io(); if(regs.p.x)last_cycle(); @@ -441,16 +401,15 @@ case 0xfa: { if(regs.p.x) { regs.p.n = !!(regs.x.l & 0x80); regs.p.z = (regs.x.l == 0); - break; + return; } last_cycle(); regs.x.h = op_readstack(); regs.p.n = !!(regs.x.w & 0x8000); regs.p.z = (regs.x.w == 0); -} break; +} -//ply -case 0x7a: { +void sCPU::op_ply() { op_io(); op_io(); if(regs.p.x)last_cycle(); @@ -458,16 +417,15 @@ case 0x7a: { if(regs.p.x) { regs.p.n = !!(regs.y.l & 0x80); regs.p.z = (regs.y.l == 0); - break; + return; } last_cycle(); regs.y.h = op_readstack(); regs.p.n = !!(regs.y.w & 0x8000); regs.p.z = (regs.y.w == 0); -} break; +} -//pld -case 0x2b: { +void sCPU::op_pld() { op_io(); op_io(); regs.d.l = op_readstackn(); @@ -476,20 +434,18 @@ case 0x2b: { regs.p.n = !!(regs.d.w & 0x8000); regs.p.z = (regs.d.w == 0); if(regs.e)regs.s.h = 0x01; -} break; +} -//plb -case 0xab: { +void sCPU::op_plb() { op_io(); op_io(); last_cycle(); regs.db = op_readstack(); regs.p.n = !!(regs.db & 0x80); regs.p.z = (regs.db == 0); -} break; +} -//plp -case 0x28: { +void sCPU::op_plp() { op_io(); op_io(); last_cycle(); @@ -499,20 +455,18 @@ case 0x28: { regs.x.h = 0x00; regs.y.h = 0x00; } -} break; +} -//pea -case 0xf4: { +void sCPU::op_pea() { aa.l = op_readpc(); aa.h = op_readpc(); op_writestackn(aa.h); last_cycle(); op_writestackn(aa.l); if(regs.e)regs.s.h = 0x01; -} break; +} -//pei -case 0xd4: { +void sCPU::op_pei() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -521,10 +475,9 @@ case 0xd4: { last_cycle(); op_writestackn(aa.l); if(regs.e)regs.s.h = 0x01; -} break; +} -//per -case 0x62: { +void sCPU::op_per() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -533,5 +486,5 @@ case 0x62: { last_cycle(); op_writestackn(rd.l); if(regs.e)regs.s.h = 0x01; -} break; +} diff --git a/src/cpu/scpu/core/op_pc.cpp b/src/cpu/scpu/core/op_pc.cpp index 9f61ba83..16f174a6 100644 --- a/src/cpu/scpu/core/op_pc.cpp +++ b/src/cpu/scpu/core/op_pc.cpp @@ -1,171 +1,157 @@ -//bcc -case 0x90: { +void sCPU::op_bcc() { if(!!regs.p.c)last_cycle(); rd.l = op_readpc(); if(!regs.p.c) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//bcs -case 0xb0: { +void sCPU::op_bcs() { if(!regs.p.c)last_cycle(); rd.l = op_readpc(); if(regs.p.c) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//bne -case 0xd0: { +void sCPU::op_bne() { if(!!regs.p.z)last_cycle(); rd.l = op_readpc(); if(!regs.p.z) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//beq -case 0xf0: { +void sCPU::op_beq() { if(!regs.p.z)last_cycle(); rd.l = op_readpc(); if(regs.p.z) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//bpl -case 0x10: { +void sCPU::op_bpl() { if(!!regs.p.n)last_cycle(); rd.l = op_readpc(); if(!regs.p.n) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//bmi -case 0x30: { +void sCPU::op_bmi() { if(!regs.p.n)last_cycle(); rd.l = op_readpc(); if(regs.p.n) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//bvc -case 0x50: { +void sCPU::op_bvc() { if(!!regs.p.v)last_cycle(); rd.l = op_readpc(); if(!regs.p.v) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//bvs -case 0x70: { +void sCPU::op_bvs() { if(!regs.p.v)last_cycle(); rd.l = op_readpc(); if(regs.p.v) { aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; } else { - break; + return; } op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//bra -case 0x80: { +void sCPU::op_bra() { rd.l = op_readpc(); aa.w = regs.pc.d + (int8)rd.l; regs.pc.w = aa.w; op_io_cond6(aa.w); last_cycle(); op_io(); -} break; +} -//brl -case 0x82: { +void sCPU::op_brl() { rd.l = op_readpc(); rd.h = op_readpc(); last_cycle(); op_io(); regs.pc.w = regs.pc.d + (int16)rd.w; -} break; +} -//jmp_addr -case 0x4c: { +void sCPU::op_jmp_addr() { rd.l = op_readpc(); last_cycle(); rd.h = op_readpc(); regs.pc.w = rd.w; -} break; +} -//jmp_long -case 0x5c: { +void sCPU::op_jmp_long() { rd.l = op_readpc(); rd.h = op_readpc(); last_cycle(); rd.b = op_readpc(); regs.pc.d = rd.d & 0xffffff; -} break; +} -//jmp_iaddr -case 0x6c: { +void sCPU::op_jmp_iaddr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readaddr(aa.w); last_cycle(); rd.h = op_readaddr(aa.w + 1); regs.pc.w = rd.w; -} break; +} -//jmp_iaddrx -case 0x7c: { +void sCPU::op_jmp_iaddrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -173,10 +159,9 @@ case 0x7c: { last_cycle(); rd.h = op_readpbr(aa.w + regs.x.w + 1); regs.pc.w = rd.w; -} break; +} -//jmp_iladdr -case 0xdc: { +void sCPU::op_jmp_iladdr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readaddr(aa.w); @@ -184,10 +169,9 @@ case 0xdc: { last_cycle(); rd.b = op_readaddr(aa.w + 2); regs.pc.d = rd.d & 0xffffff; -} break; +} -//jsr_addr -case 0x20: { +void sCPU::op_jsr_addr() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -196,10 +180,9 @@ case 0x20: { last_cycle(); op_writestack(regs.pc.l); regs.pc.w = aa.w; -} break; +} -//jsr_long -case 0x22: { +void sCPU::op_jsr_long() { aa.l = op_readpc(); aa.h = op_readpc(); op_writestackn(regs.pc.b); @@ -211,10 +194,9 @@ case 0x22: { op_writestackn(regs.pc.l); regs.pc.d = aa.d & 0xffffff; if(regs.e)regs.s.h = 0x01; -} break; +} -//jsr_iaddrx -case 0xfc: { +void sCPU::op_jsr_iaddrx() { aa.l = op_readpc(); op_writestackn(regs.pc.h); op_writestackn(regs.pc.l); @@ -225,10 +207,9 @@ case 0xfc: { rd.h = op_readpbr(aa.w + regs.x.w + 1); regs.pc.w = rd.w; if(regs.e)regs.s.h = 0x01; -} break; +} -//rti -case 0x40: { +void sCPU::op_rti() { op_io(); op_io(); regs.p = op_readstack(); @@ -242,15 +223,14 @@ case 0x40: { rd.h = op_readstack(); if(regs.e) { regs.pc.w = rd.w; - break; + return; } last_cycle(); rd.b = op_readstack(); regs.pc.d = rd.d & 0xffffff; -} break; +} -//rts -case 0x60: { +void sCPU::op_rts() { op_io(); op_io(); rd.l = op_readstack(); @@ -259,10 +239,9 @@ case 0x60: { op_io(); regs.pc.w = rd.w; regs.pc.w++; -} break; +} -//rtl -case 0x6b: { +void sCPU::op_rtl() { op_io(); op_io(); rd.l = op_readstackn(); @@ -272,5 +251,5 @@ case 0x6b: { regs.pc.d = rd.d & 0xffffff; regs.pc.w++; if(regs.e)regs.s.h = 0x01; -} break; +} diff --git a/src/cpu/scpu/core/op_read.cpp b/src/cpu/scpu/core/op_read.cpp index fee2eda8..7eeb756c 100644 --- a/src/cpu/scpu/core/op_read.cpp +++ b/src/cpu/scpu/core/op_read.cpp @@ -1,1034 +1,950 @@ -//adc_const -case 0x69: { +void sCPU::op_adc_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readpc(); op_adc_w(); -} break; +} -//and_const -case 0x29: { +void sCPU::op_and_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readpc(); op_and_w(); -} break; +} -//cmp_const -case 0xc9: { +void sCPU::op_cmp_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readpc(); op_cmp_w(); -} break; +} -//cpx_const -case 0xe0: { +void sCPU::op_cpx_const() { if(regs.p.x)last_cycle(); rd.l = op_readpc(); - if(regs.p.x) { op_cpx_b(); break; } + if(regs.p.x) { op_cpx_b(); return; } last_cycle(); rd.h = op_readpc(); op_cpx_w(); -} break; +} -//cpy_const -case 0xc0: { +void sCPU::op_cpy_const() { if(regs.p.x)last_cycle(); rd.l = op_readpc(); - if(regs.p.x) { op_cpy_b(); break; } + if(regs.p.x) { op_cpy_b(); return; } last_cycle(); rd.h = op_readpc(); op_cpy_w(); -} break; +} -//eor_const -case 0x49: { +void sCPU::op_eor_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readpc(); op_eor_w(); -} break; +} -//lda_const -case 0xa9: { +void sCPU::op_lda_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readpc(); op_lda_w(); -} break; +} -//ldx_const -case 0xa2: { +void sCPU::op_ldx_const() { if(regs.p.x)last_cycle(); rd.l = op_readpc(); - if(regs.p.x) { op_ldx_b(); break; } + if(regs.p.x) { op_ldx_b(); return; } last_cycle(); rd.h = op_readpc(); op_ldx_w(); -} break; +} -//ldy_const -case 0xa0: { +void sCPU::op_ldy_const() { if(regs.p.x)last_cycle(); rd.l = op_readpc(); - if(regs.p.x) { op_ldy_b(); break; } + if(regs.p.x) { op_ldy_b(); return; } last_cycle(); rd.h = op_readpc(); op_ldy_w(); -} break; +} -//ora_const -case 0x09: { +void sCPU::op_ora_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readpc(); op_ora_w(); -} break; +} -//sbc_const -case 0xe9: { +void sCPU::op_sbc_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readpc(); op_sbc_w(); -} break; +} -//adc_addr -case 0x6d: { +void sCPU::op_adc_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_adc_w(); -} break; +} -//and_addr -case 0x2d: { +void sCPU::op_and_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_and_w(); -} break; +} -//bit_addr -case 0x2c: { +void sCPU::op_bit_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_bit_b(); break; } + if(regs.p.m) { op_bit_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_bit_w(); -} break; +} -//cmp_addr -case 0xcd: { +void sCPU::op_cmp_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_cmp_w(); -} break; +} -//cpx_addr -case 0xec: { +void sCPU::op_cpx_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.x)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.x) { op_cpx_b(); break; } + if(regs.p.x) { op_cpx_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_cpx_w(); -} break; +} -//cpy_addr -case 0xcc: { +void sCPU::op_cpy_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.x)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.x) { op_cpy_b(); break; } + if(regs.p.x) { op_cpy_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_cpy_w(); -} break; +} -//eor_addr -case 0x4d: { +void sCPU::op_eor_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_eor_w(); -} break; +} -//lda_addr -case 0xad: { +void sCPU::op_lda_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_lda_w(); -} break; +} -//ldx_addr -case 0xae: { +void sCPU::op_ldx_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.x)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.x) { op_ldx_b(); break; } + if(regs.p.x) { op_ldx_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_ldx_w(); -} break; +} -//ldy_addr -case 0xac: { +void sCPU::op_ldy_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.x)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.x) { op_ldy_b(); break; } + if(regs.p.x) { op_ldy_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_ldy_w(); -} break; +} -//ora_addr -case 0x0d: { +void sCPU::op_ora_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_ora_w(); -} break; +} -//sbc_addr -case 0xed: { +void sCPU::op_sbc_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_sbc_w(); -} break; +} -//adc_addrx -case 0x7d: { +void sCPU::op_adc_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_adc_w(); -} break; +} -//and_addrx -case 0x3d: { +void sCPU::op_and_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_and_w(); -} break; +} -//bit_addrx -case 0x3c: { +void sCPU::op_bit_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_bit_b(); break; } + if(regs.p.m) { op_bit_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_bit_w(); -} break; +} -//cmp_addrx -case 0xdd: { +void sCPU::op_cmp_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_cmp_w(); -} break; +} -//eor_addrx -case 0x5d: { +void sCPU::op_eor_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_eor_w(); -} break; +} -//lda_addrx -case 0xbd: { +void sCPU::op_lda_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_lda_w(); -} break; +} -//ldy_addrx -case 0xbc: { +void sCPU::op_ldy_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.x)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.x) { op_ldy_b(); break; } + if(regs.p.x) { op_ldy_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_ldy_w(); -} break; +} -//ora_addrx -case 0x1d: { +void sCPU::op_ora_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_ora_w(); -} break; +} -//sbc_addrx -case 0xfd: { +void sCPU::op_sbc_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.x.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.x.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.x.w + 1); op_sbc_w(); -} break; +} -//adc_addry -case 0x79: { +void sCPU::op_adc_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_adc_w(); -} break; +} -//and_addry -case 0x39: { +void sCPU::op_and_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_and_w(); -} break; +} -//cmp_addry -case 0xd9: { +void sCPU::op_cmp_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_cmp_w(); -} break; +} -//eor_addry -case 0x59: { +void sCPU::op_eor_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_eor_w(); -} break; +} -//lda_addry -case 0xb9: { +void sCPU::op_lda_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_lda_w(); -} break; +} -//ldx_addry -case 0xbe: { +void sCPU::op_ldx_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.x)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.x) { op_ldx_b(); break; } + if(regs.p.x) { op_ldx_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_ldx_w(); -} break; +} -//ora_addry -case 0x19: { +void sCPU::op_ora_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_ora_w(); -} break; +} -//sbc_addry -case 0xf9: { +void sCPU::op_sbc_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_sbc_w(); -} break; +} -//adc_long -case 0x6f: { +void sCPU::op_adc_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_adc_w(); -} break; +} -//and_long -case 0x2f: { +void sCPU::op_and_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_and_w(); -} break; +} -//cmp_long -case 0xcf: { +void sCPU::op_cmp_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_cmp_w(); -} break; +} -//eor_long -case 0x4f: { +void sCPU::op_eor_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_eor_w(); -} break; +} -//lda_long -case 0xaf: { +void sCPU::op_lda_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_lda_w(); -} break; +} -//ora_long -case 0x0f: { +void sCPU::op_ora_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_ora_w(); -} break; +} -//sbc_long -case 0xef: { +void sCPU::op_sbc_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_sbc_w(); -} break; +} -//adc_longx -case 0x7f: { +void sCPU::op_adc_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.x.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.x.w + 1); op_adc_w(); -} break; +} -//and_longx -case 0x3f: { +void sCPU::op_and_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.x.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.x.w + 1); op_and_w(); -} break; +} -//cmp_longx -case 0xdf: { +void sCPU::op_cmp_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.x.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.x.w + 1); op_cmp_w(); -} break; +} -//eor_longx -case 0x5f: { +void sCPU::op_eor_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.x.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.x.w + 1); op_eor_w(); -} break; +} -//lda_longx -case 0xbf: { +void sCPU::op_lda_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.x.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.x.w + 1); op_lda_w(); -} break; +} -//ora_longx -case 0x1f: { +void sCPU::op_ora_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.x.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.x.w + 1); op_ora_w(); -} break; +} -//sbc_longx -case 0xff: { +void sCPU::op_sbc_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.x.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.x.w + 1); op_sbc_w(); -} break; +} -//adc_dp -case 0x65: { +void sCPU::op_adc_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_adc_w(); -} break; +} -//and_dp -case 0x25: { +void sCPU::op_and_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_and_w(); -} break; +} -//bit_dp -case 0x24: { +void sCPU::op_bit_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_bit_b(); break; } + if(regs.p.m) { op_bit_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_bit_w(); -} break; +} -//cmp_dp -case 0xc5: { +void sCPU::op_cmp_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_cmp_w(); -} break; +} -//cpx_dp -case 0xe4: { +void sCPU::op_cpx_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.x)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.x) { op_cpx_b(); break; } + if(regs.p.x) { op_cpx_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_cpx_w(); -} break; +} -//cpy_dp -case 0xc4: { +void sCPU::op_cpy_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.x)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.x) { op_cpy_b(); break; } + if(regs.p.x) { op_cpy_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_cpy_w(); -} break; +} -//eor_dp -case 0x45: { +void sCPU::op_eor_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_eor_w(); -} break; +} -//lda_dp -case 0xa5: { +void sCPU::op_lda_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_lda_w(); -} break; +} -//ldx_dp -case 0xa6: { +void sCPU::op_ldx_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.x)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.x) { op_ldx_b(); break; } + if(regs.p.x) { op_ldx_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_ldx_w(); -} break; +} -//ldy_dp -case 0xa4: { +void sCPU::op_ldy_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.x)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.x) { op_ldy_b(); break; } + if(regs.p.x) { op_ldy_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_ldy_w(); -} break; +} -//ora_dp -case 0x05: { +void sCPU::op_ora_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_ora_w(); -} break; +} -//sbc_dp -case 0xe5: { +void sCPU::op_sbc_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdp(dp + 1); op_sbc_w(); -} break; +} -//adc_dpx -case 0x75: { +void sCPU::op_adc_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_adc_w(); -} break; +} -//and_dpx -case 0x35: { +void sCPU::op_and_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_and_w(); -} break; +} -//bit_dpx -case 0x34: { +void sCPU::op_bit_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_bit_b(); break; } + if(regs.p.m) { op_bit_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_bit_w(); -} break; +} -//cmp_dpx -case 0xd5: { +void sCPU::op_cmp_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_cmp_w(); -} break; +} -//eor_dpx -case 0x55: { +void sCPU::op_eor_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_eor_w(); -} break; +} -//lda_dpx -case 0xb5: { +void sCPU::op_lda_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_lda_w(); -} break; +} -//ldy_dpx -case 0xb4: { +void sCPU::op_ldy_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.x)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.x) { op_ldy_b(); break; } + if(regs.p.x) { op_ldy_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_ldy_w(); -} break; +} -//ora_dpx -case 0x15: { +void sCPU::op_ora_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_ora_w(); -} break; +} -//sbc_dpx -case 0xf5: { +void sCPU::op_sbc_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdp(dp + regs.x.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.x.w + 1); op_sbc_w(); -} break; +} -//ldx_dpy -case 0xb6: { +void sCPU::op_ldx_dpy() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.x)last_cycle(); rd.l = op_readdp(dp + regs.y.w); - if(regs.p.x) { op_ldx_b(); break; } + if(regs.p.x) { op_ldx_b(); return; } last_cycle(); rd.h = op_readdp(dp + regs.y.w + 1); op_ldx_w(); -} break; +} -//adc_idp -case 0x72: { +void sCPU::op_adc_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_adc_w(); -} break; +} -//and_idp -case 0x32: { +void sCPU::op_and_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_and_w(); -} break; +} -//cmp_idp -case 0xd2: { +void sCPU::op_cmp_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_cmp_w(); -} break; +} -//eor_idp -case 0x52: { +void sCPU::op_eor_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_eor_w(); -} break; +} -//lda_idp -case 0xb2: { +void sCPU::op_lda_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_lda_w(); -} break; +} -//ora_idp -case 0x12: { +void sCPU::op_ora_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_ora_w(); -} break; +} -//sbc_idp -case 0xf2: { +void sCPU::op_sbc_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_sbc_w(); -} break; +} -//adc_idpx -case 0x61: { +void sCPU::op_adc_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -1036,14 +952,13 @@ case 0x61: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_adc_w(); -} break; +} -//and_idpx -case 0x21: { +void sCPU::op_and_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -1051,14 +966,13 @@ case 0x21: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_and_w(); -} break; +} -//cmp_idpx -case 0xc1: { +void sCPU::op_cmp_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -1066,14 +980,13 @@ case 0xc1: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_cmp_w(); -} break; +} -//eor_idpx -case 0x41: { +void sCPU::op_eor_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -1081,14 +994,13 @@ case 0x41: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_eor_w(); -} break; +} -//lda_idpx -case 0xa1: { +void sCPU::op_lda_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -1096,14 +1008,13 @@ case 0xa1: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_lda_w(); -} break; +} -//ora_idpx -case 0x01: { +void sCPU::op_ora_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -1111,14 +1022,13 @@ case 0x01: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_ora_w(); -} break; +} -//sbc_idpx -case 0xe1: { +void sCPU::op_sbc_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -1126,14 +1036,13 @@ case 0xe1: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + 1); op_sbc_w(); -} break; +} -//adc_idpy -case 0x71: { +void sCPU::op_adc_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1141,14 +1050,13 @@ case 0x71: { op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_adc_w(); -} break; +} -//and_idpy -case 0x31: { +void sCPU::op_and_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1156,14 +1064,13 @@ case 0x31: { op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_and_w(); -} break; +} -//cmp_idpy -case 0xd1: { +void sCPU::op_cmp_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1171,14 +1078,13 @@ case 0xd1: { op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_cmp_w(); -} break; +} -//eor_idpy -case 0x51: { +void sCPU::op_eor_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1186,14 +1092,13 @@ case 0x51: { op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_eor_w(); -} break; +} -//lda_idpy -case 0xb1: { +void sCPU::op_lda_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1201,14 +1106,13 @@ case 0xb1: { op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_lda_w(); -} break; +} -//ora_idpy -case 0x11: { +void sCPU::op_ora_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1216,14 +1120,13 @@ case 0x11: { op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_ora_w(); -} break; +} -//sbc_idpy -case 0xf1: { +void sCPU::op_sbc_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1231,14 +1134,13 @@ case 0xf1: { op_io_cond4(aa.w, aa.w + regs.y.w); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_sbc_w(); -} break; +} -//adc_ildp -case 0x67: { +void sCPU::op_adc_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1246,14 +1148,13 @@ case 0x67: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_adc_w(); -} break; +} -//and_ildp -case 0x27: { +void sCPU::op_and_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1261,14 +1162,13 @@ case 0x27: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_and_w(); -} break; +} -//cmp_ildp -case 0xc7: { +void sCPU::op_cmp_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1276,14 +1176,13 @@ case 0xc7: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_cmp_w(); -} break; +} -//eor_ildp -case 0x47: { +void sCPU::op_eor_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1291,14 +1190,13 @@ case 0x47: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_eor_w(); -} break; +} -//lda_ildp -case 0xa7: { +void sCPU::op_lda_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1306,14 +1204,13 @@ case 0xa7: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_lda_w(); -} break; +} -//ora_ildp -case 0x07: { +void sCPU::op_ora_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1321,14 +1218,13 @@ case 0x07: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_ora_w(); -} break; +} -//sbc_ildp -case 0xe7: { +void sCPU::op_sbc_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1336,14 +1232,13 @@ case 0xe7: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + 1); op_sbc_w(); -} break; +} -//adc_ildpy -case 0x77: { +void sCPU::op_adc_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1351,14 +1246,13 @@ case 0x77: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.y.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.y.w + 1); op_adc_w(); -} break; +} -//and_ildpy -case 0x37: { +void sCPU::op_and_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1366,14 +1260,13 @@ case 0x37: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.y.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.y.w + 1); op_and_w(); -} break; +} -//cmp_ildpy -case 0xd7: { +void sCPU::op_cmp_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1381,14 +1274,13 @@ case 0xd7: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.y.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.y.w + 1); op_cmp_w(); -} break; +} -//eor_ildpy -case 0x57: { +void sCPU::op_eor_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1396,14 +1288,13 @@ case 0x57: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.y.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.y.w + 1); op_eor_w(); -} break; +} -//lda_ildpy -case 0xb7: { +void sCPU::op_lda_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1411,14 +1302,13 @@ case 0xb7: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.y.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.y.w + 1); op_lda_w(); -} break; +} -//ora_ildpy -case 0x17: { +void sCPU::op_ora_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1426,14 +1316,13 @@ case 0x17: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.y.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.y.w + 1); op_ora_w(); -} break; +} -//sbc_ildpy -case 0xf7: { +void sCPU::op_sbc_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -1441,98 +1330,90 @@ case 0xf7: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); rd.l = op_readlong(aa.d + regs.y.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readlong(aa.d + regs.y.w + 1); op_sbc_w(); -} break; +} -//adc_sr -case 0x63: { +void sCPU::op_adc_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readsp(sp); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readsp(sp + 1); op_adc_w(); -} break; +} -//and_sr -case 0x23: { +void sCPU::op_and_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readsp(sp); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readsp(sp + 1); op_and_w(); -} break; +} -//cmp_sr -case 0xc3: { +void sCPU::op_cmp_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readsp(sp); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readsp(sp + 1); op_cmp_w(); -} break; +} -//eor_sr -case 0x43: { +void sCPU::op_eor_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readsp(sp); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readsp(sp + 1); op_eor_w(); -} break; +} -//lda_sr -case 0xa3: { +void sCPU::op_lda_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readsp(sp); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readsp(sp + 1); op_lda_w(); -} break; +} -//ora_sr -case 0x03: { +void sCPU::op_ora_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readsp(sp); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readsp(sp + 1); op_ora_w(); -} break; +} -//sbc_sr -case 0xe3: { +void sCPU::op_sbc_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); rd.l = op_readsp(sp); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readsp(sp + 1); op_sbc_w(); -} break; +} -//adc_isry -case 0x73: { +void sCPU::op_adc_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -1540,14 +1421,13 @@ case 0x73: { op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_adc_b(); break; } + if(regs.p.m) { op_adc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_adc_w(); -} break; +} -//and_isry -case 0x33: { +void sCPU::op_and_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -1555,14 +1435,13 @@ case 0x33: { op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_and_b(); break; } + if(regs.p.m) { op_and_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_and_w(); -} break; +} -//cmp_isry -case 0xd3: { +void sCPU::op_cmp_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -1570,14 +1449,13 @@ case 0xd3: { op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_cmp_b(); break; } + if(regs.p.m) { op_cmp_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_cmp_w(); -} break; +} -//eor_isry -case 0x53: { +void sCPU::op_eor_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -1585,14 +1463,13 @@ case 0x53: { op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_eor_b(); break; } + if(regs.p.m) { op_eor_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_eor_w(); -} break; +} -//lda_isry -case 0xb3: { +void sCPU::op_lda_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -1600,14 +1477,13 @@ case 0xb3: { op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_lda_b(); break; } + if(regs.p.m) { op_lda_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_lda_w(); -} break; +} -//ora_isry -case 0x13: { +void sCPU::op_ora_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -1615,14 +1491,13 @@ case 0x13: { op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_ora_b(); break; } + if(regs.p.m) { op_ora_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_ora_w(); -} break; +} -//sbc_isry -case 0xf3: { +void sCPU::op_sbc_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -1630,22 +1505,21 @@ case 0xf3: { op_io(); if(regs.p.m)last_cycle(); rd.l = op_readdbr(aa.w + regs.y.w); - if(regs.p.m) { op_sbc_b(); break; } + if(regs.p.m) { op_sbc_b(); return; } last_cycle(); rd.h = op_readdbr(aa.w + regs.y.w + 1); op_sbc_w(); -} break; +} -//bit_const -case 0x89: { +void sCPU::op_bit_const() { if(regs.p.m)last_cycle(); rd.l = op_readpc(); if(regs.p.m) { regs.p.z = ((rd.l & regs.a.l) == 0); - break; + return; } last_cycle(); rd.h = op_readpc(); regs.p.z = ((rd.w & regs.a.w) == 0); -} break; +} diff --git a/src/cpu/scpu/core/op_rmw.cpp b/src/cpu/scpu/core/op_rmw.cpp index 7924a1ab..2a83066a 100644 --- a/src/cpu/scpu/core/op_rmw.cpp +++ b/src/cpu/scpu/core/op_rmw.cpp @@ -1,5 +1,4 @@ -//inc -case 0x1a: { +void sCPU::op_inc() { last_cycle(); op_io(); if(regs.p.m) { @@ -11,10 +10,9 @@ case 0x1a: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//inx -case 0xe8: { +void sCPU::op_inx() { last_cycle(); op_io(); if(regs.p.x) { @@ -26,10 +24,9 @@ case 0xe8: { regs.p.n = !!(regs.x.w & 0x8000); regs.p.z = (regs.x.w == 0); } -} break; +} -//iny -case 0xc8: { +void sCPU::op_iny() { last_cycle(); op_io(); if(regs.p.x) { @@ -41,10 +38,9 @@ case 0xc8: { regs.p.n = !!(regs.y.w & 0x8000); regs.p.z = (regs.y.w == 0); } -} break; +} -//dec -case 0x3a: { +void sCPU::op_dec() { last_cycle(); op_io(); if(regs.p.m) { @@ -56,10 +52,9 @@ case 0x3a: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//dex -case 0xca: { +void sCPU::op_dex() { last_cycle(); op_io(); if(regs.p.x) { @@ -71,10 +66,9 @@ case 0xca: { regs.p.n = !!(regs.x.w & 0x8000); regs.p.z = (regs.x.w == 0); } -} break; +} -//dey -case 0x88: { +void sCPU::op_dey() { last_cycle(); op_io(); if(regs.p.x) { @@ -86,10 +80,9 @@ case 0x88: { regs.p.n = !!(regs.y.w & 0x8000); regs.p.z = (regs.y.w == 0); } -} break; +} -//asl -case 0x0a: { +void sCPU::op_asl() { last_cycle(); op_io(); if(regs.p.m) { @@ -103,10 +96,9 @@ case 0x0a: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//lsr -case 0x4a: { +void sCPU::op_lsr() { last_cycle(); op_io(); if(regs.p.m) { @@ -120,10 +112,9 @@ case 0x4a: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//rol -case 0x2a: { +void sCPU::op_rol() { last_cycle(); op_io(); uint16 c = regs.p.c; @@ -140,10 +131,9 @@ case 0x2a: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//ror -case 0x6a: { +void sCPU::op_ror() { last_cycle(); op_io(); uint16 c; @@ -162,10 +152,9 @@ case 0x6a: { regs.p.n = !!(regs.a.w & 0x8000); regs.p.z = (regs.a.w == 0); } -} break; +} -//inc_addr -case 0xee: { +void sCPU::op_inc_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -176,10 +165,9 @@ case 0xee: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//dec_addr -case 0xce: { +void sCPU::op_dec_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -190,10 +178,9 @@ case 0xce: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//asl_addr -case 0x0e: { +void sCPU::op_asl_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -204,10 +191,9 @@ case 0x0e: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//lsr_addr -case 0x4e: { +void sCPU::op_lsr_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -218,10 +204,9 @@ case 0x4e: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//rol_addr -case 0x2e: { +void sCPU::op_rol_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -232,10 +217,9 @@ case 0x2e: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//ror_addr -case 0x6e: { +void sCPU::op_ror_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -246,10 +230,9 @@ case 0x6e: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//trb_addr -case 0x1c: { +void sCPU::op_trb_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -260,10 +243,9 @@ case 0x1c: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//tsb_addr -case 0x0c: { +void sCPU::op_tsb_addr() { aa.l = op_readpc(); aa.h = op_readpc(); rd.l = op_readdbr(aa.w); @@ -274,10 +256,9 @@ case 0x0c: { op_writedbr(aa.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w, rd.l); -} break; +} -//inc_addrx -case 0xfe: { +void sCPU::op_inc_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -289,10 +270,9 @@ case 0xfe: { op_writedbr(aa.w + regs.x.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w + regs.x.w, rd.l); -} break; +} -//dec_addrx -case 0xde: { +void sCPU::op_dec_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -304,10 +284,9 @@ case 0xde: { op_writedbr(aa.w + regs.x.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w + regs.x.w, rd.l); -} break; +} -//asl_addrx -case 0x1e: { +void sCPU::op_asl_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -319,10 +298,9 @@ case 0x1e: { op_writedbr(aa.w + regs.x.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w + regs.x.w, rd.l); -} break; +} -//lsr_addrx -case 0x5e: { +void sCPU::op_lsr_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -334,10 +312,9 @@ case 0x5e: { op_writedbr(aa.w + regs.x.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w + regs.x.w, rd.l); -} break; +} -//rol_addrx -case 0x3e: { +void sCPU::op_rol_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -349,10 +326,9 @@ case 0x3e: { op_writedbr(aa.w + regs.x.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w + regs.x.w, rd.l); -} break; +} -//ror_addrx -case 0x7e: { +void sCPU::op_ror_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); @@ -364,10 +340,9 @@ case 0x7e: { op_writedbr(aa.w + regs.x.w + 1, rd.h); } last_cycle(); op_writedbr(aa.w + regs.x.w, rd.l); -} break; +} -//inc_dp -case 0xe6: { +void sCPU::op_inc_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -378,10 +353,9 @@ case 0xe6: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//dec_dp -case 0xc6: { +void sCPU::op_dec_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -392,10 +366,9 @@ case 0xc6: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//asl_dp -case 0x06: { +void sCPU::op_asl_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -406,10 +379,9 @@ case 0x06: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//lsr_dp -case 0x46: { +void sCPU::op_lsr_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -420,10 +392,9 @@ case 0x46: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//rol_dp -case 0x26: { +void sCPU::op_rol_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -434,10 +405,9 @@ case 0x26: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//ror_dp -case 0x66: { +void sCPU::op_ror_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -448,10 +418,9 @@ case 0x66: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//trb_dp -case 0x14: { +void sCPU::op_trb_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -462,10 +431,9 @@ case 0x14: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//tsb_dp -case 0x04: { +void sCPU::op_tsb_dp() { dp = op_readpc(); op_io_cond2(); rd.l = op_readdp(dp); @@ -476,10 +444,9 @@ case 0x04: { op_writedp(dp + 1, rd.h); } last_cycle(); op_writedp(dp, rd.l); -} break; +} -//inc_dpx -case 0xf6: { +void sCPU::op_inc_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -491,10 +458,9 @@ case 0xf6: { op_writedp(dp + regs.x.w + 1, rd.h); } last_cycle(); op_writedp(dp + regs.x.w, rd.l); -} break; +} -//dec_dpx -case 0xd6: { +void sCPU::op_dec_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -506,10 +472,9 @@ case 0xd6: { op_writedp(dp + regs.x.w + 1, rd.h); } last_cycle(); op_writedp(dp + regs.x.w, rd.l); -} break; +} -//asl_dpx -case 0x16: { +void sCPU::op_asl_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -521,10 +486,9 @@ case 0x16: { op_writedp(dp + regs.x.w + 1, rd.h); } last_cycle(); op_writedp(dp + regs.x.w, rd.l); -} break; +} -//lsr_dpx -case 0x56: { +void sCPU::op_lsr_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -536,10 +500,9 @@ case 0x56: { op_writedp(dp + regs.x.w + 1, rd.h); } last_cycle(); op_writedp(dp + regs.x.w, rd.l); -} break; +} -//rol_dpx -case 0x36: { +void sCPU::op_rol_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -551,10 +514,9 @@ case 0x36: { op_writedp(dp + regs.x.w + 1, rd.h); } last_cycle(); op_writedp(dp + regs.x.w, rd.l); -} break; +} -//ror_dpx -case 0x76: { +void sCPU::op_ror_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -566,5 +528,5 @@ case 0x76: { op_writedp(dp + regs.x.w + 1, rd.h); } last_cycle(); op_writedp(dp + regs.x.w, rd.l); -} break; +} diff --git a/src/cpu/scpu/core/op_write.cpp b/src/cpu/scpu/core/op_write.cpp index 97c731f9..c8e1ad10 100644 --- a/src/cpu/scpu/core/op_write.cpp +++ b/src/cpu/scpu/core/op_write.cpp @@ -1,214 +1,195 @@ -//sta_addr -case 0x8d: { +void sCPU::op_sta_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); op_writedbr(aa.w, regs.a.w); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + 1, regs.a.w >> 8); -} break; +} -//stx_addr -case 0x8e: { +void sCPU::op_stx_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.x)last_cycle(); op_writedbr(aa.w, regs.x.w); - if(regs.p.x)break; + if(regs.p.x)return; last_cycle(); op_writedbr(aa.w + 1, regs.x.w >> 8); -} break; +} -//sty_addr -case 0x8c: { +void sCPU::op_sty_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.x)last_cycle(); op_writedbr(aa.w, regs.y.w); - if(regs.p.x)break; + if(regs.p.x)return; last_cycle(); op_writedbr(aa.w + 1, regs.y.w >> 8); -} break; +} -//stz_addr -case 0x9c: { +void sCPU::op_stz_addr() { aa.l = op_readpc(); aa.h = op_readpc(); if(regs.p.m)last_cycle(); op_writedbr(aa.w, 0x0000); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + 1, 0x0000 >> 8); -} break; +} -//sta_addrx -case 0x9d: { +void sCPU::op_sta_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); if(regs.p.m)last_cycle(); op_writedbr(aa.w + regs.x.w, regs.a.w); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + regs.x.w + 1, regs.a.w >> 8); -} break; +} -//stz_addrx -case 0x9e: { +void sCPU::op_stz_addrx() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); if(regs.p.m)last_cycle(); op_writedbr(aa.w + regs.x.w, 0x0000); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + regs.x.w + 1, 0x0000 >> 8); -} break; +} -//sta_addry -case 0x99: { +void sCPU::op_sta_addry() { aa.l = op_readpc(); aa.h = op_readpc(); op_io(); if(regs.p.m)last_cycle(); op_writedbr(aa.w + regs.y.w, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + regs.y.w + 1, regs.a.h); -} break; +} -//sta_long -case 0x8f: { +void sCPU::op_sta_long() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); op_writelong(aa.d, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writelong(aa.d + 1, regs.a.h); -} break; +} -//sta_longx -case 0x9f: { +void sCPU::op_sta_longx() { aa.l = op_readpc(); aa.h = op_readpc(); aa.b = op_readpc(); if(regs.p.m)last_cycle(); op_writelong(aa.d + regs.x.w, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writelong(aa.d + regs.x.w + 1, regs.a.h); -} break; +} -//sta_dp -case 0x85: { +void sCPU::op_sta_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); op_writedp(dp, regs.a.w); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedp(dp + 1, regs.a.w >> 8); -} break; +} -//stx_dp -case 0x86: { +void sCPU::op_stx_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.x)last_cycle(); op_writedp(dp, regs.x.w); - if(regs.p.x)break; + if(regs.p.x)return; last_cycle(); op_writedp(dp + 1, regs.x.w >> 8); -} break; +} -//sty_dp -case 0x84: { +void sCPU::op_sty_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.x)last_cycle(); op_writedp(dp, regs.y.w); - if(regs.p.x)break; + if(regs.p.x)return; last_cycle(); op_writedp(dp + 1, regs.y.w >> 8); -} break; +} -//stz_dp -case 0x64: { +void sCPU::op_stz_dp() { dp = op_readpc(); op_io_cond2(); if(regs.p.m)last_cycle(); op_writedp(dp, 0x0000); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedp(dp + 1, 0x0000 >> 8); -} break; +} -//sta_dpx -case 0x95: { +void sCPU::op_sta_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); op_writedp(dp + regs.x.w, regs.a.w); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedp(dp + regs.x.w + 1, regs.a.w >> 8); -} break; +} -//sty_dpx -case 0x94: { +void sCPU::op_sty_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.x)last_cycle(); op_writedp(dp + regs.x.w, regs.y.w); - if(regs.p.x)break; + if(regs.p.x)return; last_cycle(); op_writedp(dp + regs.x.w + 1, regs.y.w >> 8); -} break; +} -//stz_dpx -case 0x74: { +void sCPU::op_stz_dpx() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.m)last_cycle(); op_writedp(dp + regs.x.w, 0x0000); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedp(dp + regs.x.w + 1, 0x0000 >> 8); -} break; +} -//stx_dpy -case 0x96: { +void sCPU::op_stx_dpy() { dp = op_readpc(); op_io_cond2(); op_io(); if(regs.p.x)last_cycle(); op_writedp(dp + regs.y.w, regs.x.l); - if(regs.p.x)break; + if(regs.p.x)return; last_cycle(); op_writedp(dp + regs.y.w + 1, regs.x.h); -} break; +} -//sta_idp -case 0x92: { +void sCPU::op_sta_idp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); aa.h = op_readdp(dp + 1); if(regs.p.m)last_cycle(); op_writedbr(aa.w, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + 1, regs.a.h); -} break; +} -//sta_ildp -case 0x87: { +void sCPU::op_sta_ildp() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -216,13 +197,12 @@ case 0x87: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); op_writelong(aa.d, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writelong(aa.d + 1, regs.a.h); -} break; +} -//sta_idpx -case 0x81: { +void sCPU::op_sta_idpx() { dp = op_readpc(); op_io_cond2(); op_io(); @@ -230,13 +210,12 @@ case 0x81: { aa.h = op_readdp(dp + regs.x.w + 1); if(regs.p.m)last_cycle(); op_writedbr(aa.w, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + 1, regs.a.h); -} break; +} -//sta_idpy -case 0x91: { +void sCPU::op_sta_idpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -244,13 +223,12 @@ case 0x91: { op_io(); if(regs.p.m)last_cycle(); op_writedbr(aa.w + regs.y.w, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + regs.y.w + 1, regs.a.h); -} break; +} -//sta_ildpy -case 0x97: { +void sCPU::op_sta_ildpy() { dp = op_readpc(); op_io_cond2(); aa.l = op_readdp(dp); @@ -258,24 +236,22 @@ case 0x97: { aa.b = op_readdp(dp + 2); if(regs.p.m)last_cycle(); op_writelong(aa.d + regs.y.w, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writelong(aa.d + regs.y.w + 1, regs.a.h); -} break; +} -//sta_sr -case 0x83: { +void sCPU::op_sta_sr() { sp = op_readpc(); op_io(); if(regs.p.m)last_cycle(); op_writesp(sp, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writesp(sp + 1, regs.a.h); -} break; +} -//sta_isry -case 0x93: { +void sCPU::op_sta_isry() { sp = op_readpc(); op_io(); aa.l = op_readsp(sp); @@ -283,8 +259,8 @@ case 0x93: { op_io(); if(regs.p.m)last_cycle(); op_writedbr(aa.w + regs.y.w, regs.a.l); - if(regs.p.m)break; + if(regs.p.m)return; last_cycle(); op_writedbr(aa.w + regs.y.w + 1, regs.a.h); -} break; +} diff --git a/src/cpu/scpu/core/optable.cpp b/src/cpu/scpu/core/optable.cpp new file mode 100644 index 00000000..88d52dd4 --- /dev/null +++ b/src/cpu/scpu/core/optable.cpp @@ -0,0 +1,256 @@ +optbl[0x69] = &sCPU::op_adc_const; +optbl[0x29] = &sCPU::op_and_const; +optbl[0xc9] = &sCPU::op_cmp_const; +optbl[0xe0] = &sCPU::op_cpx_const; +optbl[0xc0] = &sCPU::op_cpy_const; +optbl[0x49] = &sCPU::op_eor_const; +optbl[0xa9] = &sCPU::op_lda_const; +optbl[0xa2] = &sCPU::op_ldx_const; +optbl[0xa0] = &sCPU::op_ldy_const; +optbl[0x09] = &sCPU::op_ora_const; +optbl[0xe9] = &sCPU::op_sbc_const; +optbl[0x6d] = &sCPU::op_adc_addr; +optbl[0x2d] = &sCPU::op_and_addr; +optbl[0x2c] = &sCPU::op_bit_addr; +optbl[0xcd] = &sCPU::op_cmp_addr; +optbl[0xec] = &sCPU::op_cpx_addr; +optbl[0xcc] = &sCPU::op_cpy_addr; +optbl[0x4d] = &sCPU::op_eor_addr; +optbl[0xad] = &sCPU::op_lda_addr; +optbl[0xae] = &sCPU::op_ldx_addr; +optbl[0xac] = &sCPU::op_ldy_addr; +optbl[0x0d] = &sCPU::op_ora_addr; +optbl[0xed] = &sCPU::op_sbc_addr; +optbl[0x7d] = &sCPU::op_adc_addrx; +optbl[0x3d] = &sCPU::op_and_addrx; +optbl[0x3c] = &sCPU::op_bit_addrx; +optbl[0xdd] = &sCPU::op_cmp_addrx; +optbl[0x5d] = &sCPU::op_eor_addrx; +optbl[0xbd] = &sCPU::op_lda_addrx; +optbl[0xbc] = &sCPU::op_ldy_addrx; +optbl[0x1d] = &sCPU::op_ora_addrx; +optbl[0xfd] = &sCPU::op_sbc_addrx; +optbl[0x79] = &sCPU::op_adc_addry; +optbl[0x39] = &sCPU::op_and_addry; +optbl[0xd9] = &sCPU::op_cmp_addry; +optbl[0x59] = &sCPU::op_eor_addry; +optbl[0xb9] = &sCPU::op_lda_addry; +optbl[0xbe] = &sCPU::op_ldx_addry; +optbl[0x19] = &sCPU::op_ora_addry; +optbl[0xf9] = &sCPU::op_sbc_addry; +optbl[0x6f] = &sCPU::op_adc_long; +optbl[0x2f] = &sCPU::op_and_long; +optbl[0xcf] = &sCPU::op_cmp_long; +optbl[0x4f] = &sCPU::op_eor_long; +optbl[0xaf] = &sCPU::op_lda_long; +optbl[0x0f] = &sCPU::op_ora_long; +optbl[0xef] = &sCPU::op_sbc_long; +optbl[0x7f] = &sCPU::op_adc_longx; +optbl[0x3f] = &sCPU::op_and_longx; +optbl[0xdf] = &sCPU::op_cmp_longx; +optbl[0x5f] = &sCPU::op_eor_longx; +optbl[0xbf] = &sCPU::op_lda_longx; +optbl[0x1f] = &sCPU::op_ora_longx; +optbl[0xff] = &sCPU::op_sbc_longx; +optbl[0x65] = &sCPU::op_adc_dp; +optbl[0x25] = &sCPU::op_and_dp; +optbl[0x24] = &sCPU::op_bit_dp; +optbl[0xc5] = &sCPU::op_cmp_dp; +optbl[0xe4] = &sCPU::op_cpx_dp; +optbl[0xc4] = &sCPU::op_cpy_dp; +optbl[0x45] = &sCPU::op_eor_dp; +optbl[0xa5] = &sCPU::op_lda_dp; +optbl[0xa6] = &sCPU::op_ldx_dp; +optbl[0xa4] = &sCPU::op_ldy_dp; +optbl[0x05] = &sCPU::op_ora_dp; +optbl[0xe5] = &sCPU::op_sbc_dp; +optbl[0x75] = &sCPU::op_adc_dpx; +optbl[0x35] = &sCPU::op_and_dpx; +optbl[0x34] = &sCPU::op_bit_dpx; +optbl[0xd5] = &sCPU::op_cmp_dpx; +optbl[0x55] = &sCPU::op_eor_dpx; +optbl[0xb5] = &sCPU::op_lda_dpx; +optbl[0xb4] = &sCPU::op_ldy_dpx; +optbl[0x15] = &sCPU::op_ora_dpx; +optbl[0xf5] = &sCPU::op_sbc_dpx; +optbl[0xb6] = &sCPU::op_ldx_dpy; +optbl[0x72] = &sCPU::op_adc_idp; +optbl[0x32] = &sCPU::op_and_idp; +optbl[0xd2] = &sCPU::op_cmp_idp; +optbl[0x52] = &sCPU::op_eor_idp; +optbl[0xb2] = &sCPU::op_lda_idp; +optbl[0x12] = &sCPU::op_ora_idp; +optbl[0xf2] = &sCPU::op_sbc_idp; +optbl[0x61] = &sCPU::op_adc_idpx; +optbl[0x21] = &sCPU::op_and_idpx; +optbl[0xc1] = &sCPU::op_cmp_idpx; +optbl[0x41] = &sCPU::op_eor_idpx; +optbl[0xa1] = &sCPU::op_lda_idpx; +optbl[0x01] = &sCPU::op_ora_idpx; +optbl[0xe1] = &sCPU::op_sbc_idpx; +optbl[0x71] = &sCPU::op_adc_idpy; +optbl[0x31] = &sCPU::op_and_idpy; +optbl[0xd1] = &sCPU::op_cmp_idpy; +optbl[0x51] = &sCPU::op_eor_idpy; +optbl[0xb1] = &sCPU::op_lda_idpy; +optbl[0x11] = &sCPU::op_ora_idpy; +optbl[0xf1] = &sCPU::op_sbc_idpy; +optbl[0x67] = &sCPU::op_adc_ildp; +optbl[0x27] = &sCPU::op_and_ildp; +optbl[0xc7] = &sCPU::op_cmp_ildp; +optbl[0x47] = &sCPU::op_eor_ildp; +optbl[0xa7] = &sCPU::op_lda_ildp; +optbl[0x07] = &sCPU::op_ora_ildp; +optbl[0xe7] = &sCPU::op_sbc_ildp; +optbl[0x77] = &sCPU::op_adc_ildpy; +optbl[0x37] = &sCPU::op_and_ildpy; +optbl[0xd7] = &sCPU::op_cmp_ildpy; +optbl[0x57] = &sCPU::op_eor_ildpy; +optbl[0xb7] = &sCPU::op_lda_ildpy; +optbl[0x17] = &sCPU::op_ora_ildpy; +optbl[0xf7] = &sCPU::op_sbc_ildpy; +optbl[0x63] = &sCPU::op_adc_sr; +optbl[0x23] = &sCPU::op_and_sr; +optbl[0xc3] = &sCPU::op_cmp_sr; +optbl[0x43] = &sCPU::op_eor_sr; +optbl[0xa3] = &sCPU::op_lda_sr; +optbl[0x03] = &sCPU::op_ora_sr; +optbl[0xe3] = &sCPU::op_sbc_sr; +optbl[0x73] = &sCPU::op_adc_isry; +optbl[0x33] = &sCPU::op_and_isry; +optbl[0xd3] = &sCPU::op_cmp_isry; +optbl[0x53] = &sCPU::op_eor_isry; +optbl[0xb3] = &sCPU::op_lda_isry; +optbl[0x13] = &sCPU::op_ora_isry; +optbl[0xf3] = &sCPU::op_sbc_isry; +optbl[0x89] = &sCPU::op_bit_const; +optbl[0x8d] = &sCPU::op_sta_addr; +optbl[0x8e] = &sCPU::op_stx_addr; +optbl[0x8c] = &sCPU::op_sty_addr; +optbl[0x9c] = &sCPU::op_stz_addr; +optbl[0x9d] = &sCPU::op_sta_addrx; +optbl[0x9e] = &sCPU::op_stz_addrx; +optbl[0x99] = &sCPU::op_sta_addry; +optbl[0x8f] = &sCPU::op_sta_long; +optbl[0x9f] = &sCPU::op_sta_longx; +optbl[0x85] = &sCPU::op_sta_dp; +optbl[0x86] = &sCPU::op_stx_dp; +optbl[0x84] = &sCPU::op_sty_dp; +optbl[0x64] = &sCPU::op_stz_dp; +optbl[0x95] = &sCPU::op_sta_dpx; +optbl[0x94] = &sCPU::op_sty_dpx; +optbl[0x74] = &sCPU::op_stz_dpx; +optbl[0x96] = &sCPU::op_stx_dpy; +optbl[0x92] = &sCPU::op_sta_idp; +optbl[0x87] = &sCPU::op_sta_ildp; +optbl[0x81] = &sCPU::op_sta_idpx; +optbl[0x91] = &sCPU::op_sta_idpy; +optbl[0x97] = &sCPU::op_sta_ildpy; +optbl[0x83] = &sCPU::op_sta_sr; +optbl[0x93] = &sCPU::op_sta_isry; +optbl[0x1a] = &sCPU::op_inc; +optbl[0xe8] = &sCPU::op_inx; +optbl[0xc8] = &sCPU::op_iny; +optbl[0x3a] = &sCPU::op_dec; +optbl[0xca] = &sCPU::op_dex; +optbl[0x88] = &sCPU::op_dey; +optbl[0x0a] = &sCPU::op_asl; +optbl[0x4a] = &sCPU::op_lsr; +optbl[0x2a] = &sCPU::op_rol; +optbl[0x6a] = &sCPU::op_ror; +optbl[0xee] = &sCPU::op_inc_addr; +optbl[0xce] = &sCPU::op_dec_addr; +optbl[0x0e] = &sCPU::op_asl_addr; +optbl[0x4e] = &sCPU::op_lsr_addr; +optbl[0x2e] = &sCPU::op_rol_addr; +optbl[0x6e] = &sCPU::op_ror_addr; +optbl[0x1c] = &sCPU::op_trb_addr; +optbl[0x0c] = &sCPU::op_tsb_addr; +optbl[0xfe] = &sCPU::op_inc_addrx; +optbl[0xde] = &sCPU::op_dec_addrx; +optbl[0x1e] = &sCPU::op_asl_addrx; +optbl[0x5e] = &sCPU::op_lsr_addrx; +optbl[0x3e] = &sCPU::op_rol_addrx; +optbl[0x7e] = &sCPU::op_ror_addrx; +optbl[0xe6] = &sCPU::op_inc_dp; +optbl[0xc6] = &sCPU::op_dec_dp; +optbl[0x06] = &sCPU::op_asl_dp; +optbl[0x46] = &sCPU::op_lsr_dp; +optbl[0x26] = &sCPU::op_rol_dp; +optbl[0x66] = &sCPU::op_ror_dp; +optbl[0x14] = &sCPU::op_trb_dp; +optbl[0x04] = &sCPU::op_tsb_dp; +optbl[0xf6] = &sCPU::op_inc_dpx; +optbl[0xd6] = &sCPU::op_dec_dpx; +optbl[0x16] = &sCPU::op_asl_dpx; +optbl[0x56] = &sCPU::op_lsr_dpx; +optbl[0x36] = &sCPU::op_rol_dpx; +optbl[0x76] = &sCPU::op_ror_dpx; +optbl[0x90] = &sCPU::op_bcc; +optbl[0xb0] = &sCPU::op_bcs; +optbl[0xd0] = &sCPU::op_bne; +optbl[0xf0] = &sCPU::op_beq; +optbl[0x10] = &sCPU::op_bpl; +optbl[0x30] = &sCPU::op_bmi; +optbl[0x50] = &sCPU::op_bvc; +optbl[0x70] = &sCPU::op_bvs; +optbl[0x80] = &sCPU::op_bra; +optbl[0x82] = &sCPU::op_brl; +optbl[0x4c] = &sCPU::op_jmp_addr; +optbl[0x5c] = &sCPU::op_jmp_long; +optbl[0x6c] = &sCPU::op_jmp_iaddr; +optbl[0x7c] = &sCPU::op_jmp_iaddrx; +optbl[0xdc] = &sCPU::op_jmp_iladdr; +optbl[0x20] = &sCPU::op_jsr_addr; +optbl[0x22] = &sCPU::op_jsr_long; +optbl[0xfc] = &sCPU::op_jsr_iaddrx; +optbl[0x40] = &sCPU::op_rti; +optbl[0x60] = &sCPU::op_rts; +optbl[0x6b] = &sCPU::op_rtl; +optbl[0xea] = &sCPU::op_nop; +optbl[0x42] = &sCPU::op_wdm; +optbl[0xeb] = &sCPU::op_xba; +optbl[0x54] = &sCPU::op_mvn; +optbl[0x44] = &sCPU::op_mvp; +optbl[0x00] = &sCPU::op_brk; +optbl[0x02] = &sCPU::op_cop; +optbl[0xdb] = &sCPU::op_stp; +optbl[0xcb] = &sCPU::op_wai; +optbl[0xfb] = &sCPU::op_xce; +optbl[0x18] = &sCPU::op_clc; +optbl[0xd8] = &sCPU::op_cld; +optbl[0x58] = &sCPU::op_cli; +optbl[0xb8] = &sCPU::op_clv; +optbl[0x38] = &sCPU::op_sec; +optbl[0xf8] = &sCPU::op_sed; +optbl[0x78] = &sCPU::op_sei; +optbl[0xc2] = &sCPU::op_rep; +optbl[0xe2] = &sCPU::op_sep; +optbl[0xaa] = &sCPU::op_tax; +optbl[0xa8] = &sCPU::op_tay; +optbl[0x8a] = &sCPU::op_txa; +optbl[0x9b] = &sCPU::op_txy; +optbl[0x98] = &sCPU::op_tya; +optbl[0xbb] = &sCPU::op_tyx; +optbl[0x5b] = &sCPU::op_tcd; +optbl[0x1b] = &sCPU::op_tcs; +optbl[0x7b] = &sCPU::op_tdc; +optbl[0x3b] = &sCPU::op_tsc; +optbl[0xba] = &sCPU::op_tsx; +optbl[0x9a] = &sCPU::op_txs; +optbl[0x48] = &sCPU::op_pha; +optbl[0xda] = &sCPU::op_phx; +optbl[0x5a] = &sCPU::op_phy; +optbl[0x0b] = &sCPU::op_phd; +optbl[0x8b] = &sCPU::op_phb; +optbl[0x4b] = &sCPU::op_phk; +optbl[0x08] = &sCPU::op_php; +optbl[0x68] = &sCPU::op_pla; +optbl[0xfa] = &sCPU::op_plx; +optbl[0x7a] = &sCPU::op_ply; +optbl[0x2b] = &sCPU::op_pld; +optbl[0xab] = &sCPU::op_plb; +optbl[0x28] = &sCPU::op_plp; +optbl[0xf4] = &sCPU::op_pea; +optbl[0xd4] = &sCPU::op_pei; +optbl[0x62] = &sCPU::op_per; diff --git a/src/cpu/scpu/core/scpugen.cpp b/src/cpu/scpu/core/scpugen.cpp index 2047cecd..fe1aa9b1 100644 --- a/src/cpu/scpu/core/scpugen.cpp +++ b/src/cpu/scpu/core/scpugen.cpp @@ -1,9 +1,9 @@ #define CLASS_NAME "sCPU" -#include "../../../lib/opgen_s.cpp" +#include "../../../lib/opgen_so.cpp" int main() { -//fph = fopen("op.h", "wb"); -//fpt = fopen("optable.cpp", "wb"); + fph = fopen("op.h", "wb"); + fpt = fopen("optable.cpp", "wb"); generate("op_read.cpp", "op_read.b"); generate("op_write.cpp", "op_write.b"); @@ -11,8 +11,8 @@ int main() { generate("op_pc.cpp", "op_pc.b"); generate("op_misc.cpp", "op_misc.b"); -//fclose(fph); -//fclose(fpt); + fclose(fph); + fclose(fpt); return 0; } diff --git a/src/cpu/scpu/scpu.cpp b/src/cpu/scpu/scpu.cpp index 4fdba6fd..ae4be0ff 100644 --- a/src/cpu/scpu/scpu.cpp +++ b/src/cpu/scpu/scpu.cpp @@ -48,5 +48,9 @@ void sCPU::reset() { apu_port[3] = 0x00; } -sCPU::sCPU() {} -sCPU::~sCPU() {} +sCPU::sCPU() { + #include "core/optable.cpp" +} + +sCPU::~sCPU() { +} diff --git a/src/cpu/scpu/timing/timing.cpp b/src/cpu/scpu/timing/timing.cpp index 31aa1532..8809e80c 100644 --- a/src/cpu/scpu/timing/timing.cpp +++ b/src/cpu/scpu/timing/timing.cpp @@ -283,7 +283,7 @@ void sCPU::timing_reset() { //initial latch values for $213c/$213d //[x]0035 : [y]0000 (53.0 -> 212) [lda $2137] //[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137] - add_clocks(186); +//add_clocks(186); } #undef ntsc_color_burst_phase_shift_scanline diff --git a/src/dsp/adsp/adsp.cpp b/src/dsp/adsp/adsp.cpp new file mode 100644 index 00000000..1a102662 --- /dev/null +++ b/src/dsp/adsp/adsp.cpp @@ -0,0 +1,586 @@ +#include "../../base.h" +#include "adsp_tables.cpp" + +void aDSP::enter() { loop: + run(); + goto loop; +} + +uint8 aDSP::readb(uint16 addr) { + return spcram[addr]; +} + +void aDSP::writeb(uint16 addr, uint8 data) { + spcram[addr] = data; +} + +uint16 aDSP::readw(uint16 addr) { + return (readb(addr + 0)) | (readb(addr + 1) << 8); +} + +void aDSP::writew(uint16 addr, uint16 data) { + writeb(addr + 0, data); + writeb(addr + 1, data >> 8); +} + +uint8 aDSP::read(uint8 addr) { + addr &= 127; +int v = addr >> 4; +int n = addr & 15; + + switch(addr) { + case 0x00: case 0x10: case 0x20: case 0x30: + case 0x40: case 0x50: case 0x60: case 0x70: + return voice[v].VOLL; + case 0x01: case 0x11: case 0x21: case 0x31: + case 0x41: case 0x51: case 0x61: case 0x71: + return voice[v].VOLR; + case 0x02: case 0x12: case 0x22: case 0x32: + case 0x42: case 0x52: case 0x62: case 0x72: + return voice[v].PITCH; + case 0x03: case 0x13: case 0x23: case 0x33: + case 0x43: case 0x53: case 0x63: case 0x73: + return voice[v].PITCH >> 8; + case 0x04: case 0x14: case 0x24: case 0x34: + case 0x44: case 0x54: case 0x64: case 0x74: + return voice[v].SRCN; + case 0x05: case 0x15: case 0x25: case 0x35: + case 0x45: case 0x55: case 0x65: case 0x75: + return voice[v].ADSR1; + case 0x06: case 0x16: case 0x26: case 0x36: + case 0x46: case 0x56: case 0x66: case 0x76: + return voice[v].ADSR2; + case 0x07: case 0x17: case 0x27: case 0x37: + case 0x47: case 0x57: case 0x67: case 0x77: + return voice[v].GAIN; + case 0x08: case 0x18: case 0x28: case 0x38: + case 0x48: case 0x58: case 0x68: case 0x78: + return voice[v].ENVX; + case 0x09: case 0x19: case 0x29: case 0x39: + case 0x49: case 0x59: case 0x69: case 0x79: + return voice[v].OUTX; + + case 0x0f: case 0x1f: case 0x2f: case 0x3f: + case 0x4f: case 0x5f: case 0x6f: case 0x7f: + return status.FIR[v]; + + case 0x0c: return status.MVOLL; + case 0x1c: return status.MVOLR; + case 0x2c: return status.EVOLL; + case 0x3c: return status.EVOLR; + case 0x4c: return status.KON; + case 0x5c: return status.KOFF; + case 0x6c: return status.FLG; + case 0x7c: return status.ENDX; + + case 0x0d: return status.EFB; + case 0x2d: return status.PMON; + case 0x3d: return status.NON; + case 0x4d: return status.EON; + case 0x5d: return status.DIR; + case 0x6d: return status.ESA; + case 0x7d: return status.EDL; + } + + return dspram[addr]; +} + +void aDSP::write(uint8 addr, uint8 data) { +//0x80-0xff is a read-only mirror of 0x00-0x7f + if(addr & 0x80)return; + +int v = addr >> 4; +int n = addr & 15; + + switch(addr) { + case 0x00: case 0x10: case 0x20: case 0x30: + case 0x40: case 0x50: case 0x60: case 0x70: + voice[v].VOLL = data; + break; + case 0x01: case 0x11: case 0x21: case 0x31: + case 0x41: case 0x51: case 0x61: case 0x71: + voice[v].VOLR = data; + break; + case 0x02: case 0x12: case 0x22: case 0x32: + case 0x42: case 0x52: case 0x62: case 0x72: + voice[v].PITCH &= 0xff00; + voice[v].PITCH |= data; + break; + case 0x03: case 0x13: case 0x23: case 0x33: + case 0x43: case 0x53: case 0x63: case 0x73: + voice[v].PITCH &= 0x00ff; + voice[v].PITCH |= data << 8; + break; + case 0x04: case 0x14: case 0x24: case 0x34: + case 0x44: case 0x54: case 0x64: case 0x74: + voice[v].SRCN = data; + break; + case 0x05: case 0x15: case 0x25: case 0x35: + case 0x45: case 0x55: case 0x65: case 0x75: + voice[v].ADSR1 = data; + voice[v].AdjustEnvelope(); + break; + case 0x06: case 0x16: case 0x26: case 0x36: + case 0x46: case 0x56: case 0x66: case 0x76: + voice[v].ADSR2 = data; + //sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode + voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8; + voice[v].AdjustEnvelope(); + break; + case 0x07: case 0x17: case 0x27: case 0x37: + case 0x47: case 0x57: case 0x67: case 0x77: + voice[v].GAIN = data; + voice[v].AdjustEnvelope(); + break; + case 0x08: case 0x18: case 0x28: case 0x38: + case 0x48: case 0x58: case 0x68: case 0x78: + voice[v].ENVX = data; + break; + case 0x09: case 0x19: case 0x29: case 0x39: + case 0x49: case 0x59: case 0x69: case 0x79: + voice[v].OUTX = data; + break; + + case 0x0f: case 0x1f: case 0x2f: case 0x3f: + case 0x4f: case 0x5f: case 0x6f: case 0x7f: + status.FIR[v] = data; + break; + + case 0x0c: status.MVOLL = data; break; + case 0x1c: status.MVOLR = data; break; + case 0x2c: status.EVOLL = data; break; + case 0x3c: status.EVOLR = data; break; + + case 0x4c: + status.KON = data; + status.kon = data; + break; + case 0x5c: + status.KOFF = data; + break; + case 0x6c: + status.FLG = data; + status.noise_rate = rate_table[data & 0x1f]; + break; + + case 0x7c: + //read-only register, writes clear all bits of ENDX + status.ENDX = 0; + break; + + case 0x0d: status.EFB = data; break; + case 0x2d: status.PMON = data; break; + case 0x3d: status.NON = data; break; + case 0x4d: status.EON = data; break; + case 0x5d: status.DIR = data; break; + case 0x6d: status.ESA = data; break; + case 0x7d: status.EDL = data; break; + } + + dspram[addr] = data; +} + +void aDSP::power() { + spcram = r_smp->get_spcram_handle(); + memset(dspram, 0x00, 128); + + for(int v = 0; v < 8; v++) { + voice[v].VOLL = 0; + voice[v].VOLR = 0; + voice[v].PITCH = 0; + voice[v].SRCN = 0; + voice[v].ADSR1 = 0; + voice[v].ADSR2 = 0; + voice[v].GAIN = 0; + + status.FIR[v] = 0; + } + + status.FLG = 0xe0; + status.MVOLL = status.MVOLR = 0; + status.EVOLL = status.EVOLR = 0; + status.ENDX = 0; + status.EFB = 0; + status.PMON = 0; + status.NON = 0; + status.EON = 0; + status.DIR = 0; + status.ESA = 0; + status.EDL = 0; + + status.echo_length = 0; + + reset(); +} + +void aDSP::reset() { + status.KON = 0x00; + status.KOFF = 0x00; + status.FLG |= 0xe0; + + status.kon = 0x00; + status.esa = 0x00; + + status.noise_ctr = 0; + status.noise_rate = 0; + status.noise_sample = 0x4000; + + status.echo_index = 0; + status.fir_buffer_index = 0; + + for(int v = 0; v < 8; v++) { + voice[v].ENVX = 0; + voice[v].OUTX = 0; + + voice[v].pitch_ctr = 0; + + voice[v].brr_index = 0; + voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2)); + voice[v].brr_looped = false; + voice[v].brr_data[0] = 0; + voice[v].brr_data[1] = 0; + voice[v].brr_data[2] = 0; + voice[v].brr_data[3] = 0; + voice[v].brr_data_index = 0; + + voice[v].envx = 0; + voice[v].env_ctr = 0; + voice[v].env_rate = 0; + voice[v].env_state = SILENCE; + voice[v].env_mode = DIRECT; + + status.fir_buffer[0][v] = 0; + status.fir_buffer[1][v] = 0; + } + + dsp_counter = 0; +} + +void aDSP::run() { +uint8 pmon; +int32 sample; +int32 msamplel, msampler; +int32 esamplel, esampler; +int32 fir_samplel, fir_sampler; + pmon = status.PMON & ~status.NON & ~1; + + if((dsp_counter++ & 1) == 0) { + for(uint v = 0; v < 8; v++) { + if(status.soft_reset()) { + if(voice[v].env_state != SILENCE) { + voice[v].env_state = SILENCE; + voice[v].AdjustEnvelope(); + } + } + if(status.KOFF & (1 << v)) { + if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) { + voice[v].env_state = RELEASE; + voice[v].AdjustEnvelope(); + } + } + if(status.kon & (1 << v)) { + voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2)); + voice[v].brr_index = -9; + voice[v].brr_looped = false; + voice[v].brr_data[0] = 0; + voice[v].brr_data[1] = 0; + voice[v].brr_data[2] = 0; + voice[v].brr_data[3] = 0; + voice[v].envx = 0; + voice[v].env_state = ATTACK; + voice[v].AdjustEnvelope(); + } + } + status.ENDX &= ~status.kon; + status.kon = 0; + } + +/***** + * update noise + *****/ + status.noise_ctr += status.noise_rate; + if(status.noise_ctr >= 0x7800) { + status.noise_ctr -= 0x7800; + status.noise_sample = (status.noise_sample >> 1) | (((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000); + } + + msamplel = msampler = 0; + esamplel = esampler = 0; + +/***** + * process voice channels + *****/ + for(int v = 0; v < 8; v++) { + if(voice[v].brr_index < -1) { + voice[v].brr_index++; + voice[v].OUTX = voice[v].outx = 0; + voice[v].ENVX = 0; + continue; + } + + if(voice[v].brr_index >= 0) { + if(pmon & (1 << v)) { + voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15; + } else { + voice[v].pitch_ctr += voice[v].pitch_rate(); + } + } else { + voice[v].pitch_ctr = 0x3000; + voice[v].brr_index = 0; + } + + /***** + * decode BRR samples + *****/ + while(voice[v].pitch_ctr >= 0) { + voice[v].pitch_ctr -= 0x1000; + + voice[v].brr_data_index++; + voice[v].brr_data_index &= 3; + + if(voice[v].brr_index == 0) { + voice[v].brr_header = readb(voice[v].brr_ptr); + + if(voice[v].brr_header_flags() == BRR_END) { + status.ENDX |= (1 << v); + voice[v].env_state = SILENCE; + voice[v].AdjustEnvelope(); + } + } + +#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3] + if(voice[v].env_state != SILENCE) { + sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1)); + if(voice[v].brr_index & 1) { + sample = sclip<4>(sample); + } else { + sample = sclip<4>(sample >> 4); + } + + if(voice[v].brr_header_shift() <= 12) { + sample = (sample << voice[v].brr_header_shift() >> 1); + } else { + sample &= ~0x7ff; + } + + switch(voice[v].brr_header_filter()) { + case 0: //direct + break; + case 1: //15/16 + sample += S(-1) + ((-S(-1)) >> 4); + break; + case 2: //61/32 - 15/16 + sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5) + - S(-2) + (S(-2) >> 4); + break; + case 3: //115/64 - 13/16 + sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6) + - S(-2) + (((S(-2) << 1) + S(-2)) >> 4); + break; + } + + S(0) = sample = sclip<15>(sclamp<16>(sample)); + } else { + S(0) = sample = 0; + } + + if(++voice[v].brr_index > 15) { + voice[v].brr_index = 0; + if(voice[v].brr_header_flags() & BRR_END) { + if(voice[v].brr_header_flags() & BRR_LOOP) { + status.ENDX |= (1 << v); + } + voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2); + voice[v].brr_looped = true; + } else { + voice[v].brr_ptr += 9; + } + } + } + + /***** + * volume envelope adjust + *****/ + voice[v].env_ctr += voice[v].env_rate; + + if(voice[v].env_ctr >= 0x7800) { + voice[v].env_ctr -= 0x7800; + switch(voice[v].env_mode) { + case DIRECT: + voice[v].env_rate = 0; + break; + case LINEAR_DEC: + voice[v].envx -= 32; + if(voice[v].envx <= 0) { + voice[v].envx = 0; + voice[v].env_rate = 0; + voice[v].env_mode = DIRECT; + } + break; + case LINEAR_INC: + voice[v].envx += 32; + if(voice[v].envx >= 0x7ff) { + voice[v].envx = 0x7ff; + voice[v].env_rate = 0; + voice[v].env_mode = DIRECT; + if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) { + voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY); + voice[v].AdjustEnvelope(); + } + } + break; + case EXP_DEC: + //multiply by 255/256ths + voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1; + if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) { + voice[v].env_state = SUSTAIN; + voice[v].AdjustEnvelope(); + } else if(voice[v].envx <= 0) { + voice[v].envx = 0; + voice[v].env_rate = 0; + voice[v].env_mode = DIRECT; + } + break; + case BENT_INC: + if(voice[v].envx < 0x600) { + voice[v].envx += 32; + } else { + voice[v].envx += 8; + + if(voice[v].envx >= 0x7ff) { + voice[v].envx = 0x7ff; + voice[v].env_rate = 0; + voice[v].env_mode = DIRECT; + } + } + break; + case FAST_ATTACK: + voice[v].envx += 0x400; + if(voice[v].envx >= 0x7ff) { + voice[v].envx = 0x7ff; + + //attack raises to max envx. if sustain is also set to max envx, skip decay phase + voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY); + voice[v].AdjustEnvelope(); + } + break; + case RELEASE_DEC: + voice[v].envx -= 8; + if(voice[v].envx <= 0) { + voice[v].env_state = SILENCE; + voice[v].AdjustEnvelope(); + } + break; + } + } + + voice[v].ENVX = voice[v].envx >> 4; + + /***** + * gaussian interpolation / noise + *****/ + if(status.NON & (1 << v)) { + sample = sclip<15>(status.noise_sample); + } else { + int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1 + sample = ((gaussian_table[ -1 - d] * S(-3)) >> 11); + sample += ((gaussian_table[255 - d] * S(-2)) >> 11); + sample += ((gaussian_table[512 + d] * S(-1)) >> 11); + sample = sclip <15>(sample); + sample += ((gaussian_table[256 + d] * S( 0)) >> 11); + sample = sclamp<15>(sample); + } +#undef S + + /***** + * envelope / volume adjust + *****/ + sample = (sample * voice[v].envx) >> 11; + voice[v].outx = sample << 1; + voice[v].OUTX = sample >> 7; + + if(!status.mute()) { + msamplel += ((sample * voice[v].VOLL) >> 7) << 1; + msampler += ((sample * voice[v].VOLR) >> 7) << 1; + } + + if((status.EON & (1 << v)) && status.echo_write()) { + esamplel += ((sample * voice[v].VOLL) >> 7) << 1; + esampler += ((sample * voice[v].VOLR) >> 7) << 1; + } + } + +/***** + * echo (FIR) adjust + *****/ +#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index + (x)) & 7] + status.fir_buffer_index++; + F(0,0) = readw((status.esa << 8) + status.echo_index + 0); + F(1,0) = readw((status.esa << 8) + status.echo_index + 2); + + fir_samplel = (F(0,-0) * status.FIR[7] + + F(0,-1) * status.FIR[6] + + F(0,-2) * status.FIR[5] + + F(0,-3) * status.FIR[4] + + F(0,-4) * status.FIR[3] + + F(0,-5) * status.FIR[2] + + F(0,-6) * status.FIR[1] + + F(0,-7) * status.FIR[0]); + + fir_sampler = (F(1,-0) * status.FIR[7] + + F(1,-1) * status.FIR[6] + + F(1,-2) * status.FIR[5] + + F(1,-3) * status.FIR[4] + + F(1,-4) * status.FIR[3] + + F(1,-5) * status.FIR[2] + + F(1,-6) * status.FIR[1] + + F(1,-7) * status.FIR[0]); +#undef F + +/***** + * update echo buffer + *****/ + if(status.echo_write()) { + esamplel += (fir_samplel * status.EFB) >> 14; + esampler += (fir_sampler * status.EFB) >> 14; + + esamplel = sclamp<16>(esamplel); + esampler = sclamp<16>(esampler); + + writew((status.esa << 8) + status.echo_index + 0, esamplel); + writew((status.esa << 8) + status.echo_index + 2, esampler); + } + + status.echo_index += 4; + if(status.echo_index >= status.echo_length) { + status.echo_index = 0; + status.echo_length = (status.EDL & 0x0f) << 11; + } + +//ESA read occurs at roughly 22/32th sample +//ESA fetch occurs at roughly 29/32th sample +//as this is not a subsample-level S-DSP emulator, +//simulate ~25/32th delay by caching ESA for one +//complete sample ... + status.esa = status.ESA; + +/***** + * main output adjust + *****/ + if(!status.mute()) { + msamplel = (msamplel * status.MVOLL) >> 7; + msampler = (msampler * status.MVOLR) >> 7; + + msamplel += (fir_samplel * status.EVOLL) >> 14; + msampler += (fir_sampler * status.EVOLR) >> 14; + + msamplel = sclamp<16>(msamplel); + msampler = sclamp<16>(msampler); + } + + snes.audio_update(msamplel, msampler); + scheduler.addclocks_dsp(32 * 3); +} + +aDSP::aDSP() {} +aDSP::~aDSP() {} diff --git a/src/dsp/adsp/adsp.h b/src/dsp/adsp/adsp.h new file mode 100644 index 00000000..3d99a192 --- /dev/null +++ b/src/dsp/adsp/adsp.h @@ -0,0 +1,172 @@ +class aDSP : public DSP { +private: +uint8 dspram[128]; +uint8 *spcram; + +uint32 dsp_counter; + +enum { BRR_END = 1, BRR_LOOP = 2 }; + +uint8 readb (uint16 addr); +uint16 readw (uint16 addr); +void writeb(uint16 addr, uint8 data); +void writew(uint16 addr, uint16 data); + +public: +static const uint16 rate_table[32]; +static const int16 gaussian_table[512]; + +enum EnvelopeStates { + ATTACK, + DECAY, + SUSTAIN, + RELEASE, + SILENCE +}; + +enum EnvelopeModes { + DIRECT, + LINEAR_DEC, + EXP_DEC, + LINEAR_INC, + BENT_INC, + + FAST_ATTACK, + RELEASE_DEC +}; + +private: +struct Status { +//$0c,$1c + int8 MVOLL, MVOLR; +//$2c,$3c + int8 EVOLL, EVOLR; +//$4c,$5c + uint8 KON, KOFF; +//$6c + uint8 FLG; +//$7c + uint8 ENDX; +//$0d + int8 EFB; +//$2d,$3d,$4d + uint8 PMON, NON, EON; +//$5d + uint8 DIR; +//$6d,$7d + uint8 ESA, EDL; + +//$xf + int8 FIR[8]; + +//internal variables + uint8 kon, esa; + + int16 noise_ctr, noise_rate; + uint16 noise_sample; + + uint16 echo_index, echo_length; + int16 fir_buffer[2][8]; + uint8 fir_buffer_index; + +//functions + bool soft_reset() { return !!(FLG & 0x80); } + bool mute() { return !!(FLG & 0x40); } + bool echo_write() { return !(FLG & 0x20); } +} status; + +struct Voice { +//$x0-$x1 + int8 VOLL, VOLR; +//$x2-$x3 + int16 PITCH; +//$x4 + uint8 SRCN; +//$x5-$x7 + uint8 ADSR1, ADSR2, GAIN; +//$x8-$x9 + uint8 ENVX, OUTX; + +//internal variables + int16 pitch_ctr; + + int8 brr_index; + uint16 brr_ptr; + uint8 brr_header; + bool brr_looped; + + int16 brr_data[4]; + uint8 brr_data_index; + + int16 envx; + uint16 env_ctr, env_rate, env_sustain; + enum EnvelopeStates env_state; + enum EnvelopeModes env_mode; + + int16 outx; + +//functions + int16 pitch_rate() { return PITCH & 0x3fff; } + + uint8 brr_header_shift() { return brr_header >> 4; } + uint8 brr_header_filter() { return (brr_header >> 2) & 3; } + uint8 brr_header_flags() { return brr_header & 3; } + + bool ADSR_enabled() { return !!(ADSR1 & 0x80); } + uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; } + uint8 ADSR_attack() { return ADSR1 & 15; } + uint8 ADSR_sus_level() { return ADSR2 >> 5; } + uint8 ADSR_sus_rate() { return ADSR2 & 31; } + + void AdjustEnvelope() { + if(env_state == SILENCE) { + env_mode = DIRECT; + env_rate = 0; + envx = 0; + } else if(env_state == RELEASE) { + env_mode = RELEASE_DEC; + env_rate = 0x7800; + } else if(ADSR_enabled()) { + switch(env_state) { + case ATTACK: + env_rate = rate_table[(ADSR_attack() << 1) + 1]; + env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC; + break; + case DECAY: + env_rate = rate_table[(ADSR_decay() << 1) + 0x10]; + env_mode = EXP_DEC; + break; + case SUSTAIN: + env_rate = rate_table[ADSR_sus_rate()]; + env_mode = (env_rate == 0) ? DIRECT : EXP_DEC; + break; + } + } else if(GAIN & 0x80) { + switch(GAIN & 0x60) { + case 0x00: env_mode = LINEAR_DEC; break; + case 0x20: env_mode = EXP_DEC; break; + case 0x40: env_mode = LINEAR_INC; break; + case 0x60: env_mode = BENT_INC; break; + } + env_rate = rate_table[GAIN & 0x1f]; + } else { + env_mode = DIRECT; + env_rate = 0; + envx = (GAIN & 0x7f) << 4; + } + } +} voice[8]; + +public: + void enter(); + void run(); + + uint8 read (uint8 addr); + void write(uint8 addr, uint8 data); + + void power(); + void reset(); + + aDSP(); + ~aDSP(); +}; diff --git a/src/dsp/bdsp/bdsp_tables.cpp b/src/dsp/adsp/adsp_tables.cpp similarity index 96% rename from src/dsp/bdsp/bdsp_tables.cpp rename to src/dsp/adsp/adsp_tables.cpp index 27e12904..bb72e587 100644 --- a/src/dsp/bdsp/bdsp_tables.cpp +++ b/src/dsp/adsp/adsp_tables.cpp @@ -1,11 +1,11 @@ -const uint16 bDSP::RateTable[32] = { +const uint16 aDSP::rate_table[32] = { 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, 0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 }; -const int16 bDSP::GaussTable[512] = { +const int16 aDSP::gaussian_table[512] = { 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, diff --git a/src/dsp/bdsp/bdsp.cpp b/src/dsp/bdsp/bdsp.cpp index 681a4327..7afcba86 100644 --- a/src/dsp/bdsp/bdsp.cpp +++ b/src/dsp/bdsp/bdsp.cpp @@ -1,565 +1,679 @@ +/* This code is heavily customized for bsnes and requires cothreads. +Original portable snes_spc library available at http://www.slack.net/~ant/ +Copyright (C) 2007 Shay Green. See license.txt. */ + #include "../../base.h" -#include "bdsp_tables.cpp" -uint8 bDSP::readb(uint16 addr) { - return spcram[addr]; +int const brr_block_size = 9; + +// Accesses global DSP register +#define REG(n) m.regs [r_##n] + +// Accesses voice DSP register +#define VREG(r,n) r [v_##n] + +// Volume registers and efb are signed! Easy to forget int8 cast. +// Prefixes are to avoid accidental use of locals with same names. + +// Gaussian interpolation + +static short const gauss [512] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, +1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, +1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, +1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, +1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, +1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, +1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, +1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, +}; + + +//// Counters + +int const simple_counter_range = 2048 * 5 * 3; // 30720 + +static unsigned const counter_rates [32] = +{ + simple_counter_range + 1, // never fires + 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1 +}; + +static unsigned const counter_offsets [32] = +{ + 1, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 0, + 0 +}; + +inline unsigned bDSP::read_counter( int rate ) +{ + return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; } -void bDSP::writeb(uint16 addr, uint8 data) { - spcram[addr] = data; + +//// Envelope + +inline void bDSP::run_envelope( voice_t* const v ) +{ + int env = v->env; + if ( v->env_mode == env_release ) + { + if ( (env -= 0x8) < 0 ) + env = 0; + v->env = env; + } + else + { + int rate; + int env_data = VREG(v->regs,adsr1); + if ( m.t_adsr0 & 0x80 ) // ADSR + { + if ( v->env_mode >= env_decay ) + { + env--; + env -= asr<8>( env ); + rate = env_data & 0x1F; + if ( v->env_mode == env_decay ) + rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; + } + else // env_attack + { + rate = (m.t_adsr0 & 0x0F) * 2 + 1; + env += rate < 31 ? 0x20 : 0x400; + } + } + else // GAIN + { + env_data = VREG(v->regs,gain); + int mode = env_data >> 5; + if ( mode < 4 ) // direct + { + env = env_data * 0x10; + rate = 31; + } + else + { + rate = env_data & 0x1F; + if ( mode == 4 ) // 4: linear decrease + { + env -= 0x20; + } + else if ( mode < 6 ) // 5: exponential decrease + { + env--; + env -= asr<8>( env ); + } + else // 6,7: linear increase + { + env += 0x20; + if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) + env += 0x8 - 0x20; // 7: two-slope linear increase + } + } + } + + // Sustain level + if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) + v->env_mode = env_sustain; + + v->hidden_env = env; + + // unsigned cast because linear decrease going negative also triggers this + if ( (unsigned) env > 0x7FF ) + { + env = (env < 0 ? 0 : 0x7FF); + if ( v->env_mode == env_attack ) + v->env_mode = env_decay; + } + + if ( !read_counter( rate ) ) + v->env = env; // nothing else is controlled by the counter + } } -uint16 bDSP::readw(uint16 addr) { - return (readb(addr)) | (readb(addr + 1) << 8); + +//// BRR Decoding + +inline void bDSP::decode_brr( voice_t* v ) +{ + // Arrange the four input nybbles in 0xABCD order for easy decoding + int nybbles = m.t_brr_byte * 0x100 + ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; + + // Write to next four samples in circular buffer + int* pos = &v->buf [v->buf_pos]; + if ( (v->buf_pos += 4) >= brr_buf_size ) + v->buf_pos = 0; + + // Decode four samples + for ( int* end = pos + 4; pos < end; pos++ ) + { + // Extract nybble and sign-extend + int s = asr<12>( sclip<16>( nybbles ) ); + nybbles <<= 4; + + // Shift sample based on header + int const shift = m.t_brr_header >> 4; + s = asr<1>( s << shift ); + if ( shift >= 0xD ) // handle invalid range + s = (s < 0 ? -0x800 : 0); + + // Apply IIR filter (8 is the most commonly used) + int const p1 = pos [brr_buf_size - 1]; + int const p2 = asr<1>( pos [brr_buf_size - 2] ); + switch ( m.t_brr_header >> 2 & 3 ) + { + case 1: s += asr<1>( p1 ) + asr<5>( -p1 ); break; // s += p1 * 0.4687500 + case 2: s += p1 + asr<6>( p1 * -3 ) - p2 + asr<4>( p2 ); break; // s += p1 * 0.9531250 - p2 * 0.46875 + case 3: s += p1 + asr<7>( p1 * -13 ) - p2 + asr<4>( p2 * 3 ); break; // s += p1 * 0.8984375 - p2 * 0.40625 + } + + // Adjust and write sample + s = sclip<16>( sclamp<16>( s ) * 2 ); + pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around + } } -void bDSP::writew(uint16 addr, uint16 data) { - writeb(addr, data); - writeb(addr + 1, data >> 8); + +//// Voices + +#define VOICE_CLOCK( n ) void bDSP::voice_##n( voice_t* const v ) + +inline VOICE_CLOCK( V1 ) +{ + m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; + m.t_srcn = VREG(v->regs,srcn); +} +inline VOICE_CLOCK( V2 ) +{ + // Read sample pointer (ignored if not needed) + uint8 const* entry = &ram [m.t_dir_addr]; + if ( !v->kon_delay ) + entry += 2; + m.t_brr_next_addr = entry [0] | entry [1] << 8; + + m.t_adsr0 = VREG(v->regs,adsr0); + + // Read pitch, spread over two clocks + m.t_pitch = VREG(v->regs,pitchl); +} +inline VOICE_CLOCK( V3a ) +{ + m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; +} +inline VOICE_CLOCK( V3b ) +{ + // Read BRR header and byte + m.t_brr_byte = ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; + m.t_brr_header = ram [v->brr_addr]; // brr_addr doesn't need masking +} +VOICE_CLOCK( V3c ) +{ + // Pitch modulation using previous voice's output + if ( m.t_pmon & v->vbit ) + m.t_pitch += asr<10>( asr<5>( m.t_output ) * m.t_pitch ); + + if ( v->kon_delay ) + { + // Get ready to start BRR decoding on next sample + if ( v->kon_delay == 5 ) + { + v->brr_addr = m.t_brr_next_addr; + v->brr_offset = 1; + v->buf_pos = 0; + m.t_brr_header = 0; // header is ignored on this sample + } + + // Envelope is never run during KON + v->env = 0; + v->hidden_env = 0; + + // Disable BRR decoding until last three samples + v->interp_pos = 0; + if ( --v->kon_delay & 3 ) + v->interp_pos = 0x4000; + + // Pitch is never added during KON + m.t_pitch = 0; + } + + // Gaussian interpolation + { + // Make pointers into gaussian based on fractional position between samples + int offset = v->interp_pos >> 4 & 0xFF; + short const* fwd = gauss + 255 - offset; + short const* rev = gauss + offset; // mirror left half of gaussian + + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + int out; + out = asr<11>( fwd [ 0] * in [0] ); + out += asr<11>( fwd [256] * in [1] ); + out += asr<11>( rev [256] * in [2] ); + out = sclip<16>( out ); + out += asr<11>( rev [ 0] * in [3] ); + + out = sclamp<16>( out ) & ~1; + + // Noise + if ( m.t_non & v->vbit ) + out = sclip<16>( m.noise * 2 ); + + // Apply envelope + m.t_output = asr<11>( out * v->env ) & ~1; + v->t_envx_out = (uint8) (v->env >> 4); + } + + // Immediate silence due to end of sample or soft reset + if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) + { + v->env_mode = env_release; + v->env = 0; + } + + if ( m.every_other_sample ) + { + // KOFF + if ( m.t_koff & v->vbit ) + v->env_mode = env_release; + + // KON + if ( m.kon & v->vbit ) + { + v->kon_delay = 5; + v->env_mode = env_attack; + } + } + + // Run envelope for next sample + if ( !v->kon_delay ) + run_envelope( v ); +} +inline void bDSP::voice_output( voice_t const* v, int ch ) +{ + // Apply left/right volume + int amp = asr<7>( m.t_output * (int8) VREG(v->regs,voll + ch) ); + + // Add to output total + m.t_main_out [ch] = sclamp<16>( m.t_main_out [ch] + amp ); + + // Optionally add to echo total + if ( m.t_eon & v->vbit ) + m.t_echo_out [ch] = sclamp<16>( m.t_echo_out [ch] + amp ); +} +VOICE_CLOCK( V4 ) +{ + // Decode BRR + m.t_looped = 0; + if ( v->interp_pos >= 0x4000 ) + { + decode_brr( v ); + + if ( (v->brr_offset += 2) >= brr_block_size ) + { + // Start decoding next BRR block + assert( v->brr_offset == brr_block_size ); + v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; + if ( m.t_brr_header & 1 ) + { + v->brr_addr = m.t_brr_next_addr; + m.t_looped = v->vbit; + } + v->brr_offset = 1; + } + } + + // Apply pitch + v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; + + // Keep from getting too far ahead (when using pitch modulation) + if ( v->interp_pos > 0x7FFF ) + v->interp_pos = 0x7FFF; + + // Output left + voice_output( v, 0 ); +} +inline VOICE_CLOCK( V5 ) +{ + // Output right + voice_output( v, 1 ); + + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier + int endx_buf = REG(endx) | m.t_looped; + + // Clear bit in ENDX if KON just began + if ( v->kon_delay == 5 ) + endx_buf &= ~v->vbit; + m.endx_buf = (uint8) endx_buf; +} +inline VOICE_CLOCK( V6 ) +{ + (void) v; // avoid compiler warning about unused v + m.outx_buf = (uint8) (m.t_output >> 8); +} +inline VOICE_CLOCK( V7 ) +{ + // Update ENDX + REG(endx) = m.endx_buf; + + m.envx_buf = v->t_envx_out; +} +inline VOICE_CLOCK( V8 ) +{ + // Update OUTX + VREG(v->regs,outx) = m.outx_buf; +} +inline VOICE_CLOCK( V9 ) +{ + // Update ENVX + VREG(v->regs,envx) = m.envx_buf; } -uint8 bDSP::read(uint8 addr) { - addr &= 127; -int v = addr >> 4; -int n = addr & 15; - - switch(addr) { - case 0x00: case 0x10: case 0x20: case 0x30: - case 0x40: case 0x50: case 0x60: case 0x70: - return voice[v].VOLL; - case 0x01: case 0x11: case 0x21: case 0x31: - case 0x41: case 0x51: case 0x61: case 0x71: - return voice[v].VOLR; - case 0x02: case 0x12: case 0x22: case 0x32: - case 0x42: case 0x52: case 0x62: case 0x72: - return voice[v].PITCH; - case 0x03: case 0x13: case 0x23: case 0x33: - case 0x43: case 0x53: case 0x63: case 0x73: - return voice[v].PITCH >> 8; - case 0x04: case 0x14: case 0x24: case 0x34: - case 0x44: case 0x54: case 0x64: case 0x74: - return voice[v].SRCN; - case 0x05: case 0x15: case 0x25: case 0x35: - case 0x45: case 0x55: case 0x65: case 0x75: - return voice[v].ADSR1; - case 0x06: case 0x16: case 0x26: case 0x36: - case 0x46: case 0x56: case 0x66: case 0x76: - return voice[v].ADSR2; - case 0x07: case 0x17: case 0x27: case 0x37: - case 0x47: case 0x57: case 0x67: case 0x77: - return voice[v].GAIN; - case 0x08: case 0x18: case 0x28: case 0x38: - case 0x48: case 0x58: case 0x68: case 0x78: - return voice[v].ENVX; - case 0x09: case 0x19: case 0x29: case 0x39: - case 0x49: case 0x59: case 0x69: case 0x79: - return voice[v].OUTX; - - case 0x0f: case 0x1f: case 0x2f: case 0x3f: - case 0x4f: case 0x5f: case 0x6f: case 0x7f: - return status.FIR[v]; - - case 0x0c: return status.MVOLL; - case 0x1c: return status.MVOLR; - case 0x2c: return status.EVOLL; - case 0x3c: return status.EVOLR; - case 0x4c: return status.KON; - case 0x5c: return status.KOFF; - case 0x6c: return status.FLG; - case 0x7c: return status.ENDX; - - case 0x0d: return status.EFB; - case 0x2d: return status.PMON; - case 0x3d: return status.NON; - case 0x4d: return status.EON; - case 0x5d: return status.DIR; - case 0x6d: return status.ESA; - case 0x7d: return status.EDL; - } - - return dspram[addr]; +// Most voices do all these in one clock, so make a handy composite +inline VOICE_CLOCK( V3 ) +{ + voice_V3a( v ); + voice_V3b( v ); + voice_V3c( v ); } -void bDSP::write(uint8 addr, uint8 data) { -//0x80-0xff is a read-only mirror of 0x00-0x7f - if(addr & 0x80)return; +// Common combinations of voice steps on different voices. This greatly reduces +// code size and allows everything to be inlined in these functions. +VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } +VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } +VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } -int v = addr >> 4; -int n = addr & 15; - switch(addr) { - case 0x00: case 0x10: case 0x20: case 0x30: - case 0x40: case 0x50: case 0x60: case 0x70: - voice[v].VOLL = data; - break; - case 0x01: case 0x11: case 0x21: case 0x31: - case 0x41: case 0x51: case 0x61: case 0x71: - voice[v].VOLR = data; - break; - case 0x02: case 0x12: case 0x22: case 0x32: - case 0x42: case 0x52: case 0x62: case 0x72: - voice[v].PITCH &= 0xff00; - voice[v].PITCH |= data; - break; - case 0x03: case 0x13: case 0x23: case 0x33: - case 0x43: case 0x53: case 0x63: case 0x73: - voice[v].PITCH &= 0x00ff; - voice[v].PITCH |= data << 8; - break; - case 0x04: case 0x14: case 0x24: case 0x34: - case 0x44: case 0x54: case 0x64: case 0x74: - voice[v].SRCN = data; - break; - case 0x05: case 0x15: case 0x25: case 0x35: - case 0x45: case 0x55: case 0x65: case 0x75: - voice[v].ADSR1 = data; - voice[v].AdjustEnvelope(); - break; - case 0x06: case 0x16: case 0x26: case 0x36: - case 0x46: case 0x56: case 0x66: case 0x76: - voice[v].ADSR2 = data; - //sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode - voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8; - voice[v].AdjustEnvelope(); - break; - case 0x07: case 0x17: case 0x27: case 0x37: - case 0x47: case 0x57: case 0x67: case 0x77: - voice[v].GAIN = data; - voice[v].AdjustEnvelope(); - break; - case 0x08: case 0x18: case 0x28: case 0x38: - case 0x48: case 0x58: case 0x68: case 0x78: - voice[v].ENVX = data; - break; - case 0x09: case 0x19: case 0x29: case 0x39: - case 0x49: case 0x59: case 0x69: case 0x79: - voice[v].OUTX = data; - break; +//// Echo - case 0x0f: case 0x1f: case 0x2f: case 0x3f: - case 0x4f: case 0x5f: case 0x6f: case 0x7f: - status.FIR[v] = data; - break; +// Current echo buffer pointer for left/right channel +#define ECHO_PTR( ch ) (&ram [echo_ptr + ch * 2]) - case 0x0c: status.MVOLL = data; break; - case 0x1c: status.MVOLR = data; break; - case 0x2c: status.EVOLL = data; break; - case 0x3c: status.EVOLR = data; break; +// Sample in echo history buffer, where 0 is the oldest +#define ECHO_FIR( i ) (m.echo_hist [(m.echo_hist_pos + (i)) & (echo_hist_size - 1)]) - case 0x4c: - status.KON = data; - status.kon = data; - status.key_flag = true; - break; +// Calculate FIR point for left/right channel +#define CALC_FIR( i, ch ) asr<6>( ECHO_FIR( i + 1 ) [ch] * (int8) REG(fir + i * 0x10) ) - case 0x5c: - status.KOFF = data; - status.key_flag = true; - break; - - case 0x6c: - status.FLG = data; - status.key_flag = true; - status.noise_rate = RateTable[data & 0x1f]; - break; - - case 0x7c: - //read-only register, writes clear all bits of ENDX - status.ENDX = 0; - break; - - case 0x0d: status.EFB = data; break; - case 0x2d: status.PMON = data; break; - case 0x3d: status.NON = data; break; - case 0x4d: status.EON = data; break; - case 0x5d: status.DIR = data; break; - case 0x6d: status.ESA = data; break; - - case 0x7d: - status.EDL = data; - status.echo_size = (data & 0x0f) << 11; - break; - } - - dspram[addr] = data; +inline int get_echo_sample( void const* p ) +{ + return ((uint8 const*) p) [0] | + (( int8 const*) p) [1] << 8; } -void bDSP::power() { - spcram = r_smp->get_spcram_handle(); - memset(dspram, 0x00, 128); - - for(int v = 0; v < 8; v++) { - voice[v].VOLL = 0; - voice[v].VOLR = 0; - voice[v].PITCH = 0; - voice[v].SRCN = 0; - voice[v].ADSR1 = 0; - voice[v].ADSR2 = 0; - voice[v].GAIN = 0; - - status.FIR[v] = 0; - } - - status.MVOLL = status.MVOLR = 0; - status.EVOLL = status.EVOLR = 0; - status.ENDX = 0; - status.EFB = 0; - status.PMON = 0; - status.NON = 0; - status.EON = 0; - status.DIR = 0; - status.ESA = 0; - status.EDL = 0; - - status.echo_size = 0; - status.echo_target = 0; - - reset(); +inline void set_echo_sample( void* p, unsigned n ) +{ + ((uint8*) p) [0] = (uint8) n; + ((uint8*) p) [1] = (uint8) (n >> 8); } -void bDSP::reset() { - status.KON = 0x00; - status.KOFF = 0x00; - status.FLG |= 0xe0; - - status.kon = 0x00; - status.key_flag = false; - - status.noise_ctr = 0; - status.noise_rate = 0; - status.noise_sample = 0x4000; - - status.echo_index = 0; - status.fir_buffer_index = 0; - - for(int v = 0; v < 8; v++) { - voice[v].ENVX = 0; - voice[v].OUTX = 0; - - voice[v].pitch_ctr = 0; - - voice[v].brr_index = 0; - voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2)); - voice[v].brr_looped = false; - voice[v].brr_data[0] = 0; - voice[v].brr_data[1] = 0; - voice[v].brr_data[2] = 0; - voice[v].brr_data[3] = 0; - voice[v].brr_data_index = 0; - - voice[v].envx = 0; - voice[v].env_ctr = 0; - voice[v].env_rate = 0; - voice[v].env_state = SILENCE; - voice[v].env_mode = DIRECT; - - status.fir_buffer[0][v] = 0; - status.fir_buffer[1][v] = 0; - } - - dsp_counter = 0; +inline int bDSP::calc_echo_output( int ch, int echo_in ) +{ + return sclamp<16>( + sclip<16>( asr<7>( m.t_main_out [ch] * (int8) REG(mvoll + ch * 0x10) ) ) + + sclip<16>( asr<7>( echo_in * (int8) REG(evoll + ch * 0x10) ) ) ); } -uint32 bDSP::run() { -uint8 pmon; -int32 sample; -int32 msamplel, msampler; -int32 esamplel, esampler; -int32 fir_samplel, fir_sampler; - pmon = status.PMON & ~status.NON & ~1; - if(!(dsp_counter++ & 1) && status.key_flag) { - for(int v = 0; v < 8; v++) { - uint8 mask = 1 << v; - if(status.soft_reset()) { - if(voice[v].env_state != SILENCE) { - voice[v].env_state = SILENCE; - voice[v].AdjustEnvelope(); - } - } else if(status.KOFF & mask) { - if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) { - voice[v].env_state = RELEASE; - voice[v].AdjustEnvelope(); - } - } else if(status.kon & mask) { - status.ENDX &= ~mask; - status.kon &= ~mask; +//// Timing - voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2)); - voice[v].brr_index = -9; - voice[v].brr_looped = false; - voice[v].brr_data[0] = 0; - voice[v].brr_data[1] = 0; - voice[v].brr_data[2] = 0; - voice[v].brr_data[3] = 0; - voice[v].envx = 0; - voice[v].env_state = ATTACK; - voice[v].AdjustEnvelope(); - } - } - status.key_flag = false; - } +void bDSP::enter() +{ + int t_esa = REG(esa); + + while ( 1 ) + { + // n is currently ignored + #define NEXT_CLOCK( n ) \ + scheduler.addclocks_dsp( 3 ); + + // Execute clock for a particular voice + #define V( clock, voice ) voice_##clock( &m.voices [voice] ); -//update noise - status.noise_ctr += status.noise_rate; - if(status.noise_ctr >= 0x7800) { - status.noise_ctr -= 0x7800; - status.noise_sample = (status.noise_sample >> 1) | - (((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000); - } + /* The most common sequence of clocks uses composite operations + for efficiency. For example, the following are equivalent to the + individual steps on the right: - msamplel = msampler = 0; - esamplel = esampler = 0; + V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) + V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) + V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ + + NEXT_CLOCK( 0) V(V5,0)V(V2,1) + NEXT_CLOCK( 1) V(V6,0)V(V3,1) + NEXT_CLOCK( 2) V(V7_V4_V1,0) + NEXT_CLOCK( 3) V(V8_V5_V2,0) + NEXT_CLOCK( 4) V(V9_V6_V3,0) + NEXT_CLOCK( 5) V(V7_V4_V1,1) + NEXT_CLOCK( 6) V(V8_V5_V2,1) + NEXT_CLOCK( 7) V(V9_V6_V3,1) + NEXT_CLOCK( 8) V(V7_V4_V1,2) + NEXT_CLOCK( 9) V(V8_V5_V2,2) + NEXT_CLOCK(10) V(V9_V6_V3,2) + NEXT_CLOCK(11) V(V7_V4_V1,3) + NEXT_CLOCK(12) V(V8_V5_V2,3) + NEXT_CLOCK(13) V(V9_V6_V3,3) + NEXT_CLOCK(14) V(V7_V4_V1,4) + NEXT_CLOCK(15) V(V8_V5_V2,4) + NEXT_CLOCK(16) V(V9_V6_V3,4) + NEXT_CLOCK(17) V(V1,0) V(V7,5)V(V4,6) + NEXT_CLOCK(18) V(V8_V5_V2,5) + NEXT_CLOCK(19) V(V9_V6_V3,5) + NEXT_CLOCK(20) V(V1,1) V(V7,6)V(V4,7) + NEXT_CLOCK(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */ + NEXT_CLOCK(22) V(V3a,0) V(V9,6)V(V6,7) + + // History + if ( ++m.echo_hist_pos >= echo_hist_size ) + m.echo_hist_pos = 0; + + int const echo_ptr = (t_esa * 0x100 + m.echo_offset) & 0xFFFF; + + // FIR + int echo_in_l = CALC_FIR( 0, 0 ); + int echo_in_r = CALC_FIR( 0, 1 ); + + ECHO_FIR( 0 ) [0] = asr<1>( get_echo_sample( ECHO_PTR( 0 ) ) ); + + NEXT_CLOCK(23) V(V7,7) + + echo_in_l += CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); + echo_in_r += CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); + + ECHO_FIR( 0 ) [1] = asr<1>( get_echo_sample( ECHO_PTR( 1 ) ) ); + + NEXT_CLOCK(24) V(V8,7) + + echo_in_l += CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); + echo_in_r += CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); + + NEXT_CLOCK(25) V(V3b,0) V(V9,7) + + echo_in_l = sclip<16>( echo_in_l + CALC_FIR( 6, 0 ) ) + sclip<16>( CALC_FIR( 7, 0 ) ); + echo_in_r = sclip<16>( echo_in_r + CALC_FIR( 6, 1 ) ) + sclip<16>( CALC_FIR( 7, 1 ) ); + + echo_in_l = sclamp<16>( echo_in_l ) & ~1; + echo_in_r = sclamp<16>( echo_in_r ) & ~1; + + NEXT_CLOCK(26) - for(int v = 0; v < 8; v++) { - if(voice[v].brr_index < -1) { - voice[v].brr_index++; - voice[v].OUTX = voice[v].outx = 0; - voice[v].ENVX = 0; - continue; - } - - if(voice[v].brr_index >= 0) { - if(pmon & (1 << v)) { - voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15; - } else { - voice[v].pitch_ctr += voice[v].pitch_rate(); - } - } else { - voice[v].pitch_ctr = 0x3000; - voice[v].brr_index = 0; - } - - //decode BRR samples - while(voice[v].pitch_ctr >= 0) { - voice[v].pitch_ctr -= 0x1000; - - voice[v].brr_data_index++; - voice[v].brr_data_index &= 3; - - if(voice[v].brr_index == 0) { - voice[v].brr_header = readb(voice[v].brr_ptr); - - if(voice[v].brr_header_flags() == BRR_END) { - status.ENDX |= (1 << v); - voice[v].env_state = SILENCE; - voice[v].AdjustEnvelope(); - } - } - -#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3] - if(voice[v].env_state != SILENCE) { - sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1)); - if(voice[v].brr_index & 1) { - sample = sclip<4>(sample); - } else { - sample = sclip<4>(sample >> 4); - } - - if(voice[v].brr_header_shift() <= 12) { - sample = (sample << voice[v].brr_header_shift() >> 1); - } else { - sample &= ~0x7ff; - } - - switch(voice[v].brr_header_filter()) { - case 0: //direct - break; - case 1: //15/16 - sample += S(-1) + ((-S(-1)) >> 4); - break; - case 2: //61/32 - 15/16 - sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5) - - S(-2) + (S(-2) >> 4); - break; - case 3: //115/64 - 13/16 - sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6) - - S(-2) + (((S(-2) << 1) + S(-2)) >> 4); - break; - } - - S(0) = sample = sclip<15>(sclamp<16>(sample)); - } else { - S(0) = sample = 0; - } - - if(++voice[v].brr_index > 15) { - voice[v].brr_index = 0; - if(voice[v].brr_header_flags() & BRR_END) { - if(voice[v].brr_header_flags() & BRR_LOOP) { - status.ENDX |= (1 << v); - } - voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2); - voice[v].brr_looped = true; - } else { - voice[v].brr_ptr += 9; - } - } - } - - //volume envelope adjust - voice[v].env_ctr += voice[v].env_rate; - - if(voice[v].env_ctr >= 0x7800) { - voice[v].env_ctr -= 0x7800; - switch(voice[v].env_mode) { - case DIRECT: - voice[v].env_rate = 0; - break; - case LINEAR_DEC: - voice[v].envx -= 32; - if(voice[v].envx <= 0) { - voice[v].envx = 0; - voice[v].env_rate = 0; - voice[v].env_mode = DIRECT; - } - break; - case LINEAR_INC: - voice[v].envx += 32; - if(voice[v].envx >= 0x7ff) { - voice[v].envx = 0x7ff; - voice[v].env_rate = 0; - voice[v].env_mode = DIRECT; - if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) { - voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY); - voice[v].AdjustEnvelope(); - } - } - break; - case EXP_DEC: - //multiply by 255/256ths - voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1; - if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) { - voice[v].env_state = SUSTAIN; - voice[v].AdjustEnvelope(); - } else if(voice[v].envx <= 0) { - voice[v].envx = 0; - voice[v].env_rate = 0; - voice[v].env_mode = DIRECT; - } - break; - case BENT_INC: - if(voice[v].envx < 0x600) { - voice[v].envx += 32; - } else { - voice[v].envx += 8; - - if(voice[v].envx >= 0x7ff) { - voice[v].envx = 0x7ff; - voice[v].env_rate = 0; - voice[v].env_mode = DIRECT; - } - } - break; - case FAST_ATTACK: - voice[v].envx += 0x400; - if(voice[v].envx >= 0x7ff) { - voice[v].envx = 0x7ff; - - //attack raises to max envx. if sustain is also set to max envx, skip decay phase - voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY); - voice[v].AdjustEnvelope(); - } - break; - case RELEASE_DEC: - voice[v].envx -= 8; - if(voice[v].envx <= 0) { - voice[v].env_state = SILENCE; - voice[v].AdjustEnvelope(); - } - break; - } - } - - voice[v].ENVX = voice[v].envx >> 4; - - //gaussian interpolation / noise - if(status.NON & (1 << v)) { - sample = sclip<15>(status.noise_sample); - } else { - int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1 - sample = ((GaussTable[ -1-d] * S(-3)) >> 11); - sample += ((GaussTable[255-d] * S(-2)) >> 11); - sample += ((GaussTable[512+d] * S(-1)) >> 11); - sample = sclip <15>(sample); - sample += ((GaussTable[256+d] * S( 0)) >> 11); - sample = sclamp<15>(sample); - } -#undef S - - //envelope / volume adjust - sample = (sample * voice[v].envx) >> 11; - voice[v].outx = sample << 1; - voice[v].OUTX = sample >> 7; - - if(!status.mute()) { - msamplel += ((sample * voice[v].VOLL) >> 7) << 1; - msampler += ((sample * voice[v].VOLR) >> 7) << 1; - } - - if((status.EON & (1 << v)) && status.echo_write()) { - esamplel += ((sample * voice[v].VOLL) >> 7) << 1; - esampler += ((sample * voice[v].VOLR) >> 7) << 1; - } - } - -//echo (FIR) adjust -#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index+(x)) & 7] - status.fir_buffer_index++; - F(0,0) = readw((status.ESA << 8) + status.echo_index); - F(1,0) = readw((status.ESA << 8) + status.echo_index + 2); - - fir_samplel = (F(0,-0) * status.FIR[7] + - F(0,-1) * status.FIR[6] + - F(0,-2) * status.FIR[5] + - F(0,-3) * status.FIR[4] + - F(0,-4) * status.FIR[3] + - F(0,-5) * status.FIR[2] + - F(0,-6) * status.FIR[1] + - F(0,-7) * status.FIR[0]); - - fir_sampler = (F(1,-0) * status.FIR[7] + - F(1,-1) * status.FIR[6] + - F(1,-2) * status.FIR[5] + - F(1,-3) * status.FIR[4] + - F(1,-4) * status.FIR[3] + - F(1,-5) * status.FIR[2] + - F(1,-6) * status.FIR[1] + - F(1,-7) * status.FIR[0]); -#undef F - -//update echo buffer - if(status.echo_write()) { - esamplel += (fir_samplel * status.EFB) >> 14; - esampler += (fir_sampler * status.EFB) >> 14; - - esamplel = sclamp<16>(esamplel); - esampler = sclamp<16>(esampler); - - writew((status.ESA << 8) + status.echo_index, esamplel); - writew((status.ESA << 8) + status.echo_index + 2, esampler); - } - - status.echo_index += 4; - if(status.echo_index >= status.echo_target) { - status.echo_index = 0; - status.echo_target = status.echo_size; - } - -//main output adjust - if(!status.mute()) { - msamplel = (msamplel * status.MVOLL) >> 7; - msampler = (msampler * status.MVOLR) >> 7; - - msamplel += (fir_samplel * status.EVOLL) >> 14; - msampler += (fir_sampler * status.EVOLR) >> 14; - - msamplel = sclamp<16>(msamplel); - msampler = sclamp<16>(msampler); - } - - return (uint32)( (uint16)msamplel | ((uint16)msampler << 16) ); + // Echo feedback + int echo_out_l = m.t_echo_out [0] + sclip<16>( asr<7>( echo_in_l * (int8) REG(efb) ) ); + int echo_out_r = m.t_echo_out [1] + sclip<16>( asr<7>( echo_in_r * (int8) REG(efb) ) ); + + echo_out_l = sclamp<16>( echo_out_l ) & ~1; + echo_out_r = sclamp<16>( echo_out_r ) & ~1; + + // Output + int main_out_l = calc_echo_output( 0, echo_in_l ); + + NEXT_CLOCK(27) + + int main_out_r = calc_echo_output( 1, echo_in_r ); + + // TODO: global muting isn't this simple (turns DAC on and off + // or something, causing small ~37-sample pulse when first muted) + if ( REG(flg) & 0x40 ) + { + main_out_l = 0; + main_out_r = 0; + } + + // Output sample to DAC + snes.audio_update( main_out_l, main_out_r ); + + m.t_main_out [0] = 0; + m.t_main_out [1] = 0; + + m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON + + NEXT_CLOCK(28) + + m.t_non = REG(non); + m.t_eon = REG(eon); + m.t_dir = REG(dir); + + int echo_disabled = REG(flg); + + NEXT_CLOCK(29) + + // Write left echo + if ( !(echo_disabled & 0x20) ) + set_echo_sample( ECHO_PTR( 0 ), echo_out_l ); + m.t_echo_out [0] = 0; + + t_esa = REG(esa); + + if ( !m.echo_offset ) + m.echo_length = (REG(edl) & 0x0F) * 0x800; + + m.echo_offset += 4; + if ( m.echo_offset >= m.echo_length ) + m.echo_offset = 0; + + if ( (m.every_other_sample ^= 1) != 0 ) + m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read + + echo_disabled = REG(flg); + + NEXT_CLOCK(30) + + // Write right echo + if ( !(echo_disabled & 0x20) ) + set_echo_sample( ECHO_PTR( 1 ), echo_out_r ); + m.t_echo_out [1] = 0; + + if ( m.every_other_sample ) + { + m.kon = m.new_kon; + m.t_koff = REG(koff); + } + + if ( --m.counter < 0 ) + m.counter = simple_counter_range - 1; + + // Noise + if ( !read_counter( REG(flg) & 0x1F ) ) + { + int feedback = (m.noise << 13) ^ (m.noise << 14); + m.noise = (feedback & 0x4000) ^ (m.noise >> 1); + } + + V(V3c,0) + + NEXT_CLOCK(31) V(V4,0) V(V1,2) + } } -bDSP::bDSP() {} -bDSP::~bDSP() {} + +//// Setup + +bDSP::bDSP() { } + +bDSP::~bDSP() { } + +void bDSP::reset() +{ + REG(flg) = 0xE0; + + m.noise = 0x4000; + m.echo_hist_pos = 0; + m.every_other_sample = 1; + m.echo_offset = 0; + m.counter = 0; +} + +static uint8 const initial_regs [bDSP::register_count] = +{ + 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, + 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, + 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, + 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, + 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, + 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF, + 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, + 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF +}; + +void bDSP::power() +{ + ram = (uint8*) r_smp->get_spcram_handle(); + memset( &m, 0, sizeof m ); + memcpy( m.regs, initial_regs, sizeof m.regs ); + + // Internal state + for ( int i = voice_count; --i >= 0; ) + { + voice_t* v = &m.voices [i]; + v->brr_offset = 1; + v->vbit = 1 << i; + v->regs = &m.regs [i * 0x10]; + } + m.new_kon = REG(kon); + m.t_dir = REG(dir); + + reset(); +} diff --git a/src/dsp/bdsp/bdsp.h b/src/dsp/bdsp/bdsp.h index 3570827b..0ff7a5e0 100644 --- a/src/dsp/bdsp/bdsp.h +++ b/src/dsp/bdsp/bdsp.h @@ -1,171 +1,167 @@ class bDSP : public DSP { -private: -uint8 dspram[128]; -uint8 *spcram; - -uint32 dsp_counter; - -enum { BRR_END = 1, BRR_LOOP = 2 }; - -uint8 readb (uint16 addr); -uint16 readw (uint16 addr); -void writeb(uint16 addr, uint8 data); -void writew(uint16 addr, uint16 data); - public: -static const uint16 RateTable[32]; -static const int16 GaussTable[512]; - -enum EnvelopeStates { - ATTACK, - DECAY, - SUSTAIN, - RELEASE, - SILENCE -}; - -enum EnvelopeModes { - DIRECT, - LINEAR_DEC, - EXP_DEC, - LINEAR_INC, - BENT_INC, - - FAST_ATTACK, - RELEASE_DEC -}; - -private: -struct Status { -//$0c,$1c - int8 MVOLL, MVOLR; -//$2c,$3c - int8 EVOLL, EVOLR; -//$4c,$5c - uint8 KON, KOFF; -//$6c - uint8 FLG; -//$7c - uint8 ENDX; -//$0d - int8 EFB; -//$2d,$3d,$4d - uint8 PMON, NON, EON; -//$5d - uint8 DIR; -//$6d,$7d - uint8 ESA, EDL; - -//$xf - int8 FIR[8]; - -//internal variables - uint8 kon; - bool key_flag; - - int16 noise_ctr, noise_rate; - uint16 noise_sample; - - uint16 echo_index, echo_size, echo_target; - int16 fir_buffer[2][8]; - uint8 fir_buffer_index; - -//functions - bool soft_reset() { return bool(FLG & 0x80); } - bool mute() { return bool(FLG & 0x40); } - bool echo_write() { return !(FLG & 0x20); } -} status; - -struct Voice { -//$x0-$x1 - int8 VOLL, VOLR; -//$x2-$x3 - int16 PITCH; -//$x4 - uint8 SRCN; -//$x5-$x7 - uint8 ADSR1, ADSR2, GAIN; -//$x8-$x9 - uint8 ENVX, OUTX; - -//internal variables - int16 pitch_ctr; - - int8 brr_index; - uint16 brr_ptr; - uint8 brr_header; - bool brr_looped; - - int16 brr_data[4]; - uint8 brr_data_index; - - int16 envx; - uint16 env_ctr, env_rate, env_sustain; - enum EnvelopeStates env_state; - enum EnvelopeModes env_mode; - - int16 outx; - -//functions - int16 pitch_rate() { return PITCH & 0x3fff; } - - uint8 brr_header_shift() { return brr_header >> 4; } - uint8 brr_header_filter() { return (brr_header >> 2) & 3; } - uint8 brr_header_flags() { return brr_header & 3; } - - bool ADSR_enabled() { return bool(ADSR1 & 0x80); } - uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; } - uint8 ADSR_attack() { return ADSR1 & 15; } - uint8 ADSR_sus_level() { return ADSR2 >> 5; } - uint8 ADSR_sus_rate() { return ADSR2 & 31; } - - void AdjustEnvelope() { - if(env_state == SILENCE) { - env_mode = DIRECT; - env_rate = 0; - envx = 0; - } else if(env_state == RELEASE) { - env_mode = RELEASE_DEC; - env_rate = 0x7800; - } else if(ADSR_enabled()) { - switch(env_state) { - case ATTACK: - env_rate = RateTable[(ADSR_attack() << 1) + 1]; - env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC; - break; - case DECAY: - env_rate = RateTable[(ADSR_decay() << 1) + 0x10]; - env_mode = EXP_DEC; - break; - case SUSTAIN: - env_rate = RateTable[ADSR_sus_rate()]; - env_mode = (env_rate == 0) ? DIRECT : EXP_DEC; - break; - } - } else if(GAIN & 0x80) { - switch(GAIN & 0x60) { - case 0x00: env_mode = LINEAR_DEC; break; - case 0x20: env_mode = EXP_DEC; break; - case 0x40: env_mode = LINEAR_INC; break; - case 0x60: env_mode = BENT_INC; break; - } - env_rate = RateTable[GAIN & 0x1f]; - } else { - env_mode = DIRECT; - env_rate = 0; - envx = (GAIN & 0x7f) << 4; - } - } -} voice[8]; + void enter(); + + uint8 read( uint8 addr ); + void write( uint8 addr, uint8 data ); + void power(); + void reset(); + + bDSP(); + ~bDSP(); + public: - uint8 read (uint8 addr); - void write(uint8 addr, uint8 data); - void power(); - void reset(); - uint32 run(); + enum { echo_hist_size = 8 }; + enum { register_count = 128 }; + enum { voice_count = 8 }; + + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + enum { brr_buf_size = 12 }; + struct voice_t + { + int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) + int buf_pos; // place in buffer where next samples will be decoded + int interp_pos; // relative fractional position in sample (0x1000 = 1.0) + int brr_addr; // address of current BRR block + int brr_offset; // current decoding offset in BRR block + uint8* regs; // pointer to voice's DSP registers + int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. + int kon_delay; // KON delay/current setup phase + env_mode_t env_mode; + int env; // current envelope level + int hidden_env; // used by GAIN mode 7, very obscure quirk + uint8 t_envx_out; + }; +private: + + struct state_t + { + uint8 regs [register_count]; + + // Echo history keeps most recent 8 samples + int echo_hist [echo_hist_size] [2]; + int echo_hist_pos; + + int every_other_sample; // toggles every sample + int kon; // KON value when last checked + int noise; + int counter; + int echo_offset; // offset from ESA in echo buffer + int echo_length; // number of bytes that echo_offset will stop at + + // Hidden registers also written to when main register is written to + int new_kon; + uint8 endx_buf; + uint8 envx_buf; + uint8 outx_buf; + + // Temporary state between clocks + + // read once per sample + int t_pmon; + int t_non; + int t_eon; + int t_dir; + int t_koff; + + // read a few clocks ahead then used + int t_brr_next_addr; + int t_adsr0; + int t_brr_header; + int t_brr_byte; + int t_srcn; + + // internal state that is recalculated every sample + int t_dir_addr; + int t_pitch; + int t_output; + int t_looped; + + // left/right sums + int t_main_out [2]; + int t_echo_out [2]; + + voice_t voices [voice_count]; + }; + state_t m; + uint8* ram; + + unsigned read_counter( int rate ); + + void run_envelope( voice_t* const v ); + void decode_brr( voice_t* v ); - bDSP(); - ~bDSP(); + void voice_output( voice_t const* v, int ch ); + void voice_V1( voice_t* const ); + void voice_V2( voice_t* const ); + void voice_V3( voice_t* const ); + void voice_V3a( voice_t* const ); + void voice_V3b( voice_t* const ); + void voice_V3c( voice_t* const ); + void voice_V4( voice_t* const ); + void voice_V5( voice_t* const ); + void voice_V6( voice_t* const ); + void voice_V7( voice_t* const ); + void voice_V8( voice_t* const ); + void voice_V9( voice_t* const ); + void voice_V7_V4_V1( voice_t* const ); + void voice_V8_V5_V2( voice_t* const ); + void voice_V9_V6_V3( voice_t* const ); + + int calc_echo_output( int ch, int sample ); + + // Global registers + enum { + r_mvoll = 0x0C, r_mvolr = 0x1C, + r_evoll = 0x2C, r_evolr = 0x3C, + r_kon = 0x4C, r_koff = 0x5C, + r_flg = 0x6C, r_endx = 0x7C, + r_efb = 0x0D, r_pmon = 0x2D, + r_non = 0x3D, r_eon = 0x4D, + r_dir = 0x5D, r_esa = 0x6D, + r_edl = 0x7D, + r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F + }; + + // Voice registers + enum { + v_voll = 0x00, v_volr = 0x01, + v_pitchl = 0x02, v_pitchh = 0x03, + v_srcn = 0x04, v_adsr0 = 0x05, + v_adsr1 = 0x06, v_gain = 0x07, + v_envx = 0x08, v_outx = 0x09 + }; }; + +inline uint8 bDSP::read( uint8 addr ) +{ + return m.regs [addr]; +} + +inline void bDSP::write( uint8 addr, uint8 data ) +{ + m.regs [addr] = data; + switch ( addr & 0x0F ) + { + case v_envx: + m.envx_buf = data; + break; + + case v_outx: + m.outx_buf = data; + break; + + case 0x0C: + if ( addr == r_kon ) + m.new_kon = data; + + if ( addr == r_endx ) // always cleared, regardless of data written + { + m.endx_buf = 0; + m.regs [r_endx] = 0; + } + break; + } +} diff --git a/src/dsp/bdsp_official/bdsp.cpp b/src/dsp/bdsp_official/bdsp.cpp new file mode 100644 index 00000000..f5d0bd0c --- /dev/null +++ b/src/dsp/bdsp_official/bdsp.cpp @@ -0,0 +1,32 @@ +#include "../../base.h" +#include "spc_dsp.h" + +void bDSP::power() { + spc_dsp_init(r_smp->get_spcram_handle()); + spc_dsp_reset(); +} + +void bDSP::reset() { + spc_dsp_soft_reset(); +} + +uint8 bDSP::read(uint8 addr) { + return spc_dsp_read(addr); +} + +void bDSP::write(uint8 addr, uint8 data) { + spc_dsp_write(addr, data); +} + +#define SPC_DSP_CUSTOM_RUN 1 //causes spc_dsp_run() to not be defined since it's huge and we don't need it +#define SPC_DSP_OUT_HOOK(left, right) snes.audio_update(left, right); +#include "spc_dsp.cpp" + +void bDSP::enter() { loop: +#define PHASE(n) scheduler.addclocks_dsp(3); +#include "spc_dsp_timing.h" + goto loop; +} + +bDSP::bDSP() {} +bDSP::~bDSP() {} diff --git a/src/dsp/bdsp_official/bdsp.h b/src/dsp/bdsp_official/bdsp.h new file mode 100644 index 00000000..645efaec --- /dev/null +++ b/src/dsp/bdsp_official/bdsp.h @@ -0,0 +1,10 @@ +class bDSP : public DSP { public: + void enter(); + uint8 read(uint8 addr); + void write(uint8 addr, uint8 data); + void power(); + void reset(); + + bDSP(); + ~bDSP(); +}; diff --git a/src/dsp/bdsp_official/readme.txt b/src/dsp/bdsp_official/readme.txt new file mode 100644 index 00000000..b080d1a8 --- /dev/null +++ b/src/dsp/bdsp_official/readme.txt @@ -0,0 +1,64 @@ +Overall operation +----------------- +This DSP emulator fundamentally emulates the different options the DSP +performs on each clock. The pattern of operations repeats every 32 +clocks (except one minor detail, which repeats every 64 clocks instead). +There are three main types of operations: + +- Miscellaneous processing +- Voice processing +- Echo processing + +Each is done over several clocks, and several operations are done on +each clock. Each clock is defined as a separate function, then called +from a large switch block in a loop. + +Many times a value is read on one clock but not used until a later +clock, so many non-local temporary variables are used in the code to +store these values. These are named with t_ to make it clear that they +don't store long-term state. + + +Circular buffers +---------------- +Two circular buffers are used in the code (echo history and BRR decode). +Both need efficient index-based access with wrap-around. Things are +greatly simplified by repeating the contents of buffer twice, so instead +of + + 0 1 2 3 4 5 6 7 + +it stores + + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + +The position in this case would always be 0 to 7, so reading up to +8 +won't go outside buffer. This duplication is maintained by simply +writing data twice when filling buffer: + + 0 1 2 3 4 # 6 7 0 1 2 3 4 # 6 7 +new data -----^---------------^ + +No wrap checking needs to be done when writing either, since the above +reasoning holds. When making a state snapshot, only the first copy needs +to be saved. When restoring, simply duplicate the data twice. + + +Code +---- +- Currently all state is in static variables. They have either a t_ or +m_ prefix to allow easy migration to a structure. + +- Static state that persists over several samples or more is prefixed +with m_. + +- State which is temporary to the current sample is prefixed with t_. +These are usually just overwritten with new data on the next sample. +These generally correspond to temporaries/registers in actual DSP +itself. + +- Minimal stdint.h included in case your system doesn't have one. + + +-- +Shay Green diff --git a/src/dsp/bdsp_official/spc_dsp.cpp b/src/dsp/bdsp_official/spc_dsp.cpp new file mode 100644 index 00000000..83715d89 --- /dev/null +++ b/src/dsp/bdsp_official/spc_dsp.cpp @@ -0,0 +1,828 @@ +// http://www.slack.net/~ant/ + +#include "spc_dsp.h" + +#include +#include + +/* Copyright (C) 2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +// Volume registers and efb are signed! Easy to forget int8_t cast. +// Prefixes are to avoid accidental use of locals with same names. + +// Global registers +enum { + r_mvoll = 0x0C, r_mvolr = 0x1C, + r_evoll = 0x2C, r_evolr = 0x3C, + r_kon = 0x4C, r_koff = 0x5C, + r_flg = 0x6C, r_endx = 0x7C, + r_efb = 0x0D, r_pmon = 0x2D, + r_non = 0x3D, r_eon = 0x4D, + r_dir = 0x5D, r_esa = 0x6D, + r_edl = 0x7D, + r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F +}; + +// Voice registers +enum { + v_voll = 0x00, v_volr = 0x01, + v_pitchl = 0x02, v_pitchh = 0x03, + v_srcn = 0x04, v_adsr0 = 0x05, + v_adsr1 = 0x06, v_gain = 0x07, + v_envx = 0x08, v_outx = 0x09 +}; + +// Internal envelope modes +enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + +// Internal voice state +enum { brr_buf_size = 12 }; +enum { brr_block_size = 9 }; +typedef struct voice_t +{ + int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) + int buf_pos; // place in buffer where next samples will be decoded + int interp_pos; // relative fractional position in sample (0x1000 = 1.0) + int brr_addr; // address of current BRR block + int brr_offset; // current decoding offset in BRR block + uint8_t* regs; // pointer to voice's DSP registers + int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. + int kon_delay; // KON delay/current setup phase + enum env_mode_t env_mode; + int env; // current envelope level + int t_envx_out; + int hidden_env; // used by GAIN mode 7, very obscure quirk +} voice_t; + +static voice_t m_voice_state [spc_dsp_voice_count]; +static uint8_t* m_ram; // 64K shared RAM between DSP and SMP +spc_dsp_t m_spc_dsp; +spc_dsp_sample_t* m_spc_dsp_out_begin; +spc_dsp_sample_t* m_spc_dsp_out; +spc_dsp_sample_t* m_spc_dsp_out_end; + +// "Member" access +#define m m_spc_dsp + +// Access global DSP register +#define REG(n) m.regs [r_##n] + +// Access voice DSP register +#define VREG(r,n) r [v_##n] + +// if ( io < -32768 ) io = -32768; +// if ( io > 32767 ) io = 32767; +#define CLAMP16( io )\ +{\ + if ( (int16_t) io != io )\ + io = 0x7FFF ^ (io >> 31);\ +} + +// Gaussian interpolation + +static short const gauss [512] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, +1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, +1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, +1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, +1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, +1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, +1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, +1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, +}; + +static inline int interpolate( voice_t const* const v ) +{ + // Make pointers into gaussian based on fractional position between samples + int offset = v->interp_pos >> 4 & 0xFF; + short const* fwd = gauss + 255 - offset; + short const* rev = gauss + offset; // mirror left half of gaussian + + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + int out; + out = (fwd [ 0] * in [0]) >> 11; + out += (fwd [256] * in [1]) >> 11; + out += (rev [256] * in [2]) >> 11; + out = (int16_t) out; + out += (rev [ 0] * in [3]) >> 11; + + CLAMP16( out ); + out &= ~1; + return out; +} + + +//// Counters + +enum { simple_counter_range = 2048 * 5 * 3 }; // 30720 + +static unsigned short const counter_rates [32] = +{ + simple_counter_range + 1, // never fires + 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1 +}; + +static unsigned short const counter_offsets [32] = +{ + 1, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 0, + 0 +}; + +static inline void init_counters( void ) { } + +static inline void run_counters( void ) +{ + if ( --m.counter < 0 ) + m.counter = simple_counter_range - 1; +} + +static inline unsigned read_counter( int rate ) +{ + return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; +} + + +//// Envelope + +static inline void run_envelope( voice_t* const v ) +{ + int env = v->env; + if ( v->env_mode == env_release ) // 60% + { + if ( (env -= 0x8) < 0 ) + env = 0; + v->env = env; + } + else + { + int rate; + int env_data = VREG(v->regs,adsr1); + if ( m.t_adsr0 & 0x80 ) // 99% ADSR + { + if ( v->env_mode >= env_decay ) // 99% + { + env--; + env -= env >> 8; + rate = env_data & 0x1F; + if ( v->env_mode == env_decay ) // 1% + rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; + } + else // env_attack + { + rate = (m.t_adsr0 & 0x0F) * 2 + 1; + env += rate < 31 ? 0x20 : 0x400; + } + } + else // GAIN + { + env_data = VREG(v->regs,gain); + int mode = env_data >> 5; + if ( mode < 4 ) // direct + { + env = env_data * 0x10; + rate = 31; + } + else + { + rate = env_data & 0x1F; + if ( mode == 4 ) // 4: linear decrease + { + env -= 0x20; + } + else if ( mode < 6 ) // 5: exponential decrease + { + env--; + env -= env >> 8; + } + else // 6,7: linear increase + { + env += 0x20; + if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) + env += 0x8 - 0x20; // 7: two-slope linear increase + } + } + } + + // Sustain level + if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) + v->env_mode = env_sustain; + + v->hidden_env = env; + + // unsigned cast because linear decrease going negative also triggers this + if ( (unsigned) env > 0x7FF ) + { + env = (env < 0 ? 0 : 0x7FF); + if ( v->env_mode == env_attack ) + v->env_mode = env_decay; + } + + if ( !read_counter( rate ) ) + v->env = env; // nothing else is controlled by the counter + } +} + + +//// BRR Decoding + +static inline void decode_brr( voice_t* v ) +{ + // Arrange the four input nybbles in 0xABCD order for easy decoding + int nybbles = m.t_brr_byte * 0x100 + m_ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; + + int const header = m.t_brr_header; + + // 0: >>1 1: <<0 2: <<1 ... 12: <<11 13-15: >>4 <<11 + static unsigned char const shifts [16 * 2] = { + 13,12,12,12,12,12,12,12,12,12,12, 12, 12, 16, 16, 16, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11 + }; + int const scale = header >> 4; + int const right_shift = shifts [scale]; + int const left_shift = shifts [scale + 16]; + + // Write to next four samples in circular buffer + int* pos = &v->buf [v->buf_pos]; + if ( (v->buf_pos += 4) >= brr_buf_size ) + v->buf_pos = 0; + + // Decode four samples + for ( int* end = pos + 4; pos < end; pos++ ) + { + // Extract upper nybble and scale appropriately + int s = ((int16_t) nybbles >> right_shift) << left_shift; + nybbles <<= 4; + + // Apply IIR filter (8 is the most commonly used) + int const filter = header & 0x0C; + int const p1 = pos [brr_buf_size - 1]; + int const p2 = pos [brr_buf_size - 2] >> 1; + if ( filter >= 8 ) + { + s += p1; + s -= p2; + if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 + { + s += p2 >> 4; + s += (p1 * -3) >> 6; + } + else // s += p1 * 0.8984375 - p2 * 0.40625 + { + s += (p1 * -13) >> 7; + s += (p2 * 3) >> 4; + } + } + else if ( filter ) // s += p1 * 0.46875 + { + s += p1 >> 1; + s += (-p1) >> 5; + } + + // Adjust and write sample + CLAMP16( s ); + s = (int16_t) (s * 2); + pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around + } +} + + +//// Misc + +#define MISC_CLOCK( n ) inline static void misc_##n( void ) + +MISC_CLOCK( 27 ) +{ + m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON +} +MISC_CLOCK( 28 ) +{ + m.t_non = REG(non); + m.t_eon = REG(eon); + m.t_dir = REG(dir); +} +MISC_CLOCK( 29 ) +{ + if ( (m.every_other_sample ^= 1) != 0 ) + m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read +} +MISC_CLOCK( 30 ) +{ + if ( m.every_other_sample ) + { + m.kon = m.new_kon; + m.t_koff = REG(koff) | m.mute_mask; + } + + run_counters(); + + // Noise + if ( !read_counter( REG(flg) & 0x1F ) ) + { + int feedback = (m.noise << 13) ^ (m.noise << 14); + m.noise = (feedback & 0x4000) ^ (m.noise >> 1); + } +} + + +//// Voices + +#define VOICE_CLOCK( n ) static void voice_##n( voice_t* const v ) + +inline VOICE_CLOCK( V1 ) +{ + m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; + m.t_srcn = VREG(v->regs,srcn); +} +inline VOICE_CLOCK( V2 ) +{ + // Read sample pointer (ignored if not needed) + uint8_t const* entry = &m_ram [m.t_dir_addr]; + if ( !v->kon_delay ) + entry += 2; + m.t_brr_next_addr = entry [1] * 0x100 + entry [0]; + + m.t_adsr0 = VREG(v->regs,adsr0); + + // Read pitch, spread over two clocks + m.t_pitch = VREG(v->regs,pitchl); +} +inline VOICE_CLOCK( V3a ) +{ + m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; +} +inline VOICE_CLOCK( V3b ) +{ + // Read BRR header and byte + m.t_brr_byte = m_ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; + m.t_brr_header = m_ram [v->brr_addr]; // brr_addr doesn't need masking +} +VOICE_CLOCK( V3c ) +{ + // Pitch modulation using previous voice's output + if ( m.t_pmon & v->vbit ) + m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; + + if ( v->kon_delay ) + { + // Get ready to start BRR decoding on next sample + if ( v->kon_delay == 5 ) + { + v->brr_addr = m.t_brr_next_addr; + v->brr_offset = 1; + v->buf_pos = 0; + m.t_brr_header = 0; // header is ignored on this sample + } + + // Envelope is never run during KON + v->env = 0; + v->hidden_env = 0; + + // Disable BRR decoding until last three samples + v->interp_pos = 0; + if ( --v->kon_delay & 3 ) + v->interp_pos = 0x4000; + + // Pitch is never added during KON + m.t_pitch = 0; + } + + // Gaussian interpolation + int output = interpolate( v ); + + // Noise + if ( m.t_non & v->vbit ) + output = (int16_t) (m.noise * 2); + + // Apply envelope + m.t_output = (output * v->env) >> 11 & ~1; + v->t_envx_out = v->env >> 4; + + // Immediate silence due to end of sample or soft reset + if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) + { + v->env_mode = env_release; + v->env = 0; + } + + if ( m.every_other_sample ) + { + // KOFF + if ( m.t_koff & v->vbit ) + v->env_mode = env_release; + + // KON + if ( m.kon & v->vbit ) + { + v->kon_delay = 5; + v->env_mode = env_attack; + } + } + + // Run envelope for next sample + if ( !v->kon_delay ) + run_envelope( v ); +} +static inline void voice_output( voice_t const* v, int ch ) +{ + // Apply left/right volume + int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; + + // Add to output total + m.t_main_out [ch] += amp; + CLAMP16( m.t_main_out [ch] ); + + // Optionally add to echo total + if ( m.t_eon & v->vbit ) + { + m.t_echo_out [ch] += amp; + CLAMP16( m.t_echo_out [ch] ); + } +} +VOICE_CLOCK( V4 ) +{ + // Decode BRR + m.t_looped = 0; + if ( v->interp_pos >= 0x4000 ) + { + decode_brr( v ); + + if ( (v->brr_offset += 2) >= brr_block_size ) + { + // Start decoding next BRR block + assert( v->brr_offset == brr_block_size ); + v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; + if ( m.t_brr_header & 1 ) + { + v->brr_addr = m.t_brr_next_addr; + m.t_looped = v->vbit; + } + v->brr_offset = 1; + } + } + + // Apply pitch + v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; + + // Keep from getting too far ahead (when using pitch modulation) + if ( v->interp_pos > 0x7FFF ) + v->interp_pos = 0x7FFF; + + // Output left + voice_output( v, 0 ); +} +inline VOICE_CLOCK( V5 ) +{ + // Output right + voice_output( v, 1 ); + + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier + + m.endx_buf = REG(endx) | m.t_looped; + + // Clear bit in ENDX if KON just began + if ( v->kon_delay == 5 ) + m.endx_buf &= ~v->vbit; +} +inline VOICE_CLOCK( V6 ) +{ + m.outx_buf = m.t_output >> 8; +} +inline VOICE_CLOCK( V7 ) +{ + // Update ENDX + REG(endx) = (uint8_t) m.endx_buf; + + m.envx_buf = v->t_envx_out; +} +inline VOICE_CLOCK( V8 ) +{ + // Update OUTX + VREG(v->regs,outx) = (uint8_t) m.outx_buf; +} +inline VOICE_CLOCK( V9 ) +{ + // Update ENVX + VREG(v->regs,envx) = (uint8_t) m.envx_buf; +} + +// Most voices do all these in one clock, so make a handy composite +inline VOICE_CLOCK( V3 ) +{ + voice_V3a( v ); + voice_V3b( v ); + voice_V3c( v ); +} + +// Common combinations of voice steps on different voices. This greatly reduces +// code size and allows everything to be inlined in these functions. +VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } +VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } +VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } + + +//// Echo + +// Current echo buffer pointer for left/right channel +#define ECHO_PTR( ch ) (&m_ram [m.t_echo_ptr + ch * 2]) + +// Sample in echo history buffer, where 0 is the oldest +#define ECHO_FIR( i ) (m.echo_hist_pos [i]) + +// Calculate FIR point for left/right channel +#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) + +#define ECHO_CLOCK( n ) inline static void echo_##n( void ) + +static inline void echo_read( int ch ) +{ + uint8_t const* in = ECHO_PTR( ch ); + int s = (int8_t) in [1] * 0x100 + in [0]; + // second copy simplifies wrap-around handling + ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; +} + +ECHO_CLOCK( 22 ) +{ + // History + if ( ++m.echo_hist_pos >= &m.echo_hist [spc_dsp_echo_hist_size] ) + m.echo_hist_pos = m.echo_hist; + + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; + echo_read( 0 ); + + // FIR (using l and r temporaries below helps compiler optimize) + int l = CALC_FIR( 0, 0 ); + int r = CALC_FIR( 0, 1 ); + + m.t_echo_in [0] = l; + m.t_echo_in [1] = r; +} +ECHO_CLOCK( 23 ) +{ + int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); + int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; + + echo_read( 1 ); +} +ECHO_CLOCK( 24 ) +{ + int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); + int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; +} +ECHO_CLOCK( 25 ) +{ + int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); + int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); + + l = (int16_t) l; + r = (int16_t) r; + + l += (int16_t) CALC_FIR( 7, 0 ); + r += (int16_t) CALC_FIR( 7, 1 ); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_in [0] = l & ~1; + m.t_echo_in [1] = r & ~1; +} +static inline int echo_output( int ch ) +{ + int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + + (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); + CLAMP16( out ); + return out; +} +ECHO_CLOCK( 26 ) +{ + // Left output volumes + // (save sample for next clock so we can output both together) + m.t_main_out [0] = echo_output( 0 ); + + // Echo feedback + int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); + int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_out [0] = l & ~1; + m.t_echo_out [1] = r & ~1; +} +ECHO_CLOCK( 27 ) +{ + // Output + int outl = m.t_main_out [0]; + int outr = echo_output( 1 ); + m.t_main_out [0] = 0; + m.t_main_out [1] = 0; + + // TODO: global muting isn't this simple (turns DAC on and off + // or something, causing small ~37-sample pulse when first muted) + if ( REG(flg) & 0x40 ) + { + outl = 0; + outr = 0; + } + + // Output sample to DAC + #ifdef SPC_DSP_OUT_HOOK + SPC_DSP_OUT_HOOK( outl, outr ); + #else + spc_dsp_sample_t* out = m_spc_dsp_out; + assert( !out || out < m_spc_dsp_out_end ); // fails if output buffer is too small + if ( out != m_spc_dsp_out_end ) + { + out [0] = outl; + out [1] = outr; + m_spc_dsp_out = out + 2; + } + #endif +} +ECHO_CLOCK( 28 ) +{ + m.t_echo_enabled = REG(flg); +} +static inline void echo_write( int ch ) +{ + if ( !(m.t_echo_enabled & 0x20) ) + { + uint8_t* out = ECHO_PTR( ch ); + int s = m.t_echo_out [ch]; + out [0] = (uint8_t) s; + out [1] = (uint8_t) (s >> 8); + } + m.t_echo_out [ch] = 0; +} +ECHO_CLOCK( 29 ) +{ + m.t_esa = REG(esa); + + if ( !m.echo_offset ) + m.echo_length = (REG(edl) & 0x0F) * 0x800; + + m.echo_offset += 4; + if ( m.echo_offset >= m.echo_length ) + m.echo_offset = 0; + + // Write left echo + echo_write( 0 ); + + m.t_echo_enabled = REG(flg); +} +ECHO_CLOCK( 30 ) +{ + // Write right echo + echo_write( 1 ); +} + + +//// Timing + +#if !SPC_DSP_CUSTOM_RUN + +void spc_dsp_run( int clocks_remain ) +{ + assert( clocks_remain > 0 ); + + int const phase = m.phase; + m.phase = (phase + clocks_remain) & 31; + switch ( phase ) + { + loop: + + #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: + #include "spc_dsp_timing.h" + #undef PHASE + + if ( --clocks_remain ) + goto loop; + } +} + +#endif + + +//// Setup + +void spc_dsp_reset( void ) +{ + // Clear everything to zero, then set things which must be non-zero + memset( m_voice_state, 0, sizeof m_voice_state ); + memset( &m_spc_dsp, 0, sizeof m_spc_dsp ); + + m.noise = 1; + m.echo_hist_pos = m.echo_hist; + m.every_other_sample = 1; + init_counters(); + + int i; + for ( i = spc_dsp_voice_count; --i >= 0; ) + { + voice_t* v = &m_voice_state [i]; + v->regs = &m.regs [i * 0x10]; + v->vbit = 1 << i; + v->brr_offset = 1; + } + + REG(flg) = 0xE0; +} + +void spc_dsp_soft_reset( void ) +{ + // TODO: doesn't reset everything + spc_dsp_reset(); +} + +void spc_dsp_init( void* ram_64k ) +{ + m_ram = (uint8_t*) ram_64k; + spc_dsp_reset(); + + #if INT_MAX < 0x7FFFFFFF + #error "Requires that int have at least 32 bits" + #endif + + #ifndef NDEBUG + // be sure this sign-extends + assert( (int16_t) 0x8000 == -0x8000 ); + + // be sure right shift preserves sign + assert( (-1 >> 1) == -1 ); + + // check clamp macro + int i; + i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); + i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); + #endif +} + +void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] ) +{ + int i; + for ( i = 0; i < 0x80; i++ ) + spc_dsp_write( i, regs [i] ); + m.t_esa = regs [r_esa]; + m.t_dir = regs [r_dir]; +} diff --git a/src/dsp/bdsp_official/spc_dsp.h b/src/dsp/bdsp_official/spc_dsp.h new file mode 100644 index 00000000..e0ba0582 --- /dev/null +++ b/src/dsp/bdsp_official/spc_dsp.h @@ -0,0 +1,162 @@ +// SNES SPC-700 DSP emulator + +#ifndef SPC_DSP_H +#define SPC_DSP_H + +#include +#include + +//// Setup + +// Initializes DSP and has it use the 64K RAM provided +void spc_dsp_init( void* ram_64k ); + +// Restores DSP registers using supplied values +enum { spc_dsp_register_count = 128 }; +void spc_dsp_load( uint8_t const regs [spc_dsp_register_count] ); + +// Mutes voice n if bit 1<