Page 2 of 3

Re: Falco's MSP430 Assembly Programs

Posted: Thu Sep 17, 2009 7:13 am
by Netwatcher
Been wanting to learn asm for some time now,today seems like a good day to start 8-)
Thanks Falco!

Re: Falco's MSP430 Assembly Programs

Posted: Thu Sep 17, 2009 10:38 am
by RyanPridgeon
I was just wondering, what would you suggest is the best way to start learning assembly? I mean, any useful tools / good compilers / useful resource sites? I've always been interested but never really knew where to begin.

Re: Falco's MSP430 Assembly Programs

Posted: Thu Sep 17, 2009 12:50 pm
by avansc
RyanPridgeon wrote:I was just wondering, what would you suggest is the best way to start learning assembly? I mean, any useful tools / good compilers / useful resource sites? I've always been interested but never really knew where to begin.
mmm... id say the best way is to actually learn it in school. college what ever. its a hard topic to do on your own..
what you can do is to delve through college asm courses and get all the notes you can. also. get a good book, something like "assembly language for intel-based computers" but kip irvine. its probably the best book on the topic.

Re: Falco's MSP430 Assembly Programs

Posted: Thu Sep 17, 2009 11:14 pm
by short
avansc wrote:
RyanPridgeon wrote:I was just wondering, what would you suggest is the best way to start learning assembly? I mean, any useful tools / good compilers / useful resource sites? I've always been interested but never really knew where to begin.
mmm... id say the best way is to actually learn it in school. college what ever. its a hard topic to do on your own..
what you can do is to delve through college asm courses and get all the notes you can. also. get a good book, something like "assembly language for intel-based computers" but kip irvine. its probably the best book on the topic.
That's the book i learned in my cs course.

In the class I learned in, we used gnu compiler with cygwin if you used windows. Also OllyDbg was what they suggested you used as a debugger.

Personally, I preferred visual studio 2008 c++ for my compiling. I especially liked it when we did inline assembly. It took a lot of configuring, but that can all be found online. Honestly though, OllyDbg is really powerful, and I wish I had taken the time to learn it better. I know there is a lot of uses for reverse engineering I've read, if that's your kind of thing. Eventually I plan to head that way, it is extremely fascinating to me.

/back on topic.

Re: Falco's MSP430 Assembly Programs

Posted: Fri Sep 18, 2009 9:28 am
by avansc
i assume it was a course on asm?
but yeah. odbg is great. if there is any goal a asm course should have is to teach you
how to use a debugger.

i prefer the borland assmebler.
tasm. with its respective debugger.

Re: Falco's MSP430 Assembly Programs

Posted: Fri Sep 18, 2009 11:50 am
by short
avansc wrote:i assume it was a course on asm?
but yeah. odbg is great. if there is any goal a asm course should have is to teach you
how to use a debugger.

i prefer the borland assmebler.
tasm. with its respective debugger.
It was half the course's objective. In my opinion I believe the instructor did a poor job showing us how to use the debugger.

Would you say a debugger such as ollydbg is different then a normal compiler?

It seems like OllyDBG was a lot more low level then my C debugger.

If I remember correctly, you could feed it an executable and debug the actual debugger. Much different then say mvsc++ debugger.

Re: Falco's MSP430 Assembly Programs

Posted: Mon Sep 21, 2009 12:48 pm
by captjack
Ah, assembly!

I have memories of my kernel days. Nothing like writing code for a computer and not having the benefit of a standard library. The power of rolling one's own printf, farting around with scan codes for the keyboard driver, getting the global descriptor table set up correctly and unwinding all the triple faults! :twisted:

I said, "fuck it" and went to game programming instead.

-capt jack

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Thu Sep 24, 2009 3:34 pm
by Falco Girgis
So Kendall's homework assignment was to create a simple number guessing game in x86 assembly. It requires a random number between 1 and 100 to be generated, and must tell the user whether his guess is too high or too low. It also must keep track of and print the number of guesses.

Not only that, but it had to check whether the damn things were valid input or not.

I just got done helping with it (she got it started), and here's the source:
(She does the algorithms homework, I do the assembly. ;) )

Code: Select all

          ;----------------------------------------------------;
          ;    Student    --   Kendall Hyatt                   ;
          ;    ID Number  --   A25009697                       ;
          ;    Email      --   Kendall.S.Hyatt@gmail.com       ;
          ;    Course     --   CS 308 (Assembly Language)      ;
          ;    Instructor --   Joe Toone                       ;
          ;    Assignment --   Program 1                       ;
          ;    Problem    --   Random Number Game              ;
          ;    Due Date   --   09/30/2009                      ;
          ;----------------------------------------------------;

TITLE PROG1.ASM                              ;DOS file name of program

LF equ 0ah                              ;ASCII 10d - newline character
CR equ 0dh                              ;ASCII 13d - carriage return character
DOUBLESPC equ CR,LF,LF                  ;ASCII 13,10,10 - for double space line

.MODEL  SMALL                           ;Memory model is Small
.286                                    ;Allow for pusha and popa instrucitons
.STACK  100h                            ;100 hex bytes for stack
.DATA                                   ;Data segment begins here
   RandNum    DB DOUBLESPC,'Your random number is: $'
   Gener      DB DOUBLESPC, 'Your number has been generated. $'
   Prompt     DB DOUBLESPC, 'Enter a guess (1-100): $'
   InvalidStr DB DOUBLESPC,'Invalid input, try again! $'
   Hundredth  DB ?
   CheckAgain DB DOUBLESPC,'Would you like to play (Y/N)?$'
   CharTyped  DB ?
   Guess      DW 0h   ; Allocates a place in memory for our current guess
   TotalGuess DB 0h   ; Contains total number of guesses
   TooHigh    DB DOUBLESPC,'Your guess was TOO HIGH! Try again: $'
   TooLow     DB DOUBLESPC,'Your guess was TOO LOW! Try again: $'
   Winner     DB DOUBLESPC,'YEAH! That is it! It only took you $'
   Tries      DB ' tries. $'
   Error      DB DOUBLESPC,'You must enter an integer between 1 and 100. Try again: $'
   Spaces     DB DOUBLESPC,'$'

;***************************************************************************
;************************* Main Body of Program ****************************
;***************************************************************************

;********************************** MAIN ***********************************
;    Requires      --   Nothing
;    Process       --   Main Body - calls procedures to do the processing
;    Returns       --   Nothing
;***************************************************************************

.CODE                                         ;executable section begins here
_main:  mov   ax,@data                        ;starting address of data segment
        mov   ds, ax                          ;set DS to point to the data segment
DoOver: mov   TotalGuess, 0h
        lea   dx,CheckAgain                   ;Point to the question prompt
        call  PrintString                     ;go print the string
        call  GetChar                         ;Get a character from the keyboard
        mov   CharTyped,al                    ;save the character that was typed
        cmp   CharTyped,'y'                   ;Was lowercase y for get time?
        je    CTime                           ;yes, jump to get time
        cmp   CharTyped,'Y'                   ;Was uppercase Y for get time?
        je    CTime                           ;yes, jump to get time
        cmp   CharTyped, 'n'                  ;was lowercase y for get time?
        je    AllDone                         ;nope, end program
        cmp   CharTyped, 'N'                  ;was uppercase Y for get time?
        je    AllDone                         ;yep, end program
        jmp   TryAgain                        ;Not an option? Invalid input
CTime:  call  clock                           ;Go check the system clock
        mov   Hundredth,dl                    ;and save hundredths
;       lea dx,RandNum
;       call PrintString
;       mov al,Hundredth                      UNCOMMENT ME TO CHEAT!!!!
;       mov ah,0h
;       call ShowNum
;       jmp DoOver
        lea dx, Gener                         ;Copy location of "number generated" string
        call PrintString                      ;Display string
GameSet:lea dx,Prompt                         ;point to game prompt string
        call PrintString                      ;go print the string
        call Ascii2Int                        ;get guess from user
        cmp ax, 0d                            ;Check if the guess is 0
        je Invalid                            ;It is, invalid input
        mov Guess,ax                          ;Copy the location of the guess to ax
        lea dx,Spaces                         ;Copy the location of Spaces to dx
        call PrintString                      ;Print spaces
        call Int2Ascii                        ;Convert our integer guess to ascii and print
        call JdgGuess                         ;Judge our guess
        ; Check status of guess
        cmp dx, 1                             ;If the flag is true, we got it right
        je DoOver                             ;Start the game over
        jmp GameSet                           ;Otherwise it was wrong, start another guess
AllDone:mov  ax,4c00h                         ;DOS terminate program function #
        int  21h                              ;terminate the program

Invalid:lea dx, InvalidStr                    ;Copies invalid string address to dx
        call PrintString                      ;Prints error
        jmp GameSet                           ;Jumps back to guessing
TryAgain: lea dx, InvalidStr                  ;Copies invalid string address to dx
        call PrintString                      ;Prints error
        jmp DoOver                            ;Jumps back to "Play again?"

;***************************************************************************
;************************ SubRoutines/Procedures ***************************
;***************************************************************************

;******************************* JdgGuess ***********************************
;    Requires      --   User guess in register AX
;    Process       --   Judges whether the guess was too high, too low, correct, and sets flags
;    Returns       --   Status flag in DX (1 is correct, 0 is wrong)
;***************************************************************************
JdgGuess  PROC
        inc TotalGuess
        mov bl, Hundredth
        mov bh, 0h
        cmp ax, bx
        jg Greater
        jl Less
        je Equal
Equal:  lea dx, Winner
        call PrintString
        mov al, TotalGuess
        mov ah, 0h
        call Int2Ascii
        lea dx, Tries
        call PrintString
        mov dx, 1
        ret
Greater:lea dx, TooHigh
        call PrintString
        mov dx, 0
        ret
Less:   lea dx, TooLow
        call PrintString
        mov dx, 0
        ret
JdgGuess  ENDP

;******************************* GetChar ***********************************
;    Requires      --   Nothing
;    Process       --   Input a character using DOS function #1 and interrupt 21h
;    Returns       --   The input character in AL register
;***************************************************************************

GetChar PROC                            ;Define procedure
        push bx                         ;Protect some registers
        push cx                         ;
        push dx                         ;
        mov ah,01h                      ;DOS get character function #1
        int 21h                         ;Get the character
        pop dx                          ;Restore some resgisters
        pop cx                          ;
        pop bx                          ;
        ret                             ;Return to calling procedure
GetChar ENDP                            ;End of procedure

;******************************* PutChar ***********************************
;    Requires      --   The character to be printed must be in the DL register
;    Process       --   Print a character by using DOS function #2 and interrupt 21h
;    Returns       --   Nothing
;***************************************************************************

PutChar PROC                            ;Define procedure
        pusha                           ;Protect all registers
        mov ah,02h                      ;DOS print character function #2
        int 21h                         ;Get the character
        popa                            ;Restore all registers
        ret                             ;Return to calling procedure
PutChar ENDP                            ;End of procedure

;***************************** PrintString *********************************
;    Requires      --   The address of $-terminated string to print in the DX register
;    Process       --   Print the string using DOS function #9 and interrupt 21h
;    Returns       --   Nothing
;***************************************************************************

PrintString PROC                        ;Define procedure
        pusha                           ;Protect all registers
        mov  ah,9h                      ;DOS print string function #9
        int  21h                        ;display the string
        popa                            ;Restore all registers
        ret                             ;Return to calling procedure
PrintString ENDP                        ;End of procedure

;***************************** PrintString *********************************
;    Requires      --   The address of $-terminated string to print in the DX register
;    Process       --   Print the string using DOS function #9 and interrupt 21h
;    Returns       --   Nothing
;***************************************************************************

Random  PROC                                  ;define procedure
        mov bx,251d			                      ;just goof up the number
	      mul bx
	      add ax,138d			                      ;add stuff to it
	      mov ah,0d			                        ;zero the high byte
	      and al,0fh			                      ;mask the low nibble
	      ret				                            ;return to caller
Random  ENDP				                          ;end of procedure

;********************* Procedure to Read System Clock *************************
; Given   :  Nothing
; Process :  Read the system time of day clock for hour, minute, second, and
;         :  1/100 of a second
; Notes   :  Using this procedure (as written) will destroy the contents of
;         :  AH, CX, and DX registers
; Return  :  Return CH=hour CL=minute DH=second DL=100th of a second
; Author  : Joe Toone
;******************************************************************************

Clock PROC
        mov ah,2ch                      ;DOS function #2C reads time of day
        int 21h                         ;CH=hour CL=minute DH=second DL=100th sec
        ret                             ;Return to calling procedure
Clock ENDP

;********************** Procedure to Print the Number *************************
; Given   :  The integer to be printed in the AX register
; Process :  Convert the integer to a string of ASCII digits and print them
;              one at the time, until all are printed
; Return  :  Nothing
;******************************************************************************

ShowNum PROC
        pusha                           ;Save the contents of all registers
        mov cx,0h                       ;Zero the CX register for digit counter
        mov bx,10d                      ;Set up divisor of 10 decimal
NextOut:mov dx,0h                       ;Zero DX reg for high order word of div
        div bx                          ;Divide number in AX by 10
        push dx                         ;Save remainder on the stack
        inc cx                          ;Count the digit
        cmp ax,0h                       ;Is number in AX greater than 0
        jg NextOut                      ;Yes, get next digit
CharOut:pop ax                          ;Get number from the stack
        add ax,30h                      ;Convert number to ASCII character
        mov dl,al                       ;Move to character print register
        call PutChar                    ;Print the character
        dec cx                          ;Reduce characters to print by one
        jnz CharOut                     ;If CX > 0 loop to print next digit
        popa                            ;Restore the registers
        ret                             ;Return to Calling procedure
ShowNum ENDP                            ;end of procedure

;********************** Procedure to Input the Number *************************
; Requires : Nothing
; Process  : Accept a string of ASCII digits and convert them to an integer
; Returns  : Return the integer in AX register
;******************************************************************************
Ascii2Int PROC
          push bx                       ;Save the contents of all registers
        push cx                         ;  except for AX, which will contain the
        push dx                         ;  number which was read
        mov bx,0h                       ;Zero the BX register
NextDigit: mov ah,1h                    ;DOS input character function #1 hex
        int 21h                         ;Get a character
        cmp al,'0'                      ;If the character is less than 0, then
        jl Done                         ;  we have all the number and are Done
        cmp al,'9'                      ;If the character is more than 9, then
        jg Done                         ;  we have all the number and are Done
        sub al,30h                      ;Convert ASCII to integer value
        xor ah,ah                       ;Zero the high byte of AX
        push ax                         ;Save the digit on the stack
        mov ax,10d                      ;Place 10 decimal in AX to multiply by
        mul bx                          ;Multiply the number by 10
        mov bx,ax                       ;Get number from AX and put in BX
        pop ax                          ;Get the digit back from the stack
        add bx,ax                       ;Add the digit to the number
        jmp NextDigit                   ;Get the next digit
Done:   mov ax,bx                       ;Return the NUMBER in AX register
        pop dx                          ;Restore the registers in reverse order
        pop cx                          ;
        pop bx                          ;
        ret                             ;Return to Calling procedure
