diff --git a/ossc.sdc b/ossc.sdc index 8cf81a8..95dcfc7 100644 --- a/ossc.sdc +++ b/ossc.sdc @@ -9,36 +9,24 @@ set_false_path -to {sys:sys_inst|sys_pio_1:pio_1|readdata*} ### Scanconverter clock constraints ### -create_clock -period 108MHz -name pclk_1x [get_ports TVP_PCLK_i] -create_clock -period 54MHz -name pclk_2x_source [get_ports TVP_PCLK_i] -add -create_clock -period 54MHz -name pclk_3x_source [get_ports TVP_PCLK_i] -add -create_clock -period 33MHz -name pclk_4x_source [get_ports TVP_PCLK_i] -add -create_clock -period 33MHz -name pclk_5x_source [get_ports TVP_PCLK_i] -add +create_clock -period 165MHz -name pclk_tvp_high [get_ports TVP_PCLK_i] +create_clock -period 33MHz -name pclk_tvp_low [get_ports TVP_PCLK_i] -add #derive_pll_clocks -create_generated_clock -name pclk_2x -master_clock pclk_2x_source -source {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|inclk[1]} -multiply_by 2 -duty_cycle 50.00 {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|clk[0]} -add -create_generated_clock -name pclk_3x -master_clock pclk_3x_source -source {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|inclk[1]} -multiply_by 3 -duty_cycle 50.00 {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|clk[0]} -add -create_generated_clock -name pclk_4x -master_clock pclk_4x_source -source {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|inclk[1]} -multiply_by 4 -duty_cycle 50.00 {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|clk[1]} -add -create_generated_clock -name pclk_5x -master_clock pclk_5x_source -source {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|inclk[1]} -multiply_by 5 -duty_cycle 50.00 {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|clk[1]} -add -create_generated_clock -name pclk_27mhz -master_clock clk27 -source {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|inclk[0]} -multiply_by 1 -duty_cycle 50.00 {scanconverter_inst|pll_pclk|altpll_component|auto_generated|pll1|clk[0]} -add +create_generated_clock -name pclk_5x -master_clock pclk_tvp_low -source {pll_pclk|altpll_component|auto_generated|pll1|inclk[1]} -multiply_by 5 -duty_cycle 50.00 {pll_pclk|altpll_component|auto_generated|pll1|clk[0]} +create_generated_clock -name pclk_27mhz -master_clock clk27 -source {pll_pclk|altpll_component|auto_generated|pll1|inclk[0]} -multiply_by 1 -duty_cycle 50.00 {pll_pclk|altpll_component|auto_generated|pll1|clk[0]} -add # retrieve post-mapping clkmux output pin -set clkmux_output [get_pins scanconverter_inst|clkctrl1|outclk] +set clkmux_output [get_pins clkctrl1|outclk] # specify postmux clocks which clock postprocess pipeline -create_generated_clock -name pclk_1x_postmux -master_clock pclk_1x -source [get_pins scanconverter_inst|clkctrl1|inclk[0]] -multiply_by 1 $clkmux_output -create_generated_clock -name pclk_2x_postmux -master_clock pclk_2x -source [get_pins scanconverter_inst|clkctrl1|inclk[2]] -multiply_by 1 $clkmux_output -add -create_generated_clock -name pclk_3x_postmux -master_clock pclk_3x -source [get_pins scanconverter_inst|clkctrl1|inclk[2]] -multiply_by 1 $clkmux_output -add -create_generated_clock -name pclk_4x_postmux -master_clock pclk_4x -source [get_pins scanconverter_inst|clkctrl1|inclk[3]] -multiply_by 1 $clkmux_output -add -create_generated_clock -name pclk_5x_postmux -master_clock pclk_5x -source [get_pins scanconverter_inst|clkctrl1|inclk[3]] -multiply_by 1 $clkmux_output -add -create_generated_clock -name pclk_27mhz_postmux -master_clock pclk_27mhz -source [get_pins scanconverter_inst|clkctrl1|inclk[2]] -multiply_by 1 $clkmux_output -add +create_generated_clock -name pclk_1x_postmux -master_clock pclk_tvp_high -source [get_pins clkctrl1|inclk[0]] -multiply_by 1 $clkmux_output +create_generated_clock -name pclk_5x_postmux -master_clock pclk_5x -source [get_pins clkctrl1|inclk[2]] -multiply_by 1 $clkmux_output -add +create_generated_clock -name pclk_27mhz_postmux -master_clock pclk_27mhz -source [get_pins clkctrl1|inclk[2]] -multiply_by 1 $clkmux_output -add # specify output clocks that drive PCLK output pin set pclk_out_port [get_ports HDMI_TX_PCLK] create_generated_clock -name pclk_1x_out -master_clock pclk_1x_postmux -source $clkmux_output -multiply_by 1 $pclk_out_port -create_generated_clock -name pclk_2x_out -master_clock pclk_2x_postmux -source $clkmux_output -multiply_by 1 $pclk_out_port -add -create_generated_clock -name pclk_3x_out -master_clock pclk_3x_postmux -source $clkmux_output -multiply_by 1 $pclk_out_port -add -create_generated_clock -name pclk_4x_out -master_clock pclk_4x_postmux -source $clkmux_output -multiply_by 1 $pclk_out_port -add create_generated_clock -name pclk_5x_out -master_clock pclk_5x_postmux -source $clkmux_output -multiply_by 1 $pclk_out_port -add create_generated_clock -name pclk_27mhz_out -master_clock pclk_27mhz_postmux -source $clkmux_output -multiply_by 1 $pclk_out_port -add @@ -48,7 +36,7 @@ derive_clock_uncertainty set TVP_dmin 0 set TVP_dmax 1.5 set critinputs [get_ports {TVP_R_i* TVP_G_i* TVP_B_i* TVP_HS_i TVP_HSYNC_i TVP_VSYNC_i TVP_FID_i}] -foreach_in_collection c [get_clocks "pclk_1x pclk_*_source"] { +foreach_in_collection c [get_clocks "pclk_tvp*"] { set_input_delay -clock $c -min $TVP_dmin $critinputs -add_delay set_input_delay -clock $c -max $TVP_dmax $critinputs -add_delay } @@ -69,25 +57,12 @@ set_false_path -to [remove_from_collection [all_outputs] $critoutputs_hdmi] # Treat CPU clock asynchronous to pixel clocks set_clock_groups -asynchronous -group \ - {clk27 pclk_27mhz pclk_27mhz_postmux pclk_27mhz_out} \ - {pclk_1x pclk_1x_postmux pclk_1x_out} \ - {pclk_2x_source pclk_2x pclk_2x_postmux pclk_2x_out} \ - {pclk_3x_source pclk_3x pclk_3x_postmux pclk_3x_out} \ - {pclk_4x_source pclk_4x pclk_4x_postmux pclk_4x_out} \ - {pclk_5x_source pclk_5x pclk_5x_postmux pclk_5x_out} - -# Ignore paths from registers which are updated only at leading edge of vsync -set_false_path -from [get_registers {scanconverter_inst|H_* scanconverter_inst|V_* scanconverter_inst|X_* scanconverter_inst|SL_* scanconverter_inst|LT_POS_*}] - -# Ignore paths from registers which are updated only at leading edge of hsync -#set_false_path -from [get_registers {scanconverter:scanconverter_inst|line_idx scanconverter:scanconverter_inst|line_out_idx* scanconverter:scanconverter_inst|hmax*}] - -# Ignore paths that cross clock domains from 3x to 2x and 5x to 4x, since they share a clock line, but cannot co-occur. -set_false_path -from [get_clocks {pclk_3x*}] -to [get_registers {scanconverter:scanconverter_inst|*_2x*}] -set_false_path -from [get_clocks {pclk_5x*}] -to [get_registers {scanconverter:scanconverter_inst|*_4x*}] - -# Ignore paths to latency tester sync regs -set_false_path -to [get_registers {lat_tester:lt0|mode_synced* lat_tester:lt0|VSYNC_in_* lat_tester:lt0|trigger_*}] + {clk27} \ + {pclk_27mhz pclk_27mhz_postmux pclk_27mhz_out} \ + {pclk_tvp_low} \ + {pclk_tvp_high} \ + {pclk_1x_postmux pclk_1x_out} \ + {pclk_5x pclk_5x_postmux pclk_5x_out} ### JTAG Signal Constraints ### diff --git a/rtl/linebuf_top.v b/rtl/linebuf_top.v new file mode 100644 index 0000000..0c2ff81 --- /dev/null +++ b/rtl/linebuf_top.v @@ -0,0 +1,279 @@ +// +// Copyright (C) 2022 Markus Hiienkari +// +// This file is part of Open Source Scan Converter project. +// +// 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 3 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, see . +// + +//`define DEBUG + +module linebuf_top ( + input PCLK_CAP_i, + input PCLK_OUT_i, + input [7:0] R_i, + input [7:0] G_i, + input [7:0] B_i, + input DE_i, + input datavalid_i, + input [11:0] h_in_active, + input [10:0] xpos_i, + input [10:0] ypos_i, + input [10:0] xpos_lb, + input [10:0] ypos_lb, + input [10:0] ypos_lb_next, + input line_id, + input lb_enable, + output [7:0] R_linebuf, + output [7:0] G_linebuf, + output [7:0] B_linebuf, + // optional EMIF if + input emif_br_clk, + input emif_br_reset, + output reg [27:0] emif_rd_addr, + output reg emif_rd_read, + input [255:0] emif_rd_rdata, + input emif_rd_waitrequest, + input emif_rd_readdatavalid, + output reg [5:0] emif_rd_burstcount, + output [27:0] emif_wr_addr, + output reg emif_wr_write, + output [255:0] emif_wr_wdata, + input emif_wr_waitrequest, + output reg [5:0] emif_wr_burstcount +); + +parameter EMIF_ENABLE = 0; +parameter NUM_LINE_BUFFERS = 32; + + +localparam EMIF_WR_MAXBURST = 32; +localparam EMIF_RD_MAXBURST = 32; + +generate +if (EMIF_ENABLE) begin + +`ifdef DEBUG +reg [10:0] emif_wr_stall_ctr /* synthesis noprune */; +reg [10:0] emif_rd_stall_ctr /* synthesis noprune */; +reg emif_rd_line_missed /* synthesis noprune */; + +always @(posedge emif_br_clk) begin + if (emif_wr_write & emif_wr_waitrequest & (emif_wr_stall_ctr != 2047)) + emif_wr_stall_ctr <= emif_wr_stall_ctr + 1'b1; + else + emif_wr_stall_ctr <= 0; + + if (emif_rd_burstcount > 0) begin + if (emif_rd_readdatavalid) + emif_rd_stall_ctr <= 0; + else + emif_rd_stall_ctr <= emif_rd_stall_ctr + 1'b1; + end +end +`endif + +// Number of 8-pixel blocks per line +wire [8:0] blocks_per_line = (h_in_active / 8) + (h_in_active[2:0] != 3'h0); + +/* ------------------------------ EMIF WR interface ------------------------------ */ + +// PCLK_CAP_i related signals +reg [8:0] emif_wr_fifo_blksleft; +reg [19:0] emif_wr_fifo_addr; // [19:9] = y_pos; [8:0] = x_pos_x8 +reg [23:0] emif_wr_fifo_pixs[7:0] /* synthesis ramstyle = "logic" */; +reg emif_wr_fifo_wrreq; +reg [8:0] blocks_inserted; +reg DE_prev; +wire emif_wr_fifo_wrfull; + +// emif_br_clk related signals +wire [8:0] emif_wr_fifo_blksleft_q; +reg [8:0] emif_wr_blksleft; +wire [19:0] emif_wr_fifo_addr_q; +wire [23:0] emif_wr_fifo_pixs_q[7:0]; +reg emif_wr_fifo_iniread_prev; +wire emif_wr_fifo_rdempty; +wire [8:0] emif_wr_fifo_rdusedw; +wire emif_wr_fifo_iniread = (lb_enable & (emif_wr_blksleft == 0) & !emif_wr_fifo_iniread_prev & !emif_wr_fifo_rdempty); +wire emif_wr_fifo_rdreq = emif_wr_fifo_iniread | ((emif_wr_burstcount > 1) & !emif_wr_waitrequest); + +assign emif_wr_addr = {3'b001, emif_wr_fifo_addr_q, 5'h0}; +assign emif_wr_wdata = {8'h0, emif_wr_fifo_pixs_q[0], 8'h0, emif_wr_fifo_pixs_q[1], 8'h0, emif_wr_fifo_pixs_q[2], 8'h0, emif_wr_fifo_pixs_q[3], + 8'h0, emif_wr_fifo_pixs_q[4], 8'h0, emif_wr_fifo_pixs_q[5], 8'h0, emif_wr_fifo_pixs_q[6], 8'h0, emif_wr_fifo_pixs_q[7]}; + +dc_fifo_emif_wr dc_fifo_emif_wr_inst ( + .data({emif_wr_fifo_blksleft, emif_wr_fifo_addr, + emif_wr_fifo_pixs[0], emif_wr_fifo_pixs[1], emif_wr_fifo_pixs[2], emif_wr_fifo_pixs[3], + emif_wr_fifo_pixs[4], emif_wr_fifo_pixs[5], emif_wr_fifo_pixs[6], emif_wr_fifo_pixs[7]}), + .rdclk(emif_br_clk), + .rdreq(emif_wr_fifo_rdreq), + .rdempty(emif_wr_fifo_rdempty), + .rdusedw(emif_wr_fifo_rdusedw), + .wrclk(PCLK_CAP_i), + .wrreq(emif_wr_fifo_wrreq), + .wrfull(emif_wr_fifo_wrfull), + .q({emif_wr_fifo_blksleft_q, emif_wr_fifo_addr_q, + emif_wr_fifo_pixs_q[0], emif_wr_fifo_pixs_q[1], emif_wr_fifo_pixs_q[2], emif_wr_fifo_pixs_q[3], + emif_wr_fifo_pixs_q[4], emif_wr_fifo_pixs_q[5], emif_wr_fifo_pixs_q[6], emif_wr_fifo_pixs_q[7]}) +); + +always @(posedge PCLK_CAP_i) begin + emif_wr_fifo_wrreq <= 1'b0; + + if (datavalid_i) begin + emif_wr_fifo_pixs[xpos_i[2:0]] <= {R_i, G_i, B_i}; + DE_prev <= DE_i; + + if (~DE_prev & DE_i) + blocks_inserted <= 0; + + if ((blocks_inserted < blocks_per_line) & ~emif_wr_fifo_wrfull & (xpos_i[2:0] == 3'h7)) begin + emif_wr_fifo_blksleft <= blocks_per_line - blocks_inserted; + emif_wr_fifo_addr[19:9] <= ypos_i; + emif_wr_fifo_addr[7:0] <= xpos_i[10:3]; + emif_wr_fifo_wrreq <= 1'b1; + blocks_inserted <= blocks_inserted + 1'b1; + end + end +end + +always @(posedge emif_br_clk or posedge emif_br_reset) begin + if (emif_br_reset) begin + emif_wr_write <= 1'b0; + emif_wr_burstcount <= 1'b0; + end else begin + if (emif_wr_burstcount > 0) begin + if (!emif_wr_waitrequest) begin + emif_wr_burstcount <= emif_wr_burstcount - 1'b1; + if (emif_wr_burstcount == 1) begin + emif_wr_blksleft <= 0; + emif_wr_write <= 1'b0; + end + end + end else if (lb_enable & (emif_wr_blksleft > 0) & ((emif_wr_fifo_rdusedw >= emif_wr_blksleft-1) | (emif_wr_fifo_rdusedw >= 31))) begin + emif_wr_write <= 1'b1; + emif_wr_burstcount <= (emif_wr_blksleft > EMIF_WR_MAXBURST) ? EMIF_WR_MAXBURST : emif_wr_blksleft; + end else if (emif_wr_fifo_iniread_prev) begin + emif_wr_blksleft <= emif_wr_fifo_blksleft_q; + end + + emif_wr_fifo_iniread_prev <= emif_wr_fifo_iniread; + end +end + +/* ------------------------------ EMIF RD interface ------------------------------ */ + +// PCLK_OUT_i related signals +wire [12:0] linebuf_rdaddr = {xpos_lb + (line_id ? 2560 : 0)}; + +// emif_br_clk related signals +reg [8:0] blocks_copied; +wire linebuf_wren = emif_rd_readdatavalid; +wire [191:0] linebuf_wrdata = {emif_rd_rdata[23:0], emif_rd_rdata[55:32], emif_rd_rdata[87:64], emif_rd_rdata[119:96], + emif_rd_rdata[151:128], emif_rd_rdata[183:160], emif_rd_rdata[215:192], emif_rd_rdata[247:224]}; +wire [9:0] linebuf_wraddr = {blocks_copied + (line_id ? 0 : 320)}; +wire [19:0] emif_rd_block_addr = {ypos_lb_next, blocks_copied}; +reg line_id_brclk_sync1_reg, line_id_brclk_sync2_reg, line_id_brclk_sync3_reg; + + +linebuf_double linebuf_rgb ( + .data(linebuf_wrdata), + .rdaddress(linebuf_rdaddr), + .rdclock(PCLK_OUT_i), + .rdclocken(lb_enable), + .wraddress(linebuf_wraddr), + .wrclock(emif_br_clk), + .wren(linebuf_wren), + .wrclocken(lb_enable), + .q({R_linebuf, G_linebuf, B_linebuf}) +); + +// BRAM linebuffer operation +always @(posedge emif_br_clk or posedge emif_br_reset) begin + if (emif_br_reset) begin + emif_rd_read <= 1'b0; + emif_rd_burstcount <= 1'b0; + end else begin + if (emif_rd_burstcount > 0) begin // always finish read first, make sure doesn't last longer than line length + if (emif_rd_readdatavalid) begin + blocks_copied <= blocks_copied + 1'b1; + emif_rd_burstcount <= emif_rd_burstcount - 1'b1; + end + if (!emif_rd_waitrequest) + emif_rd_read <= 1'b0; +`ifdef DEBUG + emif_rd_line_missed <= (line_id_brclk_sync2_reg != line_id_brclk_sync3_reg); +`endif + end else if (line_id_brclk_sync2_reg != line_id_brclk_sync3_reg) begin + blocks_copied <= 0; + end else if (lb_enable & (blocks_copied < blocks_per_line)) begin + emif_rd_read <= 1'b1; + emif_rd_burstcount <= ((blocks_per_line-blocks_copied) > EMIF_RD_MAXBURST) ? EMIF_RD_MAXBURST : (blocks_per_line-blocks_copied); + emif_rd_addr <= {3'b001, emif_rd_block_addr, 5'h0}; + end + + line_id_brclk_sync1_reg <= line_id; + line_id_brclk_sync2_reg <= line_id_brclk_sync1_reg; + line_id_brclk_sync3_reg <= line_id_brclk_sync2_reg; + end +end + +end else begin // EMIF_ENABLE + +/* ------------------------------ BRAM lb interface ------------------------------ */ + +reg [5:0] ypos_wraddr; +reg [10:0] ypos_prev; +reg [10:0] xpos_wraddr; +reg [23:0] linebuf_wrdata; +reg linebuf_wren; + +wire [16:0] linebuf_wraddr = {ypos_wraddr[($clog2(NUM_LINE_BUFFERS)-1):0], xpos_wraddr}; +wire [16:0] linebuf_rdaddr = {ypos_lb[($clog2(NUM_LINE_BUFFERS)-1):0], xpos_lb[10:0]}; + + +linebuf linebuf_rgb ( + .data(linebuf_wrdata), + .rdaddress(linebuf_rdaddr), + .rdclock(PCLK_OUT_i), + .rdclocken(lb_enable), + .wraddress(linebuf_wraddr), + .wrclock(PCLK_CAP_i), + .wren(linebuf_wren), + .wrclocken(lb_enable), + .q({R_linebuf, G_linebuf, B_linebuf}) +); + +// Linebuffer write address calculation +always @(posedge PCLK_CAP_i) begin + if (ypos_i == 0) begin + ypos_wraddr <= 0; + end else if (ypos_i != ypos_prev) begin + if (ypos_wraddr == NUM_LINE_BUFFERS-1) + ypos_wraddr <= 0; + else + ypos_wraddr <= ypos_wraddr + 1'b1; + end + + xpos_wraddr <= xpos_i; + ypos_prev <= ypos_i; + linebuf_wrdata <= {R_i, G_i, B_i}; + linebuf_wren <= DE_i & datavalid_i; +end + +end +endgenerate + +endmodule \ No newline at end of file diff --git a/rtl/ossc.v b/rtl/ossc.v index 29e1532..9df024c 100644 --- a/rtl/ossc.v +++ b/rtl/ossc.v @@ -64,30 +64,34 @@ module ossc ( wire [31:0] sys_ctrl; -wire tvp_hsync_pol = sys_ctrl[16]; -wire tvp_vsync_pol = sys_ctrl[17]; -wire tvp_vsync_type = sys_ctrl[18]; +wire lt_active = sys_ctrl[15]; +wire lt_armed = sys_ctrl[14]; +wire [1:0] lt_mode = sys_ctrl[13:12]; +wire tvp_vsync_type = sys_ctrl[10]; +wire pll_bypass = sys_ctrl[9]; +wire remote_event = sys_ctrl[8]; +assign SD_DAT[3] = sys_ctrl[7]; //SD_SPI_SS_N +assign LCD_CS_N = sys_ctrl[6]; +assign LCD_RS = sys_ctrl[5]; +wire lcd_bl_on = sys_ctrl[4]; //hw_reset_n in v1.2 PCB +wire [1:0] lcd_bl_time = sys_ctrl[3:2]; +wire enable_sc = sys_ctrl[1]; +assign hw_reset_n = sys_ctrl[0]; //HDMI_TX_RST_N in v1.2 PCB -wire h_unstable, pll_lock_lost; -wire [31:0] hv_in_config, hv_in_config2, hv_in_config3, misc_config, sl_config, sl_config2; -wire [10:0] vmax, vmax_tvp; -wire [1:0] fpga_vsyncgen; -wire ilace_flag, vsync_flag; -wire [19:0] pcnt_frame; +wire [31:0] hv_in_config, hv_in_config2, hv_in_config3, hv_out_config, hv_out_config2, hv_out_config3, xy_out_config, xy_out_config2; +wire [31:0] misc_config, sl_config, sl_config2, sl_config3; + +wire pll_clkout, pll_clkswitch, pll_locked; +wire clkmux_clkout; wire [15:0] ir_code; wire [7:0] ir_code_cnt; -wire [7:0] R_out_sc, G_out_sc, B_out_sc; -wire HSYNC_out_sc; -wire VSYNC_out_sc; -wire PCLK_out; -wire DE_out_sc; - -wire [7:0] R_out_vg, G_out_vg, B_out_vg; -wire HSYNC_out_vg; -wire VSYNC_out_vg; -wire DE_out_vg; +wire [7:0] R_sc, G_sc, B_sc; +wire HSYNC_sc, VSYNC_sc, DE_sc; +wire pll_areset, pll_scanclk, pll_scanclkena, pll_configupdate, pll_scandata, pll_scandone, pll_activeclock; +wire PCLK_sc; +wire pclk_out = PCLK_sc; reg [7:0] po_reset_ctr = 0; @@ -103,19 +107,23 @@ reg TVP_VSYNC_sync1_reg, TVP_VSYNC_sync2_reg; reg [1:0] btn_L, btn_LL; reg ir_rx_L, ir_rx_LL, HDMI_TX_INT_N_L, HDMI_TX_INT_N_LL, HDMI_TX_MODE_L, HDMI_TX_MODE_LL; +reg vsync_flag_sync1_reg, vsync_flag_sync2_reg; + +reg [23:0] resync_led_ctr, warn_pll_lock_lost; +reg resync_strobe_sync1_reg, resync_strobe_sync2_reg, resync_strobe_prev; +wire resync_strobe_i; +wire resync_strobe = resync_strobe_sync2_reg; + +wire [31:0] controls = {ir_code_cnt, 3'b000, vsync_flag_sync2_reg, pll_activeclock, HDMI_TX_MODE_LL, btn_LL, ir_code}; wire lt_sensor = btn_LL[1]; -wire lt_active = sys_ctrl[15]; -wire lt_armed = sys_ctrl[14]; -wire lt_trigger = HDMI_TX_DE & HDMI_TX_GD[0]; -wire [1:0] lt_mode = sys_ctrl[13:12]; +wire lt_trigger = DE_sc & G_sc[0]; wire [1:0] lt_mode_synced; wire [15:0] lt_lat_result; wire [11:0] lt_stb_result; wire lt_trig_waiting; wire lt_finished; -wire remote_event = sys_ctrl[8]; reg remove_event_prev; reg [14:0] to_ctr, to_ctr_ms; wire lcd_bl_timeout; @@ -123,10 +131,20 @@ wire lcd_bl_timeout; wire [1:0] osd_color; wire osd_enable_pre; wire osd_enable = osd_enable_pre & ~lt_active; -wire [10:0] xpos, xpos_sc, xpos_vg; -wire [10:0] ypos, ypos_sc, ypos_vg; +wire [10:0] xpos_sc; +wire [10:0] ypos_sc; -wire pll_areset, pll_scanclk, pll_scanclkena, pll_configupdate, pll_scandata, pll_scandone, pll_activeclock; +`ifdef DEBUG +assign LED_R = TVP_HSYNC_i; +assign LED_G = TVP_VSYNC_i; +`else +wire resync_indicator = (warn_pll_lock_lost != 0) | (resync_led_ctr != 0); +//assign LED_R = lt_active ? lt_trig_waiting : resync_indicator; +assign LED_G = lt_active ? ~lt_sensor : (ir_code == 0) & ~resync_indicator; +`endif + +assign LCD_BL = lcd_bl_on ? (~lcd_bl_timeout | lt_active) : 1'b0; +assign HDMI_TX_PCLK = pclk_out; // TVP7002 RGB digitizer @@ -152,7 +170,7 @@ end wire [7:0] TVP_R_post, TVP_G_post, TVP_B_post; wire TVP_HSYNC_post, TVP_VSYNC_post, TVP_DE_post, TVP_FID_post, TVP_datavalid_post; -wire TVP_fe_interlace, TVP_fe_frame_change, TVP_sof_scaler; +wire TVP_fe_interlace, TVP_fe_frame_change, TVP_sof_scaler, TVP_sync_active; wire [19:0] TVP_fe_pcnt_frame; wire [10:0] TVP_fe_vtotal, TVP_fe_xpos, TVP_fe_ypos; tvp7002_frontend u_tvp_frontend ( @@ -168,8 +186,6 @@ tvp7002_frontend u_tvp_frontend ( .VSYNC_i(TVP_VSYNC_sync2_reg), .DE_i(1'b0), .FID_i(1'b0), - .hsync_i_polarity(tvp_hsync_pol), - .vsync_i_polarity(tvp_vsync_pol), .vsync_i_type(tvp_vsync_type), .hv_in_config(hv_in_config), .hv_in_config2(hv_in_config2), @@ -188,30 +204,23 @@ tvp7002_frontend u_tvp_frontend ( .vtotal(TVP_fe_vtotal), .frame_change(TVP_fe_frame_change), .sof_scaler(TVP_sof_scaler), - .pcnt_frame(TVP_fe_pcnt_frame) + .pcnt_frame(TVP_fe_pcnt_frame), + .sync_active(TVP_sync_active) ); // Insert synchronizers to async inputs (synchronize to CPU clock) always @(posedge clk27 or negedge po_reset_n) begin if (!po_reset_n) begin - btn_L <= 2'b00; - btn_LL <= 2'b00; - ir_rx_L <= 1'b0; - ir_rx_LL <= 1'b0; - HDMI_TX_INT_N_L <= 1'b0; - HDMI_TX_INT_N_LL <= 1'b0; - HDMI_TX_MODE_L <= 1'b0; - HDMI_TX_MODE_LL <= 1'b0; + {btn_L, btn_LL} <= '0; + {ir_rx_L, ir_rx_LL} <= '0; + {HDMI_TX_INT_N_L, HDMI_TX_INT_N_LL} <= '0; + {HDMI_TX_MODE_L, HDMI_TX_MODE_LL} <= '0; end else begin - btn_L <= btn; - btn_LL <= btn_L; - ir_rx_L <= ir_rx; - ir_rx_LL <= ir_rx_L; - HDMI_TX_INT_N_L <= HDMI_TX_INT_N; - HDMI_TX_INT_N_LL <= HDMI_TX_INT_N_L; - HDMI_TX_MODE_L <= HDMI_TX_MODE; - HDMI_TX_MODE_LL <= HDMI_TX_MODE_L; + {btn_L, btn_LL} <= {btn, btn_L}; + {ir_rx_L, ir_rx_LL} <= {ir_rx, ir_rx_L}; + {HDMI_TX_INT_N_L, HDMI_TX_INT_N_LL} <= {HDMI_TX_INT_N, HDMI_TX_INT_N_L}; + {HDMI_TX_MODE_L, HDMI_TX_MODE_LL} <= {HDMI_TX_MODE, HDMI_TX_MODE_L}; end end @@ -224,49 +233,9 @@ begin po_reset_ctr <= po_reset_ctr + 1'b1; end -assign hw_reset_n = sys_ctrl[0]; //HDMI_TX_RST_N in v1.2 PCB - - -`ifdef DEBUG -assign LED_R = HSYNC_in_L; -assign LED_G = VSYNC_in_L; -`else -//assign LED_R = lt_active ? lt_trig_waiting : (pll_lock_lost|h_unstable); -assign LED_G = lt_active ? ~lt_sensor : (ir_code == 0) & ~(pll_lock_lost|h_unstable); -`endif - -assign SD_DAT[3] = sys_ctrl[7]; //SD_SPI_SS_N -assign LCD_CS_N = sys_ctrl[6]; -assign LCD_RS = sys_ctrl[5]; -wire lcd_bl_on = sys_ctrl[4]; //hw_reset_n in v1.2 PCB -wire [1:0] lcd_bl_time = sys_ctrl[3:2]; -assign LCD_BL = lcd_bl_on ? (~lcd_bl_timeout | lt_active) : 1'b0; - -wire enable_sc = sys_ctrl[1]; -assign xpos = enable_sc ? xpos_sc : xpos_vg; -assign ypos = enable_sc ? ypos_sc : ypos_vg; -assign HDMI_TX_PCLK = PCLK_out; - -always @(posedge PCLK_out) begin - if (osd_enable) begin - if (osd_color == 2'h0) begin - {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'h000000; - end else if (osd_color == 2'h1) begin - {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'h0000ff; - end else if (osd_color == 2'h2) begin - {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'hffff00; - end else begin - {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'hffffff; - end - end else if (enable_sc) begin - {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= {R_out_sc, G_out_sc, B_out_sc}; - end else begin - {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= {R_out_vg, G_out_vg, B_out_vg}; - end - - HDMI_TX_HS <= enable_sc ? HSYNC_out_sc : HSYNC_out_vg; - HDMI_TX_VS <= enable_sc ? VSYNC_out_sc : VSYNC_out_vg; - HDMI_TX_DE <= enable_sc ? DE_out_sc : DE_out_vg; +// Sync vsync flag to CPU clock +always @(posedge clk27) begin + {vsync_flag_sync1_reg, vsync_flag_sync2_reg} <= {~VSYNC_sc, vsync_flag_sync1_reg}; end // LCD backlight timeout counters @@ -295,6 +264,93 @@ begin remove_event_prev <= remote_event; end +// Generate a warning signal from sync lock loss +always @(posedge clk27) begin + if (enable_sc) begin + if (~resync_strobe_prev & resync_strobe) begin + resync_led_ctr <= {24{1'b1}}; + end else if (resync_led_ctr > 0) begin + resync_led_ctr <= resync_led_ctr - 1'b1; + end + end + + resync_strobe_sync1_reg <= resync_strobe_i; + resync_strobe_sync2_reg <= resync_strobe_sync1_reg; + resync_strobe_prev <= resync_strobe_sync2_reg; +end + +// Generate a warning signal from PLL lock loss +always @(posedge clk27 or negedge sys_reset_n) +begin + if (!sys_reset_n) begin + warn_pll_lock_lost <= 1'b0; + end else begin + if (~pll_areset & ~pll_locked) + warn_pll_lock_lost <= 1; + else if (warn_pll_lock_lost != 0) + warn_pll_lock_lost <= warn_pll_lock_lost + 1'b1; + end +end + +// Control PLL reference clock switchover +always @(posedge clk27) +begin + pll_clkswitch <= (pll_activeclock != enable_sc); +end + +// Output registers +always @(posedge pclk_out) begin + if (osd_enable) begin + if (osd_color == 2'h0) begin + {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'h000000; + end else if (osd_color == 2'h1) begin + {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'h0000ff; + end else if (osd_color == 2'h2) begin + {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'hffff00; + end else begin + {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= 24'hffffff; + end + end else begin + {HDMI_TX_RD, HDMI_TX_GD, HDMI_TX_BD} <= {R_sc, G_sc, B_sc}; + end + + HDMI_TX_HS <= HSYNC_sc; + HDMI_TX_VS <= VSYNC_sc; + HDMI_TX_DE <= DE_sc; +end + + +pll_2x pll_pclk ( + .areset(pll_areset), + .clkswitch(pll_clkswitch), + .configupdate(pll_configupdate), + .inclk0(clk27), // set videogen clock to primary (power-on default) since both reference clocks must be running during switchover + .inclk1(TVP_PCLK_i), // is the secondary input clock fully compensated? + .scanclk(pll_scanclk), + .scanclkena(pll_scanclkena), + .scandata(pll_scandata), + .activeclock(pll_activeclock), + .c0(pll_clkout), + .locked(pll_locked), + .scandataout(), + .scandone(pll_scandone) +); + +cycloneive_clkctrl clkctrl1 ( + .clkselect(pll_bypass ? 2'h0 : 2'h2), + .ena(1'b1), + .inclk({1'b0, pll_clkout, 1'b0, TVP_PCLK_i}), // fitter forbids using both clk27 and pclk_1x here since they're on opposite sides + .outclk(clkmux_clkout) +// synopsys translate_off + , + .devclrn(1'b1), + .devpor(1'b1) +// synopsys translate_on +); +defparam + clkctrl1.clock_type = "Global Clock", + clkctrl1.ena_register_mode = "falling edge", + clkctrl1.lpm_type = "cycloneive_clkctrl"; sys sys_inst( .clk_clk (clk27), @@ -311,19 +367,25 @@ sys sys_inst( .i2c_opencores_1_export_sda_pad_io (SD_CMD), .i2c_opencores_1_export_spi_miso_pad_i (SD_DAT[0]), .pio_0_sys_ctrl_out_export (sys_ctrl), - .pio_1_controls_in_export ({ir_code_cnt, 4'b0000, pll_activeclock, HDMI_TX_MODE_LL, btn_LL, ir_code}), - .sc_config_0_sc_if_sc_status_i ({vsync_flag, 2'b00, vmax_tvp, fpga_vsyncgen, 4'h0, TVP_fe_interlace, TVP_fe_vtotal}), - .sc_config_0_sc_if_sc_status2_i ({12'h000, TVP_fe_pcnt_frame}), - .sc_config_0_sc_if_lt_status_i ({lt_finished, 3'h0, lt_stb_result, lt_lat_result}), - .sc_config_0_sc_if_h_config_o (hv_in_config), - .sc_config_0_sc_if_h_config2_o (hv_in_config2), - .sc_config_0_sc_if_v_config_o (hv_in_config3), + .pio_1_controls_in_export (controls), + .sc_config_0_sc_if_fe_status_i ({19'h0, TVP_sync_active, TVP_fe_interlace, TVP_fe_vtotal}), + .sc_config_0_sc_if_fe_status2_i ({12'h0, TVP_fe_pcnt_frame}), + .sc_config_0_sc_if_lt_status_i (32'h00000000), + .sc_config_0_sc_if_hv_in_config_o (hv_in_config), + .sc_config_0_sc_if_hv_in_config2_o (hv_in_config2), + .sc_config_0_sc_if_hv_in_config3_o (hv_in_config3), + .sc_config_0_sc_if_hv_out_config_o (hv_out_config), + .sc_config_0_sc_if_hv_out_config2_o (hv_out_config2), + .sc_config_0_sc_if_hv_out_config3_o (hv_out_config3), + .sc_config_0_sc_if_xy_out_config_o (xy_out_config), + .sc_config_0_sc_if_xy_out_config2_o (xy_out_config2), .sc_config_0_sc_if_misc_config_o (misc_config), .sc_config_0_sc_if_sl_config_o (sl_config), .sc_config_0_sc_if_sl_config2_o (sl_config2), - .osd_generator_0_osd_if_vclk (PCLK_out), - .osd_generator_0_osd_if_xpos (xpos), - .osd_generator_0_osd_if_ypos (ypos), + .sc_config_0_sc_if_sl_config3_o (sl_config3), + .osd_generator_0_osd_if_vclk (PCLK_sc), + .osd_generator_0_osd_if_xpos (xpos_sc), + .osd_generator_0_osd_if_ypos (ypos_sc), .osd_generator_0_osd_if_osd_enable (osd_enable_pre), .osd_generator_0_osd_if_osd_color (osd_color), .pll_reconfig_0_pll_reconfig_if_areset (pll_areset), @@ -334,49 +396,65 @@ sys sys_inst( .pll_reconfig_0_pll_reconfig_if_scandone (pll_scandone) ); -scanconverter scanconverter_inst ( - .reset_n (hw_reset_n), - .PCLK_in (TVP_PCLK_i), - .clk27 (clk27), - .enable_sc (enable_sc), - .HSYNC_in (TVP_HSYNC_post), - .VSYNC_in (TVP_VSYNC_post), - .FID_in (~TVP_FID_post), - .R_in (TVP_R_post), - .G_in (TVP_G_post), - .B_in (TVP_B_post), - .hv_in_config (hv_in_config), - .hv_in_config2 (hv_in_config2), - .hv_in_config3 (hv_in_config3), - .misc_config (misc_config), - .sl_config (sl_config), - .sl_config2 (sl_config2), - .R_out (R_out_sc), - .G_out (G_out_sc), - .B_out (B_out_sc), - .PCLK_out (PCLK_out), - .HSYNC_out (HSYNC_out_sc), - .VSYNC_out (VSYNC_out_sc), - .DE_out (DE_out_sc), - .h_unstable (h_unstable), - .fpga_vsyncgen (fpga_vsyncgen), - .pll_lock_lost (pll_lock_lost), - .vmax (vmax), - .vmax_tvp (vmax_tvp), - .pcnt_frame (pcnt_frame), - .ilace_flag (ilace_flag), - .vsync_flag (vsync_flag), - .lt_active (lt_active), - .lt_mode (lt_mode_synced), - .xpos (xpos_sc), - .ypos (ypos_sc), - .pll_areset (pll_areset), - .pll_scanclk (pll_scanclk), - .pll_scanclkena (pll_scanclkena), - .pll_configupdate (pll_configupdate), - .pll_scandata (pll_scandata), - .pll_scandone (pll_scandone), - .pll_activeclock (pll_activeclock) +scanconverter #( + .EMIF_ENABLE(0), + .NUM_LINE_BUFFERS(2) + ) scanconverter_inst ( + .PCLK_CAP_i(TVP_PCLK_i), + .PCLK_OUT_i(clkmux_clkout), + .reset_n(hw_reset_n), //TODO: sync to pclk_capture + .R_i(TVP_R_post), + .G_i(TVP_G_post), + .B_i(TVP_B_post), + .HSYNC_i(TVP_HSYNC_post), + .VSYNC_i(TVP_VSYNC_post), + .DE_i(TVP_DE_post), + .FID_i(TVP_FID_post), + .datavalid_i(TVP_datavalid_post), + .interlaced_in_i(TVP_fe_interlace), + .frame_change_i(TVP_fe_frame_change), + .xpos_i(TVP_fe_xpos), + .ypos_i(TVP_fe_ypos), + .h_in_active(hv_in_config[23:12]), + .hv_out_config(hv_out_config), + .hv_out_config2(hv_out_config2), + .hv_out_config3(hv_out_config3), + .xy_out_config(xy_out_config), + .xy_out_config2(xy_out_config2), + .misc_config(misc_config), + .sl_config(sl_config), + .sl_config2(sl_config2), + .sl_config3(sl_config3), + .testpattern_enable(~enable_sc), + .lb_enable(enable_sc), + .ext_sync_mode(1'b0), + .ext_frame_change_i(1'b0), + .ext_R_i(8'h00), + .ext_G_i(8'h00), + .ext_B_i(8'h00), + .PCLK_o(PCLK_sc), + .R_o(R_sc), + .G_o(G_sc), + .B_o(B_sc), + .HSYNC_o(HSYNC_sc), + .VSYNC_o(VSYNC_sc), + .DE_o(DE_sc), + .xpos_o(xpos_sc), + .ypos_o(ypos_sc), + .resync_strobe(resync_strobe_i), + .emif_br_clk(1'b0), + .emif_br_reset(1'b0), + .emif_rd_addr(), + .emif_rd_read(), + .emif_rd_rdata(0), + .emif_rd_waitrequest(0), + .emif_rd_readdatavalid(0), + .emif_rd_burstcount(), + .emif_wr_addr(), + .emif_wr_write(), + .emif_wr_wdata(), + .emif_wr_waitrequest(0), + .emif_wr_burstcount() ); ir_rcv ir0 ( @@ -390,12 +468,12 @@ ir_rcv ir0 ( lat_tester lt0 ( .clk27 (clk27), - .pclk (PCLK_out), + .pclk (PCLK_sc), .active (lt_active), .armed (lt_armed), .sensor (lt_sensor), .trigger (lt_trigger), - .VSYNC_in (HDMI_TX_VS), + .VSYNC_in (VSYNC_sc), .mode_in (lt_mode), .mode_synced (lt_mode_synced), .lat_result (lt_lat_result), @@ -404,8 +482,8 @@ lat_tester lt0 ( .finished (lt_finished) ); -videogen vg0 ( - .clk27 (PCLK_out), +/*Ävideogen vg0 ( + .clk27 (PCLK_sc), .reset_n (po_reset_n & ~enable_sc), .lt_active (lt_active), .lt_mode (lt_mode_synced), @@ -417,6 +495,6 @@ videogen vg0 ( .DE_out (DE_out_vg), .xpos (xpos_vg), .ypos (ypos_vg) -); +);*/ endmodule diff --git a/rtl/scanconverter.v b/rtl/scanconverter.v index ce840c5..4a3128b 100644 --- a/rtl/scanconverter.v +++ b/rtl/scanconverter.v @@ -1,5 +1,5 @@ // -// Copyright (C) 2015-2019 Markus Hiienkari +// Copyright (C) 2019-2022 Markus Hiienkari // // This file is part of Open Source Scan Converter project. // @@ -17,1198 +17,446 @@ // along with this program. If not, see . // -`include "lat_tester_includes.v" - -`define TRUE 1'b1 -`define FALSE 1'b0 -`define HI 1'b1 -`define LO 1'b0 - -`define HSYNC_POL `LO -`define VSYNC_POL `LO - -`define V_MULTMODE_1X 3'd0 -`define V_MULTMODE_2X 3'd1 -`define V_MULTMODE_3X 3'd2 -`define V_MULTMODE_4X 3'd3 -`define V_MULTMODE_5X 3'd4 - -`define PCLK_MUX_1X 2'd0 -`define PCLK_MUX_2X 2'd2 -`define PCLK_MUX_3X 2'd2 -`define PCLK_MUX_4X 2'd3 -`define PCLK_MUX_5X 2'd3 - -`define H_MULTMODE_FULLWIDTH 2'h0 -`define H_MULTMODE_ASPECTFIX 2'h1 -`define H_MULTMODE_OPTIMIZED 2'h2 -`define H_MULTMODE_OPTIMIZED_1X 2'h3 - -`define SCANLINES_HYBR_CONTR_LOW 2'h1 -`define SCANLINES_HYBR_CONTR_MED 2'h2 -`define SCANLINES_HYBR_CONTR_HIGH 2'h3 - -`define VSYNCGEN_LEN 6 -`define VSYNCGEN_GENMID_BIT 0 -`define VSYNCGEN_CHOPMID_BIT 1 - -`define FID_ODD 1'b0 -`define FID_EVEN 1'b1 - -`define MIN_VALID_LINES 256 //power of 2 optimization -> ignore lower bits with comparison -`define DBLFRAME_THOLD 5 -`define FALSE_FIELD (fpga_vsyncgen[`VSYNCGEN_CHOPMID_BIT] & (FID_in == `FID_EVEN)) - -`define HSYNC_LEADING_EDGE ((HSYNC_in_L == `HI) & (HSYNC_in == `LO)) -`define VSYNC_LEADING_EDGE ((VSYNC_in_L == `HI) & (VSYNC_in == `LO)) - -`define PP_PL_START 1 -`define PP_HS_VS_DE_START 2 -`define PP_ENABLES_START 2 -`define PP_RGB_START 4 - -//`define PP_RLPF_PL_START_EARLY // set if start with 2 -`define PP_RLPF_PL_START `PP_RGB_START // minimum 2 -`define PP_RLPF_PL_LENGTH 3 // counted from aquisition -`define PP_SLGEN_PL_LENGTH 5 -`define PP_LT_BORDER_GEN_LENGTH 1 // lt_box / border_mask gen - -`define PP_RLPF_PL_END (`PP_RLPF_PL_START+`PP_RLPF_PL_LENGTH) -`define PP_SLGEN_PL_END (`PP_RLPF_PL_END+`PP_SLGEN_PL_LENGTH) -`define PP_PIPELINE_LENGTH (`PP_SLGEN_PL_END+`PP_LT_BORDER_GEN_LENGTH-1'b1) - module scanconverter ( + input PCLK_CAP_i, + input PCLK_OUT_i, input reset_n, - input [7:0] R_in, - input [7:0] G_in, - input [7:0] B_in, - input FID_in, - input VSYNC_in, - input HSYNC_in, - input PCLK_in, - input clk27, - input enable_sc, - input [31:0] hv_in_config, - input [31:0] hv_in_config2, - input [31:0] hv_in_config3, + input [7:0] R_i, + input [7:0] G_i, + input [7:0] B_i, + input HSYNC_i, + input VSYNC_i, + input DE_i, + input FID_i, + input datavalid_i, + input interlaced_in_i, + input frame_change_i, + input [10:0] xpos_i, + input [10:0] ypos_i, + input [11:0] h_in_active, + input [31:0] hv_out_config, + input [31:0] hv_out_config2, + input [31:0] hv_out_config3, + input [31:0] xy_out_config, + input [31:0] xy_out_config2, input [31:0] misc_config, input [31:0] sl_config, input [31:0] sl_config2, - output PCLK_out, - output reg [7:0] R_out, - output reg [7:0] G_out, - output reg [7:0] B_out, - output reg HSYNC_out, - output reg VSYNC_out, - output reg DE_out, - output h_unstable, - output reg [1:0] fpga_vsyncgen, - output pll_lock_lost, - output reg [10:0] vmax, - output reg [10:0] vmax_tvp, - output reg [19:0] pcnt_frame, - output ilace_flag, - output vsync_flag, - input lt_active, - input [1:0] lt_mode, - output reg [10:0] xpos, - output reg [10:0] ypos, - input pll_areset, - input pll_scanclk, - input pll_scanclkena, - input pll_configupdate, - input pll_scandata, - output pll_scandone, - output pll_activeclock + input [31:0] sl_config3, + input testpattern_enable, + input lb_enable, + input ext_sync_mode, + input ext_frame_change_i, + input [7:0] ext_R_i, + input [7:0] ext_G_i, + input [7:0] ext_B_i, + output PCLK_o, + output [7:0] R_o, + output [7:0] G_o, + output [7:0] B_o, + output HSYNC_o, + output VSYNC_o, + output DE_o, + output [11:0] xpos_o, + output [10:0] ypos_o, + output reg resync_strobe, + input emif_br_clk, + input emif_br_reset, + output [27:0] emif_rd_addr, + output emif_rd_read, + input [255:0] emif_rd_rdata, + input emif_rd_waitrequest, + input emif_rd_readdatavalid, + output [5:0] emif_rd_burstcount, + output [27:0] emif_wr_addr, + output emif_wr_write, + output [255:0] emif_wr_wdata, + input emif_wr_waitrequest, + output [5:0] emif_wr_burstcount ); -//clock-related signals and registers -wire pclk_act; -wire pclk_1x, pclk_2x, pclk_3x, pclk_4x, pclk_5x; -wire [1:0] pclk_mux_sel; -wire pll_lock; -reg pll_clkswitch; - -//RGB signals®isters: 8 bits per component -> 16.7M colors -wire [7:0] R_act, G_act, B_act; -wire [7:0] R_lbuf, G_lbuf, B_lbuf; -reg [7:0] R_in_L, G_in_L, B_in_L, R_in_LL, G_in_LL, B_in_LL, R_in_LLL, G_in_LLL, B_in_LLL, R_1x, G_1x, B_1x; - -//H+V syncs + data enable signals®isters -wire HSYNC_act, VSYNC_act, DE_act; -reg HSYNC_in_L, VSYNC_in_L; -reg HSYNC_1x, HSYNC_2x, HSYNC_3x, HSYNC_4x, HSYNC_5x; -reg VSYNC_1x, VSYNC_2x, VSYNC_3x, VSYNC_4x, VSYNC_5x; -reg DE_1x, DE_2x, DE_3x, DE_4x, DE_5x, DE_3x_prev4x; - -//registers indicating line/frame change and field type -reg FID_cur, FID_last, FID_prev, FID_1x; -reg frame_change, frame_change_longpulse, line_change; - -//H+V counters -reg [11:0] linebuf_hoffset_pp; //Offset for line (max. 2047 pixels), MSB indicates which line is read/written -wire [11:0] linebuf_hoffset_act; -wire [11:0] hcnt_act; -reg [11:0] hcnt_1x, hcnt_2x, hcnt_3x, hcnt_4x, hcnt_5x, hcnt_4x_aspfix, hcnt_2x_opt, hcnt_3x_opt, hcnt_3x_lace_ref, hcnt_4x_opt, hcnt_5x_opt, hcnt_5x_hscomp; -reg [2:0] hcnt_2x_opt_ctr, hcnt_3x_opt_ctr, hcnt_4x_opt_ctr, hcnt_5x_opt_ctr; -wire [10:0] vcnt_act; -reg [10:0] vcnt_tvp, vcnt_1x, vcnt_2x, vcnt_3x, vcnt_4x, vcnt_5x; //max. 2047 - -//other counters -wire [2:0] line_id_act, col_id_act; -reg [11:0] hmax[0:1]; -reg [11:0] hmax_3x; -reg line_idx; -reg [1:0] line_out_idx_2x, line_out_idx_3x, line_out_idx_4x; -reg [2:0] line_out_idx_5x; -reg [23:0] warn_h_unstable, warn_pll_lock_lost; - -// post-processing pipeline -reg HSYNC_pp[1:`PP_PIPELINE_LENGTH] /* synthesis ramstyle = "logic" */; -reg VSYNC_pp[1:`PP_PIPELINE_LENGTH] /* synthesis ramstyle = "logic" */; -reg DE_pp[1:`PP_PIPELINE_LENGTH] /* synthesis ramstyle = "logic" */; -reg [7:0] R_pp[3:`PP_PIPELINE_LENGTH], G_pp[3:`PP_PIPELINE_LENGTH], B_pp[3:`PP_PIPELINE_LENGTH] /* synthesis ramstyle = "logic" */; -reg [11:0] hcnt_pp /* synthesis ramstyle = "logic" */; -reg [10:0] vcnt_pp /* synthesis ramstyle = "logic" */; -reg rlpf_trigger_r[1:`PP_RLPF_PL_START-1] /* synthesis ramstyle = "logic" */; -reg [7:0] R_prev_pp[`PP_RLPF_PL_START:`PP_RLPF_PL_END-1], G_prev_pp[`PP_RLPF_PL_START:`PP_RLPF_PL_END-1], B_prev_pp[`PP_RLPF_PL_START:`PP_RLPF_PL_END-1] /* synthesis ramstyle = "logic" */; -reg [2:0] line_id_pp[1:`PP_SLGEN_PL_END-5], col_id_pp[1:`PP_SLGEN_PL_END-5] /* synthesis ramstyle = "logic" */; -reg draw_sl_pp[`PP_SLGEN_PL_END-4:`PP_SLGEN_PL_END-1] /* synthesis ramstyle = "logic" */; -reg border_enable_pp[2:`PP_PIPELINE_LENGTH] /* synthesis ramstyle = "logic" */; -reg lt_box_enable_pp[2:`PP_PIPELINE_LENGTH] /* synthesis ramstyle = "logic" */; - -//helper registers for sampling at synchronized clock edges -reg pclk_1x_prev3x; -reg [1:0] pclk_3x_cnt; -reg pclk_1x_prev4x; -reg [1:0] pclk_4x_cnt; -reg pclk_1x_prev5x; -reg pclk_1x_prevprev5x; -reg [2:0] pclk_5x_cnt; - -//configuration registers -reg [10:0] H_ACTIVE; //max. 2047 -reg [9:0] H_AVIDSTART; //max. 1023 -reg [10:0] V_ACTIVE; //max. 2047 -reg [7:0] V_AVIDSTART; //max. 255 -reg [7:0] H_SYNCLEN; -reg [2:0] V_SYNCLEN; -reg [5:0] V_MASK; -reg [2:0] V_MULTMODE; -reg [1:0] H_MULTMODE; -reg [10:0] H_MASK; -reg [9:0] H_OPT_STARTOFF; -reg [2:0] H_OPT_SCALE; -reg [2:0] H_OPT_SAMPLE_MULT; -reg [2:0] H_OPT_SAMPLE_SEL; -reg [9:0] H_L5BORDER; -reg [9:0] H_L3BORDER; -reg [11:0] H_L3_OPT_START; -reg [3:0] X_MASK_BR; -reg [2:0] X_MASK_COLOR; -reg [5:0] X_REV_LPF_STR; -reg [3:0] SL_L_STR[4:0] /* synthesis ramstyle = "logic" */; -reg [3:0] SL_C_STR[5:0] /* synthesis ramstyle = "logic" */; -reg [4:0] SL_HYBRSTR; -reg [4:0] SL_L_OVERLAY; -reg [5:0] SL_C_OVERLAY; -reg SL_METHOD; -reg SL_NO_ALTERN; -reg SL_ALTIV; -reg X_REV_LPF_ENABLE; -reg X_PANASONIC_HACK; - -// constants for each frame to be calculated off config-registers -reg CALC_CONSTS; -reg [11:0] H_AVIDSTOP; -reg [10:0] V_AVIDSTOP; -reg [10:0] H_AVIDMASK_START; -reg [11:0] H_AVIDMASK_STOP; -reg [7:0] V_AVIDMASK_START; -reg [10:0] V_AVIDMASK_STOP; - -reg [11:0] LT_POS_TOPLEFT_BOX_H_STOP; -reg [11:0] LT_POS_TOPLEFT_BOX_V_STOP; -reg [11:0] LT_POS_CENTER_BOX_H_START; -reg [11:0] LT_POS_CENTER_BOX_H_STOP; -reg [11:0] LT_POS_CENTER_BOX_V_START; -reg [11:0] LT_POS_CENTER_BOX_V_STOP; -reg [11:0] LT_POS_BOTTOMRIGHT_H_START; -reg [10:0] LT_POS_BOTTOMRIGHT_V_START; +parameter EMIF_ENABLE = 0; +parameter NUM_LINE_BUFFERS = 32; -//clk27 related registers -reg VSYNC_in_cc_L, VSYNC_in_cc_LL, VSYNC_in_cc_LLL; -reg [21:0] clk27_ctr; // min. 6.5Hz -reg [2:0] dbl_frame_ctr; -reg frame_change_longpulse_cc_L, frame_change_longpulse_cc_LL, frame_change_longpulse_cc_LLL; -reg [19:0] pcnt_ctr; +localparam FID_EVEN = 1'b0; +localparam FID_ODD = 1'b1; + +localparam PP_PL_START = 1; +localparam PP_LINEBUF_START = PP_PL_START + 1; +localparam PP_LINEBUF_LENGTH = 1; +localparam PP_LINEBUF_END = PP_LINEBUF_START + PP_LINEBUF_LENGTH; +localparam PP_SRCSEL_START = PP_LINEBUF_END; +localparam PP_SRCSEL_LENGTH = 1; +localparam PP_SRCSEL_END = PP_SRCSEL_START + PP_SRCSEL_LENGTH; +localparam PP_SLGEN_START = PP_SRCSEL_START; +localparam PP_SLGEN_LENGTH = 3; +localparam PP_SLGEN_END = PP_SLGEN_START + PP_SLGEN_LENGTH; +localparam PP_TP_START = PP_SLGEN_END; +localparam PP_TP_LENGTH = 1; +localparam PP_TP_END = PP_TP_START + PP_TP_LENGTH; +localparam PP_PL_END = PP_TP_END; + +wire [11:0] H_TOTAL = hv_out_config[11:0]; +wire [11:0] H_ACTIVE = hv_out_config[23:12]; +wire [7:0] H_SYNCLEN = hv_out_config[31:24]; +wire [8:0] H_BACKPORCH = hv_out_config2[8:0]; + +wire V_INTERLACED = hv_out_config2[31]; +wire [10:0] V_TOTAL = hv_out_config2[19:9] >> V_INTERLACED; +wire [10:0] V_ACTIVE = hv_out_config2[30:20]; +wire [3:0] V_SYNCLEN = hv_out_config3[3:0]; +wire [8:0] V_BACKPORCH = hv_out_config3[12:4]; + +wire [10:0] V_STARTLINE = hv_out_config3[23:13]; + +wire [10:0] V_STARTLINE_PREV = (V_STARTLINE == 0) ? (V_TOTAL-1) : (V_STARTLINE-1); + +wire [11:0] X_SIZE = xy_out_config[11:0]; +wire [10:0] Y_SIZE = xy_out_config[22:12]; +wire signed [9:0] X_OFFSET = xy_out_config2[9:0]; +wire signed [8:0] Y_OFFSET = xy_out_config[31:23]; + +wire [7:0] X_START_LB = xy_out_config2[17:10]; +wire signed [5:0] Y_START_LB = xy_out_config2[23:18]; + +wire signed [3:0] X_RPT = xy_out_config2[27:24]; +wire signed [3:0] Y_RPT = xy_out_config2[31:28]; + +wire Y_SKIP = (Y_RPT == 4'(-1)); +wire [1:0] Y_STEP = Y_SKIP+1'b1; + +wire [3:0] SL_L_STR[5:0] = '{sl_config[23:20], sl_config[19:16], sl_config[15:12], sl_config[11:8], sl_config[7:4], sl_config[3:0]}; +wire [3:0] SL_C_STR[9:0] = '{sl_config3[7:4], sl_config3[3:0], sl_config2[31:28], sl_config2[27:24], sl_config2[23:20], sl_config2[19:16], sl_config2[15:12], sl_config2[11:8], sl_config2[7:4], sl_config2[3:0]}; +wire [5:0] SL_L_OVERLAY = sl_config[29:24]; +wire SL_METHOD_PRE = sl_config[30]; +wire SL_BOB_ALTERN = sl_config[31]; +wire [9:0] SL_C_OVERLAY = sl_config3[17:8]; +wire [2:0] SL_IV_Y = sl_config3[20:18]; +wire [3:0] SL_IV_X = sl_config3[24:21]; + +wire [3:0] MISC_MASK_BR = misc_config[3:0]; +wire [2:0] MISC_MASK_COLOR = misc_config[6:4]; +wire [5:0] MISC_REV_LPF_STR = (misc_config[11:7] + 6'd16); +wire MISC_REV_LPF_ENABLE = (misc_config[11:7] != 5'h0); +wire MISC_LM_DEINT_MODE = misc_config[12]; +wire MISC_NIR_EVEN_OFFSET = misc_config[13]; +wire [3:0] MISC_BFI_STR = misc_config[19:16]; +wire MISC_BFI_ENABLE = misc_config[20]; + +wire [7:0] MASK_R = MISC_MASK_COLOR[2] ? {2{MISC_MASK_BR}} : 8'h00; +wire [7:0] MASK_G = MISC_MASK_COLOR[1] ? {2{MISC_MASK_BR}} : 8'h00; +wire [7:0] MASK_B = MISC_MASK_COLOR[0] ? {2{MISC_MASK_BR}} : 8'h00; -assign pclk_1x = PCLK_in; -assign PCLK_out = pclk_act; -assign ilace_flag = (FID_cur != FID_last); +reg frame_change_sync1_reg, frame_change_sync2_reg, frame_change_prev, frame_change_resync; +wire frame_change = frame_change_sync2_reg; -//Scanline generation -reg [8:0] Y_rb_tmp; -reg [9:0] Y; -wire [8:0] Y_sl_hybr_ref_pre, R_sl_hybr_ref_pre, G_sl_hybr_ref_pre, B_sl_hybr_ref_pre; -lpm_mult_4_hybr_ref_pre Y_sl_hybr_ref_pre_u -( - .clock(pclk_act), - .dataa(Y[9:2]), - .datab(SL_HYBRSTR), - .result(Y_sl_hybr_ref_pre) -); -lpm_mult_4_hybr_ref_pre R_sl_hybr_ref_pre_u -( - .clock(pclk_act), - .dataa(R_pp[`PP_RLPF_PL_END]), - .datab(SL_HYBRSTR), - .result(R_sl_hybr_ref_pre) -); -lpm_mult_4_hybr_ref_pre G_sl_hybr_ref_pre_u -( - .clock(pclk_act), - .dataa(G_pp[`PP_RLPF_PL_END]), - .datab(SL_HYBRSTR), - .result(G_sl_hybr_ref_pre) -); -lpm_mult_4_hybr_ref_pre B_sl_hybr_ref_pre_u -( - .clock(pclk_act), - .dataa(B_pp[`PP_RLPF_PL_END]), - .datab(SL_HYBRSTR), - .result(B_sl_hybr_ref_pre) -); +reg [11:0] h_cnt; +reg [10:0] v_cnt; +reg h_avidstart, v_avidstart; +reg src_fid, dst_fid; -wire [8:0] Y_sl_hybr_ref, R_sl_hybr_ref, G_sl_hybr_ref, B_sl_hybr_ref; -lpm_mult_4_hybr_ref Y_sl_hybr_ref_u -( - .clock(pclk_act), - .dataa(Y_sl_hybr_ref_pre), - .datab(sl_str_tmp), - .result(Y_sl_hybr_ref) -); -lpm_mult_4_hybr_ref R_sl_hybr_ref_u -( - .clock(pclk_act), - .dataa(R_sl_hybr_ref_pre), - .datab(sl_str_tmp), - .result(R_sl_hybr_ref) -); -lpm_mult_4_hybr_ref G_sl_hybr_ref_u -( - .clock(pclk_act), - .dataa(G_sl_hybr_ref_pre), - .datab(sl_str_tmp), - .result(G_sl_hybr_ref) -); -lpm_mult_4_hybr_ref B_sl_hybr_ref_u -( - .clock(pclk_act), - .dataa(B_sl_hybr_ref_pre), - .datab(sl_str_tmp), - .result(B_sl_hybr_ref) -); +reg [10:0] xpos_lb; +wire [10:0] xpos_lb_start = (X_OFFSET < 10'sd0) ? 11'd0 : {1'b0, X_OFFSET}; +reg [10:0] ypos_lb, ypos_lb_next; +reg [3:0] x_ctr; +reg [3:0] y_ctr; +reg line_id; +reg ypos_pp_init; -reg [7:0] sl_str, sl_str_tmp, Y_sl_str, R_sl_str, G_sl_str, B_sl_str; +reg [7:0] sl_str; +reg sl_method; +wire bfi_frame; -reg [7:0] R_sl_sub, G_sl_sub, B_sl_sub; wire [7:0] R_sl_mult, G_sl_mult, B_sl_mult; +wire [7:0] R_linebuf, G_linebuf, B_linebuf; + +// Pipeline registers +reg [7:0] R_pp[PP_LINEBUF_END:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg [7:0] G_pp[PP_LINEBUF_END:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg [7:0] B_pp[PP_LINEBUF_END:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg HSYNC_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg VSYNC_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg DE_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg [11:0] xpos_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg [10:0] ypos_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */; +reg mask_enable_pp[PP_LINEBUF_START:PP_TP_START] /* synthesis ramstyle = "logic" */; +reg draw_sl_pp[(PP_SLGEN_START+1):(PP_SLGEN_END-1)] /* synthesis ramstyle = "logic" */; +reg [3:0] x_ctr_sl_pp[PP_PL_START:PP_SLGEN_START] /* synthesis ramstyle = "logic" */; +reg [2:0] y_ctr_sl_pp[PP_PL_START:PP_SLGEN_START] /* synthesis ramstyle = "logic" */; + +assign PCLK_o = PCLK_OUT_i; + lpm_mult_4_sl R_sl_mult_u ( - .clock(pclk_act), - .dataa(R_pp[`PP_SLGEN_PL_END-2]), - .datab(~Y_sl_str), + .clock(PCLK_OUT_i), + .dataa(R_pp[PP_SLGEN_START+1]), + .datab(~sl_str), .result(R_sl_mult) ); lpm_mult_4_sl G_sl_mult_u ( - .clock(pclk_act), - .dataa(G_pp[`PP_SLGEN_PL_END-2]), - .datab(~Y_sl_str), + .clock(PCLK_OUT_i), + .dataa(G_pp[PP_SLGEN_START+1]), + .datab(~sl_str), .result(G_sl_mult) ); lpm_mult_4_sl B_sl_mult_u ( - .clock(pclk_act), - .dataa(B_pp[`PP_SLGEN_PL_END-2]), - .datab(~Y_sl_str), + .clock(PCLK_OUT_i), + .dataa(B_pp[PP_SLGEN_START+1]), + .datab(~sl_str), .result(B_sl_mult) ); -//Reverse LPF -wire rlpf_trigger_act; -reg signed [14:0] R_diff_s15_pre, G_diff_s15_pre, B_diff_s15_pre, R_diff_s15, G_diff_s15, B_diff_s15; -reg signed [10:0] R_rlpf_result, G_rlpf_result, B_rlpf_result; - -function [7:0] apply_reverse_lpf; - input [7:0] data_prev; - input signed [14:0] diff; - reg signed [10:0] result; - - begin -// result = ({3'b0,data_prev,4'b0} - diff) >>> 4; - result = {3'b0,data_prev} + ~diff[14:4]; // allow for a small error to reduce adder length - apply_reverse_lpf = result[10] ? 8'h00 : |result[9:8] ? 8'hFF : result[7:0]; - end -endfunction - - -//Mux for active data selection -// -//List of critical signals: -// [RGB]_act, DE_act, HSYNC_act, VSYNC_act -// -//Non-critical signals and inactive clock combinations filtered out in SDC -always @(*) -case (V_MULTMODE) - default: begin //`V_MULTMODE_1X - R_act = R_1x; - G_act = G_1x; - B_act = B_1x; - HSYNC_act = HSYNC_1x; - VSYNC_act = VSYNC_1x; - DE_act = DE_1x; - line_id_act = {2'b00, vcnt_1x[0]}; - hcnt_act = hcnt_1x; - vcnt_act = vcnt_1x; - pclk_mux_sel = `PCLK_MUX_1X; - linebuf_hoffset_act = 0; - col_id_act = {2'b00, hcnt_1x[0]}; - rlpf_trigger_act = 1'b1; - end - `V_MULTMODE_2X: begin - R_act = R_lbuf; - G_act = G_lbuf; - B_act = B_lbuf; - HSYNC_act = HSYNC_2x; - VSYNC_act = VSYNC_2x; - DE_act = DE_2x; - line_id_act = SL_NO_ALTERN ? {2'b0, {line_out_idx_2x[0]+FID_1x}} : {1'b0, line_out_idx_2x}; - hcnt_act = hcnt_2x; - vcnt_act = vcnt_2x; - case (H_MULTMODE) - default: begin //`H_MULTMODE_FULLWIDTH - pclk_mux_sel = `PCLK_MUX_2X; - linebuf_hoffset_act = hcnt_2x; - col_id_act = {2'b00, hcnt_2x[0]}; - rlpf_trigger_act = 1'b1; - end - `H_MULTMODE_OPTIMIZED_1X: begin - pclk_mux_sel = `PCLK_MUX_1X; //special case: pclk bypass to enable 2x native sampling - linebuf_hoffset_act = hcnt_2x_opt; - col_id_act = {2'b00, hcnt_2x[1]}; - rlpf_trigger_act = (hcnt_2x_opt_ctr == 0); - end - `H_MULTMODE_OPTIMIZED: begin - pclk_mux_sel = `PCLK_MUX_2X; - linebuf_hoffset_act = hcnt_2x_opt; - col_id_act = hcnt_2x_opt_ctr; - rlpf_trigger_act = (hcnt_2x_opt_ctr == 0); - end - endcase - end - `V_MULTMODE_3X: begin - R_act = R_lbuf; - G_act = G_lbuf; - B_act = B_lbuf; - HSYNC_act = HSYNC_3x; - VSYNC_act = VSYNC_3x; - DE_act = DE_3x; - line_id_act = {1'b0, line_out_idx_3x}; - vcnt_act = vcnt_3x; - case (H_MULTMODE) - default: begin //`H_MULTMODE_FULLWIDTH - pclk_mux_sel = `PCLK_MUX_3X; - linebuf_hoffset_act = hcnt_3x; - hcnt_act = hcnt_3x; - col_id_act = {2'b00, hcnt_3x[0]}; - rlpf_trigger_act = 1'b1; - end - `H_MULTMODE_ASPECTFIX: begin - pclk_mux_sel = `PCLK_MUX_4X; - linebuf_hoffset_act = hcnt_4x_aspfix; - hcnt_act = hcnt_4x_aspfix; - col_id_act = {2'b00, hcnt_4x[0]}; - rlpf_trigger_act = 1'b1; - end - `H_MULTMODE_OPTIMIZED: begin - pclk_mux_sel = `PCLK_MUX_3X; - linebuf_hoffset_act = hcnt_3x_opt; - hcnt_act = hcnt_3x; - col_id_act = hcnt_3x_opt_ctr; - rlpf_trigger_act = (hcnt_3x_opt_ctr == 0); - end - endcase - end - `V_MULTMODE_4X: begin - R_act = R_lbuf; - G_act = G_lbuf; - B_act = B_lbuf; - HSYNC_act = HSYNC_4x; - VSYNC_act = VSYNC_4x; - DE_act = DE_4x; - line_id_act = SL_NO_ALTERN ? {1'b0, {line_out_idx_4x+{FID_1x, 1'b0}}} : {1'b0, line_out_idx_4x}; - hcnt_act = hcnt_4x; - vcnt_act = vcnt_4x; - pclk_mux_sel = `PCLK_MUX_4X; - case (H_MULTMODE) - default: begin //`H_MULTMODE_FULLWIDTH - linebuf_hoffset_act = hcnt_4x; - col_id_act = {2'b00, hcnt_4x[0]}; - rlpf_trigger_act = 1'b1; - end - `H_MULTMODE_OPTIMIZED: begin - linebuf_hoffset_act = hcnt_4x_opt; - col_id_act = hcnt_4x_opt_ctr; - rlpf_trigger_act = (hcnt_4x_opt_ctr == 0); - end - endcase - end - `V_MULTMODE_5X: begin - R_act = R_lbuf; - G_act = G_lbuf; - B_act = B_lbuf; - HSYNC_act = HSYNC_5x; - VSYNC_act = VSYNC_5x; - DE_act = DE_5x; - line_id_act = line_out_idx_5x; - hcnt_act = hcnt_5x; - vcnt_act = vcnt_5x; - pclk_mux_sel = `PCLK_MUX_5X; - case (H_MULTMODE) - default: begin //`H_MULTMODE_FULLWIDTH - linebuf_hoffset_act = hcnt_5x_hscomp; - col_id_act = {2'b00, hcnt_5x[0]}; - rlpf_trigger_act = 1'b1; - end - `H_MULTMODE_OPTIMIZED: begin - linebuf_hoffset_act = hcnt_5x_opt; - col_id_act = hcnt_5x_opt_ctr; - rlpf_trigger_act = (hcnt_5x_opt_ctr == 0); - end - endcase - end -endcase - -pll_2x pll_pclk ( - .areset(pll_areset), - .clkswitch(pll_clkswitch), - .configupdate(pll_configupdate), - .inclk0(clk27), // set videogen clock to primary (power-on default) since both reference clocks must be running during switchover - .inclk1(PCLK_in), // is the secondary input clock fully compensated? - .scanclk(pll_scanclk), - .scanclkena(pll_scanclkena), - .scandata(pll_scandata), - .activeclock(pll_activeclock), - .c0(pclk_2x), // pclk_3x in secondary config - .c1(pclk_5x), // pclk_4x in secondary config - .locked(pll_lock), - .scandataout(), - .scandone(pll_scandone) -); - -assign pclk_3x = pclk_2x; -assign pclk_4x = pclk_5x; - -cycloneive_clkctrl clkctrl1 ( - .clkselect(enable_sc ? pclk_mux_sel : 2'h2), - .ena(1'b1), - .inclk({pclk_5x, pclk_2x, 1'b0, pclk_1x}), // fitter forbids using both clk27 and pclk_1x here since they're on opposite sides - .outclk(pclk_act) -// synopsys translate_off - , - .devclrn(1'b1), - .devpor(1'b1) -// synopsys translate_on -); -defparam - clkctrl1.clock_type = "Global Clock", - clkctrl1.ena_register_mode = "falling edge", - clkctrl1.lpm_type = "cycloneive_clkctrl"; - - -wire [11:0] linebuf_rdaddr = linebuf_hoffset_pp-H_AVIDSTART; -wire [11:0] linebuf_wraddr = hcnt_1x-H_AVIDSTART; - -//TODO: add secondary buffers for interlaced signals with alternative field order -linebuf linebuf_rgb ( - .data({R_in_L, G_in_L, B_in_L}), - .rdaddress ( {~line_idx, linebuf_rdaddr[10:0]} ), - .rdclock ( pclk_act ), - .wraddress( {line_idx, linebuf_wraddr[10:0]} ), - .wrclock ( pclk_1x ), - .wren ( !linebuf_wraddr[11] ), - .q ( {R_lbuf, G_lbuf, B_lbuf} ) +linebuf_top #( + .EMIF_ENABLE(EMIF_ENABLE), + .NUM_LINE_BUFFERS(NUM_LINE_BUFFERS) + ) linebuf_top_inst ( + .PCLK_CAP_i(PCLK_CAP_i), + .PCLK_OUT_i(PCLK_OUT_i), + .R_i(R_i), + .G_i(G_i), + .B_i(B_i), + .DE_i(DE_i), + .datavalid_i(datavalid_i), + .h_in_active(h_in_active), + .xpos_i(xpos_i), + .ypos_i(ypos_i), + .xpos_lb(xpos_lb), + .ypos_lb(ypos_lb), + .ypos_lb_next(ypos_lb_next), + .line_id(line_id), + .lb_enable(lb_enable), + .R_linebuf(R_linebuf), + .G_linebuf(G_linebuf), + .B_linebuf(B_linebuf), + .emif_br_clk(emif_br_clk), + .emif_br_reset(emif_br_reset), + .emif_rd_addr(emif_rd_addr), + .emif_rd_read(emif_rd_read), + .emif_rd_rdata(emif_rd_rdata), + .emif_rd_waitrequest(emif_rd_waitrequest), + .emif_rd_readdatavalid(emif_rd_readdatavalid), + .emif_rd_burstcount(emif_rd_burstcount), + .emif_wr_addr(emif_wr_addr), + .emif_wr_write(emif_wr_write), + .emif_wr_wdata(emif_wr_wdata), + .emif_wr_waitrequest(emif_wr_waitrequest), + .emif_wr_burstcount(emif_wr_burstcount) ); -//Postprocess pipeline -// -// Latency with respect to h_cnt/v_cnt before 1st stage: -// line_id, col_id: 0 cycles -// HSYNC, VSYNC, DE: 1 cycle -// RGB: 2 cycles -// -// Pipeline structure -// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -// |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------| -// | RADDR | | | | | | | | | | | | -// | | LBUF | LBUF | | | | | | | | | | -// | | | | RLPF | RLPF | RLPF | | | | | | | -// | | | | | Y | Y | | | | | | | -// | | | | | | | SLG | SLG | SLG | SLG | SLG | | -// | | | | | | | | | | | | MASK | -// | | | | | | | | | | | | LTBOX | +// Frame change strobe synchronization +always @(posedge PCLK_OUT_i) begin + frame_change_sync1_reg <= frame_change_i; + frame_change_sync2_reg <= frame_change_sync1_reg; + frame_change_prev <= frame_change_sync2_reg; + + frame_change_resync <= ~frame_change_prev & frame_change & ((v_cnt != V_STARTLINE_PREV) & (v_cnt != V_STARTLINE)); +end + +// H/V counters +always @(posedge PCLK_OUT_i) begin + if (ext_sync_mode & ext_frame_change_i) begin + h_cnt <= PP_SRCSEL_START; // compensate pipeline delays + v_cnt <= 0; + bfi_frame <= bfi_frame ^ 1'b1; + end else if (~ext_sync_mode & frame_change_resync) begin + h_cnt <= 0; + v_cnt <= V_STARTLINE; + bfi_frame <= 0; + src_fid <= (~interlaced_in_i | (V_STARTLINE < (V_TOTAL/2))) ? FID_ODD : FID_EVEN; + dst_fid <= (~V_INTERLACED | (V_STARTLINE < (V_TOTAL/2))) ? FID_ODD : FID_EVEN; + resync_strobe <= 1'b1; + end else begin + if (h_cnt == H_TOTAL-1) begin + if ((~V_INTERLACED & (v_cnt == V_TOTAL-1)) | + (V_INTERLACED & (dst_fid == FID_ODD) & (v_cnt == V_TOTAL)) | + (V_INTERLACED & (dst_fid == FID_EVEN) & (v_cnt == V_TOTAL-1))) + begin + v_cnt <= 0; + v_avidstart <= (V_SYNCLEN+V_BACKPORCH-1'b1 == 0); + src_fid <= interlaced_in_i ? (src_fid ^ 1'b1) : FID_ODD; + dst_fid <= V_INTERLACED ? (dst_fid ^ 1'b1) : FID_ODD; + resync_strobe <= 1'b0; + end else begin + v_cnt <= v_cnt + 1'b1; + v_avidstart <= (v_cnt == V_SYNCLEN+V_BACKPORCH-2'h2); + end + h_cnt <= 0; + h_avidstart <= 1'b0; + end else begin + h_cnt <= h_cnt + 1'b1; + h_avidstart <= (h_cnt == H_SYNCLEN+H_BACKPORCH-1'b1); + end + end +end + +// Postprocess pipeline structure +// 1 2 3 4 5 6 7 +// |----------|----------|---------|---------|---------|---------|--------| +// | SYNC/DE | | | | | | | +// | X/Y POS | | | | | | | +// | | MASK | | | | | | +// | | LB_SETUP | LINEBUF | | | | | +// | | | | SRCSEL | | | | +// | | | | SLGEN | SLGEN | SLGEN | | +// | | | | | | | TP | + + +// Pipeline stage 1 +always @(posedge PCLK_OUT_i) begin + HSYNC_pp[1] <= (h_cnt < H_SYNCLEN) ? 1'b0 : 1'b1; + if (dst_fid == FID_ODD) + VSYNC_pp[1] <= ((v_cnt < V_SYNCLEN) | ((v_cnt == V_TOTAL) & (h_cnt >= (H_TOTAL/2)))) ? 1'b0 : 1'b1; + else + VSYNC_pp[1] <= ((v_cnt < V_SYNCLEN-1) | ((v_cnt == V_SYNCLEN-1) & (h_cnt < (H_TOTAL/2)))) ? 1'b0 : 1'b1; + DE_pp[1] <= (h_cnt >= H_SYNCLEN+H_BACKPORCH) & (h_cnt < H_SYNCLEN+H_BACKPORCH+H_ACTIVE) & (v_cnt >= V_SYNCLEN+V_BACKPORCH) & (v_cnt < V_SYNCLEN+V_BACKPORCH+V_ACTIVE); + + if (h_avidstart) begin + // Start 1 line before active so that linebuffer can be filled from DRAM in time + if (v_avidstart) begin + ypos_pp[1] <= 11'(-1); + ypos_pp_init <= 1'b1; + // Bob deinterlace adjusts linebuf start position and y_ctr for even source fields if + // output is progressive mode. Noninterlace restore as raw output mode is an exception + // which ignores LM deinterlace mode setting. + if (~ext_sync_mode & ~MISC_LM_DEINT_MODE & (Y_RPT > 0) & ~V_INTERLACED & (src_fid == FID_EVEN)) begin + ypos_lb_next <= 11'(Y_START_LB) - 1'b1; + y_ctr <= ((Y_RPT+1'b1) >> 1); + y_ctr_sl_pp[1] <= SL_BOB_ALTERN ? ((Y_RPT+1'b1) >> 1) : 0; + end else begin + if (Y_SKIP & (dst_fid == FID_EVEN)) begin + // Linedrop mode and output interlaced + ypos_lb_next <= 11'(Y_START_LB) + 1'b1; + end else if ((((Y_RPT == 0) & ~V_INTERLACED) | ((Y_RPT > 0) & MISC_LM_DEINT_MODE)) & (src_fid == FID_EVEN)) begin + // Adjust even field Y-offset for noninterlace restore + ypos_lb_next <= 11'(Y_START_LB) - MISC_NIR_EVEN_OFFSET; + end else begin + ypos_lb_next <= 11'(Y_START_LB); + end + y_ctr <= 0; + y_ctr_sl_pp[1] <= 0; + end + line_id <= ~line_id; + end else begin + if (ypos_pp[1] != V_ACTIVE) begin + ypos_pp[1] <= ypos_pp[1] + 1'b1; + + if (ypos_pp_init | (y_ctr == Y_RPT) | Y_SKIP) begin + if ((ypos_lb_next >= NUM_LINE_BUFFERS-Y_STEP) & (ypos_lb_next < NUM_LINE_BUFFERS)) + ypos_lb_next <= ypos_lb_next + Y_STEP - NUM_LINE_BUFFERS; + else + ypos_lb_next <= ypos_lb_next + Y_STEP; + ypos_lb <= ypos_lb_next; + line_id <= ~line_id; + ypos_pp_init <= 1'b0; + if (!ypos_pp_init) + y_ctr <= 0; + end else begin + y_ctr <= y_ctr + 1'b1; + end + if (!ypos_pp_init) + y_ctr_sl_pp[1] <= (y_ctr_sl_pp[1] == SL_IV_Y) ? 0 : y_ctr_sl_pp[1] + 1'b1; + end + end + xpos_pp[1] <= 0; + xpos_lb <= X_START_LB; + x_ctr <= 0; + x_ctr_sl_pp[1] <= 0; + end else begin + if (xpos_pp[1] != H_ACTIVE) begin + xpos_pp[1] <= xpos_pp[1] + 1'b1; + end + + if (xpos_pp[1] >= xpos_lb_start) begin + if (x_ctr == X_RPT) begin + xpos_lb <= xpos_lb + 1'b1; + x_ctr <= 0; + end else begin + x_ctr <= x_ctr + 1'b1; + end + x_ctr_sl_pp[1] <= (x_ctr_sl_pp[1] == SL_IV_X) ? 0 : x_ctr_sl_pp[1] + 1'b1; + end + end +end + +// Pipeline stages 2- integer pp_idx; -always @(posedge pclk_act) -begin - line_id_pp[`PP_PL_START] <= SL_ALTIV ? {2'b00, vcnt_act[0]} : line_id_act; - col_id_pp[`PP_PL_START] <= col_id_act; - for(pp_idx = `PP_PL_START+1; pp_idx <= `PP_SLGEN_PL_END-5; pp_idx = pp_idx+1) begin - line_id_pp[pp_idx] <= line_id_pp[pp_idx-1]; - col_id_pp[pp_idx] <= col_id_pp[pp_idx-1]; - end +always @(posedge PCLK_OUT_i) begin - hcnt_pp <= hcnt_act; - vcnt_pp <= vcnt_act; - linebuf_hoffset_pp <= linebuf_hoffset_act; - xpos <= hcnt_pp - H_AVIDSTART; - ypos <= vcnt_pp - V_AVIDSTART; - - border_enable_pp[`PP_ENABLES_START] <= ((hcnt_pp < H_AVIDMASK_START) | (hcnt_pp >= H_AVIDMASK_STOP) | (vcnt_pp < V_AVIDMASK_START) | (vcnt_pp >= V_AVIDMASK_STOP)); - case (lt_mode) - default: begin - lt_box_enable_pp[`PP_ENABLES_START] <= 0; - end - `LT_POS_TOPLEFT: begin - lt_box_enable_pp[`PP_ENABLES_START] <= ((hcnt_pp < LT_POS_TOPLEFT_BOX_H_STOP) && (vcnt_pp < LT_POS_TOPLEFT_BOX_V_STOP)) ? 1'b1 : 1'b0; - end - `LT_POS_CENTER: begin - lt_box_enable_pp[`PP_ENABLES_START] <= ((hcnt_pp >= LT_POS_CENTER_BOX_H_START) && (hcnt_pp < LT_POS_CENTER_BOX_H_STOP) && (vcnt_pp >= LT_POS_CENTER_BOX_V_START) && (vcnt_pp < LT_POS_CENTER_BOX_V_STOP)) ? 1'b1 : 1'b0; - end - `LT_POS_BOTTOMRIGHT: begin - lt_box_enable_pp[`PP_ENABLES_START] <= ((hcnt_pp >= LT_POS_BOTTOMRIGHT_H_START) && (vcnt_pp >= LT_POS_BOTTOMRIGHT_V_START)) ? 1'b1 : 1'b0; - end - endcase - for(pp_idx = `PP_ENABLES_START+1; pp_idx <= `PP_PIPELINE_LENGTH; pp_idx = pp_idx+1) begin - lt_box_enable_pp[pp_idx] <= lt_box_enable_pp[pp_idx-1]; - border_enable_pp[pp_idx] <= border_enable_pp[pp_idx-1]; - end - - HSYNC_pp[`PP_HS_VS_DE_START] <= HSYNC_act; - VSYNC_pp[`PP_HS_VS_DE_START] <= VSYNC_act; - DE_pp[`PP_HS_VS_DE_START] <= DE_act; - for(pp_idx = `PP_HS_VS_DE_START+1; pp_idx <= `PP_PIPELINE_LENGTH; pp_idx = pp_idx+1) begin + for(pp_idx = PP_LINEBUF_START; pp_idx <= PP_PL_END; pp_idx = pp_idx+1) begin HSYNC_pp[pp_idx] <= HSYNC_pp[pp_idx-1]; VSYNC_pp[pp_idx] <= VSYNC_pp[pp_idx-1]; DE_pp[pp_idx] <= DE_pp[pp_idx-1]; + xpos_pp[pp_idx] <= xpos_pp[pp_idx-1]; + ypos_pp[pp_idx] <= ypos_pp[pp_idx-1]; end - HSYNC_out <= HSYNC_pp[`PP_PIPELINE_LENGTH]; - VSYNC_out <= VSYNC_pp[`PP_PIPELINE_LENGTH]; - DE_out <= DE_pp[`PP_PIPELINE_LENGTH]; - - // get RGB and delay it - R_pp[`PP_RGB_START] <= R_act; - G_pp[`PP_RGB_START] <= G_act; - B_pp[`PP_RGB_START] <= B_act; - for(pp_idx = `PP_RGB_START+1; pp_idx <= `PP_PIPELINE_LENGTH; pp_idx = pp_idx + 1) begin - R_pp[pp_idx] <= R_pp[pp_idx-1]; - G_pp[pp_idx] <= G_pp[pp_idx-1]; - B_pp[pp_idx] <= B_pp[pp_idx-1]; - end - R_out <= R_pp[`PP_PIPELINE_LENGTH]; - G_out <= G_pp[`PP_PIPELINE_LENGTH]; - B_out <= B_pp[`PP_PIPELINE_LENGTH]; - - // reverse LPF ... - rlpf_trigger_r[`PP_PL_START] <= rlpf_trigger_act; - for(pp_idx = `PP_PL_START+1; pp_idx <= `PP_RLPF_PL_START-1; pp_idx = pp_idx + 1) - rlpf_trigger_r[pp_idx] <= rlpf_trigger_r[pp_idx-1]; - - // Optimized modes repeat pixels. Save previous pixel only when linebuffer offset changes. - if (rlpf_trigger_r[`PP_RLPF_PL_START-1]) begin -`ifdef PP_RLPF_PL_START_EARLY - R_prev_pp[`PP_RLPF_PL_START] <= R_act; - G_prev_pp[`PP_RLPF_PL_START] <= G_act; - B_prev_pp[`PP_RLPF_PL_START] <= B_act; -`else - R_prev_pp[`PP_RLPF_PL_START] <= R_pp[`PP_RLPF_PL_START]; - G_prev_pp[`PP_RLPF_PL_START] <= G_pp[`PP_RLPF_PL_START]; - B_prev_pp[`PP_RLPF_PL_START] <= B_pp[`PP_RLPF_PL_START]; -`endif - end - for(pp_idx = `PP_RLPF_PL_START+1; pp_idx <= `PP_RLPF_PL_END-1; pp_idx = pp_idx + 1) begin - R_prev_pp[pp_idx] <= R_prev_pp[pp_idx-1]; - G_prev_pp[pp_idx] <= G_prev_pp[pp_idx-1]; - B_prev_pp[pp_idx] <= B_prev_pp[pp_idx-1]; + for(pp_idx = PP_LINEBUF_START; pp_idx <= PP_SLGEN_START; pp_idx = pp_idx+1) begin + x_ctr_sl_pp[pp_idx] <= x_ctr_sl_pp[pp_idx-1]; + y_ctr_sl_pp[pp_idx] <= y_ctr_sl_pp[pp_idx-1]; end - // ... step 1 -`ifdef PP_RLPF_PL_START_EARLY - R_diff_s15_pre <= (R_prev_pp[`PP_RLPF_PL_START] - R_act); - G_diff_s15_pre <= (G_prev_pp[`PP_RLPF_PL_START] - G_act); - B_diff_s15_pre <= (B_prev_pp[`PP_RLPF_PL_START] - B_act); -`else - R_diff_s15_pre <= (R_prev_pp[`PP_RLPF_PL_START] - R_pp[`PP_RLPF_PL_START]); - G_diff_s15_pre <= (G_prev_pp[`PP_RLPF_PL_START] - G_pp[`PP_RLPF_PL_START]); - B_diff_s15_pre <= (B_prev_pp[`PP_RLPF_PL_START] - B_pp[`PP_RLPF_PL_START]); -`endif - - - // ... step 2 - // R_diff_s15, G_diff_s15, B_diff_s15 are outputs of multiplier IPs 12 pp-stage delay) - R_diff_s15 <= (R_diff_s15_pre * X_REV_LPF_STR); - G_diff_s15 <= (G_diff_s15_pre * X_REV_LPF_STR); - B_diff_s15 <= (B_diff_s15_pre * X_REV_LPF_STR); - - // ... step 3 - if (X_REV_LPF_ENABLE) begin - R_pp[`PP_RLPF_PL_END] <= apply_reverse_lpf(R_prev_pp[`PP_RLPF_PL_END-1], R_diff_s15); - G_pp[`PP_RLPF_PL_END] <= apply_reverse_lpf(G_prev_pp[`PP_RLPF_PL_END-1], G_diff_s15); - B_pp[`PP_RLPF_PL_END] <= apply_reverse_lpf(B_prev_pp[`PP_RLPF_PL_END-1], B_diff_s15); - end - - // calculate Y (based on non-reverseLPF values to keep pipeline length a bit lower) - Y_rb_tmp <= {1'b0,R_pp[`PP_RLPF_PL_END-2]} + {1'b0,B_pp[`PP_RLPF_PL_END-2]}; - Y <= {1'b0,Y_rb_tmp} + {1'b0,G_pp[`PP_RLPF_PL_END-1],1'b0}; - - // modify scanline strength (3 pp-stages) - // ... step 1/3 - // Y_sl_hybr_ref_tmp, R_sl_hybr_ref_tmp, G_sl_hybr_ref_tmp, B_sl_hybr_ref_tmp are outputs of multiplier IPs (1 pp-stage delay) - if (|(SL_L_OVERLAY & (5'h1<= X_OFFSET) & + ($signed({1'b0, xpos_pp[PP_LINEBUF_START-1]}) < X_OFFSET+X_SIZE) & + ($signed({1'b0, ypos_pp[PP_LINEBUF_START-1]}) >= Y_OFFSET) & + ($signed({1'b0, ypos_pp[PP_LINEBUF_START-1]}) < Y_OFFSET+Y_SIZE)) + begin + mask_enable_pp[PP_LINEBUF_START] <= 1'b0; end else begin - draw_sl_pp[`PP_SLGEN_PL_END-4] <= 1'b0; + mask_enable_pp[PP_LINEBUF_START] <= 1'b1; end - for(pp_idx = `PP_SLGEN_PL_END-3; pp_idx <= `PP_SLGEN_PL_END-1; pp_idx = pp_idx + 1) begin + for(pp_idx = PP_LINEBUF_START+1; pp_idx <= PP_TP_START; pp_idx = pp_idx+1) begin + mask_enable_pp[pp_idx] <= mask_enable_pp[pp_idx-1]; + end + + R_pp[PP_SRCSEL_END] <= ext_sync_mode ? ext_R_i : R_linebuf; + G_pp[PP_SRCSEL_END] <= ext_sync_mode ? ext_G_i : G_linebuf; + B_pp[PP_SRCSEL_END] <= ext_sync_mode ? ext_B_i : B_linebuf; + + // Scanlines (3 cycles) + if (MISC_BFI_ENABLE & bfi_frame) begin + sl_str <= ((MISC_BFI_STR+8'h01)<<4)-1'b1; + sl_method <= 1'b1; + draw_sl_pp[PP_SLGEN_START+1] <= 1'b1; + end else if (|(SL_L_OVERLAY & (6'h1< sl_str) ? (R_pp[PP_SLGEN_START+1] - sl_str) : 8'h00) : R_pp[PP_SLGEN_START+1]; + G_pp[PP_SLGEN_START+2] <= draw_sl_pp[PP_SLGEN_START+1] ? ((G_pp[PP_SLGEN_START+1] > sl_str) ? (G_pp[PP_SLGEN_START+1] - sl_str) : 8'h00) : G_pp[PP_SLGEN_START+1]; + B_pp[PP_SLGEN_START+2] <= draw_sl_pp[PP_SLGEN_START+1] ? ((B_pp[PP_SLGEN_START+1] > sl_str) ? (B_pp[PP_SLGEN_START+1] - sl_str) : 8'h00) : B_pp[PP_SLGEN_START+1]; - // ... step 3/3 - Y_sl_str <= {1'b0,sl_str} < Y_sl_hybr_ref ? 8'h0 : sl_str - Y_sl_hybr_ref[7:0]; - R_sl_str <= {1'b0,sl_str} < R_sl_hybr_ref ? 8'h0 : sl_str - R_sl_hybr_ref[7:0]; - G_sl_str <= {1'b0,sl_str} < G_sl_hybr_ref ? 8'h0 : sl_str - G_sl_hybr_ref[7:0]; - B_sl_str <= {1'b0,sl_str} < B_sl_hybr_ref ? 8'h0 : sl_str - B_sl_hybr_ref[7:0]; - - // perform scanline generation (1 pp-stage) - // R_sl_mult, G_sl_mult and B_sl_mult are registered outputs of IP blocks (1 pp-stage delay) - R_sl_sub <= (R_pp[`PP_SLGEN_PL_END-2] > R_sl_str) ? (R_pp[`PP_SLGEN_PL_END-2]-R_sl_str) : 8'h00; - G_sl_sub <= (G_pp[`PP_SLGEN_PL_END-2] > G_sl_str) ? (G_pp[`PP_SLGEN_PL_END-2]-G_sl_str) : 8'h00; - B_sl_sub <= (B_pp[`PP_SLGEN_PL_END-2] > B_sl_str) ? (B_pp[`PP_SLGEN_PL_END-2]-B_sl_str) : 8'h00; - - // draw scanline (1 pp-stage) - if (draw_sl_pp[`PP_SLGEN_PL_END-1]) begin - R_pp[`PP_SLGEN_PL_END] <= SL_METHOD ? R_sl_sub : R_sl_mult; - G_pp[`PP_SLGEN_PL_END] <= SL_METHOD ? G_sl_sub : G_sl_mult; - B_pp[`PP_SLGEN_PL_END] <= SL_METHOD ? B_sl_sub : B_sl_mult; - end - - // apply LT box / mask - if (lt_active) begin - R_out <= {8{lt_box_enable_pp[`PP_PIPELINE_LENGTH]}}; - G_out <= {8{lt_box_enable_pp[`PP_PIPELINE_LENGTH]}}; - B_out <= {8{lt_box_enable_pp[`PP_PIPELINE_LENGTH]}}; - end else if (border_enable_pp[`PP_PIPELINE_LENGTH]) begin - R_out <= X_MASK_COLOR[2] ? {2{X_MASK_BR}} : 8'h00; - G_out <= X_MASK_COLOR[1] ? {2{X_MASK_BR}} : 8'h00; - B_out <= X_MASK_COLOR[0] ? {2{X_MASK_BR}} : 8'h00; - end -end - -//Generate a warning signal from horizontal instability or PLL sync loss -always @(posedge pclk_1x or negedge reset_n) -begin - if (!reset_n) begin - warn_h_unstable <= 1'b0; - warn_pll_lock_lost <= 1'b0; - end else begin - if (hmax[0] != hmax[1]) - warn_h_unstable <= 1; - else if (warn_h_unstable != 0) - warn_h_unstable <= warn_h_unstable + 1'b1; + R_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+2] & sl_method) ? R_sl_mult : R_pp[PP_SLGEN_START+2]; + G_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+2] & sl_method) ? G_sl_mult : G_pp[PP_SLGEN_START+2]; + B_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+2] & sl_method) ? B_sl_mult : B_pp[PP_SLGEN_START+2]; - if ((V_MULTMODE > `V_MULTMODE_1X) & ~pll_lock) - warn_pll_lock_lost <= 1; - else if (warn_pll_lock_lost != 0) - warn_pll_lock_lost <= warn_pll_lock_lost + 1'b1; - end + R_pp[PP_TP_END] <= testpattern_enable ? (xpos_pp[PP_TP_START] ^ ypos_pp[PP_TP_START]) : (mask_enable_pp[PP_TP_START] ? MASK_R : R_pp[PP_TP_START]); + G_pp[PP_TP_END] <= testpattern_enable ? (xpos_pp[PP_TP_START] ^ ypos_pp[PP_TP_START]) : (mask_enable_pp[PP_TP_START] ? MASK_G : G_pp[PP_TP_START]); + B_pp[PP_TP_END] <= testpattern_enable ? (xpos_pp[PP_TP_START] ^ ypos_pp[PP_TP_START]) : (mask_enable_pp[PP_TP_START] ? MASK_B : B_pp[PP_TP_START]); end -assign h_unstable = (warn_h_unstable != 0); -assign pll_lock_lost = (warn_pll_lock_lost != 0); - -//Detect if TVP7002 is skipping VSYNCs. This occurs for interlaced signals fed via digital sync inputs, -//causing TVP7002 not to regenerate VSYNC for even field. Moreover, if leading edges of HSYNC and VSYNC are -//too far from each other for odd field, no VSYNC is regenerated at all. This can be avoided by disabling -//doubled sampling rates ("AV3 interlacefix") and/or minimizing VSYNC delay induced by RC filter on PCB. -//However, TVP7002 datasheet warns that HSYNC/VSYNC should not change simultaneously, so leaving out the -//filter may lead to stability issues and is not recommended. A combination of 220ohm resistor and 1nF -//capacitor seems to be optimal for 480i/576i, including doubled sampling rates. -always @(posedge clk27 or negedge reset_n) -begin - if (!reset_n) begin - fpga_vsyncgen[`VSYNCGEN_GENMID_BIT] <= 1'b0; - VSYNC_in_cc_L <= 1'b0; - VSYNC_in_cc_LL <= 1'b0; - VSYNC_in_cc_LLL <= 1'b0; - clk27_ctr <= 0; - dbl_frame_ctr <= 0; - end else begin - if ((VSYNC_in_cc_LLL == `HI) && (VSYNC_in_cc_LL == `LO)) begin - // If calculated refresh rate is between 22Hz and 44Hz, assume TVP7002 has skipped a vsync - if ((clk27_ctr >= (27000000/44)) && (clk27_ctr <= (27000000/22)) && (dbl_frame_ctr < `DBLFRAME_THOLD)) - dbl_frame_ctr <= dbl_frame_ctr + 1'b1; - else if ((clk27_ctr < (27000000/44)) && (dbl_frame_ctr > 0)) - dbl_frame_ctr <= dbl_frame_ctr - 1'b1; - - clk27_ctr <= 0; - end else if (clk27_ctr < (27000000/10)) begin //prevent overflow - clk27_ctr <= clk27_ctr + 1'b1; - end - - if (dbl_frame_ctr == 0) - fpga_vsyncgen[`VSYNCGEN_GENMID_BIT] <= 1'b0; - else if (dbl_frame_ctr == `DBLFRAME_THOLD) - fpga_vsyncgen[`VSYNCGEN_GENMID_BIT] <= 1'b1; - - VSYNC_in_cc_L <= VSYNC_in; - VSYNC_in_cc_LL <= VSYNC_in_cc_L; - VSYNC_in_cc_LLL <= VSYNC_in_cc_LL; - end -end - -//Calculate exact vertical frequency -always @(posedge clk27 or negedge reset_n) -begin - if (!reset_n) begin - frame_change_longpulse_cc_L <= 1'b0; - frame_change_longpulse_cc_LL <= 1'b0; - frame_change_longpulse_cc_LLL <= 1'b0; - pcnt_ctr <= 1; - pcnt_frame <= 1; - end else begin - if (frame_change_longpulse_cc_LL & !frame_change_longpulse_cc_LLL) begin - pcnt_ctr <= 1; - pcnt_frame <= pcnt_ctr; - end else if (pcnt_ctr < 20'hfffff) begin - pcnt_ctr <= pcnt_ctr + 1'b1; - end - - frame_change_longpulse_cc_L <= frame_change_longpulse; - frame_change_longpulse_cc_LL <= frame_change_longpulse_cc_L; - frame_change_longpulse_cc_LLL <= frame_change_longpulse_cc_LL; - end -end - -// Control PLL reference clock switchover -always @(posedge clk27) -begin - pll_clkswitch <= (pll_activeclock != enable_sc); -end - -//Forward status flag to CPU -assign vsync_flag = ~VSYNC_in_cc_LL; - - -wire [11:0] H_L5BORDER_1920_tmp = (11'd1920-hv_in_config[23:12]); -wire [11:0] H_L5BORDER_1600_tmp = (11'd1600-hv_in_config[23:12]); - -//Buffer the inputs using input pixel clock and generate 1x signals -always @(posedge pclk_1x or negedge reset_n) -begin - if (!reset_n) begin - hcnt_1x <= 0; - vcnt_1x <= 0; - vcnt_tvp <= 0; - hmax[0] <= 0; - hmax[1] <= 0; - vmax <= 0; - vmax_tvp <= 0; - line_idx <= 0; - FID_cur <= 1'b0; - FID_last <= 1'b0; - line_change <= 1'b0; - frame_change <= 1'b0; - frame_change_longpulse <= 1'b0; - fpga_vsyncgen[`VSYNCGEN_CHOPMID_BIT] <= 1'b0; - H_MULTMODE <= 0; - V_MULTMODE <= 0; - end else begin - if (`HSYNC_LEADING_EDGE) begin - hcnt_1x <= 0; - hmax[line_idx] <= hcnt_1x; - line_idx <= line_idx ^ 1'b1; - line_change <= 1'b1; - end else begin - hcnt_1x <= hcnt_1x + 1'b1; - line_change <= 1'b0; - end - - if (`HSYNC_LEADING_EDGE) begin - if (`VSYNC_LEADING_EDGE) begin // non-interlace frame or odd field (interlace) start - FID_cur <= `FID_ODD; - FID_last <= FID_cur; - vcnt_1x <= 0; - frame_change <= 1'b1; - vmax <= vcnt_1x; - vcnt_tvp <= 0; - vmax_tvp <= vcnt_tvp; - end else begin - vcnt_1x <= vcnt_1x + 1'b1; - vcnt_tvp <= vcnt_tvp + 1'b1; - end - end else if (`VSYNC_LEADING_EDGE) begin // even field (interlace) start - if (!`FALSE_FIELD) begin - FID_cur <= `FID_EVEN; - FID_last <= FID_cur; - vcnt_1x <= 11'h7ff; // -1 for 11 bit word - frame_change <= 1'b1; - //vmax <= vcnt_1x; - end - vcnt_tvp <= 0; - vmax_tvp <= vcnt_tvp; - end else if ((fpga_vsyncgen[`VSYNCGEN_GENMID_BIT]) && (vcnt_tvp == (vmax_tvp>>1)) && (hcnt_1x == (hmax[~line_idx]>>1))) begin //VSM=1 - FID_cur <= `FID_EVEN; - FID_last <= FID_cur; - vcnt_1x <= 11'h7ff; // -1 for 11 bit word - frame_change <= 1'b1; - //vmax <= vcnt_1x; - end else - frame_change <= 1'b0; - - if (`VSYNC_LEADING_EDGE) begin - FID_prev <= FID_in; - // detect non-interlaced signal with consecutive even field signaling (TVP7002 detects it as interlaced with analog sync inputs). - // FID is updated at leading edge of VSYNC - if (FID_in == FID_prev) - fpga_vsyncgen[`VSYNCGEN_CHOPMID_BIT] <= `FALSE; - else if (FID_in == `FID_EVEN) // TVP7002 falsely indicates field change with (vcnt < active_lines) - fpga_vsyncgen[`VSYNCGEN_CHOPMID_BIT] <= (vcnt_tvp < `MIN_VALID_LINES); - end - - if (frame_change) begin - //Read configuration data from CPU - H_MULTMODE <= misc_config[25:24]; // Horizontal scaling mode - V_MULTMODE <= misc_config[28:26]; // Line multiply mode - - H_SYNCLEN <= hv_in_config[31:24]; // Horizontal sync length (0...255) - H_AVIDSTART <= hv_in_config[31:24]+hv_in_config2[8:0]; // Horizontal sync+backporch length (0...1023) - H_ACTIVE <= hv_in_config[23:12]; // Horizontal active length (0...2047) - - V_SYNCLEN <= hv_in_config3[3:0]; // Vertical sync length (0...7) - V_AVIDSTART <= hv_in_config3[3:0]+hv_in_config3[12:4]; // Vertical sync+backporch length (0...255) - V_ACTIVE <= hv_in_config2[30:20]; // Vertical active length (0...2047) - - H_MASK <= 0; - V_MASK <= 0; - -// H_L5BORDER <= h_config[29] ? (11'd1920-h_config[10:0])/2 : (11'd1600-h_config[10:0])/2; - H_L5BORDER <= H_L5BORDER_1920_tmp[10:1]; - // For Line3x 240x360 - H_L3BORDER <= 0; - - H_L3_OPT_START <= 0; - - H_OPT_SCALE <= misc_config[31:29]; - H_OPT_SAMPLE_SEL <= hv_in_config3[31:28]; - H_OPT_SAMPLE_MULT <= hv_in_config3[27:24]; - H_OPT_STARTOFF <= misc_config[23:14]; - - X_PANASONIC_HACK <= misc_config[12]; - X_REV_LPF_ENABLE <= (misc_config[11:7] != 5'b00000); - X_REV_LPF_STR <= (misc_config[11:7] + 6'd16); - X_MASK_COLOR <= misc_config[6:4]; - X_MASK_BR <= misc_config[3:0]; - - SL_NO_ALTERN <= sl_config[31]; - SL_METHOD <= sl_config[30]; - SL_HYBRSTR <= sl_config[29:25]; - SL_L_OVERLAY <= sl_config[24:20]; - SL_L_STR[4] <= sl_config[19:16]; - SL_L_STR[3] <= sl_config[15:12]; - SL_L_STR[2] <= sl_config[11:8]; - SL_L_STR[1] <= sl_config[7:4]; - SL_L_STR[0] <= sl_config[3:0]; - SL_ALTIV <= sl_config2[31]; - SL_C_OVERLAY <= sl_config2[29:24]; - SL_C_STR[5] <= sl_config2[23:20]; - SL_C_STR[4] <= sl_config2[19:16]; - SL_C_STR[3] <= sl_config2[15:12]; - SL_C_STR[2] <= sl_config2[11:8]; - SL_C_STR[1] <= sl_config2[7:4]; - SL_C_STR[0] <= sl_config2[3:0]; - - CALC_CONSTS <= 1'b1; - end - - // generate long pulse for hz counter - if (frame_change) - frame_change_longpulse <= 1'b1; - else if (vcnt_1x > 0) - frame_change_longpulse <= 1'b0; - - if (CALC_CONSTS) begin - H_AVIDSTOP <= H_AVIDSTART+H_ACTIVE; - V_AVIDSTOP <= V_AVIDSTART+V_ACTIVE; - - H_AVIDMASK_START <= H_AVIDSTART+H_MASK; - H_AVIDMASK_STOP <= H_AVIDSTART+H_ACTIVE-H_MASK; - V_AVIDMASK_START <= V_AVIDSTART+V_MASK; - V_AVIDMASK_STOP <= V_AVIDSTART+V_ACTIVE-V_MASK; - - LT_POS_TOPLEFT_BOX_H_STOP <= H_AVIDSTART+(H_ACTIVE/`LT_WIDTH_DIV); - LT_POS_TOPLEFT_BOX_V_STOP <= V_AVIDSTART+(V_ACTIVE/`LT_HEIGHT_DIV); - LT_POS_CENTER_BOX_H_START <= H_AVIDSTART+(H_ACTIVE/2'h2)-(H_ACTIVE/(`LT_WIDTH_DIV*2'h2)); - LT_POS_CENTER_BOX_H_STOP <= H_AVIDSTART+(H_ACTIVE/2'h2)+(H_ACTIVE/(`LT_WIDTH_DIV*2'h2)); - LT_POS_CENTER_BOX_V_START <= V_AVIDSTART+(V_ACTIVE/2'h2)-(V_ACTIVE/(`LT_HEIGHT_DIV*2'h2)); - LT_POS_CENTER_BOX_V_STOP <= V_AVIDSTART+(V_ACTIVE/2'h2)+(V_ACTIVE/(`LT_HEIGHT_DIV*2'h2)); - LT_POS_BOTTOMRIGHT_H_START <= H_AVIDSTART+H_ACTIVE-(H_ACTIVE/`LT_WIDTH_DIV); - LT_POS_BOTTOMRIGHT_V_START <= V_AVIDSTART+V_ACTIVE-(V_ACTIVE/`LT_HEIGHT_DIV); - - CALC_CONSTS <= 1'b0; - end - - R_in_L <= R_in; - G_in_L <= G_in; - B_in_L <= B_in; - HSYNC_in_L <= HSYNC_in; - VSYNC_in_L <= VSYNC_in; - - // Add two delay stages to match linebuf delay - R_in_LL <= R_in_L; - G_in_LL <= G_in_L; - B_in_LL <= B_in_L; - R_in_LLL <= R_in_LL; - G_in_LLL <= G_in_LL; - B_in_LLL <= B_in_LL; - - R_1x <= R_in_LLL; - G_1x <= G_in_LLL; - B_1x <= B_in_LLL; - HSYNC_1x <= (hcnt_1x < H_SYNCLEN) ? `HSYNC_POL : ~`HSYNC_POL; - if (FID_cur == `FID_ODD) - VSYNC_1x <= (vcnt_1x < V_SYNCLEN) ? `VSYNC_POL : ~`VSYNC_POL; - else - VSYNC_1x <= (((vcnt_1x+1'b1) < V_SYNCLEN) | ((vcnt_1x+1'b1 == V_SYNCLEN) & (hcnt_1x <= (hmax[~line_idx]>>1)))) ? `VSYNC_POL : ~`VSYNC_POL; - DE_1x <= ((hcnt_1x >= H_AVIDSTART) & (hcnt_1x < H_AVIDSTOP)) & ((vcnt_1x >= V_AVIDSTART) & (vcnt_1x < V_AVIDSTOP)); - FID_1x <= FID_cur; - end -end - -//Generate 2x signals for linedouble -always @(posedge pclk_2x or negedge reset_n) -begin - if (!reset_n) begin - hcnt_2x <= 0; - vcnt_2x <= 0; - line_out_idx_2x <= 0; - end else begin - if ((pclk_1x == 1'b1) & (line_change | frame_change)) begin //aligned with negedge of pclk_1x - hcnt_2x <= 0; - hcnt_2x_opt <= H_OPT_SAMPLE_SEL; - hcnt_2x_opt_ctr <= 0; - line_out_idx_2x <= 0; - if (frame_change) - vcnt_2x <= 11'h7ff; // -1 for 11 bit word - else if (line_change & (FID_cur == `FID_ODD)) - vcnt_2x <= vcnt_2x + 1'b1; - end else if (hcnt_2x == hmax[~line_idx]) begin - hcnt_2x <= 0; - line_out_idx_2x <= line_out_idx_2x + 1'b1; - hcnt_2x_opt <= H_OPT_SAMPLE_SEL; - hcnt_2x_opt_ctr <= 0; - if (FID_cur == `FID_EVEN) - vcnt_2x <= vcnt_2x + 1'b1; - end else begin - hcnt_2x <= hcnt_2x + 1'b1; - if (hcnt_2x >= H_OPT_STARTOFF) begin - if (hcnt_2x_opt_ctr == H_OPT_SCALE-1'b1) begin - hcnt_2x_opt <= hcnt_2x_opt + H_OPT_SAMPLE_MULT; - hcnt_2x_opt_ctr <= 0; - end else - hcnt_2x_opt_ctr <= hcnt_2x_opt_ctr + 1'b1; - end - end - - HSYNC_2x <= (hcnt_2x < H_SYNCLEN) ? `HSYNC_POL : ~`HSYNC_POL; - VSYNC_2x <= (vcnt_2x < V_SYNCLEN) ? `VSYNC_POL : ~`VSYNC_POL; - DE_2x <= ((hcnt_2x >= H_AVIDSTART) & (hcnt_2x < ((X_PANASONIC_HACK & (vcnt_2x == V_AVIDSTOP-1'b1) & (line_out_idx_2x==2'h1)) ? (H_AVIDSTOP-12'd98) : H_AVIDSTOP))) & ((vcnt_2x >= V_AVIDSTART) & (vcnt_2x < V_AVIDSTOP)); - end -end - -always @(posedge pclk_3x or negedge reset_n) -begin - if (!reset_n) begin - hcnt_3x <= 0; - vcnt_3x <= 0; - line_out_idx_3x <= 0; - end else begin - if ((pclk_3x_cnt == 0) & (line_change | frame_change)) begin //aligned with posedge of pclk_1x - if (!(frame_change & (FID_cur == `FID_EVEN))) begin - hcnt_3x <= 0; - hcnt_3x_opt <= H_L3_OPT_START; - hcnt_3x_opt_ctr <= 0; - line_out_idx_3x <= 0; - end - if (frame_change) - vcnt_3x <= -11'b1-FID_cur; - else if (line_change) - vcnt_3x <= vcnt_3x + 1'b1; - end else if (hcnt_3x == hmax_3x) begin - hcnt_3x <= 0; - line_out_idx_3x <= line_out_idx_3x + 1'b1; - hcnt_3x_opt <= H_L3_OPT_START; - hcnt_3x_opt_ctr <= 0; - end else begin - hcnt_3x <= hcnt_3x + 1'b1; - if (hcnt_3x >= H_OPT_STARTOFF) begin - if (hcnt_3x_opt_ctr == H_OPT_SCALE-1'b1) begin - hcnt_3x_opt <= hcnt_3x_opt + H_OPT_SAMPLE_MULT; - hcnt_3x_opt_ctr <= 0; - end else - hcnt_3x_opt_ctr <= hcnt_3x_opt_ctr + 1'b1; - end - end - - //track pclk_3x alignment to pclk_1x rising edge (pclk_1x=1 @ 120deg & pclk_1x=0 @ 240deg) - if (((pclk_1x_prev3x == 1'b1) & (pclk_1x == 1'b0)) | (pclk_3x_cnt == 2'h2)) - pclk_3x_cnt <= 0; - else - pclk_3x_cnt <= pclk_3x_cnt + 1'b1; - - pclk_1x_prev3x <= pclk_1x; - hmax_3x <= hmax[~line_idx]; - hcnt_3x_lace_ref <= (hmax_3x>>1)+1'b1; - - HSYNC_3x <= (hcnt_3x < H_SYNCLEN) ? `HSYNC_POL : ~`HSYNC_POL; - if (FID_cur == `FID_ODD) - VSYNC_3x <= (vcnt_3x < V_SYNCLEN) ? `VSYNC_POL : ~`VSYNC_POL; - else begin - if ((vcnt_3x+1'b1 == 11'd0) & (line_out_idx_3x == 1) & (hcnt_3x == hcnt_3x_lace_ref)) - VSYNC_3x <= `VSYNC_POL; - else if ((vcnt_3x+1'b1 == V_SYNCLEN) & (line_out_idx_3x == 1) & (hcnt_3x == hcnt_3x_lace_ref)) - VSYNC_3x <= ~`VSYNC_POL; - end - - DE_3x <= ((hcnt_3x >= H_AVIDSTART-H_L3BORDER) & (hcnt_3x < H_AVIDSTOP+H_L3BORDER)) & ((vcnt_3x >= V_AVIDSTART) & (vcnt_3x < V_AVIDSTOP)); - end -end - -always @(posedge pclk_4x or negedge reset_n) -begin - if (!reset_n) begin - hcnt_4x <= 0; - vcnt_4x <= 0; - line_out_idx_4x <= 0; - end else begin - - // TODO: better implementation - if ((DE_3x == 1) & (DE_3x_prev4x == 0)) - hcnt_4x_aspfix <= hcnt_3x - 12'd160; - else - hcnt_4x_aspfix <= hcnt_4x_aspfix + 1'b1; - - DE_3x_prev4x <= DE_3x; - - if ((pclk_4x_cnt == 0) & (line_change | frame_change)) begin //aligned with posedge of pclk_1x - hcnt_4x <= 0; - hcnt_4x_opt <= H_OPT_SAMPLE_SEL; - hcnt_4x_opt_ctr <= 0; - line_out_idx_4x <= 0; - if (frame_change) - vcnt_4x <= 11'h7ff; // -1 for 11 bit word - else if (line_change & (FID_cur == `FID_ODD)) - vcnt_4x <= vcnt_4x + 1'b1; - end else if (hcnt_4x == hmax[~line_idx]) begin - hcnt_4x <= 0; - line_out_idx_4x <= line_out_idx_4x + 1'b1; - hcnt_4x_opt <= H_OPT_SAMPLE_SEL; - hcnt_4x_opt_ctr <= 0; - if ((FID_cur == `FID_EVEN) && (line_out_idx_4x == 1)) - vcnt_4x <= vcnt_4x + 1'b1; - end else begin - hcnt_4x <= hcnt_4x + 1'b1; - if (hcnt_4x >= H_OPT_STARTOFF) begin - if (hcnt_4x_opt_ctr == H_OPT_SCALE-1'b1) begin - hcnt_4x_opt <= hcnt_4x_opt + H_OPT_SAMPLE_MULT; - hcnt_4x_opt_ctr <= 0; - end else - hcnt_4x_opt_ctr <= hcnt_4x_opt_ctr + 1'b1; - end - end - - //track pclk_4x alignment to pclk_1x rising edge (pclk_1x=1 @ 180deg & pclk_1x=0 @ 270deg) - if (((pclk_1x_prev4x == 1'b1) & (pclk_1x == 1'b0)) | (pclk_4x_cnt == 2'h3)) - pclk_4x_cnt <= 0; - else - pclk_4x_cnt <= pclk_4x_cnt + 1'b1; - - pclk_1x_prev4x <= pclk_1x; - - HSYNC_4x <= (hcnt_4x < H_SYNCLEN) ? `HSYNC_POL : ~`HSYNC_POL; - VSYNC_4x <= (vcnt_4x < V_SYNCLEN) ? `VSYNC_POL : ~`VSYNC_POL; - DE_4x <= ((hcnt_4x >= H_AVIDSTART) & (hcnt_4x < H_AVIDSTOP)) & ((vcnt_4x >= V_AVIDSTART) & (vcnt_4x < V_AVIDSTOP)); - end -end - -always @(posedge pclk_5x or negedge reset_n) -begin - if (!reset_n) begin - hcnt_5x <= 0; - vcnt_5x <= 0; - line_out_idx_5x <= 0; - end else begin - if ((pclk_5x_cnt == 0) & (line_change | frame_change)) begin //aligned with posedge of pclk_1x - hcnt_5x <= 0; - hcnt_5x_opt <= H_OPT_SAMPLE_SEL + 11'd120; - hcnt_5x_opt_ctr <= 0; - line_out_idx_5x <= 0; - if (frame_change) - vcnt_5x <= 11'h7ff; // -1 for 11 bit word - else if (line_change) - vcnt_5x <= vcnt_5x + 1'b1; - end else if (hcnt_5x == hmax[~line_idx]) begin - hcnt_5x <= 0; - line_out_idx_5x <= line_out_idx_5x + 1'b1; - hcnt_5x_opt <= H_OPT_SAMPLE_SEL + 11'd120; - hcnt_5x_opt_ctr <= 0; - end else begin - hcnt_5x <= hcnt_5x + 1'b1; - if (hcnt_5x >= H_OPT_STARTOFF) begin - if (hcnt_5x_opt_ctr == H_OPT_SCALE-1'b1) begin - hcnt_5x_opt <= hcnt_5x_opt + H_OPT_SAMPLE_MULT; - hcnt_5x_opt_ctr <= 0; - end else - hcnt_5x_opt_ctr <= hcnt_5x_opt_ctr + 1'b1; - end - end - - //track pclk_5x alignment to pclk_1x rising edge (pclk_1x=1 @ 144deg & pclk_1x=0 @ 216deg & pclk_1x=0 @ 288deg) - if (((pclk_1x_prevprev5x == 1'b1) & (pclk_1x_prev5x == 1'b0)) | (pclk_5x_cnt == 3'h4)) - pclk_5x_cnt <= 0; - else - pclk_5x_cnt <= pclk_5x_cnt + 1'b1; - - pclk_1x_prev5x <= pclk_1x; - pclk_1x_prevprev5x <= pclk_1x_prev5x; - - hcnt_5x_hscomp <= hcnt_5x + 11'd121; - - HSYNC_5x <= (hcnt_5x < H_SYNCLEN) ? `HSYNC_POL : ~`HSYNC_POL; - VSYNC_5x <= (vcnt_5x < V_SYNCLEN) ? `VSYNC_POL : ~`VSYNC_POL; - DE_5x <= ((hcnt_5x >= H_AVIDSTART-H_L5BORDER) & (hcnt_5x < H_AVIDSTOP+H_L5BORDER)) & ((vcnt_5x >= V_AVIDSTART) & (vcnt_5x < V_AVIDSTOP)); - end -end +// Output +assign R_o = R_pp[PP_PL_END]; +assign G_o = G_pp[PP_PL_END]; +assign B_o = B_pp[PP_PL_END]; +assign HSYNC_o = HSYNC_pp[PP_PL_END]; +assign VSYNC_o = VSYNC_pp[PP_PL_END]; +assign DE_o = DE_pp[PP_PL_END]; +assign xpos_o = xpos_pp[PP_PL_END]; +assign ypos_o = ypos_pp[PP_PL_END]; endmodule