1use std::num::{NonZeroU32, NonZeroU64};
2
3pub use irv_traits::*;
4
5mod instruction;
6mod memory;
7
8pub use memory::Memory;
9
10#[derive(Debug)]
16pub enum Exception {
17 InstructionAddressMisaligned { address: Option<NonZeroU64> },
18 InstructionAccessFault { address: Option<NonZeroU64> },
19 IllegalInstruction { instruction: Option<NonZeroU32> },
20 Breakpoint { address: Option<NonZeroU64> },
21 LoadAddressMisaligned { address: Option<NonZeroU64> },
22 LoadAccessFault { address: Option<NonZeroU64> },
23 StoreAmoAddressMisaligned { address: Option<NonZeroU64> },
24 StoreAmoAccessFault { address: Option<NonZeroU64> },
25 EnvironmentCall,
26}
27
28pub struct BaseHart<B, C> {
30 pub bus: B,
32 pub pc: u64,
34 pub next: u64,
36 pub gpr: [u64; 32],
38 pub csr: C,
40 result: Result<(), Exception>,
42}
43
44impl<B, C> BaseHart<B, C> {
45 pub fn new(bus: B, csr: C) -> BaseHart<B, C> {
47 BaseHart {
48 bus,
49 pc: 0,
50 next: 0,
51 gpr: [0; 32],
52 csr,
53 result: Ok(()),
54 }
55 }
56
57 pub fn execute(&mut self) -> Result<(), Exception>
63 where
64 B: Bus<u64, u64> + Bus<u64, u32> + Bus<u64, u16> + Bus<u64, u8>,
65 C: Csr,
66 {
67 let raw: u32 = match self.bus.load(self.pc) {
69 Ok(raw) => raw,
70 Err(BusError::AccessFault) => {
71 return Err(Exception::InstructionAccessFault {
72 address: NonZeroU64::new(self.pc),
73 })
74 }
75 Err(BusError::AddressMisaligned) => {
76 return Err(Exception::InstructionAddressMisaligned {
77 address: NonZeroU64::new(self.pc),
78 })
79 }
80 };
81
82 let funct3_opcode = raw & 0b1111111 | raw >> 5 & 0b111 << 7;
84
85 self.gpr[0] = 0;
87
88 self.next = self.pc.wrapping_add(4);
90
91 let instruction = match funct3_opcode {
94 0b000_0110111 | 0b001_0110111 | 0b010_0110111 | 0b011_0110111 | 0b100_0110111
95 | 0b101_0110111 | 0b110_0110111 | 0b111_0110111 => instruction::lui,
96 0b000_0010111 | 0b001_0010111 | 0b010_0010111 | 0b011_0010111 | 0b100_0010111
97 | 0b101_0010111 | 0b110_0010111 | 0b111_0010111 => instruction::auipc,
98 0b000_1101111 | 0b001_1101111 | 0b010_1101111 | 0b011_1101111 | 0b100_1101111
99 | 0b101_1101111 | 0b110_1101111 | 0b111_1101111 => instruction::jal,
100 0b000_1100111 => instruction::jalr,
101 0b000_1100011 => instruction::beq,
102 0b001_1100011 => instruction::bne,
103 0b100_1100011 => instruction::blt,
104 0b101_1100011 => instruction::bge,
105 0b110_1100011 => instruction::bltu,
106 0b111_1100011 => instruction::bgeu,
107 0b000_0000011 => instruction::lb,
108 0b001_0000011 => instruction::lh,
109 0b010_0000011 => instruction::lw,
110 0b011_0000011 => instruction::ld,
111 0b100_0000011 => instruction::lbu,
112 0b101_0000011 => instruction::lhu,
113 0b110_0000011 => instruction::lwu,
114 0b000_0100011 => instruction::sb,
115 0b001_0100011 => instruction::sh,
116 0b010_0100011 => instruction::sw,
117 0b011_0100011 => instruction::sd,
118 0b000_0010011 => instruction::addi,
119 0b000_0011011 => instruction::addiw,
120 0b010_0010011 => instruction::slti,
121 0b011_0010011 => instruction::sltiu,
122 0b100_0010011 => instruction::xori,
123 0b110_0010011 => instruction::ori,
124 0b111_0010011 => instruction::andi,
125 0b001_0010011 => instruction::slli,
126 0b101_0010011 => instruction::srxi,
127 0b001_0011011 => instruction::slliw,
128 0b101_0011011 => instruction::srxiw,
129 0b000_0110011 => instruction::add_sub,
130 0b000_0111011 => instruction::addw_subw,
131 0b001_0110011 => instruction::sll,
132 0b010_0110011 => instruction::slt,
133 0b011_0110011 => instruction::sltu,
134 0b100_0110011 => instruction::xor,
135 0b101_0110011 => instruction::srx,
136 0b110_0110011 => instruction::or,
137 0b111_0110011 => instruction::and,
138 0b001_0111011 => instruction::sllw,
139 0b101_0111011 => instruction::srxw,
140 0b000_0001111 => instruction::fence,
141 0b001_0001111 => instruction::fence_i,
142 0b000_1110011 => instruction::ecall_ebreak,
143 0b001_1110011 => instruction::csrrw,
144 0b010_1110011 => instruction::csrrs,
145 0b011_1110011 => instruction::csrrc,
146 0b101_1110011 => instruction::csrrwi,
147 0b110_1110011 => instruction::csrrsi,
148 0b111_1110011 => instruction::csrrci,
149 _ => |hart: &mut BaseHart<B, C>, raw| {
150 hart.raise(Exception::IllegalInstruction {
151 instruction: NonZeroU32::new(raw),
152 })
153 },
154 };
155
156 instruction(self, raw);
157
158 self.pc = self.next;
159
160 let mut result = Ok(());
161 std::mem::swap(&mut self.result, &mut result);
162 result
163 }
164
165 fn raise(&mut self, exception: Exception) {
167 self.result = Err(exception);
168 }
169}