チートシート

VHDL、Verilog、SystemVerilogの対照表

VHDL-2008、Verilog-2001、SystemVerilogで日常的に書く構文のロゼッタ表と、表に収まらないものについてのコンパイル済みスニペットです。

最終確認 2026年11月13日· VHDL-2008, Verilog-2001, SystemVerilog-2012, checked with Icarus Verilog 13.0 and nvc

このページは、1つのハードウェア記述言語を読めて、別の言語で書く必要があるエンジニアのためのものです。対応付けるのは合成可能なサブセットだけです。以下のスニペットはすべて、完全なモジュールの一部として、公開前にIcarus Verilog(SystemVerilogモード)またはnvc(VHDL-2008)でコンパイルしています。SystemVerilogとVerilog-2001が異なる箇所は両方を示します。多くのベンダーフローが今でも.vファイルをVerilog-2001、.svをSystemVerilogとして扱うのが既定だからです。

ロゼッタ表

構文 VHDL-2008 Verilog-2001 SystemVerilog
設計単位 entityとarchitecture module module
入力ポート a : in std_logic input wire a input logic a
出力ポート y : out std_logic_vector(7 downto 0) output reg [7:0] yまたはoutput wire output logic [7:0] y
ネットまたは変数 signal(architecture内)、variable(process内) wire(assignで駆動)、reg(alwaysで駆動) 両方ともlogic
レジスタ、同期リセット if rising_edge(clk) then if rst = '1' then ... elsif en = '1' then ... always @(posedge clk) if (rst) ... else if (en) ... always_ff @(posedge clk) ...
非同期リセット if rst = '1' then ... elsif rising_edge(clk) then ... always @(posedge clk or posedge rst) always_ff @(posedge clk or posedge rst)
組み合わせ論理ブロック process (all) always @* always_comb
ノンブロッキング代入 <=(process内のsignal) <= <=
ブロッキング代入 :=(variable) = =
2対1マルチプレクサ y <= a when sel = '1' else b; assign y = sel ? a : b; 同じ
case文 case sel is when "00" => ... when others => ... case (sel) 2'b00: ... default: ... unique caseまたはpriority case
ループgenerate g : for i in 0 to N-1 generate ... end generate; genvar i; generate for (...) begin : g ... end endgenerate for (genvar i = 0; ...) begin : g
条件generate if COND generate ... else generate(2008) generate内でif (COND) begin : g ... end 同じ
パラメータ generic (WIDTH : positive := 8) parameter WIDTH = 8 parameter int WIDTH = 8
ローカル定数 constant C : natural := 3; localparam C = 3; localparam int C = 3;
パッケージ package p is ... end package;とuse work.p.all; なし(インクルードファイルを使う) package p; ... endpackageとimport p::*;
ベクタの配列 type mem_t is array (0 to 15) of std_logic_vector(7 downto 0); reg [7:0] mem [0:15]; logic [7:0] mem [16];
符号なし演算 ieee.numeric_stdのunsigned 素のベクタは符号なし 同じ、またはlogic unsigned
符号付き演算 numeric_stdのsigned reg signed [7:0] logic signed [7:0]
整数 integer、natural、positive(32ビット、範囲付き) integer(32ビット符号付き) int、shortint、longint、byte
ベクタから整数へ to_integer(unsigned(v)) 暗黙 暗黙、またはint'(v)
整数からベクタへ std_logic_vector(to_unsigned(i, 8)) 暗黙の切り詰め 8'(i)
サイズ変更 resize(u, 16) 代入によるゼロ拡張または符号拡張 16'(u)または代入
定数のビット幅 (others => '0')、x"FF" {WIDTH{1'b0}}、8'hFF '0、'1、8'hFF
連結 a & b {a, b} {a, b}
複製 (others => x)または(7 downto 0 => x) {8{x}} {8{x}}
リダクションAND and v(2008) &v &v
合成属性 attribute async_reg : string; attribute async_reg of ff : signal is "TRUE"; (* ASYNC_REG = "TRUE" *) reg [1:0] ff; Verilogと同じ
列挙型の状態 type state_t is (IDLE, RUN); localparam IDLE = 2'd0, RUN = 2'd1; typedef enum logic [1:0] {IDLE, RUN} state_t;
レコードまたは構造体 type hdr_t is record ... end record; なし typedef struct packed { ... } hdr_t;
関数 function f(x : natural) return natural is ... end function; function [7:0] f; input [7:0] x; ... endfunction function automatic logic [7:0] f(input logic [7:0] x);
アサーション(シミュレーション) assert cond report "msg" severity error; if (!cond) $error("msg"); assert (cond) else $error("msg");
コメント -- lineまたは/* block */(2008) // line、/* block */ 同じ

同期リセットとイネーブル付きレジスタ

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter is
  generic (WIDTH : positive := 8);
  port (
    clk : in  std_logic;
    rst : in  std_logic;
    en  : in  std_logic;
    q   : out std_logic_vector(WIDTH-1 downto 0)
  );
end entity;

architecture rtl of counter is
  signal q_r : unsigned(WIDTH-1 downto 0) := (others => '0');
begin
  process (clk) begin
    if rising_edge(clk) then
      if rst = '1' then
        q_r <= (others => '0');
      elsif en = '1' then
        q_r <= q_r + 1;
      end if;
    end if;
  end process;
  q <= std_logic_vector(q_r);
end architecture;
module counter #(parameter WIDTH = 8) (
  input  wire             clk,
  input  wire             rst,
  input  wire             en,
  output reg  [WIDTH-1:0] q
);
  always @(posedge clk) begin
    if (rst)     q <= {WIDTH{1'b0}};
    else if (en) q <= q + 1'b1;
  end
endmodule
module counter #(parameter int WIDTH = 8) (
  input  logic             clk,
  input  logic             rst,
  input  logic             en,
  output logic [WIDTH-1:0] q
);
  always_ff @(posedge clk) begin
    if (rst)     q <= '0;
    else if (en) q <= q + 1'b1;
  end
endmodule

VHDL版が内部にunsigned型のsignalを持つのは、std_logic_vector型のoutポートには加算ができないためです。VHDL-2008では出力ポートの読み出しが許されるので、中間signalは必須ではなく選択です。

case文による4入力マルチプレクサ

architecture rtl of mux4 is
begin
  with sel select y <=
    a when "00",
    b when "01",
    c when "10",
    d when others;
end architecture;
always @* begin
  case (sel)
    2'd0:    y = a;
    2'd1:    y = b;
    2'd2:    y = c;
    default: y = d;
  endcase
end
always_comb begin
  unique case (sel)
    2'd0:    y = a;
    2'd1:    y = b;
    2'd2:    y = c;
    default: y = d;
  endcase
end

uniqueは、ちょうど1つの分岐だけが一致することを合成ツールに伝え、優先順位の連鎖を取り除きます。これは最適化のヒントにすぎません。ラッチを防ぐのは依然としてdefaultの分岐です。

for-generate

architecture rtl of and_tree is
begin
  g_bit : for i in 0 to N-1 generate
    y(i) <= a(i) and b(i);
  end generate;
end architecture;
genvar i;
generate
  for (i = 0; i < N; i = i + 1) begin : g_bit
    assign y[i] = a[i] & b[i];
  end
endgenerate

SystemVerilogではgenerateとendgenerateのキーワードは省略可能で、genvarはループのヘッダで宣言できます。beginの後のラベルは、生成されたインスタンスに階層名が付くように多くのツールが要求します。

パッケージ

package fifo_pkg is
  constant DEPTH : positive := 16;
  subtype byte_t is std_logic_vector(7 downto 0);
  function clog2_of(n : positive) return natural;
end package;

package body fifo_pkg is
  function clog2_of(n : positive) return natural is
    variable r : natural := 0;
  begin
    while 2**r < n loop
      r := r + 1;
    end loop;
    return r;
  end function;
end package body;
package fifo_pkg;
  localparam int DEPTH = 16;
  typedef logic [7:0] byte_t;
  function automatic int clog2_of(input int n);
    return $clog2(n);
  endfunction
endpackage

module fifo_user import fifo_pkg::*; (
  input  byte_t d,
  output byte_t q
);
  localparam int AW = clog2_of(DEPTH);
  assign q = d;
endmodule

Verilog-2001にはパッケージがありません。通常の回避策は、`defineマクロを書いたヘッダか、階層を通して渡すパラメータです。VHDLのパッケージにはその上にlibrary ieee; use ieee.std_logic_1164.all;の行が必要ですが、紙幅の都合で省略しています。

配列とメモリ

architecture rtl of ram16x8 is
  type mem_t is array (0 to 15) of std_logic_vector(7 downto 0);
  signal mem : mem_t;
begin
  process (clk) begin
    if rising_edge(clk) then
      if we = '1' then
        mem(to_integer(unsigned(addr))) <= d;
      end if;
      q <= mem(to_integer(unsigned(addr)));
    end if;
  end process;
end architecture;
logic [7:0] mem [0:15];
always_ff @(posedge clk) begin
  if (we) mem[addr] <= d;
  q <= mem[addr];
end

どちらもレジスタ付き読み出し(同一アドレスではリードビフォアライト)のブロックRAM(BRAM)を推論します。Verilog-2001の形は、logicをregに、always_ff @(posedge clk)をalways @(posedge clk)に置き換えたものと同じです。

型変換と符号

-- s is signed(7 downto 0), u is unsigned(7 downto 0), sum is 9 bits
sum <= std_logic_vector(resize(signed(s), 9) + signed(resize(unsigned(u), 9)));
idx <= to_integer(unsigned(u(3 downto 0)));
// s is logic signed [7:0], u is logic [7:0], sum is logic signed [8:0]
assign sum = s + $signed({1'b0, u});
assign idx = u[3:0];

この規則の違いは落とし穴になります。VHDLでは何も暗黙に変換されず、コンパイラは混合型を拒否します。VerilogとSystemVerilogでは、式が符号付きになるのはすべてのオペランドが符号付きのときだけなので、符号なしのオペランドが1つあるだけで式全体が黙って符号なしになり、符号拡張が失われます。$signed({1'b0, u})のイディオムは、uを正に保ちながら加算を符号付きで行わせます。

合成属性

signal ff : std_logic_vector(1 downto 0);
attribute async_reg : string;
attribute async_reg of ff : signal is "TRUE";
(* ASYNC_REG = "TRUE" *) logic [1:0] ff;

属性名はベンダー固有です。AMDではASYNC_REG、KEEP、DONT_TOUCH、MAX_FANOUT、RAM_STYLE。Alteraはpreserve、keep、ramstyle、altera_attributeを使います。Libero SoCやLattice Diamondに含まれるSynopsys由来のツールはsyn_keep、syn_preserve、syn_ramstyleを使います。Yosysはkeepと独自のいくつかを尊重します。

翻訳できないもの

VHDLのみ VerilogとSystemVerilogのみ
ユーザー定義の範囲付き整数を含む強い型付け 算術における4状態のx伝播
genericに対するcase付きgenerate(2008) `ifdefプリプロセッサと`include
protected型と共有変数 インターフェースとmodport(SystemVerilog)
単位付きの物理型(timeのほか、ユーザー定義も可) クラス、制約付きランダム、カバレッジ(SystemVerilog、シミュレーションのみ)
configuration(ほとんど使われない) シミュレーションでのモジュールをまたぐ階層参照

出典

誤りやバージョン変更に気づいたら 訂正の手順をご覧ください。