You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

13KB

Commodore 64 Kernal Jump Table — Complete Reference

Source: Compute's VIC-20 & C64 Tool Kit: Kernal; The Anatomy of the Commodore 64

All addresses are jump table entries (3-byte JMP instructions pointing into the Kernal ROM). These addresses are stable across all C64 revisions — always call through the jump table, never jump directly into ROM.


Quick Usage Template

; Open file: device 8, secondary 2, name "DATA"
    LDA #1          ; logical file number
    LDX #8          ; device number (8 = disk)
    LDY #2          ; secondary address
    JSR $FFBA       ; SETLFS
    LDA #4          ; filename length
    LDX #<fname     ; filename address low
    LDY #>fname     ; filename address high
    JSR $FFBD       ; SETNAM
    JSR $FFC0       ; OPEN
fname: .BYTE "DATA"

Complete Jump Table

$FF81 — SCINIT: Initialize Screen Editor and VIC-II

  • Input: None
  • Output: None
  • Destroys: A, X, Y
  • Notes: Clears screen, sets default colors, initializes VIC-II registers. Called at RESET.

$FF84 — IOINIT: Initialize I/O Devices

  • Input: None
  • Output: None
  • Destroys: A, X, Y
  • Notes: Initializes CIA #1 and #2, serial bus, RS-232. Called at RESET.

$FF87 — RAMTAS: Test RAM and Initialize Pointers

  • Input: None
  • Output: None
  • Destroys: A, X, Y
  • Notes: Tests RAM, sets HIRAM/LORAM, initializes $0000–$00FF. Called at RESET.

$FF8A — RESTOR: Restore Default System Vectors

  • Input: None
  • Output: None
  • Destroys: A, X, Y
  • Notes: Copies ROM default vectors into $0314–$0333 (IRQ, OPEN, CLOSE, etc.)

$FF8D — VECTOR: Read/Set Vectored System Routines

  • Input: .C = 0 to write vectors from user table; .C = 1 to read vectors to user table. .XY = pointer to 2×16-byte table (alternating load/store pairs)
  • Output: None
  • Notes: Batch-sets or batch-reads the $0314–$0333 vector block.

$FF90 — SETMSG: Set Kernal Error/Status Message Flag

  • Input: .A = flag value (bit 6 = error messages on; bit 7 = I/O messages on)
  • Output: None
  • Destroys: A

$FF93 — SECOND: Send Secondary Address After LISTEN

  • Input: .A = secondary address (ORed with $60 internally)
  • Output: None; carry set on timeout
  • Destroys: A
  • Notes: Must follow a LISTEN call.

$FF96 — TKSA: Send Secondary Address After TALK

  • Input: .A = secondary address (ORed with $60 internally)
  • Output: None; carry set on timeout
  • Destroys: A
  • Notes: Must follow a TALK call.

$FF99 — MEMTOP: Read or Set Top of Memory

  • Input: .C = 1 to read; .C = 0 to set (pass address in .XY)
  • Output: .XY = top of memory (if reading)
  • Destroys: A

$FF9C — MEMBOT: Read or Set Bottom of Memory

  • Input: .C = 1 to read; .C = 0 to set (pass address in .XY)
  • Output: .XY = bottom of memory (if reading)
  • Destroys: A

$FF9F — SCNKEY: Scan Keyboard Matrix

  • Input: None
  • Output: Updates keyboard buffer at $0277; last key matrix code at $C5; shift flags at $028D
  • Destroys: A, X, Y
  • Notes: Normally called by the IRQ handler 60×/sec. Call manually if IRQs are disabled.

$FFA2 — SETTMO: Set Serial Bus Timeout

  • Input: .A = 0 to disable timeout; non-zero to enable
  • Output: None

$FFA5 — ACPTR: Receive Byte From Serial Bus

  • Input: Device must already be TALKing (TALK + TKSA already sent)
  • Output: .A = received byte; STATUS ($90) updated
  • Destroys: A
  • Notes: Check STATUS after each byte. ST bit 1 set = EOI (last byte in file).

$FFA8 — CIOUT: Send Byte to Serial Bus

  • Input: .A = byte to send; device must be LISTENing
  • Output: STATUS updated
  • Destroys: A

$FFAB — UNTLK: Send UNTALK to Serial Bus

  • Input: None
  • Output: None
  • Destroys: A
  • Notes: Releases currently TALKing device.

$FFAE — UNLSN: Send UNLISTEN to Serial Bus

  • Input: None
  • Output: None
  • Destroys: A
  • Notes: Releases currently LISTENing device.

$FFB1 — LISTEN: Command Serial Device to LISTEN

  • Input: .A = device number (4–30; 8=disk, 4=printer)
  • Output: None; carry set on timeout
  • Destroys: A

$FFB4 — TALK: Command Serial Device to TALK

  • Input: .A = device number
  • Output: None; carry set on timeout
  • Destroys: A

