HDMI协议常见用的有v1.4 v2.0 v2.1等版本,后两个版本基于v1.4版本发展而来,要想深入学习HDMI协议,从v1.4版本开始更容易上手。关于HDMI v1.4的协议内容,网上已经有很多前辈作了详细介绍,例如博主“芒果木有籽”的这篇“HDMI 1.4 协议详解”就讲解的很细致。但毕竟在一篇或者几篇博文中想要把一个协议没有遗漏的展现出来是非常困难的。更详细的协议内容协议详见《High-Definition Multimedia Interface Specification Version 1.4》协议手册。
HDMI v1.4接口FPGA软件v1.0版本(后简称HDMI模块)为前期功能验证版本,仅需实现用多种常见分辨率点亮显示器的功能并输出渐变灰度彩条。因此,HDMI模块需要实现以下功能:
根据功能需求可知,HDMI模块需要实现视频时序生成及TMDS编码等功能;因此HDMI模块可以大致划分为下文描述的几个模块。
视频时序生成模块,该模块主要根据不同分辨率产生行场同步信号及测试用的灰度渐变彩条数据信号,是HDMI模块的测试数据源。
数据组帧模块,将视频数据及行场同步信号分别打包为数据帧、控制帧等。
TMDS编码模块,该模块对数据帧、控制帧、消息帧进行编码,将数据统一编码为10BIT数据。
并转串模块,该模块实现物理层数据串行转换发送的功能。
HDMI模块FPGA软件代码方案框图如图 3-1所示。
图 3-1 HDMI模块方案框图
其中tmds_phy模块通过ISERDES原语实现TMDS编码数据的10:1并转串功能,并用ODDR原语将单端信号转换为差分信号。tmds_encode模块对输入数据进行编码,根据hdmi协议对控制帧采用传输最大化编码;对消息帧采用TREC4编码,对数据帧采用传输最小化编码。tmds_remap模块将视频数据、行场同步信号、消息数据等按对应格式进行组帧,该模块还预留了在深色模式下对像素时钟和TMDS时钟的同步处理。pixel_timing_gen模块根据分辨率参数产生行场同步信号及视频测试数据。
如图 3-1所示。HDMI模块共使用了三个时钟:pixel_clock,tmds_clock,phy_clock。pixel_clock是像素时钟,与显示分辨率有关系,各种显示分辨率与时钟的关系可在文档《A DTV Profile for Uncompressed High Speed Digital Interfaces》(协议CEA-861-D)中查阅。tmds_clock是tmds时钟,与颜色深度有关,在24bit模式下tmds_clock 等于pixel_clock,在其他颜色深度模式下则不等于,详情请查阅HDMI v1.4协议。phy_clock为串行数据时钟,其与tmds时钟的比例为5:1(phy_clock:tmds_clock)。目前时钟频率仅支持修改IP核参数的方式修改。
HDMI模块采用异步低电平复位的方式,复位信号有效电平宽度不能低于2个像素时钟周期,保证能够被正确采样。
无。
搭建如图 5-1所示仿真平台对模块代码进行功能仿真,HDMI_tx_demo使用的是开发板提供的DEMO文件。时钟复位产生模块生成仿真需要的时钟复位激励信号。
图 5-1功能仿真方案框图
通过功能仿真对比HDMI模块与HDMI_tx_demo两个模块的输出串行数据,两者结果一致。
采用器件型号为XC7A100T-2IFGG484的开发板进行烧写验证,能够成功点亮显示屏。切换不同分辨率均能正常点亮,目前已测试1280x720@60Hz与1024x768@60Hz两种分辨率。
测试结果如图 5-2所示。
图 5-2测试结果示意图
HDMI模块代码满足功能需求。
// +FHDR============================================================================/
// Author : Administrator
// Creat Time : 2023/01/14 14:00:25
// File Name : hdmi_tx_phy.v
// Module Ver : Vx.x
//
//
// All Rights Reserved
//
// ---------------------------------------------------------------------------------/
//
// Modification History:
// V1.0 initial
//
// -FHDR============================================================================/
//
// hdmi_tx_phy
// |---
//
`timescale 1ns/1ps
module hdmi_tx_phy #
(
parameter U_DLY = 1 //
)
(
// ---------------------------------------------------------------------------------
// CLock & Reset
// ---------------------------------------------------------------------------------
input clk_line ,
input clk_tdms ,
input rst_n ,
// ---------------------------------------------------------------------------------
// Phy Data
// ---------------------------------------------------------------------------------
input [9:0] phy_clk ,
input [29:0] phy_data ,
// ---------------------------------------------------------------------------------
// HMDI
// ---------------------------------------------------------------------------------
output hdmi_clk_p ,
output hdmi_clk_n ,
output [2:0] hdmi_data_p ,
output [2:0] hdmi_data_n
);
wire cshifth ;
wire cshiftl ;
wire [2:0] dshifth ;
wire [2:0] dshiftl ;
wire hdmi_clk ;
wire [2:0] hdmi_data ;
genvar i ;
OSERDESE2 #
(
.DATA_RATE_OQ ("DDR" ), // DDR, SDR
.DATA_RATE_TQ ("SDR" ), // DDR, BUF, SDR
.DATA_WIDTH (10 ), // Parallel data width (2-8,10,14)
.INIT_OQ (1'b0 ), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ (1'b0 ), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE ("MASTER" ), // MASTER, SLAVE
.SRVAL_OQ (1'b0 ), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ (1'b0 ), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL ("FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ("FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH (1 ) // 3-state converter width (1 4)
)
u0_OSERDESE2
(
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (hdmi_clk ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK (clk_line ), // 1-bit input: High speed clock
.CLKDIV (clk_tdms ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (phy_clk[0] ),
.D2 (phy_clk[1] ),
.D3 (phy_clk[2] ),
.D4 (phy_clk[3] ),
.D5 (phy_clk[4] ),
.D6 (phy_clk[5] ),
.D7 (phy_clk[6] ),
.D8 (phy_clk[7] ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (!rst_n ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (cshifth ),
.SHIFTIN2 (cshiftl ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 (1'b0 ),
.T2 (1'b0 ),
.T3 (1'b0 ),
.T4 (1'b0 ),
.TBYTEIN (1'b0 ), // 1-bit input: Byte group tristate
.TCE (1'b0 ) // 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)
.INIT_OQ (1'b0 ), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ (1'b0 ), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE ("SLAVE" ), // MASTER, SLAVE
.SRVAL_OQ (1'b0 ), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ (1'b0 ), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL ("FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ("FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH (1 ) // 3-state converter width (1 4)
)
u1_OSERDESE2
(
.OFB ( ), // 1-bit output: Feedback path for data
.OQ ( ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 (cshifth ),
.SHIFTOUT2 (cshiftl ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( a ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK (clk_line ), // 1-bit input: High speed clock
.CLKDIV (clk_tdms ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (1'b0 ),
.D2 (1'b0 ),
.D3 (phy_clk[8] ),
.D4 (phy_clk[9] ),
.D5 (1'b0 ),
.D6 (1'b0 ),
.D7 (1'b0 ),
.D8 (1'b0 ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (!rst_n ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( ),
.SHIFTIN2 ( ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 (1'b0 ),
.T2 (1'b0 ),
.T3 (1'b0 ),
.T4 (1'b0 ),
.TBYTEIN (1'b0 ), // 1-bit input: Byte group tristate
.TCE (1'b0 ) // 1-bit input: 3-state clock enable
);
OBUFDS #
(
.SLEW ("FAST" ) // Specify the output slew rate
)
u0_OBUFDS
(
.I (hdmi_clk ), // Buffer input
.O (hdmi_clk_p ), // Diff_p output (connect directly to top-level port)
.OB (hdmi_clk_n ) // Diff_n output (connect directly to top-level port)
);
generate
for(i=0;i<3;i=i+1)
begin:phy_data_loop
OSERDESE2 #
(
.DATA_RATE_OQ ("DDR" ), // DDR, SDR
.DATA_RATE_TQ ("SDR" ), // DDR, BUF, SDR
.DATA_WIDTH (10 ), // Parallel data width (2-8,10,14)
.INIT_OQ (1'b0 ), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ (1'b0 ), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE ("MASTER" ), // MASTER, SLAVE
.SRVAL_OQ (1'b0 ), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ (1'b0 ), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL ("FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ("FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH (1 ) // 3-state converter width (1 4)
)
u2_OSERDESE2
(
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (hdmi_data[i] ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK (clk_line ), // 1-bit input: High speed clock
.CLKDIV (clk_tdms ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (phy_data[i*10+0] ),
.D2 (phy_data[i*10+1] ),
.D3 (phy_data[i*10+2] ),
.D4 (phy_data[i*10+3] ),
.D5 (phy_data[i*10+4] ),
.D6 (phy_data[i*10+5] ),
.D7 (phy_data[i*10+6] ),
.D8 (phy_data[i*10+7] ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (!rst_n ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (dshifth[i] ),
.SHIFTIN2 (dshiftl[i] ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 (1'b0 ),
.T2 (1'b0 ),
.T3 (1'b0 ),
.T4 (1'b0 ),
.TBYTEIN (1'b0 ), // 1-bit input: Byte group tristate
.TCE (1'b0 ) // 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)
.INIT_OQ (1'b0 ), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ (1'b0 ), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE ("SLAVE" ), // MASTER, SLAVE
.SRVAL_OQ (1'b0 ), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ (1'b0 ), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL ("FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ("FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH (1 ) // 3-state converter width (1 4)
)
u3_OSERDESE2
(
.OFB ( ), // 1-bit output: Feedback path for data
.OQ ( ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 (dshifth[i] ),
.SHIFTOUT2 (dshiftl[i] ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK (clk_line ), // 1-bit input: High speed clock
.CLKDIV (clk_tdms ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (1'b0 ),
.D2 (1'b0 ),
.D3 (phy_data[i*10+8] ),
.D4 (phy_data[i*10+9] ),
.D5 (1'b0 ),
.D6 (1'b0 ),
.D7 (1'b0 ),
.D8 (1'b0 ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (!rst_n ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( ),
.SHIFTIN2 ( ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 (1'b0 ),
.T2 (1'b0 ),
.T3 (1'b0 ),
.T4 (1'b0 ),
.TBYTEIN (1'b0 ), // 1-bit input: Byte group tristate
.TCE (1'b0 ) // 1-bit input: 3-state clock enable
);
OBUFDS #
(
.SLEW ("FAST" ) // Specify the output slew rate
)
u1_OBUFDS
(
.I (hdmi_data[i] ), // Buffer input
.O (hdmi_data_p[i] ), // Diff_p output (connect directly to top-level port)
.OB (hdmi_data_n[i] ) // Diff_n output (connect directly to top-level port)
);
end
endgenerate
endmodule
// +FHDR============================================================================/
// Author : Administrator
// Creat Time : 2023/01/14 14:35:48
// File Name : hdmi_tx_encode.v
// Module Ver : Vx.x
//
//
// All Rights Reserved
//
// ---------------------------------------------------------------------------------/
//
// Modification History:
// V1.0 initial
//
// -FHDR============================================================================/
//
// hdmi_tx_encode
// |---
//
`timescale 1ns/1ps
module hdmi_tx_encode #
(
parameter U_DLY = 1 //
)
(
// ---------------------------------------------------------------------------------
// CLock & Reset
// ---------------------------------------------------------------------------------
input clk_tdms ,
input rst_n ,
// ---------------------------------------------------------------------------------
// Vedio & Commond Data
// ---------------------------------------------------------------------------------
// tdms_cmd[15:0] :
// bit15~12 --> data type: 4'b4 -> data island period
// 4'b5 -> data island period LGB
// 4'b6 -> data island period TGB
// 4'b8 -> data period
// 4'b9 -> data period LGB
// 4'bc -> control period
//
// bit11~8 --> same as bit 7~4
//
// bit7~4 --> When data island period,packet data
// When control period,bit4~3 -> preamble
// bit7~6 -> rsv.
// bit3~2 --> Packet header(data island period only),bit2(header),bit1(first 1'b0,others 1'b1)
// bit1~0 --> Video synchronization signal,bit1(VSYNC),bit0(HSYNC).
input [15:0] tdms_cmd ,
input [23:0] tdms_data ,
// ---------------------------------------------------------------------------------
// Phy Data
// ---------------------------------------------------------------------------------
output [9:0] phy_clk ,
output reg [29:0] phy_data
);
reg [47:0] tdms_cmd_dly ;
wire [11:0] cmd_ctrl ;
wire [11:0] cmd_island ;
wire [1:0] cmd_gb ;
reg cmd_video ;
wire [3:0] cmd_mux ;
reg [29:0] max_code_data ;
reg [29:0] phy_data_ctrl ;
reg [29:0] terc4_code_data ;
reg [29:0] phy_data_island ;
reg [29:0] ctrllgb_code_data ;
reg [29:0] phy_data_island_gb ;
wire [11:0] cnt_num_d1s ;
reg [26:0] q_m ;
reg [26:0] q_m_reg ;
reg [11:0] cnt_num_qm1s ;
reg [11:0] cnt_num_qm0s ;
reg [14:0] cnt_delta ;
reg [29:0] phy_data_video ;
wire [29:0] phy_data_video_gb ;
genvar i ;
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
tdms_cmd_dly <= #U_DLY 48'd0;
else
tdms_cmd_dly <= #U_DLY {tdms_cmd_dly[31:0],tdms_cmd};
end
assign cmd_ctrl = tdms_cmd_dly[0*16+:12];
assign cmd_island = tdms_cmd_dly[0*16+:12];
assign cmd_gb = tdms_cmd_dly[0*16+:2];
assign cmd_mux = tdms_cmd_dly[47:44];
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
cmd_video <= #U_DLY 1'b0;
else
begin
if(tdms_cmd[15:12] == 4'b1000)
cmd_video <= #U_DLY 1'b1;
else
cmd_video <= #U_DLY 1'b0;
end
end
// Control data encode
generate
for(i=0;i<3;i=i+1)
begin: control_encode_loop
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
max_code_data[i*10+:10] <= #U_DLY 10'd0;
else
case(cmd_ctrl[i*4+:2])
2'b00 : max_code_data[i*10+:10] <= #U_DLY 10'b11_0101_0100;
2'b01 : max_code_data[i*10+:10] <= #U_DLY 10'b00_1010_1011;
2'b10 : max_code_data[i*10+:10] <= #U_DLY 10'b01_0101_0100;
2'b11 : max_code_data[i*10+:10] <= #U_DLY 10'b10_1010_1011;
endcase
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
phy_data_ctrl[i*10+:10] <= #U_DLY 10'd0;
else
phy_data_ctrl[i*10+:10] <= #U_DLY max_code_data[i*10+:10];
end
end
endgenerate
// Island data encode
generate
for(i=0;i<3;i=i+1)
begin: island_encode_loop
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
terc4_code_data[i*10+:10] <= #U_DLY 10'd0;
else
case(cmd_island[i*4+:4])
4'b0000 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1001_1100;
4'b0001 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_0110_0011;
4'b0010 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1110_0100;
4'b0011 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1110_0010;
4'b0100 : terc4_code_data[i*10+:10] <= #U_DLY 10'b01_0111_0001;
4'b0101 : terc4_code_data[i*10+:10] <= #U_DLY 10'b01_0001_1110;
4'b0110 : terc4_code_data[i*10+:10] <= #U_DLY 10'b01_1000_1110;
4'b0111 : terc4_code_data[i*10+:10] <= #U_DLY 10'b01_0011_1100;
4'b1000 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1100_1100;
4'b1001 : terc4_code_data[i*10+:10] <= #U_DLY 10'b01_0011_1001;
4'b1010 : terc4_code_data[i*10+:10] <= #U_DLY 10'b01_1001_1100;
4'b1011 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1100_0110;
4'b1100 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1000_1110;
4'b1101 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_0111_0001;
4'b1110 : terc4_code_data[i*10+:10] <= #U_DLY 10'b01_0110_0011;
4'b1111 : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1100_0011;
default : terc4_code_data[i*10+:10] <= #U_DLY 10'b10_1001_1100;
endcase
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
phy_data_island[i*10+:10] <= #U_DLY 10'd0;
else
phy_data_island[i*10+:10] <= #U_DLY terc4_code_data[i*10+:10];
end
end
endgenerate
// Island data Guard Bands
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
ctrllgb_code_data <= #U_DLY 30'd0;
else
begin
case(cmd_gb[1:0])
2'b00 : ctrllgb_code_data[1*10+:10] <= #U_DLY 10'b10_1000_1110;
2'b01 : ctrllgb_code_data[1*10+:10] <= #U_DLY 10'b10_0111_0001;
2'b10 : ctrllgb_code_data[1*10+:10] <= #U_DLY 10'b01_0110_0011;
2'b11 : ctrllgb_code_data[1*10+:10] <= #U_DLY 10'b10_1100_0011;
default : ctrllgb_code_data[1*10+:10] <= #U_DLY 10'b10_1000_1110;
endcase
ctrllgb_code_data[1*10+:10] <= #U_DLY 10'b01_0011_0011;
ctrllgb_code_data[2*10+:10] <= #U_DLY 10'b01_0011_0011;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
phy_data_island_gb <= #U_DLY 30'd0;
else
phy_data_island_gb <= #U_DLY ctrllgb_code_data;
end
// Video data encode
generate
for(i=0;i<3;i=i+1)
begin: video_encode_loop
assign cnt_num_d1s[i*4+:4] = tdms_data[i*8+0] + tdms_data[i*8+1] + tdms_data[i*8+2] + tdms_data[i*8+3]
+ tdms_data[i*8+4] + tdms_data[i*8+5] + tdms_data[i*8+6] + tdms_data[i*8+7];
always @ (*)
begin
if((cnt_num_d1s[i*4+:4] > 4'd4) || ({cnt_num_d1s[i*4+:4],tdms_data[i*8+0]} == 5'b0_1000))
begin
q_m[i*9+0] = tdms_data[i*8+0];
q_m[i*9+1] = tdms_data[i*8+0] ^~ tdms_data[i*8+1];
q_m[i*9+2] = tdms_data[i*8+0] ^~ tdms_data[i*8+1] ^~ tdms_data[i*8+2];
q_m[i*9+3] = tdms_data[i*8+0] ^~ tdms_data[i*8+1] ^~ tdms_data[i*8+2] ^~ tdms_data[i*8+3];
q_m[i*9+4] = tdms_data[i*8+0] ^~ tdms_data[i*8+1] ^~ tdms_data[i*8+2]
^~ tdms_data[i*8+3] ^~ tdms_data[i*8+4];
q_m[i*9+5] = tdms_data[i*8+0] ^~ tdms_data[i*8+1] ^~ tdms_data[i*8+2]
^~ tdms_data[i*8+3] ^~ tdms_data[i*8+4] ^~ tdms_data[i*8+5];
q_m[i*9+6] = tdms_data[i*8+0] ^~ tdms_data[i*8+1] ^~ tdms_data[i*8+2] ^~ tdms_data[i*8+3]
^~ tdms_data[i*8+4] ^~ tdms_data[i*8+5] ^~ tdms_data[i*8+6];
q_m[i*9+7] = tdms_data[i*8+0] ^~ tdms_data[i*8+1] ^~ tdms_data[i*8+2] ^~ tdms_data[i*8+3]
^~ tdms_data[i*8+4] ^~ tdms_data[i*8+5] ^~ tdms_data[i*8+6] ^~ tdms_data[i*8+7];
q_m[i*9+8] = 1'b0;
end
else
begin
q_m[i*9+0] = tdms_data[i*8+0];
q_m[i*9+1] = tdms_data[i*8+0] ^ tdms_data[i*8+1];
q_m[i*9+2] = tdms_data[i*8+0] ^ tdms_data[i*8+1] ^ tdms_data[i*8+2];
q_m[i*9+3] = tdms_data[i*8+0] ^ tdms_data[i*8+1] ^ tdms_data[i*8+2] ^ tdms_data[i*8+3];
q_m[i*9+4] = tdms_data[i*8+0] ^ tdms_data[i*8+1] ^ tdms_data[i*8+2]
^ tdms_data[i*8+3] ^ tdms_data[i*8+4];
q_m[i*9+5] = tdms_data[i*8+0] ^ tdms_data[i*8+1] ^ tdms_data[i*8+2]
^ tdms_data[i*8+3] ^ tdms_data[i*8+4] ^ tdms_data[i*8+5];
q_m[i*9+6] = tdms_data[i*8+0] ^ tdms_data[i*8+1] ^ tdms_data[i*8+2] ^ tdms_data[i*8+3]
^ tdms_data[i*8+4] ^ tdms_data[i*8+5] ^ tdms_data[i*8+6];
q_m[i*9+7] = tdms_data[i*8+0] ^ tdms_data[i*8+1] ^ tdms_data[i*8+2] ^ tdms_data[i*8+3]
^ tdms_data[i*8+4] ^ tdms_data[i*8+5] ^ tdms_data[i*8+6] ^ tdms_data[i*8+7];
q_m[i*9+8] = 1'b1;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
cnt_num_qm1s[i*4+:4] <= #U_DLY 4'd0;
cnt_num_qm0s[i*4+:4] <= #U_DLY 4'd0;
end
else
begin
cnt_num_qm1s[i*4+:4] <= #U_DLY q_m[i*9+0] + q_m[i*9+1] + q_m[i*9+2] + q_m[i*9+3]
+ q_m[i*9+4] + q_m[i*9+5] + q_m[i*9+6] + q_m[i*9+7];
cnt_num_qm0s[i*4+:4] =4'd8 - cnt_num_qm1s[i*4+:4];
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
q_m_reg[i*9+:9] <= #U_DLY 9'd0;
else
q_m_reg[i*9+:9] <= #U_DLY q_m[i*9+:9];
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
cnt_delta[i*5+:5] <= #U_DLY 5'd0;
else
begin
if(cmd_video == 1'b1)
begin
if((|cnt_delta[i*5+:5] == 1'b0) || ({cnt_num_qm1s[i*4+3],cnt_num_qm0s[i*4+3]} == 2'b11))
begin
if(q_m[i*9+8] == 1'b1)
cnt_delta[i*5+:5] <= #U_DLY cnt_delta[i*5+:5] + ({cnt_num_qm1s[i*4+3],cnt_num_qm1s[i*4+:4]}
- {cnt_num_qm0s[i*4+3],cnt_num_qm0s[i*4+:4]});
else
cnt_delta[i*5+:5] <= #U_DLY cnt_delta[i*5+:5] + ({cnt_num_qm0s[i*4+3],cnt_num_qm0s[i*4+:4]}
- {cnt_num_qm1s[i*4+3],cnt_num_qm1s[i*4+:4]});
end
else if(({cnt_delta[i*5+4],cnt_num_qm1s[i*4+3],cnt_num_qm0s[i*4+3]} == 3'b010) ||
({cnt_delta[i*5+4],cnt_num_qm1s[i*4+3],cnt_num_qm0s[i*4+3]} == 3'b101))
cnt_delta[i*5+:5] <= #U_DLY cnt_delta[i*5+:5] + {3'd0,q_m[i*9+8],1'b0}
+ ({cnt_num_qm0s[i*4+3],cnt_num_qm0s[i*4+:4]}
- {cnt_num_qm1s[i*4+3],cnt_num_qm1s[i*4+:4]});
else
cnt_delta[i*5+:5] <= #U_DLY cnt_delta[i*5+:5] - {3'd0,~q_m[i*9+8],1'b0}
+ ({cnt_num_qm1s[i*4+3],cnt_num_qm1s[i*4+:4]}
- {cnt_num_qm0s[i*4+3],cnt_num_qm0s[i*4+:4]});
end
else
;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
phy_data_video[i*10+:10] <= #U_DLY 10'd0;
else
begin
if((|cnt_delta[i*5+:5] == 1'b0) || ({cnt_num_qm1s[i*4+3],cnt_num_qm0s[i*4+3]} == 2'b11))
begin
phy_data_video[i*10+9] <= #U_DLY ~q_m_reg[i*9+8];
phy_data_video[i*10+8] <= #U_DLY q_m_reg[i*9+8];
phy_data_video[i*10+:8] <= #U_DLY q_m_reg[i*9+8] ? q_m_reg[i*9+:8] : ~q_m_reg[i*9+:8];
end
else if(({cnt_delta[i*5+4],cnt_num_qm1s[i*4+3],cnt_num_qm0s[i*4+3]} == 3'b010) ||
({cnt_delta[i*5+4],cnt_num_qm1s[i*4+3],cnt_num_qm0s[i*4+3]} == 3'b101))
begin
phy_data_video[i*10+9] <= #U_DLY 1'b1;
phy_data_video[i*10+8] <= #U_DLY q_m_reg[i*9+8];
phy_data_video[i*10+:8] <= #U_DLY ~q_m_reg[i*9+:8];
end
else
begin
phy_data_video[i*10+9] <= #U_DLY 1'b0;
phy_data_video[i*10+8] <= #U_DLY q_m_reg[i*9+8];
phy_data_video[i*10+:8] <= #U_DLY q_m_reg[i*9+:8];
end
end
end
end
endgenerate
assign phy_data_video_gb[0*10+:10] = 10'b10_1100_1100;
assign phy_data_video_gb[1*10+:10] = 10'b01_0011_0011;
assign phy_data_video_gb[2*10+:10] = 10'b10_1100_1100;
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
phy_data <= #U_DLY 30'd0;
else
case(cmd_mux)
4'h4 : phy_data <= #U_DLY phy_data_island;
4'h5 : phy_data <= #U_DLY phy_data_island_gb;
4'h6 : phy_data <= #U_DLY phy_data_island_gb;
4'h8 : phy_data <= #U_DLY phy_data_video;
4'h9 : phy_data <= #U_DLY phy_data_video_gb;
4'hc : phy_data <= #U_DLY phy_data_ctrl;
default : phy_data <= #U_DLY phy_data_ctrl;
endcase
end
assign phy_clk = (cmd_mux[3] == 1'b1) ? 10'b11_1110_0000 : 10'd0;
endmodule
// +FHDR============================================================================/
// Author : Administrator
// Creat Time : 2023/01/23 15:13:04
// File Name : hdmi_tx_tdms_remap.v
// Module Ver : Vx.x
//
//
// All Rights Reserved
//
// ---------------------------------------------------------------------------------/
//
// Modification History:
// V1.0 initial
//
// -FHDR============================================================================/
//
// hdmi_tx_tdms_remap
// |---
//
`timescale 1ns/1ps
module hdmi_tx_tdms_remap #
(
parameter U_DLY = 1 //
)
(
// ---------------------------------------------------------------------------------
// CLock & Reset
// ---------------------------------------------------------------------------------
input clk_pixel ,
input clk_tdms ,
input rst_n ,
// ---------------------------------------------------------------------------------
// Pixel & Info Data
// ---------------------------------------------------------------------------------
// pixel_en [2:0] (unused)
// bit2 --> rsv // video data valid
// bit1 --> rsv // info valid
// bit0 --> cmd valid
// pixel_cmd [7:0]
// bit7~6 --> deep color mode.2'd0(8bit),2'd1(10bit),2'd2(12bit),2'd3(16bit)
// bit5 --> Island period first flag.
// bit4 --> Control period first flag.
// bit3 --> Guard Band first flag.
// bit2 --> Video pixel group first fragment flag.
// bit1~0 --> Video synchronization signal,bit1(VSYNC),bit0(HSYNC).
//
// pixel_info[15:0]
// bit15~12 --> same as tdms_cmd[15:12]
// bit11~2 --> same as tdms_cmd[11:2]
// bit1~0 --> rsv.
//
// pixel_data[47:0]
// RGB444 or YCrCb444 mode
// bit47~32 --> B or Cb,same as R
// bit31~16 --> G or Cr,same as R
// bit15~0 --> R or Y
// 8 bit mode -> bit15~8,rsv
// -> bit 7~0,R data,
// 10 bit mode -> bit15~10,rsv
// -> bit 9~0,R data,
// 12 bit mode -> bit15~12,rsv
// -> bit11~0,R data
// YCrCb422 mode
// bit47~40 --> rsv.
// bit39~32 --> Cb or Cr[11:4]pixel_data
// bit31~24 --> rsv.
// bit23~16 --> Y[11:4].
// bit15~8 --> rsv
// bit7~4 --> Cb or Cr[3:0]
// bit3~0 --> Y[3:0]
input [2:0] pixel_en ,
input [7:0] pixel_cmd ,
input [15:0] pixel_info ,
input [47:0] pixel_data ,
// ---------------------------------------------------------------------------------
// Vedio & Commond Data
// ---------------------------------------------------------------------------------
// tdms_cmd[15:0] :
// bit15~12 --> data type: 4'h4 -> data island period
// 4'h5 -> data island period LGB
// 4'h6 -> data island period TGB
// 4'h8 -> data period
// 4'h9 -> data period LGB
// 4'hc -> control period(preamble)
// bit11~8 --> same as bit 7~4,preamble(c3,c2)
//
// bit7~4 --> When data island period,packet data
// When control period,bit5~4 -> preamble(c1,c0)
// bit7~6 -> rsv.
// bit3~2 --> Packet header(data island period only),bit2(header),bit1(first 1'b0,others 1'b1)
// bit1~0 --> Video synchronization signal,bit1(VSYNC),bit0(HSYNC).
output reg [15:0] tdms_cmd ,
output reg [23:0] tdms_data
);
reg [1:0] wrstp_data ;
reg [1:0] wrstp_cnt ;
reg dfifo_wr_en_tmp ;
reg [3*40-1:0] dfifo_wr_data_d8 ;
reg [3*40-1:0] dfifo_wr_data_d10 ;
reg [3*40-1:0] dfifo_wr_data_d12 ;
reg [3*40-1:0] dfifo_wr_data_d16 ;
reg dfifo_wr_en ;
// dfifo_wr_data[i*40+:40]
// --> 8bit mode : bit3rdistp_data <= #U_DLY 5'd0;9~8,rsv
// bit7~0,1 pixel video data
// --> 10bit mode : bit39~0,4 pixel video data
// --> 12bit mode : bit39~24,rsv
// bit23~0,2 pixel video data
// --> 16bit mode : bit39~16,rsv
// bit15~0,1 pixel video data
reg [3*40-1:0] dfifo_wr_data ;
reg rdcstp_en ;
reg [2:0] rdcstp_data ;
reg [2:0] rdcbufen_data ;
reg [2:0] rdcstp_cnt ;
reg cfifo_rd_en ;
// cfifo_rd_data[7:0]
// bit7~0 --> Same as tdms_cmd [15:0]
wire [7:0] cfifo_rd_data ;
wire cfifo_empty ;
reg cfifo_empty_tmp ;
reg [1:0] hvsync_data ;
reg rdistp_en ;
reg [4:0] rdistp_data ;
reg [4:0] rdistp_cnt ;
wire ififo_rd_en ;
// ififo_rd_data[15:0]
// bit15~0 --> Same as pixel_info [15:0]
wire [15:0] ififo_rd_data ;
reg rddstp_en ;
reg [2:0] rddstp_cnt ;
reg dfifo_rd_en ;
wire [3*64-1:0] dfifo_rd_data ;
wire [2:0] dfifo_empty ;
reg [23:0] tdms_data_tmp ;
genvar i ;
// pixel video data frame.
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
wrstp_data <= #U_DLY 2'd0;
else
case(pixel_cmd[7:6])
2'd0 : wrstp_data <= #U_DLY 2'd0;
2'd1 : wrstp_data <= #U_DLY 2'd3;
2'd2 : wrstp_data <= #U_DLY 2'd1;
2'd3 : wrstp_data <= #U_DLY 2'd0;
default : wrstp_data <= #U_DLY 2'd0;
endcase
end
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
wrstp_cnt <= #U_DLY 2'd0;
else
begin
if((pixel_cmd[2] == 1'b1) && (wrstp_cnt < wrstp_data))
wrstp_cnt <= #U_DLY wrstp_cnt + 2'd1;
else
wrstp_cnt <= #U_DLY 2'd0;
end
end
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
dfifo_wr_en_tmp <= #U_DLY 1'd0;
else
begin
if((pixel_cmd[2] == 1'b1) && (wrstp_cnt >= wrstp_data))
dfifo_wr_en_tmp <= #U_DLY 1'd1;
else
dfifo_wr_en_tmp <= #U_DLY 1'd0;
end
end
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
dfifo_wr_en <= #U_DLY 1'd0;
else
begin
if(dfifo_wr_en_tmp == 1'b1)
dfifo_wr_en <= #U_DLY 1'd1;
else
dfifo_wr_en <= #U_DLY 1'd0;
end
end
generate
for(i=0;i<3;i=i+1)
begin:video_remap_loop
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
dfifo_wr_data_d8[i*40+:40] <= #U_DLY 40'd0;
else
case(wrstp_cnt)
2'd0 : dfifo_wr_data_d8[(i*40+0*8)+:8] <= #U_DLY pixel_data[i*16+:8];
2'd1 : dfifo_wr_data_d8[(i*40+1*8)+:8] <= #U_DLY pixel_data[i*16+:8];
2'd2 : dfifo_wr_data_d8[(i*40+2*8)+:8] <= #U_DLY pixel_data[i*16+:8];
2'd3 : dfifo_wr_data_d8[(i*40+3*8)+:8] <= #U_DLY pixel_data[i*16+:8];
default : ;
endcase
end
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
dfifo_wr_data_d10[i*40+:40] <= #U_DLY 40'd0;
else
case(wrstp_cnt)
2'd0 : dfifo_wr_data_d10[(i*40+0*10)+:10] <= #U_DLY pixel_data[i*16+:10];
2'd1 : dfifo_wr_data_d10[(i*40+1*10)+:10] <= #U_DLY pixel_data[i*16+:10];
2'd2 : dfifo_wr_data_d10[(i*40+2*10)+:10] <= #U_DLY pixel_data[i*16+:10];
2'd3 : dfifo_wr_data_d10[(i*40+3*10)+:10] <= #U_DLY pixel_data[i*16+:10];
default : ;
endcase
end
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
dfifo_wr_data_d12[i*40+:40] <= #U_DLY 40'd0;
else
case(wrstp_cnt[0])
1'd0 : dfifo_wr_data_d12[(i*40+0*12)+:12] <= #U_DLY pixel_data[i*16+:12];
1'd1 : dfifo_wr_data_d12[(i*40+1*12)+:12] <= #U_DLY pixel_data[i*16+:12];
default : ;
endcase
end
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
dfifo_wr_data_d16[i*40+:40] <= #U_DLY 40'd0;
else
case(wrstp_cnt[0])
1'd0 : dfifo_wr_data_d16[(i*40+0*16)+:16] <= #U_DLY pixel_data[i*16+:16];
1'd1 : dfifo_wr_data_d16[(i*40+1*16)+:16] <= #U_DLY pixel_data[i*16+:16];
default : ;
endcase
end
always @ (posedge clk_pixel or negedge rst_n)
begin
if(rst_n == 1'b0)
dfifo_wr_data[i*40+:40] <= #U_DLY 40'd0;
else
case(pixel_cmd[7:6])
2'd0 : dfifo_wr_data[i*40+:40] <= #U_DLY dfifo_wr_data_d8[i*40+:40];
2'd1 : dfifo_wr_data[i*40+:40] <= #U_DLY dfifo_wr_data_d10[i*40+:40];
2'd2 : dfifo_wr_data[i*40+:40] <= #U_DLY dfifo_wr_data_d12[i*40+:40];
2'd3 : dfifo_wr_data[i*40+:40] <= #U_DLY dfifo_wr_data_d16[i*40+:40];
default : ;
endcase
end
end
endgenerate
// Tdms fragment
//always @ (posedge clk_tdms or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// cfifo_empty_tmp <= #U_DLY 1'd0;
// else
// cfifo_empty_tmp <= #U_DLY cfifo_empty;
//end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rdcstp_en <= #U_DLY 1'b0;
else
begin
if(cfifo_empty == 1'b0)
rdcstp_en <= #U_DLY 1'b1;
else
rdcstp_en <= #U_DLY 2'b0;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rdcstp_data <= #U_DLY 3'd0;
else
case(cfifo_rd_data[7:6])
2'd0 : rdcstp_data <= #U_DLY 3'd0;
2'd1 : rdcstp_data <= #U_DLY 3'd4;
2'd2 : rdcstp_data <= #U_DLY 3'd2;
2'd3 : rdcstp_data <= #U_DLY 3'd1;
default : rdcstp_data <= #U_DLY 3'd0;
endcase
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rdcbufen_data <= #U_DLY 3'd0;
else
case(cfifo_rd_data[7:6])
2'd0 : rdcbufen_data <= #U_DLY 3'd0;
2'd1 : rdcbufen_data <= #U_DLY 3'd3;
2'd2 : rdcbufen_data <= #U_DLY 3'd1;
2'd3 : rdcbufen_data <= #U_DLY 3'd0;
default : rdcbufen_data <= #U_DLY 3'd0;
endcase
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rdcstp_cnt <= #U_DLY 3'd0;
else
begin
if((rdcstp_en == 1'b1) &&(rdcstp_cnt < rdcstp_data))
rdcstp_cnt <= #U_DLY rdcstp_cnt +3'd1;
else
rdcstp_cnt <= #U_DLY 3'd0;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
cfifo_rd_en <= #U_DLY 1'b0;
else
begin
if((rdcstp_en == 1'b1) &&(rdcstp_cnt <= rdcbufen_data))
cfifo_rd_en <= #U_DLY 1'b1;
else
cfifo_rd_en <= #U_DLY 1'b0;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
hvsync_data <= #U_DLY 2'd0;
else
if(cfifo_rd_en == 1'b1)
hvsync_data <= #U_DLY cfifo_rd_data[1:0];
else
;
end
// Get island or control data
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rdistp_en <= #U_DLY 1'b0;
else
begin
if({cfifo_rd_en,|cfifo_rd_data[5:3]} == 2'b11)
rdistp_en <= #U_DLY 1'b1;
else if(rdistp_cnt >= rdistp_data)
rdistp_en <= #U_DLY 1'b0;
else
;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rdistp_data <= #U_DLY 5'd0;
else
case({cfifo_rd_en,cfifo_rd_data[5:3]})
4'b1001 : rdistp_data <= #U_DLY 5'd1;
4'b1010 : rdistp_data <= #U_DLY 5'd7;
4'b1100 : rdistp_data <= #U_DLY 5'd31;
default : ;
endcase
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rdistp_cnt <= #U_DLY 5'd0;
else
begin
if((rdistp_en == 1'b1) && (rdistp_cnt < rdistp_data))
rdistp_cnt <= #U_DLY rdistp_cnt + 5'd1;
else
rdistp_cnt <= #U_DLY 5'd0;
end
end
assign ififo_rd_en = rdistp_en;
// Get pixel data
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rddstp_en <= #U_DLY 1'b0;
else
begin
if({cfifo_rd_en,cfifo_rd_data[2]} == 2'b11)
rddstp_en <= #U_DLY 1'b1;
else if(rddstp_cnt >= rdcstp_data)
rddstp_en <= #U_DLY 1'b0;
else
;
end
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
rddstp_cnt <= #U_DLY 3'd0;
else
begin
if((rddstp_en == 1'b1) && (rddstp_cnt < rdcstp_data))
rddstp_cnt <= #U_DLY rddstp_cnt + 3'd1;
else
rddstp_cnt <= #U_DLY 3'd0;
end
end
always @ (*)
begin
if((rddstp_en == 1'b1) && (rddstp_cnt == rdcstp_data))
dfifo_rd_en = 1'b1;
else
dfifo_rd_en = 1'b0;
end
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
tdms_cmd <= #U_DLY 16'd0;
else
case({cfifo_rd_en,ififo_rd_en,dfifo_rd_en})
3'b100 : tdms_cmd <= #U_DLY {4'hc,10'd0,hvsync_data};
3'b101 : tdms_cmd <= #U_DLY {4'h8,12'd0};
3'b110 : tdms_cmd <= #U_DLY {ififo_rd_data[15:2],hvsync_data};
default : tdms_cmd <= #U_DLY {4'hc,12'd0};
endcase
end
generate
for(i=0;i<3;i=i+1)
begin:video_getd_loop
always @ (posedge clk_tdms or negedge rst_n)
begin
if(rst_n == 1'b0)
tdms_data[i*8+:8] <= #U_DLY 8'd0;
else
tdms_data[i*8+:8] <= #U_DLY dfifo_rd_data[(i*64+rddstp_cnt*8)+:8];
end
end
endgenerate
//always @ (posedge clk_tdms or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// tdms_data <= #U_DLY 24'd0;
// else
// tdms_data <= #U_DLY tdms_data_tmp;
//end
fifo_d512w8_fwft u0_cfifo
(
.wr_clk (clk_pixel ), // input wire wr_clk
.rd_clk (clk_tdms ), // input wire rd_clk
.rst (!rst_n ), // input wire rst
.wr_en (pixel_en[0] ), // input wire wr_en
.din (pixel_cmd[7:0] ), // input wire [7 : 0] din
.rd_en (cfifo_rd_en ), // input wire rd_en
.dout (cfifo_rd_data[7:0] ), // output wire [7 : 0] dout
.prog_full_thresh (9'd500 ), // input wire [8 : 0] prog_full_thresh
.prog_full ( ), // output wire prog_full
.full ( ), // output wire full
.empty (cfifo_empty ), // output wire empty
.almost_empty ( ), // output wire almost_empty
.wr_rst_busy ( ), // output wire wr_rst_busy
.rd_rst_busy ( ) // output wire rd_rst_busy
);
fifo_d512w16_fwft u0_ififo
(
.wr_clk (clk_pixel ), // input wire wr_clk
.rd_clk (clk_tdms ), // input wire rd_clk
.rst (!rst_n ), // input wire rst
.wr_en (|pixel_cmd[4:3] ), // input wire wr_en
.din (pixel_info[15:0] ), // input wire [15 : 0] din
.rd_en (ififo_rd_en ), // input wire rd_en
.dout (ififo_rd_data[15:0] ), // output wire [15 : 0] dout
.prog_full_thresh (9'd500 ), // input wire [8 : 0] prog_full_thresh
.prog_full ( ), // output wire prog_full
.full ( ), // output wire full
.empty ( ), // output wire empty
.almost_empty ( ), // output wire almost_empty
.wr_rst_busy ( ), // output wire wr_rst_busy
.rd_rst_busy ( ) // output wire rd_rst_busy
);
generate
for(i=0;i<3;i=i+1)
begin:video_buf_loop
fifo_d512w40_fwft u0_dfifo
(
.wr_clk (clk_pixel ), // input wire wr_clk
.rd_clk (clk_tdms ), // input wire rd_clk
.rst (!rst_n ), // input wire rst
.wr_en (dfifo_wr_en ), // input wire wr_en
.din (dfifo_wr_data[i*40+:40] ), // input wire [239 : 0] din
.rd_en (dfifo_rd_en ), // input wire rd_en
.dout (dfifo_rd_data[i*64+:40] ), // output wire [239 : 0] dout
.prog_full_thresh (9'd500 ), // input wire [8 : 0] prog_full_thresh
.prog_full ( ), // output wire prog_full
.full ( ), // output wire full
.empty (dfifo_empty[i] ), // output wire empty
.almost_empty ( ), // output wire almost_empty
.wr_rst_busy ( ), // output wire wr_rst_busy
.rd_rst_busy ( ) // output wire rd_rst_busy
);
assign dfifo_rd_data[(i*64+40)+:24] = 24'd0;
end
endgenerate
endmodule
// +FHDR============================================================================/
// Author : Administrator
// Creat Time : 2023/02/18 14:14:07
// File Name : hdmi_tx_hvgen.v
// Module Ver : Vx.x
//
//
// All Rights Reserved
//
// ---------------------------------------------------------------------------------/
//
// Modification History:
// V1.0 initial
//
// -FHDR============================================================================/
//
// hdmi_tx_hvgen
// |---
//
// _____ _____
// | |_________________________________________| |__________
// _________________________________________ __________
// |_____| | | |_____|
// || | | |
// |<----hbb---->| | |
// |<----------------hde---------------->| |
// |<---------------------hba--------------------->|
//
// _____ _____
// | |_________________________________________| |__________
// _________________________________________ __________
// |_____| | | |_____|
// || | | |
// |<----vbb---->| | |
// |<---------------vdata--------------->| |
// |<---------------------vba--------------------->|
`timescale 1ns/1ps
module hdmi_tx_hvgen #
(
parameter HBF = 16'd40 ,
parameter HBB = 16'd260 ,
parameter HDE = 16'd1540 ,
parameter HBA = 16'd1650 ,
parameter VBF = 16'd6 ,
parameter VBB = 16'd35 ,
parameter VDE = 16'd803 ,
parameter VBA = 16'd806 ,
parameter U_DLY = 1 //
)
(
// ---------------------------------------------------------------------------------
// CLock & Reset
// ---------------------------------------------------------------------------------
input clk_sys ,
input rst_n ,
// ---------------------------------------------------------------------------------
// HV
// ---------------------------------------------------------------------------------
output reg hsync ,
output reg vsync ,
output reg hv_de ,
output reg [23:0] rgbdata ,
// ---------------------------------------------------------------------------------
// Pixel & Info Data
// ---------------------------------------------------------------------------------
// pixel_en [2:0] (unused)
// bit2 --> rsv // video data valid
// bit1 --> rsv // info valid
// bit0 --> cmd valid
// pixel_cmd [7:0]
// bit7~6 --> deep color mode.2'd0(8bit),2'd1(10bit),2'd2(12bit),2'd3(16bit)
// bit5 --> Island period first flag.
// bit4 --> Control period first flag.
// bit3 --> Guard Band first flag.
// bit2 --> Video pixel group first fragment flag.
// bit1~0 --> Video synchronization signal,bit1(VSYNC),bit0(HSYNC).
//
// pixel_info[15:0]
// bit15~12 --> same as tdms_cmd[15:12]
// bit11~2 --> same as tdms_cmd[11:2]
// bit1~0 --> rsv.
//
// pixel_data[47:0]
// RGB444 or YCrCb444 mode
// bit47~32 --> B or Cb,same as R
// bit31~16 --> G or Cr,same as R
// bit15~0 --> R or Y
// 8 bit mode -> bit15~8,rsv
// -> bit 7~0,R(h_cnt >= HBB + 16'd1) && (h_cnt < HDE + 16'd1) data,
// 10 bit mode -> bit15~10,rsv
// -> bit 9~0,R data,
// 12 bit mode -> bit15~12,rsv
// -> bit11~0,R data
// YCrCb422 mode
// bit47~40 --> rsv.
// bit39~32 --> Cb or Cr[11:4]pixel_data
// bit31~24 --> rsv.
// bit23~16 --> Y[11:4].
// bit15~8 --> rsv
// bit7~4 --> Cb or Cr[3:0]
// bit3~0 --> Y[3:0]
output reg [2:0] pixel_en ,
output reg [7:0] pixel_cmd ,
output reg [15:0] pixel_info ,
output reg [47:0] pixel_data
);
reg [7:0] stp_cnt ;
reg [15:0] h_cnt ;
reg [15:0] v_cnt ;
//reg hsync ;
//reg vsync ;
//reg hv_de ;
reg scan_en ;
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
stp_cnt <= #U_DLY 8'd0;
else
begin
if(&stp_cnt == 1'b0)
stp_cnt <= #U_DLY stp_cnt + 8'd1;
else
;
end
end
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
h_cnt <= #U_DLY 16'd0;
else
begin
if((h_cnt < HBA - 16'd1) && (stp_cnt[7] == 1'b1))
h_cnt <= #U_DLY h_cnt + 16'd1;
else
h_cnt <= #U_DLY 16'd0;
end
end
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
v_cnt <= #U_DLY 16'd0;
else
begin
if(h_cnt >= HBA - 16'd1)
begin
if(v_cnt < VBA - 16'd1)
v_cnt <= #U_DLY v_cnt + 16'd1;
else
v_cnt <= #U_DLY 16'd0;
end
else
;
end
end
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
hsync <= #U_DLY 1'b0;
else
begin
if((h_cnt < HBF) && (stp_cnt[7] == 1'b1))
hsync <= #U_DLY 1'b0;
else
hsync <= #U_DLY 1'b1;
end
end
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
vsync <= #U_DLY 1'b0;
else
begin
if((h_cnt == 16'd0) && (stp_cnt[7] == 1'b1))
begin
if(v_cnt < VBF)
vsync <= #U_DLY 1'b0;
else
vsync <= #U_DLY 1'b1;
end
else
;
end
end
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
scan_en <= #U_DLY 1'b0;
hv_de <= #U_DLY 1'b0;
end
else
begin
if(stp_cnt[7] == 1'b1)
scan_en <= #U_DLY 1'b1;
else
scan_en <= #U_DLY 1'b0;
if((v_cnt >= VBB) && (v_cnt < VDE) &&
(h_cnt >= HBB) && (h_cnt < HDE+10))
hv_de <= #U_DLY 1'b1;
else
hv_de <= #U_DLY 1'b0;
end
end
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
rgbdata <= #U_DLY 24'd0;
else
begin
if(hv_de == 1'b1)
begin
rgbdata[0*8+:8] <= #U_DLY rgbdata[0*8+:8] + 8'd1;
rgbdata[1*8+:8] <= #U_DLY rgbdata[1*8+:8] + 8'd1;
rgbdata[2*8+:8] <= #U_DLY rgbdata[2*8+:8] + 8'd1;
end
else
rgbdata <= #U_DLY 24'd0;
end
end
always @ (posedge clk_sys or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
pixel_en <= #U_DLY 3'b0;
pixel_cmd <= #U_DLY 8'd0;
pixel_info <= #U_DLY 16'd0;
pixel_data <= #U_DLY 48'd0;
end
else
begin
pixel_en <= #U_DLY {2'b0,scan_en};
pixel_cmd[7:5] <= #U_DLY 3'b0;
if((v_cnt >= VBB) && (v_cnt < VDE) &&
(h_cnt >= HBB - 16'd9) && (h_cnt < HBB - 16'd1))
pixel_cmd[4] <= #U_DLY 1'b1;
else
pixel_cmd[4] <= #U_DLY 1'b0;
if((v_cnt >= VBB) && (v_cnt < VDE) &&
(h_cnt >= HBB - 16'd1) && (h_cnt < HBB + 16'd1))
pixel_cmd[3] <= #U_DLY 1'b1;
else
pixel_cmd[3] <= #U_DLY 1'b0;
pixel_cmd[2] <= #U_DLY hv_de;
pixel_cmd[1] <= #U_DLY vsync;
pixel_cmd[0] <= #U_DLY hsync;
if((v_cnt >= VBB) && (v_cnt < VDE))
begin
if((h_cnt >= HBB - 16'd9) && (h_cnt < HBB - 16'd1))
begin
pixel_info[15:12] <= #U_DLY 4'hc;
pixel_info[11:8] <= #U_DLY 4'd0;
pixel_info[7:4] <= #U_DLY 4'd1;
pixel_info[3:0] <= #U_DLY 4'd0;
end
else if((h_cnt >= HBB - 16'd1) && (h_cnt < HBB + 16'd1))
begin
pixel_info[15:12] <= #U_DLY 4'h9;
pixel_info[11:0] <= #U_DLY 12'd0;
end
else if((h_cnt >= HBB + 16'd1) && (h_cnt < HDE + 16'd1))
begin
pixel_info[15:12] <= #U_DLY 4'h8;
pixel_info[11:0] <= #U_DLY 12'd0;
end
else
pixel_info <= #U_DLY 16'hc000;
end
else
pixel_info <= #U_DLY 16'hc000;
if((v_cnt >= VBB) && (v_cnt < VDE) &&
(h_cnt >= HBB + 16'd2) && (h_cnt < HDE + 16'd2))
begin
pixel_data[0*16+:16] <= #U_DLY pixel_data[0*16+:8] + 8'd1;
pixel_data[1*16+:16] <= #U_DLY pixel_data[0*16+:8] + 8'd1;
pixel_data[2*16+:16] <= #U_DLY pixel_data[0*16+:8] + 8'd1;
end
else
pixel_data <= #U_DLY 48'd0;
end
end
endmodule