diff --git a/vhdl/helpers.vhd b/vhdl/helpers.vhd new file mode 100644 index 0000000..5a44045 --- /dev/null +++ b/vhdl/helpers.vhd @@ -0,0 +1,143 @@ +-- Various smaller helpers +-- +-------------------------------------------------------------------------------- + +library ieee; + use ieee.std_logic_1164.all; + +package helpers is + -- Types + type axis_data is array (integer range <>) of std_logic_vector(31 downto 0); + + type axis_bus is record + tdata : std_logic_vector(31 downto 0); + tvalid : std_logic; + tlast : std_logic; + tready : std_logic; + end record; + + -- Case boolean to std_logic + function to_std_logic(value : boolean) return std_ulogic; + + -- Wait for c_cycles cylces of i_clk + procedure wait_clk ( + signal i_clk : in std_logic; + constant c_cycles : in integer + ); + + -- Toggle pin io_toggle for 1 cycle of i_clk + procedure toggle ( + signal i_clk : in std_logic; + signal io_toggle : inout std_logic + ); + + -- Trigger active-low reset for signal reset + procedure reset ( + signal reset : out std_logic + ); + + -- Pseudo AXI Stream Master BFM + procedure axis_send ( + signal i_clk : in std_logic; + constant i_data : in axis_data; + signal axis_tdata : out std_logic_vector(31 downto 0); + signal axis_tvalid : out std_logic; + signal axis_tlast : out std_logic; + signal axis_tready : in std_logic + ); + + -- Pseudo AXI Steam Slave BFM + procedure axis_recv ( + signal i_clk : in std_logic; + signal axis_tdata : in std_logic_vector(31 downto 0); + signal axis_tvalid : in std_logic; + signal axis_tlast : in std_logic; + signal axis_tready : out std_logic + ); +end package; + +package body helpers is + procedure wait_clk ( + signal i_clk : in std_logic; + constant c_cycles : in integer + ) is + begin + for I in 1 to c_cycles loop + wait until rising_edge(i_clk); + end loop; + end procedure; + + procedure toggle ( + signal i_clk : in std_logic; + signal io_toggle : inout std_logic + ) is + begin + io_toggle <= io_toggle xor '1'; + wait_clk(i_clk, 1); + io_toggle <= io_toggle xor '1'; + end procedure; + + procedure reset ( + signal reset : out std_logic + ) is + begin + reset <= '0'; + wait for 5 ns; + reset <= '1'; + end procedure; + + procedure axis_send ( + signal i_clk : in std_logic; + constant i_data : in axis_data; + signal axis_tdata : out std_logic_vector(31 downto 0); + signal axis_tvalid : out std_logic; + signal axis_tlast : out std_logic; + signal axis_tready : in std_logic + ) is + begin + for i in i_data'range loop + wait until rising_edge(i_clk) and axis_tready = '1'; + axis_tvalid <= '1'; + axis_tdata <= i_data(i); + + if i = i_data'high then + axis_tlast <= '1'; + else + axis_tlast <= '0'; + end if; + end loop; + + wait until rising_edge(i_clk); + axis_tvalid <= '0'; + axis_tlast <= '0'; + end procedure; + + procedure axis_recv ( + signal i_clk : in std_logic; + signal axis_tdata : in std_logic_vector(31 downto 0); + signal axis_tvalid : in std_logic; + signal axis_tlast : in std_logic; + signal axis_tready : out std_logic + ) is + begin + axis_tready <= '1'; + + loop + wait until rising_edge(i_clk) and axis_tvalid = '1'; + + if axis_tlast = '1' then + exit; + end if; + end loop; + end procedure; + + function to_std_logic(value : boolean) return std_ulogic is + begin + if value then + return('1'); + else + return('0'); + end if; + end function; + +end package body; \ No newline at end of file diff --git a/vhdl/text_util.vhd b/vhdl/text_util.vhd new file mode 100644 index 0000000..a0090e6 --- /dev/null +++ b/vhdl/text_util.vhd @@ -0,0 +1,532 @@ +-- Package for VHDL text output +-- +-- Note: +-- ----- +-- This package uses the VHDL 95 standard. +-- If VHDL 95 is not supported by your simulator +-- you need to comment out the file access functions. +-- +-- The package provides a means to output text and +-- manipulate strings. +-- +-- The basic usage is like this: >> print(s); << +-- (where s is any string) +-- To print something which is not a string it has to be converted +-- into a string first. For this purpose the package contains +-- conversion functions called >> str(...) <<. +-- For example a std_logic_vector slv would be printed like this: +-- >> print(str(slv)); <<. To print several items on one line the +-- items have to concatenated as strings with the "&" operator eg: +-- >> print("The value of slv is "& str(slv)); << +-- The string functions can also be used in assert statements as shown +-- in the example below: +-- >> assert DIN = "0101" << +-- >> report "DIN = "& str(DIN)& " expected 0101 " << +-- >> severity Error; << +-- +-------------------------------------------------------------------------------- + +library ieee; + use ieee.std_logic_1164.all; + +use std.textio.all; + +package txt_util is + + -- prints a message to the screen + procedure print(text: string); + + -- prints the message when active + -- useful for debug switches + procedure print(active: boolean; text: string); + + -- converts std_logic into a character + function chr(sl: std_logic) return character; + + -- converts std_logic into a string (1 to 1) + function str(sl: std_logic) return string; + + -- converts std_logic_vector into a string (binary base) + function str(slv: std_logic_vector) return string; + + -- converts boolean into a string + function str(b: boolean) return string; + + -- converts an integer into a single character + -- (can also be used for hex conversion and other bases) + function chr(int: integer) return character; + + -- converts integer into string using specified base + function str(int: integer; base: integer) return string; + + -- converts integer to string, using base 10 + function str(int: integer) return string; + + -- convert std_logic_vector into a string in hex format + function hstr(slv: std_logic_vector) return string; + + + -- functions to manipulate strings + ----------------------------------- + + -- convert a character to upper case + function to_upper(c: character) return character; + + -- convert a character to lower case + function to_lower(c: character) return character; + + -- convert a string to upper case + function to_upper(s: string) return string; + + -- convert a string to lower case + function to_lower(s: string) return string; + + + + -- functions to convert strings into other formats + -------------------------------------------------- + + -- converts a character into std_logic + function to_std_logic(c: character) return std_logic; + + -- converts a string into std_logic_vector + function to_std_logic_vector(s: string) return std_logic_vector; + + + + -- file I/O + ----------- + + -- read variable length string from input file + procedure str_read(file in_file: TEXT; + res_string: out string); + + -- print string to a file and start new line + procedure print(file out_file: TEXT; + new_string: in string); + + -- print character to a file and start new line + procedure print(file out_file: TEXT; + char: in character); + +end txt_util; + +package body txt_util is + -- prints text to the screen + procedure print(text: string) is + variable msg_line: line; + begin + write(msg_line, text); + writeline(output, msg_line); + end print; + + + -- prints text to the screen when active + procedure print(active: boolean; text: string) is + begin + if active then + print(text); + end if; + end print; + + + -- converts std_logic into a character + function chr(sl: std_logic) return character is + variable c: character; + begin + case sl is + when 'U' => c:= 'U'; + when 'X' => c:= 'X'; + when '0' => c:= '0'; + when '1' => c:= '1'; + when 'Z' => c:= 'Z'; + when 'W' => c:= 'W'; + when 'L' => c:= 'L'; + when 'H' => c:= 'H'; + when '-' => c:= '-'; + end case; + + return c; + end chr; + + + -- converts std_logic into a string (1 to 1) + function str(sl: std_logic) return string is + variable s: string(1 to 1); + begin + s(1) := chr(sl); + return s; + end str; + + + -- converts std_logic_vector into a string (binary base) + -- (this also takes care of the fact that the range of + -- a string is natural while a std_logic_vector may + -- have an integer range) + function str(slv: std_logic_vector) return string is + variable result : string (1 to slv'length); + variable r : integer; + begin + r := 1; + for i in slv'range loop + result(r) := chr(slv(i)); + r := r + 1; + end loop; + return result; + end str; + + + function str(b: boolean) return string is + begin + if b then + return "true"; + else + return "false"; + end if; + end str; + + + -- converts an integer into a character + -- for 0 to 9 the obvious mapping is used, higher + -- values are mapped to the characters A-Z + -- (this is usefull for systems with base > 10) + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + function chr(int: integer) return character is + variable c: character; + begin + case int is + when 0 => c := '0'; + when 1 => c := '1'; + when 2 => c := '2'; + when 3 => c := '3'; + when 4 => c := '4'; + when 5 => c := '5'; + when 6 => c := '6'; + when 7 => c := '7'; + when 8 => c := '8'; + when 9 => c := '9'; + when 10 => c := 'A'; + when 11 => c := 'B'; + when 12 => c := 'C'; + when 13 => c := 'D'; + when 14 => c := 'E'; + when 15 => c := 'F'; + when 16 => c := 'G'; + when 17 => c := 'H'; + when 18 => c := 'I'; + when 19 => c := 'J'; + when 20 => c := 'K'; + when 21 => c := 'L'; + when 22 => c := 'M'; + when 23 => c := 'N'; + when 24 => c := 'O'; + when 25 => c := 'P'; + when 26 => c := 'Q'; + when 27 => c := 'R'; + when 28 => c := 'S'; + when 29 => c := 'T'; + when 30 => c := 'U'; + when 31 => c := 'V'; + when 32 => c := 'W'; + when 33 => c := 'X'; + when 34 => c := 'Y'; + when 35 => c := 'Z'; + when others => c := '?'; + end case; + return c; + end chr; + + + -- convert integer to string using specified base + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + function str(int: integer; base: integer) return string is + variable temp: string(1 to 10); + variable num: integer; + variable abs_int: integer; + variable len: integer := 1; + variable power: integer := 1; + begin + -- bug fix for negative numbers + abs_int := abs(int); + num := abs_int; + + -- determine how many characters required to represent the number. + while num >= base loop + len := len + 1; + num := num / base; + end loop ; + + -- convert the number to a string starting with the right hand side. + for i in len downto 1 loop + temp(i) := chr(abs_int/power mod base); + power := power * base; + end loop ; + + -- return result and add sign if required + if int < 0 then + return '-'& temp(1 to len); + else + return temp(1 to len); + end if; + end str; + + + -- convert integer to string, using base 10 + function str(int: integer) return string is + begin + return str(int, 10) ; + end str; + + -- converts a std_logic_vector into a hex string. + function hstr(slv: std_logic_vector) return string is + variable hexlen: integer; + variable longslv : std_logic_vector(67 downto 0) := (others => '0'); + variable hex : string(1 to 16); + variable fourbit : std_logic_vector(3 downto 0); + begin + hexlen := (slv'left+1)/4; + if (slv'left+1) mod 4 /= 0 then + hexlen := hexlen + 1; + end if; + + longslv(slv'left downto 0) := slv; + for i in (hexlen -1) downto 0 loop + fourbit := longslv(((i*4)+3) downto (i*4)); + case fourbit is + when "0000" => hex(hexlen -I) := '0'; + when "0001" => hex(hexlen -I) := '1'; + when "0010" => hex(hexlen -I) := '2'; + when "0011" => hex(hexlen -I) := '3'; + when "0100" => hex(hexlen -I) := '4'; + when "0101" => hex(hexlen -I) := '5'; + when "0110" => hex(hexlen -I) := '6'; + when "0111" => hex(hexlen -I) := '7'; + when "1000" => hex(hexlen -I) := '8'; + when "1001" => hex(hexlen -I) := '9'; + when "1010" => hex(hexlen -I) := 'A'; + when "1011" => hex(hexlen -I) := 'B'; + when "1100" => hex(hexlen -I) := 'C'; + when "1101" => hex(hexlen -I) := 'D'; + when "1110" => hex(hexlen -I) := 'E'; + when "1111" => hex(hexlen -I) := 'F'; + when "ZZZZ" => hex(hexlen -I) := 'z'; + when "UUUU" => hex(hexlen -I) := 'u'; + when "XXXX" => hex(hexlen -I) := 'x'; + when others => hex(hexlen -I) := '?'; + end case; + end loop; + + return hex(1 to hexlen); + end hstr; + + -- convert a character to upper case + function to_upper(c: character) return character is + variable u: character; + begin + case c is + when 'a' => u := 'A'; + when 'b' => u := 'B'; + when 'c' => u := 'C'; + when 'd' => u := 'D'; + when 'e' => u := 'E'; + when 'f' => u := 'F'; + when 'g' => u := 'G'; + when 'h' => u := 'H'; + when 'i' => u := 'I'; + when 'j' => u := 'J'; + when 'k' => u := 'K'; + when 'l' => u := 'L'; + when 'm' => u := 'M'; + when 'n' => u := 'N'; + when 'o' => u := 'O'; + when 'p' => u := 'P'; + when 'q' => u := 'Q'; + when 'r' => u := 'R'; + when 's' => u := 'S'; + when 't' => u := 'T'; + when 'u' => u := 'U'; + when 'v' => u := 'V'; + when 'w' => u := 'W'; + when 'x' => u := 'X'; + when 'y' => u := 'Y'; + when 'z' => u := 'Z'; + when others => u := c; + end case; + + return u; + end to_upper; + + -- convert a character to lower case + function to_lower(c: character) return character is + variable l: character; + begin + case c is + when 'A' => l := 'a'; + when 'B' => l := 'b'; + when 'C' => l := 'c'; + when 'D' => l := 'd'; + when 'E' => l := 'e'; + when 'F' => l := 'f'; + when 'G' => l := 'g'; + when 'H' => l := 'h'; + when 'I' => l := 'i'; + when 'J' => l := 'j'; + when 'K' => l := 'k'; + when 'L' => l := 'l'; + when 'M' => l := 'm'; + when 'N' => l := 'n'; + when 'O' => l := 'o'; + when 'P' => l := 'p'; + when 'Q' => l := 'q'; + when 'R' => l := 'r'; + when 'S' => l := 's'; + when 'T' => l := 't'; + when 'U' => l := 'u'; + when 'V' => l := 'v'; + when 'W' => l := 'w'; + when 'X' => l := 'x'; + when 'Y' => l := 'y'; + when 'Z' => l := 'z'; + when others => l := c; + end case; + + return l; + end to_lower; + + + -- convert a string to upper case + function to_upper(s: string) return string is + variable uppercase: string (s'range); + begin + for i in s'range loop + uppercase(i):= to_upper(s(i)); + end loop; + + return uppercase; + end to_upper; + + + -- convert a string to lower case + function to_lower(s: string) return string is + variable lowercase: string (s'range); + begin + for i in s'range loop + lowercase(i):= to_lower(s(i)); + end loop; + return lowercase; + end to_lower; + + + -- converts a character into a std_logic + function to_std_logic(c: character) return std_logic is + variable sl: std_logic; + begin + case c is + when 'U' => + sl := 'U'; + when 'X' => + sl := 'X'; + when '0' => + sl := '0'; + when '1' => + sl := '1'; + when 'Z' => + sl := 'Z'; + when 'W' => + sl := 'W'; + when 'L' => + sl := 'L'; + when 'H' => + sl := 'H'; + when '-' => + sl := '-'; + when others => + sl := 'X'; + end case; + + return sl; + end to_std_logic; + + + -- converts a string into std_logic_vector + function to_std_logic_vector(s: string) return std_logic_vector is + variable slv: std_logic_vector(s'high-s'low downto 0); + variable k: integer; + begin + k := s'high-s'low; + + for i in s'range loop + slv(k) := to_std_logic(s(i)); + k := k - 1; + end loop; + + return slv; + end to_std_logic_vector; + + + -- read variable length string from input file + procedure str_read( + file in_file: TEXT; + res_string: out string + ) is + variable l : line; + variable c : character; + variable is_string : boolean; + begin + readline(in_file, l); + -- clear the contents of the result string + for i in res_string'range loop + res_string(i) := ' '; + end loop; + -- read all characters of the line, up to the length + -- of the results string + for i in res_string'range loop + read(l, c, is_string); + res_string(i) := c; + if not is_string then -- found end of line + exit; + end if; + end loop; + end str_read; + + + -- print string to a file + procedure print( + file out_file: TEXT; + new_string: in string + ) is + variable l: line; + begin + write(l, new_string); + writeline(out_file, l); + end print; + + + -- print character to a file and start new line + procedure print( + file out_file: TEXT; + char: in character + ) is + variable l: line; + begin + write(l, char); + writeline(out_file, l); + end print; + + + -- appends contents of a string to a file until line feed occurs + -- (LF is considered to be the end of the string) + procedure str_write( + file out_file: TEXT; + new_string: in string + ) is + begin + for i in new_string'range loop + print(out_file, new_string(i)); + + if new_string(i) = LF then -- end of string + exit; + end if; + end loop; + end str_write; +end txt_util; \ No newline at end of file diff --git a/vhdl/two_flop_synchronizer.vhd b/vhdl/two_flop_synchronizer.vhd new file mode 100644 index 0000000..5456f27 --- /dev/null +++ b/vhdl/two_flop_synchronizer.vhd @@ -0,0 +1,40 @@ +-- Two-Flop Synchronizer +-- +-------------------------------------------------------------------------------- + +library ieee; + use ieee.std_logic_1164.all; + +entity two_flop_synchronizer is + generic ( + -- 4 ns for backward compatibility with spartan3 + META_FFS_MAXDELAY : string := "4.8 ns" + ); + port ( + i_clk : in std_logic; -- destination clock + i_signal : in std_logic; -- input + o_signal : out std_logic -- output + ); +end entity; + +architecture rtl of two_flop_synchronizer is + signal meta_signal : std_logic := '0'; + signal meta_signal_1d : std_logic := '0'; + + attribute MAXDELAY : string; + attribute ASYNC_REG : string; + + attribute MAXDELAY of meta_signal : signal is META_FFS_MAXDELAY; + attribute ASYNC_REG of meta_signal : signal is "TRUE"; + attribute ASYNC_REG of meta_signal_1d : signal is "TRUE"; +begin + o_signal <= meta_signal_1d; + + process(i_clk) + begin + if rising_edge(i_clk) then + meta_signal <= i_signal; + meta_signal_1d <= meta_signal; + end if; + end process; +end architecture; \ No newline at end of file diff --git a/vhdl/two_flop_toggle_synchronizer.vhd b/vhdl/two_flop_toggle_synchronizer.vhd new file mode 100644 index 0000000..61cea51 --- /dev/null +++ b/vhdl/two_flop_toggle_synchronizer.vhd @@ -0,0 +1,62 @@ +-- CDC Synchronizer for single pulse signals +-- +-------------------------------------------------------------------------------- + +library ieee; + use ieee.std_logic_1164.all; + +entity two_flop_toggle_synchronizer is + generic ( + -- 4 ns for backward compatibility with spartan3 + META_FFS_MAXDELAY : string := "4.8 ns" + ); + port ( + i_src_clk : in std_logic; + i_dst_clk : in std_logic; + i_rst : in std_logic; + i_signal : in std_logic; + o_signal : out std_logic + ); +end entity; + +architecture rtl of two_flop_toggle_synchronizer is + signal s_tff : std_logic; + signal s_resynch : std_logic := '0'; + signal s_resynch_1d : std_logic := '0'; + signal s_resynch_2d : std_logic := '0'; + + attribute MAXDELAY : string; + attribute ASYNC_REG : string; + + attribute MAXDELAY of s_tff : signal is META_FFS_MAXDELAY; + attribute MAXDELAY of s_resynch : signal is META_FFS_MAXDELAY; + attribute MAXDELAY of s_resynch_1d : signal is META_FFS_MAXDELAY; + attribute MAXDELAY of s_resynch_2d : signal is META_FFS_MAXDELAY; + attribute ASYNC_REG of s_resynch : signal is "TRUE"; + attribute ASYNC_REG of s_resynch_1d : signal is "TRUE"; + attribute ASYNC_REG of s_resynch_2d : signal is "TRUE"; +begin + TFF: process (i_src_clk, i_rst) + begin + if i_rst = '0' then + s_tff <= '0'; + elsif rising_edge(i_src_clk) then + s_tff <= s_tff XOR i_signal; + end if; + end process; + + EDGE_SYNC: process (i_dst_clk, i_rst) + begin + if i_rst = '0' then + s_resynch <= '0'; + s_resynch_1d <= '0'; + s_resynch_2d <= '0'; + o_signal <= '0'; + elsif rising_edge(i_dst_clk) then + s_resynch <= s_tff; + s_resynch_1d <= s_resynch; + s_resynch_2d <= s_resynch_1d; + o_signal <= s_resynch_2d xor s_resynch_1d; + end if; + end process; +end architecture; \ No newline at end of file