2004/07/25 【ソフトウエア編TOPに戻る】
CPLDの魅力や実際の開発環境の整え方について401.ALTERA CPLD開発環境のページなどでご紹介してきましたが、環境は整いましたか? さてここでは、いよいよCPLDを実際に動かすためのプログラミングについてご紹介していくことにしましょう。CPLDのプログラミングを行うための言語をハードウエア記述言語と呼び、いくつかの種類があるようですが、ここではVHDL(Very High Speed Integrated Circuit Hardware Description Language)という言語を使ってみたいと思います。
VHDLの文法を紹介しているホームページはいくつかありますし、書店に行けば解説書も沢山並んでいます。あえてTekuRoboでご紹介する必要もないかもしれませんが、幾つかのロジックを組んでみた浅い経験を元に、初心者にとってつまずきやすい点などに注意しながら少しだけご紹介してみようと思います。先ずはここを足掛かりとして、専門書を紐解いていって頂ければと思います。
410−1.ハードウエアを記述するということ...
実は、VHDLについての解説記事を書くに当たり、少しだけ悩んだことがあります。それは、TekuRoboの「電子回路編」に入れるべきか、「ソフトウエア編」に入れるべきか、という問題です。「ベースとなるハードウエアデバイスがあり、それに書き込む情報によって目的に応じた動作をさせる。」ということには間違いなく、一般的にはここで言う情報がソフトウエアという位置づけになるため、「ソフトウエア編」に入れるのはある意味で妥当だとは思います。
一方、VHDLで幾つかのロジックを組んでいて感じることは、まさしく「ハードウエアを言語(ことば)で表現しているのだ」ということです。VHDLのソースプログラムをちょっと見てみると、なんとなくC言語あたりに似たような印象を受けます。実際、if文やcase文やfor文などがあったりして、もしかしたらC言語あたりをかじっていれば以外と簡単にできる?などと思ったりするかもしれません。
しかし、そういう考えは捨てたほうが良さそうです。プログラムを頭から順にひとつずつ実行していくことを基本としたCPU制御のためのプログラミングと、クロックに同期もしくは非同期で複数の箇所が同時に動くハードウエアを記述するプログラミングとでは、根本的に考え方が違うのです。CPUプログラミングに慣れた方々ほど、その根本的な思想のギャップに苦しむかも知れません。CPUプログラミングと同じつもりでいると動作しませんし、ハードウエア、特にフリップフロップを組み合わせた同期式の回路設計の基礎知識がないと、多分VHDLを自由には使いこなせないという気もします...
そんな調子なので、VHDLを勉強するにつれ、「これはソフトウエア設計ではなく、ハードウエア設計だ!」と思うようになってきました。回路図を描く代わりに、VHDL上で幾つかの回路ブロックをことばで構成し、signal定義した信号でお互いを繋いで全体を動作させるというイメージです。
いきなりこんな事を言うと、VHDLは難しく取っ付きにくいと思われてしまいそうですが、決してそんなことはありません。例えばAND、OR、NANDやNORなどの基本的ロジックだけを組み合わせたエンコーダ、デコーダ回路などは本当に簡単に組めますし、74シリーズなどの汎用TTLロジックICに相当するような機能を持たせることなども簡単に出来ます。ちょっと難しくなってくるのは、複数のフリップフロップやカウンタ機能を持たせながら、それらを組み合わせて動的な処理を行わせようとするような場合になってからでしょう。ただし、それもある程度クセを掴んでしまえば、動いてくれるようになります。(多分...)
ここで、VHDLとCPUプログラミングが根本的に違うというほんの一端をご紹介しましょう。下のVHDL記述はシフトレジスタを組む場合のプログラム例の一部です。
process (CLK)
begin
if (CLK'event and CLK = '1') then
REG1 <= SIN;
REG2 <= REG1;
REG3 <= REG2;
SOUT <= REG3;
end if;
end process;
process(CLK) からend process;の間の命令は、CLKという外部クロック入力に変化があった場合に実行されます。そして、if (CLK'event and CLK = '1') thenからend if;の間の命令は、外部クロックの変化が立ち上がりタイミングだったら実行するという意味です。<=は矢印のようですが代入の演算子で、矢印の方向に値が代入されます。
さて、
REG1 <= SIN;
REG2 <= REG1;
REG3 <= REG2;
SOUT <= REG3;
の部分ですが、CPUプログラミング的に考えると処理結果はどうなるでしょう。SINがREG1に代入されて、次にREG1がREG2に代入されて... と処理が続いて行きます。結果として、SIN = REG1 = REG2 = REG3 = SOUT 、つまり全ての変数の値が同じSINの値になりませんか?
ところが、VHDL的に考えるとそうはなりません。SINやREG1〜3やSOUTをそれぞれ1ビットのレジスタと考え、1か0の値のみを取るとします。そしてこれらは外部クロックの立ち上がりタイミングごとに、一回だけ代入文が実行されます。つまり、SIN → REG1、REG1→REG2、REG2→REG3、REG3→SOUTが1クロックごとに一回ずつ実行されるため、外部クロックに合わせて1ビットずつデータがシフトしていく、という動作になります。つまりシフトレジスタになるのです。分かりますか??
はじめに「そうなる」と言ってしまっては、きっと「あ、そう」で終わられてしまいそうな気がしますが、力弥の場合は一番初めにVHDLに触れたときに、これで目から鱗が落ちました。あ、そういうものなのか!という感じです。(^^; 多分こういった「目から鱗が落ちる」感覚は、一度自分で悩んでみないと感じないものかもしれませんね。
VHDLには、これ以外にもCPUプログラミングとは違ったクセが沢山あると思います。先ずは実例を見て真似ながら、自分なりにアレンジしてみるのが一番かと思います。
410−2.もっとも簡単なVHDLプログラム
では早速、実際のVHDLプログラムを見てみましょう。下の事例は402.QuartusⅡWebEditionの操作概要で試しにコンパイルしてみたものです。
プログラムソースはここをクリックするとダウンロードできます。and_test.vhd
| library ieee; use ieee.std_logic_1164.all; ----------------------------------- entity AND_TEST is port( a,b,c : in std_logic; end AND_TEST; y <= a and b and c; end RTL; |
このVHDLでは、以下のような回路を記述しています。
|
|
この回路の特徴を、入出力信号と内部動作の観点から見てみましょう。 ■入出力信号 入力信号は a , b , c の3つ。出力信号は y のひとつ。
■内部動作 入力信号 a , b , c の論理積(AND)の結果が出力信号 y になる。つまり、全ての入力が1の時だけ、出力信号も1になり、それ以外の時は0が出力される。
ついでに、この回路には「AND_TEST」という名前が付いている。 |
では、以上のような回路の特徴が、VHDL上でどのように記述されているかを見てみましょう。
■410−2−1.Entity(エンティティー)文
Entity(エンティティー)を辞書で引いてみると「実体、本体、実在」と出てきます。つまり、これから記述したい回路の外枠(そとわく)、外部とのインターフェイスについて定義してあげる部分がEntity文ということになります。事例では以下の部分がそれです。
entity AND_TEST is
port( a,b,c : in std_logic;
y : out std_logic);
end AND_TEST;
ここでは、entityにAND_TESTという名前を付けて、それはa,b,cという入力端子とyという出力端子がある、という記述をしています。 入出力端子はport文で定義していて、入力は in std_logic、出力はout std_logicという種別をつけています。この種別はモードとデータタイプから成り立っていますが、今のところは見たまんまで覚えておきましょう。
この時点では、まだ「この回路がどういう動作をするのか」については定義されていません。ここでは、あくまで外枠だけを定義していますね。
■410−2−2.Architecture(アーキテクチャー)文
Architecture(アーキテクチャー)も辞書で引いてみましょう。「建築、構成、基本構造の設計法」などと出てきます。あまりピンとこないかもしれませんが、内部構造、つまり内部動作についての定義を行うのがArchitecture文ということになります。事例では以下の部分になります。
architecture RTL of
AND_TEST is
begin
y <= a and b and c;
end RTL;
ここで、RTLというものが出てきましたが、これはアーキテクチャ名といい、内部動作自体に名前を付けたものです。ここでは、AND_TESTという外枠の、RTLという内部動作を定義しているという意味になりますね。そして、定義したい具体的な動作が、Begin から end RTL; までの間に記述されています。ここでは、 y <= a and b and c; の部分です。
これは単純に、a と b と c の論理積(AND)を y に代入しなさい。
という命令文になりますね。
■410−2−3.ライブラリ宣言とパッケージ呼び出し
さて、最後になってしまいましたが、VHDLプログラムの一番頭にある2行。
ibrary ieee;
use ieee.std_logic_1164.all;
これは決まり文句で付くものだと思っておきましょう。C言語でいうところのヘッダファイルのインクルードに相当します。先ほど、Entity文で入出力端子の宣言を行いましたが、その時に使ったstd_logicというデータタイプを有効にするものです。今後VHDLで様々な機能を使っていこうとした場合、これ以外にも追加で宣言するパッケージなど増えていくことになります。
さて、もう一度まとめておきましょう。
VHDLでは、実現したい回路の外枠、インターフェイス部分をEntity文で宣言し、その内部動作をArchitecture文で記述します。そして、ライブラリ宣言を頭につけてひとまとめにしたのがVHDLプログラムになります。 |
今回は、VHDLプログラミングの導入部分のご紹介でした。ポイントは、CPUプログラミングとの考え方の違いに慣れるということだと思いますが、今後いくつかのプログラム事例をご紹介しながら、そのあたりをもう少しだけ深く考えて行きたいと思います。
TekuRoboでご紹介できる内容はほんの触りの部分までですので、あくまでプログラム事例のご紹介ということまでにさせて下さい。VHDLの構文や文法その他詳細な解説については、是非専門書をご覧下さい。