A programmable circuit combinator controlled via a RISC-V inspired assembly language. Supports reading red and green input signals and writing up to four output signals per tick.
Mods introducing new content into the game.
Version: 0.8.11
Date: 01. 04. 2026
Features:
- Added LI rd, imm — load immediate. Sets rd = imm directly. Syntactic sugar for
ADDI rd, x0, imm; cleaner when the intent is loading a constant rather than adding.
Accepts decimal, hex (0x prefix), and negative values. All standard error checks apply.
- Instructions are now case-insensitive. Mnemonics may be written in upper, lower, or
mixed case (ADDI, addi, Addi). The mnemonic is uppercased once during parsing via
instruction:upper() before any comparison. Register names (x0-x31, o0-o3) and signal
names remain case-sensitive as Factorio requires.
Documentation:
- Updated README.md and LICENSE.md to user-supplied versions. LICENSE now retains
Joakim Lönnegren's original MIT copyright alongside the Analytical Combinator
contributors' copyright. README includes Credits section acknowledging the original
mod and Claude's role in development.
- README: LI added to arithmetic table; new "Instruction case" section documents
case-insensitive parsing.
- 12 new tests (132 total): LI basic use, hex/negative immediates, x0 suppression,
overwrite, error cases; case-insensitive mnemonic tests including a lower-case
loop with BNEI; signal/register case-sensitivity confirmation.
Version: 0.8.10
Date: 29. 03. 2026
Bugfixes:
- Fixed BEQ and BNE: missing register nil-checks meant that a literal (e.g. BEQ x3, 0,
label) or invalid register (e.g. BEQ x3, x99, label) was silently miscompared rather
than raising an error. nil==nil is true in Lua, so BEQ x3, x99 would always branch
regardless of x3; BEQ x3, 0 would never branch. Both now validate both operands first.
- Fixed WSIG: the count source register (third argument) had no nil check. An invalid
register name would silently emit a signal with count nil (treated as 0).
- Fixed JAL: the destination register for the saved return address had no nil check.
Writing to an invalid key (e.g. x99) would silently create a junk table entry.
- Fixed SLT: added nil check on the destination register (first argument).
Features:
- Added BEQI rs, imm, label — branch if rs == immediate value
- Added BNEI rs, imm, label — branch if rs != immediate value
- Added BLTI rs, imm, label — branch if rs < immediate value
- Added BLEI rs, imm, label — branch if rs <= immediate value
- Added BGTI rs, imm, label — branch if rs > immediate value
- Added BGEI rs, imm, label — branch if rs >= immediate value
- All immediate branches accept hex literals (0x prefix) and validate both the
register and immediate operands, erroring cleanly on invalid input.
- 20 new tests including regression tests for the nil-check bugs. 120 tests total.
Version: 0.8.9
Date: 29. 03. 2026
Features:
- Added MULI rd, rs, imm — multiply register by immediate (rd = rs * imm)
- Added DIV rd, rs, rt — integer division, floor toward -inf (rd = floor(rs/rt))
- Added DIVI rd, rs, imm — divide by immediate
- Added REM rd, rs, rt — remainder, sign follows dividend C-style (math.fmod)
- Added REMI rd, rs, imm — remainder by immediate
- DIV, DIVI, REM, REMI all produce a descriptive runtime error on divide-by-zero
rather than crashing. Lua's math.floor and math.fmod are used to give consistent
signed behaviour across all values.
- Note: MUL was already present since 0.8.4; MULI is the new immediate variant.
- 18 new tests covering basic operation, negative values, divide-by-zero errors,
hex immediates, and a practical modulo wrap-around example. 100 tests total.
Version: 0.8.8
Date: 29. 03. 2026
Changes:
- Fixed JAL to save IP+1 (address of the next instruction) rather than the line number
of the JAL itself. This matches standard RISC-V convention and makes JR work cleanly
without a compensating +1. Existing programs using JAL x0 (discard return address)
are unaffected. Programs relying on the specific numeric value saved by JAL will need
to add 1 to their expected values.
- Fixed JR to jump directly to the value in rs (no +1 adjustment needed now that JAL
saves the correct return address).
- JR x0 is now a defined special case: jumps to line 1 (program restart). Since x0 is
always 0 and 0 is not a valid line number, this provides a convenient restart without
requiring a label on line 1.
- Updated all tests: JAL return-address assertions updated (x1=3→4 etc.),
JR test comments corrected, new JR x0 restart test added. 82 tests total.
- README: JAL/JR table entries updated; subroutine example rewritten — the old version
needed an awkward BGT workaround because JAL saved the wrong value; the new example
is clean and straightforward.
Version: 0.8.7
Date: 29. 03. 2026
Features:
- Added BLT rd, rt, label — branch if rs < rt
- Added BLE rd, rt, label — branch if rs <= rt
- Added BGT rd, rt, label — branch if rs > rt
- Added BGE rd, rt, label — branch if rs >= rt
- Added JR rs — jump to instruction at rs+1, enabling subroutine returns.
JAL saves the line number of the JAL instruction itself, so JR adds 1 to
land on the instruction after the call site.
- 16 new tests (81 total): branch taken/not-taken cases for all four new
instructions, JR call/return, nested calls with distinct return registers,
and error cases.
- README: control flow table updated; new subroutine call/return example.
Version: 0.8.6
Date: 29. 03. 2026
Features:
- Added SRL rd, rs, rt — shift right logical by register (zero-fill)
- Added SRLI rd, rs, imm — shift right logical by immediate (zero-fill)
- Hex immediates: all immediate arguments now accept 0x prefix (e.g. ADDI x10, x0, 0xFF).
tonumber() auto-detects base, so decimal and hex both work everywhere.
Changes:
- Renamed shift instructions to match RISC-V convention:
SHL → SLL (shift left logical, register)
SHLI → SLLI (shift left logical, immediate)
SHR → SRA (shift right arithmetic, register)
SHRI → SRAI (shift right arithmetic, immediate)
- Moved bitlib setup (bit32/bit) to module level rather than inside step() to
avoid re-evaluating it on every tick.
- Fixed indentation bug: the else clause of the instruction dispatcher was
accidentally indented inside the CNTSG block.
Documentation:
- README Shifts table expanded to all six variants with logical/arithmetic distinction noted.
- README new section "Immediate value formats" documents decimal, hex, and negative literals.
- Test suite: shift tests renamed; 4 new tests contrasting SRL/SRLI (zero-fill) against
SRA/SRAI (sign-extend) on negative values. 65 tests total.
Version: 0.8.5
Date: 29. 03. 2026
Bugfixes:
- Fixed bitwise instruction implementation to use bit32 or bit library functions rather
than typical operators.
Version: 0.8.4
Date: 29. 03. 2026
Features:
- Added MUL rd, rs, rt — multiply two registers (rd = rs * rt)
- Added AND rd, rs, rt — bitwise AND
- Added OR rd, rs, rt — bitwise OR
- Added XOR rd, rs, rt — bitwise XOR
- Added NOT rd, rs — bitwise NOT, unary (rd = ~rs)
- Added SHL rd, rs, rt — shift left by register
- Added SHLI rd, rs, imm — shift left by immediate
- Added SHR rd, rs, rt — logical shift right by register
- Added SHRI rd, rs, imm — logical shift right by immediate
- Added CNTSR rd — count of distinct signals on the red input wire
- Added CNTSG rd — count of distinct signals on the green input wire
- All new instructions respect the x0 write-suppression rule and produce
descriptive errors for wrong argument counts or invalid register names
- 25 new tests (61 total)
- README: Bitwise and Shifts instruction tables added; CNTSR/CNTSG added to
circuit input table; two new examples (bit masking, signal presence detection)
Version: 0.8.3
Date: 29. 03. 2026
Bugfixes:
- Fixed README: the "Red/green mixer" example was using SUB (red minus green) despite
claiming to output a sum. Replaced with two correct ADD-based examples:
"Red/green signal sum" (continuous summing loop) and "Red/green sum with threshold gate"
(fires signal-A once combined total exceeds 500).
Version: 0.8.2
Date: 29. 03. 2026
Features:
- Added ADD instruction: ADD rd, rs, rt sets rd = rs + rt (register + register addition).
This is the missing complement to SUB and ADDI. Useful for combining values from two
sources, e.g. summing red and green wire readings of the same signal.
Example: RSIGR x10, iron-plate / RSIGG x11, iron-plate / ADD x12, x10, x11
- Added 6 tests for ADD covering basic addition, accumulation in place, x0 write
suppression, negative values, invalid register, and wrong argument count.
- README: ADD added to instruction table; new example showing red+green signal sum
with threshold gate.
Version: 0.8.1
Date: 29. 03. 2026
Features:
- Assembly code editor now uses a monospace font (NotoMono via the built-in "default-mono"
descriptor). A FontPrototype "ac-mono-14" is declared in prototypes/fonts.lua and applied
to the text-box at GUI creation time via textbox.style.font. No external TTF file is
required as NotoMono-Regular.ttf ships with Factorio core.
Version: 0.8.0
Date: 29. 03. 2026
Changes:
- New technology tree icon (256x256): dark PCB circle with circuit traces, central IC chip,
amber LED, and assembly code line art — no longer uses the vanilla circuit-network graphic
- New mod portal thumbnail (144x144): shows the combinator body with screen chip, green
input wire, red output wire, and a floating assembly code snippet
- Rewrote all locale descriptions in locale/en/base.cfg to specifically describe the
assembly-language programming model rather than generic combinator marketing copy
Version: 0.7.9
Date: 29. 03. 2026
Changes:
- Mod renamed from "Assembly Combinator" to "Analytical Combinator" to distinguish it
from the original constant-combinator-based mod by joalon. All internal entity names,
storage keys, GUI names, prototype IDs, and locale strings updated accordingly.
- License changed to Zero-Clause BSD (0BSD) — no attribution required.
- Updated mod description to better reflect RISC-V inspired assembly language and
dual-wire input capability.
Version: 0.7.8
Date: 28. 03. 2026
Bugfixes:
- Fixed crash when WSIG is used with virtual or fluid signals (e.g. signal-red, crude-oil).
Output signals were always emitted with type="item", causing Factorio to reject any name
that isn't a valid item. write_outputs now resolves each signal name against
prototypes.virtual_signal, prototypes.item, and prototypes.fluid in that order to
determine the correct type. Invalid signal names are silently skipped rather than crashing.
Version: 0.7.7
Date: 28. 03. 2026
Documentation:
- Fixed incorrect README description for the Threshold Gate example which claimed the
output signal appeared "on the red wire". WSIG writes to an output register with no
wire-colour specificity; the signal appears on whichever wire(s) are physically connected
to the output side of the combinator.
Version: 0.7.6
Date: 28. 03. 2026
Bugfixes:
- Fixed "everything" signal appearing on output wire in alt-mode and leaking onto the circuit
network. The always-true condition used signal-everything as its first_signal, which is a
special aggregate virtual signal that Factorio propagates to the output. Replaced with a
pure constant condition (first_constant=0, comparator="=", second_constant=0) which
references no signals at all and has no side effects on the network.
Version: 0.7.5
Date: 28. 03. 2026
Bugfixes:
- Fixed crash on load: defines.circuit_connector_id was removed in Factorio 2.0 and replaced
by defines.wire_connector_id with per-colour IDs. get_circuit_network() now takes a single
wire_connector_id (e.g. combinator_input_red / combinator_input_green) rather than a
wire_type + circuit_connector_id pair. Fixed in both events.lua and gui.lua.
Version: 0.7.4
Date: 28. 03. 2026
Bugfixes:
- Fixed RSIGR and RSIGG always reading zero: get_circuit_network() requires an explicit
circuit_connector_id for entities with separate input and output connectors. Without it
the call returns nil on a decider combinator. Both events.lua and gui.lua now pass
defines.circuit_connector_id.combinator_input when reading the input-side network.
Version: 0.7.3
Date: 28. 03. 2026
Bugfixes:
- Fixed crash when loading a saved game containing analytical combinators: Factorio does not
persist Lua metatables across saves, so stored cpu objects lost all their methods on load.
control.lua now re-attaches the cpu module metatable in both on_load (normal resume) and
on_configuration_changed (mod update). Also backfills the input_signals field for saves
predating 0.7.0 that were created without it.
Date: 28. 03. 2026
Bugfixes:
- Fixed crash on placement: LuaDeciderCombinatorControlBehavior does not expose
sections_count / add_section / get_section (those belong to the constant combinator).
Output writing now uses behavior.parameters with a conditions+outputs table, which is
the correct 2.0 API for decider combinators. Clearing outputs uses behavior.parameters=nil.
Date: 28. 03. 2026
Graphics:
- Added custom microchip display sprite (30x22) replacing the decider combinator's
comparison operator symbols (=, >, <, ≠, ≥, ≤) so the entity is visually distinct
in-world regardless of which operator mode Factorio internally selects
- Added custom 64x64 inventory/crafting icon showing the combinator body with the chip
symbol on screen, a green status LED, and an 'AC' label
Version: 0.7.0
Date: 28. 03. 2026
Major Features:
- Fork of Assembly combinator version 0.6.2 from joalon
- Analytical combinator is now based on a Decider Combinator, providing both input and output
circuit network connections (red and green wires)
- Added RSIGR instruction: read a named signal from the red input wire into a register
- Added RSIGG instruction: read a named signal from the green input wire into a register
- Red and green channels are read independently each tick, enabling programs to respond
to live circuit network state
Changes:
- Recipe now requires a Decider Combinator instead of a Constant Combinator