Skip to main content

setnex-sim

Python simulator for the Setnex ISA — an open balanced ternary instruction set architecture. Implements the full fetch/decode/execute cycle for a 27-trit processor: 27 general-purpose registers, 5 configurable ternary logic modes (LMODE), and fixed-length R/I/J/U/B instructions. Built on tritlib.

Status

v0.6 — fully functional simulator with assembler, CLI toolchain, and nested-exception handling. 52 opcodes, 13 CSRs (main + frame-2 bank for nested traps), 100 % test coverage on non-CLI modules.

Implemented:

  • Decoder (R, I, J, U, B formats)
  • ALU (ADD, SUB, MUL, DIV, MOD, NEG, TAND, TOR, TNOT, TIMPL, CONS, ACONS, TSHIFT, TCMP, TGET, TSET, TSIGN, TABS, TMIN, TMAX)
  • Ternary floating-point unit (FADD, FSUB, FMUL, FDIV, FCMP, FCVT) — T26F format (§7)
  • Configurable ternary logic via LMODE (Kleene, Łukasiewicz, Heyting, RM3, Bochvar)
  • Registers (27 GPR + CSR: PC, LMODE, FLAGS, EPC, ECAUSE, EVEC, STATUS, ESAVE, ETVAL, EPC2, ECAUSE2, ESAVE2, ETVAL2)
  • Architectural exception dispatch: EXC_DIV0, EXC_FAULT, EXC_ILLEGAL, EXC_ECALL_U/H/D, EXC_OVERFLOW (§8); nested exceptions up to depth 2 (§8.2); machine-check reset on triple fault
  • Sparse word-addressed memory
  • CPU fetch/decode/execute loop with ternary FLAGS (sign, carry)
  • Branches and jumps (BEQ, BNE, BLT, BGT, BLE, BGE, BF, BRT3, JMP, JMPA, CALL)
  • System instructions (CSRR, CSRW, CSRX, ECALL, HCALL, DBGBRK, IRET, TSEL)
  • Text assembler (setnex-asm): .sasm → .tern, label resolution, pseudo-instructions
  • Runner (setnex-run): execute .tern files with register initialisation and ternary exit status

Install

pip install setnex-sim

Or from source:

git clone https://codeberg.org/setnex/setnex-sim
cd setnex-sim
pip install -e ".[dev]"

CLI usage

Assembler

setnex-asm program.sasm -o program.tern

CSR operations accept symbolic names (case-insensitive) as an alternative to numeric addresses:

CSRR t0, FLAGS        ; equivalent to `CSRR t0, 3`
CSRW t0, EVEC         ; equivalent to `CSRW t0, 6`

Recognised names: PC, LMODE, FLAGS, EPC, ECAUSE, EVEC, STATUS, ESAVE, ETVAL, EPC2, ECAUSE2, ESAVE2, ETVAL2 (addresses 1..13, §2.2).

Runner

setnex-run program.tern --set a0=5 --print a0

Options:

  • --set REG=VAL — initialise a register before execution (repeatable)
  • --print REG — print a register after HALT (default: a0)
  • --verbose — print all registers and cycle count

Exit status follows the ternary convention via a1 at HALT:

  • a1 < 0 (N) → shell exit 1 (error)
  • a1 = 0 (Z) → shell exit 0 (indeterminate)
  • a1 > 0 (P) → shell exit 0 (success)

Example programs

Example programs are provided in fixtures/:

sum.sasm : sum of integers 1..N (validates the full pipeline: LI, CMP, BF, ADD, ADDI, JMP):

setnex-asm fixtures/sum.sasm -o sum.tern
setnex-run sum.tern --set a0=5 --print a0
# a0 = 15

count_p.sasm : count P trits in a0 using TGET and BRT3:

setnex-asm fixtures/count_p.sasm -o count_p.tern
setnex-run count_p.tern --set a0=13 --print a0
# a0 = 3  (13 = +++ in balanced ternary — three P trits)

modsum.sasm : sum with sign driven by symmetric Euclidean i mod 3 ∈ {−1, 0, +1}, dispatched natively by BRT3 — a computation that has no natural binary equivalent:

setnex-asm fixtures/modsum.sasm -o modsum.tern
setnex-run modsum.tern --set a0=6 --print a0
# a0 = -2

sign_check.sasm : looks for a zero between a0 and a1, returns a1 = P if found, Z if absent, and a0 the results if a1 == P

setnex-asm fixtures/sign_check.sasm -o sign_check.tern
setnex-run sign_check.tern --set a0=3 a1=7 --print a0 --print a1
# a0 = 3
# a1 = 0
setnex-run sign_check.tern --set a0=-3 a1=7 --print a0 --print a1
# a0 = 0
# a1 = 1

sum_saturated.sasm : iterated saturating add (ADDS), counting iterations until t1 = t1 + t0 reaches T27 saturation. Uses TMIN for the all-P saturation test and BRT3 for the three-way loop dispatch — the native balanced-ternary idiom for bounded accumulation:

setnex-asm fixtures/sum_saturated.sasm -o sum_saturated.tern
setnex-run sum_saturated.tern --set a0=1 a1=0 --print a0
# a0 = iterations to saturate adding 1 to 0

