################################################################################ ## ## LSU EE 4720 Fall 2003 Homework 2 Solution ## ## .data name: .asciiz "David Koppelman" # Put your name between the quotes. ################################################################################ ## Main Routine and Problem 2 Solution # This routine runs the test code for the first problem. It also makes # sure you put your name at the top of the file. It does not have to # be modified, but it can be if it would help. For example, you might # comment out a test for one of the problems when working on the # other. # The comments below are part of the solution to Problem 2. .data who_are_you: .asciiz "Please put your name in the top of the file where indicated." test_data: .asciiz "-4" .word -4 .asciiz "123 " .word 123 .asciiz " 3224834 " .word 3224834 .asciiz " - 7912 " .word -7912 .asciiz "X" msg: .asciiz "The value of string %/s4/s returned was %/t1/d (%/t2/s).\n" textc: .asciiz "Correct" textw: .asciiz "Wrong" msgt: .asciiz "A total of %/s2/d correct and %/s3/d wrong."; .text .globl __start __start: # # Check if name entered above. # la $s0, name # Load address of name. lb $s0, ($s0) # Load first character. bne $s0, $0 TESTS # If it's not null, jump to tests. # The pseudo instruction below (la) is in the delay slot of a # branch. This particular pseudo instruction may expand into # two machine instructions. If so, only one of them will # execute when the branch is taken. The [sic] comment is # indicating that this was done intentionally, if the branch # is taken only half of the pseudo instruction executes but # that's okay because the instruction is not needed anyway. # ([sic] means "that's not a mistake" or sometimes "that's not my mistake", # it is often used to indicate that something unusual is not a typo.) la $a0, who_are_you # [sic] <- Explain this comment. # Line above: Load format string for "missing name" message. addi $v0, $0, 11 # Choose system call 11 (printf) syscall # Print name missing error message. addi $v0, $v0, 10 # Choose system call 10 (exit) syscall # Exit # # Initialize values used in main loop. # TESTS: la $s0, test_data # Address of beginning of test data. addi $s7, $0, -4 # Prepare a mask (0xfffffffc), used for alignment. or $s2, $0, $0 # Initialize count of correct conversions to zero. andi $s3, $s3, 0 # Initialize count of incorrect conversions to zero. # # Main Loop: # # Load first character of string to convert from data table... # ...check if at end of data table... # ...if not, call atoi... # ...load value of string from data table... # ...compare with atoi return value and update correct/incorrect counters... # ...continue loop. # TLOOP: lbu $t0, 0($s0) # Load first character of string to convert. addi $t0, $t0, -88 # Check if it's "X", indicating no more tests. beq $t0, $0, TDONE # If no more tests, exit loop. xor $a0, $s0, $0 # Copy address of string to $a0, for called routine. jal atoi # Call conversion routine. add $s4, $s0, $0 # Make another copy of address of string. TEOS: lbu $t0, 0($s0) # Load character from string ... bne $t0, $0, TEOS # ...and exit if end of string found. addi $s0, $s0, 1 # Advance to maybe next character of string. addi $s0, $s0, 3 # Make data pointer a multiple of 4 by adding 3 ... and $s0, $s0, $s7 # ... and then masking with 0xfffffffc. lw $t1, 0($s0) # Load integer value of string (from aligned addr). bne $t1, $v0, TWRONG # If value returned by atoi is different, error. addi $s0, $s0, 4 # Point to next string to convert. la $t2, textc # Load address of "correct" text. j TMSG # Jump to routine printing outcome message. addi $s2, $s2, 1 # Increment correct counter. TWRONG: la $t2, textw # Load address of "wrong" text. addi $s3, $s3, 1 # Increment wrong counter. TMSG: or $t1, $v0, $v0 # Copy return value of atoi. ($v0 needed for syscall) addi $v0, $0, 11 # Choose printf syscall. la $a0, msg # Load address of outcome format string for printf. syscall # Print outcome. j TLOOP # Try to load another string to convert. nop TDONE: addi $v0, $0, 11 # Choose printf syscall. la $a0, msgt # Load address of results summary format string. syscall # Print results summary. addi $v0, $0, 10 # Choose exit syscall. syscall # Bye. ################################################################################ ## Problem 1 Solution Shell # When the routine below is called register $a0 has the address of a # null-terminated string, that string is an integer (in ASCII), for # example, "1", " 23423", " - 71 ". Note that the integer may be # negative and that there may be spaces before and after the minus # sign and digits. Assume that there are no spaces between digits and # that only digits, a minus sign, and spaces are in the string. # # The routine should place the integer value of that string in # register $v0, and then return. Make sure you understand the # difference between an ASCII string representation of an integer (the # call argument) and a 32-bit two's complement representation (the # return value). # # When your write your code follow the additional guidelines below. # If the register use guidelines are not followed the test code might # not work. The guidelines on speed and multiplication will be taken # into account when grading. atoi: ## Register Usage # # $a0: Procedure argument: pointer to string. # $v0: Return value: integer corresponding to string. # [x] Assume that multiplication takes 7 cycles. # [x] Code should run quickly, avoid multiplication if that helps. # Used two shifts and an add to avoid multiplication. # [x] Can modify registers $a0-$a3, $t0-$t9 and $v0 only. # [x] Do not modify $s0-$s7, $sp, $fp, or $ra # [x] Fill as many delay slots as possible. # Insert solution here. addi $t9, $0, 32 # Blank addi $t8, $0, 45 # - addi $t7, $0, 0 # If non-zero, sign bit present. addi $v0, $0, 0 # First, skip whitespace. PREDIGIT: lbu $t0, 0($a0) # Load character. beq $t0, $0, EXIT # If end of string, return. addi $a0, $a0, 1 # Increment address. beq $t0, $t9, PREDIGIT # If blank, continue loop. nop beq $t0, $t8, MINUS # If minus, go to code setting minus flag ... nop # ... else assume a digit and fall through. # At beginning of loop $t0 holds a digit. DIGITLOOP: addi $t0, $t0, -48 # Convert digit from ASCII to an integer. sll $t1, $v0, 3 # Multiply value of string (so far)... sll $t2, $v0, 1 # ...by 10 using two shifts and an add. add $v0, $t1, $t2 add $v0, $v0, $t0 # Add digit on to value of string. lbu $t0, 0($a0) # Load the next character ... beq $t0, $t9, EXIT # ... if it's blank, exit loop ... nop bne $t0, $0, DIGITLOOP # ... if it's not null, continue loop. addi $a0, $a0, 1 # Advance to next character. EXIT: beq $t7, $0, RETURN # If minus sign not found, go to return code. nop sub $v0, $0, $v0 # Otherwise, negate value. RETURN: jr $ra # Do not comment lines like this "return" unless # the code is part of a lesson on return statements. nop MINUS: j PREDIGIT # Remember that a minus sign was encountered. addi $t7, $0, 1