DevToPrd
  • Home
  • Knowledge Base
  • About Me
  1. Knowledge Base
  2. Articles
  3. 6502 Programming in C
  • Knowledge Base
    • Articles
      • 3D Printing and CNC
      • 6502 Programming in C
      • Add Settings File to .NET Console Application
      • AMD Ryzen 3 3200G with Radeon Vega Graphics Keeps Freezing
      • Angular Cheat Sheet
      • Angular CLI
      • Arduino / Raspberry Pi Remote Sensor
      • Bad owner or permissions on ssh config file
      • Basic Arduino Uno Dev Setup in Linux (Debian-based)
      • Boilerplate Date Definitions for SQL
      • Boot Linux Mint from flash drive on a netbook
      • Boot Linux to text mode
      • Bundling a Multiple Module Python Project Into a Zip File
      • Cache Resources Exhausted in Imagemagick
      • Call Async Method from Non-Async Method
      • Check an XML file to see if it is well-formed
      • Clear Linux Cache
      • Command-Line Arduino
      • Complex Object Collections in C++
      • Component Not Found error in VirtualBox
      • Compress and Extract Entire Directory Tree With Tar
      • Conditions on aggregates in SQL
      • Configuration of hddtemp
      • Connect To MySQL From .NET
      • Create Code Behind File for Razor Page In Blazor Application
      • Create An ISO File From a CD or DVD-ROM Using the Terminal
      • Cross-Compile Rust, Targeting Windows from Linux
      • C# Language Versioning
      • Dependency Injection in .NET/C#
      • Determine path to web.config at runtime
      • Display GRUB Menu
      • Docker in Linux
      • .NET IoT
      • Entity Framework
      • Enumeration Scoping in C++
      • File Operations in Java
      • Find Duplicate Rows By Specific Columns
      • Find Unique Instances of Text in Bash
      • Flash Disk Image to SD Card
      • Flask
      • Force SSL On Domain
      • GDB and GPROF
      • Get Started With Laravel
      • Git Tips and Tricks
      • Graphical sudo
      • Hide website from search engines
      • Hostname On Linux
      • How to install a .bundle file in Ubuntu Linux
      • HP Laptop Keyboard Not Working At Boot Start
      • Install .NET From Microsoft Feed in Ubuntu
      • Install Node.js
      • Install php7-xml to avoid utf encode/decode issue
      • Install truetype fonts in Ubuntu Linux
      • Java Links
      • JCL and Programming On the MVS Turnkey System
      • List Hardware Information in Ubuntu and other Debian-based Linux
      • Mainframe Emulation on Raspberry Pi Zero
      • Making Colors in a GIF Transparent
      • Manually Install Firefox
      • Markup and Code-Behind Examples for reveal.js
      • Merge Images
      • MicroPython on ESP32
      • Microservice Notes
      • Migrating from Windows to Linux
      • MiniDLNA - A lightweight, simple media server
      • Modify Default Folders in Ubuntu Linux
      • Modify default Java runtime in Linux
      • MongoDB Quick Start in Docker
      • Mount local folder as drive C in DOSBox
      • MVS Turnkey in Docker
      • MySQL command line – quick tips
      • No Frameworks Were Found error
      • NPM Cheat Sheet
      • NT_STATUS_UNSUCCESSFUL error when browsing machines/shares in Ubuntu Linux
      • Online IoT/Embedded Simulators
      • Package and Publish To NuGet
      • Packaging Python Projects
      • Passing a value in the URL for use by PHP
      • PDF Conversion Policy Error
      • PHP Login Script Tutorial
      • Pip Behind a Corporate Proxy
      • Prevent Code Injection In PHP
      • Programming Arduino (AVR) and Raspberry Pi Pico (ARM) in C
      • Publish to Crates.io
      • Python Optimization and Language Binding
      • Python Tkinter Examples
      • Query Windows shares from the command line in Ubuntu Linux
      • RabbitMQ in Docker
      • React Cheat Sheet
      • Recursive File Search
      • Redirect in PHP
      • Remote Access for Raspberry Pi
      • Remove Duplicates From List Collection
      • Requirements Files for Python
      • Rhythmbox tray icon plugin
      • Rsync as a Backup Solution
      • Rust Books (online)
      • Rust/Cargo Behind a Corporate Proxy
      • Selective chmod for directories and files
      • Sense HAT
      • Side-by-Side .NET Core Installations
      • Simple Raspberry Pi Control With .NET IoT and Python
      • Simple Web Server, Using Python or PHP
      • Single-File / Multi-OS / Multi-Architecture Publishing in .NET
      • Slim Framework
      • SQL Server in Docker
      • SQL Server in Linux
      • SQL Transaction Template
      • Start an X Windows session in Cygwin
      • stdio.h: No such file or directory
      • Stream Media from Ubuntu/Mint Linux to XBox360
      • Supporting Material for ‘.NET and Linux’ tech talk
      • TUI Frameworks for .NET
      • Use a value from a posted form in PHP
      • Using Your Router As A Wireless Repeater
      • Verbose PHP Logging To Web Browser
      • Version Mismatch in Python Package
      • Vim Tips and Tricks
      • Virtual Environment for Python
      • Vue.js Cheat Sheet
      • WCF Export
      • Web API with ASP.NET
      • Web Frameworks, Libraries, and Plugins
    • Glossary
      • Initial Program Load (IPL)
      • Job Control Language (JCL)
      • Just-in-time compilation (JIT)
      • Model–View–Controller (MVC)
      • Multiple Virtual Storage (MVS)
      • Resource Access Control Facility (RACF)
      • Real-time locating system (RTLS)
      • Time Sharing Option (TSO)
    • Learning Paths
      • Embedded and IoT
      • Low-Level
      • Mainframe
    • Other
      • Job and Employment Tools
  • Pages
    • About Me
  • Posts
    • 2007
      • Fake Science Makes Me Angry
      • Genetic Material from T-Rex Decoded
      • Vacuum and the Nature of Mass
    • 2011
      • Unhitched
    • 2012
      • Chick-fil-A
      • Choosing a First Telescope
      • Interesting Fossil
      • Rigorous Logic and Amelia
      • Pale Blue Dot
      • Science and Youth
      • Steve Jobs: The Lost Interview
      • Theism and the Thinking Mind
    • 2013
      • Duck and Cover
      • Duct Tape
      • Firefox OS
      • Idiocracy is Upon Us
      • It’s Just a Theory
      • Ken Feder and the Myth of the Ancient Astronauts
      • Martian Exopaleontology
      • …from the Moon and Mars
      • SunWatch Video Podcast
      • Tech Generation… not?
    • 2014
      • ‘Andean Gold’ lecture at SunWatch
      • Chelyabinsk Meteor
      • Lunar Eclipse
      • A New Meteor Shower Is Coming
      • Sleep Well, Philae
      • Why do I not believe?
    • 2015
      • Early Humans in the Americas
      • SETI@Home
      • What is a fossil?
    • 2017
      • Cleaning Fossils
      • The Dating Game
      • How Firefox Got Its Groove Back
      • March For Science
      • Printing the Past
      • Who Ya Gonna Call?
    • 2018
      • 2018 AIA/SunWatch Lecture Series: Science vs. Pseudoscience
      • Coordinate Systems: Finding Your Way Around the Sky
      • Natural Selection At Work
      • Like Water For Gravity
    • 2019
      • ‘Astronomy for Beginners’ Program
      • Homeopathy
      • Scientific and Critical Thinking Omnibus
      • Show Me What You’re Made Of
      • Visitors From Space
    • 2020
      • A Dim View of Betelgeuse
      • Cleveland Archaeological Society Lecture Series
      • Going Viral
      • The Trinity Mineral
      • Venusians, Perchance
    • 2021
      • Create Extension for Visual Studio Code
      • Early .NET 6 Observations
      • The Upcoming Lunar Eclipse: Real-World Application of the Practical Astronomy .NET Library (+ Python!)
      • Enumeration Scoping in C++
      • Fossil Hunting in Central Kentucky
      • Fossil Sites Map in Leaflet.js
      • Geology of Jezero
      • Python and XML
      • Running a Mainframe Emulator on a Raspberry Pi Zero (Lunch-n-Learn)
      • Rust in the Android Platform
      • Rust Foundation
      • Speak with Elegance (or not)
      • Supporting Material for ‘.NET and Linux’ tech talk
      • Traditional Programming on Hobbyist Microcontroller Boards
      • ‘Visual Studio Code: The Swiss Army Knife of Editors’ (tech talk)
    • 2022
      • James Webb Space Telescope
      • Program Like It’s 1982
      • Rust In the Linux Kernel
    • 2023
      • .NET IoT and Terminal GUI
      • Modern .NET Tooling in VS Code
      • Perl: Is It Really That Bad?
      • Sci-Fi Recommendations
    • 2024
      • 6502 Programming in C
      • DuckDuckGo AI Chat
      • Modern Perl
      • My AI Chatbot Experience
      • Practical Astronomy Algorithms in Various Languages
      • Site Updates
      • Think Async

