Update to v082r23 release.

byuu says:

Ryphecha fixed the FF1 glitch, added two highpass filters to NES audio
output (still working on a lowpass), and fixed VRC6 audio issues.
I reduced the complexity of all eight supported mapping modes, and
standardized them; and added in an overscan filter (not in archive) for
chopping off all the NES edge garbage (8 pixels on the left and right,
16 on the top and bottom.)
It's extreme, but anything less shows junk. I may make this part of the
menu option, just clip off more on NES mode than SNES mode.
This commit is contained in:
Tim Allen 2011-09-26 21:38:57 +10:00
parent 046e478d86
commit 875ed46d79
27 changed files with 287 additions and 465 deletions

View File

@ -47,7 +47,14 @@ void APU::main() {
clock_frame_counter_divider();
signed output = rectangle_dac[rectangle_output] + dmc_triangle_noise_dac[dmc_output][triangle_output][noise_output];
interface->audioSample(output + cartridge_sample);
output = filter.run_hipass_strong(output);
output += cartridge_sample;
output = filter.run_hipass_weak(output);
//output = filter.run_lopass(output);
output = sclamp<16>(output);
interface->audioSample(output);
tick();
}
@ -67,6 +74,10 @@ void APU::set_sample(int16 sample) {
}
void APU::power() {
filter.hipass_strong = 0;
filter.hipass_weak = 0;
filter.lopass = 0;
for(unsigned n = 0; n < 2; n++) {
rectangle[n].sweep.shift = 0;
rectangle[n].sweep.decrement = 0;
@ -302,6 +313,21 @@ void APU::write(uint16 addr, uint8 data) {
}
}
signed APU::Filter::run_hipass_strong(signed sample) {
hipass_strong += ((((int64)sample << 16) - (hipass_strong >> 16)) * HiPassStrong) >> 16;
return sample - (hipass_strong >> 32);
}
signed APU::Filter::run_hipass_weak(signed sample) {
hipass_weak += ((((int64)sample << 16) - (hipass_weak >> 16)) * HiPassWeak) >> 16;
return sample - (hipass_weak >> 32);
}
signed APU::Filter::run_lopass(signed sample) {
lopass += ((((int64)sample << 16) - (lopass >> 16)) * LoPass) >> 16;
return (lopass >> 32);
}
bool APU::Sweep::check_period() {
if(rectangle_period > 0x7ff) return false;

View File

@ -14,6 +14,19 @@ struct APU : Processor {
void serialize(serializer&);
APU();
struct Filter {
enum : signed { HiPassStrong = 225574, HiPassWeak = 57593, LoPass = 86322413 };
int64 hipass_strong;
int64 hipass_weak;
int64 lopass;
signed run_hipass_strong(signed sample);
signed run_hipass_weak(signed sample);
signed run_lopass(signed sample);
void serialize(serializer&);
} filter;
struct Envelope {
uint4 speed;
bool use_speed_as_volume;

View File

@ -1,6 +1,8 @@
void APU::serialize(serializer &s) {
Processor::serialize(s);
filter.serialize(s);
rectangle[0].serialize(s);
rectangle[1].serialize(s);
triangle.serialize(s);
@ -11,6 +13,12 @@ void APU::serialize(serializer &s) {
s.integer(cartridge_sample);
}
void APU::Filter::serialize(serializer &s) {
s.integer(hipass_strong);
s.integer(hipass_weak);
s.integer(lopass);
}
void APU::Envelope::serialize(serializer &s) {
s.integer(speed);
s.integer(use_speed_as_volume);

View File

@ -85,27 +85,27 @@ Cartridge::Cartridge() {
loaded = false;
}
uint8 Cartridge::prg_read(uint16 addr) {
uint8 Cartridge::prg_read(unsigned addr) {
return mapper->prg_read(addr);
}
void Cartridge::prg_write(uint16 addr, uint8 data) {
void Cartridge::prg_write(unsigned addr, uint8 data) {
return mapper->prg_write(addr, data);
}
uint8 Cartridge::chr_read(uint16 addr) {
uint8 Cartridge::chr_read(unsigned addr) {
return mapper->chr_read(addr);
}
void Cartridge::chr_write(uint16 addr, uint8 data) {
void Cartridge::chr_write(unsigned addr, uint8 data) {
return mapper->chr_write(addr, data);
}
uint8 Cartridge::ciram_read(uint13 addr) {
uint8 Cartridge::ciram_read(unsigned addr) {
return mapper->ciram_read(addr);
}
void Cartridge::ciram_write(uint13 addr, uint8 data) {
void Cartridge::ciram_write(unsigned addr, uint8 data) {
return mapper->ciram_write(addr, data);
}

View File

@ -20,14 +20,14 @@ struct Cartridge : Processor, property<Cartridge> {
//privileged:
Mapper::Mapper *mapper;
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 ciram_read(unsigned addr);
void ciram_write(unsigned addr, uint8 data);
uint8 *rom_data;
unsigned rom_size;

View File

@ -1,36 +1,28 @@
AOROM aorom;
uint8 AOROM::prg_read(uint16 addr) {
uint8 AOROM::prg_read(unsigned addr) {
if(addr & 0x8000) {
unsigned rom_addr = (prg_bank << 15) | (addr & 0x7fff);
return cartridge.prg_data[mirror(rom_addr, cartridge.prg_size)];
addr = (prg_bank << 15) | (addr & 0x7fff);
return Mapper::prg_read(addr);
}
return cpu.mdr();
}
void AOROM::prg_write(uint16 addr, uint8 data) {
void AOROM::prg_write(unsigned addr, uint8 data) {
if(addr & 0x8000) {
prg_bank = data & 0x0f;
mirror_select = data & 0x10;
}
}
uint8 AOROM::chr_read(uint16 addr) {
return cartridge.chr_data[mirror(addr, cartridge.chr_size)];
uint8 AOROM::chr_read(unsigned addr) {
if(addr & 0x2000) return ppu.ciram_read((mirror_select << 10) | (addr & 0x03ff));
return Mapper::chr_read(addr);
}
void AOROM::chr_write(uint16 addr, uint8 data) {
if(cartridge.chr_ram == false) return;
cartridge.chr_data[mirror(addr, cartridge.chr_size)] = data;
}
uint8 AOROM::ciram_read(uint13 addr) {
return ppu.ciram_read((mirror_select << 10) | (addr & 0x03ff));
}
void AOROM::ciram_write(uint13 addr, uint8 data) {
return ppu.ciram_write((mirror_select << 10) | (addr & 0x03ff), data);
void AOROM::chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) return ppu.ciram_write((mirror_select << 10) | (addr & 0x03ff), data);
return Mapper::chr_write(addr, data);
}
void AOROM::power() {

View File

@ -1,12 +1,9 @@
struct AOROM : Mapper {
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
void power();
void reset();

View File

@ -17,21 +17,21 @@ void BandaiFCG::main() {
}
}
uint8 BandaiFCG::prg_read(uint16 addr) {
if(addr >= 0x8000 && addr <= 0xbfff) {
unsigned rom_addr = (prg_bank << 14) | (addr & 0x3fff);
return cartridge.prg_data[mirror(rom_addr, cartridge.prg_size)];
uint8 BandaiFCG::prg_read(unsigned addr) {
if((addr & 0xc000) == 0x8000) {
addr = (prg_bank << 14) | (addr & 0x3fff);
return Mapper::prg_read(addr);
}
if(addr >= 0xc000 && addr <= 0xffff) {
unsigned rom_addr = (0x0f << 14) | (addr & 0x3fff);
return cartridge.prg_data[mirror(rom_addr, cartridge.prg_size)];
if((addr & 0xc000) == 0xc000) {
addr = (0x0f << 14) | (addr & 0x3fff);
return Mapper::prg_read(addr);
}
return cpu.mdr();
}
void BandaiFCG::prg_write(uint16 addr, uint8 data) {
void BandaiFCG::prg_write(unsigned addr, uint8 data) {
if(addr >= 0x6000) {
addr &= 0x0f;
switch(addr) {
@ -62,25 +62,18 @@ void BandaiFCG::prg_write(uint16 addr, uint8 data) {
}
}
uint8 BandaiFCG::chr_read(uint16 addr) {
unsigned rom_addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff);
return cartridge.chr_data[mirror(rom_addr, cartridge.chr_size)];
uint8 BandaiFCG::chr_read(unsigned addr) {
if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr));
addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff);
return Mapper::chr_read(addr);
}
void BandaiFCG::chr_write(uint16 addr, uint8 data) {
if(cartridge.chr_ram == false) return;
unsigned rom_addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff);
cartridge.chr_data[mirror(rom_addr, cartridge.chr_size)] = data;
}
void BandaiFCG::chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data);
uint8 BandaiFCG::ciram_read(uint13 addr) {
addr = ciram_addr(addr);
return ppu.ciram_read(addr);
}
void BandaiFCG::ciram_write(uint13 addr, uint8 data) {
addr = ciram_addr(addr);
return ppu.ciram_write(addr, data);
addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff);
Mapper::chr_write(addr, data);
}
void BandaiFCG::power() {
@ -96,8 +89,6 @@ void BandaiFCG::reset() {
irq_latch = 0;
}
//
unsigned BandaiFCG::ciram_addr(unsigned addr) const {
switch(mirror_select & 0x03) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
@ -108,8 +99,6 @@ unsigned BandaiFCG::ciram_addr(unsigned addr) const {
throw;
}
//
void BandaiFCG::serialize(serializer &s) {
s.array(chr_bank);
s.integer(prg_bank);

View File

@ -1,14 +1,11 @@
struct BandaiFCG : Mapper {
void main();
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
void power();
void reset();

View File

@ -1,36 +1,32 @@
CNROM cnrom;
uint8 CNROM::prg_read(uint16 addr) {
if(addr & 0x8000) {
return cartridge.prg_data[mirror(addr & 0x7fff, cartridge.prg_size)];
}
uint8 CNROM::prg_read(unsigned addr) {
if(addr & 0x8000) return Mapper::prg_read(addr & 0x7fff);
return cpu.mdr();
}
void CNROM::prg_write(uint16 addr, uint8 data) {
void CNROM::prg_write(unsigned addr, uint8 data) {
if(addr & 0x8000) chr_bank = data & 0x03;
}
uint8 CNROM::chr_read(uint16 addr) {
unsigned chr_addr = (chr_bank * 0x2000) + (addr & 0x1fff);
return cartridge.chr_data[mirror(chr_addr, cartridge.chr_size)];
uint8 CNROM::chr_read(unsigned addr) {
if(addr & 0x2000) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_read(addr & 0x07ff);
}
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
return Mapper::chr_read(addr);
}
void CNROM::chr_write(uint16 addr, uint8 data) {
if(cartridge.chr_ram == false) return;
unsigned chr_addr = (chr_bank * 0x2000) + (addr & 0x1fff);
cartridge.chr_data[mirror(chr_addr, cartridge.chr_size)] = data;
}
void CNROM::chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_write(addr & 0x07ff, data);
}
uint8 CNROM::ciram_read(uint13 addr) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_read(addr & 0x07ff);
}
void CNROM::ciram_write(uint13 addr, uint8 data) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_write(addr & 0x07ff, data);
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
Mapper::chr_write(addr, data);
}
void CNROM::power() {

View File

@ -1,12 +1,9 @@
struct CNROM : Mapper {
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
void power();
void reset();

View File

@ -37,14 +37,23 @@ unsigned Mapper::mirror(unsigned addr, unsigned size) const {
return base;
}
uint8& Mapper::prg_data(unsigned addr) {
uint8 Mapper::prg_read(unsigned addr) {
return cartridge.prg_data[mirror(addr, cartridge.prg_size)];
}
uint8& Mapper::chr_data(unsigned addr) {
void Mapper::prg_write(unsigned addr, uint8 data) {
cartridge.prg_data[mirror(addr, cartridge.prg_size)] = data;
}
uint8 Mapper::chr_read(unsigned addr) {
return cartridge.chr_data[mirror(addr, cartridge.chr_size)];
}
void Mapper::chr_write(unsigned addr, uint8 data) {
if(cartridge.chr_ram == false) return;
cartridge.chr_data[mirror(addr, cartridge.chr_size)] = data;
}
unsigned Mapper::ram_size() {
return 0u;
}

View File

@ -4,17 +4,18 @@ namespace Mapper {
virtual void tick();
unsigned mirror(unsigned addr, unsigned size) const;
uint8& prg_data(unsigned addr);
uint8& chr_data(unsigned addr);
virtual uint8 prg_read(uint16 addr) = 0;
virtual void prg_write(uint16 addr, uint8 data) = 0;
//note: Mapper::{prg,chr}_read() functions take literal ROM addresses; mirroring appropriately
//subclasses of Mapper take 16-bit bus addresses; decode them; and call Mapper read functions
virtual uint8 chr_read(uint16 addr) = 0;
virtual void chr_write(uint16 addr, uint8 data) = 0;
virtual uint8 prg_read(unsigned addr);
virtual void prg_write(unsigned addr, uint8 data);
virtual uint8 ciram_read(uint13 addr) = 0;
virtual void ciram_write(uint13 addr, uint8 data) = 0;
virtual uint8 chr_read(unsigned addr);
virtual void chr_write(unsigned addr, uint8 data);
virtual uint8 ciram_read(uint13 addr) {}
virtual void ciram_write(uint13 addr, uint8 data) {}
virtual unsigned ram_size();
virtual uint8* ram_data();

View File

@ -66,41 +66,27 @@ bool MMC1::prg_ram_disable() const {
return r[3] & 0x10;
}
//
uint8& MMC1::prg_data(unsigned addr) {
return cartridge.prg_data[mirror(addr, cartridge.prg_size)];
}
uint8& MMC1::chr_data(unsigned addr) {
return cartridge.chr_data[mirror(addr, cartridge.chr_size)];
}
//
uint8 MMC1::prg_read(uint16 readaddr) {
unsigned addr = readaddr;
if(addr >= 0x6000 && addr <= 0x7fff) {
uint8 MMC1::prg_read(unsigned addr) {
if((addr & 0xe000) == 0x6000) {
if(prg_ram_disable() == false) return prg_ram[addr & 0x1fff];
return 0x00;
}
if(addr >= 0x8000 && addr <= 0xffff) {
if(addr & 0x8000) {
addr = prg_addr(addr & 0x4000) | (addr & 0x3fff);
return prg_data(addr);
return Mapper::prg_read(addr);
}
return cpu.mdr();
}
void MMC1::prg_write(uint16 addr, uint8 data) {
if(addr >= 0x6000 && addr <= 0x7fff) {
void MMC1::prg_write(unsigned addr, uint8 data) {
if((addr & 0xe000) == 0x6000) {
if(prg_ram_disable() == false) prg_ram[addr & 0x1fff] = data;
return;
}
if(addr >= 0x8000 && addr <= 0xffff) {
if(addr & 0x8000) {
if(data & 0x80) {
shiftaddr = 0;
r[0] |= 0x0c;
@ -116,60 +102,48 @@ void MMC1::prg_write(uint16 addr, uint8 data) {
}
}
//
uint8 MMC1::chr_read(unsigned addr) {
if(addr & 0x2000) {
return ppu.ciram_read(ciram_addr(addr));
}
uint8 MMC1::chr_read(uint16 readaddr) {
unsigned addr = readaddr;
prg_ex_select = addr & 0x1000;
if(addr <= 0x0fff) {
addr = chr_banklo() * 0x1000 + (addr & 0x0fff);
return chr_data(addr);
return Mapper::chr_read(addr);
}
if(addr <= 0x1fff) {
addr = chr_bankhi() * 0x1000 + (addr & 0x0fff);
return chr_data(addr);
return Mapper::chr_read(addr);
}
throw;
}
void MMC1::chr_write(uint16 readaddr, uint8 data) {
unsigned addr = readaddr;
void MMC1::chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) {
return ppu.ciram_write(ciram_addr(addr), data);
}
prg_ex_select = addr & 0x1000;
if(addr <= 0x0fff) {
if(cartridge.chr_ram == false) return;
addr = chr_banklo() * 0x1000 + (addr & 0x0fff);
chr_data(addr) = data;
return;
return Mapper::chr_write(addr, data);
}
if(addr <= 0x1fff) {
if(cartridge.chr_ram == false) return;
addr = chr_bankhi() * 0x1000 + (addr & 0x0fff);
chr_data(addr) = data;
return;
return Mapper::chr_write(addr, data);
}
throw;
}
//
uint8 MMC1::ciram_read(uint13 addr) {
addr = ciram_addr(addr);
return ppu.ciram_read(addr);
}
void MMC1::ciram_write(uint13 addr, uint8 data) {
addr = ciram_addr(addr);
return ppu.ciram_write(addr, data);
}
//
unsigned MMC1::ram_size() {
return 8192u;
}
@ -178,8 +152,6 @@ uint8* MMC1::ram_data() {
return prg_ram;
}
//
void MMC1::power() {
reset();
}
@ -195,8 +167,6 @@ void MMC1::reset() {
r[3] = 0x00;
}
//
void MMC1::serialize(serializer &s) {
s.array(prg_ram);
s.array(r);

View File

@ -1,12 +1,9 @@
struct MMC1 : Mapper {
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
unsigned ram_size();
uint8* ram_data();
@ -32,9 +29,6 @@ private:
unsigned chr_bankhi() const;
unsigned prg_bank() const;
bool prg_ram_disable() const;
uint8& prg_data(unsigned addr);
uint8& chr_data(unsigned addr);
};
extern MMC1 mmc1;

View File

@ -48,7 +48,7 @@ unsigned MMC3::prg_addr(uint16 addr) {
throw;
}
uint8 MMC3::prg_read(uint16 addr) {
uint8 MMC3::prg_read(unsigned addr) {
if((addr & 0xe000) == 0x6000) { //$6000-7fff
if(prg_ram_enable) {
return prg_ram[addr & 0x1fff];
@ -56,13 +56,13 @@ uint8 MMC3::prg_read(uint16 addr) {
}
if(addr & 0x8000) { //$8000-ffff
return prg_data(prg_addr(addr));
return Mapper::prg_read(prg_addr(addr));
}
return cpu.mdr();
}
void MMC3::prg_write(uint16 addr, uint8 data) {
void MMC3::prg_write(unsigned addr, uint8 data) {
if((addr & 0xe000) == 0x6000) { //$6000-7fff
if(prg_ram_enable && prg_ram_write_protect == false) {
prg_ram[addr & 0x1fff] = data;
@ -138,33 +138,24 @@ unsigned MMC3::chr_addr(uint16 addr) {
throw;
}
uint8 MMC3::chr_read(uint16 addr) {
uint8 MMC3::chr_read(unsigned addr) {
irq_test(addr);
return chr_data(chr_addr(addr));
if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr));
return Mapper::chr_read(chr_addr(addr));
}
void MMC3::chr_write(uint16 addr, uint8 data) {
void MMC3::chr_write(unsigned addr, uint8 data) {
irq_test(addr);
if(cartridge.chr_ram == false) return;
chr_data(chr_addr(addr)) = data;
if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data);
return Mapper::chr_write(chr_addr(addr), data);
}
unsigned MMC3::ciram_addr(uint13 addr) {
irq_test(0x2000 | addr);
if(mirror_select == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
if(mirror_select == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
throw;
}
uint8 MMC3::ciram_read(uint13 addr) {
irq_test(0x2000 | addr);
return ppu.ciram_read(ciram_addr(addr));
}
void MMC3::ciram_write(uint13 addr, uint8 data) {
return ppu.ciram_write(ciram_addr(addr), data);
}
unsigned MMC3::ram_size() {
return 8192u;
}

View File

@ -1,14 +1,11 @@
struct MMC3 : Mapper {
void main();
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
unsigned ram_size();
uint8* ram_data();

View File

@ -1,35 +1,27 @@
None none;
uint8 None::prg_read(uint16 addr) {
if(addr >= 0x8000 && addr <= 0xffff) {
addr &= 0x7fff;
if(addr >= cartridge.prg_size) addr &= cartridge.prg_size - 1;
return cartridge.prg_data[addr];
}
uint8 None::prg_read(unsigned addr) {
if(addr & 0x8000) return Mapper::prg_read(addr);
return cpu.mdr();
}
void None::prg_write(uint16 addr, uint8 data) {
void None::prg_write(unsigned addr, uint8 data) {
}
uint8 None::chr_read(uint16 addr) {
return cartridge.chr_data[addr & 0x1fff];
uint8 None::chr_read(unsigned addr) {
if(addr & 0x2000) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_read(addr & 0x07ff);
}
return Mapper::chr_read(addr);
}
void None::chr_write(uint16 addr, uint8 data) {
if(cartridge.chr_ram == false) return;
cartridge.chr_data[addr & 0x1fff] = data;
}
uint8 None::ciram_read(uint13 addr) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_read(addr & 0x07ff);
}
void None::ciram_write(uint13 addr, uint8 data) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_write(addr & 0x07ff, data);
void None::chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_write(addr & 0x07ff, data);
}
return Mapper::chr_write(addr, data);
}
void None::power() {

View File

@ -1,12 +1,9 @@
struct None : Mapper {
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
void power();
void reset();

View File

@ -1,36 +1,35 @@
UOROM uorom;
uint8 UOROM::prg_read(uint16 addr) {
uint8 UOROM::prg_read(unsigned addr) {
if((addr & 0xc000) == 0x8000) {
return prg_data((prg_bank << 14) | (addr & 0x3fff));
return Mapper::prg_read((prg_bank << 14) | (addr & 0x3fff));
}
if((addr & 0xc000) == 0xc000) {
return prg_data((0x0f << 14) | (addr & 0x3fff));
return Mapper::prg_read((0x0f << 14) | (addr & 0x3fff));
}
}
void UOROM::prg_write(uint16 addr, uint8 data) {
void UOROM::prg_write(unsigned addr, uint8 data) {
if(addr & 0x8000) prg_bank = data & 0x0f;
}
uint8 UOROM::chr_read(uint16 addr) {
return chr_data(addr);
uint8 UOROM::chr_read(unsigned addr) {
if(addr & 0x2000) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_read(addr);
}
return Mapper::chr_read(addr);
}
void UOROM::chr_write(uint16 addr, uint8 data) {
if(cartridge.chr_ram == false) return;
chr_data(addr) = data;
}
void UOROM::chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_write(addr, data);
}
uint8 UOROM::ciram_read(uint13 addr) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_read(addr);
}
void UOROM::ciram_write(uint13 addr, uint8 data) {
if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_write(addr, data);
return Mapper::chr_write(addr, data);
}
void UOROM::power() {

View File

@ -1,12 +1,9 @@
struct UOROM : Mapper {
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
void power();
void reset();

View File

@ -1,45 +1,24 @@
VRC6 vrc6;
//
void VRC6::Pulse::clock() {
if(--divider == 0) {
divider = frequency;
divider = frequency + 1;
cycle++;
output = (mode == 1 || cycle < duty) ? volume : (uint4)0;
output = (mode == 1 || cycle > duty) ? volume : (uint4)0;
}
if(enable == false) output = 0;
}
void VRC6::Pulse::serialize(serializer &s) {
s.integer(mode);
s.integer(duty);
s.integer(volume);
s.integer(enable);
s.integer(frequency);
s.integer(divider);
s.integer(cycle);
s.integer(output);
}
VRC6::Pulse::Pulse() {
for(unsigned n = 0; n < 16; n++) {
dac[n] = -15360 + (n * 2048);
}
}
//
void VRC6::Sawtooth::clock() {
if(--divider == 0) {
divider = frequency;
if(phase == 0) {
phase = 0;
accumulator = 0;
} else if((phase & 1) == 0) {
divider = frequency + 1;
if(++phase == 0) {
accumulator += rate;
if(++stage == 7) {
stage = 0;
accumulator = 0;
}
}
}
@ -47,25 +26,6 @@ void VRC6::Sawtooth::clock() {
if(enable == false) output = 0;
}
void VRC6::Sawtooth::serialize(serializer &s) {
s.integer(rate);
s.integer(enable);
s.integer(frequency);
s.integer(divider);
s.integer(phase);
s.integer(accumulator);
s.integer(output);
}
VRC6::Sawtooth::Sawtooth() {
for(unsigned n = 0; n < 32; n++) {
dac[n] = -15872 + (n * 1024);
}
}
//
void VRC6::main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
@ -95,45 +55,39 @@ void VRC6::main() {
}
}
}
cpu.set_irq_line(irq_line);
pulse1.clock();
pulse2.clock();
sawtooth.clock();
signed output = (pulse1.output + pulse2.output + sawtooth.output) << 7;
apu.set_sample(-output);
signed output = 0;
output += pulse1.dac[ pulse1.output];
output += pulse2.dac[ pulse2.output];
output += sawtooth.dac[sawtooth.output];
output /= 6; //div by 3 for channel count; div that by 2 to match NES volume intensity
output = sclamp<16>(output);
apu.set_sample(output);
cpu.set_irq_line(irq_line);
tick();
}
}
uint8 VRC6::prg_read(uint16 addr) {
uint8 VRC6::prg_read(unsigned addr) {
if((addr & 0xe000) == 0x6000) {
return prg_ram[addr & 0x1fff];
}
if((addr & 0xc000) == 0x8000) {
return prg_data((prg_bank[0] << 14) | (addr & 0x3fff));
return Mapper::prg_read((prg_bank[0] << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xc000) {
return prg_data((prg_bank[1] << 13) | (addr & 0x1fff));
return Mapper::prg_read((prg_bank[1] << 13) | (addr & 0x1fff));
}
if((addr & 0xe000) == 0xe000) {
return prg_data((0xff << 13) | (addr & 0x1fff));
return Mapper::prg_read((0xff << 13) | (addr & 0x1fff));
}
return cpu.mdr();
}
void VRC6::prg_write(uint16 addr, uint8 data) {
void VRC6::prg_write(unsigned addr, uint8 data) {
if((addr & 0xe000) == 0x6000) {
prg_ram[addr & 0x1fff] = data;
return;
@ -228,15 +182,18 @@ void VRC6::prg_write(uint16 addr, uint8 data) {
}
}
uint8 VRC6::chr_read(uint16 addr) {
uint8 VRC6::chr_read(unsigned addr) {
if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr));
unsigned bank = chr_bank[(addr >> 10) & 7];
return chr_data((bank << 10) | (addr & 0x03ff));
return Mapper::chr_read((bank << 10) | (addr & 0x03ff));
}
void VRC6::chr_write(uint16 addr, uint8 data) {
if(cartridge.chr_ram == false) return;
void VRC6::chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data);
unsigned bank = chr_bank[(addr >> 10) & 7];
chr_data((bank << 10) | (addr & 0x03ff)) = data;
Mapper::chr_write((bank << 10) | (addr & 0x03ff), data);
}
unsigned VRC6::ciram_addr(unsigned addr) const {
@ -248,14 +205,6 @@ unsigned VRC6::ciram_addr(unsigned addr) const {
}
}
uint8 VRC6::ciram_read(uint13 addr) {
return ppu.ciram_read(ciram_addr(addr));
}
void VRC6::ciram_write(uint13 addr, uint8 data) {
return ppu.ciram_write(ciram_addr(addr), data);
}
unsigned VRC6::ram_size() {
return 8192u;
}
@ -297,7 +246,7 @@ void VRC6::reset() {
pulse1.enable = 0;
pulse1.frequency = 0;
pulse1.divider = 0;
pulse1.divider = 1;
pulse1.cycle = 0;
pulse1.output = 0;
@ -307,7 +256,7 @@ void VRC6::reset() {
pulse2.enable = 0;
pulse2.frequency = 0;
pulse2.divider = 0;
pulse2.divider = 1;
pulse2.cycle = 0;
pulse2.output = 0;
@ -315,8 +264,9 @@ void VRC6::reset() {
sawtooth.enable = 0;
sawtooth.frequency = 0;
sawtooth.divider = 0;
sawtooth.divider = 1;
sawtooth.phase = 0;
sawtooth.stage = 0;
sawtooth.accumulator = 0;
sawtooth.output = 0;
}
@ -340,3 +290,27 @@ void VRC6::serialize(serializer &s) {
pulse2.serialize(s);
sawtooth.serialize(s);
}
void VRC6::Pulse::serialize(serializer &s) {
s.integer(mode);
s.integer(duty);
s.integer(volume);
s.integer(enable);
s.integer(frequency);
s.integer(divider);
s.integer(cycle);
s.integer(output);
}
void VRC6::Sawtooth::serialize(serializer &s) {
s.integer(rate);
s.integer(enable);
s.integer(frequency);
s.integer(divider);
s.integer(phase);
s.integer(stage);
s.integer(accumulator);
s.integer(output);
}

View File

@ -1,14 +1,11 @@
struct VRC6 : Mapper {
void main();
uint8 prg_read(uint16 addr);
void prg_write(uint16 addr, uint8 data);
uint8 prg_read(unsigned addr);
void prg_write(unsigned addr, uint8 data);
uint8 chr_read(uint16 addr);
void chr_write(uint16 addr, uint8 data);
uint8 ciram_read(uint13 addr);
void ciram_write(uint13 addr, uint8 data);
uint8 chr_read(unsigned addr);
void chr_write(unsigned addr, uint8 data);
unsigned ram_size();
uint8* ram_data();
@ -46,11 +43,9 @@ private:
uint12 divider;
uint4 cycle;
uint4 output;
int16 dac[16];
void clock();
void serialize(serializer&);
Pulse();
} pulse1, pulse2;
struct Sawtooth {
@ -59,14 +54,13 @@ private:
uint12 frequency;
uint12 divider;
uint4 phase;
uint1 phase;
uint3 stage;
uint8 accumulator;
uint5 output;
int16 dac[32];
void clock();
void serialize(serializer&);
Sawtooth();
} sawtooth;
unsigned ciram_addr(unsigned addr) const;

View File

@ -114,10 +114,10 @@ uint8 PPU::read(uint16 addr) {
status.bus_data = cartridge.chr_read(addr);
} else if(addr <= 0x3eff) {
result = status.bus_data;
status.bus_data = cartridge.ciram_read(addr);
status.bus_data = cartridge.chr_read(addr);
} else if(addr <= 0x3fff) {
result = cgram_read(addr);
status.bus_data = cartridge.ciram_read(addr);
status.bus_data = cartridge.chr_read(addr);
}
status.vaddr += status.vram_increment;
break;
@ -179,7 +179,7 @@ void PPU::write(uint16 addr, uint8 data) {
if(addr <= 0x1fff) {
cartridge.chr_write(addr, data);
} else if(addr <= 0x3eff) {
cartridge.ciram_write(addr, data);
cartridge.chr_write(addr, data);
} else if(addr <= 0x3fff) {
cgram_write(addr, data);
}
@ -244,11 +244,6 @@ uint8 PPU::chr_load(uint16 addr) {
return cartridge.chr_read(addr);
}
uint8 PPU::ciram_load(uint16 addr) {
if(raster_enable() == false) return 0x00;
return cartridge.ciram_read(addr);
}
//
void PPU::ly_increment() {
@ -295,6 +290,7 @@ void PPU::raster_pixel(unsigned x) {
palette |= (attr & 3) << 2;
}
if(status.bg_enable == false) palette = 0;
if(status.bg_edge_enable == false && status.lx < 8) palette = 0;
for(signed sprite = 7; sprite >= 0; sprite--) {
@ -367,7 +363,7 @@ void PPU::raster_scanline() {
}
for(unsigned tile = 0; tile < 32; tile++) { // 0-255
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff));
unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7);
raster_pixel(0);
tick();
@ -375,7 +371,7 @@ void PPU::raster_scanline() {
raster_pixel(1);
tick();
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
if(scrolly() & 16) attribute >>= 4;
if(scrollx() & 16) attribute >>= 2;
raster_pixel(2);
@ -411,13 +407,13 @@ void PPU::raster_scanline() {
for(unsigned n = 0; n < 8; n++) raster.oam[n] = raster.soam[n];
for(unsigned sprite = 0; sprite < 8; sprite++) { //256-319
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff));
tick();
if(raster_enable() && sprite == 0) status.vaddr = (status.vaddr & 0x7be0) | (status.taddr & 0x041f); //257
tick();
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
unsigned tileaddr = (sprite_height() == 8)
? status.sprite_addr + raster.oam[sprite].tile * 16
: ((raster.oam[sprite].tile & ~1) * 16) + ((raster.oam[sprite].tile & 1) * 0x1000);
@ -441,12 +437,12 @@ void PPU::raster_scanline() {
}
for(unsigned tile = 0; tile < 2; tile++) { //320-335
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff));
unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7);
tick();
tick();
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
if(scrolly() & 16) attribute >>= 4;
if(scrollx() & 16) attribute >>= 2;
tick();
@ -469,11 +465,11 @@ void PPU::raster_scanline() {
}
//336-339
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff));
tick();
tick();
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
tick();
tick();
@ -483,107 +479,4 @@ void PPU::raster_scanline() {
return ly_increment();
}
#if 0
//scanline-based PPU renderer
void PPU::raster_scanline() {
if(raster_enable() == false || (status.ly >= 240 && status.ly <= 260)) {
return tick(341);
}
uint32 *line = buffer + status.ly * 256;
uint8 ioam[8][5];
unsigned oamc = 0;
unsigned sprite_height = status.sprite_size ? 16 : 8;
for(unsigned n = 0; n < 64; n++) {
unsigned y = oam[(n * 4) + 0] + 1;
if(status.ly < y || status.ly >= y + sprite_height) continue;
ioam[oamc][0] = y;
ioam[oamc][1] = oam[(n * 4) + 1];
ioam[oamc][2] = oam[(n * 4) + 2];
ioam[oamc][3] = oam[(n * 4) + 3];
ioam[oamc][4] = n;
if(++oamc >= 8) break;
}
for(unsigned x = 0; x < 256; x++) {
uint8 tile = cartridge.chr_read(0x2000 | (status.vaddr & 0x1fff));
uint8 attr = cartridge.chr_read(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
if(scrollx() & 16) attr >>= 2;
if(scrolly() & 16) attr >>= 4;
unsigned tilex = (scrollx() + x) & 7;
uint8 tdlo = cartridge.chr_read(status.bg_addr + (tile << 4) + 0 + (scrolly() & 7));
uint8 tdhi = cartridge.chr_read(status.bg_addr + (tile << 4) + 8 + (scrolly() & 7));
if(tilex == 7) scrollx_increment();
unsigned mask = 0x80 >> tilex;
unsigned palette = 0;
if(status.bg_enable) {
if(status.bg_edge_enable == true || x >= 8) {
palette |= (tdlo & mask) ? 1 : 0;
palette |= (tdhi & mask) ? 2 : 0;
if(palette) palette |= (attr & 3) << 2;
}
}
for(unsigned n = 0; n < oamc; n++) {
if(x < ioam[n][3] || x >= ioam[n][3] + 8) continue;
if(status.sprite_enable == false) continue;
if(status.sprite_edge_enable == false && x < 8) continue;
unsigned spritex = x - ioam[n][3];
unsigned spritey = status.ly - ioam[n][0];
unsigned addr = (sprite_height == 8)
? status.sprite_addr + ioam[n][1] * 16
: ((ioam[n][1] & ~1) * 16) + ((ioam[n][1] & 1) * 0x1000);
if(ioam[n][2] & 0x80) spritey ^= (sprite_height - 1);
if(ioam[n][2] & 0x40) spritex ^= 7;
if(spritey & 8) spritey += 8;
tdlo = cartridge.chr_read(addr + 0 + spritey);
tdhi = cartridge.chr_read(addr + 8 + spritey);
mask = 0x80 >> spritex;
unsigned sprite_palette = 0;
sprite_palette |= (tdlo & mask) ? 1 : 0;
sprite_palette |= (tdhi & mask) ? 2 : 0;
if(sprite_palette == 0) continue;
if(ioam[n][4] == 0) status.sprite_zero_hit = 1;
sprite_palette |= (ioam[n][2] & 3) << 2;
bool priority = ioam[n][2] & 0x20;
if(priority == 0 || palette == 0) palette = 16 + sprite_palette;
break;
}
*line++ = paletteRGB[cgram[palette]];
}
if(status.ly != 261) scrolly_increment();
tick(257); //257
if(raster_enable()) {
status.vaddr = (status.vaddr & 0x7be0) | (status.taddr & 0x041f);
}
tick(47); //304
if(status.ly == 261) status.vaddr = status.taddr;
tick(37); //341
}
#endif
}

View File

@ -25,7 +25,6 @@ struct PPU : Processor {
unsigned sprite_height() const;
uint8 chr_load(uint16 addr);
uint8 ciram_load(uint16 addr);
void ly_increment();
void scrollx_increment();

View File

@ -14,8 +14,8 @@ void Filter::render(const uint16_t *input, unsigned inputPitch, unsigned inputWi
}
Filter::Filter() {
data = new uint16_t[1024 * 1024];
pitch = 1024 * sizeof(uint16_t);
data = new uint16_t[2048 * 2048];
pitch = 2048 * sizeof(uint16_t);
}
Filter::~Filter() {

View File

@ -41,7 +41,7 @@ Application::Application(int argc, char **argv) {
inputManager = new InputManager;
utility = new Utility;
title = "bsnes v082.22";
title = "bsnes v082.23";
#if defined(PLATFORM_WIN)
normalFont = "Tahoma, 8";