2011-10-05 09:37:00 +00:00
|
|
|
//SUNSOFT-5B
|
|
|
|
|
|
|
|
struct Sunsoft5B : Board {
|
2015-12-05 05:44:49 +00:00
|
|
|
Sunsoft5B(Markup::Node& document) : Board(document) {
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
struct Pulse {
|
|
|
|
auto clock() -> void {
|
|
|
|
if(--counter == 0) {
|
|
|
|
counter = frequency << 4;
|
|
|
|
duty ^= 1;
|
|
|
|
}
|
|
|
|
output = duty ? volume : (uint4)0;
|
|
|
|
if(disable) output = 0;
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto reset() -> void {
|
|
|
|
disable = 1;
|
|
|
|
frequency = 1;
|
|
|
|
volume = 0;
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
counter = 0;
|
|
|
|
duty = 0;
|
|
|
|
output = 0;
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto serialize(serializer& s) -> void {
|
|
|
|
s.integer(disable);
|
|
|
|
s.integer(frequency);
|
|
|
|
s.integer(volume);
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
s.integer(counter);
|
|
|
|
s.integer(duty);
|
|
|
|
s.integer(output);
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
bool disable;
|
|
|
|
uint12 frequency;
|
|
|
|
uint4 volume;
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
uint16 counter; //12-bit countdown + 4-bit phase
|
|
|
|
uint1 duty;
|
|
|
|
uint4 output;
|
|
|
|
} pulse[3];
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto main() -> void {
|
2016-02-09 11:51:12 +00:00
|
|
|
if(irq_counter_enable) {
|
|
|
|
if(--irq_counter == 0xffff) {
|
Update to v099r04 release.
byuu says:
Changelog:
- lots of code cleanups to processor/r6502 (the switch.cpp file is only
halfway done ...)
- lots of code cleanups to fc/cpu
- removed fc/input
- implemented fc/controller
hex_usr, you may not like this, but I want to keep the controller port
and expansion port interface separate, like I do with the SNES. I realize
the NES' is used more for controllers, and the SNES' more for hardware
expansions, but ... they're not compatible pinouts and you can't really
connect one to the other.
Right now, I've only implemented the controller portion. I'll have to
get to the peripheral portion later.
Also, the gamepad implementation there now may be wrong. It's based off
the Super Famicom version obviously. I'm not sure if the Famicom has
different behavior with latching $4016 writes, or not. But, it works in
Mega Man II, so it's a start.
Everyone, be sure to remap your controls, and then set port 1 -> gamepad
after loading your first Famicom game with the new WIP.
2016-06-18 06:04:32 +00:00
|
|
|
cpu.irqLine(irq_enable);
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
2016-02-09 11:51:12 +00:00
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2016-02-09 11:51:12 +00:00
|
|
|
pulse[0].clock();
|
|
|
|
pulse[1].clock();
|
|
|
|
pulse[2].clock();
|
|
|
|
int16 output = dac[pulse[0].output] + dac[pulse[1].output] + dac[pulse[2].output];
|
|
|
|
apu.set_sample(-output);
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2016-02-09 11:51:12 +00:00
|
|
|
tick();
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto prg_read(uint addr) -> uint8 {
|
|
|
|
if(addr < 0x6000) return cpu.mdr();
|
|
|
|
|
|
|
|
uint8 bank = 0x3f; //((addr & 0xe000) == 0xe000
|
|
|
|
if((addr & 0xe000) == 0x6000) bank = prg_bank[0];
|
|
|
|
if((addr & 0xe000) == 0x8000) bank = prg_bank[1];
|
|
|
|
if((addr & 0xe000) == 0xa000) bank = prg_bank[2];
|
|
|
|
if((addr & 0xe000) == 0xc000) bank = prg_bank[3];
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
bool ram_enable = bank & 0x80;
|
|
|
|
bool ram_select = bank & 0x40;
|
|
|
|
bank &= 0x3f;
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
if(ram_select) {
|
|
|
|
if(ram_enable == false) return cpu.mdr();
|
|
|
|
return prgram.data[addr & 0x1fff];
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
addr = (bank << 13) | (addr & 0x1fff);
|
|
|
|
return prgrom.read(addr);
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto prg_write(uint addr, uint8 data) -> void {
|
|
|
|
if((addr & 0xe000) == 0x6000) {
|
|
|
|
prgram.data[addr & 0x1fff] = data;
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
if(addr == 0x8000) {
|
|
|
|
mmu_port = data & 0x0f;
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
if(addr == 0xa000) {
|
|
|
|
switch(mmu_port) {
|
|
|
|
case 0: chr_bank[0] = data; break;
|
|
|
|
case 1: chr_bank[1] = data; break;
|
|
|
|
case 2: chr_bank[2] = data; break;
|
|
|
|
case 3: chr_bank[3] = data; break;
|
|
|
|
case 4: chr_bank[4] = data; break;
|
|
|
|
case 5: chr_bank[5] = data; break;
|
|
|
|
case 6: chr_bank[6] = data; break;
|
|
|
|
case 7: chr_bank[7] = data; break;
|
|
|
|
case 8: prg_bank[0] = data; break;
|
|
|
|
case 9: prg_bank[1] = data; break;
|
|
|
|
case 10: prg_bank[2] = data; break;
|
|
|
|
case 11: prg_bank[3] = data; break;
|
|
|
|
case 12: mirror = data & 3; break;
|
|
|
|
case 13:
|
|
|
|
irq_enable = data & 0x80;
|
|
|
|
irq_counter_enable = data & 0x01;
|
Update to v099r04 release.
byuu says:
Changelog:
- lots of code cleanups to processor/r6502 (the switch.cpp file is only
halfway done ...)
- lots of code cleanups to fc/cpu
- removed fc/input
- implemented fc/controller
hex_usr, you may not like this, but I want to keep the controller port
and expansion port interface separate, like I do with the SNES. I realize
the NES' is used more for controllers, and the SNES' more for hardware
expansions, but ... they're not compatible pinouts and you can't really
connect one to the other.
Right now, I've only implemented the controller portion. I'll have to
get to the peripheral portion later.
Also, the gamepad implementation there now may be wrong. It's based off
the Super Famicom version obviously. I'm not sure if the Famicom has
different behavior with latching $4016 writes, or not. But, it works in
Mega Man II, so it's a start.
Everyone, be sure to remap your controls, and then set port 1 -> gamepad
after loading your first Famicom game with the new WIP.
2016-06-18 06:04:32 +00:00
|
|
|
if(irq_enable == 0) cpu.irqLine(0);
|
2015-12-05 05:44:49 +00:00
|
|
|
break;
|
|
|
|
case 14: irq_counter = (irq_counter & 0xff00) | (data << 0); break;
|
|
|
|
case 15: irq_counter = (irq_counter & 0x00ff) | (data << 8); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xc000) {
|
|
|
|
apu_port = data & 0x0f;
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
if(addr == 0xe000) {
|
|
|
|
switch(apu_port) {
|
|
|
|
case 0: pulse[0].frequency = (pulse[0].frequency & 0xff00) | (data << 0); break;
|
|
|
|
case 1: pulse[0].frequency = (pulse[0].frequency & 0x00ff) | (data << 8); break;
|
|
|
|
case 2: pulse[1].frequency = (pulse[1].frequency & 0xff00) | (data << 0); break;
|
|
|
|
case 3: pulse[1].frequency = (pulse[1].frequency & 0x00ff) | (data << 8); break;
|
|
|
|
case 4: pulse[2].frequency = (pulse[2].frequency & 0xff00) | (data << 0); break;
|
|
|
|
case 5: pulse[2].frequency = (pulse[2].frequency & 0x00ff) | (data << 8); break;
|
|
|
|
case 7:
|
|
|
|
pulse[0].disable = data & 0x01;
|
|
|
|
pulse[1].disable = data & 0x02;
|
|
|
|
pulse[2].disable = data & 0x04;
|
|
|
|
break;
|
|
|
|
case 8: pulse[0].volume = data & 0x0f; break;
|
|
|
|
case 9: pulse[1].volume = data & 0x0f; break;
|
|
|
|
case 10: pulse[2].volume = data & 0x0f; break;
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto chr_addr(uint addr) -> uint {
|
|
|
|
uint8 bank = (addr >> 10) & 7;
|
|
|
|
return (chr_bank[bank] << 10) | (addr & 0x03ff);
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto ciram_addr(uint addr) -> uint {
|
|
|
|
switch(mirror) {
|
|
|
|
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical
|
|
|
|
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal
|
|
|
|
case 2: return 0x0000 | (addr & 0x03ff); //first
|
|
|
|
case 3: return 0x0400 | (addr & 0x03ff); //second
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-05 05:44:49 +00:00
|
|
|
|
|
|
|
auto chr_read(uint addr) -> uint8 {
|
2016-06-26 08:54:12 +00:00
|
|
|
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr));
|
2015-12-05 05:44:49 +00:00
|
|
|
return Board::chr_read(chr_addr(addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto chr_write(uint addr, uint8 data) -> void {
|
2016-06-26 08:54:12 +00:00
|
|
|
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data);
|
2015-12-05 05:44:49 +00:00
|
|
|
return Board::chr_write(chr_addr(addr), data);
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
2015-12-05 05:44:49 +00:00
|
|
|
|
|
|
|
auto power() -> void {
|
|
|
|
for(signed n : range(16)) {
|
|
|
|
double volume = 1.0 / pow(2, 1.0 / 2 * (15 - n));
|
|
|
|
dac[n] = volume * 8192.0;
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto reset() -> void {
|
|
|
|
mmu_port = 0;
|
|
|
|
apu_port = 0;
|
|
|
|
|
|
|
|
for(auto& n : prg_bank) n = 0;
|
|
|
|
for(auto& n : chr_bank) n = 0;
|
|
|
|
mirror = 0;
|
|
|
|
irq_enable = 0;
|
|
|
|
irq_counter_enable = 0;
|
|
|
|
irq_counter = 0;
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
pulse[0].reset();
|
|
|
|
pulse[1].reset();
|
|
|
|
pulse[2].reset();
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto serialize(serializer& s) -> void {
|
|
|
|
Board::serialize(s);
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
s.integer(mmu_port);
|
|
|
|
s.integer(apu_port);
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
s.array(prg_bank);
|
|
|
|
s.array(chr_bank);
|
|
|
|
s.integer(mirror);
|
|
|
|
s.integer(irq_enable);
|
|
|
|
s.integer(irq_counter_enable);
|
|
|
|
s.integer(irq_counter);
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
pulse[0].serialize(s);
|
|
|
|
pulse[1].serialize(s);
|
|
|
|
pulse[2].serialize(s);
|
|
|
|
}
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
uint4 mmu_port;
|
|
|
|
uint4 apu_port;
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
uint8 prg_bank[4];
|
|
|
|
uint8 chr_bank[8];
|
|
|
|
uint2 mirror;
|
|
|
|
bool irq_enable;
|
|
|
|
bool irq_counter_enable;
|
|
|
|
uint16 irq_counter;
|
2011-10-05 09:37:00 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
int16 dac[16];
|
2011-10-05 09:37:00 +00:00
|
|
|
};
|