mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 10:12:11 +00:00
Compare commits
3 Commits
abac2b3bf3
...
e48e8881e7
Author | SHA1 | Date | |
---|---|---|---|
e48e8881e7 | |||
758d17675e | |||
eb0f61aebd |
@ -29,10 +29,9 @@ Any help or suggestion is welcome!
|
|||||||
- [ ] MBC7
|
- [ ] MBC7
|
||||||
- [ ] HuC1
|
- [ ] HuC1
|
||||||
- [x] Save files
|
- [x] Save files
|
||||||
- [ ] Web Assembly support (because this is a Rust project and it has to support Web Assembly)
|
|
||||||
- [ ] Gameboy boot ROM (not important for now)
|
- [ ] Gameboy boot ROM (not important for now)
|
||||||
- [ ] Gameboy Color compatibility
|
- [ ] Gameboy Color compatibility (WIP)
|
||||||
- [ ] Sound
|
- [ ] Sound (WIP)
|
||||||
- [ ] Many code refactors and optimizations
|
- [ ] Many code refactors and optimizations
|
||||||
|
|
||||||
# Resources
|
# Resources
|
||||||
|
@ -36,6 +36,7 @@ pub struct Bus {
|
|||||||
pub timer: Timer,
|
pub timer: Timer,
|
||||||
pub sound: Sound,
|
pub sound: Sound,
|
||||||
pub interrupts: Interrupts,
|
pub interrupts: Interrupts,
|
||||||
|
pub cgb_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
@ -67,6 +68,7 @@ impl Bus {
|
|||||||
timer: Timer::new(),
|
timer: Timer::new(),
|
||||||
sound: Sound::new(),
|
sound: Sound::new(),
|
||||||
interrupts: Interrupts::new(),
|
interrupts: Interrupts::new(),
|
||||||
|
cgb_mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hardware registers after the bootrom
|
// Hardware registers after the bootrom
|
||||||
|
22
src/cpu.rs
22
src/cpu.rs
@ -87,6 +87,21 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_cgb() -> Self {
|
||||||
|
Self {
|
||||||
|
a: 0x11,
|
||||||
|
f: 0x00,
|
||||||
|
b: 0x00,
|
||||||
|
c: 0x00,
|
||||||
|
d: 0xFF,
|
||||||
|
e: 0x56,
|
||||||
|
h: 0x00,
|
||||||
|
l: 0x0D,
|
||||||
|
sp: 0xFFFE,
|
||||||
|
pc: 0x0100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(&self, register: Register) -> u16 {
|
pub fn get(&self, register: Register) -> u16 {
|
||||||
match register {
|
match register {
|
||||||
Register::A => self.a as u16,
|
Register::A => self.a as u16,
|
||||||
@ -818,9 +833,12 @@ pub struct CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CPU {
|
impl CPU {
|
||||||
pub fn new() -> Self {
|
pub fn new(cgb_mode: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
registers: Registers::new(),
|
registers: match cgb_mode {
|
||||||
|
true => Registers::new_cgb(),
|
||||||
|
false => Registers::new(),
|
||||||
|
},
|
||||||
cycles: Cycles(0),
|
cycles: Cycles(0),
|
||||||
last_op_cycles: Cycles(0),
|
last_op_cycles: Cycles(0),
|
||||||
exec_calls_count: 0,
|
exec_calls_count: 0,
|
||||||
|
@ -16,9 +16,11 @@ pub struct Emulator {
|
|||||||
|
|
||||||
impl Emulator {
|
impl Emulator {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let bus = Bus::new();
|
||||||
|
let cgb_mode = bus.cgb_mode;
|
||||||
Self {
|
Self {
|
||||||
bus: Bus::new(),
|
bus,
|
||||||
cpu: CPU::new(),
|
cpu: CPU::new(cgb_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
src/ppu.rs
36
src/ppu.rs
@ -71,9 +71,9 @@ impl ColorPalette {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn extract_rgb(color: u16) -> RGBA {
|
fn extract_rgb(color: u16) -> RGBA {
|
||||||
let red = (color & 0b1111).to_be_bytes()[1];
|
let red = (color & 0b11111).to_be_bytes()[1];
|
||||||
let green = ((color >> 4) & 0b1111).to_be_bytes()[1];
|
let green = ((color >> 5) & 0b11111).to_be_bytes()[1];
|
||||||
let blue = ((color >> 8) & 0b1111).to_be_bytes()[1];
|
let blue = ((color >> 10) & 0b11111).to_be_bytes()[1];
|
||||||
RGBA((red << 3) | (red >> 2), (green << 3) | (green >> 2), (blue << 3) | (blue >> 2), 0)
|
RGBA((red << 3) | (red >> 2), (green << 3) | (green >> 2), (blue << 3) | (blue >> 2), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ impl Sprite {
|
|||||||
self.x
|
self.x
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pixel(&mut self, lcd_x: u8, lcd_y: u8, vram: &[u8], last_bg_index: u8, lcd_control: u8, is_cgb: bool) -> Option<(Pixel, bool, u8)> {
|
pub fn get_pixel(&mut self, lcd_x: u8, lcd_y: u8, vram: &[u8], last_bg_index: u8, last_bg_priority: bool, lcd_control: u8, is_cgb: bool) -> Option<(Pixel, bool, u8)> {
|
||||||
if !LCDControl::ObjectEnable.get(lcd_control) {
|
if !LCDControl::ObjectEnable.get(lcd_control) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -204,6 +204,10 @@ impl Sprite {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_cgb && LCDControl::BackgroundPriority.get(lcd_control) && last_bg_priority {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
if self.over_bg && (last_bg_index & 0b11) != 0 {
|
if self.over_bg && (last_bg_index & 0b11) != 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -244,8 +248,8 @@ impl Sprite {
|
|||||||
let addr = 0x8000 + (tile_number as u16 * 16) + tile_line as u16;
|
let addr = 0x8000 + (tile_number as u16 * 16) + tile_line as u16;
|
||||||
|
|
||||||
let vram_start = 0x8000;
|
let vram_start = 0x8000;
|
||||||
let tile_byte_1 = vram[(addr - vram_start) as usize];
|
let tile_byte_1 = vram[(0x2000 * self.vram_bank as usize) + (addr - vram_start) as usize];
|
||||||
let tile_byte_2 = vram[(addr - vram_start + 1) as usize];
|
let tile_byte_2 = vram[(0x2000 * self.vram_bank as usize) + (addr - vram_start + 1) as usize];
|
||||||
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
||||||
self.bit_pixels = Some(bit_pixels_array);
|
self.bit_pixels = Some(bit_pixels_array);
|
||||||
|
|
||||||
@ -274,6 +278,7 @@ pub struct PPU {
|
|||||||
sprite_buffer: Vec<Sprite>,
|
sprite_buffer: Vec<Sprite>,
|
||||||
window_y_counter: u8,
|
window_y_counter: u8,
|
||||||
last_bg_index: u8,
|
last_bg_index: u8,
|
||||||
|
last_bg_priority: bool,
|
||||||
bg_palette: u8,
|
bg_palette: u8,
|
||||||
lcd_control: u8,
|
lcd_control: u8,
|
||||||
current_background_pixels: Option<([u8; 8], u8)>,
|
current_background_pixels: Option<([u8; 8], u8)>,
|
||||||
@ -306,6 +311,7 @@ impl PPU {
|
|||||||
sprite_buffer: Vec::new(),
|
sprite_buffer: Vec::new(),
|
||||||
window_y_counter: 0,
|
window_y_counter: 0,
|
||||||
last_bg_index: 0,
|
last_bg_index: 0,
|
||||||
|
last_bg_priority: false,
|
||||||
bg_palette: 0,
|
bg_palette: 0,
|
||||||
lcd_control: 0,
|
lcd_control: 0,
|
||||||
current_background_pixels: None,
|
current_background_pixels: None,
|
||||||
@ -482,7 +488,7 @@ impl PPU {
|
|||||||
self.lcd_y = self.lcd_y.wrapping_add(1);
|
self.lcd_y = self.lcd_y.wrapping_add(1);
|
||||||
self.lcd_x = 0;
|
self.lcd_x = 0;
|
||||||
if self.window_drawn {
|
if self.window_drawn {
|
||||||
self.window_y_counter += 1;
|
self.window_y_counter = self.window_y_counter.saturating_add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frame completed
|
// Frame completed
|
||||||
@ -598,7 +604,7 @@ impl PPU {
|
|||||||
fn find_sprite_pixel(&mut self) -> Option<(Pixel, bool, u8)> {
|
fn find_sprite_pixel(&mut self) -> Option<(Pixel, bool, u8)> {
|
||||||
let lcd_y = self.lcd_y;
|
let lcd_y = self.lcd_y;
|
||||||
for sprite in &mut self.sprite_buffer {
|
for sprite in &mut self.sprite_buffer {
|
||||||
if let Some(pixel) = sprite.get_pixel(self.lcd_x, lcd_y, &self.vram, self.last_bg_index, self.lcd_control, self.cgb_mode) {
|
if let Some(pixel) = sprite.get_pixel(self.lcd_x, lcd_y, &self.vram, self.last_bg_index, self.last_bg_priority, self.lcd_control, self.cgb_mode) {
|
||||||
return Some(pixel);
|
return Some(pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -693,9 +699,16 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_window_pixel(&mut self) -> Option<(Pixel, u8)> {
|
fn get_window_pixel(&mut self) -> Option<(Pixel, u8)> {
|
||||||
if !self.window_enable {
|
if !self.window_enable {
|
||||||
|
self.last_bg_index = 0b00;
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
if !self.cgb_mode {
|
||||||
|
if !self.background_priority || !self.window_enable {
|
||||||
|
self.last_bg_index = 0b00;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let lcd_y = self.lcd_y;
|
let lcd_y = self.lcd_y;
|
||||||
let lcd_x = self.lcd_x;
|
let lcd_x = self.lcd_x;
|
||||||
@ -732,6 +745,7 @@ impl PPU {
|
|||||||
let (tile_byte_1, tile_byte_2, info) = self.get_tile_bytes(x, y, tilemap_area, default_mode);
|
let (tile_byte_1, tile_byte_2, info) = self.get_tile_bytes(x, y, tilemap_area, default_mode);
|
||||||
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
||||||
self.current_window_pixels = Some((bit_pixels_array, info.palette_number));
|
self.current_window_pixels = Some((bit_pixels_array, info.palette_number));
|
||||||
|
self.last_bg_priority = info.bg_to_oam_priority;
|
||||||
|
|
||||||
(bit_pixels_array, info.palette_number)
|
(bit_pixels_array, info.palette_number)
|
||||||
},
|
},
|
||||||
@ -746,7 +760,8 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_background_pixel(&mut self) -> Option<(Pixel, u8)> {
|
fn get_background_pixel(&mut self) -> Option<(Pixel, u8)> {
|
||||||
if !self.background_priority {
|
if !self.cgb_mode && !self.background_priority {
|
||||||
|
self.last_bg_index = 0b00;
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let lcd_y = self.lcd_y;
|
let lcd_y = self.lcd_y;
|
||||||
@ -772,6 +787,7 @@ impl PPU {
|
|||||||
let (tile_byte_1, tile_byte_2, info) = self.get_tile_bytes(x, y, tilemap_area, default_mode);
|
let (tile_byte_1, tile_byte_2, info) = self.get_tile_bytes(x, y, tilemap_area, default_mode);
|
||||||
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
||||||
self.current_background_pixels = Some((bit_pixels_array, info.palette_number));
|
self.current_background_pixels = Some((bit_pixels_array, info.palette_number));
|
||||||
|
self.last_bg_priority = info.bg_to_oam_priority;
|
||||||
|
|
||||||
(bit_pixels_array, info.palette_number)
|
(bit_pixels_array, info.palette_number)
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user