首页
学习
活动
专区
圈层
工具
发布
37 篇文章
1
Linux音频驱动-ASOC(ALSA System on Chip)
2
LPDDR5: A New Clocking Scheme 提高性能
3
FPGA 控制 RGMII 接口 PHY芯片基础
4
DDR3篇第三讲、DDR3读写测试项目分析
5
PHY(Physical Layer,PHY)通俗理
6
MIPI联盟已完成车载的Long-Reach SerDes PHY工业标准 A-PHY v1.0
7
【三】Bluetooth 技术||链路层七种状态与空口报文设计(Core_v5.2)
8
【RL-TCPnet网络教程】第5章 PHY芯片和STM32的MAC基础知识
9
FPGA和USB3.0通信-USB3.0 PHY介绍
10
USB技术浅析
11
优秀的 Verilog/FPGA开源项目介绍(二)-RISC-V
12
优秀的 Verilog/FPGA开源项目介绍(十六)- 数字频率合成器DDS
13
想学习高速ADC/DAC/SDR项目这个项目你不得不理解
14
优秀的 Verilog/FPGA开源项目介绍(九)- DP(增改版)
15
优秀的 Verilog/FPGA开源项目介绍(十三)- I2C
16
高速串行通信常用的编码方式-8b/10b编码/解码
17
SoC设计之PPA
18
SoC设计之功耗--开篇
19
开源SOC的设计与实践
20
SoC设计之功耗 – RTL/netlist功耗计算
21
转置型FIR设计
22
SSD目标检测系统系统结构网络训练
23
P2P接口Booth乘法器设计描述原理代码实现
24
流水线式p2p接口的分析与实现
25
流水线乘加树需求设计规划代码实现
26
分时复用的移位相加乘法器
27
Verilog实现全并行比较算法
28
全并行流水线移位相加乘法器
29
ROM乘法器基本算法单个ROM乘法器分时复用ROM乘法器
30
Flash中XIP模式
31
cordic的FPGA实现(五)、除法实现
32
cordic的FPGA实现(三)、乘法器实现
33
cordic的FPGA实现(三)、sin、cos函数运算与源码分析
34
FPGA卡拉ok系统--Biquad filter
35
音频总线I2S协议
36
脉冲压缩处理
37
虚拟地址(VA,virtual address)到物理地址(PA, ,physical address)的转换
清单首页SoC文章详情

分时复用的移位相加乘法器

基本算法

移位相加即是日常我们使用的手算算法,移位相加的描述如下

  • 设置积的初值为0
  • 若乘数的最低位为0,则积不变,否则累加被乘数
  • 若乘数的第一位为0,则积不变,否则累加向左移位一位的被乘数
  • ...
  • 若乘数的第n位(最高位)为0,则积不变,否则累加向左移位n位的被乘数

RTL代码

代码语言:javascript
复制
module serial_shiftadder_multipcation # (
    parameter WIDTH = 4
)(
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low

    input multiplier_valid,
    input [WIDTH - 1:0]multiplier1,
    input [WIDTH - 1:0]multiplier2,

    output reg product_valid,
    output reg [2 * WIDTH - 1:0]product
);

接口定义部分,采用参数化设计,WIDTH为乘数/被乘数的位宽,multiplier_valid拉高时表示输入有效,并开始计算。product_valid被拉高时表示计算完成,当前的输出是有效的

代码语言:javascript
复制
/*****************buffer and shift*******************/
reg [WIDTH - 1:0]min_mult;
reg [2 * WIDTH - 1:0]max_mult;
always @ (posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        {max_mult,min_mult} <= 'b0;
    end else if(multiplier_valid == 1'b1) begin
        if(multiplier1 > multiplier2) begin
            max_mult <= '{multiplier1};
            min_mult <= multiplier2;
        end else begin
            max_mult <= '{multiplier2};
            min_mult <= multiplier1;
        end
    end else if(min_mult != 'b0) begin
        max_mult <= max_mult << 1;
        min_mult <= min_mult >> 1;
    end else begin
        max_mult <= max_mult;
        min_mult <= min_mult;
    end
end

移位部分,有输入时比较两个输入的大小,使用小的数控制迭代数量,减小时间消耗。若较小的乘数不为0,则将较大的数向左移位,较小的的数向右位移。

代码语言:javascript
复制
/******************adder********************/
always @ (posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        {product_valid,product} <= 'b0;
    end else if(min_mult[0] == 1'b1) begin
        product <= product + max_mult;
        product_valid <= 1'b0;
    end else if(min_mult != 'b0) begin
        product <= product;
        product_valid <= 1'b0;
    end else if(multiplier_valid == 1'b1) begin
        product <= 'b0;
        product_valid <= 1'b0;
    end else begin
        product <= product;
        product_valid <= 1'b1;
    end
end

endmodule

累加部分,若较小的乘数最低位为0,保持积不变,否则累加当前的大乘数,当小乘数为0是,表示运算已经结束,输出有效拉高。

测试

使用自动化测试,使用高层次方法计算积,再与输出比较看是否相等

代码语言:javascript
复制
module mult_tb (
);

parameter WIDTH = 4;

logic clk,rst_n;
logic multiplier_valid;
logic [WIDTH - 1:0]multiplier1;
logic [WIDTH - 1:0]multiplier2;

logic product_valid;
logic [2 * WIDTH - 1:0]product;

serial_shiftadder_multipcation # (
    .WIDTH(WIDTH)
) dut (
    .clk(clk),    // Clock
    .rst_n(rst_n),  // Asynchronous reset active low

    .multiplier_valid(multiplier_valid),
    .multiplier1(multiplier1),
    .multiplier2(multiplier2),

    .product_valid(product_valid),
    .product(product)
);

initial begin
    clk = 1'b0;
    forever begin
        #50 clk = ~clk;
    end
end

initial begin
    rst_n = 1'b1;
    #5 rst_n = 1'b0;
    #10 rst_n = 1'b1;
end

initial begin
    {multiplier_valid,multiplier1,multiplier2} = 'b0;
    forever begin
        @(negedge clk);
        if(product_valid == 1'b1) begin
            multiplier1 = (WIDTH)'($urandom_range(0,2 ** WIDTH));
            multiplier2 = (WIDTH)'($urandom_range(0,2 ** WIDTH));
            multiplier_valid = 1'b1;
        end else begin
            multiplier_valid = 1'b0;
        end
    end
end

logic [2 * WIDTH - 1:0]exp;
initial begin
    forever begin
        @(posedge product_valid);
        exp = multiplier1 * multiplier2;
        if(exp == product) begin
            $display("successfully, mult1=%d mult2=%d product=%d",multiplier1,multiplier2,product);
        end else begin
            $display("failed,mult1=%d mult2=%d product=%d exp=%d",multiplier1,multiplier2,product,exp);
        end
    end
end

endmodule
下一篇
举报
领券