Assembly Language Programming

August 31, 2012

FASM – Binary To Decimal Conversion

This program takes a string containing a large binary, octal or hexadecimal unsigned integer and converts it to a decimal number. The input number can be up to 400 bytes in length (3200 binary digits, 800 hex digits, or 1066 octal digits).

A decimal representation of a binary value stored in memory is generated by decomposing it into a sum of its powers of ten:


Num = d(n) * 10n + d(n-1) * 10n-1 + … + d(0) * 100

i.e. for each power of ten from 0 to n (where 10n is the largest power of ten not greater than the binary number), the digit d needs to be found.

The algorithm to find the most significant decimal digit from a binary number is as follows:

GET_DIGIT:

Find the left-most decimal digit in Num:

Let n be the power of ten and x=10n.

(1) Start with n=0 and x=1.

(2) Find the largest power of ten not greater than Num:

    - set n = n + 1.

    - multiply x by 10: x = (x << 1) + (x << 3).

    - repeat until: 10 * x < Num <= x.

(3) Find the digit d(n):

    - set d=0.

    - subtract x from Num, until: Num < x.

    - increment d for each subtraction.

    - d is the value of the left-most decimal digit.

The above GET_DIGIT algorithm is applied repeatedly until all of the decimal digits have been found. Each time GET_DIGIT is called, Num is reduced until it eventually reaches zero.

The function that calls GET_DIGIT must also make sure that zeroes are correctly inserted into the string containing the decimal representation of the binary value:

BINARY_TO_DECIMAL:

  d,n = GET_DIGIT;

  outstr += d;

  n_prev = n; 

  while(Num > 0)
  {
   d,n = GET_DIGIT;

   // if (n_prev - n) is greater than 1, zeroes need to inserted before d is appended

   nZeroes = n_prev - n - 1;

   if(nZeroes > 0)
   {
    for(i = 0;i < nZeroes;i++) outstr += "0";
   } 

   outstr += d;

   n_prev = n; 
  }

  // Num is now zero

  if(n > 0)
  {
   for(i = 0;i < n;i++) outstr += "0";
  }

The FASM x86 Code

To grab this code, select it with the mouse and copy it. It can then be pasted directly into the FASM IDE.

; -------------------------------------------------------------------------------------

 format PE GUI 4.0

 entry start

 include 'win32a.inc'

; -------------------------------------------------------------------------------------

 IDD_THE_DIALOG = 102

 IDC_INPUT = 1000
 IDC_HEX = 1001
 IDC_OUTPUT = 1002

 IDC_BTN_BIN_TO_DEC = 1003
 IDC_BTN_HEX_TO_DEC = 1004
 IDC_BTN_OCT_TO_DEC = 1005
 IDC_BTN_DEC_TO_DEC = 1006

 IDC_BTN_CLEAR = 1007

; -------------------------------------------------------------------------------------

 section '.code' code readable executable

  start:

    invoke GetModuleHandle,0
    invoke DialogBoxParam,eax,IDD_THE_DIALOG,0,DialogProc,0

  exit:

    invoke  ExitProcess,0 

; -------------------------------------------------------------------------------------

proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam

	cmp [msg],WM_INITDIALOG
	je .wminitdialog

	cmp [msg],WM_COMMAND
	je .wmcommand

	cmp [msg],WM_CLOSE
	je .wmclose

	xor eax,eax
	jmp .quit

  .wminitdialog:

	invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputInfoText
	invoke SetDlgItemText,[hwnddlg],IDC_HEX,szOutputInfoText
	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,szOutputInfoText

	jmp .done

  .wmcommand:

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_BIN_TO_DEC
	je .BIN_TO_DEC

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_HEX_TO_DEC
	je .HEX_TO_DEC

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_OCT_TO_DEC
	je .OCT_TO_DEC

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_DEC_TO_DEC
	je .DEC_TO_DEC

	cmp  [wparam], BN_CLICKED shl 16 + IDC_BTN_CLEAR
	je .CLEAR_DATA

	jmp .done

  .BIN_TO_DEC:

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200

	stdcall onNullInput

	stdcall BinStrToBuffer

	stdcall PrintInputAsHex

	invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay

	stdcall ConvertToDecimal

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay

	jmp .done

  .HEX_TO_DEC:

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200

	stdcall onNullInput

	stdcall HexStrToBuffer

	stdcall PrintInputAsHex

	invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay

	stdcall ConvertToDecimal

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay

	jmp .done

  .OCT_TO_DEC:

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200

	stdcall onNullInput

	stdcall OctStrToBuffer

	stdcall PrintInputAsHex

	invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay

	stdcall ConvertToDecimal

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay

	jmp .done

  .DEC_TO_DEC:

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,3200

	stdcall onNullInput

	stdcall DecStrToBuffer

	stdcall PrintInputAsHex

	invoke SetDlgItemText,[hwnddlg],IDC_HEX,bfDisplay

	stdcall ConvertToDecimal

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay

	jmp .done

   .CLEAR_DATA:

	invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputInfoText
	invoke SetDlgItemText,[hwnddlg],IDC_HEX,szOutputInfoText
	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,szOutputInfoText

	jmp .done

  .wmclose:

	invoke EndDialog,[hwnddlg],0

  .done:

	mov eax,1

  .quit:

	ret

endp

; -------------------------------------------------------------------------------------

