<IMG SRC="pierotating.gif" WIDTH=80 HEIGHT=80 BORDER=0>

Introduction

Lesson 1
Lesson 2
Lesson 3
Lesson 4
Lesson 5
Lesson 6

TI-85 Page
Ash

Welcome to the fourth lessonf of the Ash School! The part on PUSH and POP which I promised in the last section, will come in the next lesson.

Contents


Introduction to bit manipulating instructions

All these instructions (they're quite many) changes the bits in a byte in someway. You don't add or subtract anything, you just change the bits! You can either shift them left or right in different ways, or rotate them, set/reset/test them individually and last you can make some logical operations on them (OR, AND, XOR).

Why should you use those instructions? Well, when you want fast graphics for example, because the pixel on the LCD is stored in bits (since it's only two colors, only one bit/pixel is needed) which means that 1 byte contains 8 pixels. To put a pixel, you then have to OR it, or maybe use XOR and AND to remove it or if you want something to scroll smootly to the left or right, a rotating instruction may give the best result. Also, if you want to multiply a register with 2, 4, 8... shifting is the absolute fastet way to do that.

    186d = 1 0 1 1 1 0 1 0 b

Just a simple reminder so you know how a binary number looks like :-) Remember also that bit 0 is the LSB (Least Significant Bit, the bit to the far right - a zero in this case) and bit 7 the MSB. You must know that else you may have a hard time understanding the instructions below.

Logical operators

All three logical operations uses two operands: the A registers and another registers or immediate data. The result is always stored in the A register.

OR

This instruction makes a logically 'or' with the A reg (also called accumulator) and the specified operand. With this I mean, that if at least one bit is set in a bitposition (bit 0, bit 1... bit 7) that bit is also set in the result (if bit 0 is set in the accumulator OR bit 0 is set in the specified operand then bit 0 is set in the answer. Then if bit 1 is set... and so on). Example:

Input:  A - 186
        E - 92
         
Instr:  OR E

Output: A - 254

    186  = 10111010
     92  = 01011100
    -----------------
           11111110 = 254

Note that you don't write OR A,E - just OR E. OR A wouldn't change the accumulator (that's very obvious).

How will this affect the flags? The Carry Flag is ALWAYS reset on ALL logical operators so that's easy. The zero flag is also set if the result is zero, else it will be reset.

One common use for the OR instruction is OR A. Why? It doesn't change any registers!? No, but it changes the flags. If A=0 the zero flag will be set and if A<>0 then it will be reset. That tells you "aha, then I can use OR A instead of CP 0 when I wan't to check if the accumulator is zero!". Yup! And it's smarter too! OR A just takes one byte, and CP 0 takes two bytes! So you save one byte! In a big program (>2000 rows) you can save about 50 bytes with this. When your programs are finished, search for CP 0 in it and you may find some things to change.

AND

AND is very easy to explain when you know OR. Instead of 'or'ing the bits, you 'and' the bits :-) In other words, both bits must be set if the result bit should be set. Example:

Input:  A - 186
        E - 92
         
Instr:  AND E

Output: A - 24

    186  = 10111010
     92  = 01011100
    -----------------
           00011000 = 24

AND is very useful when you want to mask away some bits. For example, you're only intersted in the lower four bits in the accumulator, and the upper four bits are just trash. How do I remove them? The answer is AND 15, since 15d = 00001111b. Now, the four upper bits are all reset since both bits would be needed to be set if the bit should hang on to the result. Since the mask (in this case, 15) have those bits reset they will be spoiled. The lower four bits are in the mask set, which means that the lower four bits in the accumulator will remain.

I really hope you can see this, because this is important. You should also write the masks in hexadecimal or even better in binary in your source, because it makes the code easier to read (in this case, $0F or %00001111).

XOR

XOR is an exclusive OR. The difference between OR is that if both bits are set, the answer bit will be reset! Example:

Input:  A - 186
        E - 92
         
Instr:  XOR E

Output: A - 230

    186  = 10111010
     92  = 01011100
    -----------------
           11100110 = 230

In other words, if the specified operands bit is set, then you change that bit in the accumulator! Since you only change the bits, you doesn't really lose the value! For example, if you make two XOR E in a row, the accumulator will have the original value again. This may be good for encoding for example, because can always know which value you had before the XOR if you know the specified operand.

This can also be used for removing bits. Since OR is used to set a bit, XOR can be used to remove bits. To do that you must first OR the accumulator then XOR it like this:

Input:  A - 186
        E - 92
         
Instr:  OR E followed by XOR E

Output: A - 162

    186  = 10111010
     92  = 01011100
    -----------------   (first the OR)
           11111110 = 254
           01011100
    -----------------   (then the XOR)
           10100010 = 162

This could also be done with a combination of AND and XOR but then the mask must be in the A reg, because first you should XOR the mask with $FF to change all bits and then you XOR that with the operand you want to remove bits from. This takes one byte more though, but may be more useful if you have the mask in the accumulator.

Instead of using XOR $FF you can use the instruction CPL, which does the same thing and it is one byte smaller.

All shift instructions

There are three shift instructions, SLA, SRA and SRL. They all have one operand (a 8 bit registers) which the result also is stored in and they all shift the bits to either the left (SLA) or the right (SRA and SRL) and the bit that disappear is stored in the Carry Flag. SLA and SRL will put a 0 at the empty position while SRA will not change the value in bit 7. To make it easier to understand here are some "pictures":

SLA (Shift left arithmeticly)

   C <- | 7 <---- 0 | <- 0
          the operand

This is a common way to multiply something with 2, 4, 8 and so on. Note: you should NEVER use SLA A since the same thing could be done with ADD A,A and the latter is one byte shorter.

SRA (Shift right arithmeticly)

     | 7 ----> 0 | -> C
      the operand

This shift is good when you know that the operand may be a negative number, since that is indicated by bit 7. This shift won't change bit 7 which may be good. For example, 10100011 will become 11010001 and with the Carry Flag set after a SRA.

SRL (Shift right logically)

  0 -> | 7 ----> 0 | -> C
        the operand

And this shift divides the operand with two and stores the remainder in the Carry Flag.

All rotate instructions

There are 10 different rotating instructions, although I won't explain two of them (RLD and RRD) since they are almost only good when dealing with BCD numbers, which I may explain in a later lesson. I've never used them, and the reason for it is that it's slow (BCD is a way to store big numbers and a way to handle floating point operations) and not really necessary in game programming.

Anyway, what's the difference between rotating and shifting? In the shifting routines you saw that a 0 was being put at the end/beginning (except SRA). That's shifting. Rotating will put the Carry Flag in that position instead! Now, why so many more instructions then? Well, some instructions are almost the same and there are both 8 bit rotating and 9 bit rotating (through the carry). Here are the instructions one by one:

RL and RLA (Rotate left through carry)

These instructions do the same, except that with RL you specify an operand and with RLA the operand is A. So, RL A and RLA are the same thing? Yes, except for the flags. RL changes the Zero flag according to the result (set if operand becomes 0, else reset) but RLA doesn't touch the Zero flag. That isn't so important because when rotating you often don't care about the flags. Also, RLA saves one byte and is one cycle faster. According to "Programming the Z80" RLA is provided for compatibility with another CPU (8080).

Another nice ASCII picture follows...

  C <- | 7 <---- 0 | <- C
        the operand

Both C:s are stands for the Carry Flag, and they're not overwritten by each other in some way. This is 9 bit rotation also as you may see.

RLC and RLCA (Rotate left with branch carry)

Same thing here, the only difference is that RLCA doesn't change the Zero flag and it's a byte shorter. This is just a 8 bit rotation though as you see of the picture below:

  C <- | 7 <---- 0 | <- b7
        the operand

b7 is the seventh bit of the operand, it's just hard to draw nice small ASCII pictures :-)

RR and RRA (Rotate right through carry)

Works like RL and RLA except for a direction change. No more explanation needed I guess.

  C -> | 7 ----> 0 | -> C
        the operand

RRC and RRCA (Rotate right with branch carry)

And this is an 8 bit rotation to the right and it stores the bit that was rotated around in the carry just like RLC and RLCA...

  b0 -> | 7 ----> 0 | -> C
          the operand

Shifting and rotating 16 bit registers

Since all shift and rotate instructions only work with 8 bit register, you have to combine them to get it to work with 16 bit registers. I will just give a few examples since you probably can figure out how to do it by your own when you've seen the technique.

Problem Solution Comment
Shifting HL left ADD HL,HL Since multiplying with two is the same as adding something with itself, so why not? Just one byte long also. This only works with HL since you're not allowed to have any other 16 bit register as the first operand.
Shifting DE left SLA E RL D First we shift the LSB left one step and put b7 in the carry, which will become b0 in the D register with RL. If you want to redo this two more times (multiply by 8) there is a smarter way which will be explained in another lesson (it's really simple though).
Shifting BC right SRL B RR C Same thing as the above except that you first start with the MSB since it's a right shift
Rotate HL right through carry RR H RR L A 17 bit rotation is easy as you see. Works like C -> H -> L -> C.

It's more complicated to make a 16 bit rotation since then you must first make a shift, then a rotate and then check if the Carry is set and if so change b0 (or b7 depending on which direction you're rotating) in the register you first shifted. Since you don't know how to change individual bytes yet (yeah, you can OR but then only with the A register) we better learn that...

All single bit manipulating instructions

With individual bits you can either set them (SET), reset them (RES) or test them (BIT). This is useful when you only want to change/test one bit in a register that isn't the accumulator. All these instructions have two operands: the bit you will change/test (0-7) and the register. Very sadly, you MUST know which bit you want to test, you can't for example write something like SET A,B which could mean "set bit A in B" but that isn't allowed.

I don't know if I have to draw some ugly pictures really, since it's pretty obvious how it works. SET sets a bit, RES resets a bit and BIT tests a bit. You must know that BIT copies the bit into the Zero flag, so if the bit is 1 (set) the Zero flag will be set (Zero = flag set = 1) even though the bit is 1...

Now we can write a short routine that rotates a 16 bit register:

RRHL:      ; Rotate HL right (16 bit rotation)
  srl h
  rr l
  ret nc
  set 7,h
  ret

Don't know if I've said it before, but you can use a condition after RET also as you see in the example. This one exits the routine (which is called with CALL RRHL) if the carry flag isn't set, because if it isn't no bit is supposed to be set.

Small, useful instructions you should know

Here are some small instructions that I've skipped that you might want to know. All instruction takes one byte also.

Instruction Comment
SCF This instruction sets the carry flag. May be useful to use before a rotate or to indicate that something went wrong before you make a return from a subroutine or something. To clear the carry flag, use one of the logical operators. OR A is often used.
CCF This instruction "complements the carry flag" which means that the Carry flag is inverted, ie if it was set it becomes reset and vice versa. Can't find any real use for it anyway.
CPL Complement accumulator. Changes all bits in the accumulator (same as XOR 255), but doesn't change the C and Z flags.
NEG Negatates the accumulator. If A=5 it becomes -5 ($FB). Good to use when subtracting sometimes because then you can change the orders of the registers (B-A can be coded as A-B followed by a NEG to save one byte).





This page is maintained by Dines Justesen. All lessons are based on Jimmy Mårdels Online ZShell School.
(c)1999 Content: Dines Justesen and Jimmy Mårdel; Design, Graphics, Animation: mousewasher's WebDesign
These sites are optimised for IE4+ 800x600