mirror of https://github.com/bsnes-emu/bsnes.git
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.
This commit is contained in:
parent
b586471562
commit
a7f7985581
|
@ -6,7 +6,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "097.25";
|
static const string Version = "097.26";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -119,7 +119,7 @@ auto V30MZ::alRcl(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
uint16 result = x;
|
uint16 result = x;
|
||||||
for(uint n = 0; n < y; n++) {
|
for(uint n = 0; n < y; n++) {
|
||||||
bool carry = result & sign;
|
bool carry = result & sign;
|
||||||
result = (result << 1) | carry;
|
result = (result << 1) | r.f.c;
|
||||||
r.f.c = carry;
|
r.f.c = carry;
|
||||||
}
|
}
|
||||||
r.f.v = (x ^ result) & sign;
|
r.f.v = (x ^ result) & sign;
|
||||||
|
@ -130,7 +130,7 @@ auto V30MZ::alRcr(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
uint16 result = x;
|
uint16 result = x;
|
||||||
for(uint n = 0; n < y; n++) {
|
for(uint n = 0; n < y; n++) {
|
||||||
bool carry = result & 1;
|
bool carry = result & 1;
|
||||||
result = (carry ? sign : 0) | (result >> 1);
|
result = (r.f.c ? sign : 0) | (result >> 1);
|
||||||
r.f.c = carry;
|
r.f.c = carry;
|
||||||
}
|
}
|
||||||
r.f.v = (x ^ result) & sign;
|
r.f.v = (x ^ result) & sign;
|
||||||
|
|
|
@ -134,7 +134,7 @@ auto V30MZ::opTestMemReg(Size size) {
|
||||||
auto V30MZ::opMultiplySignedRegMemImm(Size size) {
|
auto V30MZ::opMultiplySignedRegMemImm(Size size) {
|
||||||
wait(2);
|
wait(2);
|
||||||
modRM();
|
modRM();
|
||||||
setReg(size, alMuli(size, getMem(size), size == Word ? (int16_t)fetch(Word) : (int8_t)fetch(Byte)));
|
setReg(Word, alMuli(Word, getMem(Word), size == Word ? (int16_t)fetch(Word) : (int8_t)fetch(Byte)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//40 inc ax
|
//40 inc ax
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Processor {
|
||||||
#include "disassembler.cpp"
|
#include "disassembler.cpp"
|
||||||
|
|
||||||
auto V30MZ::debug(string text) -> void {
|
auto V30MZ::debug(string text) -> void {
|
||||||
print(text, "\n");
|
//print(text, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::power() -> void {
|
auto V30MZ::power() -> void {
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
system name:WonderSwan Color
|
system name:WonderSwan Color
|
||||||
eeprom name=internal.rom size=2048
|
eeprom name=internal.ram size=2048
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
system name:WonderSwan
|
system name:WonderSwan
|
||||||
eeprom name=internal.rom size=128
|
eeprom name=internal.ram size=128
|
||||||
|
|
|
@ -4,56 +4,54 @@ namespace WonderSwan {
|
||||||
|
|
||||||
APU apu;
|
APU apu;
|
||||||
#include "io.cpp"
|
#include "io.cpp"
|
||||||
#include "channel.cpp"
|
#include "dma.cpp"
|
||||||
#include "channel0.cpp"
|
|
||||||
#include "channel1.cpp"
|
#include "channel1.cpp"
|
||||||
#include "channel2.cpp"
|
#include "channel2.cpp"
|
||||||
#include "channel3.cpp"
|
#include "channel3.cpp"
|
||||||
#include "channel4.cpp"
|
#include "channel4.cpp"
|
||||||
|
#include "channel5.cpp"
|
||||||
|
|
||||||
auto APU::Enter() -> void {
|
auto APU::Enter() -> void {
|
||||||
while(true) scheduler.synchronize(), apu.main();
|
while(true) scheduler.synchronize(), apu.main();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::main() -> void {
|
auto APU::main() -> void {
|
||||||
channel0.run();
|
dma.run();
|
||||||
channel1.run();
|
channel1.run();
|
||||||
channel2.run();
|
channel2.run();
|
||||||
channel3.run();
|
channel3.run();
|
||||||
|
channel4.run();
|
||||||
if(s.clock.bits(0,12) == 0) {
|
channel5.run();
|
||||||
channel2.sweep();
|
if(s.clock.bits(0,12) == 0) channel3.sweep();
|
||||||
}
|
if(s.clock.bits(0, 6) == 0) dacRun();
|
||||||
|
|
||||||
if(s.clock.bits(0,6) == 0) {
|
|
||||||
channel4.run();
|
|
||||||
dacRun();
|
|
||||||
}
|
|
||||||
|
|
||||||
s.clock++;
|
s.clock++;
|
||||||
step(1);
|
step(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto APU::sample(uint channel, uint5 index) -> uint4 {
|
||||||
|
uint8 data = iram.read((r.waveBase << 6) + (--channel << 4) + (index >> 1));
|
||||||
|
if(index.bit(0) == 0) return data.bits(0,3);
|
||||||
|
if(index.bit(0) == 1) return data.bits(4,7);
|
||||||
|
}
|
||||||
|
|
||||||
auto APU::dacRun() -> void {
|
auto APU::dacRun() -> void {
|
||||||
int left = 0;
|
int left = 0;
|
||||||
if(channel0.r.enable) left += channel0.o.left;
|
|
||||||
if(channel1.r.enable) left += channel1.o.left;
|
if(channel1.r.enable) left += channel1.o.left;
|
||||||
if(channel2.r.enable) left += channel2.o.left;
|
if(channel2.r.enable) left += channel2.o.left;
|
||||||
if(channel3.r.enable) left += channel3.o.left;
|
if(channel3.r.enable) left += channel3.o.left;
|
||||||
left = (left >> r.speakerShift) << 5;
|
|
||||||
if(channel4.r.enable) left += channel4.o.left;
|
if(channel4.r.enable) left += channel4.o.left;
|
||||||
left = sclamp<16>(left << 3);
|
if(channel5.r.enable) left += (int11)channel5.o.left >> 3;
|
||||||
|
left = sclamp<16>(left << 5);
|
||||||
|
|
||||||
int right = 0;
|
int right = 0;
|
||||||
if(channel0.r.enable) right += channel0.o.right;
|
|
||||||
if(channel1.r.enable) right += channel1.o.right;
|
if(channel1.r.enable) right += channel1.o.right;
|
||||||
if(channel2.r.enable) right += channel2.o.right;
|
if(channel2.r.enable) right += channel2.o.right;
|
||||||
if(channel3.r.enable) right += channel3.o.right;
|
if(channel3.r.enable) right += channel3.o.right;
|
||||||
right = (right >> r.speakerShift) << 5;
|
|
||||||
if(channel4.r.enable) right += channel4.o.right;
|
if(channel4.r.enable) right += channel4.o.right;
|
||||||
right = sclamp<16>(right << 3);
|
if(channel5.r.enable) right += (int11)channel5.o.right >> 3;
|
||||||
|
right = sclamp<16>(right << 5);
|
||||||
|
|
||||||
if(!r.speakerEnable) {
|
if(!r.headphoneEnable) {
|
||||||
left = 0;
|
left = 0;
|
||||||
right = 0;
|
right = 0;
|
||||||
}
|
}
|
||||||
|
@ -69,8 +67,11 @@ auto APU::step(uint clocks) -> void {
|
||||||
auto APU::power() -> void {
|
auto APU::power() -> void {
|
||||||
create(APU::Enter, 3'072'000);
|
create(APU::Enter, 3'072'000);
|
||||||
|
|
||||||
for(uint n = 0x006a; n <= 0x006b; n++) iomap[n] = this;
|
bus.map(this, 0x004a, 0x004c);
|
||||||
for(uint n = 0x0080; n <= 0x0094; n++) iomap[n] = this;
|
bus.map(this, 0x004e, 0x0050);
|
||||||
|
bus.map(this, 0x0052);
|
||||||
|
bus.map(this, 0x006a, 0x006b);
|
||||||
|
bus.map(this, 0x0080, 0x0095);
|
||||||
|
|
||||||
s.clock = 0;
|
s.clock = 0;
|
||||||
r.waveBase = 0;
|
r.waveBase = 0;
|
||||||
|
@ -78,14 +79,17 @@ auto APU::power() -> void {
|
||||||
r.speakerShift = 0;
|
r.speakerShift = 0;
|
||||||
r.headphoneEnable = 0;
|
r.headphoneEnable = 0;
|
||||||
|
|
||||||
channel0.o.left = 0;
|
dma.s.clock = 0;
|
||||||
channel0.o.right = 0;
|
dma.s.source = 0;
|
||||||
channel0.s.period = 0;
|
dma.s.length = 0;
|
||||||
channel0.s.sampleOffset = 0;
|
dma.r.source = 0;
|
||||||
channel0.r.pitch = 0;
|
dma.r.length = 0;
|
||||||
channel0.r.volumeLeft = 0;
|
dma.r.rate = 0;
|
||||||
channel0.r.volumeRight = 0;
|
dma.r.unknown = 0;
|
||||||
channel0.r.enable = 0;
|
dma.r.loop = 0;
|
||||||
|
dma.r.target = 0;
|
||||||
|
dma.r.direction = 0;
|
||||||
|
dma.r.enable = 0;
|
||||||
|
|
||||||
channel1.o.left = 0;
|
channel1.o.left = 0;
|
||||||
channel1.o.right = 0;
|
channel1.o.right = 0;
|
||||||
|
@ -95,48 +99,58 @@ auto APU::power() -> void {
|
||||||
channel1.r.volumeLeft = 0;
|
channel1.r.volumeLeft = 0;
|
||||||
channel1.r.volumeRight = 0;
|
channel1.r.volumeRight = 0;
|
||||||
channel1.r.enable = 0;
|
channel1.r.enable = 0;
|
||||||
channel1.r.voice = 0;
|
|
||||||
channel1.r.voiceEnableLeft = 0;
|
|
||||||
channel1.r.voiceEnableRight = 0;
|
|
||||||
|
|
||||||
channel2.o.left = 0;
|
channel2.o.left = 0;
|
||||||
channel2.o.right = 0;
|
channel2.o.right = 0;
|
||||||
channel2.s.period = 0;
|
channel2.s.period = 0;
|
||||||
channel2.s.sampleOffset = 0;
|
channel2.s.sampleOffset = 0;
|
||||||
channel2.s.sweepCounter = 0;
|
|
||||||
channel2.r.pitch = 0;
|
channel2.r.pitch = 0;
|
||||||
channel2.r.volumeLeft = 0;
|
channel2.r.volumeLeft = 0;
|
||||||
channel2.r.volumeRight = 0;
|
channel2.r.volumeRight = 0;
|
||||||
channel2.r.sweepValue = 0;
|
|
||||||
channel2.r.sweepTime = 0;
|
|
||||||
channel2.r.enable = 0;
|
channel2.r.enable = 0;
|
||||||
channel2.r.sweep = 0;
|
channel2.r.voice = 0;
|
||||||
|
channel2.r.voiceEnableLeft = 0;
|
||||||
|
channel2.r.voiceEnableRight = 0;
|
||||||
|
|
||||||
channel3.o.left = 0;
|
channel3.o.left = 0;
|
||||||
channel3.o.right = 0;
|
channel3.o.right = 0;
|
||||||
channel3.s.period = 0;
|
channel3.s.period = 0;
|
||||||
channel3.s.sampleOffset = 0;
|
channel3.s.sampleOffset = 0;
|
||||||
channel3.s.noiseOutput = 0;
|
channel3.s.sweepCounter = 0;
|
||||||
channel3.s.noiseLFSR = 0;
|
|
||||||
channel3.r.pitch = 0;
|
channel3.r.pitch = 0;
|
||||||
channel3.r.volumeLeft = 0;
|
channel3.r.volumeLeft = 0;
|
||||||
channel3.r.volumeRight = 0;
|
channel3.r.volumeRight = 0;
|
||||||
channel3.r.noiseMode = 0;
|
channel3.r.sweepValue = 0;
|
||||||
channel3.r.noiseReset = 0;
|
channel3.r.sweepTime = 0;
|
||||||
channel3.r.noiseUpdate = 0;
|
|
||||||
channel3.r.enable = 0;
|
channel3.r.enable = 0;
|
||||||
channel3.r.noise = 0;
|
channel3.r.sweep = 0;
|
||||||
|
|
||||||
channel4.o.left = 0;
|
channel4.o.left = 0;
|
||||||
channel4.o.right = 0;
|
channel4.o.right = 0;
|
||||||
channel4.s.data = 0;
|
channel4.s.period = 0;
|
||||||
channel4.r.volume = 0;
|
channel4.s.sampleOffset = 0;
|
||||||
channel4.r.scale = 0;
|
channel4.s.noiseOutput = 0;
|
||||||
channel4.r.speed = 0;
|
channel4.s.noiseLFSR = 0;
|
||||||
|
channel4.r.pitch = 0;
|
||||||
|
channel4.r.volumeLeft = 0;
|
||||||
|
channel4.r.volumeRight = 0;
|
||||||
|
channel4.r.noiseMode = 0;
|
||||||
|
channel4.r.noiseReset = 0;
|
||||||
|
channel4.r.noiseUpdate = 0;
|
||||||
channel4.r.enable = 0;
|
channel4.r.enable = 0;
|
||||||
channel4.r.unknown = 0;
|
channel4.r.noise = 0;
|
||||||
channel4.r.leftEnable = 0;
|
|
||||||
channel4.r.rightEnable = 0;
|
channel5.o.left = 0;
|
||||||
|
channel5.o.right = 0;
|
||||||
|
channel5.s.clock = 0;
|
||||||
|
channel5.s.data = 0;
|
||||||
|
channel5.r.volume = 0;
|
||||||
|
channel5.r.scale = 0;
|
||||||
|
channel5.r.speed = 0;
|
||||||
|
channel5.r.enable = 0;
|
||||||
|
channel5.r.unknown = 0;
|
||||||
|
channel5.r.leftEnable = 0;
|
||||||
|
channel5.r.rightEnable = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
struct APU : Thread, IO {
|
struct APU : Thread, IO {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
|
auto sample(uint channel, uint5 index) -> uint4;
|
||||||
auto dacRun() -> void;
|
auto dacRun() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
@ -13,7 +14,47 @@ struct APU : Thread, IO {
|
||||||
uint13 clock;
|
uint13 clock;
|
||||||
} s;
|
} s;
|
||||||
|
|
||||||
|
struct DMA {
|
||||||
|
auto run() -> void;
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
uint clock;
|
||||||
|
uint20 source;
|
||||||
|
uint20 length;
|
||||||
|
} s;
|
||||||
|
|
||||||
|
struct Registers {
|
||||||
|
//$004a-$004c SDMA_SRC
|
||||||
|
uint20 source;
|
||||||
|
|
||||||
|
//$004e-$0050 SDMA_LEN
|
||||||
|
uint20 length;
|
||||||
|
|
||||||
|
//$0052 SDMA_CTRL
|
||||||
|
uint2 rate;
|
||||||
|
uint1 unknown;
|
||||||
|
uint1 loop;
|
||||||
|
uint1 target;
|
||||||
|
uint1 direction;
|
||||||
|
uint1 enable;
|
||||||
|
} r;
|
||||||
|
} dma;
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
|
//$004a-$004c SDMA_SRC
|
||||||
|
uint20 dmaSource;
|
||||||
|
|
||||||
|
//$004e-$0050 SDMA_LEN
|
||||||
|
uint20 dmaLength;
|
||||||
|
|
||||||
|
//$0052 SDMA_CTRL
|
||||||
|
uint2 dmaRate;
|
||||||
|
uint1 dmaUnknown;
|
||||||
|
uint1 dmaLoop;
|
||||||
|
uint1 dmaTarget;
|
||||||
|
uint1 dmaDirection;
|
||||||
|
uint1 dmaEnable;
|
||||||
|
|
||||||
//$008f SND_WAVE_BASE
|
//$008f SND_WAVE_BASE
|
||||||
uint8 waveBase;
|
uint8 waveBase;
|
||||||
|
|
||||||
|
@ -23,21 +64,13 @@ struct APU : Thread, IO {
|
||||||
uint1 headphoneEnable;
|
uint1 headphoneEnable;
|
||||||
} r;
|
} r;
|
||||||
|
|
||||||
struct Channel {
|
struct Channel1 {
|
||||||
Channel(uint id);
|
auto run() -> void;
|
||||||
auto sample(uint5 index) -> uint4;
|
|
||||||
|
|
||||||
const uint id;
|
|
||||||
|
|
||||||
struct Output {
|
struct Output {
|
||||||
int16 left;
|
uint8 left;
|
||||||
int16 right;
|
uint8 right;
|
||||||
} o;
|
} o;
|
||||||
};
|
|
||||||
|
|
||||||
struct Channel0 : Channel {
|
|
||||||
Channel0();
|
|
||||||
auto run() -> void;
|
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
uint11 period;
|
uint11 period;
|
||||||
|
@ -45,32 +78,36 @@ struct APU : Thread, IO {
|
||||||
} s;
|
} s;
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
//$0080-0081 SND_CH0_PITCH
|
//$0080-0081 SND_CH1_PITCH
|
||||||
uint11 pitch;
|
uint11 pitch;
|
||||||
|
|
||||||
//$0088 SND_CH0_VOL
|
//$0088 SND_CH1_VOL
|
||||||
uint4 volumeLeft;
|
uint4 volumeLeft;
|
||||||
uint4 volumeRight;
|
uint4 volumeRight;
|
||||||
|
|
||||||
//$0090 SND_CTRL
|
//$0090 SND_CTRL
|
||||||
uint1 enable;
|
uint1 enable;
|
||||||
} r;
|
} r;
|
||||||
} channel0;
|
} channel1;
|
||||||
|
|
||||||
struct Channel1 : Channel {
|
struct Channel2 {
|
||||||
Channel1();
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
uint8 left;
|
||||||
|
uint8 right;
|
||||||
|
} o;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
uint11 period;
|
uint11 period;
|
||||||
uint5 sampleOffset;
|
uint5 sampleOffset;
|
||||||
} s;
|
} s;
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
//$0082-0083 SND_CH1_PITCH
|
//$0082-0083 SND_CH2_PITCH
|
||||||
uint11 pitch;
|
uint11 pitch;
|
||||||
|
|
||||||
//$0089 SND_CH1_VOL
|
//$0089 SND_CH2_VOL
|
||||||
uint4 volumeLeft;
|
uint4 volumeLeft;
|
||||||
uint4 volumeRight;
|
uint4 volumeRight;
|
||||||
|
|
||||||
|
@ -78,17 +115,21 @@ struct APU : Thread, IO {
|
||||||
uint1 enable;
|
uint1 enable;
|
||||||
uint1 voice;
|
uint1 voice;
|
||||||
|
|
||||||
//$0092 SND_VOICE_CTRL
|
//$0094 SND_VOICE_CTRL
|
||||||
uint2 voiceEnableLeft;
|
uint2 voiceEnableLeft;
|
||||||
uint2 voiceEnableRight;
|
uint2 voiceEnableRight;
|
||||||
} r;
|
} r;
|
||||||
} channel1;
|
} channel2;
|
||||||
|
|
||||||
struct Channel2 : Channel {
|
struct Channel3 {
|
||||||
Channel2();
|
|
||||||
auto sweep() -> void;
|
auto sweep() -> void;
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
uint8 left;
|
||||||
|
uint8 right;
|
||||||
|
} o;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
uint11 period;
|
uint11 period;
|
||||||
uint5 sampleOffset;
|
uint5 sampleOffset;
|
||||||
|
@ -97,10 +138,10 @@ struct APU : Thread, IO {
|
||||||
} s;
|
} s;
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
//$0084-0085 SND_CH2_PITCH
|
//$0084-0085 SND_CH3_PITCH
|
||||||
uint11 pitch;
|
uint11 pitch;
|
||||||
|
|
||||||
//$008a SND_CH2_VOL
|
//$008a SND_CH3_VOL
|
||||||
uint4 volumeLeft;
|
uint4 volumeLeft;
|
||||||
uint4 volumeRight;
|
uint4 volumeRight;
|
||||||
|
|
||||||
|
@ -114,13 +155,17 @@ struct APU : Thread, IO {
|
||||||
uint1 enable;
|
uint1 enable;
|
||||||
uint1 sweep;
|
uint1 sweep;
|
||||||
} r;
|
} r;
|
||||||
} channel2;
|
} channel3;
|
||||||
|
|
||||||
struct Channel3 : Channel {
|
struct Channel4 {
|
||||||
Channel3();
|
|
||||||
auto noiseSample() -> uint4;
|
auto noiseSample() -> uint4;
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
uint8 left;
|
||||||
|
uint8 right;
|
||||||
|
} o;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
uint11 period;
|
uint11 period;
|
||||||
uint5 sampleOffset;
|
uint5 sampleOffset;
|
||||||
|
@ -130,10 +175,10 @@ struct APU : Thread, IO {
|
||||||
} s;
|
} s;
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
//$0086-0087 SND_CH3_PITCH
|
//$0086-0087 SND_CH4_PITCH
|
||||||
uint11 pitch;
|
uint11 pitch;
|
||||||
|
|
||||||
//$008b SND_CH3_VOL
|
//$008b SND_CH4_VOL
|
||||||
uint4 volumeLeft;
|
uint4 volumeLeft;
|
||||||
uint4 volumeRight;
|
uint4 volumeRight;
|
||||||
|
|
||||||
|
@ -146,14 +191,19 @@ struct APU : Thread, IO {
|
||||||
uint1 enable;
|
uint1 enable;
|
||||||
uint1 noise;
|
uint1 noise;
|
||||||
} r;
|
} r;
|
||||||
} channel3;
|
} channel4;
|
||||||
|
|
||||||
struct Channel4 : Channel {
|
struct Channel5 {
|
||||||
Channel4();
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
uint11 left;
|
||||||
|
uint11 right;
|
||||||
|
} o;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
int8 data;
|
uint clock;
|
||||||
|
uint8 data;
|
||||||
} s;
|
} s;
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
|
@ -168,7 +218,7 @@ struct APU : Thread, IO {
|
||||||
uint1 leftEnable;
|
uint1 leftEnable;
|
||||||
uint1 rightEnable;
|
uint1 rightEnable;
|
||||||
} r;
|
} r;
|
||||||
} channel4;
|
} channel5;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern APU apu;
|
extern APU apu;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
APU::Channel::Channel(uint id) : id(id) {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto APU::Channel::sample(uint5 index) -> uint4 {
|
|
||||||
auto data = iram.read((apu.r.waveBase << 6) + (id << 4) + (index >> 1));
|
|
||||||
if(index.bit(0) == 0) return data.bits(0,3);
|
|
||||||
if(index.bit(0) == 1) return data.bits(4,7);
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
APU::Channel0::Channel0() : Channel(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto APU::Channel0::run() -> void {
|
|
||||||
if(--s.period == r.pitch) {
|
|
||||||
s.period = 0;
|
|
||||||
auto output = sample(s.sampleOffset++);
|
|
||||||
o.left = output * r.volumeLeft;
|
|
||||||
o.right = output * r.volumeRight;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,7 @@
|
||||||
APU::Channel1::Channel1() : Channel(1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto APU::Channel1::run() -> void {
|
auto APU::Channel1::run() -> void {
|
||||||
if(r.voice) {
|
if(--s.period == r.pitch) {
|
||||||
uint8 volume = r.volumeLeft << 4 | r.volumeRight << 0;
|
|
||||||
o.left = r.voiceEnableLeft ? volume : (uint8)0x80;
|
|
||||||
o.right = r.voiceEnableRight ? volume : (uint8)0x80;
|
|
||||||
} else if(--s.period == r.pitch) {
|
|
||||||
s.period = 0;
|
s.period = 0;
|
||||||
auto output = sample(s.sampleOffset++);
|
auto output = apu.sample(1, s.sampleOffset++);
|
||||||
o.left = output * r.volumeLeft;
|
o.left = output * r.volumeLeft;
|
||||||
o.right = output * r.volumeRight;
|
o.right = output * r.volumeRight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
APU::Channel2::Channel2() : Channel(2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto APU::Channel2::sweep() -> void {
|
|
||||||
if(r.sweep && --s.sweepCounter < 0) {
|
|
||||||
s.sweepCounter = r.sweepTime;
|
|
||||||
r.pitch += r.sweepTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto APU::Channel2::run() -> void {
|
auto APU::Channel2::run() -> void {
|
||||||
if(--s.period == r.pitch) {
|
if(r.voice) {
|
||||||
|
uint8 volume = r.volumeLeft << 4 | r.volumeRight << 0;
|
||||||
|
o.left = r.voiceEnableLeft ? volume : (uint8)0;
|
||||||
|
o.right = r.voiceEnableRight ? volume : (uint8)0;
|
||||||
|
} else if(--s.period == r.pitch) {
|
||||||
s.period = 0;
|
s.period = 0;
|
||||||
auto output = sample(s.sampleOffset++);
|
auto output = apu.sample(2, s.sampleOffset++);
|
||||||
o.left = output * r.volumeLeft;
|
o.left = output * r.volumeLeft;
|
||||||
o.right = output * r.volumeRight;
|
o.right = output * r.volumeRight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,15 @@
|
||||||
APU::Channel3::Channel3() : Channel(3) {
|
auto APU::Channel3::sweep() -> void {
|
||||||
}
|
if(r.sweep && --s.sweepCounter < 0) {
|
||||||
|
s.sweepCounter = r.sweepTime;
|
||||||
auto APU::Channel3::noiseSample() -> uint4 {
|
r.pitch += r.sweepTime;
|
||||||
return s.noiseOutput ? 0xf : 0x0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Channel3::run() -> void {
|
auto APU::Channel3::run() -> void {
|
||||||
if(--s.period == r.pitch) {
|
if(--s.period == r.pitch) {
|
||||||
s.period = 0;
|
s.period = 0;
|
||||||
|
auto output = apu.sample(3, s.sampleOffset++);
|
||||||
auto output = r.noise ? noiseSample() : sample(s.sampleOffset++);
|
|
||||||
o.left = output * r.volumeLeft;
|
o.left = output * r.volumeLeft;
|
||||||
o.right = output * r.volumeRight;
|
o.right = output * r.volumeRight;
|
||||||
|
|
||||||
if(r.noiseReset) {
|
|
||||||
r.noiseReset = 0;
|
|
||||||
s.noiseLFSR = 0;
|
|
||||||
s.noiseOutput = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r.noiseUpdate) {
|
|
||||||
static const int taps[8] = {14, 10, 13, 4, 8, 6, 9, 11};
|
|
||||||
auto tap = taps[r.noiseMode];
|
|
||||||
|
|
||||||
s.noiseOutput = (1 ^ (s.noiseLFSR >> 7) ^ (s.noiseLFSR >> tap)) & 1;
|
|
||||||
s.noiseLFSR = s.noiseLFSR << 1 | s.noiseOutput;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
APU::Channel4::Channel4() : Channel(4) {
|
auto APU::Channel4::noiseSample() -> uint4 {
|
||||||
|
return s.noiseOutput ? 0xf : 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::Channel4::run() -> void {
|
auto APU::Channel4::run() -> void {
|
||||||
int16 sample = s.data << 8;
|
if(--s.period == r.pitch) {
|
||||||
if(r.scale != 3) sample >>= r.volume;
|
s.period = 0;
|
||||||
if(r.scale == 1) sample |= 0x70000 >> r.volume;
|
|
||||||
|
|
||||||
o.left = r.leftEnable ? sample : (int16)0;
|
auto output = r.noise ? noiseSample() : apu.sample(4, s.sampleOffset++);
|
||||||
o.right = r.rightEnable ? sample : (int16)0;
|
o.left = output * r.volumeLeft;
|
||||||
|
o.right = output * r.volumeRight;
|
||||||
|
|
||||||
|
if(r.noiseReset) {
|
||||||
|
r.noiseReset = 0;
|
||||||
|
s.noiseLFSR = 0;
|
||||||
|
s.noiseOutput = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(r.noiseUpdate) {
|
||||||
|
static const int taps[8] = {14, 10, 13, 4, 8, 6, 9, 11};
|
||||||
|
auto tap = taps[r.noiseMode];
|
||||||
|
|
||||||
|
s.noiseOutput = (1 ^ (s.noiseLFSR >> 7) ^ (s.noiseLFSR >> tap)) & 1;
|
||||||
|
s.noiseLFSR = s.noiseLFSR << 1 | s.noiseOutput;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
auto APU::Channel5::run() -> void {
|
||||||
|
if(r.speed <= 5 && s.clock++ < 1536) return; //2000hz
|
||||||
|
if(r.speed == 6 && s.clock++ < 2048) return; //1500hz
|
||||||
|
if(r.speed == 7 && s.clock++ < 3072) return; //1000hz
|
||||||
|
s.clock = 0;
|
||||||
|
|
||||||
|
uint11 output = s.data;
|
||||||
|
switch(r.scale) {
|
||||||
|
case 0: output <<= 3 - r.volume; break;
|
||||||
|
case 1: output <<= 3 - r.volume; output |= -0x100 << (3 - r.volume); break;
|
||||||
|
case 2: output <<= 3 - r.volume; break;
|
||||||
|
case 3: output <<= r.volume; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
o.left = r.leftEnable ? output : (uint11)0;
|
||||||
|
o.right = r.rightEnable ? output : (uint11)0;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
auto APU::DMA::run() -> void {
|
||||||
|
if(!r.enable) return;
|
||||||
|
|
||||||
|
if(r.rate == 0 && ++s.clock < 768) return; // 4000hz
|
||||||
|
if(r.rate == 1 && ++s.clock < 512) return; // 6000hz
|
||||||
|
if(r.rate == 2 && ++s.clock < 256) return; //12000hz
|
||||||
|
if(r.rate == 3 && ++s.clock < 128) return; //24000hz
|
||||||
|
s.clock = 0;
|
||||||
|
|
||||||
|
uint8 data = bus.read(s.source);
|
||||||
|
if(r.direction == 0) s.source++;
|
||||||
|
if(r.direction == 1) s.source--;
|
||||||
|
|
||||||
|
if(r.target == 0) {
|
||||||
|
apu.channel2.r.volumeRight = data.bits(0,3);
|
||||||
|
apu.channel2.r.volumeLeft = data.bits(4,7);
|
||||||
|
} else {
|
||||||
|
apu.channel5.s.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(--s.length) return;
|
||||||
|
|
||||||
|
if(r.loop) {
|
||||||
|
s.source = r.source;
|
||||||
|
s.length = r.length;
|
||||||
|
} else {
|
||||||
|
r.enable = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,70 +1,90 @@
|
||||||
auto APU::portRead(uint16 addr) -> uint8 {
|
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
|
//SND_HYPER_CTRL
|
||||||
if(addr == 0x006a) return (
|
if(addr == 0x006a) return (
|
||||||
channel4.r.volume << 0
|
channel5.r.volume << 0
|
||||||
| channel4.r.scale << 2
|
| channel5.r.scale << 2
|
||||||
| channel4.r.speed << 4
|
| channel5.r.speed << 4
|
||||||
| channel4.r.enable << 7
|
| channel5.r.enable << 7
|
||||||
);
|
);
|
||||||
|
|
||||||
//SND_HYPER_CHAN_CTRL
|
//SND_HYPER_CHAN_CTRL
|
||||||
if(addr == 0x006b) return (
|
if(addr == 0x006b) return (
|
||||||
channel4.r.unknown << 0
|
channel5.r.unknown << 0
|
||||||
| channel4.r.leftEnable << 5
|
| channel5.r.leftEnable << 5
|
||||||
| channel4.r.rightEnable << 6
|
| channel5.r.rightEnable << 6
|
||||||
);
|
);
|
||||||
|
|
||||||
//SND_CH0_PITCH
|
|
||||||
if(addr == 0x0080) return channel0.r.pitch.bits(0, 7);
|
|
||||||
if(addr == 0x0081) return channel0.r.pitch.bits(8,11);
|
|
||||||
|
|
||||||
//SND_CH1_PITCH
|
//SND_CH1_PITCH
|
||||||
if(addr == 0x0082) return channel1.r.pitch.bits(0, 7);
|
if(addr == 0x0080) return channel1.r.pitch.bits(0, 7);
|
||||||
if(addr == 0x0083) return channel1.r.pitch.bits(8,11);
|
if(addr == 0x0081) return channel1.r.pitch.bits(8,11);
|
||||||
|
|
||||||
//SND_CH2_PITCH
|
//SND_CH2_PITCH
|
||||||
if(addr == 0x0084) return channel2.r.pitch.bits(0, 7);
|
if(addr == 0x0082) return channel2.r.pitch.bits(0, 7);
|
||||||
if(addr == 0x0085) return channel2.r.pitch.bits(8,11);
|
if(addr == 0x0083) return channel2.r.pitch.bits(8,11);
|
||||||
|
|
||||||
//SND_CH3_PITCH
|
//SND_CH3_PITCH
|
||||||
if(addr == 0x0086) return channel3.r.pitch.bits(0, 7);
|
if(addr == 0x0084) return channel3.r.pitch.bits(0, 7);
|
||||||
if(addr == 0x0087) return channel3.r.pitch.bits(8,11);
|
if(addr == 0x0085) return channel3.r.pitch.bits(8,11);
|
||||||
|
|
||||||
//SND_CH0_VOL
|
//SND_CH4_PITCH
|
||||||
if(addr == 0x0088) return (
|
if(addr == 0x0086) return channel4.r.pitch.bits(0, 7);
|
||||||
channel0.r.volumeRight << 0
|
if(addr == 0x0087) return channel4.r.pitch.bits(8,11);
|
||||||
| channel0.r.volumeLeft << 4
|
|
||||||
);
|
|
||||||
|
|
||||||
//SND_CH1_VOL
|
//SND_CH1_VOL
|
||||||
if(addr == 0x0089) return (
|
if(addr == 0x0088) return (
|
||||||
channel1.r.volumeRight << 0
|
channel1.r.volumeRight << 0
|
||||||
| channel1.r.volumeLeft << 4
|
| channel1.r.volumeLeft << 4
|
||||||
);
|
);
|
||||||
|
|
||||||
//SND_CH2_VOL
|
//SND_CH2_VOL
|
||||||
if(addr == 0x008a) return (
|
if(addr == 0x0089) return (
|
||||||
channel2.r.volumeRight << 0
|
channel2.r.volumeRight << 0
|
||||||
| channel2.r.volumeLeft << 4
|
| channel2.r.volumeLeft << 4
|
||||||
);
|
);
|
||||||
|
|
||||||
//SND_CH3_VOL
|
//SND_CH3_VOL
|
||||||
if(addr == 0x008b) return (
|
if(addr == 0x008a) return (
|
||||||
channel3.r.volumeRight << 0
|
channel3.r.volumeRight << 0
|
||||||
| channel3.r.volumeLeft << 4
|
| channel3.r.volumeLeft << 4
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//SND_CH4_VOL
|
||||||
|
if(addr == 0x008b) return (
|
||||||
|
channel4.r.volumeRight << 0
|
||||||
|
| channel4.r.volumeLeft << 4
|
||||||
|
);
|
||||||
|
|
||||||
//SND_SWEEP_VALUE
|
//SND_SWEEP_VALUE
|
||||||
if(addr == 0x008c) return channel2.r.sweepValue;
|
if(addr == 0x008c) return channel3.r.sweepValue;
|
||||||
|
|
||||||
//SND_SWEEP_TIME
|
//SND_SWEEP_TIME
|
||||||
if(addr == 0x008d) return channel2.r.sweepTime;
|
if(addr == 0x008d) return channel3.r.sweepTime;
|
||||||
|
|
||||||
//SND_NOISE
|
//SND_NOISE
|
||||||
//(noiseReset [bit 3] always reads as zero)
|
//(noiseReset [bit 3] always reads as zero)
|
||||||
if(addr == 0x008e) return (
|
if(addr == 0x008e) return (
|
||||||
channel3.r.noiseMode << 0
|
channel4.r.noiseMode << 0
|
||||||
| channel3.r.noiseUpdate << 4
|
| channel4.r.noiseUpdate << 4
|
||||||
);
|
);
|
||||||
|
|
||||||
//SND_WAVE_BASE
|
//SND_WAVE_BASE
|
||||||
|
@ -72,13 +92,13 @@ auto APU::portRead(uint16 addr) -> uint8 {
|
||||||
|
|
||||||
//SND_CTRL
|
//SND_CTRL
|
||||||
if(addr == 0x0090) return (
|
if(addr == 0x0090) return (
|
||||||
channel0.r.enable << 0
|
channel1.r.enable << 0
|
||||||
| channel1.r.enable << 1
|
| channel2.r.enable << 1
|
||||||
| channel2.r.enable << 2
|
| channel3.r.enable << 2
|
||||||
| channel3.r.enable << 3
|
| channel4.r.enable << 3
|
||||||
| channel1.r.voice << 5
|
| channel2.r.voice << 5
|
||||||
| channel2.r.sweep << 6
|
| channel3.r.sweep << 6
|
||||||
| channel3.r.noise << 7
|
| channel4.r.noise << 7
|
||||||
);
|
);
|
||||||
|
|
||||||
//SND_OUTPUT
|
//SND_OUTPUT
|
||||||
|
@ -90,114 +110,127 @@ auto APU::portRead(uint16 addr) -> uint8 {
|
||||||
);
|
);
|
||||||
|
|
||||||
//SND_RANDOM
|
//SND_RANDOM
|
||||||
if(addr == 0x0092) return channel3.s.noiseLFSR.bits(0, 7);
|
if(addr == 0x0092) return channel4.s.noiseLFSR.bits(0, 7);
|
||||||
if(addr == 0x0093) return channel3.s.noiseLFSR.bits(8,14);
|
if(addr == 0x0093) return channel4.s.noiseLFSR.bits(8,14);
|
||||||
|
|
||||||
//SND_VOICE_CTRL
|
//SND_VOICE_CTRL
|
||||||
if(addr == 0x0094) return (
|
if(addr == 0x0094) return (
|
||||||
channel1.r.voiceEnableRight << 0
|
channel2.r.voiceEnableRight << 0
|
||||||
| channel1.r.voiceEnableLeft << 2
|
| channel2.r.voiceEnableLeft << 2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//SND_HYPERVOICE
|
||||||
|
if(addr == 0x0095) return channel5.s.data;
|
||||||
|
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::portWrite(uint16 addr, uint8 data) -> void {
|
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
|
//SND_HYPER_CTRL
|
||||||
if(addr == 0x006a) {
|
if(addr == 0x006a) {
|
||||||
channel4.r.volume = data.bits(0,1);
|
channel5.r.volume = data.bits(0,1);
|
||||||
channel4.r.scale = data.bits(2,3);
|
channel5.r.scale = data.bits(2,3);
|
||||||
channel4.r.speed = data.bits(4,6);
|
channel5.r.speed = data.bits(4,6);
|
||||||
channel4.r.enable = data.bit (7);
|
channel5.r.enable = data.bit (7);
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_HYPER_CHAN_CTRL
|
//SND_HYPER_CHAN_CTRL
|
||||||
if(addr == 0x006b) {
|
if(addr == 0x006b) {
|
||||||
channel4.r.unknown = data.bits(0,3);
|
channel5.r.unknown = data.bits(0,3);
|
||||||
channel4.r.leftEnable = data.bit (5);
|
channel5.r.leftEnable = data.bit (5);
|
||||||
channel4.r.rightEnable = data.bit (6);
|
channel5.r.rightEnable = data.bit (6);
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_CH0_PITCH
|
|
||||||
if(addr == 0x0080) { channel0.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
|
||||||
if(addr == 0x0081) { channel0.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
|
||||||
|
|
||||||
//SND_CH1_PITCH
|
//SND_CH1_PITCH
|
||||||
if(addr == 0x0082) { channel1.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
if(addr == 0x0080) channel1.r.pitch.bits(0, 7) = data.bits(0,7);
|
||||||
if(addr == 0x0083) { channel1.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
if(addr == 0x0081) channel1.r.pitch.bits(8,11) = data.bits(0,3);
|
||||||
|
|
||||||
//SND_CH2_PITCH
|
//SND_CH2_PITCH
|
||||||
if(addr == 0x0084) { channel2.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
if(addr == 0x0082) channel2.r.pitch.bits(0, 7) = data.bits(0,7);
|
||||||
if(addr == 0x0085) { channel2.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
if(addr == 0x0083) channel2.r.pitch.bits(8,11) = data.bits(0,3);
|
||||||
|
|
||||||
//SND_CH3_PITCH
|
//SND_CH3_PITCH
|
||||||
if(addr == 0x0086) { channel3.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
if(addr == 0x0084) channel3.r.pitch.bits(0, 7) = data.bits(0,7);
|
||||||
if(addr == 0x0087) { channel3.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
if(addr == 0x0085) channel3.r.pitch.bits(8,11) = data.bits(0,3);
|
||||||
|
|
||||||
//SND_CH0_VOL
|
//SND_CH4_PITCH
|
||||||
if(addr == 0x0088) {
|
if(addr == 0x0086) channel4.r.pitch.bits(0, 7) = data.bits(0,7);
|
||||||
channel0.r.volumeRight = data.bits(0,3);
|
if(addr == 0x0087) channel4.r.pitch.bits(8,11) = data.bits(0,3);
|
||||||
channel0.r.volumeLeft = data.bits(4,7);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//SND_CH1_VOL
|
//SND_CH1_VOL
|
||||||
if(addr == 0x0089) {
|
if(addr == 0x0088) {
|
||||||
channel1.r.volumeRight = data.bits(0,3);
|
channel1.r.volumeRight = data.bits(0,3);
|
||||||
channel1.r.volumeLeft = data.bits(4,7);
|
channel1.r.volumeLeft = data.bits(4,7);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_CH2_VOL
|
//SND_CH2_VOL
|
||||||
if(addr == 0x008a) {
|
if(addr == 0x0089) {
|
||||||
channel2.r.volumeRight = data.bits(0,3);
|
channel2.r.volumeRight = data.bits(0,3);
|
||||||
channel2.r.volumeLeft = data.bits(4,7);
|
channel2.r.volumeLeft = data.bits(4,7);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_CH3_VOL
|
//SND_CH3_VOL
|
||||||
if(addr == 0x008b) {
|
if(addr == 0x008a) {
|
||||||
channel3.r.volumeRight = data.bits(0,3);
|
channel3.r.volumeRight = data.bits(0,3);
|
||||||
channel3.r.volumeLeft = data.bits(4,7);
|
channel3.r.volumeLeft = data.bits(4,7);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
//SND_CH4_VOL
|
||||||
|
if(addr == 0x008b) {
|
||||||
|
channel4.r.volumeRight = data.bits(0,3);
|
||||||
|
channel4.r.volumeLeft = data.bits(4,7);
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_SWEEP_VALUE
|
//SND_SWEEP_VALUE
|
||||||
if(addr == 0x008c) {
|
if(addr == 0x008c) channel3.r.sweepValue = data;
|
||||||
channel2.r.sweepValue = data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//SND_SWEEP_TIME
|
//SND_SWEEP_TIME
|
||||||
if(addr == 0x008d) {
|
if(addr == 0x008d) channel3.r.sweepTime = data.bits(0,4);
|
||||||
channel2.r.sweepTime = data.bits(0,4);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//SND_NOISE
|
//SND_NOISE
|
||||||
if(addr == 0x008e) {
|
if(addr == 0x008e) {
|
||||||
channel3.r.noiseMode = data.bits(0,2);
|
channel4.r.noiseMode = data.bits(0,2);
|
||||||
channel3.r.noiseReset = data.bit (3);
|
channel4.r.noiseReset = data.bit (3);
|
||||||
channel3.r.noiseUpdate = data.bit (4);
|
channel4.r.noiseUpdate = data.bit (4);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_WAVE_BASE
|
//SND_WAVE_BASE
|
||||||
if(addr == 0x008f) {
|
if(addr == 0x008f) r.waveBase = data;
|
||||||
r.waveBase = data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//SND_CTRL
|
//SND_CTRL
|
||||||
if(addr == 0x0090) {
|
if(addr == 0x0090) {
|
||||||
channel0.r.enable = data.bit(0);
|
channel1.r.enable = data.bit(0);
|
||||||
channel1.r.enable = data.bit(1);
|
channel2.r.enable = data.bit(1);
|
||||||
channel2.r.enable = data.bit(2);
|
channel3.r.enable = data.bit(2);
|
||||||
channel3.r.enable = data.bit(3);
|
channel4.r.enable = data.bit(3);
|
||||||
channel1.r.voice = data.bit(5);
|
channel2.r.voice = data.bit(5);
|
||||||
channel2.r.sweep = data.bit(6);
|
channel3.r.sweep = data.bit(6);
|
||||||
channel3.r.noise = data.bit(7);
|
channel4.r.noise = data.bit(7);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_OUTPUT
|
//SND_OUTPUT
|
||||||
|
@ -205,13 +238,11 @@ auto APU::portWrite(uint16 addr, uint8 data) -> void {
|
||||||
r.speakerEnable = data.bit (0);
|
r.speakerEnable = data.bit (0);
|
||||||
r.speakerShift = data.bits(1,2);
|
r.speakerShift = data.bits(1,2);
|
||||||
r.headphoneEnable = data.bit (3);
|
r.headphoneEnable = data.bit (3);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SND_VOICE_CTRL
|
//SND_VOICE_CTRL
|
||||||
if(addr == 0x0094) {
|
if(addr == 0x0094) {
|
||||||
channel1.r.voiceEnableRight = data.bits(0,1);
|
channel2.r.voiceEnableRight = data.bits(0,1);
|
||||||
channel1.r.voiceEnableLeft = data.bits(2,3);
|
channel2.r.voiceEnableLeft = data.bits(2,3);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ auto Cartridge::unload() -> void {
|
||||||
auto Cartridge::power() -> void {
|
auto Cartridge::power() -> void {
|
||||||
eeprom.power();
|
eeprom.power();
|
||||||
|
|
||||||
for(uint n = 0x00c0; n <= 0x00c8; n++) iomap[n] = this;
|
bus.map(this, 0x00c0, 0x00c8);
|
||||||
|
|
||||||
r.bank_rom0 = 0xff;
|
r.bank_rom0 = 0xff;
|
||||||
r.bank_rom1 = 0xff;
|
r.bank_rom1 = 0xff;
|
||||||
|
|
|
@ -37,27 +37,27 @@ auto CPU::write(uint20 addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::in(uint16 port) -> uint8 {
|
auto CPU::in(uint16 port) -> uint8 {
|
||||||
return iomap[port]->portRead(port);
|
return bus.portRead(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::out(uint16 port, uint8 data) -> void {
|
auto CPU::out(uint16 port, uint8 data) -> void {
|
||||||
return iomap[port]->portWrite(port, data);
|
return bus.portWrite(port, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::power() -> void {
|
auto CPU::power() -> void {
|
||||||
V30MZ::power();
|
V30MZ::power();
|
||||||
create(CPU::Enter, 3'072'000);
|
create(CPU::Enter, 3'072'000);
|
||||||
|
|
||||||
iomap[0x00a0] = this;
|
bus.map(this, 0x00a0);
|
||||||
iomap[0x00b0] = this;
|
bus.map(this, 0x00b0);
|
||||||
iomap[0x00b2] = this;
|
bus.map(this, 0x00b2);
|
||||||
iomap[0x00b4] = this;
|
bus.map(this, 0x00b4);
|
||||||
iomap[0x00b5] = this;
|
bus.map(this, 0x00b5);
|
||||||
iomap[0x00b6] = this;
|
bus.map(this, 0x00b6);
|
||||||
|
|
||||||
if(system.model() != Model::WonderSwan) {
|
if(system.model() != Model::WonderSwan) {
|
||||||
for(uint p = 0x0040; p <= 0x0049; p++) iomap[p] = this;
|
bus.map(this, 0x0040, 0x0049);
|
||||||
iomap[0x0062] = this;
|
bus.map(this, 0x0062);
|
||||||
}
|
}
|
||||||
|
|
||||||
r.dmaSource = 0;
|
r.dmaSource = 0;
|
||||||
|
|
|
@ -2,24 +2,9 @@
|
||||||
|
|
||||||
namespace WonderSwan {
|
namespace WonderSwan {
|
||||||
|
|
||||||
IO* iomap[64 * 1024] = {nullptr};
|
|
||||||
InternalRAM iram;
|
InternalRAM iram;
|
||||||
Bus bus;
|
Bus bus;
|
||||||
|
|
||||||
auto IO::power() -> void {
|
|
||||||
static IO unmapped;
|
|
||||||
for(auto& n : iomap) n = &unmapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto IO::portRead(uint16 addr) -> uint8 {
|
|
||||||
//print("[", hex(addr, 4L), "]: port unmapped\n");
|
|
||||||
return 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto IO::portWrite(uint16 addr, uint8 data) -> void {
|
|
||||||
//print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto InternalRAM::power() -> void {
|
auto InternalRAM::power() -> void {
|
||||||
for(auto& byte : memory) byte = 0x00;
|
for(auto& byte : memory) byte = 0x00;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +22,10 @@ auto InternalRAM::write(uint16 addr, uint8 data) -> void {
|
||||||
memory[addr] = data;
|
memory[addr] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Bus::power() -> void {
|
||||||
|
for(auto& io : port) io = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto Bus::read(uint20 addr) -> uint8 {
|
auto Bus::read(uint20 addr) -> uint8 {
|
||||||
if(addr.bits(16,19) == 0) return iram.read(addr);
|
if(addr.bits(16,19) == 0) return iram.read(addr);
|
||||||
if(addr.bits(16,19) == 1) return cartridge.ramRead(addr);
|
if(addr.bits(16,19) == 1) return cartridge.ramRead(addr);
|
||||||
|
@ -50,4 +39,17 @@ auto Bus::write(uint20 addr, uint8 data) -> void {
|
||||||
if(addr.bits(16,19) >= 2) return cartridge.romWrite(addr, data);
|
if(addr.bits(16,19) >= 2) return cartridge.romWrite(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Bus::map(IO* io, uint16_t lo, maybe<uint16_t> hi) -> void {
|
||||||
|
for(uint addr = lo; addr <= (hi ? hi() : lo); addr++) port[addr] = io;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Bus::portRead(uint16 addr) -> uint8 {
|
||||||
|
if(auto io = port[addr]) return io->portRead(addr);
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Bus::portWrite(uint16 addr, uint8 data) -> void {
|
||||||
|
if(auto io = port[addr]) return io->portWrite(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
struct IO {
|
struct IO {
|
||||||
static auto power() -> void;
|
virtual auto portRead(uint16 addr) -> uint8 = 0;
|
||||||
|
virtual auto portWrite(uint16 addr, uint8 data) -> void = 0;
|
||||||
virtual auto portRead(uint16 addr) -> uint8;
|
|
||||||
virtual auto portWrite(uint16 addr, uint8 data) -> void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InternalRAM {
|
struct InternalRAM {
|
||||||
|
@ -16,10 +14,18 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bus {
|
struct Bus {
|
||||||
|
auto power() -> void;
|
||||||
|
|
||||||
auto read(uint20 addr) -> uint8;
|
auto read(uint20 addr) -> uint8;
|
||||||
auto write(uint20 addr, uint8 data) -> void;
|
auto write(uint20 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
auto map(IO* io, uint16_t lo, maybe<uint16_t> hi = nothing) -> void;
|
||||||
|
auto portRead(uint16 addr) -> uint8;
|
||||||
|
auto portWrite(uint16 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IO* port[64 * 1024] = {nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern IO* iomap[64 * 1024];
|
|
||||||
extern InternalRAM iram;
|
extern InternalRAM iram;
|
||||||
extern Bus bus;
|
extern Bus bus;
|
||||||
|
|
|
@ -15,8 +15,9 @@ auto PPU::Enter() -> void {
|
||||||
|
|
||||||
auto PPU::main() -> void {
|
auto PPU::main() -> void {
|
||||||
if(status.vclk < 144) {
|
if(status.vclk < 144) {
|
||||||
|
renderSpriteFetch();
|
||||||
renderSpriteDecode();
|
renderSpriteDecode();
|
||||||
for(uint x = 0; x < 224; x++) {
|
for(auto x : range(256)) {
|
||||||
if(!system.color()) {
|
if(!system.color()) {
|
||||||
renderMonoBack();
|
renderMonoBack();
|
||||||
renderMonoScreenOne();
|
renderMonoScreenOne();
|
||||||
|
@ -86,12 +87,13 @@ auto PPU::step(uint clocks) -> void {
|
||||||
auto PPU::power() -> void {
|
auto PPU::power() -> void {
|
||||||
create(PPU::Enter, 3'072'000);
|
create(PPU::Enter, 3'072'000);
|
||||||
|
|
||||||
for(uint n = 0x0000; n <= 0x0017; n++) iomap[n] = this;
|
bus.map(this, 0x0000, 0x0017);
|
||||||
for(uint n = 0x001c; n <= 0x003f; n++) iomap[n] = this;
|
bus.map(this, 0x001c, 0x003f);
|
||||||
iomap[0x00a2] = this;
|
bus.map(this, 0x00a2);
|
||||||
for(uint n = 0x00a4; n <= 0x00ab; n++) iomap[n] = this;
|
bus.map(this, 0x00a4, 0x00ab);
|
||||||
|
|
||||||
for(auto& n : output) n = 0;
|
for(auto& n : output) n = 0;
|
||||||
|
for(auto& n : oam) n = 0;
|
||||||
|
|
||||||
status.vclk = 0;
|
status.vclk = 0;
|
||||||
status.hclk = 0;
|
status.hclk = 0;
|
||||||
|
|
|
@ -13,10 +13,12 @@ struct PPU : Thread, IO {
|
||||||
auto portWrite(uint16 addr, uint8 data) -> void override;
|
auto portWrite(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
//render-sprite.cpp
|
//render-sprite.cpp
|
||||||
|
auto renderSpriteFetch() -> void;
|
||||||
auto renderSpriteDecode() -> void;
|
auto renderSpriteDecode() -> void;
|
||||||
|
|
||||||
//render-mono.cpp
|
//render-mono.cpp
|
||||||
auto renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2;
|
auto renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2;
|
||||||
|
auto renderMonoPalette(uint4 palette, uint2 index) -> uint12;
|
||||||
auto renderMonoBack() -> void;
|
auto renderMonoBack() -> void;
|
||||||
auto renderMonoScreenOne() -> void;
|
auto renderMonoScreenOne() -> void;
|
||||||
auto renderMonoScreenTwo() -> void;
|
auto renderMonoScreenTwo() -> void;
|
||||||
|
@ -24,6 +26,7 @@ struct PPU : Thread, IO {
|
||||||
|
|
||||||
//render-color.cpp
|
//render-color.cpp
|
||||||
auto renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4;
|
auto renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4;
|
||||||
|
auto renderColorPalette(uint4 palette, uint4 index) -> uint12;
|
||||||
auto renderColorBack() -> void;
|
auto renderColorBack() -> void;
|
||||||
auto renderColorScreenOne() -> void;
|
auto renderColorScreenOne() -> void;
|
||||||
auto renderColorScreenTwo() -> void;
|
auto renderColorScreenTwo() -> void;
|
||||||
|
@ -31,6 +34,7 @@ struct PPU : Thread, IO {
|
||||||
|
|
||||||
//state
|
//state
|
||||||
uint12 output[224 * 144];
|
uint12 output[224 * 144];
|
||||||
|
uint32 oam[128];
|
||||||
|
|
||||||
struct Status {
|
struct Status {
|
||||||
uint vclk;
|
uint vclk;
|
||||||
|
|
|
@ -17,6 +17,10 @@ auto PPU::renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4 {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto PPU::renderColorPalette(uint4 palette, uint4 index) -> uint12 {
|
||||||
|
return iram.read(0xfe00 + (palette << 5) + (index << 1), Word);
|
||||||
|
}
|
||||||
|
|
||||||
auto PPU::renderColorBack() -> void {
|
auto PPU::renderColorBack() -> void {
|
||||||
uint12 color = iram.read(0xfe00 + (r.backColor << 1), Word);
|
uint12 color = iram.read(0xfe00 + (r.backColor << 1), Word);
|
||||||
pixel = {Pixel::Source::Back, color};
|
pixel = {Pixel::Source::Back, color};
|
||||||
|
@ -39,8 +43,7 @@ auto PPU::renderColorScreenOne() -> void {
|
||||||
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
|
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
|
||||||
if(tileColor == 0) return;
|
if(tileColor == 0) return;
|
||||||
|
|
||||||
uint12 color = iram.read(0xfe00 + (tile.bits(9, 12) << 5) + (tileColor << 1), Word);
|
pixel = {Pixel::Source::ScreenOne, renderColorPalette(tile.bits(9, 12), tileColor)};
|
||||||
pixel = {Pixel::Source::ScreenOne, color};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::renderColorScreenTwo() -> void {
|
auto PPU::renderColorScreenTwo() -> void {
|
||||||
|
@ -65,8 +68,7 @@ auto PPU::renderColorScreenTwo() -> void {
|
||||||
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
|
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
|
||||||
if(tileColor == 0) return;
|
if(tileColor == 0) return;
|
||||||
|
|
||||||
uint12 color = iram.read(0xfe00 + (tile.bits(9,12) << 5) + (tileColor << 1), Word);
|
pixel = {Pixel::Source::ScreenTwo, renderColorPalette(tile.bits(9, 12), tileColor)};
|
||||||
pixel = {Pixel::Source::ScreenTwo, color};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::renderColorSprite() -> void {
|
auto PPU::renderColorSprite() -> void {
|
||||||
|
@ -85,8 +87,7 @@ auto PPU::renderColorSprite() -> void {
|
||||||
if(tileColor == 0) continue;
|
if(tileColor == 0) continue;
|
||||||
if(!sprite.priority && pixel.source == Pixel::Source::ScreenTwo) continue;
|
if(!sprite.priority && pixel.source == Pixel::Source::ScreenTwo) continue;
|
||||||
|
|
||||||
uint12 color = iram.read(0xfe00 + (sprite.palette << 5) + (tileColor << 1), Word);
|
pixel = {Pixel::Source::Sprite, renderColorPalette(sprite.palette, tileColor)};
|
||||||
pixel = {Pixel::Source::Sprite, color};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,12 @@ auto PPU::renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2 {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto PPU::renderMonoPalette(uint4 palette, uint2 index) -> uint12 {
|
||||||
|
uint3 paletteColor = r.palette[palette].color[index];
|
||||||
|
uint4 poolColor = 15 - r.pool[paletteColor];
|
||||||
|
return poolColor << 0 | poolColor << 4 | poolColor << 8;
|
||||||
|
}
|
||||||
|
|
||||||
auto PPU::renderMonoBack() -> void {
|
auto PPU::renderMonoBack() -> void {
|
||||||
uint4 poolColor = 15 - r.pool[r.backColor.bits(0,2)];
|
uint4 poolColor = 15 - r.pool[r.backColor.bits(0,2)];
|
||||||
pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||||
|
@ -37,9 +43,7 @@ auto PPU::renderMonoScreenOne() -> void {
|
||||||
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
|
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
|
||||||
if(tile.bit(11) && tileColor == 0) return;
|
if(tile.bit(11) && tileColor == 0) return;
|
||||||
|
|
||||||
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
|
pixel = {Pixel::Source::ScreenOne, renderMonoPalette(tile.bits(9,12), tileColor)};
|
||||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
|
||||||
pixel = {Pixel::Source::ScreenOne, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::renderMonoScreenTwo() -> void {
|
auto PPU::renderMonoScreenTwo() -> void {
|
||||||
|
@ -50,8 +54,8 @@ auto PPU::renderMonoScreenTwo() -> void {
|
||||||
windowInside ^= r.screenTwoWindowInvert;
|
windowInside ^= r.screenTwoWindowInvert;
|
||||||
if(r.screenTwoWindowEnable && !windowInside) return;
|
if(r.screenTwoWindowEnable && !windowInside) return;
|
||||||
|
|
||||||
uint8 scrollX = status.hclk + r.scrollTwoX;
|
|
||||||
uint8 scrollY = status.vclk + r.scrollTwoY;
|
uint8 scrollY = status.vclk + r.scrollTwoY;
|
||||||
|
uint8 scrollX = status.hclk + r.scrollTwoX;
|
||||||
|
|
||||||
uint14 tilemapOffset = r.screenTwoMapBase.bits(0,2) << 11;
|
uint14 tilemapOffset = r.screenTwoMapBase.bits(0,2) << 11;
|
||||||
tilemapOffset += (scrollY >> 3) << 6;
|
tilemapOffset += (scrollY >> 3) << 6;
|
||||||
|
@ -64,9 +68,7 @@ auto PPU::renderMonoScreenTwo() -> void {
|
||||||
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
|
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
|
||||||
if(tile.bit(11) && tileColor == 0) return;
|
if(tile.bit(11) && tileColor == 0) return;
|
||||||
|
|
||||||
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
|
pixel = {Pixel::Source::ScreenTwo, renderMonoPalette(tile.bits(9,12), tileColor)};
|
||||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
|
||||||
pixel = {Pixel::Source::ScreenTwo, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::renderMonoSprite() -> void {
|
auto PPU::renderMonoSprite() -> void {
|
||||||
|
@ -85,9 +87,7 @@ auto PPU::renderMonoSprite() -> void {
|
||||||
if(sprite.palette.bit(2) && tileColor == 0) continue;
|
if(sprite.palette.bit(2) && tileColor == 0) continue;
|
||||||
if(!sprite.priority && pixel.source == Pixel::Source::ScreenTwo) continue;
|
if(!sprite.priority && pixel.source == Pixel::Source::ScreenTwo) continue;
|
||||||
|
|
||||||
uint3 paletteColor = r.palette[sprite.palette].color[tileColor];
|
pixel = {Pixel::Source::Sprite, renderMonoPalette(sprite.palette, tileColor)};
|
||||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
|
||||||
pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
auto PPU::renderSpriteFetch() -> void {
|
||||||
|
uint16 spriteBase = r.spriteBase.bits(0, 4 + system.depth()) << 9;
|
||||||
|
for(auto spriteIndex : range(128)) {
|
||||||
|
oam[spriteIndex] = iram.read(spriteBase + (spriteIndex << 2), Long);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto PPU::renderSpriteDecode() -> void {
|
auto PPU::renderSpriteDecode() -> void {
|
||||||
sprites.reset();
|
sprites.reset();
|
||||||
sprites.reserve(32);
|
sprites.reserve(32);
|
||||||
|
@ -9,7 +16,7 @@ auto PPU::renderSpriteDecode() -> void {
|
||||||
uint7 spriteIndex = r.spriteFirst;
|
uint7 spriteIndex = r.spriteFirst;
|
||||||
uint8 spriteCount = min(128, (uint)r.spriteCount);
|
uint8 spriteCount = min(128, (uint)r.spriteCount);
|
||||||
while(spriteCount--) {
|
while(spriteCount--) {
|
||||||
uint32 attributes = iram.read(spriteBase + (spriteIndex++ << 2), Long);
|
uint32 attributes = oam[spriteIndex++];
|
||||||
|
|
||||||
Sprite sprite;
|
Sprite sprite;
|
||||||
sprite.x = attributes.bits(24,31);
|
sprite.x = attributes.bits(24,31);
|
||||||
|
|
|
@ -50,7 +50,7 @@ auto System::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
IO::power();
|
bus.power();
|
||||||
iram.power();
|
iram.power();
|
||||||
eeprom.power();
|
eeprom.power();
|
||||||
cpu.power();
|
cpu.power();
|
||||||
|
@ -59,8 +59,8 @@ auto System::power() -> void {
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
scheduler.power();
|
scheduler.power();
|
||||||
|
|
||||||
iomap[0x0060] = this;
|
bus.map(this, 0x0060);
|
||||||
for(uint n = 0x00ba; n <= 0x00be; n++) iomap[n] = this;
|
bus.map(this, 0x00ba, 0x00be);
|
||||||
|
|
||||||
r.depth = 0;
|
r.depth = 0;
|
||||||
r.color = 0;
|
r.color = 0;
|
||||||
|
|
Loading…
Reference in New Issue