Close
0%
0%

Homebrew ternary computer

TRIADOR: The only ternary computer made for real in the past 50 years.

Public Chat
Similar projects worth following
Many claimed to build a ternary computer, however nobody (to the best of my knowledge) completed the project. TRIADOR project makes no empty promises!

In this project we are trying to build a very simple but functional 3-trit balanced ternary computer. The only building block allowed is a ternary multiplexer based on DG403 analog switches. 

 ══════════════════════════════════════════════════════════
        Description of the ternary computer TRIADOR
 ══════════════════════════════════════════════════════════
  General purpose
     registers
 trits 2 1 0  (a trit can take -1,0,+1 values)
      ┌─┬─┬─┐
    R1│ │ │ │ \
      ├─┼─┼─┤ |                              Program memory
    R2│ │ │ │ |                            trits 4 3 2 1 0
      ├─┼─┼─┤ |-- main set                      ┌─┬─┬─┬─┬─┐
    R3│ │ │ │ |   of registers           a  -364│ │ │ │ │ │
      ├─┼─┼─┤ |                          d      ├─┼─┼─┼─┼─┤
    R4│ │ │ │ /                          d  -363│ │ │ │ │ │
      ├─┼─┼─┤                            r      ├─┼─┼─┼─┼─┤
    R5│ │ │ │ \                          e  -362│ │ │ │ │ │
      ├─┼─┼─┤ |                          s      ├─┼─┼─┼─┼─┤
    R6│ │ │ │ |                          s      : : : : : :
      ├─┼─┼─┤ |                                 ├─┼─┼─┼─┼─┤
    R7│ │ │ │ |                              -1 │ │ │ │ │ │
      ├─┼─┼─┤ |                                 ├─┼─┼─┼─┼─┤
    R8│ │ │ │ |                               0 │ │ │ │ │ │
      ├─┼─┼─┤ |-- extra registers               ├─┼─┼─┼─┼─┤
    R9│ │ │ │ |                              +1 │ │ │ │ │ │
      ├─┼─┼─┤ |                                 ├─┼─┼─┼─┼─┤
   R10│ │ │ │ |                                 : : : : : :
      ├─┼─┼─┤ |                                 ├─┼─┼─┼─┼─┤
   R11│ │ │ │ |                             +363│ │ │ │ │ │
      ├─┼─┼─┤ |                                 ├─┼─┼─┼─┼─┤
   R12│ │ │ │ /                             +364│ │ │ │ │ │
      ├─┼─┼─┤                                   └─┴─┴─┴─┴─┘
   R13│ │ │ │ Special register,
      └─┴─┴─┘ specifies memory segment for JP ttt
      ┌─┬─┬─┬─┬─┬─┐
   PC │ │ │ │ │ │ │ program counter register (-364..+364)
      └─┴─┴─┴─┴─┴─┘
      ┌─┐
    C │ │ borrow/carry flag (+1 borrow, -1 carry)
      └─┘

  Every 3-trit register can take values from -13 to +13:

  t2*9 + t1*3 + t0

  where t0,t1,t2 - trits (-1,0,+1)

 ═══════════════════════════════════════════════════════════
                 TRIADOR instruction set
 ═══════════════════════════════════════════════════════════
  (for lisibility we use N,O,P instead of -1,0,+1)
  ┌───────┬────────┬───────────────────────────────────────┐
  │op code│mnemonic│ description                           │
  ├───────┼────────┼───────────────────────────────────────┤
  │ NNttt │ EX ttt │ extension commands (work in progress) │
  ├───────┼────────┼───────────────────────────────────────┤
  │ NOttt │ JP ttt │ unconditional jump to R13*27+ttt      │
  ├───────┼────────┼───────────────────────────────────────┤
  │ NPttt │ SK ttt │ conditional skips of the next command │
  ├───────┼────────┼───────────────────────────────────────┤
  │ ONttt │ OP ttt │ tritwise unary operation over R1      │
  ├───────┼────────┼───────────────────────────────────────┤
  │ OOttt │ RR ttt │ copying between registers             │
  ├───────┼────────┼───────────────────────────────────────┤
  │ OPttt │ R1 ttt │ write ttt to the register R1          │
  ├───────┼────────┼───────────────────────────────────────┤
  │ PNttt │ R2 ttt │ write ttt to the register R2          │
  ├───────┼────────┼───────────────────────────────────────┤
  │ POttt │ R3 ttt │ write ttt to the register R3          │
  ├───────┼────────┼───────────────────────────────────────┤
  │ PPttt │ R4 ttt │ write ttt to the register R4          │
  └───────┴────────┴───────────────────────────────────────┘

  Additional comments:
  - ttt means a 3-trit number with values
    from NNN (-13) to PPP (+13)

  - RR ttt instruction copies a register to/from R1 or performs
    an increment/decrement over R1
    OONNN — copy R1 to R13
    OONNO — copy R1 to R12
    OONNP — copy R1 to R11
    OONON — copy R1 to R10
    OONOO — copy R1 to R9
 OONOP...
