---
# System prepended metadata

title: arch2025-homework1

---

# CA Homework 1

## problem B
I translated the C functions clz, uf8_decode, and uf8_encode into RISC-V assembly and built an automated test that exhaustively evaluates all inputs from 0 to 255.

### clz
<details>
<summary><b>clz</b></summary>
    
``` c=
static inline unsigned clz(uint32_t x)
{
    int n = 32, c = 16;
    do {
        uint32_t y = x >> c;
        if (y) {
            n -= c;
            x = y;
        }
        c >>= 1;
    } while (c);
    return n - x;
}
```
</details> 

### Assembly code

```
.text
    .globl main
main:
    li   a0, 0x0000F000 # test 0x00F00000 
    jal  ra, clz        # call clz

done:
    j    done

clz:
    li   t0, 32              # n = 32
    li   t1, 16              # c = 16

clz_loop:
    srl  t2, a0, t1          # y = x >> c
    beq  t2, zero, clz_skip  # if (!y) skip
    sub  t0, t0, t1          # n -= c
    mv   a0, t2              # x = y
clz_skip:
    srli t1, t1, 1           # c >>= 1
    bne  t1, zero, clz_loop  # while (c)

    sub  a0, t0, a0          # return n - x
    ret                      
```
### uf8_decode
```
.text
    .globl main

main:
    # test 0x7C 
    li   a0, 0x7C

    jal  ra, uf8_decode
    # a0 3568 (0xDE0)
done:
    j    done

uf8_decode:
    andi t0, a0, 0x0f           # t0 = mantissa
    srli t1, a0, 4              # t1 = exponent
    
    li   t2, 15                 
    sub  t2, t2, t1             # t2 = 15 - exponent
    
    li   t3, 0x7FFF             
    srl  t3, t3, t2             
    slli t3, t3, 4              # t3 = offset
    
    sll  t0, t0, t1             # t0 = mantissa << exponent
    
    add  a0, t0, t3             # a0 = (mantissa << exponent) + offset
    
    ret
```
### main
```
.text
    .globl main

main:
    # test function
    jal  ra, test # a0 (1 = pass, 0 = fail)。
done:
    li   a7, 10     
    ecall

test:
    addi sp, sp, -20
    sw   ra, 16(sp)   #return address
    sw   s0, 12(sp)   #s0 previous_value
    sw   s1, 8(sp)    #s1 passed flag
    sw   s2, 4(sp)    #s2 loop counter
    sw   s3, 0(sp)    #s3 result of decode

    li   s0, -1
    li   s1, 1 
    mv   s2, zero 

test_loop_start:
    
    li   t0, 256
    bge  s2, t0, test_loop_end  

    mv   a0, s2                 
    jal  ra, uf8_decode         
    mv   s3, a0            

    jal  ra, uf8_encode        

    beq  s2, a0, check_monotonicity 

    j    test_set_fail

check_monotonicity:
    bgt  s3, s0, update_and_continue 

    j    test_set_fail

update_and_continue:
    mv   s0, s3                 
    addi s2, s2, 1               
    j    test_loop_start      

test_set_fail:
    mv   s1, zero
    j    update_and_continue

test_loop_end:
    mv   a0, s1

    lw   s3, 0(sp)
    lw   s2, 4(sp)
    lw   s1, 8(sp)
    lw   s0, 12(sp)
    lw   ra, 16(sp)
    addi sp, sp, 20             
    ret                         

uf8_encode:
    addi sp, sp, -16
    sw   ra, 12(sp)
    sw   s0, 8(sp)
    sw   s1, 4(sp)
    sw   s2, 0(sp)
    li   t0, 16
    bge  a0, t0, handle_large_value_enc
    j    epilogue_encode
    
handle_large_value_enc:
    mv   s0, a0
    jal  ra, clz
    li   t0, 31
    sub  t1, t0, a0
    mv   s1, zero
    mv   s2, zero
    li   t0, 5
    blt  t1, t0, find_exact_exponent
    addi t0, t1, -4
    mv   s1, t0
    li   t0, 15
    ble  s1, t0, calculate_overflow_loop
    mv   s1, t0
    
calculate_overflow_loop:
    mv   t2, zero
    
for_loop_start:
    bge  t2, s1, for_loop_end
    slli s2, s2, 1
    addi s2, s2, 16
    addi t2, t2, 1
    j    for_loop_start
    
for_loop_end:

adjust_exponent_loop:
    ble  s1, zero, find_exact_exponent
    bge  s0, s2, find_exact_exponent
    addi s2, s2, -16
    srli s2, s2, 1
    addi s1, s1, -1
    j    adjust_exponent_loop
    
find_exact_exponent:

exact_exponent_loop:
    li   t0, 15
    bge  s1, t0, exact_exponent_end
    slli t3, s2, 1
    addi t3, t3, 16
    blt  s0, t3, exact_exponent_end
    mv   s2, t3
    addi s1, s1, 1
    j    exact_exponent_loop
    
exact_exponent_end:
    sub  t0, s0, s2
    srl  t0, t0, s1
    slli a0, s1, 4
    or   a0, a0, t0
    
epilogue_encode:
    lw   s2, 0(sp)
    lw   s1, 4(sp)
    lw   s0, 8(sp)
    lw   ra, 12(sp)
    addi sp, sp, 16
    ret

uf8_decode:
    andi t0, a0, 0x0f           # t0 = mantissa = fl & 0x0f
    srli t1, a0, 4              # t1 = exponent = fl >> 4
    li   t2, 15                 # t2 = 15
    sub  t2, t2, t1             # t2 = 15 - exponent
    li   t3, 0x7FFF             # t3 = 0x7FFF
    srl  t3, t3, t2             # t3 = 0x7FFF >> t2
    slli t3, t3, 4              # t3 = offset = (result << 4)
    sll  t0, t0, t1             # t0 = mantissa << exponent
    add  a0, t0, t3             # a0 = (mantissa << exponent) + offset
    ret                         

clz:
    mv   t3, a0                 # t3 = x
    li   t0, 32                 # t0 = n = 32
    li   t1, 16                 # t1 = c = 16
clz_loop:
    srl  t2, t3, t1             # t2 = y = x >> c
    beq  t2, zero, clz_skip     # if (y == 0) then skip
    sub  t0, t0, t1             # n -= c
    mv   t3, t2                 # x = y
clz_skip:
    srli t1, t1, 1              # c >>= 1
    bne  t1, zero, clz_loop     # while (c != 0)
    sub  a0, t0, t3             # return n - x
    ret                         
```
### Analysis
Put code above into editor and we will see that Ripe doesn't execute it literally. Instead, it replace pseudo instruction into equivalent one, and change register name from ABI name to sequencial one.
The translated code looks like:
```

00000000 <main>:
    0:        008000ef        jal x1 8 <test>

00000004 <done>:
    4:        0000006f        jal x0 0 <done>

00000008 <test>:
    8:        fec10113        addi x2 x2 -20
    c:        00112823        sw x1 16 x2
    10:        00812623        sw x8 12 x2
    14:        00912423        sw x9 8 x2
    18:        01212223        sw x18 4 x2
    1c:        01312023        sw x19 0 x2
    20:        fff00413        addi x8 x0 -1
    24:        00100493        addi x9 x0 1
    28:        00000913        addi x18 x0 0

0000002c <test_loop_start>:
    2c:        10000293        addi x5 x0 256
    30:        02595c63        bge x18 x5 56 <test_loop_end>
    34:        00090513        addi x10 x18 0
    38:        11c000ef        jal x1 284 <uf8_decode>
    3c:        00050993        addi x19 x10 0
    40:        048000ef        jal x1 72 <uf8_encode>
    44:        00a90463        beq x18 x10 8 <check_monotonicity>
    48:        0180006f        jal x0 24 <test_set_fail>

0000004c <check_monotonicity>:
    4c:        01344463        blt x8 x19 8 <update_and_continue>
    50:        0100006f        jal x0 16 <test_set_fail>

00000054 <update_and_continue>:
    54:        00098413        addi x8 x19 0
    58:        00190913        addi x18 x18 1
    5c:        fd1ff06f        jal x0 -48 <test_loop_start>

00000060 <test_set_fail>:
    60:        00000493        addi x9 x0 0
    64:        ff1ff06f        jal x0 -16 <update_and_continue>

00000068 <test_loop_end>:
    68:        00048513        addi x10 x9 0
    6c:        00012983        lw x19 0 x2
    70:        00412903        lw x18 4 x2
    74:        00812483        lw x9 8 x2
    78:        00c12403        lw x8 12 x2
    7c:        01012083        lw x1 16 x2
    80:        01410113        addi x2 x2 20
    84:        00008067        jalr x0 x1 0

00000088 <uf8_encode>:
    88:        ff010113        addi x2 x2 -16
    8c:        00112623        sw x1 12 x2
    90:        00812423        sw x8 8 x2
    94:        00912223        sw x9 4 x2
    98:        01212023        sw x18 0 x2
    9c:        01000293        addi x5 x0 16
    a0:        00555463        bge x10 x5 8 <handle_large_value_enc>
    a4:        0980006f        jal x0 152 <epilogue_encode>

000000a8 <handle_large_value_enc>:
    a8:        00050413        addi x8 x10 0
    ac:        0d4000ef        jal x1 212 <clz>
    b0:        01f00293        addi x5 x0 31
    b4:        40a28333        sub x6 x5 x10
    b8:        00000493        addi x9 x0 0
    bc:        00000913        addi x18 x0 0
    c0:        00500293        addi x5 x0 5
    c4:        04534463        blt x6 x5 72 <find_exact_exponent>
    c8:        ffc30293        addi x5 x6 -4
    cc:        00028493        addi x9 x5 0
    d0:        00f00293        addi x5 x0 15
    d4:        0092d463        bge x5 x9 8 <calculate_overflow_loop>
    d8:        00028493        addi x9 x5 0

000000dc <calculate_overflow_loop>:
    dc:        00000393        addi x7 x0 0

000000e0 <for_loop_start>:
    e0:        0093da63        bge x7 x9 20 <for_loop_end>
    e4:        00191913        slli x18 x18 1
    e8:        01090913        addi x18 x18 16
    ec:        00138393        addi x7 x7 1
    f0:        ff1ff06f        jal x0 -16 <for_loop_start>

000000f4 <for_loop_end>:
    f4:        00905c63        bge x0 x9 24 <find_exact_exponent>
    f8:        01245a63        bge x8 x18 20 <find_exact_exponent>
    fc:        ff090913        addi x18 x18 -16
    100:        00195913        srli x18 x18 1
    104:        fff48493        addi x9 x9 -1
    108:        fedff06f        jal x0 -20 <for_loop_end>

0000010c <find_exact_exponent>:
    10c:        00f00293        addi x5 x0 15
    110:        0054de63        bge x9 x5 28 <exact_exponent_end>
    114:        00191e13        slli x28 x18 1
    118:        010e0e13        addi x28 x28 16
    11c:        01c44863        blt x8 x28 16 <exact_exponent_end>
    120:        000e0913        addi x18 x28 0
    124:        00148493        addi x9 x9 1
    128:        fe5ff06f        jal x0 -28 <find_exact_exponent>

0000012c <exact_exponent_end>:
    12c:        412402b3        sub x5 x8 x18
    130:        0092d2b3        srl x5 x5 x9
    134:        00449513        slli x10 x9 4
    138:        00556533        or x10 x10 x5

0000013c <epilogue_encode>:
    13c:        00012903        lw x18 0 x2
    140:        00412483        lw x9 4 x2
    144:        00812403        lw x8 8 x2
    148:        00c12083        lw x1 12 x2
    14c:        01010113        addi x2 x2 16
    150:        00008067        jalr x0 x1 0

00000154 <uf8_decode>:
    154:        00f57293        andi x5 x10 15
    158:        00455313        srli x6 x10 4
    15c:        00f00393        addi x7 x0 15
    160:        406383b3        sub x7 x7 x6
    164:        00008e37        lui x28 0x8
    168:        fffe0e13        addi x28 x28 -1
    16c:        007e5e33        srl x28 x28 x7
    170:        004e1e13        slli x28 x28 4
    174:        006292b3        sll x5 x5 x6
    178:        01c28533        add x10 x5 x28
    17c:        00008067        jalr x0 x1 0

00000180 <clz>:
    180:        00050e13        addi x28 x10 0
    184:        02000293        addi x5 x0 32
    188:        01000313        addi x6 x0 16

0000018c <clz_loop>:
    18c:        006e53b3        srl x7 x28 x6
    190:        00038663        beq x7 x0 12 <clz_skip>
    194:        406282b3        sub x5 x5 x6
    198:        00038e13        addi x28 x7 0

0000019c <clz_skip>:
    19c:        00135313        srli x6 x6 1
    1a0:        fe0316e3        bne x6 x0 -20 <clz_loop>
    1a4:        41c28533        sub x10 x5 x28
    1a8:        00008067        jalr x0 x1 0

```
### 5-stage pipelined processor
![image](https://hackmd.io/_uploads/HkXEw7ITxe.png)
### Instruction Fetch (IF)
Fetch the next instruction at PC (e.g., jal ra, test, loop heads like test_loop_start, clz_loop).
The code has many branches and jumps—bge s2, t0, test_loop_end, beq t2, zero, clz_skip, jal x0, … (unconditional jump), and jalr x0, x1, 0 (ret).
IF speculatively fetches the fall-through; once EX resolves a branch/jump, any misfetched instruction is flushed (control hazard → bubbles).
### Instruction Decode & Register Fetch (ID)
Examples:

Loop control reads: bge s2, t0, … (reads s2, t0).

Argument setup before calls: mv a0, s2 (expanded as addi a0, s2, 0) for uf8_decode/encode.

Stack frame prologues: sw ra, 16(sp), sw s0, 12(sp) preserve live registers.

Data hazards: Back-to-back use of values returned from functions (e.g., clz → used immediately in uf8_encode) depends on forwarding; without it, the core inserts stalls.

### Execute (EX)
Representative operations

clz (count leading zeros):
Binary search via shifts: srl t2, t3, t1 with c stepping 16→8→4→2→1; branch on zero beq t2, zero, clz_skip; maintain n -= c; return sub a0, t0, t3.
Branches resolve in EX → frequent control hazards.

uf8_decode:
Field split: andi t0, a0, 0x0f (mantissa), srli t1, a0, 4 (exponent).
Build 0x7FFF via lui+addi, then srl/slli to form offset; compute (mantissa<<exp)+offset.

uf8_encode:
Estimate msb = 31 - clz(value); guess exponent ≈ msb - 4 (clamped to 15).
Build overflow by loop: overflow = (overflow<<1) + 16.
Adjust down while value < overflow: (overflow-16)>>1, exponent- -.
Refine up while value ≥ next = (overflow<<1)+16: update overflow, exponent++.
Compute mantissa = (value - overflow) >> exponent, then pack (exponent<<4)|mantissa.

Branch resolution: blt/bge/beq decide in EX; IF may need to discard prefetched instructions.

### Memory Access (MEM)
Role: Data memory loads/stores. In your code, MEM is mostly stack traffic at function boundaries.

Typical instructions:
sw ra/s0/… on entry; lw on exit to restore. The algorithm itself keeps most working data in registers, so MEM is dominated by prologue/epilogue traffic.

Note: If the simulator models cache/latency, lw followed immediately by a consumer can cause a load-use stall without forwarding.

### Register Write Back (WB)
Function returns: clz, uf8_decode, uf8_encode write results to a0; callers often consume them in the next instruction (RAW hazard → rely on forwarding).

Loop variables: addi s2, s2, 1 (i++) is written back and then read right away by bge s2, 256.

![image](https://hackmd.io/_uploads/HyPEhmITxx.png)
This routine (test) validates the round-trip correctness and monotonicity of a custom 8-bit “uf8” number format by exhaustively iterating all 256 encodings. For each fl ∈ [0,255], it:

decodes fl → value = uf8_decode(fl),

re-encodes value → fl2 = uf8_encode(value),

checks that fl2 == fl (round-trip), and

enforces value is strictly increasing over fl (monotonicity).

If any check fails, a boolean flag passed is cleared. The function returns 1 (pass) or 0 (fail) in a0.
![image](https://hackmd.io/_uploads/Syg1-mzRge.png)

## problem C

### static inline bool bf16_isnan(bf16_t a)
```
.text
    .globl main

main:
    li   a0, 0x7FC0              
    jal  ra, bf16_isnan          
    mv   s0, a0                  

    li   a0, 0x7F80              
    jal  ra, bf16_isnan          
    mv   s1, a0                  

done:
    j    done

bf16_isnan:
    li   t0, 0x7F80              
    and  t1, a0, t0              
    bne  t1, t0, is_not_nan      

    li   t0, 0x007F              
    and  t1, a0, t0              

    sltu a0, zero, t1            
    ret                          

is_not_nan:
    li   a0, 0                   
    ret                          
```
### static inline bool bf16_isinf(bf16_t a)
```
.text
    .globl main

main:
    li   a0, 0x7F80              
    jal  ra, bf16_isinf          
    mv   s0, a0                  

    li   a0, 0x7FC0              
    jal  ra, bf16_isinf          
    mv   s1, a0                  

done:
    j    done

bf16_isinf:
    li   t0, 0x7F80              
    and  t1, a0, t0              
    bne  t1, t0, is_not_inf      

    li   t0, 0x007F              
    and  t1, a0, t0              

    seqz a0, t1                  
    ret                          

is_not_inf:
    li   a0, 0                   
    ret                          
```
### static inline bool bf16_iszero(bf16_t a)

```
.text
    .globl main

main:
    li   a0, 0x8000              
    jal  ra, bf16_iszero         
    mv   s0, a0                  

    li   a0, 0x3F80              
    jal  ra, bf16_iszero         
    mv   s1, a0                  

done:
    j    done



bf16_iszero:
    li   t0, 0x7FFF              
    and  t1, a0, t0              
    
    seqz a0, t1                  
    ret                          
```
### static inline bf16_t f32_to_bf16(float val)
```
.text
    .globl main

main:
    li   a0, 0x7F800000
    jal  ra, f32_to_bf16
    mv   s0, a0                  

    li   a0, 0x40000000
    jal  ra, f32_to_bf16
    mv   s1, a0                  

    li   a0, 0x40490FDB
    jal  ra, f32_to_bf16
    mv   s2, a0                  

done:
    j    done

f32_to_bf16:
    srli t0, a0, 23              
    andi t0, t0, 0xFF            
    li   t1, 0xFF                
    bne  t0, t1, handle_normal   

handle_special:
    srli a0, a0, 16              
    ret

handle_normal:
    srli t0, a0, 16              
    andi t0, t0, 1               
    li   t1, 0x7FFF              
    add  t0, t0, t1              
    
    add  a0, a0, t0              
    
    srli a0, a0, 16              
    ret
```
### static inline float bf16_to_f32(bf16_t val)
```
.text
    .globl main

main:
    li   a0, 0x4000
    jal  ra, bf16_to_f32
    mv   s0, a0                  

    li   a0, 0x7F80
    jal  ra, bf16_to_f32
    mv   s1, a0                  

done:
    j    done

bf16_to_f32:
    slli a0, a0, 16              
    ret                          
```
### static inline bf16_t bf16_add(bf16_t a, bf16_t b)
```
.text
    .globl main

main:

    li   a0, 0x3F80              
    li   a1, 0x4000              
    jal  ra, bf16_add
    mv   s0, a0                  

    li   a0, 0x4040              
    li   a1, 0xBF80              
    jal  ra, bf16_add
    mv   s1, a0                  
    
    li   a0, 0x3FC0              
    li   a1, 0x3FC0             
    jal  ra, bf16_add
    mv   s2, a0                  
    
done:
    j    done

bf16_add:
  
    addi sp, sp, -48
    sw   ra,  44(sp)
    sw   s0,  40(sp)             # s0: a 
    sw   s1,  36(sp)             # s1: b 
    sw   s2,  32(sp)             # s2: sign_a
    sw   s3,  28(sp)             # s3: sign_b
    sw   s4,  24(sp)             # s4: exp_a
    sw   s5,  20(sp)             # s5: exp_b
    sw   s6,  16(sp)             # s6: mant_a
    sw   s7,  12(sp)             # s7: mant_b
    sw   s8,  8(sp)              # s8: result_sign
    sw   s9,  4(sp)              # s9: result_exp
    sw   s10, 0(sp)              # s10: result_mant

    mv   s0, a0                  
    mv   s1, a1
    srli s2, s0, 15              # s2 = sign_a
    andi s2, s2, 1
    srli s3, s1, 15              # s3 = sign_b
    andi s3, s3, 1
    srli s4, s0, 7               # s4 = exp_a
    andi s4, s4, 0xFF
    srli s5, s1, 7               # s5 = exp_b
    andi s5, s5, 0xFF
    andi s6, s0, 0x7F            # s6 = mant_a
    andi s7, s1, 0x7F            # s7 = mant_b


    li   t0, 0xFF
    bne  s4, t0, check_b_special 
    bne  s6, zero, return_a      
    
    bne  s5, t0, return_a        
    
    bne  s7, zero, return_b      
    
    beq  s2, s3, return_b        
    li   a0, 0x7FC0              
    j    epilogue
    
check_b_special:
    bne  s5, t0, check_zeros     
    bne  s7, zero, return_b      
    j    return_b   
    
check_zeros:
    or   t0, s4, s6
    beq  t0, zero, return_b      
    or   t0, s5, s7
    beq  t0, zero, return_a      

    li   t0, 0x80
    bne  s4, zero, add_implicit_a
    j    check_implicit_b
    
add_implicit_a:
    or   s6, s6, t0
    
check_implicit_b:
    bne  s5, zero, add_implicit_b
    j    align_exponents
    
add_implicit_b:
    or   s7, s7, t0

align_exponents:
    sub  t0, s4, s5              
    bgtz t0, a_exp_larger
    bltz t0, b_exp_larger
    mv   s9, s4                  
    j    add_sub_mantissas
    
a_exp_larger:
    mv   s9, s4                  
    li   t1, 8
    bgt  t0, t1, return_a        
    srl  s7, s7, t0              
    j    add_sub_mantissas
    
b_exp_larger:
    mv   s9, s5                  
    neg  t0, t0                  
    li   t1, 8
    bgt  t0, t1, return_b        
    srl  s6, s6, t0              

add_sub_mantissas:
    bne  s2, s3, different_signs 
    
same_signs:
    mv   s8, s2                  
    add  s10, s6, s7             
    andi t0, s10, 0x100          
    beq  t0, zero, pack_result   
    srli s10, s10, 1             
    addi s9, s9, 1               
    li   t0, 0xFF
    bge  s9, t0, return_infinity 
    j    pack_result
    
different_signs:
    bge  s6, s7, a_mant_larger   
    mv   s8, s3                  
    sub  s10, s7, s6             
    j    normalize_sub_result
    
a_mant_larger:
    mv   s8, s2                  
    sub  s10, s6, s7         
    
normalize_sub_result:
    beq  s10, zero, return_pos_zero 
    
normalize_loop:
    andi t0, s10, 0x80           
    bne  t0, zero, pack_result   
    slli s10, s10, 1             
    addi s9, s9, -1              
    blez s9, return_pos_zero     
    j    normalize_loop          

pack_result:
    slli t0, s8, 15              
    andi s9, s9, 0xFF            
    slli t1, s9, 7               
    andi t2, s10, 0x7F           
    or   a0, t0, t1              
    or   a0, a0, t2              
    j    epilogue

return_a:
    mv   a0, s0
    j    epilogue
    
return_b:
    mv   a0, s1
    j    epilogue
    
return_pos_zero:
    li   a0, 0
    j    epilogue
    
return_infinity:
    slli t0, s8, 15             
    li   t1, 0x7F80              
    or   a0, t0, t1              
    j    epilogue                

epilogue:
    lw   s10, 0(sp)
    lw   s9,  4(sp)
    lw   s8,  8(sp)
    lw   s7,  12(sp)
    lw   s6,  16(sp)
    lw   s5,  20(sp)
    lw   s4,  24(sp)
    lw   s3,  28(sp)
    lw   s2,  32(sp)
    lw   s1,  36(sp)
    lw   s0,  40(sp)
    lw   ra,  44(sp)
    addi sp, sp, 48
    ret
```
```

00000000 <main>:
    0:        00004537        lui x10 0x4
    4:        f8050513        addi x10 x10 -128
    8:        000045b7        lui x11 0x4
    c:        03c000ef        jal x1 60 <bf16_add>
    10:        00050413        addi x8 x10 0
    14:        00004537        lui x10 0x4
    18:        04050513        addi x10 x10 64
    1c:        0000c5b7        lui x11 0xc
    20:        f8058593        addi x11 x11 -128
    24:        024000ef        jal x1 36 <bf16_add>
    28:        00050493        addi x9 x10 0
    2c:        00004537        lui x10 0x4
    30:        fc050513        addi x10 x10 -64
    34:        000045b7        lui x11 0x4
    38:        fc058593        addi x11 x11 -64
    3c:        00c000ef        jal x1 12 <bf16_add>
    40:        00050913        addi x18 x10 0

00000044 <done>:
    44:        0000006f        jal x0 0 <done>

00000048 <bf16_add>:
    48:        fd010113        addi x2 x2 -48
    4c:        02112623        sw x1 44 x2
    50:        02812423        sw x8 40 x2
    54:        02912223        sw x9 36 x2
    58:        03212023        sw x18 32 x2
    5c:        01312e23        sw x19 28 x2
    60:        01412c23        sw x20 24 x2
    64:        01512a23        sw x21 20 x2
    68:        01612823        sw x22 16 x2
    6c:        01712623        sw x23 12 x2
    70:        01812423        sw x24 8 x2
    74:        01912223        sw x25 4 x2
    78:        01a12023        sw x26 0 x2
    7c:        00050413        addi x8 x10 0
    80:        00058493        addi x9 x11 0
    84:        00f45913        srli x18 x8 15
    88:        00197913        andi x18 x18 1
    8c:        00f4d993        srli x19 x9 15
    90:        0019f993        andi x19 x19 1
    94:        00745a13        srli x20 x8 7
    98:        0ffa7a13        andi x20 x20 255
    9c:        0074da93        srli x21 x9 7
    a0:        0ffafa93        andi x21 x21 255
    a4:        07f47b13        andi x22 x8 127
    a8:        07f4fb93        andi x23 x9 127
    ac:        0ff00293        addi x5 x0 255
    b0:        025a1063        bne x20 x5 32 <check_b_special>
    b4:        100b1463        bne x22 x0 264 <return_a>
    b8:        105a9263        bne x21 x5 260 <return_a>
    bc:        100b9463        bne x23 x0 264 <return_b>
    c0:        11390263        beq x18 x19 260 <return_b>
    c4:        00008537        lui x10 0x8
    c8:        fc050513        addi x10 x10 -64
    cc:        11c0006f        jal x0 284 <epilogue>

000000d0 <check_b_special>:
    d0:        005a9663        bne x21 x5 12 <check_zeros>
    d4:        0e0b9863        bne x23 x0 240 <return_b>
    d8:        0ec0006f        jal x0 236 <return_b>

000000dc <check_zeros>:
    dc:        016a62b3        or x5 x20 x22
    e0:        0e028263        beq x5 x0 228 <return_b>
    e4:        017ae2b3        or x5 x21 x23
    e8:        0c028a63        beq x5 x0 212 <return_a>
    ec:        08000293        addi x5 x0 128
    f0:        000a1463        bne x20 x0 8 <add_implicit_a>
    f4:        0080006f        jal x0 8 <check_implicit_b>

000000f8 <add_implicit_a>:
    f8:        005b6b33        or x22 x22 x5

000000fc <check_implicit_b>:
    fc:        000a9463        bne x21 x0 8 <add_implicit_b>
    100:        0080006f        jal x0 8 <align_exponents>

00000104 <add_implicit_b>:
    104:        005bebb3        or x23 x23 x5

00000108 <align_exponents>:
    108:        415a02b3        sub x5 x20 x21
    10c:        00504863        blt x0 x5 16 <a_exp_larger>
    110:        0202c063        blt x5 x0 32 <b_exp_larger>
    114:        000a0c93        addi x25 x20 0
    118:        02c0006f        jal x0 44 <add_sub_mantissas>

0000011c <a_exp_larger>:
    11c:        000a0c93        addi x25 x20 0
    120:        00800313        addi x6 x0 8
    124:        08534c63        blt x6 x5 152 <return_a>
    128:        005bdbb3        srl x23 x23 x5
    12c:        0180006f        jal x0 24 <add_sub_mantissas>

00000130 <b_exp_larger>:
    130:        000a8c93        addi x25 x21 0
    134:        405002b3        sub x5 x0 x5
    138:        00800313        addi x6 x0 8
    13c:        08534463        blt x6 x5 136 <return_b>
    140:        005b5b33        srl x22 x22 x5

00000144 <add_sub_mantissas>:
    144:        03391463        bne x18 x19 40 <different_signs>

00000148 <same_signs>:
    148:        00090c13        addi x24 x18 0
    14c:        017b0d33        add x26 x22 x23
    150:        100d7293        andi x5 x26 256
    154:        04028663        beq x5 x0 76 <pack_result>
    158:        001d5d13        srli x26 x26 1
    15c:        001c8c93        addi x25 x25 1
    160:        0ff00293        addi x5 x0 255
    164:        065cd863        bge x25 x5 112 <return_infinity>
    168:        0380006f        jal x0 56 <pack_result>

0000016c <different_signs>:
    16c:        017b5863        bge x22 x23 16 <a_mant_larger>
    170:        00098c13        addi x24 x19 0
    174:        416b8d33        sub x26 x23 x22
    178:        00c0006f        jal x0 12 <normalize_sub_result>

0000017c <a_mant_larger>:
    17c:        00090c13        addi x24 x18 0
    180:        417b0d33        sub x26 x22 x23

00000184 <normalize_sub_result>:
    184:        040d0463        beq x26 x0 72 <return_pos_zero>

00000188 <normalize_loop>:
    188:        080d7293        andi x5 x26 128
    18c:        00029a63        bne x5 x0 20 <pack_result>
    190:        001d1d13        slli x26 x26 1
    194:        fffc8c93        addi x25 x25 -1
    198:        03905a63        bge x0 x25 52 <return_pos_zero>
    19c:        fedff06f        jal x0 -20 <normalize_loop>

000001a0 <pack_result>:
    1a0:        00fc1293        slli x5 x24 15
    1a4:        0ffcfc93        andi x25 x25 255
    1a8:        007c9313        slli x6 x25 7
    1ac:        07fd7393        andi x7 x26 127
    1b0:        0062e533        or x10 x5 x6
    1b4:        00756533        or x10 x10 x7
    1b8:        0300006f        jal x0 48 <epilogue>

000001bc <return_a>:
    1bc:        00040513        addi x10 x8 0
    1c0:        0280006f        jal x0 40 <epilogue>

000001c4 <return_b>:
    1c4:        00048513        addi x10 x9 0
    1c8:        0200006f        jal x0 32 <epilogue>

000001cc <return_pos_zero>:
    1cc:        00000513        addi x10 x0 0
    1d0:        0180006f        jal x0 24 <epilogue>

000001d4 <return_infinity>:
    1d4:        00fc1293        slli x5 x24 15
    1d8:        00008337        lui x6 0x8
    1dc:        f8030313        addi x6 x6 -128
    1e0:        0062e533        or x10 x5 x6
    1e4:        0040006f        jal x0 4 <epilogue>

000001e8 <epilogue>:
    1e8:        00012d03        lw x26 0 x2
    1ec:        00412c83        lw x25 4 x2
    1f0:        00812c03        lw x24 8 x2
    1f4:        00c12b83        lw x23 12 x2
    1f8:        01012b03        lw x22 16 x2
    1fc:        01412a83        lw x21 20 x2
    200:        01812a03        lw x20 24 x2
    204:        01c12983        lw x19 28 x2
    208:        02012903        lw x18 32 x2
    20c:        02412483        lw x9 36 x2
    210:        02812403        lw x8 40 x2
    214:        02c12083        lw x1 44 x2
    218:        03010113        addi x2 x2 48
    21c:        00008067        jalr x0 x1 0

```
![image](https://hackmd.io/_uploads/HyoH-Xz0el.png)

### static inline bf16_t bf16_sub(bf16_t a, bf16_t b)
```
.text
    .globl main

main:
    li   a0, 0x4040              # a = 3.0
    li   a1, 0x3F80              # b = 1.0
    jal  ra, bf16_sub
    mv   s0, a0                  # 0x4000

    li   a0, 0x3F80              # a = 1.0
    li   a1, 0x4040              # b = 3.0
    jal  ra, bf16_sub
    mv   s1, a0                  # 0xC000

    li   a0, 0x40A0              # a = 5.0
    li   a1, 0x40A0              # b = 5.0
    jal  ra, bf16_sub
    mv   s2, a0                  # 0x0000

done:
    j    done

bf16_sub:
    li   t0, 0x8000              
    xor  a1, a1, t0              
    
    j    bf16_add
```
### static inline bf16_t bf16_mul(bf16_t a, bf16_t b)
```
    .text
    .globl main
    .globl bf16_mul

main:
    li   a0, 0x4000            # a = 2.0 (bf16)
    li   a1, 0x4040            # b = 3.0 (bf16)
    jal  ra, bf16_mul          # a0 <- result
    mv   a2, a0                # 0x40C0

    #li   a0, 0xC000            # a = -2.0
    #li   a1, 0x4040            # b = 3.0
    #jal  ra, bf16_mul
    #mv   a3, a0                # 0xC0C0

    #li   a0, 0x7F80            # a = +Inf
    #li   a1, 0x40A0            # b = 5.0
    #jal  ra, bf16_mul
    #mv   a4, a0                # 0x7F80

done:
    j    done

bf16_mul:
    srli t0, a0, 15            # sign_a
    andi t0, t0, 1
    srli t1, a1, 15            # sign_b
    andi t1, t1, 1
    xor  t6, t0, t1            # result_sign -> t6

    srli a2, a0, 7             # exp_a
    andi a2, a2, 0xFF
    srli a3, a1, 7             # exp_b
    andi a3, a3, 0xFF
    andi a4, a0, 0x7F          # mant_a
    andi a5, a1, 0x7F          # mant_b

    li   t2, 0xFF
    bne  a2, t2, 1f
      bnez a4, .ret_a          
      or   t3, a3, a5
      beqz t3, .ret_qnan      
      j    .ret_inf            
1:  bne  a3, t2, 2f
      bnez a5, .ret_b         
      or   t3, a2, a4
      beqz t3, .ret_qnan       
      j    .ret_inf
2:
  
    or   t3, a2, a4
    beqz t3, .ret_zero
    or   t3, a3, a5
    beqz t3, .ret_zero

    li   a6, 0                 

    bnez a2, 3f                
0:  andi t3, a4, 0x80
    bnez t3, 4f
    slli a4, a4, 1
    addi a6, a6, -1
    j    0b
4:  li   a2, 1
3:  ori  a4, a4, 0x80          

    bnez a3, 5f                
6:  andi t3, a5, 0x80
    bnez t3, 7f
    slli a5, a5, 1
    addi a6, a6, -1
    j    6b
7:  li   a3, 1
5:  ori  a5, a5, 0x80          

    add  a7, a2, a3
    addi t3, x0, 127
    sub  a7, a7, t3
    add  a7, a7, a6

    mv   t0, a4                
    mv   t1, a5                
    li   t4, 0                 
    li   t5, 8                 
mul_loop:
    andi t2, t1, 1
    beqz t2, 8f
    add  t4, t4, t0
8:  slli t0, t0, 1
    srli t1, t1, 1
    addi t5, t5, -1
    bnez t5, mul_loop

    li   t0, 0x8000
    and  t1, t4, t0
    beqz t1, 9f
      srli t4, t4, 8
      addi a7, a7, 1
      j    10f
9:  srli t4, t4, 7
10: andi t4, t4, 0x7F

    li   t0, 0xFF
    bge  a7, t0, .ret_inf      
    blez a7, 11f
    j    pack
11: li   t0, -6
    blt  a7, t0, .ret_zero    
    li   t1, 1
    sub  t1, t1, a7           
    srl  t4, t4, t1
    li   a7, 0

pack:
    slli t0, t6, 15
    slli t1, a7, 7
    or   a0, t0, t1
    or   a0, a0, t4
    ret

.ret_a:
    ret
.ret_b:
    mv   a0, a1
    ret
.ret_inf:
    li   a0, 0x7F80
    slli t0, t6, 15
    or   a0, a0, t0
    ret
.ret_qnan:
    li   a0, 0x7FC0
    ret
.ret_zero:
    slli a0, t6, 15
    ret

```
### static inline bf16_t bf16_div(bf16_t a, bf16_t b)
```
    .text
    .globl bf16_div
    .globl main

main:
    li   a0, 0x40C0            # a = 6.0 (bf16)
    li   a1, 0x4040            # b = 3.0 (bf16)
    jal  ra, bf16_div          # a0 <- result
    mv   a2, a0                # 0x4000

done:
    j    done

bf16_div:

    srli t0, a0, 15              # sign_a
    andi t0, t0, 1
    srli t1, a1, 15              # sign_b
    andi t1, t1, 1
    xor  t6, t0, t1              # result_sign -> t6

    srli a2, a0, 7               # exp_a
    andi a2, a2, 0xFF
    srli a3, a1, 7               # exp_b
    andi a3, a3, 0xFF
    andi a4, a0, 0x7F            # mant_a
    andi a5, a1, 0x7F            # mant_b


    li   t2, 0xFF
    bne  a3, t2, 1f              
      bnez a5, .ret_b            
      # b = Inf
      beq  a2, t2, .ret_bf16_nan 
      j    .ret_signed_zero      
1:
    or   t0, a3, a5
    bnez t0, 2f
      
      or   t1, a2, a4
      beqz t1, .ret_bf16_nan
      j    .ret_signed_inf
2:
    bne  a2, t2, 3f
      bnez a4, .ret_a            
      j    .ret_signed_inf       
3:
    or   t0, a2, a4
    beqz t0, .ret_signed_zero

    bnez a2, 4f
    j    5f
4:  ori  a4, a4, 0x80            
5:
    bnez a3, 6f
    j    7f
6:  ori  a5, a5, 0x80            
7:
    slli t4, a4, 15              # dividend
    add  t5, x0, a5              # divisor
    li   t2, 0                   # quotient
    li   t3, 0                   # i

    add  a7, a2, x0
    sub  a7, a7, a3
    addi a7, a7, 127
    bnez a2, 8f
      addi a7, a7, -1            # !exp_a → --
8:  bnez a3, 9f
      addi a7, a7, 1             # !exp_b → ++
9:
div_loop:
    slli t2, t2, 1               # quotient <<= 1
    li   t0, 15
    sub  t0, t0, t3              # k = 15 - i
    sll  t1, t5, t0              # tmp = divisor << k
    sltu t0, t4, t1              # dividend < tmp ?
    bne  t0, x0, 10f
      sub  t4, t4, t1            # dividend -= tmp
      ori  t2, t2, 1             # quotient |= 1
10:
    addi t3, t3, 1
    li   t0, 16
    blt  t3, t0, div_loop

    li   t0, 0x8000
    and  t1, t2, t0
    bnez t1, 11f
norm_loop:
    and  t1, t2, t0
    bnez t1, 12f
    li   t1, 1
    ble  a7, t1, 12f            
    slli t2, t2, 1               
    addi a7, a7, -1              
    j    norm_loop
11: srli t2, t2, 8
    j    13f
12: srli t2, t2, 8
13: andi t2, t2, 0x7F            

    li   t0, 0xFF
    bge  a7, t0, .ret_signed_inf 
    blez a7, .ret_signed_zero    

    slli t0, t6, 15              # sign<<15
    slli t1, a7, 7               # (exp&0xFF)<<7
    or   a0, t0, t1
    or   a0, a0, t2              # | mant(7 bits)
    ret

.ret_a:
    ret
.ret_b:
    mv   a0, a1
    ret
.ret_bf16_nan:
    li   a0, 0x7FC0              
    ret
.ret_signed_inf:
    li   a0, 0x7F80
    slli t0, t6, 15
    or   a0, a0, t0
    ret
.ret_signed_zero:
    slli a0, t6, 15
    ret
```

