2

I want to compute the arithmetic mean of 4 signed integers in RISC-V. My current implementation is below:

.globl mean

.text
main:
    li a0 1
    li a1 2
    li a2 3
    li a3 4
    jal ra, mean

    addi a1, a0, 0
    addi a0, x0, 1
    ecall # Print Result

    addi a1, x0, '\n'
    addi a0, x0, 11
    ecall # Print newline

    addi a0, x0, 10
    ecall # Exit

mean:
   add a0 a0, a1
   add a1, a2, a3
   add a0, a0, a1
   srai a0, a0, 2
   ret

I think I am close but i am unsure if i used div correctly to divide the values. I also am not sure if I returned the mean correctly for a0 and if I need to free up space after.

I also need to round down any non-integer values that are computed by the mean, but I have no idea how to do so.

  • Have you tried assembling this, then running it? – Erik Eidt Jul 06 '21 at 15:30
  • 1
    Rounding down is automatic with integer division. If you wanted decimals you'd have to use a different data type. – Erik Eidt Jul 06 '21 at 15:32
  • @ErikEidt it will not let me run because "register 4 is not recognized" when I try and divide by 4. I am not sure how to do that part of the mean formula – River Johnson Jul 06 '21 at 15:45
  • 1
    Right, so now you have the answer to the question you asked: you know for sure that you didn't use `div` correctly. – Erik Eidt Jul 06 '21 at 15:50
  • Load 4 as an immediate into a register, and use that register instead of 4. – Erik Eidt Jul 06 '21 at 15:51
  • If you were working in MIPS instead of RISC V, the assembler would have allowed that constant with `div`, by doing the load immediate into a register for you. That however, requires a entire CPU register dedicated to such pseudo instruction expansion, which is rather a waste of hardware resources. With RISC V, they have removed the practice of reserving a CPU register just for pseudo instruction expansion, so when it comes to these you have to do it yourself. – Erik Eidt Jul 06 '21 at 16:02
  • @ErikEidt: Or use a right-shift by 2, like a compiler would (https://godbolt.org/ has RISC-V gcc and clang; use `-O1` for a function that takes unsigned args)! `div` is a terrible way to divide by 4. Also, `jal ra, a0` is using `a0` as a jump target, isn't it? Use a `ret` pseudo-instruction. – Peter Cordes Jul 06 '21 at 17:08
  • 1
    @PeterCordes, yes, that `jal` will not assemble. It should be a `jalr` with `x0` for the return address capture, and `ra` for the branch target. RISC V pretty much standardizes the pseudo instructions, so `ret` would be simpler (and it doesn't expand, just fills in `ra` and `x0` properly). I took it somehow the OP wanted to use `div`, so I didn't suggest the shift, but that is good to note as I did forget to mention it. – Erik Eidt Jul 06 '21 at 17:43
  • 1
    @ErikEidt @PeterCordes I added a ```li``` statement to store the value 4 and then used it with ```div``` would this work to divide or should I try a right shift? Would that be a right-logical-shift? – River Johnson Jul 06 '21 at 17:53
  • Be experimental and give it a try! – Erik Eidt Jul 06 '21 at 19:09
  • @ErikEidt It is telling me that a0 is defined but never used but I don't see how that is true. How do I fix this warning? – River Johnson Jul 06 '21 at 20:48
  • @RiverJohnson: you should use a right shift; never use `div` to divide by a known constant power of 2. Like Erik said, try it, and/or look at compiler output on https://godbolt.org/ for inspiration (use rv32 gcc or clang with `-Og` for a function that takes args and returns a value. [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116)) – Peter Cordes Jul 06 '21 at 20:52
  • a0 defined but never used? That makes no sense, it's a register name. Did you maybe mean it's used but not defined? `jal ra, a0` is trying to use it as a branch target label (not register), I think. If you need help with an error message, quote it exactly and say what source line it came from. – Peter Cordes Jul 06 '21 at 20:54
  • @PeterCordes my apologies, the exact error message is "label a0 is used but not defined". How would I fix this? – River Johnson Jul 06 '21 at 21:57
  • 1
    Try carefully rereading my comment. – Erik Eidt Jul 06 '21 at 22:20
  • @ErikEidt using ```jalr x0, ra``` does not work. I am told that jalr is expecting 3 arguments but only got 2. I tried ```jalr ra, x0``` as well but it didn't work. I am so confused how to return the mean value then. I tried using ```ret``` as a last resort and it also did not work. – River Johnson Jul 06 '21 at 23:24
  • When you're saying it doesn't work, you need to be more specific about the problem you're encountering. Like `ret` for example -- what doesn't work?? – Erik Eidt Jul 07 '21 at 00:39
  • Try `jalr x0, ra, 0` (or `jalr x0, 0(ra)` perhaps) – Erik Eidt Jul 07 '21 at 00:41
  • Use `ret` like a normal person. If you can't use that pseudo-instruction, read the RISC-V manual where it explains exactly what `ret` is an alias for, and use that exactly. Or use a disassembler on the machine code you get from assembling `ret`. – Peter Cordes Jul 07 '21 at 03:02
  • You return a value by having it in `a0` when you run a `ret` instruction. The actual return only involves the program counter and return address. It's calling convention is an agreement between caller and callee that the callee will leave a value in `a0`; you don't need to run any special instructions on it to make it the return value, that's just a software convention. – Peter Cordes Jul 07 '21 at 03:04

0 Answers0