Icarus Verilog contains a code generator to emit VHDL from the Verilog netlist. This allows Icarus Verilog to function as a Verilog to VHDL translator.

Invocation[edit | edit source]

To translate a Verilog program to VHDL, invoke "iverilog" with the -tvhdl flag.

% iverilog -t vhdl -o my_design.vhd my_design.v

The generated VHDL will be placed in a single file (a.out by default), even if the Verilog is spread over multiple files.

Flags[edit | edit source]

-pdebug=1Print progress messages as the code generator visits each part of the design.
-pdepth=NOnly output VHDL entities for modules found at depth < N in the hierarchy. N=0, the default, outputs all entities. For example, -pdepth=1 outputs only the top-level entity.

Supported Constructs[edit | edit source]

// Benchmark "top" written by ABC on Thu Jul 24 17:34:52 2014

☀`timescale 1ns / 1ps
// Company:

A Verilog module produces a VHDL entity/architecture pair with the same input and output ports. Any modules instantiated within the module produce both a VHDL component instantiation statement and a component declaration.

The code generator can identify most cases when a Verilog "out" port needs to be a "buffer" port in VHDL (i.e. when the signal needs to be read inside the entity).

reg [8:0] PaddlePosition;
reg [2:0] quadAr, quadBr;
always @(posedge clk) quadAr <= {quadAr[1:0], quadA};
always @(posedge clk) quadBr <= {quadBr[1:0], quadB};
always @(posedge clk)
if(quadAr[2] ^ quadAr[1] ^ quadBr[2] ^ quadBr[1])
  if(quadAr[2] ^ quadBr[1])
    if(~&PaddlePosition)        // make sure the value doesn't overflow
      PaddlePosition <= PaddlePosition + 1;
    if(|PaddlePosition)        // make sure the value doesn't underflow
      PaddlePosition <= PaddlePosition - 1;

Processes[edit | edit source]

Both initial and always processes are converted to VHDL processes. The only difference is that an initial process has a indefinite wait statement at the end, so it is only activated once, at time step zero. For example, an empty initial process like this:

initial begin

Produces a VHDL process like this:

process is
end process;

Sensitivity lists for always processes are handled differently depending on whether the events are edge- or level-sensitive. An edge-sensitive event, or a mix of edge- and level-sensitive events, produces a wait-until statement at the start of the process:

always @(posedge x) ...
process is
  wait until rising_edge(x);

A level-sensitive event produces a wait-on statement at the end of the process:

always @(x) ...
process is
  wait on x;
end process;

This means that the body of a level-sensitive process with execute once at time step zero. Note that neither event type produces a VHDL sensitivity list: this is because VHDL does not allow any wait statements in a process with a sensitivity list, and hence Verilog processes with delays could not be translated correctly. These two styles of processes are consistent with the coding guidelines of Xilinx and other VHDL vendors.

If all assignments in an edge-sensitive always process are non-blocking (<= instead of =, unconfirmed), the generated VHDL process doesn't use wait statements:

always @(posedge clk or negedge rstn) begin
  if (!rstn)
process (rx_clk, rx_rstn) is
  if ((not rstn) = '1') then
  elsif rising_edge(clk) then
  end if;
end process;

Functions[edit | edit source]

Verilog functions are translated directly to VHDL functions. A special variable <function>_Result holds the return value of the function. For example:

assign DAC_data = cnt[10] ? ~cnt[9:0] : cnt[9:0];
function sum (
   a : unsigned(15 downto 0);
   b : unsigned(15 downto 0)
 return unsigned is
   variable sum_Result : unsigned(15 downto 0);
   sum_Result := (a + b);
   return sum_Result;
 end function;

Unlike Verilog functions, VHDL functions may not read global variables, and this restriction also applies to functions generated from Verilog. The Verilog-2001 "automatic" keyword is supported and generates recursive VHDL functions.

Tasks[edit | edit source]

Signals and Types[edit | edit source]

Single-bit signals are converted to VHDL std_logic signals. Multi-bit vectors are converted to the signed/unsigned types from the ieee.numeric_std package. Conversion between these types is handled automatically, as is conversion from Boolean to std_logic values.

The mapping between Verilog signal values and std_logic values is as follows:

Verilog valueVHDL value

Drive strengths are not yet implemented.

Signal names which conflict with VHDL reserved words, differ only in case to another signal name, or are otherwise invalid as VHDL signal names are automatically renamed -- usually by prefixing "VL_".

Logic Gates[edit | edit source]

Primitive logic gates are translated to VHDL concurrent assignment statements. For example:

and(Z, X, Y);
Z <= X and Y;

Assignment[edit | edit source]

Verilog blocking and non-blocking assignment are implemented using the the VHDL signal assignment operator.

Non-blocking assignment in Verilog has the same semantics as signal assignment in VHDL. For example, the following statement schedules the update of X at the next delay statement in Verilog, or wait statement in VHDL, or the end of the process:

X <= Y;

However, the Verilog blocking assignment operator schedules the update immediately. To emulate this in Verilog a zero-time wait is added after the assignment; this causes the VHDL simulator to schedule the update immediately after the statement has executed. For example, this Verilog statement:

X = Y;

Produces the following VHDL statements:

X <= Y;
wait for 0 ns;

The zero-delay wait is omitted if the statement is the last in the process, or the immediately following statement was a wait anyway.

Branching and Looping[edit | edit source]

Verilog if statements are translated directly to VHDL if statements which have identical semantics.

Verilog case statements can be translated to VHDL case statements provided the control and test expressions are "locally static" (basically, signal references or constants). If the control expression is not locally static, the VHDL code generator will assign it to a temporary variable immediately before the case statement and use that temporary as the control expression. For example, the following control expression would produce an invalid VHDL case statement:

case (cond&4'b1110)

So the code generator produces code to evaluate the expression separately and store it in a temporary:

  variable Verilog_Case_Ex : unsigned(3 downto 0);
  Verilog_Case_Ex := (cond and "1110");
  case Verilog_Case_Ex is

Test expression that are not locally static will currently produce invalid VHDL.

Time and Delays[edit | edit source]

User-defined Primitives[edit | edit source]

Limitations[edit | edit source]

Signal Values and Resolution[edit | edit source]

There are several cases where the behaviour of the translated VHDL deviates from the source Verilog:

  • The result of division by zero is x in Verilog but raises an exception in VHDL.
  • Similarly, the result of reading past the end of an array in Verilog is x, whereas VHDL raises an exception.
  • Any signal that is driven by two or more processes will have the value 'U'. This is the result of the signal resolution function in the std_logic_1164 package.

Constructs not Supported[edit | edit source]

The following Verilog constructs cannot be translated to VHDL:

  • fork and join
  • force and release
  • disable
  • real-valued variables
  • switches
  • hierarchical dereferencing

Other Limitations[edit | edit source]

  • The test expressions in case statements must be constant.
  • Translation of a parameter to a corresponding VHDL generic declaration. Instead the default parameter value is used.
Community content is available under CC-BY-SA unless otherwise noted.