mirror of
https://github.com/MiSTer-devel/MacPlus_MiSTer.git
synced 2024-11-27 17:51:19 +00:00
434 lines
12 KiB
VHDL
434 lines
12 KiB
VHDL
--------------------------------------------------------------------------------
|
|
-- HDMI PLL Adjust
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Changes the HDMI PLL frequency according to the scaler suggestions.
|
|
--------------------------------------------
|
|
-- LLTUNE :
|
|
-- 0 : Input Display Enable
|
|
-- 1 : Input Vsync
|
|
-- 2 : Input Interlaced mode
|
|
-- 3 : Input Interlaced field
|
|
-- 4 : Output Image frame
|
|
-- 5 :
|
|
-- 6 : Input clock
|
|
-- 7 : Output clock
|
|
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.ALL;
|
|
USE ieee.numeric_std.ALL;
|
|
|
|
ENTITY pll_hdmi_adj IS
|
|
PORT (
|
|
-- Scaler
|
|
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;
|
|
i_address : IN unsigned(5 DOWNTO 0);
|
|
i_writedata : IN unsigned(31 DOWNTO 0);
|
|
|
|
-- Outputs to PLL_HDMI_CFG
|
|
o_waitrequest : IN std_logic;
|
|
o_write : OUT std_logic;
|
|
o_address : OUT unsigned(5 DOWNTO 0);
|
|
o_writedata : OUT unsigned(31 DOWNTO 0);
|
|
|
|
------------------------------------
|
|
clk : IN std_logic;
|
|
reset_na : IN std_logic
|
|
);
|
|
|
|
BEGIN
|
|
|
|
|
|
END ENTITY pll_hdmi_adj;
|
|
|
|
--##############################################################################
|
|
|
|
ARCHITECTURE rtl OF pll_hdmi_adj IS
|
|
|
|
SIGNAL i_clk,i_de,i_de2,i_vss,i_vss2,i_vss_delay,i_ce : std_logic;
|
|
SIGNAL i_linecpt,i_line : natural RANGE 0 TO 2**12-1;
|
|
SIGNAL i_delay : natural RANGE 0 TO 2**14-1;
|
|
|
|
SIGNAL pwrite : std_logic;
|
|
SIGNAL paddress : unsigned(5 DOWNTO 0);
|
|
SIGNAL pdata : unsigned(31 DOWNTO 0);
|
|
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,mfrac_ref,diff : unsigned(40 DOWNTO 0);
|
|
SIGNAL mul : unsigned(15 DOWNTO 0);
|
|
SIGNAL sign,sign_pre : std_logic;
|
|
SIGNAL expand : boolean;
|
|
SIGNAL up,modo,phm,dir : std_logic;
|
|
SIGNAL cpt : natural RANGE 0 TO 3;
|
|
SIGNAL col : natural RANGE 0 TO 15;
|
|
|
|
SIGNAL icpt,ocpt,o2cpt,ssh,ofsize,ifsize : natural RANGE 0 TO 2**24-1;
|
|
SIGNAL ivss,ivss2,itog : std_logic;
|
|
SIGNAL ovss,ovss2,otog : std_logic;
|
|
SIGNAL sync,pulse,los,lop : std_logic;
|
|
SIGNAL osize,offset,osizep,offsetp : signed(23 DOWNTO 0);
|
|
SIGNAL logcpt : natural RANGE 0 TO 31;
|
|
SIGNAL udiff : integer RANGE -2**23 TO 2**23-1 :=0;
|
|
|
|
BEGIN
|
|
|
|
----------------------------------------------------------------------------
|
|
-- 4 lines delay to input
|
|
i_vss<=lltune(0);
|
|
i_de <=lltune(1);
|
|
i_ce <=lltune(5);
|
|
i_clk<=lltune(6);
|
|
|
|
Delay:PROCESS(i_clk) IS
|
|
BEGIN
|
|
IF rising_edge(i_clk) THEN
|
|
IF i_ce='1' THEN
|
|
-- Measure input line time.
|
|
i_de2<=i_de;
|
|
|
|
IF i_de='1' AND i_de2='0' THEN
|
|
i_linecpt<=0;
|
|
IF i_vss='1' THEN
|
|
i_line<=i_linecpt;
|
|
END IF;
|
|
ELSE
|
|
i_linecpt<=i_linecpt+1;
|
|
END IF;
|
|
|
|
-- Delay 4 lines
|
|
i_vss2<=i_vss;
|
|
IF i_vss/=i_vss2 THEN
|
|
i_delay<=0;
|
|
ELSIF i_delay=i_line * 4 THEN
|
|
i_vss_delay<=i_vss;
|
|
ELSE
|
|
i_delay<=i_delay+1;
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
END PROCESS Delay;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Sample image sizes
|
|
Sampler:PROCESS(clk,reset_na) IS
|
|
BEGIN
|
|
IF reset_na='0' THEN
|
|
--pragma synthesis_off
|
|
otog<='0';
|
|
itog<='0';
|
|
ivss<='0';
|
|
ivss2<='0';
|
|
ovss<='0';
|
|
ovss2<='0';
|
|
--pragma synthesis_on
|
|
|
|
ELSIF rising_edge(clk) THEN
|
|
-- Clock domain crossing
|
|
|
|
ivss<=i_vss_delay; -- <ASYNC>
|
|
ivss2<=ivss;
|
|
|
|
ovss<=lltune(4); -- <ASYNC>
|
|
ovss2<=ovss;
|
|
|
|
otog<=otog XOR (ovss AND NOT ovss2);
|
|
|
|
-- Measure output frame time
|
|
IF ovss='1' AND ovss2='0' AND otog='1' THEN
|
|
ocpt<=0;
|
|
osizep<=to_signed(ocpt,24);
|
|
ELSE
|
|
ocpt<=ocpt+1;
|
|
END IF;
|
|
IF ovss='0' AND ovss2='1' AND otog='0' THEN
|
|
o2cpt<=0;
|
|
ELSE
|
|
o2cpt<=o2cpt+1;
|
|
END IF;
|
|
|
|
-- Measure output image time
|
|
IF ovss='0' AND ovss2='1' AND otog='0' THEN
|
|
ofsize<=ocpt;
|
|
END IF;
|
|
|
|
itog<=itog XOR (ivss AND NOT ivss2);
|
|
|
|
-- Measure input frame time
|
|
IF ivss='1' AND ivss2='0' AND itog='1' THEN
|
|
icpt<=0;
|
|
osize<=osizep;
|
|
udiff<=integer(to_integer(osizep)) - integer(icpt);
|
|
sync<='1';
|
|
ELSE
|
|
icpt<=icpt+1;
|
|
sync<='0';
|
|
END IF;
|
|
|
|
-- Measure input image time
|
|
IF ivss='0' AND ivss2='1' AND itog='0' THEN
|
|
ifsize<=icpt;
|
|
END IF;
|
|
|
|
expand<=(ofsize>=ifsize);
|
|
-- IN | ######### | EXPAND = 1
|
|
-- OUT | ############# |
|
|
|
|
-- IN | ######### | EXPAND = 0
|
|
-- OUT | ###### |
|
|
|
|
IF expand THEN
|
|
IF ivss='1' AND ivss2='0' AND itog='1' THEN
|
|
offset<=to_signed(ocpt,24);
|
|
END IF;
|
|
ELSE
|
|
IF ivss='0' AND ivss2='1' AND itog='0' THEN
|
|
offset<=to_signed(o2cpt,24);
|
|
END IF;
|
|
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.
|
|
-- 000100 : M counter
|
|
-- 000111 : M counter Fractional Value K
|
|
|
|
Comb:PROCESS(i_write,i_address,
|
|
i_writedata,pwrite,paddress,pdata) IS
|
|
BEGIN
|
|
IF i_write='1' THEN
|
|
o_write <=i_write;
|
|
o_address <=i_address;
|
|
o_writedata <=i_writedata;
|
|
ELSE
|
|
o_write <=pwrite;
|
|
o_address <=paddress;
|
|
o_writedata<=pdata;
|
|
END IF;
|
|
END PROCESS Comb;
|
|
|
|
i_waitrequest<=o_waitrequest WHEN state=sIDLE ELSE '0';
|
|
|
|
----------------------------------------------------------------------------
|
|
Schmurtz:PROCESS(clk,reset_na) IS
|
|
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
|
|
------------------------------------------------------
|
|
-- 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;
|
|
|
|
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;
|
|
|
|
------------------------------------------------------
|
|
-- 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';
|
|
IF mulco/=mul THEN
|
|
state<=sW1;
|
|
ELSE
|
|
state<=sW3;
|
|
END IF;
|
|
END IF;
|
|
|
|
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<=sW3;
|
|
pwrite<='0';
|
|
END IF;
|
|
|
|
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<=sW6;
|
|
|
|
WHEN sW6 =>
|
|
IF pwrite='1' AND o_waitrequest='0' THEN
|
|
pwrite<='0';
|
|
state<=sIDLE;
|
|
END IF;
|
|
END CASE;
|
|
|
|
END IF;
|
|
END PROCESS Schmurtz;
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
END ARCHITECTURE rtl;
|
|
|