Z80,000やZ80320と同じように入手を諦めていたのですが、たまたまネットで見つけ、ちょっと高価でしたが購入してしまいました。
このCPUはかなり高機能で、以下のような特徴があります。
- 32本の32bit汎用レジスタ
- 浮動小数点演算命令
- V20/V30エミュレーション
- デマンドページングをサポートできるMMU
Z80,000やZ80320と同じように入手を諦めていたのですが、たまたまネットで見つけ、ちょっと高価でしたが購入してしまいました。
このCPUはかなり高機能で、以下のような特徴があります。
新しくZ8001CPUボードを作製しました。今までは、ラッピングワイヤを直接はんだ付けして配線していましたが、今回初めて、ユニバーサル基板にピンヘッダをたてワイヤラッピングで配線してみました。この方法は、ピンヘッダとICソケットとの間を配線するのが単調で根気がいります。とくにPLCCソケットは苦痛でした。ラッピングでの配線はやっていて楽しいのですが、間違いに気づいたときは修正が大変です。ほどきたい配線の上にすでに配線されていると、それもほどかないといけません。一度ほどくとワイヤが傷んでしまっているので、2回目巻きなおすと折れたりするので気を使います。年で眼も弱ってきているので、そろそろPCBが作れるようにならないとだめですね。
今回のボードは、MMUを搭載しCP/M-8000以外のOSも移植することを考えています。初代のボードでは、Z8010 MMUを使ってメモリー管理ができるように考えていたのですが、何故かうまく動作せず。結局、CPLDでセグメントアドレスを変換するロジックを組んで、CP/M-8000が動作するようにしました。しかし、この方法ではアドレス変換が固定で融通が利かず、CP/M-8000以外のOSを動かすのは難しくなります。
新しいボードでは、Z8010を使うことは諦めて、MMUを自前で組むことにしました。これに先立って、Z8002 CPUを使ったボードで、MMUを自作できそうか簡単な回路を組んで試してあったのですが、実際に作ってみると配線量の多さからかなり苦戦しました。MMU以外は、最初のボードとほぼ同じです。
自作MMUの仕様は下のようになっています。
こんなものを試す人はかなりのハッカー基質の人だと思い、Githubの説明はあまり親切でないのと、英語があまりにひどいので、CP/M-8000を起動させるための補足をしておきます。
準備
作業はDebian系のディストリビューションで行うことを想定しています。ATMEGAのコードをビルドし書き込むために、gcc-avr, avr-libc, avrdude をインストールしておきます。Z8000のコードをアセンブルするために、GNUのサイトからbinutils をダウンロードして、 Z8001クロス開発環境 binutilsをビルドしてみるを参考にビルドしてください。私が確認しているは使っているのは、binutils-2.34 です。
ATMEGA164のヒューズビット設定
Z8001MBと同じくZ8K CP/Mでは、Z8001を起動するためにATMEGA164Pが使われていますが、JTAGの禁止と外部クロック入力にするためヒューズビットの書き換えが必要です。値は、LFUSE : 0xE0, HFUSE : 0xD9 です。ATmega164PのJTAGを禁止するを参照し、avrdudeを使って書き換えてください。
マシンモニタの書き込み
z8kboot ディレクトリでmakeを実行してください。z8kbooter.elf が作られます。 チップへの書き込みは、make write で実行できます。
CP/M-8000のビルド
COFFに変換済みのcpmsys.o と libcpm.a が入れてあるので、cpm8kディレクトリで、makeするだけです。cpm8k.bin が作られます。
CP/M-8000のディスクイメージの作成
cpmtoolsをインストールし、/etc/cpmtools/diskdefsにcpm8kディレクトリにあるdiskdefsを追加します。diska/b/c/d ディレクトリにディスクイメージに含めたいファイルを入れて、make dskimg を実行します。disk.img ができるので、dd でCFに書き込めばOKのはずです。ディスクイメージに入れるCP/M-8000のコマンド類は、 http://www.cpm.z80.de/download/cpm8k11.zip を解凍すると得られるDISKn.ZIPに含まれています。
こんな状況になると予想しておらず、慌てて書いたので間違っているかもしれません。
私がGithubにあげているZ8001MBの回路図をもとに、tomi9さんがCP/M-8000を動作させることができるPCBを作成され、一枚送ってくださいました。
PCBだけでなくCFのソケットとGALも同封されており、あとは手持ちの部品だけで行ける状態でした。tomi9さん、ありがとうございます。自分もいつかはPCBを作ってみたいとは思っているのですが、なかなか勇気が出ません。ラッピングワイヤーでの手配線だと、すぐに回路の修正がききますが、PCBだとそう簡単にはできません。
久しぶり(中学高の技術の授業以来?)のPCBでの組み立てで、ちょっと一投目は緊張しましたが、最難関のCFソケットのはんだ付けを済ませ、Z8536以外の部品を組みつけて、現在、動かせるところまで来ています。
前回、Z280MBのこれ以上の高速化はやめておくと心に決めていたのですが、なにか釈然としないのと、ASCIIARTの実行速度を収集?しているはせりんさんからのリクエストもあり、外部クロックの12MHz化を試してみることにしました。
難しいというか面倒なのは、外部クロックを変更できるのが、リセット時にハードウェア的にのみできるということです。実際には、
リセット回路にCRディレイ回路を付け足したのと、写真の赤線で囲んだところに、AD0-AD7に初期化データが乗せられるようにDIPスイッチとバッファが付け足してあります。
実行結果は、外部クロック6MHzから30秒ほど縮めて、1分33秒まで高速化できました。まあこれなら納得できます。
Z280MBにCP/Mを移植できたので、この界隈で試す人の多いASCIIARTを試してみました。
結果は、キャッシュONで2分38秒、キャッシュOFFで5分11秒でした。結果をTwitterにあげたところ、Electrelicさんからリフレッシュを止めるともうちょっと速くなるとアドバイスをもらい試したところ、2分8秒まで改善しました。Z280MBはDRAMを使っていないので、リフレッシュは不要なのですが、こんなにリフレッシュサイクルが負荷になるとは思ってもいませんでした。
参考にさせてもらったElectrelicさんの記事はこちらです。Z280固有の初期化(その1)
結果は、はせりんさん 番外編:ASCIIART(マンデルブロ集合)ベンチマーク に掲載されたのですが、他のZ80系CPUに比べてお世辞にも速いとは言えません。同じクロックだと、確実に高速版Z80やHD64180に負けるでしょうし、キャッシュOFFの結果は悲惨です。
これ以上の高速化は、外部バスクロックの12MHz化とバーストモードを使うことが必要ですが、ハードウェアの改造や新規設計が必要になるのでやめておきます。
Z280には、ユーザ/システムの分離とか仮想メモリが可能なMMUとかI/D分離とか、他にも面白い機能があるので、浪漫あふれた古の石ということで良いのではないでしょうか。
CP/Mの次はFUZIXを移植してみたいと思っています。
ここしばらく、Z280MB に CP/M を移植していました。移植したバージョンは 2.2 です。EDでコードを書きASMでアセンブルできることを確認しています。
CP/M-8000 の移植は経験済みだったので、大して難しくないのかなと思っていたのですが、ディスクアクセス周りで苦戦して結構時間がかかってしまいました。かなり悩んだすえ、結局使っていたコンパクトフラッシュカードの問題だったようなのですが、おかげで、8-bit から16-bit PIOモードにコードを書き換えたりできたので良しとします。ディスクアクセスのブロッキング・デブロッキングは思いっきり手抜きです。気が向いたら書き換えることにします。
CP/M-8000と違って、CCPがコマンドで上書きされたり、メモリーの配置が全然違ったりで最初とまどったのですが、ネット上に情報が豊富にあり助けられました。今回の移植作業で、参考にしたサイトを上げておきます。
BIOSの作成過程が楽しく詳しく語られています。非常に参考になりました。
CP/M-8000のときも参考にさせてもらいました。CP/Mど素人の私にはありがたいサイトです。
コンパクトフラッシュをつなぐのに参考にさせてもらっています。
移植の成果は、Github にあげておきました。CP/Mのライセンスの関係でBIOSのソースコードのみを上げることにしました。BIOSをアセンブルし、できたバイナリをCPM.SYSと結合するMakefileとディスクイメージを作るシェルスクリプトを入れておきました。
Z280MBにCFカードを接続できるように拡張しました。Z8002MBで作ったIDEインターフェースボードをそのまま流用し、その先にIDE-CF変換アダプタを接続しています。
CFカードのセクター読み書きができることは確認できているので、まずはCP/Mを移植してみようと思っています。
ハードウェアは一段落したので、GitHubに回路図を上げておきました。これを見て作ろうとする酔狂な人はいないとおもいますが。
Z280 MPU Boardは、はんだ不良などでかなり苦戦していたのですが、安定して動作するようになりました。
現在は簡単なマシン語モニタが動作しています。
GWを目一杯使って、Z280ボードを組み立てました。
16bit CPUは配線量が多く、老眼が進んできている自分にはかなりきついです。特にPLCCソケットのピンへのはんだ付けは、線同士が重なるので見づらくて正直あまり好きではありません。よく順番を考えながらはんだ付けしていかないと、あとで後悔します。白のラッピングワイヤがデータバス、オレンジがアドレスバス、青がバス制御とその他の信号ラインです。
このMPUボードは、CPUクロックが12MHz、SRAMが256kバイト、EEPROMが16kバイトの構成です。ROMは実際には2Mビット×2なのですが、そんなにもいらないので、16kバイト分だけ使えるようにしてあります。リセット直後は、64kバイトのメモリ空間にはROMしか現れず、MMUをつかってアドレス上位に置かれているSRAMをマッピングして使えるようにします。
現状では、UARTから”hello world"が出力できているレベルで、MMUなどの確認はできていません。回路図は動作が確認できたら公開するつもりです。
Z280のクロックは少し複雑です。チップからは、XTALI, XTALO, CLK の3本もクロック関係のピンが出ています。
Z280は内部にクロックオシレータを持っており、水晶振動子をXTALIとXTALOにつなぐか、XTALIに外部からクロック信号を入れると動作することになっています。内蔵オシレータからのクロックは1/2に分周され、CPUクロックになります。今手持ちのCPUは12MHz品なので、クロックは24MHzまで入れることができます。
外部バスのクロックは、CPUクロックを更に1/2, 1/4分周にすることができ、CLKピンから出力されます。デフォルトでリセット後は1/2にセットされるのですが、この分周比は、データシートによるとソフトウェアからでは変更できません。
これは、アクセススピードが遅いメモリやI/Oを接続することを考慮したものなのでしょうが、Z280を最速で動かすには、バスクロックをCPUクロックと同一にする必要があります。厄介なことに、この分周比を変更できるのは、リセット時にデータバス経由で値を渡す方法だけのようです。
Z8000へのPCC移植がちょっと行き詰まってしまい、気分転換にはんだ付けがしたくなってきました。今回の目標はZilog の Z280を動かすことです。
この石は中国から購入したのですが、ほんまもんなのかがわかりません。時間かけたあげく無駄に終わる可能性もあります。前回のZ8002も中国から購入したのですが、(本当に10MHz品かは別として)こちらは動作しました。偽物を掴まされてたとしても、それはそれで楽しいので、手をつけてみます。
Z280は、Z80とコードレベルで互換性がある16bit CPUです。単純にCPUなわけではなく、MMUやDMA、タイマ、シリアルポートなどを集積したかなり豪華な構成になっています。メモリスペースはMMUを通して、64kByteから16MByteまで拡張されています。外部バスは、16bitのZ-BUSモードか8bitのZ80 Busを選べるようになっています。
もちろん、Z280の性能を活かし切るにはZ-BUSで使うことになるのですが、配線量が増えるし、偽物だったときの精神的ショックを抑えるため、まずはZ80 Busで動かしてみたいと思います。
Z8530 SCCを制御するコードも上げておきます。
先ずは初期化のコードです。送受信の割り込みが処理できるように初期化しています。この石もかなり曲者で初期化手順を間違うとうまく動きません。
発生させる割り込み込みベクタは0x10からで、チャンネルAの送信が0x18で、受信が0x1cになります。
.equ SCCAC, 0x0009 .equ SCCAD, 0x000D init_scc: ld r2, #(scccmde - scccmds) ! initialize Z8530 ld r3, #SCCAC ld r4, #scccmds otirb @r3, @r4, r2 ret scccmds: .byte 9, 0xc0 ! Reset .byte 4, 0x44 ! x16, 1stop-bit, non-parity .byte 3, 0xe0 ! Receive 8bit/char, rts auto .byte 5, 0xe2 ! Send 8bit/char, dtr rts .byte 2, 0x10 ! Interrupt vector .byte 1, 0x12 ! Interruprt on Rx All character and Tx Int .byte 9, 0x09 ! MIE, VIS, Status=Low .byte 11, 0x50 ! BG use for receiver and transmiter .byte 12, 30 ! 4800bps at 5MHz clock .byte 13, 00 .byte 14, 0x02 ! PCLK for BG .byte 14, 0x03 ! BG enable .byte 3, 0xe1 ! Receiver enable .byte 5, 0xea ! Transmiter enable scccmde:
割り込みハンドラーは、次のようなコードです。リングバッファ処理部分は端折ってあります。Z8536と同じで割り込み処理の終了処理を正しく行わないと、優先順位の低い割り込みがかからなくなったりします。
scc_rxint: ! Rx InterruptHandler push @r15, r0 push @r15, r1 1: inb rl0, #SCCAC andb rl0, #0x01 jr z, 1b inb rh0, #SCCAD ! Read a data from Rx buffer ! ! ldb rl0, #0x38 ! Enable IUS outb #SCCAC, rl0 pop r1, @r15 pop r0, @r15 iret scc_txint: ! Tx Interrupt Handler push @r15, r0 push @r15, r1 ! ! outb #SCCAD, rl0 ! Write a data to Tx buffer ldb rl0, #0x28 ! Clear Tx interrupt pendinng outb #SCCAC, rl0 ldb rl0, #0x38 ! Enable IUS outb #SCCAC, rl0 pop r1, @r15 pop r0, @r15 iret
Z8536の初期化手順と割込み処理のメモです。カウンタタイマ3で10mS周期の割り込みをかけます。
Z8536にはRESETピンがなく、ハードウェアリセットはRDピンとWRピンを同時にLにすることで行います。今回はハードウェアを手抜きしているので、ソフトウェアでリセットしています。A0, A1ピンをHにしてリードし、つづいて、レジスタ0に1を書き込んだのちレジスタ0に0を書き込みます。これで初期化されます。
レジスタのアクセスは、A0, A1ピンをHにしアクセスするレジスタ番号を書き込み、つづいて目的のレジスタに書き込みか読み込みをします。Z8536を初期化するのにレジスタ設定の順番を変えたりすると、なぜか動かなくなったりします。正しい手順はよく理解できていないのですが、手探りで見つけた手順が下のコードです。
.equ CIOPRTC, 0x0011 .equ CIOPRTB, 0x0015 .equ CIOPRTA, 0x0019 .equ CIOCTRL, 0x001d init_cio: ld r1, #CIOCTRL inb rl0, #CIOCTRL lda r2, ciocmds ld r3, #(ciocmde - ciocmds) otirb @r1, @r2, r3 ret ciointr: push @r15, r0 ! レジスタ保存 push @r15, r1 ! 割り込み処理 ! ! ldb rl0, #0x0c outb #CIOCTRL, rl0 ldb rl0, #0x24 outb #CIOCTRL, rl0 ! Clear IP and IUS pop r1, @r15 ! レジスタ復帰 pop r0, @r15 iret !------------------------------------------------------------------------------ ciocmds: .byte 0x00, 0x01 ! Reset .byte 0x00, 0x00 ! Clear reset .byte 0x01, 0x00 ! Reset PortC and C/T3 .byte 0x01, 0x10 ! Enable PortC and C/T3 .byte 0x1e, 0xc2 ! Continuous, Ext Output, Square wave .byte 0x1a, 0x30 ! Set timer constant .byte 0x1b, 0xd4 ! Set timer constant .byte 0x00, 0x84 ! MIE and VIS .byte 0x04, 0x00 ! Set Interupt vector .byte 0x0c, 0xc0 ! Set Interupt Enable bit .byte 0x0c, 0x06 ! Gate and Triger ciocmde:
割り込み処理は、最後にレジスタ12のIPとIUSをクリアして戻れば、続けて割り込みが発生します。これを忘れると、割り込みが単発になったり、他のチップからの割り込みが発生しなくなります。
Z8530もそうでしたが、Zilogの周辺チップはプログラムが難しい印象です。さらにデータシートが不親切で、読んだだけでは理解できないことが多々あります。ネット上にもあまり情報がないので、手探りがで動かすことになるのですが、動いた時の高揚感は格別です。
IOREQ = ST0 # !ST1 # ST2 # ST3; DI = !ST3; MMUSEL = !A15 # !A14 # IOREQ; MAPSEL = MMUENA & MMUSEL; MMUBUFE = MMUSEL # DS; MAPRD = (MMUSEL # !RW # DS) & !IOREQ; MAPWR = MMUSEL # RW # DS;
I/O Addr | N/S | D/I | Page No. |
C001 | S | I | 0 |
: | : | : | : |
C01F | S | I | F |
C021 | N | I | 0 |
: | : | : | : |
C03F | N | I | F |
C041 | S | D | 0 |
: | : | : | : |
C05F | S | D | F |
C061 | N | D | 0 |
: | : | : | : |
C07F | N | D | F |