201 lines
3.5 KiB
ArmAsm
201 lines
3.5 KiB
ArmAsm
|
// Convention:
|
||
|
// R0 / R1 is method input. Should not be clobbered unless specified otherwise
|
||
|
// R2 - R5 + R8 - R10 is general purpose.
|
||
|
// R6 is the result
|
||
|
|
||
|
// Please note that this will clobber the R6 register.
|
||
|
// To make cpulator ignore this, turn off "Function clobbered caller-saved register" in settings.
|
||
|
|
||
|
.global _start
|
||
|
|
||
|
.section .data // RW Memory
|
||
|
// This is the input you are supposed to check for a palindrome
|
||
|
// You can modify the string during development, however you
|
||
|
// are not allowed to change the label 'input'!
|
||
|
input: .asciz "level"
|
||
|
// input: .asciz "8448"
|
||
|
// input: .asciz "KayAk"
|
||
|
// input: .asciz "step on no pets"
|
||
|
// input: .asciz "Never odd or even"
|
||
|
.align
|
||
|
|
||
|
.text // RO Memory
|
||
|
notAPalindrome: .asciz "Not a palindrome"
|
||
|
palindromeDetected: .asciz "Palindrome detected"
|
||
|
.align
|
||
|
|
||
|
// ------
|
||
|
|
||
|
LED_BASE = 0xff200000
|
||
|
UART_BASE = 0xff201000
|
||
|
|
||
|
// ------
|
||
|
|
||
|
// Returns a pointer to the end of the string
|
||
|
findStringEnd:
|
||
|
MOV R6, R0
|
||
|
MOV R0, R0
|
||
|
|
||
|
fse_loop:
|
||
|
LDRB R5, [R6]
|
||
|
CMP R5, #0x0
|
||
|
BXEQ LR
|
||
|
ADD R6, R6, #1
|
||
|
B fse_loop
|
||
|
|
||
|
// Checks whether the character is valid. Returns 0 or 1
|
||
|
isValidCharacter:
|
||
|
CMP R0, #'A'
|
||
|
BLT ivc_subrange2
|
||
|
CMP R0, #'Z'
|
||
|
BLE ivc_validChar
|
||
|
|
||
|
ivc_subrange2:
|
||
|
CMP R0, #'a'
|
||
|
BLT ivc_subrange3
|
||
|
CMP R0, #'z'
|
||
|
BLE ivc_validChar
|
||
|
|
||
|
ivc_subrange3:
|
||
|
CMP R0, #'0'
|
||
|
BLT ivc_invalidChar
|
||
|
CMP R0, #'9'
|
||
|
BLE ivc_validChar
|
||
|
|
||
|
ivc_invalidChar:
|
||
|
MOV R6, #0
|
||
|
BX LR
|
||
|
|
||
|
ivc_validChar:
|
||
|
MOV R6, #1
|
||
|
BX LR
|
||
|
|
||
|
// Makes the letter lowercase if possible
|
||
|
lowercaseCharacter:
|
||
|
MOV R6, R0
|
||
|
CMP R6, #'A'
|
||
|
BXLT LR
|
||
|
CMP R6, #'Z'
|
||
|
BXGT LR
|
||
|
|
||
|
ADD R6, #0x20
|
||
|
BX LR
|
||
|
|
||
|
isPalindrome:
|
||
|
// R0 is string start
|
||
|
// R1 is string length
|
||
|
PUSH {R0, R1}
|
||
|
|
||
|
// R2 is string pointer moving from start
|
||
|
// R3 is string pointer moving from end
|
||
|
MOV R2, R0
|
||
|
MOV R3, R1
|
||
|
|
||
|
// R8 stores valid lowercased start character for later comparison
|
||
|
// R9 stores valid lowercased end character for later comparison
|
||
|
ip_loop:
|
||
|
CMP R2, R3
|
||
|
BGT ip_returnTrue
|
||
|
|
||
|
// Loop until start char is valid,
|
||
|
// lowercase the letter, and save result in R8
|
||
|
LDRB R0, [R2]
|
||
|
BL isValidCharacter
|
||
|
CMP R6, #1
|
||
|
ADDNE R2, R2, #1
|
||
|
BNE ip_loop
|
||
|
BL lowercaseCharacter
|
||
|
MOV R8, R6
|
||
|
|
||
|
// Same for end char, save in R9
|
||
|
LDRB R0, [R3]
|
||
|
BL isValidCharacter
|
||
|
CMP R6, #1
|
||
|
SUBNE R3, R3, #1
|
||
|
BNE ip_loop
|
||
|
BL lowercaseCharacter
|
||
|
MOV R9, R6
|
||
|
|
||
|
// Compare, potentially return false
|
||
|
CMP R8, R9
|
||
|
BNE ip_returnFalse
|
||
|
|
||
|
// Move both pointers and loop
|
||
|
ADD R2, R2, #1
|
||
|
SUB R3, R3, #1
|
||
|
B ip_loop
|
||
|
|
||
|
ip_returnFalse:
|
||
|
POP {R0, R1}
|
||
|
MOV R6, #0
|
||
|
B evaluatePalindromeResult
|
||
|
|
||
|
ip_returnTrue:
|
||
|
POP {R0, R1}
|
||
|
MOV R6, #1
|
||
|
B evaluatePalindromeResult
|
||
|
|
||
|
_start:
|
||
|
BL resetLEDs
|
||
|
LDR R0, =input
|
||
|
BL findStringEnd
|
||
|
MOV R1, R6
|
||
|
|
||
|
// Palindromes can not be less that two chars
|
||
|
SUB R2, R1, R0
|
||
|
CMP R2, #2
|
||
|
BLT onNotPalindrome
|
||
|
|
||
|
B isPalindrome
|
||
|
|
||
|
evaluatePalindromeResult:
|
||
|
CMP R6, #1
|
||
|
BLEQ onPalindrome
|
||
|
BL onNotPalindrome
|
||
|
|
||
|
resetLEDs:
|
||
|
LDR R8, =LED_BASE
|
||
|
MOV R5, #0b0000000000
|
||
|
STR R5, [R8]
|
||
|
BX LR
|
||
|
|
||
|
onPalindrome:
|
||
|
// Light up LEDS
|
||
|
LDR R8, =LED_BASE
|
||
|
MOV R5, #0b0000011111
|
||
|
STR R5, [R8]
|
||
|
|
||
|
// Write to UART
|
||
|
LDR R8, =UART_BASE
|
||
|
LDR R9, =palindromeDetected
|
||
|
op_write_uart_loop:
|
||
|
LDRB R0, [R9]
|
||
|
CMP R0, #0x0
|
||
|
BEQ _end
|
||
|
STR R0, [R8]
|
||
|
ADD R9, R9, #1
|
||
|
B op_write_uart_loop
|
||
|
|
||
|
onNotPalindrome:
|
||
|
// Light up LEDS
|
||
|
LDR R8, =LED_BASE
|
||
|
MOV R5, #0b1111100000
|
||
|
STR R5, [R8]
|
||
|
|
||
|
// Write to UART
|
||
|
LDR R8, =UART_BASE
|
||
|
LDR R9, =notAPalindrome
|
||
|
onp_write_uart_loop:
|
||
|
LDRB R0, [R9]
|
||
|
CMP R0, #0x0
|
||
|
BEQ _end
|
||
|
STR R0, [R8]
|
||
|
ADD R9, R9, #1
|
||
|
B onp_write_uart_loop
|
||
|
|
||
|
_end:
|
||
|
B _end
|
||
|
|
||
|
.end
|
||
|
|