Search code examples
verilogxilinxhdl

Ways to implement recipricals on Verilog


I want to implement a reciprical block on Verilog that will later be synthesized on an FPGA. The input should be a signed 32 bit wordlength with a 16 bit fraction length. The output should have the same format.

Example

input : x ---> output ---> 1/x

I have solved the problem using the inbuilt IP core divider. I'm wondering if there is an elegant/altenative way of solving this by for example by bit shifting or 2's complement with some xor grinds.


I have used the IP core to implement the inverse as it says in the manual but for some reason that i don't really understand the result is wrong and it needs to be shifted to the left by 1. For example; Reciprical of 1 gives 0.5 . Reciprical of 2 gives 1.

Below is a section from the manual and my testbench code


Test bench

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

Manual section (page 4):

... The divider can be used to implement the reciprocal of X; that is the 1/X function. To do this, the dividend bit width is set to 2 and fractional mode is selected. The dividend input is then tied to 01 for both unsigned or signed operation, and the X value is provided via the divisor input.

Ip Core used

GUI generator


Solution

  • Trying to debug part of the question:

    can you try :

        // 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();
    

    As monitor is only issued once, it might be after 200ns that it is actually firing and outputting the updated value.