Fixed up docs to reflect reality and for examples to work.

This commit is contained in:
Mattias Hansson 2026-07-12 19:31:38 +02:00
parent 8087aafc32
commit 11cc5f220b
4 changed files with 106 additions and 49 deletions

View file

@ -39,7 +39,7 @@ c65gm compiles high-level source code into ACME assembler syntax for the 6502 pr
- **Functions**: Named functions with parameters and call graph analysis - **Functions**: Named functions with parameters and call graph analysis
- **Control flow**: IF/ENDIF, WHILE/WEND, FOR loops, SWITCH/CASE - **Control flow**: IF/ENDIF, WHILE/WEND, FOR loops, SWITCH/CASE
- **Memory operations**: PEEK/POKE/PEEKW/POKEW with zero-page optimization. Access registers as variables. - **Memory operations**: PEEK/POKE/PEEKW/POKEW with zero-page optimization. Access registers as variables.
- **Operators**: Arithmetic (ADD, SUB), bitwise (AND, OR, XOR) - **Operators**: Arithmetic (ADD, SUB), bitwise (AND, OR, XOR), shifts (SHL, SHR)
- **Preprocessor**: File inclusion, macros, conditional compilation, Starlark scripting - **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) - **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 - **Optimizations**: Constant folding, self-assignment detection

View file

