プログラミング
Am29000用CコンパイラとWebブラウザを開発した方法
How I developed an Am29000 C compiler and web browser (nanochess.org)
要約
筆者は1998年から1999年にかけて、Am29000プロセッサ向けのCコンパイラとWebブラウザを開発しました。当初はマシンコードでの開発に限界を感じ、既存のコンパイラ(GCCなど)の利用を試みましたが、当時のPC環境ではリソース不足でした。最終的に、Transputer用Cコンパイラを基盤とし、動的メモリ割り当てや構造体を用いた表現ツリーの改良を経て、Am29000向けのコードジェネレータを実装しました。
全文翻訳
メインページ Intel 8080エミュレータ チェスプログラム コンテスト ストア レトロゲーミング FAQ リンク 私について スペイン語で見る
Am29000用CコンパイラとWebブラウザを開発した方法 by Oscar Toledo G. 2026年8月16日
以前の記事を読んでいただければ、Am29000プロセッサをベースにした自作コンピュータのために32ビットマシンコードでウィンドウオペレーティングシステムを開発したことをご存知でしょう。この記事では、これらのプロセッサ向けのCコンパイラとWebブラウザの開発についてお話しします。期間は1998年のクリスマスから1999年の私の誕生日まででした。私は20歳で、インターネットはメキシコで爆発的に普及し、ブルース・ウィリスは巨大な小惑星から地球を救い、黎明期のインターネットには新しいキャリア(グラフィックデザイナーにとって豊作の年でした)が登場し、人々は2000年問題がデジタル終末を引き起こすのではないかと恐れていました(シンプソンズでホーマーがコンピュータのアップデートを忘れるエピソードさえありました)、そしてアーノルド・シュワルツェネッガーはEnd of Daysで弾丸で悪魔を殺していました。
Cコンパイラを見つける
1997年、私はいくつかのユーティリティ、プリンタドライバ(HP DeskJet 500を持っており、Epson Stylus 600でカラー印刷を管理しました)、さらにはモデムカードを使ってファックスを送受信することさえ管理しました。誰もが広告を送るためにファックス機を持っているか、情報を得るために尋ねていた時代でした。私たちはファックス機を購入しましたが、翌年には誰もファックスを求めなくなりました。Eメールへようこそ!とにかく、マシンコードでの作業は困難で、泥水に深く潜るようなものでした。下を見るためのゴーグル(アドレスに関するメモや一部のドキュメント)を手に入れない限り、ますます迷子になります。ティーンエイジャーのエネルギーをすべて使っても、慎重なメモリ計画、スペースを作るためにコードを移動する方法、あるいはさらに悪いことに、1つの変更を見逃したために複数のジャンプを再配置して予期しないバグを導入することを考案せずに新しい関数をコーディングできなかったため、疲れ始めました。ある時点で、「これは成長できる」と思っただけで、コード内にはさらなる拡張のために5から10のNOP命令のシーケンスが見つかります。また、元の場所には収まらなかったため、場所から外れたルーチンも見つかります。
私はすでにインターネットカフェ(メキシコではサイバーカフェとして知られています)の常連でした。最初のインターネットカフェの1つは、今はなきBazar Pericoapaの向かい側にあり、コーヒーも提供していました。「Ciega, sordomuda」、「Amor de papel」、「Laura no esta」、「Barbie girl」のリズムでインターネットを閲覧しました。もちろん、カプチーノやエスプレッソがキーボードにこぼれたため、すぐに間違いを認識し、コーヒーは二度と提供されませんでした。
私はAm29000プロセッサに関するあらゆるものを検索していて、High-C 29kコンパイラとAm29000をサポートするGNU Cコンパイラv2.8.1について知りました。High-C 29kコンパイラを購入する方法がなかったので、GCCソースコードしかダウンロードできませんでした。そして、それは私のコンピュータがわずか512 KBのRAMしか持っていなかったのに、コンピュータに少なくとも2 MBのRAMが必要でした(仮想メモリを考えると、おそらくそれ以上)。さらに悪いことに、FlexとBisonという2つの追加プログラムが必要でした。また、私がほとんど持っていなかった基盤となるオペレーティングシステムからの多くのサポート(アセンブラとリンカに加えて)も必要でした。コンパイラを何とかブートストラップする必要がありましたが、単一の使用のために2つの大きなプログラムをポートすることには全く乗り気ではありませんでした。
そこで、私はより身近な銀河に頼りました。それはTransputer用のCコンパイラです。私の主な問題は、多くのレジスタを持つAm29000プロセッサのアーキテクチャが完全に異なることです。シングルパスコンパイラでレジスタをどのように割り当てるか理解できませんでした。通常の変数はローカルレジスタに保持できることが非常に重要でしたが、単一の間接参照(たとえば、&a)が発生した場合、その変数はメモリに保持されるべきでした。
私の最初の試みは、Small-CコンパイラをAm29000にポートすることでした。1997年12月のデイリーログにメモを残したので、それをやったことは知っています。おそらくそれは完全な失敗で、有用性に欠けていたため、それ以上の言及はありません。再び1998年2月2日、私は緊急にCコンパイラが必要だと述べ、開発を助けるために80486 PCにDJGPP(MS-DOSにポートされたGCCコンパイラ)をインストールしました。TransputerはオンボードRAMが128 KBしかなかったため、使用できませんでした。DJGPPはDJ G++の略です。コンパイラがまだ高価で販売されていた頃、DJ Delorieが世界中の開発者にどれほど助けになったかは言えません。この人物は、すぐに動作するGNU C++コンパイラのDOS版を作成しました。
木にコンパイラを育てる
1998年5月6日まで、私はTransputer用Cコンパイラのソースコードを取り、テストとしてDJGPPでコンパイルすることに成功しました。これは、標準Cライブラリ関数で非標準の入出力関数を置き換える必要があったことを意味します。私のデイリーログにはそれ以上の情報は含まれていませんでしたが、さらにデータを検索しているうちに、Am29000 Cコンパイラ作成の全ステップをフロッピーディスクに保存していたことがわかりました。Am29000 Cコンパイラの進捗状況を示すフロッピーディスクの写真がここにあります。SCCS(Source Code Control System)について読んでいたため、ソースコード管理について漠然とした考えを持っており、私のアプローチは「毎日のファイルをすべてフロッピーディスクにコピーする」でした。このフロッピーディスクには、強化されたTransputer Cコンパイラが2つと、Am29000 Cコンパイラの最初のバージョンが含まれています。このTransputer Cコンパイラは、PCマシンで元のTransputerと同じように動作するようになりました。ツリー式は配列に保持されていました。左ノードを指す配列、右ノードを指す配列、ノード値を格納する配列、ノードタイプを格納する配列です。もちろん、これは配列を必要に応じて拡張しないと複雑な式を作成できないことを意味します。このコンパイラは、Transputer gitのcc0ディレクトリで見つけることができます。これは、配列としての式ツリーのコード抜粋です(関数crea_nodo):
++ultimo_nodo;
if(ultimo_nodo == TAM_ARBOL) {
error("Expresión muy compleja");
cancela();
}
nodo_izq[ultimo_nodo] = izq;
nodo_der[ultimo_nodo] = der;
oper[ultimo_nodo] = op;
esp[ultimo_nodo] = val;
regs[ultimo_nodo] = 0;
regsf[ultimo_nodo] = 0;
私はゆっくりと計画を作成しました。Am29000コードジェネレータを作成する唯一の方法がありました。関数全体をメモリに解析する必要があり、そうすればローカルレジスタの数を知り、ローカル変数への参照を検出し、レジスタアロケータを構築できるでしょう。次に、動的メモリ(malloc/free)と構造体を使用して式ツリージェネレータを再設計しました。これはまだTransputer用でした(cc1ディレクトリを参照)。メモによると、休憩時間にはTomb Raider 2のデモもプレイしていました。これは、ノード作成コードがどのように変更されたかのコード抜粋です:
ultimo_nodo = malloc(sizeof(struct nodo));
if (ultimo_nodo == NULL) {
error("Expresión muy compleja");
cancela();
}
/* ... */
ultimo_nodo->izq = izq;
ultimo_nodo->der = der;
ultimo_nodo->oper = op;
ultimo_nodo->esp = val;
ultimo_nodo->regs = 0;
ultimo_nodo->regsf = 0;
このコードは元のコードよりもはるかに読みやすく、利用可能な総メモリによってのみ制限されます。
1998年5月13日、私はついに決心し、関数全体をツリーを持つ中間表現に保存するためのメインパーサーの作業を開始しました。ステートメントのシーケンスは連結リストになり、ネストされたステートメントはリストのブランチになりました。この時風邪をひき、レーザーディスクでジェイソン・スコット・リー主演の「ジャングル・ブック」を見ました。回復後、すぐにAm29000プロセッサのコードジェネレータを作成しました。ポート全体で2週間以上かかり、コードジェネレータのためにいくつかの小さなテストを行う必要がありました。たとえば、これはTransputerのコードジェネレータです:
/* ** Codigo para cada operador binario, y algunos unarios. */
gen_oper(oper, rev)
int oper, rev;
{
if (oper == N_NULO) return;
if (oper == N_CUENTA) emite_linea("wcnt");
else if (oper == N_OR) emite_linea("or");
else if (oper == N_XOR) emite_linea("xor");
else if (oper == N_AND) emite_linea("and");
else if (oper == N_IGUAL) {
emite_linea("diff");
emite_linea("eqc 0");
} else if (oper == N_SUMA) emite_l