diff --git a/src/cpu.rs b/src/cpu.rs index 422c860..f4a6abd 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -350,10 +350,74 @@ impl CPU { fn call(&mut self, dst: u16) { let ip = self.ip; self.push(ip); - self.dump_stack(); + //self.dump_stack(); self.ip = dst; } + fn call_condition(&mut self, cond_str: String, cond: bool) -> u8 { + let dst = to_u16(self.load_args(2)); + if self.debug { + println!("CALL {} {:04X}", cond_str, dst); + } + if cond { + self.call(dst); + 24 + } else { + 12 + } + } + + fn ret_condition(&mut self, cond_str: String, cond: bool) -> u8 { + if self.debug { + println!("RET {}", cond_str); + } + if cond { + self.ret(); + 20 + } else { + 8 + } + } + + fn jmp_r(&mut self, addr: u8) { + let off: i8 = addr as i8; + if off < 0 { + self.ip -= (-off) as u16; + } else { + self.ip += off as u16; + } + } + + fn jmp_r_condition(&mut self, cond_str: String, cond: bool) -> u8 { + let t = self.load_args(1)[0]; + if self.debug { + println!("JR {} {:02X}", cond_str, t); + } + if cond { + self.jmp_r(t); + 12 + } else { + 8 + } + } + + fn jmp_p(&mut self, addr: u16) { + self.ip = addr; + } + + fn jmp_p_condition(&mut self, cond_str: String, cond: bool) -> u8 { + let t = to_u16(self.load_args(2)); + if self.debug { + println!("JP {} {:04X}", cond_str, t); + } + if cond { + self.jmp_p(t); + 12 + } else { + 8 + } + } + fn rst(&mut self, val: u8) -> u8 { // Make sure this is correct. if self.debug { @@ -413,7 +477,7 @@ impl CPU { fn ld_r_r(&mut self, reg_dst: usize, reg_src: usize) -> u8 { if self.debug { - println!("LD {}, {}", REG_NAMES[reg_dst], REG_NAMES[reg_src]) + // println!("LD {}, {}", REG_NAMES[reg_dst], REG_NAMES[reg_src]) } let sv = self.get_8bit_reg(reg_src); self.set_8bit_reg(reg_dst, sv); @@ -427,7 +491,7 @@ impl CPU { fn ld_r_v(&mut self, r: usize) -> u8 { let val: u8 = self.load_args(1)[0]; if self.debug { - println!("LD {}, {:02X}", REG_NAMES[r], val); + // println!("LD {}, {:02X}", REG_NAMES[r], val); } self.set_8bit_reg(r, val); if r == REG_N_HL { @@ -440,7 +504,7 @@ impl CPU { fn ld_rr_vv(&mut self, r1: usize, r2: usize) -> u8 { let val: u16 = to_u16(self.load_args(2)); if self.debug { - println!("LD {}{}, {:04X}", REG_NAMES[r1], REG_NAMES[r2], val); + // println!("LD {}{}, {:04X}", REG_NAMES[r1], REG_NAMES[r2], val); } self.set_pair_value(r1, r2, val); 12 @@ -515,7 +579,7 @@ impl CPU { fn ret(&mut self) { let new_ip: u16 = self.pop(); - self.dump_stack(); + //self.dump_stack(); self.ip = new_ip; } @@ -590,7 +654,9 @@ impl CPU { 0x04 => self.reg_inc(REG_N_B), 0x05 => self.reg_dec(REG_N_B), 0x06 => self.ld_r_v(REG_N_B), - + 0x07 => { + panic!("RLCA, not implemented"); + } 0x08 => { let a: u16 = to_u16(self.load_args(2)); if self.debug{ @@ -611,6 +677,9 @@ impl CPU { 0x0C => self.reg_inc(REG_N_C), 0x0D => self.reg_dec(REG_N_C), 0x0E => self.ld_r_v(REG_N_C), + 0x0F => panic!("RRCA not implemented."), + + 0x10 => panic!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]), 0x11 => self.ld_rr_vv(REG_N_D, REG_N_E), 0x12 => self.ld_dref_rr_a(REG_N_D, REG_N_E), 0x13 => self.inc_rr(REG_N_D, REG_N_E), @@ -635,16 +704,8 @@ impl CPU { 4 }, 0x18 => { - let args = self.load_args(1); - if self.debug { - println!("JR {:02X}", args[0] as i8); - } - let off: i8 = args[0] as i8; - if off < 0 { - self.ip -= (-off) as u16; - } else { - self.ip += off as u16; - } + let dst = self.load_args(1)[0]; + self.jmp_r(dst); 12 }, 0x19 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_D, REG_N_E), @@ -676,22 +737,11 @@ impl CPU { self.clear_flag(FLAG_H); 4 }, + + 0x20 => { - let args = self.load_args(1); - if self.debug { - println!("JR NZ {:02x}", args[0] as i8); - } - if self.flags & FLAG_Z == 0 { - let offset = args[0] as i8; - if offset < 0 { - self.ip -= (-offset) as u16 - } else { - self.ip += offset as u16; - } - 12 - } else { - 8 - } + let c = self.flags & FLAG_Z == 0; + self.jmp_r_condition("NZ".to_owned(), c) } 0x21 => self.ld_rr_vv(REG_N_H, REG_N_L), 0x22 => { @@ -707,23 +757,10 @@ 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!"), 0x28 => { - let args = self.load_args(1); - let target; - if (args[0] as i8) < 0 { - target = self.ip - (-(args[0] as i8)) as u16; - } else { - target = self.ip + args[0] as u16; - } - if self.debug { - println!("JR Z, {:04X}", target); - } - if self.flags & FLAG_Z > 0 { - self.ip = target; - 12 - } else { - 8 - } + let c = self.flags & FLAG_Z > 0; + self.jmp_r_condition("Z".to_owned(), c) }, 0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L), 0x2A => { @@ -748,22 +785,11 @@ impl CPU { self.set_flag(FLAG_H); 4 }, + + 0x30 => { - let args = self.load_args(1); - if self.debug { - println!("JR NC {:02x}", args[0] as i8); - } - if self.flags & FLAG_C == 0 { - let offset = args[0] as i8; - if offset < 0 { - self.ip -= (-offset) as u16 - } else { - self.ip += offset as u16; - } - 12 - } else { - 8 - } + let c = self.flags & FLAG_C == 0; + self.jmp_r_condition("NC".to_owned(), c) }, 0x31 => { let args = self.load_args(2); @@ -788,22 +814,11 @@ impl CPU { } let sp = self.sp.wrapping_add(1); self.sp = sp; - self.set_clear_flag(FLAG_Z, sp == 0); - self.set_clear_flag(FLAG_C, sp == 0); - self.clear_flag(FLAG_N); 8 } 0x34 => self.reg_inc(REG_N_HL), 0x35 => self.reg_dec(REG_N_HL), - 0x36 => { - let args = self.load_args(1); - if self.debug { - println!("LD (HL), {:02x}", args[0]); - } - let addr = self.get_pair_value(REG_N_H, REG_N_L); - self.interconnect.write_byte(addr, args[0]); - 12 - }, + 0x36 => self.ld_r_v(REG_N_HL), 0x37 => { if self.debug { println!("SCF"); @@ -814,21 +829,8 @@ impl CPU { 4 }, 0x38 => { - let args = self.load_args(1); - if self.debug { - println!("JR C {:02x}", args[0] as i8); - } - if self.flags & FLAG_C > 0 { - let offset = args[0] as i8; - if offset < 0 { - self.ip -= (-offset) as u16 - } else { - self.ip += offset as u16; - } - 12 - } else { - 8 - } + let c = self.flags & FLAG_C > 0; + self.jmp_r_condition("C".to_owned(), c) }, 0x39 => { if self.debug { @@ -841,18 +843,17 @@ impl CPU { self.clear_flag(FLAG_N); self.set_clear_flag(FLAG_C, old > v); + // TODO: H-carry flag 8 }, + 0x3A => panic!("LD A, (HL-) not implemented"), 0x3B => { if self.debug { println!("DEC SP"); } let sp = self.sp.wrapping_sub(1); self.sp = sp; - self.set_clear_flag(FLAG_Z, sp == 0); - self.set_clear_flag(FLAG_C, sp == 0xFFFF); - self.set_flag(FLAG_N); 8 } 0x3C => self.reg_inc(REG_N_A), @@ -965,11 +966,9 @@ impl CPU { } self.regs[REG_A] &= self.get_8bit_reg(reg_id); self.clear_flag(FLAG_N); - if self.regs[REG_A] == 0 { - self.set_flag(FLAG_Z); - } else { - self.clear_flag(FLAG_Z); - } + + let v = self.regs[REG_A]; + self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); self.clear_flag(FLAG_C); @@ -983,11 +982,8 @@ impl CPU { println!("XOR {}", REG_NAMES[reg_id]); } self.regs[REG_A] ^= self.get_8bit_reg(reg_id); - if self.regs[REG_A] == 0 { - self.set_flag(FLAG_Z); - } else { - self.set_flag(FLAG_Z); - } + let v = self.regs[REG_A]; + self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); @@ -1023,137 +1019,101 @@ impl CPU { self.set_flag(FLAG_N); self.set_clear_flag(FLAG_C, rval < val); self.set_clear_flag(FLAG_Z, rval == val); + // TODO H 4 }, + 0xC0 => { - if self.debug { - println!("RET NZ"); - } - if self.flags & FLAG_Z == 0 { - self.ret(); - 20 - } else { - 8 - } + let c = self.flags & FLAG_Z == 0; + self.ret_condition("NZ".to_owned(), c) }, 0xC1 => self.pop_rr(REG_N_B, REG_N_C), 0xC2 => { - let addr: u16 = to_u16(self.load_args(2)); - if self.debug { - println!("JP NZ {:04X}", addr); - } - if self.flags & FLAG_Z == 0 { - self.ip = addr; - 16 - } else { - 12 - } + let c = self.flags & FLAG_Z == 0; + self.jmp_p_condition("NZ".to_owned(), c) }, 0xC3 => { - let addr: u16 = to_u16(self.load_args(2)); - if self.debug { - println!("JP {:04X}", addr); - } - self.ip = addr; + let dst = to_u16(self.load_args(2)); + self.jmp_p(dst); 16 - } - 0xC4 => { - let target = to_u16(self.load_args(2)); - if self.debug { - println!("CALL NZ {:04X}", &target); - } - if self.flags & FLAG_Z == 0 { - self.call(target); - 24 - } else { - 12 - } }, + 0xC4 => { + let c = self.flags & FLAG_Z == 0; + self.call_condition("NZ".to_owned(), c) + } 0xC5 => self.push_rr(REG_N_B, REG_N_C), 0xC6 => { let val = self.load_args(1)[0]; if self.debug { - println!("ADD {:02X}", val); + println!("ADD A, {:02X}", val); } - self.regs[REG_A] = self.regs[REG_A].wrapping_add(val); + let o = self.regs[REG_A]; + let v = self.regs[REG_A].wrapping_add(val); + self.regs[REG_A] = v; + self.set_clear_flag(FLAG_Z, v == 0); + self.set_clear_flag(FLAG_C, v < o); + self.clear_flag(FLAG_N); + // TOOD H + 8 }, 0xC7 => self.rst(0x00), 0xC8 => { - if self.debug { - println!("RET Z"); - } - if self.flags & FLAG_Z > 0 { - self.ret(); - 20 - } else { - 8 - } - }, - 0xC9 => { - if self.debug { - println!("RET"); - } - let new_ip: u16 = self.pop(); - self.ip = new_ip; - 16 + let c = self.flags & FLAG_Z > 0; + self.ret_condition("Z".to_owned(), c) }, + 0xC9 => {self.ret(); 16}, + 0xCA => { + let c = self.flags & FLAG_Z > 0; + self.jmp_p_condition("Z".to_owned(), c) + } 0xCB => { // Prefix CB. This is annoying. self.run_prefix_instruction(); 12 // TODO: Verify that this is the case for all prefix instructions. }, 0xCC => { - let target = to_u16(self.load_args(2)); - if self.debug { - println!("CALL Z {:04X}", &target); - } - if self.flags & FLAG_Z > 0 { - self.call(target); - 24 - } else { - 12 - } - }, - 0xCD => { - let target = to_u16(self.load_args(2)); - if self.debug { - println!("CALL {:04X}", &target); - } - self.call(target); - 24 + let c = self.flags & FLAG_Z > 0; + self.call_condition("Z".to_owned(), c) }, + 0xCD => self.call_condition("".to_owned(), true), 0xCE => { let arg = self.load_args(1)[0]; if self.debug { - println!("ADC {:02X}", arg); + println!("ADC A, {:02X}", arg); } - self.regs[REG_A] = self.regs[REG_A].wrapping_add(arg); + let o = self.regs[REG_A]; + let mut v = self.regs[REG_A].wrapping_add(arg); + if self.flags & FLAG_C > 0 { - self.regs[REG_A] = self.regs[REG_A].wrapping_add(1); - } - if self.regs[REG_A] == 0 { - self.set_flag(FLAG_Z); - } else { - self.clear_flag(FLAG_Z); + v = v.wrapping_add(1); } + + self.regs[REG_A] = v; + + self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_N); - // TODO: FLAG_H, FLAG_C + self.set_clear_flag(FLAG_C, v < o); + // TODO: FLAG_H 8 }, 0xCF => self.rst(0x08), + + 0xD0 => { - if self.debug { - println!("RET NC"); - } - if self.flags & FLAG_C == 0 { - self.ret(); - 20 - } else { - 8 - } + let c = self.flags & FLAG_C == 0; + self.ret_condition("NC".to_owned(), c) }, 0xD1 => self.pop_rr(REG_N_D, REG_N_E), + 0xD2 => { + let c = self.flags & FLAG_C == 0; + self.jmp_p_condition("NC".to_owned(), c) + } + 0xD3 => panic!("NON-EXISTING OPCODE"), + 0xD4 => { + let c = self.flags & FLAG_C == 0; + self.call_condition("NC".to_owned(), c) + } 0xD5 => self.push_rr(REG_N_D, REG_N_E), 0xD6 => { let val = self.load_args(1)[0]; @@ -1167,40 +1127,46 @@ impl CPU { self.set_flag(FLAG_N); self.regs[REG_A] = rval.wrapping_sub(val); + + // TODO: FLAG_H 8 }, 0xD7 => self.rst(0x10), 0xD8 => { - if self.debug { - println!("RET C"); - } - if self.flags & FLAG_C > 0 { - self.ret(); - 20 - } else { - 8 - } + let c = self.flags & FLAG_C > 0; + self.ret_condition("C".to_owned(), c) }, 0xD9 => self.reti(), + 0xDA => { + let c = self.flags & FLAG_C > 0; + self.jmp_p_condition("C".to_owned(), c) + }, + 0xDB => panic!("NON-EXISTING OPCODE"), + 0xDC => { + let c = self.flags & FLAG_C > 0; + self.call_condition("C".to_owned(), c) + } + 0xDD => panic!("NON-EXISTING OPCODE"), 0xDE => { let arg = self.load_args(1)[0]; if self.debug { println!("SBC {:02X}", arg); } - self.regs[REG_A] = self.regs[REG_A].wrapping_sub(arg); + let o = self.regs[REG_A]; + let mut v = self.regs[REG_A].wrapping_sub(arg); + if self.flags & FLAG_C > 0 { - self.regs[REG_A] = self.regs[REG_A].wrapping_sub(1); - } - if self.regs[REG_A] == 0 { - self.set_flag(FLAG_Z); - } else { - self.clear_flag(FLAG_Z); + v = v.wrapping_sub(1); } + self.regs[REG_A] = v; + self.set_clear_flag(FLAG_Z, v == 0); + self.set_clear_flag(FLAG_C, v > o); self.set_flag(FLAG_N); - // TODO: FLAG_H, FLAG_C + // TODO: FLAG_H 8 }, 0xDF => self.rst(0x18), + 0xE0 => { let args = self.load_args(1); if self.debug { @@ -1214,17 +1180,24 @@ impl CPU { if self.debug { println!("LD (C), A"); } - let addr = 0xFF00 + self.get_8bit_reg(REG_N_C); - self.interconnect.write_byte(0xFF00 + addr as u16, self.regs[REG_A]); + let addr: u16 = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16; + self.interconnect.write_byte(addr, self.regs[REG_A]); 8 }, + 0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"), 0xE5 => self.push_rr(REG_N_H, REG_N_L), 0xE6 => { let val = self.load_args(1)[0]; if self.debug { println!("AND {:02X}", val); } - self.regs[REG_A] &= val; + let v = self.regs[REG_A] & val; + self.regs[REG_A] = v; + self.set_clear_flag(FLAG_Z, v == 0); + self.clear_flag(FLAG_N); + self.set_flag(FLAG_H); + self.clear_flag(FLAG_C); + 8 }, 0xE7 => self.rst(0x20), @@ -1238,6 +1211,7 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_Z); self.set_clear_flag(FLAG_C, t < sp); + // TODO FLAG_H self.sp = t; 16 } @@ -1245,8 +1219,7 @@ impl CPU { if self.debug { println!("JP (HL)"); } - let new_ip = (self.ip as i16 + self.get_8bit_reg(REG_N_HL) as i16) as u16; - self.ip = new_ip; + self.ip = self.get_pair_value(REG_N_H, REG_N_L); 4 }, 0xEA => { @@ -1257,23 +1230,22 @@ impl CPU { self.interconnect.write_byte(addr, self.regs[REG_A]); 16 }, + 0xEB ... 0xED => panic!("NON-EXISTING OPCODE"), 0xEE => { let arg = self.load_args(1)[0]; if self.debug { println!("XOR {:02X}", arg); } - self.regs[REG_A] ^= arg; - if self.regs[REG_A] == 0 { - self.set_flag(FLAG_Z); - } else { - self.clear_flag(FLAG_Z); - } + let v = self.regs[REG_A] ^ arg; + self.regs[REG_A] = v; + self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_H); self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); 8 }, 0xEF => self.rst(0x28), + 0xF0 => { let args = self.load_args(1); if self.debug { @@ -1298,45 +1270,65 @@ impl CPU { self.ime = false; 4 }, + 0xF4 => panic!("NON-EXISTING OPCODE"), 0xF5 => self.push_rr(REG_N_A, REG_N_F), 0xF6 => { let val = self.load_args(1)[0]; if self.debug { println!("OR {:02X}", val); } - self.regs[REG_A] |= val; + let v = self.regs[REG_A] | val; + self.regs[REG_A] = v; + self.set_clear_flag(FLAG_Z, v == 0); + self.clear_flag(FLAG_C); + self.clear_flag(FLAG_N); + self.clear_flag(FLAG_H); 8 }, 0xF7 => self.rst(0x30), 0xF8 => { - let arg = self.load_args(1)[0]; + let arg = self.load_args(1)[0] as i16; if self.debug { println!("LD HL, SP+{:02X}", arg); } - let v = self.sp.wrapping_add(arg as u16); + if arg < 0 { + let v: u16 = self.sp.wrapping_sub((-arg) as u16); + self.set_pair_value(REG_N_H, REG_N_L, v); + } else { + let v: u16 = self.sp.wrapping_add(arg as u16); + self.set_pair_value(REG_N_H, REG_N_L, v); + } self.clear_flag(FLAG_N); self.clear_flag(FLAG_Z); - self.set_pair_value(REG_N_H, REG_N_L, v); + // TODO: FLAG_H FLAG_C 12 - } + }, + 0xF9 => { + if self.debug { + println!("LD SP, HL"); + } + self.sp = self.get_pair_value(REG_N_H, REG_N_L); + 8 + }, + 0xFA => { + let addr = to_u16(self.load_args(2)); + if self.debug { + println!("LD A, ({:04X})", addr); + } + self.regs[REG_A] = self.interconnect.read_byte(addr); + 16 + }, 0xFB => { // Enable interrupts - TODO if self.debug { println!("EI"); } - self.ime = true; // interrupt master enable + //self.ime = true; // interrupt master enable 4 }, - 0xFA => { - let addr: u16 = to_u16(self.load_args(2)); - if self.debug { - println!("LD A, ({:04X})", addr); - } - let val: u8 = self.interconnect.read_byte(addr); - self.set_8bit_reg(REG_N_A, val); - 16 - }, + 0xFC | 0xFD => panic!("NON-EXISTING OPCODE"), + 0xFE => { let args = self.load_args(1); let rval = self.regs[REG_A]; diff --git a/src/display.rs b/src/display.rs index 1092925..a4cc36a 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,6 +1,9 @@ extern crate sdl2; extern crate libc; +use self::sdl2::event::Event; +use self::sdl2::keyboard::Keycode; + // Internal ram size const VRAM_SIZE: usize = 0x2000; @@ -64,6 +67,8 @@ pub struct Display { renderer: sdl2::render::Renderer<'static>, + event_pump: sdl2::EventPump, + vblank_fired: bool, stat_fired: bool, vblank_interrupt: bool, @@ -76,6 +81,7 @@ impl Display { let video_ctx = sdl_ctx.video().unwrap(); let wnd = video_ctx.window("RustBoy", (GB_PIXELS_X * SCALE) as u32, (GB_PIXELS_Y * SCALE) as u32).position_centered().build().expect("Failed to create window :<"); let renderer = wnd.renderer().build().expect("Could not build renderer"); + let mut event_pump = sdl_ctx.event_pump().expect("Getting event pump failed"); Display { control: 0, @@ -96,6 +102,8 @@ impl Display { oam: vec![0; OAM_SIZE].into_boxed_slice(), renderer: renderer, + event_pump: event_pump, + vblank_fired: false, stat_fired: false, vblank_interrupt: false, @@ -234,6 +242,16 @@ impl Display { } else { self.status &= !(1 << 2); } + + // Make sure the window is responsive: + for event in self.event_pump.poll_iter() { + match event { + Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + panic!("TODO: Proper shutdown"); + }, + _ => {} + } + } } fn renderscan(&mut self) { @@ -322,7 +340,7 @@ impl Display { } - if self.control & CTRL_BG_SPRITE_ENABLE > 0 { + if self.control & CTRL_BG_SPRITE_ENABLE > 0 { // panic!("Sprites not supported"); // Let's draw sprites. // TODO: Sprites with smaller X coordinate should