Falco's MSP430 (and now x86) Assembly Programs

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
Posts: 4709
Joined: Tue Apr 29, 2008 3:24 pm
Current Project: https://github.com/dbechrd/RicoTech
Favorite Gaming Platforms: NES, Sega Genesis, PS2, PC
Programming Language of Choice: C
Location: San Francisco
Contact:

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

Post by dandymcgee »

Jesus Falco. *gives pat on the back*

And I thought moving the number 5 from the ax register to the bx register was badass...
Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

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

Post by avansc »

a very good friend of mine in south africa wrote this article for hack a day. quiet a smart dude. thought you might like it

http://hackaday.com/2009/10/03/garage-d ... t-sniffer/
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

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

Post by Falco Girgis »

We were assigned to screw with some buzzers/LEDs using the timer subsystem of the MSP430. It's kind of a pain in the ass if you try to follow the math. We divided the main clock of 8Mhz by 8 then fed it into the auxiliary clock which then powered our timer A, which has an internal divider that divided through by 4, then that toggled an interrupt service routine that incremented our software counter to achieve the correct frequency to drive our buzzers. Fuck me.

Code: Select all

/*
Falco Girgis
CPE323 
Project #6 - TimerA
*/

#include <msp430x14x.h>

#define PROJECT 3

void main(void) {
  int i;
  WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
  BCSCTL1 |= XTS;           
  BCSCTL1 |= DIVA_3;        //ACLK = MCLK/8
  
  do {
    IFG1 &= ~OFIFG; // Clear OSCFault flag from SW
    for (i = 0xFF; i > 0; i--); // Time for flag to set by HW
  } while ((IFG1 & OFIFG)); // OSCFault flag still set?
  // clock is stable
  BCSCTL2 |= SELM_3; // MCLK = LFXT1 (safe)
  
  CCTL0 = CCIE; // CCR0 interrupt enabled

#if PROJECT == 1
  TACTL = TACLR + TASSEL_1 + MC_1 + ID_3; // Start Timer_A in continuous mode with ACLK
   CCR0 = 62500;
  P2DIR |= 0x02; // P2.1 output
#elif PROJECT == 2
 TACTL = TACLR + TASSEL_1 + MC_3 + ID_3; // Start Timer_A in continuous mode with ACLK
  CCR0 = 62500;
  P2DIR |= 0x02; // P2.1 output
#elif PROJECT == 3
  TACTL = TACLR + TASSEL_1 + MC_3 + ID_2;
  CCR0 = 31;
  P4DIR |= 0x0C; //P4 ourput
#endif  
 
  _EINT(); // Enable interrupts
  _BIS_SR(LPM0_bits + GIE);
}


#if PROJECT == 1
int j;
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A () {
  if(j == 2) {
    j = 0;
    P2OUT ^= 0x02; // Toggle P2.1
  }
  else ++j;
}
#endif

#if PROJECT == 2
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A () {
    P2OUT ^= 0x02; // Toggle P2.1
}
#endif

#if PROJECT == 3

int current_state = 0;
int software_count = 0;
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A () {
    //check if a second has ellapsed
    if(software_count == 4032) {
       ++current_state;
       //change states
       if(current_state > 2) current_state = 0;
       software_count = 0;
    }
    else ++software_count;
  
    //Toggle port based on current state
    switch(current_state) {
    case 0:
      P4OUT = 0x00;
      break;
    case 1:
    case 2:
      P4OUT ^= 0x08;
    }
    
}
#endif
K-Bal
ES Beta Backer
ES Beta Backer
Posts: 701
Joined: Sun Mar 15, 2009 3:21 pm
Location: Germany, Aachen
Contact:

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

Post by K-Bal »

Counting NOPs would be simpler :D Strange method.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

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

Post by Falco Girgis »

K-Bal wrote:Counting NOPs would be simpler :D Strange method.
Counting NOPs in C?

And no offense, but that's a shitty method. The entire point of the MSP430 microprocessor is to be low in power consumption. I'm setting it to low power mode 0, where the CPU is set to completely turn off. Then a hardware interrupt is triggered when the separate A timer reaches the value that I specified in the CCR0 register. This exits low power mode and wakes the CPU, which toggles the LEDs/Timers then goes back to sleep. This draws minimal current from my two AA batteries.

My method is energy efficient and the correct way. Counting NOPs is what a nub with little to no hardware experience would do. ;)
K-Bal
ES Beta Backer
ES Beta Backer
Posts: 701
Joined: Sun Mar 15, 2009 3:21 pm
Location: Germany, Aachen
Contact:

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

Post by K-Bal »

I still have to learn that irony does not work in written text ;) Of course are you doing it the right way but the how sounds more like a hack :lol:
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

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

Post by Falco Girgis »

Today, ladies and gentlemen, I present to you the most tedious, bullshit, pain-in-the-asshole x86 assembly program that I have ever written. It's basically a string manipulation clusterfuck--complete with a bubble sort algorithm. If you don't know about the string/array opcodes like rep, scas, stos, lods, movs, etc--this might be moderately educational.

...I hope Kendall's teacher dies.

Code: Select all

TITLE proj3.asm                          ;File name of program

LF equ 0ah                              ;ASCII 10 - newline character
CR equ 0dh                              ;ASCII 13 - carriage return character
BEEP equ 7h                             ;ASCII Beep code
NEWLINE equ CR,LF                       ;Combine CR and LF for carriage return
DOUBLESPC equ NEWLINE,LF                ;Combine NEWLINE and LF for double space
MAXSTR equ 256d                         ;Accept up to 256 character string
MAXMSG equ 1000d

.586                                    ;Allow for Pentium instrucitons
.MODEL FLAT                             ;Memory model is FLAT (4GB)
INCLUDE io32.inc                        ;Include the 32 bit I/O procedures

include debugger.inc

.STACK  4096h                           ;4k hex bytes for stack
.DATA                                   ;Data segment begins here
   Intro     BYTE 'This program allows the user to enter a list of integers fromt he keyboard.',NEWLINE,
                  'The program saves the integers in an array, sortst he integers in ascending',NEWLINE,
                  'order, allows for the addition or deletion of integers, and deletion of the',NEWLINE,
                  'entire array.',0
   Menu      BYTE DOUBLESPC,'[1] Enter a List of Integers',NEWLINE,
                            '[2] Display the List of Integers',NEWLINE,
                            '[3] Display the List Sorted in Ascending Order',NEWLINE,
                            '[4] Add an Integer to the List',NEWLINE,
                            '[5] Delete an Integer from the List',NEWLINE,
                            '[6] Delete the List of Integers',NEWLINE,
                            '[7] Quit',DOUBLESPC,
                            'Enter a number to select --> ',0
   Invalid    BYTE NEWLINE,'That is not a "valid" choice ... try again, please.',BEEP,0
   InArray    BYTE DOUBLESPC,'Enter up to 10 integers or [Enter] to quit.',DOUBLESPC,0
   AddNumber  BYTE DOUBLESPC,'Enter a number to add --> ',0
   ArrayFull  BYTE DOUBLESPC, 'The list is full, you cannot add without deleting an integer first.',0
   Remove     BYTE DOUBLESPC, 'Enter the number to remove --> ', 0
   ConData    BYTE DOUBLESPC, 'The list contains data. Choose [4] to add one integer.',0
   Deleted    BYTE DOUBLESPC, 'The list has been deleted.', 0
   Empty      BYTE DOUBLESPC, 'The list is empty, so there is nothing to delete.', 0
   TheNum     BYTE NEWLINE, 'The number ',0
   Added      BYTE ' has been added.',0
   Rem        BYTE ' has been deleted.',0
   NotFound   BYTE ' could not be found.',0
   InvalidIn  BYTE DOUBLESPC, 'Invalid Input!',0
   String     BYTE MAXSTR dup(0)
   Array      DWORD 10d dup(?)
   SortedArray DWORD 10d dup(?)
   Choice     DWORD  ?
   Number     DWORD 0h
   Number2    DWORD 0h
   ArrayCount DWORD 0d
   TmpPtr     DWORD ?
   NextLine2  BYTE CR,LF,0
   Message    BYTE MAXMSG dup(0)
   Spacer     BYTE ' ',0
   Period     BYTE '.',0

;************************** 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, Intro
          call PrintString
NextMenu:
          lea esi, Menu
          call PrintString                ;Prompt user for input
          lea esi, Choice
          call GetChar

          .if Choice == '1'
              call FillArray              ;Fill array if 1
          .elseif Choice == '2'
              lea esi, Array
              mov TmpPtr, esi             ;Display array if 2
              call ShowArray
          .elseif Choice == '3'
              call BubbleSort             ;Display sorted array if 3
              lea esi, SortedArray
              mov TmpPtr, esi
              call ShowArray
          .elseif Choice == '4'           ;Add integer if 4
              call AddInteger
          .elseif Choice == '5'
              call DeleteInteger          ;Delete integer if 5
          .elseif Choice == '6'
              call DeleteArray            ;Delete entire array if 6
          .elseif Choice == '7'
              jmp quit                    ;Exit program if 7
          .else
              lea esi, Invalid            ;Invalid input
              call PrintString
          .endif
          jmp NextMenu                    ;Continue displaying menu until exit

quit: INVOKE  ExitProcess, 0            ; exit with return code 0

;**************** Procedure to Fill "Array" with user input ********************
; Given   : Nothing
; Process : Fills ArrayCount and Array in the data segment with user input.
;         : Continues prompting until no input is entered, or invalid input
;         : entered. 10 integer max.
; Return  : Nothing
;******************************************************************************
FillArray PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        mov eax, ArrayCount
        cmp eax, 0d                     ;Check if the array is empty
        je @@start
        lea esi, ConData                ;Otherwise print error and exit
        call PrintString
        jmp AllDone

@@start:lea esi, InArray                ;Prompt user
        call PrintString
        lea ebx, Array
        mov ArrayCount,0                ;counter for number of elements
        mov ecx,10d                     ;loop counter
looptop:
        lea esi,String
        call GetString
        cmp String,0                    ;No input--terminate
        je AllDone
        call ValidateInteger            ;Check if current input is valid
        cmp edx, 0d
        je AllDone                      ;Exit if not
        lea edi,Number
        call Ascii2Int                  ;Convert string to integer
        mov eax,Number
        mov [ebx],eax                   ;Store integer in Array
        add ebx,4d                      ;Increase array length
        inc ArrayCount
        loop looptop
AllDone:
        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
FillArray ENDP

;**************** Procedure to Display an Array *******************************
; Given   : A pointer to the array to be displayed in TmpPtr
; Process : Loops through each array entry, calculates the number of spaces to print
;         : and prints each element with corresponding index right justified
; Return  : Nothing
;******************************************************************************
ShowArray PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;

        lea esi, NextLine2
        call PrintString                ;Print newline
        mov ecx,ArrayCount              ;Exit if array is empty
        cmp ecx, 0d
        je endShA
        cld
@@loopTop:
        lea esi,NextLine2               ;Print newline
        call PrintString
        mov esi,TmpPtr                  ;Load array
        lodsd                           ;Load integer
        mov Number,eax                  ;Store current integer
        mov TmpPtr,esi                  ;Store current index

        mov ebx, ArrayCount             ;Load array size
        inc ebx
        sub ebx, ecx                    ;Determine what index we're on
        mov [Number2], ebx              ;Store index temporarily
        lea esi, Number2
        lea edi, String
        call Int2Ascii                  ;Convert index to string
        lea esi, String
        call PrintString                ;Print index

        jmp strlen                      ;Figure out strlen of current element

space:  lea esi, Spacer
        call PrintString
        loop space
        pop ecx
        lea esi,String
        call PrintString
        loop @@loopTop
        jmp endShA
strlen:
        lea esi, Number                 ;Load current element
        lea edi, String
        call Int2Ascii                  ;Convert to string
        push ecx
        mov ecx, -1d
        lea edi, String                 ;Load string
        xor al, al                      ;Scan for Null character
        repne scasb
        not ecx                         ;2s compliment ecx counter
        dec ecx                         ;ecx is now strlen
        mov eax, ecx
        mov ecx, 12d                    ;12-strlen = number of spaces required
        sub ecx, eax

        mov ebx, ecx                    ;temporarily store ecx
        pop ecx                         ;Check which loop iteration we're on
        cmp ecx, 1d                     ;last iteration
        push ecx                        ;restore ecx
        mov ecx, ebx                    ;Restore spacer counter
        ja space                        ;if we're not to the last iteration, proceed
        mov ebx, ArrayCount
        cmp ebx, 10d                    ;If we're at element 10 of the last iteration
        jb space                        ;remove a space from the spacer counter
        dec ecx
        jmp space
