Added claude code docker setup for project. Added language guide.
This commit is contained in:
parent
5f01282df5
commit
b54183aab4
5 changed files with 916 additions and 0 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -27,3 +27,6 @@ out/
|
|||
*.tmp
|
||||
.DS_Store
|
||||
c65gm
|
||||
|
||||
.claude/
|
||||
.npm/
|
||||
|
|
|
|||
4
Dockerfile
Normal file
4
Dockerfile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
RUN npm install -g @anthropic-ai/claude-code
|
||||
CMD ["claude"]
|
||||
4
claude_code_docker.sh
Normal file
4
claude_code_docker.sh
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
export DOCKER_UID=$(id -u)
|
||||
export DOCKER_GID=$(id -g)
|
||||
docker compose run --rm claude-c65gm
|
||||
13
docker-compose.yml
Normal file
13
docker-compose.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
services:
|
||||
claude-c65gm:
|
||||
build: .
|
||||
user: "${DOCKER_UID}:${DOCKER_GID}"
|
||||
volumes:
|
||||
- .:/app
|
||||
environment:
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- CLAUDE_CONFIG_DIR=/app/.claude
|
||||
- HOME=/app
|
||||
- DISABLE_AUTOUPDATER=1
|
||||
stdin_open: true
|
||||
tty: true
|
||||
892
language.md
Normal file
892
language.md
Normal file
|
|
@ -0,0 +1,892 @@
|
|||
# Programming in c65gm
|
||||
|
||||
c65gm is a high-level language for 6502 assembly programming that combines modern programming constructs with direct hardware access. Originally designed for Commodore 64 development, it compiles to efficient 6502 assembly code.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Getting Started](#getting-started)
|
||||
2. [Variables and Types](#variables-and-types)
|
||||
3. [Expressions and Operators](#expressions-and-operators)
|
||||
4. [Control Flow](#control-flow)
|
||||
5. [Functions](#functions)
|
||||
6. [Memory Operations](#memory-operations)
|
||||
7. [Code Blocks](#code-blocks)
|
||||
8. [Preprocessor](#preprocessor)
|
||||
9. [Common Patterns](#common-patterns)
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Your First Program
|
||||
|
||||
Here's a simple program that changes the screen border color on a Commodore 64:
|
||||
|
||||
```c65
|
||||
ORIGIN $0801
|
||||
|
||||
BYTE borderColor @ $D020
|
||||
|
||||
borderColor = 5 // Set border to green
|
||||
```
|
||||
|
||||
### Program Structure
|
||||
|
||||
A typical c65gm program consists of:
|
||||
|
||||
1. **ORIGIN directive** - Sets where code will be placed in memory
|
||||
2. **Variable declarations** - Define your data
|
||||
3. **Code** - Functions and statements that do the work
|
||||
|
||||
```c65
|
||||
ORIGIN $0801
|
||||
|
||||
// Variables
|
||||
BYTE counter = 0
|
||||
WORD screen = $0400
|
||||
|
||||
// Main code
|
||||
FUNC main
|
||||
counter = 10
|
||||
processData()
|
||||
FEND
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variables and Types
|
||||
|
||||
### BYTE Variables
|
||||
|
||||
BYTE variables store 8-bit values (0-255).
|
||||
|
||||
```c65
|
||||
BYTE count // Uninitialized
|
||||
BYTE speed = 5 // Initialized to 5
|
||||
BYTE screen @ $D020 // Memory-mapped to specific address
|
||||
BYTE CONST MAX_SPEED = 10 // Constant (recommended over #DEFINE)
|
||||
```
|
||||
|
||||
### WORD Variables
|
||||
|
||||
WORD variables store 16-bit values (0-65535).
|
||||
|
||||
```c65
|
||||
WORD counter // Uninitialized
|
||||
WORD address = $C000 // Initialized to hex value
|
||||
WORD message = "Hello" // String literal (pointer to text)
|
||||
WORD screenPtr @ $FB // Zero-page pointer
|
||||
WORD CONST SCREEN_RAM = $0400 // Constant
|
||||
```
|
||||
|
||||
### Memory-Mapped Variables
|
||||
|
||||
Variables can be placed at specific addresses using `@`:
|
||||
|
||||
```c65
|
||||
BYTE borderColor @ $D020 // VIC-II border color
|
||||
WORD irqVector @ $0314 // IRQ vector
|
||||
WORD zpPointer @ $FB // Zero-page variable (fast access)
|
||||
```
|
||||
|
||||
### Constants
|
||||
|
||||
Use `CONST` keyword for named constants (preferred over preprocessor defines):
|
||||
|
||||
```c65
|
||||
BYTE CONST MAX_ITEMS = 100
|
||||
WORD CONST SCREEN_START = $0400
|
||||
WORD CONST CHAR_ROM = $D000
|
||||
|
||||
// Usage
|
||||
BYTE itemCount = MAX_ITEMS
|
||||
screen = SCREEN_START
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Expressions and Operators
|
||||
|
||||
### Number Formats
|
||||
|
||||
```c65
|
||||
value = 123 // Decimal
|
||||
value = $FF // Hexadecimal ($ prefix)
|
||||
value = %11111111 // Binary (% prefix)
|
||||
```
|
||||
|
||||
### Arithmetic Operators
|
||||
|
||||
```c65
|
||||
result = 10 + 5 // Addition
|
||||
result = 100 - 5 // Subtraction
|
||||
result = 4 * 10 // Multiplication
|
||||
result = 100 / 5 // Division
|
||||
```
|
||||
|
||||
### Bitwise Operators
|
||||
|
||||
```c65
|
||||
mask = value & $FF // Bitwise AND
|
||||
flags = flags | $01 // Bitwise OR
|
||||
toggle = value ^ $FF // Bitwise XOR
|
||||
```
|
||||
|
||||
### Increment and Decrement
|
||||
|
||||
```c65
|
||||
counter++ // Increment by 1
|
||||
counter-- // Decrement by 1
|
||||
index++
|
||||
lives--
|
||||
```
|
||||
|
||||
### Critical: No Operator Precedence
|
||||
|
||||
**Expressions evaluate strictly left to right!** There is no operator precedence.
|
||||
|
||||
```c65
|
||||
result = 2 + 3 * 4 // Evaluates as (2+3)*4 = 20, NOT 2+(3*4) = 14
|
||||
value = 100 - 20 + 5 // Evaluates as (100-20)+5 = 85
|
||||
```
|
||||
|
||||
For complex expressions, use temporary variables:
|
||||
|
||||
```c65
|
||||
// Instead of: result = a + b * c (which doesn't work as expected)
|
||||
temp = b * c
|
||||
result = a + temp
|
||||
```
|
||||
|
||||
### Constant Expressions
|
||||
|
||||
Expressions without spaces are treated as compile-time constants:
|
||||
|
||||
```c65
|
||||
value = 100+50 // OK - constant expression, evaluated at compile time
|
||||
value = 100 + 50 // ERROR - spaces make it a runtime expression
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Control Flow
|
||||
|
||||
### IF Statements
|
||||
|
||||
Basic conditional execution:
|
||||
|
||||
```c65
|
||||
IF count == 10
|
||||
result = 1
|
||||
ENDIF
|
||||
|
||||
IF value > threshold
|
||||
process()
|
||||
ELSE
|
||||
skip()
|
||||
ENDIF
|
||||
```
|
||||
|
||||
Supported comparison operators: `=` `==` `<>` `!=` `>` `<` `>=` `<=`
|
||||
|
||||
Single-parameter IF treats 0 as false, non-zero as true:
|
||||
|
||||
```c65
|
||||
IF running
|
||||
// Executes if running != 0
|
||||
update()
|
||||
ENDIF
|
||||
```
|
||||
|
||||
### WHILE Loops
|
||||
|
||||
Loop while condition is true:
|
||||
|
||||
```c65
|
||||
WHILE counter < 100
|
||||
counter++
|
||||
process(counter)
|
||||
WEND
|
||||
|
||||
WHILE running
|
||||
gameLoop()
|
||||
WEND
|
||||
|
||||
WHILE x != y
|
||||
x++
|
||||
WEND
|
||||
```
|
||||
|
||||
### FOR Loops
|
||||
|
||||
Loop with automatic counter:
|
||||
|
||||
```c65
|
||||
FOR i = 0 TO 10
|
||||
screen = i
|
||||
NEXT
|
||||
|
||||
FOR x = 0 TO 255 STEP 2
|
||||
result = result + x
|
||||
NEXT
|
||||
|
||||
FOR counter = start TO finish
|
||||
process(counter)
|
||||
NEXT
|
||||
```
|
||||
|
||||
### BREAK
|
||||
|
||||
Exit a loop early:
|
||||
|
||||
```c65
|
||||
FOR i = 0 TO 100
|
||||
IF i == 50
|
||||
BREAK
|
||||
ENDIF
|
||||
process(i)
|
||||
NEXT
|
||||
|
||||
WHILE running
|
||||
IF error
|
||||
BREAK
|
||||
ENDIF
|
||||
update()
|
||||
WEND
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
### Declaring Functions
|
||||
|
||||
```c65
|
||||
FUNC initialize
|
||||
BYTE temp = 0
|
||||
screen = temp
|
||||
FEND
|
||||
|
||||
FUNC setColor(color, brightness)
|
||||
borderColor = color
|
||||
backgroundColor = brightness
|
||||
FEND
|
||||
```
|
||||
|
||||
### Calling Functions
|
||||
|
||||
```c65
|
||||
initialize()
|
||||
setColor(1, 14)
|
||||
process(xpos, ypos, spriteData)
|
||||
```
|
||||
|
||||
### Parameter Passing Modes
|
||||
|
||||
Parameters can have different access modes:
|
||||
|
||||
- `in:` - Read-only (default if not specified)
|
||||
- `out:` - Write-only (for returning values)
|
||||
- `io:` - Read-write
|
||||
|
||||
```c65
|
||||
FUNC add(in:a, in:b, out:result)
|
||||
result = a + b
|
||||
FEND
|
||||
|
||||
FUNC swap(io:x, io:y)
|
||||
BYTE temp = x
|
||||
x = y
|
||||
y = temp
|
||||
FEND
|
||||
```
|
||||
|
||||
### Local Variables
|
||||
|
||||
Variables declared inside functions are local:
|
||||
|
||||
```c65
|
||||
FUNC calculate(value)
|
||||
BYTE local = 10 // Only exists inside this function
|
||||
WORD temp // Local temporary
|
||||
temp = value + local
|
||||
FEND
|
||||
```
|
||||
|
||||
### Curly Brace Syntax
|
||||
|
||||
Alternative parameter syntax using curly braces:
|
||||
|
||||
```c65
|
||||
FUNC process({BYTE value} out:{BYTE result})
|
||||
result = value + 1
|
||||
FEND
|
||||
```
|
||||
|
||||
### Returning from Functions
|
||||
|
||||
```c65
|
||||
FUNC checkValue(value)
|
||||
IF value == 0
|
||||
EXIT // Return early
|
||||
ENDIF
|
||||
process(value)
|
||||
FEND
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Memory Operations
|
||||
|
||||
### PEEK - Reading Memory
|
||||
|
||||
Read a byte from memory:
|
||||
|
||||
```c65
|
||||
value = PEEK $D020 // Read from absolute address
|
||||
char = PEEK screenPtr[index] // Read with offset
|
||||
byte = PEEK pointer // Read from pointer
|
||||
```
|
||||
|
||||
**Important:** For indexed access, the address must be a WORD variable in zero page.
|
||||
|
||||
```c65
|
||||
WORD buffer @ $FB // Zero-page pointer
|
||||
value = PEEK buffer[10] // Read buffer+10
|
||||
```
|
||||
|
||||
### POKE - Writing Memory
|
||||
|
||||
Write a byte to memory:
|
||||
|
||||
```c65
|
||||
POKE $D020 WITH 0 // Write to absolute address
|
||||
POKE screenPtr[index] WITH char // Write with offset
|
||||
POKE pointer WITH value // Write to pointer
|
||||
```
|
||||
|
||||
### PEEKW - Reading 16-bit Words
|
||||
|
||||
Read a 16-bit value from memory:
|
||||
|
||||
```c65
|
||||
WORD address
|
||||
address = PEEKW $FFFC // Read reset vector
|
||||
|
||||
WORD buffer @ $FB
|
||||
value = PEEKW buffer[10] // Read word at buffer+10
|
||||
```
|
||||
|
||||
### POKEW - Writing 16-bit Words
|
||||
|
||||
Write a 16-bit value to memory:
|
||||
|
||||
```c65
|
||||
POKEW $0314 WITH irqHandler // Set IRQ vector
|
||||
POKEW dataPtr[0] WITH address // Write word with offset
|
||||
```
|
||||
|
||||
### POINTER - Setting Pointers
|
||||
|
||||
Set a pointer to an address:
|
||||
|
||||
```c65
|
||||
POINTER screenPtr TO $0400
|
||||
POINTER bufferPtr TO dataBuffer
|
||||
POINTER funcPtr TO myFunction
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Blocks
|
||||
|
||||
### ASM Blocks
|
||||
|
||||
Inline assembly for direct hardware control:
|
||||
|
||||
```c65
|
||||
ASM
|
||||
lda #$00
|
||||
sta $d020
|
||||
jsr $ffd2
|
||||
ENDASM
|
||||
```
|
||||
|
||||
#### Referencing Variables in ASM
|
||||
|
||||
Global variables can be referenced directly:
|
||||
|
||||
```c65
|
||||
BYTE temp = 5
|
||||
|
||||
ASM
|
||||
lda temp
|
||||
clc
|
||||
adc #10
|
||||
sta temp
|
||||
ENDASM
|
||||
```
|
||||
|
||||
Local variables (inside FUNC) need pipe delimiters `|varname|`:
|
||||
|
||||
```c65
|
||||
FUNC calculate(value)
|
||||
BYTE local = 10
|
||||
ASM
|
||||
lda |local| // Reference local variable
|
||||
clc
|
||||
adc value // Global parameter
|
||||
sta |local|
|
||||
ENDASM
|
||||
FEND
|
||||
```
|
||||
|
||||
### SCRIPT Blocks
|
||||
|
||||
Generate assembly code at compile time using Starlark (Python-like):
|
||||
|
||||
```c65
|
||||
// Generate a table of squares
|
||||
SCRIPT
|
||||
print("squares:")
|
||||
for i in range(256):
|
||||
print(" !8 %d" % (i * i % 256))
|
||||
ENDSCRIPT
|
||||
```
|
||||
|
||||
#### Sine Table Example
|
||||
|
||||
```c65
|
||||
SCRIPT
|
||||
import math
|
||||
print("sintable:")
|
||||
for i in range(256):
|
||||
angle = (i * 2.0 * math.pi) / 256.0
|
||||
sine = math.sin(angle)
|
||||
value = int((sine + 1.0) * 127.5)
|
||||
print(" !8 %d" % value)
|
||||
ENDSCRIPT
|
||||
```
|
||||
|
||||
#### Referencing Variables
|
||||
|
||||
Use `|varname|` syntax in generated assembly:
|
||||
|
||||
```c65
|
||||
BYTE tableSize = 64
|
||||
|
||||
SCRIPT
|
||||
print("lookup:")
|
||||
for i in range(64):
|
||||
print(" !8 %d" % (i * 2))
|
||||
print(" // Size stored in |tableSize|")
|
||||
ENDSCRIPT
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Preprocessor
|
||||
|
||||
### Comments
|
||||
|
||||
```c65
|
||||
// Single-line comment
|
||||
BYTE counter = 0 // End-of-line comment
|
||||
```
|
||||
|
||||
In ASM blocks, use assembly syntax:
|
||||
```c65
|
||||
ASM
|
||||
lda #$00 ; Assembly comment
|
||||
ENDASM
|
||||
```
|
||||
|
||||
In SCRIPT blocks, use Python syntax:
|
||||
```c65
|
||||
SCRIPT
|
||||
# Python-style comment
|
||||
print("hello")
|
||||
ENDSCRIPT
|
||||
```
|
||||
|
||||
### Include Files
|
||||
|
||||
```c65
|
||||
#INCLUDE mylib.c65 // Relative to current file
|
||||
#INCLUDE lib/string.c65 // Subdirectory
|
||||
#INCLUDE <stdlib.c65> // Search in C65LIBPATH
|
||||
```
|
||||
|
||||
Include guards prevent multiple inclusion:
|
||||
|
||||
```c65
|
||||
#IFNDEF __MY_LIBRARY
|
||||
#DEFINE __MY_LIBRARY = 1
|
||||
|
||||
// Library code here
|
||||
|
||||
#IFEND
|
||||
```
|
||||
|
||||
### Define Macros
|
||||
|
||||
Text substitution macros:
|
||||
|
||||
```c65
|
||||
#DEFINE MAX_SPEED = 10
|
||||
#DEFINE SCREEN = $$0400 // $$ escapes to literal $
|
||||
|
||||
speed = MAX_SPEED // Replaced with 10
|
||||
```
|
||||
|
||||
Special characters in defines:
|
||||
|
||||
```c65
|
||||
#DEFINE SPACE = $20 // Space character (hex 20)
|
||||
#DEFINE NEWLINE = $0D // Carriage return
|
||||
#DEFINE HEXADDR = $$D020 // Literal "$D020" text
|
||||
```
|
||||
|
||||
**Note:** Prefer `BYTE CONST` and `WORD CONST` over `#DEFINE` for constants.
|
||||
|
||||
### Conditional Compilation
|
||||
|
||||
```c65
|
||||
#IFDEF DEBUG
|
||||
BYTE debugFlag = 1
|
||||
#IFEND
|
||||
|
||||
#IFNDEF __LIB_INCLUDED
|
||||
#DEFINE __LIB_INCLUDED = 1
|
||||
// Include library code
|
||||
#IFEND
|
||||
```
|
||||
|
||||
### Pragma Directives
|
||||
|
||||
Control compiler behavior:
|
||||
|
||||
```c65
|
||||
#PRAGMA _P_USE_LONG_JUMP 1 // Use JMP instead of branches
|
||||
#PRAGMA _P_USE_IMMUTABLE_CODE 1 // No self-modifying code (for ROM)
|
||||
#PRAGMA _P_USE_CBM_STRINGS 1 // Use PETSCII encoding
|
||||
```
|
||||
|
||||
### Debug Directives
|
||||
|
||||
```c65
|
||||
#PRINT Compiling main module // Print during compilation
|
||||
#HALT // Stop compilation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Screen Manipulation
|
||||
|
||||
```c65
|
||||
WORD CONST SCREEN = $0400
|
||||
WORD CONST COLOR_RAM = $D800
|
||||
BYTE CONST SCREEN_WIDTH = 40
|
||||
BYTE CONST SCREEN_HEIGHT = 25
|
||||
|
||||
FUNC clearScreen
|
||||
WORD screenPtr @ $FB
|
||||
POINTER screenPtr TO SCREEN
|
||||
|
||||
WORD remaining = 1000
|
||||
WHILE remaining > 0
|
||||
POKE screenPtr[0] WITH 32 // Space character
|
||||
screenPtr++
|
||||
remaining--
|
||||
WEND
|
||||
FEND
|
||||
```
|
||||
|
||||
### String Handling
|
||||
|
||||
```c65
|
||||
// Print null-terminated string
|
||||
FUNC printString(textPtr)
|
||||
BYTE char
|
||||
char = PEEK textPtr[0]
|
||||
|
||||
WHILE char != 0
|
||||
ASM
|
||||
lda |char|
|
||||
jsr $FFD2 // CHROUT
|
||||
ENDASM
|
||||
textPtr++
|
||||
char = PEEK textPtr[0]
|
||||
WEND
|
||||
FEND
|
||||
```
|
||||
|
||||
### Sprite Manipulation
|
||||
|
||||
```c65
|
||||
WORD CONST VIC2 = $D000
|
||||
BYTE spriteX @ VIC2+0
|
||||
BYTE spriteY @ VIC2+1
|
||||
BYTE spriteEnable @ VIC2+21
|
||||
|
||||
FUNC enableSprite(spriteNum)
|
||||
BYTE mask
|
||||
mask = 1
|
||||
|
||||
FOR i = 0 TO spriteNum
|
||||
mask = mask * 2
|
||||
NEXT
|
||||
|
||||
spriteEnable = spriteEnable | mask
|
||||
FEND
|
||||
```
|
||||
|
||||
### Zero Page Optimization
|
||||
|
||||
For frequently accessed pointers, use zero page:
|
||||
|
||||
```c65
|
||||
WORD fastPtr @ $FB // Zero page = fast indexed access
|
||||
|
||||
FUNC processBuffer(buffer, size)
|
||||
POINTER fastPtr TO buffer
|
||||
|
||||
WHILE size > 0
|
||||
BYTE value
|
||||
value = PEEK fastPtr[0]
|
||||
// Process value
|
||||
fastPtr++
|
||||
size--
|
||||
WEND
|
||||
FEND
|
||||
```
|
||||
|
||||
### Interrupt Handlers
|
||||
|
||||
```c65
|
||||
WORD CONST IRQ_VECTOR = $0314
|
||||
WORD oldIRQ
|
||||
|
||||
FUNC installIRQ
|
||||
ASM
|
||||
sei // Disable interrupts
|
||||
ENDASM
|
||||
|
||||
oldIRQ = PEEKW IRQ_VECTOR
|
||||
POKEW IRQ_VECTOR WITH myIRQ
|
||||
|
||||
ASM
|
||||
cli // Enable interrupts
|
||||
ENDASM
|
||||
FEND
|
||||
|
||||
LABEL myIRQ
|
||||
// IRQ handler code
|
||||
ASM
|
||||
// Save registers
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
|
||||
// Do IRQ work
|
||||
inc $d020
|
||||
|
||||
// Restore and return
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rti
|
||||
ENDASM
|
||||
```
|
||||
|
||||
### Lookup Tables
|
||||
|
||||
Generate tables at compile time:
|
||||
|
||||
```c65
|
||||
ASM
|
||||
colorTable:
|
||||
ENDASM
|
||||
|
||||
SCRIPT
|
||||
colors = [0, 1, 15, 12, 11, 9, 2, 8]
|
||||
for c in colors:
|
||||
print(" !8 %d" % c)
|
||||
ENDSCRIPT
|
||||
```
|
||||
|
||||
### Delay Loops
|
||||
|
||||
```c65
|
||||
FUNC delay(frames)
|
||||
BYTE raster @ $D012
|
||||
BYTE oldRaster
|
||||
|
||||
WHILE frames > 0
|
||||
oldRaster = raster
|
||||
WHILE raster == oldRaster
|
||||
// Wait for raster to change
|
||||
WEND
|
||||
frames--
|
||||
WEND
|
||||
FEND
|
||||
```
|
||||
|
||||
### Bit Manipulation
|
||||
|
||||
```c65
|
||||
// Set bit
|
||||
flags = flags | %00000001 // Set bit 0
|
||||
|
||||
// Clear bit
|
||||
flags = flags & %11111110 // Clear bit 0
|
||||
|
||||
// Toggle bit
|
||||
flags = flags ^ %00000001 // Toggle bit 0
|
||||
|
||||
// Test bit
|
||||
IF flags & %00000001
|
||||
// Bit 0 is set
|
||||
ENDIF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Constants for Magic Numbers
|
||||
|
||||
```c65
|
||||
// Bad
|
||||
POKE $D020 WITH 5
|
||||
|
||||
// Good
|
||||
BYTE CONST COLOR_GREEN = 5
|
||||
BYTE borderColor @ $D020
|
||||
borderColor = COLOR_GREEN
|
||||
```
|
||||
|
||||
### 2. Zero Page for Performance
|
||||
|
||||
Place frequently accessed pointers in zero page ($00-$FF):
|
||||
|
||||
```c65
|
||||
WORD screenPtr @ $FB // Fast indexed access
|
||||
WORD tempPtr @ $FD
|
||||
```
|
||||
|
||||
### 3. Watch Expression Evaluation Order
|
||||
|
||||
Remember: left-to-right evaluation, no precedence!
|
||||
|
||||
```c65
|
||||
// Be careful with expressions
|
||||
result = 2 + 3 * 4 // = 20, not 14
|
||||
|
||||
// Use temps for clarity
|
||||
temp = 3 * 4
|
||||
result = 2 + temp // Now = 14
|
||||
```
|
||||
|
||||
### 4. Include Guards
|
||||
|
||||
Always use include guards in library files:
|
||||
|
||||
```c65
|
||||
#IFNDEF __MY_LIB
|
||||
#DEFINE __MY_LIB = 1
|
||||
|
||||
// Library code
|
||||
|
||||
#IFEND
|
||||
```
|
||||
|
||||
### 5. Comment Your Code
|
||||
|
||||
```c65
|
||||
// Explain what and why, not how
|
||||
FUNC calculateTrajectory(velocity, angle)
|
||||
// Use fixed-point math (8.8 format)
|
||||
// because we don't have floating point
|
||||
WORD xVel
|
||||
WORD yVel
|
||||
// ...
|
||||
FEND
|
||||
```
|
||||
|
||||
### 6. Use Meaningful Names
|
||||
|
||||
```c65
|
||||
// Bad
|
||||
BYTE x
|
||||
BYTE y
|
||||
|
||||
// Good
|
||||
BYTE playerXPos
|
||||
BYTE playerYPos
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Further Resources
|
||||
|
||||
- See `commands.md` for complete command reference
|
||||
- See `syntax.md` for detailed syntax rules
|
||||
- Check the `lib/` directory for example library code
|
||||
- Set `C65LIBPATH` environment variable to specify library search paths
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Card
|
||||
|
||||
```c65
|
||||
// Variables
|
||||
BYTE varName = 10
|
||||
WORD address = $C000
|
||||
BYTE CONST MAX = 100
|
||||
|
||||
// Control Flow
|
||||
IF x == 10
|
||||
// code
|
||||
ENDIF
|
||||
|
||||
WHILE x < 100
|
||||
x++
|
||||
WEND
|
||||
|
||||
FOR i = 0 TO 10
|
||||
// code
|
||||
NEXT
|
||||
|
||||
// Functions
|
||||
FUNC myFunc(in:param1, out:result)
|
||||
result = param1 + 1
|
||||
FEND
|
||||
|
||||
// Memory
|
||||
value = PEEK $D020
|
||||
POKE $D020 WITH 5
|
||||
address = PEEKW $FFFC
|
||||
POKEW $0314 WITH handler
|
||||
|
||||
// Operators
|
||||
+ - * / // Arithmetic
|
||||
& | ^ // Bitwise
|
||||
++ -- // Increment/Decrement
|
||||
== != < > <= >= // Comparison
|
||||
|
||||
// Blocks
|
||||
ASM
|
||||
// assembly code
|
||||
ENDASM
|
||||
|
||||
SCRIPT
|
||||
# Python code
|
||||
ENDSCRIPT
|
||||
```
|
||||
Loading…
Reference in a new issue