c64bridge 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +17 -5
  2. package/data/assembly/assembly-spec.md +24 -0
  3. package/data/assembly/examples/video/hello_world.asm +39 -0
  4. package/data/basic/basic-pitfalls.md +236 -0
  5. package/data/basic/basic-spec.md +507 -198
  6. package/data/video/petscii-style-guide.md +105 -0
  7. package/data/video/sprite-charset-best-practices.md +292 -0
  8. package/dist/c64Client.js +1 -0
  9. package/dist/prompts/registry.js +10 -2
  10. package/dist/rag/knowledgeIndex.js +111 -24
  11. package/dist/rag/retriever.js +110 -4
  12. package/dist/tools/audio.js +26 -13
  13. package/dist/tools/developer.js +34 -0
  14. package/dist/tools/graphics.js +6 -5
  15. package/dist/tools/memory.js +1 -1
  16. package/dist/tools/pollValidator.js +256 -0
  17. package/dist/tools/programRunners.js +352 -12
  18. package/dist/tools/rag.js +1 -7
  19. package/doc/MCP_SETUP.md +7 -1
  20. package/doc/bun/baseline-metrics.md +16 -0
  21. package/doc/bun/migration-checklist.md +55 -0
  22. package/doc/bun/migration.md +83 -0
  23. package/doc/developer.md +72 -10
  24. package/doc/improve-knowledge/notes.md +29 -0
  25. package/doc/improve-knowledge/plan.md +28 -3
  26. package/doc/improve-knowledge/rollout.md +39 -5
  27. package/doc/meta-tools/README.md +101 -0
  28. package/doc/meta-tools/analysis.md +255 -0
  29. package/doc/{meta-tools.md → meta-tools/catalog.md} +2 -2
  30. package/doc/meta-tools/notes.md +174 -0
  31. package/doc/meta-tools/rollout.md +343 -0
  32. package/mcp.json +1 -1
  33. package/package.json +17 -10
  34. package/scripts/c64-cli.mjs +42 -7
  35. package/scripts/c64-tool.sh +7 -1
  36. package/scripts/check-node-compat.mjs +107 -0
  37. package/scripts/invoke-bun.mjs +58 -0
  38. package/scripts/rag-rebuild.mjs +11 -13
  39. package/scripts/run-mcp-check.sh +10 -2
  40. package/scripts/run-tests.mjs +3 -3
  41. package/scripts/run-tests.ts +187 -0
  42. package/scripts/start.mjs +3 -26
  43. package/scripts/update-readme.ts +17 -1
  44. package/scripts/verify-package.mjs +0 -1
  45. package/data/assembly/examples/effects/sinewave.asm +0 -5
  46. package/doc/meta-tools-rollout.md +0 -211
  47. package/scripts/register-ts-node.mjs +0 -6
  48. /package/data/assembly/examples/{graphics/sprite/mover.asm → video/sprite_mover.asm} +0 -0
@@ -1,49 +1,192 @@
1
- # C64 BASIC V2 Specification
1
+ # Commodore 64 BASIC V2 Specification
2
2
 
3
- ## Language
3
+ ## 1. Overview
4
4
 
5
- ### Overview
5
+ C64 BASIC V2 is a line-numbered, interpreted, tokenised language stored in ROM.
6
+ Each program consists of linked line records beginning at `$0801`, and executes sequentially unless redirected by explicit control flow. The interpreter manages variables, arrays, and strings in RAM regions immediately following the program text.
6
7
 
7
- C64 BASIC V2 is an interpreted language with line-numbered statements, tokenised keywords, and a limited variable model. Execution flows linearly unless redirected by control statements.
8
+ ---
9
+
10
+ ## 2. Memory and Program Layout
11
+
12
+ ### 2.1 System Pointers (Zero Page)
13
+
14
+ | Name | Address | Meaning |
15
+ |------|----------|----------|
16
+ | **TXTTAB** | `$002B–002C` | Start of BASIC text (default `$0801`) |
17
+ | **VARTAB** | `$002D–002E` | Start of variable table |
18
+ | **ARYTAB** | `$002F–0030` | Start of array storage |
19
+ | **STREND** | `$0031–0032` | End of arrays (+1) |
20
+ | **FRETOP** | `$0033–0034` | Bottom of string storage |
21
+ | **MEMSIZ** | `$0037–0038` | Highest BASIC RAM address |
22
+
23
+ Variables grow upward from `TXTTAB`; strings grow downward from `MEMSIZ`.
24
+ `ARYTAB` always follows `VARTAB`; defining new scalars after arrays shifts array memory upward by 7 bytes per variable.
25
+
26
+ ---
27
+
28
+ ### 2.2 BASIC Program Storage (PRG Format)
29
+
30
+ Each BASIC program in memory (and on disk/tape) is a contiguous block:
8
31
 
