// // Copyright (C) 2019-2023 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 . // module scanconverter ( input PCLK_CAP_i, input PCLK_OUT_i, input reset_n, 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, 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 ); parameter EMIF_ENABLE = 0; parameter NUM_LINE_BUFFERS = 32; localparam FID_EVEN = 1'b0; localparam FID_ODD = 1'b1; localparam PP_PL_START = 1; localparam PP_MASK_START = PP_PL_START; localparam PP_MASK_LENGTH = 1; localparam PP_MASK_END = PP_MASK_START + PP_MASK_LENGTH; localparam PP_LINEBUF_START = PP_MASK_END; 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_SHMASK_START = PP_SRCSEL_START; localparam PP_SHMASK_LENGTH = 3; localparam PP_SHMASK_END = PP_SHMASK_START + PP_SHMASK_LENGTH; localparam PP_Y_CALC_START = PP_SRCSEL_END; localparam PP_Y_CALC_LENGTH = 2; localparam PP_Y_CALC_END = PP_Y_CALC_START + PP_Y_CALC_LENGTH; localparam PP_SLGEN_START = PP_Y_CALC_END; localparam PP_SLGEN_LENGTH = 5; 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 [4:0] SL_HYBRSTR = sl_config3[29:25]; wire [3:0] MISC_MASK_BR = misc_config[3:0]; wire [2:0] MISC_MASK_COLOR = misc_config[6:4]; 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 MISC_SHMASK_ENABLE = (misc_config[22:21] != '0); wire [1:0] MISC_SHMASK_ID = (misc_config[22:21] - 1'b1); 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; /* RGB Shadow mask presets: A-Grille, TV, PVM. Data from ShadowMasks_MiSTer */ wire [1:0] shmask_iv_x[0:2] = '{2'h3, 2'h3, 2'h2}; wire [1:0] shmask_iv_y[0:2] = '{2'h0, 2'h1, 2'h3}; wire [10:0] shmask_data[0:2][0:3][0:3] = '{'{ '{11'h44c,11'h24c,11'h14c,11'h04c}, '{11'h0,11'h0,11'h0,11'h0}, '{11'h0,11'h0,11'h0,11'h0}, '{11'h0,11'h0,11'h0,11'h0}}, '{ '{11'h708,11'h44c,11'h24c,11'h14c}, '{11'h44c,11'h24c,11'h14c,11'h708}, '{11'h0,11'h0,11'h0,11'h0}, '{11'h0,11'h0,11'h0,11'h0}}, '{ '{11'h42a,11'h72a,11'h72a,11'h0}, '{11'h42a,11'h22a,11'h72a,11'h0}, '{11'h72a,11'h22a,11'h12a,11'h0}, '{11'h42a,11'h72a,11'h12a,11'h0}}}; reg frame_change_sync1_reg, frame_change_sync2_reg, frame_change_prev, frame_change_resync; wire frame_change = frame_change_sync2_reg; reg [11:0] h_cnt; reg [10:0] v_cnt; reg h_avidstart, v_avidstart; reg src_fid, dst_fid; 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 sl_method; reg [3:0] sl_str; reg [7:0] sl_str_thold, Y_sl_str, R_sl_str, G_sl_str, B_sl_str; wire [7:0] R_sl_mult, G_sl_mult, B_sl_mult; wire bfi_frame; 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; wire [8:0] Y_sl_hybr_ref, R_sl_hybr_ref, G_sl_hybr_ref, B_sl_hybr_ref; reg [4:0] R_shmask_str, G_shmask_str, B_shmask_str; wire [8:0] R_shmask_mult, G_shmask_mult, B_shmask_mult; wire [7:0] R_vg, G_vg, B_vg; wire [7:0] R_linebuf, G_linebuf, B_linebuf; // Pipeline registers reg [7:0] R_pp[PP_SRCSEL_END:PP_PL_END] /* synthesis ramstyle = "logic" */; reg [7:0] G_pp[PP_SRCSEL_END:PP_PL_END] /* synthesis ramstyle = "logic" */; reg [7:0] B_pp[PP_SRCSEL_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_MASK_END: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" */; reg [1:0] x_ctr_shmask_pp[PP_PL_START:PP_SHMASK_START] /* synthesis ramstyle = "logic" */; reg [1:0] y_ctr_shmask_pp[PP_PL_START:PP_SHMASK_START] /* synthesis ramstyle = "logic" */; assign PCLK_o = PCLK_OUT_i; lpm_mult_8x5_9 Y_sl_hybr_ref_pre_u ( .clock(PCLK_OUT_i), .dataa(Y[9:2]), .datab(SL_HYBRSTR), .result(Y_sl_hybr_ref_pre) ); lpm_mult_8x5_9 R_sl_hybr_ref_pre_u ( .clock(PCLK_OUT_i), .dataa(R_pp[PP_SLGEN_START]), .datab(SL_HYBRSTR), .result(R_sl_hybr_ref_pre) ); lpm_mult_8x5_9 G_sl_hybr_ref_pre_u ( .clock(PCLK_OUT_i), .dataa(G_pp[PP_SLGEN_START]), .datab(SL_HYBRSTR), .result(G_sl_hybr_ref_pre) ); lpm_mult_8x5_9 B_sl_hybr_ref_pre_u ( .clock(PCLK_OUT_i), .dataa(B_pp[PP_SLGEN_START]), .datab(SL_HYBRSTR), .result(B_sl_hybr_ref_pre) ); lpm_mult_8x5_9 Y_sl_hybr_ref_u ( .clock(PCLK_OUT_i), .dataa(Y_sl_hybr_ref_pre[8:1]), .datab({sl_str, 1'b0}), .result(Y_sl_hybr_ref) ); lpm_mult_8x5_9 R_sl_hybr_ref_u ( .clock(PCLK_OUT_i), .dataa(R_sl_hybr_ref_pre[8:1]), .datab({sl_str, 1'b0}), .result(R_sl_hybr_ref) ); lpm_mult_8x5_9 G_sl_hybr_ref_u ( .clock(PCLK_OUT_i), .dataa(G_sl_hybr_ref_pre[8:1]), .datab({sl_str, 1'b0}), .result(G_sl_hybr_ref) ); lpm_mult_8x5_9 B_sl_hybr_ref_u ( .clock(PCLK_OUT_i), .dataa(B_sl_hybr_ref_pre[8:1]), .datab({sl_str, 1'b0}), .result(B_sl_hybr_ref) ); lpm_mult_sl R_sl_mult_u ( .clock(PCLK_OUT_i), .dataa(R_pp[PP_SLGEN_START+3]), .datab(~Y_sl_str), .result(R_sl_mult) ); lpm_mult_sl G_sl_mult_u ( .clock(PCLK_OUT_i), .dataa(G_pp[PP_SLGEN_START+3]), .datab(~Y_sl_str), .result(G_sl_mult) ); lpm_mult_sl B_sl_mult_u ( .clock(PCLK_OUT_i), .dataa(B_pp[PP_SLGEN_START+3]), .datab(~Y_sl_str), .result(B_sl_mult) ); lpm_mult_8x5_9 R_shmask_mult_u ( .clock(PCLK_OUT_i), .dataa(R_pp[PP_SHMASK_START+1]), .datab(R_shmask_str), .result(R_shmask_mult) ); lpm_mult_8x5_9 G_shmask_mult_u ( .clock(PCLK_OUT_i), .dataa(G_pp[PP_SHMASK_START+1]), .datab(G_shmask_str), .result(G_shmask_mult) ); lpm_mult_8x5_9 B_shmask_mult_u ( .clock(PCLK_OUT_i), .dataa(B_pp[PP_SHMASK_START+1]), .datab(B_shmask_str), .result(B_shmask_mult) ); 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) ); videogen vg0 ( .pclk (PCLK_OUT_i), .lt_active (1'b0), .lt_mode (2'h0), .xpos (xpos_pp[PP_TP_START]), .ypos (ypos_pp[PP_TP_START]), .R_out (R_vg), .G_out (G_vg), .B_out (B_vg) ); // 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) & (h_cnt > H_TOTAL-128)) | ((v_cnt == V_STARTLINE) & (h_cnt < 128))); 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 8 9 10 11 12 // |----------|----------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------| // | SYNC/DE | | | | | | | | | | | | // | X/Y POS | | | | | | | | | | | | // | | MASK | | | | | | | | | | | // | | LB_SETUP | LINEBUF | | | | | | | | | | // | | | | SRCSEL | | | | | | | | | // | | | | SHMASK | SHMASK | SHMASK | | | | | | | // | | | | | Y | Y | | | | | | | // | | | | | | | SLGEN | SLGEN | 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; y_ctr_shmask_pp[1] <= '0; 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) begin y_ctr_sl_pp[1] <= (y_ctr_sl_pp[1] == SL_IV_Y) ? '0 : y_ctr_sl_pp[1] + 1'b1; y_ctr_shmask_pp[1] <= (y_ctr_shmask_pp[1] == shmask_iv_y[MISC_SHMASK_ID]) ? '0 : y_ctr_shmask_pp[1] + 1'b1; end end end xpos_pp[1] <= 0; xpos_lb <= X_START_LB; x_ctr <= 0; x_ctr_sl_pp[1] <= 0; x_ctr_shmask_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; x_ctr_shmask_pp[1] <= (x_ctr_shmask_pp[1] == shmask_iv_x[MISC_SHMASK_ID]) ? '0 : x_ctr_shmask_pp[1] + 1'b1; end end end // Pipeline stages 2- integer pp_idx; always @(posedge PCLK_OUT_i) begin for(pp_idx = PP_PL_START+1; 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 for(pp_idx = PP_PL_START+1; 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 for(pp_idx = PP_PL_START+1; pp_idx <= PP_SHMASK_START; pp_idx = pp_idx+1) begin x_ctr_shmask_pp[pp_idx] <= x_ctr_shmask_pp[pp_idx-1]; y_ctr_shmask_pp[pp_idx] <= y_ctr_shmask_pp[pp_idx-1]; end // Overridden later where necessary for (pp_idx = PP_SRCSEL_END+1; pp_idx <= PP_PL_END; 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 /* ---------- Mask enable calculation (1 cycle) ---------- */ if (($signed({1'b0, xpos_pp[PP_MASK_START]}) >= X_OFFSET) & ($signed({1'b0, xpos_pp[PP_MASK_START]}) < X_OFFSET+X_SIZE) & ($signed({1'b0, ypos_pp[PP_MASK_START]}) >= Y_OFFSET) & ($signed({1'b0, ypos_pp[PP_MASK_START]}) < Y_OFFSET+Y_SIZE)) begin mask_enable_pp[PP_MASK_END] <= 1'b0; end else begin mask_enable_pp[PP_MASK_END] <= 1'b1; end for(pp_idx = PP_MASK_END+1; pp_idx <= PP_TP_START; pp_idx = pp_idx+1) begin mask_enable_pp[pp_idx] <= mask_enable_pp[pp_idx-1]; end /* ---------- Source selection (1 cycle) ---------- */ 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; /* ---------- Calculate Y from RGB for hybrid scanlines (2 cycles) ---------- */ Y_rb_tmp <= {1'b0, R_pp[PP_Y_CALC_START]} + {1'b0, B_pp[PP_Y_CALC_START]}; Y <= {1'b0, Y_rb_tmp} + {1'b0, G_pp[PP_Y_CALC_START+1], 1'b0}; /* ---------- Shadow mask calculation (3 cycles) ---------- */ R_shmask_str <= shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][10] ? 5'h10 + shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][7:4] : shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][3:0]; G_shmask_str <= shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][9] ? 5'h10 + shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][7:4] : shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][3:0]; B_shmask_str <= shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][8] ? 5'h10 + shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][7:4] : shmask_data[MISC_SHMASK_ID][y_ctr_shmask_pp[PP_SHMASK_START]][x_ctr_shmask_pp[PP_SHMASK_START]][3:0]; // Cycle 3 R_pp[PP_SHMASK_END] <= MISC_SHMASK_ENABLE ? (R_shmask_mult[8] ? 8'hff : R_shmask_mult[7:0]) : R_pp[PP_SHMASK_START+2]; G_pp[PP_SHMASK_END] <= MISC_SHMASK_ENABLE ? (G_shmask_mult[8] ? 8'hff : G_shmask_mult[7:0]) : G_pp[PP_SHMASK_START+2]; B_pp[PP_SHMASK_END] <= MISC_SHMASK_ENABLE ? (B_shmask_mult[8] ? 8'hff : B_shmask_mult[7:0]) : B_pp[PP_SHMASK_START+2]; /* ---------- Scanline generation (5 cycles) ---------- */ if (MISC_BFI_ENABLE & bfi_frame) begin sl_str <= MISC_BFI_STR; sl_method <= 1'b1; draw_sl_pp[PP_SLGEN_START+1] <= 1'b1; end else if (|(SL_L_OVERLAY & (6'h1< R_sl_str) ? (R_pp[PP_SLGEN_START+3] - R_sl_str) : 8'h00) : R_pp[PP_SLGEN_START+3]; G_pp[PP_SLGEN_START+4] <= draw_sl_pp[PP_SLGEN_START+3] ? ((G_pp[PP_SLGEN_START+3] > G_sl_str) ? (G_pp[PP_SLGEN_START+3] - G_sl_str) : 8'h00) : G_pp[PP_SLGEN_START+3]; B_pp[PP_SLGEN_START+4] <= draw_sl_pp[PP_SLGEN_START+3] ? ((B_pp[PP_SLGEN_START+3] > B_sl_str) ? (B_pp[PP_SLGEN_START+3] - B_sl_str) : 8'h00) : B_pp[PP_SLGEN_START+3]; // Cycle 5 R_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+4] & sl_method) ? R_sl_mult : R_pp[PP_SLGEN_START+4]; G_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+4] & sl_method) ? G_sl_mult : G_pp[PP_SLGEN_START+4]; B_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+4] & sl_method) ? B_sl_mult : B_pp[PP_SLGEN_START+4]; /* ---------- Testpattern / mask generation ---------- */ R_pp[PP_TP_END] <= testpattern_enable ? R_vg : (mask_enable_pp[PP_TP_START] ? MASK_R : R_pp[PP_TP_START]); G_pp[PP_TP_END] <= testpattern_enable ? G_vg : (mask_enable_pp[PP_TP_START] ? MASK_G : G_pp[PP_TP_START]); B_pp[PP_TP_END] <= testpattern_enable ? B_vg : (mask_enable_pp[PP_TP_START] ? MASK_B : B_pp[PP_TP_START]); 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