[转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 叁 - 位 指令 | 5. BSET, BCLR 和 BCHG 指令

注意:本文经过原作者授权转译,转载请标明出处

原文地址:http://mrjester.hapisan.com/04_MC68/Sect03Part05/Index.html

条件允许建议阅读原文,网上非中文资料还是较多,当作锻炼英文岂不美哉
翻译若有不足之处欢迎批评指正

译文:

"好朋友只能由偶然相遇的天性和谐的双方组成,并不是想成为好朋友就能成为好朋友" ---- 佛

简介

直到第三章的目前为止,我们已经学习了一系列以字节长字为单位的对二进制数据的修改指令。那么如果你想要修改数据中的某一而不是好几该怎么办呢?

接下来的三个指令就是为这个疑问而设计的,请留意它们有着非常相似的使用规则,所以它们在汇编的时候是归于一类的

BSET 指令

BSET - 设置某个位为1

这条指令会把目的操作数中的某一位设置成1,具体是哪一位取决于源操作数

例子

汇编程序可能会对这些指令的使用比较挑剔,让我们先来康康一个在数据寄存器上使用这条指令的例子:

    bset.l     #$0E, d0

我们知道数据寄存器d0中是一个长字的内容 (32 ):

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

如你所见,在指令执行前,数据寄存器d0中的32全是0,上面的每个数字表示每一

在上面的例子里,源操作数0E,所以d00E位会被设置成1

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0

此时d0的内容是00004000 (二进制表示为:0000 0000 0000 0000 0100 0000 0000 0000)

差不多就是这么简单,不过我们再康一个例子加深下理解:(假设d0的内容现在还是00004000)

    bset.l     #$01, d0

这条指令会把d0的第01设置为1:

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0

现在d0的内容变成了00004002 (二进制表示为:0000 0000 0000 0000 0100 0000 0000 0010)

当然了,源操作数的内容可以是一个大于1F的值,那么此时指令会怎么执行呢?比如:

    bset.l     #$27, d0

由于最高位是第1F位,所以任何更高的位都会从00重新计算,比如20会变成0021会变成0122会变成02等等,所以对于上面这条指令:

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0

07位被设置为1,任何更高位都会重新计算 (事实上,这条指令只读取了源操作数的后5位因为二进制中5位可以表示00-1F)

注意 如果目的操作数是一个数据寄存器 (就像上面例子列出的那样),那么长度必须是长字 (.l),你不能对数据寄存器使用字节或是长度

现在让我们再康康这条指令用在内存上的例子:

    bset.b     #$04, $000009C8

先看看指令执行前内存的内容:

偏移量 0 1 2 3 4 5 6 7 8 9 A B C D E F
...
000009A0 00 00 00 00 00 00 00 00 00 00 00 00 43 55 4E 54
000009B0 00 00 FE DC 00 00 00 00 00 00 00 00 00 00 00 00
000009C0 00 00 00 00 00 00 00 03 40 3F 00 00 00 00 00 00
000009D0 10 20 79 2A B2 00 00 00 00 00 00 00 00 00 00 00
...

内存中地址为$000009C8的内容是40,换算成二进制就是0100 0000

  07 06 05 04 03 02 01 00
40 0 1 0 0 0 0 0 0

因为源操作数04,所以把第04位设为1

  07 06 05 04 03 02 01 00
50 0 1 0 1 0 0 0 0

结果变成了50,然后存入到内存中去:

偏移量 0 1 2 3 4 5 6 7 8 9 A B C D E F
...
000009A0 00 00 00 00 00 00 00 00 00 00 00 00 43 55 4E 54
000009B0 00 00 FE DC 00 00 00 00 00 00 00 00 00 00 00 00
000009C0 00 00 00 00 00 00 00 03 50 3F 00 00 00 00 00 00
000009D0 10 20 79 2A B2 00 00 00 00 00 00 00 00 00 00 00
...

同样的对于内存的操作,如果源操作数大于07,它将会从00开始重新算,08变成0009变成010A变成02等等

注意 如果目的操作数是一个内存地址,或是通过地址寄存器获得的内存地址,那么长度必须是字节 (.b),你不能对内存地址使用或是长字长度

同时源操作数可以是立即数:

    bset.l     #$00, d0

也可以是数据寄存器:

    bset.l     d2, d0

不能是一个内存地址,或是通过地址寄存器获得的内存地址,或是直接一个地址寄存器,比如下面这些错误的示范:

    bset.l     a0, d0         
    bset.l     (a0), d0       
    bset.l     $20(a0), d0    
    bset.l     (a0)+, d0      
    bset.l     -(a0), d0      
    bset.l     $00FF8010, d0  

目的操作数可以是数据寄存器或是内存地址 ,或是通过地址寄存器获得的内存地址:

    bset.l     #$00, d0
    bset.b     #$00, $00FF8010
    bset.b     #$00, (a0)
    bset.b     #$00, $20(a0)
    bset.b     #$00, (a0)+
    bset.b     #$00, -(a0)

但是不能是一个地址寄存器:

    bset.l     #$00, a0       

接下来你会发现另两个指令BCLRBCHG也有着相同的规则。

BCLR 指令

BCLR - 擦除某个位为0

这条指令会把目的操作数中的某一位擦除成0,具体是哪一位取决于源操作数

例子

bset指令几乎相同,除了仅仅一点:

    bclr.l     #$0E, d0

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1

它会把那一擦除成0而不是设置为1,除此之外无任何区别,我想在这里就不赘述了

BCHG 指令

BCHG - 翻转某个位

这条指令会把目的操作数中的某一位做翻转,如果是0就会变成1,如果是1就会变成0,具体是哪一位取决于源操作数

例子

同样的规则,除了一点,比如d0原本内容是480E072C:

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
0 1 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 1 0 1 1 0 0

然后执行完下面这条指令后:

    bchg.l     #$07, d0

因为d0中第07原本是0,所以执行后会变成1:

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
0 1 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 0 1 0 1 1 0 0

如果此时再执行下面这条指令:

    bchg.l     #$1B, d0

因为d0中第1B原本是1,所以执行后会变成0:

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 0 1 0 1 1 0 0

所以现在d0的内容是400E07AC

如你所见,上面原本是0 (擦除) 的被修改成了1,而原本是1 (设置) 的被修改成了0,就是这么简单

除了这些,别的规则和bsetbclr完全一样

家庭作业

现在我们已经学习了主要的位指令,让我们来康一个测试吧:

    move.b     #$24, d0
    bclr.l     #$02, d0
    ori.b      #$03, d0
    move.b     #$F8, d1
    and.b      d0, d1
    not.w      d1
    eori.w     #$FF00, d1
    move.b     d1, $00002200
    bset.b     #$05, $00002200
    bchg.b     #$01, $00002200

所有寄存器的初始值都是00000000,你的任务就是算出内存中地址为00002200处的字节是什么,像往常一样,答案在下一节,看之前先自己捋一遍哦

目录
上一篇:[转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 叁 - 位 指令 | 4. EOR 指令
下一篇:[转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 叁 - 位 指令 | 6. 家庭作业答案 - 3

posted @ 2020-02-22 10:49  草帽过客  阅读(1691)  评论(0编辑  收藏  举报