So, I did pretty well on my last home assignment, where I also had to implement a program as a task in MIPS-assembly. I understood the concept and the logic of it with a little help. But still, MIPS is very new to me, and I am still learning and hoping to improve my skills in coding with MIPS.
But this time, I am completely confused. The whole logic of the task is just completely weird and confusing. And I can't understand the error messages.
The task is to implement a Roman number decoder, which sounds pretty easy at first. But I have to use the given registers, and I am not allowed to change above the label\function roman.
.data
str_input: .asciiz "numeral: "
str_return_value: .asciiz "\nReturn value: "
romdigit_table: .word 0, 0, 0, 100, 500, 0, 0, 0, 0, 1, 0, 0, 50, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 0, 0, 0, 0, 0, 0, 0
.text
.eqv SYS_PUTSTR 4
.eqv SYS_PUTCHAR 11
.eqv SYS_PUTINT 1
.eqv SYS_EXIT 10
main:
# roman numeral is output:
li $v0, SYS_PUTSTR
la $a0, str_input
syscall
li $v0, SYS_PUTSTR
la $a0, test_numeral
syscall
li $v0, SYS_PUTSTR
la $a0, str_return_value
syscall
move $v0, $zero
# calling the function roman:
la $a0, test_numeral
jal roman
# return value is output:
move $a0, $v0
li $v0, SYS_PUTINT
syscall
# end of program execution:
li $v0, SYS_EXIT
syscall
# help function: int romdigit(char digit);
romdigit:
move $v0, $zero
andi $t0, $a0, 0xE0
addi $t1, $zero, 0x40
beq $t0, $t1, _romdigit_not_null
addi $t1, $zero, 0x60
beq $t0, $t1, _romdigit_not_null
jr $ra
_romdigit_not_null:
andi $t0, $a0, 0x1F
sll $t0, $t0, 2
la $t1, romdigit_table
add $t1, $t1, $t0
lw $v0, 0($t1)
jr $ra
.data
test_numeral: .asciiz "DCCXLVI"
.text
roman:
li $t0, 0 # result
li $t1, 0 # Index in 'test_numeral'
roman_decoder:
la $a0, test_numeral # reseting $a0
add $a0, $t1, $a0 # adding the new index to the pointer $a0
lb $t2, 0($a0) # first number in 'test_numeral'
lb $t3, 1($a0) # second number in 'test_numeral'
beqz $t3, exit # exit if zero is reached
lb $a0, 0($a0) # given help function 'romdigit' needs $a0 as the argument
bgt $t3, $t2, subtract # if $t3 > $t2 subtract $t2 from result
j add
subtract: # subtract $t2 from the result
jal romdigit # calling 'romdigit'
sub $t0, $t0, $v0 # in $v0 is the encrypted decimal number
addi $t1, $t1, 1
j roman_decoder
add: # add $t2 to the result
jal romdigit # calling 'romdigit'
add $t0, $t0, $v0 # in $v0 is the encrypted decimal number
addi $t1, $t1, 1
j roman_decoder
exit:
jr $ra
The logic behind my code is simple. Iterate through test_numeral till \0; read the roman number and decode it with romdigit; add the value stored in $v0 to the result register.
I am still pretty confused that I have to use $a0 as the pointer to test_numeral and as the holder of the current roman number to be used in romdigit.
I think this code could work in theory but i wasn't able to get it run properly. I am really in despair.
I mean there are many ways to actually solve this problem. This was the easiest one I could think of. But I am always getting an "address out of range" error and I dont understand why....
I thought it would make sense to have a counter for the index $t1, which is increased by one every time a Roman number is read, and after I've used $a0 in romdigit, to add $t1 back to $a0 to get to the new index in test_numeral . But this didn't work so well, and I have no clue how to do it another way.
I would appreciate any hints on this one. Thank you guys in advance!
I was busy so I couldn`t really work on the code anymore.
But I think I have a working code now. The only issue is that it wont stop:
.data
test_numeral: .asciiz "DCCXLVI"
.text
roman:
move $t3, $a0
li $t2, 0
li $t4, 0
roman_decoder:
move $t4, $v0
lb $a0, 0($t3)
beqz $a0, exit
jal romdigit
bgt $v0, $t4, subtract
add $t2, $t2, $v0
addi $t3, $t3, 1
j roman_decoder
subtract:
sub $t2, $t2, $t4
sub $t2, $t2, $t4
add $t2, $t2, $v0
addi $t3, $t3, 1
j roman_decoder
exit:
move $v0, $t2
jr $ra
When $a0 is zero, the code jumps to exit. Moves $t2 in $v0 and should end because I'm saying jr $ra, so it should jump back to main to end the program right? What am I doing wrong?
Many thanks in advance!
The problem might be, that the romdigit function itself uses the jr callback to continue in roman_decoder. In doing this, it also changes the value of the $ra register, so the exit function calls the romand_decoder again instead of the main function. Try to store the value of $ra in an extra register before calling romdigit and in the exit function load the value back to the $ra register before using the callback