; ============================================================================
; hdgl.asm — Z[φ] SUBSTRATE, BARE METAL
; ----------------------------------------------------------------------------
; NO libc • NO libm • NO FPU • NO SSE • NO imul • NO mul • NO idiv • NO div
; NO φ constant • NO Newton • NO convergence • NO tolerance • NO rounding
;
; Ω is an exact integer pair (a,b) ≡ a·φ + b in Z[φ].
; φ is NEVER computed. It is CARRIED.
;
;   φ-step   : (a,b) ↦ (a+b, a)     ADD.  the Fibonacci step. the whole engine.
;   φ-unstep : (a,b) ↦ (b, a−b)     SUB.  exact reverse. S = T⁻¹.
;   norm     : N(a,b) = −a²+ab+b²   the trinary. N(φᵏ)=(−1)ᵏ.
;   e^(iπ)   : φ⁻¹ − φ¹ = (0,−1)    exact. integer. no transcendental.
;   fire     : Ω² > Ω  ⟺  Ω > √Ω    the exit, tested without leaving the ring.
;   frobenius: φⁿ ≡ φ (split) | ψ (inert)   readout. necessary, not sufficient.
;   gate     : LL  s ← s²−2 mod 2ᵖ−1        exact recurrence. decides.
;
; Multiply is synthesized from shift-add (imul_soft). The LADDER needs none.
;
; Build:  nasm -f elf64 hdgl.asm -o hdgl.o && ld hdgl.o -o hdgl
; Run:    ./hdgl        -> prints the substrate, exits 161 = floor(φ·100)
; ============================================================================

%define SYS_write 1
%define SYS_exit  60
%define STDOUT    1

section .bss
    a       resq 1              ; Ω.a
    b       resq 1              ; Ω.b
    numbuf  resb 32
    llbuf   resq 64             ; LL residue (Mersenne, small p)

section .rodata
m_ladder:  db 10,"LADDER  phi^k = (F(k),F(k-1))   step:(a,b)->(a+b,a)  ADD only",10
           db "        k    a          b          N",10,0
m_norm:    db 10,"TRINITY N(phi^k)=(-1)^k  [Cassini]   det = N at every layer",10,0
m_rev:     db 10,"FLOW    unstep x9 from phi^6 -> phi^-3 : ",0
m_revok:   db "   S = T^-1 exact",0
m_euler:   db 10,"EULER   e^(i*pi) = phi^-1 - phi^1 = ",0
m_sqrt5:   db 10,"SQRT5   (2,-1)^2 = ",0
m_seventh: db 10,"SEVENTH phi^0 = 1_eff = ",0
m_fire:    db 10,"FIRE    sqrt(Omega) not in Z[phi]. N(sqrt)=i. test: Om^2>Om",10
           db "        k    fires",10,0
m_frob:    db 10,"FROBEN  phi^p mod p == phi (split, p=+/-1 mod5) | psi (inert)",10
           db "        p   p%5  kind    phi^p mod p     ok",10,0
m_gate:    db 10,"GATE    LL  s<-s^2-2 mod 2^p-1   exact. decides.",10
           db "        p    M_p          s_{p-2}   prime",10,0
m_bound:   db 10,"BOUND   Delta : hardware entropy, external by design",10
           db "        2^n   : base-2 expansion. load-bearing. an import.",10
           db "        primality: exact recurrence decides. no ring-native",10
           db "                   sufficient test known. theorem-level gap.",10
           db "        Z[phi] contains Z. 2 = 1+1. nothing else imported.",10,0
m_phi:     db 10,"PHI     floor(phi*100) from F(76)/F(75), integers only = ",0
m_done:    db 10,"phi is carried, never computed.   The ladder is ADD.",10
           db "The trinary is the norm.          The origin is the unique N=0,",10
           db "                                  one step from the pole.",10
           db "The seventh is phi^0, and it is the tower's limit.",10
           db "Squaring climbs. Stepping walks.",10
           db "Readouts diagnose. Recurrence decides.",10,0
