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>
<string>higan.icns</string>
<key>NSHighResolutionCapable</key>
<true/>
<false/>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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