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}