fdiv.sasm : divides a0 by a1 in TFP (T26F), traps via ECALL to a minimal handler if the result is ∞ (division by zero in floating-point produces infinity, detected through FLAGS.carry = P). Illustrates the exception path: handler installation via CSRW t0, EVEC, trap on condition, handler advances EPC and returns via IRET. v0.5-compatible: ECALL with the default flavor tag (Z) produces ECAUSE = EXC_ECALL_U = 0, same as v0.5's EXC_ECALL:

setnex-asm fixtures/fdiv.sasm -o fdiv.tern
setnex-run fdiv.tern --set a0=10 a1=2 --print a0 --print a1
# a0 = 5 (finite), a1 = 1, exit 0
setnex-run fdiv.tern --set a0=10 a1=0 --print a0 --print a1
# a0 = 0, a1 = -1, exit 1 (handler trapped on ∞)

Exception handling

v0.6 implements the full §8 exception contract including nested exceptions (§8.2) and the three ECALL flavors. Eight architectural causes are wired:

Code Name Trigger ETVAL
−13 EXC_DIV0 DIV/MOD with rs2 = 0 0
−11 EXC_FAULT LOAD/STORE on unmapped address, or fetch from unmapped PC faulting address
−10 EXC_ILLEGAL reserved opcode (−20, −19, +14..+40) or unrecognised word raw instruction word
0 EXC_ECALL_U ECALL (user syscall flavor, imm17[0] = Z) 0 (call number in a7)
+1 EXC_ECALL_H HCALL (hypercall flavor, imm17[0] = P) 0
+2 EXC_ECALL_D DBGBRK (debug-trap flavor, imm17[0] = N) 0

Entry uses the bank selected by STATUS.depth:

  • depth = Z (no frame active): save to main bank (ESAVE/EPC/ECAUSE/ETVAL), force mode = ie = N, set depth = P, jump to EVEC.
  • depth = P (one frame active): save to frame-2 bank (ESAVE2/EPC2/ECAUSE2/ETVAL2), set depth = N; mode/ie already N. Main bank preserved.
  • depth = N (both frames in use): triple fault — machine-check reset.

Return via IRET atomically restores PC and STATUS from the bank matching the current depth (P → main bank, N → frame-2 bank). Since ESAVE/ESAVE2 captured the pre-entry depth value, the STATUS ← ESAVE* write implicitly decrements depth to its prior state — no separate depth manipulation.

Minimal handler pattern (install at EVEC, do work, advance EPC, return):

    LI    t0, handler
    CSRW  t0, EVEC           ; install handler
    ; ... user program, eventually triggers a trap ...
handler:
    ; ... handler body (read ECAUSE, ETVAL, a7 for syscall number, …) ...
    CSRR  t0, EPC
    ADDI  t0, t0, 1          ; resume at instruction after the trap
    CSRW  t0, EPC
    IRET

Machine-check reset — a third synchronous fault while both frames are in use (STATUS.depth = N) is a triple fault: the processor restarts from power-on state (PC ← 0, all CSRs and GPRs cleared). A single nested fault (fault inside an outer handler) is handled cleanly by the frame-2 bank and does not reset.

Python API

from setnex_sim.cpu import CPU
from setnex_sim.assembler import encode_R, encode_I

cpu = CPU()
program = [
    encode_I(-24, rd=1, rs1=0, imm=5),   # LI r1, 5
    encode_I(-24, rd=2, rs1=0, imm=3),   # LI r2, 3
    encode_R(-40, rd=3, rs1=1, rs2=2),   # ADD r3, r1, r2
    encode_R(0,   rd=0, rs1=0, rs2=0),   # HALT
]
cpu.load(program)
cpu.run()
print(int(cpu.regs[3]))  # 8

Setnex ISA

The full ISA specification is available at setnex.org and on Codeberg — Apache 2.0, patent-free.

Licence

MIT — Copyright 2026 Eric Tellier

Metadata

Release files for setnex-sim 0.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for setnex-sim 0.6.1
File Size Uploaded Provenance
setnex_sim-0.6.1.tar.gz 48.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for setnex-sim 0.6.1
File Interpreter ABI Platform
setnex_sim-0.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 77.4 kB

Release files / setnex_sim-0.6.1.tar.gz

Download URL setnex_sim-0.6.1.tar.gz
Size 48.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e1daaf9b001d6d23f0aba1c75cd20574dee1a5c8c9d50046e9a7225ab1ee571c
BLAKE2b-256 checksum
How to use checksums
d3d392f856d76841ccbdf0c5fc1a27767c550e5ea7dd60d3eb39943f22664f36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / setnex_sim-0.6.1-py3-none-any.whl

Download URL setnex_sim-0.6.1-py3-none-any.whl
Size 29.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
846703e6a0cae1587dbfcc3da3f62058bdfd9d5609b22982d7791fc9bf62c495
BLAKE2b-256 checksum
How to use checksums
f502ad2ef878b1f23b3553dfa3469fd791b064928c541c063eac4f4900205e31
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Security for setnex-sim 0.6.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page