2016-08-23 76 views
0

下面的VHDL片段正確地爲我提供了單個輸入字節的16位CRC校驗碼。 如何擴展多輸入字節,例如現在跨越 128個字節的框架被crc'd?帶有VHDL的CRC16(多輸入字節)

注意:函數'crc16'是使用一些在線工具生成的,但我也是自己推導出來的,所以我確信它的工作正常。目前,下面的測試臺每次調用都提供一個字節的CRC功能。

CRC特徵:

  • CRC多項式:0x8005
  • 輸入反射:是
  • 輸出反射:是
  • 種子值:0xFFFF的
  • XOR出值:爲0xFFFF(IIUC,否定CRC)

代碼:

library ieee; 
use ieee.std_logic_1164.all; 

use ieee.numeric_std.all; 

entity crc is 
port (clk: in std_logic; 
     data_in: in std_logic_vector(7 downto 0);    
     crc_out: out std_logic_vector(15 downto 0) 
    ); 
end crc; 

architecture crc_arch of crc is  

function reverse_vector(v: in std_logic_vector) 
return std_logic_vector is 
    variable result: std_logic_vector(v'RANGE); 
    alias vr: std_logic_vector(v'REVERSE_RANGE) is v; 
begin 
    for i in vr'RANGE loop 
     result(i) := vr(i); 
    end loop; 

    return result; 
end;  


function crc16(data_i: in std_logic_vector(7 downto 0);    
        crc_i: in std_logic_vector(15 downto 0)) 
return std_logic_vector is 
    variable crc_o: std_logic_vector(15 downto 0); 
begin 
    crc_o(15) := crc_i(7) xor crc_i(8) xor crc_i(9) xor crc_i(10) xor crc_i(11) xor crc_i(12) xor crc_i(13) xor crc_i(14) xor crc_i(15) xor 
        data_i(0) xor data_i(1) xor data_i(2) xor data_i(3) xor data_i(4) xor data_i(5) xor data_i(6) xor data_i(7);   
    crc_o(14) := crc_i(6);  
    crc_o(13) := crc_i(5); 
    crc_o(12) := crc_i(4); 
    crc_o(11) := crc_i(3); 
    crc_o(10) := crc_i(2); 
    crc_o(9) := crc_i(1) xor crc_i(15) xor data_i(7); 
    crc_o(8) := crc_i(0) xor crc_i(14) xor crc_i(15) xor data_i(6) xor data_i(7); 
    crc_o(7) := crc_i(13) xor crc_i(14) xor data_i(5) xor data_i(6); 
    crc_o(6) := crc_i(12) xor crc_i(13) xor data_i(4) xor data_i(5);    
    crc_o(5) := crc_i(11) xor crc_i(12) xor data_i(3) xor data_i(4); 
    crc_o(4) := crc_i(10) xor crc_i(11) xor data_i(2) xor data_i(3); 
    crc_o(3) := crc_i(9) xor crc_i(10) xor data_i(1) xor data_i(2); 
    crc_o(2) := crc_i(8) xor crc_i(9) xor data_i(0) xor data_i(1); 
    crc_o(1) := crc_i(9) xor crc_i(10) xor crc_i(11) xor crc_i(12) xor crc_i(13) xor crc_i(14) xor crc_i(15) xor 
        data_i(1) xor data_i(2) xor data_i(3) xor data_i(4) xor data_i(5) xor data_i(6) xor data_i(7); 
    crc_o(0) := crc_i(8) xor crc_i(9) xor crc_i(10) xor crc_i(11) xor crc_i(12) xor crc_i(13) xor crc_i(14) xor crc_i(15) xor 
        data_i(0) xor data_i(1) xor data_i(2) xor data_i(3) xor data_i(4) xor data_i(5) xor data_i(6) xor data_i(7); 

    return crc_o; 
end; 


begin 

    crc_out <= not reverse_vector(crc16(reverse_vector(data_in), x"FFFF")); 

end architecture crc_arch; 

測試平臺:

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 

ENTITY tb_crc IS 
END tb_crc; 

ARCHITECTURE behavior OF tb_crc IS 

-- Component Declaration for the Unit Under Test (UUT) 

COMPONENT crc 
PORT(
     clk: std_logic; 
    data_in : IN std_logic_vector(7 downto 0); 
    crc_out : OUT std_logic_vector(15 downto 0) 
    ); 
END COMPONENT; 


--Inputs 
signal tb_clk : std_logic := '0'; 
signal tb_data_in : std_logic_vector(7 downto 0) := (others => '0'); 

--Outputs 
signal tb_crc_out : std_logic_vector(15 downto 0); 

-- Clock period definitions 
constant clk_period : time := 10 ns; 

BEGIN 

-- Instantiate the Unit Under Test (UUT) 
uut: crc PORT MAP (
     clk => tb_clk, 
     data_in => tb_data_in, 
     crc_out => tb_crc_out 
    ); 

-- Clock process definitions 
clk_process :process 
begin 
    tb_clk <= '1'; 
    wait for clk_period/2; 
    tb_clk <= '0'; 
    wait for clk_period/2; 
end process; 

-- Stimulus process 
stim_proc: process 
begin  
    -- hold reset state for 100 ns. 
    wait for 100 ns; 


    -- insert stimulus here 

    tb_data_in <= x"01";   
    wait for clk_period; 

    tb_data_in <= x"02"; 
    wait for clk_period; 

    tb_data_in <= x"03"; 
    wait for clk_period; 

    tb_data_in <= x"04"; 
    wait for clk_period; 

    wait; 
end process; 

END; 

感謝您的閱讀, 克里斯

+0

你可能想看看這個通用的實現:https://github.com/VLSI-EDA/PoC/blob/master/src/comm/comm_crc.vhdl。使用可用的,經過測試的實現往往會更好。 –

+0

實際上有一個很好的例子(不使用函數調用)在線。請參見[OutputLogic.com»CRC生成器](http://outputlogic.com/?page_id=321),其數據寬度爲8,多項式寬度爲16,協議爲CRC16(適用於USB 2.0)(與0x8005相同)。第二個選項卡允許您生成VHDL示例代碼(我認爲美國版權法規定,推送按鈕的人是作者,意味着版權聲明可能無效)。任何方式顯示如何引入每個時​​鐘的成功字節並生成crc。 – user1155120

+0

OutputLogic.com使用的VHDL crc生成器的聲稱源可以通過登錄(需要註冊)從opencores [Parallel CRC Generator](http://opencores.org/project,parallelcrcgen)下載。 – user1155120

回答

2

並行CRC生成各種網站上常用的軟件是開源的。我下載並將源代碼從C++轉換爲C(布爾型,布爾型和值true和false的聲明)。

許可條款允許修改,同時保留版權聲明。我刪除了輸出中的無效版權聲明,並修正了免責聲明中的一些評論字符,並修改了適合的格式。 (我總是打算將輸出符合80列,排列在列中也是有用的)。

它產生代碼幾乎相同你的:

CRC根VHDL 8 16 8005

------------------------------------------------------------------------------- 
-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS 
-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
------------------------------------------------------------------------------- 
-- CRC entity/architecture for 
-- data(7:0) 
-- crc(15:0) = 1+x^2+x^15+x^16; 
-- 
library ieee; 
use ieee.std_logic_1164.all; 

entity crc is 
    port (
     data_in: in std_logic_vector (7 downto 0); 
     crc_en: in std_logic; 
     rst:  in std_logic; 
     clk:  in std_logic; 
     crc_out: out std_logic_vector (15 downto 0) 
    ); 
end entity crc; 

architecture imp_crc of crc is 
    signal lfsr_q: std_logic_vector (15 downto 0); 
    signal lfsr_c: std_logic_vector (15 downto 0); 
begin 
    crc_out <= lfsr_q; 

    lfsr_c(0) <= lfsr_q(8) xor lfsr_q(9) xor lfsr_q(10) xor lfsr_q(11) xor 
       lfsr_q(12) xor lfsr_q(13) xor lfsr_q(14) xor lfsr_q(15) xor 
       data_in(0) xor data_in(1) xor data_in(2) xor data_in(3) xor 
       data_in(4) xor data_in(5) xor data_in(6) xor data_in(7); 
    lfsr_c(1) <= lfsr_q(9) xor lfsr_q(10) xor lfsr_q(11) xor lfsr_q(12) xor 
       lfsr_q(13) xor lfsr_q(14) xor lfsr_q(15) xor data_in(1) xor 
       data_in(2) xor data_in(3) xor data_in(4) xor data_in(5) xor 
       data_in(6) xor data_in(7); 
    lfsr_c(2) <= lfsr_q(8) xor lfsr_q(9) xor data_in(0) xor data_in(1); 
    lfsr_c(3) <= lfsr_q(9) xor lfsr_q(10) xor data_in(1) xor data_in(2); 
    lfsr_c(4) <= lfsr_q(10) xor lfsr_q(11) xor data_in(2) xor data_in(3); 
    lfsr_c(5) <= lfsr_q(11) xor lfsr_q(12) xor data_in(3) xor data_in(4); 
    lfsr_c(6) <= lfsr_q(12) xor lfsr_q(13) xor data_in(4) xor data_in(5); 
    lfsr_c(7) <= lfsr_q(13) xor lfsr_q(14) xor data_in(5) xor data_in(6); 
    lfsr_c(8) <= lfsr_q(0) xor lfsr_q(14) xor lfsr_q(15) xor data_in(6) xor 
       data_in(7); 
    lfsr_c(9) <= lfsr_q(1) xor lfsr_q(15) xor data_in(7); 
    lfsr_c(10) <= lfsr_q(2); 
    lfsr_c(11) <= lfsr_q(3); 
    lfsr_c(12) <= lfsr_q(4); 
    lfsr_c(13) <= lfsr_q(5); 
    lfsr_c(14) <= lfsr_q(6); 
    lfsr_c(15) <= lfsr_q(7) xor lfsr_q(8) xor lfsr_q(9) xor lfsr_q(10) xor 
        lfsr_q(11) xor lfsr_q(12) xor lfsr_q(13) xor lfsr_q(14) xor 
        lfsr_q(15) xor data_in(0) xor data_in(1) xor data_in(2) xor 
        data_in(3) xor data_in(4) xor data_in(5) xor data_in(6) xor 
        data_in(7); 

REGISTERS: 
    process (clk, rst) 
    begin 
     if rst = '1' then 
      lfsr_q <= (others => '1'); 
     elsif rising_edge(clk) then 
      if crc_en = '1' then 
       lfsr_q <= lfsr_c; 
      end if; 
     end if; 
    end process; 
end architecture imp_crc; 

有趣的特點是該方法,它使用一個時鐘控制寄存器保持一個運行計數的CRC以及通過重置提供種子((others => '1'),相當於x"FFFF",基於lfsr_q的長度)。

您可以使用復位來設置狀態,以開始累計CRC的連續字節以及crc_en以控制CRC中包含哪些時鐘輸入字節。

您可以使用多路複用器來選擇x"FFFF"或存儲的CRC,因此在正在評估的塊之間不會出現「停機時間」,即將延遲串行化以包含多路複用器。

我想象一個啓用在任何情況下都可能是必不可少的。你可以通過添加一個或兩個更多的信號到你的端口接口和測試臺。

因此,一個手工製作的測試平臺使用生成的CRC碼:

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 

entity crc_tb is 
end entity; 

architecture foo of crc_tb is 

    function reverse_vector(v: in std_logic_vector) 
    return std_logic_vector is 
     variable result: std_logic_vector(v'RANGE); 
     alias vr: std_logic_vector(v'REVERSE_RANGE) is v; 
    begin 
     for i in vr'RANGE loop 
      result(i) := vr(i); 
     end loop; 

     return result; 
    end;  

    signal datain: std_logic_vector (7 downto 0); 
    signal data_in: std_logic_vector (7 downto 0); 
    signal crc_en: std_logic := '0'; 
    signal rst:  std_logic; 
    signal clk:  std_logic := '0'; 
    signal crc_out: std_logic_vector (15 downto 0); 

    signal crcout: std_logic_vector (15 downto 0); 
begin 

    crcout <= not reverse_vector (crc_out); 

DUT: 
    entity work.crc 
     port map (
      data_in => data_in, 
      crc_en => crc_en, 
      rst => rst, 
      clk => clk, 
      crc_out => crc_out 
     ); 

CLOCK: 
    process 
    begin 
     wait for 5 ns; -- half the clock period 
     clk <= not clk; 
     if now > 160 ns then 
      wait; 
     end if; 
    end process; 
    STIMULI: 
    process 
    begin 
     rst <= '1'; 
     for i in 0 to 9 loop 
      wait until rising_edge(clk); 
     end loop; 
     rst <= '0'; 
     crc_en <= '1'; 
     for i in 1 to 4 loop 
      datain <= std_logic_vector(to_unsigned (i,8)); 
      data_in <= reverse_vector (std_logic_vector(to_unsigned(i,8))); 
      wait until rising_edge(clk); 
     end loop; 
     crc_en <= '0'; 
     wait until rising_edge(clk); 
     wait; 
    end process; 
end architecture; 

這給了我們:

crc_tb.png

從你的問題在你的評論這是四個正確的值x「01」,x「02」,x「03」和x「04」的連續字節,值x「D45E」。

因此,讓我們應用,爲您的代碼

首先更改:

library ieee; 
use ieee.std_logic_1164.all; 

use ieee.numeric_std.all; 

entity crc is 
port (clk: in std_logic; 
     data_in: in std_logic_vector(7 downto 0); 
     crc_en: in std_logic; -- ADDED 
     rst:  in std_logic; -- ADDED 
     crc_out: out std_logic_vector(15 downto 0) 
    ); 
end crc; 

architecture crc_arch of crc is  

function reverse_vector(v: in std_logic_vector) 
return std_logic_vector is 
    variable result: std_logic_vector(v'RANGE); 
    alias vr: std_logic_vector(v'REVERSE_RANGE) is v; 
begin 
    for i in vr'RANGE loop 
     result(i) := vr(i); 
    end loop; 

    return result; 
end;  


function crc16(data_i: in std_logic_vector(7 downto 0);    
        crc_i: in std_logic_vector(15 downto 0)) 
return std_logic_vector is 
    variable crc_o: std_logic_vector(15 downto 0); 
begin 
    crc_o(15) := crc_i(7) xor crc_i(8) xor crc_i(9) xor crc_i(10) xor crc_i(11) xor crc_i(12) xor crc_i(13) xor crc_i(14) xor crc_i(15) xor 
        data_i(0) xor data_i(1) xor data_i(2) xor data_i(3) xor data_i(4) xor data_i(5) xor data_i(6) xor data_i(7);   
    crc_o(14) := crc_i(6);  
    crc_o(13) := crc_i(5); 
    crc_o(12) := crc_i(4); 
    crc_o(11) := crc_i(3); 
    crc_o(10) := crc_i(2); 
    crc_o(9) := crc_i(1) xor crc_i(15) xor data_i(7); 
    crc_o(8) := crc_i(0) xor crc_i(14) xor crc_i(15) xor data_i(6) xor data_i(7); 
    crc_o(7) := crc_i(13) xor crc_i(14) xor data_i(5) xor data_i(6); 
    crc_o(6) := crc_i(12) xor crc_i(13) xor data_i(4) xor data_i(5);    
    crc_o(5) := crc_i(11) xor crc_i(12) xor data_i(3) xor data_i(4); 
    crc_o(4) := crc_i(10) xor crc_i(11) xor data_i(2) xor data_i(3); 
    crc_o(3) := crc_i(9) xor crc_i(10) xor data_i(1) xor data_i(2); 
    crc_o(2) := crc_i(8) xor crc_i(9) xor data_i(0) xor data_i(1); 
    crc_o(1) := crc_i(9) xor crc_i(10) xor crc_i(11) xor crc_i(12) xor crc_i(13) xor crc_i(14) xor crc_i(15) xor 
        data_i(1) xor data_i(2) xor data_i(3) xor data_i(4) xor data_i(5) xor data_i(6) xor data_i(7); 
    crc_o(0) := crc_i(8) xor crc_i(9) xor crc_i(10) xor crc_i(11) xor crc_i(12) xor crc_i(13) xor crc_i(14) xor crc_i(15) xor 
        data_i(0) xor data_i(1) xor data_i(2) xor data_i(3) xor data_i(4) xor data_i(5) xor data_i(6) xor data_i(7); 

    return crc_o; 

end; 

    signal crc_o: std_logic_vector (15 downto 0); -- ADDED register 

begin 

    -- crc_out <= not reverse_vector(crc16(reverse_vector(data_in), x"FFFF")); 

    process (clk) -- ADDED process 
    begin 
     if rst = '1' then 
      crc_o <= x"FFFF"; 
     elsif rising_edge(clk) then 
      if crc_en = '1' then 
       crc_o <= crc16(reverse_vector(data_in), crc_o); 
      end if; 
     end if; 
    end process; 

    crc_out <= not reverse_vector(crc_o); -- ADDED 

end architecture crc_arch; 

添加的控件rstcrc_en到實體端口,增加了一個聲明的信號保持寄存器CRC值,打破了反轉和反轉,因此它不在crc_i函數調用的路徑中。

寄存器的輸入是crc16函數調用的返回值。該寄存器被重置爲CRC種子值。

測試平臺簡單了:

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 

entity crc_tb is 
end entity; 

architecture foo of crc_tb is 

    signal data_in: std_logic_vector (7 downto 0); 
    signal crc_en: std_logic := '0'; 
    signal rst:  std_logic; 
    signal clk:  std_logic := '0'; 
    signal crc_out: std_logic_vector (15 downto 0); 

begin 

DUT: 
    entity work.crc 
     port map (
      data_in => data_in, 
      crc_en => crc_en, 
      rst => rst, 
      clk => clk, 
      crc_out => crc_out 
     ); 

CLOCK: 
    process 
    begin 
     wait for 5 ns; -- half the clock period 
     clk <= not clk; 
     if now > 160 ns then 
      wait; 
     end if; 
    end process; 
STIMULI: 
    process 
    begin 
     rst <= '1'; 
     for i in 0 to 9 loop 
      wait until rising_edge(clk); 
     end loop; 
     rst <= '0'; 
     crc_en <= '1'; 
     for i in 1 to 4 loop 
      data_in <= std_logic_vector(to_unsigned (i,8)); 
      wait until rising_edge(clk); 
     end loop; 
     crc_en <= '0'; 
     wait until rising_edge(clk); 
     wait; 
    end process; 
end architecture; 

所有的變化是消減。

這一點讓:

crc_tb_chris.png

相同的答案是使用下載/生成VHDL代碼。

因此,使用你crc16函數調用的祕訣就是不要做任何反轉或從它的返回值到crc16函數調用的crc_i參數的反轉。

+0

我很欣賞你的努力,尤其是因爲它建立在我現在所擁有的基礎之上。有一個冷的。 – user2286339