更新履歴
2007.12.1 新規作成
2007.12.9 Ver1.001 追加
2007.12.16 Ver1.002 追加
2007.12.22 Ver1.003 追加
参考文献
DESIGN WAVE BOOKS 3 ハードウエア記述言語(Altera-HDL)を使いながら学ぶパソコンによるプログラマブル・ロジックの設計 CQ出版社
【はじめに】
AHDLは、単純です。難しい事はないのが特長です。ここでは、私の知っている範囲で(勘違いもあるし完全ではないということです)、実際の回路を設計しながら、まとめてゆきたいと思います。
参考文献にはAHDLの文法がBNF文法でかかれています。また、レキシカル構文要素もかかれています。ですから、これを手直ししてLEX,とYACCを通せば、AHDLコンパイラができることになります。
冗談はさておいて、この本が手に入れば、この「AHDL入門」は、多分不要です。
第一章 4bit-12進カウンタをつくる
第一節 真理値表から作る
カウンタを作る方法は、いくつかあります。たとえば、真理値表を用いるものです。
今の値 | 次の値 |
---|---|
0000 | 0001 |
0001 | 0010 |
0010 | 0011 |
0011 | 0100 |
0100 | 0101 |
0101 | 0110 |
0110 | 0111 |
0111 | 1000 |
1000 | 1001 |
1001 | 1010 |
1010 | 1011 |
1011 | 0000 |
1100 | 0000 |
1101 | 0000 |
1110 | 0000 |
1111 | 0000 |
図ー1 4bit-12進カウンタの真理値表
12進カウンタなのに、1100-1111は不要ではないかと仰るでしょうが、念のためこういうこともありえないこともないので、こうなったら0000にするようにします。
D-FFをつかって作りますので、この表は、
カウンタのQの値 | カウンタのDの値 |
---|---|
0000 | 0001 |
0001 | 0010 |
0010 | 0011 |
0011 | 0100 |
0100 | 0101 |
0101 | 0110 |
0110 | 0111 |
0111 | 1000 |
1000 | 1001 |
1001 | 1010 |
1010 | 1011 |
1011 | 0000 |
1100 | 0000 |
1101 | 0000 |
1110 | 0000 |
1111 | 0000 |
図ー2 4bit-12進カウンタの真理値表
となります。
図ー3 カウンタの回路ブロック図
上にブロック図を示します。
では、設計します。
【設計手順】
なお、ここでは見やすくするために全角文字を使っていますが、全て半角文字で書きます。予約語は太字で書いてあります。
まずはじめに、回路名を書きます。
SUBDESIGN 4bit_12counter
SUBDESIGNは、回路記述の始まりです。次に名前がきます。 4bit_12counter ですね。
その次に入力出力を書きます。
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
と書きます。(と)で挟まれているところに書きます。
入力信号名前 : INPUT;
あるいは
出力信号名前 : OUTPUT;
です。
文末には;を書きます。
CLOCKはクロック、CLEARNは非同期クリア(ローアクティブ)、PRESETNは非同期セット(ローアクティブ)、出力はQ3,Q2,Q1,Q0です。
Q3,Q2,Q1,Q0をQ[3..0]と書くと3から0の連番ですよということです。
その次にD-FFを用意します。
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
Q[3..0] : DFF;
VARIABLEは、内部変数やプリミティブ(あらかじめ用意されている部品)、自分で作った機能ブロックの名前との一致を宣言を以下に書きます。
ここでは、D-FFのプリミティブDFFを宣言しています。
図-4 DFFプリミティブの端子
さて、以上で手続きは終わりました。
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
Q[3..0] : DFF;
BEGIN
回路記述分
END;
これで、大まかな記述をしめします。
さて、回路記述部分は、ブロック図に従い、
Q[].clk=CLOCK; Q[3..0]と書いてもいいのですが、Q[]と書くと全部ということになります。
Q[].clrn=CLEARN;
Q[].prn=PRESETN;
Q3.clk これは、Q3のclkという意味になります。Q3.qはQ3の出力、Q3.dはQ3のD入力をさします。 .は「の」と覚えればいいでしょう。
Q3.clkは日本語では「Q3のclk」というわけです。
ここまで問題ないと思います。
真理値表は、ありがたいことに真理値表のまま書くことが出来ます。
そのためには、TABLEと書きます。
TABLE 真理値表の最初に書きます。
Q3.q,Q2.q,Q1.q,Q0.q => Q3.d,Q2.d,Q1.d,Q0.d; 表の対応関係を書きます。
0 , 0 , 0, 0 => 0 , 0, 0, 1;
0 , 0 , 0, 1 => 0 , 0, 1, 0;
0 , 0 , 1, 0 => 0 , 0, 1, 1;
0 , 0 , 1, 1 => 0 , 1, 0, 0;
0 , 1 , 0, 0 => 0 , 1, 0, 1;
0 , 1 , 0, 1 => 0 , 1, 1, 0;
0 , 1 , 1, 0 => 0 , 1, 1, 1;
0 , 1 , 1, 1 => 1 , 0, 0, 0;
1 , 0 , 0, 0 => 1 , 0, 0, 1;
1 , 0 , 0, 1 => 1 , 0, 1, 0;
1 , 0 , 1, 0 => 1 , 0, 1, 1;
1 , 0 , 1, 1 => 0 , 0, 0, 0;
1 , 1 , 0, 0 => 0 , 0, 0, 0;
1 , 1 , 0, 1 => 0 , 0, 0, 0;
1 , 1 , 1, 0 => 0 , 0, 0, 0;
1 , 1 , 1, 1 => 0 , 0, 0, 0;
END TABLE; 真理値表の終わりに書きます。
さて、
1 , 1 , 0, 0 => 0 , 0, 0, 0;
1 , 1 , 0, 1 => 0 , 0, 0, 0;
1 , 1 , 1, 0 => 0 , 0, 0, 0;
1 , 1 , 1, 1 => 0 , 0, 0, 0;
この部分は,Q3.qとQ2.qがともに1で、Q1,Q0は全ての組合せがあるので,
1 , 1 , X, X => 0 , 0, 0, 0; Xは1でも0でもいいよという意味です。別の言い方をすれば関係ないよということです。
と簡略化できます。
以上によって,
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
Q[3..0] : DFF;
BEGIN
Q[].clk=CLOCK;
Q[].clrn=CLEARN;
Q[].prn=PRESETN;
TABLE
Q3.q,Q2.q,Q1.q,Q0.q => Q3.d,Q2.d,Q1.d,Q0.d;
0 , 0 , 0, 0 => 0 , 0, 0, 1;
0 , 0 , 0, 1 => 0 , 0, 1, 0;
0 , 0 , 1, 0 => 0 , 0, 1, 1;
0 , 0 , 1, 1 => 0 , 1, 0, 0;
0 , 1 , 0, 0 => 0 , 1, 0, 1;
0 , 1 , 0, 1 => 0 , 1, 1, 0;
0 , 1 , 1, 0 => 0 , 1, 1, 1;
0 , 1 , 1, 1 => 1 , 0, 0, 0;
1 , 0 , 0, 0 => 1 , 0, 0, 1;
1 , 0 , 0, 1 => 1 , 0, 1, 0;
1 , 0 , 1, 0 => 1 , 0, 1, 1;
1 , 0 , 1, 1 => 0 , 0, 0, 0;
1 , 1 , X, X => 0 , 0, 0, 0;
END TABLE;
END;
と完成しました。
図ー5 シミュレーション結果
しかし、ビット列ではなく
TABLE
Q[].q => Q[],d;
H"0" => H"1"; H”123456789”と書くと16進数で表記していることを表します。B"0011"は2進数、O”1234567”は8進数、デフォルトは
H"1" => H"2"; 10進数です。
H"2" => H"3";
H"3" => H"4";
H"4" => H"5";
H"5" => H"6";
H"6" => H"7";
H"7" => H"8";
H"8" => H"9";
H"9" => H"A";
H"A" => H"B";
H"B" => H"0";
H"C" => H"0";
H"D" => H"0";
H"E" => H"0";
H"F" => H"0";
END TABLE;
と書いてもいいわけです。
【アイデアメモ】
さて、ちょっと考えてください。表で,対応させているわけだから、1の次が2である必要もないわけです。11,10,9,8,7,6,....という表を作れば,ダウンカウンタになりますし,1,11,2,10,3,9,...という順でもできるわけです。真理値表を使うとこのようにメリットがあります。
また、カウンタは0からはじめる必要もありません。2から13までの12値でも良い訳です。
第二節 CASEを使う
真理値表を書くのもいいでしょう。でもCASEをつかっても同じことです。
CASE Q[].q IS
WHEN H"0" => 「Q[].q=H"0"のときは,」の意味
Q[].d=H”1”; 「Q[].d=H"1"にせよ」の意味
WHEN H"1" =>
Q[].d=H”2”;
WHEN H"2" =>
Q[].d=H”3”;
WHEN H"3" =>
Q[].d=H”4”;
WHEN H"4" =>
Q[].d=H”5”;
WHEN H"5" =>
Q[].d=H”6”;
WHEN H"6" =>
Q[].d=H”7”;
WHEN H"7" =>
Q[].d=H”8”;
WHEN H"8" =>
Q[].d=H”9”;
WHEN H"9" =>
Q[].d=H”A”;
WHEN H"A" =>
Q[].d=H”B”;
WHEN H"B" =>
Q[].d=H”0”;
WHEN OTHERS=> 「それら以外では」ということ
Q[].d=H”0”;
END CASE;
となるわけです。
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
Q[3..0] : DFF;
BEGIN
Q[].clk=CLOCK;
Q[].clrn=CLEARN;
Q[].prn=PRESETN;
CASE Q[].q IS
WHEN H"0" =>
Q[].d=H”1”;
WHEN H"1" =>
Q[].d=H”2”;
WHEN H"2" =>
Q[].d=H”3”;
WHEN H"3" =>
Q[].d=H”4”;
WHEN H"4" =>
Q[].d=H”5”;
WHEN H"5" =>
Q[].d=H”6”;
WHEN H"6" =>
Q[].d=H”7”;
WHEN H"7" =>
Q[].d=H”8”;
WHEN H"8" =>
Q[].d=H”9”;
WHEN H"9" =>
Q[].d=H”A”;
WHEN H"A" =>
Q[].d=H”B”;
WHEN H"B" =>
Q[].d=H”0”;
WHEN OTHERS =>
Q[].d=H”0”;
END CASE;
END;
と完成します。
図5−A 合成された回路
このように回路が合成されました。
【アイデアメモ】
このままでは、0からじゃなくて3からにしようとなると全部書き換えです。
そこで,
CASE Q[].q IS
WHEN zero =>
Q[].d=one;
WHEN one =>
Q[].d=two;
WHEN two =>
Q[].d=three;
・・・・以下省略・・・・
END CASE;
とかいて,おくと CONSTANTをつかって、定数宣言すると
CONSTANT zero =H"0";
CONSTANT one =H"1";
CONSTANT two =H"2";
以下省略
とすれば,カウンタは0,1,2となりますが
CONSTANT zero =H"11";
CONSTANT one =H"10";
CONSTANT two =H"9";
以下省略
と書き換えることでCASE文以降を書き換えることなく、ダウンカウンタに出来ます。
CONSTANT zero =H"0";
CONSTANT one =H"1";
CONSTANT two =H"2";
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
Q[3..0] : DFF;
BEGIN
Q[].clk=CLOCK;
Q[].clrn=CLEARN;
Q[].prn=PRESETN;
CASE Q[].q IS
・・・・以下省略・・・・・
というように、定数宣言はSUBDESIGNの前に書きます。
第三節 式を使う
1の次は2、5の次は6、したがって,
Q[].d=Q[].q+1;
と出来ます。
でも、このままでは、12,13,14,15と行ってしまいます。
そこで、
IF Q[].q >=H"B" THEN もし、11以上なら
Q[].d=H"0"; 次は0にする
ELSE そうでないなら
Q[].d=Q[].q+1; 次は+1
END IF; IFのおわり
と制限をかけます。
よって、以下のように完成します。
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
Q[3..0] : DFF;
BEGIN
Q[].clk=CLOCK;
Q[].clrn=CLEARN;
Q[].prn=PRESETN;
IF Q[].q >=H"B" THEN
Q[].d=H"0";
ELSE
Q[].d=Q[].q+1;
END IF;
【アイデアメモ】
IFの構文にはELSIFというのがあります。
IF A THEN もしAなら つまりBとCは無視されます。 ということは (A=True)
何とかかんとか
ELSIF B THEN もしAでなくてBなら つまりCは無視されます。 ということは(A=False)&(B=True)
どうたらこうたら
ELSIF C THEN もしAでもBでもなくてCなら ということは(A=False) & (B=False) & (C=True)
うんたらかんたら
ELSE もしどれでもないなら ということは(A=False) & (B=False) & (C=False)
そんなんじゃないなら
END IF;
優先順位がついてしまいます。まあ、あいまいさがないということですね。
たとえば、以下のようなアップダウンカウンタを設計するとUPとDOWNが同時にきたらUPが優先されます。
SUBDESIGN 4bit_12up_down_counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
UP :INPUT; カウントアップ指示
DOWN :INPUT; カウントダウン指示
Q[3..0] :OUTPUT;
CARY :OUTPUT; 桁上がり出力
BROW :OUTPUT; 桁借り出力
)
VARIABLE
Q[3..0] : DFF;
BEGIN
Q[].clk=CLOCK;
Q[].clrn=CLEARN;
Q[].prn=PRESETN;
IF UP THEN UPならカウントアップ
IF Q[].q>=H"B" THEN 11の次は0に
Q[].d= H"0";
CARY=VCC;
ELSE そうでなければ+1
Q[].d=Q[].q+1;
CARY=GND;
END IF;
ELSIF DOWN THEN UPでなくてDOWNならカウントダウン
IF ((Q[].q == H"0") OR (Q[].q > H"B")) THEN 0の次は11へ または11を超えていると次は11へ
Q[].d=H"B";
BROW=VCC;
ELSE そうでなければー1
Q[].d=Q[].q-1;
BROW=GND;
END IF;
ELSE UPでもDOWNでもなければホールド
Q[].d=Q[].q;
END IF;
END;
第四節 ここまでの文法のまとめ
【コメント】
%から始まって%までをコメントします。行を超えられません。
【定数】
VCC 論理 1、真 をいみします。
GND 論理 0、偽 を意味します。
X 0でもあり1でもある。論理的に意味を持たない、つまり関係なしということです。
CONSTANT PORT1=H”BCF0” 定数を宣言します。ここではPORT1がH”BCF0”であることを決めています。
【グループ表記】
並びをあらわすには、
Q[8..2].d=(A,B,C,Q[5..2].q) これはQ8.d=A,Q7.d=B,・・・・Q2.d=Q2.q
あるいは、
A[3..0]=B[6..3]
とできます。対応関係が1:1である必要があります。
【数値の基数】
デフォルト :10進数 0から9で構成される文字列
B”1101・・・” :2進数 0,1で構成される文字列 Bで始まり””で数値を挟む。
O”1101・・・” :8進数 0から7で構成される文字列 Oで始まり””で数値を挟む。
H”1234ABC” :16進数 0から9とAからFで構成される文字列 Hで始まり””で数値を挟む。
【論理演算子】
! NOT 例 ! ( A & B ) または NOT(A & B)
& AND 例 A & B または A AND B
!& NAND 例 A !& B または A NAND B
# OR 例 A # B または A OR B
!# NOR 例 A !# B または A NOR B
$ EXOR 例 A $ B または A XOR B
!$ EXNOR 例 A !$ B または A XNOR B
【算術演算子】
+ 正 例 +5
- 負 例 -4
+ 加算 例 A[3..0]+B[5..2]
- 引き算 例 A[]-B[]
【比較演算子】
比較演算子 | 型 | 例 | 説明 |
---|---|---|---|
== | 論理 | ADDRESS[A15..A0] == H”C35E” | 等しい |
!= | 論理 | A != B | 等ししくない |
< | 算術 | Q[7..0] < B”01110000" | 小さい |
<= | 算術 | Q[7..0] <= B”01110000" | 小さいか等しい |
> | 算術 | Q[7..0] > B”01110000" | 大きい |
>= | 算術 | Q[7..0] >= B”01110000" | 大きいか等しい |
【ブール式の優先順位】
優先順位 | 同一順位の演算子・比較演算子 |
---|---|
1 | -(負符号) !(NOT) |
2 | +(加算) −(引き算) |
3 | == != < <= > >= |
4 | & !& AND NAND |
5 | $ !$ XOR XNOR |
6 | # !# OR NOR |
【IO端子宣言】
入力端子名 : INPUT;
出力端子名 : OUTPUT;
双方向端子名 : BIDIR ;
【IF文】
IF A THEN
Aが真のときの文の並び
ELSE
Aが偽の時の文の並び
END IF;
IF A THEN
Aが真のときの文の並び
ELSIF B THEN
(!A & B)が(偽) 真の時の文の並び
ELSE
AもBも偽の時の文の並び
END IF;
【CASE文】
CASE 式 IS
WHEN 値1 =>
式が値1の時の文の並び
WHEN 値2 =>
式が値2の時の文の並び
・
・
・
WHEN OTHERS=>
式が上記いずれの値でもないときの文の並び
END CASE;
第五節 プリミティブおよびファンクション
使用する定義ファンクションは、include文で先頭に宣言します。
既定義ファンクションは,
図ー6 既定義ファンクション
のMAXPLUS2のディレクトリーにある拡張子が.incでしめされるものです。非常に多数あります。
たとえば,dff.incには
FUNCTION dff (d, clk, clrn, prn)
RETURNS (q);
と書かれています。これは,図-4で説明したDFFプリミティブの宣言です。したがって,本来は
INCLUDE ”dff.inc”
SUBDESIGN 4bit_12counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
Q[3..0] : DFF;
BEGIN
Q[].clk=CLOCK;
Q[].clrn=CLEARN;
・
・
のように文頭で,INCLUDEしなければならないわけですが、これが省略できるものがあります。
図ー7 プリミティブ
このprimitivesのディレクトリーに含まれるものです。
図ー8 フリップフロッププリミティブ
これは、フリップフロップのプリミティブです。名前だけで拡張子は不要です。
端子など詳細は,maxplus2の同一名称の.incファイルを見ればわかります。
また、自分で作った回路をファンクションとして同様に再利用できます。
SUBDESIGN 4bit_12up_down_counter
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
UP :INPUT; カウントアップ指示
DOWN :INPUT; カウントダウン指示
Q[3..0] :OUTPUT;
CARY :OUTPUT; 桁上がり出力
BROW :OUTPUT; 桁借り出力
)
これは、すでに説明した回路のはじめの部分ですが、これを呼び出すとき,
FUNCTION 4bit_12up_down_counter (CLOCK,CLEARN,PRESETN,UP,DOWN) 入力端子名を()でくくってならべる
RETURNS(Q[3..0],CARY,BROW); 同じく出力端子名をRETRUNSにつづいて()でくくってならべる
SUBDESIGN mega
(
CLOCK :INPUT;
・
・
)
VARIABLE
C1,C2 :4bit_12up_down_counter; C1,C2は4bit_12up_down_counterであることの宣言
このようにすることで,自分の回路をファンクションとして使用できます。端子は.をつけて指定します。
C1.UP = A & B;
といった具合です。
良く使う代表的なプリミティブはDFF、DFFE,TRI、NODE,SOFTくらいな物でしょう。
NODEは、回路記述の中で使用される出力端子です。入力出力端子としてには外に出てきません。コンパイルの論理展開でも消滅しません。
たとえば、
VARIABLE
good : NODE;
bad : SOFT;
という風に使います。SOFTは、仮の端子で回路記述の中で使用されますが、コンパイルの論理展開で消滅してもよい端子です。
TRIは、スリーステートバッファで
図ー9 TRIプリミティブ
となっています。今下の回路の場合,
図ー10 TRIバッファの回路
VARIABLE
BUF1,BUF2 : TRI;
と宣言して
out=BUF1(in1,oe1);
out=BUF2(in2,oe2);
という回路記述となります。
DFFはDFFです。DFFEはDFFにenable端子がついたもので,enableが真のときDFFとして機能しますが、enableが偽のときホールドします。
JKFFはJKFFです。JKFFEはJKFFにenable端子がついたもので,enableが真のときJKFFとして機能しますが、enableが偽のときホールドします。
SRFFはSRFFです。SRFFEはSRFFにenable端子がついたもので,enableが真のときSRFFとして機能しますが、enableが偽のときホールドします。
TFFはTFFです。TFFEはTFFにenable端子がついたもので,enableが真のときTFFとして機能しますが、enableが偽のときホールドします。
以下に示す例はDFFEを使った例です。これは8bitラッチでloadがVCCの間、クロックの立ち上がりでDをラッチします。loadがGNDならホールドです。
SUBDESIGN 8bit_latch
(
clock : INPUT;
resetn : INPUT;
load : INPUT;
D[7..0] : INPUT;
Q[7..0] : OUTPUT;
)
VARIABLE
Q[7..0] : DFFE;
BEGIN
Q[].clk = clock;
Q[].clrn = resetn;
Q[].d = D[];
Q[].ena = load;
END;
これは、非同期リセットで格好が悪いなら,
SUBDESIGN 8bit_latch
(
clock : INPUT;
resetn : INPUT;
load : INPUT;
D[7..0] : INPUT;
Q[7..0] : OUTPUT;
)
VARIABLE
Q[7..0] : DFFE;
BEGIN
Q[].clk=clock;
IF !resetn THEN
Q[].ena = VCC;
Q[].d = H”00”;
ELSE
Q[].ena = load;
Q[].d = D[];
END IF;
END;
とすれば、どうでしょう?
第六節 ステートマシン
カウンタは順序機械ですからステートマシンでもあるわけです。
SUBDESIGN 4bit_12counter_state_machine
(
CLOCK :INPUT;
CLEARN :INPUT;
PRESETN :INPUT;
Q[3..0] :OUTPUT;
)
VARIABLE
counter:MACHINE counterがステートマシンであるという宣言です。
OF BITS (Q[3..0]) そのマシンはQ[3..0]のビットかからなり
WITH STATES( 以下のステートを持っています。
zero =H”0”,ステートの名前と値を決めています。
one =H”1”,
two =H”2”,
three =H”3”,
four =H”4”,
five =H”5”,
six =H”6”,
seven =H”7”,
eight =H”8”,
nine =H”9”,
ten =H”A”,
eleven =H”B”);
BEGIN
counter.clk=CLOCK;
IF !CLEARN THEN CLEARNのときcounterをzeroにします。
counter=zero;
ELSIF !PRESETN THEN PRESETNのときcounterをelevenにします。
counter=eleven;
ELSE そうでないとき,以下のステートを遷移します。
CASE counter IS
WHEN zero =>
counter = one;
WHEN one =>
counter = two;
WHEN two =>
counter = three;
WHEN three =>
counter = four;
WHEN four =>
counter = five;
WHEN five =>
counter = six;
WHEN six =>
counter = seven;
WHEN seven =>
counter = eight;
WHEN eight =>
counter = nine;
WHEN nine =>
counter = ten;
WHEN ten =>
counter = eleven;
WHEN eleven =>
counter = zero;
WHEN OTHERS =>
counter = zero;
END CASE;
END IF;
END;
さてここではCASE 文を使いましたがTABLE文でもかけます。
以上、カウンタを用いてほとんどのコマンドを説明してきました。
第二章 組合せ回路
第一節 デコーダ
デコーダは、第一章の説明から想像がつくようにTABLEまたはCASE、あるいは比較演算子でかけます。
比較演算子を使った場合を示します。
IO_PORT = (IO_ADRESS[7..0] == H"3E");
では、以下に示される真理値表の設計を復習をかねてTABLEを使ってやって見ましょう。
入力 | 出力 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
G1 | G2A | G2B | A | B | C | Y0 | Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 |
L | X | X | X | X | X | H | H | H | H | H | H | H | H |
H | H | X | X | X | X | H | H | H | H | H | H | H | H |
H | L | H | X | X | X | H | H | H | H | H | H | H | H |
H | L | L | L | L | L | L | H | H | H | H | H | H | H |
H | L | L | L | L | H | H | L | H | H | H | H | H | H |
H | L | L | L | H | L | H | H | L | H | H | H | H | H |
H | L | L | L | H | H | H | H | H | L | H | H | H | H |
H | L | L | H | L | L | H | H | H | H | L | H | H | H |
H | L | L | H | L | H | H | H | H | H | H | L | H | H |
H | L | L | H | H | L | H | H | H | H | H | H | L | H |
H | L | L | H | H | H | H | H | H | H | H | H | H | L |
図ー11 真理値表
SUBDESIGN decoder_table
(
G1 : INPUT;
G2A,G2B : INPUT;
A,B,C : INPUT;
Y[7..0]:OUTPUT;
)
BEGIN
TABLE
G1,G2A,G2B,A,B,C => Y[7..0]; こういう風にまとめると
0, X, X, X,X,X => B"11111111”; B"11111111”のようにかけます。
1, 1, X, X,X,X => B"11111111”;
1, 0, 1, X,X,X => B"11111111”;
1, 0, 0, 0,0,0 => B"11111110”;
1, 0, 0, 0,0,1 => B"11111101”;
1, 0, 0, 0,1,0 => B"11111011”;
1, 0, 0, 0,1,1 => B"11110111”;
1, 0, 0, 1,0,0 => B"11101111”;
1, 0, 0, 1,0,1 => B"11011111”;
1, 0, 0, 1,1,0 => B"10111111”;
1, 0, 0, 1,1,1 => B"01111111”;
END TABLE;
END;
となりますね。もっと楽にはならないでしょうか。
SUBDESIGN decoder_table1
(
G1 : INPUT;
G2A,G2B : INPUT;
A,B,C : INPUT;
Y[7..0]:OUTPUT;
)
BEGIN
TABLE
G1,G2A,G2B,(A,B,C) => Y[7..0]; A,B,Cを(A,B,C)にまとめると
0, X, X, B"XXX" => B"11111111”; B"XXX”のようにかけます。ただし、O"X"と書くことはできません。
1, 1, X, B"XXX" => B"11111111”;
1, 0, 1, B"XXX" => B"11111111”;
1, 0, 0, O"0" => B"11111110”; O"0"という風にも出来ます。
1, 0, 0, O"1" => B"11111101”;
1, 0, 0, O"2" => B"11111011”;
1, 0, 0, O"3" => B"11110111”;
1, 0, 0, O"4" => B"11101111”;
1, 0, 0, O"5" => B"11011111”;
1, 0, 0, O"6" => B"10111111”;
1, 0, 0, O"7" => B"01111111”;
END TABLE;
END;
では、CASEを使って書いてみましょう。すると、Y0からY7まで毎回全部書くことになるのではと思うでしょう。でもDEFAULTSを使うと楽が出来ます。
DEFAULTSは、指定しないときはDEFAULTSで指定した値になるというものです。
SUBDESIGN decoder_case
(
G1 : INPUT;
G2A,G2B : INPUT;
A,B,C : INPUT;
Y[7..0]:OUTPUT;
)
BEGIN
DEFAULTS
Y[7..0]=VCC; Y[7..0]は断わりがないときはVCCであるという宣言です。
END DEFAULTS;
IF (G1 & (!G2A) &(!G2B)) THEN Y0からY7が0になる条件です。
CASE (A,B,C) IS
WHEN O"0" =>
Y0=GND;
WHEN O"1" =>
Y1=GND;
WHEN O"2" =>
Y2=GND;
WHEN O"3" =>
Y3=GND;
WHEN O"4" =>
Y4=GND;
WHEN O"5" =>
Y5=GND;
WHEN O"6" =>
Y6=GND;
WHEN O"7" =>
Y7=GND;
END CASE;
END IF;
END;
以上で大概のコマンドを説明してきました。
第二節 スリーステートバッファ
双方向バスは
SUBDESIGN bus
(
dir : INPUT;
ena : INPUT;
I[7..0] : BIDIR;
Y[7..0]: BIDIR;
)
BEGIN
Y7 =TRI(I7,ena & dir); ena & dirが真ならIからYへ []は使えない。
Y6 =TRI(I6,ena & dir);
Y5 =TRI(I5,ena & dir);
Y4 =TRI(I4,ena & dir);
Y3 =TRI(I3,ena & dir);
Y2 =TRI(I2,ena & dir);
Y1 =TRI(I1,ena & dir);
Y0 =TRI(I0,ena & dir);
I7 = TRI(Y7,ena & !dir); ena & !dirが真ならYからIへ
I6 = TRI(Y6,ena & !dir);
I5 = TRI(Y5,ena & !dir);
I4 = TRI(Y4,ena & !dir);
I3 = TRI(Y3,ena & !dir);
I2 = TRI(Y2,ena & !dir);
I1 = TRI(Y1,ena & !dir);
I0 = TRI(Y0,ena & !dir);
END;
図ー12 シミュレーション結果
第三節 ランダムロジック
ランダムロジックは、たとえば,
OUT=!A & (B # C);
という風に書いてゆきます。
グループ表記のばあい、
a & b[3..0] → (a & b3 , a & b2 , a & b1 , a & b0) と展開されます。
(a,b) & (c,d) → (a & c , b & d) と展開されます。
(a , b , c) & 2 → ( a , b , c) & B"010" → (a & 0 , b & 1 , c & 0)→ (0 , b , 0) となります。
また、加算器は算術演算子を使い
OUT[3..0]=a[3..0]+b[3..0];
a[3..0],b[3..0]の加算は、桁上がりが出ますので
OUT[4..0]=(B"0",a[3..0])+(B"0",b[3..0]);とします。
となります。
算術比較器は算術比較演算子を使い、
GE_out=( A[] >= B[] );
とかけます。
第三章 プリミティブ(マクロファンクション)の利用
第一節 74シリーズの応用
74,4000シリーズは、ロジックSSI、MSIの標準です。随分いろいろとありましたが、現在このくらい知っておれば,十分でしょう。これからはずれると実際手に入りにくいですから....
74シリーズは74XXから始まって、74LSXXとなり、74HCXXとなりました。XXが機能を表しています。XXが同じなら同じ機能です。たとえば,74163は同期式の16進カウンタです。
端子名 | 論理 | 機能 |
---|---|---|
EP、ET | 正論理 | カウンタイネーブル(カウント許可) |
LD | 負論理 | カウンタロード IA-IDからロードする |
CLR | 負論理 | カウンタクリア |
CLK | ↑ | クロック入力 立ち上がりエッジで動作する |
IA,IB,IC,ID | 正論理 | ロードデータ入力 ID(MSB)・・IA(LSB) |
RC | 正論理 | 桁上がり出力 |
QA,QB,QC,QD | 正論理 | カウンタ出力 QD(MSB)・・ QA(LSB) |
表 74163 の端子の説明
74163カウンタは,完全同期式ですからクロックの立ち上がりで変化します。LD,CLRが変化してもクロックが立ち上がらない限り、HでもLでも動作しません。
図ー13 10進同期カウンタ
74163は16進カウンタですが、これは、10進カウンタを構成しています。動作は0,1,2,3,4,5,6,7,8,9ときて9のときNANDゲートが出力して次にはロードがかかるものです。ロードされる値は0なので,9の次のロードで0になり、結果として10進カウンタになります。9になるとRCOがHになり、上位の桁のカウントイネーブルとなります。
ここでは、ロードで0にしていますが,74163は同期式ですからCLRでも出来ます。ロードを使っていますから、非同期クリアの74161でも同じです。
さて、以下のように記述します。
1行目は使用するマクロファンクション74163をINCLUDEしています。このままでは何がなんだかわからないので,2,3行にコメントを入れておきました。
13行目でcounterが74163であることを宣言しています。
23行目がNANDゲートとldn(ロード端子)との結線で、24行目がANDゲートでRCOを作っています。後の結線は回路図のままです。
図ー14 シミュレーション結果
第二節 ファンクションの利用
自分の作った回路をファンクションとして同じように利用できます。
そこで、少し手直しして、
図ー15 カウンタユニット
とします。これを3つ並べて3桁のカウンタを作ります。
図ー16 全体の回路
動作を説明します。1の位のカウンタが9になると桁上がりが出ます。
RCOがHになって,10の位のカウンタのenaがHになり10の位のカウンタは次のクロックで一つだけカウントします。
つまり、09,19,29,39,49,59,69,79,89,99の時にだけカウント許可が出て次のクロックで一つ増えます。
すると、10,20,30,40,50,60,70,80,90,00となるわけです。
100の位のカウンタのenaは99,199,299,399,499,599,699,799,899,999の時にHになってカウント許可になり次のクロックで一つ増えます。
したがって次は100,200,300,400,500,600,700,800,900,000となるわけです。
1,10,100の位のカウンタは、10進カウンタなので,0から9までしかカウントしません。
ですから、見かけ上3桁になるようホールドとカウントを繰り返すわけです。
100の位のカウンタはほとんどホールドばかりですね。
では、まず、カウンタユニットの設計です。
となります。
図ー17 シミュレーション
enaがHでカウントLでホールドしてますね。
全体は、
です。C1は1の位、C10は10の位、C100は100の位です。
ここで、1行目で,先ほどの自作ファンクションを呼び出しています。
FUNCTIONにつづいて名前、つづいて(と)でくくって入力端子名、RETURNSとかいて(と)でくくって出力端子名を書きます。入力出力端子名は入力(INPUT),出力(OUTPUT)と宣言したおいたものだけです。双方向ならBIDIRです。
図ー18 シミュレーション結果
つづく