Ascii2Int ENDP

;********************** Procedure to Print the Number *************************
; Requires : The integer to be printed in the AX register
; Process  : Convert the integer to a string of ASCII digits and print them
;              one at the time, until all are printed
; Returns  : Nothing
;******************************************************************************
Int2Ascii PROC
        pusha                           ;Save the contents of all registers
        mov cx,0h                       ;Zero the CX register for digit counter
        mov bx,10d                      ;Set up divisor of 10 decimal
NextOut2:mov dx,0h                       ;Zero DX reg for high order word of div
        div bx                          ;Divide number in AX by 10
        push dx                         ;Save remainder on the stack
        inc cx                          ;Count the digit
        cmp ax,0h                       ;Is number in AX greater than 0
        jg NextOut2                      ;Yes, get next digit
CharOut2:pop ax                          ;Get number from the stack
        add ax,30h                      ;Convert number to ASCII character
        mov dl,al                       ;Move to character print register
        call PutChar                    ;Print the character
        dec cx                          ;Reduce characters to print by one
        jnz CharOut2                     ;If CX > 0 loop to print next digit
        popa                            ;Restore the registers
        ret                             ;Return to Calling procedure
Int2Ascii ENDP

END _main                                     ;code segment ends here
I find x86 quite a bit easier than MSP430. There's addressing modes for everything. I don't even have to worry about moving things from RAM into registers if I don't have to. There's also opcodes to handle all sorts of things (that MSP430 makes you do manually).

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Thu Sep 24, 2009 4:57 pm
by avansc
JdgGuess PROC
inc TotalGuess
mov bl, Hundredth
mov bh, 0h
cmp ax, bx
jg Greater
jl Less
je Equal -- this is redundant
Equal: lea dx, Winner


also, look at xlat. it translates chars depending on how you want. that way you dont have to check 4 times fir yYnN but just twice, which will resuly in only one jump and not 4.

you could also make a casetable

something like
(from my old notes, and probably from my asm book)

NE = 4
CaseTable db 'y' ; lookup
dw proc1 ; address of proc
db 'Y' ; lookup
dw proc1 ; address of proc
db 'n' ; lookup
dw proc2 ; address of proc
db 'N' ; lookup
dw proc2 ; address of proc
.code
mov al,input
mov bx, offset CaseTable
moc cx, NE

L1: cmp al, [bx]
jne L2
call word ptr [bx+1]
jmp L3
L2: add bx,3
loop L1
L3:

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Thu Oct 01, 2009 2:32 pm
by Falco Girgis
Alrighty, I'm back to the MSP430 processor. The processor was built without CPU multiplication to keep down costs and keep up clock frequency. Instead, many MSP430 models come with additional multiplication units that receive multiplicands and multipliers in special registers, and perform the computation (independent of the CPU).

Our instructor wanted us to implement software multiplication of two signed 8-bit numbers (shift and add), he also wanted us to do it with the hardware multiplier. Then the final assignment was to use the hardware multiplier's "multiply and accumulate" to take the dot product of vectors. It was a two week assignment, and I just got off my lazy ass and did it this morning (due in less than an hour).

Here we have software multiplication:

Code: Select all

/* Falco Girgis
 * CPE323 Lab Section 2
 * Lab Assignment #3
 *
 * Software Multiplication Routine
 * R13 - 8-bit Signed Multiplicand
 * R14 - 8-bit Signed Multiplier
 * R15 - 16-bit Signed Result
 *
 * R10 - Used as a flag for negative result
 * R11 - Used as a counter (both are restored) 
 */

#include "msp430.h"
  
                PUBLIC   soft_mult              ; Routine available from elsewhere
                RSEG     CODE
      
soft_mult:      PUSH     R10                    ; Preserve these registers
                PUSH     R11
                CLR      R10                    ; Clear registers for use
                CLR      R11
                CLR      R15
 mplcndChk:     BIT.B    #10000000b, R13        ; Check to see if multiplicand is negative
                JNC      mplierChk              ; If not, jump to check multiplier
                INV.B    R13                    
                INC.B    R13                    ; Take twos compliment
                INC      R10                    ; Update negative answer flag
 mplierChk:     BIT.B    #10000000b, R14        ; Check if multiplier is negative
                JNC      mult                   ; If not, proceed with unsigned multiplication
                INV.B    R14              
                INC.B    R14                    ; Take twos compliment
                INC      R10                    ; Update negative answer flag
mult:           BIT.B    #00000001b, R14        ; Check first digit of multiplier
                JC       copy                   ; Copy multiplicand to result if so
                JMP      rotate                 ; Jump to rotate loop if not
copy:           MOV      R13, R15      
rotate:         INC      R11                    ; Increment counter
                CMP      #5, R11                ; Check if we're done looping to last bit
                JEQ      signChk                ; If we are, jump to check if result is signed
                RLA      R13                    ; Rotate multiplicand left
                RRA      R14                    ; Rotate multiplier right
                BIT.B    #00000001b, R14        ; Check if first bit of multiplier is 1
                JNC      rotate                 ; If not, proceed with next iteration
                ADD      R13, R15               ; If so, add current multiplicand to running total
signChk:        CMP      #1d, R10               ; If our flag is 1, the result should be signed
                JEQ      signAns                
                JMP      endMult
signAns:        INV      R15                    ; Twos compliments result
                INC      R15
endMult:        POP      R11
                POP      R10
                RET     
                END
Here we have hardware multiplication:

Code: Select all

/* Falco Girgis
 * CPE323 Lab Section 2
 * Lab Assignment #3
 *
 * Hardware Multiplication Routine
 * R13 - 8-bit Signed Multiplicand
 * R14 - 8-bit Signed Multiplier
 * R15 - 16-bit Signed Result 
 */

#include "msp430.h"
  
                PUBLIC   hard_mult              ; Routine available from elsewhere
                RSEG     CODE
                
hard_mult:      MOV      R13, &MPYS             ; Move first operand to signed mult register
                SXT      &MPYS                  ; Sign extend
                MOV      R14, &OP2              ; Moves second operand to OP2 register
                SXT      &OP2                   ; Sign extend
               
                MOV     RESLO, R15              ; Return result through register R15

                RET
                END
                
And we have the dot product (using the hardware multiplier):

Code: Select all

/* Falco Girgis
 * CPE323 Lab Section 2
 * Lab Assignment #3
 *
 * Dot Product with Hardware Multiplier (and Accumulate)
 * R12 - Address of 8-bit signed integer array
 * R13 - Address of 8-bit signed integer array
 * R14 - Length of the two arrays
 * R15 - Return product 
 */

#include "msp430.h"
  
                PUBLIC   hard_dot              ; Routine available from elsewhere
                RSEG     CODE
                
hard_dot:       
                PUSH R10                       ; Preserve contents of R10
                CLR R10                        ; Clear counter
                INC   R14                      ; We're looping to length+1, increment length
dot_loop:       INC R10                        ; Increment counter
                CMP R10, R14                   ; Check if we have looped to > length
                JEQ end_dot                    ; If so, end
                MOV @R12+, &MACS               ; Copy first entry of array to multiplier and increase address
                MOV @R13+, &OP2                ; Copy second entry of array to multiplier and increase address
                JMP dot_loop                   ; Repeat loop
end_dot:        MOV RESLO, R15                 ; Move result to return register
                POP R10                        ; Restore register R10
                RET
                END
...and for the lulz here's my sloppy ass main that I threw together to drive these examples:

Code: Select all

#include "msp430.h"            


        NAME    main                    ; module name
        PUBLIC  main                    ; make main accessible from outside module
        
        EXTERN  soft_mult
        EXTERN  hard_mult
        EXTERN  hard_dot
        
        ORG     0FFFEh
        DC16    init                    ; set reset vector to 'init' label

        RSEG    CSTACK                  ; pre-declaration of segment CSTACK
        RSEG    CODE                    ; place program in 'CODE' segment

init:   MOV     #SFE(CSTACK), SP        ; initialize stack

/*

//Software multiplication main

main:   NOP                             ; main entry point
        MOV.W   #WDTPW+WDTHOLD,&WDTCTL  ; stop watchdog timer
        
        MOV.B     arr1, R13             ; Moves arguments into parameter registers
        MOV.B     arr2, R14
        CALL      #soft_mult            ; Calls soft multiplication routine
        
        JMP $
  
arr1    DB        -3d
arr2    DB        -5d
*/

/*
// HARDWARE MULTIPLICATION MAIN


main:   NOP                             ; main entry point 
        MOV.W   #WDTPW+WDTHOLD,&WDTCTL  ; stop watchdog timer
        
        MOV.B   arr1, R13               ;Moves argument #1 into R13
        MOV.B   arr2, R14               ;Moves argument #2 into R14
        CALL    #hard_mult              ;Calls hardware multiplication routine
        
        JMP $
          
arr1    DB      3d
arr2    DB      -18d
 */
 
 
 //   DOT PRODUCT MAIN
/* 
main:   NOP                             ; main entry point
        MOV.W   #WDTPW+WDTHOLD,&WDTCTL  ; stop watchdog timer
        
        MOV     #arr1, R12      ;Move argument #1's memory address into R12
        MOV     #arr2, R13      ;Move argument #2's memory adress into R13
        MOV     #5, R14         ;Copy array/vector length into register R14
        CALL    #hard_dot       ;Call hardware dot product routine
        
        JMP $
  
arr1    DW      -4,-2,3,4,-5
arr2    DW      2,3,4,-5,6

        END
        */

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Thu Oct 01, 2009 3:37 pm
by K-Bal
Are you going to work with peripherals?

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Thu Oct 01, 2009 3:46 pm
by Falco Girgis
K-Bal wrote:Are you going to work with peripherals?
Yeah, only the first third to half of the class is learning the general microprocessor. Now we're going to be doing all sorts of I/O, sampling, and embedded system designing (I know we're doing something with ethernet also).

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Mon Oct 19, 2009 12:51 pm
by Falco Girgis
Last night I completed the biggest, bitchiest, most trivial, yet pain-in-my-ass assembly project that I have ever worked on. Kendall was assigned to write a number converter in 32-bit x86 assembly. Not only that, but it has to check for any invalid input, uppercase lowercase letters in hex input, and do a bunch of annoying as hell overflow checks.

It was a two week project that took a day. I hope Kendall's teacher dies:

Code: Select all

;*****************************************************************************
;    Student      --   Kendall Hyatt
;    ID Number    --   A25009697
;    Email        --   Kendall.S.Hyatt@gmail.com
;    Course       --   CS 308 (Assembly Language)
;    Instructor   --   Joe Toone
;    Assignment   --   Program 2
;    Problem      --   Binary-Decimal-Hex Converter
;    Due Date     --   10/19/2009
;*****************************************************************************

TITLE PROG2.asm                         ;DOS file name of program

LF equ 0ah                              ;ASCII 10 - newline character
CR equ 0dh                              ;ASCII 13 - carriage return character
MAXSTR equ 256d
MAXARRAY equ 70d
MAXBINARY equ 32d                       ;Accept up to 32 characters for binary
MAXHEX equ 8d                           ;Accept up to 8 characters for hex
MAXDECIMAL equ 10d                      ;Accept up to 10 characters for decimal
ENABLE_PROCESSED_INPUT equ 1            ;Flag to turn off line buffering
ENABLE_PROCESSED_OUTPUT equ 1           ;Flag to turn off line buffering
ENABLE_LINE_WRAP equ 3                  ;Flag to turn line wrap on
DISABLE_PROCESSED_INPUT equ 7           ;Flag to turn on line buffering
STD_INPUT  equ -10d                     ;Function number for keyboard input
STD_OUTPUT equ -11d                     ;Function number for monitor output

.586                                    ;Allow for Pentium instrucitons
.MODEL FLAT                             ;Memory model is FLAT (4GB)

INCLUDELIB kernel32.lib                 ;Include the kernel 32 library

SetConsoleMode PROTO NEAR32 stdcall,    ;Prototype for attaching to console
    hConsoleHandle:DWORD, dwMode:DWORD

GetStdHandle PROTO NEAR32 stdcall,      ;Prototype for obtaining a file handle
    nStdHandle:DWORD

ReadFile PROTO NEAR32 stdcall,          ;Prototype for reading a file
    hFile:DWORD, lpBuffer:NEAR32,
    nNumberOfCharsToRead:DWORD,
    lpNumberOfBytesRead:NEAR32,
    lpOverlapped:NEAR32

WriteFile PROTO NEAR32 stdcall,          ;Prototype for writing a file
    hFile:DWORD, lpBuffer:NEAR32,
    nNumberOfCharsToWrite:DWORD,
    lpNumberOfBytesWritten:NEAR32,
    lpOverlapped:NEAR32

ExitProcess PROTO NEAR32 stdcall,        ;Prototype for Exit of OS
    dwExitCode:DWORD

.STACK  4096h                            ;4k hex bytes for stack

.DATA                                   ;Data segment begins here
   Welcome    BYTE  'Welcome to the binary-decimal-hex converter ',LF,CR,
                    'program. You will enter a number that is either ',LF,CR,
                    'in binary, hexadecimal, or decimal form, and I ',LF,CR,
                    'will convert your number into the each of the ',LF,CR,
                    'other two forms and then print out all three.',LF,CR,0
   Hints      BYTE  'In order for me to perform, you must adhere to ',LF,CR,
                    'the following restrictions:',LF,CR,LF,CR,
                    'Binary numbers up to 32 bits',LF,CR,
                    'Decimal numbers no greater than 4,294,967,295',LF,CR,
                    'Hexadecimal values up to FFFFFFFF',LF,CR,LF,CR,
                    'Enjoy.',LF,CR,LF,CR,0
   Prompt     BYTE  LF,CR,'Play now (y/n)?',LF,CR,
                    '(X to quit)',LF,CR,
                    '>>> ',0
   NumSel     BYTE  LF,CR,'Enter the number corresponding to the base of your',
                    ' number to be converted.',
                    LF,CR, '1) Base 10', LF, CR, '2) Base 16', LF, CR,
                    '3) Base 2', LF, CR, '4) Quit', LF, CR, LF, CR, 0
   EnterDecNum BYTE LF, CR, LF, CR,
                    'Enter a decimal number. (less than 4294967295d)',
                    LF, CR, 0
   EnterHexNum BYTE LF, CR, LF, CR,
                    'Enter a hexadecimal number. (less than 0FFFFFFFFh)',
                    LF, CR, 0
   EnterBinNum BYTE LF, CR, LF, CR,
                    'Enter a binary number. (less than 33 digits)',
                    LF, CR, 0
   Invalid    BYTE  LF,CR,"Invalid input. Try again.",LF,CR,0
   Binary     BYTE  LF,CR,'Your number in binary is: ',0
   Decimal    BYTE  LF,CR,'Your number in decimal is: ',0
   Hex        BYTE  LF,CR,'Your number in hexadecimal is: ',0
   CharTyped  BYTE  ?
   OutArray   BYTE  MAXARRAY dup(?)

   BlankLine  BYTE  LF,CR,0
   String     DWORD MAXARRAY dup(?)
   String2    DWORD MAXARRAY dup(?)
   ArrayLen   DWORD  ?
   DigitCount DWORD  ?
   DecNum     DWORD ?
   BinNum     DWORD ?
   HexNum     DWORD ?
   Zero       BYTE '0'

   DoubleQuote BYTE 22h                  ;ASCII 34 - " character
   strAddr   DWORD  ?                    ;The rest of these are used when
   strLength DWORD  ?                    ;accessing the kernel32 function
   hStdOut   DWORD  ?                    ;calls.
   hStdIn    DWORD  ?
   read      DWORD  ?
   written   DWORD  ?