proc StrToHexStr uses esi edi

  ; filter out any non hex digit characters from the bfDisplay string

	lea esi,[bfDisplay]
	lea edi,[bfDisplay]

	mov [nInputChars],word 0

  .FILTER:

	mov al,[esi]

	cmp al,0

	je .DONE

	cmp al,48

	jl .NOT_HEX

	cmp al,57

	jle .COPY

	cmp al,65

	jl .NOT_HEX

	cmp al,70

	jle .COPY

	cmp al,97

	jl .NOT_HEX

	cmp al,102

	jg .NOT_HEX

  .COPY:

	mov [edi],al

	inc edi

	inc word [nInputChars]

	; max input size = 400 bytes (800 hex digits)

	cmp [nInputChars],800

	jge .DONE

  .NOT_HEX:

	inc esi

	jmp .FILTER

  .DONE:

	; null terminate the new string

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc StrToOctStr uses esi edi

  ; filter out any non octal digit characters from the bfDisplay string

	lea esi,[bfDisplay]
	lea edi,[bfDisplay]

	mov [nInputChars],word 0

  .FILTER:

	mov al,[esi]

	cmp al,0

	je .DONE

	cmp al,48

	jl .NOT_OCT

	cmp al,55

	jg .NOT_OCT

  .COPY:

	mov [edi],al

	inc edi

	inc word [nInputChars]

	; max input size = 400 bytes (1066 oct digits)

	cmp [nInputChars],1066

	jge .DONE


  .NOT_OCT:

	inc esi

	jmp .FILTER

  .DONE:

	; null terminate the new string

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc StrToBinStr uses esi edi

  ; filter out any non binary digit characters from the bfDisplay string

	lea esi,[bfDisplay]
	lea edi,[bfDisplay]

	mov [nInputChars],word 0

  .FILTER:

	mov al,[esi]

	cmp al,0

	je .DONE

	cmp al,48

	jl .NOT_BIN

	cmp al,49

	jg .NOT_BIN

  .COPY:

	mov [edi],al

	inc edi

	inc word [nInputChars]

	; max input size = 400 bytes (3200 binary digits)

	cmp [nInputChars],3200

	jge .DONE


  .NOT_BIN:

	inc esi

	jmp .FILTER

  .DONE:

	; null terminate the new string

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc StrToDecStr uses esi edi

  ; filter out any non decimal digit characters from the bfDisplay string

	lea esi,[bfDisplay]
	lea edi,[bfDisplay]

	mov [nInputChars],word 0

  .FILTER:

	mov al,[esi]

	cmp al,0

	je .DONE

	cmp al,48

	jl .NOT_DEC

	cmp al,57

	jg .NOT_DEC

  .COPY:

	mov [edi],al

	inc edi

	inc word [nInputChars]

	; max input size = 400 bytes (963 decimal digits)

	cmp [nInputChars],963

	jge .DONE


  .NOT_DEC:

	inc esi

	jmp .FILTER

  .DONE:

	; null terminate the new string

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc HexStrToBuffer

  ; convert a string containing a HEX number to a value in memory

  ; the input string is in bfDisplay

  ; the value is written to InputBuffer

	locals

	  count dw 0

	endl

	; reset the input buffer

	stdcall ResetInputBuffer

	; filter bfDisplay so that it only contains HEX digits

	stdcall StrToHexStr

	lea esi,[bfDisplay]
	lea edi,[InputBuffer]

	; the hex digits are read from the beginning of the display string
	; and mapped to the corresponding position in the input buffer

	xor edx,edx

	mov dx,[nInputChars]

	; set cx to nInputChars, loop below ends when cx = 0

	mov ecx,edx

	; adjust EDI: EDI = EDI + (nInputChars-1)/2

	dec edx
	shr edx,1

	add edi,edx

	; use count to count the chars as they are read from the display string

	test [nInputChars],1

	jz .GET_CHARS

	; if there are an odd number of hex digits, init count to 1

	inc word [count]

  .GET_CHARS:

	mov al,byte [esi]

	; check for NULL terminator

	cmp al,0

	je .DONE

	stdcall HexDigitToValue

	; AL contains a nibble, determine where to place it in the dest byte

	; if count is even, the nibble is mapped to the lower 4 bits in dest
	; if count is odd, the nibble is mapped to the upper 4 bits in dest

	inc word [count]

	; even if count AND 1 == 0

	test [count],1

	jz .EVEN

  .ODD:

	shl al,4

	mov [edi],al

	jmp .NEXT

  .EVEN:

	or [edi],al

	dec edi

  .NEXT:

	dec cx

	inc esi

	jcxz .DONE

	jmp .GET_CHARS

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc OctStrToBuffer

  ; convert a string containing a OCT number to a value in memory

  ; the input string is in bfDisplay

  ; the value is written to InputBuffer

	; reset the input buffer

	stdcall ResetInputBuffer

	; filter bfDisplay so that it only contains OCT digits

	stdcall StrToOctStr

	lea esi,[bfDisplay]
	lea edi,[InputBuffer]

	xor edx,edx

	mov dx,[nInputChars]

	; start from the end of the bfDisplay string

	add esi,edx
	dec esi

	; read 8 digits at a time

	shr dx,3

	mov cx,dx

	; if there are less than 8 digits in bfDisplay, jump to .LAST

	jcxz .LAST

  .GET_DIGITS:

	; process 8 digits at a time

	mov dx,8

	; convert to 3 bytes

	stdcall OctToBytes

	; insert the 3 bytes into InputBuffer

	mov [edi],al
	inc edi

	mov [edi],ah
	inc edi

	shr eax,16

	mov [edi],al
	inc edi

	dec cx

	jcxz .LAST

	jmp .GET_DIGITS

  .LAST:

	; process the last few digits

	mov dx,[nInputChars]

	test dx,7

	; if zero, the number of digits in bfDisplay was a multiple of 8

	jz .DONE

	and dx,7

	stdcall OctToBytes

	mov [edi],al
	inc edi

	mov [edi],ah
	inc edi

	shr eax,16

	mov [edi],al
	inc edi

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc BinStrToBuffer

  ; convert a string containing a BIN number to a value in memory

  ; the input string is in bfDisplay

  ; the value is written to InputBuffer

	; reset the input buffer

	stdcall ResetInputBuffer

	; filter bfDisplay so that it only contains BIN digits

	stdcall StrToBinStr

	lea esi,[bfDisplay]
	lea edi,[InputBuffer]

	; the binary digits are read from the beginning of the display string
	; and mapped to the corresponding position in the input buffer

	; 8 digits are read at a time

	xor edx,edx

	mov dx,[nInputChars]

	; set cx to nInputChars, loop below ends when cx = 0

	mov cx,dx

	; adjust EDI: EDI = EDI + (nInputChars-1)/8

	dec edx
	shr edx,3

	add edi,edx

	; the input string is processed 8 digits at a time

	; if the length of bfDisplay is not a multiple of 8, then the
	; first byte in this string will have less than 8 binary digits

	; in this case initialise dx to (nInputChars mod 8)

	xor edx,edx

	mov dx,[nInputChars]

	and dx,7

	test dx,7

	jnz .GET_BYTES

	mov dx,8

  .GET_BYTES:

	; convert 8 binary bits (digits) to a byte

	stdcall BinDigitsToByte

	; insert byte into InputBuffer

	mov [edi],al

	sub cx,dx

	dec edi

	mov dx,8

	jcxz .DONE

	jmp .GET_BYTES

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc DecStrToBuffer

  ; convert a string containing a DEC number to a value in memory

  ; the input string is in bfDisplay

  ; the value is written to InputBuffer

	; reset the input buffer

	stdcall ResetInputBuffer

	; clear the Ten_N buffer

	stdcall Init_Ten_N

	mov [Ten_N_Buffer],byte 0

	; filter bfDisplay so that it only contains DEC digits

	stdcall StrToDecStr

	lea esi,[bfDisplay]

	mov cx,[nInputChars]

  .GET_DIGITS:

	xor eax,eax

	; get the digit

	mov al,[esi]
	sub al,48

	cmp al,0

	je .MULTIPLY

	; add the digit to the lower dword of the buffer

	lea edx,[Ten_N_Buffer]

	stdcall AddDWordToBuffer

  .MULTIPLY:

	; multiply the buffer by 10

	inc esi

	dec cx

	jcxz .DONE

	stdcall MultiplyByTen

	lea eax,[TempBuffer_1]
	lea edx,[Ten_N_Buffer]

	stdcall CopyBuffer

	jmp .GET_DIGITS

  .DONE:

	lea eax,[Ten_N_Buffer]
	lea edx,[InputBuffer]

	stdcall CopyBuffer

	ret

