介绍
本题目来源为牛客网中在线编程>verilog模块,要求实现串行输入数据累加输出,输入端输入8bit数据,每当模块接收到4个输入数据后,输出端输出4个接收到数据的累加结果。输入端和输出端与上下游的交互采用valid-ready双向握手机制。要求上下游均能满速传输时,数据传输无气泡,不能由于本模块的设计原因产生额外的性能损失。
电路的接口如下图所示。valid_a用来指示数据输入data_in的有效性,valid_b用来指示数据输出data_out的有效性;ready_a用来指示本模块是否准备好接收上游数据,ready_b表示下游是否准备好接收本模块的输出数据;clk是时钟信号;rst_n是异步复位信号。
思路分析
- 首先,由时序可知,要在输入四个有效数据以后才输出一个累加结果,为此可以用一个计数器对输入的数计数,当计数到4个有效数据以后,且此时模块已经准备好接受上游数据,即reay_a为高,拉高valid_b。
- 当在S1阶段时,此时若ready_b为低,即下游模块没有准备好继续接受上游传输过来的数据,那么会立即拉低ready_a信号,即阻止上游继续传输数据。
- 在S2阶段,ready_b被拉高,那么为了实现无气泡传输,ready_a应该也立即拉高,继续接受上游数据。
- 对于ready_a,当valid_b信号为低,表明此时未接受到4个有效数据,仍可以继续接受上游数据,即ready_a为高,或者当ready_b拉高时,ready_a也应该为高。
代码实现
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;
//ready_a
assign ready_a = !valid_b | ready_b;
//计数
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 0;
else if (valid_a && ready_a)
cnt <= (cnt == 2'd3)? 2'd0 : (cnt + 1'd1);
end
//valid_b signal
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
valid_b <= 0;
else if (cnt == 2'd3 && valid_a && ready_a)
valid_b <= 1;
else if (valid_b && ready_b)
valid_b <= 0;
end
//data
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
data_out <= 10'd0;
else if (ready_b && valid_a && valid_b && (cnt == 2'd0))
data_out <= data_in;
else if (valid_a && ready_a)
data_out <= data_out +data_in;
end
endmodule