UNIX 6th code reading - prf.c
初めての方はこちらを参照 http://d.hatena.ne.jp/takahirox/20101024/1287923014
はじめに
今回は301p - のprf.cです。
メッセージの表示やpanicなどを扱います。
printf
2340 : printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc)
x2以降にはx1からポインタの指す先をシフトさせることでアクセスする。(2346, 2361行)
なので呼び出されるときの引数の数は気にしない(はず)。
引数のアドレス関係は下図のようになる。
ポインタをインクリメントすることで、次の引数にアクセスできる。
2361 : adx++;
- 2348 - 2352 : fmtを一文字ずつ処理
- 2348 : '%'が来たらループを抜ける
- 2349 - 2350 : '\0'(文字列の終端)が来たらreturn. printfから抜けられる唯一の箇所。
- 2351 : そうでなければputcharを呼び出して1文字出力する
- 2353 : この時点でfmtは'%'の次の文字を指している。cに'%'の次の文字を代入。
- 2354 - 2355 : '%d', '%l', '%c'ならばprintlnを呼び出して数値の出力
- 2356 - 2360 : '%s'ならば該当のxnを出力
printn
http://www.asahi-net.or.jp/~ax2s-kmtn/ref/bdh.html#binary
上記ページの「基数による割り算を繰り返し、余を変換後の値とする」ロジックを素直に実装している。ldiv, lremはアセンブリで書かれている(なぜ?)。
putchar
端末のデバイスレジスタを参照するので、24章(444p)を読んでおくと理解が進む。
2393 : while((KL->xsr&0200) == 0 ) 2394 : ;
transmitter status registerの7番目のbitが1になるまで(端末の出力処理準備ができるまで)busy waiting.
(0200(8進数) → 10000000(2進数))
busy waitingは当然CPU負荷が高いが、短時間で上記bitがセットされることが保障されているので問題ない(? PDP11 Handbookなどで要確認)
- 2398 : KL->xsrをall 0 set. 6bit目の割り込み許可bitも0にセットされる。2406でKL->xsrの値を復帰させるまで、7bit目が1にsetされても(端末出力処理準備ができても)割り込みは発生しない。
- 2406までの処理中に7bit目がsetされて(出力処理が完了して), 次のputchar処理が開始されてしまうことを防ぐため?
- 2399 : 出力する文字をtransmitter data buffer registerにセットする。これで出力処理が開始される?
- 2402 - 2403 : 端末の改行処理が完了するまでの時間稼ぎ
- 2405 : 端末の出力処理が完了するのを待つ?
panic
- 2422 - 2423 : idleを無限に呼び出すことで、処理の継続を止める。idleを呼び出しても、システムクロックは機能し続けられる。
その他メモ
- ロジックを鑑みるに、printf( ' ', a, b, c )というような呼び方をしても、a, b, cが無視されるだけでエラーにはならないっぽい。
- PDP11 Peripherals Handbookあたりに目を通さないと、putcharの内部動作が見えてこない
終わりに
次は6章の予定。いよいよUNIXが動き出します。