|
|
@@ -0,0 +1,108 @@ |
|
|
|
/*! |
|
|
|
* @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 R0: Pointer to string |
|
|
|
* @return R0: String length (unsigned) |
|
|
|
*/ |
|
|
|
__asm uint32_t strLength (const char* src) { |
|
|
|
// R0: length, return value |
|
|
|
// R1: src |
|
|
|
// R2: v = *src |
|
|
|
MOV R1, R0 // Get variable |
|
|
|
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 R0: Pointer to string |
|
|
|
* @return R0: True if predicate |
|
|
|
* False if not |
|
|
|
*/ |
|
|
|
__asm uint32_t isPalindrome (const char* src) { |
|
|
|
// R0: src[] |
|
|
|
// R1: i |
|
|
|
// R2: j |
|
|
|
// R3: v1 = src[i] |
|
|
|
// R4: v2 = src[j] |
|
|
|
PUSH {R4, LR} |
|
|
|
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; |
|
|
|
// } 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 |
|
|
|
*/ |
|
|
|
int main(void) { |
|
|
|
const char *s1 = "hello world!"; // Not a palindrome |
|
|
|
const char *s2 = "aibohphobia"; // Aibophobia def= "Fear of palindromes", palindrome. |
|
|
|
|
|
|
|
uint32_t res1 = isPalindrome (s1); // Test case 1 |
|
|
|
uint32_t res2 = isPalindrome (s2); // Test case 2 |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
} |