Improve timer; Add 16 px sprite support

This commit is contained in:
Kevin Hamacher 2016-05-29 13:01:36 +02:00
parent 1ad3d47c88
commit b71397d16a
6 changed files with 117 additions and 24 deletions

View File

@ -106,6 +106,15 @@ impl Cartridge {
}
}
fn write_byte_none(&mut self, addr: u16, val: u8) {
match addr {
0xA000 ... 0xBFFF => {
self.ram[addr as usize - 0xA000] = val;
}
_ => println!("No MBC, unable to write {:02X} to {:04X}", val, addr),
}
}
fn write_byte_mbc3(&mut self, addr: u16, val: u8) {
match addr {
0x0000 ... 0x1FFF => {
@ -143,7 +152,7 @@ impl Cartridge {
pub fn write_byte(&mut self, addr: u16, val: u8) {
match self.mbc_type {
MemoryBankControllerType::None => println!("Cartridge: No MBC found, can not write to ROM ({:02X} to {:04X})", val, addr),
MemoryBankControllerType::None => self.write_byte_none(addr, val),
MemoryBankControllerType::MBC3 => self.write_byte_mbc3(addr, val),
_ => panic!("MBC not supported.")
}

View File

@ -742,7 +742,7 @@ impl CPU {
let e_pending = pending & enabled;
if e_pending & interconnect::INTERRUPT_DISPLAY_VBLANK > 0 {
println!("Handling vblank interrupt");
// println!("Handling vblank interrupt");
self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK);
} else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 {
println!("Handling display stat interrupt");
@ -906,7 +906,39 @@ impl CPU {
0x24 => self.reg_inc(REG_N_H),
0x25 => self.reg_dec(REG_N_H),
0x26 => self.ld_r_v(REG_N_H),
0x27 => panic!("DAA not implemented!"),
0x27 => {
// Logic copied from some other emulator
let mut v = self.regs[REG_A] as u16;
if self.flags & FLAG_N > 0{
// Lower nibble
if self.flags & FLAG_H > 0 || v & 0xF > 9 {
v += 0x06;
}
// Higher nibble
if self.flags & FLAG_C > 0 || v > 0x9F {
v += 0x60;
}
} else {
// Lower nibble
if self.flags & FLAG_H > 0 {
v = v.wrapping_sub(6) & 0xFF;
}
// Higher nibble
if self.flags & FLAG_C > 0 {
v = v.wrapping_sub(0x60);
}
}
self.clear_flag(FLAG_H);
self.set_clear_flag(FLAG_C, v == 0x100);
self.set_clear_flag(FLAG_Z, v & 0xFF == 0);
self.regs[REG_A] = v as u8;
4
},
0x28 => {
let c = self.flags & FLAG_Z > 0;
self.jmp_r_condition("Z".to_owned(), c)

View File

@ -327,33 +327,56 @@ impl Display {
}
if self.control & CTRL_BG_SPRITE_ENABLE > 0 && false {
// panic!("Sprites not supported");
if self.control & CTRL_BG_SPRITE_ENABLE > 0 {
// Let's draw sprites.
// TODO: Sprites with smaller X coordinate should
// should be in front
// TODO: Draw only up to 10 sprites per line
if self.control & CTRL_BG_SPRITE_SIZE > 0 {
println!("Wide sprites not tested!");
}
for i in 0 .. 39 {
let y: u8 = self.oam[i * 4 + 0];
let x: u8 = self.oam[i * 4 + 1];
let mut y: u8 = self.oam[i * 4 + 0];
let mut x: u8 = self.oam[i * 4 + 1];
let t_num: u8 = self.oam[i * 4 + 2];
let flags: u8 = self.oam[i * 4 + 3];
if x == 0 || y == 0 {
// This sprite is hidden
continue;
}
x = x.wrapping_sub(8);
y = y.wrapping_sub(16);
// Is this sprite on the current line?
if (y + 8) >= render_y && y <= render_y {
if y.wrapping_add(8) >= render_y && y <= render_y {
let tile_offset_y: usize = render_y as usize - y as usize;
let tile_base_addr: usize = 0x1000 + t_num as usize * 16;
let tile_base_addr: usize = 0 + t_num as usize * 16;
let tile_line_1 = self.vram[tile_base_addr + tile_offset_y * 2];
let tile_line_2 = self.vram[tile_base_addr + tile_offset_y * 2 + 1];
let tile_line_3 = self.vram[tile_base_addr + tile_offset_y * 2 + 2];
let tile_line_4 = self.vram[tile_base_addr + tile_offset_y * 2 + 3];
// We need to draw this.
for x_o in 0 .. 8 {
let b1: bool = (tile_line_1 & 1 << (7 - x_o)) > 0;
let b2: bool = (tile_line_2 & 1 << (7 - x_o)) > 0;
let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0;
let limit = match wide_mode {
true => 16,
false => 8
};
for x_o in 0 .. limit {
let mut b1: bool;
let mut b2: bool;
let mut factor = 0;
if wide_mode && x_o > 7 {
b1 = (tile_line_3 & 1 << (14 - x_o)) > 0;
b2 = (tile_line_4 & 1 << (14 - x_o)) > 0;
} else {
b1 = (tile_line_1 & 1 << (7 - x_o)) > 0;
b2 = (tile_line_2 & 1 << (7 - x_o)) > 0;
}
if b1 {
factor += 64;
}

View File

@ -210,6 +210,7 @@ impl Interconnect {
0xFF10 ... 0xFF26 => {
self.sound.read_byte(addr)
},
0xFF30 ... 0xFF3F => self.sound.read_byte(addr),
0xFF40 ... 0xFF4B => {
self.display.read_byte(addr)
},
@ -278,18 +279,17 @@ impl Interconnect {
0xFF10 ... 0xFF26 => {
self.sound.write_byte(addr, val);
},
0xFF30 ... 0xFF3F => self.sound.write_byte(addr, val),
// Exclude DMA transfer, we will do this below
0xFF40 ... 0xFF45 | 0xFF47 ... 0xFF4B => {
self.display.write_byte(addr, val);
},
0xFF46 => {
println!("OAM DMA transfer: ");
// println!("OAM DMA transfer");
for x in 0x00 .. 0x9F {
let dma_b = self.read_byte(((val as u16) << 8) | x);
self.write_byte(0xFE00 | x, dma_b);
print!("{:02X} ", val);
}
println!("");
}
0xFF50 => {
println!("Disabling boot rom.");

View File

@ -23,7 +23,9 @@ impl Sound {
0xFF24 => self.sound_channel_volume_control = val,
0xFF25 => self.sound_output_terminal_selector = val,
0xFF26 => self.enabled = val,
_ => println!("Sound: Write {:02X} to {:04X} unsupported", val, addr),
_ => {
// println!("Sound: Write {:02X} to {:04X} unsupported", val, addr);
},
}
}

View File

@ -1,10 +1,12 @@
#[derive(Default, Debug)]
pub struct Timer {
tima: u8,
tima: u8, // Timer counter, interrupt on overflow
tma: u8,
tac: u8,
tac: u8, // 00 = 4096 Hz [10240 ticks], 01 = 262144 Hz [160 ticks], 10 = 65536 Hz [640], 11 = 16384 Hz[2560]. Bit 2 0 = stop, 1 = start
div: u8, // Incremented at speed of 16384Hz
timer_interrupt: bool,
ctr: u16,
tick_counter: u16,
div_tick_counter: u16,
}
impl Timer {
@ -13,15 +15,39 @@ impl Timer {
}
pub fn tick(&mut self, ticks: u16) {
self.ctr += ticks;
if self.ctr > 0x1000 {
self.ctr = 0;
self.timer_interrupt = true;
// One tick 1/4.194304MHz on regular speed?
if self.tac & 1 << 2 == 1 { // Is timer enabled?
self.tick_counter += ticks;
let req_ticks = match self.tac & 3 {
0 => 10240,
1 => 160,
2 => 640,
3 => 2560,
_ => unreachable!()
};
if self.tick_counter > req_ticks {
if self.tima == 0xFF {
self.timer_interrupt = true;
self.tima = 0;
} else {
self.tima += 1;
}
self.tick_counter -= req_ticks;
}
}
// The div reg will always tick
self.div_tick_counter += ticks;
if self.div_tick_counter > 2560 {
self.div = self.div.wrapping_add(1);
self.div_tick_counter -= 2560;
}
}
pub fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0xFF04 => self.div = 0,
0xFF05 => self.tima = val,
0xFF06 => self.tma = val,
0xFF07 => self.tac = val,
@ -31,6 +57,7 @@ impl Timer {
pub fn read_byte(&self, addr: u16) -> u8 {
match addr {
0xFF04 => self.div,
0xFF05 => self.tima,
0xFF06 => self.tma,
0xFF07 => self.tac,