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:
Tim Allen
2016-03-08 22:34:00 +11:00
parent b0d2f5033e
commit 3d3ac8c1db
28 changed files with 766 additions and 177 deletions

View File

@@ -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.21"; static const string Version = "097.22";
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/";

View File

@@ -53,7 +53,7 @@ auto V30MZ::opGroup3MemImm(Size size) {
auto mem = getMem(size); auto mem = getMem(size);
switch(modrm.reg) { switch(modrm.reg) {
case 0: alAnd(size, mem, fetch(size)); break; 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 2: wait(2); setMem(size, alNot(size, mem)); break;
case 3: wait(2); setMem(size, alNeg(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; 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 //ff grp4 memw
auto V30MZ::opGroup4MemImm(Size size) { auto V30MZ::opGroup4MemImm(Size size) {
modRM(); modRM();
auto mem = getMem(size);
switch(modrm.reg) { switch(modrm.reg) {
case 0: wait(2); setMem(size, alInc(size, mem)); break; case 0:
case 1: wait(2); setMem(size, alDec(size, mem)); break; wait(2);
case 2: break; setMem(size, alInc(size, getMem(size)));
case 3: break; break;
case 4: break; case 1:
case 5: break; wait(2);
case 6: break; setMem(size, alDec(size, getMem(size)));
case 7: break; 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;
} }
} }

View File

@@ -65,6 +65,7 @@ auto V30MZ::opStoreString(Size size) {
auto V30MZ::opLoadString(Size size) { auto V30MZ::opLoadString(Size size) {
wait(2); wait(2);
setAcc(size, read(size, segment(r.ds), r.si)); setAcc(size, read(size, segment(r.ds), r.si));
r.si += r.f.d ? -size : size;
if(prefix.repeat && --r.cx) { if(prefix.repeat && --r.cx) {
state.prefix = true; state.prefix = true;
@@ -78,6 +79,7 @@ auto V30MZ::opScanString(Size size) {
wait(3); wait(3);
auto x = getAcc(size); auto x = getAcc(size);
auto y = read(size, r.es, r.di); auto y = read(size, r.es, r.di);
r.di += r.f.d ? -size : size;
alSub(size, x, y); alSub(size, x, y);
if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) { if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) {

View File

@@ -17,6 +17,10 @@ namespace Processor {
#include "instructions-string.cpp" #include "instructions-string.cpp"
#include "disassembler.cpp" #include "disassembler.cpp"
auto V30MZ::debug(string text) -> void {
print(text, "\n");
}
auto V30MZ::exec() -> void { auto V30MZ::exec() -> void {
state.poll = true; state.poll = true;
if(state.halt) return wait(1); if(state.halt) return wait(1);

View File

@@ -14,6 +14,7 @@ struct V30MZ {
virtual auto in(uint16 port) -> uint8 = 0; virtual auto in(uint16 port) -> uint8 = 0;
virtual auto out(uint16 port, uint8 data) -> void = 0; virtual auto out(uint16 port, uint8 data) -> void = 0;
auto debug(string text) -> void;
auto exec() -> void; auto exec() -> void;
auto instruction() -> void; auto instruction() -> void;
auto interrupt(uint8 vector) -> void; auto interrupt(uint8 vector) -> void;

View File

@@ -4,6 +4,23 @@ namespace SuperFamicom {
SuperDisc superdisc; 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 { auto SuperDisc::init() -> void {
} }
@@ -16,18 +33,77 @@ auto SuperDisc::unload() -> void {
} }
auto SuperDisc::power() -> void { auto SuperDisc::power() -> void {
create(&SuperDisc::Enter, 75);
} }
auto SuperDisc::reset() -> void { auto SuperDisc::reset() -> void {
r21e0 = 0x00;
r21e1 = 0x00;
r21e2 = 0x00;
r21e3 = 0x00;
r21e4 = 0x00;
r21e5 = 0x00;
} }
auto SuperDisc::read(uint24 addr, uint8 data) -> uint8 { auto SuperDisc::read(uint24 addr, uint8 data) -> uint8 {
addr = 0x21e0 | (addr & 7); 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; return data;
} }
auto SuperDisc::write(uint24 addr, uint8 data) -> void { auto SuperDisc::write(uint24 addr, uint8 data) -> void {
addr = 0x21e0 | (addr & 7); 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;
}
} }
} }

View File

@@ -1,4 +1,7 @@
struct SuperDisc : Memory { struct SuperDisc : Coprocessor, Memory {
static auto Enter() -> void;
auto main() -> void;
auto init() -> void; auto init() -> void;
auto load() -> void; auto load() -> void;
auto unload() -> void; auto unload() -> void;
@@ -9,6 +12,12 @@ struct SuperDisc : Memory {
auto write(uint24 addr, uint8 data) -> void; auto write(uint24 addr, uint8 data) -> void;
private: private:
uint8 r21e0;
uint8 r21e1;
uint8 r21e2;
uint8 r21e3;
uint8 r21e4;
uint8 r21e5;
}; };
extern SuperDisc superdisc; extern SuperDisc superdisc;

View File

@@ -69,8 +69,8 @@ namespace SuperFamicom {
#include <sfc/controller/controller.hpp> #include <sfc/controller/controller.hpp>
#include <sfc/system/system.hpp> #include <sfc/system/system.hpp>
#include <sfc/scheduler/scheduler.hpp> #include <sfc/scheduler/scheduler.hpp>
#include <sfc/expansion/expansion.hpp>
#include <sfc/coprocessor/coprocessor.hpp> #include <sfc/coprocessor/coprocessor.hpp>
#include <sfc/expansion/expansion.hpp>
#include <sfc/slot/slot.hpp> #include <sfc/slot/slot.hpp>
#include <sfc/cartridge/cartridge.hpp> #include <sfc/cartridge/cartridge.hpp>
#include <sfc/cheat/cheat.hpp> #include <sfc/cheat/cheat.hpp>

View File

@@ -209,6 +209,7 @@ auto System::reset() -> void {
if(cartridge.hasSharpRTC()) cpu.coprocessors.append(&sharprtc); if(cartridge.hasSharpRTC()) cpu.coprocessors.append(&sharprtc);
if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110); if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110);
if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1); if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1);
if(expansionPort() == Device::ID::SuperDisc) cpu.coprocessors.append(&superdisc);
scheduler.reset(); scheduler.reset();
device.connect(0, (Device::ID)settings.controllerPort1); device.connect(0, (Device::ID)settings.controllerPort1);

View File

@@ -3,6 +3,7 @@
namespace WonderSwan { namespace WonderSwan {
APU apu; APU apu;
#include "io.cpp"
auto APU::Enter() -> void { auto APU::Enter() -> void {
while(true) scheduler.synchronize(), apu.main(); while(true) scheduler.synchronize(), apu.main();
@@ -20,6 +21,41 @@ 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 = 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;
} }
} }

View File

@@ -1,8 +1,94 @@
struct APU : Thread { struct APU : Thread, IO {
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
auto step(uint clocks) -> void; auto step(uint clocks) -> void;
auto power() -> 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; extern APU apu;

181
higan/ws/apu/io.cpp Normal file
View File

@@ -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;
}
}

View File

@@ -3,7 +3,6 @@
namespace WonderSwan { namespace WonderSwan {
CPU cpu; CPU cpu;
#include "memory.cpp"
#include "io.cpp" #include "io.cpp"
#include "interrupt.cpp" #include "interrupt.cpp"
#include "dma.cpp" #include "dma.cpp"
@@ -61,14 +60,17 @@ auto CPU::power() -> void {
iomap[0x0062] = this; iomap[0x0062] = this;
} }
r.dmaSource = 0x00000; r.dmaSource = 0;
r.dmaTarget = 0x0000; r.dmaTarget = 0;
r.dmaLength = 0x0000; r.dmaLength = 0;
r.dmaEnable = false; r.dmaEnable = 0;
r.dmaMode = 0; r.dmaMode = 0;
r.interruptBase = 0x00; r.interruptBase = 0;
r.interruptEnable = 0x00; r.interruptEnable = 0;
r.interruptStatus = 0x00; r.interruptStatus = 0;
r.ypadEnable = 0;
r.xpadEnable = 0;
r.buttonEnable = 0;
} }
} }

View File

@@ -22,10 +22,6 @@ struct CPU : Processor::V30MZ, Thread, IO {
auto power() -> void; auto power() -> void;
//memory.cpp
auto ramRead(uint16 addr) -> uint8;
auto ramWrite(uint16 addr, uint8 data) -> void;
//io.cpp //io.cpp
auto keypadRead() -> uint4; auto keypadRead() -> uint4;
auto portRead(uint16 addr) -> uint8 override; auto portRead(uint16 addr) -> uint8 override;

View File

@@ -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;
}

View File

@@ -92,11 +92,11 @@ auto Interface::group(uint id) -> uint {
case ID::ROM: case ID::ROM:
case ID::RAM: case ID::RAM:
case ID::EEPROM: case ID::EEPROM:
switch(system.revision()) { switch(system.model()) {
case System::Revision::WonderSwan: case System::Model::WonderSwan:
return ID::WonderSwan; return ID::WonderSwan;
case System::Revision::WonderSwanColor: case System::Model::WonderSwanColor:
case System::Revision::SwanCrystal: case System::Model::SwanCrystal:
return ID::WonderSwanColor; return ID::WonderSwanColor;
} }
} }
@@ -104,8 +104,8 @@ auto Interface::group(uint id) -> uint {
} }
auto Interface::load(uint id) -> void { auto Interface::load(uint id) -> void {
if(id == ID::WonderSwan) system.load(System::Revision::WonderSwan); if(id == ID::WonderSwan) system.load(System::Model::WonderSwan);
if(id == ID::WonderSwanColor) system.load(System::Revision::WonderSwanColor); if(id == ID::WonderSwanColor) system.load(System::Model::WonderSwanColor);
} }
auto Interface::save() -> void { auto Interface::save() -> void {

View File

@@ -2,8 +2,8 @@
namespace WonderSwan { namespace WonderSwan {
uint8 iram[64 * 1024];
IO* iomap[64 * 1024] = {nullptr}; IO* iomap[64 * 1024] = {nullptr};
InternalRAM iram;
Bus bus; Bus bus;
auto IO::power() -> void { 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"); //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 { 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) == 1) return cartridge.ramRead(addr);
if(addr.bits(16,19) >= 2) return cartridge.romRead(addr); if(addr.bits(16,19) >= 2) return cartridge.romRead(addr);
unreachable; unreachable;
} }
auto Bus::write(uint20 addr, uint8 data) -> void { 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) == 1) return cartridge.ramWrite(addr, data);
if(addr.bits(16,19) >= 2) return cartridge.romWrite(addr, data); if(addr.bits(16,19) >= 2) return cartridge.romWrite(addr, data);
} }

View File

@@ -5,11 +5,21 @@ struct IO {
virtual auto portWrite(uint16 addr, uint8 data) -> void; 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 { struct Bus {
auto read(uint20 addr) -> uint8; auto read(uint20 addr) -> uint8;
auto write(uint20 addr, uint8 data) -> void; auto write(uint20 addr, uint8 data) -> void;
}; };
extern uint8 iram[64 * 1024];
extern IO* iomap[64 * 1024]; extern IO* iomap[64 * 1024];
extern InternalRAM iram;
extern Bus bus; extern Bus bus;

View File

@@ -12,7 +12,7 @@ auto PPU::portRead(uint16 addr) -> uint8 {
} }
//BACK_COLOR //BACK_COLOR
if(addr == 0x0001) return r.backColorPalette << 4 | r.backColorIndex << 0; if(addr == 0x0001) return r.backColor;
//LINE_CUR //LINE_CUR
if(addr == 0x0002) return status.vclk; 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; return 0x00;
} }
@@ -133,11 +123,9 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
//BACK_COLOR //BACK_COLOR
if(addr == 0x0001) { if(addr == 0x0001) {
if(WS()) { if(WS()) {
r.backColorPalette = 0; r.backColor = data.bits(0,2);
r.backColorIndex = data.bits(2,0);
} else { } else {
r.backColorPalette = data.bits(7,4); r.backColor = data.bits(0,7);
r.backColorIndex = data.bits(3,0);
} }
return; 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); r.palette[addr.bits(4,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0);
return; 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;
}
} }

View File

@@ -4,7 +4,8 @@ namespace WonderSwan {
PPU ppu; PPU ppu;
#include "io.cpp" #include "io.cpp"
#include "render.cpp" #include "render-mono.cpp"
#include "render-color.cpp"
#include "video.cpp" #include "video.cpp"
auto PPU::Enter() -> void { auto PPU::Enter() -> void {
@@ -14,10 +15,17 @@ auto PPU::Enter() -> void {
auto PPU::main() -> void { auto PPU::main() -> void {
if(status.vclk < 144) { if(status.vclk < 144) {
for(uint x = 0; x < 224; x++) { for(uint x = 0; x < 224; x++) {
renderBack(); if(!system.color()) {
renderScreenOne(); renderMonoBack();
renderScreenTwo(); renderMonoScreenOne();
renderSprite(); renderMonoScreenTwo();
renderMonoSprite();
} else {
renderColorBack();
renderColorScreenOne();
renderColorScreenTwo();
renderColorSprite();
}
output[status.vclk * 224 + status.hclk] = pixel.color; output[status.vclk * 224 + status.hclk] = pixel.color;
step(1); step(1);
} }
@@ -60,14 +68,48 @@ auto PPU::power() -> void {
for(uint n = 0x0000; n <= 0x0017; n++) iomap[n] = this; for(uint n = 0x0000; n <= 0x0017; n++) iomap[n] = this;
for(uint n = 0x001c; n <= 0x003f; n++) iomap[n] = this; for(uint n = 0x001c; n <= 0x003f; n++) iomap[n] = this;
iomap[0x0060] = this;
for(auto& n : output) n = 0; for(auto& n : output) n = 0;
status.vclk = 0; status.vclk = 0;
status.hclk = 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.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(); video.power();
} }

View File

@@ -12,11 +12,19 @@ struct PPU : Thread, IO {
auto portRead(uint16 addr) -> uint8 override; auto portRead(uint16 addr) -> uint8 override;
auto portWrite(uint16 addr, uint8 data) -> void override; auto portWrite(uint16 addr, uint8 data) -> void override;
//render.cpp //render-mono.cpp
auto renderBack() -> void; auto renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2;
auto renderScreenOne() -> void; auto renderMonoBack() -> void;
auto renderScreenTwo() -> void; auto renderMonoScreenOne() -> void;
auto renderSprite() -> 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 //state
uint12 output[224 * 144]; uint12 output[224 * 144];
@@ -34,16 +42,15 @@ struct PPU : Thread, IO {
struct Registers { struct Registers {
//$0000 DISP_CTRL //$0000 DISP_CTRL
bool screenTwoWindowEnable; uint1 screenTwoWindowEnable;
bool screenTwoWindowInvert; uint1 screenTwoWindowInvert;
bool spriteWindowEnable; uint1 spriteWindowEnable;
bool spriteEnable; uint1 spriteEnable;
bool screenTwoEnable; uint1 screenTwoEnable;
bool screenOneEnable; uint1 screenOneEnable;
//$0001 BACK_COLOR //$0001 BACK_COLOR
uint4 backColorIndex; uint8 backColor;
uint4 backColorPalette;
//$0003 LINE_CMP //$0003 LINE_CMP
uint8 lineCompare; uint8 lineCompare;
@@ -101,12 +108,12 @@ struct PPU : Thread, IO {
uint8 control; uint8 control;
//$0015 LCD_ICON //$0015 LCD_ICON
bool iconAux3; uint1 iconAux3;
bool iconAux2; uint1 iconAux2;
bool iconAux1; uint1 iconAux1;
bool iconHorizontal; uint1 iconHorizontal;
bool iconVertical; uint1 iconVertical;
bool iconSleep; uint1 iconSleep;
//$0016 LCD_VTOTAL //$0016 LCD_VTOTAL
uint8 vtotal; uint8 vtotal;
@@ -121,12 +128,6 @@ struct PPU : Thread, IO {
struct Palette { struct Palette {
uint3 color[4]; uint3 color[4];
} palette[16]; } palette[16];
//$0060 DISP_MODE
bool bpp;
bool color;
bool format;
uint5 u0060; //unknown purpose
} r; } r;
}; };

View File

@@ -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;
}
}

View File

@@ -1,47 +1,52 @@
auto PPU::renderBack() -> void { auto PPU::renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2 {
uint4 poolColor = 15 - r.pool[r.backColorIndex]; 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}; pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8};
} }
auto PPU::renderScreenOne() -> void { auto PPU::renderMonoScreenOne() -> void {
if(!r.screenOneEnable) return; if(!r.screenOneEnable) return;
uint8 scrollX = status.hclk + r.scrollOneX;
uint8 scrollY = status.vclk + r.scrollOneY; uint8 scrollY = status.vclk + r.scrollOneY;
uint8 scrollX = status.hclk + r.scrollOneX;
uint14 tilemapOffset = r.screenOneMapBase << 11; uint14 tilemapOffset = r.screenOneMapBase << 11;
tilemapOffset += (scrollY >> 3) << 6; tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1; tilemapOffset += (scrollX >> 3) << 1;
uint16 tile; uint16 tile = iram.read(tilemapOffset, Word);
tile.byte(0) = iram[tilemapOffset++]; uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4);
tile.byte(1) = iram[tilemapOffset++];
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1); uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
uint8 d0 = iram[tileOffset++]; if(tile.bit(11) && tileColor == 0) return;
uint8 d1 = iram[tileOffset++];
uint8 tileMask = 0x80 >> tileX;
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor]; uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
uint4 poolColor = 15 - r.pool[paletteColor]; uint4 poolColor = 15 - r.pool[paletteColor];
pixel = {Pixel::Source::ScreenOne, poolColor << 0 | poolColor << 4 | poolColor << 8}; pixel = {Pixel::Source::ScreenOne, poolColor << 0 | poolColor << 4 | poolColor << 8};
} }
auto PPU::renderScreenTwo() -> void { auto PPU::renderMonoScreenTwo() -> void {
if(!r.screenTwoEnable) return; if(!r.screenTwoEnable) return;
bool windowInside = ( bool windowInside = status.vclk >= r.screenTwoWindowY0 && status.vclk <= r.screenTwoWindowY1
status.hclk >= r.screenTwoWindowX0 && status.hclk >= r.screenTwoWindowX0 && status.hclk <= r.screenTwoWindowX1;
&& status.hclk <= r.screenTwoWindowX1
&& status.vclk >= r.screenTwoWindowY0
&& status.vclk <= r.screenTwoWindowY1
);
windowInside ^= r.screenTwoWindowInvert; windowInside ^= r.screenTwoWindowInvert;
if(r.screenTwoWindowEnable && !windowInside) return; if(r.screenTwoWindowEnable && !windowInside) return;
@@ -52,74 +57,48 @@ auto PPU::renderScreenTwo() -> void {
tilemapOffset += (scrollY >> 3) << 6; tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1; tilemapOffset += (scrollX >> 3) << 1;
uint16 tile; uint16 tile = iram.read(tilemapOffset, Word);
tile.byte(0) = iram[tilemapOffset++]; uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4);
tile.byte(1) = iram[tilemapOffset++];
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0);
uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0);
uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1); uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
uint8 d0 = iram[tileOffset++];
uint8 d1 = iram[tileOffset++];
uint8 tileMask = 0x80 >> tileX;
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
if(tile.bit(11) && tileColor == 0) return; if(tile.bit(11) && tileColor == 0) return;
uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor]; uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor];
uint4 poolColor = 15 - r.pool[paletteColor]; uint4 poolColor = 15 - r.pool[paletteColor];
pixel = {Pixel::Source::ScreenTwo, poolColor << 0 | poolColor << 4 | poolColor << 8}; pixel = {Pixel::Source::ScreenTwo, poolColor << 0 | poolColor << 4 | poolColor << 8};
} }
auto PPU::renderSprite() -> void { auto PPU::renderMonoSprite() -> void {
if(!r.spriteEnable) return; if(!r.spriteEnable) return;
bool windowInside = ( bool windowInside = status.vclk >= r.spriteWindowY0 && status.vclk <= r.spriteWindowY1
status.hclk >= r.spriteWindowX0 && status.hclk >= r.spriteWindowX0 && status.hclk <= r.spriteWindowX1;
&& status.hclk <= r.spriteWindowX1
&& status.vclk >= r.spriteWindowY0
&& status.vclk <= r.spriteWindowY1
);
uint14 spriteBase = r.spriteBase << 9; uint14 spriteBase = r.spriteBase << 9;
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 sprite; uint32 sprite = iram.read(spriteBase + (spriteIndex++ << 2), Long);
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++;
if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue; if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue;
uint8 spriteY = sprite.bits(16,23); uint8 spriteY = sprite.bits(16,23);
uint8 spriteX = sprite.bits(24,31); 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 < spriteY) continue;
if(status.vclk > (uint8)(spriteY + 7)) 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); uint3 tileY = (uint8)(status.vclk - spriteY) ^ (sprite.bit(15) ? 7 : 0);
uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0);
uint14 tileOffset = 0x2000 + (sprite.bits(0,8) << 4) + (tileY << 1); uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX);
uint8 d0 = iram[tileOffset++];
uint8 d1 = iram[tileOffset++];
uint8 tileMask = 0x80 >> tileX;
uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0);
if(sprite.bit(11) && tileColor == 0) continue; if(sprite.bit(11) && tileColor == 0) continue;
if(!sprite.bit(13) && pixel.source == Pixel::Source::ScreenTwo) continue; if(!sprite.bit(13) && pixel.source == Pixel::Source::ScreenTwo) continue;
uint3 paletteColor = r.palette[8 + sprite.bits(9,11)].color[tileColor]; uint3 paletteColor = r.palette[8 + sprite.bits(9,11)].color[tileColor];
uint4 poolColor = 15 - r.pool[paletteColor]; uint4 poolColor = 15 - r.pool[paletteColor];
pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8}; pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8};
return; return;
} }

View File

@@ -28,8 +28,8 @@ auto Video::refresh() -> void {
auto source = ppu.output + y * 224; auto source = ppu.output + y * 224;
for(uint x = 0; x < 224; x++) { for(uint x = 0; x < 224; x++) {
auto color = paletteStandard[*source++]; auto color = paletteStandard[*source++];
//*(output() + y * 224 + x) = color; *(output() + (y + 40) * 224 + x) = color;
*(output() + (223 - x) * 224 + 40 + y) = color; //*(output() + (223 - x) * 224 + 40 + y) = color;
} }
} }

View File

@@ -1,4 +1,12 @@
auto System::portRead(uint16 addr) -> uint8 { 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 //IEEP_DATA
if(addr == 0x00ba) return eeprom.read(EEPROM::DataLo); if(addr == 0x00ba) return eeprom.read(EEPROM::DataLo);
if(addr == 0x00bb) return eeprom.read(EEPROM::DataHi); 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 { 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 //IEEP_DATA
if(addr == 0x00ba) return eeprom.write(EEPROM::DataLo, data); if(addr == 0x00ba) return eeprom.write(EEPROM::DataLo, data);
if(addr == 0x00bb) return eeprom.write(EEPROM::DataHi, data); if(addr == 0x00bb) return eeprom.write(EEPROM::DataHi, data);

View File

@@ -6,7 +6,10 @@ System system;
#include "io.cpp" #include "io.cpp"
auto System::loaded() const -> bool { return _loaded; } 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 { auto System::init() -> void {
} }
@@ -14,8 +17,8 @@ auto System::init() -> void {
auto System::term() -> void { auto System::term() -> void {
} }
auto System::load(Revision revision) -> void { auto System::load(Model model) -> void {
_revision = revision; _model = model;
interface->loadRequest(ID::SystemManifest, "manifest.bml", true); interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
auto document = BML::unserialize(information.manifest); auto document = BML::unserialize(information.manifest);
@@ -45,6 +48,7 @@ auto System::unload() -> void {
auto System::power() -> void { auto System::power() -> void {
IO::power(); IO::power();
iram.power();
eeprom.power(); eeprom.power();
cpu.power(); cpu.power();
ppu.power(); ppu.power();
@@ -52,7 +56,13 @@ auto System::power() -> void {
cartridge.power(); cartridge.power();
scheduler.power(); scheduler.power();
iomap[0x0060] = this;
for(uint n = 0x00ba; n <= 0x00be; n++) iomap[n] = 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 { auto System::run() -> void {

View File

@@ -5,18 +5,21 @@ enum class Keypad : uint {
}; };
struct System : IO { struct System : IO {
enum class Revision : uint { enum class Model : uint {
WonderSwan, //SW-001 (ASWAN) WonderSwan, //SW-001 (ASWAN)
WonderSwanColor, //WSC-001 (SPHINX) WonderSwanColor, //WSC-001 (SPHINX)
SwanCrystal, //SCT-001 (SPHINX2) SwanCrystal, //SCT-001 (SPHINX2)
}; };
auto loaded() const -> bool; 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 init() -> void;
auto term() -> void; auto term() -> void;
auto load(Revision) -> void; auto load(Model) -> void;
auto unload() -> void; auto unload() -> void;
auto power() -> void; auto power() -> void;
auto run() -> void; auto run() -> void;
@@ -30,9 +33,17 @@ struct System : IO {
EEPROM eeprom; EEPROM eeprom;
struct Registers {
//$0060 DISP_MODE
uint1 depth;
uint1 color;
uint1 format;
uint5 unknown;
} r;
privileged: privileged:
bool _loaded = false; bool _loaded = false;
Revision _revision = Revision::WonderSwan; Model _model = Model::WonderSwan;
}; };
extern System system; extern System system;

View File

@@ -42,6 +42,8 @@ namespace WonderSwan {
int64 clock = 0; int64 clock = 0;
}; };
enum : uint { Byte = 1, Word = 2, Long = 4 };
#include <ws/memory/memory.hpp> #include <ws/memory/memory.hpp>
#include <ws/eeprom/eeprom.hpp> #include <ws/eeprom/eeprom.hpp>
#include <ws/system/system.hpp> #include <ws/system/system.hpp>
@@ -51,9 +53,9 @@ namespace WonderSwan {
#include <ws/ppu/ppu.hpp> #include <ws/ppu/ppu.hpp>
#include <ws/apu/apu.hpp> #include <ws/apu/apu.hpp>
inline auto WS() { return system.revision() == System::Revision::WonderSwan; } inline auto WS() { return system.model() == System::Model::WonderSwan; }
inline auto WSC() { return system.revision() == System::Revision::WonderSwanColor; } inline auto WSC() { return system.model() == System::Model::WonderSwanColor; }
inline auto SC() { return system.revision() == System::Revision::SwanCrystal; } inline auto SC() { return system.model() == System::Model::SwanCrystal; }
} }
#include <ws/interface/interface.hpp> #include <ws/interface/interface.hpp>