Skip to content

Commit a04cc18

Browse files
committed
fix: more bugs found from nestest.nes
1 parent 38e7f69 commit a04cc18

File tree

3 files changed

+55
-49
lines changed

3 files changed

+55
-49
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Priorities:
2020
- https://www.nesdev.org/obelisk-6502-guide/reference.html
2121
- http://www.6502.org/tutorials/6502opcodes.html
2222
- NES Test Roms: https://github.com/christopherpow/nes-test-roms
23+
- 6502 details
24+
- overflow and underflow: https://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
2325

2426
### Other interesting Tools
2527

src/core.rs

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,19 @@ pub enum AddressingMode {
4848
None,
4949
Indirect,
5050
Relative,
51+
Accumulator,
5152
}
5253

5354
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5455
pub enum Flag {
55-
Negative,
56-
Overflow,
57-
// Break2,
58-
// Break,
59-
Decimal,
60-
Interrupt,
56+
Carry, // 0th bit
6157
Zero,
62-
Carry,
58+
Interrupt,
59+
Decimal,
60+
Break,
61+
Break2,
62+
Overflow,
63+
Negative, // 7th bit
6364
}
6465

6566
// TODO: restore this later. It's hard-coded to support Snake right now
@@ -186,8 +187,7 @@ impl Cpu {
186187
let target = self.mem_read_zero_page_wrapping(base); // indirect
187188
target.wrapping_add(self.y as u16) // indexed
188189
}
189-
AddressingMode::None => panic!("mode {:?} is not supported", mode),
190-
AddressingMode::Relative => panic!("mode {:?} is not supported", mode),
190+
_ => panic!("mode {:?} is not supported", mode),
191191
}
192192
}
193193

