chore: restrict what should be pub or not
This commit is contained in:
parent
878edd4082
commit
ef4e54aba6
62
src/bus.rs
62
src/bus.rs
|
@ -1,13 +1,13 @@
|
||||||
use super::cartridge::Cartridge;
|
use crate::cartridge::Cartridge;
|
||||||
use super::high_ram::HighRam;
|
use crate::high_ram::HighRam;
|
||||||
use super::instruction::Cycle;
|
use crate::instruction::Cycle;
|
||||||
use super::interrupt::{Interrupt, InterruptFlag};
|
use crate::interrupt::{Interrupt, InterruptFlag};
|
||||||
use super::joypad::Joypad;
|
use crate::joypad::Joypad;
|
||||||
use super::ppu::{Ppu, PpuMode};
|
use crate::ppu::{Ppu, PpuMode};
|
||||||
use super::serial::Serial;
|
use crate::serial::Serial;
|
||||||
use super::sound::Sound;
|
use crate::sound::Sound;
|
||||||
use super::timer::Timer;
|
use crate::timer::Timer;
|
||||||
use super::work_ram::{VariableWorkRam, WorkRam};
|
use crate::work_ram::{VariableWorkRam, WorkRam};
|
||||||
use std::{fs::File, io::Read};
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
const BOOT_ROM_SIZE: usize = 0x100;
|
const BOOT_ROM_SIZE: usize = 0x100;
|
||||||
|
@ -73,14 +73,27 @@ impl Bus {
|
||||||
self.timer.step(cycles);
|
self.timer.step(cycles);
|
||||||
self.sound.step(cycles);
|
self.sound.step(cycles);
|
||||||
}
|
}
|
||||||
|
pub(crate) fn step_dma(&mut self, pending: Cycle) {
|
||||||
|
let pending_cycles: u32 = pending.into();
|
||||||
|
|
||||||
|
for _ in 0..pending_cycles {
|
||||||
|
match self.ppu.dma.clock() {
|
||||||
|
Some((src_addr, dest_addr)) => {
|
||||||
|
let byte = self.read_byte(src_addr);
|
||||||
|
self.write_byte(dest_addr, byte);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn timer(&self) -> Timer {
|
pub(crate) fn timer(&self) -> Timer {
|
||||||
self.timer
|
self.timer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
impl BusIo for Bus {
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
match addr {
|
match addr {
|
||||||
0x0000..=0x3FFF => {
|
0x0000..=0x3FFF => {
|
||||||
// 16KB ROM bank 00
|
// 16KB ROM bank 00
|
||||||
|
@ -193,7 +206,7 @@ impl Bus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
match addr {
|
match addr {
|
||||||
0x0000..=0x3FFF => {
|
0x0000..=0x3FFF => {
|
||||||
// 16KB ROM bank 00
|
// 16KB ROM bank 00
|
||||||
|
@ -322,7 +335,9 @@ impl Bus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bus {
|
||||||
pub(crate) fn read_word(&self, addr: u16) -> u16 {
|
pub(crate) fn read_word(&self, addr: u16) -> u16 {
|
||||||
(self.read_byte(addr + 1) as u16) << 8 | self.read_byte(addr) as u16
|
(self.read_byte(addr + 1) as u16) << 8 | self.read_byte(addr) as u16
|
||||||
}
|
}
|
||||||
|
@ -375,24 +390,9 @@ impl Bus {
|
||||||
// Update the Timer's instance of the following interrupts
|
// Update the Timer's instance of the following interrupts
|
||||||
self.timer.set_interrupt(timer);
|
self.timer.set_interrupt(timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn boot_enabled(&self) -> bool {
|
|
||||||
self.boot.is_some()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
pub(crate) trait BusIo {
|
||||||
pub(crate) fn step_dma(&mut self, pending: Cycle) {
|
fn read_byte(&self, addr: u16) -> u8;
|
||||||
let pending_cycles: u32 = pending.into();
|
fn write_byte(&mut self, addr: u16, byte: u8);
|
||||||
|
|
||||||
for _ in 0..pending_cycles {
|
|
||||||
match self.ppu.dma.clock() {
|
|
||||||
Some((src_addr, dest_addr)) => {
|
|
||||||
let byte = self.read_byte(src_addr);
|
|
||||||
self.write_byte(dest_addr, byte);
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ use std::fs::File;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::bus::BusIo;
|
||||||
|
|
||||||
const RAM_SIZE_ADDRESS: usize = 0x0149;
|
const RAM_SIZE_ADDRESS: usize = 0x0149;
|
||||||
const ROM_SIZE_ADDRESS: usize = 0x0148;
|
const ROM_SIZE_ADDRESS: usize = 0x0148;
|
||||||
const MBC_TYPE_ADDRESS: usize = 0x0147;
|
const MBC_TYPE_ADDRESS: usize = 0x0147;
|
||||||
|
@ -86,8 +88,8 @@ impl Cartridge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cartridge {
|
impl BusIo for Cartridge {
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
use MbcResult::*;
|
use MbcResult::*;
|
||||||
|
|
||||||
match self.mbc.handle_read(addr) {
|
match self.mbc.handle_read(addr) {
|
||||||
|
@ -95,18 +97,10 @@ impl Cartridge {
|
||||||
Value(byte) => byte,
|
Value(byte) => byte,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
|
||||||
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
self.mbc.handle_write(addr, byte);
|
self.mbc.handle_write(addr, byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_word(&self, addr: u16) -> u16 {
|
|
||||||
(self.read_byte(addr + 1) as u16) << 8 | self.read_byte(addr) as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn write_word(&mut self, addr: u16, word: u16) {
|
|
||||||
self.write_byte(addr + 1, (word >> 8) as u8);
|
|
||||||
self.write_byte(addr, (word & 0x00FF) as u8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
|
@ -294,7 +288,7 @@ enum RamSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RamSize {
|
impl RamSize {
|
||||||
pub(crate) fn as_byte_count(&self) -> u32 {
|
fn as_byte_count(&self) -> u32 {
|
||||||
use RamSize::*;
|
use RamSize::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -354,7 +348,7 @@ impl Default for BankCount {
|
||||||
|
|
||||||
impl BankCount {
|
impl BankCount {
|
||||||
// https://hacktix.github.io/GBEDG/mbcs/#rom-size
|
// https://hacktix.github.io/GBEDG/mbcs/#rom-size
|
||||||
pub(crate) fn to_byte_count(self) -> u32 {
|
fn to_byte_count(self) -> u32 {
|
||||||
use BankCount::*;
|
use BankCount::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
79
src/cpu.rs
79
src/cpu.rs
|
@ -1,7 +1,7 @@
|
||||||
use super::bus::Bus;
|
use crate::bus::{Bus, BusIo};
|
||||||
use super::instruction::{Cycle, Instruction};
|
use crate::instruction::{Cycle, Instruction};
|
||||||
use super::interrupt::{InterruptEnable, InterruptFlag};
|
use crate::interrupt::{InterruptEnable, InterruptFlag};
|
||||||
use super::ppu::Ppu;
|
use crate::ppu::Ppu;
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
|
||||||
|
@ -62,10 +62,16 @@ impl Cpu {
|
||||||
self.halted
|
self.halted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
pub(crate) fn inc_pc(&mut self) {
|
pub(crate) fn inc_pc(&mut self) {
|
||||||
self.reg.pc += 1;
|
self.reg.pc += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
|
fn inc_pc(&mut self) {
|
||||||
|
self.reg.pc += 1;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_cartridge(&mut self, path: &str) -> std::io::Result<()> {
|
pub fn load_cartridge(&mut self, path: &str) -> std::io::Result<()> {
|
||||||
self.bus.load_cartridge(path)
|
self.bus.load_cartridge(path)
|
||||||
}
|
}
|
||||||
|
@ -76,15 +82,27 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
pub(crate) fn fetch(&self) -> u8 {
|
pub(crate) fn fetch(&self) -> u8 {
|
||||||
self.bus.read_byte(self.reg.pc)
|
self.bus.read_byte(self.reg.pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
|
fn fetch(&self) -> u8 {
|
||||||
|
self.bus.read_byte(self.reg.pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
pub(crate) fn decode(&mut self, opcode: u8) -> Instruction {
|
pub(crate) fn decode(&mut self, opcode: u8) -> Instruction {
|
||||||
Instruction::from_byte(self, opcode)
|
Instruction::from_byte(self, opcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn execute(&mut self, instruction: Instruction) -> Cycle {
|
#[cfg(not(feature = "debug"))]
|
||||||
|
pub(crate) fn decode(&mut self, opcode: u8) -> Instruction {
|
||||||
|
Instruction::from_byte(self, opcode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&mut self, instruction: Instruction) -> Cycle {
|
||||||
Instruction::execute(self, instruction)
|
Instruction::execute(self, instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +145,16 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BusIo for Cpu {
|
||||||
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
|
self.bus.read_byte(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
|
self.bus.write_byte(addr, byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
pub(crate) fn read_imm_byte(&mut self, addr: u16) -> u8 {
|
pub(crate) fn read_imm_byte(&mut self, addr: u16) -> u8 {
|
||||||
self.inc_pc(); // NB: the addr read in the line below will be equal to PC - 1 after this function call
|
self.inc_pc(); // NB: the addr read in the line below will be equal to PC - 1 after this function call
|
||||||
|
@ -139,18 +167,6 @@ impl Cpu {
|
||||||
self.bus.read_word(addr)
|
self.bus.read_word(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
|
||||||
self.bus.read_byte(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
|
||||||
self.bus.write_byte(addr, byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn read_word(&mut self, addr: u16) -> u16 {
|
|
||||||
self.bus.read_word(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn write_word(&mut self, addr: u16, word: u16) {
|
pub(crate) fn write_word(&mut self, addr: u16, word: u16) {
|
||||||
self.bus.write_word(addr, word)
|
self.bus.write_word(addr, word)
|
||||||
}
|
}
|
||||||
|
@ -290,6 +306,21 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub fn register_pair(&self, pair: RegisterPair) -> u16 {
|
||||||
|
use RegisterPair::*;
|
||||||
|
|
||||||
|
match pair {
|
||||||
|
AF => (self.reg.a as u16) << 8 | u8::from(self.flags) as u16,
|
||||||
|
BC => (self.reg.b as u16) << 8 | self.reg.c as u16,
|
||||||
|
DE => (self.reg.d as u16) << 8 | self.reg.e as u16,
|
||||||
|
HL => (self.reg.h as u16) << 8 | self.reg.l as u16,
|
||||||
|
SP => self.reg.sp,
|
||||||
|
PC => self.reg.pc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
pub(crate) fn register_pair(&self, pair: RegisterPair) -> u16 {
|
pub(crate) fn register_pair(&self, pair: RegisterPair) -> u16 {
|
||||||
use RegisterPair::*;
|
use RegisterPair::*;
|
||||||
|
|
||||||
|
@ -341,7 +372,7 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
pub(crate) fn log_state(&self, mut writer: impl std::io::Write) -> std::io::Result<()> {
|
fn _log_state(&self, mut writer: impl std::io::Write) -> std::io::Result<()> {
|
||||||
write!(writer, "A: {:02X} ", self.reg.a)?;
|
write!(writer, "A: {:02X} ", self.reg.a)?;
|
||||||
write!(writer, "F: {:02X} ", u8::from(self.flags))?;
|
write!(writer, "F: {:02X} ", u8::from(self.flags))?;
|
||||||
write!(writer, "B: {:02X} ", self.reg.b)?;
|
write!(writer, "B: {:02X} ", self.reg.b)?;
|
||||||
|
@ -374,6 +405,18 @@ pub(crate) enum Register {
|
||||||
Flag,
|
Flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum RegisterPair {
|
||||||
|
AF,
|
||||||
|
BC,
|
||||||
|
DE,
|
||||||
|
HL,
|
||||||
|
SP,
|
||||||
|
PC,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(crate) enum RegisterPair {
|
pub(crate) enum RegisterPair {
|
||||||
AF,
|
AF,
|
||||||
|
|
13
src/gui.rs
13
src/gui.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::bus::BusIo;
|
||||||
use crate::cpu::Register;
|
use crate::cpu::Register;
|
||||||
use crate::cpu::RegisterPair;
|
use crate::cpu::RegisterPair;
|
||||||
use crate::LR35902;
|
use crate::LR35902;
|
||||||
|
@ -19,7 +20,7 @@ pub struct Egui {
|
||||||
render_pass: RenderPass,
|
render_pass: RenderPass,
|
||||||
paint_jobs: Vec<ClippedMesh>,
|
paint_jobs: Vec<ClippedMesh>,
|
||||||
|
|
||||||
pub(crate) config: Configuration,
|
pub config: Configuration,
|
||||||
|
|
||||||
show_flags: bool,
|
show_flags: bool,
|
||||||
show_cpu_info: bool,
|
show_cpu_info: bool,
|
||||||
|
@ -30,7 +31,7 @@ pub struct Egui {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
show_disasm: bool,
|
show_disasm: bool,
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
pub(crate) break_point: Option<u16>,
|
pub break_point: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Egui {
|
impl Egui {
|
||||||
|
@ -320,9 +321,9 @@ impl Egui {
|
||||||
let mut spacebar_step = self.config.spacebar_step;
|
let mut spacebar_step = self.config.spacebar_step;
|
||||||
egui::Window::new("Configuration")
|
egui::Window::new("Configuration")
|
||||||
.open(&mut self.config.show)
|
.open(&mut self.config.show)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |_ui| {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
ui.horizontal(|ui| {
|
_ui.horizontal(|ui| {
|
||||||
ui.label("Spacebar Steps");
|
ui.label("Spacebar Steps");
|
||||||
ui.add(egui::Slider::u16(&mut spacebar_step, 0..=std::u16::MAX));
|
ui.add(egui::Slider::u16(&mut spacebar_step, 0..=std::u16::MAX));
|
||||||
});
|
});
|
||||||
|
@ -367,14 +368,14 @@ impl Egui {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Configuration {
|
pub struct Configuration {
|
||||||
/// Show Configuration egui menu
|
/// Show Configuration egui menu
|
||||||
show: bool,
|
show: bool,
|
||||||
|
|
||||||
/// How many [`LR35902`] .step() do we want to do at once
|
/// How many [`LR35902`] .step() do we want to do at once
|
||||||
/// when pressing the spacebar key?
|
/// when pressing the spacebar key?
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
pub(crate) spacebar_step: u16,
|
pub spacebar_step: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Configuration {
|
impl Default for Configuration {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::bus::BusIo;
|
||||||
|
|
||||||
const HIGH_RAM_SIZE: usize = 0x7F;
|
const HIGH_RAM_SIZE: usize = 0x7F;
|
||||||
const HIGH_RAM_START_ADDRESS: usize = 0xFF80;
|
const HIGH_RAM_START_ADDRESS: usize = 0xFF80;
|
||||||
|
|
||||||
|
@ -14,12 +16,12 @@ impl Default for HighRam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HighRam {
|
impl BusIo for HighRam {
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
self.buf[addr as usize - HIGH_RAM_START_ADDRESS] = byte;
|
self.buf[addr as usize - HIGH_RAM_START_ADDRESS] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
self.buf[addr as usize - HIGH_RAM_START_ADDRESS]
|
self.buf[addr as usize - HIGH_RAM_START_ADDRESS]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::cpu::{Cpu, Flags, HaltState, ImeState, Register, RegisterPair};
|
use crate::bus::BusIo;
|
||||||
|
use crate::cpu::{Cpu, Flags, HaltState, ImeState, Register, RegisterPair};
|
||||||
use std::{convert::TryFrom, fmt::Debug};
|
use std::{convert::TryFrom, fmt::Debug};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -1911,7 +1912,7 @@ impl TryFrom<InstrRegister> for Register {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
pub(crate) fn r(index: u8) -> InstrRegister {
|
fn r(index: u8) -> InstrRegister {
|
||||||
match index {
|
match index {
|
||||||
0 => InstrRegister::B,
|
0 => InstrRegister::B,
|
||||||
1 => InstrRegister::C,
|
1 => InstrRegister::C,
|
||||||
|
@ -1925,7 +1926,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rp2(index: u8) -> RegisterPair {
|
fn rp2(index: u8) -> RegisterPair {
|
||||||
match index {
|
match index {
|
||||||
0 => RegisterPair::BC,
|
0 => RegisterPair::BC,
|
||||||
1 => RegisterPair::DE,
|
1 => RegisterPair::DE,
|
||||||
|
@ -1935,7 +1936,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rp(index: u8) -> RegisterPair {
|
fn rp(index: u8) -> RegisterPair {
|
||||||
match index {
|
match index {
|
||||||
0 => RegisterPair::BC,
|
0 => RegisterPair::BC,
|
||||||
1 => RegisterPair::DE,
|
1 => RegisterPair::DE,
|
||||||
|
@ -1945,7 +1946,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn cc(index: u8) -> JumpCondition {
|
fn cc(index: u8) -> JumpCondition {
|
||||||
match index {
|
match index {
|
||||||
0 => JumpCondition::NotZero,
|
0 => JumpCondition::NotZero,
|
||||||
1 => JumpCondition::Zero,
|
1 => JumpCondition::Zero,
|
||||||
|
@ -1955,7 +1956,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn x2_alu(index: u8, r_index: u8) -> Instruction {
|
fn x2_alu(index: u8, r_index: u8) -> Instruction {
|
||||||
match index {
|
match index {
|
||||||
0 => Instruction::ADD(
|
0 => Instruction::ADD(
|
||||||
// ADD A, r[z]
|
// ADD A, r[z]
|
||||||
|
@ -1973,7 +1974,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn x3_alu(index: u8, n: u8) -> Instruction {
|
fn x3_alu(index: u8, n: u8) -> Instruction {
|
||||||
match index {
|
match index {
|
||||||
0 => Instruction::ADD(
|
0 => Instruction::ADD(
|
||||||
// ADD A, n
|
// ADD A, n
|
||||||
|
@ -1991,7 +1992,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rot(index: u8, r_index: u8) -> Instruction {
|
fn rot(index: u8, r_index: u8) -> Instruction {
|
||||||
match index {
|
match index {
|
||||||
0 => Instruction::RLC(Self::r(r_index)), // RLC r[z]
|
0 => Instruction::RLC(Self::r(r_index)), // RLC r[z]
|
||||||
1 => Instruction::RRC(Self::r(r_index)), // RRC r[z]
|
1 => Instruction::RRC(Self::r(r_index)), // RRC r[z]
|
||||||
|
@ -2275,13 +2276,13 @@ impl From<Cycle> for u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstrRegisterPair {
|
impl InstrRegisterPair {
|
||||||
pub(crate) fn to_register_pair(self) -> RegisterPair {
|
fn to_register_pair(self) -> RegisterPair {
|
||||||
RegisterPair::try_from(self).expect("Failed to convert InstrRegisterPair to RegisterPair")
|
RegisterPair::try_from(self).expect("Failed to convert InstrRegisterPair to RegisterPair")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstrRegister {
|
impl InstrRegister {
|
||||||
pub(crate) fn to_register(self) -> Register {
|
fn to_register(self) -> Register {
|
||||||
Register::try_from(self).expect("Failed to convert from InstrRegister to Register")
|
Register::try_from(self).expect("Failed to convert from InstrRegister to Register")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
83
src/ppu.rs
83
src/ppu.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::bus::BusIo;
|
||||||
use crate::Cycle;
|
use crate::Cycle;
|
||||||
use crate::GB_HEIGHT;
|
use crate::GB_HEIGHT;
|
||||||
use crate::GB_WIDTH;
|
use crate::GB_WIDTH;
|
||||||
|
@ -10,7 +11,7 @@ use types::{
|
||||||
ObjectPaletteId, ObjectSize, Pixels, RenderPriority, TileDataAddress,
|
ObjectPaletteId, ObjectSize, Pixels, RenderPriority, TileDataAddress,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) mod dma;
|
mod dma;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
const VRAM_SIZE: usize = 0x2000;
|
const VRAM_SIZE: usize = 0x2000;
|
||||||
|
@ -38,7 +39,7 @@ pub struct Ppu {
|
||||||
pub(crate) control: LCDControl,
|
pub(crate) control: LCDControl,
|
||||||
pub(crate) monochrome: Monochrome,
|
pub(crate) monochrome: Monochrome,
|
||||||
pub(crate) pos: ScreenPosition,
|
pub(crate) pos: ScreenPosition,
|
||||||
pub(crate) vram: Box<[u8; VRAM_SIZE]>,
|
vram: Box<[u8; VRAM_SIZE]>,
|
||||||
pub(crate) stat: LCDStatus,
|
pub(crate) stat: LCDStatus,
|
||||||
pub(crate) oam: ObjectAttributeTable,
|
pub(crate) oam: ObjectAttributeTable,
|
||||||
pub(crate) dma: DmaProcess,
|
pub(crate) dma: DmaProcess,
|
||||||
|
@ -52,12 +53,12 @@ pub struct Ppu {
|
||||||
cycle: Cycle,
|
cycle: Cycle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ppu {
|
impl BusIo for Ppu {
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
self.vram[addr as usize - PPU_START_ADDRESS]
|
self.vram[addr as usize - PPU_START_ADDRESS]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
self.vram[addr as usize - PPU_START_ADDRESS] = byte;
|
self.vram[addr as usize - PPU_START_ADDRESS] = byte;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,18 +505,20 @@ pub(crate) struct ObjectAttributeTable {
|
||||||
buf: Box<[u8; OAM_SIZE]>,
|
buf: Box<[u8; OAM_SIZE]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectAttributeTable {
|
impl BusIo for ObjectAttributeTable {
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
let index = (addr - 0xFE00) as usize;
|
let index = (addr - 0xFE00) as usize;
|
||||||
self.buf[index]
|
self.buf[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
let index = (addr - 0xFE00) as usize;
|
let index = (addr - 0xFE00) as usize;
|
||||||
self.buf[index] = byte;
|
self.buf[index] = byte;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn attribute(&self, index: usize) -> ObjectAttribute {
|
impl ObjectAttributeTable {
|
||||||
|
fn attribute(&self, index: usize) -> ObjectAttribute {
|
||||||
let start = index * 4;
|
let start = index * 4;
|
||||||
|
|
||||||
let slice: &[u8; 4] = self.buf[start..(start + 4)]
|
let slice: &[u8; 4] = self.buf[start..(start + 4)]
|
||||||
|
@ -535,7 +538,7 @@ impl Default for ObjectAttributeTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
pub(crate) struct ObjectAttribute {
|
struct ObjectAttribute {
|
||||||
y: u8,
|
y: u8,
|
||||||
x: u8,
|
x: u8,
|
||||||
tile_index: u8,
|
tile_index: u8,
|
||||||
|
@ -571,7 +574,7 @@ struct ObjectBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectBuffer {
|
impl ObjectBuffer {
|
||||||
pub(crate) fn iter(&self) -> std::slice::Iter<'_, Option<ObjectAttribute>> {
|
fn iter(&self) -> std::slice::Iter<'_, Option<ObjectAttribute>> {
|
||||||
self.into_iter()
|
self.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -597,21 +600,21 @@ impl<'a> IntoIterator for &'a mut ObjectBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectBuffer {
|
impl ObjectBuffer {
|
||||||
pub(crate) fn is_full(&self) -> bool {
|
fn is_full(&self) -> bool {
|
||||||
self.len == OBJECT_LIMIT
|
self.len == OBJECT_LIMIT
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.buf = [Default::default(); 10];
|
self.buf = [Default::default(); 10];
|
||||||
self.len = 0;
|
self.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add(&mut self, attr: ObjectAttribute) {
|
fn add(&mut self, attr: ObjectAttribute) {
|
||||||
self.buf[self.len] = Some(attr);
|
self.buf[self.len] = Some(attr);
|
||||||
self.len += 1;
|
self.len += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn remove(&mut self, attr: &ObjectAttribute) {
|
fn remove(&mut self, attr: &ObjectAttribute) {
|
||||||
let maybe_index = self.buf.iter().position(|maybe_attr| match maybe_attr {
|
let maybe_index = self.buf.iter().position(|maybe_attr| match maybe_attr {
|
||||||
Some(other_attr) => attr == other_attr,
|
Some(other_attr) => attr == other_attr,
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -640,13 +643,13 @@ struct PixelFetcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PixelFetcher {
|
impl PixelFetcher {
|
||||||
pub(crate) fn hblank_reset(&mut self) {
|
fn hblank_reset(&mut self) {
|
||||||
self.back.hblank_reset();
|
self.back.hblank_reset();
|
||||||
self.obj.hblank_reset();
|
self.obj.hblank_reset();
|
||||||
self.x_pos = 0;
|
self.x_pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn vblank_reset(&mut self) {
|
fn vblank_reset(&mut self) {
|
||||||
self.back.vblank_reset();
|
self.back.vblank_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,11 +719,7 @@ impl PixelFetcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_obj_addr(
|
fn get_obj_addr(attr: &ObjectAttribute, pos: &ScreenPosition, size: ObjectSize) -> u16 {
|
||||||
attr: &ObjectAttribute,
|
|
||||||
pos: &ScreenPosition,
|
|
||||||
size: ObjectSize,
|
|
||||||
) -> u16 {
|
|
||||||
let line_y = pos.line_y;
|
let line_y = pos.line_y;
|
||||||
|
|
||||||
// TODO: Why is the offset 14 and 30 respectively?
|
// TODO: Why is the offset 14 and 30 respectively?
|
||||||
|
@ -841,21 +840,21 @@ struct WindowLineCounter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowLineCounter {
|
impl WindowLineCounter {
|
||||||
pub(crate) fn increment(&mut self) {
|
fn increment(&mut self) {
|
||||||
self.count += 1;
|
self.count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn vblank_reset(&mut self) {
|
fn vblank_reset(&mut self) {
|
||||||
self.count = 0;
|
self.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn count(&self) -> u8 {
|
fn count(&self) -> u8 {
|
||||||
self.count
|
self.count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) enum FetcherState {
|
enum FetcherState {
|
||||||
TileNumber,
|
TileNumber,
|
||||||
ToLowByteSleep,
|
ToLowByteSleep,
|
||||||
TileLowByte,
|
TileLowByte,
|
||||||
|
@ -894,15 +893,15 @@ struct FifoRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FifoRenderer {
|
impl FifoRenderer {
|
||||||
pub(crate) fn is_enabled(&self) -> bool {
|
fn is_enabled(&self) -> bool {
|
||||||
self.enabled
|
self.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pause(&mut self) {
|
fn pause(&mut self) {
|
||||||
self.enabled = false;
|
self.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resume(&mut self) {
|
fn resume(&mut self) {
|
||||||
self.enabled = true;
|
self.enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -925,19 +924,19 @@ struct TileBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileBuilder {
|
impl TileBuilder {
|
||||||
pub(crate) fn with_id(&mut self, id: u8) {
|
fn with_id(&mut self, id: u8) {
|
||||||
self.id = Some(id);
|
self.id = Some(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_low_byte(&mut self, data: u8) {
|
fn with_low_byte(&mut self, data: u8) {
|
||||||
self.low = Some(data);
|
self.low = Some(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_high_byte(&mut self, data: u8) {
|
fn with_high_byte(&mut self, data: u8) {
|
||||||
self.high = Some(data);
|
self.high = Some(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn bytes(&self) -> Option<(u8, u8)> {
|
fn bytes(&self) -> Option<(u8, u8)> {
|
||||||
self.high.zip(self.low)
|
self.high.zip(self.low)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -949,25 +948,25 @@ struct OamScanState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OamScanState {
|
impl OamScanState {
|
||||||
pub(crate) fn increase(&mut self) {
|
fn increase(&mut self) {
|
||||||
self.count += 1;
|
self.count += 1;
|
||||||
self.count %= 40;
|
self.count %= 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
self.count = Default::default();
|
self.count = Default::default();
|
||||||
self.mode = Default::default();
|
self.mode = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn count(&self) -> u8 {
|
fn count(&self) -> u8 {
|
||||||
self.count
|
self.count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mode(&self) -> OamScanMode {
|
fn mode(&self) -> OamScanMode {
|
||||||
self.mode
|
self.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn next(&mut self) {
|
fn next(&mut self) {
|
||||||
use OamScanMode::*;
|
use OamScanMode::*;
|
||||||
|
|
||||||
self.mode = match self.mode {
|
self.mode = match self.mode {
|
||||||
|
@ -999,19 +998,19 @@ struct WindowStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowStatus {
|
impl WindowStatus {
|
||||||
pub(crate) fn should_draw(&self) -> bool {
|
fn should_draw(&self) -> bool {
|
||||||
self.should_draw
|
self.should_draw
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn coincidence(&self) -> bool {
|
fn coincidence(&self) -> bool {
|
||||||
self.coincidence
|
self.coincidence
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_should_draw(&mut self, value: bool) {
|
fn set_should_draw(&mut self, value: bool) {
|
||||||
self.should_draw = value;
|
self.should_draw = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_coincidence(&mut self, value: bool) {
|
fn set_coincidence(&mut self, value: bool) {
|
||||||
self.coincidence = value;
|
self.coincidence = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use super::{BLACK, DARK_GRAY, LIGHT_GRAY, WHITE};
|
use super::{BLACK, DARK_GRAY, LIGHT_GRAY, WHITE};
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
pub struct LCDStatus(u8);
|
pub struct LCDStatus(u8);
|
||||||
|
@ -435,20 +434,6 @@ impl GrayShade {
|
||||||
GrayShade::Black => BLACK,
|
GrayShade::Black => BLACK,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_rgba(slice: &[u8]) -> Self {
|
|
||||||
let rgba: [u8; 4] = slice
|
|
||||||
.try_into()
|
|
||||||
.expect("Unable to interpret &[u8] as [u8; 4]");
|
|
||||||
|
|
||||||
match rgba {
|
|
||||||
WHITE => GrayShade::White,
|
|
||||||
LIGHT_GRAY => GrayShade::LightGray,
|
|
||||||
DARK_GRAY => GrayShade::DarkGray,
|
|
||||||
BLACK => GrayShade::Black,
|
|
||||||
_ => panic!("{:#04X?} is not a colour the DMG-01 supports", rgba),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GrayShade {
|
impl Default for GrayShade {
|
||||||
|
|
|
@ -79,12 +79,6 @@ impl From<u8> for FrequencyLow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_11bit_freq(low: &FrequencyLow, high: FrequencyHigh) -> u16 {
|
|
||||||
let high_bits = high.0 & 0b111;
|
|
||||||
|
|
||||||
(low.0 as u16) << 8 | ((high_bits as u16) << 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum FrequencyType {
|
enum FrequencyType {
|
||||||
Counter = 0,
|
Counter = 0,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::bus::BusIo;
|
||||||
|
|
||||||
const WORK_RAM_SIZE: usize = 0x1000;
|
const WORK_RAM_SIZE: usize = 0x1000;
|
||||||
const VARIABLE_WORK_RAM_SIZE: usize = WORK_RAM_SIZE;
|
const VARIABLE_WORK_RAM_SIZE: usize = WORK_RAM_SIZE;
|
||||||
const WORK_RAM_START_ADDRESS: usize = 0xC000;
|
const WORK_RAM_START_ADDRESS: usize = 0xC000;
|
||||||
|
@ -8,12 +10,12 @@ pub(crate) struct WorkRam {
|
||||||
bank: Box<[u8; WORK_RAM_SIZE]>,
|
bank: Box<[u8; WORK_RAM_SIZE]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkRam {
|
impl BusIo for WorkRam {
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
self.bank[addr as usize - WORK_RAM_START_ADDRESS] = byte;
|
self.bank[addr as usize - WORK_RAM_START_ADDRESS] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
self.bank[addr as usize - WORK_RAM_START_ADDRESS]
|
self.bank[addr as usize - WORK_RAM_START_ADDRESS]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +29,7 @@ impl Default for WorkRam {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) enum BankNumber {
|
enum BankNumber {
|
||||||
One = 1,
|
One = 1,
|
||||||
Two = 2,
|
Two = 2,
|
||||||
Three = 3,
|
Three = 3,
|
||||||
|
@ -53,19 +55,21 @@ impl Default for VariableWorkRam {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableWorkRam {
|
impl VariableWorkRam {
|
||||||
pub(crate) fn set_current_bank(&mut self, bank: BankNumber) {
|
fn set_current_bank(&mut self, bank: BankNumber) {
|
||||||
self.current = bank;
|
self.current = bank;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_current_bank(&self) -> BankNumber {
|
fn get_current_bank(&self) -> BankNumber {
|
||||||
self.current
|
self.current
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn write_byte(&mut self, addr: u16, byte: u8) {
|
impl BusIo for VariableWorkRam {
|
||||||
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
self.bank_n[self.current as usize][addr as usize - VARIABLE_WORK_RAM_START_ADDRESS] = byte;
|
self.bank_n[self.current as usize][addr as usize - VARIABLE_WORK_RAM_START_ADDRESS] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_byte(&self, addr: u16) -> u8 {
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
self.bank_n[self.current as usize][addr as usize - VARIABLE_WORK_RAM_START_ADDRESS]
|
self.bank_n[self.current as usize][addr as usize - VARIABLE_WORK_RAM_START_ADDRESS]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue