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