Ternary computer TRINITY-2004
Moderator: haqreu
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Ternary computer TRINITY-2004
Some draft architecture of ternary machine that may be built practically, designed by me in December 2004:
Ternary computer TRINITY will have data bus with width 3 trits (triad). Every trit can be in one of 3 state: N (-1), O (0), P (+1). 1 triad can be in one of 27 states: from NNN (-13) to PPP (+13).
TRINITY will have linear memory where address bus will have width 9 trits (in current prototype I plan to use only 8 trits - highest trit will be always 0). Memory itself will be regular "binary" chips (2 bits per 1 trit), because ternary memory is not yet available and it's almost impossible to create one "manually" using "flip-flap-flops". Address space is divided to 3 parts:
-3280...-1094: space for peripheral devices (ternary or binary);
-1093...+1093: space for ROM with basic system program;
+1094...+3280: space for RAM with user program/data.
There are 9 directly available registers:
-4 Dn: triad from memory by address DPn (see below);
-3 Do: triad from memory by address DPo (see below);
-2 Dp: triad from memory by address DPp (see below);
-1 F: flag register (RSF-ResultSignFlag, DPF-DataPointerFlag, BCF-BorrowCarryFlag);
0 A: accumulator register;
+1 B: auxiliary register;
+2 Dl: lower triad of data pointer;
+3 Dm: middle triad of data pointer;
+4 Dh: higher triad of data pointer.
Data pointer actually is set of 3 9-trits data pointer register, available through Dl/Dm/Dh and multiplexed by flag DPF and we may name that 9-trit registers DPn, DPo, DPp.
Register PC (program counter) is not available directly.
Command set has 3 groups of commands: load register A from other register (P??), save register A to other register (N??) and other commands (O??):
ONN - RLA: rotate register A to the left through flag BCF;
ONO - ADD: add A with B and BCF, save result to A and BCF;
ONP - RRA: shift register A to the right through flag BCF:
OON - LAI #: load A by immediate triad;
OOO - ADI #: add A with immediate triad and BCF, save result to A and BCF;
OOP - OPA #: unary "tritwise" operation over register A (function set by immediate triad);
OPN - LDI # # #: load to current data pointer (D2 D1 D0) immediate 3 triads;
OPO - JMP # # #: jump to address set by immediate 3 triads (put it ot register PC: Ph Pm Pl);
OPP - OPB # # #: binary "tritwise" operation over registers A and B, save result to A (function set by 3 immediate triads).
Flag RSF not always has sign (-1, 0, +1) of accumulator A value as I assumed before, because in some cases it's not changed when A changed.
Command of loading register A is written as LAr (P??), where r is name of source register.
Command of saving regster A is written as SAr (N??), where r is name of destination register.
You can see that we have couple of nonsense commands there (SAA - save A to A and LAA - load A from A). Instead of it on the same opcodes we will have 2 new ones:
POO - LPCD: load PC from D (Pl=Dl, Pm=Dm, Ph=Dh);
NOO - SPCD: save PC to D (Dl=Pl, Dm=Pm, Dh=Ph).
UPDATE: In 2008 this design was finilized and renamed to "3niti alpha": http://3niti.org/wiki/?n=Alpha.About
Ternary computer TRINITY will have data bus with width 3 trits (triad). Every trit can be in one of 3 state: N (-1), O (0), P (+1). 1 triad can be in one of 27 states: from NNN (-13) to PPP (+13).
TRINITY will have linear memory where address bus will have width 9 trits (in current prototype I plan to use only 8 trits - highest trit will be always 0). Memory itself will be regular "binary" chips (2 bits per 1 trit), because ternary memory is not yet available and it's almost impossible to create one "manually" using "flip-flap-flops". Address space is divided to 3 parts:
-3280...-1094: space for peripheral devices (ternary or binary);
-1093...+1093: space for ROM with basic system program;
+1094...+3280: space for RAM with user program/data.
There are 9 directly available registers:
-4 Dn: triad from memory by address DPn (see below);
-3 Do: triad from memory by address DPo (see below);
-2 Dp: triad from memory by address DPp (see below);
-1 F: flag register (RSF-ResultSignFlag, DPF-DataPointerFlag, BCF-BorrowCarryFlag);
0 A: accumulator register;
+1 B: auxiliary register;
+2 Dl: lower triad of data pointer;
+3 Dm: middle triad of data pointer;
+4 Dh: higher triad of data pointer.
Data pointer actually is set of 3 9-trits data pointer register, available through Dl/Dm/Dh and multiplexed by flag DPF and we may name that 9-trit registers DPn, DPo, DPp.
Register PC (program counter) is not available directly.
Command set has 3 groups of commands: load register A from other register (P??), save register A to other register (N??) and other commands (O??):
ONN - RLA: rotate register A to the left through flag BCF;
ONO - ADD: add A with B and BCF, save result to A and BCF;
ONP - RRA: shift register A to the right through flag BCF:
OON - LAI #: load A by immediate triad;
OOO - ADI #: add A with immediate triad and BCF, save result to A and BCF;
OOP - OPA #: unary "tritwise" operation over register A (function set by immediate triad);
OPN - LDI # # #: load to current data pointer (D2 D1 D0) immediate 3 triads;
OPO - JMP # # #: jump to address set by immediate 3 triads (put it ot register PC: Ph Pm Pl);
OPP - OPB # # #: binary "tritwise" operation over registers A and B, save result to A (function set by 3 immediate triads).
Flag RSF not always has sign (-1, 0, +1) of accumulator A value as I assumed before, because in some cases it's not changed when A changed.
Command of loading register A is written as LAr (P??), where r is name of source register.
Command of saving regster A is written as SAr (N??), where r is name of destination register.
You can see that we have couple of nonsense commands there (SAA - save A to A and LAA - load A from A). Instead of it on the same opcodes we will have 2 new ones:
POO - LPCD: load PC from D (Pl=Dl, Pm=Dm, Ph=Dh);
NOO - SPCD: save PC to D (Dl=Pl, Dm=Pm, Dh=Ph).
UPDATE: In 2008 this design was finilized and renamed to "3niti alpha": http://3niti.org/wiki/?n=Alpha.About
-
- Maniac
- Posts: 277
- Joined: 17 Sep 2012 13:36
- Location: 81.170.128.52
Re: Ternary computer TRINITY (Dec 2004)
Interesting architecture...
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY (Dec 2004)
Design has a few problems, but I didn't have enough time to fix it...eudoxie wrote: Interesting architecture...
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
Implementation of ternary conditional branch:
Code: Select all
; set pointers for ternary branch
LAN #ONO ; load A from number (O is zero)
SAF ; save A to F
LDP PointerN ; set address for N
LAN #OOO ; load A from number
SAF ; save A to F
LDP PointerO ; set address for O
LAN #OPO ; load A from number
SAF ; save A to F
LDP PointerP ; set address for P
Code: Select all
; this is conditional branch by ASF state:
LAF ; load A from F
SRA ; shift A right (put ASF to DPF)
SAF ; save A to F
LPD ; load P from D (load true pointer)
Code: Select all
; this is conditional branch by BCF state:
LAF ; load A from F
SLA ; shift A left (put BCF to DPF)
SAF ; save A to F
LPD ; load P from D (load true pointer)
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
Call subroutine with saving return address in 9-trit register DPo (available in 3-trit registers Dl/Dm/Dh if DPF=O):
Return from subprogram to address saved in DPo:
Full return stack implementation is much more heavy...
Code: Select all
LAN #OOO
SAF ; set DPo
LDP return_adr ; load data pointer
JMP subprg_adr ; call subprogram
return_adr:
Code: Select all
LAN #OOO
SAF ; set DPo
LPD ; load P from D
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
Some words about universal operations OPA and OPB:
Operation OPA #ttt may describe ANY unary "tritwise" operation over accumulator A. For example:
OPA #OOO means set A to 0 (N -> O, O -> O, P -> O);
OPA #PON means ternary inversion or negation (N -> P, O -> O, P -> N);
OPA #OPN means "Shift Up" (N -> O, O -> P, P -> N);
OPA #NOP means "No Operation" (N -> N, O -> O, P -> P).
Operation OPB Tn To Tp may describe ANY binary "tritwise" operation over accumulator A and auxiliary register B. Rule for every trit in A: if trit value in register B is N then choose Tn, if trit value in register B is O then choose To, if trit value in register B is P then choose Tp, then use chosen triad as for OPA operation (lower trit for N, middle trit for O, higher trit for P). For example, using OPB for masking of flag BCF in F:
After that BCF will keep its value, but other trits will set to N.
Operation OPA #ttt may describe ANY unary "tritwise" operation over accumulator A. For example:
OPA #OOO means set A to 0 (N -> O, O -> O, P -> O);
OPA #PON means ternary inversion or negation (N -> P, O -> O, P -> N);
OPA #OPN means "Shift Up" (N -> O, O -> P, P -> N);
OPA #NOP means "No Operation" (N -> N, O -> O, P -> P).
Operation OPB Tn To Tp may describe ANY binary "tritwise" operation over accumulator A and auxiliary register B. Rule for every trit in A: if trit value in register B is N then choose Tn, if trit value in register B is O then choose To, if trit value in register B is P then choose Tp, then use chosen triad as for OPA operation (lower trit for N, middle trit for O, higher trit for P). For example, using OPB for masking of flag BCF in F:
Code: Select all
LAN #NNP
SAB ; set B to #NNP (mask for BCF)
LAF ; load A from F
OPB #NNN #NOO #NOP ; operation MIN (ternary AND)
-
- Maniac
- Posts: 277
- Joined: 17 Sep 2012 13:36
- Location: 81.170.128.52
Re: Ternary computer TRINITY
It's a bit claustrophobic, with the small data units. You can't store very much information with only 27 states, and storing in several data units creates overhead; which would be a problem in general purpose applications.Shaos wrote:Design has a few problems, but I didn't have enough time to fix it...eudoxie wrote: Interesting architecture...
Though, I can imagine special purpose applications, like signal processing, where this sort of machine could be very useful.
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
Yes, it's kind of minimalistic, but main idea is ability almost for everyone to build this machine at homeeudoxie wrote:
It's a bit claustrophobic, with the small data units. You can't store very much information with only 27 states, and storing in several data units creates overhead; which would be a problem in general purpose applications.
Though, I can imagine special purpose applications, like signal processing, where this sort of machine could be very useful.

