Serializer ve FPGA Üzerinde Tasarımı

Teknolojinin ilerlemesi ile veri yapılarının büyümesi sonucu iki nokta arası yüksek hızlı veri aktarımı zorunlu hale geldi. İki nokta arası veri aktarımını paralel ya da seri yolla yapılabilir. Paralel veri aktarımı her ne kadar basit olsada yüksek bant genişliklerinde sorunlar getirmektedir. Aşağıda paralel veri aktarımının dezavantajları ve seri veri aktarımının avantajları sıralanmıştır.

Paralel Veri Aktarımının Dezavantajları:

  • Fazla kablo/hat sayısı
  • Entegre devrelerde fazla pin sayısı
  • Yüksek maliyet
  • Skew
  • Düşük aktarım hızı (~250Mbps)

Aşağıda fazla hat sayısından meydana gelen skew'in kontrol zorluğu görülebilmektedir:

Seri Veri Aktarımının Avantajları:

  • Daha az kablo/hat sayısı
  • Entegre devrelerde daha az pin sayısı
  • Düşük maliyet
  • Yüksek aktarım hızı (>2Gbps)

Seri Veri Aktarımında Fiziksel Katman

Fiziksel katman genel olarak ikiye ayrılabilir; single-ended ve differential. Single-ended sinyaller tek tel üzerinden veri aktarımı gerçekleştirirken, differential sinyaller bir birine sarmal sarılmış tel çiftinden (twisted pair) üzerinden veri aktarımını gerçekleştirirler. Differantial sinyal çiftleri arasındaki bağıntı \small{V_+=-V_-}'dir. Differantial sinyallerin gürültü dayanımları single-ended sinyallere göre çok daha iyidir.

SerDes

SerDes (Serializer-Deserializer) seri veri aktarımda kullanılan iki donanım çiftidir. Serializer, paralel veriyi seri hale getirerek fiziksel katmana gönderir. Deserializera ise fiziksel katmandan gelen seri veriyi paralele dönüştürür.

FPGA Üzerinde Serializer Tasarımı

Donanım Şeması

Paralel-Seri dönüşüm shift register ile yapılır. Her N cycle'da Strobe sinyali setlenir ve Parallel In'deki veri shift register'a yüklenir. Serializer Clock ayrı bir ring counter'da üretilir.

VHDL Kodu

------------------------- Serializer.vhd ---------------------------
--                         Bertan Taşkın
--                           10.10.2017
--                         Versiyon: 3.0
--
-- Paralel girişi seriye dönüştüren modül. Seri veri çıkışı yanında
-- clock çıkışıda bulunmaktadır.
--
--
--
-- Generic Parametreleri
--
-- SerializationFactor: Serialization oranı. 2'den büyük olmak
-- zorundadır.
--
-- NumberofChannel: Kanal sayısı.
--
-- ClockPattern: Serializer'ın çıkış clock pattern'i. Alabileceği
-- değerler:
--
--     "AutoGenerate" : Otomatik olarak clock pattern'i oluşturulur.
--     "UserClockPattern" : Clock Pattern'i kullanıcı tarafında seçilir.
--
-- UserClockPattern: Kullanıcı tarafından oluşturulan clock pattern'i.
-- Sadece ClockPattern "UserClockPattern" seçildiğinde kullanılır.
-- Clock pattern'leri kısmına nasıl kullanılacağı gösterilmiştir.
--
-- FeedbackClock: Clock geri beslemesinin kaynağı. Alabileceği değerler:
--
--    "SerializerClock" : FeedbackClock serializer clock çıkışından alınır.
--    "ExternalRing" : FeedbackClock harici ring'den alınır.
--
-- FeedbackPipelineLength: Feedback clock'un gecikmesi.
--
-- FirstBit: Serializer'dan gönderilecek ilk bit. Alabileceği değerler:
--
--		"LSB" : Gönderilecek ilk bit most significant bit.
--		"MSB" : Gönderilecek ilk bit least significant bit.
--
--
--
-- Giriş ve çıkışlar asağıdaki gibi atanacaktır:
--
-- DataIn <= CH[N - 1] & CH[N] & ... & CH[0] -- -- SerializerData => SER[N - 1] & SER[N] & ... & SER[0]
--
--
--
-- Clock Pattern'leri
--
-- "AutoGenerate" Clock Pattern'leri:
-- 
-- 1.SerializationFactor çift ise
--
-- SerializationFactor = 2, 4, 6,... gibi
--    _______________
--                   |
--                   |_______________
--                
--    <- A -><- A ->
-- 
-- A = SerializationFactor / 2
--
-- 2.SerializationFactor tek ise
--
--    2.1.(SerializationFactor - 1) mod 4 /= 0 ise
--
--    SerializationFactor = 3, 7, 11,... gibi
--      ________              ________
--              |            |
--              |____________|
--                
--      <- A -><- B -><- A ->
--
--    A = SerializationFactor / 2 - (SerializationFactor - 1) / 4
--    B = (SerializationFactor - 1) / 2
--
--    2.2.(SerializationFactor - 1) mod 4 = 0 ise
--
--    SerializationFactor = 5, 9, 13,... gibi
--      _________             _________
--               |           |
--               |___________|
--                
--      <- A -><- B -><- A ->
--
--    A = (SerializationFactor - 1) / 4
--    B = SerializationFactor - (SerializationFactor - 1) / 2
--
-- "UserPattern" Clock Pattern'i
--
--     ___________________       _________
--    |         |         |     |         |
--    | UP[N-1] | UP[N-2] | ... |  UP[0]  |
--    |_________|_________|     |_________|
--
-- UP: UserClockPattern
-- N = SerializationFactor
--
--
--
-- Aktarım hızı = NumberofChannel * Clk (bps)
--
--
--
-- Versiyon Notları:
--  
-- Versiyon 1.0 (4.10.2017): İlk sürüm.
--  
-- Versiyon 2.0 (9.10.2017): Ring yapısına geçilerek Fmax değeri arttırıldı.
--    Geri besleme clock'u için isteğe bağlı delay line eklendi.
--    Gönderilecek ilk bit için LSB ya da MSB seçeneği eklendi.
--
-- Versiyon 3.0 (10.10.2017): Kaynak kullanımını azaltmak için tek modül ile
--    birden fazla kanal kullanımı mümkün hale getirildi.
--    Serializer clock pattern'ninin kullanıcı tarafından değiştirilebilme
--    seçeneği getirildi.
--    Geri besleme clock'u için harici bir ring seçebilmesi mümkün hale
--    getirildi.
--


