久久久国产精品视频袁燕,99re久久精品国产,亚洲欧美日韩国产综合v,天天躁夜夜躁狠狠久久,激情五月婷婷激情五月婷婷

FPGA and ICer
認(rèn)證:普通會員
作者動態(tài)
Aurora8B10B IP使用 -05- 收發(fā)測試應(yīng)用示例
2天前
ZYNQ-QSPI Flash讀寫操作
2天前
ZYNQ-定時器中斷使用
3天前
ZYNQ-UART串口中斷讀寫測試
6天前
ZYNQ-XADC使用
1星期前

數(shù)字設(shè)計筆試Verilog手撕代碼 - 累加器

前言

本系列整理關(guān)于數(shù)字設(shè)計的筆試或面試的設(shè)計問題,手撕代碼繼續(xù)撕,今天撕一個百度昆侖筆試題的累加器設(shè)計。

設(shè)計需求

已知一個加法器IP,其功能是計算兩個數(shù)的和,但這個和延遲兩個周期才會輸出?,F(xiàn)在有一串連續(xù)的數(shù)據(jù)輸入,每個周期都不間斷,試問最少需要例化幾個上述的加法器IP,才可以實現(xiàn)累加的功能。

設(shè)計分析

實現(xiàn)累加器的加法器例化的個數(shù)。按照原文大佬的設(shè)計方法,因為數(shù)據(jù)連續(xù)且加法器的延遲周期是2,使用使用一個實現(xiàn)累加,會有一半的數(shù)據(jù)丟失。那這樣設(shè)計他就將奇數(shù)偶數(shù)的數(shù)據(jù)進(jìn)行了分開做一級累加,然后第二級將奇數(shù)偶數(shù)的累加結(jié)果再累加。這樣做共需消耗3個加法器。

這樣設(shè)計當(dāng)然沒問題,但是這樣設(shè)計是否是最少呢?我先拋出我的思考,我認(rèn)為在允許少量邏輯設(shè)計的情況下,最少需要例化兩個上述的加法器IP可以實現(xiàn)累加。

如果比較極限的情況下,一個都可以,先把一串?dāng)?shù)據(jù)使用寄存器緩存,然后一個一個取出來慢慢算即可,但這樣是不太可取的,首先,數(shù)據(jù)是連續(xù)的并沒有給出數(shù)據(jù)的極限長度,也就是說不論用任何涉及存儲結(jié)構(gòu)進(jìn)行緩存,都沒法確保該次數(shù)據(jù)能完全被存儲。如果題目改成一串連續(xù)數(shù)據(jù)輸入,長度最大為10,那我認(rèn)為用寄存器緩存這樣的設(shè)計是合理的。

設(shè)計架構(gòu)

回到設(shè)計思路:用兩個加法器的結(jié)構(gòu)如圖示。

設(shè)計實現(xiàn)

加法器設(shè)計

假設(shè)兩個時鐘周期延時加法器代碼如下,通過例化加法器進(jìn)行構(gòu)建累加器。

