diff --git a/part1/build.bat b/part1/build.bat index 296e243..f995686 100644 --- a/part1/build.bat +++ b/part1/build.bat @@ -34,3 +34,8 @@ set listing_0039=%build_dir%\listing_0039_more_movs %build_dir%\sim8086.exe %listing_0039% > %listing_0039%_disassembled.asm nasm %listing_0039%_disassembled.asm fc %listing_0039% %listing_0039%_disassembled || exit /b 1 + +set listing_0040=%build_dir%\listing_0040_challenge_movs +%build_dir%\sim8086.exe %listing_0040% > %listing_0040%_disassembled.asm +nasm %listing_0040%_disassembled.asm +fc %listing_0040% %listing_0040%_disassembled || exit /b 1 diff --git a/part1/sim8086.c b/part1/sim8086.c index 3e97dc2..602a5c1 100644 --- a/part1/sim8086.c +++ b/part1/sim8086.c @@ -403,17 +403,16 @@ int main(int argc, char **argv) } else { // NOTE: Memory mode w/ effective address calculation // ========================================================= + bool direct_address = mod == 0b00 && rm == 0b110; uint16_t displacement = 0; - if (mod == 0b01) { // Mem mode 8 bit displacement - displacement = S86_BufferIteratorNextByte(&buffer_it); - } else if (mod == 0b10 || (mod == 0b00 && rm == 0b110)) { // Mem mode 16 bit displacement + if (mod == 0b10 || direct_address) { // Mem mode 16 bit displacement uint8_t disp_lo = S86_BufferIteratorNextByte(&buffer_it); uint8_t disp_hi = S86_BufferIteratorNextByte(&buffer_it); displacement = (uint16_t)disp_lo << 0 | (uint16_t)disp_hi << 8; + } else if (mod == 0b01) { // Mem mode 8 bit displacement + displacement = S86_BufferIteratorNextByte(&buffer_it); } else { S86_ASSERT(mod == 0b00 /*Mem mode (no displacement)*/); - if (mod == 0b00) - S86_ASSERT(rm != 0b110 && "16 bit displacement should be handled in (mod == 0b10) branch"); } // NOTE: Generate the effective address calculation string @@ -422,6 +421,101 @@ int main(int argc, char **argv) int effective_addr_size = 0; effective_addr_buffer[effective_addr_size++] = '['; + if (direct_address) { + effective_addr_size += snprintf(effective_addr_buffer + effective_addr_size, + sizeof(effective_addr_buffer) - effective_addr_size, + "%u", + displacement); + } else { + if (rm == 0b110) { + effective_addr_buffer[effective_addr_size++] = 'b'; + effective_addr_buffer[effective_addr_size++] = 'p'; + if (displacement) { + effective_addr_size += snprintf(effective_addr_buffer + effective_addr_size, + sizeof(effective_addr_buffer) - effective_addr_size, + " + %u", + displacement); + } + } else { + S86_Str8 base_calc = {0}; + switch (rm) { + case 0b000: base_calc = S86_STR8("bx + si"); break; + case 0b001: base_calc = S86_STR8("bx + di"); break; + case 0b010: base_calc = S86_STR8("bp + si"); break; + case 0b011: base_calc = S86_STR8("bp + di"); break; + case 0b100: base_calc = S86_STR8("si"); break; + case 0b101: base_calc = S86_STR8("di"); break; + case 0b111: base_calc = S86_STR8("bx"); break; + default: S86_ASSERT(!"Invalid rm value, must be 3 bits"); break; + } + + memcpy(effective_addr_buffer + effective_addr_size, base_calc.data, base_calc.size); + effective_addr_size += S86_CAST(int)base_calc.size; + + if (mod == 0b01 || mod == 0b10) { + effective_addr_size += snprintf(effective_addr_buffer + effective_addr_size, + sizeof(effective_addr_buffer) - effective_addr_size, + " + %u", + displacement); + } + } + } + effective_addr_buffer[effective_addr_size++] = ']'; + + // NOTE: Disassemble + // ========================================================= + S86_Str8 effective_addr = { .data = effective_addr_buffer, .size = effective_addr_size }; + S86_Str8 dest_op = d ? REGISTER_FIELD_ENCODING[w][reg] : effective_addr; + S86_Str8 src_op = d ? effective_addr : REGISTER_FIELD_ENCODING[w][reg]; + S86_PrintLnFmt("mov %.*s, %.*s", S86_STR8_FMT(dest_op), S86_STR8_FMT(src_op)); + } + + } break; + + case S86_InstructionType_MOVImmediateToRegOrMem: { + S86_ASSERT(op_code_size == 2); + uint8_t w = (op_code_bytes[0] & 0b0000'0001) >> 0; + uint8_t mod = (op_code_bytes[1] & 0b1100'0000) >> 6; + uint8_t rm = (op_code_bytes[1] & 0b0000'0111) >> 0; + S86_ASSERT(w < 2); + S86_ASSERT(mod < 4); + S86_ASSERT(rm < 8); + S86_ASSERT(mod != 0b11); // NOTE: Op is IMM->Reg, register-to-register not permitted + + // NOTE: Memory mode w/ effective address calculation + // ========================================================= + bool direct_address = mod == 0b00 && rm == 0b110; + uint16_t displacement = 0; + if (mod == 0b10 || direct_address) { // Mem mode 16 bit displacement + uint8_t disp_lo = S86_BufferIteratorNextByte(&buffer_it); + uint8_t disp_hi = S86_BufferIteratorNextByte(&buffer_it); + displacement = (uint16_t)disp_lo << 0 | (uint16_t)disp_hi << 8; + } else if (mod == 0b01) { // Mem mode 8 bit displacement + displacement = S86_BufferIteratorNextByte(&buffer_it); + } else { + S86_ASSERT(mod == 0b00 /*Mem mode (no displacement)*/); + } + + // NOTE: Parse data payload + // ============================================================= + uint16_t data = S86_BufferIteratorNextByte(&buffer_it); + if (w) { // 16 bit data + uint8_t data_hi = S86_BufferIteratorNextByte(&buffer_it); + data |= (uint16_t)(data_hi) << 8; + } + + // NOTE: Generate the effective address calculation string + // ========================================================= + char effective_addr_buffer[64] = {0}; + int effective_addr_size = 0; + + effective_addr_buffer[effective_addr_size++] = '['; + if (direct_address) { + effective_addr_size += snprintf(effective_addr_buffer + effective_addr_size, + sizeof(effective_addr_buffer) - effective_addr_size, + "%u", + displacement); + } else { if (rm == 0b110) { effective_addr_buffer[effective_addr_size++] = 'b'; effective_addr_buffer[effective_addr_size++] = 'p'; @@ -454,26 +548,12 @@ int main(int argc, char **argv) displacement); } } - effective_addr_buffer[effective_addr_size++] = ']'; - - // NOTE: Disassemble - // ========================================================= - S86_Str8 effective_addr = { .data = effective_addr_buffer, .size = effective_addr_size }; - S86_Str8 dest_op = d ? REGISTER_FIELD_ENCODING[w][reg] : effective_addr; - S86_Str8 src_op = d ? effective_addr : REGISTER_FIELD_ENCODING[w][reg]; - S86_PrintLnFmt("mov %.*s, %.*s", S86_STR8_FMT(dest_op), S86_STR8_FMT(src_op)); } + effective_addr_buffer[effective_addr_size++] = ']'; - } break; - - case S86_InstructionType_MOVImmediateToRegOrMem: { - S86_ASSERT(op_code_size == 2); - #if 0 - uint8_t w = (op_code_bytes[0] & 0b0000'0001) >> 0; - uint8_t mod = (op_code_bytes[1] & 0b1100'0000) >> 6; - uint8_t rm = (op_code_bytes[1] & 0b0000'0111) >> 0; - #endif - S86_ASSERT(!"Unhandled instruction"); + // NOTE: Disassemble + // ========================================================= + S86_PrintLnFmt("mov %.*s, %s %u", effective_addr_size, effective_addr_buffer, w ? "word" : "byte", data); } break; case S86_InstructionType_MOVImmediateToReg: { @@ -497,12 +577,21 @@ int main(int argc, char **argv) S86_PrintLnFmt("mov %.*s, %d", S86_STR8_FMT(dest_register), (int16_t)data); } break; + case S86_InstructionType_MOVAccumToMem: /*FALLTHRU*/ case S86_InstructionType_MOVMemToAccum: { - S86_ASSERT(!"Unhandled instruction"); - } break; + S86_ASSERT(op_code_size == 1); + uint16_t addr_lo = S86_BufferIteratorNextByte(&buffer_it); + uint16_t addr_hi = S86_BufferIteratorNextByte(&buffer_it); + uint16_t addr = (addr_hi << 8) | (addr_lo << 0); - case S86_InstructionType_MOVAccumToMem: { - S86_ASSERT(!"Unhandled instruction"); + S86_Str8 fmt = {0}; + if (instruction_type == S86_InstructionType_MOVAccumToMem) { + fmt = S86_STR8("mov [%u], ax"); + } else { + S86_ASSERT(instruction_type == S86_InstructionType_MOVMemToAccum); + fmt = S86_STR8("mov ax, [%u]"); + } + S86_PrintLnFmt(fmt.data, addr); } break; case S86_InstructionType_MOVRegOrMemToSegReg: { diff --git a/project.rdbg b/project.rdbg index 7827ab4..f789832 100644 Binary files a/project.rdbg and b/project.rdbg differ