diff options
-rw-r--r-- | 017jump_disp8.cc | 2 | ||||
-rw-r--r-- | 018jump_disp32.cc | 2 | ||||
-rw-r--r-- | 021byte_addressing.cc | 102 | ||||
-rw-r--r-- | 033check_operands.cc | 11 | ||||
-rwxr-xr-x | apps/ex13 | bin | 0 -> 211 bytes | |||
-rw-r--r-- | apps/ex13.subx | 25 | ||||
-rwxr-xr-x | apps/mu | bin | 177228 -> 177213 bytes | |||
-rw-r--r-- | apps/mu.subx | 28 | ||||
-rw-r--r-- | subx_opcodes | 12 | ||||
-rwxr-xr-x | test_apps | 12 |
10 files changed, 168 insertions, 26 deletions
diff --git a/017jump_disp8.cc b/017jump_disp8.cc index d7558401..47a94ea9 100644 --- a/017jump_disp8.cc +++ b/017jump_disp8.cc @@ -105,7 +105,7 @@ void test_jne_disp8_success() { } :(before "End Single-Byte Opcodes") -case 0x75: { // jump disp8 unless ZF +case 0x75: { // jump disp8 if !ZF const int8_t offset = static_cast<int>(next()); if (!ZF) { trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); diff --git a/018jump_disp32.cc b/018jump_disp32.cc index 1ac4f9ec..c39da70e 100644 --- a/018jump_disp32.cc +++ b/018jump_disp32.cc @@ -105,7 +105,7 @@ void test_jne_disp32_success() { } :(before "End Two-Byte Opcodes Starting With 0f") -case 0x85: { // jump disp32 unless ZF +case 0x85: { // jump disp32 if !ZF const int32_t offset = next32(); if (!ZF) { trace(Callstack_depth+1, "run") << "jump " << offset << end(); diff --git a/021byte_addressing.cc b/021byte_addressing.cc index 36287e38..4af81c3e 100644 --- a/021byte_addressing.cc +++ b/021byte_addressing.cc @@ -66,7 +66,7 @@ case 0x88: { // copy r8 to r/m8 const uint8_t rsrc = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "copy " << rname_8bit(rsrc) << " to r8/m8-at-r32" << end(); // use unsigned to zero-extend 8-bit value to 32 bits - uint8_t* dest = reinterpret_cast<uint8_t*>(effective_byte_address(modrm)); + uint8_t* dest = effective_byte_address(modrm); const uint8_t* src = reg_8bit(rsrc); *dest = *src; // Read/write multiple elements of vector<uint8_t> at once. Assumes sizeof(int) == 4 on the host as well. trace(Callstack_depth+1, "run") << "storing 0x" << HEXBYTE << NUM(*dest) << end(); @@ -105,7 +105,7 @@ case 0x8a: { // copy r/m8 to r8 const uint8_t rdest = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "copy r8/m8-at-r32 to " << rname_8bit(rdest) << end(); // use unsigned to zero-extend 8-bit value to 32 bits - const uint8_t* src = reinterpret_cast<uint8_t*>(effective_byte_address(modrm)); + const uint8_t* src = effective_byte_address(modrm); uint8_t* dest = reg_8bit(rdest); trace(Callstack_depth+1, "run") << "storing 0x" << HEXBYTE << NUM(*src) << end(); *dest = *src; // Read/write multiple elements of vector<uint8_t> at once. Assumes sizeof(int) == 4 on the host as well. @@ -169,8 +169,104 @@ case 0xc6: { // copy imm8 to r/m8 exit(1); } // use unsigned to zero-extend 8-bit value to 32 bits - uint8_t* dest = reinterpret_cast<uint8_t*>(effective_byte_address(modrm)); + uint8_t* dest = effective_byte_address(modrm); *dest = src; // Write multiple elements of vector<uint8_t> at once. Assumes sizeof(int) == 4 on the host as well. trace(Callstack_depth+1, "run") << "storing 0x" << HEXBYTE << NUM(*dest) << end(); break; } + +//:: set flags (setcc) + +:(before "End Initialize Op Names") +put_new(Name_0f, "94", "set r8/m8-at-rm32 to 1 if equal, if ZF is set, 0 otherwise (setcc/setz/sete)"); +put_new(Name_0f, "95", "set r8/m8-at-rm32 to 1 if not equal, if ZF is not set, 0 otherwise (setcc/setnz/setne)"); +put_new(Name_0f, "9f", "set r8/m8-at-rm32 to 1 if greater (signed), if ZF is unset and SF == OF, 0 otherwise (setcc/setg/setnle)"); +put_new(Name_0f, "97", "set r8/m8-at-rm32 to 1 if greater (unsigned), if ZF is unset and CF is unset, 0 otherwise (setcc/seta/setnbe)"); +put_new(Name_0f, "9d", "set r8/m8-at-rm32 to 1 if greater or equal (signed), if SF == OF, 0 otherwise (setcc/setge/setnl)"); +put_new(Name_0f, "93", "set r8/m8-at-rm32 to 1 if greater or equal (unsigned), if CF is unset, 0 otherwise (setcc/setae/setnb)"); +put_new(Name_0f, "9c", "set r8/m8-at-rm32 to 1 if lesser (signed), if SF != OF, 0 otherwise (setcc/setl/setnge)"); +put_new(Name_0f, "92", "set r8/m8-at-rm32 to 1 if lesser (unsigned), if CF is set, 0 otherwise (setcc/setb/setnae)"); +put_new(Name_0f, "9e", "set r8/m8-at-rm32 to 1 if lesser or equal (signed), if ZF is set or SF != OF, 0 otherwise (setcc/setle/setng)"); +put_new(Name_0f, "96", "set r8/m8-at-rm32 to 1 if lesser or equal (unsigned), if ZF is set or CF is set, 0 otherwise (setcc/setbe/setna)"); + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x94: { // set r8/m8-at-rm32 if ZF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = ZF; + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x95: { // set r8/m8-at-rm32 if !ZF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = !ZF; + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x9f: { // set r8/m8-at-rm32 if !SF and !ZF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = !ZF && SF == OF; + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x97: { // set r8/m8-at-rm32 if !CF and !ZF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = (!CF && !ZF); + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x9d: { // set r8/m8-at-rm32 if !SF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = (SF == OF); + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x93: { // set r8/m8-at-rm32 if !CF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = !CF; + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x9c: { // set r8/m8-at-rm32 if SF and !ZF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = (SF != OF); + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x92: { // set r8/m8-at-rm32 if CF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = CF; + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x9e: { // set r8/m8-at-rm32 if SF or ZF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = (ZF || SF != OF); + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} +case 0x96: { // set r8/m8-at-rm32 if ZF or CF + const uint8_t modrm = next(); + trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); + uint8_t* dest = effective_byte_address(modrm); + *dest = (ZF || CF); + trace(Callstack_depth+1, "run") << "storing " << *dest << end(); + break; +} diff --git a/033check_operands.cc b/033check_operands.cc index f5959dbe..04492986 100644 --- a/033check_operands.cc +++ b/033check_operands.cc @@ -649,6 +649,17 @@ put_new(Permitted_operands_0f, "8f", 0x10); // imm32 imm8 disp32 |disp16 disp8 subop modrm // 0 0 0 |0 0 0 1 put_new(Permitted_operands_0f, "af", 0x01); +// setcc +put_new(Permitted_operands_0f, "92", 0x01); +put_new(Permitted_operands_0f, "93", 0x01); +put_new(Permitted_operands_0f, "94", 0x01); +put_new(Permitted_operands_0f, "95", 0x01); +put_new(Permitted_operands_0f, "96", 0x01); +put_new(Permitted_operands_0f, "97", 0x01); +put_new(Permitted_operands_0f, "9c", 0x01); +put_new(Permitted_operands_0f, "9d", 0x01); +put_new(Permitted_operands_0f, "9e", 0x01); +put_new(Permitted_operands_0f, "9f", 0x01); :(code) void check_operands_0f(const line& inst, const word& op) { diff --git a/apps/ex13 b/apps/ex13 new file mode 100755 index 00000000..6a4c16b8 --- /dev/null +++ b/apps/ex13 Binary files differdiff --git a/apps/ex13.subx b/apps/ex13.subx new file mode 100644 index 00000000..9e407f32 --- /dev/null +++ b/apps/ex13.subx @@ -0,0 +1,25 @@ +# Compare 3 and 3. +# +# To run: +# $ ./subx translate init.linux examples/ex13.subx -o examples/ex13 +# $ ./subx run examples/ex13 +# Expected result: +# $ echo $? +# 1 + +== code +# instruction effective address register displacement immediate +# . op subop mod rm32 base index scale r32 +# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes + +Entry: + b8/copy-to-eax 3/imm32 + 3d/compare-eax-and 3/imm32 + 0f 94/set-if-= 3/mod/direct 3/rm32/ebx . . . . . . # set ebx to ZF + 81 4/subop/and 3/mod/direct 3/rm32/ebx . . . . . 0xff/imm32 # AND eax with 0xff + +$exit: + # exit(ebx) + e8/call syscall_exit/disp32 + +# . . vim:nowrap:textwidth=0 diff --git a/apps/mu b/apps/mu index 6e3bb25d..5be49fe3 100755 --- a/apps/mu +++ b/apps/mu Binary files differdiff --git a/apps/mu.subx b/apps/mu.subx index 9c6822f7..97f9c764 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -6867,14 +6867,10 @@ power-of-2?: # n: int -> result/eax: boolean 48/decrement-eax # var tmp2/eax: int = n & tmp 0b/and-> *(ebp+8) 0/r32/eax - # return (tmp2 == 0) # TODO: replace with setcc + # return (tmp2 == 0) 3d/compare-eax-and 0/imm32 - 74/jump-if-= $power-of-2?:true/disp8 -$power-of-2?:false: - b8/copy-to-eax 0/imm32/false - eb/jump $power-of-2?:end/disp8 -$power-of-2?:true: - b8/copy-to-eax 1/imm32/true + 0f 94/set-if-= %eax + 81 4/subop/and %eax 0xff/imm32 $power-of-2?:end: # . epilogue 89/<- %esp 5/r32/ebp @@ -9067,12 +9063,8 @@ subx-type-equal?: # a: (handle tree type-id), b: (handle tree type-id) -> resul (is-literal-type? *(ebp+0xc)) # => eax # return alit == blit 39/compare %eax 1/r32/ecx - 74/jump-if-= $subx-type-equal?:true/disp8 -$subx-type-equal?:false: # TODO: replace with setcc - b8/copy-to-eax 0/imm32/false - eb/jump $subx-type-equal?:end/disp8 -$subx-type-equal?:true: - b8/copy-to-eax 1/imm32/true + 0f 94/set-if-= %eax + 81 4/subop/and %eax 0xff/imm32 $subx-type-equal?:end: # . restore registers 59/pop-to-ecx @@ -9087,14 +9079,10 @@ is-literal-type?: # a: (handle tree type-id) -> result/eax: boolean 89/<- %ebp 4/r32/esp # 8b/-> *(ebp+8) 0/r32/eax - # return (*eax == 0) # TODO: replace with setcc + # return (*eax == 0) 81 7/subop/compare *eax 0/imm32/literal-type-id # Atom-type - 75/jump-if-!= $is-literal-type?:false/disp8 -$is-literal-type?:true: - b8/copy-to-eax 1/imm32/true - eb/jump $is-literal-type?:end/disp8 -$is-literal-type?:false: - b8/copy-to-eax 0/imm32/false + 0f 94/set-if-= %eax + 81 4/subop/and %eax 0xff/imm32 $is-literal-type?:end: # . epilogue 89/<- %esp 5/r32/ebp diff --git a/subx_opcodes b/subx_opcodes index a44e2aba..688a6e26 100644 --- a/subx_opcodes +++ b/subx_opcodes @@ -80,7 +80,7 @@ Opcodes currently supported by SubX: c1: shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr) c3: return from most recent unfinished call (ret) c6: copy imm8 to r8/m8-at-r32 (mov) - c7: copy imm32 to rm32 (mov) + c7: copy imm32 to rm32 with subop 0 (mov) cd: software interrupt (int) d3: shift rm32 by CL bits depending on subop (sal/sar/shl/shr) e8: call disp32 (call) @@ -99,6 +99,16 @@ Opcodes currently supported by SubX: 0f 8d: jump disp32 bytes away if greater or equal (signed), if SF == OF (jcc/jge/jnl) 0f 8e: jump disp32 bytes away if lesser or equal (signed), if ZF is set or SF != OF (jcc/jle/jng) 0f 8f: jump disp32 bytes away if greater (signed), if ZF is unset and SF == OF (jcc/jg/jnle) + 0f 92: set rm32 to 1 if lesser (unsigned), if CF is set, 0 otherwise (setcc/setb/setnae) + 0f 93: set rm32 to 1 if greater or equal (unsigned), if CF is unset, 0 otherwise (setcc/setae/setnb) + 0f 94: set rm32 to 1 if equal, if ZF is set, 0 otherwise (setcc/setz/sete) + 0f 95: set rm32 to 1 if not equal, if ZF is not set, 0 otherwise (setcc/setnz/setne) + 0f 96: set rm32 to 1 if lesser or equal (unsigned), if ZF is set or CF is set, 0 otherwise (setcc/setbe/setna) + 0f 97: set rm32 to 1 if greater (unsigned), if ZF is unset and CF is unset, 0 otherwise (setcc/seta/setnbe) + 0f 9c: set rm32 to 1 if lesser (signed), if SF != OF, 0 otherwise (setcc/setl/setnge) + 0f 9d: set rm32 to 1 if greater or equal (signed), if SF == OF, 0 otherwise (setcc/setge/setnl) + 0f 9e: set rm32 to 1 if lesser or equal (signed), if ZF is set or SF != OF, 0 otherwise (setcc/setle/setng) + 0f 9f: set rm32 to 1 if greater (signed), if ZF is unset and SF == OF, 0 otherwise (setcc/setg/setnle) 0f af: multiply rm32 into r32 (imul) Run `bootstrap help instructions` for details on words like 'r32' and 'disp8'. For complete details on these instructions, consult the IA-32 manual (volume 2). diff --git a/test_apps b/test_apps index 1067f518..52cceeb7 100755 --- a/test_apps +++ b/test_apps @@ -167,6 +167,18 @@ test "$1" = 'record' || git diff --exit-code apps/ex12 test $EMULATED && ./bootstrap run apps/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0 test $NATIVE && apps/ex12 +echo ex13 +./bootstrap translate init.$OS apps/ex13.subx -o apps/ex13 +test "$1" = 'record' || git diff --exit-code apps/ex13 +test $EMULATED && { + ./bootstrap run apps/ex13 || ret=$? + test $ret -eq 1 # 3 == 3 +} +test $NATIVE && { + apps/ex13 || ret=$? + test $ret -eq 1 # 3 == 3 +} + # Larger apps that use the standard library. echo factorial |