-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
I simply translated it in English from my Russian message from Dec 2004. No time to check correctness...Shaos wrote: Call subroutine with saving return address in 9-trit register DPo (available in 3-trit registers Dl/Dm/Dh if DPF=O):
Return from subprogram to address saved in DPo:Code: Select all
LAN #OOO SAF ; set DPo LDP return_adr ; load data pointer JMP subprg_adr ; call subprogram return_adr:
Full return stack implementation is much more heavy...Code: Select all
LAN #OOO SAF ; set DPo LPD ; load P from D
Lets use stack of return addresses with depth 9 (27 triads).
Stack pointer will move from xxx xxx PPP to xxx xxx NNN (only Dl changed).
Stack pointer may be DPp, so first initialization is 7 triads:
Code: Select all
LDN #OPO
SAF ; set DPp
LDP StackAddress ; xxx xxx NNN (trick NNN-1=PPP)
Code: Select all
LDN #OOO
SAF ; set DPo
LDP ReturnAddress ; any address
LDN #OPO
SAF ; set DPp
LADl
ADN -1
SADl
LDN #OOO
SAF ; set DPo
LADl
SADp
LDN #OPO
SAF ; set DPp
LADl
ADN -1
SADl
LDN #OOO
SAF ; set DPo
LADm
SADp
LDN #OPO
SAF ; set DPp
LADl
ADN -1
SADl
LDN #OOO
SAF ; set DPo
LADh
SADp
JMP SubprogramAddress
ReturnAddress:
...
Code: Select all
...
LDN #OOO
SAF ; set DPo
LADp
SADh
LDN #OPO
SAF ; set DPp
LADl
ADN 1
SADl
LDN #OOO
SAF ; set DPo
LADp
SADm
LDN #OPO
SAF ; set DPp
LADl
ADN 1
SADl
LDN #OOO
SAF ; set DPo
LADp
SADl
LDN #OPO
SAF ; set DPp
LADl
ADN 1
SADl
LDN #OOO
SAF ; set DPo
LPD ; load P from D
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
I have an idea about renaming registers to do names 1-character:
-4 N: triad from memory addressed by DPn (see below);
-3 O: triad from memory addressed by DPo (see below);
-2 P: triad from memory addressed by DPp (see below);
-1 F: flag register (see below);
0 A: accumulator register;
+1 B: auxiliary register;
+2 L: lower triad of current DP register (see below);
+3 M: middle triad of current DP register (see below);
+4 H: higher triad of current DP register (see below);
Register F is set of 3 flags:
Higher trit: RSF (Result Sign Flag)
Middle trit: DPF (Data Pointer Flag)
Lower trit: BCF (Borrow Carry Flag)
There are 3 9-trit DP (data pointer) registers - DPn, DPo, DPp, available through L/M/H when flag DPF has corresponding value (N, O, P).
To separate meanings of P and PC we need to rename opcodes #POO and #NOO to LPCD and SPCD respectively. We need to rename opcodes #ONN and #ONP to RLA and RRA respectively ('R'otate instead of 'S'hift). Also we need to rename opcodes #OON, #OOO and #OPN to LAI, ADI and LDI respectively ('I'mmediate).
So full set of opcodes is:
#NNN (-13) SAN - save register A to register N;
#NNO (-12) SAO - save register A to register O;
#NNP (-11) SAP - save register A to register P;
#NON (-10) SAF - save register A to register F;
#NOO (-9) SPCD - save PC (program counter) to current data pointer;
#NOP (-8) SAB - save register A to register B;
#NPN (-7) SAL - save register A to register L (lower triade of current data pointer);
#NPO (-6) SAM - save register A to register M (middle triade of current data pointer);
#NPP (-5) SAH - save register A to register H (higher triade of current data pointer);
#ONN (-4) RLA - rotate register A to the left through flag BCF;
#ONO (-3) ADD - add register A with B and flag BCF, save result to A and BCF;
#ONP (-2) RRA - rotate register A to the right through flag BCF;
#OON (-1) LAI # - load register A from immediate triad;
#OOO (0) ADI # - add register A with immediate triad and flag BCF, save result to A and BCF;
#OOP (1) OPA # - perform unary "tritwise" operation over register A (function set by immediate triad);
#OPN (2) LDI # # # - load current data pointer by immediate 3 triads (lower, middle, higher);
#OPO (3) JMP # # # - jump to address set by immediate 3 triads (put it to register PC: lower, middle, higher);
#OPP (4) OPB # # # - perform binary "tritwise" operation over registers A and B, save result to A (function set by immediate 3 triad);
#PNN (5) LAN - load register A from register N;
#PNO (6) LAO - load register A from register O;
#PNP (7) LAP - load register A from register P;
#PON (8) LAF - load register A from register F;
#POO (9) LPCD - load PC (program counter) from current data pointer;
#POP (10) LAB - load register A from register B;
#PPN (11) LAL - load register A from register L (lower triad of current data pointer);
#PPO (12) LAM - load register A from register M (middle triad of current data pointer);
#PPP (13) LAH - load register A from register H (higher triad of current data pointer);
-4 N: triad from memory addressed by DPn (see below);
-3 O: triad from memory addressed by DPo (see below);
-2 P: triad from memory addressed by DPp (see below);
-1 F: flag register (see below);
0 A: accumulator register;
+1 B: auxiliary register;
+2 L: lower triad of current DP register (see below);
+3 M: middle triad of current DP register (see below);
+4 H: higher triad of current DP register (see below);
Register F is set of 3 flags:
Higher trit: RSF (Result Sign Flag)
Middle trit: DPF (Data Pointer Flag)
Lower trit: BCF (Borrow Carry Flag)
There are 3 9-trit DP (data pointer) registers - DPn, DPo, DPp, available through L/M/H when flag DPF has corresponding value (N, O, P).
To separate meanings of P and PC we need to rename opcodes #POO and #NOO to LPCD and SPCD respectively. We need to rename opcodes #ONN and #ONP to RLA and RRA respectively ('R'otate instead of 'S'hift). Also we need to rename opcodes #OON, #OOO and #OPN to LAI, ADI and LDI respectively ('I'mmediate).
So full set of opcodes is:
#NNN (-13) SAN - save register A to register N;
#NNO (-12) SAO - save register A to register O;
#NNP (-11) SAP - save register A to register P;
#NON (-10) SAF - save register A to register F;
#NOO (-9) SPCD - save PC (program counter) to current data pointer;
#NOP (-8) SAB - save register A to register B;
#NPN (-7) SAL - save register A to register L (lower triade of current data pointer);
#NPO (-6) SAM - save register A to register M (middle triade of current data pointer);
#NPP (-5) SAH - save register A to register H (higher triade of current data pointer);
#ONN (-4) RLA - rotate register A to the left through flag BCF;
#ONO (-3) ADD - add register A with B and flag BCF, save result to A and BCF;
#ONP (-2) RRA - rotate register A to the right through flag BCF;
#OON (-1) LAI # - load register A from immediate triad;
#OOO (0) ADI # - add register A with immediate triad and flag BCF, save result to A and BCF;
#OOP (1) OPA # - perform unary "tritwise" operation over register A (function set by immediate triad);
#OPN (2) LDI # # # - load current data pointer by immediate 3 triads (lower, middle, higher);
#OPO (3) JMP # # # - jump to address set by immediate 3 triads (put it to register PC: lower, middle, higher);
#OPP (4) OPB # # # - perform binary "tritwise" operation over registers A and B, save result to A (function set by immediate 3 triad);
#PNN (5) LAN - load register A from register N;
#PNO (6) LAO - load register A from register O;
#PNP (7) LAP - load register A from register P;
#PON (8) LAF - load register A from register F;
#POO (9) LPCD - load PC (program counter) from current data pointer;
#POP (10) LAB - load register A from register B;
#PPN (11) LAL - load register A from register L (lower triad of current data pointer);
#PPO (12) LAM - load register A from register M (middle triad of current data pointer);
#PPP (13) LAH - load register A from register H (higher triad of current data pointer);
Last edited by Shaos on 20 Sep 2012 20:43, edited 1 time in total.
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
Lets name this instruction set as "TRINITY-2004" (year of design)
It can be used as microcode for next generation of TRINITY processor!
1 trit - 3 values (N,O,P or -1,0,+1);
1 triad (3 trits) - 27 values;
1 tryte (6 trits, 2 triads) - 729 values;
1 tradr (9 trits, 3 triads) - 19 683 values;
1 trord (12 trits, 4 triads, 2 trytes) - 531 441 values;
1 truadr (18 trits, 6 triads, 3 trytes, 2 tradrs) - 387 420 489 values;
1 truble (24 trits, 8 triads, 4 trytes, 2 trords) - 282 429 536 481 values;
New words "tradr" and "trord" mean "ternary address" and "ternary word" respectively
New words "truadr" and "truble" mean "double ternary address" and "double ternary word" respectively
P.S. And "tribble" must be 2 trits (3 tribbles = 1 tryte)
It can be used as microcode for next generation of TRINITY processor!
1 trit - 3 values (N,O,P or -1,0,+1);
1 triad (3 trits) - 27 values;
1 tryte (6 trits, 2 triads) - 729 values;
1 tradr (9 trits, 3 triads) - 19 683 values;
1 trord (12 trits, 4 triads, 2 trytes) - 531 441 values;
1 truadr (18 trits, 6 triads, 3 trytes, 2 tradrs) - 387 420 489 values;
1 truble (24 trits, 8 triads, 4 trytes, 2 trords) - 282 429 536 481 values;
New words "tradr" and "trord" mean "ternary address" and "ternary word" respectively

