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 ;)
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
Counter counts from OOO (0) to PPP (+13) and then NNN (-13) and up to OOO (0) - one increment per second
Are you sure? yes | no
and Clock_Divider divides onboard clock 1.8432 MHz by 460800 in order to get 4 Hz that then turns into 1 Hz ternary clock NOPONOPONOPO...
Are you sure? yes | no