endp

; -------------------------------------------------------------------------------------

proc PrintInputAsHex uses esi edi

  ; print the contents of InputBuffer as a HEX value to the bfDisplay string

	locals

	  count db 0

	endl

	lea edi,[bfDisplay]

	lea esi,[InputBuffer]

	add esi,399

	mov cx,400

  .PRINT:

	; byte to digits

	mov al,[esi]

	stdcall ByteToDigits

	; add the 2 digits to the string

	mov [edi],ah
	inc edi

	mov [edi],al
	inc edi

	dec cx

	jcxz .DONE

	; update ESI

	dec esi

	; add spaces and CRLF to the output string

	; a space after every 8 chars
	; a CRLF after every 80 chars

	add [count],2

	test [count],7

	jne .PRINT

	cmp [count],79

	je .ADD_CRLF

	mov [edi],byte 32

	inc edi

	jmp .PRINT

  .ADD_CRLF:

	mov [count],0

	mov [edi],byte 13

	inc edi

	mov [edi],byte 10

	inc edi

	jmp .PRINT

  .DONE:

	; zero terminate the string

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc onNullInput

  ; if the bfDisplay string is empty, set it to "0"

	lea edi,[bfDisplay]

	cmp [edi],byte 0

	jne .DONE

	mov [edi],byte 48
	mov [edi+1],byte 0

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc HexDigitToValue

  ; convert a hex digit to a 4 bit value

  ; input in AL - output in AL

	; is AL in the range: 48 - 57 (0 - 9) ?

	cmp al,48

	jl .NOT_HEX

	cmp al,57

	jg .A_Z

	sub al,48

	jmp .DONE

  .A_Z:

	; is AL in the range: 65 - 70 (A - B) ?

	cmp al,65

	jl .NOT_HEX

	cmp al,70

	jg .a_z

	sub al,55

	jmp .DONE

  .a_z:

	; is AL in the range: 97 - 102 (a - b) ?

	cmp al,97

	jl .NOT_HEX

	cmp al,102

	jg .NOT_HEX

	sub al,87

	jmp .DONE

  .NOT_HEX:

	; set EAX to 0xffff if input is not a valid hex digit

	mov eax,0xffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc ByteToDigits

  ; convert 1 byte to 2 hex digits

  ; input in AL - output in AX

	; copy AL to AH

	mov ah,al

	; AH: get the upper 4 bits of the byte

	shr ah,4

	; nibble to hex digit

	add ah,48

	cmp ah,57

	jle .NEXT

	add ah,7

  .NEXT:

	; AL: get the lower 4 bits of the byte

	and al,0xf

	; nibble to hex digit

	add al,48

	cmp al,57

	jle .DONE

	add al,7

  .DONE:

	; output is in AX

	ret

