initial commit

This commit is contained in:
Minecon724 2024-10-13 17:00:40 +02:00
commit 3850c27440
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
7 changed files with 343 additions and 0 deletions

7
.gitignore vendored Normal file
View 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
View 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
View 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>

View 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);
}
}
}

View 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();
}
}

View 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();
}
}

View file

@ -0,0 +1,9 @@
package eu.m724;
public class Memory {
private byte[] memory;
public Memory(int sizeBytes) {
memory = new byte[sizeBytes];
}
}