题目描述:
实现串并转换电路,输入端输入单bit数据,每当本模块接收到6个输入数据后,输出端输出拼接后的6bit数据。本模块输入端与上游的采用valid-ready双向握手机制,输出端与下游采用valid-only握手机制。数据拼接时先接收到的数据放到data_b的低位。
电路的接口如下图所示。valid_a用来指示数据输入data_a的有效性,valid_b用来指示数据输出data_b的有效性;ready_a用来指示本模块是否准备好接收上游数据,本模块中一直拉高;clk是时钟信号;rst_n是异步复位信号。
个人理解:
从题目和波形图可看出,valid_a默认为低电平,当valid_a拉高时data_a的输入有效。先输入的data_a为data_b的低位。串并转换需要设置一个计数器,当计数个数为6个时valid_b拉高的同时data_b输出数据。ready_a=1默认模块有效,这里拉高就行了。
PS:
l data_b是在已接收到6个数据后下一个时钟产生输出;
l 本模块与上游采用valid_ready握手机制,当valid_a拉低,表示与上游握手未成功,则此时data_a的数据无效,不存入本模块当中;
l 本模块与下游采用valid_only握手机制,这是一种单向指示性握手机制,已接收到6个数据后,valid_b拉高一个时钟周期,指示输出数据有效性
代码:
`timescale 1ns / 1ns
module test(
input clk ,
input rst_n ,
input valid_a ,
input data_a ,
output reg ready_a ,
output reg valid_b ,
output reg [5:0] data_b
);
//计数
reg [2:0]cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt<=0;
else begin
//if(!valid_b)begin
if(valid_a&&ready_a)begin
if(cnt>=5)
cnt<=0;
else
cnt<=cnt+1;
end
else
cnt<=cnt;
//end
// else
// cnt<=0;
end
end
//使用移位寄存器实现串转并
reg [5:0] data_reg;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_reg<=0;
else begin
//if(!valid_b)begin
if(valid_a&&ready_a)
data_reg<={data_a,data_reg[5:1]};
else
data_reg<=data_reg;
end
//else
// data_reg<=data_reg;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
valid_b<=0;
else
valid_b<=(cnt==5)?1:0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_b<=0;
else begin
if(cnt==5)
data_b<={data_a,data_reg[5:1]};
else
data_b<=data_b;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
ready_a<=0;
else
ready_a<=1;
end
endmodule
tb:
`timescale 1ns / 1ns
`define CLK_PERIOD_100M 10
module test_tb();
//声明接口
reg clk;
reg rst_n;
reg valid_a;
reg data_a;
wire ready_a;
wire valid_b;
wire [5:0] data_b;
//例化待测试模块
test inst_s_to_p
(
.clk (clk),
.rst_n (rst_n),
.valid_a (valid_a),
.data_a (data_a),
.ready_a (ready_a),
.valid_b (valid_b),
.data_b (data_b)
);
//产生复位和时钟
//对复位和时钟进行初始化
initial begin
clk <= 0;
rst_n <= 0;
#1000;
rst_n <= 1;
end
//产生时钟
always #(`CLK_PERIOD_100M/2) clk = ~clk;
//定义二维数组
//读取文本文件到二维数组
//产生测试激励信号
initial begin
valid_a <= 0;
data_a <= 0;
@(posedge rst_n);
@(posedge clk);
gen_data101010();
@(posedge clk);
gen_data111000();
@(posedge clk);
gen_data000111();
gen_data101010();
gen_data111000();
#1000;
$fclose("file_goden");
$fclose("file_test");
$stop;
end
//定义task
task gen_data101010;
begin
valid_a <= 1;
data_a <= 1;
@(posedge clk);
data_a <= 0;
@(posedge clk);
data_a <= 1;
@(posedge clk);
data_a <= 0;
@(posedge clk);
data_a <= 1;
@(posedge clk);
data_a <= 0;
@(posedge clk);
valid_a <= 0;
end
endtask
task gen_data111000;
begin
valid_a <= 1;
data_a <= 1;
@(posedge clk);
data_a <= 1;
@(posedge clk);
data_a <= 1;
@(posedge clk);
data_a <= 0;
@(posedge clk);
data_a <= 0;
@(posedge clk);
data_a <= 0;
@(posedge clk);
valid_a <= 0;
end
endtask
task gen_data000111;
begin
valid_a <= 1;
data_a <= 0;
@(posedge clk);
data_a <= 0;
@(posedge clk);
data_a <= 0;
@(posedge clk);
data_a <= 1;
@(posedge clk);
data_a <= 1;
@(posedge clk);
data_a <= 1;
@(posedge clk);
valid_a <= 0;
end
endtask
//打开文件
integer file_goden,file_test;
initial file_goden = $fopen("./output_file/file_goden.txt","w");
initial file_test = $fopen("./output_file/file_test.txt","w");
//写入数据
always@(posedge clk) begin
if(valid_a) $fwrite(file_goden,"%b\n",data_a);
end
always@(posedge clk) begin
if(valid_b)begin
$fwrite(file_test,"%b\n",data_b[5]);
$fwrite(file_test,"%b\n",data_b[4]);
$fwrite(file_test,"%b\n",data_b[3]);
$fwrite(file_test,"%b\n",data_b[2]);
$fwrite(file_test,"%b\n",data_b[1]);
$fwrite(file_test,"%b\n",data_b[0]);
end
end
//对比数据打印结果
endmodule
仿真波形: