# c65gm A high-level 6502 cross-compiler targeting the ACME Cross-Assembler. c65gm provides a more expressive language for writing 6502 assembly programs, with features like functions, type-checked variables, control flow structures, and compile-time optimizations. ## Download Pre-built binaries are available from the [Releases page](https://github.com/YOUR_USERNAME/c65gm/releases). Each release follows the naming pattern `c65gm_v{MAJOR}.{BUILD}_os_arch`: | File | Platform | |------|----------| | `c65gm_v1.1_linux_amd64.tar.gz` | Linux (x86_64) | | `c65gm_v1.1_linux_arm64.tar.gz` | Linux (ARM64) | | `c65gm_v1.1_darwin_amd64.tar.gz` | macOS (Intel) | | `c65gm_v1.1_darwin_arm64.tar.gz` | macOS (Apple Silicon) | | `c65gm_v1.1_windows_amd64.zip` | Windows (x86_64) | Each release includes a `checksums.txt` file for verifying download integrity: ```bash sha256sum -c checksums.txt ``` ### Verify with the annotated tag Every release is created from an annotated git tag containing the Go compiler version and SHA256 checksums. To inspect: ```bash git fetch --tags git tag -l v1.1 ``` The tag message shows the exact checksums. You can reproduce the build from the tag and verify your binary matches: ## What It Does c65gm compiles high-level source code into ACME assembler syntax for the 6502 processor (Commodore 64 and similar platforms). It provides: - **Type system**: BYTE and WORD variables with scope resolution - **Functions**: Named functions with parameters and call graph analysis - **Control flow**: IF/ENDIF, WHILE/WEND, FOR loops, SWITCH/CASE - **Memory operations**: PEEK/POKE/PEEKW/POKEW with zero-page optimization. Access registers as variables. - **Operators**: Arithmetic (ADD, SUB), bitwise (AND, OR, XOR) - **Preprocessor**: File inclusion, macros, conditional compilation, Starlark scripting - **Standard library**: C64 screen/kernal routines, memory management, string handling, graphics (Koala), FAT16 filesystem, and more (accessed via `#include `, path set by `C65LIBPATH` environment variable) - **Optimizations**: Constant folding, self-assignment detection - **Safety features**: Compile-time detection of overlapping absolute addresses in function call chains ## Prerequisites ### ACME Assembler (Required for creating .prg executables) c65gm requires the ACME Cross-Assembler to create executable .prg files. If you only need to generate assembly (.asm) files, you can use compile mode without ACME. **Installation options by platform:** - **Ubuntu/Debian**: `sudo apt install acme` - **Fedora/RHEL**: `sudo dnf install acme` - **Arch Linux**: `sudo pacman -S acme` - **macOS**: `brew install acme` - **Windows**: Download binary from [ACME releases](https://github.com/meonwax/acme/releases) If ACME is not found when running the `build` command, c65gm will display platform-specific installation instructions. ### Go (Required for building c65gm from source) - **Go**: Version 1.25.1 or higher (tested with 1.25.5) The project uses Go modules with these dependencies: - `github.com/armon/go-radix` - Prefix tree for command lookup - `go.starlark.net` - Embedded Starlark scripting support ## Building Build the compiler binary: ```bash go build -o c65gm ``` Or install to your GOPATH: ```bash go install ``` ## Usage ### Quick Start (Recommended) Compile and assemble directly to a .prg file: ```bash ./c65gm myprogram.c65 # Creates myprogram.prg ./c65gm -i myprogram.c65 -o game.prg # Creates game.prg ``` ### Command Reference #### Build (compile + assemble to .prg) ```bash ./c65gm build -i myprogram.c65 [-o output.prg] [--keep-asm] [--no-cbm] ./c65gm myprogram.c65 # Default build to myprogram.prg ./c65gm -i myprogram.c65 # Same as above ./c65gm -in myprogram.c65 # Legacy syntax, still works ``` #### Compile (to .asm only) ```bash ./c65gm compile -i myprogram.c65 [-o output.asm] ./c65gm myprogram.c65 -o output.asm # .asm extension triggers compile mode ./c65gm -i myprogram.c65 -out output.asm # Legacy syntax ``` #### Help ```bash ./c65gm help ./c65gm -h ./c65gm --help ``` ### Key Features - **Self-contained**: Embedded standard library and Starlark interpreter (ACME assembler required for .prg creation) - **Flexible syntax**: `-i`/`-in` and `-o`/`-out` are equivalent - **Smart defaults**: Output extension determines mode (.prg = build, .asm = compile) - **ACME integration**: Automatically finds and runs ACME assembler with `-f cbm` by default (provides platform-specific installation instructions if missing) - **Backward compatible**: Legacy `-in`/`-out` flags still work - **Customizable**: Use `--no-cbm` to disable CBM format, `--keep-asm` to keep intermediate files ## Compiler Options Reference ### Default Behavior (Simplest Case) The simplest way to use c65gm is to provide just the input file: ```bash c65gm myprogram.c65 ``` This will: 1. Compile `myprogram.c65` to assembly 2. Run ACME assembler with `-f cbm` format 3. Produce `myprogram.prg` (C64 executable) ### Input and Output Files - **`-i`, `--input`** (`-in`): Specify input `.c65` file (required) - **`-o`, `--output`** (`-out`): Specify output file (optional) **Examples:** ```bash # Explicit input/output c65gm -i program.c65 -o game.prg # Input only (default output: program.prg) c65gm program.c65 # Legacy syntax (still works) c65gm -in program.c65 -out output.asm ``` ### Operation Modes c65gm automatically determines the operation mode based on the output file extension: #### Build Mode (`.prg` extension) Compiles **and** assembles to create a C64 executable: ```bash c65gm program.c65 # → program.prg (default) c65gm program.c65 -o game.prg # → game.prg ``` #### Compile Mode (`.asm` extension) Compiles only, producing ACME assembly for manual assembly: ```bash c65gm program.c65 -o output.asm # → output.asm c65gm compile -i program.c65 # → program.asm ``` ### Subcommands For explicit control, use subcommands: #### `build` - Compile + Assemble ```bash c65gm build -i program.c65 [-o output.prg] [--keep-asm] [--no-cbm] ``` - `--keep-asm`: Keep intermediate `.asm` file - `--no-cbm`: Don't add `-f cbm` flag to ACME (for non-CBM targets) #### `compile` - Compile Only ```bash c65gm compile -i program.c65 [-o output.asm] ``` Produces assembly file only, doesn't run ACME. #### `help` - Show Usage ```bash c65gm help c65gm -h c65gm --help ``` ### ACME Assembler Integration c65gm automatically: 1. Searches `PATH` for `acme` executable 2. Runs: `acme -o output.prg -f cbm temp.asm` 3. Shows ACME output and errors 4. Cleans up temporary files (unless `--keep-asm`) **Error Handling:** If ACME is not found, c65gm shows installation instructions and suggests using `compile` mode instead. ### Environment Variables - **`C65LIBPATH`**: Search path for `#INCLUDE ` directives ```bash export C65LIBPATH=/path/to/c65gm/lib c65gm program.c65 ``` ### Examples Summary ```bash # Quick build (recommended) c65gm program.c65 # Custom output name c65gm -i program.c65 -o game.prg # Keep intermediate assembly c65gm build -i program.c65 --keep-asm # Compile only (no ACME) c65gm compile -i program.c65 # Legacy two-step process (still works) c65gm -in program.c65 -out program.asm acme -f cbm -o program.prg program.asm ``` ## Running Tests Run all tests: ```bash go test ./... ``` Run tests with verbose output: ```bash go test -v ./... ``` Run tests for a specific package: ```bash go test ./internal/compiler go test ./internal/commands ``` ## Examples See the `examples/` directory for sample programs: - `hires/` - High-resolution graphics demo - `multicolorbm/` - Multicolor bitmap demo - `memlib_demo/` - Memory library usage - `switch_demo/` - SWITCH/CASE statement examples ### Building Examples ```bash cd examples/hires c65gm hires.c65 # Creates hires.prg c65gm -i hires.c65 -o demo.prg # Creates demo.prg c65gm compile -i hires.c65 # Creates hires.asm only ``` The example directories also contain `cm.sh` scripts showing the old build method. ## Documentation - `language.md` - Complete language reference - `syntax.md` - Syntax guide - `commands.md` - Command reference ## Editor Syntaxes - Kate: copy XML to ~/.local/share/org.kde.syntax-highlighting/syntax/ - Sublime: copy .sublime-syntax to Packages/User/ ## Release Process This section documents how to create a new release for maintainers. ### Prerequisites - Go 1.25.1+ installed - `sha256sum` (Linux) or `shasum` (macOS) - Git with write access to the repository ### Steps The release script does everything automatically. Just run it: ```bash bash scripts/release.sh ``` This performs the following sequence: 1. **Verify git clean** — fails if uncommitted changes exist 2. **Read BUILDNUM** — e.g., `42` → version `1.42` 3. **Verify tag available** — fails if tag `v1.42` already exists 4. **Bump BUILDNUM** — writes `43` to `BUILDNUM` 5. **Build all targets** — 5 platform binaries with version injected via ldflags 6. **Generate SHA256 checksums** — written to `dist/checksums.txt` 7. **Commit BUILDNUM** — `git commit` with checksums in the commit body 8. **Create annotated tag** — `git tag -a v1.42` pointing at the pre-bump commit, with checksums and Go version in the tag message ### Publish ```bash git push --follow-tags origin ``` This pushes both the new commit and the annotated tag. The tag is the source of truth for verification. ### Verify a release ```bash git checkout v1.42 # You now have the exact source (BUILDNUM=42) go build -trimpath -ldflags="-s -w -X main.version=1.42" sha256sum c65gm # Compare with the checksum in: git tag -l v1.42 ``` ### Reproducible builds The release script uses these flags for deterministic builds: ```bash go build -trimpath -ldflags="-s -w -X main.version=${VERSION}" ``` - `-trimpath` strips local filesystem paths - `-s -w` strips symbol table and DWARF debug info - `-X main.version` injects the version - `CGO_ENABLED=0` ensures fully static binaries Binaries built from the same source with the same Go version produce identical hashes. The tag message captures the Go version and expected checksums for verification. ## License Copyright (C) 1999, 2025 Mattias Hansson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA See [LICENSE](LICENSE) file for the full GPL v2 license text.