mirror of https://github.com/bsnes-emu/bsnes.git
Update to v097r22 release.
byuu says: Changelog: - WS: fixed lods, scas instructions - WS: implemented missing GRP4 instructions - WS: fixed transparency for screen one - WSC: added color-mode PPU rendering - WS+WSC: added packed pixel mode support - WS+WSC: added dummy sound register reads/writes - SFC: added threading to SuperDisc (it's hanging for right now; need to clear IRQ on $21e2 writes) SuperDisc Timer and Sound Check were failing before due to not turning off IRQs on $21e4 clear, so I'm happy that's fixed now. Riviera starts now, and displays the first intro screen before crashing. Huge, huge amounts of corrupted graphics, though. This game's really making me work for it :( No color games seem fully playable yet, but a lot of monochrome and color games are now at least showing more intro screen graphics before dying. This build defaults to horizontal orientation, but I left the inputs bound to vertical orientation. Whoops. I still need to implement a screen flip key binding.
This commit is contained in:
parent
b0d2f5033e
commit
3d3ac8c1db
|
@ -6,7 +6,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "097.21";
|
||||
static const string Version = "097.22";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -53,7 +53,7 @@ auto V30MZ::opGroup3MemImm(Size size) {
|
|||
auto mem = getMem(size);
|
||||
switch(modrm.reg) {
|
||||
case 0: alAnd(size, mem, fetch(size)); break;
|
||||
case 1: break;
|
||||
case 1: debug("[V30MZ] GRP3.1"); break;
|
||||
case 2: wait(2); setMem(size, alNot(size, mem)); break;
|
||||
case 3: wait(2); setMem(size, alNeg(size, mem)); break;
|
||||
case 4: wait(2); setAcc(size * 2, alMul(size, getAcc(size), mem)); break;
|
||||
|
@ -67,15 +67,47 @@ auto V30MZ::opGroup3MemImm(Size size) {
|
|||
//ff grp4 memw
|
||||
auto V30MZ::opGroup4MemImm(Size size) {
|
||||
modRM();
|
||||
auto mem = getMem(size);
|
||||
switch(modrm.reg) {
|
||||
case 0: wait(2); setMem(size, alInc(size, mem)); break;
|
||||
case 1: wait(2); setMem(size, alDec(size, mem)); break;
|
||||
case 2: break;
|
||||
case 3: break;
|
||||
case 4: break;
|
||||
case 5: break;
|
||||
case 6: break;
|
||||
case 7: break;
|
||||
case 0:
|
||||
wait(2);
|
||||
setMem(size, alInc(size, getMem(size)));
|
||||
break;
|
||||
case 1:
|
||||
wait(2);
|
||||
setMem(size, alDec(size, getMem(size)));
|
||||
break;
|
||||
case 2:
|
||||
if(size == Byte) { debug("[V30MZ] GRP4.2"); break; }
|
||||
wait(5);
|
||||
push(r.ip);
|
||||
r.ip = getMem(Word);
|
||||
break;
|
||||
case 3:
|
||||
if(size == Byte) { debug("[V30MZ] GRP4.3"); break; }
|
||||
wait(11);
|
||||
push(r.cs);
|
||||
push(r.ip);
|
||||
r.ip = getMem(Word, 0);
|
||||
r.cs = getMem(Word, 2);
|
||||
break;
|
||||
case 4:
|
||||
if(size == Byte) { debug("[V30MZ] GRP4.4"); break; }
|
||||
wait(4);
|
||||
r.ip = getMem(Word);
|
||||
break;
|
||||
case 5:
|
||||
if(size == Byte) { debug("[V30MZ] GRP4.5"); break; }
|
||||
wait(9);
|
||||
r.ip = getMem(Word, 0);
|
||||
r.cs = getMem(Word, 2);
|
||||
break;
|
||||
case 6:
|
||||
if(size == Byte) { debug("[V30MZ] GRP4.6"); break; }
|
||||
wait(1);
|
||||
push(getMem(Word));
|
||||
break;
|
||||
case 7:
|
||||
debug("[V30MZ] GRP4.7");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ auto V30MZ::opStoreString(Size size) {
|
|||
auto V30MZ::opLoadString(Size size) {
|
||||
wait(2);
|
||||
setAcc(size, read(size, segment(r.ds), r.si));
|
||||
r.si += r.f.d ? -size : size;
|
||||
|
||||
if(prefix.repeat && --r.cx) {
|
||||
state.prefix = true;
|
||||
|
@ -78,6 +79,7 @@ auto V30MZ::opScanString(Size size) {
|
|||
wait(3);
|
||||
auto x = getAcc(size);
|
||||
auto y = read(size, r.es, r.di);
|
||||
r.di += r.f.d ? -size : size;
|
||||
alSub(size, x, y);
|
||||
|
||||
if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) {
|
||||
|
|
|
@ -17,6 +17,10 @@ namespace Processor {
|
|||
#include "instructions-string.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
auto V30MZ::debug(string text) -> void {
|
||||
print(text, "\n");
|
||||
}
|
||||
|
||||
auto V30MZ::exec() -> void {
|
||||
state.poll = true;
|
||||
if(state.halt) return wait(1);
|
||||
|
|
|
@ -14,6 +14,7 @@ struct V30MZ {
|
|||
virtual auto in(uint16 port) -> uint8 = 0;
|
||||
virtual auto out(uint16 port, uint8 data) -> void = 0;
|
||||
|
||||
auto debug(string text) -> void;
|
||||
auto exec() -> void;
|
||||
auto instruction() -> void;
|
||||
auto interrupt(uint8 vector) -> void;
|
||||
|
|
|
@ -4,6 +4,23 @@ namespace SuperFamicom {
|
|||
|
||||
SuperDisc superdisc;
|
||||
|
||||
auto SuperDisc::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), superdisc.main();
|
||||
}
|
||||
|
||||
auto SuperDisc::main() -> void {
|
||||
if(r21e4 & 0x04) {
|
||||
cpu.regs.irq = 1;
|
||||
r21e1 = 0x81;
|
||||
} else {
|
||||
cpu.regs.irq = 0;
|
||||
r21e1 = 0x00;
|
||||
}
|
||||
|
||||
step(1);
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
auto SuperDisc::init() -> void {
|
||||
}
|
||||
|
||||
|
@ -16,18 +33,77 @@ auto SuperDisc::unload() -> void {
|
|||
}
|
||||
|
||||
auto SuperDisc::power() -> void {
|
||||
create(&SuperDisc::Enter, 75);
|
||||
}
|
||||
|
||||
auto SuperDisc::reset() -> void {
|
||||
r21e0 = 0x00;
|
||||
r21e1 = 0x00;
|
||||
r21e2 = 0x00;
|
||||
r21e3 = 0x00;
|
||||
r21e4 = 0x00;
|
||||
r21e5 = 0x00;
|
||||
}
|
||||
|
||||
auto SuperDisc::read(uint24 addr, uint8 data) -> uint8 {
|
||||
addr = 0x21e0 | (addr & 7);
|
||||
|
||||
if(addr == 0x21e0) {
|
||||
data = r21e0;
|
||||
}
|
||||
|
||||
if(addr == 0x21e1) {
|
||||
data = r21e1;
|
||||
}
|
||||
|
||||
if(addr == 0x21e2) {
|
||||
data = r21e2;
|
||||
}
|
||||
|
||||
if(addr == 0x21e3) {
|
||||
if(r21e2 == 0x01) data = 0x10;
|
||||
else data = 0x00;
|
||||
r21e2++;
|
||||
}
|
||||
|
||||
if(addr == 0x21e4) {
|
||||
data = r21e4;
|
||||
}
|
||||
|
||||
if(addr == 0x21e5) {
|
||||
data = r21e5;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SuperDisc::write(uint24 addr, uint8 data) -> void {
|
||||
addr = 0x21e0 | (addr & 7);
|
||||
|
||||
if(addr == 0x21e0) {
|
||||
r21e0 = data;
|
||||
}
|
||||
|
||||
if(addr == 0x21e1) {
|
||||
r21e1 = data;
|
||||
}
|
||||
|
||||
if(addr == 0x21e2) {
|
||||
r21e2 = data;
|
||||
}
|
||||
|
||||
if(addr == 0x21e3) {
|
||||
r21e2++;
|
||||
r21e3 = data;
|
||||
}
|
||||
|
||||
if(addr == 0x21e4) {
|
||||
r21e4 = data;
|
||||
}
|
||||
|
||||
if(addr == 0x21e5) {
|
||||
r21e5 = data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
struct SuperDisc : Memory {
|
||||
struct SuperDisc : Coprocessor, Memory {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
|
||||
auto init() -> void;
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
|
@ -9,6 +12,12 @@ struct SuperDisc : Memory {
|
|||
auto write(uint24 addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
uint8 r21e0;
|
||||
uint8 r21e1;
|
||||
uint8 r21e2;
|
||||
uint8 r21e3;
|
||||
uint8 r21e4;
|
||||
uint8 r21e5;
|
||||
};
|
||||
|
||||
extern SuperDisc superdisc;
|
||||
|
|
|
@ -69,8 +69,8 @@ namespace SuperFamicom {
|
|||
#include <sfc/controller/controller.hpp>
|
||||
#include <sfc/system/system.hpp>
|
||||
#include <sfc/scheduler/scheduler.hpp>
|
||||
#include <sfc/expansion/expansion.hpp>
|
||||
#include <sfc/coprocessor/coprocessor.hpp>
|
||||
#include <sfc/expansion/expansion.hpp>
|
||||
#include <sfc/slot/slot.hpp>
|
||||
#include <sfc/cartridge/cartridge.hpp>
|
||||
#include <sfc/cheat/cheat.hpp>
|
||||
|
|
|
@ -209,6 +209,7 @@ auto System::reset() -> void {
|
|||
if(cartridge.hasSharpRTC()) cpu.coprocessors.append(&sharprtc);
|
||||
if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110);
|
||||
if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1);
|
||||
if(expansionPort() == Device::ID::SuperDisc) cpu.coprocessors.append(&superdisc);
|
||||
|
||||
scheduler.reset();
|
||||
device.connect(0, (Device::ID)settings.controllerPort1);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace WonderSwan {
|
||||
|
||||
APU apu;
|
||||
#include "io.cpp"
|
||||
|
||||
auto APU::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), apu.main();
|
||||
|
@ -20,6 +21,41 @@ auto APU::step(uint clocks) -> void {
|
|||
|
||||
auto APU::power() -> void {
|
||||
create(APU::Enter, 3'072'000);
|
||||
|
||||
for(uint n = 0x0080; n <= 0x0094; n++) iomap[n] = this;
|
||||
|
||||
channel1.r.pitch = 0;
|
||||
channel1.r.volumeLeft = 0;
|
||||
channel1.r.volumeRight = 0;
|
||||
channel1.r.enable = 0;
|
||||
|
||||
channel2.r.pitch = 0;
|
||||
channel2.r.volumeLeft = 0;
|
||||
channel2.r.volumeRight = 0;
|
||||
channel2.r.enable = 0;
|
||||
channel2.r.voice = 0;
|
||||
|
||||
channel3.r.pitch = 0;
|
||||
channel3.r.volumeLeft = 0;
|
||||
channel3.r.volumeRight = 0;
|
||||
channel3.r.sweepValue = 0;
|
||||
channel3.r.sweepTime = 0;
|
||||
channel3.r.enable = 0;
|
||||
channel3.r.sweep = 0;
|
||||
|
||||
channel4.r.pitch = 0;
|
||||
channel4.r.volumeLeft = 0;
|
||||
channel4.r.volumeRight = 0;
|
||||
channel4.r.noiseMode = 0;
|
||||
channel4.r.enable = 0;
|
||||
channel4.r.noise = 0;
|
||||
|
||||
r.waveBase = 0;
|
||||
r.speakerEnable = 0;
|
||||
r.speakerShift = 0;
|
||||
r.headphoneEnable = 0;
|
||||
r.voiceEnableLeft = 0;
|
||||
r.voiceEnableRight = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,94 @@
|
|||
struct APU : Thread {
|
||||
struct APU : Thread, IO {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto portRead(uint16 addr) -> uint8;
|
||||
auto portWrite(uint16 addr, uint8 data) -> void;
|
||||
|
||||
struct Channel1 {
|
||||
struct Registers {
|
||||
//$0080-0081 SND_CH1_PITCH
|
||||
uint11 pitch;
|
||||
|
||||
//$0088 SND_CH1_VOL
|
||||
uint4 volumeLeft;
|
||||
uint4 volumeRight;
|
||||
|
||||
//$0090 SND_CTRL
|
||||
uint1 enable;
|
||||
} r;
|
||||
} channel1;
|
||||
|
||||
struct Channel2 {
|
||||
struct Registers {
|
||||
//$0082-0083 SND_CH2_PITCH
|
||||
uint11 pitch;
|
||||
|
||||
//$0089 SND_CH2_VOL
|
||||
uint4 volumeLeft;
|
||||
uint4 volumeRight;
|
||||
|
||||
//$0090 SND_CTRL
|
||||
uint1 enable;
|
||||
uint1 voice;
|
||||
} r;
|
||||
} channel2;
|
||||
|
||||
struct Channel3 {
|
||||
struct Registers {
|
||||
//$0084-0085 SND_CH3_PITCH
|
||||
uint11 pitch;
|
||||
|
||||
//$008a SND_CH3_VOL
|
||||
uint4 volumeLeft;
|
||||
uint4 volumeRight;
|
||||
|
||||
//$008c SND_SWEEP_VALUE
|
||||
uint8 sweepValue;
|
||||
|
||||
//$008d SND_SWEEP_TIME
|
||||
uint5 sweepTime;
|
||||
|
||||
//$0090 SND_CTRL
|
||||
uint1 enable;
|
||||
uint1 sweep;
|
||||
} r;
|
||||
} channel3;
|
||||
|
||||
struct Channel4 {
|
||||
struct Registers {
|
||||
//$0086-0087 SND_CH4_PITCH
|
||||
uint11 pitch;
|
||||
|
||||
//$008b SND_CH4_VOL
|
||||
uint4 volumeLeft;
|
||||
uint4 volumeRight;
|
||||
|
||||
//$008e SND_NOISE
|
||||
uint5 noiseMode;
|
||||
|
||||
//$0090 SND_CTRL
|
||||
uint1 enable;
|
||||
uint1 noise;
|
||||
} r;
|
||||
} channel4;
|
||||
|
||||
struct Registers {
|
||||
//$008f SND_WAVE_BASE
|
||||
uint8 waveBase;
|
||||
|
||||
//$0091 SND_OUTPUT
|
||||
uint1 speakerEnable;
|
||||
uint2 speakerShift;
|
||||
uint1 headphoneEnable;
|
||||
|
||||
//$0092 SND_VOICE_CTRL
|
||||
uint2 voiceEnableLeft;
|
||||
uint2 voiceEnableRight;
|
||||
} r;
|
||||
};
|
||||
|
||||
extern APU apu;
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
auto APU::portRead(uint16 addr) -> uint8 {
|
||||
//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
|
||||
if(addr == 0x008e) return channel4.r.noiseMode;
|
||||
|
||||
//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 rand() & 0xff;
|
||||
if(addr == 0x0093) return rand() & 0x7f;
|
||||
|
||||
//SND_VOICE_CTRL
|
||||
if(addr == 0x0094) return (
|
||||
r.voiceEnableRight << 0
|
||||
| r.voiceEnableLeft << 2
|
||||
);
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto APU::portWrite(uint16 addr, uint8 data) -> void {
|
||||
//SND_CH1_PITCH
|
||||
if(addr == 0x0080) { channel1.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
||||
if(addr == 0x0081) { channel1.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
||||
|
||||
//SND_CH2_PITCH
|
||||
if(addr == 0x0082) { channel2.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
||||
if(addr == 0x0083) { channel2.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
||||
|
||||
//SND_CH3_PITCH
|
||||
if(addr == 0x0084) { channel3.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
||||
if(addr == 0x0085) { channel3.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
||||
|
||||
//SND_CH4_PITCH
|
||||
if(addr == 0x0086) { channel4.r.pitch.bits(0, 7) = data.bits(0,7); return; }
|
||||
if(addr == 0x0087) { channel4.r.pitch.bits(8,11) = data.bits(0,3); return; }
|
||||
|
||||
//SND_CH1_VOL
|
||||
if(addr == 0x0088) {
|
||||
channel1.r.volumeRight = data.bits(0,3);
|
||||
channel1.r.volumeLeft = data.bits(4,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_CH2_VOL
|
||||
if(addr == 0x0089) {
|
||||
channel2.r.volumeRight = data.bits(0,3);
|
||||
channel2.r.volumeLeft = data.bits(4,7);
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_CH3_VOL
|
||||
if(addr == 0x008a) {
|
||||
channel3.r.volumeRight = data.bits(0,3);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_SWEEP_VALUE
|
||||
if(addr == 0x008c) {
|
||||
channel3.r.sweepValue = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_SWEEP_TIME
|
||||
if(addr == 0x008d) {
|
||||
channel3.r.sweepTime = data.bits(0,4);
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_NOISE
|
||||
if(addr == 0x008e) {
|
||||
channel4.r.noiseMode = data.bits(0,4);
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_WAVE_BASE
|
||||
if(addr == 0x008f) {
|
||||
r.waveBase = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//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);
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_OUTPUT
|
||||
if(addr == 0x0091) {
|
||||
r.speakerEnable = data.bit (0);
|
||||
r.speakerShift = data.bits(1,2);
|
||||
r.headphoneEnable = data.bit (3);
|
||||
return;
|
||||
}
|
||||
|
||||
//SND_VOICE_CTRL
|
||||
if(addr == 0x0094) {
|
||||
r.voiceEnableRight = data.bits(0,1);
|
||||
r.voiceEnableLeft = data.bits(2,3);
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
namespace WonderSwan {
|
||||
|
||||
CPU cpu;
|
||||
#include "memory.cpp"
|
||||
#include "io.cpp"
|
||||
#include "interrupt.cpp"
|
||||
#include "dma.cpp"
|
||||
|
@ -61,14 +60,17 @@ auto CPU::power() -> void {
|
|||
iomap[0x0062] = this;
|
||||
}
|
||||
|
||||
r.dmaSource = 0x00000;
|
||||
r.dmaTarget = 0x0000;
|
||||
r.dmaLength = 0x0000;
|
||||
r.dmaEnable = false;
|
||||
r.dmaSource = 0;
|
||||
r.dmaTarget = 0;
|
||||
r.dmaLength = 0;
|
||||
r.dmaEnable = 0;
|
||||
r.dmaMode = 0;
|
||||
r.interruptBase = 0x00;
|
||||
r.interruptEnable = 0x00;
|
||||
r.interruptStatus = 0x00;
|
||||
r.interruptBase = 0;
|
||||
r.interruptEnable = 0;
|
||||
r.interruptStatus = 0;
|
||||
r.ypadEnable = 0;
|
||||
r.xpadEnable = 0;
|
||||
r.buttonEnable = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,10 +22,6 @@ struct CPU : Processor::V30MZ, Thread, IO {
|
|||
|
||||
auto power() -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto ramRead(uint16 addr) -> uint8;
|
||||
auto ramWrite(uint16 addr, uint8 data) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto keypadRead() -> uint4;
|
||||
auto portRead(uint16 addr) -> uint8 override;
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
auto CPU::ramRead(uint16 addr) -> uint8 {
|
||||
if(WS() && addr >= 0x4000) return 0x90;
|
||||
return iram[addr];
|
||||
}
|
||||
|
||||
auto CPU::ramWrite(uint16 addr, uint8 data) -> void {
|
||||
if(WS() && addr >= 0x4000) return;
|
||||
iram[addr] = data;
|
||||
}
|
|
@ -92,11 +92,11 @@ auto Interface::group(uint id) -> uint {
|
|||
case ID::ROM:
|
||||
case ID::RAM:
|
||||
case ID::EEPROM:
|
||||
switch(system.revision()) {
|
||||
case System::Revision::WonderSwan:
|
||||
switch(system.model()) {
|
||||
case System::Model::WonderSwan:
|
||||
return ID::WonderSwan;
|
||||
case System::Revision::WonderSwanColor:
|
||||
case System::Revision::SwanCrystal:
|
||||
case System::Model::WonderSwanColor:
|
||||
case System::Model::SwanCrystal:
|
||||
return ID::WonderSwanColor;
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +104,8 @@ auto Interface::group(uint id) -> uint {
|
|||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
if(id == ID::WonderSwan) system.load(System::Revision::WonderSwan);
|
||||
if(id == ID::WonderSwanColor) system.load(System::Revision::WonderSwanColor);
|
||||
if(id == ID::WonderSwan) system.load(System::Model::WonderSwan);
|
||||
if(id == ID::WonderSwanColor) system.load(System::Model::WonderSwanColor);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace WonderSwan {
|
||||
|
||||
uint8 iram[64 * 1024];
|
||||
IO* iomap[64 * 1024] = {nullptr};
|
||||
InternalRAM iram;
|
||||
Bus bus;
|
||||
|
||||
auto IO::power() -> void {
|
||||
|
@ -20,15 +20,32 @@ auto IO::portWrite(uint16 addr, uint8 data) -> void {
|
|||
//print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n");
|
||||
}
|
||||
|
||||
auto InternalRAM::power() -> void {
|
||||
for(auto& byte : memory) byte = 0x00;
|
||||
}
|
||||
|
||||
auto InternalRAM::read(uint16 addr, uint size) -> uint32 {
|
||||
if(size == Long) return read(addr + 0, Word) << 0 | read(addr + 2, Word) << 16;
|
||||
if(size == Word) return read(addr + 0, Byte) << 0 | read(addr + 1, Byte) << 8;
|
||||
|
||||
if(addr >= 0x4000 && !system.r.depth) return 0x90;
|
||||
return memory[addr];
|
||||
}
|
||||
|
||||
auto InternalRAM::write(uint16 addr, uint8 data) -> void {
|
||||
if(addr >= 0x4000 && !system.r.depth) return;
|
||||
memory[addr] = data;
|
||||
}
|
||||
|
||||
auto Bus::read(uint20 addr) -> uint8 {
|
||||
if(addr.bits(16,19) == 0) return cpu.ramRead(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) >= 2) return cartridge.romRead(addr);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
auto Bus::write(uint20 addr, uint8 data) -> void {
|
||||
if(addr.bits(16,19) == 0) return cpu.ramWrite(addr, data);
|
||||
if(addr.bits(16,19) == 0) return iram.write(addr, data);
|
||||
if(addr.bits(16,19) == 1) return cartridge.ramWrite(addr, data);
|
||||
if(addr.bits(16,19) >= 2) return cartridge.romWrite(addr, data);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,21 @@ struct IO {
|
|||
virtual auto portWrite(uint16 addr, uint8 data) -> void;
|
||||
};
|
||||
|
||||
struct InternalRAM {
|
||||
auto power() -> void;
|
||||
|
||||
auto read(uint16 addr, uint size = Byte) -> uint32;
|
||||
auto write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
uint8 memory[65536];
|
||||
};
|
||||
|
||||
struct Bus {
|
||||
auto read(uint20 addr) -> uint8;
|
||||
auto write(uint20 addr, uint8 data) -> void;
|
||||
};
|
||||
|
||||
extern uint8 iram[64 * 1024];
|
||||
extern IO* iomap[64 * 1024];
|
||||
extern InternalRAM iram;
|
||||
extern Bus bus;
|
||||
|
|
|
@ -12,7 +12,7 @@ auto PPU::portRead(uint16 addr) -> uint8 {
|
|||
}
|
||||
|
||||
//BACK_COLOR
|
||||
if(addr == 0x0001) return r.backColorPalette << 4 | r.backColorIndex << 0;
|
||||
if(addr == 0x0001) return r.backColor;
|
||||
|
||||
//LINE_CUR
|
||||
if(addr == 0x0002) return status.vclk;
|
||||
|
@ -105,16 +105,6 @@ auto PPU::portRead(uint16 addr) -> uint8 {
|
|||
);
|
||||
}
|
||||
|
||||
//DISP_MODE
|
||||
if(addr == 0x0060) {
|
||||
return (
|
||||
r.bpp << 7
|
||||
| r.color << 6
|
||||
| r.format << 5
|
||||
| r.u0060 << 0
|
||||
);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
|
@ -133,11 +123,9 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
|||
//BACK_COLOR
|
||||
if(addr == 0x0001) {
|
||||
if(WS()) {
|
||||
r.backColorPalette = 0;
|
||||
r.backColorIndex = data.bits(2,0);
|
||||
r.backColor = data.bits(0,2);
|
||||
} else {
|
||||
r.backColorPalette = data.bits(7,4);
|
||||
r.backColorIndex = data.bits(3,0);
|
||||
r.backColor = data.bits(0,7);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -296,13 +284,4 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
|||
r.palette[addr.bits(4,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0);
|
||||
return;
|
||||
}
|
||||
|
||||
//DISP_MODE
|
||||
if(addr == 0x0060) {
|
||||
r.bpp = data.bit(7);
|
||||
r.color = data.bit(6);
|
||||
r.format = data.bit(5);
|
||||
r.u0060 = data & 0b1011;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ namespace WonderSwan {
|
|||
|
||||
PPU ppu;
|
||||
#include "io.cpp"
|
||||
#include "render.cpp"
|
||||
#include "render-mono.cpp"
|
||||
#include "render-color.cpp"
|
||||
#include "video.cpp"
|
||||
|
||||
auto PPU::Enter() -> void {
|
||||
|
@ -14,10 +15,17 @@ auto PPU::Enter() -> void {
|
|||
auto PPU::main() -> void {
|
||||
if(status.vclk < 144) {
|
||||
for(uint x = 0; x < 224; x++) {
|
||||
renderBack();
|
||||
renderScreenOne();
|
||||
renderScreenTwo();
|
||||
renderSprite();
|
||||
if(!system.color()) {
|
||||
renderMonoBack();
|
||||
renderMonoScreenOne();
|
||||
renderMonoScreenTwo();
|
||||
renderMonoSprite();
|
||||
} else {
|
||||
renderColorBack();
|
||||
renderColorScreenOne();
|
||||
renderColorScreenTwo();
|
||||
renderColorSprite();
|
||||
}
|
||||
output[status.vclk * 224 + status.hclk] = pixel.color;
|
||||
step(1);
|
||||
}
|
||||
|
@ -60,14 +68,48 @@ auto PPU::power() -> void {
|
|||
|
||||
for(uint n = 0x0000; n <= 0x0017; n++) iomap[n] = this;
|
||||
for(uint n = 0x001c; n <= 0x003f; n++) iomap[n] = this;
|
||||
iomap[0x0060] = this;
|
||||
|
||||
for(auto& n : output) n = 0;
|
||||
|
||||
status.vclk = 0;
|
||||
status.hclk = 0;
|
||||
|
||||
r.screenTwoWindowEnable = 0;
|
||||
r.screenTwoWindowInvert = 0;
|
||||
r.spriteWindowEnable = 0;
|
||||
r.spriteEnable = 0;
|
||||
r.screenTwoEnable = 0;
|
||||
r.screenOneEnable = 0;
|
||||
r.backColor = 0;
|
||||
r.lineCompare = 0xff;
|
||||
r.spriteBase = 0;
|
||||
r.spriteFirst = 0;
|
||||
r.spriteCount = 0;
|
||||
r.screenTwoMapBase = 0;
|
||||
r.screenOneMapBase = 0;
|
||||
r.screenTwoWindowX0 = 0;
|
||||
r.screenTwoWindowY0 = 0;
|
||||
r.screenTwoWindowX1 = 0;
|
||||
r.screenTwoWindowY1 = 0;
|
||||
r.spriteWindowX0 = 0;
|
||||
r.spriteWindowY0 = 0;
|
||||
r.spriteWindowX1 = 0;
|
||||
r.spriteWindowY1 = 0;
|
||||
r.scrollOneX = 0;
|
||||
r.scrollOneY = 0;
|
||||
r.scrollTwoX = 0;
|
||||
r.scrollTwoY = 0;
|
||||
r.control = 0;
|
||||
r.iconAux3 = 0;
|
||||
r.iconAux2 = 0;
|
||||
r.iconAux1 = 0;
|
||||
r.iconHorizontal = 0;
|
||||
r.iconVertical = 0;
|
||||
r.iconSleep = 0;
|
||||
r.vtotal = 158;
|
||||
r.vblank = 155;
|
||||
for(auto& color : r.pool) color = 0;
|
||||
for(auto& p : r.palette) for(auto& color : p.color) color = 0;
|
||||
|
||||
video.power();
|
||||
}
|
||||
|
|
|
@ -12,11 +12,19 @@ struct PPU : Thread, IO {
|
|||
auto portRead(uint16 addr) -> uint8 override;
|
||||
auto portWrite(uint16 addr, uint8 data) -> void override;
|
||||
|
||||
//render.cpp
|
||||
auto renderBack() -> void;
|
||||
auto renderScreenOne() -> void;
|
||||
auto renderScreenTwo() -> void;
|
||||
auto renderSprite() -> void;
|
||||
//render-mono.cpp
|
||||
auto renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2;
|
||||
auto renderMonoBack() -> void;
|
||||
auto renderMonoScreenOne() -> void;
|
||||
auto renderMonoScreenTwo() -> void;
|
||||
auto renderMonoSprite() -> void;
|
||||
|
||||
//render-color.cpp
|
||||
auto renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4;
|
||||
auto renderColorBack() -> void;
|
||||
auto renderColorScreenOne() -> void;
|
||||
auto renderColorScreenTwo() -> void;
|
||||
auto renderColorSprite() -> void;
|
||||
|
||||
//state
|
||||
uint12 output[224 * 144];
|
||||
|
@ -34,16 +42,15 @@ struct PPU : Thread, IO {
|
|||
|
||||
struct Registers {
|
||||
//$0000 DISP_CTRL
|
||||
bool screenTwoWindowEnable;
|
||||
bool screenTwoWindowInvert;
|
||||
bool spriteWindowEnable;
|
||||
bool spriteEnable;
|
||||
bool screenTwoEnable;
|
||||
bool screenOneEnable;
|
||||
uint1 screenTwoWindowEnable;
|
||||
uint1 screenTwoWindowInvert;
|
||||
uint1 spriteWindowEnable;
|
||||
uint1 spriteEnable;
|
||||
uint1 screenTwoEnable;
|
||||
uint1 screenOneEnable;
|
||||
|
||||
//$0001 BACK_COLOR
|
||||
uint4 backColorIndex;
|
||||
uint4 backColorPalette;
|
||||
uint8 backColor;
|
||||
|
||||
//$0003 LINE_CMP
|
||||
uint8 lineCompare;
|
||||
|
@ -101,12 +108,12 @@ struct PPU : Thread, IO {
|
|||
uint8 control;
|
||||
|
||||
//$0015 LCD_ICON
|
||||
bool iconAux3;
|
||||
bool iconAux2;
|
||||
bool iconAux1;
|
||||
bool iconHorizontal;
|
||||
bool iconVertical;
|
||||
bool iconSleep;
|
||||
uint1 iconAux3;
|
||||
uint1 iconAux2;
|
||||
uint1 iconAux1;
|
||||
uint1 iconHorizontal;
|
||||
uint1 iconVertical;
|
||||
uint1 iconSleep;
|
||||
|
||||
//$0016 LCD_VTOTAL
|
||||
uint8 vtotal;
|
||||
|
@ -121,12 +128,6 @@ struct PPU : Thread, IO {
|
|||
struct Palette {
|
||||
uint3 color[4];
|
||||
} palette[16];
|
||||
|
||||
//$0060 DISP_MODE
|
||||
bool bpp;
|
||||
bool color;
|
||||
bool format;
|
||||
uint5 u0060; //unknown purpose
|
||||
} r;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
auto PPU::renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4 {
|
||||
uint4 color;
|
||||
|
||||
if(system.planar()) {
|
||||
uint32 data = iram.read(offset + (y << 2), Long);
|
||||
color |= data.bit( 7 - x) << 0;
|
||||
color |= data.bit(15 - x) << 1;
|
||||
color |= data.bit(23 - x) << 2;
|
||||
color |= data.bit(31 - x) << 3;
|
||||
}
|
||||
|
||||
if(system.packed()) {
|
||||
uint8 data = iram.read(offset + (y << 2) + (x >> 1));
|
||||
color = data >> (4 - (x.bit(0) << 2));
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
auto PPU::renderColorBack() -> void {
|
||||
uint12 color = iram.read(0xfe00 + (r.backColor << 1), Word);
|
||||
pixel = {Pixel::Source::Back, color};
|
||||
}
|
||||
|
||||
auto PPU::renderColorScreenOne() -> void {
|
||||
if(!r.screenOneEnable) return;
|
||||
|
||||
uint8 scrollY = status.vclk + r.scrollOneY;
|
||||
uint8 scrollX = status.hclk + r.scrollOneX;
|
||||
|
||||
uint16 tilemapOffset = r.screenOneMapBase << 11;
|
||||
tilemapOffset += (scrollY >> 3) << 6;
|
||||
tilemapOffset += (scrollX >> 3) << 1;
|
||||
|
||||
uint16 tile = iram.read(tilemapOffset, Word);
|
||||
uint16 tileOffset = 0x4000 + (tile.bit(13) << 14) + (tile.bits(0,8) << 5);
|
||||
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
|
||||
if(tileColor == 0) return;
|
||||
|
||||
uint12 color = iram.read(0xfe00 + (tile.bits(9, 12) << 5) + (tileColor << 1), Word);
|
||||
pixel = {Pixel::Source::ScreenOne, color};
|
||||
}
|
||||
|
||||
auto PPU::renderColorScreenTwo() -> void {
|
||||
if(!r.screenTwoEnable) return;
|
||||
|
||||
bool windowInside = status.vclk >= r.screenTwoWindowY0 && status.vclk <= r.screenTwoWindowY1
|
||||
&& status.hclk >= r.screenTwoWindowX0 && status.hclk <= r.screenTwoWindowX1;
|
||||
windowInside ^= r.screenTwoWindowInvert;
|
||||
if(r.screenTwoWindowEnable && !windowInside) return;
|
||||
|
||||
uint8 scrollY = status.vclk + r.scrollTwoY;
|
||||
uint8 scrollX = status.hclk + r.scrollTwoX;
|
||||
|
||||
uint16 tilemapOffset = r.screenTwoMapBase << 11;
|
||||
tilemapOffset += (scrollY >> 3) << 6;
|
||||
tilemapOffset += (scrollX >> 3) << 1;
|
||||
|
||||
uint16 tile = iram.read(tilemapOffset, Word);
|
||||
uint16 tileOffset = 0x4000 + (tile.bit(13) << 14) + (tile.bits(0,8) << 5);
|
||||
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
|
||||
if(tileColor == 0) return;
|
||||
|
||||
uint12 color = iram.read(0xfe00 + (tile.bits(9,12) << 5) + (tileColor << 1), Word);
|
||||
pixel = {Pixel::Source::ScreenTwo, color};
|
||||
}
|
||||
|
||||
auto PPU::renderColorSprite() -> void {
|
||||
if(!r.spriteEnable) return;
|
||||
|
||||
bool windowInside = status.vclk >= r.spriteWindowY0 && status.vclk <= r.spriteWindowY1
|
||||
&& status.hclk >= r.spriteWindowX0 && status.hclk <= r.spriteWindowX1;
|
||||
uint16 spriteBase = r.spriteBase << 9;
|
||||
|
||||
uint7 spriteIndex = r.spriteFirst;
|
||||
uint8 spriteCount = min(128, (uint)r.spriteCount);
|
||||
while(spriteCount--) {
|
||||
uint32 sprite = iram.read(spriteBase + (spriteIndex++ << 2), Long);
|
||||
if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue;
|
||||
|
||||
uint8 spriteY = sprite.bits(16,23);
|
||||
uint8 spriteX = sprite.bits(24,31);
|
||||
|
||||
if(status.vclk < spriteY) continue;
|
||||
if(status.vclk > (uint8)(spriteY + 7)) continue;
|
||||
if(status.hclk < spriteX) continue;
|
||||
if(status.hclk > (uint8)(spriteX + 7)) continue;
|
||||
|
||||
uint16 tileOffset = 0x4000 + (sprite.bits(0,8) << 5);
|
||||
uint3 tileY = (uint8)(status.vclk - spriteY) ^ (sprite.bit(15) ? 7 : 0);
|
||||
uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0);
|
||||
uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX);
|
||||
if(tileColor == 0) continue;
|
||||
if(!sprite.bit(13) && pixel.source == Pixel::Source::ScreenTwo) continue;
|
||||
|
||||
uint12 color = iram.read(0xff00 + (sprite.bits(9,11) << 5) + (tileColor << 1), Word);
|
||||
pixel = {Pixel::Source::Sprite, color};
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,47 +1,52 @@
|
|||
auto PPU::renderBack() -> void {
|
||||
uint4 poolColor = 15 - r.pool[r.backColorIndex];
|
||||
auto PPU::renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2 {
|
||||
uint2 color;
|
||||
|
||||
if(system.planar()) {
|
||||
uint16 data = iram.read(offset + (y << 1), Word);
|
||||
color |= data.bit( 7 - x) << 0;
|
||||
color |= data.bit(15 - x) << 1;
|
||||
}
|
||||
|
||||
if(system.packed()) {
|
||||
uint8 data = iram.read(offset + (y << 1) + (x >> 2));
|
||||
color = data >> (6 - (x.bits(0,1) << 1));
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
auto PPU::renderMonoBack() -> void {
|
||||
uint4 poolColor = 15 - r.pool[r.backColor.bits(0,2)];
|
||||
pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||
}
|
||||
|
||||
auto PPU::renderScreenOne() -> void {
|
||||
auto PPU::renderMonoScreenOne() -> void {
|
||||
if(!r.screenOneEnable) return;
|
||||
|
||||
uint8 scrollX = status.hclk + r.scrollOneX;
|
||||
uint8 scrollY = status.vclk + r.scrollOneY;
|
||||
uint8 scrollX = status.hclk + r.scrollOneX;
|
||||
|
||||
uint14 tilemapOffset = r.screenOneMapBase << 11;
|
||||
tilemapOffset += (scrollY >> 3) << 6;
|
||||
tilemapOffset += (scrollX >> 3) << 1;
|
||||
|
||||
uint16 tile;
|
||||
tile.byte(0) = iram[tilemapOffset++];
|
||||
tile.byte(1) = iram[tilemapOffset++];
|
||||
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint16 tile = iram.read(tilemapOffset, Word);
|
||||
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4);
|
||||
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
|
||||
|
||||
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1);
|
||||
uint8 d0 = iram[tileOffset++];
|
||||
uint8 d1 = iram[tileOffset++];
|
||||
|
||||
uint8 tileMask = 0x80 >> tileX;
|
||||
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
|
||||
if(tile.bit(11) && tileColor == 0) return;
|
||||
|
||||
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
|
||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
||||
|
||||
pixel = {Pixel::Source::ScreenOne, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||
}
|
||||
|
||||
auto PPU::renderScreenTwo() -> void {
|
||||
auto PPU::renderMonoScreenTwo() -> void {
|
||||
if(!r.screenTwoEnable) return;
|
||||
|
||||
bool windowInside = (
|
||||
status.hclk >= r.screenTwoWindowX0
|
||||
&& status.hclk <= r.screenTwoWindowX1
|
||||
&& status.vclk >= r.screenTwoWindowY0
|
||||
&& status.vclk <= r.screenTwoWindowY1
|
||||
);
|
||||
bool windowInside = status.vclk >= r.screenTwoWindowY0 && status.vclk <= r.screenTwoWindowY1
|
||||
&& status.hclk >= r.screenTwoWindowX0 && status.hclk <= r.screenTwoWindowX1;
|
||||
windowInside ^= r.screenTwoWindowInvert;
|
||||
if(r.screenTwoWindowEnable && !windowInside) return;
|
||||
|
||||
|
@ -52,74 +57,48 @@ auto PPU::renderScreenTwo() -> void {
|
|||
tilemapOffset += (scrollY >> 3) << 6;
|
||||
tilemapOffset += (scrollX >> 3) << 1;
|
||||
|
||||
uint16 tile;
|
||||
tile.byte(0) = iram[tilemapOffset++];
|
||||
tile.byte(1) = iram[tilemapOffset++];
|
||||
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint16 tile = iram.read(tilemapOffset, Word);
|
||||
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4);
|
||||
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
|
||||
|
||||
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1);
|
||||
uint8 d0 = iram[tileOffset++];
|
||||
uint8 d1 = iram[tileOffset++];
|
||||
|
||||
uint8 tileMask = 0x80 >> tileX;
|
||||
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
|
||||
|
||||
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
|
||||
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
|
||||
if(tile.bit(11) && tileColor == 0) return;
|
||||
|
||||
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
|
||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
||||
|
||||
pixel = {Pixel::Source::ScreenTwo, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||
}
|
||||
|
||||
auto PPU::renderSprite() -> void {
|
||||
auto PPU::renderMonoSprite() -> void {
|
||||
if(!r.spriteEnable) return;
|
||||
|
||||
bool windowInside = (
|
||||
status.hclk >= r.spriteWindowX0
|
||||
&& status.hclk <= r.spriteWindowX1
|
||||
&& status.vclk >= r.spriteWindowY0
|
||||
&& status.vclk <= r.spriteWindowY1
|
||||
);
|
||||
|
||||
bool windowInside = status.vclk >= r.spriteWindowY0 && status.vclk <= r.spriteWindowY1
|
||||
&& status.hclk >= r.spriteWindowX0 && status.hclk <= r.spriteWindowX1;
|
||||
uint14 spriteBase = r.spriteBase << 9;
|
||||
|
||||
uint7 spriteIndex = r.spriteFirst;
|
||||
uint8 spriteCount = min(128, (uint)r.spriteCount);
|
||||
while(spriteCount--) {
|
||||
uint32 sprite;
|
||||
sprite.byte(0) = iram[spriteBase + (spriteIndex << 2) + 0];
|
||||
sprite.byte(1) = iram[spriteBase + (spriteIndex << 2) + 1];
|
||||
sprite.byte(2) = iram[spriteBase + (spriteIndex << 2) + 2];
|
||||
sprite.byte(3) = iram[spriteBase + (spriteIndex << 2) + 3];
|
||||
spriteIndex++;
|
||||
|
||||
uint32 sprite = iram.read(spriteBase + (spriteIndex++ << 2), Long);
|
||||
if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue;
|
||||
|
||||
uint8 spriteY = sprite.bits(16,23);
|
||||
uint8 spriteX = sprite.bits(24,31);
|
||||
|
||||
if(status.hclk < spriteX) continue;
|
||||
if(status.hclk > (uint8)(spriteX + 7)) continue;
|
||||
if(status.vclk < spriteY) continue;
|
||||
if(status.vclk > (uint8)(spriteY + 7)) continue;
|
||||
if(status.hclk < spriteX) continue;
|
||||
if(status.hclk > (uint8)(spriteX + 7)) continue;
|
||||
|
||||
uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0);
|
||||
uint14 tileOffset = 0x2000 + (sprite.bits(0,8) << 4);
|
||||
uint3 tileY = (uint8)(status.vclk - spriteY) ^ (sprite.bit(15) ? 7 : 0);
|
||||
|
||||
uint14 tileOffset = 0x2000 + (sprite.bits(0,8) << 4) + (tileY << 1);
|
||||
uint8 d0 = iram[tileOffset++];
|
||||
uint8 d1 = iram[tileOffset++];
|
||||
|
||||
uint8 tileMask = 0x80 >> tileX;
|
||||
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
|
||||
|
||||
uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0);
|
||||
uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
|
||||
if(sprite.bit(11) && tileColor == 0) continue;
|
||||
if(!sprite.bit(13) && pixel.source == Pixel::Source::ScreenTwo) continue;
|
||||
|
||||
uint3 paletteColor = r.palette[8 + sprite.bits(9,11)].color[tileColor];
|
||||
uint4 poolColor = 15 - r.pool[paletteColor];
|
||||
|
||||
pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8};
|
||||
return;
|
||||
}
|
|
@ -28,8 +28,8 @@ auto Video::refresh() -> void {
|
|||
auto source = ppu.output + y * 224;
|
||||
for(uint x = 0; x < 224; x++) {
|
||||
auto color = paletteStandard[*source++];
|
||||
//*(output() + y * 224 + x) = color;
|
||||
*(output() + (223 - x) * 224 + 40 + y) = color;
|
||||
*(output() + (y + 40) * 224 + x) = color;
|
||||
//*(output() + (223 - x) * 224 + 40 + y) = color;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
auto System::portRead(uint16 addr) -> uint8 {
|
||||
//DISP_MODE
|
||||
if(addr == 0x0060) return (
|
||||
r.unknown << 0
|
||||
| r.format << 5
|
||||
| r.color << 6
|
||||
| r.depth << 7
|
||||
);
|
||||
|
||||
//IEEP_DATA
|
||||
if(addr == 0x00ba) return eeprom.read(EEPROM::DataLo);
|
||||
if(addr == 0x00bb) return eeprom.read(EEPROM::DataHi);
|
||||
|
@ -12,6 +20,15 @@ auto System::portRead(uint16 addr) -> uint8 {
|
|||
}
|
||||
|
||||
auto System::portWrite(uint16 addr, uint8 data) -> void {
|
||||
//DISP_MODE
|
||||
if(addr == 0x0060) {
|
||||
r.unknown = data.bits(0,4) & 0b01011;
|
||||
r.format = data.bit (5);
|
||||
r.color = data.bit (6);
|
||||
r.depth = data.bit (7);
|
||||
return;
|
||||
}
|
||||
|
||||
//IEEP_DATA
|
||||
if(addr == 0x00ba) return eeprom.write(EEPROM::DataLo, data);
|
||||
if(addr == 0x00bb) return eeprom.write(EEPROM::DataHi, data);
|
||||
|
|
|
@ -6,7 +6,10 @@ System system;
|
|||
#include "io.cpp"
|
||||
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
auto System::revision() const -> Revision { return _revision; }
|
||||
auto System::model() const -> Model { return _model; }
|
||||
auto System::color() const -> bool { return r.color; }
|
||||
auto System::planar() const -> bool { return r.format == 0; }
|
||||
auto System::packed() const -> bool { return r.format == 1; }
|
||||
|
||||
auto System::init() -> void {
|
||||
}
|
||||
|
@ -14,8 +17,8 @@ auto System::init() -> void {
|
|||
auto System::term() -> void {
|
||||
}
|
||||
|
||||
auto System::load(Revision revision) -> void {
|
||||
_revision = revision;
|
||||
auto System::load(Model model) -> void {
|
||||
_model = model;
|
||||
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
@ -45,6 +48,7 @@ auto System::unload() -> void {
|
|||
|
||||
auto System::power() -> void {
|
||||
IO::power();
|
||||
iram.power();
|
||||
eeprom.power();
|
||||
cpu.power();
|
||||
ppu.power();
|
||||
|
@ -52,7 +56,13 @@ auto System::power() -> void {
|
|||
cartridge.power();
|
||||
scheduler.power();
|
||||
|
||||
iomap[0x0060] = this;
|
||||
for(uint n = 0x00ba; n <= 0x00be; n++) iomap[n] = this;
|
||||
|
||||
r.depth = 0;
|
||||
r.color = 0;
|
||||
r.format = 0;
|
||||
r.unknown = 0;
|
||||
}
|
||||
|
||||
auto System::run() -> void {
|
||||
|
|
|
@ -5,18 +5,21 @@ enum class Keypad : uint {
|
|||
};
|
||||
|
||||
struct System : IO {
|
||||
enum class Revision : uint {
|
||||
enum class Model : uint {
|
||||
WonderSwan, //SW-001 (ASWAN)
|
||||
WonderSwanColor, //WSC-001 (SPHINX)
|
||||
SwanCrystal, //SCT-001 (SPHINX2)
|
||||
};
|
||||
|
||||
auto loaded() const -> bool;
|
||||
auto revision() const -> Revision;
|
||||
auto model() const -> Model;
|
||||
auto color() const -> bool;
|
||||
auto planar() const -> bool;
|
||||
auto packed() const -> bool;
|
||||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
auto load(Revision) -> void;
|
||||
auto load(Model) -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto run() -> void;
|
||||
|
@ -30,9 +33,17 @@ struct System : IO {
|
|||
|
||||
EEPROM eeprom;
|
||||
|
||||
struct Registers {
|
||||
//$0060 DISP_MODE
|
||||
uint1 depth;
|
||||
uint1 color;
|
||||
uint1 format;
|
||||
uint5 unknown;
|
||||
} r;
|
||||
|
||||
privileged:
|
||||
bool _loaded = false;
|
||||
Revision _revision = Revision::WonderSwan;
|
||||
Model _model = Model::WonderSwan;
|
||||
};
|
||||
|
||||
extern System system;
|
||||
|
|
|
@ -42,6 +42,8 @@ namespace WonderSwan {
|
|||
int64 clock = 0;
|
||||
};
|
||||
|
||||
enum : uint { Byte = 1, Word = 2, Long = 4 };
|
||||
|
||||
#include <ws/memory/memory.hpp>
|
||||
#include <ws/eeprom/eeprom.hpp>
|
||||
#include <ws/system/system.hpp>
|
||||
|
@ -51,9 +53,9 @@ namespace WonderSwan {
|
|||
#include <ws/ppu/ppu.hpp>
|
||||
#include <ws/apu/apu.hpp>
|
||||
|
||||
inline auto WS() { return system.revision() == System::Revision::WonderSwan; }
|
||||
inline auto WSC() { return system.revision() == System::Revision::WonderSwanColor; }
|
||||
inline auto SC() { return system.revision() == System::Revision::SwanCrystal; }
|
||||
inline auto WS() { return system.model() == System::Model::WonderSwan; }
|
||||
inline auto WSC() { return system.model() == System::Model::WonderSwanColor; }
|
||||
inline auto SC() { return system.model() == System::Model::SwanCrystal; }
|
||||
}
|
||||
|
||||
#include <ws/interface/interface.hpp>
|
||||
|
|
Loading…
Reference in New Issue