The floating point register pane
This is the pane showing the values currently in the FPU (floating point unit). To display the floating point register pane click on the "MMX/FPU" toolbar button and then choose the middle button in the floating toolbar.
The first four lines of the pane display shows the control word, precision and rounding bits, the exception masks, the status word, stack pointer and condition codes, and the exception flags. Under that you can see the contents of the floating point registers. The left column shows the register, then the exponent, the sign and the mantissa, followed by the value as a real number. Finally going back to the fourth line on the right hand side there is the clear exception flag button.
The floating point instructions and registers
Floating point instructions are mnemonics which make use of the floating point registers. These registers are sometimes referred to as the FPU (floating point unit) registers. This is because before the introduction of the Intel 486 processor, the FPU used to be in a separate chip called the maths co-processor. This would be a 8087, 287 or 387 chip on the motherboard. Nowadays the floating point registers are incorporated within the main processor chip. The floating point registers permit mathematics using real numbers which means that very large or very small numbers can be manipulated, overcoming the 32 bit limit of the ordinary registers. This is achieved by means of an 80-bit architecture, which can be read to or from using a variety of data types. There are a series of mnemonics to suit, all of which begin with the letter "F". You will need to refer to your assembler instructions for a list of these and their descriptions. There are also a few very good articles describing these instructions available on the 'net. There are eight floating point registers in all.
Access to the floating point registers
The floating point registers are designed so that they are usually written to or read from by instructions which have a "push" or "pop" action. These use the floating point registers in the same way as the PUSH and POP instructions use stack memory. Since there are eight floating point registers, eight "push" commands in sequence will fill the registers and a ninth "push" will not work. When you use a "pop" command you remove from the stack the last value inserted. The most common such instructions are FLD (load), FILD (convert from integer and load), FSTP (store and pop), FISTP (convert to integer store and pop).
Sign, mantissa and exponent
There are three parts to the real numbers held (in binary form) in the 80-bit floating point registers: sign, mantissa and exponent (a binary exponent). Exactly how these values are inserted into the floating point stack and taken from the stack depends on which data type is being used. See your assembler instructions for the various data types. Whatever data type is used, when the register is loaded with a number the processor always converts it to the 80 bit ("extended precision") format. And when removing a number from the register the processor will convert it from the 80-bit format into the correct data type. Therefore the data types do not effect how the floating point register holds the number. This is always in the 80-bit format, that is:-
bit 79=sign of the real number
bits 64 to 78=binary exponent (biased- see below)
bits 0 to 63=mantissa, where bit 63 holds the integer part (one or zero) and bits 0 to 62 hold the decimal part of the real number (in binary)
Hence in its display of the contents of the 80-bit registers, GoBug does not distinguish between the data types, but merely shows the contents of the 80-bit registers in these three components. GoBug does, however, adjust the binary exponent value to allow for the bias of 16,382 decimal (this bias is used to permit negative exponent values). So if GoBug displays a binary exponent of zero, the value of the binary bits held in bits 64 to 78 is in fact 16,382 decimal (3FFEh).
If the binary exponent is one, the real number is simply the mantissa in decimalised form. If the binary exponent is two, the real number is the mantissa times two in decimalised form. If the binary exponent is three, the real number is the mantissa times four in decimalised form. In effect, therefore, the real number represented by the contents of the floating point register can be found by the formula: mantissa * 2 to the power of the exponent-1. This can be tested by entering the following digits for the exponent and mantissa respectively:-
exponent=1 mantissa=80000000 00000000 value=1E0 exponent=2 mantissa=80000000 00000000 value=2E0 exponent=3 mantissa=80000000 00000000 value=4E0 Note here bit 64 is set to "on" meaning that the mantissa has a value of 1. exponent=0 mantissa=80000000 00000000 value=5.0E-1 exponent=-1 mantissa=80000000 00000000 value=2.5E-1 exponent=-2 mantissa=80000000 00000000 value=1.25E-1Here the values of a half, quarter and an eighth are produced using zero and minus exponents.
Stack contents: the order of display
Gobug always displays the contents of all eight floating point registers, but the order of the display corresponds to the stack itself. Thus the register at the top of the stack is always called "0", and this is displayed on the first line showing stack contents. The contents of this register were the last to be put on the stack using a floating point "push" command and will be the first to be removed from the stack if there is a floating point "pop" command. The remainder of the registers are displayed in the same order as the stack.
Control word, precision and rounding
On the first line of the display you can see "Control word: number PC=number (description) and RC=number (description)". The control word is a 16 bit register which contains various flags, the most important of which are the precision control flags, the rounding control flags and the exception masks. The programmer adjusts these flags when initialising the floating point unit using floating point instructions to suit the calculatations to be performed and to suit the data types being used. The values have the following meanings, which correspond with the descriptions which GoBug puts in brackets for you on the first line of the floating point display:-
Precision control:- 0=24 bits 2=53 bits 3=64 bits Rounding control:- 0=round to nearest or even 1=round down 2=round up 3=chop
Status word, stack pointer and condition codes
On the third line of the display you can see "Status word: number SP=number and Condition codes=number". The status word is a 16-bit register which contains information about the result of the last instruction carried out by the floating point unit. The most important are the stack pointer, the condition codes and the exception flags. The stack pointer is basically a counter showing how many of the registers is currently not in use. When the floating point registers are first initialised (as they should be before all floating point calculations), the stack pointer is set to 7. It decrements on each "push" instruction and increments on each "pop" instruction. Largely you can ignore the stack pointer because GoBug always shows the contents of the registers in their correct order, see stack contents: the order of display. The condition codes are 4 bits, shown in the order C3,C2,C1 and C0. They are used by the processor for conditional branching.
Exception flags and masks
The exception flags are shown on the fourth line of the display. They come from 7 bits of the status word and show the result of instructions carried out by the floating point unit. If they are "set" they appear in a different colour even if they have not changed since the last floating point instruction. Note that none of these "exceptions" actually halt processing. Nor are they cleared on each instruction. This enables a series of instructions to be carried out before the flags are checked. However, the programmer has to be careful to clear the flags at the start of the set of instructions see clearing the exception flags. Each flag (other than the stack flag) has a corresponding "mask" bit in the control word. If desired, the programmer can set the mask bits to switch on and off exception reporting to suit the tests which may be made during processing. If the corresponding mask bit is set to zero, the exception flag will not be changed.
The exception flags (in the status word) and masks (in the control word) are:-
Bit 5 P - precision flag (loss of precision occurred) Bit 4 U - underflow flag (result too small) Bit 3 O - overflow flag (too large a result) Bit 2 Z - zero divide flag (division by zero attempted) Bit 1 D - denormalised flag (operation attempted on denormalised number) Bit 0 I - invalid flag (uncertain result)
The tag word is a 16 bit register which has 2 bits reserved for each floating point register to describe the number in the register. The meaning of these bits is as follows:-
00=normal. 01=true. 10=special (not a number or denormal) 11=empty.GoBug will display "-- empty --" if the two bits are 11 for the register concerned. In all other cases GoBug displays the value of the contents of the register as a real number in the usual way.
Real numbers are numbers which can contain a representation of a value of less than 1. Floating point numbers use a point to do this, usually a decimal point. In a floating point number the point can be anywhere within the digits. However, in the floating point register pane GoBug gives the value of the register in scientific notation. In this form only one digit is allowed to the left of the decimal point. In scientific notation the correct position of the decimal point must therefore be provided in some other way, and this is achieved by adding a signed decimal exponent to the end of the number. This corresponds with the IEEE Floating Point Standard.
1.6789E3 is the same as 1678.9
2.6789E0 is the same as 2.6789
7.6789E-2 is the same as 0.076789
-9.44E7 is the same as -94400000
In effect the correct representation of a real number given in scientific notation is number times 10 to the power of exponent.
In theory there is no limit to the size of the exponent, so that very large, or very small numbers can be representation in this way in compact form. In practice there is a limit, see changing the FP registers using GoBug.
Looking again at GoBug's floating point register pane, the right hand column shows the value of the corresponding floating point register in this real number scientific notation.
GoBug's conversion accuracy
When debugging floating point instructions, it may well be important to study the precision and accuracy of the processor and the instructions given to it. Therefore when showing the 80-bit number as a real number GoBug attempts to achieve the maximum possible precision. Some real numbers are longer than the pane and have to be truncated. To see these more accurately widen the pane by dragging its edge. Some numbers are just too long for the display. GoBug will show a maximum of approximately 80 digits, depending on the length of the decimal exponent. GoBug also takes this limit of 80 digits as a reasonable precision for the visible digits. The actual accuracy of the conversion to real numbers within GoBug is as follows:-
Negative exponents or zero - 80 digits of precision (computations are to 82 bytes then rounded).
Exponents of 1 to 64 - no lost data. Real value shown is an accurate representation of the 80-bit number.
Exponents of 65 and above - 80 digits of precision (computations are to 83/84 digits then rounded).
If you really do want to see the digits beyond the visible limit, you can click on the number and view the number in the amend window as if you were intending to change the FP registers or you can dump or print them, in which case the value will not be truncated (subject to the paper size when printing!).
Changing the FP registers using GoBug
You can amend an active FP register (this is explained below). Click on either the exponent, mantissa or the value, and an amend window will appear. Alternatively if the FP pane has the keyboard focus, press enter to make the highlight appear then press enter again.You can use ESC to make it go away, but if you do want to amend, you can delete the digits to be changed, enter new digits and press enter to change the register contents. Note when amending the value, both the exponent and the mantissa are likely to change to suit the new value. The new value must be inserted as a real number. Note that if you enter a real number which has several digits, the value which appears in the floating register pane may not correspond exactly to the real number which you entered. This is normal behaviour and arises because the floating point register may not be able to retain that particular number to the same accuracy as you have entered it. The real number which eventually appears will be the closest to the number you entered that the floating point unit can attain. Also, if you enter a real number with more than one digit before the decimal point, GoBug will show the resulting real number in scientific format (only one digit before the decimal point) with the decimal exponent adjusted accordingly. Entering new values as real numbers in this way and checking what number appears is a good study of the accuracy obtainable from the floating point registers.
The maxima and minima which can be entered are:-
The floating point exponent - +4001h to -3FFEh The mantissa - 00000000 00000000 to FFFFFFFF FFFFFFFF. The value in real number format approx 3.3621031431120935063E-4932 to 1.189731495357231765E4932.In order to achieve an FP register amendment GoBug has to simulate processor instructions. For this reason you may find the amendment also change the status word, control word and flags. Amendments will normally be made to an active FP register, that is to say one that already has a value in it. If you try to amend an inactive FP register, the amendment will still be made but the value may show as "empty". This is because the tag word will remain unchanged. To change the tag word so that the FPU knows there is a value in the register either load a number into the register in the usual way (by single-stepping over a load instruction) or insert a value into the register by amending the corresponding MMX register.
Clearing the exception flags
The button on the top right hand corner of the display marked "=0" simulates the FCLEX instruction to clear all exception flags to zero. You can use this button to clear the flags so that you can single-step the next instruction to see if it affects the flags. Either click on the button to operate it or if the FP pane has the keyboard focus, press the space bar. Since the system does not permit direct changes to these flags this is achieved by a simulated FCLEX instruction by the debuggee itself.
The "WAIT" instruction
In your disassembled code you may see a WAIT instruction (opcode 9Bh) which you didn't put in your source code. This may have been inserted automatically by your assembler. This instruction is used to tell the main processor to wait until the co-processor has completed dealing with any exceptions which might have arisen when processing the floating point instruction. Normally the WAIT instruction is not needed at all. However when the 8087 was around (accompanying the 8086/8088 processor chip), the WAIT instruction was needed before every floating point instruction. This was due to a design fault which caused the 8086 to send a floating point instruction to the 8087 but then not wait for the 8087 to finish - it would just go on to process the next instruction which could be another floating point instruction or require the results of a floating point calculation. The fault was corrected in the 80287. I am grateful to Eric Isaacson for his clear explanation in his A386 manual. If your assembler is inserting a lot of WAIT instructions, it probably thinks you want the code to be suitable to run on the 8086/8087 combo - instruct it otherwise or get an update!
The MMX instructions and registers
Later versions of the Intel chip could execute instructions using the MMX mnemonics. These are capable of moving larger blocks of data in one go than the 32 bit transfers which the ordinary registers can do. The data is transferred to and from the MMX registers. In fact these are exactly the same registers as are used for the floating point instructions, except that only 64 bits of the 80 available bits are used. This means that in practice you can't use MMX and FPU (floating point unit) instructions at the same time. It also means that when you view these registers using GoBug's MMX and floating point panes, you are simply looking at the same thing but in different ways.
The MMX Register Pane
To display the MMX register pane click on the "MMX/FPU" toolbar button and then choose the left hand button in the floating toolbar.
The MMX register pane shows the MMX registers with MM0 at the top and MM7 at the bottom. The way the information in the 64 bits is displayed can be altered. Here it is displayed as eight bytes, but you can choose words, dwords or a qword. Bear in mind that the data will appear in a different place as you switch because of the effect of reverse storage.
Changing the MMX registers using GoBug
Click on the register you want to amend. This causes the amend window to appear. Alternatively if the MMX pane has the keyboard focus, press enter to make the highlight appear then press enter again.
Delete the digits you want to change and enter the new digits, then press "Enter". The number must be in hex format (16 digits or less). Don't worry about the spaces, GoBug simply ignores them. You can get rid of the amend window without amending by pressing ESC. Since the system does not allow GoBug to write to these registers directly, to achieve these changes GoBug has to execute a MOVQ instruction on behalf of the debuggee. For this reason when amending, you may see other changes occurring to the MMX registers. These changes will not be significant and are normal.
The 3DNow! register Pane
The 3DNow! registers use the FPU registers but in a different configuration. Currently this is only available in AMD processors from the K6 onwards. Instead of eight 90-bit floating point registers, they are configured as 16 32-bit (single precision) floating point registers. One real and useful difference between the instructions is that (as in the SSE and SSE2 instructions) the "stack" principle of pushing and popping data in the registers is abandoned in favour of direct placement of data, making them much easier to use.
To display the 3DNow! register pane click on the "MMX/FPU" toolbar button and then choose the right hand button in the floating toolbar.
GoBug's display shows the registers with MM0 (high) at the top and MM7 (low) at the bottom. The 3DNow! instructions do not make use of the control word or exception masks and flags so these are not displayed.
You can alter the contents of the 3DNow! registers in the same way as you alter the contents of the FPU. If you don't have an AMD processor in your machine you will be unable to do this though.
The XMM integer register Pane
The integer instructions for the XMM registers were introduced in the Pentium 4. When used in this way they are regarded as 16 64-bit registers and this pane displays the contents of the registers as integers.
To display the XMM registers as integers click on the "XMM registers" toolbar button and then choose the left hand side button in the floating toolbar.
As with the MMX registers you can choose the type of display using the buttons and you can modify the contents of the registers at run-time (when single-stepping) by clicking on the pane (or pressing the enter key when the focus rectangle appears).
The SSE floating point register pane
The SSE instructions use the XMM registers as 32 32-bit (single precision) floating point registers. These instructions were introduced into the Intel processors from the Pentium III.
To display the SSE floating point register pane click on the "XMM registers" toolbar button and then choose the middle button in the floating toolbar.
The SSE2 floating point register Pane
The SSE2 instructions use the XMM registers as 16 64-bit (double precision) floating point registers. These instructions were introduced into the Intel processors from the Pentium 4.
To display the SSE2 floating point register pane click on the "XMM registers" toolbar button and then choose the right hand button in the floating toolbar.
SSE and SSE2 control
This is similar to the control in the floating point unit but there are some important differences. The control flags are kept in the MXCSR register. You can change these flags at run-time using the LDMXCSR (load) and STMXCSR (store) instructions. The MXCSR also reports the results of operations in the exception flags. Like the FPU these are "sticky" and cannot be relied on unless they are cleared immediately before the instruction which is to be tested. When single-stepping you can clear the exception flags by clicking on the "zero exception flags" button (or by pressing the space bar when the pane has the focus).
The exception flags have the following meanings:-
P - precision flag (loss of precision occurred) U - underflow flag (result too small) O - overflow flag (too large a result) Z - zero divide flag (division by zero attempted) D - denormalised flag (operation attempted on denormalised number) Bit 0 I - invalid flag (uncertain result)If the corresponding mask bit is set, no actual exception will result from any of these errors (that is to say the exception handler will not be called).
When the flush to zero bit in the MXCSR is set, the processor acts differently in the case of a floating point underflow. Instead of setting the "O" flag it will return a zero result in the appropriate register with the correct sign, and both the precision and underflow flags will be set.
The DAZ flag (denormals are zeroes) flag is used to permit the processor to pass over an instruction if an operand is a denormal floating point number (invalid). Apparently this is useful for streaming media processing. Note that DAZ was only supported in the later P4 processors and in the Xeon processor. If you try to set it on a processor which does not support it, the program will crash. Because of this there is certain code recommended by Intel to check for DAZ support (see Testbug sample code).
As in the FPU, the rounding control has the following values:-
0=round to nearest or even 1=round down 2=round up 3=chopThere is no precision control in these registers (this is always set to 24-bits for SSE and 53-bits for SSE2 instructions).
If the registers are not available on your processor
If the special register panes are not available on your processor, they will still appear but they will be inactive. A warning line appears at the top of the pane to inform you about this.
Refreshment of the special register panes
The contents of all the panes are refreshed immediately after each single step. If you want to refresh them any other time use the "inspect, refresh all panes/inspectors" menu item.
Dumping the special register panes
Ensure that the pane you want to dump is visible and go to the menu item "file, dump". Click on the appropriate pane which will appear in the menu item. Alternatively right click on the pane and choose "dump the pane". Choose a file name for the dumped file (GoBug will suggest a name). Choose a path for the file to be written (GoBug will remember this for the next time you debug this particular exe). Choose the type of file to make (use ANSI unless you want to make a Unicode file). The file which is created on this dump is plain text with carriage returns and line feeds but no tabs. When dumping a floating point pane the value will be shown as accurately as possible within GoBug's conversion accuracy and it will not be truncated. It is usually best to view the dumped file with an editor set to a fixed width font (as opposed to a proportionally spaced font).
Printing the special register panes
Ensure that the pane you want to print is visible and go to the menu item "file, print". Click on the appropriate pane which will appear in the menu item. Alternatively right click on the pane and choose "print the pane". When printing a floating point pane the value will be printed as accurately as possible within GoBug's conversion accuracy and it will not be truncated. You can change the font used for printing by using the "settings, fonts, when printing" menu item.