如何在 TASM 中将一个字符的位从一个位置移动到另一个位置?

How to move a char's bit from one position into another in TASM?

我必须编写一个程序,从文件中读取字符,移动每个字符中的位,并将这些更改的字符写入 TASM 中的新文件。

我编写了一个从文件中读取字符并将其写入新文件的程序,但我不知道如何移动字符中的位。

例如,这里是我们的字符文件:

        ▼    ▼
!   // 00100001 
"   // 00100010
#   // 00100011
$   // 00100100

这将是我们更改了字符的新文件(第 2 位到第 7 位):

        ▼    ▼
!   // 00100001 
b   // 01100010
c   // 01100011
$   // 00100100

如何在 TASM 中移动字符中的那个位?

编辑:

这不是 的重复问题,因为我需要检测所需的位是 0 还是 1,必须知道要使用什么,OR 或 AND,然后在 1 和中设置正确的位其余位在0,或适当的位在0,其余位在1,然后执行OR或AND。这是一个有点不同的问题。

为此,通过屏蔽除要测试的位以外的所有内容来测试 "source" 位,然后根据结果值是否为零有条件地分支。然后您可以设置或清除 "destination" 位。

因此,例如,假设您的 char 在 AL 寄存器中,

   TEST AL,2        ; TEST sets zero flag if the result of ANDing is zero,
   JZ BIT_IS_ZERO   ; so there is no need to do a separate CMP
   ; not zero, so fall through to BIT_IS_ONE, no need for a JMP

BIT_IS_ONE:
   OR AL,64         ; set bit 7; define constant make easier to understand
   JMP DONE

BIT_IS_ZERO:
   AND AL,191       ; mask off bit 7; ditto on defining constant for this
   ; fall through to DONE, no need for a JMP here

DONE:

根据您的目标芯片,您可能需要使用 AND 而不是 TEST。 AND 修改要测试的寄存器,所以你必须保留另一个副本并在 setting/clearing 位之前加载它,但其他都是一样的。

您也可以使用 SHL,通过使用 AND 清除除您关心的位以外的所有位,然后使用 SHL 将剩余位(无论是 0 还是 1)从第 2 位移到第 7 位,然后清除 "destination" 字符(一个单独的副本)中的那个位,最后将两者组合在一起。我上面提供的方法可能更容易理解和实现,但它确实引入了使用SHL时不需要的分支指令,因此效率低于SHL。

我能想到的最直截了当的英文句子"copy 2nd bit into 7th bit"直译成8086汇编:

    mov al,char  ; input value
    mov ah,al    ; copy of value for 2nd bit extraction
    and ah,0b00000010 ; keep only 2nd bit in copy
    ; ^ and ah,2 if your assembler doesn't support "0b"
    shl ah,5     ; move 2nd bit to position of 7th bit
    and al,0b10111111 ; clear 7th bit in char
    ; ^ and al,0BFh if your assembler doesn't support "0b"
    or  al,ah    ; merge "second bit" into cleared one at 7th

关于位掩码常量计算:

当你有一些二进制值,如 1010 1001 = 8 位掩码,当被 AND 使用时,它将在掩码中设置“1”的任何地方保留原始值,并且它将清除“0”所在的位。

这应该很容易想象,如果你知道你想通过AND/OR/XOR/TEST指令操作哪一位,比如"obvious"。

但是你不想将这么长的二进制数输入汇编器(另外,如果你使用一些过时的,它甚至不会为你编译)...所以用十六进制写它 0A9h.就像 "obvious" 作为二进制一样,每 4 位组成一个十六进制数字,所以 10108+2 = 10 = Ah(将“0A”写入编辑器,前导 0 告诉汇编器 "A"属于数字,不属于标签)而10018+1 = 9,将“9”写入编辑器,然后添加"h"标记为十六进制值,完成。

Matt 是如何算出小数的 191 (= 0xBF = 0b10111111) - 我不知道,可能他使用了计算器或者他在脑子里做了 255-64(全掩码减去一位)。虽然我可以通过想象 head.

中的位模式来即时编写 BF 十六进制形式

还读了这个,维基文章是IMO相当不错: https://en.wikipedia.org/wiki/Bitwise_operation