From a8323d0d2b627f60e9b7f93fc928ed8772cddedc Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 28 Jan 2016 22:39:49 +1100 Subject: [PATCH] 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.) --- higan/emulator/emulator.hpp | 2 +- higan/fc/ppu/video.cpp | 2 - higan/processor/v30mz/disassembler.cpp | 83 ++++++++++++++++++++++++++ higan/processor/v30mz/instructions.cpp | 61 +++++++++++++++++++ higan/processor/v30mz/memory.cpp | 8 +++ higan/processor/v30mz/registers.cpp | 20 +++++++ higan/processor/v30mz/v30mz.cpp | 74 +++++++++++++++++++++-- higan/processor/v30mz/v30mz.hpp | 68 +++++++++++++++++---- higan/target-tomoko/GNUmakefile | 1 + higan/ws/cartridge/cartridge.cpp | 16 +++-- higan/ws/cartridge/cartridge.hpp | 1 + higan/ws/cartridge/memory.cpp | 16 ++--- higan/ws/cpu/cpu.cpp | 16 ++++- higan/ws/cpu/cpu.hpp | 21 +++++-- higan/ws/cpu/memory.cpp | 19 ++++-- higan/ws/interface/interface.cpp | 46 +++++++++----- higan/ws/interface/interface.hpp | 3 +- higan/ws/memory/memory.cpp | 13 +++- higan/ws/memory/memory.hpp | 6 +- higan/ws/ppu/ppu.cpp | 2 + higan/ws/ppu/video.cpp | 29 +++------ higan/ws/system/system.cpp | 10 +--- higan/ws/system/system.hpp | 10 ++-- higan/ws/ws.hpp | 4 ++ 24 files changed, 430 insertions(+), 101 deletions(-) create mode 100644 higan/processor/v30mz/disassembler.cpp create mode 100644 higan/processor/v30mz/instructions.cpp create mode 100644 higan/processor/v30mz/memory.cpp create mode 100644 higan/processor/v30mz/registers.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index a16a9c63..13b4d982 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -6,7 +6,7 @@ using namespace nall; namespace Emulator { 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 License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/fc/ppu/video.cpp b/higan/fc/ppu/video.cpp index 36443a48..476f342f 100644 --- a/higan/fc/ppu/video.cpp +++ b/higan/fc/ppu/video.cpp @@ -1,5 +1,3 @@ -#include - Video video; Video::Video() { diff --git a/higan/processor/v30mz/disassembler.cpp b/higan/processor/v30mz/disassembler.cpp new file mode 100644 index 00000000..f13591d6 --- /dev/null +++ b/higan/processor/v30mz/disassembler.cpp @@ -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" + }; +} diff --git a/higan/processor/v30mz/instructions.cpp b/higan/processor/v30mz/instructions.cpp new file mode 100644 index 00000000..819a7963 --- /dev/null +++ b/higan/processor/v30mz/instructions.cpp @@ -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; +} diff --git a/higan/processor/v30mz/memory.cpp b/higan/processor/v30mz/memory.cpp new file mode 100644 index 00000000..c45d16d9 --- /dev/null +++ b/higan/processor/v30mz/memory.cpp @@ -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; +} diff --git a/higan/processor/v30mz/registers.cpp b/higan/processor/v30mz/registers.cpp new file mode 100644 index 00000000..47958c4e --- /dev/null +++ b/higan/processor/v30mz/registers.cpp @@ -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; +} diff --git a/higan/processor/v30mz/v30mz.cpp b/higan/processor/v30mz/v30mz.cpp index cc048a06..fedafe99 100644 --- a/higan/processor/v30mz/v30mz.cpp +++ b/higan/processor/v30mz/v30mz.cpp @@ -3,23 +3,85 @@ namespace Processor { +#include "registers.cpp" +#include "memory.cpp" +#include "instructions.cpp" +#include "disassembler.cpp" + 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 { + halt = false; + executed = 0; + + r.ip = 0x0000; r.ax = 0x0000; + r.bx = 0x0000; r.cx = 0x0000; r.dx = 0x0000; - r.bx = 0x0000; - r.sp = 0x0000; - r.bp = 0x0000; r.si = 0x0000; r.di = 0x0000; - r.es = 0x0000; + r.bp = 0x0000; + r.sp = 0x0000; r.cs = 0xffff; - r.ss = 0x0000; r.ds = 0x0000; + r.es = 0x0000; + r.ss = 0x0000; + r.f = 0x8000; } } diff --git a/higan/processor/v30mz/v30mz.hpp b/higan/processor/v30mz/v30mz.hpp index 8f6794ee..5b75684f 100644 --- a/higan/processor/v30mz/v30mz.hpp +++ b/higan/processor/v30mz/v30mz.hpp @@ -5,26 +5,72 @@ namespace Processor { struct V30MZ { - virtual auto step(uint clocks) -> void = 0; - virtual auto read(uint32 addr) -> uint8 = 0; - virtual auto write(uint32 addr, uint8 data) -> void = 0; + virtual auto wait(uint clocks = 1) -> void = 0; + virtual auto read(uint20 addr) -> uint8 = 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 execOpcode() -> 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 { uint16 ax; uint8 order_lsb2(al, ah); }; - struct { uint16 cx; uint8 order_lsb2(cl, ch); }; - struct { uint16 dx; uint8 order_lsb2(dl, dh); }; - struct { uint16 bx; uint8 order_lsb2(bl, bh); }; - uint16 sp; - uint16 bp; + uint16 ip; + union { struct { uint16 ax; uint8 order_lsb2(al, ah); }; }; + union { struct { uint16 bx; uint8 order_lsb2(bl, bh); }; }; + union { struct { uint16 cx; uint8 order_lsb2(cl, ch); }; }; + union { struct { uint16 dx; uint8 order_lsb2(dl, dh); }; }; uint16 si; uint16 di; - uint16 es; + uint16 bp; + uint16 sp; uint16 cs; - uint16 ss; 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; }; diff --git a/higan/target-tomoko/GNUmakefile b/higan/target-tomoko/GNUmakefile index 02359d74..3bd16503 100644 --- a/higan/target-tomoko/GNUmakefile +++ b/higan/target-tomoko/GNUmakefile @@ -107,5 +107,6 @@ else ifeq ($(platform),macosx) if [ -d /Applications/$(name).app ]; then rm -r /Applications/$(name).app; fi else ifneq ($(filter $(platform),linux bsd),) 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 endif diff --git a/higan/ws/cartridge/cartridge.cpp b/higan/ws/cartridge/cartridge.cpp index 34d5e0b2..acd1ecc0 100644 --- a/higan/ws/cartridge/cartridge.cpp +++ b/higan/ws/cartridge/cartridge.cpp @@ -20,14 +20,16 @@ auto Cartridge::load() -> void { if(auto node = document["board/rom"]) { rom.name = node["name"].text(); 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(auto node = document["board/ram"]) { ram.name = node["name"].text(); 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); } @@ -42,19 +44,21 @@ auto Cartridge::unload() -> void { delete[] rom.data; rom.data = nullptr; rom.size = 0; + rom.mask = 0; rom.name = ""; delete[] ram.data; ram.data = nullptr; ram.size = 0; + ram.mask = 0; ram.name = ""; } auto Cartridge::power() -> void { - r.bank_rom0 = 0x00; - r.bank_rom1 = 0x00; - r.bank_rom2 = 0x00; - r.bank_sram = 0x00; + r.bank_rom0 = 0xff; + r.bank_rom1 = 0xff; + r.bank_rom2 = 0xff; + r.bank_sram = 0xff; } } diff --git a/higan/ws/cartridge/cartridge.hpp b/higan/ws/cartridge/cartridge.hpp index 2d1bca54..712b0c37 100644 --- a/higan/ws/cartridge/cartridge.hpp +++ b/higan/ws/cartridge/cartridge.hpp @@ -21,6 +21,7 @@ struct Cartridge { struct Memory { uint8* data = nullptr; uint size = 0; + uint mask = 0; string name; } rom, ram; diff --git a/higan/ws/cartridge/memory.cpp b/higan/ws/cartridge/memory.cpp index 116da69e..67b8584b 100644 --- a/higan/ws/cartridge/memory.cpp +++ b/higan/ws/cartridge/memory.cpp @@ -1,12 +1,12 @@ //20000-fffff 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 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; - return rom.data[addr]; + if(!rom.data) return 0x00; + return rom.data[addr & rom.mask]; } auto Cartridge::romWrite(uint addr, uint8 data) -> void { @@ -15,12 +15,12 @@ auto Cartridge::romWrite(uint addr, uint8 data) -> void { //10000-1ffff auto Cartridge::ramRead(uint addr) -> uint8 { addr = r.bank_sram << 16 | (uint16)addr; - if(!ram.data || addr >= ram.size) return 0x00; - return ram.data[addr]; + if(!ram.data) return 0x00; + return ram.data[addr & ram.mask]; } auto Cartridge::ramWrite(uint addr, uint8 data) -> void { addr = r.bank_sram << 16 | (uint16)addr; - if(!ram.data || addr >= ram.size) return; - ram.data[addr] = data; + if(!ram.data) return; + ram.data[addr & ram.mask] = data; } diff --git a/higan/ws/cpu/cpu.cpp b/higan/ws/cpu/cpu.cpp index 80438b9c..b79b3d2c 100644 --- a/higan/ws/cpu/cpu.cpp +++ b/higan/ws/cpu/cpu.cpp @@ -28,14 +28,26 @@ auto CPU::step(uint clocks) -> void { 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); } -auto CPU::write(uint32 addr, uint8 data) -> void { +auto CPU::write(uint20 addr, uint8 data) -> void { 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 { V30MZ::power(); create(CPU::Enter, 3072000); diff --git a/higan/ws/cpu/cpu.hpp b/higan/ws/cpu/cpu.hpp index 4685c7d9..45d9d713 100644 --- a/higan/ws/cpu/cpu.hpp +++ b/higan/ws/cpu/cpu.hpp @@ -1,14 +1,23 @@ -struct CPU : Processor::V30MZ, Thread { +struct CPU : Processor::V30MZ, Thread, IO { static auto Enter() -> void; auto main() -> void; - auto step(uint clocks) -> void override; - auto read(uint32 addr) -> uint8 override; - auto write(uint32 addr, uint8 data) -> void override; + auto step(uint clocks) -> void; + + 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 ramRead(uint addr) -> uint8; - auto ramWrite(uint addr, uint8 data) -> void; + //memory.cpp + 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; diff --git a/higan/ws/cpu/memory.cpp b/higan/ws/cpu/memory.cpp index faa2812c..7f642b82 100644 --- a/higan/ws/cpu/memory.cpp +++ b/higan/ws/cpu/memory.cpp @@ -1,9 +1,16 @@ -auto CPU::ramRead(uint addr) -> uint8 { - uint mask = system.monochrome() ? 0x3fff : 0xffff; - return iram[addr & mask]; +auto CPU::ramRead(uint16 addr) -> uint8 { + if(WS() && addr >= 0x4000) return 0x90; + return iram[addr]; } -auto CPU::ramWrite(uint addr, uint8 data) -> void { - uint mask = system.monochrome() ? 0x3fff : 0xffff; - iram[addr & mask] = data; +auto CPU::ramWrite(uint16 addr, uint8 data) -> void { + if(WS() && addr >= 0x4000) return; + iram[addr] = data; +} + +auto CPU::portRead(uint16 addr) -> uint16 { + return 0x0000; +} + +auto CPU::portWrite(uint16 addr, uint16 data) -> void { } diff --git a/higan/ws/interface/interface.cpp b/higan/ws/interface/interface.cpp index 9633ad17..84c6dd97 100644 --- a/higan/ws/interface/interface.cpp +++ b/higan/ws/interface/interface.cpp @@ -21,24 +21,40 @@ Interface::Interface() { media.append({ID::WonderSwan, "WonderSwan", "ws", true}); media.append({ID::WonderSwanColor, "WonderSwan Color", "wsc", true}); - { Device device{0, ID::Device, "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, "Sound"}); - device.input.append({11, 0, "Start"}); - device.order = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + { Device device{0, ID::DeviceHorizontal, "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, "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 { diff --git a/higan/ws/interface/interface.hpp b/higan/ws/interface/interface.hpp index b56e9b2b..35da5edd 100644 --- a/higan/ws/interface/interface.hpp +++ b/higan/ws/interface/interface.hpp @@ -16,7 +16,8 @@ struct ID { }; enum : uint { - Device = 1, + DeviceHorizontal = 1, + DeviceVertical = 2, }; }; diff --git a/higan/ws/memory/memory.cpp b/higan/ws/memory/memory.cpp index b6ef7592..019a384b 100644 --- a/higan/ws/memory/memory.cpp +++ b/higan/ws/memory/memory.cpp @@ -3,12 +3,21 @@ namespace WonderSwan { uint8 iram[64 * 1024] = {0}; -IO* io[256]; +IO* iomap[64 * 1024] = {0}; Bus bus; auto IO::power() -> void { 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 { diff --git a/higan/ws/memory/memory.hpp b/higan/ws/memory/memory.hpp index bcfa7c93..60716a27 100644 --- a/higan/ws/memory/memory.hpp +++ b/higan/ws/memory/memory.hpp @@ -1,8 +1,8 @@ struct IO { static auto power() -> void; - virtual auto in(uint8 addr) -> uint8 { return 0x00; } - virtual auto out(uint8 addr, uint8 data) -> void {} + virtual auto portRead(uint16 addr) -> uint16; + virtual auto portWrite(uint16 addr, uint16 data) -> void; }; struct Bus { @@ -11,5 +11,5 @@ struct Bus { }; extern uint8 iram[64 * 1024]; -extern IO* io[256]; +extern IO* iomap[64 * 1024]; extern Bus bus; diff --git a/higan/ws/ppu/ppu.cpp b/higan/ws/ppu/ppu.cpp index 5ae4fe52..15872bc0 100644 --- a/higan/ws/ppu/ppu.cpp +++ b/higan/ws/ppu/ppu.cpp @@ -39,6 +39,8 @@ auto PPU::power() -> void { status.vclk = 0; status.hclk = 0; + + video.power(); } } diff --git a/higan/ws/ppu/video.cpp b/higan/ws/ppu/video.cpp index 78d78b75..4279fa0c 100644 --- a/higan/ws/ppu/video.cpp +++ b/higan/ws/ppu/video.cpp @@ -9,28 +9,17 @@ Video::Video() { auto Video::power() -> void { memory::fill(output(), 224 * 224 * sizeof(uint32)); - if(system.monochrome()) { - for(auto color : range(16)) { - paletteLiteral[color] = color; + for(auto color : range(1 << 12)) { + paletteLiteral[color] = color; - uint L = image::normalize(15 - color, 4, 16); - paletteStandard[color] = interface->videoColor(L, L, L); - } - } + uint R = (uint4)(color >> 8); + uint G = (uint4)(color >> 4); + uint B = (uint4)(color >> 0); - if(system.color()) { - for(auto color : range(1 << 12)) { - paletteLiteral[color] = color; - - uint R = (uint4)(color >> 8); - uint G = (uint4)(color >> 4); - uint B = (uint4)(color >> 0); - - R = image::normalize(R, 4, 16); - G = image::normalize(G, 4, 16); - B = image::normalize(B, 4, 16); - paletteStandard[color] = interface->videoColor(R, G, B); - } + R = image::normalize(R, 4, 16); + G = image::normalize(G, 4, 16); + B = image::normalize(B, 4, 16); + paletteStandard[color] = interface->videoColor(R, G, B); } } diff --git a/higan/ws/system/system.cpp b/higan/ws/system/system.cpp index 964455e8..9c124eab 100644 --- a/higan/ws/system/system.cpp +++ b/higan/ws/system/system.cpp @@ -8,14 +8,6 @@ auto System::revision() const -> 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 { } @@ -28,6 +20,8 @@ auto System::load(Revision revision) -> void { interface->loadRequest(ID::SystemManifest, "manifest.bml", true); auto document = BML::unserialize(information.manifest); + //note: IPLROM is currently undumped; otherwise we'd load it here ... + cartridge.load(); } diff --git a/higan/ws/system/system.hpp b/higan/ws/system/system.hpp index 9fd35ed0..10d90604 100644 --- a/higan/ws/system/system.hpp +++ b/higan/ws/system/system.hpp @@ -1,9 +1,11 @@ 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 monochrome() const -> bool; - auto color() const -> bool; auto init() -> void; auto term() -> void; @@ -16,7 +18,7 @@ struct System { } information; privileged: - Revision _revision; + Revision _revision = Revision::WonderSwan; }; extern System system; diff --git a/higan/ws/ws.hpp b/higan/ws/ws.hpp index d9370174..27b7b8b2 100644 --- a/higan/ws/ws.hpp +++ b/higan/ws/ws.hpp @@ -49,6 +49,10 @@ namespace WonderSwan { #include #include #include + + 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