//加法器IP
module adder
#(parameter DATA_WIDTH = 8)(
    input clk,
    input rst_n,
    input [DATA_WIDTH-1:0] a_in,
    input [DATA_WIDTH-1:0] b_in,
    output reg [DATA_WIDTH-1:0] out
  );
  reg [DATA_WIDTH-1:0] sum;
  always @(posedge clk or negedge rst_n)begin
    if(rst_n == 'd0)begin
      sum <= 'd0;
      out <= 'd0;
    end
    else begin
      sum <= a_in + b_in;
      out <= sum;
    end
  end
endmodule

累加器設(shè)計

//累加器實現(xiàn)
module adder_for_acc
  #(parameter DATA_WIDTH = 8)
   (
     input                        clk,
     input                      rst_n,
     input       [DATA_WIDTH-1:0] din,
     input                  din_valid,
     output reg            dout_valid,
     output reg [DATA_WIDTH-1:0] dout
   );

  reg [DATA_WIDTH-1:0]din_r0;

  //打一拍
  always @(posedge clk or negedge rst_n)begin
    if(rst_n == 'd0)begin
      din_r0 <= 'd0;
    end
    else if(din_valid==1'B1)begin
      din_r0<= din;
    end
    else begin
      din_r0<='d0;
    end
  end

  //adder0_valid信號
  reg adder0_valid;
  always @(posedge clk or negedge rst_n)begin
    if(rst_n == 'd0)begin
      adder0_valid <= 'd0;
    end
    else if(din_valid==1'B1)begin
      adder0_valid<=!adder0_valid;
    end
    else begin
      adder0_valid<='d0;
    end
  end

  wire[DATA_WIDTH-1:0] a_in = (adder0_valid && din_valid)?din:0;
  wire[DATA_WIDTH-1:0] b_in = (adder0_valid)?din_r0:0;
  wire[DATA_WIDTH-1:0] ab_sum;

  adder adder0_dut (
    .clk  (clk   ),
    .rst_n(rst_n ),
    .a_in (a_in  ),
    .b_in (b_in  ),
    .out  (ab_sum)
  );
  //第一級加法器輸出有效信號
  reg [1:0]adder0_valid_dly;
  wire ab_sum_valid = adder0_valid_dly[1];
  always @(posedge clk ) begin
      adder0_valid_dly<={adder0_valid_dly[0],adder0_valid};
  end

  wire [DATA_WIDTH-1:0] sum_in;
  wire [DATA_WIDTH-1:0] ab_sum_in = (ab_sum_valid)?ab_sum:0;
  wire [DATA_WIDTH-1:0] accsum_in = (ab_sum_valid)?sum_in:dout;

  adder adder1_dut (
    .clk  (clk      ),
    .rst_n(rst_n    ),
    .a_in (ab_sum_in),
    .b_in (accsum_in),
    .out  (sum_in   )
  );
  
  //第二級加法器輸出有效信號
  reg [3:0]din_valid_r0;
  reg [1:0]adder1_valid_dly;
  wire adder1_outvld = adder1_valid_dly[1];
  always @(posedge clk ) begin
    adder1_valid_dly<={adder1_valid_dly[0],ab_sum_valid};
  end
  //輸出
  always @(posedge clk ) begin
    din_valid_r0<={din_valid_r0[2:0],(din_valid || adder0_valid)};
  end
  always @(posedge clk or negedge rst_n) begin
    if(rst_n == 'd0)begin
      dout <= 'd0;
      dout_valid <= 'd0;
    end
    else if(adder1_outvld == 1 && (din_valid_r0[3]==1 && din_valid_r0[2]==0))begin
      dout <= sum_in ;
      dout_valid <= 'd1;
    end
    else begin
      dout <= dout ;
      dout_valid <= 'd0;
    end
  end

endmodule

代碼架構(gòu)設(shè)計

  1. 打拍:先對數(shù)據(jù)用寄存器緩存一拍,輸入數(shù)據(jù)暫時用in[i]表示,緩存。
  2. 第一級加法器輸入選擇valid:因為前級積累一拍的數(shù)據(jù),設(shè)計valid用于指示加法器的輸入數(shù)據(jù)。
  3. 第一級加法器信號輸入:根據(jù)valid信號進(jìn)行選擇數(shù)據(jù)輸入。
  4. 調(diào)用第一級加法器,同時對輸入valid信號進(jìn)行打兩拍處理,指示有效的輸出數(shù)據(jù)。
  5. 第二級加法器信號輸入:根據(jù)valid信號進(jìn)行選擇數(shù)據(jù)輸入。
  6. 調(diào)用第二級加法器,同時對輸入valid信號進(jìn)行打兩拍處理,指示有效的輸出數(shù)據(jù)。
  7. 輸出結(jié)果和valid信號。

經(jīng)過分析,目前設(shè)計延時是4拍,也即兩級,這里dout和valid使用的是時序邏輯輸出,所以在輸入valid拉低后的第五個時鐘周期輸出正確的結(jié)果。

仿真測試

設(shè)計仿真測試代碼對代碼進(jìn)行測試,這里使用了遞增數(shù)測試代碼可用性,在實際測試時,可通過改變DATA_LEN的大小測試單次遞增累加后的結(jié)果,后續(xù)結(jié)果依次遞增為第一次的N倍。

`timescale 1ns/1ps
module adder_for_acc_tb;

  // Parameters
  localparam  DATA_WIDTH = 8;
  localparam  DATA_LEN = 5;
  // Ports
  reg clk = 1;
  reg rst_n = 0;
  reg [DATA_WIDTH-1:0] din;
  reg din_valid = 0;
  wire  dout_valid;
  wire [DATA_WIDTH-1:0] dout;

  adder_for_acc 
  #(
    .DATA_WIDTH (
        DATA_WIDTH )
  )
  adder_for_acc_dut (
    .clk (clk ),
    .rst_n (rst_n ),
    .din (din ),
    .din_valid (din_valid ),
    .dout_valid (dout_valid ),
    .dout  ( dout)
  );
  always @(posedge clk or negedge rst_n)begin
    if(rst_n == 'd0)begin
            din <= 'd0;
      din_valid <= 'd0;
    end
    else if(dout_valid == 1)begin
      din <= 'd0;
      din_valid <= 'd1;
    end
    else if(din == DATA_LEN)begin
      din <= din;
      din_valid <= 'd0;
    end
    else if(din != DATA_LEN)begin
      din <= din + 1;
      din_valid <= 'd1;
    end
    else begin
      din <= din;
      din_valid <= 'd0;
    end
  end

  always #5  clk = ! clk ;
  initial begin
    begin
      #100;
      rst_n = 1;
      #1000;
      $finish;
    end
  end

 
endmodule

仿真截圖

仿真分析

在圖示仿真可知,累加器功能正常,在din_valid信號拉低后第五拍可得到輸出結(jié)果,功能正常。

聲明:本內(nèi)容為作者獨立觀點,不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 2
收藏 3
關(guān)注 15
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