mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 10:12:11 +00:00
Tile fetch refactor and window pixel get
This commit is contained in:
parent
b0c07a5264
commit
b5bb582c54
@ -5,7 +5,7 @@ use crate::utils::{
|
|||||||
join_bytes
|
join_bytes
|
||||||
};
|
};
|
||||||
use crate::rom::ROM;
|
use crate::rom::ROM;
|
||||||
use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag, LCD_CONTROL_ADDRESS, LCD_Y_ADDRESS};
|
use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag, LCD_STATUS_ADDRESS, LCD_CONTROL_ADDRESS, LCD_Y_ADDRESS};
|
||||||
use crate::cpu::{Interrupt};
|
use crate::cpu::{Interrupt};
|
||||||
use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS};
|
use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS};
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ pub struct Bus {
|
|||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let game_rom = match ROM::load_file("ignore/mario-land.gb".to_string()) {
|
let game_rom = match ROM::load_file("ignore/dr-mario.gb".to_string()) {
|
||||||
// let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) {
|
// let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) {
|
||||||
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) {
|
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) {
|
||||||
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/02-interrupts.gb".to_string()) {
|
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/02-interrupts.gb".to_string()) {
|
||||||
@ -105,6 +105,10 @@ impl Bus {
|
|||||||
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
|
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
|
||||||
} else if address == TIMER_DIVIDER_REGISTER_ADDRESS {
|
} else if address == TIMER_DIVIDER_REGISTER_ADDRESS {
|
||||||
self.data[address as usize] = 0x00;
|
self.data[address as usize] = 0x00;
|
||||||
|
} else if address == LCD_STATUS_ADDRESS {
|
||||||
|
// Prevent user from modifying LCD Status mode
|
||||||
|
let byte = self.data[address as usize];
|
||||||
|
self.data[address as usize] = (data & 0b1111_1100) | (byte & 0b0000_0011);
|
||||||
} else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) {
|
} else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) {
|
||||||
self.data[address as usize] = data;
|
self.data[address as usize] = data;
|
||||||
self.data[LCD_Y_ADDRESS as usize] = 0x00;
|
self.data[LCD_Y_ADDRESS as usize] = 0x00;
|
||||||
|
10
src/cpu.rs
10
src/cpu.rs
@ -913,17 +913,16 @@ impl CPU {
|
|||||||
bus.set_interrupt_flag(interrupt, false);
|
bus.set_interrupt_flag(interrupt, false);
|
||||||
let vector = interrupt.get_vector();
|
let vector = interrupt.get_vector();
|
||||||
self.exec(Opcode::CALL(OpcodeParameter::U16(vector)), bus);
|
self.exec(Opcode::CALL(OpcodeParameter::U16(vector)), bus);
|
||||||
self.increment_cycles(Cycles(5));
|
|
||||||
println!("Interrupt: {:?}", interrupt);
|
println!("Interrupt: {:?}", interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_interrupts(&mut self, bus: &mut Bus) -> Option<Interrupt> {
|
pub fn check_interrupts(&mut self, bus: &mut Bus) -> Option<Interrupt> {
|
||||||
|
if !self.ime && !self.is_halted {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
if bus.read(INTERRUPT_ENABLE_ADDRESS) & bus.read(INTERRUPT_FLAG_ADDRESS) != 0 {
|
if bus.read(INTERRUPT_ENABLE_ADDRESS) & bus.read(INTERRUPT_FLAG_ADDRESS) != 0 {
|
||||||
self.is_halted = false;
|
self.is_halted = false;
|
||||||
}
|
}
|
||||||
if !self.ime {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if bus.get_interrupt(Interrupt::VBlank) {
|
if bus.get_interrupt(Interrupt::VBlank) {
|
||||||
return Some(Interrupt::VBlank);
|
return Some(Interrupt::VBlank);
|
||||||
} else if bus.get_interrupt(Interrupt::LCDSTAT) {
|
} else if bus.get_interrupt(Interrupt::LCDSTAT) {
|
||||||
@ -942,6 +941,7 @@ impl CPU {
|
|||||||
let cycles_start = self.get_cycles();
|
let cycles_start = self.get_cycles();
|
||||||
if let Some(interrupt) = self.check_interrupts(bus) {
|
if let Some(interrupt) = self.check_interrupts(bus) {
|
||||||
self.handle_interrupt(bus, interrupt);
|
self.handle_interrupt(bus, interrupt);
|
||||||
|
self.increment_cycles(Cycles(5));
|
||||||
} else if !self.is_halted {
|
} else if !self.is_halted {
|
||||||
let program_counter = self.registers.get(Register::PC);
|
let program_counter = self.registers.get(Register::PC);
|
||||||
let parameter_bytes = OpcodeParameterBytes::from_address(program_counter, bus);
|
let parameter_bytes = OpcodeParameterBytes::from_address(program_counter, bus);
|
||||||
@ -1780,13 +1780,11 @@ impl CPU {
|
|||||||
Opcode::EI => {
|
Opcode::EI => {
|
||||||
self.registers.increment(Register::PC, 1);
|
self.registers.increment(Register::PC, 1);
|
||||||
self.ime = true;
|
self.ime = true;
|
||||||
// bus.write(INTERRUPT_MASTER_ENABLE_ADDRESS, 0xFF); // Enable all interrupts
|
|
||||||
},
|
},
|
||||||
// Disable interrupts
|
// Disable interrupts
|
||||||
Opcode::DI => {
|
Opcode::DI => {
|
||||||
self.registers.increment(Register::PC, 1);
|
self.registers.increment(Register::PC, 1);
|
||||||
self.ime = false;
|
self.ime = false;
|
||||||
// bus.write(INTERRUPT_MASTER_ENABLE_ADDRESS, 0x00); // Disable all interrupts
|
|
||||||
},
|
},
|
||||||
// Same as enabling interrupts and then executing RET
|
// Same as enabling interrupts and then executing RET
|
||||||
Opcode::RETI => {
|
Opcode::RETI => {
|
||||||
|
147
src/ppu.rs
147
src/ppu.rs
@ -23,7 +23,7 @@ pub enum LCDControl {
|
|||||||
LCDEnable,
|
LCDEnable,
|
||||||
WindowTileMapAddress,
|
WindowTileMapAddress,
|
||||||
WindowEnable,
|
WindowEnable,
|
||||||
BackgroundWindowTileAddress,
|
TileAddressMode,
|
||||||
BackgroundTileMapAddress,
|
BackgroundTileMapAddress,
|
||||||
ObjectSize,
|
ObjectSize,
|
||||||
ObjectEnable,
|
ObjectEnable,
|
||||||
@ -36,7 +36,7 @@ impl LCDControl {
|
|||||||
LCDControl::LCDEnable => BitIndex::I7,
|
LCDControl::LCDEnable => BitIndex::I7,
|
||||||
LCDControl::WindowTileMapAddress => BitIndex::I6,
|
LCDControl::WindowTileMapAddress => BitIndex::I6,
|
||||||
LCDControl::WindowEnable => BitIndex::I5,
|
LCDControl::WindowEnable => BitIndex::I5,
|
||||||
LCDControl::BackgroundWindowTileAddress => BitIndex::I4,
|
LCDControl::TileAddressMode => BitIndex::I4,
|
||||||
LCDControl::BackgroundTileMapAddress => BitIndex::I3,
|
LCDControl::BackgroundTileMapAddress => BitIndex::I3,
|
||||||
LCDControl::ObjectSize => BitIndex::I2,
|
LCDControl::ObjectSize => BitIndex::I2,
|
||||||
LCDControl::ObjectEnable => BitIndex::I1,
|
LCDControl::ObjectEnable => BitIndex::I1,
|
||||||
@ -95,6 +95,11 @@ pub struct PPU {
|
|||||||
rgba_frame: [[u8; 4]; FRAME_BUFFER_LENGTH as usize],
|
rgba_frame: [[u8; 4]; FRAME_BUFFER_LENGTH as usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum TileNumber {
|
||||||
|
Base(u16),
|
||||||
|
Absolute(u8),
|
||||||
|
}
|
||||||
|
|
||||||
impl PPU {
|
impl PPU {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -128,22 +133,27 @@ impl PPU {
|
|||||||
if PPU::get_lcd_y(bus) < 144 {
|
if PPU::get_lcd_y(bus) < 144 {
|
||||||
if self.cycles.0 == 0 {
|
if self.cycles.0 == 0 {
|
||||||
// Mode 2 OAM scan
|
// Mode 2 OAM scan
|
||||||
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
|
||||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM), true);
|
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM), true);
|
||||||
|
if PPU::get_lcd_status(bus, LCDStatus::Mode2OAMInterrupt) {
|
||||||
|
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
||||||
|
}
|
||||||
} else if self.cycles.0 == 80 + 1 {
|
} else if self.cycles.0 == 80 + 1 {
|
||||||
// Mode 3 drawing pixel line. This could also last 289 cycles
|
// Mode 3 drawing pixel line. This could also last 289 cycles
|
||||||
// PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
|
||||||
self.draw_line(bus);
|
self.draw_line(bus);
|
||||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD), true);
|
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD), true);
|
||||||
} else if self.cycles.0 == 80 + 172 + 1 {
|
} else if self.cycles.0 == 80 + 172 + 1 {
|
||||||
// Mode 0 Horizontal blank. This could last 87 or 204 cycles depending on the mode 3
|
// Mode 0 Horizontal blank. This could last 87 or 204 cycles depending on the mode 3
|
||||||
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
|
||||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::HBlank), true);
|
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::HBlank), true);
|
||||||
|
if PPU::get_lcd_status(bus, LCDStatus::Mode0HBlankInterrupt) {
|
||||||
|
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if PPU::get_lcd_y(bus) == 144 && self.cycles.0 == 0 {
|
} else if PPU::get_lcd_y(bus) == 144 && self.cycles.0 == 0 {
|
||||||
// Mode 1 Vertical blank
|
// Mode 1 Vertical blank
|
||||||
PPU::request_interrupt(bus, Interrupt::VBlank);
|
|
||||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank), true);
|
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank), true);
|
||||||
|
if PPU::get_lcd_status(bus, LCDStatus::Mode1VBlankInterrupt) {
|
||||||
|
PPU::request_interrupt(bus, Interrupt::VBlank);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Horizontal scan completed
|
// Horizontal scan completed
|
||||||
@ -153,11 +163,10 @@ impl PPU {
|
|||||||
PPU::set_lcd_y(bus, PPU::get_lcd_y(bus) + 1);
|
PPU::set_lcd_y(bus, PPU::get_lcd_y(bus) + 1);
|
||||||
|
|
||||||
let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
|
let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
|
||||||
if lyc_compare {
|
PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare);
|
||||||
PPU::set_lcd_status(bus, LCDStatus::LYCInterrupt, lyc_compare);
|
if PPU::get_lcd_status(bus, LCDStatus::LYCInterrupt) && lyc_compare {
|
||||||
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frame completed
|
// Frame completed
|
||||||
if PPU::get_lcd_y(bus) > 153 {
|
if PPU::get_lcd_y(bus) > 153 {
|
||||||
PPU::set_lcd_y(bus, 0);
|
PPU::set_lcd_y(bus, 0);
|
||||||
@ -168,8 +177,6 @@ impl PPU {
|
|||||||
fn request_interrupt(bus: &mut Bus, interrupt: Interrupt) {
|
fn request_interrupt(bus: &mut Bus, interrupt: Interrupt) {
|
||||||
if PPU::get_lcd_control(bus, LCDControl::LCDEnable) {
|
if PPU::get_lcd_control(bus, LCDControl::LCDEnable) {
|
||||||
bus.set_interrupt_flag(interrupt, true);
|
bus.set_interrupt_flag(interrupt, true);
|
||||||
} else {
|
|
||||||
println!("lcd off");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,16 +192,16 @@ impl PPU {
|
|||||||
bus.read(SCROLL_X_ADDRESS)
|
bus.read(SCROLL_X_ADDRESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scroll_x(bus: &mut Bus, val: u8) {
|
|
||||||
bus.write(SCROLL_X_ADDRESS, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_scroll_y(bus: &Bus) -> u8 {
|
fn get_scroll_y(bus: &Bus) -> u8 {
|
||||||
bus.read(SCROLL_Y_ADDRESS)
|
bus.read(SCROLL_Y_ADDRESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scroll_y(bus: &mut Bus, val: u8) {
|
fn get_window_x(bus: &Bus) -> u8 {
|
||||||
bus.write(SCROLL_Y_ADDRESS, val);
|
bus.read(WINDOW_X_ADDRESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_window_y(bus: &Bus) -> u8 {
|
||||||
|
bus.read(WINDOW_Y_ADDRESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_lcd_control(bus: &Bus, control: LCDControl) -> bool {
|
pub fn get_lcd_control(bus: &Bus, control: LCDControl) -> bool {
|
||||||
@ -242,7 +249,55 @@ impl PPU {
|
|||||||
bus.write(LCD_STATUS_ADDRESS, byte);
|
bus.write(LCD_STATUS_ADDRESS, byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_line(&mut self, bus: &Bus) {
|
fn get_tile_bytes(x: u8, y: u8, tile_number: TileNumber, default_method: bool, bus: &Bus) -> (u8, u8) {
|
||||||
|
let index_x = x as u16 / 8;
|
||||||
|
let index_y = (y as u16 / 8) * 32;
|
||||||
|
let index = index_x + index_y;
|
||||||
|
let tile_line = (y).rem_euclid(8) * 2;
|
||||||
|
let tile_number = match tile_number {
|
||||||
|
TileNumber::Base(base) => bus.read(base + index as u16),
|
||||||
|
TileNumber::Absolute(num) => bus.read(0x8000 + num as u16),
|
||||||
|
|
||||||
|
} as u16;
|
||||||
|
let addr = if default_method {
|
||||||
|
0x8000 + tile_line as u16 + (tile_number * 16)
|
||||||
|
} else {
|
||||||
|
let tile_number = (tile_number as i8) as i16;
|
||||||
|
let tile_line = tile_line as i16;
|
||||||
|
let base = (0x9000 as u16) as i16;
|
||||||
|
(base + tile_line + (tile_number * 16)) as u16
|
||||||
|
};
|
||||||
|
|
||||||
|
(bus.read(addr), bus.read(addr + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_window_pixel(lcd_x: u8, bus: &Bus) -> Option<Pixel> {
|
||||||
|
let lcd_y = PPU::get_lcd_y(bus);
|
||||||
|
let window_x = (PPU::get_window_x(bus) as i8 - 7) as u8;
|
||||||
|
let window_y = PPU::get_window_y(bus);
|
||||||
|
|
||||||
|
if window_x != lcd_x || window_y != lcd_y {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = lcd_x - window_x;
|
||||||
|
let y = lcd_y - window_x;
|
||||||
|
|
||||||
|
let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode);
|
||||||
|
let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::WindowTileMapAddress) {
|
||||||
|
true => 0x9C00,
|
||||||
|
false => 0x9800,
|
||||||
|
};
|
||||||
|
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, TileNumber::Base(tilemap_area), default_mode, bus);
|
||||||
|
|
||||||
|
let palette = bus.read(BACKGROUND_PALETTE_ADDRESS);
|
||||||
|
let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
|
||||||
|
|
||||||
|
Some(pixels[(x as usize).rem_euclid(8)])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_line(&mut self, bus: &Bus) {
|
||||||
|
let palette = bus.read(BACKGROUND_PALETTE_ADDRESS);
|
||||||
let lcd_y = PPU::get_lcd_y(bus);
|
let lcd_y = PPU::get_lcd_y(bus);
|
||||||
if lcd_y as u32 >= LCD_HEIGHT {
|
if lcd_y as u32 >= LCD_HEIGHT {
|
||||||
return;
|
return;
|
||||||
@ -251,26 +306,40 @@ impl PPU {
|
|||||||
while (lcd_x as u32) < LCD_WIDTH {
|
while (lcd_x as u32) < LCD_WIDTH {
|
||||||
let y = lcd_y.wrapping_add(PPU::get_scroll_y(bus));
|
let y = lcd_y.wrapping_add(PPU::get_scroll_y(bus));
|
||||||
let x = lcd_x.wrapping_add(PPU::get_scroll_x(bus));
|
let x = lcd_x.wrapping_add(PPU::get_scroll_x(bus));
|
||||||
let index_x = x as u16 / 8;
|
|
||||||
let index_y = (y as u16 / 8) * 32;
|
|
||||||
let index = index_x + index_y;
|
|
||||||
let tile_line = (y).rem_euclid(8) * 2;
|
|
||||||
let tile_number = bus.read(0x9800 + index as u16) as u16;
|
|
||||||
let addr = 0x8000 + tile_line as u16 + (tile_number * 16);
|
|
||||||
|
|
||||||
let tile_byte_1 = bus.read(addr);
|
let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode);
|
||||||
let tile_byte_2 = bus.read(addr + 1);
|
let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::BackgroundTileMapAddress) {
|
||||||
|
true => 0x9C00,
|
||||||
|
false => 0x9800,
|
||||||
|
};
|
||||||
|
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, TileNumber::Base(tilemap_area), default_mode, bus);
|
||||||
|
|
||||||
let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
let bg_pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
|
||||||
|
|
||||||
for pixel in pixels {
|
for pixel in bg_pixels {
|
||||||
let idx = lcd_x as usize + (lcd_y as usize * LCD_WIDTH as usize);
|
let idx = lcd_x as usize + (lcd_y as usize * LCD_WIDTH as usize);
|
||||||
self.rgba_frame[idx] = PPU::get_rgba(pixel);
|
self.rgba_frame[idx] = PPU::get_rgba(pixel);
|
||||||
|
if PPU::get_lcd_control(bus, LCDControl::WindowEnable) {
|
||||||
|
if let Some(window_pixel) = PPU::get_window_pixel(lcd_x, bus) {
|
||||||
|
self.rgba_frame[idx] = PPU::get_rgba(window_pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lcd_x += 1;
|
lcd_x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_palette(index: u8, palette_byte: u8) -> u8 {
|
||||||
|
match index {
|
||||||
|
0b00 => palette_byte & 0b11,
|
||||||
|
0b01 => (palette_byte >> 2) & 0b11,
|
||||||
|
0b10 => (palette_byte >> 4) & 0b11,
|
||||||
|
0b11 => (palette_byte >> 6) & 0b11,
|
||||||
|
_ => 0b00,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_pixel(two_bit_pixel: u8) -> Pixel {
|
fn get_pixel(two_bit_pixel: u8) -> Pixel {
|
||||||
match two_bit_pixel {
|
match two_bit_pixel {
|
||||||
0x00 => Pixel::White,
|
0x00 => Pixel::White,
|
||||||
@ -290,17 +359,17 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_byte_pixels(byte1: u8, byte2: u8) -> [Pixel; 8] {
|
fn get_byte_pixels(byte1: u8, byte2: u8, palette: u8) -> [Pixel; 8] {
|
||||||
let mut pixels: [Pixel; 8] = [Pixel::White; 8];
|
[
|
||||||
pixels[0] = PPU::get_pixel(((get_bit(byte1, BitIndex::I7) as u8) << 1) | (get_bit(byte2, BitIndex::I7) as u8));
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 7) & 0b01) | ((byte2 >> 6) & 0b10), palette)),
|
||||||
pixels[1] = PPU::get_pixel(((get_bit(byte1, BitIndex::I6) as u8) << 1) | (get_bit(byte2, BitIndex::I6) as u8));
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 6) & 0b01) | ((byte2 >> 5) & 0b10), palette)),
|
||||||
pixels[2] = PPU::get_pixel(((get_bit(byte1, BitIndex::I5) as u8) << 1) | (get_bit(byte2, BitIndex::I5) as u8));
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 5) & 0b01) | ((byte2 >> 4) & 0b10), palette)),
|
||||||
pixels[3] = PPU::get_pixel(((get_bit(byte1, BitIndex::I4) as u8) << 1) | (get_bit(byte2, BitIndex::I4) as u8));
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 4) & 0b01) | ((byte2 >> 3) & 0b10), palette)),
|
||||||
pixels[4] = PPU::get_pixel(((get_bit(byte1, BitIndex::I3) as u8) << 1) | (get_bit(byte2, BitIndex::I3) as u8));
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 3) & 0b01) | ((byte2 >> 2) & 0b10), palette)),
|
||||||
pixels[5] = PPU::get_pixel(((get_bit(byte1, BitIndex::I2) as u8) << 1) | (get_bit(byte2, BitIndex::I2) as u8));
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 2) & 0b01) | ((byte2 >> 1) & 0b10), palette)),
|
||||||
pixels[6] = PPU::get_pixel(((get_bit(byte1, BitIndex::I1) as u8) << 1) | (get_bit(byte2, BitIndex::I1) as u8));
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 1) & 0b01) | (byte2 & 0b10), palette)),
|
||||||
pixels[7] = PPU::get_pixel(((get_bit(byte1, BitIndex::I0) as u8) << 1) | (get_bit(byte2, BitIndex::I0) as u8));
|
PPU::get_pixel(PPU::get_palette((byte1 & 0b01) | ((byte2 << 1) & 0b10), palette)),
|
||||||
pixels
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rgba_frame(&self) -> &[[u8; 4]; FRAME_BUFFER_LENGTH as usize] {
|
pub fn get_rgba_frame(&self) -> &[[u8; 4]; FRAME_BUFFER_LENGTH as usize] {
|
||||||
|
@ -48,7 +48,7 @@ impl Timer {
|
|||||||
if self.cycles.0 >= tima_rate {
|
if self.cycles.0 >= tima_rate {
|
||||||
if tima.checked_add(1) == None {
|
if tima.checked_add(1) == None {
|
||||||
bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS));
|
bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS));
|
||||||
bus.set_interrupt_flag(Interrupt::Timer, true);
|
bus.set_interrupt_flag(Interrupt::Timer, false);
|
||||||
} else {
|
} else {
|
||||||
bus.write(TIMER_COUNTER_ADDRESS, tima.wrapping_add(1));
|
bus.write(TIMER_COUNTER_ADDRESS, tima.wrapping_add(1));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user