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
//! Zve64x configuration instructions
#[cfg(test)]
mod tests;
use crate::instructions::Instruction;
use crate::registers::general_purpose::Register;
use ab_riscv_macros::instruction;
use core::fmt;
/// RISC-V Zve64x configuration instruction.
///
/// These instructions set the vector type (`vtype`) and vector length (`vl`) registers. They use
/// the OP-V major opcode (0b1010111) with funct3=0b111 (OPCFG).
#[instruction]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[rustfmt::skip]
#[doc(hidden)]
pub enum Zve64xConfigInstruction<Reg> {
/// Set vector length and type from GPR
///
/// `vsetvli rd, rs1, vtypei`
/// rd = new vl, rs1 = AVL, vtypei = new vtype setting (11-bit immediate)
Vsetvli { rd: Reg, rs1: Reg, vtypei: u16 },
/// Set vector length and type from immediate AVL
///
/// `vsetivli rd, uimm, vtypei`
/// rd = new vl, uimm\[4:0] = AVL, vtypei = new vtype setting (10-bit immediate)
Vsetivli { rd: Reg, uimm: u8, vtypei: u16 },
/// Set vector length and type from GPRs
///
/// `vsetvl rd, rs1, rs2`
/// rd = new vl, rs1 = AVL, rs2 = new vtype value
Vsetvl { rd: Reg, rs1: Reg, rs2: Reg },
}
#[instruction]
impl<Reg> const Instruction for Zve64xConfigInstruction<Reg>
where
Reg: [const] Register,
{
type Reg = Reg;
#[inline(always)]
fn try_decode(instruction: u32) -> Option<Self> {
let opcode = (instruction & 0b111_1111) as u8;
// OP-V major opcode
if opcode != 0b1010111 {
None?;
}
let rd_bits = ((instruction >> 7) & 0x1f) as u8;
let funct3 = ((instruction >> 12) & 0b111) as u8;
let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
let bit31 = (instruction >> 31) & 1;
let bit30 = (instruction >> 30) & 1;
// OPCFG: funct3 = 0b111
if funct3 != 0b111 {
None?;
}
let rd = Reg::from_bits(rd_bits)?;
match bit31 {
// vsetvli: bit31=0
// [0|zimm[10:0]|rs1|111|rd|1010111]
0 => {
let rs1 = Reg::from_bits(rs1_bits)?;
let vtypei = ((instruction >> 20) & 0x7ff) as u16;
Some(Self::Vsetvli { rd, rs1, vtypei })
}
// bit31=1: vsetivli or vsetvl
_ => match bit30 {
// vsetivli: bits[31:30]=11
// [11|zimm[9:0]|uimm[4:0]|111|rd|1010111]
1 => {
let uimm = rs1_bits;
let vtypei = ((instruction >> 20) & 0x3ff) as u16;
Some(Self::Vsetivli { rd, uimm, vtypei })
}
// vsetvl: bit31=1, bit30=0
// [1000000|rs2|rs1|111|rd|1010111]
_ => {
// bits[29:25] must be 0b00000
let bits_29_25 = ((instruction >> 25) & 0b1_1111) as u8;
if bits_29_25 != 0 {
None?;
}
let rs1 = Reg::from_bits(rs1_bits)?;
let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
let rs2 = Reg::from_bits(rs2_bits)?;
Some(Self::Vsetvl { rd, rs1, rs2 })
}
},
}
}
#[inline(always)]
fn alignment() -> u8 {
align_of::<u32>() as u8
}
#[inline(always)]
fn size(&self) -> u8 {
size_of::<u32>() as u8
}
}
impl<Reg> fmt::Display for Zve64xConfigInstruction<Reg>
where
Reg: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[rustfmt::skip]
match self {
Self::Vsetvli { rd, rs1, vtypei } => write!(f, "vsetvli {rd}, {rs1}, {vtypei}"),
Self::Vsetivli { rd, uimm, vtypei } => write!(f, "vsetivli {rd}, {uimm}, {vtypei}"),
Self::Vsetvl { rd, rs1, rs2 } => write!(f, "vsetvl {rd}, {rs1}, {rs2}"),
}
}
}