endShA: popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
ShowArray ENDP


;**************** Procedure for Bubble Sort Algorithm**************************
; Given   : Nothing
; Process : Takes "Array" in the Data segment, copies it over to "SortedArray"
;         : then performs bubble sort algorithm to organize in ascending order.
; Return  : Nothing
;******************************************************************************
BubbleSort PROC NEAR32
        pushad
        pushfd
        cld
        ;COPY ARRAY
        lea esi, Array
        lea edi, SortedArray
        mov ecx, 10d
        rep movsd                       ;Copy Array to SortedArray
        mov ecx, ArrayCount
        cmp ecx, 0d                     ;Exit if array is empty
        je @@end
@@loopOuter:
        mov eax, ArrayCount             ;Inner loop counter
        dec eax                         ;loop to ArrayCount-1
@@loopInner:
        cmp eax, 0d                     ;Check if we've looped to all elements
        je @@endInner
        lea esi, SortedArray            ;Reset array pointer
        push ecx                        ;save outer loop counter
        mov ecx, eax
@@PtrLoop:
        add esi, 4                      ;Increment pointer to current index
		    loop @@PtrLoop
		    pop ecx                         ;Restore outer loop counter
        push eax                        ;Store inner loop counter
        lodsd                           ;Load current index
        mov edi, eax                    ;edi holds index i
        pop eax
        dec eax                         ;decrement inner loop counter
        push eax
        sub esi, 8d                     ;move pointer to next number
        lodsd
        mov edx, eax                    ;edx holds index i-1
        pop eax
        cmp edi, edx                    ;if i < i-1
        jae @@loopInner                 ;else continue
        ;OTHERWISE SWAP edi, edx
        sub esi, 4
        mov [esi], edi                  ;Swap the two entries
        add esi, 4
        mov [esi], edx
        jmp @@loopInner                 ;Continue inner loop
@@endInner:
        loop @@loopOuter                ;Continue outer loop
@@end:  popfd
        popad
        ret
BubbleSort ENDP

;**************** Procedure to Add an Integer to the Array ********************
; Given   : Nothing
; Process : Prompts user for input (assuming array isn't full) then stores the
;         : new value in the last position of "Array" in the data segment
; Return  : Nothing
;******************************************************************************
AddInteger PROC NEAR32
        pushad
        pushfd
        cld
        mov edx, ArrayCount
        cmp edx, 10d                    ;Exit if array is full
        jge AddIError
        lea esi, AddNumber
        call PrintString                ;Display prompt
        lea esi, String                 ;Get user input
        call GetString                  ;Validate input
        call ValidateInteger
        cmp edx, 0d
        je AddIExit                     ;exit if they didn't enter anything
        lea edi, Number
        call Ascii2Int                  ;convert input to integer
        mov eax, [Number]
        mov ecx, ArrayCount             ;Load counter
        lea edi, Array                  ;Load array index
AddILoop:
        add edi, 4      ;Apply our index offset manually since stosd won't do it for us. :(
        loop AddILoop
        stosd                           ;Store integer
        inc ArrayCount
        lea edi, Message
        mov [Message], 0d
        lea esi, TheNum
        call Strcat                     ;Concatenate success message
        lea esi, String
        call Strcat
        lea esi, Added
        call Strcat
        lea esi, Message
        call PrintString                 ;Display success message
        jmp AddIExit
AddIError:
        lea esi, ArrayFull
        call PrintString
AddIExit:
        popfd
        popad
        ret
AddInteger ENDP

;**************** Procedure to Delete an Integer ******************************
; Given   : Nothing
; Process : Prompts for user for a number. Scans "Array" for the number, then 
;         : removes it. Appropriate message is displayed if the Number was not
;         : found in the array.
; Return  : Nothing
;******************************************************************************
DeleteInteger PROC NEAR32
        pushad
        pushfd
        cld
        mov eax, ArrayCount             ;Check to see if Array is empty
        cmp eax, 0d
        ja @@start                      ;Continue if not
        lea esi, Empty
        call PrintString                ;Display error if it is empty
        jmp @@end
@@start:
        lea esi, Remove                 ;Prompt for an integer
        call PrintString
        lea esi, String
        call GetString
        call ValidateInteger            ;Get and validate integer
        cmp edx, 0d                     ;Exit if they entered nothing
        je @@end
        lea edi, Number
        call Ascii2Int                  ;convert input from string to integer
        mov eax, [Number]
        lea edi, Array                  ;load destination array
        mov ecx, ArrayCount             ;load counter
        repne scasd                     ;can for integer

        cmp ecx, 0d                     ;If we found it before the end, continue
        ja @@mid
        sub edi, 4                      ;Check to see if last index was a match
        mov ebx, [edi]
        cmp ebx, eax
        je @@mid                        ;If so, continue
        lea edi, Message
        mov Message, 0d
        lea esi, TheNum
        call Strcat                     ;If not, the string wasn't found
        lea esi, String
        call Strcat
        lea esi, NotFound
        call Strcat
        lea esi, Message                ;Concatenate error message and exit
        call PrintString
        jmp @@end

@@mid:  mov esi, edi                    ;Copy string to cover blank entry
        sub edi, 4d
        rep movsd
        dec ArrayCount                  ;Decrease array length

        lea edi, Message
        mov Message, 0d
        lea esi, TheNum                 ;Concatenate success message
        call Strcat
        lea esi, String
        call Strcat
        lea esi, Rem
        call Strcat
        lea esi, Message
        call PrintString                ;Display success message

@@end:  popfd
        popad
        ret
DeleteInteger ENDP

;**************** Procedure to Delete Entire Array *******************************
; Given   : Nothing
; Process : Checks to make sure the array isn't already empty, then clears it
; Return  : Nothing
;******************************************************************************
DeleteArray PROC NEAR32
        pushad
        pushfd
        cld
        mov eax, ArrayCount            ;Load array length
        cmp eax, 0d
        ja @@start
        lea esi, Empty
        call PrintString               ;If array is empty, display error and exit
        jmp @@end
@@start:mov ArrayCount, 0d
        lea esi, Deleted               ;Otherwise set length to 0 and exit
        call PrintString
@@end:  popfd
        popad
        ret
DeleteArray ENDP

;**************** Procedure to Concatenate Arrays *****************************
; Given   : Source string in ESI. Destination String in EDI
; Process : Finds terminating null character at the end of ESI. Copies EDI over
;         : until its null character is found.
; Return  : Nothing
;******************************************************************************
Strcat PROC NEAR32
        pushad
        pushfd
        cld
        mov ecx, -1
        xor al, al
        repnz scasb                    ;Scan until terminating null character is found
        dec edi                        ;Back up one byte

@@loop: lodsb                          ;load value from source
        stosb                          ;store value in destination
        test al, al
        jnz @@loop                     ;continue until destination's NULL is hit
        popfd
        popad
        ret
Strcat ENDP

;**************** Procedure to Validate an Integer ****************************
; Given   : Nothing
; Process : Checks to see that the "String" array would become a valid integer
;         : before calling Ascii2Int
; Return  : Bool in EDX - 1 is valid; 0 is invalid
;******************************************************************************
ValidateInteger PROC NEAR32
        push ecx
        push eax
        push esi

        mov edx, 1d                    ;Set validity to true
        lea eax, String                ;Load string
@@loop: mov cl, BYTE PTR [eax]         ;Loop every byte
        cmp cl, 0h
        je  @@done                     ;Exit when NULL is reached
        inc eax
        cmp cl, 48d
        jb @@inv                       ;Check for 0-9 ascii range
        cmp cl, 57d
        jbe @@loop
        jmp @@inv
@@inv:  mov edx, 0d                    ;Set validity to false
        lea esi, InvalidIn
        call PrintString               ;Display error message if outside of range
@@done: pop esi
        pop eax                        ;Restore all registers that were screwed with except EDX flag
        pop ecx

        ret
ValidateInteger ENDP

Public _main
END                                     ;Code segment ends
]
And a sample run (annoying spacing compliments of MSWord)

