GBC features

This commit is contained in:
Kevin Hamacher 2020-02-14 22:16:26 +01:00
parent 2f03b015f1
commit 74234dd405
4 changed files with 137 additions and 32 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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 {