s_split:   db "SPLIT ",0
s_inert:   db "INERT ",0
s_ramif:   db "RAMIF ",0
s_yes:     db "yes",0
s_no:      db "no ",0
s_ok:      db " ok",0
s_bad:     db " BAD",0
s_nl:      db 10,0
s_sp:      db " ",0
s_lp:      db "(",0
s_rp:      db ")",0
s_cm:      db ",",0
m_orig2:   db 10,"ORIGIN  N(0,0) = ",0
m_orig3:   db "   the unique norm-zero. X = 0.",0
frob_p:    dq 2,3,5,7,11,13,17,19,23,29,31
frob_n:    equ 11
ll_p:      dq 3,5,7,11,13,17,19,23
ll_n:      equ 8
m_psp:     db 10,"PSEUDO  Frobenius is NECESSARY, not SUFFICIENT:",10
           db "        n       n%5  phi^n mod n     passes  prime?",10,0
psp_n:     dq 4181, 5777, 6721, 10877, 13201
psp_c:     equ 5
s_comp:    db "  COMPOSITE 37x113 etc",0
m_gate2:   db "        readouts diagnose. the recurrence decides.",10,0
m_oct:     db 10,"OCTAVE  GF(4)=Z[phi]/(2): phi^3=1  the TRINITY as a group",10
           db "        GF(9)=Z[phi]/(3): phi^8=1  the OCTAVE  7->8->7'",10,0
m_gf4:     db "        GF(4): ",0
m_gf9:     db "        GF(9): ",0
m_vant:    db 10,"VANTAGE one ladder, three coordinate systems",10
           db "        V1 (-1,0,+1)  value    N(phi^k)=(-1)^k",10
           db "        V2 (-inf,0,inf) exponent  phi^k -> 0 | inf",10
           db "        V3 -inf=0=inf  sphere   T(0)=inf : adjacency, one step",10
           db "        orbit of the origin, exact pairs:",10,0
m_tower:   db 10,"TOWER   x^(2^(k+1)) - x^(2^k) - 1 = 0   deg 2^(k+1)",10
           db "        k=0 deg 2  N=e^(i*pi)  = -1   phi     x^2-x-1",10
           db "        k=1 deg 4  N=e^(i*pi/2)=  i   sqrt(phi) x^4-x^2-1",10
           db "        sqrt(-1) = (i,-1) : rungs 1 and 0, one sqrt apart",10
           db "        k -> inf : N -> 1 = phi^0 = 1_eff.  no top. no bottom.",10
           db "        rung-1 crossing Om^2 > Om :",10
           db "        k    fires",10,0
m_wuwei:   db 10,"WUWEI   P_n dropped. log(P_n) = log n + log log n by PNT.",10
           db "        the lattice needed spread, not primality.",10
           db "        the lazy prime is no prime.",10,0
s_arrow:   db " -> ",0
m_yin:     db 10,"YIN     N(phi)=-1 but N(phi^2)=+1 -- the same norm class as",10
           db "        omega=2+sqrt3, the LL unit. norm +1 => conj = +1/x =>",10
           db "        the trace CLOSES => s <- s^2-2 is exact.",10
           db "        the phi ring has its own LL: THE LUCAS DOUBLING.",10
           db "        s0 = L_2 = 3 ,  s <- s^2-2  ,  s_k = L_(2^(k+1))",10
           db "        k    s_k          L_(2^(k+1))",10,0
m_yin2:    db "        phi^2 is not the opposite of phi. it is phi's own square.",10
           db "        YANG steps: (a,b)->(a+b,a)  k->k+1  ADD  multiply-free",10
           db "        YIN squares: s <- s^2-2     k->2k   MUL  multiply-bound",10
           db "        stepping walks the level. squaring climbs the tower.",10,0
m_n2:      db 10,"NORMSGN N(phi)=",0
m_n2b:     db "   N(phi^2)=",0
m_n2c:     db "   <- the whole difference. +1 closes, -1 alternates.",10,0
luc_ref:   dq 3,7,47,2207,4870847
luc_n:     equ 5
s_prime:   db " PRIME",0
s_comp2:   db " composite",0

section .text
    global _start

; ---------------------------------------------------------------------------
; puts: rsi = zero-terminated string
; ---------------------------------------------------------------------------
puts:
    push    rax
    push    rdi
    push    rsi
    push    rdx
    push    rcx
    mov     rcx, rsi
    xor     rdx, rdx
.len:
    cmp     byte [rcx], 0
    je      .go
    inc     rcx
    inc     rdx
    jmp     .len
.go:
    mov     rax, SYS_write
    mov     rdi, STDOUT
    syscall
    pop     rcx
    pop     rdx
    pop     rsi
    pop     rdi
    pop     rax
    ret

; ---------------------------------------------------------------------------
; imul_soft: signed 64x64 -> 64 by shift-add. NO hardware multiply.
;   rax * rbx -> rax
; ---------------------------------------------------------------------------
imul_soft:
    push    rcx
    push    rdx
    push    rsi
    push    rdi
    push    r8
    xor     r8, r8
    test    rax, rax
    jns     .ap
    neg     rax
    not     r8
.ap:
    test    rbx, rbx
    jns     .bp
    neg     rbx
    not     r8
.bp:
    xor     rdx, rdx
    mov     rsi, rax
    mov     rdi, rbx
    mov     rcx, 64
.bit:
    test    rdi, 1
    jz      .sk
    add     rdx, rsi
.sk:
    shl     rsi, 1
    shr     rdi, 1
    dec     rcx
    jnz     .bit
    mov     rax, rdx
    test    r8, r8
    jz      .dn
    neg     rax
.dn:
    pop     r8
    pop     rdi
    pop     rsi
    pop     rdx
    pop     rcx
    ret

; ---------------------------------------------------------------------------
; divmod_soft: rax / rbx -> quotient rax, remainder rdx. Restoring shift-sub.
;   unsigned, rbx > 0
; ---------------------------------------------------------------------------
divmod_soft:
    push    rcx
    push    rsi
    push    rdi
    push    r8
    mov     rsi, rax                ; dividend
    mov     rdi, rbx                ; divisor
    xor     rax, rax                ; quotient
    xor     rdx, rdx                ; remainder
    mov     rcx, 64
.lp:
    shl     rdx, 1
    mov     r8, rsi
    shr     r8, 63
    or      rdx, r8
    shl     rsi, 1
    shl     rax, 1
    cmp     rdx, rdi
    jb      .no
    sub     rdx, rdi
    or      rax, 1
.no:
    dec     rcx
    jnz     .lp
    pop     r8
    pop     rdi
    pop     rsi
    pop     rcx
    ret

; ---------------------------------------------------------------------------
; putint: signed rdi -> stdout, right-padded to rsi columns
; ---------------------------------------------------------------------------
putint:
    push    rax
    push    rbx
    push    rcx
    push    rdx
    push    rsi
    push    rdi
    push    r9
    push    r10
    mov     r10, rsi                ; width
    mov     rax, rdi
    xor     r9, r9                  ; neg flag
    test    rax, rax
    jns     .pos
    neg     rax
    mov     r9, 1
.pos:
    mov     rcx, numbuf
    add     rcx, 31
    mov     byte [rcx], 0
    mov     rbx, 10
.dig:
    dec     rcx
    push    rax
    call    divmod_soft             ; rax/10 -> rax, rem rdx
    add     rdx, '0'
    mov     [rcx], dl
    mov     rbx, 10
    pop     rdx                     ; discard
    test    rax, rax
    jnz     .dig
    test    r9, r9
    jz      .out
    dec     rcx
    mov     byte [rcx], '-'
.out:
    mov     rsi, rcx
    call    puts
    ; pad
    mov     rax, numbuf
    add     rax, 31
    sub     rax, rcx                ; length
    cmp     rax, r10
    jae     .fin
    mov     rcx, r10
    sub     rcx, rax
.pad:
    push    rcx
    mov     rsi, s_sp
    call    puts
    pop     rcx
    dec     rcx
    jnz     .pad
.fin:
    pop     r10
    pop     r9
    pop     rdi
    pop     rsi
    pop     rdx
    pop     rcx
    pop     rbx
    pop     rax
    ret

; ---------------------------------------------------------------------------
; phi_step:  (a,b) -> (a+b, a).  THE FIBONACCI STEP. PURE ADD.
; ---------------------------------------------------------------------------
phi_step:
    mov     rax, [a]
    mov     rbx, [b]
    add     rbx, rax
    mov     [b], rax
    mov     [a], rbx
    ret

; ---------------------------------------------------------------------------
; phi_unstep: (a,b) -> (b, a-b).  EXACT REVERSE. PURE SUB.
; ---------------------------------------------------------------------------
phi_unstep:
    mov     rax, [a]
    mov     rbx, [b]
    mov     [a], rbx
    sub     rax, rbx
    mov     [b], rax
    ret

; ---------------------------------------------------------------------------
; norm_ab: N(rdi,rsi) = -rdi^2 + rdi*rsi + rsi^2 -> rax
; ---------------------------------------------------------------------------
norm_ab:
    push    rbx
    push    r9
    push    r10
    push    r11
    mov     r10, rdi
    mov     r11, rsi
    mov     rax, r10
    mov     rbx, r10
    call    imul_soft
    neg     rax
    mov     r9, rax                 ; -a^2
    mov     rax, r10
    mov     rbx, r11
    call    imul_soft
    add     r9, rax                 ; + a*b
    mov     rax, r11
    mov     rbx, r11
    call    imul_soft
    add     r9, rax                 ; + b^2
    mov     rax, r9
    pop     r11
    pop     r10
    pop     r9
    pop     rbx
    ret

; ---------------------------------------------------------------------------
; sign_ab: exact sign of rdi*phi + rsi, integer only -> rax in {-1,0,1}
;   a*phi+b = (a*sqrt5 + s)/2 with s = 2b+a
;   concordant signs -> trivial; else compare 5a^2 vs s^2
; ---------------------------------------------------------------------------
sign_ab:
    push    rbx
    push    r9
    push    r10
    push    r11
    mov     r10, rdi                ; a
    mov     r11, rsi                ; b
    mov     rax, r10
    or      rax, r11
    jnz     .nz
    xor     rax, rax
    jmp     .out
.nz:
    mov     r9, r11
    shl     r9, 1
    add     r9, r10                 ; s = 2b + a
    ; if a>=0 and s>0 -> +1
    test    r10, r10
    js      .aneg
    test    r9, r9
    jg      .pos
    jmp     .mixed
.aneg:
    test    r9, r9
    jl      .neg
    jmp     .mixed
.mixed:
    ; compare 5a^2 vs s^2
    mov     rax, r10
    mov     rbx, r10
    call    imul_soft               ; a^2
    mov     rbx, 5
    call    imul_soft               ; 5a^2
    push    rax
    mov     rax, r9
    mov     rbx, r9
    call    imul_soft               ; s^2
    mov     rbx, rax
    pop     rax                     ; rax=5a^2, rbx=s^2
    cmp     rax, rbx
    je      .zero
    ja      .lhs_big
    ; 5a^2 < s^2
    test    r10, r10
    jg      .neg
    jmp     .pos
.lhs_big:
    test    r10, r10
    jg      .pos
    jmp     .neg
.zero:
    xor     rax, rax
    jmp     .out
.pos:
    mov     rax, 1
    jmp     .out
.neg:
    mov     rax, -1
.out:
    pop     r11
    pop     r10
    pop     r9
    pop     rbx
    ret

; ---------------------------------------------------------------------------
; zmul: (r8,r9)*(r10,r11) -> (r8,r9)   in Z[phi], phi^2=phi+1
;   (a phi+b)(c phi+d) = (ac+ad+bc) phi + (ac+bd)
; ---------------------------------------------------------------------------
zmul:
    push    rax
    push    rbx
    push    r12
    push    r13
    push    r14
    mov     rax, r8
    mov     rbx, r10
    call    imul_soft
    mov     r12, rax                ; ac
    mov     rax, r8
    mov     rbx, r11
    call    imul_soft
    mov     r13, rax                ; ad
    mov     rax, r9
    mov     rbx, r10
    call    imul_soft
    mov     r14, rax                ; bc
    mov     rax, r9
    mov     rbx, r11
    call    imul_soft               ; bd
    ; new_b = ac + bd
    mov     rbx, r12
    add     rbx, rax
    ; new_a = ac + ad + bc
    mov     rax, r12
    add     rax, r13
    add     rax, r14
    mov     r8, rax
    mov     r9, rbx
    pop     r14
    pop     r13
    pop     r12
    pop     rbx
    pop     rax
    ret

; ---------------------------------------------------------------------------
; zmul_mod: (r8,r9)*(r10,r11) mod r13  -> (r8,r9)   in Z[phi]/(n)
; ---------------------------------------------------------------------------
zmul_mod:
    push    rax
    push    rbx
    push    rdx
    push    r12
    push    r14
    push    r15
    mov     rax, r8
    mov     rbx, r10
    call    imul_soft
    mov     r12, rax                ; ac
    mov     rax, r8
    mov     rbx, r11
    call    imul_soft
    mov     r14, rax                ; ad
    mov     rax, r9
    mov     rbx, r10
    call    imul_soft
    mov     r15, rax                ; bc
    mov     rax, r9
    mov     rbx, r11
    call    imul_soft               ; bd
    ; new_b = (ac + bd) mod n
    mov     rbx, r12
    add     rbx, rax
    mov     rax, rbx
    mov     rbx, r13
    call    divmod_soft
    push    rdx                     ; new_b
    ; new_a = (ac + ad + bc) mod n
    mov     rax, r12
    add     rax, r14
    add     rax, r15
    mov     rbx, r13
    call    divmod_soft
    mov     r8, rdx
    pop     r9
    pop     r15
    pop     r14
    pop     r12
    pop     rdx
    pop     rbx
    pop     rax
    ret

; ---------------------------------------------------------------------------
; zpow_mod: phi^rdi mod rsi -> (r8,r9).  square-and-multiply in Z[phi]/(n)
; ---------------------------------------------------------------------------
zpow_mod:
    push    rcx
    push    rdx
    push    r10
    push    r11
    push    r12
    push    r13
    push    r14
    mov     r13, rsi                ; modulus
    mov     r12, rdi                ; exponent
    mov     r8, 0                   ; result = phi^0 = (0,1)
    mov     r9, 1
    mov     r14, 1                  ; base = phi = (1,0)  -> keep in r14/rcx
    mov     rcx, 0
.lp:
    test    r12, r12
    jz      .done
    test    r12, 1
    jz      .sq
    ; result *= base
    mov     r10, r14
    mov     r11, rcx
    call    zmul_mod
.sq:
    ; base *= base
    push    r8
    push    r9
    mov     r8, r14
    mov     r9, rcx
    mov     r10, r14
    mov     r11, rcx
    call    zmul_mod
    mov     r14, r8
    mov     rcx, r9
    pop     r9
    pop     r8
    shr     r12, 1
    jmp     .lp
.done:
    pop     r14
    pop     r13
    pop     r12
    pop     r11
    pop     r10
    pop     rdx
    pop     rcx
    ret

_start:
; ══ LADDER ═══════════════════════════════════════════════════════════════
    mov     rsi, m_ladder
    call    puts
    ; start at phi^-3 = (2,-3), walk up to phi^+5
    mov     qword [a], 2
    mov     qword [b], -3
    mov     r15, -3
