Verilog parameters with parametric width - verilog

It isn't hard to agree that parametrized module design is a good practice and data width is a good starting point.
I have been defining constants 0 and 1 of required bus or operand widths for years. That to avoid compiler warnings and to explicitly communicate the intention. Typically using something like:
parameter WIDTH = 16;
// ...
parameter ZERO = {WIDTH{1'b0}}; // all zeroes
parameter UNO = {{WIDTH-1{1'b0}}, 1'b1}; // all zeroes except LSB
This is all fine until I want to define an arbitrary constant with given parametrized WIDTH.
I certainly can write a constant with fixed width - but that's not what I want:
parameter FULL = 16'd57;
However, analogous construct using the parametric WIDTH fails with syntax error:
parameter LEVEL = WIDTH'd57; // <== *ERROR*
What is the proper syntax - if there is one?

This was a problem in Verilog because the RHS of a parameter assignment was used as the self-determined width of the parameter. SystemVerilog addressed this by allowing you to specify a datatype as part of a parameter declaration
parameter WIDTH = 16;
// ...
parameter bit [WIDTH-1:0] ZERO = '0; // all zeroes
parameter bit [WIDTH-1:0] UNO = 1; // all zeroes except LSB
parameter bit [WIDTH-1:0] LEVEL = 57;
The datatype does not change when overriding.
Another way is using a sizing cast
parameter LEVEL = WIDTH'(56);
But if you do it this way and override the parameter, the datatype becomes the width of the overriding value's type.

Related

Expansion of logic array to 2D array

In my system, each pixel on an LCD screen is represented by 16-bits (RGBA):
typedef logic [15:0] pix;
In order to display characters on the screen, I have created a simple 8x8 typeface, whereby characters are stored such as:
typedef logic char_8x8 [7:0][7:0];
localparam char_8x8 txt_G = '{'h3C, 'h66, 'h03, 'h03, 'h73, 'h66, 'h7C, 'h00};
As they are currently stored (the hex numbers above), a 'b1 represents a turned-on pixel and 'b0 turned off.
Now, to display them, I need some method to convert each character to the following form:
typedef logic [15:0] char_8x8_colored [7:0][7:0];
Notice how now each pixel element also carries the 16 bits of color as a packed array. (Frankly I'm not 100% how the whole packed/unpacked affects code - even though I know the implementation difference).
The way this would work is, wherever there exists a 'b1 in the character array, this would be replaced with an element with value 'hFFFF (white) - and of course 'h0000 (black) for no pixel present.
I'm unsure of the best way to implement this in SystemVerilog.
Thanks.
As far as I know you the only type of indices you can use in systemverilog are slices (without stride). I know that numpy, pytorch, or octave for instance have much richer indexing options and could use something like colored[face] = foreground. To set the color of all the pixels turned on. But in systemverilog I would go with a function.
function char_8x8_colored color_out(
input char_8x8 face,
input pix background,
input pix foreground);
char_8x8_colored data;
begin
for(int i = 0; i < 8; i = i + 1) begin
for(int j = 0; j < 8; i = i + 1) begin
data[i][j] = face[i][j] ? foreground : background;
end
end
end
end
endfunction
This is a pure function this function can be synthesized using without any logic (only routing) if you pass a parameter such as txt_G as the face argument.

What happens if I dont specify the size and base format for unknown state x in Verilog/SystemVerilog?

As stated in the title, what happens if I do something like
Signal1 = 'x;
as opposed to something like
Signal1 = 4'bxxxx;
Are there any difference? Note that I have previously declared Signal1 as
reg[3:0] Signal1;
This difference is if/when you change the width of Signal1 to be more than 4 bits and forget to change 4'bxxxx, you are going to silently get 0 padding. 'x, 'z, '0, and '0 are all fill literals that expand to width of whatever context they are in.
This is only applicable to SystemVerilog, not Verilog.

System Verilog using mask

I can't get the meaning of this code.
I know VHDL and need system verilog. I do not know the meaning of bits [num] = '{4, 4}) or (output logic [width-1:0] mask [num]);
please explain me
module works
#(parameter int num = 4,
parameter int width = 8,
parameter int bits [num] = '{4, 4})
(output logic [width-1:0] mask [num]);
A module is like a VHDL entity, so we have a block called works:
module works
A parameter is like a VHDL generic. Instead of saying generic, in SystemVerilog we just say #. So, we have a block with three parameters (generics), an int (32-bit signed integer like a VHDL integer) with a default value of 4:
#(parameter int num = 4,
an int with a default value of 8:
parameter int width = 8,
and an array of ints of size equal to the value of the parameter num, which will be numbered 0 to num-1:
parameter int bits [num] = '{4, 4})
'{4,4} is an assignment pattern and is the (rough) equivalent of a VHDL aggregate. So, this code is trying to initialise two of the values of this array to to integer 4. The trouble is this code is probably illegal. The array bits can be of any size (depending on the value of the parameter num) and this array is what is called an unpacked array. In SystemVerilog (and in Verilog), both the size and shape of assignments to packed arrays must match (just like in VHDL). This size of either side of this assignment will not match unless the value of num is 2. If you want to initialise all the elements of an unpacked array to the same thing, you can use a key (rather like VHDL others):
parameter int bits [num] = '{default:4})
https://www.edaplayground.com/x/5w8y
This is a port:
(output logic [width-1:0] mask [num]);
whose size is defined by the two parameters, width and num. The output is an array of num (a so-called unpacked dimension) of words of width width (a so-called packed dimension). logic is a type. Variables of type logic can take one of four values: 0, 1, X or Z.
output logic [width-1:0] mask [num]
[width-1:0] mask is a vector of width bits. With a width of 8 this would be an 8-bit vecor: [7:0] mask.
The vector is followed by [num] means it is an array of 'num' vectors. The total is a two-dimensional array of width x num bits.
That syntax is verry common and you will see it often.
I had to look for the '{4,4} pattern (I could not find it in my little System Verilog booklet) and as Matthew says it is an assignment of values to an array. So, my initial interpretation was wrong.
The problem with the existing code is that my Verilog simulator throws an error message when using the default values. num is 4 and '{4,4} has only two elements. This upon start-up I get an error:
ERROR: [VRFC 10-666] expression has 2 elements; expected 4 [...
If I set num to 2 #(.num(2)) the simulator is happy.

Using real parameter to determine counter sizes

I am trying to make my debounce code more modular by passing in parameters that are the frequency and the desired bounce time to eliminate button/switch bounce. This is how I approached it:
module debounceCounter
#(
parameter CLOCK_FREQUENCY_Hz = 50_000_000,
parameter BOUNCE_TIME_s = 0.003
)
(
input wire sysClk, reset,
input wire i_async,
output reg o_sync
);
/* include tasks/functions */
`include "clog2.v"
/* constants */
parameter [(clog2(BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz + 0.5) - 1) : 0]
MAX_COUNT = BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz;
Synthesis using Xilinx ISE 14.7 Throws this error:
Xst:850 - "../../rtl/verilog/debounceCounter.v" line0: Unsupported real
constant
How can I get around this issue so that I can determine the counter size and max count value based on parameters being passed in from code above this module in the heirarchy? A majority of my code has sizes of variables and such determined by frequency generics, so not being able to use methods like VHDL has proven to create problems in my designs.
Seems to work fine on Vivado 2016.3 (the oldest I have available). I think the problem is that 2014.7 is too old to support this. You didn't show the contents of the `include, but I'm assuming its the one from AR# 44586. If so, it should take and return integers and it will truncate the real floating point values for you. Floating point arithmetic is fine to use in Verilog/SystemVerilog testbenches and parameters.
How can I get around this issue so that I can determine the counter
size and max count value based on parameters being passed in from code
above this module in the heirarchy?
Update to a recent version. 2017.1 or 2017.3 are working good for me. I tested the following on 2016.3 and it also worked fine.
Try using SystemVerilog (.sv) which supports the $clog2() system function natively without the `include. Not sure when .sv started working, but probably needs 2015+.
Verify that your version of clog2 in the clog2.v header matches the following
NOTE: There is another pretty serious bug in the code you posted.
When you want to get the MSB required to hold a constant expression "x" the pattern should be $clog2((x)+1)-1. You have only added 0.5 instead of 1. This causes there to not be enough bits whenever the result of the floating point expression "x" falls between 2^n and (2^n + 0.5). For example, what you have erronously computes the constant as 17'h0 instead of 18'h4_0000 for the the frequency 87381333 but it still appears to work for your example at 50Mhz. Murphy's law says you will accidentally fall into this narrow bad range at the worst possible time, but never during testing :).
For reference, this is what I tested, with the `include expanded inline:
`timescale 1ns / 1ps
module debounceCounter
#(
//parameter CLOCK_FREQUENCY_Hz = 50_000_000,
parameter CLOCK_FREQUENCY_Hz = 87381333, // whoops
parameter BOUNCE_TIME_s = 0.003
)
(
input wire sysClk, reset,
input wire i_async,
output reg o_sync
);
/* include tasks/functions */
//`include "clog2.v"
function integer clog2;
input integer value;
begin
value = value-1;
for (clog2=0; value>0; clog2=clog2+1)
value = value>>1;
end
endfunction
/* constants */
//parameter [(clog2(BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz + 0.5) - 1) : 0] // <- BUG!!! 0.5 should 1
parameter [(clog2(BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz + 1) - 1) : 0]
MAX_COUNT = BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz;
initial
$display("MAX_COUNT %d", MAX_COUNT);
endmodule
Type Real is not synthesizable. Draw/Create your design before you translate into/write HDL and you will realize this. Ask yourself, "What does a real synthesize to in gates?"
For those tools (e.g. Synplify) that do "support" Type Real, it is just a vendor interpretation, and as such is impossible to "support" since it is not defined as part of any HDL standard. The implication: If you had a simulator that interprets Type Real one way, and your synthesizer (likely) interprets it another way, you will get sim/syn mismatches. You may get away with them, depending on what you are trying to accomplish, but, it would still be considered poor design practice.
Behavioral code, for modeling and use in testbenches, as stated above, a different story as it is not synthesized.

How to define and initialize a vector containing only ones in Verilog?

If I want to declare a 128 bit vector of all ones, which one of these methods is always correct?
wire [127:0] mywire;
assign mywire = 128'b1;
assign mywire = {128{1'b1}};
assign mywire = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
As a quick simulation would prove, assign mywire = 128'b1; does not assign all bits of mywire to 1. Only bit 0 is assigned 1.
Both of the following always assign all 128 bits to 1:
assign mywire = {128{1'b1}};
assign mywire = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
One advantage of the 1st line is that it is more easily scalable to widths greater than and less than 128.
With SystemVerilog, the following syntax also always assigns all 128 bits to 1:
assign mywire = '1;
I would use the following statement instead:
assign mywire = ~0;
in a simple expression like this, the width on the left-hand side of the assignment sets the width for the expression on the right hand side. So 0, which is a 32 bit constant, is first extended to the full 128 bit of mywire, then all the bits are flipped and the resulting all-ones vector is assigned.
I'd prefer this version because it does not require you to specify the width of mywire anywhere in the assignment.

Resources