レトロマイコン86ボードの構想(その4)V20とPICのI/F確認 [8086]
前回の記事でPICからメモリに書込んだプログラムがV20で実行できることを確認できたので今回はPICとV20のインタフェース部の動作について確認しました。
前回書いたようにアセンブラはNASMを使っていますがマニュアルにはできるように書いてある
でのセグメント値の参照やセグメントの絶対アドレス指定の
でエラーやワーニングが発生したり、ORGを2カ所に書くとエラーになったりで悩みましたが、8086のメモリモデルとしてコードセグメントとデータセグメントを同じ値にするtinyモデルにし、データは EQUステートメントでアドレス指定することでPICとV20のインタフェースを確認しました。
PICとのインタフェースの仕掛けとして、回路は初回の記事を参照して頂くとして処理概要としては
となります。
V20側のアセンブルリストは下記のとおりです。処理内容としてはこの手の確認では定番の"Hello!"の表示です。
インタフェース試験でのV20側アセンブラソース
PIC側でのリスト表示後実行した際のログを以下に示します。ログの末尾にあるように想定通り"Hello!"が表示されました(^^)/
V20とPICのI/F確認時のpicleソース
この時のロジアナ波形を貼っておきます。左端でRESETがオフになることでV20が動作を開始し、中央部のHLDACがhighになっている部分がV20からの'H'(Hello!の最初の文字)出力要求に対してPICが処理している部分となります。
[TOP] [ 前へ ] 連載記事 [ 次へ ]
前回書いたようにアセンブラはNASMを使っていますがマニュアルにはできるように書いてある
SEGMENT DATA MOV AX,DATA |
でのセグメント値の参照やセグメントの絶対アドレス指定の
SEGMENT CODE ABSOLUTE=0xffc0 |
でエラーやワーニングが発生したり、ORGを2カ所に書くとエラーになったりで悩みましたが、8086のメモリモデルとしてコードセグメントとデータセグメントを同じ値にするtinyモデルにし、データは EQUステートメントでアドレス指定することでPICとV20のインタフェースを確認しました。
PICとのインタフェースの仕掛けとして、回路は初回の記事を参照して頂くとして処理概要としては
- V20からの処理要求
I/F用のワークエリアにパラメータを設定し、A15=1のアドレスにI/O命令を発行する。 - READY信号がinactiveに遷移
PICのコンパレータの出力(オープンドレイン)を使ってハード的にREADY信号がinactiveとなりV20はwait状態になる。 - PIC側での処理
PIC側ではREADY信号を監視していてREADY信号がinactiveになったらコンパレータ出力を無効にし(プルアップしているのでREADY信号はactiveになる)HLDRQをactiveにしてバスの使用権を獲得し、ワークエリアに設定された要求を処理後、結果をワークエリアに保存する。 - PIC側のバスの開放
バスを開放し、コンパレータの出力を有効にする。
となります。
V20側のアセンブルリストは下記のとおりです。処理内容としてはこの手の確認では定番の"Hello!"の表示です。
|
PIC側でのリスト表示後実行した際のログを以下に示します。ログの末尾にあるように想定通り"Hello!"が表示されました(^^)/
|
この時のロジアナ波形を貼っておきます。左端でRESETがオフになることでV20が動作を開始し、中央部のHLDACがhighになっている部分がV20からの'H'(Hello!の最初の文字)出力要求に対してPICが処理している部分となります。
PICとV20のインタフェース確認時の波形サンプル |
|
[TOP] [ 前へ ] 連載記事 [ 次へ ]
レトロマイコン86ボードの構想(その3)V20の動作確認 [8086]
今回は8088互換チップであるV20(uPD70108H)の簡単な動作確認を行ってみたので記録しておきます。
前回のPIC24FJのPMP(パラレルマスタポート)機能の確認ではPICとメモリを実装した状態でしたが、ブレッドボードにV20の配線を追加したところ、不安定な状態でなかなか改善しなかったので古いブレッドボードをあまり使っていないものに交換し再度配線し直したところなんとか安定動作するようになりました。
しかし後述するようにV20のクロックが8MHzの場合は安定に動作していますが、16MHzでは動作しません。
V20の動作確認をするにあたり、ハンドアセンブルでは辛いのでアセンブラ環境が必要になりますが、free(BSDライセンス)でWindows環境でも使えるNASMを使うことにしました。
NASMはダウンロードしたアーカイブファイルを解凍してpathを通せばいいだけなのでインストールも楽でWindowsのレジストリが変更されることもありません。
リンカはVisualStudioのものが使えるようですが、単一のソースファイルであれば(複数ソースをリンクしないのであれば)、-o オプションでバイナリファイルを作成するとアセンブルされたコードの入ったファイルが生成されます。
このバイナリファイルをPic24CPMの開発時に作成したpicleのステートメントに変換するツールを使いpicleのステートメントに変換し、picleソースに入れ込んでいます。
ニーモニックの表記でメモリアクセス時は[]で囲むように統一されているのでワークエリアのアドレスなのか、中身なのか混乱することが無い等、インテルのニーモニックより改善されていて使い易くなっています。しかし英語のマニュアルが217ページあり、斜め読みするだけでもある程度の時間が必要です(プアなマニュアルよりは細かく記載されている方が絶対いいけどね)
V20の動作確認のために下のリストのような簡単なものを作りました。
V20動作確認ソース
処理内容としてはプログラムの末尾に0x1234を書込むという単純なものです。
メモリ(K6T4008C1B-DB70)は512KBのものを1個使用していて、V20のメモリ空間(1MB)の半分のサイズですが、V20のリセット直後の実行アドレスがメモリのエンド領域(0xffff0)なのでメモリ空間の後半に前半と同じイメージが見えてアクセスできるようにしています。
アセンブルとpicleステートメントへの変換操作は
アセンブルとpicleステートメントへの変換操作
こんな感じです。
下記はV20動作テスト用のpicleソースを表示後、実行した際のログです。
V20のプログラム実行により0x020dからの2バイトが想定通り0x1234に書き換えられていることが判ります。
41行目でV20がリセット直後に実行する0xffff0アドレスに 0000:0200 へのファージャンプ命令を書込んでいます。
PMP機能確認用picleソース
冒頭でも書いたように V20(16MHz対応版)のクロックを16MHにすると動作しなかったので8Mhzにして動作確認しています。
それぞれのクロックでのメモリリード時の波形サンプルを下図に示します。この時のロジアナのサンプリング周波数は50MHzなので分解能は20nsです。
16MHzの波形の方はアドレスラッチストローブ(LATCH)の立下りととアドレス線(AD0)の変化までの時間が20ns(50MHz相当)なので結線の接触抵抗が生じるブレッドボードでは厳しいかもしれません。回路的にはV20のクロックをジャンパピンにより8MHz/16MHzの切り換え可能にし、プリント基板化した際に16Mzで動作するか確認する予定です。
今回使用しているV20は uPD70108HCZ-16 なのですがreset中のWR/、RD/信号に関して、マニュアルにはハイレベルに保たれると書かれていますが、今回使用しているものでは下図のロジアナ波形のOE/とWR/に示すようにRESETがハイレベルの時でもローレベル(プルアップするとハイレベルになったのでハイインピーダンス状態と思われる)でした。
reset解除後、6バイト読込んでからジャンプ(A15:low)していますが、ジャンプ命令は5バイトなので最後の1バイトはプリフェッチによるアクセスですね。
また、hold 時にASTBがハイインピーダンスにならないことも、今回のようにアドレスとデータを分離前のバスをPICで制御する場合は使いづらいです。ロジックICを使えば簡単に対応できますが、今回は抵抗を使って対処しています。
★2019/11/04 追記 {
抵抗での対処ではV20のドライブ能力が低くなるため、不安定だったのでASTBをプルダウンし、ショットキーを介してHighレベルに引っ張れるようにしました(Hold中のLowレベル時はPIC側に影響を与えない)
}
[TOP] [ 前へ ] 連載記事 [ 次へ ]
前回のPIC24FJのPMP(パラレルマスタポート)機能の確認ではPICとメモリを実装した状態でしたが、ブレッドボードにV20の配線を追加したところ、不安定な状態でなかなか改善しなかったので古いブレッドボードをあまり使っていないものに交換し再度配線し直したところなんとか安定動作するようになりました。
しかし後述するようにV20のクロックが8MHzの場合は安定に動作していますが、16MHzでは動作しません。
V20の動作確認をするにあたり、ハンドアセンブルでは辛いのでアセンブラ環境が必要になりますが、free(BSDライセンス)でWindows環境でも使えるNASMを使うことにしました。
NASMはダウンロードしたアーカイブファイルを解凍してpathを通せばいいだけなのでインストールも楽でWindowsのレジストリが変更されることもありません。
リンカはVisualStudioのものが使えるようですが、単一のソースファイルであれば(複数ソースをリンクしないのであれば)、-o オプションでバイナリファイルを作成するとアセンブルされたコードの入ったファイルが生成されます。
このバイナリファイルをPic24CPMの開発時に作成したpicleのステートメントに変換するツールを使いpicleのステートメントに変換し、picleソースに入れ込んでいます。
ニーモニックの表記でメモリアクセス時は[]で囲むように統一されているのでワークエリアのアドレスなのか、中身なのか混乱することが無い等、インテルのニーモニックより改善されていて使い易くなっています。しかし英語のマニュアルが217ページあり、斜め読みするだけでもある程度の時間が必要です(プアなマニュアルよりは細かく記載されている方が絶対いいけどね)
V20の動作確認のために下のリストのような簡単なものを作りました。
|
処理内容としてはプログラムの末尾に0x1234を書込むという単純なものです。
メモリ(K6T4008C1B-DB70)は512KBのものを1個使用していて、V20のメモリ空間(1MB)の半分のサイズですが、V20のリセット直後の実行アドレスがメモリのエンド領域(0xffff0)なのでメモリ空間の後半に前半と同じイメージが見えてアクセスできるようにしています。
アセンブルとpicleステートメントへの変換操作は
|
こんな感じです。
下記はV20動作テスト用のpicleソースを表示後、実行した際のログです。
V20のプログラム実行により0x020dからの2バイトが想定通り0x1234に書き換えられていることが判ります。
41行目でV20がリセット直後に実行する0xffff0アドレスに 0000:0200 へのファージャンプ命令を書込んでいます。
|
冒頭でも書いたように V20(16MHz対応版)のクロックを16MHにすると動作しなかったので8Mhzにして動作確認しています。
それぞれのクロックでのメモリリード時の波形サンプルを下図に示します。この時のロジアナのサンプリング周波数は50MHzなので分解能は20nsです。
16MHzの波形の方はアドレスラッチストローブ(LATCH)の立下りととアドレス線(AD0)の変化までの時間が20ns(50MHz相当)なので結線の接触抵抗が生じるブレッドボードでは厳しいかもしれません。回路的にはV20のクロックをジャンパピンにより8MHz/16MHzの切り換え可能にし、プリント基板化した際に16Mzで動作するか確認する予定です。
クロック8MHz時のメモリリード波形サンプル(結果:OK) |
|
クロック16MHz時のメモリリード波形サンプル(結果:NG) |
|
今回使用しているV20は uPD70108HCZ-16 なのですがreset中のWR/、RD/信号に関して、マニュアルにはハイレベルに保たれると書かれていますが、今回使用しているものでは下図のロジアナ波形のOE/とWR/に示すようにRESETがハイレベルの時でもローレベル(プルアップするとハイレベルになったのでハイインピーダンス状態と思われる)でした。
reset解除後、6バイト読込んでからジャンプ(A15:low)していますが、ジャンプ命令は5バイトなので最後の1バイトはプリフェッチによるアクセスですね。
また、hold 時にASTBがハイインピーダンスにならないことも、今回のようにアドレスとデータを分離前のバスをPICで制御する場合は使いづらいです。ロジックICを使えば簡単に対応できますが、今回は抵抗を使って対処しています。
★2019/11/04 追記 {
抵抗での対処ではV20のドライブ能力が低くなるため、不安定だったのでASTBをプルダウンし、ショットキーを介してHighレベルに引っ張れるようにしました(Hold中のLowレベル時はPIC側に影響を与えない)
}
マニュアル記載内容 |
|
reset解除直後の波形サンプル |
|
[TOP] [ 前へ ] 連載記事 [ 次へ ]
レトロマイコン86ボードの構想(その2) [8086]
86ボード制作ですが、PIC24FJのPMP(パラレルマスタポート)機能について実験してみました。
今回はシリアル通信をアサインするピンを変更するのでブートローダー側のシリアルも変更が必要でPic24FJ用ブートローダーのOneBitLoaderを入れるところからです。
久々にOneBitLoaderの最初の立ち上げ画面を見ました。
次にローダーを使ってpicleコンパイラを書込み、その後はpicleのセルフコンパイル環境でソースを変更し、コンパイルの繰り返し作業なのでローダーすらほとんど使いません。
V20(8088相当品)を使用することを想定しているので8bitのデータバスに下位アドレスがマルチプレクスする半多重化アドレッシングモードを使用します。
データ線とアドレス線がマルチプレクスされることでPIC24側のI/Oに少し余裕ができます。
PMP機能では下図のようにタイミングをパラメータにより色々設定可能なので数通りのパラメータパターンについてロジアナで確認してみました。
タイミングの調整要素としては上図に書かれているように WAITB,WAITM,WAITE(それぞれBegin、Middle、Endの略だと思う)があり、全てゼロの場合の最速タイミングが下図です。PIC24のクロックは内蔵クロックを使用して32MHzにしています。
モニタした信号はメモリアクセスのための下記の信号です。
今回もアクセスタイムが70nsのメモリを使用する予定なので WR/ はもっと広げないと駄目ですね。LATCHもマージンを大きくし、ノイズの発生も少なくするためにもっと広げたいと思います。
下の図が3通りのパラメータで設定した場合のロジアナ波形です。WR/幅が140nsでlatch幅が80nsでlatch後20ns程度アドレスを保持しているWAITB:1,WAITM:2,WAITE:1 を採用することにします。
その時、PIC の PMCON と PMMODE のレジスタの設定値はそれぞれ 0x0ba0、0x0a49 になります。
★2019/07/15 修正
採用パターンのWAITEを0から1に修正(latch後のアドレス保持時間の確保のため))
参考として WAITB:1,WAITM:2,WAITE:1 時のメモリリードタイミングが下図です。
今回の確認に使用したpicleソースと実行結果を貼っておきます。
PMP機能確認用picleソース
[TOP] [ 前へ ] 連載記事 [ 次へ ]
今回はシリアル通信をアサインするピンを変更するのでブートローダー側のシリアルも変更が必要でPic24FJ用ブートローダーのOneBitLoaderを入れるところからです。
久々にOneBitLoaderの最初の立ち上げ画面を見ました。
次にローダーを使ってpicleコンパイラを書込み、その後はpicleのセルフコンパイル環境でソースを変更し、コンパイルの繰り返し作業なのでローダーすらほとんど使いません。
OneBirLoaderの最初の立ち上げ画面 |
|
V20(8088相当品)を使用することを想定しているので8bitのデータバスに下位アドレスがマルチプレクスする半多重化アドレッシングモードを使用します。
データ線とアドレス線がマルチプレクスされることでPIC24側のI/Oに少し余裕ができます。
PMP機能では下図のようにタイミングをパラメータにより色々設定可能なので数通りのパラメータパターンについてロジアナで確認してみました。
PMP半多重化アドレッシングタイミング |
|
タイミングの調整要素としては上図に書かれているように WAITB,WAITM,WAITE(それぞれBegin、Middle、Endの略だと思う)があり、全てゼロの場合の最速タイミングが下図です。PIC24のクロックは内蔵クロックを使用して32MHzにしています。
モニタした信号はメモリアクセスのための下記の信号です。
- MCS/ チップセレクト
- OE/ リードストローブ
- WR/ ライトストローブ
- LATCH 下位アドレスラッチ用のHC573へのG信号
- AD0 データ線のLSBビットの信号
PMPライトタイミング(wait無し) |
|
今回もアクセスタイムが70nsのメモリを使用する予定なので WR/ はもっと広げないと駄目ですね。LATCHもマージンを大きくし、ノイズの発生も少なくするためにもっと広げたいと思います。
下の図が3通りのパラメータで設定した場合のロジアナ波形です。WR/幅が140nsでlatch幅が80nsでlatch後20ns程度アドレスを保持しているWAITB:1,WAITM:2,WAITE:1 を採用することにします。
その時、PIC の PMCON と PMMODE のレジスタの設定値はそれぞれ 0x0ba0、0x0a49 になります。
★2019/07/15 修正
採用パターンのWAITEを0から1に修正(latch後のアドレス保持時間の確保のため))
PMPライトタイミング(WAITB:1, WAITM:1, WAITE:1) |
|
PMPライトタイミング(WAITB:1, WAITM:2, WAITE:1) |
|
PMPライトタイミング(WAITB:1, WAITM:2, WAITE:0) |
|
参考として WAITB:1,WAITM:2,WAITE:1 時のメモリリードタイミングが下図です。
PMPリードタイミング(WAITB:1, WAITM:2, WAITE:1) |
|
今回の確認に使用したpicleソースと実行結果を貼っておきます。
|
[TOP] [ 前へ ] 連載記事 [ 次へ ]
Z80での10の高速除算方法 [Z80]
今回はtwitterで見かけたZ80で10で割る処理に関するお題について書いてみます。
お題としてはZ80で100未満の数値を10で除算処理する場合、如何に高速にできるか?というもので
Breg ÷ 10 = Hreg ... Areg
という処理です。
具体的な処理例も挙げられていて次の処理を高速化できるか? という問題です。
100要素分の回答の配列から引っ張るのが一番速いですがそれは無しという条件付きです。
尚、以下に示す各処理は0..99の入力に対するリターン値(AregとHreg)が全て同じであることを確認済みのものです。
処理例
上記の処理内容を見ると通常の割算処理のループを展開したような形になっています。
ループが展開されているので被除数が小さい場合には上位桁の演算をスキップするショートカット方式を最初に思いつきました。
ショートカットすることで
0~39なら -54clk
40~99なら+18clk
となり平均すれば-10.8clk分速くなりそうです。
最初に思いついたショートカット方式
しかし、既に下記のバイナリサーチのような処理案(「引き放し法」と言うそうです)が出ていて処理内容が複雑そうですが確かに速そうです。
引き放し法
ぱっと見は処理内容が解り辛いですが、10 x (2のべき乗) の大きい方(80)から引いていき(キャリが出たら次は足す)、10未満になったら終了するような処理が見えてきます。
最初に書いた処理例では比較(CP)で確認後減算(SUB)していますが、比較による確認無しに減算し、マイナスになっても元に戻さず(だから「引き放し法」)次に半分の値を足すことで結果として半分の値を引いたのと等価になるというものです。
しかし、入力値の条件が100未満なので80を引けた場合、直後に40を引いているのは無駄なように見えます。
80を引いた後は0..19の範囲内なので10を引けるかのチェックをした方が早く収束するはずなので改善してみたものが下の処理です。
引き放し法の改善案
発想を変えて、お題がZ80なのでBCD関連の命令をうまく利用できないか考えてみた結果が次の処理です。
★追記 2019/07/13 {
思考の順番としては100要素の回答テーブルの各要素の規則性は単純なのでもっと短いテーブルにできないものか?という発想から考えた結果として上位ニブルに対するBCDテーブルに行き着きました。
}
RRD命令のクロック数が多いのが気になりますがこれも結構速そうですね^^
気合を入れれば平均クロック数を算出して上の処理と比較できますが夜の作業としては他の作業をしたい(上の処理は分岐確率が50%でないところがあるので更にややこしい)
今時のマイコンであれば統合開発環境内で実行時のクロック数はシミュレータですぐに確認できるのですが、Z80のシミュレータで実行クロック数を確認できるものを少し探しましたが見当たりませんでした。
0..99をループで回し開始/終了時にI/O命令を実行してロジアナで確認することはある程度容易にできますが、それもやぼったいので、クロック数をモニタできるシミュレータが見つかったら比較してみたいと思います。
現時点で最新の高速処理案
★追記 2019/08/01
このブログの読者にはあまり人気が無かったこのページのアクセスが最近多くなりました。
yasuokaの日記: Z80における定数10の除算は、商と余りのどちらを先に求めるべきか
関連の書込み記事からのアクセスのおかげのようです^^
51/512倍することで商を出す手法で末尾に ret を加えると108clk(ステート)で上記のもの(118clk)より高速です(上記のものもRRD命令部をシフト化して数clkの短縮は可能ですが)。
今回の問題では入力範囲が0..99なのでこのような分数演算の手法では誤差を1%未満にする必要があります。私も13/128でやってみたところ誤差が1%以上なので回答が途中からズレた結果になりました。
また、整数演算なので誤差が1%未満であっても誤差の範囲内の変動で回答が影響を受けないように inc a で微調整されています。
普通に考えると16bitでシフトしたいところですが、なんと8bitのシフトや演算で処理を完結しています・・すばらしい!
私も新たなアイディアを思いついたら追記したいと思います。
★追記 2019/08/02
アイディアが浮かんだので試してみた結果をメモしておきます。
今回、複数のアイディアを盛り込み、結果として上記の分数方式(108clk)より4clk短縮(104clk)できました。(^^)/
★変更 2019/08/03 {
yasuokaの日記: Re:Z80における定数10の除算は、商と余りのどちらを先に求めるべきかの記事がアップされ剰余を先に求める方法で103clk(最後にretを追加した場合)達成とのこと。
今回追記した処理に関してもまだ少しのりしろがあったので一部見直し103clkになりました^^
}
今回適用した主要なアイディアとしては、少数演算の使用と上位/下位のnibleを逆転することによる4bitシフト処理の省略です。
後者についてはピンと来ないかも知れませんが以下に概要を説明します。
小数点で0.1倍した改善処理
★追記 2019/12/27
下記の変更で3ステート速くなり、サイズも1バイト小さくなります。
★追記 2021/12/03
上記の変更でEregが非破壊になりました。更にCregを使用している3箇所をHreg使用に変更することでCregも非破壊にできます。
★追記 2019/08/07
分数方式についての考察を少し書いてみます。
初めに前回の小数点方式について動作を判り易く図解してみます。
下図で一番上に書いてある「x 1.5」の行は被除数を1.5倍したものです。
0.1を2進数で表すと上記のように「0001100110011・・・」の循環小数になるので「1.5倍」の数を4ビットずつシフトしながら無限回並べたものの合計になります。
上の小数点方式の説明で「上位/下位ニブルの逆転処理」と書いた部分でキャリーを足している対象は正確に言うと下図の「整数部分」になります。
因みに4bit周期の循環小数なのでうまくやれば誤差無しに計算可能で(循環部で桁上りした場合、下の桁からも必ず桁上りしてくるので)、小数点部分を正確に求められれば、小数点の上位3bitの2倍と8倍を足すことで余りの値も計算結果から求められるはずなのですが、
の理由から断念しました。
話を分数方式に戻すと分母が2のべき乗の場合、分子のビットパターンは結局上記の0.1の循環小数と同様になり(分母が2のべき乗なら分子は0.1の循環小数のパターンをシフトしたものの近似になるのは当然)、処理内容は前回書いた小数点方式とほぼ同様になります。
試しに 25.5 / 256(1バイトなので判り易い)を例にすると下図のように1.5倍したものを RLCA で4回左シフトし、整数部は下位4bitに折り返した形になります(折り返し部分は不要なのですが、上の小数点方式の観点で見れば、演算精度を上げる方向に作用するのでワザワザ削除する必要はない)。
シフト前とシフト後の値の合計を取り、発生したキャリーを整数部に加える処理となり、前回書いた小数点方式と処理内容は同じになります。
小数点方式も同様ですが(ウルトラCのアイディアがあれば)循環小数点部分の処理の高速化については検討の余地があるかもしれません。
★追記 2019/09/16
「Z80における2進→BCD変換」というお題を見つけたのでWeb上のMSX環境で凸撃兵さんが作られたのものを改造してMSXPen環境で確認してみました。
★追記 2023/04/22
下記の記事で 8bit 符号無し整数の高速な乗算方法を提案しました。
お題としてはZ80で100未満の数値を10で除算処理する場合、如何に高速にできるか?というもので
Breg ÷ 10 = Hreg ... Areg
という処理です。
具体的な処理例も挙げられていて次の処理を高速化できるか? という問題です。
100要素分の回答の配列から引っ張るのが一番速いですがそれは無しという条件付きです。
尚、以下に示す各処理は0..99の入力に対するリターン値(AregとHreg)が全て同じであることを確認済みのものです。
|
上記の処理内容を見ると通常の割算処理のループを展開したような形になっています。
ループが展開されているので被除数が小さい場合には上位桁の演算をスキップするショートカット方式を最初に思いつきました。
ショートカットすることで
0~39なら -54clk
40~99なら+18clk
となり平均すれば-10.8clk分速くなりそうです。
|
しかし、既に下記のバイナリサーチのような処理案(「引き放し法」と言うそうです)が出ていて処理内容が複雑そうですが確かに速そうです。
|
ぱっと見は処理内容が解り辛いですが、10 x (2のべき乗) の大きい方(80)から引いていき(キャリが出たら次は足す)、10未満になったら終了するような処理が見えてきます。
最初に書いた処理例では比較(CP)で確認後減算(SUB)していますが、比較による確認無しに減算し、マイナスになっても元に戻さず(だから「引き放し法」)次に半分の値を足すことで結果として半分の値を引いたのと等価になるというものです。
しかし、入力値の条件が100未満なので80を引けた場合、直後に40を引いているのは無駄なように見えます。
80を引いた後は0..19の範囲内なので10を引けるかのチェックをした方が早く収束するはずなので改善してみたものが下の処理です。
|
発想を変えて、お題がZ80なのでBCD関連の命令をうまく利用できないか考えてみた結果が次の処理です。
★追記 2019/07/13 {
思考の順番としては100要素の回答テーブルの各要素の規則性は単純なのでもっと短いテーブルにできないものか?という発想から考えた結果として上位ニブルに対するBCDテーブルに行き着きました。
}
RRD命令のクロック数が多いのが気になりますがこれも結構速そうですね^^
気合を入れれば平均クロック数を算出して上の処理と比較できますが夜の作業としては他の作業をしたい(上の処理は分岐確率が50%でないところがあるので更にややこしい)
今時のマイコンであれば統合開発環境内で実行時のクロック数はシミュレータですぐに確認できるのですが、Z80のシミュレータで実行クロック数を確認できるものを少し探しましたが見当たりませんでした。
0..99をループで回し開始/終了時にI/O命令を実行してロジアナで確認することはある程度容易にできますが、それもやぼったいので、クロック数をモニタできるシミュレータが見つかったら比較してみたいと思います。
|
★追記 2019/08/01
このブログの読者にはあまり人気が無かったこのページのアクセスが最近多くなりました。
yasuokaの日記: Z80における定数10の除算は、商と余りのどちらを先に求めるべきか
関連の書込み記事からのアクセスのおかげのようです^^
51/512倍することで商を出す手法で末尾に ret を加えると108clk(ステート)で上記のもの(118clk)より高速です(上記のものもRRD命令部をシフト化して数clkの短縮は可能ですが)。
今回の問題では入力範囲が0..99なのでこのような分数演算の手法では誤差を1%未満にする必要があります。私も13/128でやってみたところ誤差が1%以上なので回答が途中からズレた結果になりました。
また、整数演算なので誤差が1%未満であっても誤差の範囲内の変動で回答が影響を受けないように inc a で微調整されています。
普通に考えると16bitでシフトしたいところですが、なんと8bitのシフトや演算で処理を完結しています・・すばらしい!
私も新たなアイディアを思いついたら追記したいと思います。
★追記 2019/08/02
アイディアが浮かんだので試してみた結果をメモしておきます。
★変更 2019/08/03 {
yasuokaの日記: Re:Z80における定数10の除算は、商と余りのどちらを先に求めるべきかの記事がアップされ剰余を先に求める方法で103clk(最後にretを追加した場合)達成とのこと。
今回追記した処理に関してもまだ少しのりしろがあったので一部見直し103clkになりました^^
}
今回適用した主要なアイディアとしては、少数演算の使用と上位/下位のnibleを逆転することによる4bitシフト処理の省略です。
後者についてはピンと来ないかも知れませんが以下に概要を説明します。
- 小数点で処理
分数方式だと前回記載したように誤差が1%未満の条件で分子と分母の組合せを色々考えることになりますが、0.1を2進数で表現し、その乗算値を求めればいいのでは?と考えました。
小数点であれば分数のように組合せを考える必要が無いし、誤差は桁数に依存し一意に決まります。
また、シフトが一方向なので往復するようなシフト処理が発生しません。
下表に示すように 0.1を2進数で表すと2進数の循環小数になります。
下表の1~9(橙色部分)の合計は 0.099609 なのでここまで算出すれば1%未満という条件を満たす誤差範囲になるはずです。
- 小数点の桁のアサイン
速度優先で計算は8bitで行うので8bit分の有効桁数を維持するために表中のNo.1~3のゼロの部分は省略してNo4をMSBに割り振ります。
この場合、16倍したことになるので最終的に上位nibleに結果が求まることになり、結果を取り出すために4回のシフト処理が必要になりますが、この問題は後述の対策で解決します。
- 循環小数の求め方
表中のNo4と5の合計を求め、1/16倍(4bitシフト)すればNo8と9の合計になります。
- 上位/下位ニブルの逆転処理
上記の循環小数のための4bitシフトでRRCAを使用することで、上位のnibleと下位のnibleが入代ります。
ここでLSB側のnibleの方を上位、MSB側のnibleを下位と考えるとシフト前の値がシフト後の値の1/16と考えることができます。
また、0.1倍した結果がLSB側のnibleに入るようになるので、前述した結果を取り出す際の4回のシフト処理が不要になります。
- 加算部の処理
表中のNo.4,5にNo.8,9を加算する際は、MSB側の下位nibleから上位nibleへ桁上り(キャリー)が発生するか否かが必要な情報であり、キャリーが発生した場合、LSB側の上位nibleに反映するために、No.8,9を加算後にキャリ付き加算(ADC)を実行しています。
- 剰余の計算
商が求まったら、商の10倍を入力値から減算して余りを算出しています。
|
★追記 2019/12/27
下記の変更で3ステート速くなり、サイズも1バイト小さくなります。
5F LD E,A ; 4 81 ADD A,C ; 4 3E 00 LD A,0 ; 7 8B ADC A,E ; 4 ↓ 81 ADD A,C ; 4 3F CCF ; 4 99 SBC A,C ; 4 3C INC A ; 4 |
★追記 2021/12/03
上記の変更でEregが非破壊になりました。更にCregを使用している3箇所をHreg使用に変更することでCregも非破壊にできます。
★追記 2019/08/07
分数方式についての考察を少し書いてみます。
初めに前回の小数点方式について動作を判り易く図解してみます。
下図で一番上に書いてある「x 1.5」の行は被除数を1.5倍したものです。
0.1を2進数で表すと上記のように「0001100110011・・・」の循環小数になるので「1.5倍」の数を4ビットずつシフトしながら無限回並べたものの合計になります。
上の小数点方式の説明で「上位/下位ニブルの逆転処理」と書いた部分でキャリーを足している対象は正確に言うと下図の「整数部分」になります。
小数点方式の処理イメージ図 |
|
因みに4bit周期の循環小数なのでうまくやれば誤差無しに計算可能で(循環部で桁上りした場合、下の桁からも必ず桁上りしてくるので)、小数点部分を正確に求められれば、小数点の上位3bitの2倍と8倍を足すことで余りの値も計算結果から求められるはずなのですが、
- 8bitでは処理が難しい
シフトする塊が被除数の3倍なので桁落ちせずに計算するには 99 x 3 = 297 まで扱う必要があり、1バイト処理では難しい
- 小数部からの余りの取り出し処理
現状の商から余りを求める部分と比較し大きな効果が出るとは思えない。
の理由から断念しました。
話を分数方式に戻すと分母が2のべき乗の場合、分子のビットパターンは結局上記の0.1の循環小数と同様になり(分母が2のべき乗なら分子は0.1の循環小数のパターンをシフトしたものの近似になるのは当然)、処理内容は前回書いた小数点方式とほぼ同様になります。
試しに 25.5 / 256(1バイトなので判り易い)を例にすると下図のように1.5倍したものを RLCA で4回左シフトし、整数部は下位4bitに折り返した形になります(折り返し部分は不要なのですが、上の小数点方式の観点で見れば、演算精度を上げる方向に作用するのでワザワザ削除する必要はない)。
シフト前とシフト後の値の合計を取り、発生したキャリーを整数部に加える処理となり、前回書いた小数点方式と処理内容は同じになります。
小数点方式も同様ですが(ウルトラCのアイディアがあれば)循環小数点部分の処理の高速化については検討の余地があるかもしれません。
分数方式(25.5/256)の処理イメージ図 |
|
★追記 2019/09/16
「Z80における2進→BCD変換」というお題を見つけたのでWeb上のMSX環境で凸撃兵さんが作られたのものを改造してMSXPen環境で確認してみました。
★追記 2023/04/22
下記の記事で 8bit 符号無し整数の高速な乗算方法を提案しました。
3チップ構成Pic24CPM68Kマイコン(CP/M-68K起動までの作業まとめ) [68K]
今回作成した3チップ構成のワンボードマイコン(下の写真)でCP/M-68Kが動作しているようなのでCP/M-68Kを立ち上げるまでに必要な作業を整理しました。
使用しているチップは下記のとおり、3チップ構成で汎用ロジックICやPLD等は使っていません。
★2019/07/07 追記 {
Pic24CPM68Kのアーカイブファイルに入れた方が良かったかもと後で思いましたが、CP/M-68Kとパソコン間でファイル送受信したい場合には「3チップ構成68Kマイコンの構想(その10)XMODEMアプリの作成」の記事に書いた拙作のCP/M-68K用のxmodemアプリを使用するとメチャ便利です。パソコン側ではTeraTermのxmodem機能を使います。
コンソール出力はPIC側でCP/M時代のエスケープシーケンスの一部をANSIエスケープシーケンスに変換しているのでTeraTermのディフォルトターミナルであるVT100でもWordMasterやWordStarが動きます。
しかし、このためにコンソール出力データがPICの変換処理で変更されてしまい、バイナリデータの透過性が保証されません。
Pic24CPM68KではBIOSの汎用入出力(CP/M-80で言うPUN/RDRデバイス)をコンソール用のシリアルを使い、バイナリデータの透過性を保証できるように実装しているので xmodem 使用時に /p のオプションを付けることでファイル送受信をバイナリ透過性のある汎用入出力で行えます。
また、Pic24CPM68KのOPEスイッチを押すことで上記のPIC側でのエスケープシーケンス変換を有効/無効に切り換えれるのでxmodem使用時に変換処理を無効状態にして /p オプション無しで使うことも可能です。
}
★2019/07/08 追記
上記の「WordMasterやWordStarが動きます」はCP/M-80(Pic24CPM)での話です^^;
Pic24CPM68Kでも同様にエスケープシーケンスの変換処理が実装されています。
【参考リンク】
下記のwebサイトを参考にさせて頂きました。
★追記 2023/06/28 {
MC68K を使用したチップサイズとほぼ同じサイズの CP/M-68K ボード(Pic24MC68K)について記載した記事のリンクを追加しました。
}
[TOP] [ 前へ ] 連載記事 [ 次へ ]
使用しているチップは下記のとおり、3チップ構成で汎用ロジックICやPLD等は使っていません。
- MC68008P10
10MHz版のバスが8bit幅の68Kチップ。PICからクロックを供給する関係で8MHzで動作。
- K6T4008C1B-DB70
512KBのSRAM。アクセスタイムは70ns。
- PIC24FJ64GA004
16bitPICマイコン。セルフコンパイラの独自言語picleを使って制御
Pic24CPM68K |
|
- 事前にダウンロードするもの
- 今回作成したPic24CPM68K用のファイル
PICファーム全体のhexファイル(これを書込めばPIC側の準備は完了)とIPL、bios等のCP/M関連のソース等をアーカイブした下記のファイルをダウンロードする。
★変更 2022/02/21
CPM本体をメモリの上位に移動し、TPAが0400Hから始まる前提のプログラムも動くようにした
旧バージョンから変更する場合はA:ドライブ内の CPM.SYS を新しいものに入れ替えるだけです
- cpmtools
the Wonderfully Ancient World of CP/Mのサイトでhttp://www.cpm8680.com/cpmtools/cpmtoolsWin32.zipのリンクからダウンロード
- CP/M-68K関連ファイル
CP/M-68K Ver1.3のファイルは下記から入手しました。
- DD for Windows
作成したCP/MディスクイメージをSDカードに書込むユーティリティ
DD for Windowsからダウンロード。
※2018/05/12現在での最新版はVer.0.9.9.8です(これを使用しています)
- 今回作成したPic24CPM68K用のファイル
- PIC24FJ64GA004側の準備
- ワンボードマイコン基板
回路図は下記のとおりです。詳細は「3チップ構成68Kマイコンの構想(その11)回路図整理とパターン設計」の記事を参照してください。
SDカードホルダはebayで購入したものを使っていますが、秋月電子通商さんで販売している「SDカードコネクタ SD381200-S304」も使えると思います。
今回作成したプリント基板のガーバーデータをseeedさんの「Fusion gallery」の「Geek product」コーナーで公開しました。
CP/M-68K board consisting three chips
3チップ構成の68Kマイコンボードの回路図 ※R3は+5Vにプルアップするつもりでしたが3.3Vへのプルアップでも動作することを確認しました^^;
- PICのファーム
上記でダウンロードしたファイルのPICディレクトリ直下のhexファイルをPIC24FJ64GA004に書き込めば準備完了です。
- PICにPICKIT3等で書込みを行う場合はPL2コネクタに接続してください。
書込み時に使用するピンはSDカードと兼用しているので、SDカードを抜いた状態で書込んでください(68Kやメモリは挿した状態でOKです)。
書込み器を接続した状態ではSDカードのアクセスエラーが発生するので、書込み器を外してからCP/Mを起動してください。
- 68Kとの連携処理等はpicle言語で記述していて、自動起動状態にしているので電源ONでCP/Mが起動します。
- cpmディレクトリに入っている「EXIT.68K」をCP/M上で起動するとCP/Mから抜けてpicleコンパイラの世界に戻ります(runコマンドでCP/M再起動)
- picleのソースもpic用hexファイルに入れてあるのでセルフコンパイル環境で機能変更が可能です。
picleソースの表示方法やpicleの使用方法については「独自言語 picle on PIC24FJ」や「独自言語 picle compiler on PIC24FJ」を参照してください。
- TeraTermのシリアル設定は38400bps、8bit、Parity無しです。
- SDカードの抜き差しをPICが監視しています。抜いた状態ではERSDのLEDが点滅します。SDカードを抜いてから挿入するとSDカードを再度イニシャライズ(保存データは消えない)するので継続してSDカードのアクセスが可能です。
- 「OPE」スイッチでコンソールのエスケープシーケンスの有効/無効を切り替えられます。
無効にした場合、PIC側の処理でコンソールデータの書換えが発生しないのでコンソール用シリアル通信でバイナリデータの透過性が保証できるようになります(バイナリデータ転送時に利用)。
- PICにPICKIT3等で書込みを行う場合はPL2コネクタに接続してください。
- ワンボードマイコン基板
- ディスクイメージの作成
ダウンロードしたcpmtoolsを展開したフォルダにPic24CPM68K用アーカイブ内にあるdiskdefs、cpmboot.img及びsysgen68.batファイルを置きます。
上記でダウンロードしたCP/M-68K Ver1.3のアーカイブ内にある「DISK1」~「DISK9」のフォルダをcpmtoolsを展開したフォルダ直下にコピーします。
DISK1フォルダにはPic24CPM68K用アーカイブ内にあるCPM.SYSを上書きでコピーします。
sysgen68.bat内を見れば判るように「DISK10」(Jドライブ)までのファイルイメージを作成するようになっているのでDISK10のフォルダを作成し、Pic24CPM68K用アーカイブ内にあるSKED.RELやEXIT.68K(その他、CP/MのJドライブに入れたいファイル)を「DISK10」フォルダに入れます。
DISK1~DISK10までのフォルダの準備ができたら、sysgen68を実行すると「diskimage」というファイルが生成されます。
- SDカードへの書込み
SDHCタイプ(2GBより大きく32GB以下)のSDカードに、上記操作で作成した diskimage を DD for Windows で書き込みます。
SD書込みソフトは実行ファイルを右クリックして表示されるポップアップメニュで「管理者として起動」を選択して起動する必要があります。
- CP/Mの起動
上記で作成したSDカードを入れた状態で電源を入れれば、自動的にCP/Mが立ち上がります。
ダウンロードしたPic24CPM68Kファイルに入っている「EXIT.68K」を実行することで、CP/M-68Kから抜け、PIC上のpicleコンパイラの環境に戻ります。
★2019/07/07 追記 {
Pic24CPM68Kのアーカイブファイルに入れた方が良かったかもと後で思いましたが、CP/M-68Kとパソコン間でファイル送受信したい場合には「3チップ構成68Kマイコンの構想(その10)XMODEMアプリの作成」の記事に書いた拙作のCP/M-68K用のxmodemアプリを使用するとメチャ便利です。パソコン側ではTeraTermのxmodem機能を使います。
コンソール出力はPIC側でCP/M時代のエスケープシーケンスの一部をANSIエスケープシーケンスに変換しているのでTeraTermのディフォルトターミナルであるVT100でもWordMasterやWordStarが動きます。
しかし、このためにコンソール出力データがPICの変換処理で変更されてしまい、バイナリデータの透過性が保証されません。
Pic24CPM68KではBIOSの汎用入出力(CP/M-80で言うPUN/RDRデバイス)をコンソール用のシリアルを使い、バイナリデータの透過性を保証できるように実装しているので xmodem 使用時に /p のオプションを付けることでファイル送受信をバイナリ透過性のある汎用入出力で行えます。
また、Pic24CPM68KのOPEスイッチを押すことで上記のPIC側でのエスケープシーケンス変換を有効/無効に切り換えれるのでxmodem使用時に変換処理を無効状態にして /p オプション無しで使うことも可能です。
}
★2019/07/08 追記
上記の「WordMasterやWordStarが動きます」はCP/M-80(Pic24CPM)での話です^^;
Pic24CPM68Kでも同様にエスケープシーケンスの変換処理が実装されています。
【参考リンク】
下記のwebサイトを参考にさせて頂きました。
- CP/Mコーナー neko JavaさんのCP/Mの導入に関する情報全般
- Digital Research Binary Files CP/Mシステム関連のソース
- MMC/SDCの使いかた ChaNさんのSPIでのSDカードの制御方法解説
- SD規格の概要
★追記 2023/06/28 {
MC68K を使用したチップサイズとほぼ同じサイズの CP/M-68K ボード(Pic24MC68K)について記載した記事のリンクを追加しました。
小型CP/M-68Kボード(Pic24MC68K) |
|
[TOP] [ 前へ ] 連載記事 [ 次へ ]