Added two new built-in functions to the HAS compiler for direct register access:
- GetReg(register) - Reads a value from a specified register
- SetReg(register, value) - Writes a value to a specified register
var result: long = GetReg("d0"); // Read from data register d0
var addr: long = GetReg("a1"); // Read from address register a1
SetReg("d3", myvar); // Write variable to data register d3
SetReg("a0", address_value); // Write address to address register a0
SetReg("d2", x + y); // Write expression result to register
- d0, d1, d2, d3, d4, d5, d6, d7 (8 data registers)
- a0, a1, a2, a3 (4 address registers)
Note: Registers a4-a7 are not valid parameters as they are reserved:
- a4: Frame pointer (in procedures with local variables)
- a5: Caller-save area
- a6: Additional uses in some calling conventions
- a7: Stack pointer
- GetReg always returns
long(4-byte value) - SetReg accepts any expression that evaluates to a value
- Added
getregandsetreggrammar rules in theatomsection - Parses string literals for register names:
GetReg("d0")→ast.GetReg(register="d0") - Parses SetReg with two arguments:
SetReg("d3", expr)→ast.SetReg(register="d3", value=expr)
@dataclass
class GetReg:
register: str # Register name (d0-d7, a0-a3)
@dataclass
class SetReg:
register: str # Register name (d0-d7, a0-a3)
value: Any # Expression to assign to register- Validates that register names are in the allowed set {d0-d7, a0-a3}
- GetReg: No expression validation needed (just register validation)
- SetReg: Validates both register and the value expression
- GetReg: Generates
move.l <register>,<target_reg>to read register into target - SetReg:
- Evaluates the value expression into a temp register (d1 or d2)
- Generates
move.l <temp_reg>,<register>to write to target register
proc example1() -> long {
var myval: long = 42;
SetReg("d4", myval); // Write to d4
var result: long = GetReg("d4"); // Read from d4
return result;
}
proc example2() -> long {
var ptr: long = 0x1000;
SetReg("a0", ptr); // Load pointer into a0
var ptr_value: long = GetReg("a0"); // Read it back
return ptr_value;
}
proc example3() -> long {
var a: long = 10;
var b: long = 20;
SetReg("d5", a + b); // Write expression result to d5
var result: long = GetReg("d5"); // Read it back
return result;
}
; var result: long = GetReg("d0");
move.l d0,-4(a4) ; Read from d0, store in local variable; SetReg("d3", myval);
move.l -4(a4),d1 ; Load myval into d1
move.l d1,d3 ; Write d1 to d3; SetReg("d2", a + b);
move.l -4(a4),d1 ; Load a
move.l -8(a4),d2 ; Load b
add.l d2,d1 ; Add: d1 = a + b
move.l d1,d2 ; Write result to d2Created example files to test the implementation:
examples/getreg_setreg_simple.has- Basic GetReg/SetReg usageexamples/getreg_setreg_test.has- Comprehensive tests with all registersexamples/getreg_addr_regs.has- Tests address registers a0-a3examples/getreg_invalid_reg.has- Validation error test (attempts to use a4)
Invalid register names are caught during validation:
Validation error: GetReg invalid register 'a4'. Valid registers: d0-d7, a0-a3
- GetReg/SetReg are expressions, not statements (they can be used in assignments)
- SetReg returns a value for compatibility with expression context (the written value)
- Register values are not type-checked - they're treated as raw long values
- These functions provide low-level register access for performance-critical code and hardware interaction