AHDL入門
ver1.003b 2009.05.23

更新履歴
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" 大きいか等しい

【ブール式の優先順位】

優先順位 同一順位の演算子・比較演算子
-(負符号) !(NOT)
+(加算)  −(引き算)
==  !=  <  <=  >  >=
& !&  AND NAND 
$ !$  XOR XNOR
# !# 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); 
という回路記述となります。

DFFDFFです。DFFEDFFにenable端子がついたもので,enableが真のときDFFとして機能しますが、enableが偽のときホールドします。
JKFFJKFFです。JKFFEJKFFにenable端子がついたもので,enableが真のときJKFFとして機能しますが、enableが偽のときホールドします。
SRFFSRFFです。SRFFESRFFにenable端子がついたもので,enableが真のときSRFFとして機能しますが、enableが偽のときホールドします。
TFFTFFです。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 シミュレーション結果




つづく

メインページに戻る