base:machine_language_tutorial_part_4

Logical operations are simply operations that have to do with the logic circuits of the computer. Therefore we will be dealing with bits in this part.

All of these commands can only be used on the A register. The commands are applied to A with a mask, which is the operand.

This command will turn bits in A on. If the mask is zero, the bit will be left alone. If the mask is one, the bit will be turned on.

Bit in accumulator | Mask = Resulting A bit. 0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1

Let's see this in action. If A was %00110101 and we ORA %01010011, what would happen?

A = 00110101 ORA 01010110 <- masks vvvvvvvv A = 01110111

This command will turn bits in A off. If the mask is zero, the bit will be turned off. If the mask is one, the bit will be left alone.

Bit in accumulator & Mask = Resulting A bit. 0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1

A = 00110101 AND 01010011 <- masks vvvvvvvv A = 00010001

This command flips bits around. If the mask is zero, the bit is left alone. If the mask is 1, the bit is flipped.

Bit in accumulator ^ Mask = Resulting A bit. 0 ^ 0 = 0 0 ^ 1 = 1 1 ^ 0 = 1 1 ^ 1 = 0

A = 00110101 EOR 01010011 <- masks vvvvvvvv A = 01100011

To add to A, we use ADC. The carry bit is used to link different ADCs together for multi-byte addition. Therefore we must clear carry before any new addition to prevent any previous carry from being added.

So to add a two byte value at $3000 to a value at $2000 and store that to $4000, we'd do:

CLC LDA $2000 <- handle low byte ADC $3000 STA $4000 LDA $2001 <- handle high byte ADC $3001 STA $4001

By the way, it doesn't matter if you CLC or LDA first.

To subtract from A, we use SBC. The carry bit is used as a borrow for multi-byte subtraction. We need to set the carry to prevent anything extra from being subtracted.

SEC LDA $2000 SBC $3000 STA $4000 LDA $2001 SBC $3001 STA $4001

For both subtraction and addition, if the carry flag is on after addition, that means that the number overflowed and you will need to use another byte depending on what you're trying to do.

To multiply by two we need to shift the bytes back. We use ASL (arithmetic shift left) or ROL (rotate left). You can use these on memory or A.

ASL does this:

+-+-+-+-+-+-+-+-+ C <- |7|6|5|4|3|2|1|0| <- 0 +-+-+-+-+-+-+-+-+

It shifts bit 7 into carry, all other bits left, and 0 goes in bit 0.

ROL does this:

+------------------------------+ | | | +-+-+-+-+-+-+-+-+ +-+ | +-< |7|6|5|4|3|2|1|0| <- |C| <-+ +-+-+-+-+-+-+-+-+ +-+

It shifts carry into zero, all other bits left, and bit 7 goes into the new carry.

To multiply by non-powers of two, we must use other ways to get there. So to multiply by 6:

LDA #$01 ASL A <- multiply by 2 STA $xxxx <- store A*2 into some location ASL A <- now we have A*4 CLC ADC $xxxx <- and add A*2 to get A*6

To multiply a two-byte value we need to use ASL and ROL in sequence.

ASL $2000 <- x*2 ROL $2001 ASL $2000 <- x*4 ROL $2001 ...and so on.

To divide by two we use LSR (logical shift right) and ROR (rotate right). These work similarly to their “left” counterparts.

LSR does this:

+-+-+-+-+-+-+-+-+ 0 -> |7|6|5|4|3|2|1|0| -> C +-+-+-+-+-+-+-+-+

And ROR does this:

+------------------------------+ | | | +-+ +-+-+-+-+-+-+-+-+ | +-> |C| -> |7|6|5|4|3|2|1|0| >-+ +-+ +-+-+-+-+-+-+-+-+

Note that the ASL/LSR/ROL/ROR can be used for more than just addition, since they work with the bits of a memory address/accumulator.

base/machine_language_tutorial_part_4.txt · Last modified: 2015-08-08 04:06 by karmic