From d0ddd87e9c747447784f3c0cce524759f316afd6 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 31 Jan 2016 18:59:44 +1100 Subject: [PATCH] Update to v097r06 release. byuu says: Man, the 80186 is taking a lot longer to implement than I thought it would. So far I'm 18 hours into this emulator. Whereas I had Super Mario Bros fully playable (no sound) in 12 hours for the NES >_> I refactored all the byte/word variant functions to single functions that take a size parameter. Cuts the amount of code in half. Also implemented repz/repnz + movsb/movsw, so Riviera now gets 299 instructions in before dying. Nobody really bothers to explain how the CPU actually implements these instructions, but I think I have it right: ignore non-string opcodes that follow rep, invoke the string operations inside the rep opcodes to prevent interrupts from triggering between the two (which will be even more fun for segment selector overrides ...) The next opcode needed is 0xC7, which ... throws ModRM on its head. In this mode, ModRM is only used to determine the target operand (and it doesn't use the middle bits for that at all), and the source is an immediate that follows it. Gonna have to waste a few more hours thinking about how best to handle that. Also, disabled HiDPI for higan as well on OS X. --- higan/data/higan.plist | 2 +- higan/emulator/emulator.hpp | 2 +- higan/processor/v30mz/algorithms.cpp | 19 +--- higan/processor/v30mz/disassembler.cpp | 140 +++++++++++++++---------- higan/processor/v30mz/instructions.cpp | 117 ++++++++++----------- higan/processor/v30mz/memory.cpp | 91 +++++++--------- higan/processor/v30mz/registers.cpp | 32 ++++-- higan/processor/v30mz/v30mz.cpp | 68 ++++++------ higan/processor/v30mz/v30mz.hpp | 60 +++++------ 9 files changed, 268 insertions(+), 263 deletions(-) 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&);