-------------------------------------------------
--	Simple Bit Error Rate Tester (max count of 2^24-1)
--	list5-1.vhd
-------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity BERT is
	port( RESET : in std_logic;
		CLK : in std_logic; --システムクロック、TCK, RCKより充分に高速なこと
							--この信号はCLKバッファに割り振ること
		TCK : in std_logic; --送信クロック
		RCK : in std_logic; --受信クロック
		RcvBit : in std_logic; --受信判定結果入力
		RefBit : in std_logic; --TxD(14)〜(0)から適切なタイミングを選択
		MesSw : in std_logic;  --チャタリングは発生させぬこと！
		Sel : in std_logic_vector(2 downto 0);
		Dout : out std_logic_vector(7 downto 0);
		TxD : out std_logic_vector(14 downto 0)
	);
end BERT;

architecture RTL of BERT is 

signal PRBS_reg : std_logic_vector(14 downto 0);
signal BitCounter : std_logic_vector(23 downto 0);
signal ErrCounter : std_logic_vector(23 downto 0);
signal TckDelay1, TckDelay2 : std_logic;
signal RckDelay1, RckDelay2 : std_logic;
signal RcvBitSample, RcvBitSync, RefBitSync : std_logic;
signal Measure : std_logic;

begin

-- TxD(14)がTXビット
-- TxD(14)〜(0)はRXビット用遅延

TxD <= PRBS_reg;

-- PRBSレジスタ, PN15
	process (CLK, RESET) begin
		if (RESET = '0') then
			PRBS_reg <= "111111111111111";
		elsif (CLK'event and CLK='1') then
			if (TckDelay1 = '1' and TckDelay2 = '0') then  --TCKの立ち上がりエッジ
				-- Polynomial X(n) = x15 + x1 + 1, PN15
				PRBS_reg(14) <= PRBS_reg(0) xor PRBS_reg(1);
				for I in 0 to 13 loop
					PRBS_reg(I) <= PRBS_reg(I+1);
				end loop;
			end if;
		end if;
	end process;


-- TCK, RCKを内部CLKに同期させる
	process (CLK, RESET) begin
		if (RESET = '0') then
			TckDelay1 <= '0';
			TckDelay2 <= '0';
			RckDelay1 <= '0';
			RckDelay2 <= '0';
		elsif (CLK'event and CLK='1') then
			TckDelay1 <= TCK;
			TckDelay2 <= TckDelay1;
			RckDelay1 <= RCK;
			RckDelay2 <= RckDelay1;
		end if;
	end process;


-- RcvBitをRCKでサンプルする
	process (RCK, RESET) begin
		if (RESET = '0') then
			RcvBitSample <= '0';
		elsif (RCK'event and RCK='1') then
			RcvBitSample <= RcvBit;
		end if;
	end process;


-- RcvBit, RefBit, MesSwを内部CLKに同期させる
	process (CLK, RESET) begin
		if (RESET = '0') then
			RcvBitSync <= '0';
			RefBitSync <= '0';
			Measure <= '0';
		elsif (CLK'event and CLK='1') then
			RcvBitSync <= RcvBitSample;
			RefBitSync <= RefBit;
			Measure <= MesSw;
		end if;
	end process;


-- 受信ビット数検出
	process (CLK, RESET) begin
		if (RESET = '0') then
			BitCounter <= x"000000";
		elsif (CLK'event and CLK='1') then
			if (RckDelay1 = '1' and RckDelay2 = '0' and Measure = '1') then
				BitCounter <= BitCounter + 1;
				--上記は24ビットをいきなり足しているが、FPGA化するときに
				--ゲート数削減のため、ビットスライスさせたほうが良い
				--詳細はHDLや論理回路の各種文献を参照のこと
			end if;
		end if;
	end process;

-- エラービット数検出
	process (CLK, RESET) begin
		if (RESET = '0') then
			ErrCounter <= x"000000";
		elsif (CLK'event and CLK='1') then
			if (RckDelay1 = '1' and RckDelay2 = '0' and Measure = '1') then
				if (RcvBitSync /= RefBitSync ) then
					ErrCounter <= ErrCounter + 1;
					--ここもBitCounterと同じ。ビットスライスさせたほうが良い
				end if;
			end if;
		end if;
	end process;

	process(Sel, BitCounter, ErrCounter) begin
		-- Selで出力するカウンタを設定する
		case Sel is
			when "000" =>
				Dout <= BitCounter(7 downto 0);
			when "001" =>
				Dout <= BitCounter(15 downto 8);
			when "010"|"011" =>
				Dout <= BitCounter(23 downto 16);
			when "100" =>
				Dout <= ErrCounter(7 downto 0);
			when "101" =>
				Dout <= ErrCounter(15 downto 8);
			when others => -- "110"|"111"
				Dout <= ErrCounter(23 downto 16);
		end case;
	end process;

end RTL;
