Skip to content

Commit af4d734

Browse files
committed
cpu: add basic support for 65C02 opcodes
Add support for the new addressing modes and new instructions in the 65C02 family of processors. The distinction is noted in the source but is not exposed to the programmer yet. New instructions: BRA, PHX, PHY, PLX, PLY, STZ, TRB and TSB. Add the (zp) addressing mode to ADC, AND, CMP, EOR, LDA, ORA, SBC and STA. Add (abs,X) and (zp,X) addressing modes to BIT. Add accumulator implicit target for DEC/INC. Add (abs,X) addressing mode for JMP.
1 parent 8cbd0f5 commit af4d734

File tree

2 files changed

+159
-9
lines changed

2 files changed

+159
-9
lines changed

cpu/cpu.go

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,16 @@ func (c *Cpu) memoryAddress(in Instruction) uint16 {
156156
return uint16(in.Op8 + c.X)
157157
case zeropageY:
158158
return uint16(in.Op8 + c.Y)
159+
160+
// 65C02-only modes
161+
case zpindirect:
162+
return c.Bus.Read16(uint16(in.Op8))
163+
case indirect:
164+
return c.Bus.Read16(uint16(in.Op16))
165+
159166
default:
160-
panic("unhandled addressing")
167+
panic(fmt.Sprintf("unhandled addressing mode: %v",
168+
addressingNames[in.addressing]))
161169
}
162170
}
163171

