数据位宽转换器
数据位宽转换器,一般常用于模块接口处,比如一个电路模块的输出数据位宽大于另一个模块的输入数据位宽,此时就需要进行数据位宽转换。比如SATA控制器中,内部数据位宽为32bit,但外部物理收发器PHY的接口通常为16bit,或者8bit,在不使用FIFO进行缓存的情况下,可以使用数据位宽转换器,通过时钟倍频在实现数据位宽的转换。
宽到窄
假设数据从模块A传入到模块B,模块A的输出数据为32位,模块B的输入数据位宽为16位,并把数据从A传入B而不损失数据。
假设一个原时钟clk2x,通过二分频,把原时钟变为时钟clk1x,那么clk2x的时钟频率就是clk1x的两倍。在clk2x的上升沿,我们读入32bit数据,在clk2x的上升沿我们输出16bit数据,由于clk2x的频率是clk1x的两倍,每读入一次32bit数据,就会输出两次16bit数据,从而实现了数据位宽的转换,如图:
module width_32to16(
input clk,
input rst_n,
input [31:0] data_in,
output [15:0] data_out
);
reg clk1;
reg [31:0] data_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
clk1 <= 1'b1;
else
clk1 <= ~clk1;
end
always@(posedge clk1 or negedge rst_n)begin
if(!rst_n)
data_r <= 31'd0;
else
data_r <= data_in;
end
assign data_out = clk1?data_r[31:16]:data_r[15:0];
endmodule
Testbench:
`timescale 1ns/1ns
module width_32to16_tb();
reg clk;
reg rst_n;
reg [31:0]data_in;
wire [15:0]data_out;
width_32to16 inst(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.data_out(data_out)
);
always #10 clk = ~clk;
initial begin
clk =0;
rst_n = 0;
data_in = 32'h0000_0000;
#10
rst_n = 1;
#5
data_in = 32'h0000_1111;
#50
data_in = 32'h2222_3333;
#50
data_in = 32'h4444_5555;
#50
data_in = 32'h6666_7777;
#200
$stop;
end
endmodule
仿真结果:
窄到宽
8bit to 16bit
实现数据位宽转换电路,实现8bit数据输入转换为16bit数据输出。其中,先到的8bit数据应置于输出16bit的高8位。
电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号
代码:
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 [1:0]cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 2'b0;
else if(valid_in)
cnt <= (cnt == 1'd1)?1'd0:cnt + 1'b1;
else
cnt <= cnt;
end
reg [7:0]data_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_r <= 8'd0;
else
data_r <= valid_in?data_in:data_r;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_out <= 16'd0;
valid_out <= 1'b0;
end
else if(cnt == 1)begin
data_out <= valid_in?{data_r,data_in}:data_out;
valid_out <= valid_in;
end
else begin
data_out <= data_out;
valid_out <= 1'b0;
end
end
endmodule
Testbench:
module width_8to16_tb();
reg clk;
reg rst_n;
reg valid_in;
reg [7:0]data_in;
wire valid_out;
wire [15:0]data_out;
width_8to16 inst(
.clk(clk),
.rst_n(rst_n),
.valid_in(valid_in),
.data_in(data_in),
.valid_out(valid_out),
.data_out(data_out)
);
always #10 clk = ~clk;
initial begin
clk = 0;
rst_n = 0;
valid_in = 0;
data_in = 8'd0;
#15
rst_n = 1;
#5
valid_in = 1;
#20
data_in = 8'h11;
#20
data_in = 8'h22;
#20
data_in = 8'h33;
#20
valid_in = 0;
#20
valid_in = 1;
#20
data_in = 8'h44;
#20
data_in = 8'h55;
#200
$stop;
end
endmodule
仿真结果:
非整数倍转换
8bit to 12bit
代码:
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]cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(valid_in)
cnt <= cnt == 2?0:cnt + 1;
else
cnt <= cnt;
end
reg [7:0]data_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_r <= 0;
else
data_r <= valid_in?data_in:data_r;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_out <= 0;
else if(cnt == 1)
data_out <= valid_in?{data_r,data_in[7:4]}:data_out;
else if(cnt == 2)
data_out <= valid_in?{data_r[3:0],data_in}:data_out;
else
data_out <= data_out;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
valid_out <= 0;
else
valid_out <= (cnt == 1 || cnt == 2) && valid_in;
end
endmodule
Testbench:
module width_8to12_tb();
reg clk;
reg rst_n;
reg valid_in;
reg [7:0] data_in;
wire valid_out;
wire [11:0] data_out;
width_8to12 inst(
.clk(clk),
.rst_n(rst_n),
.valid_in(valid_in),
.data_in(data_in),
.valid_out(valid_out),
.data_out(data_out)
);
always #10 clk = ~clk;
initial begin
clk = 0;
rst_n = 0;
data_in = 0;
valid_in = 0;
#15
rst_n = 1;
#15
valid_in = 1;
data_in = 8'ha0;
#40
valid_in = 0;
data_in = 8'ha1;
#60
valid_in = 1;
#20
valid_in = 0;
data_in = 8'hb0;
#200
$stop;
end
endmodule
仿真结果:
24bit to 128bit
代码:
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]cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 4'd0;
else if(valid_in)
cnt <= (cnt == 4'd15)?0:cnt + 1'b1;
end
reg [127:0] data_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_r <= 128'd0;
else
data_r <= valid_in?{data_r[103:0],data_in}:data_r;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_out <= 128'd0;
else if(cnt == 4'd5)
data_out <= valid_in?{data_r[119:0],data_in[23:16]}:data_out;
else if(cnt == 4'd10)
data_out <= valid_in?{data_r[111:0],data_in[23:8]}:data_out;
else if(cnt == 4'd15)
data_out <= valid_in?{data_r[103:0],data_in[23:0]}:data_out;
else
data_out <= data_out;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
valid_out <= 1'd0;
else
valid_out <= (cnt == 4'd5 || cnt == 4'd10 || cnt == 4'd15) && valid_in;
end
endmodule
Testbench:文章来源:https://www.toymoban.com/news/detail-692503.html
module 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 inst(
.clk(clk),
.rst_n(rst_n),
.valid_in(valid_in),
.data_in(data_in),
.valid_out(valid_out),
.data_out(data_out)
);
always #10 clk = ~clk;
initial begin
clk = 0;
rst_n = 0;
valid_in = 0;
data_in = 0;
#15
rst_n = 1;
#15
valid_in = 1;
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
valid_in = 0;
#200
$stop;
end
endmodule
仿真结果:
文章来源地址https://www.toymoban.com/news/detail-692503.html
到了这里,关于Verilog手撕代码(7)数据位宽转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!