summaryrefslogtreecommitdiff
path: root/chapter21/src/test/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'chapter21/src/test/java/com')
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java49
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java222
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java15
3 files changed, 270 insertions, 16 deletions
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index d1db1609..1d37deb0 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.cpus.arm.arm;
import com.seaofnodes.simple.node.cpus.riscv.riscv;
import java.io.IOException;
import java.nio.file.Files;
@@ -94,10 +95,12 @@ public class Chapter21Test {
// Return register A0 holds fib(8)==55
assertEquals(1.732051,R5.fregs[riscv.FA0 - riscv.F_OFFSET], 0.00001);
- // TODO: Run on ARM eval
- String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp"))
- + "flt farg = arg; return test_sqrt(farg) + test_sqrt(farg+2.0);";
- testCPU(src,"arm", "SystemV",19,null);
+ // arm
+ EvalArm64 A5 = TestArm64.build("newtonFloat", 0, 10);
+ A5.fregs[arm.D0 - arm.D_OFFSET] = 3.0;
+ int trap_arm = A5.step(1000);
+ assertEquals(0,trap_arm);
+ assertEquals(1.732051, A5.fregs[arm.D0 - arm.D_OFFSET], 0.00001);
}
@Test public void testSieve() throws IOException {
@@ -134,9 +137,12 @@ public class Chapter21Test {
// Return register A0 holds fib(8)==55
assertEquals(55,R5.regs[riscv.A0]);
- // TODO: run on arm eval
- String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/fib.smp"));
- testCPU(src,"arm" , "SystemV",16,null);
+ // arm
+ EvalArm64 A5 = TestArm64.build("fib", 9, 16);
+ int trap_arm = A5.step(100);
+ assertEquals(0,trap_arm);
+ // Return register X0 holds fib(8)==55
+ assertEquals(55, A5.regs[arm.X0]);
}
@Test public void testPerson() throws IOException {
@@ -186,6 +192,7 @@ public class Chapter21Test {
R5.fregs[riscv.FA6 - riscv.F_OFFSET] = 1.1;
R5.fregs[riscv.FA7 - riscv.F_OFFSET] = 1.1;
+ // a0 is passed in arg
R5.regs[riscv.A1] = 2;
R5.regs[riscv.A2] = 2;
R5.regs[riscv.A3] = 2;
@@ -198,7 +205,33 @@ public class Chapter21Test {
assertEquals(0,trap);
double result = R5.fregs[riscv.FA0 - riscv.F_OFFSET];
- // missing a float
+
assertEquals(22.8, result, 0.00001);
+
+ // arm
+ EvalArm64 A5 = TestArm64.build("no_stack_arg_count", 0, 0);
+
+ A5.fregs[arm.D0 - arm.D_OFFSET] = 1.1;
+ A5.fregs[arm.D1 - arm.D_OFFSET] = 1.1;
+ A5.fregs[arm.D2 - arm.D_OFFSET] = 1.1;
+ A5.fregs[arm.D3 - arm.D_OFFSET] = 1.1;
+ A5.fregs[arm.D4 - arm.D_OFFSET] = 1.1;
+ A5.fregs[arm.D5 - arm.D_OFFSET] = 1.1;
+ A5.fregs[arm.D6 - arm.D_OFFSET] = 1.1;
+ A5.fregs[arm.D7 - arm.D_OFFSET] = 1.1;
+
+ A5.regs[arm.X1] = 2;
+ A5.regs[arm.X2] = 2;
+ A5.regs[arm.X3] = 2;
+ A5.regs[arm.X4] = 2;
+ A5.regs[arm.X5] = 2;
+ A5.regs[arm.X6] = 2;
+ A5.regs[arm.X7] = 2;
+
+ int trap_arm = A5.step(100);
+ assertEquals(0,trap_arm);
+
+ double result1 = A5.fregs[arm.D0 - arm.D_OFFSET];
+ assertEquals(22.8, result1, 0.00001);
}
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java
index 55a16f84..370745dd 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java
@@ -17,6 +17,12 @@ public class EvalArm64 {
// Cycle counters
int _cycle;
+ // flags
+ boolean N = false;
+ boolean Z = false;
+ boolean C = false;
+ boolean V = false;
+
EvalArm64(byte[] buf, int stackSize) {
_buf = buf;
regs = new long[32];
@@ -26,6 +32,24 @@ public class EvalArm64 {
_pc = 0;
}
+ // Little endian
+ public int ld1s(int x) { return _buf[x ] ; }
+ public int ld1z(int x) { return _buf[x ]&0xFF; }
+ public int ld2s(int x) { return ld1z(x) | ld1s(x+1)<< 8; }
+ public int ld2z(int x) { return ld1z(x) | ld1z(x+1)<< 8; }
+ public int ld4s(int x) { return ld2z(x) | ld2s(x+2)<<16; }
+ public long ld8 (int x) { return (long)ld4s(x)&0xFFFFFFFFL | ((long)ld4s(x+4))<<32; }
+
+
+ public float ld4f(int x) { return Float.intBitsToFloat(ld4s(x)); }
+ public double ld8f(int x) { return Double.longBitsToDouble(ld8(x)); }
+
+ public void st1(int x, int val) { _buf[x] = (byte)val; }
+ public void st2(int x, int val) { st1(x,val); st1(x+1,val>> 8); }
+ public void st4(int x, int val) { st2(x,val); st2(x+2,val>>16); }
+ public void st8(int x, long val) { st4(x,(int)val); st2(x+4,(int)(val>>32)); }
+
+
public int step(int maxops) {
int trap = 0;
long rval = 0;
@@ -50,15 +74,205 @@ public class EvalArm64 {
}
// Load instruction from image buffer at PC
- //ir = ld4s( pc );
+ ir = ld4s( pc );
+
+ int rdid = ir & 0x1f;
+ // [31:24]
+ int opcode1 = (ir >> 24) & 0xFF;
+ // [31:26]
+ int opcode2 = (ir >> 26) & 0x3F;
+ switch(opcode2) {
+ case 5: {
+ //b
+ int imm26 = ir << 6 >> 6;
+
+ pc = pc + (imm26 * 4) - 4;
+ // won't hit pc += 4 at the bottom because continue
+ // do it manually
+ pc += 4;
+ rdid = -1;
+ continue ;
+ }
+ }
+ // for the opcode we just match for bits[31:24];
+ switch(opcode1) {
+ case 0xD2: {
+ // movz
+ // get immediate
+ rval = (ir >> 5) & 0x7FFF;
+ break;
+ }
+ case 0x54: {
+ // b.cond
+ int imm19 = ir << 8 >> 13;
+ imm19 = pc + (imm19 * 4) - 4;
+ rdid = -1;
+
+ switch(ir & 0xF) {
+ case 0x0: if(Z) pc = imm19; break; // eq
+ case 0x1: if(!Z) pc = imm19; break; // ne
+ case 0x2: if(C) pc = imm19; break; // cs
+ case 0x3: if(!C) pc = imm19; break;
+ case 0x4: if(N) pc = imm19; break; // mi
+ case 0x5: if(!N) pc = imm19; break; // pl
+ case 0x6: if(V) pc = imm19; break; // vs
+ case 0x7: if(!V) pc = imm19; break; // vc
+ case 0x8: if(C && !Z) pc = imm19; break; // hi
+ case 0x9: if(!C || Z) pc = imm19; break; // ls
+ case 0xA: if(N == V) pc = imm19; break; // ge
+ case 0xB: if(N != V) pc = imm19; break; // lt
+ case 0xC: if(!Z && N == V) pc = imm19; break; // gt
+ case 0xD: if(Z || N != V) pc = imm19; break; // le
+ case 0xE: pc = imm19; break; // always executed(al)
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0x9a: {
+ // conditional select(csel)
+ int rm = (ir >> 16) & 0x1F;
+ switch((ir >> 12) & 0xF) {
+ case 0x0: if(Z) rval = regs[rm]; break; // eq
+ case 0x1: if(!Z) rval = regs[rm]; break; // ne
+ case 0x2: if(C) rval = regs[rm]; break; // cs
+ case 0x3: if(!C) rval = regs[rm]; break;
+ case 0x4: if(N) rval = regs[rm]; break; // mi
+ case 0x5: if(!N) rval = regs[rm]; break; // pl
+ case 0x6: if(V) rval = regs[rm]; break; // vs
+ case 0x7: if(!V) rval = regs[rm]; break; // vc
+ case 0x8: if(C && !Z) rval = regs[rm]; break; // hi
+ case 0x9: if(!C || Z) rval = regs[rm]; break; // ls
+ case 0xA: if(N == V) rval = regs[rm]; break; // ge
+ case 0xB: if(N != V) rval = regs[rm]; break; // lt
+ case 0xC: if(!Z && N == V) rval = regs[rm]; break; // gt
+ case 0xD: if(Z || N != V) rval = regs[rm]; break; // le
+ case 0xE: rval = regs[rm]; break; // always executed(al)
+ default: {
+ rval = regs[(ir >> 5) & 0x1F];
+ }
+ }
+ break;
+ }
+ case 0xeb: {
+ // subs(shifted register)
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ int lhs = (int)regs[rn];
+ int rhs = (int)regs[rm];
+ rval = lhs - rhs;
+
+ // set flags as a side effect
+ Z = (rval == 0);
+ N = (rval < 0);
+ C = lhs >= rhs;
+
+ boolean sign_lhs = (lhs >>> 63) != 0;
+ boolean sign_rhs = (rhs >>> 63) != 0;
+ boolean sign_res = (rval >>> 63) != 0;
+ V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs);
+ rdid = -1;
+ break;
+ }
+ case 0xF1: {
+ // subs(immediate)
+ int rn = (ir >> 5) & 0x1F;
+ int immediate = ir << 10 >> 20;
+ int lhs = (int)regs[rn];
+
+ rval = lhs - immediate;
+
+ // set flags as a side effect
+ Z = (rval == 0);
+ N = (rval < 0);
+ C = lhs >= immediate;
+
+ boolean sign_lhs = (lhs >>> 63) != 0;
+ boolean sign_rhs = (immediate >>> 63) != 0;
+ boolean sign_res = (rval >>> 63) != 0;
+ V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs);
+ rdid = -1;
+ break;
+ }
+ case 0x8B: {
+ // add(shifted register)
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ long lhs = regs[rn];
+ long rhs = regs[rm];
+ rval = lhs + rhs;
+ break;
+ }
+ case 0x91: {
+ // add(immediate)
+ int rn = (ir >> 5) & 0x1F;
+ int immediate = ir << 10 >> 20;
+ rval = regs[rn] + immediate;
+ break;
+ }
+ case 0xAA: {
+ // MOV(register)
+ int rm = (ir >> 16) & 0x1F;
+ rval = regs[rm];
+ break;
+ }
+ case 0xD6: {
+ rdid = -1;
+ if(ld4s(pc + 4) == 0) {
+ break outer;
+ }
+ }
+ // bitwise
+ case 0x8A: {
+ // AND
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ rval = regs[rn] & regs[rm];
+ break;
+ }
+ // floats
+ case 0x1E: {
+ is_f = true;
+ int rs1 = (ir >> 5) & 0x1F;
+ int rs2 = (ir >> 16) & 0x1F;
+
+ int op = (ir >> 10) & 0x3F;
+ switch(op) {
+ case 16: frval = fregs[rs1]; break; // fmov
+ case 10:frval = fregs[rs1] + fregs[rs2]; break; // fadd
+
+ case 6: frval = fregs[rs1] / fregs[rs2]; break; // fdiv
+
+ case 2: frval = fregs[rs1] * fregs[rs2]; break; // fmul
+ case 14: frval = fregs[rs1] - fregs[rs2]; break; // fsub
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0x9e: {
+ // scvtf
+ is_f = true;
+ int rs1 = (ir >> 5) & 0x1F;
+ frval = (double)regs[rs1];
+ break;
+ }
+ default: trap = (2+1);
+ }
+ if(trap != 0) {
+ _pc = pc;
+ break;
+ }
+ if(rdid != -1) {
+ if(is_f) {fregs[rdid] = frval; is_f = false;}
+ else regs[rdid] = rval;
+ }
- //int rdid = ir & 0x1f;
- //switch(ir & )
+ pc += 4;
}
+ // Handle traps and interrupts.
if(trap != 0) {
return trap;
}
- _cycle = _cycle;
+ _cycle = cycle;
_pc = pc;
return 0;
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java b/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
index 1325f1e1..874beca8 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
@@ -8,26 +8,33 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.io.IOException;
+import static org.junit.Assert.assertEquals;
+
// Runs 32-bit ARM code in an emulator
public class TestArm64 {
- public static EvalArm64 build(String file, int arg) throws IOException {
- return build("src/test/java/com/seaofnodes/simple/progs",file, arg);
+ public static EvalArm64 build(String file, int arg, int spills) throws IOException {
+ return build("src/test/java/com/seaofnodes/simple/progs",file, arg, spills);
}
// Compile and run a simple program
- public static EvalArm64 build(String dir, String file, int arg) throws IOException {
+ public static EvalArm64 build(String dir, String file, int arg, int spills) throws IOException {
// Compile and export Simple
String src = Files.readString(Path.of(dir+"/"+file+".smp"));
CodeGen code = new CodeGen(src).driver("arm", "SystemV",null);
+ // Allocation quality not degraded
+ int delta = spills>>3;
+ if(delta == 0) delta =1;
+ if(spills != -1) assertEquals("Expect spills:", spills, code._regAlloc._spillScaled, delta);
+
// Image
byte[] image = new byte[1<<20]; // A megabyte (1024*1024 bytes)
EvalArm64 ARM = new EvalArm64(image, 1<<16);
// Code at offset 0
System.arraycopy(code._encoding.bits(), 0, image, 0, code._encoding.bits().length);
// Initial incoming int arg
- ARM.regs[arm.D0] = arg;
+ ARM.regs[arm.X0] = arg;
// malloc memory starts at 64K and goes up
return ARM;
}