【问题标题】:Ways to implement recipricals on Verilog在 Verilog 上实现互惠的方法
【发布时间】:2016-03-01 23:39:33
【问题描述】:

我想在 Verilog 上实现一个互易块,稍后将在 FPGA 上进行综合。输入应该是带符号的 32 位字长和 16 位小数长度。输出应具有相同的格式。

例子

输入:x ---> 输出 ---> 1/x

我已经使用内置的 IP 核分频器解决了这个问题。我想知道是否有一种优雅/替代的方法来解决这个问题,例如通过位移或 2 的补码加上一些异或研磨。


我已经使用 IP 内核来实现逆向,如手册中所述,但由于某种原因,我并不真正理解结果是错误的,需要向左移动 1。例如; 1 的倒数给出 0.5 。 2 的倒数得到 1。

下面是手册的一部分和我的测试台代码


测试台

module reciprical_tb;

    // Inputs
    reg clk;
    reg [1:0] dividend;
    reg [31:0] divisor;

    // Outputs
    wire rfd;
    wire [1:0] quotient;
    wire [31:0] fractional;

    // Instantiate the Unit Under Test (UUT)
    reciprical uut (
        .rfd(rfd), 
        .clk(clk), 
        .dividend(dividend), 
        .quotient(quotient), 
        .divisor(divisor), 
        .fractional(fractional)
    );

    // clock
    always begin
        #5 clk = ~clk;
    end

    initial begin
        // Initialize Inputs
        clk = 0;
        dividend = 2'b1; // 1
        divisor = 2**16;; // = 1  when fraction length is 16bit

        // Wait 100 ns for global reset to finish
        #100;

        // Add stimulus here :: Inverse of 2 should give 0.5
        //$display("inv(%g) =>  %g || inv = %b",$itor(divisor)*2.0**-16, $itor(fractional)*2.0**-16, fractional); //gives zero
        $monitor("inv(%d) => q = %d || inv = %b", divisor>>>16,fractional>>>16, fractional);  //gives a wrong answer by a factor of 2
        // Using the monitor i get inv(1) = 0.5 instead of 1.
        #100;
    end

endmodule

手册部分(第 4 页):

... 除法器可以用来实现X的倒数;这就是 1/X 函数。为此, 被除数位宽设置为 2 并选择小数模式。然后将股息输入绑定到 01 无符号或有符号运算,X 值通过除数输入提供。

使用的 IP 核心

【问题讨论】:

  • 我建议将#100; 替换为#100ns;,这消除了对模拟时间设置的依赖。时钟源中的#5 相同。

标签: verilog xilinx hdl


【解决方案1】:

尝试调试部分问题:

你能试试吗:

    // Wait 10 clock cycles
    repeat (10) begin
      @(posedge clk);
    end

    // Add stimulus here :: Inverse of 2 should give 0.5
    $display("dsiplay inv(%g) =>  %g || inv = %b",$itor(divisor)*2.0**-16, $itor(fractional)*2.0**-16, fractional); //gives zero
    $monitor("inv(%d) => q = %d || inv = %b", divisor>>>16,fractional>>>16, fractional);  //gives a wrong answer by a factor of 2
    // Using the monitor i get inv(1) = 0.5 instead of 1.
    // Wait 10 clock cycles
    repeat (10) begin
      @(posedge clk);
    end
    $display("dsiplay inv(%g) =>  %g || inv = %b",$itor(divisor)*2.0**-16, $itor(fractional)*2.0**-16, fractional);

    //End simulation
    $finish();

由于监视器只发出一次,它可能在 200ns 之后才真正触发并输出更新的值。

【讨论】:

  • 我收到一条错误消息,提示 未声明。 当我写 #100ns
  • 啊,好的。从技术上讲,它是系统 verilog 语法,但据我所知,大多数 verilog 模拟器都允许它。
  • @user3697625 更新了问题,改为等待 10 个时钟周期,并使用 $finish 结束 sim,因为可能是 stdout 没有被正确刷新。
【解决方案2】:

IP 内核通常非常高效,但它们会使用结构乘法器和合理数量的逻辑。根据您需要的精度,也可以使用存储在块 RAM 中的查找表来完成。使用原始输入作为地址的 RAM 对于设备来说太大了。但是您可以存储倒数曲线并对输入进行预缩放并在输出处应用偏移。您可以通过在曲线上的两点之间进行线性插值来进一步减少内存使用量。

这取决于您拥有什么资源以及您需要什么准确性。

【讨论】:

    猜你喜欢
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多