Copy Link
Add to Bookmark
Report

Fixpoint numbers and ALU registers

DrWatson's profile picture
Published in 
atari
 · 11 months ago

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. Follows is a list with a few examples of numbers and their corresponding hexadecimal values.

0.0=$0000000.25=$2000000.5=$400000~1.0=$7FFFFF-1.0=$800000-0.5=$C00000-0.25=$E00000The ~ 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 $400000 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 necessarily does want to get $A00000 into X0, this can be done by using:

MOVE A1,X0MOVE 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,XorMOVE 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 bitsY1, Y0 - 24 bitsA2, A1, A0 A2 - 8 bits and A1, A0 - 24 bitsB2, B1, B0 B2 - 8 bits and B1, B0 - 24 bitsX = X1:X0 - 48 bitsY = Y1:Y0 - 48 bitsA = 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 bitsB10 = B1:B0 - 48 bitsThose marked with * are those which makes limiting occur when used as a source register. When they are used as destination registers, sign extension and zeroing takes place.That was a little on limiting and the use of accumulators and the data registers. The L flag is set every time limiting has occurred.

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT