dakies/OSS_Verilog huggingface dataset:
module window   
(
    input  clk,
    input  rstn,
    input  start,       // 开始标志
    input  state,                   
    input  [7:0]  din,  
    output [39:0] taps  // 一列数据
);
           
	integer i;
	// reg start_ff;
	reg [7:0] mem [0:139];
	
	//	always@(posedge clk)begin
	//		if(!rstn)
	//			start_ff <= 0;
	//		else
	//			start_ff <= start;	
	//	end
	
	// 串行存储140（28*5）个输入数据
	// 每个上升沿，由低向高移位一次
	always@(posedge clk)begin
		if(start)
			begin
			   mem[0] <= din;           
			   for(i=0;i<139;i=i+1)  
			   	  mem[i+1] <= mem[i];
			end
	end
	// state=0:28*28   state=1:12*12
	assign taps = (!state)?{mem[139],mem[111],mem[83],mem[55],mem[27]}:{mem[59],mem[47],mem[35],mem[23],mem[11]};

endmodule
module maxpooling
(
    input  clk,
    input  rstn,
    input  ivalid,      // 输入有效
    input  state,       // 0: 24*24; 1: 8*8
    input  [7:0] din,   // 像素数据 8bit
    output ovalid,      // 输出有效
    output [7:0] dout   // 输出结果 
);

	reg [7:0] data [0:23];  // 缓存一行输入数据 24 or 8
	reg [6:0] ptr;          // 地址指针 0 ~ 47
	reg cnt;                // 由于只有 1 bit，所以超过会溢出， 0：data_reg_0，1：data_reg_1
	reg [7:0] data_reg_0;   // 缓存寄存器0
	reg [7:0] data_reg_1;   // 缓存寄存器1
	reg [7:0] dout_r;       // 最终输出结果
	
	// ptr 地址指针递增
	always@(posedge clk)begin
		if(!rstn)
			ptr <= 7'b0000000;
		else
			case(state)
				1'b0:begin
					if(ptr == 7'd48-1) // 2*24 两行，从0算起，所以需要减1
						ptr <= 7'd0;
					else 
						if(!ivalid)
							ptr <= ptr;
						else
							ptr <= ptr + 7'd1;
					end
				1'b1:begin
					if(ptr == 7'd16-1) // 2*8 两行
						ptr <= 7'd0;
					else 
						if(!ivalid)
							ptr <= ptr;
						else
							ptr <= ptr + 7'd1;
					end               
			endcase
	end
	
	// cnt 计数
	// 24 -> cnt=0 、25 -> cnt=1
	// 26 -> cnt=0 、27 -> cnt=1
	// ...
	always@(posedge clk or negedge rstn)begin
	if(!rstn)
		cnt <= 0;
	else
		case(state)
			1'b0:begin
					if(ptr < 7'd25 - 1) //慢一拍
						cnt <= 0;
					else
						if(ivalid)
							cnt <= cnt + 1'b1;
						else
							cnt <= cnt;
				end
			1'b1:begin
					if(ptr <= 7'd7)
						cnt <= 0;
					else
						if(ivalid)
							cnt <= cnt + 1'b1;
						else
							cnt <= cnt;
				end
		endcase
	end
	
	// 行数据缓存
	always@(posedge clk)
	begin
		case(state)
		1'b0:begin
			if(ptr <= 7'd24 && ivalid) 
				data[ptr] <= din;
			end
		1'b1:begin
			if(ptr <= 7'd8 && ivalid) 
				data[ptr] <= din;
			end          
		endcase   
	end
	// 两行对应索引数据对比，缓存较大值
	always@(posedge clk)
	begin
		case({state,cnt}) // 这里的 cnt是触发时的值，而不是计算后的值
		2'b00:begin
			if(ptr >= 7'd24)
			begin
				if(din>data[ptr-7'd24])
					data_reg_0 <= din;
				else
					data_reg_0 <= data[ptr-7'd24];
			end
			else
				data_reg_0 <= 0;
			end
		2'b01:begin
			if(ptr >= 7'd24)
			begin
				if(din>data[ptr-7'd24])
					data_reg_1 <= din;
				else
					data_reg_1 <= data[ptr-7'd24];
			end
			else
				data_reg_1 <= 0;
			end
		2'b10:begin
			if(ptr >= 7'd9)
			begin
				if(din>data[ptr-7'd9])
					data_reg_0 <= din;
				else
					data_reg_0 <= data[ptr-7'd9];
			end
			else
				data_reg_0 <= 0;
			end
		2'b11:begin
			if(ptr >= 7'd9)
			begin
				if(din>data[ptr-7'd9])
					data_reg_1 <= din;
				else
					data_reg_1 <= data[ptr-7'd9];
			end
			else
				data_reg_1 <= 0;
			end 
		default:begin
				data_reg_1 <= 0; 
				data_reg_0 <= 0;
				end         
		endcase
	end

	// 打拍采沿
	reg cnt_d;
	always@(posedge clk)begin
		if(!rstn)
			cnt_d <= 0;
		else
			cnt_d <= cnt;
	end
	
	// cnt 为 1时，输出才是有效的，即 2*2 的kernel， cnt=1含义为第二行且为偶数位索引（从1计数）
	// 筛选输出数据
	assign ovalid = ~cnt && cnt_d; // 采样下降沿
	assign dout   = data_reg_1 > data_reg_0 ? data_reg_1 : data_reg_0;
	
endmodule
module maxpooling_tb();
	// 输入
	reg clk;
	reg rstn;
	reg ivalid;
	reg state;
	reg [7:0] din;
	
	// 输出
	wire[7:0] dout;
	wire ovalid;
	
	integer STATE = 0; // 输入图像 Size 配置 0: 24x24 1:8x8 
	reg[10:0] cnt_line; // 读取行数计数
	integer count_w,fp_i;// 文件指针
	
	reg [7:0] pool_result_tb [0:150]; //用于缓存池化计算结果 12x12=144
	reg [10:0] cnt_pool; // 缓存的卷积计算结果计数
	
	// maxpooling module
	maxpooling u_maxpooling(
	.clk(clk),
	.rstn(rstn),
	.ivalid(ivalid),
	.state(state),
	.din(din),
	.dout(dout),
	.ovalid(ovalid)
	);
	
	// 初始信号赋值-maxpooling module
	initial
	begin
		clk = 0;
		rstn = 0; // 复位
		cnt_line = 0; //行数清零
		cnt_pool = 0; //计数清零
		state = STATE;
		ivalid = 0; 
		din = 0;
		# 20; // 一周期后填充数据，即 ivalid = 1前数据就要准备好
		rstn = 1;
		ivalid = 1; // input valid
	end
	
	// 读取图片数据
	initial
	begin
		fp_i = $fopen("C:/Users/Administrator/Desktop/pic/24/0.txt","r"); // 数字 0  (1)输入数据路径
	end
	
	
	// 读取图像数据，一共 576 行，即 576*20 = 11520 ns = 11.52 ms 读完一张24x24图片 
	// 也是池化模块的计算速度
	always@(posedge clk)
	begin
		if(ivalid == 1)// 当输入有效标志拉高时读取数据时，数据要准备好，否则数据会错位，
		begin
			count_w  <= $fscanf(fp_i,"%b" ,din);
			cnt_line <= cnt_line + 1;
			if(cnt_line == 10'd576) $display("picture read over");
			// $display("%d,%b",count_w,image_in);
		end
	end
	
	// 时钟信号 50MHz
	always #10 clk <= ~clk; 
	
//=======================最大池化计算结果打印=======================
	integer i;
	integer display_line = 0;
	always@(posedge clk)// 缓存有效卷积结果
	begin
		if(ovalid && cnt_pool<144) 
		begin
			//$display("cnt_pool: %d  ", cnt_pool); // 先输出计数，表示缓存到该地址
			// 输入:24*24 -> 输出 12x12=144
			// 输入:8*8   -> 输出 4x4=16
			pool_result_tb[cnt_pool] =  dout; 
			cnt_pool = cnt_pool + 1;
		end
	end
	// 以12x12二维矩阵形式打印卷积结果
	initial
	begin
		# (11540+20); // 等待池化完成
		
		$display("maxpooling complete");
		if(state == 0)
		begin
			for(i=0;i<144;i=i+1)
			begin 
				if(i == 0) $write("%d :", display_line);
				$write("%d ", pool_result_tb[i]); // $write 不会自动换行
				//$write("i:%d %d ", i,pool_result_tb[i]); // $write 不会自动换行
				if((i+1)%12 == 0)// 添加行号并换行,每行 12 个数据
				begin
					$display(" "); 
					display_line = display_line + 1;
					$write("%d :", display_line);
				end
			end	
		end
		else if(state == 1)
		begin
			for(i=0;i<16;i=i+1)
			begin
				$display("%d", pool_result_tb[i]);
			end	
		end
		
		$finish; // 打印完结果后完成仿真
	end
	
endmodule
module window_tb();
	// 输入
	reg clk;
	reg resetn;
	reg start_window;
	reg state;
	reg[7:0] image_in;
	// 输出
	wire[39:0] taps;
	
	// 文件指针
	integer fp_i;
	integer count_w;
	
	// 读取行数计数
	reg[10:0] cnt_line;
	
	// 滑窗模块
	window window_inst(
		.clk  (clk),
		.rstn (resetn),
		.start(start_window),
		.state(state),
		.din  (image_in),
		.taps (taps)
	);
	
	// 读取图片数据
	initial
	begin
		fp_i = $fopen("C:/Users/Administrator/Desktop/pic/1/num3_0.txt","r"); // 数字 3
	end
	// 初始信号
	initial
	begin
		cnt_line = 0;// 读取行数清零
		clk = 0;
		start_window = 0;
		state = 0;
		# 20;
		start_window = 1;
	end
	
	// 读取图像数据，一共 784 行，即 784*20 + 20 = 15700 ns = 15.7 ms 读完一张28*28图片 
	always@(posedge clk)
	begin
		begin
			count_w  <= $fscanf(fp_i,"%b" ,image_in);
			cnt_line <= cnt_line + 1;
			if(cnt_line == 11'd784) $display("picture read over");
			// $display("%d,%b",count_w,image_in);
		end
	end
	
	// 时钟信号 50MHz
	always #10 clk <= ~clk; 
endmodule
module fc_tb();
	// 输入
	reg clk;
	reg rstn;
	reg ivalid;
	reg signed [7:0] din_0;
	reg signed [7:0] din_1;
	reg signed [7:0] din_2;
	reg signed [7:0] din_3;
	reg signed [7:0] din_4;
	reg signed [7:0] din_5;
	reg signed [7:0] weight;
	reg weight_en;
	// 输出
	wire ovalid;
	wire signed [31:0]dout;
	
	reg[10:0] cnt_line; // 读取行数计数
	integer count_w,fp_i;// 文件指针
	
	integer i_fc;// 循环计数变量
	
	reg signed[31:0] fc_result_tb ; //用于缓存全连接计算结果
	reg [10:0] cnt_fc; // 缓存的全连接模块计算结果计数
	
	// fullconnect module
	fc u_fc(
		.clk(clk),
		.rstn(rstn),
		.ivalid(ivalid),
		.din_0(din_0),
		.din_1(din_1),
		.din_2(din_2),
		.din_3(din_3),
		.din_4(din_4),
		.din_5(din_5),
		.weight(weight),
		.weight_en(weight_en),
		.ovalid(ovalid),
		.dout(dout)
	);
	
	// 初始信号赋值-fullconnect module
	initial
	begin
		clk = 0;
		rstn = 0; // 复位
		cnt_line = 0; //行数清零
		cnt_fc = 0; //计数清零
		ivalid = 0; 
		din_0 = 0;
		din_1 = 0;
		din_2 = 0;
		din_3 = 0;
		din_4 = 0;
		din_5 = 0;
		weight_en = 0;
		weight = 0;
		# 20; // 一周期后填充权重数据，共需要192个时钟周期，192x20
		rstn = 1;
		weight_en = 1;
		weight = 1; // 这里权重全为1
		# (192*20);// 开始填充数据
		// 全连接模块的输入有效信号不能一直为1
		for(i_fc=0;i_fc<32;i_fc=i_fc+1)
		begin
			ivalid = 1; // input valid
			#20;
			ivalid = 0;
			#20;
		end
		
	end
	
	// 读取图片数据
	initial
	begin
		fp_i = $fopen("C:/Users/Administrator/Desktop/pic/16x12/0.txt","r"); // 数字 0  (1)输入数据路径
	end
	
	
	// 读取图像数据，一共 192 行，即 (192/6)*20 = 640 ns = 0.64 ns 读完6x4x4图片 
	// 也是全连接模块的计算速度
	always@(posedge clk)
	begin
		if(ivalid == 1)// 当输入有效标志拉高时读取数据时，数据要准备好，否则数据会错位，
		begin
			count_w  <= $fscanf(fp_i,"%b" ,din_0); // 一次读取6个数据
			count_w  <= $fscanf(fp_i,"%b" ,din_1);
			count_w  <= $fscanf(fp_i,"%b" ,din_2);
			count_w  <= $fscanf(fp_i,"%b" ,din_3);
			count_w  <= $fscanf(fp_i,"%b" ,din_4);
			count_w  <= $fscanf(fp_i,"%b" ,din_5);
			cnt_line <= cnt_line + 6;
			if(cnt_line == 9'd192) $display("picture read over");
			// $display("%d,%b",count_w,image_in);
		end
	end
	
	// 时钟信号 50MHz
	always #10 clk <= ~clk; 
	
//=======================全连接模块计算结果打印=======================
	integer i;
	integer display_line = 0;
	always@(posedge clk)// 缓存有效计算结果
	begin
		if(ovalid) 
		begin
			$display("cnt_fc: %d  ", cnt_fc); // 先输出计数，表示缓存到该地址
			fc_result_tb[cnt_fc] =  dout; 
			$display("fc_result_tb: %d  ", dout);
			cnt_fc = cnt_fc + 1;
		end
	end
	// 仿真
	initial
	begin
		# (20+192*20+32*40+5*20); // 等待全连接模块计算完成
		
		$finish; // 打印完结果后完成仿真
	end
endmodule
module window   
(
    input  clk,
    input  rstn,
    input  start,       // 开始标志
    input  state,                   
    input  [7:0]  din,  
    output [39:0] taps  // 一列数据
);
           
	integer i;
	reg [7:0] mem [0:139];
	
	// 串行存储140（28*5）个输入数据
	always@(posedge clk)begin
		if(start)
			begin
				mem[0] <= din;           
				for(i=0;i<139;i=i+1) 
					mem[i+1] <= mem[i];
			end
	end
	// state=0:28*28   state=1:12*12
	assign taps = (!state)?{mem[139],mem[111],mem[83],mem[55],mem[27]}:{mem[59],mem[47],mem[35],mem[23],mem[11]};

endmodule
module add
(
    input clk,
    input signed [31:0] din_0,
    input signed [31:0] din_1,
    input ivalid,
    output ovalid,
    output signed [31:0] dout
);

	reg [31:0] dout_r;
	reg wren;
	reg [31:0] din_0_delay;
	reg wren_delay;
	// 1周期完成计算
	always@(posedge clk)
		din_0_delay <= din_0;
	
	always@(posedge clk)
		dout_r = din_0_delay + din_1;
	
	always@(posedge clk)
	if(ivalid)
		wren <= 1'b1;
	else
		wren <= 1'b0;
	
	always@(posedge clk)
		wren_delay <= wren;
	
	assign ovalid = wren_delay;
	assign dout = dout_r;

endmodule
module maxpooling
(
    input  clk,
    input  rstn,
    input  ivalid,      // ???????,?????
    input  state,       // 0: ???24*24; 1: 8*8
    input  [7:0] din,   // ???? 8bit
    output ovalid,      // ???????
    output [7:0] dout   // ???? 
);

	reg [7:0] data [0:23];  // ??????,????? 24 or 8
	reg [6:0] ptr;
	reg cnt;                //??0?¡À??¡À????¨¢????data_reg_0,??1?¡À??¡À????¨¢????data_reg_1
	reg [7:0] data_reg_0;
	reg [7:0] data_reg_1;
	reg [7:0] dout_r;
	reg wren;

	// ????
	reg [7:0] din_delay;
	always@(posedge clk)
	if(!rstn)
		din_delay <= 0;
	else
		din_delay <= din;
	// ????????,??2?
	always@(posedge clk)begin
		if(!rstn)
			ptr <= 7'b0000000;
		else
			case(state)
				1'b0:begin
					if(ptr == 7'd48)
						ptr <= 7'd0;
					else 
						if(!ivalid)
							ptr <= ptr;
						else
							ptr <= ptr + 7'd1;
					end
				1'b1:begin
					if(ptr == 7'd16)
						ptr <= 7'd0;
					else 
						if(!ivalid)
							ptr <= ptr;
						else
							ptr <= ptr + 7'd1;
					end               
			endcase
	end
	
	// ???,?????????
	always@(posedge clk or negedge rstn)begin
	if(!rstn)
		cnt <= 0;
	else
		case(state)
			1'b0:begin
					if(ptr <= 7'd23)
						cnt <= 0;
					else
						if(ivalid)
							cnt <= cnt + 1'b1;
						else
							cnt <= cnt;
				end
			1'b1:begin
					if(ptr <= 7'd7)
						cnt <= 0;
					else
						if(ivalid)
							cnt <= cnt + 1'b1;
						else
							cnt <= cnt;
				end
		endcase
	end
	// ??????
	always@(posedge clk)
	begin
		case(state)
		1'b0:begin
			if(ptr <= 7'd24 && ivalid)
				data[ptr-1] <= din_delay;
			end
		1'b1:begin
			if(ptr <= 7'd8 && ivalid) 
				data[ptr-1] <= din;
			end          
		endcase   
	end
	// ????????????????,?????
	always@(*)
	begin
		case({state,cnt})
		2'b00:begin
			if(ptr >= 7'd25)
			begin
				if(din_delay>data[ptr-7'd25])
					data_reg_1 <= din_delay;
				else
					data_reg_1 <= data[ptr-7'd25];
			end
			else
				data_reg_1 <= 0;
			end
		2'b01:begin
			if(ptr >= 7'd25)
			begin
				if(din_delay>data[ptr-7'd25])
					data_reg_0 <= din_delay;
				else
					data_reg_0 <= data[ptr-7'd25];
			end
			else
				data_reg_0 <= 0;
			end
		2'b10:begin
			if(ptr >= 7'd9)
			begin
				if(din>data[ptr-7'd9])
					data_reg_1 <= din;
				else
					data_reg_1 <= data[ptr-7'd9];
			end
			else
				data_reg_1 <= 0;
			end
		2'b11:begin
			if(ptr >= 7'd9)
			begin
				if(din>data[ptr-7'd9])
					data_reg_0 <= din;
				else
					data_reg_0 <= data[ptr-7'd9];
			end
			else
				data_reg_0 <= 0;
			end 
		default:begin
				data_reg_0 <= 0; 
				data_reg_1 <= 0;
				end         
		endcase
	end
	
	// ??????
	always@(posedge clk)begin
		wren <= cnt;
	end

	// reg0 ? reg1 ??,?????
	always@(posedge clk)begin
		if(data_reg_0 > data_reg_1)
			dout_r <= data_reg_0;
		else
			dout_r <= data_reg_1;
	end
	
	assign ovalid = wren; // ????
	assign dout   = dout_r; // ???(????)
	
endmodule
module FIFO_fmap
( 	
    input  clk,
	input  rstn,
	input  [7:0] din,
	input  wr_en,
	input  rd_en,
	input  rd_rst,
	output empty,
	output full,
	output [7:0] dout
);
	reg [7:0] rd_ptr, wr_ptr;
	reg [7:0] mem [0:149];// 深度为 150
	reg [7:0] dout_r;
	integer i;
	
	assign empty = (wr_ptr == rd_ptr);
	assign full  = ((wr_ptr - rd_ptr) == 8'd150);
	
	// 延迟一拍
	reg wr_en_delay;
	always@(posedge clk)begin
		if(!rstn)
			wr_en_delay <= 0;
		else
			wr_en_delay <= wr_en;
	end
	// 读操作
	always @(posedge clk or negedge rstn)begin
		if(!rstn)
			dout_r <= 0;
		else if(rd_en && !empty)
			dout_r <= mem[rd_ptr];
	end
	// 写操作
	always @(posedge clk) 
	begin
	if(rstn && wr_en_delay && !full)
		mem[wr_ptr] <= din;
	end
	
	// 写指针递增	
	always @(posedge clk or negedge rstn) 
	begin
		if(!rstn) 
			wr_ptr <= 0;
		else if(!full && wr_en_delay)// 非满且写使能
			wr_ptr <= wr_ptr + 1;
	end
	
	// 读指针递增
	always @(posedge clk or negedge rstn) 
	begin
		if(!rstn)
			rd_ptr <= 0;
		else
			if(rd_rst)	
				rd_ptr <= 0;
			else if(!empty && rd_en)// 非空且读使能
				rd_ptr <= rd_ptr + 1;
		end
	
	assign dout = dout_r;

endmodule
module relu
(
    input clk,
    input signed [31:0] din,  
    input ivalid,
    input state,
    output reg ovalid,   
    output reg signed [7:0] dout
);

	reg wren;
	reg [31:0] dout_r;
	reg [31:0] dout_delay;
	
	// ????,?????
	always@(posedge clk)begin
		if(ivalid)
			wren <= 1'b1;
		else
			wren <= 1'b0;
	end

	// ?????,?0????
	always@(posedge clk)begin
		if(din[31])
			dout_r <= 0;
		else
			dout_r <= din;
	end
	// ????
	always@(posedge clk)begin
		dout_delay <= dout_r;
	end
	
	/*    
	assign dout = (state)?(dout_delay >>> 10):(dout_r >>> 10);
	assign ovalid = wren;
	*/
	always@(posedge clk)begin
		if(state)
			dout <= (dout_delay >>> 10);
		else
			dout <= (dout_r >>> 10); 
	end
	
	always@(posedge clk)begin
		ovalid <= wren;
	end
	
endmodule
module  scrambler_reset_inserter( 
            input         clk,
            input  [71:0] in_data,
            output reg [71:0] out_data
        );

reg [8:0] bs_count;
reg       substitue_next;

localparam [8:0] BS = 9'b110111100;  // K28.5 0x1BC
localparam [8:0] SR = 9'b100011100;  // K28.0 0x11C

initial begin
    bs_count       = 9'b0;
    substitue_next = 1'b0;
    out_data       = 72'b0;
end

always @(posedge clk) begin
    //----------------------------------------------
    // Subsitute every 512nd Blank start (BS) symbol
    // with a Scrambler Reset (SR) symbol. 
    //----------------------------------------------
    out_data  <= in_data;

    if(substitue_next == 1'b1) begin
        if(in_data[8:0]   == BS) begin
            out_data[8:0]   <= SR;
        end

        if(in_data[26:18] == BS) begin
            out_data[26:18] <= SR;
        end

        if(in_data[44:36] == BS) begin
            out_data[44:36] <= SR;
        end

        if(in_data[62:54] == BS) begin
            out_data[62:54] <= SR;
        end
    end

    if(in_data[8:0] == BS) begin
    	if(bs_count == 1'b0) begin
            substitue_next <= 1'b1;
    	end else begin
            substitue_next <= 1'b0;
    	end
    	bs_count <= bs_count + 1;
    end
end

endmodule
module  main_stream_processing (
		input         symbol_clk,
        input         tx_link_established,
        input         source_ready,
        input         tx_clock_train,
        input         tx_align_train,
        input  [72:0] in_data,
        output [79:0] tx_symbols
  );

wire [71:0] signal_data;
wire [71:0] sr_inserted_data;
wire [71:0] scrambled_data;
wire [79:0] before_skew;
wire [79:0] final_data;
 
localparam [7:0] delay_index = 8'b11100100;

/////////////////////////////////////////////////////////
// Flick between the idle pattern and a valid data stream
// at the time when the in_data's high bit is set
/////////////////////////////////////////////////////////
idle_pattern_inserter i_idle_pattern_inserter( 
		.clk              (symbol_clk),
		.channel_ready    (tx_link_established),
		.source_ready     (source_ready),
		
		.in_data          (in_data),
		.out_data         (signal_data)
    );

/////////////////////////////////////////////////////////
// Change the 512th Blank Start (BS) symbol into a 
// Scrambler Reset (SR) symbol
/////////////////////////////////////////////////////////
scrambler_reset_inserter i_scrambler_reset_inserter( 
		.clk       (symbol_clk),
		.in_data   (signal_data),
		.out_data  (sr_inserted_data)
	);

/////////////////////////////////////////////////////////
// Now scramble the data stream - only scrambles the data
// symbols, the K symbols go through unscrambled.
/////////////////////////////////////////////////////////
scrambler_all_channels i_scrambler( 
		.clk        (symbol_clk),
		.bypass0    (1'b0),
		.bypass1    (1'b0),
		.in_data    (sr_inserted_data),
		.out_data   (scrambled_data)
	);

/////////////////////////////////////////////////////////
// This allows the controller to send the two training 
// patterns, allowing the link drive levels to be set up
/////////////////////////////////////////////////////////
insert_training_pattern i_insert_training_pattern(
        .clk               (symbol_clk),
        .clock_train       (tx_clock_train),
        .align_train       (tx_align_train), 
        ///////////////////////////////////////////////////////
        // Adds one bit per symbol - the force_neg parity flag         
        // This takes the 72-bit wide data word to 80 bits.
        ///////////////////////////////////////////////////////
        .in_data           (scrambled_data),
        .out_data          (before_skew)
    );

/////////////////////////////////////////////////////////
// The last step is to skew the data channels (zero cycles
// cycles for channel zero, two cycle for channel one, 
// four for channel two and six for channel three.
/////////////////////////////////////////////////////////
skew_channels i_skew_channels(
        .clk               (symbol_clk),
        .in_data           (before_skew),
        .out_data          (tx_symbols)
    );

endmodule
module skew_channels (
    input clk,
    input [79:0]  in_data,
    output [79:0] out_data
    );

  reg [59:0] delay0;
  reg [39:0] delay1;
  reg [19:0] delay2;

  assign out_data[79:60] = delay2[19:0];
  assign out_data[59:40] = delay1[19:0];
  assign out_data[39:20] = delay0[19:0];
  assign out_data[19:0]  = in_data[19:0];

always @(posedge clk) begin
    delay2 <= delay1[39:20];
    delay1 <= delay0[59:20];
    delay0 <= in_data[79:20];
end

endmodule
module tb_test_source_800_600_RGB_444_ch1;

    reg clk = 1'b0;


initial begin
        forever #10 clk = ~clk; // generate a clock
    end     

    wire        ready = 1'b1;
    wire [2:0]  stream_channel_count = 3'b1;
    wire [23:0] M_value;
    wire [23:0] N_value;
    wire [11:0] H_visible;
    wire [11:0] V_visible;
    wire [11:0] H_total;
    wire [11:0] V_total;
    wire [11:0] H_sync_width;
    wire [11:0] V_sync_width;
    wire [11:0] H_start;
    wire [11:0] V_start;
    wire        H_vsync_active_high;
    wire        V_vsync_active_high;
    wire        flag_sync_clock;
    wire        flag_YCCnRGB;
    wire        flag_422n444;
    wire        flag_YCC_colour_709;
    wire        flag_range_reduced;
    wire        flag_interlaced_even;
    wire  [1:0] flags_3d_Indicators;
    wire  [4:0] bits_per_colour;

    wire [72:0] raw_data;

test_source_800_600_RGB_444_ch1 i_test_source(
        .M_value              (M_value),
        .N_value              (N_value),
        
        .H_visible            (H_visible),
        .H_total              (H_total),
        .H_sync_width         (H_sync_width),
        .H_start              (H_start),    
        
        .V_visible            (V_visible),
        .V_total              (V_total),
        .V_sync_width         (V_sync_width),
        .V_start              (V_start),
        .H_vsync_active_high  (H_vsync_active_high),
        .V_vsync_active_high  (V_vsync_active_high),
        .flag_sync_clock      (flag_sync_clock),
        .flag_YCCnRGB         (flag_YCCnRGB),
        .flag_422n444         (flag_422n444),
        .flag_range_reduced   (flag_range_reduced),
        .flag_interlaced_even (flag_interlaced_even),
        .flag_YCC_colour_709  (flag_YCC_colour_709),
        .flags_3d_Indicators  (flags_3d_Indicators),
        .bits_per_colour      (bits_per_colour), 
        .stream_channel_count (stream_channel_count),
        
        .clk          (clk),
        .ready        (ready),
        .data         (raw_data)
    );

endmodule
module tb_transceiver;

    reg clk = 1'b0;


    reg        mgmt_clk;
    reg [1:0]  powerup_channel;

    reg        preemp_0p0;
    reg        preemp_3p5;
    reg        preemp_6p0;
           
    reg        swing_0p4;
    reg        swing_0p6;
    reg        swing_0p8;

    wire [1:0] tx_running;

    reg        refclk0;
    reg        refclk1;

    wire       tx_symbol_clk;
    reg [79:0] tx_symbols;

    wire [7:0]  debug;
           
    wire [1:0] gtptx_p;
    wire [1:0] gtptx_n;

   reg  [15:0] count;
initial begin
    mgmt_clk        = 1'b0;
    powerup_channel = 2'b11;
    preemp_0p0      = 1'b1;
    preemp_3p5      = 1'b0;
    preemp_6p0      = 1'b0;
           
    swing_0p4       = 1'b1;
    swing_0p6       = 1'b0;
    swing_0p8       = 1'b0;

    refclk0         = 1'b0;
    refclk1         = 1'b0;

    tx_symbols = 80'h0000000000000003FCFF;

    count = 16'b0;
       
    forever begin 
        #2
        refclk0  = ~refclk0;
        #2
        refclk0  = ~refclk0;
        mgmt_clk = ~mgmt_clk; // generate a clock
        if(count == 100) begin
            powerup_channel = 2'b00;
        end
        count = count + 1;
    end
end     

transceiver i_transceiver(
    .mgmt_clk        (mgmt_clk),
    .powerup_channel (powerup_channel),

    .preemp_0p0      (preemp_0p0),
    .preemp_3p5      (preemp_3p5),
    .preemp_6p0      (preemp_6p0),
           
    .swing_0p4       (swing_0p4),
    .swing_0p6       (swing_0p6),
    .swing_0p8       (swing_0p8),

    .tx_running      (tx_running),

    .refclk0         (refclk0),
    .refclk1         (refclk1),

    .tx_symbol_clk   (tx_symbol_clk),
    .tx_symbols      (tx_symbols),

    .debug           (debug),
           
    .gtptx_p         (gtptx_p),
    .gtptx_n         (gtptx_n)
);

endmodule
module tb_scrambler_reset_inserter;

    reg clk = 1'b1;

    reg  [71:0] in_data;
    wire [71:0] out_data;

    localparam [8:0] BS = 9'b110111100;  // K28.5

initial begin
    
    in_data      = 72'b0;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
   
    forever begin
        #1
        in_data[8:0] = BS;
        #3
        clk = ~clk;
        #4
        clk = ~clk;
        #1
        in_data      = 72'b0;
        #3
        clk = ~clk;
        #4
        clk = ~clk;
    end
end

scrambler_reset_inserter  i_scrambler_reset_inserter(
    .clk      (clk),
    .in_data  (in_data),
    .out_data (out_data)
);

endmodule
module tb_hotplug_detect;

    reg        clk100;
    wire [7:0] debug;

    reg        hpd;
    reg        auxch_in;
    wire       auxch_out;
    wire       auxch_tri;

        // Datapath requirements
    reg  [2:0] stream_channel_count;
    reg  [2:0] source_channel_count;

        // Datapath control
    wire       tx_clock_train;
    wire       tx_align_train;

        // Transceiver management
    wire [3:0] tx_powerup_channel;

    wire       tx_preemp_0p0;
    wire       tx_preemp_3p5;
    wire       tx_preemp_6p0;
           
    wire       tx_swing_0p4;
    wire       tx_swing_0p6;
    wire       tx_swing_0p8;
          
    reg  [3:0] tx_running;
    wire       tx_link_established;

    reg  [19:0] count;
initial begin
    clk100               = 1'b0;
    hpd                  = 1'b0;
    auxch_in             = 1'b0;
        // Datapath requirements
    stream_channel_count = 3'b001;
    source_channel_count = 3'b001;
    tx_running           = 4'b0000;
    count                = 16'b0;
end

initial begin
    forever begin
        if(count == 100) begin
            hpd = 1'b1;
        end
        if(count == 250000) begin   // IRQ PULSE
            hpd = 1'b0;
        end
        if(count == 400000) begin
            hpd = 1'b1;
        end
        if(count == 750000) begin
            hpd = 1'b0;
        end
        #5 
        clk100 = ~clk100; // generate a clock
        #5 
        clk100 = ~clk100; // generate a clock
        count = count +1;
    end     
end     


channel_management i_channel_management(
        .clk100               (clk100),
        .debug                (debug),

        .hpd                  (hpd),
        .auxch_in             (auxch_in),
        .auxch_out            (auxch_out),
        .auxch_tri            (auxch_tri),

        // Datapath requirements
        .stream_channel_count (stream_channel_count),
        .source_channel_count (source_channel_count),

        // Datapath control
        .tx_clock_train       (tx_clock_train),
        .tx_align_train       (tx_align_train),

        // Transceiver management
        .tx_powerup_channel   (tx_powerup_channel),

        .tx_preemp_0p0        (tx_preemp_0p0),
        .tx_preemp_3p5        (tx_preemp_3p5),
        .tx_preemp_6p0        (tx_preemp_6p0),
           
        .tx_swing_0p4         (tx_swing_0p4),
        .tx_swing_0p6         (tx_swing_0p6),
        .tx_swing_0p8         (tx_swing_0p8),
 
        .tx_running           (tx_running),
        .tx_link_established  (tx_link_established)
);

endmodule
module tb_channel_management;

    reg        clk100;
    wire [7:0] debug;

    wire       hpd;
    wire       auxch_in;
    wire       auxch_out;
    wire       auxch_tri;

        // Datapath requirements
    reg  [2:0] stream_channel_count;
    reg  [2:0] source_channel_count;

        // Datapath control
    wire       tx_clock_train;
    wire       tx_align_train;

        // Transceiver management
    wire [3:0] tx_powerup_channel;

    wire       tx_preemp_0p0;
    wire       tx_preemp_3p5;
    wire       tx_preemp_6p0;
           
    wire       tx_swing_0p4;
    wire       tx_swing_0p6;
    wire       tx_swing_0p8;
          
    reg  [3:0] tx_running;
    wire       tx_link_established;

    reg  [31:0] i, j;
    
initial begin
    clk100               = 1'b0;
        // Datapath requirements
    stream_channel_count = 3'b001;
    source_channel_count = 3'b001;
    tx_running           = 4'b0000;
end


always begin
    #5  clk100 = ~clk100; // generate a clock
end

wire dp_tx_hp_detect;
tb_dummy_sink i_tb_dummy_sink(
    .clk100           (clk100),
    .auxch_data       (auxch_in),
    .hotplug_detect   (hpd)
);


channel_management i_channel_management(
        .clk100               (clk100),
        .debug                (debug),

        .hpd                  (hpd),
        .auxch_in             (auxch_in),
        .auxch_out            (auxch_out),
        .auxch_tri            (auxch_tri),

        // Datapath requirements
        .stream_channel_count (stream_channel_count),
        .source_channel_count (source_channel_count),

        // Datapath control
        .tx_clock_train       (tx_clock_train),
        .tx_align_train       (tx_align_train),

        // Transceiver management
        .tx_powerup_channel   (tx_powerup_channel),

        .tx_preemp_0p0        (tx_preemp_0p0),
        .tx_preemp_3p5        (tx_preemp_3p5),
        .tx_preemp_6p0        (tx_preemp_6p0),
           
        .tx_swing_0p4         (tx_swing_0p4),
        .tx_swing_0p6         (tx_swing_0p6),
        .tx_swing_0p8         (tx_swing_0p8),
 
        .tx_running           (tx_running),
        .tx_link_established  (tx_link_established)
);

endmodule
module tb_compare;

    reg clk = 1'b0;


initial begin
        forever #10 clk = ~clk; // generate a clock
    end     

    wire  [2:0] stream_channel_count;
    wire [72:0] data;
    wire        ready;

    wire  [2:0] v_stream_channel_count;
    wire [72:0] v_data;
    wire        v_ready;


test_source i_test_source(
    .clk                  (clk),
    .stream_channel_count (stream_channel_count),
    .ready                (ready),
    .data                 (data)
);

test_source_cmp i_v_test_source_cmp(
    .clk                  (clk),
    .stream_channel_count (v_stream_channel_count),
    .ready                (v_ready),
    .data                 (v_data)
);

    wire [72:0] diff = data ^ v_data;
endmodule
module tb_skew_channels;

    reg clk = 1'b1;

    reg  [79:0] in_data;
    wire [79:0] out_data;

initial begin
    
    in_data      = 80'b0;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
   
    forever begin
        #1
        in_data = 80'h44444333332222211111;
        #3
        clk = ~clk;
        #4
        clk = ~clk;
        #1
        in_data = 80'b0;
        #3
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
    end
end

skew_channels  i_skew_channels(
    .clk      (clk),
    .in_data  (in_data),
    .out_data (out_data)
);

endmodule
module tb_test_source;

    reg clk = 1'b0;
    reg [8:0] ch1;
    reg [8:0] ch2;
    reg [8:0] ch3;
    reg [8:0] ch4;

        wire  [2:0] stream_channel_count;
        wire [72:0] data;
        wire        ready;
        
        
initial begin
        forever begin
             #4 
             clk = 1'b0; // generate a clock
             ch1 <= data[8:0];
             ch2 <= data[26:18];
             ch3 <= data[44:36];
             ch4 <= data[62:54];

             #4 
             clk = 1'b1; // generate a clock
             ch1 <= data[17:9];
             ch2 <= data[35:27];
             ch3 <= data[53:45];
             ch4 <= data[71:63];
         end
    end     


test_source i_test_source(
    .clk                  (clk),
    .stream_channel_count (stream_channel_count),
    .ready                (ready),
    .data                 (data)
);

endmodule
module tb_idle_pattern_inserter;

    reg clk = 1'b1;

    reg channel_ready = 1'b1;
    reg source_ready  = 1'b1;

    reg  [72:0] in_data;
    wire [71:0] out_data;
    reg  [15:0] count;

initial begin
    
    in_data      = 80'b0;
    channel_ready = 1'b1;
    source_ready  = 1'b1;
    count         =    0;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
   
    forever begin
        case(count)
           100: in_data = 73'h1444333332222211111;
           200: in_data = 73'h0444333332222211111;
        endcase
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        count = count + 1;
    end
end

idle_pattern_inserter  i_idle_pattern_inserter(
    .clk            (clk),
    .channel_ready  (channel_ready),
    .source_ready   (source_ready),
    .in_data        (in_data),
    .out_data       (out_data)
);

endmodule
module tb_insert_training_pattern;

    reg         clk         = 1'b1;
    reg         clock_train = 1'b0;
    reg         align_train = 1'b0;
    reg  [71:0] in_data;
    wire [79:0] out_data;
    reg  [11:0] count;

initial begin
    count       = 12'b0;
    clock_train = 1'b1;  
    align_train = 1'b0;  
    in_data = 72'hFFFFFFFFFFFFFFFFFF;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
   
    forever begin
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #1
        if(count == 100) begin clock_train = 1'b0; align_train = 1'b1; end
        if(count == 200) begin clock_train = 1'b0; align_train = 1'b0; end
        #3
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        #4
        clk = ~clk;
        count = count + 1;
    end
end

insert_training_pattern i_insert_training_pattern(
    .clk         (clk),
    .clock_train (clock_train),
    .align_train (align_train),
    .in_data     (in_data),
    .out_data    (out_data)
);

endmodule
module tb_data_stream;

reg        tx_symbol_clk;
reg        tx_align_train;       
reg        tx_clock_train;       
reg        tx_link_established;
reg f;

wire [72:0] msa_merged_data;
wire        test_signal_ready;
wire  [2:0] stream_channel_count;

initial begin
  tx_symbol_clk       = 1'b0;
  tx_align_train      = 1'b0;
  tx_clock_train      = 1'b0;
  tx_link_established = 1'b1;
end

always begin
  #4    // Should be 135MHz, but 125 is close enough for simulation
  tx_symbol_clk = ~tx_symbol_clk;
  #4    // Should be 135MHz, but 125 is close enough for simulation
  tx_symbol_clk = ~tx_symbol_clk;
  $display("%b %b", 
         msa_merged_data[8:0],  msa_merged_data[26:18]
  );

  $display("%b %b", 
         msa_merged_data[17:9], msa_merged_data[35:27]
  );
end

///////////////////////////////////////////////////
// Video pipeline
/////////////////////////////////////////%/////////
test_source i_test_source(
        .clk                  (tx_symbol_clk),
        .stream_channel_count (stream_channel_count),
        .ready                (test_signal_ready),
        .data                 (msa_merged_data)
    );

wire [79:0] tx_symbols;
main_stream_processing i_main_stream_processing(
        .symbol_clk          (tx_symbol_clk),
        .tx_link_established (tx_link_established),
        .source_ready        (test_signal_ready),
        .tx_clock_train      (tx_clock_train),
        .tx_align_train      (tx_align_train),
        .in_data             (msa_merged_data),
        .tx_symbols          (tx_symbols)
    );

endmodule
module tb_scrambler_all_channels;

    reg clk = 1'b0;

    reg         bypass0;
    reg         bypass1;
    reg  [71:0] in_data;
    wire [71:0] out_data;
    wire [8:0]  data0;
    wire [8:0]  data1;

    localparam [8:0] scrambler_reset = 9'b100011100;
 
    assign data0 = out_data[8:0];
    assign data1 = out_data[17:9];

    //--------------------------------------------------------------------------------
    // Should be verified against the table in Appendix C of the "PCI Express Base 
    // Specification 2.1" which uses the same polynomial.
    //
    // Here are the first 32 output words when data values of "00" are scrambled: 
    //
    // If the Scramble reset code is in the first word:
    //
    // cycle | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    // ------+------------------------------------------------
    // data0 |[SR]17 14 E7 82 6E A6 6D 8D 40 E6 D3 B2 02 2A 34 E0
    // data1 | FF C0 B2 02 72 28 BE BF BE A7 2C E2 07 77 CD BE ...
    //
    // If the Scramble reset code is in the second word:
    //
    // cycle | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    // ------+------------------------------------------------
    // data0 | xx FF C0 B2 02 72 28 BE BF BE A7 2C E2 07 77 CD BE ...
    // data1 |[SR]17 14 E7 82 6E A6 6D 8D 40 E6 D3 B2 02 2A 34 E0
    //
    //--------------------------------------------------------------------------------
          
initial begin
    bypass0 = 0;
    bypass1 = 0;
    
    in_data      = 72'b0;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    #4
    clk = ~clk;

    in_data[8:0] = scrambler_reset;
    #4
    clk = ~clk;
    #4
    clk = ~clk;

    in_data      = 72'b0;
    #4
    clk = ~clk;
    #4
    clk = ~clk;
    
        
    forever #4 clk = ~clk; // generate a clock
end

scrambler_all_channels  i_scrambler_all_channels(
    .clk      (clk),
    .bypass0  (bypass0),
    .bypass1  (bypass1),
    .in_data  (in_data),
    .out_data (out_data)
);

endmodule
module tb_gtx_tx_reset_controller;

    reg  clk = 1'b0;
    reg  powerup_channel;
    reg  plllock;
    reg  txresetdone;
    reg  ref_clk;
    
    wire tx_running;
    wire txreset;
    wire txuserrdy;
    wire txpmareset;
    wire txpcsreset;
    wire pllpd;
    wire pllreset;
    wire plllocken;
    wire resetsel;

    reg [15:0] count;
    
initial begin
    count           = 16'd0;

    powerup_channel = 1'b1;
    plllock         = 1'b0;
    txresetdone     = 1'b0;
    ref_clk         = 1'b0;
    
    forever begin
        #1
        if(count == 16'd500) begin
            powerup_channel = 1'b0;
        end
        
        if(count == 16'd700) begin
            plllock = 1'b1;
        end

        if(count == 16'd1000) begin
            txresetdone = 1'b1;
        end

        #4
        ref_clk = 1'b1;
        clk = 1'b1;
        
        #5
        clk     = 1'b0;
        ref_clk = 1'b0;
        count   = count + 1;
    end 
    
end     
 
    
gtx_tx_reset_controller i_gtx_tx_reset_controller(
  .clk (clk),

  .ref_clk         (ref_clk),
  .powerup_channel (powerup_channel),
  .plllock         (plllock),         
  .txresetdone     (txresetdone),

  .tx_running      (tx_running),
  .txreset         (txreset),
  .txuserrdy       (txuserrdy),
  .txpmareset      (txpmareset),
  .txpcsreset      (txpcsreset),
  .pllpd           (pllpd),
  .pllreset        (pllreset),
  .plllocken       (plllocken),
  .resetsel        (resetsel)
);
endmodule
module tb_top_level;

    reg        clk100;
    wire [7:0] debug;
    wire [1:0] dp_tx_lane_p;
    wire [1:0] dp_tx_lane_n;
    wire [7:0] LED;
    //////////////////////////////////////////
    reg        dp_refclk_p;
    reg        dp_refclk_n;
    reg        mgtrefclk1_p;
    reg        mgtrefclk1_n;
    //////////////////////////////////////////
    wire       dp_tx_hp_detect;
    wire       dp_tx_auxch_tx_p;
    wire       dp_tx_auxch_tx_n;
    wire       dp_tx_auxch_rx_p;
    wire       dp_tx_auxch_rx_n;
    ///////////////////////////////////////////
    reg  [3:0] sw;
    wire       auxch_data;

    reg  [31:0] i, j, k;


    
initial begin
    clk100               = 1'b0;

    dp_refclk_p = 1'b1;
    dp_refclk_n = 1'b0;

    mgtrefclk1_p         = 1'b0;
    mgtrefclk1_n         = 1'b1;

    sw                   = 3'b001;

    i                    = 31'b0;
    j                    = 31'b0;
    k                    = 31'b0;

end

   
always begin
        #5  clk100 = ~clk100; // generate a clock
end 

always begin
        #4  dp_refclk_p = ~dp_refclk_p; dp_refclk_n = ~dp_refclk_n;// generate a clock
end 

assign dp_tx_auxch_rx_p = auxch_data;
assign dp_tx_auxch_rx_n = ~auxch_data;

tb_dummy_sink i_tb_dummy_sink(
    .clk100           (clk100),
    .auxch_data       (auxch_data),
    .hotplug_detect   (dp_tx_hp_detect)
);

top_level_nexys_video i_top_level_nexys_video(
    .clk100           (clk100),
    //////////////////////////////////////////
    .dp_tx_lane_p     (dp_tx_lane_p),
    .dp_tx_lane_n     (dp_tx_lane_n),
    //////////////////////////////////////////
    .dp_refclk_p      (dp_refclk_p),
    .dp_refclk_n      (dp_refclk_n),
    .mgtrefclk1_p     (mgtrefclk1_p),
    .mgtrefclk1_n     (mgtrefclk1_n),
    //////////////////////////////////////////
    .dp_tx_hp_detect  (dp_tx_hp_detect),
    .dp_tx_auxch_tx_p (dp_tx_auxch_tx_p),
    .dp_tx_auxch_tx_n (dp_tx_auxch_tx_n),
    .dp_tx_auxch_rx_p (dp_tx_auxch_rx_p),
    .dp_tx_auxch_rx_n (dp_tx_auxch_rx_n),
    ///////////////////////////////////////////
    .debug            (debug),
    .sw               (sw),
    .LED              (LED)
);

endmodule
module dp_register_decode(
   input         clk,

   input         de,
   input  [7:0]  data,
   input  [7:0]  addr,
   input         invalidate,

   output reg        valid,
 
   output reg [7:0]  revision,
   output reg        link_rate_2_70,
   output reg        link_rate_1_62,
   output reg        extended_framing,
   output reg [3:0]  link_count,
   output reg [7:0]  max_downspread,
   output reg [7:0]  coding_supported,
   output reg [15:0] port0_capabilities,
   output reg [15:0] port1_capabilities,
   output reg [7:0]  norp
);

initial begin
    valid              = 1'b0;
    revision           = 8'b0;
    link_rate_2_70     = 1'b0;
    link_rate_1_62     = 1'b0;
    extended_framing   = 1'b0;
    link_count         = 3'b0;
    max_downspread     = 8'b0;
    coding_supported   = 8'b0;
    port0_capabilities = 16'b0;
    port1_capabilities = 16'b0;
    norp               = 8'b0;
end

always @(posedge clk) begin
    if(de == 1'b1) begin
        valid    <= 1'b0;
        case(addr)
            8'h00: begin
                       revision <= data;
                   end
            8'h01: begin
                       case(data) 
                              8'h0A:   begin
                                           link_rate_2_70 <= 1'b1;
                                           link_rate_1_62 <= 1'b1;
                                       end
                              8'h06:   begin
                                           link_rate_2_70 <= 1'b0;
                                           link_rate_1_62 <= 1'b1;
                                       end
                              default: begin
                                           link_rate_2_70 <= 1'b0;
                                           link_rate_1_62 <= 1'b0;
                                       end
                       endcase
                   end
            8'h02: begin
                       extended_framing <= data[7];
                       link_count       <= data[3:0];         
                   end
            8'h03: begin
                       max_downspread   <= data;
                   end
            8'h04: begin
                       norp             <= data;
                   end
            8'h06: begin
                       coding_supported <= data;    
                   end
            8'h08: begin
                       port0_capabilities[7:0] <= data;
                   end
            8'h09: begin
                       port0_capabilities[15:8]<= data;
                   end
            8'h0A: begin
                       port1_capabilities[7:0] <= data;
                   end
            8'h0B: begin
                       port1_capabilities[15:8]<= data;
                       valid <= 1'b1;
                   end
        endcase

        //----------------------------------------------
        // Allow for an external event to invalidate the 
        // outputs (e.g. hot plug)
        //----------------------------------------------
        if(invalidate == 1'b1) begin
           valid <= 1'b0;
        end
    end
end
endmodule
module hotplug_decode(
    input  clk,
    input  hpd,
    output reg irq,
    output reg present
);

   reg hpd_meta1;   // TODO Should also set ASYNC_REG
   reg hpd_meta2;   // TODO Should also set ASYNC_REG
   reg hpd_synced;
   reg hpd_last;

   reg [17:0] pulse_count;


initial begin
    hpd_meta1    = 1'b0;
    hpd_meta2    = 1'b0;
    hpd_synced   = 1'b0;
    hpd_last     = 1'b1;
    pulse_count  = 18'b0;
    present      = 1'b0;
    irq          = 1'b0;
end 

always @(posedge clk) begin
    irq <= 1'b0;
    if(hpd_last == 1'b0) begin
        if(hpd_synced == 1'b0) begin
            if(pulse_count == 200000) begin  // TODO - should not be a constant!
                //--------------------------------
                // Sink has gone away for over 2ms
                // No longer present
                //--------------------------------
                present <= 1'b0;
            end else begin
                pulse_count <= pulse_count + 1;
            end
        end else begin
            //----------------------------------------
            // Timing the pulse to see if it is an IRQ
            //----------------------------------------
            if(pulse_count > 100000) begin  // TODO - should not be a constant!
                //-----------------------------------
                // Signal is back, but less than 2ms
                // so signal an IRQ...
                //-----------------------------------
                if(present == 1'b1) begin
                  irq <= present;
                end
            end
            pulse_count = 18'b0;
        end
    end else begin
        if(hpd_synced == 1'b0) begin
            pulse_count = 18'b0;            // Flip to other state
        end else begin
            if(pulse_count == 220000) begin
                present <= 1'b1;                // Pulse seen long enough to be valid
            end else begin
                pulse_count <= pulse_count + 1; // Time till the signal is valid for > 2ms
            end
        end
    end
    hpd_last   <= hpd_synced;
    hpd_synced <= hpd_meta1;
    hpd_meta1  <= hpd_meta2;
    hpd_meta2  <= hpd;
end
endmodule
module seven_segment_driver(
    input  wire clk,
    input  wire [11:0] value,
    output reg  [7:0] segments,
    output reg  [2:0] segment_enable
    );
    
reg [39:0] counter;
reg [2:0] next_enable;
reg [3:0] to_decode;
    
always @(posedge clk) begin

//                         Top:RT:RB:Bot:LT:LB:mid:DP
   case (to_decode)
     4'b0000: segments <= 8'b00000011; // 0
     4'b0001: segments <= 8'b10011111; // 1
     4'b0010: segments <= 8'b00100101; // 2 
     4'b0011: segments <= 8'b00001101; // 3  
     4'b0100: segments <= 8'b10011001; // 4
     4'b0101: segments <= 8'b01001001; // 5
     4'b0110: segments <= 8'b01000001; // 6
     4'b0111: segments <= 8'b00011111; // 7 
     4'b1000: segments <= 8'b00000001; // 8
     4'b1001: segments <= 8'b00001001; // 9
     4'b1010: segments <= 8'b00010001; // A
     4'b1011: segments <= 8'b11000001; // B
     4'b1100: segments <= 8'b01100011; // C 
     4'b1101: segments <= 8'b10000101; // D
     4'b1110: segments <= 8'b01100001; // E
     default: segments <= 8'b01110001; // F
   endcase;
    
   segment_enable <= next_enable;

   case (counter[19:18]) 
     2'b00:   begin 
                next_enable <= 3'b110;
                to_decode   <= value[3:0];
              end

     2'b01:   begin
                next_enable <= 3'b101;
                to_decode   <= value[7:4];
              end

     2'b10:   begin
                next_enable <= 3'b011;
                to_decode   <= value[11:8];
              end

     default: begin 
                next_enable <= 3'b111;
                to_decode   <= 4'b0000;
              end
   endcase;          

   counter  <= counter + 1;
end

endmodule
module nor_4(y, a, b, c, d, rst, clk);
    parameter delay = 9;
    parameter iv = 1'b0;
    input wire a, b, c, d, rst, clk;

`ifdef TARGET_FPGA
    output reg y = iv;
    reg next_val = iv;
    reg prev_val = iv;
    wire result;
    
    assign result = ~(a|b|c|d);

    always @(posedge clk)
    begin
        prev_val = y;
        y = next_val;
    end

    always @(negedge clk)
    begin
        next_val = ((result == prev_val) && (y == iv)) ? iv : result;
    end
`else
    output wire y;
    assign #delay y = (rst) ? iv : ~(a|b|c|d);
`endif
endmodule
module nor_1(y, a, rst, clk);
    parameter delay = 9;
    parameter iv = 1'b0;
    input wire a, rst, clk;

`ifdef TARGET_FPGA
    output reg y = iv;
    reg next_val = iv;

    always @(posedge clk)
    begin
        y = next_val;
    end

    always @(negedge clk)
    begin
        next_val = ~a;
    end
`else
    output wire y;
    assign #delay y = (rst) ? iv : ~a;
`endif
endmodule