A simple and convenient data splicing module (supports any bit width and any integer multiple)

Write in front

         When writing the serial port diagram transmission project (using SDRAM cache), because the bit width of the write port of the SDRAM controller previously written is 16 bits, and the general serial port host computer can only send 8 bits at most, so the problem of inconsistent bit width on both sides needs to be solved. After thinking about it, there seem to be many solutions:

  • Change the write bit width of SDRAM controller to 8bit directly - but in this case, RGB565 format cannot be used directly. Give up
  • Add a FIFO to cache in the middle - very good, or if you want to change other bit widths, you have to change the FIFO, which is still inconvenient (lazy)
  • I wrote a merging and splicing module to support the splicing of any integer multiple data -- it's very convenient. Just before, a friend wanted an 8bit to 32bit serial port data splicing module

1. Design

         There are two goals to achieve:

  • Supports the merging of any integer multiple data
  • Data bit width optional

         For example, if the serial port with input data of 8bit receives data and is accompanied by data valid signal, it shall be spliced into 16bit (or 24bit, 32bit) data and output data valid signal at the same time.

1.1 port

        The input and output ports of splicing module are as follows:

        The meaning of each signal is as follows:

                Parameters:

                         DATA_WIDTH: input data bit width

                         MERGE_STAGE: merge order. For example, 2 means that every two inputs are merged into one output

                Input:

                        sys_clk: system clock. My development board is 50M with a cycle of 20ns

                        sys_rst_n: Low level active asynchronous reset signal

                         data_ In [DATA_WIDTH - 1: 0]: enter data, and the bit width is data_ WIDTH - 1

                         data_in_valid: input data valid signal

                Output terminal

                        data_out[DATA_WIDTH*MERGE_STAGE - 1: 0]: output data. The bit width is equal to the input bit width * merge order - 1

                         data_out_valid: output data valid signal

1.2 Verilog code

         You might as well conceive the realization idea first:

  • Assuming that the merging order is 2 and the data bit width is 8, that is, every two 8bit data are merged into one 16bit data
  • For each data, its shift is registered to the output
  • Construct a counter. Whenever a data is input, it is + 1 (starting from 0). When it is 1 and there is input data valid at this time, it indicates that it has received two data and can pull up the output data valid

        The approximate sequence diagram is as follows:

         According to the above, the complete code can be written as follows:

module merge #(
	parameter	integer	DATA_WIDTH  = 8,							//Input data bit width
	parameter	integer	MERGE_STAGE = 2								//Merge the series. If 2, merge the two data into one.	
)
(
	input										sys_clk			,
	input										sys_rst_n		,
				
	input		[DATA_WIDTH - 1 : 0]			data_in			,	//input data	
	input										data_in_valid	,	//The input data is valid			
	output	reg	[DATA_WIDTH*MERGE_STAGE - 1: 0]	data_out		,	//output data
	output	reg									data_out_valid		//Output data valid
);

reg	[$clog2(MERGE_STAGE) - 1 : 0]	cnt_valid;						//Counter for inputting valid signals, each valid signal + 1

//Input data counter
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(~sys_rst_n)
		cnt_valid <= 0;
	else if(data_in_valid)begin
		if(cnt_valid == MERGE_STAGE - 1)
			cnt_valid <= 0;
		else
			cnt_valid <= cnt_valid + 1;
	end
	else
		cnt_valid <= cnt_valid ;
end
//Input data shift register
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(~sys_rst_n)
		data_out <= 0;
	else if(data_in_valid)
		data_out <= {data_out[DATA_WIDTH*(MERGE_STAGE - 1) - 1:0],data_in};	
	else
		data_out <= data_out ;
end
//Output data valid
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(~sys_rst_n)
		data_out_valid <= 0;
	else if(cnt_valid == MERGE_STAGE - 1 && data_in_valid)
		data_out_valid <= 1;	
	else
		data_out_valid <= 0 ;
end

endmodule

2. Testing

2.1,Testbench

         testbench needs to generate input data and effective signals of input data, and instantiate the tested merging module.

  • A random 8bit data is generated in each cycle, and an effective signal of input data is generated every 50 cycles. Equivalent to inputting a valid 8bit signal every 50 clock cycles.
  • Three merging modules are instantiated to test, including second-order merging, third-order merging and fourth-order merging.

         The complete TB file is as follows:

`timescale	1ns/1ns

module tb_merge();

parameter	integer	DATA_WIDTH    = 8;			//Input data bit width
parameter	integer	MERGE_STAGE_2 = 2;			//Merge series. If 2, merge 2 data into one	
parameter	integer	MERGE_STAGE_3 = 3;			//Merge the series. If 3, merge the three data into one	
parameter	integer	MERGE_STAGE_4 = 4;			//Merge the series. If 3, merge the three data into one	
	
reg											sys_clk			;
reg											sys_rst_n		;		
reg		[DATA_WIDTH - 1:0]					data_in			;
reg											data_in_valid	;
//Second order merging														
wire	[DATA_WIDTH*MERGE_STAGE_2 - 1:0]	data_out_2		;
wire										data_out_valid_2 ;
//3rd order merge														
wire	[DATA_WIDTH*MERGE_STAGE_3 - 1:0]	data_out_3		;
wire										data_out_valid_3 ;
//4th order merge														
wire	[DATA_WIDTH*MERGE_STAGE_4 - 1:0]	data_out_4		;
wire										data_out_valid_4 ;

//------------< set initial test conditions >----------------------------------------
initial begin
	sys_clk = 1'b0;					//The initial clock is 0
	sys_rst_n <= 1'b0;				//Initial reset
	data_in_valid <= 0;
	#seventy 								// After 70 clock cycles
	sys_rst_n <= 1'b1;				//Pull up to reset and the system enters the working state
	repeat(13)begin	
		#1000	
			data_in_valid <= 1;		//Pull up every 50 clock cycles
		#20		
			data_in_valid <= 0;
	end
	$stop;
end
//------------< set clock >----------------------------------------------
always #10 sys_clk = ~sys_clk; 		// System clock cycle 20ns
		
//Generate data, each clock cycle + 1
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(~sys_rst_n)
		data_in <= 0;	
	else
		data_in <= {$random % 8};	//Generate random data
end
//Print generated random data
always@(posedge sys_clk)begin
	@(posedge data_in_valid)
		$display("data_in = %h",data_in);
end

//Second order merging
merge #(
	.DATA_WIDTH 	(DATA_WIDTH 		),				//Input data bit width
	.MERGE_STAGE	(MERGE_STAGE_2		)				//Merge the series. If 2, merge the two data into one.	
)	
merge_inst_2(	
	.sys_clk		(sys_clk			),
	.sys_rst_n		(sys_rst_n			),
						
	.data_in		(data_in			),	
	.data_in_valid	(data_in_valid		),
					
	.data_out		(data_out_2			),
	.data_out_valid	(data_out_valid_2	)
);
//3rd order merge
merge #(
	.DATA_WIDTH 	(DATA_WIDTH 		),			
	.MERGE_STAGE	(MERGE_STAGE_3		)			
)	
merge_inst_3(	
	.sys_clk		(sys_clk			),
	.sys_rst_n		(sys_rst_n			),
						
	.data_in		(data_in			),	
	.data_in_valid	(data_in_valid		),
					
	.data_out		(data_out_3			),
	.data_out_valid	(data_out_valid_3	)
);
//4th order merge
merge #(
	.DATA_WIDTH 	(DATA_WIDTH 		),			
	.MERGE_STAGE	(MERGE_STAGE_4		)			
)	
merge_inst_4(	
	.sys_clk		(sys_clk			),
	.sys_rst_n		(sys_rst_n			),
						
	.data_in		(data_in			),	
	.data_in_valid	(data_in_valid		),
					
	.data_out		(data_out_4			),
	.data_out_valid	(data_out_valid_4	)
);

endmodule

2.2 simulation results

         The simulation results are as follows (only 15 data are input for easy explanation):

          The results in the figure above:

  • The upper left corner is valid input data (printed out in consideration of inconvenient viewing)
  • The valid input data are: FC --- 03 --- FD --- 05 --- FD --- 04 --- 05 --- FC --- 07 --- F9 --- FD --- 04
  • The effective outputs of level 2 merging are: fc03 --- fd05 ~ ~ ~ ~ ~ ~, in accordance with the rules
  • The effective outputs of level 3 merging are: fc03fd --- 05fd04 ~ ~ ~ ~ ~ ~ ~, in accordance with the rules
  • The effective outputs of level 4 merging are: fc03fd05 --- fd0405fc ~ ~ ~ ~, in accordance with the rules

3. Other

  • Creation is not easy. If this article is helpful to you, please praise, comment and collect more. Your support is the biggest driving force for my continuous update!
  • For this article, you can leave a message in the comment area. If you need the whole project, please leave an email in the comments or send a private letter to my email (pay attention to Privacy).
  • Your ability is insufficient. Please point out any mistakes!

Version information

         File: V1.0

        No.: 68

        Vivado: None

        Modelsim: Modelsim SE-64 10.4

        Quartus II: Quartus II 13.1 (64-bit)
 

 

Tags: Verilog

Posted on Sun, 05 Dec 2021 02:28:42 -0500 by python_q