mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-02-23 22:52:34 +01:00
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.
249 lines
6.3 KiB
C++
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);
|
|
}
|
|
}
|