mirror of
https://github.com/lcbcFoo/ReonV.git
synced 2025-04-23 21:17:07 -04:00
243 lines
8.5 KiB
VHDL
243 lines
8.5 KiB
VHDL
------------------------------------------------------------------------------
|
|
-- 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;
|
|
|