9
- ### Variable Types
32
+ | Field | Size | Description |
33
+ |--------|------|-------------|
34
+ | Load address | 2 bytes | `$0801` little-endian |
35
+ | Next line pointer | 2 bytes | Absolute address of next line |
36
+ | Line number | 2 bytes | 0–65535 |
37
+ | Tokenised PETSCII text | variable | Zero-terminated statement list |
38
+ | Terminator | 2 bytes | Final `$0000` sentinel |
39
+
40
+ Pointers increase monotonically. The final record’s pointer references the terminator.
41
+ Tokenisation replaces keywords by single-byte codes (`$80–$CB`), ignoring quoted strings and `REM` comments. Empty lines are stored as a single `$20` (space).
42
+
43
+ ---
44
+
45
+ ## 3. Variables and Data Model
46
+
47
+ ### 3.1 Variable Types
48
+
49
+ All variables occupy **7 bytes** in the variable table.
50
+ The first two bytes encode the name and type; the remaining bytes store the data or descriptor.
10
51
 
11
52
  | Type | Suffix | Range | Storage | Notes |
12
53
  |------|---------|--------|----------|-------|
13
- | **Real (Float)** | none | ±2.9×10⁻³⁸ … ±1.7×10³⁸ | 5 bytes (1 exp, 4 mantissa) | Default type. |
14
- | **Integer** | `%` | −32768 … 32767 | 2 bytes | Converted from float on assignment, slower. |
15
- | **String** | `$` | 0–255 chars | 3-byte descriptor | Holds PETSCII text. |
54
+ | **Real (Float)** | none | ±2.9×10⁻³⁸ … ±1.7×10³⁸ | 1-byte exponent + 4-byte mantissa | Default numeric type, ≈9.6-digit precision. |
55
+ | **Integer** | `%` | −32768 … 32767 | 2 bytes (hi-lo) | High bit set on both name bytes; slower than float due to conversion. |
56
+ | **String** | `$` | 0–255 chars | 1-byte length + 2-byte pointer | High bit set on second name byte; pointer references PETSCII data. |
57
+ | **Boolean** | — | `0` (FALSE), `−1` or any non-zero (TRUE) | Numeric representation | Implemented via integers. |
16
58
 
17
- Booleans are represented numerically: `FALSE=0`, `TRUE=−1` or any non-zero value.
59
+ #### Name Encoding
18
60
 
19
- ### Variable Naming
61
+ - Only first two letters significant (`CO`, `COCOS` → same variable).
62
+ - Letters A–Z, digits 0–9; must start with a letter.
63
+ - Case-insensitive; stored uppercase.
64
+ - Type suffix distinguishes variants (`A`, `A%`, `A$`).
65
+ - Reserved names: `ST`, `TI`, `TI$`, `FN`, and all keywords.
66
+ - Max name length ≈ 80 characters (logical line length).
20
67
 
21
- - Only the **first two letters** of a name are significant (`CO`, `COCOS` → same variable).
22
- - Type suffix (`%`, `$`) distinguishes otherwise identical names.
23
- - Allowed: `A–Z`, `0–9`; must start with a letter.
24
- - Keywords and system variables (`ST`, `TI`, `TI$`, `FN`) are reserved.
25
- - Maximum logical name length ≈80 characters.
68
+ **Example collision:**
26
69
 
27
- ### Arrays
70
+ ```
71
+ 10 A$="1":AA$="2":AAA$="3":PRINT A$,AA$,AAA$
72
+ → 1 3 3
73
+ ```
74
+
75
+ ---
76
+
77
+ ### 3.2 Internal Representation
78
+
79
+ | Offset | Field | Description |
80
+ |--------:|--------|-------------|
81
+ | 0–1 | Name (2 chars) with high bits as type markers | Identifier |
82
+ | 2–6 | Data payload | Depends on type |
83
+
84
+ **Encoding rules:**
85
+
86
+ - *Real*: ASCII name, 2nd byte zero if single char.
87
+ - *Integer*: both name bytes have high-bit set.
88
+ - *String*: only 2nd byte has high-bit set.
89
+
90
+ **Payload:**
91
+
92
+ - Real: exponent + mantissa (5 bytes).
93
+ - Integer: 2-byte value, 3 bytes padding 0.
94
+ - String: length (1 byte), pointer (2 bytes LE), padding 0s.
95
+
96
+ ---
97
+
98
+ ### 3.3 Arrays
99
+
100
+ Declared via `DIM`, e.g. `DIM A(7)` (indices 0–7).
101
+ If a program uses an array without prior `DIM`, BASIC auto-DIMs it to 11 elements per dimension (0–10).
102
+ Re-DIMing → `?REDIM'D ARRAY ERROR`.
103
+ Index < 0 or > 32767 → `?ILLEGAL QUANTITY ERROR`.
104
+
105
+ #### Internal Layout
106
+
107
+ ```
108
+ name(2) , offset_to_next(2) , dimensions(1) ,
109
+ length1(2) [, length2(2)...] , data...
110
+ ```
28
111
 
29
- Declared via `DIM`, e.g. `DIM A(7)` (indices 0–7). Multi-dimensional arrays are supported (`DIM B$(4,5)`).
112
+ - Offset is relative to next array (for relocation).
113
+ - `dimensions` = number of axes (1–255 theoretical).
114
+ - Each element stored in ascending index order; leftmost index varies fastest.
115
+ - Element sizes: Real 5 B, Integer 2 B, String 3 B descriptor.
30
116
 
