about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-03-06 17:41:36 -0800
committerKartik Agaram <vc@akkartik.com>2020-03-06 17:42:17 -0800
commit5c26afb1de61dc650f0f7523c92143747c960432 (patch)
tree22c00a6ba562cbd80e2432201399ee800c5247da
parent0743b981a823049bfe0a24f9204e629ce375af39 (diff)
downloadmu-5c26afb1de61dc650f0f7523c92143747c960432.tar.gz
6088 - start using setCC instructions
-rw-r--r--017jump_disp8.cc2
-rw-r--r--018jump_disp32.cc2
-rw-r--r--021byte_addressing.cc102
-rw-r--r--033check_operands.cc11
-rwxr-xr-xapps/ex13bin0 -> 211 bytes
-rw-r--r--apps/ex13.subx25
-rwxr-xr-xapps/mubin177228 -> 177213 bytes
-rw-r--r--apps/mu.subx28
-rw-r--r--subx_opcodes12
-rwxr-xr-xtest_apps12
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