VL5 位拆分与运算

写在前面

  1. 这个专栏的内容记录的是牛客的Verilog题库刷题,附带RTL\TestBench,并进行覆盖率收集
  2. 牛客算是一个Verilog宝藏刷题网站了,网站提供在线仿真环境,不用自己找题(点击直达),<刷题记录>专栏,持续打卡中…


一、题目

(1)题目描述

现在输入了一个压缩的16位数据,其实际上包含了四个数据[3:0][7:4][11:8][15:12],现在请按照sel选择输出四个数据的相加结果,并输出valid_out信号(在不输出时候拉低)


(2) 状态转换

seloutvalidout
0:不输出且只有此时的输入有效0
1输出[3:0]+[7:4]1
2输出[3:0]+[11:8]1
3输出[3:0]+[15:12]1

(3)信号示意图

在这里插入图片描述


(4)波形示意图

在这里插入图片描述


(5)端口描述

信号方向类型位宽描述
clkinputwire1时钟,周期为5ns
rstinputwire1同步复位,低电平有效
dinputwire16输入的16bit数据
validoutoutputreg1有效输出时为1,否则为0
outoutputreg5输出结果

二、分析

  题意可知,模块采用同步复位且复位信号在低电平有效;可以使用时序逻辑对输入数据d进行锁存到data_buff;输出信号out和validout可使用组合逻辑输出,输出信号根据sel的变化进行变化。


三、RTL

module data_cal(
input             clk     ,
input             rst     ,
input      [15:0] d       ,
input      [1 :0] sel     ,

output reg [4:0]  out     ,
output reg        validout
);

reg [15:0] data_buff;

//*************code***********//

always @ (posedge clk) begin
  if (!rst) begin
    data_buff <= 16'b0;
    out <= 5'b0;
    validout <= 1'b0;
  end
  else begin
    data_buff <= d;
  end
end


always @ (*) begin
  if(sel)begin
    validout = 1'b1;
  end
  else begin
    validout = 1'b0;
  end
end

always @ (*) begin
  case(sel)
    2'd0:out = 5'b0;
    2'd1:out = data_buff[3:0] + data_buff[7 :4 ];
    2'd2:out = data_buff[3:0] + data_buff[11:8 ];
    2'd3:out = data_buff[3:0] + data_buff[15:12];
    default:out = 5'b0;
  endcase
end
//*************code***********//
endmodule

四、Testbench

`timescale 1ps/1ps
module tb_data_cal;

  reg         clk      ;
  reg         rst      ;
  reg  [15:0] d        ;
  reg  [ 4:0] sel      ;
  
  wire [4 :0] out      ;
  
  wire        validout ;

//-- debug signal

/*-----------------------------------------------\
 --    --
\-----------------------------------------------*/

initial begin
  clk   = 1     ;
  rst   = 1     ;
  d     = 16'd0 ;
  #1000 rst  = 0;
  #4001 rst  = 1;
         d_case(d,16'd0                  );
  #5000  d_case(d,16'b1000_0100_0010_0001);
  #20000 d_case(d,16'b1000_0100_0010_0011);
  #25000 d_case(d,16'b1000_0100_0010_0111);
  #5000  d_case(d,16'b1000_0100_0010_1111);
  #5000  d_case(d,16'b1000_0100_0011_1111);
  #5000  d_case(d,16'b1000_0100_0111_1111);
  #5000  d_case(d,16'b1000_0100_1111_1111);
  #5000  d_case(d,16'b1000_0101_1111_1111);
  #5000  d_case(d,16'b1000_0111_1111_1111);
  #5000  d_case(d,16'b1000_1111_1111_1111);
  #5000  d_case(d,16'b1001_1111_1111_1111);
  #5000  d_case(d,16'b1011_1111_1111_1111);
  #5000  d_case(d,16'b1111_1111_1111_1111);
  #20000 ;
  repeat(10000)begin
  #5000  d_case(d,{$random}%8'hFF);
  end
end


/*-----------------------------------------------\
 -- sigal var T*5000ps     --
\-----------------------------------------------*/
initial begin
         sel_case(sel,0);
  #15000 sel_case(sel,2);
  #15000 sel_case(sel,2);
  #15000 sel_case(sel,1);
  #5000  sel_case(sel,0);
  #25000 sel_case(sel,3);
  repeat(10000)begin
    #5000 sel_case(sel,{$random}%4);
  end
end

/*-----------------------------------------------\
 --  task of d_case and sel_case  --
\-----------------------------------------------*/
task d_case;
  output  [15:0] a;
  input   [15:0] b;

  a = b;

endtask

task sel_case;
  output [1:0] s  ;
  input  [1:0] b  ;

  begin
    s = b;
  end
endtask

/*-----------------------------------------------\
 --  clock period is 5ns  --
\-----------------------------------------------*/
always begin
  #2500 clk = ~clk;
end


/*-----------------------------------------------\
 --  display  --
\-----------------------------------------------*/
always @ (data_cal.data_buff)begin
  if(sel == 2'd0)begin
    if((out != 0) || (validout != 0))begin
      $display($realtime,",true = %d,out = %d,validout = %d",data_cal.data_buff,out,validout);
    end
    else begin
    end
  end
  else if(sel == 2'd1) begin
    if((out != data_cal.data_buff[3:0] +  data_cal.data_buff[7:4]) || (validout != 1'b1))begin
      $display($realtime,",true = %d,out = %d,validout = %d",data_cal.data_buff[3:0] +  data_cal.data_buff[7:4],out,validout);
    end
    else begin
    end
  end
  else if(sel == 2'd2) begin
    if((out != data_cal.data_buff[3:0] +  data_cal.data_buff[11:8]) || (validout != 1'b1))begin
      $display($realtime,",true = %d,out = %d,validout = %d",data_cal.data_buff[3:0] +  data_cal.data_buff[11:8],out,validout);
    end
    else begin
    end
  end
else if(sel == 2'd3) begin
    if((out != data_cal.data_buff[3:0] +  data_cal.data_buff[15:12]) || (validout != 1'b1))begin
      $display($realtime,",true = %d,out = %d,validout = %d",data_cal.data_buff[3:0] +  data_cal.data_buff[15:12],out,validout);
    end
    else begin
    end
  end

end

data_cal u_data_cal(
                   .clk       (clk     ),
                   .rst       (rst     ),
                   .d         (d       ),
                   .out       (out     ),
                   .sel       (sel     ),
                   .validout  (validout)
              );

initial #60000000 $finish;
initial begin
  $fsdbDumpfile("data_cal.fsdb");
  $fsdbDumpvars            ;
  $fsdbDumpMDA             ;
end
endmodule


五、结果分析

(1)TB结果

在这里插入图片描述
在这里插入图片描述


(2)波形图

在这里插入图片描述

由波形图可tb可以确定,输出符合预期结果


(3)覆盖率

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

可以看到总覆盖率只有93.92%,受行覆盖率和分支覆盖率的影响。查看信息可以看到主要是case语句的default语句没有被执行到。


✍✍☛ 题库入口
  经过一段时间的沉淀,发现入行IC行业,自己的底子还是很差,写的文章质量参差不齐,也没能解答大家的疑问。决定还是要实打实从基础学起,由浅入深。因此决定通过补充/完善基础知识的同时,通过题库刷题不断提高自己的设计水平,题库推荐给大家(点击直达),<题库记录>栏目不定期更新,欢迎前来讨论。


作者:xlinxdu
版权:本文版权归作者所有
转载:未经作者允许,禁止转载,转载必须保留此段声明,必须在文章中给出原文连接。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xlinxdu

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值