summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorNathan Lee <me@nwlee.tech>2026-06-05 17:28:06 -0500
committerNathan Lee <me@nwlee.tech>2026-06-05 17:28:06 -0500
commit4aaac36bd8331a5f61c7dad1911d0d37561e0e2f (patch)
tree58ffc5faf7f60bc4e76fe4a8a3a8208a268fa63f /src/main.rs
parentf92fa7c0aaec9da67fec2854ad484568df0307c9 (diff)
add A extension
(todo: make atomic semantics mean something)
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs129
1 files changed, 113 insertions, 16 deletions
diff --git a/src/main.rs b/src/main.rs
index df644a4..36c1c8c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,13 +6,15 @@ use std::process::exit;
use std::sync::{LazyLock, Mutex};
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],
- pc: &'a mut u32
+ registers: &'a mut [u32; 32],
+ pc: &'a mut u32,
+ reservations: &'a mut Vec<usize>,
}
fn main() {
@@ -38,6 +40,7 @@ fn main() {
let mut registers: [u32; 32] = [0; 32];
let mut pc: u32 = 0;
+ let mut reservations: Vec<usize> = vec![];
let str_tab = stab.expect("Cannot read strtab");
if let Some(headers) = sh {
@@ -57,13 +60,14 @@ fn main() {
handle_instruction(CpuState {
memory: &mut *memory,
registers: &mut registers,
- pc: &mut pc
+ pc: &mut pc,
+ reservations: &mut reservations,
});
}
}
}
-fn handle_instruction(CpuState { memory, registers, pc }: CpuState) {
+fn handle_instruction(CpuState { memory, registers, pc, reservations }: CpuState) {
let word = u32::from_le_bytes([
memory[*pc as usize],
memory[*pc as usize + 1],
@@ -76,9 +80,9 @@ fn handle_instruction(CpuState { memory, registers, pc }: CpuState) {
let f7 = word >> 25;
let f3 = (word >> 12) & 0b111;
- let rs2 = ((word >> 20) & 0b11111) as usize;
- let rs1 = ((word >> 15) & 0b11111) as usize;
- let rd = ((word >> 7) & 0b11111) as usize;
+ let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize;
+ let rs1 = ((word >> 15) & REGISTER_NAME_WIDTH) as usize;
+ let rd = ((word >> 7) & REGISTER_NAME_WIDTH) as usize;
match (f7 << 3) | f3 {
0 => registers[rd] = registers[rs1].wrapping_add(registers[rs2]), // add
@@ -232,8 +236,8 @@ fn handle_instruction(CpuState { memory, registers, pc }: CpuState) {
let imm_low = (word >> 7) & 0b11111;
let imm_high = (word >> 25) & 0b1111111;
let f3 = (word >> 12) & 0b111;
- let rs1 = ((word >> 15) & 0b11111) as usize;
- let rs2 = ((word >> 20) & 0b11111) as usize;
+ let rs1 = ((word >> 15) & REGISTER_NAME_WIDTH) as usize;
+ let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize;
let imm = ((((imm_high << 5) | imm_low) as i32) << 20 >> 20) as u32;
@@ -254,8 +258,8 @@ fn handle_instruction(CpuState { memory, registers, pc }: CpuState) {
}
0b1100011 => {
let f3 = (word >> 12) & 0b111;
- let rs1 = ((word >> 15) & 0b11111) as usize;
- let rs2 = ((word >> 20) & 0b11111) as usize;
+ let rs1 = ((word >> 15) & REGISTER_NAME_WIDTH) as usize;
+ let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize;
let imm = (((word >> 31) & 0x1) << 12)
| (((word >> 7) & 0x1) << 11)
@@ -305,18 +309,18 @@ fn handle_instruction(CpuState { memory, registers, pc }: CpuState) {
}
}
0b1101111 => {
- let rd = (word >> 7) & 0b11111;
+ let rd = (word >> 7) & REGISTER_NAME_WIDTH;
let imm = word >> 12;
registers[rd as usize] = *pc + 4;
*pc += imm;
} // jal
0b1100111 => {
- let rs1 = (word >> 15) & 0b11111;
- let rd = (word >> 7) & 0b11111;
+ let rs1 = (word >> 15) & REGISTER_NAME_WIDTH;
+ let rd = (word >> 7) & REGISTER_NAME_WIDTH;
let imm = word >> 20;
let sentinel = (word >> 12) & 0b111;
- if (sentinel != 0) {
+ if sentinel != 0 {
panic!("Illegal instruction: {:x}", word);
}
@@ -330,7 +334,7 @@ fn handle_instruction(CpuState { memory, registers, pc }: CpuState) {
}
0b0010111 => {
let imm = word >> 12;
- let rd = (word >> 7) & 0b11111;
+ let rd = (word >> 7) & REGISTER_NAME_WIDTH;
registers[rd as usize] = *pc + (imm << 12); // auipc
}
0b1110011 => {
@@ -351,8 +355,101 @@ fn handle_instruction(CpuState { memory, registers, pc }: CpuState) {
exit(registers[10] as i32);
}
} // ecall (ebreak not implemented)
+ 0b0101111 => {
+ let f5 = word >> 27;
+ let f3 = (word >> 12) & 0b111;
+ let rd = ((word >> 7) & REGISTER_NAME_WIDTH) as usize;
+ let rs1 = ((word >> 15) & REGISTER_NAME_WIDTH) as usize;
+ let rs2 = ((word >> 20) & REGISTER_NAME_WIDTH) as usize;
+
+ if f3 != 2 {
+ panic!("Illegal instruction: {:x}", word);
+ }
+
+ match f5 {
+ 2 => {
+ let addr = registers[rs1] as usize;
+ let number: u32 = load_word(&memory, addr);
+ registers[rd] = number;
+ (*reservations).push(addr);
+ } // lr.w
+ 3 => {
+ let addr = registers[rs1] as usize;
+ if (*reservations).contains(&addr) {
+ memory[addr..addr + 4].copy_from_slice(&registers[rs2].to_le_bytes());
+ registers[rd] = 0;
+ } else {
+ registers[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]);
+ } // 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]);
+ } // 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]);
+ } // 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]);
+ } // 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]);
+ } // 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]);
+ } // 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]);
+ } // 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]);
+ } // 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]);
+ } // amomin.w
+
+ _ => panic!("Illegal instruction: {:x}", word),
+ }
+ }
_ => panic!("Illegal instruction or todo: {:x}", word),
}
*pc += 4;
}
+
+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