# Fixpoint numbers and ALU registers

In this second part of my DSP programming pages, I will describe how the number representation in DSP56001 works, some instructions, explainations of the ALU registers and how to make use of the address registers and its offset and modulo registers.

The DSP doesn't use integers as the 68K does. Instead it uses something called fix point numbers. This is not to be mixed up with floating point numbers. Floating point numbers consists of two part, one fractional part and one exponential part, to form its numbers. Fix point numbers only use the fractional part, numbers between -1 and +1. This is how the DSP uses its numbers, 24-bit fix point. The largest value that can be represented with the DSP is nealy one, hexadecimal $7FFFFF=0.99999988079 and the lowest value is exactly -1=$800000. The MSB is the sign of the value and the 23 LSBs are the fractional number. Below is a list with a few examples of numbers and their corresponding hexadecimal values.

0.0=$000000
0.25=$200000
0.5=$400000
~1.0=$7FFFFF
-1.0=$800000
-0.5=$C00000
-0.25=$E00000

The ~ in front of 1.0 is because it is not exactly equal to 1.0 but it is as near as it can get, using two complement 24-bit fix point. Usually, the assembler accepts that you write 1.0 and uses $7FFFFF, but may give a warning that you have used a number not representable.

How the DSP uses the numbers is very important to know. If you want to move a value of, say 42 into data register X0, you might write:

  `MOVE #42,X0`

This will put the hexadecimal value $2A0000 into X0 and NOT $00002A as you might have expected it to do. To tell the assembler that you really want the integer 42 put in X0, you'll have to insert a '>', like this:

  `MOVE #>42,X0`

Believe me, this is a common source of error, that isn't very easy to discover.

Back to some fix points.

When multiplying two numbers in DSP, you use the instruction MPY. This multiplies two 24-bit values and results in a 48-bit value. Multiplications are always two complemental. Let's give an example, we want to multiply 0.5 by -0.25, which will of course be -0.125. The DSP will have the values $40000 and $E00000, which will result in a 48-bit values of $F00000:000000.
The instruction for this could look like:

  `MPY X0,Y0,A`

X0=$400000, Y0=$E00000 and after execution: A=$FF:F00000:000000. Which directly leads us into the construct of the accumulators. In part one, I mentioned that the accumulators could be divided into three registers, A2, A1 and A0. In the example above these registers would be: A2=$FF, A1=$F00000 and A0=$000000. A2, you might wonder, how did that get its value. Simple, doing a multiplication, A2 will be the signextension of the MSB of A1. Sounds complicated? It's not, if the result is positive, >=0, A2 will be $00 and if the result is negative, <0 as in our case, A2=$FF. This sign extension will also occur when a value is move to an accumulator. For example, if we would do a:

  `MOVE #$876543,A`

A would contain $FF:876543:000000 after execution.

In this case, when we move a 24-bit value into the 56-bit accumulator, not only is the value sign extended into A2, but A0 is also zeroed. The N flag in CCR is also set according to MSB of A2.

This takes us to another possible error in our programming. Say that the accumulator A contains a value of $00:123456:789ABC and we want to move this 56-bit value to the other accumulator, B. A normal person would try:

  `MOVE A,B`

But this will not do exactly what we intended to do. This example would take the A1 part of A and put that in the B1 part of B, sign extend into B2 and zero B0, which would make B=$00:123456:000000. Close to what we want, but not close enough. But no worries, there is a specially made instruction for this 56-bit transfer, namely TFR (Transfer Data ALU).
This:

  `TFR A,B`

will move the whole 56-bit value from A to B. Ok, that's good, but what about when adding two numbers, that would make it possible to produce a value larger than 1. Yes, that's correct. This is where we get use of the 8-bit extension part of the accumulators, more than a sign extension. We take two values, for example 0.75=$600000 and 0.5=$400000, which will make a result of 1.25=$?, hard to represent with the usual two complement 24-bit fix point. The instruction would be:

  `ADD X0,A`

Before execution: X0=$600000 (0.75), A=$00:400000:000000 (0.5)
After execution: X0=$600000 (0.75), A=$00:A00000:000000 (1.25)

We see here that A2 is still zeroed even if MSB of A1 is set. When using 56-bit values, it is MSB of A2 that decide if the value is negative. This means that values from -128.0 to +127.999 can be represented in an accumulator, which may be useful sometimes. When an accumulator results in a value greater than 1.0 or less than -1.0, the extension flag (E) of CCR is set.

But, when we want to move this value from the accumulator to some other place, memory or data register, we bump into some problems. Neither of them has got this extra byte, and therefore cannot represent values below or above -1 - +1. If we do this:

  `MOVE A,X0`

when A=$00:A00000:000000 (1.25) as after the previous example, the value will be limited to be the closest representative value, i.e. ~1.0 or $7FFFFF. This is called limiting in the DSP and when this occurs, the L flag will be set in CCR. If we neccessarily does want to get $A00000 into X0, this can be done by using:

  `MOVE A1,X0`

  `MOVE A,X` Limiting will occur and X will be $7FFFFF:FFFFFF. When we use X as a 48-bit value, X1 is the MSW and X0 the LSW. This means that X1=$7FFFFF and X0=$FFFFFF. As with above, we might not want limiting to occur. This is done with:
    `MOVE A10,X`
  which directly copy the value in A1 to X1 and A0 to X0 without any change of the numbers and will give X=$A00000:000000.

  There is a third way of using 48-bit values, to combine the two accumulators. We can do this two ways:

    `MOVE AB,X`
  or
    `MOVE BA,X`
  As said before, if a 24-bit value is move to an accumulator, for example A, the value will come in A1, sign extend into A2 and A0 will be zeroed. But values can also be moved to and from parts of the accumulator, A0, A1 or A2 and no sign extension or zeroing will happen. None of the other parts are affected.

  Of course, in all of the examples above, no restriction are to that particularly the A accumulator is used, or that the X data register is used. Both accumulators may be used the same. X and Y may also be used the same way.

  Let's now give a summary of the registers in the ALU and how they may be used:

  X1, X0 - 24 bits
  Y1, Y0 - 24 bits
  A2, A1, A0 A2 - 8 bits and A1, A0 - 24 bits
  B2, B1, B0 B2 - 8 bits and B1, B0 - 24 bits
  X = X1:X0 - 48 bits
  Y = Y1:Y0 - 48 bits
  A = A2:A1:A0 - 56 bits*
  B = B2:B1:B0 - 56 bits*
  AB = A1:B1 - 2x24 bits*
  BA = B1:A1 - 2x24 bits*
  A10 = A1:A0 - 48 bits
  B10 = B1:B0 - 48 bits
  Those marked with * are those which makes limiting occur when used as a source register. When they are used as destinationregisters, sign extension and zeroing takes place.

  That was a little on limiting and the use of accumulators and the dataregisters. The L flag is set every time limiting has occured.

  Prev part - The basic structure of DSP56001
  Next part - Addressing modes

  Back to DSP main page

  Back to Index page

  Accessed 242 times since 961007.