Created
January 25, 2021 22:57
-
-
Save goran-mahovlic/083e5223038b593d9143db4b191613ff to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`timescale 1ns / 1ps | |
////////////////////////////////////////////////////////////////////////////////// | |
// Company: | |
// Engineer: | |
// | |
// Create Date: 06.01.2021 12:44:12 | |
// Design Name: | |
// Module Name: top | |
// Project Name: | |
// Target Devices: | |
// Tool Versions: | |
// Description: | |
// | |
// Dependencies: | |
// | |
// Revision: | |
// Revision 0.01 - File Created | |
// Additional Comments: | |
// | |
////////////////////////////////////////////////////////////////////////////////// | |
module HDMI_Top( | |
input CLK_IN, | |
output [2:0] TMDS_data_p, | |
output [2:0] TMDS_data_n, | |
output TMDS_clk_p, TMDS_clk_n, | |
output led | |
); | |
wire pixclk; // 25 MHz | |
wire clk_TMDS; // 250 MHz | |
reg [31:0] cnt = 0; | |
clk_wiz_0 clk_wiz ( | |
.clk_in1(CLK_IN), | |
.reset(1'b0), | |
.clk_out1(pixclk), | |
.clk_out2(clk_TMDS) | |
// .clk_out3(clk_pix_5x_180) | |
); | |
//////////////////////////////////////////////////////////////////////// | |
reg [9:0] CounterX, CounterY; | |
reg hSync, vSync, DrawArea; | |
always @(posedge pixclk) DrawArea <= (CounterX<640) && (CounterY<480); | |
always @(posedge pixclk) CounterX <= (CounterX==799) ? 0 : CounterX+1; | |
always @(posedge pixclk) if(CounterX==799) CounterY <= (CounterY==524) ? 0 : CounterY+1; | |
always @(posedge pixclk) hSync <= (CounterX>=656) && (CounterX<752); | |
always @(posedge pixclk) vSync <= (CounterY>=490) && (CounterY<492); | |
//////////////// | |
wire [7:0] W = {8{CounterX[7:0]==CounterY[7:0]}}; | |
wire [7:0] A = {8{CounterX[7:5]==3'h2 && CounterY[7:5]==3'h2}}; | |
reg [7:0] red, green, blue; | |
always @(posedge pixclk) red <= ({CounterX[5:0] & {6{CounterY[4:3]==~CounterX[4:3]}}, 2'b00} | W) & ~A; | |
always @(posedge pixclk) green <= (CounterX[7:0] & {8{CounterY[6]}} | W) & ~A; | |
always @(posedge pixclk) blue <= CounterY[7:0] | W | A; | |
//////////////////////////////////////////////////////////////////////// | |
wire [9:0] TMDS_red, TMDS_green, TMDS_blue; | |
TMDS_encoder encode_R(.clk(pixclk), .VD(red ), .CD(2'b00) , .VDE(DrawArea), .TMDS(TMDS_red)); | |
TMDS_encoder encode_G(.clk(pixclk), .VD(green), .CD(2'b00) , .VDE(DrawArea), .TMDS(TMDS_green)); | |
TMDS_encoder encode_B(.clk(pixclk), .VD(blue ), .CD({vSync,hSync}), .VDE(DrawArea), .TMDS(TMDS_blue)); | |
//////////////////////////////////////////////////////////////////////// | |
reg [3:0] TMDS_mod10=0; // modulus 10 counter | |
reg [9:0] TMDS_shift_red=0, TMDS_shift_green=0, TMDS_shift_blue=0; | |
reg TMDS_shift_load=0; | |
always @(posedge clk_TMDS) TMDS_shift_load <= (TMDS_mod10==4'd9); | |
always @(posedge clk_TMDS) | |
begin | |
TMDS_shift_red <= TMDS_shift_load ? TMDS_red : TMDS_shift_red [9:1]; | |
TMDS_shift_green <= TMDS_shift_load ? TMDS_green : TMDS_shift_green[9:1]; | |
TMDS_shift_blue <= TMDS_shift_load ? TMDS_blue : TMDS_shift_blue [9:1]; | |
TMDS_mod10 <= (TMDS_mod10==4'd9) ? 4'd0 : TMDS_mod10+4'd1; | |
cnt <= cnt + 1; | |
end | |
assign led = cnt[26]; | |
OBUFDS OBUFDS_red (.I(TMDS_shift_red [0]), .O(TMDS_data_p[2]), .OB(TMDS_data_n[2])); | |
OBUFDS OBUFDS_green(.I(TMDS_shift_green[0]), .O(TMDS_data_p[1]), .OB(TMDS_data_n[1])); | |
OBUFDS OBUFDS_blue (.I(TMDS_shift_blue [0]), .O(TMDS_data_p[0]), .OB(TMDS_data_n[0])); | |
OBUFDS OBUFDS_clock(.I(pixclk), .O(TMDS_clk_p), .OB(TMDS_clk_n)); | |
endmodule | |
//////////////////////////////////////////////////////////////////////// | |
module TMDS_encoder( | |
input clk, | |
input [7:0] VD, // video data (red, green or blue) | |
input [1:0] CD, // control data | |
input VDE, // video data enable, to choose between CD (when VDE=0) and VD (when VDE=1) | |
output reg [9:0] TMDS = 0 | |
); | |
wire [3:0] Nb1s = VD[0] + VD[1] + VD[2] + VD[3] + VD[4] + VD[5] + VD[6] + VD[7]; | |
wire XNOR = (Nb1s>4'd4) || (Nb1s==4'd4 && VD[0]==1'b0); | |
wire [8:0] q_m = {~XNOR, q_m[6:0] ^ VD[7:1] ^ {7{XNOR}}, VD[0]}; | |
reg [3:0] balance_acc = 0; | |
wire [3:0] balance = q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7] - 4'd4; | |
wire balance_sign_eq = (balance[3] == balance_acc[3]); | |
wire invert_q_m = (balance==0 || balance_acc==0) ? ~q_m[8] : balance_sign_eq; | |
wire [3:0] balance_acc_inc = balance - ({q_m[8] ^ ~balance_sign_eq} & ~(balance==0 || balance_acc==0)); | |
wire [3:0] balance_acc_new = invert_q_m ? balance_acc-balance_acc_inc : balance_acc+balance_acc_inc; | |
wire [9:0] TMDS_data = {invert_q_m, q_m[8], q_m[7:0] ^ {8{invert_q_m}}}; | |
wire [9:0] TMDS_code = CD[1] ? (CD[0] ? 10'b1010101011 : 10'b0101010100) : (CD[0] ? 10'b0010101011 : 10'b1101010100); | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment