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