diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index d86d2454..c1a642f6 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.08"; + static const string Version = "097.09"; 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 f4f6e263..45f65c0f 100644 --- a/higan/processor/v30mz/algorithms.cpp +++ b/higan/processor/v30mz/algorithms.cpp @@ -9,7 +9,7 @@ auto V30MZ::parity(uint16 value) const -> bool { #define bits (size == Byte ? 8 : 16) #define mask (size == Byte ? 0xff : 0xffff) -#define sign (size == Byte ? 0x80 : 0xffff) +#define sign (size == Byte ? 0x80 : 0x8000) auto V30MZ::alAdc(Size size, uint16 x, uint16 y) -> uint16 { return alAdd(size, x, y + r.f.c); @@ -37,6 +37,74 @@ auto V30MZ::alAnd(Size size, uint16 x, uint16 y) -> uint16 { return result; } +auto V30MZ::alDec(Size size, uint16 x) -> uint16 { + uint16 result = (x - 1) & mask; + r.f.p = parity(result); + r.f.h = (x & 0x0f) == 0; + r.f.z = result == 0; + r.f.s = result & sign; + r.f.v = result == sign - 1; + return result; +} + +auto V30MZ::alDiv(Size size, uint32 x, uint32 y) -> uint32 { + if(y == 0) return 0; //todo: throw exception + uint32 quotient = x / y; + uint32 remainder = x % y; + return (remainder & mask) << bits | (quotient & mask); +} + +auto V30MZ::alDivi(Size size, int32 x, int32 y) -> uint32 { + if(y == 0) return 0; //todo: throw exception + x = size == Byte ? (int8)x : (int16)x; + y = size == Byte ? (int8)y : (int16)y; + uint32 quotient = x / y; + uint32 remainder = x % y; + return (remainder & mask) << bits | (quotient & mask); +} + +auto V30MZ::alInc(Size size, uint16 x) -> uint16 { + uint16 result = (x + 1) & mask; + r.f.p = parity(result); + r.f.h = (x & 0x0f) == 0x0f; + r.f.z = result == 0; + r.f.s = result & sign; + r.f.v = result == sign; + return result; +} + +auto V30MZ::alMul(Size size, uint16 x, uint16 y) -> uint32 { + uint32 result = x * y; + r.f.c = result >> bits; + r.f.v = result >> bits; + return result; +} + +auto V30MZ::alMuli(Size size, int16 x, int16 y) -> uint32 { + x = size == Byte ? (int8)x : (int16)x; + y = size == Byte ? (int8)y : (int16)y; + uint32 result = x * y; + r.f.c = result >> bits; + r.f.v = result >> bits; + return result; +} + +auto V30MZ::alNeg(Size size, uint16 x) -> uint16 { + uint16 result = (-x) & mask; + r.f.c = x; + r.f.p = parity(result); + r.f.h = x & 0x0f; + r.f.z = result == 0; + r.f.s = result & sign; + r.f.v = x == sign; + return result; +} + +auto V30MZ::alNot(Size size, uint16 x) -> uint16 { + uint16 result = (~x) & mask; + return result; +} + auto V30MZ::alOr(Size size, uint16 x, uint16 y) -> uint16 { uint16 result = (x | y) & mask; r.f.c = 0; diff --git a/higan/processor/v30mz/disassembler.cpp b/higan/processor/v30mz/disassembler.cpp index 8bce4c4f..54dcaff3 100644 --- a/higan/processor/v30mz/disassembler.cpp +++ b/higan/processor/v30mz/disassembler.cpp @@ -28,6 +28,12 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str uint16 word = fetch(); word |= fetch() << 8; return {"$", hex(ip + (int16)word, 4L)}; }; + auto readIndirectByte = [&]() -> string { + return {"[", readWord(), "]"}; + }; + auto readIndirectWord = [&]() -> string { + return {"{", readWord(), "}"}; + }; auto readRegByte = [&](bool inc = true) -> string { uint8 modRM = fetch(inc); static const string reg[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}; @@ -57,11 +63,11 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str uint8 modRM = fetch(inc); static const string reg[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}; if(modRM >= 0xc0) return reg[(uint3)modRM]; - if((modRM & 0xc7) == 0x06) return {"[", readWord(), "]"}; + if((modRM & 0xc7) == 0x06) return {"{", readWord(), "}"}; static const string mem[] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"}; - if((modRM & 0xc0) == 0x40) return {"[", mem[(uint3)modRM], "+", readByte(), "]"}; - if((modRM & 0xc0) == 0x80) return {"[", mem[(uint3)modRM], "+", readWord(), "]"}; - return {"[", mem[(uint3)modRM], "]"}; + if((modRM & 0xc0) == 0x40) return {"{", mem[(uint3)modRM], "+", readByte(), "}"}; + if((modRM & 0xc0) == 0x80) return {"{", mem[(uint3)modRM], "+", readWord(), "}"}; + return {"{", mem[(uint3)modRM], "}"}; }; auto readGroup = [&](uint group) -> string { uint8 modRM = fetch(false); @@ -71,7 +77,7 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str {"test", "??? ", "not ", "neg ", "mul ", "imul", "div ", "idiv"}, {"inc ", "dec ", "??? ", "??? ", "??? ", "??? ", "??? ", "??? "}, }; - return opcode[group - 3][(uint3)(modRM >> 3)]; + return opcode[group - 1][(uint3)(modRM >> 3)]; }; auto opcode = fetch(); @@ -172,6 +178,22 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str case 0x5d: s = {"pop bp"}; break; case 0x5e: s = {"pop si"}; break; case 0x5f: s = {"pop di"}; break; + case 0x60: s = {"pusha "}; break; + case 0x61: s = {"popa "}; break; + case 0x62: s = {"bound {0},{1}", format{readRegWord(0), readMemWord()}}; break; +//case 0x63: +//case 0x64: +//case 0x65: +//case 0x66: +//case 0x67: + case 0x68: s = {"push {0}", format{readWord()}}; break; + case 0x69: s = {"imul {0},{1},{2}", format{readRegWord(0), readMemWord(), readWord()}}; break; + case 0x6a: s = {"push {0}", format{readByteSigned()}}; break; + case 0x6b: s = {"imul {0},{1},{2}", format{readRegWord(0), readMemWord(), readByteSigned()}}; break; + case 0x6c: s = {"insb "}; break; + case 0x6d: s = {"insw "}; break; + case 0x6e: s = {"outsb "}; break; + case 0x6f: s = {"outsw "}; break; case 0x70: s = {"jo {0}", format{readRelativeByte()}}; break; case 0x71: s = {"jno {0}", format{readRelativeByte()}}; break; case 0x72: s = {"jc {0}", format{readRelativeByte()}}; break; @@ -189,14 +211,21 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str case 0x7e: s = {"jle {0}", format{readRelativeByte()}}; break; case 0x7f: s = {"jnle {0}", format{readRelativeByte()}}; break; case 0x80: s = {"{0} {1},{2}", format{readGroup(1), readMemByte(), readByte()}}; break; - case 0x81: s = {"{0}w {1},{2}", format{readGroup(1), readMemWord(), readWord()}}; break; + case 0x81: s = {"{0} {1},{2}", format{readGroup(1), readMemWord(), readWord()}}; break; case 0x82: s = {"{0} {1},{2}", format{readGroup(1), readMemByte(), readByteSigned()}}; break; - case 0x83: s = {"{0}w {1},{2}", format{readGroup(1), readMemWord(), readByteSigned()}}; break; + case 0x83: s = {"{0} {1},{2}", format{readGroup(1), readMemWord(), readByteSigned()}}; break; + case 0x84: s = {"test {0},{1}", format{readMemByte(0), readRegByte()}}; break; + case 0x85: s = {"test {0},{1}", format{readMemWord(0), readRegWord()}}; break; + case 0x86: s = {"xchg {0},{1}", format{readMemByte(0), readRegByte()}}; break; + case 0x87: s = {"xchg {0},{1}", format{readMemWord(0), readRegWord()}}; break; case 0x88: s = {"mov {0},{1}", format{readMemByte(0), readRegByte()}}; break; case 0x89: s = {"mov {0},{1}", format{readMemWord(0), readRegWord()}}; break; case 0x8a: s = {"mov {0},{1}", format{readRegByte(0), readMemByte()}}; break; case 0x8b: s = {"mov {0},{1}", format{readRegWord(0), readMemWord()}}; break; + case 0x8c: s = {"mov {0},{1}", format{readMemWord(0), readSeg()}}; break; + case 0x8d: s = {"lea {0},{1}", format{readRegWord(0), readMemWord()}}; break; case 0x8e: s = {"mov {0},{1}", format{readSeg(0), readMemWord()}}; break; + case 0x8f: s = {"pop {0}", format{readMemWord()}}; break; case 0x90: s = {"nop "}; break; case 0x91: s = {"xchg ax,cx"}; break; case 0x92: s = {"xchg ax,dx"}; break; @@ -205,11 +234,15 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str case 0x95: s = {"xchg ax,bp"}; break; case 0x96: s = {"xchg ax,si"}; break; case 0x97: s = {"xchg ax,di"}; break; + case 0x98: s = {"cbw "}; break; + case 0x99: s = {"cwd "}; break; case 0x9a: s = {"call {1}:{0}", format{readWord(), readWord()}}; break; - case 0xa0: s = {"mov al,[{0}]", format{readWord()}}; break; - case 0xa1: s = {"mov ax,[{0}]", format{readWord()}}; break; - case 0xa2: s = {"mov [{0}],al", format{readWord()}}; break; - case 0xa3: s = {"mov [{0}],ax", format{readWord()}}; break; + case 0x9e: s = {"sahf "}; break; + case 0x9f: s = {"lahf "}; break; + case 0xa0: s = {"mov al,{0}", format{readIndirectByte()}}; break; + case 0xa1: s = {"mov ax,{0}", format{readIndirectWord()}}; break; + case 0xa2: s = {"mov {0},al", format{readIndirectByte()}}; break; + case 0xa3: s = {"mov {0},ax", format{readIndirectWord()}}; break; case 0xa4: s = {"movsb "}; break; case 0xa5: s = {"movsw "}; break; case 0xa6: s = {"cmpsb "}; break; @@ -239,17 +272,20 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str case 0xbe: s = {"mov si,{0}", format{readWord()}}; break; case 0xbf: s = {"mov di,{0}", format{readWord()}}; break; case 0xc0: s = {"{0} {1},{2}", format{readGroup(2), readMemByte(), readByte()}}; break; - case 0xc1: s = {"{0}w {1},{2}", format{readGroup(2), readMemWord(), readByte()}}; break; + case 0xc1: s = {"{0} {1},{2}", format{readGroup(2), readMemWord(), readByte()}}; break; case 0xc2: s = {"ret {0}", format{readWord()}}; break; case 0xc3: s = {"ret "}; break; case 0xc6: s = {"mov {0},{1}", format{readMemByte(), readByte()}}; break; case 0xc7: s = {"mov {0},{1}", format{readMemWord(), readWord()}}; break; + case 0xc9: s = {"leave "}; break; case 0xca: s = {"retf {0}", format{readWord()}}; break; case 0xcb: s = {"retf "}; break; + case 0xce: s = {"into "}; break; + case 0xcf: s = {"iret "}; break; case 0xd0: s = {"{0} {1},1", format{readGroup(2), readMemByte()}}; break; - case 0xd1: s = {"{0}w {1},1", format{readGroup(2), readMemWord()}}; break; + case 0xd1: s = {"{0} {1},1", format{readGroup(2), readMemWord()}}; break; case 0xd2: s = {"{0} {1},cl", format{readGroup(2), readMemByte()}}; break; - case 0xd3: s = {"{0}w {1},cl", format{readGroup(2), readMemWord()}}; break; + case 0xd3: s = {"{0} {1},cl", format{readGroup(2), readMemWord()}}; break; //case 0xd8: //case 0xd9: //case 0xda: @@ -277,8 +313,10 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str //case 0xf1: case 0xf2: s = {"repnz: "}; break; case 0xf3: s = {"repz: "}; break; + case 0xf4: s = {"hlt "}; break; + case 0xf5: s = {"cmc "}; break; case 0xf6: s = {"{0} {1},{2}", format{readGroup(3), readMemByte(), readByte()}}; break; - case 0xf7: s = {"{0}w {1},{2}", format{readGroup(3), readMemWord(), readWord()}}; break; + case 0xf7: s = {"{0} {1},{2}", format{readGroup(3), readMemWord(), readWord()}}; break; case 0xf8: s = {"clc "}; break; case 0xf9: s = {"stc "}; break; case 0xfa: s = {"cli "}; break; @@ -286,7 +324,7 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str case 0xfc: s = {"cld "}; break; case 0xfd: s = {"std "}; break; case 0xfe: s = {"{0} {1},{2}", format{readGroup(4), readMemByte(), readByte()}}; break; - case 0xff: s = {"{0}w {1},{2}", format{readGroup(4), readMemWord(), readWord()}}; break; + case 0xff: s = {"{0} {1},{2}", format{readGroup(4), readMemWord(), readWord()}}; break; default: s = {"??? [", hex(opcode, 2L), "]"}; diff --git a/higan/processor/v30mz/instructions.cpp b/higan/processor/v30mz/instructions.cpp index feef06e5..12384435 100644 --- a/higan/processor/v30mz/instructions.cpp +++ b/higan/processor/v30mz/instructions.cpp @@ -98,12 +98,9 @@ auto V30MZ::opSubAccImm(Size size) { //2e cs: //36 ss: //3e ds: -auto V30MZ::opPrefix(uint flag) { +auto V30MZ::opPrefix(uint16& segment) { prefix.hold = true; - prefix.es = flag == 0; - prefix.cs = flag == 1; - prefix.ss = flag == 2; - prefix.ds = flag == 3; + prefix.segment = segment; } //27 daa @@ -200,6 +197,73 @@ auto V30MZ::opPopReg(uint16& reg) { reg = pop(); } +//60 pusha +auto V30MZ::opPushAll() { + wait(8); + auto sp = r.sp; + push(r.ax); + push(r.cx); + push(r.dx); + push(r.bx); + push(sp); + push(r.bp); + push(r.si); + push(r.di); +} + +//61 popa +auto V30MZ::opPopAll() { + wait(7); + r.di = pop(); + r.si = pop(); + r.bp = pop(); + auto sp = pop(); + r.bx = pop(); + r.dx = pop(); + r.cx = pop(); + r.ax = pop(); + r.sp = sp; +} + +//62 bound reg,mem,mem +auto V30MZ::opBound() { + wait(12); + auto modRM = fetch(); + auto bound = getMem(Long, modRM); + auto reg = getReg(Word, modRM); + uint16 lo = bound >> 0; + uint16 hi = bound >> 16; + if(reg < lo || reg > hi) { + //todo + } +} + +//68 push imm16 +//6a push imm8s +auto V30MZ::opPushImm(Size size) { + push(size == Word ? fetch(Word) : (int8)fetch(Byte)); +} + +auto V30MZ::opMultiplySignedRegMemImm(Size size) { + wait(2); + auto modRM = fetch(); + auto mem = getMem(size, modRM); + auto imm = size == Word ? fetch(Word) : (int8)fetch(Byte); + setReg(size, modRM, alMuli(size, mem, imm)); +} + +//9e sahf +auto V30MZ::opStoreFlagsAcc() { + wait(3); + r.f = (r.f & 0xff00) | r.ah; +} + +//9f lahf +auto V30MZ::opLoadAccFlags() { + wait(1); + r.ah = (r.f & 0x00ff); +} + auto V30MZ::opJumpIf(bool condition) { auto offset = (int8)fetch(); if(condition) r.ip += offset; @@ -225,6 +289,22 @@ auto V30MZ::opGroup1MemImm(Size size, bool sign) { } } +auto V30MZ::opTestMemReg(Size size) { + auto modRM = fetch(); + auto mem = getMem(size, modRM); + auto reg = getReg(size, modRM); + alAnd(size, mem, reg); +} + +auto V30MZ::opExchangeMemReg(Size size) { + wait(2); + auto modRM = fetch(); + auto mem = getMem(size, modRM); + auto reg = getReg(size, modRM); + setMem(size, modRM, reg); + setReg(size, modRM, mem); +} + auto V30MZ::opMoveMemReg(Size size) { auto modRM = fetch(); setMem(size, modRM, getReg(size, modRM)); @@ -235,12 +315,27 @@ auto V30MZ::opMoveRegMem(Size size) { setReg(size, modRM, getMem(size, modRM)); } +auto V30MZ::opLoadEffectiveAddressRegMem() { + auto modRM = fetch(); + setReg(Word, modRM, getMemAddress(modRM)); +} + +auto V30MZ::opMoveMemSeg() { + auto modRM = fetch(); + setMem(Word, modRM, getSeg(modRM)); +} + auto V30MZ::opMoveSegMem() { wait(1); auto modRM = fetch(); setSeg(modRM, getMem(Word, modRM)); } +auto V30MZ::opPopMem() { + auto modRM = fetch(); + setMem(Word, modRM, pop()); +} + auto V30MZ::opNop() { } @@ -251,6 +346,16 @@ auto V30MZ::opExchange(uint16& x, uint16& y) { y = z; } +//98 cbw +auto V30MZ::opSignExtendByte() { + setAcc(Word, (int8)getAcc(Byte)); +} + +//99 cwd +auto V30MZ::opSignExtendWord() { + setAcc(Long, (int16)getAcc(Word)); +} + auto V30MZ::opCallFar() { wait(9); auto ip = fetch(Word); @@ -269,29 +374,54 @@ auto V30MZ::opMoveMemAcc(Size size) { write(size, r.ds, fetch(Word), getAcc(size)); } +auto V30MZ::opInString(Size size) { + wait(5); + auto data = in(size, r.dx); + write(size, r.es, r.di, data); + r.di += r.f.d ? -size : size; + + if(prefix.repeat && --r.cx) { + prefix.hold = true; + r.ip--; + } +} + +auto V30MZ::opOutString(Size size) { + wait(6); + auto data = read(size, segment(r.ds), r.si); + out(size, r.dx, data); + r.si += r.f.d ? -size : size; + + if(prefix.repeat && --r.cx) { + prefix.hold = true; + r.ip--; + } +} + auto V30MZ::opMoveString(Size size) { wait(4); - write(size, r.es, r.di, read(size, r.ds, r.si)); + auto data = read(size, segment(r.ds), r.si); + write(size, r.es, r.di, data); r.si += r.f.d ? -size : size; r.di += r.f.d ? -size : size; - if(prefix.repnz || prefix.repz) { - if(--r.cx) r.ip--, prefix.hold = true; + if(prefix.repeat && --r.cx) { + prefix.hold = true; + r.ip--; } } auto V30MZ::opCompareString(Size size) { wait(5); - auto x = read(size, r.ds, r.si); + auto x = read(size, segment(r.ds), r.si); auto y = read(size, r.es, r.di); r.si += r.f.d ? -size : size; r.di += r.f.d ? -size : size; alSub(size, x, y); - if(prefix.repnz || prefix.repz) { - if(r.f.z == 1 && prefix.repnz) return; - if(r.f.z == 0 && prefix.repz) return; - if(--r.cx) r.ip--, prefix.hold = true; + if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) { + prefix.hold = true; + r.ip--; } } @@ -304,8 +434,9 @@ auto V30MZ::opStoreString(Size size) { write(size, r.es, r.di, getAcc(size)); r.di += r.f.d ? -size : size; - if(prefix.repnz || prefix.repz) { - if(--r.cx) r.ip--, prefix.hold = true; + if(prefix.repeat && --r.cx) { + prefix.hold = true; + r.ip--; } } @@ -313,10 +444,11 @@ auto V30MZ::opStoreString(Size size) { //ad lodsw auto V30MZ::opLoadString(Size size) { wait(2); - setAcc(size, read(size, r.ds, r.si)); + setAcc(size, read(size, segment(r.ds), r.si)); - if(prefix.repnz || prefix.repz) { - if(--r.cx) r.ip--, prefix.hold = true; + if(prefix.repeat && --r.cx) { + prefix.hold = true; + r.ip--; } } @@ -328,10 +460,9 @@ auto V30MZ::opSubtractCompareString(Size size) { auto y = read(size, r.es, r.di); alSub(size, x, y); - if(prefix.repnz || prefix.repz) { - if(r.f.z == 1 && prefix.repnz) return; - if(r.f.z == 0 && prefix.repz) return; - if(--r.cx) r.ip--, prefix.hold = true; + if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) { + prefix.hold = true; + r.ip--; } } @@ -374,6 +505,24 @@ auto V30MZ::opReturnFar() { r.cs = pop(); } +auto V30MZ::opReturnInt() { + wait(9); + r.ip = pop(); + r.cs = pop(); + r.f = pop(); +} + +auto V30MZ::opInto() { + wait(5); + //todo +} + +auto V30MZ::opLeave() { + wait(1); + r.sp = r.bp; + r.bp = pop(); +} + auto V30MZ::opGroup2MemImm(Size size, maybe imm) { auto modRM = fetch(); if(!imm) { @@ -396,11 +545,31 @@ auto V30MZ::opGroup2MemImm(Size size, maybe imm) { auto V30MZ::opGroup3MemImm(Size size) { auto modRM = fetch(); auto mem = getMem(size, modRM); + switch((uint3)(modRM >> 3)) { + case 0: alAnd(size, mem, fetch(size)); break; + case 1: break; + case 2: wait(2); setMem(size, modRM, alNot(size, mem)); break; + case 3: wait(2); setMem(size, modRM, alNeg(size, mem)); break; + case 4: wait(2); setAcc(size * 2, alMul(size, getAcc(size), mem)); break; + case 5: wait(2); setAcc(size * 2, alMuli(size, getAcc(size), mem)); break; break; + case 6: wait(size == Byte ? 15 : 23); setAcc(size * 2, alDiv(size, getAcc(size * 2), mem)); break; + case 7: wait(size == Byte ? 17 : 24); setAcc(size * 2, alDivi(size, getAcc(size * 2), mem)); break; + } } auto V30MZ::opGroup4MemImm(Size size) { auto modRM = fetch(); auto mem = getMem(size, modRM); + switch((uint3)(modRM >> 3)) { + case 0: wait(2); setMem(size, modRM, alInc(size, mem)); break; + case 1: wait(2); setMem(size, modRM, alDec(size, mem)); break; + case 2: break; + case 3: break; + case 4: break; + case 5: break; + case 6: break; + case 7: break; + } } auto V30MZ::opLoopWhile(bool value) { @@ -483,8 +652,19 @@ auto V30MZ::opRepeat(bool flag) { wait(4); if(r.cx == 0) return; prefix.hold = true; - prefix.repnz = flag == 0; - prefix.repz = flag == 1; + prefix.repeat = flag; +} + +//f4 halt +auto V30MZ::opHalt() { + wait(8); + //todo +} + +//f5 cmc +auto V30MZ::opComplementCarry() { + wait(3); + r.f.c = !r.f.c; } auto V30MZ::opClearFlag(bool& flag) { diff --git a/higan/processor/v30mz/memory.cpp b/higan/processor/v30mz/memory.cpp index 5f4b4051..68e8f20a 100644 --- a/higan/processor/v30mz/memory.cpp +++ b/higan/processor/v30mz/memory.cpp @@ -1,6 +1,8 @@ -auto V30MZ::read(Size size, uint16 segment, uint16 address) -> uint16 { - uint16 data = read(segment * 16 + address); +auto V30MZ::read(Size size, uint16 segment, uint16 address) -> uint32 { + uint32 data = read(segment * 16 + address); if(size == Word) data |= read(segment * 16 + ++address) << 8; + if(size == Long) data |= read(segment * 16 + ++address) << 16; + if(size == Long) data |= read(segment * 16 + ++address) << 24; return data; } @@ -11,6 +13,19 @@ auto V30MZ::write(Size size, uint16 segment, uint16 address, uint16 data) -> voi // +auto V30MZ::in(Size size, uint16 address) -> uint16 { + uint16 data = in(address); + if(size == Word) data |= in(++address) << 8; + return data; +} + +auto V30MZ::out(Size size, uint16 address, uint16 data) -> void { + out(address, data); + if(size == Word) out(++address, data >> 8); +} + +// + auto V30MZ::fetch(Size size) -> uint16 { uint16 data = read(size, r.cs, r.ip); return r.ip += size, data; diff --git a/higan/processor/v30mz/modrm.cpp b/higan/processor/v30mz/modrm.cpp index 1651655d..8a48d10e 100644 --- a/higan/processor/v30mz/modrm.cpp +++ b/higan/processor/v30mz/modrm.cpp @@ -4,9 +4,7 @@ //d2-d0 => mem auto V30MZ::getReg(Size size, uint8 modRM) -> uint16 { - if(size == Byte) return r.byte(modRM >> 3); - if(size == Word) return r.word(modRM >> 3); - unreachable; + return size == Byte ? r.byte(modRM >> 3) : r.word(modRM >> 3); } auto V30MZ::setReg(Size size, uint8 modRM, uint16 data) -> void { @@ -44,15 +42,10 @@ auto V30MZ::getMemAddress(uint8 modRM) -> uint32 { case 7: s = r.ds; a += r.bx; break; } - if(prefix.es) s = r.es; - if(prefix.cs) s = r.cs; - if(prefix.ss) s = r.ss; - if(prefix.ds) s = r.ds; - - return s << 16 | a; + return segment(s) << 16 | a; } -auto V30MZ::getMem(Size size, uint8 modRM) -> uint16 { +auto V30MZ::getMem(Size size, uint8 modRM) -> uint32 { if(modRM >= 0xc0) return getReg(size, modRM << 3); auto addr = getMemAddress(modRM); return read(size, addr >> 16, addr); diff --git a/higan/processor/v30mz/registers.cpp b/higan/processor/v30mz/registers.cpp index b7df7f3d..383725f1 100644 --- a/higan/processor/v30mz/registers.cpp +++ b/higan/processor/v30mz/registers.cpp @@ -1,12 +1,19 @@ -auto V30MZ::getAcc(Size size) -> uint16 { +auto V30MZ::segment(uint16 segment) -> uint16 { + if(prefix.segment) return prefix.segment(); + return segment; +} + +auto V30MZ::getAcc(Size size) -> uint32 { if(size == Byte) return r.al; if(size == Word) return r.ax; + if(size == Long) return r.dx << 16 | r.ax; unreachable; } -auto V30MZ::setAcc(Size size, uint16 data) -> void { +auto V30MZ::setAcc(Size size, uint32 data) -> void { if(size == Byte) r.al = data; if(size == Word) r.ax = data; + if(size == Long) r.ax = data, r.dx = data >> 16; } auto V30MZ::Registers::byte(uint3 r) -> uint8& { diff --git a/higan/processor/v30mz/v30mz.cpp b/higan/processor/v30mz/v30mz.cpp index c3fe3903..e9b1c64d 100644 --- a/higan/processor/v30mz/v30mz.cpp +++ b/higan/processor/v30mz/v30mz.cpp @@ -3,8 +3,6 @@ namespace Processor { -const uint V30MZ::Byte = 1; -const uint V30MZ::Word = 2; #include "registers.cpp" #include "modrm.cpp" #include "memory.cpp" @@ -15,7 +13,7 @@ const uint V30MZ::Word = 2; auto V30MZ::exec() -> void { if(halt) return wait(1); - #if 0 + #if 1 static uint16 cs = 0, ip = 0; if(cs != r.cs || ip != r.ip) print(disassemble(cs = r.cs, ip = r.ip), "\n"); #endif @@ -25,8 +23,8 @@ auto V30MZ::exec() -> void { if(prefix.hold) { prefix.hold = false; } else { - prefix.es = prefix.cs = prefix.ss = prefix.ds = false; - prefix.repnz = prefix.repz = false; + prefix.segment = nothing; + prefix.repeat = nothing; } } @@ -75,7 +73,7 @@ auto V30MZ::execOpcode() -> void { case 0x23: return opAndRegMem(Word); case 0x24: return opAndAccImm(Byte); case 0x25: return opAndAccImm(Word); - case 0x26: return opPrefix(0); //es: + case 0x26: return opPrefix(r.es); case 0x27: return opDecimalAdjust(0); //daa case 0x28: return opSubMemReg(Byte); case 0x29: return opSubMemReg(Word); @@ -83,7 +81,7 @@ auto V30MZ::execOpcode() -> void { case 0x2b: return opSubRegMem(Word); case 0x2c: return opSubAccImm(Byte); case 0x2d: return opSubAccImm(Word); - case 0x2e: return opPrefix(1); //cs: + case 0x2e: return opPrefix(r.cs); case 0x2f: return opDecimalAdjust(1); //das case 0x30: return opXorMemReg(Byte); case 0x31: return opXorMemReg(Word); @@ -91,7 +89,7 @@ auto V30MZ::execOpcode() -> void { case 0x33: return opXorRegMem(Word); case 0x34: return opXorAccImm(Byte); case 0x35: return opXorAccImm(Word); - case 0x36: return opPrefix(2); //ss: + case 0x36: return opPrefix(r.ss); case 0x37: return opAsciiAdjust(0); //aaa case 0x38: return opCmpMemReg(Byte); case 0x39: return opCmpMemReg(Word); @@ -99,7 +97,7 @@ auto V30MZ::execOpcode() -> void { case 0x3b: return opCmpRegMem(Word); case 0x3c: return opCmpAccImm(Byte); case 0x3d: return opCmpAccImm(Word); - case 0x3e: return opPrefix(3); //ds: + case 0x3e: return opPrefix(r.ds); case 0x3f: return opAsciiAdjust(1); //aas case 0x40: return opIncReg(r.ax); case 0x41: return opIncReg(r.cx); @@ -133,7 +131,22 @@ auto V30MZ::execOpcode() -> void { case 0x5d: return opPopReg(r.bp); case 0x5e: return opPopReg(r.si); case 0x5f: return opPopReg(r.di); -//60-62,68-6f + case 0x60: return opPushAll(); + case 0x61: return opPopAll(); + case 0x62: return opBound(); + case 0x63: return; + case 0x64: return; + case 0x65: return; + case 0x66: return; + case 0x67: return; + case 0x68: return opPushImm(Word); + case 0x69: return opMultiplySignedRegMemImm(Word); + case 0x6a: return opPushImm(Byte); + case 0x6b: return opMultiplySignedRegMemImm(Byte); + case 0x6c: return opInString(Byte); + case 0x6d: return opInString(Word); + case 0x6e: return opOutString(Byte); + case 0x6f: return opOutString(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); @@ -154,14 +167,18 @@ auto V30MZ::execOpcode() -> void { case 0x81: return opGroup1MemImm(Word, 0); case 0x82: return opGroup1MemImm(Byte, 1); case 0x83: return opGroup1MemImm(Word, 1); -//84-87 + case 0x84: return opTestMemReg(Byte); + case 0x85: return opTestMemReg(Word); + case 0x86: return opExchangeMemReg(Byte); + case 0x87: return opExchangeMemReg(Word); case 0x88: return opMoveMemReg(Byte); case 0x89: return opMoveMemReg(Word); case 0x8a: return opMoveRegMem(Byte); case 0x8b: return opMoveRegMem(Word); -//8c,8d + case 0x8c: return opMoveMemSeg(); + case 0x8d: return opLoadEffectiveAddressRegMem(); case 0x8e: return opMoveSegMem(); -//8f + case 0x8f: return opPopMem(); case 0x90: return opNop(); case 0x91: return opExchange(r.ax, r.cx); case 0x92: return opExchange(r.ax, r.dx); @@ -170,9 +187,14 @@ auto V30MZ::execOpcode() -> void { case 0x95: return opExchange(r.ax, r.bp); case 0x96: return opExchange(r.ax, r.si); case 0x97: return opExchange(r.ax, r.di); -//98-99 + case 0x98: return opSignExtendByte(); + case 0x99: return opSignExtendWord(); case 0x9a: return opCallFar(); -//9b-9f +//9b +//9c +//9d + case 0x9e: return opStoreFlagsAcc(); + case 0x9f: return opLoadAccFlags(); case 0xa0: return opMoveAccMem(Byte); case 0xa1: return opMoveAccMem(Word); case 0xa2: return opMoveMemAcc(Byte); @@ -209,18 +231,26 @@ auto V30MZ::execOpcode() -> void { case 0xc1: return opGroup2MemImm(Word); case 0xc2: return opReturnImm(); case 0xc3: return opReturn(); -//c4,c5 +//c4 +//c5 case 0xc6: return opMoveMemImm(Byte); case 0xc7: return opMoveMemImm(Word); -//c8,c9 +//c8 + case 0xc9: return opLeave(); case 0xca: return opReturnFarImm(); case 0xcb: return opReturnFar(); -//cc-cf +//cc +//cd + case 0xce: return opInto(); + case 0xcf: return opReturnInt(); case 0xd0: return opGroup2MemImm(Byte, 1); case 0xd1: return opGroup2MemImm(Word, 1); case 0xd2: return opGroup2MemImm(Byte, r.cl); case 0xd3: return opGroup2MemImm(Word, r.cl); -//d4,d5,d7 +//d4 +//d5 + case 0xd6: return; +//d7 case 0xd8: return; //fpo1 case 0xd9: return; //fpo1 case 0xda: return; //fpo1 @@ -249,7 +279,8 @@ auto V30MZ::execOpcode() -> void { case 0xf1: return; case 0xf2: return opRepeat(0); //repnz case 0xf3: return opRepeat(1); //repz -//f4-f5 + case 0xf4: return opHalt(); + case 0xf5: return opComplementCarry(); case 0xf6: return opGroup3MemImm(Byte); case 0xf7: return opGroup3MemImm(Word); case 0xf8: return opClearFlag(r.f.c); @@ -272,8 +303,8 @@ auto V30MZ::power() -> void { executed = 0; prefix.hold = false; - prefix.es = prefix.cs = prefix.ss = prefix.ds = false; - prefix.repz = prefix.repnz = false; + prefix.segment = nothing; + prefix.repeat = nothing; r.ip = 0x0000; r.ax = 0x0000; diff --git a/higan/processor/v30mz/v30mz.hpp b/higan/processor/v30mz/v30mz.hpp index 9d931555..fe73332f 100644 --- a/higan/processor/v30mz/v30mz.hpp +++ b/higan/processor/v30mz/v30mz.hpp @@ -6,8 +6,7 @@ namespace Processor { struct V30MZ { using Size = const uint&; - static const uint Byte; //= 1 - static const uint Word; //= 2 + enum : uint { Byte = 1, Word = 2, Long = 4 }; virtual auto wait(uint clocks = 1) -> void = 0; virtual auto read(uint20 addr) -> uint8 = 0; @@ -20,8 +19,10 @@ struct V30MZ { auto power() -> void; //registers.cpp - auto getAcc(Size) -> uint16; - auto setAcc(Size, uint16) -> void; + auto segment(uint16) -> uint16; + + auto getAcc(Size) -> uint32; + auto setAcc(Size, uint32) -> void; //modrm.cpp auto getReg(Size, uint8) -> uint16; @@ -31,13 +32,16 @@ struct V30MZ { auto setSeg(uint8, uint16) -> void; auto getMemAddress(uint8) -> uint32; - auto getMem(Size, uint8) -> uint16; + auto getMem(Size, uint8) -> uint32; auto setMem(Size, uint8, uint16) -> void; //memory.cpp - auto read(Size, uint16, uint16) -> uint16; + auto read(Size, uint16, uint16) -> uint32; auto write(Size, uint16, uint16, uint16) -> void; + auto in(Size, uint16) -> uint16; + auto out(Size, uint16, uint16) -> void; + auto fetch(Size = Byte) -> uint16; auto pop() -> uint16; auto push(uint16) -> void; @@ -47,6 +51,14 @@ struct V30MZ { auto alAdc(Size, uint16, uint16) -> uint16; auto alAdd(Size, uint16, uint16) -> uint16; auto alAnd(Size, uint16, uint16) -> uint16; + auto alDec(Size, uint16 ) -> uint16; + auto alDiv(Size, uint32, uint32) -> uint32; + auto alDivi(Size, int32, int32) -> uint32; + auto alInc(Size, uint16 ) -> uint16; + auto alMul(Size, uint16, uint16) -> uint32; + auto alMuli(Size, int16, int16) -> uint32; + auto alNeg(Size, uint16 ) -> uint16; + auto alNot(Size, uint16 ) -> uint16; auto alOr (Size, uint16, uint16) -> uint16; auto alRcl(Size, uint16, uint5 ) -> uint16; auto alRcr(Size, uint16, uint5 ) -> uint16; @@ -76,7 +88,7 @@ struct V30MZ { auto opAndMemReg(Size); auto opAndRegMem(Size); auto opAndAccImm(Size); - auto opPrefix(uint); + auto opPrefix(uint16&); auto opDecimalAdjust(bool); auto opAsciiAdjust(bool); auto opSubMemReg(Size); @@ -92,16 +104,32 @@ struct V30MZ { auto opDecReg(uint16&); auto opPushReg(uint16&); auto opPopReg(uint16&); + auto opPushAll(); + auto opPopAll(); + auto opBound(); + auto opPushImm(Size); + auto opMultiplySignedRegMemImm(Size); + auto opStoreFlagsAcc(); + auto opLoadAccFlags(); auto opJumpIf(bool); auto opGroup1MemImm(Size, bool); + auto opTestMemReg(Size); + auto opExchangeMemReg(Size); auto opMoveMemReg(Size); auto opMoveRegMem(Size); + auto opMoveMemSeg(); + auto opLoadEffectiveAddressRegMem(); auto opMoveSegMem(); + auto opPopMem(); auto opNop(); auto opExchange(uint16&, uint16&); + auto opSignExtendByte(); + auto opSignExtendWord(); auto opCallFar(); auto opMoveAccMem(Size); auto opMoveMemAcc(Size); + auto opInString(Size); + auto opOutString(Size); auto opMoveString(Size); auto opCompareString(Size); auto opTestAcc(Size); @@ -115,6 +143,9 @@ struct V30MZ { auto opMoveMemImm(Size); auto opReturnFarImm(); auto opReturnFar(); + auto opReturnInt(); + auto opInto(); + auto opLeave(); auto opGroup2MemImm(Size, maybe = {}); auto opGroup3MemImm(Size); auto opGroup4MemImm(Size); @@ -129,6 +160,8 @@ struct V30MZ { auto opOutDX(Size); auto opLock(); auto opRepeat(bool); + auto opHalt(); + auto opComplementCarry(); auto opClearFlag(bool&); auto opSetFlag(bool&); @@ -141,8 +174,8 @@ struct V30MZ { struct Prefix { bool hold; - bool es, cs, ss, ds; - bool repnz, repz; + maybe segment; + maybe repeat; } prefix; struct Registers {