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ı '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 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;