mirror of https://github.com/bsnes-emu/bsnes.git
Update to v075r05 release.
byuu says: Added Game Boy sound emulation, all four channels. It's really, really, really bad. Plenty of bugs, I don't even know what the fuck a high-pass filter is so that isn't there. Hermite resampling from 4MHz down to 44KHz. But it's tolerable. I don't understand what sweep is for at all, and I'm sure I have that insane recursive reload behavior wrong. This is pretty much my own design. I referenced blargg's gb snd emu, blargg's older gb apu ref, Cydrak's APU core, that lousy gbdev wiki article, the completely and utterly worthless pandocs, and received nothing but bad and wrong information that just wasted my time from But I managed to pull it off. It's also painfully slow, like 250fps on my machine slow. Countless optimizations are possible.
This commit is contained in:
parent
f88ef9e9a2
commit
a3abe8ebaa
|
@ -2,7 +2,7 @@ include nall/Makefile
|
|||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := compatibility
|
||||
ui := ui
|
||||
ui := ui-gameboy
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#include <nall/random.hpp>
|
||||
|
||||
#define APU_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "square/square.cpp"
|
||||
#include "square1/square1.cpp"
|
||||
#include "square2/square2.cpp"
|
||||
#include "wave/wave.cpp"
|
||||
#include "noise/noise.cpp"
|
||||
#include "master/master.cpp"
|
||||
|
@ -23,25 +21,45 @@ void APU::main() {
|
|||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if((counter & 8191) == 0) { //512hz
|
||||
if(sequencer == 0 || sequencer == 2 || sequencer == 4 || sequencer == 6) { //256hz
|
||||
square1.clock_length();
|
||||
square2.clock_length();
|
||||
wave.clock_length();
|
||||
noise.clock_length();
|
||||
}
|
||||
if(sequencer == 2 || sequencer == 6) { //128hz
|
||||
square1.clock_sweep();
|
||||
}
|
||||
if(sequencer == 7) { //64hz
|
||||
square1.clock_envelope();
|
||||
square2.clock_envelope();
|
||||
noise.clock_envelope();
|
||||
}
|
||||
sequencer = (sequencer + 1) & 7;
|
||||
}
|
||||
|
||||
square1.run();
|
||||
square2.run();
|
||||
wave.run();
|
||||
noise.run();
|
||||
master.run();
|
||||
|
||||
system.interface->audio_sample((uint16)prng() >> 3, (uint16)prng() >> 3);
|
||||
system.interface->audio_sample(master.center, master.left, master.right);
|
||||
|
||||
if(++counter == 4194304) counter = 0;
|
||||
|
||||
if(++clock >= 0) co_switch(scheduler.active_thread = cpu.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::power() {
|
||||
create(Main, 4 * 1024 * 1024);
|
||||
|
||||
create(Main, 4194304);
|
||||
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||
|
||||
square1.has_sweep = true;
|
||||
square2.has_sweep = false;
|
||||
foreach(n, mmio_data) n = 0x00;
|
||||
counter = 0;
|
||||
sequencer = 0;
|
||||
|
||||
square1.power();
|
||||
square2.power();
|
||||
|
@ -50,4 +68,40 @@ void APU::power() {
|
|||
master.power();
|
||||
}
|
||||
|
||||
uint8 APU::mmio_read(uint16 addr) {
|
||||
static const uint8 table[48] = {
|
||||
0x80, 0x3f, 0x00, 0xff, 0xbf, //square1
|
||||
0xff, 0x3f, 0x00, 0xff, 0xbf, //square2
|
||||
0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave
|
||||
0xff, 0xff, 0x00, 0x00, 0xbf, //noise
|
||||
0x00, 0x00, 0x70, //master
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
||||
};
|
||||
|
||||
if(addr == 0xff26) {
|
||||
uint8 data = master.enable << 7;
|
||||
if(square1.counter && square1.length) data |= 0x01;
|
||||
if(square2.counter && square2.length) data |= 0x02;
|
||||
if( wave.counter && wave.length) data |= 0x04;
|
||||
if( noise.counter && noise.length) data |= 0x08;
|
||||
return data | table[addr - 0xff10];
|
||||
}
|
||||
|
||||
if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10];
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void APU::mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data;
|
||||
|
||||
if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data);
|
||||
if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data);
|
||||
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data);
|
||||
if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data);
|
||||
if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data);
|
||||
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
struct APU : Processor, MMIO {
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "square/square.hpp"
|
||||
#include "square1/square1.hpp"
|
||||
#include "square2/square2.hpp"
|
||||
#include "wave/wave.hpp"
|
||||
#include "noise/noise.hpp"
|
||||
#include "master/master.hpp"
|
||||
|
||||
Square square1;
|
||||
Square square2;
|
||||
uint8 mmio_data[48];
|
||||
unsigned counter;
|
||||
unsigned sequencer;
|
||||
|
||||
Square1 square1;
|
||||
Square2 square2;
|
||||
Wave wave;
|
||||
Noise noise;
|
||||
Master master;
|
||||
|
@ -15,6 +19,9 @@ struct APU : Processor, MMIO {
|
|||
void main();
|
||||
void power();
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,99 +1,132 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Master::run() {
|
||||
}
|
||||
signed sample = 0, channels = 4;
|
||||
sample += apu.square1.output;
|
||||
sample += apu.square2.output;
|
||||
sample += apu.wave.output;
|
||||
sample += apu.noise.output;
|
||||
sample /= channels;
|
||||
if(sample < -32768) sample = -32768;
|
||||
if(sample > +32767) sample = +32767;
|
||||
center = sample;
|
||||
|
||||
uint8 APU::Master::read(unsigned r) {
|
||||
if(r == 0) {
|
||||
return (so2_enable << 7) | (so2_volume << 4) | (so1_enable << 3) | (so1_volume << 0);
|
||||
sample = 0;
|
||||
channels = 0;
|
||||
if(channel1_left_enable) { sample += apu.square1.output; channels++; }
|
||||
if(channel2_left_enable) { sample += apu.square2.output; channels++; }
|
||||
if(channel3_left_enable) { sample += apu.wave.output; channels++; }
|
||||
if(channel4_left_enable) { sample += apu.noise.output; channels++; }
|
||||
if(channels) sample /= channels;
|
||||
left = sample;
|
||||
|
||||
switch(left_volume) {
|
||||
case 0: left *= 0.125; break;
|
||||
case 1: left *= 0.250; break;
|
||||
case 2: left *= 0.375; break;
|
||||
case 3: left *= 0.500; break;
|
||||
case 4: left *= 0.625; break;
|
||||
case 5: left *= 0.750; break;
|
||||
case 6: left *= 0.875; break;
|
||||
case 7: left *= 1.000; break;
|
||||
}
|
||||
if(left_enable == false) left = 0;
|
||||
|
||||
sample = 0;
|
||||
channels = 0;
|
||||
if(channel1_right_enable) { sample += apu.square1.output; channels++; }
|
||||
if(channel2_right_enable) { sample += apu.square2.output; channels++; }
|
||||
if(channel3_right_enable) { sample += apu.wave.output; channels++; }
|
||||
if(channel4_right_enable) { sample += apu.noise.output; channels++; }
|
||||
if(channels) sample /= channels;
|
||||
right = sample;
|
||||
|
||||
switch(right_volume) {
|
||||
case 0: right *= 0.125; break;
|
||||
case 1: right *= 0.250; break;
|
||||
case 2: right *= 0.375; break;
|
||||
case 3: right *= 0.500; break;
|
||||
case 4: right *= 0.625; break;
|
||||
case 5: right *= 0.750; break;
|
||||
case 6: right *= 0.875; break;
|
||||
case 7: right *= 1.000; break;
|
||||
}
|
||||
if(right_enable == false) right = 0;
|
||||
|
||||
if(left_enable == false && right_enable == false) {
|
||||
left = center;
|
||||
right = center;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
return (channel4_so2_enable << 7)
|
||||
| (channel3_so2_enable << 6)
|
||||
| (channel2_so2_enable << 5)
|
||||
| (channel1_so2_enable << 4)
|
||||
| (channel4_so1_enable << 3)
|
||||
| (channel3_so1_enable << 2)
|
||||
| (channel2_so1_enable << 1)
|
||||
| (channel1_so1_enable << 0);
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
return (enable << 7)
|
||||
| (channel4_enable << 3)
|
||||
| (channel3_enable << 2)
|
||||
| (channel2_enable << 1)
|
||||
| (channel1_enable << 0);
|
||||
if(enable == false) {
|
||||
center = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Master::write(unsigned r, uint8 data) {
|
||||
if(r == 0) {
|
||||
so2_enable = data & 0x80;
|
||||
so2_volume = (data >> 4) & 7;
|
||||
so1_enable = data & 0x08;
|
||||
so1_volume = (data >> 0) & 7;
|
||||
left_enable = data & 0x80;
|
||||
left_volume = (data >> 4) & 7;
|
||||
right_enable = data & 0x08;
|
||||
right_volume = (data >> 0) & 7;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
channel4_so2_enable = data & 0x80;
|
||||
channel3_so2_enable = data & 0x40;
|
||||
channel2_so2_enable = data & 0x20;
|
||||
channel1_so2_enable = data & 0x10;
|
||||
channel4_so1_enable = data & 0x08;
|
||||
channel3_so1_enable = data & 0x04;
|
||||
channel2_so1_enable = data & 0x02;
|
||||
channel1_so1_enable = data & 0x01;
|
||||
channel4_left_enable = data & 0x80;
|
||||
channel3_left_enable = data & 0x40;
|
||||
channel2_left_enable = data & 0x20;
|
||||
channel1_left_enable = data & 0x10;
|
||||
channel4_right_enable = data & 0x08;
|
||||
channel3_right_enable = data & 0x04;
|
||||
channel2_right_enable = data & 0x02;
|
||||
channel1_right_enable = data & 0x01;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
enable = data & 0x80;
|
||||
channel4_enable = data & 0x08;
|
||||
channel3_enable = data & 0x04;
|
||||
channel2_enable = data & 0x02;
|
||||
channel1_enable = data & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Master::power() {
|
||||
so2_enable = 0;
|
||||
so2_volume = 0;
|
||||
so1_enable = 0;
|
||||
so1_volume = 0;
|
||||
channel4_so2_enable = 0;
|
||||
channel3_so2_enable = 0;
|
||||
channel2_so2_enable = 0;
|
||||
channel1_so2_enable = 0;
|
||||
channel4_so1_enable = 0;
|
||||
channel3_so1_enable = 0;
|
||||
channel2_so1_enable = 0;
|
||||
channel1_so1_enable = 0;
|
||||
left_enable = 0;
|
||||
left_volume = 0;
|
||||
right_enable = 0;
|
||||
right_volume = 0;
|
||||
channel4_left_enable = 0;
|
||||
channel3_left_enable = 0;
|
||||
channel2_left_enable = 0;
|
||||
channel1_left_enable = 0;
|
||||
channel4_right_enable = 0;
|
||||
channel3_right_enable = 0;
|
||||
channel2_right_enable = 0;
|
||||
channel1_right_enable = 0;
|
||||
enable = 0;
|
||||
channel4_enable = 0;
|
||||
channel3_enable = 0;
|
||||
channel2_enable = 0;
|
||||
channel1_enable = 0;
|
||||
|
||||
center = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
}
|
||||
|
||||
void APU::Master::serialize(serializer &s) {
|
||||
s.integer(so2_enable);
|
||||
s.integer(so2_volume);
|
||||
s.integer(so1_enable);
|
||||
s.integer(so1_volume);
|
||||
s.integer(channel4_so2_enable);
|
||||
s.integer(channel3_so2_enable);
|
||||
s.integer(channel2_so2_enable);
|
||||
s.integer(channel1_so2_enable);
|
||||
s.integer(channel4_so1_enable);
|
||||
s.integer(channel3_so1_enable);
|
||||
s.integer(channel2_so1_enable);
|
||||
s.integer(channel1_so1_enable);
|
||||
s.integer(left_enable);
|
||||
s.integer(left_volume);
|
||||
s.integer(right_enable);
|
||||
s.integer(right_volume);
|
||||
s.integer(channel4_left_enable);
|
||||
s.integer(channel3_left_enable);
|
||||
s.integer(channel2_left_enable);
|
||||
s.integer(channel1_left_enable);
|
||||
s.integer(channel4_right_enable);
|
||||
s.integer(channel3_right_enable);
|
||||
s.integer(channel2_right_enable);
|
||||
s.integer(channel1_right_enable);
|
||||
s.integer(enable);
|
||||
s.integer(channel4_enable);
|
||||
s.integer(channel3_enable);
|
||||
s.integer(channel2_enable);
|
||||
s.integer(channel1_enable);
|
||||
|
||||
s.integer(center);
|
||||
s.integer(left);
|
||||
s.integer(right);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
struct Master {
|
||||
bool so2_enable;
|
||||
unsigned so2_volume;
|
||||
bool so1_enable;
|
||||
unsigned so1_volume;
|
||||
bool channel4_so2_enable;
|
||||
bool channel3_so2_enable;
|
||||
bool channel2_so2_enable;
|
||||
bool channel1_so2_enable;
|
||||
bool channel4_so1_enable;
|
||||
bool channel3_so1_enable;
|
||||
bool channel2_so1_enable;
|
||||
bool channel1_so1_enable;
|
||||
bool left_enable;
|
||||
unsigned left_volume;
|
||||
bool right_enable;
|
||||
unsigned right_volume;
|
||||
bool channel4_left_enable;
|
||||
bool channel3_left_enable;
|
||||
bool channel2_left_enable;
|
||||
bool channel1_left_enable;
|
||||
bool channel4_right_enable;
|
||||
bool channel3_right_enable;
|
||||
bool channel2_right_enable;
|
||||
bool channel1_right_enable;
|
||||
bool enable;
|
||||
bool channel4_enable;
|
||||
bool channel3_enable;
|
||||
bool channel2_enable;
|
||||
bool channel1_enable;
|
||||
|
||||
int16 center;
|
||||
int16 left;
|
||||
int16 right;
|
||||
|
||||
void run();
|
||||
uint8 read(unsigned r);
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
uint8 APU::mmio_read(uint16 addr) {
|
||||
if(addr >= 0xff10 && addr <= 0xff14) return square1.read(addr - 0xff10);
|
||||
if(addr >= 0xff15 && addr <= 0xff19) return square2.read(addr - 0xff15);
|
||||
if(addr >= 0xff1a && addr <= 0xff1e) return wave.read(addr - 0xff1a);
|
||||
if(addr >= 0xff1f && addr <= 0xff23) return noise.read(addr - 0xff1f);
|
||||
if(addr >= 0xff24 && addr <= 0xff26) return master.read(addr - 0xff24);
|
||||
if(addr >= 0xff30 && addr <= 0xff3f) return wave.read_pattern(addr - 0xff30);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void APU::mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr >= 0xff10 && addr <= 0xff14) return square1.write(addr - 0xff10, data);
|
||||
if(addr >= 0xff15 && addr <= 0xff19) return square2.write(addr - 0xff15, data);
|
||||
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write(addr - 0xff1a, data);
|
||||
if(addr >= 0xff1f && addr <= 0xff23) return noise.write(addr - 0xff1f, data);
|
||||
if(addr >= 0xff24 && addr <= 0xff26) return master.write(addr - 0xff24, data);
|
||||
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,2 +0,0 @@
|
|||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
|
@ -1,66 +1,102 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Noise::run() {
|
||||
if(period && --period == 0) {
|
||||
period = divisor << frequency;
|
||||
if(frequency < 14) {
|
||||
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
|
||||
lfsr = (lfsr >> 1) ^ (bit << 14);
|
||||
if(narrow_lfsr) lfsr |= (bit << 6);
|
||||
}
|
||||
}
|
||||
|
||||
uint4 sample = (lfsr & 1) ? -volume : volume;
|
||||
if(counter && length == 0) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
}
|
||||
|
||||
uint8 APU::Noise::read(unsigned r) {
|
||||
if(r == 2) {
|
||||
return (envelope_volume << 4) | (envelope_direction << 3) | (envelope_period << 0);
|
||||
}
|
||||
void APU::Noise::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
return (period << 4) | (step << 3) | (divisor);
|
||||
void APU::Noise::clock_envelope() {
|
||||
if(envelope_period && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
if(envelope_direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
return (counter << 6);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void APU::Noise::write(unsigned r, uint8 data) {
|
||||
if(r == 1) {
|
||||
length = data & 0x3f;
|
||||
initial_length = 64 - (data & 0x3f);
|
||||
|
||||
length = initial_length;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
envelope_volume = data >> 4;
|
||||
envelope_direction = data & 0x08;
|
||||
envelope_period = data & 0x07;
|
||||
envelope_frequency = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
period = data >> 4;
|
||||
step = data & 0x08;
|
||||
divisor = data & 0x07;
|
||||
frequency = data >> 4;
|
||||
narrow_lfsr = data & 0x08;
|
||||
divisor = (data & 0x07) << 4;
|
||||
if(divisor == 0) divisor = 8;
|
||||
|
||||
period = divisor << frequency;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
|
||||
if(initialize) {
|
||||
lfsr = ~0U;
|
||||
length = initial_length;
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Noise::power() {
|
||||
length = 0;
|
||||
initial_length = 0;
|
||||
envelope_volume = 0;
|
||||
envelope_direction = 0;
|
||||
envelope_period = 0;
|
||||
period = 0;
|
||||
step = 0;
|
||||
envelope_frequency = 0;
|
||||
frequency = 0;
|
||||
narrow_lfsr = 0;
|
||||
divisor = 0;
|
||||
counter = 0;
|
||||
|
||||
output = 0;
|
||||
length = 0;
|
||||
envelope_period = 0;
|
||||
volume = 0;
|
||||
period = 0;
|
||||
lfsr = 0;
|
||||
}
|
||||
|
||||
void APU::Noise::serialize(serializer &s) {
|
||||
s.integer(length);
|
||||
s.integer(initial_length);
|
||||
s.integer(envelope_volume);
|
||||
s.integer(envelope_direction);
|
||||
s.integer(envelope_period);
|
||||
s.integer(period);
|
||||
s.integer(step);
|
||||
s.integer(envelope_frequency);
|
||||
s.integer(frequency);
|
||||
s.integer(narrow_lfsr);
|
||||
s.integer(divisor);
|
||||
s.integer(counter);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(length);
|
||||
s.integer(envelope_period);
|
||||
s.integer(volume);
|
||||
s.integer(period);
|
||||
s.integer(lfsr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
struct Noise {
|
||||
unsigned length;
|
||||
unsigned initial_length;
|
||||
unsigned envelope_volume;
|
||||
bool envelope_direction;
|
||||
unsigned envelope_period;
|
||||
unsigned period;
|
||||
bool step;
|
||||
unsigned envelope_frequency;
|
||||
unsigned frequency;
|
||||
bool narrow_lfsr;
|
||||
unsigned divisor;
|
||||
bool counter;
|
||||
|
||||
int16 output;
|
||||
unsigned length;
|
||||
unsigned envelope_period;
|
||||
unsigned volume;
|
||||
unsigned period;
|
||||
uint15 lfsr;
|
||||
|
||||
void run();
|
||||
uint8 read(unsigned r);
|
||||
void clock_length();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::serialize(serializer &s) {
|
||||
s.array(mmio_data);
|
||||
s.integer(counter);
|
||||
s.integer(sequencer);
|
||||
|
||||
square1.serialize(s);
|
||||
square2.serialize(s);
|
||||
wave.serialize(s);
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Square::run() {
|
||||
}
|
||||
|
||||
uint8 APU::Square::read(unsigned r) {
|
||||
if(r == 0) {
|
||||
return (sweep_period << 4) | (sweep_direction << 3) | (sweep_shift << 0);
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
return (duty << 6);
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
return (envelope_volume << 4) | (envelope_direction << 3) | (envelope_period << 0);
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
return (counter << 6);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void APU::Square::write(unsigned r, uint8 data) {
|
||||
if(r == 0) {
|
||||
sweep_period = (data >> 4) & 7;
|
||||
sweep_direction = data & 0x08;
|
||||
sweep_shift = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
duty = data >> 6;
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
envelope_volume = data >> 4;
|
||||
envelope_direction = data & 0x08;
|
||||
envelope_period = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
frequency = (frequency & 0x0700) | data;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square::power() {
|
||||
sweep_period = 0;
|
||||
sweep_direction = 0;
|
||||
sweep_shift = 0;
|
||||
|
||||
duty = 0;
|
||||
length = 0;
|
||||
|
||||
envelope_volume = 0;
|
||||
envelope_direction = 0;
|
||||
envelope_period = 0;
|
||||
|
||||
frequency = 0;
|
||||
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void APU::Square::serialize(serializer &s) {
|
||||
s.integer(sweep_period);
|
||||
s.integer(sweep_direction);
|
||||
s.integer(sweep_shift);
|
||||
s.integer(duty);
|
||||
s.integer(length);
|
||||
s.integer(envelope_volume);
|
||||
s.integer(envelope_direction);
|
||||
s.integer(envelope_period);
|
||||
s.integer(frequency);
|
||||
s.integer(counter);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Square1::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 4 * (2048 - frequency);
|
||||
phase = (phase + 1) & 7;
|
||||
switch(duty) {
|
||||
case 0: duty_output = (phase == 6); break; //______-_
|
||||
case 1: duty_output = (phase >= 6); break; //______--
|
||||
case 2: duty_output = (phase >= 4); break; //____----
|
||||
case 3: duty_output = (phase <= 5); break; //------__
|
||||
}
|
||||
}
|
||||
|
||||
uint4 sample = (duty_output ? volume : 0);
|
||||
if(counter && length == 0) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
}
|
||||
|
||||
void APU::Square1::sweep() {
|
||||
if(enable == false) return;
|
||||
|
||||
signed offset = frequency_shadow >> sweep_shift;
|
||||
if(sweep_direction) offset = -offset;
|
||||
frequency_shadow += offset;
|
||||
|
||||
if(frequency_shadow < 0) {
|
||||
frequency_shadow = 0;
|
||||
} else if(frequency_shadow > 2047) {
|
||||
frequency_shadow = 2048;
|
||||
enable = false;
|
||||
}
|
||||
|
||||
if(frequency_shadow <= 2047 && sweep_shift) {
|
||||
frequency = frequency_shadow;
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
void APU::Square1::clock_sweep() {
|
||||
if(sweep_frequency && sweep_period && --sweep_period == 0) {
|
||||
sweep_period = sweep_frequency;
|
||||
sweep();
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clock_envelope() {
|
||||
if(envelope_period && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
if(envelope_direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::write(unsigned r, uint8 data) {
|
||||
if(r == 0) {
|
||||
sweep_frequency = (data >> 4) & 7;
|
||||
sweep_direction = data & 0x08;
|
||||
sweep_shift = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
duty = data >> 6;
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
envelope_volume = data >> 4;
|
||||
envelope_direction = data & 0x08;
|
||||
envelope_frequency = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
frequency = (frequency & 0x0700) | data;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||
|
||||
if(initialize) {
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
frequency_shadow = frequency;
|
||||
sweep_period = sweep_frequency;
|
||||
enable = sweep_period || sweep_shift;
|
||||
if(sweep_shift) sweep();
|
||||
}
|
||||
}
|
||||
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Square1::power() {
|
||||
sweep_frequency = 0;
|
||||
sweep_direction = 0;
|
||||
sweep_shift = 0;
|
||||
duty = 0;
|
||||
length = 0;
|
||||
envelope_volume = 0;
|
||||
envelope_direction = 0;
|
||||
envelope_frequency = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
|
||||
output = 0;
|
||||
duty_output = 0;
|
||||
phase = 0;
|
||||
period = 0;
|
||||
envelope_period = 0;
|
||||
sweep_period = 0;
|
||||
frequency_shadow = 0;
|
||||
enable = 0;
|
||||
volume = 0;
|
||||
}
|
||||
|
||||
void APU::Square1::serialize(serializer &s) {
|
||||
s.integer(sweep_frequency);
|
||||
s.integer(sweep_direction);
|
||||
s.integer(sweep_shift);
|
||||
s.integer(duty);
|
||||
s.integer(length);
|
||||
s.integer(envelope_volume);
|
||||
s.integer(envelope_direction);
|
||||
s.integer(envelope_frequency);
|
||||
s.integer(frequency);
|
||||
s.integer(counter);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(duty_output);
|
||||
s.integer(phase);
|
||||
s.integer(period);
|
||||
s.integer(envelope_period);
|
||||
s.integer(sweep_period);
|
||||
s.integer(frequency_shadow);
|
||||
s.integer(enable);
|
||||
s.integer(volume);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
struct Square1 {
|
||||
unsigned sweep_frequency;
|
||||
unsigned sweep_direction;
|
||||
unsigned sweep_shift;
|
||||
unsigned duty;
|
||||
unsigned length;
|
||||
unsigned envelope_volume;
|
||||
unsigned envelope_direction;
|
||||
unsigned envelope_frequency;
|
||||
unsigned frequency;
|
||||
unsigned counter;
|
||||
|
||||
int16 output;
|
||||
bool duty_output;
|
||||
unsigned phase;
|
||||
unsigned period;
|
||||
unsigned envelope_period;
|
||||
unsigned sweep_period;
|
||||
signed frequency_shadow;
|
||||
bool enable;
|
||||
unsigned volume;
|
||||
|
||||
void run();
|
||||
void sweep();
|
||||
void clock_length();
|
||||
void clock_sweep();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
|
@ -0,0 +1,97 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Square2::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 4 * (2048 - frequency);
|
||||
phase = (phase + 1) & 7;
|
||||
switch(duty) {
|
||||
case 0: duty_output = (phase == 6); break; //______-_
|
||||
case 1: duty_output = (phase >= 6); break; //______--
|
||||
case 2: duty_output = (phase >= 4); break; //____----
|
||||
case 3: duty_output = (phase <= 5); break; //------__
|
||||
}
|
||||
}
|
||||
|
||||
uint4 sample = (duty_output ? volume : 0);
|
||||
if(counter && length == 0) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
}
|
||||
|
||||
void APU::Square2::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
void APU::Square2::clock_envelope() {
|
||||
if(envelope_period && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
if(envelope_direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square2::write(unsigned r, uint8 data) {
|
||||
if(r == 1) {
|
||||
duty = data >> 6;
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
envelope_volume = data >> 4;
|
||||
envelope_direction = data & 0x08;
|
||||
envelope_frequency = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
frequency = (frequency & 0x0700) | data;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||
|
||||
if(initialize) {
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
}
|
||||
}
|
||||
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Square2::power() {
|
||||
duty = 0;
|
||||
length = 0;
|
||||
envelope_volume = 0;
|
||||
envelope_direction = 0;
|
||||
envelope_frequency = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
|
||||
output = 0;
|
||||
duty_output = 0;
|
||||
phase = 0;
|
||||
period = 0;
|
||||
envelope_period = 0;
|
||||
volume = 0;
|
||||
}
|
||||
|
||||
void APU::Square2::serialize(serializer &s) {
|
||||
s.integer(duty);
|
||||
s.integer(length);
|
||||
s.integer(envelope_volume);
|
||||
s.integer(envelope_direction);
|
||||
s.integer(envelope_frequency);
|
||||
s.integer(frequency);
|
||||
s.integer(counter);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(duty_output);
|
||||
s.integer(phase);
|
||||
s.integer(period);
|
||||
s.integer(envelope_period);
|
||||
s.integer(volume);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,19 +1,22 @@
|
|||
struct Square {
|
||||
bool has_sweep;
|
||||
|
||||
unsigned sweep_period;
|
||||
unsigned sweep_direction;
|
||||
unsigned sweep_shift;
|
||||
struct Square2 {
|
||||
unsigned duty;
|
||||
unsigned length;
|
||||
unsigned envelope_volume;
|
||||
unsigned envelope_direction;
|
||||
unsigned envelope_period;
|
||||
unsigned envelope_frequency;
|
||||
unsigned frequency;
|
||||
unsigned counter;
|
||||
|
||||
int16 output;
|
||||
bool duty_output;
|
||||
unsigned phase;
|
||||
unsigned period;
|
||||
unsigned envelope_period;
|
||||
unsigned volume;
|
||||
|
||||
void run();
|
||||
uint8 read(unsigned r);
|
||||
void clock_length();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
|
@ -1,31 +1,40 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Wave::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 2 * (2048 - frequency);
|
||||
pattern_offset = (pattern_offset + 1) & 31;
|
||||
pattern_sample = pattern[pattern_offset];
|
||||
}
|
||||
|
||||
uint4 sample = pattern_sample;
|
||||
if(counter && length == 0) sample = 0;
|
||||
if(enable == false) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
switch(volume) {
|
||||
case 0: output *= 0.00; break;
|
||||
case 1: output *= 1.00; break;
|
||||
case 2: output *= 0.50; break;
|
||||
case 3: output *= 0.25; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 APU::Wave::read(unsigned r) {
|
||||
if(r == 0) {
|
||||
return (off << 7);
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
return (volume << 5);
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
return (counter << 6);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
void APU::Wave::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
void APU::Wave::write(unsigned r, uint8 data) {
|
||||
if(r == 0) {
|
||||
off = data & 0x80;
|
||||
dac_enable = data & 0x80;
|
||||
|
||||
if(dac_enable == false) enable = false;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
length = data;
|
||||
initial_length = 256 - data;
|
||||
|
||||
length = initial_length;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
|
@ -40,36 +49,55 @@ void APU::Wave::write(unsigned r, uint8 data) {
|
|||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 APU::Wave::read_pattern(unsigned p) {
|
||||
p <<= 1;
|
||||
return (pattern[p + 0] << 4) | (pattern[p + 1] << 0);
|
||||
if(initialize && dac_enable) {
|
||||
enable = true;
|
||||
pattern_offset = 0;
|
||||
length = initial_length;
|
||||
}
|
||||
}
|
||||
|
||||
period = 2 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Wave::write_pattern(unsigned p, uint8 data) {
|
||||
p <<= 1;
|
||||
pattern[p + 0] = data >> 4;
|
||||
pattern[p + 1] = data >> 0;
|
||||
pattern[p + 0] = (data >> 4) & 15;
|
||||
pattern[p + 1] = (data >> 0) & 15;
|
||||
}
|
||||
|
||||
void APU::Wave::power() {
|
||||
off = 0;
|
||||
length = 0;
|
||||
dac_enable = 0;
|
||||
initial_length = 0;
|
||||
volume = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
foreach(n, pattern) n = 0;
|
||||
|
||||
random_cyclic r;
|
||||
foreach(n, pattern) n = r() & 15;
|
||||
|
||||
output = 0;
|
||||
enable = 0;
|
||||
length = 0;
|
||||
period = 0;
|
||||
pattern_offset = 0;
|
||||
pattern_sample = 0;
|
||||
}
|
||||
|
||||
void APU::Wave::serialize(serializer &s) {
|
||||
s.integer(off);
|
||||
s.integer(length);
|
||||
s.integer(dac_enable);
|
||||
s.integer(initial_length);
|
||||
s.integer(volume);
|
||||
s.integer(frequency);
|
||||
s.integer(counter);
|
||||
s.array(pattern);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(enable);
|
||||
s.integer(length);
|
||||
s.integer(period);
|
||||
s.integer(pattern_offset);
|
||||
s.integer(pattern_sample);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
struct Wave {
|
||||
bool off;
|
||||
unsigned length;
|
||||
bool dac_enable;
|
||||
unsigned initial_length;
|
||||
unsigned volume;
|
||||
unsigned frequency;
|
||||
bool counter;
|
||||
uint8 pattern[32];
|
||||
|
||||
int16 output;
|
||||
bool enable;
|
||||
unsigned length;
|
||||
unsigned period;
|
||||
unsigned pattern_offset;
|
||||
unsigned pattern_sample;
|
||||
|
||||
void run();
|
||||
uint8 read(unsigned r);
|
||||
void clock_length();
|
||||
void write(unsigned r, uint8 data);
|
||||
uint8 read_pattern(unsigned p);
|
||||
void write_pattern(unsigned p, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
|
|
|
@ -114,13 +114,7 @@ void CPU::power() {
|
|||
status.clock = 0;
|
||||
status.halt = false;
|
||||
status.stop = false;
|
||||
|
||||
status.ime = 0;
|
||||
status.timer0 = 0;
|
||||
status.timer1 = 0;
|
||||
status.timer2 = 0;
|
||||
status.timer3 = 0;
|
||||
status.timer4 = 0;
|
||||
|
||||
status.p15 = 0;
|
||||
status.p14 = 0;
|
||||
|
|
|
@ -17,13 +17,7 @@ struct CPU : Processor, MMIO {
|
|||
unsigned clock;
|
||||
bool halt;
|
||||
bool stop;
|
||||
|
||||
bool ime;
|
||||
unsigned timer0;
|
||||
unsigned timer1;
|
||||
unsigned timer2;
|
||||
unsigned timer3;
|
||||
unsigned timer4;
|
||||
|
||||
//$ff00 JOYP
|
||||
bool p15;
|
||||
|
|
|
@ -21,13 +21,7 @@ void CPU::serialize(serializer &s) {
|
|||
s.integer(status.clock);
|
||||
s.integer(status.halt);
|
||||
s.integer(status.stop);
|
||||
|
||||
s.integer(status.ime);
|
||||
s.integer(status.timer0);
|
||||
s.integer(status.timer1);
|
||||
s.integer(status.timer2);
|
||||
s.integer(status.timer3);
|
||||
s.integer(status.timer4);
|
||||
|
||||
s.integer(status.p15);
|
||||
s.integer(status.p14);
|
||||
|
|
|
@ -22,8 +22,12 @@ void CPU::add_clocks(unsigned clocks) {
|
|||
cartridge.mbc3.second();
|
||||
}
|
||||
|
||||
status.timer0 += clocks;
|
||||
if(status.timer0 >= 16) timer_stage0();
|
||||
//4194304 / N(hz) - 1 = mask
|
||||
if((status.clock & 15) == 0) timer_262144hz();
|
||||
if((status.clock & 63) == 0) timer_65536hz();
|
||||
if((status.clock & 255) == 0) timer_16384hz();
|
||||
if((status.clock & 511) == 0) timer_8192hz();
|
||||
if((status.clock & 1023) == 0) timer_4096hz();
|
||||
|
||||
lcd.clock -= clocks;
|
||||
if(lcd.clock <= 0) co_switch(scheduler.active_thread = lcd.thread);
|
||||
|
@ -32,31 +36,25 @@ void CPU::add_clocks(unsigned clocks) {
|
|||
if(apu.clock <= 0) co_switch(scheduler.active_thread = apu.thread);
|
||||
}
|
||||
|
||||
void CPU::timer_stage0() { //262144hz
|
||||
void CPU::timer_262144hz() {
|
||||
if(status.timer_enable && status.timer_clock == 1) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer0 -= 16;
|
||||
if(++status.timer1 >= 4) timer_stage1();
|
||||
}
|
||||
|
||||
void CPU::timer_stage1() { // 65536hz
|
||||
void CPU::timer_65536hz() {
|
||||
if(status.timer_enable && status.timer_clock == 2) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer1 -= 4;
|
||||
if(++status.timer2 >= 4) timer_stage2();
|
||||
}
|
||||
|
||||
void CPU::timer_stage2() { // 16384hz
|
||||
void CPU::timer_16384hz() {
|
||||
if(status.timer_enable && status.timer_clock == 3) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
|
@ -65,32 +63,24 @@ void CPU::timer_stage2() { // 16384hz
|
|||
}
|
||||
|
||||
status.div++;
|
||||
|
||||
status.timer2 -= 4;
|
||||
if(++status.timer3 >= 2) timer_stage3();
|
||||
}
|
||||
|
||||
void CPU::timer_stage3() { // 8192hz
|
||||
void CPU::timer_8192hz() {
|
||||
if(status.serial_transfer && status.serial_clock) {
|
||||
if(--status.serial_bits == 0) {
|
||||
status.serial_transfer = 0;
|
||||
interrupt_raise(Interrupt::Serial);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer3 -= 2;
|
||||
if(++status.timer4 >= 2) timer_stage4();
|
||||
}
|
||||
|
||||
void CPU::timer_stage4() { // 4096hz
|
||||
void CPU::timer_4096hz() {
|
||||
if(status.timer_enable && status.timer_clock == 0) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer4 -= 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
void add_clocks(unsigned clocks);
|
||||
void timer_stage0();
|
||||
void timer_stage1();
|
||||
void timer_stage2();
|
||||
void timer_stage3();
|
||||
void timer_stage4();
|
||||
void timer_262144hz();
|
||||
void timer_65536hz();
|
||||
void timer_16384hz();
|
||||
void timer_8192hz();
|
||||
void timer_4096hz();
|
||||
|
||||
//opcode.cpp
|
||||
void op_io();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const char Version[] = "000.15";
|
||||
static const char Version[] = "000.16";
|
||||
static unsigned SerializerVersion = 1;
|
||||
}
|
||||
}
|
||||
|
@ -15,22 +15,30 @@ namespace GameBoy {
|
|||
#include <nall/foreach.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
using namespace nall;
|
||||
|
||||
namespace GameBoy {
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef int_t< 4> int4;
|
||||
typedef int_t<15> int15;
|
||||
|
||||
typedef uint_t< 4> uint4;
|
||||
typedef uint_t<15> uint15;
|
||||
|
||||
template<uint16 lo, uint16 hi>
|
||||
alwaysinline bool within(uint16 addr) {
|
||||
static const uint16 mask = ~(hi ^ lo);
|
||||
|
|
|
@ -3,7 +3,7 @@ public:
|
|||
virtual void joyp_write(bool p15, bool p14) {}
|
||||
|
||||
virtual void video_refresh(const uint8_t *data) {}
|
||||
virtual void audio_sample(signed left, signed right) {}
|
||||
virtual void audio_sample(int16_t center, int16_t left, int16_t right) {}
|
||||
virtual void input_poll() {}
|
||||
virtual bool input_poll(unsigned id) {}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ void ICD2::joyp_write(bool p15, bool p14) {
|
|||
void ICD2::video_refresh(const uint8_t *data) {
|
||||
}
|
||||
|
||||
void ICD2::audio_sample(signed left, signed right) {
|
||||
void ICD2::audio_sample(int16_t center, int16_t left, int16_t right) {
|
||||
audio.coprocessor_sample(left, right);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
void joyp_write(bool p15, bool p14);
|
||||
void video_refresh(const uint8_t *data);
|
||||
void audio_sample(signed left, signed right);
|
||||
void audio_sample(int16_t center, int16_t left, int16_t right);
|
||||
void input_poll();
|
||||
bool input_poll(unsigned id);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "075.04";
|
||||
static const char Version[] = "075.05";
|
||||
static const unsigned SerializerVersion = 18;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ void Interface::video_refresh(const uint8_t *data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Interface::audio_sample(signed left, signed right) {
|
||||
void Interface::audio_sample(int16_t center, int16_t left, int16_t right) {
|
||||
audio.sample(left, right);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ struct Interface : public GameBoy::Interface {
|
|||
int16_t inputState[Scancode::Limit];
|
||||
|
||||
void video_refresh(const uint8_t *data);
|
||||
void audio_sample(signed left, signed right);
|
||||
void audio_sample(int16_t center, int16_t left, int16_t right);
|
||||
void input_poll();
|
||||
bool input_poll(unsigned id);
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ void Utility::loadCartridge(const char *filename) {
|
|||
fp.close();
|
||||
|
||||
cartridge.basename = nall::basename(filename);
|
||||
print(cartridge.basename, "\n");
|
||||
|
||||
GameBoyCartridge info(data, size);
|
||||
GameBoy::cartridge.load(info.xml, data, size);
|
||||
|
|
Loading…
Reference in New Issue