Skip to main content

ab_riscv_interpreter/rv32/c/
zca.rs

1//! RV32 Zca extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::{
7    ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
8    ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
9    PackedAddress, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
10    SystemInstructionHandler, ThreadedExecutableInstruction, ThreadedExecutionResult,
11    VirtualMemory,
12};
13use ab_riscv_macros::instruction_execution;
14use ab_riscv_primitives::prelude::*;
15
16#[instruction_execution]
17const impl<Reg, Hart> ExecutableInstructionOperands for Rv32ZcaInstruction<Hart>
18where
19    Reg: Register<Type = u32>,
20    Hart: HartConfig<Reg = Reg>,
21{
22}
23
24#[instruction_execution]
25const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for Rv32ZcaInstruction<Hart>
26where
27    Reg: Register<Type = u32>,
28    Hart: HartConfig<Reg = Reg>,
29{
30}
31
32#[instruction_execution]
33const impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
34    for Rv32ZcaInstruction<Hart>
35where
36    Reg: [const] Register<Type = u32>,
37    Hart: HartConfig<Reg = Reg>,
38    Regs: [const] RegisterFile<Reg>,
39    Memory: [const] VirtualMemory,
40    PC: [const] ProgramCounter<Reg::Type, Memory>,
41    Env: [const] SystemInstructionHandler<Reg, Regs, Memory, PC>,
42{
43    #[inline(always)]
44    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
45    fn execute(
46        self,
47        Rs1Rs2OperandValues {
48            rs1_value,
49            rs2_value,
50        }: Rs1Rs2OperandValues<Reg::Type>,
51        regs: &mut Regs,
52        env: &mut Env,
53        memory: &mut Memory,
54        program_counter: &PC,
55    ) -> ExecutionResult<Reg> {
56        match self {
57            // Quadrant 00
58            Self::CAddi4spn { rd, nzuimm } => {
59                let sp_val = regs.read(Reg::SP);
60                ExecutionResult::Continue {
61                    rd,
62                    value: sp_val.wrapping_add(u32::from(nzuimm)),
63                }
64            }
65            Self::CLw { rd, rs1: _, uimm } => {
66                let addr = rs1_value.wrapping_add(u32::from(uimm));
67                let value = memory.read::<i32>(u64::from(addr))?.cast_unsigned();
68                ExecutionResult::Continue { rd, value }
69            }
70            Self::CSw {
71                rs1: _,
72                rs2: _,
73                uimm,
74            } => {
75                let addr = rs1_value.wrapping_add(u32::from(uimm));
76                memory.write(u64::from(addr), rs2_value)?;
77                ExecutionResult::ContinueNoWrite
78            }
79
80            // Quadrant 01
81            Self::CNop => ExecutionResult::ContinueNoWrite,
82            Self::CAddi { rd, nzimm } => {
83                let value = regs.read(rd).wrapping_add(i32::from(nzimm).cast_unsigned());
84                ExecutionResult::Continue { rd, value }
85            }
86            Self::CJal { imm } => {
87                let return_addr = program_counter.get_pc();
88                regs.write(Reg::RA, return_addr);
89                ExecutionResult::Branch {
90                    offset: i32::from(imm),
91                }
92            }
93            Self::CLi { rd, imm } => ExecutionResult::Continue {
94                rd,
95                value: i32::from(imm).cast_unsigned(),
96            },
97            Self::CAddi16sp { nzimm } => {
98                let value = regs
99                    .read(Reg::SP)
100                    .wrapping_add(i32::from(nzimm).cast_unsigned());
101                ExecutionResult::Continue { rd: Reg::SP, value }
102            }
103            Self::CLui { rd, nzimm } => ExecutionResult::Continue {
104                rd,
105                value: nzimm.to_i32().cast_unsigned(),
106            },
107            Self::CSrli { rd, shamt } => {
108                let value = regs.read(rd) >> shamt.get();
109                ExecutionResult::Continue { rd, value }
110            }
111            Self::CSrai { rd, shamt } => {
112                let value = regs.read(rd).cast_signed() >> shamt.get();
113                ExecutionResult::Continue {
114                    rd,
115                    value: value.cast_unsigned(),
116                }
117            }
118            Self::CAndi { rd, imm } => {
119                let value = regs.read(rd) & i32::from(imm).cast_unsigned();
120                ExecutionResult::Continue { rd, value }
121            }
122            Self::CSub { rd, rs2: _ } => {
123                let value = regs.read(rd).wrapping_sub(rs2_value);
124                ExecutionResult::Continue { rd, value }
125            }
126            Self::CXor { rd, rs2: _ } => {
127                let value = regs.read(rd) ^ rs2_value;
128                ExecutionResult::Continue { rd, value }
129            }
130            Self::COr { rd, rs2: _ } => {
131                let value = regs.read(rd) | rs2_value;
132                ExecutionResult::Continue { rd, value }
133            }
134            Self::CAnd { rd, rs2: _ } => {
135                let value = regs.read(rd) & rs2_value;
136                ExecutionResult::Continue { rd, value }
137            }
138            Self::CJ { imm } => ExecutionResult::Branch {
139                offset: i32::from(imm),
140            },
141            Self::CBeqz { rs1: _, imm } => {
142                if rs1_value == 0 {
143                    return ExecutionResult::Branch {
144                        offset: i32::from(imm),
145                    };
146                }
147
148                ExecutionResult::ContinueNoWrite
149            }
150            Self::CBnez { rs1: _, imm } => {
151                if rs1_value != 0 {
152                    return ExecutionResult::Branch {
153                        offset: i32::from(imm),
154                    };
155                }
156
157                ExecutionResult::ContinueNoWrite
158            }
159
160            // Quadrant 10
161            Self::CSlli { rd, shamt } => {
162                let value = regs.read(rd) << shamt.get();
163                ExecutionResult::Continue { rd, value }
164            }
165            Self::CLwsp { rd, uimm } => {
166                let addr = regs.read(Reg::SP).wrapping_add(u32::from(uimm));
167                let value = memory.read::<i32>(u64::from(addr))?.cast_unsigned();
168                ExecutionResult::Continue { rd, value }
169            }
170            Self::CJr { rs1: _ } => {
171                let target = rs1_value & !1;
172                ExecutionResult::Jump { target }
173            }
174            Self::CMv { rd, rs2: _ } => ExecutionResult::Continue {
175                rd,
176                value: rs2_value,
177            },
178            Self::CEbreak => {
179                env.handle_ebreak(regs, memory, program_counter, size_of::<u16>() as u8)
180            }
181            Self::CJalr { rs1: _ } => {
182                let target = rs1_value & !1;
183                let return_addr = program_counter.get_pc();
184                regs.write(Reg::RA, return_addr);
185                return ExecutionResult::Jump { target };
186            }
187            Self::CAdd { rd, rs2: _ } => {
188                let value = regs.read(rd).wrapping_add(rs2_value);
189                ExecutionResult::Continue { rd, value }
190            }
191            Self::CSwsp { rs2: _, uimm } => {
192                let addr = regs.read(Reg::SP).wrapping_add(u32::from(uimm));
193                memory.write(u64::from(addr), rs2_value)?;
194                ExecutionResult::ContinueNoWrite
195            }
196            Self::CUnimp => {
197                let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
198                ExecutionResult::Err(ExecutionError::IllegalInstruction {
199                    address: PackedAddress::new(old_pc),
200                })
201            }
202        }
203    }
204}