Skip to content

Commit 69e5464

Browse files
committed
added ISA
1 parent ae1ada4 commit 69e5464

7 files changed

Lines changed: 151 additions & 0 deletions

File tree

MASTER_ISA.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ focuses on instructions whose semantics *literally require* a three-valued persp
4444
| two or more `0` values | 0 |
4545
| two or more `−1` values | −1 |
4646
| `(-1, 0, +1)` (all distinct) | 0 |
47+
- **TEQUIV** – Tritwise equivalence (balanced ternary XNOR). Returns +1 if both trits match and are non-zero, 0 if either trit is 0, and −1 otherwise. This provides a symmetric similarity test without losing unknown propagation (unlike chaining binary XNOR).
48+
| input ↓ \ input → | -1 | 0 | +1 |
49+
|------------------|----|---|----|
50+
| -1 | +1 | 0 | -1 |
51+
| 0 | 0 | 0 | 0 |
52+
| +1 | -1 | 0 | +1 |
53+
- **TXOR** – Tritwise exclusive-or (a + b mod 3). Outputs 0 when inputs match, ±1 when they differ, and keeps unknowns as neutral. Ideal for ternary hashing/diff operations where sign matters but zero must stay neutral.
54+
| input ↓ \ input → | -1 | 0 | +1 |
55+
|------------------|----|---|----|
56+
| -1 | 0 | -1 | +1 |
57+
| 0 | -1 | 0 | +1 |
58+
| +1 | +1 | -1 | 0 |
4759

4860
### 2. Control flow that uses three-way decisions
4961

@@ -54,6 +66,9 @@ focuses on instructions whose semantics *literally require* a three-valued persp
5466
- **TSIGNJMP** – Jump based on the sign trit of a register (positive/zero/negative), letting
5567
late-stage code skip redundant compares or flags. A binary design must inspect zero and sign
5668
flags separately, but balanced ternary exposes the sign trit directly.
69+
- **TMUX** – Three-way data multiplexer controlled by a ternary trit. Chooses operand A for −1,
70+
B for 0, and C for +1, mirroring `TBRANCH`’s select logic but for data paths. This avoids chained
71+
binary muxes in ternary state machines and pairs with the async control arbiter metadata.
5772

5873
### 3. Symmetric arithmetic helpers for AI / DSP workloads
5974

@@ -71,6 +86,7 @@ focuses on instructions whose semantics *literally require* a three-valued persp
7186
AI weights. Binary quantization typically lands at {0,1} or 8-bit ints; ternary quantization
7287
captures more information with fewer bits. This helper is critical for runtime math that
7388
prepares data for `TMIN/TMAX`-style activations.
89+
- **TNET** – Net trit sum: emit the count of `+1` values minus the count of `−1` values within a register. Balanced ternary makes this reduction carry-free and perfectly symmetric, serving as a lightweight “balance” check for ternary neural networks or error-detecting schemes.
7490

7591
### 4. Memory / conversion utilities beyond standard packing
7692

SPECIFICATION.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ intended to be exposed via the GCC plugin and helper ABI.
151151
- tand: per-trit min(a, b)
152152
- tor: per-trit max(a, b)
153153
- txor: ternary XOR (ISA-defined and stable)
154+
- tequiv: tritwise equivalence (Kleene XNOR) that propagates unknowns and returns +1 only when the inputs match.
154155
- tmin: per-trit minimum (alias of tand, optional)
155156
- tmax: per-trit maximum (alias of tor, optional)
156157

@@ -165,12 +166,14 @@ intended to be exposed via the GCC plugin and helper ABI.
165166
- tmuladd: ternary multiply-add with symmetric rounding (A×B + C)
166167
- tround: drop least-significant trits with symmetric rounding bias
167168
- tabs: absolute value (optional helper if not encoded in hardware)
169+
- tnet: net trit sum (count(+1) − count(−1)) for fast majority/balance checks.
168170

169171
### Ternary Comparison and Condition Ops
170172

171173
- tcmp: ternary compare returning {-1, 0, +1}
172174
- tsel: select with ternary condition (cond != 0)
173175
- tcmpz: compare against zero, returning {-1, 0, +1} (optional shortcut)
176+
- tmux: data multiplexer that selects among three operands based on a ternary control trit (-1,0,+1).
174177

175178
### Trit Shifts and Rotates
176179

