VHDL入門: 第1回 AND_OR_NOTの記述と文法

マイコンを開発する際には主にソフトウェアで機能を実現しますが、IOポートの本数が不足する、IOの駆動能力が不足する、メモリー容量が不足するなどはソフトウェアでは解決できません。このソフトウェアで解決できないことを実現するのに便利なのがPLDやFPGAです。テキスト・ベースで回路を記述するための言語(HDL)であるVHDLとFPGAについて基礎的なことを解説します。

[▲上位階層] 2005/11/07 新規作成, 2016/02/22 更新

目次

  1. これからはVHDLでディジタル設計をしよう
    1-1 VHDLは配線数・端子数の増大に対応できる
    1-2 VHDLは開発効率が高い
    1-3 VHDLはデータの互換性/移植性が高い
    1-4 VHDLとVerilogの比較
  2. 開発フロー
    2-1 ツール
    2-2 ファイル
  3. VHDLの文法の基本要素
    3-1 予約語
    3-2 識別子
    3-3 コメント(注釈)
    3-4 改行と空白の扱い
    3-5 演算子
    3-6 ライブラリ宣言
    3-7 デザイン・ユニット
  4. ゲート回路の表現
    4-1 AND アンド・ゲート
    4-2 OR オア・ゲート
    4-3 NOT インバータ
  5. VHDLソース・コード
  6. まとめ
  7. 用語説明
⇒第2回 フリップフロップの記述とテストベンチ
⇒VHDL,Verilogの開発環境 ModelSim

はじめてのVHDL [ 坂巻佳寿美 ]/東京電機大学出版局/ [目次] 1)VHDLの基礎/2)ストップウォッチを作る「組み合わせ回路まで」/3)ストップウォッチを作る「順序回路から」/4)VHDL文法のあらまし 2,268円 (税込)

ALTERA社製CYCLONE(EP1C3T100C8N)を搭載したFPGAボード(レギュレータ搭載)  6,000円 (税込、送料別 )

これからはVHDLでディジタル設計をしよう

VHDLとは「テキスト・ベース」で回路(または機能)を表現するための言語(HDL)の1つです。以前はASIC,PLDの開発に回路図入力がよく使用されていましたが、なぜそれが今はHDLを使用するようになったのでしょうか? 1つは開発効率をあげるため、そして標準化のためです。

VHDLは配線数・端子数の増大に対応できる

デジタルICの進歩は早く高集積度、高速になりました。1000ピンぐらいのICを使用する事が時々あります。実際に回路図ベースで大規模な回路入力をしてみるとわかるのですが、上の方の階層の方に行くにしたがってブロックの端子数が多くなるで入力するのが大変です。

グラフィックだと部品の位置、配線の重なり、文字と他の要素が重なってしまうなどレイアウトが気になり余分な作業工数がかかります。テキスト・ベースではそれを気にする必要がありません。

また回路図は用紙の大きさに依存するという問題があります。一番大きな用紙を使用してもブロックが紙からはみ出てしまったり、縮小すると印刷した時に端子名があまりに小さくなってしまって回路図を目で読めなくなってしまったりします。大型のプロッターは、高価であるので通常のプリンターしかないということが多いのではないでしょうか。仕方がなく複数のページに分割するのですが今度はページ数が多くなりすぎてしまって端子名、信号名などを目で探すのが大変になってしまいます。

グラフィックの方が見易いと思うかもしれませんがそれは単純な回路の場合だけで、複雑な回路では配線が網目のようになってしまい返って見づらいです。テキスト・ベースならばどんなにピン数が多くなっても印刷して文字が見れなくなることがなく、A4ぐらいのプリンターでも問題ありません。

VHDLは開発効率が高い

回路図入力を使用してゲート・レベルで入力するよりもVHDLを使用して、"RTL"で入力する方が早く出来ます。VHDLを利用すると抽象的な記述が可能で記述量が少なくて済むからです。回路図レベルでもソフトマクロを使用すれば抽象度をあげられますがこれらソフトマクロは標準化がされていません。大規模な回路はシミュレーションに何時間もかかります。RTLでのシュミレーションはその時間の短縮ができるので有利です。

VHDLのシュミレータは、ブレーク・ポイントを設定し、止まった時に変数の状態を調べるなどソフトウェアのデバッグと同等な手法が使えるのでソフト屋さんにとって理解し易いということもあるかもしれません。

VHDLはデータの互換性/移植性が高い

