Files
bsnes/sfc/dsp/dsp.cpp
Tim Allen d1ffd59c29 Update to v095r04 release.
Changelog:
- S-SMP core code style updated
- S-SMP loads reset vector from IPLROM ($fffe-ffff)
- sfc/base => sfc/expansion
- system/input => system/device
- added expansion/eBoot (simulation of defparam's SNES-Boot device)
- expansion port device can now be selected from Super Famicom menu
  option
- improved GBA MROM/SRAM reading

endrift's memory test is up to 1388/1552.

Note: I added the expansion port devices to the same group as controller
ports. I also had to move "None" to the top of the list. Before v096,
I am going to have to add caching of port selections to the
configuration file, check the proper default item in the system menu,
and remove the items with no mappings from the input configuration
window. Lots of work >_>
2015-11-10 22:11:29 +11:00

304 lines
5.5 KiB
C++

#include <sfc/sfc.hpp>
#define DSP_CPP
namespace SuperFamicom {
DSP dsp;
#define REG(n) state.regs[n]
#define VREG(n) state.regs[v.vidx + n]
#include "serialization.cpp"
#include "gaussian.cpp"
#include "counter.cpp"
#include "envelope.cpp"
#include "brr.cpp"
#include "misc.cpp"
#include "voice.cpp"
#include "echo.cpp"
DSP::DSP() {
static_assert(sizeof(signed) >= 32 / 8, "signed >= 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);
}
/* timing */
auto DSP::step(unsigned clocks) -> void {
clock += clocks;
}
auto DSP::synchronizeSMP() -> void {
if(SMP::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(smp.thread);
} else {
while(clock >= 0) smp.enter();
}
}
auto DSP::Enter() -> void { dsp.enter(); }
auto DSP::enter() -> void {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
voice5(voice[0]);
voice2(voice[1]);
tick();
voice6(voice[0]);
voice3(voice[1]);
tick();
voice7(voice[0]);
voice4(voice[1]);
voice1(voice[3]);
tick();
voice8(voice[0]);
voice5(voice[1]);
voice2(voice[2]);
tick();
voice9(voice[0]);
voice6(voice[1]);
voice3(voice[2]);
tick();
voice7(voice[1]);
voice4(voice[2]);
voice1(voice[4]);
tick();
voice8(voice[1]);
voice5(voice[2]);
voice2(voice[3]);
tick();
voice9(voice[1]);
voice6(voice[2]);
voice3(voice[3]);
tick();
voice7(voice[2]);
voice4(voice[3]);
voice1(voice[5]);
tick();
voice8(voice[2]);
voice5(voice[3]);
voice2(voice[4]);
tick();
voice9(voice[2]);
voice6(voice[3]);
voice3(voice[4]);
tick();
voice7(voice[3]);
voice4(voice[4]);
voice1(voice[6]);
tick();
voice8(voice[3]);
voice5(voice[4]);
voice2(voice[5]);
tick();
voice9(voice[3]);
voice6(voice[4]);
voice3(voice[5]);
tick();
voice7(voice[4]);
voice4(voice[5]);
voice1(voice[7]);
tick();
voice8(voice[4]);
voice5(voice[5]);
voice2(voice[6]);
tick();
voice9(voice[4]);
voice6(voice[5]);
voice3(voice[6]);
tick();
voice1(voice[0]);
voice7(voice[5]);
voice4(voice[6]);
tick();
voice8(voice[5]);
voice5(voice[6]);
voice2(voice[7]);
tick();
voice9(voice[5]);
voice6(voice[6]);
voice3(voice[7]);
tick();
voice1(voice[1]);
voice7(voice[6]);
voice4(voice[7]);
tick();
voice8(voice[6]);
voice5(voice[7]);
voice2(voice[0]);
tick();
voice3a(voice[0]);
voice9(voice[6]);
voice6(voice[7]);
echo22();
tick();
voice7(voice[7]);
echo23();
tick();
voice8(voice[7]);
echo24();
tick();
voice3b(voice[0]);
voice9(voice[7]);
echo25();
tick();
echo26();
tick();
misc27();
echo27();
tick();
misc28();
echo28();
tick();
misc29();
echo29();
tick();
misc30();
voice3c(voice[0]);
echo30();
tick();
voice4(voice[0]);
voice1(voice[2]);
tick();
}
}
auto DSP::tick() -> void {
step(3 * 8);
synchronizeSMP();
}
/* register interface for S-SMP $00f2,$00f3 */
auto DSP::mute() const -> bool {
return REG(FLG) & 0x40;
}
auto DSP::read(uint8 addr) -> uint8 {
return REG(addr);
}
auto DSP::write(uint8 addr, uint8 data) -> void {
REG(addr) = data;
if((addr & 0x0f) == ENVX) {
state.envxBuffer = data;
} else if((addr & 0x0f) == OUTX) {
state.outxBuffer = data;
} else if(addr == KON) {
state.konBuffer = data;
} else if(addr == ENDX) {
//always cleared, regardless of data written
state.endxBuffer = 0;
REG(ENDX) = 0;
}
}
/* initialization */
auto DSP::power() -> void {
for(auto& r : state.regs) r = 0;
state.echoHistoryOffset = 0;
state.everyOtherSample = false;
state.kon = 0;
state.noise = 0;
state.counter = 0;
state.echoOffset = 0;
state.echoLength = 0;
state.konBuffer = 0;
state.endxBuffer = 0;
state.envxBuffer = 0;
state.outxBuffer = 0;
state._pmon = 0;
state._non = 0;
state._eon = 0;
state._dir = 0;
state._koff = 0;
state._brrNextAddress = 0;
state._adsr0 = 0;
state._brrHeader = 0;
state._brrByte = 0;
state._srcn = 0;
state._esa = 0;
state._echoDisabled = 0;
state._dirAddress = 0;
state._pitch = 0;
state._output = 0;
state._looped = 0;
state._echoPointer = 0;
state._mainOut[0] = state._mainOut[1] = 0;
state._echoOut[0] = state._echoOut[1] = 0;
state._echoIn[0] = state._echoIn[1] = 0;
for(auto n : range(8)) {
voice[n].bufferOffset = 0;
voice[n].gaussianOffset = 0;
voice[n].brrAddress = 0;
voice[n].brrOffset = 1;
voice[n].vbit = 1 << n;
voice[n].vidx = n * 0x10;
voice[n].konDelay = 0;
voice[n].envelopeMode = EnvelopeRelease;
voice[n].envelope = 0;
voice[n].hiddenEnvelope = 0;
voice[n]._envxOut = 0;
}
}
auto DSP::reset() -> void {
create(Enter, system.apuFrequency());
REG(FLG) = 0xe0;
state.noise = 0x4000;
state.echoHistoryOffset = 0;
state.everyOtherSample = 1;
state.echoOffset = 0;
state.counter = 0;
}
#undef REG
#undef VREG
}