feat: add more debug tools to gui
This commit is contained in:
parent
bbcbbd8ce3
commit
e72b11f946
22
src/cpu.rs
22
src/cpu.rs
|
@ -73,15 +73,12 @@ impl Cpu {
|
|||
///
|
||||
/// If opcode == 0xCB, then decoding costs 4 cycles.
|
||||
/// Otherwise, decoding is free
|
||||
pub(crate) fn decode(&mut self, mut opcode: u8) -> Instruction {
|
||||
let instr = if opcode == 0xCB {
|
||||
opcode = self.fetch();
|
||||
Instruction::decode(opcode, true)
|
||||
pub(crate) fn decode(&mut self, opcode: u8) -> Instruction {
|
||||
if opcode == 0xCB {
|
||||
Instruction::decode(self.fetch(), true)
|
||||
} else {
|
||||
Instruction::decode(opcode, false)
|
||||
};
|
||||
|
||||
instr.unwrap_or_else(|| panic!("{:#04X} is an invalid instruction", opcode))
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute an [Instruction].
|
||||
|
@ -366,15 +363,12 @@ impl Cpu {
|
|||
}
|
||||
|
||||
fn _dbg_instr(&self) -> Instruction {
|
||||
let mut byte = self.read_byte(self.reg.pc);
|
||||
let instr = if byte == 0xCB {
|
||||
byte = self.read_byte(self.reg.pc + 1);
|
||||
Instruction::decode(byte, true)
|
||||
let byte = self.read_byte(self.reg.pc);
|
||||
if byte == 0xCB {
|
||||
Instruction::decode(self.read_byte(self.reg.pc + 1), true)
|
||||
} else {
|
||||
Instruction::decode(byte, false)
|
||||
};
|
||||
|
||||
instr.unwrap_or_else(|| panic!("{:#04X} is an invalid instruction", byte))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
src/emu.rs
12
src/emu.rs
|
@ -18,7 +18,13 @@ pub const CYCLES_IN_FRAME: Cycle = 456 * 154; // 456 Cycles times 154 scanlines
|
|||
pub(crate) const SM83_CLOCK_SPEED: u64 = 0x40_0000; // Hz which is 4.194304Mhz
|
||||
const DEFAULT_TITLE: &str = "Game Boy Screen";
|
||||
|
||||
pub fn run_frame(cpu: &mut Cpu, gamepad: &mut Gilrs, key: KeyboardInput) -> Cycle {
|
||||
#[inline]
|
||||
pub fn run_frame(cpu: &mut Cpu, gamepad: &mut Gilrs, key: KeyboardInput) {
|
||||
run(cpu, gamepad, key, CYCLES_IN_FRAME)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn run(cpu: &mut Cpu, gamepad: &mut Gilrs, key: KeyboardInput, cycles: Cycle) {
|
||||
let mut elapsed = 0;
|
||||
|
||||
if let Some(event) = gamepad.next_event() {
|
||||
|
@ -26,11 +32,9 @@ pub fn run_frame(cpu: &mut Cpu, gamepad: &mut Gilrs, key: KeyboardInput) -> Cycl
|
|||
}
|
||||
crate::joypad::handle_keyboard_input(&mut cpu.bus.joyp, key);
|
||||
|
||||
while elapsed < CYCLES_IN_FRAME {
|
||||
while elapsed < cycles {
|
||||
elapsed += cpu.step();
|
||||
}
|
||||
|
||||
elapsed
|
||||
}
|
||||
|
||||
pub fn save_and_exit(cpu: &Cpu, control_flow: &mut ControlFlow) {
|
||||
|
|
47
src/gui.rs
47
src/gui.rs
|
@ -26,6 +26,7 @@ pub struct GuiState {
|
|||
/// When true, egui winit should exit the application
|
||||
pub quit: bool,
|
||||
pub title: String,
|
||||
pub mode: EmuMode,
|
||||
}
|
||||
|
||||
impl GuiState {
|
||||
|
@ -33,10 +34,19 @@ impl GuiState {
|
|||
Self {
|
||||
title,
|
||||
quit: Default::default(),
|
||||
mode: EmuMode::Running,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EmuMode {
|
||||
Running,
|
||||
StepFrame,
|
||||
Stopped,
|
||||
Step,
|
||||
}
|
||||
|
||||
/// To avoid using an [Option<KeyboardInput>] to keep track of user input from winit,
|
||||
/// we can use a "default" value. However, in order for this to work the chosen "default"
|
||||
/// value must be an **unused** key, so that it is ignored by the emulator.
|
||||
|
@ -223,7 +233,7 @@ pub fn execute_render_pass(
|
|||
|
||||
#[inline]
|
||||
pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &CtxRef, texture_id: TextureId) {
|
||||
use crate::{cpu, instruction};
|
||||
use crate::{cpu, instruction, ppu};
|
||||
|
||||
fn selectable_text(ui: &mut egui::Ui, mut text: &str) -> egui::Response {
|
||||
ui.add(egui::TextEdit::multiline(&mut text).code_editor())
|
||||
|
@ -247,6 +257,17 @@ pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &CtxRef, texture_id: Textur
|
|||
selectable_text(ui, &instruction::dbg::tmp_disasm(cpu, 20));
|
||||
});
|
||||
|
||||
egui::Window::new("Settings").show(ctx, |ui| {
|
||||
egui::ComboBox::from_label("Emulation Mode")
|
||||
.selected_text(format!("{:?}", app.mode))
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut app.mode, EmuMode::Running, "Running");
|
||||
ui.selectable_value(&mut app.mode, EmuMode::Stopped, "Stopped");
|
||||
ui.selectable_value(&mut app.mode, EmuMode::StepFrame, "Step Frame");
|
||||
ui.selectable_value(&mut app.mode, EmuMode::Step, "Step");
|
||||
})
|
||||
});
|
||||
|
||||
egui::Window::new("GB Info").show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.vertical(|ui| {
|
||||
|
@ -262,10 +283,21 @@ pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &CtxRef, texture_id: Textur
|
|||
});
|
||||
|
||||
ui.vertical(|ui| {
|
||||
let ppu = &cpu.bus.ppu;
|
||||
|
||||
ui.heading("PPU");
|
||||
|
||||
ui.monospace("LY: ?");
|
||||
ui.monospace("SCX: ?");
|
||||
ui.monospace(format!("LY: {}", ppu::dbg::ly(ppu)));
|
||||
ui.horizontal(|ui| {
|
||||
ui.monospace(format!("SCX: {}", ppu::dbg::scx(ppu)));
|
||||
ui.monospace(format!("SCY: {}", ppu::dbg::scy(ppu)));
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.monospace(format!("WX: {}", ppu::dbg::wx(ppu)));
|
||||
ui.monospace(format!("WY: {}", ppu::dbg::wy(ppu)));
|
||||
});
|
||||
|
||||
ui.monospace(format!("Mode: {:?}", ppu::dbg::mode(ppu)))
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -312,3 +344,12 @@ pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &CtxRef, texture_id: Textur
|
|||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub mod kbd {
|
||||
use winit::event::{ElementState, KeyboardInput, VirtualKeyCode};
|
||||
|
||||
pub fn space_released(input: &KeyboardInput) -> bool {
|
||||
let keycode = input.virtual_keycode;
|
||||
matches!(input.state, ElementState::Released if keycode == Some(VirtualKeyCode::Space))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ pub(crate) enum Instruction {
|
|||
BIT(u8, Register),
|
||||
RES(u8, Register),
|
||||
SET(u8, Register),
|
||||
Invalid,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Instruction {
|
||||
|
@ -109,6 +110,7 @@ impl std::fmt::Debug for Instruction {
|
|||
BIT(b, r) => write!(f, "BIT {}, {:?}", b, r),
|
||||
RES(b, r) => write!(f, "RES {}, {:?}", b, r),
|
||||
SET(b, r) => write!(f, "SET {}, {:?}", b, r),
|
||||
Invalid => f.write_str("???"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1294,6 +1296,7 @@ impl Instruction {
|
|||
}
|
||||
}
|
||||
}
|
||||
Instruction::Invalid => panic!("Attempted to execute invalid instruction"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1538,7 +1541,7 @@ impl Instruction {
|
|||
}
|
||||
|
||||
impl Instruction {
|
||||
pub(crate) fn decode(byte: u8, prefixed: bool) -> Option<Self> {
|
||||
pub(crate) fn decode(byte: u8, prefixed: bool) -> Self {
|
||||
if prefixed {
|
||||
Self::prefixed(byte)
|
||||
} else {
|
||||
|
@ -1546,139 +1549,132 @@ impl Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
fn unprefixed(byte: u8) -> Option<Self> {
|
||||
fn unprefixed(byte: u8) -> Self {
|
||||
use Instruction::*;
|
||||
|
||||
match byte {
|
||||
// NOP
|
||||
0o000 => Some(NOP),
|
||||
0o000 => NOP,
|
||||
// LD (u16), SP
|
||||
0o010 => Some(LD(LDTarget::IndirectImmediateWord, LDSource::SP)),
|
||||
0o010 => LD(LDTarget::IndirectImmediateWord, LDSource::SP),
|
||||
// STOP
|
||||
0o020 => Some(STOP),
|
||||
0o020 => STOP,
|
||||
// JR i8
|
||||
0o030 => Some(JR(JpCond::Always)),
|
||||
0o030 => JR(JpCond::Always),
|
||||
// JR cond i8
|
||||
0o040 | 0o050 | 0o060 | 0o070 => Some(JR(jump_cond((byte >> 3) & 0x03))),
|
||||
0o040 | 0o050 | 0o060 | 0o070 => JR(jump_cond((byte >> 3) & 0x03)),
|
||||
// LD r16, u16
|
||||
0o001 | 0o021 | 0o041 | 0o061 => Some(LD(
|
||||
0o001 | 0o021 | 0o041 | 0o061 => LD(
|
||||
LDTarget::Group1(group1((byte >> 4) & 0x03)),
|
||||
LDSource::ImmediateWord,
|
||||
)),
|
||||
),
|
||||
// ADD HL, r16
|
||||
0o011 | 0o031 | 0o051 | 0o071 => Some(ADD(
|
||||
AddTarget::HL,
|
||||
AddSource::Group1(group1((byte >> 4) & 0x03)),
|
||||
)),
|
||||
0o011 | 0o031 | 0o051 | 0o071 => {
|
||||
ADD(AddTarget::HL, AddSource::Group1(group1((byte >> 4) & 0x03)))
|
||||
}
|
||||
// LD (r16), A
|
||||
0o002 | 0o022 | 0o042 | 0o062 => Some(LD(
|
||||
0o002 | 0o022 | 0o042 | 0o062 => LD(
|
||||
LDTarget::IndirectGroup2(group2((byte >> 4) & 0x03)),
|
||||
LDSource::A,
|
||||
)),
|
||||
),
|
||||
// LD A, (r16)
|
||||
0o012 | 0o032 | 0o052 | 0o072 => Some(LD(
|
||||
0o012 | 0o032 | 0o052 | 0o072 => LD(
|
||||
LDTarget::A,
|
||||
LDSource::IndirectGroup2(group2((byte >> 4) & 0x03)),
|
||||
)),
|
||||
),
|
||||
// INC r16
|
||||
0o003 | 0o023 | 0o043 | 0o063 => {
|
||||
Some(INC(AllRegisters::Group1(group1((byte >> 4) & 0x03))))
|
||||
}
|
||||
0o003 | 0o023 | 0o043 | 0o063 => INC(AllRegisters::Group1(group1((byte >> 4) & 0x03))),
|
||||
// DEC r16
|
||||
0o013 | 0o033 | 0o053 | 0o073 => {
|
||||
Some(DEC(AllRegisters::Group1(group1((byte >> 4) & 0x03))))
|
||||
}
|
||||
0o013 | 0o033 | 0o053 | 0o073 => DEC(AllRegisters::Group1(group1((byte >> 4) & 0x03))),
|
||||
// INC r8
|
||||
0o004 | 0o014 | 0o024 | 0o034 | 0o044 | 0o054 | 0o064 | 0o074 => {
|
||||
Some(INC(AllRegisters::Register(register((byte >> 3) & 0x07))))
|
||||
INC(AllRegisters::Register(register((byte >> 3) & 0x07)))
|
||||
}
|
||||
// DEC r8
|
||||
0o005 | 0o015 | 0o025 | 0o035 | 0o045 | 0o055 | 0o065 | 0o075 => {
|
||||
Some(DEC(AllRegisters::Register(register((byte >> 3) & 0x07))))
|
||||
DEC(AllRegisters::Register(register((byte >> 3) & 0x07)))
|
||||
}
|
||||
// LD r8, u8
|
||||
0o006 | 0o016 | 0o026 | 0o036 | 0o046 | 0o056 | 0o066 | 0o076 => Some(LD(
|
||||
0o006 | 0o016 | 0o026 | 0o036 | 0o046 | 0o056 | 0o066 | 0o076 => LD(
|
||||
LDTarget::Register(register((byte >> 3) & 0x07)),
|
||||
LDSource::ImmediateByte,
|
||||
)),
|
||||
),
|
||||
// RLCA, RRCA, RLA, RRA, DAA, CPL, SCF, and CCF
|
||||
0o007 | 0o017 | 0o027 | 0o037 | 0o047 | 0o057 | 0o067 | 0o077 => {
|
||||
Some(flag_instr((byte >> 3) & 0x07))
|
||||
flag_instr((byte >> 3) & 0x07)
|
||||
}
|
||||
// HALT
|
||||
0o166 => Some(HALT),
|
||||
0o166 => HALT,
|
||||
// LD r8, r8
|
||||
0o100..=0o177 => Some(LD(
|
||||
0o100..=0o177 => LD(
|
||||
LDTarget::Register(register((byte >> 3) & 0x07)),
|
||||
LDSource::Register(register(byte & 0x07)),
|
||||
)),
|
||||
),
|
||||
// ADD, ADC, SUB, SBC, AND, XOR, OR, and CP
|
||||
0o200..=0o277 => Some(alu_reg_instr((byte >> 3) & 0x07, byte & 0x07)),
|
||||
0o200..=0o277 => alu_reg_instr((byte >> 3) & 0x07, byte & 0x07),
|
||||
// RET cond
|
||||
0o300 | 0o310 | 0o320 | 0o330 => Some(RET(jump_cond((byte >> 3) & 0x03))),
|
||||
0o300 | 0o310 | 0o320 | 0o330 => RET(jump_cond((byte >> 3) & 0x03)),
|
||||
// LD (0xFF00 + u8), A
|
||||
0o340 => Some(LD(LDTarget::IoWithImmediateOffset, LDSource::A)),
|
||||
0o340 => LD(LDTarget::IoWithImmediateOffset, LDSource::A),
|
||||
// ADD SP, i8
|
||||
0o350 => Some(ADD(AddTarget::SP, AddSource::ImmediateSignedByte)),
|
||||
0o350 => ADD(AddTarget::SP, AddSource::ImmediateSignedByte),
|
||||
// LD A, (0xFF00 + u8)
|
||||
0o360 => Some(LD(LDTarget::A, LDSource::IoWithImmediateOffset)),
|
||||
0o360 => LD(LDTarget::A, LDSource::IoWithImmediateOffset),
|
||||
// LD HL, SP + i8
|
||||
0o370 => Some(LDHL),
|
||||
0o370 => LDHL,
|
||||
// POP r16
|
||||
0o301 | 0o321 | 0o341 | 0o361 => Some(POP(group3((byte >> 4) & 0x03))),
|
||||
0o301 | 0o321 | 0o341 | 0o361 => POP(group3((byte >> 4) & 0x03)),
|
||||
// RET
|
||||
0o311 => Some(RET(JpCond::Always)),
|
||||
0o311 => RET(JpCond::Always),
|
||||
// RETI
|
||||
0o331 => Some(RETI),
|
||||
0o331 => RETI,
|
||||
// JP HL
|
||||
0o351 => Some(JP(JpCond::Always, JpLoc::HL)),
|
||||
0o351 => JP(JpCond::Always, JpLoc::HL),
|
||||
// LD SP, HL
|
||||
0o371 => Some(LD(LDTarget::SP, LDSource::HL)),
|
||||
0o371 => LD(LDTarget::SP, LDSource::HL),
|
||||
// JP cond u16
|
||||
0o302 | 0o312 | 0o322 | 0o332 => {
|
||||
Some(JP(jump_cond((byte >> 3) & 0x03), JpLoc::ImmediateWord))
|
||||
JP(jump_cond((byte >> 3) & 0x03), JpLoc::ImmediateWord)
|
||||
}
|
||||
// LD (0xFF00 + C), A
|
||||
0o342 => Some(LD(LDTarget::IoWithC, LDSource::A)),
|
||||
0o342 => LD(LDTarget::IoWithC, LDSource::A),
|
||||
// LD (u16), A
|
||||
0o352 => Some(LD(LDTarget::IndirectImmediateWord, LDSource::A)),
|
||||
0o352 => LD(LDTarget::IndirectImmediateWord, LDSource::A),
|
||||
// LD A, (0xFF00 + C)
|
||||
0o362 => Some(LD(LDTarget::A, LDSource::IoWithC)),
|
||||
0o362 => LD(LDTarget::A, LDSource::IoWithC),
|
||||
// LD A, (u16)
|
||||
0o372 => Some(LD(LDTarget::A, LDSource::IndirectImmediateWord)),
|
||||
0o372 => LD(LDTarget::A, LDSource::IndirectImmediateWord),
|
||||
// JP u16
|
||||
0o303 => Some(JP(JpCond::Always, JpLoc::ImmediateWord)),
|
||||
0o303 => JP(JpCond::Always, JpLoc::ImmediateWord),
|
||||
// DI
|
||||
0o363 => Some(DI),
|
||||
0o363 => DI,
|
||||
// EI
|
||||
0o373 => Some(EI),
|
||||
0o373 => EI,
|
||||
// CALL cond u16
|
||||
0o304 | 0o314 | 0o324 | 0o334 => Some(CALL(jump_cond((byte >> 3) & 0x03))),
|
||||
0o304 | 0o314 | 0o324 | 0o334 => CALL(jump_cond((byte >> 3) & 0x03)),
|
||||
// PUSH r16
|
||||
0o305 | 0o325 | 0o345 | 0o365 => Some(PUSH(group3((byte >> 4) & 0x03))),
|
||||
0o315 => Some(CALL(JpCond::Always)),
|
||||
0o305 | 0o325 | 0o345 | 0o365 => PUSH(group3((byte >> 4) & 0x03)),
|
||||
0o315 => CALL(JpCond::Always),
|
||||
0o306 | 0o316 | 0o326 | 0o336 | 0o346 | 0o356 | 0o366 | 0o376 => {
|
||||
Some(alu_imm_instr((byte >> 3) & 0x07))
|
||||
alu_imm_instr((byte >> 3) & 0x07)
|
||||
}
|
||||
0o307 | 0o317 | 0o327 | 0o337 | 0o347 | 0o357 | 0o367 | 0o377 => {
|
||||
Some(RST(byte & 0b00111000))
|
||||
}
|
||||
_ => None, // 0xCB is 0o313
|
||||
0o307 | 0o317 | 0o327 | 0o337 | 0o347 | 0o357 | 0o367 | 0o377 => RST(byte & 0b00111000),
|
||||
_ => Invalid, // 0xCB is 0o313
|
||||
}
|
||||
}
|
||||
|
||||
fn prefixed(byte: u8) -> Option<Self> {
|
||||
fn prefixed(byte: u8) -> Self {
|
||||
use Instruction::*;
|
||||
|
||||
match byte {
|
||||
// RLC, RRC, RL, RR, SLA, SRA, SWAP and SRL
|
||||
0o000..=0o077 => Some(prefix_alu((byte >> 3) & 0x07, byte & 0x07)),
|
||||
0o000..=0o077 => prefix_alu((byte >> 3) & 0x07, byte & 0x07),
|
||||
// BIT bit, r8
|
||||
0o100..=0o177 => Some(BIT((byte >> 3) & 0x07, register(byte & 0x07))),
|
||||
0o100..=0o177 => BIT((byte >> 3) & 0x07, register(byte & 0x07)),
|
||||
// RES bit, r8
|
||||
0o200..=0o277 => Some(RES((byte >> 3) & 0x07, register(byte & 0x07))),
|
||||
0o200..=0o277 => RES((byte >> 3) & 0x07, register(byte & 0x07)),
|
||||
// SET bit, r8
|
||||
0o300..=0o377 => Some(SET((byte >> 3) & 0x07, register(byte & 0x07))),
|
||||
0o300..=0o377 => SET((byte >> 3) & 0x07, register(byte & 0x07)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2163,7 +2159,7 @@ pub(crate) mod dbg {
|
|||
use super::{AllRegisters, BusIo, Cpu, Instruction, RegisterPair};
|
||||
|
||||
pub(crate) fn tmp_disasm(cpu: &Cpu, limit: u8) -> String {
|
||||
let mut asm = String::new();
|
||||
let mut sm83_asm = String::new();
|
||||
let mut pc = cpu.register_pair(RegisterPair::PC);
|
||||
|
||||
for _ in 0..limit {
|
||||
|
@ -2179,15 +2175,17 @@ pub(crate) mod dbg {
|
|||
Instruction::unprefixed(opcode)
|
||||
};
|
||||
|
||||
if let Some(instr) = maybe_instr {
|
||||
let instr_asm = format!("{:04X} {:?}\n", pc - 1, instr);
|
||||
asm.push_str(&instr_asm);
|
||||
|
||||
pc += delta::pc_inc_count(instr)
|
||||
match maybe_instr {
|
||||
Instruction::Invalid => {}
|
||||
instr => {
|
||||
let asm = format!("{:04X} {:?}\n", pc - 1, instr);
|
||||
sm83_asm.push_str(&asm);
|
||||
pc += delta::pc_inc_count(instr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asm
|
||||
sm83_asm
|
||||
}
|
||||
|
||||
fn disasm(cpu: &Cpu, pc: u16, instr: Instruction) -> String {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::derivable_impls)] // Will remove this if bitfield-rs allows default impls
|
||||
|
||||
pub use apu::gen::init as spsc_init;
|
||||
pub type Cycle = u64;
|
||||
|
||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -2,6 +2,7 @@ use std::time::Instant;
|
|||
|
||||
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
|
||||
use egui_wgpu_backend::RenderPass;
|
||||
use gb::gui::EmuMode;
|
||||
use gb::{emu, gui};
|
||||
use gilrs::Gilrs;
|
||||
use gui::GuiState;
|
||||
|
@ -129,7 +130,19 @@ fn main() {
|
|||
emu::save_and_exit(&cpu, control_flow);
|
||||
}
|
||||
|
||||
emu::run_frame(&mut cpu, &mut gamepad, last_key);
|
||||
match app.mode {
|
||||
EmuMode::Running => emu::run_frame(&mut cpu, &mut gamepad, last_key),
|
||||
EmuMode::StepFrame if gui::kbd::space_released(&last_key) => {
|
||||
emu::run_frame(&mut cpu, &mut gamepad, last_key)
|
||||
}
|
||||
EmuMode::Step if gui::kbd::space_released(&last_key) => {
|
||||
emu::run(&mut cpu, &mut gamepad, last_key, 4);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// Input has been consumed, reset it
|
||||
last_key = gui::unused_key();
|
||||
|
||||
window.request_redraw();
|
||||
}
|
||||
|
|
28
src/ppu.rs
28
src/ppu.rs
|
@ -910,3 +910,31 @@ struct WindowStatus {
|
|||
/// drawing from the window tile map is true
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
pub(crate) mod dbg {
|
||||
use super::{Ppu, PpuMode};
|
||||
|
||||
pub(crate) fn ly(ppu: &Ppu) -> u8 {
|
||||
ppu.pos.line_y
|
||||
}
|
||||
|
||||
pub(crate) fn scx(ppu: &Ppu) -> u8 {
|
||||
ppu.pos.scroll_x
|
||||
}
|
||||
|
||||
pub(crate) fn scy(ppu: &Ppu) -> u8 {
|
||||
ppu.pos.scroll_y
|
||||
}
|
||||
|
||||
pub(crate) fn mode(ppu: &Ppu) -> PpuMode {
|
||||
ppu.stat.mode()
|
||||
}
|
||||
|
||||
pub(crate) fn wx(ppu: &Ppu) -> i16 {
|
||||
ppu.pos.window_x as i16
|
||||
}
|
||||
|
||||
pub(crate) fn wy(ppu: &Ppu) -> i16 {
|
||||
ppu.pos.window_y as i16
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue