プリンター on unix/v6

訳有りで田舎で避暑してきた。昼間は暑いけど(女房によれば、太陽に刺されるとか)日陰に 入るとそこはカリホーニアな塩梅。夜は窓を開けておくと寒いぐらいな別天地。 おいらだけ、先に帰ってきたんだけど、運転疲れもあって9時過ぎには寝たよ。

11時にお尻に汗を掻いて目が覚めちゃった。水を一杯飲んで再び寝床へ。クーラーをかけっ放し にしてるんだけど、不快。寝付けない。寝付けない。しゃーないナイトキャップするか。

冷凍庫から冷やした角とグラスを取り出してきてハイボールにした。何かつまみが無いと 胃に悪いよね。明朝食べる予定だったポテトサラダを先行評価。難しい本でも読めば、ブースト されるかもと思って、CQ誌にしては珍しく複雑な式が載ってる記事を読んだよ。

効果てきめんで、ふらふらしてきたので、再び寝床へ。あーあ、女房が楽しみにしてたハイボール 飲んじゃったよ。3倍返しで、マティウスやらマドンナを要求されるんかいな? 明日の朝食に 手付けちゃったよ。なんて考えているうちに、地球や天井が回り出したよ。あーー、いい気持ち。

こんな気分は何年ぶり? 酔った時は、深く深呼吸だな。きっと部屋一面がアルコール臭く なっているに違いないな。

nm もどき

前回、カーネルのコンパイルを行って、大局が掴めた。今回は落ち葉を拾っていく。(早く 秋が来ないかな)

unix/v6には、内蔵のnmコマンドが用意されてる。が、その結果を眺めようとしても画面が 流れてしまって、ちと不都合だ。sim コマンドの所で、set log mylogとかやって、ログを FreeBSDに残すって方法もあるんだけど、別の方法を考えてみる。

unix/v6界からFreeBSDへのチャンネルは、今の所 ddしかない。ddで、FreeBSDに仮想Tapeを 持ってきた場合、512Byte毎に、ヘッダーとフッターが入るんだった。まずはこれを除去せんとな。 Perlで書かれた、逆パターンのやつがあるんで、それを流用してしまおう。

#! /usr/local/bin/perl
# Delete 512Byte each header/footer
# Usage; delhf.pl < dump.tap > out-file

while(!eof(STDIN)){
    read(STDIN, $dmy,4);
    read(STDIN, $str, 512);
    print $str;
    read(STDIN, $dmy,4);
}

もうPerlで考えられなくなったので、これでいいのかしらん? まあ、これで、いらないものが除去出来たとしましょう。次は、車輪の再発明します。はい、nmです。 勿論、FreeBSDのそれは使えませんから、スクラッチから書きます。リハビリを兼ねて、rubyします。

#!/usr/local/bin/ruby
# List symbol section for a.out
# Usage; nm.rb a.out

def cv(flg)
  case flg
    when /00/ then rv = "u"  # Undefine
    when /01/ then rv = "a"  # Absolute
    when /02/ then rv = "t"  # Text
    when /03/ then rv = "d"  # Data
    when /04/ then rv = "b"  # Bss
    when /1f/ then rv = "f"  # File name (0x1f == \037)
    when /20/ then rv = "U"  # ext Undefine (Global)
    when /21/ then rv = "A"  # ext Absolute
    when /22/ then rv = "T"  # ext Text
    when /23/ then rv = "D"  # ext Data
    when /24/ then rv = "B"  # ext Bss
    else           rv = "?"  # Unknown
  end
  rv
end

## main
f = File.open(ARGV[0])
  h = f.read(10).unpack("v*")  # read header by vax order(little endian)
  cnt = h[4]/12                # symbol entries count
  f.seek(16 + h[1] + h[2])     # skip (header + text + data)

  cnt.times do
    name = f.read(8).unpack("Z8")[0]
    flg  = f.read(2).unpack("H2")[0]
    val  = f.read(2).unpack("v")[0]
    printf("%s  %9s  %06o\n", cv(flg),name,val)
  end
f.close

相手はバイナリーファイルなんで、unpack使いまくりです。アンパックのテンプレートに8進数を 処理するやつが無いのは、誰に文句を言えばよいのでしょうか?

動いているか確認します。unix/v6のカーネルにどんな名前が含まれているのかなあ? 興味が ありますよ。

[sakae@cdr ~/UV6]$ cat dump.tap | bin/delht.pl > a.out
[sakae@cdr ~/UV6]$ bin/nm.rb a.out
D       trap  000746
D      start  000422
D       dump  000320
T       call  020010
T    _klrint  071100
  :
