################################################################################
##
## 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