summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Lee <me@nwlee.tech>2026-06-10 22:10:59 -0500
committerNathan Lee <me@nwlee.tech>2026-06-10 22:10:59 -0500
commita37a07533fa9b8bd8962ca3c1aea082ae2548651 (patch)
treec2ee061f6047eeda966ef9a4f3a7c26cf7da2061
parent615e98a616c851fb6230184029aa4297417cdf6e (diff)
move memory and cpu state into its own files
-rw-r--r--src/core.rs394
-rw-r--r--src/main.rs344
-rw-r--r--src/mem.rs105
-rw-r--r--src/state.rs22
4 files changed, 465 insertions, 400 deletions
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(&registers[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<Mutex<Box<[u8]>>> =
- 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<usize>,
-}
+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::<AnyEndian>::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<usize> = 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],
- &registers[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(&registers[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<usize>, 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<usize>, 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<Page>,
+}
+impl Memory {
+ pub fn new(size: usize) -> Memory {
+ let mut pages: Vec<Page> = 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<usize> {
+ // 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<usize> {
+ 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<usize> {
+ 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<u8, ()> {
+ 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<Box<[u8]>, ()> {
+ 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<usize>
+}
+
+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