// gf_inv.S // james.stine@okstate.edu 9 April 2025 .text .global rvtest_entry_point rvtest_entry_point: li a0, 0x32 # Input value to invert in GF(2^8) li t0, 0x11B # Modulus: irreducible poly x^8 + x^4 + x^3 + x + 1 # Initialize Extended Euclidean variables: a*x+b*y=gcd(a,b) li t1, 0 # s0 = 0 (old x) li t2, 1 # s1 = 1 (new x) mv t3, t0 # r0 = modulus mv t4, a0 # r1 = input value csrr s8, instret # count instructions at beginning # --- Register usage --- # a0: Input / Final result (return value) # t0: Modulus (0x11B) # t1: s0 (previous x value) # t2: s1 (current x value) # t3: r0 (previous remainder) # t4: r1 (current remainder) # t5: degree(r0) # t6: degree(r1) # a1: argument to gf_degree # a2: shift amount # a3: temporary for SLT result # a4/a5: shift results, temporaries # s8: initial seed of instruction count (instret) # s9: final value of instruction count (instret) # -------------------------------------- # Main loop: Extended Euclidean Division # -------------------------------------- inv_loop: beqz t4, fail # If r1 == 0, input is not invertible → fail # Compute degree of r0 mv a1, t3 # Set a1 = r0 = (modulus m) call gf_degree # Compute deg(r0) mv t5, a0 # degree(r0) # Compute degree of r1 mv a1, t4 # Set a1 = r1 = (input a) call gf_degree # Compute deg(r1) mv t6, a0 # degree (r1) # Compute shift = deg(r0) - deg(r1) sub a2, t5, t6 # alignment r1 with highest term in r0 slt a3, a2, zero # Check if shift < 0 bnez a3, swap_and_negate # Perform r0 ^= r1 << shift # Polynomial subtraction in GF(2) sll a4, t4, a2 xor t3, t3, a4 andi t3, t3, 0x1FF # Mask off 9 bits to stay in GF(2^8) # Update s0: s0 ^= s1 << shift - Update Bezout coefficient sll a5, t2, a2 xor t1, t1, a5 andi t1, t1, 0x1FF # Mask off 9 bits to stay in GF(2^8) # Swap (r0, r1) mv a4, t3 mv t3, t4 mv t4, a4 # Swap (s0, s1) mv a4, t1 mv t1, t2 mv t2, a4 # Check if r0 == 1, then we are done li t5, 1 beq t3, t5, done j inv_loop # ------------------------------------------- # Case: shift < 0 → negate, then apply shift # ------------------------------------------- swap_and_negate: # Swap r0 <-> r1 mv a4, t3 mv t3, t4 mv t4, a4 # Swap s0 <-> s1 mv a4, t1 mv t1, t2 mv t2, a4 # shift = -shift sub a2, zero, a2 # r0 ^= r1 << shift sll a4, t4, a2 xor t3, t3, a4 andi t3, t3, 0x1FF # Mask off to 9 bits again # s0 ^= s1 << shift sll a5, t2, a2 xor t1, t1, a5 andi t1, t1, 0x1FF # Final swap to maintain invariant mv a4, t3 mv t3, t4 mv t4, a4 mv a4, t1 mv t1, t2 mv t2, a4 # Check if r0 == 1 li t5, 1 beq t3, t5, done j inv_loop # ------------------------------------- # Helper: compute degree of a1 (MSB set) # ------------------------------------- gf_degree: li t0, 8 # Start checking from MSB down deg_loop: srl a0, a1, t0 # Right shift a1 by t0 andi a0, a0, 1 # Isolate LSB bnez a0, done_deg # If bit is set, we're done addi t0, t0, -1 bgez t0, deg_loop # Check next bit li a0, 0 # Nothing set ret done_deg: mv a0, t0 ret # --------------------- # Finalize inverse # --------------------- done: mv a0, t1 # Result is a0 andi a0, a0, 0xFF # Mask to 8 bits csrr s9, instret # count instructions at end sub s9, s9, s8 # get number of #instructions executed write_tohost: # HTIF stuff la t1, tohost li t0, 1 # 1 for success, 3 for failure sw t0, 0(t1) # send success code la t0, begin_signature # Address of signature sw a0, 0(t0) # Store result (i.e., a0) sw s9, 4(t0) # record #instructions executed fail: li a0, 0xff # Signal failure: no inverse exists self_loop: j self_loop .section .tohost tohost: # write to HTIF .word 0 fromhost: .word 0 .data .EQU XLEN,32 begin_signature: .fill 2*(XLEN/32),4,0xdeadbeef end_signature: .bss .space 512