Add message loop; Implement all basic instructions

This commit is contained in:
Kevin Hamacher 2016-05-28 22:44:48 +02:00
parent 710b057f54
commit 001eb19df3
2 changed files with 247 additions and 237 deletions

View File

@ -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];

View File

@ -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