ReonV/lib/techmap/inferred/sim_pll.vhd

209 lines
6.3 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: sim_pll
-- File: sim_pll.vhd
-- Author: Magnus Hjorth, Aeroflex Gaisler
-- Description: Generic simulated PLL with input frequency checking
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
library grlib;
use grlib.stdlib.all;
entity sim_pll is
generic (
clkmul: integer := 1;
clkdiv1: integer := 1;
clkphase1: integer := 0;
clkdiv2: integer := 1;
clkphase2: integer := 0;
clkdiv3: integer := 1;
clkphase3: integer := 0;
clkdiv4: integer := 1;
clkphase4: integer := 0;
-- Frequency limits in kHz, for checking only
minfreq: integer := 0;
maxfreq: integer := 10000000;
-- Lock tolerance in ps
locktol: integer := 2
);
port (
i: in std_logic;
o1: out std_logic;
o2: out std_logic;
o3: out std_logic;
o4: out std_logic;
lock: out std_logic;
rst: in std_logic
);
end;
architecture sim of sim_pll is
signal clkout1,clkout2,clkout3,clkout4: std_logic;
signal tp: time := 1 ns;
signal timeset: boolean := false;
signal fb: std_ulogic;
signal comp: time := 0 ns;
signal llock: std_logic;
begin
o1 <= transport clkout1 after tp + (tp*clkdiv1*(clkphase1 mod 360)) / (clkmul*360);
o2 <= transport clkout2 after tp + (tp*clkdiv2*(clkphase2 mod 360)) / (clkmul*360);
o3 <= transport clkout3 after tp + (tp*clkdiv3*(clkphase3 mod 360)) / (clkmul*360);
o4 <= transport clkout4 after tp + (tp*clkdiv4*(clkphase4 mod 360)) / (clkmul*360);
lock <= llock after tp*20; -- 20 cycle inertia on lock signal
freqmeas: process(i)
variable ts,te: time;
variable mf: integer;
variable warned: boolean := false;
variable first: boolean := true;
begin
if rising_edge(i) and (now /= (0 ps)) then
ts := te;
te := now;
if first then
first := false;
else
mf := (1 ms) / (te-ts);
assert (mf >= minfreq and mf <= maxfreq) or warned or rst='0' or llock/='1'
report "Input frequency out of range, " &
"measured: " & tost(mf) & ", min:" & tost(minfreq) & ", max:" & tost(maxfreq)
severity warning;
if (mf < minfreq or mf > maxfreq) and rst/='0' and llock='1' then warned := true; end if;
if llock='0' or te-ts-tp > locktol*(1 ps) or te-ts-tp < -locktol*(1 ps) then
tp <= te-ts;
timeset <= true;
end if;
end if;
end if;
end process;
genclk: process
variable divcount1,divcount2,divcount3,divcount4: integer;
variable compen: boolean;
variable t: time;
variable compps: integer;
begin
compen := false;
clkout1 <= '0';
clkout2 <= '0';
clkout3 <= '0';
clkout4 <= '0';
if not timeset or rst='0' then
wait until timeset and rst/='0';
end if;
divcount1 := 0;
divcount2 := 0;
divcount3 := 0;
divcount4 := 0;
fb <= '1';
clkout1 <= '1';
clkout2 <= '1';
clkout3 <= '1';
clkout4 <= '1';
oloop: loop
for x in 0 to 2*clkmul-1 loop
if x=0 then fb <= '1'; end if;
if x=clkmul then fb <= '0'; end if;
t := tp/(2*clkmul);
if compen and comp /= (0 ns) then
-- Handle compensation below resolution limit (1 ps assumed)
if comp < 2*clkmul*(1 ps) and comp > -2*clkmul*(1 ps) then
compps := abs(comp / (1 ps));
if x > 0 and x <= compps then
if comp > 0 ps then
t := t + 1 ps;
else
t := t - 1 ps;
end if;
end if;
else
t:=t+comp/(2*clkmul);
end if;
end if;
if t > (0 ns) then
wait on rst for t;
else
wait for 1 ns;
end if;
exit oloop when rst='0';
divcount1 := divcount1+1;
if divcount1 >= clkdiv1 then
clkout1 <= not clkout1;
divcount1 := 0;
end if;
divcount2 := divcount2+1;
if divcount2 >= clkdiv2 then
clkout2 <= not clkout2;
divcount2 := 0;
end if;
divcount3 := divcount3+1;
if divcount3 >= clkdiv3 then
clkout3 <= not clkout3;
divcount3 := 0;
end if;
divcount4 := divcount4+1;
if divcount4 >= clkdiv4 then
clkout4 <= not clkout4;
divcount4 := 0;
end if;
end loop;
compen := true;
end loop oloop;
end process;
fbchk: process(fb,i)
variable last_i,prev_i: time;
variable last_fb,prev_fb: time;
variable vlock: std_logic := '0';
begin
if falling_edge(i) then
prev_i := last_i;
last_i := now;
end if;
if falling_edge(fb) then
-- Update phase compensation
if last_i < last_fb+tp/2 then
comp <= (last_i - last_fb);
else
comp <= last_i - now;
end if;
prev_fb := last_fb;
last_fb := now;
end if;
if (last_i<=(last_fb+locktol*(1 ps)) and last_i>=(last_fb-locktol*(1 ps)) and
prev_i<=(prev_fb+locktol*(1 ps)) and prev_i>=(prev_fb-locktol*(1 ps))) then
vlock := '1';
end if;
if prev_fb > last_i+locktol*(1 ps) or prev_i>last_fb+locktol*(1 ps) then
vlock := '0';
end if;
llock <= vlock;
end process;
end;