Speed enhancements; Write savefiles
This commit is contained in:
parent
be4f9da380
commit
023b9ff0e4
51
src/cpu.rs
51
src/cpu.rs
@ -1,5 +1,8 @@
|
|||||||
use super::interconnect;
|
use super::interconnect;
|
||||||
|
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
use std::thread::sleep;
|
||||||
|
|
||||||
const REG_A: usize = 6;
|
const REG_A: usize = 6;
|
||||||
|
|
||||||
const REG_N_B: usize = 0;
|
const REG_N_B: usize = 0;
|
||||||
@ -46,7 +49,7 @@ impl CPU {
|
|||||||
ip: 0,
|
ip: 0,
|
||||||
sp: 0xFFFE,
|
sp: 0xFFFE,
|
||||||
interconnect: interconnect,
|
interconnect: interconnect,
|
||||||
ime: false, // Is this correct?
|
ime: false,
|
||||||
debug: false,
|
debug: false,
|
||||||
halted: false,
|
halted: false,
|
||||||
}
|
}
|
||||||
@ -861,39 +864,58 @@ impl CPU {
|
|||||||
self.halted = false;
|
self.halted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_instruction(&mut self) {
|
pub fn run(&mut self) {
|
||||||
// self.debug = !self.interconnect.is_boot_rom();
|
loop {
|
||||||
/*
|
let mut cycles: i32 = 0;
|
||||||
if self.ip == 0x553 {
|
let start = Instant::now();
|
||||||
self.debug = true;
|
for _ in 0 .. 1000 {
|
||||||
|
cycles += self.run_instruction() as i32;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
// Check for interrupts.
|
let gb_dur = cycles * 238;
|
||||||
// TODO: Make this right
|
let our_dur = start.elapsed().subsec_nanos() as i32;
|
||||||
if self.ime {
|
let delta = gb_dur - our_dur;
|
||||||
|
if delta > (20 * 238) { // We're at least 20 cycles faster.
|
||||||
|
sleep(Duration::new(0, delta as u32));
|
||||||
|
} else if delta < 0 {
|
||||||
|
print!("-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_interrupts(&mut self) {
|
||||||
// read pending interrupts
|
// read pending interrupts
|
||||||
let pending = self.interconnect.read_byte(0xFF0F);
|
let pending = self.interconnect.read_byte(0xFF0F);
|
||||||
let enabled = self.interconnect.read_byte(0xFFFF);
|
let enabled = self.interconnect.read_byte(0xFFFF);
|
||||||
let e_pending = pending & enabled;
|
let e_pending = pending & enabled;
|
||||||
|
|
||||||
if e_pending & interconnect::INTERRUPT_DISPLAY_VBLANK > 0 {
|
if e_pending & interconnect::INTERRUPT_DISPLAY_VBLANK > 0 {
|
||||||
// println!("Handling vblank interrupt");
|
|
||||||
self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK);
|
self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK);
|
||||||
} else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 {
|
} else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 {
|
||||||
// println!("Handling display stat interrupt");
|
|
||||||
self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT);
|
self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT);
|
||||||
} else if e_pending & interconnect::INTERRUPT_TIMER_OVERFLOW > 0 {
|
} else if e_pending & interconnect::INTERRUPT_TIMER_OVERFLOW > 0 {
|
||||||
println!("Handling timer interrupt");
|
|
||||||
self.handle_interrupt(0x50, interconnect::INTERRUPT_TIMER_OVERFLOW);
|
self.handle_interrupt(0x50, interconnect::INTERRUPT_TIMER_OVERFLOW);
|
||||||
|
} else if e_pending & interconnect::INTERRUPT_SERIAL > 0 {
|
||||||
|
self.handle_interrupt(0x58, interconnect::INTERRUPT_SERIAL);
|
||||||
|
} else if e_pending & interconnect::INTERRUPT_INPUT > 0 {
|
||||||
|
self.handle_interrupt(0x60, interconnect::INTERRUPT_INPUT);
|
||||||
} else if e_pending > 0 {
|
} else if e_pending > 0 {
|
||||||
panic!("Unknown pending interrupt: {:02X}", e_pending);
|
panic!("Unknown pending interrupt: {:02X}", e_pending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_instruction(&mut self) -> u8 {
|
||||||
|
// self.debug = !self.interconnect.is_boot_rom();
|
||||||
|
// Check for interrupts.
|
||||||
|
if self.ime {
|
||||||
|
self.check_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
let mut cycles: u8 = 1;
|
let mut cycles: u8 = 1;
|
||||||
|
let instruction: u8;
|
||||||
if !self.halted {
|
if !self.halted {
|
||||||
// We need to double-check the flags
|
// We need to double-check the flags
|
||||||
let instruction = self.read_byte(self.ip);
|
instruction = self.read_byte(self.ip);
|
||||||
if self.debug {
|
if self.debug {
|
||||||
print!("{:#06x}: [SP: {:#04X}] i={:02X}. ", &self.ip, &self.sp, &instruction);
|
print!("{:#06x}: [SP: {:#04X}] i={:02X}. ", &self.ip, &self.sp, &instruction);
|
||||||
for i in 0 .. 6 {
|
for i in 0 .. 6 {
|
||||||
@ -1647,5 +1669,6 @@ impl CPU {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.interconnect.tick(cycles);
|
self.interconnect.tick(cycles);
|
||||||
|
cycles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,12 +45,20 @@ const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only
|
|||||||
// const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only
|
// const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only
|
||||||
|
|
||||||
// Display color
|
// Display color
|
||||||
|
/*
|
||||||
const MONOCHROME_PALETTE: &'static [[f64; 3]; 4] = &[
|
const MONOCHROME_PALETTE: &'static [[f64; 3]; 4] = &[
|
||||||
[0.605, 0.734, 0.059],
|
[0.605, 0.734, 0.059],
|
||||||
[0.543, 0.672, 0.059],
|
[0.543, 0.672, 0.059],
|
||||||
[0.188, 0.383, 0.188],
|
[0.188, 0.383, 0.188],
|
||||||
[0.059, 0.219, 0.059],
|
[0.059, 0.219, 0.059],
|
||||||
];
|
];
|
||||||
|
*/
|
||||||
|
const MONOCHROME_PALETTE: &'static [[u8; 3]; 4] = &[
|
||||||
|
[255, 255, 255],
|
||||||
|
[200, 200, 200],
|
||||||
|
[125, 125, 12],
|
||||||
|
[50, 50, 50],
|
||||||
|
];
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
enum PixelOrigin {
|
enum PixelOrigin {
|
||||||
@ -150,6 +158,9 @@ pub struct Display {
|
|||||||
stat_interrupt: bool,
|
stat_interrupt: bool,
|
||||||
|
|
||||||
pixels: [Pixel; GB_PIXELS_X * GB_PIXELS_Y],
|
pixels: [Pixel; GB_PIXELS_X * GB_PIXELS_Y],
|
||||||
|
|
||||||
|
frameskip: u8,
|
||||||
|
frame_no: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display {
|
impl Display {
|
||||||
@ -185,6 +196,8 @@ impl Display {
|
|||||||
vblank_interrupt: false,
|
vblank_interrupt: false,
|
||||||
stat_interrupt: false,
|
stat_interrupt: false,
|
||||||
pixels: pixels,
|
pixels: pixels,
|
||||||
|
frameskip: 0,
|
||||||
|
frame_no: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +341,9 @@ impl Display {
|
|||||||
if self.current_ticks > TICKS_END_READMODE {
|
if self.current_ticks > TICKS_END_READMODE {
|
||||||
self.current_ticks = 0;
|
self.current_ticks = 0;
|
||||||
self.current_mode = DisplayMode::HBlank;
|
self.current_mode = DisplayMode::HBlank;
|
||||||
|
if self.frameskip < self.frame_no {
|
||||||
self.renderscan();
|
self.renderscan();
|
||||||
|
}
|
||||||
if self.status & STAT_MODE_HBLANK_INT > 0 {
|
if self.status & STAT_MODE_HBLANK_INT > 0 {
|
||||||
self.stat_interrupt = true;
|
self.stat_interrupt = true;
|
||||||
}
|
}
|
||||||
@ -365,10 +380,15 @@ impl Display {
|
|||||||
}
|
}
|
||||||
if self.curline > 153 {
|
if self.curline > 153 {
|
||||||
self.current_mode = DisplayMode::ReadOAMMemory; // Mode 2, scanline.
|
self.current_mode = DisplayMode::ReadOAMMemory; // Mode 2, scanline.
|
||||||
|
if self.frameskip < self.frame_no {
|
||||||
self.render_screen();
|
self.render_screen();
|
||||||
self.renderer.present();
|
self.renderer.present();
|
||||||
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 255, 255));
|
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 255, 255));
|
||||||
self.renderer.clear();
|
self.renderer.clear();
|
||||||
|
self.frame_no = 0;
|
||||||
|
} else {
|
||||||
|
self.frame_no += 1;
|
||||||
|
}
|
||||||
self.curline = 0;
|
self.curline = 0;
|
||||||
if self.status & STAT_MODE_OAM_INT > 0 {
|
if self.status & STAT_MODE_OAM_INT > 0 {
|
||||||
self.stat_interrupt = true;
|
self.stat_interrupt = true;
|
||||||
@ -423,10 +443,11 @@ impl Display {
|
|||||||
let tile_offset_y: usize = render_y as usize - y_o as usize;
|
let tile_offset_y: usize = render_y as usize - y_o as usize;
|
||||||
let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode?
|
let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode?
|
||||||
|
|
||||||
let tile_line_1 = self.vram[tile_base_addr + tile_offset_y * 2 + 1];
|
let tile_addr = tile_base_addr + tile_offset_y * 2;
|
||||||
let tile_line_2 = self.vram[tile_base_addr + tile_offset_y * 2 + 1];
|
let tile_line_1 = self.vram[tile_addr + 0];
|
||||||
let tile_line_3 = self.vram[tile_base_addr + tile_offset_y * 2 + 2];
|
let tile_line_2 = self.vram[tile_addr + 1];
|
||||||
let tile_line_4 = self.vram[tile_base_addr + tile_offset_y * 2 + 3];
|
let tile_line_3 = self.vram[tile_addr + 2];
|
||||||
|
let tile_line_4 = self.vram[tile_addr + 3];
|
||||||
|
|
||||||
// We need to draw this.
|
// We need to draw this.
|
||||||
let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0;
|
let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0;
|
||||||
@ -488,7 +509,7 @@ impl Display {
|
|||||||
let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize];
|
let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize];
|
||||||
|
|
||||||
// Draw stuff. We're currently only in monochrome mode
|
// Draw stuff. We're currently only in monochrome mode
|
||||||
self.set_pixel(x.wrapping_add(x_o), render_y, sdl2::pixels::Color::RGB((entry[0]*255.0) as u8, (entry[1]*255.0) as u8, (entry[2]*255.0) as u8), PixelOrigin::Sprite);
|
self.set_pixel(x.wrapping_add(x_o), render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), PixelOrigin::Sprite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,11 +520,11 @@ impl Display {
|
|||||||
fn get_bg_window_tile_addr(&self, tile_id: u8) -> usize {
|
fn get_bg_window_tile_addr(&self, tile_id: u8) -> usize {
|
||||||
if (self.control & CTRL_BG_WINDOW_TILE_DATA_SELECT) == CTRL_BG_WINDOW_TILE_DATA_SELECT {
|
if (self.control & CTRL_BG_WINDOW_TILE_DATA_SELECT) == CTRL_BG_WINDOW_TILE_DATA_SELECT {
|
||||||
let base_addr = 0x0000;
|
let base_addr = 0x0000;
|
||||||
base_addr + (tile_id as usize) * 16
|
base_addr + ((tile_id as usize) << 4)
|
||||||
} else {
|
} else {
|
||||||
let base_addr = 0x0800;
|
let base_addr = 0x0800;
|
||||||
let tile_id = (128u8 as i8).wrapping_add(tile_id as i8) as u8;
|
let tile_id = (128u8 as i8).wrapping_add(tile_id as i8) as u8;
|
||||||
base_addr + (tile_id as usize) * 16
|
base_addr + ((tile_id as usize) << 4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,19 +591,20 @@ impl Display {
|
|||||||
let tile_index_y: u8 = render_abs_y >> 3;
|
let tile_index_y: u8 = render_abs_y >> 3;
|
||||||
let tile_offset_y: u8 = render_abs_y & 7;
|
let tile_offset_y: u8 = render_abs_y & 7;
|
||||||
|
|
||||||
let vram_offset: usize = background_map + (tile_index_y as usize) * 32 + tile_index_x as usize;
|
let vram_offset: usize = background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize;
|
||||||
|
|
||||||
// Obtain tile ID in this area
|
// Obtain tile ID in this area
|
||||||
let tile_id = self.vram[vram_offset];
|
let tile_id = self.vram[vram_offset];
|
||||||
|
|
||||||
// Obtain tile information
|
// Obtain tile information
|
||||||
let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id);
|
let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id);
|
||||||
let tile_line_1 = self.vram[tile_base_addr + (tile_offset_y as usize) * 2];
|
let addr = tile_base_addr + (tile_offset_y as usize) * 2;
|
||||||
let tile_line_2 = self.vram[tile_base_addr + (tile_offset_y as usize) * 2 + 1];
|
let tile_line_1 = self.vram[addr];
|
||||||
|
let tile_line_2 = self.vram[addr + 1];
|
||||||
|
|
||||||
// Get the correct bit
|
// Get the correct bit
|
||||||
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) > 0;
|
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) != 0;
|
||||||
let b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) > 0;
|
let b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) != 0;
|
||||||
|
|
||||||
// Lookup the color
|
// Lookup the color
|
||||||
let c = (b1 as u8) * 2 + b2 as u8;
|
let c = (b1 as u8) * 2 + b2 as u8;
|
||||||
@ -598,11 +620,7 @@ impl Display {
|
|||||||
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
|
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
|
||||||
_ => PixelOrigin::Background,
|
_ => PixelOrigin::Background,
|
||||||
};
|
};
|
||||||
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB((entry[0]*255.0) as u8, (entry[1]*255.0) as u8, (entry[2]*255.0) as u8), origin);
|
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin);
|
||||||
}
|
|
||||||
|
|
||||||
if (self.control & CTRL_BG_SPRITE_ENABLE) == CTRL_BG_SPRITE_ENABLE {
|
|
||||||
self.render_sprites(&queue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,8 +646,9 @@ impl Display {
|
|||||||
|
|
||||||
// Obtain tile information
|
// Obtain tile information
|
||||||
let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id);
|
let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id);
|
||||||
let tile_line_1 = self.vram[tile_base_addr + (tile_offset_y as usize) * 2];
|
let tile_addr = tile_base_addr + (tile_offset_y as usize) * 2;
|
||||||
let tile_line_2 = self.vram[tile_base_addr + (tile_offset_y as usize) * 2 + 1];
|
let tile_line_1 = self.vram[tile_addr];
|
||||||
|
let tile_line_2 = self.vram[tile_addr + 1];
|
||||||
|
|
||||||
// Get the correct bit
|
// Get the correct bit
|
||||||
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) > 0;
|
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) > 0;
|
||||||
@ -649,9 +668,12 @@ impl Display {
|
|||||||
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
|
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
|
||||||
_ => PixelOrigin::Window,
|
_ => PixelOrigin::Window,
|
||||||
};
|
};
|
||||||
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB((entry[0]*255.0) as u8, (entry[1]*255.0) as u8, (entry[2]*255.0) as u8), origin);
|
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (self.control & CTRL_BG_SPRITE_ENABLE) == CTRL_BG_SPRITE_ENABLE {
|
||||||
|
self.render_sprites(&queue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
const WRAM_SIZE: usize = 0x8000;
|
const WRAM_SIZE: usize = 0x8000;
|
||||||
const HIRAM_SIZE: usize = (0xFFFE - 0xFF80) + 1;
|
const HIRAM_SIZE: usize = (0xFFFE - 0xFF80) + 1;
|
||||||
|
|
||||||
|
pub const INTERRUPT_INPUT: u8 = 1 << 4;
|
||||||
|
pub const INTERRUPT_SERIAL: u8 = 1 << 3;
|
||||||
pub const INTERRUPT_TIMER_OVERFLOW: u8 = 1 << 2;
|
pub const INTERRUPT_TIMER_OVERFLOW: u8 = 1 << 2;
|
||||||
pub const INTERRUPT_DISPLAY_STAT: u8 = 1 << 1;
|
pub const INTERRUPT_DISPLAY_STAT: u8 = 1 << 1;
|
||||||
pub const INTERRUPT_DISPLAY_VBLANK: u8 = 1 << 0;
|
pub const INTERRUPT_DISPLAY_VBLANK: u8 = 1 << 0;
|
||||||
@ -92,11 +94,13 @@ impl Interconnect {
|
|||||||
joy_regular_keys: 0x0F,
|
joy_regular_keys: 0x0F,
|
||||||
joy_special_keys: 0x0F,
|
joy_special_keys: 0x0F,
|
||||||
joy_switch: 0x30,
|
joy_switch: 0x30,
|
||||||
|
|
||||||
|
cycles: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn press_key(&mut self, key: Key) {
|
fn press_key(&mut self, key: Key) {
|
||||||
println!("Press key {:?}", &key);
|
// println!("Press key {:?}", &key);
|
||||||
match key {
|
match key {
|
||||||
Key::UP => self.joy_regular_keys &= !KEY_UP,
|
Key::UP => self.joy_regular_keys &= !KEY_UP,
|
||||||
Key::DOWN => self.joy_regular_keys &= !KEY_DOWN,
|
Key::DOWN => self.joy_regular_keys &= !KEY_DOWN,
|
||||||
@ -107,10 +111,11 @@ impl Interconnect {
|
|||||||
Key::A => self.joy_special_keys &= !KEY_A,
|
Key::A => self.joy_special_keys &= !KEY_A,
|
||||||
Key::B => self.joy_special_keys &= !KEY_B,
|
Key::B => self.joy_special_keys &= !KEY_B,
|
||||||
}
|
}
|
||||||
|
self.interrupt_request_flags |= INTERRUPT_INPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_key(&mut self, key: Key) {
|
fn release_key(&mut self, key: Key) {
|
||||||
println!("Release key {:?}", &key);
|
// println!("Release key {:?}", &key);
|
||||||
match key {
|
match key {
|
||||||
Key::UP => self.joy_regular_keys |= KEY_UP,
|
Key::UP => self.joy_regular_keys |= KEY_UP,
|
||||||
Key::DOWN => self.joy_regular_keys |= KEY_DOWN,
|
Key::DOWN => self.joy_regular_keys |= KEY_DOWN,
|
||||||
@ -121,6 +126,7 @@ impl Interconnect {
|
|||||||
Key::A => self.joy_special_keys |= KEY_A,
|
Key::A => self.joy_special_keys |= KEY_A,
|
||||||
Key::B => self.joy_special_keys |= KEY_B,
|
Key::B => self.joy_special_keys |= KEY_B,
|
||||||
}
|
}
|
||||||
|
self.interrupt_request_flags |= INTERRUPT_INPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Somehow we need different timers for this.
|
// Somehow we need different timers for this.
|
||||||
@ -140,11 +146,17 @@ impl Interconnect {
|
|||||||
self.interrupt_request_flags |= INTERRUPT_TIMER_OVERFLOW;
|
self.interrupt_request_flags |= INTERRUPT_TIMER_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.serial.serial_interrupt() {
|
||||||
|
self.interrupt_request_flags |= INTERRUPT_SERIAL;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the window is responsive:
|
// Make sure the window is responsive:
|
||||||
|
if self.cycles > 500 {
|
||||||
loop {
|
loop {
|
||||||
if let Some(event) = self.display.event_pump.poll_event(){
|
if let Some(event) = self.display.event_pump.poll_event(){
|
||||||
match event {
|
match event {
|
||||||
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
||||||
|
self.cartridge.save();
|
||||||
panic!("TODO: Proper shutdown");
|
panic!("TODO: Proper shutdown");
|
||||||
},
|
},
|
||||||
Event::KeyDown { keycode: Some(Keycode::Left), .. } => self.press_key(Key::LEFT),
|
Event::KeyDown { keycode: Some(Keycode::Left), .. } => self.press_key(Key::LEFT),
|
||||||
@ -170,6 +182,10 @@ impl Interconnect {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.cycles = 0;
|
||||||
|
} else {
|
||||||
|
self.cycles += cycles as u16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -11,7 +11,10 @@ impl Serial {
|
|||||||
|
|
||||||
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
||||||
match addr {
|
match addr {
|
||||||
0xFF01 => self.data = val,
|
0xFF01 => {
|
||||||
|
println!("Serial: Write {:02X}", val);
|
||||||
|
self.data = val;
|
||||||
|
}
|
||||||
0xFF02 => self.control = val,
|
0xFF02 => self.control = val,
|
||||||
_ => panic!("Serial: Write {:02X} to {:04X} unsupported", val, addr),
|
_ => panic!("Serial: Write {:02X} to {:04X} unsupported", val, addr),
|
||||||
}
|
}
|
||||||
@ -24,4 +27,9 @@ impl Serial {
|
|||||||
_ => panic!("Serial: Read from {:04X} unsupported", addr),
|
_ => panic!("Serial: Read from {:04X} unsupported", addr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serial_interrupt(&self) -> bool {
|
||||||
|
// TODO
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user