// Define one of: // MODE_640x480, MODE_800x600, MODE_1024x768, MODE_1280x1024. // ("physical mode" sent to the HDMI) `include "TMDS_encoder.v" // Generate HDMI signal from VGA signal module GFX_hdmi( input wire pixel_clk, // pixel clock input wire pixel_clk_x5, // 5 times pixel clock freq (used by TMDS serializer) // The TMDS serializers operate at (pixel_clock_freq * 10), // but we use DDR mode, hence (pixel_clock_freq * 5). input wire [7:0] R, input wire [7:0] G, input wire [7:0] B, input wire hsync, input wire vsync, input wire draw_area, output wire [3:0] gpdi_dp // HDMI signals, blue, green, red, clock // dgpi_dn generated by pins (see, e.g., ulx3s.lpf) ); // RGB TMDS encoding // Generate 10-bits TMDS red,green,blue signals. Blue embeds HSync/VSync in its // control part. wire [9:0] TMDS_R, TMDS_G, TMDS_B; TMDS_encoder encode_R(.clk(pixel_clk), .VD(R), .CD(2'b00) , .VDE(draw_area), .TMDS(TMDS_R)); TMDS_encoder encode_G(.clk(pixel_clk), .VD(G), .CD(2'b00) , .VDE(draw_area), .TMDS(TMDS_G)); TMDS_encoder encode_B(.clk(pixel_clk), .VD(B), .CD({vsync,hsync}), .VDE(draw_area), .TMDS(TMDS_B)); // Modulo-5 clock divider. reg [4:0] TMDS_mod5=1; wire TMDS_shift_load = TMDS_mod5[4]; always @(posedge pixel_clk_x5) TMDS_mod5 <= {TMDS_mod5[3:0],TMDS_mod5[4]}; // Shifters // Every 5 clocks, we get a fresh R,G,B triplet from the TMDS encoders, // else we shift. reg [9:0] TMDS_shift_R=0, TMDS_shift_G=0, TMDS_shift_B=0; always @(posedge pixel_clk_x5) begin TMDS_shift_R <= TMDS_shift_load ? TMDS_R : {2'b00,TMDS_shift_R[9:2]}; TMDS_shift_G <= TMDS_shift_load ? TMDS_G : {2'b00,TMDS_shift_G[9:2]}; TMDS_shift_B <= TMDS_shift_load ? TMDS_B : {2'b00,TMDS_shift_B[9:2]}; end // DDR serializers: they send D0 at the rising edge and D1 at the falling edge. `ifndef BENCH_OR_LINT `ifdef ULX3S ODDRX1F ddr_R (.D0(TMDS_shift_R[0]), .D1(TMDS_shift_R[1]), .Q(gpdi_dp[2]), .SCLK(pixel_clk_x5), .RST(1'b0)); ODDRX1F ddr_G (.D0(TMDS_shift_G[0]), .D1(TMDS_shift_G[1]), .Q(gpdi_dp[1]), .SCLK(pixel_clk_x5), .RST(1'b0)); ODDRX1F ddr_B (.D0(TMDS_shift_B[0]), .D1(TMDS_shift_B[1]), .Q(gpdi_dp[0]), .SCLK(pixel_clk_x5), .RST(1'b0)); `endif `endif // The pixel clock is sent through the fourth differential pair. assign gpdi_dp[3] = pixel_clk; endmodule /**************************************************************************************/ `ifdef BENCH_OR_LINT module GFX_PLL( input wire pclk, // the board's clock output wire pixel_clk, // pixel clock output wire pixel_clk_x5 // 5 times pixel clock freq (used by TMDS serializer) ); assign pixel_clk = pclk; assign pixel_clk_x5 = pclk; endmodule `else `ifdef ULX3S module GFX_PLL( input wire pclk, // the board's clock output wire pixel_clk, // pixel clock output wire pixel_clk_x5 // 5 times pixel clock freq (used by TMDS serializer) // The TMDS serializers operate at (pixel_clock_freq * 10), // but we use DDR mode, hence (pixel_clock_freq * 5). ); // The parameters of the PLL, // They are found by using: ecppll -i 25 -o <5*pixel_clock> -f foobar.v `ifdef MODE_640x480 localparam CLKI_DIV = 1; localparam CLKOP_DIV = 5; localparam CLKOP_CPHASE = 2; localparam CLKOP_FPHASE = 0; localparam CLKFB_DIV = 5; `endif `ifdef MODE_800x600 localparam CLKI_DIV = 1; localparam CLKOP_DIV = 3; localparam CLKOP_CPHASE = 1; localparam CLKOP_FPHASE = 0; localparam CLKFB_DIV = 8; `endif `ifdef MODE_1024x768 localparam CLKI_DIV = 1; localparam CLKOP_DIV = 2; localparam CLKOP_CPHASE = 1; localparam CLKOP_FPHASE = 0; localparam CLKFB_DIV = 13; `endif `ifdef MODE_1280x1024 localparam CLKI_DIV = 3; localparam CLKOP_DIV = 1; localparam CLKOP_CPHASE = 0; localparam CLKOP_FPHASE = 0; localparam CLKFB_DIV = 65; `endif // The PLL converts a 25 MHz clock into a (pixel_clock_freq * 5) clock // The (half) TMDS serializer clock is generated on pin CLKOP. // In addition, the pixel clock (at TMDS freq/5) is generated on // pin CLKOS (hence CLKOS_DIV = 5*CLKOP_DIV). (* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) EHXPLLL #( .CLKI_DIV(CLKI_DIV), .CLKOP_DIV(CLKOP_DIV), .CLKOP_CPHASE(CLKOP_CPHASE), .CLKOP_FPHASE(CLKOP_FPHASE), .CLKOS_ENABLE("ENABLED"), .CLKOS_DIV(5*CLKOP_DIV), .CLKOS_CPHASE(CLKOP_CPHASE), .CLKOS_FPHASE(CLKOP_FPHASE), .CLKFB_DIV(CLKFB_DIV) ) pll_i ( .CLKI(pclk), .CLKOP(pixel_clk_x5), .CLKFB(pixel_clk_x5), .CLKOS(pixel_clk), .PHASESEL0(1'b0), .PHASESEL1(1'b0), .PHASEDIR(1'b1), .PHASESTEP(1'b1), .PHASELOADREG(1'b1), .PLLWAKESYNC(1'b0), .ENCLKOP(1'b0) ); endmodule `endif `endif