; Project #2 ; S. Laufer ; CS221-01 - Fall 2010 dosseg .186 .8087 .model large .stack 200h .data float1 dd ? float2 dd ? float3 dd ? prompt db 'Enter a float: ',0 crlf db 13,10,0 s_div db ' / ',0 s_mul db ' * ',0 s_sub db ' - ',0 s_add db ' + ',0 s_eq db ' = ',0 .code ProgramStart proc mov ax, @data mov ds, ax ; greet() call Greet ; // this section prompts for and reads the first float ; puts(prompt); ; cin >> float1 ; cout << float1 << endl push offset prompt call WriteStr push offset float1 call ReadFloat push float1 call disp push offset crlf call WriteStr ; this section prompts for and reads the second float ; puts(prompt); ; cin >> float1 ; cout << float1 << endl push offset prompt call WriteStr push offset float2 call ReadFloat push float2 call disp push offset crlf call WriteStr ; // this section divides the first float by the second float ; float3 = float1 / float2 fld float1 fld float2 fdiv fwait fstp float3 ; cout << float1 << " / " << float2 << " = " << float3 << endl push float1 call disp push offset s_div call WriteStr push float2 call disp push offset s_eq call WriteStr push float3 call disp push offset crlf call WriteStr ; // this section multiplies the first float by the second float ; float3 = float1 * float2 fld float1 fld float2 fmul fwait fstp float3 ; cout << float1 << " * " << float2 << " = " << float3 << endl push float1 call disp push offset s_mul call WriteStr push float2 call disp push offset s_eq call WriteStr push float3 call disp push offset crlf call WriteStr ; // this section adds the first float to the second float ; float3 = float1 + float2 fld float1 fld float2 fadd fwait fstp float3 ; // this section subtracts the second float from the first float ; cout << float1 << " + " << float2 << " = " << float3 << endl push float1 call disp push offset s_add call WriteStr push float2 call disp push offset s_eq call WriteStr push float3 call disp push offset crlf call WriteStr ; float3 = float1 - float2 fld float1 fld float2 fsub fwait fstp float3 ; cout << float1 << " - " << float2 << " = " << float3 << endl push float1 call disp push offset s_sub call WriteStr push float2 call disp push offset s_eq call WriteStr push float3 call disp push offset crlf call WriteStr ; putchar('\n') push offset crlf call WriteStr ; exit(0) mov ah, 4ch int 21h ProgramStart endp ; ========= ; ReadFloat ; ========= ; Reads a floating point number. .data read db 128 DUP (?) inv_ent db 'Invalid Entry. Please try again.',13,10,'$' sign db ? tmp dw ? base dw 10 .code ReadFloat proc near pusha pushf mov bp, sp ; cin.get(read, 256); read_start: push word ptr 256 push offset read call ReadStr ; bx = read mov bx, offset read ; cl = si = 0 xor cl,cl xor si,si mov sign, 0 cmp [bx], byte ptr '-' jne noneg mov sign, 1 inc bx noneg: ; // this section validates input ; for (i = 0; read[i] != '\0'; i++) { ; if ((read[i] < '0' || read[i] > '9') && read[i] != '.') ; goto read_start ; } testloop_start: cmp [bx+si], byte ptr 0 je testloop_end cmp [bx+si], byte ptr '0' jb notdec cmp [bx+si], byte ptr '9' jbe valid notdec: cmp [bx+si], byte ptr '.' jne invalid cmp cl, 1 jae invalid inc cl valid: inc si jmp testloop_start invalid: mov ah, 9 mov dx, offset inv_ent int 21h jmp read_start testloop_end: ; float0 = 0.0 fldz dec si ; // this section isolates the fractional portion ; while (read[i] != 0) { ; if (read[i] == '.') break; ; float0 = read[i] - '0'; ; float0 /= 10 ; } cmp cl, 0 je nofrac xor ah, ah frac: cmp [bx+si], byte ptr '.' je endfrac mov al, [bx+si] sub al, '0' mov temp, ax fiadd temp fidiv base dec si jmp frac endfrac: dec si nofrac: ; float1 = float0 ; float0 = 0.0 fldz ; // this section isolates the integer portion ; i = 0 ; while (read[i] >= '0' && read[i] <= '9') { ; float0 *= 10 ; float0 += read[i] - '0' ; } xor si, si xor ah, ah wholepart: cmp [bx+si], byte ptr '0' jb endwholepart cmp [bx+si], byte ptr '9' ja endwholepart fimul base mov al, [bx+si] sub al, '0' mov temp, ax fiadd temp inc si jmp wholepart endwholepart: ; // combine the two parts ; float0 += float1 ; float1 = 0.0 fadd ; // store the answer to the output parameter ; *arg = float0 mov bx, [bp+20] fwait fstp dword ptr [bx] cmp sign, 1 jne noneg1 or [bx+2], 8000h noneg1: ; // and done ; return popf popa ret 2 ReadFloat endp ; ==== ; disp ; ==== ; displays a floating point number. .data numb dd ? fract dd ? twoTimes dd ? temp dw ? whole dw ? .code disp proc near pusha pushf mov bp, sp ; numb = arg; mov dx, [bp+20] mov word ptr numb, dx mov dx, [bp+22] mov word ptr numb+2, dx ; sets rounding control to trunc fstcw temp or temp,0c00h fldcw temp ; float0 = numb; ; if (float0 < 0) { putchar('-'); } fld numb ftst fstsw temp mov ax, temp and ax,4500h cmp ax,0100h jne disp1 mov al,'-' call disps ; float0 = abs(float0) ; float0 = floor(float0) ; whole = int(float0) ; float1 = float0 ; float0 = numb ; float0 = abs(float0) ; float0 = float0 - float1 ; fract = float0 ; float0 = float1 disp1: fabs frndint fist whole fld numb fabs fsubr fstp fract ; ax = whole ; cx = 0 ; bx = 10 mov ax,whole xor cx,cx mov bx,10 ; do { ; dx = (ax % 10) ; ax -= dx ; ax /= 10 ; putchar(dx + '0') ; } while (ax > 0) disp2: inc cx xor dx,dx div bx add dx,'0' push dx test ax,ax jnz disp2 disp3: pop ax call disps loop disp3 ; putchar('.') mov al,'.' call disps ; not sure how to make the below sections ; look like a high-level language due to bitwise operations ; copy fract into dx:ax mov ax,word ptr fract mov dx, word ptr fract+2 ; isolate exponent mov bx,dx and bx,7f80h mov cl,7 shr bx,cl mov bh,127 sub bh,bl ; shift mantissa over mov cx,8 disp4: shl ax,1 rcl dx,1 loop disp4 ; set first 4 bytes of dx or dx,8000h xchg ax,dx dec bh mov cl,bh ; if exponent is 0 we don't need to adjust test cx,cx jz disp6 ; adjust for exponent disp5: shr ax,1 rcr dx,1 loop disp5 disp6: mov cx,4 disp7: shr ax,1 rcr dx,1 loop disp7 ; print out individual characters disp8: shl dx,1 rcl ax,1 mov word ptr twoTimes+2, ax mov word ptr twoTimes, dx shl dx,1 rcl ax,1 shl dx,1 rcl ax,1 add dx, word ptr twoTimes adc ax, word ptr twoTimes+2 push ax and ax,0f000h mov al,ah mov cl,4 shr al,cl add al,'0' push dx call disps pop dx pop ax and ax, 0fffh push ax sub ax,dx jz disp9 pop ax jmp disp8 disp9: pop ax popf popa ret 4 disp endp ; ===== ; disps ; ===== ; this simple procedure prints out one character .code disps proc near mov ah,6 mov dl,al int 21h ret disps endp ; ===== ; Greet ; ===== ; This procedure prints a simple greeting message. .data GreetMsg db 'Program: Reads , operates on and writes floats',13,10, \ 'Programmer: S. Laufer',13,10, \ 'Date: October 31, 2010',13,10,13,10,0 .code Greet proc near ;void greet() { pusha pushf push offset GreetMsg call WriteStr popf popa ret ; return Greet endp ;} ; ===================== ; WriteStr (char * ptr) ; ===================== ; writes a null-terminated string to the console. WriteStr proc near ;void writestr(char * ptr) { pusha pushf ; Read the argument in mov bp, sp mov bx, [bp+20] ; bx = ptr ; Start at the pointer passed, print the byte pointed to, ; then increment the counter, until we get 0x00 (NULL) printloop0_start: ; while (*bx != 0) { mov ah, 0 cmp ah, [bx] je printloop0_end mov ah, 2 ; putchar(*bx) mov dl, [bx] int 21h inc bx ; bx++ jmp printloop0_start ; } printloop0_end: popf popa ret 2 ; return WriteStr endp ;} ; ===================================== ; ReadStr (char * PTR, short SIZE) ; ===================================== ; Reads a string of SIZE length from the console, stores it beginning at ; *PTR. When (SIZE - 1) characters have been read, or 0x0D (CR) is read, ; reading stops and a null terminator is inserted in the next position. If ; the string entered is greater than (SIZE - 1) characters, all subsequent ; characters leading up to 0x1D (CR) are discarded. ReadStr proc near ;void ReadStr(char * PTR, short SIZE) { pusha pushf mov bp, sp ; Read the arguments in mov bx, [bp+20] ; bx = PTR mov dx, [bp+22] ; dx = SIZE dec dx ; dx-- mov cx, 0 ; cx = 0 ; While we don't get 0x0D (CR), read characters into ; the pointer that was passed in, incrementing the pointer ; with each character mov ah, 1 ; ah = 1 readloop0_start: ; while ((al = getchar()) != 13) { int 21h cmp al, 13 je readloop0_end cmp cx, dx ; if (cx >= dx) jae readloop0_overflow ; goto overflow mov [bx], al ; *bx = al inc bx ; bx++ inc cx ; cx++ jmp readloop0_start ; } readloop0_end: ; If we got too many characters (more than SIZE-1), read them ; and immediately discard them until we get 0x0D (CR) jmp readloop0_overflow_end ; goto notoverflow readloop0_overflow: ; overflow: int 21h ; while ((al = getchar()) != 13) {} cmp al, 13 jne readloop0_overflow readloop0_overflow_end: ; notoverflow: ; Put a null terminator at the end of the string mov byte ptr [bx], 0 ; *bx = 0 popf popa ret 4 ; return ReadStr endp ;} end ProgramStart