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)