integrate RTL from ossc_pro project

This commit is contained in:
marqs 2023-02-13 19:00:57 +02:00
parent 94c0526265
commit 804642bd98
4 changed files with 913 additions and 1333 deletions

View File

@ -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 ###

279
rtl/linebuf_top.v Normal file
View File

@ -0,0 +1,279 @@
//
// Copyright (C) 2022 Markus Hiienkari <mhiienka@niksula.hut.fi>
//
// 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 <http://www.gnu.org/licenses/>.
//
//`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

View File

@ -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

File diff suppressed because it is too large Load Diff