Update to v097r06 release.

byuu says:

Man, the 80186 is taking a lot longer to implement than I thought it
would. So far I'm 18 hours into this emulator. Whereas I had Super Mario
Bros fully playable (no sound) in 12 hours for the NES >_>

I refactored all the byte/word variant functions to single functions
that take a size parameter. Cuts the amount of code in half.

Also implemented repz/repnz + movsb/movsw, so Riviera now gets 299
instructions in before dying. Nobody really bothers to explain how the
CPU actually implements these instructions, but I think I have it right:
ignore non-string opcodes that follow rep, invoke the string operations
inside the rep opcodes to prevent interrupts from triggering between the
two (which will be even more fun for segment selector overrides ...)

The next opcode needed is 0xC7, which ... throws ModRM on its head. In
this mode, ModRM is only used to determine the target operand (and it
doesn't use the middle bits for that at all), and the source is an
immediate that follows it. Gonna have to waste a few more hours thinking
about how best to handle that.

Also, disabled HiDPI for higan as well on OS X.
This commit is contained in:
Tim Allen 2016-01-31 18:59:44 +11:00
parent 605a8aa3e9
commit d0ddd87e9c
9 changed files with 268 additions and 263 deletions

View File

@ -11,7 +11,7 @@
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>higan.icns</string> <string>higan.icns</string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
<true/> <false/>
<key>NSSupportsAutomaticGraphicsSwitching</key> <key>NSSupportsAutomaticGraphicsSwitching</key>
<true/> <true/>
</dict> </dict>

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "097.05"; static const string Version = "097.06";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -7,24 +7,15 @@ auto V30MZ::parity(uint16 value) const -> bool {
return !(value & 1); return !(value & 1);
} }
auto V30MZ::albAnd(uint8 x, uint8 y) -> uint8 { auto V30MZ::alAnd(Size size, uint16 x, uint16 y) -> uint16 {
uint8 result = x & y; uint16 bits = size == Byte ? 0xff : 0xffff;
uint16 mask = size == Byte ? 0x80 : 0x8000;
uint16 result = (x & y) & bits;
r.f.c = 0; r.f.c = 0;
r.f.p = parity(result); r.f.p = parity(result);
r.f.h = 0; r.f.h = 0;
r.f.z = result == 0; r.f.z = result == 0;
r.f.s = result & 0x80; r.f.s = result & mask;
r.f.v = 0;
return result;
}
auto V30MZ::alwAnd(uint16 x, uint16 y) -> uint16 {
uint16 result = x & y;
r.f.c = 0;
r.f.p = parity(result);
r.f.h = 0;
r.f.z = result == 0;
r.f.s = result & 0x8000;
r.f.v = 0; r.f.v = 0;
return result; return result;
} }

View File

