
// multiply.dsa
// usage:
//
// include multiply "<relative path>"
//
// usage for multiply:
// push (arg1)
// push (arg0)
// call multiply::multiply
// pop (arg0)
// pop (arg1)

multiply:
    push bpr
    mov spr, bpr

    ldw bpr, rg0, 8  // load op 2
    ldw bpr, rg1, 12 // load op 1
    lwi 0, rg2       // initialise rg2 to zero

_multiply_loop:
    add rg2, rg0, rg2
    dec rg1

    cmp rg1, zero
    jgt _multiply_loop

_multiply_end:
    stw rg2, bpr, 8

    mov bpr, spr
    pop bpr
    return

divmod:
    push bpr
    mov spr, bpr

    ldw bpr, rg1, 8  // load op 2
    ldw bpr, rg0, 12 // load op 1

    lli 0, rg3

_divmod_loop:
    cmp rg0, rg1
    jlt _divmod_end

    sub rg0, rg1, rg0
    inc rg3

    jmp _divmod_loop

_divmod_end:
    // store div in first arg
    // store mod in second arg
    stw rg3, bpr, 8
    stw rg0, bpr, 12

    mov bpr, spr
    pop bpr
    return

// multiply.dsa - improved version
// Multiplies two 32-bit numbers using shift-and-add
//
// Usage:
// push operand2  (multiplier)
// push operand1  (multiplicand)
// call multiply::multiply
// pop result
// pop zero       (discard second argument)

new_multiply:
    push bpr
    mov spr, bpr

    ldw bpr, rg0, 8     // rg0 = multiplicand
    ldw bpr, rg1, 12    // rg1 = multiplier

    lli 0, rg2          // rg2 = result (accumulator)
    lli 32, rg3         // rg3 = bit counter

mult_loop:
    // Check if lowest bit of multiplier is 1
    lli 1, acc
    and rg1, acc, acc   // acc = rg1 & 1
    cmp acc, zero
    jeq skip_add        // if (rg1 & 1) == 0, skip addition

    // Add multiplicand to result
    add rg2, rg0, rg2

skip_add:
    shl rg0, 1          // shift multiplicand left
    shr rg1, 1          // shift multiplier right

    dec rg3
    cmp rg3, zero
    jgt mult_loop

    stw rg2, bpr, 8     // store result
    mov bpr, spr
    pop bpr
    return
