# Ultimate Commodore 64 Reference Guide
## Introduction
The Ultimate Commodore 64 Reference Guide is a comprehensive project that collects, formats, and presents Commodore 64 reference material in machine-readable form. This repository aggregates historical documentation about the C64 including ROM disassemblies, memory maps, KERNAL API documentation, 6502 CPU instruction references, character sets, PETSCII codes, and keyboard layouts. The project was initially created by Michael Steil to preserve and make accessible critical technical documentation about the iconic Commodore 64 computer system and related machines in the Commodore family (PET, VIC-20, C128, C65, TED, CBM2).
The project generates a multi-page interactive HTML website from structured text files and Python scripts. Each reference category (6502 CPU, KERNAL API, ROM Disassembly, Memory Map, I/O Map, Character Sets, and Colors) has its own generation scripts that parse text-based source files and produce richly formatted HTML with cross-references, side-by-side commentary views, and interactive features. The build system includes validation, git integration for revision tracking, and deployment capabilities to publish the documentation online.
## Build System
### Main Build Script
The primary build script that orchestrates the entire generation and deployment process.
```python
#!/usr/bin/env python3
# Generate the entire Ultimate C64 Reference website
# Build locally with all stable categories
./generate.py local
# Build with work-in-progress categories (colors, c64io)
./generate.py local --wip
# Build only specific categories by path name
./generate.py local --only 6502 kernal c64mem
# Deploy to production server (requires clean git state on main branch)
./generate.py upload
# Example: Typical development workflow
# 1. Make changes to source files
./generate.py local --only c64mem # Build just the changed category
# 2. Test locally at http://localhost:6464/c64ref/c64mem/
python3 -m http.server 6464
```
### Build Configuration
Configure build parameters programmatically using the BuildConfig class.
```python
from dataclasses import dataclass
@dataclass
class BuildConfig():
source_dir: str = "src" # Source files location
build_dir: str = "out" # Output directory
base_dir: str = "c64ref" # Web base path
server_path: str = "user@server:/var/www/html/"
deploy: bool = False # Upload to server
build_wips: bool = False # Include WIP categories
enabled_paths: list = None # Selective builds
# Usage in custom build script
config = BuildConfig()
config.build_dir = "custom_out"
config.enabled_paths = ["6502", "kernal"]
# ... proceed with build using config
```
### Adding New Reference Categories
Define new reference categories by extending the CATEGORIES list.
```python
from dataclasses import dataclass
@dataclass
class RefCategory():
path: str # Folder name in src/
long_title: str # Full title for HTML
short_title: str # Menu title
authors: list # Author names/links
is_wip: bool = False # Work in progress flag
# Add a new category
CATEGORIES.append(
RefCategory(
'sid',
'C64 SID Sound Interface Device Reference',
'SID Audio',
['Your Name'],
is_wip=True
)
)
# The build system will automatically:
# 1. Look for src/sid/generate.py or out.sh
# 2. Generate navigation with "SID Audio" menu item
# 3. Create index at /c64ref/sid/
# 4. Skip on production if is_wip=True (unless --wip flag used)
```
## Memory Map Generator
### Memory Map HTML Generation
Generates interactive HTML tables comparing multiple C64 memory map references side-by-side.
```python
#!/usr/bin/env python3
# src/c64mem/generate.py - Generate memory map comparison
# Input file format (c64mem_*.txt):
# $0000-$0001 D6510 I/O port data direction and I/O port
#
# This is the detailed description that can span
# multiple lines and include markdown formatting.
# Generate the memory map
import sys
sys.path.insert(0, './src/c64mem')
from generate import *
# Example: Cross-reference memory addresses
text = "See address $D000 and routine $E000"
result = cross_reference(text)
# Output: 'See address $D000 and
# routine $E000'
# Memory addresses < $0400 link to memory map
# Addresses $A000-$BFFF and $E000-$FFFF link to disassembly
# Generate full HTML output
import subprocess
subprocess.run(['python3', 'src/c64mem/generate.py'],
stdout=open('out/c64ref/c64mem/index.html', 'w'))
```
### Memory Map Data Format
Structure memory map data files for multiple sources.
```python
# Example memory map entry format in c64mem_*.txt
# Address range, symbol, and short description
$0000-$0001 D6510 I/O port DDR and data
# First blank line separates heading from details
Detailed description with **markdown** support.
Can include tables and cross-references to $FFD2.
| Bit | Function |
|-----|----------|
| 0-2 | Memory configuration |
# Comment lines (ignored)
#----------------------------
# Single address entry
$0002 UNUSED Unused memory location
# Parse and process programmatically
filenames = ['c64mem_mapc64.txt', 'c64mem_sta.txt']
data = []
for filename in filenames:
lines = [line.rstrip() for line in open(filename)]
data.append(lines)
# The generator merges entries by address range
# Longest range wins for defining address spans
# Multiple commentaries displayed in columns
```
## KERNAL API Generator
### KERNAL API Documentation
Generate comprehensive KERNAL API reference with multiple commentary sources.
```python
#!/usr/bin/env python3
# src/kernal/generate.py - Generate KERNAL API reference
# Input file format (kernal_*.txt):
# $FFD2 CHROUT Output a character
#
# Detailed description of the routine,
# including register usage and examples.
# Define categories for color-coding
categories = {
0xFFD2: 'IO', # Input/Output
0xFFE4: 'KBD', # Keyboard
0xFFDE: 'TIME', # Time/Jiffy clock
0xFF9C: 'MEM', # Memory management
0xFF93: 'IEEE', # IEEE-488 bus
0xFFED: 'EDITOR', # Screen editor
}
# Example: Generate API entry with category
address = 0xFFD2
symbol = 'CHROUT'
category = categories[address]
summary = 'Output a character'
html = f'''
${address:04X}
{symbol}
{category}
{summary}
Outputs a character to the current output device.
Input: .A = character to output
Output: None
'''
```
### KERNAL API Cross-Referencing
Implement automatic cross-referencing between KERNAL routines.
```python
import re
# Automatic cross-referencing of symbols and addresses
def cross_reference(text):
# Link hex addresses to appropriate sections
hex_numbers = re.findall(r'\$[0-9A-F]{4}', text)
for hex_num in hex_numbers:
dec = int(hex_num[1:], 16)
if dec < 0x0400:
# Link to memory map
text = text.replace(
hex_num,
f'${dec:04X}'
)
elif (0xA000 <= dec <= 0xBFFF) or (0xE000 <= dec <= 0xFFFF):
# Link to disassembly
text = text.replace(
hex_num,
f'{hex_num}'
)
return text
# Example usage
description = """
CHROUT calls $E716 internally and uses zero page
locations $D3 and $D6. See also CHRIN at $FFCF.
"""
html_description = cross_reference(description)
# Links are automatically created for $E716, $D3, $D6, $FFCF
```
### KERNAL API Smart Text Joining
Handle hyphenated line breaks intelligently when processing multi-line text.
```python
def smart_join(lines):
"""Join lines with intelligent hyphen handling"""
s = ''
while len(lines) > 0:
if s == '':
s = lines[0]
elif s[-1] == '-':
# Check if next word continues (lowercase) or is new (uppercase)
if len(lines[0]) > 0 and lines[0][0].islower():
s = s[:-1] + lines[0] # Remove hyphen, join words
else:
s += lines[0] # Keep hyphen
else:
s += '\n' + lines[0]
lines = lines[1:]
return s
# Example
input_lines = [
'This is a demon-',
'stration of the smart',
'join function. It han-',
'dles word breaks.'
]
result = smart_join(input_lines)
# Output: 'This is a demonstration of the smart\njoin function. It handles word breaks.'
```
## Character Set and PETSCII
### PETSCII to Screen Code Conversion
Convert between PETSCII character codes and screen codes.
```python
# Generate scrcode_from_petscii mapping
scrcode_from_petscii = []
for petscii in range(0, 256):
# Special handling for $FF (pi symbol)
if petscii == 0xff:
petscii = 0xde
# Conversion logic
if petscii < 0x20:
scrcode = petscii + 0x80 # Inverted control chars
elif petscii < 0x40:
scrcode = petscii
elif petscii < 0x60:
scrcode = petscii - 0x40
elif petscii < 0x80:
scrcode = petscii - 0x20
elif petscii < 0xa0:
scrcode = petscii + 0x40 # Inverted
elif petscii < 0xc0:
scrcode = petscii - 0x40
else:
scrcode = petscii - 0x80
scrcode_from_petscii.append(scrcode)
# Usage example
petscii_a = 0x41 # Letter 'A'
scrcode = scrcode_from_petscii[petscii_a]
print(f"PETSCII ${petscii_a:02X} = Screen Code ${scrcode:02X}")
# Output: PETSCII $41 = Screen Code $01
```
### Keyboard Layout Generation
Generate SVG keyboard layouts from ASCII art descriptions.
```python
def keyboard_layout_html(machine, layout_lines):
"""Generate interactive SVG keyboard from text layout"""
# Example layout format (keyboard_c64.txt):
# layout +---+---+---+
# layout | 3E| 3F| 40| (Scancode in hex)
# layout +---+---+---+
SCALE = 8
VSCALE = 2
total_width = max(len(line) for line in layout_lines) * SCALE
total_height = len(layout_lines) * VSCALE * SCALE
svg = f''
return svg
# Load keyboard layouts for all machines
machines = ['C64', 'C128', 'VIC-20', 'PET-N', 'PET-B']
for machine in machines:
layout = []
for line in open(f'keyboard_{machine.lower()}.txt'):
if line.startswith('layout'):
layout.append(line[8:]) # Skip 'layout ' prefix
html = keyboard_layout_html(machine, layout)
```
### PETSCII Control Codes
Map and display control code functions across different Commodore machines.
```python
# Control code descriptions
description_from_control_code_symbol = {
'CRSR_DOWN': ('Crsr ↓', 'Cursor Down'),
'CRSR_HOME': ('HOME', 'Cursor Home'),
'CLEAR': ('CLR', 'Clear Screen'),
'DEL': ('DEL', 'Delete'),
'INST': ('INST', 'Insert'),
'COL_WHITE': ('Wht', 'Set text color to White'),
'COL_RED': ('Red', 'Set text color to Red'),
'RVS_ON': ('RVS On', 'Reverse Video On'),
'RVS_OFF': ('RVS Off', 'Reverse Video Off'),
}
# Load control codes for each machine
machines = ['C64', 'C128', 'VIC-20', 'PET-N', 'PET-B', 'CBM2', 'C65', 'TED']
description_from_control_code = {}
for machine in machines:
description_from_control_code[machine] = {}
for line in open(f'control_codes_{machine.lower()}.txt'):
line = line.split('#')[0].rstrip()
if len(line) == 0:
continue
petscii = int(line[0:2], 16)
symbol = line[3:].split()[0]
if symbol in description_from_control_code_symbol:
description_from_control_code[machine][petscii] = \
description_from_control_code_symbol[symbol]
# Example: Display control code for PETSCII $13 (HOME)
petscii = 0x13
for machine in machines:
if petscii in description_from_control_code[machine]:
short, long = description_from_control_code[machine][petscii]
print(f"{machine}: {short} - {long}")
```
### Unicode Mapping
Map PETSCII characters to Unicode using the Symbols for Legacy Computing standard.
```python
# Load PETSCII to Unicode mappings
unicode_from_petscii = {'upper': {}, 'lower': {}}
description_from_unicode = {}
# C64IPRI.TXT - Primary (uppercase/graphics) character set
for line in open('C64IPRI.TXT'):
if line.startswith('#') or len(line.strip()) == 0:
continue
# Format: 0x41 -> U+1FB00 LATIN CAPITAL LETTER A
petscii = int(line[2:4], 16)
unicode_val = int(line[7:12], 16)
unicode_from_petscii['upper'][petscii] = unicode_val
description_from_unicode[unicode_val] = line[14:].strip()
# C64IALT.TXT - Alternate (lowercase) character set
for line in open('C64IALT.TXT'):
if line.startswith('#') or len(line.strip()) == 0:
continue
petscii = int(line[2:4], 16)
unicode_val = int(line[7:12], 16)
unicode_from_petscii['lower'][petscii] = unicode_val
# Usage example: Convert PETSCII to Unicode
def petscii_to_unicode(petscii, charset='upper'):
"""Convert PETSCII code to Unicode character"""
if petscii in unicode_from_petscii[charset]:
unicode_val = unicode_from_petscii[charset][petscii]
char = chr(unicode_val)
desc = description_from_unicode.get(unicode_val, 'Unknown')
return char, unicode_val, desc
return None, None, None
# Example
char, code, desc = petscii_to_unicode(0x41, 'upper')
print(f"PETSCII $41 = U+{code:04X} ({desc}): {char}")
# Output: PETSCII $41 = U+1FB01 (LATIN CAPITAL LETTER A): 🬁
```
## Header and Navigation Generation
### HTML Header with Navigation
Generate consistent headers with navigation across all reference pages.
```python
def get_header_str(current_category, categories, source_path,
base_path, git_has_changes):
"""Generate HTML header with GitHub corner and navigation"""
# GitHub corner (octocat icon)
octocat_svg = """
"""
# Navigation menu
nav = f'
{GLOBAL_TITLE}
\n'
for cat in categories:
if cat == current_category:
nav += f'{cat.short_title}\n'
else:
nav += f'{cat.short_title}\n'
# Git revision info
revision = os.popen(f'git log -1 --pretty=format:%h {source_path}').read()
if git_has_changes:
revision += "+"
date = os.popen(f'git log -1 --date=short --pretty=format:%cd {source_path}').read()
authors = ', '.join(current_category.authors)
byline = f'''
by {authors}.
[
github.com/mist64/c64ref, rev {revision}, {date}]
'''
return f"""
{octocat_svg}
{current_category.long_title}
{byline}
"""
# Usage in build script
header_html = get_header_str(
current_category=CATEGORIES[0], # 6502 CPU
categories=CATEGORIES,
source_path='src/6502',
base_path='c64ref',
git_has_changes=False
)
```
### Path Utilities
Safely create directories for build output.
```python
import os
def ensured_path(path, *paths, is_dir):
"""Join paths and ensure parent directories exist"""
result = os.path.join(path, *paths)
dir_name = result if is_dir else os.path.dirname(result)
if not os.path.exists(dir_name):
os.makedirs(dir_name)
return result
# Usage examples
# Ensure directory exists
output_dir = ensured_path('out', 'c64ref', 'kernal', is_dir=True)
# Ensure parent directory exists for file
output_file = ensured_path('out', 'c64ref', 'kernal', 'index.html', is_dir=False)
# Complex nested path
css_file = ensured_path('out', 'c64ref', 'assets', 'css', 'style.css', is_dir=False)
# Creates: out/c64ref/assets/css/ if it doesn't exist
```
## HTML Validation
### Shell Script Validation
Validate generated HTML files before deployment.
```bash
#!/bin/bash
# validate_html.sh - Validate all generated HTML files
# Find all HTML files in output directory
find out/c64ref -name "*.html" -type f | while read file; do
echo "Validating: $file"
# Use tidy for HTML validation
tidy -q -e -utf8 "$file" 2>&1 | grep -v "Warning:"
if [ $? -eq 0 ]; then
echo "✓ Valid: $file"
else
echo "✗ Errors in: $file"
exit 1
fi
done
echo "All HTML files validated successfully"
# Usage in build pipeline
# ./generate.py local
# ./validate_html.sh
# if [ $? -eq 0 ]; then ./generate.py upload; fi
```
## Summary
The Ultimate Commodore 64 Reference Guide provides a complete, maintainable documentation system for Commodore 64 technical reference material. The project's strength lies in its structured approach to aggregating multiple historical sources, presenting them in comparable side-by-side views, and automatically generating rich cross-references between related documentation sections. Developers can extend the system by adding new reference categories, contributing additional source commentaries, or improving the generation scripts.
The build system is designed for both local development and production deployment, with selective building capabilities for rapid iteration and comprehensive validation before publishing. The generated HTML is self-contained with embedded CSS and JavaScript, creating an accessible reference that works offline. Integration patterns include extending the category system, adding new data sources in the standardized text formats, implementing custom generators for new reference types, and deploying to web servers via rsync. The modular architecture allows contributors to focus on individual reference categories without affecting the broader system.