2015年01月20日の日記です


【追悼】森公一郎さん (LSI-C の作者)  2015-01-20 17:46:26  コンピュータ 今日は何の日

LSI-C の作者の方が一昨日亡くなった、という訃報を Twitter で読んだ


LSI-C ならずいぶんお世話になった、と詳細を読むと、LSI-C 80 の開発者だという。森公一郎さん。


アルバイトで一緒に開発を行った、という近藤嘉雪さんが訃報を伝えていた。


僕がお世話になったのは LSI-C 86 。80 は存在すら知らなかった。

しかし、86 は 80 の後に開発されたらしい。多分改良品なのだと思う。


というわけで、きっと僕もお世話になった方なのだ、と勝手に推察して思い出話など書く。




近藤さんによれば、LSI-C 80 は、参考にするものが無い状態で開発されたらしい。


もちろん、C言語を作るのだから、C言語の仕様書(K&Rかもしれない)などはあったのだろう。

C言語を使って、動作を確認することも出来たかもしれない。


でも、gcc など、今では手に入る「C言語処理系のソース」は入手できない状況での開発。


yacc とかは使えたのかな。

これが使えるとコンパイラを作るのはずいぶん楽になる。


もっとも、yacc は UNIX のツールで、メモリはふんだんにあるのを前提としている。

そもそもが、C言語自体が広いメモリと多数のレジスタを前提としている。


8080 で動作するように、CP/M で、64K のメモリで動作するように作った、というのだからすごいと思う。




現在でも、LSI-C 80 は製品として販売されているようだ。


もちろん、CP/M 用ではない。Windows などの現代の OS 上で動作し、8080 などのコードを生成する。

現在は Ver.3 だが、Ver.2 の時点で MS-DOS 用のクロスコンパイラだったようだ。


パソコンが 16bit の時代になっても、組込み用に 8080 や Z80 は使われていた。

クロスコンパイラに需要があるのだろう。



セルフコンパイルからクロスコンパイルに移行できた、ということは、コンパイラ自体もC言語で書いていたのだろう。


8080 上でC言語をC言語で書き、セルフコンパイルする。

…いや、それは難しいか。絶対無理とは言わないけど、開発効率が悪そうだ。


16bit マシン上で、8080 のコードを生成するコンパイラを作成し、16bit 環境からクロスコンパイルできるようにして、最後にコンパイラ自体を 8080 用にコンパイルしたのかもしれない。


そして、ver.2 の時に、同じソースを 8086 用のコンパイラにかけて(LSI-C 86 だろうか)、クロスコンパイル環境とする。

そうなると、森さんが作ったソースがまだ使われているのかもしれない。



#翌日追記:CP/M 上の BDS-C で開発されていたそうです。BDS-C は、1970年代からある 8080 用のC言語実装。

 詳細は最後に。




ネットで調べると使ったことのある方の話なども結構出てきて、「LSI-C 80 の生成するコード品質は異常」(に良い)だそうだ。

C言語と言う言語構造があまり 8080 向けではないのだが、それで品質の高いコードを生成するのだというからすごい。


先に書いたように、C言語で書いているのだとしたら、8080 上で動作するC言語を生成している、という時点でその品質は折り紙付きだ。


そして、ソースがCであれば、生成するコードの部分を作り変えたのが LSI-C 86 だったのではないかなぁ、と思う。




やっと LSI-C 86 の思い出話に入れた(笑)


当時はC言語は高価だった。安いものでも数万円から、信頼のある処理系なら10万円していた。

でも、LSI-C 86 は、「試食版」という名前のサブセットを、なんと無料で配布していた。


サブセットとはいっても、言語機能に特に問題はない。

テキストデータだけどマニュアルもちゃんとついてくる。


当時の MS-DOS は、8086 のメモリ管理にべったりだったので、メモリが 64K ごとに断片化していた。

