Skip to main content

riscv_etrace/instruction/
decode.rs

1// Copyright (C) 2026 FZI Forschungszentrum Informatik
2// SPDX-License-Identifier: Apache-2.0
3//! Instruction decode
4
5use crate::config::Parameters;
6
7use super::bits::Bits;
8use super::info::Info;
9
10/// Decode for instruction [`Info`]
11pub trait Decode<I: Info> {
12    /// Decode a 16bit ("compressed") instruction [`Info`]
13    fn decode_16(&self, insn: u16) -> I;
14
15    /// Decode a 32bit ("normal") instruction [`Info`]
16    fn decode_32(&self, insn: u32) -> I;
17
18    /// Decode a 48bit instruction [`Info`]
19    fn decode_48(&self, insn: u64) -> I;
20
21    /// Decode a 64bit instruction [`Info`]
22    fn decode_64(&self, insn: u64) -> I;
23
24    /// Decode instruction [`Info`] from [`Bits`]
25    fn decode_bits(&self, bits: Bits) -> I {
26        match bits {
27            Bits::Bit16(bits) => self.decode_16(bits),
28            Bits::Bit32(bits) => self.decode_32(bits),
29            Bits::Bit48(bits) => self.decode_48(bits),
30            Bits::Bit64(bits) => self.decode_64(bits),
31        }
32    }
33}
34
35impl<D, I> Decode<(I, Bits)> for D
36where
37    D: Decode<I>,
38    I: Info,
39    (I, Bits): Info,
40{
41    fn decode_16(&self, insn: u16) -> (I, Bits) {
42        (self.decode_16(insn), Bits::Bit16(insn))
43    }
44
45    fn decode_32(&self, insn: u32) -> (I, Bits) {
46        (self.decode_32(insn), Bits::Bit32(insn))
47    }
48
49    fn decode_48(&self, insn: u64) -> (I, Bits) {
50        (self.decode_48(insn), Bits::Bit48(insn))
51    }
52
53    fn decode_64(&self, insn: u64) -> (I, Bits) {
54        (self.decode_64(insn), Bits::Bit64(insn))
55    }
56}
57
58#[cfg(feature = "riscv-isa")]
59impl Decode<riscv_isa::Instruction> for riscv_isa::Target {
60    fn decode_16(&self, insn: u16) -> riscv_isa::Instruction {
61        use riscv_isa::Compressed;
62
63        // Version 0.3.1 of `riscv-isa` wrongly decodes some instructions as
64        // `c.lui`, `c.jr` or `c.jalr`.
65        match riscv_isa::decode_compressed(insn, self) {
66            Compressed::C_LUI { rd: 0, .. } => Compressed::UNIMP,
67            Compressed::C_JR { rs1: 0, .. } => Compressed::UNIMP,
68            Compressed::C_JALR { rs1: 0, .. } => Compressed::UNIMP,
69            insn => insn,
70        }
71        .into()
72    }
73
74    fn decode_32(&self, insn: u32) -> riscv_isa::Instruction {
75        riscv_isa::decode_full(insn, self)
76    }
77
78    fn decode_48(&self, _insn: u64) -> riscv_isa::Instruction {
79        riscv_isa::Instruction::UNIMP
80    }
81
82    fn decode_64(&self, _insn: u64) -> riscv_isa::Instruction {
83        riscv_isa::Instruction::UNIMP
84    }
85}
86
87#[cfg(feature = "riscv-isa")]
88impl Decode<riscv_isa::Compressed> for riscv_isa::Target {
89    fn decode_16(&self, insn: u16) -> riscv_isa::Compressed {
90        use riscv_isa::Compressed;
91
92        // Version 0.3.1 of `riscv-isa` wrongly decodes some instructions as
93        // `c.lui`, `c.jr` or `c.jalr`.
94        match riscv_isa::decode_compressed(insn, self) {
95            Compressed::C_LUI { rd: 0, .. } => Compressed::UNIMP,
96            Compressed::C_JR { rs1: 0, .. } => Compressed::UNIMP,
97            Compressed::C_JALR { rs1: 0, .. } => Compressed::UNIMP,
98            insn => insn,
99        }
100    }
101
102    fn decode_32(&self, _insn: u32) -> riscv_isa::Compressed {
103        riscv_isa::Compressed::UNIMP
104    }
105
106    fn decode_48(&self, _insn: u64) -> riscv_isa::Compressed {
107        riscv_isa::Compressed::UNIMP
108    }
109
110    fn decode_64(&self, _insn: u64) -> riscv_isa::Compressed {
111        riscv_isa::Compressed::UNIMP
112    }
113}
114
115#[cfg(all(feature = "either", feature = "riscv-isa"))]
116impl Decode<either::Either<riscv_isa::Compressed, riscv_isa::Instruction>> for riscv_isa::Target {
117    fn decode_16(
118        &self,
119        insn: u16,
120    ) -> either::Either<riscv_isa::Compressed, riscv_isa::Instruction> {
121        either::Left(self.decode_16(insn))
122    }
123
124    fn decode_32(
125        &self,
126        insn: u32,
127    ) -> either::Either<riscv_isa::Compressed, riscv_isa::Instruction> {
128        either::Right(self.decode_32(insn))
129    }
130
131    fn decode_48(
132        &self,
133        insn: u64,
134    ) -> either::Either<riscv_isa::Compressed, riscv_isa::Instruction> {
135        either::Right(self.decode_48(insn))
136    }
137
138    fn decode_64(
139        &self,
140        insn: u64,
141    ) -> either::Either<riscv_isa::Compressed, riscv_isa::Instruction> {
142        either::Right(self.decode_64(insn))
143    }
144}
145
146/// Make a [`Decode`]
147///
148/// This trait allows type agnostic creation of some [`Decode`] values, provided
149/// that the type it is implemented for functions as one.
150pub trait MakeDecode {
151    /// Create a [`Decode`] for RV32I with all extensions enabled
152    ///
153    /// The resulting [`Decode`] decodes any instruction based on RV32I known to
154    /// it. It is not configured according to limitations of a specific target
155    /// CPU.
156    fn rv32i_full() -> Self;
157
158    /// Create a [`Decode`] for RV64I with all extensions enabled
159    ///
160    /// The resulting [`Decode`] decodes any instruction based on RV64I known to
161    /// it. It is not configured according to limitations of a specific target
162    /// CPU.
163    fn rv64i_full() -> Self;
164
165    /// Infer a [`Decode`] value from the given [`Parameters`]
166    ///
167    /// The value is (currently) inferred from the `iaddress_width_p` parameter.
168    /// The base set with the lowest general purpose register greater than
169    /// `iaddress_width_p` will be selected.
170    fn infer_from_params(params: &Parameters) -> Option<Self>
171    where
172        Self: Sized,
173    {
174        match params.iaddress_width_p.get() {
175            0..=32 => Some(Self::rv32i_full()),
176            33..=64 => Some(Self::rv64i_full()),
177            _ => None,
178        }
179    }
180}
181
182#[cfg(feature = "riscv-isa")]
183impl MakeDecode for riscv_isa::Target {
184    fn rv32i_full() -> Self {
185        Self {
186            xlen: riscv_isa::Xlen::Rv32,
187            privileged: true,
188            supervisor_mode: true,
189            m: true,
190            a: true,
191            f: true,
192            d: true,
193            q: true,
194            c: true,
195            zicsr: true,
196            zifencei: true,
197            zawrs: true,
198            zfh: true,
199            zba: true,
200            zbb: true,
201            zbc: true,
202            zbkb: true,
203            zbs: true,
204        }
205    }
206
207    fn rv64i_full() -> Self {
208        Self {
209            xlen: riscv_isa::Xlen::Rv64,
210            privileged: true,
211            supervisor_mode: true,
212            m: true,
213            a: true,
214            f: true,
215            d: true,
216            q: true,
217            c: true,
218            zicsr: true,
219            zifencei: true,
220            zawrs: true,
221            zfh: true,
222            zba: true,
223            zbb: true,
224            zbc: true,
225            zbkb: true,
226            zbs: true,
227        }
228    }
229}