$FFB7 — READST: Read I/O Status Word

  • Input: None
  • Output: .A = STATUS byte ($90)
  • Destroys: A

STATUS bits: | Bit | Meaning | |-----|------------------------------------------| | 0 | Write timeout (serial bus out) | | 1 | Read timeout / EOI received | | 2 | (RS-232) short block | | 3 | (RS-232) long block | | 4 | (RS-232) receive buffer empty / cassette | | 5 | Checksum error | | 6 | End of file (EOI on tape read) | | 7 | End of tape / device not present |

$FFBA — SETLFS: Set Logical File, Device, Secondary Address

  • Input: .A = logical file number (1–127 typical); .X = device number; .Y = secondary address (255=$FF = no secondary)
  • Output: None

Device numbers: | # | Device | |---|---------------| | 0 | Keyboard | | 1 | Cassette | | 2 | RS-232 | | 3 | Screen | | 4 | Printer | | 5 | Printer #2 | | 8 | Disk drive | | 9 | Disk drive #2 |

$FFBD — SETNAM: Set Filename

  • Input: .A = length (0 for no name); .XY = address of filename (X=low, Y=high)
  • Output: None
  • Notes: For disk: name can include drive number prefix like “0:MYFILE,S,R”. Length 0 for LOAD without name (loads tape program).

$FFC0 — OPEN: Open a Logical File

  • Input: Preceded by SETLFS and SETNAM
  • Output: Carry set on error; .A = error code (1=file open, 2=too many files, 6=not input, etc.)
  • Destroys: A, X, Y
  • Notes: Must CLOSE file when done. Max 10 open files.

$FFC3 — CLOSE: Close a Logical File

  • Input: .A = logical file number
  • Output: None
  • Destroys: A, X, Y

$FFC6 — CHKIN: Set Input Channel

  • Input: .X = logical file number (must be already OPENed)
  • Output: Carry set on error; .A = error
  • Destroys: A, X
  • Notes: Redirects CHRIN/GETIN to this file. Call CLRCH to restore keyboard input.

$FFC9 — CKOUT: Set Output Channel

  • Input: .X = logical file number
  • Output: Carry set on error
  • Destroys: A, X
  • Notes: Redirects CHROUT/BSOUT to this file.

$FFCC — CLRCH: Restore Default I/O Channels

  • Input: None
  • Output: None
  • Destroys: A, X
  • Notes: Resets input to keyboard (device 0), output to screen (device 3).

$FFCF — CHRIN: Input Character from Current Channel

  • Input: None
  • Output: .A = character received; STATUS updated
  • Destroys: A
  • Notes: Waits for character if keyboard. Returns PETSCII code. Check STATUS after for EOF.

$FFD2 — CHROUT / BSOUT: Output Character to Current Channel

  • Input: .A = character to output (PETSCII)
  • Output: STATUS updated
  • Destroys: A (X and Y preserved)
  • Notes: Most commonly called Kernal routine. Outputs to current CKOUT channel (screen by default). Also vectored via $0326.

Useful PETSCII codes for CHROUT: | Code | Effect | |------|---------------------| | $0D | RETURN (newline) | | $11 | Cursor down | | $13 | HOME | | $14 | DELETE | | $1D | Cursor right | | $91 | Cursor up | | $93 | CLEAR | | $9D | Cursor left | | $12 | Reverse on | | $92 | Reverse off |

$FFD5 — LOAD: Load a File from Device

  • Input: Preceded by SETLFS and SETNAM. .A = 0 (load) or 1 (verify). .XY = load address (used only if secondary address = 0, meaning override file's own load address)
  • Output: Carry set on error; .A = error code; .XY = address of last byte loaded + 1
  • Destroys: A, X, Y
  • Notes: With secondary address 1, file loads to its original address. With secondary address 0, .XY overrides load address.

$FFD8 — SAVE: Save a File to Device

  • Input: Preceded by SETLFS and SETNAM. .A = zero-page address containing start address (2 bytes). .XY = end address + 1
  • Output: Carry set on error
  • Destroys: A, X, Y
  • Notes: .A is a zero-page pointer to the 2-byte start address, not the start address itself.

Example — Save $C000–$CFFF:

    LDA #<$C000
    STA $FB          ; store start in ZP
    LDA #>$C000
    STA $FC
    LDA #1           ; logical file
    LDX #8           ; disk
    LDY #1           ; secondary address
    JSR $FFBA        ; SETLFS
    LDA #6
    LDX #<savename
    LDY #>savename
    JSR $FFBD        ; SETNAM
    LDA #$FB         ; ZP pointer to start address
    LDX #<$D000      ; end+1 low
    LDY #>$D000      ; end+1 high
    JSR $FFD8        ; SAVE
savename: .BYTE "MYFILE"

$FFDB — SETTIM: Set Jiffy Clock

  • Input: .A = high byte, .X = mid byte, .Y = low byte (24-bit value at 60Hz units)
  • Output: None

$FFDE — RDTIM: Read Jiffy Clock

  • Input: None
  • Output: .A = high byte, .X = mid byte, .Y = low byte
  • Notes: Clock wraps after ~18.2 hours (16,777,215 jiffies). Updated 60× per second by IRQ.

$FFE1 — STOP: Check STOP Key

  • Input: None
  • Output: .Z = 1 if STOP key pressed; .A = keyboard row scan byte
  • Destroys: A, X
  • Notes: If STOP pressed, also calls CLRCH. Use to allow program abort.

$FFE4 — GETIN: Get Character from Keyboard Buffer

  • Input: None
  • Output: .A = character (0 if buffer empty); STATUS updated
  • Destroys: A, X, Y
  • Notes: Non-blocking. Returns 0 immediately if no key waiting. For file input, same as CHRIN.

$FFE7 — CLALL: Close All Files and Channels

  • Input: None
  • Output: None
  • Destroys: A, X
  • Notes: Clears open file table and resets I/O to defaults. Does NOT send UNLISTEN/UNTALK to devices.

$FFEA — UDTIM: Update Jiffy Clock

  • Input: None
  • Output: None
  • Notes: Increments 3-byte clock at $A0–$A2. Called by the default IRQ handler. If you replace the IRQ, call this manually to maintain timing.

$FFED — SCREEN: Return Screen Dimensions

  • Input: None
  • Output: .X = number of columns (40), .Y = number of rows (25)

$FFF0 — PLOT: Read or Set Cursor Position

  • Input: .C = 0 to set cursor (X=column, Y=row); .C = 1 to read cursor position
  • Output: .X = cursor column, .Y = cursor row (when reading)
  • Destroys: A (X, Y preserved when setting)

$FFF3 — IOBASE: Return Base Address of I/O Devices

  • Input: None
  • Output: .XY = base address of CIA #1 ($DC00)
  • Notes: Useful for position-independent code.

Hardware Vectors (ROM, read-only)

Address Vector Name Default Points To
$FFFA NMI vector $FE43 (Kernal NMI handler)
$FFFC RESET vector $FCE2 (Kernal cold start)
$FFFE IRQ/BRK $FF48 (Kernal IRQ entry)

The Kernal IRQ entry at $FF48 pushes registers and then jumps through the RAM vector at $0314 — that is what you override to install custom IRQ handlers.


Complete File I/O Pattern (ML)

Write Sequential File to Disk

WRITE_FILE:
    ; Set up file
    LDA #2          ; logical file #2
    LDX #8          ; disk drive
    LDY #2          ; secondary address 2 = write
    JSR $FFBA       ; SETLFS
    LDA #FNAME_LEN
    LDX #<FNAME
    LDY #>FNAME
    JSR $FFBD       ; SETNAM
    JSR $FFC0       ; OPEN
    BCS WRITE_ERR   ; carry set = error

    ; Redirect output
    LDX #2
    JSR $FFC9       ; CKOUT

    ; Write bytes
    LDY #0
WLOOP:
    LDA DATA,Y
    JSR $FFD2       ; CHROUT
    INY
    CPY #DATA_LEN
    BNE WLOOP

    ; Close
    JSR $FFCC       ; CLRCH
    LDA #2
    JSR $FFC3       ; CLOSE
    RTS
WRITE_ERR:
    RTS

Read Sequential File from Disk

READ_FILE:
    LDA #3
    LDX #8
    LDY #2          ; secondary address 2 = read
    JSR $FFBA
    LDA #FNAME_LEN
    LDX #<FNAME
    LDY #>FNAME
    JSR $FFBD
    JSR $FFC0       ; OPEN
    BCS READ_ERR

    LDX #3
    JSR $FFC6       ; CHKIN

RLOOP:
    JSR $FFCF       ; CHRIN
    STA BUFFER,Y    ; store to buffer
    INY
    JSR $FFB7       ; READST
    AND #$40        ; EOF bit
    BEQ RLOOP

    JSR $FFCC       ; CLRCH
    LDA #3
    JSR $FFC3       ; CLOSE
    RTS
READ_ERR:
    RTS

Intercepting BSOUT (Custom Character Output)

To redirect all screen output (PRINT, CHROUT) through your own routine:

INSTALL:
    LDA #<MY_BSOUT
    STA $0326        ; patch BSOUT vector
    LDA #>MY_BSOUT
    STA $0327
    RTS

MY_BSOUT:
    ; .A = character to output
    ; Do custom processing here, then fall through to original:
    JMP $F1CA        ; Kernal BSOUT (bypassing vector)

REMOVE:
    LDA #$CA         ; restore default ($F1CA)
    STA $0326
    LDA #$F1
    STA $0327
    RTS

Powered by TurnKey Linux.