6088 - start using setCC instructions
This commit is contained in:
parent
0743b981a8
commit
5c26afb1de
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
28
apps/mu.subx
28
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
|
||||
|
|
12
subx_opcodes
12
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).
|
||||
|
|
12
test_apps
12
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
|
||||
|
|
Loading…
Reference in New Issue