Width independent functions

2019-01-19 01:51发布

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.

4条回答
神经病院院长
2楼-- · 2019-01-19 02:12

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.

查看更多
可以哭但决不认输i
3楼-- · 2019-01-19 02:25

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.

查看更多
Evening l夕情丶
4楼-- · 2019-01-19 02:29

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

查看更多
Ridiculous、
5楼-- · 2019-01-19 02:29

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

查看更多
登录 后发表回答