New words "truadr" and "truble" mean "double ternary address" and "double ternary word" respectively

P.S. And "tribble" must be 2 trits (3 tribbles = 1 tryte)
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
Idea about representation of floating point numbers: Lets take "truble" and divide it to 2 parts: 6-trit exponent and 18-trit fraction. By accuracy it is better than 32-bit "float", worse than 64-bit "double" and similar to 36-bit floating number in IBM System/360 from 1964 that had 9-bit sign and exponent and 27-bit fraction. Because of nature of balanced ternary numeric system we don't need "biasing" exponent. Also we don't need separate sign bit - we simply combine it with "hidden" most significant bit of fraction instead and it will be part of full 18-trit fraction. So range of exponent is from -364 to +364 (3^6/2) and fraction from -193710244 to +193710244 (3^18/2 that is max possible integer represented by this floating point format). To simplify formula for calculation number from representation we may simply forget about "fractional" nature of fraction and say F*3^E
P.S. here ^ means "power"

P.S. here ^ means "power"
-
- Retired
- Posts: 1474
- Joined: 03 Aug 2003 22:37
- Location: Moscow
Re: Ternary computer TRINITY
So, let's take the representation as a basic representation of fractional numbers for ternary platform.
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
Right now I think that ability to compare normalized floating point numbers as integers is good and to have it we should do "fraction" really fractional (-1 < F < 1): (F*3^18)*3^E = F*3^(18+E). In this case for example to do float from integer 193710244 (PPPPPPPPPPPPPPPPPP) we have to add exponent +18 (OOPNOO): OOPNOOPPPPPPPPPPPPPPPPPP (here fraction is O.PPPPPPPPPPPPPPPPPP). Also to represent 0.5 we will use OOOOOOPPPPPPPPPPPPPPPPPP (error is 0.00000000258).
P.S. But in case of integer "fraction" described in my previous post we still can use normalization as shifting to the left and comparison "normalized" floating point numbers as regular integers...
P.S. But in case of integer "fraction" described in my previous post we still can use normalization as shifting to the left and comparison "normalized" floating point numbers as regular integers...
Last edited by Shaos on 20 Sep 2012 20:43, edited 1 time in total.
-
- Admin
- Posts: 24036
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Re: Ternary computer TRINITY
I forgot one important feature of balanced ternary numeric system - fractional number may NOT have a ZERO in integer part of balanced ternary representation!
For example P.N is 0.666...
For example P.N is 0.666...