Section
03 Part 05 – The BSET, BCLR and BCHG Instructions |
“Unity can only be manifested by the Binary. Unity itself and the idea of Unity are already two.” ~Buddha |
Introduction
So
far in Section
03, we have had
instructions that alter binary data in sizes of bytes, words or
long-words. However, what if you wanted
to change one single specific bit, instead of several at once?
These
next three instructions are designed for that very purpose, please be aware
that they have very much the same set-out and rules, hence the reason they are
compiled together under a single part.
The BSET
Instruction
BSET – test a Bit and SET
This
instruction will set the bit number in the destination operand decided by the source operand, setting the bit to 1.
Examples
Assemblers
can be a little fussy with the use of these instructions, so we’ll start with
performing the instruction on a data register:
bset.l #$0E,d0 |
Now
here’s how it works, the data register “d0” is a long-word in size (i.e. 32
bits):
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 |
Now as
you can see in the table above, the data register “d0” has 32 bits all
currently set to 0 (clear). Above each
one is a number to represent the bit.
In
the example above, the source operand is
0E, so, bit
number 0E of d0 is set to 1:
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 |
Now
d0 contains 00004000 (In binary: 0000 0000 0000 0000 0100 0000 0000 0000).
It is
more or less that simple. But we’ll have
another example to clear it up a bit (we’ll pretend that d0 still contains
00004000):
bset.l #$01,d0 |
This
will set the 01st bit of d0:
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 |
Now
d0 contains 00004002 (In binary: 0000 0000 0000 0000 0100 0000 0000 0010).
Of
course, the source
operand can contain
a number that is higher than 1F, so what happens when this instruction below is
processed?
bset.l #$27,d0 |
Since
the highest bit setting is the 1Fth bit, anything higher wraps back around to
00 again. 20 becomes
00, 21 becomes 01, 22 becomes 02, etc.
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 |
And
so, the 07th bit is set. Anything higher,
always wraps around (The instruction only reads the first 5 bits of the source operand).
An
important thing to note, is that if the destination operand is a data register (just like above), then the size is always .l
for long-word. You cannot have byte or word size for data registers.
Now
we shall look at performing the instruction on memory:
bset.b #$04,$000009C8 |
Now
first, we’ll take a look inside memory:
Offset |
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 |
etc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The
byte in memory offset $000009C8 is 40, in binary that’s 0100 0000:
Hex |
Binary (with position
number above) |
|||||||
|
|
|||||||
|
07 |
06 |
05 |
04 |
03 |
02 |
01 |
00 |
40 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
The source operand is 04, so the 04th bit is set:
Hex |
Binary (with position
number above) |
|||||||
|
|
|||||||
|
07 |
06 |
05 |
04 |
03 |
02 |
01 |
00 |
50 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
This
results in 50, which is then saved into memory:
Offset |
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 |
etc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The
whole wrapping occurs here too, if the source operand is greater than 07, it’ll wrap around to 00. 08 becomes 00, 09 becomes 01, 0A becomes 02,
etc.
If
the destination
operand is a
memory location (directly or via an address register), the size is always .b
for byte. You cannot have word or long-word size for memory.
The source operand can be either an immediate
value:
bset.l #$00,d0 |
Or a
data register:
bset.l d2,d0 |
It cannot be a memory location
(directly or via an address register), or an address register
directly (these below are invalid):
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 |
The destination operand on the other hand can be a data
register or a memory location (directly or via an address register):
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) |
It cannot be an address register
directly:
bset.l #$00,a0 |
You
will find that the other two instructions BCLR and BCHG will have the exact
same rules, so please keep that in mind.
The BCLR
Instruction
BCLR – test a Bit and CLeaR
This
instruction will clear the bit number in the destination operand decided by the source operand, setting the bit to 0.
Examples
This
is pretty much the same as BSET, except having one difference:
bclr.l #$0E,d0 |
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 |
It
clears the bit, making it 0, instead of setting it as 1. The exact same rules apply. I don’t think I need to explain any further.
The BCHG
Instruction
BCHG – test a Bit and CHanGe
This
instruction will change the bit number in the destination operand decided by the source operand, setting the bit from 0 to 1, or from 1 to 0.
Examples
Again,
same rules, one difference. Say d0
contains 480E072C:
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 |
If we
use this instruction:
bchg.l #$07,d0 |
Bit 07 in d0 is 0, so it is changed to 1:
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 |
Then
we’ll use this instruction:
bchg.l #$1B,d0 |
Bit 1B in d0 is 1, so it is changed to 0:
Binary contents inside d0
(with position number above) |
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
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 now contains 400E07AC.
As
you can plainly see, bits that are 0 (clear) are changed to 1 (set), bits that
are 1 (set) are changed to 0 (clear), it’s as simple
as that.
Apart
from that, it is exactly the same as BSET and BCLR, the same rules apply.
Homework
So,
now that the major binary instructions are out of the way, we’ll have a test:
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 |
All
data registers start with 00000000, and your job is to find out what the byte
is in memory at offset 00002200. As always,
the answer is on the next part, be sure it give it a
try first.