赞
踩
握手信号,就是为了模块之间的数据交互正确才衍生出来的信号。其无非就是三种可能
对于master来说,master发出一个数据,如果数据有效,master就会把传送给slave的valid信号拉高,即告诉slave数据有效可以接收!如果slave准备好了,slave就把传送给master的ready信号拉高,告诉master我准备好了,如果你数据有效,我就可以接收!所以当master传输的数据有效,且slave也准备好时,数据就会在下一个周期被slave取走,master可以接着传下一个数据。
代码:
`timescale 1ns/1ns module handshake( input clk, input rst_n, input valid_i, input [7:0] data_i, output ready_o, output [7:0]data_o, input ready_i, output valid_o ); reg [7:0] data_o_r; reg valid_o_r; assign ready_o = ready_i; // 下游准备好时,此模块也准备好接收上游数据 always@(posedge clk or negedge rst_n)begin if(!rst_n) data_o_r <= 8'b0; else if(valid_i && ready_i) //如果下游准备好了,并且上游数据有效,那就把输入的数据乘以二输出 data_o_r <= data_i * 2; end always@(posedge clk or negedge rst_n)begin if(!rst_n) valid_o_r <= 1'b0; else if(ready_o) valid_o_r <= valid_i; //如果准备好了,就把上游的valid传递给下游。 end assign data_o = data_o_r; assign valid_o = valid_o_r; endmodule
Testbench:
`timescale 1ns/1ns module handshake_tb(); reg clk; reg rst_n; reg valid_i; reg[7:0] data_i; wire ready_o; wire [7:0]data_o; reg ready_i; wire valid_o; handshake inst( .clk(clk), .rst_n(rst_n), .valid_i(valid_i), .data_i(data_i), .ready_o(ready_o), .data_o(data_o), .ready_i(ready_i), .valid_o(valid_o) ); always #10 clk = ~clk; initial begin clk = 0; rst_n = 0; data_i = 8'd0; valid_i = 1'b0; ready_i = 1'b1; #15 rst_n = 1; #15 rst_n <= 1'b1; ready_i <= 1'b1; //下游准备好了 valid_i <= 1'b0; //上游数据无效 data_i <= 8'b0000_1000; #20 data_i <= 8'b0111_1000; valid_i <= 1'b1; //上游数据有效 #20 data_i <= 8'b0100_0100; #20 valid_i <= 1'b0; #20 data_i <= 8'b0010_0100; valid_i <= 1'b1; //虽然上游数据有效,但下游没准备好 ready_i <= 1'b0; #20 ready_i <= 1'b1; //上游数据有效,下游准备好了 #20 valid_i <= 1'b0; #500 $stop(); end endmodule
用tb来模拟本模块的上游master和下游slave,用tb给本模块提供上游数据data_i和valid_i信号。分别模拟了上游断流,即valid_i中途拉低,以及下游反压,即ready_i中途为低的情况。
仿真结果:
实现串并转换电路,输入端输入单bit数据,每当本模块接收到6个输入数据后,输出端输出拼接后的6bit数据。本模块输入端与上游的采用valid-ready双向握手机制,输出端与下游采用valid-only握手机制。数据拼接时先接收到的数据放到data_b的低位。
电路的接口如下图所示。valid_a用来指示数据输入data_a的有效性,valid_b用来指示数据输出data_b的有效性;ready_a用来指示本模块是否准备好接收上游数据,本模块中一直拉高;clk是时钟信号;rst_n是异步复位信号。
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 ); always@(posedge clk or negedge rst_n)begin if(!rst_n) ready_a = 1'b0; else ready_a = 1'b1; end reg[2:0]cnt; always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 3'd0; else if(valid_a && ready_a) cnt <= (cnt == 3'd5)?3'd0:cnt + 1'b1; else cnt <= cnt; end reg [5:0] data_b_r; always@(posedge clk or negedge rst_n)begin if(!rst_n) data_b_r <= 6'd0; else if(valid_a && ready_a) data_b_r <= {data_a,data_b_r[5:1]}; end always@(posedge clk or negedge rst_n)begin if(!rst_n)begin data_b <= 6'd0; valid_b <= 1'b0; end else if(cnt == 3'd5)begin data_b <= {data_a,data_b_r[5:1]}; valid_b <= 1'b1; end else valid_b <= 1'b0; end endmodule
Testbench:
`timescale 1ns/1ns module s_to_p_tb(); reg clk; reg rst_n; reg valid_a; reg data_a; wire ready_a; wire valid_b; wire[5:0] data_b; s_to_p inst( .clk(clk), .rst_n(rst_n), .valid_a(valid_a), .data_a(data_a), .ready_a(ready_a), .valid_b(valid_b), .data_b(data_b) ); always #10 clk = ~clk; initial begin clk= 0; rst_n = 0; valid_a = 0; data_a = 0; #15 rst_n = 1; #15 valid_a = 1; data_a = 1; #20 data_a = 0; #20 data_a = 1; #20 data_a = 0; #20 data_a = 0; #20 data_a = 1; #20 data_a = 1; #20 valid_a = 0; #40 valid_a = 1; #40 data_a = 0; #40 data_a = 1; #20 data_a = 0; #200 $stop; end endmodule
仿真结果:
实现串行输入数据累加输出,输入端输入8bit数据,每当模块接收到4个输入数据后,输出端输出4个接收到数据的累加结果。输入端和输出端与上下游的交互采用valid-ready双向握手机制。要求上下游均能满速传输时,数据传输无气泡,不能由于本模块的设计原因产生额外的性能损失。
电路的接口如下图所示。valid_a用来指示数据输入data_in的有效性,valid_b用来指示数据输出data_out的有效性;ready_a用来指示本模块是否准备好接收上游数据,ready_b表示下游是否准备好接收本模块的输出数据;clk是时钟信号;rst_n是异步复位信号。
代码:
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 = !valid_b || ready_b; reg [1:0]cnt; always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 2'd0; else if(valid_a && ready_a) cnt <= (cnt == 2'd3)?2'd0:cnt + 1'd1; end always@(posedge clk or negedge rst_n)begin if(!rst_n) valid_b <= 1'b0; else if(cnt == 2'd3 && valid_a && ready_a) valid_b <= 1'b1; else if(valid_b && ready_b) valid_b <= 1'b0; end always@(posedge clk or negedge rst_n)begin if(!rst_n) data_out <= 10'd0; else if(cnt == 2'd0 && valid_a && ready_a && ready_b) data_out <= data_in; else if(valid_a && ready_a) data_out <= data_in + data_out; end endmodule
Testbench:
`timescale 1ns/1ns module valid_ready_tb(); reg clk; reg rst_n; reg [7:0] data_in; reg valid_a; reg ready_b; wire ready_a; wire valid_b; wire [9:0] data_out; valid_ready inst( .clk(clk), .rst_n(rst_n), .data_in(data_in), .valid_a(valid_a), .ready_b(ready_b), .ready_a(ready_a), .valid_b(valid_b), .data_out(data_out) ); always #10 clk= ~clk; initial begin clk = 0; rst_n = 0; ready_b = 0; #15 rst_n = 1; #15 valid_a = 1; data_in = 1; #20 data_in = 2; #20 data_in = 3; #20 data_in = 4; #20 data_in = 5; #40 ready_b = 1; #200 $stop; end endmodule
仿真结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。