Earxtutapp1

From Atari Wiki
Jump to navigation Jump to search
APPENDIX A: BITS AND BYTES

A very important part of coding is keeping track of the required memory, be
it internal registers of the CPU, RAM, ROM or diskspace. In a machine
everything is calculated in BYTES. And these bytes consist of eight smaller
buggers known as bits.

A bit can store either a 0 or a 1:

1 bit           {0, 1}
                (this is two possibilities folks.. =))

Combining two bits gives a total of 4 posibilities:

2 bits          {00, 01, 10, 11}
                (2^2 = four possibilities)

So if a byte contains 8 bits and try out all possible combinations with
zeroes and ones, this would give:

byte (= 8 bits) {00000000, 00000001, 00000010, ....., 11111110, 11111111}
                (2^8 = 256 possibilities)

The 680x0 series can also work with units called WORD and LONGWORD (also
called LONG). In the 680x0 a WORD consists of two bytes and a longword
consists of four bytes.

The 680x0 can look at number in two particular ways when testing/comparing
values: SIGNED or UNSIGNED. In signed-mode, the highest bit in a number is
reserved as a SIGN indicating plus or minus.

         +------+------+----------------+---------------------------+
         | UNIT | BITS | UNSIGNED RANGE |              SIGNED RANGE |
         +------+------+----------------+---------------------------+
         | BYTE |    8 |            256 |               -128 - +127 |
         +------+------+----------------+---------------------------+
         | WORD |   16 |          65536 |           -32768 - +32767 |
         +------+------+----------------+---------------------------+
         | LONG |   32 |     4294967296 | -2147483648 - +2147483647 |
         +------+------+----------------+---------------------------+

Now.. If you want to store a variable that can reach values upto 320 for
instance (number of pixels in an ST-low screenline), you can't use a BYTE,
because a byte can only hold 0-255. You'd have to go for a WORD.

Let's say you want to store a coordinate of somekind and this should be able
to reach from -50000 upto 50000. Then you can't fit this anymore into a WORD
(just look at the figure underneath SIGNED RANGE) and you'll have to settle
for a LONG.

It's often the case that graphics have dimensions like 256*256 or 32*16 or
whatever. Why? Well.. Those values are all powers of 2.

2^4 =  16
2^5 =  32
2^8 = 256

See? And these values are alot easier and faster to work with compared to other
numbers. .....

All units can be put through various logical operations such as AND, OR, XOR,
NOT and then some more. The most simplest is probably NOT: This simple inverts
all bits. So all ones are turned into zeroes and the other way round.

                  00000000        01010101        00001111

                     ||              ||              ||
               > LOGICAL NOT < > LOGICAL NOT < > LOGICAL NOT <
                     ||              ||              ||
                     \/              \/              \/

                  11111111        10101010        11110000

Unlike NOT, AND and OR require two value's as input. Because they are a bit
harder to comprehend we'll give some logic tables with BIT-units first.

AND | 0 | 1                                                      OR | 0 | 1
----+---+---                                                     ---+---+---
  0 | 0 | 0                                                       0 | 0 | 1
----+---+---                                                     ---+---+---
  1 | 0 | 1                                                       1 | 1 | 1

The AND-operation only outputs 1 if both input bits are 1, else it outputs 0.
You could say it requires both input1 >AND< input2 to be 1 in order to output a
1. The OR-operation requires only one of the input to be 1.

Now a logical OR/AND on a unit like a byte, word, long is simply the bitwise
operation done for all 8/16/32 bits. This means the first bit of a byte is
ANDED/ORRED with the same bit in another byte.

10101010                      00001111                     00111100
   \/                            \/                           \/
   OR====> 11111111              OR====> 00001111             OR====> 11111100
   /\                            /\                           /\
01010101                      00001111                     11110000

10101010                      00001111                     00111100
   \/                            \/                           \/
  AND====> 00000000             AND====> 00001111            AND====> 00110000
   /\                            /\                           /\
01010101                      00001111                     11110000

You can ofcourse do the same for words or longs.

Ok, let's get counting with binary numbers, shall we? ("Why do you call me
count? Because I count! Bwuahahahaha!".. Thanx to Rich Davey for that one =))

