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が動き出します。