Reputation: 3457
I am used to programming in VHDL and I want to know the "best" way to do some types of actions that I use in VHDL in Verilog. I suppose that each of these could be their own dedicated question, but I thought it would be nice to have a collection of these for people just to see a bunch of Verilog examples in one place rather than spread across 5 questions. Thanks.
Here are some examples that I would like to see best practices for:
Replacement for Others:
I know that for signal assignments in Verilog, you can do:
data <= 'b0;
This assigns all bits in data to zero, and if data changes its width it still works. Neat trick, but what about when instantiating a module and tying an input to zero? E.G.
Data_Module UUT
(
.Data(8'h00), //'b0 doesn't work here
Replacement for Attributes:
Writing flexible code is nice, so I like to define my port widths based on generics such that if the port widths change all it takes is a quick update of the generic and everything still works. I often have VHDL code like this:
signal some_data : std_logic_vector(g_DATA_WIDTH+g_GENERIC-1 downto 0);
signal some2 : std_logic_vector(some_data'length-1 downto 0);
-- OR I may have this:
left_bit <= some_data'left;
Long when/else chain:
This one gives me troubles. Is the best way to do this to set up a combinational always block and use a case-statement on index? That seems like a lot of code. Using the ?
operator can lead to some illegible code, so I prefer not to do that for long when/else chains.
some_data <= X"01" when index = 0 else
X"04" when index = 1 else
X"02" when index = 2 else
X"F0";
Assertions:
How can I trigger a modelsim assertion in Verilog? I often use these on my VHDL FIFOs to check for overflow/underflow conditions. E.G.
assert NOT_FIFO_OVERFLOW report "FIFO has overflowed, that's a bad thing" severity failure;
Generate Blocks:
In VHDL, it's nice to be able to generate a block of code based on a generic, or completely remove it if that generic is not present. E.G.
g_LFSR_3 : if g_Num_Bits = 3 generate
w_XNOR <= r_LFSR(3) xnor r_LFSR(2);
end generate g_LFSR_3;
g_LFSR_4 : if g_Num_Bits = 4 generate
w_XNOR <= r_LFSR(4) xnor r_LFSR(3);
end generate g_LFSR_4;
State Machine Enumeration:
In Verilog, do I really need to create parameters
for each individual state? If that's the best way to do it, I'll do it, but it seems like a lot. I like that in VHDL you can create a type that just contains each state and then create a state machine signal of that type.
Creating Integers:
Often I have code like this:
signal Row_Count : integer range 0 to c_TOTAL_ROWS-1 := 0;
What's the best way to do this in Verilog? Do I need to take the log base 2 of c_TOTAL_ROWS to find the max width of it then define a reg
based on this? That seems like a lot of work. I believe that Verilog creates 32-bit integers by default, but I do not want to generate extra logic if I do not need to. Also I like that if I exceed the expected range, my Modelsim simulation will crash.
Upvotes: 4
Views: 3846
Reputation: 19094
Not everything can be directly translated into Verilog.
'b0
should work with port declinations. There should be compiling warnings, not errors. Some simulator try to be backward compatible to IEEE Std 1364-2005 where 'b0
is an inferred 32'b0
. According to IEEE Std 1364-2005 § 3.5.1 this 32-bit max limitation seems to be removed. Simulators may be lagging behind the standard. It is a simulator limitation if the module port instantiation .Data('b0),
results in a compiling error.
SystemVerilog added a fill constants '0
, '1
, 'x
, & 'z
. '0
, 'x
, & 'z
are the same as IEEE Std 1364-2005 'b0
, 'bx
, & 'bz
with one less character. 'b1
is {(N-1){1'b0},1'b1}
where '1
is {N{1'b1}}
with N being the width of the destination vector/packed-array.
Non that could be found.
logic [g_DATA_WIDTH+g_GENERIC-1:0] some_data;
logic [$size(some_data)-1:0] some2;
logic [$bits(some_data)-1:0] some3; // or with $bits for vector
// OR I may have this:
left_bit <= some_data[$left(ome_data)];
some_data <= (index == 0) ? 'h01 :
(index == 1) ? 'h04 :
(index == 2) ? 'h02 :
'hF0 ;
The works functionally but may not give the best timing and area when synthesized. When some synthesizers see ?:
they will always generate a 2-to-1 mux; if they see a chain of nested ?:
it will create a chain of 2-to-1 muxes even is a 4-to-1 mux (or other mux types) is available.
It a little more typing but this should give a better result (same functionality)
case(index)
0 : some_data <= 'h01;
1 : some_data <= 'h04;
2 : some_data <= 'h02;
default : some_data <= 'hF0;
endcase
Verilog does not have assertions built into the language. Creating some for of checkers are not to challenging (for example non-overlaping concurrent check can be done with a always block), but flagging the error to the simulator may be a bit tricky. Usually a global error counter incremented of failures and the simulation will abort with $finish
if a user defined error limit is reached. There might be a PLI/VPI solution or a something that simulator specific.
SystemVerilog has two main types of assertions; concurrent and immediate. Immediate exist inside of a procedural block (i.e. begin-end) such as:
optional_label : assert (NOT_FIFO_OVERFLOW) $error("FIFO has overflowed, that's a bad thing");
Concurrent assertions run in the module scope, out side of a procedural block. They use a clocking reference.
optional_label : assert property (@(posedge clk) !$stable(fifo_ptr) |-> fifo_pt < FIFO_DEPTH) $error("FIFO has overflowed, that's a bad thing");
Refer to IEEE Std 1800-2012 § 16. Assertions for further explinations and examples.
Note - if using UVM, use `uvm_error
instead of $error
Generate blocks were added in Verilog's IEEE Std 1364-2001. The generate
-endgenerate
are actually optional, but make a good visual reference. See IEEE Std 1800-2012 § 27. Generate constructs for full detail
generate
if (g_Num_Bits = 3) begin : g_LFSR_3
xnor (w_XNOR, r_LFSR[3], r_LFSR[2]);
end : g_LFSR_3
if (g_Num_Bits = 4) begin : g_LFSR_4
always @* begin
w_XNOR = ~{r_LFSR[4] ^ r_LFSR[3]};
end
end
endgenerate
Note: In this particular example part-select addressing would also work in Verilog/System Verilog: w_XNOR = ~^r_LFSR[g_Num_Bits-:2];
IEEE Std 1800-2012 § 11.5.1
Got to use parameter
here if it is desired to using names instead of memorizing indexes. It legal possible to define multiple parameter in a one statement, but identifier still needs to define its value.
Enumeration is supported. See IEEE Std 1800-2012 § 6.19 Enumerations
Example:
typedef enum logic [3:0] { IDLE=0, START, STAGE[4:6], BLAH, STAGE[3] } states_e;
states_e state, next_state;
Is the equivalent of writing:
parameter [3:0] IDLE = 4'd0,
START = 4'd1,
STAGE4 = 4'd2,
STAGE5 = 4'd3,
STAGE6 = 4'd4,
BLAH = 4'd5,
STAGE0 = 4'd6,
STAGE1 = 4'd7,
STAGE2 = 4'd8;
With IEEE Std 1364-2005 (Final version of Verilog) or IEEE Std 1800 (SystemVerilog) use reg [$clog2(c_TOTAL_ROWS)-1:0] Row_Count;
For older Verilog (IEEE Std 1364-1995 and IEEE Std 1364-2001) create a custom fuction to find the ceiling of a log base 2. Example:
function interger ceiling_log2(input integer value);
interger local_copy;
local_copy = value;
ceiling_log2 = 0;
while(local_copy!=0) begin
ceiling_log2 = ceiling_log2 + 1;
local_copy = local_copy >> 1;
end
return ceiling_log2;
endfunction
reg [ceiling_log2(c_TOTAL_ROWS)-1:0] Row_Count;
Note: Some synthesizer may have limitations
Upvotes: 5