endp

; -------------------------------------------------------------------------------------

proc BinDigitsToByte uses ecx edx

  ; convert up to 8 binary digits to a byte value

  ; number of digits is in EDX

  ; ESI is initialised outside of this proc

	mov cx,dx

	xor eax,eax

  .GET_DIGITS:

	mov dl,[esi]

	inc esi

	cmp dl,48

	je .SHIFT

	or al,1

  .SHIFT:

	dec cx

	jcxz .DONE

	shl al,1

	jmp .GET_DIGITS

  .DONE:

	; AL now contains the byte value

	ret

endp

; -------------------------------------------------------------------------------------

proc OctToBytes uses ecx

  ; convert up to 8 octal digits to 3 bytes

  ; bytes are returned in EAX

  ; ESI points to the least significant digit

  ; ESI is set outside this proc

  ; the number of digits to process is passed in DX

	locals

	  nDigits dw 0

	endl

	mov [nDigits],dx

	xor eax,eax

	; CX is an index (0-7)

	xor ecx,ecx

	mov cl,dl

	; if there are zero digits, do nothing

	jcxz .DONE

	; make sure CX = 0-7

	dec cx

  .GET_DIGITS:

	mov dl,[esi]

	sub dl,48

	; OR the value into the upper 3 bits of EAX

	shl edx,29

	or eax,edx

	dec esi

	jcxz .DONE

	; right shift EAX by 3 bits

	shr eax,3

	dec cx

	jmp .GET_DIGITS

  .DONE:

	; adjust EAX so that the final value is in the lower 3 bytes

	shr eax,8

	cmp [nDigits],8

	jge .QUIT

	; if there were less than 8 digits, further adjust EAX

	; i.e. for each digit less than 8, shift right EAX by 3 bits

	mov cx,8

	sub cx,[nDigits]

	; multiply CX by 3

	mov dx,cx

	shl dx,1

	add cx,dx

	; adjust EAX

	shr eax,cl

  .QUIT:

	ret

endp

; -------------------------------------------------------------------------------------

proc ResetInputBuffer uses edi ecx

  ; clear the input buffer

	lea edi,[InputBuffer]

	mov cx,0

  .CLEAR:

	mov [edi],byte 0

	inc edi

	inc cx

	cmp cx,400

	jl .CLEAR

	ret

endp

; -------------------------------------------------------------------------------------

