2023年6月29日木曜日

UNIX V7のブート 2

inodeブロックを見ていきます。inodeブロックは、ディスクイメージでは0x0400から始まっています。
inodeの構造は、/usr/sys/h/ino.h の dinode構造体で定義されています。この構造体のサイズは64バイトです。
 struct dinode
{
	unsigned short	di_mode;/* mode and type of file */
	short	di_nlink;    	/* number of links to file */
	short	di_uid;      	/* owner's user id */
	short	di_gid;      	/* owner's group id */
	off_t	di_size;     	/* number of bytes in file */
	char  	di_addr[40];	/* disk block addresses */
	time_t	di_atime;   	/* time last accessed */
	time_t	di_mtime;   	/* time last modified */
	time_t	di_ctime;   	/* time created */
};
#define	INOPB	8	/* 8 inodes per block */
/*
 * the 40 address bytes:
 *	39 used; 13 addresses
 *	of 3 bytes each.
 */
};
inode番号0は未使用で、ルートディレクトリのinode番号は2なので、ルートのinodeの位置は、ディスクイメージでは0x0440からです。


ルートディレクトリのファイルの位置は、0x044cからのdi_addr[]にブロック番号がリストされています。このアドレスは、下のコメントのように3バイトで表され、上位1バイト+下位2バイトで記録されています。最初の3バイトは0x0002d4で1ブロック512バイトなので、0x5a800からファイルのデータが保存されています。
アスキーダンプにunixの文字列が見られます。SIMHでルートを ls してみた結果が下で、対応していることがわかります。

2023年6月25日日曜日

UNIX V7のブート 1


ブートローダの移植から始めようとしているわけですが、ディスクドライブからカーネルを読み込まないといけないので、まずはファイルシステムを理解する必要があります。この辺りは参考になりそうな書籍やネット上の情報があるので助かります。

技術評論社から出ている「はじめてのOSコードリーディング」は、UNIX V6の説明ですが、基本はV7とほぼ同じなので参考になります。

コードだけを読んで理解するのは難しいので、ディスクイメージと照らし合わせながら理解していきます。SIMHのサイトからUNIX V7のSoftware Kitesをダウンロードし、ZIPファイルに含まれているunix_v7_rl.dskを使います。

http://simh.trailing-edge.com/kits/uv7swre.zip 

このディスクイメージのブロックサイズは512バイトです。

先頭のブロックはブートブロックで、システム起動時に最初に読み込まれるブートプログラムが格納されています。ディスクからカーネルを読み出すコードですが、とりあえずは手をつけずに置いておきます。

ブートブロックに続く1ブロック、ディスクイメージのダンプリストで0x0200から0x03FFまでがスーパーブロックになります。



スーパーブロックの構造の定義は、/usr/sys/h/filsys.h にある filsys 構造体です。NICFREEなどの定数は param.h に定義されてます。

 /*
 * Structure of the super-block
 */
struct	filsys {
	unsigned short s_isize;	/* size in blocks of i-list */
	daddr_t	s_fsize;   	/* size in blocks of entire volume */
	short  	s_nfree;   	/* number of addresses in s_free */
	daddr_t	s_free[NICFREE];/* free block list */
	short  	s_ninode;  	/* number of i-nodes in s_inode */
	ino_t  	s_inode[NICINOD];/* free i-node list */
	char   	s_flock;   	/* lock during free list manipulation */
	char   	s_ilock;   	/* lock during i-list manipulation */
	char   	s_fmod;    	/* super block modified flag */
	char   	s_ronly;   	/* mounted read-only flag */
	time_t 	s_time;    	/* last super block update */
	/* remainder not maintained by this version of the system */
	daddr_t	s_tfree;   	/* total free blocks*/
	ino_t  	s_tinode;  	/* total free inodes */
	short  	s_m;       	/* interleave factor */
	short  	s_n;       	/* " " */
	char   	s_fname[6];	/* file system name */
	char   	s_fpack[6];	/* file system pack name */
};
これらデータは、ブートには直接関係ないのですが、ファイルシステムの構造が含まれています。
0x0200 : s_isize(2バイト)は、inodeブロックのブロック数です。PDP-11はリトル(ミドル)エンディアンなので、0x02D2で722ブロックになります。

0x0202: s_fsize(4バイト)は、ディスクドライブのブロック数です。上位の2バイト、下位の2バイトの順に並んでいます。0x00004650なので18000ブロックです。

スーパーブロックの次のブロックは、inodeブロックでinodeのリストです。このディスクイメージでは、722ブロック続きます。

2023年6月24日土曜日

UNIX V7の移植に挑む

PCCをZ8000に対応できそうな目処がたってきたので、UNIXの移植に手をつけていきます。何年越しのプロジェクトやねん、って感じですが、PCCの作業にすこし飽きてきたのと、実際のコードをコンパイルしながらデバッグしていった方が現実的な気がしてきたきたからです。途中で挫折しそうな気がしますが、気長にやっていきます。なにせ趣味(暇つぶし)ですから。

まず第一歩として、githubの unix-history-repo からV7のソースコードをクローンしました。

$ git clone git@github.com:dspinellis/unix-history-repo.git -b Research-V7-Snapshot-Development --depth 1 
ざっと眺めてみて正直どこから手を付ければ良いのか、ちょっと悩みます。少しでも成果が見えて、進んでいる実感がないと継続は難しいですからね。やはり、ブートローダあたりからかなあ。