@ -91,6 +91,7 @@ BREAK
``` ```
// BREAK in FOR loop // BREAK in FOR loop
BYTE i
FOR i = 0 TO 100 FOR i = 0 TO 100
IF i = 50 IF i = 50
BREAK BREAK
@ -242,7 +243,8 @@ See [FUNC](#func) for syntax and examples.
## FOR ## FOR
Loop with automatic counter increment. Loop with automatic counter increment. The iterator variable must be declared
beforehand.
**Syntax:** **Syntax:**
``` ```
@ -253,6 +255,7 @@ FOR <iterator> = <start_value> TO <end_value>
``` ```
// FOR loop with literal values // FOR loop with literal values
BYTE i
FOR i = 0 TO 10 FOR i = 0 TO 10
screen = i screen = i
NEXT NEXT
@ -260,6 +263,7 @@ NEXT
``` ```
// FOR loop with variables // FOR loop with variables
BYTE counter
FOR counter = start TO finish FOR counter = start TO finish
process(counter) process(counter)
NEXT NEXT

View file

@ -178,7 +178,13 @@ 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 value = 100-20+5 // Evaluates as (100-20)+5 = 85
``` ```
For complex expressions, use temporary variables: These multi-term forms are folded at compile time and only work when every
term is a literal or `CONST` (write them without spaces). `*` and `/` are
**only** available in these constant expressions, not on runtime variables.
Runtime expressions involving a variable perform exactly one operation and
must be space-separated (`dest = a + b`). For anything more complex, use
temporary variables:
```c65 ```c65
// Instead of: result = (b - c) + a // Instead of: result = (b - c) + a
@ -238,9 +244,10 @@ WEND
### FOR Loops ### FOR Loops
Loop with automatic counter: Loop with automatic counter. The loop variable must be declared beforehand:
```c65 ```c65
BYTE i
FOR i = 0 TO 10 FOR i = 0 TO 10
screen = i screen = i
NEXT NEXT
@ -255,6 +262,7 @@ NEXT
Exit a loop early: Exit a loop early:
```c65 ```c65
BYTE i
FOR i = 0 TO 100 FOR i = 0 TO 100
IF i == 50 IF i == 50
BREAK BREAK
@ -354,15 +362,17 @@ Read a byte from memory:
```c65 ```c65
value = PEEK $D020 // Read from absolute address value = PEEK $D020 // Read from absolute address
char = PEEK screenPtr[index] // Read with offset byte = PEEK pointer // Read through a WORD pointer
byte = PEEK pointer // Read from pointer
``` ```
**Important:** For indexed access, the address must be a WORD variable in zero page. **Indexed access:** Add `[offset]` to read at pointer+offset. The offset can
be a constant or a BYTE variable, and the pointer **must** be a WORD variable
in zero page:
```c65 ```c65
WORD buffer @ $FB // Zero-page pointer WORD buffer @ $FB // Zero-page pointer
value = PEEK buffer[10] // Read buffer+10 value = PEEK buffer[10] // Read buffer+10
char = PEEK buffer[index] // Read buffer+index
``` ```
### POKE - Writing Memory ### POKE - Writing Memory
@ -371,8 +381,18 @@ Write a byte to memory:
```c65 ```c65
POKE $D020, 0 // Write to absolute address POKE $D020, 0 // Write to absolute address
POKE screenPtr[index], char // Write with offset POKE pointer, value // Write through a WORD pointer
POKE pointer, value // Write to pointer ```
**Indexed access:** As with PEEK, `[offset]` requires a zero-page WORD
pointer. This is handy for reaching into structured data through a base
pointer:
```c65
WORD vic @ $FB
POINTER vic TO $D000 // VIC-II base register
POKE vic[$20], 2 // Write border color ($D020) = red
POKE vic[$21], 0 // Write background color ($D021) = black
``` ```
### PEEKW - Reading 16-bit Words ### PEEKW - Reading 16-bit Words
@ -393,7 +413,8 @@ Write a 16-bit value to memory:
```c65 ```c65
POKEW $0314, irqHandler // Set IRQ vector POKEW $0314, irqHandler // Set IRQ vector
POKEW dataPtr[0], address // Write word with offset POKEW dataPtr, address // Write word through a pointer
POKEW dataPtr[2], address // Write word at dataPtr+2 (zero-page pointer)
``` ```
### POINTER - Setting Pointers ### POINTER - Setting Pointers
@ -830,7 +851,7 @@ FEND
FUNC updateScreen FUNC updateScreen
BYTE color BYTE color
color = frameCount & $0F color = frameCount & $0F
POKE screenPtr[0], color POKE screenPtr, color
frameCount++ frameCount++
FEND FEND
@ -857,7 +878,7 @@ FUNC clearScreen
WORD remaining = 1000 WORD remaining = 1000
WHILE remaining > 0 WHILE remaining > 0
POKE screenPtr[0], 32 // Space character POKE screenPtr, 32 // Space character
screenPtr++ screenPtr++
remaining-- remaining--
WEND WEND
@ -870,7 +891,7 @@ FEND
// Print null-terminated string // Print null-terminated string
FUNC printString({WORD textPtr}) FUNC printString({WORD textPtr})
BYTE char BYTE char
char = PEEK textPtr[0] char = PEEK textPtr
WHILE char != 0 WHILE char != 0
ASM ASM
@ -878,7 +899,7 @@ FUNC printString({WORD textPtr})
jsr $FFD2 // CHROUT jsr $FFD2 // CHROUT
ENDASM ENDASM
textPtr++ textPtr++
char = PEEK textPtr[0] char = PEEK textPtr
WEND WEND
FEND FEND
``` ```
@ -893,10 +914,11 @@ BYTE spriteEnable @ VIC2+21
FUNC enableSprite({BYTE spriteNum}) FUNC enableSprite({BYTE spriteNum})
BYTE mask BYTE mask
BYTE i
mask = 1 mask = 1
FOR i = 0 TO spriteNum FOR i = 0 TO spriteNum
mask = mask * 2 mask = mask << 1
NEXT NEXT
spriteEnable = spriteEnable | mask spriteEnable = spriteEnable | mask
@ -908,14 +930,14 @@ FEND
For frequently accessed pointers, use zero page: For frequently accessed pointers, use zero page:
```c65 ```c65
WORD fastPtr @ $FB // Zero page = fast indexed access WORD fastPtr @ $FB // Zero page = fast pointer access
FUNC processBuffer({WORD buffer} {BYTE size}) FUNC processBuffer({WORD buffer} {BYTE size})
POINTER fastPtr TO buffer POINTER fastPtr TO buffer
WHILE size > 0 WHILE size > 0
BYTE value BYTE value
value = PEEK fastPtr[0] value = PEEK fastPtr
// Process value // Process value
fastPtr++ fastPtr++
size-- size--
@ -1012,11 +1034,6 @@ flags = flags & %11111110 // Clear bit 0
// Toggle bit // Toggle bit
flags = flags ^ %00000001 // Toggle bit 0 flags = flags ^ %00000001 // Toggle bit 0
// Test bit
IF flags & %00000001
// Bit 0 is set
ENDIF
``` ```
--- ---
@ -1049,12 +1066,14 @@ WORD tempPtr @ $FD
Remember: left-to-right evaluation, no precedence! Remember: left-to-right evaluation, no precedence!
```c65 ```c65
// Be careful with expressions // Constant expressions fold left-to-right at compile time.
result = 2 + 3 * 4 // = 20, not 14 // Write them without spaces:
result = 2+3*4 // = (2+3)*4 = 20, not 14
// Use temps for clarity // Runtime expressions (with variables) do ONE operation per
temp = 3 * 4 // statement and must be space-separated. Use temps to order them:
result = 2 + temp // Now = 14 temp = b + c
result = a + temp
``` ```
### 4. Include Guards ### 4. Include Guards
@ -1139,8 +1158,9 @@ address = PEEKW $FFFC
POKEW $0314, handler POKEW $0314, handler
// Operators // Operators
+ - * / // Arithmetic + - // Arithmetic (runtime + constants)
& | ^ // Bitwise * / // Multiply/Divide (constant expressions only)
& | ^ << >> // Bitwise / shift
++ -- // Increment/Decrement ++ -- // Increment/Decrement
== != < > <= >= // Comparison == != < > <= >= // Comparison

View file

@ -12,6 +12,7 @@ C65GM uses C-style line comments.
**Examples:** **Examples:**
``` ```
BYTE counter = 0 // Initialize counter BYTE counter = 0 // Initialize counter
BYTE i // Loop variable (must be declared)
// This is a full line comment // This is a full line comment
FOR i = 0 TO 10 // Loop through values FOR i = 0 TO 10 // Loop through values
counter++ // Increment counter++ // Increment
@ -623,15 +624,26 @@ $00
### Operators ### Operators
Evaluated strictly left to right: Evaluated strictly left to right (no precedence):
- `+` Addition - `+` Addition (runtime and constant expressions)
- `-` Subtraction - `-` Subtraction (runtime and constant expressions)
- `*` Multiplication - `*` Multiplication (constant expressions only)
- `/` Division - `/` Division (constant expressions only)
- `|` Bitwise OR - `|` Bitwise OR
- `&` Bitwise AND - `&` Bitwise AND
- `^` Bitwise XOR - `^` Bitwise XOR
- `<<` Shift left
- `>>` Shift right
There are two distinct expression forms:
- **Constant expressions** — written *without spaces* (e.g. `2+3*4`). Every
term must be a literal or a `CONST`; these are folded at compile time and
may chain any number of terms. `*` and `/` are only available here.
- **Runtime expressions** — written *with spaces* (e.g. `a + b`). These
perform exactly one operation, where at least one operand may be a variable.
Only `+ - & | ^ << >>` are supported; `*` and `/` are not.
### Constants ### Constants
@ -647,13 +659,20 @@ pointer = SCREEN
### Expression Examples ### Expression Examples
Constant expressions (no spaces, all terms literals or constants):
``` ```
value = 100+50 value = 100+50
result = $FF-10 result = $FF-10
address = $D000+32 address = $D000+32
mask = %11110000&$0F mask = %11110000&$0F
combined = BASE|OFFSET
calculated = START+LENGTH*2
```
Runtime expressions (spaces, one operation, may use variables):
```
combined = base | offset combined = base | offset
calculated = start+length*2 adjusted = value + count
``` ```
**Critical:** No operator precedence. Evaluation is strictly left to right: **Critical:** No operator precedence. Evaluation is strictly left to right:
@ -682,15 +701,22 @@ INC $D000+20
``` ```
FOR i = 0 TO MAX_VALUE-1 FOR i = 0 TO MAX_VALUE-1
IF x > THRESHOLD+10 IF x > THRESHOLD+10
POKE $D020+offset, value POKE $D020+OFFSET, value
result = PEEK $0400+index result = PEEK $0400+INDEX
``` ```
**Arithmetic operations:** **Arithmetic operations:**
Constant expressions (compile-time, all terms literal/CONST):
```
sum = VALUE1+VALUE2
adjusted = BASE+OFFSET
```
Runtime expressions (one operation, may use variables):
``` ```
sum = value1 + value2 sum = value1 + value2
product = base*factor adjusted = original + offset
adjusted = original+OFFSET
``` ```
### Limitations ### Limitations
@ -702,11 +728,15 @@ result = (a+b)*c
value = base+(offset*2) value = base+(offset*2)
``` ```
**No nested expressions in assignments:** **No multi-operation runtime expressions:**
``` ```
; NOT SUPPORTED: ; NOT SUPPORTED (more than one operation with variables):
x = y + z ; only single value or constant expression x = a + b + c ; chain of runtime operations
x = a+b ; constant expression (no spaces) OK if a,b are constants x = a + b * c ; ditto
; SUPPORTED:
x = y + z ; single runtime operation (one operator)
x = a+b ; constant expression (no spaces) if a,b are literals/CONST
``` ```
**Workaround for complex expressions:** **Workaround for complex expressions:**
@ -720,7 +750,10 @@ result = temp - c
Expressions without spaces are treated as constant expressions: Expressions without spaces are treated as constant expressions:
``` ```
value = 100+50 ; OK - constant expression value = 100+50 ; constant expression (folded at compile time)
value = 100 + 50 ; ERROR - not a simple assignment value = 100 + 50 ; single runtime operation (also OK)
value = MAX+10 ; OK if MAX is constant value = MAX+10 ; constant expression, OK if MAX is a constant
``` ```
The difference matters for chaining: `2+3*4` (no spaces) folds all terms at
compile time, while a spaced form allows only one operation.