proc ConvertToDecimal

  ; convert the hex value stored in InputBuffer to a string of decimal digits

	locals

	  Last_Power_N dw 0

	endl

	lea edi,[bfDisplay]

  .ZERO_INPUT:

	; if the input is zero, just exit

	lea eax,[InputBuffer]

	stdcall IsZero

	cmp al,1

	je .DONE

  .FIRST:

	; get the first digit

	stdcall GetNextDigit

	jmp .ADD_DIGIT

  .PROCESS:

	; get the next digit

	stdcall GetNextDigit

	; update the power of ten: N

	mov cx,[Last_Power_N]
	sub cx,[Power_N]

	cmp cx,1

	jle .ADD_DIGIT

	sub cx,1

  .INSERT:

	; if the difference between the current N and the previous N
	; is greater than 1, insert zeroes into the output string

	mov [edi],byte 48

	inc edi

	dec cx

	jcxz .ADD_DIGIT

	jmp .INSERT

  .ADD_DIGIT:

	; add the digit to the string

	mov al,[Digit]
	mov [edi],al

	inc edi

	mov ax,[Power_N]
	mov [Last_Power_N],ax

	; has InputBuffer been reduced to zero

	lea eax,[InputBuffer]

	stdcall IsZero

	cmp al,1

	je .FINAL

	jmp .PROCESS

  .FINAL:

	mov cx,[Power_N]

	jcxz .DONE

  .APPEND:

	; if InputBuffer has been reduced to zero, but N is still
	; greater than zero, append zeroes to the output string

	mov [edi],byte 48

	inc edi

	dec cx

	jcxz .DONE

	jmp .APPEND

  .DONE:

	; NULL terminate bfDisplay

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc GetNextDigit

  ; find the most siginificant decimal digit for the hex value stored in InputBuffer

	; set Ten(N) = 1

	stdcall Init_Ten_N

	mov [Power_N],word 0

  .FIND:

	; Ten(N) = Ten(N) * 10

	stdcall MultiplyByTen

	lea eax,[TempBuffer_1]
	lea edx,[InputBuffer]

	; when(TempBuffer_1 greater than InputBuffer) goto .GET_DIGIT

	stdcall Compare

	cmp al,4

	je .GET_DIGIT

	; update Ten(N)

	lea eax,[TempBuffer_1]
	lea edx,[Ten_N_Buffer]

	stdcall CopyBuffer

	inc [Power_N]

	jmp .FIND

  .GET_DIGIT:

	mov [Digit],byte 0

  .CALC:

	; InputBuffer = InputBuffer - Ten(N)

	lea eax,[Ten_N_Buffer]
	lea edx,[InputBuffer]

	stdcall CalcDiff

	inc [Digit]

	lea eax,[InputBuffer]
	lea edx,[Ten_N_Buffer]

	; when((InputBuffer less than Ten(N)) = TRUE) break

	stdcall Compare

	cmp al,1

	je .DONE

	jmp .CALC

  .DONE:

	; convert Digit to an ASCII value

	add [Digit],byte 48

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_Ten_N uses edi ecx

  ; clear the Ten_N_Buffer value and then init to 1

	lea edi,[Ten_N_Buffer]

	mov cx,0

  .CLEAR:

	mov [edi],byte 0

	inc edi

	inc cx

	cmp cx,400

	jl .CLEAR

	; set equal to 1

	mov [Ten_N_Buffer],byte 1

	ret

endp

; -------------------------------------------------------------------------------------

proc MultiplyByTen

  ; multiply the value in Ten_N_Buffer by 10

  ; result is saved in TempBuffer_1

  ; A x 10 = SHL(A,1) + SHL(A,3)

	; TempBuffer_1 = A

	lea eax,[Ten_N_Buffer]
	lea edx,[TempBuffer_1]

	stdcall CopyBuffer

	; SHL(TempBuffer_1,1)

	lea eax,[TempBuffer_1]

	stdcall ShiftLeft

	; TempBuffer_2 = SHL(A,1)

	lea eax,[TempBuffer_1]
	lea edx,[TempBuffer_2]

	stdcall CopyBuffer

	; TempBuffer_2 = SHL(A,2)

	lea eax,[TempBuffer_2]

	stdcall ShiftLeft

	; TempBuffer_2 = SHL(A,3)

	lea eax,[TempBuffer_2]

	stdcall ShiftLeft

	; TempBuffer_1 = TempBuffer_1 + TempBuffer_2

	lea eax,[TempBuffer_2]
	lea edx,[TempBuffer_1]

	stdcall CalcSum

	ret

