編集:任意の加算または減算は、258 バイトのルックアップ テーブルmov
で、cmp
およびのみを使用して行うことができますjne
。巨大なルックアップ テーブルはまったく必要ありません。下位 8 ビットと上位 8 ビットは、同じルックアップ テーブルを使用して個別に更新されます。
以下は、 258 バイトのルックアップ テーブルを 1 つだけ使用し、 と のみを合計ax
して使用するコードです。bx
mov
cmp
jne
[ビット 64]
; 有効な命令: mov、cmp、jmp、je、jne
; 使用命令: mov、cmp、jne
セクション .text
グローバル_開始
; このコードはaxとbxを合計します
_始める:
; 合計する値を定義します (ax & bx)。
移動斧、12853; 加数 1 の例。
mov bx,33276 ; 加数 2 の例。
; 合計は簡単です: ゼロになるまで各被加数を減らすだけです。
; 減分ごとに、合計を (ax で) 増分します。
cmp bx,0
jne start_summing ; 通常、これは準備ができており、
; 次の 2 つの命令が削除されます。
cmp bx,1 ; これは、jne で十分であることを示しています。
準備ができました。この条件付きジャンプは常に分岐します。
start_summing:
移動 ecx,0
summing_loop:
mov cl,bl
mov bl,[rcx+(number_line-1)] ; bl を減少させます。
cmp bl,255
jne bl_not_carry
mov cl,bh
mov bh,[rcx+(number_line-1)] ; デクリメント bh。
bl_not_carry:
mov cl,al
mov al,[rcx+(number_line+1)] ; インクリメントアル。
cmp al,0
jne al_not_carry
mov cl,ah
mov ah,[rcx+(number_line+1)] ; インクリメントああ。
al_not_carry:
cmp bx,0
jne summing_loop
準備:
; sum は eax になりました。
セクション .data
max_value eq 255
max_value_plus_1 式 (最大値 + 1)
デシベル最大値; 0 - 1 = 255
行番号:
%assign myValue 0
%rep max_value_plus_1
デシベル myValue
%assign myValue (myValue + 1)
%endrep
デシベル 0
編集:答えの残りの部分は、より多くのメモリを必要とする他のソリューションを扱います。
編集: 16 ビット オペランドの加算または減算には、1 次元の 128 KiB ルックアップ テーブルで十分です。巨大なルックアップ テーブルは必要ありません。
編集:通常はキャリー フラグを設定する加算が誤った結果を生成する原因となるバグを修正しました。
これはx86-64アセンブリのコードで、YASMでアセンブルされ、おそらくNASMでもアセンブルされます。&add ax,bx
のみを使用して をmov
実装します。cmp
jne
[ビット 64]
; 有効なコマンド: mov、cmp、jmp、je、jne
; 使用コマンド:mov、cmp、jne
セクション .text
グローバル_開始
; このコードはaxとbxを合計します
_始める:
; 合計する値を定義します (ax & bx)。
移動斧、12853; 加数 1 の例。
mov bx,33276 ; 加数 2 の例。
; 合計は簡単です: ゼロになるまで各被加数を減らすだけです。
; 減分ごとに、合計を (ax で) 増分します。
移動edx,0
移動DX、斧
eax、edxを移動します。eax = 斧
移動 ecx,0
mov cx,bx ; ecx = bx
summing_loop:
mov cx,[2*rcx+(number_line-2)] ; ecx をデクリメントします。
mov ax,[2*rax+(number_line+2)] ; eax をインクリメントします。
cmp ecx,0
jne summing_loop
; sum は eax になりました。
セクション .data
max_value eq 65535
dw max_value ; 0 - 1 = 65535
行番号:
%assign myValue 0
%rep max_value
dw myValue
%assign myValue (myValue + 1)
%endrep
dw 0
編集:回答の残りの部分は、私が最初に思いついたより限定的なソリューションを扱っています。
これは、2 次元ルックアップ テーブルで実行できます。
al
&などの 8 ビット レジスタの場合はbl
簡単です。16 ビット レジスタの場合は可能ですが、ルックアップ テーブルが巨大になります (ほぼ 1 テビバイト)。以下の理由を参照してください。ルックアップ テーブルの各セルには、対応する X 座標と Y 座標の合計が含まれます (X 座標と Y 座標は被加数です)。
8 ビットの合計の場合、ルックアップ テーブル(256 * 256 行列)は次のようになります。
db 0, 1, 2, ... , 253, 254, 255
db 1, 2, 3, ... , 254, 255, 0
db 2, 3, 4, ... , 255, 0, 1
. . . . . . .
. . . . . . .
. . . . . . .
db 253, 254, 255, ... , 250, 251, 252
db 254, 255, 0, ... , 251, 252, 253
db 255, 0, 1, ... , 252, 253, 254
x86 および x86-64 では、mov
256^n による乗算に使用できます。つまり、256、65536、16777216、...
で 256 を掛けるのmov
は簡単で、計算は次のax = 256 * bl
とおりです。
mov ax,0
mov ah,bl
例を追加するには。al
& bl
、正しいオフセットを取得する必要があります。それは256 * al + bl
、 or256 * bl + al
です (ルックアップ テーブルは対称行列であり、加算は可換演算であるため対称であるため)。
x86/x86-64のみを使用して 65536 以上の数を掛けるmov
には、メモリを使用する必要があります。これは、32 ビット汎用レジスタ (eax など) の上位 16 ビットまたは 64 レジスタの上位 32 ビットを直接アドレス指定する方法がないためです。ビット汎用レジスタ (rax など)。
eax = 65536 * bx
のみを使用して計算するにはmov
:
mov [temp], dword 0
mov [temp+2], bx
mov eax, [temp]
...
temp dd 0
しかし、16 ビット値の実際の問題は、x86/x86-64 では、メモリが word/dword/qword オフセットではなくバイト オフセットを使用してアドレス指定され、 256^nでしか乗算できないことです。しかし、最初に、乗算とバイト オフセット アドレッシングでこの問題がなければ、ルックアップ テーブルがどのようになるかを見てみましょう。ルックアップ テーブルは次のようになります。
dw 0, 1, 2, ... , 65533, 65534, 65535
dw 1, 2, 3, ... , 65534, 65535, 0
dw 2, 3, 4, ... , 65535, 0, 1
. . . . . . .
. . . . . . .
. . . . . . .
dw 65533, 65534, 65535, ... , 65530, 65531, 65532
dw 65534, 65535, 0, ... , 65531, 65532, 65533
dw 65535, 0, 1, ... , 65532, 65533, 65534
ここでは、各行に 65536 個のセルがあり、それぞれが dword なので、各行は 2 * 65536 バイト = 131072 バイトになります。65536 行あるので、65536 * 65536 の行列です。
x86 アセンブリでは 1、2、4 、および 8 のスケール係数が許可されるため、ワード サイズのセルは X (水平インデックス、被加数のいずれか) では問題になりません。
編集:配列サイズに関するテキストを修正しました。実際には 1 TiB より少し小さいです。
ここでの問題は、Y (垂直方向のインデックス、もう一方の被加数) を 131072 だけで乗算することができないことmov
です。したがって、ルックアップ テーブルの各行を 32768 回繰り返す必要があります。より正確には、実際のデータ行の間に 32767 の未使用のフィラー行が必要です。なぜ 32767 なのですか?は 256、65536、16777216 の乗算にのみ使用できるためmov
、Y (垂直インデックス、もう一方の被加数) に 16777216 を乗算する必要があります。各行は 131072 バイトかかるため、新しいデータ行を作成するには、16777216 バイトごとに、各データ行の後に 32767 の未使用のフィラー行 (それぞれ 131072 バイト) が必要です。最後のデータ行の後、フィラー行は必要ないため、配列の合計サイズは次のようになります。
65535 * 16777216 + 131072 = 10.99 * 10^12 バイト = ほぼ 1 テビバイト (1 TiB)。
残念ながら、私のコンピューターにはそれほど多くのメモリがありませんが、x86-64 では可能です。
mov
以下は、256 * 256 ルックアップ テーブルのみを使用した 8 ビット加算のコードです(YASM でテスト済み、NASM でアセンブルする必要があります)。
[ビット 64]
; 有効な命令: mov、cmp、jmp、je、jne
; 使用命令: mov
セクション .text
グローバル_開始
; al & bl は保存する必要があります
; このコードは al と bl を合計します
_始める:
; 合計する値を定義します (al & bl)。
動く47。例の最初の加数
移動 bl,55 ; 例 2 番目の被加数
; 加算コードはここから始まります。
移動 ecx,0
mov cl,al ; ecx = アル
mov ch,bl ; ecx = 256 * bl + アル
mov al,[rcx+sum_look_up_table] ; ルックアップ テーブルから合計を取得します。
; 32 ビット コードの場合、rcx -> ecx
; 合計は al になりました。
セクション .data
y_times equ 256
x_times equ 256
sum_look_up_table:
%assign myY 0
%rep y_times
%assign myX 0
%rep x_times
%assign myValue (myX + myY)
%rep y_times
%if myValue >= 256
%assign myValue (myValue - 256)
%endif
%endrep
デシベル myValue
%assign myX (myX + 1)
%endrep
%assign myY (myY + 1)
%endrep