9

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.

Ari
  • 7,251
  • 11
  • 40
  • 70
  • 2
    I realise this function is just an example; so this is not an answer but the above function can be implemented with a unary XOR `parity = ^data ;` – Morgan Mar 27 '14 at 19:23
  • @Morgan: I edited the example to make it more clear. – Ari Mar 28 '14 at 00:55

5 Answers5

7

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.

nguthrie
  • 2,615
  • 6
  • 26
  • 43
  • 1
    Have you been successful in synthesizing this? – Ari Mar 28 '14 at 18:12
  • 2
    @Ari No, I haven't tried. Section 5.6.7 of this paper: http://www.sutherland-hdl.com/papers/2013-SNUG-SV_Synthesizable-SystemVerilog_paper.pdf talks about this. – nguthrie Mar 28 '14 at 18:30
  • +1 for the great reference. According to Sutherland in the section you are referring to, this is supported by DC: "DC places two restrictions on parameterized classes that are not SystemVerilog restrictions: The class must be declared as a virtual class, and the class must be defined in the $unit declaration space" – Ari Mar 28 '14 at 21:11
  • I tried this on Quartus and it doesn't synthesise: `"Error (10170): Verilog HDL syntax error at testing.sv(10) near text "virtual"; expecting "endmodule"`. – Chiggs Mar 31 '14 at 08:41
  • @Chiggs I added a working example. So it at least works in modelsim – nguthrie Mar 31 '14 at 11:37
  • @Chiggs I just realized you were probably talking about synthesis: I still haven't tried that. – nguthrie Mar 31 '14 at 11:46
  • @nguthrie Yes I was trying to synthesise it. Haven't tried Vivado yet. – Chiggs Mar 31 '14 at 12:04
6

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

Chrysa
  • 81
  • 1
  • 7
2

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

Community
  • 1
  • 1
Chiggs
  • 2,824
  • 21
  • 31
  • Thanks for the answer. I need the code to be synthesizable. Looks like the old preprocessor macro way with $bits is the way to go! – Ari Mar 28 '14 at 17:32
  • 2
    @Ari I'm hoping somebody will answer with a synthesisable way to do this and prove my answer wrong ;) It seems absolutely mad that it's not possible in SystemVerilog.. VHDL has had this capability since 1993! – Chiggs Mar 28 '14 at 17:35
0

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:

  1. 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.
  2. 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.

RaZ
  • 364
  • 1
  • 5
  • 17
0

Here is a quick update on using the paramaterized virtual class idea posted in another answer. I tried this in Vivado, and it appears to work correctly in synthesis. Using nguthrie's solution, I can do:

logic [7:0] data;
assign data = {sw, btn};
assign led[0] = C#($bits(data))::parity(data);

This is in Vivado 2021.

toolic
  • 57,801
  • 17
  • 75
  • 117
okonomi
  • 21
  • 1