GBC features
This commit is contained in:
parent
2f03b015f1
commit
74234dd405
@ -34,6 +34,8 @@ pub struct CPU {
|
||||
debug: bool,
|
||||
|
||||
halted: bool,
|
||||
|
||||
trigger_once: bool,
|
||||
}
|
||||
|
||||
fn to_u16(args: Args) -> u16 {
|
||||
@ -68,6 +70,8 @@ impl CPU {
|
||||
ime: false,
|
||||
debug: false,
|
||||
halted: false,
|
||||
|
||||
trigger_once: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -949,6 +953,11 @@ impl CPU {
|
||||
|
||||
pub fn run_instruction(&mut self) -> u8 {
|
||||
// self.debug = !self.interconnect.is_boot_rom();
|
||||
if !self.trigger_once && !self.interconnect.is_boot_rom() {
|
||||
self.trigger_once = true;
|
||||
self.regs[REG_A] = 0x11;
|
||||
println!("Patching reg");
|
||||
}
|
||||
|
||||
/*
|
||||
if self.ip >= 100 && self.ip < 120 {
|
||||
|
||||
152
src/display.rs
152
src/display.rs
@ -42,7 +42,7 @@ const SPRITE_OBJ_BG_PRIORITY: u8 = 1 << 7;
|
||||
const SPRITE_Y_FLIP: u8 = 1 << 6;
|
||||
const SPRITE_X_FLIP: u8 = 1 << 5;
|
||||
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
|
||||
/*
|
||||
@ -122,11 +122,25 @@ impl Sprite {
|
||||
}
|
||||
|
||||
fn palette(&self) -> u8 {
|
||||
// GB
|
||||
/*
|
||||
if (self.flags & SPRITE_PALETTE_NO) == 0 {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
*/
|
||||
// GBC
|
||||
self.flags & 0b111
|
||||
}
|
||||
|
||||
// GBC only
|
||||
fn vram_bank(&self) -> u8 {
|
||||
if (self.flags & SPRITE_TILE_VRAM_BANK) == 0 {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,8 +148,8 @@ pub struct Display {
|
||||
control: u8,
|
||||
status: u8,
|
||||
background_palette: u8,
|
||||
object_palette_0: u8,
|
||||
object_palette_1: u8,
|
||||
// Only 0 and 1 for GB
|
||||
object_palette: [u8; 256], //4 * 2 * 8],
|
||||
scrollx: u8,
|
||||
scrolly: u8,
|
||||
windowx: u8,
|
||||
@ -143,9 +157,11 @@ pub struct Display {
|
||||
curline: u8,
|
||||
lyc: u8,
|
||||
|
||||
vram: Box<[u8]>,
|
||||
vram0: Box<[u8]>,
|
||||
vram1: Box<[u8]>,
|
||||
oam: Box<[u8]>,
|
||||
|
||||
vram_bank: u8,
|
||||
current_ticks: u16,
|
||||
current_mode: DisplayMode,
|
||||
// TODO
|
||||
@ -160,6 +176,13 @@ pub struct Display {
|
||||
|
||||
frameskip: u8,
|
||||
frame_no: u8,
|
||||
|
||||
// GBC:
|
||||
background_palette_autoinc: bool,
|
||||
background_palette_index: u8,
|
||||
background_palette_c: [u8; 256], // 0x40],
|
||||
|
||||
object_palette_index: u8,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
@ -179,8 +202,7 @@ impl Display {
|
||||
control: 0,
|
||||
status: 0,
|
||||
background_palette: 0,
|
||||
object_palette_0: 0,
|
||||
object_palette_1: 0,
|
||||
object_palette: [0u8; 256], // 64],
|
||||
scrollx: 0,
|
||||
scrolly: 0,
|
||||
windowx: 0,
|
||||
@ -190,7 +212,9 @@ impl Display {
|
||||
|
||||
current_ticks: 0,
|
||||
current_mode: DisplayMode::default(),
|
||||
vram: vec![0; VRAM_SIZE].into_boxed_slice(),
|
||||
vram0: vec![0; VRAM_SIZE].into_boxed_slice(),
|
||||
vram1: vec![0; VRAM_SIZE].into_boxed_slice(),
|
||||
vram_bank: 0,
|
||||
oam: vec![0; OAM_SIZE].into_boxed_slice(),
|
||||
renderer: renderer,
|
||||
|
||||
@ -201,6 +225,11 @@ impl Display {
|
||||
pixels: pixels,
|
||||
frameskip: 0,
|
||||
frame_no: 0,
|
||||
|
||||
background_palette_autoinc: false,
|
||||
background_palette_index: 0,
|
||||
background_palette_c: [0u8; 256], // 0x40],
|
||||
object_palette_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,7 +301,13 @@ impl Display {
|
||||
#[inline]
|
||||
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
match addr {
|
||||
0x8000..=0x9FFF => self.vram[(addr - 0x8000) as usize] = val,
|
||||
0x8000..=0x9FFF => {
|
||||
if self.vram_bank == 0 {
|
||||
self.vram0[(addr - 0x8000) as usize] = val
|
||||
} else {
|
||||
self.vram1[(addr - 0x8000) as usize] = val
|
||||
}
|
||||
}
|
||||
0xFE00..=0xFE9F => self.oam[(addr - 0xFE00) as usize] = val,
|
||||
0xFF40 => self.control = val,
|
||||
0xFF41 => self.status = val,
|
||||
@ -280,9 +315,27 @@ impl Display {
|
||||
0xFF43 => self.scrollx = val,
|
||||
0xFF44 => self.curline = 0,
|
||||
0xFF45 => self.lyc = val,
|
||||
// GB classic
|
||||
0xFF47 => self.background_palette = val,
|
||||
0xFF48 => self.object_palette_0 = val,
|
||||
0xFF49 => self.object_palette_1 = val,
|
||||
0xFF48 => self.object_palette[0] = val,
|
||||
0xFF49 => self.object_palette[1] = val,
|
||||
// GBC
|
||||
0xFF68 => {
|
||||
self.background_palette_index = val;
|
||||
self.background_palette_autoinc = (val >> 7) != 0;
|
||||
}
|
||||
0xFF69 => {
|
||||
self.background_palette_c[self.background_palette_index as usize] = val;
|
||||
if self.background_palette_autoinc {
|
||||
self.background_palette_index += 1;
|
||||
}
|
||||
}
|
||||
0xFF6A => {
|
||||
self.object_palette_index = val;
|
||||
}
|
||||
0xFF6B => {
|
||||
self.object_palette[self.object_palette_index as usize] = val;
|
||||
}
|
||||
0xFF4A => {
|
||||
if self.windowy != val {
|
||||
println!("WY set to {:02X}", val);
|
||||
@ -295,6 +348,7 @@ impl Display {
|
||||
}
|
||||
self.windowx = val;
|
||||
}
|
||||
0xFF4f => self.vram_bank = val,
|
||||
_ => panic!("Display: Write {:02X} to {:04X} unsupported", val, addr),
|
||||
}
|
||||
}
|
||||
@ -302,7 +356,13 @@ impl Display {
|
||||
#[inline]
|
||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||
match addr {
|
||||
0x8000..=0x9FFF => self.vram[(addr - 0x8000) as usize],
|
||||
0x8000..=0x9FFF => {
|
||||
if self.vram_bank == 0 {
|
||||
self.vram0[(addr - 0x8000) as usize]
|
||||
} else {
|
||||
self.vram1[(addr - 0x8000) as usize]
|
||||
}
|
||||
}
|
||||
0xFE00..=0xFE9F => self.oam[(addr - 0xFE00) as usize],
|
||||
0xFF40 => self.control,
|
||||
0xFF41 => self.status,
|
||||
@ -311,10 +371,11 @@ impl Display {
|
||||
0xFF44 => self.curline,
|
||||
0xFF45 => self.lyc,
|
||||
0xFF47 => self.background_palette,
|
||||
0xFF48 => self.object_palette_0,
|
||||
0xFF49 => self.object_palette_1,
|
||||
0xFF48 => self.object_palette[0],
|
||||
0xFF49 => self.object_palette[1],
|
||||
0xFF4A => self.windowy,
|
||||
0xFF4B => self.windowx,
|
||||
0xFF4F => self.vram_bank | 0b1111_1110,
|
||||
_ => panic!("Display: Read from {:04X} unsupported", addr),
|
||||
}
|
||||
}
|
||||
@ -452,10 +513,15 @@ impl Display {
|
||||
let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode?
|
||||
|
||||
let tile_addr = tile_base_addr + tile_offset_y * 2;
|
||||
let tile_line_1 = self.vram[tile_addr + 0];
|
||||
let tile_line_2 = self.vram[tile_addr + 1];
|
||||
let tile_line_3 = self.vram[tile_addr + 2];
|
||||
let tile_line_4 = self.vram[tile_addr + 3];
|
||||
let vram = if sprite.vram_bank() == 0 {
|
||||
&*self.vram0
|
||||
} else {
|
||||
&*self.vram1
|
||||
};
|
||||
let tile_line_1 = vram[tile_addr + 0];
|
||||
let tile_line_2 = vram[tile_addr + 1];
|
||||
let tile_line_3 = vram[tile_addr + 2];
|
||||
let tile_line_4 = vram[tile_addr + 3];
|
||||
|
||||
// We need to draw this.
|
||||
let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0;
|
||||
@ -499,19 +565,21 @@ impl Display {
|
||||
continue;
|
||||
}
|
||||
|
||||
// GB
|
||||
/*
|
||||
let c = (b1 as u8) * 2 + b2 as u8;
|
||||
let lookup: [u8; 4] = match sprite.palette() {
|
||||
0 => [
|
||||
self.object_palette_0 & 3,
|
||||
(self.object_palette_0 >> 2) & 3,
|
||||
(self.object_palette_0 >> 4) & 3,
|
||||
(self.object_palette_0 >> 6) & 3,
|
||||
self.object_palette[0] & 3,
|
||||
(self.object_palette[0] >> 2) & 3,
|
||||
(self.object_palette[0] >> 4) & 3,
|
||||
(self.object_palette[0] >> 6) & 3,
|
||||
],
|
||||
1 => [
|
||||
self.object_palette_1 & 3,
|
||||
(self.object_palette_1 >> 2) & 3,
|
||||
(self.object_palette_1 >> 4) & 3,
|
||||
(self.object_palette_1 >> 6) & 3,
|
||||
self.object_palette[1] & 3,
|
||||
(self.object_palette[1] >> 2) & 3,
|
||||
(self.object_palette[1] >> 4) & 3,
|
||||
(self.object_palette[1] >> 6) & 3,
|
||||
],
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@ -524,6 +592,20 @@ impl Display {
|
||||
sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]),
|
||||
PixelOrigin::Sprite,
|
||||
);
|
||||
*/
|
||||
let c = ((b1 as u8) * 2 + b2 as u8) as usize;
|
||||
let a = self.object_palette[sprite.palette() as usize * 8 + c * 2];
|
||||
let b = self.object_palette[sprite.palette() as usize * 8 + c * 2 + 1];
|
||||
let ab = ((b as u16) << 8) | a as u16;
|
||||
let r = (ab & 0b11111) as u8;
|
||||
let g = ((ab >> 5) & 0b11111) as u8;
|
||||
let b = ((ab >> 10) & 0b11111) as u8;
|
||||
self.set_pixel(
|
||||
x.wrapping_add(x_o),
|
||||
render_y,
|
||||
sdl2::pixels::Color::RGB(r, g, b),
|
||||
PixelOrigin::Sprite,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -608,13 +690,21 @@ impl Display {
|
||||
background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize;
|
||||
|
||||
// Obtain tile ID in this area
|
||||
let tile_id = self.vram[vram_offset];
|
||||
let tile_id = self.vram0[vram_offset];
|
||||
|
||||
// Obtain tile information
|
||||
let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id);
|
||||
let addr = tile_base_addr + (tile_offset_y as usize) * 2;
|
||||
let tile_line_1 = self.vram[addr];
|
||||
let tile_line_2 = self.vram[addr + 1];
|
||||
|
||||
// GBC stuff
|
||||
let vram = if (self.vram1[vram_offset] >> 3) == 1 {
|
||||
&*self.vram0
|
||||
} else {
|
||||
&*self.vram1
|
||||
};
|
||||
|
||||
let tile_line_1 = vram[addr];
|
||||
let tile_line_2 = vram[addr + 1];
|
||||
|
||||
// Get the correct bit
|
||||
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) != 0;
|
||||
@ -662,13 +752,13 @@ impl Display {
|
||||
window_map + (tile_index_y as usize) * 32 + tile_index_x as usize;
|
||||
|
||||
// Obtain tile ID in this area
|
||||
let tile_id = self.vram[vram_offset];
|
||||
let tile_id = self.vram0[vram_offset];
|
||||
|
||||
// Obtain tile information
|
||||
let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id);
|
||||
let tile_addr = tile_base_addr + (tile_offset_y as usize) * 2;
|
||||
let tile_line_1 = self.vram[tile_addr];
|
||||
let tile_line_2 = self.vram[tile_addr + 1];
|
||||
let tile_line_1 = self.vram0[tile_addr];
|
||||
let tile_line_2 = self.vram0[tile_addr + 1];
|
||||
|
||||
// Get the correct bit
|
||||
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) > 0;
|
||||
|
||||
@ -292,6 +292,7 @@ impl Interconnect {
|
||||
0xFF10..=0xFF26 => self.sound.sound_object.lock().unwrap().read_byte(addr),
|
||||
0xFF30..=0xFF3F => self.sound.sound_object.lock().unwrap().read_byte(addr),
|
||||
0xFF40..=0xFF4B => self.display.read_byte(addr),
|
||||
0xFF4F => self.display.read_byte(addr),
|
||||
0xFF50 => self.disable_bootrom,
|
||||
0xFF51 => self.vram_dma_source_high,
|
||||
0xFF52 => self.vram_dma_source_low,
|
||||
@ -299,6 +300,7 @@ impl Interconnect {
|
||||
0xFF54 => self.vram_dma_destination_low,
|
||||
0xFF55 => self.vram_dma_length,
|
||||
0xFF56 => self.infrared_com_port,
|
||||
0xFF6A | 0xFF6B => self.display.read_byte(addr),
|
||||
0xFF70 => self.wram_bank,
|
||||
0xFF80..=0xFFFE => self.hiram[(addr - 0xFF80) as usize],
|
||||
0xFFFF => self.interrupt,
|
||||
@ -369,6 +371,7 @@ impl Interconnect {
|
||||
self.write_byte(0xFE00 | x, dma_b);
|
||||
}
|
||||
}
|
||||
0xFF4F => self.display.write_byte(addr, val),
|
||||
0xFF50 => {
|
||||
println!("Disabling boot rom.");
|
||||
self.disable_bootrom = val;
|
||||
@ -413,6 +416,8 @@ impl Interconnect {
|
||||
}
|
||||
}
|
||||
}
|
||||
0xFF68 | 0xFF69 => self.display.write_byte(addr, val),
|
||||
0xFF6A | 0xFF6B => self.display.write_byte(addr, val),
|
||||
0xFF80..=0xFFFE => {
|
||||
self.hiram[(addr - 0xFF80) as usize] = val;
|
||||
}
|
||||
|
||||
@ -103,7 +103,8 @@ impl Channel1 {
|
||||
if self.tick_state == 7 {
|
||||
self.envelope.clock();
|
||||
}
|
||||
|
||||
// TODO: Sweep
|
||||
// TODO: Sweep in adition mode + overflow? stop.
|
||||
self.tick_state += 1;
|
||||
|
||||
if self.tick_state == 8 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user