Improve timer; Add 16 px sprite support
This commit is contained in:
parent
1ad3d47c88
commit
b71397d16a
@ -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.")
|
||||
}
|
||||
|
||||
36
src/cpu.rs
36
src/cpu.rs
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -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);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
41
src/timer.rs
41
src/timer.rs
@ -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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user