Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

6502-PRG

A 6502 assembly language program template for the A.C. Wright 6502 family of computer systems.

📖 Guide:AC6502 Documentation — the user's and programmer's guide for the whole family. This template is walked through end to end in Starting from a template.

Overview

Programs for this system are loaded into RAM at $0800 and executed from BASIC. Unlike cartridges (which replace ROM), programs run entirely in RAM alongside the BIOS, Kernal, BASIC interpreter, and Monitor — all of which remain available.

How It Works

  1. The program is loaded into RAM at $0800 — normally with BASIC's LOAD, from CompactFlash or over serial
  2. BASIC's RUN command executes the tokenized stub at the start of the file
  3. The stub decodes to 10 SYS 2060, which calls the machine code entry point at $080C
  4. Your program runs with full access to the Kernal jump table
  5. Return to BASIC with RTS

Memory Layout

RangeContents
$0000–$0039Zero page — system pointers, Monitor and XModem scratch (see 6502.inc for details)
$003A–$00FFZero page — free for user programs (198 bytes)
$0100–$01FFCPU stack
$0200–$02FFInput ring buffer (managed by Kernal)
$0300–$03FFKernal variables (vectors, cursor, HW flags, etc.)
$0400–$05FFUser/BASIC variables
$0600–$07FFCompactFlash sector buffer — clobbered by any filesystem call
$0800–$080BBASIC startup stub (10 SYS 2060)
$080C–$7FFFYour program code and data (~30 KB available)
$8000–$9FFFI/O hardware registers
$A000–$A0FFKernal jump table (stable API)

BASIC Startup Stub

The first 12 bytes of every program file contain a tokenized BASIC line that serves as a loader:

AddressByteMeaning
$0800$0ANext-line pointer lo → $080A
$0801$08Next-line pointer hi
$0802$0ALine number 10 (lo)
$0803$00Line number 10 (hi)
$0804$A5TOK_SYS
$0805$32'2'
$0806$30'0'
$0807$36'6'
$0808$30'0'
$0809$00Line terminator
$080A$00End-of-program sentinel (lo)
$080B$00End-of-program sentinel (hi)
$080CMachine code entry point (2060 decimal = $080C)

Kernal Services

The system is already fully initialized when your program runs. Key entry points:

AddressRoutineDescription
$A000ChroutOutput character (routed by IO_MODE)
$A003ChrinRead character from input buffer (non-blocking — C=1 with the character in A, C=0 if none; loop for blocking behaviour)
$A00CBufferSizeNumber of unread bytes in input buffer
$A018VideoClearClear screen and reset cursor
$A01BVideoPutCharWrite character at cursor position
$A01EVideoSetCursorSet cursor position (X=col, Y=row)
$A027VideoSetColorSet text color (A = fg<<4 | bg)
$A033SidPlayNotePlay note (A=voice, X=freqLo, Y=freqHi)
$A075SysDelayDelay A=lo, X=hi centiseconds
$A048ReadJoystick1Read joystick 1 bitmask

See 6502.inc for the complete jump table with calling conventions.

Hardware Detection

Check HW_PRESENT ($030D) before using optional hardware:

lda HW_PRESENTand #HW_SID ; Is SID present?beq @NoSound ; Skip sound code if notjsr SidPlayNote@NoSound:

Building

Prerequisites

CC65 Compiler

On macOS, install via Homebrew:

brew install cc65

For other platforms, see the cc65 project.

bin2woz (optional — for Wozmon loading)

npm install -g bin2woz

Converts the binary to a format loadable via the Wozmon serial monitor. See the bin2woz project.

cffs (optional — for CompactFlash images)

npm install -g cffs-image-tool

Creates CompactFlash disk images with the program file. See the cffs project.

6502 CLI (optional — for make run)

Installed via the 6502-EMULATOR app's Settings → Command Line → Install.

Build Commands

CommandDescription
makeBuild all targets (.prg, .woz, and CF image)
make buildAssemble only (Program.prg)
make viewDisplay hexdump of the built program
make wozCreate Wozmon-compatible file (Program.woz)
make cfCreate CompactFlash disk image with the program
make runLaunch the emulator app with the built program loaded
make cleanRemove build artifacts

Build Output

make

Produces:

  • Program.prg — Raw binary, load address $0800
  • Program.woz — Wozmon-compatible format for serial upload
  • Program.lst — Assembly listing file for debugging
  • Program.img — CompactFlash disk image with the program

Loading & Running

Use BASIC's LOAD. Requires BIOS v1.3 or later.

From CompactFlash — the usual case:

LOAD "PROGRAM.PRG"
RUN

Over serial, with no CF card:

LOAD

Then send Program.prg from the host with any terminal that speaks XMODEM (128-byte blocks, checksum mode). The transfer is padded up to a block boundary, which is harmless.

Either way, RUN executes the stub and SYS 2060 enters your code at $080C.

From the Monitor, if you are already there:

L "PROGRAM.PRG"
X

L loads to $0800 by default and X returns to BASIC, where RUN works as usual.

Why the loader matters

Your machine code lives past the end-of-program marker at $080A, where BASIC would otherwise put its variables. Keeping the two apart depends on the loader telling BASIC how many bytes it wrote, so BASIC can place VARTAB past the whole image rather than at the end of the tokenized line chain.

LOAD and the Monitor's L both do this as of BIOS v1.3. Wozmon does not — it writes bytes one at a time with no notion of a length, so BASIC falls back to walking the line chain, VARTAB lands at $080C on top of your code, and the first variable assignment destroys it. Use Wozmon for code you will enter from the Monitor, not for programs you intend to RUN.

On BIOS versions before v1.3 the byte count was discarded on every path, so all three loaders had this problem.

Template Structure

FilePurpose
Program.asmMain source — BASIC stub, entry point, example code
6502.incSystem include file — Kernal jump table, hardware registers, constants
6502.cfgLinker configuration — memory layout for RAM programs
MakefileBuild system

Customizing

  1. Edit Program.asm — replace the example code after the Start: label with your program
  2. Do not modify the BasicStartup bytes — they must remain at $0800 for BASIC RUN to work
  3. Return to BASIC with RTS when your program finishes
  4. Add additional .asm files and .include them as needed
  5. You have ~30 KB of RAM ($080C–$7FFF) for code and data

Related

  • 6502-ACE — the hardware, and the index of the whole family
  • 6502-BIOS — the firmware behind the Kernal jump table; 6502.inc here tracks its published API
  • 6502-EMULATOR — run a program without hardware (make run)
  • 6502-CRT — the same idea for cartridge ROMs
  • 6502-ASM — worked assembly examples
  • 6502-DOCS — the documentation site: the cross-development and assembly guides, and the printable reference cards
  • cffs / bin2woz — the tools behind make cf and make woz

License

MIT License — see LICENSE.

About

A 6502 assembly language program template for A.C. Wright 6502 project

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages