summaryrefslogtreecommitdiff
path: root/chapter23/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'chapter23/src/test/java')
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/BrainFuckTest.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java766
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/EvalRisc5.java368
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/MergeSortTest.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/TestArm64.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/TestRisc5.java2
10 files changed, 26 insertions, 1134 deletions
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter23/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index bf809d2a..9f626805 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -1,5 +1,9 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalRisc5;
+
+import com.seaofnodes.isa.eval.EvalArm64;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.cpus.arm.arm;
import com.seaofnodes.simple.node.cpus.riscv.riscv;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 14f9fdb8..9aa18821 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -1,5 +1,9 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalRisc5;
+
+import com.seaofnodes.isa.eval.EvalArm64;
+
import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.cpus.arm.arm;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
index def21258..46457b40 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -1,5 +1,9 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalRisc5;
+
+import com.seaofnodes.isa.eval.EvalArm64;
+
import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen;
import com.seaofnodes.simple.codegen.CodeGen;
import java.io.IOException;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
index 41f0df6e..10d27ac8 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
@@ -1,5 +1,9 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalRisc5;
+
+import com.seaofnodes.isa.eval.EvalArm64;
+
import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java
deleted file mode 100644
index e0cbdcff..00000000
--- a/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java
+++ /dev/null
@@ -1,766 +0,0 @@
-package com.seaofnodes.simple;
-
-import com.seaofnodes.simple.codegen.Encoding;
-import com.seaofnodes.simple.node.cpus.arm.arm;
-import com.seaofnodes.simple.util.Utils;
-import java.io.ByteArrayOutputStream;
-
-public class EvalArm64 {
- // Memory image, always 0-based
- public final byte[] _buf;
-
- // GPRs
- final long[] regs;
- // FRs
- final double[] fregs;
-
- int _pc;
-
- // Start of free memory for allocation
- int _heap;
-
- // Standard out and err streams
- ByteArrayOutputStream _stdout, _stderr;
-
- // 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];
- fregs = new double[32];
- // Stack grows down, heap grows up
- regs[arm.RSP] = _heap = stackSize;
- _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); st4(x+4,(int)(val>>32)); }
-
- public int step(int maxops) {
- int trap = 0;
- long rval = 0;
- double frval = 0;
- int pc = _pc;
- int cycle = _cycle;
- boolean is_f = false;
- outer:
- for(int icount = 0; icount < maxops; icount++) {
- int ir = 0;
- rval = 0;
- frval = 0;
- cycle++;
- if( pc >= _buf.length ) {
- trap = 1 + 1; // Handle access violation on instruction read.
- break;
- }
-
- if( (pc & 3)!=0 ) {
- trap = 1; // Handle PC-misaligned access
- break;
- }
-
- // Load instruction from image buffer at PC
- ir = ld4s( pc );
-
- int rdid = ir & 0x1f;
- // [31:24]
- int opcode1 = (ir >> 24) & 0xFF;
-
- // for the opcode we just match for bits[31:24];
- switch( opcode1 ) {
- case 0x14, 0x15, 0x16, 0x17: { //b
- int imm26 = ir << 6 >> 6;
- pc = pc + (imm26 * 4) - 4;
- rdid = -1;
- break;
- }
- case 0x1E: { // floats
- 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: if (fregs[rs2] == 0) frval = 0; else frval = fregs[rs1] / fregs[rs2]; break; // fdiv
- case 8: {
- // fcmp
- double lhs = fregs[rs1];
- double rhs = fregs[rs2];
-
- Z = (lhs == rhs);
- N = (lhs < rhs);
- C = lhs >= rhs;
- V = Double.isNaN(lhs) || Double.isNaN(rhs);
- rdid = -1;
-
- break;
- }
- case 2: frval = fregs[rs1] * fregs[rs2]; break; // fmul
- case 14: frval = fregs[rs1] - fregs[rs2]; break; // fsub
- default: trap = (2+1);
- }
- break;
- }
-
- case 0x38: {
- // STRB/LDRB(register)
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch( ir >> 21 & 0x7 ) {
- case 0x1 -> { // store
- if( opcode1 == arm.OP_STORE_R_8 ) st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- else trap = (2+1);
- rdid = -1;
- }
- case 0x3 -> { // load
- if( opcode1 == arm.OP_LOAD_R_8 ) rval = ld1s((int)regs[rn] + (int)regs[rm]);
- else trap = (2+1);
- }
- default -> trap = (2+1);
- }
- break;
- }
- case 0x39: {
- // STRB/LDRB(immediate)
- // str/ldr(immediate)
- // rn
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
-
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_8) {
- st1((int)rval, (int)regs[rdid]);
- } else trap = (2+1);
- rdid = -1;
-
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_8) {
- rval = ld1s((int)rval);
- } else trap = (2+1);
- rdid = -1;
- break;
- }
- default: trap = (2+1);
- }
- 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 0x5c: {
- // ldr
- is_f = true;
- // address = delta
- int address = ir << 8 >> 13;
- address *= 4;
- if(address >= _buf.length-3) trap = (5 + 1);
- frval = ld8f(pc + address);
- break;
- }
-
- case 0x78: {
- // STRH/LDRH(register)
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- // store
- if(opcode1 == arm.OP_STORE_R_16) {
- st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- }else {
- trap = (2+1);
- }
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OP_LOAD_R_16) {
- rval = ld1s((int)regs[rn] + (int)regs[rm]);
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
- break;
- }
-
- case 0x79: {
- // STRH/LDRH(immediate)
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
- imm *= 2;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
-
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_16) {
- st2((int)rval, (int)regs[rdid]);
- } else trap = (2+1);
- rdid = -1;
-
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_16) {
- rval = ld2s((int)rval);
- } else trap = (2+1);
- rdid = -1;
- break;
- }
- default: trap = (2+1);
- }
- break;
- }
-
- case 0x8A: { // AND
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- rval = regs[rn] & regs[rm];
- break;
- }
-
- case 0x8B, 0xCB: {
- // add/sub(register), unshifted form emitted by Simple
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- long lhs = regs[rn];
- long rhs = regs[rm];
- rval = opcode1==0x8B ? lhs + rhs : lhs - rhs;
- break;
- }
-
- case 0x90: { // adrp
- int immhi = ( (ir& ~0x1F) << 8 ) >> 8;
- int immlo = (ir>>29)& 3;
- int imm = ((immhi<<2) | immlo) << 12;
- rval = (pc & ~0xFFF) + imm;
- break;
- }
-
- case 0x91, 0xD1: { // ADD/SUB (immediate), unsigned imm12, optional LSL #12
- int rn = (ir >> 5) & 0x1F;
- long immediate = (ir >>> 10) & 0xFFF;
- if( (ir & (1<<22))!=0 ) immediate <<= 12;
- rval = opcode1==0x91 ? regs[rn] + immediate : regs[rn] - immediate;
- break;
- }
- case 0x92: { // and(immediate)
- int imm12 = (ir >> 10) & 0x1FFF;
- long immediate = arm.decodeImm12(imm12);
- int rn = (ir >> 5) & 0x1F;
- rval = regs[rn] & immediate;
- break;
- }
- case 0x93, 0xD3: { // SBFM/UBFM: shifts and signed/unsigned extracts
- int immr = (ir >>> 16) & 63;
- int imms = (ir >>> 10) & 63;
- int rn = (ir >>> 5) & 31;
- boolean signed = (ir & 0x40000000)==0;
- long value = regs[rn] << (63-imms);
- value = signed ? value >> (63-imms) : value >>> (63-imms);
- rval = immr > imms ? value << (64-immr)
- : signed ? value >> immr : value >>> immr;
- break;
- }
-
- case 0x94, 0x95, 0x96, 0x97: { // bl
- rdid = -1; // BL writes only X30, not a displacement-selected register.
- rval = pc + 4;
- regs[arm.X30] = rval;
- int imm26 = (ir & 0x03FFFFFF);
- int imm = (imm26 << 6) >> 6;
- pc = pc + (imm << 2) ;
- if( pc == Encoding.SENTINEL_CALLOC ) {
- assert (_heap&7) == 0; // 8-byte aligned
- long size = regs[arm.X0]*regs[arm.X1];
- size = (size+7) & -8; // 8-byte aligned
- regs[arm.X0] = _heap;
- _heap += (int)size;
- pc = (int)rval;
- rdid = -1;
- }
- if( pc == Encoding.SENTINEL_WRITE ) {
- ByteArrayOutputStream baos = switch((int)regs[0]) {
- case 1 -> _stdout==null ? (_stdout = new ByteArrayOutputStream()) : _stdout;
- case 2 -> _stderr==null ? (_stderr = new ByteArrayOutputStream()) : _stderr;
- default -> throw new IllegalArgumentException();
- };
- baos.write(_buf,(int)regs[1],(int)regs[2]);
- regs[0] = regs[2];
- pc = (int)rval;
- rdid = -1;
- }
- pc -= 4;
- 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 0x9B: { // mul
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- rval = regs[rn] * regs[rm];
- break;
- }
- case 0x9E: {
- // scvtf
- is_f = true;
- int rs1 = (ir >> 5) & 0x1F;
- frval = (double)regs[rs1];
- break;
- }
-
- case 0xAA: {
- // MOV(register)
- int rm = (ir >> 16) & 0x1F;
- rval = regs[rm];
- break;
- }
-
- case 0xB8: {
- // LDR/STR (register + index) 32 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OP_STORE_R_32) {
- st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if( opcode1 == arm.OP_LOAD_R_32) {
- rval = ld4s((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
-
- break;
- }
-
- case 0xB9: {
- // str/ldr(immediate) 32 bits
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
- imm *= 4;
-
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
-
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_32) {
- st4((int)rval, (int)regs[rdid]);
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_32) {
- rval = ld4s((int) rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
- }
- break;
- }
-
- case 0xBC: {
- // LDR/STR (register + index) float 32 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- is_f = true;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OPF_STORE_R_32) {
- st4((int)regs[rn] + (int)regs[rm], Float.floatToRawIntBits((float)fregs[rdid]));
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OPF_LOAD_R_32) {
- frval = ld4f((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
-
- break;
- }
-
- case 0xBD: {
- // LDR/STR(immediate) 32 bits floats
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
-
- imm *= 4;
- is_f = true;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OPF_STORE_IMM_32) {
- st4((int)rval, Float.floatToRawIntBits((float)fregs[rdid]));
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OPF_LOAD_IMM_32) {
- frval = ld4f((int)rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
- }
- break;
- }
-
- case 0xD2: // MOVZ
- case 0xF2: { // MOVK preserves the other halfwords
- // movz
- // get immediate
- int shift = ((ir >> 21) & 3)*16;
- rval = ((ir >> 5) & 0xFFFFL) << shift;
- if( opcode1==0xF2 ) rval |= regs[rdid] & ~(0xFFFFL << shift);
- break;
- }
-
- case 0xEB: {
- // subs(shifted register)
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- long lhs = regs[rn];
- long rhs = 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 0xD6: {
- int op = ir & 0xFFFFFC1F;
- int rn = (ir >>> 5) & 31;
- int target = (int)regs[rn]; // Read before BLR overwrites X30.
- rdid = -1;
- if( op==0xD63F0000 ) regs[arm.X30] = pc+4; // BLR
- else if( op!=0xD65F0000 ) { trap = 3; break; } // RET
- pc = target;
- if( op==0xD65F0000 && pc==0 ) break outer;
- pc -= 4;
- break;
- }
-
- case 0xF1: {
- // subs(immediate)
- int rn = (ir >> 5) & 0x1F;
- int immediate = ir << 10 >> 20;
- long lhs = 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 0xF8: {
- // LDR/STR (register + index) 64 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OP_STORE_R_64) {
- st8((int)regs[rn] + (int)regs[rm], regs[rdid]);
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OP_LOAD_R_64) {
- rval = ld8((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
-
- break;
- }
- case 0xF9: {
- // str/ldr(immediate) 64 bits
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
-
- imm *= 8;
-
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_64) {
- st8((int)rval, regs[rdid]);
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_64) {
- rval = ld8((int)rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
- }
- break;
- }
-
- case 0xFC: {
- // LDR/STR (register + index) float 64 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- is_f = true;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OPF_STORE_R_64) {
- st8((int)regs[rn] + (int)regs[rm], Double.doubleToRawLongBits(fregs[rdid]));
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OPF_LOAD_R_64) {
- frval = ld8f((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
-
- break;
- }
- case 0xFD: {
- // LDR/STR(immediate) 64 bits floats
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
-
- imm *= 8;
- is_f = true;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OPF_STORE_IMM_64) {
- st8((int)rval, Double.doubleToRawLongBits(fregs[rdid]));
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OPF_LOAD_IMM_64) {
- frval = ld8f((int)rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
- }
- 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;
- }
-
- pc += 4;
- }
- // Handle traps and interrupts.
- if(trap != 0) {
- return trap;
- }
- _cycle = cycle;
- _pc = pc;
- return 0;
- }
-
-
-}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter23/src/test/java/com/seaofnodes/simple/EvalRisc5.java
deleted file mode 100644
index 633e931e..00000000
--- a/chapter23/src/test/java/com/seaofnodes/simple/EvalRisc5.java
+++ /dev/null
@@ -1,368 +0,0 @@
- package com.seaofnodes.simple;
-
-/** Simple RISC5 CPU Emulator
- *
- * Original works credit Charles Lohr.
- * This is a complete rewrite in Java.
- *
- * Load code into memory and go!
- */
-
-import com.seaofnodes.simple.codegen.Encoding;
-import com.seaofnodes.simple.node.cpus.riscv.riscv;
-import com.seaofnodes.simple.util.Utils;
-import java.io.ByteArrayOutputStream;
-import java.util.Arrays;
-
-public class EvalRisc5 {
-
- // Memory image, always 0-based
- public final byte[] _buf;
-
- // GPRs
- final long[] regs;
- // FRs
- final double[] fregs;
- // PC
- int _pc;
-
- // Start of free memory for allocation
- int _heap;
-
- // Standard out and err streams
- ByteArrayOutputStream _stdout, _stderr;
-
- // Cycle counters
- int _cycle;
-
- EvalRisc5( byte[] buf, int stackSize ) {
- _buf = buf;
- regs = new long[32];
- fregs = new double[32];
- // Stack grows down, heap grows up
- regs[riscv.RSP] = _heap = stackSize;
- _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); st4(x+4,(int)(val>>32)); }
-
- // Note: only a few bits are used. (Machine = 3, User = 0)
- // Bits 0..1 = privilege.
- // Bit 2 = WFI (Wait for interrupt)
- // Bit 3+ = Load/Store reservation LSBs.
- int _extraflags;
-
- public int step( int maxops ) {
- int trap = 0;
- long rval = 0;
- double frval = 0;
- int pc = _pc;
- int cycle = _cycle;
- boolean is_f = false;
- outer:
- for( int icount = 0; icount < maxops; icount++ ) {
- int ir = 0;
- rval = 0;
- cycle++;
-
- if( pc >= _buf.length ) {
- trap = 1 + 1; // Handle access violation on instruction read.
- break;
- }
- if( (pc & 3)!=0 ) {
- trap = 1; // Handle PC-misaligned access
- break;
- }
- // Load instruction from image buffer at PC
- ir = ld4s( pc );
- int rdid = (ir >> 7) & 0x1f;
-
- switch( ir & 0x7f ) {
- case 0x37: // LUI (0b0110111)
- rval = ( ir & 0xfffff000 );
- break;
- case 0x17: // AUIPC (0b0010111)
- rval = pc + ( ir & 0xfffff000 );
- break;
- case 0x6F: { // JAL (0b1101111)
- int reladdy = ((ir & 0x80000000)>>11) | ((ir & 0x7fe00000)>>20) | ((ir & 0x00100000)>>9) | ((ir&0x000ff000));
- if( (reladdy & 0x00100000)!=0 ) reladdy |= 0xffe00000; // Sign extension.
- rval = pc + 4;
- pc = pc + reladdy - 4;
- if( pc+4 == Encoding.SENTINEL_WRITE ) {
- ByteArrayOutputStream baos = switch((int)regs[10]) {
- case 1 -> _stdout==null ? (_stdout = new ByteArrayOutputStream()) : _stdout;
- case 2 -> _stderr==null ? (_stderr = new ByteArrayOutputStream()) : _stderr;
- default -> throw new IllegalArgumentException();
- };
- baos.write(_buf,(int)regs[11],(int)regs[12]);
- regs[10] = regs[12];
- rdid = 0;
- pc = (int)(rval - 4); // Unwind PC, as-if returned from write
- }
- break;
- }
- case 0x67: { // JALR (0b1100111)
- int imm_se = ir >> 20; // Sign extend 12 bits
- rval = pc + 4;
- pc = ((int)regs[ (ir >> 15) & 0x1f ] + imm_se) & ~1;
- // Return from top-level ; exit sim
- if( pc==0 ) {
- if( rdid!=0 ) regs[rdid] = rval; // Write PC into register before exit
- break outer;
- }
- // Inline CALLOC effect
- if( pc == Encoding.SENTINEL_CALLOC ) {
- assert (_heap&7) == 0; // 8-byte aligned
- int size = (int)(regs[10]*regs[11]);
- size = (size+7) & -8; // 8-byte aligned
- regs[10] = _heap; // Return next free address
- _heap += size;
- pc = (int)(rval - 4); // Unwind PC, as-if returned from calloc
- } else
- pc -= 4;
- break;
- }
- case 0x63: { // Branch (0b1100011)
- int immm4 = ((ir & 0xf00)>>7) | ((ir & 0x7e000000)>>20) | ((ir & 0x80) << 4) | ((ir >> 31)<<12);
- if( (immm4 & 0x1000)!=0 ) immm4 |= 0xffffe000;
- long rs1 = regs[(ir >> 15) & 0x1f];
- long rs2 = regs[(ir >> 20) & 0x1f];
- immm4 = pc + immm4 - 4;
- rdid = 0;
- if( switch( (ir >> 12) & 0x7 ) {
- case 0 -> rs1 == rs2;
- case 1 -> rs1 != rs2;
- case 4 -> rs1 < rs2;
- case 5 -> rs1 >= rs2;
- case 6 -> Long.compareUnsigned(rs1,rs2) < 0; //BLTU
- case 7 -> Long.compareUnsigned(rs1,rs2) >= 0; //BGEU
- default -> { trap = (2+1); yield false; }
- } ) pc = immm4;
- break;
- }
- case 0x03: { // Load (0b0000011)
- int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b
- int imm = ir >> 20;
- int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0 );
- int rsval = rs1 + imm_se;
-
- if( rsval >= _buf.length-3 ) {
- trap = (5+1);
- rval = rsval;
- } else {
- switch( ( ir >> 12 ) & 0x7 ) {
- //LB, LH, LW, LBU, LHU
- case 0: rval = ld1s( rsval ); break;
- case 1: rval = ld2s( rsval ); break;
- case 2: rval = ld4s( rsval ); break;
- case 3: rval = ld8 ( rsval ); break;
- case 4: rval = ld1z( rsval ); break;
- case 5: rval = ld2z( rsval ); break;
- case 6: rval = ld4s( rsval ); break;
- default: trap = (2+1);
- }
- }
- break;
- }
- // floats
- case 0x7: {
- is_f = true;
- int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b
- int imm = ir >> 20;
- int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0 );
- int rsval = rs1 + imm_se;
-
- if( rsval >= _buf.length-3 ) {
- trap = (5+1);
- rval = rsval;
- } else {
- switch( ( ir >> 12 ) & 0x7 ) {
- case 2: frval = ld4f( rsval ); break;
- case 3: frval = ld8f( rsval ); break;
- default: trap = (2+1);
- }
- }
- break;
- }
-
- case 0x23: { // Store 0b0100011
- int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b
- long rs2 = regs[(ir >> 20) & 0x1f];
- int addy = ( ( ir >> 7 ) & 0x1f ) | ( ( ir & 0xfe000000 ) >> 20 );
- if( (addy & 0x800)!=0 ) addy |= 0xfffff000;
- addy += rs1;
- rdid = 0;
- if( addy >= _buf.length-3 ) {
- trap = (7+1); // Store access fault.
- rval = addy;
- } else {
- switch( ( ir >> 12 ) & 0x7 ) { //SB, SH, SW
- case 0: st1( addy, (int)rs2 ); break;
- case 1: st2( addy, (int)rs2 ); break;
- case 2: st4( addy, (int)rs2 ); break;
- case 3: st8( addy, rs2 ); break;
- default: trap = (2+1);
- }
- }
- break;
- }
- case 0x13: // Op-immediate 0b0010011
- case 0x33: { // Op 0b0110011
- int imm = ir >> 20;
- imm = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0);
- long rs1 = regs[(ir >> 15) & 0x1f];
- boolean is_reg = (ir & 0x20)!=0;
- long rs2 = is_reg ? regs[imm & 0x1f] : imm;
-
- // Insert the detection here
- int rs1id = (ir >> 15) & 0x1f;
- int funct3 = (ir >> 12) & 0x7;
-
- if( is_reg && ( ir & 0x02000000 )!=0 ) {
- switch( (ir>>12)&7 ) { //0x02000000 = RV32M
- case 0: rval = rs1 * rs2; break; // MUL
- case 1: rval = (int)((long)((int)rs1) * (long)((int)rs2)) >> 32; break; // MULH
- case 2: rval = (int)((long)((int)rs1) * (long)rs2) >> 32; break; // MULHSU
- case 3: rval = (int)((long)rs1 * (long)rs2) >> 32; break; // MULHU
- case 4: if( rs2 == 0 ) rval = -1; else rval = ((int)rs1 == Integer.MIN_VALUE && (int)rs2 == -1) ? rs1 : ((int)rs1 / (int)rs2); break; // DIV
- case 5: if( rs2 == 0 ) rval = 0xffffffff; else rval = rs1 / rs2; break; // DIVU
- case 6: if( rs2 == 0 ) rval = rs1; else rval = ((int)rs1 == Integer.MIN_VALUE && (int)rs2 == -1) ? 0 : ((int)((int)rs1 % (int)rs2)); break; // REM
- case 7: if( rs2 == 0 ) rval = rs1; else rval = rs1 % rs2; break; // REMU
- }
- } else {
- rval = switch( (ir >> 12) & 7 ) { // These could be either op-immediate or op commands. Be careful.
- case 0 -> (is_reg && (ir & 0x40000000) != 0) ? (rs1 - rs2) : (rs1 + rs2);
- case 1 -> rs1 << (rs2 & 0x3F);
- case 2 -> (rs1 < rs2) ? 1 : 0;
- case 3 -> (rs1 < rs2) ? 1 : 0;
- case 4 -> rs1 ^ rs2;
- case 5 -> (ir & 0x40000000) != 0 ? (rs1 >> (rs2 & 0x3F)) : (rs1 >>> (rs2 & 0x3F));
- case 6 -> rs1 | rs2;
- case 7 -> rs1 & rs2;
- default -> rval;
- };
- }
- break;
- }
- case 0x0f: // 0b0001111
- rdid = 0; // fencetype = (ir >> 12) & 0b111; We ignore fences in this impl.
- break;
- case 0x73: // Zifencei+Zicsr (0b1110011)
- trap = (2+1); // Note micrrop 0b100 == undefined.
- break;
-
- case 0x2f: { // RV32A (0b00101111)
- long rs1 = regs[(ir >> 15) & 0x1f];
- long rs2 = regs[(ir >> 20) & 0x1f];
- int irmid = ( ir>>27 ) & 0x1f;
-
- // We don't implement load/store from UART or CLNT with RV32A here.
- if( rs1 >= _buf.length-3 ) {
- trap = (7+1); //Store/AMO access fault
- rval = rs1;
- } else {
- rval = ld4s( (int)rs1 );
-
- // Referenced a little bit of https://github.com/franzflasch/riscv_em/blob/master/src/core/core.c
- boolean dowrite = true;
- switch( irmid ) {
- case 2: //LR.W (0b00010)
- dowrite = false;
- _extraflags = (_extraflags & 0x07) | (int)(rs1<<3);
- break;
- case 3: { //SC.W (0b00011) (Make sure we have a slot, and, it's valid)
- boolean xflag = _extraflags >> 3 != ( rs1 & 0x1fffffff );
- rval = xflag ? 1 : 0; // Validate that our reservation slot is OK.
- dowrite = !xflag; // Only write if slot is valid.
- break;
- }
- case 0: rs2 += rval; break; // AMOADD.W (0b00000)
- case 1: break; // AMOSWAP.W (0b00001)
- case 4: rs2 ^= rval; break; // AMOXOR.W (0b00100)
- case 8: rs2 |= rval; break; // AMOOR.W (0b01000)
- case 12: rs2 &= rval; break; // AMOAND.W (0b01100)
- case 16: rs2 = Math.min( rs2, rval ); break; //AMOMIN.W (0b10000)
- case 20: rs2 = Math.max( rs2, rval ); break; //AMOMAX.W (0b10100)
- case 24: rs2 = Math.min( rs2, rval ); break; //AMOMINU.W (0b11000)
- case 28: rs2 = Math.max( rs2, rval ); break; //AMOMAXU.W (0b11100)
- default: trap = (2+1); dowrite = false; break; //Not supported.
- }
- if( dowrite ) st4( (int)rs1, (int)rs2 );
- }
- break;
- }
-
- case 0x53: {
- is_f = true;
- int rs1 = (ir >> 15) & 0x1F;
- int rs2 = (ir >> 20) & 0x1F;
- double lhs = fregs[rs1];
- double rhs = fregs[rs2];
- int func5 = (ir >> 27) & 0x1F;
- int func2 = (ir >> 25) & 0x3;
- if( func2 != 1 ) throw Utils.TODO(); // 1==double
- switch( func5 ) {
- case 0: frval = lhs + rhs; break; // fadd.d
- case 1: frval = lhs - rhs; break; // fsub.d
- case 2: frval = lhs * rhs; break; // fmul.d
- case 3: frval = lhs / rhs; break; // fdiv.d
- case 5: frval = Math.min(lhs,rhs); break; // fmin.d, also used for move
- case 20:
- is_f = false; // Output into a GPR
- rval = switch( (ir >> 12) & 7 ) {
- case 0 -> lhs <= rhs ? 1 : 0;
- case 1 -> lhs == rhs ? 1 : 0;
- case 2 -> lhs < rhs ? 1 : 0;
- default -> throw Utils.TODO();
- };
- break;
- case 26: frval = (double)regs[rs1]; break; // fcvt.w.d
- default:
- trap = (2+1); // Fault: Invalid opcode.
- throw Utils.TODO();
- }
- break;
- }
-
- default: trap = (2+1); // Fault: Invalid opcode.
- }
-
- // If there was a trap, do NOT allow register writeback.
- if( trap!=0 ) {
- _pc = pc;
- break;
- }
-
- if( rdid!=0 || is_f) {
- if(is_f) {fregs[rdid] = frval; is_f = false;} // Write back register.
- else regs[rdid] = rval; // Write back register.
- }
-
- pc += 4;
- }
-
- // Handle traps and interrupts.
- if( trap!=0 )
- return trap;
-
- _cycle = cycle;
- _pc = pc;
- return 0;
- }
-}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java b/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
index 0f09b7f0..11881194 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
@@ -1,5 +1,9 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalRisc5;
+
+import com.seaofnodes.isa.eval.EvalArm64;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegAllocTestSupport;
import com.seaofnodes.simple.node.*;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/MergeSortTest.java b/chapter23/src/test/java/com/seaofnodes/simple/MergeSortTest.java
index d1fbd7df..39cacd98 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/MergeSortTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/MergeSortTest.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalRisc5;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.node.cpus.riscv.riscv;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/TestArm64.java b/chapter23/src/test/java/com/seaofnodes/simple/TestArm64.java
index edce92f3..a22063eb 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/TestArm64.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/TestArm64.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalArm64;
+
import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/TestRisc5.java b/chapter23/src/test/java/com/seaofnodes/simple/TestRisc5.java
index adb256eb..ace2a7ea 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/TestRisc5.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/TestRisc5.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple;
+import com.seaofnodes.isa.eval.EvalRisc5;
+
import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.FunNode;