题解 | #数据串转并电路#
数据串转并电路
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