;************************** Main Body of Program *****************************
; Given  : Nothing
; Process: Main Body - calls procedures to do the processing
; Return : Nothing
;*****************************************************************************
.CODE                                   ;executable section begins here
_main:
        lea esi,Welcome                 ;load addr of Welcome string
        call PrintString                ;display welcome string
        lea esi,Hints                   ;load addr of hints
        call PrintString                ;display hints

EnterChoice:
        lea esi, NumSel                 ;load addr of number select prompt
        call PrintString                ;display prompt
        lea esi, CharTyped              ;load addr of input char
        call GetChar                    ;get character
        cmp CharTyped, '1'              ;check if entering decimal
        jz DecInput
        cmp CharTyped, '2'              ;check if entering hex
        jz HexInput
        cmp CharTyped, '3'              ;check if entering binary
        jz BinInput
        cmp CharTyped, '4'              ;check if quiting program
        jz EndProgram
        lea esi, Invalid                ;anything else is invalid
        call PrintString
        jmp EnterChoice                 ;reprompt user

;****************Near procedure for Decimal Numbers**************************
; Given   :  Nothing
; Process :  Retrieves Decimal number and converts to hex and binary
; Return  :  Nothing
;******************************************************************************
DecInput:                               ;handles decimal number input
        lea esi,EnterDecNum             ;load addr of prompt
        call PrintString                ;display prompt
        lea esi,String                  ;load addr of input string
        call GetString                  ;get string

        call ValidateDec                ;check if string is a valid decimal number

        lea esi, Decimal                ;load addr of prompt
        call PrintString                ;display prompt
        lea esi, String                 ;load addr of decimal string
        call PrintString                ;display decimal string

        lea esi, Hex                    ;load addr of prompt
        call PrintString                ;display prompt
        lea esi, String                 ;load addr of decimal string input
        lea edi, DecNum                 ;load addr for decimal integer output
        call Ascii2Int                  ;convert from ascii to int
        call DecToHex                   ;convert from base 10 to 16 and print

        lea esi, Binary                 ;load addr of prompt
        call PrintString                ;display prompt
        call DecToBin                   ;convert from base 10 to 2 and print

        lea esi, BlankLine              ;load addr of newline string
        call PrintString                ;display newline
        jmp EnterChoice                 ;jump back to main menu

;****************Near procedure for Hexadecimal Numbers**************************
; Given   :  Nothing
; Process :  Retrieves hex number and converts to binary and decimal
; Return  :  Nothing
;******************************************************************************
HexInput:                               ;handles hexadecimal number input
        lea esi,EnterHexNum             ;load addr of prompt
        call PrintString                ;display prompt
        lea esi,String                  ;get addr of input string
        call GetString                  ;get input string

        call ValidateHex                ;check to see if input is valid hex number

        lea ebx, String                 ;load address of input
        call AsciiStrToIntArray         ;convert input from an ascii string to int array
        call HexToDec                   ;convert from hex to decimal
        lea esi, Decimal                ;load addr of prompt
        call PrintString                ;display prompt
        lea esi, DecNum                 ;load addr of decimal number
        lea edi, String2                ;load addr of output string
        call Int2Ascii                  ;convert number to ascii
        lea esi, String2                ;load addr of output string
        call PrintString                ;print decimal string

        lea esi, Hex                    ;load addr of hex char array
        call PrintString                ;display array

        xor eax, eax                    ;clear eax
        lea ebx, String                 ;load addr of input
        mov al, BYTE PTR [ebx]          ;grab the highest digit
        cmp eax, 65d                    ;check if it's a letter
        jb printh                       ;if not, don't bother
        lea esi, Zero                   ;if so, print a 0 first
        call PutChar
printh: lea esi, String
        call PrintString                ;print hexadecimal number

        lea esi, Binary
        call PrintString                ;print prompt
        call DecToBin                   ;print binary number

        lea esi, BlankLine              ;print newline
        call PrintString
        jmp EnterChoice                 ;jump back to main menu

;****************Near procedure for Binary Numbers**************************
; Given   :  Nothing
; Process :  Retrieves Binary number and converts to hex and decimal
; Return  :  Nothing
;******************************************************************************
BinInput:
        lea esi,EnterBinNum
        call PrintString                ;display prompt
        lea esi,String
        call GetString                  ;get input

        call ValidateBinary             ;check if it's a valid binary number

        lea ebx, String
        call AsciiStrToIntArray         ;convert input string to array of integers
        call BinToDec                   ;convert array to decimal number
        lea esi, Decimal
        call PrintString                ;display prompt
        lea esi, DecNum
        lea edi, String2
        call Int2Ascii                  ;convert decimal number to ascii
        lea esi, String2                ;print decimal number
        call PrintString

        lea esi, Hex
        call PrintString                ;display prompt
        call DecToHex                   ;print hexadecimal number

        lea esi, Binary
        call PrintString                ;display prompt
        lea esi, String
        call PrintString                ;print binary number

        lea esi, BlankLine
        call PrintString                ;print newline
        jmp EnterChoice                 ;back to main menu

EndProgram:
        INVOKE ExitProcess, 0           ;quit program

;****************Near procedure for Binary Validation**************************
; Given   :  Input String in data segment
; Process :  Checks to see if only valid characters were inputed and
;            to make sure number is in the correct range
; Return  :  Nothing
;******************************************************************************
ValidateBinary PROC NEAR32
             pushad                     ;save all registers
						 pushfd                     ;save flags
             lea eax, String            ;load input
             xor ecx, ecx
             xor ebx, ebx               ;clear registers
loopbval:    mov bl, BYTE PTR[eax]    ;load digit
             inc eax                  ;increment pointer
             cmp bl, 0d               ;check if NULL
             je Quitbv
             inc ecx                  ;increment digit counter
             cmp ebx, 48d             ;check if '1'
             je loopbval
             cmp ebx, 49d             ;check if '0'
             je loopbval
invb:        lea esi, Invalid         ;invalid input
             call PrintString
             call BinInput            ;reprompt
Quitbv:      cmp ecx, 0d
             je invb
             cmp ecx, 32d             ;check if there's too many digits
             ja invb
             popfd                    ;restore flags
						 popad                    ;restore registers
             ret
ValidateBinary ENDP

;****************Near procedure for Hexadecimal Validation**************************
; Given   :  Input String in data segment
; Process :  Checks to see if only valid characters were inputed and
;            to make sure number is in the correct range
; Return  :  Nothing
;******************************************************************************
ValidateHex PROC NEAR32
             pushad                     ;save all registers
						 pushfd                     ;save flags
             lea eax, String            ;load input string
             xor ecx, ecx
             xor ebx, ebx               ;clear registers
loophval:    mov bl, BYTE PTR[eax]      ;load digit
             inc eax                    ;increment pointer
             cmp bl, 0d                 ;check if NULL
             je Quithv
             inc ecx                    ;increment digit counter
             cmp ebx, 48d
             jb invh
             cmp ebx, 58d
             jb loophval
             cmp ebx, 65d
             jb invh                    ;check if it's in the correct range
             cmp ebx, 71d
             jb loophval
             cmp ebx, 97d
             jb invh
             cmp ebx, 103
             jb toUpper
             jae invh
