简析
输入:data_in[7:0] , valid_a, ready_b
输出:data_out[9:0], ready_a, valid_b
- 数据端口:输入数据
data_in
,输出数据data_out
; - 上游握手信号:上游输入的数据是否有效
valid_a
,向上游发送本模块是否准备好接受ready_a
; - 下游握手信号:本模块输出的数据是否有效
valid_b
,下游是否准备好接受ready_b
。
首先设置一个计数器cnt
用来指示有效数据的数量。cnt
应只在输入有效且模块当前可以接收数据的状态工作。
reg [1:0] cnt;
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
cnt <= 0;
else
cnt <= valid_a&&ready_a? cnt+1: cnt;
end
当输入的有效数据达到4个时,输出数据有效,valid_b==1
,模块暂停数据输入和更新;当下游将数据取走后,也就是ready_b==1
时,valid==0
,模块继续工作。
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
valid_b <= 0;
else if(~valid_b)
valid_b <= cnt==3;
else
valid_b <= ready_b==0;
end
当输出数据有效并且尚未被下游读取时,模块尚未准备好接受新数据,此时ready_a==0
。同时,通过多次仿真发现ready_a
可以在非时钟边沿变化,所以是组合逻辑。
assign ready_a = ~(valid_b&&~ready_b);
最后,输出的数据data_out
,当输入数据无效或者模块还未准备好接收数据时,data_out
保持;当计数器清零时,输入新的数据;当正常工作时,data_out
与输入数据累加。
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
data_out <= 0;
else if(~valid_a||~ready_a)
data_out <= data_out;
else if(cnt==0)
data_out <= data_in;
else
data_out <= data_out+data_in;
end
代码
`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@(posedge clk or negedge rst_n) begin
if(~rst_n)
cnt <= 0;
else
cnt <= valid_a&&ready_a? cnt+1: cnt;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
data_out <= 0;
else if(~valid_a||~ready_a)
data_out <= data_out;
else if(cnt==0)
data_out <= data_in;
else
data_out <= data_out+data_in;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
valid_b <= 0;
else if(~valid_b)
valid_b <= cnt==3;
else
valid_b <= ready_b==0;
end
assign ready_a = ~(valid_b&&~ready_b);
endmodule