-- LSI Design Contest in Okinawa 2010
-- encoder.vhd
-- 2009/October/11th
-- TASK: BCH(15,7) 
-- Copyright by  Tom Wada@Univ. of the Ryukyus

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.std_logic_unsigned.all;

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

architecture RTL of ENCODER is
    -- phase counts from 0 to 14
    -- phase  0 to 6    : information U(X) 7 bits sent
    -- phase  7 to 14  : parity R(X) 8 bits sent
    -- phase 0  : START signal is asserted
    signal  phase    : std_logic_vector (3 downto 0);
    -- 7 bits information bits
    signal  infbit   : std_logic_vector (6 downto 0);
    -- serial info bit
    signal  sin         : std_logic;
    -- switchA bit
    signal  switchA  : std_logic;
    -- rreg
    signal rreg        : std_logic_vector(7 downto 0);
    -- internal sb bit
    signal  sbint     :    std_logic;
   -- error interval counter
    signal  errcnt  : std_logic_vector(7 downto 0);
   -- error signal
    signal  errsig   : std_logic; 
begin
------------------------------------------------
-- 0 to 14 counter 
------------------------------------------------
    PHASE_CNT: process(CLK,RESET)
    begin 
        if (RESET='1') then  
	    phase <= "0000";
	elsif (CLK'event and CLK = '1') then  
            if (phase="1110") then -- if phase=14
		phase <= "0000";
            else
                phase <= phase + 1;
	    end if;		
	end if;
    end process PHASE_CNT;
------------------------------------------------
-- 7 bits information generation unit
-- count up from 0000000 by 1
------------------------------------------------
    INF_GEN: process(CLK, RESET)
    begin
	if (RESET='1') then
	    infbit <= "1000000";
        elsif (CLK'event and CLK = '1') then  
            if (phase="1110") then -- if phase=14
		infbit <= infbit + 1;
            end if;
        end if;
    end process INF_GEN;
------------------------------------------------
-- internal sin generation
------------------------------------------------
   SIN_GEN: process(phase, infbit) begin
      case phase is
         when "0000" => sin <= infbit(6);
         when "0001" => sin <= infbit(5);
         when "0010" => sin <= infbit(4);
         when "0011" => sin <= infbit(3);
         when "0100" => sin <= infbit(2);
         when "0101" => sin <= infbit(1);
         when "0110" => sin <= infbit(0);
         when  others => sin <= 'X';  --others
       end case;
   end process SIN_GEN;
------------------------------------------------
-- switchA generation
------------------------------------------------
   SWITCHA_GEN: process(phase) begin
      case phase is
         when "0000" => switchA <= '1';
         when "0001" => switchA <= '1';
         when "0010" => switchA <= '1';
         when "0011" => switchA <= '1';
         when "0100" => switchA <= '1';
         when "0101" => switchA <= '1';
         when "0110" => switchA <= '1';
         when "0111" => switchA <= '0';
         when "1000" => switchA <= '0';
         when "1001" => switchA <= '0';
         when "1010" => switchA <= '0';
         when "1011" => switchA <= '0';
         when "1100" => switchA <= '0';
         when "1101" => switchA <= '0';
         when "1110" => switchA <= '0';
         when  others => switchA <= 'X';  --others
       end case;
   end process SWITCHA_GEN;
------------------------------------------------
-- parity calculation
------------------------------------------------
    PARITY_CAL: process(CLK, RESET)
    begin
	if (RESET='1') then
            rreg <= "00000000";
        elsif (CLK'event and CLK = '1') then  
            if (switchA='1') then
               rreg(7) <= rreg(6) xor rreg(7) xor sin;
               rreg(6) <= rreg(5) xor rreg(7) xor sin;
               rreg(5) <= rreg(4);
               rreg(4) <= rreg(3) xor rreg(7) xor sin;
               rreg(3) <= rreg(2);
               rreg(2) <= rreg(1);
               rreg(1) <= rreg(0);
               rreg(0) <= rreg(7) xor sin;
            else
               rreg <= rreg(6 downto 0) & '0';
            end if;
        end if;
    end process PARITY_CAL;
------------------------------------------------
-- sb combinational logic
------------------------------------------------
SB_COMB: process(sin, rreg(7), switchA) begin
   if (switchA='1') then
      sbint <= sin;
   else
      sbint <= rreg(7);
   end if;
end process SB_COMB;
------------------------------------------------
-- error interval counter
------------------------------------------------
    ERR_CNT: process (CLK, RESET) begin
        if (RESET='1') then errcnt <= "00000000";
	elsif (CLK'event and CLK = '1') then  
              if (errcnt = "00001001") then -- max=9 (0-9) 
		 errcnt <= "00000000";
              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 (CLK'event and CLK = '1') then  
              if (errcnt="00000000") 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
	    SB <= '0';
               SBWE <='0';
       elsif (CLK'event and CLK = '1') then  
             SB   <= sbint;
             SBWE <= sbint xor errsig;
       end if;
    end process SBOUT;

    STARTOUT: process (phase) begin
       if (phase = "0001") then
          START <= '1';
       else
          START <= '0';
       end if;
    end process STARTOUT;

end architecture RTL;
