bsnes/higan/ws/apu/io.cpp
Tim Allen a7f7985581 Update to v097r26 release.
byuu says:

Changelog:
- WS: fixed 8-bit sign-extended imul (fixes Star Hearts completely,
  Final Fantasy world map)
- WS: fixed rcl/rcr carry shifting (fixes Crazy Climber, others)
- WS: added sound DMA emulation (Star Hearts rain sound for one example)
- WS: added OAM caching, but it's forced every line for now because
  otherwise there are too many sprite glitches
- WS: use headphoneEnable bit instead of speakerEnable bit (fixes muted
  audio in games)
- WS: various code cleanups (I/O mapping, audio channel naming, etc)

The hypervoice channel doesn't sound all that great just yet. But I'm
not sure how it's supposed to sound. I need a better example of some
more complex music.

What's left are some unknown register status bits (especially in the
sound area), keypad interrupts, RTC emulation, CPU prefetch emulation.
And then it's all just bugs. Lots and lots of bugs that need to be
fixed.

EDIT: oops, bad typo in the code.

ws/ppu/ppu.cpp line 20: change range(256) to range(224).

Also, delete the r.speed stuff from channel5.cpp to make the rain sound
a lot better in Star Hearts. Apparently that's outdated and not what the
bits really do.
2016-03-17 22:28:15 +11:00

249 lines
6.3 KiB
C++

auto APU::portRead(uint16 addr) -> uint8 {
//SDMA_SRC
if(addr == 0x004a) return dma.s.source.bits( 0, 7);
if(addr == 0x004b) return dma.s.source.bits( 8,15);
if(addr == 0x004c) return dma.s.source.bits(16,19);
//SDMA_LEN
if(addr == 0x004e) return dma.s.length.bits( 0, 7);
if(addr == 0x004f) return dma.s.length.bits( 8,15);
if(addr == 0x0050) return dma.s.length.bits(16,19);
//SDMA_CTRL
if(addr == 0x0052) return (
dma.r.rate << 0
| dma.r.unknown << 2
| dma.r.loop << 3
| dma.r.target << 4
| dma.r.direction << 6
| dma.r.enable << 7
);
//SND_HYPER_CTRL
if(addr == 0x006a) return (
channel5.r.volume << 0
| channel5.r.scale << 2
| channel5.r.speed << 4
| channel5.r.enable << 7
);
//SND_HYPER_CHAN_CTRL
if(addr == 0x006b) return (
channel5.r.unknown << 0
| channel5.r.leftEnable << 5
| channel5.r.rightEnable << 6
);
//SND_CH1_PITCH
if(addr == 0x0080) return channel1.r.pitch.bits(0, 7);
if(addr == 0x0081) return channel1.r.pitch.bits(8,11);
//SND_CH2_PITCH
if(addr == 0x0082) return channel2.r.pitch.bits(0, 7);
if(addr == 0x0083) return channel2.r.pitch.bits(8,11);
//SND_CH3_PITCH
if(addr == 0x0084) return channel3.r.pitch.bits(0, 7);
if(addr == 0x0085) return channel3.r.pitch.bits(8,11);
//SND_CH4_PITCH
if(addr == 0x0086) return channel4.r.pitch.bits(0, 7);
if(addr == 0x0087) return channel4.r.pitch.bits(8,11);
//SND_CH1_VOL
if(addr == 0x0088) return (
channel1.r.volumeRight << 0
| channel1.r.volumeLeft << 4
);
//SND_CH2_VOL
if(addr == 0x0089) return (
channel2.r.volumeRight << 0
| channel2.r.volumeLeft << 4
);
//SND_CH3_VOL
if(addr == 0x008a) return (
channel3.r.volumeRight << 0
| channel3.r.volumeLeft << 4
);
//SND_CH4_VOL
if(addr == 0x008b) return (
channel4.r.volumeRight << 0
| channel4.r.volumeLeft << 4
);
//SND_SWEEP_VALUE
if(addr == 0x008c) return channel3.r.sweepValue;
//SND_SWEEP_TIME
if(addr == 0x008d) return channel3.r.sweepTime;
//SND_NOISE
//(noiseReset [bit 3] always reads as zero)
if(addr == 0x008e) return (
channel4.r.noiseMode << 0
| channel4.r.noiseUpdate << 4
);
//SND_WAVE_BASE
if(addr == 0x008f) return r.waveBase;
//SND_CTRL
if(addr == 0x0090) return (
channel1.r.enable << 0
| channel2.r.enable << 1
| channel3.r.enable << 2
| channel4.r.enable << 3
| channel2.r.voice << 5
| channel3.r.sweep << 6
| channel4.r.noise << 7
);
//SND_OUTPUT
if(addr == 0x0091) return (
r.speakerEnable << 0
| r.speakerShift << 1
| r.headphoneEnable << 3
| 1 << 7 //headphone connected
);
//SND_RANDOM
if(addr == 0x0092) return channel4.s.noiseLFSR.bits(0, 7);
if(addr == 0x0093) return channel4.s.noiseLFSR.bits(8,14);
//SND_VOICE_CTRL
if(addr == 0x0094) return (
channel2.r.voiceEnableRight << 0
| channel2.r.voiceEnableLeft << 2
);
//SND_HYPERVOICE
if(addr == 0x0095) return channel5.s.data;
return 0x00;
}
auto APU::portWrite(uint16 addr, uint8 data) -> void {
//SDMA_SRC
if(addr == 0x004a) dma.r.source.bits( 0, 7) = data.bits(0,7);
if(addr == 0x004b) dma.r.source.bits( 8,15) = data.bits(0,7);
if(addr == 0x004c) dma.r.source.bits(16,19) = data.bits(0,3);
//SDMA_LEN
if(addr == 0x004e) dma.r.length.bits( 0, 7) = data.bits(0,7);
if(addr == 0x004f) dma.r.length.bits( 8,15) = data.bits(0,7);
if(addr == 0x0050) dma.r.length.bits(16,19) = data.bits(0,3);
//SDMA_CTRL
if(addr == 0x0052) {
bool trigger = !dma.r.enable && data.bit(7);
dma.r.rate = data.bits(0,1);
dma.r.unknown = data.bit (2);
dma.r.loop = data.bit (3);
dma.r.target = data.bit (4);
dma.r.direction = data.bit (6);
dma.r.enable = data.bit (7);
if(trigger) {
dma.s.source = dma.r.source;
dma.s.length = dma.r.length;
}
}
//SND_HYPER_CTRL
if(addr == 0x006a) {
channel5.r.volume = data.bits(0,1);
channel5.r.scale = data.bits(2,3);
channel5.r.speed = data.bits(4,6);
channel5.r.enable = data.bit (7);
}
//SND_HYPER_CHAN_CTRL
if(addr == 0x006b) {
channel5.r.unknown = data.bits(0,3);
channel5.r.leftEnable = data.bit (5);
channel5.r.rightEnable = data.bit (6);
}
//SND_CH1_PITCH
if(addr == 0x0080) channel1.r.pitch.bits(0, 7) = data.bits(0,7);
if(addr == 0x0081) channel1.r.pitch.bits(8,11) = data.bits(0,3);
//SND_CH2_PITCH
if(addr == 0x0082) channel2.r.pitch.bits(0, 7) = data.bits(0,7);
if(addr == 0x0083) channel2.r.pitch.bits(8,11) = data.bits(0,3);
//SND_CH3_PITCH
if(addr == 0x0084) channel3.r.pitch.bits(0, 7) = data.bits(0,7);
if(addr == 0x0085) channel3.r.pitch.bits(8,11) = data.bits(0,3);
//SND_CH4_PITCH
if(addr == 0x0086) channel4.r.pitch.bits(0, 7) = data.bits(0,7);
if(addr == 0x0087) channel4.r.pitch.bits(8,11) = data.bits(0,3);
//SND_CH1_VOL
if(addr == 0x0088) {
channel1.r.volumeRight = data.bits(0,3);
channel1.r.volumeLeft = data.bits(4,7);
}
//SND_CH2_VOL
if(addr == 0x0089) {
channel2.r.volumeRight = data.bits(0,3);
channel2.r.volumeLeft = data.bits(4,7);
}
//SND_CH3_VOL
if(addr == 0x008a) {
channel3.r.volumeRight = data.bits(0,3);
channel3.r.volumeLeft = data.bits(4,7);
}
//SND_CH4_VOL
if(addr == 0x008b) {
channel4.r.volumeRight = data.bits(0,3);
channel4.r.volumeLeft = data.bits(4,7);
}
//SND_SWEEP_VALUE
if(addr == 0x008c) channel3.r.sweepValue = data;
//SND_SWEEP_TIME
if(addr == 0x008d) channel3.r.sweepTime = data.bits(0,4);
//SND_NOISE
if(addr == 0x008e) {
channel4.r.noiseMode = data.bits(0,2);
channel4.r.noiseReset = data.bit (3);
channel4.r.noiseUpdate = data.bit (4);
}
//SND_WAVE_BASE
if(addr == 0x008f) r.waveBase = data;
//SND_CTRL
if(addr == 0x0090) {
channel1.r.enable = data.bit(0);
channel2.r.enable = data.bit(1);
channel3.r.enable = data.bit(2);
channel4.r.enable = data.bit(3);
channel2.r.voice = data.bit(5);
channel3.r.sweep = data.bit(6);
channel4.r.noise = data.bit(7);
}
//SND_OUTPUT
if(addr == 0x0091) {
r.speakerEnable = data.bit (0);
r.speakerShift = data.bits(1,2);
r.headphoneEnable = data.bit (3);
}
//SND_VOICE_CTRL
if(addr == 0x0094) {
channel2.r.voiceEnableRight = data.bits(0,1);
channel2.r.voiceEnableLeft = data.bits(2,3);
}
}