選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

8.6KB


name: 6510-assembly description: > Use this skill for any question about MOS 6510/6502 assembly language on the Commodore 64. Covers CPU registers, instruction set, addressing modes, writing and entering ML programs, using assemblers, the single-step simulator, and connecting ML to BASIC. Sources: The Machine Language Book for the C64, The Advanced Machine Language Book for the C64, The Anatomy of the C64, The Complete C64 ROM Disassembly.

6510 Assembly Language for the Commodore 64

The 6510 CPU

The Commodore 64 uses the MOS 6510 processor, which is a slightly modified 6502 with an additional 8-bit I/O port at addresses $0000–$0001. It runs at:

  • NTSC: 1,022,727 Hz (~1 MHz)
  • PAL: 985,248 Hz (~0.985 MHz)

CPU Registers

Register Size Description
A (Accumulator) 8-bit Primary arithmetic/logic register
X (Index X) 8-bit Index register, loop counter, offset
Y (Index Y) 8-bit Index register, loop counter, offset
PC (Program Counter) 16-bit Address of next instruction
SP (Stack Pointer) 8-bit Points into stack ($0100–$01FF)
SR (Status Register) 8-bit Processor flags

Status Register (SR) Flags

Bit 7  N  Negative   — Set if result bit 7 = 1
Bit 6  V  Overflow   — Set on signed arithmetic overflow
Bit 5  -  (always 1)
Bit 4  B  Break      — Set when BRK instruction executed
Bit 3  D  Decimal    — Decimal mode (BCD arithmetic)
Bit 2  I  IRQ Mask   — 1 = IRQ disabled
Bit 1  Z  Zero       — Set if result = 0
Bit 0  C  Carry      — Set on unsigned arithmetic carry/borrow

Addressing Modes

Mode Syntax Bytes Example Description
Implied 1 CLC Operand implied by opcode
Accumulator A 1 LSR A Operand is accumulator
Immediate #$nn 2 LDA #$41 Literal value
Zero Page $nn 2 LDA $FB Byte in zero page (fast!)
Zero Page,X $nn,X 2 LDA $FB,X Zero page + X
Zero Page,Y $nn,Y 2 LDX $FB,Y Zero page + Y
Absolute $nnnn 3 LDA $C000 16-bit address
Absolute,X $nnnn,X 3 LDA $C000,X 16-bit + X
Absolute,Y $nnnn,Y 3 LDA $C000,Y 16-bit + Y
Indirect ($nnnn) 3 JMP ($0314) Jump via pointer
(Indirect,X) ($nn,X) 2 LDA ($FC,X) Zero-page ptr + X (pre-indexed)
(Indirect),Y ($nn),Y 2 LDA ($FC),Y Zero-page ptr, then + Y (post-indexed)
Relative $nn 2 BEQ $+5 Branch offset (-128 to +127)

Performance note: Zero-page addressing is 1 cycle faster than absolute and uses 1 fewer byte. Use zero page for frequently accessed variables.


Complete Instruction Set Reference

Load/Store Instructions

LDA  Load Accumulator       N Z
LDX  Load X Register        N Z
LDY  Load Y Register        N Z
STA  Store Accumulator
STX  Store X Register
STY  Store Y Register

Transfer Instructions

TAX  Transfer A to X        N Z
TAY  Transfer A to Y        N Z
TXA  Transfer X to A        N Z
TYA  Transfer Y to A        N Z
TSX  Transfer SP to X       N Z
TXS  Transfer X to SP

Arithmetic Instructions

ADC  Add with Carry         N V Z C
SBC  Subtract with Carry    N V Z C
INC  Increment Memory       N Z
INX  Increment X            N Z
INY  Increment Y            N Z
DEC  Decrement Memory       N Z
DEX  Decrement X            N Z
DEY  Decrement Y            N Z

Important: Always use CLC before ADC and SEC before SBC unless chaining multi-byte math.

Logical Instructions

AND  AND with Accumulator   N Z
ORA  OR with Accumulator    N Z
EOR  XOR with Accumulator   N Z
BIT  Bit Test               N V Z

Shift and Rotate

ASL  Arithmetic Shift Left  N Z C    (multiply by 2)
LSR  Logical Shift Right    N Z C    (divide by 2)
ROL  Rotate Left            N Z C    (shift through carry)
ROR  Rotate Right           N Z C    (shift through carry)

Compare Instructions

CMP  Compare A with Memory  N Z C
CPX  Compare X with Memory  N Z C
CPY  Compare Y with Memory  N Z C

Branch Instructions (all relative, ±127 bytes)

BCC  Branch if Carry Clear       (C=0)
BCS  Branch if Carry Set         (C=1)
BEQ  Branch if Equal (zero)      (Z=1)
BNE  Branch if Not Equal         (Z=0)
BMI  Branch if Minus             (N=1)
BPL  Branch if Plus              (N=0)
BVC  Branch if Overflow Clear    (V=0)
BVS  Branch if Overflow Set      (V=1)