回路図ベースの場合はファイルが通常バイナリになっておりCAD固有のため互換性がありません。ツールを変えた場合、回路図資産の継承に困りました。HDLについてはVerilogとVHDLの2つがほぼ業界標準です。テキストベースであるためツールを変更した場合やPC←→ワークステーションのデータ交換も問題がありません。CADファイルの場合そのCADをインストールしてあるPCでないとそのデータを見ることができませが、HDLならばテキストベースなのでメールで送れば誰でも見ることが可能、かつ変更も可能です。品種の異なるPLDでも同じソース・コードが使用可能なのはVHDLの大きなメリットです。回路図の方が見やすく感じるかもしれませんがそれはなれの問題です。

回路図ベースのファイル・フォマットを統一しようという試みや、回路図のソフト・マクロに互換性を持たせようという試みもあるようですがあまり普及していないようです。どうしても回路図には限界があるのでHDLへに移行が必須だと思います。

開発ツールには回路図入力もありますがそれは過去の遺物で新規設計には使わないようにしましょう。

VHDLとVerilogの比較

初めてHDLを学習する方にとってVHDLとVerilogのどちらを学習すればよいか迷うと思います。結果から申し上げますと両方です。どちらにも特徴があります。ソフト開発の経験が有る方ならばVerilogはC言語に近い、VHDLはAdaやPascalに近いといえばニュアンスはわかると思います。

VHDLは型に厳密であるため型が違う場合、いちいち変換しなければなりません。厳密であるのでソース・コードの不具合をコンパイラが自動検出してくれます。IPを作るために便利な機能があります。自動車、航空機、医療機器、軍事など信頼性を重視した設計に適しています。

Verilogはそれほど型にはうるさくなく、ソースの記述量もVHDLよりも少なくてすみます。また、シュミレーションやテスト・ベンチの時に便利な機能があります。

実際に大規模なセルベースICを作成する場合は社内にある設計資産をかき集めたり、外部から購入してきたIPを組み合わせて使用します。全てのブロックを新規設計するわけにはいかないのでVerilogだけまたはVHDLだけで構成するのは不可能です。結局 VerilogとVHDL、回路図入力全ての知識が必要になる場合が多いです。それぞれの使い分けですがテスト・ベンチなどはVerilogでIPはVHDLで記述する場合が多いようです。小規模なPLDを開発する場合はVHDL,Verilogのどちらでも大差はないと思います。

開発フロー

開発フロー
【図1 PLDの開発の流れ】

Xilinx社の開発ツール ISEとModelSimを使用する場合について説明します。ISEではデバイス固有のことを行い、ModelSimはシミュレーションを行います。開発ツールの大枠は左の図のような構成になっています。

ツール

テキスト・エディタ
ソース・コードの作成します。(デザイン入力) 統合開発環境(ISE)に付属しているものを使用してもかまいませんが、 普段使い慣れているツールでも良いです。
シミュレータ(Modelsim)
設計した回路が正しく動作するかをコンピュータ上の計算によって確認します。(シミュレーション)
シミュレーションには、「ほぼ0nsの遅延」で行う、「RTLシミュレーション」(ファンクション・シミュレーション)と実際のゲートの遅延や配線の遅延を加味した「ゲートレベル・シミュレーション」(タイミング・シミュレーション)があります。
コンパイラ
ソース・コードからプリミティブ(またはセル)と配線のみで表されたされた表現である「ネットリスト」を出力します。(論理合成/デザイン合成) この状態では配線の遅延、プリミティブが実際にどこに配置されるか決まっていません。
フィッタ
実際にプリミティブがPLDの中のどこに配置するかを決めます。 あるいは配線の仕方を決めます。(配置配線/デザイン・インプリメンテーション)ここで回路の遅延が決定します。
スタティック・タイミング解析ツール
配置配線後の遅延が設計どうりにできたか確認します。(STA)
コンフィグレーション・ハードウェア
ビット・ストリームをPLDデバイスに電気的に転送して設計した回路が動作できる状態にします。(ダウンロード)
実機評価
システム全体を含めた状態、かつリアルタイムで動作させて 仕様どうりに動いているか確認します。

ファイル

VHDL開発で設計者が入力するファイルはVHDLのソース・コード、制約ファイルです。VHDLのソース・コードは実際にロジック(回路)を生成するのに使用するものとロジックをテストするために使用する「テスト・ベンチ」があります。

通常は1つのファイルに1つのエンティティと関連するアーキテクチャ1つを入れます。(1つのファイルが1つのブロックに対応)制約ファイルはVHDLの規格ではなく各PLDメーカ固有で互換性は無いようです。

