Is $clog2 task supported in Verilog HDL? - verilog

When I used it in a program an error was generated ($clog2 is not supported). But I see our StackOverflowers using $clog2 task in their program. Please tell me how to use that.

$clog2 is not supported by Verilog. It is a SystemVerilog system task. Moreover, system tasks are not synthesizable.
However, you can make a function/macro which outputs the log bsae 2 value of a given number. Here are some of the examples of user defined implementation:
Using macro:
`define CLOG2(x) \
(x <= 2) ? 1 : \
(x <= 4) ? 2 : \
(x <= 8) ? 3 : \
(x <= 16) ? 4 : \
(x <= 32) ? 5 : \
(x <= 64) ? 6 : \
..etc, ..
(x <= 4294967296) ? 32 : \
-1
parameter MAX_VALUE = 42;
parameter MAX_WIDTH = `CLOG2(MAX_VALUE);
Using function:
function [31:0] log2;
input [31:0] value;
integer i;
reg [31:0] j;
begin
j = value - 1;
log2 = 0;
for (i = 0; i < 31; i = i + 1)
if (j[i]) log2 = i+1;
end
endfunction
initial
begin
$display("10 = %d", log2(10));
end
Both the above examples leads to synthesizable code. The user can extend this code as per the maximum bit width requirement.
So, you can either change the compiler to compile SystemVerilog code or implement the above function to make a user-defined log code.

$clog2is supported by Verilog, but only Verilog-2005 (IEEE Std 1364-2005). Since Verilog-2005 was released at the same time as IEEE's SystemVerilog, it is generally considered a SystemVerilog enhancement. Here are two source documenting $clog2 as a Verilog-2005 feature:
Sutherland HDL - Busting the Myth that SystemVerilog is only for Verification § 9.6 Expression size functions
Xilinx - Verilog $clog2 function implemented improperly
The Verilog-2005 was mostly an intermediate release for eventual merger of Verilog and SystemVerilog (which happened in IEEE Std 1800-2009). Some simulators may have not implanted Verilog-2005 as everything in it is included in SystemVerilog. If your simulator does not run Verilog-2005 by default, then refer to your manual which may included a option to enable it. Enabling SystemVerilog is another option, or user methods as described in sharvil111's solution.

Just wanted to point out that $clog2 is a synthesizable construct and can be handled by most tools. It does not become unsynthesizable simply because it is a system task.
For example, the following is a synthesizable statement:
logic [$clog2(WIDTH) - 1 : 0] addr;

Related

Create matrix of instances in veriloga

