diff --git a/Cargo.lock b/Cargo.lock index 345bd11..0c37f38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,37 +29,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "errno" version = "0.3.10" @@ -164,26 +133,6 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "rustix" version = "1.0.1" @@ -222,7 +171,6 @@ name = "rvdc" version = "0.1.1" dependencies = [ "object", - "rayon", "tempfile", ] diff --git a/rvdc/Cargo.toml b/rvdc/Cargo.toml index 420b0c6..de87c41 100644 --- a/rvdc/Cargo.toml +++ b/rvdc/Cargo.toml @@ -15,5 +15,4 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(slow_tests)'] } [dev-dependencies] object = "0.36.7" -rayon = "1.10.0" tempfile = "3.19.1" diff --git a/rvdc/README.md b/rvdc/README.md index 5bad4cd..8494525 100644 --- a/rvdc/README.md +++ b/rvdc/README.md @@ -38,7 +38,7 @@ More extensions may be implemented in the future. let x = 0x1101_u32; let expected = rvdc::Inst::Addi { imm: rvdc::Imm::new_i32(-0x20), dest: rvdc::Reg::SP, src1: rvdc::Reg::SP }; -let (inst, is_compressed) = rvdc::Inst::decode(x, rvdc::Xlen::Rv32).unwrap(); +let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap(); assert_eq!(inst, expected); assert_eq!(is_compressed, rvdc::IsCompressed::Yes); assert_eq!(format!("{inst}"), "addi sp, sp, -32") @@ -49,7 +49,7 @@ assert_eq!(format!("{inst}"), "addi sp, sp, -32") let x = 0x0000a317; let expected = rvdc::Inst::Auipc { uimm: rvdc::Imm::new_u32(0xa << 12), dest: rvdc::Reg::T1 }; -let (inst, is_compressed) = rvdc::Inst::decode(x, rvdc::Xlen::Rv32).unwrap(); +let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap(); assert_eq!(inst, expected); assert_eq!(is_compressed, rvdc::IsCompressed::No); assert_eq!(format!("{inst}"), "auipc t1, 10") diff --git a/rvdc/src/lib.rs b/rvdc/src/lib.rs index ff6e41f..3eec47c 100644 --- a/rvdc/src/lib.rs +++ b/rvdc/src/lib.rs @@ -6,7 +6,7 @@ use core::fmt::{self, Debug, Display}; use core::ops::RangeInclusive; /// The register size of the ISA, RV32 or RV64. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Xlen { /// 32 bit Rv32, @@ -274,16 +274,10 @@ pub enum Inst { /// Add Add { dest: Reg, src1: Reg, src2: Reg }, - /// Add 32-bit (**RV64 only**) - AddW { dest: Reg, src1: Reg, src2: Reg }, /// Subtract Sub { dest: Reg, src1: Reg, src2: Reg }, - /// Subtract 32-bit (**RV64 only**) - SubW { dest: Reg, src1: Reg, src2: Reg }, /// Shift Left Logical Sll { dest: Reg, src1: Reg, src2: Reg }, - /// Shift Left Logical 32-bit (**RV64 only**) - SllW { dest: Reg, src1: Reg, src2: Reg }, /// Set Less Than (signed) Slt { dest: Reg, src1: Reg, src2: Reg }, /// Set Less Than Unsigned @@ -292,12 +286,8 @@ pub enum Inst { Xor { dest: Reg, src1: Reg, src2: Reg }, /// Shift Right Logical (unsigned) Srl { dest: Reg, src1: Reg, src2: Reg }, - /// Shift Right Logical (unsigned) 32-bit (**RV64 only**) - SrlW { dest: Reg, src1: Reg, src2: Reg }, /// Shift Right Arithmetic (unsigned) Sra { dest: Reg, src1: Reg, src2: Reg }, - /// Shift Right Arithmetic (unsigned) 32-bit (**RV64 only**) - SraW { dest: Reg, src1: Reg, src2: Reg }, /// OR Or { dest: Reg, src1: Reg, src2: Reg }, /// AND @@ -313,8 +303,6 @@ pub enum Inst { // ------------- M extension ------------- /// Multiply Mul { dest: Reg, src1: Reg, src2: Reg }, - /// Multiply 32-bit (**RV64 only**) - MulW { dest: Reg, src1: Reg, src2: Reg }, /// Mul Upper Half Signed-Signed Mulh { dest: Reg, src1: Reg, src2: Reg }, /// Mul Upper Half Signed-Unsigned @@ -323,20 +311,12 @@ pub enum Inst { Mulhu { dest: Reg, src1: Reg, src2: Reg }, /// Divide (signed) Div { dest: Reg, src1: Reg, src2: Reg }, - /// Divide (signed) 32-bit (**RV64 only**) - DivW { dest: Reg, src1: Reg, src2: Reg }, /// Divide Unsigned Divu { dest: Reg, src1: Reg, src2: Reg }, - /// Divide Unsigned 32-bit (**RV64 only**) - DivuW { dest: Reg, src1: Reg, src2: Reg }, /// Remainder (signed) Rem { dest: Reg, src1: Reg, src2: Reg }, - /// Remainder (signed) 32-bit (**RV64 only**) - RemW { dest: Reg, src1: Reg, src2: Reg }, /// Remainder Unsigned Remu { dest: Reg, src1: Reg, src2: Reg }, - /// Remainder Unsigned 32-bit (**RV64 only**) - RemuW { dest: Reg, src1: Reg, src2: Reg }, // ------------- A extension ------------- /// Load-Reserved Word @@ -565,7 +545,7 @@ impl Display for Inst { if imm.as_u32() == 0 { write!(f, "sext.w {dest}, {src1}") } else { - write!(f, "addiw {dest}, {src1}, {}", imm.as_i32()) + write!(f, "addi.w {dest}, {src1}, {}", imm.as_i32()) } } Inst::Slti { @@ -626,20 +606,13 @@ impl Display for Inst { Inst::Add { dest, src1, src2 } => { write!(f, "add {dest}, {src1}, {src2}") } - Inst::AddW { dest, src1, src2 } => { - write!(f, "addw {dest}, {src1}, {src2}") - } Inst::Sub { dest, src1, src2 } => write!(f, "sub {dest}, {src1}, {src2}"), - Inst::SubW { dest, src1, src2 } => write!(f, "subw {dest}, {src1}, {src2}"), Inst::Sll { dest, src1, src2 } => write!(f, "sll {dest}, {src1}, {src2}"), - Inst::SllW { dest, src1, src2 } => write!(f, "sllw {dest}, {src1}, {src2}"), Inst::Slt { dest, src1, src2 } => write!(f, "slt {dest}, {src1}, {src2}"), Inst::Sltu { dest, src1, src2 } => write!(f, "sltu {dest}, {src1}, {src2}"), Inst::Xor { dest, src1, src2 } => write!(f, "xor {dest}, {src1}, {src2}"), Inst::Srl { dest, src1, src2 } => write!(f, "srl {dest}, {src1}, {src2}"), - Inst::SrlW { dest, src1, src2 } => write!(f, "srlw {dest}, {src1}, {src2}"), Inst::Sra { dest, src1, src2 } => write!(f, "sra {dest}, {src1}, {src2}"), - Inst::SraW { dest, src1, src2 } => write!(f, "sraw {dest}, {src1}, {src2}"), Inst::Or { dest, src1, src2 } => write!(f, "or {dest}, {src1}, {src2}"), Inst::And { dest, src1, src2 } => write!(f, "and {dest}, {src1}, {src2}"), Inst::Fence { fence } => match fence.fm { @@ -652,18 +625,13 @@ impl Display for Inst { Inst::Ecall => write!(f, "ecall"), Inst::Ebreak => write!(f, "ebreak"), Inst::Mul { dest, src1, src2 } => write!(f, "mul {dest}, {src1}, {src2}"), - Inst::MulW { dest, src1, src2 } => write!(f, "mulw {dest}, {src1}, {src2}"), Inst::Mulh { dest, src1, src2 } => write!(f, "mulh {dest}, {src1}, {src2}"), Inst::Mulhsu { dest, src1, src2 } => write!(f, "mulhsu {dest}, {src1}, {src2}"), Inst::Mulhu { dest, src1, src2 } => write!(f, "mulhu {dest}, {src1}, {src2}"), Inst::Div { dest, src1, src2 } => write!(f, "div {dest}, {src1}, {src2}"), - Inst::DivW { dest, src1, src2 } => write!(f, "divw {dest}, {src1}, {src2}"), Inst::Divu { dest, src1, src2 } => write!(f, "divu {dest}, {src1}, {src2}"), - Inst::DivuW { dest, src1, src2 } => write!(f, "divuw {dest}, {src1}, {src2}"), Inst::Rem { dest, src1, src2 } => write!(f, "rem {dest}, {src1}, {src2}"), - Inst::RemW { dest, src1, src2 } => write!(f, "remw {dest}, {src1}, {src2}"), Inst::Remu { dest, src1, src2 } => write!(f, "remu {dest}, {src1}, {src2}"), - Inst::RemuW { dest, src1, src2 } => write!(f, "remuw {dest}, {src1}, {src2}"), Inst::LrW { order, dest, addr } => write!(f, "lr.w{order} {dest}, ({addr})",), Inst::ScW { order, @@ -769,6 +737,14 @@ impl InstCode { let end_span = 32 - (range.end() + 1); (self.0 << (end_span)) >> (end_span + range.start()) } + fn immediate_u(self, mappings: &[(RangeInclusive, u32)]) -> Imm { + let mut imm = 0; + for (from, to) in mappings { + let value = self.extract(from.clone()); + imm |= value << to; + } + Imm::new_u32(imm) + } fn immediate_s(self, mappings: &[(RangeInclusive, u32)]) -> Imm { let mut imm = 0; let mut size = 0; @@ -799,10 +775,6 @@ impl InstCode { fn rs2_imm(self) -> u32 { self.extract(20..=24) } - // shifts on RV64 have one extra bit - fn rs2_imm_plus(self) -> u32 { - self.extract(20..=25) - } fn rd(self) -> Reg { Reg(self.extract(7..=11) as u8) } @@ -816,8 +788,7 @@ impl InstCode { self.immediate_s(&[(31..=31, 12), (7..=7, 11), (25..=30, 5), (8..=11, 1)]) } fn imm_u(self) -> Imm { - // Don't be fooled by the "u", LUI/AUIPC immediates are sign-extended on RV64. - self.immediate_s(&[(12..=31, 12)]) + self.immediate_u(&[(12..=31, 12)]) } fn imm_j(self) -> Imm { self.immediate_s(&[(31..=31, 20), (21..=30, 1), (20..=20, 11), (12..=19, 12)]) @@ -957,10 +928,10 @@ impl Inst { /// let x = 0x1101_u16; /// let expected = rvdc::Inst::Addi { imm: rvdc::Imm::new_i32(-0x20), dest: rvdc::Reg::SP, src1: rvdc::Reg::SP }; /// - /// let inst = rvdc::Inst::decode_compressed(x, rvdc::Xlen::Rv32).unwrap(); + /// let inst = rvdc::Inst::decode_compressed(x).unwrap(); /// assert_eq!(inst, expected); /// ``` - pub fn decode_compressed(code: u16, _xlen: Xlen) -> Result { + pub fn decode_compressed(code: u16, xlen: Xlen) -> Result { let code = InstCodeC(code); if code.0 == 0 { return Err(decode_error(code, "null instruction")); @@ -1125,7 +1096,7 @@ impl Inst { _ => { let uimm = code.immediate_s(&[(2..=6, 12), (12..=12, 17)]); if uimm.as_u32() == 0 { - return Err(decode_error(code, "C.LUI zero immediate")); + return Err(decode_error(code, "C.LUI imm")); } Inst::Lui { uimm, @@ -1381,13 +1352,7 @@ impl Inst { src1: code.rs1(), }, 0b001 => { - // For RV32, bit 25 must be zero as well. - let left_zeroes = code.funct7() - >> match xlen { - Xlen::Rv32 => 0, - Xlen::Rv64 => 1, - }; - if left_zeroes != 0 { + if code.funct7() != 0 { return Err(decode_error(code, "slli shift overflow")); } Inst::Slli { @@ -1396,42 +1361,24 @@ impl Inst { src1: code.rs1(), } } - 0b101 => match xlen { - Xlen::Rv32 => match code.funct7() { - 0b0000000 => Inst::Srli { - imm: Imm::new_u32(code.rs2_imm()), - dest: code.rd(), - src1: code.rs1(), - }, - 0b0100000 => Inst::Srai { - imm: Imm::new_u32(code.rs2_imm()), - dest: code.rd(), - src1: code.rs1(), - }, - _ => return Err(decode_error(code, "srli shift overflow")), + 0b101 => match code.funct7() { + 0b0000000 => Inst::Srli { + imm: Imm::new_u32(code.rs2_imm()), + dest: code.rd(), + src1: code.rs1(), }, - Xlen::Rv64 => { - let upper = code.funct7() >> 1; - match upper { - 0b010000 => Inst::Srai { - imm: Imm::new_u32(code.rs2_imm_plus()), - dest: code.rd(), - src1: code.rs1(), - }, - 0b000000 => Inst::Srli { - imm: Imm::new_u32(code.rs2_imm_plus()), - dest: code.rd(), - src1: code.rs1(), - }, - _ => return Err(decode_error(code, "srai/srli upper bits")), - } - } + 0b0100000 => Inst::Srai { + imm: Imm::new_u32(code.rs2_imm()), + dest: code.rd(), + src1: code.rs1(), + }, + _ => return Err(decode_error(code, "OP-IMM funct7")), }, _ => return Err(decode_error(code, "OP-IMM funct3")), }, // OP-IMM-32 0b0011011 => { - if xlen.is_32() { + if !xlen.is_64() { return Err(decode_error(code, "OP-IMM-32 only on RV64")); } @@ -1496,28 +1443,6 @@ impl Inst { _ => return Err(decode_error(code, "OP funct3/funct7")), } } - // OP-32 - 0b0111011 => { - if xlen.is_32() { - return Err(decode_error(code, "OP-IMM-32 only on RV64")); - } - - let (dest, src1, src2) = (code.rd(), code.rs1(), code.rs2()); - match (code.funct3(), code.funct7()) { - (0b000, 0b0000000) => Inst::AddW { dest, src1, src2 }, - (0b000, 0b0100000) => Inst::SubW { dest, src1, src2 }, - (0b001, 0b0000000) => Inst::SllW { dest, src1, src2 }, - (0b101, 0b0000000) => Inst::SrlW { dest, src1, src2 }, - (0b101, 0b0100000) => Inst::SraW { dest, src1, src2 }, - - (0b000, 0b0000001) => Inst::MulW { dest, src1, src2 }, - (0b100, 0b0000001) => Inst::DivW { dest, src1, src2 }, - (0b101, 0b0000001) => Inst::DivuW { dest, src1, src2 }, - (0b110, 0b0000001) => Inst::RemW { dest, src1, src2 }, - (0b111, 0b0000001) => Inst::RemuW { dest, src1, src2 }, - _ => return Err(decode_error(code, "OP-32 funct3/funct7")), - } - } // MISC-MEM 0b0001111 => { let fm = code.extract(28..=31); @@ -1632,8 +1557,6 @@ impl Inst { #[cfg(test)] mod tests { extern crate std; - use core::sync::atomic::AtomicU32; - use core::sync::atomic::Ordering; use std::prelude::rust_2024::*; use std::fmt::Write as _; @@ -1641,8 +1564,6 @@ mod tests { use object::Object; use object::ObjectSection; - use rayon::iter::IntoParallelRefIterator; - use rayon::iter::ParallelIterator; use crate::Fence; use crate::FenceSet; @@ -1653,17 +1574,7 @@ mod tests { #[test] #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")] - fn exhaustive_decode_no_panic_32() { - exhaustive_decode_no_panic(Xlen::Rv32); - } - - #[test] - #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")] - fn exhaustive_decode_no_panic_64() { - exhaustive_decode_no_panic(Xlen::Rv64); - } - - fn exhaustive_decode_no_panic(xlen: Xlen) { + fn exhaustive_decode_no_panic() { for i in 0..u32::MAX { if (i % (2 << 25)) == 0 { let percent = i as f32 / (u32::MAX as f32); @@ -1671,18 +1582,25 @@ mod tests { std::print!("\r{}{}", "#".repeat(done), "-".repeat(100 - done)); std::io::stdout().flush().unwrap(); } - let _ = Inst::decode(i, xlen); + let _ = Inst::decode(i, Xlen::Rv32); } - let _ = Inst::decode(u32::MAX, xlen); + let _ = Inst::decode(u32::MAX, Xlen::Rv32); + + for i in 0..u32::MAX { + if (i % (2 << 25)) == 0 { + let percent = i as f32 / (u32::MAX as f32); + let done = (100.0 * percent) as usize; + std::print!("\r{}{}", "#".repeat(done), "-".repeat(100 - done)); + std::io::stdout().flush().unwrap(); + } + let _ = Inst::decode(i, Xlen::Rv64); + } + let _ = Inst::decode(u32::MAX, Xlen::Rv64); } #[test] fn size_of_instruction() { - assert!( - size_of::() <= 16, - "size of instruction is too large: {}", - size_of::() - ); + assert!(size_of::() <= 12); } const TEST_SECTION_NAME: &str = ".text.rvdctest"; @@ -1781,14 +1699,14 @@ mod tests { const CHUNKS: u32 = 128; const CHUNK_SIZE: u32 = u32::MAX / CHUNKS; - let chunks = ((SKIP_CHUNKS * CHUNK_SIZE)..u32::MAX) + for (chunk_idx, start) in ((SKIP_CHUNKS * CHUNK_SIZE)..u32::MAX) .step_by(CHUNK_SIZE as usize) - .collect::>(); + .enumerate() + { + let chunk_idx = chunk_idx + SKIP_CHUNKS as usize; - let start_time = std::time::Instant::now(); - let completed = AtomicU32::new(0); + let start_time = std::time::Instant::now(); - chunks.par_iter().for_each(|&start| { let insts = (start..=start.saturating_add(CHUNK_SIZE)) .filter_map(|code| Some((code, Inst::decode_normal(code, Xlen::Rv32).ok()?))) .filter(|(_, inst)| is_inst_supposed_to_roundtrip(inst)) @@ -1807,26 +1725,23 @@ mod tests { assert_eq!( insts[i].0, result_code, "failed to rountrip!\n\ - instruction `{:0>32b}` failed to rountrip\n\ - resulted in `{:0>32b}` instead.\n\ - disassembly of original instruction: `{}`", + instruction `{:0>32b}` failed to rountrip\n\ + resulted in `{:0>32b}` instead.\n\ + disassembly of original instruction: `{}`", insts[i].0, result_code, insts[i].1 ); } - let already_completed = completed.fetch_add(1, Ordering::Relaxed); - let already_elapsed = start_time.elapsed(); - - let remaining_chunks = CHUNKS.saturating_sub(already_completed); - let remaining = - already_elapsed / std::cmp::max(already_completed, 1) * remaining_chunks; + let elapsed = start_time.elapsed(); + let chunk_number = chunk_idx + 1; + let remaining = elapsed * (CHUNKS.saturating_sub(chunk_number as u32)); writeln!( std::io::stdout(), - "Completed chunk {already_completed}/{CHUNKS} (estimated {remaining:?} remaining)", + "Completed chunk {chunk_number}/{CHUNKS} (estimated {remaining:?} remaining)", ) .unwrap(); - }); + } } #[test] diff --git a/src/emu.rs b/src/emu.rs index 06a1eb9..2881412 100644 --- a/src/emu.rs +++ b/src/emu.rs @@ -386,33 +386,8 @@ impl Emulator { Inst::Srli { imm, dest, src1 } => self[dest] = self[src1].unsigned_shr(imm.as_u32()), Inst::Srai { imm, dest, src1 } => self[dest] = self[src1].signed_shr(imm.as_u32()), Inst::Add { dest, src1, src2 } => self[dest] = self[src1].add(self[src2]), - Inst::AddW { dest, src1, src2 } => { - self[dest] = XLEN::switch2( - self[src1], - self[src2], - |_, _| unreachable!(), - |a, b| (a as u32).add(b as u32) as i32 as i64 as u64, - ); - } Inst::Sub { dest, src1, src2 } => self[dest] = self[src1].sub(self[src2]), - Inst::SubW { dest, src1, src2 } => { - self[dest] = XLEN::switch2( - self[src1], - self[src2], - |_, _| unreachable!(), - |a, b| (a as u32).sub(b as u32) as i32 as i64 as u64, - ); - } - Inst::Sll { dest, src1, src2 } => { - self[dest] = self[src1].shl(self[src2].truncate32()); - } - Inst::SllW { dest, src1, src2 } => { - self[dest] = XLEN::switch( - self[src1], - |_| unreachable!(), - |a| (a as u32).shl(self[src2].truncate32()) as i32 as i64 as u64, - ); - } + Inst::Sll { dest, src1, src2 } => self[dest] = self[src1].shl(self[src2].truncate32()), Inst::Slt { dest, src1, src2 } => { self[dest] = XLEN::from_bool(self[src1].signed_lt(self[src2])); } @@ -423,23 +398,9 @@ impl Emulator { Inst::Srl { dest, src1, src2 } => { self[dest] = self[src1].unsigned_shr(self[src2].truncate32()) } - Inst::SrlW { dest, src1, src2 } => { - self[dest] = XLEN::switch( - self[src1], - |_| unreachable!(), - |a| (a as u32).unsigned_shr(self[src2].truncate32()) as i32 as i64 as u64, - ); - } Inst::Sra { dest, src1, src2 } => { self[dest] = self[src1].signed_shr(self[src2].truncate32()) } - Inst::SraW { dest, src1, src2 } => { - self[dest] = XLEN::switch( - self[src1], - |_| unreachable!(), - |a| (a as u32).unsigned_shr(self[src2].truncate32()) as i32 as i64 as u64, - ); - } Inst::Or { dest, src1, src2 } => self[dest] = self[src1].or(self[src2]), Inst::And { dest, src1, src2 } => self[dest] = self[src1].and(self[src2]), Inst::Fence { fence: _ } => { /* dont care */ } @@ -541,40 +502,7 @@ impl Emulator { } self.reservation_set = None; } - Inst::AddiW { imm, dest, src1 } => { - self[dest] = XLEN::switch( - self[src1], - |_| unreachable!(), - |src| ((src as u32).wrapping_add(imm.as_u32())) as i32 as i64 as u64, - ); - } - Inst::SlliW { imm, dest, src1 } => { - self[dest] = XLEN::switch( - self[src1], - |_| unreachable!(), - |src| ((src as u32).shl(imm.as_u32())) as u64, - ); - } - Inst::SrliW { imm, dest, src1 } => { - self[dest] = XLEN::switch( - self[src1], - |_| unreachable!(), - |src| ((src as u32).unsigned_shr(imm.as_u32())) as u64, - ); - } - Inst::SraiW { imm, dest, src1 } => { - self[dest] = XLEN::switch( - self[src1], - |_| unreachable!(), - |src| ((src as u32).signed_shr(imm.as_u32())) as u64, - ); - } - Inst::MulW { dest, src1, src2 } => todo!(), - Inst::DivW { dest, src1, src2 } => todo!(), - Inst::DivuW { dest, src1, src2 } => todo!(), - Inst::RemW { dest, src1, src2 } => todo!(), - Inst::RemuW { dest, src1, src2 } => todo!(), - _ => todo!(), + _ => return Err(Status::UnsupportedInst(inst)), } if !jumped { @@ -748,7 +676,7 @@ impl Emulator { } } -pub trait XLen: Copy + PartialEq + Eq + Debug { +pub trait XLen: Copy + PartialEq + Eq { type Signed; type NextUnsigned; type NextSigned; @@ -759,15 +687,7 @@ pub trait XLen: Copy + PartialEq + Eq + Debug { const SIGNED_MIN: Self; const MAX: Self; - const IS_64: bool = matches!(Self::XLEN, rvdc::Xlen::Rv64); - - fn switch(self, on_32: impl FnOnce(u32) -> u32, on_64: impl FnOnce(u64) -> u64) -> Self; - fn switch2( - self, - other: Self, - on_32: impl FnOnce(u32, u32) -> u32, - on_64: impl FnOnce(u64, u64) -> u64, - ) -> Self; + fn switch(self, on_32: impl FnOnce(u32) -> R, on_64: impl FnOnce(u64) -> R) -> R; fn from_bool(v: bool) -> Self { Self::from_32_z(v as u32) @@ -919,17 +839,9 @@ impl XLen for u32 { const XLEN: rvdc::Xlen = rvdc::Xlen::Rv32; - fn switch(self, on_32: impl FnOnce(u32) -> u32, _: impl FnOnce(u64) -> u64) -> Self { + fn switch(self, on_32: impl FnOnce(u32) -> R, _: impl FnOnce(u64) -> R) -> R { on_32(self) } - fn switch2( - self, - other: Self, - on_32: impl FnOnce(u32, u32) -> u32, - _: impl FnOnce(u64, u64) -> u64, - ) -> Self { - on_32(self, other) - } fn from_32_s(v: u32) -> Self { v @@ -951,17 +863,9 @@ impl XLen for u64 { const XLEN: rvdc::Xlen = rvdc::Xlen::Rv64; - fn switch(self, _: impl FnOnce(u32) -> u32, on_64: impl FnOnce(u64) -> u64) -> Self { + fn switch(self, _: impl FnOnce(u32) -> R, on_64: impl FnOnce(u64) -> R) -> R { on_64(self) } - fn switch2( - self, - other: Self, - _: impl FnOnce(u32, u32) -> u32, - on_64: impl FnOnce(u64, u64) -> u64, - ) -> Self { - on_64(self, other) - } fn from_32_s(v: u32) -> Self { v as i32 as i64 as u64 diff --git a/tests/check.rs b/tests/check.rs index 91d4380..9dd4fc2 100644 --- a/tests/check.rs +++ b/tests/check.rs @@ -30,7 +30,7 @@ fn check() -> eyre::Result<()> { test_case(tmpdir.path(), &file, name, 32, "rv32ima")?; test_case(tmpdir.path(), &file, name, 32, "rv32imac")?; - test_case(tmpdir.path(), &file, name, 64, "rv64ima")?; + // test_case(tmpdir.path(), &file, name, 64, "rv64ima")?; // test_case(tmpdir.path(), &file, name, 64, "rv64imac")?; } @@ -70,7 +70,7 @@ fn test_case( } }), Box::new(|_, xreg| { - if xreg[Reg::A7.0 as usize] == u64::MAX { + if xreg[Reg::A7.0 as usize] == u32::MAX as u64 { if xreg[Reg::A0.0 as usize] == 1 { Err(rustv32i::emu::Status::Exit { code: 0 }) } else { @@ -101,7 +101,6 @@ fn build(tmpdir: &Path, src: &Path, size: u8, march: &str) -> eyre::Result