From 67307e81b8c2d17093f7fde88c34b3eff141c2c6 Mon Sep 17 00:00:00 2001 From: doyle Date: Fri, 31 Mar 2023 23:33:11 +1100 Subject: [PATCH] perfaware/part1: Support listing 0045 --- part1/build.bat | 7 + part1/listing_0045_challenge_register_movs | 1 + .../listing_0045_challenge_register_movs.asm | 43 ++++ .../listing_0045_challenge_register_movs.txt | 35 ++++ part1/sim8086.c | 184 +++++++++++------- project.rdbg | Bin 2017 -> 1934 bytes 6 files changed, 196 insertions(+), 74 deletions(-) create mode 100644 part1/listing_0045_challenge_register_movs create mode 100644 part1/listing_0045_challenge_register_movs.asm create mode 100644 part1/listing_0045_challenge_register_movs.txt diff --git a/part1/build.bat b/part1/build.bat index d74f8dc..96b1faa 100644 --- a/part1/build.bat +++ b/part1/build.bat @@ -70,3 +70,10 @@ copy /Y %script_dir%\%listing_0044%.txt %build_dir% 1>NUL set build_dir_listing_0044=%build_dir%\%listing_0044% %build_dir%\sim8086.exe --exec %build_dir_listing_0044% > %build_dir_listing_0044%_disassembled.txt fc /N %build_dir_listing_0044%.txt %build_dir_listing_0044%_disassembled.txt || exit /b 1 + +set listing_0045=listing_0045_challenge_register_movs +copy /Y %script_dir%\%listing_0045% %build_dir% 1>NUL +copy /Y %script_dir%\%listing_0045%.txt %build_dir% 1>NUL +set build_dir_listing_0045=%build_dir%\%listing_0045% +%build_dir%\sim8086.exe --exec %build_dir_listing_0045% > %build_dir_listing_0045%_disassembled.txt +fc /N %build_dir_listing_0045%.txt %build_dir_listing_0045%_disassembled.txt || exit /b 1 diff --git a/part1/listing_0045_challenge_register_movs b/part1/listing_0045_challenge_register_movs new file mode 100644 index 0000000..dd781b2 --- /dev/null +++ b/part1/listing_0045_challenge_register_movs @@ -0,0 +1 @@ +¸""»DD¹ffºˆˆŽÐŽÛŽÁ°·3±U¶wˆÜˆñŽÐŽÛŽÁŒÔŒÝŒÆ‰× \ No newline at end of file diff --git a/part1/listing_0045_challenge_register_movs.asm b/part1/listing_0045_challenge_register_movs.asm new file mode 100644 index 0000000..9e25fda --- /dev/null +++ b/part1/listing_0045_challenge_register_movs.asm @@ -0,0 +1,43 @@ +; ======================================================================== +; +; (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 45 +; ======================================================================== + +bits 16 + +mov ax, 0x2222 +mov bx, 0x4444 +mov cx, 0x6666 +mov dx, 0x8888 + +mov ss, ax +mov ds, bx +mov es, cx + +mov al, 0x11 +mov bh, 0x33 +mov cl, 0x55 +mov dh, 0x77 + +mov ah, bl +mov cl, dh + +mov ss, ax +mov ds, bx +mov es, cx + +mov sp, ss +mov bp, ds +mov si, es +mov di, dx diff --git a/part1/listing_0045_challenge_register_movs.txt b/part1/listing_0045_challenge_register_movs.txt new file mode 100644 index 0000000..66c8c7b --- /dev/null +++ b/part1/listing_0045_challenge_register_movs.txt @@ -0,0 +1,35 @@ +--- test\listing_0045_challenge_register_movs execution --- +mov ax, 8738 ; ax:0x0->0x2222 +mov bx, 17476 ; bx:0x0->0x4444 +mov cx, 26214 ; cx:0x0->0x6666 +mov dx, 34952 ; dx:0x0->0x8888 +mov ss, ax ; ss:0x0->0x2222 +mov ds, bx ; ds:0x0->0x4444 +mov es, cx ; es:0x0->0x6666 +mov al, 17 ; ax:0x2222->0x2211 +mov bh, 51 ; bx:0x4444->0x3344 +mov cl, 85 ; cx:0x6666->0x6655 +mov dh, 119 ; dx:0x8888->0x7788 +mov ah, bl ; ax:0x2211->0x4411 +mov cl, dh ; cx:0x6655->0x6677 +mov ss, ax ; ss:0x2222->0x4411 +mov ds, bx ; ds:0x4444->0x3344 +mov es, cx ; es:0x6666->0x6677 +mov sp, ss ; sp:0x0->0x4411 +mov bp, ds ; bp:0x0->0x3344 +mov si, es ; si:0x0->0x6677 +mov di, dx ; di:0x0->0x7788 + +Final registers: + ax: 0x4411 (17425) + bx: 0x3344 (13124) + cx: 0x6677 (26231) + dx: 0x7788 (30600) + sp: 0x4411 (17425) + bp: 0x3344 (13124) + si: 0x6677 (26231) + di: 0x7788 (30600) + es: 0x6677 (26231) + ss: 0x4411 (17425) + ds: 0x3344 (13124) + diff --git a/part1/sim8086.c b/part1/sim8086.c index d6e5f33..e3206e3 100644 --- a/part1/sim8086.c +++ b/part1/sim8086.c @@ -8,10 +8,16 @@ typedef struct RegisterFile { uint16_t cx; uint16_t dx; uint16_t bx; + uint16_t sp; uint16_t bp; uint16_t si; uint16_t di; + + uint16_t es; + uint16_t cs; + uint16_t ss; + uint16_t ds; } RegisterFile; S86_Str8 S86_MnemonicStr8(S86_Mnemonic type) @@ -470,49 +476,64 @@ S86_Opcode S86_DecodeOpcode(S86_BufferIterator *buffer_it, case S86_OpDecodeType_LES: /*FALLTHRU*/ case S86_OpDecodeType_XCHGRegOrMemWithReg: /*FALLTHRU*/ case S86_OpDecodeType_CMPRegOrMemAndReg: /*FALLTHRU*/ - case S86_OpDecodeType_MOVRegOrMemToOrFromReg: { + case S86_OpDecodeType_MOVRegOrMemToOrFromReg: /*FALLTHRU*/ + case S86_OpDecodeType_MOVSegRegToRegOrMem: /*FALLTHRU*/ + case S86_OpDecodeType_MOVRegOrMemToSegReg: { // NOTE: Instruction does not have opcode bits in the 2nd byte - S86_ASSERT(op_code_size == 1); - op_code_bytes[op_code_size++] = S86_BufferIteratorNextByte(buffer_it); - - uint8_t w = (op_code_bytes[0] & 0b0000'0001) >> 0; - uint8_t d = (op_code_bytes[0] & 0b0000'0010) >> 1; - if (op_decode_type == S86_OpDecodeType_XCHGRegOrMemWithReg || - op_decode_type == S86_OpDecodeType_LEA || - op_decode_type == S86_OpDecodeType_LDS || - op_decode_type == S86_OpDecodeType_LES) { - d = 1; // Destintation is always the register - if (op_decode_type == S86_OpDecodeType_XCHGRegOrMemWithReg) { - if (*lock_prefix) { - // NOTE: When we XCHG, NASM complains that the - // instruction is not lockable, unless, the memory - // operand comes first. Here we flip the direction - // to ensure the memory operand is the destination. - // - // listing_0042_completionist_decode_disassembled.asm|319| warning: instruction is not lockable [-w+prefix-lock] - d = 0; - } - } else { - w = 1; // Always 16 bit (load into register) - } + if (op_decode_type == S86_OpDecodeType_MOVSegRegToRegOrMem || + op_decode_type == S86_OpDecodeType_MOVRegOrMemToSegReg) { + S86_ASSERT(op_code_size == 2); + } else { + S86_ASSERT(op_code_size == 1); + op_code_bytes[op_code_size++] = S86_BufferIteratorNextByte(buffer_it); } + uint8_t d = 0; uint8_t mod = (op_code_bytes[1] & 0b1100'0000) >> 6; - uint8_t reg = (op_code_bytes[1] & 0b0011'1000) >> 3; uint8_t rm = (op_code_bytes[1] & 0b0000'0111) >> 0; - S86_ASSERT(d < 2); - S86_ASSERT(w < 2); S86_ASSERT(mod < 4); - S86_ASSERT(reg < 8); S86_ASSERT(rm < 8); - result.wide = w; - result.src = S86_MnemonicOpFromWReg(result.wide, reg); + if (op_decode_type == S86_OpDecodeType_MOVRegOrMemToSegReg || + op_decode_type == S86_OpDecodeType_MOVSegRegToRegOrMem) { + uint8_t sr = (op_code_bytes[1] & 0b0001'1000) >> 3; + result.src = S86_MnemonicOpFromSR(sr); + result.wide = 1; + if (op_decode_type == S86_OpDecodeType_MOVRegOrMemToSegReg) + d = 1; + } else { + result.wide = (op_code_bytes[0] & 0b0000'0001) >> 0; + d = (op_code_bytes[0] & 0b0000'0010) >> 1; + if (op_decode_type == S86_OpDecodeType_XCHGRegOrMemWithReg || + op_decode_type == S86_OpDecodeType_LEA || + op_decode_type == S86_OpDecodeType_LDS || + op_decode_type == S86_OpDecodeType_LES) { + d = 1; // Destintation is always the register + if (op_decode_type == S86_OpDecodeType_XCHGRegOrMemWithReg) { + if (*lock_prefix) { + // NOTE: When we XCHG, NASM complains that the + // instruction is not lockable, unless, the memory + // operand comes first. Here we flip the direction + // to ensure the memory operand is the destination. + // + // listing_0042_completionist_decode_disassembled.asm|319| warning: instruction is not lockable [-w+prefix-lock] + d = 0; + } + } else { + result.wide = 1; // Always 16 bit (load into register) + } + } + + uint8_t reg = (op_code_bytes[1] & 0b0011'1000) >> 3; + result.src = S86_MnemonicOpFromWReg(result.wide, reg); + } + S86_ASSERT(result.wide < 2); + S86_ASSERT(d < 2); + if (mod == 0b11) { // NOTE: Register-to-register move result.dest = S86_MnemonicOpFromWReg(result.wide, rm); } else { // NOTE: Memory mode w/ effective address calculation - S86_DecodeEffectiveAddr(&result, buffer_it, rm, mod, w); - result.src = S86_MnemonicOpFromWReg(w, reg); + S86_DecodeEffectiveAddr(&result, buffer_it, rm, mod, result.wide); if (d) result.effective_addr = S86_EffectiveAddress_Src; else @@ -775,6 +796,15 @@ S86_Opcode S86_DecodeOpcode(S86_BufferIterator *buffer_it, return result; } +typedef struct S86_MnemonicOpToRegisterFileMap { + S86_MnemonicOp mnemonic_op; ///< Register/op that the mnemonic is using + S86_MnemonicOp mnemonic_op_reg16; ///< 16 bit register for the mnemonic op + uint16_t mask; ///< Mask for the bits that the mnemonic op is using (hi/lo/full bit coverage) + uint16_t r_shift; ///< Shift amount for isolating the masked value + uint16_t *reg; ///< Pointer to the register memory this mnemonic op is using +} S86_MnemonicOpToRegisterFileMap; + + #define PRINT_USAGE S86_PrintLn(S86_STR8("usage: sim8086.exe [--exec] ")) int main(int argc, char **argv) { @@ -1118,34 +1148,32 @@ int main(int argc, char **argv) S86_MnemonicOp seg_reg = {0}; bool lock_prefix = false; - typedef struct MnemonicOpToRegisterFileMap { - S86_MnemonicOp mnemonic_op; - uint16_t mask; - uint16_t r_shift; - uint16_t *reg; - } MnemonicOpToRegisterFileMap; + S86_MnemonicOpToRegisterFileMap mnemonic_op_to_register_file_map[] = { + {.mnemonic_op = S86_MnemonicOp_AX, .mnemonic_op_reg16 = S86_MnemonicOp_AX, .reg = ®ister_file.ax, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_AL, .mnemonic_op_reg16 = S86_MnemonicOp_AX, .reg = ®ister_file.ax, .mask = 0x00FF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_AH, .mnemonic_op_reg16 = S86_MnemonicOp_AX, .reg = ®ister_file.ax, .mask = 0xFF00, .r_shift = 8}, - MnemonicOpToRegisterFileMap mnemonic_op_to_register_file_map[] = { - {.mnemonic_op = S86_MnemonicOp_AX, .reg = ®ister_file.ax, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_AL, .reg = ®ister_file.ax, .mask = 0x00FF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_AH, .reg = ®ister_file.ax, .mask = 0xFF00, .r_shift = 8}, + {.mnemonic_op = S86_MnemonicOp_CX, .mnemonic_op_reg16 = S86_MnemonicOp_CX, .reg = ®ister_file.cx, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_CL, .mnemonic_op_reg16 = S86_MnemonicOp_CX, .reg = ®ister_file.cx, .mask = 0x00FF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_CH, .mnemonic_op_reg16 = S86_MnemonicOp_CX, .reg = ®ister_file.cx, .mask = 0xFF00, .r_shift = 8}, - {.mnemonic_op = S86_MnemonicOp_CX, .reg = ®ister_file.cx, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_CL, .reg = ®ister_file.cx, .mask = 0x00FF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_CH, .reg = ®ister_file.cx, .mask = 0xFF00, .r_shift = 8}, + {.mnemonic_op = S86_MnemonicOp_DX, .mnemonic_op_reg16 = S86_MnemonicOp_DX, .reg = ®ister_file.dx, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_DL, .mnemonic_op_reg16 = S86_MnemonicOp_DX, .reg = ®ister_file.dx, .mask = 0x00FF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_DH, .mnemonic_op_reg16 = S86_MnemonicOp_DX, .reg = ®ister_file.dx, .mask = 0xFF00, .r_shift = 8}, - {.mnemonic_op = S86_MnemonicOp_DX, .reg = ®ister_file.dx, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_DL, .reg = ®ister_file.dx, .mask = 0x00FF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_DH, .reg = ®ister_file.dx, .mask = 0xFF00, .r_shift = 8}, + {.mnemonic_op = S86_MnemonicOp_BX, .mnemonic_op_reg16 = S86_MnemonicOp_BX, .reg = ®ister_file.bx, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_BL, .mnemonic_op_reg16 = S86_MnemonicOp_BX, .reg = ®ister_file.bx, .mask = 0x00FF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_BH, .mnemonic_op_reg16 = S86_MnemonicOp_BX, .reg = ®ister_file.bx, .mask = 0xFF00, .r_shift = 8}, - {.mnemonic_op = S86_MnemonicOp_BX, .reg = ®ister_file.bx, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_BL, .reg = ®ister_file.bx, .mask = 0x00FF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_BH, .reg = ®ister_file.bx, .mask = 0xFF00, .r_shift = 8}, + {.mnemonic_op = S86_MnemonicOp_SP, .mnemonic_op_reg16 = S86_MnemonicOp_SP, .reg = ®ister_file.sp, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_BP, .mnemonic_op_reg16 = S86_MnemonicOp_BP, .reg = ®ister_file.bp, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_SI, .mnemonic_op_reg16 = S86_MnemonicOp_SI, .reg = ®ister_file.si, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_DI, .mnemonic_op_reg16 = S86_MnemonicOp_DI, .reg = ®ister_file.di, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_SP, .reg = ®ister_file.sp, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_BP, .reg = ®ister_file.bp, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_SI, .reg = ®ister_file.si, .mask = 0xFFFF, .r_shift = 0}, - {.mnemonic_op = S86_MnemonicOp_DI, .reg = ®ister_file.di, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_ES, .mnemonic_op_reg16 = S86_MnemonicOp_ES, .reg = ®ister_file.es, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_CS, .mnemonic_op_reg16 = S86_MnemonicOp_CS, .reg = ®ister_file.cs, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_SS, .mnemonic_op_reg16 = S86_MnemonicOp_SS, .reg = ®ister_file.ss, .mask = 0xFFFF, .r_shift = 0}, + {.mnemonic_op = S86_MnemonicOp_DS, .mnemonic_op_reg16 = S86_MnemonicOp_DS, .reg = ®ister_file.ds, .mask = 0xFFFF, .r_shift = 0}, }; while (S86_BufferIteratorHasMoreBytes(buffer_it)) { @@ -1159,33 +1187,35 @@ int main(int argc, char **argv) continue; if (exec_mode && opcode.mnemonic == S86_Mnemonic_MOV) { - MnemonicOpToRegisterFileMap const *dest_map = NULL; + S86_MnemonicOpToRegisterFileMap const *dest_map = NULL; for (size_t index = 0; !dest_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) { - MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index; + S86_MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index; if (item->mnemonic_op == opcode.dest) dest_map = item; } - if (dest_map) { - uint16_t *dest = dest_map->reg; - if (opcode.src == S86_MnemonicOp_Immediate) { - S86_Str8 mnemonic_op = S86_MnemonicOpStr8(dest_map->mnemonic_op); - S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(mnemonic_op), *dest, opcode.immediate); - *dest = (uint16_t)opcode.immediate; - } else if (opcode.src >= S86_MnemonicOp_AX && opcode.src <= S86_MnemonicOp_DI) { - MnemonicOpToRegisterFileMap const *src_map = NULL; - for (size_t index = 0; !src_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) { - MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index; - if (item->mnemonic_op == opcode.src) - src_map = item; - } + S86_ASSERT(dest_map); + uint16_t *dest = dest_map->reg; + uint16_t src = 0; - S86_Str8 dest_op = S86_MnemonicOpStr8(dest_map->mnemonic_op); - uint16_t *src = src_map->reg; - S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(dest_op), *dest, *src); - *dest = *src; + if (opcode.src == S86_MnemonicOp_Immediate) { + src = (uint16_t)opcode.immediate; + } else if ((opcode.src >= S86_MnemonicOp_AL && opcode.src <= S86_MnemonicOp_DI) || + (opcode.src >= S86_MnemonicOp_ES && opcode.src <= S86_MnemonicOp_DS)) { + S86_MnemonicOpToRegisterFileMap const *src_map = NULL; + for (size_t index = 0; !src_map && index < S86_ARRAY_UCOUNT(mnemonic_op_to_register_file_map); index++) { + S86_MnemonicOpToRegisterFileMap const *item = mnemonic_op_to_register_file_map + index; + if (item->mnemonic_op == opcode.src) + src_map = item; } + + src = (*src_map->reg & src_map->mask) >> src_map->r_shift; } + + S86_Str8 dest_reg16 = S86_MnemonicOpStr8(dest_map->mnemonic_op_reg16); + uint16_t new_dest = (*dest & ~dest_map->mask) | (src << dest_map->r_shift); + S86_PrintFmt(" ; %.*s:0x%x->0x%x ", S86_STR8_FMT(dest_reg16), *dest, new_dest); + *dest = new_dest; } S86_Print(S86_STR8("\n")); } @@ -1200,6 +1230,12 @@ int main(int argc, char **argv) S86_PrintLnFmt(" bp: 0x%04x (%u)", register_file.bp, register_file.bp); S86_PrintLnFmt(" si: 0x%04x (%u)", register_file.si, register_file.si); S86_PrintLnFmt(" di: 0x%04x (%u)", register_file.di, register_file.di); + if (register_file.es) + S86_PrintLnFmt(" es: 0x%04x (%u)", register_file.es, register_file.es); + if (register_file.ss) + S86_PrintLnFmt(" ss: 0x%04x (%u)", register_file.ss, register_file.ss); + if (register_file.ds) + S86_PrintLnFmt(" ds: 0x%04x (%u)", register_file.ds, register_file.ds); S86_Print(S86_STR8("\n")); } } diff --git a/project.rdbg b/project.rdbg index b89ca4433ac9cdf5536bff4217294a222b6efc37..4d5acbb623b36e4b195630193fe32b6f14c9912f 100644 GIT binary patch delta 216 zcmaFJ-^V{;10(CkjjoInb6m`Ju`n<&F)%Q20C7rcaY=k`VgW0VotBxGm;++4asNC5 z!Xkz5SAwu~>65>#lLOgg7&#|Lv$$_Q!yL>sIgZ7JQE~D|R#7gK_@dPG%;J*NqR9a) zL5$iUL1okUS&~}J0u)F|EJ*}OXk_M<7@EbG zXo3V7fdb_`NXm;dt5QKmWabr@6qP2IWaj6^msA#{s)2L{TbRXrA|yh9;+n_`GxJjF zQ!7k>NM&5C%FZwF0D?4X8S?I5$4OfD_0{%gjlQ&r8e&`xMM6NG!>S zhNy-s0Er1At5(of04o87CL8z9BOokN_