120 lines
3.8 KiB
C

/*!
* @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 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}
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.
}