2011-10-01 12:06:48 +00:00
|
|
|
struct VRC6 : Chip {
|
2015-12-05 05:44:49 +00:00
|
|
|
VRC6(Board& board) : Chip(board) {
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Pulse {
|
|
|
|
auto clock() -> void {
|
|
|
|
if(--divider == 0) {
|
|
|
|
divider = frequency + 1;
|
|
|
|
cycle++;
|
|
|
|
output = (mode == 1 || cycle > duty) ? volume : (uint4)0;
|
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
if(enable == false) output = 0;
|
2011-10-01 12:06:48 +00:00
|
|
|
}
|
2011-09-26 11:27:06 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto serialize(serializer& s) -> void {
|
|
|
|
s.integer(mode);
|
|
|
|
s.integer(duty);
|
|
|
|
s.integer(volume);
|
|
|
|
s.integer(enable);
|
|
|
|
s.integer(frequency);
|
2011-09-26 11:27:06 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
s.integer(divider);
|
|
|
|
s.integer(cycle);
|
|
|
|
s.integer(output);
|
|
|
|
}
|
2011-09-26 11:27:06 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
bool mode;
|
|
|
|
uint3 duty;
|
|
|
|
uint4 volume;
|
|
|
|
bool enable;
|
|
|
|
uint12 frequency;
|
|
|
|
|
|
|
|
uint12 divider;
|
|
|
|
uint4 cycle;
|
|
|
|
uint4 output;
|
|
|
|
} pulse1, pulse2;
|
|
|
|
|
|
|
|
struct Sawtooth {
|
|
|
|
auto clock() -> void {
|
|
|
|
if(--divider == 0) {
|
|
|
|
divider = frequency + 1;
|
|
|
|
if(++phase == 0) {
|
|
|
|
accumulator += rate;
|
|
|
|
if(++stage == 7) {
|
|
|
|
stage = 0;
|
|
|
|
accumulator = 0;
|
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
}
|
2011-09-26 11:38:57 +00:00
|
|
|
}
|
2015-12-05 05:44:49 +00:00
|
|
|
|
|
|
|
output = accumulator >> 3;
|
|
|
|
if(enable == false) output = 0;
|
2011-09-26 11:27:06 +00:00
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto serialize(serializer& s) -> void {
|
|
|
|
s.integer(rate);
|
|
|
|
s.integer(enable);
|
|
|
|
s.integer(frequency);
|
2011-09-26 11:27:06 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
s.integer(divider);
|
|
|
|
s.integer(phase);
|
|
|
|
s.integer(stage);
|
|
|
|
s.integer(accumulator);
|
|
|
|
s.integer(output);
|
|
|
|
}
|
2011-10-01 12:06:48 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
uint6 rate;
|
|
|
|
bool enable;
|
|
|
|
uint12 frequency;
|
|
|
|
|
|
|
|
uint12 divider;
|
|
|
|
uint1 phase;
|
|
|
|
uint3 stage;
|
|
|
|
uint8 accumulator;
|
|
|
|
uint5 output;
|
|
|
|
} sawtooth;
|
|
|
|
|
|
|
|
auto main() -> void {
|
2016-02-09 11:51:12 +00:00
|
|
|
if(irq_enable) {
|
|
|
|
if(irq_mode == 0) {
|
|
|
|
irq_scalar -= 3;
|
|
|
|
if(irq_scalar <= 0) {
|
|
|
|
irq_scalar += 341;
|
2011-09-26 11:27:06 +00:00
|
|
|
if(irq_counter == 0xff) {
|
|
|
|
irq_counter = irq_latch;
|
|
|
|
irq_line = 1;
|
|
|
|
} else {
|
|
|
|
irq_counter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-09 11:51:12 +00:00
|
|
|
if(irq_mode == 1) {
|
|
|
|
if(irq_counter == 0xff) {
|
|
|
|
irq_counter = irq_latch;
|
|
|
|
irq_line = 1;
|
|
|
|
} else {
|
|
|
|
irq_counter++;
|
|
|
|
}
|
|
|
|
}
|
2011-09-26 11:27:06 +00:00
|
|
|
}
|
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_line);
|
2016-02-09 11:51:12 +00:00
|
|
|
|
|
|
|
pulse1.clock();
|
|
|
|
pulse2.clock();
|
|
|
|
sawtooth.clock();
|
|
|
|
int output = (pulse1.output + pulse2.output + sawtooth.output) << 7;
|
|
|
|
apu.set_sample(-output);
|
|
|
|
|
|
|
|
tick();
|
2015-12-05 05:44:49 +00:00
|
|
|
}
|
2011-09-26 11:27:06 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto prg_addr(uint addr) const -> uint {
|
|
|
|
if((addr & 0xc000) == 0x8000) return (prg_bank[0] << 14) | (addr & 0x3fff);
|
|
|
|
if((addr & 0xe000) == 0xc000) return (prg_bank[1] << 13) | (addr & 0x1fff);
|
|
|
|
if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff);
|
|
|
|
}
|
2011-09-26 11:27:06 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto chr_addr(uint addr) const -> uint {
|
|
|
|
uint bank = chr_bank[(addr >> 10) & 7];
|
|
|
|
return (bank << 10) | (addr & 0x03ff);
|
2011-09-26 11:27:06 +00:00
|
|
|
}
|
2015-12-05 05:44:49 +00:00
|
|
|
|
|
|
|
auto ciram_addr(uint addr) const -> uint {
|
|
|
|
switch(mirror) {
|
|
|
|
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
|
|
|
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
|
|
|
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
|
|
|
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
|
|
|
}
|
2011-09-26 11:27:06 +00:00
|
|
|
}
|
2015-12-05 05:44:49 +00:00
|
|
|
|
|
|
|
auto ram_read(uint addr) -> uint8 {
|
|
|
|
return board.prgram.data[addr & 0x1fff];
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ram_write(uint addr, uint8 data) -> void {
|
|
|
|
board.prgram.data[addr & 0x1fff] = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto reg_write(uint addr, uint8 data) -> void {
|
|
|
|
switch(addr) {
|
|
|
|
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
|
|
|
prg_bank[0] = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x9000:
|
|
|
|
pulse1.mode = data & 0x80;
|
|
|
|
pulse1.duty = (data & 0x70) >> 4;
|
|
|
|
pulse1.volume = data & 0x0f;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x9001:
|
|
|
|
pulse1.frequency = (pulse1.frequency & 0x0f00) | ((data & 0xff) << 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x9002:
|
|
|
|
pulse1.frequency = (pulse1.frequency & 0x00ff) | ((data & 0x0f) << 8);
|
|
|
|
pulse1.enable = data & 0x80;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xa000:
|
|
|
|
pulse2.mode = data & 0x80;
|
|
|
|
pulse2.duty = (data & 0x70) >> 4;
|
|
|
|
pulse2.volume = data & 0x0f;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xa001:
|
|
|
|
pulse2.frequency = (pulse2.frequency & 0x0f00) | ((data & 0xff) << 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xa002:
|
|
|
|
pulse2.frequency = (pulse2.frequency & 0x00ff) | ((data & 0x0f) << 8);
|
|
|
|
pulse2.enable = data & 0x80;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xb000:
|
|
|
|
sawtooth.rate = data & 0x3f;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xb001:
|
|
|
|
sawtooth.frequency = (sawtooth.frequency & 0x0f00) | ((data & 0xff) << 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xb002:
|
|
|
|
sawtooth.frequency = (sawtooth.frequency & 0x00ff) | ((data & 0x0f) << 8);
|
|
|
|
sawtooth.enable = data & 0x80;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xb003:
|
|
|
|
mirror = (data >> 2) & 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xc000: case 0xc001: case 0xc002: case 0xc003:
|
|
|
|
prg_bank[1] = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xd000: case 0xd001: case 0xd002: case 0xd003:
|
|
|
|
chr_bank[0 + (addr & 3)] = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xe000: case 0xe001: case 0xe002: case 0xe003:
|
|
|
|
chr_bank[4 + (addr & 3)] = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf000:
|
|
|
|
irq_latch = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf001:
|
|
|
|
irq_mode = data & 0x04;
|
|
|
|
irq_enable = data & 0x02;
|
|
|
|
irq_acknowledge = data & 0x01;
|
|
|
|
if(irq_enable) {
|
|
|
|
irq_counter = irq_latch;
|
|
|
|
irq_scalar = 341;
|
|
|
|
}
|
|
|
|
irq_line = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf002:
|
|
|
|
irq_enable = irq_acknowledge;
|
|
|
|
irq_line = 0;
|
|
|
|
break;
|
2011-09-26 11:27:06 +00:00
|
|
|
}
|
2015-12-05 05:44:49 +00:00
|
|
|
}
|
2011-09-26 11:27:06 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto power() -> void {
|
|
|
|
}
|
|
|
|
|
|
|
|
auto reset() -> void {
|
|
|
|
prg_bank[0] = 0;
|
|
|
|
prg_bank[1] = 0;
|
|
|
|
chr_bank[0] = 0;
|
|
|
|
chr_bank[1] = 0;
|
|
|
|
chr_bank[2] = 0;
|
|
|
|
chr_bank[3] = 0;
|
|
|
|
chr_bank[4] = 0;
|
|
|
|
chr_bank[5] = 0;
|
|
|
|
chr_bank[6] = 0;
|
|
|
|
chr_bank[7] = 0;
|
|
|
|
mirror = 0;
|
|
|
|
irq_latch = 0;
|
|
|
|
irq_mode = 0;
|
|
|
|
irq_enable = 0;
|
|
|
|
irq_acknowledge = 0;
|
|
|
|
|
|
|
|
irq_counter = 0;
|
|
|
|
irq_scalar = 0;
|
2011-09-26 11:27:06 +00:00
|
|
|
irq_line = 0;
|
2015-12-05 05:44:49 +00:00
|
|
|
|
|
|
|
pulse1.mode = 0;
|
|
|
|
pulse1.duty = 0;
|
|
|
|
pulse1.volume = 0;
|
|
|
|
pulse1.enable = 0;
|
|
|
|
pulse1.frequency = 0;
|
|
|
|
|
|
|
|
pulse1.divider = 1;
|
|
|
|
pulse1.cycle = 0;
|
|
|
|
pulse1.output = 0;
|
|
|
|
|
|
|
|
pulse2.mode = 0;
|
|
|
|
pulse2.duty = 0;
|
|
|
|
pulse2.volume = 0;
|
|
|
|
pulse2.enable = 0;
|
|
|
|
pulse2.frequency = 0;
|
|
|
|
|
|
|
|
pulse2.divider = 1;
|
|
|
|
pulse2.cycle = 0;
|
|
|
|
pulse2.output = 0;
|
|
|
|
|
|
|
|
sawtooth.rate = 0;
|
|
|
|
sawtooth.enable = 0;
|
|
|
|
sawtooth.frequency = 0;
|
|
|
|
|
|
|
|
sawtooth.divider = 1;
|
|
|
|
sawtooth.phase = 0;
|
|
|
|
sawtooth.stage = 0;
|
|
|
|
sawtooth.accumulator = 0;
|
|
|
|
sawtooth.output = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto serialize(serializer& s) -> void {
|
|
|
|
pulse1.serialize(s);
|
|
|
|
pulse2.serialize(s);
|
|
|
|
sawtooth.serialize(s);
|
|
|
|
|
|
|
|
s.array(prg_bank);
|
|
|
|
s.array(chr_bank);
|
|
|
|
s.integer(mirror);
|
|
|
|
s.integer(irq_latch);
|
|
|
|
s.integer(irq_mode);
|
|
|
|
s.integer(irq_enable);
|
|
|
|
s.integer(irq_acknowledge);
|
|
|
|
|
|
|
|
s.integer(irq_counter);
|
|
|
|
s.integer(irq_scalar);
|
|
|
|
s.integer(irq_line);
|
2011-09-26 11:27:06 +00:00
|
|
|
}
|
2011-09-26 11:38:57 +00:00
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
uint8 prg_bank[2];
|
|
|
|
uint8 chr_bank[8];
|
|
|
|
uint2 mirror;
|
|
|
|
uint8 irq_latch;
|
|
|
|
bool irq_mode;
|
|
|
|
bool irq_enable;
|
|
|
|
bool irq_acknowledge;
|
|
|
|
|
|
|
|
uint8 irq_counter;
|
|
|
|
int irq_scalar;
|
|
|
|
bool irq_line;
|
2011-10-01 12:06:48 +00:00
|
|
|
};
|