Z80GALの構想(その11)IPLの製作 [Z80]
前回の「Z80GALの構想(その10)回路図とパターン設計」で書いたようにプリント基板のパターン設計ができたのでseeedさんへ発注しましたが、その後2ヶ所ミスを発見orz
1つはシルクが2022年になっていました(未来から来た基板w)、あと1つはパターンをカットすれば対応できそうですがプリント基板が届いてから具体的な対処を検討します。
今回は未作成だったIPLを作ったので書いてみます。IPLを先頭セクタに保存し、リセット時に先頭セクタをメモリに読込み、実行することでCP/Mが立ち上るようになります。
IPLは1つのセクタ(128バイト)に入れるため、SDカードのブロック読込みはEEPROMからRAMへコピーされたコード内の処理を呼び出すようにしました。
また、割込み処理の切替えは少し面倒なのでシリアル出力は割込みを使用せずソフトでタイミングを取った専用のものを使用するようにしました。
短いので全ソースを貼っておきます。
★変更 2020/11/29 Putc処理のコードを短縮
また、リセット後の立上り処理として、SDカードを挿している場合はCP/Mを起動し、SDカードが無い場合にはGAMEインタープリタを起動するようにしました。
更にCP/M起動後にGAMEの世界に戻ったりGAMEからCP/Mを起動できるようにしてみました。下図がリセット後のCP/M起動から切替え操作例のキャプチャです。
CP/Mが動作している状態でEEPROM内コードをRAMにコピー後に、0003Hから実行するとGAMEインタープリタが起動するようにしています。
CP/MからGAMEへ移行するためには下記のリストのようにROM/RAM切替の影響を受けないメモリの後半(下記の場合は8000H)で動作するプログラムでEEPROMをアクティブにしてコードをRAMにコピー後、0003HへジャンプすることでGAMEインタープリタが立ち上がります。
また、GAMEが動作している状態では、単に0000HへジャンプするだけでCP/Mが起動します。
★追記 2021/01/22
CP/MからGAMEインタープリタの世界に移行するためには、ROMがアクティブな状態で0003Hから実行すればいいので、上記のGAMEインタープリタ起動コマンドをスリム化しました。
[TOP] [ 前へ ] 連載記事 [ 次へ ]
1つはシルクが2022年になっていました(未来から来た基板w)、あと1つはパターンをカットすれば対応できそうですがプリント基板が届いてから具体的な対処を検討します。
今回は未作成だったIPLを作ったので書いてみます。IPLを先頭セクタに保存し、リセット時に先頭セクタをメモリに読込み、実行することでCP/Mが立ち上るようになります。
IPLは1つのセクタ(128バイト)に入れるため、SDカードのブロック読込みはEEPROMからRAMへコピーされたコード内の処理を呼び出すようにしました。
また、割込み処理の切替えは少し面倒なのでシリアル出力は割込みを使用せずソフトでタイミングを取った専用のものを使用するようにしました。
短いので全ソースを貼っておきます。
Z80GAL IPL(Initial Program Loader) |
|
また、リセット後の立上り処理として、SDカードを挿している場合はCP/Mを起動し、SDカードが無い場合にはGAMEインタープリタを起動するようにしました。
更にCP/M起動後にGAMEの世界に戻ったりGAMEからCP/Mを起動できるようにしてみました。下図がリセット後のCP/M起動から切替え操作例のキャプチャです。
CP/MとGAMEの切替え |
|
CP/Mが動作している状態でEEPROM内コードをRAMにコピー後に、0003Hから実行するとGAMEインタープリタが起動するようにしています。
CP/MからGAMEへ移行するためには下記のリストのようにROM/RAM切替の影響を受けないメモリの後半(下記の場合は8000H)で動作するプログラムでEEPROMをアクティブにしてコードをRAMにコピー後、0003HへジャンプすることでGAMEインタープリタが立ち上がります。
また、GAMEが動作している状態では、単に0000HへジャンプするだけでCP/Mが起動します。
CP/MからGAMEインタープリタ起動コマンドのソース |
|
★追記 2021/01/22
CP/MからGAMEインタープリタの世界に移行するためには、ROMがアクティブな状態で0003Hから実行すればいいので、上記のGAMEインタープリタ起動コマンドをスリム化しました。
CP/MからGAMEインタープリタ起動コマンド改善版のソース |
|
[TOP] [ 前へ ] 連載記事 [ 次へ ]
Z80GALの構想(その10)回路図とパターン設計 [Z80]
Z80を高速(20MHz)で動作させることで、周辺ICの機能をソフトで代行し、チップ数の少ないZ80シングルボードを作ろうと始めた今回の試みですが、CP/Mも快適に動くようになりゴールに近づいてきたので回路図の整理とパターン設計を行ってみました。
全体の概要を改めてまとめてみると
★追記 2020/12/11 {
試作基板評価結果を反映して回路図とパターン図をアップデートしました。
【主な変更点】
}
[TOP] [ 前へ ] 連載記事 [ 次へ ]
全体の概要を改めてまとめてみると
- チップ構成
当初の予定通り、8ピンのICも含めて5チップ構成でCP/Mが快適に動くようになりました。
使用したICは次の通りで、全てDIPパッケージのICです。
- Z80
Z84C0020PEG(40PIN)をクロック上限の20MHzで動作させています。
メモリも下記のように高速なものを使い、wait無しで動作しています。9600bpsの調歩同期式シリアル通信をソフトで実現するために34.7us間隔で割込み処理を実行していることから処理能力は14.516MHz相当になります(今後改善する可能性もある)。
当然ですが、シリアル入力をバックグラウンドでセンスしなければ(タイマー割込みを禁止すれば)20MHz相当のスピードになります。
★変更 2020/12/30
処理能力を16MHz相当に変更。詳細は「Z80GALの構想(その8)Blocking/Deblockingの実装」を参照してください。
- RAM
UM61512-15(32PIN)を使用しました。ピン数が少し多いですが、64Kx8bitのスタティックRAMでアクセスタイムは15nsと高速です。
- EEPROM
W27C512-45(28PIN)でアクセスタイムが45nsでROMではかなり速い方だと思います。Z80のメモリ空間の後半は常にRAMをアクセスできるようにしているので、EEPROMのサイズは64Kx8bitですがZ80のメモリ空間の前半の32KBにマッピングしています。
ジャンパーピンの設定によりメモリ空間にマッピングされるのがどちらか(EEPROMの前半か後半か)を選択可能としました。
メモリライトは常にRAMが対象となり、メモリリードはEEPROMかRAMかをI/Oでコントロールできるようにしています。
- GAL
GAL22V10D(24PIN)を使用しています。詳細は「Z80GALの構想(その2)GALの設計」の記事を参照してください。
- クロック発振&タイマー割込み信号生成
PIC12F683(8PIN)で水晶発振子用バッファとタイマー割込み用のインターバル信号を生成しています。
発振部分は後段に一段バッファを設けたかったのですがICが追加になってしまうので後段バッファは無しにしています(PIC12F683の内蔵コンパレータをバッファにできないか試みましたが20MHzでは利得が落ちて駄目でした)
- Z80
- ソフトで代行した機能
調歩同期式シリアル通信(9600bps)をタイマー割込みを使ってバックグラウンドでの受信センスも含めて実現しています。詳細は「Z80GALの構想(その5)タイマ割込みによるシリアル通信」を参照してください。
また、SDカードとのインターフェースであるSPIインターフェースをソフトウェアにより実現しています。こちらも詳細は「Z80GALの構想(その6)SPIインターフェースの実装」を参照願います。
- 回路図
今後変更する可能性もありますが、現時点での回路図は下図の通りです。
ATF22V10C対応(リセット部の抵抗を10Kから33Kに変更)
★変更 2021/02/05
リセット時の動作の違いはSDカード依存だったのでリセット部抵抗を10Kに戻した
- パターン設計
下図が今回設計した基板のパターン図でトップ面とボトム面を重ねて表示したものです。黄色の細い線はグランドの接続を示していて、グランドをベタパターン化した際に接続されます(接続されない場合はviaを打つ)。
トップとボトムのパターン(ベタグランド化前)
トップ面のグランドをベタパターン化したものが下図です。
今回はMicroSDカードを使って小型化を図りました。SDカードコネクタは秋月さんから購入したヒロセ・マイクロSDカードコネクタを使用しています。
11ピン~14ピン(周囲の淵にあるピン)は未使用ですが強度を高めるために周りをベタパターン化しました。
トップパターン(ベタグランド化後)
下図がボトム面のパターンです。トップ面もそうですが今回はチップ数が多いので結構混雑度の高いパターンになっています。
ボトムパターン(ベタグランド化後)
★追記 2020/12/11 {
試作基板評価結果を反映して回路図とパターン図をアップデートしました。
【主な変更点】
- Versionを0.01aに変更
- microSDの配線を修正
- R7を10Kから1Kに修正
- シルクの日付を修正
- ダイオードの極性が判り易いシルクに変更
- ダイオードを1種類に統一
試作基板(Ver0.01) |
|
}
[TOP] [ 前へ ] 連載記事 [ 次へ ]
Z80GALの構想(その9)簡易モニタの製作(その2)ブレーク機能の実装 [Z80]
「Z80GALの構想(その4)簡易モニタの製作」の記事で書いたように今回はZ80GALに移植したGAME言語を使って作成した簡易モニタを使ってプログラムをダウンロードしディバッグを行いました。
始めからブレーク機能を実装してディバッグに使えば良かったようなものですが、ブレーク機能無しでも今回の開発作業は問題ないと考えていました。
今回のプログラム開発で残りはIPLくらいしかありませんが、実装方法を考えるのが面白そうだったのでブレーク機能を追加してみました。
まずはモニタにおけるテスト対象プログラム実行時に期待する機能として、RET命令でモニタに戻ってきた際のレジスタの値などを確認する使い方と、ブレークポイントを設定して実行プログラムがブレークポイントに到達した時点でのレジスタ内容などを確認したい場合の二通りあるのではないかと思います。
また、いずれの場合もプログラム実行前にはレジスタの値を事前に設定したいものです。
今回は上記の2つの使い方に対応できるようにしました。それぞれの機能について以下に概要を説明します。
下記のサンプルプログラムを用いて、今回追加した機能についての概要を書いてみます。
文字でいろいろ書くよりも操作例を示した方が判り易いと思います。
ブレークを設定後に最初だけ「Gxxxx」コマンドで対象プログラムを実行し、ブレーク後は「G」コマンドで継続して実行しています。
最後にRET命令によりモニタに戻ってきますが、この場合、PCの値が不明(ステップ動作すれば判るようになるがそのためには命令長情報が必要になる)なのでPCの表示値は実行開始のアドレス値を表示するようにしました。
また、今回追加したレジスタ管理機能とブレーク設定/解除機能はいずれもマルチステートメント対応にしているで複数命令を一度に(場合によってはコピペで)実行可能です。
★変更 2011/11/22 操作例をアップデート
このような機能はGAME言語だけでは記述できないので上記の二通りの実行機能(GO:がブレーク用、GOxx:がRET時レジスタ確認用の実行開始モジュール)とモニタへリターン時のレジスタ格納処理(RSTENT:)をアセンブラで記述しました。
先頭のジャンプ命令とワークメモリアドレスはGAME言語とのインターフェース用です。
下のリストが今回機能追加したGAME言語のモニタ(Gamon)のソースです。GAME言語を移植できる環境があるのであれば、モニタの移植も容易だと思います。
★変更 2011/11/19
Ver0.03a "Gxxxx"と"G"の混在使用を可能にしました。
★追記 2024/02/28
GAMON の最新版は「GAME言語で作った簡易モニタ(Gamon)」の記事からダウンロードできます。
[TOP] [ 前へ ] 連載記事 [ 次へ ]
始めからブレーク機能を実装してディバッグに使えば良かったようなものですが、ブレーク機能無しでも今回の開発作業は問題ないと考えていました。
今回のプログラム開発で残りはIPLくらいしかありませんが、実装方法を考えるのが面白そうだったのでブレーク機能を追加してみました。
まずはモニタにおけるテスト対象プログラム実行時に期待する機能として、RET命令でモニタに戻ってきた際のレジスタの値などを確認する使い方と、ブレークポイントを設定して実行プログラムがブレークポイントに到達した時点でのレジスタ内容などを確認したい場合の二通りあるのではないかと思います。
また、いずれの場合もプログラム実行前にはレジスタの値を事前に設定したいものです。
今回は上記の2つの使い方に対応できるようにしました。それぞれの機能について以下に概要を説明します。
- 実行プログラムリターン時のレジスタ確認機能
事前に任意のレジスタの値を設定して指定した番地からプログラムを実行し、RET命令でモニタに戻ってくる。
この場合にスタック上にはモニタへの戻り値を積んだうえで対象プログラムを実行します。
対象プログラムから戻ってきたら、その時点のレジスタを保存し、確認できるようにします。この戻り時の処理は次に述べるブレーク機能と同じ処理になります。
試験プログラムの実行方法としては「Gaaaa」になります(aaaaは開始アドレス)。
- ブレーク機能
試験対象プログラムの複数個所にブレークポイント(今回はRST 30H(F7H)を使用)を設定後、プログラムを実行し、ブレークポイントに達した時点でモニタに戻し、レジスタ内容の確認などができるようにする。
今回はブレークポイントを5個まで設定可能で、ブレークした時点で置き換えたF7Hのコードを元のコードに戻す(ブレークポイントを自動的にクリアする)ことで継続して試験プログラムを実行できるようにしました。
試験プログラムの実行方法はPC(プログラムカウンタ)に実行アドレスを設定後、「G」コマンドで試験対象プログラムを実行します。
下記のサンプルプログラムを用いて、今回追加した機能についての概要を書いてみます。
使用したサンプルプログラム |
---|
8000 32 800F LD (800FH),A 8003 3E 55 LD A,55H 8005 06 11 LD B,11H 8007 CD 8010 CALL 8010H 800A D9 EXX 800B C9 RET 800C 00 NOP 800D 00 NOP 800E 00 NOP 800F 00 NOP 8010 0E 22 LD C,22H 8012 21 1234 LD HL,1234H 8015 C9 RET |
文字でいろいろ書くよりも操作例を示した方が判り易いと思います。
ブレークを設定後に最初だけ「Gxxxx」コマンドで対象プログラムを実行し、ブレーク後は「G」コマンドで継続して実行しています。
最後にRET命令によりモニタに戻ってきますが、この場合、PCの値が不明(ステップ動作すれば判るようになるがそのためには命令長情報が必要になる)なのでPCの表示値は実行開始のアドレス値を表示するようにしました。
また、今回追加したレジスタ管理機能とブレーク設定/解除機能はいずれもマルチステートメント対応にしているで複数命令を一度に(場合によってはコピペで)実行可能です。
モニタでのブレーク操作例(水色:入力部) |
|
★変更 2011/11/22 操作例をアップデート
このような機能はGAME言語だけでは記述できないので上記の二通りの実行機能(GO:がブレーク用、GOxx:がRET時レジスタ確認用の実行開始モジュール)とモニタへリターン時のレジスタ格納処理(RSTENT:)をアセンブラで記述しました。
先頭のジャンプ命令とワークメモリアドレスはGAME言語とのインターフェース用です。
ブレーク処理用のアセンブラ記述部分(Z80アセンブラ) |
|
下のリストが今回機能追加したGAME言語のモニタ(Gamon)のソースです。GAME言語を移植できる環境があるのであれば、モニタの移植も容易だと思います。
Gamon(Game Monitor)ソース(GAME言語) |
|
★変更 2011/11/19
Ver0.03a "Gxxxx"と"G"の混在使用を可能にしました。
★追記 2024/02/28
GAMON の最新版は「GAME言語で作った簡易モニタ(Gamon)」の記事からダウンロードできます。
[TOP] [ 前へ ] 連載記事 [ 次へ ]
Z80GALの構想(その8)Blocking/Deblockingの実装 [Z80]
前回の「Z80GALの構想(その7)hexローダーでのCP/M-80ブート」の記事の最後の方で「Blocking/Deblocking処理を追加してSDアクセスを高速化したい」と書いたように、今回はBlocking/Deblocking処理の実装について書いてみたいと思います。
その前に、前回記事に追記しましたが、"dir *.z"のようにファイルが一致しないdirコマンドで固まる現象が発生することが判明しました。割込み処理で引き継いだスタック上へのpushを無くし、スタックを切りなおすことでこの問題が解消しました。
この為、割込み処理の先頭と末尾にSPストア/リストア等が追加になったことから実行速度が少し遅くなりました。
下表が今回の割込み処理の変更とBlocking/Deblocking処理を追加前後において、いくつかのパターンの処理時間を測定した結果です。
純粋にメモリ上のみの処理のASCIIART.BASの実装速度を16MHzで動作するPic24CPMと比較すると、従来はほぼ同じ速度だったのが、速度が約1割減となり14.5MHz(=16x75/83)相当の速度ということになりました。
SDカードのアクセスはPic24CPMよりも早くなり、全体的にはPic24CPM相当のパフォーマンスと言えるのではないでしょうか?(シリアル通信の速度がPic24CPMは38400bpsでZ80GALは9600bpsなので画面表示はZ80GALの方が遅い)
SPIインターフェースやシリアル通信をソフトで実装した割にはまずまずの結果だと思います。
話をBlocking/Deblocking処理に戻すと、処理自体は「3チップ構成68Kマイコンの構想(その12)Blocking/Deblocking」の記事に書いたものとほぼ同じロジックです。この時はsector read時に無条件にバッファをFlushしていましたが今回はバッファ内にリード対象のデータがある場合にはFlushしないようにしました(この変更による速度的な効果は未確認でほとんど効果は無いと思いますが少しでも速くなるように変更した)
上記の記事の時と同様にSDカードのブロックサイズは512byteでCP/Mのブロックサイズが2Kbyteです。CP/Mのセクタサイズは128byteに固定なのでSDカードの1ブロックリード/ライトで4セクタ分のリード/ライトができるようになります。また、CP/Mの新ブロックへの書込み時にはSDブロックの先読みが4回分省略できます。
動作を確認するために、連続的なリード処理とライト処理のテストプラグラムを作成し、ロジアナで確認しました(ファイルアクセスの直前でポーズ(キー入力)することでディレクトリ処理が観測されないようにしています)。
また、ライト処理は新規に作成したファイルに対しての連続書込みになるようにしています。
今回の変更(Blocking/Deblocking処理の実装と割込み処理の変更)前の確認結果が下図になります。
変更後のロジアナでの確認結果が下図になります。
上図での4回分のリード/ライトがBlocking/Deblocking処理により1回に集約されています。また、新ブロックへの書込みでは想定通り、先読み無しでSDカードへのライト処理のみになっています。
ライト時のデータ送信完了からSDからの応答までの時間が上図よりも短いのはSDカードの応答速度の違いによるものです。
★追記 2020/11/15 {
本確認作業で使用したSDカードは下記になります(いずれもmicroSDです)
・変更前:ShanDian micro SD HC1 8GB
・変更後:SAMSUNG EVO Plus 32GB
}
twitterにポストしたBDS Cでのコンパイル動画付きコメントを貼っておきます。
[TOP] [ 前へ ] 連載記事 [ 次へ ]
その前に、前回記事に追記しましたが、"dir *.z"のようにファイルが一致しないdirコマンドで固まる現象が発生することが判明しました。割込み処理で引き継いだスタック上へのpushを無くし、スタックを切りなおすことでこの問題が解消しました。
この為、割込み処理の先頭と末尾にSPストア/リストア等が追加になったことから実行速度が少し遅くなりました。
下表が今回の割込み処理の変更とBlocking/Deblocking処理を追加前後において、いくつかのパターンの処理時間を測定した結果です。
純粋にメモリ上のみの処理のASCIIART.BASの実装速度を16MHzで動作するPic24CPMと比較すると、従来はほぼ同じ速度だったのが、速度が約1割減となり14.5MHz(=16x75/83)相当の速度ということになりました。
SDカードのアクセスはPic24CPMよりも早くなり、全体的にはPic24CPM相当のパフォーマンスと言えるのではないでしょうか?(シリアル通信の速度がPic24CPMは38400bpsでZ80GALは9600bpsなので画面表示はZ80GALの方が遅い)
SPIインターフェースやシリアル通信をソフトで実装した割にはまずまずの結果だと思います。
|
||||||||||||||||||||||||||||
※1 今回のbiosソースをM80でリストファイル出力付きでアセンブルした際の時間(m80 =bios/l) ※2 hello.cをHiTech Cでコンパイルした場合の時間(c -v hello.c) ★追記 2020/11/29 CP/M側のスタック制限により10%弱遅くなるのはもったいないのでCP/M側のCCP用スタックを拡張してBIOS内の割込み処理ではStackを再設定しないように改善してみた結果を追記しました(improveカラム)。処理速度は16MHz相当に戻りました。 ★追記 2021/10/03 タイマ割込み内のシリアル送受信処理を見直し「push hl」の範囲を最小化することで高速化し、実行時間測定結果を上表のimpeove2のカラムに追記しました。 |
話をBlocking/Deblocking処理に戻すと、処理自体は「3チップ構成68Kマイコンの構想(その12)Blocking/Deblocking」の記事に書いたものとほぼ同じロジックです。この時はsector read時に無条件にバッファをFlushしていましたが今回はバッファ内にリード対象のデータがある場合にはFlushしないようにしました(この変更による速度的な効果は未確認でほとんど効果は無いと思いますが少しでも速くなるように変更した)
上記の記事の時と同様にSDカードのブロックサイズは512byteでCP/Mのブロックサイズが2Kbyteです。CP/Mのセクタサイズは128byteに固定なのでSDカードの1ブロックリード/ライトで4セクタ分のリード/ライトができるようになります。また、CP/Mの新ブロックへの書込み時にはSDブロックの先読みが4回分省略できます。
動作を確認するために、連続的なリード処理とライト処理のテストプラグラムを作成し、ロジアナで確認しました(ファイルアクセスの直前でポーズ(キー入力)することでディレクトリ処理が観測されないようにしています)。
また、ライト処理は新規に作成したファイルに対しての連続書込みになるようにしています。
今回の変更(Blocking/Deblocking処理の実装と割込み処理の変更)前の確認結果が下図になります。
ファイルの連続リード処理(変更前) |
|
ファイルの連続ライト処理(変更前) |
|
変更後のロジアナでの確認結果が下図になります。
上図での4回分のリード/ライトがBlocking/Deblocking処理により1回に集約されています。また、新ブロックへの書込みでは想定通り、先読み無しでSDカードへのライト処理のみになっています。
ライト時のデータ送信完了からSDからの応答までの時間が上図よりも短いのはSDカードの応答速度の違いによるものです。
★追記 2020/11/15 {
本確認作業で使用したSDカードは下記になります(いずれもmicroSDです)
・変更前:ShanDian micro SD HC1 8GB
・変更後:SAMSUNG EVO Plus 32GB
}
ファイルの連続リード処理(変更後) |
|
ファイルの連続ライト処理(変更後) |
|
twitterにポストしたBDS Cでのコンパイル動画付きコメントを貼っておきます。
GALを使ったZ80ボードを構想中
— skyriver (@wcinp) November 15, 2020
ソフト実装のSPIではSDカードのアクセスが遅いのでCP/MのBlocking/Deblocking処理を実装し、SDアクセスが違和感がないくらい速くなった
BDS Cのコンパイルも爆速で完了します^^https://t.co/8kcLcFLiia#Z80GAL #CPM80 #BlockingDeblocking #BdsC pic.twitter.com/Xeht27hkct
[TOP] [ 前へ ] 連載記事 [ 次へ ]
Z80GALの構想(その7)hexローダーでのCP/M-80ブート [Z80]
前々回の記事でタイマ割込みによるシリアル通信を実装し、前回の記事でSDカードのアクセスに必要なSPIインターフェースを実装したので今回はいよいよCP/M-80の移植です。
いままで検討してきたZ80GAL基板は想定通り、Z80:Z84C0020PEG(40PIN)、RAM:UM61512-15(32PIN)、EEPROM:W24C512-45Z(28PIN)、GAL:GAL22V10D(24PIN)、クロック&タイマ:PIC12F683(8PIN)の5チップ構成で仕上がりそうです。
CP/M-80の起動画面が下図です。
hexローダーでCP/M本体とBIOSをロード後、BIOSの先頭(boot)を実行することでCP/Mが起動しています。(^^)/
久々にHI-TECH Cでコンパイルした際の画面です。「-v」オプションで詳細表示指定しています。
しかし、今回のCP/Mの移植はいつもより、少し手間取りました・・ ^^;
他の人の参考になるかもしれないので発生した主要な問題を二つ書いておきます。
以上が、Z80GALへCP/M-80を移植した際に発生した問題の簡単なメモになります。
今回のソフトによるSPIインターフェスでのSDカードのアクセスはできるだけ高速化したつもりですが、Pic24CPMと比較して体感上はSDアクセスが倍以上遅く感じます(^Cでのシステム+ディレクトリ読込みで2秒程度時間が掛かる)。
Pic24CPMでは例えばSDリード時はPICでアクセスしたデータをZ80に引き渡し、更にDMA領域に転送していたので(Z80GALでは直にDMA領域への読込み)もう少し速くなると期待していたのですが・・
CP/Mのメモリサイズも62KBになったのでBlocking/Deblocking処理を追加してSDアクセスを高速化したいと思います。
因みにタイマ割込み処理は34.7us間隔で割込み処理時間は約7us程度(シリアル通信状態にも依存)なので
20MHz x (35 - 7) / 35) = 16MHz
のクロック相当の処理速度です。Pic24CPMのクロックが丁度16MHzなのでASCIIART.BASを並べて実行してみたところ、見た目上はまったく同じ速度でした。
[TOP] [ 前へ ] 連載記事 [ 次へ ]
いままで検討してきたZ80GAL基板は想定通り、Z80:Z84C0020PEG(40PIN)、RAM:UM61512-15(32PIN)、EEPROM:W24C512-45Z(28PIN)、GAL:GAL22V10D(24PIN)、クロック&タイマ:PIC12F683(8PIN)の5チップ構成で仕上がりそうです。
CP/M-80の起動画面が下図です。
hexローダーでCP/M本体とBIOSをロード後、BIOSの先頭(boot)を実行することでCP/Mが起動しています。(^^)/
Z80GALでのCP/M-80起動画面 |
|
久々にHI-TECH Cでコンパイルした際の画面です。「-v」オプションで詳細表示指定しています。
HI-TECH Cでのコンパイル |
|
しかし、今回のCP/Mの移植はいつもより、少し手間取りました・・ ^^;
他の人の参考になるかもしれないので発生した主要な問題を二つ書いておきます。
- M80/L80で作成したCOMファイルの問題
アセンブラ/リンカはMACRO-80(M80/L80)を使っていて、DOS窓でCPMエミュレータで動かしています。生成したcomファイルは開始アドレスを指定してhexファイルに変換後、モニタでZ80GAL内のメモリにダウンロードしています。
開始アドレスを指定できるHEXファイル変換ツールが見当たらなかったので簡易的なツールを自作しました(「Z80GALの構想(その4)簡易モニタの製作」の記事の末尾に追記して公開しました)
今回は割込み処理、SPIインターフェース及びSDカード初期化等もあるので64KBのCP/MではBIOS領域が足りず、CP/Mを62KBサイズにしているのでBIOSは0F200Hから始まります。
COMファイルを生成するために先頭で「ORG 0100H」で宣言後、.phaseステートメントを使って実アドレスを指定しているのですが、.dephaseして、再度.phaseした際に生成されるcomファイルが16バイト欠落する問題が発生しました。
アドレス再指定部分のソースは下記のとおりです。
0020 RBUFSZ EQU 32 FFE0 RBUFMSK EQU NOT (RBUFSZ - 1) F6C0 RBufAd EQU ($ + RBUFSZ -1) AND RBUFMSK .DEPHASE .PHASE RBuFAd F6C0 RBuf: DS RBUFSZ ; ;Drive A B C D .. K L F6E0 drvtbl: dtbl <dpha,dphb,dphc,dphd,dphe,,,,,,,> F6E0 F74B + dw dpha F6E2 F75B + dw dphb
下図が生成されたcomファイルをバイナリエディタで確認した結果です。
comファイル内コードの開始アドレスは0F200Hなので「drvtbl」が04E0H(=0F6E0H-0F200H)に配置されるはずなのに下図のように04D0Hに配置されてしまっています。orz
04C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04D0 4B F7 5B F7 6B F7 7B F7 8B F7 00 00 00 00 00 00 04E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
この問題は下記のようにして回避できました(その他の変更箇所もあるので上記のものとアドレスは異なっています)。
0020 RBUFSZ EQU 32 FFE0 RBUFMSK EQU NOT (RBUFSZ - 1) F6E0 RBufAd EQU ($ + RBUFSZ - 1) AND RBUFMSK ; .DEPHASE ; .PHASE RBuFAd F6D2 DS RBufAd - $ F6E0 RBuf: DS RBUFSZ
今回のディバッグスタイルはブレークなどは使わず、机上ディバッグがメインなのでこの手の問題が発生すると手こずります^^;
- CP/M-80の割込み用スタックの制限
Z80GAL用のBIOSを書き上げてCP/Mを起動するとdirコマンド終了後にwboot内のシステムを読込み処理が走った後ディレクトリセクタの読込みが走る(固まる場合もある)現象が発生しました。
他の動作は問題無いように見え、"dir"だけがおかしな状態です。BIOSのソースをいくら確認してもおかしな箇所は見当たらないので、コンソール入出力を初期に作った割込みを使わないものに変えてみたところ"dir"が正常に動作しました。
割込み処理によるスタックの問題と思いdirコマンド実施時に実行されるであろうBIOS内の「READ」や「CONOUT」等の処理を確認し、「READ」処理内のPUSH BC,DE,HLを削除しても状況は変わりませんでした(CONOUTではPUSHは1つだけ)
タイマ割込み処理ではPUSHは2個(AFとHL)だけでしたが少し遅くなりますがHLをメモリ変数に退避したところ、問題が解消しました。
CCP内でのdirコマンド処理からのBIOSコール時ではなく、dirコマンド処理内自体でスタックが溢れていたようです。
ネット情報をざっと調べましたが、CP/M-80実装時における割込み処理のスタック数についての情報は見当たりませんでした(どこかにあるのかも)。
割込み処理内では"PUSH AF"以外はレジスタをメモリ上の変数に保存するか、スタックを切りなおしてPUSH/POPした方がいいようです。
★追記 2020/11/15 {
"dir *.z"等のようにどのファイルにもヒットしないワイルドカードでのdirコマンドで固まる現象が発生しました。
割込み処理内で引き継いだスタックへの"PUSH"を無くし、スタックを切り直してから"PUSH"することで問題が解消しました。
上の記載では割込み処理内で1段だけはスタックを使用しても問題ないようなことを書きましたが割込み処理内ではスタックを切りなおしてPUSH/POPした方がいいようです("CALL"でスタックを使用する場合も同様)
}
因みにCCPがコマンド内容を処理する際のスタック領域は下記のように8段しか確保されていないようです。
E386 CD66E0 GETBACK CALL RESETDR ;reset previous drive. E389 CD5EDE GETBACK1:CALL CONVFST ;convert first name in (FCB). E38C 3ACEE3 LDA FCB+1 ;if this was just a drive change request, E38F D620 SUI ' ' ;make sure it was valid. E391 21F0E3 LXI H,CHGDRV E394 B6 ORA M E395 C209DE JNZ SYNERR E398 C382DF JMP CMMND1 ;ok, return to command level. ; ; ccp stack area. ; E39B 0000000000 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 E3AB = CCPSTACK:EQU $ ;end of ccp stack area.
以上が、Z80GALへCP/M-80を移植した際に発生した問題の簡単なメモになります。
今回のソフトによるSPIインターフェスでのSDカードのアクセスはできるだけ高速化したつもりですが、Pic24CPMと比較して体感上はSDアクセスが倍以上遅く感じます(^Cでのシステム+ディレクトリ読込みで2秒程度時間が掛かる)。
Pic24CPMでは例えばSDリード時はPICでアクセスしたデータをZ80に引き渡し、更にDMA領域に転送していたので(Z80GALでは直にDMA領域への読込み)もう少し速くなると期待していたのですが・・
CP/Mのメモリサイズも62KBになったのでBlocking/Deblocking処理を追加してSDアクセスを高速化したいと思います。
因みにタイマ割込み処理は34.7us間隔で割込み処理時間は約7us程度(シリアル通信状態にも依存)なので
20MHz x (35 - 7) / 35) = 16MHz
のクロック相当の処理速度です。Pic24CPMのクロックが丁度16MHzなのでASCIIART.BASを並べて実行してみたところ、見た目上はまったく同じ速度でした。
[TOP] [ 前へ ] 連載記事 [ 次へ ]