Update scaler, fix tearing.

This commit is contained in:
sorgelig
2018-12-31 07:06:21 +08:00
parent e14e47322e
commit a825c829aa
5 changed files with 333 additions and 55 deletions

View File

@@ -255,6 +255,8 @@ ARCHITECTURE rtl OF ascal IS
----------------------------------------------------------
-- Input image
SIGNAL i_phs,i_pvs,i_pfl,i_pde,i_pce : std_logic;
SIGNAL i_pr,i_pg,i_pb : unsigned(7 DOWNTO 0);
SIGNAL i_freeze : std_logic;
SIGNAL i_hsize,i_hmin,i_hmax,i_hcpt : uint12;
SIGNAL i_hrsize,i_vrsize : uint12;
@@ -948,7 +950,6 @@ BEGIN
ELSIF rising_edge(i_clk) THEN
i_push<='0';
i_pushhead<='0';
i_eol<='0'; -- End Of Line
i_freeze <=freeze; -- <ASYNC>
i_iauto<=iauto; -- <ASYNC> ?
@@ -959,7 +960,7 @@ BEGIN
i_head(111 DOWNTO 96)<=to_unsigned(N_BURST,16); -- Header size
i_head(95 DOWNTO 80)<=x"0000"; -- Attributes. TBD
i_head(80)<=i_inter;
i_head(81)<=i_fl;
i_head(81)<=i_pfl;
i_head(82)<=i_hdown;
i_head(83)<=i_vdown;
i_head(79 DOWNTO 64)<=to_unsigned(i_hrsize,16); -- Image width
@@ -967,32 +968,42 @@ BEGIN
i_head(47 DOWNTO 32)<=
to_unsigned(N_BURST * i_hburst,16); -- Line Length. Bytes
i_head(31 DOWNTO 0)<=x"0000_0000"; -- TBD
------------------------------------------------------
i_pr <=i_r;
i_pg <=i_g;
i_pb <=i_b;
i_phs<=i_hs;
i_pvs<=i_vs;
i_pfl<=i_fl;
i_pde<=i_de;
i_pce<=i_ce;
------------------------------------------------------
IF i_ce='1' THEN
IF i_pce='1' THEN
----------------------------------------------------
i_hs_pre<=i_hs;
i_vs_pre<=i_vs;
i_de_pre<=i_de;
i_fl_pre<=i_fl;
i_hs_pre<=i_phs;
i_vs_pre<=i_pvs;
i_de_pre<=i_pde;
i_fl_pre<=i_pfl;
----------------------------------------------------
-- Detect interlaced video
IF NOT INTER THEN
i_intercnt<=0;
ELSIF i_fl/=i_fl_pre THEN
ELSIF i_pfl/=i_fl_pre THEN
i_intercnt<=3;
ELSIF i_vs='1' AND i_vs_pre='0' AND i_intercnt>0 THEN
ELSIF i_pvs='1' AND i_vs_pre='0' AND i_intercnt>0 THEN
i_intercnt<=i_intercnt-1;
END IF;
i_inter<=to_std_logic(i_intercnt>0);
----------------------------------------------------
IF i_vs='1' AND i_vs_pre='0' THEN
IF i_pvs='1' AND i_vs_pre='0' THEN
i_sof<='1';
END IF;
IF i_de='1' AND i_sof='1' THEN
IF i_pde='1' AND i_sof='1' THEN
i_sof<='0';
i_vcpt<=0;
IF i_inter='1' AND i_flm='1' AND i_half='0' AND INTER THEN
@@ -1005,33 +1016,33 @@ BEGIN
END IF;
END IF;
IF i_de='1' THEN
i_flm<=NOT i_fl;
IF i_pde='1' THEN
i_flm<=NOT i_pfl;
END IF;
i_ven<=to_std_logic(i_hcpt>=i_hmin AND i_hcpt<=i_hmax+1 AND
i_vcpt>=i_vmin AND i_vcpt<=i_vmax AND i_de='1');
i_vcpt>=i_vmin AND i_vcpt<=i_vmax AND i_pde='1');
-- Detects end of frame for triple buffering.
-- Waits for second frame of interlaced video
i_endframe<=to_std_logic(i_vcpt=i_vmax + 1 AND
(i_inter='0' OR i_fl='1'));
(i_inter='0' OR i_pfl='1'));
-- Detects third line for low lag mode
i_syncline<=to_std_logic(i_vcpt=i_vmin + 3);
----------------------------------------------------
IF i_de='1' AND i_de_pre='0' THEN
IF i_pde='1' AND i_de_pre='0' THEN
i_vimaxc<=i_vcpt;
i_hcpt<=0;
ELSE
i_hcpt<=(i_hcpt+1) MOD 4096;
END IF;
IF i_de='0' AND i_de_pre='1' THEN
IF i_pde='0' AND i_de_pre='1' THEN
i_himax<=i_hcpt;
END IF;
IF i_vs='1' THEN
IF i_pvs='1' THEN
i_vimax<=i_vimaxc;
END IF;
@@ -1040,7 +1051,7 @@ BEGIN
i_hmin<=0;
i_hmax<=i_himax;
i_vmin<=0;
IF i_inter='0' OR i_fl='0' THEN
IF i_inter='0' OR i_pfl='0' THEN
i_vmax<=i_vimax;
END IF;
ELSE
@@ -1051,17 +1062,17 @@ BEGIN
i_vmax<=vimax; -- <ASYNC>
END IF;
--pragma synthesis_off
--pragma synthesis_off
----------------------------------------------------
-- TEST : Scan image properties
IF i_hs='1' AND i_hs_pre='0' AND i_vcpt=1 THEN i_hsstart<=i_hcpt+1; END IF;
IF i_hs='0' AND i_hs_pre='1' AND i_vcpt=1 THEN i_hsend<=i_hcpt+1; END IF;
IF i_de='1' AND i_de_pre='0' AND i_vcpt=1 THEN i_htotal<=i_hcpt+1; END IF;
IF i_phs='1' AND i_hs_pre='0' AND i_vcpt=1 THEN i_hsstart<=i_hcpt+1; END IF;
IF i_phs='0' AND i_hs_pre='1' AND i_vcpt=1 THEN i_hsend<=i_hcpt+1; END IF;
IF i_pde='1' AND i_de_pre='0' AND i_vcpt=1 THEN i_htotal<=i_hcpt+1; END IF;
IF i_vs='1' AND i_vs_pre='0' THEN i_vsstart<=i_vcpt; END IF;
IF i_vs='0' AND i_vs_pre='1' THEN i_vsend<=i_vcpt; END IF;
IF i_de='1' AND i_sof='1' THEN i_vtotal<=i_vcpt; END IF;
--pragma synthesis_on
IF i_pvs='1' AND i_vs_pre='0' THEN i_vsstart<=i_vcpt; END IF;
IF i_pvs='0' AND i_vs_pre='1' THEN i_vsend<=i_vcpt; END IF;
IF i_pde='1' AND i_sof='1' THEN i_vtotal<=i_vcpt; END IF;
--pragma synthesis_on
----------------------------------------------------
i_mode<=mode; -- <ASYNC>
@@ -1132,7 +1143,7 @@ BEGIN
----------------------------------------------------
-- Downscaling interpolation
i_hpixp<=(i_r,i_g,i_b);
i_hpixp<=(i_pr,i_pg,i_pb);
i_hpix0<=i_hpixp;
i_hpix1<=i_hpix0;
i_hpix2<=i_hpix1;
@@ -1237,7 +1248,7 @@ BEGIN
END IF;
-- Delay I_HS raising for a few cycles, finish ongoing mem. access
IF i_hs='1' AND i_hs_pre='0' THEN
IF i_phs='1' AND i_hs_pre='0' THEN
i_hs_delay<=0;
ELSIF i_hs_delay<15 THEN
i_hs_delay<=i_hs_delay+1;
@@ -1257,24 +1268,24 @@ BEGIN
END IF;
END IF;
IF i_vs='0' AND i_vs_pre='1' THEN
IF i_pvs='0' AND i_vs_pre='1' THEN
i_vacc<=i_ovsize/2 + i_vsize/2;
-- Push header
i_pushhead<=to_std_logic(HEADER);
i_hbfix<='0';
END IF;
END IF; -- IF i_ce='1'
END IF; -- IF i_pce='1'
------------------------------------------------------
-- Push pixels to downscaling line buffer
i_lwr<=i_hnp4 AND i_ven5 AND i_ce;
i_lwr<=i_hnp4 AND i_ven5 AND i_pce;
IF i_lwr='1' THEN
i_lwad<=(i_lwad+1) MOD OHRES;
END IF;
i_ldw<=i_hpix;
IF i_hnp3='1' AND i_ven4='1' AND i_ce='1' THEN
IF i_hnp3='1' AND i_ven4='1' AND i_pce='1' THEN
i_lrad<=(i_lrad+1) MOD OHRES;
END IF;
@@ -2206,7 +2217,7 @@ BEGIN
o_llicpt<=0;
o_llipos<=o_llocpt;
o_llisize<=o_llicpt;
o_llfl<=i_fl; -- <ASYNC>
o_llfl<=i_pfl; -- <ASYNC>
ELSE
o_llicpt<=o_llicpt+1;
END IF;
@@ -2224,7 +2235,7 @@ BEGIN
-- Period difference between input and output images
o_lldiff<=(integer(o_llosize) - integer(o_llisize));
o_lltune_i(14)<='0'; -- Unused
o_lltune_i(14)<='0'; -- Interleaved video field
o_lltune_i(7 DOWNTO 6)<=i_inter & o_llfl; -- <ASYNC>
IF o_llup='1' THEN
o_llcpt<=0;
@@ -2389,13 +2400,13 @@ BEGIN
o_b<=x"00";
END IF;
--pragma synthesis_off
--pragma synthesis_off
IF o_mode(2 DOWNTO 0)="111" AND o_vcpt<2*8 THEN
o_r<=(OTHERS => o_debug_set);
o_g<=(OTHERS => o_debug_set);
o_b<=(OTHERS => o_debug_set);
END IF;
--pragma synthesis_on
--pragma synthesis_on
----------------------------------------------------
END IF;
@@ -2403,7 +2414,7 @@ BEGIN
END PROCESS VSCAL;
--pragma synthesis_off
--pragma synthesis_off
-----------------------------------------------------------------------------
-- DEBUG
Debug:PROCESS(o_clk) IS
@@ -2507,8 +2518,8 @@ BEGIN
'0' & o_lltune_i(7 DOWNTO 4) & -- 1
'0' & o_lltune_i(3 DOWNTO 0) & -- 1
CS(" ");
----------------------------------------------------------------------------
--pragma synthesis_on
----------------------------------------------------------------------------
--pragma synthesis_on
END ARCHITECTURE rtl;