C言語は本来「連続した大きなメモリ空間」を想定して作られているので、MS-DOS のCコンパイラでは「メモリモデル」という、複雑怪奇な仕組みを取り入れざるを得なかった。


コードとデータをあわせて 64K に収まるなら「タイニーモデル」。

コードとデータ、それぞれで 64K 以内、全体で 128K 以内なら「スモールモデル」。

コードは 64K 以内だけど、データが 64K 以上になるなら「ミディアムモデル」。

コードは 64K 以上だけど、データが 64K 以内になるなら「コンパクトモデル」。

コードもデータも 64K 以上なら、「ラージモデル」。

コードまたはデータが 64K 以上で、ポインタ比較などを使用する必要があるなら「ヒュージモデル」。


タイニーモデルで生成されるのが .COM ファイルで、これ以外は .EXE ファイルになる。




ヒュージの説明が必要だ。ラージとどう違うのか。


8086 では、64K 以上のアドレスが必要な場合は、2つのレジスタを足してアドレスを表現する。


もっと厳密に言えば、2つの16bit レジスタのうち、一つ(ベースと呼ぶ)は 4bit シフトしてから、もう一つ(オフセットと呼ぶ)はそのまま足す。

すると、20bit の結果が得られる。1Mバイトのアドレス空間だ。


一方、ポインタを比較しようとすると、基本的に「オフセット」をそのまま比較しようとする。

64K 以内なら、ベースは同じで、オフセットが違うだけ、のはずだからだ。



ところが、64K を超えると話がおかしくなってくる。

64K を超えたアクセスでは、ベースも頻繁に変わることになる。ポインタのインクリメント/デクリメントでいちいちベースを変えるのは面倒なので、普段はオフセットしか変えない。

しかし、いざベースを変えるときには、その時によって都合のよいベース値に変更される…


ここで、ポインタ比較が破綻することになる。



そこで、ヒュージモデルでは、ポインタを正規化する。

ベースを 16bit フルに使い、オフセットは必ず 0~15 、つまり下位 4bit しか使わないことにする。


インクリメント/デクリメントするたびに 4bit 境界のチェックが必要となり、速度は低下する。

しかし、これでアドレス比較は正しく行われるようになる。


これがヒュージモデルだ。

そもそも、MS-DOS でそんなに巨大なプログラムを作る必要がある時点で間違っている。

しかし、間違っていても必要な時はあるのだ。そんな時に、速度低下を覚悟で使うメモリモデルだ。



…さて、話を戻すと、LSI-C 86 も当然こうしたメモリモデルに対応していた。


でも、「試食版」では、スモールモデルしか使えなかった。

そして、もし生成物を配布するのであれば、対価を受け取らないこと、また LSI-C 86 試食版を使用したことを明記することが条件だった。




もっとも、普通のプログラムならスモールモデルで十分。

だって、コードとデータ併せて 128K って、その時点で 8bit 機の全メモリより大きなもの作れちゃうんだから。


当時は今のようにネット時代でもないし、多くの人は「自分のために」プログラムしているだけ。

そう考えれば、配布条件もたいした問題ではない。


だから、かなり多くの人が LSI-C 試食版のお世話になっていたはず。僕もその一人です。

と言っても、僕は X68k の人だったから、あまり MS-DOS は使ってない。


大学時代は電算機室に PC-98 がたくさん置いてあって、ある程度学生が自由に使えました。


#条件があって、講師の先生かティーチングアシスタントの大学院生、もしくは「マイコンクラブ」のメンバーが部屋にいないといけなかった。

 彼らなら、何かトラブルがあった時にすぐに対処できるから。

 でも、僕はそのマイコンクラブのメンバーだったから、自由に使えた。


学生が使うマシンにはハードディスクは付いてなくて、フロッピーディスク運用だったのだけど、当時は言語だってフロッピー1枚に収まることが多かった。

FORTRAN とか Pascal とか。


…でも、C言語ってライブラリが大きいから、フロッピーでの運用はちょっと辛い。

ところが、LSI-C 試食版はスモールモデルに絞ってあるから、フロッピー1枚に入るのね。


Comet の 98 移植版作ろうと思ってしばらく奮闘していたのだけど、学校で使っている時間だけだと思うように進まず、モチベーションが続かなくなってやめました (^^;


あと、Handy 98 と、HP200LX でも使っていた気がするな。

携帯機でコンパイル…というのが、実際には無駄なので、使えることに満足しただけだったように思うけど。



Windows の時代になってから、Java のプログラムをしていて「プリプロセッサが欲しい」と思って、LSI-C 試食版のプリプロセッサだけ使おうとしたこともありました。

まぁ、これは Windows のロングファイルネームに対応してなかったんで使えなかったのだけど、こういう時にすぐ思い出す程度には心に沁みついていた。




LSI-C の思い出はこの程度で、「今日は何の日」で、コンピューター関連のいろんな人の誕生日・命日などを書いている僕としては、訃報が伝えられた森公一郎さんの詳細が気になる。


名前で調べたらすぐにWEBページが見つかった。いつまで残されているかは不明だけど。


そこには、プロフィールとして次のように書かれていました。


年齢: 四つの'3'の日に生まれ、三つの'3'の日に33歳になった。牡羊座。


ディオファントスの墓碑のようです。


えーと、牡羊座は3月21日から4月20日。

3が多いのですから、3月30日か31日、または 23日が誕生日なのでしょう。


生年月日ですが、生まれ年に後二つの「3」が必要です。

1933年だとしたら、33年後は 1966 年。3がありません。


ここは、「昭和」33年でしょうね。1958年。

すると、33年後は 1991年。平成3年です。


恐らく、1958年3月23、30、または 31日生まれ。

56歳で亡くなられたのは、まだお若いです。


しかし、WEB ページを見ると人工透析を受けていることも書かれているので、恐らく腎臓の病で闘病しておられたのでしょう。


プログラマとしての偉大な先人の御冥福をお祈りします。




以降は翌日追記


LSI-Cに思い出のある方は多かったようで、想像以上に多くの方からの反響がありました。

上の記事はすでに修正していますが、当初「C言語は広いメモリと多数の32bitレジスタを前提とし…」と書いていましたが、これは勘違いです。


それ、gcc の最適化の前提条件だ。個別の実装系の話で、C言語全体の話ではありませんでした。


ちなみに、最初にC言語が作られた PDP-7 は 18bit マシン。PDP-11 は 16bit マシンです。

そのため、C言語自体は当初から特定のレジスタ幅を前提にはしていませんでした。


#とはいえ、PDP-11 のようなアーキテクチャを念頭に設計していた節はあります。


#18bit が中途半端に思える人は、TX-0の話読んでね。

 TX-0 を元に PDP-1 が作られ、その後継機が PDP-4 、PDP-7 です。PDP-11 は全く別の機械。

 PDP は開発順に番号が付いているので、系統がわかりにくいです。




日記に、BDS-C を使って CP/M 上で LSI-C を作ったとある、と指摘がありました。

はてなで日記を付けている、と氏のページにあったのですが、見に行った時点で非公開になっていました。


いま情報の裏を取ろうと InternetArchive を少し探しましたがどこにあるかわからず。

しかし、おそらくC言語で作ったのだろうなぁ、と思っていたのが裏付けられたので情報信じます(笑)


C言語使わずに 8080のアセンブラでいきなり書いていた、とかだと、LSI-C 86 とも、現在の LSI-C 80 とも無関係になってしまうから。

自分の思い出(LSI-C 86)につなげたかったのもありますし、氏が亡くなってもソースは受け継がれている、と思いたかったのもありました。




当初、当時のC言語は10万円位するのが普通だった、と書いていました。

TurboC や QuickC はもっと安かったよ、という指摘がありました。

うん、そうだったかも。


実は TurboC の DOS 版は購入して今でも持っています。社会人になって、Windows の時代になってから、安売りされていたのを買ったのだけどね。

安売りとはいえ、元が10万円していたら、当時の僕が手を出せないくらいの値段だったでしょう。


それでも、LSI-C 試食版が無料、というのは驚きでした。

当時の趣味プログラマーに大きな影響を与えたと思います。




「LSI-C 80 のコード品質が異常に良い」というのは言い過ぎではないか、という指摘がありました。

これはね、本文中にもあるように、実際のところは LSI-C 80 は使ったことないからわからないのよ (^^;

ただ、そう評価している人が居たからそのまま書いただけで。


各種評価ある中で、自分が思い入れがあるから「一番良い評価」を選んだのはあります。


ネットで見つかるいろんな人の話を読むと、レジスタの使い方が上手かったようです。

普通は変数はメモリに割り当てるわけですが、8080 はメモリアクセスが遅い。


そこで、一部の変数をレジスタに直接割り振るわけです。

まぁ、ここら辺のことは他のC言語でもやっていること。


興味深いのは、8080 ではレジスタごとに「使える命令」が違っていて、変数を単純にレジスタに割り振るだけでは無理が出てしまうのに、どうやっていたのかな、というところですね。

ここら辺、僕は使っていないので知らない。


そして、こちらも寄せられた情報ですが、LSI-C 80 では関数の呼び出し時に、引数をレジスタ渡しするそうです。


C言語の関数を呼び出す際は、一般的には引数をスタックに積んでから呼び出します。

でも、8080 では先に書いたようにメモリが遅いし、そもそもスタックが 16bit 単位でしかアクセスできない、という制約があります。


そのための工夫なのでしょう。

多分「品質が異常に良い」と評価していた人も、ここら辺の工夫を褒めていたのではないかな、と思います。



#引数をスタックに積んで…で、またツッコミが入りそうなので牽制。

 SPARC のことはもちろん知っていますし、printf("%d %d",a++,a++) の結果が処理系依存なのも承知。




MSX にも MSX-C というものがあったのですが、実は LSI-C 80 の OEM 版なのだそうです。


情報を頂いて裏を取ったら、詳細を書いているページを見つけました。


MSX-C のバイナリをダンプすると、LSI JAPAN のコピーライト表示が埋め込まれているとか。


MSX の CPU は Z80 だと決められているにも関わらず、8080 でも実行できるコードを生成するのだとか。

MSX 用に Z80 や R800 のコードを生成するようにする、後付けの「オプティマイザ」も有志の手で開発されていたようです。





同じテーマの日記(最近の一覧)

コンピュータ

今日は何の日

関連ページ

森公一郎 命日(2015) レイ・ドルビー誕生日(1933)【日記 16/01/18】

1988年のパソコン事情【日記 16/03/05】

1988年のパソコン事情【日記 16/03/05】

リロケータブル【日記 17/11/27】

別年同日の日記

06年 ウッドデッキ完成

07年 人生初ギャグ?

13年 ピクミン

17年 1996年のそのほかのゲーム


申し訳ありませんが、現在意見投稿をできない状態にしています

【BDS-C使い】 LSI C-80(CP/M)のOEM変化形のMSX-Cになりますが、BDS CやHI-TEC C(CP/M)でコンパイルしたものよりMSX-Cでコンパイルしたもののほうがサイズが小さくなるので最適化がすごいのは事実だと思いますよ。計測まではしてませんが多分速度も速いでしょう。ただし、8ビットOSでコンパイルする場合はMSX-C(多分本家のLSI C-80も)ではメモリが足らずにコンパイルエラーになることが多いし、8ビットマシン実機ではコンパイル速度がものすごく遅かったです。BDS Cのほうが実用的と個人的に感じました。ただし、LSI C-80のMS-DOS版ではそれらの欠点は感じませんでした。おそらく今のWindows版のLSI CはZ80開発には最強レベルでしょうね。ただしZ80が衰退した現在となるとLSI CのWindows版は有料なのでお金を出して買う人は少ないでしょう。BDS C(CP/M)、HI-TECH C(CP/M)は無料でエミュレーターでWindowsでも動き、他にも無料のz88dk(Windows等)、SDCC(Windows等)がありますし。 (2017-04-01 19:16:32)

【ななし】 JavaScriptのyaccを探していたらkmyaccが対応していると見つけて、二十数年ぶりにお名前を見て、でもウェブの更新がとまっているので心配していました。商用C言語コンパイラ実装者の末席のひとりとして、先達の業績には尊敬の念しかありません。ご冥福をお祈りいたします。 (2015-02-07 15:48:43)

【名無し】 MSX C ver 1.1 のパーサとコードジェネレータには"Copyright (C) 1985 by LSI JAPAN Co., Ltd."の文字列が埋め込まれてます。 (2015-01-24 13:14:13)

【中の人】 LSI-C86はLSI-C80を使って bootstrap していました、LSI-C80は最初はBDS-Cでbootstrapしていましたがある程度動き始めたら自身でコンパイルして最後は gcc と同様に自身で生成と言う開発を行っていました。 (2015-01-23 19:59:10)

【名無し】 >MSX-C のバイナリをダンプすると、LSI JAPAN のコピーライト表示が埋め込まれているとか。 手元のMSX-C ver 1.20pのパーサ(CF.COM)とコードジェネレータ(CG.COM)を確認してみましたがアスキーの版権表示があるのみでそのようなものは見当たりませんでした。バージョンに拠るのかもしれませんが…。 (2015-01-23 04:07:06)

【G-SHOES】 思い出深いのは,引数の引き渡しを可能な限りレジスタで行おうとしたコンパイラだったので,出来るだけ引数を少なく,短いビット長で行うように関数仕様を検討していました。16nitの引数を3つも4つも引数にすると間違いなくスタック経由になり,速度が撃オチです。そこで関数を分ける,逆に統合するなどの工夫をやっていたことを思い出します。森さんのご冥福をお祈り致します。 (2015-01-22 08:19:26)

【G-SHOES】 LSI-C80を仕事で使っていた人です。確かにいいコードを生成してくれるので信頼して使っていました。当時のZ80のCコンパイラは正直中途半端で,LSI-Cを使えば遅いCPUでも,小さいメモリでも,なんとか乗り切れた事が多く,極論するとコスト削減に貢献してくれていたということになります。 (2015-01-22 08:14:07)

あきよし】 おぉ、多数の指摘ありがとうございます。PDP-11が16bitだったのはご指摘の通りで、勇み足でした。他の件も含め、後で記事修正しておきます。 (2015-01-21 11:14:19)

【名無し】 「LSI-C 80 の生成するコード品質は異常」(に良い)というのはちょっと大袈裟ですね。生成されるコードのサイズや実行効率的にアセンブラの代わりになる程のものではなく、当時の他のコンパイラ製品と比べてレジスタの使い方が効率的だった、くらいの説明が適当だと思います。 (2015-01-21 05:03:49)

【名無し】 >当時はC言語なんて十万円くらいするのが普通で、 10万とかいい値段がするのはLettice-CやWhitesmith-C、MS-Cなんかで、TurboCやQuickC等安価な製品も存在しました。 (2015-01-21 00:11:42)

【名無し】 >8080 上でC言語をC言語で書き、セルフコンパイルする。 …いや、それは難しいか。絶対無理とは言わないけど、開発効率が悪そうだ。 日記に「80年代の初めに、BDS-CをつかってCP/MでLSI-Cを書いていました。」と書かれてますよ。 (2015-01-21 00:07:27)

【名無し】 >そもそもが、C言語自体が広いメモリと 32bit の多数のレジスタを前提としている。 C言語の起源が16bitのPDP-7だかPDP-11だかその辺なのでその説はおかしい。 (2015-01-20 23:54:31)


戻る
トップページへ

-- share --

73000

-- follow --




- Reverse Link -