c64ref Commodore 64 Reference Guide

repository·main·Indexed 19 days ago

https://github.com/mist64/c64ref

A collection of Commodore 64 reference material converted into machine-readable formats for programmatic use and web presentation. It provides structured data for ROM disassembly (KERNAL and BASIC), memory maps, and KERNAL API documentation, including machine language routines and jump tables. The repository includes build-time utilities like generate.py to create HTML side-by-side comparisons of disassembly and memory map commentaries.

Tokens
7.9K
Snippets
18
Records
39
Agent score
69%

What's inside c64ref

  1. Overview of the Commodore 64 Reference Guide

    main
    The c64ref repository is a collection of Commodore 64 reference material converted into machine-readable formats. It serves as a centralized resource for developers and enthusiasts working with C64 hardware, providing structured data for ROM disassembly, memory maps, and KERNAL API documentation. The project also maintains scripts to present this material via a web interface.
  2. Memory structure of String Arrays (DIM AB$)

    main

    When dimensioning a string array (e.g., DIM AB$(1,2,3)), the Commodore BASIC memory allocates a header in the variable area.

    Header Structure:

    • Character 1: The first character of the field name (displayed inverted to indicate it is a string field).
    • Character 2: The second character of the field name.
    • Characters 3 & 4: The address where the string data is stored, represented as a Low-Byte and High-Byte pair.
    • Characters 5 & 6: The length of the string (in bytes).

    Data Storage: Each element in the array occupies a specific number of bytes. For an array like AB$(1,2,3), the total elements are $2 imes 3 imes 4 = 24$. If the header uses 11 bytes, the remaining space is divided by the number of elements to find the size per element.

    Each element's data block contains:

    1. Byte 1: The length of the string.
    2. Bytes 2 & 3: The Low-Byte and High-Byte of the address where the actual string characters are stored in the fourth memory block.
    DIM AB$(1,2,3)
    AB$(0,0,0) = "AAAAAA"
    AB$(1,2,3) = "BB"
  3. Understand Floating-Point Number Representation

    main

    Commodore computers process all numbers internally as floating-point numbers. To represent very large or very small numbers without using excessive space, the system uses a Mantissa (the base number) and an Exponent (the power of 10).

    For example, the number 0.000000000000000123 is represented by moving the decimal point to the first non-zero digit: 0.123 x 10^15. Here, 0.123 is the mantissa and 15 is the exponent.

  4. Memory layout of String Variables (String-Variable)

    main

    String variables occupy 7 bytes in memory. They are identified by having the second character of their name displayed as inverted (ASCII + 128).

    Memory Structure:

    ByteDescription
    1First character of variable name (ASCII)
    2Second character of variable name (ASCII + 128)
    3Length of the string (number of characters)
    4Low-Byte of the memory address where string text begins
    5High-Byte of the memory address where string text begins
    6-7Padding (0)

    String Storage: The actual text of the string is stored at the end of the work memory (e.g., address 40959 on C 64 or 7679 on VC 20) and grows backwards towards the start of memory.

  5. Convert decimal numbers to Low/High-Byte format

    main

    Since Commodore memory cells are 8-bit (0–255), 16-bit addresses or values must be split into a Low-Byte and a High-Byte.

    Conversion Recipes

    Decimal to Low/High-Byte

    To split a decimal number into two bytes:

    1. Divide the decimal number by 256.
    2. The quotient is the High-Byte.
    3. The remainder is the Low-Byte.

    Example: 47491 / 256 = 185 (High-Byte) with a remainder of 131 (Low-Byte).

    Low/High-Byte to Decimal

    To reconstruct a decimal number from two bytes: High-Byte * 256 + Low-Byte = Decimal

    Example: (185 * 256) + 131 = 47491.

    Important Rule

    When storing addresses in memory (e.g., for USR or SYS), the Low-Byte must always be stored before the High-Byte (addressing from right to left).

  6. Define Pointers, Vectors, and Flags

    main

    In Commodore programming, these terms describe how 16-bit values (stored as Low/High-Byte pairs) are used:

    • Pointer (Zeiger): A 16-bit address that points to the beginning of a data block.
    • Vector (Vektor): A 16-bit address that points to the start of a machine code routine.
    • Flag (Flagge): A value stored in a single memory cell used by a program to record the result of an operation or to hold data for later use.
  7. Optimize BASIC Variable Usage

    main

    BASIC variables are stored in a dedicated memory area. The start and end of this area are defined by pointers in cells 45/46 and 47/48. When BASIC looks for a variable, it must scan this area from the beginning. To improve performance, follow these two rules:

    1. Define frequently used variables first: Define them at the very beginning of your program (even with a 'dummy' value) so they appear at the start of the variable memory area. This minimizes search time.
    2. Define all normal variables before arrays: Arrays (Fields) are stored after normal variables. If you define an array first and then try to define a normal variable, the system must shift all existing arrays to make room, which is slow.
  8. Define and use BASIC Arrays (Felder)

    main

    In Commodore BASIC, arrays (Felder) allow you to store multiple values under a single variable name. Unlike normal variables, arrays must be dimensioned using the DIM command before use.

    Array Types

    Arrays are categorized by the type of data they hold, which is indicated by a suffix in the variable name:

    • Floating-point (Gleitkomma): Default (no suffix). Example: DIM AB(1,2,3)
    • Integer (Ganzzahlen): Suffix %. Example: DIM CZ%(10)
    • String (Zeichenketten): Suffix $. Example: DIM DT$(5)

    Dimensions

    • One-dimensional: DIM NAME(size) (e.g., DIM KARLSTRASSE(12) creates 13 elements, indices 0-12).
    • Two-dimensional: DIM NAME(size1, size2) (e.g., DIM AX(7,7) creates a 64-element grid).
    • Three-dimensional: DIM NAME(size1, size2, size3) (e.g., DIM BY(125,6,2)).

    Memory Efficiency

    Arrays are more memory-efficient than multiple individual variables because they share a single header.

    • Floating-point: 6 bytes per element.
    • Integer (%): 2 bytes per element.
    • String ($): Variable (uses standard string storage).
    DIM KARLSTRASSE(12)
    KARLSTRASSE(0)=25
    KARLSTRASSE(1)=56
    
    DIM AX(7,7)
    DIM BY(125,6,2)
    
    DIM CZ%(10)
    DIM DT$(5)
  9. Visualize BASIC Variables in Screen Memory

    main

    You can inspect the contents of the BASIC variable area by redirecting the variable pointers (cells 45, 46, 47, and 48) to the start of the screen memory. This allows you to see variable definitions directly on the screen.

    Note that the method for redirecting these pointers differs between the Commodore 64 and the VC 20.

  10. Memory layout of Integer Variables (Ganzzahl-Variable)

    main

    Integer variables in BASIC occupy 7 bytes in memory. They are identified in the screen memory by having the first two characters of their name displayed as inverted (ASCII value + 128).

    Memory Structure:

    ByteDescription
    1First character of variable name (ASCII + 128)
    2Second character of variable name (ASCII + 128)
    3High-Byte of the variable value
    4Low-Byte of the variable value
    5-7Padding (0)

    Behavior Notes:

    • The High-Byte allows values from 0 to 127. Values from 128 and above signal negative numbers using two's complement.
    • Example: VA% = 3 results in the value being stored in bytes 3 and 4 as High-Byte 0 and Low-Byte 3.
  11. Inspect BASIC Program Memory Layout

    main

    BASIC programs are stored in memory with a specific structure. Each line begins with a Link Address (Koppeladresse), which is the memory address of the next line, and ends with a 0 (null byte) as a separator.

    To calculate the address of the next line from the current link address, use the formula: LowByte + (HighByte * 256).

    Example: If the first two bytes are 18 and 18, the next line starts at 18 + (18 * 256) = 4626.

  12. Memory structure of User-Defined Functions (DEF FN)

    main

    User-defined functions created with DEF FN have a specific representation in the variable memory. A function like 10 DEF FNAA(X)=3*SIN(X)+COS(X) creates a variable entry with the following 7-character structure:

    PosDescriptionDetails
    1First CharASCII value + 128 (inverted)
    2Second CharASCII value
    3Low ByteLow byte of the address where the function is stored in program memory
    4High ByteHigh byte of the address where the function is stored in program memory
    5Low ByteLow byte of the address where the function's variable (e.g., X) starts
    6High ByteHigh byte of the address where the function's variable (e.g., X) starts
    7Seventh CharThe first character of the function definition (e.g., the first digit of the formula)

    To find the program memory address of the function, use: PEEK(3) + 256 * PEEK(4).

    10 DEF FNAA(X)=3*SIN(X)+COS(X)
    20 X=5
    30 PRINT FNAA(X)