From 82fb58e6068f3718fe7cedd1cde1b405308bbbab Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 12 May 2019 22:41:19 -0700 Subject: CF needs special handling for some arithmetic ops Inline some macro definitions. --- subx/011run.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'subx/011run.cc') diff --git a/subx/011run.cc b/subx/011run.cc index 6b18ca06..ccc891c3 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -355,9 +355,21 @@ put_new(Name, "05", "add imm32 to EAX (add)"); //: our first opcode :(before "End Single-Byte Opcodes") case 0x05: { // add imm32 to EAX - int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << arg2 << " to reg EAX" << end(); - BINARY_ARITHMETIC_OP(+, Reg[EAX].i, arg2); + int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); + int64_t signed_full_result = Reg[EAX].i + signed_arg2; + Reg[EAX].i += signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i < 0); + ZF = (Reg[EAX].i == 0); + OF = (Reg[EAX].i != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(Reg[EAX].i); + uint32_t unsigned_arg2 = static_cast(signed_arg2); + uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; + uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } -- cgit 1.4.1-2-gfad0 From 3f2c4fc564fc7169bb64107b5b7655d76c98204c Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 07:53:31 -0700 Subject: . Make the first instruction described something that doesn't touch flags, so we don't introduce too much complexity all at once. --- subx/011run.cc | 44 ++++++++++++++++++++--------------------- subx/015immediate_addressing.cc | 26 ++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 24 deletions(-) (limited to 'subx/011run.cc') diff --git a/subx/011run.cc b/subx/011run.cc index ccc891c3..9c1bc4b0 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -65,19 +65,18 @@ void test_add_imm32_to_eax() { // opcode ModR/M SIB displacement immediate // instruction mod, reg, Reg/Mem bits scale, index, base // 1-3 bytes 0/1 byte 0/1 byte 0/1/2/4 bytes 0/1/2/4 bytes - " 05 . . . 0a 0b 0c 0d\n" // add 0x0d0c0b0a to EAX + " b8 . . . 0a 0b 0c 0d\n" // copy 0x0d0c0b0a to EAX // The periods are just to help the eye track long gaps between columns, // and are otherwise ignored. ); // This program, when run, causes the following events in the trace: CHECK_TRACE_CONTENTS( - "load: 0x00000001 -> 05\n" + "load: 0x00000001 -> b8\n" "load: 0x00000002 -> 0a\n" "load: 0x00000003 -> 0b\n" "load: 0x00000004 -> 0c\n" "load: 0x00000005 -> 0d\n" - "run: add imm32 0x0d0c0b0a to reg EAX\n" - "run: storing 0x0d0c0b0a\n" + "run: copy imm32 0x0d0c0b0a to EAX\n" ); } @@ -350,29 +349,30 @@ void parse_and_load(const string& text_bytes) { //:: run :(before "End Initialize Op Names") -put_new(Name, "05", "add imm32 to EAX (add)"); +put_new(Name, "b8", "copy imm32 to EAX (mov)"); -//: our first opcode :(before "End Single-Byte Opcodes") -case 0x05: { // add imm32 to EAX - int32_t signed_arg2 = next32(); - trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); - int64_t signed_full_result = Reg[EAX].i + signed_arg2; - Reg[EAX].i += signed_arg2; - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); - SF = (Reg[EAX].i < 0); - ZF = (Reg[EAX].i == 0); - OF = (Reg[EAX].i != signed_full_result); - // set CF - uint32_t unsigned_arg1 = static_cast(Reg[EAX].i); - uint32_t unsigned_arg2 = static_cast(signed_arg2); - uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; - uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; - CF = (unsigned_result != unsigned_full_result); - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); +case 0xb8: { // copy imm32 to EAX + const int32_t src = next32(); + trace(Callstack_depth+1, "run") << "copy imm32 0x" << HEXWORD << src << " to EAX" << end(); + Reg[EAX].i = src; break; } +:(code) +void test_copy_imm32_to_EAX() { + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " b8 0a 0b 0c 0d \n" // copy 0x0d0c0b0a to EAX + ); + CHECK_TRACE_CONTENTS( + "run: copy imm32 0x0d0c0b0a to EAX\n" + ); +} + +//: our first opcode + :(code) // read a 32-bit int in little-endian order from the instruction stream int32_t next32() { diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 8a0ba020..f4762c2b 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -1,5 +1,28 @@ //: instructions that (immediately) contain an argument to act with +:(before "End Initialize Op Names") +put_new(Name, "05", "add imm32 to EAX (add)"); + +:(before "End Single-Byte Opcodes") +case 0x05: { // add imm32 to EAX + int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); + int64_t signed_full_result = Reg[EAX].i + signed_arg2; + Reg[EAX].i += signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i < 0); + ZF = (Reg[EAX].i == 0); + OF = (Reg[EAX].i != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(Reg[EAX].i); + uint32_t unsigned_arg2 = static_cast(signed_arg2); + uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; + uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); + break; +} + :(before "End Initialize Op Names") put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)"); @@ -832,7 +855,7 @@ void test_compare_imm32_with_mem_at_r32_equal() { //:: copy (mov) :(before "End Initialize Op Names") -put_new(Name, "b8", "copy imm32 to EAX (mov)"); +// b8 defined earlier to copy imm32 to EAX put_new(Name, "b9", "copy imm32 to ECX (mov)"); put_new(Name, "ba", "copy imm32 to EDX (mov)"); put_new(Name, "bb", "copy imm32 to EBX (mov)"); @@ -854,7 +877,6 @@ void test_copy_imm32_to_r32() { } :(before "End Single-Byte Opcodes") -case 0xb8: case 0xb9: case 0xba: case 0xbb: -- cgit 1.4.1-2-gfad0 From 59a04f794f45864fe0901a9747ca24cfc41a9bb4 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 12:38:36 -0700 Subject: . --- subx/011run.cc | 2 +- subx/013direct_addressing.cc | 10 +++++----- subx/015immediate_addressing.cc | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'subx/011run.cc') diff --git a/subx/011run.cc b/subx/011run.cc index 9c1bc4b0..d949f87e 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -35,7 +35,7 @@ put_new(Help, "syntax", cerr << " syntax\n"; :(code) -void test_add_imm32_to_eax() { +void test_add_imm32_to_EAX() { // At the lowest level, SubX programs are a series of hex bytes, each // (variable-length) instruction on one line. run( diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index d4dcd92a..a2331213 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -249,7 +249,7 @@ void test_subtract_r32_from_r32_signed_and_unsigned_overflow() { put_new(Name, "f7", "negate/multiply/divide rm32 (with EAX and EDX if necessary) depending on subop (neg/mul/idiv)"); :(code) -void test_multiply_eax_by_r32() { +void test_multiply_EAX_by_r32() { Reg[EAX].i = 4; Reg[ECX].i = 3; run( @@ -388,7 +388,7 @@ void test_negate_can_overflow() { //:: divide with remainder -void test_divide_eax_by_rm32() { +void test_divide_EAX_by_rm32() { Reg[EAX].u = 7; Reg[EDX].u = 0; Reg[ECX].i = 3; @@ -422,7 +422,7 @@ case 7: { // divide EDX:EAX by r/m32, storing quotient in EAX and remainder in } :(code) -void test_divide_eax_by_negative_rm32() { +void test_divide_EAX_by_negative_rm32() { Reg[EAX].u = 7; Reg[EDX].u = 0; Reg[ECX].i = -3; @@ -441,7 +441,7 @@ void test_divide_eax_by_negative_rm32() { ); } -void test_divide_negative_eax_by_rm32() { +void test_divide_negative_EAX_by_rm32() { Reg[EAX].i = -7; Reg[EDX].i = -1; // sign extend Reg[ECX].i = 3; @@ -460,7 +460,7 @@ void test_divide_negative_eax_by_rm32() { ); } -void test_divide_negative_edx_eax_by_rm32() { +void test_divide_negative_EDX_EAX_by_rm32() { Reg[EAX].i = 0; // lower 32 bits are clear Reg[EDX].i = -7; Reg[ECX].i = 0x40000000; // 2^30 (largest positive power of 2) diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 959482cb..6682bc6d 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -211,7 +211,7 @@ void test_add_imm32_to_mem_at_r32() { put_new(Name, "2d", "subtract imm32 from EAX (sub)"); :(code) -void test_subtract_imm32_from_eax() { +void test_subtract_imm32_from_EAX() { Reg[EAX].i = 0x0d0c0baa; run( "== 0x1\n" // code segment @@ -612,7 +612,7 @@ void test_shift_right_logical_negative_r32_with_imm8() { put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)"); :(code) -void test_and_imm32_with_eax() { +void test_and_imm32_with_EAX() { Reg[EAX].i = 0xff; run( "== 0x1\n" // code segment @@ -704,7 +704,7 @@ void test_and_imm32_with_r32() { put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)"); :(code) -void test_or_imm32_with_eax() { +void test_or_imm32_with_EAX() { Reg[EAX].i = 0xd0c0b0a0; run( "== 0x1\n" // code segment @@ -794,7 +794,7 @@ void test_or_imm32_with_r32() { put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)"); :(code) -void test_xor_imm32_with_eax() { +void test_xor_imm32_with_EAX() { Reg[EAX].i = 0xddccb0a0; run( "== 0x1\n" // code segment @@ -884,7 +884,7 @@ void test_xor_imm32_with_r32() { put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)"); :(code) -void test_compare_imm32_with_eax_greater() { +void test_compare_imm32_with_EAX_greater() { Reg[EAX].i = 0x0d0c0b0a; run( "== 0x1\n" // code segment @@ -917,7 +917,7 @@ case 0x3d: { // compare EAX with imm32 } :(code) -void test_compare_eax_with_imm32_lesser() { +void test_compare_EAX_with_imm32_lesser() { Reg[EAX].i = 0x0d0c0b07; run( "== 0x1\n" // code segment @@ -930,7 +930,7 @@ void test_compare_eax_with_imm32_lesser() { ); } -void test_compare_imm32_with_eax_equal() { +void test_compare_imm32_with_EAX_equal() { Reg[EAX].i = 0x0d0c0b0a; run( "== 0x1\n" // code segment -- cgit 1.4.1-2-gfad0 From 8a69bf9883985411653f766de0f28928ac844ccc Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 12:40:24 -0700 Subject: . --- subx/011run.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'subx/011run.cc') diff --git a/subx/011run.cc b/subx/011run.cc index d949f87e..236401b8 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -351,6 +351,8 @@ void parse_and_load(const string& text_bytes) { :(before "End Initialize Op Names") put_new(Name, "b8", "copy imm32 to EAX (mov)"); +//: our first opcode + :(before "End Single-Byte Opcodes") case 0xb8: { // copy imm32 to EAX const int32_t src = next32(); @@ -371,9 +373,6 @@ void test_copy_imm32_to_EAX() { ); } -//: our first opcode - -:(code) // read a 32-bit int in little-endian order from the instruction stream int32_t next32() { int32_t result = read_mem_i32(EIP); -- cgit 1.4.1-2-gfad0