diff --git a/lib/mos6510/cpu.rb b/lib/mos6510/cpu.rb index 60e3a11..ead9c23 100644 --- a/lib/mos6510/cpu.rb +++ b/lib/mos6510/cpu.rb @@ -31,6 +31,20 @@ def pc=(new_pc) @cpu.pc = new_pc end + def inspect + status = @cpu.p + status_encoded = [ + (status & Mos6510::Flag::N) != 0, (status & Mos6510::Flag::V) != 0, (status & Mos6510::Flag::B2) != 0, (status & Mos6510::Flag::B1) != 0, (status & Mos6510::Flag::D) != 0, + (status & Mos6510::Flag::I) != 0, (status & Mos6510::Flag::Z) != 0, (status & Mos6510::Flag::C) != 0 + ].reduce(0) { |acc, flag| (acc << 1) + (flag ? 1 : 0) } + + format( + 'a: 0x%02x, x: 0x%02x, y: 0x%02x, sp: 0x%02x, ' \ + 'pc: 0x%04x, op: 0x%02x, status: 0b%08b, memory: %i', + @cpu.a, @cpu.x, @cpu.y, @cpu.s, @cpu.pc, @cpu.getmem(@cpu.pc), status_encoded, @memory.sum + ) + end + def peek(address) @cpu.getmem(address) end diff --git a/lib/mos6510/jssid_mos6510.rb b/lib/mos6510/jssid_mos6510.rb index 6bdd4d2..550aca7 100644 --- a/lib/mos6510/jssid_mos6510.rb +++ b/lib/mos6510/jssid_mos6510.rb @@ -238,15 +238,11 @@ def setflags(flag, cond) def push(val) self.setmem(0x100 + self.s, val) - if self.s > 0 - self.s -= 1 - end + self.s = (self.s - 1) & 0xff end def pop - if self.s < 0xff - self.s += 1 - end + self.s = (self.s + 1) & 0xff self.getmem(0x100 + self.s) end @@ -275,7 +271,7 @@ def reset self.a = 0 self.x = 0 self.y = 0 - self.p = 0 + self.p = Flag::B1 | Flag::B2 self.s = 255 self.pc = self.getmem(0xfffc) self.pc |= 256 * self.getmem(0xfffd) @@ -291,12 +287,26 @@ def step case cmd when Inst::ADC - self.wval = self.a + self.getaddr(addr) + ((self.p & Flag::C) != 0 ? 1 : 0) - self.setflags(Flag::C, self.wval & 0x100) + value = self.getaddr(addr) + carry = (self.p & Flag::C) != 0 ? 1 : 0 + if (self.p & Flag::D) != 0 + value_bcd = (value & 0xf) + (value >> 4 & 0xf) * 10 + a_bcd = (self.a & 0xf) + (self.a >> 4 & 0xf) * 10 + sum = value_bcd + a_bcd + carry + self.wval = (sum % 10) + (((sum / 10) % 10) << 4) + ((sum / 100) << 8) + self.setflags(Flag::C, sum >= 100) + self.setflags(Flag::V, self.wval > 127 || self.wval < -128) + else + self.wval = self.a + value + carry + v = (((self.a & 0x7f) + (value & 0x7f) + carry) >> 7) ^ (self.wval >> 8) + # TODO: Shouldn't this work? + #v = self.wval > 127 || self.wval < -128 + self.setflags(Flag::C, self.wval & 0x100) + self.setflags(Flag::V, v) + end self.a = self.wval & 0xff - self.setflags(Flag::Z, self.a == 0) self.setflags(Flag::N, self.a & 0x80) - self.setflags(Flag::V, ((self.p & Flag::C) != 0 ? 1 : 0) ^ ((self.p & Flag::N) != 0 ? 1 : 0)) + self.setflags(Flag::Z, self.a == 0) when Inst::AND self.bval = self.getaddr(addr) self.a &= self.bval @@ -331,14 +341,14 @@ def step self.setflags(Flag::N, self.bval & 0x80) self.setflags(Flag::V, self.bval & 0x40) when Inst::BRK - pc = 0 # just quit per rockbox - #self.push(self.pc & 0xff); - #self.push(self.pc >> 8); - #self.push(self.p); - #self.setflags(jsSID.MOS6510.Flag::B, 1); - # FIXME: should Z be set as well? - #self.pc = self.getmem(0xfffe); - #self.cycles += 7; + self.pcinc() + self.push(self.pc >> 8) + self.push(self.pc & 0xff) + self.push(self.p) + self.setflags(Flag::B1, true) + self.setflags(Flag::I, true) + self.pc = self.getmem(0xfffe) + (self.getmem(0xffff) << 8) + self.cycles += 7 when Inst::CLC self.cycles += 2 self.setflags(Flag::C, 0) @@ -491,7 +501,7 @@ def step self.setflags(Flag::N, self.a & 0x80) self.cycles += 4 when Inst::PLP - self.p = self.pop + self.p = self.pop | Flag::B1 | Flag::B2 self.cycles += 4 when Inst::ROL self.bval = self.getaddr(addr) @@ -513,20 +523,25 @@ def step self.setflags(Flag::N, self.bval & 0x80) self.setflags(Flag::Z, self.bval == 0) when Inst::RTI - # treat like RTS + self.p = self.pop + self.pc = self.pop + (self.pop << 8) + self.cycles += 6 when Inst::RTS self.wval = self.pop self.wval |= 256 * self.pop self.pc = self.wval + 1 self.cycles += 6 when Inst::SBC - self.bval = self.getaddr(addr) ^ 0xff - self.wval = self.a + self.bval + ((self.p & Flag::C) != 0 ? 1 : 0) + # Almost identical to SBC, just inverting value + value = self.getaddr(addr) ^ 0xff + carry = (self.p & Flag::C) != 0 ? 1 : 0 + self.wval = self.a + value + carry + v = (((self.a & 0x7f) + (value & 0x7f) + carry) >> 7) ^ (self.wval >> 8) self.setflags(Flag::C, self.wval & 0x100) self.a = self.wval & 0xff self.setflags(Flag::Z, self.a == 0) - self.setflags(Flag::N, self.a > 127) - self.setflags(Flag::V, ((self.p & Flag::C) != 0 ? 1 : 0) ^ ((self.p & Flag::N) != 0 ? 1 : 0)) + self.setflags(Flag::N, self.a & 0x80) + self.setflags(Flag::V, v) when Inst::SEC self.cycles += 2 self.setflags(Flag::C, 1) @@ -583,7 +598,7 @@ def jsr(npc, na) self.a = na self.x = 0 self.y = 0 - self.p = 0 + self.p = Flag::B1 | Flag::B2 self.s = 255 self.pc = npc self.push(0) @@ -598,7 +613,7 @@ def jsr(npc, na) # Flags Enum module Flag - N = 128; V = 64; B = 16; D = 8; I = 4; Z = 2; C = 1 + N = 128; V = 64; B2 = 32; B1 = 16; D = 8; I = 4; Z = 2; C = 1 end # Opcodes Enum diff --git a/spec/cpu_spec.rb b/spec/cpu_spec.rb index dfb745c..5afe04b 100644 --- a/spec/cpu_spec.rb +++ b/spec/cpu_spec.rb @@ -16,7 +16,7 @@ module Mos6510 expect(cpu.peek(4000)).to eq(7) end - it "can run the whole Klaus Dormann functional test suite", skip: "Needs more work!" do + it "can run the whole Klaus Dormann functional test suite" do#, skip: "Needs more work!" do # TODO: This suite does _not_ pass currently. It relies on you copying # bin_files/6502_functional_test.bin from https://github.com/Klaus2m5/6502_65C02_functional_tests # (and even then, it ends up on the wrong PC) @@ -29,9 +29,9 @@ module Mos6510 last_pc = 0 while last_pc != cpu.pc last_pc = cpu.pc - #puts cpu.inspect + puts cpu.inspect - puts "Stepping: #{last_pc}" + #puts "Stepping: #{last_pc}" cpu.step end