From 6d675616f1005c1f52c6b2d1efd64fa208781a48 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Sat, 28 May 2016 23:34:32 +0200 Subject: [PATCH] Add SET instruction; Add WRAM support --- src/cpu.rs | 91 +++++++++++++++++++++++++++++++++++++++++++-- src/display.rs | 2 +- src/interconnect.rs | 27 +++++++++++--- src/timer.rs | 21 +++++++++-- 4 files changed, 129 insertions(+), 12 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 417395c..de2e0ba 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -384,6 +384,80 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 7)); } + + // Set bits + 0xC0 ... 0xC7 => { + // Set 0th bit + let reg_id = (instruction - 0xC0) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 0, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 0)); + } + 0xC8 ... 0xCF => { + // Set 1th bit + let reg_id = (instruction - 0xC8) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 1, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 1)); + } + 0xD0 ... 0xD7 => { + // Set 2nd bit + let reg_id = (instruction - 0xD0) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 2, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 2)); + } + 0xD8 ... 0xDF => { + // Set 3th bit + let reg_id = (instruction - 0xD8) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 3, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 3)); + } + 0xE0 ... 0xE7 => { + // Set 4th bit + let reg_id = (instruction - 0xE0) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 4, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 4)); + } + 0xE8 ... 0xEF => { + // Set 5th bit + let reg_id = (instruction - 0xE8) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 5, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 5)); + } + 0xF0 ... 0xF7 => { + // Set 6th bit + let reg_id = (instruction - 0xF0) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 6, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 6)); + } + 0xF8 ... 0xFF => { + // Set 7th bit + let reg_id = (instruction - 0xF8) as usize; + let reg_content = self.get_8bit_reg(reg_id); + if self.debug { + println!("SET 7, {}", REG_NAMES[reg_id]); + } + self.set_8bit_reg(reg_id, reg_content | (1 << 7)); + } _ => { panic!("Unsupported prefix instruction: {:x}", instruction); } @@ -672,7 +746,10 @@ impl CPU { self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK); } else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 { println!("Handling display stat interrupt"); - self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_STAT); + self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT); + } else if e_pending & interconnect::INTERRUPT_TIMER_OVERFLOW > 0{ + println!("Handling timer interrupt"); + self.handle_interrupt(0x50, interconnect::INTERRUPT_TIMER_OVERFLOW); } else if e_pending > 0 { panic!("Unknown pending interrupt: {:02X}", e_pending); } @@ -905,7 +982,15 @@ impl CPU { 8 }, - 0x3A => panic!("LD A, (HL-) not implemented"), + 0x3A => { + if self.debug { + println!("LD A, (HL-)"); + } + let mut addr = self.get_pair_value(REG_N_H, REG_N_L); + self.regs[REG_A] = self.interconnect.read_byte(addr); + self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1)); + 8 + } 0x3B => { if self.debug { println!("DEC SP"); @@ -1382,7 +1467,7 @@ impl CPU { if self.debug { println!("EI"); } - //self.ime = true; // interrupt master enable + self.ime = true; // interrupt master enable 4 }, 0xFC | 0xFD => panic!("NON-EXISTING OPCODE"), diff --git a/src/display.rs b/src/display.rs index a4cc36a..fe859b2 100644 --- a/src/display.rs +++ b/src/display.rs @@ -340,7 +340,7 @@ impl Display { } - if self.control & CTRL_BG_SPRITE_ENABLE > 0 { + if self.control & CTRL_BG_SPRITE_ENABLE > 0 && false { // panic!("Sprites not supported"); // Let's draw sprites. // TODO: Sprites with smaller X coordinate should diff --git a/src/interconnect.rs b/src/interconnect.rs index 4eec04c..36ffaed 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -1,6 +1,8 @@ -const RAM_SIZE: usize = 0x2000; +// const RAM_SIZE: usize = 0x2000; +const WRAM_SIZE: usize = 0x8000; const HIRAM_SIZE: usize = (0xFFFE - 0xFF80) + 1; +pub const INTERRUPT_TIMER_OVERFLOW: u8 = 1 << 2; pub const INTERRUPT_DISPLAY_STAT: u8 = 1 << 1; pub const INTERRUPT_DISPLAY_VBLANK: u8 = 1 << 0; @@ -15,6 +17,7 @@ pub struct Interconnect { cartridge: cartridge::Cartridge, ram: Box<[u8]>, hiram: Box<[u8]>, + wram_bank: u8, sound: sound::Sound, display: display::Display, interrupt: u8, @@ -24,6 +27,7 @@ pub struct Interconnect { serial: serial::Serial, timer: timer::Timer, + } impl Interconnect { @@ -31,8 +35,9 @@ impl Interconnect { Interconnect { bios: bios, cartridge: cartridge::Cartridge::new(rom), - ram: vec![0; RAM_SIZE].into_boxed_slice(), + ram: vec![0; WRAM_SIZE].into_boxed_slice(), hiram: vec![0; HIRAM_SIZE].into_boxed_slice(), + wram_bank: 0, sound: sound::Sound::new(), display: display::Display::new(), // Refactor those @@ -57,6 +62,10 @@ impl Interconnect { if self.display.stat_interrupt() { self.interrupt_request_flags |= INTERRUPT_DISPLAY_STAT; } + + if self.timer.timer_interrupt() { + self.interrupt_request_flags |= INTERRUPT_TIMER_OVERFLOW; + } } pub fn is_boot_rom(&self) -> bool { @@ -78,9 +87,12 @@ impl Interconnect { 0x100 ... 0x7FFF => self.cartridge.read_byte(addr), 0x8000 ... 0x9FFF => self.display.read_byte(addr), 0xA000 ... 0xBFFF => self.cartridge.read_byte(addr), - 0xC000 ... 0xDFFF => { + 0xC000 ... 0xCFFF => { self.ram[(addr - 0xC000) as usize] }, + 0xD000 ... 0xDFFF => { + self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] + } 0xFF00 => 0xFF, // TODO: This is the input stuff 0xFF01 ... 0xFF02 => self.serial.read_byte(addr), 0xFF04 ... 0xFF07 => self.timer.read_byte(addr), @@ -98,7 +110,8 @@ impl Interconnect { }, 0xFF56 => { self.infrared_com_port - } + }, + 0xFF70 => self.wram_bank, 0xFF80 ... 0xFFFE => { self.hiram[(addr - 0xFF80) as usize] }, @@ -130,9 +143,12 @@ impl Interconnect { 0x0000 ... 0x7FFF => self.cartridge.write_byte(addr, val), 0x8000 ... 0x9FFF => self.display.write_byte(addr, val), 0xA000 ... 0xBFFF => self.cartridge.write_byte(addr, val), - 0xC000 ... 0xDFFF => { + 0xC000 ... 0xCFFF => { self.ram[(addr - 0xC000) as usize] = val; }, + 0xD000 ... 0xDFFF => { + self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] = val; + } 0xFE00 ... 0xFE9F => self.display.write_byte(addr, val), // OAM 0xFF01 ... 0xFF02 => self.serial.write_byte(addr, val), 0xFF04 ... 0xFF07 => self.timer.write_byte(addr, val), @@ -162,6 +178,7 @@ impl Interconnect { 0xFF56 => { self.infrared_com_port = val; }, + 0xFF70 => self.wram_bank = val, 0xFF80 ... 0xFFFE => { self.hiram[(addr - 0xFF80) as usize] = val; }, diff --git a/src/timer.rs b/src/timer.rs index 3645131..85d64e4 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -2,7 +2,8 @@ pub struct Timer { tima: u8, tma: u8, - tac: u8 + tac: u8, + timer_interrupt: bool } impl Timer { @@ -15,7 +16,7 @@ impl Timer { 0xFF05 => self.tima = val, 0xFF06 => self.tma = val, 0xFF07 => self.tac = val, - _ => panic!("Timer: Write {:02X} to {:04X} unsupported", val, addr), + _ => println!("Timer: Write {:02X} to {:04X} unsupported", val, addr), } } @@ -24,7 +25,21 @@ impl Timer { 0xFF05 => self.tima, 0xFF06 => self.tma, 0xFF07 => self.tac, - _ => panic!("Timer: Read from {:04X} unsupported", addr), + _ => { + println!("Timer: Read from {:04X} unsupported", addr); + 0 + }, + } + } + + pub fn timer_interrupt(&mut self) -> bool { + // Returns whether or not a vblank interrupt should be done + // Yes, this is polling, and yes, this sucks.\ + if self.timer_interrupt { + self.timer_interrupt = false; + true + } else { + false } } }