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; } }