@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ Program part 0: initial declarations @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ .globl _start .equ RXFE, 0x10 .equ TXFF, 0x20 .equ OFFSET_FR, 0x018 .equ IO_ADDRESS, 0x101f1000 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ Program part 1: definition of main. @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @main program _start: mov sp,#0x100000 @ set up stack @ program preamble push {r0, r1, r2, r3, r4} @ program main body ldr r4,=IO_ADDRESS @ r4 := 0x 101f 1000 ldr r0, =input_buffer main_loop: bl get_line bl print_string bl newline @ quit if q found ldrb r1, [r0] cmp r1,#'q' ldreq r0,=string_quit bleq print_string beq program_exit @ else, repeat b main_loop program_exit: @ program wrap-up pop {r0, r1, r2, r3, r4} bl print_end the_end: b the_end @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ Program part 2: definition of functions @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ author: Brandon Lawrence @ @ div: computes result of integer division r0/r1 @ @ results: r0 = r0/r1 @ r1 = r0 mod r1 div: @preamble push {r2, r3, r4, r5, r6, r7, r8, lr} div_main: @r0 holds numerator @r1 holds denominator mov r4, #1 mov r5, #-1 cmp r1, #0 moveq r3, #0 beq div_exit mullt r6, r4, r5 movlt r4, r6 mullt r6, r1, r5 movlt r1, r6 cmp r0, #0 mullt r6, r4, r5 movlt r4, r6 mullt r6, r0, r5 movlt r0, r6 mov r7, r0 mov r8, r1 mov r3,#0 mov r2,r1 div_counter: @sets r2 to the largest multiple cmp r2,r0 @of 2 smaller than r0 lsrgt r2,r2,#1 bge div_loop lsl r2,r2,#1 b div_counter div_loop: cmp r2,r1 blt div_exit lsl r3,r3,#1 @r3 stores result cmp r0,r2 subge r0,r0,r2 addge r3,r3,#1 lsr r2,r2,#1 b div_loop div_exit: mul r0,r3,r4 mul r6, r3, r8 sub r1, r7, r6 @wrap-up pop {r2, r3, r4, r5, r6, r7, r8, lr} bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ r0 should be a buffer that can receive the data. @ The buffer should have size at least 1000 bytes. get_line: @preamble push {r0, r4, r5, r6, r7, lr} @ main body ldr r4, =IO_ADDRESS mov r5, r0 mov r6, #0 mov r7, #1000 get_line_loop: cmp r6, r7 beq get_line_exit bl get_char cmp r0, #'\r' beq get_line_exit str r0, [r4] strb r0, [r5, r6] add r6, r6, #1 b get_line_loop get_line_exit: bl newline mov r7, #0 strb r7, [r5, r6] @ wrap-up pop {r0, r4, r5, r6, r7, lr} bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ get_char: @preamble push {r2, r3, r4, lr} @ main body ldr r4,=IO_ADDRESS @ r4 := 0x 101f 1000 get_char_wait: ldr r2,[r4,#OFFSET_FR] @ load IO flag register to r2 and r3,r2,#RXFE @ mask non receive fifo empty bits cmp r3, #0 @ r3 == 0? bne get_char_wait @ wait until ready ldr r0,[r4] @ wrap-up pop {r2, r3, r4, lr} bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ print_end: @ preamble push {r1, r4, lr} @ main body ldr r4,=IO_ADDRESS @ r4 := 0x 101f 1000 mov r1, #13 str r1, [r4] mov r1, #10 str r1, [r4] mov r1, #'E' str r1, [r4] mov r1, #'N' str r1, [r4] mov r1, #'D' str r1, [r4] @ wrap-up pop {r1, r4, lr} bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ newline: @ preamble push {r2, r4, lr} @ main body ldr r4,=IO_ADDRESS @ r4 := 0x 101f 1000 mov r2, #'\n' str r2,[r4] mov r2, #'\r' str r2,[r4] @ wrap-up pop {r2, r4, lr} bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ r0 should be address of first character of string to display print_string: @preamble push {r0,r4,r5,lr} @ main body ldr r4,=IO_ADDRESS @ r0 := 0x 101f 1000 str_out: ldrb r5,[r0] cmp r5,#0x00 @ '\0' = 0x00: null character? beq str_done @ if yes, quit str r5,[r4] @ otherwise, write character add r0,r0,#1 @ go to next character b str_out @ repeat @ wrap-up str_done: pop {r0,r4,r5,lr} bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ div10: @ div10 preamble sub sp, sp, #36 str lr, [sp, #0] str r4, [sp, #4] str r5, [sp, #8] str r6, [sp, #12] str r7, [sp, #16] str r8, [sp, #20] str r9, [sp, #24] str r10, [sp, #28] str r11, [sp, #32] @ div10 main body mov r4, r0 @ r4 = arg lsr r5, r4, #4 @ r5: lower bound lsr r6, r4, #3 @ r6: upper bound mov r7, r6 @ r7: current guess, initialized to upper bound mov r9, #10 @ r9: constant 10. div10_loop: mul r8, r7, r9 @ r8 = current guess * 10 cmp r8, #0 @ check for overflow movlt r6, r7 @ if overflow, set upper bound = guess. blt div10_next_guess cmp r8, r4 mov r10, #0 movle r10, #1 @ r10 = (10 * current guess <= arg) mov r11, #0 add r8, r8, #9 @ r8 = 10 * current guess + 9 cmp r8, #0 @ check for overflow movlt r11, #1 @ if overflow, it means that @ (10 * current guess + 9 >= arg) blt div10_check cmp r8, r4 movge r11, #1 @ r11 = (10 * current guess + 9 >= arg) div10_check: add r11, r11, r10 @ r11 = 2 if (10*guess <= arg <= 10*guess + 9) cmp r11, #2 @ if r11 == 2, we are done moveq r0, r7 @ arg/10 is r7, store at r0 mul r8, r7, r9 @ r8 = current guess * 10 subeq r1, r4, r8 @ r1 = remainder of arg/10 beq div10_exit @ exit, we have computed the results cmp r8, r4 @ compare 10*guess with arg movgt r6, r7 @ if 10>guess > arg, set upper_bound = guess movlt r5, r7 @ else set lower bound = guess div10_next_guess: add r7, r5, r6 @ guess = (lower bound + upper bound) lsr r7, r7, #1 @ guess = (lower bound + upper bound) / 2 b div10_loop div10_exit: @ div10 wrap-up ldr lr, [sp, #0] ldr r4, [sp, #4] ldr r5, [sp, #8] ldr r6, [sp, #12] ldr r7, [sp, #16] ldr r8, [sp, #20] ldr r9, [sp, #24] ldr r10, [sp, #28] ldr r11, [sp, #32] add sp, sp, #36 bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ print10: @ print10 preamble sub sp, sp, #28 str lr, [sp, #0] str r0, [sp, #4] str r1, [sp, #8] str r4, [sp, #12] str r5, [sp, #16] str r6, [sp, #20] str r7, [sp, #24] @ print10 main body ldr r4,=0x101f1000 @ ASCII codes stored @ at [r4] get printed mov r5, r0 cmp r5, #0 movlt r6, #'-' strlt r6, [r4] movlt r7, #-1 mullt r0, r5, r7 bl print10_helper @ print newline mov r5, #13 str r5, [r4] mov r5, #10 str r5, [r4] @ print_number wrap-up ldr lr, [sp, #0] ldr r0, [sp, #4] ldr r1, [sp, #8] ldr r4, [sp, #12] ldr r5, [sp, #16] ldr r6, [sp, #20] ldr r7, [sp, #24] add sp, sp, #28 bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ print10_helper: @ print10_helper preamble sub sp, sp, #28 str lr, [sp, #0] str r0, [sp, #4] str r1, [sp, #8] str r4, [sp, #12] str r5, [sp, #16] str r6, [sp, #20] str r7, [sp, #24] @ print10_helper main body ldr r4,=0x101f1000 @ ASCII codes stored @ at [r4] get printed cmp r0, #10 addlt r6, r0, #'0' strlt r6, [r4] blt print10_helper_exit bl div10 bl print10_helper add r6, r1, #'0' str r6, [r4] print10_helper_exit: @ print10_helper wrap-up ldr lr, [sp, #0] ldr r0, [sp, #4] ldr r1, [sp, #8] ldr r4, [sp, #12] ldr r5, [sp, #16] ldr r6, [sp, #20] ldr r7, [sp, #24] add sp, sp, #28 bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ print_digit: @ print_digit preamble sub sp, sp, #12 str lr, [sp, #0] str r4, [sp, #4] str r5, [sp, #8] @ print_digit main body ldr r4,=0x101f1000 @ ASCII codes stored @ at [r4] get printed cmp r0, #10 addlt r5, r0, #48 addge r5, r0, #55 str r5, [r4] @ print_digit wrap-up ldr lr, [sp, #0] ldr r4, [sp, #4] ldr r5, [sp, #8] add sp, sp, #12 bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ print_number: @ print_number preamble sub sp, sp, #24 str lr, [sp, #0] str r0, [sp, #4] str r4, [sp, #8] str r5, [sp, #12] str r6, [sp, #16] str r7, [sp, #20] @ print_number main body ldr r4,=0x101f1000 @ ASCII codes stored @ at [r4] get printed mov r5, #28 mov r6, r0 print_number_loop: cmp r5, #0 blt print_number_exit lsr r7, r6, r5 and r7, r7, #0x0000000f mov r0, r7 bl print_digit sub r5, r5, #4 b print_number_loop print_number_exit: @ print newline mov r5, #13 str r5, [r4] mov r5, #10 str r5, [r4] @ print_number wrap-up ldr lr, [sp, #0] ldr r0, [sp, #4] ldr r4, [sp, #8] ldr r5, [sp, #12] ldr r6, [sp, #16] ldr r7, [sp, #20] add sp, sp, #24 bx lr @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ Program part 3: data @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ string_start: .asciz "Starting echo program\n\r" input_buffer: .space 1005 input_buffer2: .space 1005 string_quit: .ascii "exiting echo program\n\r" .word 0x00