VHDLソース・コード
回路の動作、またはプリミティブの接続を表現したテキスト・ファイル。(通常は設計者が手で入力する)
制約ファイル
論理合成をする際の条件を指定します。 一般的には、ピン配置の指定と最大動作クロック周波数を指定します。 テキストファイルで指定することもできますしGUIで入力することも可能です。
EDIFネットリスト
対象とするPLD固有のプリミティブ(またはセル)と配線での回路表現です。EDIFと呼ばれるファイル形式が業界標準で使用されています。
SDF遅延情報
プリミティブと配線の遅延データです。SDFと呼ばれるファイル形式が業界標準で使用されています。ゲートレベルシミュレーションの場合に必要でRTLシミュレーションでは使用しません。
各種レポートファイル、ログファイル
テキスト形式でSTAの結果、エラー・メッセージなどが出力されます。ほとんどのツールはコンソールと共にログファイル(またはレポートファイル)を出力します。バグの無い回路を設計するためには面倒がらずログ・ファイルをチェックするしましょう。
ビット・ストリーム
最終的にPLDに転送する、配置配線済みの回路データ。

VHDLの文法の基本要素

ここでは、文法の基本要素から説明していきます。複雑な記述、抽象的な記述は第2回以降その都度説明します。 マイコンなどでC言語を知っている方が多いと思いますので、C言語との比較も掲載します。

予約語

「予約語」とは使用目的が決まっていて、識別子に使えない単語です。 以下、アルファベッド順に予約語を示します。WAITなどは端子名としてよく使われるので重複に注意してください。

【表1 予約語の一覧】
abs
access
after
alias
all
and
architecture
array
assert
attribute
file
for
function
nand
new
next
nor
not
null
then
to
transport
type
begin
block
body
buffer
bus
generate
generic
group
guarded
of
on
open
or
others
out
unaffected
units
until
use
case
component
configuration
constant
if
impure
in
inertial
inout
is
package
port
postponed
procedure
pure
variable
disconnect
downto
label
library
linkage
literal
loop
range
record
register
reject
rem
report
return
rol
ror
wait
when
while
whith
else
elseif
end
entity
exit
map
mod
select
severity
shared
signal
sla
sll
sra
srl
subtype
xnor
xor

識別子

「識別子」とは信号名、端子名、ブロック名、ラベルなどに使用される名前です。予約語と重複しない英数字からなる単語を用います。

VHDLでは大文字と小文字を区別しませんが大文字と小文字の使い分けには何かルールを決めておくと見やすくなります。たとえば予約語は小文字を使用、識別子は大文字を使用など。

識別子に区切りがほしいときには _ を使うことができますが、先頭や最後に _ を使用しないこと、連続して2つ以上繰り返さないことなどの制約があります。

コメント(注釈)

「コメント」とはロジックの生成には影響をあたえない、任意の文章です。一般的にソース・コードの説明などを記入します。VHDLのコメントは -- で始まって行末で終了します。C言語の /* */ のように複数行にわたって継続するコメントはありません。 コメントはまったくなくてもロジック(回路)を作ることができるのでおざなりにされやすいのですが保守のためには重要な部分です。私は以下のようにしています。

タイトルと概略

コメントのうち最低限必要なものは、ブロックの名称(エンディティ)、設計担当者、作成した日付、ポートの説明です。

ソース・コード先頭にブロックの名称、設計担当者、日付を入れます。

【リスト1 コメントの書き方】
-- ブロック名称   日付 設計担当者(部署)
-- ブロックの簡単な説明

設計担当者

大規模な回路設計の場合、すでに社内にある設計済みのソース・コードやIPをかき集めて、それで1機種の製品、(またはLSI)を作成します。 社内で設計した古いソース・コードとかで、そのブロックに対する質問をしたい場合にそのブロックは誰が設計したかわからなくて困る場合があります。 設計者が他の部署に移動していたり、派遣の人間が設計していて今は社内にいないとか困りますよね。開発が終わって年月がたっても設計者がわかるようにしておくことは重要です。

作成した日付

ファイルは簡単にコピーできてしまうのであちこちのPC,ワークステーションに重要なファイルのコピーが存在するかもしれません。その際にどのファイル、バージョンが最新で信用できるものなのかわからなくなる場合があります。ファイルのタイムスタンプが目安にはなりますが、ファイルの内容を変更していないで上書き保存する場合もあり確実ではありません。ファイル先頭にコメントとして入れておくと管理ミスが発生しにくいです。

ポートの説明

