From a37a07533fa9b8bd8962ca3c1aea082ae2548651 Mon Sep 17 00:00:00 2001 From: Nathan Lee Date: Wed, 10 Jun 2026 22:10:59 -0500 Subject: move memory and cpu state into its own files --- src/core.rs | 394 ++++++++++++++++++++++++++++++----------------------------- src/main.rs | 344 ++++++++++++++++++++------------------------------- src/mem.rs | 105 ++++++++++++++++ src/state.rs | 22 ++++ 4 files changed, 465 insertions(+), 400 deletions(-) create mode 100644 src/mem.rs create mode 100644 src/state.rs diff --git a/src/core.rs b/src/core.rs index 251336e..67a21de 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,77 +1,81 @@ +use crate::state::CpuState; use std::num::FpCategory; -pub fn add(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1].wrapping_add(registers[rs2]); +pub fn add(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1].wrapping_add(state.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 sub(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1].wrapping_sub(state.registers[rs2]); } -pub fn xor(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] ^ registers[rs2]; +pub fn xor(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1] ^ state.registers[rs2]; } -pub fn or(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] | registers[rs2]; +pub fn or(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1] | state.registers[rs2]; } -pub fn and(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] & registers[rs2]; +pub fn and(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1] & state.registers[rs2]; } -pub fn sll(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] << (registers[rs2] & 0b11111); +pub fn sll(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1] << (state.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 srl(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1] >> (state.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 sra(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = + ((state.registers[rs1] as i32) >> (state.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; +pub fn slt(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + let rs1_signed = state.registers[rs1] as i32; + let rs2_signed = state.registers[rs2] as i32; - registers[rd] = if rs1_signed < rs2_signed { 1 } else { 0 }; + state.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] { +pub fn sltu(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = if state.registers[rs1] < state.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 mul(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = state.registers[rs1].wrapping_mul(state.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 mulh(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = (((state.registers[rs1] as i32 as i64) + * (state.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; +pub fn mulhsu(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + let rs1_signed = (state.registers[rs1] as i32) as i64; + let rs2_unsigned = state.registers[rs2] as i64; - registers[rd] = ((rs1_signed * rs2_unsigned) >> 32) as u32; + state.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 mulhu(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = + ((state.registers[rs1] as u64 * state.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; +pub fn div(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + let a = state.registers[rs1] as i32; + let b = state.registers[rs2] as i32; - registers[rd] = if b == 0 { + state.registers[rd] = if b == 0 { u32::MAX } else if a == i32::MIN && b == -1 { a as u32 @@ -80,19 +84,19 @@ pub fn div(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { }; } -pub fn divu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = if registers[rs2] == 0 { +pub fn divu(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = if state.registers[rs2] == 0 { u32::MAX } else { - registers[rs1] / registers[rs2] + state.registers[rs1] / state.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; +pub fn rem(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + let a = state.registers[rs1] as i32; + let b = state.registers[rs2] as i32; - registers[rd] = if b == 0 { + state.registers[rd] = if b == 0 { a as u32 } else if a == i32::MIN && b == -1 { 0 @@ -101,184 +105,210 @@ pub fn rem(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { }; } -pub fn remu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = if registers[rs2] == 0 { - registers[rs1] +pub fn remu(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = if state.registers[rs2] == 0 { + state.registers[rs1] } else { - registers[rs1] % registers[rs2] + state.registers[rs1] % state.registers[rs2] }; } -pub fn addi(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { - registers[rd] = registers[rs1].wrapping_add(imm); +pub fn addi(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state.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 xori(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state.registers[rs1] ^ imm; } -pub fn ori(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { - registers[rd] = registers[rs1] | imm; +pub fn ori(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state.registers[rs1] | imm; } -pub fn andi(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { - registers[rd] = registers[rs1] & imm; +pub fn andi(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state.registers[rs1] & imm; } -pub fn slli(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { - registers[rd] = registers[rs1] << (imm & 0b11111); +pub fn slli(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state.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 srli(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state.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 srai(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = ((state.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) { +pub fn slti(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = if (state.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 sltiu(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = if state.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 lb(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + let byte = state + .memory + .read((state.registers[rs1] + imm) as usize, 99) + .unwrap(); + state.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]; +pub fn lh(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + let bytes = state + .memory + .read_multiple_bytes((state.registers[rs1] + imm) as usize, 2, 99) + .unwrap(); - registers[rd] = (((high as u16) << 8 | low as u16) as i16) as u32; + state.registers[rd] = (((bytes[1] as u16) << 8 | bytes[0] 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()); +pub fn lw(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + let addr = (state.registers[rs1] + imm) as usize; + let slice = state.memory.read_multiple_bytes(addr, 4, 99).unwrap(); + let number = u32::from_le_bytes(slice[0..4].try_into().unwrap()); - registers[rd] = number; + state.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 lbu(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state + .memory + .read((state.registers[rs1] + imm) as usize, 99) + .unwrap() 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]; +pub fn lhu(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + let bytes = state + .memory + .read_multiple_bytes((state.registers[rs1] + imm) as usize, 2, 99) + .unwrap(); - registers[rd] = ((high as u16) << 8 | low as u16) as u32; + state.registers[rd] = ((bytes[1] as u16) << 8 | bytes[0] 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 sb(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + state + .memory + .write( + (state.registers[rs1] + imm) as usize, + 99, + state.registers[rs2] as u8, + ) + .unwrap(); } -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; +pub fn sh(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + let halfword = state.registers[rs2] & 0xFFFF; + let index = (state.registers[rs1] + imm) as usize; - memory[index] = (halfword & 0xFF) as u8; - memory[index + 1] = (halfword >> 8) as u8; + state + .memory + .write_multiple_bytes(index, &[(halfword & 0xFF) as u8, (halfword >> 8) as u8], 99) + .unwrap(); } -pub fn sw(registers: &[u32; 32], memory: &mut [u8], rs1: usize, rs2: usize, imm: u32) { - let index = (registers[rs1] + imm) as usize; +pub fn sw(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + let index = (state.registers[rs1] + imm) as usize; - memory[index..index + 4].copy_from_slice(®isters[rs2].to_le_bytes()); + state + .memory + .write_multiple_bytes(index, &state.registers[rs2].to_le_bytes(), 99) + .unwrap(); } -pub fn beq(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { - if registers[rs1] == registers[rs2] { - *pc += imm; +pub fn beq(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + if state.registers[rs1] == state.registers[rs2] { + state.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 bne(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + if state.registers[rs1] != state.registers[rs2] { + state.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 blt(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + if (state.registers[rs1] as i32) < (state.registers[rs2] as i32) { + state.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 bge(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + if (state.registers[rs1] as i32) >= (state.registers[rs2] as i32) { + state.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 bltu(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + if state.registers[rs1] < state.registers[rs2] { + state.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 bgeu(state: &mut CpuState, rs1: usize, rs2: usize, imm: u32) { + if state.registers[rs1] >= state.registers[rs2] { + state.pc += imm; } } -pub fn jal(registers: &mut [u32; 32], pc: &mut u32, rd: usize, imm: u32) { - registers[rd] = *pc + 4; - *pc += imm; +pub fn jal(state: &mut CpuState, rd: usize, imm: u32) { + state.registers[rd] = state.pc + 4; + state.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 jalr(state: &mut CpuState, rd: usize, rs1: usize, imm: u32) { + state.registers[rd] = state.pc + 4; + state.pc = state.registers[rs1] + imm; } -pub fn lui(registers: &mut [u32; 32], rd: usize, imm: u32) { - registers[rd] = imm << 12; +pub fn lui(state: &mut CpuState, rd: usize, imm: u32) { + state.registers[rd] = imm << 12; } -pub fn auipc(registers: &mut [u32; 32], pc: u32, rd: usize, imm: u32) { - registers[rd] = pc + (imm << 12); +pub fn auipc(state: &mut CpuState, pc: u32, rd: usize, imm: u32) { + state.registers[rd] = pc + (imm << 12); } -pub fn fmadd_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { - registers[rd] = registers[rs1] * registers[rs2] + registers[rs3]; +pub fn fmadd_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize, rs3: usize) { + state.f_registers[rd] = + state.f_registers[rs1] * state.f_registers[rs2] + state.f_registers[rs3]; } -pub fn fmsub_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { - registers[rd] = registers[rs1] * registers[rs2] - registers[rs3]; +pub fn fmsub_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize, rs3: usize) { + state.f_registers[rd] = + state.f_registers[rs1] * state.f_registers[rs2] - state.f_registers[rs3]; } -pub fn fnmadd_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { - registers[rd] = -registers[rs1] * registers[rs2] + registers[rs3]; +pub fn fnmadd_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize, rs3: usize) { + state.f_registers[rd] = + -state.f_registers[rs1] * state.f_registers[rs2] + state.f_registers[rs3]; } -pub fn fnmsub_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { - registers[rd] = -registers[rs1] * registers[rs2] - registers[rs3]; +pub fn fnmsub_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize, rs3: usize) { + state.f_registers[rd] = + -state.f_registers[rs1] * state.f_registers[rs2] - state.f_registers[rs3]; } -pub fn fadd_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] + registers[rs2]; +pub fn fadd_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1] + state.f_registers[rs2]; } -pub fn fsub_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] - registers[rs2]; +pub fn fsub_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1] - state.f_registers[rs2]; } -pub fn fmul_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] * registers[rs2]; +pub fn fmul_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1] * state.f_registers[rs2]; } -pub fn fdiv_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - let a = registers[rs1]; - let b = registers[rs2]; +pub fn fdiv_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + let a = state.f_registers[rs1]; + let b = state.f_registers[rs2]; - registers[rd] = if b == 0.0 { + state.f_registers[rd] = if b == 0.0 { f32::NAN // todo: raise division by zero in csr } else { @@ -286,99 +316,81 @@ pub fn fdiv_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { } } -pub fn fsqrt_s(registers: &mut [f32; 32], rd: usize, rs1: usize) { - registers[rd] = registers[rs1].sqrt(); +pub fn fsqrt_s(state: &mut CpuState, rd: usize, rs1: usize) { + state.f_registers[rd] = state.f_registers[rs1].sqrt(); } -pub fn fsgnj_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1].abs() * registers[rs2].signum(); +pub fn fsgnj_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1].abs() * state.f_registers[rs2].signum(); } -pub fn fsgnjn_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1].abs() * -registers[rs2].signum(); +pub fn fsgnjn_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1].abs() * -state.f_registers[rs2].signum(); } -pub fn fsgnjx_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1] * registers[rs2].signum(); +pub fn fsgnjx_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1] * state.f_registers[rs2].signum(); } -pub fn fmin_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1].min(registers[rs2]); +pub fn fmin_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1].min(state.f_registers[rs2]); } -pub fn fmax_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { - registers[rd] = registers[rs1].max(registers[rs2]); +pub fn fmax_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.f_registers[rd] = state.f_registers[rs1].max(state.f_registers[rs2]); } -pub fn fcvt_s_w(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { - f_registers[rd] = registers[rs1] as i32 as f32; +pub fn fcvt_s_w(state: &mut CpuState, rd: usize, rs1: usize) { + state.f_registers[rd] = state.registers[rs1] as i32 as f32; } -pub fn fcvt_s_wu(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { - f_registers[rd] = registers[rs1] as f32; +pub fn fcvt_s_wu(state: &mut CpuState, rd: usize, rs1: usize) { + state.f_registers[rd] = state.registers[rs1] as f32; } -pub fn fcvt_w_s(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { - registers[rd] = f_registers[rs1] as i32 as u32; +pub fn fcvt_w_s(state: &mut CpuState, rd: usize, rs1: usize) { + state.registers[rd] = state.f_registers[rs1] as i32 as u32; } -pub fn fcvt_wu_s(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { - registers[rd] = f_registers[rs1] as u32; +pub fn fcvt_wu_s(state: &mut CpuState, rd: usize, rs1: usize) { + state.registers[rd] = state.f_registers[rs1] as u32; } -pub fn fmv_x_w(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { - registers[rd] = u32::from_le_bytes(f_registers[rs1].to_le_bytes()); +pub fn fmv_x_w(state: &mut CpuState, rd: usize, rs1: usize) { + state.registers[rd] = u32::from_le_bytes(state.f_registers[rs1].to_le_bytes()); } -pub fn fmv_w_x(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { - f_registers[rd] = f32::from_le_bytes(registers[rs1].to_le_bytes()); +pub fn fmv_w_x(state: &mut CpuState, rd: usize, rs1: usize) { + state.f_registers[rd] = f32::from_le_bytes(state.registers[rs1].to_le_bytes()); } -pub fn feq_s( - registers: &mut [u32; 32], - f_registers: &mut [f32; 32], - rd: usize, - rs1: usize, - rs2: usize, -) { - registers[rd] = if f_registers[rs1] == f_registers[rs2] { +pub fn feq_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = if state.f_registers[rs1] == state.f_registers[rs2] { 1 } else { 0 } } -pub fn flt_s( - registers: &mut [u32; 32], - f_registers: &mut [f32; 32], - rd: usize, - rs1: usize, - rs2: usize, -) { - registers[rd] = if f_registers[rs1] < f_registers[rs2] { +pub fn flt_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = if state.f_registers[rs1] < state.f_registers[rs2] { 1 } else { 0 } } -pub fn fle_s( - registers: &mut [u32; 32], - f_registers: &mut [f32; 32], - rd: usize, - rs1: usize, - rs2: usize, -) { - registers[rd] = if f_registers[rs1] <= f_registers[rs2] { +pub fn fle_s(state: &mut CpuState, rd: usize, rs1: usize, rs2: usize) { + state.registers[rd] = if state.f_registers[rs1] <= state.f_registers[rs2] { 1 } else { 0 } } -pub fn fclass_s(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { - let number = f_registers[rs1]; +pub fn fclass_s(state: &mut CpuState, rd: usize, rs1: usize) { + let number = state.f_registers[rs1]; let class = number.classify(); let frac_msb = (number.to_bits() >> 22) & 0x01; - registers[rd] = match class { + state.registers[rd] = match class { FpCategory::Nan => { if frac_msb == 0 { 0b1 diff --git a/src/main.rs b/src/main.rs index 9ec507b..965826e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,94 +1,38 @@ pub mod core; +pub mod mem; +pub mod state; use crate::core::*; -use elf::ElfBytes; -use elf::endian::AnyEndian; use std::collections::HashSet; use std::io; use std::io::Write; use std::process::exit; -use std::sync::{LazyLock, Mutex}; +use crate::mem::Memory; +use crate::state::CpuState; const MEMORY_SIZE: usize = 64 * 1024 * 1024; const REGISTER_NAME_WIDTH: u32 = 0b11111; -static MEMORY: LazyLock>> = - LazyLock::new(|| Mutex::new(vec![0u8; MEMORY_SIZE].into_boxed_slice())); - -struct CpuState<'a> { - memory: &'a mut Box<[u8]>, - registers: &'a mut [u32; 32], - f_registers: &'a mut [f32; 32], - pc: &'a mut u32, - reservations: &'a mut HashSet, -} +const RO_TARGET: u32 = 0x80000000; fn main() { - let path = std::path::PathBuf::from("hi"); - + let path = std::path::PathBuf::from("wkern.bin"); let f_dat = std::fs::read(path).expect("Unable to read file"); - let elf = ElfBytes::::minimal_parse(f_dat.as_slice()).expect("Unable to parse elf"); - - let (sh, stab) = elf - .section_headers_with_strtab() - .expect("Unable to get section headers"); - - let dup = f_dat.clone(); + let memory = Memory::new(MEMORY_SIZE); - // write memory - { - let mut memory = MEMORY.lock().expect("Unable to get memory"); - for i in 0..dup.len() { - memory[i] = dup[i]; - } - } - - let mut registers: [u32; 32] = [0; 32]; - let mut f_registers: [f32; 32] = [0f32; 32]; - let mut pc: u32 = 0; - let mut reservations: HashSet = HashSet::new(); - - let str_tab = stab.expect("Cannot read strtab"); - if let Some(headers) = sh { - for header in headers { - // Search for .text - if let Ok(sh_name) = str_tab.get(header.sh_name as usize) - && sh_name == ".text" - { - pc = header.sh_addr as u32; - } - } - } + let mut state = CpuState::new(memory); loop { { - let mut memory = MEMORY.lock().expect("Unable to get memory"); - handle_instruction(CpuState { - memory: &mut *memory, - registers: &mut registers, - f_registers: &mut f_registers, - pc: &mut pc, - reservations: &mut reservations, - }); + handle_instruction(&mut state); } } } -fn handle_instruction( - CpuState { - memory, - registers, - f_registers, - pc, - reservations, - }: CpuState, -) { - let word = u32::from_le_bytes([ - memory[*pc as usize], - memory[*pc as usize + 1], - memory[*pc as usize + 2], - memory[*pc as usize + 3], - ]); +fn handle_instruction(state: &mut CpuState) { + let pc = state.pc; + let instruction = state.memory.read_multiple_bytes(pc as usize, 4, 99); + let word = u32::from_le_bytes(instruction.unwrap()[0..4].try_into().unwrap()); let opcode = word & 0x7f; match opcode { 0b0110011 => { @@ -100,24 +44,24 @@ fn handle_instruction( let rd = ((word >> 7) & REGISTER_NAME_WIDTH) as usize; match (f7 << 3) | f3 { - 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), + 0 => add(state, rd, rs1, rs2), + 256 => sub(state, rd, rs1, rs2), + 4 => xor(state, rd, rs1, rs2), + 6 => or(state, rd, rs1, rs2), + 7 => and(state, rd, rs1, rs2), + 1 => sll(state, rd, rs1, rs2), + 5 => srl(state, rd, rs1, rs2), + 261 => sra(state, rd, rs1, rs2), + 2 => slt(state, rd, rs1, rs2), + 3 => sltu(state, rd, rs1, rs2), + 8 => mul(state, rd, rs1, rs2), + 9 => mulh(state, rd, rs1, rs2), + 10 => mulhsu(state, rd, rs1, rs2), + 11 => mulhu(state, rd, rs1, rs2), + 12 => div(state, rd, rs1, rs2), + 13 => divu(state, rd, rs1, rs2), + 14 => rem(state, rd, rs1, rs2), + 15 => remu(state, rd, rs1, rs2), _ => panic!("Illegal instruction: {:x}", word), } } @@ -129,28 +73,28 @@ fn handle_instruction( let rd = ((word >> 7) & 0b11111) as usize; match f3 { - 0 => addi(registers, rd, rs1, imm), - 4 => xori(registers, rd, rs1, imm), - 6 => ori(registers, rd, rs1, imm), - 7 => andi(registers, rd, rs1, imm), + 0 => addi(state, rd, rs1, imm), + 4 => xori(state, rd, rs1, imm), + 6 => ori(state, rd, rs1, imm), + 7 => andi(state, rd, rs1, imm), 1 => { if (imm >> 5) != 0 { panic!("Illegal instruction: {:x}", word); } - slli(registers, rd, rs1, imm); + slli(state, rd, rs1, imm); } 5 => { if (imm >> 5) != 0 { panic!("Illegal instruction: {:x}", word); } if (imm >> 5) & 0b1111111 == 0 { - srli(registers, rd, rs1, imm); + srli(state, rd, rs1, imm); } else { - srai(registers, rd, rs1, imm); + srai(state, rd, rs1, imm); } } - 2 => slti(registers, rd, rs1, imm), - 3 => sltiu(registers, rd, rs1, imm), + 2 => slti(state, rd, rs1, imm), + 3 => sltiu(state, rd, rs1, imm), _ => panic!("Illegal instruction: {:x}", word), } } @@ -162,11 +106,11 @@ fn handle_instruction( let rd = ((word >> 7) & 0b11111) as usize; match f3 { - 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), + 0 => lb(state, rd, rs1, imm), + 1 => lh(state, rd, rs1, imm), + 2 => lw(state, rd, rs1, imm), + 4 => lbu(state, rd, rs1, imm), + 5 => lhu(state, rd, rs1, imm), _ => panic!("Illegal instruction: {:x}", word), } } @@ -179,20 +123,20 @@ fn handle_instruction( let imm = ((((imm_high << 5) | imm_low) as i32) << 20 >> 20) as u32; - let addr = (registers[rs1] + imm) as usize; + let addr = (state.registers[rs1] + imm) as usize; match f3 { 0 => { - sb(registers, memory, rs1, rs2, imm); - release_reservations(reservations, &[addr]); + sb(state, rs1, rs2, imm); + release_reservations(state, &[addr]); } 1 => { - sh(registers, memory, rs1, rs2, imm); - release_reservations(reservations, &[addr, addr + 1]); + sh(state, rs1, rs2, imm); + release_reservations(state, &[addr, addr + 1]); } 2 => { - sw(registers, memory, rs1, rs2, imm); - release_reservations(reservations, &[addr, addr + 1, addr + 2, addr + 3]); + sw(state, rs1, rs2, imm); + release_reservations(state, &[addr, addr + 1, addr + 2, addr + 3]); } _ => panic!("Illegal instruction: {:x}", word), }; @@ -210,12 +154,12 @@ fn handle_instruction( let imm = ((imm as i32) << 19 >> 19) as u32; match f3 { - 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), + 0 => beq(state, rs1, rs2, imm), + 1 => bne(state, rs1, rs2, imm), + 4 => blt(state, rs1, rs2, imm), + 5 => bge(state, rs1, rs2, imm), + 6 => bltu(state, rs1, rs2, imm), + 7 => bgeu(state, rs1, rs2, imm), _ => panic!("Illegal instruction: {:x}", word), } return; @@ -227,7 +171,7 @@ fn handle_instruction( | (((word >> 20) & 0x1) << 11) | (((word >> 21) & 0x3FF) << 1); let imm = ((imm as i32) << 11 >> 11) as u32; - jal(registers, pc, rd as usize, imm); + jal(state, rd as usize, imm); return; } 0b1100111 => { @@ -240,36 +184,26 @@ fn handle_instruction( panic!("Illegal instruction: {:x}", word); } - jalr(registers, pc, rd as usize, rs1 as usize, imm); + jalr(state, rd as usize, rs1 as usize, imm); return; } 0b0110111 => { let imm = word >> 12; let rd = ((word >> 7) & 0b11111) as usize; - lui(registers, rd, imm); + lui(state, rd, imm); } 0b0010111 => { let imm = word >> 12; let rd = (word >> 7) & REGISTER_NAME_WIDTH; - auipc(registers, *pc, rd as usize, imm); + auipc(state, *pc, rd as usize, imm); } 0b1110011 => { // ecall eprintln!( - "TRAP! syscall {} with gp registers {:?} calling instruction {:x}", - registers[17], - ®isters[10..17], - *pc + "TRAP! syscall {} with gp state {:?}", + state.registers[17], + pc ); - if registers[17] == 0 { - // sys_write: just a debug - let buf = registers[11] as usize; - let len = registers[12] as usize; - let total_bytes = &memory[buf..buf + len]; - io::stdout().write(&total_bytes).unwrap(); - } else if registers[17] == 60 { - exit(registers[10] as i32); - } } // ecall (ebreak not implemented) 0b0101111 => { let f5 = word >> 27; @@ -284,73 +218,73 @@ fn handle_instruction( match f5 { 2 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = number; + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = number; acquire_reservations(reservations, &[addr, addr + 1, addr + 2, addr + 3]); } // lr.w 3 => { - let addr = registers[rs1] as usize; + let addr = state[rs1] as usize; if (*reservations).contains(&addr) { - memory[addr..addr + 4].copy_from_slice(®isters[rs2].to_le_bytes()); - registers[rd] = 0; + memory[addr..addr + 4].copy_from_slice(&state[rs2].to_le_bytes()); + state[rd] = 0; } else { - registers[rd] = 1; + state[rd] = 1; } } // sc.w 1 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = number; - store_word(memory, addr, registers[rs2]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = number; + store_word(addr, state[rs2]); } // amoswap.w 0 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = (number as i32 + registers[rs2] as i32) as u32; - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = (number as i32 + state[rs2] as i32) as u32; + store_word(addr, state[rd]); } // amoadd.w 12 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = number & registers[rs2]; - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = number & state[rs2]; + store_word(addr, state[rd]); } // amoand.w 8 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = number | registers[rs2]; - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = number | state[rs2]; + store_word(addr, state[rd]); } // amoor.w 4 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = number ^ registers[rs2]; - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = number ^ state[rs2]; + store_word(addr, state[rd]); } // amoxor.w 20 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = std::cmp::max(number as i32, registers[rs2] as i32) as u32; - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = std::cmp::max(number as i32, state[rs2] as i32) as u32; + store_word(addr, state[rd]); } // amomax.w 16 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = std::cmp::min(number as i32, registers[rs2] as i32) as u32; - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = std::cmp::min(number as i32, state[rs2] as i32) as u32; + store_word(addr, state[rd]); } // amomin.w 28 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = std::cmp::max(number, registers[rs2]); - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = std::cmp::max(number, state[rs2]); + store_word(addr, state[rd]); } // amomaxu.w 24 => { - let addr = registers[rs1] as usize; - let number: u32 = load_word(&memory, addr); - registers[rd] = std::cmp::min(number, registers[rs2]); - store_word(memory, addr, registers[rd]); + let addr = state[rs1] as usize; + let number: u32 = load_word(&addr); + state[rd] = std::cmp::min(number, state[rs2]); + store_word(addr, state[rd]); } // amomin.w _ => panic!("Illegal instruction: {:x}", word), @@ -363,7 +297,7 @@ fn handle_instruction( let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize; let rs3 = ((word >> 27) & REGISTER_NAME_WIDTH) as usize; - fmadd_s(f_registers, rd, rs1, rs2, rs3); + fmadd_s(state, rd, rs1, rs2, rs3); } 0b1000111 => { // todo: handle rm bit @@ -372,7 +306,7 @@ fn handle_instruction( let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize; let rs3 = ((word >> 27) & REGISTER_NAME_WIDTH) as usize; - fmsub_s(f_registers, rd, rs1, rs2, rs3); + fmsub_s(state, rd, rs1, rs2, rs3); } 0b1001011 => { // todo: handle rm bit @@ -381,7 +315,7 @@ fn handle_instruction( let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize; let rs3 = ((word >> 27) & REGISTER_NAME_WIDTH) as usize; - fnmsub_s(f_registers, rd, rs1, rs2, rs3); + fnmsub_s(state, rd, rs1, rs2, rs3); } 0b1001111 => { // todo: handle rm bit @@ -390,7 +324,7 @@ fn handle_instruction( let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize; let rs3 = ((word >> 27) & REGISTER_NAME_WIDTH) as usize; - fnmadd_s(f_registers, rd, rs1, rs2, rs3); + fnmadd_s(state, rd, rs1, rs2, rs3); } 0b1010011 => { // todo: handle rm bit @@ -401,36 +335,36 @@ fn handle_instruction( let rm = (word >> 12) & 0b111; match f5 { - 0 => fadd_s(f_registers, rd, rs1, rs2), - 1 => fsub_s(f_registers, rd, rs1, rs2), - 2 => fmul_s(f_registers, rd, rs1, rs2), - 3 => fdiv_s(f_registers, rd, rs1, rs2), - 11 => fsqrt_s(f_registers, rd, rs1), + 0 => fadd_s(state, rd, rs1, rs2), + 1 => fsub_s(state, rd, rs1, rs2), + 2 => fmul_s(state, rd, rs1, rs2), + 3 => fdiv_s(state, rd, rs1, rs2), + 11 => fsqrt_s(state, rd, rs1), 4 => match rm { - 0 => fsgnj_s(f_registers, rd, rs1, rs2), - 1 => fsgnjn_s(f_registers, rd, rs1, rs2), - 2 => fsgnjx_s(f_registers, rd, rs1, rs2), + 0 => fsgnj_s(state, rd, rs1, rs2), + 1 => fsgnjn_s(state, rd, rs1, rs2), + 2 => fsgnjx_s(state, rd, rs1, rs2), _ => panic!("Illegal instruction: {:x}", rm), }, 5 => match rm { - 0 => fmin_s(f_registers, rd, rs1, rs2), - 1 => fmax_s(f_registers, rd, rs1, rs2), + 0 => fmin_s(state, rd, rs1, rs2), + 1 => fmax_s(state, rd, rs1, rs2), _ => panic!("Illegal instruction: {:x}", rm), }, 24 => { - fcvt_wu_s(registers, f_registers, rd, rs1); + fcvt_wu_s(state, rd, rs1); } 28 => { match rm { - 0 => fmv_x_w(registers, f_registers, rd, rs1), - 1 => fclass_s(registers, f_registers, rd, rs1), + 0 => fmv_x_w(state, rd, rs1), + 1 => fclass_s(state, rd, rs1), _ => panic!("Illegal instruction: {:x}", rm), }; } 20 => match rm { - 0 => feq_s(registers, f_registers, rd, rs1, rs2), - 1 => flt_s(registers, f_registers, rd, rs1, rs2), - 2 => fle_s(registers, f_registers, rd, rs1, rs2), + 0 => feq_s(state, rd, rs1, rs2), + 1 => flt_s(state, rd, rs1, rs2), + 2 => fle_s(state, rd, rs1, rs2), _ => panic!("Illegal instruction: {:x}", rm), }, @@ -440,29 +374,21 @@ fn handle_instruction( 0b1010101 => { let rd = ((word >> 7) & REGISTER_NAME_WIDTH) as usize; let rs1 = ((word >> 15) & REGISTER_NAME_WIDTH) as usize; - fcvt_w_s(registers, f_registers, rd, rs1); + fcvt_w_s(state, rd, rs1); } _ => panic!("Illegal instruction or todo: {:x}", word), } - *pc += 4; + state.pc += 4; } -fn release_reservations(reservations: &mut HashSet, indices: &[usize]) { +fn release_reservations(state: &mut CpuState, indices: &[usize]) { for index in indices { - reservations.remove(&index); + state.reservations.remove(&index); } } -fn acquire_reservations(reservations: &mut HashSet, indices: &[usize]) { +fn acquire_reservations(state: &mut CpuState, indices: &[usize]) { for index in indices { - reservations.insert(*index); + state.reservations.insert(*index); } -} - -fn load_word(memory: &&mut Box<[u8]>, addr: usize) -> u32 { - let slice = memory.get(addr..addr + 4).unwrap(); - u32::from_le_bytes(slice.try_into().unwrap()) -} -fn store_word(memory: &mut Box<[u8]>, addr: usize, value: u32) { - memory[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); -} +} \ No newline at end of file diff --git a/src/mem.rs b/src/mem.rs new file mode 100644 index 0000000..297c54c --- /dev/null +++ b/src/mem.rs @@ -0,0 +1,105 @@ +const PAGE_SIZE: usize = 4 * 1024; +const PAGE_MASK: usize = !(PAGE_SIZE - 1); + +struct Page { + virtual_addr: usize, + real_addr: usize, + permission: usize, + allocated: usize, +} +pub struct Memory { + memory: Box<[u8]>, + pages: Vec, +} +impl Memory { + pub fn new(size: usize) -> Memory { + let mut pages: Vec = Vec::with_capacity(size / PAGE_SIZE); + for i in 0..size / PAGE_SIZE { + pages[i] = Page { + virtual_addr: usize::MAX, + real_addr: i * PAGE_SIZE, + permission: 0, + allocated: 0 + } + } + Memory { + memory: vec![0u8; size].into_boxed_slice(), + pages, + } + } + + pub fn create_page(&mut self, virtual_addr: usize, permission: usize) -> Option { + // Find first page that isn't allocated and set it to allocated + for (i, page) in self.pages.iter_mut().enumerate() { + if page.allocated == 0 { + page.virtual_addr = virtual_addr; + page.permission = permission; + page.allocated = 1; + return Some(i); + } + } + None + } + + pub fn lookup_page(&mut self, virtual_addr: usize, permission: usize) -> Option { + for (i, page) in self.pages.iter().enumerate() { + if page.virtual_addr == virtual_addr && permission >= page.permission && page.allocated == 1 { + return Some(i); + } + } + return self.create_page(virtual_addr, permission); + } + + pub fn ro_lookup(&self, virtual_addr: usize, permission: usize) -> Option { + for (i, page) in self.pages.iter().enumerate() { + if page.virtual_addr == virtual_addr && page.permission == permission && page.allocated == 1 { + return Some(i); + } + } + None + } + + pub fn write(&mut self, address: usize, permission: usize, value: u8) -> Result<(), ()> { + let page = address & PAGE_MASK; + let offset = address - page; + + if let Some(page) = self.lookup_page(address, permission) { + self.memory[self.pages[page].real_addr + offset] = value; + Ok(()) + } else { + Err(()) + } + } + + pub fn read(&self, address: usize, permission: usize) -> Result { + let page = address & PAGE_MASK; + let offset = address - page; + + if let Some(page) = self.ro_lookup(address, permission) { + Ok(self.memory[self.pages[page].real_addr + offset]) + } else { + Err(()) + } + } + + pub fn read_multiple_bytes(&self, address: usize, size: usize, permission: usize) -> Result, ()> { + let mut ret = []; + for addr in address..address+size { + if let Ok(byte) = self.read(addr, permission) { + ret[addr - address] = byte; + } else { + return Err(()); + } + } + Ok(Box::new(ret)) + } + + pub fn write_multiple_bytes(&mut self, address: usize, bytes: &[u8], permission: usize) -> Result<(), ()> { + for addr in address..address + bytes.len() { + if let Err(_) = self.write(addr, permission, bytes[addr - address]) { + return Err(()); + } + } + Ok(()) + } +} \ No newline at end of file diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..dcb1959 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,22 @@ +use std::collections::HashSet; +use crate::mem::Memory; + +pub struct CpuState { + pub memory: Memory, + pub registers: [u32; 32], + pub f_registers: [f32; 32], + pub pc: u32, + pub reservations: HashSet +} + +impl CpuState { + pub fn new(memory: Memory) -> CpuState { + CpuState { + memory, + registers: [0u32; 32], + f_registers: [0f32; 32], + pc: 0, + reservations: HashSet::new() + } + } +} \ No newline at end of file -- cgit v1.2.3