@ -36,66 +36,90 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers) -> string {
if((modRM & 0xc0) == 0x80) return {d, ",[", mem[modRM & 7], "+", readWord(offset), "]"}; if((modRM & 0xc0) == 0x80) return {d, ",[", mem[modRM & 7], "+", readWord(offset), "]"};
return {d, ",[", mem[modRM & 7], "]"}; return {d, ",[", mem[modRM & 7], "]"};
}; };
auto readRepeat = [&](uint offset) -> string {
uint8 opcode = read((cs << 4) + (uint16)(ip + offset++));
switch(opcode) {
case 0x6c: return "insb";
case 0x6d: return "insw";
case 0x6e: return "outsb";
case 0x6f: return "outsw";
case 0xa4: return "movsb";
case 0xa5: return "movsw";
case 0xa6: return "cmpsb";
case 0xa7: return "cmpsw";
case 0xaa: return "stosb";
case 0xab: return "stosw";
case 0xac: return "lodsb";
case 0xad: return "lodsw";
case 0xae: return "scasb";
case 0xaf: return "scasw";
}
return "";
};
uint8 opcode = read(ea); auto opcode = read(ea);
switch(opcode) { switch(opcode) {
case 0x22: s = {"xor ", readModRM(1, Byte)}; break; case 0x22: s = {"xor ", readModRM(1, Byte)}; break;
case 0x33: s = {"xor ", readModRM(1, Word)}; break; case 0x33: s = {"xor ", readModRM(1, Word)}; break;
case 0x70: s = {"jo ", readRelativeByte(1, 2)}; break; case 0x70: s = {"jo ", readRelativeByte(1, 2)}; break;
case 0x71: s = {"jno ", readRelativeByte(1, 2)}; break; case 0x71: s = {"jno ", readRelativeByte(1, 2)}; break;
case 0x72: s = {"jc ", readRelativeByte(1, 2)}; break; case 0x72: s = {"jc ", readRelativeByte(1, 2)}; break;
case 0x73: s = {"jnc ", readRelativeByte(1, 2)}; break; case 0x73: s = {"jnc ", readRelativeByte(1, 2)}; break;
case 0x74: s = {"jz ", readRelativeByte(1, 2)}; break; case 0x74: s = {"jz ", readRelativeByte(1, 2)}; break;
case 0x75: s = {"jnz ", readRelativeByte(1, 2)}; break; case 0x75: s = {"jnz ", readRelativeByte(1, 2)}; break;
case 0x76: s = {"jcz ", readRelativeByte(1, 2)}; break; case 0x76: s = {"jcz ", readRelativeByte(1, 2)}; break;
case 0x77: s = {"jncz ", readRelativeByte(1, 2)}; break; case 0x77: s = {"jncz ", readRelativeByte(1, 2)}; break;
case 0x78: s = {"js ", readRelativeByte(1, 2)}; break; case 0x78: s = {"js ", readRelativeByte(1, 2)}; break;
case 0x79: s = {"jns ", readRelativeByte(1, 2)}; break; case 0x79: s = {"jns ", readRelativeByte(1, 2)}; break;
case 0x7a: s = {"jp ", readRelativeByte(1, 2)}; break; case 0x7a: s = {"jp ", readRelativeByte(1, 2)}; break;
case 0x7b: s = {"jnp ", readRelativeByte(1, 2)}; break; case 0x7b: s = {"jnp ", readRelativeByte(1, 2)}; break;
case 0x7c: s = {"jl ", readRelativeByte(1, 2)}; break; case 0x7c: s = {"jl ", readRelativeByte(1, 2)}; break;
case 0x7d: s = {"jnl ", readRelativeByte(1, 2)}; break; case 0x7d: s = {"jnl ", readRelativeByte(1, 2)}; break;
case 0x7e: s = {"jle ", readRelativeByte(1, 2)}; break; case 0x7e: s = {"jle ", readRelativeByte(1, 2)}; break;
case 0x7f: s = {"jnle ", readRelativeByte(1, 2)}; break; case 0x7f: s = {"jnle ", readRelativeByte(1, 2)}; break;
case 0x8a: s = {"mov ", readModRM(1, Byte)}; break; case 0x8a: s = {"mov ", readModRM(1, Byte)}; break;
case 0x8b: s = {"mov ", readModRM(1, Word)}; break; case 0x8b: s = {"mov ", readModRM(1, Word)}; break;
case 0x8e: s = {"mov ", readModRM(1, Segment)}; break; case 0x8e: s = {"mov ", readModRM(1, Segment)}; break;
case 0x90: s = {"nop "}; break; case 0x90: s = {"nop "}; break;
case 0xa8: s = {"test al,", readByte(1)}; break; case 0xa4: s = {"movsb "}; break;
case 0xa9: s = {"test ax,", readWord(1)}; break; case 0xa5: s = {"movsw "}; break;
case 0xb0: s = {"mov al,", readByte(1)}; break; case 0xa8: s = {"test al,", readByte(1)}; break;
case 0xb1: s = {"mov cl,", readByte(1)}; break; case 0xa9: s = {"test ax,", readWord(1)}; break;
case 0xb2: s = {"mov dl,", readByte(1)}; break; case 0xb0: s = {"mov al,", readByte(1)}; break;
case 0xb3: s = {"mov bl,", readByte(1)}; break; case 0xb1: s = {"mov cl,", readByte(1)}; break;
case 0xb4: s = {"mov ah,", readByte(1)}; break; case 0xb2: s = {"mov dl,", readByte(1)}; break;
case 0xb5: s = {"mov ch,", readByte(1)}; break; case 0xb3: s = {"mov bl,", readByte(1)}; break;
case 0xb6: s = {"mov dh,", readByte(1)}; break; case 0xb4: s = {"mov ah,", readByte(1)}; break;
case 0xb7: s = {"mov bh,", readByte(1)}; break; case 0xb5: s = {"mov ch,", readByte(1)}; break;
case 0xb8: s = {"mov ax,", readWord(1)}; break; case 0xb6: s = {"mov dh,", readByte(1)}; break;
case 0xb9: s = {"mov cx,", readWord(1)}; break; case 0xb7: s = {"mov bh,", readByte(1)}; break;
case 0xba: s = {"mov dx,", readWord(1)}; break; case 0xb8: s = {"mov ax,", readWord(1)}; break;
case 0xbb: s = {"mov bx,", readWord(1)}; break; case 0xb9: s = {"mov cx,", readWord(1)}; break;
case 0xbc: s = {"mov sp,", readWord(1)}; break; case 0xba: s = {"mov dx,", readWord(1)}; break;
case 0xbd: s = {"mov bp,", readWord(1)}; break; case 0xbb: s = {"mov bx,", readWord(1)}; break;
case 0xbe: s = {"mov si,", readWord(1)}; break; case 0xbc: s = {"mov sp,", readWord(1)}; break;
case 0xbf: s = {"mov di,", readWord(1)}; break; case 0xbd: s = {"mov bp,", readWord(1)}; break;
case 0xc3: s = {"ret "}; break; case 0xbe: s = {"mov si,", readWord(1)}; break;
case 0xe4: s = {"in al,", readByte(1)}; break; case 0xbf: s = {"mov di,", readWord(1)}; break;
case 0xe5: s = {"in ax,", readByte(1)}; break; case 0xc3: s = {"ret "}; break;
case 0xe6: s = {"out ", readByte(1), ",al"}; break; case 0xe4: s = {"in al,", readByte(1)}; break;
case 0xe7: s = {"out ", readByte(1), ",ax"}; break; case 0xe5: s = {"in ax,", readByte(1)}; break;
case 0xe8: s = {"call ", readRelativeWord(1, 3)}; break; case 0xe6: s = {"out ", readByte(1), ",al"}; break;
case 0xea: s = {"jmp ", readWord(3), ":", readWord(1)}; break; case 0xe7: s = {"out ", readByte(1), ",ax"}; break;
case 0xec: s = {"in al,dx"}; break; case 0xe8: s = {"call ", readRelativeWord(1, 3)}; break;
case 0xed: s = {"in ax,dx"}; break; case 0xea: s = {"jmp ", readWord(3), ":", readWord(1)}; break;
case 0xee: s = {"out dx,al"}; break; case 0xec: s = {"in al,dx"}; break;
case 0xef: s = {"out dx,ax"}; break; case 0xed: s = {"in ax,dx"}; break;
case 0xf8: s = {"clc "}; break; case 0xee: s = {"out dx,al"}; break;
case 0xf9: s = {"stc "}; break; case 0xef: s = {"out dx,ax"}; break;
case 0xfa: s = {"cli "}; break; case 0xf2: s = {"repnz ", readRepeat(1)}; break;
case 0xfb: s = {"sti "}; break; case 0xf3: s = {"repz ", readRepeat(1)}; break;
case 0xfc: s = {"cld "}; break; case 0xf8: s = {"clc "}; break;
case 0xfd: s = {"std "}; break; case 0xf9: s = {"stc "}; break;
case 0xfa: s = {"cli "}; break;
case 0xfb: s = {"sti "}; break;
case 0xfc: s = {"cld "}; break;
case 0xfd: s = {"std "}; break;
default: default:
s = {"??? [", hex(opcode, 2L), "]"}; s = {"??? [", hex(opcode, 2L), "]"};

View File

@ -1,51 +1,44 @@
auto V30MZ::opbXorRegisterModRM() { auto V30MZ::opXorRegisterModRM(Size size) {
auto md = readbIP(); auto modRM = readIP();
regb(md) ^= readbModRM(md); setRegister(size, modRM, getRegister(size, modRM) ^ readModRM(size, modRM));
}
auto V30MZ::opwXorRegisterModRM() {
auto md = readbIP();
regw(md) ^= readwModRM(md);
} }
auto V30MZ::opJumpIf(bool condition) { auto V30MZ::opJumpIf(bool condition) {
auto displacement = (int8)readbIP(); auto displacement = (int8)readIP();
if(condition) r.ip += displacement; if(condition) r.ip += displacement;
} }
auto V30MZ::opbMoveRegisterModRM() { auto V30MZ::opMoveRegisterModRM(Size size) {
auto md = readbIP(); auto modRM = readIP();
regb(md) = readbModRM(md); setRegister(size, modRM, readModRM(size, modRM));
}
auto V30MZ::opwMoveRegisterModRM() {
auto md = readbIP();
regw(md) = readwModRM(md);
} }
auto V30MZ::opMoveSegmentRegisterModRM() { auto V30MZ::opMoveSegmentRegisterModRM() {
wait(1); wait(1);
auto md = readbIP(); auto modRM = readIP();
sreg(md) = readwModRM(md); setSegment(modRM, readModRM(Word, modRM));
} }
auto V30MZ::opNoOperation() { auto V30MZ::opNoOperation() {
} }
auto V30MZ::opTestAL() { auto V30MZ::opMoveString(Size size) {
albAnd(r.al, readbIP()); wait(4);
write(size, r.es, r.di, read(size, r.ds, r.si));
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
} }
auto V30MZ::opTestAX() { auto V30MZ::opTestAX(Size size) {
alwAnd(r.ax, readwIP()); alAnd(size, r.ax, readIP(size));
} }
auto V30MZ::opbMoveRegisterImmediate(uint8& rd) { auto V30MZ::opMoveRegisterImmediate(uint8& rd) {
rd = readbIP(); rd = readIP(Byte);
} }
auto V30MZ::opwMoveRegisterImmediate(uint16& rd) { auto V30MZ::opMoveRegisterImmediate(uint16& rd) {
rd = readwIP(); rd = readIP(Word);
} }
auto V30MZ::opReturn() { auto V30MZ::opReturn() {
@ -53,69 +46,69 @@ auto V30MZ::opReturn() {
r.ip = readSP(); r.ip = readSP();
} }
auto V30MZ::opbIn() { auto V30MZ::opIn(Size size) {
wait(5); wait(5);
auto port = readbIP(); auto port = readIP();
r.al = in(port); r.al = in(port++);
if(size != Word) return;
r.ah = in(port++);
} }
auto V30MZ::opwIn() { auto V30MZ::opOut(Size size) {
wait(5); wait(5);
auto port = readbIP(); auto port = readIP();
r.al = in(port + 0); out(port++, r.al);
r.ah = in(port + 1); if(size != Word) return;
} out(port++, r.ah);
auto V30MZ::opbOut() {
wait(5);
auto port = readbIP();
out(port, r.al);
}
auto V30MZ::opwOut() {
wait(5);
auto port = readbIP();
out(port + 0, r.al);
out(port + 1, r.ah);
} }
auto V30MZ::opCallNear() { auto V30MZ::opCallNear() {
wait(4); wait(4);
auto displacement = (int16)readwIP(); auto displacement = (int16)readIP(Word);
writeSP(r.ip); writeSP(r.ip);
r.ip += displacement; r.ip += displacement;
} }
auto V30MZ::opJumpFar() { auto V30MZ::opJumpFar() {
wait(6); wait(6);
auto ip = readwIP(); auto ip = readIP(Word);
auto cs = readwIP(); auto cs = readIP(Word);
r.ip = ip; r.ip = ip;
r.cs = cs; r.cs = cs;
} }
auto V30MZ::opbInDX() { auto V30MZ::opInDX(Size size) {
wait(5);
r.al = in(r.dx);
}
auto V30MZ::opwInDX() {
wait(5); wait(5);
r.al = in(r.dx + 0); r.al = in(r.dx + 0);
if(size != Word) return;
r.ah = in(r.dx + 1); r.ah = in(r.dx + 1);
} }
auto V30MZ::opbOutDX() { auto V30MZ::opOutDX(Size size) {
wait(5);
out(r.dx, r.al);
}
auto V30MZ::opwOutDX() {
wait(5); wait(5);
out(r.dx + 0, r.al); out(r.dx + 0, r.al);
if(size != Word) return;
out(r.dx + 1, r.ah); out(r.dx + 1, r.ah);
} }
auto V30MZ::opRepeat(bool flag) {
wait(4);
auto opcode = readIP();
if((opcode & 0xfc) != 0x6c && (opcode & 0xfc) != 0xa4
&& (opcode & 0xfe) != 0xaa && (opcode & 0xfc) != 0xac) {
//invalid argument
r.ip--;
return;
}
if(r.cx == 0) return;
r.cx--;
switch(opcode) {
case 0xa4: opMoveString(Byte); r.ip -= 2; break;
case 0xa5: opMoveString(Word); r.ip -= 2; break;
}
}
auto V30MZ::opClearFlag(bool& flag) { auto V30MZ::opClearFlag(bool& flag) {
wait(3); wait(3);
flag = false; flag = false;

View File

@ -1,75 +1,58 @@
auto V30MZ::readbIP() -> uint8 { auto V30MZ::read(Size size, uint16 segment, uint16 address) -> uint16 {
return read((r.cs << 4) + r.ip++); uint16 data = read(segment * 16 + address);
if(size == Word) data |= read(segment * 16 + ++address) << 8;
return data;
} }
auto V30MZ::readwIP() -> uint16 { auto V30MZ::write(Size size, uint16 segment, uint16 address, uint16 data) -> void {
uint16 word = read((r.cs << 4) + r.ip++) << 0; write(segment * 16 + address, data);
return word | read((r.cs << 4) + r.ip++) << 8; if(size == Word) write(segment * 16 + ++address, data >> 8);
}
//
auto V30MZ::readIP(Size size) -> uint16 {
uint16 data = read(size, r.cs, r.ip);
return r.ip += size, data;
} }
// //
auto V30MZ::readSP() -> uint16 { auto V30MZ::readSP() -> uint16 {
uint16 word = read((r.ss << 4) + r.sp++) << 0; uint16 data = read(Word, r.ss, r.sp);
return word | read((r.ss << 4) + r.sp++) << 8; return r.sp += Word, data;
} }
auto V30MZ::writeSP(uint16 data) -> void { auto V30MZ::writeSP(uint16 data) -> void {
write((r.ss << 4) + --r.sp, data >> 8); r.sp -= Word;
write((r.ss << 4) + --r.sp, data >> 0); write(Word, r.ss, r.sp, data);
} }
// //
auto V30MZ::readb(uint20 ea) -> uint8 { auto V30MZ::readModRM(uint8 modRM) -> uint32 {
return read(ea++); if((modRM & 0xc7) == 0x06) return r.ds << 16 | readIP(Word);
}
auto V30MZ::readw(uint20 ea) -> uint16 { uint16 s = 0, a = 0;
uint16 word = read(ea++) << 0; if((modRM & 0xc0) == 0x40) a = (int8)readIP(Byte);
return word | read(ea++) << 8; if((modRM & 0xc0) == 0x80) a = (int16)readIP(Word);
}
//
auto V30MZ::readb(uint16 rs, uint16 ea) -> uint8 {
return read((rs << 4) + ea++);
}
auto V30MZ::readw(uint16 rs, uint16 ea) -> uint16 {
uint16 word = read((rs << 4) + ea++) << 0;
return word | read((rs << 4) + ea++) << 8;
}
//
//todo: return tuple<uint16 seg, uint16 ea>
auto V30MZ::readModRM(uint8 modRM) -> uint20 {
if((modRM & 0xc7) == 0x06) return (r.ds << 4) + (int16)readwIP();
int16 displacement = 0;
if((modRM & 0xc0) == 0x40) displacement = (int8)readbIP();
if((modRM & 0xc0) == 0x80) displacement = (int16)readwIP();
switch(modRM & 7) { switch(modRM & 7) {
case 0: return (r.ds << 4) + r.bx + r.si + displacement; case 0: s = r.ds; a += r.bx + r.si; break;
case 1: return (r.ds << 4) + r.bx + r.di + displacement; case 1: s = r.ds; a += r.bx + r.di; break;
case 2: return (r.ss << 4) + r.bp + r.si + displacement; case 2: s = r.ss; a += r.bp + r.si; break;
case 3: return (r.ss << 4) + r.bp + r.di + displacement; case 3: s = r.ss; a += r.bp + r.di; break;
case 4: return (r.ds << 4) + r.si + displacement; case 4: s = r.ds; a += r.si; break;
case 5: return (r.ds << 4) + r.di + displacement; case 5: s = r.ds; a += r.di; break;
case 6: return (r.ss << 4) + r.bp + displacement; case 6: s = r.ss; a += r.bp; break;
case 7: return (r.ds << 4) + r.bx + displacement; case 7: s = r.ds; a += r.bx; break;
} }
unreachable;
return s << 16 | a;
} }
auto V30MZ::readbModRM(uint8 modRM) -> uint8 { auto V30MZ::readModRM(Size size, uint8 modRM) -> uint16 {
if(modRM >= 0xc0) return regb(modRM); if(modRM >= 0xc0) return getRegister(size, modRM);
return readb(readModRM(modRM)); auto addr = readModRM(modRM);
} return read(size, addr >> 16, addr);
auto V30MZ::readwModRM(uint8 modRM) -> uint16 {
if(modRM >= 0xc0) return regw(modRM);
return readw(readModRM(modRM));
} }

View File

@ -1,18 +1,32 @@
auto V30MZ::regb(uint8 modRM) -> uint8& { auto V30MZ::getRegister(Size size, uint8 modRM) -> uint16 {
static uint8* p[] = {&r.al, &r.cl, &r.dl, &r.bl, &r.ah, &r.ch, &r.dh, &r.bh}; static uint8* byte[] = {&r.al, &r.cl, &r.dl, &r.bl, &r.ah, &r.ch, &r.dh, &r.bh};
return *p[(modRM >> 3) & 7]; static uint16* word[] = {&r.ax, &r.cx, &r.dx, &r.bx, &r.sp, &r.bp, &r.si, &r.di};
if(size == Byte) return *byte[(modRM >> 3) & 7];
if(size == Word) return *word[(modRM >> 3) & 7];
throw;
} }
auto V30MZ::regw(uint8 modRM) -> uint16& { auto V30MZ::setRegister(Size size, uint8 modRM, uint16 data) -> void {
static uint16* p[] = {&r.ax, &r.cx, &r.dx, &r.bx, &r.sp, &r.bp, &r.si, &r.di}; static uint8* byte[] = {&r.al, &r.cl, &r.dl, &r.bl, &r.ah, &r.ch, &r.dh, &r.bh};
return *p[(modRM >> 3) & 7]; static uint16* word[] = {&r.ax, &r.cx, &r.dx, &r.bx, &r.sp, &r.bp, &r.si, &r.di};
if(size == Byte) *byte[(modRM >> 3) & 7] = data;
if(size == Word) *word[(modRM >> 3) & 7] = data;
} }
auto V30MZ::sreg(uint8 modRM) -> uint16& { //
static uint16* p[] = {&r.es, &r.cs, &r.ss, &r.ds};
return *p[(modRM >> 3) & 3]; auto V30MZ::getSegment(uint8 modRM) -> uint16 {
static uint16* word[] = {&r.es, &r.cs, &r.ss, &r.ds};
return *word[(modRM >> 3) & 3];
} }
auto V30MZ::setSegment(uint8 modRM, uint16 data) -> void {
static uint16* word[] = {&r.es, &r.cs, &r.ss, &r.ds};
*word[(modRM >> 3) & 3] = data;
}
//
V30MZ::Registers::Flags::operator uint16() const { V30MZ::Registers::Flags::operator uint16() const {
return m << 15 | 1 << 14 | 1 << 13 | 1 << 12 return m << 15 | 1 << 14 | 1 << 13 | 1 << 12
| v << 11 | d << 10 | i << 9 | b << 8 | v << 11 | d << 10 | i << 9 | b << 8

View File

@ -3,6 +3,8 @@
namespace Processor { namespace Processor {
const uint V30MZ::Byte = 1;
const uint V30MZ::Word = 2;
#include "registers.cpp" #include "registers.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "algorithms.cpp" #include "algorithms.cpp"
@ -22,12 +24,12 @@ auto V30MZ::exec() -> void {
auto V30MZ::execOpcode() -> void { auto V30MZ::execOpcode() -> void {
executed++; executed++;
uint8 opcode = readbIP(); auto opcode = readIP();
wait(1); wait(1);
switch(opcode) { switch(opcode) {
case 0x32: return opbXorRegisterModRM(); case 0x32: return opXorRegisterModRM(Byte);
case 0x33: return opwXorRegisterModRM(); case 0x33: return opXorRegisterModRM(Word);
case 0x70: return opJumpIf(r.f.v == 1); case 0x70: return opJumpIf(r.f.v == 1);
case 0x71: return opJumpIf(r.f.v == 0); case 0x71: return opJumpIf(r.f.v == 0);
case 0x72: return opJumpIf(r.f.c == 1); case 0x72: return opJumpIf(r.f.c == 1);
@ -44,39 +46,43 @@ auto V30MZ::execOpcode() -> void {
case 0x7d: return opJumpIf(r.f.s == r.f.v || r.f.z == 1); case 0x7d: return opJumpIf(r.f.s == r.f.v || r.f.z == 1);
case 0x7e: return opJumpIf(r.f.s != r.f.v || r.f.z == 1); case 0x7e: return opJumpIf(r.f.s != r.f.v || r.f.z == 1);
case 0x7f: return opJumpIf(r.f.s == r.f.v && r.f.z == 0); case 0x7f: return opJumpIf(r.f.s == r.f.v && r.f.z == 0);
case 0x8a: return opbMoveRegisterModRM(); case 0x8a: return opMoveRegisterModRM(Byte);
case 0x8b: return opwMoveRegisterModRM(); case 0x8b: return opMoveRegisterModRM(Word);
case 0x8e: return opMoveSegmentRegisterModRM(); case 0x8e: return opMoveSegmentRegisterModRM();
case 0x90: return opNoOperation(); case 0x90: return opNoOperation();
case 0xa8: return opTestAL(); case 0xa4: return opMoveString(Byte);
case 0xa9: return opTestAX(); case 0xa5: return opMoveString(Word);
case 0xb0: return opbMoveRegisterImmediate(r.al); case 0xa8: return opTestAX(Byte);
case 0xb1: return opbMoveRegisterImmediate(r.cl); case 0xa9: return opTestAX(Word);
case 0xb2: return opbMoveRegisterImmediate(r.dl); case 0xb0: return opMoveRegisterImmediate(r.al);
case 0xb3: return opbMoveRegisterImmediate(r.bl); case 0xb1: return opMoveRegisterImmediate(r.cl);
case 0xb4: return opbMoveRegisterImmediate(r.ah); case 0xb2: return opMoveRegisterImmediate(r.dl);
case 0xb5: return opbMoveRegisterImmediate(r.ch); case 0xb3: return opMoveRegisterImmediate(r.bl);
case 0xb6: return opbMoveRegisterImmediate(r.dh); case 0xb4: return opMoveRegisterImmediate(r.ah);
case 0xb7: return opbMoveRegisterImmediate(r.bh); case 0xb5: return opMoveRegisterImmediate(r.ch);
case 0xb8: return opwMoveRegisterImmediate(r.ax); case 0xb6: return opMoveRegisterImmediate(r.dh);
case 0xb9: return opwMoveRegisterImmediate(r.cx); case 0xb7: return opMoveRegisterImmediate(r.bh);
case 0xba: return opwMoveRegisterImmediate(r.dx); case 0xb8: return opMoveRegisterImmediate(r.ax);
case 0xbb: return opwMoveRegisterImmediate(r.bx); case 0xb9: return opMoveRegisterImmediate(r.cx);
case 0xbc: return opwMoveRegisterImmediate(r.sp); case 0xba: return opMoveRegisterImmediate(r.dx);
case 0xbd: return opwMoveRegisterImmediate(r.bp); case 0xbb: return opMoveRegisterImmediate(r.bx);
case 0xbe: return opwMoveRegisterImmediate(r.si); case 0xbc: return opMoveRegisterImmediate(r.sp);
case 0xbf: return opwMoveRegisterImmediate(r.di); case 0xbd: return opMoveRegisterImmediate(r.bp);
case 0xbe: return opMoveRegisterImmediate(r.si);
case 0xbf: return opMoveRegisterImmediate(r.di);
case 0xc3: return opReturn(); case 0xc3: return opReturn();
case 0xe4: return opbIn(); case 0xe4: return opIn(Byte);
case 0xe5: return opwIn(); case 0xe5: return opIn(Word);
case 0xe6: return opbOut(); case 0xe6: return opOut(Byte);
case 0xe7: return opwOut(); case 0xe7: return opOut(Word);
case 0xe8: return opCallNear(); case 0xe8: return opCallNear();
case 0xea: return opJumpFar(); case 0xea: return opJumpFar();
case 0xec: return opbInDX(); case 0xec: return opInDX(Byte);
case 0xed: return opwInDX(); case 0xed: return opInDX(Word);
case 0xee: return opbOutDX(); case 0xee: return opOutDX(Byte);
case 0xef: return opwOutDX(); case 0xef: return opOutDX(Word);
case 0xf2: return opRepeat(1);
case 0xf3: return opRepeat(0);
case 0xf8: return opClearFlag(r.f.c); case 0xf8: return opClearFlag(r.f.c);
case 0xf9: return opSetFlag(r.f.c); case 0xf9: return opSetFlag(r.f.c);
case 0xfa: return opClearFlag(r.f.i); case 0xfa: return opClearFlag(r.f.i);

View File

@ -5,6 +5,10 @@
namespace Processor { namespace Processor {
struct V30MZ { struct V30MZ {
using Size = const uint&;
static const uint Byte;
static const uint Word;
virtual auto wait(uint clocks = 1) -> void = 0; virtual auto wait(uint clocks = 1) -> void = 0;
virtual auto read(uint20 addr) -> uint8 = 0; virtual auto read(uint20 addr) -> uint8 = 0;
virtual auto write(uint20 addr, uint8 data) -> void = 0; virtual auto write(uint20 addr, uint8 data) -> void = 0;
@ -16,56 +20,46 @@ struct V30MZ {
auto power() -> void; auto power() -> void;
//registers.cpp //registers.cpp
auto regb(uint8) -> uint8&; auto getRegister(Size, uint8) -> uint16;
auto regw(uint8) -> uint16&; auto setRegister(Size, uint8, uint16) -> void;
auto sreg(uint8) -> uint16&;
auto getSegment(uint8) -> uint16;
auto setSegment(uint8, uint16) -> void;
//memory.cpp //memory.cpp
auto readbIP() -> uint8; auto read(Size, uint16, uint16) -> uint16;
auto readwIP() -> uint16; auto write(Size, uint16, uint16, uint16) -> void;
auto readIP(Size = Byte) -> uint16;
auto readSP() -> uint16; auto readSP() -> uint16;
auto writeSP(uint16) -> void; auto writeSP(uint16) -> void;
auto readb(uint20 ea) -> uint8; auto readModRM(uint8) -> uint32;
auto readw(uint20 ea) -> uint16; auto readModRM(Size, uint8) -> uint16;
auto readb(uint16 rs, uint16 ea) -> uint8;
auto readw(uint16 rs, uint16 ea) -> uint16;
auto readModRM(uint8) -> uint20;
auto readbModRM(uint8) -> uint8;
auto readwModRM(uint8) -> uint16;
//algorithms.cpp //algorithms.cpp
auto parity(uint16) const -> bool; auto parity(uint16) const -> bool;
auto alAnd(Size, uint16, uint16) -> uint16;
auto albAnd(uint8, uint8) -> uint8;
auto alwAnd(uint16, uint16) -> uint16;
//instructions.cpp //instructions.cpp
auto opbXorRegisterModRM(); auto opXorRegisterModRM(Size);
auto opwXorRegisterModRM();
auto opJumpIf(bool); auto opJumpIf(bool);
auto opbMoveRegisterModRM(); auto opMoveRegisterModRM(Size);
auto opwMoveRegisterModRM();
auto opMoveSegmentRegisterModRM(); auto opMoveSegmentRegisterModRM();
auto opNoOperation(); auto opNoOperation();
auto opTestAL(); auto opMoveString(Size);
auto opTestAX(); auto opTestAX(Size);
auto opbMoveRegisterImmediate(uint8&); auto opMoveRegisterImmediate(uint8&);
auto opwMoveRegisterImmediate(uint16&); auto opMoveRegisterImmediate(uint16&);
auto opReturn(); auto opReturn();
auto opbIn(); auto opIn(Size);
auto opwIn(); auto opOut(Size);
auto opbOut();
auto opwOut();
auto opCallNear(); auto opCallNear();
auto opJumpFar(); auto opJumpFar();
auto opbInDX(); auto opInDX(Size);
auto opwInDX(); auto opOutDX(Size);
auto opbOutDX(); auto opRepeat(bool);
auto opwOutDX();
auto opClearFlag(bool&); auto opClearFlag(bool&);
auto opSetFlag(bool&); auto opSetFlag(bool&);