2022年8月11日木曜日

ZCCの注意点

YouTube に ZCCで "Hello, world" する動画を上げました。

"Hello, world" under CP/M-8000

 ZCCを使ってみて気づいた注意点を上げておきます。なにせK&R時代の古いCコンパイラなので、今の感覚でコードを書くと、思わぬところでエラーの嵐に遭遇します。

・=- に注意

 「x=-1」 は、「x = -1」ではなく「x -= 1」に解釈されます。コンパイル時にwarningがでますが、オブジェクトファイルが出力されリンクも正常にできるので注意が必要です。実行してみて意図した動作をしないことで気づきましたが、理由がわからずしばらく悩みました。 かなり古い(K&R以前?)の書き方のようです。

・関数のプロトタイプ宣言に引数の型を含めない & 戻り値がなくても int で宣言

 これもかなりハマりました。次のように宣言します。

         int foo(a, b);

         foo(a, b) int a, b;
         {
            /* 戻り値なしの処理 */
         }

・unsigned char が使えない?

 unsigned int は使えるのですが、unsigned char はサポートしていないようです。

・関数名、ラベル名、変数名は8文字まで 

 Cコンパイラは名前の前に "_" をつけるので、実質使えるのは7文字です。それ以上の文字は無視されるので、気を付けないと違う名前を付けたのに同じと判別されてしまいます。アセンブラとリンカが8文字までしかとらない仕様なので、これは仕方ありません。

・コンパイラの -D オプションが働かない

 これは、The Unofficial CP/M Web Siteに書かれていました。試したところ本当に働きません。ヘッダファイルに、#define で定義しておく必要があります。

・コンパイラのオプションがわからない

 ZCCのドキュメントが失われているようで、コンパイラーに指定できるオプションがわかりません。今のところわかっているのは、上の働かない-Dぐらいです。CP/M-68KのCコンパイラにはドキュメントが残っているようなので、参考になるかもしれません。

・改行コードと終端コードに注意

 改行コードがCR+LFで、テキストがEOFで終端されていないとエラーに悩まされます。これはZCCというよりCP/Mの仕様なのですが、意味のわからないエラーメッセージがでるので悩まされます。CP/M上でコードを編集する場合は大丈夫ですが、LinuxやWindows上で編集している場合に問題になります。改行コードは指定しておけば問題ないのですが、末尾にEOFをいれてくれるエディターはないようなので、意図的に入れる必要があります。VimだとCtrl+Zで入れられます。EOFのあとにテキストが入っていても無視されます。

癖がわかってくると、ZCCは結構使える気がします。アセンブリ言語で書くよりは格段に楽ですから、多少の制約は我慢できます。

2022年8月1日月曜日

CP/M-8000にFPUエミュレーションを追加

 CP/Mのライセンスに変化があったのと、夏休みに入って時間ができたこともあり、CP/M-8000に手を入れています。その一番目として、やり残していたFPUエミュレーションをCP/Mにリンクして使えるようにしました。

作業としては、fpe.o と fpedep.o をXOUTからCOFFに変換し、biostrap.sを書き換えるだけですんだので拍子抜けするほど簡単でした。fpe.oはZilogが出荷予定だった実数演算コプロセッサのZ8070をエミュレートするもので、Z8070の命令がくると例外処理で実数演算をソフトウェアで実行します。

これで、ZCC(ZilogのCコンパイラ)で、floatが扱えるようになりました。ためしに、レトロCPU界隈ではメジャーなマンデルブロ集合のASCIIARTをC言語に書き換えて実行してみました。コードは下のような感じです。


これをコンパイルして実行したのが下の結果です。

見慣れたアスキーアートが出ているので、問題なく動作しているようです。ただし実行時間は遅く、7分44秒とかなり期待はずれな結果です。結果はともかく、実数演算がC言語で使えるようになっただけで可能性は広がります。試せる人はかなり限られると思いますが、この成果はGitHubのリポジトリに反映しました。

今後は、開発環境を改善していく予定です。私にはCP/M標準のEDが全く馴染まないので、まずはエディタをどうにかしようと検討中です。

2021年12月27日月曜日

Z8K CP/Mボード その2

こんなものを試す人はかなりのハッカー基質の人だと思い、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に含まれています。

こんな状況になると予想しておらず、慌てて書いたので間違っているかもしれません。

2021年12月26日日曜日

Z8K CP/Mボード

 私がGithubにあげているZ8001MBの回路図をもとに、tomi9さんがCP/M-8000を動作させることができるPCBを作成され、一枚送ってくださいました。


PCBだけでなくCFのソケットとGALも同封されており、あとは手持ちの部品だけで行ける状態でした。tomi9さん、ありがとうございます。自分もいつかはPCBを作ってみたいとは思っているのですが、なかなか勇気が出ません。ラッピングワイヤーでの手配線だと、すぐに回路の修正がききますが、PCBだとそう簡単にはできません。

久しぶり(中学高の技術の授業以来?)のPCBでの組み立てで、ちょっと一投目は緊張しましたが、最難関のCFソケットのはんだ付けを済ませ、Z8536以外の部品を組みつけて、現在、動かせるところまで来ています。