Source: POLIZ_PROGRAMMING_MANUAL.md (derived from Brusentsov et al., 1970)
A trit (ternary digit) has three possible values:
Value Symbol Alternate
─────────────────────────
-1 T ī
0 0 0
+1 1 1
A tryte consists of 6 trits:
┌─────┬─────┬─────┬─────┬─────┬─────┐
│ t[0]│ t[1]│ t[2]│ t[3]│ t[4]│ t[5]│
└─────┴─────┴─────┴─────┴─────┴─────┘
MST LST
- Range: -364 to +364 (decimal)
- Total values: 3^6 = 729
decimal_value = Σ(t[i] × 3^(5-i)) for i in 0..5
Example: (1, 0, T, 1, 0, T) where T = -1
= 1×243 + 0×81 + (-1)×27 + 1×9 + 0×3 + (-1)×1
= 243 - 27 + 9 - 1
= 224
Every syllable is exactly 6 trits. Type determined by first two trits:
| t[0:1] | Type | Description |
|---|---|---|
(0, 0) |
OPERATION | Execute an operation |
| anything else | ADDRESS | Push value from memory |
┌─────────────┬──────────┬─────────────────────┐
│ t[0:1] = 00 │ t[2] │ t[3:5] │
│ (marker) │ (type) │ (opcode) │
└─────────────┴──────────┴─────────────────────┘
Operation Types (t[2]):
| Value | Type | Description |
|---|---|---|
| 0 | BASIC | Arithmetic, stack, control flow |
| 1 | SERVICE | I/O operations |
| -1 | MACRO | User-defined (software dispatch) |
Opcode (t[3:5]): 3-trit signed integer, range -13 to +13
┌──────────────┬──────────────┬─────────────────────┐
│ t[0] │ t[1] │ t[2:5] │
│ (length) │ (page_reg) │ (offset) │
└──────────────┴──────────────┴─────────────────────┘
Length (t[0]): Word size to fetch
| Value | Syllables |
|---|---|
| -1 | 3 syllables (18 trits) |
| 0 | 2 syllables (12 trits) |
| 1 | 1 syllable (6 trits) |
Page Register (t[1]): Which of 3 page registers to use (-1, 0, 1)
Offset (t[2:5]): 4-trit offset within page, range -40 to +40
Total Memory: 27 pages × 81 syllables = 2,187 syllables
(3^3 pages × 3^4 locations)
Page Types:
- Pages 0-8: RAM (read/write)
- Pages 9-26: ROM/Pluggable (read-only)
Three page registers (P[-1], P[0], P[1]) hold page numbers:
Effective_Address = (Page_Registers[t[1]], t[2:5])
= (page_number, offset)
def resolve_address(syllable):
length = syllable[0] # Word size
page_reg = syllable[1] # Which page register
offset = trits_to_int(syllable[2:6]) # Offset in page
page = page_registers[page_reg]
return (page, offset, length)| Stack | Purpose | Access |
|---|---|---|
| Operand Stack | Values, intermediate results | T (top), S (second) |
| Return Stack | Procedure return addresses | R (top) |
PUSH(value):
operand_stack.append(value)
POP() -> value:
return operand_stack.pop()
T: operand_stack[-1] # Top
S: operand_stack[-2] # Second (under-top)
For each syllable in program:
if syllable.is_operation():
execute_operation(syllable)
else:
value = memory_fetch(syllable)
PUSH(value)
| Opcode | Mnemonic | Stack Effect | Description |
|---|---|---|---|
| 0 | NOP | ( -- ) | No operation |
| 1 | ADD | ( a b -- a+b ) | Add |
| 2 | SUB | ( a b -- a-b ) | Subtract (S - T) |
| 3 | MUL | ( a b -- a×b ) | Multiply |
| 4 | DIV | ( a b -- a÷b ) | Divide (S ÷ T) |
| 5 | DUP | ( a -- a a ) | Duplicate top |
| 6 | DROP | ( a -- ) | Remove top |
| 7 | SWAP | ( a b -- b a ) | Exchange top two |
| 8 | CMP | ( a b -- c ) | Compare: -1, 0, or 1 |
| 9 | JMP | ( addr -- ) | Jump to address |
| 10 | JZ | ( addr -- ) | Jump if T = 0 |
| 11 | JN | ( addr -- ) | Jump if T < 0 |
| 12 | JP | ( addr -- ) | Jump if T > 0 |
| 13 | CALL | ( addr -- ) | Call procedure |
| Opcode | Mnemonic | Stack Effect | Description |
|---|---|---|---|
| -1 | NEG | ( a -- -a ) | Negate |
| -2 | ABS | ( a -- |a| ) | Absolute value |
| -3 | OVER | ( a b -- a b a ) | Copy second to top |
| -4 | ROT | ( a b c -- b c a ) | Rotate three |
| -5 | STORE | ( val addr -- ) | Store to memory |
| -6 | FETCH | ( addr -- val ) | Fetch from memory |
| -7 | RET | ( -- ) | Return from call |
| -8 | HALT | ( -- ) | Stop execution |
| Opcode | Mnemonic | Description |
|---|---|---|
| 0 | IN | Read from input |
| 1 | OUT | Write to output |
| 2 | DRUM_R | Read from drum |
| 3 | DRUM_W | Write to drum |
User-defined. Opcode indexes into macro dispatch table.
def trits_to_int(trits):
"""Convert trit array to decimal integer."""
result = 0
for i, t in enumerate(trits):
result += t * (3 ** (len(trits) - 1 - i))
return resultdef int_to_trits(n, width=6):
"""Convert decimal integer to balanced ternary trits."""
trits = []
for _ in range(width):
rem = n % 3
if rem == 2:
rem = -1
n += 1
elif rem == 0:
rem = 0
else:
rem = 1
trits.append(rem)
n //= 3
return list(reversed(trits))ADD operation: (0, 0, 0, 0, 0, 1) = opcode 1
SUB operation: (0, 0, 0, 0, 1, T) = opcode 2 (where T = -1)
Address page0/0: (0, 0, 0, 0, 0, 0) = ERROR (looks like NOP!)
Address page1/0: (0, 1, 0, 0, 0, 0) = page_reg=1, offset=0
Address page0/1: (1, 0, 0, 0, 0, 1) = length=1, page_reg=0, offset=1
@dataclass
class Setun70State:
operand_stack: List[int] # Operand stack
return_stack: List[int] # Return address stack
memory: Dict[Tuple[int,int], int] # (page, offset) -> value
page_registers: List[int] # 3 page registers
pc: Tuple[int, int] # Program counter (page, offset)
running: bool # Execution state
comparison_flag: int # Last comparison resultwhile running:
syllable = memory[pc]
pc = next_address(pc)
if syllable[0:2] == (0, 0):
execute_operation(syllable)
else:
value = fetch_from_address(syllable)
operand_stack.push(value)
When t[0:2] == (0, 0), the syllable is ALWAYS an operation.
This means address (0, 0, *, *, *, *) is impossible.
Workaround: Use page register 1 or -1 for addresses near zero.
When offset exceeds page boundary (±40):
- In interrupt mode: wrap to page start
- In normal mode: trigger page fault
Attempting to pop from empty stack triggers HALT with error code.
; Comments start with semicolon
label: ; Labels end with colon
PUSH 10 ; Push literal
PUSH 20
ADD ; Add top two
STORE x ; Store to variable x
HALT
x: .word 0 ; Variable declaration
| Syntax | Meaning |
|---|---|
.word N |
Reserve N syllables |
.const V |
Define constant value V |
.page N |
Set current page to N |
.org A |
Set origin address |