YAMAGUTIseisei wrote:
> PR : シンギュラリティ系有料メールマガジン発行を構想致しております
> 無料メールマガジン版 ( 別途有料版開始時打切 )
> http://mailux.com/mm_dsp.php?mm_id=MM53D8AF3589BC7
> 
> 
> 
>Google 翻訳 http://webcache.googleusercontent.com/search?q=cache:mazonka.com/st/lcss.pdf#iT0urchwkbIJ
> 
> ページ1
> 
> 
> ? Subleqに基づく単純な ry
> Subleq ベースのシンプルなマルチプロセッサコンピュータ
> 
> 
> Oleg MazonkaとAlex Kolodin
> mazonkaATgmail alex.kolodinATgmail
> 
> 2011年5月(改訂3、草案8)
> 
> 
> 
> 抽象
> 
>? Subleq(結果の減算と分岐は0より小さいか等しい)は、命令セットコンピュータ(OISC)の命令 ry 言語の両方です。
>Subleq ( 減算 ( Subtract ) しそして結果が 0 より小さい ( Less than ) か等しい ( Equal ) ならば分岐 ( Branch ) ) は 1 命令セットコンピュータ ( One Instruction Set Computer , OISC ) の、命令セットとプログラミング言語との両方です。
> 我々は、低コストFPGAボード上に28個の1命令Subleqプロセッサのアレイをハードウェアで実装することについて説明します。
> 私たちのテスト結果は、Subleq OISCマルチプロセッサの計算能力は現代のパーソナルコンピュータのCPUの計算能力に匹敵することを示しています。
> さらに、Cスタイルの言語からSubleqまで、コンパイラの実装の詳細を提供します。
> 
> 内容
> 
>  1. はじめに   .       .       .       .       2
> 2. Subleqアセンブリ言語   .       .       .       3
>  3. ハードウェア設計       .       .       .       .       6
>    3.1 概要  .       .       .       .       6
>    3.2 インタフェースの説明  .       .       7
>    3.3 Subleqプロセッサ .       .       .       7
> 4. Subleq用のCコンパイラ  .       .       .       8
>    4.1スタック .       .       .       .       8
>    4.2 式   .       .       .       .       10
>    4.3 関数呼び出し      .       .       .       11
>    4.4 スタック変数      .       .       .       14
>    4.5 掛け算 .       .       .       .       15
>    4.6 条件ジャンプ      .       .       .       16
> 5. 結果      .       .       .       .       .       17
>    5.1 テスト#1       .       .       .       17
>    5.2 テスト#2       .       .       .       18
> 6. 結論      .       .       .       .       .       19
> 7. 付録      .       .       .       .       .       21
> ?  7.1 Cと乗算 ry
>    7.1 乗算ありの C     .       .       .       21
>    7.2 乗法なしのC      .       .       .       21
>    7.3 Subleqコード   .       .       .       22
> 参考文献       .       .       .       .       .       23
> 
> 
> ?1?
> 
> ページ2
> 
> 
> 1. はじめに
> 
> ? ry 、命令数が1に減少します。
> OISC(One Instruction Set Computer)は、従来のCPUを搭載した究極のRISC(Reduced Instruction Set Computer)であり、命令数が1に縮小されています。
> ? ry 、オペコードの必要性がなくなり、より ry 要素が可能になり、同じ数の論理 ry ウェアでより多くの命令を実装することが可能になる。
>利用可能なプロセッサ命令が1つだけである事はオペコードの必要性を抹消しそして、より単純な計算要素を許容、従ってより多くのそれらを実装する事を、論理ゲートを同数有したハードウェアで可能とする。
> 我々の目標は、単一の低コストプログラマブルチップ上に可能な限り多くのプロセッサを備えた機能的なマルチプロセッサシステムを構築することだったので、
> OISCは自然な選択であり、残りのステップは適切なシングルプロセッサ命令セットの選択であった。
> 
> 現在知られているOISCは大きく3つの大きなカテゴリーに分けることができます。
> 
> ? 1.トランスポートされたアーキテクチャのマシン。
>  1.転送トリガ型アーキテクチャのマシン。
> ? ビット操作機械; 2。
>  2. ビットマニピュレーションマシン ; 
>  3.算術ベースのチューリング - コンプリート・マシン。
> 
> トランスポートトリガアーキテクチャ(TTA)は、計算がデータ転送の副作用である設計です。
> 通常、共通アドレス空間内のいくつかのメモリレジスタ(トリガポート)は、命令がそれらを参照するときに割り当てられた動作を実行します。
> 例えば、単一メモリ対メモリコピー命令[1]を利用するOISCでは、書き込み時に算術および命令ポインタジャンプを実行するポートをトリガすることによってこれが行われる。
> 魅力的な単純さにもかかわらず、このようなOISCには2つの大きな欠点があります。
> 第1に、CPUは、トリガポートを制御する別個の機能ユニットを有する必要がある。
> 第2に、2つの異なるハードウェア設計は2つの異なるアセンブリ言語を使用する可能性が高いため、設計の一般化は困難です。
> ? ry 、このクラスのOISCは実装されていませんでした。
> これらの欠点のため、このクラスの OISC を我々の実装として除外しました。
> 
> Bit Manipulating Machinesは最も簡単なクラスです。
> ? ry 、命令[2]のオペランドの1つで指定されたアドレスに無条件に実行を渡します。
> BitBitJumpと呼ばれるビットコピーマシンは、メモリ内の1ビットをコピーし、命令のオペランドの1つで指定されたアドレスに無条件に実行を渡します [2] 。
> このプロセスは、普遍的な計算が可能であることが判明している(すなわち、
> ? ry でき、他の普遍的なマシンを解釈する ry コピーすることにより、実行されるコードを条件付きで修正することができるからである。
>任意のアルゴリズムを実行することができ、そして任意の他のユニバーサルマシンをインタプリトすることができる)。なぜなら、ビットをコピーすることにより、コードを実行に先立って条件付きで修正することができるからである。
> Togaコンピュータと呼ばれる別のマシンは、ビットを反転し、反転の結果に応じて条件付きで実行をパスします[3]。
> BitBitJumpに似た、さらに別のビット演算マシンは、同時にいくつかのビットをコピーします。
> ? ry 、計算上の汎用性の問題が解決される[4]。
> この場合、あらかじめ定義されたジャンプテーブルをメモリに保持することにより、汎用的計問題が解決される[4]。
> ビット操作マシンの単純さにもかかわらず、安価なFPGAで普通に利用可能なメモリよりも多くのメモリを必要とするため、我々はそれらを排除しました。
> ? ビット操作操作で機能 ry 。
> ビットマニピュレーションで機能するマルチプロセッサマシンを作成するには、プロセッサあたり少なくとも1Mbのメモリが必要です。
> したがって、私たちは、より少ないメモリを持つより複雑なプロセッサーが私たちの目的にとってより良い選択であると判断しました。
> 
> 
> ?2?
> 
> Page 3
> 
> 
> 算術ベースのチューリング完結型マシンは、算術演算と条件付きジャンプを使用します。
> ? ry の以前のクラス ry 、このクラスは普遍的なものであり、抽象的表現ではチューリング完全です。
> ユニバーサルコンピュータである2つの前述のクラスの様ではなく、このクラスはユニバーサルな、そして抽象的表現に於ての、チューリング完全です。
>? ry 、メモリ内のアドレス ry 。
>命令は、メモリ内アドレスであってもよい整数で動作する。
> ? ry 、異なる算術演算[5]に基づいて、このクラス ry のOISCが存在する。
> 現在、異なる算術演算に基づいた、このクラスのいくつかの既知の OISC が存在する [5] 。
> ? 追加? Addleq、減少? DJN、増分? P1eqと減算? Subleq (結果の減算と分岐は0より小さいか等しい)。
> 加算 - Addleq、デクリメント - DJN、インクリメント - P1eq 、そして減算 - Subleq ( 減算そして結果が 0 より小さいか等しい際に分岐 ) 。
> 後者は最も古く、最も一般的であり、間違いなく最も効率的である[6] [7]。
> ? ry .2つは減算用、2つは条件ジャンプ用です。
> Subleq命令は3つのオペランドで構成されています.2つは減算用、1つは条件ジャンプ用です。
> 
> ? Subleqの周りにハードウェアを ry 。
> Subleq 系にハードウェアを構築しようとする試みは以前から行われていました。
> 例えば、David A RobertsはSubleq CPUを設計し、ソフトウェアSubleqライブラリ[8]を書いた。
> 彼の実装は、キーボード入力、端末、制御ROM、および16MbのRAMを備えた単一のCPUであり、私たちよりはるかに複雑です。
> さまざまなインターネットサイトで記述された他の同様のデザインがいくつかありました。例えば[9]。
> しかし、それらのすべては、実用的な実装がなされていない概念実証シミュレーションでした。
> 
> 以下のセクションでは、構築したシステムのコンポーネントについて説明します。
> 第2節では、Subleq抽象機械とそのアセンブリ記法を概説する。
> セクション3では、マルチプロセッサコアのハードウェア実装について説明します。
> セクション4では、高水準プログラミング言語をSubleq命令コードに変換するために使用される手法について簡単に説明します。
> セクション5と6では、デバイスのスピードテスト結果を比較し、ディスカッションと要約を示します。
> 付録では、階乗を計算するコードがCおよびSubleqの表記法で示されています。
> 
> 
> Subleqソフトウェア< - USB - >ドライバ、プログラミング環境
> 
> 図1 FPGAボードはUSBケーブルでPCに接続
> 
> 
> 図1は、USBケーブルを使用してデバイスとコンピュータを接続した状態を示しています。
> 
> 2. Subleqアセンブリ言語
> 
> Subleq抽象機械は、各セルが整数を保持する無限のメモリ配列上で動作する。
> この数は、別のメモリセルのアドレスとすることができる。
> 番号は0から始まります。
> ? プログラムは、アドレスゼロで第1の命令を用いてメモリから読み出された一連の命令として定義される。
> プログラムは、 0 番地にある最初の命令からメモリより読出されたシーケンスとして定義される。
> Subleq命令には3つのオペランドがあります。
> 
>    A B C
> 
> ? 1つの命令ABC ry 。
> 1 つの命令 A B C を実行すると、Bに格納されたアドレスのメモリセルの内容からAに格納されたアドレスのメモリセルの値が減算され、その結果がBのアドレスのセルに書き戻されます。
> Bの減算後の値がゼロ以下の場合、実行はCで指定されたアドレスにジャンプします。 さもなければ、実行は次の命令、すなわちCに続くメモリセルのアドレスに進む。
> 
> 
> ?3?
> 
> Page 4
> 
> 
> アセンブリ記法は、Subleqでコードを読み書きするのに役立ちます。
> 構文は次のとおりです。
> 
>    ? ラベル;
>    ? 疑問符;
>    ? 縮小命令;
>    ? マルチ命令;
>    ? リテラルと式。
>    ? データセクション。
>    ? コメント。
> 
> ラベルは、コロンが後に続く特定のアドレスの記号的な名前です。
> 次の例では
> 
>      A   B C
>    A:2 B:1 0
>    C:B   B 0
> 
> 各行は3つのオペランドを持つ1つの命令を表します。
> ここで、A、B、Cは抽象名ではなく、メモリ内の特定のセルのラベル(アドレス)です。
> たとえば、ラベルAは4番目のセルを参照し、値2で初期化されます。
> ? 最初の命令は、セルBの値からセルAの値を減算し、その値を1とし、結果をセルBに格納します。この値は-1になります。
> 最初の命令は、セル A の値をセル B の値、その値 1 から減算し、結果をセルBに格納します。それは -1 になります。
> 結果はゼロより小さいので、値Cは第3行の命令の第1オペランドのアドレスであるため、次に実行される命令は第3行である。
> これはBからBを減算してゼロにするので、実行はアドレス0に渡されます。
> これらの3行がプログラム全体である場合、最初の命令の第1オペランドはアドレス0を有する。
> この場合、実行はB -2となる最初の命令に戻される。
> そのプロセスは永遠に続く。
> 実行される命令は1行目と3行目のみであり、セルBの値は1、-1、0、-2、0、-2、0などのように変化します。
> 
> 疑問符はメモリ内の次のセルのアドレスとして定義されます。
> 
>    A B ?
>    B B 0
> 
> ? ?と同じです
> は以下と同じです
> 
>    A B C
>    C:B B 0
> 
> ? 命令フォーマットの縮小は便利 ry 、つまり? 
> 縮小命令フォーマットは便利なショートカットです:3つではなく2つのオペランドが次の命令のアドレス、つまり ; ? 、
> ? 1つのオペランドだけが第2のものを第1のものと同じであるとみなすので、
> そしてオペランド 1 つだけだと第 2 のものを第 1 のものと同じであるとみなすので、
> 
>    A
> 
> ? ?と同じです
> は以下と同じです
> 
>    A A
> 
> 
> ?4?
> 
> Page 5
> 
> 
> ? ?と同じです
> そして以下と同じです
> 
>    A A ?
> 
> 同じ行に複数の命令が置かれている場合は、最後の命令にセミコロンが続く必要があります。
> ? 次のコードは、
> 次のコードは値をA から B へコピーします:
> 
> ?  AからB:Z; B; AZ; ZB
>    Z; B; A Z; Z B
> 
> A:72のような整数はコード内の定数として使用されます。
> リテラルは、ASCII値を仮定して整数の代わりに使用できます。
> たとえば、A: 'H'はA:72と同じです。 A: "Hi"はA: 'H' 'i'と同じです。
> 加算、減算、括弧、および単項マイナスを式で使用できます。
> ?  ZZ←+3 ABCDEF
> コード
> 
>    Z Z ?+3
>    A B C
>    D E F
> 
> は、Zをゼロに設定し、第3の命令DE Fにジャンプする。
> 
> ? 命令を減らすことができるため、アセンブラは3つのオペランドで完全な命令を生成するタイミングを知る必要があります。
> 命令を縮小できる為、アセンブラは 3 オペランドな完全な命令をいつ生成するかを知る必要があります。
> このような生成を避けるために、行頭のピリオドが使用されます。
> したがって、プログラムデータはそのような行に置くことができます。
> コード
> 
>    A A ?+1 
>    . U:-1 
>    U A 
> 
> ? Aに1を ry 。
> は A に 1 を設定します。
> 2行目にピリオドがないと、コードは次のように解釈されます。
> 
>    A A ?+1 
>    U:-1 (-1) ? 
>    U A 
> 
> コメントはハッシュ記号#で区切られています。#から行末まではすべてコメントです。
> 負のアドレスにジャンプすると、プログラムが停止します。
> 第3オペランドとして通常は(-1)を使用してプログラムを停止します。たとえば、次のようになります。
> 
>    #停止
>    Z Z  (-1)
> 
> 3番目のオペランドであることを示すためには、(-1)の前後のかっこが必要です。したがって、命令は次のように解釈されません。
> 
>    Z Z-1 ?
> 
> ? プログラム ry 。
> Subleq プログラムをインタラクティブにする(データを要求して作業中にユーザに応答する)ために、入力および出力動作は、存在しないメモリセルに対する動作として定義することができる。
> これには同じ(-1)アドレスを使用できます。
> 第2オペランドが(-1)の場合、第1オペランドの値が出力になります。
> 第1オペランドが(-1)の場合、第2オペランドは入力ストリームから値を取得します。
> 入出力操作はバイト単位でASCIIコードで定義されています。
> プログラムが255より大きい値を出力しようとすると、その動作は未定義です。
> 
> ? ry [10]の「Hello ry 。
> 以下はLawrence Woodman helloworld.sq [10] から適応させた「Hello world」プログラムです。
> 
> 
> ?5?
> 
> Page 6
> 
> 
> これは非常に簡潔ですが、Subleq効率の良い例です。
> 
>    L:H (-1); U L; U ?+2; Z H (-1); Z Z L
>    U:-1 H:"hello, world\n" Z:0   こんにちは、世界\ n
> 
> Subleqでは、Zと呼ばれる特別な変数が非常に小さな範囲内で中間の一時変数として使用されることがよくあります。
> ? ry 、使用ごとに0 ry 。
> 通常、この変数はゼロで初期化され、毎使用後に 0 になっていると仮定します。
> 
> 上記のプログラムは5つの命令で構成されています。
> ? The first instruction prints the character pointed by its first operand (the first pointer) which is initialised to the beginning of the data string ? the letter 'h'.
> ? ry が指す文字を出力します。文字 'h'。
> 最初の命令は、データ文字列の先頭に初期化された最初のオペランド(最初のポインタ)が指す文字 -  'h' を出力します。
> ? The second instruction increments that pointer ? the first operand of the first instruction.
> ? ry ポインタをインクリメントしますか? 最初の命令の最初のオペランド。
> 2番目の命令はそのポインタ -最初の命令の最初のオペランド- をインクリメントします。
> 第3の命令は、第4の命令の第2のオペランドである第2のポインタをインクリメントする。
> ? ry テストし、値が ry 。
> 第4の命令は、第2のポインタが指す値をテストし、その値がゼロであるときにプログラムを停止させる。
> ? ポインターがZ:0のデータストリングの終わりの後のセル1に到達するとゼロに ry 。
> データストリングの終わりの一つ後の Z:0 なセルにポインタが到達すると零になります。
> ? ry ループバックするので、プロセスは停止条件 ry 。
>5番目の命令はプログラムの先頭にループし戻るので、プロセスは /HALT ( /アサート /ネゲート ) 条件が満たされなくなるまで続きます。

> 3. ハードウェア設計
> 
> 3.1 概要
> 
> ? ry 実装の基礎として使用しました。
> アルテラのCyclone III EP3C16 FPGAをハードウェア実装のベースとして我々は使用しました。
> ? ry (約30米ドル) ry 。
> その選択は、このFPGA ICチップの比較的低価格 ( 高くとも約 $30 ) と、そのためのテストハードウェアの可用性に基づいています。
> 
> 使用したテストボードにはDDR2 RAM ICが装備されていますが、RAMへのアクセスは一度に1プロセスに制限されています。
> 真の並列実装では、プロセッサごとに別々の内部メモリブロックが割り当てられているため、FPGA内の使用可能なメモリ量によってプロセッサ数が制限されます。
> EP3C16 FPGAには、それぞれ8Kビットの16ビットメモリブロック56個があります。
> ? 32ビットのSubleqプ ry 。
> 我々の 32bit Subleq プロセッサを1つ実装するには、最低2つのメモリブロックが必要です。そのため、FPGAには28個のプロセッサしか搭載できません。
> 私たちは16ビット実装を選択し、より多くのプロセッサ(最大56)を持つことができますが、それぞれに割り当てられるメモリはわずか1Kバイトです。
> 
> ? ry データをFPGAにロードするために使用されるUSBとSPI( ry )間ののブリッジとして構成された外部サイプレスFX2 CPUの ry 。
> FPGAは、コードとデータとを FPGA にロードする為に有用な SPI ( シリアルペリフェラルインターフェイス ) と USB との間のブリッジとして構成されたエクスターナルなサイプレス FX2 CPU の助けを借りてUSBバスに接続されています。
> インターフェイスブリッジは、PCソフトウェアに対して透過的です。
> 
> 
> (                FPGA
> MEMORY < - > PROCESSOR1      < - > (
> メモリ< - >プロセッサ2        < - >
> メモリ< - >プロセッサ3        < - >
>   :                :       < - > SPI         < - > CONTROL_CPU < - > USB
> メモリ< - >プロセッサ7        < - >
> メモリ< - >プロセッサ8        < - > ))
> 
> 図2  ボードのブロック図
> 
> 
> ?6?
> 
> Page 7
> 
> 
> 図2はボードの通信ブロック図です。
> ? ry でコード化され、 ry 。
> このソリューションはVHDLでコーディングされ、アルテラのWebサイトから自由に入手できるQuartus II Web Editionソフトウェアでコンパイルされています。
> ? ry 当社の ry 。
> 我々のコードは、大規模FPGAで使用可能な最大63プロセッサまでスケーラブルです。
> 63プロセッサの制限はSPIバスのアドレッシングの実装によるもので、必要に応じて増やすことができます。
> 
> 28個のプロセッサはすべて独立して動作し、PCBに取り付けられた基準発振器からFPGA PLLの1つで生成された単一の150 MHzクロックによって同期されます。
> 
> プロセッサ数を増やすには、FPGAを搭載したボードをUSBバス経由で簡単に接続することができます。
> 
> 3.2 インターフェースの説明
> 
> 各プロセッサには、割り当てられたメモリへのシリアルインタフェースとステータスバイトがあり、単一アドレスのシリアルロードからアクセスできます。
> ? シリアルインタフェースは、処理が停止すると、 ry 。
> シリアルインタフェースは、プロセッシングが停止すると、メモリのデータバスとアドレスバスを引き継ぎます。
> 
> FPGA内部のアドレス空間は、プロセッサインデックスとメモリアドレスという2つの数値によってアドレス指定されたテーブルとして編成されています。
> インデックス0から1バイトを読み取ると、FPGA内部のプロセッサ数が返されます。
> この設計では、戻り値は28です。
> 1から28のインデックスがプロセッサに割り当てられ、2048バイト(512ビットの32ビットワード)のメモリがそれぞれ使用可能です。
> 
> プロセッサメモリへの書き込みは、2048バイトのバッファを順次ロードする動作である。
> プロセッサのメモリからの読み出しは異なります。最初に返されるワード(4バイト)はプロセッサのステータスで、残りはメモリの内容です。
> 
> ? ステータスバイト - 最初の単語の ry 停止し、実行しません。
> ステータスバイト - 最初のワードの最初のバイト - は次の3つの状態のいずれかになります。0xA1 - 実行中、0xA2 - 停止したか、0xA0 - 電源が入ってから停止そして実行せず。
> プロセッサのメモリに書き込むと自動的に実行が開始されるため、別のコマンドで処理する必要はありません。
> プロセッサのメモリから読み出すと、そのプロセッサが停止します。
> ? 例外はプロセッサーを停止させない状態の最初のバイトを読み取ることです。
> そのプロセッサを停止させない 1 つ例外はステータスの先頭バイトの読取りです。
> さらに、プロセッサは、セクション2で述べたように、Subleq停止オペランド(-1)によって停止することができます。
> 上記のSubleqアセンブリ言語セクションで説明した入力や出力などの他の負の参照も、このアーキテクチャでIO操作が定義されていないためプロセッサを停止します。
> 
> 3.3 サブレックプロセッサ
> 
> ステートマシンアルゴリズムは以下のように擬似コードで表現できます。
> 
>   IP = 0 
>   while (IP >= 0) 
>   { 
>     A = memory[IP]                 // A =メモリ[IP]
>     B = memory[IP+1] 
>     C = memory[IP+2] 
>     if (A < 0 or B < 0):     // if(A <0またはB <0):
>     { 
>       IP = -1 
>     } 
>     else: 
>     { 
>       memory[B] = memory[B] - memory[A] 
>       if (memory[B] > 0) 
>         IP = IP + 3 
>       else: 
>         IP = C 
>       } 
>     } 
> 
> 
> ?7?
> 
> Page 8
> 
> 
> IPは命令ポインタ、memory []はメモリセルの値、A、B、Cは整数である。
> 
> Subleqプロセッサ・コアは、デュアル・ポート・メモリ・アクセスを構築するために使用したQuartus IIソフトウェアのRAM 2ポートメガファンクションの助けを借りて書かれています。
> ? ry 、処理クロックティックを節約します。
> 実装されたソリューションは、2つの異なるアドレス(メモリ[A]とメモリ[B])で同時にコンテンツにアクセスすることを可能にし、処理クロック数を節約します。
> この実装の欠点は、単一のポートメモリの実装と比較して、データバスとアドレスバスにアクセスするための1クロックティックの追加レイテンシです。
> ただし、デュアルポートのメモリアクセスあたりの処理クロックティックの合計は、単一ポートに必要なメモリアクセスよりもまだ少ないです。
> 
> コアは、プロセッサのメモリがロードされると自動的に起動するステートマシンに基づいています。
> ? いずれの読み出しまたは書き込み操作においても、または負 ry 遭遇すると、処理は停止するが、計算 ry なく、いつでも第1の状態バイトを読み取ること ry 。
> 読出又は書込のいずれの操作、又は負のオペランドに遭遇しての処理停止、に於ても計算に影響を与えることなく、いつでも先頭のステータスバイトを読取る事ができる。
> 
> 4. Subleq用Cコンパイラ
> 
> ? ry するコンパイラ ry 。
> この節では、簡単なCコードをSubleq [11]にコンパイルする自前コンパイラのいくつかの要素について簡単に説明します。
> ? ry テストの1つで、コンパイル ry 。
> コンパイラは私たちのテストの 1 つで用い、同じ C ソースからコンパイルされたネイティブ C コードと Subleq コードとの実行の間で直接比較が可能です。
> ? The compiler is a high-level language interface to OISC ?
> ? ry コンパイラ ry インタフェースですか? 私たちに知られている唯一のこのようなコンパイラは、執筆の時点で。
> そのコンパイラはOISCの高水準言語インタフェースです - その様なコンパイラとして執筆時点で私たちに知られている唯一の。
> 
> 4.1 スタック
> 
> ? ry 主要なCプログラミング言語の概念は、 ry 。
> C プログラミング言語の主要な概念は、関数とスタックです。
> ? ry は、コードの下のメモリを使用することで実現 ry 。
> Subleqでのスタックの実装は、下記コード的なメモリ使用で実現できます。
> ? ryの自己修正を使用 ry 、スタックの値に配置して取得することができます。
> コードの自己書換を使用すると、スタックに置いたりその値から復元したりできます。
> 関数呼び出しでは、リターンアドレスをスタックに配置する必要があります。
> 以下のCコードを考えてみましょう:
> 
>    void f() 
>    { 
>            ... 
>    } 
> 
>    void main() 
>    { 
>            ... 
>    } 
> 
>    f();
>             ... 
>    } 
> 
> 
> ?8?
> 
> Page 9
> 
> 
> 上記をマシンコードにコンパイルした後、次の操作を実行する必要があります
> ? 1)fを呼び出した直後 ry 。
> 1)f を呼出す直後の命令のアドレスをスタックに置かなければならない。
> 2)関数fのコードへジャンプする必要があります
> 3)関数fの終わりに、スタックからのアドレスを抽出する必要があり、
> 4)抽出されたアドレスに実行を転送する必要があります。
> ? C標準によれば、 ry 。
> C標準に従い、関数mainは適切なC関数です。すなわち、それ自身を含む他の関数から呼び出すことができます。
> したがって、プログラムには別のエントリポイントが必要です。このエントリポイントは、次のコードではsqmainと呼ばれます。
> 上記のCコードは次のようにコンパイルされます:
> 
>            0 0 sqmain 
>    _f: 
>            ... 
>            #return 
>            ?+8; sp ?+4; ?+7; 0 ?+3; Z Z 0 
>    _main: 
>            ... 
>            #call f 
>            dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0 
>            ?+6; sp ?+2; ?+2 0 _f; . ?; inc sp 
>            ... 
>            #return 
>            ?+8; sp ?+4; ?+7; 0 ?+3; Z Z 0 
>    sqmain: 
>            #call main 
>            dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0 
>            ?+6; sp ?+2; ?+2 0 _main; . ?; inc sp 
>            0 0 (-1) 
>    . inc:-1 Z:0 dec:1 sp:-sp 
> 
> セルスタックポインタspは、プログラム内の最後のメモリセルです。
> それは、それ自身のアドレスの負の値で初期化されます。
> ? A negative value is used here to speed up the code execution ?
> ? ry 化しますか? 
> ここで負の値を使用してコード実行を高速化します - データが実際の値の負数として記録されている場合、減算操作を使用すると、いくつかのステップを節約することがあります。
> 命令dec spはspから1を引くので、その実際の値は1だけ増加する。
> ? Below is an excerpt calling the function f in more readable form ? relative references ?
> ? ry 、関数fをより読みやすい形で呼び出す抜粋です。 相対的な参照? ラベルに置き換えられます。
> 以下は、関数 f を呼出すより読み易い形 - 相対的な参照 - ラベルに置換えられます - の抜粋です。 
> 
>    dec sp 
>    A; sp A 
>    B; sp B 
>    A:0 B:0 
>    C; sp C 
>    D C:0 _f 
>    . D:? 
>    inc sp 
> 
> ? ry クリアすることです。これは、前回の使用時に残っていた値があるためです。
> 4行目の命令は、スタック内のセルをクリアする為で、前回の使用時に値を残した事に因ります。
> ? しかし、スタック内の最上位セルをクリア ry 。
> しかしながら、スタック内のトップセルをクリアすることは、命令自体のオペランドをクリアしてからspポインタの値で初期化する必要があるため、単一ステップのタスクではありません。
> ? ry です。
> したがって、実行コマンドシーケンスは次のとおりです :
> スタックポインタを増加させることによってスタック内に新しいセルを割り当てる(第1行)。
> 命令の第1オペランドをクリアする。 このオペランドをスタックポインタの新しい値で初期化する(2行目)。
> ? do the same with the second operand of the instruction ?
> ? ry 同じことをしますか? 
> 命令の第2オペランドと同じことをします - クリアして初期化する(3行目)。 
> ? その命令を実行すると、スタック内の割り当てられたセル ry 。
> そしてそれからこの命令を実行すると、スタック内のアロケートされたセルがクリアされます(4行目)。
> 
> ? 次の2つの命令は、 ry 。
> 同じ様に次の 2 つの命令は、セルCをクリアして初期化します。
> ? The instruction DC:0 _f ry .
> The instruction D C:0 _f ry .
> ? 命令D C:0_fは、 ry 。
> 命令 D C:0 _f は、命令inc spのアドレスをスタックにコピーし、_ fにジャンプする。
> ? これは、Dが次 ry 保持しているため( ry )、Cはスタック ry 指しているためです。
> これが機能するのは、Dが次のメモリセルの値を保持している(覚えていますか?)、そして C がスタック上の現在消去されているトップセルを指しているのが理由です。
> 
> 
> ?9?
> 
> Page 10
> 
> 
> ? ry 、ラベル_fにジャンプします。
> スタックに書き込まれた負の値は、ラベル _f へのジャンプを強制します。
> 
> 関数fの内部では、スタックポインタを変更することができますが、関数が終了する前にそれを復元すると仮定します。
> したがって、リターンコードはスタックから抽出されたアドレスにジャンプしなければなりません:
> 
>    A; sp A 
>    B; A:0 B 
>    Z Z B:0 
> 
> ここでスタックポインタspの値はAに書き込まれ、命令A:0 Bは格納されたアドレスをBにコピーする。
> ? ry が負に格納され、 ry 。
> アドレスが負で格納され、正の値が復元されています。
> 
> ? ry だけではありません。
> スタックはリターンアドレスを格納するだけという訳ではありません。
> これについては、後のサブセクション4.3と4.4で説明します。
> 
> 4.2 式
> 
> ? C言語の操作は、キーワード・ ry と式で ry 。
> C 言語のオペレーションは、キーワード・ステートメントと式とで構成されるステートメントで構成されます。
> ? The syntax of keyword statements and expressions are best represented by Backus-Naur Forms (BNF) ?
> ? ry (BNF)によって最もよく表現されますか? 文脈自由文法を表す標準的な方法。
> キーワードステートメントと式の構文はBackus-Naur Forms(BNF) - 文脈自由文法を表す標準的な方法 - によってベストに表現されます 。
> 古典的な例は、算術式の文法です:
> 
>    expression:=                            式:=
>            term                            ? 期間
>                    expression + term       ? 式+用語
>                    expression - term       ? 表現 - 用語
>            term:= 
>                    primary                 一次
>                    term * primary          ? 期間*プライマリ
>                    term / primary          ターム/プライマリ
>            primary:=                       プライマリ:=
>                    identifier              識別子
>                    constant                定数
>                    ( expression )          (表現)
> 
> これらの相互に再帰的な定義は、文法的に有効な任意の式のツリー表現を構築するためにparserと呼ばれるプログラムによって使用できます。
> このような ry 役割は、一連の命令を整理 ry 。
> ひとたびこのようなツリーが構築されれば、コンパイラの役割は、命令のシーケンスを整理して、すべてのサブツリーの結果がツリーに渡されるようにすることです。
> たとえば、式のツリー:
> 
>    a + ( b - c ) 
> 
> ? ノード ry 変数a、およびノー??ド「 - 」と変数bおよびcからなるサブツリーからなる。
> は、 ノード「+」、変数 a、および、ノード「 - 」と変数 b および c とからなるサブツリー、からなる。
> 
> 
> 図
> 
>    a
> 
> +
>            b 
>     - 
>            c
> 
> 
> ? ry 。これは後でさらに使用 ry 。  ry 。
> 計算を行うために、コンパイラは、サブツリーの結果を格納するために一時変数を使用する必要があります。これは後に加算で使用する必要があります。 この式がより大きな式の一部である場合、潜在的にさらに使用される可能性があります。
> ? ry では、一時的なものは1つ ry 、 ry の一時的なものが必要です。
> この特定の例では、テンポラリは 1 つだけ必要ですが、一般的には多くのテンポラリが必要です。
> 式は次のコードにコンパイルされます:
> 
>    t; b Z; Z t; Z 
>    c t 
>    a Z; Z t; Z 
> 
> 
> ?10?
> 
> Page 11
> 
> 
> 最初の行は値bを一時的なtにコピーします。
> 2行目は、一時的な値から値cを減算します。
> ? ry 、コンパイラはサブツリーで終了します。
> この時点で、サブツリーを携えてコンパイラは終了します。
> その結果は、生成されたコードと、計算されたサブツリーの値を保持する一時変数tです。
> 今度はコンパイラが追加用のコードを生成します。
> ? その引数は変数aと一時tです。
> その今度の引数は変数 a とテンポラリ t です。
> ?  3行目にaを追加します。
> a を t に 3 行目で加算します。
> 今、tは式全体の結果を保持します。
> この式がより大きな式の一部である場合、tはツリーの上位ノードへの引数としてツリーに渡されます。
> そうでない場合は、評価が終了したため、t値は破棄されます。
> 
> より高度な文法には、代入、逆参照、単項演算などがあります。
> しかし、各文法構造は、対応するサブツリーによって表現され、後にコンパイラによって処理されてコードを生成することができる。
> ? 例えば、Cで表される逆 ry 減算は次のようになります。
> 例えば、逆参照された値からの減算の C 表記つまり :
> 
>   *k -= a 
> 
> ? 翻訳されなければならない
> は次の様に変換されなければならない
> 
>   t; k Z; Z t; Z 
>   a t:0 
> 
> ここでは、間接参照のために一時変数をコード内で使用する必要があります。
> ? 命令の順序は次のとおりです。 kをtにコピーする。 aからkを引く。
> 命令の手順は : t をクリア。 k を t にコピーする。 k がポイントするメモリから a を引く。
> 
> ここでは、文法処理のいくつかの要素が触れられている。
> ? ry するために数ページしかかかりません。
> C文法は、BNFをリストするだけの為に数ページ使います。
> ? ry 文法は、 ry 。
> しかし、より大きくより複雑な文法が、同様の方法でコンパイラによって解決される。
> 
> 4.3 関数呼び出し
> 
> ? ry 、スタックに押し込んでポップ ry 。
> 上のサブセクション4.1では、スタックにプッシュしポップする方法が示されていました。
> 関数が引数を取るとき、それらは戻りアドレスとともにスタックにプッシュされなければならない。
> 関数の復帰時にスタックを復元する必要があります。
> 2つの引数を取る関数を考えてみましょう:
> 
>   int f(int a, int b); 
>     ... 
>     f(a,b); 
> 
> 関数fへの呼び出しは、次のようなものに変換されなければなりません
> 
>   # 1 push b                               #1プッシュb
>   # 2 push a                               ? #2プッシュ
>   # 3 push return_address 
>   # 4 goto f 
>   # return_address: 
>   # 5 sp -= 3 
> 
> ? ry 別の式の一部にすることができます。 コンパイラ
> Cの引数は式にすることができ、関数への呼び出しは別の式の一部 - サブ式にすることができます。即ちコンパイラは次のようなより複雑なケースを適切に処理する必要があります
> 
> 
> ?11?
> 
> Page 12
> 
> 
>    int f(int a, int b) 
>    { 
>            ... 
>            return f;                                               fを返す。
>    } 
>            ... 
>            int k; 
>            k=f; 
>            k(f(1,2),3);    // call via variable -  indirect call   //変数経由で呼び出し - 間接呼び出し
>            k = f(1,2)(3,4);        // call by return value         //戻り値で呼び出す
> 
> ここでは簡単のため、Cの関数型int(*)(int、int)はintとして表されています。
> ? ry は1つの変数タイプのみ ry 。
> Subleqは変数の型を 1 つのみサポートしています。
> ? したがって、より精巧なタイピングシステムは、言語に余分な機能を導入しません。
> 従って言語に、余分な機能をより精巧なタイピングシステムが齎しません。
> 
> ? ry として適切に計算 ry 。
> スタックにプッシュされた引数は、サブ式(サブツリー)として恙なく計算できます。
> ? 実際の関数呼び出しのこの意味では、プログラム変数または一時変数のいずれかがスタック ry されることはありません。
> この意味では、プログラム変数又は一時変数、のどちらも実際の関数呼出でスタックにプッシュされるいわれはありません。
> 
>   # 1 push B        #1プッシュB
> ?    # ry [spは負であることを覚えています]
>     #スタック内の次のセルをクリアする[ sp が負である事を忘れない ]
> ?    #下の行はCの構文と同じです:*(++ sp)= 0;
>     # *(++sp)=0; という C 構文と下の行とは同じです:
>     dec sp; t1; sp t1; t2; sp t2; t1:0 t2:0 
>     #Cの構文と同じです:* sp + = B;
>     t3; sp t3; b Z; Z t3:0; Z 
> 
>   #2プッシュA 
>     ? # the same with A            ? B ?
>     #Aと同じ
>     dec sp; t4; sp t4; t5; sp t5; t4:0 t5:0 
>     t6; sp t6; a Z; Z t6:0; Z 
> 
>   #3 push return_address
>     dec sp; t7; sp t7; t8; sp t8; t7:0 t8:0 
>     t9; sp t9; t10 t9:0 goto_address 
>     . t10: return_address 
> 
>   #4 goto f 
>     goto_address: Z Z f
>   #5 sp - = 3
>     return_address: const(-3) sp 
> 
> ? 表記const(-3)spは
> ノート : const(-3) sp は以下の短縮
> 
>   unique_name sp 
>   ... 
>   unique_name:-3 
> 
> ? ry 扱っていません。
> 上のコードは戻り値も間接呼び出しもまだ扱っていません。
> 戻り値は特別な変数(レジスタ)に格納できます。
> ? ry サブ式でする場合は、戻り値をすぐに一時的に値にコピー ry 。
> プログラムがサブ式の戻り値を使用するならば、戻り値を return 後すぐにテンポラリにコピーする必要があります。
> ? ry アドレスを一時的に保持する参照解除によって ry 。
> 間接呼び出しは、関数のアドレスを保持しているテンポラリを間接参照する事によって実現できます。
> それは簡単ですが、より複雑なコードです。
> 
> スタックポインタは、関数がスタック(ローカル)変数を要求するときに関数内で変更できます。
> ローカル変数にアクセスするには、通常、ベースポインタbpが使用されます。
> ? 関数の ry 。 ローカル変数の基本参照 ry いますか? 各ローカル変数には、ベースポインタからの関連オフセットがあります。 関数の終わりにスタックポインタを復元するために使用 ry 。
> それは関数の入り口で初期化されます。 それはローカル変数のベース参照として使用されています - 各ローカル変数は、ベースポインタから紐付けられたオフセットを持ちます。 そしてそれはスタックポインタ復元の為に関数の終わりで使用されます。
> ? ry できます。つまり、各関数は、終了時のベースポインタの終了時に入力および復元時に保存する必要があります。
> 関数は他の関数を呼び出すことができ、つまり、各関数が、ベースポインタをエントリ時点で保存しそして終了時に復元する必要を意味します。
> ? ry ます。
> したがって、関数本体は次のコマンドでラップする必要があります :
> 
> 
> ?12?
> 
> Page 13
> 
> 
>   1. # push bp             1.#プッシュbp
>   2. # sp -> bp 
>   3. # sp -= stack_size 
>   # ... function body      #...関数本体
>   5. # bp -> sp
>   6. # pop bp
>   7. # return              ? 7.#返品
> 
> またはSubleqコードで。
> 
>   dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
>   ?+6; sp ?+2; bp 0
>   bp; sp bp
>   stack_size sp
> 
>   # ... function body      #...関数本体
> 
>   sp; bp sp
>   ?+8; sp ?+4; bp; 0 bp; inc sp
>   ?+8; sp ?+4; ?+7; 0 ?+3; Z Z 0
> 
> ? ry 、解析中の関数 ry 。
> stack_sizeは定数で、パーシングに伴って関数ごとに計算されます。
> ? bp ry 不十分であることが判明しました。
> 要するに bpを保存するだけでは不十分です。
> 関数呼び出しは、式の中で起こることがあります。
> ? ry 、表現の一時的なものを保存 ry 。
> そのような場合には、式の全てのテンポラリを保存しなければならない。
> ? 新しい機能は、 ry 同じ一時メモリセルを ry 。
> 新しい関数は、それ自身の必要性のために同じテンポラリメモリセルを使用することになります。
> 式f()+ g()に対して、呼び出しの結果は変数t1とt2に格納される。
> ? ry いる関数gがt1を変更 ry 。
> 関数fの結果が格納されている t1 を関数 g が変更すると、問題が発生します。
> 
> ? ry 、すべての機能を使用しているすべての一時的なデータをスタック ry 。
> 解決策は、各関数毎にそれが使用している全テンポラリをスタックにプッシュし、終了時にそれらを復元することです。
> 以下の関数を考えてみましょう:
> 
>   int g()
>   {
>     return k+1;            // k + 1を返す。
>   }
> 
> ? ry に翻訳されます:
> それは次のようにトランスレートされます:
> 
>   _g:
>     # save bp
>     dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
>     ?+6; sp ?+2; bp 0
>     bp; sp bp
> 
>     # push t1                                      #プッシュt1
>     dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
>     ?+6; sp ?+2; t1 0
>     # push t2                                      #プッシュt2
>     dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
>     ?+6; sp ?+2; t2 0
> 
>     # calculate addition                   #加算を計算する
>     t1; t2
>     _k t1
>     dec t1
>     t1 t2
>     # set the return value [negative]              #戻り値を設定する[負]
>     ax; t2 ax                                      ? 斧; t2 ax
> 
>     # pop t2
>     ?+8; sp ?+4; t2; 0 t2; inc sp
>     # pop t1
>     ?+8; sp ?+4; t1; 0 t1; inc sp
> 
>     # restore bp
>     sp; bp sp
>     ?+8; sp ?+4; bp; 0 bp; inc sp
>     # exit                                 # 出口
>     ?+8; sp ?+4; ?+7; 0 ?+3; Z Z 0
> 
> 
> ?13?
> 
> Page 14
> 
> 
> コードのどこかに他の関数の呼び出しがある場合、他の関数が実行時にそれらを保存して復元するため、一時変数t1とt2は計算値を保持します。
> ? ry すべての一時的なデータはスタック ry されるので、使用された一時的なデータの数を減らすために支出されます。
> 関数内で使用された全てのテンポラリがスタックにプッシュされる事を以て、使用されるテンポラリの数を減らす為の支払となります。
> ? これは、使用された一時的なものを、使用された一時的なもののプールに解放することによって、これを行うことができます。
> これは、使用されたテンポラリを、使用テンポラリのプールに逃がすだけで可能です。
> ? ry 、新しい一時的なものが要求 ry 新しい一時的なものが割り当てられます。
> その後、新しいテンポラリが要求されると、プールが最初にチェックされ、そのプールが空の場合にのみ新しいテンポラリがアロケートされます。
> ? 表現
> 式
> 
>   1+k[1]
> 
> ? コンパイルする
> は以下の通りにコンパイルされる
> 
>   t1; t2; _k t1; dec t1; t1 t2
>   t3; t4; ?+11; t2 Z; Z ?+4; Z; 0 t3; t3 t4;
>   t5; t6; dec t5; t4 t5; t5 t6
>   # result in t6   ? #t6の結果        # 結果は t6 の中
> 
> ? ry 時間軸のプール ry 、時間軸の数 ry 半分になります。
> テンポラリのプールが導入されると、テンポラリの数は半分になり :
> 
>   t1; t2; _k t1; dec t1; t1 t2
>   t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
>   t1; t2; dec t1; t3 t1; t1 t2
>   # result in t2   ? #結果はt2になります   #結果は t2 の中
> 
> ? ry 削除するコードが ry 。
> 対応するプッシュおよびポップ操作を削除しコードが大幅に削減されます。
> 
> 4.4スタック変数
> 
> bpがスタックに置かれ、spがデクリメントされてメモリが割り当てられると、すべてのローカル変数が使用可能になります。
> コンパイラはアドレスを知らないため間接的にしかアクセスできません。
> ? 例えば、関数f in
> 例えば、以下の関数 f
> 
>   int f(int x, int y)
>   {
>     int a, b=3, c[3], d=5;
>     ...
>   }
>   f(7,9);
> 
> ?    スタックサイズが6に等しい4つのローカル変数があります。
> は 6 に等しいスタックサイズと共にある 4 つのローカル変数、を持ちます。
> ? ry 関数が入力されると、スタックは次の値を ry :
> この関数が開始されると、スタックは下記の値を持ちます:
> 
>    ... y[9] x[7] [return_address] [saved_bp] a[?] b[3] c0[?] c1[?] c2[?] d[5] ... 
>                                            ^                                   ^ 
>                                            (bp)                                (sp) 
> 
> コンパイラは、bpからの各変数のオフセットについて知っています。
> 
> 
> ?14?
> 
> Page 15
> 
> 
> 可変オフセット
>   y   -3 
>   x   -2 
>   a   1 
>   b   2 
>   c   3 
>   d   6 
> 
> したがって、コードでは、配列を指さないローカル変数への参照は*(bp + offset)で置き換えることができます。
> ? arrayの ry 。
> 配列の名前は最初の要素のアドレスなので、配列cは(bp + offset)に置き換えなければなりません。
> 名前は変数を参照するのではなく、[]で参照することは変数を参照します。
> Cで
> 
>   c[i] 
> 
> ? is the same as ?
> is the same as 
> ? と同じです
> は以下と同じで
> 
>   *(c+i) 
> 
> この例では次のように解釈できます。
> 
>   *((bp+3)+i) 

> 4.5 乗算
> 
> Subleqにおける唯一の些細な乗算は2倍の乗算であり、
> 
>   t=a+a: t; a Z; a Z; Z t; Z 
> 
> ?、式を使用できます
> 2つの数字を乗算するには、以下の式を使用できます
> 
>   A*B = (2A)*(B/2) + A*(B%2) 
> 
> ? ry 整数とモジュール分割が必要です。
> これは単純な再帰式ですが、整数と剰余演算とが必要です。
> 除算は、次のアルゴリズムとして実装できます。
> ? ry 与えられたとき、Bは2だけ増加し、次の増加がBよりAより大きくなるまで増加する。
> 2つの数AとBが与えられた時 B を、 B が A より大きくなるまで 2 倍する。
> ? ry させると同時に、別の変数Iを2だけ増やします。これは1に初期化されています。
> Bを増加させ同時に、 1 に初期化されている別の変数 I を 2 倍します。
> ? ry と、私は除算の結果の一部を保持しますか? 残りはABと元のBを ry 。
> BがAより大きくなると、 I は除算の結果の一部を保持し - 残りは A - ( 訳注 : 前回の ) B と元の B とを使用してさらに計算されます。
> これは再帰的にすべてのIを蓄積することができます。
> A <Bの最後のステップでは、Aはモジュラスです。
> このアルゴリズムは、Cの短い再帰関数として実装できます。
> ? 終了時に、この関数は引数jの結果と除算モジュラスとして整数除算を返します。
> この整数除算その結果と、そして引数 j の除算モジュラスとを、この関数は終了時に返します。
> 
>   int a, int b, int * j)
>   {
> 
>     if( a < b ) { *j=a; return 0; }     // 0を返します。 
> 
>     int b1=b, i=1, bp, ip;
> 
>   next:                                    // 次:
>     bp = b1; ip = i;
>     b1 *= 2; i *= 2;
>     if( b1 > a )
>       return ip+divMod(a-bp,b,j);
>     goto next;                             ? // 次へ進む。      // next へ行く;
>   }
> 
> 
> ?15?
> 
> Page 16
> 
> 
> この機能は最適ではありません。
> 再帰を別の外部ループに置き換えることで、より効率的な関数を実現できます。
> 非常に精巧な計算を必要とする乗算、整数およびモジュラ除算演算は、ライブラリ関数として実装できます。
> つまり、各乗算a * bは、呼び出し_mul(a、b)に置き換えることができ、後でコンパイラは関数の実装を(必要に応じて)追加することができます。
> 
> 4.6 条件ジャンプ
> 
> Cでは、ゼロと評価されるブール式は偽であり、非ゼロは真です。
> ? Subleqでは、すべてのブール式が平等または不等号に基づいてゼロに評価されるため、ブール式を処理するときにコードが長くなります。
> Subleq ではブール式を扱う場合にコードが長くなりますが何故なら全てのブール式評価が 0 との等又不等に基づく為です。
> 
> ? ry 偽と正の値を真として扱 ry 。
> より良い方法は、ゼロ以下を偽とし正の値を真として扱うことです。
> ? if-expression if(expr){<body>}が1つの命令にすぎない場合
> すると if-式 if(expr){<body>} はたった 1 つの命令
> 
>    Z t next 
>    <body> 
>    next: ...               次: ...
> 
> ? tは式 ry 。
> になり t が式exprの結果です。
> ? ただし、(x + 1){...}がブール値への暗黙的な変換の場合など、Cと完全に互換性を保つために、 ry 。
> 但し注意として、 C ( 例えば、ブール値への暗黙的な変換としての if(x+1){...} ) との完全互換の為に、整数式がブール値として使用されるすべてのケースを検出する必要があります。
> ? ry です。
> 幸い、そのようなケースはほんのわずかです :
> 
>    ^Zif(expr)
>    ^Zwhile(expr)
>    ^Zfor(...,expr,...)
>    ^Z! expr
>    ^Zexpr1 && expr2
>    ^Zexpr1 || expr2
> 
> ? ry できるので、コンパイラはブール値や整数式を気にする必要がなく、より ry 。
> この作業はパーサ内で行うことができ、するとコンパイラは、ブーリアンか整数か式に付いてを気にする必要がなくそしてより単純なコードを生成することができます。
> 
> ? ry 、次のようになります。
> ブール変数が式で整数として使用される場合、次の様に :
> 
>   ^Z引数f(a> 0)を渡し、
> ?  ^Z関数の戻り値(a> 0)から戻り値。
>   ^Z関数 return(a>0); から戻り値。
>   ^Z代入x =(a> 0)。
>   ^Z他の算術式x = 1 + 5 *(a> 0)。
> 
> 変数はCスタイルに変換する必要があります。つまり、負の結果はゼロになります。
> これは、以下のように簡単に行うことができます。
> 
>   x Z ?+3; x; Z            ? x≠z + 3であり、 バツ; Z 
> 
> 
> Z x ? + 3          x > 0        次の行のアドレス +  3 ( = 4 - 1 ) 番地つまり次の次の行から実行
> Z Z ■ →                            ? グーグー
> x Z ■ →
> Z                  x == 0
> 
> x < 0
> 
> ? 図3条件付きジャンプを表す図
> 図3 条件ジャンプを表すダイアグラム
> 
> 
> ?16?
> 
> Page 17
> 
> 
> ? ry 0より小さい、等しい、またはより大きい場合の簡潔 ry とおりです。
> 値が0より小さいか等しい、か、より大きいかの簡潔なチェックは次の通りで :
> 
>   Z x ?+3; Z Z G; x Z E; Z; L: 
> 
> ここで、L、E、およびGは、xがそれぞれ0より小さい、等しい、または大きい場合の実行に合格するアドレスです。
> 図3に実行のスキーマを示します。
> ? xが変わらず、Zがゼロであることに注意してください。
> x は変化しない、そしてどんな exit に於ても Z はゼロである、に注意。
> 
> 5.結果
> 
> 
> 
> 図4 FPGAボード、28個のSubleqプロセッサ、プロセッサあたり2 Kb割り当て
> 
> 
> 図4は、USBケーブルを介してFPGAボードに給電した状態を示しています。
> ボードは約5 x 7センチメートルの大きさで、28個のSubleqプロセッサを搭載しており、プロセッサあたり2 KBのメモリが割り当てられ、クロック周波数150 MHzで動作します。
> 
> ボードの効率をテストするために、我々は2つの数学的問題を選んだ。
> 最初は、算術演算グループの関数剰余のサイズを計算します。
> ? ry 2番目のモジュールは、二重階乗を計 ry 。
> 2番目に、モジュラ二重階乗を計算します。
> 
> 5.1 テスト#1
> 
> ? ry テストでは、次のプロセスの関数残基の順序を見つける問題を選択しました。
> 最初のテストで我々が選択したのは以下に示す、関数残基の順序を見つける問題 :
> 
>   xi +1 = 2 xi mod M
>   yi +1 = 2( xi + yi ) mod M
> 
> ? x ry 、Mはある値です。
> で、 xとyは1に初期化された整数、modはモジュロ演算、M はとある値です。
> 点(x0 = 1、y0 = 1)から出発して、方程式は対のシーケンスを生成する。
> ? この問題は、解決策が難しく、M(M 2未満)よりも頻繁に答えが多いため、この問題を選択しました。
> 解法が難しく、答えが M よりもしばしば非常に大きい ( しかし M 2 未満 ) 為 、この問題を我々は選択しました。
> ? ry 数Mが選択されたので、計算 ry 。
> 数 M がその様に選択される計算は数分で完了することができました。
> ? ry 新しいペアのペア ry 同じになります。
> このシーケンスが十分に長い場合、生成された新しい数のペアは、シーケンス内で以前に生成されたペアとやがて同じになります。
> タスクは、同じ値を持つ結果が最初に出現するまでに完了する必要のあるステップの数を見つけることです。
> 我々のテストでは、Mの選択値はM = 5039であり、反復回数は12693241と計算された。
> 
> 
> Page 17
> 
> ?18?
> 
> 
> ? ry のACプログラムは、 ry ます。
> この問題を解決するための C プログラムは、乗算または除算を使用せずに記述することができます :
> 
>   int x=1, y=1, m=5039;
>   int c=0, ctr=1, t;
>   int x0=0, y0=0;
> 
>   int printf();
>   int main()
>   {
> 
>     while(1)                                                       ? // 一方、(1)
>     {
>       y += x; y += y; x += x;
>       while( x>=m ) x-=m;
>       while( y>=m ) y-=m;
> 
>       if( x==x0 && y==y0 ) break;
> 
>       if( ++c==ctr )
>       {
>         x0=x; y0=y;
>         c=0; ctr+=ctr;
>       }
>     }
>     printf("point: %d %d loop: %d of %d\n",x0,y0,c+1,ctr);       printf( "ポイント:%d%dループ:%dの%d \ n"、x0、y0、c + 1、ctr);
>   }
> 
> ? ry ます。
> このプログラムは、以下の場合にテストされています :
> 
> 1. Subleqコンパイラでコンパイルし、FPGAボード上のプロセッサの1つで実行します。
> 2. Subleqコンパイラでコンパイルし、PC#1(Intel Q9650 at 3GHz)でエミュレートします。
> 3. Microsoft C / C ++コンパイラ(v16)で完全最適化してコンパイルし、PC#1で実行します。
> 4. 2と同じですが、PC#2(1.7GHzのPentium 4)で動作します。
> ? 5. PC#2で3回実行と同じ
> 5. 3 と同じ事を PC#2 で
> 
> 以下の表は、各テストの実行時間を秒単位で示しています。
> 
> 1 Subleq on 1プロセッサFPGA     94.0
> 2 Subleq on PC#1           46.0
> 3 C on PC#1                        0.37
> 4 PC#2上のSubleq                     216
> ? PC#2の5C                  0.54
> 5 PC#2 の C                         0.54
> 
> これらの結果から、FPGA上の単一プロセッサの速度は、Subleq命令をエミュレートする場合、通常のPCのCPUの速度と同じオーダーの大きさであると結論づけられます。
> PC上のネイティブコードは約100倍高速に動作します。
> 
> 5.2テスト#2
> 
> ? ry 計算であった。
> 第2のテストは、モジュラー二階乗の計算、つまり
> 
>             N     n
>   (N !)! mod M = ?? i mod M
>            n =1 i =1
> 
> 
> Page 18
> 
> ?19?
> 
> 
> このテストケースでは、マルチプロセッサSubleqシステムのフルパワーを使用することができました。上記の式の乗算は28個のプロセッサすべてで並列に計算できるためです。
> N = 5029およびM = 5039の場合、結果は95であり、これらの数値はテストで使用された。
> 数Mはテスト#1と同じであり、数NはASCII印刷可能範囲内の結果(95)を与えるように選択された。
> ? ry た。
> 計算は次の構成で実行されました :
> 
> ? 1.手書きFPGAボードのSubleqコード実行[ ry
> 1. 手書きの Subleq コードを FPGA ボード上実行 [付録7.3]
> ? ry コード(最初のテストではPC#1と同じ)
> 2. PC上でエミュレートされたSubleqコード ( 最初のテストを PC#1 上でと同じ )
> ? ry じCコ ry ルされ、PC上で実行される同等のCコード[付録7.1]
> 3. 同じ C コンパイラでコンパイルされた同等の C コードそして PC上で実行 [ 付録7.1 ]
> 4. Subleqコンパイラでコンパイルされ、PC上でエミュレートされた同じCコード
> 5. CコンパイラでコンパイルしてPC上で実行する乗算演算なしの等価Cコード[付録7.2]
> 6. Subeqコンパイラでコンパイルされ、PC上でエミュレートされた5と同じCコード
> 
> ? ry いるように?O(N^2)ではなく、モジュラ ry 、問題への解決に?O(NlogN)演算 ry 、使用 ry 。
> 付録に示されている様な、 ~O( N^2 ) でなくモジュラ累乗を利用する場合には、問題への解法に ~O( NlogN ) 演算が必要なので、我々が使用したコードは100%効率的ではありませんでした。
> ただし、これは相対的なパフォーマンスを評価する際には重要ではありません。
> 
> 結果を以下の表に示す。
> 値は秒単位の実行時間です。
> 
> 1 FPGA上のSubleq、28プロセッサで並列          62.0
> 2 PC上のサブレック(エミュレーション)              865
> ? ry 付き3 C、PC上で実行可能な実行0.15
> 3 乗算付 C 、実行形態を PC 上で実行             0.15
> ? ry 付き4 C、PC 12060でエミュ ry たSubleq
> 4 乗算付 C 、PC でエミュレートされたSubleq       12060
> ? ry なしの5 C、PC 7.8で実行可能な実行
> 5 乗算なしの C 、実行形態を PC 上で実行   7.8
> ? ry なしの6 C、PC 9795でエ ry たSubleq
> 6 乗算なしの C 、PC でエミュレートされたSubleq     9795
> 
> 28のFPGAプロセッサは、PC上で同じSubleqコードのエミュレーションを容易に凌駕します。
> ? ry にコンパイルされた乗算のないCコードは、乗算付きのCコードよりも高速に実行されます。 ry 関数ほど効率 ry 。
> Subleqにコンパイルされそしてエミュレートされた実行で、乗算なしの C コードは乗算ありの C コードよりも高速です。これは、コンパイラのライブラリ乗算関数がこの例で記述された乗算関数程には効率的でないためです。

> 6.結論
> 
> ? 安価なCyclone ry 使用して、並列 ry デバイスを構築しました。
> 高価でない Cyclone III FPGAを使用し我々は、並列に動作するプロセッサを備えたOISCマルチプロセッサ・デバイス構築に成功しました。
> ? Each processor has its own memory limited to 2 Kb.
> ? ry 、2 Kb ry 。
> 各プロセッサには、 2 KBに制限された独自のメモリがあります。
> この制限のために、例えばビットコピー [2] の様な更に単純な個別プロセッサ命令セットを持つマルチプロセッサボードを構築することはできませんでした。 何故ならこの場合、実際に有用な計算タスクを実行するために必要最小限のメモリは1プロセッサあたり~ 1Mbのメモリです。
> ? ry 限られていても、他 ry 使用するなど、より高度なプログラムを実行することはできませんでした。 ry  。 すべての計算コードが各プロセッサに割り当てられたメモリ内に収 ry 。
> 私たちのデバイスで利用可能なメモリが限られているだけでなく、他のプロセッサのエミュレータやより複雑な計算アルゴリズムを使用するといった、より高度なプログラムの実行の余地も与えられませんでした。 各プロセッサに割り当てられたメモリの中に計算コードその全てが収まる必要があるからです。
> 
> 
> Page 19
> 
> ?20?
> 
> 
> ? ry 、より高価なFPGAであるにもかかわらず、より高速で高速なものを選択することで、各 ry 。
> Stratix Vなど、より高価であれどより大規模でより高速な FPGA を選択する事により、各プロセッサで使用できるメモリのサイズを増やすことができます。
> ? その後、より ry CPUを実装 ry 。
> すると、より速い処理クロックとより多くの CPU とを上手く実装することができます。
> CPUステートマシンのVHDLコードを最適化して計算速度を向上させることもできます。
> 十分なメモリがあれば、他のプロセッサアーキテクチャをエミュレートし、他のCPU用に書かれたアルゴリズムを使用するか、オペレーティングシステムを実行することが可能です。
> ? 記憶の制約とは別に、この最小限のアプローチ ry はスピードの低下であった。
> メモリの制約とは別に、この最小限主義者アプローチのもう一つの欠点は低速度であった。
> 私たちのボードは、CPUクロックの速度がかなり遅い(150MHz)。
> 前述のように、より高価なFPGAははるかに高速なクロック速度で動作することができます。
> 
> 一方、設計の簡素化により、スタンドアローン型の小型マルチプロセッサー・コンピューターとして実装できるため、物理的サイズとエネルギー消費の両方が削減されます。
> 適切なハードウェアを使用すると、安価な電卓で使用されるものと同様の低電力太陽電池でそのようなデバイスに電力を供給することも可能です。
> ? ry 実装は拡張性があります - ホストの電源に大きな負荷をかけることなく追加のボードを接続することにより、プロセッサの数を増やすことは容易です。
> 私たちの実装はスケーラブル - 追加ボードの接続により、ホストの電源の負荷の大きな影響なくのプロセッサ数増は容易です。
> 
> ホストPCは、コードをロードして結果を読み取るために高速である必要はありません。
> 我々の実装はFPGAベースであるため、FPGAを再プログラミングすることによって、特定のタスクに合わせてカスタマイズされた他のタイプの実行時再ロード可能なCPUを作成することが可能です。
> 
> 結論として、我々はOISCコンセプトの実現可能性を実証し、それをOISCマルチプロセッサシステムの機能プロトタイプ構築に適用した。
> 我々の結果は、適切なハードウェアおよびソフトウェア実装では、非常に単純なOISCマルチプロセッサ設計ですでに相当な計算能力を達成できることを示しています。
> 
> 
> Page 21
> 
> ?21?
> 
> 
> 7.付録
> 
> ? ry コードを示します。
> このセクションでは、モジュラー二階乗を計算するコード片を示します。
> 
> ? 乗算付きの7.1C
> 7.1 乗算付の C
> 
> ? ry 、組み込みの ry 。
> 次のCプログラムは、ビルトインの組み込みの乗算と除算を使用してモジュラー二階乗を計算します。
> 
>  1   int printf();
>  2   int main()
>  3   {
>  4     int a=5029;
>  5     int b=1;
>  6     int m=5039;
>  7     int x=1;
>  8     int i,j;
>  9 
> 10     for( i=a; i>b; i-- )
> 11     for( j=1; j<=i; j++ )
> 12     x = (j*x)%m;
> 13 
> 14     printf("%d",x);
> 15   }
> 
> ? ry の複素ループです。
> 10行目から12行目は、bからモジュロmまでの倍数の二重ループです。
> 
> 7.2 乗法なしのC
> 
> ? ry が、乗算と除算の組み込み操作はありません。
> このCプログラムは、7.1のプログラムと同じ計算を行いますが、ビルトインな乗除算はありません。
> 乗算と除算の関数は明示的に記述されます。
> 
> 1   int DivMod(int a, int b, int *m)
> 2   {
> 3     int b1, i1, bp, ip;
> 4     int z = 0;
> 5 
> 6   start:                         6スタート:
> 7     if( a<b ){ *m=a; return z; }      zを返します。
> 8 
> 9     b1=b; i1=1;
> 10 
> 11   next:
> 12     bp = b1; ip = i1;
> 13     b1 += b1; i1 += i1;
> 14 
> 15     if( b1 > a )
> 16     {
> 17       a = a-bp;
> 18       z += ip;
> 19       goto start;
> 20     }
> 21 
> 22     if( b1 < 0 ) return z;           (b1 <0)がzを返す。
> 23 
> 24     goto next;
> 25   }
> 26 
> 27   int Mult(int a, int b)
> 28   {
> 29     int dmm, r=0;
> 30 
> 31     while(1)
> 32     {
> 33       if( !a ) return r;
> 34       a=DivMod(a,2,&dmm);
> 35       if( dmm ) r += b;
> 36       b += b;
> 37     }
> 38   }
> 39 
> 40   int printf();
> 41 
> 42  int a=5029, b=1, m=5039;
> 43   int k=0, x=1, t;
> 44 
> 45   int main()
> 46   {
> 47   start: k=a;
> 48   loop: t=Mult(k,x);                    ループ:t = Mult(k、x);
> 49     DivMod(t,m,&x);
> 50 
> 51     if( --k ) goto loop;                gotoループ。
> 52     if( --a > b ) goto start;
> 53 
> 54     printf("%d",x);
> 55   }
> 
> 行1-25は、4.5で説明した分割アルゴリズムを実装していますが、再帰呼び出しを削除することで最適化されています。
> 乗算(27?38行目)は、4.5に示す式の直接的な実装です。
> 
> 
> Page 21
> 
> ?22?
> 
> 
> ? ry 7.3でSubleqの実装 ry 。
> Cループは、次のサブセクション7.3 での Subleq 実装と同様のプロセスフローを作るためにgoto文に置き換えられています。
> 
> ? 7.3 サブコード
> 7.3 Subleq コード
> 
> CからのコンパイルされたSubleqがメモリに収まらなかったため、Subleqコードのモジュラー二階乗計算は手動で書かれています。
> ? 以下のコードは83の命令を持っています。これは32ビットワードの1Kbにも適合します。
> 83 の命令を持つ、 32 ビットワードの 1KB に適合するコードを以下に。
> 
> 1   0 0 Start                              スタート
> 2 
> 3   . A:5029 B:1 MOD:5039
> 4   . Z:0 K:0 X:1
> 5 
> 6   Start:                         開始:
> 7   A Z; Z K; Z
> 8 
> 9   Loop:                          ループ:
> 10   mu_a; K mu_a
> 11   mu_b; X mu_b
> 12 
> 13 
> 14   Mult:                         マルチ:
> 15   mu_r
> 16 
> 17   mu_begin:
> 18   t2; mu_a t2 mu_return:N2
> 19 
> 20   dm_a; mu_a dm_a
> 21   dm_b; C2 dm_b
> 22   dm_return; N3L dm_return
> 23   t2 t2 DivMod
> 24 
> 25   N3:
> 26   dm_m t2 ?+3
> 27 
> 28   mu_b mu_r
> 29 
> 30   mu_a; dm_z mu_a
> 31   mu_b Z; Z mu_b; Z Z mu_begin
> 32 
> 33   . mu_a:0 mu_b:0 mu_r:0
> 34 
> 35   #Mult                         ? #教室           # 乗算
> 36 
> 37
> 38   N2:
> 39   dm_a; mu_r Z; Z dm_a; Z
> 40   dm_b; MOD dm_b
> 41 
> 42   dm_return; N1L dm_return
> 43   Z Z DivMod
> 44 
> 45   N1:
> 46   X; dm_m X
> 47 
> 48   C1 K ?+3
> 49   Z Z Loop                              ループ
> 50 
> 51   C1 A
> 52   B A END
> 53   B Z; Z A; Z
> 54   K K Start                             スタート
> 55 
> 56   END:                          終了:
> 57   X (-1)
> 58   Z Z (-1)
> 59 
> 60   DivMod:
> 61 
> 62   dm_z
> 63   dm_m
> 64 
> 65   dm_start:
> 66   t1; dm_b t1
> 67   dm_a t1 ?+6
> 68   dm_a dm_m; Z Z dm_return:0
> 69 
> 70   dm_b1; dm_b Z; Z dm_b1; Z
> 71   dm_i1; C1 dm_i1
> 72 
> 73  dm_next:
> 74   dm_bp; dm_b1 dm_bp
> 75   dm_ip; dm_i1 dm_ip
> 76 
> 77   dm_b1 Z; Z dm_b1; Z
> 78   dm_i1 Z; Z dm_i1; Z
> 79   t1; dm_b1 t1
> 80   dm_a t1 dm_next
> 81 
> 82   dm_bp dm_a
> 83   dm_ip Z; Z dm_z; Z Z dm_start
> 84 
> 85   . dm_a:0 dm_b:0 dm_z:0
> 86   . dm_m:0 dm_b1:0 dm_ip:0
> 87   . dm_i1:0 dm_bp:0 t1:0
> 88 
> 89   #divMod
> 90 
> 91   . N1L:-N1 N3L:-N3 t2:0
> 92   . C1:1 C2:2 0
> 
> 3行目と4行目は、上記のCの例で変数を定義する方法と同様の変数を定義しています。
> Aは二重階乗が計算される数を定義する。 Bは開始番号です - 私たちの場合は1ですが、一般的には任意の数にすることができます。
> タスクが並列プロセッサ間で分散されると、範囲BからAはより小さな範囲に分割され、独立してプロセッサに提出される。
> 完了すると、結果は収集され、さらに処理されます。
> MODはアルゴリズムのモジュラスです。
> ZはSubleqゼロレジスタです。
> KはAから1までの中間値です。
> ? X ry 。
> そして Xは累積された結果です。
> 
> 7行目がKを初期化する。
> 10行目と11行目は、14行目と35行目の間に書かれた乗算アルゴリズムの仮引数を準備します。
> 乗算アルゴリズムのこのコードは、前のサブセクションで記述された関数Multにほぼ1対1に相当します。
> 
> 
> Page 22
> 
> ?23?
> 
> 
> ? ry 関数が関数であり、 ry 。
> 唯一の複合体は、ここで編成されたDivMod機能が関数であり、そのコードが23行目と43行目から再利用されているということです。
> ? ry 、関数の正式な引数と戻りアドレスを初期 ry 。
> これを可能にするには、関数の仮引数をリターンアドレスに初期化する必要があります。
> リターンアドレスは、間接ラベルN1LおよびN3Lを介してコピーされます。
> 
> ? ry 、除算の結果 ry 。
> 39行と40行は、乗算の結果を受け取り、除算の引数を初期化します。
> 42行と43行はリターンアドレスを初期化し、DivModを呼び出します。
> 46行目は結果をXに抽出します。
> 
> ? ry 小さいかどうかを ry 。
> 48行と49行はKを減分し、1より小さいかをチェックします。
> そうでなければ、反復全体が、Kを1だけ小さくして繰り返される。
> Kがゼロに達した場合は、進みます。
> 
> 行51-54はAを減分し、AがBに達したかどうかをチェックする。
> ? はいの場合は、ENDとラベル付けします。
> もし yes ならば、ラベル END へ飛びます。
> ? そうでない場合は、7行目に戻り、もう一度プロセス全体を繰り返しますが、AをA、新しい値をAとします。
> もしそうでないならば、 7 行目へ飛びそしてプロセス全体を再び繰返しますが今度は、小さくなった A とそして当然 A の新しい値な K と共に始まります。
> 
> ? 57行目は、結果を印刷することです。
> 57 行目は帰結として結果表示します。
> この命令は、Subleqをエミュレートするときに便利です。
> しかし、FPGAボード上での計算では、ボードに入出力処理の概念がないため、この命令は存在しません。
> 次のライン58は有効なSubleq停止コマンドである。
> 
> 60?89行目は、上記のサブセクションのCで提示された関数DivModの対応するSubleqコードです。
> 
> ? ry 、DivMod、一時的なt2、2つの定数1と2の呼び出しの戻りアドレスを定義します。
> 最後に、91行目と92行目は、DivMod 呼出しのリターンアドレスと、テンポラリ t2 と、2 つの定数 1 と 2 とを定義します。
> ? ry 4.5からの乗算式の除 ry 。
> 後者は、4.5 にある乗算式内の除算に必要です。
> 
> 参考文献
> 
> 1。
> ジョーンズ、ダグラスW.
> (1988年6月)。
> "究極のRISC"。
> ACM SIGARCH Computer Architecture News(ニューヨーク:ACM)16(3):48?55。
> 2。
> Oleg Mazonka、 "ビットコピー:究極の計算の単純さ"、
> Complex Systems Journal 2011、Vol 19、N3、pp.263-285
> 3。
> http://esolangs.org/wiki/TOGA_computer
> 4。
> http://esolangs.org/wiki/ByteByteJump
> 5。
> ? http://esolangs.org/wiki/ Subleqの参照セクションの派生言語
> http://esolangs.org/wiki/Subleq# の参照セクション内の派生言語
> 6。
> ? ; Mavaddat、F。 Parhami、B.
> Mavaddat, F.; Parhami、B.
> (1988年10月)。
> "URISC:究極の縮小命令セットコンピュータ"。 
> 国際J.電気工学教育 (マンチェスター大学出版)25(4): 327?334
> 7。
> http://esolangs.org/wiki/Subleq
> 8。
> http://da.vidr.cc/projects/subleq/
> 9。
> http://www.sccs.swarthmore.edu/users/06/adem/engin/e25/finale/
> 
> 
> Page 23
> 
> ?24?
> 
> 
> 10。
> http://techtinkering.com/articles/?id=22
> 11。
> http://esolangs.org/wiki/Higher_Subleq
> 
> 
> 
> -- 
> フリーソフトウエア関連ボランティアの皆様に感謝申上げますと共に
> 当原稿執筆編集の甚大コストへの御配慮に厚く御礼申上げます
> 三菱 UFJ 銀行 平針支店 ( 普 ) 0111481 ヤマグチセイセイ
> 郵便局 218普2449768 ヤマグチセイセイ
> Yahoo pt 1362821068616323 Rakuten pt 1100-3310-4065-1717
> http://yahoo.jp/HsDIGs?#_2TB_0S03224
> 
> 
> 
> 訂正 : Smalltalkの背後にある設計原則
> 
> 
>>図1: 言語設計のスコープ
>>、その識別子の言及だけがオリジナルオブジェクト参照の為に必要です。
>>とある言語が上手く機能しているかを見出す方法は、彼らプログラムがしている事を彼らがやっているかの様であるか、彼らを見る事です。
>>メッセージ送信メタファは、メッセージの意図 (その名前で具現化されている)を、その意図の実行の為に受信者によって使用されるそのメソッドから、切離すことによってモジュール性を提供する。 
>>、心の中の別オブジェクト、純精神的な椅子又は椅子性として顕在化します。


> 訂正 ( 後半 )
>>操作するオブジェクトにコードが依存している場合、
>>第2に、ユーザーは特定のニーズを満たすコンポーネントをより簡単に位置指定する事ができます。 
>>因枢分解での失敗がモジュール性の破れに達する様をあなたは目にします。
>>反応原理: ユーザーがアクセス可能なすべてのコンポーネントはそれ自身を観察と操作との為の有意義な方法で提示できるべきです。 
>>独立オブジェクト群たるサブシステムが自然に組み込まれている Smalltalk: そこでは既存の大規模な記述の宇宙をキャンバスにできます。そしてそれらは、ユーザインタフェース内のコンポーネントとして参画できるユーザ、とのインタラクションを取込んでいます。


> 見出し
>>スコープ : コンピュータを使用するための言語のデザインは、内部モデル、外部メディア、およびこれらの間での、人間とコンピュータとの両方におけるインタラクション、を取回さねばなりません。 
>>? 良いデザイン: ry 一般的なもの ry は統一された枠組みの中に保持 ry 。
>>メッセージ: コンピューティングは、メッセージを送信することによって統一的呼出しができるオブジェクト固有機能と見なす必要があります。 
>>因数分解 ( 因枢分解 韻枢分解 ) : システム内の各独立コンポーネントは 1 箇所にしか現出しません。 
> 
> 
> 見出し直前 ( : )
>>ウォームアップだけを得る為には、私は技術的よりも社会的であり、そしてそれがSmalltalkプロジェクトの特定の偏りにとって大きな役割を果たす、という原則から始めます:
>>、設計の一般原則を推測することができます :
>>言語はその情報の鍵です :
>>、オブジェクトのメタファを完全にサポートするために不可欠です :
>>これはデザインの3番目の原則を示唆しています :
>>グッドデザインその原則は、言語に付いても言えます :
>>、シミュレーションにそれらを含めるための変更は不要です :
>>継承は、ファクタリングのさらに実用的な利点を示しています :
>>バーチャルマシン仕様と呼ばれます :
>>ユーザーインターフェイスの十分な柔軟性を実現するための有効条件は、オブジェクト指向な原則と言えます :


> 訂正重要度低
>>? 良いデザイン: ry 一般的なもの ry は統一された枠組みの中に保持 ry 。
>>、経験は文字通りな「あのもの」と抽象的な「その椅子のようなもの」との双方を得られます。 
>>継承を通じたよく因枢分解された設計をSmalltalk は奨励します。 
>>Smalltalk バーチャルマシンは、ストーリッジ用のオブジェクト指向モデル、
>>? ユーザーインターフェイスは、 ry 。 
>>Smalltalk はそれ自体では「オペレーションシステム」を持ちません
>>ディスクからページを読み取るなどの必要なプリミティブオペレーションは話が別であり



-- 
YAMAGUTIseisei ( str_h__namae = { :sei => "山口" , :mei => "青星" } )
http://hello.to/seisei/ mailto:seisei@.68..net  tel:081-70-5152-1104
heiwa furiisekkusu 1tu