mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 18:21:31 +00:00
Compare commits
No commits in common. "5d488d4fa6997eb5961388ac1ff691b4c54b5260" and "c5ff92c0ab0b7d2101f3fbd4e64265edc4dcab71" have entirely different histories.
5d488d4fa6
...
c5ff92c0ab
22
src/bus.rs
22
src/bus.rs
@ -11,8 +11,7 @@ use crate::ppu::{
|
|||||||
LCDStatusModeFlag,
|
LCDStatusModeFlag,
|
||||||
LCD_STATUS_ADDRESS,
|
LCD_STATUS_ADDRESS,
|
||||||
LCD_CONTROL_ADDRESS,
|
LCD_CONTROL_ADDRESS,
|
||||||
LCD_Y_ADDRESS,
|
LCD_Y_ADDRESS
|
||||||
DMA_ADDRESS,
|
|
||||||
};
|
};
|
||||||
use crate::cpu::{Interrupt};
|
use crate::cpu::{Interrupt};
|
||||||
use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS};
|
use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS};
|
||||||
@ -56,12 +55,11 @@ pub struct Bus {
|
|||||||
game_rom: ROM,
|
game_rom: ROM,
|
||||||
data: [u8; 0x10000],
|
data: [u8; 0x10000],
|
||||||
pub reset_timer: bool,
|
pub reset_timer: bool,
|
||||||
pub joypad: Joypad,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let game_rom = match ROM::load_file("ignore/tetris.gb".to_string()) {
|
let game_rom = match ROM::load_file("ignore/m3_scy_change.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()) {
|
||||||
@ -106,18 +104,12 @@ impl Bus {
|
|||||||
data,
|
data,
|
||||||
game_rom,
|
game_rom,
|
||||||
reset_timer: false,
|
reset_timer: false,
|
||||||
joypad: Joypad::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self, address: u16) -> u8 {
|
pub fn read(&self, address: u16) -> u8 {
|
||||||
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
|
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
|
||||||
return self.game_rom.read(address);
|
return self.game_rom.read(address);
|
||||||
|
|
||||||
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
|
|
||||||
return 0b11100000 | self.data[address as usize];
|
|
||||||
} else if address == JOYPAD_ADDRESS {
|
|
||||||
return self.joypad.read(self.data[address as usize]);
|
|
||||||
}
|
}
|
||||||
self.data[address as usize]
|
self.data[address as usize]
|
||||||
}
|
}
|
||||||
@ -155,16 +147,6 @@ impl Bus {
|
|||||||
} else if address == JOYPAD_ADDRESS {
|
} else if address == JOYPAD_ADDRESS {
|
||||||
let byte = self.data[address as usize];
|
let byte = self.data[address as usize];
|
||||||
self.data[address as usize] = (data & 0b11110000) | (byte & 0b00001111);
|
self.data[address as usize] = (data & 0b11110000) | (byte & 0b00001111);
|
||||||
} else if address == DMA_ADDRESS {
|
|
||||||
// the idea is: when something gets written to $FF46, multiply it by 0x100, then copy 160 bytes starting from that memory location into OAM
|
|
||||||
self.data[address as usize] = data;
|
|
||||||
let source = (data as usize) * 0x100;
|
|
||||||
let mut count = 0;
|
|
||||||
let oam_addr = SPRITE_ATTRIBUTE_TABLE.begin() as usize;
|
|
||||||
while count < 160 {
|
|
||||||
self.data[oam_addr + count] = self.data[source + count];
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.data[address as usize] = data;
|
self.data[address as usize] = data;
|
||||||
}
|
}
|
||||||
|
@ -911,7 +911,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
|
pub fn handle_interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
|
||||||
// println!("Interrupt: {:?}", interrupt);
|
println!("Interrupt: {:?}", interrupt);
|
||||||
bus.set_interrupt_flag(interrupt, false);
|
bus.set_interrupt_flag(interrupt, false);
|
||||||
self.ime = false;
|
self.ime = false;
|
||||||
self.registers.decrement(Register::PC, 3);
|
self.registers.decrement(Register::PC, 3);
|
||||||
|
@ -13,15 +13,18 @@ pub struct Emulator {
|
|||||||
ppu: PPU,
|
ppu: PPU,
|
||||||
bus: Bus,
|
bus: Bus,
|
||||||
timer: Timer,
|
timer: Timer,
|
||||||
|
joypad: Joypad,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Emulator {
|
impl Emulator {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let mut joypad: Joypad = Joypad::new();
|
||||||
Self {
|
Self {
|
||||||
cpu: CPU::new(),
|
cpu: CPU::new(),
|
||||||
ppu: PPU::new(),
|
ppu: PPU::new(),
|
||||||
bus: Bus::new(),
|
bus: Bus::new(),
|
||||||
timer: Timer::new(),
|
timer: Timer::new(),
|
||||||
|
joypad: Joypad::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,68 +32,68 @@ impl Emulator {
|
|||||||
let mut change = false;
|
let mut change = false;
|
||||||
if input.key_pressed(VirtualKeyCode::K) {
|
if input.key_pressed(VirtualKeyCode::K) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::A);
|
self.joypad.press(Button::A);
|
||||||
}
|
}
|
||||||
if input.key_pressed(VirtualKeyCode::J) {
|
if input.key_pressed(VirtualKeyCode::J) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::B);
|
self.joypad.press(Button::B);
|
||||||
}
|
}
|
||||||
if input.key_pressed(VirtualKeyCode::W) {
|
if input.key_pressed(VirtualKeyCode::W) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::Up);
|
self.joypad.press(Button::Up);
|
||||||
}
|
}
|
||||||
if input.key_pressed(VirtualKeyCode::S) {
|
if input.key_pressed(VirtualKeyCode::S) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::Down);
|
self.joypad.press(Button::Down);
|
||||||
}
|
}
|
||||||
if input.key_pressed(VirtualKeyCode::A) {
|
if input.key_pressed(VirtualKeyCode::A) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::Left);
|
self.joypad.press(Button::Left);
|
||||||
}
|
}
|
||||||
if input.key_pressed(VirtualKeyCode::D) {
|
if input.key_pressed(VirtualKeyCode::D) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::Right);
|
self.joypad.press(Button::Right);
|
||||||
}
|
}
|
||||||
if input.key_pressed(VirtualKeyCode::N) {
|
if input.key_pressed(VirtualKeyCode::N) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::Start);
|
self.joypad.press(Button::Start);
|
||||||
}
|
}
|
||||||
if input.key_pressed(VirtualKeyCode::B) {
|
if input.key_pressed(VirtualKeyCode::B) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.press(Button::Select);
|
self.joypad.press(Button::Select);
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.key_released(VirtualKeyCode::K) {
|
if input.key_released(VirtualKeyCode::K) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::A);
|
self.joypad.release(Button::A);
|
||||||
}
|
}
|
||||||
if input.key_released(VirtualKeyCode::J) {
|
if input.key_released(VirtualKeyCode::J) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::B);
|
self.joypad.release(Button::B);
|
||||||
}
|
}
|
||||||
if input.key_released(VirtualKeyCode::W) {
|
if input.key_released(VirtualKeyCode::W) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::Up);
|
self.joypad.release(Button::Up);
|
||||||
}
|
}
|
||||||
if input.key_released(VirtualKeyCode::S) {
|
if input.key_released(VirtualKeyCode::S) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::Down);
|
self.joypad.release(Button::Down);
|
||||||
}
|
}
|
||||||
if input.key_released(VirtualKeyCode::A) {
|
if input.key_released(VirtualKeyCode::A) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::Left);
|
self.joypad.release(Button::Left);
|
||||||
}
|
}
|
||||||
if input.key_released(VirtualKeyCode::D) {
|
if input.key_released(VirtualKeyCode::D) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::Right);
|
self.joypad.release(Button::Right);
|
||||||
}
|
}
|
||||||
if input.key_released(VirtualKeyCode::N) {
|
if input.key_released(VirtualKeyCode::N) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::Start);
|
self.joypad.release(Button::Start);
|
||||||
}
|
}
|
||||||
if input.key_released(VirtualKeyCode::B) {
|
if input.key_released(VirtualKeyCode::B) {
|
||||||
change = true;
|
change = true;
|
||||||
self.bus.joypad.release(Button::Select);
|
self.joypad.release(Button::Select);
|
||||||
}
|
}
|
||||||
if change {
|
if change {
|
||||||
self.bus.set_interrupt_flag(Interrupt::Joypad, true);
|
self.bus.set_interrupt_flag(Interrupt::Joypad, true);
|
||||||
@ -99,7 +102,7 @@ impl Emulator {
|
|||||||
|
|
||||||
pub fn run(&mut self, cpu_cycles: Cycles, frame_buffer: &mut [u8]) {
|
pub fn run(&mut self, cpu_cycles: Cycles, frame_buffer: &mut [u8]) {
|
||||||
self.cpu.reset_cycles();
|
self.cpu.reset_cycles();
|
||||||
while self.cpu.get_cycles().to_t() <= cpu_cycles.0 {
|
while self.cpu.get_cycles().0 <= cpu_cycles.0 {
|
||||||
self.cpu.run(&mut self.bus);
|
self.cpu.run(&mut self.bus);
|
||||||
if self.bus.reset_timer {
|
if self.bus.reset_timer {
|
||||||
self.bus.reset_timer = false;
|
self.bus.reset_timer = false;
|
||||||
|
@ -41,6 +41,7 @@ impl Joypad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn press(&mut self, button: Button) {
|
pub fn press(&mut self, button: Button) {
|
||||||
|
println!("{:?} pressed", button);
|
||||||
match button {
|
match button {
|
||||||
Button::A => self.a = true,
|
Button::A => self.a = true,
|
||||||
Button::B => self.b = true,
|
Button::B => self.b = true,
|
||||||
@ -54,6 +55,7 @@ impl Joypad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(&mut self, button: Button) {
|
pub fn release(&mut self, button: Button) {
|
||||||
|
println!("{:?} released", button);
|
||||||
match button {
|
match button {
|
||||||
Button::A => self.a = false,
|
Button::A => self.a = false,
|
||||||
Button::B => self.b = false,
|
Button::B => self.b = false,
|
||||||
@ -66,7 +68,8 @@ impl Joypad {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self, byte: u8) -> u8 {
|
pub fn read(&self, bus: &mut Bus) -> u8 {
|
||||||
|
let byte = bus.read(JOYPAD_ADDRESS);
|
||||||
let direction = !get_bit(byte, BitIndex::I4);
|
let direction = !get_bit(byte, BitIndex::I4);
|
||||||
let action = !get_bit(byte, BitIndex::I5);
|
let action = !get_bit(byte, BitIndex::I5);
|
||||||
|
|
||||||
|
157
src/ppu.rs
157
src/ppu.rs
@ -4,7 +4,7 @@ use crate::utils::{
|
|||||||
set_bit,
|
set_bit,
|
||||||
to_bit_index,
|
to_bit_index,
|
||||||
};
|
};
|
||||||
use crate::bus::{Bus, AddressRange, BANK_ZERO, VIDEO_RAM, SPRITE_ATTRIBUTE_TABLE};
|
use crate::bus::{Bus, AddressRange, BANK_ZERO, VIDEO_RAM};
|
||||||
use crate::cpu::{Cycles, Interrupt};
|
use crate::cpu::{Cycles, Interrupt};
|
||||||
|
|
||||||
pub const LCD_WIDTH: u32 = 160;
|
pub const LCD_WIDTH: u32 = 160;
|
||||||
@ -94,60 +94,11 @@ pub struct PPU {
|
|||||||
prev_state: bool,
|
prev_state: bool,
|
||||||
cycles: Cycles,
|
cycles: Cycles,
|
||||||
rgba_frame: [[u8; 4]; FRAME_BUFFER_LENGTH as usize],
|
rgba_frame: [[u8; 4]; FRAME_BUFFER_LENGTH as usize],
|
||||||
sprite_buffer: Vec<Sprite>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sprite {
|
enum TileNumber {
|
||||||
x: u8,
|
Base(u16),
|
||||||
y: u8,
|
Absolute(u8),
|
||||||
tile_number: u8,
|
|
||||||
x_flip: bool,
|
|
||||||
y_flip: bool,
|
|
||||||
over_bg: bool,
|
|
||||||
palette_one: bool,
|
|
||||||
is_long: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sprite {
|
|
||||||
pub fn x(&self) -> u8 {
|
|
||||||
self.x
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_pixel(&self, lcd_x: u8, lcd_y: u8, bus: &Bus) -> Option<Pixel> {
|
|
||||||
todo!("Implement sprite flipping");
|
|
||||||
if lcd_x < self.x.saturating_sub(8) || lcd_x >= self.x {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let height: u8 = match self.is_long {
|
|
||||||
true => 16,
|
|
||||||
false => 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
let x = lcd_x.saturating_sub(self.x.saturating_sub(8));
|
|
||||||
let y = lcd_y.saturating_sub(self.y .saturating_sub(16));
|
|
||||||
|
|
||||||
let tile_line = y.rem_euclid(height) * 2;
|
|
||||||
let addr = 0x8000 + (self.tile_number as u16 * 16) + tile_line as u16;
|
|
||||||
|
|
||||||
let tile_byte_1 = bus.read(addr);
|
|
||||||
let tile_byte_2 = bus.read(addr + 1);
|
|
||||||
|
|
||||||
let pixel_index = (x as usize).rem_euclid(8);
|
|
||||||
|
|
||||||
if PPU::get_two_bit_byte_pixels(tile_byte_1, tile_byte_2)[pixel_index] == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let palette = match self.palette_one {
|
|
||||||
true => bus.read(OBJECT_PALETTE_1_ADDRESS),
|
|
||||||
false => bus.read(OBJECT_PALETTE_0_ADDRESS),
|
|
||||||
};
|
|
||||||
let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
|
|
||||||
|
|
||||||
Some(pixels[pixel_index])
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PPU {
|
impl PPU {
|
||||||
@ -156,7 +107,6 @@ impl PPU {
|
|||||||
prev_state: false,
|
prev_state: false,
|
||||||
cycles: Cycles(0),
|
cycles: Cycles(0),
|
||||||
rgba_frame: [[0xFF, 0xFF, 0xFF, 0]; FRAME_BUFFER_LENGTH as usize],
|
rgba_frame: [[0xFF, 0xFF, 0xFF, 0]; FRAME_BUFFER_LENGTH as usize],
|
||||||
sprite_buffer: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +120,7 @@ impl PPU {
|
|||||||
|
|
||||||
pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles, frame_buffer: &mut [u8]) {
|
pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles, frame_buffer: &mut [u8]) {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
while count < cycles.to_t() {
|
while count < cycles.0 {
|
||||||
self.cycle(bus, frame_buffer);
|
self.cycle(bus, frame_buffer);
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
@ -187,7 +137,6 @@ impl PPU {
|
|||||||
// Mode 2 OAM scan
|
// Mode 2 OAM scan
|
||||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM), true);
|
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM), true);
|
||||||
self.stat_interrupt(bus);
|
self.stat_interrupt(bus);
|
||||||
self.oam_search(bus);
|
|
||||||
} 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
|
||||||
self.draw_line(bus, frame_buffer);
|
self.draw_line(bus, frame_buffer);
|
||||||
@ -240,71 +189,6 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oam_search(&mut self, bus: &Bus) {
|
|
||||||
self.sprite_buffer = Vec::new();
|
|
||||||
if !PPU::get_lcd_control(bus, LCDControl::ObjectEnable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let long_sprites = PPU::get_lcd_control(bus, LCDControl::ObjectSize);
|
|
||||||
let mut addr = SPRITE_ATTRIBUTE_TABLE.begin();
|
|
||||||
while addr <= SPRITE_ATTRIBUTE_TABLE.end() {
|
|
||||||
// The gameboy only supports 10 sprites per line,
|
|
||||||
// but since we are on an emulator we can avoud that limitation
|
|
||||||
if self.sprite_buffer.len() >= 10 {
|
|
||||||
todo!("Make a setting for the 10 sprites per scanline");
|
|
||||||
// break;
|
|
||||||
}
|
|
||||||
let y = bus.read(addr);
|
|
||||||
let x = bus.read(addr + 1);
|
|
||||||
|
|
||||||
if x == 0 {
|
|
||||||
addr += 4;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let sprite_height: u8 = match long_sprites {
|
|
||||||
true => 16,
|
|
||||||
false => 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
let lcd_y = PPU::get_lcd_y(bus).saturating_add(16);
|
|
||||||
|
|
||||||
if lcd_y < y || lcd_y > (y + sprite_height) {
|
|
||||||
addr += 4;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let tile_number = bus.read(addr + 2);
|
|
||||||
let attributes = bus.read(addr + 3);
|
|
||||||
|
|
||||||
self.sprite_buffer.push(Sprite {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
tile_number,
|
|
||||||
is_long: long_sprites,
|
|
||||||
palette_one: get_bit(attributes, BitIndex::I4),
|
|
||||||
x_flip: get_bit(attributes, BitIndex::I5),
|
|
||||||
y_flip: get_bit(attributes, BitIndex::I6),
|
|
||||||
over_bg: get_bit(attributes, BitIndex::I7),
|
|
||||||
});
|
|
||||||
|
|
||||||
addr += 4;
|
|
||||||
}
|
|
||||||
self.sprite_buffer.sort_by(|a, b| a.x().cmp(&b.x()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_sprite_pixel(&self, lcd_x: u8, bus: &Bus) -> Option<Pixel> {
|
|
||||||
let lcd_y = PPU::get_lcd_y(bus);
|
|
||||||
for sprite in &self.sprite_buffer {
|
|
||||||
if let Some(pixel) = sprite.get_pixel(lcd_x, lcd_y, bus) {
|
|
||||||
return Some(pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_lcd_y(bus: &Bus) -> u8 {
|
fn get_lcd_y(bus: &Bus) -> u8 {
|
||||||
bus.read(LCD_Y_ADDRESS)
|
bus.read(LCD_Y_ADDRESS)
|
||||||
}
|
}
|
||||||
@ -374,12 +258,15 @@ impl PPU {
|
|||||||
bus.force_write(LCD_STATUS_ADDRESS, byte);
|
bus.force_write(LCD_STATUS_ADDRESS, byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tile_bytes(x: u8, y: u8, tilemap_area: u16, default_method: bool, bus: &Bus) -> (u8, u8) {
|
fn get_tile_bytes(x: u8, y: u8, tile_number_type: TileNumber, default_method: bool, bus: &Bus) -> (u8, u8) {
|
||||||
let index_x = x as u16 / 8;
|
let index_x = x as u16 / 8;
|
||||||
let index_y = (y as u16 / 8) * 32;
|
let index_y = (y as u16 / 8) * 32;
|
||||||
let index = index_x + index_y;
|
let index = index_x + index_y;
|
||||||
let tile_line = (y).rem_euclid(8) * 2;
|
let tile_line = (y).rem_euclid(8) * 2;
|
||||||
let tile_number = bus.read(tilemap_area + index as u16) as u16;
|
let tile_number = match tile_number_type {
|
||||||
|
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 {
|
let addr = if default_method {
|
||||||
0x8000 + tile_line as u16 + (tile_number * 16)
|
0x8000 + tile_line as u16 + (tile_number * 16)
|
||||||
} else {
|
} else {
|
||||||
@ -409,7 +296,7 @@ impl PPU {
|
|||||||
true => 0x9C00,
|
true => 0x9C00,
|
||||||
false => 0x9800,
|
false => 0x9800,
|
||||||
};
|
};
|
||||||
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, tilemap_area, default_mode, bus);
|
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 palette = bus.read(BACKGROUND_PALETTE_ADDRESS);
|
||||||
let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
|
let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
|
||||||
@ -433,7 +320,7 @@ impl PPU {
|
|||||||
true => 0x9C00,
|
true => 0x9C00,
|
||||||
false => 0x9800,
|
false => 0x9800,
|
||||||
};
|
};
|
||||||
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, tilemap_area, default_mode, bus);
|
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, TileNumber::Base(tilemap_area), default_mode, bus);
|
||||||
|
|
||||||
let bg_pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
|
let bg_pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
|
||||||
|
|
||||||
@ -450,13 +337,6 @@ impl PPU {
|
|||||||
frame_buffer[idx + 2] = rgba[2];
|
frame_buffer[idx + 2] = rgba[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(sprite_pixel) = self.find_sprite_pixel(lcd_x, bus) {
|
|
||||||
let rgba = PPU::get_rgba(sprite_pixel);
|
|
||||||
frame_buffer[idx] = rgba[0];
|
|
||||||
frame_buffer[idx + 1] = rgba[1];
|
|
||||||
frame_buffer[idx + 2] = rgba[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
lcd_x += 1;
|
lcd_x += 1;
|
||||||
|
|
||||||
/* for pixel in bg_pixels {
|
/* for pixel in bg_pixels {
|
||||||
@ -506,19 +386,6 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_two_bit_byte_pixels(byte1: u8, byte2: u8) -> [u8; 8] {
|
|
||||||
[
|
|
||||||
((byte1 >> 7) & 0b01) | ((byte2 >> 6) & 0b10),
|
|
||||||
((byte1 >> 6) & 0b01) | ((byte2 >> 5) & 0b10),
|
|
||||||
((byte1 >> 5) & 0b01) | ((byte2 >> 4) & 0b10),
|
|
||||||
((byte1 >> 4) & 0b01) | ((byte2 >> 3) & 0b10),
|
|
||||||
((byte1 >> 3) & 0b01) | ((byte2 >> 2) & 0b10),
|
|
||||||
((byte1 >> 2) & 0b01) | ((byte2 >> 1) & 0b10),
|
|
||||||
((byte1 >> 1) & 0b01) | (byte2 & 0b10),
|
|
||||||
(byte1 & 0b01) | ((byte2 << 1) & 0b10),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_byte_pixels(byte1: u8, byte2: u8, palette: u8) -> [Pixel; 8] {
|
fn get_byte_pixels(byte1: u8, byte2: u8, palette: u8) -> [Pixel; 8] {
|
||||||
[
|
[
|
||||||
PPU::get_pixel(PPU::get_palette(((byte1 >> 7) & 0b01) | ((byte2 >> 6) & 0b10), palette)),
|
PPU::get_pixel(PPU::get_palette(((byte1 >> 7) & 0b01) | ((byte2 >> 6) & 0b10), palette)),
|
||||||
|
@ -67,7 +67,7 @@ pub fn start_eventloop() {
|
|||||||
emulator.run(Cycles(70224), pixels.get_frame());
|
emulator.run(Cycles(70224), pixels.get_frame());
|
||||||
// emulator.draw(pixels.get_frame());
|
// emulator.draw(pixels.get_frame());
|
||||||
|
|
||||||
thread::sleep(time::Duration::from_millis(10));
|
// thread::sleep(time::Duration::from_millis(1000));
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
},
|
},
|
||||||
Event::RedrawRequested(_) => {
|
Event::RedrawRequested(_) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user