Added BYTE REGISTER to docs and to editor syntaxes
This commit is contained in:
parent
501f58a968
commit
b49ba67aac
5 changed files with 76 additions and 5 deletions
11
commands.md
11
commands.md
|
|
@ -113,12 +113,14 @@ WEND
|
||||||
|
|
||||||
## BYTE
|
## BYTE
|
||||||
|
|
||||||
Declares an 8-bit variable or constant.
|
Declares an 8-bit variable, register-hinted temporary, or constant.
|
||||||
|
|
||||||
**Syntax:**
|
**Syntax:**
|
||||||
```
|
```
|
||||||
BYTE <varname>
|
BYTE <varname>
|
||||||
BYTE <varname> = <value>
|
BYTE <varname> = <value>
|
||||||
|
BYTE REGISTER <varname>
|
||||||
|
BYTE REGISTER <varname> = <value>
|
||||||
BYTE <varname> @ <address>
|
BYTE <varname> @ <address>
|
||||||
BYTE CONST <varname> = <value>
|
BYTE CONST <varname> = <value>
|
||||||
```
|
```
|
||||||
|
|
@ -127,10 +129,17 @@ BYTE CONST <varname> = <value>
|
||||||
```
|
```
|
||||||
BYTE counter
|
BYTE counter
|
||||||
BYTE speed = 5
|
BYTE speed = 5
|
||||||
|
BYTE REGISTER temp
|
||||||
|
BYTE REGISTER scratch = 0
|
||||||
BYTE screen @ $D020
|
BYTE screen @ $D020
|
||||||
BYTE CONST MAX_SPEED = 10
|
BYTE CONST MAX_SPEED = 10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`REGISTER` is a storage hint for the optimizer. The variable may be kept in a
|
||||||
|
CPU register (A/X/Y) and its memory allocation can be eliminated entirely.
|
||||||
|
Only valid inside `FUNC`/`FEND` blocks; incompatible with `@` and `CONST`.
|
||||||
|
See the REGISTER section in `language.md` for details.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## CALL
|
## CALL
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
<item>POINTER</item>
|
<item>POINTER</item>
|
||||||
<item>POKE</item>
|
<item>POKE</item>
|
||||||
<item>POKEW</item>
|
<item>POKEW</item>
|
||||||
|
<item>REGISTER</item>
|
||||||
<item>SCRIPT</item>
|
<item>SCRIPT</item>
|
||||||
<item>STEP</item>
|
<item>STEP</item>
|
||||||
<item>SUBEND</item>
|
<item>SUBEND</item>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ contexts:
|
||||||
scope: meta.preprocessor.c65cm
|
scope: meta.preprocessor.c65cm
|
||||||
|
|
||||||
keywords:
|
keywords:
|
||||||
- match: '\b(ADD|AND|AS|ASM|BREAK|BYTE|CALL|CASE|CONST|DEC|DECREMENT|DEFAULT|DO|ELSE|ENDASM|ENDIF|ENDSCRIPT|ENDSWITCH|EXIT|FEND|FOR|FUNC|GOSUB|GOTO|IF|INC|INCREMENT|LABEL|LET|LIBRARY|MACRO|NEXT|OR|ORIGIN|PASSING|PEEK|PEEKW|POINTER|POKE|POKEW|SCRIPT|STEP|SUBEND|SUBTRACT|SWITCH|THEN|TO|WHILE|WITH|WEND|WORD|XOR)\b'
|
- match: '\b(ADD|AND|AS|ASM|BREAK|BYTE|CALL|CASE|CONST|DEC|DECREMENT|DEFAULT|DO|ELSE|ENDASM|ENDIF|ENDSCRIPT|ENDSWITCH|EXIT|FEND|FOR|FUNC|GOSUB|GOTO|IF|INC|INCREMENT|LABEL|LET|LIBRARY|MACRO|NEXT|OR|ORIGIN|PASSING|PEEK|PEEKW|POINTER|POKE|POKEW|REGISTER|SCRIPT|STEP|SUBEND|SUBTRACT|SWITCH|THEN|TO|WHILE|WITH|WEND|WORD|XOR)\b'
|
||||||
scope: keyword.control.c65cm
|
scope: keyword.control.c65cm
|
||||||
- match: '\b(in|out|io)\b(?=\s*:)'
|
- match: '\b(in|out|io)\b(?=\s*:)'
|
||||||
scope: storage.modifier.parameter.c65cm
|
scope: storage.modifier.parameter.c65cm
|
||||||
|
|
|
||||||
|
|
@ -732,3 +732,36 @@ func TestPassRegDead_CallSiteKeepsStore(t *testing.T) {
|
||||||
t.Errorf("expected sta call_val to be kept (before jsr), got:\n%s", joined)
|
t.Errorf("expected sta call_val to be kept (before jsr), got:\n%s", joined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPassRegDead_InitValueFlowsThrough(t *testing.T) {
|
||||||
|
// BYTE REGISTER x = 42; POKE $d020, x → value flows through A, never touches RAM
|
||||||
|
input := []string{
|
||||||
|
"\tlda #$2a",
|
||||||
|
"\tsta test_x",
|
||||||
|
"\tlda test_x",
|
||||||
|
"\tsta 53280",
|
||||||
|
"\trts",
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &Config{
|
||||||
|
EnableRegisterVars: true,
|
||||||
|
EnableStoreLoad: true,
|
||||||
|
RegisterVars: map[string]bool{
|
||||||
|
"test_x": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
output, dissolved := Optimize(input, cfg)
|
||||||
|
|
||||||
|
if !dissolved["test_x"] {
|
||||||
|
t.Error("test_x should be dissolved — init value flows through A to POKE")
|
||||||
|
}
|
||||||
|
|
||||||
|
joined := strings.Join(output, "\n")
|
||||||
|
if strings.Contains(joined, "test_x") {
|
||||||
|
t.Errorf("expected no reference to test_x in output, got:\n%s", joined)
|
||||||
|
}
|
||||||
|
if !strings.Contains(joined, "lda #$2a") {
|
||||||
|
t.Error("init value lda #$2a should survive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
34
language.md
34
language.md
|
|
@ -88,12 +88,40 @@ initialize()
|
||||||
BYTE variables store 8-bit values (0-255).
|
BYTE variables store 8-bit values (0-255).
|
||||||
|
|
||||||
```c65
|
```c65
|
||||||
BYTE count // Uninitialized
|
BYTE count // Uninitialized (0)
|
||||||
BYTE speed = 5 // Initialized to 5
|
BYTE speed = 5 // Initialized to 5
|
||||||
|
BYTE REGISTER temp // Register-hinted (default 0)
|
||||||
|
BYTE REGISTER scratch = 0 // Register-hinted with init value
|
||||||
BYTE screen @ $D020 // Memory-mapped to specific address
|
BYTE screen @ $D020 // Memory-mapped to specific address
|
||||||
BYTE CONST MAX_SPEED = 10 // Constant (recommended over #DEFINE)
|
BYTE CONST MAX_SPEED = 10 // Constant
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### REGISTER Variables
|
||||||
|
|
||||||
|
The `REGISTER` hint tells the optimizer that a BYTE variable's value only matters as
|
||||||
|
it flows through the computation — never its stored location. The compiler can keep
|
||||||
|
the value in a CPU register (A, X, or Y) and eliminate dead stores and memory
|
||||||
|
allocations entirely.
|
||||||
|
|
||||||
|
```c65
|
||||||
|
FUNC fast_copy
|
||||||
|
BYTE REGISTER b
|
||||||
|
b = PEEK $d011
|
||||||
|
b = b | 32
|
||||||
|
POKE $d011, b // b never touches RAM — flows through A
|
||||||
|
FEND
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rules:**
|
||||||
|
|
||||||
|
- `BYTE REGISTER` is only valid inside `FUNC`/`FEND` blocks (function-local only)
|
||||||
|
- Cannot be combined with `@` (memory-mapped) or `CONST`
|
||||||
|
- Cannot be referenced from `ASM`, `SCRIPT`, or `MACRO` blocks via `|varname|`
|
||||||
|
- `WORD REGISTER` is not supported (the 6502 has no 16-bit ALU register)
|
||||||
|
- Without `--opt`, `REGISTER` behaves identically to a normal `BYTE`
|
||||||
|
- With `--opt`, the optimizer may dissolve the variable, eliminating its `!8`
|
||||||
|
allocation and all store/load operations
|
||||||
|
|
||||||
### WORD Variables
|
### WORD Variables
|
||||||
|
|
||||||
WORD variables store 16-bit values (0-65535).
|
WORD variables store 16-bit values (0-65535).
|
||||||
|
|
@ -109,7 +137,7 @@ WORD CONST SCREEN_RAM = $0400 // Constant
|
||||||
|
|
||||||
### Memory-Mapped Variables
|
### Memory-Mapped Variables
|
||||||
|
|
||||||
Variables can be placed at specific addresses using `@`:
|
Variables can be placed at specific addresses using `@`. Not compatible with `REGISTER`.
|
||||||
|
|
||||||
```c65
|
```c65
|
||||||
BYTE borderColor @ $D020 // VIC-II border color
|
BYTE borderColor @ $D020 // VIC-II border color
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue