VHDL、Verilog、SystemVerilogの対照表
VHDL-2008、Verilog-2001、SystemVerilogで日常的に書く構文のロゼッタ表と、表に収まらないものについてのコンパイル済みスニペットです。
このページは、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(ほとんど使われない) | シミュレーションでのモジュールをまたぐ階層参照 |
出典
- IEEE 1076-2019, VHDL Language Reference Manual
- IEEE 1800-2023, SystemVerilog
- Yosys documentation, supported SystemVerilog subset
- nvc VHDL simulator
- 当サイトの関連ページ: /topics/hdl-languages/ と /reference/reset-and-cdc-patterns/