239
sys/pll_hdmi_adj.vhd Normal file
View File

@@ -0,0 +1,239 @@
--------------------------------------------------------------------------------
-- HDMI PLL Adjust
--------------------------------------------------------------------------------
-- 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)
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
-- 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 pwrite : std_logic;
SIGNAL paddress : unsigned(5 DOWNTO 0);
SIGNAL pdata : unsigned(31 DOWNTO 0);
TYPE enum_state IS (sIDLE,sW1,sW2,sW3);
SIGNAL state : enum_state;
SIGNAL lltune_sync,lltune_sync2,lltune_sync3 : unsigned(15 DOWNTO 0);
SIGNAL mfrac,mfrac_mem : unsigned(31 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;
BEGIN
----------------------------------------------------------------------------
-- 000010 : Start reg "Write either 0 or 1 to start fractional PLL reconf.
-- 000111 : M counter Fractional Value
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,ofp : natural RANGE 0 TO 63;
VARIABLE dif : unsigned(31 DOWNTO 0);
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;
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;
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;
------------------------------------------------------
CASE state IS
WHEN sIDLE =>
pwrite<='0';
IF up='1' THEN
up<='0';
state<=sW1;
pdata<=mfrac;
paddress<="000111";
pwrite<='1';
END IF;
WHEN sW1 =>
IF pwrite='1' AND o_waitrequest='0' THEN
state<=sW2;
pwrite<='0';
END IF;
WHEN sW2 =>
pdata<=x"0000_0001";
paddress<="000010";
pwrite<='1';
state<=sW3;
WHEN sW3 =>
IF pwrite='1' AND o_waitrequest='0' THEN
pwrite<='0';
state<=sIDLE;
END IF;
END CASE;
END IF;
END PROCESS Schmurtz;
----------------------------------------------------------------------------
END ARCHITECTURE rtl;

View File

@@ -4,6 +4,7 @@ set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) p
set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi.qip ]
set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi_cfg.qip ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ascal.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) pll_hdmi_adj.vhd ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hq2x.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scanlines.v ]

