------------------------------------------------------------------------------ -- This file is a part of the GRLIB VHDL IP LIBRARY -- Copyright (C) 2003 - 2008, Gaisler Research -- Copyright (C) 2008 - 2014, Aeroflex Gaisler -- Copyright (C) 2015 - 2017, Cobham Gaisler -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ----------------------------------------------------------------------------- -- Entity: synciotest -- File: synciotest.vhd -- Author: Magnus Hjorth - Aeroflex Gaisler -- Description: Synchronous I/O test module ------------------------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library grlib; use grlib.stdlib.all; entity synciotest is generic ( ninputs : integer := 1; noutputs : integer := 1; nbidir : integer := 1; dirmode: integer range 0 to 2 := 0 -- 0=both, 1=in-only, 2=out-only ); port ( clk: in std_ulogic; rstn: in std_ulogic; datain: in std_logic_vector(ninputs+nbidir-1 downto 0); dataout: out std_logic_vector(noutputs+nbidir-1 downto 0); -- 000=stopped, 001=input 010=output one-by-one, 011=output prng -- 110=on-off 111=on-off with oe toggle -- bit 5:3 inverted copy of 2:0, otherwise stopped tmode: in std_logic_vector(5 downto 0); tmodeact: out std_ulogic; tmodeoe: out std_ulogic -- 0=input, 1=output ); end; architecture rtl of synciotest is constant bytelanes_in : integer := (ninputs+nbidir)/8; -- rounded down constant bytelanes_out : integer := (noutputs+nbidir+7)/8; -- rounded up function int_max(i1,i2: integer) return integer is begin if i1>i2 then return i1; else return i2; end if; end int_max; constant bytelanes_max: integer := int_max(bytelanes_in, bytelanes_out); -- LFSR with period 255 (x^8+x^6+x^5+x^4+1) -- Rotate 7 steps each time to remove correlation between bits -- between successive samples -- Step State -->shift direction---> -- *8 7 *6 *5 *4 3 2 1 -- 0 a b c d e f g h -- 1 h a hb hc hd e f g -- 2 g h ga ghb ghc hd e f -- 3 f g fh fga fghb ghc hd e -- 4 e f eg efh efga fghb ghc hd -- 5 hd e hdf hdeg def efga fghb ghc -- 6 ghc hd ghce gcdf cde def efga fghb -- 7 fghb ghc fgbd fbce hbcd cde def efga subtype lfsrstate is std_logic_vector(8 downto 1); function nextlfsr (s: lfsrstate) return lfsrstate is variable nsx: lfsrstate; variable a,b,c,d,e,f,g,h: std_ulogic; begin a := s(8); b := s(7); c := s(6); d := s(5); e := s(4); f := s(3); g := s(2); h := s(1); nsx := (f xor g xor h xor b) & (g xor h xor c) & (f xor g xor b xor d) & (f xor b xor c xor e) & (h xor b xor c xor d) & (c xor d xor e) & (d xor e xor f) & (e xor f xor g xor a); return nsx; end nextlfsr; type synciotest_regs is record datareg: std_logic_vector(bytelanes_max*8-1 downto 0); end record; signal r,nr: synciotest_regs; begin comb: process(rstn, tmode, datain, r) variable v: synciotest_regs; variable nls: std_logic_vector(bytelanes_max*8-1 downto 0); variable o: std_logic_vector(noutputs+nbidir-1 downto 0); variable op: std_logic_vector(2**log2(bytelanes_out*8)-1 downto 0); variable vact: std_ulogic; variable voe: std_ulogic; variable vrst, dx: std_logic_vector(bytelanes_max*8-1 downto 0); begin v := r; o := r.datareg(noutputs+nbidir-1 downto 0); op := (others => '0'); vact := '0'; voe := tmode(1); for x in 0 to bytelanes_max-1 loop nls(x*8+7 downto x*8) := nextlfsr(r.datareg(x*8+7 downto x*8)); end loop; vrst := (others => '0'); for x in 0 to bytelanes_max-1 loop vrst(x*8+7 downto x*8) := std_logic_vector(to_unsigned(x+1,8)); end loop; dx := r.datareg xor vrst; case tmode is when "110001" => -- Use datareg as sampled input and LFSR state, compare input with -- expected next state if dirmode /= 2 then vact := '1'; o(o'high downto nbidir) := (others => '0'); for x in 0 to bytelanes_in-1 loop if datain(x*8+7 downto x*8) /= nls(x*8+7 downto x*8) then o(nbidir+(x mod noutputs)) := '1'; end if; v.datareg(x*8+7 downto x*8) := datain(x*8+7 downto x*8); end loop; -- handle ninputs % 8 != 0 by re-using bottom byte lane LFSR if ninputs+nbidir > bytelanes_in*8 then if datain(ninputs+nbidir-1 downto 8*bytelanes_in) /= nls(ninputs+nbidir-bytelanes_in*8-1 downto 0) then o(nbidir+(bytelanes_in mod noutputs)) := '1'; end if; end if; end if; when "101010" => if dirmode /= 1 then vact := '1'; -- FIXME handle wrong reset vals -- Use datareg as counter -- Bits 2:0 pos in sequence "00101010" -- Bits 3 inv controls value on other outputs than tested -- Bits X:4 controls which bit is tested if dx(3)='1' then op := (others => '0'); else op := (others => '1'); end if; op(to_integer(unsigned(dx(log2(noutputs+nbidir)+3 downto 4)))) := not dx(0) and (dx(1) or dx(2)); o := op(noutputs+nbidir-1 downto 0); dx(log2(noutputs+nbidir)+3 downto 0) := std_logic_vector(unsigned(dx(log2(noutputs+nbidir)+3 downto 0))+1); v.datareg := dx xor vrst; end if; when "100011" => -- Use datareg as LFSR state, drive as output and clock in next state if dirmode /= 1 then vact := '1'; v.datareg := nls; end if; when "001110" => -- Toggle value on all outputs each cycle if dirmode /= 1 then vact := '1'; o := r.datareg(o'length-1 downto 2) & r.datareg(2) & r.datareg(2); v.datareg(r.datareg'high downto 2) := (others => r.datareg(1)); v.datareg(0) := '1'; v.datareg(1) := r.datareg(1) xor r.datareg(0); end if; when "000111" => -- Toggle output-enable each cycle, toggle all outputs whenever OE changes if dirmode /= 1 and nbidir > 0 then vact := '1'; o := r.datareg(o'length-1 downto 2) & r.datareg(2) & r.datareg(2); v.datareg(r.datareg'high downto 2) := (others => r.datareg(1)); voe := r.datareg(0); -- 2-bit counter v.datareg(0) := not v.datareg(0); v.datareg(1) := r.datareg(1) xor r.datareg(0); end if; when others => end case; if rstn='0' or tmode(2 downto 0)="000" then v.datareg := vrst; end if; nr <= v; dataout <= o; tmodeact <= vact; tmodeoe <= voe; end process; regs: process(clk) begin if rising_edge(clk) then r <= nr; end if; end process; --pragma translate_off tg: if false generate lfsrtest: process variable s: lfsrstate; variable stmap: std_logic_vector(255 downto 0); variable i,x: integer; begin print("------ LFSR test ------"); stmap := (others => '0'); s := "10000000"; i := 0; loop x := to_integer(unsigned(s)); print("State: " & tost(s)); if stmap(x)='1' then print("Looped after " & tost(i) & " iterations"); assert i=255 severity failure; assert stmap(0)='0' severity failure; for q in 1 to 255 loop assert stmap(q)='1' severity failure; end loop; print("------ LFSR test done ------"); wait; end if; stmap(x) := '1'; s := nextlfsr(s); i := i+1; end loop; end process; end generate; --pragma translate_on end;