mirror of
https://github.com/zellyn/go6502.git
synced 2025-02-06 11:30:11 +00:00
Make lots of instructions cycle-accurate
This commit is contained in:
parent
56959ddcc9
commit
cfff197420
@ -15,7 +15,7 @@ func (c *cpu) setNZ(value byte) {
|
||||
// samePage is a helper that returns true if two memory addresses
|
||||
// refer to the same page.
|
||||
func samePage(a1 uint16, a2 uint16) bool {
|
||||
return a1^a2&0xFF00 == 0
|
||||
return (a1^a2)&0xFF00 == 0
|
||||
}
|
||||
|
||||
// clearFlag builds instructions that clear the flag specified by the
|
||||
@ -23,6 +23,7 @@ func samePage(a1 uint16, a2 uint16) bool {
|
||||
func clearFlag(flag byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
c.r.P &^= flag
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
@ -32,6 +33,7 @@ func clearFlag(flag byte) func(*cpu) {
|
||||
func setFlag(flag byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
c.r.P |= flag
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
@ -40,17 +42,22 @@ func setFlag(flag byte) func(*cpu) {
|
||||
// register masks to a given value.
|
||||
func branch(mask, value byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
offset := c.m.Read(c.r.PC)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
oldPC := c.r.PC
|
||||
if c.r.P&mask == value {
|
||||
c.m.Read(oldPC)
|
||||
c.t.Tick()
|
||||
// T3
|
||||
c.r.PC = c.r.PC + uint16(offset)
|
||||
if offset >= 128 {
|
||||
c.r.PC = c.r.PC - 256
|
||||
}
|
||||
if !samePage(c.r.PC, oldPC) {
|
||||
c.m.Read((oldPC & 0xFF00) | (c.r.PC & 0x00FF))
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
@ -146,6 +153,7 @@ func bit(c *cpu, value byte) {
|
||||
// http://en.wikipedia.org/wiki/Interrupts_in_65xx_processors#Using_BRK_and_COP
|
||||
func brk(c *cpu) {
|
||||
// T1
|
||||
c.m.Read(c.r.PC)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
@ -206,12 +214,14 @@ func dec(c *cpu, value byte) byte {
|
||||
func dex(c *cpu) {
|
||||
c.r.X--
|
||||
c.setNZ(c.r.X)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func dey(c *cpu) {
|
||||
c.r.Y--
|
||||
c.setNZ(c.r.Y)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
@ -229,12 +239,14 @@ func inc(c *cpu, value byte) byte {
|
||||
func inx(c *cpu) {
|
||||
c.r.X++
|
||||
c.setNZ(c.r.X)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func iny(c *cpu) {
|
||||
c.r.Y++
|
||||
c.setNZ(c.r.Y)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
@ -287,13 +299,14 @@ func jsr(c *cpu) {
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(0x100 + uint16(c.r.SP)) // Ignored read on stack
|
||||
c.t.Tick()
|
||||
// T3
|
||||
c.m.Write(0x100+uint16(c.r.SP), byte(c.r.PC>>8))
|
||||
c.m.Write(0x100+uint16(c.r.SP), byte(c.r.PC>>8)) // Write PC|hi to stack
|
||||
c.r.SP--
|
||||
c.t.Tick()
|
||||
// T4
|
||||
c.m.Write(0x100+uint16(c.r.SP), byte(c.r.PC&0xff))
|
||||
c.m.Write(0x100+uint16(c.r.SP), byte(c.r.PC&0xff)) // Write PC|lo to stack
|
||||
c.r.SP--
|
||||
c.t.Tick()
|
||||
// T5
|
||||
@ -330,10 +343,12 @@ func ora(c *cpu, value byte) {
|
||||
}
|
||||
|
||||
func nop(c *cpu) {
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func pha(c *cpu) {
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
c.m.Write(0x100+uint16(c.r.SP), c.r.A)
|
||||
c.r.SP--
|
||||
@ -341,7 +356,9 @@ func pha(c *cpu) {
|
||||
}
|
||||
|
||||
func pla(c *cpu) {
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
c.m.Read(0x100 + uint16(c.r.SP))
|
||||
c.r.SP++
|
||||
c.t.Tick()
|
||||
c.r.A = c.m.Read(0x100 + uint16(c.r.SP))
|
||||
@ -350,13 +367,17 @@ func pla(c *cpu) {
|
||||
}
|
||||
|
||||
func php(c *cpu) {
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
c.m.Write(0x100+uint16(c.r.SP), c.r.P)
|
||||
c.r.SP--
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func plp(c *cpu) {
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
c.m.Read(0x100 + uint16(c.r.SP))
|
||||
c.r.SP++
|
||||
c.t.Tick()
|
||||
c.r.P = c.m.Read(0x100+uint16(c.r.SP)) | FLAG_UNUSED | FLAG_B
|
||||
@ -379,8 +400,10 @@ func ror(c *cpu, value byte) byte {
|
||||
|
||||
func rts(c *cpu) {
|
||||
// T1
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(0x100 + uint16(c.r.SP))
|
||||
c.r.SP++
|
||||
c.t.Tick()
|
||||
// T3
|
||||
@ -391,14 +414,17 @@ func rts(c *cpu) {
|
||||
addr |= (uint16(c.m.Read(0x100+uint16(c.r.SP))) << 8)
|
||||
c.t.Tick()
|
||||
// T5
|
||||
c.m.Read(addr)
|
||||
c.r.PC = addr + 1 // Since we pushed PC(next) - 1
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func rti(c *cpu) {
|
||||
// T1
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(0x100 + uint16(c.r.SP))
|
||||
c.r.SP++
|
||||
c.t.Tick()
|
||||
// T3
|
||||
@ -498,34 +524,40 @@ func sty(c *cpu) byte {
|
||||
func tax(c *cpu) {
|
||||
c.r.X = c.r.A
|
||||
c.setNZ(c.r.X)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func tay(c *cpu) {
|
||||
c.r.Y = c.r.A
|
||||
c.setNZ(c.r.Y)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func tsx(c *cpu) {
|
||||
c.r.X = c.r.SP
|
||||
c.setNZ(c.r.X)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func txa(c *cpu) {
|
||||
c.r.A = c.r.X
|
||||
c.setNZ(c.r.A)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func txs(c *cpu) {
|
||||
c.r.SP = c.r.X
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func tya(c *cpu) {
|
||||
c.r.A = c.r.Y
|
||||
c.setNZ(c.r.A)
|
||||
c.m.Read(c.r.PC)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
@ -94,14 +94,16 @@ func absx4r(f func(*cpu, byte)) func(*cpu) {
|
||||
c.t.Tick()
|
||||
// T2
|
||||
addr |= (uint16(c.m.Read(c.r.PC)) << 8)
|
||||
addrX := addr + uint16(c.r.X)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T3
|
||||
if !samePage(addr, addr+uint16(c.r.X)) {
|
||||
if !samePage(addr, addrX) {
|
||||
c.m.Read(addrX - 0x100)
|
||||
c.t.Tick()
|
||||
}
|
||||
// T3(cotd.) or T4
|
||||
value := c.m.Read(addr + uint16(c.r.X))
|
||||
value := c.m.Read(addrX)
|
||||
f(c, value)
|
||||
c.t.Tick()
|
||||
}
|
||||
@ -116,14 +118,16 @@ func absy4r(f func(*cpu, byte)) func(*cpu) {
|
||||
c.t.Tick()
|
||||
// T2
|
||||
addr |= (uint16(c.m.Read(c.r.PC)) << 8)
|
||||
addrY := addr + uint16(c.r.Y)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T3
|
||||
if !samePage(addr, addr+uint16(c.r.Y)) {
|
||||
if !samePage(addr, addrY) {
|
||||
c.m.Read(addrY - 0x100)
|
||||
c.t.Tick()
|
||||
}
|
||||
// T3(cotd.) or T4
|
||||
value := c.m.Read(addr + uint16(c.r.Y))
|
||||
value := c.m.Read(addrY)
|
||||
f(c, value)
|
||||
c.t.Tick()
|
||||
}
|
||||
@ -138,12 +142,14 @@ func absx5w(f func(*cpu) byte) func(*cpu) {
|
||||
c.t.Tick()
|
||||
// T2
|
||||
addr |= (uint16(c.m.Read(c.r.PC)) << 8)
|
||||
addrX := addr + uint16(c.r.X)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T3
|
||||
c.m.Read((addr & 0xFF00) | (addrX & 0x00FF))
|
||||
c.t.Tick()
|
||||
// T4
|
||||
c.m.Write(addr+uint16(c.r.X), f(c))
|
||||
c.m.Write(addrX, f(c))
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
@ -157,12 +163,14 @@ func absy5w(f func(*cpu) byte) func(*cpu) {
|
||||
c.t.Tick()
|
||||
// T2
|
||||
addr |= (uint16(c.m.Read(c.r.PC)) << 8)
|
||||
addrY := addr + uint16(c.r.Y)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T3
|
||||
c.m.Read((addr & 0xFF00) | (addrY & 0x00FF))
|
||||
c.t.Tick()
|
||||
// T4
|
||||
c.m.Write(addr+uint16(c.r.Y), f(c))
|
||||
c.m.Write(addrY, f(c))
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
@ -172,13 +180,14 @@ func zpx4r(f func(*cpu, byte)) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
addr := c.m.Read(c.r.PC)
|
||||
addrX := uint16(addr + c.r.X)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(uint16(addr))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr += c.r.X
|
||||
value := c.m.Read(uint16(addr))
|
||||
value := c.m.Read(addrX)
|
||||
f(c, value)
|
||||
c.t.Tick()
|
||||
}
|
||||
@ -189,13 +198,14 @@ func zpx4w(f func(*cpu) byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
addr := c.m.Read(c.r.PC)
|
||||
addrX := uint16(addr + c.r.X)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(uint16(addr))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr += c.r.X
|
||||
c.m.Write(uint16(addr), f(c))
|
||||
c.m.Write(uint16(addrX), f(c))
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
@ -205,13 +215,14 @@ func zpy4r(f func(*cpu, byte)) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
addr := c.m.Read(c.r.PC)
|
||||
addrY := uint16(addr + c.r.Y)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(uint16(addr))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr += c.r.Y
|
||||
value := c.m.Read(uint16(addr))
|
||||
value := c.m.Read(uint16(addrY))
|
||||
f(c, value)
|
||||
c.t.Tick()
|
||||
}
|
||||
@ -222,13 +233,14 @@ func zpy4w(f func(*cpu) byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
addr := c.m.Read(c.r.PC)
|
||||
addrY := uint16(addr + c.r.Y)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(uint16(addr))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr += c.r.Y
|
||||
c.m.Write(uint16(addr), f(c))
|
||||
c.m.Write(addrY, f(c))
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
@ -241,13 +253,15 @@ func zpiy5r(f func(*cpu, byte)) func(*cpu) {
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
addr := uint16(uint16(c.m.Read(uint16(iAddr))))
|
||||
addr := uint16(c.m.Read(uint16(iAddr)))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr |= (uint16(c.m.Read(uint16(iAddr+1))) << 8)
|
||||
addrY := addr + uint16(c.r.Y)
|
||||
c.t.Tick()
|
||||
// T4
|
||||
if !samePage(addr, addr+uint16(c.r.Y)) {
|
||||
if !samePage(addr, addrY) {
|
||||
c.m.Read((addr & 0xFF00) | (addrY & 0x00FF))
|
||||
c.t.Tick()
|
||||
}
|
||||
// T4(cotd.) or T5
|
||||
@ -269,8 +283,10 @@ func zpiy6w(f func(*cpu) byte) func(*cpu) {
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr |= (uint16(c.m.Read(uint16(iAddr+1))) << 8)
|
||||
addrY := addr + uint16(c.r.Y)
|
||||
c.t.Tick()
|
||||
// T4
|
||||
c.m.Read((addr & 0xFF00) | (addrY & 0x00FF))
|
||||
c.t.Tick()
|
||||
// T5
|
||||
c.m.Write(addr+uint16(c.r.Y), f(c))
|
||||
@ -286,6 +302,7 @@ func zpxi6r(f func(*cpu, byte)) func(*cpu) {
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(uint16(iAddr))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr := uint16(uint16(c.m.Read(uint16(iAddr + c.r.X))))
|
||||
@ -308,6 +325,7 @@ func zpxi6w(f func(*cpu) byte) func(*cpu) {
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(uint16(iAddr))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr := uint16(uint16(c.m.Read(uint16(iAddr + c.r.X))))
|
||||
@ -321,16 +339,17 @@ func zpxi6w(f func(*cpu) byte) func(*cpu) {
|
||||
}
|
||||
}
|
||||
|
||||
// acc2rmw performs 1-opcode, 2-cycle, accumulator rmw instructions.
|
||||
// acc2rmw performs 1-opcode, 2-cycle, accumulator rmw instructions. eg. ASL
|
||||
func acc2rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
c.m.Read(c.r.PC)
|
||||
c.r.A = f(c, c.r.A)
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
|
||||
// zp5rmw performs 2-opcode, 5-cycle, zp rmw instructions.
|
||||
// zp5rmw performs 2-opcode, 5-cycle, zp rmw instructions. eg. ASL $70
|
||||
func zp5rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
@ -341,6 +360,7 @@ func zp5rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
value := c.m.Read(addr)
|
||||
c.t.Tick()
|
||||
// T3
|
||||
c.m.Write(addr, value)
|
||||
c.t.Tick()
|
||||
// T4
|
||||
c.m.Write(addr, f(c, value))
|
||||
@ -348,7 +368,7 @@ func zp5rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
}
|
||||
}
|
||||
|
||||
// abs6rmw performs 3-opcode, 6-cycle, abs rmw instructions.
|
||||
// abs6rmw performs 3-opcode, 6-cycle, abs rmw instructions. eg. ASL $5F72
|
||||
func abs6rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
@ -371,7 +391,7 @@ func abs6rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
}
|
||||
}
|
||||
|
||||
// zpx6rmw performs 2-opcode, 6-cycle, zp,X rmw instructions.
|
||||
// zpx6rmw performs 2-opcode, 6-cycle, zp,X rmw instructions. eg. ASL $70,X
|
||||
func zpx6rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
@ -379,6 +399,7 @@ func zpx6rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T2
|
||||
c.m.Read(uint16(addr8))
|
||||
c.t.Tick()
|
||||
// T3
|
||||
addr := uint16(addr8 + c.r.X)
|
||||
@ -393,7 +414,7 @@ func zpx6rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
}
|
||||
}
|
||||
|
||||
// absx7rmw performs 3-opcode, 7-cycle, abs,X rmw instructions.
|
||||
// absx7rmw performs 3-opcode, 7-cycle, abs,X rmw instructions. eg. ASL $5F72,X
|
||||
func absx7rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
// T1
|
||||
@ -402,18 +423,20 @@ func absx7rmw(f func(*cpu, byte) byte) func(*cpu) {
|
||||
c.t.Tick()
|
||||
// T2
|
||||
addr |= (uint16(c.m.Read(c.r.PC)) << 8)
|
||||
addr += uint16(c.r.X)
|
||||
c.r.PC++
|
||||
c.t.Tick()
|
||||
// T3
|
||||
c.m.Read(addr)
|
||||
c.t.Tick()
|
||||
// T4
|
||||
value := c.m.Read(addr + uint16(c.r.X))
|
||||
value := c.m.Read(addr)
|
||||
c.t.Tick()
|
||||
// T5
|
||||
c.m.Write(addr+uint16(c.r.X), value) // Spurious write
|
||||
c.m.Write(addr, value) // Spurious write
|
||||
c.t.Tick()
|
||||
// T6
|
||||
c.m.Write(addr+uint16(c.r.X), f(c, value))
|
||||
c.m.Write(addr, f(c, value))
|
||||
c.t.Tick()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user