how does movia, movi, ldw, addi, stw, ldw, ret statements work?

fhuseynli picture fhuseynli · Jan 28, 2013 · Viewed 10.1k times · Source

I thought it will be easy to explain on specific example, i understood beq works like if r9==r10 that statement gives a call for the label which is shown on the same line but i didn't understand others exactly.

START: .word 0 .word INSTR1 INSTR1: .word 1 .word 77 .word INSTR2 INSTR2: .word 2 .word 15 .word FIN FIN: .word 3

acc:
    .word 0


.text

.global main

main:   movia r8, START
    movia r9, acc

myloop: movi r10, 1
    ldw r11, 0x0(r8)
    beq r11, r0, clear
    beq r11, r10, add
    addi r10, r10, 1
    beq r11, r10, sub
    addi r10, r10, 1
    beq r11, r10, exit
    br fail

clear:  stw r0, 0x0(r9)
    ldw r8, 0x4(r8)
    br myloop

add:    ldw r12, 0x0(r9)
    ldw r13, 0x4(r9)
    addi r12, r12, r13
    stw r12, 0x0(r9)
    ldw r8, 0x8(r8)
    br myloop

sub:    ldw r12, 0x0(r9)
    ldw r13, 0x4(r9)
    sub r12, r12, r13
    stw r12, 0x0(r9)
    ldw r8, 0x8(r8)
    br myloop

exit:   ret

fail:   movia r12, 0xFFFFFFFF
    stw r12, 0x0(r9)
    ret

Answer

Aki Suihkonen picture Aki Suihkonen · Jan 28, 2013

Movia is a pseudo statement, that loads a 32-bit immediate address to a register. As the instruction width in NIOS is fixed to 32-bit it happens using two instructions:

"load_high_16_bits_and_clear_the_lower_part, register, #imm16_hi"
"or_register_with_16_bit_immediate_at_the_lower_part, register, #imm16_lo"

Because NIOS provides orhi instruction, the same can be performed as:

"load_lower_bits_and_clear_the_rest register, #imm16"
"orhi register, #imm16_hi_bits"

movi == move immediate. Again, that instruction can accept only #imm16.

ldw = load "word" == 32 bits. The address is calculated by adding an immediate to a register. In this case the instruction set allows only 14 bits of displacement.

stw = store "word" == 32 bits.

addi = add immediate: register = register + #imm_16

The instruction set reference uses a Greek symbol "sigma" before the immediate as a notation for a function doing "sign extension", which means copying the most significant bit in the immediate all over the 32-bit register (or temporary value) allowing also signed immediates. (notice sig_ned vs. sig_ma).

EDIT

The call mechanism in NIOS also needs some attention: it uses a "sliding window register mechanism", which means that the processor has e.g. 64 or 256 registers out of which only 32 registers are simultaneously visible. The lower 16 registers, IIRC, are "global" and the 16 upper registers shift 4 or 8 registers every time a call or a return is made.

This means that the register bank automatically "allocates" some temporary variables, which become the input parameters of the next function call when the window is shifted. Again, IIRC, call copies the return address to one particular register (e.g. r31) at call, which is seen as r23 (or vice versa) at the called function. There 'ret' would mean to jump to 'r23' and shift the register window back. Likewise, one could return several registers back to the caller.