Skip to main content

ab_riscv_interpreter/rv64/c/
zca.rs

1//! RV64 Zca extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::{
7    ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
8    ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands, SystemInstructionHandler,
9    VirtualMemory,
10};
11use ab_riscv_macros::instruction_execution;
12use ab_riscv_primitives::prelude::*;
13use core::ops::ControlFlow;
14
15#[instruction_execution]
16impl<Reg> ExecutableInstructionOperands for Rv64ZcaInstruction<Reg> where Reg: Register<Type = u64> {}
17
18#[instruction_execution]
19impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
20    for Rv64ZcaInstruction<Reg>
21where
22    Reg: Register<Type = u64>,
23{
24}
25
26#[instruction_execution]
27impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
28    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
29    for Rv64ZcaInstruction<Reg>
30where
31    Reg: Register<Type = u64>,
32    Regs: RegisterFile<Reg>,
33    Memory: VirtualMemory,
34    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
35    InstructionHandler: SystemInstructionHandler<Reg, Regs, Memory, PC, CustomError>,
36{
37    #[inline(always)]
38    fn execute(
39        self,
40        Rs1Rs2OperandValues {
41            rs1_value,
42            rs2_value,
43        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
44        regs: &mut Regs,
45        _ext_state: &mut ExtState,
46        memory: &mut Memory,
47        program_counter: &mut PC,
48        system_instruction_handler: &mut InstructionHandler,
49    ) -> Result<
50        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
51        ExecutionError<Reg::Type, CustomError>,
52    > {
53        match self {
54            // Quadrant 00
55            Self::CAddi4spn { rd, nzuimm } => {
56                let sp_val = regs.read(Reg::SP);
57                Ok(ControlFlow::Continue((
58                    rd,
59                    sp_val.wrapping_add(u64::from(nzuimm)),
60                )))
61            }
62            Self::CLw { rd, rs1: _, uimm } => {
63                let addr = rs1_value.wrapping_add(u64::from(uimm));
64                let value = i64::from(memory.read::<i32>(addr)?);
65                Ok(ControlFlow::Continue((rd, value.cast_unsigned())))
66            }
67            Self::CLd { rd, rs1: _, uimm } => {
68                let addr = rs1_value.wrapping_add(u64::from(uimm));
69                let value = memory.read::<u64>(addr)?;
70                Ok(ControlFlow::Continue((rd, value)))
71            }
72            Self::CSw {
73                rs1: _,
74                rs2: _,
75                uimm,
76            } => {
77                let addr = rs1_value.wrapping_add(u64::from(uimm));
78                memory.write(addr, rs2_value as u32)?;
79                Ok(ControlFlow::Continue(Default::default()))
80            }
81            Self::CSd {
82                rs1: _,
83                rs2: _,
84                uimm,
85            } => {
86                let addr = rs1_value.wrapping_add(u64::from(uimm));
87                memory.write(addr, rs2_value)?;
88                Ok(ControlFlow::Continue(Default::default()))
89            }
90
91            // Quadrant 01
92            Self::CNop => {}
93            Self::CAddi { rd, nzimm } => {
94                let value = regs.read(rd).wrapping_add(i64::from(nzimm).cast_unsigned());
95                Ok(ControlFlow::Continue((rd, value)))
96            }
97            Self::CAddiw { rd, imm } => {
98                let sum = (regs.read(rd) as i32).wrapping_add(i32::from(imm));
99                Ok(ControlFlow::Continue((rd, i64::from(sum).cast_unsigned())))
100            }
101            Self::CLi { rd, imm } => {
102                Ok(ControlFlow::Continue((rd, i64::from(imm).cast_unsigned())))
103            }
104            Self::CAddi16sp { nzimm } => {
105                let value = regs
106                    .read(Reg::SP)
107                    .wrapping_add(i64::from(nzimm).cast_unsigned());
108                Ok(ControlFlow::Continue((Reg::SP, value)))
109            }
110            Self::CLui { rd, nzimm } => Ok(ControlFlow::Continue((
111                rd,
112                i64::from(nzimm).cast_unsigned(),
113            ))),
114            Self::CSrli { rd, shamt } => {
115                let value = regs.read(rd) >> shamt;
116                Ok(ControlFlow::Continue((rd, value)))
117            }
118            Self::CSrai { rd, shamt } => {
119                let value = regs.read(rd).cast_signed() >> shamt;
120                Ok(ControlFlow::Continue((rd, value.cast_unsigned())))
121            }
122            Self::CAndi { rd, imm } => {
123                let value = regs.read(rd) & i64::from(imm).cast_unsigned();
124                Ok(ControlFlow::Continue((rd, value)))
125            }
126            Self::CSub { rd, rs2: _ } => {
127                let value = regs.read(rd).wrapping_sub(rs2_value);
128                Ok(ControlFlow::Continue((rd, value)))
129            }
130            Self::CXor { rd, rs2: _ } => {
131                let value = regs.read(rd) ^ rs2_value;
132                Ok(ControlFlow::Continue((rd, value)))
133            }
134            Self::COr { rd, rs2: _ } => {
135                let value = regs.read(rd) | rs2_value;
136                Ok(ControlFlow::Continue((rd, value)))
137            }
138            Self::CAnd { rd, rs2: _ } => {
139                let value = regs.read(rd) & rs2_value;
140                Ok(ControlFlow::Continue((rd, value)))
141            }
142            Self::CSubw { rd, rs2: _ } => {
143                let diff = (regs.read(rd) as i32).wrapping_sub(rs2_value as i32);
144                Ok(ControlFlow::Continue((rd, i64::from(diff).cast_unsigned())))
145            }
146            Self::CAddw { rd, rs2: _ } => {
147                let sum = (regs.read(rd) as i32).wrapping_add(rs2_value as i32);
148                Ok(ControlFlow::Continue((rd, i64::from(sum).cast_unsigned())))
149            }
150            Self::CJ { imm } => {
151                let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
152                return program_counter
153                    .set_pc(memory, old_pc.wrapping_add(i64::from(imm).cast_unsigned()))
154                    .map(|control_flow| control_flow.map_continue(|()| Default::default()))
155                    .map_err(ExecutionError::from);
156            }
157            Self::CBeqz { rs1: _, imm } => {
158                if rs1_value == 0 {
159                    let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
160                    return program_counter
161                        .set_pc(memory, old_pc.wrapping_add(i64::from(imm).cast_unsigned()))
162                        .map(|control_flow| control_flow.map_continue(|()| Default::default()))
163                        .map_err(ExecutionError::from);
164                }
165
166                Ok(ControlFlow::Continue(Default::default()))
167            }
168            Self::CBnez { rs1: _, imm } => {
169                if rs1_value != 0 {
170                    let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
171                    return program_counter
172                        .set_pc(memory, old_pc.wrapping_add(i64::from(imm).cast_unsigned()))
173                        .map(|control_flow| control_flow.map_continue(|()| Default::default()))
174                        .map_err(ExecutionError::from);
175                }
176
177                Ok(ControlFlow::Continue(Default::default()))
178            }
179
180            // Quadrant 10
181            Self::CSlli { rd, shamt } => {
182                let value = regs.read(rd) << shamt;
183                Ok(ControlFlow::Continue((rd, value)))
184            }
185            Self::CLwsp { rd, uimm } => {
186                let addr = regs.read(Reg::SP).wrapping_add(u64::from(uimm));
187                let value = i64::from(memory.read::<i32>(addr)?);
188                Ok(ControlFlow::Continue((rd, value.cast_unsigned())))
189            }
190            Self::CLdsp { rd, uimm } => {
191                let addr = regs.read(Reg::SP).wrapping_add(u64::from(uimm));
192                let value = memory.read::<u64>(addr)?;
193                Ok(ControlFlow::Continue((rd, value)))
194            }
195            Self::CJr { rs1: _ } => {
196                let target = rs1_value & !1;
197                return program_counter
198                    .set_pc(memory, target)
199                    .map(|control_flow| control_flow.map_continue(|()| Default::default()))
200                    .map_err(ExecutionError::from);
201            }
202            Self::CMv { rd, rs2: _ } => Ok(ControlFlow::Continue((rd, rs2_value))),
203            Self::CEbreak => {
204                system_instruction_handler.handle_ebreak(regs, memory, program_counter.get_pc());
205                Ok(ControlFlow::Continue(Default::default()))
206            }
207            Self::CJalr { rs1: _ } => {
208                let target = rs1_value & !1;
209                let return_addr = program_counter.get_pc();
210                regs.write(Reg::RA, return_addr);
211                return program_counter
212                    .set_pc(memory, target)
213                    .map(|control_flow| control_flow.map_continue(|()| Default::default()))
214                    .map_err(ExecutionError::from);
215            }
216            Self::CAdd { rd, rs2: _ } => {
217                let value = regs.read(rd).wrapping_add(rs2_value);
218                Ok(ControlFlow::Continue((rd, value)))
219            }
220            Self::CSwsp { rs2: _, uimm } => {
221                let addr = regs.read(Reg::SP).wrapping_add(u64::from(uimm));
222                memory.write(addr, rs2_value as u32)?;
223                Ok(ControlFlow::Continue(Default::default()))
224            }
225            Self::CSdsp { rs2: _, uimm } => {
226                let addr = regs.read(Reg::SP).wrapping_add(u64::from(uimm));
227                memory.write(addr, rs2_value)?;
228                Ok(ControlFlow::Continue(Default::default()))
229            }
230            Self::CUnimp => {
231                let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
232                return Err(ExecutionError::IllegalInstruction { address: old_pc });
233            }
234        }
235    }
236}