B   _t_nxrec  041542
T   _tcomman  073724
T   _tmstart  074206
T    _tmphys  075124

オリジナルとは多少フォーマットが違うけど、いいやね。

ラインプリンターを使う

マニュアルによると、使えそうなコマンドは、prとかoprがあります。実際に試す前に、お前 ラインプリンターなんて持ってないじゃんと言う、大問題に気づきました。が、それはそう simの力を借りて、FreeBSD界にファイルと言う形で結果を残す事に今決めました。simの 起動スクリプトに

att lpt paper.txt

なんてのを指定しておきます。(paper.txtは任意の名前です。へたれな名前ですが、ご勘弁を) で、実際に試してみると。。。

# pr rootList


Aug 20 13:28 1994  rootList Page 1


total 294
-rw-rw-rw-  1 root    26127 Aug 20 13:13 CATLOG
drwxr-xr-x  2 bin      1040 Jan  1  1970 bin
drwxr-xr-x  2 bin       400 Aug 20 13:16 dev
drwxr-xr-x  2 bin       304 Aug 20 13:27 etc
drwxr-xr-x  2 bin       336 Jan  1  1970 lib
drwxr-xr-x 17 bin       272 Jan  1  1970 mnt
drwxr-xr-x  2 bin        32 Jan  1  1970 mnt2
-rwxrwxrwx  1 root    29302 Aug 20 13:24 myunix
-rw-rw-rw-  1 root    28472 Aug 20 12:01 rkunix
-rwxr-xr-x  1 bin     28636 Aug 20 11:38 rkunix.40
drwxrwxrwx  2 bin       144 Aug 20 13:27 tmp
-rwxr-xr-x  1 bin     28472 Aug 20 12:01 unix
drwxr-xr-x 13 bin       224 Aug 20 12:22 usr
drwxr-xr-x  2 bin       144 Aug 20 13:28 usr2


# opr -lp rootList
#

どうやら、prは整形してコンソールに出力するようでした。それなら、oprをばと思って 試してみるも、FreeBSD側には結果が残らず。はて、使い方が悪いのかしらん? こういう時は かなめのデバイスがあるかですね。/devの下をサルベージするも、lpなんてのはかすりも しませんでした。

じゃ、無いなら作るだけとばかり、作りましたよ。(lpは、キャラクターデバイスです)

# ls -l /dev/lp*
crw-rw-rw-  1 root    2,  0 Aug 20 13:28 /dev/lp
crw-rw-rw-  1 root    2,  0 Aug 20 13:16 /dev/lp0

最初に、lp0を作って試すもダメだったので、lpも作って試すと言う馬鹿をやちゃいました。 でも、動かんのですよ。これが。ならば、奥の手を出しますか。恐怖のデバイス直叩き。

# cat rootList > /dev/lp
/dev/lp: cannot create

見事に怒られましたね。そんなデバイスは無いのかしらん?

Simulation stopped, PC: 021630 (MOV (SP)+,177776)
sim> sh lpt
LPT, address=17777514-17777517, vector=200, attached to paper.txt
sim> e 200/4
200:    000000
202:    000000

simに落ちて、割り込みベクターを確認してみたよ。そしたら、見事にベクターが設定されて ないじゃないですか。これじゃ、動く訳ありませんな。これはもう、カーネルを作り直す しか。例の本には、unixのコンフィグレーションは、(某OSに比べて非常に)簡単よーー、 とか書いてますし。

sysの下にあるrunにlpを追加します。

mkconf
rk
tm
tc
lp       : <--- Add
done

そして、コンパイルし、出来たカーネルを /myunix として保存。起動時に、myunixを 指定してbootします。

PDP-11 simulator V3.8-1
Disabling XQ
@myunix

login: root
# sync
#
Simulation stopped, PC: 002510 (MOV (SP)+,177776)
sim> sh lpt
LPT, address=17777514-17777517, vector=200, attached to paper.txt
sim> e 200/4
200:    000276
202:    000200
sim> c

今度は、ちゃんとベクターが設定されますね。

# cat rootLisp > /dev/lp
#

文句を言われずに、lpにデータが流れて行ったようです。FreeBSD側で確認してみます。

