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