summaryrefslogtreecommitdiff
path: root/chapter21
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-04-08 14:28:51 -0700
committerCliff Click <cliffc@acm.org>2025-04-08 14:28:51 -0700
commit938c09baca29b0647dcd56e9581540d7a8142fb4 (patch)
tree0c213a1ead31de632b88f29308a9a00f8c8f76ee /chapter21
parent06872d180720c376d3fdcc0bd0a2a973bf9341c4 (diff)
downloadSimple-938c09baca29b0647dcd56e9581540d7a8142fb4.tar.gz
Simple-938c09baca29b0647dcd56e9581540d7a8142fb4.zip
Fix risc5 bugs from emulator
Diffstat (limited to 'chapter21')
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java2
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java33
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java67
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java12
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c2
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/progs/person.smp1
7 files changed, 72 insertions, 47 deletions
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index a92b4e21..b8eb7644 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
@@ -52,7 +52,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode {
// float
if(_declaredType == TypeFloat.F32) func3 = 2; // fLW fSW
if(_declaredType == TypeFloat.F64) func3 = 3; // fLD fSD
- if( _declaredType instanceof TypeMemPtr ) func3=6; // 4 byte pointers, assumed unsigned?
+ if( _declaredType instanceof TypeMemPtr ) func3=3; // 8 byte pointers
if( func3 == -1 ) throw Utils.TODO();
return func3;
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
index e82a6f24..fe767a36 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
@@ -497,7 +497,7 @@ public class riscv extends Machine {
return new BranchRISC(iff, bop, bool.in(1), bool.in(2));
}
// Vs zero
- return new BranchRISC(iff, "==", iff.in(1), null);
+ return new BranchRISC(iff, "!=", iff.in(1), null);
}
private Node or(OrNode or) {
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index e3239c48..a5316d62 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -98,19 +98,46 @@ public class Chapter21Test {
String fib = "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]";
TestC.run("fib", fib);
- EvalRisc5 R5 = TestRisc5.run("fib", 1000, 8);
- // Return register A0 holds 55
+ EvalRisc5 R5 = TestRisc5.build("fib", 8);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ // Return register A0 holds fib(8)==55
assertEquals(55,R5.regs[riscv.A0]);
}
@Test public void testBrainFuck() throws IOException {
- String brain_fuck = "Hello World!\r\n";
+ String brain_fuck = "Hello World!\n";
TestC.run("brain_fuck", brain_fuck);
}
@Test public void testPerson() throws IOException {
String person = "6\n";
TestC.run("person", person);
+
+ // Memory layout starting at PS:
+ int ps = 1<<16; // Person array pointer
+ // Person[3] = { len,pad,P0,P1,P2 }; // sizeof = 4*8
+ // P0 = { age } // sizeof=8
+ int p0 = ps+4*8+0*8;
+ // P1 = { age } // sizeof=8
+ int p1 = ps+4*8+1*8;
+ // P2 = { age } // sizeof=8
+ int p2 = ps+4*8+2*8;
+ EvalRisc5 R5 = TestRisc5.build("person", ps);
+ R5.regs[riscv.A1] = 1; // Index 1
+ R5.st4(ps,3); // Length
+ R5.st8(ps+1*8,p0);
+ R5.st8(ps+2*8,p1);
+ R5.st8(ps+3*8,p2);
+ R5.st8(p0, 5); // age= 5
+ R5.st8(p1,17); // age=17
+ R5.st8(p2,60); // age=60
+
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals( 5+0,R5.ld8(p0));
+ assertEquals(17+1,R5.ld8(p1));
+ assertEquals(60+0,R5.ld8(p2));
}
@Ignore
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
index bced2505..cb5417d8 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
@@ -27,19 +27,21 @@ public class EvalRisc5 {
//#endif
// 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 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 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 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)); }
// GPRs
- final int[] regs = new int[32];
+ final long[] regs = new long[32];
// PC
int _pc;
@@ -55,7 +57,7 @@ public class EvalRisc5 {
public int step( int maxops ) {
int trap = 0;
- int rval = 0;
+ long rval = 0;
int pc = _pc;
int cycle = _cycle;
@@ -95,7 +97,7 @@ public class EvalRisc5 {
int imm = ir >> 20;
int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0);
rval = pc + 4;
- pc = ( (regs[ (ir >> 15) & 0x1f ] + imm_se) & ~1) - 4;
+ pc = ( ((int)regs[ (ir >> 15) & 0x1f ] + imm_se) & ~1) - 4;
// Return from top-level ; exit sim
if( pc+4==0 ) {
if( rdid!=0 ) regs[rdid] = rval;
@@ -106,29 +108,28 @@ public class EvalRisc5 {
case 0x63: { // Branch (0b1100011)
int immm4 = ((ir & 0xf00)>>7) | ((ir & 0x7e000000)>>20) | ((ir & 0x80) << 4) | ((ir >> 31)<<12);
if( (immm4 & 0x1000)!=0 ) immm4 |= 0xffffe000;
- int rs1 = regs[(ir >> 15) & 0x1f];
- int rs2 = regs[(ir >> 20) & 0x1f];
+ long rs1 = regs[(ir >> 15) & 0x1f];
+ long rs2 = regs[(ir >> 20) & 0x1f];
immm4 = pc + immm4 - 4;
rdid = 0;
switch( ( ir >> 12 ) & 0x7 ) {
// BEQ, BNE, BLT, BGE, BLTU, BGEU
case 0: if( rs1 == rs2 ) pc = immm4; break;
case 1: if( rs1 != rs2 ) pc = immm4; break;
- case 4: if( rs1 < rs2 ) pc = immm4; break;
- case 5: if( rs1 >= rs2 ) pc = immm4; break; //BGE
- case 6: if( (int)rs1 < (int)rs2 ) pc = immm4; break; //BLTU
- case 7: if( (int)rs1 >= (int)rs2 ) pc = immm4; break; //BGEU
+ case 4: if( rs1 < rs2 ) pc = immm4; break;
+ case 5: if( rs1 >= rs2 ) pc = immm4; break;
+ case 6: if( Long.compareUnsigned(rs1,rs2) < 0 ) pc = immm4; break; //BLTU
+ case 7: if( Long.compareUnsigned(rs1,rs2) >= 0 ) pc = immm4; break; //BGEU
default: trap = (2+1);
}
break;
}
case 0x03: { // Load (0b0000011)
- int rs1 = regs[(ir >> 15) & 0x1f];
+ 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;
- rsval -= 0;
if( rsval >= _buf.length-3 ) {
trap = (5+1);
rval = rsval;
@@ -138,6 +139,7 @@ public class EvalRisc5 {
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;
default: trap = (2+1);
@@ -146,11 +148,11 @@ public class EvalRisc5 {
break;
}
case 0x23: { // Store 0b0100011
- int rs1 = regs[(ir >> 15) & 0x1f];
- int rs2 = regs[(ir >> 20) & 0x1f];
+ 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 - 0;
+ addy += rs1;
rdid = 0;
if( addy >= _buf.length-3 ) {
@@ -158,9 +160,10 @@ public class EvalRisc5 {
rval = addy;
} else {
switch( ( ir >> 12 ) & 0x7 ) { //SB, SH, SW
- case 0: st1( addy, rs2 ); break;
- case 1: st2( addy, rs2 ); break;
- case 2: st4( addy, rs2 ); break;
+ 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);
}
}
@@ -170,9 +173,9 @@ public class EvalRisc5 {
case 0x33: { // Op 0b0110011
int imm = ir >> 20;
imm = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0);
- int rs1 = regs[(ir >> 15) & 0x1f];
+ long rs1 = regs[(ir >> 15) & 0x1f];
boolean is_reg = (ir & 0x20)!=0;
- int rs2 = is_reg ? regs[imm & 0x1f] : imm;
+ long rs2 = is_reg ? regs[imm & 0x1f] : imm;
if( is_reg && ( ir & 0x02000000 )!=0 ) {
switch( (ir>>12)&7 ) { //0x02000000 = RV32M
@@ -208,8 +211,8 @@ public class EvalRisc5 {
break;
case 0x2f: { // RV32A (0b00101111)
- int rs1 = regs[(ir >> 15) & 0x1f];
- int rs2 = regs[(ir >> 20) & 0x1f];
+ 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.
@@ -217,14 +220,14 @@ public class EvalRisc5 {
trap = (7+1); //Store/AMO access fault
rval = rs1;
} else {
- rval = ld4s( rs1 );
+ 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) | (rs1<<3);
+ _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 );
@@ -243,7 +246,7 @@ public class EvalRisc5 {
case 28: rs2 = Math.max( rs2, rval ); break; //AMOMAXU.W (0b11100)
default: trap = (2+1); dowrite = false; break; //Not supported.
}
- if( dowrite ) st4( rs1, rs2 );
+ if( dowrite ) st4( (int)rs1, (int)rs2 );
}
break;
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
index 29be1814..275cdebb 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
@@ -10,12 +10,12 @@ import java.io.IOException;
// Runs 32-bit R5 code in an emulator
public abstract class TestRisc5 {
- public static EvalRisc5 run( String file, int steps, int arg ) throws IOException {
- return run("src/test/java/com/seaofnodes/simple/progs",file,steps, arg);
+ public static EvalRisc5 build( String file, int arg ) throws IOException {
+ return build("src/test/java/com/seaofnodes/simple/progs",file, arg);
}
// Compile and run a simple program
- public static EvalRisc5 run( String dir, String file, int steps, int arg ) throws IOException {
+ public static EvalRisc5 build( String dir, String file, int arg ) throws IOException {
// Compile and export Simple
String src = Files.readString(Path.of(dir+"/"+file+".smp"));
CodeGen code = new CodeGen(src).parse().opto().typeCheck().instSelect( "riscv", "SystemV").GCM().localSched().regAlloc().encode();
@@ -32,11 +32,7 @@ public abstract class TestRisc5 {
// Initial incoming int arg
R5.regs[riscv.A0] = arg;
// malloc memory starts at 64K and goes up
-
- // Run until stopped or steps
- int trap = R5.step(steps);
- Assert.assertEquals(0,trap); // Exit for steps, not trap
-
return R5;
}
+
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c b/chapter21/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c
index 9efc7d5b..bf981afd 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c
+++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c
@@ -11,7 +11,7 @@ extern AryInt* brain_fuck();
int main() {
AryInt* ps = brain_fuck();
- printf("%.*s", ps->len, ps->data);
+ printf("%.*s", ps->len, ps->data);
return 0;
} \ No newline at end of file
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/person.smp b/chapter21/src/test/java/com/seaofnodes/simple/progs/person.smp
index 9791f252..9f0f5bea 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/progs/person.smp
+++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/person.smp
@@ -4,7 +4,6 @@ struct Person {
};
val fcn = { Person?[] ps, int x ->
- val tmp = ps[x];
if( ps[x] )
ps[x].age++;
}; \ No newline at end of file