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, 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 Rv32ZcaInstruction<Reg>
18where
19    Reg: Register<Type = u32>,
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(u32::from(nzuimm)));
39            }
40            Self::CLw { rd, rs1, uimm } => {
41                let addr = regs.read(rs1).wrapping_add(u32::from(uimm));
42                let value = memory.read::<i32>(u64::from(addr))?.cast_unsigned();
43                regs.write(rd, value);
44            }
45            Self::CSw { rs1, rs2, uimm } => {
46                let addr = regs.read(rs1).wrapping_add(u32::from(uimm));
47                memory.write(u64::from(addr), regs.read(rs2))?;
48            }
49
50            // Quadrant 01
51            Self::CNop => {}
52            Self::CAddi { rd, nzimm } => {
53                let value = regs.read(rd).wrapping_add(i32::from(nzimm).cast_unsigned());
54                regs.write(rd, value);
55            }
56            Self::CJal { imm } => {
57                let return_addr = program_counter.get_pc();
58                regs.write(Reg::RA, return_addr);
59                let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
60                return program_counter
61                    .set_pc(memory, old_pc.wrapping_add(i32::from(imm).cast_unsigned()))
62                    .map_err(ExecutionError::from);
63            }
64            Self::CLi { rd, imm } => {
65                regs.write(rd, i32::from(imm).cast_unsigned());
66            }
67            Self::CAddi16sp { nzimm } => {
68                let value = regs
69                    .read(Reg::SP)
70                    .wrapping_add(i32::from(nzimm).cast_unsigned());
71                regs.write(Reg::SP, value);
72            }
73            Self::CLui { rd, nzimm } => {
74                regs.write(rd, nzimm.cast_unsigned());
75            }
76            Self::CSrli { rd, shamt } => {
77                let value = regs.read(rd) >> shamt;
78                regs.write(rd, value);
79            }
80            Self::CSrai { rd, shamt } => {
81                let value = regs.read(rd).cast_signed() >> shamt;
82                regs.write(rd, value.cast_unsigned());
83            }
84            Self::CAndi { rd, imm } => {
85                let value = regs.read(rd) & i32::from(imm).cast_unsigned();
86                regs.write(rd, value);
87            }
88            Self::CSub { rd, rs2 } => {
89                let value = regs.read(rd).wrapping_sub(regs.read(rs2));
90                regs.write(rd, value);
91            }
92            Self::CXor { rd, rs2 } => {
93                let value = regs.read(rd) ^ regs.read(rs2);
94                regs.write(rd, value);
95            }
96            Self::COr { rd, rs2 } => {
97                let value = regs.read(rd) | regs.read(rs2);
98                regs.write(rd, value);
99            }
100            Self::CAnd { rd, rs2 } => {
101                let value = regs.read(rd) & regs.read(rs2);
102                regs.write(rd, value);
103            }
104            Self::CJ { imm } => {
105                let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
106                return program_counter
107                    .set_pc(memory, old_pc.wrapping_add(i32::from(imm).cast_unsigned()))
108                    .map_err(ExecutionError::from);
109            }
110            Self::CBeqz { rs1, imm } => {
111                if regs.read(rs1) == 0 {
112                    let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
113                    return program_counter
114                        .set_pc(memory, old_pc.wrapping_add(i32::from(imm).cast_unsigned()))
115                        .map_err(ExecutionError::from);
116                }
117            }
118            Self::CBnez { rs1, imm } => {
119                if regs.read(rs1) != 0 {
120                    let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
121                    return program_counter
122                        .set_pc(memory, old_pc.wrapping_add(i32::from(imm).cast_unsigned()))
123                        .map_err(ExecutionError::from);
124                }
125            }
126
127            // Quadrant 10
128            Self::CSlli { rd, shamt } => {
129                let value = regs.read(rd) << shamt;
130                regs.write(rd, value);
131            }
132            Self::CLwsp { rd, uimm } => {
133                let addr = regs.read(Reg::SP).wrapping_add(u32::from(uimm));
134                let value = memory.read::<i32>(u64::from(addr))?.cast_unsigned();
135                regs.write(rd, value);
136            }
137            Self::CJr { rs1 } => {
138                let target = regs.read(rs1) & !1;
139                return program_counter
140                    .set_pc(memory, target)
141                    .map_err(ExecutionError::from);
142            }
143            Self::CMv { rd, rs2 } => {
144                regs.write(rd, regs.read(rs2));
145            }
146            Self::CEbreak => {
147                system_instruction_handler.handle_ebreak(regs, memory, program_counter.get_pc());
148            }
149            Self::CJalr { rs1 } => {
150                let target = regs.read(rs1) & !1;
151                let return_addr = program_counter.get_pc();
152                regs.write(Reg::RA, return_addr);
153                return program_counter
154                    .set_pc(memory, target)
155                    .map_err(ExecutionError::from);
156            }
157            Self::CAdd { rd, rs2 } => {
158                let value = regs.read(rd).wrapping_add(regs.read(rs2));
159                regs.write(rd, value);
160            }
161            Self::CSwsp { rs2, uimm } => {
162                let addr = regs.read(Reg::SP).wrapping_add(u32::from(uimm));
163                memory.write(u64::from(addr), regs.read(rs2))?;
164            }
165            Self::CUnimp => {
166                let old_pc = program_counter.old_pc(size_of::<u16>() as u8);
167                return Err(ExecutionError::IllegalInstruction { address: old_pc });
168            }
169        }
170
171        Ok(ControlFlow::Continue(()))
172    }
173}