@@ -304,6 +312,24 @@ func (c *Cpu) execute(in Instruction) {
304312
c.TXS(in)
305313
case tya:
306314
c.TYA(in)
315+
316+
// 65C02 only
317+
case phx:
318+
c.PHX(in)
319+
case phy:
320+
c.PHY(in)
321+
case plx:
322+
c.PLX(in)
323+
case ply:
324+
c.PLY(in)
325+
case stz:
326+
c.STZ(in)
327+
case bra:
328+
c.BRA(in)
329+
case trb:
330+
c.TRB(in)
331+
case tsb:
332+
c.TSB(in)
307333
case _end:
308334
c._END(in)
309335
default:
@@ -371,6 +397,22 @@ func (c *Cpu) BIT(in Instruction) {
371397
c.setStatus(sNegative, value&(1<<7) != 0)
372398
}
373399

400+
// TRB: Test and Reset bits
401+
func (c *Cpu) TRB(in Instruction) {
402+
value := c.resolveOperand(in)
403+
c.setStatus(sZero, value&c.AC == 0)
404+
// note: the bits which are *set* in AC are *cleared* in value
405+
c.Bus.Write(c.memoryAddress(in), value&(c.AC^0xFF))
406+
}
407+
408+
// TSB: Test and Set bits
409+
func (c *Cpu) TSB(in Instruction) {
410+
value := c.resolveOperand(in)
411+
c.setStatus(sZero, value&c.AC == 0)
412+
// note: the bits which are *set* in AC are *set* in value
413+
c.Bus.Write(c.memoryAddress(in), value|c.AC)
414+
}
415+
374416
// BMI: Branch if negative.
375417
func (c *Cpu) BMI(in Instruction) {
376418
if c.getStatus(sNegative) {
@@ -392,6 +434,11 @@ func (c *Cpu) BPL(in Instruction) {
392434
}
393435
}
394436

437+
// BRA: Unconditional branch
438+
func (c *Cpu) BRA(in Instruction) {
439+
c.branch(in)
440+
}
441+
395442
// BRK: software interrupt
396443
func (c *Cpu) BRK(in Instruction) {
397444
// temporarily used to dump status
@@ -436,10 +483,17 @@ func (c *Cpu) CPY(in Instruction) {
436483

437484
// DEC: Decrement.
438485
func (c *Cpu) DEC(in Instruction) {
439-
address := c.memoryAddress(in)
440-
value := c.Bus.Read(address) - 1
441-
c.Bus.Write(address, value)
442-
c.updateStatus(value)
486+
switch in.addressing {
487+
case implied:
488+
// 65C02 only: decrement accumulator
489+
c.AC--
490+
c.updateStatus(c.AC)
491+
default:
492+
address := c.memoryAddress(in)
493+
value := c.Bus.Read(address) - 1
494+
c.Bus.Write(address, value)
495+
c.updateStatus(value)
496+
}
443497
}
444498

445499
// DEX: Decrement index register X.
@@ -463,10 +517,17 @@ func (c *Cpu) EOR(in Instruction) {
463517

464518
// INC: Increment.
465519
func (c *Cpu) INC(in Instruction) {
466-
address := c.memoryAddress(in)
467-
value := c.Bus.Read(address) + 1
468-
c.Bus.Write(address, value)
469-
c.updateStatus(value)
520+
switch in.addressing {
521+
case implied:
522+
// 65C02 only: increment accumulator
523+
c.AC++
524+
c.updateStatus(c.AC)
525+
default:
526+
address := c.memoryAddress(in)
527+
value := c.Bus.Read(address) + 1
528+
c.Bus.Write(address, value)
529+
c.updateStatus(value)
530+
}
470531
}
471532

472533
// INX: Increment index register X.
@@ -550,6 +611,30 @@ func (c *Cpu) PLA(in Instruction) {
550611
c.AC = c.Bus.Read(0x0100 + uint16(c.SP))
551612
}
552613

614+
// PHX: Push X onto stack.
615+
func (c *Cpu) PHX(in Instruction) {
616+
c.Bus.Write(0x0100+uint16(c.SP), c.X)
617+
c.SP--
618+
}
619+
620+
// PLX: Pull X from stack.
621+
func (c *Cpu) PLX(in Instruction) {
622+
c.SP++
623+
c.X = c.Bus.Read(0x0100 + uint16(c.SP))
624+
}
625+
626+
// PHY: Push Y onto stack.
627+
func (c *Cpu) PHY(in Instruction) {
628+
c.Bus.Write(0x0100+uint16(c.SP), c.Y)
629+
c.SP--
630+
}
631+
632+
// PLY: Pull Y from stack.
633+
func (c *Cpu) PLY(in Instruction) {
634+
c.SP++
635+
c.Y = c.Bus.Read(0x0100 + uint16(c.SP))
636+
}
637+
553638
// ROL: Rotate memory or accumulator left one bit.
554639
func (c *Cpu) ROL(in Instruction) {
555640
carry := c.getStatusInt(sCarry)
@@ -637,6 +722,11 @@ func (c *Cpu) STY(in Instruction) {
637722
c.Bus.Write(c.memoryAddress(in), c.Y)
638723
}
639724

725+
// STZ: Store zero to memory.
726+
func (c *Cpu) STZ(in Instruction) {
727+
c.Bus.Write(c.memoryAddress(in), 0)
728+
}
729+
640730
// TAX: Transfer accumulator to index register X.
641731
func (c *Cpu) TAX(in Instruction) {
642732
c.X = c.AC

cpu/op_type.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ const (
1818
zeropage
1919
zeropageX
2020
zeropageY
21+
22+
// 65C02 only
23+
zpindirect
2124
)
2225

2326
var addressingNames = [...]string{
@@ -35,6 +38,7 @@ var addressingNames = [...]string{
3538
"zeropage",
3639
"zeropageX",
3740
"zeropageY",
41+
"(zeropage)",
3842
}
3943

4044
// adc..tya represent the 6502 instruction set mnemonics. Each mnemonic maps to
@@ -97,6 +101,17 @@ const (
97101
txa
98102
txs
99103
tya
104+
105+
// 65{S}C02-only
106+
bra
107+
phx
108+
phy
109+
plx
110+
ply
111+
stz
112+
trb
113+
tsb
114+
100115
_end
101116
)
102117

@@ -158,6 +173,17 @@ var instructionNames = [...]string{
158173
"TXA",
159174
"TXS",
160175
"TYA",
176+
177+
// 65{S}C02-only
178+
"BRA",
179+
"PHX",
180+
"PHY",
181+
"PLX",
182+
"PLY",
183+
"STZ",
184+
"TRB",
185+
"TSB",
186+
161187
"_END",
162188
}
163189

@@ -351,5 +377,39 @@ var optypes = map[uint8]OpType{
351377
0x8A: OpType{0x8A, txa, implied, 1, 2},
352378
0x9A: OpType{0x9A, txs, implied, 1, 2},
353379
0x98: OpType{0x98, tya, implied, 1, 2},
380+
381+
// 65C02 only
382+
383+
// Additional addressing modes
384+
0x12: OpType{0x12, ora, zpindirect, 2, 5},
385+
0x32: OpType{0x32, and, zpindirect, 2, 5},
386+
0x52: OpType{0x52, eor, zpindirect, 2, 5},
387+
0x72: OpType{0x72, adc, zpindirect, 2, 5},
388+
0x92: OpType{0x92, sta, zpindirect, 2, 5},
389+
0xB2: OpType{0xB2, lda, zpindirect, 2, 5},
390+
0xD2: OpType{0xD2, cmp, zpindirect, 2, 5},
391+
0xF2: OpType{0xF2, sbc, zpindirect, 2, 5},
392+
0x89: OpType{0x89, bit, immediate, 2, 2},
393+
0x34: OpType{0x34, bit, zeropageX, 2, 4},
394+
0x3C: OpType{0x3C, bit, absoluteX, 3, 4},
395+
0x3A: OpType{0x3A, dec, implied, 1, 2},
396+
0x1A: OpType{0x1A, inc, implied, 1, 2},
397+
0x7C: OpType{0x7C, jmp, absoluteX, 3, 6},
398+
399+
// New instructions
400+
0x80: OpType{0x80, bra, relative, 2, 3},
401+
0xDA: OpType{0xDA, phx, implied, 1, 3},
402+
0x5A: OpType{0x5A, phy, implied, 1, 3},
403+
0xFA: OpType{0xFA, plx, implied, 1, 4},
404+
0x7A: OpType{0x7A, ply, implied, 1, 4},
405+
0x64: OpType{0x64, stz, zeropage, 2, 3},
406+
0x74: OpType{0x74, stz, zeropageX, 2, 4},
407+
0x9C: OpType{0x9C, stz, absolute, 3, 4},
408+
0x9E: OpType{0x9E, stz, absoluteX, 3, 5},
409+
0x14: OpType{0x14, trb, zeropage, 2, 5},
410+
0x1C: OpType{0x1C, trb, absolute, 3, 6},
411+
0x04: OpType{0x04, tsb, zeropage, 2, 5},
412+
0x0C: OpType{0x0C, tsb, absolute, 3, 5},
413+
354414
0xFF: OpType{0xFF, _end, implied, 1, 1},
355415
}

0 commit comments

Comments
 (0)