ディスクドライブの構成
構成物は3つで下記の通り:
- ディスクコントローラ: RK11
- ディスクドライブ: RK05
- ディスクカードリッジ: RK03-KA
RK11ディスクコントローラには最大8台のドライブを接続できる。
また、RK11-DとRK11-Eと2種類ある。
前者は1word=16bit、後者は18bit単位でデータをアクセスする。
RK05ディスクドライブには交換可能なディスクカードリッジが1枚挿さる。ディスクのサイズは14インチ!
ネットの写真を見ると大人が抱えて持つくらいな大きさ。
ディスクの論理的な構成は、現代のハードディスクとまったく一緒だ。
ディスク表面だけでなく裏面にもデータ記録に使う。1ディスク2面持っているということだ。
スペック:
- 1ディスクカードリッジ/ディスクドライブ
- 2面/ディスク
- 203シリンダ/ディスク
- 203トラック/面 (406トラック/ディスク)
- 12セクタ/トラック
- 256ワード/セクタ
RK11-Dの場合は1word=16bitなので、512バイト/セクタになる。
一枚のディスクの容量は、512バイト x 12セクタ x 406トラック = 2494464バイト。(2.5MB)である。
ディスクの読み書き
ディスクに対してデータを読み書きするためには、RK11の制御レジスタにアクセスして行う。
PDP-11はMemory-mapped I/O なので、ペリフェラルのレジスタは特定のメモリ番地の読み書きをすればよい。
以下はマニュアルからの抜粋。
####RK11の制御レジスタ一覧
Name | Abbreviation | Address | 意味 |
---|---|---|---|
RK11 Drive Status Register | RKDS | 777400 | ドライブの状態を表す |
RK11 Error Register | RKER | 777402 | エラーの状態を表す |
RK11 Control Status Register | RKCS | 777404 | ディスク制御に使用される |
RK11 Word Count Register | RKWC | 777406 | 転送データサイズを表す |
RK11 Bus Address Register | RKBA | 777410 | メモリ中の転送データのアドレス |
RK11 Disk Address Register | RKDA | 777412 | ドライブ中の転送データのアドレス |
RK11 Data Buffer Register | RKDB | 777416 |
※アドレスは8進数表記
別の資料を探したら、RK11のコントロール用のレジスタ一覧は以下が見やすい。(http://www.psych.usyd.edu.au/pdp-11/rk05_internals.html)
まず知りたいのは、ディスク領域の場所指定の仕方だ。
ディスクのアドレス指定は、RKDAレジスタを使う。
777412 Disk address 15-13 Drive select : 3bit (0〜7)
12-5 Cylinder address : 8bit (0〜202)
4 Surface (head) : 1bit (0,1)
3-0 Sector : 4bit (0〜11)
ドライブ番号は0〜7番。シリンダは外周側から0番号が振られ、202まで。
ディスク面は表と裏の0,1指定。あとはセクタ番号のの指定(0〜11)。
UNIX V6のディスクブロック
でも、これデータを保存するときに、いちいち全パラメータを指定するのは面倒だろう。
UNIX V6の場合はどうしているのかというと、ドライブ番号はデバイスファイルのマイナー番号として使っているが、あとは論理的にはブロック番号というもので統一して扱っている。
あるディスク上のブロック番号は、シリンダ0, 面0, セクタ0 をブロック0として、リニアに増えて行く。(これはハードディスクのLBA方式と同じ考え方ですね。UNIXがベースになってるのかしら)
#####ブロック番号とセクタ、面、シリンダの関係
Block | Cylinder | Surface | Sector |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 |
2 | 0 | 0 | 2 |
... | |||
11 | 0 | 0 | 11 |
12 | 0 | 1 | 0 |
13 | 0 | 1 | 1 |
... | |||
23 | 0 | 1 | 11 |
24 | 1 | 0 | 0 |
25 | 1 | 0 | 1 |
... |
#####計算式 (C言語)
- シリンダ番号 = (ブロック番号/12)/2
- 面番号 = (ブロック番号/12)&1
- セクタ番号 = ブロック番号%12
#####UNIX V6の実装
コードそのままではないが、以下のような実装をしている。
return (d_minor<<13 | (blkno/12)<<4 | blkno%12);
d_minor:デバイスのマイナー番号、blkno:ブロック番号。
またシリンダ番号と面番号はビット的には隣どおしなので、(blkno/12)<<4だけで済んでいる。
PDP-11(エミュ)上でRK11を使ってみる
PDP-11エミュレータsimhを使って、rk11のディスクを使ってみる。
具体的にはディスクの1ブロック分(512バイト分)のデータをメモリに読み込んでみる。
簡単なアセンブラプログラムを、UNIX V6のディスクブートローダのソース(mdec/rk.s)を参考にしながら作ってみた。
下記のプログラムは、rk11ディスクコントローラを使ってブロックNo 1のディスク領域からメモリ番地02000番地に512バイト転送する。
(なお、以下も含めアドレスは全て8進表記)
.global start
STACK = 01000
rkda = 0177412
.text
start:
mov $STACK,sp
mov $1,r1 / r1 = block no = 1
rblk:
clr r0 / r0 = 0
div $12,r0 / r0 = r1/12, r1 = r1%12
ash $4,r0 / r0 = r0 << 4
bis r1,r0 / r0 = r0
mov $rkda,r1
mov r0,(r1) / *RKDA = r0
mov $02000,-(r1) / *RKBA = 02000
mov $-256,-(r1) / *RKWC = -256
mov $5,-(r1) / *RKCS = 5 (READ & GO)
1:
tstb (r1) / check *RKCS is ready
bpl 1b
loop:
br loop
.end
ENTRY(start)
SECTIONS
{
. = 01000;
.text : {
*(.text)
*(.rodata)
. = ALIGN(0100);
}
.data : {
*(.data)
. = ALIGN(0100);
}
.bss : {
*(.bss)
. = ALIGN(0100);
}
end = .;
}
TARGET = start
OBJS = start.o
CC = pdp11-aout-gcc
AS = pdp11-aout-as
CFLAGS = -ffreestanding
all: $(TARGET).lda
run: rc-pdp11
pdp11 $<
$(TARGET).lda: $(TARGET).out
bin2load -a -f $< -o $@
$(TARGET).out: $(OBJS) ld.script
pdp11-aout-ld -T ld.script $(OBJS) -o $@
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
.c.s:
$(CC) -S $< -o $@
.S.o:
$(AS) $< -o $@
clean:
rm -f *.lda
rm -f *.out
rm -f *.o
#####実行はこんな感じ
$ pdp11 rc-pdp11
rc-pdp11
はsimhのPDP-11の設定ファイルで、起動時に引数として与えて読み込ませている。内容は以下の通り。
set cpu 11/40
set cpu u18
att rk0 unix0_v6_rk.dsk
l start.lda
attr rk0 unix0_v6_rk.dsk
ではUNIXのディスクイメージのファイルをディスクrk0にアタッチしている。そして、ここで作ったプログラムのバイナリのstart.lda
は最後に読み込んでいる。
unix0_v6_rk.dskはodで中身を確認する。01000番地(512バイト)以降、つまりブロック番号1では、以下のようになっている。
*
0001000 000144 007640 000052 002412 002371 002442 002141 002130
0001020 002157 002376 002411 002214 002417 002307 002440 002437
で、エミュレータ起動後は、以下のようにしてg
でプログラムを実行する。
PDP-11 simulator V3.9-0
Disabling XQ
sim> g
# <C-e>を押す
Simulation stopped, PC: 001052 (BR 1052)
sim> e 2000:2030
2000: 000144
2002: 007640
2004: 000052
....
最後の方は、コマンドe
でメモリ番地の02000の内容をexamin(ダンプ)している。
02000はプログラムで読み込み先として指定した番地。
中身がunix0_v6_rk.dskをodした内容と同じことが確認できたかと。
##参考資料
- シリンダ、トラック、セクタの用語の意味
- RK11 disk driveマニュアル
- RK05 Maintenance Manual
- 「はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus)」
必要なツール環境
(1) PDP-11のgccクロス環境構築は以下記事を参照
http://qiita.com/hifistar/items/187fd7ad780c6aa26141
(2) bin2loadは以下から
The Ancient Bits adventure: Writing PDP11 assembly code from Linux (and running it on bare -simulated- metal!)
(3) simh
http://simh.trailing-edge.com/