Falco's MSP430 (and now x86) Assembly Programs
Moderator: Coders of Rage
- dandymcgee
- 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
Jesus Falco. *gives pat on the back*
And I thought moving the number 5 from the ax register to the bx register was badass...
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!
Re: Falco's MSP430 (and now x86) Assembly Programs
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/
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"
Dad, "Yea well I have a fan belt in street fighting"
- Falco Girgis
- 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
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
Re: Falco's MSP430 (and now x86) Assembly Programs
Counting NOPs would be simpler :D Strange method.
- Falco Girgis
- 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
Counting NOPs in C?K-Bal wrote:Counting NOPs would be simpler :D Strange method.
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.
Re: Falco's MSP430 (and now x86) Assembly Programs
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
- Falco Girgis
- 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
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.
And a sample run (annoying spacing compliments of MSWord)
...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
]
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 . . .
- Falco Girgis
- 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
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:
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:
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
}
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
}
- hurstshifter
- 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
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).
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
http://www.thenerdnight.com
- Falco Girgis
- 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
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
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.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).
- Vincent
- 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
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
- Falco Girgis
- 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
lol, thanks. Looking back at these programs, I definitely think I write even cleaner code today... especially cleaner assembly.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