31
- ### Operators and Precedence
117
+ **Examples:**
118
+
119
+ ```
120
+ DIM C%(2,3) → 3×4 = 12 integers
121
+ DIM S$(1,2,3) → 2×3×4 = 24 string descriptors
122
+ ```
123
+
124
+ ---
125
+
126
+ ### 3.4 Strings
127
+
128
+ Strings hold PETSCII text of up to 255 chars.
129
+ The descriptor’s pointer targets either:
130
+
131
+ - an in-place literal within BASIC text (for quoted constants), or
132
+ - an allocated region in the **string heap** (descending from `FRETOP`).
133
+
134
+ New strings are created whenever:
135
+
136
+ - concatenation (`+`),
137
+ - substring (`LEFT$`, `MID$`, `RIGHT$`),
138
+ - or runtime expression evaluation occurs.
139
+
140
+ No garbage collection exists. `CLR` or `NEW` frees all strings.
141
+
142
+ **Efficiency notes**
143
+
144
+ - Prefer `PRINT A$;B$` instead of `PRINT A$+B$` (no new allocation).
145
+ - Define and reuse variables to prevent heap growth.
146
+ - Direct-mode string operations always allocate temporary strings.
147
+
148
+ **Advanced manipulation:**
149
+ By modifying the descriptor at `VARTAB` (length and pointer), one can create scrolling or “windowed” text effects without copying data.
150
+
151
+ ---
152
+
153
+ ### 3.5 Variable Optimisation Guidelines
154
+
155
+ - Declare scalar variables before arrays (avoids array shifting).
156
+ - Use short two-character names for speed.
157
+ - Avoid redundant `LET`.
158
+ - Keep string operations minimal in loops.
159
+ - Use `FRE(0)` to inspect available memory (16-bit signed).
160
+ - To locate start of variable table:
161
+
162
+ ```
163
+ VT = PEEK(46)*256 + PEEK(45)
164
+ ```
165
+
166
+ ---
167
+
168
+ ## 4. Operators
32
169
 
33
170
  | Rank | Operators | Description |
34
171
  |------|------------|-------------|
35
172
  | 1 | `^` | Exponentiation |
36
- | 2 | unary `+` `-` | Sign |
37
- | 3 | `*` `/` | Multiplication, Division |
38
- | 4 | `+` `-` | Addition, Subtraction, String concat |
39
- | 5 | `<` `<=` `=` `>=` `>` `<>` | Comparison |
40
- | 6 | `NOT` | Logical NOT |
41
- | 7 | `AND` | Logical AND |
42
- | 8 | `OR` | Logical OR |
173
+ | 2 | unary `+ −` | Sign prefix |
174
+ | 3 | `* /` | Multiplication / Division |
175
+ | 4 | `+ −` | Addition, Subtraction, String concatenation |
176
+ | 5 | `< <= = >= > <>` | Comparison |
177
+ | 6 | `NOT` | Logical NOT / bitwise invert |
178
+ | 7 | `AND` | Logical AND / bitwise AND |
179
+ | 8 | `OR` | Logical OR / bitwise OR |
180
+
181
+ Parentheses nest ≤ 10 levels.
182
+ Division by 0 → `?DIVISION BY ZERO`.
183
+ Logical ops on integers act bitwise on 16-bit values.
184
+
185
+ ---
43
186
 
44
- Parentheses may nest up to 10 levels. Logical operators can also perform bitwise operations on 16‑bit integers.
187
+ ## 5. Syntax Definition (EBNF)
45
188
 
46
- ### Syntax Definition (EBNF)
189
+ *(Complete grammar retained for program analysis)*
47
190
 
48
191
  ```
49
192
  program = { line }, endmarker ;
@@ -51,180 +194,346 @@ line = nextptr word , lineno word , stmtlist , 0x00 ;
51
194
  stmtlist = statement , { ":" , statement } ;
52
195
 
53
196
  statement =
54
- "REM" , { <any PETSCII except CR> } |
55
- "FOR" , var , "=" , expr , "TO" , expr , [ "STEP" , expr ] |
56
- "NEXT" , [ var ] |
57
- "IF" , expr , "THEN" , ( stmtlist | lineno ) |
58
- ( "GOTO" | "GO" , "TO" ) , lineno |
59
- "GOSUB" , lineno | "RETURN" |
60
- "ON" , expr , ( "GOTO" | "GOSUB" ) , lineno , { "," , lineno } |
61
- "DEF" , "FN" , fnname , "(" , var , ")" , "=" , expr |
62
- "INPUT" , [ prompt ] , varlist | "GET" , var | "PRINT" , [ printlist ] |
63
- "OPEN" , expr , "," , expr , [ "," , expr , [ "," , fnameMode ] ] |
64
- "CLOSE" , expr | "CMD" , expr , [ "," , exprlist ] |
65
- "LOAD" , fname [ "," , dev [ "," , secdev ] ] |
66
- "SAVE" , fname [ "," , dev [ "," , secdev ] ] |
67
- "VERIFY" , fname [ "," , dev [ "," , secdev ] ] |
68
- "READ" , varlist | "RESTORE" | "DATA" , datalist |
69
- "POKE" , expr , "," , expr | "PEEK" , "(" , expr , ")" |
70
- "WAIT" , expr , "," , expr , [ "," , expr ] |
71
- "SYS" , expr , { "," , expr } | var , "=" , expr |
72
- "USR" , "(" , expr , ")" |
73
- "RUN" , [ lineno ] | "STOP" | "END" | "CONT" |
74
- "LIST" , [ listRange ] | "NEW" | "CLR" |
75
- "FRE" , "(" , expr , ")" ;
76
-
77
- expr = term , { "OR" , term } ;
78
- term = factor , { "AND" , factor } ;
79
- factor = [ "NOT" ] , relation ;
80
- relation = sum , { ( "=" | "<" | ">" | "<=" | ">=" | "<>" ) , sum } ;
81
- sum = product , { ( "+" | "-" ) , product } ;
82
- product = power , { ( "*" | "/" ) , power } ;
83
- power = unary , { "^" , unary } ;
84
- unary = [ "+" | "-" ] , primary ;
85
- primary = number | string | var | fncall | "(" , expr , ")" ;
86
-
87
- fncall = ( "SGN" | "INT" | "ABS" | "USR" | "FRE" | "POS" | "SQR" | "RND" |
88
- "LOG" | "EXP" | "COS" | "SIN" | "TAN" | "ATN" | "PEEK" | "LEN" |
89
- "STR$" | "VAL" | "ASC" | "CHR$" | "LEFT$" | "RIGHT$" | "MID$" |
90
- "TAB" | "SPC" ), "(" , [ expr , { "," , expr } ] , ")" ;
91
-
92
- printlist = [ expr | "#" , expr ] , { "," | ";" , [ expr | "#" , expr ] } ;
93
- varlist = var , { "," , var } ;
94
- datalist = datum , { "," , datum } ;
95
- datum = number | string | expr ;
96
-
97
- fname = string ; dev = expr ; secdev = expr ; fnameMode = string ;
98
- lineno = 0..65535 ;
99
- var = name [ "%" | "$" ] ; fnname = "FN" , name ;
100
- name = letter , { letter | digit } ;
101
- prompt = string , ";" ;
102
- listRange = lineno | "-" , lineno | lineno , "-" ;
103
- number = integer | float ; string = quoted PETSCII ;
197
+ "REM" , { <any PETSCII except CR> } |
198
+ "FOR" , var , "=" , expr , "TO" , expr , [ "STEP" , expr ] |
199
+ "NEXT" , [ var ] |
200
+ "IF" , expr , "THEN" , ( stmtlist | lineno ) |
201
+ ( "GOTO" | "GO" , "TO" ) , lineno |
202
+ "GOSUB" , lineno | "RETURN" |
203
+ "ON" , expr , ( "GOTO" | "GOSUB" ) , lineno , { "," , lineno } |
204
+ "DEF" , "FN" , fnname , "(" , var , ")" , "=" , expr |
205
+ "INPUT" , [ prompt ] , varlist | "GET" , var | "PRINT" , [ printlist ] |
206
+ "OPEN" , expr , "," , expr , [ "," , expr , [ "," , fnameMode ] ] |
207
+ "CLOSE" , expr | "CMD" , expr , [ "," , exprlist ] |
208
+ "LOAD" , fname [ "," , dev [ "," , secdev ] ] |
209
+ "SAVE" , fname [ "," , dev [ "," , secdev ] ] |
210
+ "VERIFY" , fname [ "," , dev [ "," , secdev ] ] |
211
+ "READ" , varlist | "RESTORE" | "DATA" , datalist |
212
+ "POKE" , expr , "," , expr | "PEEK" , "(" , expr , ")" |
213
+ "WAIT" , expr , "," , expr , [ "," , expr ] |
214
+ "SYS" , expr , { "," , expr } | var , "=" , expr |
215
+ "USR" , "(" , expr , ")" |
216
+ "RUN" , [ lineno ] | "STOP" | "END" | "CONT" |
217
+ "LIST" , [ listRange ] | "NEW" | "CLR" |
218
+ "FRE" , "(" , expr , ")" ;
219
+
220
+ expr = term , { "OR" , term } ;
221
+ term = factor , { "AND" , factor } ;
222
+ factor= [ "NOT" ] , relation ;
223
+ relation = sum , { ( "=" | "<" | ">" | "<=" | ">=" | "<>" ) , sum } ;
224
+ sum = product , { ( "+" | "-" ) , product } ;
225
+ product = power , { ( "*" | "/" ) , power } ;
226
+ power = unary , { "^" , unary } ;
227
+ unary = [ "+" | "-" ] , primary ;
228
+ primary = number | string | var | fncall | "(" , expr , ")" ;
229
+
230
+ fncall = ( "SGN" | "INT" | "ABS" | "USR" | "FRE" | "POS" | "SQR" | "RND" |
231
+ "LOG" | "EXP" | "COS" | "SIN" | "TAN" | "ATN" | "PEEK" | "LEN" |
232
+ "STR$" | "VAL" | "ASC" | "CHR$" | "LEFT$" | "RIGHT$" | "MID$" |
233
+ "TAB" | "SPC" ), "(" , [ expr , { "," , expr } ] , ")" ;
104
234
  ```
105
235
 
