2015-11-16 08:38:05 +00:00
|
|
|
auto APU::Square1::runsweep(bool update) -> void {
|
|
|
|
if(!sweep.enable) return;
|
2012-04-06 04:29:50 +00:00
|
|
|
|
|
|
|
sweep.negate = sweep.direction;
|
2015-11-16 08:38:05 +00:00
|
|
|
uint delta = shadowfrequency >> sweep.shift;
|
|
|
|
int updatefrequency = shadowfrequency + (sweep.negate ? -delta : delta);
|
2012-04-06 04:29:50 +00:00
|
|
|
|
|
|
|
if(updatefrequency > 2047) {
|
|
|
|
enable = false;
|
|
|
|
} else if(sweep.shift && update) {
|
|
|
|
shadowfrequency = updatefrequency;
|
|
|
|
frequency = updatefrequency;
|
2013-12-10 12:12:54 +00:00
|
|
|
period = 2 * (2048 - frequency);
|
2012-04-06 04:29:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 08:38:05 +00:00
|
|
|
auto APU::Square1::clocksweep() -> void {
|
2012-04-06 04:29:50 +00:00
|
|
|
if(enable && sweep.frequency && --sweep.period == 0) {
|
|
|
|
sweep.period = sweep.frequency;
|
|
|
|
runsweep(1);
|
|
|
|
runsweep(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 08:38:05 +00:00
|
|
|
auto APU::Square1::read(uint addr) const -> uint8 {
|
2012-04-06 04:29:50 +00:00
|
|
|
switch(addr) {
|
|
|
|
case 0: return (sweep.shift << 0) | (sweep.direction << 3) | (sweep.frequency << 4);
|
2015-11-14 00:52:51 +00:00
|
|
|
case 1: return (duty << 6);
|
2012-04-06 04:29:50 +00:00
|
|
|
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
|
2015-11-14 00:52:51 +00:00
|
|
|
case 3: return 0;
|
|
|
|
case 4: return (counter << 6);
|
2012-04-06 04:29:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 08:38:05 +00:00
|
|
|
auto APU::Square1::write(uint addr, uint8 byte) -> void {
|
2012-04-06 04:29:50 +00:00
|
|
|
switch(addr) {
|
|
|
|
case 0: //NR10
|
|
|
|
if(sweep.negate && sweep.direction && !(byte & 0x08)) enable = false;
|
|
|
|
sweep.shift = byte >> 0;
|
|
|
|
sweep.direction = byte >> 3;
|
|
|
|
sweep.frequency = byte >> 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: //NR11
|
|
|
|
length = byte >> 0;
|
|
|
|
duty = byte >> 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: //NR12
|
|
|
|
envelope.frequency = byte >> 0;
|
|
|
|
envelope.direction = byte >> 3;
|
|
|
|
envelope.volume = byte >> 4;
|
2015-11-16 08:38:05 +00:00
|
|
|
if(!envelope.dacEnable()) enable = false;
|
2012-04-06 04:29:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: //NR13
|
|
|
|
frequency = (frequency & 0xff00) | (byte << 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: //NR14
|
|
|
|
frequency = (frequency & 0x00ff) | (byte << 8);
|
|
|
|
counter = byte >> 6;
|
|
|
|
initialize = byte >> 7;
|
|
|
|
|
|
|
|
if(initialize) {
|
2015-11-16 08:38:05 +00:00
|
|
|
enable = envelope.dacEnable();
|
2013-12-10 12:12:54 +00:00
|
|
|
period = 2 * (2048 - frequency);
|
2012-04-06 04:29:50 +00:00
|
|
|
envelope.period = envelope.frequency;
|
|
|
|
volume = envelope.volume;
|
|
|
|
shadowfrequency = frequency;
|
|
|
|
sweep.period = sweep.frequency;
|
|
|
|
sweep.enable = sweep.period || sweep.shift;
|
|
|
|
sweep.negate = false;
|
|
|
|
if(sweep.shift) runsweep(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 08:38:05 +00:00
|
|
|
auto APU::Square1::power() -> void {
|
2012-04-06 04:29:50 +00:00
|
|
|
envelope.frequency = 0;
|
|
|
|
envelope.direction = 0;
|
|
|
|
envelope.direction = 0;
|
|
|
|
envelope.period = 0;
|
|
|
|
sweep.shift = 0;
|
|
|
|
sweep.direction = 0;
|
|
|
|
sweep.frequency = 0;
|
|
|
|
sweep.enable = 0;
|
|
|
|
sweep.negate = 0;
|
|
|
|
sweep.period = 0;
|
|
|
|
enable = 0;
|
|
|
|
length = 0;
|
|
|
|
duty = 0;
|
|
|
|
frequency = 0;
|
|
|
|
counter = 0;
|
|
|
|
initialize = 0;
|
|
|
|
shadowfrequency = 0;
|
|
|
|
signal = 0;
|
|
|
|
output = 0;
|
|
|
|
period = 0;
|
|
|
|
phase = 0;
|
|
|
|
volume = 0;
|
|
|
|
}
|