endp

; -------------------------------------------------------------------------------------

proc AddDWordToBuffer uses edi ecx

  ; Add a dword to a 400 byte value

  ; dword is in EAX

  ; address of dest number is in EDX

	mov edi,edx

	mov cx,0

	; add the dword to the dest

	add dword [edi],eax

	; exit if no carry

	jnc .DONE

  .ADD_C:

	; add in the carry bit

	add edi,4

	add dword [edi],1

	; exit if no carry

	jnc .DONE

	add cx,4

	cmp cx,400

	jl .ADD_C

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc CalcSum uses esi edi ecx

  ; Add two 400 byte values

  ; address of src number is in EAX
  ; address of dest number is in EDX

	mov esi,eax
	mov edi,edx

	mov cx,0

	; save CF from iteration to iteration

	; init CF = 0

	clc

	; push flags register to the stack

	pushf

  .SUM:

	mov eax,dword [esi]

	; get the flags register from the stack

	popf

	; [EDI] = [EDI] + [ESI] + CF

	adc dword [edi],eax

	; save the flags register to the stack, for the next iteration

	pushf

	; these affect the CF, which is why it has to be saved to the stack

	add esi,4
	add edi,4

	add cx,4

	; cmp also affects the CF

	cmp cx,400

	jl .SUM

	; clean up the stack

	popf

	ret

endp

; -------------------------------------------------------------------------------------

proc CalcDiff uses esi edi ecx

  ; Calc the difference between two 400 byte numbers

  ; dest = dest - src

  ; address of src number is in eax
  ; address of dest number is in edx

	mov esi,eax
	mov edi,edx

	mov cx,0

	; compute diff as: dest = dest + ~src + 1

	; the 1 is introduced by initialising CF to 1

	; save CF from iteration to iteration

	; init CF = 1

	stc

	; push flags register to the stack

	pushf

  .SUB:

	mov eax,dword [esi]

	; ~src here:

	not eax

	; get the flags register from the stack

	popf

	; [EDI] = [EDI] + ~[ESI] + CF

	adc dword [edi],eax

	; save the flags register to the stack, for the next iteration

	pushf

	; these affect the CF, which is why it has to be saved to the stack

	add esi,4
	add edi,4

	add cx,4

	; cmp also affects the CF

	cmp cx,400

	jl .SUB

	; clean up the stack

	popf

	ret

endp

; -------------------------------------------------------------------------------------

proc ShiftLeft uses edi ecx

  ; Shift dest number left by 1 bit

  ; address of dest number is in eax

	mov edi,eax

	; start from the high order double word in the dest

	add edi,396

	mov cx,396

  .SHIFT:

	mov eax,dword [edi-4]

	shld dword [edi],eax,1

	sub edi,4

	sub cx,4

	cmp cx,0

	jg .SHIFT

	shl dword [edi],1

	ret

endp

; -------------------------------------------------------------------------------------

proc CopyBuffer uses esi edi ecx

  ; copy data from one 400 byte buffer to another

  ; address of source passed in EAX

  ; address of destination passed in EDX

	mov esi,eax
	mov edi,edx

	mov cx,400

  .COPY:

	mov eax,[esi]
	mov [edi],eax

	inc esi
	inc edi

	dec cx

	jcxz .DONE

	jmp .COPY

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc IsZero uses esi ecx

  ; test a 400 byte value

  ; address passed in EAX

	mov esi,eax

	mov cx,400

	; the result is returned in AL

	xor al,al

  .CHECK_IF_0:

	cmp dword [esi],0

	; just quit if found to be non zero

	jne .QUIT

	sub cx,4

	; if cx reaches zero, the hex value is zero

	cmp cx,0

	jle .IS_ZERO

	add esi,4

	jmp .CHECK_IF_0

	; AL = true if the value is zero

  .IS_ZERO:

	mov al,1

  .QUIT:

	ret

