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.