mirror of https://github.com/bsnes-emu/bsnes.git
Update to v097r09 release.
244 of 256 opcodes implemented now, although the interrupt triggering portions are missing from them still. Much better handling of prefixes now. I definitely have a newfound hatepreciation for x86 now >_>
This commit is contained in:
parent
71bda4144a
commit
d158c8f293
|
@ -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/";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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), "]"};
|
||||
|
|
|
@ -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<uint8> imm) {
|
||||
auto modRM = fetch();
|
||||
if(!imm) {
|
||||
|
@ -396,11 +545,31 @@ auto V30MZ::opGroup2MemImm(Size size, maybe<uint8> 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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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& {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<uint8> = {});
|
||||
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<uint16> segment;
|
||||
maybe<bool> repeat;
|
||||
} prefix;
|
||||
|
||||
struct Registers {
|
||||
|
|
Loading…
Reference in New Issue