04-21-2016 07:19 AM
[Synth 8-26] function call with parameters not implemented ["/home/ted/srcFPGA/test/mwe.srcs/sources_1/new/test.sv":35]
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Engineer: Malte Vesper ////////////////////////////////////////////////////////////////////////////////// class channelInfoParser #(int unsigned CHANNELS = 4); static function int channelModeCount(logic [0:CHANNELS-1] channels); begin return channels[1]; end endfunction endclass module test ( output logic test ); localparam int outputConst = channelInfoParser #(4)::channelModeCount(4'b1011); assign test = outputConst; endmodule
04-21-2016 04:56 PM
Wow! That actually WORKED in 2015.4? Not just passed the syntax check but synthesized to the correct logic, and everything?
Wow, that's a useful tool. I remember some industry folks pushing for this feature in order to support "parameterizable functions". But I didn't think I'd see support out of any synthesis tools for a while.
Regards,
Mark
04-22-2016 04:12 AM
The technique is described here :http://forums.accellera.org/topic/1177-how-to-pass-variable-sized-packed-arguments-to-a-taskfunction/
The hardware I synthesized with this seems to be working correctly for me.
Also, I find the warning message very obscure.
When I synthesized the calls was actually part of a package in another file, but that should not make a difference, this is a stripped down MWE, for which I just checked the synthesis steps.
04-22-2016 08:46 AM
Oh, I familiar with the technique quite well. What has me gobsmacked is that any part of it is synthesizable. In theory it should be, but I'm quite astonished that Vivado synthesis would support it. I'd assume the synthesizer would see the word "class" and do a full stop.
I'm actually quite happy that you've shown it (at least MAY, in 2015.2) have worked.
Thanks,
Mark
04-22-2016 09:36 AM - edited 04-22-2016 09:36 AM
Another method to get parameterizable functions is to bury the functions within a parameterized interface.
Every time I've needed it, it's been associated with an interface I'm already using. But that isn't a requirement. I don't think there's anything stoping you from creating a "dummy" interface just to get the parameterized function:
interface #( parameter CHANNELS = 4) foo_if; bit dummy; // May(?) be neccesary to have one actual port? function int channelModeCount( input logic [ 0 : CHANNELS - 1 ] channels ); return( channels[ 1 ] ); endfunction endinterface module test( output logic test ); foo_if #( 4 ) foo_if4(); always_comb test = foo_if4.channelModeCount( 4'b1011 ); endmodule
Not syntax checked, you get the idea. The interface never needs to be used on a portlist (i.e. its "intended" use case).
Regards,
Mark
04-27-2016 06:23 AM
06-20-2016 06:22 AM
Bump. Regression carried forward to Vivado 2016.2
12-19-2016 09:53 AM
For the record I don't this every truly worked. I found that while earlier version of VIvado didn't choke on the syntax they silently ignored the call site parameters and used the default parameters instead.
XIlinx has since 'fixed' that bug by throwing an error instead of properly supporting static virtual functions. It's a shame since this feature would be immensely useful to me. I'm currently working around it with some serious pre-processor abuse and it's still limited in what it can achieve.
12-20-2016 09:48 AM
Regarding the parameterized interface trick. It's a good one and I'm trying to adopt it. Did you ever try to push that through Vivado? I get a 'Synth 8-660' error where it's unable to see the function call through the hierarchy. DC and Incisive accept it just fine of course.... Doesn't work on 2016.2 at least. Not sure if a later version corrected this.
12-20-2016 10:25 AM
Yes, we're using the "parameterized function" within interfaces trick. I've used from at least Vivado 2016.1. As I indicated, I'm not using "dummy" interfaces, rather reals ones. But the functions within are just that - parameterized functions where the parameters are fixed at the interface instantiation.
Not sure what trouble you're having, can you post some examples?
Regards,
Mark
12-20-2016 11:40 AM
Looks like I've managed to stumble over a bug with interfaces that isn't related to parameters at all.
interface test_intf; generate if (1) begin : bar function id1(input [3:0] a); return a; endfunction end else begin : bar function id1(input [3:0] a); return ~a; endfunction end /* begin : bar function [3:0] id1(input [3:0] a); return ~a; endfunction end */ endgenerate function id(input [3:0] a); return bar.id1(a); endfunction endinterface module test ( input wire [3:0] a, output reg [3:0] b ); test_intf foo(); always_comb begin b = foo.id(a); end endmodule
This code fails with
ERROR: [Synth 8-660] unable to resolve 'id1' [/home/bmagnuson/tmp/test_intf_no_param.sv:23]
But if I replace the if/else with the commented bare begin with the same name everything is happy. Additionally the same style of code without an interface involved also works fine.
module test ( input a, output y ); generate if (1) begin : bar function id1(input a); return a; endfunction end else begin : bar function id1(input a); return !a; endfunction end endgenerate function id(input a); return bar.id1(a); endfunction assign y = id(a); endmodule
So this appears to be a bug with hierarchical paths when using an if/else style generate inside of an interface. Fun.
12-20-2016 11:56 AM
Ahh - I've never tried using generates within the interfaces. I take that back - I have, but not within the synthesizable portion of the interface. So, I'm unsure on Vivado support there.
You've got a typo correct - in that both generate clauses are named "bar" (plus a third commented out "bar"). I'm guessing this is just a cut/paste error when you entered it here?
And conditional function definitions within a generate clause. That's new to me as well. I've not tried that either.
--Mark
12-20-2016 01:17 PM
Actually not a typo! IEEE 1800-2012 (and earlier) Section 27.5 explicitly shows that in an if/else if/else if/else chain within a generate you can name all the blocks with the same identifier since it's guaranteed that only one of them will exist. That way you don't need to know which branch of the conditional was taken to predict the hierarchical path.
Of course, being technically correct (the best kind of correct) doesn't help me here. Have to get an SR filed for this I suppose.
12-20-2016 01:21 PM
Ahh - thanks for that info on the SystemVerilog Spec. Didn't know that about the generate if/else and names. Learned something new today.
Makes sense, and I agree your example is legal syntax. As you say, however, doesn't really help you that its correct, if the tool doesn't accept it...
Good luck with the SR.
Regards,
Mark