News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Simplest adder.

Started by felipe, June 15, 2017, 07:54:11 AM

Previous topic - Next topic

felipe

Well i want to post this code here because i want to share it and here you can do with it whatever you want to  :biggrin:.
You can try the program using wrong inputs or whatever and see the results, also try good inputs.
The explanation for the code: Well, it wasn't made with the idea of been optimed code, but that can change. To control the input buffer the only method that worked for me was using AllocateConsole and FreeConsole many times as necessary. This because the buffer input has a strange behavior when some wrong inputs were inserted.
The last part has a minor check for wrong inputs, but that can be different too. Enjoy, comment, critizice, or do whatever you want with this code.  :icon_mrgreen:


.386
.model  flat,stdcall
option  casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

.data?
hconsoleinput   dd  ?
hconsoleoutput  dd  ?
charswritten    dd  ?
charsread       dd  ?
charsattset     dd  ?


.data
binarysum   dd  0
programname db  "THE SIMPLEST ADDER",0
welcome     db  "Sum of natural numbers!",0
inpbuff     db  256 dup(" ")
promptnum   db  "Enter a natural number: ",0
bye?        db  "Exit program?(Y/N): ",0
inerror     db  "Error! just numbers allowed of 8 digits as maximum...",0
inerror2    db  "Error! you must put a number here of 1 digit as minimum...",0
errorform   db  "Error! just decimal digits allowed no others symbols...",0
result      db  9 dup(" "),0
showsum     db  "The sum is: ",0

cursorp proto   :word,:word
paintb  proto   :word,:word
asc2bin proto   
bin2asc proto
upper   proto

.code

main    proc

allagain:
        invoke  AllocConsole                                                        ; Creates a new console.
        invoke  GetStdHandle,STD_INPUT_HANDLE
        mov     hconsoleinput,eax
        invoke  GetStdHandle,STD_OUTPUT_HANDLE
        mov     hconsoleoutput,eax
        invoke  SetConsoleTitle,offset programname   
        invoke  cursorp,0,0                                                         ; Locates the cursor.
        invoke  paintb,0,0                                                          ; Clears the screen.
        invoke  SetConsoleTextAttribute,hconsoleoutput,\                            ; Set the text and background
                FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_INTENSITY or\     ;  colors for the console.
                BACKGROUND_GREEN     
        invoke  WriteConsole,hconsoleoutput,offset welcome,sizeof welcome,\         ; Welcome message in screen.
                offset charswritten,NULL   
        invoke  cursorp,0,2     
        invoke  WriteConsole,hconsoleoutput,offset promptnum,sizeof promptnum,\     ; Prompt for the first number.
                offset charswritten,NULL
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\
                offset charsread,NULL
        cmp     charsread,11                                                        ; More chars than allowed?:                           
        jb      not2big                                                             ;  -no, so continue.
        invoke  cursorp,0,0                                                         ;  -yes, so:
        invoke  paintb,0,0                                                          ;    *clears the screen.
        invoke  WriteConsole,hconsoleoutput,offset inerror,sizeof inerror,\         ;    *show error message.
                offset charswritten,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_LINE_INPUT
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\           ;    *Waits for the CR key.
                offset charsread,NULL     
        invoke  SetConsoleMode,hconsoleinput,ENABLE_ECHO_INPUT or\                  ; Allows inputs again (256 chars).
                ENABLE_LINE_INPUT
        invoke  FreeConsole                                                         ; Terminates current console.
        jmp     allagain                                                                         
           
not2big:   
        cmp     charsread,2                                                         ; Less chars than allowed?:
        ja      not2small                                                           ;  -If no input at all (just CR):       
        invoke  cursorp,0,0                                                         ;   *set cursor location (0,0)
        invoke  paintb,0,0                                                          ;   *clears the screen
        invoke  WriteConsole,hconsoleoutput,offset inerror2,sizeof inerror2,\       ;   *show error message
                offset charswritten,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_LINE_INPUT                      ;   *Waits for CR key.
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\
                offset charsread,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_ECHO_INPUT or\                  ; All keys accepted from now,
                ENABLE_LINE_INPUT                                                   ;   again (256 chars).
        invoke  FreeConsole                                                         ; Terminates current console.
        jmp     allagain
       
not2small:                                         
        mov     edi,offset inpbuff                                                  ; Address the input buffer.
        mov     ebx,charsread
        sub     ebx,2                                                               ; Discard the LF and CR.

chek:       
        cmp     byte ptr[edi],30h                                                   ; Is a number?
        jb      bad
        cmp     byte ptr[edi],39h                                                   
        ja      bad
        inc     edi
        dec     ebx       
        jnz     chek
        jmp     good                                                                ; Yes, it is.

bad:                                                                                ; No, is not.
        invoke  cursorp,0,0                                                         ;   *set cursor location (0,0)
        invoke  paintb,0,0                                                          ;   *clears the screen
        invoke  WriteConsole,hconsoleoutput,offset errorform,sizeof errorform,\     ;   *show error message
                offset charswritten,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_LINE_INPUT                      ;   *Waits for CR key.
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\
                offset charsread,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_ECHO_INPUT or\                  ; All keys accepted from now,
                ENABLE_LINE_INPUT                                                   ;   again (256 chars).
        invoke  FreeConsole                                                         ; Terminates current console.
        jmp     allagain


good:       
        ;mov     eax,charsread                                                       ; Correct number format from here.
        invoke  asc2bin                                                             ; Convert ascii code to binary
        invoke  cursorp,0,4     
        invoke  WriteConsole,hconsoleoutput,offset promptnum,sizeof promptnum,\     ; Prompt for the second number.
                offset charswritten,NULL
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\
                offset charsread,NULL
        cmp     charsread,11                                                        ; More chars than allowed?:                           
        jb      xnot2big                                                            ;  -no, so continue.
        invoke  cursorp,0,0                                                         ;  -yes, so:
        invoke  paintb,0,0                                                          ;    *clears the screen.
        invoke  WriteConsole,hconsoleoutput,offset inerror,sizeof inerror,\         ;    *show error message.
                offset charswritten,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_LINE_INPUT
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\           ;    *Waits for the CR key.
                offset charsread,NULL     
        invoke  SetConsoleMode,hconsoleinput,ENABLE_ECHO_INPUT or\                  ; Allows inputs again (256 chars).
                ENABLE_LINE_INPUT
        invoke  FreeConsole                                                         ; Terminates current console.
        mov     binarysum,0                                                         ; Clears the sum.
        jmp     allagain                                                                         
           
xnot2big:   
        cmp     charsread,2                                                         ; Less chars than allowed?:
        ja      xnot2small                                                          ;  -If no input at all (just CR):       
        invoke  cursorp,0,0                                                         ;   *set cursor location (0,0)
        invoke  paintb,0,0                                                          ;   *clears the screen
        invoke  WriteConsole,hconsoleoutput,offset inerror2,sizeof inerror2,\       ;   *show error message
                offset charswritten,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_LINE_INPUT                      ;   *Waits for CR key.
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\
                offset charsread,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_ECHO_INPUT or\                  ; All keys accepted from now,
                ENABLE_LINE_INPUT                                                   ;   again (256 chars).
        invoke  FreeConsole                                                         ; Terminates current console.
        mov     binarysum,0                                                         ; Clears the sum.
        jmp     allagain

xnot2small:
        mov     edi,offset inpbuff                                                  ; Address the input buffer.
        mov     ebx,charsread
        sub     ebx,2                                                               ; Discard the LF and CR.

xchek:       
        cmp     byte ptr[edi],30h                                                   ; Is a number?
        jb      bad
        cmp     byte ptr[edi],39h                                                   
        ja      xbad
        inc     edi
        dec     ebx       
        jnz     xchek
        jmp     xgood                                                               ; Yes, it is.

xbad:                                                                               ; No, is not.
        invoke  cursorp,0,0                                                         ;   *set cursor location (0,0)
        invoke  paintb,0,0                                                          ;   *clears the screen
        invoke  WriteConsole,hconsoleoutput,offset errorform,sizeof errorform,\     ;   *show error message
                offset charswritten,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_LINE_INPUT                      ;   *Waits for CR key.
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\
                offset charsread,NULL
        invoke  SetConsoleMode,hconsoleinput,ENABLE_ECHO_INPUT or\                  ; All keys accepted from now,
                ENABLE_LINE_INPUT                                                   ;   again (256 chars).
        invoke  FreeConsole                                                         ; Terminates current console.
        mov     binarysum,0                                                         ; Clears the sum.
        jmp     allagain


xgood:       
        ;mov     eax,charsread                                                       ; Number 2 correct from here.
        invoke  asc2bin                                                             ; Convert ascii code to binary.           
        invoke  bin2asc                                                             ; Convert binary sum to ascii.
        invoke  cursorp,0,6
        invoke  WriteConsole,hconsoleoutput,offset showsum,sizeof showsum,\         ; Show the result of the sum.
                offset charswritten,NULL
        invoke  WriteConsole,hconsoleoutput,offset result,sizeof result,\
                offset charswritten,NULL