include/ternary_runtime.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ t32_t __ternary_tmuladd_t32(t32_t a, t32_t b, t32_t c);
8383
t32_t __ternary_tround_t32(t32_t a, unsigned drop);
8484
t32_t __ternary_tnormalize_t32(t32_t a);
8585
t32_t __ternary_tbias_t32(t32_t a, int64_t bias);
86+
t32_t __ternary_tmux_t32(t32_t sel, t32_t neg, t32_t zero, t32_t pos);
87+
t32_t __ternary_tequiv_t32(t32_t a, t32_t b);
88+
t32_t __ternary_txor_t32(t32_t a, t32_t b);
89+
int __ternary_tnet_t32(t32_t a);
8690
t32_t __ternary_shl_t32(t32_t a, int shift);
8791
t32_t __ternary_shr_t32(t32_t a, int shift);
8892
t32_t __ternary_rol_t32(t32_t a, int shift);
@@ -122,6 +126,10 @@ t64_t __ternary_tmuladd_t64(t64_t a, t64_t b, t64_t c);
122126
t64_t __ternary_tround_t64(t64_t a, unsigned drop);
123127
t64_t __ternary_tnormalize_t64(t64_t a);
124128
t64_t __ternary_tbias_t64(t64_t a, int64_t bias);
129+
t64_t __ternary_tmux_t64(t64_t sel, t64_t neg, t64_t zero, t64_t pos);
130+
t64_t __ternary_tequiv_t64(t64_t a, t64_t b);
131+
t64_t __ternary_txor_t64(t64_t a, t64_t b);
132+
int __ternary_tnet_t64(t64_t a);
125133
t64_t __ternary_shl_t64(t64_t a, int shift);
126134
t64_t __ternary_shr_t64(t64_t a, int shift);
127135
t64_t __ternary_rol_t64(t64_t a, int shift);

runtime/ternary_runtime.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,72 @@ static uint64_t ternary_quantize_vector(float value, float threshold, unsigned t
370370
return result;
371371
}
372372

373+
static int ternary_tequiv_trit(int a, int b)
374+
{
375+
if (a == 0 || b == 0)
376+
return 0;
377+
return (a == b) ? 1 : -1;
378+
}
379+
380+
static uint64_t ternary_tequiv_u64(uint64_t a, uint64_t b, unsigned trit_count)
381+
{
382+
uint64_t out = 0;
383+
for (unsigned i = 0; i < trit_count; ++i) {
384+
int trit = ternary_tequiv_trit(ternary_get_trit(a, i), ternary_get_trit(b, i));
385+
out = ternary_set_trit(out, i, trit);
386+
}
387+
return out;
388+
}
389+
390+
static int ternary_txor_trit(int a, int b)
391+
{
392+
int sum = a + b;
393+
int mod = ((sum % 3) + 3) % 3;
394+
if (mod == 0)
395+
return 0;
396+
if (mod == 1)
397+
return 1;
398+
return -1;
399+
}
400+
401+
static uint64_t ternary_txor_u64(uint64_t a, uint64_t b, unsigned trit_count)
402+
{
403+
uint64_t out = 0;
404+
for (unsigned i = 0; i < trit_count; ++i) {
405+
int trit = ternary_txor_trit(ternary_get_trit(a, i), ternary_get_trit(b, i));
406+
out = ternary_set_trit(out, i, trit);
407+
}
408+
return out;
409+
}
410+
411+
static int64_t ternary_tnet_u64(uint64_t packed, unsigned trit_count)
412+
{
413+
int64_t net = 0;
414+
for (unsigned i = 0; i < trit_count; ++i)
415+
net += ternary_get_trit(packed, i);
416+
return net;
417+
}
418+
419+
static t32_t ternary_tmux_u32(t32_t sel, t32_t neg, t32_t zero, t32_t pos)
420+
{
421+
int64_t cond = ternary_decode((uint64_t)sel, 32);
422+
if (cond < 0)
423+
return neg;
424+
if (cond > 0)
425+
return pos;
426+
return zero;
427+
}
428+
429+
static t64_t ternary_tmux_u64(t64_t sel, t64_t neg, t64_t zero, t64_t pos)
430+
{
431+
int64_t cond = ternary_decode_u128((unsigned __int128)sel, 64);
432+
if (cond < 0)
433+
return neg;
434+
if (cond > 0)
435+
return pos;
436+
return zero;
437+
}
438+
373439
static unsigned __int128 ternary_majority_u128(unsigned __int128 a, unsigned __int128 b,
374440
unsigned __int128 c, unsigned trit_count)
375441
{
@@ -1003,6 +1069,26 @@ t32_t __ternary_tbias_t32(t32_t a, int64_t bias)
10031069
return (t32_t)ternary_tbias_u64((uint64_t)a, 32, bias);
10041070
}
10051071