エンティティの部分でそれぞれのポート(外部端子)の意味または機能の説明をいれます。ポートはそのブロックの内部回路と外部とのインターフェースを限定する部分なので重要です。

ブロックの機能説明

再利用の観点からは、ソース・コード全体を見ないでそのブロックの動作がわかるような説明文があった方が良いと思います。

評価済のロジック部分はできるだけ、変更をするべきでありません。ロジック部分(アーキテクチャ)の記述部分を読み始めてしまうと記述がきたなくて変更したくなるとか識別子のネーミングが気に入らないとか出てきてしまうと思います。この業界は短納期で仕事をやらなければならない場合が多いので記述がきたなくても評価済で正常に動作することが確認されているのであればできるだけ見ない・さわなないようにすべきでしょう。

紙に整理されたきれいなドキュメント(またはワープロのファイル)はたしかに見やすいのですが作成するのに多大な工数がかかります。それに紙に整理されたドキュメントの場合はソース・コードと1体ではないのでソース・コードを変更してドキュメントは修正されていないということがよくあります。必要最低限の工数で保守可能な情報を残すという意味でファイル先頭での機能説明は必要です。

ただ上位のブロックでは非常に機能が多く、それをわかりやすい文章で表現するのは難しいものです。コメントを書くのにあまり悩んでしまうのは設計効率を落としてしまいます。なので省略してしまうのではなく、全ての機能を説明しなくても良いから概略で説明するのが良いと思います。

1行毎のコメント

自分のためのメモ的な役割のコメントは重要ではありません。保守性という意味ではコメントは多い方が良いと思いコメントを多くしすぎるとそのコメントの作成に時間がかかってしまうのでそれらはバランス感覚になると思います。またコードだけ修正してコメントは修正しなかったということが起こり易く、そのようなものが残っていると再利用しようとする人を返って迷わせてしまいます。小見出し的なものはいれると見やすくなります。

改行と空白の扱い

単語の区切りとして半角の空白、改行、または記号を用います。 文字列リテラル内を除き、2つ以上の空白は、1つの空白と同じです。 文字列リテラルやコメントを除き全角の空白を使うとエラーになるので注意してください。

単語の途中でないならば任意の場所で改行ができます。コメント中の場合はそこでコメントが終了します。 1つの文を複数の行に分割して記述したり、1行の中に複数の文を記述することができます(セミコロンで区切る)。

演算子

「演算子」とは、1つ以上の入力値に対して演算を行い、1つの値を返す 働きをする単語です。式の中で用いられ、制御は行いません。

【表2 演算子の一覧】
分類演算子説明
論理演算子and論理積
or論理和
not否定
xor排他的論理和
nand反転・論理積
nor反転・論理和
xnor反転・排他的論理和
算術演算子+加算
-減算
*乗算
/除算 (論理合成不可の場合が多いので注意)
modモジュロ
rem剰余
※その他に関係演算子、結合演算子、アブソリュート、指数があります。
※乗算は巨大なロジックを生成する場合があるので論理合成する部分での使用には注意。除算は一般的に論理合成できない。

演算子の優先順位

C言語の場合は演算子の種類によって優先順位が決まっていて括弧が無くてもコンパイルエラーにはなりません。しかしVHDLでは1つの文で複数の演算子を使用する場合、括弧をつけて優先順位を明確にする必要があります(コンパイラでのチェック有)。andだけ、orだけの場合は演算順序を変えても結果が同じなのでエラーにはなりません。

【表3 演算子の優先順位 】(上の方が優先順位が高い)
その他の演算子abs **
乗法演算子* / mod rem
加法演算子= - &
関係演算子= /= < <= > >=
論理演算子and or nand nor xor not

ライブラリ宣言

ライブラリとパッケージの概念
【図2 ライブラリとパッケージの概念】

「ライブラリ」とはコンパイル済の設計データ(パッケージ)を保存しておく場所です。ライブラリは複数のパッケージを保存することが可能です。通常は1つのライブラリとして同じ名称の1つのディレクトリーが対応します。1つのライブラリは0個以上のパッケージを格納することができます。エンディティーやアーキテクチャのコンパイル結果は特に指定がない場合は"work"という名前のライブラリに保存されます。

「ライブラリ宣言」は、ライブラリ, パッケージの内容を見えるようにします。書式は次の通りです。

ライブラリ宣言の書式
library ライブラリ名{, ライブラリ名};
use ライブラリ名.パッケージ.all;
{ }は0回以上繰り返しが可能。

「パッケージ」は、複数のデザイン・ユニットで共通に使用する関数、定数、エンティティなどの宣言を共有するためのしくみです。 1つのパッケージには0個以上の宣言を格納することができます。 次第に自分独自のパッケージを作りたくなると思いますが始めの頃は標準で用意されたパッケージを使えるようにする手段だとの理解で良いと思います。

C言語の"#include"で言えば、ライブラリ名はたくさんインクルード・ファイルを作った時に仕分けするためのディレクトリー名に相当します。workがカレント・ディレクトリーに相当し、パッケージが1つのインクルード・ファイルに相当。 ただし"#include"のようにそこに他のファイルが挿入されるわけではありません。 ライブラリ名はコンパイル済みのデータを保管しておく場所という意味もあるのが相違点です。

予約語"all"はパッケージの全てを表します。初級では"all"のみの使用で問題はないでしょう。 VHDLではパッケージの一部だけ可視化する機能があります。

ライブラリ宣言がファイル先頭で宣言された場合、1つのエンティティ宣言とそれに関連するアーキテクチャまで有効です。エンティティ宣言が2つ以上ある場合はあらためて宣言しなおします。

システムで定義されているライブラリ

STANDARDというライブラリは指定がなくても常に可視化されています。 CHARACTER, BOOLEAN, BIT, BIT_VECTER, INTEGERなど基本的なタイプが定義されています。STDの中にはパッケージ STANDARD,TEXTIOが含まれていて、開発環境にこれらのソース・コードは付属しているので詳細はそれを見るとわかります。

【リスト2 暗黙的に宣言されているライブラリ】
library STD;     -- 記述不要
use STD.STANDARD.all;

STD_LOGICは必ずと言っていいぐらい使用するので以下のライブラリは必須だと思ってよいでしょう。

【リスト3 ファイル先頭でとなえるおまじない】
library IEEE;  -- STD_LOGIC, STD_LOGIC_VECTORを使用可能にする
use IEEE.STD_LOGIC_1164.all;

デザイン・ユニット

「デザイン・ユニット」とはエンティティ、アーキテクチャ などのことです。

エンティティの宣言

「エンティティ」とはブロックの内部と外部を接続するためのインターフェース(ブロック名、外部ポートなど)を定義します。書式は以下の通りです。

【エンティティ宣言の簡略書式】
entity エンティティ名  is  [ポート宣言]  end [エンティティ名];
[]は省略可能。正式な書式ではジャネリックなどを追記することができる。
AND_OR_NOTのエンティティ
【図3 これから作成するAND_OR_NOTのエンティティ】

エンティティはブロックの外枠に相当します。「ブロック」とは、再利用やテストをしやすくするため、意味のある扱い易い大きさに括った回路単位です。

大きなシステムを設計する際にはまずインターフェース(エンティティ)の部分の仕様をはっきり決めてから内部回路(アーキテクチャ)を記述します。その状態でシュミレーションをして仕様自身に誤りがないかを確認します。

小規模な回路では初めから論理合成が可能な記述(RTL)で書くことが多いのですが、大規模な回路の初期段階では論理合成ができない抽象的な書き方をすることもあります。その後実際に論理合成が可能な回路でソース・コードを作成します。このような手法ではインターフェース部分と内部回路部分が別になっていてその組み合わせを自由に変えられるようになっていると便利です。

ポートの宣言

「ポート文」は、そのブロックの端子(ポート)を宣言します。書式は以下の通りです。

【ポート文の簡略書式】
port(端子名{, 端子名} :[端子の方向] 信号タイプ);
端子の方向は、 in | out | inout | buffer | linkage
| はいずれか1つを選択する。{ }は0回以上の繰り返し。
※正式な書式では初期値、busを追加できる。

端子の方向は、inが入力, outが出力, inoutが入出力を表します。 その他にbuffer、linkageというのがありますが初級では使いません。

信号タイプはSTD_LOGIC, STD_LOGIC_VECTOR, SIGNED, UNSIGNEDのいずれかを使用します。 古い本を見るとBIT, BIT_VECTORが使われていることがあります。 これらは、何もパッケージを指定しなくても使用可能ですが最近は使われません。 トライ・ステートやプルアップを表現できない、信号の状態が'0'と'1'しか使えないからです。 シュミレーションだけならばその他のタイプも利用可能ですが、しばらくは1本の信号の場合はSTD_LOGIC, 複数の信号(バス)の場合はSTD_LOGIC_VECTORと使うと覚えてください。

【表4 信号のクラス】
クラス意味・用途備考
BIT1本の信号線現在はほとんど使用しない
BITVECTORバス現在はほとんど使用しない
STD_LOGIC1本の信号線トライステートを表現できる
STD_LOGIC_VECTORバスバスに対して主にビット演算をする場合
SIGNEDバスバスを符号あり整数とみなして数値演算をする場合
UNSIGNEDバスバスを符号なし整数とみなして数値演算をする場合

OUTポートは書き込みだけで読み出しができないので注意してください。OUTポートに対して読み書き両方したい場合は別途、信号線を用意します。

STD_LOGIC, STD_LOGIC_VECTOR は以下の9つの状態を表現することができます。

【表5 STD_LOGICの値】
説明備考
0'L'に強く駆動ゲートのL出力
1'H'に強く駆動ゲートのH出力
Z駆動されていない事を表すオープン(トライステートバッファOFF状態)
X不定を表すどのような状態になるかは保証されない
L弱く'L'に駆動プルダウン抵抗でGNDに接続されている状態
H弱く'H'に駆動プルアップ抵抗でVCCに接続されている状態
W弱い不定どのような状態になるかは保証されない
U初期値フリップフロップやレジスタが1度も書き込まれていない状態
-don't care

初級において入力は'1', '0'出力はそれに加えて 'X', 'Z'を覚えていれば良いでしょう。PLD内部でトライステート'Z'を使えるかどうかはその品種により異なります。通常はIOバッファーの所のみでトライステートが使えるようになっているはずです。なのでできるだけ内部バスはトライステートを使わずにマルチプレクサで設計します。どうしても内部でトライステートを使いたい場合は、使用予定PLDのデーターシートで使えるかどうか?何本まで使えるか?を確認してからにしてください。

アーキテクチャの宣言

「アーキテクチャ宣言」はブロックの中身がどのようになっているか記述します。 architectureとbeginの間で、信号や定数、部品の宣言を行い。 beginとendの間で、ブロックの内部がどのような機能を持っているか、またはどのような回路になっているか記述します。書式は以下の通りです。

【アーキテクチャの書式】
architecture アーキテクチャ名 of エンティティ名 is
    {アーキテクチャの中で使用する信号や定数、部品の宣言}
begin
    {回路記述}
end [アーキテクチャ名] ;
{ }は0回以上繰り返し可能。

ゲート回路の表現

ここではいちばん簡単なアーキテクチャとしてシンプルなゲートの記述(同時処理文)を説明していきます。

AND、OR、NOT(アンド・ゲート、オア・ゲート、インバータ)は全てのディジタル回路の基本要素です。このの3種類のゲートさえあればどんなデジタル回路でも実現しえます。特に動作周波数を高めたり、遅延を調整するときには、ゲートやフリップ・フロップを駆使します。 実務にて、基本要素のみで回路を構成すると開発効率の点で好ましくありませんので抽象的な記述方法を多用しますが、その記述方法は後の回で説明します。

ここで説明するAND_OR_NOTの回路記述はデータフローのモデル(同時処理文)のみを使用しています。「同時処理文」とは全ての文が同時に実行される文を言います。1つの文がマルチタスクにおける1つのタスクみたいに考えても良いと思います。正確に言いますと入力信号が変化したときにそのプロセス(マルチタスクにおけるタスクあるいはスレッドに相当)が起動して出力信号の値が計算されます。左辺の信号に代入されるのは少しシミュレーション時間が経過してからです。 そして次のイベントが来るまで待ち、イベントが発生したなら同じことを繰り返します。 C言語では必ず上の文から実行されるのと対照的です。

※上から順番に実行させる記述も存在しますが、第2回で説明します。

AND アンド・ゲート

ANDゲート
【図4 ANDゲートの記述】

「論理積回路」とも呼ばれます。全ての入力端子が'1'の場合のみ出力端子が '1'になります。それ以外は出力は'0'です。

ゲートの記述には、and、or、notなどの演算子と同時処理文を用います。 代入には2種類有り、使い分けが必要なので注意してください。 <= は信号に対する代入を表します。 := は変数に対する代入を表します。

入力と出力がSTD_LOGICの場合とSTD_LOGIC_VECTOR(バス)の場合と 記述方法はまったく同じです。STD_LOGIC_VECTORの場合は同じビット位置同士の信号が演算されます。STD_LOGICとSTD_LOGIC_VECTORを混在させての演算はできません。

記述方法は以下に示しますが、<=の左辺に出力となる信号名、右辺に入力となる信号名を演算子 and で結合したもの、文の最後には ; をつけます。

【リスト4  2入力 ANDゲート VHDL-同時処理文】
X <= A and B;

C言語と比較するとわかりやすいかもしれませんのでC言語での記述を示しておきます。

【リスト5 2入力 ANDゲート C言語-参考】
X = (A & B);

C言語では上の文から下の文の順序で1回だけ実行されます。入力ポートの変化をすぐに出力ポートに 反映させたいのであれば、while(1)で無限ループを作りその中に代入式を入れる必要があります。 VHDLの同時代入文では、1つの文がマルチタスクにおける1つのタスクのように振舞うので文の記述順序を変えても動作は変わりません。明示的に無限ループを作らなくても1つの文が無限ループみたいに動作しているところが相違点です。

入力端子が2本以上の場合もありますが、その場合も全ての入力端子が'1'の場合のみ出力端子が '1'になります。入力端子が3本の場合は以下のような記述になります。同様にバスでの演算もできます。

【リスト6 3入力 ANDゲート】
X <= A and B and C;

OR オア・ゲート

ORゲート
【図5 ORゲートの記述】

「論理和回路」とも呼ばれます。1つ以上の入力端子が'1'の場合に出力端子が '1'になります。全ての入力が'0'であった時のみ'0'になります。左の回路図をソース・コードで記述すると以下の通りになります。

【リスト7 2入力 ORゲート VHDL 同時処理文】
Y <= A or B;
【リスト8 2入力 ORゲート C言語 参考】
Y = (A | B);

入力端子が2本以上の場合もありますが、その場合も1つ以上の入力端子が'1'の場合出力端子が '1'になることは同じです。入力端子が4本の場合は次のような記述になります。

【リスト9 4入力 ORゲート】
Y <= A or B or C or D;

NOT インバータ

NOT
【図6 インバータの記述】

「否定回路」とも呼ばれます。入力が'1'の場合 出力は'0'になり、 入力が'0'の場合 出力は'1'になります。左の回路図をソース・コードで記述すると以下の通りになります。

【リスト10 インバータ VHDL 同時処理文】
Z <= not A;
【リスト11 インバータ C言語 参考】
Z = (~A);
※これらのゲートはVHDL上では予約語のAND,OR,NOTで表現されますが、論理合成をして実際のプリミティブ(またはセル)に変換された場合プリミティブの名前はメーカによって、デバイスの品種によって異なります。

VHDLソース・コード

ここまでで説明したAND、OR、NOTを各1つづつ入れたブロックのソース・コードを示します。ソース・コードはタブサイズ4、文字コードはシフトJISです。

⇒AND_OR_NOTのソース・コード
⇒テストベンチ(AND_OR_NOT_BENCH)
※テストベンチについては第2回で解説します。

VHDLとC言語の記述比較

同じ機能をC言語で記述するとどうなるか、VHDLと比較してみましょう。 H8マイコン用にC言語で記述するすると以下のようになるはずです。

【リスト C言語によるAND_OR_NOT】
/* H8/3694F マイコン用、回路はH8データロガーを流用 */
#include    "iodefine.h"

void main(void);    /* プロトタイプ宣言 */
/* 使わないIOも初期化しておくこと */

#define A  (IO.PDR5.BIT.B0)   /* P50をAとして使用 */
#define B  (IO.PDR5.BIT.B1)   /* P51をBとして使用 */
#define X  (IO.PDR1.BIT.B5)   /* P15をXとして使用 */
#define Y  (IO.PDR1.BIT.B6)   /* P16をYとして使用 */
#define Z  (IO.PDR1.BIT.B7)   /* P17をZとして使用 */

void main()
    {
    IO.PCR1 = 0xff;       /* IOポート1の方向を設定 */
    IO.PCR5 = 0xf0;       /* IOポート5の方向を設定 */
    IO.PDR1.BYTE = 0;     /* IOポート1の初期値を設定 */
    IO.PDR5.BYTE = 0;     /* IOポート5の初期値を設定 */
    IO.PUCR5.BYTE = 0xf;  /* P50〜53はプルアップ抵抗をイネーブル */

    while(1)   /* 無限ループにする */
        {
        X = (A & B);
        Y = (A | B);
        Z = (~A);
        }
    }

C言語はもともとミニコンでの移植性を高めるために設計された高級言語です。 コンピュータ、マイコンというのはバス・アクセスの最小単位は大抵バイト(8ビット)です。 ビット・セット命令、ビット・クリア命令というのもありますが、バスの動作としては、「①SFRから1バイト分レジスタにロード、②そのデータのうち1ビットだけセット(またはクリア)、③その後1バイト分でSFRにストア」という面倒な動作をしています。 SFRの名前とかはそのチップ設計者の個性が反映されてしまい必ずしも覚えやすくないし、ビット位置とかもいちいちデーターシートとにらめっこをしなければならないので結構わずらわしいです。 マイコンでは入力の変化が出力に伝播するまで時間がかかるし、記述も面倒です。

