CS253 Laboratory session 3
Part 1: Evaluating floating point expressions using the maths co-processor.
A floating point number, N, can be described in scientific notation in the following familiar way
N = M.RE
where M is known as the significand (or coefficient or mantissa), M has the range of values
-1.0 < M < 1.0
E is the exponent and is an integer in the range
- ∞ < E < ∞
R is called the radix and is equal to ten in the case of scientific notation,
R = 10
Thus a number such as 22/7 can be approximated by the following expression,
The IEEE Short Real Format for floating point numbers is similar. These are called “floats” in most languages and can be used inside the maths co-processor such as
the 8087. However there are some differences to consider when compared to scientific notation.
The following line of code found in the DATA segment of the listing of some machine code shows how four bytes are used to store a floating point number,
Address Machine Code Label Assembly Language (define data)
0000 40A00000 SX dd 5.0
you can see from the above that the number 5.0 is stored as four bytes, starting at memory location 0000 in the data segment, this memory location is labelled SX. The four bytes contain 4x8=32 bits of information organised as follows,
40H = 0100,0000b A0H = 1010,0000b 00H = 0000,0000b 00H = 0000,0000b
The number is coded in the 32 bits as follows,
0100,0000 - 1010,0000 - 0000,0000 - 0000,0000
the first bit contains 0 so the number is positive (1 means negative). 0100,0000 – 1010,0000 - 0000,0000 - 0000,0000
the next eight bits contain information about the exponent coded as follows, 1000,0001b = 129 decimal
The exponent is offset by -127 so that both negative and positive exponents can be coded.
So the exponent is E = 129 -127 = 2 or you could say multiply significand by 22 = 4
Finally the final 23 bits store the significand. The first binary digit for all numbers (except 0) is one so this bit is not stored and needs to be added back before working out the signifcand. Zero is a special case where all 32 bits are set to zero.
0100,0000 – 1010,0000 - 0000,0000 - 0000,0000
So add back the first bit
1010,0000 - 0000,0000 - 0000,0000
these bits are coded as 2/1, 4/1, 8/1, 16/1, 32/1,....
or in decimal notation 0.5, 0.25, 0.125, 0.0625, 0.03125, … So the signifcand is 1.010b or 1.25d
So putting it all together in decimal 1.25 × 4 = 5 or binary 1.01 × 22 = 101 = 5
In summary
|
N = S.M.RE
|
|
where
|
(S = -1)or(S = +1)
|
The sign, 1=-ve or 0=+ve, 1st bit.
|
|
0 < M < 1
|
Signifcand (last 23 bits, add backbit=1 at start)
|
|
R = 2
|
radix
|
|
- 127 ≤ E ≤ 128
|
exponent (bits 1 to 8)
|
Rebuild the MASM floating point code shown on the next page that evaluates the length of the hypotenuse given the length of the sides of the triangle are 3 and 4. Confirm the result by inspecting the 32 bit binary result is the same as that calculated above. You could use DOSBox to do this, but we have a VPL assignment that you can paste the code into and run it. Don’t evaluate the code yet, VPL is expecting a different equation. The code is also available in for download as float.asm.
;Program to evaluate SQRT(SX^2+SY^2) ;By: Charles Markham
;Date: 22nd February 2016
;Note SQRT(25)=5 (Calculator expected value)
;Result: 0100,0000 - 1010,0000 - 0000,0000 - 0000,0000 ;First bit 0 => Positive
;Bits 1-9 => =129, Subtract 127 => x2 to the power of 2
;Bits 10.. => [1],010,0000 = 1.01=1.01 ;1.01*4=5.0 QED
.model medium
.8087 ; Tell MASM co-processor is present
.STACK 100h
.DATA
SX dd 4.0 ; short real 4 bytes SX = 4.0
SY dd 5.0 ;
HY dd 0.0 ;
cntrl dw 03FFh ; Control word for 8087
stat dw 0 ; Status after calculation
.CODE ; Start of Program
.STARTUP
FINIT ; Set FPU to default state
FLDCW cntrl ; Round even, Mask Interrupts
FLD SX ; Push SX onto FP stack
FMUL ST,ST(0) ; Multiply ST*ST result on ST
FLD SY ; Push SY onto FP stack
FMUL ST,ST(0) ; Multiply ST*ST
FADD ST,ST(1) ; ADD top two numbers on stack
FSQRT ; Square root number on stack
FSTSW stat ; Load FPU status into [stat]
mov ax,stat ; Copy [stat] into ax
and al,0BFh ; Check all 6 status bits
jnz pass ; If any bit set then jump
FSTP HY ; Copy result from stack into HY
|
mov inc inc mov mov
mov
|
bx,OFFSET RESULT bx
bx
ax,[bx] bx,ax
cx,16
|
;bx=[RESULT+2]+256*[RESULT+3]
|
back:
|
rol
|
bx,1
jc set
|
; Rotate bx
; Check MSB first
|
|
mov
|
dl,'0'
jmp over
|
; If carry set dl='0'
|
set:
|
mov
|
dl,'1'
|
; If carry not set dl='1'
|
over:
|
mov
|
ah,02h
int 021h
|
; Print ASCII of dl
|
|
loop
mov mov mov
mov
|
back
bx,OFFSET RESULT ax,[bx]
bx,ax cx,16
|
; Repeat 16 times
;bx=[RESULT+0]+256*[RESULT+1]
|
back1:
|
rol jc mov jmp
|
bx,1
set1
dl,'0' over1
|
; Rotate bx
; Check MSB first
; If carry set dl=‘0’
|
set1:
|
mov
|
dl,'1'
|
; If carry not set dl=‘1’
|
over1:
|
mov
int
|
ah,02h 021h
|
; Print ASCII of dl
|
|
loop .EXIT
|
back1
|
; Repeat 16 times
|
END
|
|
|
|
Now modify your code to evaluate the following expression, submit this code with comments at the start of the listing demonstrating the result obtained was what was expected.
where A=3 and B=9. Use run and evaluate to attempt to modify the program supplied to give the correct answer.
Hint: Replace SX by A and SY by B and then consider changing the stack operations to realise the equation requested. Evaluating a cube may require you to FLD A a second time.
Expected result:
Expected output: 0,10000011,11100000..... ,132-127=5, 1.111x2^5=11110b=30d
To do: Submit this code using the VPL link on the sandbox page for evaluation
Part 2: So far we have created and compiled a number of assembly language programs using the Microsoft assembler (MASM). Writing a big program using MASM is probably impractical. However, you can embed assembly language in your C\C++ programs. This is something that you could do in practice so as to optimise a piece of code or make use of instructions that are not accessible via the standard libraries (such a MMX, multimedia extension).
This approach has the benefit of allowing you to write the input and output in C/C++ and use the assembly language for high speed calculation.
It should be said that in practice compilers are so good that it is very difficult to write better machine code than they can generate.
Launch Microsoft Visual Studio 2010 and create a new Windows 32 bit Console Application. Call the project MASM_FP.sln, other names will not work. On the solution explorer double click on the Sources folder and the open the file
MASM_FP.cpp. Replace the boiler plate code provided by Microsoft with the code shown on the next page.
Figure 1: Launch VS2010
Create a New Project of type C++ (not c#) Windows 32 Console application called MASM_FP (short for Microsoft Assembler Floating Point). You could call it what you like.
Figure 2: Create a new Windows 32 console application in C++.
The project could be saved locally in c:\temp or in x:\CS253 on your own disk drive
Figure 3: Create a new Windows 32 console application in C++.
Cut and paste the following MASM_FP code from the next page of this handout and use it to replace all the exisitng code contained in MASM_FP.cpp. You may need to click on the Solution Explorer in Visual Studio to find this file. If the IDE gets in a muddle then just choose Window – Reset Windows Layout from the toolbar. Set the configuration manager from “Debug” to “Release” and then compile and run the code by clicking on the green triangle “play” button.
Figure 3: Entering the code, compile and run within the Visual Studio IDE.
All being well you should produce a run display that allows you to enter two numbers (short integers) and display the sum of the two. This makes use of in-line assembly language to do the addition.
Figure 4: Addition using Assembly Language, Input and Output using C++.
Program 1
// MASM_FP.cpp : Defines the entry point for the console application.
#include "stdafx.h" #include
void test(void); // Function prototype (description) int _tmain(int argc, _TCHAR* argv[])
{
test();
return 0;
}
// Put our unmanaged asm code in here
void test() {
unsigned short num1;
unsigned short num2;
unsigned short result;
printf("Enter first number: "); scanf(" %hd",&num1);
printf("Enter second number: "); scanf(" %hd",&num2);
asm
__
{
mov ax, num1 ; Direct addressing to access num1 mov bx, num2 ; put value in num2 into bx
add ax, bx ; ax=ax+bx
mov result,ax; ; put value into result }
printf("%hd",result); // Display result
// Wait for enter to be pressed before terminating
while(getchar()!=10); // Clear buffer of previous while(getchar()!=10); // Wait for a new
}