toUpper:     sub ebx, 32
             dec eax
             mov BYTE PTR[eax], bl     ;change from lowercase to uppercase
             inc eax
             jmp loophval
invh:        lea esi, Invalid
             call PrintString          ;invalid hex number, reprompt
             call HexInput
Quithv:      cmp ecx, 0d
             je invh
             cmp ecx, 8d
             ja invh                   ;check number of digits
             popfd                     ;restore flags
						 popad                     ;restore registers
             ret
ValidateHex ENDP

;****************Near procedure for Decimal Validation**************************
; Given   :  Input String in data segment
; Process :  Checks to see if only valid characters were inputed and
;            to make sure number is in the correct range
; Return  :  Nothing
;******************************************************************************
ValidateDec PROC NEAR32
             pushad                         ;save all registers
						 pushfd                         ;save flags
             lea eax, String
             xor ecx, ecx
             xor ebx, ebx                   ;clear registers
loopdval:    mov bl, BYTE PTR[eax]          ;load character
             inc eax                        ;increment pointer
             cmp bl, 0d
             je Quitdv
             inc ecx
             cmp ebx, 48d                   ;check for correct range
             jb invld
             cmp ebx, 58d
             jb loopdval
invld:       lea esi, Invalid               ;invalid input, reprompt
             call PrintString
             popfd
             popad
             call DecInput
Quitdv:      cmp ecx, 0d
             je invld
             cmp ecx, 10d                   ;check number of digits
             ja invld
             lea esi, String
             lea edi, DecNum
             call Ascii2Int                 ;convert from string to integer
             mov edi, [edi]                 ;to check if too large
             cmp edi, 4294967295d
             ja invld
             popfd                          ;restore flags
						 popad                          ;restore registers
             ret
ValidateDec ENDP


;******** Near procedure to turn an ASCII string into an Integer array ********
; Given   :  The address of the string in the bx register
; Process :  Converts a string of ASCII characters into an array of integers (as digits)
; Return  :  Outputs the array and array length in the data segment
;******************************************************************************
AsciiStrToIntArray PROC NEAR32
						             pushad                         ;save all registers
					               pushfd                         ;save flags
                         mov [ArrayLen], -1d			      ;set length of array to -1
                         xor eax, eax
                Check:   mov al, BYTE PTR[ebx]					;load first char
                         cmp eax,0d						          ;check if NULL
                         je Quit						            ;quit if NULL
                         add ebx, 1d					          ;point to next character
                         add [ArrayLen], 1d				      ;increment array length
                         cmp eax,57d					          ;check alpha/num
                         jbe Digit						          ;handle number
                         ja Alpha						            ;handle letter
                Digit:   sub eax,48d					          ;sub offset
                         lea esi, OutArray				      ;load address of outArray
                         add esi, ArrayLen				      ;move to current position in outArray
                         mov [esi], eax					        ;output digit
                         jmp Check						          ;repeat loop
                Alpha:   sub eax,55d					          ;sub offset
                         lea esi, OutArray				      ;load addr of outArray
                         add esi, ArrayLen				      ;move to current position
                         mov [esi], eax					        ;output digit
                         jmp Check						          ;repeat loop
                 Quit:   popfd                          ;restore flags
						 popad                                      ;restore registers
					     ret
AsciiStrToIntArray ENDP


;****************Near procedure for Hex to Decim**************************
; Given   :  The address of the integer digit array in the data segment
; Process :  Multiply each digit times 16 to the power of the digit number
;            and add to the running total
; Return  :  DecNum--containing decimal number in data segment
;******************************************************************************
HexToDec PROC NEAR32
                    pushad                          ;save all registers
                    pushfd                          ;save flags
         Init:      lea ecx, OutArray				        ;load addr of OutArray
                    add ecx, [ArrayLen]				      ;ecx points to last digit in array
                    mov [DigitCount], 0d			      ;clear digit counter
                    mov [DecNum], 0d				        ;clear result
         Repeater:  mov ebx, 0d						          ;clear all bytes
					          mov bl, BYTE PTR[ecx]			      ;grab first digit
                    sub ecx, 1d					          	;ecx points to next digit
                    mov eax, 1d						          ;eax equals 1 for multiplication
                    mov edx, 0d						          ;clear exponent counter
                    push ecx						            ;store digit pointer
                    mov ecx, 16d                    ;divisor is 16
         Power:     cmp edx, [DigitCount]			      ;check if exponent equals digitCount
                    je Product						          ;if so, done multiplying
                    push edx
                    mul ecx							            ;otherwise multiply by 16 again
                    pop edx
                    add edx, 1d						          ;increase counter
                    jmp Power						            ;repeat
         Product:   pop ecx							            ;restore digit pointer
                    mul ebx							            ;multiply power of 16 by digit
                    add [DecNum], eax				        ;add to running total
                    add [DigitCount], 1d				    ;increase digit number
                    lea eax, OutArray				        ;eax holds array location
                    cmp eax, ecx					          ;check if we've looped all digits
                    jle Repeater						        ;if not, continue looping
         Done:      popfd                           ;restore flags
                    popad                           ;restore registers
                    ret
HexToDec ENDP

;****************Near procedure for Binary to Decim**************************
; Given   :  The address of the integer digit array in the data segment
; Process :  Multiply each digit times 2 to the power of the digit number
;            and add to the running total
; Return  :  DecNum--containing decimal number in data segment
;******************************************************************************
BinToDec PROC NEAR32
                    pushad                          ;save all registers
                    pushfd                          ;save flags
         Initb:     lea ecx, OutArray				        ;load addr of OutArray
                    add ecx, [ArrayLen]				      ;ecx points to last digit in array
                    mov [DigitCount], 0d			      ;clear digit counter
                    mov [DecNum], 0d				        ;clear result
         Repeaterb: mov ebx, 0d						          ;clear all bytes
	                  mov bl, BYTE PTR[ecx]			      ;grab first digit
                    sub ecx, 1d						          ;ecx points to next digit
                    mov eax, 1d						          ;eax equals 1 for multiplication
                    mov edx, 0d						          ;clear exponent counter
                    push ecx						            ;store digit pointer
                    mov ecx, 2d                     ;divisor is 2
         Powerb:    cmp edx, [DigitCount]		        ;check if exponent equals digitCount
                    je Productb						          ;if so, done multiplying
                    push edx
                    mul ecx							            ;otherwise multiply by 16 again
                    pop edx
                    add edx, 1d						          ;increase counter
                    jmp Powerb						          ;repeat
         Productb:  pop ecx							            ;restore digit pointer
                    mul ebx							            ;multiply power of 16 by digit
                    add [DecNum], eax				        ;add to running total
                    add [DigitCount], 1d				    ;increase digit number
                    lea eax, OutArray				        ;eax holds array location
                    cmp eax, ecx					          ;check if we've looped all digits
                    jle Repeaterb						        ;if not, continue looping
         Doneb:     popfd                           ;restore flags
                    popad                           ;restore registers
                    ret
BinToDec ENDP

;****************Near procedure for Decimal to Hex**************************
; Given   :  Decimal number in DecNum in data segment
; Process :  Divides number by 16 until 0 is reached. Remainders are popped
;            from the stack and displayed as digits
; Return  :  HexNum--containing hexadecimal number in data segment
;******************************************************************************
DecToHex PROC NEAR32
                    pushad                          ;save all registers
                    pushfd                          ;save flags
                    mov eax, [DecNum]
                    mov ecx, 0d                     ;clear digit counter
                    mov ebx, 16d                    ;set divisor
         Divide:    mov edx,0h
                    div ebx                         ;divide number by 16
                    push edx                        ;store remainder
                    inc ecx                         ;increment digit counter
                    cmp eax, 0d
                    ja Divide                       ;keep dividing if not 0