Is it possible do create an crossbararray of memristormodules with two for loops in veriloga? I have the following code but it does not work:
module variable_crossbar(I, V);
`define size 4
output [`size:1] I;
electrical [`size:1] I;
input [`size:1] V;
electrical [`size:1] V;
genvar i,j;
analog begin
for(i = 1; i < `size; i = i + 1) begin
for(j = 1; j <= `size; j = j + 1) begin
JART_VCM_2 mem_'j'_'i' ( V[j] , I[i] ); //memristormodulefile is included
end
end
end
endmodule
Verilog-A is not a standard by itself. It is described in Appendix C of the Verilog-AMS LRM (which you provided a link to).
Verilog-AMS was standardized based on the pre-existing implementation. As such, it is a set of analog extensions mixed with IEEE 1364-2004 Verilog, and a tiny bit of IEEE 1800 SystemVerilog (the string type). Verilog-AMS standardization was all done at Accellera. Normally Accellera standards feed into IEEE standards, but this proved to be problematic since by the time the possibility of IEEE standardization arose, IEEE 1364 Verilog was superseded by IEEE 1800 SystemVerilog. IEEE does not normally allow standards based on other superseded standards. There has been work on upgrading to SystemVerilog-AMS but this is a mammoth task and has not yet borne any fruit.
Verilog-A and Verilog-AMS should support generate and genvar.
From what I can tell pure Verilog-A does not support instantiating modules with generate loops. Verilog-AMS, a superset language of Verilog-A, does.
Verilog-A and Verilog-AMS are frequently referred to interchangeable in my research. From what I can tell, the original Verilog-A was derived from Verilog (IEEE1364-1995) syntax; adding analog features (Ex: electrical, V(), etc.) and removing digital features (reg, always, etc.). The latest version of Verilog-AMS merged Verilog (IEEE1364-2005) with Verilog-A, supporting both syntax and features in one language. Oddly, Verilog-AMS LRM explicitly refers to IEEE1364-2005, buts does not mention Verilog-A despite using the same analog syntax. Maybe they are near identical competing languages, or maybe there is some trademark issue over the names, or some other convoluted reason I couldn't figure out in the time I allocated to look up Verilog-A and Verilog-AMS.
With Verilog-AMS you can use the Verilog approach to instantiating modules with generate loops. Note the you cannot use the index in the instance name. It is recommenced to name the generate blocks (loop_i,loop_j in this example). Also not it is recommened to use parameter instead of `define to prevent polluting the global space.
module variable_crossbar(I, V);
parameter SIZE 4; // `define are global space and assigned by compile order
output [SIZE:1] I;
electrical [SIZE:1] I;
input [SIZE:1] V;
electrical [SIZE:1] V;
genvar i,j;
generate
for(i = 1; i < SIZE; i = i + 1) begin : loop_i
for(j = 1; j <= SIZE; j = j + 1) begin : loop_j
JART_VCM_2 mem ( V[j] , I[i] ); //memristormodulefile is included
end
end
endgenerate
endmodule
Again, from what I can tell pure Verilog-A does not support instantiating modules with generate loops. So hopefully what you really mean is Verilog-AMS. And hopefully your simulator supports the the features.

Determine whether a binary number is of power of two in verilog code

I am trying to determine whether a binary number is of power of two (in other words, is it of one-hot encoding).
I found a method to do so, but it is for integer.
Could anyone help to transform the method for usage with binary number in verilog ?
There's nothing wrong with your code—it's limitations of the tool you are using.
Verilator requires code with inputs and outputs so it can be stimulated and results displayed.
It also doesn't like performing logical operators on multi-bit operands.
module is_power_of_two(output reg f);
reg [7:0];
initial begin
#1 v = 8'b11110000;
#1;
end
always #(*) f = v != 0 && !((v & v - 1) != 0);
endmodule

Quartus and modelsim - compile size casting

I'll try to compile in Quartus and simulate in ModelSim some module.
See this:
module somemodule(
... inputs, outputs, etc...
);
localparam BUFFER_LEN = 96;
localparam BUFFER_LENW = $clog2(BUFFER_LEN);
localparam DATA_WIDTH = 32;
logic [BUFFER_LENW-1:0] bits_remain;
always_ff #(posedge rd_clk) begin : _proc_bitsremain
if (state == LOAD) begin
case (somevalue)
1: bits_remain <= DATA_WIDTH * 1;
2: bits_remain <= DATA_WIDTH * 2;
default: bits_remain <= BUFFER_LEN;
endcase
end
else
bits_remain <= bits_remain - 1;
end
endmodule
So, I compile it in modelsim. I have 0 errors and 0 warnings. Simulation is success, all is good. Next, I compile (synthesis) it in Quartus, and I have this warning:
Warning (10230): Verilog HDL assignment warning at <location>:
truncated value with size 32 to match size of target (7)
So, I understand the warning, and fix it by size casting:
module somemodule(
... inputs, outputs, etc...
);
localparam BUFFER_LEN = 96;
localparam BUFFER_LENW = $clog2(BUFFER_LEN);
logic [BUFFER_LENW-1:0] bits_remain;
always_ff #(posedge rd_clk) begin : _proc_bitsremain
if (state == LOAD) begin
case (somevalue)
1: bits_remain <= BUFFER_LENW'(DATA_WIDTH * 1);
2: bits_remain <= BUFFER_LENW'(DATA_WIDTH * 2);
default: bits_remain <= BUFFER_LENW'(BUFFER_LEN);
endcase
end
else
bits_remain <= BUFFER_LENW'(bits_remain - 1);
end
endmodule
In Quartus compilation is success. But, If I'll try to compile this code in ModelSim again, I have a error:
** Error: <location>(148): near "'": syntax error, unexpected '\'', expecting ';'
Where I wrong and why modelSim can't compile a size casting?
The casting is covered by section 6.24 in IEEE 1800-2012 & IEEE 1800-2009. IEEE 1800 is the SystemVerilog standard. I do not see it covered in any of the Verilog standards (please leave a comment if you can point me to the section in IEEE 1364-1995, 2001 or 2005).
Forcing to use system verilog compiler might solve the issue, normally done through changing the file extension to '.sv' or adding a -sv flag to the command line.
The standards do not dictate which parts are for simulation only and which are synthesisable, so you may run into issues where you can simulate but not synthesise. If I have followed the question correctly the reverse is true at the minute. which could just be differing levels of support for SystemVerilog.
However you can cast using temp variables or have a temp variable to catch the extra bits, which never gets used and is optimised away.
reg [W-1:0] temp_two;
always #* begin
temp_two = (DATA_WIDTH * 2);
end
//...
bits_remain <= temp_two[4:0];
Or
reg [W-5:0] temp_throw_away;
{temp_throw_away, bits_remain} <= (DATA_WIDTH * 2);
The legality of the syntax BUFFER_LENW'(DATA_WIDTH * 1) is questionable in the current SystemVerilog standard. The LRM only mentions a positive decimal number appearing before the ' and everything else is interpreted as a type. However many tools now allow an integer parameter as you have done so here. ModelSim 10.3 and later releases now support this extension to the LRM.
There are two currently legal ways to write this in SystemVerilog. One is with a part-select on a concatenation.
bits_remain <= {DATA_WIDTH * 2}[BUFFER_LENW-1:0];
The other way is using a typedef and bit-stream cast
typedef logic [BUFFER_LENW-1:0] buffer_width_t;
buffer_width_t bits_remain;
bits_remain = buffer_width_t'(DATA_WIDTH * 2);
To typecast from a 32-bit unsigned to 8-bit unsigned, you need to select the bits you want from the 32-bit local parameter, and then perform any operations you want in the usual way.
localparam MY_CONST_32_BITS = 96; // parameters always seem to be type cast to 32 bit, even if you pass 8'd96 as the value.
wire [7:0] my_const_8_bits = MY_CONST_32_BITS[7:0]; // Select lower 8 bits out of 32 bits
wire [8:0] double_my_const_9_bits = my_const_8_bits * 8'd2; // 8 bit wide unsigned decimal value 2.
The above code compiles fine for me in Altera Quartus tools.

Verilog: Adding individual bits of a register (combinational logic, register width is parameterizable)

I am trying to come up with a way to add individual bits of a register.
eg, if regA = 111000 then regB = 3 (Sum of bits of regA).
1) Is there any synthesizable function/operator in Verilog or SystemVerilog which I can directly use to do this operation?
If not, then maybe the problem is a little interesting, especially because the operation has to be done in one clock cycle (pure combinational logic) and the register width is parameterizable.
2) In case there is no inbuilt Verilog or SystemVerilog operator then what can be done?
Thanks,
Ujjwal
Verilog (IEEE Std 1364-2001 or newer):
integer i;
always #* begin
B = WIDTH_LOG2'b0;
for (i=0; i<WIDTH; i=i+1)
B = B + A[i];
end
SystemVerilog (IEEE Std 1800-2005 or newer):
always_comb begin
B = '0; // fill 0
foreach(A[i])
B += A[i];
end
Both will synthesize to combination logic. No latches or flops.
SystemVerilog does have $countones(), but I'm unsure if it is synthesizable. Ff it is then: always_comb B = $countones(A)
You can try something like this. I am not exactly sure what it will synthesize to but it should work.
int i;
reg [`WIDTH-1:0] A;
reg [`WIDTH_LOG2:0] B;
B = 0;
for(i = 0; i < `WIDTH; i = i + 1)
begin
B = B + A[i];
end
Of course there are more complex ways that may have better performance, depending on on your tool flow and what is available, where you can create your own adders and cascade them in parallel reducing the size each step. Assuming the width was 32-bits, something like:
adder1bit_1(output1, A[31:24]);
adder1bit_2(output2, A[23:16]);
adder1bit_3(output3, A[15:8]);
adder1bit_4(output4, A[7:0]);
adder3bit_1(output5, output1, output2);
adder3bit_2(output6, output3, output4);
adder4bit(final_ouput, output5, output6);

Logarithm in Verilog

I've a statement in verilog looking like integer level = log(N) (Where N is a parameter and level is to be determined) But I understand I cannot do complex math statements in verilog, so I'm wondering if there is an alternative solution to the above problem?
Any feedback appreciated!
If it is a logarithm base 2 you are trying to do, you can use the built-in function $clog2().
The answer to ADDRESS WIDTH from RAM DEPTH describes a couple ways to evaluate constant logarithms in this situation.
Verilog has functions for natural logarithm ($ln()), decadic logarithm ($log10()) and ceiling of binary logarithm ($clog2()). In constant expressions they should be synthesizable, but actual support by tools varies.
The following is synthesizable Verilog code:
module test(output [31:0] a, b, c);
assign a = 1000 * $ln(123);
assign b = 1000 * $log10(123);
assign c = 1000 * $clog2(123);
endmodule
E.g. after RTL synthesis with Yosys (e.g. yosys -p 'prep; write_verilog -noattr' test.v):
module test(a, b, c);
output [31:0] a;
output [31:0] b;
output [31:0] c;
assign a = 32'd4812;
assign b = 32'd2090;
assign c = 32'd7000;
endmodule
But I understand I cannot do complex math statements in Verilog
Verilog is first and foremost a hardware description language. What hardware log(N) statement is describing? Modern FPGAs consist of LUTs, flops, small embedded memories, simple DSPs that implement MAC (multiply-accumulate) primitives. log(N) and other complex math statements cannot be mapped directly into those primitives. The same goes with ASICs.
By analogy, log(N) doesn't get executed by a processor. It calls a bunch of lower-level assembly instructions to do so. Those assembly instructions are part of the log(N) library (C, C++, etc.)
To be able to synthesize log(N) for ASIC/FPGA it requires an instance of a log(N) IP core.
I like to think of (logarithm base n of value) as answering the question "How many base n digits do I need to represent 'value' independent numbers?" (Keeping in mind that 0 counts as a number)
Thinking of it that way, you can implement your own log base 2 in SystemVerilog:
function bit [31:0] log_base_2 (bit [31:0] log_input);
bit [31:0] input_copy;
bit [31:0] log_out = 0;
input_copy = log_input;
while(input_copy > 0)begin
input_copy = input_copy >> 1;
log_out = log_out + 1;
end
log_out = log_out - 1;
if(log_input != (1 << log_out))
log_out = log_out + 1;
return log_out;
endfunction

Resources