106
- ### Commands and Functions
236
+ ---
237
+
238
+ ## 6. Commands and Functions
239
+
240
+ **Flow Control**
241
+ `FOR–TO–STEP–NEXT`, `IF–THEN`, `GOTO`, `GOSUB`, `RETURN`, `ON–GOTO/GOSUB`, `DEF FN`.
242
+
243
+ **Input/Output**
244
+ `INPUT`, `INPUT#`, `GET`, `PRINT`, `PRINT#`, `SPC(n)`, `TAB(n)`, `POS()`.
245
+
246
+ **File Operations**
247
+ `LOAD`, `SAVE`, `VERIFY`, `OPEN`, `CLOSE`, `CMD`, `ST`.
248
+
249
+ **Data Access**
250
+ `DATA`, `READ`, `RESTORE`.
251
+
252
+ **Math / Logic**
253
+ `ABS`, `ATN`, `COS`, `EXP`, `INT`, `LOG`, `RND`, `SGN`, `SIN`, `SQR`, `TAN`;
254
+ Operators `+ − * / ^ AND OR NOT`.
255
+
256
+ **String Processing**
257
+ `LEN`, `LEFT$`, `RIGHT$`, `MID$`, `STR$`, `VAL`, `ASC`, `CHR$`, `+` (concat).
107
258
 
