ECE/CS 314 Fall 2003 Homework 2 Solutions Question 1 /* Equivalent C code with no loops (goto instead) char* strchr(char* pcstring, char csearchchr) strchr_loop: if (!*pcstring) return 0; if (*pcstring == csearchchr) return pcstring; pcstring++; goto strchr_loop; /* Assembly of strchr Note: leaf function Also, s used very conservatively strchr: 5 points if they remember to check first condition that if the input string is NULL, the function must return NULL lbu $8, 0($4) load the first character of pcstring bne $8, $0, $L2 branch if not null move $2, $0 null, so set return value to 0 jr $31 and return delay branch $L2: 10 points if they remember to check end condition bne $8, $5, $L3 If they are equal, we found it move $2, $4 set $2 to $4 and return jr $31 $L3: 10 points if they remember to increment addu $2,$4,1 we want to increment $4 move $4,$2 j strchr
Question 2 /* Equivalent C code with no loops (goto instead) int strccnt(char* pcstring, char csearchchr) int ncounter = 0; strcnnt_loop: pcstring = strchr(pcstring, csearchchr); if (pcstring) ncounter++; pcstring++; goto strcnnt_loop; return ncounter; /* Assembly of strccnt Notes: Use of fp is optional. In fact,the following code uses fp trivially. Do not take points off is fp is not used but the code is otherwise functional Also, s used very conservatively strccnt: Setting up stack frame and initializing variable - 5 points 2 points for allocating space (32 for fp version, 24 for non fp) 2 points for saving ra 1 point for initialize counter to 0 subu $sp,$sp,32 allocate space 32 because: 4 for ra 4 for old fp 4 for var ncounter 16 for additional args double word aligh sw $31, 28($sp) save ra sw $fp, 24($sp) save old fp move $fp, $sp move current sp into fp
$L6: $L7: sw $0, 20($fp) set counter to 0 Calling strchr - 8 points 2 points for allocating space and restoring space on stack 3 points for for saving and restoring register 3 points for the branch test subu $sp, $sp, 16 allocate space to save arguments sw $4, 0($sp) save A0 and A1 sw $5, 4($sp) jal strchr lw $4, 0($sp) Restore A0 and A1 lw $5, 4($sp) addu $sp, $sp, 16 restore stack beq $2, $0, $L7 If strchr returns 0, jump to label which sets return value from counter and returns Incrementing variables - 8 points 2 points for loading counter 2 points for incrementing counter 2 points for restoring counter 2 points for incrementing pcstring lw $3, 20($fp) load counter into $3 addu $3, $3, 1 add 1 to counter sw $3, 20($fp) and store it back into mem addu $4, $2, 1 increment pcstring, and store it into $4 (A0) j $L6 goto L6 to restart loop Restoring stack 4 points 2 points for restoring stack 2 points for restoring ra lw $2,16($fp) Set return value to counter move $sp,$fp sp not trusted here lw $31,28($sp) restore ra lw $fp,24($sp) restore old fp addu $sp,$sp,32 restore stack jr $31 exit
Question 3 int timesten(int ninvalue) /* Multiple by 8 (shift by 3) + Multiple by 2 (shift by 2) return ((ninvalue << 3) + ( ninvalue << 1)); Assume initial param value in $4 The question doesn't specify that it is a function, so just a sequence of 3 instructions is fine 20 points if shift used but used incorrectly 15 points if some type of loop is used sll $2, $4, 3 $2 has the value to be multiplied sll $1, $4, 1 $1 is $at addu $2, $2, $1 Alternate solution for Question 3: ninvalue = (ninvalue << 2 + ninvalue) << 1; sll $2,$4,2 ninvalue = ninvalue * 4 + ninvalue add $1,$2,$4 sll $2,$1,1 ninvalue * 2 Question 4 /* C version of atoi with no loops (using gotos) Note: Horner's rule example 123 = (((1 * 10) + 2) * 10) + 3 ASCII numbers from 0 to 9 are 48 to 57 int atoi(char* pcstring)
int nreturnvalue = 0; atoi_loop: if (*pcstring >= 48 && *pcstring <= 57) nreturnvalue = nreturnvalue * 10 + *pcstring - 48; pcstring++; goto atoi_loop; else if (*pcstring!= 0) return -1; return nreturnvalue; /* Assembly version of atoi Note, leaf function with data atoi: 2 points for allocating space on stack subu $sp,$sp,8 sw $0,4($sp) nreturnvalue = 0 $L2: 10 points for implementing horners rule although other creative solution might be okay as well, use discretion. Note that multiple can be used instead of the shift and add solution. 5 points to recognize ASCII range of 0 to 9 lbu $8, 0($4) Load first character of string sltu $2, $8, 48 Test if it is less than 48 bne $2, $0, $L3 If it is, go to else if sltu $2, $8, 58 Test if it is less than 58 beq $2, $0, $L3 If false, go to else if lw $2, 4($sp) Load nreturnvalue sll $3, $2, 2 nreturnvalue = nreturnvalue * 4 + nreturnvalue addu $3, $3, $2 sll $2, $3, 1 nreturnvalue = nreturnvalue * 2 addu $2, $2, $8 nreturnvalue = nreturnvalue + *pcstring addu $3, $2, -48 nreturnvalue = nreturnvalue - 48 sw $3, 4($sp) Store back into memory
$L3: $L5: $L1: addu $4, $4, 1 pcstring++ j $L2 Loop back and test again 3 points for checking NULL end case beq $8, $0, $L5 If *pcstring is 0, we've hit the NULL, and we can return the value 3 points for checking the invalid case li $2, -1 Load -1 into return value as j $L1 we have hit the invalid case lw $2, 4($sp) Load nreturnvalue into return register j $L1 2 points for restoring stack addu $sp, $sp, 8 Restore stack jr $31 Return