Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/isa/riscv/compressed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ fn decode_q0(h: u16, funct3: u32, rv64: bool, isa: &Isa) -> Insn {
mk(Op::LdPair, rd_, rs1_, 0, off_d as i64, h)
} else {
// C.FLW -> flw rd', off(rs1')
if !isa.f {
return ill(h);
}
let off = (bits(h, 12, 10) << 3) | (bit(h, 6) << 2) | (bit(h, 5) << 6);
mk(Op::Flw, rd_, rs1_, 0, off as i64, h)
}
Expand Down Expand Up @@ -171,6 +174,9 @@ fn decode_q0(h: u16, funct3: u32, rv64: bool, isa: &Isa) -> Insn {
mk(Op::SdPair, 0, rs1_, rs2_, off_d as i64, h)
} else {
// C.FSW -> fsw rs2', off(rs1')
if !isa.f {
return ill(h);
}
let off = (bits(h, 12, 10) << 3) | (bit(h, 6) << 2) | (bit(h, 5) << 6);
mk(Op::Fsw, 0, rs1_, rvc_reg(bits(h, 4, 2)), off as i64, h)
}
Expand Down Expand Up @@ -384,6 +390,9 @@ fn decode_q2(h: u16, funct3: u32, rv64: bool, isa: &Isa) -> Insn {
mk(Op::LdPair, rd, 2, 0, off as i64, h)
} else {
// C.FLWSP -> flw rd, off(x2)
if !isa.f {
return ill(h);
}
let off = (bit(h, 12) << 5) | (bits(h, 6, 4) << 2) | (bits(h, 3, 2) << 6);
mk(Op::Flw, rd, 2, 0, off as i64, h)
}
Expand Down Expand Up @@ -454,6 +463,9 @@ fn decode_q2(h: u16, funct3: u32, rv64: bool, isa: &Isa) -> Insn {
mk(Op::SdPair, 0, 2, rs2, off as i64, h)
} else {
// C.FSWSP -> fsw rs2, off(x2)
if !isa.f {
return ill(h);
}
let off = (bits(h, 12, 9) << 2) | (bits(h, 8, 7) << 6);
mk(Op::Fsw, 0, 2, bits(h, 6, 2) as u8, off as i64, h)
}
Expand Down Expand Up @@ -715,6 +727,29 @@ mod tests {
assert_eq!(decode_rvc(c_sd, Xlen::Rv32, &isa).op, Op::Fsw);
}

#[test]
fn rv32_compressed_single_precision_memory_requires_f() {
let encodings = [
((0b011 << 13) | (2 << 7) | 0b00, Op::Flw),
((0b111 << 13) | (2 << 7) | 0b00, Op::Fsw),
((0b011 << 13) | (8 << 7) | 0b10, Op::Flw),
((0b111 << 13) | (8 << 2) | 0b10, Op::Fsw),
];

let enabled = Isa::rv64gc();
let mut disabled = enabled;
disabled.f = false;
disabled.d = false;
disabled.zclsd = false;
for (raw, expected) in encodings {
assert_eq!(decode_rvc(raw as u16, Xlen::Rv32, &enabled).op, expected);
assert_eq!(
decode_rvc(raw as u16, Xlen::Rv32, &disabled).op,
Op::Illegal
);
}
}

