VL4 移位运算与乘法

本文分享了如何使用Verilog实现一个8位数乘法器模块,包括题目的详细描述、信号示意图、波形分析和覆盖率测试。通过实例演示了如何处理时钟同步、复位、数据输入和输出控制,以及使用Testbench验证和覆盖率收集。
摘要由CSDN通过智能技术生成

写在前面

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


一、题目

(1)题目描述

已知d为一个8位数,请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效(d给出的信号的上升沿表示写入有效)


(2)信号示意图

在这里插入图片描述


(3)波形示意图

在这里插入图片描述


(4)端口描述

信号方向类型位宽描述
clkinputwire1bit时钟,周期为5ns
rstinputwire1bit同步复位,低电平复位
dinputwire8bit输入的8bit数据
outoutputreg11bit输出,依次将输入*1、*3、*7、*8输出
input_grantoutputreg1bit输出,指示当前输入是有效的,时序控制

二、分析

由时序可以知道,模块采用低电平有效的同步复位;在输入有效的情况下,依次输出4次乘法的结果后,再重新对输入采样并再一次输出一个输入有效的输出信号(input_grant);在两次有效的输入之间,输入数据发生了变化,因此需要在锁存每次有效的数据再进行运算。

cntout
0out = {3’b0,d[7:0]}
1out = (d << 2) - d
2out = (d <<< 3) - d
3out = d <<< 3

三、RTL

module multi_sel
(
  input              clk        , 
  input              rst        ,
  input      [7 :0]  d          ,
  output reg [10:0]  out        ,
  output reg         input_grant
);

reg [7:0] d_buff;
reg [1:0] cnt   ;


always @ (posedge clk) begin
  if (!rst) begin
    cnt <= 2'b0;
  end
  else if(cnt == 3)begin
    cnt <= 2'b0;
  end
  else begin
    cnt <= cnt + 1'b1;
  end
end


always @ (posedge clk) begin
  if (!rst) begin
    d_buff <= 8'b0;
  end
  else if (cnt == 0) begin
    d_buff <= d;
  end
  else begin
    d_buff <= d_buff;
  end
end


always @ (posedge clk) begin
  if (!rst) begin
    out <= 11'b0;
  end
  else begin
    case(cnt)
      0: begin out <= {3'b0,d}    ;end
      1: begin out <= (d_buff << 2) - d_buff;end
      2: begin out <= (d_buff << 3) - d_buff;end
      3: begin out <=  d_buff << 3          ;end
      default: out <= 11'b0;
    endcase
  end
end


always @ (posedge clk) begin
  if (!rst) begin
    input_grant <= 1'b0;
  end
  else if (cnt == 2'b00) begin
    input_grant <= 1'b1;
  end
  else begin
    input_grant <= 1'b0;
  end
end
endmodule

四、Testbench

`timescale 1ps/1ps
module tb_multi_sel;

  reg         clk         ;
  reg         rst         ;
  reg  [7:0]  d           ;
  
  wire [10:0] out         ;
  
  wire        input_grant ;


/*-----------------------------------------------\
 --    --
\-----------------------------------------------*/
//-- debug signal
reg  [7:0] clk_cnt   ;
reg  [1:0] cnt_buff  ;
reg        clk_cnt_en;


initial begin
  clk   = 1;
  rst   = 1;
  clk_cnt_en = 0;
  #1000 rst = 0;
  d = 8'd143; 
  #4001 rst = 1;
         d_case(d,8'd143);
  #15000 d_case(d,8'd7  );
  #25000 d_case(d,8'd6  );
  #5000  d_case(d,8'd128);
  #5000  d_case(d,8'd129);
  #30000 clk_cnt_en = 1;
  repeat(257)begin
    #20000  d_case(d,clk_cnt);
  end
  repeat(10000)begin
  #5000  d_case(d,{$random}%8'hFF);
  end
end

always@(multi_sel.d_buff)begin
  if(clk_cnt == 255)begin
    clk_cnt <= 1;
  end
  else if(clk_cnt_en)begin
    clk_cnt <= clk_cnt + 1'b1;
  end
  else begin
    clk_cnt = 0;
  end
end
/*-----------------------------------------------\
 --    --
\-----------------------------------------------*/
task d_case;
  output  [7:0] a;
  input   [7:0] b;

  a = b;

endtask

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

/*-----------------------------------------------\
 --  display  --
\-----------------------------------------------*/
always @ (posedge clk) begin               
  cnt_buff <= multi_sel.cnt;
end

always @ (cnt_buff)begin
  if((cnt_buff == 0) && (rst == 1))begin
    if(out == {3'b0,multi_sel.d_buff});
    else begin
      $display($realtime,",*1 error:cnt_buff = %d;d_buff*1 = %d;out = %d",cnt_buff,{3'b0,multi_sel.d_buff},out);
    end
  end
  else if((cnt_buff == 1) && (rst == 1))begin
    if(out == ((multi_sel.d_buff << 2) - multi_sel.d_buff));
    else begin
      $display($realtime,",*3 error:cnt_buff = %d;d_buff*3 = %d;out = %d",cnt_buff,(multi_sel.d_buff << 2) - multi_sel.d_buff,out);
    end
  end
  else if((cnt_buff == 2) && (rst == 1))begin
    if(out == ((multi_sel.d_buff << 3) - multi_sel.d_buff));
    else begin
      $display($realtime,",*7 error:cnt_buff = %d;d_buff*7 = %d;out = %d",cnt_buff,(multi_sel.d_buff << 3) - multi_sel.d_buff,out);
    end
  end
  else if((cnt_buff == 3) && (rst == 1))begin
    if(out == (multi_sel.d_buff << 3));
    else begin
      $display($realtime,",*8 error:cnt_buff = %d;d_buff*8 = %d;out = %d",cnt_buff,(multi_sel.d_buff << 3),out);
    end
  end
end

multi_sel u_multi_sel(
                 .clk          (clk  ),
                 .rst          (rst  ),
                 .d            (d    ),
                 .out          (out  ),
                 .input_grant  (input_grant)
              );

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


五、结果分析

(1)TB结果

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


(2)波形图

在这里插入图片描述

测试波形与预期时序一致


(3)覆盖率

在这里插入图片描述

例化的模块相关覆盖率达到100%


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


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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xlinxdu

你的鼓励是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值