Code: Select all

This program allows the user to enter a list of integers fromt he keyboard.

The program saves the integers in an array, sortst he integers in ascending

order, allows for the addition or deletion of integers, and deletion of the

entire array. 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 1 

Enter up to 10 integers or [Enter] to quit. 

23

44444

8765

0

123456

2

23

456

1

76587633 
 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 2 

1          23

2       44444

3        8765

4           0

5      123456

6           2

7          23

8         456

9           1

10   76587633 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 3 

1           0

2           1

3           2

4          23

5          23

6         456

7        8765

8       44444

9      123456

10   76587633 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 4 

The list is full, you cannot add without deleting an integer first. 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 5 

Enter the number to remove --> 456 

The number 456 has been deleted. 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 3 

1           0

2           1

3           2

4          23

5          23

6        8765

7       44444

8      123456

9    76587633 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 4 

Enter a number to add --> abcde 
 

Invalid Input! 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 4 

Enter a number to add --> 46720 

The number 46720 has been added. 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 3 

1           0

2           1

3           2

4          23

5          23

6        8765

7       44444

8       46720

9      123456

10   76587633 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 6 

The list has been deleted. 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 2 
 

[1] Enter a List of Integers

[2] Display the List of Integers

[3] Display the List Sorted in Ascending Order

[4] Add an Integer to the List

[5] Delete an Integer from the List

[6] Delete the List of Integers

[7] Quit 

Enter a number to select --> 7Press any key to continue . . .
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

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

Post by Falco Girgis »

So I just barely got out of my final lab for embedded systems. We had two final projects, both of which were pretty damn extreme.

Our first project utilized the timerA subsystem of the MSP430 to wake it from lower power mode (CPU off) every half second, so that it could check the USART (configured in UART mode) for an incoming bitstream. The MSP430 was supposed to communicate with Windows hyperterminal on Com1 and continually print the temperature (which we received by polling the temperature sensor during our interrupt period) along with a timestamp:

Code: Select all

/*
  Falco Girgis
  11/19/09
  Lab #8
  Assignment #1
*/

#include <msp430x14x.h>
#include "stdio.h"

int i = 0;
int z =0;
char x[10];
unsigned char thr_char; /* hold char from UART RX*/
unsigned char rx_flag; /* receiver rx status flag */
long int IntDegF;
long int temp;
long int IntDegC;


// initialize basic clock module
void InitOsc(void);
// UART Initializaion
void UART_Initialize(void);
//send char function
void UART0_putchar(char c);

void main(void) {
  WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
  InitOsc();
  UART_Initialize();
  ADC12CTL0 = SHT0_8 + REFON + ADC12ON;
  ADC12CTL1 = SHP; // enable sample timer
  ADC12MCTL0 = 0x01A;
  ADC12IE = 0x001;
  rx_flag = 0; // rx default state "empty"
  _EINT();  
  
  BCSCTL1 |= XTS;
  BCSCTL1 |= DIVA_3;
  WDTCTL = WDTPW + WDTHOLD; // Stop WDT
  P3SEL |= 0x30; // P3.6,7 = USART1 option select
  
  ME1 |= UTXE0 + URXE0; // Enable USART1 TXD/RXD
  UCTL0 |= CHAR; // 8-bit character
  UTCTL0 |= SSEL0; // UCLK = ACLK 
  UBR00 = 0x1A; // 
  UBR10 = 0x00;
  UMCTL0 = 0x00; // Modulation
  UCTL0 &= ~SWRST; // Initialize USART state machine
  //IE1 |= URXIE0; // Enable USART1 RX interrupt
 
  do {
    IFG1 &= ~OFIFG; // Clear OSCFault flag from SW
    for (i = 0xFF; i > 0; i--); // Time for flag to set by HW
  } while ((IFG1 & OFIFG)); // OSCFault flag still set?
  // clock is stable
  BCSCTL2 |= SELM_3; // MCLK = LFXT1 (safe)

  CCTL0 = CCIE; // CCR0 interrupt enabled
  CCR0 = 62500;
  P2DIR |= 0x02; // P2.1 output
  TACTL = TASSEL_1 + TACLR + MC_1 + ID_3;
  _EINT(); // Enable interrupts
  _BIS_SR(LPM0_bits + GIE); // Enter the low-power mode 0

  for(;;);
}
 
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void) {
  i++;
  if(i == 2) {
    i=0;
    static int s1=0,s2=0,m1=0,m2=0;
    s1++;
    if(s1 == 10) {
      s2++;
      s1 = 0;
      if(s2 == 6) {
        m1++;
        s2 = 0;
        if(m1 == 10) {
          m2++;
          m1 = 0;
          if(m2 == 6) {        
            m2 = 0;   
          }
        }
      }
    }
    
    ADC12CTL0 |= ENC + ADC12SC; // Sampling and conversion start
  _BIS_SR(CPUOFF + GIE); // LPM0 with interrupts enabled
  // oF = ((x/4096)*1500mV)-923mV)*1/1.97mV = x*761/4096 - 468
  // IntDegF = (ADC12MEM0 - 2519)* 761/4096
  IntDegF = (temp - 2519) * 761;
  IntDegF = IntDegF / 4096;
  // oC = ((x/4096)*1500mV)-986mV)*1/3.55mV = x*423/4096 - 278
  // IntDegC = (ADC12MEM0 - 2692)* 423/4096
  IntDegC = (temp - 2692) * 423;
  IntDegC = IntDegC / 4096;
      
    z = sprintf(x, "%d%d:%d%d<%ld F/ %ld C>", m2, m1, s2 , s1, IntDegF, IntDegC);
    
    for(int i = 0; i < z; ++i) {
     while (!(IFG1 & UTXIFG0)); // USART1 TX buffer ready?
     TXBUF0 = x[i]; // RXBUF1 to TXBUF1
     
    }
      while (!(IFG1 & UTXIFG0)); // USART1 TX buffer ready?
     TXBUF0 = '\r'; // RXBUF1 to TXBUF1

  }
}

