Fixed up docs to reflect reality and for examples to work.
This commit is contained in:
parent
8087aafc32
commit
11cc5f220b
4 changed files with 106 additions and 49 deletions
|
|
@ -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
|
||||
- **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)
|
||||
- **Operators**: Arithmetic (ADD, SUB), bitwise (AND, OR, XOR), shifts (SHL, SHR)
|
||||
- **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
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ BREAK
|
|||
|
||||
```
|
||||
// BREAK in FOR loop
|
||||
BYTE i
|
||||
FOR i = 0 TO 100
|
||||
IF i = 50
|
||||
BREAK
|
||||
|
|
@ -242,7 +243,8 @@ See [FUNC](#func) for syntax and examples.
|
|||
|
||||
## FOR
|
||||
|
||||
Loop with automatic counter increment.
|
||||
Loop with automatic counter increment. The iterator variable must be declared
|
||||
beforehand.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
|
|
@ -253,6 +255,7 @@ FOR <iterator> = <start_value> TO <end_value>
|
|||
|
||||
```
|
||||
// FOR loop with literal values
|
||||
BYTE i
|
||||
FOR i = 0 TO 10
|
||||
screen = i
|
||||
NEXT
|
||||
|
|
@ -260,6 +263,7 @@ NEXT
|
|||
|
||||
```
|
||||
// FOR loop with variables
|
||||
BYTE counter
|
||||
FOR counter = start TO finish
|
||||
process(counter)
|
||||
NEXT
|
||||
|
|
|
|||
74
language.md
74
language.md
|
|
@ -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
|
||||
```
|
||||
|
||||
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
|
||||
// Instead of: result = (b - c) + a
|
||||
|
|
@ -238,9 +244,10 @@ WEND
|
|||
|
||||
### FOR Loops
|
||||
|
||||
Loop with automatic counter:
|
||||
Loop with automatic counter. The loop variable must be declared beforehand:
|
||||
|
||||
```c65
|
||||
BYTE i
|
||||
FOR i = 0 TO 10
|
||||
screen = i
|
||||
NEXT
|
||||
|
|
@ -255,6 +262,7 @@ NEXT
|
|||
Exit a loop early:
|
||||
|
||||
```c65
|
||||
BYTE i
|
||||
FOR i = 0 TO 100
|
||||
IF i == 50
|
||||
BREAK
|
||||
|
|
@ -354,15 +362,17 @@ 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
|
||||
byte = PEEK pointer // Read through a WORD 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
|
||||
WORD buffer @ $FB // Zero-page pointer
|
||||
value = PEEK buffer[10] // Read buffer+10
|
||||
char = PEEK buffer[index] // Read buffer+index
|
||||
```
|
||||
|
||||
### POKE - Writing Memory
|
||||
|
|
@ -371,8 +381,18 @@ Write a byte to memory:
|
|||
|
||||
```c65
|
||||
POKE $D020, 0 // Write to absolute address
|
||||
POKE screenPtr[index], char // Write with offset
|
||||
POKE pointer, value // Write to pointer
|
||||
POKE pointer, value // Write through a WORD 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
|
||||
|
|
@ -393,7 +413,8 @@ Write a 16-bit value to memory:
|
|||
|
||||
```c65
|
||||
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
|
||||
|
|
@ -830,7 +851,7 @@ FEND
|
|||
FUNC updateScreen
|
||||
BYTE color
|
||||
color = frameCount & $0F
|
||||
POKE screenPtr[0], color
|
||||
POKE screenPtr, color
|
||||
frameCount++
|
||||
FEND
|
||||
|
||||
|
|
@ -857,7 +878,7 @@ FUNC clearScreen
|
|||
|
||||
WORD remaining = 1000
|
||||
WHILE remaining > 0
|
||||
POKE screenPtr[0], 32 // Space character
|
||||
POKE screenPtr, 32 // Space character
|
||||
screenPtr++
|
||||
remaining--
|
||||
WEND
|
||||
|
|
@ -870,7 +891,7 @@ FEND
|
|||
// Print null-terminated string
|
||||
FUNC printString({WORD textPtr})
|
||||
BYTE char
|
||||
char = PEEK textPtr[0]
|
||||
char = PEEK textPtr
|
||||
|
||||
WHILE char != 0
|
||||
ASM
|
||||
|
|
@ -878,7 +899,7 @@ FUNC printString({WORD textPtr})
|
|||
jsr $FFD2 // CHROUT
|
||||
ENDASM
|
||||
textPtr++
|
||||
char = PEEK textPtr[0]
|
||||
char = PEEK textPtr
|
||||
WEND
|
||||
FEND
|
||||
```
|
||||
|
|
@ -893,10 +914,11 @@ BYTE spriteEnable @ VIC2+21
|
|||
|
||||
FUNC enableSprite({BYTE spriteNum})
|
||||
BYTE mask
|
||||
BYTE i
|
||||
mask = 1
|
||||
|
||||
FOR i = 0 TO spriteNum
|
||||
mask = mask * 2
|
||||
mask = mask << 1
|
||||
NEXT
|
||||
|
||||
spriteEnable = spriteEnable | mask
|
||||
|
|
@ -908,14 +930,14 @@ FEND
|
|||
For frequently accessed pointers, use zero page:
|
||||
|
||||
```c65
|
||||
WORD fastPtr @ $FB // Zero page = fast indexed access
|
||||
WORD fastPtr @ $FB // Zero page = fast pointer access
|
||||
|
||||
FUNC processBuffer({WORD buffer} {BYTE size})
|
||||
POINTER fastPtr TO buffer
|
||||
|
||||
WHILE size > 0
|
||||
BYTE value
|
||||
value = PEEK fastPtr[0]
|
||||
value = PEEK fastPtr
|
||||
// Process value
|
||||
fastPtr++
|
||||
size--
|
||||
|
|
@ -1012,11 +1034,6 @@ flags = flags & %11111110 // Clear bit 0
|
|||
|
||||
// Toggle bit
|
||||
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!
|
||||
|
||||
```c65
|
||||
// Be careful with expressions
|
||||
result = 2 + 3 * 4 // = 20, not 14
|
||||
// Constant expressions fold left-to-right at compile time.
|
||||
// Write them without spaces:
|
||||
result = 2+3*4 // = (2+3)*4 = 20, not 14
|
||||
|
||||
// Use temps for clarity
|
||||
temp = 3 * 4
|
||||
result = 2 + temp // Now = 14
|
||||
// Runtime expressions (with variables) do ONE operation per
|
||||
// statement and must be space-separated. Use temps to order them:
|
||||
temp = b + c
|
||||
result = a + temp
|
||||
```
|
||||
|
||||
### 4. Include Guards
|
||||
|
|
@ -1139,8 +1158,9 @@ address = PEEKW $FFFC
|
|||
POKEW $0314, handler
|
||||
|
||||
// Operators
|
||||
+ - * / // Arithmetic
|
||||
& | ^ // Bitwise
|
||||
+ - // Arithmetic (runtime + constants)
|
||||
* / // Multiply/Divide (constant expressions only)
|
||||
& | ^ << >> // Bitwise / shift
|
||||
++ -- // Increment/Decrement
|
||||
== != < > <= >= // Comparison
|
||||
|
||||
|
|
|
|||
67
syntax.md
67
syntax.md
|
|
@ -12,6 +12,7 @@ C65GM uses C-style line comments.
|
|||
**Examples:**
|
||||
```
|
||||
BYTE counter = 0 // Initialize counter
|
||||
BYTE i // Loop variable (must be declared)
|
||||
// This is a full line comment
|
||||
FOR i = 0 TO 10 // Loop through values
|
||||
counter++ // Increment
|
||||
|
|
@ -623,15 +624,26 @@ $00
|
|||
|
||||
### Operators
|
||||
|
||||
Evaluated strictly left to right:
|
||||
Evaluated strictly left to right (no precedence):
|
||||
|
||||
- `+` Addition
|
||||
- `-` Subtraction
|
||||
- `*` Multiplication
|
||||
- `/` Division
|
||||
- `+` Addition (runtime and constant expressions)
|
||||
- `-` Subtraction (runtime and constant expressions)
|
||||
- `*` Multiplication (constant expressions only)
|
||||
- `/` Division (constant expressions only)
|
||||
- `|` Bitwise OR
|
||||
- `&` Bitwise AND
|
||||
- `^` 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
|
||||
|
||||
|
|
@ -647,13 +659,20 @@ pointer = SCREEN
|
|||
|
||||
### Expression Examples
|
||||
|
||||
Constant expressions (no spaces, all terms literals or constants):
|
||||
```
|
||||
value = 100+50
|
||||
result = $FF-10
|
||||
address = $D000+32
|
||||
mask = %11110000&$0F
|
||||
combined = BASE|OFFSET
|
||||
calculated = START+LENGTH*2
|
||||
```
|
||||
|
||||
Runtime expressions (spaces, one operation, may use variables):
|
||||
```
|
||||
combined = base | offset
|
||||
calculated = start+length*2
|
||||
adjusted = value + count
|
||||
```
|
||||
|
||||
**Critical:** No operator precedence. Evaluation is strictly left to right:
|
||||
|
|
@ -682,15 +701,22 @@ INC $D000+20
|
|||
```
|
||||
FOR i = 0 TO MAX_VALUE-1
|
||||
IF x > THRESHOLD+10
|
||||
POKE $D020+offset, value
|
||||
result = PEEK $0400+index
|
||||
POKE $D020+OFFSET, value
|
||||
result = PEEK $0400+INDEX
|
||||
```
|
||||
|
||||
**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
|
||||
product = base*factor
|
||||
adjusted = original+OFFSET
|
||||
adjusted = original + offset
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
|
@ -702,11 +728,15 @@ result = (a+b)*c
|
|||
value = base+(offset*2)
|
||||
```
|
||||
|
||||
**No nested expressions in assignments:**
|
||||
**No multi-operation runtime expressions:**
|
||||
```
|
||||
; NOT SUPPORTED:
|
||||
x = y + z ; only single value or constant expression
|
||||
x = a+b ; constant expression (no spaces) OK if a,b are constants
|
||||
; NOT SUPPORTED (more than one operation with variables):
|
||||
x = a + b + c ; chain of runtime operations
|
||||
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:**
|
||||
|
|
@ -720,7 +750,10 @@ result = temp - c
|
|||
|
||||
Expressions without spaces are treated as constant expressions:
|
||||
```
|
||||
value = 100+50 ; OK - constant expression
|
||||
value = 100 + 50 ; ERROR - not a simple assignment
|
||||
value = MAX+10 ; OK if MAX is constant
|
||||
value = 100+50 ; constant expression (folded at compile time)
|
||||
value = 100 + 50 ; single runtime operation (also OK)
|
||||
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.
|
||||
Loading…
Reference in a new issue