// Multiplier-based RGB -> YPbPr conversion // Copyright 2020/2021 by Alastair M. Robinson module RGBtoYPbPr ( input clk, input ena, input [WIDTH-1:0] red_in, input [WIDTH-1:0] green_in, input [WIDTH-1:0] blue_in, input hs_in, input vs_in, input cs_in, input pixel_in, output [WIDTH-1:0] red_out, output [WIDTH-1:0] green_out, output [WIDTH-1:0] blue_out, output reg hs_out, output reg vs_out, output reg cs_out, output reg pixel_out ); parameter WIDTH = 8; reg [8+WIDTH-1:0] r_y; reg [8+WIDTH-1:0] g_y; reg [8+WIDTH-1:0] b_y; reg [8+WIDTH-1:0] r_b; reg [8+WIDTH-1:0] g_b; reg [8+WIDTH-1:0] b_b; reg [8+WIDTH-1:0] r_r; reg [8+WIDTH-1:0] g_r; reg [8+WIDTH-1:0] b_r; reg [8+WIDTH-1:0] y; reg [8+WIDTH-1:0] b; reg [8+WIDTH-1:0] r; reg hs_d; reg vs_d; reg cs_d; reg pixel_d; assign red_out = r[8+WIDTH-1:8]; assign green_out = y[8+WIDTH-1:8]; assign blue_out = b[8+WIDTH-1:8]; // Multiply in the first stage... always @(posedge clk) begin hs_d <= hs_in; // Register sync, pixel clock, etc vs_d <= vs_in; // so they're delayed the same amount as the incoming video cs_d <= cs_in; pixel_d <= pixel_in; if(ena) begin // (Y = 0.299*R + 0.587*G + 0.114*B) r_y <= red_in * 8'd76; g_y <= green_in * 8'd150; b_y <= blue_in * 8'd29; // (Pb = -0.169*R - 0.331*G + 0.500*B) r_b <= red_in * 8'd43; g_b <= green_in * 8'd84; b_b <= blue_in * 8'd128; // (Pr = 0.500*R - 0.419*G - 0.081*B) r_r <= red_in * 8'd128; g_r <= green_in * 8'd107; b_r <= blue_in * 8'd20; end else begin r_r[8+WIDTH-1:8] <= red_in; // Passthrough g_y[8+WIDTH-1:8] <= green_in; b_b[8+WIDTH-1:8] <= blue_in; end end // Second stage - adding always @(posedge clk) begin hs_out <= hs_d; vs_out <= vs_d; cs_out <= cs_d; pixel_out <= pixel_d; if(ena) begin y <= r_y + g_y + b_y; b <= 2'd2**(8+WIDTH-1) + b_b - r_b - g_b; r <= 2'd2**(8+WIDTH-1) + r_r - g_r - b_r; end else begin y <= g_y; // Passthrough b <= b_b; r <= r_r; end end endmodule