3

Im writing some MIPS code to take a string of ASCII digits and convert the string into an integer. The string is entered by the user and can be at most 10 digits in length. My code works fine and uses the obvious method of performing looped addition after multiplying the Least Significant number in the string by a power of ten determined by the index of the array, starting from the last digit entered (10^0) to the first digit entered (10^n, n=number of digits in the array).

I was wondering if there was an alternate method that would be quicker or shorter to write. In particular, I wanted to know if using a logical bit shift might make this process shorter. Any ideas for optimizing or improving this code would be greatly appreciated!

Also, as a side note, I would like to call the gets and readInt subroutines using jal, but because gets and readInt both call subroutines, using jal in the main method to call gets or readInt causes problems. Any ideas how to get around this? Thanks again Cheers

PS: sorry for the formatting of the comments in this code, copy and pasting from MARS simulator into the stack overflow text box caused the alignment to be off :/

#IO
#Prompts user to input 10 ascii digits into an array
#Converts the string of digits into a single int
#Also handles any number of digits between 1 and 10 
#Returns 0 if non-digit chars are entered into the string

.data           #declaration of vars follows
array: .space 11    #reserves space for a 10 elem array
char: .space 2
prompt: .asciiz "Please enter 10 numbers, then press ENTER:  \n"
null: .asciiz ""
space: .ascii " "
newline: .asciiz "\n"
.text           #instructions follow

main:
la $a0, prompt      #load prompt message into $a0 for syscall
li $v0, 4               #load syscall to print string
syscall         #print prompt message
j readInt               #call readInt function to get user input string         

gets:           #read multiple chars from keyboard buffer until ENTER key,
                            #add NULL char and store into buffer pointed to by *array
                            #passed to the subroutine
la $s1, array       #set base address of array to s1
loop:           #start of read loop
jal getc        #jump to getc subroutine
lb $t0, char        #load the char from char buffer into t0, stripping null
sb $t0, 0($s1)      #store the char into the nth elem of array
lb $t1, newline     #load newline char into t1
beq $t0, $t1, done  #end of string?  jump to done
addi $s1, $s1, 1    #increments base address of array
j loop          #jump to start of read loop

getc:           #read char from keyboard buffer and return ascii value
li $v0, 8       #call code for read string
la $a0, char        #load address of char for read
li $a1, 2       #length of string is 1byte char and 1byte for null
syscall         #store the char byte from input buffer into char
jr $ra          #jump-register to calling function

readInt:        #read string of ascii digits, store into a local variable and  
                    #convert into integer, return that int unless string contains 
                    #non-integers 
j gets          #let s1 be top address of array, let s0 be the digitcounter
done:           #let s2 be the sum total
addi $s1, $s1, -1   #reposition array pointer to last char before newline char
la $s0, array       #set base address of array to s0 for use as counter
addi $s0, $s0, -1   #reposition base array to read leftmost char in string
add $s2, $zero, $zero   #initialize sum to 0
li $t0, 10      #set t0 to be 10, used for decimal conversion
li $t3, 1
lb $t1, 0($s1)      #load char from array into t1
blt $t1, 48, error  #check if char is not a digit (ascii<'0')
bgt $t1, 57, error  #check if char is not a digit (ascii>'9')
addi $t1, $t1, -48  #converts t1's ascii value to dec value
add $s2, $s2, $t1   #add dec value of t1 to sumtotal
addi $s1, $s1, -1   #decrement array address
lp:         #loop for all digits preceeding the LSB
mul $t3, $t3, $t0   #multiply power by 10
beq $s1, $s0, FIN   #exit if beginning of string is reached
lb $t1, ($s1)       #load char from array into t1
blt $t1, 48, error  #check if char is not a digit (ascii<'0')
bgt $t1, 57, error  #check if char is not a digit (ascii>'9')
addi $t1, $t1, -48  #converts t1's ascii value to dec value
mul $t1, $t1, $t3   #t1*10^(counter)
add $s2, $s2, $t1   #sumtotal=sumtotal+t1
addi $s1, $s1, -1   #decrement array address
j lp            #jump to start of loop

error:          #if non digit chars are entered, readInt returns 0
add $s2, $zero, $zero
j FIN

FIN:
li $v0, 1
add $a0, $s2, $zero
syscall 
li $v0, 10      #ends program
syscall
4

3 回答 3

8

用和ing 字符串掩蔽前四位0x0F,如下所示

andi $t0,$t0,0x0F # where $t0 contains the ascii digit .

现在$t0有了它的int。

于 2013-08-10T17:03:32.190 回答
3

假设$s1指向以 NULL 结尾的字符串的开头(即最高有效位),$t0包含 10,并且$s2包含 0:

lp:         
  lbu $t1, ($s1)       #load unsigned char from array into t1
  beq $t1, $0, FIN     #NULL terminator found
  blt $t1, 48, error   #check if char is not a digit (ascii<'0')
  bgt $t1, 57, error   #check if char is not a digit (ascii>'9')
  addi $t1, $t1, -48   #converts t1's ascii value to dec value
  mul $s2, $s2, $t0    #sum *= 10
  add $s2, $s2, $t1    #sum += array[s1]-'0'
  addi $s1, $s1, 1     #increment array address
  j lp                 #jump to start of loop

每次迭代都会少一个mul,并且在进入循环之前不需要知道字符串的长度。

于 2013-04-11T06:35:39.507 回答
0

针对jal在嵌套调用中使用的问题,你可以在第一次进入第一个调用的时候保存寄存器from $ra(这个是调用时用来存放返回地址的寄存器);jal当您到达可以正常使用的 alst 呼叫时$ra

main:
    jal call1

call1:
    add $s0, $ra, 0
    ...
    jal call2
    ...
    jr $s0 # will be where $ra was when call 1 was implemented

call2:
    ...
    jr $ra

使用s寄存器可能是最安全的,但我也可以使用t寄存器。

于 2020-11-28T18:41:21.500 回答