--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 
use ieee.math_real.all;

entity Serializer is
	generic(SerializationFactor : natural := 10;                     --Serializer Katsayısı
		NumberofChannel : natural := 1;                      --Kanal Sayısı
		ClockPattern : string := "AutoGenerate";             --Clock Pattern'i
		UserClockPattern : std_logic_vector := "1111100000"; --Kullanıcı Clock Pattern'i
		FeedbackClockSource : string := "ExternalRing";      --Geri Besleme Clock Kaynağı
		FeedbackPipelineLength : natural := 2;               --Geri Besleme Gecikmesi
		FirstBit : string := "LSB");                         --Gönderilecek İlk Bit

	port(Clk, Enable : in std_logic;                                                       --Clock ve Enable Girişleri
		DataIn : in std_logic_vector(SerializationFactor * NumberofChannel - 1 downto 0);  --Veri Girişi
		SerializerData : out std_logic_vector(NumberofChannel - 1 downto 0);               --Serializer Veri Çıkışı
		SerializerClock : out std_logic;                                                   --Serializer Clock Çıkışı
		FeedbackClock : out std_logic);                                                    --Geri Besleme Clock Çıkışı
end Serializer;

architecture Behavioral of Serializer is

	--Serializer'ın clock pattern'nini oluşturan fonksiyon
	function GenerateClockPattern return std_logic_vector is
	variable Pattern : std_logic_vector(SerializationFactor - 1 downto 0);
	begin
	
		--Otomatik clock pattern'i
		if ClockPattern = "AutoGenerate" then
		
			if SerializationFactor mod 2 = 0 then
				Pattern := (SerializationFactor / 2 - 1 downto 0 => '1') &
							(SerializationFactor / 2 - 1 downto 0 => '0');
			else
				if ((SerializationFactor - 1) / 4) mod 4 = 0 then
					Pattern := ((SerializationFactor - 1) / 4 - 1 downto 0 => '1') &
								(SerializationFactor - (SerializationFactor - 1) / 2 - 1 downto 0 => '0') &
								((SerializationFactor - 1) / 4 - 1 downto 0 => '1');
				else
					Pattern := (SerializationFactor / 2 - (SerializationFactor - 1) / 4 - 1 downto 0 => '1') &
								((SerializationFactor - 1) / 2 - 1 downto 0 => '0') &
								(SerializationFactor / 2 - (SerializationFactor - 1) / 4 - 1 downto 0 => '1');
				end if;
			end if;
			
			return Pattern;
		
		--Kullanıcı clock pattern'i
		elsif ClockPattern = "UserClockPattern" then
			return UserClockPattern;
		end if;
		
	end GenerateClockPattern;
	
	--Geri dönüş clock pattern'nini oluşturan fonksiyon
	function GenerateFeedbackClockPattern return std_logic_vector is
	variable Pattern : std_logic_vector(SerializationFactor - 1 downto 0);
	begin
	
		if SerializationFactor mod 2 = 0 then
			Pattern := (SerializationFactor / 2 - 1 downto 0 => '1') &
						(SerializationFactor / 2 - 1 downto 0 => '0');
		else
			Pattern := (SerializationFactor / 2 downto 0 => '1') &
						(SerializationFactor / 2 - 1 downto 0 => '0');
		end if;
		
		return Pattern;
	end GenerateFeedbackClockPattern;

	signal Ring1 : std_logic_vector(SerializationFactor - 1 downto 0) := '1' & (SerializationFactor - 2 downto 0 => '0');
	signal Ring2 : std_logic_vector(SerializationFactor - 1 downto 0) := GenerateClockPattern;
	signal Ring3 : std_logic_vector(SerializationFactor - 1 downto 0) := GenerateFeedbackClockPattern;
	
	type stdlogicvector_array is array(NumberofChannel - 1 downto 0) of std_logic_vector(SerializationFactor - 1 downto 0);
	
	signal DataReg : stdlogicvector_array := (others=>(others=>'0'));
	signal FeedbackPipeline : std_logic_vector(FeedbackPipelineLength - 1 downto 0) := (others=>'0');
	
