bus.rsannotatedbus.rssource94 lines · 3.0 KB · raw
1use bincode::{Decode, Encode};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
4pub enum MemoryCycle {
5    N, // Non-sequential
6    S, // Sequential
7}
8
9pub struct OpSize;
10
11impl OpSize {
12    pub const BYTE: u8 = 0;
13    pub const HALFWORD: u8 = 1;
14    pub const WORD: u8 = 2;
15
16    #[must_use]
17    pub const fn display(size: u8) -> &'static str {
18        match size {
19            Self::BYTE => "Byte",
20            Self::HALFWORD => "Halfword",
21            Self::WORD => "Word",
22            _ => "(invalid)",
23        }
24    }
25}
26
27pub trait BusInterface {
28    /// 8-bit / 16-bit / 32-bit read instruction
29    fn read<const SIZE: u8>(&mut self, address: u32, cycle: MemoryCycle) -> u32;
30
31    /// 16-bit (Thumb) / 32-bit (ARM) opcode fetch
32    /// Implementations can override this to adjust behavior based on PC location or whether a read
33    /// is for instruction fetch
34    fn fetch_opcode<const SIZE: u8>(&mut self, address: u32, cycle: MemoryCycle) -> u32 {
35        self.read::<SIZE>(address, cycle)
36    }
37
38    /// 8-bit / 16-bit / 32-bit write instruction
39    fn write<const SIZE: u8>(&mut self, address: u32, value: u32, cycle: MemoryCycle);
40
41    /// 8-bit read instruction
42    fn read_byte(&mut self, address: u32, cycle: MemoryCycle) -> u8 {
43        self.read::<{ OpSize::BYTE }>(address, cycle) as u8
44    }
45
46    /// 16-bit read instruction
47    fn read_halfword(&mut self, address: u32, cycle: MemoryCycle) -> u16 {
48        self.read::<{ OpSize::HALFWORD }>(address, cycle) as u16
49    }
50
51    /// 32-bit read instruction
52    fn read_word(&mut self, address: u32, cycle: MemoryCycle) -> u32 {
53        self.read::<{ OpSize::WORD }>(address, cycle)
54    }
55
56    /// Opcode fetch in Thumb mode
57    /// Implementations can override this to adjust behavior based on PC location
58    fn fetch_opcode_halfword(&mut self, address: u32, cycle: MemoryCycle) -> u16 {
59        self.fetch_opcode::<{ OpSize::HALFWORD }>(address, cycle) as u16
60    }
61
62    /// Opcode fetch in ARM mode
63    /// Implementations can override this to adjust behavior based on PC location
64    fn fetch_opcode_word(&mut self, address: u32, cycle: MemoryCycle) -> u32 {
65        self.fetch_opcode::<{ OpSize::WORD }>(address, cycle)
66    }
67
68    /// 8-bit write instruction
69    fn write_byte(&mut self, address: u32, value: u8, cycle: MemoryCycle) {
70        self.write::<{ OpSize::BYTE }>(address, value.into(), cycle);
71    }
72
73    /// 16-bit write instruction
74    fn write_halfword(&mut self, address: u32, value: u16, cycle: MemoryCycle) {
75        self.write::<{ OpSize::HALFWORD }>(address, value.into(), cycle);
76    }
77
78    /// 32-bit write instruction
79    fn write_word(&mut self, address: u32, value: u32, cycle: MemoryCycle) {
80        self.write::<{ OpSize::WORD }>(address, value, cycle);
81    }
82
83    /// IRQ line
84    fn irq(&self) -> bool;
85
86    /// Called when instructions have internal cycles
87    fn internal_cycles(&mut self, cycles: u32);
88
89    /// Lock the bus (used by SWAP instruction)
90    fn lock(&mut self) {}
91
92    /// Unlock the bus (used by SWAP instruction)
93    fn unlock(&mut self) {}
94}