gabbro/
bus.rs

1use crate::{
2    apu::Apu,
3    cartridge::Cartridge,
4    cpu::interrupts::InterruptControl,
5    joypad::JoypadController,
6    peripherals::{Cable, Joypad, Lcd, Speaker},
7    ppu::Ppu,
8    serial::SerialController,
9    timer::Timer,
10};
11
12/// The bus which handles all reads and writes from/to memory.
13/// Also used to access all parts of the Game Boy besides the CPU.
14pub struct Bus<L, S, J, C>
15where
16    L: Lcd,
17    S: Speaker,
18    J: Joypad,
19    C: Cable,
20{
21    cart: Cartridge,
22    ram: [u8; 0x2000],
23    hram: [u8; 0x7f],
24    joypad: JoypadController<J>,
25    serial: SerialController<C>,
26    timer: Timer,
27    apu: Apu<S>,
28    ppu: Ppu<L>,
29    pub interrupts: InterruptControl,
30}
31
32impl<L, S, J, C> Bus<L, S, J, C>
33where
34    L: Lcd,
35    S: Speaker,
36    J: Joypad,
37    C: Cable,
38{
39    /// Initializes all the emulated hardware and the memory of the Game Boy.
40    /// Also prints information contained in the ROM header.
41    pub fn new(rom: Vec<u8>, lcd: L, speaker: S, joypad: J, cable: C) -> Self {
42        let cart = Cartridge::new(rom)
43            .map_err(|e| log::error!("Failed to parse ROM header: {}", e))
44            .unwrap();
45        cart.log_header();
46        Self {
47            cart,
48            ram: [0; 0x2000],
49            hram: [0; 0x7f],
50            joypad: JoypadController::new(joypad),
51            serial: SerialController::new(cable),
52            timer: Timer::new(),
53            apu: Apu::new(speaker),
54            ppu: Ppu::new(lcd),
55            interrupts: InterruptControl::new(),
56        }
57    }
58
59    /// Reads a value from the memory mapped at `addr`.
60    pub fn read(&self, addr: u16) -> u8 {
61        match addr {
62            // ROM
63            0x0000..=0x7fff => self.cart.mbc.read_rom(addr),
64            // Video RAM
65            0x8000..=0x9fff => self.ppu.fetcher.vram.read(addr - 0x8000),
66            // External Working RAM
67            0xa000..=0xbfff => self.cart.mbc.read_ram(addr - 0xa000),
68            // Working RAM (+ Echo)
69            0xc000..=0xdfff => self.ram[addr as usize - 0xc000],
70            0xe000..=0xfdff => {
71                log::debug!("Read from echo RAM at address {:#06x}", addr);
72                self.ram[addr as usize - 0xe000]
73            }
74            // Object Attribute Memory
75            0xfe00..=0xfe9f => self.ppu.fetcher.oam.read(addr - 0xfe00),
76            // IO Registers
77            // Joypad
78            0xff00 => self.joypad.p1.byte(),
79            // Serial
80            0xff01 => self.serial.sb,
81            0xff02 => self.serial.sc,
82            // Timer
83            0xff04 => (self.timer.div >> 8) as u8,
84            0xff05 => self.timer.tima,
85            0xff06 => self.timer.tma,
86            0xff07 => self.timer.tac.byte(),
87            // APU
88            0xff10..=0xff3f => self.apu.read(addr),
89            // PPU
90            0xff40 => self.ppu.fetcher.lcdc.byte(),
91            0xff41 => self.ppu.stat.byte(),
92            0xff42 => self.ppu.fetcher.scy,
93            0xff43 => self.ppu.fetcher.scx,
94            0xff44 => self.ppu.fetcher.ly,
95            0xff45 => self.ppu.lyc,
96            0xff46 => 0xff,
97            0xff47 => self.ppu.fetcher.bgp.byte(),
98            0xff48 => self.ppu.fetcher.obp0.byte(),
99            0xff49 => self.ppu.fetcher.obp1.byte(),
100            0xff4a => self.ppu.fetcher.wy,
101            0xff4b => self.ppu.fetcher.wx,
102            // High RAM
103            0xff80..=0xfffe => self.hram[addr as usize - 0xff80],
104            // Interrupts
105            0xff0f => self.interrupts.flags.byte(),
106            0xffff => self.interrupts.enable.byte(),
107            _ => {
108                log::debug!("Read from unmapped address {:#06x}", addr);
109                0xff
110            }
111        }
112    }
113
114    /// Writes the value `val` to the memory mapped at `addr`.
115    pub fn write(&mut self, addr: u16, val: u8) {
116        match addr {
117            // ROM
118            0x0000..=0x7fff => self.cart.mbc.write_rom(addr, val),
119            // Video RAM
120            0x8000..=0x9fff => self.ppu.fetcher.vram.write(addr - 0x8000, val),
121            // External Working RAM
122            0xa000..=0xbfff => self.cart.mbc.write_ram(addr - 0xa000, val),
123            // Working RAM (+ Echo)
124            0xc000..=0xdfff => self.ram[addr as usize - 0xc000] = val,
125            0xe000..=0xfdff => {
126                self.ram[addr as usize - 0xe000] = val;
127                log::debug!("Write to echo RAM at address {:#06x}", addr);
128            }
129            // Object Attribute Memory
130            0xfe00..=0xfe9f => self.ppu.fetcher.oam.write(addr - 0xfe00, val),
131            // IO Registers
132            // Joypad
133            0xff00 => self.joypad.p1.set_byte(val),
134            // Serial
135            0xff01 => self.serial.sb = val,
136            0xff02 => self.serial.sc = val,
137            // Timer
138            0xff04 => self.timer.div = 0,
139            0xff05 => self.timer.tima = val,
140            0xff06 => self.timer.tma = val,
141            0xff07 => self.timer.tac.set_byte(val),
142            // APU
143            0xff10..=0xff3f => self.apu.write(addr, val),
144            // PPU
145            0xff40 => self.ppu.fetcher.lcdc.set_byte(val),
146            0xff41 => self.ppu.stat.set_byte(val),
147            0xff42 => self.ppu.fetcher.scy = val,
148            0xff43 => self.ppu.fetcher.scx = val,
149            0xff44 => self.ppu.fetcher.ly = val,
150            0xff45 => self.ppu.lyc = val,
151            0xff46 => self.ppu.dma.start(val),
152            0xff47 => self.ppu.fetcher.bgp.set_byte(val),
153            0xff48 => self.ppu.fetcher.obp0.set_byte(val),
154            0xff49 => self.ppu.fetcher.obp1.set_byte(val),
155            0xff4a => self.ppu.fetcher.wy = val,
156            0xff4b => self.ppu.fetcher.wx = val,
157            // High RAM
158            0xff80..=0xfffe => self.hram[addr as usize - 0xff80] = val,
159            // Interrupts
160            0xff0f => self.interrupts.flags.set_byte(val),
161            0xffff => self.interrupts.enable.set_byte(val),
162            _ => log::debug!("Write to unmapped address {:#06x}", addr),
163        }
164    }
165
166    /// Emulates a machine cycle for all parts of the Game Boy that are stored in the [`Bus`].
167    /// This does not include the CPU.
168    pub fn io_step(&mut self) {
169        self.dma_step();
170
171        let ints = &mut self.interrupts.flags;
172        self.joypad.step(ints);
173        self.ppu.step(ints);
174        self.apu.step();
175        self.serial.step(ints);
176        self.timer.step(ints);
177    }
178
179    /// Performs a step of the Direct Memory Access feature of the PPU when active.
180    fn dma_step(&mut self) {
181        if self.ppu.dma.active {
182            let val = self.read(self.ppu.dma.src());
183            self.write(self.ppu.dma.dst(), val);
184            self.ppu.dma.step();
185        }
186    }
187}