题解 | #数据串转并电路#
数据串转并电路
https://www.nowcoder.com/practice/6134dc3c8d0741d08eb522542913583d
`timescale 1ns/1ns 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 ); //===========================================================// // 错误总结: /* 昨晚犯困的时候, 1. 计数器没做复位操作。计数器一直在计数,没有考虑到3'd5的时候归零。 2. ready信号恒拉高,逻辑错误。这种寄存器逻辑必须要有复位值,不然给出的值就是不定态。再者,根据报错,这里的ready_a信号是受clk同步约束的,这里需要用时序逻辑拉高ready_a 3. 位拼接逻辑混淆。这里这道题的题意也比较混淆,题目中说是到来的数据放到最低位,但是其实根据时序图,如果数据寄存器为小端定义的话,比如data_b[5:0],应该是先来的数据放在最高位,然后向右移位拼接。 4. 最后一段寄存器逻辑,数据更新的判断条件。根据时序图,data_b和valid_b是同时更新的,我的想法是data_b用组合逻辑写,valid_b用时序逻辑同步,这样valid_b的值能够被data_b及时判断到,但是valid_b的更新要晚一拍。 这样想当然对,而且也符合valid_b约束data_b的关系。 但是我在写的时候还是讲判断条件写成valid_b的更新判断条件了(计数器计满),导致data_b更新提前一个时钟周期。如果使用时序逻辑输出是可以这样判断的。 */ //===========================================================// // bit计数器 reg [2:0] cnt; always @(posedge clk or negedge rst_n) begin if(~rst_n) begin cnt <= 3'b0; end else begin cnt <= valid_a? ((cnt==3'd5)? 3'd0 : cnt+1'b1) : cnt; end end // always ready always @(posedge clk or negedge rst_n) begin if(~rst_n) ready_a <= 1'b0; else ready_a <= 1'b1; end // 输出的valid逻辑 always @(posedge clk or negedge rst_n) begin if(~rst_n) valid_b <= 1'b0; else valid_b <= (cnt==3'd5); end reg [5:0] data_tmp; // 数据接收与拼接 always @(posedge clk or negedge rst_n) begin if(~rst_n) begin data_tmp <= 6'b0; end else begin data_tmp <= valid_a? {data_a, data_tmp[5:1]} : data_tmp; end end always @(*) begin if(~rst_n) data_b = 6'b0; else data_b = (valid_b)? data_tmp : data_b; end endmodule
testbench:
`timescale 1ns/1ns module tb; reg clk; reg rst_n; reg valid_a; reg data_a; wire ready_a; wire valid_b; wire [5:0] data_b; initial begin clk = 1'b1; rst_n = 1'b0; valid_a = 1'b0; data_a = 1'b0; #20; rst_n = 1'b1; #20; valid_a = 1'b1; data_a = 1'b1; #10; data_a = 1'b0; #10; data_a = 1'b1; #10; data_a = 1'b0; #20; data_a = 1'b1; #20; valid_a = 1'b0; #20; valid_a = 1'b1; #20; data_a = 1'b0; #20; data_a = 1'b1; #10; data_a = 1'b0; #100; $finish(); end // 10ns period always#5 clk = ~clk; s_to_p u_s_to_p( .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 ) ); endmodule