From 233c36ce7ee96e69b9c064bc04c6fc921ea26b14 Mon Sep 17 00:00:00 2001 From: Andrew Keeton Date: Thu, 13 Nov 2014 19:52:10 -0500 Subject: [PATCH 1/5] Add compare_test(). --- src/machine.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index e36093c..4848ae2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1030,3 +1030,53 @@ fn branch_if_overflow_set_test() { machine.branch_if_overflow_set(Address(0xABCD)); assert_eq!(machine.registers.program_counter, Address(0xABCD)); } + +#[test] +fn compare_test() { + let mut machine = Machine::new(); + + machine.execute_instruction( + (instruction::LDA, instruction::UseImmediate(127)) + ); + + machine.compare(127); + assert!( machine.registers.status.contains(PS_ZERO )); + assert!( machine.registers.status.contains(PS_CARRY )); + assert!(!machine.registers.status.contains(PS_NEGATIVE)); + + machine.execute_instruction( + (instruction::LDA, instruction::UseImmediate(127)) + ); + + machine.compare(1); + assert!(!machine.registers.status.contains(PS_ZERO )); + assert!( machine.registers.status.contains(PS_CARRY )); + assert!(!machine.registers.status.contains(PS_NEGATIVE)); + + machine.execute_instruction( + (instruction::LDA, instruction::UseImmediate(1)) + ); + + machine.compare(2); + assert!(!machine.registers.status.contains(PS_ZERO )); + assert!(!machine.registers.status.contains(PS_CARRY )); + assert!(!machine.registers.status.contains(PS_NEGATIVE)); + + machine.execute_instruction( + (instruction::LDA, instruction::UseImmediate(1)) + ); + + machine.compare(2); + assert!(!machine.registers.status.contains(PS_ZERO )); + assert!(!machine.registers.status.contains(PS_CARRY )); + assert!( machine.registers.status.contains(PS_NEGATIVE)); + + machine.execute_instruction( + (instruction::LDA, instruction::UseImmediate(20)) + ); + + machine.compare(-50); + assert!(!machine.registers.status.contains(PS_ZERO )); + assert!( machine.registers.status.contains(PS_CARRY )); + assert!(!machine.registers.status.contains(PS_NEGATIVE)); +} \ No newline at end of file From 8b962fd542917fa4a93d57e4222b7ca5393a6dbc Mon Sep 17 00:00:00 2001 From: Andrew Keeton Date: Thu, 13 Nov 2014 20:08:56 -0500 Subject: [PATCH 2/5] Add compare(). Add more cases to compare_test(). --- src/machine.rs | 63 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 4848ae2..57aad5d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -619,6 +619,37 @@ impl Machine { } } + + // From http://www.6502.org/tutorials/compare_beyond.html: + // If the Z flag is 0, then A <> NUM and BNE will branch + // If the Z flag is 1, then A = NUM and BEQ will branch + // If the C flag is 0, then A (unsigned) < NUM (unsigned) and BCC will branch + // If the C flag is 1, then A (unsigned) >= NUM (unsigned) and BCS will branch + // ... + // The N flag contains most significant bit of the of the subtraction result. + fn compare(&mut self, val: u8) { + let a = self.registers.accumulator; + + if a as u8 >= val as u8 { + self.registers.status.insert(PS_CARRY); + } else { + self.registers.status.remove(PS_CARRY); + } + + if a as i8 == val as i8 { + self.registers.status.insert(PS_ZERO); + } else { + self.registers.status.remove(PS_ZERO); + } + + let diff: i8 = (a as i8) - (val as i8); + if diff < 0 { + self.registers.status.insert(PS_NEGATIVE); + } else { + self.registers.status.remove(PS_NEGATIVE); + } + } + fn push_on_stack(&mut self, val: u8) { let addr = self.registers.stack_pointer.to_address(); self.memory.set_byte(addr, val); @@ -1044,6 +1075,7 @@ fn compare_test() { assert!( machine.registers.status.contains(PS_CARRY )); assert!(!machine.registers.status.contains(PS_NEGATIVE)); + machine.execute_instruction( (instruction::LDA, instruction::UseImmediate(127)) ); @@ -1053,14 +1085,6 @@ fn compare_test() { assert!( machine.registers.status.contains(PS_CARRY )); assert!(!machine.registers.status.contains(PS_NEGATIVE)); - machine.execute_instruction( - (instruction::LDA, instruction::UseImmediate(1)) - ); - - machine.compare(2); - assert!(!machine.registers.status.contains(PS_ZERO )); - assert!(!machine.registers.status.contains(PS_CARRY )); - assert!(!machine.registers.status.contains(PS_NEGATIVE)); machine.execute_instruction( (instruction::LDA, instruction::UseImmediate(1)) @@ -1071,12 +1095,33 @@ fn compare_test() { assert!(!machine.registers.status.contains(PS_CARRY )); assert!( machine.registers.status.contains(PS_NEGATIVE)); + machine.execute_instruction( (instruction::LDA, instruction::UseImmediate(20)) ); machine.compare(-50); assert!(!machine.registers.status.contains(PS_ZERO )); - assert!( machine.registers.status.contains(PS_CARRY )); + assert!(!machine.registers.status.contains(PS_CARRY )); assert!(!machine.registers.status.contains(PS_NEGATIVE)); + + + machine.execute_instruction( + (instruction::LDA, instruction::UseImmediate(1)) + ); + + machine.compare(-1); + assert!(!machine.registers.status.contains(PS_ZERO )); + assert!(!machine.registers.status.contains(PS_CARRY )); + assert!(!machine.registers.status.contains(PS_NEGATIVE)); + + + machine.execute_instruction( + (instruction::LDA, instruction::UseImmediate(127)) + ); + + machine.compare(-128); + assert!(!machine.registers.status.contains(PS_ZERO )); + assert!(!machine.registers.status.contains(PS_CARRY )); + assert!( machine.registers.status.contains(PS_NEGATIVE)); } \ No newline at end of file From a05a5dfde73781a301d400f09ea55161bfd39237 Mon Sep 17 00:00:00 2001 From: Andrew Keeton Date: Thu, 13 Nov 2014 20:15:40 -0500 Subject: [PATCH 3/5] Add CMP to execute_instruction(). --- src/machine.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 57aad5d..bb74bb1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -188,6 +188,14 @@ impl Machine { self.registers.status.and(!PS_OVERFLOW); } + (instruction::CMP, instruction::UseImmediate(val)) => { + self.compare(val); + } + (instruction::CMP, instruction::UseAddress(addr)) => { + let val = self.memory.get_byte(addr); + self.compare(val); + } + (instruction::DEC, instruction::UseAddress(addr)) => { self.decrement_memory(addr) } @@ -619,7 +627,6 @@ impl Machine { } } - // From http://www.6502.org/tutorials/compare_beyond.html: // If the Z flag is 0, then A <> NUM and BNE will branch // If the Z flag is 1, then A = NUM and BEQ will branch From 99345e2b1fb8ba036e37070fb6e8874dddd3b84b Mon Sep 17 00:00:00 2001 From: Andrew Keeton Date: Thu, 13 Nov 2014 20:58:56 -0500 Subject: [PATCH 4/5] Make compare() take a variable register. --- src/machine.rs | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index bb74bb1..ddc17f0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -189,11 +189,11 @@ impl Machine { } (instruction::CMP, instruction::UseImmediate(val)) => { - self.compare(val); + self.compare_with_a_register(val); } (instruction::CMP, instruction::UseAddress(addr)) => { let val = self.memory.get_byte(addr); - self.compare(val); + self.compare_with_a_register(val); } (instruction::DEC, instruction::UseAddress(addr)) => { @@ -634,22 +634,20 @@ impl Machine { // If the C flag is 1, then A (unsigned) >= NUM (unsigned) and BCS will branch // ... // The N flag contains most significant bit of the of the subtraction result. - fn compare(&mut self, val: u8) { - let a = self.registers.accumulator; - - if a as u8 >= val as u8 { + fn compare(&mut self, r: i8, val: u8) { + if r as u8 >= val as u8 { self.registers.status.insert(PS_CARRY); } else { self.registers.status.remove(PS_CARRY); } - if a as i8 == val as i8 { + if r as i8 == val as i8 { self.registers.status.insert(PS_ZERO); } else { self.registers.status.remove(PS_ZERO); } - let diff: i8 = (a as i8) - (val as i8); + let diff: i8 = (r as i8) - (val as i8); if diff < 0 { self.registers.status.insert(PS_NEGATIVE); } else { @@ -657,6 +655,11 @@ impl Machine { } } + fn compare_with_a_register(&mut self, val: u8) { + let a = self.registers.accumulator; + self.compare(a, val); + } + fn push_on_stack(&mut self, val: u8) { let addr = self.registers.stack_pointer.to_address(); self.memory.set_byte(addr, val); @@ -1069,15 +1072,14 @@ fn branch_if_overflow_set_test() { assert_eq!(machine.registers.program_counter, Address(0xABCD)); } -#[test] -fn compare_test() { +fn compare_test_helper(compare: |&mut Machine, u8|) { let mut machine = Machine::new(); machine.execute_instruction( (instruction::LDA, instruction::UseImmediate(127)) ); - machine.compare(127); + compare(&mut machine, 127); assert!( machine.registers.status.contains(PS_ZERO )); assert!( machine.registers.status.contains(PS_CARRY )); assert!(!machine.registers.status.contains(PS_NEGATIVE)); @@ -1087,7 +1089,7 @@ fn compare_test() { (instruction::LDA, instruction::UseImmediate(127)) ); - machine.compare(1); + compare(&mut machine, 1); assert!(!machine.registers.status.contains(PS_ZERO )); assert!( machine.registers.status.contains(PS_CARRY )); assert!(!machine.registers.status.contains(PS_NEGATIVE)); @@ -1097,7 +1099,7 @@ fn compare_test() { (instruction::LDA, instruction::UseImmediate(1)) ); - machine.compare(2); + compare(&mut machine, 2); assert!(!machine.registers.status.contains(PS_ZERO )); assert!(!machine.registers.status.contains(PS_CARRY )); assert!( machine.registers.status.contains(PS_NEGATIVE)); @@ -1107,7 +1109,7 @@ fn compare_test() { (instruction::LDA, instruction::UseImmediate(20)) ); - machine.compare(-50); + compare(&mut machine, -50); assert!(!machine.registers.status.contains(PS_ZERO )); assert!(!machine.registers.status.contains(PS_CARRY )); assert!(!machine.registers.status.contains(PS_NEGATIVE)); @@ -1117,7 +1119,7 @@ fn compare_test() { (instruction::LDA, instruction::UseImmediate(1)) ); - machine.compare(-1); + compare(&mut machine, -1); assert!(!machine.registers.status.contains(PS_ZERO )); assert!(!machine.registers.status.contains(PS_CARRY )); assert!(!machine.registers.status.contains(PS_NEGATIVE)); @@ -1127,8 +1129,17 @@ fn compare_test() { (instruction::LDA, instruction::UseImmediate(127)) ); - machine.compare(-128); + compare(&mut machine, -128); assert!(!machine.registers.status.contains(PS_ZERO )); assert!(!machine.registers.status.contains(PS_CARRY )); assert!( machine.registers.status.contains(PS_NEGATIVE)); +} + +#[test] +fn compare_with_a_register_test() { + compare_test_helper( + |machine: &mut Machine, val: u8| { + machine.compare_with_a_register(val); + } + ); } \ No newline at end of file From 0eee2e659b2fd67da4f95cdba73e0de1cdfc360f Mon Sep 17 00:00:00 2001 From: Andrew Keeton Date: Thu, 13 Nov 2014 21:17:59 -0500 Subject: [PATCH 5/5] Add CPX and CPY. --- src/machine.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index ddc17f0..e85837e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -196,6 +196,22 @@ impl Machine { self.compare_with_a_register(val); } + (instruction::CPX, instruction::UseImmediate(val)) => { + self.compare_with_x_register(val); + } + (instruction::CPX, instruction::UseAddress(addr)) => { + let val = self.memory.get_byte(addr); + self.compare_with_x_register(val); + } + + (instruction::CPY, instruction::UseImmediate(val)) => { + self.compare_with_y_register(val); + } + (instruction::CPY, instruction::UseAddress(addr)) => { + let val = self.memory.get_byte(addr); + self.compare_with_y_register(val); + } + (instruction::DEC, instruction::UseAddress(addr)) => { self.decrement_memory(addr) } @@ -660,6 +676,18 @@ impl Machine { self.compare(a, val); } + fn compare_with_x_register(&mut self, val: u8) { + debug!("compare_with_x_register"); + + let x = self.registers.index_x; + self.compare(x, val); + } + + fn compare_with_y_register(&mut self, val: u8) { + let y = self.registers.index_y; + self.compare(y, val); + } + fn push_on_stack(&mut self, val: u8) { let addr = self.registers.stack_pointer.to_address(); self.memory.set_byte(addr, val); @@ -1072,11 +1100,14 @@ fn branch_if_overflow_set_test() { assert_eq!(machine.registers.program_counter, Address(0xABCD)); } -fn compare_test_helper(compare: |&mut Machine, u8|) { +fn compare_test_helper( + compare: |&mut Machine, u8|, + load_instruction: instruction::Instruction +) { let mut machine = Machine::new(); machine.execute_instruction( - (instruction::LDA, instruction::UseImmediate(127)) + (load_instruction, instruction::UseImmediate(127)) ); compare(&mut machine, 127); @@ -1086,7 +1117,7 @@ fn compare_test_helper(compare: |&mut Machine, u8|) { machine.execute_instruction( - (instruction::LDA, instruction::UseImmediate(127)) + (load_instruction, instruction::UseImmediate(127)) ); compare(&mut machine, 1); @@ -1096,7 +1127,7 @@ fn compare_test_helper(compare: |&mut Machine, u8|) { machine.execute_instruction( - (instruction::LDA, instruction::UseImmediate(1)) + (load_instruction, instruction::UseImmediate(1)) ); compare(&mut machine, 2); @@ -1106,7 +1137,7 @@ fn compare_test_helper(compare: |&mut Machine, u8|) { machine.execute_instruction( - (instruction::LDA, instruction::UseImmediate(20)) + (load_instruction, instruction::UseImmediate(20)) ); compare(&mut machine, -50); @@ -1116,7 +1147,7 @@ fn compare_test_helper(compare: |&mut Machine, u8|) { machine.execute_instruction( - (instruction::LDA, instruction::UseImmediate(1)) + (load_instruction, instruction::UseImmediate(1)) ); compare(&mut machine, -1); @@ -1126,7 +1157,7 @@ fn compare_test_helper(compare: |&mut Machine, u8|) { machine.execute_instruction( - (instruction::LDA, instruction::UseImmediate(127)) + (load_instruction, instruction::UseImmediate(127)) ); compare(&mut machine, -128); @@ -1140,6 +1171,27 @@ fn compare_with_a_register_test() { compare_test_helper( |machine: &mut Machine, val: u8| { machine.compare_with_a_register(val); - } + }, + instruction::LDA + ); +} + +#[test] +fn compare_with_x_register_test() { + compare_test_helper( + |machine: &mut Machine, val: u8| { + machine.compare_with_x_register(val); + }, + instruction::LDX + ); +} + +#[test] +fn compare_with_y_register_test() { + compare_test_helper( + |machine: &mut Machine, val: u8| { + machine.compare_with_y_register(val); + }, + instruction::LDY ); } \ No newline at end of file