[新連載]CPLD入門!
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使うことになるだろうと思ってはいたのですが。
何を今頃になって、というようなものですが。
ようやく本気で、CPLDと四つに取り組みます。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
[第71回]
●VHDLサンプルプログラム1 82C55(4)
前回はポートの初期設定について書きました。
今回はポートからの出力です。
VHDLプログラムの記述順に説明するつもりだったのですが、Cポートの記述はちょっと複雑なので、先にAポートとBポートの説明をします。
●Aポート出力とBポート出力
VHDLプログラムは基本的には記述した内容(回路)は同時に実行されます。
そういうことなので、つい信号の論理的な流れを無視したプログラムを書いてしまいます。
こうやって説明をしようとしますと、ずいぶんいい加減な順番で記述しているな、と反省させられます。
やっぱり最終的には記述する順序も整理し直したほうがよさそうです。
それはそれとしまして。
AポートとBポートにデータが出力される回路の説明です。
前段と後段の2つに分けて考えます。
まずは前段です。
--out data PORTA,PORTB 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; end if; end if; end process; |
ainout、binoutにはそれぞれそれ以前に読み込まれたコントロールワードのAポート、Bポートの向きを示す値が保持されています(前回参照)。
値が’0’なら出力、’1’なら入力です。
CPUからのOUT命令が出されたとき(IOW=’0’のとき)、I/OアドレスがF0ならAポートへの出力で、F1ならBポートへの出力です。
ポートの向きが出力なら、そのときのデータバスの値がpaout、pboutに入ります。
IOW=’0’のときのみ、then以下の条件がチェックされます。
結果が真のときにpaout、pboutに入れられた値は、次に同じことが発生するまでそれぞれラッチされています。
ここではAポートとBポートの記述を1つのprocess文として記述しましたが、次のようにそれぞれ別のprocess文として記述しても結果は変わりません。
--out data PORTA process(IOW) begin if IOW='0' then if ADRSIN="11110000" and ainout='0' then paout<=DINOUT; end if; end if; end process; -out data PORTB process(IOW) begin if IOW='0' then if ADRSIN="11110001" and binout='0' then pbout<=DINOUT; end if; end if; end process; |
このほうがわかりやすいかもしれませんね。
そして下はAポート、Bポート出力の後段の記述です。
--portA out process(ainout,paout) begin if ainout='0' then PA<=paout; else PA<="ZZZZZZZZ"; end if; end process; --portB out process(binout,pbout) begin if binout='0' then PB<=pbout; else PB<="ZZZZZZZZ"; end if; end process; |
PA、PBはそれぞれAポート入出力端子、Bポート入出力端子です。
ポートの向きが出力に設定されているときだけ、内部でラッチされている出力データが入出力端子に出力されます。
ポートの向きが入力に設定されているとき(ainout=’1’、binout=’1’のとき)は、入出力端子はハイインピーダンスになります。
’Z’はハイインピーダンス出力を意味する値です。
8ビット出力ですから”ZZZZZZZZ”です。
前段のprocess文と後段のprocess文は同時に実行されますから記述する順序を変えても結果は変わりません。
ここのところがVHDLプログラムのわかりにくいところかもしれませんが、鶏が先か、卵が先かの関係にあると考えます。
ただしprocess文の中での記述については順に実行される関係になることもあります(次に説明するCポートでそれが出てきます)。
ここでポート出力の記述をわざわざ前段と後段の2つに分けたのには理由があります。
前段でいきなり
PA<=DINOUT;
と書くこともできそうです。
しかしそうすると困ることが出てきます。
82C55は向きを出力に設定したポートに対してIN命令を実行するとそのときにポートから出力されている値がデータバスに読み出されます。
つまりIOR=’0’のときには(そのときにポートのアドレスがI/Oアドレスとして出力されていれば)
DINOUT<=PA;
と書きたいところなのですが。
………。
ここまで書いてきて、あれ?と思いました。
DINOUT<=PA;
と書くとコンパイルエラーになる、と書こうとして。
あれっ?そうだっけ?
この場合には、エラーにはならないはず…
ちょいとした思い違いをしていたことに気が付きました。
もしもPAをout std_logic;
と定義していたら、
DINOUT<=PA;
はコンパイルエラーになります。
そこを
paout<=PA;
と書いても、エラーになります。
出力に定義した端子から値を読むことは認められません。
なのでそうしたければ、
ポート出力の記述で
paout<=DINOUT;
PA<=DINOUT;
としておいて、そのポートへのIN命令に対しては
DINOUT<=paout;
と記述します。
ところが。
当プログラムのようにPAを
inout std_logic;
と定義した場合には、
DINOUT<=PA;
と書いてもコンパイルエラーにはなりません。
そして期待した通り正しく実行されます。
わかっていてプログラムを書いていながら、そこには「出力端子から入力はできない」という思い込みが働いていたようです。
ええ。
入出力端子からなら当然のことながら、入力できて当たり前でした。
それではその入出力端子から値を読み込むと何が読み込まれるでしょうか?
それ以前の出力がもしラッチされた出力ならば、そのラッチされている値が読み込まれます。
それならそれも82C55の動作として問題はなさそうです。
何が問題になるかというと。
実は問題にはなりません。
問題になるのは、最初に考えた82C55の動作の通りにはならないという点だけでした。
その入出力端子を「入力」に使いたいときには、そのままではそれ以前に「出力」として使ったときの出力された値が邪魔をします。
ですから入力に備えるために、
ポートを入力モードで使うときには、
PA<=”ZZZZZZZZ”;
と書いておくことが必要になります。
それもそのように書いておけば、ちゃんと「入出力端子」から外部の値が読み込まれます。
そういうことなら、そういうことでもよさそうです。
すると、ふたたびそのポートを出力モードに設定したとき、PA<=”ZZZZZZZZ”が残ったままになります。
出力モードになったとき、出力がハイインピーダンスでもよければそれでもかまわないことになります。
あるいは出力モードに設定したときは、そこで
PA<=”00000000”;
と記述しておけば、これは82C55のふるまいと同じになります。
結局のところ、このプログラムのように、ポート出力を前段と後段に分けて書く必要があるのは、入力モードに設定している間も、内部で出力値を保持していたい、という82C55に対する私の積年の不満を解消するためだった、ということになりそうです。
そこまで深く考えた結果そのようなプログラムを書いたのか、あるいは単に「出力端子からは入力はできない」ということが「入出力端子に対してもそのはず」という誤った思い込みにつながってしまったからなのか、そこはもう記憶にありません。
うーん。
簡単にプログラムを書いてしまうのですけれど。
こうやって細かく分けて説明をしていこうとしますと、いい加減に考えていたところが浮かび上がってきます。
よいことなのですけれど。
疲れます。
今回は、ここまでです。
CPLD入門![第71回]
2019.6.18upload
前へ
次へ
ホームページトップへ戻る