Fix ADD, ADC, SUB, SBC, CP; Pass test
This commit is contained in:
parent
6455732043
commit
7dadc79078
@ -11,8 +11,8 @@ Display is able to render tiles + sprites, 8x16 sprites are implemented but unte
|
||||
|
||||
- Test 01 fails because of DAA
|
||||
- Test 02 fails because interrupts are not fully implemented.
|
||||
- Test 03 fails
|
||||
- Test 04 fails
|
||||
- Test 03 fails, probably because of flags.
|
||||
- Test 04 passes
|
||||
- Test 05 fails
|
||||
- Test 06 passes (LD R, R)
|
||||
- Test 07 fails
|
||||
|
||||
264
src/cpu.rs
264
src/cpu.rs
@ -103,6 +103,90 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn adc_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let mut new: u8 = old;
|
||||
let c: u8;
|
||||
if self.flags & FLAG_C == FLAG_C {
|
||||
c = 1;
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
new = new.wrapping_add(val);
|
||||
new = new.wrapping_add(c);
|
||||
self.regs[REG_A] = new;
|
||||
|
||||
self.clear_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, ((val + c) > 0 && new < old) || (c == 1 && new == old));
|
||||
self.set_clear_flag(FLAG_H, ((old & 0x0F) + (val & 0x0F) + c) > 0x0F);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let new: u8 = old.wrapping_add(val);
|
||||
let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16);
|
||||
self.regs[REG_A] = new;
|
||||
|
||||
self.clear_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, val > 0 && new < old);
|
||||
self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sbc_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let mut new: u8 = old as u8;
|
||||
let c: u8;
|
||||
if self.flags & FLAG_C == FLAG_C {
|
||||
c = 1;
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
new = new.wrapping_sub(val);
|
||||
new = new.wrapping_sub(c);
|
||||
|
||||
self.regs[REG_A] = new;
|
||||
|
||||
self.set_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, new > old || (new == old && c == 1));
|
||||
self.set_clear_flag(FLAG_H, ((old & 0x0F) - (val & 0x0F) - c) > 0x0F);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sub_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let new: u8 = old.wrapping_sub(val);
|
||||
let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16);
|
||||
self.regs[REG_A] = new;
|
||||
|
||||
self.set_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, new > old);
|
||||
self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cp_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let new: u8 = old.wrapping_sub(val);
|
||||
let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16);
|
||||
|
||||
self.set_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, new > old);
|
||||
self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn run_prefix_instruction(&mut self) {
|
||||
let instruction = self.read_byte(self.ip);
|
||||
@ -561,7 +645,7 @@ impl CPU {
|
||||
#[inline]
|
||||
fn rst(&mut self, val: u8) -> u8 {
|
||||
// Make sure this is correct.
|
||||
if self.debug {
|
||||
if self.debug || true {
|
||||
println!("RST {:02X}", val);
|
||||
}
|
||||
self.call(val as u16);
|
||||
@ -626,7 +710,7 @@ impl CPU {
|
||||
#[inline]
|
||||
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);
|
||||
@ -641,7 +725,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 {
|
||||
@ -655,7 +739,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
|
||||
@ -676,9 +760,21 @@ impl CPU {
|
||||
|
||||
#[inline]
|
||||
fn add_rr_rr(&mut self, r1: usize, r2: usize, r3: usize, r4: usize) -> u8 {
|
||||
if self.debug {
|
||||
println!("ADD {}{}, {}{}", REG_NAMES[r1], REG_NAMES[r2], REG_NAMES[r3], REG_NAMES[r4]);
|
||||
}
|
||||
|
||||
let val1 = self.get_pair_value(r1, r2);
|
||||
let val2 = self.get_pair_value(r3, r4);
|
||||
self.set_pair_value(r1, r2, val1.wrapping_add(val2));
|
||||
let res = val1.wrapping_add(val2);
|
||||
self.set_pair_value(r1, r2, res);
|
||||
|
||||
// We need to update the flags
|
||||
self.clear_flag(FLAG_N);
|
||||
|
||||
// Some magic formula
|
||||
self.set_clear_flag(FLAG_C, val1 as usize + val2 as usize & 0x10000 == 0x10000);
|
||||
self.set_clear_flag(FLAG_H, (val1 ^ val2 ^ res) & 0x1000 == 0x1000);
|
||||
8
|
||||
}
|
||||
|
||||
@ -961,22 +1057,22 @@ impl CPU {
|
||||
|
||||
if self.flags & FLAG_N == 0 {
|
||||
// Lower nibble
|
||||
if self.flags & FLAG_H > 0 || (v & 0xF) > 9 {
|
||||
if self.flags & FLAG_H == FLAG_H || (v & 0xF) > 9 {
|
||||
v += 0x06;
|
||||
}
|
||||
|
||||
// Higher nibble
|
||||
if self.flags & FLAG_C > 0 || v > 0x9F {
|
||||
if self.flags & FLAG_C == FLAG_C || v > 0x9F {
|
||||
v += 0x60;
|
||||
}
|
||||
} else {
|
||||
// Lower nibble
|
||||
if self.flags & FLAG_H > 0 {
|
||||
if self.flags & FLAG_H == FLAG_H {
|
||||
v = v.wrapping_sub(6) & 0xFF;
|
||||
}
|
||||
|
||||
// Higher nibble
|
||||
if self.flags & FLAG_C > 0 {
|
||||
if self.flags & FLAG_C == FLAG_C {
|
||||
v = v.wrapping_sub(0x60);
|
||||
}
|
||||
}
|
||||
@ -989,7 +1085,7 @@ impl CPU {
|
||||
4
|
||||
},
|
||||
0x28 => {
|
||||
let c = self.flags & FLAG_Z > 0;
|
||||
let c = self.flags & FLAG_Z == FLAG_Z;
|
||||
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),
|
||||
@ -1033,7 +1129,7 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("LD (HL-), A");
|
||||
}
|
||||
let mut addr = self.get_pair_value(REG_N_H, REG_N_L);
|
||||
let addr = self.get_pair_value(REG_N_H, REG_N_L);
|
||||
self.interconnect.write_byte(addr, self.regs[REG_A]);
|
||||
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1));
|
||||
8
|
||||
@ -1059,7 +1155,7 @@ impl CPU {
|
||||
4
|
||||
},
|
||||
0x38 => {
|
||||
let c = self.flags & FLAG_C > 0;
|
||||
let c = self.flags & FLAG_C == FLAG_C;
|
||||
self.jmp_r_condition("C".to_owned(), c)
|
||||
},
|
||||
0x39 => {
|
||||
@ -1073,8 +1169,8 @@ impl CPU {
|
||||
|
||||
self.clear_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_C, old > v);
|
||||
// TODO: H-carry flag
|
||||
|
||||
// Is this correct? I don't know:
|
||||
self.set_clear_flag(FLAG_H, (old & 0x8 | sp & 0x8) == 1 && v & 0x8 == 0);
|
||||
8
|
||||
},
|
||||
0x3A => {
|
||||
@ -1131,14 +1227,8 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("ADD {}", REG_NAMES[reg_id]);
|
||||
}
|
||||
let old = self.regs[REG_A];
|
||||
let new = old.wrapping_add(self.get_8bit_reg(reg_id));
|
||||
self.regs[REG_A] = new;
|
||||
|
||||
self.clear_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, new < old);
|
||||
// TODO: H
|
||||
let v = self.get_8bit_reg(reg_id);
|
||||
self.add_r(v);
|
||||
4
|
||||
}
|
||||
|
||||
@ -1149,17 +1239,8 @@ impl CPU {
|
||||
println!("ADC {}", REG_NAMES[reg_id]);
|
||||
}
|
||||
|
||||
let old = self.regs[REG_A];
|
||||
let mut new = old.wrapping_add(self.get_8bit_reg(reg_id));
|
||||
if self.flags & FLAG_C > 0 {
|
||||
new = new.wrapping_add(1);
|
||||
}
|
||||
self.regs[REG_A] = new;
|
||||
|
||||
self.clear_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, new < old);
|
||||
// TODO: H
|
||||
let v = self.get_8bit_reg(reg_id);
|
||||
self.adc_r(v);
|
||||
4
|
||||
}
|
||||
|
||||
@ -1169,13 +1250,8 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("SUB {}", REG_NAMES[reg_id]);
|
||||
}
|
||||
let old = self.regs[REG_A];
|
||||
let new = old.wrapping_sub(self.get_8bit_reg(reg_id));
|
||||
self.regs[REG_A] = new;
|
||||
self.set_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, new > old);
|
||||
// TODO: H
|
||||
let r = self.get_8bit_reg(reg_id);
|
||||
self.sub_r(r);
|
||||
4
|
||||
}
|
||||
|
||||
@ -1185,16 +1261,8 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("SBC {}", REG_NAMES[reg_id]);
|
||||
}
|
||||
let old = self.regs[REG_A];
|
||||
let mut new = old.wrapping_sub(self.get_8bit_reg(reg_id));
|
||||
if self.flags & FLAG_C > 0 {
|
||||
new = new.wrapping_sub(1);
|
||||
}
|
||||
self.regs[REG_A] = new;
|
||||
|
||||
self.set_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_Z, new == 0);
|
||||
self.set_clear_flag(FLAG_C, new > old);
|
||||
let r = self.get_8bit_reg(reg_id);
|
||||
self.sbc_r(r);
|
||||
4
|
||||
}
|
||||
|
||||
@ -1252,13 +1320,9 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("CP {}", REG_NAMES[reg_id]);
|
||||
}
|
||||
let val = self.get_8bit_reg(reg_id);
|
||||
let rval = self.regs[REG_A];
|
||||
|
||||
self.set_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_C, rval < val);
|
||||
self.set_clear_flag(FLAG_Z, rval == val);
|
||||
// TODO H
|
||||
let v = self.get_8bit_reg(reg_id);
|
||||
self.cp_r(v);
|
||||
4
|
||||
},
|
||||
|
||||
@ -1286,24 +1350,19 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("ADD A, {:02X}", 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
|
||||
|
||||
self.add_r(val);
|
||||
|
||||
8
|
||||
},
|
||||
0xC7 => self.rst(0x00),
|
||||
0xC8 => {
|
||||
let c = self.flags & FLAG_Z > 0;
|
||||
let c = self.flags & FLAG_Z == FLAG_Z;
|
||||
self.ret_condition("Z".to_owned(), c)
|
||||
},
|
||||
0xC9 => {self.ret(); 16},
|
||||
0xCA => {
|
||||
let c = self.flags & FLAG_Z > 0;
|
||||
let c = self.flags & FLAG_Z == FLAG_Z;
|
||||
self.jmp_p_condition("Z".to_owned(), c)
|
||||
}
|
||||
0xCB => {
|
||||
@ -1312,7 +1371,7 @@ impl CPU {
|
||||
12 // TODO: Verify that this is the case for all prefix instructions.
|
||||
},
|
||||
0xCC => {
|
||||
let c = self.flags & FLAG_Z > 0;
|
||||
let c = self.flags & FLAG_Z == FLAG_Z;
|
||||
self.call_condition("Z".to_owned(), c)
|
||||
},
|
||||
0xCD => self.call_condition("".to_owned(), true),
|
||||
@ -1321,19 +1380,7 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("ADC A, {:02X}", arg);
|
||||
}
|
||||
let o = self.regs[REG_A];
|
||||
let mut v = self.regs[REG_A].wrapping_add(arg);
|
||||
|
||||
if self.flags & FLAG_C > 0 {
|
||||
v = v.wrapping_add(1);
|
||||
}
|
||||
|
||||
self.regs[REG_A] = v;
|
||||
|
||||
self.set_clear_flag(FLAG_Z, v == 0);
|
||||
self.clear_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_C, v < o);
|
||||
// TODO: FLAG_H
|
||||
self.adc_r(arg);
|
||||
8
|
||||
},
|
||||
0xCF => self.rst(0x08),
|
||||
@ -1360,29 +1407,22 @@ impl CPU {
|
||||
println!("SUB {:02X}", val);
|
||||
}
|
||||
|
||||
let rval = self.regs[REG_A];
|
||||
self.set_clear_flag(FLAG_C, val > rval);
|
||||
self.set_clear_flag(FLAG_Z, val == rval);
|
||||
self.set_flag(FLAG_N);
|
||||
|
||||
self.regs[REG_A] = rval.wrapping_sub(val);
|
||||
|
||||
// TODO: FLAG_H
|
||||
self.sub_r(val);
|
||||
8
|
||||
},
|
||||
0xD7 => self.rst(0x10),
|
||||
0xD8 => {
|
||||
let c = self.flags & FLAG_C > 0;
|
||||
let c = self.flags & FLAG_C == FLAG_C;
|
||||
self.ret_condition("C".to_owned(), c)
|
||||
},
|
||||
0xD9 => self.reti(),
|
||||
0xDA => {
|
||||
let c = self.flags & FLAG_C > 0;
|
||||
let c = self.flags & FLAG_C == FLAG_C;
|
||||
self.jmp_p_condition("C".to_owned(), c)
|
||||
},
|
||||
0xDB => panic!("NON-EXISTING OPCODE"),
|
||||
0xDC => {
|
||||
let c = self.flags & FLAG_C > 0;
|
||||
let c = self.flags & FLAG_C == FLAG_C;
|
||||
self.call_condition("C".to_owned(), c)
|
||||
}
|
||||
0xDD => panic!("NON-EXISTING OPCODE"),
|
||||
@ -1391,17 +1431,7 @@ impl CPU {
|
||||
if self.debug {
|
||||
println!("SBC {:02X}", arg);
|
||||
}
|
||||
let o = self.regs[REG_A];
|
||||
let mut v = self.regs[REG_A].wrapping_sub(arg);
|
||||
|
||||
if self.flags & FLAG_C > 0 {
|
||||
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
|
||||
self.sbc_r(arg);
|
||||
8
|
||||
},
|
||||
0xDF => self.rst(0x18),
|
||||
@ -1441,16 +1471,21 @@ impl CPU {
|
||||
},
|
||||
0xE7 => self.rst(0x20),
|
||||
0xE8 => {
|
||||
let arg = self.load_args(1)[0];
|
||||
let arg = self.load_args(1)[0] as i8;
|
||||
if self.debug {
|
||||
println!("ADD SP, {:02X}", arg);
|
||||
}
|
||||
let t = self.sp.wrapping_add(arg as u16);
|
||||
let t: u16;
|
||||
if arg > 0 {
|
||||
t = self.sp.wrapping_add(arg as u16);
|
||||
} else {
|
||||
t = self.sp.wrapping_sub((-arg) as u16);
|
||||
}
|
||||
let sp = self.sp;
|
||||
self.clear_flag(FLAG_N);
|
||||
self.clear_flag(FLAG_Z);
|
||||
self.set_clear_flag(FLAG_C, t < sp);
|
||||
// TODO FLAG_H
|
||||
self.set_clear_flag(FLAG_C, (sp ^ arg as u16 ^ t) & 0x100 == 0x100);
|
||||
self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ t) & 0x10 == 0x10);
|
||||
self.sp = t;
|
||||
16
|
||||
}
|
||||
@ -1526,21 +1561,26 @@ impl CPU {
|
||||
},
|
||||
0xF7 => self.rst(0x30),
|
||||
0xF8 => {
|
||||
let arg = self.load_args(1)[0] as i16;
|
||||
let arg = self.load_args(1)[0] as i8;
|
||||
if self.debug {
|
||||
println!("LD HL, SP+{:02X}", arg);
|
||||
}
|
||||
|
||||
self.clear_flag(FLAG_N);
|
||||
self.clear_flag(FLAG_Z);
|
||||
let sp = self.sp;
|
||||
|
||||
if arg < 0 {
|
||||
let v: u16 = self.sp.wrapping_sub((-arg) as u16);
|
||||
self.set_pair_value(REG_N_H, REG_N_L, v);
|
||||
self.set_clear_flag(FLAG_C, (sp ^ arg as u16 ^ v) & 0x100 == 0x100);
|
||||
self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10);
|
||||
} else {
|
||||
let v: u16 = self.sp.wrapping_add(arg as u16);
|
||||
self.set_pair_value(REG_N_H, REG_N_L, v);
|
||||
self.set_clear_flag(FLAG_C, (sp ^ arg as u16 ^ v) & 0x100 == 0x100);
|
||||
self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10);
|
||||
}
|
||||
self.clear_flag(FLAG_N);
|
||||
self.clear_flag(FLAG_Z);
|
||||
// TODO: FLAG_H FLAG_C
|
||||
12
|
||||
},
|
||||
0xF9 => {
|
||||
@ -1570,15 +1610,11 @@ impl CPU {
|
||||
|
||||
0xFE => {
|
||||
let args = self.load_args(1);
|
||||
let rval = self.regs[REG_A];
|
||||
if self.debug {
|
||||
println!("CP {:02X}", args[0]);
|
||||
}
|
||||
self.set_flag(FLAG_N);
|
||||
self.set_clear_flag(FLAG_C, args[0] > rval);
|
||||
self.set_clear_flag(FLAG_Z, args[0] == rval);
|
||||
|
||||
// TODO H
|
||||
self.cp_r(args[0]);
|
||||
8
|
||||
},
|
||||
0xFF => self.rst(0x38),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user