airbender_host/
machine.rs1use riscv_transpiler::ir::{
2 preprocess_bytecode, DecodingOptions, FullUnsignedMachineDecoderConfig, Instruction,
3 ReducedMachineDecoderConfig,
4};
5
6#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
17#[non_exhaustive]
18pub enum MachineProfile {
19 #[default]
21 FullUnsigned,
22 Reduced,
24}
25
26type PreprocessBytecodeFn = fn(&[u32]) -> Vec<Instruction>;
27
28#[derive(Clone, Copy)]
29pub(crate) struct TranspilerDecoderConfig {
30 name: &'static str,
31 preprocess_bytecode: PreprocessBytecodeFn,
32 pub(crate) stable_profile: Option<MachineProfile>,
33}
34
35impl TranspilerDecoderConfig {
36 pub(crate) fn from_profile(profile: MachineProfile) -> Self {
37 match profile {
38 MachineProfile::FullUnsigned => Self {
39 name: "full unsigned",
40 preprocess_bytecode: preprocess_bytecode::<FullUnsignedMachineDecoderConfig>,
41 stable_profile: Some(profile),
42 },
43 MachineProfile::Reduced => Self {
44 name: "reduced",
45 preprocess_bytecode: preprocess_bytecode::<ReducedMachineDecoderConfig>,
46 stable_profile: Some(profile),
47 },
48 }
49 }
50
51 pub(crate) fn unstable_raw<D>(name: &'static str) -> Self
52 where
53 D: DecodingOptions,
54 {
55 Self {
56 name,
57 preprocess_bytecode: preprocess_bytecode::<D>,
58 stable_profile: None,
59 }
60 }
61
62 pub(crate) fn name(&self) -> &'static str {
63 self.name
64 }
65
66 pub(crate) fn preprocess(&self, bytecode: &[u32]) -> Vec<Instruction> {
67 (self.preprocess_bytecode)(bytecode)
68 }
69}
70
71impl Default for TranspilerDecoderConfig {
72 fn default() -> Self {
73 Self::from_profile(MachineProfile::default())
74 }
75}
76
77impl std::fmt::Debug for TranspilerDecoderConfig {
78 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 formatter
80 .debug_struct("TranspilerDecoderConfig")
81 .field("name", &self.name)
82 .field("stable_profile", &self.stable_profile)
83 .finish_non_exhaustive()
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::{MachineProfile, TranspilerDecoderConfig};
90 use riscv_transpiler::ir::{
91 DebugReducedMachineDecoderConfig, FullMachineDecoderConfig, InstructionName,
92 };
93
94 const DIV_X3_X1_X2: u32 = 0x0220c1b3;
95 const LBU_X1_FROM_X0: u32 = 0x00004083;
96
97 #[test]
98 fn raw_decoder_can_opt_into_full_signed_decoding() {
99 let full_signed =
100 TranspilerDecoderConfig::unstable_raw::<FullMachineDecoderConfig>("test full signed")
101 .preprocess(&[DIV_X3_X1_X2]);
102 let full_unsigned = TranspilerDecoderConfig::from_profile(MachineProfile::FullUnsigned)
103 .preprocess(&[DIV_X3_X1_X2]);
104
105 assert_eq!(full_signed[0].name, InstructionName::Div);
106 assert_eq!(full_unsigned[0].name, InstructionName::Illegal);
107 }
108
109 #[test]
110 fn profile_controls_subword_memory_decoding() {
111 let full_unsigned = TranspilerDecoderConfig::from_profile(MachineProfile::FullUnsigned)
112 .preprocess(&[LBU_X1_FROM_X0]);
113 let reduced = TranspilerDecoderConfig::from_profile(MachineProfile::Reduced)
114 .preprocess(&[LBU_X1_FROM_X0]);
115
116 assert_eq!(full_unsigned[0].name, InstructionName::Lbu);
117 assert_eq!(reduced[0].name, InstructionName::Illegal);
118 }
119
120 #[test]
121 fn raw_decoder_accepts_upstream_decoder_configurations() {
122 let instructions =
123 TranspilerDecoderConfig::unstable_raw::<DebugReducedMachineDecoderConfig>(
124 "debug reduced",
125 )
126 .preprocess(&[LBU_X1_FROM_X0]);
127
128 assert_eq!(instructions[0].name, InstructionName::Lbu);
129 }
130}