Add message loop; Implement all basic instructions
This commit is contained in:
parent
710b057f54
commit
001eb19df3
464
src/cpu.rs
464
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];
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user