decide:
        invoke  cursorp,0,8
        invoke  WriteConsole,hconsoleoutput,offset bye?,sizeof bye?,\               ; Exit program?
                offset charswritten,NULL
        invoke  ReadConsole,hconsoleinput,offset inpbuff,sizeof inpbuff,\
                offset charsread,NULL
        invoke  upper                                                               ; Convert the answer to uppercase.
        cmp     al,'N'
        jne     wasyes?
        invoke  FreeConsole                                                         ; No? so all again.
        mov     binarysum,0                                                         ;   But we clean this
        mov     edi,offset result                                                   ;     and this.
        mov     ebx,9
        mov     al,20h                                                             
       
cleaning:
        stosb
        dec     ebx
        jnz     cleaning
        invoke  FreeConsole
        jmp     allagain

wasyes?:
        cmp     al,'Y'
        je      byebye
        jmp     decide                                                              ; Wrong answer. Do it again.

byebye:
        invoke  FreeConsole
        invoke  ExitProcess,0
main    endp

paintb  proc    colx:word,rowy:word                                                 ; Fill into green all the screen,
        local   cc:COORD                                                            ;   (background and foreground).
        mov     ax,colx
        mov     cc.x,ax
        mov     ax,rowy
        mov     cc.y,ax
        mov     eax,cc       
        invoke  FillConsoleOutputAttribute,hconsoleoutput,BACKGROUND_GREEN or\
                FOREGROUND_GREEN,30000,eax,offset charsread
        ret
paintb  endp

cursorp proc    col:word,row:word                                                   ; Sets the cursor location.
        local   cc:COORD
        mov     ax,col
        mov     cc.x,ax
        mov     ax,row
        mov     cc.y,ax
        mov     eax,cc
        invoke  SetConsoleCursorPosition,hconsoleoutput,eax
        ret
cursorp endp         
       
asc2bin proc
        mov     esi,10                                                              ; Sets the powers
        mov     ecx,1                                                               ;  of 10.
        mov     ebx,charsread                                                       ; Convert 'ascii code' times.
        sub     ebx,2                                                               ; Discard the LF and the CR keys.
        mov     edi,offset inpbuff                                                  ; Address first ascii
        dec     ebx                                                                 ;   from right
        add     edi,ebx                                                             ;     to left.
        inc     ebx                                                                 ; Set the counter properly again.
       
nextasc:
        mov     al,[edi]                                                            ; The rightmost ascii.
        and     eax,000fh                                                           ; Convert to unpacked BCD.
        mul     ecx                                                                 ; Multiply by power of 10.
        add     binarysum,eax                                                       ; Accumulate the binary sum here.   
        mov     eax,ecx                                                             
        mul     esi                                                                 ; Next power of 10.
        mov     ecx,eax
        dec     edi                                                                 ; Next ascii.
        dec     ebx
        jnz     nextasc
        ;mov     eax,binarysum
        ret
asc2bin endp
       
bin2asc proc
        mov     edi,offset result                                                   ; Address for the result
        add     edi,8                                                               ;   from right to left.
        mov     eax,binarysum
        mov     ecx,10
@@:
        cmp     eax,ecx                                                             ; We finish if the dividend
        jb      done                                                                ;  is below the divisor.
        xor     edx,edx
        div     ecx
        or      dl,30h                                                              ; Ascii to unpacked BCD.
        mov     byte ptr[edi],dl                                                    ; Less significant digit of result.
        dec     edi
        jmp     @b                                                                 

done:
        or      eax,30h                                                             ; This is the most significant.
        mov     byte ptr[edi],al
        ret
bin2asc endp

upper   proc                                                                        ; Converts the ascii to uppercase.
        mov     esi,offset inpbuff
        mov     al,[esi]
        and     al,11011111b
        ret
upper   endp
               
        end     main
   

hutch--

felipe,

Something worth timing is the difference between this code,

        cmp     byte ptr[edi],30h                                                   ; Is a number?
        jb      bad
        cmp     byte ptr[edi],39h                                                   
        ja      bad

and code something like this.

    movzx eax, BYTE PTR [edi]    ; an extra line of code
    cmp eax, 30h                      ; do the comparisons in native data size where possible
    jb bad
    cmp eax, 39h
    ja bad


For the extra instruction, you reduce the memory access count from 2 to 1 and sometimes this will give you a speed gain as memory is a lot slower than accessing a register.



felipe

I got it. Thanks a lot Hutch.  :icon14: