commit 3850c2744039a4604e364de2ba06af94ba46fcd1 Author: Minecon724 Date: Sun Oct 13 17:00:40 2024 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56ffa04 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/ \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..2b13975 --- /dev/null +++ b/README.txt @@ -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 \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0c228ef --- /dev/null +++ b/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + eu.m724 + risc + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/src/main/java/eu/m724/AddressSpace.java b/src/main/java/eu/m724/AddressSpace.java new file mode 100644 index 0000000..0b1ffba --- /dev/null +++ b/src/main/java/eu/m724/AddressSpace.java @@ -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 + * + * @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> (8 * i) & 0xFF); + } + } +} diff --git a/src/main/java/eu/m724/CPU.java b/src/main/java/eu/m724/CPU.java new file mode 100644 index 0000000..1ac7495 --- /dev/null +++ b/src/main/java/eu/m724/CPU.java @@ -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