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