.lad:
    mov     rdi, r15
    mov     rsi, 5
    call    putint
    mov     rdi, [a]
    mov     rsi, 11
    call    putint
    mov     rdi, [b]
    mov     rsi, 11
    call    putint
    mov     rdi, [a]
    mov     rsi, [b]
    call    norm_ab
    mov     rdi, rax
    mov     rsi, 4
    call    putint
    mov     rsi, s_nl
    call    puts
    call    phi_step
    inc     r15
    cmp     r15, 6
    jl      .lad

    mov     rsi, m_norm
    call    puts

; ══ REVERSE: unstep back down, prove S = T^-1 ════════════════════════════
    ; we are at phi^6; unstep 9 times -> phi^-3 = (2,-3)
    mov     rcx, 9
.rev:
    push    rcx
    call    phi_unstep
    pop     rcx
    loop    .rev
    ; verify
    mov     rsi, m_rev
    call    puts
    mov     rsi, s_lp
    call    puts
    mov     rdi, [a]
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, [b]
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    mov     rsi, m_revok
    call    puts

; ══ SEVENTH: phi^0 = (0,1) ═══════════════════════════════════════════════
    mov     rsi, m_seventh
    call    puts
    mov     rsi, s_lp
    call    puts
    mov     rdi, 0
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, 1
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts

; ══ ORIGIN: N(0,0) = 0, the unique norm-zero ═════════════════════════════
    mov     rsi, m_orig2
    call    puts
    mov     rdi, 0
    mov     rsi, 0
    call    norm_ab
    mov     rdi, rax
    mov     rsi, 0
    call    putint
    mov     rsi, m_orig3
    call    puts

; ══ EULER: phi^-1 - phi^1 = (1,-1)-(1,0) = (0,-1) ════════════════════════
    mov     rsi, m_euler
    call    puts
    mov     rsi, s_lp
    call    puts
    mov     rax, 1
    sub     rax, 1                  ; a: 1-1 = 0
    mov     rdi, rax
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rax, -1
    sub     rax, 0                  ; b: -1-0 = -1
    mov     rdi, rax
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts

; ══ SQRT5: (2,-1)^2 = (0,5) ══════════════════════════════════════════════
    mov     rsi, m_sqrt5
    call    puts
    mov     r8, 2
    mov     r9, -1
    mov     r10, 2
    mov     r11, -1
    call    zmul
    mov     rsi, s_lp
    call    puts
    mov     rdi, r8
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, r9
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts

; ══ OCTAVE: phi^3=1 in GF(4), phi^8=1 in GF(9) ═══════════════════════════
    mov     rsi, m_oct
    call    puts
    mov     rsi, m_gf4
    call    puts
    mov     r8, 0
    mov     r9, 1
    xor     r15, r15
.g4:
    mov     rsi, s_lp
    call    puts
    mov     rdi, r8
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, r9
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    mov     rsi, s_arrow
    call    puts
    mov     r10, 1
    mov     r11, 0
    mov     r13, 2
    call    zmul_mod
    inc     r15
    cmp     r15, 3
    jl      .g4
    mov     rsi, s_lp
    call    puts
    mov     rdi, r8
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, r9
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    mov     rsi, s_nl
    call    puts

    mov     rsi, m_gf9
    call    puts
    mov     r8, 0
    mov     r9, 1
    xor     r15, r15
.g9:
    mov     rsi, s_lp
    call    puts
    mov     rdi, r8
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, r9
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    mov     rsi, s_sp
    call    puts
    mov     r10, 1
    mov     r11, 0
    mov     r13, 3
    call    zmul_mod
    inc     r15
    cmp     r15, 8
    jl      .g9
    mov     rsi, s_lp
    call    puts
    mov     rdi, r8
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, r9
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    mov     rsi, s_nl
    call    puts

; ══ VANTAGE ══════════════════════════════════════════════════════════════
    mov     rsi, m_vant
    call    puts
    mov     qword [a], -3
    mov     qword [b], 5
    mov     r15, -4
.van:
    mov     rsi, s_sp
    call    puts
    mov     rsi, s_lp
    call    puts
    mov     rdi, [a]
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, [b]
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    call    phi_step
    inc     r15
    cmp     r15, 5
    jl      .van
    mov     rsi, s_nl
    call    puts