1072+
t32_t __ternary_tequiv_t32(t32_t a, t32_t b)
1073+
{
1074+
return (t32_t)ternary_tequiv_u64((uint64_t)a, (uint64_t)b, 32);
1075+
}
1076+
1077+
t32_t __ternary_txor_t32(t32_t a, t32_t b)
1078+
{
1079+
return (t32_t)ternary_txor_u64((uint64_t)a, (uint64_t)b, 32);
1080+
}
1081+
1082+
int __ternary_tnet_t32(t32_t a)
1083+
{
1084+
return (int)ternary_tnet_u64((uint64_t)a, 32);
1085+
}
1086+
1087+
t32_t __ternary_tmux_t32(t32_t sel, t32_t neg, t32_t zero, t32_t pos)
1088+
{
1089+
return ternary_tmux_u32(sel, neg, zero, pos);
1090+
}
1091+
10061092
t64_t __ternary_tmin_t64(t64_t a, t64_t b)
10071093
{
10081094
return (t64_t)ternary_tritwise_op_u128((unsigned __int128)a, (unsigned __int128)b, 64, 0);
@@ -1061,6 +1147,26 @@ t64_t __ternary_tbias_t64(t64_t a, int64_t bias)
10611147
return (t64_t)ternary_tbias_u128((unsigned __int128)a, 64, bias);
10621148
}
10631149

1150+
t64_t __ternary_tequiv_t64(t64_t a, t64_t b)
1151+
{
1152+
return (t64_t)ternary_tequiv_u64((unsigned __int128)a, (unsigned __int128)b, 64);
1153+
}
1154+
1155+
t64_t __ternary_txor_t64(t64_t a, t64_t b)
1156+
{
1157+
return (t64_t)ternary_txor_u64((unsigned __int128)a, (unsigned __int128)b, 64);
1158+
}
1159+
1160+
int __ternary_tnet_t64(t64_t a)
1161+
{
1162+
return (int)ternary_tnet_u64((unsigned __int128)a, 64);
1163+
}
1164+
1165+
t64_t __ternary_tmux_t64(t64_t sel, t64_t neg, t64_t zero, t64_t pos)
1166+
{
1167+
return ternary_tmux_u64(sel, neg, zero, pos);
1168+
}
1169+
10641170
int __ternary_tbranch(TERNARY_COND_T cond, int neg_target, int zero_target, int pos_target)
10651171
{
10661172
return ternary_branch_target(cond, neg_target, zero_target, pos_target);

tests/test_logic_helpers

704 Bytes
Binary file not shown.

tests/test_logic_helpers.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ int main(void)
7272
expect_int("tsignjmp_zero", __ternary_tsignjmp_t64(__ternary_tb2t_t64(0), -1, 0, 1), 0);
7373
expect_int("tsignjmp_pos", __ternary_tsignjmp_t64(__ternary_tb2t_t64(3), -1, 0, 1), 1);
7474

75+
expect_int("tequiv_true", __ternary_tt2b_t32(__ternary_tequiv_t32(pos, pos)), 1);
76+
expect_int("tequiv_unknown", __ternary_tt2b_t32(__ternary_tequiv_t32(zero, pos)), 0);
77+
expect_int("tequiv_false", __ternary_tt2b_t32(__ternary_tequiv_t32(pos, neg)), -1);
78+
79+
expect_int("txor_zero", __ternary_tt2b_t32(__ternary_txor_t32(pos, neg)), 0);
80+
expect_int("txor_diff", __ternary_tt2b_t32(__ternary_txor_t32(pos, zero)), 1);
81+
expect_int("txor_same", __ternary_tt2b_t32(__ternary_txor_t32(pos, pos)), -1);
82+
83+
t32_t mux_lo = __ternary_tb2t_t32(1);
84+
t32_t mux_mid = __ternary_tb2t_t32(0);
85+
t32_t mux_hi = __ternary_tb2t_t32(-1);
86+
expect_int("tmux_neg", __ternary_tt2b_t32(__ternary_tmux_t32(__ternary_tb2t_t32(-1), mux_lo, mux_mid, mux_hi)), 1);
87+
expect_int("tmux_zero", __ternary_tt2b_t32(__ternary_tmux_t32(__ternary_tb2t_t32(0), mux_lo, mux_mid, mux_hi)), 0);
88+
expect_int("tmux_pos", __ternary_tt2b_t32(__ternary_tmux_t32(__ternary_tb2t_t32(1), mux_lo, mux_mid, mux_hi)), -1);
89+
90+
expect_int("tnet_one", __ternary_tnet_t32(__ternary_tb2t_t32(1)), 1);
91+
expect_int("tnet_minus", __ternary_tnet_t32(__ternary_tb2t_t32(-1)), -1);
92+
7593
tv64_t v_lo = { __ternary_tb2t_t64(1), __ternary_tb2t_t64(2) };
7694
tv64_t v_hi = { __ternary_tb2t_t64(3), __ternary_tb2t_t64(-1) };
7795
tv64_t added = __ternary_add_tv64(v_lo, v_hi);

tests/test_varargs

16.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)