void UART0_putchar(char c) {
  // wait for other character to transmit
  while (!(IFG1 & UTXIFG0));
  U0TXBUF = c;
}

#pragma vector=ADC_VECTOR
__interrupt void ADC12ISR (void){
  temp = ADC12MEM0; // Move results, IFG is cleared
  _BIC_SR_IRQ(CPUOFF); // Clear CPUOFF bit from 0(SR)
}

void InitOsc(void) {
  int i;
  IFG2 = 0;
  IFG1 = 0;
  //using a 8MHz clock from LFXT1, and ACLK=LFXT1
  BCSCTL1 |= XTS;
  /*wait in loop until crystal stabalizes*/
  do{
    IFG1 &= ~OFIFG;
  }
  while (OFIFG & IFG1);
  for (i = 0xFF; i > 0; i--);
  //Reset osc. fault flag again
  IFG1 &= ~OFIFG;
}

void UART_Initialize(void) {
////////////////////////////////////////////////////////////////
// UART0 Initialization
////////////////////////////////////////////////////////////////
// UART0 - 38400 bps
// IMPORTANT NOTICE: the following configuration works only for 8MHZ clock rate
// AND 38400 bps baud rate
// You have to recalculate these values if the cpu clock rate or baud rate has changed  
  U0MCTL = 146;
  U0BR0 = 208;
  U0BR1 = 0;
  P3SEL |= 0x30; // bits 4-5 are for special function UART0
  ME1 |= URXE0 + UTXE0; // UART module enable
  U0CTL = CHAR; /* 8-bit characters */
  U0TCTL = SSEL0; /* clock source ACLK, 8MHZ */
  U0RCTL = 0;
  IE1 |= URXIE0; // enable RX interrupts
}
With the second project, we were supposed to be generating a 100hz sinusoidal output wave with an amplitude oscillating between 0v and 2.5V. The problem was that the standard sin(), cos() functions were waaay too slow to be utilized in software to generate the required waveform with an 8mhz clock. I had to create a loockup table of approximated sin/cos values (256 samples for 0 to 1/2pi). I sampled a fourth of the sin wave (because of memory constraints). Then I did simple arithmetic on this lookup table and sent the result to the DAC (digital to analog converter) to produce the entire waveform:

Code: Select all

/*
  Falco Girgis
  11/19/09
  Lab #8 Project 2
*/
#include "msp430xG46x.h"
#include "sine_lut_256_fourth.h" 

void main(void) {
  unsigned int i;
  int quad;
//  Description: This program demonstrates setting the internal DCO to run at
//  8MHz with auto-calibration by the FLL+.
//  ACLK = LFXT1 = 32768Hz, MCLK = SMCLK = DCO = (121+1) x 2 x ACLK = 7995392Hz
//  //* An external watch crystal between XIN & XOUT is required for ACLK *//	
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  FLL_CTL0 |= DCOPLUS + XCAP18PF;           // DCO+ set, freq = xtal x D x N+1
  SCFI0 |= FN_4;                            // x2 DCO freq, 8MHz nominal DCO
  SCFQCTL = 121;                            // (121+1) x 32768 x 2 = 7.99 MHz
  P1DIR = 0x22;                             // P1.1 & P1.5 to output direction
  P1SEL = 0x22;                             // P1.1 & P1.5 to output MCLK & ACLK
  

  ADC12CTL0 = REF2_5V + REFON; // Internal 2.5V ref on
  for (i=50000; i>0; i--); // Delay to allow Ref to settle
  __disable_interrupt(); // Disable Interrupts
  DAC12_0CTL = DAC12IR + DAC12AMP_5 + DAC12ENC; //Sets DAC12
  CCTL0 = CCIE; // CCR0 interrupt enabled
  CCR0 = 72; // Sets Timer Freq (1048576*0.1sec/256)
  TACTL = TASSEL_2 + MC_1; // set clock to SMCLK, up mode

  i=0;
  while (1){
    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled
    switch (quad) {
     case 0: DAC12_0DAT = LUT256[i];    
         break;
     case 1: DAC12_0DAT = LUT256[255-i];
         break;
     case 2: DAC12_0DAT = 4095 - LUT256[i];
         break;
     case 3: DAC12_0DAT = -(LUT256[255-i]);
  }
  ++i;
  if(i == 256) {
    i = 0;
    ++quad;
    if(quad == 4) quad = 0;
  }
  }
}

#pragma vector = TIMERA0_VECTOR
__interrupt void TA0_ISR(void) {
  __bic_SR_register_on_exit(LPM0_bits); // Exit LPMx, interrupts enabled
}
User avatar
hurstshifter
ES Beta Backer
ES Beta Backer
Posts: 713
Joined: Mon Jun 08, 2009 8:33 pm
Favorite Gaming Platforms: SNES
Programming Language of Choice: C/++
Location: Boston, MA
Contact:

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

Post by hurstshifter »

That's some damn interesting stuff right there. Way over my head though.

