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