2020年4月29日水曜日

CP/M-8000の移植とその先へ

暫くCP/M-8000のBIOSを書いていたのですが、ほぼ終わりました。
現在、CFに書き込んだCP/Mのディスクイメージから起動できるようになっています。コマンドも実行可能で、下はSTATを実行した例です。


CP/Mのことをほとんど知らないのに移植に挑んだのが原因ですが、Disk I/Oの部分を書くのにかなり手間取りました。いかに役に立ったサイトのリンクを載せておきます。
  • John Elliott氏のCP/M Main Page : CP/M全般の情報が集められています。ファイルシステムの構造やBIOSの情報が役に立ちました。
  • Grant Searle氏のGrant's homebuilt electronics : CP/MのドライブをCFに対応させるアイデアや、ディスクフォーマットの決め方を参考にさせてもらいました。その他の情報も盛りだくさんです。
  • neko Javaさん?のCP/Mコーナー : CP/Mのディスクイメージの作成方法の情報があります。

ここまでで「CP/M-8000の移植はできた」と言っていいとは思うのですが、実は問題があります。トランジェントコマンドの多くが、インストラクションとデータのメモリ空間が分けられるハードウェアを要求することです。
Z8001は8MBのアドレス空間を持ってはいますが、64kBのセグメントに分割されています。コマンドはノンセグメンテッドのコードで書かれているため、利用できるメモリー空間が64kBに制限されてしまいます。それを補うためインストラクションとデータとを別々の空間に置き、128kBまで扱えるようにしているのです。

今回作ったCPUボードでは空間の分離には対応していないので、殆どのコマンドが実行できません。EDやASすら実行できなので、テキストを入力してアセンブルすることすらできず正直何もできません。

動かないコマンドがあることは、移植を開始した早い段階で気づいていましたが、「移植できるのか」という技術的なことにしか興味がなかったので目をつむっていました。せっかくここまで来たので、ハードウェアを改造してインストラクションとデータ空間を分けられるようにしていきます。

2020年4月19日日曜日

CP/M-8000 目覚める

ここ暫くCP/M-8000のBIOSの実装を続けてきたのですが、やっとプロンプトが表示されるところまで来ました。まだプロンプトの表示が変で、謎の"1#"が表示されてはいますが、ビルトインコマンドをタイプすると実行できることを確認できました。
完全にBIOSが実装できておらず、特にディスクI/Oがまだ未実装なので何もできませんが、ゴールデンウィークを中に実装を進めるつもりです。


The Unofficial CP/M Web site には、「CP/M-8000を移植するには、CP/Mが動作するOlibetti-M20上でビルドすることを検討しろ」と書かれていたのですが、オブジェクトファイルをCOFFに変換するツールができたことで、LinuxやWindows上でクロス開発できるようになりました。LinuxやWindows上では高機能な開発環境が使えるので、作業がかなり楽になります。
このあと、私以外にCP/M-8000を移植しようとする人が現れるのかはわかりませんが、ものずきな人のために情報をまとめて公開していくつもりです。

2020年3月14日土曜日

XOUT to COFF 変換

ここ暫く作業を続けていた、CP/M-8000のXOUTファイルをCOFFに変換するツールができたので、まとめてGitHubで公開することにします。

xoutulis (GitHub)

当初、いつものようにCで書いていたのですが途中で行き詰ってしまい、気分転換と自分の勉強を兼ねてGoで書き直しました。Goでかいた最初のアプリになるので、かなり変なことをしているかもしれませんが、とりあえず動きます。

公開するツールは、XOUTからCOFFに変換する xout2coff と、ライブラリファイルをXOUTファイルに分割する xarch です。

使い方は単純で、GOPATHをxoututils/ に通して、そのディレクトリで、
$ go build xout2coff
$ go build xarch
とコマンドを打つと、それぞれビルドされて xoututils/ にコマンドができます。
$ xarch libXXX.a
で、ライブラリの展開。

$ xout2coff XXX.rel
で、COFFへのファイル変換ができます。

これで、CP/M-8000をLinuxやWindows上でクロス開発できるようになりました。今はOlivetti M20用のBIOSを読んで、自作Z8001ボード用に書き直す作業に入っています。

2019年11月4日月曜日

ATmega164PのJTAGを禁止する

初期状態のATmega164PのPC2 - PC5 は、JTAGに割り当てられているため、そのままでは入出力に使えません。これらのピンを入出力で使うには、JTAGを禁止する必要があります。
ネット上ではソフト的に禁止する方法が見つかるのですが、試したてみたものの、うまく行きませんでした。

ハード的にJTAGを禁止するには、ヒューズビットの上位バイトのbit6を1に書き換えます。
私の手持ちの石の上位バイトは0x99でしたので、これを0xD9に書き換えます。
AVR ISP mkIIを使ってavrdudeで書き換える場合だと、
avrdude -c avrisp2 -P usb -p m164p -U hfuse:w:0xD9:m 

ヒューズビットの設定を間違えると最悪起動しなくなることもあるので、注意が必要です。

2019年10月23日水曜日

Z8k-COFF フォーマット 3

リロケーション情報

Z8k-COFFで拡張され、offsetとstuffが追加されている。
変数名はBFDのコードに合わせたが、用途は不明。
リロケーション情報は、r_vaddrが昇順になるよう並べないと、リンカがsegmentation fault を起こす。

 r_vaddr  (4 bytes)
  リロケーションを行う箇所のセクション先頭からのアドレス。

 r_symndx (4 bytes)
 シンボル番号


 offset (4 bytes)
 オフセット+シンボル中の e_value が、リロケーションを行う箇所の値になる。

 r_type (2 bytes)
 アドレスのタイプ。確認できているのは次の6種類。
 外部シンボルをPC相対で参照するケースがあるのか分からないが、
 アセンブリ言語でコードを書いてobjdumpで確認すると、これらのタイプが使われている。
 内部シンボルへのPC相対アドレスは解決できるので、リロケーション情報にはない。 
 16bitの短縮セグメントアドレスがあるかは不明。

 0x01 - 16bit オフセットアドレス (ノンセグメント)
 0x02 - 8bit PC相対 ( JR )
 0x04 - 16bit PC相対 (LDA, LDAR)
 0x05 - 12bit PC相対 ( CALR )
 0x11 - 32bit セグメントアドレス
 0x25 - 7bit PC相対 ( DJNZ )

 セクションデータ中のr_vaddrが指すアドレスには、各r_typeごとに次の値が書き込まれている。 
 
 0x01 : セクション先頭からの16 bitアドレス 
 0x02 : セクション先頭を指すPC相対アドレス (v_addrが指す次のアドレスが基点)
 0x04 : 0x0000が書かれている。
 0x05 : セクション先頭を指すPC相対アドレス (v_addrが指すアドレスが基点)
 0x11 : セクション先頭からのセグメント形式でない32bitアドレス
 0x25 : 何を指しているのか不明 

 stuff (2 bytes)
 不明 0x5343 "SC" が書かれている。

XOUTとCOFFの両フォーマットがなんとなく理解できたので、これで先に進めます。
まずはシンボルテーブルあたりから変換できそうか試してみるつもりです。

Z8k-COFF フォーマット 2

シンボルテーブル

シンボルが定義されたテーブル。
シンボル値は、シンボルクラスによって意味が変わったりするので複雑。

 e.e_name 
 シンボルネーム。8文字に満たない場合は、残りを0で埋められている。
 8文字の場合は、0で終端していない。
 先頭の4byteが0の場合、次の4byteは文字列テーブルへのオフセットになっている。

 e_value
 シンボルの値。e_scnume_typeによって意味が変わる。

 e_scnum
 シンボルが属しているセクション番号。セクションテーブルの先頭セクションは1になるので注意。
 0以下の値は特別の意味を持つ

  0 : 外部シンボル
 -1 : 即値 アセンブラで .equ 定義した値など、再配置で変化しない値
 -2 :  デバッギングシンボル

 e_type
 シンボルの型を表すことになっているが、オブジェクトファイルを見ると何故かいつも0x0000。
 実行ファイルには、何か値が入っている。
 e_sclass
 シンボルクラス。 DJGPP COFF SPEC の Symbol Table を参照 

 e_numaux
 現在のエントリに続く、補助エントリの数。シンボルクラスに応じて補助エントリの内容が変わる。

補助エントリ
 セクションクラスがファイル名とセクション定義の補助エントリは確認されるが、その他は不明。
 逆アセのスス乂の5.5.5 補助形式5:セクション定義を参照。

文字列テーブル

シンボルテーブルの後に続く、0で終端された文字列の配列。長いシンボル名などが収められる。
先頭4byteは、このテーブルのサイズ(先頭4byteを含む)。

2019年10月22日火曜日

Z8k-COFF フォーマット 1

つづいてZ8k-COFF

COFFの資料はネット上にいくらでも転がっているので、理解は楽だろうと踏んでいたのですが、x86のものや、WidowsのPEフォーマットのものばかりで、Z8000のCPU依存に関する情報はほとんどありません。
それでも基本構造は同じなので、機種依存はGNUのBFDライブラリのソースコードを参照しながら進めています。

参考にした情報のリンクを上げておきます。
 DJGPP COFF Spec
 逆アセのスス乂
 BFDソースコード

gccとasでテスト用のオブジェクトファイルを作り、バイナリエディタとobjdumpで変化を確認していく地道な作業を続けており、Z8000依存で判明した部分や忘れてしまいそうな事などをメモ代わりに書いていきます。変数名は、DJGPPのドキュメントに合わせてあります。

Z8k-COFF フォーマット

次の7パートからなっている。
 ・ ファイルヘッダ
 ・ オプショナルヘッダ
 ・ セクションテーブル
 ・ セクションデータ
 ・ リロケーション情報
 ・ シンボルテーブル
 ・ 文字列テーブル 

ファイルヘッダ

ファイルの全体的な構造が記されている

 f_magic 
 0x8000 - Z8001/2の識別はflagsによる。

 f_flags
 0x1000 - Z8001 セグメンテッドコード
 0x2000 - Z8002 非セグメンテッドコード 
 0x0200 - 不明 (ビッグエンディアンかも)
 0x0008 - ローカルシンボル情報なし 
 0x0004 - ライン番号情報なし
 0x0002 - 実行形式
 0x0001 - リロケーション情報なし

オプショナルヘッダ

実行ファイルの場合のみ付き、実行ファイルに必要な付加情報が入っている。
下の2つは詳細不明。

 magic
 0x0000 

 vstamp
 0x0000 

セクションテーブル

セクションの情報が記されたセクションヘッダの配列。

 s_flags
 0x80 - 初期地を持たないデータ(BSS)
 0x40 - 初期値をもつデータ
 0x20 - 実行コード