注意:本文经过原作者授权转译,转载请标明出处
条件允许建议阅读原文,网上非中文资料还是较多,当作锻炼英文岂不美哉
翻译若有不足之处欢迎批评指正
"好朋友只能由偶然相遇的天性和谐的双方组成,并不是想成为好朋友就能成为好朋友" ---- 佛
直到第三章的目前为止,我们已经学习了一系列以字节,字和长字为单位的对二进制数据的修改指令。那么如果你想要修改数据中的某一位而不是好几位该怎么办呢?
接下来的三个指令就是为这个疑问而设计的,请留意它们有着非常相似的使用规则,所以它们在汇编的时候是归于一类的
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,所以d0的0E位会被设置成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会变成00,21会变成01,22会变成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变成00,09变成01,0A变成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 ?
接下来你会发现另两个指令BCLR和BCHG也有着相同的规则。
<= TBD
[转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 叁 - 位 指令 | 5. BSET, BCLR 和 BCHG 指令
原文:https://www.cnblogs.com/strawhatboy/p/12344482.html