How to add the roman numbers in decimal with a MIPS code?

230 Views Asked by At

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!

1

There are 1 best solutions below

1
Estudiante On

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