题解 | #数据串转并电路#

数据串转并电路

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

全部评论

相关推荐

不愿透露姓名的神秘牛友
07-01 12:22
点赞 评论 收藏
分享
07-01 23:23
郑州大学 Java
否极泰来来来来:牛客迟早有高三的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务