These were parts of your final project your say? When does your semester end? Ours goes until December 22nd (pending on when your finals are that week).
"Time is an illusion. Lunchtime, doubly so."
http://www.thenerdnight.com
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

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

Post by Falco Girgis »

I present to you Kendall's final project in her x86 assembly programming class. It implements a bunch of formulas for calculating the volume and surface area of various different geometries. Everything is done using the FPU and IEEE floating point numbers.

Code: Select all

TITLE proj3.asm                          ;File name of program

MAXSTR equ 256d                         ;Accept up to 256 character string

LF equ 0ah                              ;ASCII 10 - newline character
CR equ 0dh                              ;ASCII 13 - carriage return character
BEEP equ 7h                             ;ASCII Beep code
NEWLINE equ CR,LF                       ;Combine CR and LF for carriage return
DOUBLESPC equ NEWLINE,LF                ;Combine NEWLINE and LF for double space
MAXSTR equ 256d                         ;Accept up to 256 character string
MAXMSG equ 1000d
FALSE EQU  0                            ;Flags
TRUE  EQU  1                            ;
C3 EQU 0100000000000000b                ;Condition codes which are checked
C2 EQU 0000010000000000b                ;  in the FPU Status register
C0 EQU 0000000100000000b                ;

.586                                    ;Allow for Pentium instrucitons
.MODEL FLAT                             ;Memory model is FLAT (4GB)
INCLUDE io32.inc                        ;Include the 32 bit I/O procedures
.STACK  4096h                           ;4k hex bytes for stack

.DATA                                   ;Data segment begins here
   Intro     BYTE 'This program takes user-inputted floating point numbers and calculates',NEWLINE,
                  'surface area and volume for the selected geometric shapes.',0
   Menu      BYTE DOUBLESPC,'1) Surface Area and Volume of a Cube',NEWLINE,
                            '2) Surface Area and Volume of a Rectangular Prism',NEWLINE,
                            '3) Surface Area and Volume of a Sphere',NEWLINE,
                            '4) Surface Area and Volume of a Cylinder',NEWLINE,
                            '5) Surface Area and Volume of a Cone',NEWLINE,
                            '6) Quit',DOUBLESPC,
                            'Enter a number to select --> ',0
   InvMenu   BYTE DOUBLESPC,'Invalid menu option!',0
   InvalidIn BYTE NEWLINE,'Invalid floating point number!',0
   PSide     BYTE 'Enter the length of a side(real) --> ',0
   PLength   BYTE 'Enter the length(real) --> ',0
   PWidth    BYTE 'Enter the width (real) --> ',0
   PHeight   BYTE 'Enter the height(real) --> ',0
   PRadius   BYTE 'Enter the radius(real) --> ',0
   Area      BYTE NEWLINE,'Area:    ',0
   Volume    BYTE 'Volume:  ',0
   Valid     BYTE ?

   Choice    DWORD ?
   String    BYTE MAXSTR dup(0)
   Newl      BYTE NEWLINE,0
   ADat      REAL4 ?
   VDat      REAL4 ?
   SDat      REAL4 ?
   LDat      REAL4 ?
   HDat      REAL4 ?
   WDat      REAL4 ?
   RDat      REAL4 ?

  one        REAL4  1.0                   ;Used in fp2a
  ten        REAL4  10.0                  ;Used in a2fp and fp2a
  round      REAL4  0.000005              ;Used for rounding control in fp2a
  FPNum      REAL4  ?                     ;Storage for entered real number
  byteTen    BYTE   10                    ;Used in fp2a
  point      BYTE   ?                     ;Flag for a2fp
  minus      BYTE   ?                     ;Flag for a2fp
  digit      WORD   ?                     ;Used in a2fp and fp2a
  exponent   WORD   ?                     ;Used in fp2a
  controlWd  WORD  ?                     ;Used in fp2a
  
  FlConst6   REAL4 6.0000
  FlConst2   REAL4 2.0000
  FLConst4   REAL4 4.0000
  FLConst3   REAL4 3.0000
  FLConsthalf REAL4 0.5000
  FLConstPi  REAL4 3.14159265
  TempF1     REAL4 ?
  TempF2     REAL4 ?


.CODE                                     ;executable section begins here
_main:
        lea esi, Intro
        call PrintString
prompt: lea esi, Menu
        call PrintString
        lea esi, choice
        call GetChar

        .if Choice == '1'
             call PromptCube
             mov al, Valid
             cmp al, 1d
             jne prompt
             call ProcessCube
             call PrintResults
        .elseif Choice == '2'
             call PromptPrism
             mov al, Valid
             cmp al, 1d
             jne prompt
             call ProcessPrism
             call PrintResults
        .elseif Choice == '3'
             call PromptSphere
             mov al, Valid
             cmp al, 1d
             jne prompt
             call ProcessSphere
             call PrintResults
        .elseif Choice == '4'
             call PromptCylinder
             mov al, Valid
             cmp al, 1d
             jne prompt
             call ProcessCylinder
             call PrintResults
        .elseif Choice == '5'
             call PromptCone
             mov al, Valid
             cmp al, 1d
             jne prompt
             call ProcessCone
             call PrintResults
        .elseif Choice == '6'
             jmp quit
        .else
             lea esi, InvMenu
             call PrintString
        .endif
        jmp prompt

quit: INVOKE  ExitProcess, 0            ; exit with return code 0


PromptCube PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        lea esi, Newl
        call PrintString
        call PrintString
        lea esi, PSide
        call PrintString
        lea esi, String
        call GetString
        mov Valid, 1d
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp SDat
@@quit: popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
PromptCube ENDP

PromptPrism PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        mov Valid, 1d
        lea esi, Newl
        call PrintString
        call PrintString
        lea esi, PLength
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp LDat
        lea esi, PWidth
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp WDat
        lea esi, PHeight
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp HDat
@@quit:
        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
PromptPrism ENDP


PromptSphere PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        mov Valid, 1d
        lea esi, Newl
        call PrintString
        call PrintString
        lea esi, PRadius
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp RDat
@@quit:
        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
PromptSphere ENDP


PromptCylinder PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        mov Valid, 1d
        lea esi, Newl
        call PrintString
        call PrintString
        lea esi, PRadius
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp RDat
        lea esi, PHeight
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp HDat
@@quit:
        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
PromptCylinder ENDP

