A nice idea
The XST documentation says that Verilog functions are fully supported. I was frustrated today to discover that this is not the case. I was trying to make a library for handling fixed point arithmetic. Module instantiation overhead in Verilog is quite high in terms of lines of code and excess verbiage. All the code I need to use is combinational, so the natural thing to do is have one module with all my functions and parameters which control the representation of the fixed point numbers. After this, I can make instances of the library module with the various fixed point representations I need and use the functions.
So I whip out the following:
module SignedInteger
parameter out_int = 1;
parameter out_frac = 1;
parameter in_a_int = out_int;
parameter in_a_frac = out_frac;
parameter in_b_int = in_a_int;
parameter in_b_frac = in_a_frac;
parameter out_width = out_int+out_frac;
parameter in_a_width = in_a_int+in_a_frac;
parameter in_b_width = in_b_int+in_b_frac;
function signed [out_width-1:0] sum;
input signed [in_a_width-1:0] a;
input signed [in_b_width-1:0] b;
begin
if (in_a_frac > in_b_frac)
sum = a + (b<<(in_a_frac-in_b_frac));
else
sum = (a<<(in_b_frac-in_a_frac)) + b;
end
endfunction
endmodule
Now I can instantiate SignedInteger in another module and call the sum function. I need the function in another module because I may have multiple instances of SignedInteger in the calling module with different parameter values– sort of a poor man’s class mechanism. Everything simulates just peachy. Now, I synthesize a test case in XST.
Prepare to crash and burn
I’ll spare you the details, but XST has a number of issues with doing things like this, though the first few are not insurmountable. XST will first error out because I used concatenation instead of shift operators in the sum function. XST didn’t like the fact that one of the concatenation multipliers was negative. I got boxed into a corner here by Verilog too, because you can’t use a generate inside a function, and if I use a generate outside the function, it makes it really hard to call the function from outside the module. So, we’ll go back to the drawing board and use the shift operator. Next, XST believes that modules need at least one port. My guess is that the people who wrote XST never thought about just using a module as a container for its tasks and functions. Hmm… it’s not great, but I can add a port that I won’t use.
At this point, I’m faced with an interesting error message:
Analyzing top module .
ERROR:Xst:917 - Undeclared signal .
ERROR:Xst:2083 - "test.v" line 29: Unsupported range for function.
What do you mean, undeclared signal out_width? Firstly, it’s not a signal and secondly, it is so declared. The second message gives me pause. Crap– it really thinks that out_width is a signal. Why can’t it see it?
An experiment
Time for a test case. I try to synthesize this module, and guess what? It compiles without errors.
module test2
(
input signed [15:0] a,
input signed [15:0] b,
output signed [19:0] sum
);
localparam out_width = 20;
localparam in_a_width = 16;
localparam in_a_frac = 0;
localparam in_b_width = 16;
localparam in_b_frac = 4;
SignedInteger #(16,4,16,0,12,4) si_16_4_16_0_12_4(.value());
assign sum = si_16_4_16_0_12_4.sum(a,b);
endmodule
If I give it the parameters it is looking for, the errors go away. I do get some strange warnings, however…
WARNING:Xst:616 - Invalid property "out_width 00000014": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "in_a_frac 00000000": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "in_a_int 00000010": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "in_a_width 00000010": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "in_b_frac 00000004": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "in_b_int 0000000C": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "in_b_width 00000010": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "out_frac 00000004": Did not attach to si_16_4_16_0_12_4.
WARNING:Xst:616 - Invalid property "out_int 00000010": Did not attach to si_16_4_16_0_12_4.
Not sure what that means exactly, but it sounds like something is rotten with the parameters.
Incorrect logic
Now this could cause incorrect logic to be synthesized. So I tried this test case.
module sub(empty);
output empty;
parameter paramvalue = 1;
assign empty = 0;
function [3:0] myparam_plus;
input [3:0] in;
begin
myparam_plus = paramvalue + in;
end
endfunction
endmodule // sub
module test3(value,empty);
output [3:0] value;
output empty;
parameter paramvalue = 10;
sub #(2) mysub(.empty(empty));
assign value = mysub.myparam_plus(3);
endmodule
The value output is a constant 5. That is, the sub module has a paramvalue of 2 and we add 3 to it. XST synthesizes this with no errors, warnings, or infos. The module is totally clean. Even so, the netlist it produces gives value a constant output of 13. Let’s see Xilinx support try to squirm their way out of this one. This seems like a bug to me.
At any rate, I have to give up on a pure Verilog solution to a fixed point library. Time to use Perl.