Update to v097r07 release.

byuu says:

26 hours in, 173 instructions implemented. Although the four segment
prefix opcodes don't actually do anything yet. There's less than 256
actual instructions on the 80186, not sure of the exact count.

Gunpey gets around ~8,200 instructions in before hitting an unsupported
opcode (loop). Riviera goes off the rails on a retf and ends up
executing an endless stream of bad opcodes in RAM =( Both games hammer
the living shit out of the in/out ports pretty much immediately.
This commit is contained in:
Tim Allen 2016-02-02 21:51:17 +11:00
parent d0ddd87e9c
commit ad51f1478e
24 changed files with 1023 additions and 301 deletions

View File

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

View File

@ -1,5 +1,4 @@
#ifndef PROCESSOR_ARM_HPP
#define PROCESSOR_ARM_HPP
#pragma once
namespace Processor {
@ -65,5 +64,3 @@ struct ARM {
};
}
#endif

View File

@ -1,5 +1,3 @@
#ifdef PROCESSOR_ARM_HPP
auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
static string conditions[] = {
"eq", "ne", "cs", "cc",
@ -777,5 +775,3 @@ auto ARM::disassemble_registers() -> string {
output.append("/", hex(spsr().m, 2L));
return output;
}
#endif

View File

@ -1,5 +1,3 @@
#ifdef PROCESSOR_ARM_HPP
auto ARM::arm_opcode(uint32 rm) {
uint4 opcode = instruction() >> 21;
uint1 save = instruction() >> 20;
@ -585,5 +583,3 @@ auto ARM::arm_op_software_interrupt() {
vector(0x00000008, Processor::Mode::SVC);
}
#endif

View File

@ -1,5 +1,3 @@
#ifdef PROCESSOR_ARM_HPP
auto ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
switch(opcode) {
case 0: r(d) = bit(r(d) & r(m)); break; //AND
@ -372,5 +370,3 @@ auto ARM::thumb_op_branch_long_suffix() {
r(15) = r(14) + (offsetlo * 2);
r(14) = pipeline.decode.address | 1;
}
#endif

View File

@ -1,5 +1,3 @@
#ifdef PROCESSOR_ARM_HPP
auto ARM::Processor::power() -> void {
r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = 0;
usr.r8 = usr.r9 = usr.r10 = usr.r11 = usr.r12 = usr.sp = usr.lr = 0;
@ -59,5 +57,3 @@ auto ARM::Processor::setMode(Mode mode) -> void {
default: r[13] = &usr.sp; r[14] = &usr.lr; spsr = nullptr; break;
}
}
#endif

View File

@ -1,5 +1,4 @@
#ifndef PROCESSOR_GSU_HPP
#define PROCESSOR_GSU_HPP
#pragma once
namespace Processor {
@ -117,5 +116,3 @@ struct GSU {
};
}
#endif

View File

@ -1,7 +1,6 @@
//Hitachi HG51B169 (HG51BS family/derivative?)
#ifndef PROCESSOR_HG51B_HPP
#define PROCESSOR_HG51B_HPP
#pragma once
namespace Processor {
@ -54,5 +53,3 @@ protected:
};
}
#endif

View File

@ -1,5 +1,3 @@
#ifdef PROCESSOR_HG51B_HPP
auto HG51B::push() -> void {
stack[7] = stack[6];
stack[6] = stack[5];
@ -352,5 +350,3 @@ auto HG51B::instruction() -> void {
regs.halt = true;
}
}
#endif

View File

@ -1,5 +1,3 @@
#ifdef PROCESSOR_HG51B_HPP
auto HG51B::reg_read(uint8 addr) const -> uint24 {
switch(addr) {
case 0x00: return regs.a;
@ -74,5 +72,3 @@ auto HG51B::reg_write(uint8 addr, uint24 data) -> void {
case 0x6f: regs.gpr[15] = data; return;
}
}
#endif

View File

@ -1,5 +1,3 @@
#ifdef PROCESSOR_HG51B_HPP
auto HG51B::serialize(serializer& s) -> void {
s.array(dataRAM);
for(auto& n : stack) s.integer(n);
@ -23,5 +21,3 @@ auto HG51B::serialize(serializer& s) -> void {
s.integer(regs.ramaddr);
for(auto& n : regs.gpr) s.integer(n);
}
#endif

View File

@ -1,7 +1,6 @@
//Sharp LR35902 (Game Boy Z80-derivative)
#ifndef PROCESSOR_LR35902_HPP
#define PROCESSOR_LR35902_HPP
#pragma once
namespace Processor {
@ -164,5 +163,3 @@ privileged:
};
}
#endif

View File

@ -2,8 +2,7 @@
//* Ricoh 2A03
//* Ricoh 2A07
#ifndef PROCESSOR_R6502_HPP
#define PROCESSOR_R6502_HPP
#pragma once
namespace Processor {
@ -114,5 +113,3 @@ struct R6502 {
};
}
#endif

View File

@ -1,12 +1,11 @@
#ifndef PROCESSOR_R65816_HPP
#define PROCESSOR_R65816_HPP
namespace Processor {
//WDC 65C816 CPU core
//* Ricoh 5A22
//* Nintendo SA-1
#pragma once
namespace Processor {
struct R65816 {
#include "registers.hpp"
#include "memory.hpp"
@ -227,5 +226,3 @@ struct R65816 {
};
}
#endif

View File

@ -1,5 +1,4 @@
#ifndef PROCESSOR_SPC700_HPP
#define PROCESSOR_SPC700_HPP
#pragma once
namespace Processor {
@ -104,5 +103,3 @@ protected:
};
}
#endif

View File

@ -2,8 +2,7 @@
//NEC uPD7725
//NEC uPD96050
#ifndef PROCESSOR_UPD96050_HPP
#define PROCESSOR_UPD96050_HPP
#pragma once
namespace Processor {
@ -72,5 +71,3 @@ struct uPD96050 {
};
}
#endif

View File

@ -7,15 +7,153 @@ auto V30MZ::parity(uint16 value) const -> bool {
return !(value & 1);
}
#define bits (size == Byte ? 8 : 16)
#define mask (size == Byte ? 0xff : 0xffff)
#define sign (size == Byte ? 0x80 : 0xffff)
auto V30MZ::alAdc(Size size, uint16 x, uint16 y) -> uint16 {
return alAdd(size, x, y + r.f.c);
}
auto V30MZ::alAdd(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x + y) & mask;
r.f.c = x + y > mask;
r.f.p = parity(result);
r.f.h = (uint4)x + (uint4)y >= 16;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (result ^ x) & (result ^ y) & sign;
return result;
}
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;
uint16 result = (x & y) & mask;
r.f.c = 0;
r.f.p = parity(result);
r.f.h = 0;
r.f.z = result == 0;
r.f.s = result & mask;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::alOr(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x | y) & mask;
r.f.c = 0;
r.f.p = parity(result);
r.f.h = 0;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::alRcl(Size size, uint16 x, uint5 y) -> uint16 {
uint16 result = x;
for(uint n = 0; n < y; n++) {
bool carry = result & sign;
result = (result << 1) | carry;
r.f.c = carry;
}
r.f.v = (x ^ result) & sign;
return result & mask;
}
auto V30MZ::alRcr(Size size, uint16 x, uint5 y) -> uint16 {
uint16 result = x;
for(uint n = 0; n < y; n++) {
bool carry = result & 1;
result = (carry ? sign : 0) | (result >> 1);
r.f.c = carry;
}
r.f.v = (x ^ result) & sign;
return result & mask;
}
auto V30MZ::alRol(Size size, uint16 x, uint4 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = ((x << y) | (x >> (bits - y))) & mask;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::alRor(Size size, uint16 x, uint4 y) -> uint16 {
r.f.c = (x >> (y - 1)) & 1;
uint16 result = ((x >> y) | (x << (bits - y))) & mask;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::alSal(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = (x << y) & mask;
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::alSar(Size size, uint16 x, uint5 y) -> uint16 {
if(y & 16) {
r.f.c = x & sign;
return 0 - r.f.c;
}
r.f.c = (x >> (y - 1)) & 1;
uint16 result = (x >> y) & mask;
if(x & sign) result |= mask << (bits - y);
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
auto V30MZ::alSbb(Size size, uint16 x, uint16 y) -> uint16 {
return alSub(size, x, y + r.f.c);
}
auto V30MZ::alShl(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = (x << y) & mask;
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::alShr(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x >> (y - 1)) & 1;
uint16 result = (x >> y) & mask;
r.f.p = parity(result);
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::alSub(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x - y) & mask;
r.f.c = y > x;
r.f.p = parity(result);
r.f.h = (uint4)y > (uint4)x;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = (x ^ y) & (x ^ result) & sign;
return result;
}
auto V30MZ::alXor(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x ^ y) & mask;
r.f.c = 0;
r.f.p = parity(result);
r.f.h = 0;
r.f.z = result == 0;
r.f.s = result & sign;
r.f.v = 0;
return result;
}
#undef mask
#undef sign

View File

@ -1,43 +1,80 @@
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers) -> string {
auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> string {
string s;
uint20 ea = (cs << 4) + ip;
uint20 ea = cs * 16 + ip;
vector<uint8> bytesRead;
enum : uint { Byte, Word, Segment };
auto readByte = [&](uint offset) -> string {
uint8 byte = read((cs << 4) + (uint16)(ip + offset++));
auto fetch = [&](bool inc = true) -> uint8 {
uint8 data = read(cs * 16 + ip);
if(inc) ip++, bytesRead.append(data);
return data;
};
auto readByte = [&]() -> string {
uint8 byte = fetch();
return {"$", hex(byte, 2L)};
};
auto readWord = [&](uint offset) -> string {
uint16 word = read((cs << 4) + (uint16)(ip + offset++)) << 0;
word |= read((cs << 4) + (uint16)(ip + offset++)) << 8;
auto readWord = [&]() -> string {
uint16 word = fetch(); word |= fetch() << 8;
return {"$", hex(word, 4L)};
};
auto readRelativeByte = [&](uint offset, uint displacement) -> string {
uint8 byte = read((cs << 4) + (uint16)(ip + offset++));
return {"$", hex(ip + displacement + (int8)byte, 4L)};
auto readByteSigned = [&]() -> string {
uint8 byte = fetch();
return {"$", byte & 0x80 ? "-" : "+", hex(byte & 0x80 ? 256 - byte : byte, 2L)};
};
auto readRelativeWord = [&](uint offset, uint displacement) -> string {
uint16 word = read((cs << 4) + (uint16)(ip + offset++)) << 0;
word |= read((cs << 4) + (uint16)(ip + offset++)) << 8;
return {"$", hex(ip + displacement + (int16)word, 4L)};
auto readRelativeByte = [&]() -> string {
uint8 byte = fetch();
return {"$", hex(ip + (int8)byte, 4L)};
};
auto readModRM = [&](uint offset, uint mode) -> string {
uint8 modRM = read((cs << 4) + (uint16)(ip + offset++));
static const string reg[3][8] = {
{"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"},
{"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"},
{"es", "cs", "ss", "ds", "es", "cs", "ss", "ds"},
};
string d = reg[mode][(uint3)(modRM >> 3)];
if(modRM >= 0xc0) return {d, ",", reg[Word][modRM & 7]};
if((modRM & 0xc7) == 0x06) return {d, ",[", readWord(offset), "]"};
static const string mem[8] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"};
if((modRM & 0xc0) == 0x40) return {d, ",[", mem[modRM & 7], "+", readByte(offset), "]"};
if((modRM & 0xc0) == 0x80) return {d, ",[", mem[modRM & 7], "+", readWord(offset), "]"};
return {d, ",[", mem[modRM & 7], "]"};
auto readRelativeWord = [&]() -> string {
uint16 word = fetch(); word |= fetch() << 8;
return {"$", hex(ip + (int16)word, 4L)};
};
auto readRepeat = [&](uint offset) -> string {
uint8 opcode = read((cs << 4) + (uint16)(ip + offset++));
auto readRegByte = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string reg[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
return reg[(uint3)(modRM >> 3)];
};
auto readRegWord = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string reg[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
return reg[(uint3)(modRM >> 3)];
};
auto readSeg = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string seg[] = {"es", "cs", "ss", "ds"};
return seg[(uint2)(modRM >> 3)];
};
auto readMemByte = [&](bool inc = true) -> string {
uint8 modRM = fetch(inc);
static const string reg[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
if(modRM >= 0xc0) return reg[(uint3)modRM];
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], "]"};
};
auto readMemWord = [&](bool inc = true) -> string {
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(), "]"};
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], "]"};
};
auto readGroup1 = [&]() -> string {
uint8 modRM = fetch(false);
static const string grp[] = {"add", "or ", "adc", "sbb", "and", "sub", "xor", "cmp"};
return grp[(uint3)(modRM >> 3)];
};
auto readGroup2 = [&]() -> string {
uint8 modRM = fetch(false);
static const string grp[] = {"rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar"};
return grp[(uint3)(modRM >> 3)];
};
auto readRepeat = [&]() -> string {
uint8 opcode = fetch();
switch(opcode) {
case 0x6c: return "insb";
case 0x6d: return "insw";
@ -57,63 +94,176 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers) -> string {
return "";
};
auto opcode = read(ea);
auto opcode = fetch();
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 0x00: s = {"add {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x01: s = {"add {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x02: s = {"add {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x03: s = {"add {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x04: s = {"add al,{0}", format{readByte()}}; break;
case 0x05: s = {"add ax,{0}", format{readWord()}}; break;
case 0x08: s = {"or {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x09: s = {"or {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x0a: s = {"or {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x0b: s = {"or {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x0c: s = {"or al,{0}", format{readByte()}}; break;
case 0x0d: s = {"or ax,{0}", format{readWord()}}; break;
case 0x10: s = {"adc {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x11: s = {"adc {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x12: s = {"adc {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x13: s = {"adc {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x14: s = {"adc al,{0}", format{readByte()}}; break;
case 0x15: s = {"adc ax,{0}", format{readWord()}}; break;
case 0x18: s = {"sbb {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x19: s = {"sbb {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x1a: s = {"sbb {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x1b: s = {"sbb {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x1c: s = {"sbb al,{0}", format{readByte()}}; break;
case 0x1d: s = {"sbb ax,{0}", format{readWord()}}; break;
case 0x20: s = {"and {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x21: s = {"and {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x22: s = {"and {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x23: s = {"and {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x24: s = {"and al,{0}", format{readByte()}}; break;
case 0x25: s = {"and ax,{0}", format{readWord()}}; break;
case 0x26: s = {"es: "}; break;
case 0x28: s = {"sub {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x29: s = {"sub {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x2a: s = {"sub {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x2b: s = {"sub {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x2c: s = {"sub al,{0}", format{readByte()}}; break;
case 0x2d: s = {"sub ax,{0}", format{readWord()}}; break;
case 0x2e: s = {"cs: "}; break;
case 0x30: s = {"xor {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x31: s = {"xor {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x32: s = {"xor {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x33: s = {"xor {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x34: s = {"xor al,{0}", format{readByte()}}; break;
case 0x35: s = {"xor ax,{0}", format{readWord()}}; break;
case 0x36: s = {"ss: "}; break;
case 0x38: s = {"cmp {0},{1}", format{readMemByte(0), readRegByte()}}; break;
case 0x39: s = {"cmp {0},{1}", format{readMemWord(0), readRegWord()}}; break;
case 0x3a: s = {"cmp {0},{1}", format{readRegByte(0), readMemByte()}}; break;
case 0x3b: s = {"cmp {0},{1}", format{readRegWord(0), readMemWord()}}; break;
case 0x3c: s = {"cmp al,{0}", format{readByte()}}; break;
case 0x3d: s = {"cmp ax,{0}", format{readWord()}}; break;
case 0x3e: s = {"ds: "}; break;
case 0x40: s = {"inc ax"}; break;
case 0x41: s = {"inc cx"}; break;
case 0x42: s = {"inc dx"}; break;
case 0x43: s = {"inc bx"}; break;
case 0x44: s = {"inc sp"}; break;
case 0x45: s = {"inc bp"}; break;
case 0x46: s = {"inc si"}; break;
case 0x47: s = {"inc di"}; break;
case 0x48: s = {"dec ax"}; break;
case 0x49: s = {"dec cx"}; break;
case 0x4a: s = {"dec dx"}; break;
case 0x4b: s = {"dec bx"}; break;
case 0x4c: s = {"dec sp"}; break;
case 0x4d: s = {"dec bp"}; break;
case 0x4e: s = {"dec si"}; break;
case 0x4f: s = {"dec di"}; break;
case 0x50: s = {"push ax"}; break;
case 0x51: s = {"push cx"}; break;
case 0x52: s = {"push dx"}; break;
case 0x53: s = {"push bx"}; break;
case 0x54: s = {"push sp"}; break;
case 0x55: s = {"push bp"}; break;
case 0x56: s = {"push si"}; break;
case 0x57: s = {"push di"}; break;
case 0x58: s = {"pop ax"}; break;
case 0x59: s = {"pop cx"}; break;
case 0x5a: s = {"pop dx"}; break;
case 0x5b: s = {"pop bx"}; break;
case 0x5c: s = {"pop sp"}; break;
case 0x5d: s = {"pop bp"}; break;
case 0x5e: s = {"pop si"}; break;
case 0x5f: s = {"pop di"}; 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;
case 0x73: s = {"jnc {0}", format{readRelativeByte()}}; break;
case 0x74: s = {"jz {0}", format{readRelativeByte()}}; break;
case 0x75: s = {"jnz {0}", format{readRelativeByte()}}; break;
case 0x76: s = {"jcz {0}", format{readRelativeByte()}}; break;
case 0x77: s = {"jncz {0}", format{readRelativeByte()}}; break;
case 0x78: s = {"js {0}", format{readRelativeByte()}}; break;
case 0x79: s = {"jns {0}", format{readRelativeByte()}}; break;
case 0x7a: s = {"jp {0}", format{readRelativeByte()}}; break;
case 0x7b: s = {"jnp {0}", format{readRelativeByte()}}; break;
case 0x7c: s = {"jl {0}", format{readRelativeByte()}}; break;
case 0x7d: s = {"jnl {0}", format{readRelativeByte()}}; break;
case 0x7e: s = {"jle {0}", format{readRelativeByte()}}; break;
case 0x7f: s = {"jnle {0}", format{readRelativeByte()}}; break;
case 0x80: s = {"{0} {1},{2}", format{readGroup1(), readMemByte(), readByte()}}; break;
case 0x81: s = {"{0} {1},{2}", format{readGroup1(), readMemWord(), readWord()}}; break;
case 0x82: s = {"{0} {1},{2}", format{readGroup1(), readMemByte(), readByteSigned()}}; break;
case 0x83: s = {"{0} {1},{2}", format{readGroup1(), readMemWord(), readByteSigned()}}; 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 0x8e: s = {"mov {0},{1}", format{readSeg(0), readMemWord()}}; break;
case 0x90: s = {"nop "}; 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 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 0xa8: s = {"test al,{0}", format{readByte()}}; break;
case 0xa9: s = {"test ax,{0}", format{readWord()}}; break;
case 0xaa: s = {"stosb "}; break;
case 0xab: s = {"stosw "}; break;
case 0xb0: s = {"mov al,{0}", format{readByte()}}; break;
case 0xb1: s = {"mov cl,{0}", format{readByte()}}; break;
case 0xb2: s = {"mov dl,{0}", format{readByte()}}; break;
case 0xb3: s = {"mov bl,{0}", format{readByte()}}; break;
case 0xb4: s = {"mov ah,{0}", format{readByte()}}; break;
case 0xb5: s = {"mov ch,{0}", format{readByte()}}; break;
case 0xb6: s = {"mov dh,{0}", format{readByte()}}; break;
case 0xb7: s = {"mov bh,{0}", format{readByte()}}; break;
case 0xb8: s = {"mov ax,{0}", format{readWord()}}; break;
case 0xb9: s = {"mov cx,{0}", format{readWord()}}; break;
case 0xba: s = {"mov dx,{0}", format{readWord()}}; break;
case 0xbb: s = {"mov bx,{0}", format{readWord()}}; break;
case 0xbc: s = {"mov sp,{0}", format{readWord()}}; break;
case 0xbd: s = {"mov bp,{0}", format{readWord()}}; break;
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{readGroup2(), readMemByte(), readByte()}}; break;
case 0xc1: s = {"{0}w {1},{2}", format{readGroup2(), readMemWord(), readByte()}}; 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 0xc6: s = {"mov {0},{1}", format{readMemByte(), readByte()}}; break;
case 0xc7: s = {"mov {0},{1}", format{readMemWord(), readWord()}}; break;
case 0xcb: s = {"retf "}; break;
case 0xd0: s = {"{0} {1},1", format{readGroup2(), readMemByte()}}; break;
case 0xd1: s = {"{0}w {1},1", format{readGroup2(), readMemWord()}}; break;
case 0xd2: s = {"{0} {1},cl", format{readGroup2(), readMemByte()}}; break;
case 0xd3: s = {"{0}w {1},cl", format{readGroup2(), readMemWord()}}; break;
case 0xd8: s = {"fpo1 d8"}; break;
case 0xd9: s = {"fpo1 d9"}; break;
case 0xda: s = {"fpo1 da"}; break;
case 0xdb: s = {"fpo1 db"}; break;
case 0xdc: s = {"fpo1 dc"}; break;
case 0xdd: s = {"fpo1 dd"}; break;
case 0xde: s = {"fpo1 de"}; break;
case 0xdf: s = {"fpo1 df"}; break;
case 0xe4: s = {"in al,{0}", format{readByte()}}; break;
case 0xe5: s = {"in ax,{0}", format{readByte()}}; break;
case 0xe6: s = {"out {0},al", format{readByte()}}; break;
case 0xe7: s = {"out {0},ax", format{readByte()}}; break;
case 0xe8: s = {"call {0}", format{readRelativeWord()}}; break;
case 0xea: s = {"jmp {1}:{0}", format{readWord(), readWord()}}; break;
case 0xeb: s = {"jmp {0}", format{readRelativeByte()}}; 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 0xf2: s = {"repnz {0}", format{readRepeat()}}; break;
case 0xf3: s = {"repz {0}", format{readRepeat()}}; break;
case 0xf8: s = {"clc "}; break;
case 0xf9: s = {"stc "}; break;
case 0xfa: s = {"cli "}; break;
@ -124,34 +274,45 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers) -> string {
default:
s = {"??? [", hex(opcode, 2L), "]"};
}
while(s.size() < 20) s.append(" ");
while(s.size() < 24) s.append(" ");
if(!registers) return {hex(ea, 5L), " ", s};
string l;
if(registers) {
l = {
" ax:", hex(r.ax, 4L),
" bx:", hex(r.bx, 4L),
" cx:", hex(r.cx, 4L),
" dx:", hex(r.dx, 4L),
" si:", hex(r.si, 4L),
" di:", hex(r.di, 4L),
" bp:", hex(r.bp, 4L),
" sp:", hex(r.sp, 4L),
" ip:", hex(r.ip, 4L),
" cs:", hex(r.cs, 4L),
" ds:", hex(r.ds, 4L),
" es:", hex(r.es, 4L),
" ss:", hex(r.ss, 4L), " ",
r.f.m ? "M" : "m",
r.f.v ? "V" : "v",
r.f.d ? "D" : "d",
r.f.i ? "I" : "i",
r.f.b ? "B" : "b",
r.f.s ? "S" : "s",
r.f.z ? "Z" : "z",
r.f.h ? "H" : "h",
r.f.p ? "P" : "p",
r.f.c ? "C" : "c"
};
}
return {
hex(ea, 5L), " ", s,
" ax:", hex(r.ax, 4L),
" bx:", hex(r.bx, 4L),
" cx:", hex(r.cx, 4L),
" dx:", hex(r.dx, 4L),
" si:", hex(r.si, 4L),
" di:", hex(r.di, 4L),
" bp:", hex(r.bp, 4L),
" sp:", hex(r.sp, 4L),
" ip:", hex(r.ip, 4L),
" cs:", hex(r.cs, 4L),
" ds:", hex(r.ds, 4L),
" es:", hex(r.es, 4L),
" ss:", hex(r.ss, 4L), " ",
r.f.m ? "M" : "m",
r.f.v ? "V" : "v",
r.f.d ? "D" : "d",
r.f.i ? "I" : "i",
r.f.b ? "B" : "b",
r.f.s ? "S" : "s",
r.f.z ? "Z" : "z",
r.f.h ? "H" : "h",
r.f.p ? "P" : "p",
r.f.c ? "C" : "c"
};
string b;
if(bytes) {
b = " ";
while(bytesRead) {
b.append(hex(bytesRead.takeFirst(), 2L), " ");
}
b.rstrip();
}
return {hex(ea, 5L), " ", s, l, b};
}

View File

@ -1,25 +1,227 @@
auto V30MZ::opXorRegisterModRM(Size size) {
auto modRM = readIP();
setRegister(size, modRM, getRegister(size, modRM) ^ readModRM(size, modRM));
//00 addb mem,reg
//01 addw mem,reg
auto V30MZ::opAddMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alAdd(size, getMem(size, modRM), getReg(size, modRM)));
}
//02 addb reg,mem
//03 addw reg,mem
auto V30MZ::opAddRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alAdd(size, getReg(size, modRM), getMem(size, modRM)));
}
//04 add al,#imm
//05 add ax,#imm
auto V30MZ::opAddAccImm(Size size) {
setAcc(size, alAdd(size, getAcc(size), fetch(size)));
}
//08 orb mem,reg
//09 orb mem,reg
auto V30MZ::opOrMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alOr(size, getMem(size, modRM), getReg(size, modRM)));
}
//0a orb reg,mem
//0b orb reg,mem
auto V30MZ::opOrRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alOr(size, getReg(size, modRM), getMem(size, modRM)));
}
//0c or al,#imm
//0d or ax,#imm
auto V30MZ::opOrAccImm(Size size) {
setAcc(size, alOr(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAdcMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alAdc(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opAdcRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alAdc(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opAdcAccImm(Size size) {
setAcc(size, alAdc(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSbbMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alSbb(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opSbbRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alSbb(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opSbbAccImm(Size size) {
setAcc(size, alSbb(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAndMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alAnd(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opAndRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alAnd(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opAndAccImm(Size size) {
setAcc(size, alAnd(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSubMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alSub(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opSubRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alSub(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opSubAccImm(Size size) {
setAcc(size, alSub(size, getAcc(size), fetch(size)));
}
//26 es:
//2e cs:
//36 ss:
//3e ds:
auto V30MZ::opPrefix(uint16& segment) {
//todo
}
auto V30MZ::opXorMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, alXor(size, getMem(size, modRM), getReg(size, modRM)));
}
auto V30MZ::opXorRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, alXor(size, getReg(size, modRM), getMem(size, modRM)));
}
auto V30MZ::opXorAccImm(Size size) {
setAcc(size, alXor(size, getAcc(size), fetch(size)));
}
auto V30MZ::opCmpMemReg(Size size) {
auto modRM = fetch();
alSub(size, getMem(size, modRM), getReg(size, modRM));
}
auto V30MZ::opCmpRegMem(Size size) {
auto modRM = fetch();
alSub(size, getReg(size, modRM), getMem(size, modRM));
}
auto V30MZ::opCmpAccImm(Size size) {
alSub(size, getAcc(size), fetch(size));
}
//40 inc ax
//41 inc cx
//42 inc dx
//43 inc bx
//44 inc sp
//45 inc bp
//46 inc si
//47 inc di
auto V30MZ::opIncReg(uint16& reg) {
reg++;
}
//48 dec ax
//49 dec cx
//4a dec dx
//4b dec bx
//4c dec sp
//4d dec bp
//4e dec si
//4f dec di
auto V30MZ::opDecReg(uint16& reg) {
reg--;
}
auto V30MZ::opPushReg(uint16& reg) {
push(reg);
}
auto V30MZ::opPopReg(uint16& reg) {
reg = pop();
}
auto V30MZ::opJumpIf(bool condition) {
auto displacement = (int8)readIP();
if(condition) r.ip += displacement;
auto offset = (int8)fetch();
if(condition) r.ip += offset;
}
auto V30MZ::opMoveRegisterModRM(Size size) {
auto modRM = readIP();
setRegister(size, modRM, readModRM(size, modRM));
//80 grp1 memb,imm8
//81 grp1 memw,imm16
//82 grp1 memb,imm8s
//83 grp1 memw,imm8s
auto V30MZ::opGroup1MemImm(Size size, bool sign) {
auto modRM = fetch();
auto imm = sign ? (int8)fetch() : size == Byte ? fetch() : fetch(Word);
auto mem = getMem(size, modRM);
switch((uint3)(modRM >> 3)) {
case 0: setMem(size, modRM, alAdd(size, mem, imm)); break;
case 1: setMem(size, modRM, alOr (size, mem, imm)); break;
case 2: setMem(size, modRM, alAdc(size, mem, imm)); break;
case 3: setMem(size, modRM, alSbb(size, mem, imm)); break;
case 4: setMem(size, modRM, alAnd(size, mem, imm)); break;
case 5: setMem(size, modRM, alSub(size, mem, imm)); break;
case 6: setMem(size, modRM, alXor(size, mem, imm)); break;
case 7: alSub(size, mem, imm); break;
}
}
auto V30MZ::opMoveSegmentRegisterModRM() {
auto V30MZ::opMoveMemReg(Size size) {
auto modRM = fetch();
setMem(size, modRM, getReg(size, modRM));
}
auto V30MZ::opMoveRegMem(Size size) {
auto modRM = fetch();
setReg(size, modRM, getMem(size, modRM));
}
auto V30MZ::opMoveSegMem() {
wait(1);
auto modRM = readIP();
setSegment(modRM, readModRM(Word, modRM));
auto modRM = fetch();
setSeg(modRM, getMem(Word, modRM));
}
auto V30MZ::opNoOperation() {
auto V30MZ::opNop() {
}
auto V30MZ::opCallFar() {
wait(9);
auto ip = fetch(Word);
auto cs = fetch(Word);
push(r.cs);
push(r.ip);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::opMoveAccMem(Size size) {
setAcc(size, read(size, r.ds, fetch(Word)));
}
auto V30MZ::opMoveMemAcc(Size size) {
write(size, r.ds, fetch(Word), getAcc(size));
}
auto V30MZ::opMoveString(Size size) {
@ -29,26 +231,64 @@ auto V30MZ::opMoveString(Size size) {
r.di += r.f.d ? -size : size;
}
auto V30MZ::opTestAX(Size size) {
alAnd(size, r.ax, readIP(size));
auto V30MZ::opTestAcc(Size size) {
alAnd(size, getAcc(size), fetch(size));
}
auto V30MZ::opMoveRegisterImmediate(uint8& rd) {
rd = readIP(Byte);
auto V30MZ::opStoreString(Size size) {
wait(2);
write(size, r.es, r.di, getAcc(size));
r.di += r.f.d ? -size : size;
}
auto V30MZ::opMoveRegisterImmediate(uint16& rd) {
rd = readIP(Word);
auto V30MZ::opMoveRegImm(uint8& reg) {
reg = fetch(Byte);
}
auto V30MZ::opMoveRegImm(uint16& reg) {
reg = fetch(Word);
}
auto V30MZ::opReturn() {
wait(5);
r.ip = readSP();
r.ip = pop();
}
auto V30MZ::opMoveMemImm(Size size) {
auto modRM = fetch();
setMem(size, modRM, fetch(size));
}
auto V30MZ::opRetFar() {
wait(7);
auto ip = pop();
auto cs = pop();
r.cs = cs;
r.ip = ip;
}
auto V30MZ::opGroup2MemImm(Size size, maybe<uint8> imm) {
auto modRM = fetch();
if(!imm) {
wait(2);
imm = fetch();
}
auto mem = getMem(size, modRM);
switch((uint3)(modRM >> 3)) {
case 0: setMem(size, modRM, alRol(size, mem, *imm)); break;
case 1: setMem(size, modRM, alRor(size, mem, *imm)); break;
case 2: setMem(size, modRM, alRcl(size, mem, *imm)); break;
case 3: setMem(size, modRM, alRcr(size, mem, *imm)); break;
case 4: setMem(size, modRM, alShl(size, mem, *imm)); break;
case 5: setMem(size, modRM, alShr(size, mem, *imm)); break;
case 6: setMem(size, modRM, alSal(size, mem, *imm)); break;
case 7: setMem(size, modRM, alSar(size, mem, *imm)); break;
}
}
auto V30MZ::opIn(Size size) {
wait(5);
auto port = readIP();
auto port = fetch();
r.al = in(port++);
if(size != Word) return;
r.ah = in(port++);
@ -56,7 +296,7 @@ auto V30MZ::opIn(Size size) {
auto V30MZ::opOut(Size size) {
wait(5);
auto port = readIP();
auto port = fetch();
out(port++, r.al);
if(size != Word) return;
out(port++, r.ah);
@ -64,17 +304,23 @@ auto V30MZ::opOut(Size size) {
auto V30MZ::opCallNear() {
wait(4);
auto displacement = (int16)readIP(Word);
writeSP(r.ip);
r.ip += displacement;
auto offset = (int16)fetch(Word);
push(r.ip);
r.ip += offset;
}
auto V30MZ::opJumpFar() {
wait(6);
auto ip = readIP(Word);
auto cs = readIP(Word);
r.ip = ip;
auto ip = fetch(Word);
auto cs = fetch(Word);
r.cs = cs;
r.ip = ip;
}
auto V30MZ::opJumpShort() {
wait(3);
auto offset = (int8)fetch();
r.ip += offset;
}
auto V30MZ::opInDX(Size size) {
@ -93,7 +339,7 @@ auto V30MZ::opOutDX(Size size) {
auto V30MZ::opRepeat(bool flag) {
wait(4);
auto opcode = readIP();
auto opcode = fetch();
if((opcode & 0xfc) != 0x6c && (opcode & 0xfc) != 0xa4
&& (opcode & 0xfe) != 0xaa && (opcode & 0xfc) != 0xac) {
//invalid argument
@ -106,6 +352,8 @@ auto V30MZ::opRepeat(bool flag) {
switch(opcode) {
case 0xa4: opMoveString(Byte); r.ip -= 2; break;
case 0xa5: opMoveString(Word); r.ip -= 2; break;
case 0xaa: opStoreString(Byte); r.ip -= 2; break;
case 0xab: opStoreString(Word); r.ip -= 2; break;
}
}

View File

@ -11,48 +11,19 @@ auto V30MZ::write(Size size, uint16 segment, uint16 address, uint16 data) -> voi
//
auto V30MZ::readIP(Size size) -> uint16 {
auto V30MZ::fetch(Size size) -> uint16 {
uint16 data = read(size, r.cs, r.ip);
return r.ip += size, data;
}
//
auto V30MZ::readSP() -> uint16 {
auto V30MZ::pop() -> uint16 {
uint16 data = read(Word, r.ss, r.sp);
return r.sp += Word, data;
}
auto V30MZ::writeSP(uint16 data) -> void {
auto V30MZ::push(uint16 data) -> void {
r.sp -= Word;
write(Word, r.ss, r.sp, data);
}
//
auto V30MZ::readModRM(uint8 modRM) -> uint32 {
if((modRM & 0xc7) == 0x06) return r.ds << 16 | readIP(Word);
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: 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;
}
return s << 16 | a;
}
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

@ -0,0 +1,60 @@
//ModRM functions
//d7-d6 => mod
//d5-d3 => reg
//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;
}
auto V30MZ::setReg(Size size, uint8 modRM, uint16 data) -> void {
if(size == Byte) r.byte(modRM >> 3) = data;
if(size == Word) r.word(modRM >> 3) = data;
}
//
auto V30MZ::getSeg(uint8 modRM) -> uint16 {
return r.segment(modRM >> 3);
}
auto V30MZ::setSeg(uint8 modRM, uint16 data) -> void {
r.segment(modRM >> 3) = data;
}
//
auto V30MZ::getMemAddress(uint8 modRM) -> uint32 {
if((modRM & 0xc7) == 0x06) return r.ds << 16 | fetch(Word);
uint16 s = 0, a = 0;
if((modRM & 0xc0) == 0x40) a = (int8)fetch(Byte);
if((modRM & 0xc0) == 0x80) a = (int16)fetch(Word);
switch(modRM & 7) {
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;
}
return s << 16 | a;
}
auto V30MZ::getMem(Size size, uint8 modRM) -> uint16 {
if(modRM >= 0xc0) return getReg(size, modRM << 3);
auto addr = getMemAddress(modRM);
return read(size, addr >> 16, addr);
}
auto V30MZ::setMem(Size size, uint8 modRM, uint16 data) -> void {
if(modRM >= 0xc0) return setReg(size, modRM << 3, data);
auto addr = getMemAddress(modRM);
return write(size, addr >> 16, addr, data);
}

View File

@ -1,28 +1,47 @@
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::getAcc(Size size) -> uint16 {
if(size == Byte) return r.al;
if(size == Word) return r.ax;
unreachable;
}
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::setAcc(Size size, uint16 data) -> void {
if(size == Byte) r.al = data;
if(size == Word) r.ax = data;
}
//
auto V30MZ::getSegment(uint8 modRM) -> uint16 {
static uint16* word[] = {&r.es, &r.cs, &r.ss, &r.ds};
return *word[(modRM >> 3) & 3];
auto V30MZ::Registers::byte(uint3 r) -> uint8& {
switch(r) {
case 0: return al;
case 1: return cl;
case 2: return dl;
case 3: return bl;
case 4: return ah;
case 5: return ch;
case 6: return dh;
case 7: return bh;
} unreachable;
}
auto V30MZ::setSegment(uint8 modRM, uint16 data) -> void {
static uint16* word[] = {&r.es, &r.cs, &r.ss, &r.ds};
*word[(modRM >> 3) & 3] = data;
auto V30MZ::Registers::word(uint3 r) -> uint16& {
switch(r) {
case 0: return ax;
case 1: return cx;
case 2: return dx;
case 3: return bx;
case 4: return sp;
case 5: return bp;
case 6: return si;
case 7: return di;
} unreachable;
}
auto V30MZ::Registers::segment(uint2 r) -> uint16& {
switch(r) {
case 0: return es;
case 1: return cs;
case 2: return ss;
case 3: return ds;
} unreachable;
}
//

View File

@ -6,6 +6,7 @@ namespace Processor {
const uint V30MZ::Byte = 1;
const uint V30MZ::Word = 2;
#include "registers.cpp"
#include "modrm.cpp"
#include "memory.cpp"
#include "algorithms.cpp"
#include "instructions.cpp"
@ -15,7 +16,8 @@ auto V30MZ::exec() -> void {
if(halt) return wait(1);
#if 1
print(disassemble(r.cs, r.ip), "\n");
static uint16 cs = 0, ip = 0;
if(cs != r.cs || ip != r.ip) print(disassemble(cs = r.cs, ip = r.ip), "\n");
#endif
execOpcode();
@ -24,12 +26,94 @@ auto V30MZ::exec() -> void {
auto V30MZ::execOpcode() -> void {
executed++;
auto opcode = readIP();
auto opcode = fetch();
wait(1);
switch(opcode) {
case 0x32: return opXorRegisterModRM(Byte);
case 0x33: return opXorRegisterModRM(Word);
case 0x00: return opAddMemReg(Byte);
case 0x01: return opAddMemReg(Word);
case 0x02: return opAddRegMem(Byte);
case 0x03: return opAddRegMem(Word);
case 0x04: return opAddAccImm(Byte);
case 0x05: return opAddAccImm(Word);
case 0x08: return opOrMemReg(Byte);
case 0x09: return opOrMemReg(Word);
case 0x0a: return opOrRegMem(Byte);
case 0x0b: return opOrRegMem(Word);
case 0x0c: return opOrAccImm(Byte);
case 0x0d: return opOrAccImm(Word);
case 0x10: return opAdcMemReg(Byte);
case 0x11: return opAdcMemReg(Word);
case 0x12: return opAdcRegMem(Byte);
case 0x13: return opAdcRegMem(Word);
case 0x14: return opAdcAccImm(Byte);
case 0x15: return opAdcAccImm(Word);
case 0x18: return opSbbMemReg(Byte);
case 0x19: return opSbbMemReg(Word);
case 0x1a: return opSbbRegMem(Byte);
case 0x1b: return opSbbRegMem(Word);
case 0x1c: return opSbbAccImm(Byte);
case 0x1d: return opSbbAccImm(Word);
case 0x20: return opAndMemReg(Byte);
case 0x21: return opAndMemReg(Word);
case 0x22: return opAndRegMem(Byte);
case 0x23: return opAndRegMem(Word);
case 0x24: return opAndAccImm(Byte);
case 0x25: return opAndAccImm(Word);
case 0x26: return opPrefix(r.es);
case 0x28: return opSubMemReg(Byte);
case 0x29: return opSubMemReg(Word);
case 0x2a: return opSubRegMem(Byte);
case 0x2b: return opSubRegMem(Word);
case 0x2c: return opSubAccImm(Byte);
case 0x2d: return opSubAccImm(Word);
case 0x2e: return opPrefix(r.cs);
case 0x30: return opXorMemReg(Byte);
case 0x31: return opXorMemReg(Word);
case 0x32: return opXorRegMem(Byte);
case 0x33: return opXorRegMem(Word);
case 0x34: return opXorAccImm(Byte);
case 0x35: return opXorAccImm(Word);
case 0x36: return opPrefix(r.ss);
case 0x38: return opCmpMemReg(Byte);
case 0x39: return opCmpMemReg(Word);
case 0x3a: return opCmpRegMem(Byte);
case 0x3b: return opCmpRegMem(Word);
case 0x3c: return opCmpAccImm(Byte);
case 0x3d: return opCmpAccImm(Word);
case 0x3e: return opPrefix(r.ds);
case 0x40: return opIncReg(r.ax);
case 0x41: return opIncReg(r.cx);
case 0x42: return opIncReg(r.dx);
case 0x43: return opIncReg(r.bx);
case 0x44: return opIncReg(r.sp);
case 0x45: return opIncReg(r.bp);
case 0x46: return opIncReg(r.si);
case 0x47: return opIncReg(r.di);
case 0x48: return opDecReg(r.ax);
case 0x49: return opDecReg(r.cx);
case 0x4a: return opDecReg(r.dx);
case 0x4b: return opDecReg(r.bx);
case 0x4c: return opDecReg(r.sp);
case 0x4d: return opDecReg(r.bp);
case 0x4e: return opDecReg(r.si);
case 0x4f: return opDecReg(r.di);
case 0x50: return opPushReg(r.ax);
case 0x51: return opPushReg(r.cx);
case 0x52: return opPushReg(r.dx);
case 0x53: return opPushReg(r.bx);
case 0x54: return opPushReg(r.sp);
case 0x55: return opPushReg(r.bp);
case 0x56: return opPushReg(r.si);
case 0x57: return opPushReg(r.di);
case 0x58: return opPopReg(r.ax);
case 0x59: return opPopReg(r.cx);
case 0x5a: return opPopReg(r.dx);
case 0x5b: return opPopReg(r.bx);
case 0x5c: return opPopReg(r.sp);
case 0x5d: return opPopReg(r.bp);
case 0x5e: return opPopReg(r.si);
case 0x5f: return opPopReg(r.di);
case 0x70: return opJumpIf(r.f.v == 1);
case 0x71: return opJumpIf(r.f.v == 0);
case 0x72: return opJumpIf(r.f.c == 1);
@ -46,37 +130,68 @@ 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 opMoveRegisterModRM(Byte);
case 0x8b: return opMoveRegisterModRM(Word);
case 0x8e: return opMoveSegmentRegisterModRM();
case 0x90: return opNoOperation();
case 0x80: return opGroup1MemImm(Byte, 0);
case 0x81: return opGroup1MemImm(Word, 0);
case 0x82: return opGroup1MemImm(Byte, 1);
case 0x83: return opGroup1MemImm(Word, 1);
case 0x88: return opMoveMemReg(Byte);
case 0x89: return opMoveMemReg(Word);
case 0x8a: return opMoveRegMem(Byte);
case 0x8b: return opMoveRegMem(Word);
case 0x8e: return opMoveSegMem();
case 0x90: return opNop();
case 0x9a: return opCallFar();
case 0xa0: return opMoveAccMem(Byte);
case 0xa1: return opMoveAccMem(Word);
case 0xa2: return opMoveMemAcc(Byte);
case 0xa3: return opMoveMemAcc(Word);
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 0xa8: return opTestAcc(Byte);
case 0xa9: return opTestAcc(Word);
case 0xaa: return opStoreString(Byte);
case 0xab: return opStoreString(Word);
case 0xb0: return opMoveRegImm(r.al);
case 0xb1: return opMoveRegImm(r.cl);
case 0xb2: return opMoveRegImm(r.dl);
case 0xb3: return opMoveRegImm(r.bl);
case 0xb4: return opMoveRegImm(r.ah);
case 0xb5: return opMoveRegImm(r.ch);
case 0xb6: return opMoveRegImm(r.dh);
case 0xb7: return opMoveRegImm(r.bh);
case 0xb8: return opMoveRegImm(r.ax);
case 0xb9: return opMoveRegImm(r.cx);
case 0xba: return opMoveRegImm(r.dx);
case 0xbb: return opMoveRegImm(r.bx);
case 0xbc: return opMoveRegImm(r.sp);
case 0xbd: return opMoveRegImm(r.bp);
case 0xbe: return opMoveRegImm(r.si);
case 0xbf: return opMoveRegImm(r.di);
case 0xc0: return opGroup2MemImm(Byte);
case 0xc1: return opGroup2MemImm(Word);
case 0xc3: return opReturn();
case 0xc6: return opMoveMemImm(Byte);
case 0xc7: return opMoveMemImm(Word);
case 0xcb: return opRetFar();
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);
case 0xd8: return opNop(); //FPO1
case 0xd9: return opNop(); //FPO1
case 0xda: return opNop(); //FPO1
case 0xdb: return opNop(); //FPO1
case 0xdc: return opNop(); //FPO1
case 0xdd: return opNop(); //FPO1
case 0xde: return opNop(); //FPO1
case 0xdf: return opNop(); //FPO1
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 0xeb: return opJumpShort();
case 0xec: return opInDX(Byte);
case 0xed: return opInDX(Word);
case 0xee: return opOutDX(Byte);

View File

@ -6,8 +6,8 @@ namespace Processor {
struct V30MZ {
using Size = const uint&;
static const uint Byte;
static const uint Word;
static const uint Byte; //= 1
static const uint Word; //= 2
virtual auto wait(uint clocks = 1) -> void = 0;
virtual auto read(uint20 addr) -> uint8 = 0;
@ -20,43 +20,99 @@ struct V30MZ {
auto power() -> void;
//registers.cpp
auto getRegister(Size, uint8) -> uint16;
auto setRegister(Size, uint8, uint16) -> void;
auto getAcc(Size) -> uint16;
auto setAcc(Size, uint16) -> void;
auto getSegment(uint8) -> uint16;
auto setSegment(uint8, uint16) -> void;
//modrm.cpp
auto getReg(Size, uint8) -> uint16;
auto setReg(Size, uint8, uint16) -> void;
auto getSeg(uint8) -> uint16;
auto setSeg(uint8, uint16) -> void;
auto getMemAddress(uint8) -> uint32;
auto getMem(Size, uint8) -> uint16;
auto setMem(Size, uint8, uint16) -> void;
//memory.cpp
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 readModRM(uint8) -> uint32;
auto readModRM(Size, uint8) -> uint16;
auto fetch(Size = Byte) -> uint16;
auto pop() -> uint16;
auto push(uint16) -> void;
//algorithms.cpp
auto parity(uint16) const -> bool;
auto alAdc(Size, uint16, uint16) -> uint16;
auto alAdd(Size, uint16, uint16) -> uint16;
auto alAnd(Size, uint16, uint16) -> uint16;
auto alOr (Size, uint16, uint16) -> uint16;
auto alRcl(Size, uint16, uint5 ) -> uint16;
auto alRcr(Size, uint16, uint5 ) -> uint16;
auto alRol(Size, uint16, uint4 ) -> uint16;
auto alRor(Size, uint16, uint4 ) -> uint16;
auto alSal(Size, uint16, uint5 ) -> uint16;
auto alSar(Size, uint16, uint5 ) -> uint16;
auto alSbb(Size, uint16, uint16) -> uint16;
auto alSub(Size, uint16, uint16) -> uint16;
auto alShl(Size, uint16, uint5 ) -> uint16;
auto alShr(Size, uint16, uint5 ) -> uint16;
auto alXor(Size, uint16, uint16) -> uint16;
//instructions.cpp
auto opXorRegisterModRM(Size);
auto opAddMemReg(Size);
auto opAddRegMem(Size);
auto opAddAccImm(Size);
auto opOrMemReg(Size);
auto opOrRegMem(Size);
auto opOrAccImm(Size);
auto opAdcMemReg(Size);
auto opAdcRegMem(Size);
auto opAdcAccImm(Size);
auto opSbbMemReg(Size);
auto opSbbRegMem(Size);
auto opSbbAccImm(Size);
auto opAndMemReg(Size);
auto opAndRegMem(Size);
auto opAndAccImm(Size);
auto opPrefix(uint16&);
auto opSubMemReg(Size);
auto opSubRegMem(Size);
auto opSubAccImm(Size);
auto opXorMemReg(Size);
auto opXorRegMem(Size);
auto opXorAccImm(Size);
auto opCmpMemReg(Size);
auto opCmpRegMem(Size);
auto opCmpAccImm(Size);
auto opIncReg(uint16&);
auto opDecReg(uint16&);
auto opPushReg(uint16&);
auto opPopReg(uint16&);
auto opJumpIf(bool);
auto opMoveRegisterModRM(Size);
auto opMoveSegmentRegisterModRM();
auto opNoOperation();
auto opGroup1MemImm(Size, bool);
auto opMoveMemReg(Size);
auto opMoveRegMem(Size);
auto opMoveSegMem();
auto opNop();
auto opCallFar();
auto opMoveAccMem(Size);
auto opMoveMemAcc(Size);
auto opMoveString(Size);
auto opTestAX(Size);
auto opMoveRegisterImmediate(uint8&);
auto opMoveRegisterImmediate(uint16&);
auto opTestAcc(Size);
auto opStoreString(Size);
auto opMoveRegImm(uint8&);
auto opMoveRegImm(uint16&);
auto opReturn();
auto opMoveMemImm(Size);
auto opRetFar();
auto opGroup2MemImm(Size, maybe<uint8> = {});
auto opIn(Size);
auto opOut(Size);
auto opCallNear();
auto opJumpFar();
auto opJumpShort();
auto opInDX(Size);
auto opOutDX(Size);
auto opRepeat(bool);
@ -64,13 +120,18 @@ struct V30MZ {
auto opSetFlag(bool&);
//disassembler.cpp
auto disassemble(uint16 cs, uint16 ip, bool registers = true) -> string;
auto disassemble(uint16 cs, uint16 ip, bool registers = true, bool bytes = true) -> string;
//state
bool halt = false;
uint executed = 0;
struct Registers {
//registers.cpp
auto byte(uint3) -> uint8&;
auto word(uint3) -> uint16&;
auto segment(uint2) -> uint16&;
uint16 ip;
union { uint16 ax; struct { uint8 order_lsb2(al, ah); }; };
union { uint16 bx; struct { uint8 order_lsb2(bl, bh); }; };
@ -86,6 +147,7 @@ struct V30MZ {
uint16 ss;
struct Flags {
//registers.cpp
operator uint16() const;
auto operator=(uint16 data);