提交代码:
考虑情况全面
(1)valid-ready双向握手机制:上游正常通讯时(即valid_a和ready_a均为高)
(2)data_out: 同理,当和上游正常通讯时(即valid_a和ready_a均为高),数据正常接收,数据累加,当计数器data_cnt == 2'd0表示需要从头再加,清零,但注意需要等到ready_b拉高,表示下游接收完成才能清空重新累加。
`timescale 1ns/1ns
module valid_ready(
input clk ,
input rst_n ,
input [7:0] data_in ,
input valid_a ,
input ready_b ,
output ready_a ,
output reg valid_b ,
output reg [9:0] data_out
);
reg [1:0]cnt;
always@(negedge rst_n, posedge clk)begin
if(~rst_n)
cnt <= 0;
else if(valid_a && ready_a)
//valid_a和ready_a同时拉高,valid_a数据有效,ready_a数据准备好,说明上游数据正常,计数器计数
cnt <= cnt == 3 ? 0 : cnt + 1;
end
//在data_out准备好,valid_b拉高时,如果下游的ready_b为低,表示下游此时不能接收本模块的数据,那么,将会拉低ready_a,以反压上游数据输入;
assign ready_a = ~valid_b || ready_b;
always@(negedge rst_n, posedge clk) begin
if (~rst_n)
valid_b <= 0;
else if (cnt == 3 && valid_a && ready_a)
//完成4个数累加同时上游数据正常
valid_b <= 1;
else if(valid_b && ready_b)
//当下游ready_b拉高,且valid_b为高,表示模块与下游握手成功,valid_b在下一个时钟周期拉低;
valid_b <= 0;
end
always@(negedge rst_n, posedge clk) begin
if(~rst_n)
data_out <= 0;
else if (ready_b && cnt == 0 && ready_a && valid_a)
data_out <= {2'b00, data_in};
else if (ready_a && valid_a)
data_out <= data_out + data_in;
end
endmodule
tb文件
`timescale 1ns/1ns
module testbench();
initial begin
#50 $finish;
end
//波形图必须输出到out.vcd
initial begin
$dumpfile("out.vcd"); // 波形图必须输出到out.vcd
$dumpvars(0, testbench);
end
reg clk, rst_n, valid_a, ready_b;
reg [7:0]data_in;
wire ready_a, valid_b;
wire [9:0] data_out;
initial begin
rst_n = 0;
clk = 0;
valid_a = 1;
#2 rst_n = 1;
end
always #1 clk = ~clk;
initial begin
ready_b = 0;
#17 ready_b = 1;
end
always@(negedge rst_n, posedge clk) begin
if (~rst_n)
data_in <= 1;
else
data_in <= data_in + 1;
end
valid_ready dut(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.valid_a(valid_a),
.ready_b(ready_b),
.ready_a(ready_a),
.valid_b(valid_b),
.data_out(data_out)
);
endmodule