begin
	
	InterConn : for i in 0 to NumberofChannel - 1 generate
		SerializerData(i) <= DataReg(i)(SerializationFactor - 1);
	end generate;

	FeedbackClock <= FeedbackPipeline(FeedbackPipelineLength - 1);

	process(Clk, Enable)
	begin

		if rising_edge(Clk) and Enable = '1' then

			SerializerClock <= Ring2(SerializationFactor - 1);

			--Ring1 için dairesel shift register
			for i in 0 to SerializationFactor - 1 loop
				Ring1((i + 1) mod SerializationFactor) <= Ring1(i);
			end loop;

			--Ring2 için dairesel shift register
			for i in 0 to SerializationFactor - 1 loop
				Ring2((i + 1) mod SerializationFactor) <= Ring2(i);
			end loop;

			--Ring3 için dairesel shift register
			for i in 0 to SerializationFactor - 1 loop
				Ring3((i + 1) mod SerializationFactor) <= Ring3(i);
			end loop;

			--Serializer 
			for i in 0 to NumberofChannel - 1 loop
				for j in 0 to SerializationFactor - 1 loop
					--Shift register'a yeni veriler alınmayacak ise mevcut veriler
					--kaydırılır
					if Ring1(SerializationFactor - 1) = '0' then
						DataReg(i)((j + 1) mod SerializationFactor) <= DataReg(i)(j);					
					--Shift register'a yeni veriler yüklenir
					else
						--Gönderilecek ilk bit MSB ise
						if FirstBit = "MSB" then
							DataReg(i)(j) <= DataIn(SerializationFactor * i + j);
						--Gönderilecek ilk bit LSB ise
						elsif FirstBit = "LSB" then
							DataReg(i)(j) <= DataIn(SerializationFactor * (i + 1) - j - 1);
						end if;
					end if;
				end loop;
			end loop;

			--Feedback clock'unun kaynağı
			if FeedbackClockSource = "ExternalRing" then
				FeedbackPipeline(0) <= Ring3(SerializationFactor - 1);
			elsif FeedbackClockSource = "SerializerClock" then
				FeedbackPipeline(0) <= Ring2(SerializationFactor - 1);
			end if;

			--Feedback clock'u için delay line
			for i in 0 to FeedbackPipelineLength - 2 loop
				FeedbackPipeline(i + 1) <= FeedbackPipeline(i);
			end loop;
			
		end if;

	end process;

end Behavioral;

RTL Şeması

Kaynak Kullanımı

EP4CE22F17C6 için Fmax Değerleri

Test Donanımları

1.Kurulum: Serializer çarpanı = 10, Kanal sayısı = 1, İlk bit = MSB

VHDL kodu
--------------------------- SerializerTest.vhd ------------------------------
--                            Bertan Taşkın
--                             10.10.2017
--
-- Serializer.vhd (Versiyon 3.0) için hazırlanmış test donanımı.
--


--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 
use ieee.math_real.all;

entity SerializerTest is
	port(Clk : in std_logic;
		SerializerData : out std_logic_vector(0 downto 0); 
		SerializerClock : out std_logic;
		FeedbackClock : out std_logic);
end SerializerTest;

architecture Behavioral of SerializerTest is

component Serializer
	generic(SerializationFactor : natural := 10;            --Serializer Katsayısı
		NumberofChannel : natural := 1;                      --Kanal Sayısı
		ClockPattern : string := "AutoGenerate";             --Clock Pattern'i
		UserClockPattern : std_logic_vector := "1111100000"; --Kullanıcı Clock Pattern'i
		FeedbackClockSource : string := "ExternalRing";      --Geri Besleme Clock Kaynağı
		FeedbackPipelineLength : natural := 2;               --Geri Besleme Gecikmesi
		FirstBit : string := "LSB");                         --Gönderilecek İlk Bit

	port(Clk, Enable : in std_logic;                                                      --Clock ve Enable Girişleri
		DataIn : in std_logic_vector(SerializationFactor * NumberofChannel - 1 downto 0);  --Veri Girişi
		SerializerData : out std_logic_vector(NumberofChannel - 1 downto 0);               --Serializer Veri Çıkışı
		SerializerClock : out std_logic;                                                   --Serializer Clock Çıkışı
		FeedbackClock : out std_logic);                                                    --Geri Besleme Clock Çıkışı
end component;

	signal Clock, FBClock : std_logic;
	
	signal CH0 : std_logic_vector(9 downto 0) := (others=>'0');
	
begin

	FeedbackClock <= FBClock; Ser : Serializer generic map(SerializationFactor => 10,
			NumberofChannel => 1,
			ClockPattern => "AutoGenerate",
			UserClockPattern => "1111100000",
			FeedbackClockSource => "ExternalRing",
			FeedbackPipelineLength => 2,
			FirstBit => "MSB")
		port map(Clk => Clock,
			Enable => '1',
			DataIn => CH0,
			SerializerData => SerializerData,
			SerializerClock => SerializerClock,
			FeedbackClock => FBClock);
	
	process(Clk, FBClock)
	begin
	
		if rising_edge(Clk) then
			Clock <= not Clock;
		end if;
		
		if rising_edge(FBClock) then
			CH0 <= std_logic_vector(unsigned(CH0) + 1);
		end if;
		
	end process;

end Behavioral;
Signal Tap

2.Kurulum: Serializer çarpanı = 7, Kanal sayısı = 3, İlk bit = LSB

VHDL kodu
--------------------------- SerializerTest.vhd ------------------------------
--                            Bertan Taşkın
--                             10.10.2017
--
-- Serializer.vhd (Versiyon 3.0) için hazırlanmış test donanımı.
--


--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 
use ieee.math_real.all;

entity SerializerTest is
	port(Clk : in std_logic;
		SerializerData : out std_logic_vector(3 downto 0); 
		SerializerClock : out std_logic;
		FeedbackClock : out std_logic);
end SerializerTest;

architecture Behavioral of SerializerTest is

component Serializer
	generic(SerializationFactor : natural := 10;            --Serializer Katsayısı
		NumberofChannel : natural := 1;                      --Kanal Sayısı
		ClockPattern : string := "AutoGenerate";             --Clock Pattern'i
		UserClockPattern : std_logic_vector := "1111100000"; --Kullanıcı Clock Pattern'i
		FeedbackClockSource : string := "ExternalRing";      --Geri Besleme Clock Kaynağı
		FeedbackPipelineLength : natural := 2;               --Geri Besleme Gecikmesi
		FirstBit : string := "LSB");                         --Gönderilecek İlk Bit

	port(Clk, Enable : in std_logic;                                                      --Clock ve Enable Girişleri
		DataIn : in std_logic_vector(SerializationFactor * NumberofChannel - 1 downto 0);  --Veri Girişi
		SerializerData : out std_logic_vector(NumberofChannel - 1 downto 0);               --Serializer Veri Çıkışı
		SerializerClock : out std_logic;                                                   --Serializer Clock Çıkışı
		FeedbackClock : out std_logic);                                                    --Geri Besleme Clock Çıkışı
end component;

	signal Clock, FBClock : std_logic;
	
	signal CH0, CH1, CH2, CH3 : std_logic_vector(6 downto 0) := (others=>'0');
	
begin

	FeedbackClock <= FBClock; Ser : Serializer generic map(SerializationFactor => 7,
			NumberofChannel => 4,
			ClockPattern => "AutoGenerate",
			UserClockPattern => "1111100000",
			FeedbackClockSource => "ExternalRing",
			FeedbackPipelineLength => 2,
			FirstBit => "LSB")
		port map(Clk => Clock,
			Enable => '1',
			DataIn => CH3 & CH2 & CH1 & CH0,
			SerializerData => SerializerData,
			SerializerClock => SerializerClock,
			FeedbackClock => FBClock);
	
	process(Clk, FBClock)
	begin
	
		if rising_edge(Clk) then
			Clock <= not Clock;
		end if;
		
		if rising_edge(FBClock) then
			CH0 <= std_logic_vector(unsigned(CH0) + 1);
			CH1 <= std_logic_vector(unsigned(CH1) + 2);
			CH2 <= std_logic_vector(unsigned(CH2) + 4);
			CH3 <= std_logic_vector(unsigned(CH3) + 8);
		end if;
		
	end process;

end Behavioral;
Signal Tap

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.