sys: update the scaler.

This commit is contained in:
sorgelig
2019-02-13 15:43:40 +08:00
parent 3b7a882182
commit 32658ca65d
2 changed files with 539 additions and 631 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -5,14 +5,15 @@
-- Changes the HDMI PLL frequency according to the scaler suggestions.
--------------------------------------------
-- LLTUNE :
-- 15 : Toggle
-- 14 : Unused
-- 13 : Sign phase difference
-- 12:8 : Phase difference. Log (0=Large 31=Small)
-- 7:6 : Unused
-- 5 : Sign period difference.
-- 4:0 : Period difference. Log (0=Large 31=Small)
-- 0 : Input Syncline
-- 1 :
-- 2 : Input Interlaced mode
-- 3 : Input Interlaced field
-- 4 : Output Syncline
-- 5 :
-- 6 : Input clock
-- 7 : Output clock
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
@@ -23,6 +24,8 @@ ENTITY pll_hdmi_adj IS
llena : IN std_logic; -- 0=Disabled 1=Enabled
lltune : IN unsigned(15 DOWNTO 0); -- Outputs from scaler
locked : OUT std_logic;
-- Signals from reconfig commands
i_waitrequest : OUT std_logic;
i_write : IN std_logic;
@@ -51,24 +54,115 @@ ARCHITECTURE rtl OF pll_hdmi_adj IS
SIGNAL pwrite : std_logic;
SIGNAL paddress : unsigned(5 DOWNTO 0);
SIGNAL pdata : unsigned(31 DOWNTO 0);
TYPE enum_state IS (sIDLE,sW1,sW2,sW3);
TYPE enum_state IS (sIDLE,sW1,sW2,sW3,sW4,sW5,sW6);
SIGNAL state : enum_state;
SIGNAL tune_freq,tune_phase : unsigned(5 DOWNTO 0);
SIGNAL lltune_sync,lltune_sync2,lltune_sync3 : unsigned(15 DOWNTO 0);
SIGNAL mfrac,mfrac_mem : unsigned(31 DOWNTO 0);
SIGNAL mfrac,mfrac_mem,mfrac_ref,diff : unsigned(40 DOWNTO 0);
SIGNAL mul : unsigned(15 DOWNTO 0);
SIGNAL sign,sign_pre : std_logic;
SIGNAL up,modo,phm,dir : std_logic;
SIGNAL fcpt : natural RANGE 0 TO 3;
SIGNAL cptx : natural RANGE 0 TO 3;
SIGNAL cpt : natural RANGE 0 TO 4095;
SIGNAL phcor : natural RANGE 0 TO 3;
SIGNAL diff : unsigned(31 DOWNTO 0);
TYPE enum_tstate IS (sWAIT,sADJ,sADJ2);
SIGNAL tstate : enum_tstate;
SIGNAL cpt : natural RANGE 0 TO 3;
SIGNAL col : natural RANGE 0 TO 15;
SIGNAL icpt,ocpt,ssh : natural RANGE 0 TO 2**24-1;
SIGNAL isync,isync2,itog,ipulse : std_logic;
SIGNAL osync,osync2,otog,opulse : std_logic;
SIGNAL sync,pulse,los,lop : std_logic;
SIGNAL osize,isize,offset,osizep : signed(23 DOWNTO 0);
SIGNAL logcpt : natural RANGE 0 TO 31;
SIGNAL udiff : integer RANGE -2**23 TO 2**23-1 :=0;
BEGIN
----------------------------------------------------------------------------
-- Sample image sizes
Sampler:PROCESS(clk,reset_na) IS
BEGIN
IF reset_na='0' THEN
--pragma synthesis_off
otog<='0';
itog<='0';
isync<='0';
isync2<='0';
osync<='0';
osync2<='0';
--pragma synthesis_on
ELSIF rising_edge(clk) THEN
-- Clock domain crossing
isync<=lltune(0); -- <ASYNC>
isync2<=isync;
osync<=lltune(4); -- <ASYNC>
osync2<=osync;
itog<=itog XOR (isync AND NOT isync2);
otog<=otog XOR (osync AND NOT osync2);
ipulse<=isync AND NOT isync2 AND itog;
opulse<=osync AND NOT osync2 AND otog;
-- Measure output image size
IF osync='1' AND osync2='0' AND otog='1' THEN
ocpt<=0;
osizep<=to_signed(ocpt,24);
ELSE
ocpt<=ocpt+1;
END IF;
-- Measure input image size
IF isync='1' AND isync2='0' AND itog='1' THEN
icpt<=0;
isize<=to_signed(icpt,24);
osize<=osizep;
offset<=to_signed(ocpt,24);
udiff<=integer(to_integer(osizep)) - integer(icpt);
sync<='1';
ELSE
icpt<=icpt+1;
sync<='0';
END IF;
--------------------------------------------
pulse<='0';
IF sync='1' THEN
logcpt<=0;
ssh<=to_integer(osize);
los<='0';
lop<='0';
ELSIF logcpt<24 THEN
-- Frequency difference
IF udiff>0 AND ssh<udiff AND los='0' THEN
tune_freq<='0' & to_unsigned(logcpt,5);
los<='1';
ELSIF udiff<=0 AND ssh<-udiff AND los='0' THEN
tune_freq<='1' & to_unsigned(logcpt,5);
los<='1';
END IF;
-- Phase difference
IF offset<osize/2 AND ssh<offset AND lop='0' THEN
tune_phase<='0' & to_unsigned(logcpt,5);
lop<='1';
ELSIF offset>=osize/2 AND ssh<(osize-offset) AND lop='0' THEN
tune_phase<='1' & to_unsigned(logcpt,5);
lop<='1';
END IF;
ssh<=ssh/2;
logcpt<=logcpt+1;
ELSIF logcpt=24 THEN
pulse<='1';
ssh<=ssh/2;
logcpt<=logcpt+1;
END IF;
END IF;
END PROCESS Sampler;
----------------------------------------------------------------------------
-- 000010 : Start reg "Write either 0 or 1 to start fractional PLL reconf.
-- 000111 : M counter Fractional Value
-- 000100 : M counter
-- 000111 : M counter Fractional Value K
Comb:PROCESS(i_write,i_address,
i_writedata,pwrite,paddress,pdata) IS
@@ -88,141 +182,169 @@ BEGIN
----------------------------------------------------------------------------
Schmurtz:PROCESS(clk,reset_na) IS
VARIABLE off,ofp : natural RANGE 0 TO 63;
VARIABLE dif : unsigned(31 DOWNTO 0);
VARIABLE off_v,ofp_v : natural RANGE 0 TO 63;
VARIABLE diff_v : unsigned(40 DOWNTO 0);
VARIABLE mulco : unsigned(15 DOWNTO 0);
VARIABLE up_v,sign_v : std_logic;
BEGIN
IF reset_na='0' THEN
modo<='0';
state<=sIDLE;
ELSIF rising_edge(clk) THEN
IF i_address="000111" AND i_write='1' THEN
mfrac<=i_writedata;
mfrac_mem<=i_writedata;
------------------------------------------------------
-- Snoop accesses to PLL reconfiguration
IF i_address="000100" AND i_write='1' THEN
mfrac (40 DOWNTO 32)<=('0' & i_writedata(15 DOWNTO 8)) +
('0' & i_writedata(7 DOWNTO 0));
mfrac_ref(40 DOWNTO 32)<=('0' & i_writedata(15 DOWNTO 8)) +
('0' & i_writedata(7 DOWNTO 0));
mfrac_mem(40 DOWNTO 32)<=('0' & i_writedata(15 DOWNTO 8)) +
('0' & i_writedata(7 DOWNTO 0));
mul<=i_writedata(15 DOWNTO 0);
modo<='1';
END IF;
lltune_sync<=lltune; -- <ASYNC>
lltune_sync2<=lltune_sync;
lltune_sync3<=lltune_sync2;
off:=to_integer('0' & lltune_sync(4 DOWNTO 0));
ofp:=to_integer('0' & lltune_sync(12 DOWNTO 8));
IF lltune_sync(15)/=lltune_sync2(15) THEN
fcpt<=fcpt+1;
IF fcpt=2 THEN fcpt<=0; END IF;
IF i_address="000111" AND i_write='1' THEN
mfrac (31 DOWNTO 0)<=i_writedata;
mfrac_ref(31 DOWNTO 0)<=i_writedata;
mfrac_mem(31 DOWNTO 0)<=i_writedata;
modo<='1';
END IF;
CASE tstate IS
WHEN sWAIT =>
cpt<=0;
IF lltune_sync3(15)/=lltune_sync2(15) AND llena='1' THEN
IF llena='0' THEN
-- Recover original freq when disabling low lag mode
phm<='0';
IF modo='1' THEN
mfrac<=mfrac_mem;
up<='1';
modo<='0';
END IF;
ELSIF phm='0' AND fcpt=2 THEN
-- Frequency adjust
IF off<10 THEN off:=10; END IF;
dif:=shift_right(mfrac,off + 1);
diff<=dif;
sign<=lltune_sync(5);
IF off>=18 THEN
phm<='1';
ELSE
tstate<=sADJ;
END IF;
cptx<=0;
ELSIF phm='1' THEN
-- Phase adjust
IF ofp<5 THEN ofp:=5; END IF;
dif:=shift_right(mfrac,ofp + 3 + 1);
IF (ofp>=18 OR off<16) AND fcpt=2 AND phcor=0 THEN
phm<='0';
END IF;
IF phcor=0 THEN
IF cptx=0 THEN
sign<=NOT lltune_sync(13);
sign_pre<=sign;
diff<=dif;
IF sign_pre/=NOT lltune_sync(13) THEN
diff<='0' & dif(31 DOWNTO 1);
END IF;
END IF;
cptx<=cptx+1;
IF cptx=2 THEN
cptx<=0;
sign<=NOT sign;
phcor<=1;
END IF;
tstate<=sADJ;
ELSIF phcor=1 THEN
cptx<=cptx+1;
IF cptx=2 THEN
cptx<=0;
phcor<=2;
tstate<=sADJ;
END IF;
ELSIF fcpt=2 THEN
phcor<=0;
cptx<=0;
END IF;
END IF;
END IF;
WHEN sADJ =>
IF sign='0' THEN
mfrac<=mfrac + diff(31 DOWNTO 8);
ELSE
mfrac<=mfrac - diff(31 DOWNTO 8);
END IF;
IF up='0' THEN
up<='1';
tstate<=sADJ2;
END IF;
WHEN sADJ2 =>
cpt<=cpt+1;
IF cpt=1023 THEN
tstate<=sWAIT;
ELSE
tstate<=sADJ;
END IF;
END CASE;
------------------------------------------------------
-- Tuning
off_v:=to_integer('0' & tune_freq(4 DOWNTO 0));
ofp_v:=to_integer('0' & tune_phase(4 DOWNTO 0));
--IF off_v<8 THEN off_v:=8; END IF;
--IF ofp_v<7 THEN ofp_v:=7; END IF;
IF off_v<4 THEN off_v:=4; END IF;
IF ofp_v<4 THEN ofp_v:=4; END IF;
IF off_v>=18 AND ofp_v>=18 THEN
locked<=llena;
ELSE
locked<='0';
END IF;
up_v:='0';
IF pulse='1' THEN
cpt<=(cpt+1) MOD 4;
IF llena='0' THEN
-- Recover original freq when disabling low lag mode
cpt<=0;
col<=0;
IF modo='1' THEN
mfrac<=mfrac_mem;
mfrac_ref<=mfrac_mem;
up<='1';
modo<='0';
END IF;
ELSIF phm='0' AND cpt=0 THEN
-- Frequency adjust
sign_v:=tune_freq(5);
IF col<10 THEN col<=col+1; END IF;
IF off_v>=16 AND col>=10 THEN
phm<='1';
col<=0;
ELSE
off_v:=off_v+1;
IF off_v>17 THEN
off_v:=off_v + 3;
END IF;
up_v:='1';
up<='1';
END IF;
ELSIF cpt=0 THEN
-- Phase adjust
sign_v:=NOT tune_phase(5);
col<=col+1;
IF col>=10 THEN
phm<='0';
up_v:='1';
off_v:=31;
col<=0;
ELSE
off_v:=ofp_v + 1;
IF ofp_v>7 THEN
off_v:=off_v + 1;
END IF;
IF ofp_v>14 THEN
off_v:=off_v + 2;
END IF;
IF ofp_v>17 THEN
off_v:=off_v + 3;
END IF;
up_v:='1';
END IF;
up<='1';
END IF;
END IF;
diff_v:=shift_right(mfrac_ref,off_v);
IF sign_v='0' THEN
diff_v:=mfrac_ref + diff_v;
ELSE
diff_v:=mfrac_ref - diff_v;
END IF;
IF up_v='1' THEN
mfrac<=diff_v;
END IF;
IF up_v='1' AND phm='0' THEN
mfrac_ref<=diff_v;
END IF;
------------------------------------------------------
-- Update PLL registers
mulco:=mfrac(40 DOWNTO 33) & (mfrac(40 DOWNTO 33) + ('0' & mfrac(32)));
CASE state IS
WHEN sIDLE =>
pwrite<='0';
IF up='1' THEN
up<='0';
state<=sW1;
pdata<=mfrac;
paddress<="000111";
pwrite<='1';
IF mulco/=mul THEN
state<=sW1;
ELSE
state<=sW3;
END IF;
END IF;
WHEN sW1 =>
WHEN sW1 => -- Change M multiplier
mul<=mulco;
pdata<=x"0000" & mulco;
paddress<="000100";
pwrite<='1';
state<=sW2;
WHEN sW2 =>
IF pwrite='1' AND o_waitrequest='0' THEN
state<=sW2;
state<=sW3;
pwrite<='0';
END IF;
WHEN sW2 =>
WHEN sW3 => -- Change M fractional value
pdata<=mfrac(31 DOWNTO 0);
paddress<="000111";
pwrite<='1';
state<=sW4;
WHEN sW4 =>
IF pwrite='1' AND o_waitrequest='0' THEN
state<=sW5;
pwrite<='0';
END IF;
WHEN sW5 =>
pdata<=x"0000_0001";
paddress<="000010";
pwrite<='1';
state<=sW3;
state<=sW6;
WHEN sW3 =>
WHEN sW6 =>
IF pwrite='1' AND o_waitrequest='0' THEN
pwrite<='0';
state<=sIDLE;
@@ -233,7 +355,6 @@ BEGIN
END PROCESS Schmurtz;
----------------------------------------------------------------------------
END ARCHITECTURE rtl;