数据位宽转换器,一般常用于模块接口处,比如一个电路模块的输出数据位宽大于另一个模块的输入数据位宽,此时就需要进行数据位宽转换。比如SATA控制器中,内部数据位宽为32bit,但外部物理收发器PHY的接口通常为16bit,或者8bit,在不使用FIFO进行缓存的情况下,可以使用数据位宽转换器,通过时钟倍频在实现数据位宽的转换。
关于分频器,请移步到之前的一篇文章点击传送门
假设数据从模块A传入到模块B,模块A的输出数据为32位,模块B的输入数据位宽为16位,那么如何能把数据从A传入B而不损失数据呢?
答:通过时钟的分频与倍频实现。
我们假设一个原时钟clk1,通过二分频,把原时钟变为时钟clk2,那么clk2的时钟周期就是clk1的两倍。在clk2的上升沿,我们读入32bit数据,在第一个clk1的上升沿我们输出读进来的高16bit数据,第二个clk1的上升沿我们输出读进来的低16bit数据,由于clk1的频率是clk2的两倍,每读入一次32bit数据,就会输出两次16bit数据,从而实现了数据位宽的转换。
参考文章
它里边可能有的地方有笔误,大家看的时候注意一下就行。
由窄到宽的数据位宽转换原理和由宽到窄的是一样的。把频率高一点的时钟用来采样16bit数据,频率低一点的时钟用来输出32bit数据。
同样参考2.1.1即可。
不知道大家有没有注意到,通过分频来做的话,我们拿到一个整数分频还好点,比如8位转16位,或者64位转16位,这样只要简单实现一下整数分频器;那要是小数分频器怎么办?虽然说也能实现,但是是不是有点麻烦了呢?那怎么解决呢?
答:我们都知道了多少位转多少位了,那不是意味着他俩的关系就确定了,是吧,我们可以用 计数器 来做呀!!!
计数器计数,计到一定的数值之后,就对我们暂存的数进行拼接,之后输出。
解题思路:
首先,需要有个计数器计数(为什么该题以为计数器就行?因为我们一共就需要计2个数呀!!!),注意的是只有当输入valid_in 有效才计数,否则都是保持,同时呢,因为两个8位才能实现一个16位嘛,所以需要给先采进来的8位数据暂存起来,之后等到下一个8位数据之后一起给它输出出去。
代码实现:
`timescale 1ns/1ns
module width_8to16(
input clk ,
input rst_n ,
input valid_in ,
input [7:0] data_in ,
output reg valid_out,
output reg [15:0] data_out
);
reg count;
reg [7:0] temp_data;
//counter
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
count <= 0;
end
else begin
if(valid_in) begin
count <= count + 1;
end
end
end
//convert
always @ (posedge clk or rst_n) begin
if(!rst_n) begin
valid_out <= 0;
data_out <= 0;
end
else begin
if(valid_in) begin
if(count == 0) begin
temp_data <= data_in;
valid_out <= 0;
end
else begin
data_out <= {temp_data, data_in};
valid_out <= 1;
end
end
else begin
valid_out <= 0;
end
end
end
endmodule
解题思路:
其实和上一个题思路差不多,只不过这个题它不是整数转换了,而是非整数!
首先也是计数器,这次需要2位,为什么?3个8位数据可以拼成2个12位数据,需要计数三次,两位足够!
其次就是需要进行拼接操作了,参见代码就可以!
代码实现:
`timescale 1ns/1ns
module width_8to12(
input clk ,
input rst_n ,
input valid_in ,
input [7:0] data_in ,
output reg valid_out,
output reg [11:0] data_out
);
reg [1:0] count;
reg [7:0] data_reg;
//counter
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
count <= 0;
end
else begin
if(valid_in) begin
if(count == 2) begin //3个8位数据可以拼成2个12位数据
count <= 2'b0;
end
else begin
count <= count + 1;
end
end
end
end
//convert
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
valid_out <= 0;
data_out <= 0;
data_reg <= 0;
end
else begin
if(valid_in) begin
case(count)
2'b00 : begin //注意加 begin - end
data_reg <= data_in;
valid_out <= 0;
end
2'b01 : begin
data_out <= {data_reg, data_in[7:4]};
data_reg[3:0] <= data_in[3:0];
valid_out <= 1;
end
2'b10 : begin
data_out <= {data_reg[3:0], data_in};
valid_out <= 1;
end
default : begin
valid_out <= 0;
data_out <= 0;
data_reg <= 0;
end
endcase
end
else begin
valid_out <= 0;
end
end
end
endmodule
解题思路:
同样的,也是通过计数器实现,该题 16个24位数据可以拼成3个128位数据,所以需要16位计数器,剩下的我也不详细写了,参考上一个题就完全可以写出来的。
代码实现:
`timescale 1ns/1ns
module 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] count; //16个24位数据可以拼成3个128位数据
// reg [23:0] data_reg;
reg [127:0] data_out_reg;
//counter
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
count <= 4'b0;
end
else begin
if(valid_in) begin
count <= count + 1;
end
end
end
//convert
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
valid_out <= 0;
data_out <= 0;
data_out_reg <= 0;
end
else begin
if(valid_in) begin
case(count)
4'b0000 : begin //注意加 begin - end
data_out_reg[127:104] <= data_in;
valid_out <= 0;
end
4'b0001 : begin
data_out_reg[103:80] <= data_in;
valid_out <= 0;
end
4'b0010 : begin
data_out_reg[79:56] <= data_in;
valid_out <= 0;
end
4'b0011 : begin
data_out_reg[55:32] <= data_in;
valid_out <= 0;
end
4'b0100 : begin
data_out_reg[31:8] <= data_in;
valid_out <= 0;
end
4'b0101 : begin
data_out <= {data_out_reg[127:8], data_in[23:16]};
data_out_reg[127:112] <= data_in[15:0];
valid_out <= 1;
end
4'b0110 : begin
data_out_reg[111:88] <= data_in;
valid_out <= 0;
end
4'b0111 : begin
data_out_reg[87:64] <= data_in;
valid_out <= 0;
end
4'b1000 : begin
data_out_reg[63:40] <= data_in;
valid_out <= 0;
end
4'b1001 : begin
data_out_reg[39:16] <= data_in;
valid_out <= 0;
end
4'b1010 : begin
data_out <= {data_out_reg[127:16], data_in[23:8]};
data_out_reg[127:120] <= data_in[7:0];
valid_out <= 1;
end
4'b1011 : begin
data_out_reg[119:96] <= data_in;
valid_out <= 0;
end
4'b1100 : begin
data_out_reg[95:72] <= data_in;
valid_out <= 0;
end
4'b1101 : begin
data_out_reg[71:48] <= data_in;
valid_out <= 0;
end
4'b1110 : begin
data_out_reg[47:24] <= data_in;
valid_out <= 0;
end
4'b1111 : begin
data_out <= {data_out_reg[127:24], data_in};
valid_out <= 1;
end
default : begin
valid_out <= 0;
data_out <= 0;
data_out_reg <= 0;
end
endcase
end
else begin
valid_out <= 0;
end
end
end
endmodule
持续更新中…