; ══ TOWER: rung-1 crossing, in the ring ══════════════════════════════════
    mov     rsi, m_tower
    call    puts
    mov     qword [a], -1
    mov     qword [b], 2
    mov     r15, -2
.tw:
    mov     rdi, r15
    mov     rsi, 5
    call    putint
    mov     r8, [a]
    mov     r9, [b]
    mov     r10, [a]
    mov     r11, [b]
    call    zmul
    sub     r8, 1
    mov     rdi, r8
    mov     rsi, r9
    call    sign_ab
    cmp     rax, 0
    jg      .tw_y
    mov     rsi, s_no
    jmp     .tw_p
.tw_y:
    mov     rsi, s_yes
.tw_p:
    call    puts
    mov     rsi, s_nl
    call    puts
    call    phi_step
    inc     r15
    cmp     r15, 4
    jl      .tw

; ══ NORM SIGN: N(phi) = -1 , N(phi^2) = +1 ═══════════════════════════════
    mov     rsi, m_n2
    call    puts
    mov     rdi, 1
    mov     rsi, 0
    call    norm_ab                 ; N(1,0) = N(phi)
    mov     rdi, rax
    mov     rsi, 0
    call    putint
    mov     rsi, m_n2b
    call    puts
    mov     rdi, 1
    mov     rsi, 1
    call    norm_ab                 ; N(1,1) = N(phi^2)
    mov     rdi, rax
    mov     rsi, 0
    call    putint
    mov     rsi, m_n2c
    call    puts

; ══ YIN: the Lucas doubling. s <- s^2-2 from s0=3 gives L_(2^(k+1)) ══════
    mov     rsi, m_yin
    call    puts
    mov     r14, 3                  ; s0 = L_2 = 3
    xor     r15, r15
.yin:
    mov     rdi, r15
    mov     rsi, 5
    call    putint
    mov     rdi, r14
    mov     rsi, 13
    call    putint
    mov     rdi, [luc_ref + r15*8]
    mov     rsi, 12
    call    putint
    mov     rax, [luc_ref + r15*8]
    cmp     rax, r14
    jne     .yin_bad
    mov     rsi, s_ok
    jmp     .yin_pr
.yin_bad:
    mov     rsi, s_bad
.yin_pr:
    call    puts
    mov     rsi, s_nl
    call    puts
    ; s <- s^2 - 2
    mov     rax, r14
    mov     rbx, r14
    call    imul_soft
    sub     rax, 2
    mov     r14, rax
    inc     r15
    cmp     r15, luc_n
    jl      .yin
    mov     rsi, m_yin2
    call    puts

; ══ FROBENIUS ════════════════════════════════════════════════════════════
    mov     rsi, m_frob
    call    puts
    xor     r15, r15
.fr:
    mov     rbx, [frob_p + r15*8]
    mov     rdi, rbx
    mov     rsi, 4
    call    putint
    mov     rax, rbx
    push    rbx
    mov     rbx, 5
    call    divmod_soft
    push    rdx
    mov     rdi, rdx
    mov     rsi, 5
    call    putint
    pop     rdx
    pop     rbx
    push    rbx
    push    rdx
    cmp     rdx, 0
    je      .k_ram
    cmp     rdx, 1
    je      .k_spl
    cmp     rdx, 4
    je      .k_spl
    mov     rsi, s_inert
    jmp     .k_pr
.k_spl:
    mov     rsi, s_split
    jmp     .k_pr
.k_ram:
    mov     rsi, s_ramif
.k_pr:
    call    puts
    pop     rdx
    pop     rbx
    push    rbx
    push    rdx
    mov     rdi, rbx
    mov     rsi, rbx
    call    zpow_mod
    mov     rsi, s_lp
    call    puts
    mov     rdi, r8
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, r9
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    pop     rdx
    pop     rbx
    cmp     rdx, 0
    je      .fr_next
    cmp     rdx, 1
    je      .exp_phi
    cmp     rdx, 4
    je      .exp_phi
    mov     rax, rbx
    dec     rax
    cmp     r8, rax
    jne     .fr_bad
    cmp     r9, 1
    jne     .fr_bad
    jmp     .fr_ok