Display0:           pop eax                         ;peak at top remainder
                    cmp eax, 10d                    ;if it's a letter, display 0 first
                    push eax                        ;push it back
                    jb ShowDigit
                    lea esi, Zero
                    call PutChar                    ;print 0
         ShowDigit: pop eax                         ;pop remainders off stack
                    cmp eax, 10d                    ;check whether alpha or numeric
                    jae AlphaHx
         Numbre:    or eax, 30h                     ;subtract number offset
                    jmp PrintHexChar
         AlphaHx:   add eax, 37h                    ;subtract alpha offset
     PrintHexChar:  mov [HexNum], eax               ;store digit
                    lea esi, HexNum
                    call PutChar                    ;display digit
                    dec ecx                         ;decrement digit counter
                    jnz ShowDigit                   ;continue until zero
                    popfd                           ;restore flags
                    popad
                    ret
DecToHex ENDP

;****************Near procedure for Decimal to Binary**************************
; Given   :  Decimal number in DecNum in data segment
; Process :  Divides number by 2 until 0 is reached. Remainders are popped
;            from the stack and displayed as digits
; Return  :  BinNum--containing binary number in data segment
;******************************************************************************
DecToBin PROC NEAR32
                    pushad                          ;save all registers
                    pushfd                          ;save flags
                    mov eax, [DecNum]
                    mov ecx, 0d                     ;clear digit counter
                    mov ebx, 2d                     ;set divisor
         Divideb:   mov edx,0h
                    div ebx                         ;divide number by 16
                    push edx                        ;store remainder
                    inc ecx                         ;increment digit counter
                    cmp eax, 0d                     ;continue until result is 0
                    ja Divideb
        ShowDigitb: pop eax                         ;pop remainders off stack
                    cmp eax, 10d                    ;check whether alpha or numeric
                    jge AlphaHxb
        Numbreb:    or eax, 30h                     ;add numeric offset
                    jmp PrintHexCharb
        AlphaHxb:   add eax, 37h                    ;add alpha offset
    PrintHexCharb:  mov [BinNum], eax               ;store digit
                    lea esi, BinNum
                    call PutChar                    ;display digit
                    dec ecx
                    jnz ShowDigitb
                    popfd                           ;restore flags
                    popad
                    ret

DecToBin ENDP


;********************* Near procedure to get a Character **********************
; Given   :  The Address of the Character to get in ESI register
; Process :  Input the Character using the kernel32.lib ReadFile from the
;         :  Standard_Input function call.  No registers are changed and the
;         :  flags are not affected.
; Return  :  The input character in the data segment
;******************************************************************************
GetChar PROC NEAR32                         ; Define procedure
            pushad                          ; save all registers
            pushfd                          ; save flags
            INVOKE GetStdHandle,STD_INPUT   ; get handle for keyboard
            mov hStdIn, eax                 ; save the handle
            INVOKE SetConsoleMode,          ; invoke standard console with
            hStdIn,                         ;   file handle for keyboard
            ENABLE_PROCESSED_INPUT          ;   turn line buffering off
            INVOKE ReadFile,                ; invoke standard ReadFile with
              hStdIn,                       ;   file handle for keyboard
              esi,                          ;   address of character
              1,                            ;   length of one byte
              NEAR32 PTR read,              ;   variable for # bytes read
              0                             ;   overlapped mode
            call PutChar                    ; echo the character on screen
            popfd                           ; restore flags
            popad                           ; restore registers
            ret                             ; return to caller
GetChar   ENDP

;******************* NEAR32 procedure to print a Character ********************
; Given   :  The Address of the Character to print in ESI register
; Process :  Print the Character using the kernel32.lib WriteFile to
;         :  Standard_Output function call.  No registers are changed and the
;         :  flags are not affected.
; Return  :  Nothing
;******************************************************************************
PutChar PROC NEAR32                         ; Define procedure
            pushad                          ; save registers
            pushfd                          ; save flags
            INVOKE GetStdHandle,STD_OUTPUT  ; get handle for console output
            mov hStdOut, eax                ; copy file handle for screen
	    INVOKE SetConsoleMode,          ; invoke standard console with
            hStdOut,                        ;   file handle for screen
            ENABLE_PROCESSED_OUTPUT	    ;   turn line buffering off
	    INVOKE WriteFile,               ; invoke standard WriteFile with
            hStdOut,                        ;   file handle for screen
            esi,                            ;   address of character
            1,                              ;   length of one byte
            NEAR32 PTR written,             ;   variable for # bytes written
            0                               ;   overlapped mode
            popfd                           ; restore flags
            popad                           ; restore registers
            ret                             ; return to caller
PutChar ENDP

;********************* Near procedure to get a String *************************
; Given   :  The Address of the String to fill in ESI register
; Process :  Input the String using the kernel32.lib ReadFile from the
;         :  Standard_Input function call.  No registers are changed and the
;         :  flags are not affected.
; Return  :  The input string in the data segment
;******************************************************************************
GetString PROC NEAR32                  ; Define procedure
            pushad                     ; save all registers
            pushfd                     ; save flags


            INVOKE GetStdHandle,STD_OUTPUT  ; get handle for console
            mov    hStdOut, eax             ; save the handle
            INVOKE SetConsoleMode,          ; invoke standard console with
            hStdOut,                        ;   file handle for keyboard
            ENABLE_LINE_WRAP                ;   turn line wrap on



            INVOKE GetStdHandle,STD_INPUT  ; get handle for console
            mov    hStdIn, eax         ; save the handle
            INVOKE SetConsoleMode,     ; invoke standard console with
            hStdIn,                    ;   file handle for keyboard
            DISABLE_PROCESSED_INPUT    ;   turn line buffering on
            mov    ecx, MAXSTR         ; string length
            mov    strLength, ecx      ; maximum string to accept
            mov    strAddr, esi        ; save pointer to input string
            INVOKE ReadFile,           ; invoke standard ReadFile with
              hStdIn,                  ;   file handle for keyboard
              strAddr,                 ;   address of string
              strLength,               ;   length of string
              NEAR32 PTR read,         ;   variable for # bytes read
              0                        ;   overlapped mode
            mov ecx, read              ; number of bytes read
            mov BYTE PTR [esi+ecx-2],0 ; replace CR/LF by trailing null
            popfd                      ; restore flags
            popad                      ; restore registers
            ret                        ; return to caller
GetString   ENDP

;******************* NEAR32 procedure to print a string ***********************
; Given   :  The Address of Null (0) terminated String to print in ESI register
; Process :  Print the String using the kernel32.lib WriteFile to
;         :  Standard_Output function call.  No registers are changed and the
;         :  flags are not affected.
; Return  :  Nothing
;******************************************************************************
PrintString PROC   NEAR32
            pushad                     ; save registers
            pushfd                     ; save flags
            mov    strAddr, esi        ; copy string address
                                       ; find string length   
            mov    strLength, 0        ; initialize string length
WhileChar:  cmp    BYTE PTR [esi], 0   ; character = null?
            jz     EndWhileChar        ; exit if so
            inc    strLength           ; increment character count
            inc    esi                 ; point at next character
            jmp    WhileChar           ; while more characters exist
