如何将布尔表达式转换为汇编代码

问题描述 投票:1回答:1

我刚来组装考虑以下功能:enter image description here

其中“ +”代表“或”逻辑门,变量的串联表示“与”逻辑门。如何在emu8086中实现这样的功能?假设输入参数可以代表寄存器的位AL,例如,输出将其值更改为0或1。

更新:这就是我所做的,我知道这写得不好,如果有任何建议或更简单的方法让我知道,这的确可行谢谢大家的帮助,特别是彼得。

org 100h

mov al, 0A3h     pour le test              

mov ah, al
and ah, 01h        ;ah = x0 
shr al, 1

mov bl, al 
and bl, 01h        ;bl = x1 
shr al, 1

mov bh, al
and bh, 01h            
not bh
and bh, 01h         ;bh = !x2
shr al, 1

mov cl, al 
and cl, 01h        
not cl
and cl, 01h        ;cl = !x3
shr al, 1

mov ch, al
and ch, 01h        
not ch
and ch, 01h        ;ch = !x4
shr al, 1

mov dl, al
and dl, 01h        ;x5 = dl
shr al, 1

mov dh, al
and dh, 01h        
not dh
and dh, 01h        ;dh = !x6    

shr al, 1          ;al = x7  


and bh, dl
and bh, cl
and bh, ah         ;!x2 and x5 and !x3 and x0     

and dh, bl 
and dh, ch
and dh, al         ;!x6 and x1 and !x4 and x7 

or dh, bh   

mov ah, dh         ;resultat dans ah







ret
assembly boolean-logic boolean-expression emu8086 boolean-algebra
1个回答
0
投票

确定具有四个x_n值彼此相邻的表达式应该按位与,而不是将它们连接为4位值吗?然后二进制添加?因为我可能已经猜到了。如果是这样,请参见https://codegolf.stackexchange.com/a/203610中的移位和rcl reg, 1在一对寄存器之间拆分位的方法。


此答案的其余部分是关于优化asm中的操作,该操作执行两组AND(与)操作,或OR(OR)操作一起生成一个布尔值,在AL中产生01

您可以对仅提取每个位的简单/简单实现进行一些改进。例如您无需在and之前与AND。第一个AND将使高位全为0,然后不将其设为1,然后第二个AND将其再次设为零。

mov bh, al
; and bh, 01h            ; This is pointless
not bh
and bh, 01h         ;bh = !x2

您可以更进一步:您仅使用按位运算,仅关心每个寄存器中的低位。 您可以在最后一次and al, 1隔离所需的位,所有临时人员都在其高位携带垃圾。


要翻转some而不是全部,请使用带有恒定掩码的XOR。例如要翻转AL中的6,4,3,2位并保留其他位不变,请使用xor al, 01011100b 1。然后,您可以转移和移动到单独的寄存器,而无需任何NOT指令。

脚注1:尾随的b表示以2为底/二进制。如果emu8086支持它,或者如果您必须编写等效的十六进制,则可以在MASM syntax,IDK中使用。

而且您可以与这些寄存器进行AND操作,而不是先提取它们,因此只需要两个临时寄存器。

   xor   al, 01011100b    ; complement bits 6,4,3,2
   mov   cl, al           ; x0, first bit of the 2&5&3&0 group

   shr   al, 1
   mov   dl, al           ; x1, first bit of the 6&1&4&7 group

   shr   al, 1
   and   cl, al           ; AND X2 into the first group, X2 & x0

   shr   al, 1
   and   cl, al           ; cl = X2 & X3 & x0

   ...                    ; cl = 2&5&3&0,  dl = 6&1&4 with a few more steps

   shr   al, 1            ; AL = x7 
   and   al, dl           ; AL = x6 & x1 & x4 & x7  (reading 6,1,4 from dl)

   or    al, cl           ; logical + apparently is regular (not exclusive) OR
   and   al, 1            ; clear high garbage
   ret

((使用普通的ASCII注释,我已经忽略了“补码”部分,因为我们在一开始就用一条指令来处理所有这些。)


据我所知,我们采用了一种简单的实现,该实现只是将位移到寄存器的底部,并使用单独的asm指令执行每个布尔操作(除补码之外)。

为了做得更好,我们需要利用我们可以与一条指令并行执行的寄存器中的8(或16)位。由于模式不规则,我们无法轻松地将位打乱以使它们彼此对齐。

IDK,如果有什么聪明的方法,我们可以左移AX以将AL中的位放入AH的底部,以及将AL中的一些分组。嗯,也许将shl axrol al交替使用以将位发送回AL的底部。但这仍然需要7个移位来分离位。 (对于在一起的连续位(7,6和3,2),shl ax,2rol al,2仅在186上可用,而将计数放在CL中几乎不值得)。

更可能的迎角是FLAGS:大多数ALU操作会根据结果更新FLAGS,如果结果中的所有位均为0,则将ZF设置为1,否则将其设置为1。这使我们对一个寄存器。由于!(a | b) = !a & !b,我们可以反转输入中的非互补位,以将其用作水平AND而不是OR。 (我对单个位求反使用!。在C语言中,!是一个逻辑非运算符,与~按位非运算符不同,它会将任何非零数字变为0。)

但是很遗憾,8086没有简单的方法可以直接将ZF转换为寄存器中的0/1。对于CF,这是可能的。我们可以通过使用sub reg, 1根据寄存器为非零来设置CF设置,如果reg为0(因为借位从顶部开始),则CF会设置CF。否则清除CF。我们可以根据CF用sbb al, al来获得reg的0 / -1(减去借位)。 al-al部分取消,剩下0 - CF

要设置使用标记,我们可以使用AND掩码将位分成两组。

;; UNTESTED, I might have some logic inverted.

   xor   al, 10100011b         ; all bits are the inverse of their state in the original expression.

   mov   dl, al
   and   dl, 11010010b         ; ~x[7,6,4,1]
   and   al, 00101101b         ; ~x[5,3,2,0]

   cmp   dl, 1                 ; set CF if that group was all zero (i.e. if the original AND was 1), else clear
   sbb   dl, dl                ; dl = -1 or 0 for the first group

   cmp   al, 1
   sbb   al, al                ; al = -1 or 0 for the second group.  Fun fact: undocumented SALC does this

   or    al, dl                ; The + in the original expression
   and   al, 1                 ; keep only the low bit

   ret

根据DL中SBB的结果,我们甚至可以做更多的工作,例如and al, dl来清除或不清除AL中的位。或者也许用adc al, -1而不是cmp al, 1来使用DL的CF结果来影响如何从AL设置CF。

求反/求逆的数量很快就变得很棘手,但是如果每个字节的代码大小或每个性能周期都很重要,那么您就应该研究一下。 (这些日子很少见,在这种情况下,您经常使用SSE2或AVX进行矢量化处理,因此不会有标志,只需在矢量元素内按位并打包比较,就可以将匹配变成全匹配和不匹配放入0。)

请注意,在使用mov / AND分割后,AL和DL都不能为全1,因此加1永远不会换为零。那么也许sbb al, -1可以加上0或1并可以设置ZF?

[如果要分支,则在ZF上用jzjnz很好。甚至在8086上可能最好,例如如果第一个AND组给出1,则不需要隔离另一个组。因此,xor al, ...相应地补全位,那么test al, mask1 /jnz check_other_group/ mov al,1将是快速路径的不错选择。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.