|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Utility functions | 
|  | */ | 
|  | package prim_util_pkg; | 
|  | /** | 
|  | * Math function: $clog2 as specified in Verilog-2005 | 
|  | * | 
|  | * Do not use this function if $clog2() is available. | 
|  | * | 
|  | * clog2 =          0        for value == 0 | 
|  | *         ceil(log2(value)) for value >= 1 | 
|  | * | 
|  | * This implementation is a synthesizable variant of the $clog2 function as | 
|  | * specified in the Verilog-2005 standard (IEEE 1364-2005). | 
|  | * | 
|  | * To quote the standard: | 
|  | *   The system function $clog2 shall return the ceiling of the log | 
|  | *   base 2 of the argument (the log rounded up to an integer | 
|  | *   value). The argument can be an integer or an arbitrary sized | 
|  | *   vector value. The argument shall be treated as an unsigned | 
|  | *   value, and an argument value of 0 shall produce a result of 0. | 
|  | */ | 
|  | function automatic integer _clog2(integer value); | 
|  | integer result; | 
|  | // Use an intermediate value to avoid assigning to an input port, which produces a warning in | 
|  | // Synopsys DC. | 
|  | integer v = value; | 
|  | v = v - 1; | 
|  | for (result = 0; v > 0; result++) begin | 
|  | v = v >> 1; | 
|  | end | 
|  | return result; | 
|  | endfunction | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Math function: Number of bits needed to address |value| items. | 
|  | * | 
|  | *                  0        for value == 0 | 
|  | * vbits =          1        for value == 1 | 
|  | *         ceil(log2(value)) for value > 1 | 
|  | * | 
|  | * | 
|  | * The primary use case for this function is the definition of registers/arrays | 
|  | * which are wide enough to contain |value| items. | 
|  | * | 
|  | * This function identical to $clog2() for all input values except the value 1; | 
|  | * it could be considered an "enhanced" $clog2() function. | 
|  | * | 
|  | * | 
|  | * Example 1: | 
|  | *   parameter Items = 1; | 
|  | *   localparam ItemsWidth = vbits(Items); // 1 | 
|  | *   logic [ItemsWidth-1:0] item_register; // items_register is now [0:0] | 
|  | * | 
|  | * Example 2: | 
|  | *   parameter Items = 64; | 
|  | *   localparam ItemsWidth = vbits(Items); // 6 | 
|  | *   logic [ItemsWidth-1:0] item_register; // items_register is now [5:0] | 
|  | * | 
|  | * Note: If you want to store the number "value" inside a register, you need | 
|  | * a register with size vbits(value + 1), since you also need to store | 
|  | * the number 0. | 
|  | * | 
|  | * Example 3: | 
|  | *   logic [vbits(64)-1:0]     store_64_logic_values; // width is [5:0] | 
|  | *   logic [vbits(64 + 1)-1:0] store_number_64;       // width is [6:0] | 
|  | */ | 
|  | function automatic integer vbits(integer value); | 
|  | `ifdef XCELIUM | 
|  | // The use of system functions was not allowed here in Verilog-2001, but is | 
|  | // valid since (System)Verilog-2005, which is also when $clog2() first | 
|  | // appeared. | 
|  | // Xcelium < 19.10 does not yet support the use of $clog2() here, fall back | 
|  | // to an implementation without a system function. Remove this workaround | 
|  | // if we require a newer Xcelium version. | 
|  | // See #2579 and #2597. | 
|  | return (value == 1) ? 1 : _clog2(value); | 
|  | `else | 
|  | return (value == 1) ? 1 : $clog2(value); | 
|  | `endif | 
|  | endfunction | 
|  |  | 
|  | endpackage |