CRC16 与 VHDL(多输入字节)
CRC16 with VHDL (multiple input bytes)
下面的 VHDL 片段正确地为我提供了单个输入字节的 16 位 CRC。
我将如何为多个输入字节扩展它,例如现在跨越的框架
128 个字节要进行 CRC 校验?
注意:函数 'crc16' 是使用一些在线工具生成的,但我也是自己导出的,所以我相信它可以正常工作。目前,下面的测试平台每次调用提供一个字节的 CRC 函数。
CRC特性:
- CRC多项式:0x8005
- 反映的输入:是
- 输出反映:是
- 种子值:0xFFFF
- 异或输出值: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;
感谢阅读,
克里斯
各大网站常用的并行CRC生成器软件开源。我下载并将源代码从 C++ 转换为 C(boolean、bool 类型和值 true 和 false 的声明)。
许可条款允许在保留版权声明的同时进行修改。我删除了输出中无效的版权声明,并修复了免责声明中的一些注释字符,并更改了格式以适合。 (我一直打算将输出也放入 80 列中,在列中排列术语也很有用)。
它生成的代码与您的代码几乎相同:
crc-gen 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 之间使用多路复用器代替 select,因此在评估的块之间没有 'downtime',序列化延迟以包括多路复用器.
我想在任何一种情况下启用都可能是必不可少的。您可以通过向端口接口和测试台添加一个或两个以上的信号来解决问题。
所以一个使用生成的 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;
这给了我们:
根据你在问题下的评论,这是 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;
向实体端口添加了控件 rst
和 crc_en
,为保存寄存器 CRC 值的信号添加了声明,并分解了反转和反转,因此它不在 crc_i 用于 crc16 函数调用。
寄存器的输入是 crc16 函数调用的 return 值。寄存器重置为 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;
所有更改都是减法。
这给出了:
与使用 downloaded/generated VHDL 代码的答案相同。
所以使用 crc16 函数调用的秘诀是不要将它的 return 值转换为 crc16 函数调用的 crc_i 参数。
下面的 VHDL 片段正确地为我提供了单个输入字节的 16 位 CRC。 我将如何为多个输入字节扩展它,例如现在跨越的框架 128 个字节要进行 CRC 校验?
注意:函数 'crc16' 是使用一些在线工具生成的,但我也是自己导出的,所以我相信它可以正常工作。目前,下面的测试平台每次调用提供一个字节的 CRC 函数。
CRC特性:
- CRC多项式:0x8005
- 反映的输入:是
- 输出反映:是
- 种子值:0xFFFF
- 异或输出值: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;
感谢阅读, 克里斯
各大网站常用的并行CRC生成器软件开源。我下载并将源代码从 C++ 转换为 C(boolean、bool 类型和值 true 和 false 的声明)。
许可条款允许在保留版权声明的同时进行修改。我删除了输出中无效的版权声明,并修复了免责声明中的一些注释字符,并更改了格式以适合。 (我一直打算将输出也放入 80 列中,在列中排列术语也很有用)。
它生成的代码与您的代码几乎相同:
crc-gen 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 之间使用多路复用器代替 select,因此在评估的块之间没有 'downtime',序列化延迟以包括多路复用器.
我想在任何一种情况下启用都可能是必不可少的。您可以通过向端口接口和测试台添加一个或两个以上的信号来解决问题。
所以一个使用生成的 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;
这给了我们:
根据你在问题下的评论,这是 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;
向实体端口添加了控件 rst
和 crc_en
,为保存寄存器 CRC 值的信号添加了声明,并分解了反转和反转,因此它不在 crc_i 用于 crc16 函数调用。
寄存器的输入是 crc16 函数调用的 return 值。寄存器重置为 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;
所有更改都是减法。
这给出了:
与使用 downloaded/generated VHDL 代码的答案相同。
所以使用 crc16 函数调用的秘诀是不要将它的 return 值转换为 crc16 函数调用的 crc_i 参数。