1

i want to write a program that use russian peasant multiplication with mips but i face some problems

/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
    int res = 0;  // initialize result

    // While second number doesn't become 1
    while (b > 0)
    {
         // If second number becomes odd, add the first number to result
         if (b & 1)
             res = res + a;

         // Double the first number and halve the second number
         a = a << 1;
         b = b >> 1;
     }
     return res;
}

I translated it in mips with MARS environment

    .data
msg1: .asciiz "give your first number"
msg2: .asciiz "give the second number"

    .text
#a = $t1
#b = $t2
li $t3,0 #p

li $s1,1
li $s2,2

#display msg1
li $v0,4
la $a0,msg1
syscall
#read first number
li $v0,5
syscall
move $t1,$v0

#display msg2
li $v0,4
la $a0,msg2
syscall
#read second number
li $v0,5
syscall
move $t2,$v0

WHILE: 
    bgt $t2,$zero,DO
    move $a0,$t3
    li $v0,1
    syscall
    li $v0,10
    syscall

DO:
     div $t2,$s2
     mfhi $s0 #r $s0 = $t2 / $s2
     beq $s0,$s1,INC # IF b MOD 2 = 1 I jump to INC
    #a = 2xa
     mul $t1,$t1,$s2

     div $t2,$s2
     mflo $t2 # b = $t2/$s2
     j WHILE 

# i = i+ 1   
INC:
    add $t3,$t3,$t1
    jr $ra 

please , someone could help me ? to fix "Error in : invalid program counter value: 0x00000000" i searched how to fix it but i have a problem with $ra how to save propertly the return address in $ra ?

  • The `jr $ra` at last line is supposed to achieve what? Looks like MARS/SPIM environment (guessing from `syscall` usage), where `$ra` is zero upon start of program, and I don't see any `jal` or `move/add/...` which would change the `$ra`, so it looks like you face the problem of adding random instructions into your code instead of figuring out what exactly you want to do, and do only that. – Ped7g Apr 01 '18 at 17:11
  • yeah i know but don't know how to use jal in my code , it could break my code. Yes I use MARS environment –  Apr 01 '18 at 17:26
  • `jal` is jump which also set's `$ra` with address of following instruction (or next one, not even sure which one, because the delayed branch slot of MIPS CPU, which makes all jumping around more complicated .. your code looks to expect that feature switched OFF, so your MARS is simulating virtual simplified MIPS CPU without branch delay slot). So what was that last instruction supposed to achieve? Why did you put there `jr $ra`? To end code execution use `syscall` with terminate function. To jump back into your code use plain jump to label. To use "subroutines" learn how to use `jal+jr $ra`. – Ped7g Apr 01 '18 at 18:21
  • i just edit my post , i hope you understand what i look for now –  Apr 01 '18 at 19:53
  • I understand what you did want to code, I don't understand how you came up with the code you have - well, I *do* understand how, because you are just learning assembly and you didn't spend enough time+practice with the CPU instruction set and you don't understand yet common idioms how certain things are done in assembly, but the result is good for taking a long look on everything you wrote, cross-checking with your lectures and available instructions and trying to figure out what looks reasonable and what is convoluted mess diverting from C source way too much. Then delete it, and start over. – Ped7g Apr 01 '18 at 20:02

1 Answers1

1

the jr $ra will jump to the address stored in register $ra, which was not set by your code, so it is still zero (initial register value from MARS before running your code). The CPU will then jump to address zero, which is failure, and reports that.

To use jr $ra to "return" from some code, you have to first use jal instruction (or other instruction modifying $ra content) to set up $ra. Also when you want to nest several jal "subroutines calls", you have to store/restore the $ra of the outer calls around to not lose the value by the next nested jal.

Following code is example of both using paired jal+jr $ra for "subroutine"-like call, and also example how straightforward the implementation of such algorithm is in assembly (because actually that C source is more like assembly in C, so your inexperience made you take a very convoluted and complex approach of something what can be implemented in assembly almost 1:1 with the original C source):

.text
main:  # just minimal "main" to verify the code works
    # read two integers as input
    li      $v0,5
    syscall
    move    $a0, $v0        # $a0 = a
    li      $v0,5
    syscall
    move    $a1, $v0        # $a1 = b
    # call the russianPeasant subroutine
    jal     russianPeasant  # $v0 = a * b
    nop
    # output result
    move    $a0, $v0
    li      $v0, 1
    syscall
    # terminate
    li      $v0, 10
    syscall

And the subroutine itself, which can be called with arguments in a0 and a1 and returns result in v0.

# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant:
    li      $v0, 0          # res = 0
    beq     $a1, $zero, russianPeasant_b_zero
    nop     # neutralize "Delayed branching" setting ("nop" works with both ON/OFF setting)
russianPeasant_while_b:
    andi    $at, $a1, 1     # test if b is odd, for even b skip the res = res + a
    beq     $at, $zero, russianPeasant_b_even
    nop     # but such neutralization comes with performance cost of course
    add     $v0, $v0, $a0   # res = res + a
russianPeasant_b_even:
    sll     $a0, $a0, 1     # a = a << 1
    srl     $a1, $a1, 1     # b = b >> 1
    bne     $a1, $zero, russianPeasant_while_b  # repeat when (b != 0)
    nop     # on real MIPS production code the instructions are reordered to avoid useless nop
russianPeasant_b_zero:
    jr      $ra             # return res
    nop

The code is intentionally putting after each branch nop instruction to make it work with both delayed branching setting ON or OFF.

Try to use MARS help (F1) with instruction description to figure out, how it works, also use the single-step feature of the debugger to watch out the code in action, one instruction at time, observing all the register values and code flow.

On real MIPS CPU with the delayed branching the code can be optimized like this (you can switch "Delayed branching" ON in MARS settings to make it simulate real MIPS CPU with this somewhat confusing behaviour .. from your original source it looks like you are learning the MIPS assembly without delayed branching, which is certainly reasonable approach for somebody just starting with assembly, but that's not how real MIPS CPU works):

# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant_real_MIPS:   # second variant supporting delayed branching like real MIPS CPU
    beq     $a1, $zero, russianPeasant2_b_zero
    li      $v0, 0          # res = 0
russianPeasant2_while_b:
    andi    $at, $a1, 1     # test if b is odd, for even b skip the res = res + a
    beq     $at, $zero, russianPeasant2_b_even
    srl     $a1, $a1, 1     # b = b >> 1
    add     $v0, $v0, $a0   # res = res + a
russianPeasant2_b_even:
    bne     $a1, $zero, russianPeasant2_while_b  # repeat when (b != 0)
    sll     $a0, $a0, 1     # a = a << 1
russianPeasant2_b_zero:
    jr      $ra             # return res
    nop
Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • 1
    @kevin73 ?? of course it works, but that's not the point, the point is, whether you will understand HOW it works... keep studying and experimenting with debugger, and ask me in comments if something is undecipherable. If you will just copy this and submit as your work, you are wasting everyone's time. – Ped7g Apr 01 '18 at 20:42
  • 1
    oh okay , i just see that i am a real newbie so i have to learn much –  Apr 01 '18 at 20:44
  • @kevin73 yep, but that's fine, assembly has quite steep learning curve. Actually it's not that hard, it's simple overgrown calculator, nothing more, but it takes some time until this sinks into your mind, and you will learn this machine-like way of thinking, purely math+deterministic approach, without ever letting your brain to divert you from real state by what you were wishing, or some false assumptions. After getting that feel of machine you will probably find the assembly surprisingly "simple" to understand (it's the amount of code needed to achieve something, which makes it "complex"). – Ped7g Apr 01 '18 at 20:48