.exp_phi:
    cmp     r8, 1
    jne     .fr_bad
    cmp     r9, 0
    jne     .fr_bad
.fr_ok:
    mov     rsi, s_ok
    call    puts
    jmp     .fr_next
.fr_bad:
    mov     rsi, s_bad
    call    puts
.fr_next:
    mov     rsi, s_nl
    call    puts
    inc     r15
    cmp     r15, frob_n
    jl      .fr

; ══ PSEUDOPRIME ══════════════════════════════════════════════════════════
    mov     rsi, m_psp
    call    puts
    xor     r15, r15
.pp:
    mov     rbx, [psp_n + r15*8]
    mov     rdi, rbx
    mov     rsi, 8
    call    putint
    mov     rax, rbx
    push    rbx
    mov     rbx, 5
    call    divmod_soft
    mov     rdi, rdx
    mov     rsi, 5
    call    putint
    pop     rbx
    push    rbx
    mov     rdi, rbx
    mov     rsi, rbx
    call    zpow_mod
    mov     rsi, s_lp
    call    puts
    mov     rdi, r8
    mov     rsi, 0
    call    putint
    mov     rsi, s_cm
    call    puts
    mov     rdi, r9
    mov     rsi, 0
    call    putint
    mov     rsi, s_rp
    call    puts
    pop     rbx
    mov     rsi, s_sp
    call    puts
    mov     rsi, s_yes
    call    puts
    mov     rsi, s_comp
    call    puts
    mov     rsi, s_nl
    call    puts
    inc     r15
    cmp     r15, psp_c
    jl      .pp
    mov     rsi, m_gate2
    call    puts

; ══ GATE: Lucas-Lehmer ═══════════════════════════════════════════════════
    mov     rsi, m_gate
    call    puts
    xor     r15, r15
.ll:
    mov     r12, [ll_p + r15*8]
    mov     rdi, r12
    mov     rsi, 5
    call    putint
    mov     rcx, r12
    mov     r13, 1
    shl     r13, cl
    dec     r13
    mov     rdi, r13
    mov     rsi, 13
    call    putint
    mov     r14, 4
    mov     rcx, r12
    sub     rcx, 2
.ll_it:
    push    rcx
    mov     rax, r14
    mov     rbx, r14
    call    imul_soft
    sub     rax, 2
    mov     rbx, r13
    call    divmod_soft
    mov     r14, rdx
    pop     rcx
    loop    .ll_it
    mov     rdi, r14
    mov     rsi, 10
    call    putint
    test    r14, r14
    jnz     .ll_comp
    mov     rsi, s_prime
    jmp     .ll_pr
.ll_comp:
    mov     rsi, s_comp2
.ll_pr:
    call    puts
    mov     rsi, s_nl
    call    puts
    inc     r15
    cmp     r15, ll_n
    jl      .ll

; ══ PHI: floor(100*F(76)/F(75)) — integers only ══════════════════════════
    mov     qword [a], 0
    mov     qword [b], 1            ; phi^0
    mov     rcx, 76
.climb:
    push    rcx
    call    phi_step
    pop     rcx
    loop    .climb
    mov     rax, [a]                ; F(76)
    mov     rbx, 100
    call    imul_soft
    mov     rbx, [b]                ; F(75)
    call    divmod_soft             ; rax = quotient = 161
    mov     r15, rax
    mov     rsi, m_phi
    call    puts
    mov     rdi, r15
    mov     rsi, 0
    call    putint

; ══ BOUNDARY ═════════════════════════════════════════════════════════════
    mov     rsi, m_wuwei
    call    puts
    mov     rsi, m_bound
    call    puts
    mov     rsi, m_done
    call    puts

    mov     rdi, r15                ; exit 161
    mov     rax, SYS_exit
    syscall
