题意梳理
两组握手信号,分别是与上游的valid_a和ready_a、与下游的valid_b和ready_b; 需要说明的是每组的valid和ready之间没有先后关系,谁先谁后都行;
输出信号有三个:
①ready_a:为高表示我现在没啥事,告诉上游我准备好了,你可以发数据了;
②valid_b:为高表示给下游说我发数据了;
③data_out:给下游发的数据,配合valid_b,只有valid_b为高时,发送的才是有效数据。
那么分别来处理:
①ready_a: 如果下游ready_b拉高,表示下游可以接收模块输出数据,那么此时ready_a应拉高;同时,如果valid_b为低,表示4个数据还没收完,所以也拉高继续接收。
assign ready_a = ready_b | ~valid_b;
②valid_b: 当和上游正常通讯时(即valid_a和ready_a均为高),数据正常接收,但注意计数了4个就得加起来输出一次,所以data_cnt == 2'd3时拉高valid_b;而等待下游接收,即当ready_a也拉高表示接收完成,则拉低valid_b,保证只有在四个数之和的时候才拉高。
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
valid_b <= 1'b0;
else if(valid_a && ready_a && data_cnt == 2'd3)
valid_b <= 1'd1;
else if(valid_b && ready_b)
valid_b <= 1'd0;
end
③data_out: 同理,当和上游正常通讯时(即valid_a和ready_a均为高),数据正常接收,数据累加,当计数器data_cnt == 2'd0表示需要从头再加,清零,但注意需要等到ready_b拉高,表示下游接收完成才能清空重新累加。
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
data_out <= 10'b0;
else if(valid_a && ready_a && data_cnt == 2'd0 && ready_b)
data_out <= data_in;
else if(valid_a && ready_a)
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
);
assign ready_a = ready_b | ~valid_b;
reg [1:0] data_cnt;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
data_cnt <= 2'd0;
else if(valid_a && ready_a)
data_cnt <= data_cnt +2'd1;
else
data_cnt <= data_cnt;
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
valid_b <= 1'b0;
else if(valid_a && ready_a && data_cnt == 2'd3)
valid_b <= 1'd1;
else if(valid_b && ready_b)
valid_b <= 1'd0;
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
data_out <= 10'b0;
else if(valid_a && ready_a && data_cnt == 2'd0 && ready_b)
data_out <= data_in; //相当于清零,重新累加
else if(valid_a && ready_a)
data_out <= data_out + data_in;
end
endmodule