In order to understand binary numbers you must first know that every bit can
be 0 or 1 and the 1 always refers to a unique value. The lowest (rightmost) bit
has value 2^0 = 1, the one after that 2^1 = 2, the next one 2^2 = 4, etc. Let's
write it out with an examples of a byte.

1
2 6 3 1
8 4 2 6 8 4 2 1

0 0 0 0 0 0 0 1 = 128*0 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*0 + 1*1 =   1

0 0 0 0 0 0 1 0 = 128*0 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 + 1*0 =   2

0 0 0 0 0 0 1 1 = 128*0 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 + 1*1 =   3

....

0 1 0 1 0 1 1 1 = 128*0 + 64*1 + 32*0 + 16*1 + 8*0 + 4*1 + 2*1 + 1*1 = 83

......

1 0 1 1 1 0 1 1 = 128*1 + 64*0 + 32*1 + 16*1 + 8*1 + 4*0 + 2*1 + 1*1 = 187

.....

1 1 1 1 1 1 1 1 = 128*1 + 64*1 + 32*1 + 16*1 + 8*1 + 4*1 + 2*1 + 1*1 = 255

We ofcouse want the option to deal with negative values as well. How do we do
that?

The SIGNED and UNSIGNED numbertypes come in handy here. UNSIGNED means you can
only have positive values. Such like the ones, we've just dealt with. UNSIGNED
is the one where you use the hightest (leftmost) bit as a SIGN indicating
negative or positive.

In all processors the numbers are implemented so that they can be handled as
SIGNED or UNSIGNED at any time. For instance the smallest negative number -1 can
also be seen as the highest UNSIGNED number (255 in byte, 65335 in word, etc).

Anyway, let's give some more examples. This is how SIGNED numbers work:

+
/ 6 3 1
- 4 2 6 8 4 2 1

0 1 1 1 1 1 1 1 = (0*-128) + 64*1 + 32*1 + 16*1 + 8*1 + 4*1 * 2*1 1*1 = 127

1 1 1 1 1 1 1 1 = (1*-128) + 64*1 + 32*1 + 16*1 + 8*1 + 4*1 * 2*1 1*1 = -1

1 0 0 0 0 0 0 0 = (1*-128) + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 * 2*0 1*0 = -128

Not too much trouble to understand, is it? Adding and subtracting might be a
bit more difficult, but once you understand it's even easier than working with
decimal numbers. Every digit can only have two values as opposed to ten in
decimal calculus. The basis is understanding when a digit overflows. This
happens when the decimal digit surpasses 9 and when the binary digit surpasses
1. When a digit is overflown you must add 1 extra to the next digit.

00000000
00000001
-------- +
00000001 (easy as pie.)

00000001
00000001
-------- +
00000010 (lowest digit overflows, 1 extra is added to the next!)

00001011
00000001
-------- +
00001100 (lowest digit overflows, 1 extra is added to the next, this overflows
          again)

The nice thing is this operation is exactly the same for unsiged as well as
signed values. I could explain subtracting here as well, but I think all this
calculus stuff is not meant for this tutorial, but for a schoolbook.

One more thing that used very frequently in assemblers and debuggers (as well
as C-- and other yech languages) is the hexadecimal notation. You might have
noticed binary numbers can be somewhat long to write down. You need 8 digits
for a byte, 16 for a word and a nasty 32 for a long. Not very nice when you
have to type all that into you assembler.

The hexadecimal notation is basicly used because it is very close to our own
decimal notation. Every digit ranges from 0,1,2..9,a,b,c,d,e,f, so it has the a
bit larger range than decimal notation AND it is very easy to convert from and
to binary, because one digit contains exactly 4 binary digits.

00000000 (binary) = 00 (hexadecimal)
11111111 (binary) = ff (hexadecimal)
01111111 (binary) = 7f (hexadecimal)
01000110 (binary) = 46 (hexadecimal)

Also you have the ASCII notation, in which every digit (or character)
represents one byte with the range from 0-255. This is only nice in working
with textstrings.

In motorola assembler (68K, 65xx, 56K, PPC) they are indicated like this:

12345     (normal decimal, no extra indicator)
%11001100 (binary, a "%" character)
$1a       (hexadecimal, a dollarsign)
"HI"      (ASCII, quotation marks)

Back to ASM_Tutorial