summaryrefslogtreecommitdiff
path: root/isa
diff options
context:
space:
mode:
Diffstat (limited to 'isa')
-rw-r--r--isa/src/main/java/com/seaofnodes/isa/Arm64.java6
-rw-r--r--isa/src/main/java/com/seaofnodes/isa/X86.java7
-rw-r--r--isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java16
-rw-r--r--isa/src/test/java/com/seaofnodes/isa/RiscTest.java16
-rw-r--r--isa/src/test/java/com/seaofnodes/isa/X86Test.java4
5 files changed, 49 insertions, 0 deletions
diff --git a/isa/src/main/java/com/seaofnodes/isa/Arm64.java b/isa/src/main/java/com/seaofnodes/isa/Arm64.java
index ce7f7b11..5edb2f3c 100644
--- a/isa/src/main/java/com/seaofnodes/isa/Arm64.java
+++ b/isa/src/main/java/com/seaofnodes/isa/Arm64.java
@@ -4,6 +4,12 @@ package com.seaofnodes.isa;
public final class Arm64 {
private Arm64() {}
+ // MRS Xt,NZCV / MSR NZCV,Xt. Register 31 denotes XZR.
+ public static int flags(int reg, boolean toFlags) {
+ assert 0<=reg && reg<32;
+ return (toFlags ? 0xD51B4200 : 0xD53B4200) | reg;
+ }
+
public static final int OP_ADD = 0b10_001_011;
public static final int OPF_ADD = 0b00_011_110;
public static final int OPF_OP_ADD = 0b00_101_0;
diff --git a/isa/src/main/java/com/seaofnodes/isa/X86.java b/isa/src/main/java/com/seaofnodes/isa/X86.java
index 78fa3da5..d5150a31 100644
--- a/isa/src/main/java/com/seaofnodes/isa/X86.java
+++ b/isa/src/main/java/com/seaofnodes/isa/X86.java
@@ -162,11 +162,18 @@ public final class X86 {
}
}
public static void flags(CodeSink out, int reg, boolean toFlags) {
+ assert 0<=reg && reg<16 && reg!=4;
if( !toFlags ) out.add1(0x9C); // PUSHF
rexF(0,reg,-1,false,out);
out.add1((toFlags ? 0x50 : 0x58)+(reg&7));
if( toFlags ) out.add1(0x9D); // POPF
}
+ public static void flagsStack(CodeSink out, int offset, boolean toFlags) {
+ if( !toFlags ) out.add1(0x9C); // PUSHFQ
+ // POP's destination uses the restored RSP, so offset needs no adjustment.
+ memory(out,0,toFlags ? 0xFF : 0x8F,false,toFlags ? 6 : 0,4,-1,offset,0);
+ if( toFlags ) out.add1(0x9D); // POPFQ
+ }
public static void stackCopy(CodeSink out, int srcOffset, int dstOffset) {
memory(out,0,0xFF,false,6,4,-1,srcOffset,0); // PUSH [rsp+srcOffset]
memory(out,0,0x8F,false,0,4,-1,dstOffset,0); // POP uses the restored rsp.
diff --git a/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java b/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java
index 1ff77f59..d4a54719 100644
--- a/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java
+++ b/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java
@@ -597,6 +597,22 @@ public class EvalArm64 {
break;
}
+ case 0xD5: {
+ if( (ir & ~31)==0xD53B4200 ) { // MRS Xt,NZCV
+ rval = (N ? 1L<<31 : 0) | (Z ? 1L<<30 : 0) |
+ (C ? 1L<<29 : 0) | (V ? 1L<<28 : 0);
+ if( rdid==31 ) rdid=-1; // XZR, not SP.
+ } else if( (ir & ~31)==0xD51B4200 ) { // MSR NZCV,Xt
+ long value = rdid==31 ? 0 : regs[rdid];
+ N = (value & (1L<<31))!=0;
+ Z = (value & (1L<<30))!=0;
+ C = (value & (1L<<29))!=0;
+ V = (value & (1L<<28))!=0;
+ rdid=-1;
+ } else throw new UnsupportedOperationException("Unknown system instruction");
+ break;
+ }
+
case 0xD6: {
int op = ir & 0xFFFFFC1F;
int rn = (ir >>> 5) & 31;
diff --git a/isa/src/test/java/com/seaofnodes/isa/RiscTest.java b/isa/src/test/java/com/seaofnodes/isa/RiscTest.java
index d10f97a4..5b354036 100644
--- a/isa/src/test/java/com/seaofnodes/isa/RiscTest.java
+++ b/isa/src/test/java/com/seaofnodes/isa/RiscTest.java
@@ -9,6 +9,22 @@ public class RiscTest {
assert expected==actual : String.format("Expected %08x, got %08x",expected,actual);
}
public static void main(String[] args) {
+ word(0xD53B4209,Arm64.flags(9,false)); // MRS x9,NZCV
+ word(0xD51B421A,Arm64.flags(26,true)); // MSR NZCV,x26
+ for( int flags=0; flags<16; flags++ ) {
+ var a=new EvalArm64(new byte[1024],512);
+ a.st4(4,0xD51B4209); // MSR NZCV,x9
+ a.st4(8,0xD53B421A); // MRS x26,NZCV
+ a.st4(12,0xD53B421F); // MRS xzr,NZCV
+ a.st4(16,0xD51B421F); // MSR NZCV,xzr
+ a._pc=4; a.regs[9]=((long)flags<<28) | 0xFFF;
+ assert a.step(3)==0;
+ assert a.regs[26]==(long)flags<<28 && a.regs[31]==512;
+ assert a.N==((flags&8)!=0) && a.Z==((flags&4)!=0);
+ assert a.C==((flags&2)!=0) && a.V==((flags&1)!=0);
+ assert a.step(1)==0;
+ assert !a.N && !a.Z && !a.C && !a.V && a.regs[31]==512;
+ }
// Instructions encountered by dynamic allocation measurements.
for( long[] pair : new long[][]{{17,3},{-17,3},{17,0},{Long.MIN_VALUE,-1}} ) {
var a=new EvalArm64(new byte[1024],512);
diff --git a/isa/src/test/java/com/seaofnodes/isa/X86Test.java b/isa/src/test/java/com/seaofnodes/isa/X86Test.java
index 8af84ae8..4d3f1433 100644
--- a/isa/src/test/java/com/seaofnodes/isa/X86Test.java
+++ b/isa/src/test/java/com/seaofnodes/isa/X86Test.java
@@ -102,6 +102,10 @@ public class X86Test {
check("41ffd2", b -> X86.callRegister(b,10));
check("41519d", b -> X86.flags(b,9,true));
check("9c4159", b -> X86.flags(b,9,false));
+ check("9c8f442418", b -> X86.flagsStack(b,24,false));
+ check("ff7424189d", b -> X86.flagsStack(b,24,true));
+ check("9c8f842480000000", b -> X86.flagsStack(b,128,false));
+ check("ffb424800000009d", b -> X86.flagsStack(b,128,true));
check("ff7424088f442410", b -> X86.stackCopy(b,8,16));
check("4d8bca", b -> X86.move(b,false,false,9,10));
check("4d0f28ca", b -> X86.move(b,true,true,9,10));