前言
昨晚上做了联发科的数字IC笔试题,这道题没写好,特做个博客,记录一下。
在极短的时间内写一道代码题,又想要逻辑没有问题,在不经过仿真的情况下还是很困难的。
题目:
7、(15分)【简答题】如下图所示,按照图中的时序和数据格式示例,使用verilog编写一段数据格式转换的代码。其中,输入数据in_data的宽度为2个Bytes,按YU/YV的格式交替排列,Y和U或V各占1个Byte (Y在高Byte,U或V在低yte)。输出数据out_data的宽度为3个Bytes,格式为YUV(在高Byte,U在次高Byte,V在最低Byte),每2个Y的UV值相同(如Y0和Y1均对应U0V0, Y2和Y3均对应U2V2),valid信号为数据有效信号。
要求:输出和输入之间的延迟为2T且处理过程中不能丢失数据。
解答:
简单分析一下其实不难,但是如何在不仿真情况下理清时序关系,还有需要一定的基础。
在图中我们可以看到,out_valid和out_data输出延迟两个周期,且与时钟对齐。
有细心的小伙伴可能发现,输入数据的下降沿正好对着数据的中心,能够完美的采集到数据。如果代码中也要这样子去写,就要注意了其他信号都是上升沿触发,在时序上如何保持一致?容易出错且复杂这里就不推荐了。
整个题的关键就在使用中间信号,根据其高低电平,保存前后两个数据,然后再拼接。请看下面代码
/*
* @Author : CCL
* @Date : 2024-07-31 14:44:24
* @LastEditors : CCL
* @LastEditTime : 2024-07-31 15:19:01
* @FilePath : \abFPGA\ccl_prj\test\data_converter.v
* @Description : 数据转换
* Copyright (c) 2024 by CCL All Rights Reserved.
*/
module data_converter(
input clk,
input rst,
input [15:0] in_data,
input in_valid,
output [23:0] out_data,
output out_valid
);
reg [23:0] rout_data ;
reg rout_valid;
reg [ 7:0] Y;//寄存
reg [ 7:0] Y_;//寄存
reg [ 7:0] U;//寄存
reg [ 7:0] V;//寄存
reg en;//中间标志信号
assign out_data = rout_data ;
assign out_valid = rout_valid;
always@(posedge clk or posedge rst)begin
if(rst)
en <= 'd0;
else if(in_valid)
en <= en + 'd1;
else
en <= en;
end
always@(posedge clk or posedge rst)begin
if(rst)
Y <= 'd0;
else if(en && in_valid)
Y <= in_data[15:8];
else
Y <= Y;
end
always@(posedge clk or posedge rst)begin
if(rst)
Y_ <= 'd0;
else if(!en && in_valid)
Y_ <= in_data[15:8];
else
Y_ <= Y_;
end
always@(posedge clk or posedge rst)begin
if(rst)
U <= 'd0;
else if(!en && in_valid)
U <= in_data[7:0];
else
U <= U;
end
always@(posedge clk or posedge rst)begin
if(rst)
V <= 'd0;
else if(in_valid)
V <= in_data[7:0];
else
V <= V;
end
always@(posedge clk or posedge rst)begin
if(rst)
rout_valid <= 'd0;
else if(en)
rout_valid <= 'd1;
else
rout_valid <= rout_valid;
end
always@(posedge clk or posedge rst)begin
if(rst)
rout_data <= 'd0;
else if(en && in_valid)
rout_data <= {Y_,U,V};
else if(!en && in_valid)
rout_data <= {Y,U,V};
else
rout_data <= rout_valid;
end
endmodule
仿真
根据时序波形简单写一个测试激励
task Data_Send();
begin:send
rin_data <= 'd0;
rin_valid <= 'd0;
@(posedge clk);
rin_data <= 16'h00_00;//Y0U0
rin_valid <= 'd1;
@(posedge clk);
rin_data <= 16'h11_00;//Y1V0
rin_valid <= 'd1;
@(posedge clk);
rin_data <= 16'h22_22;//Y2U2
rin_valid <= 'd1;
@(posedge clk);
rin_data <= 16'h33_22;//Y2V2
rin_valid <= 'd1;
@(posedge clk);
rin_data <= 16'h44_44;//Y4U4
rin_valid <= 'd1;
@(posedge clk);
rin_data <= 16'h55_44;//Y5V4
rin_valid <= 'd1;
@(posedge clk);
rin_data <= 16'h0000;//Y5V4
rin_valid <= 'd1; //波形中一直拉高,这里也将为1
@(posedge clk);
end
endtask
从仿真图中可以看出,延时两个时钟周期,且数据转换也正确。