#[test]
fn zcmp_zcmt_decode_overlap_slot() {
let mut isa = Isa::rv64gc();
Expand Down
77 changes: 36 additions & 41 deletions src/isa/riscv/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ mod execution;
mod jit;
mod vector_config;
mod vector_conversion;
mod vector_mask;
mod vector_memory;
mod vector_permute;
mod vector_validation;

/// Privilege level of the hart.
Expand Down Expand Up @@ -187,6 +189,7 @@ pub struct RiscVCpu {
mstatus: u64,
mtvec: u64,
mepc: u64,
sepc: u64,
mcause: u64,
mtval: u64,
mscratch: u64,
Expand Down Expand Up @@ -266,6 +269,7 @@ impl RiscVCpu {
mstatus: 0,
mtvec: 0,
mepc: 0,
sepc: 0,
mcause: 0,
mtval: 0,
mscratch: 0,
Expand Down Expand Up @@ -310,6 +314,7 @@ impl RiscVCpu {
self.mstatus = 0;
self.mtvec = 0;
self.mepc = 0;
self.sepc = 0;
self.mcause = 0;
self.mtval = 0;
self.mscratch = 0;
Expand Down Expand Up @@ -733,7 +738,6 @@ impl RiscVCpu {
| Op::PrefetchI
| Op::PrefetchR
| Op::PrefetchW
| Op::SfenceVm
| Op::SfenceVma
| Op::SinvalVma
| Op::SfenceWInval
Expand Down Expand Up @@ -909,10 +913,17 @@ impl RiscVCpu {
let mask = (1u64 << nbits) - 1;
self.set_x(rd, (a >> (rs2 as u64)) & mask);
}
Op::Wfi => return Ok(RiscVExit::Wfi),
Op::Wfi => {
return Ok(if self.locally_enabled_interrupt_pending() {
RiscVExit::Continue
} else {
RiscVExit::Wfi
});
}
Op::WrsNto | Op::WrsSto => {}
Op::Uret | Op::SfenceVm => return Err(Trap::illegal(insn.raw)),
Op::Mret => self.mret(),
Op::Sret | Op::Uret => self.mret(), // single-mode model: same restore path
Op::Sret => self.sret(insn)?,

// ---- Zicsr ----
Op::Csrrw | Op::Csrrs | Op::Csrrc | Op::Csrrwi | Op::Csrrsi | Op::Csrrci => {
Expand Down Expand Up @@ -2193,18 +2204,19 @@ impl RiscVCpu {
| Op::Vmsgt => {
let eb = self.sew_bytes();
let mask = Self::sew_mask(eb);
let source = self.vector_snapshot();
let scalar = match insn.funct3 {
0b100 => self.x(insn.rs1) & mask,
0b011 => sext5(insn.rs1) & mask,
_ => 0,
};
for e in vstart..vl {
if !vm && !self.vmask_bit(e) {
if !vm && !Self::snapshot_mask_bit(&source, e) {
continue; // masked-off: undisturbed
}
let a = self.velem(vs2, e, eb);
let a = Self::snapshot_velem(&source, vs2, e, eb);
let b = if insn.funct3 == 0b000 {
self.velem(insn.rs1, e, eb)
Self::snapshot_velem(&source, insn.rs1, e, eb)
} else {
scalar
};
Expand Down Expand Up @@ -2600,19 +2612,20 @@ impl RiscVCpu {
Op::Vmfeq | Op::Vmfne | Op::Vmflt | Op::Vmfle | Op::Vmfgt | Op::Vmfge => {
let eb = self.sew_bytes();
let is_vv = insn.funct3 == 0b001;
let source = self.vector_snapshot();
let scalar = match eb {
2 => self.h(insn.rs1),
4 => self.s32(insn.rs1),
_ => self.f(insn.rs1),
};
let mut flags = 0u32;
for e in vstart..vl {
if !vm && !self.vmask_bit(e) {
if !vm && !Self::snapshot_mask_bit(&source, e) {
continue;
}
let a = self.velem(vs2, e, eb);
let a = Self::snapshot_velem(&source, vs2, e, eb);
let b = if is_vv {
self.velem(insn.rs1, e, eb)
Self::snapshot_velem(&source, insn.rs1, e, eb)
} else {
scalar
};
Expand Down Expand Up @@ -3202,6 +3215,7 @@ impl RiscVCpu {
// vd.mask[i] = carry/borrow-out; carry-in from v0 only when vm == 0.
let eb = self.sew_bytes();
let mask = Self::sew_mask(eb) as u128;
let source = self.vector_snapshot();
let scalar = match insn.funct3 {
0b100 => self.x(insn.rs1) & Self::sew_mask(eb),
0b011 => sext5(insn.rs1) & Self::sew_mask(eb),
Expand All @@ -3210,14 +3224,14 @@ impl RiscVCpu {
let is_vv = insn.funct3 == 0b000;
let use_cin = !vm;
for e in vstart..vl {
let a = self.velem(vs2, e, eb) as u128;
let a = Self::snapshot_velem(&source, vs2, e, eb) as u128;
let b = if is_vv {
self.velem(insn.rs1, e, eb)
Self::snapshot_velem(&source, insn.rs1, e, eb)
} else {
scalar
} as u128;
let cin = if use_cin {
self.vmask_bit(e) as u128
Self::snapshot_mask_bit(&source, e) as u128
} else {
0
};
Expand Down Expand Up @@ -3262,25 +3276,7 @@ impl RiscVCpu {
}
}
Op::Vmvr => {
// vmv<nr>r.v whole-register move: only nr in {1,2,4,8} (simm
// 0/1/3/7) is defined, the encoding must be unmasked, and both
// vd and vs2 must be aligned to the nr-register group. Reserved
// simm values, masked encodings, or misaligned groups trap.
let nreg = match insn.rs1 {
0 => 1u8,
1 => 2,
3 => 4,
7 => 8,
_ => return Err(Trap::illegal(insn.raw)),
};
if !vm || vd % nreg != 0 || vs2 % nreg != 0 {
return Err(Trap::illegal(insn.raw));
}
let total = nreg as usize * VLENB as usize;
for i in 0..total {
let b = self.velem(vs2, i, 1);
self.set_velem(vd, i, 1, b);
}
self.exec_whole_register_move(insn, vm)?;
}
Op::Vcompress => {
// vcompress.vm is unmasked (vm=1), is not restartable (vstart
Expand Down Expand Up @@ -5254,21 +5250,20 @@ mod tests {
let sys =
|funct7: u32, rs2: u32, rs1: u32| (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | 0x73;
for w in [
sys(0x08, 0x04, 10), // sfence.vm a0
sys(0x09, 11, 10), // sfence.vma a0, a1
sys(0x0b, 11, 10), // sinval.vma a0, a1
sys(0x0c, 0, 0), // sfence.w.inval
sys(0x0c, 1, 0), // sfence.inval.ir
sys(0x11, 11, 10), // hfence.vvma a0, a1
sys(0x13, 11, 10), // hinval.vvma a0, a1
sys(0x31, 11, 10), // hfence.gvma a0, a1
sys(0x33, 11, 10), // hinval.gvma a0, a1
sys(0x09, 11, 10), // sfence.vma a0, a1
sys(0x0b, 11, 10), // sinval.vma a0, a1
sys(0x0c, 0, 0), // sfence.w.inval
sys(0x0c, 1, 0), // sfence.inval.ir
sys(0x11, 11, 10), // hfence.vvma a0, a1
sys(0x13, 11, 10), // hinval.vvma a0, a1
sys(0x31, 11, 10), // hfence.gvma a0, a1
sys(0x33, 11, 10), // hinval.gvma a0, a1
] {
assert_eq!(run_one(&mut c, w), RiscVExit::Continue);
}
assert_eq!(c.x(10), 0x4000);
assert_eq!(c.x(11), 0x22);
assert_eq!(c.pc(), 0x300 + 9 * 4);
assert_eq!(c.pc(), 0x300 + 8 * 4);
}

#[test]
Expand Down
Loading
Loading