diff options
| author | Cliff Click <cliffc@acm.org> | 2025-05-06 10:45:11 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-05-06 10:45:11 -0700 |
| commit | 018f64fb8c147b4a82d74f5a4df408fef817bb41 (patch) | |
| tree | 39c1622eda8a460591aebc6c3590a4ae8a9a6aec /chapter22/src | |
| parent | 31f89ec8f8d2b05e2550b7c6957259380ef21575 (diff) | |
| download | Simple-018f64fb8c147b4a82d74f5a4df408fef817bb41.tar.gz Simple-018f64fb8c147b4a82d74f5a4df408fef817bb41.zip | |
hello world arm
Fix arm TFP/TMP encoding, delta is from 4K base page
8b align heap allocations
Sort arm major opcodes
Diffstat (limited to 'chapter22/src')
6 files changed, 604 insertions, 597 deletions
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java index da4f9ee7..6efb84dd 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -497,16 +497,16 @@ public class Encoding { // A series of libc/external calls that Simple can link against in a JIT. // Since no runtime in the JVM process, using magic numbers for the CPU // emulators to pick up on. - public static int SENTINAL_CALLOC = -4; - public static int SENTINAL_WRITE = -8; + public static int SENTINEL_CALLOC = -4; + public static int SENTINEL_WRITE = -8; void patchGlobalRelocations() { for( Node src : _externals.keySet() ) { int start = _opStart[src._nid]; String dst = _externals.get(src); int target = switch( dst ) { - case "calloc" -> SENTINAL_CALLOC; - case "write" -> SENTINAL_WRITE ; + case "calloc" -> SENTINEL_CALLOC; + case "write" -> SENTINEL_WRITE ; default -> throw Utils.TODO(); }; ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java index 908d46d0..606b03f0 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -32,13 +32,15 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short rpc = enc.reg(this); if(opLen == 8 ) { - // opstart of add - int next = opStart + opLen; + // ARM encoding delta is from PC & 0xFFF + int target = opStart+delta; + int base = opStart & ~0xFFF; + delta = target-base; int adrp_delta = delta >> 12; // patch upper 20 bits via adrp enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, rpc)); // low 12 bits via add - enc.patch4(next, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, rpc)); + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, rpc)); } else { // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java index 7600d66b..68e32c78 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java @@ -31,13 +31,15 @@ public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short dst = enc.reg(this); if(opLen == 8 ) { - // opstart of add - int next = opStart + opLen; + // ARM encoding delta is from PC & 0xFFF + int target = opStart+delta; + int base = opStart & ~0xFFF; + delta = target-base; int adrp_delta = delta >> 12; // patch upper 20 bits via adrp enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, dst)); // low 12 bits via add - enc.patch4(next, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, dst)); + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, dst)); } else { throw Utils.TODO(); } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java index b441aa4a..3c228a5b 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -107,19 +107,18 @@ return cc.cz; @Test public void testHelloWorld() throws IOException { - //String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/helloWorld.smp")); - //TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/helloWorld","","Hello, World!",0); - // - //// Evaluate on RISC5 emulator - //EvalRisc5 R5 = TestRisc5.build("helloWorld", 0, 2, false); - //int trap = R5.step(100); - //assertEquals(0,trap); - //assertEquals(0,R5.regs[riscv.A0]); + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/helloWorld.smp")); + TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/helloWorld","","Hello, World!",0); + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("helloWorld", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); // Evaluate on ARM emulator EvalArm64 arm = TestArm64.build("helloWorld", 0, 2, false); - int trap = arm.step(100); + trap = arm.step(100); assertEquals(0,trap); assertEquals(0,arm.regs[0]); } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter22/src/test/java/com/seaofnodes/simple/EvalArm64.java index 3ea9bea0..08cd7c8d 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/EvalArm64.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/EvalArm64.java @@ -3,6 +3,8 @@ package com.seaofnodes.simple; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.node.cpus.arm.arm; +import java.io.PrintStream; + public class EvalArm64 { // Memory image, always 0-based public final byte[] _buf; @@ -13,7 +15,6 @@ public class EvalArm64 { final double[] fregs; int _pc; - int SENTINEL_CALLOC = -4; // Start of free memory for allocation int _heap; // Cycle counters @@ -38,8 +39,7 @@ public class EvalArm64 { 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 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; } @@ -81,652 +81,656 @@ public class EvalArm64 { 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; + + // 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; - continue ; - } - case 0x25: { - // bl (just calloc) - rval = pc + 4; - regs[arm.X30] = rval; - if(pc + 4 == 0) { - regs[rdid] = rval; - break outer; - } - int imm26 = (ir & 0x03FFFFFF); - int imm = (imm26 << 6) >> 6; - pc = pc + (imm << 2) ; - if (pc == SENTINEL_CALLOC) { - long size = regs[arm.X0]*regs[arm.X1]; - regs[arm.X0] = _heap; - _heap += (int)size; - // unwind pc - pc = (int)rval; - } - continue; + + break; } + case 2: frval = fregs[rs1] * fregs[rs2]; break; // fmul + case 14: frval = fregs[rs1] - fregs[rs2]; break; // fsub + default: trap = (2+1); + } + break; } - // for the opcode we just match for bits[31:24]; - switch(opcode1) { - case 0xD2: { - // movz - // get immediate - rval = (ir >> 5) & 0x7FFF; - 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 0x38: { - // STRB/LDRB(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_8) { - 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_8) { - rval = ld1s((int)regs[rn] + (int)regs[rm]); - } else { - trap = (2+1); - } - break; - } - default: trap = (2+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 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); - } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_8) { + rval = ld1s((int)rval); + } else trap = (2+1); + rdid = -1; 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); + 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 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); + 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; - 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 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); - } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_16) { + rval = ld2s((int)rval); + } else trap = (2+1); + rdid = -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; + default: trap = (2+1); } - 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; + } - break; - } + case 0x8A: { // AND + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + rval = regs[rn] & 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); - } + 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; + } - 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 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], (int)regs[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); - } + case 0x91: { // add(immediate) + int rn = (ir >> 5) & 0x1F; + int immediate = ir << 10 >> 20; + // only hit it twice + rval = 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: { + // asr(immediate) + int imm = (ir >> 16) & 0x3F; + int rn = (ir >> 5) & 0x1F; + rval = regs[rn] >> (imm); + break; + } - break; + case 0x94, 0x95, 0x96, 0x97: { // bl + 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 ) { + PrintStream ps = switch((int)regs[0]) { + case 1 -> System.out; + case 2 -> System.err; + default -> throw new IllegalArgumentException(); + }; + ps.write(_buf,(int)regs[1],(int)regs[2]); + regs[0] = regs[2]; + pc = (int)rval; + rdid = -1; + } + pc -= 4; + 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], (int)regs[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); + 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 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, (int)regs[rdid]); - } else trap = (2+1); - - rdid = -1; - break; - } - case 0x1: { - // LDR (immediate) - if(opcode1 == arm.OPF_LOAD_IMM_32) { - frval = ld4s((int)rval); - } else trap = (2+1); - break; - } - default: trap = (2+1); + case 0x3: { + // load + if( opcode1 == arm.OP_LOAD_R_32) { + rval = ld4s((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); } break; } - case 0xFD: { - // LDR/STR(immediate) 64 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_64) { - st8((int)rval, regs[rdid]); - } else trap = (2+1); - - rdid = -1; - break; - } - case 0x1: { - // LDR (immediate) - if(opcode1 == arm.OPF_LOAD_IMM_64) { - frval = ld8((int)rval); - } else trap = (2+1); - break; - } - default: trap = (2+1); - } + 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 0x9b: { - // mul - int rn = (ir >> 5) & 0x1F; - int rm = (ir >> 16) & 0x1F; - rval = regs[rn] * regs[rm]; + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_32) { + rval = ld4s((int) rval); + } else trap = (2+1); break; } - case 0x54: { - // b.cond - int imm19 = ir << 8 >> 13; - imm19 = pc + (imm19 * 4) - 4; - rdid = -1; + default: trap = (2+1); + } + break; + } - 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); + 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], (int)regs[rdid]); + }else { + trap = (2+1); } + // store(expected to store the length here) + + rdid = -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]; - } + case 0x3: { + // load + if(opcode1 == arm.OPF_LOAD_R_32) { + frval = ld4f((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); } 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; + 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, (int)regs[rdid]); + } else trap = (2+1); - 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; - long lhs = regs[rn]; + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OPF_LOAD_IMM_32) { + frval = ld4s((int)rval); + } else trap = (2+1); + break; + } + default: trap = (2+1); + } + break; + } - rval = lhs - immediate; + case 0xD2: { + // movz + // get immediate + rval = (ir >> 5) & 0x7FFF; + break; + } - // set flags as a side effect - Z = (rval == 0); - N = (rval < 0); - C = lhs >= immediate; + 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 0xD3: { + // lsl(immediate) + int imm = (ir >> 16) & 0x3F; + int rn = (ir >> 5) & 0x1F; + rval = regs[rn] << (64 - imm); + break; + } + case 0xD6: { + rdid = -1; + // Return to zero breaks simulation + if(regs[30] == 0) + break outer; + throw Utils.TODO(); + } + + 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) - 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; + case 0x3: { + // load + if(opcode1 == arm.OP_LOAD_R_64) { + rval = ld8((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); + } break; } - case 0x91: { - // add(immediate) - int rn = (ir >> 5) & 0x1F; - int immediate = ir << 10 >> 20; - // only hit it twice - rval = regs[rn] + immediate; - break; + default: trap = (2+1); } - case 0xD3: { - // lsl(immediate) - int imm = (ir >> 16) & 0x3F; - int rn = (ir >> 5) & 0x1F; - rval = regs[rn] << (64 - imm); + + 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 0x93: { - // asr(immediate) - int imm = (ir >> 16) & 0x3F; - int rn = (ir >> 5) & 0x1F; - rval = regs[rn] >> (imm); + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_64) { + rval = ld8((int)rval); + } else trap = (2+1); 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; + default: trap = (2+1); } - case 0xAA: { - // MOV(register) - int rm = (ir >> 16) & 0x1F; - rval = regs[rm]; + 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], (int)regs[rdid]); + }else { + trap = (2+1); + } + // store(expected to store the length here) + + rdid = -1; break; } - case 0xD6: { - rdid = -1; - if(ld4s(pc + 4) == 0) { - break outer; + case 0x3: { + // load + if(opcode1 == arm.OPF_LOAD_R_64) { + frval = ld8f((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); } - } - // 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: 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); - } + default: trap = (2+1); + } + + break; + } + case 0xFD: { + // LDR/STR(immediate) 64 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_64) { + st8((int)rval, regs[rdid]); + } else trap = (2+1); + + rdid = -1; break; } - case 0x9e: { - // scvtf - is_f = true; - int rs1 = (ir >> 5) & 0x1F; - frval = (double)regs[rs1]; + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OPF_LOAD_IMM_64) { + frval = ld8((int)rval); + } else trap = (2+1); break; } default: trap = (2+1); + } + break; } + + default: trap = (2+1); + } + if(trap != 0) { _pc = pc; break; diff --git a/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java index 8fe22bc2..d2255278 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java @@ -101,7 +101,7 @@ import java.util.Arrays; if( (reladdy & 0x00100000)!=0 ) reladdy |= 0xffe00000; // Sign extension. rval = pc + 4; pc = pc + reladdy - 4; - if( pc+4 == Encoding.SENTINAL_WRITE ) { + if( pc+4 == Encoding.SENTINEL_WRITE ) { PrintStream ps = switch((int)regs[10]) { case 1 -> System.out; case 2 -> System.err; @@ -124,11 +124,11 @@ import java.util.Arrays; break outer; } // Inline CALLOC effect - if( pc == Encoding.SENTINAL_CALLOC ) { + 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 - // Pre-zeroed; epsilon (null) collector, never recycles memory so always zero - // Arrays.fill(_buf,_heap,_heap+size, (byte) 0 ); _heap += size; pc = (int)(rval - 4); // Unwind PC, as-if returned from calloc } else |
