1
0
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:
Zellyn Hunter 2013-03-11 17:21:45 -07:00
parent 56959ddcc9
commit cfff197420
2 changed files with 82 additions and 27 deletions

View File

@ -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()
}

View File

@ -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()
}
}