PromptCone PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        mov Valid, 1d
        lea esi, Newl
        lea esi, Newl
        call PrintString
        call PrintString
        lea esi, PRadius
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp RDat
        lea esi, PHeight
        call PrintString
        lea esi, String
        call GetString
        call ValidateReal
        cmp edx, 1d
        je @@quit
        call a2fp
        fstp HDat
@@quit: popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
PromptCone ENDP

PrintResults PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        lea esi, Area
        call PrintString
        lea edi, String
        lea esi, ADat
        call fp2a
        lea esi, String
        call PrintString
        lea esi, Newl
        call PrintString
        lea esi, Volume
        call PrintString
        lea edi, String
        lea esi, VDat
        call fp2a
        lea esi, String
        call PrintString
        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
PrintResults ENDP

ValidateReal PROC NEAR32                        ;
        push ecx
        push eax
        push esi
        push ebx ;decimal flag
        
        mov ebx, 0d
        mov edx, 0d

        lea eax, String                ;Load string
@@loop: mov cl, BYTE PTR [eax]         ;Loop every byte
        cmp cl, 0h
        je  @@done                     ;Exit when NULL is reached
        inc eax
        cmp cl, 48d
        jb @@maybeinv                       ;Check for 0-9 ascii range
        cmp cl, 57d
        jbe @@loop
        jmp @@inv
@@maybeinv:
        cmp cl, 46d
        jne @@inv
        inc ebx ;found another decimal
        cmp ebx, 1d
        ja @@inv
        jmp @@loop
@@inv:  mov edx, 1d                    ;Set validity to false
        lea esi, InvalidIn
        call PrintString               ;Display error message if outside of range
        mov Valid, 0d
@@done: lea ebx, string
        cmp ebx, eax
        jne @@done2
        lea esi, InvalidIn
        call PrintString
        mov Valid, 0d
        mov edx, 1d
@@done2:pop ebx
        pop esi
        pop eax                        ;Restore all registers that were screwed with except EDX flag
        pop ecx
        ret
ValidateReal ENDP

ProcessCube PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        finit

        fld1
        fldz
        fadd SDat
        fmul SDat
        fmul FlConst6
        fstp ADat
        
        fld1
        fldz
        fadd SDat
        fmul SDat
        fmul SDat
        fstp VDat

        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
ProcessCube ENDP

ProcessPrism PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        finit

        fld1
        fldz
        fadd LDat
        fmul HDat
        fmul FLConst2
        fstp TempF1
        fld1
        fldz
        fadd WDat
        fmul HDat
        fmul FLConst2
        fstp TempF2
        fld1
        fldz
        fadd WDat
        fmul LDat
        fmul FLConst2
        fadd TempF1
        fadd TempF2
        fstp ADat

        fld1
        fldz
        fadd LDat
        fmul WDat
        fmul HDat
        fstp VDat

        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
ProcessPrism ENDP

ProcessSphere PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        finit

        fld1
        fldz
        fadd RDat
        fmul RDat
        fmul FLConstPi
        fmul FLConst4
        fstp ADat
        
        fld1
        fldz
        fadd RDat
        fmul RDat
        fmul RDat
        fmul FLConstPi
        fstp TempF1
        fld1
        fldz
        fadd FLConst4
        fxch
        fmul FLConst3
        fxch
        fdivr
        fmul TempF1
        fstp VDat

        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
ProcessSphere ENDP

ProcessCylinder PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        finit

        fld1
        fldz
        fadd RDat
        fmul RDat
        fmul FLConstPi
        fmul FLConst2
        fstp TempF1
        fld1
        fldz
        fadd HDat
        fmul RDat
        fmul FLConstPi
        fmul FLConst2
        fadd TempF1
        fstp ADat

        fld1
        fldz
        fadd RDat
        fmul RDat
        fmul HDat
        fmul FLConstPi
        fstp VDat

        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
ProcessCylinder ENDP

ProcessCone PROC NEAR32
        pushad                          ;Save the contents of all registers
        pushfd                          ;
        finit

        fld1
        fldz
        fadd RDat
        fmul RDat
        fmul FLConstPi
        fstp TempF1
        fld1
        fldz
        fadd RDat
        fmul RDat
        fstp TempF2
        fld1
        fldz
        fadd HDat
        fmul HDat
        fadd TempF2
        fsqrt 
        fmul RDat
        fmul FLConstPi
        fadd TempF1
        fstp ADat

        fld1
        fldz
        fadd RDat
        fmul RDat
        fmul HDat
        fmul FLConstPi
        fxch
        fmul FLConst3
        fxch
        fdivr
        fstp VDat


        popfd                           ;Restore the registers
        popad                           ;
        ret                             ;Return to Calling procedure
ProcessCone ENDP


;--------- Convert ASCII String to Floating Point Number ----------------------
; Given   :ESI register pointing to the ASCII number to convert
; Process :After an optional leading minus sign, only digits 0-9 and a decimal
;          point are accepted -- the scan terminates with any other character.
;          This procedure produces an IEEE floating point number.  No registers
;          are changed and the flags are not affected.
; Return  :The floating point value is returned in ST.
;------------------------------------------------------------------------------
a2fp PROC NEAR32
          pushad               ;Save the contents of all registers
          pushfd               ;
          finit                ;Initialize the Floating Point Stack
          fld1                 ; divisor := 1.0
          fldz                 ; value := 0.0
          mov  point, false    ; no decimal point found yet
          mov  minus, false    ; no minus sign found yet
          lodsb                ; load first character into AL register
          cmp al,'-'           ; check for minus sign
          jne  NotMinus        ; skip if not
          mov  minus, true     ; minus sign found
          lodsb                ; load next character into AL register
NotMinus:                      ; was not negative number
WhileMore:cmp  al, '.'         ; decimal point?
          jne  NotPoint        ; skip if not
          mov  point, true     ; found decimal point
          jmp  nextChar
NotPoint: cmp  al, '0'         ; character a digit?
          jl   EndWhile        ; exit if lower than '0'
          cmp  al, '9'
          jg   EndWhile        ; exit if higher than '9'
          and  ax, 000fh       ; convert ASCII to integer value
          mov  digit, ax       ; put integer in memory
          fmul ten             ; value := value * 10
          fiadd digit          ; value := value + digit
          cmp  point, true     ; already found a decimal point?
          jne  endifDec        ; skip if not
          fxch                 ; put divisor in ST and value in ST(1)
          fmul ten             ; divisor := divisor * 10
          fxch                 ; value back to ST; divisor back to ST(1)
