/* Clemson University -- CPSC 231 -- Fall 2001 * example program 1 * * test of a routine to determine the length of a string * * macro processing and assembly commands: * m4 ex1.s * gcc ex1.s * a.out * * you should see: * string length is 0 bytes (not including terminating 0) * * string length is 1 bytes (not including terminating 0) * This is a test. * string length is 16 bytes (not including terminating 0) * Hello, world! * string length is 14 bytes (not including terminating 0) * abcdefghijklmnopqrstuvwxyz 0123456789 .,;: +-* /_=()&%$#[] * string length is 60 bytes (not including terminating 0) * * note: because of printf, %% in the last string prints as one % * thus the string has 58 printed characters + extra % + newline = 60 * * this program illustrates: * 1) use of a pointer to access bytes in memory (i.e., dereferencing a * pointer) * 2) traversing a string until its end, i.e., loop until null byte found * ptr = start; while( *ptr != 0 ){ ...; } * 3) use of the printf subroutine * 4) use of m4 * 5) writing a test driver * * * e.g., consider a string "abc..." in memory starting at address 0x00001000, * that address will be passed to the subroutine in %o0, which becomes * %i0 after the save instruction, and that address is moved to the * %ptr_r register by the second instruction of the subroutine, %len_r * is then cleared (i.e., set to zero) * * as the subroutine enters the loop * * registers address memory * +----------+ ... * |0x00001000| %ptr_r ----> 0x00001000| 0x61 | = binary 01100001 = 'a' * +----------+ 0x00001001| 0x62 | = binary 01100010 = 'b' * | ?| %byte_r 0x00001002| 0x63 | = binary 01100011 = 'c' * +----------+ ... * | 0| %len_r * +----------+ * * after ldub [%ptr_r], %byte_r * * registers memory * +----------+ ... * |0x00001000| %ptr_r ----> 0x00001000| 0x61 | * +----------+ 0x00001001| 0x62 | * |0x00000061| %byte_r 0x00001002| 0x63 | * +----------+ ... * | 0| %len_r * +----------+ * * at the bottom of the loop - after the cmp, after falling through the beq * branch (since %byte_r is not 0), and after the two increment instructions * * registers memory * +----------+ ... * |0x00001001| %ptr_r -. 0x00001000| 0x61 | * +----------+ `-> 0x00001001| 0x62 | <--(ready to read 'b' next * |0x00000061| %byte_r 0x00001002| 0x63 | time through the loop) * +----------+ ... * | 1| %len_r * +----------+ * * at the bottom of the loop after the second iteration * * registers memory * +----------+ ... * |0x00001002| %ptr_r -. 0x00001000| 0x61 | * +----------+ \ 0x00001001| 0x62 | * |0x00000062| %byte_r `> 0x00001002| 0x63 | <--(ready to read 'c' next * +----------+ ... time through the loop) * | 2| %len_r * +----------+ * * etc., until the null byte ('\0' = binary 0) is reached that signals the * end of the string */ /* string length routine * * input parameter: * %i0 (%o0 in caller) - address of string * (assumption: string ends in null byte) * * return value: * %i0 (%o0 in caller) - string length * * other output parameters: * none * * effect/output * none apart from return value * * typical calling sequence * set str,%o0 * call length * nop * * local register usage: * %ptr_r - %l0 - string pointer, initialized to input value * %byte_r - %l1 - holds byte at current string pointer * %len_r - %l2 - current length */ define(`ptr_r', l0) define(`byte_r', l1) define(`len_r', l2) .global length length: save %sp, -96, %sp mov %i0, %ptr_r ! copy starting address clr %len_r ! length starts at 0 loop: ldub [%ptr_r], %byte_r ! load next byte (unsigned) cmp %byte_r, 0 ! exit when zero byte reached beq done nop inc %ptr_r ! increment string pointer inc %len_r ! increment length ba loop nop done: mov %len_r,%i0 ! copy length to return value ret restore /* test driver for string length */ define(TEST_STRING,`! print the string before the call to length set $1,%o0 call printf nop ! printf should not change %o0, but reset just to be sure set $1,%o0 call length nop ! print the result mov %o0,%o1 set cnt_fmt,%o0 call printf nop')dnl .global main main: save %sp, -96, %sp TEST_STRING(str0) TEST_STRING(str1) TEST_STRING(str2) TEST_STRING(str3) TEST_STRING(str4) ret restore .section ".data" str0: .byte 0 str1: .asciz "\n" str2: .asciz "This is a test.\n" str3: .asciz "Hello, world!\n" str4: .asciz "abcdefghijklmnopqrstuvwxyz 0123456789 .,;: +-* /_=()&%%$#[]\n" cnt_fmt:.asciz "string length is %d bytes (not including terminating 0)\n" ------------------------------------------------------------------------------ /* Clemson University -- CPSC 231 -- Fall 2001 * example program 2 * * test of a routine to capitalize all letters in a string whose address is * passed via register %o0 * * macro processing and assembly commands: * m4 ex2.s * gcc ex2.s * a.out * * you should see: * Hello, world! * HELLO, WORLD! * This is a test of the capitalization subroutine. * THIS IS A TEST OF THE CAPITALIZATION SUBROUTINE. * What happens to punctuation? and numbers like 42? * WHAT HAPPENS TO PUNCTUATION? AND NUMBERS LIKE 42? * abcdefghijklmnopqrstuvwxyz 0123456789 .,;: +-* /_=()&%$#[] * ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 .,;: +-* /_=()&%$#[] * * note: because of printf, %% in the last string prints as one % * * this program illustrates: * 1) use of a pointer to access bytes in memory (i.e., dereferencing a * pointer) * 2) traversing a string until its end, i.e., loop until null byte found * ptr = start; while( *ptr != 0 ){ ...; } * 3) use of compound condition (i.e., range test) in a conditional structure * 4) use of the printf subroutine * 5) ASCII encoding of characters * 6) use of m4 with a macro expansion count and labels * 7) writing a test driver */ /* capitalization routine * * input parameter: * %i0 (%o0 in caller) - address of string * (assumption: string ends in a null byte) * * return value and other output parameters: * none * * effect/output: * characters within string are changed * * typical calling sequence: * set str,%o0 * call capital * nop * * local register usage: * %ptr_r - %l0 - string pointer, initialized to input value * %byte_r - %l1 - holds byte at current string pointer */ define(`ptr_r', l0) define(`byte_r', l1) .global capital capital: save %sp, -96, %sp mov %i0, %ptr_r ! copy starting address loop: ldub [%ptr_r], %byte_r ! load next byte (unsigned) cmp %byte_r, 0 ! exit when zero byte reached beq done nop cmp %byte_r, 'a' ! cmp to lower limit 0x61 = 97 = 'a' blt next ! lower case letter will be >= 'a' nop cmp %byte_r, 'z' ! cmp to upper limit 0x7a = 122 = 'z' bgt next ! lower case letter will be <= 'z' nop sub %byte_r, 0x20, %byte_r ! change lower case letter to upper case stb %byte_r, [%ptr_r] ! store back to string (update in place) next: inc %ptr_r ! increment string pointer ba loop nop done: ret restore /* test driver for capital subroutine */ define(MACRO_EXP_CNT,1)dnl define(CAPITAL,` ! expansion MACRO_EXP_CNT of `CAPITAL' macro, parameter is $1 set $1,%l0 mov %l0,%o0 call printf nop mov %l0,%o0 call capital nop cmp %l0,%o0 beq `next'MACRO_EXP_CNT nop mov %o0,%o1 set errfmt,%o0 call printf nop `next'MACRO_EXP_CNT: mov %l0,%o0 call printf nop define(`MACRO_EXP_CNT',eval(MACRO_EXP_CNT+1))dnl ')dnl .global main main: save %sp, -96, %sp CAPITAL(str1) CAPITAL(str2) CAPITAL(str3) CAPITAL(str4) CAPITAL(str5) ret restore .section ".data" str1: .byte 0 str2: .asciz "Hello, world!\n" str3: .asciz "This is a test of the capitalization subroutine.\n" str4: .asciz "What happens to punctuation? and numbers like 42?\n" str5: .asciz "abcdefghijklmnopqrstuvwxyz 0123456789 .,;: +-* /_=()&%%$#[]\n" errfmt: .asciz "--- capital returns with different value (=%x) in %o0 ---\n"