View File

@@ -8,6 +8,7 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) p
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_hdmi_cfg/altera_pll_reconfig_core.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_hdmi_cfg/altera_pll_reconfig_top.v ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ascal.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) pll_hdmi_adj.vhd ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hq2x.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scanlines.v ]

View File

@@ -216,6 +216,7 @@ reg coef_set = 0;
wire [7:0] ARX, ARY;
reg [11:0] VSET = 0;
reg [2:0] scaler_flt;
reg lowlat = 0;
always@(posedge clk_sys) begin
reg [7:0] cmd;
@@ -273,8 +274,9 @@ always@(posedge clk_sys) begin
if(cnt[1:0]==2) begin
cfg_custom_p2[31:16] <= io_din;
cfg_custom_t <= ~cfg_custom_t;
cnt[1:0] <= 0;
cnt[2:0] <= 3'b100;
end
if(cnt == 8) lowlat <= io_din[15];
end
end
if(cmd == 'h25) {led_overtake, led_state} <= io_din;
@@ -434,6 +436,12 @@ vip_config vip_config
.writedata(ctl_writedata),
.waitrequest(ctl_waitrequest)
);
assign cfg_write = adj_write;
assign cfg_address = adj_address;
assign cfg_data = adj_data;
assign adj_waitrequest = cfg_waitrequest;
`endif
@@ -561,7 +569,7 @@ ascal
.vmin (vmin),
.vmax (vmax),
.mode ({1'b1,scaler_flt,2'b00}),
.mode ({~lowlat,|scaler_flt,2'b00}),
.poly_clk (clk_sys),
.poly_a (coef_addr),
.poly_dw (coef_data),
@@ -610,6 +618,23 @@ always @(posedge clk_vid) begin
endcase
end
pll_hdmi_adj pll_hdmi_adj
(
.clk(FPGA_CLK1_50),
.reset_na(~reset_req),
.llena(lowlat),
.lltune(lltune),
.i_waitrequest(adj_waitrequest),
.i_write(adj_write),
.i_address(adj_address),
.i_writedata(adj_data),
.o_waitrequest(cfg_waitrequest),
.o_write(cfg_write),
.o_address(cfg_address),
.o_writedata(cfg_data)
);
`endif
@@ -636,10 +661,10 @@ reg [11:0] VBP = 36;
wire [63:0] reconfig_to_pll;
wire [63:0] reconfig_from_pll;
wire cfg_waitrequest;
reg cfg_write;
reg [5:0] cfg_address;
reg [31:0] cfg_data;
wire cfg_waitrequest,adj_waitrequest;
reg cfg_write,adj_write;
reg [5:0] cfg_address,adj_address;
reg [31:0] cfg_data,adj_data;
pll_hdmi_cfg pll_hdmi_cfg
(
@@ -665,24 +690,24 @@ always @(posedge FPGA_CLK1_50) begin
gotd <= cfg_got;
gotd2 <= gotd;
cfg_write <= 0;
adj_write <= 0;
custd <= cfg_custom_t;
custd2 <= custd;
if(custd2 != custd & ~gotd) begin
cfg_address <= cfg_custom_p1;
cfg_data <= cfg_custom_p2;
cfg_write <= 1;
adj_address <= cfg_custom_p1;
adj_data <= cfg_custom_p2;
adj_write <= 1;
end
if(~gotd2 & gotd) begin
cfg_address <= 2;
cfg_data <= 0;
cfg_write <= 1;
adj_address <= 2;
adj_data <= 0;
adj_write <= 1;
end
old_wait <= cfg_waitrequest;
if(old_wait & ~cfg_waitrequest & gotd) cfg_ready <= 1;
old_wait <= adj_waitrequest;
if(old_wait & ~adj_waitrequest & gotd) cfg_ready <= 1;
end
hdmi_config hdmi_config
@@ -884,6 +909,7 @@ wire [1:0] audio_mix;
wire [7:0] r_out, g_out, b_out;
wire vs, hs, de, f1;
wire [1:0] scanlines;
wire [15:0] lltune;
wire clk_sys, clk_vid, ce_pix;
wire ram_clk;