1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Zve64x configuration instructions
#[cfg(test)]
mod tests;
pub mod zve64x_config_helpers;
use crate::v::vector_registers::VectorRegistersExt;
use crate::{CsrError, Csrs, ExecutableInstruction, ExecutionError, ProgramCounter, RegisterFile};
use ab_riscv_macros::instruction_execution;
use ab_riscv_primitives::prelude::*;
use core::fmt;
use core::ops::ControlFlow;
#[instruction_execution]
impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
for Zve64xConfigInstruction<Reg>
where
Reg: Register,
Regs: RegisterFile<Reg>,
ExtState: VectorRegistersExt<Reg, CustomError>,
[(); ExtState::ELEN as usize]:,
[(); ExtState::VLEN as usize]:,
PC: ProgramCounter<Reg::Type, Memory, CustomError>,
CustomError: fmt::Debug,
{
/// Validate reads to vector CSRs from Zicsr instructions.
///
/// All vector CSRs are accessible from unprivileged code (U-mode).
/// Reads are pass-through: the raw value stored in the CSR is the output value.
fn prepare_csr_read<C>(
_csrs: &C,
csr_index: u16,
raw_value: Reg::Type,
output_value: &mut Reg::Type,
) -> Result<bool, CsrError<CustomError>>
where
C: Csrs<Self::Reg, CustomError>,
{
if VCsr::from_index(csr_index).is_some() {
*output_value = raw_value;
Ok(true)
} else {
// Not a vector CSR
Ok(false)
}
}
/// Validate, sanitize, and mirror writes to vector CSRs from Zicsr instructions.
///
/// Enforces WARL semantics and vcsr mirroring:
/// - `vl`, `vtype`, `vlenb` are read-only: writes are rejected
/// - `vxsat`: only bit 0 is writable; mirrors into `vcsr[0]`
/// - `vxrm`: only bits `[1:0]` are writable; mirrors into `vcsr[2:1]`
/// - `vcsr`: only bits `[2:0]` are writable; mirrors into `vxsat` and `vxrm`
/// - `vstart`: full XLEN write allowed (WARL, implementation may restrict range)
fn prepare_csr_write<C>(
csrs: &mut C,
csr_index: u16,
write_value: Reg::Type,
output_value: &mut Reg::Type,
) -> Result<bool, CsrError<CustomError>>
where
C: Csrs<Self::Reg, CustomError>,
{
if let Some(vcsr) = VCsr::from_index(csr_index) {
// WARL: mask to valid bits, zero upper bits
*output_value = match vcsr {
VCsr::Vstart => {
// WARL: allow full XLEN write, but clamp to implementation-supported range
let max = Reg::Type::from(u16::MAX);
write_value.min(max)
}
VCsr::Vxsat => {
let masked = write_value & Reg::Type::from(1u8);
// Mirror `vxsat` into `vcsr[0]`, preserving `vcsr[2:1]` (`vxrm`)
let old_vcsr = csrs.read_csr(VCsr::Vcsr as u16)?;
let new_vcsr = (old_vcsr & !Reg::Type::from(1u8)) | masked;
csrs.write_csr(VCsr::Vcsr as u16, new_vcsr)?;
masked
}
VCsr::Vxrm => {
let masked = write_value & Reg::Type::from(0b11u8);
// Mirror `vxrm` into `vcsr[2:1]`, preserving `vcsr[0]` (`vxsat`)
let old_vcsr = csrs.read_csr(VCsr::Vcsr as u16)?;
let new_vcsr = (old_vcsr & !Reg::Type::from(0b110u8)) | (masked << 1);
csrs.write_csr(VCsr::Vcsr as u16, new_vcsr)?;
masked
}
VCsr::Vcsr => {
// Mirror `vcsr[0]` -> `vxsat`
let new_vxsat = write_value & Reg::Type::from(1u8);
csrs.write_csr(VCsr::Vxsat as u16, new_vxsat)?;
// Mirror `vcsr[2:1]` -> `vxrm`
let new_vxrm = (write_value >> 1) & Reg::Type::from(0b11u8);
csrs.write_csr(VCsr::Vxrm as u16, new_vxrm)?;
write_value & Reg::Type::from(0b111u8)
}
VCsr::Vl | VCsr::Vtype | VCsr::Vlenb => {
// Read-only CSRs (from Zicsr perspective)
Err(CsrError::ReadOnly { csr_index })?
}
};
Ok(true)
} else {
Ok(false)
}
}
#[inline(always)]
fn execute(
self,
regs: &mut Regs,
ext_state: &mut ExtState,
_memory: &mut Memory,
program_counter: &mut PC,
_system_instruction_handler: &mut InstructionHandler,
) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>> {
match self {
Self::Vsetvli { rd, rs1, vtypei } => {
zve64x_config_helpers::apply_vsetvl(
regs,
ext_state,
program_counter,
rd,
rs1,
Reg::Type::from(vtypei),
)?;
}
Self::Vsetivli { rd, uimm, vtypei } => {
zve64x_config_helpers::apply_vsetivli(
regs,
ext_state,
program_counter,
rd,
uimm,
vtypei,
)?;
}
Self::Vsetvl { rd, rs1, rs2 } => {
let vtype_raw = regs.read(rs2);
zve64x_config_helpers::apply_vsetvl(
regs,
ext_state,
program_counter,
rd,
rs1,
vtype_raw,
)?;
}
}
Ok(ControlFlow::Continue(()))
}
}