[sakae@cdr ~/UV6]$ cat paper.txt | head
        total 294
        -rw-rw-rw-  1 root    26127 Aug 20 13:13 CATLOG
        drwxr-xr-x  2 bin      1040 Jan  1  1970 bin
        drwxr-xr-x  2 bin       400 Aug 20 13:16 dev
        drwxr-xr-x  2 bin       304 Aug 20 13:25 etc
        drwxr-xr-x  2 bin       336 Jan  1  1970 lib
        drwxr-xr-x 17 bin       272 Jan  1  1970 mnt
        drwxr-xr-x  2 bin        32 Jan  1  1970 mnt2
        -rwxrwxrwx  1 root    29302 Aug 20 13:24 myunix
        -rw-rw-rw-  1 root    28472 Aug 20 12:01 rkunix

ちょいと余白が取られているのは、ラインプリンターっぽくていい感じです。この後 いろいろなファイルとかコマンドの結果をプリントしてみましたが、途中に改ページの マーク(^Lがそうです)が入ってて、いかにもな感じでしたよ。

ついでなので、オリジナルのnmの結果の一部も残しておきます。

        002166T _pmode
        003704T _printf
        004566T _putchar^L        005402T _qs1
        012632B _qscmp
        012634B _qses
        006130T _qsexc

再び simhで

折角プリンターを組み込んだので、動きを追ってみます。myunixなんで、生成途中でmkconfが 作ったl.sもオリジナルになってます。(例の本では、low.sとなってますが。)以下は、 その抜粋です。

. = 200^.
        lpou; br4

. = 214^.
        tcio; br6

. = 220^.
        rkio; br5

. = 224^.
        tmio; br5
//////////////////////////////////////////////////////
/               interface code to C
//////////////////////////////////////////////////////

.globl  call, trap

.globl  _klrint
klin:   jsr     r0,call; _klrint
.globl  _klxint
klou:   jsr     r0,call; _klxint

.globl  _clock
kwlp:   jsr     r0,call; _clock


.globl  _lpint
lpou:   jsr     r0,call; _lpint

.globl  _tcintr
tcio:   jsr     r0,call; _tcintr

.globl  _rkintr
rkio:   jsr     r0,call; _rkintr

.globl  _tmintr
tmio:   jsr     r0,call; _tmintr

PTP/PTRが無くて、LPとTMが登録されてます。それじゃ、プリンターの割り込みハンドラから 辿ってみます。

Simulation stopped, PC: 002510 (MOV (SP)+,177776)
sim> e 200
200:    000276
sim> e 276/10
276:    004067
300:    000116
302:    057410
304:    004067
sim> e -m 276/10
276:    JSR R0,420
302:    BIS @4067(R4),(R0)
sim> br -e 57410

割り込みベクターですから、動作としては、jmp @200 という事で、276番地から、ちょっと 表示してみました。-m を付けると逆アセンブルしてくれます。この結果、420番地は、Cの関数 callの開始番地。そこで、もう一度、次の番地が間接呼び出し(相当)される事になる。 最終的に呼び出される _lpintは、57410番地と判明したので、そこにブレークポイントを 設定した。

# cat l.s > /dev/lp
Breakpoint, PC: 057410 (JSR R5,3574)
sim> step 20

Step expired, PC: 000642 (MOV 2(SP),R1)
sim> sh cpu history=20
PC     PSW     src    dst     IR

057410 030204|141622 057410  JSR R5,3574
003574 030204|057414 000304  MOV R5,R0
003576 030200|141566 057414  MOV SP,R5
003600 030210|000057 141566  MOV R4,-(SP)
003602 030200|000002 141564  MOV R3,-(SP)
003604 030200|067334 141562  MOV R2,-(SP)
003606 030200|003606 057414  JSR PC,(R0)
057414 030200|057414 057414  JSR PC,57346
057346 030200|141566 057346  JSR R5,3574
003574 030200|057352 057414  MOV R5,R0
003576 030200|141552 057352  MOV SP,R5
003600 030210|000057 141552  MOV R4,-(SP)
003602 030200|000002 141550  MOV R3,-(SP)
003604 030200|067334 141546  MOV R2,-(SP)
003606 030200|003606 057352  JSR PC,(R0)
057352 030200|               BR 57374
057374 030200|057374 057374  BIT #200,@#177514
057402 030200|               BNE 57354
057354 030200|057354 141542  MOV #120314,(SP)
057360 030210|057360 057360  JSR PC,@#642

これと、lp.cの該当部分を比べると。。

8976: lpint()
8977: {
8978:         register int c;
8979: 
8980:         lpstart();
8981:         if (lp11.cc == LPLWAT || lp11.cc == 0)
8982:                 wakeup(&lp11);
8983: }

最初に呼ばれている、3574番地は、レジスターの退避ルーチンか。でもって、 54346番地は、lpstartになるかな。こんな具合に、地図を埋めて いくのがいいのかな。なんだかジグソーパズルをやってるみたいで、面白いな。