From 3c2ca5a383df3456b7c49ed5349c4e42db0a2779 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 19 Aug 2010 16:54:15 +1000 Subject: [PATCH] Updated to v067r25 release. byuu says: Removed snes_spc, and the fast/smp + fast/dsp wrappers around it. Cloned dsp to fast/dsp, and re-added the state machine, affects Compatibility and Performance cores. Added debugger support to fast/cpu, with full properties list and Qt debugger functionality. Rewrote all debugger property functions to return data directly: - this avoids some annoying conflicts where ChipDebugger::foo() overshadows Chip::foo() - this removes the need for an extra 20-200 functions per debugger core - this makes the overall code size a good bit smaller - this currently makes PPU::oam_basesize() inaccessible, so the OAM viewer will show wrong sprite sizes Used an evil trick to simplify MMIO read/write address decoding: - MMIO *mmio[0x8000], where only 0x2000-5fff are used, allows direct indexing without -0x2000 adjust So end result: both save states and debugger support work on all three cores now. Dual Orb II sound is fixed. The speed hit was worse than I thought, -7% for compatibility, and -10% for performance. At this point, the compatibility core is the exact same code and speed as v067 official, and the performance core is now only ~36-40% faster than the compatibility core. Sigh, so much for my dream of using this on my netbook. At 53fps average now, compared to 39fps before. Profiling will only get that to ~58fps, and that's way too low for the more intensive scenes (Zelda 3 rain, CT black omen, etc.) It would probably be a good idea to find out why my DSP is so much slower than blargg's, given that it's based upon the same code. The simple ring buffer stuff can't possibly slow things down that much. More precisely, it would probably be best to leave blargg's DSP in the performance core since it's a pretty minor issue, but then I'd have to have three DSPs: accuracy=threaded, compatibility=state-machine, performance=blargg. Too much hassle. Only code in the core emulator now that wasn't at the very least rewritten for bsnes would be the DSP-3 and DSP-4 modules, which are really, really lazily done #define hacks around the original C code. --- qt/base/about.cpp | 10 + qt/base/main.cpp | 1 + qt/debugger/ppu/oam-viewer.cpp | 3 +- snes/cpu/debugger/debugger.cpp | 279 ++--- snes/cpu/debugger/debugger.hpp | 73 -- snes/dsp/debugger/debugger.cpp | 108 +- snes/dsp/debugger/debugger.hpp | 33 - snes/fast/cpu/cpu.cpp | 13 +- snes/fast/cpu/cpu.hpp | 14 +- snes/fast/cpu/debugger/debugger.cpp | 155 +++ snes/fast/cpu/debugger/debugger.hpp | 23 + snes/fast/dsp/brr.cpp | 62 + snes/fast/dsp/counter.cpp | 52 + snes/fast/dsp/debugger/debugger.cpp | 53 + snes/fast/dsp/debugger/debugger.hpp | 4 + snes/fast/dsp/dsp.cpp | 310 ++++- snes/fast/dsp/dsp.hpp | 167 ++- snes/fast/dsp/echo.cpp | 135 ++ snes/fast/dsp/envelope.cpp | 62 + snes/fast/dsp/gaussian.cpp | 54 + snes/fast/dsp/misc.cpp | 35 + snes/fast/dsp/serialization.cpp | 80 +- snes/fast/dsp/voice.cpp | 174 +++ snes/fast/ppu/debugger/debugger.cpp | 752 ++++-------- snes/fast/ppu/debugger/debugger.hpp | 244 ---- snes/fast/ppu/debugger/render.cpp | 2 +- snes/fast/smp/iplrom.cpp | 44 - snes/fast/smp/serialization.cpp | 32 - snes/fast/smp/smp.cpp | 87 -- snes/fast/smp/smp.hpp | 30 - snes/fast/snes_spc/SNES_SPC.cpp | 564 --------- snes/fast/snes_spc/SNES_SPC.h | 279 ----- snes/fast/snes_spc/SNES_SPC_misc.cpp | 380 ------ snes/fast/snes_spc/SNES_SPC_state.cpp | 129 -- snes/fast/snes_spc/SPC_CPU.h | 1220 ------------------- snes/fast/snes_spc/SPC_DSP.cpp | 1018 ---------------- snes/fast/snes_spc/SPC_DSP.h | 304 ----- snes/fast/snes_spc/SPC_Filter.cpp | 68 -- snes/fast/snes_spc/SPC_Filter.h | 47 - snes/fast/snes_spc/blargg_common.h | 186 --- snes/fast/snes_spc/blargg_config.h | 24 - snes/fast/snes_spc/blargg_endian.h | 185 --- snes/fast/snes_spc/blargg_source.h | 100 -- snes/fast/snes_spc/dsp.cpp | 48 - snes/fast/snes_spc/dsp.h | 83 -- snes/fast/snes_spc/spc.cpp | 73 -- snes/fast/snes_spc/spc.h | 147 --- snes/memory/memory-inline.hpp | 3 +- snes/memory/memory.cpp | 14 +- snes/memory/memory.hpp | 2 +- snes/ppu/debugger/debugger.cpp | 302 +---- snes/ppu/debugger/debugger.hpp | 240 ---- snes/smp/core/disassembler/disassembler.cpp | 9 +- snes/smp/debugger/debugger.cpp | 61 +- snes/smp/debugger/debugger.hpp | 17 - snes/snes.hpp | 2 +- 56 files changed, 1802 insertions(+), 6794 deletions(-) create mode 100755 snes/fast/cpu/debugger/debugger.cpp create mode 100755 snes/fast/cpu/debugger/debugger.hpp create mode 100755 snes/fast/dsp/brr.cpp create mode 100755 snes/fast/dsp/counter.cpp create mode 100755 snes/fast/dsp/debugger/debugger.cpp create mode 100755 snes/fast/dsp/debugger/debugger.hpp create mode 100755 snes/fast/dsp/echo.cpp create mode 100755 snes/fast/dsp/envelope.cpp create mode 100755 snes/fast/dsp/gaussian.cpp create mode 100755 snes/fast/dsp/misc.cpp create mode 100755 snes/fast/dsp/voice.cpp delete mode 100755 snes/fast/smp/iplrom.cpp delete mode 100755 snes/fast/smp/serialization.cpp delete mode 100755 snes/fast/smp/smp.cpp delete mode 100755 snes/fast/smp/smp.hpp delete mode 100755 snes/fast/snes_spc/SNES_SPC.cpp delete mode 100755 snes/fast/snes_spc/SNES_SPC.h delete mode 100755 snes/fast/snes_spc/SNES_SPC_misc.cpp delete mode 100755 snes/fast/snes_spc/SNES_SPC_state.cpp delete mode 100755 snes/fast/snes_spc/SPC_CPU.h delete mode 100755 snes/fast/snes_spc/SPC_DSP.cpp delete mode 100755 snes/fast/snes_spc/SPC_DSP.h delete mode 100755 snes/fast/snes_spc/SPC_Filter.cpp delete mode 100755 snes/fast/snes_spc/SPC_Filter.h delete mode 100755 snes/fast/snes_spc/blargg_common.h delete mode 100755 snes/fast/snes_spc/blargg_config.h delete mode 100755 snes/fast/snes_spc/blargg_endian.h delete mode 100755 snes/fast/snes_spc/blargg_source.h delete mode 100755 snes/fast/snes_spc/dsp.cpp delete mode 100755 snes/fast/snes_spc/dsp.h delete mode 100755 snes/fast/snes_spc/spc.cpp delete mode 100755 snes/fast/snes_spc/spc.h diff --git a/qt/base/about.cpp b/qt/base/about.cpp index 3edbe859..580ebc3c 100755 --- a/qt/base/about.cpp +++ b/qt/base/about.cpp @@ -7,6 +7,16 @@ AboutWindow::AboutWindow() { setGeometryString(&config().geometry.aboutWindow); application.windowList.append(this); + #if defined(DEBUGGER) + setStyleSheet("background: #e0e0a0"); + #elif defined(PROFILE_ACCURACY) + setStyleSheet("background: #e0a0a0"); + #elif defined(PROFILE_COMPATIBILITY) + setStyleSheet("background: #a0a0e0"); + #elif defined(PROFILE_PERFORMANCE) + setStyleSheet("background: #a0e0a0"); + #endif + layout = new QVBoxLayout; layout->setSizeConstraint(QLayout::SetFixedSize); layout->setMargin(Style::WindowMargin); diff --git a/qt/base/main.cpp b/qt/base/main.cpp index f6318afd..1f7247cd 100755 --- a/qt/base/main.cpp +++ b/qt/base/main.cpp @@ -222,6 +222,7 @@ MainWindow::MainWindow() { QPalette palette; palette.setColor(QPalette::Window, QColor(0, 0, 0)); + canvas->setPalette(palette); canvas->setAutoFillBackground(true); } diff --git a/qt/debugger/ppu/oam-viewer.cpp b/qt/debugger/ppu/oam-viewer.cpp index 86cd000b..09ce00a6 100755 --- a/qt/debugger/ppu/oam-viewer.cpp +++ b/qt/debugger/ppu/oam-viewer.cpp @@ -22,8 +22,9 @@ void OamViewer::refresh() { bool x = d4 & (1 << ((i & 3) << 1)); bool size = d4 & (2 << ((i & 3) << 1)); + //TODO: create method to expose ChipDebugger::property values by name unsigned width, height; - switch(SNES::ppu.oam_base_size()) { default: + switch(0 /*SNES::ppu.oam_base_size()*/) { default: case 0: width = !size ? 8 : 16; height = !size ? 8 : 16; break; case 1: width = !size ? 8 : 32; height = !size ? 8 : 32; break; case 2: width = !size ? 8 : 64; height = !size ? 8 : 64; break; diff --git a/snes/cpu/debugger/debugger.cpp b/snes/cpu/debugger/debugger.cpp index bb014df7..b278d9ab 100755 --- a/snes/cpu/debugger/debugger.cpp +++ b/snes/cpu/debugger/debugger.cpp @@ -1,101 +1,5 @@ #ifdef CPU_CPP -bool CPUDebugger::property(unsigned id, string &name, string &value) { - unsigned n = 0; - - //internal - if(id == n++) { name = "S-CPU MDR"; value = string("0x", strhex<2>(mdr())); return true; } - - //$2181-2183 - if(id == n++) { name = "$2181-$2183"; value = ""; return true; } - if(id == n++) { name = "WRAM Address"; value = string("0x", strhex<6>(wram_address())); return true; } - - //$4016 - if(id == n++) { name = "$4016"; value = ""; return true; } - if(id == n++) { name = "Joypad Strobe Latch"; value = joypad_strobe_latch(); return true; } - - //$4200 - if(id == n++) { name = "$4200"; value = ""; return true; } - if(id == n++) { name = "NMI Enable"; value = nmi_enable(); return true; } - if(id == n++) { name = "H-IRQ Enable"; value = hirq_enable(); return true; } - if(id == n++) { name = "V-IRQ Enable"; value = virq_enable(); return true; } - if(id == n++) { name = "Auto Joypad Poll"; value = auto_joypad_poll(); return true; } - - //$4201 - if(id == n++) { name = "$4201"; value = ""; return true; } - if(id == n++) { name = "PIO"; value = string("0x", strhex<2>(pio_bits())); return true; } - - //$4202 - if(id == n++) { name = "$4202"; value = ""; return true; } - if(id == n++) { name = "Multiplicand"; value = string("0x", strhex<2>(multiplicand())); return true; } - - //$4203 - if(id == n++) { name = "$4203"; value = ""; return true; } - if(id == n++) { name = "Multiplier"; value = string("0x", strhex<2>(multiplier())); return true; } - - //$4204-$4205 - if(id == n++) { name = "$4204-$4205"; value = ""; return true; } - if(id == n++) { name = "Dividend"; value = string("0x", strhex<4>(dividend())); return true; } - - //$4206 - if(id == n++) { name = "$4206"; value = ""; return true; } - if(id == n++) { name = "Divisor"; value = string("0x", strhex<2>(divisor())); return true; } - - //$4207-$4208 - if(id == n++) { name = "$4207-$4208"; value = ""; return true; } - if(id == n++) { name = "H-Time"; value = string("0x", strhex<4>(htime())); return true; } - - //$4209-$420a - if(id == n++) { name = "$4209-$420a"; value = ""; return true; } - if(id == n++) { name = "V-Time"; value = string("0x", strhex<4>(vtime())); return true; } - - //$420b - if(id == n++) { name = "$420b"; value = ""; return true; } - if(id == n++) { name = "DMA Enable"; value = string("0x", strhex<2>(dma_enable())); return true; } - - //$420c - if(id == n++) { name = "$420c"; value = ""; return true; } - if(id == n++) { name = "HDMA Enable"; value = string("0x", strhex<2>(hdma_enable())); return true; } - - //$420d - if(id == n++) { name = "$420d"; value = ""; return true; } - if(id == n++) { name = "FastROM Enable"; value = fastrom_enable(); return true; } - - for(unsigned i = 0; i < 8; i++) { - if(id == n++) { name = string() << "DMA Channel " << i; return true; } - - //$43x0 - if(id == n++) { name = "Direction"; value = dma_direction(i); return true; } - if(id == n++) { name = "Indirect"; value = dma_indirect(i); return true; } - if(id == n++) { name = "Reverse Transfer"; value = dma_reverse_transfer(i); return true; } - if(id == n++) { name = "Fixed Transfer"; value = dma_fixed_transfer(i); return true; } - if(id == n++) { name = "Transfer Mode"; value = dma_transfer_mode(i); return true; } - - //$43x1 - if(id == n++) { name = "B-Bus Address"; value = string("0x", strhex<4>(dma_bbus_address(i))); return true; } - - //$43x2-$43x3 - if(id == n++) { name = "A-Bus Address"; value = string("0x", strhex<4>(dma_abus_address(i))); return true; } - - //$43x4 - if(id == n++) { name = "A-Bus Bank"; value = string("0x", strhex<2>(dma_abus_bank(i))); return true; } - - //$43x5-$43x6 - if(id == n++) { name = "Transfer Size / Indirect Address"; value = string("0x", strhex<4>(dma_transfer_size(i))); return true; } - - //$43x7 - if(id == n++) { name = "Indirect Bank"; value = string("0x", strhex<2>(dma_indirect_bank(i))); return true; } - - //$43x8-$43x9 - if(id == n++) { name = "Table Address"; value = string("0x", strhex<4>(dma_table_address(i))); return true; } - - //$43xa - if(id == n++) { name = "Line Counter"; value = string("0x", strhex<2>(dma_line_counter(i))); return true; } - } - - return false; -} - void CPUDebugger::op_step() { bool break_event = false; @@ -138,89 +42,114 @@ CPUDebugger::~CPUDebugger() { delete[] usage; } -//internal -unsigned CPUDebugger::mdr() { return regs.mdr; } +bool CPUDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; -//$2181-$2183 -unsigned CPUDebugger::wram_address() { return status.wram_addr; } - -//$4016 -bool CPUDebugger::joypad_strobe_latch() { return status.joypad_strobe_latch; } - -//$4200 -bool CPUDebugger::nmi_enable() { return status.nmi_enabled; } -bool CPUDebugger::hirq_enable() { return status.hirq_enabled; } -bool CPUDebugger::virq_enable() { return status.virq_enabled; } -bool CPUDebugger::auto_joypad_poll() { return status.auto_joypad_poll; } - -//$4201 -unsigned CPUDebugger::pio_bits() { return status.pio; } - -//$4202 -unsigned CPUDebugger::multiplicand() { return status.wrmpya; } - -//$4203 -unsigned CPUDebugger::multiplier() { return status.wrmpyb; } - -//$4204-$4205 -unsigned CPUDebugger::dividend() { return status.wrdiva; } - -//$4206 -unsigned CPUDebugger::divisor() { return status.wrdivb; } - -//$4207-$4208 -unsigned CPUDebugger::htime() { return status.hirq_pos; } - -//$4209-$420a -unsigned CPUDebugger::vtime() { return status.virq_pos; } - -//$420b -unsigned CPUDebugger::dma_enable() { - unsigned result = 0; - for(unsigned n = 0; n < 8; n++) { - result |= channel[n].dma_enabled << n; + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ } - return result; -} -//$420c -unsigned CPUDebugger::hdma_enable() { - unsigned result = 0; - for(unsigned n = 0; n < 8; n++) { - result |= channel[n].hdma_enabled << n; + //internal + item("S-CPU MDR", string("0x", strhex<2>(regs.mdr))); + + //$2181-2183 + item("$2181-$2183", ""); + item("WRAM Address", string("0x", strhex<6>(status.wram_addr))); + + //$4016 + item("$4016", ""); + item("Joypad Strobe Latch", status.joypad_strobe_latch); + + //$4200 + item("$4200", ""); + item("NMI Enable", status.nmi_enabled); + item("H-IRQ Enable", status.hirq_enabled); + item("V-IRQ Enable", status.virq_enabled); + item("Auto Joypad Poll", status.auto_joypad_poll); + + //$4201 + item("$4201", ""); + item("PIO", string("0x", strhex<2>(status.pio))); + + //$4202 + item("$4202", ""); + item("Multiplicand", string("0x", strhex<2>(status.wrmpya))); + + //$4203 + item("$4203", ""); + item("Multiplier", string("0x", strhex<2>(status.wrmpyb))); + + //$4204-$4205 + item("$4204-$4205", ""); + item("Dividend", string("0x", strhex<4>(status.wrdiva))); + + //$4206 + item("$4206", ""); + item("Divisor", string("0x", strhex<2>(status.wrdivb))); + + //$4207-$4208 + item("$4207-$4208", ""); + item("H-Time", string("0x", strhex<4>(status.hirq_pos))); + + //$4209-$420a + item("$4209-$420a", ""); + item("V-Time", string("0x", strhex<4>(status.virq_pos))); + + //$420b + unsigned dma_enable = 0; + for(unsigned n = 0; n < 8; n++) dma_enable |= channel[n].dma_enabled << n; + + item("$420b", ""); + item("DMA Enable", string("0x", strhex<2>(dma_enable))); + + //$420c + unsigned hdma_enable = 0; + for(unsigned n = 0; n < 8; n++) hdma_enable |= channel[n].hdma_enabled << n; + + item("$420c", ""); + item("HDMA Enable", string("0x", strhex<2>(hdma_enable))); + + //$420d + item("$420d", ""); + item("FastROM Enable", status.rom_speed == 6); + + for(unsigned i = 0; i < 8; i++) { + item(string("DMA Channel ", i), ""); + + //$43x0 + item("Direction", channel[i].direction); + item("Indirect", channel[i].indirect); + item("Reverse Transfer", channel[i].reverse_transfer); + item("Fixed Transfer", channel[i].fixed_transfer); + item("Transfer Mode", (unsigned)channel[i].transfer_mode); + + //$43x1 + item("B-Bus Address", string("0x", strhex<4>(channel[i].dest_addr))); + + //$43x2-$43x3 + item("A-Bus Address", string("0x", strhex<4>(channel[i].source_addr))); + + //$43x4 + item("A-Bus Bank", string("0x", strhex<2>(channel[i].source_bank))); + + //$43x5-$43x6 + item("Transfer Size / Indirect Address", string("0x", strhex<4>(channel[i].transfer_size))); + + //$43x7 + item("Indirect Bank", string("0x", strhex<2>(channel[i].indirect_bank))); + + //$43x8-$43x9 + item("Table Address", string("0x", strhex<4>(channel[i].hdma_addr))); + + //$43xa + item("Line Counter", string("0x", strhex<2>(channel[i].line_counter))); } - return result; + + #undef item + return false; } -//$420d -bool CPUDebugger::fastrom_enable() { return status.rom_speed; } - -//$43x0 -bool CPUDebugger::dma_direction(unsigned n) { return channel[n].direction; } -bool CPUDebugger::dma_indirect(unsigned n) { return channel[n].hdma_indirect; } -bool CPUDebugger::dma_reverse_transfer(unsigned n) { return channel[n].reversexfer; } -bool CPUDebugger::dma_fixed_transfer(unsigned n) { return channel[n].fixedxfer; } -unsigned CPUDebugger::dma_transfer_mode(unsigned n) { return channel[n].xfermode; } - -//$43x1 -unsigned CPUDebugger::dma_bbus_address(unsigned n) { return 0x2100 + channel[n].destaddr; } - -//$43x2-$43x3 -unsigned CPUDebugger::dma_abus_address(unsigned n) { return channel[n].srcaddr; } - -//$43x4 -unsigned CPUDebugger::dma_abus_bank(unsigned n) { return channel[n].srcbank; } - -//$43x5-$43x6 -unsigned CPUDebugger::dma_transfer_size(unsigned n) { return channel[n].xfersize; } - -//$43x7 -unsigned CPUDebugger::dma_indirect_bank(unsigned n) { return channel[n].hdma_ibank; } - -//$43x8-$43x9 -unsigned CPUDebugger::dma_table_address(unsigned n) { return channel[n].hdma_addr; } - -//$43xa -unsigned CPUDebugger::dma_line_counter(unsigned n) { return channel[n].hdma_line_counter; } - #endif diff --git a/snes/cpu/debugger/debugger.hpp b/snes/cpu/debugger/debugger.hpp index 19d060d7..a74f6015 100755 --- a/snes/cpu/debugger/debugger.hpp +++ b/snes/cpu/debugger/debugger.hpp @@ -20,77 +20,4 @@ public: CPUDebugger(); ~CPUDebugger(); - - //internal - unsigned mdr(); - - //$2181-$2183 - unsigned wram_address(); - - //$4016 - bool joypad_strobe_latch(); - - //$4200 - bool nmi_enable(); - bool hirq_enable(); - bool virq_enable(); - bool auto_joypad_poll(); - - //$4201 - unsigned pio_bits(); - - //$4202 - unsigned multiplicand(); - - //$4203 - unsigned multiplier(); - - //$4204-$4205 - unsigned dividend(); - - //$4206 - unsigned divisor(); - - //$4207-$4208 - unsigned htime(); - - //$4209-$420a - unsigned vtime(); - - //$420b - unsigned dma_enable(); - - //$420c - unsigned hdma_enable(); - - //$420d - bool fastrom_enable(); - - //$43x0 - bool dma_direction(unsigned); - bool dma_indirect(unsigned); - bool dma_reverse_transfer(unsigned); - bool dma_fixed_transfer(unsigned); - unsigned dma_transfer_mode(unsigned); - - //$43x1 - unsigned dma_bbus_address(unsigned); - - //$43x2-$43x3 - unsigned dma_abus_address(unsigned); - - //$43x4 - unsigned dma_abus_bank(unsigned); - - //$43x5-$43x6 - unsigned dma_transfer_size(unsigned); - - //$43x7 - unsigned dma_indirect_bank(unsigned); - - //$43x8-$43x9 - unsigned dma_table_address(unsigned); - - //$43xa - unsigned dma_line_counter(unsigned); }; diff --git a/snes/dsp/debugger/debugger.cpp b/snes/dsp/debugger/debugger.cpp index 9394dd29..72d9d3e2 100755 --- a/snes/dsp/debugger/debugger.cpp +++ b/snes/dsp/debugger/debugger.cpp @@ -3,85 +3,51 @@ bool DSPDebugger::property(unsigned id, string &name, string &value) { unsigned n = 0; - if(id == n++) { name = "Main Volume - Left"; value = main_volume_left(); return true; } - if(id == n++) { name = "Main Volume - Right"; value = main_volume_right(); return true; } - if(id == n++) { name = "Echo Volume - Left"; value = echo_volume_left(); return true; } - if(id == n++) { name = "Echo Volume - Right"; value = echo_volume_right(); return true; } - if(id == n++) { name = "Key On"; value = string("0x", strhex<2>(key_on())); return true; } - if(id == n++) { name = "Key Off"; value = string("0x", strhex<2>(key_off())); return true; } - if(id == n++) { name = "Flag - Reset"; value = flag_reset(); return true; } - if(id == n++) { name = "Flag - Mute"; value = flag_mute(); return true; } - if(id == n++) { name = "Flag - Echo Disable"; value = flag_echo_disable(); return true; } - if(id == n++) { name = "Flag - Noise Clock"; value = flag_noise_clock(); return true; } - if(id == n++) { name = "Source End Block"; value = source_end_block(); return true; } - if(id == n++) { name = "Echo Feedback"; value = echo_feedback(); return true; } - if(id == n++) { name = "Pitch Modulation Enable"; value = string("0x", strhex<2>(pitch_modulation_enable())); return true; } - if(id == n++) { name = "Noise Enable"; value = string("0x", strhex<2>(noise_enable())); return true; } - if(id == n++) { name = "Echo Enable"; value = string("0x", strhex<2>(echo_enable())); return true; } - if(id == n++) { name = "Source Directory"; value = source_directory(); return true; } - if(id == n++) { name = "Echo Start Address"; value = echo_start_address(); return true; } - if(id == n++) { name = "Echo Directory"; value = echo_directory(); return true; } + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + item("Main Volume - Left", (unsigned)state.regs[0x0c]); + item("Main Volume - Right", (unsigned)state.regs[0x1c]); + item("Echo Volume - Left", (unsigned)state.regs[0x2c]); + item("Echo Volume - Right", (unsigned)state.regs[0x3c]); + item("Key On", string("0x", strhex<2>(state.regs[0x4c]))); + item("Key Off", string("0x", strhex<2>(state.regs[0x5c]))); + item("Flag - Reset", (bool)(state.regs[0x6c] & 0x80)); + item("Flag - Mute", (bool)(state.regs[0x6c] & 0x40)); + item("Flag - Echo Disable", (bool)(state.regs[0x6c] & 0x20)); + item("Flag - Noise Clock", (unsigned)state.regs[0x6c] & 0x1f); + item("Source End Block", (unsigned)state.regs[0x7c]); + item("Echo Feedback", (unsigned)state.regs[0x0d]); + item("Pitch Modulation Enable", string("0x", strhex<2>(state.regs[0x2d]))); + item("Noise Enable", string("0x", strhex<2>(state.regs[0x3d]))); + item("Echo Enable", string("0x", strhex<2>(state.regs[0x4d]))); + item("Source Directory", (unsigned)state.regs[0x5d]); + item("Echo Start Address", (unsigned)state.regs[0x6d]); + item("Echo Directory", (unsigned)state.regs[0x7d]); for(unsigned i = 0; i < 8; i++) { - if(id == n++) { - name = string("Coefficient ", i); - value = string("0x", strhex<2>(echo_filter_coefficient(i))); - return true; - } + item(string("Coefficient ", i), string("0x", strhex<2>(state.regs[(i << 4) + 0x0f]))); } for(unsigned i = 0; i < 8; i++) { - if(id == n++) { - name = string("Voice ", i); - value = ""; - return true; - } - - if(id == n++) { name = "Volume - Left"; value = voice_volume_left(i); return true; } - if(id == n++) { name = "Volume - Right"; value = voice_volume_right(i); return true; } - if(id == n++) { name = "Pitch Height"; value = string("0x", strhex<4>(voice_pitch_height(i))); return true; } - if(id == n++) { name = "Source Number"; value = voice_source_number(i); return true; } - if(id == n++) { name = "ADSR1"; value = voice_adsr1(i); return true; } - if(id == n++) { name = "ADSR2"; value = voice_adsr2(i); return true; } - if(id == n++) { name = "GAIN"; value = voice_gain(i); return true; } - if(id == n++) { name = "ENVX"; value = voice_envx(i); return true; } - if(id == n++) { name = "OUTX"; value = voice_outx(i); return true; } + item(string("Voice ", i), ""); + item("Volume - Left", (unsigned)state.regs[(i << 4) + 0x00]); + item("Volume - Right", (unsigned)state.regs[(i << 4) + 0x01]); + item("Pitch Height", string("0x", strhex<4>(state.regs[(i << 4) + 0x02] + (state.regs[(i << 4) + 0x03] << 8)))); + item("Source Number", (unsigned)state.regs[(i << 4) + 0x04]); + item("ADSR1", (unsigned)state.regs[(i << 4) + 0x05]); + item("ADSR2", (unsigned)state.regs[(i << 4) + 0x06]); + item("GAIN", (unsigned)state.regs[(i << 4) + 0x07]); + item("ENVX", (unsigned)state.regs[(i << 4) + 0x08]); + item("OUTX", (unsigned)state.regs[(i << 4) + 0x09]); } + #undef item return false; } -//=========== -//DSPDebugger -//=========== - -unsigned DSPDebugger::main_volume_left() { return state.regs[0x0c]; } -unsigned DSPDebugger::main_volume_right() { return state.regs[0x1c]; } -unsigned DSPDebugger::echo_volume_left() { return state.regs[0x2c]; } -unsigned DSPDebugger::echo_volume_right() { return state.regs[0x3c]; } -unsigned DSPDebugger::key_on() { return state.regs[0x4c]; } -unsigned DSPDebugger::key_off() { return state.regs[0x5c]; } -bool DSPDebugger::flag_reset() { return state.regs[0x6c] & 0x80; } -bool DSPDebugger::flag_mute() { return state.regs[0x6c] & 0x40; } -bool DSPDebugger::flag_echo_disable() { return state.regs[0x6c] & 0x20; } -unsigned DSPDebugger::flag_noise_clock() { return state.regs[0x6c] & 0x1f; } -unsigned DSPDebugger::source_end_block() { return state.regs[0x7c]; } -unsigned DSPDebugger::echo_feedback() { return state.regs[0x0d]; } -unsigned DSPDebugger::pitch_modulation_enable() { return state.regs[0x2d]; } -unsigned DSPDebugger::noise_enable() { return state.regs[0x3d]; } -unsigned DSPDebugger::echo_enable() { return state.regs[0x4d]; } -unsigned DSPDebugger::source_directory() { return state.regs[0x5d]; } -unsigned DSPDebugger::echo_start_address() { return state.regs[0x6d]; } -unsigned DSPDebugger::echo_directory() { return state.regs[0x7d]; } -unsigned DSPDebugger::echo_filter_coefficient(unsigned n) { return state.regs[(n << 4) + 0x0f]; } -unsigned DSPDebugger::voice_volume_left(unsigned n) { return state.regs[(n << 4) + 0x00]; } -unsigned DSPDebugger::voice_volume_right(unsigned n) { return state.regs[(n << 4) + 0x01]; } -unsigned DSPDebugger::voice_pitch_height(unsigned n) { return state.regs[(n << 4) + 0x02] + (state.regs[(n << 4) + 0x03] << 8); } -unsigned DSPDebugger::voice_source_number(unsigned n) { return state.regs[(n << 4) + 0x04]; } -unsigned DSPDebugger::voice_adsr1(unsigned n) { return state.regs[(n << 4) + 0x05]; } -unsigned DSPDebugger::voice_adsr2(unsigned n) { return state.regs[(n << 4) + 0x06]; } -unsigned DSPDebugger::voice_gain(unsigned n) { return state.regs[(n << 4) + 0x07]; } -unsigned DSPDebugger::voice_envx(unsigned n) { return state.regs[(n << 4) + 0x08]; } -unsigned DSPDebugger::voice_outx(unsigned n) { return state.regs[(n << 4) + 0x09]; } - #endif diff --git a/snes/dsp/debugger/debugger.hpp b/snes/dsp/debugger/debugger.hpp index 5946bac9..3339ea3d 100755 --- a/snes/dsp/debugger/debugger.hpp +++ b/snes/dsp/debugger/debugger.hpp @@ -1,37 +1,4 @@ class DSPDebugger : public DSP, public ChipDebugger { public: bool property(unsigned id, string &name, string &value); - - //=========== - //DSPDebugger - //=========== - - unsigned main_volume_left(); - unsigned main_volume_right(); - unsigned echo_volume_left(); - unsigned echo_volume_right(); - unsigned key_on(); - unsigned key_off(); - bool flag_reset(); - bool flag_mute(); - bool flag_echo_disable(); - unsigned flag_noise_clock(); - unsigned source_end_block(); - unsigned echo_feedback(); - unsigned pitch_modulation_enable(); - unsigned noise_enable(); - unsigned echo_enable(); - unsigned source_directory(); - unsigned echo_start_address(); - unsigned echo_directory(); - unsigned echo_filter_coefficient(unsigned); - unsigned voice_volume_left(unsigned); - unsigned voice_volume_right(unsigned); - unsigned voice_pitch_height(unsigned); - unsigned voice_source_number(unsigned); - unsigned voice_adsr1(unsigned); - unsigned voice_adsr2(unsigned); - unsigned voice_gain(unsigned); - unsigned voice_envx(unsigned); - unsigned voice_outx(unsigned); }; diff --git a/snes/fast/cpu/cpu.cpp b/snes/fast/cpu/cpu.cpp index b6b5790b..6f4f9ca0 100755 --- a/snes/fast/cpu/cpu.cpp +++ b/snes/fast/cpu/cpu.cpp @@ -3,7 +3,12 @@ #define CPU_CPP namespace SNES { -CPU cpu; +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + CPUDebugger cpu; +#else + CPU cpu; +#endif #include "serialization.cpp" #include "dma.cpp" @@ -62,10 +67,14 @@ void CPU::enter() { op_irq(regs.e == false ? 0xffee : 0xfffe); } - (this->*opcode_table[op_readpc()])(); + op_step(); } } +alwaysinline void CPU::op_step() { + (this->*opcode_table[op_readpc()])(); +} + void CPU::op_irq(uint16 vector) { op_read(regs.pc.d); op_io(); diff --git a/snes/fast/cpu/cpu.hpp b/snes/fast/cpu/cpu.hpp index 45cf9cac..7e9aa794 100755 --- a/snes/fast/cpu/cpu.hpp +++ b/snes/fast/cpu/cpu.hpp @@ -16,8 +16,8 @@ public: void mmio_write(unsigned addr, uint8 data); void op_io(); - uint8 op_read(unsigned addr); - void op_write(unsigned addr, uint8 data); + debugvirtual uint8 op_read(unsigned addr); + debugvirtual void op_write(unsigned addr, uint8 data); void enter(); void power(); @@ -30,6 +30,7 @@ public: private: //cpu static void Enter(); + void op_step(); void op_irq(uint16 vector); //timing @@ -142,6 +143,13 @@ private: uint8 joy3l, joy3h; uint8 joy4l, joy4h; } status; + + friend class CPUDebugger; }; -extern CPU cpu; +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern CPUDebugger cpu; +#else + extern CPU cpu; +#endif diff --git a/snes/fast/cpu/debugger/debugger.cpp b/snes/fast/cpu/debugger/debugger.cpp new file mode 100755 index 00000000..dae1b415 --- /dev/null +++ b/snes/fast/cpu/debugger/debugger.cpp @@ -0,0 +1,155 @@ +#ifdef CPU_CPP + +void CPUDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] &= ~(UsageFlagM | UsageFlagX); + usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0); + opcode_pc = regs.pc; + + if(debugger.step_cpu) { + debugger.break_event = Debugger::BreakEvent::CPUStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } else { + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + } + + if(step_event) step_event(); + CPU::op_step(); + synchronize_smp(); +} + +uint8 CPUDebugger::op_read(uint32 addr) { + uint8 data = CPU::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void CPUDebugger::op_write(uint32 addr, uint8 data) { + CPU::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Write, addr, data); +} + +CPUDebugger::CPUDebugger() { + usage = new uint8[1 << 24](); + opcode_pc = 0x8000; +} + +CPUDebugger::~CPUDebugger() { + delete[] usage; +} + +bool CPUDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //internal + item("S-CPU MDR", string("0x", strhex<2>(regs.mdr))); + + //$2181-2183 + item("$2181-$2183", ""); + item("WRAM Address", string("0x", strhex<6>(status.wram_addr))); + + //$4016 + item("$4016", ""); + item("Joypad Strobe Latch", status.joypad_strobe_latch); + + //$4200 + item("$4200", ""); + item("NMI Enable", status.nmi_enabled); + item("H-IRQ Enable", status.hirq_enabled); + item("V-IRQ Enable", status.virq_enabled); + item("Auto Joypad Poll", status.auto_joypad_poll_enabled); + + //$4201 + item("$4201", ""); + item("PIO", string("0x", strhex<2>(status.pio))); + + //$4202 + item("$4202", ""); + item("Multiplicand", string("0x", strhex<2>(status.wrmpya))); + + //$4203 + item("$4203", ""); + item("Multiplier", string("0x", strhex<2>(status.wrmpyb))); + + //$4204-$4205 + item("$4204-$4205", ""); + item("Dividend", string("0x", strhex<4>(status.wrdiva))); + + //$4206 + item("$4206", ""); + item("Divisor", string("0x", strhex<2>(status.wrdivb))); + + //$4207-$4208 + item("$4207-$4208", ""); + item("H-Time", string("0x", strhex<4>(status.htime))); + + //$4209-$420a + item("$4209-$420a", ""); + item("V-Time", string("0x", strhex<4>(status.vtime))); + + //$420b + unsigned dma_enable = 0; + for(unsigned n = 0; n < 8; n++) dma_enable |= channel[n].dma_enabled << n; + + item("$420b", ""); + item("DMA Enable", string("0x", strhex<2>(dma_enable))); + + //$420c + unsigned hdma_enable = 0; + for(unsigned n = 0; n < 8; n++) hdma_enable |= channel[n].hdma_enabled << n; + + item("$420c", ""); + item("HDMA Enable", string("0x", strhex<2>(hdma_enable))); + + //$420d + item("$420d", ""); + item("FastROM Enable", status.rom_speed == 6); + + for(unsigned i = 0; i < 8; i++) { + item(string("DMA Channel ", i), ""); + + //$43x0 + item("Direction", channel[i].direction); + item("Indirect", channel[i].indirect); + item("Reverse Transfer", channel[i].reverse_transfer); + item("Fixed Transfer", channel[i].fixed_transfer); + item("Transfer Mode", (unsigned)channel[i].transfer_mode); + + //$43x1 + item("B-Bus Address", string("0x", strhex<4>(channel[i].dest_addr))); + + //$43x2-$43x3 + item("A-Bus Address", string("0x", strhex<4>(channel[i].source_addr))); + + //$43x4 + item("A-Bus Bank", string("0x", strhex<2>(channel[i].source_bank))); + + //$43x5-$43x6 + item("Transfer Size / Indirect Address", string("0x", strhex<4>(channel[i].transfer_size))); + + //$43x7 + item("Indirect Bank", string("0x", strhex<2>(channel[i].indirect_bank))); + + //$43x8-$43x9 + item("Table Address", string("0x", strhex<4>(channel[i].hdma_addr))); + + //$43xa + item("Line Counter", string("0x", strhex<2>(channel[i].line_counter))); + } + + #undef item + return false; +} + +#endif diff --git a/snes/fast/cpu/debugger/debugger.hpp b/snes/fast/cpu/debugger/debugger.hpp new file mode 100755 index 00000000..a74f6015 --- /dev/null +++ b/snes/fast/cpu/debugger/debugger.hpp @@ -0,0 +1,23 @@ +class CPUDebugger : public CPU, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + UsageFlagM = 0x02, + UsageFlagX = 0x01, + }; + uint8 *usage; + uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints + + void op_step(); + uint8 op_read(uint32 addr); + void op_write(uint32 addr, uint8 data); + + CPUDebugger(); + ~CPUDebugger(); +}; diff --git a/snes/fast/dsp/brr.cpp b/snes/fast/dsp/brr.cpp new file mode 100755 index 00000000..abdf2a0d --- /dev/null +++ b/snes/fast/dsp/brr.cpp @@ -0,0 +1,62 @@ +#ifdef DSP_CPP + +void DSP::brr_decode(voice_t &v) { + //state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle + int nybbles = (state.t_brr_byte << 8) + memory::apuram[(uint16)(v.brr_addr + v.brr_offset + 1)]; + + const int filter = (state.t_brr_header >> 2) & 3; + const int scale = (state.t_brr_header >> 4); + + //decode four samples + for(unsigned i = 0; i < 4; i++) { + //bits 12-15 = current nybble; sign extend, then shift right to 4-bit precision + //result: s = 4-bit sign-extended sample value + int s = (int16)nybbles >> 12; + nybbles <<= 4; //slide nybble so that on next loop iteration, bits 12-15 = current nybble + + if(scale <= 12) { + s <<= scale; + s >>= 1; + } else { + s &= ~0x7ff; + } + + //apply IIR filter (2 is the most commonly used) + const int p1 = v.buffer[v.buf_pos - 1]; + const int p2 = v.buffer[v.buf_pos - 2] >> 1; + + switch(filter) { + case 0: break; //no filter + + case 1: { + //s += p1 * 0.46875 + s += p1 >> 1; + s += (-p1) >> 5; + } break; + + case 2: { + //s += p1 * 0.953125 - p2 * 0.46875 + s += p1; + s -= p2; + s += p2 >> 4; + s += (p1 * -3) >> 6; + } break; + + case 3: { + //s += p1 * 0.8984375 - p2 * 0.40625 + s += p1; + s -= p2; + s += (p1 * -13) >> 7; + s += (p2 * 3) >> 4; + } break; + } + + //adjust and write sample + s = sclamp<16>(s); + s = (int16)(s << 1); + v.buffer.write(v.buf_pos++, s); + if(v.buf_pos >= brr_buf_size) v.buf_pos = 0; + } +} + +#endif diff --git a/snes/fast/dsp/counter.cpp b/snes/fast/dsp/counter.cpp new file mode 100755 index 00000000..f65fdd26 --- /dev/null +++ b/snes/fast/dsp/counter.cpp @@ -0,0 +1,52 @@ +#ifdef DSP_CPP + +//counter_rate = number of samples per counter event +//all rates are evenly divisible by counter_range (0x7800, 30720, or 2048 * 5 * 3) +//note that rate[0] is a special case, which never triggers + +const uint16 DSP::counter_rate[32] = { + 0, 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, +}; + +//counter_offset = counter offset from zero +//counters do not appear to be aligned at zero for all rates + +const uint16 DSP::counter_offset[32] = { + 0, 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 void DSP::counter_tick() { + state.counter--; + if(state.counter < 0) state.counter = counter_range - 1; +} + +//return true if counter event should trigger + +inline bool DSP::counter_poll(unsigned rate) { + if(rate == 0) return false; + return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0; +} + +#endif diff --git a/snes/fast/dsp/debugger/debugger.cpp b/snes/fast/dsp/debugger/debugger.cpp new file mode 100755 index 00000000..72d9d3e2 --- /dev/null +++ b/snes/fast/dsp/debugger/debugger.cpp @@ -0,0 +1,53 @@ +#ifdef DSP_CPP + +bool DSPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + item("Main Volume - Left", (unsigned)state.regs[0x0c]); + item("Main Volume - Right", (unsigned)state.regs[0x1c]); + item("Echo Volume - Left", (unsigned)state.regs[0x2c]); + item("Echo Volume - Right", (unsigned)state.regs[0x3c]); + item("Key On", string("0x", strhex<2>(state.regs[0x4c]))); + item("Key Off", string("0x", strhex<2>(state.regs[0x5c]))); + item("Flag - Reset", (bool)(state.regs[0x6c] & 0x80)); + item("Flag - Mute", (bool)(state.regs[0x6c] & 0x40)); + item("Flag - Echo Disable", (bool)(state.regs[0x6c] & 0x20)); + item("Flag - Noise Clock", (unsigned)state.regs[0x6c] & 0x1f); + item("Source End Block", (unsigned)state.regs[0x7c]); + item("Echo Feedback", (unsigned)state.regs[0x0d]); + item("Pitch Modulation Enable", string("0x", strhex<2>(state.regs[0x2d]))); + item("Noise Enable", string("0x", strhex<2>(state.regs[0x3d]))); + item("Echo Enable", string("0x", strhex<2>(state.regs[0x4d]))); + item("Source Directory", (unsigned)state.regs[0x5d]); + item("Echo Start Address", (unsigned)state.regs[0x6d]); + item("Echo Directory", (unsigned)state.regs[0x7d]); + + for(unsigned i = 0; i < 8; i++) { + item(string("Coefficient ", i), string("0x", strhex<2>(state.regs[(i << 4) + 0x0f]))); + } + + for(unsigned i = 0; i < 8; i++) { + item(string("Voice ", i), ""); + item("Volume - Left", (unsigned)state.regs[(i << 4) + 0x00]); + item("Volume - Right", (unsigned)state.regs[(i << 4) + 0x01]); + item("Pitch Height", string("0x", strhex<4>(state.regs[(i << 4) + 0x02] + (state.regs[(i << 4) + 0x03] << 8)))); + item("Source Number", (unsigned)state.regs[(i << 4) + 0x04]); + item("ADSR1", (unsigned)state.regs[(i << 4) + 0x05]); + item("ADSR2", (unsigned)state.regs[(i << 4) + 0x06]); + item("GAIN", (unsigned)state.regs[(i << 4) + 0x07]); + item("ENVX", (unsigned)state.regs[(i << 4) + 0x08]); + item("OUTX", (unsigned)state.regs[(i << 4) + 0x09]); + } + + #undef item + return false; +} + +#endif diff --git a/snes/fast/dsp/debugger/debugger.hpp b/snes/fast/dsp/debugger/debugger.hpp new file mode 100755 index 00000000..3339ea3d --- /dev/null +++ b/snes/fast/dsp/debugger/debugger.hpp @@ -0,0 +1,4 @@ +class DSPDebugger : public DSP, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); +}; diff --git a/snes/fast/dsp/dsp.cpp b/snes/fast/dsp/dsp.cpp index 3c18b714..fe35bbbe 100755 --- a/snes/fast/dsp/dsp.cpp +++ b/snes/fast/dsp/dsp.cpp @@ -3,12 +3,28 @@ #define DSP_CPP namespace SNES { -DSP dsp; - -#include "../snes_spc/SPC_DSP.cpp" +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + DSPDebugger dsp; +#else + DSP dsp; +#endif #include "serialization.cpp" +#define REG(n) state.regs[r_##n] +#define VREG(n) state.regs[v.vidx + v_##n] + +#include "gaussian.cpp" +#include "counter.cpp" +#include "envelope.cpp" +#include "brr.cpp" +#include "misc.cpp" +#include "voice.cpp" +#include "echo.cpp" + +/* timing */ + void DSP::step(unsigned clocks) { clock += clocks; } @@ -21,36 +37,298 @@ void DSP::synchronize_smp() { } } -void DSP::enter() { - spc_dsp.run(1); - step(24); +void DSP::Enter() { dsp.enter(); } - signed count = spc_dsp.sample_count(); - if(count > 0) { - for(unsigned n = 0; n < count; n += 2) audio.sample(samplebuffer[n + 0], samplebuffer[n + 1]); - spc_dsp.set_output(samplebuffer, 8192); +void DSP::enter() { + switch(phase) { + case 0: + voice_5(voice[0]); + voice_2(voice[1]); + return tick(); + + case 1: + voice_6(voice[0]); + voice_3(voice[1]); + return tick(); + + case 2: + voice_7(voice[0]); + voice_4(voice[1]); + voice_1(voice[3]); + return tick(); + + case 3: + voice_8(voice[0]); + voice_5(voice[1]); + voice_2(voice[2]); + return tick(); + + case 4: + voice_9(voice[0]); + voice_6(voice[1]); + voice_3(voice[2]); + return tick(); + + case 5: + voice_7(voice[1]); + voice_4(voice[2]); + voice_1(voice[4]); + return tick(); + + case 6: + voice_8(voice[1]); + voice_5(voice[2]); + voice_2(voice[3]); + return tick(); + + case 7: + voice_9(voice[1]); + voice_6(voice[2]); + voice_3(voice[3]); + return tick(); + + case 8: + voice_7(voice[2]); + voice_4(voice[3]); + voice_1(voice[5]); + return tick(); + + case 9: + voice_8(voice[2]); + voice_5(voice[3]); + voice_2(voice[4]); + return tick(); + + case 10: + voice_9(voice[2]); + voice_6(voice[3]); + voice_3(voice[4]); + return tick(); + + case 11: + voice_7(voice[3]); + voice_4(voice[4]); + voice_1(voice[6]); + return tick(); + + case 12: + voice_8(voice[3]); + voice_5(voice[4]); + voice_2(voice[5]); + return tick(); + + case 13: + voice_9(voice[3]); + voice_6(voice[4]); + voice_3(voice[5]); + return tick(); + + case 14: + voice_7(voice[4]); + voice_4(voice[5]); + voice_1(voice[7]); + return tick(); + + case 15: + voice_8(voice[4]); + voice_5(voice[5]); + voice_2(voice[6]); + return tick(); + + case 16: + voice_9(voice[4]); + voice_6(voice[5]); + voice_3(voice[6]); + return tick(); + + case 17: + voice_1(voice[0]); + voice_7(voice[5]); + voice_4(voice[6]); + return tick(); + + case 18: + voice_8(voice[5]); + voice_5(voice[6]); + voice_2(voice[7]); + return tick(); + + case 19: + voice_9(voice[5]); + voice_6(voice[6]); + voice_3(voice[7]); + return tick(); + + case 20: + voice_1(voice[1]); + voice_7(voice[6]); + voice_4(voice[7]); + return tick(); + + case 21: + voice_8(voice[6]); + voice_5(voice[7]); + voice_2(voice[0]); + return tick(); + + case 22: + voice_3a(voice[0]); + voice_9(voice[6]); + voice_6(voice[7]); + echo_22(); + return tick(); + + case 23: + voice_7(voice[7]); + echo_23(); + return tick(); + + case 24: + voice_8(voice[7]); + echo_24(); + return tick(); + + case 25: + voice_3b(voice[0]); + voice_9(voice[7]); + echo_25(); + return tick(); + + case 26: + echo_26(); + return tick(); + + case 27: + misc_27(); + echo_27(); + return tick(); + + case 28: + misc_28(); + echo_28(); + return tick(); + + case 29: + misc_29(); + echo_29(); + return tick(); + + case 30: + misc_30(); + voice_3c(voice[0]); + echo_30(); + return tick(); + + case 31: + voice_4(voice[0]); + voice_1(voice[2]); + return tick(); } } +void DSP::tick() { + step(3 * 8); + synchronize_smp(); + phase = (phase + 1) & 31; +} + +/* register interface for S-SMP $00f2,$00f3 */ + uint8 DSP::read(uint8 addr) { - return spc_dsp.read(addr); + return state.regs[addr]; } void DSP::write(uint8 addr, uint8 data) { - spc_dsp.write(addr, data); + state.regs[addr] = data; + + if((addr & 0x0f) == v_envx) { + state.envx_buf = data; + } else if((addr & 0x0f) == v_outx) { + state.outx_buf = data; + } else if(addr == r_kon) { + state.new_kon = data; + } else if(addr == r_endx) { + //always cleared, regardless of data written + state.endx_buf = 0; + state.regs[r_endx] = 0; + } } +/* initialization */ + void DSP::power() { - spc_dsp.init(memory::apuram.data()); - spc_dsp.reset(); + memset(&state.regs, 0, sizeof state.regs); + state.echo_hist_pos = 0; + state.every_other_sample = false; + state.kon = 0; + state.noise = 0; + state.counter = 0; + state.echo_offset = 0; + state.echo_length = 0; + state.new_kon = 0; + state.endx_buf = 0; + state.envx_buf = 0; + state.outx_buf = 0; + state.t_pmon = 0; + state.t_non = 0; + state.t_eon = 0; + state.t_dir = 0; + state.t_koff = 0; + state.t_brr_next_addr = 0; + state.t_adsr0 = 0; + state.t_brr_header = 0; + state.t_brr_byte = 0; + state.t_srcn = 0; + state.t_esa = 0; + state.t_echo_disabled = 0; + state.t_dir_addr = 0; + state.t_pitch = 0; + state.t_output = 0; + state.t_looped = 0; + state.t_echo_ptr = 0; + state.t_main_out[0] = state.t_main_out[1] = 0; + state.t_echo_out[0] = state.t_echo_out[1] = 0; + state.t_echo_in[0] = state.t_echo_in[1] = 0; + + for(unsigned i = 0; i < 8; i++) { + voice[i].buf_pos = 0; + voice[i].interp_pos = 0; + voice[i].brr_addr = 0; + voice[i].brr_offset = 1; + voice[i].vbit = 1 << i; + voice[i].vidx = i * 0x10; + voice[i].kon_delay = 0; + voice[i].env_mode = env_release; + voice[i].env = 0; + voice[i].t_envx_out = 0; + voice[i].hidden_env = 0; + } + + reset(); } void DSP::reset() { - spc_dsp.soft_reset(); - spc_dsp.set_output(samplebuffer, 8192); + create(Enter, system.apu_frequency()); + + REG(flg) = 0xe0; + + state.noise = 0x4000; + state.echo_hist_pos = 0; + state.every_other_sample = 1; + state.echo_offset = 0; + state.counter = 0; } DSP::DSP() { + static_assert(sizeof(int) >= 32 / 8, "int >= 32-bits"); + static_assert((int8)0x80 == -0x80, "8-bit sign extension"); + static_assert((int16)0x8000 == -0x8000, "16-bit sign extension"); + static_assert((uint16)0xffff0000 == 0, "16-bit unsigned clip"); + static_assert((-1 >> 1) == -1, "arithmetic shift right"); + + //-0x8000 <= n <= +0x7fff + assert(sclamp<16>(+0x8000) == +0x7fff); + assert(sclamp<16>(-0x8001) == -0x8000); } DSP::~DSP() { diff --git a/snes/fast/dsp/dsp.hpp b/snes/fast/dsp/dsp.hpp index b8992d6b..581a0e48 100755 --- a/snes/fast/dsp/dsp.hpp +++ b/snes/fast/dsp/dsp.hpp @@ -1,5 +1,3 @@ -#include "../snes_spc/SPC_DSP.h" - class DSP : public Processor { public: enum : bool { Threaded = false }; @@ -18,8 +16,167 @@ public: ~DSP(); private: - SPC_DSP spc_dsp; - int16 samplebuffer[8192]; + unsigned phase; + + //global registers + enum global_reg_t { + 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 voice_reg_t { + 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 constants + enum { echo_hist_size = 8 }; + enum { brr_buf_size = 12 }; + enum { brr_block_size = 9 }; + + //global state + struct state_t { + uint8 regs[128]; + + modulo_array echo_hist[2]; //echo history keeps most recent 8 samples + int echo_hist_pos; + + bool 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; + int endx_buf; + int envx_buf; + int 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 before used + int t_brr_next_addr; + int t_adsr0; + int t_brr_header; + int t_brr_byte; + int t_srcn; + int t_esa; + int t_echo_disabled; + + //internal state that is recalculated every sample + int t_dir_addr; + int t_pitch; + int t_output; + int t_looped; + int t_echo_ptr; + + //left/right sums + int t_main_out[2]; + int t_echo_out[2]; + int t_echo_in [2]; + } state; + + //voice state + struct voice_t { + modulo_array buffer; //decoded samples + 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 + int vbit; //bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc + int vidx; //voice channel register index: 0x00 for voice 0, 0x10 for voice 1, etc + int kon_delay; //KON delay/current setup phase + int env_mode; + int env; //current envelope level + int t_envx_out; + int hidden_env; //used by GAIN mode 7, very obscure quirk + } voice[8]; + + //gaussian + static const int16 gaussian_table[512]; + int gaussian_interpolate(const voice_t &v); + + //counter + enum { counter_range = 2048 * 5 * 3 }; //30720 (0x7800) + static const uint16 counter_rate[32]; + static const uint16 counter_offset[32]; + void counter_tick(); + bool counter_poll(unsigned rate); + + //envelope + void envelope_run(voice_t &v); + + //brr + void brr_decode(voice_t &v); + + //misc + void misc_27(); + void misc_28(); + void misc_29(); + void misc_30(); + + //voice + void voice_output(voice_t &v, bool channel); + void voice_1 (voice_t &v); + void voice_2 (voice_t &v); + void voice_3 (voice_t &v); + void voice_3a(voice_t &v); + void voice_3b(voice_t &v); + void voice_3c(voice_t &v); + void voice_4 (voice_t &v); + void voice_5 (voice_t &v); + void voice_6 (voice_t &v); + void voice_7 (voice_t &v); + void voice_8 (voice_t &v); + void voice_9 (voice_t &v); + + //echo + int calc_fir(int i, bool channel); + int echo_output(bool channel); + void echo_read(bool channel); + void echo_write(bool channel); + void echo_22(); + void echo_23(); + void echo_24(); + void echo_25(); + void echo_26(); + void echo_27(); + void echo_28(); + void echo_29(); + void echo_30(); + + //dsp + static void Enter(); + alwaysinline void tick(); + + friend class DSPDebugger; }; -extern DSP dsp; +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern DSPDebugger dsp; +#else + extern DSP dsp; +#endif diff --git a/snes/fast/dsp/echo.cpp b/snes/fast/dsp/echo.cpp new file mode 100755 index 00000000..c0cf5f37 --- /dev/null +++ b/snes/fast/dsp/echo.cpp @@ -0,0 +1,135 @@ +#ifdef DSP_CPP + +int DSP::calc_fir(int i, bool channel) { + int s = state.echo_hist[channel][state.echo_hist_pos + i + 1]; + return (s * (int8)REG(fir + i * 0x10)) >> 6; +} + +int DSP::echo_output(bool channel) { + int output = (int16)((state.t_main_out[channel] * (int8)REG(mvoll + channel * 0x10)) >> 7) + + (int16)((state.t_echo_in [channel] * (int8)REG(evoll + channel * 0x10)) >> 7); + return sclamp<16>(output); +} + +void DSP::echo_read(bool channel) { + unsigned addr = state.t_echo_ptr + channel * 2; + uint8 lo = memory::apuram[(uint16)(addr + 0)]; + uint8 hi = memory::apuram[(uint16)(addr + 1)]; + int s = (int16)((hi << 8) + lo); + state.echo_hist[channel].write(state.echo_hist_pos, s >> 1); +} + +void DSP::echo_write(bool channel) { + if(!(state.t_echo_disabled & 0x20)) { + unsigned addr = state.t_echo_ptr + channel * 2; + int s = state.t_echo_out[channel]; + memory::apuram[(uint16)(addr + 0)] = s; + memory::apuram[(uint16)(addr + 1)] = s >> 8; + } + + state.t_echo_out[channel] = 0; +} + +void DSP::echo_22() { + //history + state.echo_hist_pos++; + if(state.echo_hist_pos >= echo_hist_size) state.echo_hist_pos = 0; + + state.t_echo_ptr = (uint16)((state.t_esa << 8) + state.echo_offset); + echo_read(0); + + //FIR + int l = calc_fir(0, 0); + int r = calc_fir(0, 1); + + state.t_echo_in[0] = l; + state.t_echo_in[1] = r; +} + +void DSP::echo_23() { + int l = calc_fir(1, 0) + calc_fir(2, 0); + int r = calc_fir(1, 1) + calc_fir(2, 1); + + state.t_echo_in[0] += l; + state.t_echo_in[1] += r; + + echo_read(1); +} + +void DSP::echo_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); + + state.t_echo_in[0] += l; + state.t_echo_in[1] += r; +} + +void DSP::echo_25() { + int l = state.t_echo_in[0] + calc_fir(6, 0); + int r = state.t_echo_in[1] + calc_fir(6, 1); + + l = (int16)l; + r = (int16)r; + + l += (int16)calc_fir(7, 0); + r += (int16)calc_fir(7, 1); + + state.t_echo_in[0] = sclamp<16>(l) & ~1; + state.t_echo_in[1] = sclamp<16>(r) & ~1; +} + +void DSP::echo_26() { + //left output volumes + //(save sample for next clock so we can output both together) + state.t_main_out[0] = echo_output(0); + + //echo feedback + int l = state.t_echo_out[0] + (int16)((state.t_echo_in[0] * (int8)REG(efb)) >> 7); + int r = state.t_echo_out[1] + (int16)((state.t_echo_in[1] * (int8)REG(efb)) >> 7); + + state.t_echo_out[0] = sclamp<16>(l) & ~1; + state.t_echo_out[1] = sclamp<16>(r) & ~1; +} + +void DSP::echo_27() { + //output + int outl = state.t_main_out[0]; + int outr = echo_output(1); + state.t_main_out[0] = 0; + state.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 + audio.sample(outl, outr); +} + +void DSP::echo_28() { + state.t_echo_disabled = REG(flg); +} + +void DSP::echo_29() { + state.t_esa = REG(esa); + + if(!state.echo_offset) state.echo_length = (REG(edl) & 0x0f) << 11; + + state.echo_offset += 4; + if(state.echo_offset >= state.echo_length) state.echo_offset = 0; + + //write left echo + echo_write(0); + + state.t_echo_disabled = REG(flg); +} + +void DSP::echo_30() { + //write right echo + echo_write(1); +} + +#endif diff --git a/snes/fast/dsp/envelope.cpp b/snes/fast/dsp/envelope.cpp new file mode 100755 index 00000000..9ae0d3e0 --- /dev/null +++ b/snes/fast/dsp/envelope.cpp @@ -0,0 +1,62 @@ +#ifdef DSP_CPP + +void DSP::envelope_run(voice_t &v) { + int env = v.env; + + if(v.env_mode == env_release) { //60% + env -= 0x8; + if(env < 0) env = 0; + v.env = env; + return; + } + + int rate; + int env_data = VREG(adsr1); + if(state.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 = ((state.t_adsr0 >> 3) & 0x0e) + 0x10; + } + } else { //env_attack + rate = ((state.t_adsr0 & 0x0f) << 1) + 1; + env += rate < 31 ? 0x20 : 0x400; + } + } else { //GAIN + env_data = VREG(gain); + int mode = env_data >> 5; + if(mode < 4) { //direct + env = env_data << 4; + 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 underflowing also triggers this + if((unsigned)env > 0x7ff) { + env = (env < 0 ? 0 : 0x7ff); + if(v.env_mode == env_attack) v.env_mode = env_decay; + } + + if(counter_poll(rate) == true) v.env = env; +} + +#endif diff --git a/snes/fast/dsp/gaussian.cpp b/snes/fast/dsp/gaussian.cpp new file mode 100755 index 00000000..80aed8ad --- /dev/null +++ b/snes/fast/dsp/gaussian.cpp @@ -0,0 +1,54 @@ +#ifdef DSP_CPP + +const int16 DSP::gaussian_table[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, +}; + +int DSP::gaussian_interpolate(const voice_t &v) { + //make pointers into gaussian table based on fractional position between samples + int offset = (v.interp_pos >> 4) & 0xff; + const int16 *fwd = gaussian_table + 255 - offset; + const int16 *rev = gaussian_table + offset; //mirror left half of gaussian table + + offset = v.buf_pos + (v.interp_pos >> 12); + int output; + output = (fwd[ 0] * v.buffer[offset + 0]) >> 11; + output += (fwd[256] * v.buffer[offset + 1]) >> 11; + output += (rev[256] * v.buffer[offset + 2]) >> 11; + output = (int16)output; + output += (rev[ 0] * v.buffer[offset + 3]) >> 11; + return sclamp<16>(output) & ~1; +} + +#endif diff --git a/snes/fast/dsp/misc.cpp b/snes/fast/dsp/misc.cpp new file mode 100755 index 00000000..244fc51f --- /dev/null +++ b/snes/fast/dsp/misc.cpp @@ -0,0 +1,35 @@ +#ifdef DSP_CPP + +void DSP::misc_27() { + state.t_pmon = REG(pmon) & ~1; //voice 0 doesn't support PMON +} + +void DSP::misc_28() { + state.t_non = REG(non); + state.t_eon = REG(eon); + state.t_dir = REG(dir); +} + +void DSP::misc_29() { + state.every_other_sample ^= 1; + if(state.every_other_sample) { + state.new_kon &= ~state.kon; //clears KON 63 clocks after it was last read + } +} + +void DSP::misc_30() { + if(state.every_other_sample) { + state.kon = state.new_kon; + state.t_koff = REG(koff); + } + + counter_tick(); + + //noise + if(counter_poll(REG(flg) & 0x1f) == true) { + int feedback = (state.noise << 13) ^ (state.noise << 14); + state.noise = (feedback & 0x4000) ^ (state.noise >> 1); + } +} + +#endif diff --git a/snes/fast/dsp/serialization.cpp b/snes/fast/dsp/serialization.cpp index 0565a1b5..62b3acdf 100755 --- a/snes/fast/dsp/serialization.cpp +++ b/snes/fast/dsp/serialization.cpp @@ -1,30 +1,66 @@ #ifdef DSP_CPP -static void dsp_state_save(unsigned char **out, void *in, size_t size) { - memcpy(*out, in, size); - *out += size; -} - -static void dsp_state_load(unsigned char **in, void *out, size_t size) { - memcpy(out, *in, size); - *in += size; -} - void DSP::serialize(serializer &s) { Processor::serialize(s); - s.array(samplebuffer); + s.integer(phase); - unsigned char state[SPC_DSP::state_size]; - unsigned char *p = state; - memset(&state, 0, SPC_DSP::state_size); - if(s.mode() == serializer::Save) { - spc_dsp.copy_state(&p, dsp_state_save); - s.array(state); - } else if(s.mode() == serializer::Load) { - s.array(state); - spc_dsp.copy_state(&p, dsp_state_load); - } else { - s.array(state); + s.array(state.regs, 128); + state.echo_hist[0].serialize(s); + state.echo_hist[1].serialize(s); + s.integer(state.echo_hist_pos); + + s.integer(state.every_other_sample); + s.integer(state.kon); + s.integer(state.noise); + s.integer(state.counter); + s.integer(state.echo_offset); + s.integer(state.echo_length); + + s.integer(state.new_kon); + s.integer(state.endx_buf); + s.integer(state.envx_buf); + s.integer(state.outx_buf); + + s.integer(state.t_pmon); + s.integer(state.t_non); + s.integer(state.t_eon); + s.integer(state.t_dir); + s.integer(state.t_koff); + + s.integer(state.t_brr_next_addr); + s.integer(state.t_adsr0); + s.integer(state.t_brr_header); + s.integer(state.t_brr_byte); + s.integer(state.t_srcn); + s.integer(state.t_esa); + s.integer(state.t_echo_disabled); + + s.integer(state.t_dir_addr); + s.integer(state.t_pitch); + s.integer(state.t_output); + s.integer(state.t_looped); + s.integer(state.t_echo_ptr); + + s.integer(state.t_main_out[0]); + s.integer(state.t_main_out[1]); + s.integer(state.t_echo_out[0]); + s.integer(state.t_echo_out[1]); + s.integer(state.t_echo_in [0]); + s.integer(state.t_echo_in [1]); + + for(unsigned n = 0; n < 8; n++) { + voice[n].buffer.serialize(s); + s.integer(voice[n].buf_pos); + s.integer(voice[n].interp_pos); + s.integer(voice[n].brr_addr); + s.integer(voice[n].brr_offset); + s.integer(voice[n].vbit); + s.integer(voice[n].vidx); + s.integer(voice[n].kon_delay); + s.integer(voice[n].env_mode); + s.integer(voice[n].env); + s.integer(voice[n].t_envx_out); + s.integer(voice[n].hidden_env); } } diff --git a/snes/fast/dsp/voice.cpp b/snes/fast/dsp/voice.cpp new file mode 100755 index 00000000..2e882f21 --- /dev/null +++ b/snes/fast/dsp/voice.cpp @@ -0,0 +1,174 @@ +#ifdef DSP_CPP + +inline void DSP::voice_output(voice_t &v, bool channel) { + //apply left/right volume + int amp = (state.t_output * (int8)VREG(voll + channel)) >> 7; + + //add to output total + state.t_main_out[channel] += amp; + state.t_main_out[channel] = sclamp<16>(state.t_main_out[channel]); + + //optionally add to echo total + if(state.t_eon & v.vbit) { + state.t_echo_out[channel] += amp; + state.t_echo_out[channel] = sclamp<16>(state.t_echo_out[channel]); + } +} + +void DSP::voice_1(voice_t &v) { + state.t_dir_addr = (state.t_dir << 8) + (state.t_srcn << 2); + state.t_srcn = VREG(srcn); +} + +void DSP::voice_2(voice_t &v) { + //read sample pointer (ignored if not needed) + uint16 addr = state.t_dir_addr; + if(!v.kon_delay) addr += 2; + uint8 lo = memory::apuram[(uint16)(addr + 0)]; + uint8 hi = memory::apuram[(uint16)(addr + 1)]; + state.t_brr_next_addr = ((hi << 8) + lo); + + state.t_adsr0 = VREG(adsr0); + + //read pitch, spread over two clocks + state.t_pitch = VREG(pitchl); +} + +void DSP::voice_3(voice_t &v) { + voice_3a(v); + voice_3b(v); + voice_3c(v); +} + +void DSP::voice_3a(voice_t &v) { + state.t_pitch += (VREG(pitchh) & 0x3f) << 8; +} + +void DSP::voice_3b(voice_t &v) { + state.t_brr_byte = memory::apuram[(uint16)(v.brr_addr + v.brr_offset)]; + state.t_brr_header = memory::apuram[(uint16)(v.brr_addr)]; +} + +void DSP::voice_3c(voice_t &v) { + //pitch modulation using previous voice's output + + if(state.t_pmon & v.vbit) { + state.t_pitch += ((state.t_output >> 5) * state.t_pitch) >> 10; + } + + if(v.kon_delay) { + //get ready to start BRR decoding on next sample + if(v.kon_delay == 5) { + v.brr_addr = state.t_brr_next_addr; + v.brr_offset = 1; + v.buf_pos = 0; + state.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; + v.kon_delay--; + if(v.kon_delay & 3) v.interp_pos = 0x4000; + + //pitch is never added during KON + state.t_pitch = 0; + } + + //gaussian interpolation + int output = gaussian_interpolate(v); + + //noise + if(state.t_non & v.vbit) { + output = (int16)(state.noise << 1); + } + + //apply envelope + state.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 || (state.t_brr_header & 3) == 1) { + v.env_mode = env_release; + v.env = 0; + } + + if(state.every_other_sample) { + //KOFF + if(state.t_koff & v.vbit) { + v.env_mode = env_release; + } + + //KON + if(state.kon & v.vbit) { + v.kon_delay = 5; + v.env_mode = env_attack; + } + } + + //run envelope for next sample + if(!v.kon_delay) envelope_run(v); +} + +void DSP::voice_4(voice_t &v) { + //decode BRR + state.t_looped = 0; + if(v.interp_pos >= 0x4000) { + brr_decode(v); + v.brr_offset += 2; + if(v.brr_offset >= 9) { + //start decoding next BRR block + v.brr_addr = (uint16)(v.brr_addr + 9); + if(state.t_brr_header & 1) { + v.brr_addr = state.t_brr_next_addr; + state.t_looped = v.vbit; + } + v.brr_offset = 1; + } + } + + //apply pitch + v.interp_pos = (v.interp_pos & 0x3fff) + state.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); +} + +void DSP::voice_5(voice_t &v) { + //output right + voice_output(v, 1); + + //ENDX, OUTX and ENVX won't update if you wrote to them 1-2 clocks earlier + state.endx_buf = REG(endx) | state.t_looped; + + //clear bit in ENDX if KON just began + if(v.kon_delay == 5) state.endx_buf &= ~v.vbit; +} + +void DSP::voice_6(voice_t &v) { + state.outx_buf = state.t_output >> 8; +} + +void DSP::voice_7(voice_t &v) { + //update ENDX + REG(endx) = (uint8)state.endx_buf; + state.envx_buf = v.t_envx_out; +} + +void DSP::voice_8(voice_t &v) { + //update OUTX + VREG(outx) = (uint8)state.outx_buf; +} + +void DSP::voice_9(voice_t &v) { + //update ENVX + VREG(envx) = (uint8)state.envx_buf; +} + +#endif diff --git a/snes/fast/ppu/debugger/debugger.cpp b/snes/fast/ppu/debugger/debugger.cpp index 3b9df44f..3d8958e8 100755 --- a/snes/fast/ppu/debugger/debugger.cpp +++ b/snes/fast/ppu/debugger/debugger.cpp @@ -2,308 +2,6 @@ #include "render.cpp" -bool PPUDebugger::property(unsigned id, string &name, string &value) { - unsigned n = 0; - - //internal - if(id == n++) { name = "S-PPU1 MDR"; value = string("0x", strhex<2>(ppu1_mdr())); return true; } - if(id == n++) { name = "S-PPU2 MDR"; value = string("0x", strhex<2>(ppu2_mdr())); return true; } - - //$2100 - if(id == n++) { name = "$2100"; value = ""; return true; } - if(id == n++) { name = "Display Disable"; value = display_disable(); return true; } - if(id == n++) { name = "Display Brightness"; value = display_brightness(); return true; } - - //$2101 - if(id == n++) { name = "$2101"; value = ""; return true; } - if(id == n++) { name = "OAM Base Size"; value = oam_base_size(); return true; } - if(id == n++) { name = "OAM Name Select"; value = oam_name_select(); return true; } - if(id == n++) { name = "OAM Name Base Address"; value = string("0x", strhex<4>(oam_name_base_address())); return true; } - - //$2102-$2103 - if(id == n++) { name = "$2102-$2103"; value = ""; return true; } - if(id == n++) { name = "OAM Base Address"; value = string("0x", strhex<4>(oam_base_address())); return true; } - if(id == n++) { name = "OAM Priority"; value = oam_priority(); return true; } - - //$2105 - if(id == n++) { name = "$2105"; value = ""; return true; } - if(id == n++) { name = "BG1 Tile Size"; value = bg1_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG2 Tile Size"; value = bg2_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG3 Tile Size"; value = bg3_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG4 Tile Size"; value = bg4_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG3 Priority"; value = bg3_priority(); return true; } - if(id == n++) { name = "BG Mode"; value = bg_mode(); return true; } - - //$2106 - if(id == n++) { name = "$2106"; value = ""; return true; } - if(id == n++) { name = "Mosaic Size"; value = mosaic_size(); return true; } - if(id == n++) { name = "BG1 Mosaic Enable"; value = bg1_mosaic_enable(); return true; } - if(id == n++) { name = "BG2 Mosaic Enable"; value = bg2_mosaic_enable(); return true; } - if(id == n++) { name = "BG3 Mosaic Enable"; value = bg3_mosaic_enable(); return true; } - if(id == n++) { name = "BG4 Mosaic Enable"; value = bg4_mosaic_enable(); return true; } - - static char screen_size[4][8] = { "32x32", "32x64", "64x32", "64x64" }; - - //$2107 - if(id == n++) { name = "$2107"; value = ""; return true; } - if(id == n++) { name = "BG1 Screen Address"; value = string("0x", strhex<4>(bg1_screen_address())); return true; } - if(id == n++) { name = "BG1 Screen Size"; value = screen_size[bg1_screen_size()]; return true; } - - //$2108 - if(id == n++) { name = "$2108"; value = ""; return true; } - if(id == n++) { name = "BG2 Screen Address"; value = string("0x", strhex<4>(bg2_screen_address())); return true; } - if(id == n++) { name = "BG2 Screen Size"; value = screen_size[bg2_screen_size()]; return true; } - - //$2109 - if(id == n++) { name = "$2109"; value = ""; return true; } - if(id == n++) { name = "BG3 Screen Address"; value = string("0x", strhex<4>(bg3_screen_address())); return true; } - if(id == n++) { name = "BG3 Screen Size"; value = screen_size[bg3_screen_size()]; return true; } - - //$210a - if(id == n++) { name = "$210a"; value = ""; return true; } - if(id == n++) { name = "BG4 Screen Address"; value = string("0x", strhex<4>(bg4_screen_address())); return true; } - if(id == n++) { name = "BG4 Screen Size"; value = screen_size[bg4_screen_size()]; return true; } - - //$210b - if(id == n++) { name = "$210b"; value = ""; return true; } - if(id == n++) { name = "BG1 Name Base Address"; value = string("0x", strhex<4>(bg1_name_base_address())); return true; } - if(id == n++) { name = "BG2 Name Base Address"; value = string("0x", strhex<4>(bg2_name_base_address())); return true; } - - //$210c - if(id == n++) { name = "$210c"; value = ""; return true; } - if(id == n++) { name = "BG3 Name Base Address"; value = string("0x", strhex<4>(bg3_name_base_address())); return true; } - if(id == n++) { name = "BG4 Name Base Address"; value = string("0x", strhex<4>(bg4_name_base_address())); return true; } - - //$210d - if(id == n++) { name = "$210d"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Scroll H-offset"; value = mode7_hoffset(); return true; } - if(id == n++) { name = "BG1 Scroll H-offset"; value = bg1_hoffset(); return true; } - - //$210e - if(id == n++) { name = "$210e"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Scroll V-offset"; value = mode7_voffset(); return true; } - if(id == n++) { name = "BG1 Scroll V-offset"; value = bg1_voffset(); return true; } - - //$210f - if(id == n++) { name = "$210f"; value = ""; return true; } - if(id == n++) { name = "BG2 Scroll H-offset"; value = bg2_hoffset(); return true; } - - //$2110 - if(id == n++) { name = "$2110"; value = ""; return true; } - if(id == n++) { name = "BG2 Scroll V-offset"; value = bg2_voffset(); return true; } - - //$2111 - if(id == n++) { name = "$2111"; value = ""; return true; } - if(id == n++) { name = "BG3 Scroll H-offset"; value = bg3_hoffset(); return true; } - - //$2112 - if(id == n++) { name = "$2112"; value = ""; return true; } - if(id == n++) { name = "BG3 Scroll V-offset"; value = bg3_voffset(); return true; } - - //$2113 - if(id == n++) { name = "$2113"; value = ""; return true; } - if(id == n++) { name = "BG4 Scroll H-offset"; value = bg4_hoffset(); return true; } - - //$2114 - if(id == n++) { name = "$2114"; value = ""; return true; } - if(id == n++) { name = "BG4 Scroll V-offset"; value = bg4_voffset(); return true; } - - //$2115 - if(id == n++) { name = "$2115"; value = ""; return true; } - if(id == n++) { name = "VRAM Increment Mode"; value = (unsigned)vram_increment_mode(); return true; } - if(id == n++) { name = "VRAM Increment Formation"; value = vram_increment_formation(); return true; } - if(id == n++) { name = "VRAM Increment Size"; value = vram_increment_size(); return true; } - - //$2116-$2117 - if(id == n++) { name = "$2116-$2117"; value = ""; return true; } - if(id == n++) { name = "VRAM Address"; value = string("0x", strhex<4>(vram_address())); return true; } - - //$211a - if(id == n++) { name = "$211a"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Repeat"; value = mode7_repeat(); return true; } - if(id == n++) { name = "Mode 7 V-flip"; value = mode7_vflip(); return true; } - if(id == n++) { name = "Mode 7 H-flip"; value = mode7_hflip(); return true; } - - //$211b - if(id == n++) { name = "$211b"; value = ""; return true; } - if(id == n++) { name = "Mode 7 A"; value = mode7_a(); return true; } - - //$211c - if(id == n++) { name = "$211c"; value = ""; return true; } - if(id == n++) { name = "Mode 7 B"; value = mode7_b(); return true; } - - //$211d - if(id == n++) { name = "$211d"; value = ""; return true; } - if(id == n++) { name = "Mode 7 C"; value = mode7_c(); return true; } - - //$211e - if(id == n++) { name = "$211e"; value = ""; return true; } - if(id == n++) { name = "Mode 7 D"; value = mode7_d(); return true; } - - //$211f - if(id == n++) { name = "$211f"; value = ""; return true; } - if(id == n++) { name = "Mode 7 X"; value = mode7_x(); return true; } - - //$2120 - if(id == n++) { name = "$2120"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Y"; value = mode7_y(); return true; } - - //$2121 - if(id == n++) { name = "$2121"; value = ""; return true; } - if(id == n++) { name = "CGRAM Address"; value = string("0x", strhex<4>(cgram_address())); return true; } - - //$2123 - if(id == n++) { name = "$2123"; value = ""; return true; } - if(id == n++) { name = "BG1 Window 1 Enable"; value = bg1_window1_enable(); return true; } - if(id == n++) { name = "BG1 Window 1 Invert"; value = bg1_window1_invert(); return true; } - if(id == n++) { name = "BG1 Window 2 Enable"; value = bg1_window2_enable(); return true; } - if(id == n++) { name = "BG1 Window 2 Invert"; value = bg1_window2_invert(); return true; } - if(id == n++) { name = "BG2 Window 1 Enable"; value = bg2_window1_enable(); return true; } - if(id == n++) { name = "BG2 Window 1 Invert"; value = bg2_window1_invert(); return true; } - if(id == n++) { name = "BG2 Window 2 Enable"; value = bg2_window2_enable(); return true; } - if(id == n++) { name = "BG2 Window 2 Invert"; value = bg2_window2_invert(); return true; } - - //$2124 - if(id == n++) { name = "$2124"; value = ""; return true; } - if(id == n++) { name = "BG3 Window 1 Enable"; value = bg3_window1_enable(); return true; } - if(id == n++) { name = "BG3 Window 1 Invert"; value = bg3_window1_invert(); return true; } - if(id == n++) { name = "BG3 Window 2 Enable"; value = bg3_window2_enable(); return true; } - if(id == n++) { name = "BG3 Window 2 Invert"; value = bg3_window2_invert(); return true; } - if(id == n++) { name = "BG4 Window 1 Enable"; value = bg4_window1_enable(); return true; } - if(id == n++) { name = "BG4 Window 1 Invert"; value = bg4_window1_invert(); return true; } - if(id == n++) { name = "BG4 Window 2 Enable"; value = bg4_window2_enable(); return true; } - if(id == n++) { name = "BG4 Window 2 Invert"; value = bg4_window2_invert(); return true; } - - //$2125 - if(id == n++) { name = "$2125"; value = ""; return true; } - if(id == n++) { name = "OAM Window 1 Enable"; value = oam_window1_enable(); return true; } - if(id == n++) { name = "OAM Window 1 Invert"; value = oam_window1_invert(); return true; } - if(id == n++) { name = "OAM Window 2 Enable"; value = oam_window2_enable(); return true; } - if(id == n++) { name = "OAM Window 2 Invert"; value = oam_window2_invert(); return true; } - if(id == n++) { name = "Color Window 1 Enable"; value = color_window1_enable(); return true; } - if(id == n++) { name = "Color Window 1 Invert"; value = color_window1_invert(); return true; } - if(id == n++) { name = "Color Window 2 Enable"; value = color_window2_enable(); return true; } - if(id == n++) { name = "Color Window 2 Invert"; value = color_window2_invert(); return true; } - - //$2126 - if(id == n++) { name = "$2126"; value = ""; return true; } - if(id == n++) { name = "Window 1 Left"; value = window1_left(); return true; } - - //$2127 - if(id == n++) { name = "$2127"; value = ""; return true; } - if(id == n++) { name = "Window 1 Right"; value = window1_right(); return true; } - - //$2128 - if(id == n++) { name = "$2128"; value = ""; return true; } - if(id == n++) { name = "Window 2 Left"; value = window2_left(); return true; } - - //$2129 - if(id == n++) { name = "$2129"; value = ""; return true; } - if(id == n++) { name = "Window 2 Right"; value = window2_right(); return true; } - - static char window_mask_mode[4][8] = { "OR", "AND", "XOR", "XNOR" }; - - //$212a - if(id == n++) { name = "$212a"; value = ""; return true; } - if(id == n++) { name = "BG1 Window Mask"; value = window_mask_mode[bg1_window_mask()]; return true; } - if(id == n++) { name = "BG2 Window Mask"; value = window_mask_mode[bg2_window_mask()]; return true; } - if(id == n++) { name = "BG3 Window Mask"; value = window_mask_mode[bg3_window_mask()]; return true; } - if(id == n++) { name = "BG4 Window Mask"; value = window_mask_mode[bg4_window_mask()]; return true; } - - //$212b - if(id == n++) { name = "$212b"; value = ""; return true; } - if(id == n++) { name = "OAM Window Mask"; value = window_mask_mode[oam_window_mask()]; return true; } - if(id == n++) { name = "Color Window Mask"; value = window_mask_mode[color_window_mask()]; return true; } - - //$212c - if(id == n++) { name = "$212c"; value = ""; return true; } - if(id == n++) { name = "BG1 Mainscreen Enable"; value = bg1_mainscreen_enable(); return true; } - if(id == n++) { name = "BG2 Mainscreen Enable"; value = bg2_mainscreen_enable(); return true; } - if(id == n++) { name = "BG3 Mainscreen Enable"; value = bg3_mainscreen_enable(); return true; } - if(id == n++) { name = "BG4 Mainscreen Enable"; value = bg4_mainscreen_enable(); return true; } - if(id == n++) { name = "OAM Mainscreen Enable"; value = oam_mainscreen_enable(); return true; } - - //$212d - if(id == n++) { name = "$212d"; value = ""; return true; } - if(id == n++) { name = "BG1 Subscreen Enable"; value = bg1_subscreen_enable(); return true; } - if(id == n++) { name = "BG2 Subscreen Enable"; value = bg2_subscreen_enable(); return true; } - if(id == n++) { name = "BG3 Subscreen Enable"; value = bg3_subscreen_enable(); return true; } - if(id == n++) { name = "BG4 Subscreen Enable"; value = bg4_subscreen_enable(); return true; } - if(id == n++) { name = "OAM Subscreen Enable"; value = oam_subscreen_enable(); return true; } - - //$212e - if(id == n++) { name = "$212e"; value = ""; return true; } - if(id == n++) { name = "BG1 Mainscreen Window Enable"; value = bg1_mainscreen_window_enable(); return true; } - if(id == n++) { name = "BG2 Mainscreen Window Enable"; value = bg2_mainscreen_window_enable(); return true; } - if(id == n++) { name = "BG3 Mainscreen Window Enable"; value = bg3_mainscreen_window_enable(); return true; } - if(id == n++) { name = "BG4 Mainscreen Window Enable"; value = bg4_mainscreen_window_enable(); return true; } - if(id == n++) { name = "OAM Mainscreen Window Enable"; value = oam_mainscreen_window_enable(); return true; } - - //$212f - if(id == n++) { name = "$212f"; value = ""; return true; } - if(id == n++) { name = "BG1 Subscreen Window Enable"; value = bg1_subscreen_window_enable(); return true; } - if(id == n++) { name = "BG2 Subscreen Window Enable"; value = bg2_subscreen_window_enable(); return true; } - if(id == n++) { name = "BG3 Subscreen Window Enable"; value = bg3_subscreen_window_enable(); return true; } - if(id == n++) { name = "BG4 Subscreen Window Enable"; value = bg4_subscreen_window_enable(); return true; } - if(id == n++) { name = "OAM Subscreen Window Enable"; value = oam_subscreen_window_enable(); return true; } - - static char color_window_mask_mode[4][32] = { "Always", "Never", "Inside Window Only", "Outside Window Only" }; - - //$2130 - if(id == n++) { name = "$2130"; value = ""; return true; } - if(id == n++) { name = "Color Mainscreen Window Mask"; value = color_window_mask_mode[color_mainscreen_window_mask()]; return true; } - if(id == n++) { name = "Color Subscreen Window Mask"; value = color_window_mask_mode[color_subscreen_window_mask()]; return true; } - if(id == n++) { name = "Color Add/Subtract Mode"; value = !color_add_subtract_mode() ? "Fixed Color" : "Subscreen"; return true; } - if(id == n++) { name = "Direct Color"; value = direct_color(); return true; } - - //$2131 - if(id == n++) { name = "$2131"; value = ""; return true; } - if(id == n++) { name = "Color Mode"; value = !color_mode() ? "Add" : "Subtract"; return true; } - if(id == n++) { name = "Color Halve"; value = color_halve(); return true; } - if(id == n++) { name = "BG1 Color Enable"; value = bg1_color_enable(); return true; } - if(id == n++) { name = "BG2 Color Enable"; value = bg2_color_enable(); return true; } - if(id == n++) { name = "BG3 Color Enable"; value = bg3_color_enable(); return true; } - if(id == n++) { name = "BG4 Color Enable"; value = bg4_color_enable(); return true; } - if(id == n++) { name = "OAM Color Enable"; value = oam_color_enable(); return true; } - if(id == n++) { name = "Back Color Enable"; value = back_color_enable(); return true; } - - //$2132 - if(id == n++) { name = "$2132"; value = ""; return true; } - if(id == n++) { name = "Color Constant - Blue"; value = color_constant_blue(); return true; } - if(id == n++) { name = "Color Constant - Green"; value = color_constant_green(); return true; } - if(id == n++) { name = "Color Constant - Red"; value = color_constant_red(); return true; } - - //$2133 - if(id == n++) { name = "$2133"; value = ""; return true; } - if(id == n++) { name = "Mode 7 EXTBG"; value = mode7_extbg(); return true; } - if(id == n++) { name = "Pseudo Hires"; value = pseudo_hires(); return true; } - if(id == n++) { name = "Overscan"; value = overscan_enable(); return true; } - if(id == n++) { name = "OAM Interlace"; value = oam_interlace(); return true; } - if(id == n++) { name = "Interlace"; value = interlace_enable(); return true; } - - //$213c - if(id == n++) { name = "$213c"; value = ""; return true; } - if(id == n++) { name = "H-counter"; value = hcounter(); return true; } - - //$213d - if(id == n++) { name = "$213d"; value = ""; return true; } - if(id == n++) { name = "V-counter"; value = vcounter(); return true; } - - //$213e - if(id == n++) { name = "$213e"; value = ""; return true; } - if(id == n++) { name = "Range Over"; value = range_over(); return true; } - if(id == n++) { name = "Time Over"; value = time_over(); return true; } - if(id == n++) { name = "S-PPU1 Version"; value = ppu1_version(); return true; } - - //$213f - if(id == n++) { name = "$213f"; value = ""; return true; } - if(id == n++) { name = "Field"; value = field(); return true; } - if(id == n++) { name = "Region"; value = !region() ? "NTSC" : "PAL"; return true; } - if(id == n++) { name = "S-PPU2 Version"; value = ppu2_version(); return true; } - - return false; -} - uint8 PPUDebugger::vram_mmio_read(uint16 addr) { uint8 data = PPU::vram_mmio_read(addr); debugger.breakpoint_test(Debugger::Breakpoint::Source::VRAM, Debugger::Breakpoint::Mode::Read, addr, data); @@ -345,248 +43,314 @@ PPUDebugger::PPUDebugger() { oam_enabled[0] = oam_enabled[1] = oam_enabled[2] = oam_enabled[3] = true; } -//=========== -//PPUDebugger -//=========== +bool PPUDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; -//internal -unsigned PPUDebugger::ppu1_mdr() { return regs.ppu1_mdr; } -unsigned PPUDebugger::ppu2_mdr() { return regs.ppu2_mdr; } + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } -//$2100 -bool PPUDebugger::display_disable() { return regs.display_disabled; } -unsigned PPUDebugger::display_brightness() { return regs.display_brightness; } + //internal + item("S-PPU1 MDR", string("0x", strhex<2>(regs.ppu1_mdr))); + item("S-PPU2 MDR", string("0x", strhex<2>(regs.ppu2_mdr))); -//$2101 -unsigned PPUDebugger::oam_base_size() { return regs.oam_basesize; } -unsigned PPUDebugger::oam_name_select() { return regs.oam_nameselect; } -unsigned PPUDebugger::oam_name_base_address() { return regs.oam_tdaddr; } + //$2100 + item("$2100", ""); + item("Display Disable", regs.display_disabled); + item("Display Brightness", (unsigned)regs.display_brightness); -//$2102-$2103 -unsigned PPUDebugger::oam_base_address() { return regs.oam_baseaddr; } -bool PPUDebugger::oam_priority() { return regs.oam_priority; } + //$2101 + item("$2101", ""); + item("OAM Base Size", (unsigned)regs.oam_basesize); + item("OAM Name Select", (unsigned)regs.oam_nameselect); + item("OAM Name Base Address", string("0x", strhex<4>(regs.oam_tdaddr))); -//$2105 -bool PPUDebugger::bg1_tile_size() { return regs.bg_tilesize[BG1]; } -bool PPUDebugger::bg2_tile_size() { return regs.bg_tilesize[BG2]; } -bool PPUDebugger::bg3_tile_size() { return regs.bg_tilesize[BG3]; } -bool PPUDebugger::bg4_tile_size() { return regs.bg_tilesize[BG4]; } -bool PPUDebugger::bg3_priority() { return regs.bg3_priority; } -unsigned PPUDebugger::bg_mode() { return regs.bg_mode; } + //$2102-$2103 + item("$2102-$2103", ""); + item("OAM Base Address", string("0x", strhex<4>(regs.oam_baseaddr))); + item("OAM Priority", regs.oam_priority); -//$2106 -unsigned PPUDebugger::mosaic_size() { return regs.mosaic_size; } -bool PPUDebugger::bg1_mosaic_enable() { return regs.mosaic_enabled[BG1]; } -bool PPUDebugger::bg2_mosaic_enable() { return regs.mosaic_enabled[BG2]; } -bool PPUDebugger::bg3_mosaic_enable() { return regs.mosaic_enabled[BG3]; } -bool PPUDebugger::bg4_mosaic_enable() { return regs.mosaic_enabled[BG4]; } + //$2105 + item("$2105", ""); + item("BG1 Tile Size", regs.bg_tilesize[BG1] ? "16x16" : "8x8"); + item("BG2 Tile Size", regs.bg_tilesize[BG2] ? "16x16" : "8x8"); + item("BG3 Tile Size", regs.bg_tilesize[BG3] ? "16x16" : "8x8"); + item("BG4 Tile Size", regs.bg_tilesize[BG4] ? "16x16" : "8x8"); + item("BG3 Priority", regs.bg3_priority); + item("BG Mode", (unsigned)regs.bg_mode); -//$2107 -unsigned PPUDebugger::bg1_screen_address() { return regs.bg_scaddr[BG1]; } -unsigned PPUDebugger::bg1_screen_size() { return regs.bg_scsize[BG1]; } + //$2106 + item("$2106", ""); + item("Mosaic Size", (unsigned)regs.mosaic_size); + item("BG1 Mosaic Enable", regs.mosaic_enabled[BG1]); + item("BG2 Mosaic Enable", regs.mosaic_enabled[BG2]); + item("BG3 Mosaic Enable", regs.mosaic_enabled[BG3]); + item("BG4 Mosaic Enable", regs.mosaic_enabled[BG4]); -//$2108 -unsigned PPUDebugger::bg2_screen_address() { return regs.bg_scaddr[BG2]; } -unsigned PPUDebugger::bg2_screen_size() { return regs.bg_scsize[BG2]; } + static char screen_size[4][8] = { "32x32", "32x64", "64x32", "64x64" }; -//$2109 -unsigned PPUDebugger::bg3_screen_address() { return regs.bg_scaddr[BG3]; } -unsigned PPUDebugger::bg3_screen_size() { return regs.bg_scsize[BG3]; } + //$2107 + item("$2107", ""); + item("BG1 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG1]))); + item("BG1 Screen Size", screen_size[regs.bg_scsize[BG1]]); -//$210a -unsigned PPUDebugger::bg4_screen_address() { return regs.bg_scaddr[BG4]; } -unsigned PPUDebugger::bg4_screen_size() { return regs.bg_scsize[BG4]; } + //$2108 + item("$2108", ""); + item("BG2 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG2]))); + item("BG2 Screen Size", screen_size[regs.bg_scsize[BG2]]); -//$210b -unsigned PPUDebugger::bg1_name_base_address() { return regs.bg_tdaddr[BG1]; } -unsigned PPUDebugger::bg2_name_base_address() { return regs.bg_tdaddr[BG2]; } + //$2109 + item("$2109", ""); + item("BG3 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG3]))); + item("BG3 Screen Size", screen_size[regs.bg_scsize[BG3]]); -//$210c -unsigned PPUDebugger::bg3_name_base_address() { return regs.bg_tdaddr[BG3]; } -unsigned PPUDebugger::bg4_name_base_address() { return regs.bg_tdaddr[BG4]; } + //$210a + item("$210a", ""); + item("BG4 Screen Address", string("0x", strhex<4>(regs.bg_scaddr[BG4]))); + item("BG4 Screen Size", screen_size[regs.bg_scsize[BG4]]); -//$210d -unsigned PPUDebugger::mode7_hoffset() { return regs.m7_hofs & 0x1fff; } -unsigned PPUDebugger::bg1_hoffset() { return regs.bg_hofs[BG1] & 0x03ff; } + //$210b + item("$210b", ""); + item("BG1 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG1]))); + item("BG2 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG2]))); -//$210e -unsigned PPUDebugger::mode7_voffset() { return regs.m7_vofs & 0x1fff; } -unsigned PPUDebugger::bg1_voffset() { return regs.bg_vofs[BG1] & 0x03ff; } + //$210c + item("$210c", ""); + item("BG3 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG3]))); + item("BG4 Name Base Address", string("0x", strhex<4>(regs.bg_tdaddr[BG4]))); -//$210f -unsigned PPUDebugger::bg2_hoffset() { return regs.bg_hofs[BG2] & 0x03ff; } + //$210d + item("$210d", ""); + item("Mode 7 Scroll H-offset", (unsigned)(regs.m7_hofs & 0x1fff)); + item("BG1 Scroll H-offset", (unsigned)(regs.bg_hofs[BG1] & 0x03ff)); -//$2110 -unsigned PPUDebugger::bg2_voffset() { return regs.bg_vofs[BG2] & 0x03ff; } + //$210e + item("$210e", ""); + item("Mode 7 Scroll V-offset", (unsigned)(regs.m7_vofs & 0x1fff)); + item("BG1 Scroll V-offset", (unsigned)(regs.bg_vofs[BG1] & 0x03ff)); -//$2111 -unsigned PPUDebugger::bg3_hoffset() { return regs.bg_hofs[BG3] & 0x03ff; } + //$210f + item("$210f", ""); + item("BG2 Scroll H-offset", (unsigned)(regs.bg_hofs[BG2] & 0x03ff)); -//$2112 -unsigned PPUDebugger::bg3_voffset() { return regs.bg_vofs[BG3] & 0x03ff; } + //$2110 + item("$2110", ""); + item("BG2 Scroll V-offset", (unsigned)(regs.bg_vofs[BG2] & 0x03ff)); -//$2113 -unsigned PPUDebugger::bg4_hoffset() { return regs.bg_hofs[BG4] & 0x03ff; } + //$2111 + item("$2111", ""); + item("BG3 Scroll H-offset", (unsigned)(regs.bg_hofs[BG3] & 0x03ff)); -//$2114 -unsigned PPUDebugger::bg4_voffset() { return regs.bg_vofs[BG4] & 0x03ff; } + //$2112 + item("$2112", ""); + item("BG3 Scroll V-offset", (unsigned)(regs.bg_vofs[BG3] & 0x03ff)); -//$2115 -bool PPUDebugger::vram_increment_mode() { return regs.vram_incmode; } -unsigned PPUDebugger::vram_increment_formation() { return regs.vram_mapping; } -unsigned PPUDebugger::vram_increment_size() { return regs.vram_incsize; } + //$2113 + item("$2113", ""); + item("BG4 Scroll H-offset", (unsigned)(regs.bg_hofs[BG4] & 0x03ff)); -//$2116-$2117 -unsigned PPUDebugger::vram_address() { return regs.vram_addr; } + //$2114 + item("$2114", ""); + item("BG4 Scroll V-offset", (unsigned)(regs.bg_vofs[BG4] & 0x03ff)); -//$211a -unsigned PPUDebugger::mode7_repeat() { return regs.mode7_repeat; } -bool PPUDebugger::mode7_vflip() { return regs.mode7_vflip; } -bool PPUDebugger::mode7_hflip() { return regs.mode7_hflip; } + //$2115 + item("$2115", ""); + item("VRAM Increment Mode", (unsigned)regs.vram_incmode); + item("VRAM Increment Formation", (unsigned)regs.vram_mapping); + item("VRAM Increment Size", (unsigned)regs.vram_incsize); -//$211b -unsigned PPUDebugger::mode7_a() { return regs.m7a; } + //$2116-$2117 + item("$2116-$2117", ""); + item("VRAM Address", string("0x", strhex<4>(regs.vram_addr))); -//$211c -unsigned PPUDebugger::mode7_b() { return regs.m7b; } + //$211a + item("$211a", ""); + item("Mode 7 Repeat", (unsigned)regs.mode7_repeat); + item("Mode 7 V-flip", regs.mode7_vflip); + item("Mode 7 H-flip", regs.mode7_hflip); -//$211d -unsigned PPUDebugger::mode7_c() { return regs.m7c; } + //$211b + item("$211b", ""); + item("Mode 7 A", (unsigned)regs.m7a); -//$211e -unsigned PPUDebugger::mode7_d() { return regs.m7d; } + //$211c + item("$211c", ""); + item("Mode 7 B", (unsigned)regs.m7b); -//$211f -unsigned PPUDebugger::mode7_x() { return regs.m7x; } + //$211d + item("$211d", ""); + item("Mode 7 C", (unsigned)regs.m7c); -//$2120 -unsigned PPUDebugger::mode7_y() { return regs.m7y; } + //$211e + item("$211e", ""); + item("Mode 7 D", (unsigned)regs.m7d); -//$2121 -unsigned PPUDebugger::cgram_address() { return regs.cgram_addr; } + //$211f + item("$211f", ""); + item("Mode 7 X", (unsigned)regs.m7x); -//$2123 -bool PPUDebugger::bg1_window1_enable() { return regs.window1_enabled[BG1]; } -bool PPUDebugger::bg1_window1_invert() { return regs.window1_invert [BG1]; } -bool PPUDebugger::bg1_window2_enable() { return regs.window2_enabled[BG1]; } -bool PPUDebugger::bg1_window2_invert() { return regs.window2_invert [BG1]; } -bool PPUDebugger::bg2_window1_enable() { return regs.window1_enabled[BG2]; } -bool PPUDebugger::bg2_window1_invert() { return regs.window1_invert [BG2]; } -bool PPUDebugger::bg2_window2_enable() { return regs.window2_enabled[BG2]; } -bool PPUDebugger::bg2_window2_invert() { return regs.window2_invert [BG2]; } + //$2120 + item("$2120", ""); + item("Mode 7 Y", (unsigned)regs.m7y); -//$2124 -bool PPUDebugger::bg3_window1_enable() { return regs.window1_enabled[BG3]; } -bool PPUDebugger::bg3_window1_invert() { return regs.window1_invert [BG3]; } -bool PPUDebugger::bg3_window2_enable() { return regs.window2_enabled[BG3]; } -bool PPUDebugger::bg3_window2_invert() { return regs.window2_invert [BG3]; } -bool PPUDebugger::bg4_window1_enable() { return regs.window1_enabled[BG4]; } -bool PPUDebugger::bg4_window1_invert() { return regs.window1_invert [BG4]; } -bool PPUDebugger::bg4_window2_enable() { return regs.window2_enabled[BG4]; } -bool PPUDebugger::bg4_window2_invert() { return regs.window2_invert [BG4]; } + //$2121 + item("$2121", ""); + item("CGRAM Address", string("0x", strhex<4>(regs.cgram_addr))); -//$2125 -bool PPUDebugger::oam_window1_enable() { return regs.window1_enabled[OAM]; } -bool PPUDebugger::oam_window1_invert() { return regs.window1_invert [OAM]; } -bool PPUDebugger::oam_window2_enable() { return regs.window2_enabled[OAM]; } -bool PPUDebugger::oam_window2_invert() { return regs.window2_invert [OAM]; } -bool PPUDebugger::color_window1_enable() { return regs.window1_enabled[COL]; } -bool PPUDebugger::color_window1_invert() { return regs.window1_invert [COL]; } -bool PPUDebugger::color_window2_enable() { return regs.window2_enabled[COL]; } -bool PPUDebugger::color_window2_invert() { return regs.window2_enabled[COL]; } + //$2123 + item("$2123", ""); + item("BG1 Window 1 Enable", regs.window1_enabled[BG1]); + item("BG1 Window 1 Invert", regs.window1_invert [BG1]); + item("BG1 Window 2 Enable", regs.window2_enabled[BG1]); + item("BG1 Window 2 Invert", regs.window2_invert [BG1]); + item("BG2 Window 1 Enable", regs.window1_enabled[BG2]); + item("BG2 Window 1 Invert", regs.window1_invert [BG2]); + item("BG2 Window 2 Enable", regs.window2_enabled[BG2]); + item("BG2 Window 2 Invert", regs.window2_invert [BG2]); -//$2126 -unsigned PPUDebugger::window1_left() { return regs.window1_left; } + //$2124 + item("$2124", ""); + item("BG3 Window 1 Enable", regs.window1_enabled[BG3]); + item("BG3 Window 1 Invert", regs.window1_invert [BG3]); + item("BG3 Window 2 Enable", regs.window2_enabled[BG3]); + item("BG3 Window 2 Invert", regs.window2_invert [BG3]); + item("BG4 Window 1 Enable", regs.window1_enabled[BG4]); + item("BG4 Window 1 Invert", regs.window1_invert [BG4]); + item("BG4 Window 2 Enable", regs.window2_enabled[BG4]); + item("BG4 Window 2 Invert", regs.window2_invert [BG4]); -//$2127 -unsigned PPUDebugger::window1_right() { return regs.window1_right; } + //$2125 + item("$2125", ""); + item("OAM Window 1 Enable", regs.window1_enabled[OAM]); + item("OAM Window 1 Invert", regs.window1_invert [OAM]); + item("OAM Window 2 Enable", regs.window2_enabled[OAM]); + item("OAM Window 2 Invert", regs.window2_invert [OAM]); + item("Color Window 1 Enable", regs.window1_enabled[COL]); + item("Color Window 1 Invert", regs.window1_invert [COL]); + item("Color Window 2 Enable", regs.window2_enabled[COL]); + item("Color Window 2 Invert", regs.window2_enabled[COL]); -//$2128 -unsigned PPUDebugger::window2_left() { return regs.window2_left; } + //$2126 + item("$2126", ""); + item("Window 1 Left", (unsigned)regs.window1_left); -//$2129 -unsigned PPUDebugger::window2_right() { return regs.window2_right; } + //$2127 + item("$2127", ""); + item("Window 1 Right", (unsigned)regs.window1_right); -//$212a -unsigned PPUDebugger::bg1_window_mask() { return regs.window_mask[BG1]; } -unsigned PPUDebugger::bg2_window_mask() { return regs.window_mask[BG2]; } -unsigned PPUDebugger::bg3_window_mask() { return regs.window_mask[BG3]; } -unsigned PPUDebugger::bg4_window_mask() { return regs.window_mask[BG4]; } + //$2128 + item("$2128", ""); + item("Window 2 Left", (unsigned)regs.window2_left); -//$212b -unsigned PPUDebugger::oam_window_mask() { return regs.window_mask[OAM]; } -unsigned PPUDebugger::color_window_mask() { return regs.window_mask[COL]; } + //$2129 + item("$2129", ""); + item("Window 2 Right", (unsigned)regs.window2_right); -//$212c -bool PPUDebugger::bg1_mainscreen_enable() { return regs.bg_enabled[BG1]; } -bool PPUDebugger::bg2_mainscreen_enable() { return regs.bg_enabled[BG2]; } -bool PPUDebugger::bg3_mainscreen_enable() { return regs.bg_enabled[BG3]; } -bool PPUDebugger::bg4_mainscreen_enable() { return regs.bg_enabled[BG4]; } -bool PPUDebugger::oam_mainscreen_enable() { return regs.bg_enabled[OAM]; } + static char window_mask_mode[4][8] = { "OR", "AND", "XOR", "XNOR" }; -//$212d -bool PPUDebugger::bg1_subscreen_enable() { return regs.bgsub_enabled[BG1]; } -bool PPUDebugger::bg2_subscreen_enable() { return regs.bgsub_enabled[BG2]; } -bool PPUDebugger::bg3_subscreen_enable() { return regs.bgsub_enabled[BG3]; } -bool PPUDebugger::bg4_subscreen_enable() { return regs.bgsub_enabled[BG4]; } -bool PPUDebugger::oam_subscreen_enable() { return regs.bgsub_enabled[OAM]; } + //$212a + item("$212a", ""); + item("BG1 Window Mask", window_mask_mode[regs.window_mask[BG1]]); + item("BG2 Window Mask", window_mask_mode[regs.window_mask[BG2]]); + item("BG3 Window Mask", window_mask_mode[regs.window_mask[BG3]]); + item("BG4 Window Mask", window_mask_mode[regs.window_mask[BG4]]); -//$212e -bool PPUDebugger::bg1_mainscreen_window_enable() { return regs.window_enabled[BG1]; } -bool PPUDebugger::bg2_mainscreen_window_enable() { return regs.window_enabled[BG2]; } -bool PPUDebugger::bg3_mainscreen_window_enable() { return regs.window_enabled[BG3]; } -bool PPUDebugger::bg4_mainscreen_window_enable() { return regs.window_enabled[BG4]; } -bool PPUDebugger::oam_mainscreen_window_enable() { return regs.window_enabled[OAM]; } + //$212b + item("$212b", ""); + item("OAM Window Mask", window_mask_mode[regs.window_mask[OAM]]); + item("Color Window Mask", window_mask_mode[regs.window_mask[COL]]); -//$212f -bool PPUDebugger::bg1_subscreen_window_enable() { return regs.sub_window_enabled[BG1]; } -bool PPUDebugger::bg2_subscreen_window_enable() { return regs.sub_window_enabled[BG2]; } -bool PPUDebugger::bg3_subscreen_window_enable() { return regs.sub_window_enabled[BG3]; } -bool PPUDebugger::bg4_subscreen_window_enable() { return regs.sub_window_enabled[BG4]; } -bool PPUDebugger::oam_subscreen_window_enable() { return regs.sub_window_enabled[OAM]; } + //$212c + item("$212c", ""); + item("BG1 Mainscreen Enable", regs.bg_enabled[BG1]); + item("BG2 Mainscreen Enable", regs.bg_enabled[BG2]); + item("BG3 Mainscreen Enable", regs.bg_enabled[BG3]); + item("BG4 Mainscreen Enable", regs.bg_enabled[BG4]); + item("OAM Mainscreen Enable", regs.bg_enabled[OAM]); -//$2130 -unsigned PPUDebugger::color_mainscreen_window_mask() { return regs.color_mask; } -unsigned PPUDebugger::color_subscreen_window_mask() { return regs.colorsub_mask; } -bool PPUDebugger::color_add_subtract_mode() { return regs.addsub_mode; } -bool PPUDebugger::direct_color() { return regs.direct_color; } + //$212d + item("$212d", ""); + item("BG1 Subscreen Enable", regs.bgsub_enabled[BG1]); + item("BG2 Subscreen Enable", regs.bgsub_enabled[BG2]); + item("BG3 Subscreen Enable", regs.bgsub_enabled[BG3]); + item("BG4 Subscreen Enable", regs.bgsub_enabled[BG4]); + item("OAM Subscreen Enable", regs.bgsub_enabled[OAM]); -//$2131 -bool PPUDebugger::color_mode() { return regs.color_mode; } -bool PPUDebugger::color_halve() { return regs.color_halve; } -bool PPUDebugger::bg1_color_enable() { return regs.color_enabled[BG1]; } -bool PPUDebugger::bg2_color_enable() { return regs.color_enabled[BG2]; } -bool PPUDebugger::bg3_color_enable() { return regs.color_enabled[BG3]; } -bool PPUDebugger::bg4_color_enable() { return regs.color_enabled[BG4]; } -bool PPUDebugger::oam_color_enable() { return regs.color_enabled[OAM]; } -bool PPUDebugger::back_color_enable() { return regs.color_enabled[BACK]; } + //$212e + item("$212e", ""); + item("BG1 Mainscreen Window Enable", regs.window_enabled[BG1]); + item("BG2 Mainscreen Window Enable", regs.window_enabled[BG2]); + item("BG3 Mainscreen Window Enable", regs.window_enabled[BG3]); + item("BG4 Mainscreen Window Enable", regs.window_enabled[BG4]); + item("OAM Mainscreen Window Enable", regs.window_enabled[OAM]); -//$2132 -unsigned PPUDebugger::color_constant_blue() { return regs.color_b; } -unsigned PPUDebugger::color_constant_green() { return regs.color_g; } -unsigned PPUDebugger::color_constant_red() { return regs.color_r; } + //$212f + item("$212f", ""); + item("BG1 Subscreen Window Enable", regs.sub_window_enabled[BG1]); + item("BG2 Subscreen Window Enable", regs.sub_window_enabled[BG2]); + item("BG3 Subscreen Window Enable", regs.sub_window_enabled[BG3]); + item("BG4 Subscreen Window Enable", regs.sub_window_enabled[BG4]); + item("OAM Subscreen Window Enable", regs.sub_window_enabled[OAM]); -//$2133 -bool PPUDebugger::mode7_extbg() { return regs.mode7_extbg; } -bool PPUDebugger::pseudo_hires() { return regs.pseudo_hires; } -bool PPUDebugger::overscan_enable() { return regs.overscan; } -bool PPUDebugger::oam_interlace() { return regs.oam_interlace; } -bool PPUDebugger::interlace_enable() { return regs.interlace; } + static char color_window_mask_mode[4][32] = { "Always", "Never", "Inside Window Only", "Outside Window Only" }; -//$213c -unsigned PPUDebugger::hcounter() { return PPU::hcounter(); } + //$2130 + item("$2130", ""); + item("Color Mainscreen Window Mask", color_window_mask_mode[regs.color_mask]); + item("Color Subscreen Window Mask", color_window_mask_mode[regs.colorsub_mask]); + item("Color Add/Subtract Mode", !regs.addsub_mode ? "Fixed Color" : "Subscreen"); + item("Direct Color", regs.direct_color); -//$213d -unsigned PPUDebugger::vcounter() { return PPU::vcounter(); } + //$2131 + item("$2131", ""); + item("Color Mode", !regs.color_mode ? "Add" : "Subtract"); + item("Color Halve", regs.color_halve); + item("BG1 Color Enable", regs.color_enabled[BG1]); + item("BG2 Color Enable", regs.color_enabled[BG2]); + item("BG3 Color Enable", regs.color_enabled[BG3]); + item("BG4 Color Enable", regs.color_enabled[BG4]); + item("OAM Color Enable", regs.color_enabled[OAM]); + item("Back Color Enable", regs.color_enabled[BACK]); -//$213e -bool PPUDebugger::range_over() { return regs.range_over; } -bool PPUDebugger::time_over() { return regs.time_over; } -unsigned PPUDebugger::ppu1_version() { return PPU::ppu1_version; } + //$2132 + item("$2132", ""); + item("Color Constant - Blue", (unsigned)regs.color_b); + item("Color Constant - Green", (unsigned)regs.color_g); + item("Color Constant - Red", (unsigned)regs.color_r); -//$213f -bool PPUDebugger::field() { return cpu.field(); } -bool PPUDebugger::region() { return PPU::region; } -unsigned PPUDebugger::ppu2_version() { return PPU::ppu2_version; } + //$2133 + item("$2133", ""); + item("Mode 7 EXTBG", regs.mode7_extbg); + item("Pseudo Hires", regs.pseudo_hires); + item("Overscan", regs.overscan); + item("OAM Interlace", regs.oam_interlace); + item("Interlace", regs.interlace); + + //$213c + item("$213c", ""); + item("H-counter", (unsigned)hcounter()); + + //$213d + item("$213d", ""); + item("V-counter", (unsigned)vcounter()); + + //$213e + item("$213e", ""); + item("Range Over", regs.range_over); + item("Time Over", regs.time_over); + item("S-PPU1 Version", (unsigned)ppu1_version); + + //$213f + item("$213f", ""); + item("Field", cpu.field()); + item("Region", !region ? "NTSC" : "PAL"); + item("S-PPU2 Version", (unsigned)ppu2_version); + + #undef item + return false; +} #endif diff --git a/snes/fast/ppu/debugger/debugger.hpp b/snes/fast/ppu/debugger/debugger.hpp index 0cdf42a3..528704d2 100755 --- a/snes/fast/ppu/debugger/debugger.hpp +++ b/snes/fast/ppu/debugger/debugger.hpp @@ -27,248 +27,4 @@ public: void render_line_mode7(); PPUDebugger(); - - //=========== - //PPUDebugger - //=========== - - //internal - unsigned ppu1_mdr(); - unsigned ppu2_mdr(); - - //$2100 - bool display_disable(); - unsigned display_brightness(); - - //$2101 - unsigned oam_base_size(); - unsigned oam_name_select(); - unsigned oam_name_base_address(); - - //$2102-$2103 - unsigned oam_base_address(); - bool oam_priority(); - - //$2105 - bool bg1_tile_size(); - bool bg2_tile_size(); - bool bg3_tile_size(); - bool bg4_tile_size(); - bool bg3_priority(); - unsigned bg_mode(); - - //$2106 - unsigned mosaic_size(); - bool bg1_mosaic_enable(); - bool bg2_mosaic_enable(); - bool bg3_mosaic_enable(); - bool bg4_mosaic_enable(); - - //$2107 - unsigned bg1_screen_address(); - unsigned bg1_screen_size(); - - //$2108 - unsigned bg2_screen_address(); - unsigned bg2_screen_size(); - - //$2109 - unsigned bg3_screen_address(); - unsigned bg3_screen_size(); - - //$210a - unsigned bg4_screen_address(); - unsigned bg4_screen_size(); - - //$210b - unsigned bg1_name_base_address(); - unsigned bg2_name_base_address(); - - //$210c - unsigned bg3_name_base_address(); - unsigned bg4_name_base_address(); - - //$210d - unsigned mode7_hoffset(); - unsigned bg1_hoffset(); - - //$210e - unsigned mode7_voffset(); - unsigned bg1_voffset(); - - //$210f - unsigned bg2_hoffset(); - - //$2110 - unsigned bg2_voffset(); - - //$2111 - unsigned bg3_hoffset(); - - //$2112 - unsigned bg3_voffset(); - - //$2113 - unsigned bg4_hoffset(); - - //$2114 - unsigned bg4_voffset(); - - //$2115 - bool vram_increment_mode(); - unsigned vram_increment_formation(); - unsigned vram_increment_size(); - - //$2116-$2117 - unsigned vram_address(); - - //$211a - unsigned mode7_repeat(); - bool mode7_vflip(); - bool mode7_hflip(); - - //$211b - unsigned mode7_a(); - - //$211c - unsigned mode7_b(); - - //$211d - unsigned mode7_c(); - - //$211e - unsigned mode7_d(); - - //$211f - unsigned mode7_x(); - - //$2120 - unsigned mode7_y(); - - //$2121 - unsigned cgram_address(); - - //$2123 - bool bg1_window1_enable(); - bool bg1_window1_invert(); - bool bg1_window2_enable(); - bool bg1_window2_invert(); - bool bg2_window1_enable(); - bool bg2_window1_invert(); - bool bg2_window2_enable(); - bool bg2_window2_invert(); - - //$2124 - bool bg3_window1_enable(); - bool bg3_window1_invert(); - bool bg3_window2_enable(); - bool bg3_window2_invert(); - bool bg4_window1_enable(); - bool bg4_window1_invert(); - bool bg4_window2_enable(); - bool bg4_window2_invert(); - - //$2125 - bool oam_window1_enable(); - bool oam_window1_invert(); - bool oam_window2_enable(); - bool oam_window2_invert(); - bool color_window1_enable(); - bool color_window1_invert(); - bool color_window2_enable(); - bool color_window2_invert(); - - //$2126 - unsigned window1_left(); - - //$2127 - unsigned window1_right(); - - //$2128 - unsigned window2_left(); - - //$2129 - unsigned window2_right(); - - //$212a - unsigned bg1_window_mask(); - unsigned bg2_window_mask(); - unsigned bg3_window_mask(); - unsigned bg4_window_mask(); - - //$212b - unsigned oam_window_mask(); - unsigned color_window_mask(); - - //$212c - bool bg1_mainscreen_enable(); - bool bg2_mainscreen_enable(); - bool bg3_mainscreen_enable(); - bool bg4_mainscreen_enable(); - bool oam_mainscreen_enable(); - - //$212d - bool bg1_subscreen_enable(); - bool bg2_subscreen_enable(); - bool bg3_subscreen_enable(); - bool bg4_subscreen_enable(); - bool oam_subscreen_enable(); - - //$212e - bool bg1_mainscreen_window_enable(); - bool bg2_mainscreen_window_enable(); - bool bg3_mainscreen_window_enable(); - bool bg4_mainscreen_window_enable(); - bool oam_mainscreen_window_enable(); - - //$212f - bool bg1_subscreen_window_enable(); - bool bg2_subscreen_window_enable(); - bool bg3_subscreen_window_enable(); - bool bg4_subscreen_window_enable(); - bool oam_subscreen_window_enable(); - - //$2130 - unsigned color_mainscreen_window_mask(); - unsigned color_subscreen_window_mask(); - bool color_add_subtract_mode(); - bool direct_color(); - - //$2131 - bool color_mode(); - bool color_halve(); - bool bg1_color_enable(); - bool bg2_color_enable(); - bool bg3_color_enable(); - bool bg4_color_enable(); - bool oam_color_enable(); - bool back_color_enable(); - - //$2132 - unsigned color_constant_blue(); - unsigned color_constant_green(); - unsigned color_constant_red(); - - //$2133 - bool mode7_extbg(); - bool pseudo_hires(); - bool overscan_enable(); - bool oam_interlace(); - bool interlace_enable(); - - //$213c - unsigned hcounter(); - - //$213d - unsigned vcounter(); - - //$213e - bool range_over(); - bool time_over(); - unsigned ppu1_version(); - - //$213f - bool field(); - bool region(); - unsigned ppu2_version(); }; diff --git a/snes/fast/ppu/debugger/render.cpp b/snes/fast/ppu/debugger/render.cpp index 5e6ff6e9..f6a999e1 100755 --- a/snes/fast/ppu/debugger/render.cpp +++ b/snes/fast/ppu/debugger/render.cpp @@ -1,6 +1,6 @@ #ifdef PPU_CPP -//render_line_modeN() taken from src/ppu/bppu/render/render.cpp +//render_line_modeN(): //modified to support layer disable; accomplished by setting priority to zero //a priority of zero won't override the back layer, effectively nullifying it //for speed, rendering loop is skipped entirely if all priorities are disabled diff --git a/snes/fast/smp/iplrom.cpp b/snes/fast/smp/iplrom.cpp deleted file mode 100755 index a2ade89d..00000000 --- a/snes/fast/smp/iplrom.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifdef SMP_CPP - -//this is the IPLROM for the S-SMP coprocessor. -//the S-SMP does not allow writing to the IPLROM. -//all writes are instead mapped to the extended -//RAM region, accessible when $f1.d7 is clear. - -const uint8 SMP::iplrom[64] = { -/*ffc0*/ 0xcd, 0xef, //mov x,#$ef -/*ffc2*/ 0xbd, //mov sp,x -/*ffc3*/ 0xe8, 0x00, //mov a,#$00 -/*ffc5*/ 0xc6, //mov (x),a -/*ffc6*/ 0x1d, //dec x -/*ffc7*/ 0xd0, 0xfc, //bne $ffc5 -/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa -/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb -/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc -/*ffd2*/ 0xd0, 0xfb, //bne $ffcf -/*ffd4*/ 0x2f, 0x19, //bra $ffef -/*ffd6*/ 0xeb, 0xf4, //mov y,$f4 -/*ffd8*/ 0xd0, 0xfc, //bne $ffd6 -/*ffda*/ 0x7e, 0xf4, //cmp y,$f4 -/*ffdc*/ 0xd0, 0x0b, //bne $ffe9 -/*ffde*/ 0xe4, 0xf5, //mov a,$f5 -/*ffe0*/ 0xcb, 0xf4, //mov $f4,y -/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a -/*ffe4*/ 0xfc, //inc y -/*ffe5*/ 0xd0, 0xf3, //bne $ffda -/*ffe7*/ 0xab, 0x01, //inc $01 -/*ffe9*/ 0x10, 0xef, //bpl $ffda -/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4 -/*ffed*/ 0x10, 0xeb, //bpl $ffda -/*ffef*/ 0xba, 0xf6, //movw ya,$f6 -/*fff1*/ 0xda, 0x00, //movw $00,ya -/*fff3*/ 0xba, 0xf4, //movw ya,$f4 -/*fff5*/ 0xc4, 0xf4, //mov $f4,a -/*fff7*/ 0xdd, //mov a,y -/*fff8*/ 0x5d, //mov x,a -/*fff9*/ 0xd0, 0xdb, //bne $ffd6 -/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x) -/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0) -}; - -#endif diff --git a/snes/fast/smp/serialization.cpp b/snes/fast/smp/serialization.cpp deleted file mode 100755 index ea7c695d..00000000 --- a/snes/fast/smp/serialization.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifdef SMP_CPP - -static void smp_state_save(unsigned char **out, void *in, size_t size) { - memcpy(*out, in, size); - *out += size; -} - -static void smp_state_load(unsigned char **in, void *out, size_t size) { - memcpy(out, *in, size); - *in += size; -} - -void SMP::serialize(serializer &s) { - Processor::serialize(s); - s.integer(snes_spc_time); - s.array(samplebuffer); - - unsigned char state[SNES_SPC::state_size]; - unsigned char *p = state; - memset(&state, 0, SNES_SPC::state_size); - if(s.mode() == serializer::Save) { - snes_spc.copy_state(&p, smp_state_save); - s.array(state); - } else if(s.mode() == serializer::Load) { - s.array(state); - snes_spc.copy_state(&p, smp_state_load); - } else { - s.array(state); - } -} - -#endif diff --git a/snes/fast/smp/smp.cpp b/snes/fast/smp/smp.cpp deleted file mode 100755 index 8124778b..00000000 --- a/snes/fast/smp/smp.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include - -#define SMP_CPP -namespace SNES { - -SMP smp; - -#include "../snes_spc/dsp.cpp" -#include "../snes_spc/SNES_SPC.cpp" -#include "../snes_spc/SNES_SPC_misc.cpp" -#include "../snes_spc/SNES_SPC_state.cpp" -#include "../snes_spc/spc.cpp" -#include "../snes_spc/SPC_DSP.cpp" -#include "../snes_spc/SPC_Filter.cpp" - -#include "serialization.cpp" -#include "iplrom.cpp" - -void SMP::step(unsigned clocks) { - clock += clocks * (uint64)cpu.frequency; -} - -void SMP::synchronize_cpu() { - if(CPU::Threaded == true) { - if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); - } else { - while(clock >= 0) cpu.enter(); - } -} - -void SMP::synchronize_dsp() { - if(DSP::Threaded == true) { - if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread); - } else { - while(dsp.clock < 0) dsp.enter(); - } -} - -uint8 SMP::port_read(uint8 port) { - return snes_spc.read_port(snes_spc_time, port & 3); -} - -void SMP::port_write(uint8 port, uint8 data) { - snes_spc.write_port(snes_spc_time, port & 3, data); -} - -void SMP::enter() { - step(24); - if(++snes_spc_time >= snes_spc.clock_rate / 60) { - snes_spc.end_frame(snes_spc_time); - snes_spc_time = 0; - - signed count = snes_spc.sample_count(); - if(count > 0) { - for(unsigned n = 0; n < count; n += 2) audio.sample(samplebuffer[n + 0], samplebuffer[n + 1]); - snes_spc.set_output(samplebuffer, 8192); - } - - //while(signed count = snes_spc.read_samples(buffer, 8192)) { - // for(unsigned n = 0; n < count; n += 2) audio.sample(samplebuffer[n + 0], samplebuffer[n + 1]); - //} - } -} - -static void Enter() {} - -void SMP::power() { - create(Enter, 24576000); //system.apu_frequency() - snes_spc.init(); - snes_spc.init_rom(iplrom); - snes_spc.reset(); - snes_spc_time = 0; -} - -void SMP::reset() { - snes_spc.soft_reset(); - snes_spc.set_output(samplebuffer, 8192); - snes_spc_time = 0; -} - -SMP::SMP() { -} - -SMP::~SMP() { -} - -} diff --git a/snes/fast/smp/smp.hpp b/snes/fast/smp/smp.hpp deleted file mode 100755 index cc37e072..00000000 --- a/snes/fast/smp/smp.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "../snes_spc/SNES_SPC.h" - -class SMP : public Processor { -public: - enum : bool { Threaded = false }; - alwaysinline void step(unsigned clocks); - alwaysinline void synchronize_cpu(); - alwaysinline void synchronize_dsp(); - - uint8 port_read(uint8 port); - void port_write(uint8 port, uint8 data); - - void enter(); - void power(); - void reset(); - - void serialize(serializer&); - SMP(); - ~SMP(); - -private: - SNES_SPC snes_spc; - unsigned snes_spc_time; - int16 samplebuffer[8192]; - static const uint8 iplrom[64]; - - friend class SMPcore; -}; - -extern SMP smp; diff --git a/snes/fast/snes_spc/SNES_SPC.cpp b/snes/fast/snes_spc/SNES_SPC.cpp deleted file mode 100755 index fb3b147a..00000000 --- a/snes/fast/snes_spc/SNES_SPC.cpp +++ /dev/null @@ -1,564 +0,0 @@ -// Core SPC emulation: CPU, timers, SMP registers, memory - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#include - -/* Copyright (C) 2004-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 */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - -// Note: SPC_MORE_ACCURACY exists mainly so I can run my validation tests, which -// do crazy echo buffer accesses. -#ifndef SPC_MORE_ACCURACY - #define SPC_MORE_ACCURACY 0 -#endif - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - - -//// Timers - -#if SPC_DISABLE_TEMPO - #define TIMER_DIV( t, n ) ((n) >> t->prescaler) - #define TIMER_MUL( t, n ) ((n) << t->prescaler) -#else - #define TIMER_DIV( t, n ) ((n) / t->prescaler) - #define TIMER_MUL( t, n ) ((n) * t->prescaler) -#endif - -SNES_SPC::Timer* SNES_SPC::run_timer_( Timer* t, rel_time_t time ) -{ - int elapsed = TIMER_DIV( t, time - t->next_time ) + 1; - t->next_time += TIMER_MUL( t, elapsed ); - - if ( t->enabled ) - { - int remain = IF_0_THEN_256( t->period - t->divider ); - int divider = t->divider + elapsed; - int over = elapsed - remain; - if ( over >= 0 ) - { - int n = over / t->period; - t->counter = (t->counter + 1 + n) & 0x0F; - divider = over - n * t->period; - } - t->divider = (uint8_t) divider; - } - return t; -} - -inline SNES_SPC::Timer* SNES_SPC::run_timer( Timer* t, rel_time_t time ) -{ - if ( time >= t->next_time ) - t = run_timer_( t, time ); - return t; -} - - -//// ROM - -void SNES_SPC::enable_rom( int enable ) -{ - if ( m.rom_enabled != enable ) - { - m.rom_enabled = enable; - if ( enable ) - memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram ); - memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size ); - // TODO: ROM can still get overwritten when DSP writes to echo buffer - } -} - - -//// DSP - -#if SPC_LESS_ACCURATE - int const max_reg_time = 29; - - signed char const SNES_SPC::reg_times_ [256] = - { - -1, 0,-11,-10,-15,-11, -2, -2, 4, 3, 14, 14, 26, 26, 14, 22, - 2, 3, 0, 1,-12, 0, 1, 1, 7, 6, 14, 14, 27, 14, 14, 23, - 5, 6, 3, 4, -1, 3, 4, 4, 10, 9, 14, 14, 26, -5, 14, 23, - 8, 9, 6, 7, 2, 6, 7, 7, 13, 12, 14, 14, 27, -4, 14, 24, - 11, 12, 9, 10, 5, 9, 10, 10, 16, 15, 14, 14, -2, -4, 14, 24, - 14, 15, 12, 13, 8, 12, 13, 13, 19, 18, 14, 14, -2,-36, 14, 24, - 17, 18, 15, 16, 11, 15, 16, 16, 22, 21, 14, 14, 28, -3, 14, 25, - 20, 21, 18, 19, 14, 18, 19, 19, 25, 24, 14, 14, 14, 29, 14, 25, - - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - }; - - #define RUN_DSP( time, offset ) \ - int count = (time) - (offset) - m.dsp_time;\ - if ( count >= 0 )\ - {\ - int clock_count = (count & ~(clocks_per_sample - 1)) + clocks_per_sample;\ - m.dsp_time += clock_count;\ - dsp.run( clock_count );\ - } -#else - #define RUN_DSP( time, offset ) \ - {\ - int count = (time) - m.dsp_time;\ - if ( !SPC_MORE_ACCURACY || count )\ - {\ - assert( count > 0 );\ - m.dsp_time = (time);\ - dsp.run( count );\ - }\ - } -#endif - -int SNES_SPC::dsp_read( rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr] & 0x7F] ); - - int result = dsp.read( REGS [r_dspaddr] & 0x7F ); - - #ifdef SPC_DSP_READ_HOOK - SPC_DSP_READ_HOOK( spc_time + time, (REGS [r_dspaddr] & 0x7F), result ); - #endif - - return result; -} - -inline void SNES_SPC::dsp_write( int data, rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr]] ) - #if SPC_LESS_ACCURATE - else if ( m.dsp_time == skipping_time ) - { - int r = REGS [r_dspaddr]; - if ( r == SPC_DSP::r_kon ) - m.skipped_kon |= data & ~dsp.read( SPC_DSP::r_koff ); - - if ( r == SPC_DSP::r_koff ) - { - m.skipped_koff |= data; - m.skipped_kon &= ~data; - } - } - #endif - - #ifdef SPC_DSP_WRITE_HOOK - SPC_DSP_WRITE_HOOK( m.spc_time + time, REGS [r_dspaddr], (uint8_t) data ); - #endif - - if ( REGS [r_dspaddr] <= 0x7F ) - dsp.write( REGS [r_dspaddr], data ); - else if ( !SPC_MORE_ACCURACY ) - dprintf( "SPC wrote to DSP register > $7F\n" ); -} - - -//// Memory access extras - -#if SPC_MORE_ACCURACY - #define MEM_ACCESS( time, addr ) \ - {\ - if ( time >= m.dsp_time )\ - {\ - RUN_DSP( time, max_reg_time );\ - }\ - } -#elif !defined (NDEBUG) - // Debug-only check for read/write within echo buffer, since this might result in - // inaccurate emulation due to the DSP not being caught up to the present. - - bool SNES_SPC::check_echo_access( int addr ) - { - if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) - { - int start = 0x100 * dsp.read( SPC_DSP::r_esa ); - int size = 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); - int end = start + (size ? size : 4); - if ( start <= addr && addr < end ) - { - if ( !m.echo_accessed ) - { - m.echo_accessed = 1; - return true; - } - } - } - return false; - } - - #define MEM_ACCESS( time, addr ) check( !check_echo_access( (uint16_t) addr ) ); -#else - #define MEM_ACCESS( time, addr ) -#endif - - -//// CPU write - -#if SPC_MORE_ACCURACY -static unsigned char const glitch_probs [3] [256] = -{ - 0xC3,0x92,0x5B,0x1C,0xD1,0x92,0x5B,0x1C,0xDB,0x9C,0x72,0x18,0xCD,0x5C,0x38,0x0B, - 0xE1,0x9C,0x74,0x17,0xCF,0x75,0x45,0x0C,0xCF,0x6E,0x4A,0x0D,0xA3,0x3A,0x1D,0x08, - 0xDB,0xA0,0x82,0x19,0xD9,0x73,0x3C,0x0E,0xCB,0x76,0x52,0x0B,0xA5,0x46,0x1D,0x09, - 0xDA,0x74,0x55,0x0F,0xA2,0x3F,0x21,0x05,0x9A,0x40,0x20,0x07,0x63,0x1E,0x10,0x01, - 0xDF,0xA9,0x85,0x1D,0xD3,0x84,0x4B,0x0E,0xCF,0x6F,0x49,0x0F,0xB3,0x48,0x1E,0x05, - 0xD8,0x77,0x52,0x12,0xB7,0x49,0x23,0x06,0xAA,0x45,0x28,0x07,0x7D,0x28,0x0F,0x07, - 0xCC,0x7B,0x4A,0x0E,0xB2,0x4F,0x24,0x07,0xAD,0x43,0x2C,0x06,0x86,0x29,0x11,0x07, - 0xAE,0x48,0x1F,0x0A,0x76,0x21,0x19,0x05,0x76,0x21,0x14,0x05,0x44,0x11,0x0B,0x01, - 0xE7,0xAD,0x96,0x23,0xDC,0x86,0x59,0x0E,0xDC,0x7C,0x5F,0x15,0xBB,0x53,0x2E,0x09, - 0xD6,0x7C,0x4A,0x16,0xBB,0x4A,0x25,0x08,0xB3,0x4F,0x28,0x0B,0x8E,0x23,0x15,0x08, - 0xCF,0x7F,0x57,0x11,0xB5,0x4A,0x23,0x0A,0xAA,0x42,0x28,0x05,0x7D,0x22,0x12,0x03, - 0xA6,0x49,0x28,0x09,0x82,0x2B,0x0D,0x04,0x7A,0x20,0x0F,0x04,0x3D,0x0F,0x09,0x03, - 0xD1,0x7C,0x4C,0x0F,0xAF,0x4E,0x21,0x09,0xA8,0x46,0x2A,0x07,0x85,0x1F,0x0E,0x07, - 0xA6,0x3F,0x26,0x07,0x7C,0x24,0x14,0x07,0x78,0x22,0x16,0x04,0x46,0x12,0x0A,0x02, - 0xA6,0x41,0x2C,0x0A,0x7E,0x28,0x11,0x05,0x73,0x1B,0x14,0x05,0x3D,0x11,0x0A,0x02, - 0x70,0x22,0x17,0x05,0x48,0x13,0x08,0x03,0x3C,0x07,0x0D,0x07,0x26,0x07,0x06,0x01, - - 0xE0,0x9F,0xDA,0x7C,0x4F,0x18,0x28,0x0D,0xE9,0x9F,0xDA,0x7C,0x4F,0x18,0x1F,0x07, - 0xE6,0x97,0xD8,0x72,0x64,0x13,0x26,0x09,0xDC,0x67,0xA9,0x38,0x21,0x07,0x15,0x06, - 0xE9,0x91,0xD2,0x6B,0x63,0x14,0x2B,0x0E,0xD6,0x61,0xB7,0x41,0x2B,0x0E,0x10,0x09, - 0xCF,0x59,0xB0,0x2F,0x35,0x08,0x0F,0x07,0xB6,0x30,0x7A,0x21,0x17,0x07,0x09,0x03, - 0xE7,0xA3,0xE5,0x6B,0x65,0x1F,0x34,0x09,0xD8,0x6B,0xBE,0x45,0x27,0x07,0x10,0x07, - 0xDA,0x54,0xB1,0x39,0x2E,0x0E,0x17,0x08,0xA9,0x3C,0x86,0x22,0x16,0x06,0x07,0x03, - 0xD4,0x51,0xBC,0x3D,0x38,0x0A,0x13,0x06,0xB2,0x37,0x79,0x1C,0x17,0x05,0x0E,0x06, - 0xA7,0x31,0x74,0x1C,0x11,0x06,0x0C,0x02,0x6D,0x1A,0x38,0x10,0x0B,0x05,0x06,0x03, - 0xEB,0x9A,0xE1,0x7A,0x6F,0x13,0x34,0x0E,0xE6,0x75,0xC5,0x45,0x3E,0x0B,0x1A,0x05, - 0xD8,0x63,0xC1,0x40,0x3C,0x1B,0x19,0x06,0xB3,0x42,0x83,0x29,0x18,0x0A,0x08,0x04, - 0xD4,0x58,0xBA,0x43,0x3F,0x0A,0x1F,0x09,0xB1,0x33,0x8A,0x1F,0x1F,0x06,0x0D,0x05, - 0xAF,0x3C,0x7A,0x1F,0x16,0x08,0x0A,0x01,0x72,0x1B,0x52,0x0D,0x0B,0x09,0x06,0x01, - 0xCF,0x63,0xB7,0x47,0x40,0x10,0x14,0x06,0xC0,0x41,0x96,0x20,0x1C,0x09,0x10,0x05, - 0xA6,0x35,0x82,0x1A,0x20,0x0C,0x0E,0x04,0x80,0x1F,0x53,0x0F,0x0B,0x02,0x06,0x01, - 0xA6,0x31,0x81,0x1B,0x1D,0x01,0x08,0x08,0x7B,0x20,0x4D,0x19,0x0E,0x05,0x07,0x03, - 0x6B,0x17,0x49,0x07,0x0E,0x03,0x0A,0x05,0x37,0x0B,0x1F,0x06,0x04,0x02,0x07,0x01, - - 0xF0,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x47,0x1E,0x6E,0x1B,0x32,0x0A, - 0xF0,0xD6,0xEA,0xA4,0xED,0xC4,0xDE,0x82,0x98,0x1F,0x50,0x13,0x52,0x15,0x2A,0x0A, - 0xF1,0xD1,0xEB,0xA2,0xEB,0xB7,0xD8,0x69,0xA2,0x1F,0x5B,0x18,0x55,0x18,0x2C,0x0A, - 0xED,0xB5,0xDE,0x7E,0xE6,0x85,0xD3,0x59,0x59,0x0F,0x2C,0x09,0x24,0x07,0x15,0x09, - 0xF1,0xD6,0xEA,0xA0,0xEC,0xBB,0xDA,0x77,0xA9,0x23,0x58,0x14,0x5D,0x12,0x2F,0x09, - 0xF1,0xC1,0xE3,0x86,0xE4,0x87,0xD2,0x4E,0x68,0x15,0x26,0x0B,0x27,0x09,0x15,0x02, - 0xEE,0xA6,0xE0,0x5C,0xE0,0x77,0xC3,0x41,0x67,0x1B,0x3C,0x07,0x2A,0x06,0x19,0x07, - 0xE4,0x75,0xC6,0x43,0xCC,0x50,0x95,0x23,0x35,0x09,0x14,0x04,0x15,0x05,0x0B,0x04, - 0xEE,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x56,0x14,0x5A,0x12,0x26,0x0A, - 0xEE,0xBB,0xE7,0x7E,0xE9,0x8D,0xCB,0x49,0x67,0x11,0x34,0x07,0x2B,0x0B,0x14,0x07, - 0xED,0xA7,0xE5,0x76,0xE3,0x7E,0xC4,0x4B,0x77,0x14,0x34,0x08,0x27,0x07,0x14,0x04, - 0xE7,0x8B,0xD2,0x4C,0xCA,0x56,0x9E,0x31,0x36,0x0C,0x11,0x07,0x14,0x04,0x0A,0x02, - 0xF0,0x9B,0xEA,0x6F,0xE5,0x81,0xC4,0x43,0x74,0x10,0x30,0x0B,0x2D,0x08,0x1B,0x06, - 0xE6,0x83,0xCA,0x48,0xD9,0x56,0xA7,0x23,0x3B,0x09,0x12,0x09,0x15,0x07,0x0A,0x03, - 0xE5,0x5F,0xCB,0x3C,0xCF,0x48,0x91,0x22,0x31,0x0A,0x17,0x08,0x15,0x04,0x0D,0x02, - 0xD1,0x43,0x91,0x20,0xA9,0x2D,0x54,0x12,0x17,0x07,0x09,0x02,0x0C,0x04,0x05,0x03, -}; -#endif - -// divided into multiple functions to keep rarely-used functionality separate -// so often-used functionality can be optimized better by compiler - -// If write isn't preceded by read, data has this added to it -int const no_read_before_write = 0x2000; - -void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, int addr ) -{ - switch ( addr ) - { - case r_t0target: - case r_t1target: - case r_t2target: { - Timer* t = &m.timers [addr - r_t0target]; - int period = IF_0_THEN_256( data ); - if ( t->period != period ) - { - t = run_timer( t, time ); - #if SPC_MORE_ACCURACY - // Insane behavior when target is written just after counter is - // clocked and counter matches new period and new period isn't 1, 2, 4, or 8 - if ( t->divider == (period & 0xFF) && - t->next_time == time + TIMER_MUL( t, 1 ) && - ((period - 1) | ~0x0F) & period ) - { - //dprintf( "SPC pathological timer target write\n" ); - - // If the period is 3, 5, or 9, there's a probability this behavior won't occur, - // based on the previous period - int prob = 0xFF; - int old_period = t->period & 0xFF; - if ( period == 3 ) prob = glitch_probs [0] [old_period]; - if ( period == 5 ) prob = glitch_probs [1] [old_period]; - if ( period == 9 ) prob = glitch_probs [2] [old_period]; - - // The glitch suppresses incrementing of one of the counter bits, based on - // the lowest set bit in the new period - int b = 1; - while ( !(period & b) ) - b <<= 1; - - if ( (rand() >> 4 & 0xFF) <= prob ) - t->divider = (t->divider - b) & 0xFF; - } - #endif - t->period = period; - } - break; - } - - case r_t0out: - case r_t1out: - case r_t2out: - if ( !SPC_MORE_ACCURACY ) - dprintf( "SPC wrote to counter %d\n", (int) addr - r_t0out ); - - if ( data < no_read_before_write / 2 ) - run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0; - break; - - // Registers that act like RAM - case 0x8: - case 0x9: - REGS_IN [addr] = (uint8_t) data; - break; - - case r_test: - if ( (uint8_t) data != 0x0A ) - dprintf( "SPC wrote to test register\n" ); - break; - - case r_control: - // port clears - if ( data & 0x10 ) - { - REGS_IN [r_cpuio0] = 0; - REGS_IN [r_cpuio1] = 0; - } - if ( data & 0x20 ) - { - REGS_IN [r_cpuio2] = 0; - REGS_IN [r_cpuio3] = 0; - } - - // timers - { - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - int enabled = data >> i & 1; - if ( t->enabled != enabled ) - { - t = run_timer( t, time ); - t->enabled = enabled; - if ( enabled ) - { - t->divider = 0; - t->counter = 0; - } - } - } - } - enable_rom( data & 0x80 ); - break; - } -} - -void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr ) -{ - if ( addr == r_dspdata ) // 99% - dsp_write( data, time ); - else - cpu_write_smp_reg_( data, time, addr ); -} - -void SNES_SPC::cpu_write_high( int data, int i, rel_time_t time ) -{ - if ( i < rom_size ) - { - m.hi_ram [i] = (uint8_t) data; - if ( m.rom_enabled ) - RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM - } - else - { - assert( RAM [i + rom_addr] == (uint8_t) data ); - RAM [i + rom_addr] = cpu_pad_fill; // restore overwritten padding - cpu_write( data, i + rom_addr - 0x10000, time ); - } -} - -int const bits_in_int = CHAR_BIT * sizeof (int); - -void SNES_SPC::cpu_write( int data, int addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - RAM [addr] = (uint8_t) data; - int reg = addr - 0xF0; - if ( reg >= 0 ) // 64% - { - // $F0-$FF - if ( reg < reg_count ) // 87% - { - REGS [reg] = (uint8_t) data; - - // Ports - #ifdef SPC_PORT_WRITE_HOOK - if ( (unsigned) (reg - r_cpuio0) < port_count ) - SPC_PORT_WRITE_HOOK( m.spc_time + time, (reg - r_cpuio0), - (uint8_t) data, ®S [r_cpuio0] ); - #endif - - // Registers other than $F2 and $F4-$F7 - //if ( reg != 2 && reg != 4 && reg != 5 && reg != 6 && reg != 7 ) - // TODO: this is a bit on the fragile side - if ( ((~0x2F00 << (bits_in_int - 16)) << reg) < 0 ) // 36% - cpu_write_smp_reg( data, time, reg ); - } - // High mem/address wrap-around - else - { - reg -= rom_addr - 0xF0; - if ( reg >= 0 ) // 1% in IPL ROM area or address wrapped around - cpu_write_high( data, reg, time ); - } - } -} - - -//// CPU read - -inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time ) -{ - int result = REGS_IN [reg]; - reg -= r_dspaddr; - // DSP addr and data - if ( (unsigned) reg <= 1 ) // 4% 0xF2 and 0xF3 - { - result = REGS [r_dspaddr]; - if ( (unsigned) reg == 1 ) - result = dsp_read( time ); // 0xF3 - } - return result; -} - -int SNES_SPC::cpu_read( int addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - int result = RAM [addr]; - int reg = addr - 0xF0; - if ( reg >= 0 ) // 40% - { - reg -= 0x10; - if ( (unsigned) reg >= 0xFF00 ) // 21% - { - reg += 0x10 - r_t0out; - - // Timers - if ( (unsigned) reg < timer_count ) // 90% - { - Timer* t = &m.timers [reg]; - if ( time >= t->next_time ) - t = run_timer_( t, time ); - result = t->counter; - t->counter = 0; - } - // Other registers - else if ( reg < 0 ) // 10% - { - result = cpu_read_smp_reg( reg + r_t0out, time ); - } - else // 1% - { - assert( reg + (r_t0out + 0xF0 - 0x10000) < 0x100 ); - result = cpu_read( reg + (r_t0out + 0xF0 - 0x10000), time ); - } - } - } - - return result; -} - - -//// Run - -// Prefix and suffix for CPU emulator function -#define SPC_CPU_RUN_FUNC \ -BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\ -{\ - rel_time_t rel_time = m.spc_time - end_time;\ - assert( rel_time <= 0 );\ - m.spc_time = end_time;\ - m.dsp_time += rel_time;\ - m.timers [0].next_time += rel_time;\ - m.timers [1].next_time += rel_time;\ - m.timers [2].next_time += rel_time; - -#define SPC_CPU_RUN_FUNC_END \ - m.spc_time += rel_time;\ - m.dsp_time -= rel_time;\ - m.timers [0].next_time -= rel_time;\ - m.timers [1].next_time -= rel_time;\ - m.timers [2].next_time -= rel_time;\ - assert( m.spc_time <= end_time );\ - return ®S [r_cpuio0];\ -} - -int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks - -void SNES_SPC::end_frame( time_t end_time ) -{ - // Catch CPU up to as close to end as possible. If final instruction - // would exceed end, does NOT execute it and leaves m.spc_time < end. - if ( end_time > m.spc_time ) - run_until_( end_time ); - - m.spc_time -= end_time; - m.extra_clocks += end_time; - - // Greatest number of clocks early that emulation can stop early due to - // not being able to execute current instruction without going over - // allowed time. - assert( -cpu_lag_max <= m.spc_time && m.spc_time <= 0 ); - - // Catch timers up to CPU - for ( int i = 0; i < timer_count; i++ ) - run_timer( &m.timers [i], 0 ); - - // Catch DSP up to CPU - if ( m.dsp_time < 0 ) - { - RUN_DSP( 0, max_reg_time ); - } - - // Save any extra samples beyond what should be generated - if ( m.buf_begin ) - save_extra(); -} - -// Inclusion here allows static memory access functions and better optimization -#include "SPC_CPU.h" diff --git a/snes/fast/snes_spc/SNES_SPC.h b/snes/fast/snes_spc/SNES_SPC.h deleted file mode 100755 index 8ea0392f..00000000 --- a/snes/fast/snes_spc/SNES_SPC.h +++ /dev/null @@ -1,279 +0,0 @@ -// SNES SPC-700 APU emulator - -// snes_spc 0.9.0 -#ifndef SNES_SPC_H -#define SNES_SPC_H - -#include "SPC_DSP.h" -#include "blargg_endian.h" - -struct SNES_SPC { -public: - typedef BOOST::uint8_t uint8_t; - - // Must be called once before using - blargg_err_t init(); - - // Sample pairs generated per second - enum { sample_rate = 32000 }; - -// Emulator use - - // Sets IPL ROM data. Library does not include ROM data. Most SPC music files - // don't need ROM, but a full emulator must provide this. - enum { rom_size = 0x40 }; - void init_rom( uint8_t const rom [rom_size] ); - - // Sets destination for output samples - typedef short sample_t; - void set_output( sample_t* out, int out_size ); - - // Number of samples written to output since last set - int sample_count() const; - - // Resets SPC to power-on state. This resets your output buffer, so you must - // call set_output() after this. - void reset(); - - // Emulates pressing reset switch on SNES. This resets your output buffer, so - // you must call set_output() after this. - void soft_reset(); - - // 1024000 SPC clocks per second, sample pair every 32 clocks - typedef int time_t; - enum { clock_rate = 1024000 }; - enum { clocks_per_sample = 32 }; - - // Emulated port read/write at specified time - enum { port_count = 4 }; - int read_port ( time_t, int port ); - void write_port( time_t, int port, int data ); - - // Runs SPC to end_time and starts a new time frame at 0 - void end_frame( time_t end_time ); - -// Sound control - - // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). - // Reduces emulation accuracy. - enum { voice_count = 8 }; - void mute_voices( int mask ); - - // If true, prevents channels and global volumes from being phase-negated. - // Only supported by fast DSP. - void disable_surround( bool disable = true ); - - // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. - enum { tempo_unit = 0x100 }; - void set_tempo( int ); - -// SPC music files - - // Loads SPC data into emulator - enum { spc_min_file_size = 0x10180 }; - enum { spc_file_size = 0x10200 }; - blargg_err_t load_spc( void const* in, long size ); - - // Clears echo region. Useful after loading an SPC as many have garbage in echo. - void clear_echo(); - - // Plays for count samples and write samples to out. Discards samples if out - // is NULL. Count must be a multiple of 2 since output is stereo. - blargg_err_t play( int count, sample_t* out ); - - // Skips count samples. Several times faster than play() when using fast DSP. - blargg_err_t skip( int count ); - -// State save/load (only available with accurate DSP) - -#if !SPC_NO_COPY_STATE_FUNCS - // Saves/loads state - enum { state_size = 67 * 1024L }; // maximum space needed when saving - typedef SPC_DSP::copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); - - // Writes minimal header to spc_out - static void init_header( void* spc_out ); - - // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. - // Does not set up SPC header; use init_header() for that. - void save_spc( void* spc_out ); - - // Returns true if new key-on events occurred since last check. Useful for - // trimming silence while saving an SPC. - bool check_kon(); -#endif - -public: - BLARGG_DISABLE_NOTHROW - - typedef BOOST::uint16_t uint16_t; - - // Time relative to m_spc_time. Speeds up code a bit by eliminating need to - // constantly add m_spc_time to time from CPU. CPU uses time that ends at - // 0 to eliminate reloading end time every instruction. It pays off. - typedef int rel_time_t; - - struct Timer - { - rel_time_t next_time; // time of next event - int prescaler; - int period; - int divider; - int enabled; - int counter; - }; - enum { reg_count = 0x10 }; - enum { timer_count = 3 }; - enum { extra_size = SPC_DSP::extra_size }; - - enum { signature_size = 35 }; - -private: - SPC_DSP dsp; - - #if SPC_LESS_ACCURATE - static signed char const reg_times_ [256]; - signed char reg_times [256]; - #endif - - struct state_t - { - Timer timers [timer_count]; - - uint8_t smp_regs [2] [reg_count]; - - struct - { - int pc; - int a; - int x; - int y; - int psw; - int sp; - } cpu_regs; - - rel_time_t dsp_time; - time_t spc_time; - bool echo_accessed; - - int tempo; - int skipped_kon; - int skipped_koff; - const char* cpu_error; - - int extra_clocks; - sample_t* buf_begin; - sample_t const* buf_end; - sample_t* extra_pos; - sample_t extra_buf [extra_size]; - - int rom_enabled; - uint8_t rom [rom_size]; - uint8_t hi_ram [rom_size]; - - unsigned char cycle_table [256]; - - struct - { - // padding to neutralize address overflow - union { - uint8_t padding1 [0x100]; - uint16_t align; // makes compiler align data for 16-bit access - } padding1 [1]; - uint8_t ram [0x10000]; - uint8_t padding2 [0x100]; - } ram; - }; - state_t m; - - enum { rom_addr = 0xFFC0 }; - - enum { skipping_time = 127 }; - - // Value that padding should be filled with - enum { cpu_pad_fill = 0xFF }; - - enum { - r_test = 0x0, r_control = 0x1, - r_dspaddr = 0x2, r_dspdata = 0x3, - r_cpuio0 = 0x4, r_cpuio1 = 0x5, - r_cpuio2 = 0x6, r_cpuio3 = 0x7, - r_f8 = 0x8, r_f9 = 0x9, - r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC, - r_t0out = 0xD, r_t1out = 0xE, r_t2out = 0xF - }; - - void timers_loaded(); - void enable_rom( int enable ); - void reset_buf(); - void save_extra(); - void load_regs( uint8_t const in [reg_count] ); - void ram_loaded(); - void regs_loaded(); - void reset_time_regs(); - void reset_common( int timer_counter_init ); - - Timer* run_timer_ ( Timer* t, rel_time_t ); - Timer* run_timer ( Timer* t, rel_time_t ); - int dsp_read ( rel_time_t ); - void dsp_write ( int data, rel_time_t ); - void cpu_write_smp_reg_( int data, rel_time_t, int addr ); - void cpu_write_smp_reg ( int data, rel_time_t, int addr ); - void cpu_write_high ( int data, int i, rel_time_t ); - void cpu_write ( int data, int addr, rel_time_t ); - int cpu_read_smp_reg ( int i, rel_time_t ); - int cpu_read ( int addr, rel_time_t ); - unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t ); - - bool check_echo_access ( int addr ); - uint8_t* run_until_( time_t end_time ); - - struct spc_file_t - { - char signature [signature_size]; - uint8_t has_id666; - uint8_t version; - uint8_t pcl, pch; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t psw; - uint8_t sp; - char text [212]; - uint8_t ram [0x10000]; - uint8_t dsp [128]; - uint8_t unused [0x40]; - uint8_t ipl_rom [0x40]; - }; - - static char const signature [signature_size + 1]; - - void save_regs( uint8_t out [reg_count] ); -}; - -#include - -inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; } - -inline int SNES_SPC::read_port( time_t t, int port ) -{ - assert( (unsigned) port < port_count ); - return run_until_( t ) [port]; -} - -inline void SNES_SPC::write_port( time_t t, int port, int data ) -{ - assert( (unsigned) port < port_count ); - run_until_( t ) [0x10 + port] = data; -} - -inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); } - -inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); } - -#if !SPC_NO_COPY_STATE_FUNCS -inline bool SNES_SPC::check_kon() { return dsp.check_kon(); } -#endif - -#endif diff --git a/snes/fast/snes_spc/SNES_SPC_misc.cpp b/snes/fast/snes_spc/SNES_SPC_misc.cpp deleted file mode 100755 index 87288ab8..00000000 --- a/snes/fast/snes_spc/SNES_SPC_misc.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// SPC emulation support: init, sample buffering, reset, SPC loading - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#include - -/* Copyright (C) 2004-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 */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - - -//// Init - -blargg_err_t SNES_SPC::init() -{ - memset( &m, 0, sizeof m ); - dsp.init( RAM ); - - m.tempo = tempo_unit; - - // Most SPC music doesn't need ROM, and almost all the rest only rely - // on these two bytes - m.rom [0x3E] = 0xFF; - m.rom [0x3F] = 0xC0; - - static unsigned char const cycle_table [128] = - {// 01 23 45 67 89 AB CD EF - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x68, // 0 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x46, // 1 - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x74, // 2 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x38, // 3 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x66, // 4 - 0x48,0x47,0x45,0x56,0x55,0x45,0x22,0x43, // 5 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x75, // 6 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x36, // 7 - 0x28,0x47,0x34,0x36,0x26,0x54,0x52,0x45, // 8 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0xC5, // 9 - 0x38,0x47,0x34,0x36,0x26,0x44,0x52,0x44, // A - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x34, // B - 0x38,0x47,0x45,0x47,0x25,0x64,0x52,0x49, // C - 0x48,0x47,0x56,0x67,0x45,0x55,0x22,0x83, // D - 0x28,0x47,0x34,0x36,0x24,0x53,0x43,0x40, // E - 0x48,0x47,0x45,0x56,0x34,0x54,0x22,0x60, // F - }; - - // unpack cycle table - for ( int i = 0; i < 128; i++ ) - { - int n = cycle_table [i]; - m.cycle_table [i * 2 + 0] = n >> 4; - m.cycle_table [i * 2 + 1] = n & 0x0F; - } - - #if SPC_LESS_ACCURATE - memcpy( reg_times, reg_times_, sizeof reg_times ); - #endif - - reset(); - return 0; -} - -void SNES_SPC::init_rom( uint8_t const in [rom_size] ) -{ - memcpy( m.rom, in, sizeof m.rom ); -} - -void SNES_SPC::set_tempo( int t ) -{ - m.tempo = t; - int const timer2_shift = 4; // 64 kHz - int const other_shift = 3; // 8 kHz - - #if SPC_DISABLE_TEMPO - m.timers [2].prescaler = timer2_shift; - m.timers [1].prescaler = timer2_shift + other_shift; - m.timers [0].prescaler = timer2_shift + other_shift; - #else - if ( !t ) - t = 1; - int const timer2_rate = 1 << timer2_shift; - int rate = (timer2_rate * tempo_unit + (t >> 1)) / t; - if ( rate < timer2_rate / 4 ) - rate = timer2_rate / 4; // max 4x tempo - m.timers [2].prescaler = rate; - m.timers [1].prescaler = rate << other_shift; - m.timers [0].prescaler = rate << other_shift; - #endif -} - -// Timer registers have been loaded. Applies these to the timers. Does not -// reset timer prescalers or dividers. -void SNES_SPC::timers_loaded() -{ - int i; - for ( i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->period = IF_0_THEN_256( REGS [r_t0target + i] ); - t->enabled = REGS [r_control] >> i & 1; - t->counter = REGS_IN [r_t0out + i] & 0x0F; - } - - set_tempo( m.tempo ); -} - -// Loads registers from unified 16-byte format -void SNES_SPC::load_regs( uint8_t const in [reg_count] ) -{ - memcpy( REGS, in, reg_count ); - memcpy( REGS_IN, REGS, reg_count ); - - // These always read back as 0 - REGS_IN [r_test ] = 0; - REGS_IN [r_control ] = 0; - REGS_IN [r_t0target] = 0; - REGS_IN [r_t1target] = 0; - REGS_IN [r_t2target] = 0; -} - -// RAM was just loaded from SPC, with $F0-$FF containing SMP registers -// and timer counts. Copies these to proper registers. -void SNES_SPC::ram_loaded() -{ - m.rom_enabled = 0; - load_regs( &RAM [0xF0] ); - - // Put STOP instruction around memory to catch PC underflow/overflow - memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 ); - memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 ); -} - -// Registers were just loaded. Applies these new values. -void SNES_SPC::regs_loaded() -{ - enable_rom( REGS [r_control] & 0x80 ); - timers_loaded(); -} - -void SNES_SPC::reset_time_regs() -{ - m.cpu_error = 0; - m.echo_accessed = 0; - m.spc_time = 0; - m.dsp_time = 0; - #if SPC_LESS_ACCURATE - m.dsp_time = clocks_per_sample + 1; - #endif - - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->next_time = 1; - t->divider = 0; - } - - regs_loaded(); - - m.extra_clocks = 0; - reset_buf(); -} - -void SNES_SPC::reset_common( int timer_counter_init ) -{ - int i; - for ( i = 0; i < timer_count; i++ ) - REGS_IN [r_t0out + i] = timer_counter_init; - - // Run IPL ROM - memset( &m.cpu_regs, 0, sizeof m.cpu_regs ); - m.cpu_regs.pc = rom_addr; - - REGS [r_test ] = 0x0A; - REGS [r_control] = 0xB0; // ROM enabled, clear ports - for ( i = 0; i < port_count; i++ ) - REGS_IN [r_cpuio0 + i] = 0; - - reset_time_regs(); -} - -void SNES_SPC::soft_reset() -{ - reset_common( 0 ); - dsp.soft_reset(); -} - -void SNES_SPC::reset() -{ - memset( RAM, 0xFF, 0x10000 ); - ram_loaded(); - reset_common( 0x0F ); - dsp.reset(); -} - -char const SNES_SPC::signature [signature_size + 1] = - "SNES-SPC700 Sound File Data v0.30\x1A\x1A"; - -blargg_err_t SNES_SPC::load_spc( void const* data, long size ) -{ - spc_file_t const* const spc = (spc_file_t const*) data; - - // be sure compiler didn't insert any padding into fle_t - assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 ); - - // Check signature and file size - if ( size < signature_size || memcmp( spc, signature, 27 ) ) - return "Not an SPC file"; - - if ( size < spc_min_file_size ) - return "Corrupt SPC file"; - - // CPU registers - m.cpu_regs.pc = spc->pch * 0x100 + spc->pcl; - m.cpu_regs.a = spc->a; - m.cpu_regs.x = spc->x; - m.cpu_regs.y = spc->y; - m.cpu_regs.psw = spc->psw; - m.cpu_regs.sp = spc->sp; - - // RAM and registers - memcpy( RAM, spc->ram, 0x10000 ); - ram_loaded(); - - // DSP registers - dsp.load( spc->dsp ); - - reset_time_regs(); - - return 0; -} - -void SNES_SPC::clear_echo() -{ - if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) - { - int addr = 0x100 * dsp.read( SPC_DSP::r_esa ); - int end = addr + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); - if ( end > 0x10000 ) - end = 0x10000; - memset( &RAM [addr], 0xFF, end - addr ); - } -} - - -//// Sample output - -void SNES_SPC::reset_buf() -{ - // Start with half extra buffer of silence - sample_t* out = m.extra_buf; - while ( out < &m.extra_buf [extra_size / 2] ) - *out++ = 0; - - m.extra_pos = out; - m.buf_begin = 0; - - dsp.set_output( 0, 0 ); -} - -void SNES_SPC::set_output( sample_t* out, int size ) -{ - require( (size & 1) == 0 ); // size must be even - - m.extra_clocks &= clocks_per_sample - 1; - if ( out ) - { - sample_t const* out_end = out + size; - m.buf_begin = out; - m.buf_end = out_end; - - // Copy extra to output - sample_t const* in = m.extra_buf; - while ( in < m.extra_pos && out < out_end ) - *out++ = *in++; - - // Handle output being full already - if ( out >= out_end ) - { - // Have DSP write to remaining extra space - out = dsp.extra(); - out_end = &dsp.extra() [extra_size]; - - // Copy any remaining extra samples as if DSP wrote them - while ( in < m.extra_pos ) - *out++ = *in++; - assert( out <= out_end ); - } - - dsp.set_output( out, out_end - out ); - } - else - { - reset_buf(); - } -} - -void SNES_SPC::save_extra() -{ - // Get end pointers - sample_t const* main_end = m.buf_end; // end of data written to buf - sample_t const* dsp_end = dsp.out_pos(); // end of data written to dsp.extra() - if ( m.buf_begin <= dsp_end && dsp_end <= main_end ) - { - main_end = dsp_end; - dsp_end = dsp.extra(); // nothing in DSP's extra - } - - // Copy any extra samples at these ends into extra_buf - sample_t* out = m.extra_buf; - sample_t const* in; - for ( in = m.buf_begin + sample_count(); in < main_end; in++ ) - *out++ = *in; - for ( in = dsp.extra(); in < dsp_end ; in++ ) - *out++ = *in; - - m.extra_pos = out; - assert( out <= &m.extra_buf [extra_size] ); -} - -blargg_err_t SNES_SPC::play( int count, sample_t* out ) -{ - require( (count & 1) == 0 ); // must be even - if ( count ) - { - set_output( out, count ); - end_frame( count * (clocks_per_sample / 2) ); - } - - const char* err = m.cpu_error; - m.cpu_error = 0; - return err; -} - -blargg_err_t SNES_SPC::skip( int count ) -{ - #if SPC_LESS_ACCURATE - if ( count > 2 * sample_rate * 2 ) - { - set_output( 0, 0 ); - - // Skip a multiple of 4 samples - time_t end = count; - count = (count & 3) + 1 * sample_rate * 2; - end = (end - count) * (clocks_per_sample / 2); - - m.skipped_kon = 0; - m.skipped_koff = 0; - - // Preserve DSP and timer synchronization - // TODO: verify that this really preserves it - int old_dsp_time = m.dsp_time + m.spc_time; - m.dsp_time = end - m.spc_time + skipping_time; - end_frame( end ); - m.dsp_time = m.dsp_time - skipping_time + old_dsp_time; - - dsp.write( SPC_DSP::r_koff, m.skipped_koff & ~m.skipped_kon ); - dsp.write( SPC_DSP::r_kon , m.skipped_kon ); - clear_echo(); - } - #endif - - return play( count, 0 ); -} diff --git a/snes/fast/snes_spc/SNES_SPC_state.cpp b/snes/fast/snes_spc/SNES_SPC_state.cpp deleted file mode 100755 index a8052b65..00000000 --- a/snes/fast/snes_spc/SNES_SPC_state.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// SPC emulation state save/load: copy_state(), save_spc() -// Separate file to avoid linking in unless needed - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#if !SPC_NO_COPY_STATE_FUNCS - -#include - -/* Copyright (C) 2004-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 */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -void SNES_SPC::save_regs( uint8_t out [reg_count] ) -{ - // Use current timer counter values - for ( int i = 0; i < timer_count; i++ ) - out [r_t0out + i] = m.timers [i].counter; - - // Last written values - memcpy( out, REGS, r_t0out ); -} - -void SNES_SPC::init_header( void* spc_out ) -{ - spc_file_t* const spc = (spc_file_t*) spc_out; - - spc->has_id666 = 26; // has none - spc->version = 30; - memcpy( spc, signature, sizeof spc->signature ); - memset( spc->text, 0, sizeof spc->text ); -} - -void SNES_SPC::save_spc( void* spc_out ) -{ - spc_file_t* const spc = (spc_file_t*) spc_out; - - // CPU - spc->pcl = (uint8_t) (m.cpu_regs.pc >> 0); - spc->pch = (uint8_t) (m.cpu_regs.pc >> 8); - spc->a = m.cpu_regs.a; - spc->x = m.cpu_regs.x; - spc->y = m.cpu_regs.y; - spc->psw = m.cpu_regs.psw; - spc->sp = m.cpu_regs.sp; - - // RAM, ROM - memcpy( spc->ram, RAM, sizeof spc->ram ); - if ( m.rom_enabled ) - memcpy( spc->ram + rom_addr, m.hi_ram, sizeof m.hi_ram ); - memset( spc->unused, 0, sizeof spc->unused ); - memcpy( spc->ipl_rom, m.rom, sizeof spc->ipl_rom ); - - // SMP registers - save_regs( &spc->ram [0xF0] ); - int i; - for ( i = 0; i < port_count; i++ ) - spc->ram [0xF0 + r_cpuio0 + i] = REGS_IN [r_cpuio0 + i]; - - // DSP registers - for ( i = 0; i < SPC_DSP::register_count; i++ ) - spc->dsp [i] = dsp.read( i ); -} - -void SNES_SPC::copy_state( unsigned char** io, copy_func_t copy ) -{ - SPC_State_Copier copier( io, copy ); - - // Make state data more readable by putting 64K RAM, 16 SMP registers, - // then DSP (with its 128 registers) first - - // RAM - enable_rom( 0 ); // will get re-enabled if necessary in regs_loaded() below - copier.copy( RAM, 0x10000 ); - - { - // SMP registers - uint8_t out_ports [port_count]; - uint8_t regs [reg_count]; - memcpy( out_ports, ®S [r_cpuio0], sizeof out_ports ); - save_regs( regs ); - copier.copy( regs, sizeof regs ); - copier.copy( out_ports, sizeof out_ports ); - load_regs( regs ); - regs_loaded(); - memcpy( ®S [r_cpuio0], out_ports, sizeof out_ports ); - } - - // CPU registers - SPC_COPY( uint16_t, m.cpu_regs.pc ); - SPC_COPY( uint8_t, m.cpu_regs.a ); - SPC_COPY( uint8_t, m.cpu_regs.x ); - SPC_COPY( uint8_t, m.cpu_regs.y ); - SPC_COPY( uint8_t, m.cpu_regs.psw ); - SPC_COPY( uint8_t, m.cpu_regs.sp ); - copier.extra(); - - SPC_COPY( int16_t, m.spc_time ); - SPC_COPY( int16_t, m.dsp_time ); - - // DSP - dsp.copy_state( io, copy ); - - // Timers - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - SPC_COPY( int16_t, t->next_time ); - SPC_COPY( uint8_t, t->divider ); - copier.extra(); - } - copier.extra(); -} -#endif diff --git a/snes/fast/snes_spc/SPC_CPU.h b/snes/fast/snes_spc/SPC_CPU.h deleted file mode 100755 index 664fc488..00000000 --- a/snes/fast/snes_spc/SPC_CPU.h +++ /dev/null @@ -1,1220 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -/* Copyright (C) 2004-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 */ - -//// Memory access - -#if SPC_MORE_ACCURACY - #define SUSPICIOUS_OPCODE( name ) ((void) 0) -#else - #define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" ) -#endif - -#define CPU_READ( time, offset, addr )\ - cpu_read( addr, time + offset ) - -#define CPU_WRITE( time, offset, addr, data )\ - cpu_write( data, addr, time + offset ) - -#if SPC_MORE_ACCURACY - #define CPU_READ_TIMER( time, offset, addr, out )\ - { out = CPU_READ( time, offset, addr ); } - -#else - // timers are by far the most common thing read from dp - #define CPU_READ_TIMER( time, offset, addr_, out )\ - {\ - rel_time_t adj_time = time + offset;\ - int dp_addr = addr_;\ - int ti = dp_addr - (r_t0out + 0xF0);\ - if ( (unsigned) ti < timer_count )\ - {\ - Timer* t = &m.timers [ti];\ - if ( adj_time >= t->next_time )\ - t = run_timer_( t, adj_time );\ - out = t->counter;\ - t->counter = 0;\ - }\ - else\ - {\ - out = ram [dp_addr];\ - int i = dp_addr - 0xF0;\ - if ( (unsigned) i < 0x10 )\ - out = cpu_read_smp_reg( i, adj_time );\ - }\ - } -#endif - -#define TIME_ADJ( n ) (n) - -#define READ_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out ) -#define READ( time, addr ) CPU_READ ( rel_time, TIME_ADJ(time), (addr) ) -#define WRITE( time, addr, data ) CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) ) - -#define DP_ADDR( addr ) (dp + (addr)) - -#define READ_DP_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out ) -#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) ) -#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data ) - -#define READ_PROG16( addr ) GET_LE16( ram + (addr) ) - -#define SET_PC( n ) (pc = ram + (n)) -#define GET_PC() (pc - ram) -#define READ_PC( pc ) (*(pc)) -#define READ_PC16( pc ) GET_LE16( pc ) - -// TODO: remove non-wrapping versions? -#define SPC_NO_SP_WRAPAROUND 0 - -#define SET_SP( v ) (sp = ram + 0x101 + (v)) -#define GET_SP() (sp - 0x101 - ram) - -#if SPC_NO_SP_WRAPAROUND -#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) -#define PUSH( v ) (void) (*--sp = (uint8_t) (v)) -#define POP( out ) (void) ((out) = *sp++) - -#else -#define PUSH16( data )\ -{\ - int addr = (sp -= 2) - ram;\ - if ( addr > 0x100 )\ - {\ - SET_LE16( sp, data );\ - }\ - else\ - {\ - ram [(uint8_t) addr + 0x100] = (uint8_t) data;\ - sp [1] = (uint8_t) (data >> 8);\ - sp += 0x100;\ - }\ -} - -#define PUSH( data )\ -{\ - *--sp = (uint8_t) (data);\ - if ( sp - ram == 0x100 )\ - sp += 0x100;\ -} - -#define POP( out )\ -{\ - out = *sp++;\ - if ( sp - ram == 0x201 )\ - {\ - out = sp [-0x101];\ - sp -= 0x100;\ - }\ -} - -#endif - -#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel ) - -unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time ) -{ - unsigned addr = READ_PC16( pc ); - unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13); - return t << 8 & 0x100; -} - -//// Status flag handling - -// Hex value in name to clarify code and bit shifting. -// Flag stored in indicated variable during emulation -int const n80 = 0x80; // nz -int const v40 = 0x40; // psw -int const p20 = 0x20; // dp -int const b10 = 0x10; // psw -int const h08 = 0x08; // psw -int const i04 = 0x04; // psw -int const z02 = 0x02; // nz -int const c01 = 0x01; // c - -int const nz_neg_mask = 0x880; // either bit set indicates N flag set - -#define GET_PSW( out )\ -{\ - out = psw & ~(n80 | p20 | z02 | c01);\ - out |= c >> 8 & c01;\ - out |= dp >> 3 & p20;\ - out |= ((nz >> 4) | nz) & n80;\ - if ( !(uint8_t) nz ) out |= z02;\ -} - -#define SET_PSW( in )\ -{\ - psw = in;\ - c = in << 8;\ - dp = in << 3 & 0x100;\ - nz = (in << 4 & 0x800) | (~in & z02);\ -} - -SPC_CPU_RUN_FUNC -{ - uint8_t* const ram = RAM; - int a = m.cpu_regs.a; - int x = m.cpu_regs.x; - int y = m.cpu_regs.y; - uint8_t const* pc; - uint8_t* sp; - int psw; - int c; - int nz; - int dp; - - SET_PC( m.cpu_regs.pc ); - SET_SP( m.cpu_regs.sp ); - SET_PSW( m.cpu_regs.psw ); - - goto loop; - - - // Main loop - -cbranch_taken_loop: - pc += *(BOOST::int8_t const*) pc; -inc_pc_loop: - pc++; -loop: -{ - unsigned opcode; - unsigned data; - - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - opcode = *pc; - if ( (rel_time += m.cycle_table [opcode]) > 0 ) - goto out_of_time; - - #ifdef SPC_CPU_OPCODE_HOOK - SPC_CPU_OPCODE_HOOK( GET_PC(), opcode ); - #endif - /* - //SUB_CASE_COUNTER( 1 ); - #define PROFILE_TIMER_LOOP( op, addr, len )\ - if ( opcode == op )\ - {\ - int cond = (unsigned) ((addr) - 0xFD) < 3 &&\ - pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\ - SUB_CASE_COUNTER( op && cond );\ - } - - PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 ); - PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 ); - PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 ); - */ - - // TODO: if PC is at end of memory, this will get wrong operand (very obscure) - data = *++pc; - switch ( opcode ) - { - -// Common instructions - -#define BRANCH( cond )\ -{\ - pc++;\ - pc += (BOOST::int8_t) data;\ - if ( cond )\ - goto loop;\ - pc -= (BOOST::int8_t) data;\ - rel_time -= 2;\ - goto loop;\ -} - - case 0xF0: // BEQ - BRANCH( !(uint8_t) nz ) // 89% taken - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ) - - case 0x3F:{// CALL - int old_addr = GET_PC() + 2; - SET_PC( READ_PC16( pc ) ); - PUSH16( old_addr ); - goto loop; - } - - case 0x6F:// RET - #if SPC_NO_SP_WRAPAROUND - { - SET_PC( GET_LE16( sp ) ); - sp += 2; - } - #else - { - int addr = sp - ram; - SET_PC( GET_LE16( sp ) ); - sp += 2; - if ( addr < 0x1FF ) - goto loop; - - SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] ); - sp -= 0x100; - } - #endif - goto loop; - - case 0xE4: // MOV a,dp - ++pc; - // 80% from timer - READ_DP_TIMER( 0, data, a = nz ); - goto loop; - - case 0xFA:{// MOV dp,dp - int temp; - READ_DP_TIMER( -2, data, temp ); - data = temp + no_read_before_write ; - } - // fall through - case 0x8F:{// MOV dp,#imm - int temp = READ_PC( pc + 1 ); - pc += 2; - - #if !SPC_MORE_ACCURACY - { - int i = dp + temp; - ram [i] = (uint8_t) data; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 76% - { - REGS [i] = (uint8_t) data; - - // Registers other than $F2 and $F4-$F7 - //if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 ) - if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12% - cpu_write_smp_reg( data, rel_time, i ); - } - } - #else - WRITE_DP( 0, temp, data ); - #endif - goto loop; - } - - case 0xC4: // MOV dp,a - ++pc; - #if !SPC_MORE_ACCURACY - { - int i = dp + data; - ram [i] = (uint8_t) a; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 39% - { - unsigned sel = i - 2; - REGS [i] = (uint8_t) a; - - if ( sel == 1 ) // 51% $F3 - dsp_write( a, rel_time ); - else if ( sel > 1 ) // 1% not $F2 or $F3 - cpu_write_smp_reg_( a, rel_time, i ); - } - } - #else - WRITE_DP( 0, data, a ); - #endif - goto loop; - -#define CASE( n ) case n: - -// Define common address modes based on opcode for immediate mode. Execution -// ends with data set to the address of the operand. -#define ADDR_MODES_( op )\ - CASE( op - 0x02 ) /* (X) */\ - data = x + dp;\ - pc--;\ - goto end_##op;\ - CASE( op + 0x0F ) /* (dp)+Y */\ - data = READ_PROG16( data + dp ) + y;\ - goto end_##op;\ - CASE( op - 0x01 ) /* (dp+X) */\ - data = READ_PROG16( ((uint8_t) (data + x)) + dp );\ - goto end_##op;\ - CASE( op + 0x0E ) /* abs+Y */\ - data += y;\ - goto abs_##op;\ - CASE( op + 0x0D ) /* abs+X */\ - data += x;\ - CASE( op - 0x03 ) /* abs */\ - abs_##op:\ - data += 0x100 * READ_PC( ++pc );\ - goto end_##op;\ - CASE( op + 0x0C ) /* dp+X */\ - data = (uint8_t) (data + x); - -#define ADDR_MODES_NO_DP( op )\ - ADDR_MODES_( op )\ - data += dp;\ - end_##op: - -#define ADDR_MODES( op )\ - ADDR_MODES_( op )\ - CASE( op - 0x04 ) /* dp */\ - data += dp;\ - end_##op: - -// 1. 8-bit Data Transmission Commands. Group I - - ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr - a = nz = READ( 0, data ); - goto inc_pc_loop; - - case 0xBF:{// MOV A,(X)+ - int temp = x + dp; - x = (uint8_t) (x + 1); - a = nz = READ( -1, temp ); - goto loop; - } - - case 0xE8: // MOV A,imm - a = data; - nz = data; - goto inc_pc_loop; - - case 0xF9: // MOV X,dp+Y - data = (uint8_t) (data + y); - case 0xF8: // MOV X,dp - READ_DP_TIMER( 0, data, x = nz ); - goto inc_pc_loop; - - case 0xE9: // MOV X,abs - data = READ_PC16( pc ); - ++pc; - data = READ( 0, data ); - case 0xCD: // MOV X,imm - x = data; - nz = data; - goto inc_pc_loop; - - case 0xFB: // MOV Y,dp+X - data = (uint8_t) (data + x); - case 0xEB: // MOV Y,dp - // 70% from timer - pc++; - READ_DP_TIMER( 0, data, y = nz ); - goto loop; - - case 0xEC:{// MOV Y,abs - int temp = READ_PC16( pc ); - pc += 2; - READ_TIMER( 0, temp, y = nz ); - //y = nz = READ( 0, temp ); - goto loop; - } - - case 0x8D: // MOV Y,imm - y = data; - nz = data; - goto inc_pc_loop; - -// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 - - ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A - WRITE( 0, data, a ); - goto inc_pc_loop; - - { - int temp; - case 0xCC: // MOV abs,Y - temp = y; - goto mov_abs_temp; - case 0xC9: // MOV abs,X - temp = x; - mov_abs_temp: - WRITE( 0, READ_PC16( pc ), temp ); - pc += 2; - goto loop; - } - - case 0xD9: // MOV dp+Y,X - data = (uint8_t) (data + y); - case 0xD8: // MOV dp,X - WRITE( 0, data + dp, x ); - goto inc_pc_loop; - - case 0xDB: // MOV dp+X,Y - data = (uint8_t) (data + x); - case 0xCB: // MOV dp,Y - WRITE( 0, data + dp, y ); - goto inc_pc_loop; - -// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. - - case 0x7D: // MOV A,X - a = x; - nz = x; - goto loop; - - case 0xDD: // MOV A,Y - a = y; - nz = y; - goto loop; - - case 0x5D: // MOV X,A - x = a; - nz = a; - goto loop; - - case 0xFD: // MOV Y,A - y = a; - nz = a; - goto loop; - - case 0x9D: // MOV X,SP - x = nz = GET_SP(); - goto loop; - - case 0xBD: // MOV SP,X - SET_SP( x ); - goto loop; - - //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2) - - case 0xAF: // MOV (X)+,A - WRITE_DP( 0, x, a + no_read_before_write ); - x++; - goto loop; - -// 5. 8-BIT LOGIC OPERATION COMMANDS - -#define LOGICAL_OP( op, func )\ - ADDR_MODES( op ) /* addr */\ - data = READ( 0, data );\ - case op: /* imm */\ - nz = a func##= data;\ - goto inc_pc_loop;\ - { unsigned addr;\ - case op + 0x11: /* X,Y */\ - data = READ_DP( -2, y );\ - addr = x + dp;\ - goto addr_##op;\ - case op + 0x01: /* dp,dp */\ - data = READ_DP( -3, data );\ - case op + 0x10:{/*dp,imm*/\ - uint8_t const* addr2 = pc + 1;\ - pc += 2;\ - addr = READ_PC( addr2 ) + dp;\ - }\ - addr_##op:\ - nz = data func READ( -1, addr );\ - WRITE( 0, addr, nz );\ - goto loop;\ - } - - LOGICAL_OP( 0x28, & ); // AND - - LOGICAL_OP( 0x08, | ); // OR - - LOGICAL_OP( 0x48, ^ ); // EOR - -// 4. 8-BIT ARITHMETIC OPERATION COMMANDS - - ADDR_MODES( 0x68 ) // CMP addr - data = READ( 0, data ); - case 0x68: // CMP imm - nz = a - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x79: // CMP (X),(Y) - data = READ_DP( -2, y ); - nz = READ_DP( -1, x ) - data; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x69: // CMP dp,dp - data = READ_DP( -3, data ); - case 0x78: // CMP dp,imm - nz = READ_DP( -1, READ_PC( ++pc ) ) - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x3E: // CMP X,dp - data += dp; - goto cmp_x_addr; - case 0x1E: // CMP X,abs - data = READ_PC16( pc ); - pc++; - cmp_x_addr: - data = READ( 0, data ); - case 0xC8: // CMP X,imm - nz = x - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x7E: // CMP Y,dp - data += dp; - goto cmp_y_addr; - case 0x5E: // CMP Y,abs - data = READ_PC16( pc ); - pc++; - cmp_y_addr: - data = READ( 0, data ); - case 0xAD: // CMP Y,imm - nz = y - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - { - int addr; - case 0xB9: // SBC (x),(y) - case 0x99: // ADC (x),(y) - pc--; // compensate for inc later - data = READ_DP( -2, y ); - addr = x + dp; - goto adc_addr; - case 0xA9: // SBC dp,dp - case 0x89: // ADC dp,dp - data = READ_DP( -3, data ); - case 0xB8: // SBC dp,imm - case 0x98: // ADC dp,imm - addr = READ_PC( ++pc ) + dp; - adc_addr: - nz = READ( -1, addr ); - goto adc_data; - -// catch ADC and SBC together, then decode later based on operand -#undef CASE -#define CASE( n ) case n: case (n) + 0x20: - ADDR_MODES( 0x88 ) // ADC/SBC addr - data = READ( 0, data ); - case 0xA8: // SBC imm - case 0x88: // ADC imm - addr = -1; // A - nz = a; - adc_data: { - int flags; - if ( opcode >= 0xA0 ) // SBC - data ^= 0xFF; - - flags = data ^ nz; - nz += data + (c >> 8 & 1); - flags ^= nz; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = nz; - if ( addr < 0 ) - { - a = (uint8_t) nz; - goto inc_pc_loop; - } - WRITE( 0, addr, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - } - - } - -// 6. ADDITION & SUBTRACTION COMMANDS - -#define INC_DEC_REG( reg, op )\ - nz = reg op;\ - reg = (uint8_t) nz;\ - goto loop; - - case 0xBC: INC_DEC_REG( a, + 1 ) // INC A - case 0x3D: INC_DEC_REG( x, + 1 ) // INC X - case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y - - case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A - case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X - case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y - - case 0x9B: // DEC dp+X - case 0xBB: // INC dp+X - data = (uint8_t) (data + x); - case 0x8B: // DEC dp - case 0xAB: // INC dp - data += dp; - goto inc_abs; - case 0x8C: // DEC abs - case 0xAC: // INC abs - data = READ_PC16( pc ); - pc++; - inc_abs: - nz = (opcode >> 4 & 2) - 1; - nz += READ( -1, data ); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - -// 7. SHIFT, ROTATION COMMANDS - - case 0x5C: // LSR A - c = 0; - case 0x7C:{// ROR A - nz = (c >> 1 & 0x80) | (a >> 1); - c = a << 8; - a = nz; - goto loop; - } - - case 0x1C: // ASL A - c = 0; - case 0x3C:{// ROL A - int temp = c >> 8 & 1; - c = a << 1; - nz = c | temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x0B: // ASL dp - c = 0; - data += dp; - goto rol_mem; - case 0x1B: // ASL dp+X - c = 0; - case 0x3B: // ROL dp+X - data = (uint8_t) (data + x); - case 0x2B: // ROL dp - data += dp; - goto rol_mem; - case 0x0C: // ASL abs - c = 0; - case 0x2C: // ROL abs - data = READ_PC16( pc ); - pc++; - rol_mem: - nz = c >> 8 & 1; - nz |= (c = READ( -1, data ) << 1); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - - case 0x4B: // LSR dp - c = 0; - data += dp; - goto ror_mem; - case 0x5B: // LSR dp+X - c = 0; - case 0x7B: // ROR dp+X - data = (uint8_t) (data + x); - case 0x6B: // ROR dp - data += dp; - goto ror_mem; - case 0x4C: // LSR abs - c = 0; - case 0x6C: // ROR abs - data = READ_PC16( pc ); - pc++; - ror_mem: { - int temp = READ( -1, data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - WRITE( 0, data, nz ); - goto inc_pc_loop; - } - - case 0x9F: // XCN - nz = a = (a >> 4) | (uint8_t) (a << 4); - goto loop; - -// 8. 16-BIT TRANSMISION COMMANDS - - case 0xBA: // MOVW YA,dp - a = READ_DP( -2, data ); - nz = (a & 0x7F) | (a >> 1); - y = READ_DP( 0, (uint8_t) (data + 1) ); - nz |= y; - goto inc_pc_loop; - - case 0xDA: // MOVW dp,YA - WRITE_DP( -1, data, a ); - WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write ); - goto inc_pc_loop; - -// 9. 16-BIT OPERATION COMMANDS - - case 0x3A: // INCW dp - case 0x1A:{// DECW dp - int temp; - // low byte - data += dp; - temp = READ( -3, data ); - temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW - nz = ((temp >> 1) | temp) & 0x7F; - WRITE( -2, data, /*(uint8_t)*/ temp ); - - // high byte - data = (uint8_t) (data + 1) + dp; - temp = (uint8_t) ((temp >> 8) + READ( -1, data )); - nz |= temp; - WRITE( 0, data, temp ); - - goto inc_pc_loop; - } - - case 0x7A: // ADDW YA,dp - case 0x9A:{// SUBW YA,dp - int lo = READ_DP( -2, data ); - int hi = READ_DP( 0, (uint8_t) (data + 1) ); - int result; - int flags; - - if ( opcode == 0x9A ) // SUBW - { - lo = (lo ^ 0xFF) + 1; - hi ^= 0xFF; - } - - lo += a; - result = y + hi + (lo >> 8); - flags = hi ^ y ^ result; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = result; - a = (uint8_t) lo; - result = (uint8_t) result; - y = result; - nz = (((lo >> 1) | lo) & 0x7F) | result; - - goto inc_pc_loop; - } - - case 0x5A: { // CMPW YA,dp - int temp = a - READ_DP( -1, data ); - nz = ((temp >> 1) | temp) & 0x7F; - temp = y + (temp >> 8); - temp -= READ_DP( 0, (uint8_t) (data + 1) ); - nz |= temp; - c = ~temp; - nz &= 0xFF; - goto inc_pc_loop; - } - -// 10. MULTIPLICATION & DIVISON COMMANDS - - case 0xCF: { // MUL YA - unsigned temp = y * a; - a = (uint8_t) temp; - nz = ((temp >> 1) | temp) & 0x7F; - y = temp >> 8; - nz |= y; - goto loop; - } - - case 0x9E: // DIV YA,X - { - unsigned ya = y * 0x100 + a; - - psw &= ~(h08 | v40); - - if ( y >= x ) - psw |= v40; - - if ( (y & 15) >= (x & 15) ) - psw |= h08; - - if ( y < x * 2 ) - { - a = ya / x; - y = ya - a * x; - } - else - { - a = 255 - (ya - x * 0x200) / (256 - x); - y = x + (ya - x * 0x200) % (256 - x); - } - - nz = (uint8_t) a; - a = (uint8_t) a; - - goto loop; - } - -// 11. DECIMAL COMPENSATION COMMANDS - - case 0xDF: // DAA - SUSPICIOUS_OPCODE( "DAA" ); - if ( a > 0x99 || c & 0x100 ) - { - a += 0x60; - c = 0x100; - } - - if ( (a & 0x0F) > 9 || psw & h08 ) - a += 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - - case 0xBE: // DAS - SUSPICIOUS_OPCODE( "DAS" ); - if ( a > 0x99 || !(c & 0x100) ) - { - a -= 0x60; - c = 0; - } - - if ( (a & 0x0F) > 9 || !(psw & h08) ) - a -= 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - -// 12. BRANCHING COMMANDS - - case 0x2F: // BRA rel - pc += (BOOST::int8_t) data; - goto inc_pc_loop; - - case 0x30: // BMI - BRANCH( (nz & nz_neg_mask) ) - - case 0x10: // BPL - BRANCH( !(nz & nz_neg_mask) ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - - case 0x70: // BVS - BRANCH( psw & v40 ) - - case 0x50: // BVC - BRANCH( !(psw & v40) ) - - #define CBRANCH( cond )\ - {\ - pc++;\ - if ( cond )\ - goto cbranch_taken_loop;\ - rel_time -= 2;\ - goto inc_pc_loop;\ - } - - case 0x03: // BBS dp.bit,rel - case 0x23: - case 0x43: - case 0x63: - case 0x83: - case 0xA3: - case 0xC3: - case 0xE3: - CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 ) - - case 0x13: // BBC dp.bit,rel - case 0x33: - case 0x53: - case 0x73: - case 0x93: - case 0xB3: - case 0xD3: - case 0xF3: - CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) ) - - case 0xDE: // CBNE dp+X,rel - data = (uint8_t) (data + x); - // fall through - case 0x2E:{// CBNE dp,rel - int temp; - // 61% from timer - READ_DP_TIMER( -4, data, temp ); - CBRANCH( temp != a ) - } - - case 0x6E: { // DBNZ dp,rel - unsigned temp = READ_DP( -4, data ) - 1; - WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write ); - CBRANCH( temp ) - } - - case 0xFE: // DBNZ Y,rel - y = (uint8_t) (y - 1); - BRANCH( y ) - - case 0x1F: // JMP [abs+X] - SET_PC( READ_PC16( pc ) + x ); - // fall through - case 0x5F: // JMP abs - SET_PC( READ_PC16( pc ) ); - goto loop; - -// 13. SUB-ROUTINE CALL RETURN COMMANDS - - case 0x0F:{// BRK - int temp; - int ret_addr = GET_PC(); - SUSPICIOUS_OPCODE( "BRK" ); - SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified - PUSH16( ret_addr ); - GET_PSW( temp ); - psw = (psw | b10) & ~i04; - PUSH( temp ); - goto loop; - } - - case 0x4F:{// PCALL offset - int ret_addr = GET_PC() + 1; - SET_PC( 0xFF00 | data ); - PUSH16( ret_addr ); - goto loop; - } - - case 0x01: // TCALL n - case 0x11: - case 0x21: - case 0x31: - case 0x41: - case 0x51: - case 0x61: - case 0x71: - case 0x81: - case 0x91: - case 0xA1: - case 0xB1: - case 0xC1: - case 0xD1: - case 0xE1: - case 0xF1: { - int ret_addr = GET_PC(); - SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) ); - PUSH16( ret_addr ); - goto loop; - } - -// 14. STACK OPERATION COMMANDS - - { - int temp; - case 0x7F: // RET1 - temp = *sp; - SET_PC( GET_LE16( sp + 1 ) ); - sp += 3; - goto set_psw; - case 0x8E: // POP PSW - POP( temp ); - set_psw: - SET_PSW( temp ); - goto loop; - } - - case 0x0D: { // PUSH PSW - int temp; - GET_PSW( temp ); - PUSH( temp ); - goto loop; - } - - case 0x2D: // PUSH A - PUSH( a ); - goto loop; - - case 0x4D: // PUSH X - PUSH( x ); - goto loop; - - case 0x6D: // PUSH Y - PUSH( y ); - goto loop; - - case 0xAE: // POP A - POP( a ); - goto loop; - - case 0xCE: // POP X - POP( x ); - goto loop; - - case 0xEE: // POP Y - POP( y ); - goto loop; - -// 15. BIT OPERATION COMMANDS - - case 0x02: // SET1 - case 0x22: - case 0x42: - case 0x62: - case 0x82: - case 0xA2: - case 0xC2: - case 0xE2: - case 0x12: // CLR1 - case 0x32: - case 0x52: - case 0x72: - case 0x92: - case 0xB2: - case 0xD2: - case 0xF2: { - int bit = 1 << (opcode >> 5); - int mask = ~bit; - if ( opcode & 0x10 ) - bit = 0; - data += dp; - WRITE( 0, data, (READ( -1, data ) & mask) | bit ); - goto inc_pc_loop; - } - - case 0x0E: // TSET1 abs - case 0x4E: // TCLR1 abs - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data ); - nz = (uint8_t) (a - temp); - temp &= ~a; - if ( opcode == 0x0E ) - temp |= a; - WRITE( 0, data, temp ); - } - goto loop; - - case 0x4A: // AND1 C,mem.bit - c &= MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x6A: // AND1 C,/mem.bit - c &= ~MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x0A: // OR1 C,mem.bit - c |= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x2A: // OR1 C,/mem.bit - c |= ~MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x8A: // EOR1 C,mem.bit - c ^= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0xEA: // NOT1 mem.bit - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -1, data & 0x1FFF ); - temp ^= 1 << (data >> 13); - WRITE( 0, data & 0x1FFF, temp ); - } - goto loop; - - case 0xCA: // MOV1 mem.bit,C - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data & 0x1FFF ); - unsigned bit = data >> 13; - temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit); - WRITE( 0, data & 0x1FFF, temp + no_read_before_write ); - } - goto loop; - - case 0xAA: // MOV1 C,mem.bit - c = MEM_BIT( 0 ); - pc += 2; - goto loop; - -// 16. PROGRAM PSW FLAG OPERATION COMMANDS - - case 0x60: // CLRC - c = 0; - goto loop; - - case 0x80: // SETC - c = ~0; - goto loop; - - case 0xED: // NOTC - c ^= 0x100; - goto loop; - - case 0xE0: // CLRV - psw &= ~(v40 | h08); - goto loop; - - case 0x20: // CLRP - dp = 0; - goto loop; - - case 0x40: // SETP - dp = 0x100; - goto loop; - - case 0xA0: // EI - SUSPICIOUS_OPCODE( "EI" ); - psw |= i04; - goto loop; - - case 0xC0: // DI - SUSPICIOUS_OPCODE( "DI" ); - psw &= ~i04; - goto loop; - -// 17. OTHER COMMANDS - - case 0x00: // NOP - goto loop; - - case 0xFF:{// STOP - // handle PC wrap-around - unsigned addr = GET_PC() - 1; - if ( addr >= 0x10000 ) - { - addr &= 0xFFFF; - SET_PC( addr ); - dprintf( "SPC: PC wrapped around\n" ); - goto loop; - } - } - // fall through - case 0xEF: // SLEEP - SUSPICIOUS_OPCODE( "STOP/SLEEP" ); - --pc; - rel_time = 0; - m.cpu_error = "SPC emulation error"; - goto stop; - } // switch - - assert( 0 ); // catch any unhandled instructions -} -out_of_time: - rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode -stop: - - // Uncache registers - if ( GET_PC() >= 0x10000 ) - dprintf( "SPC: PC wrapped around\n" ); - m.cpu_regs.pc = (uint16_t) GET_PC(); - m.cpu_regs.sp = ( uint8_t) GET_SP(); - m.cpu_regs.a = ( uint8_t) a; - m.cpu_regs.x = ( uint8_t) x; - m.cpu_regs.y = ( uint8_t) y; - { - int temp; - GET_PSW( temp ); - m.cpu_regs.psw = (uint8_t) temp; - } -} -SPC_CPU_RUN_FUNC_END diff --git a/snes/fast/snes_spc/SPC_DSP.cpp b/snes/fast/snes_spc/SPC_DSP.cpp deleted file mode 100755 index dd180506..00000000 --- a/snes/fast/snes_spc/SPC_DSP.cpp +++ /dev/null @@ -1,1018 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SPC_DSP.h" - -#include "blargg_endian.h" -#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 */ - -#include "blargg_source.h" - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -#if INT_MAX < 0x7FFFFFFF - #error "Requires that int type have at least 32 bits" -#endif - -// TODO: add to blargg_endian.h -#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr )) -#define GET_LE16A( addr ) GET_LE16( addr ) -#define SET_LE16A( addr, data ) SET_LE16( addr, data ) - -static BOOST::uint8_t const initial_regs [SPC_DSP::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 -}; - -// if ( io < -32768 ) io = -32768; -// if ( io > 32767 ) io = 32767; -#define CLAMP16( io )\ -{\ - if ( (int16_t) io != io )\ - io = (io >> 31) ^ 0x7FFF;\ -} - -// Access global DSP register -#define REG(n) m.regs [r_##n] - -// Access voice DSP register -#define VREG(r,n) r [v_##n] - -#define WRITE_SAMPLES( l, r, out ) \ -{\ - out [0] = l;\ - out [1] = r;\ - out += 2;\ - if ( out >= m.out_end )\ - {\ - check( out == m.out_end );\ - check( m.out_end != &m.extra [extra_size] || \ - (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ - out = m.extra;\ - m.out_end = &m.extra [extra_size];\ - }\ -}\ - -void SPC_DSP::set_output( sample_t* out, int size ) -{ - require( (size & 1) == 0 ); // must be even - if ( !out ) - { - out = m.extra; - size = extra_size; - } - m.out_begin = out; - m.out = out; - m.out_end = out + size; -} - -// Volume registers and efb are signed! Easy to forget int8_t 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, -}; - -inline int SPC_DSP::interpolate( voice_t 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 - -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 void SPC_DSP::init_counter() -{ - m.counter = 0; -} - -inline void SPC_DSP::run_counters() -{ - if ( --m.counter < 0 ) - m.counter = simple_counter_range - 1; -} - -inline unsigned SPC_DSP::read_counter( int rate ) -{ - return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; -} - - -//// Envelope - -inline void SPC_DSP::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 - { - int mode; - env_data = VREG(v->regs,gain); - 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 - -inline void SPC_DSP::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; - - // Write to next four samples in circular buffer - int* pos = &v->buf [v->buf_pos]; - int* end; - if ( (v->buf_pos += 4) >= brr_buf_size ) - v->buf_pos = 0; - - // Decode four samples - for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) - { - // Extract nybble and sign-extend - int s = (int16_t) nybbles >> 12; - - // Shift sample based on header - int const shift = header >> 4; - s = (s << shift) >> 1; - if ( shift >= 0xD ) // handle invalid range - s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) - - // 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 void SPC_DSP::misc_##n() - -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 ) void SPC_DSP::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 = GET_LE16A( entry ); - - 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 - m.kon_check = true; - } - - // 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 = (uint8_t) (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 SPC_DSP::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 - 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_t) endx_buf; -} -inline VOICE_CLOCK( V6 ) -{ - (void) v; // avoid compiler warning about unused v - m.outx_buf = (uint8_t) (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; -} - -// 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 void SPC_DSP::echo_##n() - -inline void SPC_DSP::echo_read( int ch ) -{ - int s = GET_LE16SA( ECHO_PTR( ch ) ); - // 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 [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; -} -inline int SPC_DSP::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 l = m.t_main_out [0]; - int r = 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 ) - { - l = 0; - r = 0; - } - - // Output sample to DAC - #ifdef SPC_DSP_OUT_HOOK - SPC_DSP_OUT_HOOK( l, r ); - #else - sample_t* out = m.out; - WRITE_SAMPLES( l, r, out ); - m.out = out; - #endif -} -ECHO_CLOCK( 28 ) -{ - m.t_echo_enabled = REG(flg); -} -inline void SPC_DSP::echo_write( int ch ) -{ - if ( !(m.t_echo_enabled & 0x20) ) - SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); - 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 - -// Execute clock for a particular voice -#define V( clock, voice ) voice_##clock( &m.voices [voice] ); - -/* The most common sequence of clocks uses composite operations -for efficiency. For example, the following are equivalent to the -individual steps on the right: - -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) */ - -// Voice 0 1 2 3 4 5 6 7 -#define GEN_DSP_TIMING \ -PHASE( 0) V(V5,0)V(V2,1)\ -PHASE( 1) V(V6,0)V(V3,1)\ -PHASE( 2) V(V7_V4_V1,0)\ -PHASE( 3) V(V8_V5_V2,0)\ -PHASE( 4) V(V9_V6_V3,0)\ -PHASE( 5) V(V7_V4_V1,1)\ -PHASE( 6) V(V8_V5_V2,1)\ -PHASE( 7) V(V9_V6_V3,1)\ -PHASE( 8) V(V7_V4_V1,2)\ -PHASE( 9) V(V8_V5_V2,2)\ -PHASE(10) V(V9_V6_V3,2)\ -PHASE(11) V(V7_V4_V1,3)\ -PHASE(12) V(V8_V5_V2,3)\ -PHASE(13) V(V9_V6_V3,3)\ -PHASE(14) V(V7_V4_V1,4)\ -PHASE(15) V(V8_V5_V2,4)\ -PHASE(16) V(V9_V6_V3,4)\ -PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ -PHASE(18) V(V8_V5_V2,5)\ -PHASE(19) V(V9_V6_V3,5)\ -PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ -PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ -PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ -PHASE(23) V(V7,7) echo_23();\ -PHASE(24) V(V8,7) echo_24();\ -PHASE(25) V(V3b,0) V(V9,7) echo_25();\ -PHASE(26) echo_26();\ -PHASE(27) misc_27(); echo_27();\ -PHASE(28) misc_28(); echo_28();\ -PHASE(29) misc_29(); echo_29();\ -PHASE(30) misc_30();V(V3c,0) echo_30();\ -PHASE(31) V(V4,0) V(V1,2)\ - -#if !SPC_DSP_CUSTOM_RUN - -void SPC_DSP::run( int clocks_remain ) -{ - require( 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: - GEN_DSP_TIMING - #undef PHASE - - if ( --clocks_remain ) - goto loop; - } -} - -#endif - - -//// Setup - -void SPC_DSP::init( void* ram_64k ) -{ - m.ram = (uint8_t*) ram_64k; - mute_voices( 0 ); - disable_surround( false ); - set_output( 0, 0 ); - reset(); - - #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 ); - - blargg_verify_byte_order(); - #endif -} - -void SPC_DSP::soft_reset_common() -{ - require( m.ram ); // init() must have been called already - - m.noise = 0x4000; - m.echo_hist_pos = m.echo_hist; - m.every_other_sample = 1; - m.echo_offset = 0; - m.phase = 0; - - init_counter(); -} - -void SPC_DSP::soft_reset() -{ - REG(flg) = 0xE0; - soft_reset_common(); -} - -void SPC_DSP::load( uint8_t const regs [register_count] ) -{ - memcpy( m.regs, regs, sizeof m.regs ); - memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); - - // 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); - m.t_esa = REG(esa); - - soft_reset_common(); -} - -void SPC_DSP::reset() { load( initial_regs ); } - - -//// State save/load - -#if !SPC_NO_COPY_STATE_FUNCS - -void SPC_State_Copier::copy( void* state, size_t size ) -{ - func( buf, state, size ); -} - -int SPC_State_Copier::copy_int( int state, int size ) -{ - BOOST::uint8_t s [2]; - SET_LE16( s, state ); - func( buf, &s, size ); - return GET_LE16( s ); -} - -void SPC_State_Copier::skip( int count ) -{ - if ( count > 0 ) - { - char temp [64]; - memset( temp, 0, sizeof temp ); - do - { - int n = sizeof temp; - if ( n > count ) - n = count; - count -= n; - func( buf, temp, n ); - } - while ( count ); - } -} - -void SPC_State_Copier::extra() -{ - int n = 0; - SPC_State_Copier& copier = *this; - SPC_COPY( uint8_t, n ); - skip( n ); -} - -void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) -{ - SPC_State_Copier copier( io, copy ); - - // DSP registers - copier.copy( m.regs, register_count ); - - // Internal state - - // Voices - int i; - for ( i = 0; i < voice_count; i++ ) - { - voice_t* v = &m.voices [i]; - - // BRR buffer - int i; - for ( i = 0; i < brr_buf_size; i++ ) - { - int s = v->buf [i]; - SPC_COPY( int16_t, s ); - v->buf [i] = v->buf [i + brr_buf_size] = s; - } - - SPC_COPY( uint16_t, v->interp_pos ); - SPC_COPY( uint16_t, v->brr_addr ); - SPC_COPY( uint16_t, v->env ); - SPC_COPY( int16_t, v->hidden_env ); - SPC_COPY( uint8_t, v->buf_pos ); - SPC_COPY( uint8_t, v->brr_offset ); - SPC_COPY( uint8_t, v->kon_delay ); - { - int m = v->env_mode; - SPC_COPY( uint8_t, m ); - v->env_mode = (enum env_mode_t) m; - } - SPC_COPY( uint8_t, v->t_envx_out ); - - copier.extra(); - } - - // Echo history - for ( i = 0; i < echo_hist_size; i++ ) - { - int j; - for ( j = 0; j < 2; j++ ) - { - int s = m.echo_hist_pos [i] [j]; - SPC_COPY( int16_t, s ); - m.echo_hist [i] [j] = s; // write back at offset 0 - } - } - m.echo_hist_pos = m.echo_hist; - memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); - - // Misc - SPC_COPY( uint8_t, m.every_other_sample ); - SPC_COPY( uint8_t, m.kon ); - - SPC_COPY( uint16_t, m.noise ); - SPC_COPY( uint16_t, m.counter ); - SPC_COPY( uint16_t, m.echo_offset ); - SPC_COPY( uint16_t, m.echo_length ); - SPC_COPY( uint8_t, m.phase ); - - SPC_COPY( uint8_t, m.new_kon ); - SPC_COPY( uint8_t, m.endx_buf ); - SPC_COPY( uint8_t, m.envx_buf ); - SPC_COPY( uint8_t, m.outx_buf ); - - SPC_COPY( uint8_t, m.t_pmon ); - SPC_COPY( uint8_t, m.t_non ); - SPC_COPY( uint8_t, m.t_eon ); - SPC_COPY( uint8_t, m.t_dir ); - SPC_COPY( uint8_t, m.t_koff ); - - SPC_COPY( uint16_t, m.t_brr_next_addr ); - SPC_COPY( uint8_t, m.t_adsr0 ); - SPC_COPY( uint8_t, m.t_brr_header ); - SPC_COPY( uint8_t, m.t_brr_byte ); - SPC_COPY( uint8_t, m.t_srcn ); - SPC_COPY( uint8_t, m.t_esa ); - SPC_COPY( uint8_t, m.t_echo_enabled ); - - SPC_COPY( int16_t, m.t_main_out [0] ); - SPC_COPY( int16_t, m.t_main_out [1] ); - SPC_COPY( int16_t, m.t_echo_out [0] ); - SPC_COPY( int16_t, m.t_echo_out [1] ); - SPC_COPY( int16_t, m.t_echo_in [0] ); - SPC_COPY( int16_t, m.t_echo_in [1] ); - - SPC_COPY( uint16_t, m.t_dir_addr ); - SPC_COPY( uint16_t, m.t_pitch ); - SPC_COPY( int16_t, m.t_output ); - SPC_COPY( uint16_t, m.t_echo_ptr ); - SPC_COPY( uint8_t, m.t_looped ); - - copier.extra(); -} -#endif diff --git a/snes/fast/snes_spc/SPC_DSP.h b/snes/fast/snes_spc/SPC_DSP.h deleted file mode 100755 index 4522ace9..00000000 --- a/snes/fast/snes_spc/SPC_DSP.h +++ /dev/null @@ -1,304 +0,0 @@ -// Highly accurate SNES SPC-700 DSP emulator - -// snes_spc 0.9.0 -#ifndef SPC_DSP_H -#define SPC_DSP_H - -#include "blargg_common.h" - -extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } - -class SPC_DSP { -public: - typedef BOOST::uint8_t uint8_t; - -// Setup - - // Initializes DSP and has it use the 64K RAM provided - void init( void* ram_64k ); - - // Sets destination for output samples. If out is NULL or out_size is 0, - // doesn't generate any. - typedef short sample_t; - void set_output( sample_t* out, int out_size ); - - // Number of samples written to output since it was last set, always - // a multiple of 2. Undefined if more samples were generated than - // output buffer could hold. - int sample_count() const; - -// Emulation - - // Resets DSP to power-on state - void reset(); - - // Emulates pressing reset switch on SNES - void soft_reset(); - - // Reads/writes DSP registers. For accuracy, you must first call run() - // to catch the DSP up to present. - int read ( int addr ) const; - void write( int addr, int data ); - - // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks - // a pair of samples is be generated. - void run( int clock_count ); - -// Sound control - - // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). - // Reduces emulation accuracy. - enum { voice_count = 8 }; - void mute_voices( int mask ); - -// State - - // Resets DSP and uses supplied values to initialize registers - enum { register_count = 128 }; - void load( uint8_t const regs [register_count] ); - - // Saves/loads exact emulator state - enum { state_size = 640 }; // maximum space needed when saving - typedef dsp_copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); - - // Returns non-zero if new key-on events occurred since last call - bool check_kon(); - -// DSP register addresses - - // 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 - }; - -public: - enum { extra_size = 16 }; - sample_t* extra() { return m.extra; } - sample_t const* out_pos() const { return m.out; } - void disable_surround( bool ) { } // not supported -public: - BLARGG_DISABLE_NOTHROW - - typedef BOOST::int8_t int8_t; - typedef BOOST::int16_t int16_t; - - enum { echo_hist_size = 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_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 - env_mode_t env_mode; - int env; // current envelope level - int hidden_env; // used by GAIN mode 7, very obscure quirk - uint8_t t_envx_out; - }; -private: - enum { brr_block_size = 9 }; - - struct state_t - { - uint8_t regs [register_count]; - - // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) - int echo_hist [echo_hist_size * 2] [2]; - int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] - - 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 - int phase; // next clock cycle to run (0-31) - bool kon_check; // set when a new KON occurs - - // Hidden registers also written to when main register is written to - int new_kon; - uint8_t endx_buf; - uint8_t envx_buf; - uint8_t 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; - int t_esa; - int t_echo_enabled; - - // internal state that is recalculated every sample - int t_dir_addr; - int t_pitch; - int t_output; - int t_looped; - int t_echo_ptr; - - // left/right sums - int t_main_out [2]; - int t_echo_out [2]; - int t_echo_in [2]; - - voice_t voices [voice_count]; - - // non-emulation state - uint8_t* ram; // 64K shared RAM between DSP and SMP - int mute_mask; - sample_t* out; - sample_t* out_end; - sample_t* out_begin; - sample_t extra [extra_size]; - }; - state_t m; - - void init_counter(); - void run_counters(); - unsigned read_counter( int rate ); - - int interpolate( voice_t const* v ); - void run_envelope( voice_t* const v ); - void decode_brr( voice_t* v ); - - void misc_27(); - void misc_28(); - void misc_29(); - void misc_30(); - - 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 ); - - void echo_read( int ch ); - int echo_output( int ch ); - void echo_write( int ch ); - void echo_22(); - void echo_23(); - void echo_24(); - void echo_25(); - void echo_26(); - void echo_27(); - void echo_28(); - void echo_29(); - void echo_30(); - - void soft_reset_common(); -}; - -#include - -inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } - -inline int SPC_DSP::read( int addr ) const -{ - assert( (unsigned) addr < register_count ); - return m.regs [addr]; -} - -inline void SPC_DSP::write( int addr, int data ) -{ - assert( (unsigned) addr < register_count ); - - m.regs [addr] = (uint8_t) data; - switch ( addr & 0x0F ) - { - case v_envx: - m.envx_buf = (uint8_t) data; - break; - - case v_outx: - m.outx_buf = (uint8_t) data; - break; - - case 0x0C: - if ( addr == r_kon ) - m.new_kon = (uint8_t) data; - - if ( addr == r_endx ) // always cleared, regardless of data written - { - m.endx_buf = 0; - m.regs [r_endx] = 0; - } - break; - } -} - -inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } - -inline bool SPC_DSP::check_kon() -{ - bool old = m.kon_check; - m.kon_check = 0; - return old; -} - -#if !SPC_NO_COPY_STATE_FUNCS - -class SPC_State_Copier { - SPC_DSP::copy_func_t func; - unsigned char** buf; -public: - SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } - void copy( void* state, size_t size ); - int copy_int( int state, int size ); - void skip( int count ); - void extra(); -}; - -#define SPC_COPY( type, state )\ -{\ - state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\ - assert( (BOOST::type) state == state );\ -} - -#endif - -#endif diff --git a/snes/fast/snes_spc/SPC_Filter.cpp b/snes/fast/snes_spc/SPC_Filter.cpp deleted file mode 100755 index b3d57708..00000000 --- a/snes/fast/snes_spc/SPC_Filter.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SPC_Filter.h" - -#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 */ - -#include "blargg_source.h" - -void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); } - -SPC_Filter::SPC_Filter() -{ - gain = gain_unit; - bass = bass_norm; - clear(); -} - -void SPC_Filter::run( short* io, int count ) -{ - require( (count & 1) == 0 ); // must be even - - int const gain = this->gain; - int const bass = this->bass; - chan_t* c = &ch [2]; - do - { - // cache in registers - int sum = (--c)->sum; - int pp1 = c->pp1; - int p1 = c->p1; - - for ( int i = 0; i < count; i += 2 ) - { - // Low-pass filter (two point FIR with coeffs 0.25, 0.75) - int f = io [i] + p1; - p1 = io [i] * 3; - - // High-pass filter ("leaky integrator") - int delta = f - pp1; - pp1 = f; - int s = sum >> (gain_bits + 2); - sum += (delta * gain) - (sum >> bass); - - // Clamp to 16 bits - if ( (short) s != s ) - s = (s >> 31) ^ 0x7FFF; - - io [i] = (short) s; - } - - c->p1 = p1; - c->pp1 = pp1; - c->sum = sum; - ++io; - } - while ( c != ch ); -} diff --git a/snes/fast/snes_spc/SPC_Filter.h b/snes/fast/snes_spc/SPC_Filter.h deleted file mode 100755 index d5c83cb8..00000000 --- a/snes/fast/snes_spc/SPC_Filter.h +++ /dev/null @@ -1,47 +0,0 @@ -// Simple low-pass and high-pass filter to better match sound output of a SNES - -// snes_spc 0.9.0 -#ifndef SPC_FILTER_H -#define SPC_FILTER_H - -#include "blargg_common.h" - -struct SPC_Filter { -public: - - // Filters count samples of stereo sound in place. Count must be a multiple of 2. - typedef short sample_t; - void run( sample_t* io, int count ); - -// Optional features - - // Clears filter to silence - void clear(); - - // Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit - // are fine, since output is clamped to 16-bit sample range. - enum { gain_unit = 0x100 }; - void set_gain( int gain ); - - // Sets amount of bass (logarithmic scale) - enum { bass_none = 0 }; - enum { bass_norm = 8 }; // normal amount - enum { bass_max = 31 }; - void set_bass( int bass ); - -public: - SPC_Filter(); - BLARGG_DISABLE_NOTHROW -private: - enum { gain_bits = 8 }; - int gain; - int bass; - struct chan_t { int p1, pp1, sum; }; - chan_t ch [2]; -}; - -inline void SPC_Filter::set_gain( int g ) { gain = g; } - -inline void SPC_Filter::set_bass( int b ) { bass = b; } - -#endif diff --git a/snes/fast/snes_spc/blargg_common.h b/snes/fast/snes_spc/blargg_common.h deleted file mode 100755 index 75edff39..00000000 --- a/snes/fast/snes_spc/blargg_common.h +++ /dev/null @@ -1,186 +0,0 @@ -// Sets up common environment for Shay Green's libraries. -// To change configuration options, modify blargg_config.h, not this file. - -// snes_spc 0.9.0 -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -#include -#include -#include -#include - -#undef BLARGG_COMMON_H -// allow blargg_config.h to #include blargg_common.h -#include "blargg_config.h" -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -// BLARGG_RESTRICT: equivalent to restrict, where supported -#if defined (__GNUC__) || _MSC_VER >= 1100 - #define BLARGG_RESTRICT __restrict -#else - #define BLARGG_RESTRICT -#endif - -// STATIC_CAST(T,expr): Used in place of static_cast (expr) -#ifndef STATIC_CAST - #define STATIC_CAST(T,expr) ((T) (expr)) -#endif - -// blargg_err_t (0 on success, otherwise error string) -#ifndef blargg_err_t - typedef const char* blargg_err_t; -#endif - -// blargg_vector - very lightweight vector of POD types (no constructor/destructor) -template -class blargg_vector { - T* begin_; - size_t size_; -public: - blargg_vector() : begin_( 0 ), size_( 0 ) { } - ~blargg_vector() { free( begin_ ); } - size_t size() const { return size_; } - T* begin() const { return begin_; } - T* end() const { return begin_ + size_; } - blargg_err_t resize( size_t n ) - { - // TODO: blargg_common.cpp to hold this as an outline function, ugh - void* p = realloc( begin_, n * sizeof (T) ); - if ( p ) - begin_ = (T*) p; - else if ( n > size_ ) // realloc failure only a problem if expanding - return "Out of memory"; - size_ = n; - return 0; - } - void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } - T& operator [] ( size_t n ) const - { - assert( n <= size_ ); // <= to allow past-the-end value - return begin_ [n]; - } -}; - -#ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if operator new can return NULL - #if __cplusplus >= 199711 || defined (__GNUC__) - #define BLARGG_THROWS( spec ) throw spec - #else - #define BLARGG_THROWS( spec ) - #endif - #define BLARGG_DISABLE_NOTHROW \ - void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ - void operator delete ( void* p ) { free( p ); } - #define BLARGG_NEW new -#else - #include - #define BLARGG_NEW new (std::nothrow) -#endif - -// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) -#define BLARGG_4CHAR( a, b, c, d ) \ - ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) - -// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. -#ifndef BOOST_STATIC_ASSERT - #ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) - #else - // Some other compilers fail when declaring same function multiple times in class, - // so differentiate them by line - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) - #endif -#endif - -// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, -// compiler is assumed to support bool. If undefined, availability is determined. -#ifndef BLARGG_COMPILER_HAS_BOOL - #if defined (__MWERKS__) - #if !__option(bool) - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (_MSC_VER) - #if _MSC_VER < 1100 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (__GNUC__) - // supports bool - #elif __cplusplus < 199711 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif -#endif -#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL - // If you get errors here, modify your blargg_config.h file - typedef int bool; - const bool true = 1; - const bool false = 0; -#endif - -// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough - -#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF - typedef long blargg_long; -#else - typedef int blargg_long; -#endif - -#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF - typedef unsigned long blargg_ulong; -#else - typedef unsigned blargg_ulong; -#endif - -// BOOST::int8_t etc. - -// HAVE_STDINT_H: If defined, use for int8_t etc. -#if defined (HAVE_STDINT_H) - #include - #define BOOST - -// HAVE_INTTYPES_H: If defined, use for int8_t etc. -#elif defined (HAVE_INTTYPES_H) - #include - #define BOOST - -#else - struct BOOST - { - #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F - typedef signed char int8_t; - typedef unsigned char uint8_t; - #else - // No suitable 8-bit type available - typedef struct see_blargg_common_h int8_t; - typedef struct see_blargg_common_h uint8_t; - #endif - - #if USHRT_MAX == 0xFFFF - typedef short int16_t; - typedef unsigned short uint16_t; - #else - // No suitable 16-bit type available - typedef struct see_blargg_common_h int16_t; - typedef struct see_blargg_common_h uint16_t; - #endif - - #if ULONG_MAX == 0xFFFFFFFF - typedef long int32_t; - typedef unsigned long uint32_t; - #elif UINT_MAX == 0xFFFFFFFF - typedef int int32_t; - typedef unsigned int uint32_t; - #else - // No suitable 32-bit type available - typedef struct see_blargg_common_h int32_t; - typedef struct see_blargg_common_h uint32_t; - #endif - }; -#endif - -#endif -#endif diff --git a/snes/fast/snes_spc/blargg_config.h b/snes/fast/snes_spc/blargg_config.h deleted file mode 100755 index 9dc69db8..00000000 --- a/snes/fast/snes_spc/blargg_config.h +++ /dev/null @@ -1,24 +0,0 @@ -// snes_spc 0.9.0 user configuration file. Don't replace when updating library. - -// snes_spc 0.9.0 -#ifndef BLARGG_CONFIG_H -#define BLARGG_CONFIG_H - -// Uncomment to disable debugging checks -//#define NDEBUG 1 - -// Uncomment to enable platform-specific (and possibly non-portable) optimizations -//#define BLARGG_NONPORTABLE 1 - -// Uncomment if automatic byte-order determination doesn't work -//#define BLARGG_BIG_ENDIAN 1 - -// Uncomment if you get errors in the bool section of blargg_common.h -//#define BLARGG_COMPILER_HAS_BOOL 1 - -// Use standard config.h if present -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#endif diff --git a/snes/fast/snes_spc/blargg_endian.h b/snes/fast/snes_spc/blargg_endian.h deleted file mode 100755 index f2daca64..00000000 --- a/snes/fast/snes_spc/blargg_endian.h +++ /dev/null @@ -1,185 +0,0 @@ -// CPU Byte Order Utilities - -// snes_spc 0.9.0 -#ifndef BLARGG_ENDIAN -#define BLARGG_ENDIAN - -#include "blargg_common.h" - -// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) -#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ - defined (__x86_64__) || defined (__ia64__) || defined (__i386__) - #define BLARGG_CPU_X86 1 - #define BLARGG_CPU_CISC 1 -#endif - -#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) - #define BLARGG_CPU_POWERPC 1 - #define BLARGG_CPU_RISC 1 -#endif - -// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only -// one may be #defined to 1. Only needed if something actually depends on byte order. -#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) -#ifdef __GLIBC__ - // GCC handles this for us - #include - #if __BYTE_ORDER == __LITTLE_ENDIAN - #define BLARGG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER == __BIG_ENDIAN - #define BLARGG_BIG_ENDIAN 1 - #endif -#else - -#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ - (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) - #define BLARGG_LITTLE_ENDIAN 1 -#endif - -#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ - defined (__sparc__) || BLARGG_CPU_POWERPC || \ - (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) - #define BLARGG_BIG_ENDIAN 1 -#elif !defined (__mips__) - // No endian specified; assume little-endian, since it's most common - #define BLARGG_LITTLE_ENDIAN 1 -#endif -#endif -#endif - -#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN - #undef BLARGG_LITTLE_ENDIAN - #undef BLARGG_BIG_ENDIAN -#endif - -inline void blargg_verify_byte_order() -{ - #ifndef NDEBUG - #if BLARGG_BIG_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i == 0 ); - #elif BLARGG_LITTLE_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i != 0 ); - #endif - #endif -} - -inline unsigned get_le16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 8 | - (unsigned) ((unsigned char const*) p) [1]; -} - -inline blargg_ulong get_le32( void const* p ) -{ - return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | - (blargg_ulong) ((unsigned char const*) p) [2] << 16 | - (blargg_ulong) ((unsigned char const*) p) [1] << 8 | - (blargg_ulong) ((unsigned char const*) p) [0]; -} - -inline blargg_ulong get_be32( void const* p ) -{ - return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | - (blargg_ulong) ((unsigned char const*) p) [1] << 16 | - (blargg_ulong) ((unsigned char const*) p) [2] << 8 | - (blargg_ulong) ((unsigned char const*) p) [3]; -} - -inline void set_le16( void* p, unsigned n ) -{ - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [0] = (unsigned char) n; -} - -inline void set_be16( void* p, unsigned n ) -{ - ((unsigned char*) p) [0] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) n; -} - -inline void set_le32( void* p, blargg_ulong n ) -{ - ((unsigned char*) p) [0] = (unsigned char) n; - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [2] = (unsigned char) (n >> 16); - ((unsigned char*) p) [3] = (unsigned char) (n >> 24); -} - -inline void set_be32( void* p, blargg_ulong n ) -{ - ((unsigned char*) p) [3] = (unsigned char) n; - ((unsigned char*) p) [2] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) (n >> 16); - ((unsigned char*) p) [0] = (unsigned char) (n >> 24); -} - -#if BLARGG_NONPORTABLE - // Optimized implementation if byte order is known - #if BLARGG_LITTLE_ENDIAN - #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) - #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) - #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #elif BLARGG_BIG_ENDIAN - #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) - #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) - #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - - #if BLARGG_CPU_POWERPC - // PowerPC has special byte-reversed instructions - #if defined (__MWERKS__) - #define GET_LE16( addr ) (__lhbrx( addr, 0 )) - #define GET_LE32( addr ) (__lwbrx( addr, 0 )) - #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) - #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) - #elif defined (__GNUC__) - #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) - #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) - #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) - #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) - #endif - #endif - #endif -#endif - -#ifndef GET_LE16 - #define GET_LE16( addr ) get_le16( addr ) - #define SET_LE16( addr, data ) set_le16( addr, data ) -#endif - -#ifndef GET_LE32 - #define GET_LE32( addr ) get_le32( addr ) - #define SET_LE32( addr, data ) set_le32( addr, data ) -#endif - -#ifndef GET_BE16 - #define GET_BE16( addr ) get_be16( addr ) - #define SET_BE16( addr, data ) set_be16( addr, data ) -#endif - -#ifndef GET_BE32 - #define GET_BE32( addr ) get_be32( addr ) - #define SET_BE32( addr, data ) set_be32( addr, data ) -#endif - -// auto-selecting versions - -inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } -inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } -inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } -inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } -inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } -inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } -inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } -inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } - -#endif diff --git a/snes/fast/snes_spc/blargg_source.h b/snes/fast/snes_spc/blargg_source.h deleted file mode 100755 index 5e45c4fb..00000000 --- a/snes/fast/snes_spc/blargg_source.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Included at the beginning of library source files, after all other #include lines. -Sets up helpful macros and services used in my source code. They don't need -module an annoying module prefix on their names since they are defined after -all other #include lines. */ - -// snes_spc 0.9.0 -#ifndef BLARGG_SOURCE_H -#define BLARGG_SOURCE_H - -// If debugging is enabled, abort program if expr is false. Meant for checking -// internal state and consistency. A failed assertion indicates a bug in the module. -// void assert( bool expr ); -#include - -// If debugging is enabled and expr is false, abort program. Meant for checking -// caller-supplied parameters and operations that are outside the control of the -// module. A failed requirement indicates a bug outside the module. -// void require( bool expr ); -#undef require -#define require( expr ) assert( expr ) - -// Like printf() except output goes to debug log file. Might be defined to do -// nothing (not even evaluate its arguments). -// void dprintf( const char* format, ... ); -static inline void blargg_dprintf_( const char*, ... ) { } -#undef dprintf -#define dprintf (1) ? (void) 0 : blargg_dprintf_ - -// If enabled, evaluate expr and if false, make debug log entry with source file -// and line. Meant for finding situations that should be examined further, but that -// don't indicate a problem. In all cases, execution continues normally. -#undef check -#define check( expr ) ((void) 0) - -// If expr yields error string, return it from current function, otherwise continue. -#undef RETURN_ERR -#define RETURN_ERR( expr ) do { \ - blargg_err_t blargg_return_err_ = (expr); \ - if ( blargg_return_err_ ) return blargg_return_err_; \ - } while ( 0 ) - -// If ptr is 0, return out of memory error string. -#undef CHECK_ALLOC -#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) - -// Avoid any macros which evaluate their arguments multiple times -#undef min -#undef max - -#define DEF_MIN_MAX( type ) \ - static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ - static inline type max( type x, type y ) { if ( y < x ) return x; return y; } - -DEF_MIN_MAX( int ) -DEF_MIN_MAX( unsigned ) -DEF_MIN_MAX( long ) -DEF_MIN_MAX( unsigned long ) -DEF_MIN_MAX( float ) -DEF_MIN_MAX( double ) - -#undef DEF_MIN_MAX - -/* -// using const references generates crappy code, and I am currenly only using these -// for built-in types, so they take arguments by value - -// TODO: remove -inline int min( int x, int y ) -template -inline T min( T x, T y ) -{ - if ( x < y ) - return x; - return y; -} - -template -inline T max( T x, T y ) -{ - if ( x < y ) - return y; - return x; -} -*/ - -// TODO: good idea? bad idea? -#undef byte -#define byte byte_ -typedef unsigned char byte; - -// deprecated -#define BLARGG_CHECK_ALLOC CHECK_ALLOC -#define BLARGG_RETURN_ERR RETURN_ERR - -// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check -#ifdef BLARGG_SOURCE_BEGIN - #include BLARGG_SOURCE_BEGIN -#endif - -#endif diff --git a/snes/fast/snes_spc/dsp.cpp b/snes/fast/snes_spc/dsp.cpp deleted file mode 100755 index 99d0cf5c..00000000 --- a/snes/fast/snes_spc/dsp.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "dsp.h" - -#include "SPC_DSP.h" - -/* 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 */ - -#include "blargg_source.h" - -SPC_DSP* spc_dsp_new( void ) -{ - // be sure constants match - assert( spc_dsp_voice_count == (int) SPC_DSP::voice_count ); - assert( spc_dsp_register_count == (int) SPC_DSP::register_count ); - #if !SPC_NO_COPY_STATE_FUNCS - assert( spc_dsp_state_size == (int) SPC_DSP::state_size ); - #endif - - return new SPC_DSP; -} - -void spc_dsp_delete ( SPC_DSP* s ) { delete s; } -void spc_dsp_init ( SPC_DSP* s, void* ram_64k ) { s->init( ram_64k ); } -void spc_dsp_set_output ( SPC_DSP* s, spc_dsp_sample_t* p, int n ) { s->set_output( p, n ); } -int spc_dsp_sample_count( SPC_DSP const* s ) { return s->sample_count(); } -void spc_dsp_reset ( SPC_DSP* s ) { s->reset(); } -void spc_dsp_soft_reset ( SPC_DSP* s ) { s->soft_reset(); } -int spc_dsp_read ( SPC_DSP const* s, int addr ) { return s->read( addr ); } -void spc_dsp_write ( SPC_DSP* s, int addr, int data ) { s->write( addr, data ); } -void spc_dsp_run ( SPC_DSP* s, int clock_count ) { s->run( clock_count ); } -void spc_dsp_mute_voices ( SPC_DSP* s, int mask ) { s->mute_voices( mask ); } -void spc_dsp_disable_surround( SPC_DSP* s, int disable ) { s->disable_surround( disable ); } -void spc_dsp_load ( SPC_DSP* s, unsigned char const regs [spc_dsp_register_count] ) { s->load( regs ); } - -#if !SPC_NO_COPY_STATE_FUNCS -void spc_dsp_copy_state ( SPC_DSP* s, unsigned char** p, spc_dsp_copy_func_t f ) { s->copy_state( p, f ); } -int spc_dsp_check_kon ( SPC_DSP* s ) { return s->check_kon(); } -#endif diff --git a/snes/fast/snes_spc/dsp.h b/snes/fast/snes_spc/dsp.h deleted file mode 100755 index 59867d92..00000000 --- a/snes/fast/snes_spc/dsp.h +++ /dev/null @@ -1,83 +0,0 @@ -/* SNES SPC-700 DSP emulator C interface (also usable from C++) */ - -/* snes_spc 0.9.0 */ -#ifndef DSP_H -#define DSP_H - -#include - -#ifdef __cplusplus - extern "C" { -#endif - -typedef struct SPC_DSP SPC_DSP; - -/* Creates new DSP emulator. NULL if out of memory. */ -SPC_DSP* spc_dsp_new( void ); - -/* Frees DSP emulator */ -void spc_dsp_delete( SPC_DSP* ); - -/* Initializes DSP and has it use the 64K RAM provided */ -void spc_dsp_init( SPC_DSP*, void* ram_64k ); - -/* Sets destination for output samples. If out is NULL or out_size is 0, -doesn't generate any. */ -typedef short spc_dsp_sample_t; -void spc_dsp_set_output( SPC_DSP*, spc_dsp_sample_t* out, int out_size ); - -/* Number of samples written to output since it was last set, always -a multiple of 2. Undefined if more samples were generated than -output buffer could hold. */ -int spc_dsp_sample_count( SPC_DSP const* ); - - -/**** Emulation *****/ - -/* Resets DSP to power-on state */ -void spc_dsp_reset( SPC_DSP* ); - -/* Emulates pressing reset switch on SNES */ -void spc_dsp_soft_reset( SPC_DSP* ); - -/* Reads/writes DSP registers. For accuracy, you must first call spc_dsp_run() */ -/* to catch the DSP up to present. */ -int spc_dsp_read ( SPC_DSP const*, int addr ); -void spc_dsp_write( SPC_DSP*, int addr, int data ); - -/* Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks */ -/* a pair of samples is be generated. */ -void spc_dsp_run( SPC_DSP*, int clock_count ); - - -/**** Sound control *****/ - -/* Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */ -enum { spc_dsp_voice_count = 8 }; -void spc_dsp_mute_voices( SPC_DSP*, int mask ); - -/* If true, prevents channels and global volumes from being phase-negated. -Only supported by fast DSP; has no effect on accurate DSP. */ -void spc_dsp_disable_surround( SPC_DSP*, int disable ); - - -/**** State save/load *****/ - -/* Resets DSP and uses supplied values to initialize registers */ -enum { spc_dsp_register_count = 128 }; -void spc_dsp_load( SPC_DSP*, unsigned char const regs [spc_dsp_register_count] ); - -/* Saves/loads exact emulator state (accurate DSP only) */ -enum { spc_dsp_state_size = 640 }; /* maximum space needed when saving */ -typedef void (*spc_dsp_copy_func_t)( unsigned char** io, void* state, size_t ); -void spc_dsp_copy_state( SPC_DSP*, unsigned char** io, spc_dsp_copy_func_t ); - -/* Returns non-zero if new key-on events occurred since last call (accurate DSP only) */ -int spc_dsp_check_kon( SPC_DSP* ); - - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/snes/fast/snes_spc/spc.cpp b/snes/fast/snes_spc/spc.cpp deleted file mode 100755 index 85deaefc..00000000 --- a/snes/fast/snes_spc/spc.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "spc.h" - -#include "SNES_SPC.h" -#include "SPC_Filter.h" - -/* Copyright (C) 2004-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 */ - -#include "blargg_source.h" - -SNES_SPC* spc_new( void ) -{ - // be sure constants match - assert( spc_sample_rate == (int) SNES_SPC::sample_rate ); - assert( spc_rom_size == (int) SNES_SPC::rom_size ); - assert( spc_clock_rate == (int) SNES_SPC::clock_rate ); - assert( spc_clocks_per_sample == (int) SNES_SPC::clocks_per_sample ); - assert( spc_port_count == (int) SNES_SPC::port_count ); - assert( spc_voice_count == (int) SNES_SPC::voice_count ); - assert( spc_tempo_unit == (int) SNES_SPC::tempo_unit ); - assert( spc_file_size == (int) SNES_SPC::spc_file_size ); - #if !SPC_NO_COPY_STATE_FUNCS - assert( spc_state_size == (int) SNES_SPC::state_size ); - #endif - - SNES_SPC* s = new SNES_SPC; - if ( s && s->init() ) - { - delete s; - s = 0; - } - return s; -} - -void spc_delete ( SNES_SPC* s ) { delete s; } -void spc_init_rom ( SNES_SPC* s, unsigned char const r [64] ) { s->init_rom( r ); } -void spc_set_output ( SNES_SPC* s, spc_sample_t* p, int n ) { s->set_output( p, n ); } -int spc_sample_count ( SNES_SPC const* s ) { return s->sample_count(); } -void spc_reset ( SNES_SPC* s ) { s->reset(); } -void spc_soft_reset ( SNES_SPC* s ) { s->soft_reset(); } -int spc_read_port ( SNES_SPC* s, spc_time_t t, int p ) { return s->read_port( t, p ); } -void spc_write_port ( SNES_SPC* s, spc_time_t t, int p, int d ) { s->write_port( t, p, d ); } -void spc_end_frame ( SNES_SPC* s, spc_time_t t ) { s->end_frame( t ); } -void spc_mute_voices ( SNES_SPC* s, int mask ) { s->mute_voices( mask ); } -void spc_disable_surround( SNES_SPC* s, int disable ) { s->disable_surround( disable ); } -void spc_set_tempo ( SNES_SPC* s, int tempo ) { s->set_tempo( tempo ); } -spc_err_t spc_load_spc ( SNES_SPC* s, void const* p, long n ) { return s->load_spc( p, n ); } -void spc_clear_echo ( SNES_SPC* s ) { s->clear_echo(); } -spc_err_t spc_play ( SNES_SPC* s, int count, short* out ) { return s->play( count, out ); } -spc_err_t spc_skip ( SNES_SPC* s, int count ) { return s->skip( count ); } -#if !SPC_NO_COPY_STATE_FUNCS -void spc_copy_state ( SNES_SPC* s, unsigned char** p, spc_copy_func_t f ) { s->copy_state( p, f ); } -void spc_init_header ( void* spc_out ) { SNES_SPC::init_header( spc_out ); } -void spc_save_spc ( SNES_SPC* s, void* spc_out ) { s->save_spc( spc_out ); } -int spc_check_kon ( SNES_SPC* s ) { return s->check_kon(); } -#endif - -SPC_Filter* spc_filter_new( void ) { return new SPC_Filter; } -void spc_filter_delete( SPC_Filter* f ) { delete f; } -void spc_filter_run( SPC_Filter* f, spc_sample_t* p, int s ) { f->run( p, s ); } -void spc_filter_clear( SPC_Filter* f ) { f->clear(); } -void spc_filter_set_gain( SPC_Filter* f, int gain ) { f->set_gain( gain ); } -void spc_filter_set_bass( SPC_Filter* f, int bass ) { f->set_bass( bass ); } diff --git a/snes/fast/snes_spc/spc.h b/snes/fast/snes_spc/spc.h deleted file mode 100755 index 9ffdedce..00000000 --- a/snes/fast/snes_spc/spc.h +++ /dev/null @@ -1,147 +0,0 @@ -/* SNES SPC-700 APU emulator C interface (also usable from C++) */ - -/* snes_spc 0.9.0 */ -#ifndef SPC_H -#define SPC_H - -#include - -#ifdef __cplusplus - extern "C" { -#endif - -/* Error string return. NULL if success, otherwise error message. */ -typedef const char* spc_err_t; - -typedef struct SNES_SPC SNES_SPC; - -/* Creates new SPC emulator. NULL if out of memory. */ -SNES_SPC* spc_new( void ); - -/* Frees SPC emulator */ -void spc_delete( SNES_SPC* ); - -/* Sample pairs generated per second */ -enum { spc_sample_rate = 32000 }; - - -/**** Emulator use ****/ - -/* Sets IPL ROM data. Library does not include ROM data. Most SPC music files -don't need ROM, but a full emulator must provide this. */ -enum { spc_rom_size = 0x40 }; -void spc_init_rom( SNES_SPC*, unsigned char const rom [spc_rom_size] ); - -/* Sets destination for output samples */ -typedef short spc_sample_t; -void spc_set_output( SNES_SPC*, spc_sample_t* out, int out_size ); - -/* Number of samples written to output since last set */ -int spc_sample_count( SNES_SPC const* ); - -/* Resets SPC to power-on state. This resets your output buffer, so you must -call spc_set_output() after this. */ -void spc_reset( SNES_SPC* ); - -/* Emulates pressing reset switch on SNES. This resets your output buffer, so -you must call spc_set_output() after this. */ -void spc_soft_reset( SNES_SPC* ); - -/* 1024000 SPC clocks per second, sample pair every 32 clocks */ -typedef int spc_time_t; -enum { spc_clock_rate = 1024000 }; -enum { spc_clocks_per_sample = 32 }; - -/* Reads/writes port at specified time */ -enum { spc_port_count = 4 }; -int spc_read_port ( SNES_SPC*, spc_time_t, int port ); -void spc_write_port( SNES_SPC*, spc_time_t, int port, int data ); - -/* Runs SPC to end_time and starts a new time frame at 0 */ -void spc_end_frame( SNES_SPC*, spc_time_t end_time ); - - -/**** Sound control ****/ - -/*Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */ -enum { spc_voice_count = 8 }; -void spc_mute_voices( SNES_SPC*, int mask ); - -/* If true, prevents channels and global volumes from being phase-negated. -Only supported by fast DSP; has no effect on accurate DSP. */ -void spc_disable_surround( SNES_SPC*, int disable ); - -/* Sets tempo, where spc_tempo_unit = normal, spc_tempo_unit / 2 = half speed, etc. */ -enum { spc_tempo_unit = 0x100 }; -void spc_set_tempo( SNES_SPC*, int ); - - -/**** SPC music playback *****/ - -/* Loads SPC data into emulator. Returns NULL on success, otherwise error string. */ -spc_err_t spc_load_spc( SNES_SPC*, void const* spc_in, long size ); - -/* Clears echo region. Useful after loading an SPC as many have garbage in echo. */ -void spc_clear_echo( SNES_SPC* ); - -/* Plays for count samples and write samples to out. Discards samples if out -is NULL. Count must be a multiple of 2 since output is stereo. */ -spc_err_t spc_play( SNES_SPC*, int count, short* out ); - -/* Skips count samples. Several times faster than spc_play(). */ -spc_err_t spc_skip( SNES_SPC*, int count ); - - -/**** State save/load (only available with accurate DSP) ****/ - -/* Saves/loads exact emulator state */ -enum { spc_state_size = 67 * 1024L }; /* maximum space needed when saving */ -typedef void (*spc_copy_func_t)( unsigned char** io, void* state, size_t ); -void spc_copy_state( SNES_SPC*, unsigned char** io, spc_copy_func_t ); - -/* Writes minimal SPC file header to spc_out */ -void spc_init_header( void* spc_out ); - -/* Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. -Does not set up SPC header; use spc_init_header() for that. */ -enum { spc_file_size = 0x10200 }; /* spc_out must have this many bytes allocated */ -void spc_save_spc( SNES_SPC*, void* spc_out ); - -/* Returns non-zero if new key-on events occurred since last check. Useful for -trimming silence while saving an SPC. */ -int spc_check_kon( SNES_SPC* ); - - -/**** SPC_Filter ****/ - -typedef struct SPC_Filter SPC_Filter; - -/* Creates new filter. NULL if out of memory. */ -SPC_Filter* spc_filter_new( void ); - -/* Frees filter */ -void spc_filter_delete( SPC_Filter* ); - -/* Filters count samples of stereo sound in place. Count must be a multiple of 2. */ -void spc_filter_run( SPC_Filter*, spc_sample_t* io, int count ); - -/* Clears filter to silence */ -void spc_filter_clear( SPC_Filter* ); - -/* Sets gain (volume), where spc_filter_gain_unit is normal. Gains greater than -spc_filter_gain_unit are fine, since output is clamped to 16-bit sample range. */ -enum { spc_filter_gain_unit = 0x100 }; -void spc_filter_set_gain( SPC_Filter*, int gain ); - -/* Sets amount of bass (logarithmic scale) */ -enum { spc_filter_bass_none = 0 }; -enum { spc_filter_bass_norm = 8 }; /* normal amount */ -enum { spc_filter_bass_max = 31 }; -void spc_filter_set_bass( SPC_Filter*, int bass ); - - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/snes/memory/memory-inline.hpp b/snes/memory/memory-inline.hpp index 71127ca3..bf3aad65 100755 --- a/snes/memory/memory-inline.hpp +++ b/snes/memory/memory-inline.hpp @@ -58,12 +58,11 @@ uint8 Bus::read(uint24 addr) { if(cheat.read(addr, r)) return r; } #endif - Page &p = page[addr >> 8]; return p.access->read(p.offset + addr); } void Bus::write(uint24 addr, uint8 data) { Page &p = page[addr >> 8]; - return p.access->write(p.offset + addr, data); + p.access->write(p.offset + addr, data); } diff --git a/snes/memory/memory.cpp b/snes/memory/memory.cpp index 9c4a13bb..0ae1c1fb 100755 --- a/snes/memory/memory.cpp +++ b/snes/memory/memory.cpp @@ -27,20 +27,19 @@ uint8 UnmappedMMIO::mmio_read(unsigned) { return cpu.regs.mdr; } void UnmappedMMIO::mmio_write(unsigned, uint8) {} MMIO* MMIOAccess::handle(unsigned addr) { - return mmio[(addr - 0x2000) & 0x3fff]; + return mmio[addr & 0x7fff]; } void MMIOAccess::map(unsigned addr, MMIO &access) { - //MMIO: $[00-3f]:[2000-5fff] - mmio[(addr - 0x2000) & 0x3fff] = &access; + mmio[addr & 0x7fff] = &access; } uint8 MMIOAccess::read(unsigned addr) { - return mmio[(addr - 0x2000) & 0x3fff]->mmio_read(addr); + return mmio[addr & 0x7fff]->mmio_read(addr); } void MMIOAccess::write(unsigned addr, uint8 data) { - mmio[(addr - 0x2000) & 0x3fff]->mmio_write(addr, data); + mmio[addr & 0x7fff]->mmio_write(addr, data); } unsigned Bus::mirror(unsigned addr, unsigned size) { @@ -62,8 +61,9 @@ unsigned Bus::mirror(unsigned addr, unsigned size) { } void Bus::map(unsigned addr, Memory &access, unsigned offset) { - page[addr >> 8].access = &access; - page[addr >> 8].offset = offset - addr; + Page &p = page[addr >> 8]; + p.access = &access; + p.offset = offset - addr; } void Bus::map( diff --git a/snes/memory/memory.hpp b/snes/memory/memory.hpp index a6aaa883..c53dec94 100755 --- a/snes/memory/memory.hpp +++ b/snes/memory/memory.hpp @@ -64,7 +64,7 @@ struct MMIOAccess : Memory { void write(unsigned addr, uint8 data); private: - MMIO *mmio[0x4000]; + MMIO *mmio[0x8000]; }; struct Bus { diff --git a/snes/ppu/debugger/debugger.cpp b/snes/ppu/debugger/debugger.cpp index 501874f1..28a519fc 100755 --- a/snes/ppu/debugger/debugger.cpp +++ b/snes/ppu/debugger/debugger.cpp @@ -3,302 +3,14 @@ bool PPUDebugger::property(unsigned id, string &name, string &value) { unsigned n = 0; - //internal - if(id == n++) { name = "S-PPU1 MDR"; value = string("0x", strhex<2>(ppu1_mdr())); return true; } - if(id == n++) { name = "S-PPU2 MDR"; value = string("0x", strhex<2>(ppu2_mdr())); return true; } - - //$2100 - if(id == n++) { name = "$2100"; value = ""; return true; } - if(id == n++) { name = "Display Disable"; value = display_disable(); return true; } - if(id == n++) { name = "Display Brightness"; value = display_brightness(); return true; } - - //$2101 - if(id == n++) { name = "$2101"; value = ""; return true; } - if(id == n++) { name = "OAM Base Size"; value = oam_base_size(); return true; } - if(id == n++) { name = "OAM Name Select"; value = oam_name_select(); return true; } - if(id == n++) { name = "OAM Name Base Address"; value = string("0x", strhex<4>(oam_name_base_address())); return true; } - - //$2102-$2103 - if(id == n++) { name = "$2102-$2103"; value = ""; return true; } - if(id == n++) { name = "OAM Base Address"; value = string("0x", strhex<4>(oam_base_address())); return true; } - if(id == n++) { name = "OAM Priority"; value = oam_priority(); return true; } - - //$2105 - if(id == n++) { name = "$2105"; value = ""; return true; } - if(id == n++) { name = "BG1 Tile Size"; value = bg1_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG2 Tile Size"; value = bg2_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG3 Tile Size"; value = bg3_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG4 Tile Size"; value = bg4_tile_size() ? "16x16" : "8x8"; return true; } - if(id == n++) { name = "BG3 Priority"; value = bg3_priority(); return true; } - if(id == n++) { name = "BG Mode"; value = bg_mode(); return true; } - - //$2106 - if(id == n++) { name = "$2106"; value = ""; return true; } - if(id == n++) { name = "Mosaic Size"; value = mosaic_size(); return true; } - if(id == n++) { name = "BG1 Mosaic Enable"; value = bg1_mosaic_enable(); return true; } - if(id == n++) { name = "BG2 Mosaic Enable"; value = bg2_mosaic_enable(); return true; } - if(id == n++) { name = "BG3 Mosaic Enable"; value = bg3_mosaic_enable(); return true; } - if(id == n++) { name = "BG4 Mosaic Enable"; value = bg4_mosaic_enable(); return true; } - - static char screen_size[4][8] = { "32x32", "32x64", "64x32", "64x64" }; - - //$2107 - if(id == n++) { name = "$2107"; value = ""; return true; } - if(id == n++) { name = "BG1 Screen Address"; value = string("0x", strhex<4>(bg1_screen_address())); return true; } - if(id == n++) { name = "BG1 Screen Size"; value = screen_size[bg1_screen_size()]; return true; } - - //$2108 - if(id == n++) { name = "$2108"; value = ""; return true; } - if(id == n++) { name = "BG2 Screen Address"; value = string("0x", strhex<4>(bg2_screen_address())); return true; } - if(id == n++) { name = "BG2 Screen Size"; value = screen_size[bg2_screen_size()]; return true; } - - //$2109 - if(id == n++) { name = "$2109"; value = ""; return true; } - if(id == n++) { name = "BG3 Screen Address"; value = string("0x", strhex<4>(bg3_screen_address())); return true; } - if(id == n++) { name = "BG3 Screen Size"; value = screen_size[bg3_screen_size()]; return true; } - - //$210a - if(id == n++) { name = "$210a"; value = ""; return true; } - if(id == n++) { name = "BG4 Screen Address"; value = string("0x", strhex<4>(bg4_screen_address())); return true; } - if(id == n++) { name = "BG4 Screen Size"; value = screen_size[bg4_screen_size()]; return true; } - - //$210b - if(id == n++) { name = "$210b"; value = ""; return true; } - if(id == n++) { name = "BG1 Name Base Address"; value = string("0x", strhex<4>(bg1_name_base_address())); return true; } - if(id == n++) { name = "BG2 Name Base Address"; value = string("0x", strhex<4>(bg2_name_base_address())); return true; } - - //$210c - if(id == n++) { name = "$210c"; value = ""; return true; } - if(id == n++) { name = "BG3 Name Base Address"; value = string("0x", strhex<4>(bg3_name_base_address())); return true; } - if(id == n++) { name = "BG4 Name Base Address"; value = string("0x", strhex<4>(bg4_name_base_address())); return true; } - - //$210d - if(id == n++) { name = "$210d"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Scroll H-offset"; value = mode7_hoffset(); return true; } - if(id == n++) { name = "BG1 Scroll H-offset"; value = bg1_hoffset(); return true; } - - //$210e - if(id == n++) { name = "$210e"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Scroll V-offset"; value = mode7_voffset(); return true; } - if(id == n++) { name = "BG1 Scroll V-offset"; value = bg1_voffset(); return true; } - - //$210f - if(id == n++) { name = "$210f"; value = ""; return true; } - if(id == n++) { name = "BG2 Scroll H-offset"; value = bg2_hoffset(); return true; } - - //$2110 - if(id == n++) { name = "$2110"; value = ""; return true; } - if(id == n++) { name = "BG2 Scroll V-offset"; value = bg2_voffset(); return true; } - - //$2111 - if(id == n++) { name = "$2111"; value = ""; return true; } - if(id == n++) { name = "BG3 Scroll H-offset"; value = bg3_hoffset(); return true; } - - //$2112 - if(id == n++) { name = "$2112"; value = ""; return true; } - if(id == n++) { name = "BG3 Scroll V-offset"; value = bg3_voffset(); return true; } - - //$2113 - if(id == n++) { name = "$2113"; value = ""; return true; } - if(id == n++) { name = "BG4 Scroll H-offset"; value = bg4_hoffset(); return true; } - - //$2114 - if(id == n++) { name = "$2114"; value = ""; return true; } - if(id == n++) { name = "BG4 Scroll V-offset"; value = bg4_voffset(); return true; } - - //$2115 - if(id == n++) { name = "$2115"; value = ""; return true; } - if(id == n++) { name = "VRAM Increment Mode"; value = (unsigned)vram_increment_mode(); return true; } - if(id == n++) { name = "VRAM Increment Formation"; value = vram_increment_formation(); return true; } - if(id == n++) { name = "VRAM Increment Size"; value = vram_increment_size(); return true; } - - //$2116-$2117 - if(id == n++) { name = "$2116-$2117"; value = ""; return true; } - if(id == n++) { name = "VRAM Address"; value = string("0x", strhex<4>(vram_address())); return true; } - - //$211a - if(id == n++) { name = "$211a"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Repeat"; value = mode7_repeat(); return true; } - if(id == n++) { name = "Mode 7 V-flip"; value = mode7_vflip(); return true; } - if(id == n++) { name = "Mode 7 H-flip"; value = mode7_hflip(); return true; } - - //$211b - if(id == n++) { name = "$211b"; value = ""; return true; } - if(id == n++) { name = "Mode 7 A"; value = mode7_a(); return true; } - - //$211c - if(id == n++) { name = "$211c"; value = ""; return true; } - if(id == n++) { name = "Mode 7 B"; value = mode7_b(); return true; } - - //$211d - if(id == n++) { name = "$211d"; value = ""; return true; } - if(id == n++) { name = "Mode 7 C"; value = mode7_c(); return true; } - - //$211e - if(id == n++) { name = "$211e"; value = ""; return true; } - if(id == n++) { name = "Mode 7 D"; value = mode7_d(); return true; } - - //$211f - if(id == n++) { name = "$211f"; value = ""; return true; } - if(id == n++) { name = "Mode 7 X"; value = mode7_x(); return true; } - - //$2120 - if(id == n++) { name = "$2120"; value = ""; return true; } - if(id == n++) { name = "Mode 7 Y"; value = mode7_y(); return true; } - - //$2121 - if(id == n++) { name = "$2121"; value = ""; return true; } - if(id == n++) { name = "CGRAM Address"; value = string("0x", strhex<4>(cgram_address())); return true; } - - //$2123 - if(id == n++) { name = "$2123"; value = ""; return true; } - if(id == n++) { name = "BG1 Window 1 Enable"; value = bg1_window1_enable(); return true; } - if(id == n++) { name = "BG1 Window 1 Invert"; value = bg1_window1_invert(); return true; } - if(id == n++) { name = "BG1 Window 2 Enable"; value = bg1_window2_enable(); return true; } - if(id == n++) { name = "BG1 Window 2 Invert"; value = bg1_window2_invert(); return true; } - if(id == n++) { name = "BG2 Window 1 Enable"; value = bg2_window1_enable(); return true; } - if(id == n++) { name = "BG2 Window 1 Invert"; value = bg2_window1_invert(); return true; } - if(id == n++) { name = "BG2 Window 2 Enable"; value = bg2_window2_enable(); return true; } - if(id == n++) { name = "BG2 Window 2 Invert"; value = bg2_window2_invert(); return true; } - - //$2124 - if(id == n++) { name = "$2124"; value = ""; return true; } - if(id == n++) { name = "BG3 Window 1 Enable"; value = bg3_window1_enable(); return true; } - if(id == n++) { name = "BG3 Window 1 Invert"; value = bg3_window1_invert(); return true; } - if(id == n++) { name = "BG3 Window 2 Enable"; value = bg3_window2_enable(); return true; } - if(id == n++) { name = "BG3 Window 2 Invert"; value = bg3_window2_invert(); return true; } - if(id == n++) { name = "BG4 Window 1 Enable"; value = bg4_window1_enable(); return true; } - if(id == n++) { name = "BG4 Window 1 Invert"; value = bg4_window1_invert(); return true; } - if(id == n++) { name = "BG4 Window 2 Enable"; value = bg4_window2_enable(); return true; } - if(id == n++) { name = "BG4 Window 2 Invert"; value = bg4_window2_invert(); return true; } - - //$2125 - if(id == n++) { name = "$2125"; value = ""; return true; } - if(id == n++) { name = "OAM Window 1 Enable"; value = oam_window1_enable(); return true; } - if(id == n++) { name = "OAM Window 1 Invert"; value = oam_window1_invert(); return true; } - if(id == n++) { name = "OAM Window 2 Enable"; value = oam_window2_enable(); return true; } - if(id == n++) { name = "OAM Window 2 Invert"; value = oam_window2_invert(); return true; } - if(id == n++) { name = "Color Window 1 Enable"; value = color_window1_enable(); return true; } - if(id == n++) { name = "Color Window 1 Invert"; value = color_window1_invert(); return true; } - if(id == n++) { name = "Color Window 2 Enable"; value = color_window2_enable(); return true; } - if(id == n++) { name = "Color Window 2 Invert"; value = color_window2_invert(); return true; } - - //$2126 - if(id == n++) { name = "$2126"; value = ""; return true; } - if(id == n++) { name = "Window 1 Left"; value = window1_left(); return true; } - - //$2127 - if(id == n++) { name = "$2127"; value = ""; return true; } - if(id == n++) { name = "Window 1 Right"; value = window1_right(); return true; } - - //$2128 - if(id == n++) { name = "$2128"; value = ""; return true; } - if(id == n++) { name = "Window 2 Left"; value = window2_left(); return true; } - - //$2129 - if(id == n++) { name = "$2129"; value = ""; return true; } - if(id == n++) { name = "Window 2 Right"; value = window2_right(); return true; } - - static char window_mask_mode[4][8] = { "OR", "AND", "XOR", "XNOR" }; - - //$212a - if(id == n++) { name = "$212a"; value = ""; return true; } - if(id == n++) { name = "BG1 Window Mask"; value = window_mask_mode[bg1_window_mask()]; return true; } - if(id == n++) { name = "BG2 Window Mask"; value = window_mask_mode[bg2_window_mask()]; return true; } - if(id == n++) { name = "BG3 Window Mask"; value = window_mask_mode[bg3_window_mask()]; return true; } - if(id == n++) { name = "BG4 Window Mask"; value = window_mask_mode[bg4_window_mask()]; return true; } - - //$212b - if(id == n++) { name = "$212b"; value = ""; return true; } - if(id == n++) { name = "OAM Window Mask"; value = window_mask_mode[oam_window_mask()]; return true; } - if(id == n++) { name = "Color Window Mask"; value = window_mask_mode[color_window_mask()]; return true; } - - //$212c - if(id == n++) { name = "$212c"; value = ""; return true; } - if(id == n++) { name = "BG1 Mainscreen Enable"; value = bg1_mainscreen_enable(); return true; } - if(id == n++) { name = "BG2 Mainscreen Enable"; value = bg2_mainscreen_enable(); return true; } - if(id == n++) { name = "BG3 Mainscreen Enable"; value = bg3_mainscreen_enable(); return true; } - if(id == n++) { name = "BG4 Mainscreen Enable"; value = bg4_mainscreen_enable(); return true; } - if(id == n++) { name = "OAM Mainscreen Enable"; value = oam_mainscreen_enable(); return true; } - - //$212d - if(id == n++) { name = "$212d"; value = ""; return true; } - if(id == n++) { name = "BG1 Subscreen Enable"; value = bg1_subscreen_enable(); return true; } - if(id == n++) { name = "BG2 Subscreen Enable"; value = bg2_subscreen_enable(); return true; } - if(id == n++) { name = "BG3 Subscreen Enable"; value = bg3_subscreen_enable(); return true; } - if(id == n++) { name = "BG4 Subscreen Enable"; value = bg4_subscreen_enable(); return true; } - if(id == n++) { name = "OAM Subscreen Enable"; value = oam_subscreen_enable(); return true; } - - //$212e - if(id == n++) { name = "$212e"; value = ""; return true; } - if(id == n++) { name = "BG1 Mainscreen Window Enable"; value = bg1_mainscreen_window_enable(); return true; } - if(id == n++) { name = "BG2 Mainscreen Window Enable"; value = bg2_mainscreen_window_enable(); return true; } - if(id == n++) { name = "BG3 Mainscreen Window Enable"; value = bg3_mainscreen_window_enable(); return true; } - if(id == n++) { name = "BG4 Mainscreen Window Enable"; value = bg4_mainscreen_window_enable(); return true; } - if(id == n++) { name = "OAM Mainscreen Window Enable"; value = oam_mainscreen_window_enable(); return true; } - - //$212f - if(id == n++) { name = "$212f"; value = ""; return true; } - if(id == n++) { name = "BG1 Subscreen Window Enable"; value = bg1_subscreen_window_enable(); return true; } - if(id == n++) { name = "BG2 Subscreen Window Enable"; value = bg2_subscreen_window_enable(); return true; } - if(id == n++) { name = "BG3 Subscreen Window Enable"; value = bg3_subscreen_window_enable(); return true; } - if(id == n++) { name = "BG4 Subscreen Window Enable"; value = bg4_subscreen_window_enable(); return true; } - if(id == n++) { name = "OAM Subscreen Window Enable"; value = oam_subscreen_window_enable(); return true; } - - static char color_window_mask_mode[4][32] = { "Always", "Never", "Inside Window Only", "Outside Window Only" }; - - //$2130 - if(id == n++) { name = "$2130"; value = ""; return true; } - if(id == n++) { name = "Color Mainscreen Window Mask"; value = color_window_mask_mode[color_mainscreen_window_mask()]; return true; } - if(id == n++) { name = "Color Subscreen Window Mask"; value = color_window_mask_mode[color_subscreen_window_mask()]; return true; } - if(id == n++) { name = "Color Add/Subtract Mode"; value = !color_add_subtract_mode() ? "Fixed Color" : "Subscreen"; return true; } - if(id == n++) { name = "Direct Color"; value = direct_color(); return true; } - - //$2131 - if(id == n++) { name = "$2131"; value = ""; return true; } - if(id == n++) { name = "Color Mode"; value = !color_mode() ? "Add" : "Subtract"; return true; } - if(id == n++) { name = "Color Halve"; value = color_halve(); return true; } - if(id == n++) { name = "BG1 Color Enable"; value = bg1_color_enable(); return true; } - if(id == n++) { name = "BG2 Color Enable"; value = bg2_color_enable(); return true; } - if(id == n++) { name = "BG3 Color Enable"; value = bg3_color_enable(); return true; } - if(id == n++) { name = "BG4 Color Enable"; value = bg4_color_enable(); return true; } - if(id == n++) { name = "OAM Color Enable"; value = oam_color_enable(); return true; } - if(id == n++) { name = "Back Color Enable"; value = back_color_enable(); return true; } - - //$2132 - if(id == n++) { name = "$2132"; value = ""; return true; } - if(id == n++) { name = "Color Constant - Blue"; value = color_constant_blue(); return true; } - if(id == n++) { name = "Color Constant - Green"; value = color_constant_green(); return true; } - if(id == n++) { name = "Color Constant - Red"; value = color_constant_red(); return true; } - - //$2133 - if(id == n++) { name = "$2133"; value = ""; return true; } - if(id == n++) { name = "Mode 7 EXTBG"; value = mode7_extbg(); return true; } - if(id == n++) { name = "Pseudo Hires"; value = pseudo_hires(); return true; } - if(id == n++) { name = "Overscan"; value = overscan_enable(); return true; } - if(id == n++) { name = "OAM Interlace"; value = oam_interlace(); return true; } - if(id == n++) { name = "Interlace"; value = interlace_enable(); return true; } - - //$213c - if(id == n++) { name = "$213c"; value = ""; return true; } - if(id == n++) { name = "H-counter"; value = hcounter(); return true; } - - //$213d - if(id == n++) { name = "$213d"; value = ""; return true; } - if(id == n++) { name = "V-counter"; value = vcounter(); return true; } - - //$213e - if(id == n++) { name = "$213e"; value = ""; return true; } - if(id == n++) { name = "Range Over"; value = range_over(); return true; } - if(id == n++) { name = "Time Over"; value = time_over(); return true; } - if(id == n++) { name = "S-PPU1 Version"; value = ppu1_version(); return true; } - - //$213f - if(id == n++) { name = "$213f"; value = ""; return true; } - if(id == n++) { name = "Field"; value = field(); return true; } - if(id == n++) { name = "Region"; value = !region() ? "NTSC" : "PAL"; return true; } - if(id == n++) { name = "S-PPU2 Version"; value = ppu2_version(); return true; } + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + #undef item return false; } diff --git a/snes/ppu/debugger/debugger.hpp b/snes/ppu/debugger/debugger.hpp index 570eee68..d2e3d913 100755 --- a/snes/ppu/debugger/debugger.hpp +++ b/snes/ppu/debugger/debugger.hpp @@ -7,244 +7,4 @@ public: bool bg3_enabled[2]; bool bg4_enabled[2]; bool oam_enabled[4]; - - //internal - virtual unsigned ppu1_mdr() { return 0; } - virtual unsigned ppu2_mdr() { return 0; } - - //$2100 - virtual bool display_disable() { return 0; } - virtual unsigned display_brightness() { return 0; } - - //$2101 - virtual unsigned oam_base_size() { return 0; } - virtual unsigned oam_name_select() { return 0; } - virtual unsigned oam_name_base_address() { return 0; } - - //$2102-$2103 - virtual unsigned oam_base_address() { return 0; } - virtual bool oam_priority() { return 0; } - - //$2105 - virtual bool bg1_tile_size() { return 0; } - virtual bool bg2_tile_size() { return 0; } - virtual bool bg3_tile_size() { return 0; } - virtual bool bg4_tile_size() { return 0; } - virtual bool bg3_priority() { return 0; } - virtual unsigned bg_mode() { return 0; } - - //$2106 - virtual unsigned mosaic_size() { return 0; } - virtual bool bg1_mosaic_enable() { return 0; } - virtual bool bg2_mosaic_enable() { return 0; } - virtual bool bg3_mosaic_enable() { return 0; } - virtual bool bg4_mosaic_enable() { return 0; } - - //$2107 - virtual unsigned bg1_screen_address() { return 0; } - virtual unsigned bg1_screen_size() { return 0; } - - //$2108 - virtual unsigned bg2_screen_address() { return 0; } - virtual unsigned bg2_screen_size() { return 0; } - - //$2109 - virtual unsigned bg3_screen_address() { return 0; } - virtual unsigned bg3_screen_size() { return 0; } - - //$210a - virtual unsigned bg4_screen_address() { return 0; } - virtual unsigned bg4_screen_size() { return 0; } - - //$210b - virtual unsigned bg1_name_base_address() { return 0; } - virtual unsigned bg2_name_base_address() { return 0; } - - //$210c - virtual unsigned bg3_name_base_address() { return 0; } - virtual unsigned bg4_name_base_address() { return 0; } - - //$210d - virtual unsigned mode7_hoffset() { return 0; } - virtual unsigned bg1_hoffset() { return 0; } - - //$210e - virtual unsigned mode7_voffset() { return 0; } - virtual unsigned bg1_voffset() { return 0; } - - //$210f - virtual unsigned bg2_hoffset() { return 0; } - - //$2110 - virtual unsigned bg2_voffset() { return 0; } - - //$2111 - virtual unsigned bg3_hoffset() { return 0; } - - //$2112 - virtual unsigned bg3_voffset() { return 0; } - - //$2113 - virtual unsigned bg4_hoffset() { return 0; } - - //$2114 - virtual unsigned bg4_voffset() { return 0; } - - //$2115 - virtual bool vram_increment_mode() { return 0; } - virtual unsigned vram_increment_formation() { return 0; } - virtual unsigned vram_increment_size() { return 0; } - - //$2116-$2117 - virtual unsigned vram_address() { return 0; } - - //$211a - virtual unsigned mode7_repeat() { return 0; } - virtual bool mode7_vflip() { return 0; } - virtual bool mode7_hflip() { return 0; } - - //$211b - virtual unsigned mode7_a() { return 0; } - - //$211c - virtual unsigned mode7_b() { return 0; } - - //$211d - virtual unsigned mode7_c() { return 0; } - - //$211e - virtual unsigned mode7_d() { return 0; } - - //$211f - virtual unsigned mode7_x() { return 0; } - - //$2120 - virtual unsigned mode7_y() { return 0; } - - //$2121 - virtual unsigned cgram_address() { return 0; } - - //$2123 - virtual bool bg1_window1_enable() { return 0; } - virtual bool bg1_window1_invert() { return 0; } - virtual bool bg1_window2_enable() { return 0; } - virtual bool bg1_window2_invert() { return 0; } - virtual bool bg2_window1_enable() { return 0; } - virtual bool bg2_window1_invert() { return 0; } - virtual bool bg2_window2_enable() { return 0; } - virtual bool bg2_window2_invert() { return 0; } - - //$2124 - virtual bool bg3_window1_enable() { return 0; } - virtual bool bg3_window1_invert() { return 0; } - virtual bool bg3_window2_enable() { return 0; } - virtual bool bg3_window2_invert() { return 0; } - virtual bool bg4_window1_enable() { return 0; } - virtual bool bg4_window1_invert() { return 0; } - virtual bool bg4_window2_enable() { return 0; } - virtual bool bg4_window2_invert() { return 0; } - - //$2125 - virtual bool oam_window1_enable() { return 0; } - virtual bool oam_window1_invert() { return 0; } - virtual bool oam_window2_enable() { return 0; } - virtual bool oam_window2_invert() { return 0; } - virtual bool color_window1_enable() { return 0; } - virtual bool color_window1_invert() { return 0; } - virtual bool color_window2_enable() { return 0; } - virtual bool color_window2_invert() { return 0; } - - //$2126 - virtual unsigned window1_left() { return 0; } - - //$2127 - virtual unsigned window1_right() { return 0; } - - //$2128 - virtual unsigned window2_left() { return 0; } - - //$2129 - virtual unsigned window2_right() { return 0; } - - //$212a - virtual unsigned bg1_window_mask() { return 0; } - virtual unsigned bg2_window_mask() { return 0; } - virtual unsigned bg3_window_mask() { return 0; } - virtual unsigned bg4_window_mask() { return 0; } - - //$212b - virtual unsigned oam_window_mask() { return 0; } - virtual unsigned color_window_mask() { return 0; } - - //$212c - virtual bool bg1_mainscreen_enable() { return 0; } - virtual bool bg2_mainscreen_enable() { return 0; } - virtual bool bg3_mainscreen_enable() { return 0; } - virtual bool bg4_mainscreen_enable() { return 0; } - virtual bool oam_mainscreen_enable() { return 0; } - - //$212d - virtual bool bg1_subscreen_enable() { return 0; } - virtual bool bg2_subscreen_enable() { return 0; } - virtual bool bg3_subscreen_enable() { return 0; } - virtual bool bg4_subscreen_enable() { return 0; } - virtual bool oam_subscreen_enable() { return 0; } - - //$212e - virtual bool bg1_mainscreen_window_enable() { return 0; } - virtual bool bg2_mainscreen_window_enable() { return 0; } - virtual bool bg3_mainscreen_window_enable() { return 0; } - virtual bool bg4_mainscreen_window_enable() { return 0; } - virtual bool oam_mainscreen_window_enable() { return 0; } - - //$212f - virtual bool bg1_subscreen_window_enable() { return 0; } - virtual bool bg2_subscreen_window_enable() { return 0; } - virtual bool bg3_subscreen_window_enable() { return 0; } - virtual bool bg4_subscreen_window_enable() { return 0; } - virtual bool oam_subscreen_window_enable() { return 0; } - - //$2130 - virtual unsigned color_mainscreen_window_mask() { return 0; } - virtual unsigned color_subscreen_window_mask() { return 0; } - virtual bool color_add_subtract_mode() { return 0; } - virtual bool direct_color() { return 0; } - - //$2131 - virtual bool color_mode() { return 0; } - virtual bool color_halve() { return 0; } - virtual bool bg1_color_enable() { return 0; } - virtual bool bg2_color_enable() { return 0; } - virtual bool bg3_color_enable() { return 0; } - virtual bool bg4_color_enable() { return 0; } - virtual bool oam_color_enable() { return 0; } - virtual bool back_color_enable() { return 0; } - - //$2132 - virtual unsigned color_constant_blue() { return 0; } - virtual unsigned color_constant_green() { return 0; } - virtual unsigned color_constant_red() { return 0; } - - //$2133 - virtual bool mode7_extbg() { return 0; } - virtual bool pseudo_hires() { return 0; } - virtual bool overscan_enable() { return 0; } - virtual bool oam_interlace() { return 0; } - virtual bool interlace_enable() { return 0; } - - //$213c - virtual unsigned hcounter() { return 0; } - - //$213d - virtual unsigned vcounter() { return 0; } - - //$213e - virtual bool range_over() { return 0; } - virtual bool time_over() { return 0; } - virtual unsigned ppu1_version() { return 0; } - - //$213f - virtual bool field() { return 0; } - virtual bool region() { return 0; } - virtual unsigned ppu2_version() { return 0; } }; diff --git a/snes/smp/core/disassembler/disassembler.cpp b/snes/smp/core/disassembler/disassembler.cpp index ee5663a3..5ddd09bd 100755 --- a/snes/smp/core/disassembler/disassembler.cpp +++ b/snes/smp/core/disassembler/disassembler.cpp @@ -1,14 +1,7 @@ #ifdef SMPCORE_CPP uint8 SMPcore::disassemble_read(uint16 addr) { - if(addr >= 0xffc0) { - #if defined(DEBUGGER) - if(smp.iplrom_enable()) return smp.iplrom[addr & 0x3f]; - #else - //unable to determine if IPLROM is enabled, assume that it is - return smp.iplrom[addr & 0x3f]; - #endif - } + if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f]; return memory::apuram[addr]; } diff --git a/snes/smp/debugger/debugger.cpp b/snes/smp/debugger/debugger.cpp index 0d700634..74bdbc1a 100755 --- a/snes/smp/debugger/debugger.cpp +++ b/snes/smp/debugger/debugger.cpp @@ -1,27 +1,5 @@ #ifdef SMP_CPP -bool SMPDebugger::property(unsigned id, string &name, string &value) { - unsigned n = 0; - - //$00f0 - if(id == n++) { name = "$00f0"; value = ""; return true; } - if(id == n++) { name = "Clock Speed"; value = clock_speed(); return true; } - if(id == n++) { name = "Timers Enable"; value = timers_enable(); return true; } - if(id == n++) { name = "RAM Disable"; value = ram_disable(); return true; } - if(id == n++) { name = "RAM Writable"; value = ram_writable(); return true; } - if(id == n++) { name = "Timers Disable"; value = timers_disable(); return true; } - - //$00f1 - if(id == n++) { name = "$00f1"; value = ""; return true; } - if(id == n++) { name = "IPLROM Enable"; value = iplrom_enable(); return true; } - - //$00f2 - if(id == n++) { name = "$00f2"; value = ""; return true; } - if(id == n++) { name = "DSP Address"; value = string("0x", strhex<2>(dsp_address())); return true; } - - return false; -} - void SMPDebugger::op_step() { bool break_event = false; @@ -63,21 +41,34 @@ SMPDebugger::~SMPDebugger() { delete[] usage; } -//=========== -//SMPDebugger -//=========== +bool SMPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; -//$00f0 -unsigned SMPDebugger::clock_speed() { return status.clock_speed; } -bool SMPDebugger::timers_enable() { return status.timers_enabled; } -bool SMPDebugger::ram_disable() { return status.ram_disabled; } -bool SMPDebugger::ram_writable() { return status.ram_writable; } -bool SMPDebugger::timers_disable() { return status.timers_disabled; } + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } -//$00f1 -bool SMPDebugger::iplrom_enable() { return status.iplrom_enabled; } + //$00f0 + item("$00f0", ""); + item("Clock Speed", (unsigned)status.clock_speed); + item("Timers Enable", status.timers_enabled); + item("RAM Disable", status.ram_disabled); + item("RAM Writable", status.ram_writable); + item("Timers Disable", status.timers_disabled); -//$00f2 -unsigned SMPDebugger::dsp_address() { return status.dsp_addr; } + //$00f1 + item("$00f1", ""); + item("IPLROM Enable", status.iplrom_enabled); + + //$00f2 + item("$00f2", ""); + item("DSP Address", string("0x", strhex<2>(status.dsp_addr))); + + #undef item + return false; +} #endif diff --git a/snes/smp/debugger/debugger.hpp b/snes/smp/debugger/debugger.hpp index 70211d89..9c613497 100755 --- a/snes/smp/debugger/debugger.hpp +++ b/snes/smp/debugger/debugger.hpp @@ -18,21 +18,4 @@ public: SMPDebugger(); ~SMPDebugger(); - - //=========== - //SMPDebugger - //=========== - - //$00f0 - unsigned clock_speed(); - bool timers_enable(); - bool ram_disable(); - bool ram_writable(); - bool timers_disable(); - - //$00f1 - bool iplrom_enable(); - - //$00f2 - unsigned dsp_address(); }; diff --git a/snes/snes.hpp b/snes/snes.hpp index 6635521d..a5a03480 100755 --- a/snes/snes.hpp +++ b/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "067.24"; + static const char Version[] = "067.25"; static const unsigned SerializerVersion = 12; } }