endifDec:
nextChar: lodsb                ; load next character into AL registe
          jmp  WhileMore       ; go process the character
EndWhile: fdivr                ; value := value / divisor
          cmp  minus, true     ; was there a minus sign?
          jne  IsPositive      ; no, it is a positive number
          fchs                 ; yes, value := -value
IsPositive:
          popfd                ;Restore the registers
          popad                ;
          ret                  ; return
a2fp  ENDP

;--------- Convert Floating Point Number to ASCII String ----------------------
; Given   :ESI pointing to FP value to convert and EDI pointing to the output 
;          string destination.
; Process :Build ASCII string with format [blank/-]d.dddddE[+/-]dd and store
;          the string in the data segment. (Output is always 12 characters.)
;          No registers are changed and the flags are not affected.
; Return  :Nothing
;------------------------------------------------------------------------------
fp2a PROC NEAR32
          pushad                ;Save the contents of all registers
          pushfd                ;
          finit                 ; initialize the Floating Point Stack
          fstcw controlWd       ; get control word
          push controlWd        ; save control word
          or   controlWd, 0000110000000000b
          fldcw controlWd       ; set control to chop
          fld REAL4 PTR [esi]   ; load ST with the FP value
          mov  exponent, 0      ; exponent := 0
          ftst                  ; value >= 0?
          fstsw  ax             ; status word to AX
          and  ax, C0           ; check C0
          jnz  elseNeg          ; skip if set (value negative)
          mov al,' '            ; blank for positive
          stosb                 ; write the blank to the string
          jmp  NotNeg           ; jump over negative sign
elseNeg:  mov al,'-'            ; minus for negative
          stosb                 ; write the minus to the string
          fchs                  ; convert number to positive
NotNeg:
          mov  exponent, 0      ; exponent := 0
          ftst                  ; value = 0?
          fstsw ax              ; status word to AX
          and  ax, C3           ; check C3
          jne  endifZero        ; skip if zero
          fcom ten              ; value > 10?
          fstsw ax              ; status word to AX
          and  ax, C3 or C2 or C0   ; check for all C3=C2=C0=0
          jnz  elseLess         ; skip if value not > 10
untilLess:
          inc  exponent         ; add 1 to exponent
          fdiv ten              ; value := value/10
          fcom ten              ; value < 10
          fstsw ax              ; status word to AX
          and  ax, C0           ; check C0
          jz  untilLess         ; continue until value < 10
          jmp  endifBigger      ; exit if
elseLess:
whileLess:
          fcom one              ; value < 1
          fstsw ax              ; status word to AX
          and  ax, C0           ; check C0
          jz   endwhileLess     ; exit if not less
          fmul ten              ; value := 10*value
          dec  exponent         ; subtract 1 from exponent
          jmp  whileLess        ; continue while value < 1
endwhileLess:
endifBigger:
endifZero:
          fadd round            ; add rounding value
          fcom ten              ; value > 10?
          fstsw ax              ; status word to AX
          and  ax, C3 or C2 or C0  ; C3=C2=C0=0? (value > 10?)
          jnz  endifOver        ; skip if not
          fdiv ten              ; value := value/10
          inc  exponent         ; add 1 to exponent
endifOver:
                                ; at this point 1.0 <= value < 10.0
          fist digit            ; store integer part
          mov  bx, digit        ; copy integer to BX
          or   bx, 30h          ; convert digit to character
          mov al,bl             ; copy character to AL for writing
          stosb                 ; write the character to the string
          mov al,'.'            ; load AL with decimal point
          stosb                 ; write decimal point to string

          mov ecx,5             ; count of remaining digits
forDigit: fisub digit           ; subtract integer part
          fmul ten              ; multiply by 10
          fist digit            ; store integer part
          mov  bx, digit        ; copy integer to BX
          or   bx, 30h          ; convert digit to character
          mov al,bl             ; copy character to write
          stosb                 ; write the character to the string
          loop forDigit         ; repeat 5 times
          mov al,'E'            ; exponent indicator
          stosb                 ; write the character to the string
          mov  ax, exponent     ; get exponent
          push ax               ; save the exponenet
          cmp  ax, 0            ; exponent >= 0 ?
          jnge NegExp
          mov al,'+'            ; non-negative exponent
          stosb                 ; write the character to the string
          pop ax                ; restore the exponent if not negative
          jmp  endifNegExp
NegExp:   mov al,'-'            ; negative exponent
          stosb                 ; write the character to the string
          pop ax                ; restore the exponent if negative
          neg ax                ; change exponent to positive
endifNegExp:
          div  byteTen          ; convert exponent to 2 digits
          or   ax, 3030h        ; convert both digits to ASCII
          stosb                 ; write AL character to the string
          mov al,ah             ; copy low order character to DL
          stosb                 ; write the character to the string
          xor al,al             ; zero the AL register
          stosb                 ; write NULL to terminate string
          pop  controlWd        ; restore control word
          fldcw controlWd       ; load the control word back to FPU
          popfd                 ;Restore the registers
          popad                 ;
          ret
fp2a  ENDP

Public _main
END                                     ;Code segment ends
hurtshifter wrote:These were parts of your final project your say? When does your semester end? Ours goes until December 22nd (pending on when your finals are that week).
Yeah, we have Thanksgiving break next week, then finals after that. I believe our last day is something like December 4th. I'm excited as hell. Plan for lots of new Youtube videos.
User avatar
Vincent
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 6
Joined: Fri Apr 26, 2013 1:32 am
Current Project: Learning C++, Java, and OO
Favorite Gaming Platforms: PC, Famicom and PS2
Programming Language of Choice: C++, Java
Location: Spain

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

Post by Vincent »

I really like the way you code Falco, you're like the cleanest coder I know so far in my early coder life. Keep it up man. I'm learning a lot from this forum. ;D
"Stop bitchin' and start codin' !!!" by myself
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

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

Post by Falco Girgis »

Vincent wrote:I really like the way you code Falco, you're like the cleanest coder I know so far in my early coder life. Keep it up man. I'm learning a lot from this forum. ;D
lol, thanks. Looking back at these programs, I definitely think I write even cleaner code today... especially cleaner assembly.
Post Reply