On this page

  • What is the 6502?
  • Installation
  • Get Started
    • Native
    • 6502
    • Testing
  • Detailed Example
    • Makefile
    • Testing
  • Next Steps
  1. Knowledge Base
  2. Articles
  3. 6502 Programming in C

6502 Programming in C

Retro
C
Assembly

What is the 6502?

From Wikipedia:

The MOS Technology 6502 (typically pronounced “sixty-five-oh-two”) is an 8-bit microprocessor that was designed by a small team led by Chuck Peddle for MOS Technology. The design team had formerly worked at Motorola on the Motorola 6800 project; the 6502 is essentially a simplified, less expensive and faster version of that design.

When it was introduced in 1975, the 6502 was the least expensive microprocessor on the market by a considerable margin. It initially sold for less than one-sixth the cost of competing designs from larger companies, such as the 6800 or Intel 8080. Its introduction caused rapid decreases in pricing across the entire processor market. Along with the Zilog Z80, it sparked a series of projects that resulted in the home computer revolution of the early 1980s.

Popular video game consoles and home computers of the 1980s and early 1990s, such as the Atari 2600, Atari 8-bit computers, Apple II, Nintendo Entertainment System, Commodore 64, Atari Lynx, BBC Micro and others, use the 6502 or variations of the basic design. Soon after the 6502’s introduction, MOS Technology was purchased outright by Commodore International, who continued to sell the microprocessor and licenses to other manufacturers. In the early days of the 6502, it was second-sourced by Rockwell and Synertek, and later licensed to other companies.

In 1981, the Western Design Center started development of a CMOS version, the 65C02. This continues to be widely used in embedded systems, with estimated production volumes in the hundreds of millions.

David Murray (“The 8-Bit Guy”) created a video showcasing the 6502, with lots of info: The 6502 CPU Powered a Whole Generation!

Installation

This assumes a Debian-based system.

sudo apt install cc65 cc65-doc

The following programs are installed (descriptions taken from https://cc65.github.io/doc/):

Program Description
ar65 Archiver for object files generated by ca65. It allows to create archives, add or remove modules from archives, and to extract modules from existing archives.
ca65 Macro assembler for the 6502, 65C02, and 65816 CPUs. It is used as a companion assembler for the cc65 crosscompiler, but it may also be used as a standalone product.
cc65 C compiler for 6502 targets. It supports several 6502-based home computers such as the Commodore and Atari machines, but it easily is retargetable.
chrcvt65 Vector font converter. It is able to convert a foreign font into the native format.
cl65 Compile & link utility for cc65, the 6502 C compiler. It was designed as a smart frontend for the C compiler (cc65), the assembler (ca65), the object file converter (co65), and the linker (ld65).
co65 Object file conversion utility. It converts o65 object files into the native object file format used by the cc65 tool chain. Since o65 is the file format used by cc65 for loadable drivers, the co65 utility allows (among other things) to link drivers statically to the generated executables instead of loading them from disk.
da65 6502/65C02 disassembler that is able to read user-supplied information about its input data, for better results. The output is ready for feeding into ca65, the macro assembler supplied with the cc65 C compiler.
grc65 A compiler that can create GEOS headers and menus for cc65-compiled programs.
ld65 The linker combines object files into an executable file. ld65 is highly configurable and uses configuration files for high flexibility.
od65 Object file dump utility. It is able to output most parts of ca65-generated object files in readable form.
sim65 Simulator for 6502 and 65C02 CPUs. It allows to test target independent code.
sp65 Sprite and bitmap utility that is part of the cc65 development suite. It is used to convert graphics and bitmaps into the target formats of the supported machines.

Get Started

Of course we’ll start with the ubiquitous “Hello, world”.

hello.c

#include <stdio.h>
    
int main()
{
    printf("Hello, world!\n");
    
    return(0);
}

Native

We can target our native platform (Linux) using the gcc compiler we’re already familiar with:

gcc hello.c -o hello

This gives us the following binary output:

hello  ELF 64-bit LSB pie executable

6502

To target the 6502 processor, we use cl65 instead:

cl65 hello.c

This produces two output files:

hello.o   xo65 object
hello     Commodore 64 program

The default target is Commodore 64, but you can specify a different platform with the -t argument. The Apple II, for example:

cl65 -t apple2 hello.c

Output:

hello   AppleSingle encoded Macintosh file

To see all of the available platforms, use –list-targets:

cl65 --list-targets

Testing

If you want to test your binary, use sim6502 as your target:

cl65 --target sim6502 hello.c
hello   sim65 executable, version 2, 6502

Test using sim65:

sim65 hello
Hello, world!

You can get some additional info with the -v (verbose) argument:

sim65 -v hello
Loaded 'hello' at $0200-$0AE6
File version: 2
Reset: $0200
Hello, world!
PVExit ($00)

Detailed Example

The compile and link utility (cl65) simplifies the process of building a binary by combining multiple build steps into one. For this section, we’ll perform those steps individually.

We’ll start with another “Hello world!” example, but with a few tweaks to the hello.c source:

hello.c

#include <stdio.h>
    
extern const char text[];
    
int main() {
    printf("%s\n", text);
    
    return (0);
}

You’ll notice that our “Hello world!” text doesn’t appear in the source. Instead, we have a const char text[] declaration. The extern qualifier is a hint: We’ll actually define our text in a separate assembly file:

text.s

.export _text
_text:  .asciiz "Hello world!"

With both files in place, we’re ready to compile using cc65. I’m targeting Commodore 64 and I’ve also added a -O argument to optimize the output:

cc65 -O -t c64 hello.c

This will generate a hello.s assembly file:

hello.s

;
; File generated by cc65 v 2.18 - Ubuntu 2.19-1
;
    .fopt       compiler,"cc65 v 2.18 - Ubuntu 2.19-1"
    .setcpu     "6502"
    .smart      on
    .autoimport on
    .case       on
    .debuginfo  off
    .importzp   sp, sreg, regsave, regbank
    .importzp   tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
    .macpack    longbranch
    .forceimport    __STARTUP__
    .import     _printf
    .import     _text
    .export     _main
    
.segment    "RODATA"
    
L0003:
    .byte   $25,$53,$0D,$00
    
; ---------------------------------------------------------------
; int __near__ main (void)
; ---------------------------------------------------------------
    
.segment    "CODE"
    
.proc   _main: near
    
.segment    "CODE"
    
    lda     #<(L0003)
    ldx     #>(L0003)
    jsr     pushax
    lda     #<(_text)
    ldx     #>(_text)
    jsr     pushax
    ldy     #$04
    jsr     _printf
    ldx     #$00
    txa
    rts
    
.endproc

Now we can take our two assembly files (the one we created from scratch, and the one we generated) and build object files from them using the macro assembler:

ca65 hello.s
ca65 -t c64 text.s
hello.o    xo65 object, version 17, no debug info
text.o     xo65 object, version 17, no debug info

Finally, we use the linker to create our executable:

ld65 -o hello -t c64 hello.o text.o c64.lib
hello   Commodore C64 program

Makefile

Here’s a Makefile, if you’d like to simplify those steps:

Makefile

TARGET = c64
    
COMPILER = cc65
ASSEMBLER = ca65
LINKER = ld65
    
default:
    @echo 'Targets:'
    @echo '  build'
    @echo '  clean'
    
build: hello
    
hello: hello.o text.o
    $(LINKER) -o hello -t $(TARGET) hello.o text.o $(TARGET).lib
    
hello.o: hello.s
    $(ASSEMBLER) hello.s
    
text.o: text.s
    $(ASSEMBLER) -t $(TARGET) text.s
    
hello.s: hello.c
    $(COMPILER) -O -t $(TARGET) hello.c
    
clean:
    @rm -f hello.s
    @rm -f *.o
    @rm -f hello

Testing

The 8-bit Workshop IDE provides a quick and easy way to test your binary.

  1. Go to https://8bitworkshop.com/
  2. Click the “Open 8bitworkshop IDE” button.
  3. Open the systems dropdown list in the upper-left corner of the screen and select “Computers”, “Commodore 64”
  4. Click the menu button next to the systems dropdown and select “Upload”.
  5. Browse to your hello binary and click “Open”.
  6. The IDE will ask if you’d like to open ‘hello’ as your main project file. Click “Open As New Project”.

The binary will be loaded and you should see output similar to this:

Next Steps

If you’d like to learn more, here are some sites to visit:

  • The cc65 repo has lots of sample code.
  • The cc65 website has a lot of information, including links to detailed documentation and the repo wiki.
  • 8bitworkshop is a treasure trove of information about programming for old systems, including books and an online IDE where you can write code and see it emulated in real-time.
 

Copyright 2024, Jim Carr

Cookie Preferences