From 8f39a6cb1568f39c623cdb3e60c2848f3252b196 Mon Sep 17 00:00:00 2001 From: Nathan Lee Date: Sat, 6 Jun 2026 14:29:39 -0500 Subject: refactor most extensions in to their own separate core.rs file --- src/core.rs | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 222 ++++++++++++++---------------------------------------- 2 files changed, 303 insertions(+), 164 deletions(-) create mode 100644 src/core.rs (limited to 'src') diff --git a/src/core.rs b/src/core.rs new file mode 100644 index 0000000..ff6bb52 --- /dev/null +++ b/src/core.rs @@ -0,0 +1,245 @@ +pub fn add(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1].wrapping_add(registers[rs2]); +} + +pub fn sub(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1].wrapping_sub(registers[rs2]); +} + +pub fn xor(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1] ^ registers[rs2]; +} + +pub fn or(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1] | registers[rs2]; +} + +pub fn and(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1] & registers[rs2]; +} + +pub fn sll(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1] << (registers[rs2] & 0b11111); +} + +pub fn srl(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1] >> (registers[rs2] & 0b11111); +} + +pub fn sra(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = ((registers[rs1] as i32) >> (registers[rs2] & 0b11111)) as u32; +} + +pub fn slt(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + let rs1_signed = registers[rs1] as i32; + let rs2_signed = registers[rs2] as i32; + + registers[rd] = if rs1_signed < rs2_signed { 1 } else { 0 }; +} + +pub fn sltu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = if registers[rs1] < registers[rs2] { + 1 + } else { + 0 + }; +} + +pub fn mul(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = registers[rs1].wrapping_mul(registers[rs2]); +} + +pub fn mulh(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = + (((registers[rs1] as i32 as i64) * (registers[rs2] as i32 as i64)) >> 32) as u32; +} + +pub fn mulhsu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + let rs1_signed = (registers[rs1] as i32) as i64; + let rs2_unsigned = registers[rs2] as i64; + + registers[rd] = ((rs1_signed * rs2_unsigned) >> 32) as u32; +} + +pub fn mulhu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = ((registers[rs1] as u64 * registers[rs2] as u64) >> 32) as u32; +} + +pub fn div(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + let a = registers[rs1] as i32; + let b = registers[rs2] as i32; + + registers[rd] = if b == 0 { + u32::MAX + } else if a == i32::MIN && b == -1 { + a as u32 + } else { + (a / b) as u32 + }; +} + +pub fn divu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = if registers[rs2] == 0 { + u32::MAX + } else { + registers[rs1] / registers[rs2] + }; +} + +pub fn rem(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + let a = registers[rs1] as i32; + let b = registers[rs2] as i32; + + registers[rd] = if b == 0 { + a as u32 + } else if a == i32::MIN && b == -1 { + 0 + } else { + (a % b) as u32 + }; +} + +pub fn remu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { + registers[rd] = if registers[rs2] == 0 { + registers[rs1] + } else { + registers[rs1] % registers[rs2] + }; +} + +pub fn addi(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = registers[rs1].wrapping_add(imm); +} + +pub fn xori(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = registers[rs1] ^ imm; +} + +pub fn ori(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = registers[rs1] | imm; +} + +pub fn andi(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = registers[rs1] & imm; +} + +pub fn slli(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = registers[rs1] << (imm & 0b11111); +} +pub fn srli(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = registers[rs1] >> (imm & 0b11111); +} +pub fn srai(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = ((registers[rs1] as i32) >> (imm & 0b11111)) as u32; +} + +pub fn slti(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = if (registers[rs1] as i32) < (imm as i32) { + 1 + } else { + 0 + }; +} + +pub fn sltiu(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { + registers[rd] = if registers[rs1] < imm { 1 } else { 0 }; +} +pub fn lb(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { + let byte = memory[(registers[rs1] + imm) as usize]; + registers[rd] = (byte as i8) as u32; +} + +pub fn lh(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { + let low = memory[(registers[rs1] + imm) as usize]; + let high = memory[(registers[rs1] + imm + 1) as usize]; + + registers[rd] = (((high as u16) << 8 | low as u16) as i16) as u32; +} + +pub fn lw(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { + let addr = (registers[rs1] + imm) as usize; + let slice = memory.get(addr..addr + 4).unwrap(); + let number = u32::from_le_bytes(slice.try_into().unwrap()); + + registers[rd] = number; +} + +pub fn lbu(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { + registers[rd] = memory[(registers[rs1] + imm) as usize] as u32; +} + +pub fn lhu(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { + let low = memory[(registers[rs1] + imm) as usize]; + let high = memory[(registers[rs1] + imm + 1) as usize]; + + registers[rd] = ((high as u16) << 8 | low as u16) as u32; +} +pub fn sb(registers: &[u32; 32], memory: &mut [u8], rs1: usize, rs2: usize, imm: u32) { + memory[(registers[rs1] + imm) as usize] = registers[rs2] as u8; +} + +pub fn sh(registers: &[u32; 32], memory: &mut [u8], rs1: usize, rs2: usize, imm: u32) { + let halfword = registers[rs2] & 0xFFFF; + let index = (registers[rs1] + imm) as usize; + + memory[index] = (halfword & 0xFF) as u8; + memory[index + 1] = (halfword >> 8) as u8; +} + +pub fn sw(registers: &[u32; 32], memory: &mut [u8], rs1: usize, rs2: usize, imm: u32) { + let index = (registers[rs1] + imm) as usize; + + memory[index..index + 4].copy_from_slice(®isters[rs2].to_le_bytes()); +} + +pub fn beq(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { + if registers[rs1] == registers[rs2] { + *pc += imm; + } +} + +pub fn bne(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { + if registers[rs1] != registers[rs2] { + *pc += imm; + } +} + +pub fn blt(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { + if (registers[rs1] as i32) < (registers[rs2] as i32) { + *pc += imm; + } +} + +pub fn bge(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { + if (registers[rs1] as i32) >= (registers[rs2] as i32) { + *pc += imm; + } +} + +pub fn bltu(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { + if registers[rs1] < registers[rs2] { + *pc += imm; + } +} + +pub fn bgeu(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { + if registers[rs1] >= registers[rs2] { + *pc += imm; + } +} +pub fn jal(registers: &mut [u32; 32], pc: &mut u32, rd: usize, imm: u32) { + registers[rd] = *pc + 4; + *pc += imm; +} + +pub fn jalr(registers: &mut [u32; 32], pc: &mut u32, rd: usize, rs1: usize, imm: u32) { + registers[rd] = *pc + 4; + *pc = registers[rs1] + imm; +} +pub fn lui(registers: &mut [u32; 32], rd: usize, imm: u32) { + registers[rd] = imm << 12; +} + +pub fn auipc(registers: &mut [u32; 32], pc: u32, rd: usize, imm: u32) { + registers[rd] = pc + (imm << 12); +} diff --git a/src/main.rs b/src/main.rs index 36c1c8c..a351d48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,12 @@ +pub mod core; + use elf::ElfBytes; use elf::endian::AnyEndian; use std::io; use std::io::Write; use std::process::exit; use std::sync::{LazyLock, Mutex}; +use crate::core::*; const MEMORY_SIZE: usize = 64 * 1024 * 1024; const REGISTER_NAME_WIDTH: u32 = 0b11111; @@ -85,79 +88,24 @@ fn handle_instruction(CpuState { memory, registers, pc, reservations }: CpuState let rd = ((word >> 7) & REGISTER_NAME_WIDTH) as usize; match (f7 << 3) | f3 { - 0 => registers[rd] = registers[rs1].wrapping_add(registers[rs2]), // add - 256 => registers[rd] = registers[rs1].wrapping_sub(registers[rs2]), // sub - 4 => registers[rd] = registers[rs1] ^ registers[rs2], // xor - 6 => registers[rd] = registers[rs1] | registers[rs2], // or - 7 => registers[rd] = registers[rs1] & registers[rs2], // and - 1 => registers[rd] = registers[rs1] << (registers[rs2] & 0b11111), // sll - 5 => registers[rd] = registers[rs1] >> (registers[rs2] & 0b11111), // srl - 261 => { - registers[rd] = ((registers[rs1] as i32) >> (registers[rs2] & 0b11111)) as u32 - } // sra - 2 => { - let rs1_signed: i32 = registers[rs1] as i32; - let rs2_signed: i32 = registers[rs2] as i32; - registers[rd] = if rs1_signed < rs2_signed { 1 } else { 0 }; // slt - } - 3 => { - registers[rd] = if registers[rs1] < registers[rs2] { - 1 - } else { - 0 - } - } // sltu - 8 => registers[rd] = registers[rs1].wrapping_mul(registers[rs2]), // mul - 9 => { - registers[rd] = (((registers[rs1] as i32 as i64) - * (registers[rs2] as i32 as i64)) - >> 32) as u32 - } // mulh - 10 => { - let rs1_signed = (registers[rs1] as i32) as i64; - let rs2_unsigned = registers[rs2] as i64; - registers[rd] = ((rs1_signed * rs2_unsigned) >> 32) as u32; - } // mulhsu - 11 => { - registers[rd] = ((registers[rs1] as u64 * registers[rs2] as u64) >> 32) as u32 - } // mulhu - 12 => { - let a = registers[rs1] as i32; - let b = registers[rs2] as i32; - registers[rd] = if b == 0 { - u32::MAX - } else if a == i32::MIN && b == -1 { - a as u32 - } else { - (a / b) as u32 - }; - } // div - 13 => { - registers[rd] = if registers[rs2] == 0 { - u32::MAX - } else { - registers[rs1] / registers[rs2] - } - } // divu - 14 => { - let a = registers[rs1] as i32; - let b = registers[rs2] as i32; - registers[rd] = if b == 0 { - a as u32 - } else if a == i32::MIN && b == -1 { - 0 - } else { - (a % b) as u32 - } - } // rem - 15 => { - registers[rd] = if registers[rs2] == 0 { - registers[rs1] - } else { - registers[rs1] % registers[rs2] - } - } //remu - + 0 => add(registers, rd, rs1, rs2), + 256 => sub(registers, rd, rs1, rs2), + 4 => xor(registers, rd, rs1, rs2), + 6 => or(registers, rd, rs1, rs2), + 7 => and(registers, rd, rs1, rs2), + 1 => sll(registers, rd, rs1, rs2), + 5 => srl(registers, rd, rs1, rs2), + 261 => sra(registers, rd, rs1, rs2), + 2 => slt(registers, rd, rs1, rs2), + 3 => sltu(registers, rd, rs1, rs2), + 8 => mul(registers, rd, rs1, rs2), + 9 => mulh(registers, rd, rs1, rs2), + 10 => mulhsu(registers, rd, rs1, rs2), + 11 => mulhu(registers, rd, rs1, rs2), + 12 => div(registers, rd, rs1, rs2), + 13 => divu(registers, rd, rs1, rs2), + 14 => rem(registers, rd, rs1, rs2), + 15 => remu(registers, rd, rs1, rs2), _ => panic!("Illegal instruction: {:x}", word), } } @@ -169,34 +117,28 @@ fn handle_instruction(CpuState { memory, registers, pc, reservations }: CpuState let rd = ((word >> 7) & 0b11111) as usize; match f3 { - 0 => registers[rd] = registers[rs1].wrapping_add(imm), // addi - 4 => registers[rd] = registers[rs1] ^ imm, // xori - 6 => registers[rd] = registers[rs1] | imm, // ori - 7 => registers[rd] = registers[rs1] & imm, // andi + 0 => addi(registers, rd, rs1, imm), + 4 => xori(registers, rd, rs1, imm), + 6 => ori(registers, rd, rs1, imm), + 7 => andi(registers, rd, rs1, imm), 1 => { if (imm >> 5) != 0 { panic!("Illegal instruction: {:x}", word); } - registers[rd] = registers[rs1] << (imm & 0b11111); // slli + slli(registers, rd, rs1, imm); } 5 => { if (imm >> 5) != 0 { panic!("Illegal instruction: {:x}", word); } if (imm >> 5) & 0b1111111 == 0 { - registers[rd] = registers[rs1] >> (imm & 0b11111); // srli + srli(registers, rd, rs1, imm); } else { - registers[rd] = (registers[rs1] as i32 >> (imm & 0b11111)) as u32; // srai + srai(registers, rd, rs1, imm); } } - 2 => { - registers[rd] = if (registers[rs1] as i32) < (imm as i32) { - 1 - } else { - 0 - } - } // slti - 3 => registers[rd] = if registers[rs1] < imm { 1 } else { 0 }, // sltiu + 2 => slti(registers, rd, rs1, imm), + 3 => sltiu(registers, rd, rs1, imm), _ => panic!("Illegal instruction: {:x}", word), } } @@ -208,27 +150,11 @@ fn handle_instruction(CpuState { memory, registers, pc, reservations }: CpuState let rd = ((word >> 7) & 0b11111) as usize; match f3 { - 0 => { - let byte: u8 = memory[(registers[rs1] + imm) as usize]; - registers[rd] = (byte as i8) as u32; // lb - } - 1 => { - let low = memory[(registers[rs1] + imm) as usize]; - let high = memory[(registers[rs1] + imm + 1) as usize]; - registers[rd] = (((high as u16) << 8 | low as u16) as i16) as u32; // lh - } - 2 => { - let addr = (registers[rs1] + imm) as usize; - let slice = memory.get(addr..addr + 4).unwrap(); - let number: u32 = u32::from_le_bytes(slice.try_into().unwrap()); - registers[rd] = number; // lw - } - 4 => registers[rd] = memory[(registers[rs1] + imm) as usize] as u32, // lbu - 5 => { - let low = memory[(registers[rs1] + imm) as usize]; - let high = memory[(registers[rs1] + imm + 1) as usize]; - registers[rd] = ((high as u16) << 8 | low as u16) as u32; // lhu - } + 0 => lb(registers, memory, rd, rs1, imm), + 1 => lh(registers, memory, rd, rs1, imm), + 2 => lw(registers, memory, rd, rs1, imm), + 4 => lbu(registers, memory, rd, rs1, imm), + 5 => lhu(registers, memory, rd, rs1, imm), _ => panic!("Illegal instruction: {:x}", word), } } @@ -242,17 +168,9 @@ fn handle_instruction(CpuState { memory, registers, pc, reservations }: CpuState let imm = ((((imm_high << 5) | imm_low) as i32) << 20 >> 20) as u32; match f3 { - 0 => memory[(registers[rs1] + imm) as usize] = registers[rs2] as u8, // sb - 1 => { - let halfword = registers[rs2] & 0xFFFF; - let index = (registers[rs1] + imm) as usize; - memory[index] = (halfword & 0xFF) as u8; - memory[index + 1] = (halfword >> 8) as u8; - } // sh - 2 => { - let index = (registers[rs1] + imm) as usize; - memory[index..index + 4].copy_from_slice(®isters[rs2].to_le_bytes()); // sw - } + 0 => sb(registers, memory, rs1, rs2, imm), // sb + 1 => sh(registers, memory, rs1, rs2, imm), + 2 => sw(registers, memory, rs1, rs2, imm), _ => panic!("Illegal instruction: {:x}", word), }; } @@ -269,51 +187,27 @@ fn handle_instruction(CpuState { memory, registers, pc, reservations }: CpuState let imm = ((imm as i32) << 19 >> 19) as u32; match f3 { - 0 => { - if registers[rs1] == registers[rs2] { - *pc += imm; - } - return; - } // beq - 1 => { - if registers[rs1] != registers[rs2] { - *pc += imm; - } - return; - } // bne - 4 => { - if (registers[rs1] as i32) < (registers[rs2] as i32) { - *pc += imm; - } - return; - } // blt - 5 => { - if (registers[rs1] as i32) >= (registers[rs2] as i32) { - *pc += imm; - } - return; - } // bge - 6 => { - if registers[rs1] < registers[rs2] { - *pc += imm; - } - return; - } // bltu - 7 => { - if registers[rs1] >= registers[rs2] { - *pc += imm; - } - return; - } // bgeu + 0 => beq(registers, pc, rs1, rs2, imm), + 1 => bne(registers, pc, rs1, rs2, imm), + 4 => blt(registers, pc, rs1, rs2, imm), + 5 => bge(registers, pc, rs1, rs2, imm), + 6 => bltu(registers, pc, rs1, rs2, imm), + 7 => bgeu(registers, pc, rs1, rs2, imm), _ => panic!("Illegal instruction: {:x}", word), } + return; } 0b1101111 => { let rd = (word >> 7) & REGISTER_NAME_WIDTH; - let imm = word >> 12; - registers[rd as usize] = *pc + 4; - *pc += imm; - } // jal + let imm = + (((word >> 31) & 0x1) << 20) | + (((word >> 12) & 0xFF) << 12) | + (((word >> 20) & 0x1) << 11) | + (((word >> 21) & 0x3FF) << 1); + let imm = ((imm as i32) << 11 >> 11) as u32; + jal(registers, pc, rd as usize, imm); + return; + } 0b1100111 => { let rs1 = (word >> 15) & REGISTER_NAME_WIDTH; let rd = (word >> 7) & REGISTER_NAME_WIDTH; @@ -324,18 +218,18 @@ fn handle_instruction(CpuState { memory, registers, pc, reservations }: CpuState panic!("Illegal instruction: {:x}", word); } - registers[rd as usize] = *pc + 4; - *pc = registers[rs1 as usize] + imm; + jalr(registers, pc, rd as usize, rs1 as usize, imm); + return; } 0b0110111 => { let imm = word >> 12; let rd = ((word >> 7) & 0b11111) as usize; - registers[rd] = imm << 12; // lui + lui(registers, rd, imm); } 0b0010111 => { let imm = word >> 12; let rd = (word >> 7) & REGISTER_NAME_WIDTH; - registers[rd as usize] = *pc + (imm << 12); // auipc + auipc(registers, *pc, rd as usize, imm); } 0b1110011 => { // ecall -- cgit v1.2.3