Add Problem 18.5 exercise

This commit is contained in:
James Stine 2025-04-11 10:04:27 -05:00
parent 2ad4f20900
commit 0e141e6229
4 changed files with 285 additions and 0 deletions

View file

@ -0,0 +1,21 @@
TARGET = gf_inv
$(TARGET).objdump: $(TARGET)
riscv64-unknown-elf-objdump -Dls $(TARGET) > $(TARGET).objdump
$(TARGET): $(TARGET).S Makefile
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32gc -mabi=ilp32 -mcmodel=medany \
-nostartfiles -nostdlib -T../../link/link.ld $(TARGET).S
sim:
spike --isa=rv32gc_zicsr_zicntr +signature=$(TARGET).signature.output +signature-granularity=4 $(TARGET)
diff --ignore-case $(TARGET).signature.output $(TARGET).reference_output || exit
echo "Signature matches! Success!"
clean:
rm -f $(TARGET) $(TARGET).objdump $(TARGET).signature.output
rm -f *~

View file

@ -0,0 +1,80 @@
Extended Euclidean Algorithm
EEA Cycle Estimates
Main loop body: 25
swap_and_negate: 22
gf_degree: 10
Pseuo-Code
r0 := m
r1 := a
s0 := 0
s1 := 1
while r1 \neq 0:
deg_r0 = degree(r0)
deg_r1 = degree(r1)
shift = deg_r0 - deg_r1
if shift < 0:
swap(r0, r1)
swap(s0, s1)
shift := -shift
r0 = r0 ^ (r1 << shift)
s0 = s0 ^ (s1 << shift)
if r0 \neq 1:
return "No inverse"
else:
return s0
LaTeX
------
\documentclass{article}
\usepackage{algorithm}
\usepackage{algpseudocode}
\usepackage{amsmath}
\begin{document}
\begin{algorithm}
\caption{Extended Euclidean Algorithm in GF(2\textsuperscript{8})}
\begin{algorithmic}[1]
\Require Input value $a$, modulus $m$ (usually $0x11B$)
\Ensure Return $s_0$ such that $s_0 \cdot a \equiv 1 \pmod{m}$ if inverse exists
\State $r_0 \gets m$
\State $r_1 \gets a$
\State $s_0 \gets 0$
\State $s_1 \gets 1$
\While{$r_1 \ne 0$}
\State $d_0 \gets \text{deg}(r_0)$
\State $d_1 \gets \text{deg}(r_1)$
\State $\text{shift} \gets d_0 - d_1$
\If{$\text{shift} < 0$}
\State Swap $r_0 \leftrightarrow r_1$
\State Swap $s_0 \leftrightarrow s_1$
\State $\text{shift} \gets -\text{shift}$
\EndIf
\State $r_0 \gets r_0 \oplus (r_1 \ll \text{shift})$
\State $s_0 \gets s_0 \oplus (s_1 \ll \text{shift})$
\State Mask $r_0$ and $s_0$ to 9 bits: $r_0 \gets r_0 \mathbin{\&} 0x1FF$, $s_0 \gets s_0 \mathbin{\&} 0x1FF$
\EndWhile
\If{$r_0 = 1$}
\State \Return $s_0$ \Comment{Inverse found}
\Else
\State \Return \textbf{error} \Comment{No inverse exists}
\EndIf
\end{algorithmic}
\end{algorithm}
\end{document}

View file

@ -0,0 +1,182 @@
// 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

View file

@ -0,0 +1,2 @@
00000092
00000398