diff --git a/run-riscv-tests.sh b/run-riscv-tests.sh new file mode 100755 index 0000000..c39c59d --- /dev/null +++ b/run-riscv-tests.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +for f in $(cat torun.txt); do + result=$(cargo run $f 2>&1 | tail -n 1 | awk '{print $NF}') + if [[ $result != 0 ]]; then + testnum=$(( result >> 1 )) + echo $f: test $testnum failed + exit 1 + fi +done + +echo all tests passed diff --git a/src/core.rs b/src/core.rs index 07df2f5..64a6a25 100644 --- a/src/core.rs +++ b/src/core.rs @@ -164,7 +164,7 @@ impl Core { let instr = Instruction(instr); if let Err(e) = find_and_exec(instr, self) { - eprintln!("instr: {:08x}", instr.0); + dbg!(instr); return Err(e); } @@ -174,6 +174,7 @@ impl Core { fn throw_exception(&mut self, exception: Exception) { eprintln!("Exception: {exception:?}"); dbg!(self.pc, self.x_regs); + dbg!(self.x_regs[10]); } pub fn reset(&mut self, pc: u64) { diff --git a/src/decode.rs b/src/decode.rs index 616f7f7..7f58516 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -6,9 +6,15 @@ const MASK_REGISTER: u32 = 0x1f; -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] pub struct Instruction(pub u32); +impl std::fmt::Debug for Instruction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{:08x}", self.0)) + } +} + #[allow(dead_code)] impl Instruction { #[inline] diff --git a/src/instructions.rs b/src/instructions.rs index 90f2e28..2a224b3 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -131,6 +131,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E // FENCE is just implemented as a SeqCst fence always here // I dont yet care about the potential performance issue this may bring std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst); + core.advance_pc(); Ok(()) } _ => illegal(instr), @@ -142,7 +143,15 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E Err(ExceptionType::EnvironmentCallFromMMode.with_no_value()) } (0b000, 0b000000000001, 0, 0) => Err(ExceptionType::Breakpoint.with_no_value()), - _ => illegal(instr), + _ => { + // Temporarily allowing unrecognized instructions here to be able to run + // the official ISA tests, which perform CSR operations but work just fine + // without them + eprintln!("Unrecognized instruction within SYSTEM opcode"); + dbg!(instr); + core.advance_pc(); + Ok(()) + } }, _ => illegal(instr), } diff --git a/src/instructions/rvi.rs b/src/instructions/rvi.rs index 424e9e4..78267ea 100644 --- a/src/instructions/rvi.rs +++ b/src/instructions/rvi.rs @@ -32,7 +32,7 @@ instr_op!(srl, srli, |x, shamt| x >> (shamt & 0b111111)); instr_op!( srlw, srliw, - |x, shamt| (x >> (shamt & 0b11111)) as i32 as i64 as u64 + |x, shamt| (x as u32 >> (shamt & 0b11111)) as i32 as i64 as u64 ); instr_op!(sra, srai, |x, shamt| (x as i64 >> (shamt & 0b111111)) as u64); @@ -64,8 +64,9 @@ pub fn jal(core: &mut Core, instr: Instruction) -> Result<(), Exception> { } pub fn jalr(core: &mut Core, instr: Instruction) -> Result<(), Exception> { + let target = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()) & !1; core.reg_write(instr.rd(), core.pc.wrapping_add(4)); - core.pc = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()); + core.pc = target; Ok(()) } diff --git a/src/mem.rs b/src/mem.rs index e3cbe82..a3b087c 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -263,8 +263,8 @@ impl Ram { if !addr.is_multiple_of(8) { let high_word_addr = addr.wrapping_add(4); - let low_word = self.read_byte(addr)?; - let high_word = self.read_byte(high_word_addr)?; + let low_word = self.read_word(addr)?; + let high_word = self.read_word(high_word_addr)?; return Ok((low_word as u64) | (high_word as u64) << 32); }