2021-01-03 00:16:07 +00:00
|
|
|
|
//
|
|
|
|
|
// x86.cpp
|
|
|
|
|
// Clock Signal
|
|
|
|
|
//
|
|
|
|
|
// Created by Thomas Harte on 1/1/21.
|
|
|
|
|
// Copyright © 2021 Thomas Harte. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "x86.hpp"
|
|
|
|
|
|
2021-01-03 22:03:50 +00:00
|
|
|
|
#include <algorithm>
|
2021-01-03 02:11:19 +00:00
|
|
|
|
#include <cassert>
|
|
|
|
|
|
2021-01-03 00:16:07 +00:00
|
|
|
|
using namespace CPU::Decoder::x86;
|
|
|
|
|
|
2021-01-03 21:37:35 +00:00
|
|
|
|
// Only 8086 is suppoted for now.
|
|
|
|
|
Decoder::Decoder(Model) {}
|
|
|
|
|
|
2021-01-04 01:08:13 +00:00
|
|
|
|
Instruction Decoder::decode(const uint8_t *source, size_t length) {
|
|
|
|
|
const uint8_t *const end = source + length;
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// MARK: - Prefixes (if present) and the opcode.
|
|
|
|
|
|
|
|
|
|
/// Covers anything which is complete as soon as the opcode is encountered.
|
|
|
|
|
#define MapComplete(value, op, src, dest, size) \
|
|
|
|
|
case value: \
|
|
|
|
|
operation_ = Operation::op; \
|
|
|
|
|
source_ = Source::src; \
|
|
|
|
|
destination_ = Source::dest; \
|
|
|
|
|
phase_ = Phase::ReadyToPost; \
|
|
|
|
|
operation_size_ = size; \
|
2021-01-03 00:29:43 +00:00
|
|
|
|
break
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
/// Handles instructions of the form rr, kk and rr, jjkk, i.e. a destination register plus an operand.
|
|
|
|
|
#define MapRegData(value, op, dest, size) \
|
|
|
|
|
case value: \
|
|
|
|
|
operation_ = Operation::op; \
|
|
|
|
|
source_ = Source::Immediate; \
|
|
|
|
|
destination_ = Source::dest; \
|
|
|
|
|
phase_ = Phase::AwaitingDisplacementOrOperand; \
|
|
|
|
|
operand_size_ = size; \
|
2021-01-04 00:33:16 +00:00
|
|
|
|
break
|
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
/// Handles instructions of the form Ax, jjkk where the latter is implicitly an address.
|
|
|
|
|
#define MapRegAddr(value, op, dest, op_size, addr_size) \
|
|
|
|
|
case value: \
|
|
|
|
|
operation_ = Operation::op; \
|
|
|
|
|
destination_ = Source::dest; \
|
|
|
|
|
source_ = Source::DirectAddress; \
|
|
|
|
|
phase_ = Phase::AwaitingDisplacementOrOperand; \
|
|
|
|
|
operand_size_ = addr_size; \
|
|
|
|
|
operation_size_ = op_size; \
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
/// Handles instructions of the form jjkk, Ax where the former is implicitly an address.
|
|
|
|
|
#define MapAddrReg(value, op, source, op_size, addr_size) \
|
|
|
|
|
case value: \
|
|
|
|
|
operation_ = Operation::op; \
|
|
|
|
|
source_ = Source::source; \
|
|
|
|
|
destination_ = Source::DirectAddress; \
|
|
|
|
|
phase_ = Phase::AwaitingDisplacementOrOperand; \
|
|
|
|
|
operand_size_ = addr_size; \
|
|
|
|
|
operation_size_ = op_size; \
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
/// Covers both `mem/reg, reg` and `reg, mem/reg`.
|
|
|
|
|
#define MapMemRegReg(value, op, format, size) \
|
|
|
|
|
case value: \
|
|
|
|
|
operation_ = Operation::op; \
|
|
|
|
|
phase_ = Phase::ModRegRM; \
|
|
|
|
|
modregrm_format_ = ModRegRMFormat::format; \
|
|
|
|
|
operand_size_ = 0; \
|
|
|
|
|
operation_size_ = size; \
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
/// Handles JO, JNO, JB, etc — jumps with a single byte displacement.
|
|
|
|
|
#define MapJump(value, op) \
|
|
|
|
|
case value: \
|
|
|
|
|
operation_ = Operation::op; \
|
|
|
|
|
phase_ = Phase::AwaitingDisplacementOrOperand; \
|
|
|
|
|
operand_size_ = 1; \
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
/// Handles far CALL and far JMP — fixed four byte operand operations.
|
|
|
|
|
#define MapFar(value, op) \
|
|
|
|
|
case value: \
|
|
|
|
|
operation_ = Operation::op; \
|
|
|
|
|
phase_ = Phase::AwaitingDisplacementOrOperand; \
|
|
|
|
|
operand_size_ = 4; \
|
2021-01-03 00:29:43 +00:00
|
|
|
|
break
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
2021-01-03 22:03:50 +00:00
|
|
|
|
while(phase_ == Phase::Instruction && source != end) {
|
2021-01-03 00:29:43 +00:00
|
|
|
|
// Retain the instruction byte, in case additional decoding is deferred
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// to the ModRegRM byte.
|
2021-01-03 00:29:43 +00:00
|
|
|
|
instr_ = *source;
|
2021-01-04 01:08:13 +00:00
|
|
|
|
++source;
|
|
|
|
|
++consumed_;
|
|
|
|
|
|
2021-01-03 00:29:43 +00:00
|
|
|
|
switch(instr_) {
|
2021-01-04 01:08:13 +00:00
|
|
|
|
default: {
|
|
|
|
|
const Instruction instruction(consumed_);
|
2021-01-03 22:28:29 +00:00
|
|
|
|
reset_parsing();
|
2021-01-04 01:08:13 +00:00
|
|
|
|
return instruction;
|
|
|
|
|
}
|
2021-01-03 22:28:29 +00:00
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
#define PartialBlock(start, operation) \
|
|
|
|
|
MapMemRegReg(start + 0x00, operation, MemReg_Reg, 1); \
|
|
|
|
|
MapMemRegReg(start + 0x01, operation, MemReg_Reg, 2); \
|
|
|
|
|
MapMemRegReg(start + 0x02, operation, Reg_MemReg, 1); \
|
|
|
|
|
MapMemRegReg(start + 0x03, operation, Reg_MemReg, 2); \
|
|
|
|
|
MapRegData(start + 0x04, operation, AL, 1); \
|
|
|
|
|
MapRegData(start + 0x05, operation, AX, 2);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x00, ADD);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x06, PUSH, ES, None, 2);
|
|
|
|
|
MapComplete(0x07, POP, ES, None, 2);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x08, OR);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x0e, PUSH, CS, None, 2);
|
|
|
|
|
// 0x0f: not used.
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x10, ADC);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x16, PUSH, SS, None, 2);
|
|
|
|
|
MapComplete(0x17, POP, SS, None, 2);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x18, SBB);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x1e, PUSH, DS, None, 2);
|
|
|
|
|
MapComplete(0x1f, POP, DS, None, 2);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x20, AND);
|
|
|
|
|
case 0x26: segment_override_ = Source::ES; break;
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x27, DAA, None, None, 1);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x28, SUB);
|
|
|
|
|
case 0x2e: segment_override_ = Source::CS; break;
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x2f, DAS, None, None, 1);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x30, XOR);
|
|
|
|
|
case 0x36: segment_override_ = Source::SS; break;
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x37, AAA, None, None, 1);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
PartialBlock(0x38, CMP);
|
|
|
|
|
case 0x3e: segment_override_ = Source::DS; break;
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0x3f, AAS, None, None, 1);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
#undef PartialBlock
|
|
|
|
|
|
|
|
|
|
#define RegisterBlock(start, operation) \
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(start + 0x00, operation, AX, AX, 2); \
|
|
|
|
|
MapComplete(start + 0x01, operation, CX, CX, 2); \
|
|
|
|
|
MapComplete(start + 0x02, operation, DX, DX, 2); \
|
|
|
|
|
MapComplete(start + 0x03, operation, BX, BX, 2); \
|
|
|
|
|
MapComplete(start + 0x04, operation, SP, SP, 2); \
|
|
|
|
|
MapComplete(start + 0x05, operation, BP, BP, 2); \
|
|
|
|
|
MapComplete(start + 0x06, operation, SI, SI, 2); \
|
|
|
|
|
MapComplete(start + 0x07, operation, DI, DI, 2); \
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
|
|
|
|
RegisterBlock(0x40, INC);
|
|
|
|
|
RegisterBlock(0x48, DEC);
|
|
|
|
|
RegisterBlock(0x50, PUSH);
|
|
|
|
|
RegisterBlock(0x58, POP);
|
|
|
|
|
|
|
|
|
|
#undef RegisterBlock
|
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// 0x60–0x6f: not used.
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
2021-01-03 02:11:19 +00:00
|
|
|
|
MapJump(0x70, JO);
|
|
|
|
|
MapJump(0x71, JNO);
|
|
|
|
|
MapJump(0x72, JB);
|
|
|
|
|
MapJump(0x73, JNB);
|
|
|
|
|
MapJump(0x74, JE);
|
|
|
|
|
MapJump(0x75, JNE);
|
|
|
|
|
MapJump(0x76, JBE);
|
|
|
|
|
MapJump(0x77, JNBE);
|
|
|
|
|
MapJump(0x78, JS);
|
|
|
|
|
MapJump(0x79, JNS);
|
|
|
|
|
MapJump(0x7a, JP);
|
|
|
|
|
MapJump(0x7b, JNP);
|
|
|
|
|
MapJump(0x7c, JL);
|
|
|
|
|
MapJump(0x7d, JNL);
|
|
|
|
|
MapJump(0x7e, JLE);
|
|
|
|
|
MapJump(0x7f, JNLE);
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
2021-01-03 00:29:43 +00:00
|
|
|
|
// TODO:
|
|
|
|
|
//
|
|
|
|
|
// 0x80, 0x81, 0x82, 0x83, which all require more
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// input, from the ModRegRM byte.
|
|
|
|
|
|
|
|
|
|
MapMemRegReg(0x84, TEST, MemReg_Reg, 1);
|
|
|
|
|
MapMemRegReg(0x85, TEST, MemReg_Reg, 2);
|
|
|
|
|
MapMemRegReg(0x86, XCHG, Reg_MemReg, 1);
|
|
|
|
|
MapMemRegReg(0x87, XCHG, Reg_MemReg, 2);
|
|
|
|
|
MapMemRegReg(0x88, MOV, MemReg_Reg, 1);
|
|
|
|
|
MapMemRegReg(0x89, MOV, MemReg_Reg, 2);
|
|
|
|
|
MapMemRegReg(0x8a, MOV, Reg_MemReg, 1);
|
|
|
|
|
MapMemRegReg(0x8b, MOV, Reg_MemReg, 2);
|
|
|
|
|
// 0x8c: not used.
|
|
|
|
|
MapMemRegReg(0x8d, LEA, Reg_MemReg, 2);
|
|
|
|
|
// MapMemRegReg(0x8e, MOV, SegReg_MemReg, 1); // TODO: SegReg_MemReg
|
|
|
|
|
|
|
|
|
|
// TODO: 0x8f, which requires further selection from the ModRegRM byte.
|
|
|
|
|
|
|
|
|
|
MapComplete(0x90, NOP, None, None, 0); // Or XCHG AX, AX?
|
|
|
|
|
MapComplete(0x91, XCHG, AX, CX, 2);
|
|
|
|
|
MapComplete(0x92, XCHG, AX, DX, 2);
|
|
|
|
|
MapComplete(0x93, XCHG, AX, BX, 2);
|
|
|
|
|
MapComplete(0x94, XCHG, AX, SP, 2);
|
|
|
|
|
MapComplete(0x95, XCHG, AX, BP, 2);
|
|
|
|
|
MapComplete(0x96, XCHG, AX, SI, 2);
|
|
|
|
|
MapComplete(0x97, XCHG, AX, DI, 2);
|
|
|
|
|
|
|
|
|
|
MapComplete(0x98, CBW, None, None, 1);
|
|
|
|
|
MapComplete(0x99, CWD, None, None, 2);
|
|
|
|
|
MapFar(0x9a, CALL);
|
|
|
|
|
MapComplete(0x9b, WAIT, None, None, 0);
|
|
|
|
|
MapComplete(0x9c, PUSHF, None, None, 2);
|
|
|
|
|
MapComplete(0x9d, POPF, None, None, 2);
|
|
|
|
|
MapComplete(0x9e, SAHF, None, None, 1);
|
|
|
|
|
MapComplete(0x9f, LAHF, None, None, 1);
|
|
|
|
|
|
|
|
|
|
MapRegAddr(0xa0, MOV, AL, 1, 1); MapRegAddr(0xa1, MOV, AX, 2, 2);
|
|
|
|
|
MapAddrReg(0xa2, MOV, AL, 1, 1); MapAddrReg(0xa3, MOV, AX, 2, 2);
|
|
|
|
|
|
|
|
|
|
MapComplete(0xa4, MOVS, None, None, 1);
|
|
|
|
|
MapComplete(0xa5, MOVS, None, None, 2);
|
|
|
|
|
MapComplete(0xa6, CMPS, None, None, 1);
|
|
|
|
|
MapComplete(0xa7, CMPS, None, None, 2);
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapRegData(0xa8, TEST, AL, 1);
|
|
|
|
|
MapRegData(0xa9, TEST, AX, 2);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0xaa, STOS, None, None, 1);
|
|
|
|
|
MapComplete(0xab, STOS, None, None, 2);
|
|
|
|
|
MapComplete(0xac, LODS, None, None, 1);
|
|
|
|
|
MapComplete(0xad, LODS, None, None, 2);
|
|
|
|
|
MapComplete(0xae, SCAS, None, None, 1);
|
|
|
|
|
MapComplete(0xaf, SCAS, None, None, 2);
|
|
|
|
|
|
|
|
|
|
MapRegData(0xb0, MOV, AL, 1); MapRegData(0xb1, MOV, CL, 1);
|
|
|
|
|
MapRegData(0xb2, MOV, DL, 1); MapRegData(0xb3, MOV, BL, 1);
|
|
|
|
|
MapRegData(0xb4, MOV, AH, 1); MapRegData(0xb5, MOV, CH, 1);
|
|
|
|
|
MapRegData(0xb6, MOV, DH, 1); MapRegData(0xb7, MOV, BH, 1);
|
|
|
|
|
MapRegData(0xb8, MOV, AX, 2); MapRegData(0xb9, MOV, CX, 2);
|
|
|
|
|
MapRegData(0xba, MOV, DX, 2); MapRegData(0xbb, MOV, BX, 2);
|
|
|
|
|
MapRegData(0xbc, MOV, SP, 2); MapRegData(0xbd, MOV, BP, 2);
|
|
|
|
|
MapRegData(0xbe, MOV, SI, 2); MapRegData(0xbf, MOV, DI, 2);
|
|
|
|
|
|
|
|
|
|
MapRegData(0xc2, RETIntra, None, 2);
|
|
|
|
|
MapComplete(0xc3, RETIntra, None, None, 2);
|
|
|
|
|
MapMemRegReg(0xc4, LES, Reg_MemReg, 4);
|
|
|
|
|
MapMemRegReg(0xc5, LDS, Reg_MemReg, 4);
|
|
|
|
|
|
|
|
|
|
MapRegData(0xca, RETInter, None, 2);
|
|
|
|
|
MapComplete(0xcb, RETInter, None, None, 4);
|
|
|
|
|
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapComplete(0xcc, INT3, None, None, 0);
|
|
|
|
|
MapRegData(0xcd, INT, None, 1);
|
|
|
|
|
MapComplete(0xce, INTO, None, None, 0);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0xcf, IRET, None, None, 0);
|
|
|
|
|
|
|
|
|
|
MapRegData(0xd4, AAM, None, 1);
|
|
|
|
|
MapRegData(0xd5, AAD, None, 1);
|
|
|
|
|
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapComplete(0xd7, XLAT, None, None, 1);
|
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapMemRegReg(0xd8, ESC, MemReg_Reg, 0);
|
|
|
|
|
MapMemRegReg(0xd9, ESC, MemReg_Reg, 0);
|
|
|
|
|
MapMemRegReg(0xda, ESC, MemReg_Reg, 0);
|
|
|
|
|
MapMemRegReg(0xdb, ESC, MemReg_Reg, 0);
|
|
|
|
|
MapMemRegReg(0xdc, ESC, MemReg_Reg, 0);
|
|
|
|
|
MapMemRegReg(0xdd, ESC, MemReg_Reg, 0);
|
|
|
|
|
MapMemRegReg(0xde, ESC, MemReg_Reg, 0);
|
|
|
|
|
MapMemRegReg(0xdf, ESC, MemReg_Reg, 0);
|
|
|
|
|
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapJump(0xe0, LOOPNE); MapJump(0xe1, LOOPE);
|
|
|
|
|
MapJump(0xe2, LOOP); MapJump(0xe3, JPCX);
|
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapRegAddr(0xe4, IN, AL, 1, 1); MapRegAddr(0xe5, IN, AX, 2, 1);
|
|
|
|
|
MapAddrReg(0xe6, OUT, AL, 1, 1); MapAddrReg(0xe7, OUT, AX, 2, 1);
|
|
|
|
|
|
|
|
|
|
MapRegData(0xe8, CALL, None, 2);
|
|
|
|
|
MapRegData(0xe9, JMP, None, 2);
|
|
|
|
|
MapFar(0xea, JMP);
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapJump(0xeb, JMP);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
|
|
|
|
|
MapComplete(0xec, IN, DX, AL, 1); MapComplete(0xed, IN, DX, AX, 1);
|
|
|
|
|
MapComplete(0xee, OUT, AL, DX, 1); MapComplete(0xef, OUT, AX, DX, 1);
|
|
|
|
|
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapComplete(0xf4, HLT, None, None, 1);
|
|
|
|
|
MapComplete(0xf5, CMC, None, None, 1);
|
2021-01-06 02:34:35 +00:00
|
|
|
|
MapMemRegReg(0xf6, Invalid, MemRegTEST_to_IDIV, 1);
|
|
|
|
|
MapMemRegReg(0xf7, Invalid, MemRegTEST_to_IDIV, 2);
|
|
|
|
|
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapComplete(0xf8, CLC, None, None, 1);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0xf9, STC, None, None, 1);
|
2021-01-06 02:47:12 +00:00
|
|
|
|
MapComplete(0xfa, CLI, None, None, 1);
|
|
|
|
|
MapComplete(0xfb, STI, None, None, 1);
|
|
|
|
|
MapComplete(0xfc, CLD, None, None, 1);
|
2021-01-06 02:25:12 +00:00
|
|
|
|
MapComplete(0xfd, STD, None, None, 1);
|
2021-01-04 01:08:13 +00:00
|
|
|
|
|
2021-01-06 02:47:12 +00:00
|
|
|
|
/*
|
|
|
|
|
Unimplemented (but should be):
|
|
|
|
|
|
|
|
|
|
0x8e, 0x8f,
|
|
|
|
|
0xc6, 0xc7,
|
|
|
|
|
0xd0, 0xd1, 0xd2, 0xd3,
|
|
|
|
|
0xfe, 0xff
|
|
|
|
|
|
|
|
|
|
[and consider which others are unused but seem to be
|
|
|
|
|
known to consume a second byte?]
|
|
|
|
|
*/
|
|
|
|
|
|
2021-01-03 02:11:19 +00:00
|
|
|
|
// Other prefix bytes.
|
|
|
|
|
case 0xf0: lock_ = true; break;
|
|
|
|
|
case 0xf2: repetition_ = Repetition::RepNE; break;
|
|
|
|
|
case 0xf3: repetition_ = Repetition::RepE; break;
|
2021-01-03 00:16:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef MapInstr
|
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// MARK: - ModRegRM byte, if any.
|
|
|
|
|
|
|
|
|
|
if(phase_ == Phase::ModRegRM && source != end) {
|
2021-01-03 02:11:19 +00:00
|
|
|
|
const uint8_t mod = *source >> 6; // i.e. mode.
|
|
|
|
|
const uint8_t reg = (*source >> 3) & 7; // i.e. register.
|
|
|
|
|
const uint8_t rm = *source & 7; // i.e. register/memory.
|
2021-01-06 02:25:12 +00:00
|
|
|
|
++source;
|
|
|
|
|
++consumed_;
|
2021-01-03 02:11:19 +00:00
|
|
|
|
|
2021-01-06 02:34:35 +00:00
|
|
|
|
Source memreg;
|
|
|
|
|
constexpr Source reg_table[3][8] = {
|
|
|
|
|
{},
|
|
|
|
|
{
|
|
|
|
|
Source::AL, Source::CL, Source::DL, Source::BL,
|
|
|
|
|
Source::AH, Source::CH, Source::DH, Source::BH,
|
|
|
|
|
}, {
|
|
|
|
|
Source::AX, Source::CX, Source::DX, Source::BX,
|
|
|
|
|
Source::SP, Source::BP, Source::SI, Source::DI,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
switch(mod) {
|
|
|
|
|
case 0: {
|
|
|
|
|
constexpr Source rm_table[8] = {
|
|
|
|
|
Source::IndBXPlusSI, Source::IndBXPlusDI,
|
|
|
|
|
Source::IndBPPlusSI, Source::IndBPPlusDI,
|
|
|
|
|
Source::IndSI, Source::IndDI,
|
|
|
|
|
Source::DirectAddress, Source::IndBX,
|
2021-01-03 02:11:19 +00:00
|
|
|
|
};
|
2021-01-06 02:34:35 +00:00
|
|
|
|
memreg = rm_table[rm];
|
|
|
|
|
} break;
|
2021-01-03 02:11:19 +00:00
|
|
|
|
|
2021-01-06 02:34:35 +00:00
|
|
|
|
default: {
|
|
|
|
|
constexpr Source rm_table[8] = {
|
|
|
|
|
Source::IndBXPlusSI, Source::IndBXPlusDI,
|
|
|
|
|
Source::IndBPPlusSI, Source::IndBPPlusDI,
|
|
|
|
|
Source::IndSI, Source::IndDI,
|
|
|
|
|
Source::IndBP, Source::IndBX,
|
|
|
|
|
};
|
|
|
|
|
memreg = rm_table[rm];
|
2021-01-03 02:11:19 +00:00
|
|
|
|
|
2021-01-06 02:34:35 +00:00
|
|
|
|
displacement_size_ = 1 + (mod == 2);
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
// Other operand is just a register.
|
|
|
|
|
case 3:
|
|
|
|
|
memreg = reg_table[operation_size_][rm];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(modregrm_format_) {
|
|
|
|
|
case ModRegRMFormat::Reg_MemReg:
|
|
|
|
|
case ModRegRMFormat::MemReg_Reg: {
|
2021-01-06 02:25:12 +00:00
|
|
|
|
if(modregrm_format_ == ModRegRMFormat::Reg_MemReg) {
|
|
|
|
|
source_ = memreg;
|
|
|
|
|
destination_ = reg_table[operation_size_][reg];
|
|
|
|
|
} else {
|
|
|
|
|
source_ = reg_table[operation_size_][reg];
|
|
|
|
|
destination_ = memreg;
|
|
|
|
|
}
|
2021-01-03 02:11:19 +00:00
|
|
|
|
} break;
|
|
|
|
|
|
2021-01-06 02:34:35 +00:00
|
|
|
|
case ModRegRMFormat::MemRegTEST_to_IDIV:
|
|
|
|
|
source_ = destination_ = memreg;
|
|
|
|
|
|
|
|
|
|
switch(reg) {
|
|
|
|
|
default:
|
|
|
|
|
reset_parsing();
|
|
|
|
|
return Instruction();
|
|
|
|
|
|
|
|
|
|
case 0: operation_ = Operation::TEST; break;
|
|
|
|
|
case 2: operation_ = Operation::NOT; break;
|
|
|
|
|
case 3: operation_ = Operation::NEG; break;
|
|
|
|
|
case 4: operation_ = Operation::MUL; break;
|
|
|
|
|
case 5: operation_ = Operation::IMUL; break;
|
|
|
|
|
case 6: operation_ = Operation::DIV; break;
|
|
|
|
|
case 7: operation_ = Operation::IDIV; break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-01-03 02:11:19 +00:00
|
|
|
|
default: assert(false);
|
|
|
|
|
}
|
2021-01-06 02:34:35 +00:00
|
|
|
|
|
|
|
|
|
phase_ = Phase::AwaitingDisplacementOrOperand;
|
2021-01-03 02:11:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// MARK: - Displacement and operand.
|
|
|
|
|
|
|
|
|
|
if(phase_ == Phase::AwaitingDisplacementOrOperand && source != end) {
|
2021-01-03 02:11:19 +00:00
|
|
|
|
// TODO: calculate number of expected operands.
|
2021-01-06 02:25:12 +00:00
|
|
|
|
const int required_bytes = displacement_size_ + operand_size_;
|
2021-01-03 22:03:50 +00:00
|
|
|
|
|
|
|
|
|
const int outstanding_bytes = required_bytes - operand_bytes_;
|
|
|
|
|
const int bytes_to_consume = std::min(int(end - source), outstanding_bytes);
|
|
|
|
|
source += bytes_to_consume;
|
|
|
|
|
consumed_ += bytes_to_consume;
|
|
|
|
|
operand_bytes_ += bytes_to_consume;
|
|
|
|
|
if(bytes_to_consume == outstanding_bytes) {
|
|
|
|
|
phase_ = Phase::ReadyToPost;
|
|
|
|
|
} else {
|
|
|
|
|
// Provide a genuine measure of further bytes required.
|
|
|
|
|
return Instruction(-(outstanding_bytes - bytes_to_consume));
|
|
|
|
|
}
|
2021-01-03 02:11:19 +00:00
|
|
|
|
}
|
2021-01-03 00:16:07 +00:00
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// MARK: - Check for completion.
|
2021-01-03 22:28:29 +00:00
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
if(phase_ == Phase::ReadyToPost) {
|
|
|
|
|
Instruction result(operation_, Size(operation_size_), source_, destination_, consumed_);
|
2021-01-03 22:28:29 +00:00
|
|
|
|
reset_parsing();
|
2021-01-03 22:03:50 +00:00
|
|
|
|
phase_ = Phase::Instruction;
|
|
|
|
|
return result;
|
2021-01-03 00:16:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-01-06 02:25:12 +00:00
|
|
|
|
// i.e. not done yet.
|
2021-01-03 00:16:07 +00:00
|
|
|
|
return Instruction();
|
|
|
|
|
}
|