mirror of
https://github.com/ariejan/i6502.git
synced 2025-04-08 21:43:30 +00:00
Implement more opcodes, minor improvements
This commit is contained in:
parent
9c8f47abbc
commit
f3f95dda39
67
cpu.go
67
cpu.go
@ -7,6 +7,7 @@ type Cpu struct {
|
||||
|
||||
PC uint16 // 16-bit program counter
|
||||
P byte // Status Register
|
||||
SP byte // Stack Pointer
|
||||
|
||||
A byte // Accumulator
|
||||
X byte // X index register
|
||||
@ -52,8 +53,74 @@ func (c *Cpu) Step() {
|
||||
|
||||
func (c *Cpu) execute(instruction Instruction) {
|
||||
switch instruction.opcodeId {
|
||||
case nop:
|
||||
break
|
||||
case adc:
|
||||
c.ADC(instruction)
|
||||
case sbc:
|
||||
c.SBC(instruction)
|
||||
case sec:
|
||||
c.setCarry(true)
|
||||
case sed:
|
||||
c.setDecimal(true)
|
||||
case sei:
|
||||
c.setInterrupt(true)
|
||||
case clc:
|
||||
c.setCarry(false)
|
||||
case cld:
|
||||
c.setDecimal(false)
|
||||
case cli:
|
||||
c.setInterrupt(false)
|
||||
case clv:
|
||||
c.setOverflow(false)
|
||||
case inx:
|
||||
c.setX(c.X + 1)
|
||||
case iny:
|
||||
c.setY(c.Y + 1)
|
||||
case inc:
|
||||
c.INC(instruction)
|
||||
case dex:
|
||||
c.setX(c.X - 1)
|
||||
case dey:
|
||||
c.setY(c.Y - 1)
|
||||
case dec:
|
||||
c.DEC(instruction)
|
||||
case lda:
|
||||
c.LDA(instruction)
|
||||
case ldx:
|
||||
c.LDX(instruction)
|
||||
case ldy:
|
||||
c.LDY(instruction)
|
||||
case ora:
|
||||
c.ORA(instruction)
|
||||
case and:
|
||||
c.AND(instruction)
|
||||
case eor:
|
||||
c.EOR(instruction)
|
||||
case sta:
|
||||
c.STA(instruction)
|
||||
case stx:
|
||||
c.STX(instruction)
|
||||
case sty:
|
||||
c.STY(instruction)
|
||||
case tax:
|
||||
c.setX(c.A)
|
||||
case tay:
|
||||
c.setY(c.A)
|
||||
case txa:
|
||||
c.setA(c.X)
|
||||
case tya:
|
||||
c.setA(c.Y)
|
||||
case tsx:
|
||||
c.setX(c.SP)
|
||||
case txs:
|
||||
c.setSP(c.X)
|
||||
case asl:
|
||||
c.ASL(instruction)
|
||||
case lsr:
|
||||
c.LSR(instruction)
|
||||
default:
|
||||
panic(fmt.Errorf("Unimplemented instruction: %s", instruction))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,15 +3,120 @@ package i6502
|
||||
// Add Memory to Accumulator with Carry
|
||||
func (c *Cpu) ADC(in Instruction) {
|
||||
operand := c.resolveOperand(in)
|
||||
carryIn := c.getStatusInt(sCarry)
|
||||
carryIn := c.getCarryInt()
|
||||
|
||||
if c.getStatus(sDecimal) {
|
||||
if c.getDecimal() {
|
||||
c.adcDecimal(c.A, operand, carryIn)
|
||||
} else {
|
||||
c.adcNormal(c.A, operand, carryIn)
|
||||
}
|
||||
}
|
||||
|
||||
// Substract memory from Accummulator with carry
|
||||
func (c *Cpu) SBC(in Instruction) {
|
||||
operand := c.resolveOperand(in)
|
||||
carryIn := c.getCarryInt()
|
||||
|
||||
if c.getDecimal() {
|
||||
c.sbcDecimal(c.A, operand, carryIn)
|
||||
} else {
|
||||
c.adcNormal(c.A, ^operand, carryIn)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cpu) INC(in Instruction) {
|
||||
address := c.memoryAddress(in)
|
||||
value := c.bus.Read(address) + 1
|
||||
|
||||
c.bus.Write(address, value)
|
||||
c.setArithmeticFlags(value)
|
||||
}
|
||||
|
||||
func (c *Cpu) DEC(in Instruction) {
|
||||
address := c.memoryAddress(in)
|
||||
value := c.bus.Read(address) - 1
|
||||
|
||||
c.bus.Write(address, value)
|
||||
c.setArithmeticFlags(value)
|
||||
}
|
||||
|
||||
func (c *Cpu) LDA(in Instruction) {
|
||||
value := c.resolveOperand(in)
|
||||
c.setA(value)
|
||||
}
|
||||
|
||||
func (c *Cpu) LDX(in Instruction) {
|
||||
value := c.resolveOperand(in)
|
||||
c.setX(value)
|
||||
}
|
||||
|
||||
func (c *Cpu) LDY(in Instruction) {
|
||||
value := c.resolveOperand(in)
|
||||
c.setY(value)
|
||||
}
|
||||
|
||||
func (c *Cpu) ORA(in Instruction) {
|
||||
value := c.resolveOperand(in)
|
||||
c.setA(c.A | value)
|
||||
}
|
||||
|
||||
func (c *Cpu) AND(in Instruction) {
|
||||
value := c.resolveOperand(in)
|
||||
c.setA(c.A & value)
|
||||
}
|
||||
|
||||
func (c *Cpu) EOR(in Instruction) {
|
||||
value := c.resolveOperand(in)
|
||||
c.setA(c.A ^ value)
|
||||
}
|
||||
|
||||
func (c *Cpu) STA(in Instruction) {
|
||||
address := c.memoryAddress(in)
|
||||
c.bus.Write(address, c.A)
|
||||
}
|
||||
|
||||
func (c *Cpu) STX(in Instruction) {
|
||||
address := c.memoryAddress(in)
|
||||
c.bus.Write(address, c.X)
|
||||
}
|
||||
|
||||
func (c *Cpu) STY(in Instruction) {
|
||||
address := c.memoryAddress(in)
|
||||
c.bus.Write(address, c.Y)
|
||||
}
|
||||
|
||||
func (c *Cpu) ASL(in Instruction) {
|
||||
switch in.addressingId {
|
||||
case accumulator:
|
||||
c.setCarry((c.A >> 7) == 1)
|
||||
c.A <<= 1
|
||||
c.setArithmeticFlags(c.A)
|
||||
default:
|
||||
address := c.memoryAddress(in)
|
||||
value := c.bus.Read(address)
|
||||
c.setCarry((value >> 7) == 1)
|
||||
value <<= 1
|
||||
c.bus.Write(address, value)
|
||||
c.setArithmeticFlags(value)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cpu) LSR(in Instruction) {
|
||||
switch in.addressingId {
|
||||
case accumulator:
|
||||
c.setCarry((c.A & 0x01) == 1)
|
||||
c.A >>= 1
|
||||
c.setArithmeticFlags(c.A)
|
||||
default:
|
||||
address := c.memoryAddress(in)
|
||||
value := c.bus.Read(address)
|
||||
c.setCarry((value & 0x01) == 1)
|
||||
value >>= 1
|
||||
c.bus.Write(address, value)
|
||||
c.setArithmeticFlags(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Performs regular, 8-bit addition
|
||||
func (c *Cpu) adcNormal(a uint8, b uint8, carryIn uint8) {
|
||||
result16 := uint16(a) + uint16(b) + uint16(carryIn)
|
||||
@ -24,9 +129,7 @@ func (c *Cpu) adcNormal(a uint8, b uint8, carryIn uint8) {
|
||||
// Set the overflow bit
|
||||
c.setOverflow(overflow)
|
||||
// Store the resulting value (8-bits)
|
||||
c.A = result
|
||||
// Update sZero and sNegative
|
||||
c.setArithmeticFlags(c.A)
|
||||
c.setA(result)
|
||||
}
|
||||
|
||||
// Performs addition in decimal mode
|
||||
@ -50,7 +153,35 @@ func (c *Cpu) adcDecimal(a uint8, b uint8, carryIn uint8) {
|
||||
|
||||
c.setCarry(high > 15)
|
||||
c.setZero(result == 0)
|
||||
c.setNegative(false) // BCD is never negative
|
||||
c.setNegative(false) // BCD never sets negative
|
||||
c.setOverflow(false) // BCD never sets overflow
|
||||
|
||||
c.A = result
|
||||
}
|
||||
|
||||
func (c *Cpu) sbcDecimal(a uint8, b uint8, carryIn uint8) {
|
||||
var carryB uint8 = 0
|
||||
|
||||
carryIn = (carryIn + 1) % 1
|
||||
|
||||
low := (a & 0x0F) - (b & 0x0F) - carryIn
|
||||
if (low & 0x10) != 0 {
|
||||
low -= 6
|
||||
}
|
||||
if (low & 0x10) != 0 {
|
||||
carryB = 1
|
||||
}
|
||||
|
||||
high := (a >> 4) - (b >> 4) - carryB
|
||||
if (high & 0x10) != 0 {
|
||||
high -= 6
|
||||
}
|
||||
|
||||
result := (low & 0x0F) | (high << 4)
|
||||
|
||||
c.setCarry((high & 0xFF) < 15)
|
||||
c.setZero(result == 0)
|
||||
c.setNegative(false) // BCD never sets negative
|
||||
c.setOverflow(false) // BCD never sets overflow
|
||||
|
||||
c.A = result
|
||||
|
@ -32,18 +32,62 @@ func (c *Cpu) setCarry(state bool) {
|
||||
c.setStatus(sCarry, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) setOverflow(state bool) {
|
||||
c.setStatus(sOverflow, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) setZero(state bool) {
|
||||
c.setStatus(sZero, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) setInterrupt(state bool) {
|
||||
c.setStatus(sInterrupt, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) setDecimal(state bool) {
|
||||
c.setStatus(sDecimal, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) setBreak(state bool) {
|
||||
c.setStatus(sBreak, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) setOverflow(state bool) {
|
||||
c.setStatus(sOverflow, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) setNegative(state bool) {
|
||||
c.setStatus(sNegative, state)
|
||||
}
|
||||
|
||||
func (c *Cpu) getCarry() bool {
|
||||
return c.getStatus(sCarry)
|
||||
}
|
||||
|
||||
func (c *Cpu) getCarryInt() uint8 {
|
||||
return c.getStatusInt(sCarry)
|
||||
}
|
||||
|
||||
func (c *Cpu) getZero() bool {
|
||||
return c.getStatus(sZero)
|
||||
}
|
||||
|
||||
func (c *Cpu) getInterrupt() bool {
|
||||
return c.getStatus(sInterrupt)
|
||||
}
|
||||
|
||||
func (c *Cpu) getDecimal() bool {
|
||||
return c.getStatus(sDecimal)
|
||||
}
|
||||
|
||||
func (c *Cpu) getBreak() bool {
|
||||
return c.getStatus(sBreak)
|
||||
}
|
||||
|
||||
func (c *Cpu) getOverflow() bool {
|
||||
return c.getStatus(sOverflow)
|
||||
}
|
||||
|
||||
func (c *Cpu) getNegative() bool {
|
||||
return c.getStatus(sNegative)
|
||||
}
|
||||
|
||||
func (c *Cpu) setArithmeticFlags(value uint8) {
|
||||
// Set sZero if value is 0
|
||||
c.setStatus(sZero, value == 0)
|
||||
@ -53,3 +97,23 @@ func (c *Cpu) setArithmeticFlags(value uint8) {
|
||||
// negatives
|
||||
c.setStatus(sNegative, (value>>7) == 1)
|
||||
}
|
||||
|
||||
func (c *Cpu) setA(value byte) {
|
||||
c.A = value
|
||||
c.setArithmeticFlags(c.A)
|
||||
}
|
||||
|
||||
func (c *Cpu) setX(value byte) {
|
||||
c.X = value
|
||||
c.setArithmeticFlags(c.X)
|
||||
}
|
||||
|
||||
func (c *Cpu) setY(value byte) {
|
||||
c.Y = value
|
||||
c.setArithmeticFlags(c.Y)
|
||||
}
|
||||
|
||||
func (c *Cpu) setSP(value byte) {
|
||||
c.SP = value
|
||||
c.setArithmeticFlags(c.SP)
|
||||
}
|
||||
|
1706
cpu_test.go
1706
cpu_test.go
File diff suppressed because it is too large
Load Diff
147
opcodes.go
147
opcodes.go
@ -144,12 +144,157 @@ type OpType struct {
|
||||
var opTypes = map[uint8]OpType{
|
||||
0xEA: OpType{0xEA, nop, implied, 1, 2},
|
||||
|
||||
// Set instruction
|
||||
0x38: OpType{0x38, sec, implied, 1, 2},
|
||||
0xF8: OpType{0xF8, sed, implied, 1, 2},
|
||||
0x78: OpType{0x78, sei, implied, 1, 2},
|
||||
|
||||
// Clear instructions
|
||||
0x18: OpType{0x18, clc, implied, 1, 2},
|
||||
0xD8: OpType{0xD8, cld, implied, 1, 2},
|
||||
0x58: OpType{0x58, cli, implied, 1, 2},
|
||||
0xB8: OpType{0xB8, clv, implied, 1, 2},
|
||||
|
||||
// ADC
|
||||
0x69: OpType{0x69, adc, immediate, 2, 2},
|
||||
0x65: OpType{0x65, adc, zeropage, 2, 2},
|
||||
0x65: OpType{0x65, adc, zeropage, 2, 3},
|
||||
0x75: OpType{0x75, adc, zeropageX, 2, 4},
|
||||
0x6D: OpType{0x6D, adc, absolute, 3, 4},
|
||||
0x7D: OpType{0x7D, adc, absoluteX, 3, 4},
|
||||
0x79: OpType{0x79, adc, absoluteY, 3, 4},
|
||||
0x61: OpType{0x61, adc, indirectX, 2, 6},
|
||||
0x71: OpType{0x71, adc, indirectY, 2, 5},
|
||||
|
||||
// SBC
|
||||
0xE9: OpType{0xE9, sbc, immediate, 2, 2},
|
||||
0xE5: OpType{0xE5, sbc, zeropage, 2, 3},
|
||||
0xF5: OpType{0xF5, sbc, zeropageX, 2, 4},
|
||||
0xED: OpType{0xED, sbc, absolute, 3, 4},
|
||||
0xFD: OpType{0xFD, sbc, absoluteX, 3, 4},
|
||||
0xF9: OpType{0xF9, sbc, absoluteY, 3, 4},
|
||||
0xE1: OpType{0xE1, sbc, indirectX, 2, 6},
|
||||
0xF1: OpType{0xF1, sbc, indirectY, 2, 5},
|
||||
|
||||
// Increments
|
||||
0xE8: OpType{0xE8, inx, implied, 1, 2},
|
||||
0xC8: OpType{0xC8, iny, implied, 1, 2},
|
||||
|
||||
0xE6: OpType{0xE6, inc, zeropage, 2, 5},
|
||||
0xF6: OpType{0xF6, inc, zeropageX, 2, 6},
|
||||
0xEE: OpType{0xEE, inc, absolute, 3, 6},
|
||||
0xFE: OpType{0xFE, inc, absoluteX, 3, 7},
|
||||
|
||||
// Decrements
|
||||
0xCA: OpType{0xCA, dex, implied, 1, 2},
|
||||
0x88: OpType{0x88, dey, implied, 1, 2},
|
||||
|
||||
0xC6: OpType{0xC6, dec, zeropage, 2, 5},
|
||||
0xD6: OpType{0xD6, dec, zeropageX, 2, 6},
|
||||
0xCE: OpType{0xCE, dec, absolute, 3, 6},
|
||||
0xDE: OpType{0xDE, dec, absoluteX, 3, 7},
|
||||
|
||||
// LDA
|
||||
0xA9: OpType{0xA9, lda, immediate, 2, 2},
|
||||
0xA5: OpType{0xA5, lda, zeropage, 2, 3},
|
||||
0xB5: OpType{0xB5, lda, zeropageX, 2, 4},
|
||||
0xAD: OpType{0xAD, lda, absolute, 3, 4},
|
||||
0xBD: OpType{0xBD, lda, absoluteX, 3, 4},
|
||||
0xB9: OpType{0xB9, lda, absoluteY, 3, 4},
|
||||
0xA1: OpType{0xA1, lda, indirectX, 2, 6},
|
||||
0xB1: OpType{0xB1, lda, indirectY, 2, 5},
|
||||
|
||||
// LDX
|
||||
0xA2: OpType{0xA2, ldx, immediate, 2, 2},
|
||||
0xA6: OpType{0xA6, ldx, zeropage, 2, 3},
|
||||
0xB6: OpType{0xB6, ldx, zeropageY, 2, 4},
|
||||
0xAE: OpType{0xAE, ldx, absolute, 3, 4},
|
||||
0xBE: OpType{0xBE, ldx, absoluteY, 3, 4},
|
||||
|
||||
// LDY
|
||||
0xA0: OpType{0xA0, ldy, immediate, 2, 2},
|
||||
0xA4: OpType{0xA4, ldy, zeropage, 2, 3},
|
||||
0xB4: OpType{0xB4, ldy, zeropageY, 2, 4},
|
||||
0xAC: OpType{0xAC, ldy, absolute, 3, 4},
|
||||
0xBC: OpType{0xBC, ldy, absoluteY, 3, 4},
|
||||
|
||||
// ORA
|
||||
0x09: OpType{0x09, ora, immediate, 2, 2},
|
||||
0x05: OpType{0x05, ora, zeropage, 2, 3},
|
||||
0x15: OpType{0x15, ora, zeropageX, 2, 4},
|
||||
0x0D: OpType{0x0D, ora, absolute, 3, 4},
|
||||
0x1D: OpType{0x1D, ora, absoluteX, 3, 4},
|
||||
0x19: OpType{0x19, ora, absoluteY, 3, 4},
|
||||
0x01: OpType{0x01, ora, indirectX, 2, 6},
|
||||
0x11: OpType{0x11, ora, indirectY, 2, 5},
|
||||
|
||||
// AND
|
||||
0x29: OpType{0x29, and, immediate, 2, 2},
|
||||
0x25: OpType{0x25, and, zeropage, 2, 3},
|
||||
0x35: OpType{0x35, and, zeropageX, 2, 4},
|
||||
0x2D: OpType{0x2D, and, absolute, 3, 4},
|
||||
0x3D: OpType{0x3D, and, absoluteX, 3, 4},
|
||||
0x39: OpType{0x39, and, absoluteY, 3, 4},
|
||||
0x21: OpType{0x21, and, indirectX, 2, 6},
|
||||
0x31: OpType{0x31, and, indirectY, 2, 5},
|
||||
|
||||
// EOR
|
||||
0x49: OpType{0x49, eor, immediate, 2, 2},
|
||||
0x45: OpType{0x45, eor, zeropage, 2, 3},
|
||||
0x55: OpType{0x55, eor, zeropageX, 2, 4},
|
||||
0x4D: OpType{0x4D, eor, absolute, 3, 4},
|
||||
0x5D: OpType{0x5D, eor, absoluteX, 3, 4},
|
||||
0x59: OpType{0x59, eor, absoluteY, 3, 4},
|
||||
0x41: OpType{0x41, eor, indirectX, 2, 6},
|
||||
0x51: OpType{0x51, eor, indirectY, 2, 5},
|
||||
|
||||
// STA
|
||||
0x85: OpType{0x85, sta, zeropage, 2, 3},
|
||||
0x95: OpType{0x95, sta, zeropageX, 2, 4},
|
||||
0x8D: OpType{0x8D, sta, absolute, 3, 4},
|
||||
0x9D: OpType{0x9D, sta, absoluteX, 3, 5},
|
||||
0x99: OpType{0x99, sta, absoluteY, 3, 5},
|
||||
0x81: OpType{0x81, sta, indirectX, 2, 6},
|
||||
0x91: OpType{0x91, sta, indirectY, 2, 6},
|
||||
|
||||
// STX
|
||||
0x86: OpType{0x86, stx, zeropage, 2, 3},
|
||||
0x96: OpType{0x96, stx, zeropageY, 2, 4},
|
||||
0x8E: OpType{0x8E, stx, absolute, 3, 4},
|
||||
|
||||
// STY
|
||||
0x84: OpType{0x84, sty, zeropage, 2, 3},
|
||||
0x94: OpType{0x94, sty, zeropageX, 2, 4},
|
||||
0x8C: OpType{0x8C, sty, absolute, 3, 4},
|
||||
|
||||
// TAX
|
||||
0xAA: OpType{0xAA, tax, implied, 1, 2},
|
||||
|
||||
// TAY
|
||||
0xA8: OpType{0xA8, tay, implied, 1, 2},
|
||||
|
||||
// TXA
|
||||
0x8A: OpType{0x8A, txa, implied, 1, 2},
|
||||
|
||||
// TXA
|
||||
0x98: OpType{0x98, tya, implied, 1, 2},
|
||||
|
||||
// TSX
|
||||
0xBA: OpType{0xBA, tsx, implied, 1, 2},
|
||||
|
||||
// TXS
|
||||
0x9A: OpType{0x9A, txs, implied, 1, 2},
|
||||
|
||||
// ASL
|
||||
0x0A: OpType{0x0A, asl, accumulator, 1, 2},
|
||||
0x06: OpType{0x06, asl, zeropage, 2, 5},
|
||||
0x16: OpType{0x16, asl, zeropageX, 2, 6},
|
||||
0x0E: OpType{0x0E, asl, absolute, 3, 6},
|
||||
0x1E: OpType{0x1E, asl, absoluteX, 3, 7},
|
||||
|
||||
// LSR
|
||||
0x4A: OpType{0x4A, lsr, accumulator, 1, 2},
|
||||
0x46: OpType{0x46, lsr, zeropage, 2, 5},
|
||||
0x56: OpType{0x56, lsr, zeropageX, 2, 6},
|
||||
0x4E: OpType{0x4E, lsr, absolute, 3, 6},
|
||||
0x5E: OpType{0x5E, lsr, absoluteX, 3, 7},
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user