diff --git a/.vscode/settings.json b/.vscode/settings.json index a928b13..4ab2e90 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,7 @@ "*.rmd": "markdown", "zpl.h": "c", "cstddef": "cpp", - "xtr1common": "cpp" + "xtr1common": "cpp", + "*.inline": "cpp" } } \ No newline at end of file diff --git a/8086/Op.hpp b/8086/Op.hpp new file mode 100644 index 0000000..6864db9 --- /dev/null +++ b/8086/Op.hpp @@ -0,0 +1,51 @@ +#include "bloat.hpp" + +namespace Op +{ + enum Code : u8 + { + #define D_Entry( Entry_ ) Entry, + #include "opcodes.inline" + Num, + #undef D_Entry + }; + + char const* str( Code code ) + { + static + char const* code_to_str[ Num] = + { + #define D_Entry( Entry_ ) ZPL_STRINGIFY( Entry_ ), + #include "opcodes.inline" + #undef D_Entry + }; + + return code_to_str[ code ]; + } + + char const* meumonic( Code code ) + { + static + char const* code_to_str[ Num] = + { + #define D_Entry( Entry_ ) ZPL_STRINGIFY( Entry_ ), + #include "opcodes.meumonics.inline" + #undef D_Entry + }; + + return code_to_str[ code ]; + } + + char const* intuitive( Code code ) + { + static + char const* code_to_str[ Num] = + { + #define D_Entry( Entry_ ) ZPL_STRINGIFY( Entry_ ), + #include "opcodes.intuitive.inline" + #undef D_Entry + }; + + return code_to_str[ Num]; + } +} \ No newline at end of file diff --git a/8086/opcodes.inline b/8086/opcodes.inline new file mode 100644 index 0000000..ccc2507 --- /dev/null +++ b/8086/opcodes.inline @@ -0,0 +1,146 @@ +D_Entry( add_00 ) +D_Entry( add_01 ) +D_Entry( add_02 ) +D_Entry( add_04 ) +D_Entry( add_05 ) +D_Entry( push_06 ) +D_Entry( pop_07 ) +D_Entry( or_10 ) +D_Entry( or_11 ) +D_Entry( or_12 ) +D_Entry( or_13 ) +D_Entry( or_14 ) +D_Entry( or_15 ) +D_Entry( push_16 ) +D_Entry( _17 ) +D_Entry( adc_20 ) +D_Entry( adc_21 ) +D_Entry( adc_22 ) +D_Entry( adc_23 ) +D_Entry( adc_24 ) +D_Entry( adc_25 ) +D_Entry( push_26 ) +D_Entry( pop_27 ) +D_Entry( sbb_30 ) +D_Entry( sbb_31 ) +D_Entry( sbb_32 ) +D_Entry( sbb_33 ) +D_Entry( sbb_34 ) +D_Entry( sbb_35 ) +D_Entry( push_36 ) +D_Entry( pop_37 ) +D_Entry( and_40 ) +D_Entry( and_41 ) +D_Entry( and_42 ) +D_Entry( and_43 ) +D_Entry( and_44 ) +D_Entry( and_45 ) +D_Entry( es_46 ) +D_Entry( daa_47 ) +D_Entry( sub_50 ) +D_Entry( sub_51 ) +D_Entry( sub_52 ) +D_Entry( sub_53 ) +D_Entry( sub_54 ) +D_Entry( sub_55 ) +D_Entry( cs_56 ) +D_Entry( das_57 ) +D_Entry( xor_60 ) +D_Entry( xor_61 ) +D_Entry( xor_62 ) +D_Entry( xor_63 ) +D_Entry( xor_64 ) +D_Entry( xor_65 ) +D_Entry( ss_66 ) +D_Entry( aaa_67 ) +D_Entry( cmp_70 ) +D_Entry( cmp_71 ) +D_Entry( cmp_72 ) +D_Entry( cmp_73 ) +D_Entry( cmp_74 ) +D_Entry( cmp_75 ) +D_Entry( ds_75 ) +D_Entry( ds_76 ) +D_Entry( aas_107 ) +D_Entry( inc_100 ) +D_Entry( inc_101 ) +D_Entry( inc_102 ) +D_Entry( inc_103 ) +D_Entry( inc_104 ) +D_Entry( inc_105 ) +D_Entry( inc_106 ) +D_Entry( inc_107 ) +D_Entry( dec_100 ) +D_Entry( dec_101 ) +D_Entry( dec_102 ) +D_Entry( dec_103 ) +D_Entry( dec_104 ) +D_Entry( dec_105 ) +D_Entry( dec_106 ) +D_Entry( dec_107 ) +D_Entry( push_110 ) +D_Entry( push_111 ) +D_Entry( push_112 ) +D_Entry( push_113 ) +D_Entry( push_114 ) +D_Entry( push_115 ) +D_Entry( push_116 ) +D_Entry( push_117 ) +D_Entry( pop_120 ) +D_Entry( pop_121 ) +D_Entry( pop_122 ) +D_Entry( pop_123 ) +D_Entry( pop_124 ) +D_Entry( pop_125 ) +D_Entry( pop_126 ) +D_Entry( pop_127 ) +D_Entry( pop_130 ) +D_Entry( pop_131 ) +D_Entry( pop_132 ) +D_Entry( pop_133 ) +D_Entry( pop_134 ) +D_Entry( pop_135 ) +D_Entry( pop_136 ) +D_Entry( pop_137 ) +D_Entry( _140 ) +D_Entry( _141 ) +D_Entry( _142 ) +D_Entry( _143 ) +D_Entry( _144 ) +D_Entry( _145 ) +D_Entry( _146 ) +D_Entry( _147 ) +D_Entry( _150 ) +D_Entry( _151 ) +D_Entry( _152 ) +D_Entry( _153 ) +D_Entry( _154 ) +D_Entry( _155 ) +D_Entry( _156 ) +D_Entry( _157 ) +D_Entry( jo_160 ) +D_Entry( jno_161 ) +D_Entry( jb_jnae_jc_162 ) +D_Entry( jnb_jae_jnc_163 ) +D_Entry( je_jz_164 ) +D_Entry( jne_jnz_165 ) +D_Entry( jbe_jna_166 ) +D_Entry( jnbe_ja_167 ) +D_Entry( js_170 ) +D_Entry( jns_171 ) +D_Entry( jp_jpe_172 ) +D_Entry( jnp_jpo_173 ) +D_Entry( jl_jnge_174 ) +D_Entry( jnl_jge_175 ) +D_Entry( jle_jng_176 ) +D_Entry( jnle_jg_177 ) +D_Entry( add_200 ) +D_Entry( or_201 ) +D_Entry( adc_201 ) +D_Entry( sbb_202 ) +D_Entry( sub_203 ) +D_Entry( cmp_204 ) +D_Entry( add_205 ) +D_Entry( adc_206 ) +D_Entry( sbb_207 ) +D_Entry( sub_210 ) \ No newline at end of file diff --git a/8086/opcodes.intuitive.inline b/8086/opcodes.intuitive.inline new file mode 100644 index 0000000..e69de29 diff --git a/8086/opcodes.meumonics.inline b/8086/opcodes.meumonics.inline new file mode 100644 index 0000000..e69de29 diff --git a/part_1/bloat.hpp b/part_1/bloat.hpp index f815fc3..c749118 100644 --- a/part_1/bloat.hpp +++ b/part_1/bloat.hpp @@ -30,22 +30,101 @@ // # define ZPL_MODULE_THREADING // # define ZPL_MODULE_JOBS // # define ZPL_MODULE_PARSER -extern "C" { +// extern "C" { #include "zpl.h" -} +// } #if __clang__ # pragma clang diagnostic pop #endif -#undef cast #pragma endregion ZPL INCLUDE +zpl_arena Global_Arena {}; +#define g_allocator zpl_arena_allocator( & Global_Arena) + +void setup() +{ + zpl_arena_init_from_allocator( & Global_Arena, zpl_heap(), zpl_megabytes(10) ); + + if ( Global_Arena.total_size == 0 ) + { + zpl_assert_crash( "Failed to reserve memory for Tests:: Global_Arena" ); + } +} + +void cleanup() +{ + zpl_arena_free( & Global_Arena); +} + + + +#pragma region ZPL Expose +zpl_string string_make(zpl_isize capacity) +{ + zpl_isize header_size = zpl_size_of(zpl_string_header); + void *ptr = zpl_alloc(g_allocator, header_size + capacity + 1); + + zpl_string str; + zpl_string_header *header; + + if (ptr == NULL) return NULL; + zpl_zero_size(ptr, header_size + capacity + 1); + + str = cast(char *) ptr + header_size; + header = ZPL_STRING_HEADER(str); + header->allocator = g_allocator; + header->length = 0; + header->capacity = capacity; + str[capacity] = '\0'; + + return str; +} + +inline +zpl_string string_make(const char *str) +{ + zpl_isize len = str ? zpl_strlen(str) : 0; + return zpl_string_make_length(g_allocator, str, len); +} + +inline +zpl_string string_append(zpl_string str, zpl_string const other) +{ + return zpl_string_append_length(str, other, zpl_string_length(other)); +} + +zpl_string string_format( char const* fmt, ... ) +{ + zpl_local_persist zpl_thread_local char buf[ZPL_PRINTF_MAXLEN] = { 0 }; + va_list va; + va_start(va, fmt); + zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va); + va_end(va); + + return zpl_string_make(g_allocator, buf); +} + +zpl_string string_format( char* buffer, zpl_isize size, char const* fmt, ... ) +{ + va_list va; + va_start(va, fmt); + zpl_snprintf_va(buffer, size, fmt, va); + va_end(va); + + return zpl_string_make(g_allocator, buffer); +} +#pragma endregion ZPL Expose + + + #define bit( Value_ ) ( 1 << Value_ ) #define bitfield_is_equal( Field_, Mask_ ) ( ( Mask_ & Field_ ) == Mask_ ) +#undef cast #define cast( Type_ , Value_ ) ( ( Type_ )( Value_ ) ) #define ct constexpr #define gen( ... ) template< __VA_ARGS__ > @@ -54,13 +133,31 @@ extern "C" { #define Msg_Invalid_Value "INVALID VALUE PROVIDED" #define scast static_cast #define rcast reinterpret_cast +#define pcast( Type_, Value_ ) ( * (Type_*)( & Value_ ) ) + + +using s8 = zpl_i8; using u8 = zpl_u8; using u16 = zpl_u16; using u32 = zpl_u32; +using f64 = zpl_f64; using uw = zpl_usize; using sw = zpl_isize; +struct u16_Split +{ + u8 Low; + u8 High; + + operator u16() + { + return * cast( u16*, this ); + } +}; + + + ct inline char char_binary( u8 value, u8 pos ) { diff --git a/part_1/build.bat b/part_1/build.bat index e8ac896..38882b0 100644 --- a/part_1/build.bat +++ b/part_1/build.bat @@ -15,5 +15,15 @@ if not exist tests\listing_0038_many_register_mov ( call nasm ".\tests\listing_0038_many_register_mov.asm" ) +if not exist tests\listing_0039_more_movs ( + echo Assembling: listing_0039_more_movs.asm + call nasm ".\tests\listing_0039_more_movs.asm" +) + +if not exist tests\listing_0040_challenge_movs ( + echo Assembling: listing_0040_challenge_movs.asm + call nasm ".\tests\listing_0040_challenge_movs.asm" +) + echo: ninja -C build \ No newline at end of file diff --git a/part_1/clean.bat b/part_1/clean.bat index 7dd0442..08547f1 100644 --- a/part_1/clean.bat +++ b/part_1/clean.bat @@ -11,3 +11,12 @@ if exist tests\listing_0037_single_register_mov ( if exist tests\listing_0038_many_register_mov ( DEL /Q tests\listing_0038_many_register_mov ) + +if exist tests\listing_0039_more_movs ( + DEL /Q tests\listing_0039_more_movs +) + +if exist tests\listing_0040_challenge_movs ( + DEL /Q tests\listing_0040_challenge_movs +) + diff --git a/part_1/sim_8086.cpp b/part_1/sim_8086.cpp index 213412e..a4c3825 100644 --- a/part_1/sim_8086.cpp +++ b/part_1/sim_8086.cpp @@ -1,60 +1,46 @@ #include "bloat.hpp" -zpl_arena BlobArena {}; -#define allocator zpl_arena_allocator( & BlobArena) - -void setup() -{ - zpl_arena_init_from_allocator( & BlobArena, zpl_heap(), zpl_megabytes(10) ); - - if ( BlobArena.total_size == 0 ) - { - zpl_assert_crash( "Failed to reserve memory for Tests:: BLobArena" ); - } -} - -void cleanup() -{ - zpl_arena_free( & BlobArena); -} - -// Binary formatting for literals is used heavily as that its -// how the encoding is conveyed in the hardware reference from intel. +// Octal formatting is used heavily throughout +// See: https://gist.github.com/seanjensengrey/f971c20d05d4d0efc0781f2f3c0353da +// (x86 is an octal machine) namespace Op { + ct u8 Mask = 00210; + ct u8 Mask_Low = 0b11110000; + ct u8 Mask_High = 0b00001111; + ct u8 Mask_Imme = 0b00111000; #define D_Opcodes \ - D_Entry( mov_88 ) \ - D_Entry( mov_89 ) \ + 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 ) \ enum Code : u8 { - Mask = 0b11111100, - mov_88 = 0b10001000, - mov_89 = 0b11000100, + 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 }; char const* str( Code type ) { switch ( type ) { - case mov_88: - return "mov_88"; - case mov_89: - return "mov_89"; - } + #define D_Entry( Entry_ ) \ + case Entry_: \ + return ZPL_STRINGIFY(Entry_); \ - return Msg_Invalid_Value; - } - - ct char const* helper_meumonic( Code type ) - { - switch ( type ) - { - case mov_88: - case mov_89: - return "mov"; + D_Opcodes + #undef D_Entry } return Msg_Invalid_Value; @@ -64,32 +50,30 @@ namespace Op { switch ( type ) { - case mov_88: - case mov_89: + 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 : return "mov"; } return Msg_Invalid_Value; } - ct char const* helper_intuitive( Code type ) - { - switch ( type ) - { - case mov_88: - case mov_89: - return "move"; - } - - return Msg_Invalid_Value; - } - char const* intuitive( Code type ) { switch ( type ) { - case mov_88: - case mov_89: + 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 : return "move"; } @@ -101,9 +85,8 @@ namespace Op namespace Field { - // Effective Address offset inline - u8 effective_address( u8 reg ) + u8 offset_left_reg( u8 reg ) { return reg << 3; } @@ -134,9 +117,10 @@ namespace Field // https://i.imgur.com/9Op8Lnd.png enum Width : u8 { - Mask_Width = 0b00000001, - Width_Byte = 0b00, - Width_Word = 0b01, + Mask_Width = 0b00000001, + Mask_Width_Imme = 0b00001000, + Width_Byte = 0b00, + Width_Word = 0b01, }; inline @@ -184,37 +168,81 @@ namespace Field return Msg_Invalid_Value; } -#if 0 - ct u8 RegMem_AL = 0b00000000; - ct u8 RegMem_AX = 0b00000000; - ct u8 RegMem_BX_SI = 0b00000000; - ct u8 RegMem_BX_SI_D8 = 0b00000000; - ct u8 RegMem_BX_SI_D16 = 0b00000000; -#endif + 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 ]; + } } namespace Register { + ct u8 Mask_Imme = 0b00000111; ct u8 Mask_Left = 0b00111000; ct u8 Mask_Right = 0b00000111; #define D_Opcodes \ - 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 ) \ + 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 ) \ enum Type : u8 { @@ -251,7 +279,7 @@ namespace Register #undef D_Entry }; - return Type_To_Meumonic[ type + Width * 7 + 1 ]; + return Type_To_Meumonic[ type + Width * ( 7 + 1 ) ]; } char const* intuitive( Type type, u8 Width ) @@ -259,38 +287,77 @@ namespace Register static char const* Type_To_Intuitive[ Num ] = { - "A.Low", - "C.Low", - "D.Low", - "B.Low", - "A.High", - "C.High", - "D.High", - "B.High", - "A.16", - "C.16", - "D.16", - "B.16", + "Accumulator.Low", + "Count.Low", + "Data.Low", + "Base.Low", + "Accumulator.High", + "Count.High", + "Data.High", + "Base.High", + "Accumulator.16", + "Count.16", + "Data.16", + "Base.16", "Stack.Pointer", "Stack.Base", "Source.Index", "Destination.Index", }; - return Type_To_Intuitive[ type + Width * 7 + 1 ]; + return Type_To_Intuitive[ type + Width * ( 7 + 1 ) ]; } } -// 8086 Instructions are 1 to 6 bytes in length. + +struct Octal +{ + u8 Low : 3; + u8 High : 3; + u8 Dir : 1; + u8 Write : 1; + + operator u8() + { + return * cast( u8*, this); + } +}; + struct POD_Instruction { - u8 Byte_1; - u8 Byte_2; - u8 Byte_3; - u8 Byte_4; - u8 Byte_5; - u8 Byte_6; + // 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; + + struct + { + u8 Pad; + u16_Split Data; + } + Addr; + }; + + // If directly referencing blob data: + // Part of next instruction, do not use as stratch memory. u16 Pad; }; @@ -299,120 +366,232 @@ struct Instruction : public POD_Instruction using Code = Op::Code; using Direction = Field::Direction; using Mode = Field::Mode; + using Memory = Field::Memory; using Width = Field::Width; using Reg = Register::Type; inline - Direction direction() + Direction get_direction() { - Direction - direction = cast(Direction, Byte_1 & Field::Mask_Dir); + Direction direction = cast(Direction, Byte[0] & Field::Mask_Dir); return direction; } inline - Mode mode() + Mode get_mode() { - Mode mode = cast( Mode, Byte_2 & Field::Mask_Mode ); + Mode mode = cast( Mode, Byte[1] & Field::Mask_Mode ); return mode; } inline - Code opcode() + Code get_opcode( u8 mask ) { - Op::Code - opcode = cast( Op::Code, Byte_1 & Op::Mask ); + Op::Code opcode = cast( Op::Code, Byte[0] & mask ); return opcode; } inline - Reg operand_left() + Width get_width( u8 mask ) + { + Width width = cast( Width, Byte[0] & mask ); + + return width; + } + + inline + Reg mode_operand_left_reg() { u8 - operand = Byte_2 & Register::Mask_Left; + operand = Byte[1] & Register::Mask_Left; operand >>= 3; return cast(Reg, operand); } inline - Reg operand_right() + Reg mode_operand_right_reg() { - u8 operand = Byte_2 & Register::Mask_Right; + u8 operand = Byte[1] & Register::Mask_Right; return cast( Reg, operand ); } - inline - Width width() - { - Width width = cast( Width, Byte_1 & Field::Mask_Width ); - - return width; - } - - void dissassemble( zpl_string* result_out ) + forceinline + void dissassemble_mode( char const*& str_operand, Width& width, u8& length ) { using namespace Field; using namespace Op; using namespace Register; - Direction dir = direction(); - Width width_val = width(); + switch ( get_mode() ) + { + case Mode_Mem: + { + Memory operand_right = cast( Memory, Byte[1] & Mask_Memory ); - char const* opcode_str = Op::meumonic( opcode() ); - char const* direction_str = Field::str_direction( dir ); - char const* width_str = Field::str_width( width_val ); - char const* mode_str = Field::str_mode( mode() ); - char const* operand_left_str = Register::meumonic( operand_left(), width_val ); - char const* operand_right_str = Register::meumonic( operand_right(), width_val ); + length += 2; - char - binary_string[9]; - binary_string[8] = '\0'; + if ( operand_right == Add_Direct ) + { + u16 address = EffAddr.Disp; - #if Build_Debug - str_binary( binary_string, opcode() ); - zpl_printf("\nOpcode : %s : %s", binary_string, opcode_str); + str_operand = string_format( "[ %u ]", address ); + } + else + { + str_operand = str_memory( operand_right ); + } + } + break; - str_binary( binary_string, dir ); - zpl_printf("\nDirection : %s : %s", binary_string, direction_str); + case Mode_Mem8: + { + Memory operand_right = cast( Memory, Byte[1] & Mask_Memory ); - str_binary( binary_string, width_val ); - zpl_printf("\nWidth : %s : %s", binary_string, width_str); + length += 1; - str_binary( binary_string, mode() ); - zpl_printf("\nMode : %s : %s", binary_string, mode_str); + str_operand = string_format( "[ %s + %u ]", str_memory( operand_right), EffAddr.Disp.Low ); + } + break; - str_binary( binary_string, operand_left() ); - zpl_printf("\nOperand : %s : %s", binary_string, operand_left_str); + case Mode_Mem16: + { + length += 2; - str_binary( binary_string, operand_right() ); - zpl_printf("\nOperand EA : %s : %s", binary_string, operand_right_str); - #endif + Memory operand_right = cast( Memory, Byte[1] & Mask_Memory ); + u16 address = EffAddr.Disp; - if ( result_out == nullptr ) - return; + str_operand = string_format( "[ %s + %u ]", str_memory( operand_right), address ); + } + break; - if ( * result_out == nullptr ) - * result_out = zpl_string_make_reserve( allocator, zpl_kilobytes(1) ); + case Mode_Reg: + str_operand = Register::meumonic( mode_operand_right_reg(), width ); + break; + } + } - zpl_string assembly = zpl_string_make_reserve( allocator, 32); + u8 dissassemble( zpl_string* result_out ) + { + using namespace Field; + using namespace Op; + using namespace Register; - assembly = zpl_string_sprintf( allocator, assembly, zpl_kilobytes(1) - 1, "\n%s %s, %s" - , opcode_str - , dir == Dir_Src ? operand_right_str : operand_left_str - , dir == Dir_Src ? operand_left_str : operand_right_str + u8 length = 1; + + zpl_string assembly = string_make( 32); + + Code code = get_opcode( Op::Mask ); + Direction dir = get_direction(); + + char const* str_operand_left = nullptr; + char const* str_operand_right = nullptr; + + 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; + + 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; + + 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 + } + } + + assembly = string_format( assembly, 32, "\n%s %s, %s" + // opcode operand_right, operand_left + , Op::meumonic( code) + , str_operand_right + , str_operand_left ); - * result_out = zpl_string_append( * result_out, assembly ); + if ( result_out == nullptr ) + return length; + + if ( * result_out == nullptr ) + * result_out = string_make( zpl_kilobytes(1) ); + + * result_out = string_append( * result_out, assembly ); - #if Build_Debug zpl_printf("\n\nAssembly: %s\n\n", assembly); - #endif + + return length; } }; @@ -426,14 +605,14 @@ namespace Tests Instruction mock; // mov CX, BX - mock.Byte_1 = mov_88 | Dir_Src | Field::Width_Word; - mock.Byte_2 = Field::Mode_Reg | effective_address(BX) | CX; + mock.Byte[0] = mov_RM_R | Dir_Src | Field::Width_Word; + mock.Byte[1] = Field::Mode_Reg | offset_left_reg(BX) | CX; zpl_printf("\n\nAttempting Mock Instruction: mov CX, BX"); print_nl(); - print_as_binary( & mock.Byte_1, 1, " " ); - print_as_binary( & mock.Byte_2, 1, " " ); + print_as_binary( & mock.Byte[0], 1, " " ); + print_as_binary( & mock.Byte[1], 1, " " ); print_nl(); zpl_string dissasembly = nullptr; @@ -441,12 +620,12 @@ namespace Tests mock.dissassemble( & dissasembly); } - void try_blob_single_instruction() + void try_blob_single_move() { zpl_printf("\n\nAttempting to read blob: listing_0037_single_register_mov"); zpl_file_contents - blob = zpl_file_read_contents( allocator, false, "tests/listing_0037_single_register_mov" ); + blob = zpl_file_read_contents( g_allocator, false, "tests/listing_0037_single_register_mov" ); if (blob.data == nullptr ) return; @@ -462,17 +641,17 @@ namespace Tests Instruction instr; - instr.Byte_1 = data[0]; - instr.Byte_2 = data[1]; + instr.Byte[0] = data[0]; + instr.Byte[1] = data[1]; instr.dissassemble( & dissasembly); } - void try_blob_many_instructions() + void try_blob_many_moves() { zpl_printf("\n\nAttempting to read blob: listing_0038_many_register_mov"); zpl_file_contents - blob = zpl_file_read_contents( allocator, false, "tests/listing_0038_many_register_mov" ); + blob = zpl_file_read_contents( g_allocator, false, "tests/listing_0038_many_register_mov" ); if (blob.data == nullptr ) return; @@ -484,14 +663,14 @@ namespace Tests print_as_binary( data, left, " " ); print_nl(); - zpl_string dissasembly = zpl_string_make( allocator, "bits 16\n"); + zpl_string dissasembly = string_make( "bits 16\n"); while ( left ) { Instruction instr; - instr.Byte_1 = data[0]; - instr.Byte_2 = data[1]; + instr.Byte[0] = data[0]; + instr.Byte[1] = data[1]; instr.dissassemble( & dissasembly); data += 2; @@ -509,7 +688,47 @@ namespace Tests ); } - #undef allocator + 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 + ); + } } @@ -519,16 +738,14 @@ int main() setup(); - zpl_f64 start = zpl_time_rel(); + f64 start = zpl_time_rel(); -#if 0 - Tests::try_mock_instruction(); - Tests::try_blob_single_instruction(); -#endif - Tests::try_blob_many_instructions(); + // Tests::try_blob_single_move(); + // Tests::try_blob_many_moves(); + Tests::try_blob_more_moves(); - zpl_f64 end = zpl_time_rel(); - zpl_f64 ms = (end - start) * 100; + f64 end = zpl_time_rel(); + f64 ms = (end - start) * 100; printf("\n\nElapsed Time: %lf ms", ms); printf("\n\n"); diff --git a/part_1/tests/listing_0038_many_register_mov.out.asm b/part_1/tests/listing_0038_many_register_mov.out.asm index e017295..e75e952 100644 --- a/part_1/tests/listing_0038_many_register_mov.out.asm +++ b/part_1/tests/listing_0038_many_register_mov.out.asm @@ -1,12 +1,12 @@ bits 16 mov CX, BX -mov DH, CH +mov CH, AH mov DX, BX mov SI, BX mov BX, DI -mov CL, DL -mov DH, DH +mov AL, CL +mov CH, CH mov BX, AX mov BX, SI mov SP, DI diff --git a/part_1/tests/listing_0039_more_movs b/part_1/tests/listing_0039_more_movs new file mode 100644 index 0000000..405b804 Binary files /dev/null and b/part_1/tests/listing_0039_more_movs differ diff --git a/part_1/tests/listing_0039_more_movs.asm b/part_1/tests/listing_0039_more_movs.asm new file mode 100644 index 0000000..854fcb4 --- /dev/null +++ b/part_1/tests/listing_0039_more_movs.asm @@ -0,0 +1,47 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 39 +; ======================================================================== + +bits 16 + +; Register-to-register +mov si, bx +mov dh, al + +; 8-bit immediate-to-register +mov cl, 12 +mov ch, -12 + +; 16-bit immediate-to-register +mov cx, 12 +mov cx, -12 +mov dx, 3948 +mov dx, -3948 + +; Source address calculation +mov al, [bx + si] +mov bx, [bp + di] +mov dx, [bp] + +; Source address calculation plus 8-bit displacement +mov ah, [bx + si + 4] + +; Source address calculation plus 16-bit displacement +mov al, [bx + si + 4999] + +; Dest address calculation +mov [bx + di], cx +mov [bp + si], cl +mov [bp], ch diff --git a/part_1/tests/listing_0039_more_movs.asm.out.asm b/part_1/tests/listing_0039_more_movs.asm.out.asm new file mode 100644 index 0000000..22c116b --- /dev/null +++ b/part_1/tests/listing_0039_more_movs.asm.out.asm @@ -0,0 +1,43 @@ +bits 16 + +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), +INVALID VALUE PROVIDED (null), diff --git a/part_1/tests/listing_0040_challenge_movs b/part_1/tests/listing_0040_challenge_movs new file mode 100644 index 0000000..63b3ec5 Binary files /dev/null and b/part_1/tests/listing_0040_challenge_movs differ diff --git a/part_1/tests/listing_0040_challenge_movs.asm b/part_1/tests/listing_0040_challenge_movs.asm new file mode 100644 index 0000000..966e47a --- /dev/null +++ b/part_1/tests/listing_0040_challenge_movs.asm @@ -0,0 +1,38 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 40 +; ======================================================================== + +bits 16 + +; Signed displacements +mov ax, [bx + di - 37] +mov [si - 300], cx +mov dx, [bx - 32] + +; Explicit sizes +mov [bp + di], byte 7 +mov [di + 901], word 347 + +; Direct address +mov bp, [5] +mov bx, [3458] + +; Memory-to-accumulator test +mov ax, [2555] +mov ax, [16] + +; Accumulator-to-memory test +mov [2554], ax +mov [15], ax