Is it possible to write a function that can detect the input data width automatically? For example, consider the parity function below:
function parity;
input [31:0] data;
parity = ^ data;
endfunction
When parity(data)
is called, the input data should be limited to 32 bits.
Alternatively, one could write a macro, such as `PARITY(data)
in which the system function $bits
can detect the width of data and make the macro width-independent. Is it possible to have the same flexibility for functions?
Edit: I need my code to be synthesizable.
You can create a parameterized function. See section 13.8 in the LRM. It looks like the function must be declared inside a class like this:
virtual class C #(parameter WIDTH=32);
static function parity (input [WIDTH-1:0] data);
parity=^data;
endfunction
endclass
Then when you call the function parameterized it with the bits
task:
assign parity_bit = C#($bits(data))::parity(data);
Working example on EDA Playground.
It is possible using unbounded arrays.
Unfortunately SystemVerilog doesn't have decent support for unbounded arrays. The LRM seems to equate unbounded with dynamic, which suggests it's going to be almost impossible to create something synthesisable. VHDL has unbounded arrays which are supported by tools and incredibly useful so it's a pity that SystemVerilog didn't include this feature properly.
Here is an example:
function automatic logic parity(input logic data[]);
logic p = 0;
for (int i=0; i<data.size(); i++)
p ^= data[i];
return p;
//return = ^data; <--- not allowd on unpacked arrays?
endfunction
logic [7:0] data_in;
logic result;
logic data_in_unpacked [] = new[$bits(data_in)];
always_comb begin
// Convert to unpacked array (better way to do this?)
for (int i=0; i<$bits(data_in); i++)
data_in_unpacked[i] = data_in[i];
result = parity(data_in_unpacked);
end
This is running on Modelsim on EDAPlayground here: http://www.edaplayground.com/x/3tS
EDIT 1: Updated the code - I just realised it's possible to call new[]
at initialisation and thus statically, so in theory synthesis tools could support this. It would be interesting to synthesise this and see...
EDIT 2: Thought I'd try synthesising and unsurprisingly Quartus doesn't like this:
Error (10170): Verilog HDL syntax error at testing.sv(10) near text "]"; expecting an operand
Error (10170): Verilog HDL syntax error at testing.sv(18) near text "]"; expecting an operand
Error (10112): Ignored design unit "my_parity" at testing.sv(2) due to previous errors
You can use macros. The function can be declared like:
`define PARITY(FUNC_name, WIDTH) \
function FUNC_name (input [WIDTH-1:0] data); \
begin \
FUNC_name = ^ data; \
end \
endfunction
and you can call it with:
`PARITY(parity, 32);
assign parity_bit = parity(data);
This code is synthesizable in xilinx, altera and synopsys tools
Interesting question. According to my knowledge, I don't think that's possible. I would also stay away from macros (even more problems). I can propose a synthesizable workaround:
- When calling your function parity on widths lesser than your defined width pad your data with 0's like this:
assign my_parity_bits = parity({16'd0, my_data});
Hopefully, synthesis tool would ignore those 0's but you will have to check it yourself.
- If you want to perform such operation on large data buses in a convenient way you will have to write some more Verilog. E.g. a module that would accept a
WIDTH
parameter and actual data as an input
vector. To do this, I would advise you to write a generic module that does exactly what your function parity
does. Then, write a module which will be a parity wrapper
. Inside this wrapper I would perform math operations on input WIDTH
parameter to determine number of parity
modules needed for input data and instantiate those modules in a generate
loop.
Remember that Verilog is a hardware description language, thus such limitations. Think about what your code will synthesize into when writing RTL.