@@ -343,15 +343,20 @@ impl Cpu {
343343
fn adc(&mut self, mode: &AddressingMode) {
344344
let addr = self.get_operand_address(mode);
345345
let param = self.mem_read(addr);
346-
let (mid, overflow) = self.a.overflowing_add(param);
346+
347+
self.adc_helper(param);
348+
}
349+
350+
fn adc_helper(&mut self, mem_value: u8) {
351+
let (mid, overflow) = self.a.overflowing_add(mem_value);
347352

348353
let c = if self.get_flag(Flag::Carry) { 1 } else { 0 };
349354
let (result, overflow2) = mid.overflowing_add(c);
350355

351356
self.set_zero_and_negative_flags(result);
352357
self.set_flag(Flag::Carry, overflow || overflow2);
353358

354-
let v = (result ^ self.a) & (result ^ param) & 0x80;
359+
let v = (result ^ self.a) & (result ^ mem_value) & 0x80;
355360
self.set_flag(Flag::Overflow, v > 0);
356361

357362
self.a = result;
@@ -369,8 +374,7 @@ impl Cpu {
369374

370375
/// ASL (Arithmetic Shift Left)
371376
fn asl(&mut self, mode: &AddressingMode) {
372-
// I've overloaded the addressing mode idea to handle accumlator variant
373-
if mode == &AddressingMode::None {
377+
if mode == &AddressingMode::Accumulator {
374378
let old_val = self.a;
375379
let new_val = self.a << 1;
376380

@@ -452,14 +456,9 @@ impl Cpu {
452456

453457
let (result, borrow) = val.overflowing_sub(param);
454458

455-
// let gte = val >= param;
456459
self.set_flag(Flag::Carry, !borrow);
457460

458-
// let eq = val == param;
459-
self.set_flag(Flag::Zero, result == 0);
460-
461-
// let sign = (param & (1 << 7)) > 0;
462-
self.set_flag(Flag::Negative, borrow);
461+
self.set_zero_and_negative_flags(result);
463462
}
464463

465464
/// CMP (CoMPare accumulator)
@@ -567,7 +566,7 @@ impl Cpu {
567566
let param = self.mem_read(addr);
568567

569568
self.x = param;
570-
self.set_zero_and_negative_flags(self.a);
569+
self.set_zero_and_negative_flags(self.x);
571570
}
572571

573572
/// LDY (LoaD Y register)
@@ -576,13 +575,12 @@ impl Cpu {
576575
let param = self.mem_read(addr);
577576

578577
self.y = param;
579-
self.set_zero_and_negative_flags(self.a);
578+
self.set_zero_and_negative_flags(self.y);
580579
}
581580

582581
/// LSR (Logical Shift Right)
583582
fn lsr(&mut self, mode: &AddressingMode) {
584-
// I've overloaded the addressing mode idea to handle accumlator variant
585-
if mode == &AddressingMode::None {
583+
if mode == &AddressingMode::Accumulator {
586584
let old_val = self.a;
587585
let new_val = self.a >> 1;
588586

@@ -617,8 +615,7 @@ impl Cpu {
617615

618616
/// ROL (ROtate Left)
619617
fn rol(&mut self, mode: &AddressingMode) {
620-
// I've overloaded the addressing mode idea to handle accumlator variant
621-
if mode == &AddressingMode::None {
618+
if mode == &AddressingMode::Accumulator {
622619
let old_val = self.a;
623620
let new_val = (self.a << 1) + self.get_flag(Flag::Carry) as u8;
624621

@@ -640,8 +637,7 @@ impl Cpu {
640637

641638
/// ROR (ROtate Right)
642639
fn ror(&mut self, mode: &AddressingMode) {
643-
// I've overloaded the addressing mode idea to handle accumlator variant
644-
if mode == &AddressingMode::None {
640+
if mode == &AddressingMode::Accumulator {
645641
let old_val = self.a;
646642
let mut new_val = self.a >> 1;
647643
if self.get_flag(Flag::Carry) {
@@ -671,22 +667,16 @@ impl Cpu {
671667
fn rti(&mut self) {
672668
self.status = self.stack_pop();
673669
self.pc = self.stack_pop_u16();
674-
// self.set_flag(Flag::Break, false);
675-
// self.set_flag(Flag::Break2, true);
670+
self.set_flag(Flag::Break, false);
671+
self.set_flag(Flag::Break2, true);
676672
}
677673

678674
/// SBC (SuBtract with Carry)
679675
fn sbc(&mut self, mode: &AddressingMode) {
680676
let addr = self.get_operand_address(mode);
681677
let param = self.mem_read(addr);
682-
let (new_val, overflow) = self.a.overflowing_sub(param);
683-
self.a = new_val;
684678

685-
self.set_zero_and_negative_flags(new_val);
686-
if overflow {
687-
self.set_flag(Flag::Carry, false);
688-
}
689-
self.set_flag(Flag::Overflow, false); // TODO: not implemented -- fix it for snake to work?
679+
self.adc_helper(255 - param);
690680
}
691681

692682
/// STA (STore Accumulator)
@@ -715,7 +705,6 @@ impl Cpu {
715705
/// TXS (Transfer X to Stack ptr)
716706
fn txs(&mut self) {
717707
self.sp = self.x;
718-
self.set_zero_and_negative_flags(self.sp);
719708
}
720709

721710
/// TSX (Transfer Stack ptr to X)
@@ -777,8 +766,8 @@ impl Cpu {
777766
Flag::Zero => 1,
778767
Flag::Interrupt => 2,
779768
Flag::Decimal => 3,
780-
// Flag::Break => 4,
781-
// Flag::Break2 => 5,
769+
Flag::Break => 4,
770+
Flag::Break2 => 5,
782771
Flag::Overflow => 6,
783772
Flag::Negative => 7,
784773
};
@@ -799,8 +788,8 @@ impl Cpu {
799788
Flag::Zero => 1,
800789
Flag::Interrupt => 2,
801790
Flag::Decimal => 3,
802-
// Flag::Break => 4,
803-
// Flag::Break2 => 5,
791+
Flag::Break => 4,
792+
Flag::Break2 => 5,
804793
Flag::Overflow => 6,
805794
Flag::Negative => 7,
806795
};
@@ -830,7 +819,19 @@ impl Cpu {
830819
}
831820
AddressingMode::ZeroPageX => format!("${:02X},X", param1),
832821
AddressingMode::ZeroPageY => format!("${:02X},Y", param1),
833-
AddressingMode::Absolute => format!("${:02X}{:02X}", param2, param1),
822+
AddressingMode::Absolute => {
823+
let hi = (param2 as u16) << 8;
824+
let addr: u16 = hi + (param1 as u16);
825+
match name {
826+
OpName::STX | OpName::LDX | OpName::LDA => format!(
827+
"${:02X}{:02X} = {:02X}",
828+
param2,
829+
param1,
830+
self.mem_read(addr)
831+
),
832+
_ => format!("${:02X}{:02X}", param2, param1,),
833+
}
834+
}
834835
AddressingMode::AbsoluteX => format!("${:02X}{:02X},X", param2, param1),
835836
AddressingMode::AbsoluteY => format!("${:02X}{:02X},Y", param2, param1),
836837
AddressingMode::IndirectX => {
@@ -857,6 +858,7 @@ impl Cpu {
857858
(self.pc as isize + 2 + (param1 as i8) as isize) as u16
858859
)
859860
}
861+
AddressingMode::Accumulator => format!("A"),
860862
// AddressingMode::Indirect => todo!(),
861863
_ => "".to_string(),
862864
};
@@ -1533,7 +1535,7 @@ mod tests {
15331535

15341536
#[test]
15351537
fn test_nestest() {
1536-
let max_known_good_line = 313;
1538+
let max_known_good_line = 1061;
15371539

15381540
let program = fs::read("roms/nestest.nes").unwrap();
15391541

@@ -1568,8 +1570,10 @@ mod tests {
15681570
assert_eq!(
15691571
actual[idx],
15701572
e.unwrap().as_str(),
1571-
"first diff found on line = {:?}",
1572-
line_num
1573+
"First diff found on line = {:?}. In context the output was: \n\n{}\n{}\n",
1574+
line_num,
1575+
if idx == 0 { "n/a" } else { &actual[idx - 1] },
1576+
&actual[idx]
15731577
);
15741578
}
15751579
}

src/ops.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub fn lookup_opcode(code: u8) -> Op {
9191
0x21 => (OpName::AND, 2, AddressingMode::IndirectX),
9292
0x31 => (OpName::AND, 2, AddressingMode::IndirectY),
9393

94-
0x0A => (OpName::ASL, 2, AddressingMode::None),
94+
0x0A => (OpName::ASL, 1, AddressingMode::Accumulator),
9595
0x06 => (OpName::ASL, 2, AddressingMode::ZeroPage),
9696
0x16 => (OpName::ASL, 2, AddressingMode::ZeroPageX),
9797
0x0E => (OpName::ASL, 3, AddressingMode::Absolute),
@@ -157,7 +157,7 @@ pub fn lookup_opcode(code: u8) -> Op {
157157
0xAC => (OpName::LDY, 3, AddressingMode::Absolute),
158158
0xBC => (OpName::LDY, 3, AddressingMode::AbsoluteX),
159159

160-
0x4A => (OpName::LSR, 2, AddressingMode::None),
160+
0x4A => (OpName::LSR, 1, AddressingMode::Accumulator),
161161
0x46 => (OpName::LSR, 2, AddressingMode::ZeroPage),
162162
0x56 => (OpName::LSR, 2, AddressingMode::ZeroPageX),
163163
0x4E => (OpName::LSR, 3, AddressingMode::Absolute),
@@ -174,13 +174,13 @@ pub fn lookup_opcode(code: u8) -> Op {
174174
0x01 => (OpName::ORA, 2, AddressingMode::IndirectX),
175175
0x11 => (OpName::ORA, 2, AddressingMode::IndirectY),
176176

177-
0x2A => (OpName::ROL, 2, AddressingMode::None),
177+
0x2A => (OpName::ROL, 1, AddressingMode::Accumulator),
178178
0x26 => (OpName::ROL, 2, AddressingMode::ZeroPage),
179179
0x36 => (OpName::ROL, 2, AddressingMode::ZeroPageX),
180180
0x2E => (OpName::ROL, 3, AddressingMode::Absolute),
181181
0x3E => (OpName::ROL, 3, AddressingMode::AbsoluteX),
182182

183-
0x6A => (OpName::ROR, 2, AddressingMode::None),
183+
0x6A => (OpName::ROR, 1, AddressingMode::Accumulator),
184184
0x66 => (OpName::ROR, 2, AddressingMode::ZeroPage),
185185
0x76 => (OpName::ROR, 2, AddressingMode::ZeroPageX),
186186
0x6E => (OpName::ROR, 3, AddressingMode::Absolute),

0 commit comments

Comments
 (0)