Taylor Series in Verilog

I am doing my first student Project in Verilog. My project is to calculate log base 2 using "Taylor Series" in Fixed-Point arithmetic (s4.27). I have implemented the Horner's method as well in my code.

Overall it looks like this:

log=c0+(q*(c1+(q*(c2+(q*(c3+(q*(c4(q*(c5+(q*c6))))))))));

Finally log_base_2=log*con;

`timescale 10ns/10ns

module log (q ,clk,log_result);

input clk;
input [31:0] q; // q=x-a; x=user input, a=1.5 (Taylor series is calculated around point "a")

output [31:0] log_result;

localparam con= 32'h0B8AA3B0; //1.44269504088895
localparam c0 = 32'h033E647C; //0.40546510810816
localparam c1 = 32'h05555558; //0.66666666666666
localparam c2 = 32'hFE38E38E; //-0.222222222222
localparam c3 = 32'h00CA4588; //0.0987654321
localparam c4 = 32'hFF9ADD3C; //-0.04938271605
localparam c5 = 32'h0035F068; //0.02633744856
localparam c6 = 32'hFFE208AA; //-0.01463191587

wire [31:0] x0,x1,x2,x3,x4,x5,x6;
wire [31:0] y0,y1,y2,y3,y4,y5,y6;

multiplier  #(27,32) m6(.i_multiplicand(q),.i_multiplier(c6),.o_result(x6));
adder       #(27,32) a6 (.a(x6),.b(c5),.c(y6));
multiplier  #(27,32) m5(.i_multiplicand(q),.i_multiplier(y6),.o_result(x5));
adder       #(27,32) a5 (.a(x5),.b(c4),.c(y5));
multiplier  #(27,32) m4(.i_multiplicand(q),.i_multiplier(y5),.o_result(x4));
adder       #(27,32) a4 (.a(x4),.b(c3),.c(y4));
multiplier  #(27,32) m3(.i_multiplicand(q),.i_multiplier(y4),.o_result(x3));
adder       #(27,32) a3 (.a(x3),.b(c2),.c(y3));
multiplier  #(27,32) m2(.i_multiplicand(q),.i_multiplier(y3),.o_result(x2));
adder       #(27,32) a2 (.a(x2),.b(c1),.c(y2));
multiplier  #(27,32) m1(.i_multiplicand(q),.i_multiplier(y2),.o_result(x1));
adder       #(27,32) a1 (.a(x1),.b(c0),.c(y1));
multiplier  #(27,32) (.i_multiplicand(con),.i_multiplier(y1),.o_result(x0));

assign log_result = x0;

endmodule

Test bench code:

`timescale 10ns/10ns

module tb_log ();

reg clk;
reg [ 31 : 0 ] q;

wire [ 31 : 0 ] log_result;

log log_i (
    .q(q),
    .clk(clk),
    .log_result(log_result)     
    );

parameter CLKPERIODE = 100;

initial clk = 1'b1;
always #(CLKPERIODE/2) clk = !clk;

initial begin

$dumpfile("log_wave.vcd");
$dumpvars(1);


$monitor ("Q=%h,Log2=%h ", q, log_result);

#1
  #(CLKPERIODE)
  q = 32'hFC000000; // q=1-1.5=-0.5;
  $finish();

end

endmodule

So I am expecting a result close to zero. But unfortunately I am getting 9B917CED. When I tried to include clock an error naming "Malformed Statement" occurred. I am using Icarus verilog for compiling.

Code for fixed-point multiplier(qmult) and adder(qadd)

I am sure there are bugs but currently my rookie eyes are unable to notice it. What am I missing?

1 answer

  • answered 2018-01-22 21:40 Oldfart

    I suggest you do just one multiplication and one adder and check the result of that. Fixed point multiplications should be very well checked for overflowing, which I very strongly suspect is the case here!

    It is a problem I have seen again and again: multipliers in all Verilog examples take two N bit numbers and produce a 2N result. Very few sources tackle e.g. a 20 stage FIR filter where you have twenty multipliers each using two 16 bit numbers. Following "example" code you end up with a 52 bit wide result.


    To prevent overflow each argument of the multiplication should be <16 bits. (As you are using 32 bits results). Then every time you add you need another extra bit. Thus either your data gets wider further down the stream, or you have to start sufficiently small that it fits in the en result of 32 bits.

    You can compensate if you have constant values and know what range of the result is. e.g. in a digital filter all coefficients add up to 1 and they are often positive, negative,positive, negative so the additions do not all increment all the time.

    Welcome to the world of hardware integer arithmetics!