initial commit
This commit is contained in:
commit
3850c27440
7 changed files with 343 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/
|
4
README.txt
Normal file
4
README.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
This is just for me to understand how all this works, and to learn something new.
|
||||||
|
|
||||||
|
For example, I learned that endianness is not per bit but per byte. My whole life I've been in misinformation.
|
||||||
|
So little endian is not that first bit is the LSB, but it's MSB... and after 8 bits it becomes larger, which makes no point
|
17
pom.xml
Normal file
17
pom.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>eu.m724</groupId>
|
||||||
|
<artifactId>risc</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
85
src/main/java/eu/m724/AddressSpace.java
Normal file
85
src/main/java/eu/m724/AddressSpace.java
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package eu.m724;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an address space
|
||||||
|
*
|
||||||
|
* Basically, there's ROM, then RAM, then IO
|
||||||
|
*/
|
||||||
|
public class AddressSpace {
|
||||||
|
public final int romBase, romSize;
|
||||||
|
public final int ramBase, ramSize;
|
||||||
|
public boolean isRomInit;
|
||||||
|
|
||||||
|
private final byte[] rom;
|
||||||
|
private final byte[] ram;
|
||||||
|
|
||||||
|
public AddressSpace(int romSize, int ramSize) {
|
||||||
|
this.romBase = 0;
|
||||||
|
this.ramBase = romSize;
|
||||||
|
|
||||||
|
this.romSize = romSize;
|
||||||
|
this.ramSize = ramSize;
|
||||||
|
|
||||||
|
this.rom = new byte[romSize];
|
||||||
|
this.ram = new byte[ramSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initRom(byte[] program) { // TODO test method
|
||||||
|
if (isRomInit) throw new RuntimeException("ROM already initialized");
|
||||||
|
isRomInit = true;
|
||||||
|
|
||||||
|
for (int i=0; i<program.length; i++) {
|
||||||
|
rom[i] = program[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read {@code n} bytes from ROM<br>
|
||||||
|
*
|
||||||
|
* @param address address of first byte
|
||||||
|
* @param n number of bytes, max 8
|
||||||
|
* @return the unsigned bytes
|
||||||
|
*/
|
||||||
|
long readRom(int address, int n) {
|
||||||
|
long v = 0;
|
||||||
|
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
v |= (long) (rom[address + i] & 0xFF) << (8 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read {@code n} bytes from RAM
|
||||||
|
*
|
||||||
|
* @param address address of first byte
|
||||||
|
* @param n number of bytes, max 8
|
||||||
|
* @return the unsigned bytes
|
||||||
|
*/
|
||||||
|
long readRam(int address, int n) {
|
||||||
|
long v = 0;
|
||||||
|
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
v |= (long) (ram[address + i] & 0xFF) << (8 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write {@code} value to RAM
|
||||||
|
*
|
||||||
|
* @param address the address of first byte
|
||||||
|
* @param n number of bytes of value, max 8
|
||||||
|
* @param value the value
|
||||||
|
*/
|
||||||
|
void writeRam(int address, int n, long value) {
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
ram[address + i] = (byte) (value >> (8 * i) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
202
src/main/java/eu/m724/CPU.java
Normal file
202
src/main/java/eu/m724/CPU.java
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
package eu.m724;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a rv32i CPU
|
||||||
|
*/
|
||||||
|
public class CPU {
|
||||||
|
private final int xsize = 32;
|
||||||
|
private final int[] register = new int[32];
|
||||||
|
|
||||||
|
private AddressSpace addressSpace;
|
||||||
|
private int programCounter;
|
||||||
|
|
||||||
|
public void init(AddressSpace addressSpace) {
|
||||||
|
this.addressSpace = addressSpace; // TODO should addressspace really be linked
|
||||||
|
|
||||||
|
register[2] = addressSpace.romSize + addressSpace.ramSize;
|
||||||
|
programCounter = addressSpace.romBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNextInstruction() {
|
||||||
|
if (programCounter > addressSpace.romSize - 1)
|
||||||
|
throw new NullPointerException();
|
||||||
|
|
||||||
|
int inst = (int) addressSpace.readRom(programCounter, 4);
|
||||||
|
programCounter += 4;
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean executeNextInstruction() {
|
||||||
|
try {
|
||||||
|
executeInstruction(getNextInstruction());
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void executeInstruction(int instruction) {
|
||||||
|
register[0] = 0x0; // so it's not signed
|
||||||
|
int opcode = instruction & 0x7F;
|
||||||
|
int rd = instruction >> 7 & 0x1F;
|
||||||
|
|
||||||
|
if (opcode != 0) {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("Instruction: " + Integer.toBinaryString(instruction));
|
||||||
|
System.out.println("Opcode: " + Integer.toBinaryString(opcode));
|
||||||
|
System.out.println("Destination register: " + Integer.toBinaryString(rd));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode == 0b0010011) { // OP-IMM for Integer Register-Immediate Instructions (I type)
|
||||||
|
int funct3 = instruction >> 12 & 0x7;
|
||||||
|
int rs1 = instruction >> 15 & 0x1F;
|
||||||
|
int imm = instruction >> 20 & 0xFFF;
|
||||||
|
|
||||||
|
if (funct3 == 0b000) { // ADDI
|
||||||
|
System.out.printf("ADDI: %d #%d + %d imm = #%d\n", register[rs1], rs1, imm, rd);
|
||||||
|
|
||||||
|
register[rd] = register[rs1] + imm;
|
||||||
|
} else if (funct3 == 0b010) { // SLTI
|
||||||
|
System.out.println("SLTI");
|
||||||
|
} else if (funct3 == 0b011) { // SLTIU
|
||||||
|
System.out.println("SLTIU");
|
||||||
|
} else if (funct3 == 0b100) { // XORI
|
||||||
|
System.out.println("XORI");
|
||||||
|
} else if (funct3 == 0b110) { // ORI
|
||||||
|
System.out.println("ORI");
|
||||||
|
} else if (funct3 == 0b111) { // ANDI
|
||||||
|
System.out.println("ANDI");
|
||||||
|
} else if (funct3 == 0b001) { // SLLI
|
||||||
|
System.out.println("SLLI");
|
||||||
|
} else if (funct3 == 0b101) { // SRLI / SRAI
|
||||||
|
int funct7 = instruction >> 25 & 0x7F;
|
||||||
|
|
||||||
|
if (funct7 == 0b0000000) { // SRLI
|
||||||
|
System.out.println("SRLI");
|
||||||
|
} else if (funct7 == 0b0100000) { // SRAI
|
||||||
|
System.out.println("SRAI");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (opcode == 0b0110111) { // LUI load upper immediate (U type)
|
||||||
|
|
||||||
|
} else if (opcode == 0b0010111) { // AUIPC (add upper immediate to pc) (U type)
|
||||||
|
|
||||||
|
} else if (opcode == 0b0110011) { // OP for Integer Register-Register Operations (R type)
|
||||||
|
int funct3 = instruction >> 12 & 0x7;
|
||||||
|
|
||||||
|
if (funct3 == 0b000) { // ADD / SUB
|
||||||
|
int funct7 = instruction >> 25 & 0x7F;
|
||||||
|
|
||||||
|
if (funct7 == 0b0000000) { // ADD
|
||||||
|
int rs1 = instruction >> 15 & 0x1F;
|
||||||
|
int rs2 = instruction >> 20 & 0x1F;
|
||||||
|
|
||||||
|
int sum = register[rs1] + register[rs2] & 0xFF; // to overflow
|
||||||
|
|
||||||
|
System.out.printf("ADD: %d #%d + %d #%d = %d #%d\n", register[rs1], rs1, register[rs2], rs2, sum, rd);
|
||||||
|
|
||||||
|
register[rd] = sum;
|
||||||
|
} else if (funct7 == 0b0100000) { // SUB
|
||||||
|
System.out.println("SUB");
|
||||||
|
}
|
||||||
|
} else if (funct3 == 0b001) { // SLL
|
||||||
|
|
||||||
|
} else if (funct3 == 0b010) { // SLT
|
||||||
|
|
||||||
|
} else if (funct3 == 0b011) { // SLTU
|
||||||
|
|
||||||
|
} else if (funct3 == 0b100) { // XOR
|
||||||
|
|
||||||
|
} else if (funct3 == 0b101) { // SRL / SRA
|
||||||
|
int funct7 = instruction >> 25 & 0x7F;
|
||||||
|
|
||||||
|
if (funct7 == 0b0000000) { // SRL
|
||||||
|
|
||||||
|
} else if (funct7 == 0b0100000) { // SRA
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (funct3 == 0b110) { // OR
|
||||||
|
|
||||||
|
} else if (funct3 == 0b111) { // AND
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (opcode == 0b1101111) { // JAL for unconditional jump (J type)
|
||||||
|
|
||||||
|
} else if (opcode == 0b1100111) { // JALR for unconditional jump and link register (I type)
|
||||||
|
|
||||||
|
} else if (opcode == 0b1100011) { // BRANCH instruction (B type)
|
||||||
|
int funct3 = instruction >> 12 & 0x1F;
|
||||||
|
|
||||||
|
if (funct3 == 0b000) { // BEQ
|
||||||
|
|
||||||
|
} else if (funct3 == 0b001) { // BNE
|
||||||
|
|
||||||
|
} else if (funct3 == 0b100) { // BLT
|
||||||
|
|
||||||
|
} else if (funct3 == 0b101) { // BGE
|
||||||
|
|
||||||
|
} else if (funct3 == 0b110) { // BLTU
|
||||||
|
|
||||||
|
} else if (funct3 == 0b111) { // BGEU
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (opcode == 0b0000011) { // LOAD instruction (I type)
|
||||||
|
int funct3 = instruction >> 12 & 0x1F;
|
||||||
|
|
||||||
|
if (funct3 == 0b000) { // LB
|
||||||
|
|
||||||
|
} else if (funct3 == 0b001) { // LH
|
||||||
|
|
||||||
|
} else if (funct3 == 0b010) { // LW
|
||||||
|
|
||||||
|
} else if (funct3 == 0b100) { // LBU
|
||||||
|
|
||||||
|
} else if (funct3 == 0b101) { // LHU
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (opcode == 0b0100011) { // STORE instruction (S type)
|
||||||
|
int funct3 = instruction >> 12 & 0x1F;
|
||||||
|
|
||||||
|
if (funct3 == 0b000) { // SB
|
||||||
|
|
||||||
|
} else if (funct3 == 0b001) { // SH
|
||||||
|
|
||||||
|
} else if (funct3 == 0b010) { // SW
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (opcode == 0b0001111) { // MISC-MEM for Memory Ordering Instructions (I type)
|
||||||
|
|
||||||
|
|
||||||
|
} else if (opcode == 0b1110011) { // SYSTEM instructions (I type)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a register to a value
|
||||||
|
*
|
||||||
|
* @param index the index of the register
|
||||||
|
* @param value the value
|
||||||
|
*/
|
||||||
|
public void setRegister(int index, int value) {
|
||||||
|
register[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a register's value
|
||||||
|
*
|
||||||
|
* @param index the index of the register
|
||||||
|
*/
|
||||||
|
public int getRegister(int index) {
|
||||||
|
return register[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dumpRegisters() { // TODO debug function
|
||||||
|
System.out.print("Dump of registers");
|
||||||
|
for (int i=0; i<register.length; i++) {
|
||||||
|
if (i % 8 == 0) System.out.println();
|
||||||
|
System.out.printf("#%d: %d (0x%s) | ", i, register[i], Integer.toHexString(register[i]));
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
19
src/main/java/eu/m724/Main.java
Normal file
19
src/main/java/eu/m724/Main.java
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package eu.m724;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
AddressSpace addressSpace = new AddressSpace(1024, 1024); // 1 KiB
|
||||||
|
byte[] program = Base64.getDecoder().decode("kw5QABMPUAKzD98B");
|
||||||
|
addressSpace.initRom(program);
|
||||||
|
|
||||||
|
CPU cpu = new CPU();
|
||||||
|
cpu.init(addressSpace);
|
||||||
|
|
||||||
|
while (cpu.executeNextInstruction()) { }
|
||||||
|
|
||||||
|
System.out.println("\nEnd of program");
|
||||||
|
cpu.dumpRegisters();
|
||||||
|
}
|
||||||
|
}
|
9
src/main/java/eu/m724/Memory.java
Normal file
9
src/main/java/eu/m724/Memory.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package eu.m724;
|
||||||
|
|
||||||
|
public class Memory {
|
||||||
|
private byte[] memory;
|
||||||
|
|
||||||
|
public Memory(int sizeBytes) {
|
||||||
|
memory = new byte[sizeBytes];
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue