rrs_lib/
lib.rs

1// Copyright 2021 Gregory Chadwick <mail@gregchadwick.co.uk>
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5//! RISC-V instruction set simulator library
6//!
7//! Containts the building blocks for a RISC-V ISS. The seperate rrs-cli uses rrs-lib to implement
8//! a CLI driven ISS.
9
10pub mod instruction_executor;
11pub mod instruction_formats;
12pub mod instruction_string_outputter;
13pub mod memories;
14pub mod process_instruction;
15
16use downcast_rs::{impl_downcast, Downcast};
17
18pub use process_instruction::process_instruction;
19
20/// A trait for objects which do something with RISC-V instructions (e.g. execute them or print a
21/// disassembly string).
22///
23/// There is one function per RISC-V instruction. Each function takes the appropriate struct from
24/// [instruction_formats] giving access to the decoded fields of the instruction. All functions
25/// return the [InstructionProcessor::InstructionResult] associated type.
26pub trait InstructionProcessor {
27    type InstructionResult;
28
29    fn process_add(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
30    fn process_sub(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
31    fn process_sll(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
32    fn process_slt(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
33    fn process_sltu(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
34    fn process_xor(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
35    fn process_srl(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
36    fn process_sra(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
37    fn process_or(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
38    fn process_and(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
39
40    fn process_addi(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
41    fn process_slli(
42        &mut self,
43        dec_insn: instruction_formats::ITypeShamt,
44    ) -> Self::InstructionResult;
45    fn process_slti(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
46    fn process_sltui(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
47    fn process_xori(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
48    fn process_srli(
49        &mut self,
50        dec_insn: instruction_formats::ITypeShamt,
51    ) -> Self::InstructionResult;
52    fn process_srai(
53        &mut self,
54        dec_insn: instruction_formats::ITypeShamt,
55    ) -> Self::InstructionResult;
56    fn process_ori(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
57    fn process_andi(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
58
59    fn process_lui(&mut self, dec_insn: instruction_formats::UType) -> Self::InstructionResult;
60    fn process_auipc(&mut self, dec_insn: instruction_formats::UType) -> Self::InstructionResult;
61
62    fn process_beq(&mut self, dec_insn: instruction_formats::BType) -> Self::InstructionResult;
63    fn process_bne(&mut self, dec_insn: instruction_formats::BType) -> Self::InstructionResult;
64    fn process_blt(&mut self, dec_insn: instruction_formats::BType) -> Self::InstructionResult;
65    fn process_bltu(&mut self, dec_insn: instruction_formats::BType) -> Self::InstructionResult;
66    fn process_bge(&mut self, dec_insn: instruction_formats::BType) -> Self::InstructionResult;
67    fn process_bgeu(&mut self, dec_insn: instruction_formats::BType) -> Self::InstructionResult;
68
69    fn process_lb(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
70    fn process_lbu(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
71    fn process_lh(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
72    fn process_lhu(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
73    fn process_lw(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
74
75    fn process_sb(&mut self, dec_insn: instruction_formats::SType) -> Self::InstructionResult;
76    fn process_sh(&mut self, dec_insn: instruction_formats::SType) -> Self::InstructionResult;
77    fn process_sw(&mut self, dec_insn: instruction_formats::SType) -> Self::InstructionResult;
78
79    fn process_jal(&mut self, dec_insn: instruction_formats::JType) -> Self::InstructionResult;
80    fn process_jalr(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
81
82    fn process_mul(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
83    fn process_mulh(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
84    fn process_mulhu(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
85    fn process_mulhsu(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
86
87    fn process_div(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
88    fn process_divu(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
89    fn process_rem(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
90    fn process_remu(&mut self, dec_insn: instruction_formats::RType) -> Self::InstructionResult;
91
92    fn process_fence(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult;
93}
94
95/// State of a single RISC-V hart (hardware thread)
96pub struct HartState {
97    /// x1 - x31 register values. The contents of index 0 (the x0 zero register) are ignored.
98    pub registers: [u32; 32],
99    /// Program counter
100    pub pc: u32,
101    /// Gives index of the last register written if one occurred in the previous instruciton. Set
102    /// to `None` if latest instruction did not write a register.
103    pub last_register_write: Option<usize>,
104}
105
106impl HartState {
107    pub fn new() -> Self {
108        HartState {
109            registers: [0; 32],
110            pc: 0,
111            last_register_write: None,
112        }
113    }
114
115    /// Write a register in the hart state. Used by executing instructions for correct zero
116    /// register handling
117    fn write_register(&mut self, reg_index: usize, data: u32) {
118        if reg_index == 0 {
119            return;
120        }
121
122        self.registers[reg_index] = data;
123        self.last_register_write = Some(reg_index)
124    }
125
126    /// Read a register from the hart state. Used by executing instructions for correct zero
127    /// register handling
128    fn read_register(&self, reg_index: usize) -> u32 {
129        if reg_index == 0 {
130            0
131        } else {
132            self.registers[reg_index]
133        }
134    }
135}
136
137impl Default for HartState {
138    fn default() -> Self {
139        Self::new()
140    }
141}
142
143/// The different sizes used for memory accesses
144#[derive(Clone, Copy)]
145pub enum MemAccessSize {
146    /// 8 bits
147    Byte,
148    /// 16 bits
149    HalfWord,
150    /// 32 bits
151    Word,
152}
153
154/// A trait for objects which implement memory operations
155pub trait Memory: Downcast {
156    /// Read `size` bytes from `addr`.
157    ///
158    /// `addr` must be aligned to `size`.
159    /// Returns `None` if `addr` doesn't exist in this memory.
160    fn read_mem(&mut self, addr: u32, size: MemAccessSize) -> Option<u32>;
161
162    /// Write `size` bytes of `store_data` to `addr`
163    ///
164    /// `addr` must be aligned to `size`.
165    /// Returns `true` if write succeeds.
166    fn write_mem(&mut self, addr: u32, size: MemAccessSize, store_data: u32) -> bool;
167}
168
169impl_downcast!(Memory);
170
171#[cfg(test)]
172mod tests {
173    use super::instruction_executor::{InstructionException, InstructionExecutor};
174    use super::instruction_string_outputter::InstructionStringOutputter;
175    use super::*;
176
177    #[test]
178    fn test_insn_execute() {
179        let mut hart = HartState::new();
180        let mut mem = memories::VecMemory::new(vec![
181            0x1234b137, 0xbcd10113, 0xf387e1b7, 0x3aa18193, 0xbed892b7, 0x7ac28293, 0x003100b3,
182            0xf4e0e213, 0x02120a63, 0x00121463, 0x1542c093, 0x00c0036f, 0x0020f0b3, 0x402080b3,
183            0x00000397, 0x02838393, 0x0003a403, 0x00638483, 0x0023d503, 0x00139223, 0x0043a583,
184            0x00000000, 0x00000000, 0x00000000, 0xdeadbeef, 0xbaadf00d,
185        ]);
186
187        hart.pc = 0;
188
189        // TODO: With the 'executor' concept we need to effectively create a new one each step as
190        // it's meant to be just taking a reference to things to execute, but then if we want to
191        // access those things we either do it via the executor or create a new one before the next
192        // step to allow access via the 'main' object, could just make step part of the 'main'
193        // object? Having the executor only coupled to a bare minimum of state could be good?
194        let mut executor = InstructionExecutor {
195            hart_state: &mut hart,
196            mem: &mut mem,
197        };
198
199        while executor.hart_state.pc != 0x54 {
200            let mut outputter = InstructionStringOutputter {
201                insn_pc: executor.hart_state.pc,
202            };
203            let insn_bits = executor
204                .mem
205                .read_mem(executor.hart_state.pc, MemAccessSize::Word)
206                .unwrap();
207
208            assert_eq!(executor.step(), Ok(()));
209
210            println!(
211                "{:x} {}",
212                executor.hart_state.pc,
213                process_instruction(&mut outputter, insn_bits).unwrap()
214            );
215            if let Some(reg_index) = executor.hart_state.last_register_write {
216                println!(
217                    "x{} = {:08x}",
218                    reg_index, executor.hart_state.registers[reg_index]
219                );
220            }
221        }
222
223        assert_eq!(executor.hart_state.registers[1], 0x05bc8f77);
224        assert_eq!(executor.hart_state.registers[2], 0x1234abcd);
225        assert_eq!(executor.hart_state.registers[3], 0xf387e3aa);
226        assert_eq!(executor.hart_state.registers[4], 0xffffff7f);
227        assert_eq!(executor.hart_state.registers[5], 0xbed897ac);
228        assert_eq!(executor.hart_state.registers[6], 0x00000030);
229        assert_eq!(executor.hart_state.registers[7], 0x00000060);
230        assert_eq!(executor.hart_state.registers[8], 0xdeadbeef);
231        assert_eq!(executor.hart_state.registers[9], 0xffffffad);
232        assert_eq!(executor.hart_state.registers[10], 0x0000dead);
233        assert_eq!(executor.hart_state.registers[11], 0xbaad8f77);
234
235        assert_eq!(
236            executor.step(),
237            Err(InstructionException::IllegalInstruction(0x54, 0))
238        );
239    }
240}