发布时间:2023-11-28 08:30
目录
数据串转并
数据累加输出
最近笔试刷题,串并转换和数据累加都是常考点,做法如下
时序图含有的信息较多,观察时序图需要注意:
l data_b是在已接收到6个数据后下一个时钟产生输出;
l 本模块与上游采用valid_ready握手机制,当valid_a拉低,表示与上游握手未成功,则此时data_a的数据无效,不存入本模块当中;
l 本模块与下游采用valid_only握手机制,这是一种单向指示性握手机制,已接收到6个数据后,valid_b拉高一个时钟周期,指示输出数据有效性
要实现6个单bit输入数据的拼接,要用1个寄存器将先到达的数据缓存。当上游握手成功,将输入数据进寄存器,先收到的数据放在低位;当缓存好6个输入数据,valid_b拉高,输出data_b。
需要计数器来计数接收到的数据数量,计数器在0-5之间循环。计数器初始值是0,每接收一个数据,计数器加1,当计数器再次循环到0时,表示已经接收到6个数据,可以输出拼接结果。
module s_to_p(
input clk ,
input rst_n ,
input valid_a ,
input data_a ,
output reg ready_a ,
output reg valid_b ,
output reg [5:0] data_b
);
reg [5:0] data_reg;//数据缓存
reg [2:0] data_cnt;//计数数据个数
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
ready_a<=1'd0;//握手信号
end
else begin
ready_a<=1'd1;
end
end
always@(posedge clk or negedge rst_n)begin//计数6个数据
if(!rst_n)begin
data_cnt<=6'd0;
end
else if(ready_a && valid_a) begin
data_cnt<=(data_cnt==3'd5) ? 3'd0 : (data_cnt+3'd1);
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_reg<=6'd0;
end
else if(ready_a && valid_a) begin
data_reg<={data_a,data_reg[5:1]}; //缓存数据,按照从低到高
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
valid_b <= 'd0;
data_b <= 'd0;
end
else if(data_cnt==3'd5) begin
valid_b <= 1'd1; //输出指示信号
data_b <= {data_a,data_reg[5:1]};//将数据输出
end
else begin
valid_b <= 'd0;
end
end
endmodule
通过这个例子,我们不难总结出,串转并的思路:
(1)设计数据寄存器+计数器
(2)根据指示信号,根据串转并的数据个数,设置计数器计数个位
(3)根据指示信号,将串行数据移位存入寄存器
(4)当计数器达到数据个数时,将数据输出
同时也可以总结出,并转串的思路:
(1)设置数据寄存器+计数器
(2)根据指示信号,根据串转并的数据个数,设置计数器计数个位
(3)根据指示信号,将并行数据移位存入寄存器,输出寄存的数据的最低位
(4)当计数器达到数据个数时,将数据输出
时序图含有的信息较多,观察时序图需要注意:
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信号的产生采用组合逻辑产生。
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] data_cnt;
assign ready_a = !valid_b | ready_b;
always @(posedge clk or negedge rst_n ) begin
if(!rst_n)
data_cnt <= 'd0;
else if(valid_a && ready_a)//计数器累加4
data_cnt <= (data_cnt == 2'd3) ? 'd0 : (data_cnt + 1'd1);
end
always @(posedge clk or negedge rst_n ) begin
if(!rst_n)
valid_b <= 'd0;
else if(data_cnt == 2'd3 && valid_a && ready_a)//数据累加到4个
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 <= 'd0;
else if(ready_b && valid_a && ready_a && (data_cnt == 2'd0))//计数器为0
data_out <= data_in;//输入数据
else if(valid_a && ready_a)//数据有效
data_out <= data_out + data_in;//进行累加
end
endmodule
总结一下数据累加的方法:
(1)设置一个计数器,根据题目要求,设置计数个数和计数条件
(2)在计数器=0的时候,数据累加 :其实就是在clk下 data_out <= data_out + data_in;最后data_out就是累加值