SICC is yet another compiler for Stationeers IC10. It compiles to minimize code size.
This works by writing python code which gets traced and then compiled into IC10. See examples/explained.py for how this works.
This is a WIP; review output before using. API is subject to change without notice.
- Produces very optimized code, usually significantly shorter than from other tools
- use any python features at trace time: trace time loops, if, assert, etc
- Also produce a readable equivalent of the output, which is easier to inspect manually
- colored and with source information
- currently, its highly recommended to review this manually
- operators
+,-,*,/&for boolean and;|for boolean or,~for boolean not- this is because python
andandoronly work withbool - in python,
&and|have differenct precedence asandandor; use parenthesis:(a < b) & (c < d)
- this is because python
- control flow
if_,else_,while_,continue_,break_,return_- the python counterparts would run at trace time
- math functions
- only a small subset is supported at the moment
- Structures with pre-defined fields
- static typing and autocomplete (with pyright only)
- embed raw asm code
- in development
- high level construct for other operations: slots, stack, etc
- in development
- Subroutines
- recursion is not supported
- Nested function calls
- SICC does not use
pushandpop; instead it movesrato a different register if needed, saving lines - arguments and return value can be
tuple,list,dict, or classes
Install uv and run
git clone https://github.com/Alan-Chen99/sicc-template.git
cd sicc-template
uv sync
# optional: upgrade to latest git version
# uv lock --upgrade
source ./.venv/bin/activate
python main.py
# or: sicc main.pyhere is a equivalent of the ic11 example here:
| SICC | IC11 |
|---|---|
from sicc import *
from sicc.devices import *
pa1 = d0
valve1 = d1
pa2 = d2
valve2 = d3
TargetTemp1 = 297
TargetTemp2 = 297
@program
def main():
with loop():
yield_()
control_temp(pa1, valve1, TargetTemp1)
control_temp(pa2, valve2, TargetTemp2)
@subr
def control_temp(pa: Pin, valve: Pin, targetTemp: Int):
needCooling = pa.Temperature > targetTemp
delta = abs(targetTemp - pa.Temperature)
power = Variable(10)
with if_(delta > 5):
power.value = 100
valve.On = needCooling
valve.Setting = power |
pin PA1 d0;
pin Valve1 d1;
pin PA2 d2;
pin Valve2 d3;
const TargetTemp1 = 297;
const TargetTemp2 = 297;
void Main()
{
while(true)
{
yield;
ControlTemp(0, 1, TargetTemp1);
ControlTemp(2, 3, TargetTemp2);
}
}
void ControlTemp(paIdx, valveIdx, targetTemp)
{
var needCooling = Pins[paIdx].Temperature > targetTemp;
var delta = Abs(targetTemp - Pins[paIdx].Temperature);
var power = 10;
if (delta > 5)
power = 100;
Pins[valveIdx].On = needCooling;
Pins[valveIdx].Setting = power;
} |
| SICC (17 lines) | IC11 (29 lines, excluding alias statements) |
|
|
| SICC (readable equivalent; terminal output has color) | |
|
This compiler uses Static single-assignment form (SSA), but it does not have phi instructions; instead it has mutable variables (MVar) representing varaibles that opts out of SSA invariant. MVar must be first converted from/to Var before used; The register allocator will tries its best to allocate read/write mvar operands to the same register. MVar are printed with an underline in the current main.py output.
This project uses uv to manage dependencies; so it is recommended to use uv to install dependencies locked in uv.lock
This codebase is statically typed; this works with pyright only.