From 355bbc5ab15d5a8b946fe28d619e053e17935b46 Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Mon, 30 Aug 2021 12:15:23 +0200 Subject: [PATCH] mac: Add generic CRC --- bench/bench_crc.vhd | 77 +++++++++++++++++++++++++++++++++++++++++++++ trashernet/crc.vhd | 58 ++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 bench/bench_crc.vhd create mode 100644 trashernet/crc.vhd diff --git a/bench/bench_crc.vhd b/bench/bench_crc.vhd new file mode 100644 index 0000000..0b2049f --- /dev/null +++ b/bench/bench_crc.vhd @@ -0,0 +1,77 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library trashernet; + +entity bench_crc is +end entity bench_crc; + +architecture bench of bench_crc is + constant POLYNOMIAL : std_logic_vector(31 downto 0) := x"04C11DB7"; + signal clk : std_logic; + signal rst : std_logic; + signal data : std_logic_vector(7 downto 0); + signal data_valid : std_logic; + signal crc_clear : std_logic; + signal crc_out : std_logic_vector(POLYNOMIAL'range); +begin + crc_inst : entity trashernet.crc + generic map( + POLYNOMIAL => POLYNOMIAL, + START => x"FFFFFFFF", + FINAL_XOR => x"FFFFFFFF", + REVERSE_OUT => true + ) + port map( + clk => clk, + rst => rst, + data => data, + data_valid => data_valid, + crc_clear => crc_clear, + crc_out => crc_out + ); + + clock_driver : process + constant period : time := 10 ns; + begin + clk <= '0'; + wait for period / 2; + clk <= '1'; + wait for period / 2; + end process clock_driver; + + test : process is + procedure send_byte(b : std_logic_vector(data'range)) is + begin + data <= b; + data_valid <= '1'; + wait until rising_edge(clk); + data_valid <= '0'; + end procedure send_byte; + + variable temp : std_logic_vector(crc_out'range); + begin + rst <= '1'; + data_valid <= '0'; + crc_clear <= '0'; + wait for 20 ns; + rst <= '0'; + + wait until rising_edge(clk); + + send_byte(x"01"); + + wait until rising_edge(clk); + + report "CRC: " & to_hstring(crc_out); + + for i in 31 downto 0 loop + temp(i) := crc_out(31 - i); + end loop; + report "BITREV: " & to_hstring(temp); + + wait; + end process test; + +end architecture bench; diff --git a/trashernet/crc.vhd b/trashernet/crc.vhd new file mode 100644 index 0000000..186eca7 --- /dev/null +++ b/trashernet/crc.vhd @@ -0,0 +1,58 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity crc is + generic( + POLYNOMIAL : std_logic_vector; -- Polynomial, leading '1' is implicit + START : std_logic_vector; -- CRC start value (after `crc_clear`) + FINAL_XOR : std_logic_vector; -- CRC will be XORed with this value on `crc_out` + REVERSE_OUT : boolean -- Bit reverse the output vector + ); + port( + clk : in std_logic; + rst : in std_logic; + data : in std_logic_vector; + data_valid : in std_logic; + crc_clear : in std_logic; + crc_out : out std_logic_vector(POLYNOMIAL'range) + ); +end entity crc; + +architecture rtl of crc is + signal crc_i : std_logic_vector(crc_out'range); + + function reverse_bits(slv : std_logic_vector) return std_logic_vector is + variable r : std_logic_vector(slv'range); + begin + for i in slv'low to slv'high loop + r(i) := slv(r'low + slv'high - i); + end loop; + return r; + end function reverse_bits; + +begin + crc_calc : process(clk, rst) is + variable crc_v : std_logic_vector(crc_out'range); + variable fb : std_logic; + begin + if rst then + crc_i <= START; + elsif rising_edge(clk) then + if data_valid then + crc_v := crc_i; + for i in data'low to data'high loop + fb := data(i) xor crc_v(crc_v'high); + crc_v := (crc_v(crc_v'high - 1 downto crc_v'low) & '0') xor (POLYNOMIAL and fb); + end loop; + crc_i <= crc_v; + end if; + + if crc_clear then + crc_i <= START; + end if; + end if; + end process crc_calc; + + crc_out <= reverse_bits(crc_i xor FINAL_XOR) when REVERSE_OUT else (crc_i xor FINAL_XOR); +end architecture rtl;