endp

; -------------------------------------------------------------------------------------

proc Compare uses esi edi ecx

  ; compare two 400 byte unsigned integers A and B

  ; address of A passed in EAX
  ; address of B passed in EDX

  ; result is returned in AL

  ; if(A less than B) AL = 1
  ; if(A equals B) AL = 2
  ; if(A greater than B) AL = 4

	mov edi,eax
	mov esi,edx

	; start from the high order bytes

	add esi,396
	add edi,396

	mov cx,0

	xor eax,eax

  .COMPARE:

	mov edx,dword [edi]
	cmp edx,dword [esi]

	ja .GREATER_THAN

	jb .LESS_THAN

	add cx,4

	cmp cx,400

	jge .EQUAL

	sub esi,4
	sub edi,4

	jmp .COMPARE

  .LESS_THAN:

	mov al,1

	jmp .QUIT

  .EQUAL:

	mov al,2

	jmp .QUIT

  .GREATER_THAN:

	mov al,4

  .QUIT:

	ret

endp

; -------------------------------------------------------------------------------------

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
	  user,'USER32.DLL'

  import kernel,\
	 GetModuleHandle,'GetModuleHandleA',\
	 ExitProcess,'ExitProcess'

  import user,\
	 DialogBoxParam,'DialogBoxParamA',\ 
	 SetDlgItemText,'SetDlgItemTextA',\
	 GetDlgItemText,'GetDlgItemTextA',\
	 EndDialog,'EndDialog'

; -------------------------------------------------------------------------------------

section '.data' readable writeable

  InputBuffer rb 400

  Ten_N_Buffer rb 400

  TempBuffer_1 rd 400

  TempBuffer_2 rd 400

  bfDisplay rb 4000

  nInputChars dw 0

  Digit db 0

  Power_N dw 0

  szInputInfoText db "Enter the input as a BIN, HEX or OCT number. Max number size = 400 bytes.",0
  szOutputInfoText db "",0

; -------------------------------------------------------------------------------------

section '.rc' resource data readable

  directory RT_DIALOG,dialogs

  resource dialogs,IDD_THE_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_dialog

  dialog the_dialog,\
  'Binary To Decimal',50,50,400,400,\
  DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\
  0,0,"Lucida Console",11

  dialogitem 'BUTTON','Input',-1,7,5,386,120,BS_GROUPBOX+WS_VISIBLE,0
  dialogitem 'BUTTON',"Hex",-1,7,130,386,120,BS_GROUPBOX+WS_VISIBLE,0
  dialogitem 'BUTTON',"Decimal",-1,7,255,386,120,BS_GROUPBOX+WS_VISIBLE,0

  dialogitem 'EDIT',0,IDC_INPUT,13,17,375,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_HEX,13,142,375,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_OUTPUT,13,265,375,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'BUTTON',"Binary To Decimal",IDC_BTN_BIN_TO_DEC,7,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Hex To Decimal",IDC_BTN_HEX_TO_DEC,89,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Octal To Decimal",IDC_BTN_OCT_TO_DEC,171,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Decimal To Decimal",IDC_BTN_DEC_TO_DEC,253,380,80,14,BS_PUSHBUTTON+WS_VISIBLE,0

  dialogitem 'BUTTON',"Clear",IDC_BTN_CLEAR,335,380,40,14,BS_PUSHBUTTON+WS_VISIBLE,0

  enddialog

; -------------------------------------------------------------------------------------
Advertisements

Create a free website or blog at WordPress.com.

%d bloggers like this: