Update to v097r04 release.

byuu says:

Lots of improvements. We're now able to start executing some V30MZ
instructions. 32 of 256 opcodes implemented so far.

I hope this goes without saying, but there's absolutely no point in
loading WS/WSC games right now. You won't see anything until I have the
full CPU and partial PPU implemented.

ROM bank 2 works properly now, the I/O map is 16-bit (address) x 16-bit
(data) as it should be*, and I have a basic disassembler in place
(adding to it as I emulate new opcodes.)

(* I don't know what happens if you access an 8-bit port in 16-bit mode
or vice versa, so for now I'm just treating the handlers as always being
16-bit, and discarding the upper 8-bits when not needed.)
This commit is contained in:
Tim Allen 2016-01-28 22:39:49 +11:00
parent d7998b23ef
commit a8323d0d2b
24 changed files with 430 additions and 101 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.03"; static const string Version = "097.04";
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

@ -1,5 +1,3 @@
#include <cmath>
Video video; Video video;
Video::Video() { Video::Video() {

View File

@ -0,0 +1,83 @@
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers) -> string {
string s;
uint20 ea = (cs << 4) + ip;
auto readByte = [&](uint offset) {
uint8 byte = read((cs << 4) + (uint16)(ip + offset));
return hex(byte, 2L);
};
auto readWord = [&](uint offset) {
uint16 word = read((cs << 4) + (uint16)(ip + offset++)) << 0;
word | read((cs << 4) + (uint16)(ip + offset++)) << 8;
return hex(word, 4L);
};
uint8 opcode = read(ea);
switch(opcode) {
case 0x90: s = {"nop"}; break;
case 0xb0: s = {"mov al,", readByte(1)}; break;
case 0xb1: s = {"mov cl,", readByte(1)}; break;
case 0xb2: s = {"mov dl,", readByte(1)}; break;
case 0xb3: s = {"mov bl,", readByte(1)}; break;
case 0xb4: s = {"mov ah,", readByte(1)}; break;
case 0xb5: s = {"mov ch,", readByte(1)}; break;
case 0xb6: s = {"mov dh,", readByte(1)}; break;
case 0xb7: s = {"mov bh,", readByte(1)}; break;
case 0xb8: s = {"mov ax,", readWord(1)}; break;
case 0xb9: s = {"mov cx,", readWord(1)}; break;
case 0xba: s = {"mov dx,", readWord(1)}; break;
case 0xbb: s = {"mov bx,", readWord(1)}; break;
case 0xbc: s = {"mov sp,", readWord(1)}; break;
case 0xbd: s = {"mov bp,", readWord(1)}; break;
case 0xbe: s = {"mov si,", readWord(1)}; break;
case 0xbf: s = {"mov di,", readWord(1)}; break;
case 0xe4: s = {"in al,", readByte(1)}; break;
case 0xe5: s = {"in ax,", readByte(1)}; break;
case 0xe6: s = {"out ", readByte(1), ",al"}; break;
case 0xe7: s = {"out ", readByte(1), ",ax"}; break;
case 0xea: s = {"jmp ", readWord(3), ":", readWord(1)}; break;
case 0xec: s = {"in al,dx"}; break;
case 0xed: s = {"in ax,dx"}; break;
case 0xee: s = {"out dx,al"}; break;
case 0xef: s = {"out dx,ax"}; break;
case 0xf8: s = {"clc"}; break;
case 0xf9: s = {"stc"}; break;
case 0xfa: s = {"cli"}; break;
case 0xfb: s = {"sti"}; break;
case 0xfc: s = {"cld"}; break;
case 0xfd: s = {"std"}; break;
default:
s = {"??? [", hex(opcode, 2L), "]"};
}
while(s.size() < 20) s.append(" ");
if(!registers) return {hex(ea, 5L), " ", s};
return {
hex(ea, 5L), " ", s,
" ax:", hex(r.ax, 4L),
" bx:", hex(r.bx, 4L),
" cx:", hex(r.cx, 4L),
" dx:", hex(r.dx, 4L),
" si:", hex(r.si, 4L),
" di:", hex(r.di, 4L),
" bp:", hex(r.bp, 4L),
" sp:", hex(r.sp, 4L),
" cs:", hex(r.cs, 4L),
" ip:", hex(ip, 4L),
" ds:", hex(r.ds, 4L),
" es:", hex(r.es, 4L),
" ss:", hex(r.ss, 4L), " ",
r.f.m ? "M" : "m",
r.f.v ? "V" : "v",
r.f.d ? "D" : "d",
r.f.i ? "I" : "i",
r.f.b ? "B" : "b",
r.f.s ? "S" : "s",
r.f.z ? "Z" : "z",
r.f.h ? "H" : "h",
r.f.p ? "P" : "p",
r.f.c ? "C" : "c"
};
}

View File

@ -0,0 +1,61 @@
auto V30MZ::opJumpFar() {
auto ip = readWord();
auto cs = readWord();
r.ip = ip;
r.cs = cs;
}
auto V30MZ::opInByte() {
auto port = readByte();
r.al = in(port);
}
auto V30MZ::opInWord() {
auto port = readByte();
r.ax = in(port);
}
auto V30MZ::opOutByte() {
auto port = readByte();
out(port, r.al);
}
auto V30MZ::opOutWord() {
auto port = readByte();
out(port, r.ax);
}
auto V30MZ::opInDXByte() {
r.al = in(r.dx);
}
auto V30MZ::opInDXWord() {
r.ax = in(r.dx);
}
auto V30MZ::opOutDXByte() {
out(r.dx, r.al);
}
auto V30MZ::opOutDXWord() {
out(r.dx, r.ax);
}
auto V30MZ::opMoveRegisterImmediateByte(uint8& breg) {
breg = readByte();
}
auto V30MZ::opMoveRegisterImmediateWord(uint16& wreg) {
wreg = readWord();
}
auto V30MZ::opNoOperation() {
}
auto V30MZ::opClearFlag(bool& flag) {
flag = false;
}
auto V30MZ::opSetFlag(bool& flag) {
flag = true;
}

View File

@ -0,0 +1,8 @@
auto V30MZ::readByte() -> uint8 {
return read((r.cs << 4) + (r.ip++));
}
auto V30MZ::readWord() -> uint16 {
uint16 word = read((r.cs << 4) + (r.ip++)) << 0;
return word | read((r.cs << 4) + (r.ip++)) << 8;
}

View File

@ -0,0 +1,20 @@
V30MZ::Registers::Flags::operator uint16() const {
return m << 15 | 1 << 14 | 1 << 13 | 1 << 12
| v << 11 | d << 10 | i << 9 | b << 8
| s << 7 | z << 6 | h << 4 | p << 2
| 1 << 1 | c << 0;
}
auto V30MZ::Registers::Flags::operator=(uint16 data) {
m = (uint1)(data >> 15);
v = (uint1)(data >> 11);
d = (uint1)(data >> 10);
i = (uint1)(data >> 9);
b = (uint1)(data >> 8);
s = (uint1)(data >> 7);
z = (uint1)(data >> 6);
h = (uint1)(data >> 4);
p = (uint1)(data >> 2);
c = (uint1)(data >> 0);
return *this;
}

View File

@ -3,23 +3,85 @@
namespace Processor { namespace Processor {
#include "registers.cpp"
#include "memory.cpp"
#include "instructions.cpp"
#include "disassembler.cpp"
auto V30MZ::exec() -> void { auto V30MZ::exec() -> void {
step(1); if(halt) return wait(1);
#if 1
print(disassemble(r.cs, r.ip), "\n");
#endif
execOpcode();
}
auto V30MZ::execOpcode() -> void {
executed++;
uint8 opcode = readByte();
wait(1);
switch(opcode) {
case 0x90: return opNoOperation();
case 0xb0: return opMoveRegisterImmediateByte(r.al);
case 0xb1: return opMoveRegisterImmediateByte(r.cl);
case 0xb2: return opMoveRegisterImmediateByte(r.dl);
case 0xb3: return opMoveRegisterImmediateByte(r.bl);
case 0xb4: return opMoveRegisterImmediateByte(r.ah);
case 0xb5: return opMoveRegisterImmediateByte(r.ch);
case 0xb6: return opMoveRegisterImmediateByte(r.dh);
case 0xb7: return opMoveRegisterImmediateByte(r.bh);
case 0xb8: return opMoveRegisterImmediateWord(r.ax);
case 0xb9: return opMoveRegisterImmediateWord(r.cx);
case 0xba: return opMoveRegisterImmediateWord(r.dx);
case 0xbb: return opMoveRegisterImmediateWord(r.bx);
case 0xbc: return opMoveRegisterImmediateWord(r.sp);
case 0xbd: return opMoveRegisterImmediateWord(r.bp);
case 0xbe: return opMoveRegisterImmediateWord(r.si);
case 0xbf: return opMoveRegisterImmediateWord(r.di);
case 0xe4: return opInByte();
case 0xe5: return opInWord();
case 0xe6: return opOutByte();
case 0xe7: return opOutWord();
case 0xea: return opJumpFar();
case 0xec: return opInDXByte();
case 0xed: return opInDXWord();
case 0xee: return opOutDXByte();
case 0xef: return opOutDXWord();
case 0xf8: return opClearFlag(r.f.c);
case 0xf9: return opSetFlag(r.f.c);
case 0xfa: return opClearFlag(r.f.i);
case 0xfb: return opSetFlag(r.f.i);
case 0xfc: return opClearFlag(r.f.d);
case 0xfd: return opSetFlag(r.f.d);
}
print("error: unknown opcode: ", hex(opcode, 2L), "\n");
print("executed: ", --executed, "\n");
halt = true;
} }
auto V30MZ::power() -> void { auto V30MZ::power() -> void {
halt = false;
executed = 0;
r.ip = 0x0000;
r.ax = 0x0000; r.ax = 0x0000;
r.bx = 0x0000;
r.cx = 0x0000; r.cx = 0x0000;
r.dx = 0x0000; r.dx = 0x0000;
r.bx = 0x0000;
r.sp = 0x0000;
r.bp = 0x0000;
r.si = 0x0000; r.si = 0x0000;
r.di = 0x0000; r.di = 0x0000;
r.es = 0x0000; r.bp = 0x0000;
r.sp = 0x0000;
r.cs = 0xffff; r.cs = 0xffff;
r.ss = 0x0000;
r.ds = 0x0000; r.ds = 0x0000;
r.es = 0x0000;
r.ss = 0x0000;
r.f = 0x8000;
} }
} }

View File

@ -5,26 +5,72 @@
namespace Processor { namespace Processor {
struct V30MZ { struct V30MZ {
virtual auto step(uint clocks) -> void = 0; virtual auto wait(uint clocks = 1) -> void = 0;
virtual auto read(uint32 addr) -> uint8 = 0; virtual auto read(uint20 addr) -> uint8 = 0;
virtual auto write(uint32 addr, uint8 data) -> void = 0; virtual auto write(uint20 addr, uint8 data) -> void = 0;
virtual auto in(uint16 port) -> uint16 = 0;
virtual auto out(uint16 port, uint16 data) -> void = 0;
auto exec() -> void; auto exec() -> void;
auto execOpcode() -> void;
auto power() -> void; auto power() -> void;
//memory.cpp
auto readByte() -> uint8;
auto readWord() -> uint16;
//instructions.cpp
auto opJumpFar();
auto opInByte();
auto opInWord();
auto opOutByte();
auto opOutWord();
auto opInDXByte();
auto opInDXWord();
auto opOutDXByte();
auto opOutDXWord();
auto opMoveRegisterImmediateByte(uint8&);
auto opMoveRegisterImmediateWord(uint16&);
auto opNoOperation();
auto opClearFlag(bool&);
auto opSetFlag(bool&);
//disassembler.cpp
auto disassemble(uint16 cs, uint16 ip, bool registers = true) -> string;
//state
bool halt = false;
uint executed = 0;
struct Registers { struct Registers {
struct { uint16 ax; uint8 order_lsb2(al, ah); }; uint16 ip;
struct { uint16 cx; uint8 order_lsb2(cl, ch); }; union { struct { uint16 ax; uint8 order_lsb2(al, ah); }; };
struct { uint16 dx; uint8 order_lsb2(dl, dh); }; union { struct { uint16 bx; uint8 order_lsb2(bl, bh); }; };
struct { uint16 bx; uint8 order_lsb2(bl, bh); }; union { struct { uint16 cx; uint8 order_lsb2(cl, ch); }; };
uint16 sp; union { struct { uint16 dx; uint8 order_lsb2(dl, dh); }; };
uint16 bp;
uint16 si; uint16 si;
uint16 di; uint16 di;
uint16 es; uint16 bp;
uint16 sp;
uint16 cs; uint16 cs;
uint16 ss;
uint16 ds; uint16 ds;
uint16 es;
uint16 ss;
struct Flags {
operator uint16() const;
auto operator=(uint16 data);
bool m; //mode
bool v; //overflow
bool d; //direction
bool i; //interrupt
bool b; //break
bool s; //sign
bool z; //zero
bool h; //half-carry
bool p; //parity
bool c; //carry
} f;
} r; } r;
}; };

View File

@ -107,5 +107,6 @@ else ifeq ($(platform),macosx)
if [ -d /Applications/$(name).app ]; then rm -r /Applications/$(name).app; fi if [ -d /Applications/$(name).app ]; then rm -r /Applications/$(name).app; fi
else ifneq ($(filter $(platform),linux bsd),) else ifneq ($(filter $(platform),linux bsd),)
if [ -f $(prefix)/bin/$(name) ]; then rm $(prefix)/bin/$(name); fi if [ -f $(prefix)/bin/$(name) ]; then rm $(prefix)/bin/$(name); fi
if [ -f $(prefix)/share/applications/$(name).desktop ]; then rm $(prefix)/share/applications/$(name).desktop; fi
if [ -f $(prefix)/share/icons/$(name).png ]; then rm $(prefix)/share/icons/$(name).png; fi if [ -f $(prefix)/share/icons/$(name).png ]; then rm $(prefix)/share/icons/$(name).png; fi
endif endif

View File

@ -20,14 +20,16 @@ auto Cartridge::load() -> void {
if(auto node = document["board/rom"]) { if(auto node = document["board/rom"]) {
rom.name = node["name"].text(); rom.name = node["name"].text();
rom.size = node["size"].natural(); rom.size = node["size"].natural();
if(rom.size) rom.data = new uint8[rom.size](); rom.mask = bit::round(rom.size) - 1;
if(rom.size) rom.data = new uint8[rom.mask + 1]();
if(rom.name) interface->loadRequest(ID::ROM, rom.name, true); if(rom.name) interface->loadRequest(ID::ROM, rom.name, true);
} }
if(auto node = document["board/ram"]) { if(auto node = document["board/ram"]) {
ram.name = node["name"].text(); ram.name = node["name"].text();
ram.size = node["size"].natural(); ram.size = node["size"].natural();
if(ram.size) ram.data = new uint8[ram.size](); ram.mask = bit::round(ram.size) - 1;
if(ram.size) ram.data = new uint8[ram.mask + 1]();
if(ram.name) interface->loadRequest(ID::RAM, ram.name, true); if(ram.name) interface->loadRequest(ID::RAM, ram.name, true);
} }
@ -42,19 +44,21 @@ auto Cartridge::unload() -> void {
delete[] rom.data; delete[] rom.data;
rom.data = nullptr; rom.data = nullptr;
rom.size = 0; rom.size = 0;
rom.mask = 0;
rom.name = ""; rom.name = "";
delete[] ram.data; delete[] ram.data;
ram.data = nullptr; ram.data = nullptr;
ram.size = 0; ram.size = 0;
ram.mask = 0;
ram.name = ""; ram.name = "";
} }
auto Cartridge::power() -> void { auto Cartridge::power() -> void {
r.bank_rom0 = 0x00; r.bank_rom0 = 0xff;
r.bank_rom1 = 0x00; r.bank_rom1 = 0xff;
r.bank_rom2 = 0x00; r.bank_rom2 = 0xff;
r.bank_sram = 0x00; r.bank_sram = 0xff;
} }
} }

View File

@ -21,6 +21,7 @@ struct Cartridge {
struct Memory { struct Memory {
uint8* data = nullptr; uint8* data = nullptr;
uint size = 0; uint size = 0;
uint mask = 0;
string name; string name;
} rom, ram; } rom, ram;

View File

@ -1,12 +1,12 @@
//20000-fffff //20000-fffff
auto Cartridge::romRead(uint addr) -> uint8 { auto Cartridge::romRead(uint addr) -> uint8 {
switch(addr >> 16) { switch((uint4)(addr >> 16)) {
case 2: addr = r.bank_rom0 << 16 | (uint16)addr; break; //20000-2ffff case 2: addr = r.bank_rom0 << 16 | (uint16)addr; break; //20000-2ffff
case 3: addr = r.bank_rom1 << 16 | (uint16)addr; break; //30000-3ffff case 3: addr = r.bank_rom1 << 16 | (uint16)addr; break; //30000-3ffff
default: addr = r.bank_rom2 << 16 | (uint16)addr; break; //40000-fffff default: addr = r.bank_rom2 << 20 | (uint20)addr; break; //40000-fffff
} }
if(!rom.data || addr >= rom.size) return 0x00; if(!rom.data) return 0x00;
return rom.data[addr]; return rom.data[addr & rom.mask];
} }
auto Cartridge::romWrite(uint addr, uint8 data) -> void { auto Cartridge::romWrite(uint addr, uint8 data) -> void {
@ -15,12 +15,12 @@ auto Cartridge::romWrite(uint addr, uint8 data) -> void {
//10000-1ffff //10000-1ffff
auto Cartridge::ramRead(uint addr) -> uint8 { auto Cartridge::ramRead(uint addr) -> uint8 {
addr = r.bank_sram << 16 | (uint16)addr; addr = r.bank_sram << 16 | (uint16)addr;
if(!ram.data || addr >= ram.size) return 0x00; if(!ram.data) return 0x00;
return ram.data[addr]; return ram.data[addr & ram.mask];
} }
auto Cartridge::ramWrite(uint addr, uint8 data) -> void { auto Cartridge::ramWrite(uint addr, uint8 data) -> void {
addr = r.bank_sram << 16 | (uint16)addr; addr = r.bank_sram << 16 | (uint16)addr;
if(!ram.data || addr >= ram.size) return; if(!ram.data) return;
ram.data[addr] = data; ram.data[addr & ram.mask] = data;
} }

View File

@ -28,14 +28,26 @@ auto CPU::step(uint clocks) -> void {
if(apu.clock < 0) co_switch(apu.thread); if(apu.clock < 0) co_switch(apu.thread);
} }
auto CPU::read(uint32 addr) -> uint8 { auto CPU::wait(uint clocks) -> void {
step(clocks);
}
auto CPU::read(uint20 addr) -> uint8 {
return bus.read(addr); return bus.read(addr);
} }
auto CPU::write(uint32 addr, uint8 data) -> void { auto CPU::write(uint20 addr, uint8 data) -> void {
return bus.write(addr, data); return bus.write(addr, data);
} }
auto CPU::in(uint16 port) -> uint16 {
return iomap[port]->portRead(port);
}
auto CPU::out(uint16 port, uint16 data) -> void {
return iomap[port]->portWrite(port, data);
}
auto CPU::power() -> void { auto CPU::power() -> void {
V30MZ::power(); V30MZ::power();
create(CPU::Enter, 3072000); create(CPU::Enter, 3072000);

View File

@ -1,14 +1,23 @@
struct CPU : Processor::V30MZ, Thread { struct CPU : Processor::V30MZ, Thread, IO {
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
auto step(uint clocks) -> void override; auto step(uint clocks) -> void;
auto read(uint32 addr) -> uint8 override;
auto write(uint32 addr, uint8 data) -> void override; auto wait(uint clocks = 1) -> void override;
auto read(uint20 addr) -> uint8 override;
auto write(uint20 addr, uint8 data) -> void override;
auto in(uint16 port) -> uint16 override;
auto out(uint16 port, uint16 data) -> void override;
auto power() -> void; auto power() -> void;
auto ramRead(uint addr) -> uint8; //memory.cpp
auto ramWrite(uint addr, uint8 data) -> void; auto ramRead(uint16 addr) -> uint8;
auto ramWrite(uint16 addr, uint8 data) -> void;
auto portRead(uint16 addr) -> uint16 override;
auto portWrite(uint16 addr, uint16 data) -> void override;
}; };
extern CPU cpu; extern CPU cpu;

View File

@ -1,9 +1,16 @@
auto CPU::ramRead(uint addr) -> uint8 { auto CPU::ramRead(uint16 addr) -> uint8 {
uint mask = system.monochrome() ? 0x3fff : 0xffff; if(WS() && addr >= 0x4000) return 0x90;
return iram[addr & mask]; return iram[addr];
} }
auto CPU::ramWrite(uint addr, uint8 data) -> void { auto CPU::ramWrite(uint16 addr, uint8 data) -> void {
uint mask = system.monochrome() ? 0x3fff : 0xffff; if(WS() && addr >= 0x4000) return;
iram[addr & mask] = data; iram[addr] = data;
}
auto CPU::portRead(uint16 addr) -> uint16 {
return 0x0000;
}
auto CPU::portWrite(uint16 addr, uint16 data) -> void {
} }

View File

@ -21,24 +21,40 @@ Interface::Interface() {
media.append({ID::WonderSwan, "WonderSwan", "ws", true}); media.append({ID::WonderSwan, "WonderSwan", "ws", true});
media.append({ID::WonderSwanColor, "WonderSwan Color", "wsc", true}); media.append({ID::WonderSwanColor, "WonderSwan Color", "wsc", true});
{ Device device{0, ID::Device, "Controller"}; { Device device{0, ID::DeviceHorizontal, "Controller"};
device.input.append({ 0, 0, "X1" }); device.input.append({ 0, 0, "X1"});
device.input.append({ 1, 0, "X2" }); device.input.append({ 1, 0, "X2"});
device.input.append({ 2, 0, "X3" }); device.input.append({ 2, 0, "X3"});
device.input.append({ 3, 0, "X4" }); device.input.append({ 3, 0, "X4"});
device.input.append({ 4, 0, "Y1" }); device.input.append({ 4, 0, "Y1"});
device.input.append({ 5, 0, "Y2" }); device.input.append({ 5, 0, "Y2"});
device.input.append({ 6, 0, "Y3" }); device.input.append({ 6, 0, "Y3"});
device.input.append({ 7, 0, "Y4" }); device.input.append({ 7, 0, "Y4"});
device.input.append({ 8, 0, "B" }); device.input.append({ 8, 0, "B"});
device.input.append({ 9, 0, "A" }); device.input.append({ 9, 0, "A"});
device.input.append({10, 0, "Sound"}); device.input.append({10, 0, "Start"});
device.input.append({11, 0, "Start"}); device.order = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
device.order = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
this->device.append(device); this->device.append(device);
} }
port.append({0, "Device", {device[0]}}); { Device device{1, ID::DeviceVertical, "Controller"};
device.input.append({ 0, 0, "X1"});
device.input.append({ 1, 0, "X2"});
device.input.append({ 2, 0, "X3"});
device.input.append({ 3, 0, "X4"});
device.input.append({ 4, 0, "Y1"});
device.input.append({ 5, 0, "Y2"});
device.input.append({ 6, 0, "Y3"});
device.input.append({ 7, 0, "Y4"});
device.input.append({ 8, 0, "B"});
device.input.append({ 9, 0, "A"});
device.input.append({10, 0, "Start"});
device.order = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
this->device.append(device);
}
port.append({0, "Horizontal Orientation", {device[0]}});
port.append({1, "Vertical Orientation", {device[1]}});
} }
auto Interface::manifest() -> string { auto Interface::manifest() -> string {

View File

@ -16,7 +16,8 @@ struct ID {
}; };
enum : uint { enum : uint {
Device = 1, DeviceHorizontal = 1,
DeviceVertical = 2,
}; };
}; };

View File

@ -3,12 +3,21 @@
namespace WonderSwan { namespace WonderSwan {
uint8 iram[64 * 1024] = {0}; uint8 iram[64 * 1024] = {0};
IO* io[256]; IO* iomap[64 * 1024] = {0};
Bus bus; Bus bus;
auto IO::power() -> void { auto IO::power() -> void {
static IO unmapped; static IO unmapped;
for(auto& n : io) n = &unmapped; for(auto& n : iomap) n = &unmapped;
}
auto IO::portRead(uint16 addr) -> uint16 {
print("[", hex(addr, 4L), "]: port unmapped\n");
return 0x0000;
}
auto IO::portWrite(uint16 addr, uint16 data) -> void {
print("[", hex(addr, 4L), "] = ", hex(data, 4L), ": port unmapped\n");
} }
auto Bus::read(uint20 addr) -> uint8 { auto Bus::read(uint20 addr) -> uint8 {

View File

@ -1,8 +1,8 @@
struct IO { struct IO {
static auto power() -> void; static auto power() -> void;
virtual auto in(uint8 addr) -> uint8 { return 0x00; } virtual auto portRead(uint16 addr) -> uint16;
virtual auto out(uint8 addr, uint8 data) -> void {} virtual auto portWrite(uint16 addr, uint16 data) -> void;
}; };
struct Bus { struct Bus {
@ -11,5 +11,5 @@ struct Bus {
}; };
extern uint8 iram[64 * 1024]; extern uint8 iram[64 * 1024];
extern IO* io[256]; extern IO* iomap[64 * 1024];
extern Bus bus; extern Bus bus;

View File

@ -39,6 +39,8 @@ auto PPU::power() -> void {
status.vclk = 0; status.vclk = 0;
status.hclk = 0; status.hclk = 0;
video.power();
} }
} }

View File

@ -9,16 +9,6 @@ Video::Video() {
auto Video::power() -> void { auto Video::power() -> void {
memory::fill(output(), 224 * 224 * sizeof(uint32)); memory::fill(output(), 224 * 224 * sizeof(uint32));
if(system.monochrome()) {
for(auto color : range(16)) {
paletteLiteral[color] = color;
uint L = image::normalize(15 - color, 4, 16);
paletteStandard[color] = interface->videoColor(L, L, L);
}
}
if(system.color()) {
for(auto color : range(1 << 12)) { for(auto color : range(1 << 12)) {
paletteLiteral[color] = color; paletteLiteral[color] = color;
@ -31,7 +21,6 @@ auto Video::power() -> void {
B = image::normalize(B, 4, 16); B = image::normalize(B, 4, 16);
paletteStandard[color] = interface->videoColor(R, G, B); paletteStandard[color] = interface->videoColor(R, G, B);
} }
}
} }
auto Video::refresh() -> void { auto Video::refresh() -> void {

View File

@ -8,14 +8,6 @@ auto System::revision() const -> Revision {
return _revision; return _revision;
} }
auto System::monochrome() const -> bool {
return revision() == Revision::WonderSwan;
}
auto System::color() const -> bool {
return revision() != Revision::WonderSwan;
}
auto System::init() -> void { auto System::init() -> void {
} }
@ -28,6 +20,8 @@ auto System::load(Revision revision) -> void {
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);
//note: IPLROM is currently undumped; otherwise we'd load it here ...
cartridge.load(); cartridge.load();
} }

View File

@ -1,9 +1,11 @@
struct System { struct System {
enum class Revision : uint { WonderSwan, WonderSwanColor, SwanCrystal }; enum class Revision : uint {
WonderSwan, //SW-001 (ASWAN)
WonderSwanColor, //WSC-001 (SPHINX)
SwanCrystal, //SCT-001 (SPHINX2)
};
auto revision() const -> Revision; auto revision() const -> Revision;
auto monochrome() const -> bool;
auto color() const -> bool;
auto init() -> void; auto init() -> void;
auto term() -> void; auto term() -> void;
@ -16,7 +18,7 @@ struct System {
} information; } information;
privileged: privileged:
Revision _revision; Revision _revision = Revision::WonderSwan;
}; };
extern System system; extern System system;

View File

@ -49,6 +49,10 @@ namespace WonderSwan {
#include <ws/cpu/cpu.hpp> #include <ws/cpu/cpu.hpp>
#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 WSC() { return system.revision() == System::Revision::WonderSwanColor; }
inline auto SC() { return system.revision() == System::Revision::SwanCrystal; }
} }
#include <ws/interface/interface.hpp> #include <ws/interface/interface.hpp>