Jump and Subroutine

JMP  Jump (absolute or indirect)
JSR  Jump to Subroutine         (pushes PC-1 to stack)
RTS  Return from Subroutine     (pulls PC+1 from stack)
RTI  Return from Interrupt      (pulls SR then PC from stack)
BRK  Software Break/Interrupt

Stack Instructions

PHA  Push Accumulator to Stack
PLA  Pull Accumulator from Stack   N Z
PHP  Push Status Register to Stack
PLP  Pull Status Register from Stack

Flag Instructions

CLC  Clear Carry
SEC  Set Carry
CLI  Clear IRQ Mask (enable IRQs)
SEI  Set IRQ Mask (disable IRQs)
CLD  Clear Decimal Mode
SED  Set Decimal Mode
CLV  Clear Overflow
NOP  No Operation (2 cycles)

Multi-Byte Arithmetic

16-bit Addition

; Add 16-bit values at $FB/$FC to $FD/$FE
; Result in $FB/$FC
        CLC
        LDA $FB
        ADC $FD
        STA $FB
        LDA $FC
        ADC $FE         ; carry propagates
        STA $FC

16-bit Subtraction

        SEC
        LDA $FB
        SBC $FD
        STA $FB
        LDA $FC
        SBC $FE
        STA $FC

Entering ML Programs

Method 1: DATA Statements (most portable)

10 FOR I=49152 TO 49152+N : READ D : POKE I,D : NEXT
20 SYS 49152
100 DATA 169,72,32,210,255,169,73,32,210,255,96

Method 2: Using a ML Monitor (SUPERMON)

; After loading SUPERMON:
A C000      ; assemble at $C000
LDA #$41
JSR $FFD2   ; BSOUT - print char
RTS
; Press RETURN on empty line to exit
G C000      ; execute from $C000

Method 3: Using the Built-in Monitor (from BASIC)

SYS 1536    ; enter monitor (if SUPERMON at $0600)

Linking ML to BASIC

Simple SYS call

SYS 49152           ' call ML at $C000
SYS 49152,A,X,Y     ' with register values (some monitors)

Passing parameters via memory

POKE 251,LO : POKE 252,HI  ' pass address in ZP
SYS 49152
RESULT = PEEK(253)          ' read result back

USR function hook

Location $0311-$0312 contains the USR vector (default: $FFB7)
POKE 785, LO : POKE 786, HI  ' point USR to your routine
X = USR(VALUE)               ' call from BASIC, float in FAC

Useful ML Idioms

Clear accumulator quickly

LDA #0      ; or: AND #0  or: EOR #$FF ; not #$FF

Test if A = 0 without changing A

BEQ zero    ; branch if A was 0 (after any instruction that sets Z)

Delay loop (~1 second at 1MHz, NTSC)

DELAY   LDX #$FF
OUTER   LDY #$FF
INNER   DEY
        BNE INNER
        DEX
        BNE OUTER
        RTS

Copy a block of memory

; Copy $C000-$C0FF to $D000 (100 bytes example — NOT I/O area in practice!)
        LDX #0
LOOP    LDA $C000,X
        STA $CC00,X     ; adjust destination
        INX
        BNE LOOP        ; loop 256 times

Increment 16-bit pointer in zero page ($FB/$FC)

        INC $FB
        BNE SKIP
        INC $FC
SKIP    ...

Common Pitfalls

  1. Forgetting CLC/SEC before ADC/SBC — results will be off by 1
  2. Branch out of range — branches are ±127 bytes; use JMP workaround for longer distances
  3. Stack overflow — only 256 bytes of stack; watch nested JSR depth
  4. I/O area at $D000 — reading/writing here when I/O is banked in hits chip registers, not RAM
  5. Decimal mode — the 6510 supports BCD; make sure D flag is clear for normal math
  6. JMP ($nnFF) bug — the 6502/6510 has a page-crossing bug with indirect JMP: high byte is fetched from $nn00, not ($nnFF)+1
  7. Forgetting RTI vs RTS — IRQ handlers must use RTI; subroutines use RTS

6510-Specific: I/O Port ($0000/$0001)

The 6510 has a built-in 8-bit I/O port multiplexed at $0000 (direction) and $0001 (data):

$0000  Direction: 1=output, 0=input (default: $2F = %00101111)
$0001  Data port:
  Bit 0: LORAM  — 0=BASIC ROM off, 1=on
  Bit 1: HIRAM  — 0=Kernal ROM off, 1=on
  Bit 2: CHAREN — 0=Char ROM at $D000, 1=I/O at $D000
  Bit 3: Cassette data output
  Bit 4: Cassette switch sense (input)
  Bit 5: Cassette motor control

To bank out ROMs and access full RAM:

LDA #$34    ; %00110100 - RAM everywhere, I/O still visible
STA $0001

To restore normal operation:

LDA #$37    ; %00110111 - BASIC+Kernal+I/O (normal)
STA $0001

Powered by TurnKey Linux.