2023-03-05 17:57:40 -08:00
|
|
|
#include "bloat.hpp"
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
// Octal formatting is used heavily throughout
|
|
|
|
// See: https://gist.github.com/seanjensengrey/f971c20d05d4d0efc0781f2f3c0353da
|
|
|
|
// (x86 is an octal machine)
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
namespace Op
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
ct u8 Mask = 00210;
|
|
|
|
ct u8 Mask_Low = 0b11110000;
|
|
|
|
ct u8 Mask_High = 0b00001111;
|
|
|
|
ct u8 Mask_Imme = 0b00111000;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
#define D_Opcodes \
|
2023-03-06 04:33:25 -08:00
|
|
|
D_Entry( mov_RM_R ) \
|
|
|
|
D_Entry( mov_Im_RM ) \
|
|
|
|
D_Entry( mov_Im_R ) \
|
|
|
|
D_Entry( mov_M_Acc ) \
|
|
|
|
D_Entry( mov_Acc_M ) \
|
|
|
|
D_Entry( mov_RM_SR ) \
|
|
|
|
D_Entry( mov_SR_RM ) \
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
enum Code : u8
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
mov_RM_R = 0b10001000,
|
|
|
|
mov_Im_RM = 0b11001100,
|
|
|
|
mov_Im_R = 0b10110000,
|
|
|
|
mov_M_Acc = 0b10100000,
|
|
|
|
mov_Acc_M = 0b10100010,
|
|
|
|
mov_RM_SR = 0b10001110,
|
|
|
|
mov_SR_RM = 0b10001100
|
2023-03-03 03:43:41 -08:00
|
|
|
};
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
char const* str( Code type )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
switch ( type )
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
#define D_Entry( Entry_ ) \
|
|
|
|
case Entry_: \
|
|
|
|
return ZPL_STRINGIFY(Entry_); \
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
D_Opcodes
|
|
|
|
#undef D_Entry
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return Msg_Invalid_Value;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
char const* meumonic( Code type )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
switch ( type )
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
case mov_RM_R :
|
|
|
|
case mov_Im_RM :
|
|
|
|
case mov_Im_R :
|
|
|
|
case mov_M_Acc :
|
|
|
|
case mov_Acc_M :
|
|
|
|
case mov_RM_SR :
|
|
|
|
case mov_SR_RM :
|
2023-03-03 03:43:41 -08:00
|
|
|
return "mov";
|
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return Msg_Invalid_Value;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
char const* intuitive( Code type )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
switch ( type )
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
case mov_RM_R :
|
|
|
|
case mov_Im_RM :
|
|
|
|
case mov_Im_R :
|
|
|
|
case mov_M_Acc :
|
|
|
|
case mov_Acc_M :
|
|
|
|
case mov_RM_SR :
|
|
|
|
case mov_SR_RM :
|
2023-03-03 03:43:41 -08:00
|
|
|
return "move";
|
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return Msg_Invalid_Value;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef D_Opcodes
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Field
|
|
|
|
{
|
2023-03-05 17:57:40 -08:00
|
|
|
inline
|
2023-03-06 04:33:25 -08:00
|
|
|
u8 offset_left_reg( u8 reg )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
return reg << 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://i.imgur.com/drsyYnM.png
|
2023-03-05 17:57:40 -08:00
|
|
|
enum Direction : u8
|
|
|
|
{
|
|
|
|
Mask_Dir = 0b00000010,
|
|
|
|
Dir_Src = 0b00,
|
|
|
|
Dir_Dest = 0b10,
|
|
|
|
};
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
inline
|
2023-03-05 17:57:40 -08:00
|
|
|
char const* str_direction( Direction direction )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
switch ( direction )
|
|
|
|
{
|
2023-03-05 17:57:40 -08:00
|
|
|
case Dir_Dest:
|
2023-03-03 03:43:41 -08:00
|
|
|
return "Destination";
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
case Dir_Src:
|
2023-03-03 03:43:41 -08:00
|
|
|
return "Source";
|
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return Msg_Invalid_Value;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// https://i.imgur.com/9Op8Lnd.png
|
2023-03-05 17:57:40 -08:00
|
|
|
enum Width : u8
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
Mask_Width = 0b00000001,
|
|
|
|
Mask_Width_Imme = 0b00001000,
|
|
|
|
Width_Byte = 0b00,
|
|
|
|
Width_Word = 0b01,
|
2023-03-05 17:57:40 -08:00
|
|
|
};
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
inline
|
2023-03-05 17:57:40 -08:00
|
|
|
char const* str_width( Width width )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
switch ( width )
|
|
|
|
{
|
|
|
|
case Width_Byte:
|
|
|
|
return "Byte";
|
|
|
|
|
|
|
|
case Width_Word:
|
|
|
|
return "Word";
|
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return Msg_Invalid_Value;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// https://i.imgur.com/Job2oPd.png
|
2023-03-05 17:57:40 -08:00
|
|
|
enum Mode : u8
|
|
|
|
{
|
|
|
|
Mask_Mode = 0b11000000,
|
|
|
|
Mode_Mem = 0b00000000,
|
|
|
|
Mode_Mem8 = 0b01000000,
|
|
|
|
Mode_Mem16 = 0b10000000,
|
|
|
|
Mode_Reg = 0b11000000,
|
|
|
|
};
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
char const* str_mode( Mode mode )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case Mode_Mem:
|
|
|
|
return "Memory: No Displacement";
|
|
|
|
|
|
|
|
case Mode_Mem8:
|
|
|
|
return "Memory: 8-bit Displacment";
|
|
|
|
|
|
|
|
case Mode_Mem16:
|
|
|
|
return "Memory: 16-bit Displacement";
|
|
|
|
|
|
|
|
case Mode_Reg:
|
|
|
|
return "Register";
|
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return Msg_Invalid_Value;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
ct u8 Mask_Memory = 0b00000111;
|
|
|
|
|
|
|
|
// https://i.imgur.com/Tm5roJu.png
|
|
|
|
enum Memory : u8
|
|
|
|
{
|
|
|
|
Add_BX_SI = 0b000,
|
|
|
|
Add_BX_DI = 0b001,
|
|
|
|
Add_BP_SI = 0b010,
|
|
|
|
Add_BP_DI = 0b011,
|
|
|
|
Add_SI = 0b100,
|
|
|
|
Add_DI = 0b101,
|
|
|
|
Add_Direct = 0b110,
|
|
|
|
Add_BX = 0b111,
|
|
|
|
|
|
|
|
Num_Memory
|
|
|
|
};
|
|
|
|
|
|
|
|
char const* str_memory( Memory mem )
|
|
|
|
{
|
|
|
|
char const* mem_to_str[Num_Memory] =
|
|
|
|
{
|
|
|
|
"BX + SI",
|
|
|
|
"BX + DI",
|
|
|
|
"BP + SI",
|
|
|
|
"BP + DI",
|
|
|
|
"SI",
|
|
|
|
"DI",
|
|
|
|
"BP",
|
|
|
|
"BX"
|
|
|
|
};
|
|
|
|
|
|
|
|
return mem_to_str[ mem ];
|
|
|
|
}
|
|
|
|
|
|
|
|
char const* str_memory_intuitive( Memory mem )
|
|
|
|
{
|
|
|
|
char const* mem_to_str[Num_Memory] =
|
|
|
|
{
|
|
|
|
"Base.16 + Stack.Index",
|
|
|
|
"Base.16 + Destination.Index",
|
|
|
|
"Stack.Base + Stack.Index",
|
|
|
|
"Stack.Base + Destination.Index",
|
|
|
|
"Stack.Index",
|
|
|
|
"Destination.Index",
|
|
|
|
"Stack.Base",
|
|
|
|
"BX"
|
|
|
|
};
|
|
|
|
|
|
|
|
return mem_to_str[ mem ];
|
|
|
|
}
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace Register
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
ct u8 Mask_Imme = 0b00000111;
|
2023-03-03 03:43:41 -08:00
|
|
|
ct u8 Mask_Left = 0b00111000;
|
|
|
|
ct u8 Mask_Right = 0b00000111;
|
|
|
|
|
|
|
|
#define D_Opcodes \
|
2023-03-06 04:33:25 -08:00
|
|
|
D_Entry( AL ) \
|
|
|
|
D_Entry( CL ) \
|
|
|
|
D_Entry( DL ) \
|
|
|
|
D_Entry( BL ) \
|
|
|
|
D_Entry( AH ) \
|
|
|
|
D_Entry( CH ) \
|
|
|
|
D_Entry( DH ) \
|
|
|
|
D_Entry( BH ) \
|
|
|
|
D_Entry( AX ) \
|
|
|
|
D_Entry( CX ) \
|
|
|
|
D_Entry( DX ) \
|
|
|
|
D_Entry( BX ) \
|
|
|
|
D_Entry( SP ) \
|
|
|
|
D_Entry( BP ) \
|
|
|
|
D_Entry( SI ) \
|
|
|
|
D_Entry( DI ) \
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
enum Type : u8
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
AL = 0b000,
|
|
|
|
CL = 0b001,
|
|
|
|
DL = 0b010,
|
|
|
|
BL = 0b011,
|
|
|
|
|
|
|
|
AH = 0b100,
|
|
|
|
CH = 0b101,
|
|
|
|
DH = 0b110,
|
|
|
|
BH = 0b111,
|
|
|
|
|
|
|
|
AX = 0b000,
|
|
|
|
CX = 0b001,
|
|
|
|
DX = 0b010,
|
|
|
|
BX = 0b011,
|
|
|
|
|
|
|
|
SP = 0b100,
|
|
|
|
BP = 0b101,
|
|
|
|
SI = 0b110,
|
|
|
|
DI = 0b111,
|
|
|
|
|
|
|
|
Num = 16
|
|
|
|
};
|
|
|
|
|
|
|
|
char const* meumonic( Type type, u8 Width )
|
|
|
|
{
|
|
|
|
static char const*
|
|
|
|
Type_To_Meumonic[ Num ] =
|
|
|
|
{
|
|
|
|
#define D_Entry( Entry_ ) #Entry_,
|
|
|
|
D_Opcodes
|
|
|
|
#undef D_Entry
|
|
|
|
};
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
return Type_To_Meumonic[ type + Width * ( 7 + 1 ) ];
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
char const* intuitive( Type type, u8 Width )
|
|
|
|
{
|
|
|
|
static char const*
|
|
|
|
Type_To_Intuitive[ Num ] =
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
"Accumulator.Low",
|
|
|
|
"Count.Low",
|
|
|
|
"Data.Low",
|
|
|
|
"Base.Low",
|
|
|
|
"Accumulator.High",
|
|
|
|
"Count.High",
|
|
|
|
"Data.High",
|
|
|
|
"Base.High",
|
|
|
|
"Accumulator.16",
|
|
|
|
"Count.16",
|
|
|
|
"Data.16",
|
|
|
|
"Base.16",
|
2023-03-03 03:43:41 -08:00
|
|
|
"Stack.Pointer",
|
|
|
|
"Stack.Base",
|
|
|
|
"Source.Index",
|
|
|
|
"Destination.Index",
|
|
|
|
};
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
return Type_To_Intuitive[ type + Width * ( 7 + 1 ) ];
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
|
|
|
|
struct Octal
|
|
|
|
{
|
|
|
|
u8 Low : 3;
|
|
|
|
u8 High : 3;
|
|
|
|
u8 Dir : 1;
|
|
|
|
u8 Write : 1;
|
|
|
|
|
|
|
|
operator u8()
|
|
|
|
{
|
|
|
|
return * cast( u8*, this);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-03 03:43:41 -08:00
|
|
|
struct POD_Instruction
|
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
// 8086 Instructions are 1 to 6 bytes in length.
|
|
|
|
union
|
|
|
|
{
|
|
|
|
u8* Ptr;
|
|
|
|
u8 Byte[6];
|
|
|
|
|
|
|
|
Octal Instr;
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
u8 Pad[2];
|
|
|
|
u16_Split Disp;
|
|
|
|
u16_Split Data;
|
|
|
|
}
|
|
|
|
EffAddr;
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
u8 Pad[1];
|
|
|
|
u16_Split Data;
|
|
|
|
}
|
|
|
|
Imme;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
u8 Pad;
|
|
|
|
u16_Split Data;
|
|
|
|
}
|
|
|
|
Addr;
|
|
|
|
};
|
|
|
|
|
|
|
|
// If directly referencing blob data:
|
|
|
|
// Part of next instruction, do not use as stratch memory.
|
2023-03-03 03:43:41 -08:00
|
|
|
u16 Pad;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Instruction : public POD_Instruction
|
|
|
|
{
|
2023-03-05 17:57:40 -08:00
|
|
|
using Code = Op::Code;
|
|
|
|
using Direction = Field::Direction;
|
|
|
|
using Mode = Field::Mode;
|
2023-03-06 04:33:25 -08:00
|
|
|
using Memory = Field::Memory;
|
2023-03-05 17:57:40 -08:00
|
|
|
using Width = Field::Width;
|
|
|
|
using Reg = Register::Type;
|
|
|
|
|
2023-03-03 03:43:41 -08:00
|
|
|
inline
|
2023-03-06 04:33:25 -08:00
|
|
|
Direction get_direction()
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
Direction direction = cast(Direction, Byte[0] & Field::Mask_Dir);
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
return direction;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2023-03-06 04:33:25 -08:00
|
|
|
Mode get_mode()
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
Mode mode = cast( Mode, Byte[1] & Field::Mask_Mode );
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2023-03-06 04:33:25 -08:00
|
|
|
Code get_opcode( u8 mask )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
Op::Code opcode = cast( Op::Code, Byte[0] & mask );
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
return opcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2023-03-06 04:33:25 -08:00
|
|
|
Width get_width( u8 mask )
|
|
|
|
{
|
|
|
|
Width width = cast( Width, Byte[0] & mask );
|
|
|
|
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
|
|
|
Reg mode_operand_left_reg()
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
u8
|
2023-03-06 04:33:25 -08:00
|
|
|
operand = Byte[1] & Register::Mask_Left;
|
2023-03-03 03:43:41 -08:00
|
|
|
operand >>= 3;
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return cast(Reg, operand);
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2023-03-06 04:33:25 -08:00
|
|
|
Reg mode_operand_right_reg()
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
u8 operand = Byte[1] & Register::Mask_Right;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
return cast( Reg, operand );
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
forceinline
|
|
|
|
void dissassemble_mode( char const*& str_operand, Width& width, u8& length )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
2023-03-06 04:33:25 -08:00
|
|
|
using namespace Field;
|
|
|
|
using namespace Op;
|
|
|
|
using namespace Register;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
switch ( get_mode() )
|
|
|
|
{
|
|
|
|
case Mode_Mem:
|
|
|
|
{
|
|
|
|
Memory operand_right = cast( Memory, Byte[1] & Mask_Memory );
|
|
|
|
|
|
|
|
length += 2;
|
|
|
|
|
|
|
|
if ( operand_right == Add_Direct )
|
|
|
|
{
|
|
|
|
u16 address = EffAddr.Disp;
|
|
|
|
|
|
|
|
str_operand = string_format( "[ %u ]", address );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
str_operand = str_memory( operand_right );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Mode_Mem8:
|
|
|
|
{
|
|
|
|
Memory operand_right = cast( Memory, Byte[1] & Mask_Memory );
|
|
|
|
|
|
|
|
length += 1;
|
|
|
|
|
|
|
|
str_operand = string_format( "[ %s + %u ]", str_memory( operand_right), EffAddr.Disp.Low );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Mode_Mem16:
|
|
|
|
{
|
|
|
|
length += 2;
|
|
|
|
|
|
|
|
Memory operand_right = cast( Memory, Byte[1] & Mask_Memory );
|
|
|
|
u16 address = EffAddr.Disp;
|
|
|
|
|
|
|
|
str_operand = string_format( "[ %s + %u ]", str_memory( operand_right), address );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Mode_Reg:
|
|
|
|
str_operand = Register::meumonic( mode_operand_right_reg(), width );
|
|
|
|
break;
|
|
|
|
}
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
u8 dissassemble( zpl_string* result_out )
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
using namespace Field;
|
|
|
|
using namespace Op;
|
|
|
|
using namespace Register;
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
u8 length = 1;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
zpl_string assembly = string_make( 32);
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
Code code = get_opcode( Op::Mask );
|
|
|
|
Direction dir = get_direction();
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
char const* str_operand_left = nullptr;
|
|
|
|
char const* str_operand_right = nullptr;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
const u8 code_low = Byte[0] & Op::Mask_Low;
|
|
|
|
const u8 code_high = Byte[0] & Op::Mask_High;
|
|
|
|
const u8 sig_imme = Byte[0] & Op::Mask_Imme;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
if ( get_opcode( Op::Mask_Low ) == mov_Im_R )
|
|
|
|
{
|
|
|
|
Width width = get_width( Mask_Width_Imme );
|
|
|
|
Reg reg = cast(Reg, Byte[0] & Register::Mask_Right );
|
|
|
|
u16 immediate = width == Width_Byte ?
|
|
|
|
Imme.Data.Low : Imme.Data;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
str_operand_left = Register::meumonic( reg, width );
|
|
|
|
str_operand_right = string_format( "%u", immediate );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch ( code )
|
|
|
|
{
|
|
|
|
#pragma region mov
|
|
|
|
case mov_RM_R:
|
|
|
|
{
|
|
|
|
length++;
|
|
|
|
|
|
|
|
Width width = get_width( Mask_Width );
|
|
|
|
|
|
|
|
str_operand_left = Register::meumonic( mode_operand_left_reg(), width );
|
|
|
|
|
|
|
|
dissassemble_mode( str_operand_right, width, length );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case mov_Im_RM:
|
|
|
|
{
|
|
|
|
Width width = get_width( Mask_Width_Imme );
|
|
|
|
|
|
|
|
Memory operand_left = cast( Memory, Byte[1] & Mask_Memory );
|
|
|
|
u16 address = EffAddr.Disp;
|
|
|
|
u16 immediate = width == Width_Byte ?
|
|
|
|
EffAddr.Data.Low : EffAddr.Data;
|
|
|
|
|
|
|
|
dissassemble_mode( str_operand_left, width, length );
|
|
|
|
|
|
|
|
str_operand_right = string_format( "%u", immediate );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case mov_M_Acc:
|
|
|
|
{
|
|
|
|
Width width = get_width( Mask_Width );
|
|
|
|
u16 address = width == Width_Byte ?
|
|
|
|
Addr.Data.Low : Addr.Data;
|
|
|
|
|
|
|
|
str_operand_left = Register::meumonic( Reg::AX, Width_Word );
|
|
|
|
str_operand_right = string_format( "%u", address );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case mov_Acc_M:
|
|
|
|
{
|
|
|
|
Width width = get_width( Mask_Width );
|
|
|
|
u16 address = width == Width_Byte ?
|
|
|
|
Addr.Data.Low : Addr.Data;
|
|
|
|
|
|
|
|
str_operand_right = string_format( "%u", address );
|
|
|
|
str_operand_left = Register::meumonic( Reg::AX, Width_Word );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case mov_RM_SR:
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case mov_SR_RM:
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#pragma endregion mov
|
|
|
|
}
|
|
|
|
}
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
assembly = string_format( assembly, 32, "\n%s %s, %s"
|
|
|
|
// opcode operand_right, operand_left
|
|
|
|
, Op::meumonic( code)
|
|
|
|
, str_operand_right
|
|
|
|
, str_operand_left
|
|
|
|
);
|
2023-03-05 17:57:40 -08:00
|
|
|
|
|
|
|
if ( result_out == nullptr )
|
2023-03-06 04:33:25 -08:00
|
|
|
return length;
|
2023-03-05 17:57:40 -08:00
|
|
|
|
|
|
|
if ( * result_out == nullptr )
|
2023-03-06 04:33:25 -08:00
|
|
|
* result_out = string_make( zpl_kilobytes(1) );
|
2023-03-05 17:57:40 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
* result_out = string_append( * result_out, assembly );
|
2023-03-05 17:57:40 -08:00
|
|
|
|
|
|
|
zpl_printf("\n\nAssembly: %s\n\n", assembly);
|
2023-03-06 04:33:25 -08:00
|
|
|
|
|
|
|
return length;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace Tests
|
|
|
|
{
|
2023-03-05 17:57:40 -08:00
|
|
|
void try_mock_instruction()
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
using namespace Field;
|
|
|
|
using namespace Op;
|
|
|
|
using namespace Register;
|
|
|
|
|
|
|
|
Instruction
|
2023-03-05 17:57:40 -08:00
|
|
|
mock; // mov CX, BX
|
2023-03-06 04:33:25 -08:00
|
|
|
mock.Byte[0] = mov_RM_R | Dir_Src | Field::Width_Word;
|
|
|
|
mock.Byte[1] = Field::Mode_Reg | offset_left_reg(BX) | CX;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
zpl_printf("\n\nAttempting Mock Instruction: mov CX, BX");
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
print_nl();
|
2023-03-06 04:33:25 -08:00
|
|
|
print_as_binary( & mock.Byte[0], 1, " " );
|
|
|
|
print_as_binary( & mock.Byte[1], 1, " " );
|
2023-03-05 17:57:40 -08:00
|
|
|
print_nl();
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
zpl_string dissasembly = nullptr;
|
|
|
|
|
|
|
|
mock.dissassemble( & dissasembly);
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
void try_blob_single_move()
|
2023-03-03 03:43:41 -08:00
|
|
|
{
|
|
|
|
zpl_printf("\n\nAttempting to read blob: listing_0037_single_register_mov");
|
|
|
|
|
|
|
|
zpl_file_contents
|
2023-03-06 04:33:25 -08:00
|
|
|
blob = zpl_file_read_contents( g_allocator, false, "tests/listing_0037_single_register_mov" );
|
2023-03-03 03:43:41 -08:00
|
|
|
|
|
|
|
if (blob.data == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
u32 left = blob.size;
|
2023-03-05 17:57:40 -08:00
|
|
|
u8* data = cast( u8*, blob.data );
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
print_nl();
|
|
|
|
print_as_binary( data, left, " " );
|
|
|
|
print_nl();
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
zpl_string dissasembly = nullptr;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
Instruction
|
|
|
|
instr;
|
2023-03-06 04:33:25 -08:00
|
|
|
instr.Byte[0] = data[0];
|
|
|
|
instr.Byte[1] = data[1];
|
2023-03-05 17:57:40 -08:00
|
|
|
instr.dissassemble( & dissasembly);
|
|
|
|
}
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
void try_blob_many_moves()
|
2023-03-05 17:57:40 -08:00
|
|
|
{
|
|
|
|
zpl_printf("\n\nAttempting to read blob: listing_0038_many_register_mov");
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
zpl_file_contents
|
2023-03-06 04:33:25 -08:00
|
|
|
blob = zpl_file_read_contents( g_allocator, false, "tests/listing_0038_many_register_mov" );
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
if (blob.data == nullptr )
|
|
|
|
return;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
u32 left = blob.size;
|
|
|
|
u8* data = cast( u8*, blob.data );
|
|
|
|
|
|
|
|
print_nl();
|
|
|
|
print_as_binary( data, left, " " );
|
|
|
|
print_nl();
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
zpl_string dissasembly = string_make( "bits 16\n");
|
2023-03-05 17:57:40 -08:00
|
|
|
|
|
|
|
while ( left )
|
|
|
|
{
|
|
|
|
Instruction
|
|
|
|
instr;
|
2023-03-06 04:33:25 -08:00
|
|
|
instr.Byte[0] = data[0];
|
|
|
|
instr.Byte[1] = data[1];
|
2023-03-05 17:57:40 -08:00
|
|
|
instr.dissassemble( & dissasembly);
|
|
|
|
|
|
|
|
data += 2;
|
|
|
|
left -= 2;
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
zpl_printf("\n\nDissassemlby:\n%s", dissasembly);
|
|
|
|
dissasembly = zpl_string_append_fmt( dissasembly, "\n" );
|
|
|
|
|
|
|
|
zpl_printf("\n\nSaving to file");
|
|
|
|
zpl_file_write_contents("tests/listing_0038_many_register_mov.out.asm"
|
|
|
|
, dissasembly
|
|
|
|
, zpl_string_length(dissasembly)
|
|
|
|
, nullptr
|
|
|
|
);
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
2023-03-05 17:57:40 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
void try_blob_more_moves()
|
|
|
|
{
|
|
|
|
zpl_printf("\n\nAttempting to read blob: listing_0039_more_movs");
|
|
|
|
|
|
|
|
zpl_file_contents
|
|
|
|
blob = zpl_file_read_contents( g_allocator, false, "tests/listing_0039_more_movs" );
|
|
|
|
|
|
|
|
if (blob.data == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
u32 left = blob.size;
|
|
|
|
u8* data = cast( u8*, blob.data );
|
|
|
|
|
|
|
|
print_nl();
|
|
|
|
print_as_binary( data, left, " " );
|
|
|
|
print_nl();
|
|
|
|
|
|
|
|
zpl_string dissasembly = string_make( "bits 16\n");
|
|
|
|
|
|
|
|
while ( left )
|
|
|
|
{
|
|
|
|
Instruction
|
|
|
|
instr;
|
|
|
|
instr.Ptr = data;
|
|
|
|
|
|
|
|
u8 length = instr.dissassemble( & dissasembly);
|
|
|
|
|
|
|
|
data += length;
|
|
|
|
left -= length;
|
|
|
|
}
|
|
|
|
|
|
|
|
zpl_printf("\n\nDissassemlby:\n%s", dissasembly);
|
|
|
|
dissasembly = zpl_string_append_fmt( dissasembly, "\n" );
|
|
|
|
|
|
|
|
zpl_printf("\n\nSaving to file");
|
|
|
|
zpl_file_write_contents("tests/listing_0039_more_movs.asm.out.asm"
|
|
|
|
, dissasembly
|
|
|
|
, zpl_string_length(dissasembly)
|
|
|
|
, nullptr
|
|
|
|
);
|
|
|
|
}
|
2023-03-03 03:43:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
zpl_printf("sim 8086!");
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
setup();
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
f64 start = zpl_time_rel();
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
// Tests::try_blob_single_move();
|
|
|
|
// Tests::try_blob_many_moves();
|
|
|
|
Tests::try_blob_more_moves();
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-06 04:33:25 -08:00
|
|
|
f64 end = zpl_time_rel();
|
|
|
|
f64 ms = (end - start) * 100;
|
2023-03-03 03:43:41 -08:00
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
printf("\n\nElapsed Time: %lf ms", ms);
|
2023-03-03 03:43:41 -08:00
|
|
|
printf("\n\n");
|
|
|
|
|
2023-03-05 17:57:40 -08:00
|
|
|
cleanup();
|
|
|
|
|
2023-03-03 03:43:41 -08:00
|
|
|
return 0;
|
|
|
|
}
|