EndWhileChar:
            INVOKE GetStdHandle,STD_OUTPUT ; get handle for console output
            mov    hStdOut, eax        ; copy file handle for screen
            INVOKE WriteFile,          ; invoke standard WriteFile with
              hStdOut,                 ;   file handle for screen
              strAddr,                 ;   address of string
              strLength,               ;   length of string
              NEAR32 PTR written,      ;   variable for # bytes written
              0                        ;   overlapped mode
            popfd                      ; restore flags
            popad                      ; restore registers
            ret                        ; return to caller
PrintString ENDP


;**************** Procedure to Convert ASCII to Integer ***********************
; Given   :  A pointer to the string to be Converted in the ESI register and a
;         :  pointer to the destination integer in EDI
; Process :  Convert the string of ASCII digits to an integer and store the
;         :  string in the address pointed to by EDI.  No registers are changed
;         :  and the flags are not affected.
; Return  :  Nothing
;******************************************************************************
Ascii2Int PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        cld                             ;Set the direction flag for forward
        mov ebx,0h                      ;Zero the EBX register
        xor eax,eax                     ;Clear the EAX register
NextIn: lodsb                           ;Get a character from the string
        cmp al,'0'                      ;If the character is less than 0, then
        jl Done                         ;  we have all the number and are Done
        cmp al,'9'                      ;If the character is more than 9, then
        jg Done                         ;  we have all the number and are Done
        and al,0Fh                      ;Mask out the high 4 bits, converting to Int
        xor ah,ah                       ;Zero the high byte of AX
        push eax                        ;Save the digit on the stack
        mov eax,10d                     ;Place 10 decimal in AX to multiply by
        mul ebx                         ;Multiply the number by 10
        mov ebx,eax                     ;Get number from EAX and put in EBX
        pop eax                         ;Get the digit back from the stack
        add ebx,eax                     ;Add the digit to the number
        jmp NextIn                      ;Get the next digit
Done:   mov [edi],ebx                   ;Save NUMBER at address pointed to by EDI
        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
Ascii2Int ENDP

;**************** Procedure to Convert Integer to ASCII ***********************
; Given   :  A pointer to the integer to be Converted in the ESI register and a
;         :  pointer to the destination string in EDI
; Process :  Convert the integer to a string of ASCII digits and store the
;         :  string in the address pointed to by EDI.  No registers are changed
;         :  and the flags are not affected.
; Return  :  Nothing
;******************************************************************************
Int2Ascii PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        cld                             ;Set the direction flag for forward
        mov eax,[esi]                   ;copy the integer to eax
        mov ecx,0h                      ;Zero the CX register for digit counter
        mov ebx,10d                     ;Set up divisor of 10 decimal
NextOut:mov edx,0h                      ;Zero EDX reg for high order dword of div
        div ebx                         ;Divide number in EAX by 10d
        push edx                        ;Save remainder on the stack
        inc ecx                         ;Count the digit
        cmp eax,0h                      ;Is number in EAX greater than 0
        jg NextOut                      ;Yes, get next digit
CharOut:pop eax                         ;Get number from the stack
        or eax, 0030h                   ;Convert Int to Ascii by adding 30h
        stosb                           ;  and store  in the destination string
        dec ecx                         ;Reduce characters to print by one
        jnz CharOut                     ;If CX > 0 loop to print next digit
        mov al,0                        ;Place a NULL in AL
        stosb                           ;  and null terminate the string
        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
Int2Ascii ENDP


Public _main
END                                         ;Code segment ends
And a sample run:

Code: Select all

Welcome to the binary-decimal-hex converter
program. You will enter a number that is either
in binary, hexadecimal, or decimal form, and I
will convert your number into the each of the
other two forms and then print out all three.
In order for me to perform, you must adhere to
the following restrictions:

Binary numbers up to 32 bits
Decimal numbers no greater than 4,294,967,295
Hexadecimal values up to FFFFFFFF

Enjoy.


Enter the number corresponding to the base of your number to be converted.
1) Base 10
2) Base 16
3) Base 2
4) Quit

5
Invalid input. Try again.

Enter the number corresponding to the base of your number to be converted.
1) Base 10
2) Base 16
3) Base 2
4) Quit

1

Enter a decimal number. (less than 4294967295d)
23456

Your number in decimal is: 23456
Your number in hexadecimal is: 5BA0
Your number in binary is: 101101110100000

Enter the number corresponding to the base of your number to be converted.
1) Base 10
2) Base 16
3) Base 2
4) Quit

2

Enter a hexadecimal number. (less than 0FFFFFFFFh)
FFFFFFFFF

Invalid input. Try again.


Enter a hexadecimal number. (less than 0FFFFFFFFh)
FFFFFFFF

Your number in decimal is: 4294967295
Your number in hexadecimal is: 0FFFFFFFF
Your number in binary is: 11111111111111111111111111111111

Enter the number corresponding to the base of your number to be converted.
1) Base 10
2) Base 16
3) Base 2
4) Quit

3

Enter a binary number. (less than 33 digits)
11001010101

Your number in decimal is: 1621
Your number in hexadecimal is: 655
Your number in binary is: 11001010101

Enter the number corresponding to the base of your number to be converted.
1) Base 10
2) Base 16
3) Base 2
4) Quit

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Mon Oct 19, 2009 12:56 pm
by Falco Girgis
Last week's microprocessor lab introduced us to I/O ports. We were required to flash LEDs in a sequence by varying voltage levels via bit manipulation on ports.

We had to do the equivalent in C and assembly.

MSP430 assembly:

Code: Select all

#include <msp430xG46x.h>

        NAME    main                    ; module name
        PUBLIC  main                    ; make main accessible from outside module
        
        ORG     0FFFEh
        DC16    init                    ; set reset vector to 'init' label

        RSEG    CSTACK                  ; pre-declaration of segment CSTACK
        RSEG    CODE                    ; place program in 'CODE' segment

init:   MOV     #SFE(CSTACK), SP        ; initialize stack
        BIS.B   #03h, &P1DIR
        BIS.B   #30h, &P7DIR
        
main:   MOV.B #00h, &P7OUT
        MOV.B #01h, &P1OUT
        MOV   #50000, R15
        
wait1:  DEC R15
        NOP
        NOP
        JNZ wait1
        
        MOV.B #02, &P1OUT
        MOV #050000, R15
        
wait2:  DEC R15
        NOP
        NOP
        JNZ wait2
        
        MOV.B #00h, &P1OUT
        MOV.B #10h, &P7OUT
        MOV #50000, R15
        
wait3:  DEC R15
        NOP
        NOP
        JNZ wait3
        
        MOV.B #20h, &P7OUT
        MOV #50000, R15
        
wait4:  DEC R15
        NOP
        NOP
        JNZ wait4
        
        JMP main
 
        END
        
C (lol)

Code: Select all

#include "msp430xG46x.h"

int  main() {
    WDTCTL = WDTPW + WDTHOLD;
    P1DIR |= 0x03;
    P7DIR |= 0x30;
    
    for(;;) {
        volatile int i;
        
        P1OUT = 0x02;
        
        i = 25000; 
      
        do { --i; } while (i != 0);
        
        P1OUT = 0x00;
        P7OUT = 0x10;
        
        i = 25000;
        do { --i; } while ( i != 0);
        
        P7OUT = 0x20;
        
        i = 25000;
        
        do { --i; } while( i!= 0);
        
        P7OUT = 0x00;    
    }
  
    return 0;
} 

Re: Falco's MSP430 (and now x86) Assembly Programs

Posted: Mon Oct 19, 2009 2:50 pm
by Pickzell
I downloaded a PDF for x86 ASM in June, I think. I haven't used it though.

Goals for 2009/10
-Learn ASM
-Understand these programs
-Kill Mark Overmars.
Good goals