注意:本文經過原作者授權轉譯,轉載請標明出處
原文地址: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,所以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也有着相同的規則。
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,就是這么簡單
除了這些,別的規則和bset與bclr完全一樣
家庭作業
現在我們已經學習了主要的位指令,讓我們來康一個測試吧:
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
