2013.7.3
前へ
次へ
ホームページトップへ戻る

復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります

[第433回]


●PL/IのLINKでエラー(2)

前回からの続きです。
COBOLに引き続いてPL/IでもファイルOPENでこけてしまいました。
互換性を実現するというのはなかなかに難しいものです。
ZB3DOS(CP/M互換DOS)はCP/Mについて書かれた参考書などをもとにしましてプログラムを書いたものなのですが、説明書などには書かれていないような細かいところまではわからないので、こういうことがでてきてしまいます。

なんだ。
オリジナルのCP/Mを解析したんじゃないのか。
と疑問に思われるかもしれません。

ええ。
オリジナルのCP/Mのソースリストは[第17回]に書きましたように、ダウンロードさせていただいております。
ですけれど、どうしても不明なところはちょいと参考にはさせていただきましたけれど、ほとんど解析などはしておりません。
互換プログラムなどを書こうとする場合には、オリジナルのプログラムを逆アセンブルなどして解析するのが常道ではないかと思われるかもしれませんが、それは労多くして功少ない方法だと思います。
一体何がしんどいと言いましても他人が書いたプログラムを解読するということくらいしんどいものはありませぬ。
もうほとんど拷問ですな。
ですので、やりたくはありませんです。

入力がこうで、出力がこう、というように、インプットとアウトプットが決まっていて、その間のプロセスを記述するのがプログラムでありますから、それができなきゃあプログラマとはいえませんでしょう。
他人の書いたプログラムを解析するより、はなから自前でプログラムを書いたほうがなんぼ楽かわかりません。
そのかわり、約束事として表に出てきていないような微妙な仕様が使われるところでは、とたんにこけてしまうことになります。

ま、しかし。
そうやってこけたところをひとつひとつつぶしていくことによって、少しずつ完全な互換に近づいていくことになります。
このところのH様、N様のご協力によりまして、かなりオリジナルに近い互換性が実現できたと思っております。
これひとえに両氏のご協力のたまものと、心より感謝いたしております。
今後とも引き続きご協力のほどをお願い申し上げます。

さて、それで。
前回の続きなのですが。

H様のデバッグによりまして、PLILIB.IRLをファイルOPENしようとしたところでこけていることがわかりました。
ファイルOPENのファンクションコール(ファンクション0F)は、FCB(ここではアドレス005CH〜)にファイル名を書いてコールするのですが、そのFCBではエクステント(拡張aBFCBの先頭から13バイト目)に01が書かれているのです。
ここは本来は00でなければならないはずなので、それでZB3DOSではエラーにしてしまったのです。

CP/Mのディレクトリについておさらいです。
ディスクにファイルをセーブするときには、まずディレクトリにそのファイル名を登録します。
ディレクトリは目次のようなもので32バイトずつに区切られています。
メモリ内に置かれるFCBとレイアウトはよく似ていますが、異なっているところもあります。