アセンブラのビット・セット、ビット・クリアの命令は、C言語では、ビット・フィールドというのに相当します。 ビット・フィールドは本来ビット単位でのアクセスができないマイコンに対して記述上ビット単位でアクセスしているように見せかけるものですが、あまり書き易いとは言えません。

VDHLではビット幅に関係なく(ビット・フィールドも必要なく)代入すればその値を出力してくれます。 マイコンでは扱いにくい、半端なデータ幅(たとえば9ビットとか)の扱いがしやすいです。

C言語におけるピン配置は、その仕様に会うようにソース・コード上でSFRの設定をしなければなりません。 そしてSFRがマイコンの品種により異なり、互換性がないところが悩ましいです。 SFRの設定するソース・コード(大抵はスタートアップ)を間違えると入力がオープンになってしまい貫通電流が流れるとか、出力同士が衝突してしまいマイコンに過電流が流れるなどの危険があります。

VHDLではピン配置は開発ツールのGUIで設定するのが一般的です。特に指定しなければコンパイラが自動的に決めてくれます。使わない端子の処理(オープンあるいはGNDに接続)はレポートファイルに記述されています。

C言語において、IO制御は、OSやBIOSを経由することが前提だったのでビットの扱いは苦手です。 それに対してVHDLはハードウェアを記述する言語なのでビットの扱いは得意です。

まとめ

初めから難しい記述を使うと理解しにくくなるので、今回は最も簡単な回路をVHDLで記述することをして見ました。難しい書き方はいくらでもできますがそれらはまず使い始めてから少しずつ覚えていけばいいと思います。 「VHDL,Verilogの開発環境 ModelSim 」にシミュレータの使い方がありますので実際にシミュレーション をして予想どうりの波形がでるか実習してみると良いと思います。

⇒第2回 フリップフロップの記述とテストベンチ

用語説明

テキスト・ベース
テキスト・ファイルはPC、ワークステーションであつかうファイルの中でもっとも古くからあり、かつ互換性の高いデータです。回路図入力などグラフィックスを使用した開発手法に対してテキスト・エディタをメインで使用する手法をテキストベースと言っています。
ブロック
ASIC・PLDの設計においてある意味を持った回路部分を括った範囲をブロックといいます。 1個のLSIの内部を多くのブロックに分割して各ブロック毎に設計します。それに対して初めからメーカで準備されているAND,OR,NOTゲート,FF(フリップフロップ)などはプリミティブ(またはセル)と言います。ごく小さなPLDを設計する場合はPLDの1個分を1つのブロックに対応させる場合もありますが、回路規模が大きくなるにしたがい1つのPLDの中を複数のブロックに分割させて、ブロック単位で設計、評価するのが一般的です。
RTLレベル
本来はレジスタ(一般的にはフリップフロップ)のあるべき位置と数量を回路設計者が明示して、レジスタから次のレジスタまでの組み合わせ回路を開発ツールで自動生成するソース・コードの書き方です。それに対してPLDのプリミティブ(またはセルベースICのセル)を意識したソース・コードの書き方をゲート・レベルといいます。通常の開発ツールの場合、RTLならば論理合成が可能なので、論理合成が可能なソース・コードをRTLと言う人もいます。
ソフト・マクロ
回路図入力で設計する場合、主にベンダーから提供される設計済みのブロック。
テストベンチ
ASIC, PLDなどをシュミレーションで評価する場合に入力信号を生成したり、出力が期待どうりに変化しているか確認するための回路、またはソース・コード。論理合成の対象となる範囲を除いた回路部分。
IP(知的財産Intellectual Property)
ASICの業界ではVHDLなどで設計された再利用する事を前提とした回路をさす場合が多いです。内部回路がわからないようなファイルで供給される場合もあります。ハードだけでなくソフトとの組み合わせの場合もあります。TCP/IPのIPではありません。
本ページから直接リンクされているVHDLのソース・コードについては 無料でコピー・配布をして結構です。(特に許可も必要ありません。) それ以外の本webデータに対して許可のない 複製・譲渡はお断りします。 本webにリンクを張る場合 許可は必要ありません。

--- Copyright N.Kojima 2005/2016 ---

[ ホーム(総目次) ] → [ 言語 ] → [ VHDL ]