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> ExecutableInstructionOperands for Rv32ZcaInstruction<Reg> where
18    Reg: Register<Type = u32>
19{
20}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32ZcaInstruction<Reg> where
24    Reg: Register<Type = u32>
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30    for Rv32ZcaInstruction<Reg>
31where
32    Reg: [const] Register<Type = u32>,
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(u32::from(nzuimm)),
58                }
59            }
60            Self::CLw { rd, rs1: _, uimm } => {
61                let addr = rs1_value.wrapping_add(u32::from(uimm));
62                let value = memory.read::<i32>(u64::from(addr))?.cast_unsigned();
63                ExecutionResult::Continue { rd, value }
64            }
65            Self::CSw {
66                rs1: _,
67                rs2: _,
68                uimm,
69            } => {
70                let addr = rs1_value.wrapping_add(u32::from(uimm));
71                memory.write(u64::from(addr), rs2_value)?;
72                ExecutionResult::ContinueNoWrite
73            }
74
75            // Quadrant 01
76            Self::CNop => ExecutionResult::ContinueNoWrite,
77            Self::CAddi { rd, nzimm } => {
78                let value = regs.read(rd).wrapping_add(i32::from(nzimm).cast_unsigned());
79                ExecutionResult::Continue { rd, value }
80            }
81            Self::CJal { imm } => {
82                let return_addr = program_counter.get_pc();
83                regs.write(Reg::RA, return_addr);
84                ExecutionResult::Branch {
85                    offset: i32::from(imm),
86                }
87            }
88            Self::CLi { rd, imm } => ExecutionResult::Continue {
89                rd,
90                value: i32::from(imm).cast_unsigned(),
91            },
92            Self::CAddi16sp { nzimm } => {
93                let value = regs
94                    .read(Reg::SP)
95                    .wrapping_add(i32::from(nzimm).cast_unsigned());
96                ExecutionResult::Continue { rd: Reg::SP, value }
97            }
98            Self::CLui { rd, nzimm } => ExecutionResult::Continue {
99                rd,
100                value: nzimm.to_i32().cast_unsigned(),
101            },
102            Self::CSrli { rd, shamt } => {
103                let value = regs.read(rd) >> shamt;
104                ExecutionResult::Continue { rd, value }
105            }
106            Self::CSrai { rd, shamt } => {
107                let value = regs.read(rd).cast_signed() >> shamt;
108                ExecutionResult::Continue {
109                    rd,
110                    value: value.cast_unsigned(),
111                }
112            }
113            Self::CAndi { rd, imm } => {
114                let value = regs.read(rd) & i32::from(imm).cast_unsigned();
115                ExecutionResult::Continue { rd, value }
116            }
117            Self::CSub { rd, rs2: _ } => {
118                let value = regs.read(rd).wrapping_sub(rs2_value);
119                ExecutionResult::Continue { rd, value }
120            }
121            Self::CXor { rd, rs2: _ } => {
122                let value = regs.read(rd) ^ rs2_value;
123                ExecutionResult::Continue { rd, value }
124            }
125            Self::COr { rd, rs2: _ } => {
126                let value = regs.read(rd) | rs2_value;
127                ExecutionResult::Continue { rd, value }
128            }
129            Self::CAnd { rd, rs2: _ } => {
130                let value = regs.read(rd) & rs2_value;
131                ExecutionResult::Continue { rd, value }
132            }
133            Self::CJ { imm } => ExecutionResult::Branch {
134                offset: i32::from(imm),
135            },
136            Self::CBeqz { rs1: _, imm } => {
137                if rs1_value == 0 {
138                    return ExecutionResult::Branch {
139                        offset: i32::from(imm),
140                    };
141                }
142
143                ExecutionResult::ContinueNoWrite
144            }
145            Self::CBnez { rs1: _, imm } => {
146                if rs1_value != 0 {
147                    return ExecutionResult::Branch {
148                        offset: i32::from(imm),
149                    };
150                }
151
152                ExecutionResult::ContinueNoWrite
153            }
154
155            // Quadrant 10
156            Self::CSlli { rd, shamt } => {
157                let value = regs.read(rd) << shamt;
158                ExecutionResult::Continue { rd, value }
159            }
160            Self::CLwsp { rd, uimm } => {
161                let addr = regs.read(Reg::SP).wrapping_add(u32::from(uimm));
162                let value = memory.read::<i32>(u64::from(addr))?.cast_unsigned();
163                ExecutionResult::Continue { rd, value }
164            }
165            Self::CJr { rs1: _ } => {
166                let target = rs1_value & !1;
167                ExecutionResult::Jump { target }
168            }
169            Self::CMv { rd, rs2: _ } => ExecutionResult::Continue {
170                rd,
171                value: rs2_value,
172            },
173            Self::CEbreak => {
174                env.handle_ebreak(regs, memory, program_counter.get_pc());
175                ExecutionResult::ContinueNoWrite
176            }
177            Self::CJalr { rs1: _ } => {
178                let target = rs1_value & !1;
179                let return_addr = program_counter.get_pc();
180                regs.write(Reg::RA, return_addr);
181                return ExecutionResult::Jump { target };
182            }
183            Self::CAdd { rd, rs2: _ } => {
184                let value = regs.read(rd).wrapping_add(rs2_value);
185                ExecutionResult::Continue { rd, value }
186            }
187            Self::CSwsp { rs2: _, uimm } => {
188                let addr = regs.read(Reg::SP).wrapping_add(u32::from(uimm));
189                memory.write(u64::from(addr), rs2_value)?;
190                ExecutionResult::ContinueNoWrite
191            }
192            Self::CUnimp => {
193                let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
194                ExecutionResult::Err(ExecutionError::IllegalInstruction {
195                    address: PackedAddress::new(old_pc),
196                })
197            }
198        }
199    }
200}