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 {

8-bit / 16-bit / 32-bit read instruction

29    fn read<const SIZE: u8>(&mut self, address: u32, cycle: MemoryCycle) -> u32;

16-bit (Thumb) / 32-bit (ARM) opcode fetch Implementations can override this to adjust behavior based on PC location or whether a read 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    }

8-bit / 16-bit / 32-bit write instruction

39    fn write<const SIZE: u8>(&mut self, address: u32, value: u32, cycle: MemoryCycle);

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    }

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    }

32-bit read instruction

52    fn read_word(&mut self, address: u32, cycle: MemoryCycle) -> u32 {
53        self.read::<{ OpSize::WORD }>(address, cycle)
54    }

Opcode fetch in Thumb mode 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    }

Opcode fetch in ARM mode 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    }

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    }

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    }

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    }

IRQ line

84    fn irq(&self) -> bool;

Called when instructions have internal cycles

87    fn internal_cycles(&mut self, cycles: u32);

Lock the bus (used by SWAP instruction)

90    fn lock(&mut self) {}

Unlock the bus (used by SWAP instruction)

93    fn unlock(&mut self) {}
94}