From 4aaac36bd8331a5f61c7dad1911d0d37561e0e2f Mon Sep 17 00:00:00 2001 From: Nathan Lee Date: Fri, 5 Jun 2026 17:28:06 -0500 Subject: add A extension (todo: make atomic semantics mean something) --- src/main.rs | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 16 deletions(-) (limited to 'src/main.rs') 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>> = 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, } fn main() { @@ -38,6 +40,7 @@ fn main() { let mut registers: [u32; 32] = [0; 32]; let mut pc: u32 = 0; + let mut reservations: Vec = 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(®isters[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 -- cgit v1.2.3