|
- /*!
- * @file
- * main.c
- * @brief
- * A palindrome implementation and testing application
- * for A.U.TH. Microprocessors and peripherals Lab.
- *
- * Created on: May 1, 2020
- * Author: Christos Choutouridis AEM: 8997
- * email : <cchoutou@ece.auth.gr>
- */
- #include <stdint.h>
-
- /*!
- * The RAM address to use for palindrome result.
- * @note:
- * Select a RAM location above `__initial_sp`. See your startup_xx.s for details.
- * Keil's RAM layout is:
- *
- * RAM: |<-Heap_Size-><-Stack_Size->|<- WASTED RAM SPACE ->|
- * ^ ^ ^
- * | | |
- * Start:0x20000000 __initial_sp End of RAM
- *
- */
- #define RESULT 0x20001000
-
-
- /*!
- * String length calculation.
- * @arg src{R0} Pointer to string
- * @return {R0} String length, -1 if src is NULL
- */
- __asm uint32_t strLength (const char* src) {
- // R0: length, return value
- // R1: src
- // R2: v = *src
- MOV R1, R0 // Get variable
- CMP R1, #0 // if (src{R1} == NULL)
- MOVEQ R0, #-1 // return -1;
- BXEQ LR
- MOV R0, #0 // length{R0} =0;
- len_loop // do {
- LDRB R2, [R1], #1 // v{R2} = *src++;
- CMP R2, #0 // if(v)
- ADDNE R0, R0, #1 // ++length{R0};
- BNE len_loop // } while (v);
- BX LR // return length;
- }
-
- /*!
- * A string palindrome predicate.
- * @note
- * We use a simple O(n), no stack algorithm.
- * @note
- * This function also writes to RAM address @ref RESULT the return value (which is nasty).
- * @arg src{R0} Pointer to string
- * @return {R0} True if palindrome, false if not or src is NULL pointer
- * @note
- * We consider an empty string "" to be a palindrome, as we can see it the same way both
- * from the front and the back.
- */
- __asm uint32_t isPalindrome (const char* src) {
- // R0: src[]
- // R1: i
- // R2: j
- // R3: v1 = src[i]
- // R4: v2 = src[j]
- PUSH {R4, LR}
- CMP R0, #0 // if (src{R0} == NULL)
- BEQ pal_false // return false;
- MOV R4, R0 // save R0
- BL strLength // j{R2} = strLength(src) - 1
- SUB R2, R0, #1
- MOV R0, R4 // src{R0}
- MOV R1, #0 // i{R1} =0;
-
- pal_loop
- CMP R1, R2 // while (i<j) {
- BGE pal_true
- LDRB R3, [R0, R1] // v1 = *src[i];
- LDRB R4, [R0, R2] // v2 = *src[j];
- CMP R3, R4 // if (v1 == v2) {
- ADDEQ R1, R1, #1 // ++i;
- SUBEQ R2, R2, #1 // --j;
- BEQ pal_loop // // goto loop;
- pal_false // } else
- MOV R0, #0 // return *RESULT = 0;
- LDR R1, =RESULT
- STRB R0, [R1]
- POP {R4, PC}
- // }
- pal_true
- MOV R0, #1 // return *RESULT = 1;
- LDR R1, =RESULT
- STRB R0, [R1]
- POP {R4, PC}
- }
-
- /*!
- * Main routine.
- * @note
- * This routine plays the role of debuging-mode unit testing.
- */
- int main(void) {
- const char *s1 = "hello world!"; // Not a palindrome
- const char *s2 = "aibohphobia"; // Aibophobia def= "Irational fear of palindromes", palindrome.
- const char *s3 = ""; // Empty string, palindrome.
- const char *s4 = 0; // NULL pointer. Out of scope, not palindrome
-
- uint32_t res1 = isPalindrome (s1); // Test case 1
- uint32_t res2 = isPalindrome (s2); // Test case 2
- uint32_t res3 = isPalindrome (s3); // Test case 3
- uint32_t res4 = isPalindrome (s4); // Test case 4
-
- while (1); // Trap forever
- //return 0; //!< comment out return, to suppress "statement is unreachable" warning.
- //!^ @note:
- //! **Weird** Keil's way for "statement is unreachable", suppresion.
-
- }
|