Bus

Trait Bus 

Source
pub trait Bus {
    // Required methods
    fn read(&mut self, addr: u16) -> u8;
    fn write(&mut self, addr: u16, value: u8);

    // Provided methods
    fn peek(&self, addr: u16) -> u8 { ... }
    fn read_u16(&mut self, addr: u16) -> u16 { ... }
    fn read_u16_wrap(&mut self, addr: u16) -> u16 { ... }
}
Expand description

Memory bus interface

Implementors of this trait provide memory access to the CPU. The CPU calls read() and write() for all memory operations.

§Examples

§Simple RAM-only bus

use rustynes_cpu::Bus;

struct SimpleBus {
    ram: [u8; 0x10000],
}

impl Bus for SimpleBus {
    fn read(&mut self, addr: u16) -> u8 {
        self.ram[addr as usize]
    }

    fn write(&mut self, addr: u16, value: u8) {
        self.ram[addr as usize] = value;
    }
}

§NES bus with memory-mapped I/O

use rustynes_cpu::Bus;

struct NesBus {
    ram: [u8; 0x800],
    ppu: Ppu,
    // ... other components
}

impl Bus for NesBus {
    fn read(&mut self, addr: u16) -> u8 {
        match addr {
            0x0000..=0x1FFF => {
                // 2KB internal RAM, mirrored 4 times
                self.ram[(addr & 0x07FF) as usize]
            }
            0x2000..=0x3FFF => {
                // PPU registers, mirrored every 8 bytes
                self.ppu.read_register(addr & 0x0007)
            }
            // ... other address ranges
            _ => 0,
        }
    }

    fn write(&mut self, addr: u16, value: u8) {
        match addr {
            0x0000..=0x1FFF => {
                self.ram[(addr & 0x07FF) as usize] = value;
            }
            0x2000..=0x3FFF => {
                self.ppu.write_register(addr & 0x0007, value);
            }
            // ... other address ranges
            _ => {}
        }
    }
}

Required Methods§

Source

fn read(&mut self, addr: u16) -> u8

Read a byte from memory

§Arguments
  • addr - 16-bit memory address to read from
§Returns

The 8-bit value at the specified address

§Notes
  • This function may have side effects (e.g., reading from a hardware register)
  • Open bus behavior: return last value on the bus for unmapped addresses
  • For debugging, implement peek() instead
Source

fn write(&mut self, addr: u16, value: u8)

Write a byte to memory

§Arguments
  • addr - 16-bit memory address to write to
  • value - 8-bit value to write
§Notes
  • This function may have side effects (e.g., triggering DMA)
  • Writes to ROM or unmapped areas should be ignored (or logged)

Provided Methods§

Source

fn peek(&self, addr: u16) -> u8

Read a byte without side effects (for debugging/disassembly)

Default implementation returns 0. Override for proper debugging support.

§Arguments
  • addr - 16-bit memory address to peek at
§Returns

The 8-bit value at the specified address, without triggering side effects

§Notes
  • This should NOT modify any state (e.g., don’t clear IRQ flags)
  • Used by debuggers and disassemblers
  • Default implementation returns 0 for simplicity
Source

fn read_u16(&mut self, addr: u16) -> u16

Read a 16-bit value in little-endian format

Reads two consecutive bytes and combines them into a 16-bit value.

§Arguments
  • addr - Address of the low byte
§Returns

16-bit value: (high << 8) | low

§Notes
  • Reads from addr (low byte) and addr + 1 (high byte)
  • Addition wraps: 0xFFFF + 1 = 0x0000
§Example
bus.write(0x1000, 0x34); // Low byte
bus.write(0x1001, 0x12); // High byte
assert_eq!(bus.read_u16(0x1000), 0x1234);
Source

fn read_u16_wrap(&mut self, addr: u16) -> u16

Read a 16-bit value with page wrap (for JMP indirect bug)

The 6502 has a bug in JMP indirect where if the low byte is $FF, the high byte is read from $xx00 instead of $(xx+1)00.

§Arguments
  • addr - Address of the low byte
§Returns

16-bit value with page-wrap behavior

§Example: JMP ($10FF) Bug
bus.write(0x10FF, 0x34); // Low byte at $10FF
bus.write(0x1100, 0x56); // Should be high byte (correct)
bus.write(0x1000, 0x12); // Actually read as high byte (bug!)

// Normal read would give 0x5634
assert_eq!(bus.read_u16(0x10FF), 0x5634);

// Page-wrap read gives 0x1234 (bug behavior)
assert_eq!(bus.read_u16_wrap(0x10FF), 0x1234);

Implementors§

Source§

impl<T: CpuBus> Bus for T

Blanket implementation: any CpuBus also implements Bus

This provides backward compatibility - code using the simpler Bus trait will continue to work. The CpuBus trait just adds the on_cpu_cycle() method.