-
-
Save marklove5102/a4c47f61d3587d6bbb604a187410dcc5 to your computer and use it in GitHub Desktop.
Zynq HDMI Output
This file contains 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: 2024/01/08 18:22:57 | |
// Design Name: | |
// Module Name: ser_10to1 | |
// Project Name: | |
// Target Devices: | |
// Tool Versions: | |
// Description: | |
// | |
// Dependencies: | |
// | |
// Revision: | |
// Revision 0.01 - File Created | |
// Additional Comments: | |
// | |
////////////////////////////////////////////////////////////////////////////////// | |
module ser_10to1( | |
input reset, | |
input clk, | |
input clk_5x, | |
input [9:0] d, | |
output out | |
); | |
wire shift1; | |
wire shift2; | |
OSERDESE2 #( | |
.DATA_RATE_OQ("DDR"), // DDR, SDR | |
.DATA_RATE_TQ("SDR"), // DDR, BUF, SDR | |
.DATA_WIDTH(10), // Parallel data width (2-8,10,14) | |
.SERDES_MODE("MASTER"), // MASTER, SLAVE | |
.TBYTE_CTL("FALSE"), // Enable tristate byte operation (FALSE, TRUE) | |
.TBYTE_SRC("FALSE"), // Tristate byte source (FALSE, TRUE) | |
.TRISTATE_WIDTH(1) | |
) | |
OSERDESE2_M ( | |
.CLK(clk_5x), // 1-bit input: High speed clock | |
.CLKDIV(clk), // 1-bit input: Divided clock | |
.OQ(out), | |
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) | |
.D1(d[0]), | |
.D2(d[1]), | |
.D3(d[2]), | |
.D4(d[3]), | |
.D5(d[4]), | |
.D6(d[5]), | |
.D7(d[6]), | |
.D8(d[7]), | |
.RST(reset), // 1-bit input: Reset | |
.SHIFTIN1(shift1), | |
.SHIFTIN2(shift2), | |
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs | |
.T1(0), | |
.T2(0), | |
.T3(0), | |
.T4(0), | |
.TBYTEIN(0), // 1-bit input: Byte group tristate | |
.TCE(0) // 1-bit input: 3-state clock enable | |
); | |
OSERDESE2 #( | |
.DATA_RATE_OQ("DDR"), // DDR, SDR | |
.DATA_RATE_TQ("SDR"), // DDR, BUF, SDR | |
.DATA_WIDTH(10), // Parallel data width (2-8,10,14) | |
.SERDES_MODE("SLAVE"), // MASTER, SLAVE | |
.TBYTE_CTL("FALSE"), // Enable tristate byte operation (FALSE, TRUE) | |
.TBYTE_SRC("FALSE"), // Tristate byte source (FALSE, TRUE) | |
.TRISTATE_WIDTH(1) | |
) | |
OSERDESE2_S ( | |
.CLK(clk_5x), // 1-bit input: High speed clock | |
.CLKDIV(clk), // 1-bit input: Divided clock | |
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) | |
.D1(0), | |
.D2(0), | |
.D3(d[8]), | |
.D4(d[9]), | |
.D5(0), | |
.D6(0), | |
.D7(0), | |
.D8(0), | |
.RST(reset), // 1-bit input: Reset | |
.SHIFTOUT1(shift1), | |
.SHIFTOUT2(shift2), | |
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs | |
.T1(0), | |
.T2(0), | |
.T3(0), | |
.T4(0), | |
.TBYTEIN(0), // 1-bit input: Byte group tristate | |
.TCE(0) // 1-bit input: 3-state clock enable | |
); | |
endmodule |
This file contains 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
// TMDS 编码 | |
module tmds_encoder( | |
input clk, | |
input resetn, | |
input [7:0] din, | |
input c0, | |
input c1, | |
input de, | |
output reg [9:0] q_out | |
); | |
localparam CTRLTOKEN0 = 10'b1101010100; | |
localparam CTRLTOKEN1 = 10'b0010101011; | |
localparam CTRLTOKEN2 = 10'b0101010100; | |
localparam CTRLTOKEN3 = 10'b1010101011; | |
reg [7:0] din_r; // 锁存输入的数据 | |
reg [1:0] de_r,c0_r,c1_r; // 锁存输入的控制信号 | |
reg [3:0] n1d,n1q_m,n0q_m; // 统计数据中的1个数,输出中间寄存器中的1和0个数. | |
reg [5:0] cnt; // 记录上一次传输时候1比0多了多少个,初始发送时会被控制信号设置为0. | |
reg [8:0] q_m_r; // 缓存中间变量 | |
wire [8:0] q_m; // 中间变量 | |
wire condition1; | |
wire condition2; | |
wire condition3; | |
//统计待编码输入数据中1的个数,最多8个1,所以位宽为4. | |
always@(posedge clk) | |
begin | |
if(!resetn) | |
begin | |
n1d <= 4'd0; | |
end | |
else if(de) | |
begin | |
n1d <= din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7]; | |
end | |
else begin // DE为低时候传输的是控制字符,硬编码的,没有统计必要. | |
n1d <= 4'd0; | |
end | |
end | |
// 前面统计数据时候打了一拍,这里也要打一拍来同步. | |
always@(posedge clk)begin | |
din_r <= din; | |
de_r <= {de_r[0],de}; | |
c0_r <= {c0_r[0],c0}; | |
c1_r <= {c1_r[0],c1}; | |
q_m_r <= q_m; | |
end | |
//判断条件1:输入数据1的个数多余4或者1的个数等于4并且最低位为0时拉高,其余时间拉低. | |
assign condition1 = ((n1d > 4'd4) || ((n1d == 4'd4) && (~din_r[0]))); | |
//对输入的信号进行XOR/XNOR运算. | |
assign q_m[0] = din_r[0]; | |
assign q_m[1] = condition1 ? ~((q_m[0] ^ din_r[1])) : (q_m[0] ^ din_r[1]); | |
assign q_m[2] = condition1 ? ~((q_m[1] ^ din_r[2])) : (q_m[1] ^ din_r[2]); | |
assign q_m[3] = condition1 ? ~((q_m[2] ^ din_r[3])) : (q_m[2] ^ din_r[3]); | |
assign q_m[4] = condition1 ? ~((q_m[3] ^ din_r[4])) : (q_m[3] ^ din_r[4]); | |
assign q_m[5] = condition1 ? ~((q_m[4] ^ din_r[5])) : (q_m[4] ^ din_r[5]); | |
assign q_m[6] = condition1 ? ~((q_m[5] ^ din_r[6])) : (q_m[5] ^ din_r[6]); | |
assign q_m[7] = condition1 ? ~((q_m[6] ^ din_r[7])) : (q_m[6] ^ din_r[7]); | |
assign q_m[8] = ~condition1; | |
always@(posedge clk) | |
begin | |
if(!resetn) | |
begin | |
n1q_m <= 4'd0; | |
n0q_m <= 4'd0; | |
end | |
else if(de_r[0])begin // 实际DE有效时统计,否则就是前面说的硬编码的. | |
n1q_m <= q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]; | |
n0q_m <= 4'd8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]); | |
end | |
else begin//输入数据无效时清零。 | |
n1q_m <= 4'd0; | |
n0q_m <= 4'd0; | |
end | |
end | |
//判断条件2:一行已编码数据(上一次传输会更新Cnt)中1的个数等于0的个数或者本次编码数据中1的个数等于0的个数. | |
assign condition2 = ((cnt == 6'd0) || (n1q_m == n0q_m)); | |
//判断条件3:已编码数据中1的多余0并且本次编码中间数据1的个数也多与0的个数或者已编码数据中0的个数较多并且此次编码中0的个数也比较多时拉高,其余时间拉低,为什么判断bit5,因为对于我们看,他就是符号位. | |
assign condition3 = (((~cnt[5]) && (n1q_m > n0q_m)) || (cnt[5] && (n1q_m < n0q_m))); | |
always@(posedge clk) | |
begin | |
if(!resetn) | |
begin | |
cnt <= 6'd0; | |
q_out <= 10'd0; | |
end | |
else if(de_r[1]) //又打了一拍之后,de_r[1]就是原来的de. | |
begin | |
q_out[8] <= q_m_r[8]; //第8位为编码方式位,直接输出即可. | |
if(condition2) | |
begin | |
q_out[9] <= ~q_m_r[8]; | |
q_out[7:0] <= q_m_r[8] ? q_m_r[7:0] : ~q_m_r[7:0]; | |
// 按照规范更新Cnt. | |
cnt <= q_m_r[8] ? (cnt + n1q_m - n0q_m) : (cnt + n0q_m - n1q_m); | |
end | |
else if(condition3) | |
begin | |
q_out[9] <= 1'b1; | |
q_out[7:0] <= ~q_m_r[7:0]; | |
// 按照规范更新Cnt. | |
cnt <= cnt + {q_m_r[8],1'b0} + n0q_m - n1q_m; | |
end | |
else | |
begin | |
q_out[9] <= 1'b0; | |
q_out[7:0] <= q_m_r[7:0]; | |
// 按照规范更新Cnt. | |
cnt <= cnt - {~q_m_r[8],1'b0} + n1q_m - n0q_m; | |
end | |
end | |
else | |
begin | |
// DE = 0时,需要设置Cnt = 0. | |
cnt <= 6'd0; | |
case ({c1_r[1],c0_r[1]}) | |
2'b00 : q_out <= CTRLTOKEN0; | |
2'b01 : q_out <= CTRLTOKEN1; | |
2'b10 : q_out <= CTRLTOKEN2; | |
2'b11 : q_out <= CTRLTOKEN3; | |
endcase | |
end | |
end | |
endmodule |
This file contains 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: 2024/01/08 14:37:31 | |
// Design Name: | |
// Module Name: top | |
// Project Name: | |
// Target Devices: | |
// Tool Versions: | |
// Description: | |
// | |
// Dependencies: | |
// | |
// Revision: | |
// Revision 0.01 - File Created | |
// Additional Comments: | |
// | |
////////////////////////////////////////////////////////////////////////////////// | |
module top( | |
input clk, | |
input resetn, | |
output tmds_clk_p, | |
output tmds_clk_n, | |
output [2:0] tmds_data_p, | |
output [2:0] tmds_data_n | |
); | |
wire hs; | |
wire vs; | |
wire de; | |
wire [11:0] active_x; | |
wire [11:0] active_y; | |
wire [9:0] tmds_blue; | |
wire [9:0] tmds_green; | |
wire [9:0] tmds_red; | |
wire clk_pclk; | |
wire clk_pclk_5x; | |
wire clk_locked; | |
wire [2:0] tmds_data; | |
wire tmds_clk; | |
wire reset0_n = resetn & clk_locked; | |
reg [24:0] color; | |
// Color Gen | |
always @(posedge clk_pclk) | |
begin | |
if(active_x < 300 && active_y < 300) | |
color <= 24'h0000ff; | |
else if(active_x < 600 && active_y < 600) | |
color <= 24'h00ff00; | |
else if(active_x < 1000 && active_y < 1000) | |
color <= 24'hff0000; | |
else | |
color <= color; | |
end | |
clk_wiz_0 clk_wiz_inst( | |
.clk_out1(clk_pclk), | |
.clk_out2(clk_pclk_5x), | |
.reset(~resetn), | |
.locked(clk_locked), | |
.clk_in1(clk) | |
); | |
tmds_encoder tmds_encoder_blue( | |
.clk(clk_pclk), | |
.resetn(reset0_n), | |
.din(color[7:0]), | |
.c0(hs), | |
.c1(vs), | |
.de(de), | |
.q_out(tmds_blue) | |
); | |
tmds_encoder tmds_encoder_green( | |
.clk(clk_pclk), | |
.resetn(reset0_n), | |
.din(color[15:8]), | |
.c0(0), | |
.c1(0), | |
.de(de), | |
.q_out(tmds_green) | |
); | |
tmds_encoder tmds_encoder_red( | |
.clk(clk_pclk), | |
.resetn(reset0_n), | |
.din(color[23:16]), | |
.c0(0), | |
.c1(0), | |
.de(de), | |
.q_out(tmds_red) | |
); | |
// VGA ʱ������ | |
vga_timing vga_timing_inst( | |
.clk(clk_pclk), | |
.resetn(reset0_n), | |
.hs(hs), | |
.vs(vs), | |
.de(de), | |
.active_x(active_x), | |
.active_y(active_y) | |
); | |
ser_10to1 ser_blue( | |
.reset(!reset0_n), | |
.clk(clk_pclk), | |
.clk_5x(clk_pclk_5x), | |
.d(tmds_blue), | |
.out(tmds_data[0]) | |
); | |
ser_10to1 ser_green( | |
.reset(!reset0_n), | |
.clk(clk_pclk), | |
.clk_5x(clk_pclk_5x), | |
.d(tmds_green), | |
.out(tmds_data[1]) | |
); | |
ser_10to1 ser_red( | |
.reset(!reset0_n), | |
.clk(clk_pclk), | |
.clk_5x(clk_pclk_5x), | |
.d(tmds_red), | |
.out(tmds_data[2]) | |
); | |
ser_10to1 ser_clk( | |
.reset(!reset0_n), | |
.clk(clk_pclk), | |
.clk_5x(clk_pclk_5x), | |
.d(10'b1111100000), | |
.out(tmds_clk) | |
); | |
OBUFDS #( | |
.IOSTANDARD("TMDS_33") | |
) tmds_diff_0 ( | |
.O(tmds_data_p[0]), // Diff_p output (connect directly to top-level port) | |
.OB(tmds_data_n[0]), // Diff_n output (connect directly to top-level port) | |
.I(tmds_data[0]) // Buffer input | |
); | |
OBUFDS #( | |
.IOSTANDARD("TMDS_33") | |
) tmds_diff_1 ( | |
.O(tmds_data_p[1]), // Diff_p output (connect directly to top-level port) | |
.OB(tmds_data_n[1]), // Diff_n output (connect directly to top-level port) | |
.I(tmds_data[1]) // Buffer input | |
); | |
OBUFDS #( | |
.IOSTANDARD("TMDS_33") | |
) tmds_diff_2 ( | |
.O(tmds_data_p[2]), // Diff_p output (connect directly to top-level port) | |
.OB(tmds_data_n[2]), // Diff_n output (connect directly to top-level port) | |
.I(tmds_data[2]) // Buffer input | |
); | |
OBUFDS #( | |
.IOSTANDARD("TMDS_33") | |
) tmds_diff_clk ( | |
.O(tmds_clk_p), // Diff_p output (connect directly to top-level port) | |
.OB(tmds_clk_n), // Diff_n output (connect directly to top-level port) | |
.I(tmds_clk) // Buffer input | |
); | |
endmodule |
This file contains 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
// VGA 时序生成 | |
module vga_timing#( | |
parameter integer H_ACTIVE = 16'd2560, | |
parameter integer H_FP = 16'd8, | |
parameter integer H_SYNC = 16'd32, | |
parameter integer H_BP = 16'd40, | |
parameter integer V_ACTIVE = 16'd1440, | |
parameter integer V_FP = 16'd17, | |
parameter integer V_SYNC = 16'd8, | |
parameter integer V_BP = 16'd6 | |
)( | |
input clk, | |
input resetn, | |
output hs, | |
output vs, | |
output de, | |
output reg [11:0] active_x, // Video Position (Early 1 PCLK) | |
output reg [11:0] active_y | |
); | |
parameter integer H_TOTAL = H_ACTIVE + H_FP + H_SYNC + H_BP; | |
parameter integer V_TOTAL = V_ACTIVE + V_FP + V_SYNC + V_BP; | |
wire h_active; | |
wire v_active; | |
reg [11:0] h_cnt; | |
reg [11:0] v_cnt; | |
assign de = h_active & v_active; | |
// Horizontal Counter | |
always @ (posedge clk or negedge resetn) | |
begin | |
if(!resetn) | |
h_cnt <= 0; | |
else if(h_cnt == H_TOTAL - 1) | |
h_cnt <= 0; | |
else | |
h_cnt <= h_cnt + 1; | |
end | |
// Vertical Counter | |
always @ (posedge clk or negedge resetn) | |
begin | |
if(!resetn) | |
v_cnt <= 0; | |
else if(h_cnt == H_FP - 1) // Horizontal Sync Time | |
if(v_cnt == V_TOTAL - 1) | |
v_cnt <= 0; | |
else | |
v_cnt <= v_cnt + 1; | |
else | |
v_cnt <= v_cnt; | |
end | |
// Position Counter | |
always @ (posedge clk) | |
begin | |
if(h_active) | |
active_x <= h_cnt - H_SYNC - H_BP; | |
else | |
active_x <= 0; | |
end | |
always @ (posedge clk) | |
begin | |
if(v_active) | |
active_y <= v_cnt - V_SYNC - V_BP; | |
else | |
active_y <= active_y; | |
end | |
// Horizontal Active | |
assign h_active = ((h_cnt >= H_SYNC + H_BP) && (h_cnt < H_SYNC + H_BP + H_ACTIVE))?1'b1:1'b0; | |
// Vertical Active | |
assign v_active = ((v_cnt >= V_SYNC + V_BP) && (v_cnt < V_SYNC + V_BP + V_ACTIVE))?1'b1:1'b0; | |
// HS Generate | |
assign hs = (h_cnt > H_SYNC)?1'b0:1'b1; | |
// VS Generate | |
assign vs = (v_cnt > V_SYNC)?1'b0:1'b1; | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment