题解 | #数据累加输出#
数据累加输出
https://www.nowcoder.com/practice/956fa4fa03e4441d85262dc1ec46a3bd
`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 , output reg [1:0] cnt ); //===================================================== /*这道题有两个注意点: 1)对于握手信号这一类的题目,在编写内部握手信号产生逻辑、数据产生逻辑时,一定要注意使用一对握手信号的作为核心判断依据。 比如该题中,使用 (valid_a & ready_a) 以及 (valid_b & ready_b) 作为两个核心判断条件,来产生其他的信号。 2)在该题中,判断数据的更新时候,要注意:将判断数据是否开始接收下一轮输入的条件放在第一个if分支中,然后再判断数据的累加情况。 这是因为,在输出开始接收新的输入时,可能会满足 (valid_a & ready_a)和(valid_b & ready_b)同时拉高; 但是数据累加情况是只有(valid_a & ready_a)拉高时才能进行的。若把累加情况的分支放在第一个,在本该接收新输入时,就会出现,Verilog找到第一个符合的条件,就跳出分支, 结果执行的是累加而不是接收输入。 */ //===================================================== wire rec_st; wire tra_st; assign rec_st = (valid_a & ready_a); assign tra_st = (valid_b & ready_b); // 四个数据,0-3,计数到3之后,会覆盖原数据从0重新开始计数, // 所以这里不用写其归零逻辑 // reg [1:0] cnt; always @(posedge clk or negedge rst_n) begin if(~rst_n) begin cnt <= 2'b00; end else begin // if(rec_st) // cnt <= (cnt==2'b11)? 2'b00 : cnt+1'b1; // else // cnt <= cnt; cnt <= rec_st? cnt+1'b1 : cnt; end end // assign ready_a = (~valid_b | tra_st); // valid_b always @(posedge clk or negedge rst_n) begin if(~rst_n) begin valid_b <= 1'b0; end else begin if(cnt==2'b11 && rec_st) valid_b <= 1'b1; else if(tra_st) valid_b <= 1'b0; else valid_b <= valid_b; end end // data_out always @(posedge clk or negedge rst_n) begin if(~rst_n) begin data_out <= 10'd0; end else begin // if(rec_st) // data_out <= data_out+data_in; // else if(tra_st && cnt==2'b00) // // 这里判断条件加上 cnt=2'b00,是考虑到ready_b比valid_b提前拉高的情况 // data_out <= data_in; // else // data_out <= data_out; if(tra_st && cnt==2'b00) data_out <= data_in; else if(rec_st) data_out <= data_out+data_in; else data_out <= data_out; end end endmodule
testbench:
`timescale 1ns/1ns module 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; wire [1:0] cnt; always#5 clk = ~clk; initial begin clk = 1'b1; rst_n = 1'b0; data_in = 'b0; valid_a = 1'b0; ready_b = 1'b0; #10 rst_n = 1'b1; #30; valid_a = 1'b1; data_in = 'd1; #10; data_in = 'd2; #10; data_in = 'd3; #10; data_in = 'd4; #10; data_in = 'd5; #20; ready_b = 1'b1; #10; data_in = 'd2; #10; data_in = 'd7; #10; data_in = 'd8; #10; valid_a = 1'b0; #20; $finish(); end valid_ready u_valid_ready( .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 ), .cnt (cnt) ); endmodule