108
- - **Flow:** `FOR…TO…[STEP…]…NEXT [var]`, `IF expr THEN (stmts|line)`, `GOTO`, `GO TO`, `GOSUB`, `RETURN`, `ON expr GOTO/GOSUB`, `DEF FN name(x)=expr`
109
- - **I/O:** `GET var$`, `INPUT ["prompt";] var[,var…]`, `PRINT [items]`, `SPC(n)`, `TAB(n)`, `POS(dummy)`
110
- - **Files:** `LOAD`, `SAVE`, `VERIFY`, `OPEN`, `CLOSE`, `GET#`, `INPUT#`, `PRINT#`, `CMD`, `ST`
111
- - **DATA:** `DATA`, `READ`, `RESTORE`
112
- - **Math/Logic:** `+ - * / ^`, comparisons, `AND OR NOT`; `SGN INT ABS RND SQR LOG EXP SIN COS TAN ATN`
113
- - **Strings:** `+` (concat), `LEN LEFT$ RIGHT$ MID$ STR$ VAL ASC CHR$`
114
- - **Memory:** `PEEK(addr)`, `POKE addr,val`, `WAIT addr,mask[,invert]`
115
- - **System:** `SYS addr[,p…]`, `USR(expr)` (fixed $0310)
116
- - **Execution:** `RUN [line]`, `STOP`, `END`, `CONT`
117
- - **Misc:** `REM`, `LIST`, `NEW`, `CLR`, `FRE(0)`, constants `π`, timers `TI`, `TI$`
259
+ **Memory / System**
260
+ `PEEK`, `POKE`, `WAIT`, `SYS`, `USR`.
261
+
262
+ **Program Control**
263
+ `RUN`, `STOP`, `END`, `CONT`, `NEW`, `CLR`, `LIST`, `FRE(0)`.
264
+
265
+ Constants: `π`, `TI`, `TI$`.
266
+
267
+ ---
268
+
269
+ ## 7. Keywords and Abbreviations (BASIC V2)
270
+
271
+ | Hex | Keyword | Abbrev. | Keystroke | Description |
272
+ |------|----------|----------|------------|-------------|
273
+ | 80 | END | eN | E + Shift-N | End program |
274
+ | 81 | FOR | fO | F + Shift-O | Loop start |
275
+ | 82 | NEXT | nE | N + Shift-E | Loop end |
276
+ | 83 | DATA | dA | D + Shift-A | Literal data |
277
+ | 84 | INPUT# | iN | I + Shift-N | File input |
278
+ | 85 | INPUT | — | — | Keyboard input |
279
+ | 86 | DIM | dI | D + Shift-I | Array declaration |
280
+ | 87 | READ | rE | R + Shift-E | Read DATA |
281
+ | 88 | LET | lE | L + Shift-E | Assignment |
282
+ | 89 | GOTO | gO | G + Shift-O | Branch |
283
+ | 8A | RUN | rU | R + Shift-U | Execute program |
284
+ | 8B | IF | — | — | Conditional |
285
+ | 8C | RESTORE | reS | R,E + Shift-S | Reset DATA pointer |
286
+ | 8D | GOSUB | goS | G,O + Shift-S | Subroutine |
287
+ | 8E | RETURN | reT | R,E + Shift-T | Return |
288
+ | 8F | REM | — | — | Comment |
289
+ | 90 | STOP | sT | S + Shift-T | Halt |
290
+ | 91 | ON | — | — | Indexed branch |
291
+ | 92 | WAIT | wA | W + Shift-A | Wait for mask |
292
+ | 93 | LOAD | lO | L + Shift-O | Load file |
293
+ | 94 | SAVE | sA | S + Shift-A | Save file |
294
+ | 95 | VERIFY | vE | V + Shift-E | Verify file |
295
+ | 96 | DEF | dE | D + Shift-E | Define FN |
296
+ | 97 | POKE | pO | P + Shift-O | Write memory |
297
+ | 98 | PRINT# | pR | P + Shift-R | Output to file |
298
+ | 99 | PRINT | ? | ? key | Output to screen |
299
+ | 9A | CONT | cO | C + Shift-O | Continue |
300
+ | 9B | LIST | lI | L + Shift-I | List program |
301
+ | 9C | CLR | cL | C + Shift-L | Clear vars |
302
+ | 9D | CMD | cM | C + Shift-M | Redirect output |
303
+ | 9E | SYS | sY | S + Shift-Y | Call machine code |
304
+ | 9F | OPEN | oP | O + Shift-P | Open device |
305
+ | A0 | CLOSE | clO | C,L + Shift-O | Close device |
306
+ | A1 | GET | gE | G + Shift-E | Read char |
307
+ | A2 | NEW | — | — | Clear program |
308
+ | A3 | TAB( | tA | T + Shift-A | Tab cursor |
309
+ | A4 | TO | — | — | Range keyword |
310
+ | A5 | FN | — | — | Function prefix |
311
+ | A6 | SPC( | sP | S + Shift-P | Space in print |
312
+ | A7 | THEN | tH | T + Shift-H | IF branch |
313
+ | A8 | NOT | nO | N + Shift-O | Logical NOT |
314
+ | A9 | STEP | stE | S,T + Shift-E | Loop increment |
315
+ | AF | AND | aN | A + Shift-N | Logical AND |
316
+ | B0 | OR | — | — | Logical OR |
317
+ | B4 | SGN | sG | S + Shift-G | Sign |
318
+ | B5 | INT | — | — | Integer truncation |
319
+ | B6 | ABS | aB | A + Shift-B | Absolute |
320
+ | B7 | USR | uS | U + Shift-S | User routine |
321
+ | B8 | FRE | fR | F + Shift-R | Free memory |
322
+ | B9 | POS | — | — | Cursor position |
323
+ | BA | SQR | sQ | S + Shift-Q | Square root |
324
+ | BB | RND | rN | R + Shift-N | Random number |
325
+ | BC | LOG | — | — | Natural log |
326
+ | BD | EXP | eX | E + Shift-X | Exponent |
327
+ | BE | COS | — | — | Cosine |
328
+ | BF | SIN | sI | S + Shift-I | Sine |
329
+ | C0 | TAN | — | — | Tangent |
330
+ | C1 | ATN | aT | A + Shift-T | Arctangent |
331
+ | C2 | PEEK | pE | P + Shift-E | Read memory |
332
+ | C3 | LEN | — | — | String length |
333
+ | C4 | STR$ | stR | S,T + Shift-R | Number→String |
334
+ | C5 | VAL | vA | V + Shift-A | String→Number |
335
+ | C6 | ASC | aS | A + Shift-S | ASCII code |
336
+ | C7 | CHR$ | cH | C + Shift-H | Code→Char |
337
+ | C8 | LEFT$ | leF | L,E + Shift-F | Left substring |
338
+ | C9 | RIGHT$ | rI | R + Shift-I | Right substring |
339
+ | CA | MID$ | mI | M + Shift-I | Middle substring |
340
+ | CB | GO | — | — | Used for GOTO/GOSUB |
341
+
342
+ ---
343
+
344
+ ## 8. System Constants and Status
345
+
346
+ | Name | Meaning | Typical Range |
347
+ |------|----------|----------------|
348
+ | `PI` | 3.14159265 | Constant |
349
+ | `ST` | Device status byte | Bit6=EOF, Bit7=No device |
350
+ | `TI` | System tick counter | 1/60s resolution |
351
+ | `TI$` | Time string | "hhmmss" |
352
+ | `FRE(0)` | Free memory in bytes | 0–38911 |
353
+ | `TRUE` | −1 ($FFFF) | Boolean |
354
+ | `FALSE` | 0 | Boolean |
118
355
 
119
356
  ---
120
357
 
121
- ## Tokenization
122
-
123
- ### Encoding Rules
124
-
125
- - Keywords occupy **$80–$CB**; single‑byte tokens replace text during encoding.
126
- - Tokenisation **skips inside** strings (`"..."`) and remarks (`REM`).
127
- - Matching is **greedy**, **case‑insensitive**; e.g. `PRINT#` before `PRINT`.
128
- - If a line becomes empty, insert a single space (`$20`).
129
- - Characters are written as **PETSCII**, with identifiers uppercased; strings/comments unchanged.
130
-
131
- ### Keyword Table
132
-
133
- | Hex | Keyword | Notes |
134
- |------|----------|-------|
135
- | 80 | END | |
136
- | 81 | FOR | |
137
- | 82 | NEXT | |
138
- | 83 | DATA | |
139
- | 84 | INPUT# | |
140
- | 85 | INPUT | |
141
- | 86 | DIM | |
142
- | 87 | READ | |
143
- | 88 | LET | Optional |
144
- | 89 | GOTO | |
145
- | 8A | RUN | |
146
- | 8B | IF | |
147
- | 8C | RESTORE | |
148
- | 8D | GOSUB | |
149
- | 8E | RETURN | |
150
- | 8F | REM | De-tokenises remainder |
151
- | 90 | STOP | |
152
- | 91 | ON | |
153
- | 92 | WAIT | |
154
- | 93 | LOAD | |
155
- | 94 | SAVE | |
156
- | 95 | VERIFY | |
157
- | 96 | DEF | |
158
- | 97 | POKE | |
159
- | 98 | PRINT# | |
160
- | 99 | PRINT | |
161
- | 9A | CONT | |
162
- | 9B | LIST | |
163
- | 9C | CLR | |
164
- | 9D | CMD | |
165
- | 9E | SYS | |
166
- | 9F | OPEN | |
167
- | A0 | CLOSE | |
168
- | A1 | GET | |
169
- | A2 | NEW | |
170
- | A3 | TAB( | |
171
- | A4 | TO | |
172
- | A5 | FN | |
173
- | A6 | SPC( | |
174
- | A7 | THEN | |
175
- | A8 | NOT | |
176
- | A9 | STEP | |
177
- | AA | + | |
178
- | AB | - | |
179
- | AC | * | |
180
- | AD | / | |
181
- | AE | ^ | |
182
- | AF | AND | |
183
- | B0 | OR | |
184
- | B1 | > | |
185
- | B2 | = | |
186
- | B3 | < | |
187
- | B4 | SGN | |
188
- | B5 | INT | |
189
- | B6 | ABS | |
190
- | B7 | USR | |
191
- | B8 | FRE | |
192
- | B9 | POS | |
193
- | BA | SQR | |
194
- | BB | RND | |
195
- | BC | LOG | |
196
- | BD | EXP | |
197
- | BE | COS | |
198
- | BF | SIN | |
199
- | C0 | TAN | |
200
- | C1 | ATN | |
201
- | C2 | PEEK | |
202
- | C3 | LEN | |
203
- | C4 | STR$ | |
204
- | C5 | VAL | |
205
- | C6 | ASC | |
206
- | C7 | CHR$ | |
207
- | C8 | LEFT$ | |
208
- | C9 | RIGHT$ | |
209
- | CA | MID$ | |
210
- | CB | GO | For GO TO / GO SUB |
211
-
212
- ### PRG Layout
213
-
214
- Each BASIC program is stored as a contiguous memory block starting at `$0801`:
215
-
216
- 1. **Load address** `$0801` (little‑endian).
217
- 2. Repeated **line records**:
218
- - Pointer to next line (absolute address, word LE)
219
- - Line number (word LE)
220
- - Tokenised bytes ending with `00`
221
- 3. Final **terminator word `0000`**.
222
-
223
- Pointers increase monotonically. The last line points to the terminator.
224
-
225
- ### Validation Rules
226
-
227
- - Line numbers `0–65535` only.
228
- - Final sentinel `0000` required.
229
- - `ST` bits: 6 = EOF, 7 = Device not present.
230
- - `RND(seed<0)` re‑initialises RNG; `RND(0)` continues sequence.
358
+ ## 9. Validation Rules
359
+
360
+ - Line numbers: 0–65535.
361
+ - Each program ends with `$0000` sentinel.
362
+ - Parentheses depth ≤10.
363
+ - Array redefinition prohibited.
364
+ - Division by zero → runtime error.
365
+ - Out-of-memory or string overflow → `?OUT OF MEMORY`.
366
+ - Keyword collision in variable name → `?SYNTAX ERROR`.
367
+
368
+ ---
369
+
370
+ ## 10. Performance and Optimisation Guidelines
371
+
372
+ C64 BASIC V2 is fully interpreted and float-based. Optimise by reducing parsing, conversions, and heap movement. Every line lookup and variable access incurs cost; fast programs minimise interpreter work.
373
+
374
+ ### 10.1 Execution Model
375
+
376
+ - Each line is linked; `GOTO`, `GOSUB`, `IF` search from start. Keep hot loops in low line numbers.
377
+ - Keywords are tokenised; variables and literals parsed at runtime.
378
+ - Numeric work is float unless explicitly integer; type conversions are slow.
379
+
380
+ ### 10.2 Variables
381
+
382
+ - Only first two name letters count—use short names.
383
+ - Define scalars before arrays; new scalars shift arrays by 7 B each.
384
+ - Floats faster than integers; mixed arithmetic incurs conversion.
385
+ - `FRE(0)` scans all variables—use sparingly.
386
+ - Use 0 and −1 for Boolean logic.
387
+
388
+ ### 10.3 Arrays
389
+
390
+ - Always `DIM`; undeclared arrays auto-DIM 11 elements per dimension.
391
+ - Re-DIM → error; index 0–32767 only.
392
+ - Keep dimensions small and fixed; leftmost index varies fastest.
393
+
394
+ ### 10.4 Arithmetic
395
+
396
+ - Replace `^` with multiplication; pre-compute constants and function results.
397
+ - `INT(X)` faster than truncation math; avoid mixing ints/floats.
398
+ - Keep loops tight; each iteration re-parses expressions.
399
+
400
+ ### 10.5 Strings
401
+
402
+ - Heap grows downward, no garbage collection.
403
+ - Avoid `A$=A$+B$` in loops; prefer `PRINT A$;B$`.
404
+ - Reuse string vars; overwrite via `MID$` instead of reallocating.
405
+ - Use `CLR` to reclaim heap; `LEFT$/RIGHT$/MID$` create new descriptors—use sparingly.
406
+
407
+ ### 10.6 Control Flow
408
+
409
+ - Prefer `FOR…NEXT` to manual `GOTO` loops.
410
+ - Keep `IF` expressions short; parser re-evaluates every branch.
411
+ - Combine short statements with `:` (< 80 chars per line).
412
+ - Limit nesting depth (< 5) for readability and speed.
413
+
414
+ ### 10.7 Program Structure & I/O
415
+
416
+ - Put constants/setup early; `DATA` and rarely used routines last.
417
+ - Remove `REM` in loops; still parsed.
418
+ - Minimise disk/tape/printer I/O; buffer in memory.
419
+ - `CMD` redirection is slow—set once.
420
+ - Avoid frequent `TI$`; use loop counters instead.
421
+ - Use `SYS` for time-critical routines.
422
+
423
+ ### 10.8 Memory Use
424
+
425
+ - Each scalar = 7 B; arrays store only element data.
426
+ - Pack short related statements on one line.
427
+ - Use abbreviations (`?`, `gO`, `sT`) to stay within 80 chars.
428
+ - Maintain ≥ 50 % free RAM for string heap stability.
429
+ - Call `CLR` to drop unused variables.
430
+
431
+ ### 10.9 Summary
432
+
433
+ Fast BASIC = minimal parsing, fixed data, short names, reused strings, few allocations.
434
+ Define vars early, pre-DIM arrays, keep loops shallow, and avoid heap churn.
435
+ Typical speed gain: 2–5× over unoptimised code.
436
+
437
+ ---
438
+
439
+ ## 11. Writing Games Efficiently in BASIC
440
+
441
+ C64 BASIC games rely on careful screen, input, and timing control. Interpreter speed limits frame rate; optimise for responsiveness, not raw throughput.
442
+
443
+ ### 11.1 Core Strategy
444
+
445
+ - BASIC handles logic; graphics/sound via `POKE` to hardware.
446
+ - Use fixed variables and arrays; avoid runtime string creation.
447
+ - Keep main loop short and predictable.
448
+
449
+ ### 11.2 Screen Handling
450
+
451
+ - Screen RAM $0400 (1024 dec); Colour RAM $D800 (55296 dec).
452
+ - `PRINT` is slow; use direct writes:
453
+
454
+ ```basic
455
+ POKE1024+X+40*Y,CHR
456
+ POKE55296+X+40*Y,COLOR
457
+ ```
458
+
459
+ - Redraw only modified cells; update deltas, not full screen.
460
+ - For static backgrounds, draw once, then update moving parts.
461
+ - To clear screen, loop over $0400/$D800 ranges.
462
+
463
+ ### 11.3 Delta Updates
464
+
465
+ - Track old/new positions; erase previous cell, draw new one.
466
+ - Use flags or small arrays for active objects only.
467
+ - Skip unchanged elements; BASIC loops are costly.
468
+
469
+ ### 11.4 Timing (Delays)
470
+
471
+ - **Do not delay by default**—BASIC is slower than 50 Hz refresh.
472
+ - Add timing only for pacing (slow motion, animation rhythm, cross-platform consistency, or sync with music).
473
+ - Implement fixed-step gating, not busy-waits:
474
+
475
+ ```basic
476
+ IF TI-T0>=N THEN T0=TI:GOSUB UPDATE
477
+ ```
478
+
479
+ → limits maximum update rate without freezing input.
480
+ - Avoid `FOR T=1 TO N:NEXT` and tight wait loops; they waste CPU.
481
+ - If the game already runs slower than `N`, no wait occurs.
482
+
483
+ ### 11.5 Movement & Input
484
+
485
+ - Move by arithmetic deltas (`X=X+DX`); keep signed `DX/DY`.
486
+ - Keyboard: `GET A$` (non-blocking). Avoid `INPUT`.
487
+
488
+ ```basic
489
+ GETK$:IFK$<>""THEN...
490
+ ```
491
+
492
+ - Joystick port 2 @ $DC00 (56320):
493
+
494
+ | Bit | Function | Mask |
495
+ |------|-----------|------|
496
+ | 0 | Up | 1 |
497
+ | 1 | Down | 2 |
498
+ | 2 | Left | 4 |
499
+ | 3 | Right | 8 |
500
+ | 4 | Fire | 16 |
501
+ Example:
502
+ `J=PEEK(56320):IF(JAND1)=0THENPY=PY-1`
503
+
504
+ ### 11.6 Sprites & Graphics
505
+
506
+ - VIC sprite enable $D015; positions $D000–$D00F; colours $D027–$D02E.
507
+ - Pre-load sprite data; update only X/Y each frame via `POKE`.
508
+ - VIC renders asynchronously—BASIC handles motion logic only.
509
+
510
+ ### 11.7 Sound
511
+
512
+ - SID base $D400.
513
+ - Store freq/envelope tables in DATA or arrays; `POKE` directly each frame.
514
+
515
+ ### 11.8 Memory & Performance
516
+
517
+ - Use integer arrays for coordinates/counters.
518
+ - Keep < 26 variables for faster lookup.
519
+ - Avoid `PRINT` during play; write HUD directly to screen RAM.
520
+ - For scrolling, shift indices or viewport pointers instead of copying memory.
521
+ - Reuse data structures; avoid new strings inside loop.
522
+
523
+ ### 11.9 Example Loop Skeleton
524
+
525
+ ```basic
526
+ 10 T0=TI:GETK$
527
+ 20 GOSUB1000:REM LOGIC
528
+ 30 GOSUB2000:REM DRAW
529
+ 40 IF TI-T0<2 THEN GOTO40
530
+ 50 GOTO10
531
+ ```
532
+
533
+ → adds frame pacing only if motion needs slowing.
534
+
535
+ ### 11.10 Summary
536
+
537
+ Efficient BASIC games minimise interpreter overhead.
538
+ Use `POKE/PEEK` for graphics and input, delta redraw for movement, fixed-step gating only when required, and pre-allocated variables for state.
539
+ Result: smooth, responsive gameplay within BASIC’s limits.