实现串行输入数据累加输出,输入端输入8bit数据,每当模块接收到4个输入数据后,输出端输出4个接收到数据的累加结果。输入端和输出端与上下游的交互采用valid-ready双向握手机制。要求上下游均能满速传输时,数据传输无气泡,不能由于本模块的设计原因产生额外的性能损失。
电路的接口如下图所示。valid_a用来指示数据输入data_in的有效性,valid_b用来指示数据输出data_out的有效性;ready_a用来指示本模块是否准备好接收上游数据,ready_b表示下游是否准备好接收本模块的输出数据;clk是时钟信号;rst_n是异步复位信号。
接口时序示意图
输入描述:
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
本题要求实现将4个输入数据累加之后输出,模块与上下游采用valid-ready双向握手机制。
时序图含有的信息较多,观察时序图需要注意:
l data_out是在已接收到4个数据后产生输出;
l 在data_out准备好,valid_b拉高时,如果下游的ready_b为低,表示下游此时不能接收本模块的数据,那么,将会拉低ready_a,以反压上游数据输入;
l 当下游ready_b拉高,且valid_b为高,表示模块与下游握手成功,valid_b在下一个时钟周期拉低;
l 当下游ready_b拉高,本来由于之前ready_b为低而反压上游的ready_a立即拉高,开始接收上游数据,注意,此细节,也是体现了题目要求的数据传输无气泡。如果ready_a不是立即拉高,而是在下一个时钟周期拉高,那么本模块将会在下游握手成功后空一个时钟周期,才能开始接收上游数据,这样是不满足题目要求的。
题解主体
要实现4个输入数据的累加,要用1个寄存器将先到达的数据累加之后进行缓存。当上游握手成功,将输入数据累加进寄存器;当累加完4个输入数据,且下游握手成功,将新的输入数据缓存进寄存器。注意,之所以这样设计,是为了不造成性能损失,而之前的累加结果,已经传给了下游。
需要计数器来计数接收到的数据数量,计数器在0-3之间循环。计数器初始值是0,每接收一个数据,计数器加1,当计数器再次循环到0时,表示已经接收到4个数据,可以输出累加结果。
对于ready_a输出信号的产生,如果下游ready_b拉高,表示下游可以接收模块输出数据,那么此时ready_a应拉高,即本模块可以接收上游数据;如果没有接收够4个数据,即valid_b未拉高,那么表示本模块仍可以接收上游数据此时ready_a应拉高。所以综上所述,ready_a信号的产生采用组合逻辑产生。
`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 [2:0] cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else begin
if(valid_a && ready_a)begin
if(cnt == 3)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_out <= 0;
else begin
//别忘了每一次循环要重新赋初值
if(ready_b && valid_a && ready_a && (cnt == 2'd0))
data_out <= data_in;
else if ((cnt <= 3 ) && ready_a && valid_a)
data_out <= data_out + data_in;
else
data_out <= data_out;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
valid_b <= 0;
else begin
if(cnt == 3)
valid_b <= 1;
else if(ready_b)
valid_b <= 0;
else
valid_b <= valid_b;
end
end
注意这里的条件
//assign ready_a = valid_b && (!ready_b);
assign ready_a = !valid_b | ready_b;
endmodule