2013-04-10 114 views
3

首先,不要打擾「您是否使用AT & T或Intel彙編?」或類似的東西。彙編[ASM]如何在沒有「ADD」指令的情況下將兩個寄存器合併在一起

我想知道是否可以在不使用「ADD」或「ADC」指令的情況下將兩個寄存器的內容(如AX和BX)一起添加到。我想只使用此指令集做:

MOV 
CMP 
JMP 
JE 
JNE 

我想看到一個簡單的例子,即使是剛剛算法沒有任何真正的代碼,或一個很好的教程這一點。

如果您想知道我爲什麼要問這個問題,那是因爲我正在創建一臺非常基本的計算機,只提供那些當時的說明,並且我想知道它是否已經能夠將兩個寄存器一起添加。

非常感謝!

+3

如果你有遞減/遞增指令,你可以這樣做。 – 2013-04-10 08:57:20

+3

假設'MOV'可以從內存中移動,那麼如果你在大型查找表中有大量內存需要燒錄,那麼這是可能的。 – harold 2013-04-10 09:04:58

+1

@harold或者它可能是一個巨大的狀態機的內存噸,其中指令指針值是狀態,假設CMP可以與常量進行比較。 – 2013-04-10 09:22:10

回答

3

理論上,是的。下面堆積如山的程序可以使用的指令集來表示,並執行加法:

if ax = 0 and bx = 0: 
    result = 0 
else if ax = 0 and bx = 1: 
    result = 1 
... 
else if ax = 42 and bx = 24: 
    result = 66 
... 

在任何實際意義上說,回答你的問題是「不」。

+0

我的想法確切,+1。 – 2013-04-10 09:23:05

+0

好,如果我明白了,我應該測試......所有可能的值並給出結果... 不夠實用,但謝謝你的想法:)。當從高級編程語言到assambly時,算法看起來很愚蠢...... – 2013-04-10 09:28:11

+0

@GuillaumeVoiron:鑑於我們並不真正瞭解你在這裏實現的目標,所以很難評論你應該做什麼。 – NPE 2013-04-10 09:29:01

3

編輯:任何加法或減法可以做一個258字節的查表並只使用movcmpjne。根本不需要巨型查找表。使用相同的查找表分別更新低8位和高8位。

下面是僅使用一個258字節的查表只有movcmpjne總結axbx代碼:

 
[bits 64] 

; valid instuctions: mov, cmp, jmp, je, jne 
; used instuctions: mov, cmp, jne 

section .text 
global _start 

; this code sums ax & bx 

_start: 

; define the values to be summed (in ax & bx). 

     mov  ax,12853  ; example summand 1. 
     mov  bx,33276  ; example summand 2. 

; summing is easy: just decrement each summand until it becomes zero, 
; and for each decrement, increment the sum (in ax). 

     cmp  bx,0 
     jne  start_summing ; normally this would be je ready and 
           ; next 2 instructions would be deleted. 

       cmp  bx,1 ; this shows that jne is sufficient. 
       jne  ready ; this conditional jump branches always. 

start_summing: 
     mov  ecx,0 

summing_loop: 
     mov  cl,bl 
     mov  bl,[rcx+(number_line-1)]  ; decrement bl. 
     cmp  bl,255 
     jne  bl_not_carry 

       mov  cl,bh 
       mov  bh,[rcx+(number_line-1)]  ; decrement bh. 

bl_not_carry: 
     mov  cl,al 
     mov  al,[rcx+(number_line+1)]  ; increment al. 
     cmp  al,0 
     jne  al_not_carry 

       mov  cl,ah 
       mov  ah,[rcx+(number_line+1)]  ; increment ah. 

al_not_carry: 
     cmp  bx,0 
     jne  summing_loop 

ready: 

; sum is now in eax. 

section .data 

max_value equ 255 
max_value_plus_1 equ (max_value + 1) 

db max_value ; 0 - 1 = 255 

number_line: 

%assign myValue 0 

%rep max_value_plus_1 
     db myValue 
     %assign myValue (myValue + 1) 
%endrep 

db 0 

編輯:的答案涉及其他的解決方案,其餘那需要更多的記憶。

編輯:一維128 KiB查找表就足以用於任何加法或減法的16位操作數。不需要巨大的查找表。 編輯:修正了導致通常設置進位標誌產生不正確結果的附加錯誤。

下面是x86-64程序集中的代碼,與YASM組裝在一起,也可能與NASM組裝在一起。實現add ax,bx,僅使用mov,cmp & jne

 
[bits 64] 

; valid commands: mov, cmp, jmp, je, jne 
; used commands: mov, cmp, jne 

section .text 
global _start 

; this code sums ax & bx 

_start: 

; define the values to be summed (in ax & bx). 

     mov  ax,12853 ; example summand 1. 
     mov  bx,33276 ; example summand 2. 

; summing is easy: just decrement each summand until it becomes zero, 
; and for each decrement, increment the sum (in ax). 

     mov  edx,0 
     mov  dx,ax 
     mov  eax,edx ; eax = ax 

     mov  ecx,0 
     mov  cx,bx  ; ecx = bx 

summing_loop: 
     mov  cx,[2*rcx+(number_line-2)]  ; decrement ecx. 
     mov  ax,[2*rax+(number_line+2)]  ; increment eax. 
     cmp  ecx,0 
     jne  summing_loop 

; sum is now in eax. 

section .data 

max_value equ 65535 

dw max_value ; 0 - 1 = 65535 

number_line: 

%assign myValue 0 

%rep max_value 
     dw myValue 
     %assign myValue (myValue + 1) 
%endrep 

dw 0 

編輯:與我第一次來到了一個更爲有限的解決方案的答案交易休息。

它可以用完成一個二維查找表

對於8位寄存器,例如al & bl,這很容易。對於16位寄存器,它可以完成,但查找表將是巨大的(幾乎1 tebibtete),請參閱下面的原因。查找表的每個單元格包含相應的X座標的總和(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 

在86和x86-64 mov可以通過用於乘法256^N,即:256,65536,16777216,...

乘以256 mov容易,計算ax = 256 * bl

mov ax,0 
mov ah,bl 

要添加例如, al & bl,我們需要得到正確的偏移量,它是256 * al + bl256 * bl + al(因爲查找表是一個對稱矩陣,並且它是對稱的,因爲加法是交換操作)。

在x86/x86-64中乘以65536和更大的數字只使用mov需要使用內存,因爲無法直接尋址32位通用寄存器(如eax)的高16位或高32位64位通用寄存器的位(如rax)。

爲了計算eax = 65536 * bx只有mov使用:

mov [temp], dword 0 
mov [temp+2], bx 
mov eax, [temp] 

... 

temp dd 0 

但隨着16位值,真正的問題是,在86/x86-64的內存使用字節尋址偏置,不與字/雙字/四字偏移,我們只能乘以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單元,每個單元爲雙字,所以每一行需要2個* 65536字節= 131072個字節。有65536行,所以它是一個65536 * 65536矩陣

由於x86程序集允許比例因子爲1,2,4和8,因此字大小的單元對於X(水平索引或任一加數)不是問題。

編輯:更正陣列大小的文本,它實際上比1 TiB小一點點。

這裏的問題是,僅用mov乘以Y(垂直索引,其他加數)131072是不可能的。因此,查找表的每一行必須重複32768次,或者更確切地說,在任何實際數據行之間必須有32767個未使用的填充行。爲什麼選擇32767? 由於mov只能用於乘以256,65536,16777216 ......所以我們需要乘以Y(垂直索引,其他加數)16777216。由於每行需要131072個字節,爲了每16777216字節創建新的數據行,每個數據行後面必須有32767個未使用的填充行(每個填充行需要131072個字節)。不需要的最後一個數據行的行填料後,因此,在總的陣列尺寸將是:

65535 * 16777216 + 131072 = 10.99 * 10^12個字節=幾乎1 tebibyte(1的TiB)

不幸的是,我的電腦裏沒有那麼多的內存,但是在x86-64中是可以的。

下面是使用只mov256 * 256查表(與YASM測試,應與NASM組裝太)爲8位加法代碼:

 
[bits 64] 

; valid instructions: mov, cmp, jmp, je, jne 
; used instructions: mov 

section .text 
global _start 

; al & bl must be preserved 

; this code sums al & bl 

_start: 

; define the values to be summed (in al & bl). 

     mov  al,47 ; example first summand 
     mov  bl,55 ; example second summand 

; the summing code starts here. 

     mov  ecx,0 
     mov  cl,al ; ecx = al 
     mov  ch,bl ; ecx = 256 * bl + al 
     mov  al,[rcx+sum_look_up_table] ; fetch the sum from look-up table. 
              ; for 32-bit code, rcx -> ecx 
; the sum is now in al. 

section .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 
       db myValue 
       %assign myX (myX + 1) 
     %endrep 

     %assign myY (myY + 1) 
%endrep 
+0

你知道,你可以對待... – 2013-04-11 23:53:57

+1

我喜歡這個答案如何使用需要添加的x86尋址模式,這是對OP的愚蠢嘗試以避免需要添加電路的嘲弄。使用我認爲可能需要的不太可怕的代碼來完成這項工作的好主意!我喜歡存儲/重新加載偏移想法來處理低於2的字節,它們沒有單獨的部分寄存器名稱。 – 2016-08-25 03:54:51

1

一個非常基本的計算機應該至少有一個位操作指令。只需一個NAND或NOR即可滿足所有的邏輯計算。並且,你也可以做一些算術運算。

相關問題