2019.6.19
前へ
次へ
ホームページトップへ戻る

[新連載]CPLD入門!
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使うことになるだろうと思ってはいたのですが。
何を今頃になって、というようなものですが。
ようやく本気で、CPLDと四つに取り組みます。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜



[第72回]


●VHDLサンプルプログラム1 82C55(5)

前回はAポート出力とBポート出力について書きました。
今回はCポート出力です。

●Cポート出力

前回と同様、前段と後段の2つに分けて考えます。
まずは前段です。
Cポートは上位4ビットと下位4ビットが分かれています。
両方が出力のときはAポート、Bポートと同じ動作になりますが、片方が出力でもう片方が入力の場合もありますから、それを考慮したプログラムになります。
さらにCポートにはビット出力モードがあるので、そのための記述も必要です。

-- portC out
process(IOW)
begin
        if IOW='0' then
                if ADRSIN="11110010" then
                        if chinout='0' then
                                pchout<=DINOUT(7 downto 4);
                        end if;
                        if clinout='0' then
                                pclout<=DINOUT(3 downto 0);
                        end if;
        -- bit out
                elsif ADRSIN="11110011" and DINOUT(7)='0' then
                        if clinout='0' then
                                if DINOUT(3 downto 1)="000" then
                                        pclout(0)<=DINOUT(0);
                                elsif DINOUT(3 downto 1)="001" then
                                        pclout(1)<=DINOUT(0);
                                elsif DINOUT(3 downto 1)="010" then
                                        pclout(2)<=DINOUT(0);
                                elsif DINOUT(3 downto 1)="011" then
                                        pclout(3)<=DINOUT(0);
                                end if;
                        end if;
                        if chinout='0' then
                                if DINOUT(3 downto 1)="100" then
                                        pchout(0)<=DINOUT(0);
                                elsif DINOUT(3 downto 1)="101" then
                                        pchout(1)<=DINOUT(0);
                                elsif DINOUT(3 downto 1)="110" then
                                        pchout(2)<=DINOUT(0);
                                elsif DINOUT(3 downto 1)="111" then
                                        pchout(3)<=DINOUT(0);
                                end if;
                        end if;
                end if;
        end if;
end process;

if ADRSIN=”11110010” thenのところの記述はAポート、Bポートと同じ考え方です。
chinout、clinoutにはそれぞれそれ以前に読み込まれたコントロールワードのCポート上位4ビット、下位4ビットの向きを示す値が保持されています。
値が’0’なら出力、’1’なら入力です。
CPUからのOUT命令が出されたとき(IOW=’0’のとき)、I/OアドレスがF2ならばCポートへの出力になります。
ポートの向きが出力なら、そのときのデータバスの上位4ビットの値がpchout、下位4ビットの値がpcloutに入ります。
pchout、pcloutに入れられた値は、次に同じことが発生するまでそれぞれラッチされています。

IOW=’0’でADRSINがF3のときはコントロールワード出力ですが、その値のビット7が’0’のときは、Cポートに対するビット出力コマンドになります([第68回]参照)。
elsif ADRSIN=”11110011” and DINOUT(7)=’0’ then 以下がそのための記述です。
Cポートの下位4ビットが出力モードに設定されているならば(clinout=’0’ならば)、DINOUTのビット3〜ビット1が”000”〜”011”のときはCポートの下位4ビットの出力データをラッチしているpcloutのビット0〜ビット3に、DINOUTのビット0の値が出力されます。
またCポートの上位4ビットが出力モードに設定されているならば(chinout=’0’ならば)、DINOUTのビット3〜ビット1が”100”〜”111”のときはCポートの上位4ビットの出力データをラッチしているpchoutのビット4〜ビット7に、DINOUTのビット0の値が出力されます。

●elsifかifか?

実は上のプログラムのif ADRSIN=”11110010” thenのところは、当初はAポート、Bポートと一緒にして下のように書いていました。
この時点ではビット出力については後回しにしていたため、そのように記述できると考えたからです。

-- port out data from pc
process(IOW)
begin
        if IOW='0' then
                if ADRSIN="11110000" and ainout='0' then
                        paout<=DINOUT;
                elsif ADRSIN="11110001" and binout='0' then
                        pbout<=DINOUT;
                elsif ADRSIN="11110010" and chinout='0' then
                        pchout<=DINOUT(7 downto 4);
                elsif ADRSIN="11110010" and clinout='0' then
                        pclout<=DINOUT(3 downto 0);
                end if; 
        end if;
end process;

ところがこのプログラムをEPM7128SLC84に書き込んで、ND80Z3.5に接続してテストしてみると、Aポート、Bポート、Cポートの上位4ビットからは正しくデータが出力されます。
しかしCポートの下位4ビットだけは反応してくれません。
なぜだ?
最初は全く原因がわからず、あれこれあちこちをいじっていましたが、そのうち上のプログラムのCポートの上位4ビットの記述と下位4ビットの記述を入れ替えたところ、今度は下位4ビットからは正しく出力が行なわれるようになったのですが、上位4ビットが反応なしになってしまいました。
記述順序が関係する???(その通りなのですが、この時点ではそのことがわかっていませんでした)
しかしAポートとBポートの記述順序を入れ替えても、特に問題は発生しません。
Cポートの上位と下位だけが、あとで記述した部分のみ実行されないように見えます。
なぜだああ?

上のリストをうなりながら眺めているうちに、やっと気が付きました。
わかったぞお!

●if文にelsifがついているときは要注意

if文の次にelsifが続くときは、上から順にif、elsifの条件が試されていきます。
上のプログラムでは最初にまずADRSIN=”11110000” and ainout=’0’がチェックされます。
その結果が真のときは、elsif以下の文は実行されません。
elsifはそれより前のif(またはelsif)を受けて、「そうではないならば」と続くif文です。
ですからそれよりも前のifが真になってしまったら、それより後ろのelsifは実行されない道理です。

もしもADRSIN=”11110000” and ainout=’0’であったならば、最初のifの結果が真になりますから、paout<=DINOUTのみが実行されます。
もしもADRSIN=”11110001” and binout=’0’であったならば、最初のifの結果は偽ですから、次のelsifが試され、その結果pbout<=DINOUTのみが実行されます。
もしもADRSIN=”11110010” and chinout=’0’であったならば、最初のifと次のelsifの結果は偽ですから、その次のelsifが試され、その結果pchout<=DINOUTのみが実行されます。

さてここからが問題です。
もしもADRSIN=”11110010” and clinout=’0’であったならば、同じように最後のpclout<=DINOUTが実行される、と考えたのですが、考えが足りませんでした。
ADRSINの値が同時にF0、F1、F2の値をとることはありません。
ですから上のプログラムは最後のelsif文以外はそれぞれ正しく機能します。

しかし最後のelsif文は?
もしもその上のADRSIN=”11110010” and chinout=’0’が成立してしまうと、その次のelsif文は実行されません。
このことはCポートの上位4ビットと下位4ビットがともに出力に設定されているときに起きてしまいます。
そういうことだったのでした。
このように同時に成立する複数の条件がある場合には、elsifでつなぐのではなくて、それぞれをif〜then、end if;を使って記述しなければなりません。
ということを体験を通じて学んでしまいました。
これは貴重な体験ではありますが、なかなかに苦い薬であります。

さて。
それでは本筋に戻ります。
下はCポート出力の後段の記述です。

--portCL out
process(clinout,pclout)
begin
        if clinout='0' then
                PCL<=pclout;
        else
                PCL<="ZZZZ";
        end if;
end process;
--portCH out
process(chinout,pchout)
begin
        if chinout='0' then
                PCH<=pchout;
        else
                PCH<="ZZZZ";            
        end if;
end process;

ここは前回のAポート、Bポートの後段のプログラムと同じです。
出力モードのとき(clinout=’0’のとき)はPCLにpcloutが出力されます。
pcloutは今回の最初のところでお見せしたプログラムでラッチされた出力データです。
elseはその他のとき、つまりclinout=’1’、入力モードのときを指しています。
そのときはPCL出力はハイインピーダンスになります。
センシビリティリスト(process文の( )の中)はclinoutとpcloutしか記述していませんから、begin以下の文はclinoutの値が変化したときか、pcloutの値が変化したとき以外は実行されません。
以上はPCLについての説明ですが、PCHについても全く同様です。

今回もしっかり疲れてしまいました。
今回は、ここまでにいたします。

CPLD入門![第72回]
2019.6.19upload

前へ
次へ
ホームページトップへ戻る