mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-13 00:25:26 +00:00
Does the easier part of the easier half of 8086 decoding.
This commit is contained in:
@@ -183,6 +183,8 @@
|
|||||||
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */; };
|
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */; };
|
||||||
4B3BA0D11D318B44005DD7A7 /* TestMachine6502.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */; };
|
4B3BA0D11D318B44005DD7A7 /* TestMachine6502.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */; };
|
||||||
4B3BF5B01F146265005B6C36 /* CSW.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BF5AE1F146264005B6C36 /* CSW.cpp */; };
|
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 */; };
|
4B3FCC40201EC24200960631 /* MultiMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FCC3F201EC24200960631 /* MultiMachine.cpp */; };
|
||||||
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */; };
|
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */; };
|
||||||
4B448E811F1C45A00009ABD6 /* TZX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B448E7F1F1C45A00009ABD6 /* TZX.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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;
|
path = Bridges;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4B3F76AB25A0196100178AEC /* x86 */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4B3F76AC25A0196100178AEC /* x86.hpp */,
|
||||||
|
4B3F76AD25A0196100178AEC /* x86.cpp */,
|
||||||
|
);
|
||||||
|
path = x86;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
4B3FCC3D201EC24200960631 /* MultiMachine */ = {
|
4B3FCC3D201EC24200960631 /* MultiMachine */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -3892,6 +3905,7 @@
|
|||||||
children = (
|
children = (
|
||||||
4B3F769E259FCE0F00178AEC /* README.md */,
|
4B3F769E259FCE0F00178AEC /* README.md */,
|
||||||
4BDDBBD4259D757800CEFF58 /* PowerPC */,
|
4BDDBBD4259D757800CEFF58 /* PowerPC */,
|
||||||
|
4B3F76AB25A0196100178AEC /* x86 */,
|
||||||
);
|
);
|
||||||
path = Decoders;
|
path = Decoders;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -4666,6 +4680,7 @@
|
|||||||
4B0F94FF208C1A1600FE41D9 /* NIB.cpp in Sources */,
|
4B0F94FF208C1A1600FE41D9 /* NIB.cpp in Sources */,
|
||||||
4B0E04EB1FC9E78800F43484 /* CAS.cpp in Sources */,
|
4B0E04EB1FC9E78800F43484 /* CAS.cpp in Sources */,
|
||||||
4BB0A65D2045009000FB3688 /* ColecoVision.cpp in Sources */,
|
4BB0A65D2045009000FB3688 /* ColecoVision.cpp in Sources */,
|
||||||
|
4B3F76AF25A0196100178AEC /* x86.cpp in Sources */,
|
||||||
4BB0A65C2044FD3000FB3688 /* SN76489.cpp in Sources */,
|
4BB0A65C2044FD3000FB3688 /* SN76489.cpp in Sources */,
|
||||||
4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */,
|
4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */,
|
||||||
4B055AB91FAE86170060FFFF /* Acorn.cpp in Sources */,
|
4B055AB91FAE86170060FFFF /* Acorn.cpp in Sources */,
|
||||||
@@ -4738,6 +4753,7 @@
|
|||||||
4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */,
|
4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */,
|
||||||
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */,
|
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */,
|
||||||
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */,
|
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */,
|
||||||
|
4B3F76AE25A0196100178AEC /* x86.cpp in Sources */,
|
||||||
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */,
|
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */,
|
||||||
4BBFFEE61F7B27F1005F3FEB /* TrackSerialiser.cpp in Sources */,
|
4BBFFEE61F7B27F1005F3FEB /* TrackSerialiser.cpp in Sources */,
|
||||||
4BAE49582032881E004BE78E /* CSZX8081.mm in Sources */,
|
4BAE49582032881E004BE78E /* CSZX8081.mm in Sources */,
|
||||||
|
126
Processors/Decoders/x86/x86.cpp
Normal file
126
Processors/Decoders/x86/x86.cpp
Normal 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
|
||||||
|
|
||||||
|
/* 0x60–0x6f: 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();
|
||||||
|
}
|
127
Processors/Decoders/x86/x86.hpp
Normal file
127
Processors/Decoders/x86/x86.hpp
Normal 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 */
|
Reference in New Issue
Block a user