Read more »

ternary.vhd

Ternary VHDL package v1.0

x-vhdl - 7.30 kB - 07/06/2018 at 09:18

Download

ternary_circ.zip

Archive with TRIADOR simulation for Logisim v2.7.1 and also couple TXT files with some details from Shaos

Zip Archive - 49.99 kB - 06/23/2018 at 04:32

Download

TRIADOR.TXT

Specification of ternary computer TRIADOR (DOS encoding with pseudographics)

plain - 7.88 kB - 12/17/2017 at 23:58

Download

  • 600 × dg403dy Switches and Multiplexers / Analog Switches and Multiplexers

  • TRIADOR ALU

    Dmitry V. Sokolov07/10/2018 at 19:39 0 comments

    Back to the true ternary triador implementation. The ALU will look like this:

    Compare it to the overall schematics of the triador in the project details. All input signals are shown on the left of the boxes, all output signals are on the right. The ALU consists of 5 slices (one per operation) plus one trit memory cell for the borrow/carry flag. This flag won't be accessible outside of the ALU, its value is set by the RR slice, and is read by the SK slice only.

    Just to give you an idea of what the boxes look inside, here is the OP box (tritwise unary operation over R1 register):

  • Ternary counter on VHDL

    SHAOS07/08/2018 at 09:26 2 comments

    I just literally copied this ternary counter design from 2011 into VHDL:

    This is VHDL source code (only 3 trits were used):

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    
    use ternary.all;
    
    entity main is
        Port ( clk : in bit;
               res : in bit;
               a : in FakeTrit;
               b : in FakeTrit;
               c : in FakeTrit;
               s1 : out FakeTrit;
               s2 : out FakeTrit;
               s3 : out FakeTrit;
               led : out bit);
    end main;
    
    architecture Behavioral of main is
    signal a1,b1,c1,ss0,ss1,ss2,ss3,ss4 : FakeTrit;
    signal pclk,pclk1,nclk,nclk1,res0,res1,m1,m2,m3,m4,h1,h2,h3,h4,g1,g2,g3 : FakeTrit;
    signal tmp_clk_std, tmp_iclk_std : STD_LOGIC;
    signal tmp_clk : BIT;
    
    COMPONENT Clock_Divider
    PORT(
    clk : IN std_logic;
    reset : IN std_logic;
    clock_out : OUT std_logic
    );
    END COMPONENT;
    
    COMPONENT Half_Adder
    Port ( a : in FakeTrit;
           b : in FakeTrit;
           s : out FakeTrit;
           c : out FakeTrit
          );
    END COMPONENT;      
    
    FUNCTION io_invert(T: FakeTrit) RETURN FakeTrit IS
    begin
                    case T is
                    when N =>
                            return P;
                    when O =>
                            return X;
                    when P =>
                            return N;
                    when others =>
                            return O;
                    end case;
    end;
          
    begin
    
    a1 <= io_invert(a);
    b1 <= io_invert(b);
    c1 <= io_invert(c);
    
    tmp_iclk_std <= to_stdulogic(clk);
    div1: Clock_Divider port map( clk => tmp_iclk_std, reset => '0', clock_out => tmp_clk_std );
    tmp_clk <= to_bit(tmp_clk_std);
    
    res0(0) <= '0';
    res0(1) <= res;
    res1 <= res0;
    
    clk1: ternary_clock port map( B_C => tmp_clk, T_C => ss0 );
    mux1: ternary_mux port map( T_S => ss0, T_N => O, T_O => O, T_P => P, T_C => pclk );
    mux2: ternary_mux port map( T_S => res1, T_N => pclk, T_O => N, T_P => N, T_C => pclk1 );
    mux3: ternary_mux port map( T_S => ss0, T_N => N, T_O => O, T_P => O, T_C => nclk );
    mux4: ternary_mux port map( T_S => res1, T_N => nclk, T_O => P, T_P => P, T_C => nclk1 );
    
    mem1: ternary_mem port map( T_S => pclk1, T_N => O, T_P => ss1, T_Q => m1 );
    ha1: Half_Adder port map( a => P, b => m1, s => h1, c => g1 );
    mem2: ternary_mem port map( T_S => nclk1, T_N => h1, T_P => O, T_Q => ss1 );
    
    mem3: ternary_mem port map( T_S => pclk1, T_N => O, T_P => ss2, T_Q => m2 );
    ha2: Half_Adder port map( a => g1, b => m2, s => h2, c => g2 );
    mem4: ternary_mem port map( T_S => nclk1, T_N => h2, T_P => O, T_Q => ss2 );
    
    mem5: ternary_mem port map( T_S => pclk1, T_N => O, T_P => ss3, T_Q => m3 );
    ha3: Half_Adder port map( a => g2, b => m3, s => h3, c => g3 );
    mem6: ternary_mem port map( T_S => nclk1, T_N => h3, T_P => O, T_Q => ss3 );
    
    s1 <= io_invert(ss1);
    s2 <= io_invert(ss2);
    s3 <= io_invert(ss3);
    
    led <= to_bit(tmp_clk_std);
    
    end Behavioral;

    Every trit in the counter takes 2 macrocells on CoolRunner-II, so technically CoolRunner-II chip XC2C256 with 256 macrocells may have up to 128-trit counter inside! This is pin assignments for XC2-XL board (a,b,c are not used here):

    NET "clk" LOC = "P38" | IOSTANDARD = LVTTL ; 
    NET "res" LOC = "P143" | IOSTANDARD = LVTTL ; 
    NET "a<0>"  LOC = "P140" | IOSTANDARD = LVTTL ; 
    NET "a<1>"  LOC = "P142" | IOSTANDARD = LVTTL ; 
    NET "b<0>"  LOC = "P138" | IOSTANDARD = LVTTL ; 
    NET "b<1>"  LOC = "P139" | IOSTANDARD = LVTTL ; 
    NET "c<0>"  LOC = "P136" | IOSTANDARD = LVTTL ; 
    NET "c<1>"  LOC = "P137" | IOSTANDARD = LVTTL ; 
    NET "s3<0>"  LOC = "P82" | IOSTANDARD = LVTTL ; 
    NET "s3<1>"  LOC = "P83" | IOSTANDARD = LVTTL ; 
    NET "s2<0>"  LOC = "P85" | IOSTANDARD = LVTTL ; 
    NET "s2<1>"  LOC = "P86" | IOSTANDARD = LVTTL ; 
    NET "s1<0>"  LOC = "P87" | IOSTANDARD = LVTTL ; 
    NET "s1<1>"  LOC = "P88" | IOSTANDARD = LVTTL ; 
    NET "led"  LOC = "P92" | IOSTANDARD = LVTTL ; 
    

    and this is a video that proves that it's working on Xilinx CoolRunner-II ;) 

  • Ternary VHDL package v1.0 is ready

    SHAOS07/06/2018 at 09:30 0 comments

    So now we have everything to build a ternary computer in binary CPLD (or FPGA)::

    https://cdn.hackaday.io/files/285791222723936/ternary.vhd

    Last pieces were just added:

    - procedure dmux:

            PROCEDURE dmux(signal T_S: IN FakeTrit;
                           signal T_C: IN FakeTrit;
                           signal T_N: OUT FakeTrit;
                           signal T_O: OUT FakeTrit;
                           signal T_P: OUT FakeTrit) IS
            begin
                    case T_S is
                    when N =>
                            T_N <= T_C;
                            T_O <= O;
                            T_P <= O;
                    when O =>
                            T_N <= O;
                            T_O <= T_C;
                            T_P <= O;
                    when P =>
                            T_N <= O;
                            T_O <= O;
                            T_P <= T_C;
                    when others =>
                            T_N <= X;
                            T_O <= X;
                            T_P <= X;
                    end case;
            end;
    

    - component ternary_mem:

    -- Entity ternary_mem
    
    USE ternary.ALL;
    
    ENTITY ternary_mem IS
            PORT (
                  T_S : IN FakeTrit;
                  T_N : IN FakeTrit;
                  T_P : IN FakeTrit;
                  T_Q : OUT FakeTrit
            );
    END ternary_mem;
    
    ARCHITECTURE Behavioral OF ternary_mem IS
    BEGIN
        PROCESS (T_S)
        BEGIN
            IF (T_S(0) = '1') THEN
                T_Q <= T_P;
            ELSIF (T_S(1) = '1') THEN
                T_Q <= T_N;
            END IF;
        END PROCESS;
    END Behavioral;
    
      - component ternary_clock:
    -- Entity ternary_clock
    
    USE ternary.ALL;
    
    ENTITY ternary_clock IS
            PORT (
                  B_C : IN BIT;
                  T_C : OUT FakeTrit
            );
    END ternary_clock;
    
    ARCHITECTURE Behavioral OF ternary_clock IS
    signal flag : bit;
    BEGIN
        PROCESS (B_C)
        BEGIN
            IF (B_C'event AND B_C = '1') THEN
                IF (flag = '0') THEN
                    flag <= '1';
                ELSE
                    flag <= '0';
                END IF;
            END IF;
            IF (B_C = '1' AND flag = '0') THEN
                T_C(0) <= '1';
            ELSE
                T_C(0) <= '0';
            END IF;
            IF (B_C = '1' AND flag = '1') THEN
                T_C(1) <= '1';
            ELSE
                T_C(1) <= '0';
            END IF;
        END PROCESS;
    END Behavioral;
    

    Last one turns binary clock into ternary sequence NOPONOPONOPO...

    Also I renamed some variable names and added additional components for mux and dmux ( just in case if somebody doesn't like them as functions ; )

  • Interfacing ternary and binary components

    SHAOS07/05/2018 at 04:15 0 comments

    Ok, now it is kind of proven that binary CPLD (or FPGA) may implement ternary logic, but how we can integrate it with "true" ternary components, especially when CPLD is 3.3V and TRIMUXes are -5V and +5V? Answer is DG403 chips may do the job:

    Because simplified ternary mutexes e12 and e21 can be easily implemented by DG403 integrated circuits:

    So we need to have ONE DG403 per every binary represented TRIT and it doesn't matter if it's input or output, but number of inputs should be multiple by 2 in order to use DG403 chips optimally.
    Also we can do similar interfacing for binary ROM or RAM that may also be required for complex ternary systems. For example we can do translation from triad (3 trits) to a byte the same way how it's already done in 3niti alpha simu1 ternary computer simulator on PIC16:
    ;Format of the triad:
    ;|7|6|5|4|3|2|1|0|
    ;|+|-|+|-|+|-|+|-|
    ;|par|low|mid|high
    ;par (parity) is not yet used, so it's always 0 0 for now...
    
    tOOO    EQU    0x00 ; 0
    tNOO    EQU    0x01 ; -9
    tPOO    EQU    0x02 ; +9
    tONO    EQU    0x04 ; -3
    tNNO    EQU    0x05 ; -12
    tPNO    EQU    0x06 ; +6
    tOPO    EQU    0x08 ; +3
    tNPO    EQU    0x09 ; -6
    tPPO    EQU    0x0A ; +12
    tOON    EQU    0x10 ; -1
    tNON    EQU    0x11 ; -10
    tPON    EQU    0x12 ; +8
    tONN    EQU    0x14 ; -4
    tNNN    EQU    0x15 ; -13
    tPNN    EQU    0x16 ; +5
    tOPN    EQU    0x18 ; +2
    tNPN    EQU    0x19 ; -7
    tPPN    EQU    0x1A ; +11
    tOOP    EQU    0x20 ; +1
    tNOP    EQU    0x21 ; -8
    tPOP    EQU    0x22 ; +10
    tONP    EQU    0x24 ; -2
    tNNP    EQU    0x25 ; -11
    tPNP    EQU    0x26 ; +7
    tOPP    EQU    0x28 ; +4
    tNPP    EQU    0x29 ; -5
    tPPP    EQU    0x2A ; +13
    

    As you can see we directly translate triad to byte and vice versa for data, but we can do the same for address - lower 3 trit of address can address the same 48 bytes (so instead of 27 triad one page will occupy 48 bytes of binary memory). Higher trits of address may or may not have similar translation.

    Also we can have a special CPLD that converts ternary address to binary address optimally (without gaps and holes as above). Below you can see calculations for mostly used memory sizes:

    2KB = 11-bit address = 6 trits (729 ternary cells - 28% used);

    8KB = 13-bit address = 8 trits (6,561 ternary cells - 63% used);

    32KB = 15-bit address = 9 trits (19,683 ternary cells - 48% used);

    64KB = 16-bit address = 10 trits (59,049 ternary cells - 71% used);

    128KB = 17-bit address = the same 10 trits (59,049 ternary cells - 45% used);

    256KB = 18-bit address = 11 trits (177,147 ternary cells - 67% used);

    512KB = 19-bit address = the same 11 trits (177,147 ternary cells - almost 34% used);

    1MB = 20-bit address = 12 trits (531,441 ternary cells - almost 51% used).

    As you can see we have better usage of binary memory in ternary computer system when it's 64KB addressed by 10 trits and this approach will use 71% of memory space.


    In case of TRIADOR we have 6-trit address for program memory - it has addresses from -364 to +364 and each read-only memory cell should have 5-trit value - to simplify things in my Logisim model I addressed 2K binary ROM directly when every TRIT of ternary address is converted to 2 BITS of binary address, but in this case it has to be 12 bits total, but we have only 11 (2^11=2048) - my idea was to allow user to use ternary addresses from ONNNNN to PPPPPP only (it is 66% of all 6-trit address space and should be more than enough for start) and we need to convert 1-byte data to 5-trit program word by another smaller ROM (or CPLD): 
        <comp lib="4" loc="(850,300)" name="ROM">
          <a name="dataWidth" val="10"/>
          <a name="contents">addr/data: 8 10
    0 1 6 4 5 1a 18 19
    12 10 11 16 14 15 6a 68
    69 62 60 61 66 64 65 4a
    48 49 42 40 41 46 44 45
    5a 58 59 52 50 51 56 54
    55 1aa 1a8 1a9 1a2 1a0 1a1 1a6
    1a4 1a5 18a 188 189 182 180 181
    186 184 185 19a 198 199 192 190
    191 196 194 195 12a 128 129 122
    120 121 126 124 125 10a 108 109
    102 100 101 106 104 105 11a 118
    119 112 110 111 116 114 115 16a
    168 169 162 160 161 166 164 165
    14a 148 149 142 140 141 146 144
    145 15a 158 159 152 150 151 156
    154 155 13*0 2aa 2a8 2a9 2a2 2a0
    2a1 2a6 2a4 2a5 28a 288 289 282
    280 281 286 284 285 29a...
    Read more »

  • Simulating ternary full adder in VHDL

    SHAOS07/03/2018 at 05:13 0 comments

    Now we will simulate ternary full adder:

    Using ternary.vhd described in previous log, we can do this architecture in VHDL:

    use ternary.all;
    
    entity main is
        Port ( a : in FakeTrit;
               b : in FakeTrit;
               c : in FakeTrit;
               s : out FakeTrit;
               c2 : out FakeTrit
                 );
    end main;
    
    architecture Behavioral of main is
    signal r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14 : FakeTrit;
    signal a1,b1,c1,s1,cc1 : FakeTrit;
    begin
    process (a,b,c)
    
    FUNCTION io_invert(T: FakeTrit) RETURN FakeTrit IS
    begin
                    case T is
                    when N =>
                            return P;
                    when O =>
                            return X;
                    when P =>
                            return N;
                    when others =>
                            return O;
                    end case;
    end;
    
    begin
    
        a1 <= io_invert(a);
        b1 <= io_invert(b);
        c1 <= io_invert(c);
        
        r1 <= mux(a1,O,P,N);
        r2 <= mux(a1,P,N,O);
        r3 <= mux(b1,r1,r2,a1);
        r4 <= mux(b1,r2,a1,r1);
        r5 <= mux(b1,a1,r1,r2);
        r6 <= mux(c1,r3,r4,r5);
        r7 <= e21(a1,N,O);
        r8 <= e12(a1,N,O);
        r9 <= e21(a1,O,P);
        r10 <= e12(a1,O,P);
        r11 <= mux(b1,r7,r8,O);
        r12 <= mux(b1,r8,O,r9);
        r13 <= mux(b1,O,r9,r10);
        r14 <= mux(c1,r11,r12,r13);
        s1 <= r6;
        cc1 <= r14;
        
        s <= io_invert(s1);
        c2 <= io_invert(cc1);
    
    end process;
    
    end Behavioral;
    

    io_invert is function to do bitwise inversion for inputs and outputs, because we are using 3-state switches (0 is active state) and 3-wire Red-Green LEDs (0 is active state) - schematics below repeated 3 time on the board with CoolRunner-II:

    This is 1+1+1 = 3

    This is (-1)+(-1)+(-1) = -3



    Pin assignments:

    NET "a<0>"  LOC = "P140" | IOSTANDARD = LVTTL ; 
    NET "a<1>"  LOC = "P142" | IOSTANDARD = LVTTL ; 
    NET "b<0>"  LOC = "P138" | IOSTANDARD = LVTTL ; 
    NET "b<1>"  LOC = "P139" | IOSTANDARD = LVTTL ; 
    NET "c<0>"  LOC = "P136" | IOSTANDARD = LVTTL ; 
    NET "c<1>"  LOC = "P137" | IOSTANDARD = LVTTL ; 
    NET "s<0>"  LOC = "P87" | IOSTANDARD = LVTTL ; 
    NET "s<1>"  LOC = "P88" | IOSTANDARD = LVTTL ; 
    NET "c2<0>"  LOC = "P85" | IOSTANDARD = LVTTL ; 
    NET "c2<1>"  LOC = "P86" | IOSTANDARD = LVTTL ; 
    

    This ternary full adder ate 8 macrocells (4% of XC2C256):

    And this is logic equations generated by Xilinx ISE software:

    Next step - MEM... 

  • Simulating ternary in VHDL

    SHAOS07/02/2018 at 03:55 0 comments

    So, now we will show you how to use balanced ternary in VHDL (tested in Xilinx ISE v9.2i on CPLD CoolRunner-II). Similarly to Logisim approach when 2 "binary" wires were used to simulate 1 "ternary" wire we can define new VHDL type to handle ternary and call it "FakeTrit" that will be BIT_VECTOR with 2 wires in it - VHDL package built around this approach may look like this:

    PACKAGE ternary IS
    
            SUBTYPE FakeTrit is BIT_VECTOR (1 downto 0);
            SUBTYPE FakeTriad is BIT_VECTOR (5 downto 0);
            SUBTYPE FakeTriadWithParity is BIT_VECTOR (7 downto 0);
    
            CONSTANT O : FakeTrit := "00";
            CONSTANT P : FakeTrit := "01";
            CONSTANT N : FakeTrit := "10";
            CONSTANT X : FakeTrit := "11";
    
            FUNCTION buf(T: FakeTrit) RETURN FakeTrit;
            FUNCTION inv(T: FakeTrit) RETURN FakeTrit;
            FUNCTION mux(T_C: FakeTrit; T_N: FakeTrit; T_O: FakeTrit; T_P: FakeTrit) RETURN FakeTrit;
            FUNCTION e12(T_C: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit;
            FUNCTION e21(T_C: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit;
    
    END PACKAGE ternary;
    
    PACKAGE BODY ternary IS
    
            FUNCTION buf(T: FakeTrit) RETURN FakeTrit IS
            begin
                    case T is
                    when N =>
                            return N;
                    when O =>
                            return O;
                    when P =>
                            return P;
                    when others =>
                            return X;
                    end case;
            end;
    
            FUNCTION inv(T: FakeTrit) RETURN FakeTrit IS
            begin
                    case T is
                    when N =>
                            return P;
                    when O =>
                            return O;
                    when P =>
                            return N;
                    when others =>
                            return X;
                    end case;
            end;
    
              FUNCTION mux(T_C: FakeTrit; T_N: FakeTrit; T_O: FakeTrit; T_P: FakeTrit) RETURN FakeTrit IS
              begin
                    case T_C is
                    when N =>
                            return T_N;
                    when O =>
                            return T_O;
                    when P =>
                            return T_P;
                    when others => 
                            return X;
                    end case;      
              end;
    
            FUNCTION e12(T_C: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit IS
            begin
                    case T_C is
                    when N =>
                            return T_N;
                    when O =>
                            return T_P;
                    when P =>
                            return T_P;
                    when others =>
                            return X;
                    end case;
            end;
    
            FUNCTION e21(T_C: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit IS
            begin
                    case T_C is
                    when N =>
                            return T_N;
                    when O =>
                            return T_N;
                    when P =>
                            return T_P;
                    when others =>
                            return X;
                    end case;
            end;
    
    END ternary;

    4th state X (11) might be used as an exception to detect error during simulation.

    Now we can implement ternary half-adder (see example in previous log) in VHDL:

    use ternary.all;
    
    entity main is
        Port ( a : in FakeTrit;
               b : in FakeTrit;
               c : out FakeTrit;
               s : out FakeTrit
              );
    end main;
    
    architecture Behavioral of main is
    signal r1,r2,r3,r4,r5,r6 : FakeTrit;
    begin
    process (a,b)
    begin
        r1 <= mux(a,P,N,O);
        r2 <= mux(a,O,P,N);
        r3 <= mux(b,r1,a,r2);
        r4 <= e12(a,N,O);
        r5 <= e21(a,O,P);
        r6 <= mux(b,r4,O,r5);
        s <= r3;
        c <= r6;
    end process;
    end Behavioral;

    It takes 4 macrocells (out of 256) of Xilinx CPLD CoolRunner-II XC2C256/144 (or 2%).


    All results of activity around this could be found on GitLab: 

    https://gitlab.com/ternary/ternary/tree/master/vhdl

  • Simulated TRIADOR 2

    SHAOS07/01/2018 at 06:13 0 comments

    In last log I forgot to mention other 2 "fake" ternary blocks that were used in TRIADOR simulation in Logisim. In real life ternary selector can work both as multiplexer and as demultiplexer (because it's physically connecting wires and it doesn't matter which way current is flowing), but in Logisim it has to be 2 separate circuits, so this is ternary demux for Logisim:

    and this one is "ternary clock" (only one instance of it exists in TRIADOR model for Logisim):

    It produces clock sequence ONOPONOP (in real circuit simple sine or triangle signal will do the same).

    Also that Logsim model has a few "true ternary" circuits built from muxes (with help of my DDT ternary synthesis tool). For example half adder:

    Full adder:

    Ternary ROM ;)

    and even converter from triad to 7-segment indicator (as per previous log):

    P.S. e12 and e21 are simplified ternary muxes where 2 first or 2 last inputs are identical:

    In 2010 I called them "Element 12" and "Element 21" (or XYY and XXY) and they are existing by itself because it's simpler than full-scale ternary mux - one DG403 chip could be connected as 2 E12 or as 2 E21 (when 2 DG403 can do only 2 ternary muxes):

  • Simulated TRIADOR

    SHAOS06/23/2018 at 05:06 0 comments

    TRIADOR specification was born in summer 2017 during long discussion on my forum http://nedopc.org/forum/ when Dmitry asked forum users to think about simple, but powerful enough ternary hardware design that could be built from TRIMUXes (dual ternary multiplexers that I accidentally "invented" in 2010 when tested limits of DG403 switching chips). Then he finally built it in reality :)

    I don't have so many TRIMUXes (yet) so I decided to create my own version of TRIADOR (slightly different from Dmitry's creation, but still reflecting the same specification) in Logisim (digital electronics simulator written in Java). I already had most building blocks from 2011 when I simulated ternary counter for ternary clock:

    Main idea was to represent every ternary signal as a bus that consists of 2 digital wires - 00 will be 0 (O), 01 will be +1 (P), 10 will be -1 (N) and 11 will be forbidden combination. So in 2011 I created 2 most generic ternary blocks (using Logisim "binary" components) - ternary MUX (single ternary multiplexer):

    and ternary MEM (single memory cell with 1 control input and 2 data inputs):

    Everything else was built out of these two (in reality MEM could also be build from MUXes with loops as Dmitry showed here, but not in Logisim). Below you can see Logisim model to simulate TRIADOR without extension instructions and this model already is big enough to make Logisim crash most of the times when it's loaded:

    https://cdn.hackaday.io/files/285791222723936/ternary_circ.zip

    Source code for this could be found on GitLab: https://gitlab.com/ternary/ternary

    Here you can see additional indication - 6x6 Red/Green LED matrix and eight 7-segment indicators connected to outputs of TRIADOR registers. This is how I represent triads on 7-segments:

    This is a way to build a calculator (eventually). But because of unstable behavior of the model I stopped in November 2017 - now I want to go further with conversion of this model to netlist that could be translated into (1) C program for further compilation and testing and (2) VHDL program for flashing into some FPGA board to create more or less affordable real life application of ternary computing ;)

    P.S. and may be even (3) CMOS full custom IC as part of my Shared Silicon project :)

  • Here how 600 dg403dy look like

    Dmitry V. Sokolov12/20/2017 at 06:22 0 comments

    Some of them have 1990 on the label :)

  • More on ternary memory (flip-flap-flops)

    Dmitry V. Sokolov12/19/2017 at 11:50 0 comments

    A flip-flap-flop can be made from two static memory cells wired in a master-slave configuration. Here is the schematics and accompagnying video:

    I use exactly this schematic in the program counter. The RAM is wired a bit differently, however the idea is the same. 

View all 18 project logs

Enjoy this project?

Share

Discussions

xor wrote 08/01/2018 at 11:29 point

better way is 0 1 *

please read book evolution algorithm goldberd

  Are you sure? yes | no

SHAOS wrote 08/02/2018 at 00:58 point

no it is not :)

  Are you sure? yes | no

fabian wrote 08/04/2018 at 13:13 point

this is not trouble caligraphy ,

read abou genetic algorithm

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates