1.题目描述
实现数据位宽转换电路,实现24bit数据输入转换为128bit数据输出。其中,先到的数据应置于输出的高bit位。电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号。
2.波形图
3.错误分析
最开始的时候分析问题,只考虑了在一次数据传输的周期中的传输过程,由于是24to128的数据转换,需要传输六次,且最后一次的数据只会存最高的8位。即开始时的数据转换是通过data_out_reg缓存数据,但是最后一次会慢一拍,所以,最后需要通过data_out再缓存最终的高位数据。
reg [127:0] data_out_reg;always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_out_reg <= 128'd0;else if(valid_in)data_out_reg <= {data_out_reg[103:0],data_in};elsedata_out_reg <= 128'd0;end
always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_out <= 128'd0;else if(valid_in && (data_cnt == 4'd5))data_out <= {data_out_reg[119:0],data_in[23:16]};else data_out <= data_out; end
4.错误代码
整体代码也不赘述了,只能实现次6位数据的转换,后续数据处理都是错误的:
`timescale 1ns/1nsmodule width_24to128(input clk , input rst_n ,input valid_in ,input [23:0] data_in ,output reg valid_out ,output reg [127:0] data_out
);reg [3:0] data_cnt;always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_cnt <= 4'd0;else if(valid_in == 1'b1)data_cnt <= (data_cnt == 4'd5)? 4'd0 : data_cnt + 1'b1;endalways@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)valid_out <= 1'b0;else if(data_cnt == 4'd5 && valid_in)valid_out <= 1'b1;elsevalid_out <= 1'b0;endreg [127:0] data_out_reg;always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_out_reg <= 128'd0;else if(valid_in)data_out_reg <= {data_out_reg[103:0],data_in};elsedata_out_reg <= 128'd0;endalways@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_out <= 128'd0;else if(valid_in && (data_cnt == 4'd5))data_out <= {data_out_reg[119:0],data_in[23:16]};else data_out <= data_out; endendmodule
验证代码,一次数据转换:
`timescale 1ns/1nsmodule width_24to128_tb;reg clk ;
reg rst_n ;
reg valid_in ;
reg [23:0] data_in ;wire valid_out ;
wire [127:0] data_out ;width_24to128 inst1(.clk(clk),.rst_n(rst_n),.valid_in(valid_in),.data_in(data_in),.valid_out(valid_out),.data_out(data_out)
);initial begin clk = 1'b0; forever begin #10; clk = ~clk; end end
initial begin rst_n = 1'b0; #25; rst_n = 1'b1; end
initial begin valid_in = 1'b0; #52 ;valid_in = 1'b1; #120;valid_in =1'b0; end
initial begin data_in = 24'd0; #52 ;data_in = 24'ha0a1a2;#20;data_in = 24'hb2b1b0;#20;data_in = 24'hc2c1c0;#20;data_in = 24'hd2d1d0;#20;data_in = 24'he2e1e0;#20;data_in = 24'hf2f1f0;#20;end
initial begin #5000; $stop; endendmodule
从波形图也可以看出问题所在,所以对RTL代码进行修改。
5.正确分析
输入数据是24bit,输出数据是128bit,要找到二者的公倍数,才能将所有传输的数据都进行一个合理的整合。因为128 * 3 = 24 * 16,所以每输入16个有效数据,就可以产生三个完整的输出。因此设置一个仅在输入数据有效时工作的计数器cnt,计数范围是0-15。
`timescale 1ns/1nsmodule width_24to128(input clk , input rst_n ,input valid_in ,input [23:0] data_in ,output reg valid_out ,output reg [127:0] data_out
);reg [3:0] data_cnt;//16位always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_cnt <= 4'd0;else if(valid_in == 1'b1)data_cnt <= data_cnt + 1'b1;endalways@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)valid_out <= 1'b0;else if((data_cnt == 4'd5 || data_cnt == 4'd10 || data_cnt == 4'd15) && valid_in)valid_out <= 1'b1;elsevalid_out <= 1'b0;endreg [127:0] data_out_reg;always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_out_reg <= 128'd0;else if(valid_in)data_out_reg <= {data_out_reg[103:0],data_in};elsedata_out_reg <= data_out_reg;endalways@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)data_out <= 128'd0;else if(data_cnt == 4'd5)data_out <= {data_out_reg[119:0],data_in[23:16]};else if(data_cnt == 4'd10)data_out <= {data_out_reg[119:0],data_in[23:8]};else if(data_cnt == 4'd15)data_out <= {data_out_reg[119:0],data_in[23:0]};else data_out <= data_out; endendmodule
后续的验证波形大家可以自己写一下,后面如果有,相对来说还是比较简单的。祝大家越学越开心。