diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 13b4d982..afc938af 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.04"; + static const string Version = "097.05"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index f532a721..11ea0417 100644 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -4,6 +4,7 @@ namespace Emulator { struct Interface { struct Information { + string manufacturer; string name; uint width; uint height; diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp index 0f5fb010..3aaa556c 100644 --- a/higan/fc/interface/interface.cpp +++ b/higan/fc/interface/interface.cpp @@ -8,12 +8,14 @@ Settings settings; Interface::Interface() { interface = this; - information.name = "Famicom"; - information.width = 256; - information.height = 240; - information.overscan = true; - information.aspectRatio = 8.0 / 7.0; - information.resettable = true; + information.manufacturer = "Nintendo"; + information.name = "Famicom"; + information.width = 256; + information.height = 240; + information.overscan = true; + information.aspectRatio = 8.0 / 7.0; + information.resettable = true; + information.capability.states = true; information.capability.cheats = true; diff --git a/higan/gb/interface/interface.cpp b/higan/gb/interface/interface.cpp index aa740750..01267ff9 100644 --- a/higan/gb/interface/interface.cpp +++ b/higan/gb/interface/interface.cpp @@ -9,12 +9,14 @@ Interface::Interface() { interface = this; hook = nullptr; - information.name = "Game Boy"; - information.width = 160; - information.height = 144; - information.overscan = false; - information.aspectRatio = 1.0; - information.resettable = false; + information.manufacturer = "Nintendo"; + information.name = "Game Boy"; + information.width = 160; + information.height = 144; + information.overscan = false; + information.aspectRatio = 1.0; + information.resettable = false; + information.capability.states = true; information.capability.cheats = true; diff --git a/higan/gba/interface/interface.cpp b/higan/gba/interface/interface.cpp index 7ae297be..96ed9499 100644 --- a/higan/gba/interface/interface.cpp +++ b/higan/gba/interface/interface.cpp @@ -8,12 +8,14 @@ Settings settings; Interface::Interface() { interface = this; - information.name = "Game Boy Advance"; - information.width = 240; - information.height = 160; - information.overscan = false; - information.aspectRatio = 1.0; - information.resettable = false; + information.manufacturer = "Nintendo"; + information.name = "Game Boy Advance"; + information.width = 240; + information.height = 160; + information.overscan = false; + information.aspectRatio = 1.0; + information.resettable = false; + information.capability.states = true; information.capability.cheats = false; diff --git a/higan/processor/v30mz/algorithms.cpp b/higan/processor/v30mz/algorithms.cpp new file mode 100644 index 00000000..a1e2f784 --- /dev/null +++ b/higan/processor/v30mz/algorithms.cpp @@ -0,0 +1,30 @@ +//(0 = odd, 1 = even) number of bits set in value +auto V30MZ::parity(uint16 value) const -> bool { + value ^= value >> 8; + value ^= value >> 4; + value ^= value >> 2; + value ^= value >> 1; + return !(value & 1); +} + +auto V30MZ::albAnd(uint8 x, uint8 y) -> uint8 { + uint8 result = x & y; + r.f.c = 0; + r.f.p = parity(result); + r.f.h = 0; + r.f.z = result == 0; + r.f.s = result & 0x80; + r.f.v = 0; + return result; +} + +auto V30MZ::alwAnd(uint16 x, uint16 y) -> uint16 { + uint16 result = x & y; + r.f.c = 0; + r.f.p = parity(result); + r.f.h = 0; + r.f.z = result == 0; + r.f.s = result & 0x8000; + r.f.v = 0; + return result; +} diff --git a/higan/processor/v30mz/disassembler.cpp b/higan/processor/v30mz/disassembler.cpp index f13591d6..7a87fdf1 100644 --- a/higan/processor/v30mz/disassembler.cpp +++ b/higan/processor/v30mz/disassembler.cpp @@ -2,50 +2,100 @@ 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); + enum : uint { Byte, Word, Segment }; + auto readByte = [&](uint offset) -> string { + 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); + auto readWord = [&](uint offset) -> string { + uint16 word = read((cs << 4) + (uint16)(ip + offset++)) << 0; + word |= read((cs << 4) + (uint16)(ip + offset++)) << 8; + return {"$", hex(word, 4L)}; + }; + auto readRelativeByte = [&](uint offset, uint displacement) -> string { + uint8 byte = read((cs << 4) + (uint16)(ip + offset++)); + return {"$", hex(ip + displacement + (int8)byte, 4L)}; + }; + auto readRelativeWord = [&](uint offset, uint displacement) -> string { + uint16 word = read((cs << 4) + (uint16)(ip + offset++)) << 0; + word |= read((cs << 4) + (uint16)(ip + offset++)) << 8; + return {"$", hex(ip + displacement + (int16)word, 4L)}; + }; + auto readModRM = [&](uint offset, uint mode) -> string { + uint8 modRM = read((cs << 4) + (uint16)(ip + offset++)); + static const string reg[3][8] = { + {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}, + {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}, + {"es", "cs", "ss", "ds", "es", "cs", "ss", "ds"}, + }; + string d = reg[mode][(uint3)(modRM >> 3)]; + if(modRM >= 0xc0) return {d, ",", reg[Word][modRM & 7]}; + if((modRM & 0xc7) == 0x06) return {d, ",[", readWord(offset), "]"}; + static const string mem[8] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"}; + if((modRM & 0xc0) == 0x40) return {d, ",[", mem[modRM & 7], "+", readByte(offset), "]"}; + if((modRM & 0xc0) == 0x80) return {d, ",[", mem[modRM & 7], "+", readWord(offset), "]"}; + return {d, ",[", mem[modRM & 7], "]"}; }; 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; + case 0x22: s = {"xor ", readModRM(1, Byte)}; break; + case 0x33: s = {"xor ", readModRM(1, Word)}; break; + case 0x70: s = {"jo ", readRelativeByte(1, 2)}; break; + case 0x71: s = {"jno ", readRelativeByte(1, 2)}; break; + case 0x72: s = {"jc ", readRelativeByte(1, 2)}; break; + case 0x73: s = {"jnc ", readRelativeByte(1, 2)}; break; + case 0x74: s = {"jz ", readRelativeByte(1, 2)}; break; + case 0x75: s = {"jnz ", readRelativeByte(1, 2)}; break; + case 0x76: s = {"jcz ", readRelativeByte(1, 2)}; break; + case 0x77: s = {"jncz ", readRelativeByte(1, 2)}; break; + case 0x78: s = {"js ", readRelativeByte(1, 2)}; break; + case 0x79: s = {"jns ", readRelativeByte(1, 2)}; break; + case 0x7a: s = {"jp ", readRelativeByte(1, 2)}; break; + case 0x7b: s = {"jnp ", readRelativeByte(1, 2)}; break; + case 0x7c: s = {"jl ", readRelativeByte(1, 2)}; break; + case 0x7d: s = {"jnl ", readRelativeByte(1, 2)}; break; + case 0x7e: s = {"jle ", readRelativeByte(1, 2)}; break; + case 0x7f: s = {"jnle ", readRelativeByte(1, 2)}; break; + case 0x8a: s = {"mov ", readModRM(1, Byte)}; break; + case 0x8b: s = {"mov ", readModRM(1, Word)}; break; + case 0x8e: s = {"mov ", readModRM(1, Segment)}; break; + case 0x90: s = {"nop "}; break; + case 0xa8: s = {"test al,", readByte(1)}; break; + case 0xa9: s = {"test ax,", readWord(1)}; 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 0xc3: s = {"ret "}; 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 0xe8: s = {"call ", readRelativeWord(1, 3)}; 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), "]"}; @@ -64,8 +114,8 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers) -> string { " di:", hex(r.di, 4L), " bp:", hex(r.bp, 4L), " sp:", hex(r.sp, 4L), + " ip:", hex(r.ip, 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), " ", diff --git a/higan/processor/v30mz/instructions.cpp b/higan/processor/v30mz/instructions.cpp index 819a7963..500b8d57 100644 --- a/higan/processor/v30mz/instructions.cpp +++ b/higan/processor/v30mz/instructions.cpp @@ -1,61 +1,127 @@ -auto V30MZ::opJumpFar() { - auto ip = readWord(); - auto cs = readWord(); - r.ip = ip; - r.cs = cs; +auto V30MZ::opbXorRegisterModRM() { + auto md = readbIP(); + regb(md) ^= readbModRM(md); } -auto V30MZ::opInByte() { - auto port = readByte(); - r.al = in(port); +auto V30MZ::opwXorRegisterModRM() { + auto md = readbIP(); + regw(md) ^= readwModRM(md); } -auto V30MZ::opInWord() { - auto port = readByte(); - r.ax = in(port); +auto V30MZ::opJumpIf(bool condition) { + auto displacement = (int8)readbIP(); + if(condition) r.ip += displacement; } -auto V30MZ::opOutByte() { - auto port = readByte(); - out(port, r.al); +auto V30MZ::opbMoveRegisterModRM() { + auto md = readbIP(); + regb(md) = readbModRM(md); } -auto V30MZ::opOutWord() { - auto port = readByte(); - out(port, r.ax); +auto V30MZ::opwMoveRegisterModRM() { + auto md = readbIP(); + regw(md) = readwModRM(md); } -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::opMoveSegmentRegisterModRM() { + wait(1); + auto md = readbIP(); + sreg(md) = readwModRM(md); } auto V30MZ::opNoOperation() { } +auto V30MZ::opTestAL() { + albAnd(r.al, readbIP()); +} + +auto V30MZ::opTestAX() { + alwAnd(r.ax, readwIP()); +} + +auto V30MZ::opbMoveRegisterImmediate(uint8& rd) { + rd = readbIP(); +} + +auto V30MZ::opwMoveRegisterImmediate(uint16& rd) { + rd = readwIP(); +} + +auto V30MZ::opReturn() { + wait(5); + r.ip = readSP(); +} + +auto V30MZ::opbIn() { + wait(5); + auto port = readbIP(); + r.al = in(port); +} + +auto V30MZ::opwIn() { + wait(5); + auto port = readbIP(); + r.al = in(port + 0); + r.ah = in(port + 1); +} + +auto V30MZ::opbOut() { + wait(5); + auto port = readbIP(); + out(port, r.al); +} + +auto V30MZ::opwOut() { + wait(5); + auto port = readbIP(); + out(port + 0, r.al); + out(port + 1, r.ah); +} + +auto V30MZ::opCallNear() { + wait(4); + auto displacement = (int16)readwIP(); + writeSP(r.ip); + r.ip += displacement; +} + +auto V30MZ::opJumpFar() { + wait(6); + auto ip = readwIP(); + auto cs = readwIP(); + r.ip = ip; + r.cs = cs; +} + +auto V30MZ::opbInDX() { + wait(5); + r.al = in(r.dx); +} + +auto V30MZ::opwInDX() { + wait(5); + r.al = in(r.dx + 0); + r.ah = in(r.dx + 1); +} + +auto V30MZ::opbOutDX() { + wait(5); + out(r.dx, r.al); +} + +auto V30MZ::opwOutDX() { + wait(5); + out(r.dx + 0, r.al); + out(r.dx + 1, r.ah); +} + auto V30MZ::opClearFlag(bool& flag) { + wait(3); flag = false; } auto V30MZ::opSetFlag(bool& flag) { + wait(3); flag = true; } diff --git a/higan/processor/v30mz/memory.cpp b/higan/processor/v30mz/memory.cpp index c45d16d9..e9c11013 100644 --- a/higan/processor/v30mz/memory.cpp +++ b/higan/processor/v30mz/memory.cpp @@ -1,8 +1,75 @@ -auto V30MZ::readByte() -> uint8 { - return read((r.cs << 4) + (r.ip++)); +auto V30MZ::readbIP() -> 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; +auto V30MZ::readwIP() -> uint16 { + uint16 word = read((r.cs << 4) + r.ip++) << 0; + return word | read((r.cs << 4) + r.ip++) << 8; +} + +// + +auto V30MZ::readSP() -> uint16 { + uint16 word = read((r.ss << 4) + r.sp++) << 0; + return word | read((r.ss << 4) + r.sp++) << 8; +} + +auto V30MZ::writeSP(uint16 data) -> void { + write((r.ss << 4) + --r.sp, data >> 8); + write((r.ss << 4) + --r.sp, data >> 0); +} + +// + +auto V30MZ::readb(uint20 ea) -> uint8 { + return read(ea++); +} + +auto V30MZ::readw(uint20 ea) -> uint16 { + uint16 word = read(ea++) << 0; + return word | read(ea++) << 8; +} + +// + +auto V30MZ::readb(uint16 rs, uint16 ea) -> uint8 { + return read((rs << 4) + ea++); +} + +auto V30MZ::readw(uint16 rs, uint16 ea) -> uint16 { + uint16 word = read((rs << 4) + ea++) << 0; + return word | read((rs << 4) + ea++) << 8; +} + +// + +//todo: return tuple +auto V30MZ::readModRM(uint8 modRM) -> uint20 { + if((modRM & 0xc7) == 0x06) return (r.ds << 4) + (int16)readwIP(); + + int16 displacement = 0; + if((modRM & 0xc0) == 0x40) displacement = (int8)readbIP(); + if((modRM & 0xc0) == 0x80) displacement = (int16)readwIP(); + + switch(modRM & 7) { + case 0: return (r.ds << 4) + r.bx + r.si + displacement; + case 1: return (r.ds << 4) + r.bx + r.di + displacement; + case 2: return (r.ss << 4) + r.bp + r.si + displacement; + case 3: return (r.ss << 4) + r.bp + r.di + displacement; + case 4: return (r.ds << 4) + r.si + displacement; + case 5: return (r.ds << 4) + r.di + displacement; + case 6: return (r.ss << 4) + r.bp + displacement; + case 7: return (r.ds << 4) + r.bx + displacement; + } + unreachable; +} + +auto V30MZ::readbModRM(uint8 modRM) -> uint8 { + if(modRM >= 0xc0) return regb(modRM); + return readb(readModRM(modRM)); +} + +auto V30MZ::readwModRM(uint8 modRM) -> uint16 { + if(modRM >= 0xc0) return regw(modRM); + return readw(readModRM(modRM)); } diff --git a/higan/processor/v30mz/registers.cpp b/higan/processor/v30mz/registers.cpp index 47958c4e..c1771054 100644 --- a/higan/processor/v30mz/registers.cpp +++ b/higan/processor/v30mz/registers.cpp @@ -1,3 +1,18 @@ +auto V30MZ::regb(uint8 modRM) -> uint8& { + static uint8* p[] = {&r.al, &r.cl, &r.dl, &r.bl, &r.ah, &r.ch, &r.dh, &r.bh}; + return *p[(modRM >> 3) & 7]; +} + +auto V30MZ::regw(uint8 modRM) -> uint16& { + static uint16* p[] = {&r.ax, &r.cx, &r.dx, &r.bx, &r.sp, &r.bp, &r.si, &r.di}; + return *p[(modRM >> 3) & 7]; +} + +auto V30MZ::sreg(uint8 modRM) -> uint16& { + static uint16* p[] = {&r.es, &r.cs, &r.ss, &r.ds}; + return *p[(modRM >> 3) & 3]; +} + V30MZ::Registers::Flags::operator uint16() const { return m << 15 | 1 << 14 | 1 << 13 | 1 << 12 | v << 11 | d << 10 | i << 9 | b << 8 diff --git a/higan/processor/v30mz/v30mz.cpp b/higan/processor/v30mz/v30mz.cpp index fedafe99..608ea94e 100644 --- a/higan/processor/v30mz/v30mz.cpp +++ b/higan/processor/v30mz/v30mz.cpp @@ -5,6 +5,7 @@ namespace Processor { #include "registers.cpp" #include "memory.cpp" +#include "algorithms.cpp" #include "instructions.cpp" #include "disassembler.cpp" @@ -21,36 +22,61 @@ auto V30MZ::exec() -> void { auto V30MZ::execOpcode() -> void { executed++; - uint8 opcode = readByte(); + uint8 opcode = readbIP(); wait(1); switch(opcode) { + case 0x32: return opbXorRegisterModRM(); + case 0x33: return opwXorRegisterModRM(); + case 0x70: return opJumpIf(r.f.v == 1); + case 0x71: return opJumpIf(r.f.v == 0); + case 0x72: return opJumpIf(r.f.c == 1); + case 0x73: return opJumpIf(r.f.c == 0); + case 0x74: return opJumpIf(r.f.z == 1); + case 0x75: return opJumpIf(r.f.z == 0); + case 0x76: return opJumpIf(r.f.z == 1 || r.f.c == 1); + case 0x77: return opJumpIf(r.f.z != 1 && r.f.c != 1); + case 0x78: return opJumpIf(r.f.s == 1); + case 0x79: return opJumpIf(r.f.s == 0); + case 0x7a: return opJumpIf(r.f.p == 1); + case 0x7b: return opJumpIf(r.f.p == 0); + case 0x7c: return opJumpIf(r.f.s != r.f.v && r.f.z == 0); + case 0x7d: return opJumpIf(r.f.s == r.f.v || r.f.z == 1); + case 0x7e: return opJumpIf(r.f.s != r.f.v || r.f.z == 1); + case 0x7f: return opJumpIf(r.f.s == r.f.v && r.f.z == 0); + case 0x8a: return opbMoveRegisterModRM(); + case 0x8b: return opwMoveRegisterModRM(); + case 0x8e: return opMoveSegmentRegisterModRM(); 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 0xa8: return opTestAL(); + case 0xa9: return opTestAX(); + case 0xb0: return opbMoveRegisterImmediate(r.al); + case 0xb1: return opbMoveRegisterImmediate(r.cl); + case 0xb2: return opbMoveRegisterImmediate(r.dl); + case 0xb3: return opbMoveRegisterImmediate(r.bl); + case 0xb4: return opbMoveRegisterImmediate(r.ah); + case 0xb5: return opbMoveRegisterImmediate(r.ch); + case 0xb6: return opbMoveRegisterImmediate(r.dh); + case 0xb7: return opbMoveRegisterImmediate(r.bh); + case 0xb8: return opwMoveRegisterImmediate(r.ax); + case 0xb9: return opwMoveRegisterImmediate(r.cx); + case 0xba: return opwMoveRegisterImmediate(r.dx); + case 0xbb: return opwMoveRegisterImmediate(r.bx); + case 0xbc: return opwMoveRegisterImmediate(r.sp); + case 0xbd: return opwMoveRegisterImmediate(r.bp); + case 0xbe: return opwMoveRegisterImmediate(r.si); + case 0xbf: return opwMoveRegisterImmediate(r.di); + case 0xc3: return opReturn(); + case 0xe4: return opbIn(); + case 0xe5: return opwIn(); + case 0xe6: return opbOut(); + case 0xe7: return opwOut(); + case 0xe8: return opCallNear(); case 0xea: return opJumpFar(); - case 0xec: return opInDXByte(); - case 0xed: return opInDXWord(); - case 0xee: return opOutDXByte(); - case 0xef: return opOutDXWord(); + case 0xec: return opbInDX(); + case 0xed: return opwInDX(); + case 0xee: return opbOutDX(); + case 0xef: return opwOutDX(); case 0xf8: return opClearFlag(r.f.c); case 0xf9: return opSetFlag(r.f.c); case 0xfa: return opClearFlag(r.f.i); diff --git a/higan/processor/v30mz/v30mz.hpp b/higan/processor/v30mz/v30mz.hpp index 5b75684f..af41e9b2 100644 --- a/higan/processor/v30mz/v30mz.hpp +++ b/higan/processor/v30mz/v30mz.hpp @@ -8,30 +8,64 @@ struct V30MZ { 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; + virtual auto in(uint16 port) -> uint8 = 0; + virtual auto out(uint16 port, uint8 data) -> void = 0; auto exec() -> void; auto execOpcode() -> void; auto power() -> void; + //registers.cpp + auto regb(uint8) -> uint8&; + auto regw(uint8) -> uint16&; + auto sreg(uint8) -> uint16&; + //memory.cpp - auto readByte() -> uint8; - auto readWord() -> uint16; + auto readbIP() -> uint8; + auto readwIP() -> uint16; + + auto readSP() -> uint16; + auto writeSP(uint16) -> void; + + auto readb(uint20 ea) -> uint8; + auto readw(uint20 ea) -> uint16; + + auto readb(uint16 rs, uint16 ea) -> uint8; + auto readw(uint16 rs, uint16 ea) -> uint16; + + auto readModRM(uint8) -> uint20; + auto readbModRM(uint8) -> uint8; + auto readwModRM(uint8) -> uint16; + + //algorithms.cpp + auto parity(uint16) const -> bool; + + auto albAnd(uint8, uint8) -> uint8; + auto alwAnd(uint16, uint16) -> 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 opbXorRegisterModRM(); + auto opwXorRegisterModRM(); + auto opJumpIf(bool); + auto opbMoveRegisterModRM(); + auto opwMoveRegisterModRM(); + auto opMoveSegmentRegisterModRM(); auto opNoOperation(); + auto opTestAL(); + auto opTestAX(); + auto opbMoveRegisterImmediate(uint8&); + auto opwMoveRegisterImmediate(uint16&); + auto opReturn(); + auto opbIn(); + auto opwIn(); + auto opbOut(); + auto opwOut(); + auto opCallNear(); + auto opJumpFar(); + auto opbInDX(); + auto opwInDX(); + auto opbOutDX(); + auto opwOutDX(); auto opClearFlag(bool&); auto opSetFlag(bool&); @@ -44,10 +78,10 @@ struct V30MZ { struct Registers { 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); }; }; + union { uint16 ax; struct { uint8 order_lsb2(al, ah); }; }; + union { uint16 bx; struct { uint8 order_lsb2(bl, bh); }; }; + union { uint16 cx; struct { uint8 order_lsb2(cl, ch); }; }; + union { uint16 dx; struct { uint8 order_lsb2(dl, dh); }; }; uint16 si; uint16 di; uint16 bp; @@ -56,6 +90,7 @@ struct V30MZ { uint16 ds; uint16 es; uint16 ss; + struct Flags { operator uint16() const; auto operator=(uint16 data); diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index ad4d2256..c6de2436 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -9,12 +9,14 @@ Interface::Interface() { interface = this; system.init(); - information.name = "Super Famicom"; - information.width = 256; - information.height = 240; - information.overscan = true; - information.aspectRatio = 8.0 / 7.0; - information.resettable = true; + information.manufacturer = "Nintendo"; + information.name = "Super Famicom"; + information.width = 256; + information.height = 240; + information.overscan = true; + information.aspectRatio = 8.0 / 7.0; + information.resettable = true; + information.capability.states = true; information.capability.cheats = true; diff --git a/higan/ws/cartridge/cartridge.cpp b/higan/ws/cartridge/cartridge.cpp index acd1ecc0..4bad3527 100644 --- a/higan/ws/cartridge/cartridge.cpp +++ b/higan/ws/cartridge/cartridge.cpp @@ -55,6 +55,11 @@ auto Cartridge::unload() -> void { } auto Cartridge::power() -> void { + iomap[0x00c0] = this; + iomap[0x00c1] = this; + iomap[0x00c2] = this; + iomap[0x00c3] = this; + r.bank_rom0 = 0xff; r.bank_rom1 = 0xff; r.bank_rom2 = 0xff; diff --git a/higan/ws/cartridge/cartridge.hpp b/higan/ws/cartridge/cartridge.hpp index 712b0c37..8a42b7ad 100644 --- a/higan/ws/cartridge/cartridge.hpp +++ b/higan/ws/cartridge/cartridge.hpp @@ -1,4 +1,4 @@ -struct Cartridge { +struct Cartridge : IO { auto loaded() const -> bool; auto load() -> void; @@ -11,6 +11,9 @@ struct Cartridge { auto ramRead(uint addr) -> uint8; auto ramWrite(uint addr, uint8 data) -> void; + auto portRead(uint16 addr) -> uint8 override; + auto portWrite(uint16 addr, uint8 data) -> void override; + struct Registers { uint8 bank_rom0; uint8 bank_rom1; diff --git a/higan/ws/cartridge/memory.cpp b/higan/ws/cartridge/memory.cpp index 67b8584b..7811149c 100644 --- a/higan/ws/cartridge/memory.cpp +++ b/higan/ws/cartridge/memory.cpp @@ -24,3 +24,45 @@ auto Cartridge::ramWrite(uint addr, uint8 data) -> void { if(!ram.data) return; ram.data[addr & ram.mask] = data; } + +auto Cartridge::portRead(uint16 addr) -> uint8 { + if(addr == 0x00c0) { + return r.bank_rom2; + } + + if(addr == 0x00c1) { + return r.bank_sram; + } + + if(addr == 0x00c2) { + return r.bank_rom0; + } + + if(addr == 0x00c3) { + return r.bank_rom1; + } + + return 0x00; +} + +auto Cartridge::portWrite(uint16 addr, uint8 data) -> void { + if(addr == 0x00c0) { + r.bank_rom2 = data; + return; + } + + if(addr == 0x00c1) { + r.bank_sram = data; + return; + } + + if(addr == 0x00c2) { + r.bank_rom0 = data; + return; + } + + if(addr == 0x00c3) { + r.bank_rom1 = data; + return; + } +} diff --git a/higan/ws/cpu/cpu.cpp b/higan/ws/cpu/cpu.cpp index b79b3d2c..12d4fc98 100644 --- a/higan/ws/cpu/cpu.cpp +++ b/higan/ws/cpu/cpu.cpp @@ -40,17 +40,19 @@ auto CPU::write(uint20 addr, uint8 data) -> void { return bus.write(addr, data); } -auto CPU::in(uint16 port) -> uint16 { +auto CPU::in(uint16 port) -> uint8 { return iomap[port]->portRead(port); } -auto CPU::out(uint16 port, uint16 data) -> void { +auto CPU::out(uint16 port, uint8 data) -> void { return iomap[port]->portWrite(port, data); } auto CPU::power() -> void { V30MZ::power(); create(CPU::Enter, 3072000); + + iomap[0x00a0] = this; } } diff --git a/higan/ws/cpu/cpu.hpp b/higan/ws/cpu/cpu.hpp index 45d9d713..dfaf8850 100644 --- a/higan/ws/cpu/cpu.hpp +++ b/higan/ws/cpu/cpu.hpp @@ -7,8 +7,8 @@ struct CPU : Processor::V30MZ, Thread, IO { 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 in(uint16 port) -> uint8 override; + auto out(uint16 port, uint8 data) -> void override; auto power() -> void; @@ -16,8 +16,8 @@ struct CPU : Processor::V30MZ, Thread, IO { 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; + auto portRead(uint16 addr) -> uint8 override; + auto portWrite(uint16 addr, uint8 data) -> void override; }; extern CPU cpu; diff --git a/higan/ws/cpu/memory.cpp b/higan/ws/cpu/memory.cpp index 7f642b82..71278752 100644 --- a/higan/ws/cpu/memory.cpp +++ b/higan/ws/cpu/memory.cpp @@ -8,9 +8,21 @@ auto CPU::ramWrite(uint16 addr, uint8 data) -> void { iram[addr] = data; } -auto CPU::portRead(uint16 addr) -> uint16 { - return 0x0000; +auto CPU::portRead(uint16 addr) -> uint8 { + //HW_FLAGS + if(addr == 0x00a0) { + return 1 << 7 //1 = built-in self-test passed + | 1 << 2 //0 = 8-bit bus width; 1 = 16-bit bus width + | !WS() << 1 //0 = WonderSwan; 1 = WonderSwan Color or SwanCrystal + | 1 << 0; //0 = BIOS mapped; 1 = cartridge mapped + } + + return 0x00; //should never occur } -auto CPU::portWrite(uint16 addr, uint16 data) -> void { +auto CPU::portWrite(uint16 addr, uint8 data) -> void { + //HW_FLAGS + if(addr == 0x00a0) { + //todo: d2 (bus width) bit is writable; but ... it will do very bad things + } } diff --git a/higan/ws/interface/interface.cpp b/higan/ws/interface/interface.cpp index 84c6dd97..2fdcf34b 100644 --- a/higan/ws/interface/interface.cpp +++ b/higan/ws/interface/interface.cpp @@ -8,12 +8,13 @@ Settings settings; Interface::Interface() { interface = this; - information.name = "WonderSwan"; - information.width = 224; //note: technically 224x144; but screen can be rotated - information.height = 224; //by using a square size; this can be done in the core - information.overscan = false; - information.aspectRatio = 1.0; - information.resettable = false; + information.manufacturer = "Bandai"; + information.name = "WonderSwan"; + information.width = 224; //note: technically 224x144; but screen can be rotated + information.height = 224; //by using a square size; this can be done in the core + information.overscan = false; + information.aspectRatio = 1.0; + information.resettable = false; information.capability.states = false; information.capability.cheats = false; diff --git a/higan/ws/memory/memory.cpp b/higan/ws/memory/memory.cpp index 019a384b..cd2ad309 100644 --- a/higan/ws/memory/memory.cpp +++ b/higan/ws/memory/memory.cpp @@ -11,13 +11,13 @@ auto IO::power() -> void { for(auto& n : iomap) n = &unmapped; } -auto IO::portRead(uint16 addr) -> uint16 { +auto IO::portRead(uint16 addr) -> uint8 { print("[", hex(addr, 4L), "]: port unmapped\n"); - return 0x0000; + return 0x00; } -auto IO::portWrite(uint16 addr, uint16 data) -> void { - print("[", hex(addr, 4L), "] = ", hex(data, 4L), ": port unmapped\n"); +auto IO::portWrite(uint16 addr, uint8 data) -> void { + print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n"); } auto Bus::read(uint20 addr) -> uint8 { diff --git a/higan/ws/memory/memory.hpp b/higan/ws/memory/memory.hpp index 60716a27..f64fd98f 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 portRead(uint16 addr) -> uint16; - virtual auto portWrite(uint16 addr, uint16 data) -> void; + virtual auto portRead(uint16 addr) -> uint8; + virtual auto portWrite(uint16 addr, uint8 data) -> void; }; struct Bus { diff --git a/icarus/core/core.cpp b/icarus/core/core.cpp index c462b627..d60601cb 100644 --- a/icarus/core/core.cpp +++ b/icarus/core/core.cpp @@ -1,11 +1,13 @@ Icarus::Icarus() { - database.famicom = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Famicom.bml"))); - database.superFamicom = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Super Famicom.bml"))); - database.gameBoy = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Game Boy.bml"))); - database.gameBoyColor = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Game Boy Color.bml"))); - database.gameBoyAdvance = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Game Boy Advance.bml"))); - database.bsMemory = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/BS Memory.bml"))); - database.sufamiTurbo = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Sufami Turbo.bml"))); + database.famicom = BML::unserialize(string::read(locate("Database/Famicom.bml"))); + database.superFamicom = BML::unserialize(string::read(locate("Database/Super Famicom.bml"))); + database.gameBoy = BML::unserialize(string::read(locate("Database/Game Boy.bml"))); + database.gameBoyColor = BML::unserialize(string::read(locate("Database/Game Boy Color.bml"))); + database.gameBoyAdvance = BML::unserialize(string::read(locate("Database/Game Boy Advance.bml"))); + database.wonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml"))); + database.wonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml"))); + database.bsMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml"))); + database.sufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml"))); } auto Icarus::error() const -> string { @@ -32,6 +34,8 @@ auto Icarus::manifest(string location) -> string { if(type == ".gb") return gameBoyManifest(location); if(type == ".gbc") return gameBoyColorManifest(location); if(type == ".gba") return gameBoyAdvanceManifest(location); + if(type == ".ws") return wonderSwanManifest(location); + if(type == ".wsc") return wonderSwanColorManifest(location); if(type == ".bs") return bsMemoryManifest(location); if(type == ".st") return sufamiTurboManifest(location); @@ -65,6 +69,8 @@ auto Icarus::import(string location) -> string { if(type == ".gb") return gameBoyImport(buffer, location); if(type == ".gbc") return gameBoyColorImport(buffer, location); if(type == ".gba") return gameBoyAdvanceImport(buffer, location); + if(type == ".ws") return wonderSwanImport(buffer, location); + if(type == ".wsc") return wonderSwanColorImport(buffer, location); if(type == ".bs") return bsMemoryImport(buffer, location); if(type == ".st") return sufamiTurboImport(buffer, location); diff --git a/icarus/core/core.hpp b/icarus/core/core.hpp index 7e6e098b..341ef607 100644 --- a/icarus/core/core.hpp +++ b/icarus/core/core.hpp @@ -47,6 +47,16 @@ struct Icarus { auto sufamiTurboManifest(vector& buffer, string location) -> string; auto sufamiTurboImport(vector& buffer, string location) -> string; + //wonderswan.cpp + auto wonderSwanManifest(string location) -> string; + auto wonderSwanManifest(vector& buffer, string location) -> string; + auto wonderSwanImport(vector& buffer, string location) -> string; + + //wonderswan-color.cpp + auto wonderSwanColorManifest(string location) -> string; + auto wonderSwanColorManifest(vector& buffer, string location) -> string; + auto wonderSwanColorImport(vector& buffer, string location) -> string; + private: string errorMessage; @@ -56,6 +66,8 @@ private: Markup::Node gameBoy; Markup::Node gameBoyColor; Markup::Node gameBoyAdvance; + Markup::Node wonderSwan; + Markup::Node wonderSwanColor; Markup::Node bsMemory; Markup::Node sufamiTurbo; } database; diff --git a/icarus/core/wonderswan-color.cpp b/icarus/core/wonderswan-color.cpp new file mode 100644 index 00000000..944dafde --- /dev/null +++ b/icarus/core/wonderswan-color.cpp @@ -0,0 +1,51 @@ +auto Icarus::wonderSwanColorManifest(string location) -> string { + vector buffer; + concatenate(buffer, {location, "program.rom"}); + return wonderSwanColorManifest(buffer, location); +} + +auto Icarus::wonderSwanColorManifest(vector& buffer, string location) -> string { + string manifest; + string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); + + if(settings["icarus/UseDatabase"].boolean() && !manifest) { + for(auto node : database.wonderSwanColor) { + if(node["sha256"].text() == digest) { + manifest.append(node.text(), "\n sha256: ", digest, "\n"); + break; + } + } + } + + if(settings["icarus/UseHeuristics"].boolean() && !manifest) { + WonderSwanColorCartridge cartridge{buffer.data(), buffer.size()}; + if(manifest = cartridge.manifest) { + manifest.append("\n"); + manifest.append("information\n"); + manifest.append(" title: ", prefixname(location), "\n"); + manifest.append(" sha256: ", digest, "\n"); + manifest.append(" note: ", "heuristically generated by icarus\n"); + } + } + + return manifest; +} + +auto Icarus::wonderSwanColorImport(vector& buffer, string location) -> string { + auto name = prefixname(location); + auto source = pathname(location); + string target{settings["Library/Location"].text(), "WonderSwan Color/", name, ".wsc/"}; +//if(directory::exists(target)) return failure("game already exists"); + + auto manifest = wonderSwanColorManifest(buffer, location); + if(!manifest) return failure("failed to parse ROM image"); + + if(!directory::create(target)) return failure("library path unwritable"); + if(file::exists({source, name, ".sav"}) && !file::exists({target, "save.ram"})) { + file::copy({source, name, ".sav"}, {target, "save.ram"}); + } + + if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, manifest); + file::write({target, "program.rom"}, buffer); + return success(target); +} diff --git a/icarus/core/wonderswan.cpp b/icarus/core/wonderswan.cpp new file mode 100644 index 00000000..48611631 --- /dev/null +++ b/icarus/core/wonderswan.cpp @@ -0,0 +1,51 @@ +auto Icarus::wonderSwanManifest(string location) -> string { + vector buffer; + concatenate(buffer, {location, "program.rom"}); + return wonderSwanManifest(buffer, location); +} + +auto Icarus::wonderSwanManifest(vector& buffer, string location) -> string { + string manifest; + string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); + + if(settings["icarus/UseDatabase"].boolean() && !manifest) { + for(auto node : database.wonderSwan) { + if(node["sha256"].text() == digest) { + manifest.append(node.text(), "\n sha256: ", digest, "\n"); + break; + } + } + } + + if(settings["icarus/UseHeuristics"].boolean() && !manifest) { + WonderSwanCartridge cartridge{buffer.data(), buffer.size()}; + if(manifest = cartridge.manifest) { + manifest.append("\n"); + manifest.append("information\n"); + manifest.append(" title: ", prefixname(location), "\n"); + manifest.append(" sha256: ", digest, "\n"); + manifest.append(" note: ", "heuristically generated by icarus\n"); + } + } + + return manifest; +} + +auto Icarus::wonderSwanImport(vector& buffer, string location) -> string { + auto name = prefixname(location); + auto source = pathname(location); + string target{settings["Library/Location"].text(), "WonderSwan/", name, ".ws/"}; +//if(directory::exists(target)) return failure("game already exists"); + + auto manifest = wonderSwanManifest(buffer, location); + if(!manifest) return failure("failed to parse ROM image"); + + if(!directory::create(target)) return failure("library path unwritable"); + if(file::exists({source, name, ".sav"}) && !file::exists({target, "save.ram"})) { + file::copy({source, name, ".sav"}, {target, "save.ram"}); + } + + if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, manifest); + file::write({target, "program.rom"}, buffer); + return success(target); +} diff --git a/icarus/heuristics/bs-memory.hpp b/icarus/heuristics/bs-memory.cpp similarity index 100% rename from icarus/heuristics/bs-memory.hpp rename to icarus/heuristics/bs-memory.cpp diff --git a/icarus/heuristics/famicom.hpp b/icarus/heuristics/famicom.cpp similarity index 100% rename from icarus/heuristics/famicom.hpp rename to icarus/heuristics/famicom.cpp diff --git a/icarus/heuristics/game-boy-advance.hpp b/icarus/heuristics/game-boy-advance.cpp similarity index 100% rename from icarus/heuristics/game-boy-advance.hpp rename to icarus/heuristics/game-boy-advance.cpp diff --git a/icarus/heuristics/game-boy.hpp b/icarus/heuristics/game-boy.cpp similarity index 100% rename from icarus/heuristics/game-boy.hpp rename to icarus/heuristics/game-boy.cpp diff --git a/icarus/heuristics/sufami-turbo.hpp b/icarus/heuristics/sufami-turbo.cpp similarity index 100% rename from icarus/heuristics/sufami-turbo.hpp rename to icarus/heuristics/sufami-turbo.cpp diff --git a/icarus/heuristics/super-famicom.hpp b/icarus/heuristics/super-famicom.cpp similarity index 100% rename from icarus/heuristics/super-famicom.hpp rename to icarus/heuristics/super-famicom.cpp diff --git a/icarus/heuristics/wonderswan-color.cpp b/icarus/heuristics/wonderswan-color.cpp new file mode 100644 index 00000000..37d39081 --- /dev/null +++ b/icarus/heuristics/wonderswan-color.cpp @@ -0,0 +1,16 @@ +struct WonderSwanColorCartridge { + WonderSwanColorCartridge(uint8* data, uint size); + + string manifest; + +//private: + struct Information { + } information; +}; + +WonderSwanColorCartridge::WonderSwanColorCartridge(uint8* data, uint size) { + if(size < 0x10000) return; + + manifest.append("board\n"); + manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); +} diff --git a/icarus/heuristics/wonderswan.cpp b/icarus/heuristics/wonderswan.cpp new file mode 100644 index 00000000..65a39a9b --- /dev/null +++ b/icarus/heuristics/wonderswan.cpp @@ -0,0 +1,16 @@ +struct WonderSwanCartridge { + WonderSwanCartridge(uint8* data, uint size); + + string manifest; + +//private: + struct Information { + } information; +}; + +WonderSwanCartridge::WonderSwanCartridge(uint8* data, uint size) { + if(size < 0x10000) return; + + manifest.append("board\n"); + manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); +} diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp index ffd9abe9..7a45cca7 100644 --- a/icarus/icarus.cpp +++ b/icarus/icarus.cpp @@ -4,23 +4,28 @@ using namespace nall; #include using namespace hiro; -//if file already exists in the same path as the binary; use it (portable mode) -//if not, use default requested path (*nix/user mode) -auto locate(string pathname, string filename) -> string { - string location{programpath(), filename}; +auto locate(string name) -> string { + string location = {programpath(), name}; if(file_system_object::exists(location)) return location; - return {pathname, filename}; + + location = {configpath(), "icarus/", name}; + if(file_system_object::exists(location)) return location; + + directory::create({localpath(), "icarus/"}); + return {localpath(), "icarus/", name}; } #include "settings.cpp" Settings settings; -#include "heuristics/famicom.hpp" -#include "heuristics/super-famicom.hpp" -#include "heuristics/game-boy.hpp" -#include "heuristics/game-boy-advance.hpp" -#include "heuristics/bs-memory.hpp" -#include "heuristics/sufami-turbo.hpp" +#include "heuristics/famicom.cpp" +#include "heuristics/super-famicom.cpp" +#include "heuristics/game-boy.cpp" +#include "heuristics/game-boy-advance.cpp" +#include "heuristics/wonderswan.cpp" +#include "heuristics/wonderswan-color.cpp" +#include "heuristics/bs-memory.cpp" +#include "heuristics/sufami-turbo.cpp" #include "core/core.hpp" #include "core/core.cpp" @@ -29,6 +34,8 @@ Settings settings; #include "core/game-boy.cpp" #include "core/game-boy-color.cpp" #include "core/game-boy-advance.cpp" +#include "core/wonderswan.cpp" +#include "core/wonderswan-color.cpp" #include "core/bs-memory.cpp" #include "core/sufami-turbo.cpp" Icarus icarus; @@ -60,7 +67,7 @@ auto nall::main(lstring args) -> void { if(string source = BrowserDialog() .setTitle("Load ROM Image") .setPath(settings["icarus/Path"].text()) - .setFilters("ROM Files|*.fc:*.nes:*.sfc:*.smc:*.gb:*.gbc:*.gba:*.bs:*.st:*.zip") + .setFilters("ROM Files|*.fc:*.nes:*.sfc:*.smc:*.gb:*.gbc:*.gba:*.ws:*.wsc:*.bs:*.st:*.zip") .openFile()) { if(string target = icarus.import(source)) { settings["icarus/Path"].setValue(pathname(source)); diff --git a/icarus/icarus.plist b/icarus/icarus.plist index 67833d77..5caaab81 100644 --- a/icarus/icarus.plist +++ b/icarus/icarus.plist @@ -13,7 +13,7 @@ icarus.icns --> NSHighResolutionCapable - + NSSupportsAutomaticGraphicsSwitching diff --git a/icarus/settings.cpp b/icarus/settings.cpp index 66b22850..d0dab44a 100644 --- a/icarus/settings.cpp +++ b/icarus/settings.cpp @@ -4,7 +4,7 @@ struct Settings : Markup::Node { }; Settings::Settings() { - Markup::Node::operator=(BML::unserialize(string::read(locate({configpath(), "icarus/"}, "settings.bml")))); + Markup::Node::operator=(BML::unserialize(string::read(locate("settings.bml")))); auto set = [&](const string& name, const string& value) { //create node and set to default value only if it does not already exist @@ -20,6 +20,5 @@ Settings::Settings() { } Settings::~Settings() { - directory::create({configpath(), "icarus/"}); - file::write(locate({configpath(), "icarus/"}, "settings.bml"), BML::serialize(*this)); + file::write(locate("settings.bml"), BML::serialize(*this)); }