Stellar C
A small C-like language that compiles straight to STELLAR bytecode. Write a program, compile it, and run it here on the real V0061.35 firmware — or download the .lst for an Elf2K. The compiler is the real one, written in Python, running in your browser.
Source
Compiled
Compile to see the STELLAR bytecode here, each opcode next to the source line it came from.
Run it
Serial terminal
Click the terminal and type to send keys to the running program; on a phone or tablet, tap it for the keyboard, with the arrow keys, Esc and Enter in the row underneath. The input box pre-loads keystrokes before it starts.
Front panel
The language
STELLAR has sixteen fast registers and no stack frames, so Stellar C works like PL/M or Atari Action!: every variable has one fixed home, most of them in registers, and there is no recursion (the compiler refuses it). Two functions that are never active at the same time share registers. Everything is unsigned.
| Write | Means |
|---|---|
| const W = 80; | a compile-time constant |
| u16 score, best; | 16-bit unsigned variables — registers where possible |
| u8 lvl; | one byte of memory |
| u8 grid[1680]; | a byte array (set to zero at every start if the program writes it) |
| u8 rev[] = { 0, 2, 1 }; u8 msg[] = "hello"; | initialised arrays; a string is one, with a 0 on the end |
| u16 f(u16 a, u16 b) { … } | functions with parameters, locals and a return value; void main() is where it starts |
| if else while for break continue return | as in C |
| = += -= *= /= %= &= |= ^= ++ -- | assignment |
| + - * / % & | ^ << >> | arithmetic (shifts by a constant); a[i], &a[i], calls |
| == != < <= > >= && || ! | conditions |
| putc(c) print("text") printu(n) | a character, a string or array, a number in decimal |
| getc() keyready() | wait for a key; is a key waiting? |
| rand() delay(k) halt() | a random number, a pause, stop the program |
| fill(&a[i], v, n) copy(&dst, &src, n) | fill or copy a run of bytes |
| out(e) outmem(&a[i]) outport(p) | a byte to the output port — the front panel's hex display on port 4 (choose 1, 4-7) |
| q(e) | the Q lamp: q(0) off, q(1) on, q(2) one blink, q(3) two |
| scanin() getin() inport(p) | read the input port now; or wait for the INPUT button (EF4), then read it |
| ef() ef(n) efsource(n) efsource(n, 1) | all four EF lines as a mask (bit 0 = EF1 ... bit 3 = EF4); 1 if line n is on, else 0; the EF line getin() and waitef() wait on, 1-4 (a second argument of 1: inverted, active low) |
| waitef() waitef(n) | wait for that EF line to go on, then off — or for EF line n (1-4), whatever efsource() says. Other VMs keep running meanwhile |
Inline STELLAR: asm { }
One STELLAR command per line — the mnemonic, then its operand bytes in hex, as the opcode reference lays them out. {x} is the register variable x lives in, #e two bytes (a constant or &array), %e one byte, @name an address (a label, a function, or @break @continue @return), and name: a label. Each command's length is checked. The asm may use RD, RE and RF, and must leave RC alone.
asm {
poll:
SERST // a key waiting?
IFFALSEI @done
SERIN
INCX 0{k} // {k} = the register k lives in
GAL @poll
done:
}
Native 1802: native { }
Raw 1802 machine code, assembled by the compiler and run in place by $F1 RUNMC — for the inner loop that must be fast. {x} is the address of variable x's VM register (high byte first), &a an array's address, hi(e) and lo(e) its two bytes. The block returns by itself at the end (or BR exit). Free registers are R7 R8 R9 RB RD RE RF; the compiler refuses writes to the others. Set X with SEX before any STR, and remember the other VMs wait while native code runs.
The compiler's Python source is served with this page, in sc/, and as one download, stellar-c.zip. Look up any opcode in the reference; load other programs on the Simulator.