311 lines
14 KiB
Odin
311 lines
14 KiB
Odin
package sim_8086
|
|
|
|
Op :: enum {
|
|
UNKNOWN,
|
|
TBD1,
|
|
TBD2,
|
|
TBD3,
|
|
TBD4,
|
|
TBD5,
|
|
TBD6,
|
|
MOV,
|
|
PUSH,
|
|
POP,
|
|
XCHG,
|
|
IN,
|
|
OUT,
|
|
XLAT,
|
|
LEA,
|
|
LDS,
|
|
LES,
|
|
LAHF,
|
|
SAHF,
|
|
PUSHF,
|
|
POPF,
|
|
ADD,
|
|
ADC,
|
|
INC,
|
|
AAA,
|
|
DAA,
|
|
SUB,
|
|
SBB,
|
|
DEC,
|
|
NEG,
|
|
MUL,
|
|
IMUL,
|
|
CMP,
|
|
AAS,
|
|
DAS,
|
|
AAM,
|
|
DIV,
|
|
IDIV,
|
|
AAD,
|
|
CBW,
|
|
CWD,
|
|
ROL,
|
|
ROR,
|
|
RCL,
|
|
RCR,
|
|
SHL,
|
|
SHR,
|
|
SAR,
|
|
NOT,
|
|
TEST,
|
|
OR,
|
|
AND,
|
|
XOR,
|
|
REP,
|
|
RET,
|
|
RETF,
|
|
INT,
|
|
INT3,
|
|
INTO,
|
|
IRET,
|
|
CLC,
|
|
CMC,
|
|
STC,
|
|
CLD,
|
|
STD,
|
|
CLI,
|
|
STI,
|
|
HLT,
|
|
WAIT,
|
|
ESC,
|
|
LOCK,
|
|
SEGMENT,
|
|
CALL,
|
|
JMP,
|
|
JNZ,
|
|
JNE,
|
|
JNGE,
|
|
JE,
|
|
JZ,
|
|
JL,
|
|
JLE,
|
|
JNG,
|
|
JB,
|
|
JNAE,
|
|
JP,
|
|
JPE,
|
|
JNA,
|
|
JBE,
|
|
JO,
|
|
JS,
|
|
JNL,
|
|
JGE,
|
|
JNLE,
|
|
JG,
|
|
JNB,
|
|
JAE,
|
|
JNBE,
|
|
JA,
|
|
JNP,
|
|
JPO,
|
|
JNO,
|
|
JNS,
|
|
LOOP,
|
|
LOOPZ,
|
|
LOOPNZ,
|
|
LOOPNE,
|
|
JCXZ,
|
|
}
|
|
|
|
// TODO: We should figure out another way of handling this case. The way we're doing it
|
|
// isn't that great; we return a string with the instruction name, but ideally we have all
|
|
// the instructions accounted for, because eventually we will need the final parsed
|
|
// instruction to contain all the information related to it
|
|
// test_inst := InstructionInfo {
|
|
// opname = .NOT, desc = "", mask = 0b11111110, encoding = 0b11110110,
|
|
// dst = .RegisterMemory, src = .Immediate, word_size = .LastBit
|
|
// }
|
|
test_inst := InstructionInfo {
|
|
opname = .TEST, desc = "", mask = 0b11111110, encoding = 0b11110110,
|
|
dst = .RegisterMemory, src = .Immediate, word_size = .LastBit
|
|
}
|
|
|
|
instructions := [?]InstructionInfo {
|
|
{ opname = .TBD1, desc = "Immediate to accumulator",
|
|
mask = 0b11000110, encoding = 0b00000100, check_second_encoding = true,
|
|
dst = .Accumulator, src = .Immediate,
|
|
word_size = .LastBit, },
|
|
{ opname = .TBD2, desc = "", check_second_encoding = true,
|
|
mask = 0b11111110, encoding = 0b11111110,
|
|
src = .RegisterMemory,
|
|
word_size = .LastBit, },
|
|
{ opname = .TBD3, desc = "", check_second_encoding = true,
|
|
mask = 0b11000100, encoding = 0b00000000,
|
|
dst = .RegisterMemory, src = .Register,
|
|
word_size = .LastBit, reg_info = .SecondByteMiddle3, has_flip = true },
|
|
{ opname = .TBD4, desc = "", check_second_encoding = true,
|
|
mask = 0b11111100, encoding = 0b10000000,
|
|
dst = .RegisterMemory, src = .Immediate,
|
|
word_size = .LastBit, has_sign_extension = true },
|
|
{ opname = .TBD5, desc = "", check_second_encoding = true,
|
|
mask = 0b11111110, encoding = 0b11110110,
|
|
// dst = .Immediate, src = .RegisterMemory, word_size = .LastBit, },
|
|
src = .RegisterMemory, word_size = .LastBit, },
|
|
{ opname = .TBD6, desc = "", check_second_encoding = true,
|
|
mask = 0b11111100, encoding = 0b11010000,
|
|
dst = .RegisterMemory, src = .ShiftRotate, word_size = .LastBit, },
|
|
{ opname = .MOV, desc = "Register/memory to/from register",
|
|
mask = 0b11111100, encoding = 0b10001000,
|
|
dst = .RegisterMemory, src = .Register,
|
|
word_size = .LastBit, reg_info = .SecondByteMiddle3, has_flip = true },
|
|
{ opname = .MOV, desc = "Immediate to register/memory",
|
|
mask = 0b11111110, encoding = 0b11000110,
|
|
dst = .RegisterMemory, src = .Immediate,
|
|
word_size = .LastBit, },
|
|
{ opname = .MOV, desc = "Immediate to register",
|
|
mask = 0b11110000, encoding = 0b10110000,
|
|
dst = .Register, src = .Immediate,
|
|
word_size = .FourthBit, reg_info = .FirstByteLast3 },
|
|
{ opname = .MOV, desc = "Memory to accumulator",
|
|
mask = 0b11111110, encoding = 0b10100000,
|
|
dst = .Accumulator, src = .DirectAddress,
|
|
word_size = .LastBit, },
|
|
{ opname = .MOV, desc = "Accumulator to memory",
|
|
mask = 0b11111110, encoding = 0b10100010,
|
|
dst = .DirectAddress, src = .Accumulator,
|
|
word_size = .LastBit, },
|
|
// NOTE: There's another instruction but it seems like it just flips, and while not specified
|
|
// it seems like it has an undocumented flip bit just like the others
|
|
{ opname = .MOV, desc = "Register/memory to segment register",
|
|
mask = 0b11111101, encoding = 0b10001100,
|
|
dst = .RegisterMemory, src = .SegmentRegister,
|
|
reg_info = .SecondByteMiddle3, word_size = .Always16, has_flip = true },
|
|
{ opname = .PUSH, desc = "", mask = 0b11111000, encoding = 0b01010000,
|
|
src = .Register, reg_info = .FirstByteLast3,
|
|
word_size = .Always16, },
|
|
{ opname = .PUSH, desc = "", mask = 0b11100111, encoding = 0b00000110,
|
|
src = .SegmentRegister, reg_info = .FirstByteMiddle3,
|
|
word_size = .Always16, },
|
|
{ opname = .POP, desc = "", mask = 0b11111111, encoding = 0b10001111,
|
|
src = .RegisterMemory, word_size = .Always16 },
|
|
{ opname = .POP, desc = "", mask = 0b11111000, encoding = 0b01011000,
|
|
src = .Register, reg_info = .FirstByteLast3,
|
|
word_size = .Always16, },
|
|
{ opname = .POP, desc = "", mask = 0b11100111, encoding = 0b00000111,
|
|
src = .SegmentRegister, reg_info = .FirstByteMiddle3,
|
|
word_size = .Always16, },
|
|
{ opname = .XCHG, desc = "", mask = 0b11111110, encoding = 0b10000110,
|
|
dst = .RegisterMemory, src = .Register,
|
|
reg_info = .SecondByteMiddle3, word_size = .LastBit, has_flip = true },
|
|
{ opname = .XCHG, desc = "", mask = 0b11111000, encoding = 0b10010000,
|
|
dst = .Accumulator, src = .Register,
|
|
reg_info = .FirstByteLast3, has_flip = true, word_size = .Always16 },
|
|
{ opname = .IN, desc = "", mask = 0b11111110, encoding = 0b11100100,
|
|
dst = .Accumulator, src = .ImmediateUnsigned },
|
|
{ opname = .IN, desc = "", mask = 0b11111110, encoding = 0b11101100,
|
|
dst = .Accumulator, src = .VariablePort,
|
|
word_size = .LastBit, },
|
|
{ opname = .OUT, desc = "", mask = 0b11111110, encoding = 0b11100110,
|
|
dst = .ImmediateUnsigned, src = .Accumulator,
|
|
word_size = .LastBit, },
|
|
{ opname = .OUT, desc = "", mask = 0b11111110, encoding = 0b11101110,
|
|
dst = .VariablePort, src = .Accumulator,
|
|
word_size = .LastBit, },
|
|
{ opname = .TEST, desc = "", mask = 0b11111110, encoding = 0b10101000,
|
|
dst = .Accumulator, src = .Immediate, word_size = .LastBit },
|
|
{ opname = .XLAT, desc = "", mask = 0b11111111, encoding = 0b11010111,},
|
|
{ opname = .LEA, desc = "", mask = 0b11111111, encoding = 0b10001101,
|
|
dst = .Register, src = .RegisterMemory,
|
|
reg_info = .SecondByteMiddle3, word_size = .Always16 },
|
|
{ opname = .LDS, desc = "", mask = 0b11111111, encoding = 0b11000101,
|
|
dst = .Register, src = .RegisterMemory,
|
|
reg_info = .SecondByteMiddle3, word_size = .Always16 },
|
|
{ opname = .LES, desc = "", mask = 0b11111111, encoding = 0b11000100,
|
|
dst = .Register, src = .RegisterMemory,
|
|
reg_info = .SecondByteMiddle3, word_size = .Always16 },
|
|
{ opname = .LAHF, desc = "", mask = 0b11111111, encoding = 0b10011111,},
|
|
{ opname = .SAHF, desc = "", mask = 0b11111111, encoding = 0b10011110,},
|
|
{ opname = .PUSHF, desc = "", mask = 0b11111111, encoding = 0b10011100,},
|
|
{ opname = .POPF, desc = "", mask = 0b11111111, encoding = 0b10011101,},
|
|
{ opname = .INC, desc = "", mask = 0b11111000, encoding = 0b01000000,
|
|
src = .Register, reg_info = .FirstByteLast3, word_size = .Always16 },
|
|
{ opname = .AAA, desc = "", mask = 0b11111111, encoding = 0b00110111,},
|
|
{ opname = .DAA, desc = "", mask = 0b11111111, encoding = 0b00100111,},
|
|
{ opname = .DEC, desc = "", mask = 0b11111000, encoding = 0b01001000,
|
|
src = .Register, reg_info = .FirstByteLast3, word_size = .Always16 },
|
|
{ opname = .AAS, desc = "", mask = 0b11111111, encoding = 0b00111111,},
|
|
{ opname = .DAS, desc = "", mask = 0b11111111, encoding = 0b00101111,},
|
|
{ opname = .AAM, desc = "", mask = 0b11111111, encoding = 0b11010100,},
|
|
{ opname = .AAD, desc = "", mask = 0b11111111, encoding = 0b11010101, consume_extra_bytes = 1 },
|
|
{ opname = .CBW, desc = "", mask = 0b11111111, encoding = 0b10011000,},
|
|
{ opname = .CWD, desc = "", mask = 0b11111111, encoding = 0b10011001,},
|
|
{ opname = .TEST, desc = "", mask = 0b11111100, encoding = 0b10000100,
|
|
dst = .RegisterMemory, src = .Register,
|
|
word_size = .LastBit, reg_info = .SecondByteMiddle3, has_flip = true },
|
|
{ opname = .REP, desc = "", mask = 0b11111110, encoding = 0b11110010, src = .Repeat },
|
|
{ opname = .RET, desc = "", mask = 0b11111111, encoding = 0b11000011,},
|
|
{ opname = .RET, src = .Immediate, word_size = .Always16,
|
|
desc = "", mask = 0b11111111, encoding = 0b11000010,},
|
|
{ opname = .RETF, desc = "", mask = 0b11111111, encoding = 0b11001011,},
|
|
{ opname = .RETF, desc = "", mask = 0b11111111, encoding = 0b11001010,
|
|
src = .Immediate, word_size = .Always16 },
|
|
{ opname = .INT, src = .Immediate, desc = "", mask = 0b11111111, encoding = 0b11001101,},
|
|
{ opname = .INT3, desc = "", mask = 0b11111111, encoding = 0b11001100,},
|
|
{ opname = .INTO, desc = "", mask = 0b11111111, encoding = 0b11001110,},
|
|
{ opname = .IRET, desc = "", mask = 0b11111111, encoding = 0b11001111,},
|
|
{ opname = .CLC, desc = "", mask = 0b11111111, encoding = 0b11111000,},
|
|
{ opname = .CMC, desc = "", mask = 0b11111111, encoding = 0b11110101,},
|
|
{ opname = .STC, desc = "", mask = 0b11111111, encoding = 0b11111001,},
|
|
{ opname = .CLD, desc = "", mask = 0b11111111, encoding = 0b11111100,},
|
|
{ opname = .STD, desc = "", mask = 0b11111111, encoding = 0b11111101,},
|
|
{ opname = .CLI, desc = "", mask = 0b11111111, encoding = 0b11111010,},
|
|
{ opname = .STI, desc = "", mask = 0b11111111, encoding = 0b11111011,},
|
|
{ opname = .HLT, desc = "", mask = 0b11111111, encoding = 0b11110100,},
|
|
{ opname = .WAIT, desc = "", mask = 0b11111111, encoding = 0b10011011,},
|
|
{ opname = .LOCK, desc = "", mask = 0b11111111, encoding = 0b11110000,},
|
|
{ opname = .SEGMENT, desc = "", mask = 0b11100111, encoding = 0b00100110,},
|
|
{ opname = .CALL, desc = "", mask = 0b11111111, encoding = 0b10011010, src = .Intersegment },
|
|
{ opname = .JMP, desc = "", mask = 0b11111111, encoding = 0b11101010, src = .Intersegment },
|
|
{ opname = .JMP, desc = "", mask = 0b11111111, encoding = 0b11101001, src = .DirectWithinSegment },
|
|
{ opname = .CALL, desc = "", mask = 0b11111111, encoding = 0b11101000, src = .DirectWithinSegment },
|
|
{ opname = .JE, mask = 0b11111111, encoding = 0b01110100, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JZ, mask = 0b11111111, encoding = 0b01110100, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JL, mask = 0b11111111, encoding = 0b01111100, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JNGE, mask = 0b11111111, encoding = 0b01111100, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JLE, mask = 0b11111111, encoding = 0b01111110, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JNG, mask = 0b11111111, encoding = 0b01111110, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JB, mask = 0b11111111, encoding = 0b01110010, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JNAE, mask = 0b11111111, encoding = 0b01110010, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JBE, mask = 0b11111111, encoding = 0b01110110, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JNA, mask = 0b11111111, encoding = 0b01110110, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JP, mask = 0b11111111, encoding = 0b01111010, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JPE, mask = 0b11111111, encoding = 0b01111010, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JO, mask = 0b11111111, encoding = 0b01110000, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JS, mask = 0b11111111, encoding = 0b01111000, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNE, mask = 0b11111111, encoding = 0b01110101, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JNZ, mask = 0b11111111, encoding = 0b01110101, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNL, mask = 0b11111111, encoding = 0b01111101, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JGE, mask = 0b11111111, encoding = 0b01111101, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNLE, mask = 0b11111111, encoding = 0b01111111, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JG, mask = 0b11111111, encoding = 0b01111111, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNB, mask = 0b11111111, encoding = 0b01110011, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JAE, mask = 0b11111111, encoding = 0b01110011, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNBE, mask = 0b11111111, encoding = 0b01110111, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JA, mask = 0b11111111, encoding = 0b01110111, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNP, mask = 0b11111111, encoding = 0b01111011, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JPO, mask = 0b11111111, encoding = 0b01111011, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNO, mask = 0b11111111, encoding = 0b01110001, src = .Jump, desc = "Jump on not zero", },
|
|
|
|
{ opname = .JNS, mask = 0b11111111, encoding = 0b01111001, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .LOOP, mask = 0b11111111, encoding = 0b11100010, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .LOOPZ, mask = 0b11111111, encoding = 0b11100001, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .LOOPNZ, mask = 0b11111111, encoding = 0b11100000, src = .Jump, desc = "Jump on not zero", },
|
|
{ opname = .JCXZ, mask = 0b11111111, encoding = 0b11100011, src = .Jump, desc = "Jump on not zero", },
|
|
}
|