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:
Tim Allen 2016-02-03 21:24:58 +11:00
parent 71bda4144a
commit d158c8f293
9 changed files with 452 additions and 87 deletions

View File

@ -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/";

View File

@ -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;

View File

@ -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), "]"};

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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& {

View File

@ -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;

View File

@ -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 {