diff --git a/higan/data/higan.plist b/higan/data/higan.plist
index 6d59f131..53d81b52 100644
--- a/higan/data/higan.plist
+++ b/higan/data/higan.plist
@@ -11,7 +11,7 @@
CFBundleIconFile
higan.icns
NSHighResolutionCapable
-
+
NSSupportsAutomaticGraphicsSwitching
diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp
index afc938af..4a87e31e 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.05";
+ static const string Version = "097.06";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";
diff --git a/higan/processor/v30mz/algorithms.cpp b/higan/processor/v30mz/algorithms.cpp
index a1e2f784..4af15058 100644
--- a/higan/processor/v30mz/algorithms.cpp
+++ b/higan/processor/v30mz/algorithms.cpp
@@ -7,24 +7,15 @@ auto V30MZ::parity(uint16 value) const -> bool {
return !(value & 1);
}
-auto V30MZ::albAnd(uint8 x, uint8 y) -> uint8 {
- uint8 result = x & y;
+auto V30MZ::alAnd(Size size, uint16 x, uint16 y) -> uint16 {
+ uint16 bits = size == Byte ? 0xff : 0xffff;
+ uint16 mask = size == Byte ? 0x80 : 0x8000;
+ uint16 result = (x & y) & bits;
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.s = result & mask;
r.f.v = 0;
return result;
}
diff --git a/higan/processor/v30mz/disassembler.cpp b/higan/processor/v30mz/disassembler.cpp
index 7a87fdf1..80599369 100644
--- a/higan/processor/v30mz/disassembler.cpp
+++ b/higan/processor/v30mz/disassembler.cpp
@@ -36,66 +36,90 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers) -> string {
if((modRM & 0xc0) == 0x80) return {d, ",[", mem[modRM & 7], "+", readWord(offset), "]"};
return {d, ",[", mem[modRM & 7], "]"};
};
+ auto readRepeat = [&](uint offset) -> string {
+ uint8 opcode = read((cs << 4) + (uint16)(ip + offset++));
+ switch(opcode) {
+ case 0x6c: return "insb";
+ case 0x6d: return "insw";
+ case 0x6e: return "outsb";
+ case 0x6f: return "outsw";
+ case 0xa4: return "movsb";
+ case 0xa5: return "movsw";
+ case 0xa6: return "cmpsb";
+ case 0xa7: return "cmpsw";
+ case 0xaa: return "stosb";
+ case 0xab: return "stosw";
+ case 0xac: return "lodsb";
+ case 0xad: return "lodsw";
+ case 0xae: return "scasb";
+ case 0xaf: return "scasw";
+ }
+ return "";
+ };
- uint8 opcode = read(ea);
+ auto opcode = read(ea);
switch(opcode) {
- 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;
+ 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 0xa4: s = {"movsb "}; break;
+ case 0xa5: s = {"movsw "}; 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 0xf2: s = {"repnz ", readRepeat(1)}; break;
+ case 0xf3: s = {"repz ", readRepeat(1)}; 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), "]"};
diff --git a/higan/processor/v30mz/instructions.cpp b/higan/processor/v30mz/instructions.cpp
index 500b8d57..183f9e93 100644
--- a/higan/processor/v30mz/instructions.cpp
+++ b/higan/processor/v30mz/instructions.cpp
@@ -1,51 +1,44 @@
-auto V30MZ::opbXorRegisterModRM() {
- auto md = readbIP();
- regb(md) ^= readbModRM(md);
-}
-
-auto V30MZ::opwXorRegisterModRM() {
- auto md = readbIP();
- regw(md) ^= readwModRM(md);
+auto V30MZ::opXorRegisterModRM(Size size) {
+ auto modRM = readIP();
+ setRegister(size, modRM, getRegister(size, modRM) ^ readModRM(size, modRM));
}
auto V30MZ::opJumpIf(bool condition) {
- auto displacement = (int8)readbIP();
+ auto displacement = (int8)readIP();
if(condition) r.ip += displacement;
}
-auto V30MZ::opbMoveRegisterModRM() {
- auto md = readbIP();
- regb(md) = readbModRM(md);
-}
-
-auto V30MZ::opwMoveRegisterModRM() {
- auto md = readbIP();
- regw(md) = readwModRM(md);
+auto V30MZ::opMoveRegisterModRM(Size size) {
+ auto modRM = readIP();
+ setRegister(size, modRM, readModRM(size, modRM));
}
auto V30MZ::opMoveSegmentRegisterModRM() {
wait(1);
- auto md = readbIP();
- sreg(md) = readwModRM(md);
+ auto modRM = readIP();
+ setSegment(modRM, readModRM(Word, modRM));
}
auto V30MZ::opNoOperation() {
}
-auto V30MZ::opTestAL() {
- albAnd(r.al, readbIP());
+auto V30MZ::opMoveString(Size size) {
+ wait(4);
+ write(size, r.es, r.di, read(size, r.ds, r.si));
+ r.si += r.f.d ? -size : size;
+ r.di += r.f.d ? -size : size;
}
-auto V30MZ::opTestAX() {
- alwAnd(r.ax, readwIP());
+auto V30MZ::opTestAX(Size size) {
+ alAnd(size, r.ax, readIP(size));
}
-auto V30MZ::opbMoveRegisterImmediate(uint8& rd) {
- rd = readbIP();
+auto V30MZ::opMoveRegisterImmediate(uint8& rd) {
+ rd = readIP(Byte);
}
-auto V30MZ::opwMoveRegisterImmediate(uint16& rd) {
- rd = readwIP();
+auto V30MZ::opMoveRegisterImmediate(uint16& rd) {
+ rd = readIP(Word);
}
auto V30MZ::opReturn() {
@@ -53,69 +46,69 @@ auto V30MZ::opReturn() {
r.ip = readSP();
}
-auto V30MZ::opbIn() {
+auto V30MZ::opIn(Size size) {
wait(5);
- auto port = readbIP();
- r.al = in(port);
+ auto port = readIP();
+ r.al = in(port++);
+ if(size != Word) return;
+ r.ah = in(port++);
}
-auto V30MZ::opwIn() {
+auto V30MZ::opOut(Size size) {
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 port = readIP();
+ out(port++, r.al);
+ if(size != Word) return;
+ out(port++, r.ah);
}
auto V30MZ::opCallNear() {
wait(4);
- auto displacement = (int16)readwIP();
+ auto displacement = (int16)readIP(Word);
writeSP(r.ip);
r.ip += displacement;
}
auto V30MZ::opJumpFar() {
wait(6);
- auto ip = readwIP();
- auto cs = readwIP();
+ auto ip = readIP(Word);
+ auto cs = readIP(Word);
r.ip = ip;
r.cs = cs;
}
-auto V30MZ::opbInDX() {
- wait(5);
- r.al = in(r.dx);
-}
-
-auto V30MZ::opwInDX() {
+auto V30MZ::opInDX(Size size) {
wait(5);
r.al = in(r.dx + 0);
+ if(size != Word) return;
r.ah = in(r.dx + 1);
}
-auto V30MZ::opbOutDX() {
- wait(5);
- out(r.dx, r.al);
-}
-
-auto V30MZ::opwOutDX() {
+auto V30MZ::opOutDX(Size size) {
wait(5);
out(r.dx + 0, r.al);
+ if(size != Word) return;
out(r.dx + 1, r.ah);
}
+auto V30MZ::opRepeat(bool flag) {
+ wait(4);
+ auto opcode = readIP();
+ if((opcode & 0xfc) != 0x6c && (opcode & 0xfc) != 0xa4
+ && (opcode & 0xfe) != 0xaa && (opcode & 0xfc) != 0xac) {
+ //invalid argument
+ r.ip--;
+ return;
+ }
+ if(r.cx == 0) return;
+ r.cx--;
+
+ switch(opcode) {
+ case 0xa4: opMoveString(Byte); r.ip -= 2; break;
+ case 0xa5: opMoveString(Word); r.ip -= 2; break;
+ }
+}
+
auto V30MZ::opClearFlag(bool& flag) {
wait(3);
flag = false;
diff --git a/higan/processor/v30mz/memory.cpp b/higan/processor/v30mz/memory.cpp
index e9c11013..c3cb70e6 100644
--- a/higan/processor/v30mz/memory.cpp
+++ b/higan/processor/v30mz/memory.cpp
@@ -1,75 +1,58 @@
-auto V30MZ::readbIP() -> uint8 {
- return read((r.cs << 4) + r.ip++);
+auto V30MZ::read(Size size, uint16 segment, uint16 address) -> uint16 {
+ uint16 data = read(segment * 16 + address);
+ if(size == Word) data |= read(segment * 16 + ++address) << 8;
+ return data;
}
-auto V30MZ::readwIP() -> uint16 {
- uint16 word = read((r.cs << 4) + r.ip++) << 0;
- return word | read((r.cs << 4) + r.ip++) << 8;
+auto V30MZ::write(Size size, uint16 segment, uint16 address, uint16 data) -> void {
+ write(segment * 16 + address, data);
+ if(size == Word) write(segment * 16 + ++address, data >> 8);
+}
+
+//
+
+auto V30MZ::readIP(Size size) -> uint16 {
+ uint16 data = read(size, r.cs, r.ip);
+ return r.ip += size, data;
}
//
auto V30MZ::readSP() -> uint16 {
- uint16 word = read((r.ss << 4) + r.sp++) << 0;
- return word | read((r.ss << 4) + r.sp++) << 8;
+ uint16 data = read(Word, r.ss, r.sp);
+ return r.sp += Word, data;
}
auto V30MZ::writeSP(uint16 data) -> void {
- write((r.ss << 4) + --r.sp, data >> 8);
- write((r.ss << 4) + --r.sp, data >> 0);
+ r.sp -= Word;
+ write(Word, r.ss, r.sp, data);
}
//
-auto V30MZ::readb(uint20 ea) -> uint8 {
- return read(ea++);
-}
+auto V30MZ::readModRM(uint8 modRM) -> uint32 {
+ if((modRM & 0xc7) == 0x06) return r.ds << 16 | readIP(Word);
-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();
+ uint16 s = 0, a = 0;
+ if((modRM & 0xc0) == 0x40) a = (int8)readIP(Byte);
+ if((modRM & 0xc0) == 0x80) a = (int16)readIP(Word);
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;
+ case 0: s = r.ds; a += r.bx + r.si; break;
+ case 1: s = r.ds; a += r.bx + r.di; break;
+ case 2: s = r.ss; a += r.bp + r.si; break;
+ case 3: s = r.ss; a += r.bp + r.di; break;
+ case 4: s = r.ds; a += r.si; break;
+ case 5: s = r.ds; a += r.di; break;
+ case 6: s = r.ss; a += r.bp; break;
+ case 7: s = r.ds; a += r.bx; break;
}
- unreachable;
+
+ return s << 16 | a;
}
-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));
+auto V30MZ::readModRM(Size size, uint8 modRM) -> uint16 {
+ if(modRM >= 0xc0) return getRegister(size, modRM);
+ auto addr = readModRM(modRM);
+ return read(size, addr >> 16, addr);
}
diff --git a/higan/processor/v30mz/registers.cpp b/higan/processor/v30mz/registers.cpp
index c1771054..92921a2a 100644
--- a/higan/processor/v30mz/registers.cpp
+++ b/higan/processor/v30mz/registers.cpp
@@ -1,18 +1,32 @@
-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::getRegister(Size size, uint8 modRM) -> uint16 {
+ static uint8* byte[] = {&r.al, &r.cl, &r.dl, &r.bl, &r.ah, &r.ch, &r.dh, &r.bh};
+ static uint16* word[] = {&r.ax, &r.cx, &r.dx, &r.bx, &r.sp, &r.bp, &r.si, &r.di};
+ if(size == Byte) return *byte[(modRM >> 3) & 7];
+ if(size == Word) return *word[(modRM >> 3) & 7];
+ throw;
}
-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::setRegister(Size size, uint8 modRM, uint16 data) -> void {
+ static uint8* byte[] = {&r.al, &r.cl, &r.dl, &r.bl, &r.ah, &r.ch, &r.dh, &r.bh};
+ static uint16* word[] = {&r.ax, &r.cx, &r.dx, &r.bx, &r.sp, &r.bp, &r.si, &r.di};
+ if(size == Byte) *byte[(modRM >> 3) & 7] = data;
+ if(size == Word) *word[(modRM >> 3) & 7] = data;
}
-auto V30MZ::sreg(uint8 modRM) -> uint16& {
- static uint16* p[] = {&r.es, &r.cs, &r.ss, &r.ds};
- return *p[(modRM >> 3) & 3];
+//
+
+auto V30MZ::getSegment(uint8 modRM) -> uint16 {
+ static uint16* word[] = {&r.es, &r.cs, &r.ss, &r.ds};
+ return *word[(modRM >> 3) & 3];
}
+auto V30MZ::setSegment(uint8 modRM, uint16 data) -> void {
+ static uint16* word[] = {&r.es, &r.cs, &r.ss, &r.ds};
+ *word[(modRM >> 3) & 3] = data;
+}
+
+//
+
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 608ea94e..027d0588 100644
--- a/higan/processor/v30mz/v30mz.cpp
+++ b/higan/processor/v30mz/v30mz.cpp
@@ -3,6 +3,8 @@
namespace Processor {
+const uint V30MZ::Byte = 1;
+const uint V30MZ::Word = 2;
#include "registers.cpp"
#include "memory.cpp"
#include "algorithms.cpp"
@@ -22,12 +24,12 @@ auto V30MZ::exec() -> void {
auto V30MZ::execOpcode() -> void {
executed++;
- uint8 opcode = readbIP();
+ auto opcode = readIP();
wait(1);
switch(opcode) {
- case 0x32: return opbXorRegisterModRM();
- case 0x33: return opwXorRegisterModRM();
+ case 0x32: return opXorRegisterModRM(Byte);
+ case 0x33: return opXorRegisterModRM(Word);
case 0x70: return opJumpIf(r.f.v == 1);
case 0x71: return opJumpIf(r.f.v == 0);
case 0x72: return opJumpIf(r.f.c == 1);
@@ -44,39 +46,43 @@ auto V30MZ::execOpcode() -> void {
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 0x8a: return opMoveRegisterModRM(Byte);
+ case 0x8b: return opMoveRegisterModRM(Word);
case 0x8e: return opMoveSegmentRegisterModRM();
case 0x90: return opNoOperation();
- 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 0xa4: return opMoveString(Byte);
+ case 0xa5: return opMoveString(Word);
+ case 0xa8: return opTestAX(Byte);
+ case 0xa9: return opTestAX(Word);
+ case 0xb0: return opMoveRegisterImmediate(r.al);
+ case 0xb1: return opMoveRegisterImmediate(r.cl);
+ case 0xb2: return opMoveRegisterImmediate(r.dl);
+ case 0xb3: return opMoveRegisterImmediate(r.bl);
+ case 0xb4: return opMoveRegisterImmediate(r.ah);
+ case 0xb5: return opMoveRegisterImmediate(r.ch);
+ case 0xb6: return opMoveRegisterImmediate(r.dh);
+ case 0xb7: return opMoveRegisterImmediate(r.bh);
+ case 0xb8: return opMoveRegisterImmediate(r.ax);
+ case 0xb9: return opMoveRegisterImmediate(r.cx);
+ case 0xba: return opMoveRegisterImmediate(r.dx);
+ case 0xbb: return opMoveRegisterImmediate(r.bx);
+ case 0xbc: return opMoveRegisterImmediate(r.sp);
+ case 0xbd: return opMoveRegisterImmediate(r.bp);
+ case 0xbe: return opMoveRegisterImmediate(r.si);
+ case 0xbf: return opMoveRegisterImmediate(r.di);
case 0xc3: return opReturn();
- case 0xe4: return opbIn();
- case 0xe5: return opwIn();
- case 0xe6: return opbOut();
- case 0xe7: return opwOut();
+ case 0xe4: return opIn(Byte);
+ case 0xe5: return opIn(Word);
+ case 0xe6: return opOut(Byte);
+ case 0xe7: return opOut(Word);
case 0xe8: return opCallNear();
case 0xea: return opJumpFar();
- case 0xec: return opbInDX();
- case 0xed: return opwInDX();
- case 0xee: return opbOutDX();
- case 0xef: return opwOutDX();
+ case 0xec: return opInDX(Byte);
+ case 0xed: return opInDX(Word);
+ case 0xee: return opOutDX(Byte);
+ case 0xef: return opOutDX(Word);
+ case 0xf2: return opRepeat(1);
+ case 0xf3: return opRepeat(0);
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 af41e9b2..bb2869fe 100644
--- a/higan/processor/v30mz/v30mz.hpp
+++ b/higan/processor/v30mz/v30mz.hpp
@@ -5,6 +5,10 @@
namespace Processor {
struct V30MZ {
+ using Size = const uint&;
+ static const uint Byte;
+ static const uint Word;
+
virtual auto wait(uint clocks = 1) -> void = 0;
virtual auto read(uint20 addr) -> uint8 = 0;
virtual auto write(uint20 addr, uint8 data) -> void = 0;
@@ -16,56 +20,46 @@ struct V30MZ {
auto power() -> void;
//registers.cpp
- auto regb(uint8) -> uint8&;
- auto regw(uint8) -> uint16&;
- auto sreg(uint8) -> uint16&;
+ auto getRegister(Size, uint8) -> uint16;
+ auto setRegister(Size, uint8, uint16) -> void;
+
+ auto getSegment(uint8) -> uint16;
+ auto setSegment(uint8, uint16) -> void;
//memory.cpp
- auto readbIP() -> uint8;
- auto readwIP() -> uint16;
+ auto read(Size, uint16, uint16) -> uint16;
+ auto write(Size, uint16, uint16, uint16) -> void;
+
+ auto readIP(Size = Byte) -> 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;
+ auto readModRM(uint8) -> uint32;
+ auto readModRM(Size, uint8) -> uint16;
//algorithms.cpp
auto parity(uint16) const -> bool;
-
- auto albAnd(uint8, uint8) -> uint8;
- auto alwAnd(uint16, uint16) -> uint16;
+ auto alAnd(Size, uint16, uint16) -> uint16;
//instructions.cpp
- auto opbXorRegisterModRM();
- auto opwXorRegisterModRM();
+ auto opXorRegisterModRM(Size);
auto opJumpIf(bool);
- auto opbMoveRegisterModRM();
- auto opwMoveRegisterModRM();
+ auto opMoveRegisterModRM(Size);
auto opMoveSegmentRegisterModRM();
auto opNoOperation();
- auto opTestAL();
- auto opTestAX();
- auto opbMoveRegisterImmediate(uint8&);
- auto opwMoveRegisterImmediate(uint16&);
+ auto opMoveString(Size);
+ auto opTestAX(Size);
+ auto opMoveRegisterImmediate(uint8&);
+ auto opMoveRegisterImmediate(uint16&);
auto opReturn();
- auto opbIn();
- auto opwIn();
- auto opbOut();
- auto opwOut();
+ auto opIn(Size);
+ auto opOut(Size);
auto opCallNear();
auto opJumpFar();
- auto opbInDX();
- auto opwInDX();
- auto opbOutDX();
- auto opwOutDX();
+ auto opInDX(Size);
+ auto opOutDX(Size);
+ auto opRepeat(bool);
auto opClearFlag(bool&);
auto opSetFlag(bool&);