mirror of
https://github.com/zellyn/go6502.git
synced 2025-04-20 11:38:36 +00:00
Doc fixes.
This commit is contained in:
parent
769924cd72
commit
5102e1af3f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Package asm provides routines for decomiling 6502 assembly language.
|
||||
Package asm provides routines for decompiling 6502 assembly language.
|
||||
*/
|
||||
package asm
|
||||
|
||||
|
37
cpu/cpu.go
37
cpu/cpu.go
@ -1,23 +1,22 @@
|
||||
/*
|
||||
6502 implementation.
|
||||
|
||||
TODO(zellyn): Provide configurable options
|
||||
TODO(zellyn): Implement IRQ, NMI
|
||||
TODO(zellyn): Does BRK on 65C02 CLD?
|
||||
*/
|
||||
|
||||
package cpu
|
||||
|
||||
// BUG(zellyn): Implement IRQ, NMI.
|
||||
|
||||
// BUG(zellyn): implement interrupts, and 6502/65C02
|
||||
// decimal-mode-clearing and BRK-skipping quirks. See
|
||||
// http://en.wikipedia.org/wiki/MOS_Technology_6502#Bugs_and_quirks.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// See http://en.wikipedia.org/wiki/MOS_Technology_6502#Bugs_and_quirks
|
||||
// Chip versions.
|
||||
const (
|
||||
VERSION_6502 = iota
|
||||
VERSION_65C02
|
||||
)
|
||||
|
||||
// Interface for the Cpu type.
|
||||
type Cpu interface {
|
||||
Reset()
|
||||
Step() error
|
||||
@ -28,18 +27,21 @@ type Cpu interface {
|
||||
PC() uint16
|
||||
P() byte // [NV-BDIZC]
|
||||
SP() byte
|
||||
// TODO(zellyn): Add signaling of interrupts
|
||||
// BUG(zellyn): Add signaling of interrupts.
|
||||
}
|
||||
|
||||
// Memory interface, for all memory access.
|
||||
type Memory interface {
|
||||
Read(uint16) byte
|
||||
Write(uint16, byte)
|
||||
}
|
||||
|
||||
// Ticker interface, for keeping track of cycles.
|
||||
type Ticker interface {
|
||||
Tick()
|
||||
}
|
||||
|
||||
// Interrupt vectors.
|
||||
const (
|
||||
STACK_BASE = 0x100
|
||||
IRQ_VECTOR = 0xFFFE
|
||||
@ -47,6 +49,7 @@ const (
|
||||
RESET_VECTOR = 0xFFFC
|
||||
)
|
||||
|
||||
// Flag masks.
|
||||
const (
|
||||
FLAG_C = 1 << iota
|
||||
FLAG_Z
|
||||
@ -76,6 +79,7 @@ type cpu struct {
|
||||
version int
|
||||
}
|
||||
|
||||
// Create and return a new Cpu object with the given memory, ticker, and of the given version.
|
||||
func NewCPU(memory Memory, ticker Ticker, version int) Cpu {
|
||||
c := cpu{m: memory, t: ticker, version: version}
|
||||
c.r.P |= FLAG_UNUSED // Set unused flag to 1
|
||||
@ -101,10 +105,12 @@ func (c *cpu) SP() byte {
|
||||
return c.r.SP
|
||||
}
|
||||
|
||||
// Helper for reading a word of memory.
|
||||
func (c *cpu) readWord(address uint16) uint16 {
|
||||
return uint16(c.m.Read(address)) + (uint16(c.m.Read(address+1)) << 8)
|
||||
}
|
||||
|
||||
// Reset performs a reset.
|
||||
func (c *cpu) Reset() {
|
||||
c.r.SP = 0
|
||||
c.r.PC = c.readWord(RESET_VECTOR)
|
||||
@ -119,6 +125,7 @@ func (c *cpu) Reset() {
|
||||
}
|
||||
}
|
||||
|
||||
// Step takes a single step (which will last several cycles, calling Tick() on the Ticker for each).
|
||||
func (c *cpu) Step() error {
|
||||
c.oldPC = c.r.PC
|
||||
i := c.m.Read(c.r.PC)
|
||||
@ -133,15 +140,7 @@ func (c *cpu) Step() error {
|
||||
return fmt.Errorf("Unknown opcode at location $%04X: $%02X", c.r.PC, i)
|
||||
}
|
||||
|
||||
// Set the program counter.
|
||||
func (c *cpu) SetPC(address uint16) {
|
||||
c.r.PC = address
|
||||
}
|
||||
|
||||
func (c *cpu) SetNZ(value byte) {
|
||||
c.r.P = (c.r.P &^ FLAG_N) | (value & FLAG_N)
|
||||
if value == 0 {
|
||||
c.r.P |= FLAG_Z
|
||||
} else {
|
||||
c.r.P &^= FLAG_Z
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,6 @@
|
||||
/*
|
||||
|
||||
Package cpu provides routines for emulating a 6502 or 65C02. It also
|
||||
provides data about opcodes that is used by the asm package to
|
||||
(dis)assemble 6502 assembly language.
|
||||
|
||||
BUG(zellyn): 6502 should do invalid reads when doing indexed addressing across page boundaries. See http://en.wikipedia.org/wiki/MOS_Technology_6502#Bugs_and_quirks.
|
||||
BUG(zellyn): rmw instructions should write old data back on 6502, read twice on 65C02. See http://en.wikipedia.org/wiki/MOS_Technology_6502#Bugs_and_quirks.
|
||||
BUG(zellyn): implement interrupts, and 6502/65C02 decimal-mode-clearing and BRK-skipping quirks.
|
||||
*/
|
||||
package cpu
|
||||
|
@ -2,6 +2,16 @@ package cpu
|
||||
|
||||
// Helpers and instruction-builders
|
||||
|
||||
// setNZ uses the given value to set the N and Z flags.
|
||||
func (c *cpu) setNZ(value byte) {
|
||||
c.r.P = (c.r.P &^ FLAG_N) | (value & FLAG_N)
|
||||
if value == 0 {
|
||||
c.r.P |= FLAG_Z
|
||||
} else {
|
||||
c.r.P &^= FLAG_Z
|
||||
}
|
||||
}
|
||||
|
||||
// samePage is a helper that returns true if two memory addresses
|
||||
// refer to the same page.
|
||||
func samePage(a1 uint16, a2 uint16) bool {
|
||||
@ -62,7 +72,7 @@ func adc(c *cpu, value byte) {
|
||||
c.r.P |= FLAG_V
|
||||
}
|
||||
c.r.A = result
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
}
|
||||
|
||||
// adc_d performs decimal-mode add-with-carry.
|
||||
@ -105,7 +115,7 @@ func adc_d(c *cpu, value byte) {
|
||||
}
|
||||
case VERSION_65C02:
|
||||
c.t.Tick()
|
||||
c.SetNZ(byte(a & 0xFF))
|
||||
c.setNZ(byte(a & 0xFF))
|
||||
default:
|
||||
panic("Unknown chip version")
|
||||
}
|
||||
@ -113,13 +123,13 @@ func adc_d(c *cpu, value byte) {
|
||||
|
||||
func and(c *cpu, value byte) {
|
||||
c.r.A &= value
|
||||
c.SetNZ(c.r.A)
|
||||
c.setNZ(c.r.A)
|
||||
}
|
||||
|
||||
func asl(c *cpu, value byte) byte {
|
||||
result := value << 1
|
||||
c.r.P = (c.r.P &^ FLAG_C) | (value >> 7)
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
return result
|
||||
}
|
||||
|
||||
@ -166,7 +176,7 @@ func cmp(c *cpu, value byte) {
|
||||
if c.r.A >= value {
|
||||
c.r.P |= FLAG_C
|
||||
}
|
||||
c.SetNZ(v)
|
||||
c.setNZ(v)
|
||||
}
|
||||
|
||||
func cpx(c *cpu, value byte) {
|
||||
@ -175,7 +185,7 @@ func cpx(c *cpu, value byte) {
|
||||
if c.r.X >= value {
|
||||
c.r.P |= FLAG_C
|
||||
}
|
||||
c.SetNZ(v)
|
||||
c.setNZ(v)
|
||||
}
|
||||
|
||||
func cpy(c *cpu, value byte) {
|
||||
@ -184,47 +194,47 @@ func cpy(c *cpu, value byte) {
|
||||
if c.r.Y >= value {
|
||||
c.r.P |= FLAG_C
|
||||
}
|
||||
c.SetNZ(v)
|
||||
c.setNZ(v)
|
||||
}
|
||||
|
||||
func dec(c *cpu, value byte) byte {
|
||||
result := value - 1
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func dex(c *cpu) {
|
||||
c.r.X--
|
||||
c.SetNZ(c.r.X)
|
||||
c.setNZ(c.r.X)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func dey(c *cpu) {
|
||||
c.r.Y--
|
||||
c.SetNZ(c.r.Y)
|
||||
c.setNZ(c.r.Y)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func eor(c *cpu, value byte) {
|
||||
c.r.A ^= value
|
||||
c.SetNZ(c.r.A)
|
||||
c.setNZ(c.r.A)
|
||||
}
|
||||
|
||||
func inc(c *cpu, value byte) byte {
|
||||
result := value + 1
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func inx(c *cpu) {
|
||||
c.r.X++
|
||||
c.SetNZ(c.r.X)
|
||||
c.setNZ(c.r.X)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func iny(c *cpu) {
|
||||
c.r.Y++
|
||||
c.SetNZ(c.r.Y)
|
||||
c.setNZ(c.r.Y)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
@ -294,29 +304,29 @@ func jsr(c *cpu) {
|
||||
|
||||
func lda(c *cpu, value byte) {
|
||||
c.r.A = value
|
||||
c.SetNZ(value)
|
||||
c.setNZ(value)
|
||||
}
|
||||
|
||||
func ldx(c *cpu, value byte) {
|
||||
c.r.X = value
|
||||
c.SetNZ(value)
|
||||
c.setNZ(value)
|
||||
}
|
||||
|
||||
func ldy(c *cpu, value byte) {
|
||||
c.r.Y = value
|
||||
c.SetNZ(value)
|
||||
c.setNZ(value)
|
||||
}
|
||||
|
||||
func lsr(c *cpu, value byte) byte {
|
||||
result := (value >> 1)
|
||||
c.r.P = (c.r.P &^ FLAG_C) | (value & FLAG_C)
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func ora(c *cpu, value byte) {
|
||||
c.r.A |= value
|
||||
c.SetNZ(c.r.A)
|
||||
c.setNZ(c.r.A)
|
||||
}
|
||||
|
||||
func nop(c *cpu) {
|
||||
@ -355,14 +365,14 @@ func plp(c *cpu) {
|
||||
func rol(c *cpu, value byte) byte {
|
||||
result := value<<1 | (c.r.P & FLAG_C)
|
||||
c.r.P = (c.r.P &^ FLAG_C) | (value >> 7)
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func ror(c *cpu, value byte) byte {
|
||||
result := (value >> 1) | (c.r.P << 7)
|
||||
c.r.P = (c.r.P &^ FLAG_C) | (value & FLAG_C)
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
return result
|
||||
}
|
||||
|
||||
@ -424,7 +434,7 @@ func sbc_bin(c *cpu, value byte) byte {
|
||||
if (c.r.A^result)&(value^result)&0x80 > 0 {
|
||||
c.r.P |= FLAG_V
|
||||
}
|
||||
c.SetNZ(result)
|
||||
c.setNZ(result)
|
||||
return result
|
||||
}
|
||||
|
||||
@ -466,7 +476,7 @@ func sbc_d(c *cpu, value byte) {
|
||||
// fmt.Printf(" a=$%04X ($%02X)\n", a, byte(a))
|
||||
c.r.A = byte(a)
|
||||
c.t.Tick()
|
||||
c.SetNZ(c.r.A)
|
||||
c.setNZ(c.r.A)
|
||||
default:
|
||||
panic("Unknown chip version")
|
||||
}
|
||||
@ -486,25 +496,25 @@ func sty(c *cpu) byte {
|
||||
|
||||
func tax(c *cpu) {
|
||||
c.r.X = c.r.A
|
||||
c.SetNZ(c.r.X)
|
||||
c.setNZ(c.r.X)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func tay(c *cpu) {
|
||||
c.r.Y = c.r.A
|
||||
c.SetNZ(c.r.Y)
|
||||
c.setNZ(c.r.Y)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func tsx(c *cpu) {
|
||||
c.r.X = c.r.SP
|
||||
c.SetNZ(c.r.X)
|
||||
c.setNZ(c.r.X)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
func txa(c *cpu) {
|
||||
c.r.A = c.r.X
|
||||
c.SetNZ(c.r.A)
|
||||
c.setNZ(c.r.A)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
||||
@ -515,6 +525,6 @@ func txs(c *cpu) {
|
||||
|
||||
func tya(c *cpu) {
|
||||
c.r.A = c.r.Y
|
||||
c.SetNZ(c.r.A)
|
||||
c.setNZ(c.r.A)
|
||||
c.t.Tick()
|
||||
}
|
||||
|
@ -1,5 +1,13 @@
|
||||
package cpu
|
||||
|
||||
// BUG(zellyn): 6502 should do invalid reads when doing indexed
|
||||
// addressing across page boundaries. See
|
||||
// http://en.wikipedia.org/wiki/MOS_Technology_6502#Bugs_and_quirks.
|
||||
|
||||
// BUG(zellyn): rmw instructions should write old data back on 6502,
|
||||
// read twice on 65C02. See
|
||||
// http://en.wikipedia.org/wiki/MOS_Technology_6502#Bugs_and_quirks.
|
||||
|
||||
// immediate2 performs 2-opcode, 2-cycle immediate mode instructions.
|
||||
func immediate2(f func(*cpu, byte)) func(*cpu) {
|
||||
return func(c *cpu) {
|
||||
|
@ -50,6 +50,8 @@ var NoOp = Opcode{"???", MODE_IMPLIED, nil}
|
||||
|
||||
// The list of Opcodes.
|
||||
var Opcodes = map[byte]Opcode{
|
||||
// BUG(zellyn): Add 65C02 instructions.
|
||||
|
||||
// Flag set and clear
|
||||
0x18: {"CLC", MODE_IMPLIED, clearFlag(FLAG_C)}, // CLC
|
||||
0xD8: {"CLD", MODE_IMPLIED, clearFlag(FLAG_D)}, // CLD
|
||||
|
Loading…
x
Reference in New Issue
Block a user