1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +00:00

Does the easier part of the easier half of 8086 decoding.

This commit is contained in:
Thomas Harte 2021-01-02 19:16:07 -05:00
parent a41be61f99
commit dc9d370952
3 changed files with 269 additions and 0 deletions

View File

@ -183,6 +183,8 @@
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */; };
4B3BA0D11D318B44005DD7A7 /* TestMachine6502.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */; };
4B3BF5B01F146265005B6C36 /* CSW.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BF5AE1F146264005B6C36 /* CSW.cpp */; };
4B3F76AE25A0196100178AEC /* x86.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F76AD25A0196100178AEC /* x86.cpp */; };
4B3F76AF25A0196100178AEC /* x86.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F76AD25A0196100178AEC /* x86.cpp */; };
4B3FCC40201EC24200960631 /* MultiMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FCC3F201EC24200960631 /* MultiMachine.cpp */; };
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */; };
4B448E811F1C45A00009ABD6 /* TZX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B448E7F1F1C45A00009ABD6 /* TZX.cpp */; };
@ -1077,6 +1079,8 @@
4B3BF5AE1F146264005B6C36 /* CSW.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSW.cpp; sourceTree = "<group>"; };
4B3BF5AF1F146264005B6C36 /* CSW.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CSW.hpp; sourceTree = "<group>"; };
4B3F769E259FCE0F00178AEC /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
4B3F76AC25A0196100178AEC /* x86.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = x86.hpp; sourceTree = "<group>"; };
4B3F76AD25A0196100178AEC /* x86.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x86.cpp; sourceTree = "<group>"; };
4B3FCC3E201EC24200960631 /* MultiMachine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MultiMachine.hpp; sourceTree = "<group>"; };
4B3FCC3F201EC24200960631 /* MultiMachine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MultiMachine.cpp; sourceTree = "<group>"; };
4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CPM.cpp; path = Parsers/CPM.cpp; sourceTree = "<group>"; };
@ -2324,6 +2328,15 @@
path = Bridges;
sourceTree = "<group>";
};
4B3F76AB25A0196100178AEC /* x86 */ = {
isa = PBXGroup;
children = (
4B3F76AC25A0196100178AEC /* x86.hpp */,
4B3F76AD25A0196100178AEC /* x86.cpp */,
);
path = x86;
sourceTree = "<group>";
};
4B3FCC3D201EC24200960631 /* MultiMachine */ = {
isa = PBXGroup;
children = (
@ -3892,6 +3905,7 @@
children = (
4B3F769E259FCE0F00178AEC /* README.md */,
4BDDBBD4259D757800CEFF58 /* PowerPC */,
4B3F76AB25A0196100178AEC /* x86 */,
);
path = Decoders;
sourceTree = "<group>";
@ -4666,6 +4680,7 @@
4B0F94FF208C1A1600FE41D9 /* NIB.cpp in Sources */,
4B0E04EB1FC9E78800F43484 /* CAS.cpp in Sources */,
4BB0A65D2045009000FB3688 /* ColecoVision.cpp in Sources */,
4B3F76AF25A0196100178AEC /* x86.cpp in Sources */,
4BB0A65C2044FD3000FB3688 /* SN76489.cpp in Sources */,
4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */,
4B055AB91FAE86170060FFFF /* Acorn.cpp in Sources */,
@ -4738,6 +4753,7 @@
4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */,
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */,
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */,
4B3F76AE25A0196100178AEC /* x86.cpp in Sources */,
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */,
4BBFFEE61F7B27F1005F3FEB /* TrackSerialiser.cpp in Sources */,
4BAE49582032881E004BE78E /* CSZX8081.mm in Sources */,

View File

@ -0,0 +1,126 @@
//
// x86.cpp
// Clock Signal
//
// Created by Thomas Harte on 1/1/21.
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#include "x86.hpp"
using namespace CPU::Decoder::x86;
Instruction Decoder::decode(uint8_t *source, size_t length) {
uint8_t *const limit = source + length;
#define MapPartial(value, op, sz, fmt, phs) \
case value: \
operation_ = Operation::op; \
operand_size_ = Size::sz; \
format_ = Format::fmt; \
phase_ = Phase::phs; \
break;
#define MapComplete(value, op, sz, src, dest) \
case value: \
operation_ = Operation::op; \
operand_size_ = Size::sz; \
source_ = Source::src; \
destination_ = Source::dest; \
phase_ = Phase::ReadyToPost; \
break;
while(phase_ == Phase::Instruction && source != limit) {
switch(*source) {
#define PartialBlock(start, operation) \
MapPartial(start + 0x00, operation, Byte, MemReg_Reg, ModRM); \
MapPartial(start + 0x01, operation, Word, MemReg_Reg, ModRM); \
MapPartial(start + 0x02, operation, Byte, Reg_MemReg, ModRM); \
MapPartial(start + 0x03, operation, Word, Reg_MemReg, ModRM); \
MapPartial(start + 0x04, operation, Byte, Ac_Data, AwaitingOperands); \
MapPartial(start + 0x05, operation, Word, Ac_Data, AwaitingOperands);
PartialBlock(0x00, ADD);
MapComplete(0x06, PUSH, Word, ES, None);
MapComplete(0x07, POP, Word, ES, None);
PartialBlock(0x08, OR);
MapComplete(0x0e, PUSH, Word, CS, None);
/* 0x0f: not used. */
PartialBlock(0x10, ADC);
MapComplete(0x16, PUSH, Word, SS, None);
MapComplete(0x17, POP, Word, SS, None);
PartialBlock(0x18, SBB);
MapComplete(0x1e, PUSH, Word, DS, None);
MapComplete(0x1f, POP, Word, DS, None);
PartialBlock(0x20, AND);
case 0x26: segment_override_ = Source::ES; break;
MapComplete(0x27, DAA, Implied, None, None);
PartialBlock(0x28, SUB);
case 0x2e: segment_override_ = Source::CS; break;
MapComplete(0x2f, DAS, Implied, None, None);
PartialBlock(0x30, XOR);
case 0x36: segment_override_ = Source::SS; break;
MapComplete(0x37, AAA, Implied, None, None);
PartialBlock(0x38, CMP);
case 0x3e: segment_override_ = Source::DS; break;
MapComplete(0x3f, AAS, Implied, None, None);
#undef PartialBlock
#define RegisterBlock(start, operation) \
MapComplete(start + 0x00, operation, Word, AX, AX); \
MapComplete(start + 0x01, operation, Word, CX, CX); \
MapComplete(start + 0x02, operation, Word, DX, DX); \
MapComplete(start + 0x03, operation, Word, BX, BX); \
MapComplete(start + 0x04, operation, Word, SP, SP); \
MapComplete(start + 0x05, operation, Word, BP, BP); \
MapComplete(start + 0x06, operation, Word, SI, SI); \
MapComplete(start + 0x07, operation, Word, DI, DI); \
RegisterBlock(0x40, INC);
RegisterBlock(0x48, DEC);
RegisterBlock(0x50, PUSH);
RegisterBlock(0x58, POP);
#undef RegisterBlock
/* 0x600x6f: not used. */
MapPartial(0x70, JO, Byte, Disp, AwaitingOperands);
MapPartial(0x71, JNO, Byte, Disp, AwaitingOperands);
MapPartial(0x72, JB, Byte, Disp, AwaitingOperands);
MapPartial(0x73, JNB, Byte, Disp, AwaitingOperands);
MapPartial(0x74, JE, Byte, Disp, AwaitingOperands);
MapPartial(0x75, JNE, Byte, Disp, AwaitingOperands);
MapPartial(0x76, JBE, Byte, Disp, AwaitingOperands);
MapPartial(0x77, JNBE, Byte, Disp, AwaitingOperands);
MapPartial(0x78, JS, Byte, Disp, AwaitingOperands);
MapPartial(0x79, JNS, Byte, Disp, AwaitingOperands);
MapPartial(0x7a, JP, Byte, Disp, AwaitingOperands);
MapPartial(0x7b, JNP, Byte, Disp, AwaitingOperands);
MapPartial(0x7c, JL, Byte, Disp, AwaitingOperands);
MapPartial(0x7d, JNL, Byte, Disp, AwaitingOperands);
MapPartial(0x7e, JLE, Byte, Disp, AwaitingOperands);
MapPartial(0x7f, JNLE, Byte, Disp, AwaitingOperands);
}
++source;
++consumed_;
}
#undef MapInstr
if(phase_ == Phase::ReadyToPost) {
// TODO: construct actual Instruction.
}
return Instruction();
}

View File

@ -0,0 +1,127 @@
//
// x86.hpp
// Clock Signal
//
// Created by Thomas Harte on 1/1/21.
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#ifndef x86_hpp
#define x86_hpp
#include <cstddef>
#include <cstdint>
namespace CPU {
namespace Decoder {
namespace x86 {
enum class Model {
i8086,
};
enum class Operation: uint8_t {
Invalid,
AAA, AAD, AAM, AAS, ADC, ADD, AND, CALL, CBW, CLC, CLD, CLI, CMC,
CMP, CMPS, CWD, DAA, DAS, DEC, DIV, ESC, HLT, IDIV, IMUL, IN,
INC, INT, INTO, IRET,
JO, JNO,
JB, JNB,
JE, JNE,
JBE, JNBE,
JS, JNS,
JP, JNP,
JL, JNL,
JLE, JNLE,
JMP, JCXZ,
LAHF, LDS, LEA,
LODS, LOOPE, LOOPNE, MOV, MOVS, MUL, NEG, NOP, NOT, OR, OUT,
POP, POPF, PUSH, PUSHF, RCL, RCR, REP, RET, ROL, ROR, SAHF,
SAR, SBB, SCAS, SHL, SHR, STC, STD, STI, STOS, SUB, TEST,
WAIT, XCHG, XLAT, XOR
};
enum class Size: uint8_t {
Implied = 0,
Byte = 1,
Word = 2,
};
enum class Source: uint8_t {
None,
AL, AH, AX,
BL, BH, BX,
CL, CH, CX,
DL, DH, DX,
CS, DS, ES, SS,
SI, DI,
BP, SP,
Memory, Immediate
};
class Instruction {
public:
const Operation operation = Operation::Invalid;
const Size operand_size = Size::Byte;
const Source source = Source::AL;
const Source destination = Source::AL;
int size() const {
return size_;
}
private:
int size_ = 0;
};
/*!
Implements Intel x86 instruction decoding.
This is an experimental implementation; it has not yet undergone significant testing.
*/
struct Decoder {
public:
Decoder(Model model);
/*!
@returns an @c Instruction with a positive size to indicate successful decoding; a
negative size specifies the number of further bytes required fully to decode, and
a zero size indicates that further bytes are required but the decoder does not yet
know exactly how many.
*/
Instruction decode(uint8_t *source, size_t length);
private:
enum class Phase {
Instruction,
ModRM,
AwaitingOperands,
ReadyToPost
} phase_ = Phase::Instruction;
enum class Format: uint8_t {
MemReg_Reg,
Reg_MemReg,
Ac_Data,
MemReg_Data,
Disp
} format_ = Format::MemReg_Reg;
int consumed_ = 0;
Operation operation_ = Operation::Invalid;
Size operand_size_ = Size::Implied;
Source source_ = Source::None;
Source destination_ = Source::None;
Source segment_override_ = Source::None;
};
}
}
}
#endif /* x86_hpp */