module video (
	      input	   rst_n,
	      input	   vid_clk,
	      inout [1:0]  pll_locked,

	      output [2:0] hdmi_d,
	      output	   hdmi_clk,
	      inout	   hdmi_scl,
	      inout	   hdmi_sda,
	      inout	   hdmi_hpd
	      );

   assign hdmi_scl = 1'bz;
   assign hdmi_sda = 1'bz;
   assign hdmi_hpd = 1'bz;

   //
   // 1024x768x60 with a 56 MHz pixel clock
   //
   // Htiming: 1024 48 32 80 = 1184 = 47.297 kHz
   // Vtiming:  768  4  4 12 =  788 = 60.022 Hz
   //

   localparam [10:0] xact   = 11'd1024;
   localparam [10:0] xback  = 11'd48;
   localparam [10:0] xsync  = 11'd32;
   localparam [10:0] xfront = 11'd80;

   localparam [ 9:0] yact   = 10'd768;
   localparam [ 9:0] yback  = 10'd4;
   localparam [ 9:0] ysync  = 10'd4;
   localparam [ 9:0] yfront = 10'd12;

   reg [10:0]	    x;
   reg [ 9:0]	    y;

   reg [7:0]	    r;
   reg [7:0]	    g;
   reg [7:0]	    b;
   reg		    hblank;
   reg		    hsync;
   reg		    vblank;
   reg		    vsync;

   wire [7:0]	    pixbar = { x[6:0], 1'b0 } ^ {8{y[9]}};

   always @(posedge vid_clk or negedge rst_n)
     if (~rst_n)
       begin
	  x      <= 11'b0;
	  y      <= 10'b0;
	  r      <= 8'b0;
	  g      <= 8'b0;
	  b      <= 8'b0;

	  hblank <= 1'b0;
	  hsync  <= 1'b0;
	  vblank <= 1'b0;
	  vsync  <= 1'b0;
       end
     else
       begin
	  r <= pixbar & {8{x[9]}};
	  g <= pixbar & {8{x[8]}};
	  b <= pixbar & {8{x[7]}};

	  x <= x + 1'b1;
	  if (x >= (xact+xback+xsync+xfront-1'b1))
	    begin
	       x <= 11'd0;
	       y <= y + 1'b1;
	       if (y >= (yact+yback+ysync+yfront-1'b1))
		 y <= 10'd0;
	    end

	  hblank <= x >= xact;
	  vblank <= y >= yact;

	  hsync  <= (x >= (xact+xback) && x < (xact+xback+xsync));
	  vsync  <= (y >= (yact+yback) && y < (yact+yback+ysync));

       end // else: !if(~rst_n)

   wire [7:0] hdmi_data[0:2];
   assign hdmi_data[2] = r;
   assign hdmi_data[1] = g;
   assign hdmi_data[0] = b;

   wire [1:0] hdmi_ctl[0:2];
   assign hdmi_ctl[0]      = { vsync, hsync };
   assign hdmi_ctl[1]      = 2'b00;
   assign hdmi_ctl[2]      = 2'b00;

   wire [9:0] hdmi_tmds_data[0:2]; // TMDS encoded data per channel

   generate
      genvar   i;
      for (i = 0; i < 3; i = i + 1)
	begin : hdmitmds
	   tmdsenc enc (
			.rst_n ( rst_n ),
			.clk   ( vid_clk ),
			.den   ( ~hblank & ~vblank ),
			.d     ( hdmi_data[i] ),
			.ten   ( 1'b0 ), // TERC data not supported yet
			.t     ( 4'bx ),
			.c     ( hdmi_ctl[i] ),
			.q     ( hdmi_tmds_data[i] )
			);
	end
   endgenerate

   assign hdmi_scl = 1'bz;
   assign hdmi_sda = 1'bz;
   assign hdmi_hpd = 1'bz;

   //
   // The ALTLVDS_TX megafunctions is MSB-first in channel-major
   // order, but TMDS is LSB first. Thus, bit-reverse the data within
   // each channel.
   //
   wire [39:0] hdmi_to_tx;	// TMDS data in the order hdmitx expects

   transpose #(.words( 4 ),
	       .bits( 10 ),
	       .reverse_b ( 1'b1 ),
	       .reverse_w ( 1'b0 ),
	       .transpose ( 1'b0 ),
	       .reg_d ( 1'b0 ),
	       .reg_q ( 1'b0 )
	       ) hdmitranspose
     (
      .clk ( vid_clk ),
      .d ( { 10'b00000_11111, hdmi_tmds_data[2],
	     hdmi_tmds_data[1], hdmi_tmds_data[0] } ),
      .q ( hdmi_to_tx )
      );

   wire        vid_hdmiclk;

   hdmitx hdmitx (
		  .pll_areset ( ~pll_locked[0] ),
		  .tx_in ( hdmi_to_tx ),
		  .tx_inclock ( vid_clk ),
		  .tx_coreclock ( vid_hdmiclk ), // Pixel clock in HDMI domain
		  .tx_locked ( pll_locked[1] ),
		  .tx_out ( { hdmi_clk, hdmi_d } ),
		  .tx_outclock ( )
		  );
endmodule // video