先頭の1バイトはメモリ内に置かれるFCBではドライブb示しますがディレクトリではファイルの存在を示す場所として使われ、そこには00が書かれます。
未使用であったり、消去された場合には先頭の1バイトは非00(E5)になります。
次の8バイトがファイル名で、次に3バイトの拡張子が続きます。
その次の1バイトがエクステント(拡張ajです。
それではそのエクステントとはなんだ?
ということについて説明をしなければなりません。

32バイトの後半16バイトはブロックアローケーションエリアです。
CP/Mではセクタをまとめたものとしてブロックという概念を使います。
ハードに依存しない論理的なものですが、ハードと一致すればトラックと考えてもいいと思います。
ZB3DOSのシステムでは、1セクタが128バイトで1トラック=1ブロックは16セクタ(2048バイト)です。

ZB3DOSの仮想FDDは先頭からbOブロック、bPブロック、…と順にブロックbつけて、そのブロックbイとに管理を
しています。
ファイルのデータはセクタに書き込まれますが、そのときには1ブロックが丸ごと空いているブロックをみつけて、そこの16個のセクタに順にデータを書き込んでいきます。
たとえ1セクタしか使わなくて書き込みを完了した場合でもそのブロックは使用済みになります。

ファイルを保存する場合には、ディスクのデータ領域の先頭から空いているブロック(2048バイト)をさがしながらセクタ単位でデータがディスクに記録されていき、同時にディレクトリ内のFCBの後半16バイトのブロックアローケーションエリアに、データを書き込んだブロックの位置を示す2バイトのブロックbェ記入されます。
16バイトですから、8個のブロックb記入すると、枠がいっぱいになってしまいます。
ということは、そのルールでディスクに書き込めるデータは最大で2048×8=16KBです。

それでは16KBを越えるファイルを作成するにはどうしたらよいでしょうか?
そこで登場するのがエクステントです。
データを16KB書き込んで、枠がいっぱいになってしまうと、同じファイル名の32バイトのエリアがディレクトリ内にもうひとつ作成されます。
これでもう16KB分のデータ保存が可能になります。

ただそれだけでは、ディレクトリ内に同じファイル名のFCBが2つ存在することになりますから、あとから作成したFCBのエクステントは01にして、最初のFCBとは区別します。
このように、ディレクトリに最初に作られるFCBのエクステントは00で、次に作られる同じファイル名のFCBのエクステントは01、その次には02…というように、エクステントb順につけることで、大きな容量のファイルでも、その記録した順序の通りにデータを読み出すことができます。

実はH様がデバッグのために表示させたメモリダンプでそのことを確認することができます。
下は前回お見せしたログファイルの一部です。

>DM@0050,00FF
0050  0C A8 AE EA 08 E8 77 75-02 85 AA 2A 00 50 4C 49  .ィョ...wu..ェ*.PLI
0060  4C 49 42 20 20 49 52 4C-01 00 00 80 3E 00 3F 00  LIB  IRL....>.?.
0070  40 00 41 00 42 00 43 00-44 00 45 00 18 35 F7 00  @.A.B.C.D.E..5..
0080  00 50 4C 49 4C 49 42 20-20 49 52 4C 00 00 00 80  .PLILIB  IRL....
0090  3E 00 3F 00 40 00 41 00-42 00 43 00 44 00 45 00  >.?.@.A.B.C.D.E.
00A0  00 50 4C 49 4C 49 42 20-20 49 52 4C 01 00 00 80  .PLILIB  IRL....
00B0  46 00 47 00 48 00 49 00-4A 00 4B 00 4C 00 4D 00  F.G.H.I.J.K.L.M.
00C0  00 50 4C 49 4C 49 42 20-20 49 52 4C 02 00 00 5C  .PLILIB  IRL...\
00D0  4E 00 4F 00 50 00 51 00-52 00 53 00 00 00 00 00  N.O.P.Q.R.S.....
00E0  00 52 4D 41 43 20 20 20-20 43 4F 4D 00 00 00 6B  .RMAC    COM...k
00F0  54 00 55 00 56 00 57 00-58 00 59 00 5A 00 00 00  T.U.V.W.X.Y.Z...

0080H〜00FFHはDMAバッファです。
ちょうどここに仮想ディスクドライブからディレクトリの1セクタが読み込まれています。
0080H〜と00A0H〜と00C0H〜の各32バイトに、同じファイル名PLILIB.IRLが書かれています。
その13バイト目を見ると、00、01、02になっていることがわかります。
実は先頭から16バイト目はデータのサイズを示しています。
最初の2つは80H(=128)で最後は5CH(=92)になっています。
これはセクタ数ですから、PLILIB.IRLのサイズは128+128+92=348セクタ(/8=43.5KB)であることがわかります。

それではこのファイルをOPENしてシーケンシャルREADで読み出す場合について考えてみます。
ディレクトリをサーチして目的のファイル名でエクステントbO0のFCBをみつけます。
そのブロックアローケーションエリアのブロックbキーにしてデータが格納されているセクタb算出して、データを順次読み出します。
8個のブロックの全部を読み出したら、次は同じファイル名でエクステントが01のFCBをサーチします。
この仕組みは実はシーケンシャルREAD(ファンクション14H)がオートマチックに行ないます。
ですからユーザーサイドでいちいちエクステントb調べて次をサーチする必要はありません。
当然のことながら、必要がない以上、エクステントbO0以外でファイルOPENを仕掛けてくるようなアプリケーションはないだろうと思って、そのようにプログラムしていたのでありますが。

どういう必要からそういうプログラムになっているのかはわからないのですけれど、とにかくエクステントを指定してファイルOPENをしようとするアプリケーションがでてきた以上、それに対応するしかありません。
で。
そのようにしましたところ、LINKが通るようになりました。

下はそのようにZB3DOSを修正したあと、コンパイルからLINK、実行まで行なったログファイルです。

D>dir dfact.*
D: DFACT    PLI
D>pli dfact


PL/I-80 V1.0, COMPILATION OF: DFACT


   NO ERROR(S) IN PASS 1

   NO ERROR(S) IN PASS 2


CODE SIZE = 00A5
DATA AREA = 0028
END  COMPILATION
D>dir dfact.*
D: DFACT    PLI : DFACT    REL
D>link dfact
LINK 1.0

F        0100   /SYSIN/  1BAD   /SYSPRI/ 1BD2   

ABSOLUTE     0000
CODE SIZE    1A54 (0100-1B53)
DATA SIZE    01E5 (1C28-1E0C)
COMMON SIZE  00D4 (1B54-1C27)
USE FACTOR     5E

D>dir dfact.*
D: DFACT    PLI : DFACT    REL : DFACT    COM : DFACT    SYM

D>dfact

Factorial(         0 )=                  1
Factorial(         1 )=                  1
Factorial(         2 )=                  2
Factorial(         3 )=                  6
Factorial(         4 )=                 24
Factorial(         5 )=                120
Factorial(         6 )=                720
Factorial(         7 )=               5040
Factorial(         8 )=              40320
Factorial(         9 )=             362880
Factorial(        10 )=            3628800
Factorial(        11 )=           39916800
Factorial(        12 )=          479001600
Factorial(        13 )=         6227020800
Factorial(        14 )=        87178291200
Factorial(        15 )=      1307674368000
Factorial(        16 )=     20922789888000
Factorial(        17 )=    355687428096000
Factorial(        18 )=
FIXED OVERFLOW (1)
Traceback: 0007 019F 0018 0000 # 2809 6874 0355 0141
End of Execution
D>


最初に
D>DIR DFACT.*[Enter]
でカレントドライブにサンプルプログラムDFACT.PLIがあることを確認しています。
このときにはソースプログラム以外はありません。
次に
D>PLI DFACT[Enter]
でコンパイルを実行し、その結果をまたD>DIR DFACT.*[Enter]で確認しています。
コンパイルが正しく終了した結果、カレントドライブにはソースプログラム(DFACT.PLI)からDFACT.REL(相対形式ファイル)が作成されました。
次に
D>LINK DFACT[Enter]
を実行し、その結果をまたD>DIR DFACT.*[Enter]で確認しています。
リンクが正しく終了した結果、カレントドライブにはDFACT.RELから実行プログラムDFACT.COMが作成されました。
最後に
D>DFACT[Enter]
でDFACT.COMを実行しました。
おお。
これは階乗(n!)ですね。
Factorialの意味を調べてみましたら、階乗でした。

こちらは実行したときの画面です。



ワンボードマイコンでCP/Mを![第433回]
2013.7.3upload

前へ
次へ
ホームページトップへ戻る