-- Synopsys Design Contest 2002
-- transmitter.vhd
-- 2001/September/10th
-- TASK: Differencial Cyclic Code FEC
-- Copyright by  Tom Wada@Univ. of the Ryukyus

library IEEE;
use IEEE.STD_LOGIC_1164.all, IEEE.NUMERIC_STD.all;

entity TRANSMITTER is
    port (SBWE     : out std_logic;
	  SB       : out std_logic;
	  START    : out std_logic;
	  RESET    : in  std_logic;
	  CLK      : in  std_logic );
end entity TRANSMITTER;

architecture RTL of TRANSMITTER is
    -- phase counts from 0 to 41
    -- phase  0 to 20 : sync bits are transmitted
    -- phase 21 to 31 : information bits transmitted
    -- phase 32 to 41 : parity bits transmitted
    signal  phase    : unsigned (5 downto 0);
    -- 11bits information bits
    signal  infbit   : unsigned (10 downto 0);
    -- internal start signal
    signal  intstart : std_logic;
    -- internal sb signal
    signal  intsb,intsb2    : std_logic;
    -- 10 parity bits
    signal  parity   : unsigned (9 downto 0); 
    -- error signal
    signal  errsig   : std_logic;
    -- error counter
    signal  errcnt   : unsigned (9 downto 0);
begin
------------------------------------------------
-- 42 phase (0 to 41 counter) generation unit
------------------------------------------------
    PHASE_CNT: process(CLK,RESET)
    begin 
        if (RESET='1') then  
	    phase <= "000000";
	elsif rising_edge(CLK) then  
            if (phase="101001") then -- if phase=41
		phase <= "000000";
            else
                phase <= phase + 1;
	    end if;		
	end if;
    end process PHASE_CNT;
------------------------------------------------
-- 11 bits information generation unit
-- count down from 1111111111 by 1
------------------------------------------------
    INF_GEN: process(CLK, RESET)
    begin
	if (RESET='1') then
	    infbit <= "00000000010";
        elsif rising_edge(CLK) then
            if (phase="010100") then -- if phase=20
		infbit <= infbit - 1;
            end if;
        end if;
    end process INF_GEN;
------------------------------------------------
-- internal start (intstart)  generation
------------------------------------------------
    START_GEN: process(CLK, RESET)
    begin
	if (RESET='1') then
	    intstart <= '0';
        elsif rising_edge(CLK) then
	    if (phase="010101") then -- if phase=21
	       intstart <= '1';
            else intstart <= '0';
	    end if;
        end if;
    end process START_GEN;
------------------------------------------------
-- internal sb signal (intsb) generation
------------------------------------------------
    SB_GEN: process(CLK, RESET)
    begin
	if (RESET='1') then
            intsb <= '0';
        elsif rising_edge(CLK) then
            case phase is
	      when "000000"=> intsb <= '0'; -- 0
	      when "000001"=> intsb <= '0'; -- 1
	      when "000010"=> intsb <= '1'; -- 2
	      when "000011"=> intsb <= '1'; -- 3
	      when "000100"=> intsb <= '0'; -- 4
	      when "000101"=> intsb <= '1'; -- 5
	      when "000110"=> intsb <= '0'; -- 6
	      when "000111"=> intsb <= '1'; -- 7
	      when "001000"=> intsb <= '1'; -- 8
	      when "001001"=> intsb <= '1'; -- 9
	      when "001010"=> intsb <= '1'; --10
	      when "001011"=> intsb <= '0'; --11
	      when "001100"=> intsb <= '1'; --12
	      when "001101"=> intsb <= '1'; --13
	      when "001110"=> intsb <= '1'; --14
	      when "001111"=> intsb <= '0'; --15
	      when "010000"=> intsb <= '0'; --16
	      when "010001"=> intsb <= '0'; --17
	      when "010010"=> intsb <= '0'; --18
	      when "010011"=> intsb <= '0'; --19
	      when "010100"=> intsb <= '0'; --20
	      when "010101"=> intsb <= infbit(10); --21
	      when "010110"=> intsb <= infbit(9);  --22
	      when "010111"=> intsb <= infbit(8);  --23
	      when "011000"=> intsb <= infbit(7);  --24
	      when "011001"=> intsb <= infbit(6);  --25
	      when "011010"=> intsb <= infbit(5);  --26
	      when "011011"=> intsb <= infbit(4);  --27
	      when "011100"=> intsb <= infbit(3);  --28
	      when "011101"=> intsb <= infbit(2);  --29
	      when "011110"=> intsb <= infbit(1);  --30
	      when "011111"=> intsb <= infbit(0);  --31
	      when  others => intsb <= 'X';  --others
            end case;	      
	end if;
    end process SB_GEN;
------------------------------------------------
-- parity calculation
------------------------------------------------
    PARITY_CAL: process(CLK, RESET)
    begin
	if (RESET='1') then
            parity <= "0000000000";
        elsif rising_edge(CLK) then
            if (phase="010101") then
		parity <= "0000000000";
            elsif (phase>="010110" and phase<="100000") then
		parity(9) <= parity(8);
		parity(8) <= parity(7);
		parity(7) <= parity(6) xor intsb xor parity(9);
		parity(6) <= parity(5) xor intsb xor parity(9);
		parity(5) <= parity(4);
		parity(4) <= parity(3) xor intsb xor parity(9);
		parity(3) <= parity(2);
		parity(2) <= parity(1) xor intsb xor parity(9);
		parity(1) <= parity(0);
		parity(0) <= intsb xor parity(9);
            else
                parity <= parity(8 downto 0) & parity(9);
            end if;
        end if;
    end process PARITY_CAL;
------------------------------------------------
-- error interval counter
------------------------------------------------
    ERR_CNT: process (CLK, RESET) begin
        if (RESET='1') then errcnt <= "0000000000";
	elsif rising_edge(CLK) then
            if (errcnt = "0000001001") then -- max=9 (0-9) 
		 errcnt <= "0000000000";
            else errcnt <= errcnt +1;
            end if;
	end if;
    end process ERR_CNT;
------------------------------------------------
-- error signal generation
------------------------------------------------
    ERROR_GEN: process (CLK, RESET)
    begin
        if (RESET='1') then
	   errsig <= '0'; 
	elsif rising_edge(CLK) then
           if (errcnt="0000000000") then
	       errsig <= '1';  -- error happens every 10 cycle
           else errsig <= '0';
	   end if;
        end if;
    end process ERROR_GEN;
------------------------------------------------
-- output signals
------------------------------------------------
    SBOUT: process (CLK, RESET)
    begin
	if (RESET='1') then
	    intsb2 <= '0';
        elsif rising_edge(CLK) then
            if(phase >="100001" or phase="000000") then
                intsb2 <= parity(9);
            else
		intsb2 <= intsb;
            end if;
	end if;
    end process SBOUT;

    STARTOUT: process (CLK, RESET)
    begin
	if (RESET='1') then
	    START <= '0';
        elsif rising_edge(CLK) then
            START <= intstart;
        end if;
    end process STARTOUT;

    SB   <= intsb2;
    SBWE <= intsb2 xor errsig;

end architecture RTL;
