370 lines
11 KiB
Markdown
370 lines
11 KiB
Markdown
# 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 <file>`, 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 <file>` 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
|
|
```
|
|
|
|
**`--follow-tags` is critical.** Without it, only the commit is pushed — the annotated tag (with checksums) stays local. The release is incomplete until the tag is on the remote.
|
|
|
|
### Forgot to use `--follow-tags`?
|
|
|
|
If you already ran `git push` without it, push just the tag:
|
|
|
|
```bash
|
|
git push origin v1.1
|
|
```
|
|
|
|
The tag is the source of truth for verification. Without it on the remote, nobody can verify.
|
|
|
|
### 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.
|