files (14).zip (14.1 KB)
; =============================================================================
; HDGL — FOUR-ELEMENT BARE-METAL Z[φ] SUBSTRATE WITH WU-WEI ORACLE
; =============================================================================
;
; TARGET: x86-64 / BIOS / QEMU
; BUILD: nasm -f bin hdgl_wuwei.asm -o hdgl_wuwei.img
; RUN: qemu-system-x86_64 -drive format=raw,file=hdgl_wuwei.img -smp 4 -m 128M -boot c
;
; ARCHITECTURE:
; CPU 0 = FIRE (operator / strategy selector)
; CPU 1 = WATER (inverse verification)
; CPU 2 = EARTH (N_phi pattern oracle)
; CPU 3 = WIND (T(X) fixed-point residual)
;
; WU-WEI ORACLE:
; Each element reports resistance as a SIGNAL, not a failure.
; ORACLE is a bitfield:
; bit 0: WATER invariant broken
; bit 1: EARTH pattern broken (delta not alternating sign)
; bit 2: EARTH magnitude wrong (|delta| != 2)
; bit 3: WIND fixed point detected
; bit 4: WIND diverging
; bit 7: CRITICAL
; FIRE reads ORACLE and selects strategy:
; 0x00 -> FLOWING RIVER (advance normally)
; 0x02 -> NON-ACTION (hold, log)
; 0x04 -> REDIRECT (rebase)
; 0x08 -> CONVERGENCE (log phi approach)
; 0x80+ -> CRITICAL (halt + display)
;
; PHI INVARIANT:
; N_phi(a,b) = -a² + ab + b²
; For Fibonacci pairs: N oscillates ±2 every step.
; This oscillation IS the healthy signal, not a failure.
; EARTH verifies the pattern (alternating ±2), not invariance.
;
; =============================================================================
BITS 16
ORG 0x7C00
; =============================================================================
; CONSTANTS
; =============================================================================
PAYLOAD_PHYS equ 0x00010000
AP_TRAMP_PHYS equ 0x00008000
PML4_PHYS equ 0x00009000
PDPT_PHYS equ 0x0000A000
PD0_PHYS equ 0x0000B000
PD1_PHYS equ 0x0000C000
PD2_PHYS equ 0x0000D000
PD3_PHYS equ 0x0000E000
BSP_STACK equ 0x00070000
AP_STACK_BASE equ 0x00090000
AP_STACK_STRIDE equ 0x00010000
LAPIC_BASE equ 0xFEE00000
LAPIC_ICR_LOW equ 0x300
LAPIC_ICR_HIGH equ 0x310
VGA_BASE equ 0x000B8000
VGA_COLS equ 80 ; characters per row
VGA_ROW equ 160 ; bytes per row
PRINT_EVERY equ 1048576
PRINT_MASK equ PRINT_EVERY - 1
IMAGE_SECTORS equ 64
PAYLOAD_SECTORS equ IMAGE_SECTORS - 1
; =============================================================================
; SHARED STATE LAYOUT (at 0x500000)
; =============================================================================
STATE_A equ 0x00500000 ; Current Omega: a
STATE_B equ 0x00500008 ; Current Omega: b
STATE_K equ 0x00500010 ; Iteration counter
FIRE_A equ 0x00500020 ; FIRE result: a+b
FIRE_B equ 0x00500028 ; FIRE result: a
FIRE_K equ 0x00500030 ; FIRE step counter
WATER_A equ 0x00500040 ; WATER result: b
WATER_B equ 0x00500048 ; WATER result: a-b
EARTH_N equ 0x00500060 ; N_phi(current)
EARTH_N_FIRE equ 0x00500068 ; N_phi(FIRE(current))
EARTH_DELTA equ 0x00500070 ; N_phi(FIRE) - N_phi(current)
EARTH_PREV_DELTA equ 0x00500078 ; Previous delta (for pattern check)
WIND_RES_A equ 0x00500080 ; T(X) phi-coefficient residual
WIND_RES_B equ 0x00500088 ; T(X) constant residual
WIND_FIX equ 0x00500090 ; 1 if at fixed point
REQUEST_K equ 0x005000A0 ; Published step for APs
DONE_WATER equ 0x005000A8
DONE_EARTH equ 0x005000B0
DONE_WIND equ 0x005000B8
READY_MASK equ 0x005000C0
ORACLE equ 0x005000C8 ; Wu-Wei oracle bitfield
TRINARY equ 0x005000D0 ; Trinary projection of N
STRATEGY equ 0x005000D8 ; Current strategy index
YIN equ 0x005000E0 ; Yin: s -> s^2 - 2
PHASE equ 0x005000E8 ; Completion phase 0->3->0
DEPTH equ 0x005000F0 ; Total iteration depth
CPU_COUNT equ 0x00500100
PARALLEL_MODE equ 0x00500108
; Physical address adjustment for 64-bit code
; Label values are ORG-relative (0x7C00+), actual physical = label + PHYS_ADJ
PHYS_ADJ equ 0x8200
; Strategy indices
STRATEGY_FLOWING equ 0 ; Healthy oscillation
STRATEGY_NONACTION equ 1 ; Hold on anomaly
STRATEGY_REDIRECT equ 2 ; Rebase on magnitude error
STRATEGY_CONVERGE equ 3 ; Fixed point detected
STRATEGY_CRITICAL equ 7 ; Halt
; Oracle bits
ORACLE_WATER_BROKEN equ 0x01
ORACLE_EARTH_PATTERN equ 0x02
ORACLE_EARTH_MAGNITUDE equ 0x04
ORACLE_WIND_FIXED equ 0x08
ORACLE_WIND_DIVERGE equ 0x10
ORACLE_CRITICAL equ 0x80
; =============================================================================
; BIOS BOOT
; =============================================================================
boot_start:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
mov [boot_drive], dl
; Load sectors 2..64 to 0x10000
mov si, disk_address_packet
mov dl, [boot_drive]
mov ah, 0x42
int 0x13
jc boot_disk_error
; Copy AP trampoline to 0x8000
; Source: payload at 0x10000 + (ap_trampoline - payload_start_in_file)
; payload_start_in_file = 512 bytes (sector 2)
; ap_trampoline offset within payload = (ap_trampoline - boot_start) - 512
mov ax, 0x1000
mov ds, ax
mov ax, 0x0800
mov es, ax
; SI = offset within payload (NOT offset from boot_start)
mov si, ap_trampoline - boot_start - 512
xor di, di
mov cx, (ap_trampoline_end - ap_trampoline + 1) / 2
cld
rep movsw
xor ax, ax
mov ds, ax
mov es, ax
; A20
in al, 0x92
or al, 00000010b
and al, 11111110b
out 0x92, al
; GDT
lgdt [gdt_ptr]
; Protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword 0x08:PROTECTED_ENTRY_PHYS
boot_disk_error:
mov si, boot_error_msg
.loop:
lodsb
test al, al
jz .halt
mov ah, 0x0E
xor bh, bh
int 0x10
jmp .loop
.halt:
cli
hlt
jmp .halt
; =============================================================================
; DISK ADDRESS PACKET
; =============================================================================
disk_address_packet:
db 0x10, 0x00
dw PAYLOAD_SECTORS
dw 0x0000
dw 0x1000
dq 1
boot_drive: db 0
boot_error_msg: db "HDGL DISK ERROR",0
; =============================================================================
; GDT
; =============================================================================
align 8
gdt_base:
dq 0x0000000000000000 ; null
dq 0x00CF9A000000FFFF ; 0x08: 32-bit code
dq 0x00CF92000000FFFF ; 0x10: data (32 and 64 bit)
dq 0x00AF9A000000FFFF ; 0x18: 64-bit code
gdt_end:
gdt_ptr:
dw gdt_end - gdt_base - 1
dd gdt_base
; =============================================================================
; BOOT SECTOR PAD
; =============================================================================
times 510 - ($ - $$) db 0
dw 0xAA55
; =============================================================================
; PAYLOAD — 32-BIT PROTECTED MODE ENTRY
; =============================================================================
; File offset 512 = physical 0x10200 when loaded.
; PROTECTED_ENTRY_PHYS = 0x10000 + 512 = 0x10200
BITS 32
protected_entry:
cli
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov esp, BSP_STACK
; Build identity page tables (0..4 GiB, 2 MB pages)
call build_page_tables
; PAE
mov eax, cr4
or eax, (1 << 5)
mov cr4, eax
; EFER.LME
mov ecx, 0xC0000080
rdmsr
or eax, (1 << 8)
wrmsr
; CR3
mov eax, PML4_PHYS
mov cr3, eax
; Paging on
mov eax, cr0
or eax, (1 << 31)
mov cr0, eax
; Far jump to 64-bit entry — LONG_MODE_ENTRY_PHYS computed below
jmp dword 0x18:LONG_MODE_ENTRY_PHYS
; =============================================================================
; PAGE TABLE CONSTRUCTION (32-bit)
; =============================================================================
build_page_tables:
pushad
; Zero PML4 + PDPT + 4 PDs = 6 pages = 0x6000 bytes
mov edi, PML4_PHYS
xor eax, eax
mov ecx, 0x6000 / 4
cld
rep stosd
; PML4[0] -> PDPT
mov dword [PML4_PHYS + 0], PDPT_PHYS | 0x003
mov dword [PML4_PHYS + 4], 0
; PDPT[0..3] -> PD0..PD3
mov dword [PDPT_PHYS + 0], PD0_PHYS | 0x003
mov dword [PDPT_PHYS + 4], 0
mov dword [PDPT_PHYS + 8], PD1_PHYS | 0x003
mov dword [PDPT_PHYS + 12], 0
mov dword [PDPT_PHYS + 16], PD2_PHYS | 0x003
mov dword [PDPT_PHYS + 20], 0
mov dword [PDPT_PHYS + 24], PD3_PHYS | 0x003
mov dword [PDPT_PHYS + 28], 0
; PD0: 0..1 GiB (512 entries × 2 MB = 1 GiB)
mov edi, PD0_PHYS
xor eax, eax
mov ecx, 512
.pd0:
mov edx, eax
or edx, 0x83 ; present + RW + huge (2MB)
mov [edi], edx
mov dword [edi+4], 0
add eax, 0x200000
add edi, 8
loop .pd0
; PD1: 1..2 GiB
mov edi, PD1_PHYS
mov eax, 0x40000000
mov ecx, 512
.pd1:
mov edx, eax
or edx, 0x83
mov [edi], edx
mov dword [edi+4], 0
add eax, 0x200000
add edi, 8
loop .pd1
; PD2: 2..3 GiB
mov edi, PD2_PHYS
mov eax, 0x80000000
mov ecx, 512
.pd2:
mov edx, eax
or edx, 0x83
mov [edi], edx
mov dword [edi+4], 0
add eax, 0x200000
add edi, 8
loop .pd2
; PD3: 3..4 GiB (wraps at 4 GiB, ok for identity map)
mov edi, PD3_PHYS
mov eax, 0xC0000000
mov ecx, 512
.pd3:
mov edx, eax
or edx, 0x83
mov [edi], edx
mov dword [edi+4], 0
add eax, 0x200000
add edi, 8
loop .pd3
popad
ret
; =============================================================================
; 64-BIT BSP ENTRY
; =============================================================================
; THIS LABEL MUST BE THE FIRST BITS 64 INSTRUCTION IN THE FILE.
; LONG_MODE_ENTRY_PHYS is computed from its file position.
BITS 64
long_mode_entry:
cli
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov rsp, BSP_STACK
; Detect logical processor count via CPUID
mov eax, 1
cpuid
shr ebx, 16
and ebx, 0xFF
test ebx, ebx
jnz .cpu_ok
mov ebx, 1
.cpu_ok:
mov [CPU_COUNT], rbx
cmp ebx, 4
jb .serial
mov qword [PARALLEL_MODE], 1
jmp .mode_done
.serial:
mov qword [PARALLEL_MODE], 0
.mode_done:
; ─── Canonical initial state: Ω = 0·φ + 1 ───
mov qword [STATE_A], 0
mov qword [STATE_B], 1
mov qword [STATE_K], 0
mov qword [FIRE_A], 0
mov qword [FIRE_B], 1
mov qword [FIRE_K], 0
mov qword [WATER_A], 0
mov qword [WATER_B], 1
mov qword [EARTH_N], 1 ; N(0,1) = 1
mov qword [EARTH_N_FIRE], 0
mov qword [EARTH_DELTA], 0
mov qword [EARTH_PREV_DELTA], 0 ; no previous delta yet
mov qword [WIND_RES_A], 0
mov qword [WIND_RES_B], 0
mov qword [WIND_FIX], 0
mov qword [REQUEST_K], 0
mov qword [DONE_WATER], 0
mov qword [DONE_EARTH], 0
mov qword [DONE_WIND], 0
mov qword [READY_MASK], 1
mov qword [ORACLE], 0
mov qword [TRINARY], 0
mov qword [STRATEGY], STRATEGY_FLOWING
mov qword [YIN], 2
mov qword [PHASE], 0
mov qword [DEPTH], 0
; VGA init
call vga_init
; Launch APs if multi-core
cmp qword [PARALLEL_MODE], 1
jne .bsp_fire
call start_aps
.bsp_fire:
call role_fire
.halt:
cli
hlt
jmp .halt
; =============================================================================
; START APPLICATION PROCESSORS
; =============================================================================
start_aps:
; Enable BSP local APIC
mov ecx, 0x1B
rdmsr
or eax, 0x800
wrmsr
mov r8, LAPIC_BASE
; INIT IPI to all excluding self
mov dword [r8 + LAPIC_ICR_HIGH], 0
mov dword [r8 + LAPIC_ICR_LOW], 0x000C4500
call apic_wait
; SIPI #1 — vector 0x08 -> physical 0x8000
mov dword [r8 + LAPIC_ICR_HIGH], 0
mov dword [r8 + LAPIC_ICR_LOW], 0x000C4608
call apic_wait
; SIPI #2
mov dword [r8 + LAPIC_ICR_HIGH], 0
mov dword [r8 + LAPIC_ICR_LOW], 0x000C4608
call apic_wait
; Wait for all 4 CPUs to set their bits in READY_MASK
.wait_aps:
mov rax, [READY_MASK]
and eax, 0xF
cmp eax, 0xF
jne .wait_aps
ret
apic_wait:
mov ecx, 100000
.spin:
pause
loop .spin
ret
; =============================================================================
; FIRE — CPU 0 (Operator / Strategy Selector)
; =============================================================================
role_fire:
mov qword [READY_MASK], 1 ; mark CPU 0 ready
fire_cycle:
; ── Snapshot current Ω ──
mov r8, [STATE_A]
mov r9, [STATE_B]
mov r10, [STATE_K]
; ── FIRE: (a,b) -> (a+b, a) ──
mov rax, r8
add rax, r9
mov [FIRE_A], rax
mov [FIRE_B], r8
inc r10
mov [FIRE_K], r10
; ── Serial or parallel path ──
cmp qword [PARALLEL_MODE], 0
je .serial
; Parallel: publish request and wait
mov [REQUEST_K], r10
.wait_water:
mov rax, [DONE_WATER]
cmp rax, r10
jne .wait_water
.wait_earth:
mov rax, [DONE_EARTH]
cmp rax, r10
jne .wait_earth
.wait_wind:
mov rax, [DONE_WIND]
cmp rax, r10
jne .wait_wind
jmp .commit
.serial:
call water_compute
call earth_compute
call wind_compute
.commit:
; ── Wu-Wei strategy selection ──
mov rax, [ORACLE]
call fire_select_strategy
; ── Commit FIRE result as new canonical state ──
; (strategy may modify this later - for now, always advance)
mov rax, [FIRE_A]
mov rbx, [FIRE_B]
mov [STATE_A], rax
mov [STATE_B], rbx
mov [STATE_K], r10
; ── YIN: s -> s² - 2 ──
mov rax, [YIN]
imul rax, rax
sub rax, 2
mov [YIN], rax
; ── Completion: 0->1->2->3->0 ──
inc qword [PHASE]
and qword [PHASE], 3
; ── Depth ──
inc qword [DEPTH]
; ── Display every PRINT_EVERY iterations ──
mov rax, r10
test rax, PRINT_MASK
jnz fire_cycle
call vga_update
jmp fire_cycle
; ============================================================================
; FIRE: WU-WEI STRATEGY SELECTOR
; Input: rax = ORACLE bitfield
; ============================================================================
fire_select_strategy:
; CRITICAL: halt and display
test al, ORACLE_CRITICAL
jnz .critical
; EARTH magnitude wrong: redirect (rebase)
test al, ORACLE_EARTH_MAGNITUDE
jnz .redirect
; EARTH pattern broken: non-action
test al, ORACLE_EARTH_PATTERN
jnz .nonaction
; WIND convergence: log it
test al, ORACLE_WIND_FIXED
jnz .converge
; WATER broken: flag but continue
test al, ORACLE_WATER_BROKEN
jnz .water_anom
; All clear
mov qword [STRATEGY], STRATEGY_FLOWING
ret
.critical:
mov qword [STRATEGY], STRATEGY_CRITICAL
call vga_update ; force display
cli
hlt ; deliberate halt on critical
jmp .critical
.redirect:
mov qword [STRATEGY], STRATEGY_REDIRECT
; Rebase: reset STATE to (0,1) to restart from known phi seed
; In a more sophisticated version this would be a soft reset
ret
.nonaction:
mov qword [STRATEGY], STRATEGY_NONACTION
ret
.converge:
mov qword [STRATEGY], STRATEGY_CONVERGE
ret
.water_anom:
; Water anomaly with no other flags: continue but log
mov qword [STRATEGY], STRATEGY_FLOWING
ret
; =============================================================================
; WATER — CPU 1 (Inverse Verification)
; =============================================================================
; WATER(a,b) = (b, a-b)
; Checks: WATER(FIRE(Ω)) == Ω
; WATER(a+b, a) = (a, (a+b)-a) = (a, b) = Ω -- always true for exact arithmetic
; So ORACLE_WATER_BROKEN fires only on arithmetic error (impossible mod 2^64)
water_compute:
mov r8, [STATE_A]
mov r9, [STATE_B]
; Compute WATER of current state
mov rax, r9
mov rbx, r8
sub rbx, r9
mov [WATER_A], rax
mov [WATER_B], rbx
; Verify WATER(FIRE(Ω)) == Ω
; FIRE = (FIRE_A, FIRE_B) = (a+b, a)
; WATER(a+b, a) = (a, b) so check WATER_FIRE_A==STATE_A, WATER_FIRE_B==STATE_B
mov rcx, [FIRE_A]
mov rdx, [FIRE_B]
; WATER of FIRE: first = FIRE_B = a, second = FIRE_A - FIRE_B = b
cmp rdx, r8 ; FIRE_B == STATE_A?
jne .broken
mov rsi, rcx
sub rsi, rdx
cmp rsi, r9 ; FIRE_A - FIRE_B == STATE_B?
jne .broken
; Clear water bit in oracle
mov rax, [ORACLE]
and rax, ~ORACLE_WATER_BROKEN
mov [ORACLE], rax
ret
.broken:
or qword [ORACLE], ORACLE_WATER_BROKEN
or qword [ORACLE], ORACLE_CRITICAL ; water failure is always critical
ret
; =============================================================================
; WATER WORKER — CPU 1 (AP loop)
; =============================================================================
role_water:
xor r15d, r15d
lock or qword [READY_MASK], 2
.wait:
mov rax, [REQUEST_K]
cmp rax, r15
je .wait
mov r15, rax
call water_compute
mov [DONE_WATER], r15
jmp .wait
; =============================================================================
; EARTH — CPU 2 (N_phi Pattern Oracle)
; =============================================================================
; N_phi(a,b) = -a² + ab + b²
;
; WU-WEI: For Fibonacci pairs, N oscillates: N(k) = (-1)^k.
; Expected delta each step: -(EARTH_N)*2 (flips sign, magnitude 2)
; If delta != -2*N(prev): pattern broken -> ORACLE_EARTH_PATTERN
; If |delta| != 2: magnitude wrong -> ORACLE_EARTH_MAGNITUDE
earth_compute:
mov r8, [STATE_A]
mov r9, [STATE_B]
; ── N(current) = -a² + ab + b² ──
mov rax, r8
imul rax, r8
neg rax ; -a²
mov rbx, r8
imul rbx, r9
add rax, rbx ; -a² + ab
mov rbx, r9
imul rbx, r9
add rax, rbx ; -a² + ab + b²
mov [EARTH_N], rax
; ── N(FIRE(current)): FIRE=(a+b, a) ──
mov r10, r8
add r10, r9 ; r10 = a+b = FIRE_A
mov r11, r8 ; r11 = a = FIRE_B
mov rax, r10
imul rax, r10
neg rax
mov rbx, r10
imul rbx, r11
add rax, rbx
mov rbx, r11
imul rbx, r11
add rax, rbx
mov [EARTH_N_FIRE], rax
; ── Delta = N(FIRE) - N(current) ──
mov rcx, [EARTH_N]
mov rdx, [EARTH_N_FIRE]
mov rax, rdx
sub rax, rcx ; delta = N_fire - N_curr
mov [EARTH_DELTA], rax
; ── Pattern check: |delta| should be 2 ──
mov rbx, rax
; abs(rax): if negative, negate
test rax, rax
jns .pos
neg rbx
.pos:
cmp rbx, 2
jne .magnitude_wrong
; ── Sign check: delta should be opposite sign of N(current) ──
; N positive -> delta should be negative
; N negative -> delta should be positive
; i.e. N(current) * delta < 0 (opposite signs)
; Skip sign check on very first iteration (prev_delta == 0)
cmp qword [EARTH_PREV_DELTA], 0
je .first_iter
; Check alternation: delta sign should be opposite of prev_delta sign
mov r12, rax ; current delta
mov r13, [EARTH_PREV_DELTA]
; If both same sign -> pattern broken
; r12 and r13: test sign agreement via XOR of sign bits
mov r14, r12
xor r14, r13
; If bit 63 of XOR is 0, both same sign -> broken
test r14, r14
js .signs_ok
; Same sign = pattern broken
or qword [ORACLE], ORACLE_EARTH_PATTERN
jmp .done
.signs_ok:
; Pattern good: clear earth bits
mov rbx, [ORACLE]
and rbx, ~(ORACLE_EARTH_PATTERN | ORACLE_EARTH_MAGNITUDE)
mov [ORACLE], rbx
jmp .done
.first_iter:
; First iteration: just clear earth error bits
mov rbx, [ORACLE]
and rbx, ~(ORACLE_EARTH_PATTERN | ORACLE_EARTH_MAGNITUDE)
mov [ORACLE], rbx
jmp .done
.magnitude_wrong:
or qword [ORACLE], ORACLE_EARTH_MAGNITUDE
jmp .done
.done:
; Save delta for next iteration
mov rax, [EARTH_DELTA]
mov [EARTH_PREV_DELTA], rax
; ── Trinary projection: sign of N ──
mov rax, [EARTH_N]
test rax, rax
jz .tri_zero
js .tri_neg
mov qword [TRINARY], 1
ret
.tri_neg:
mov qword [TRINARY], -1
ret
.tri_zero:
mov qword [TRINARY], 0
ret
; =============================================================================
; EARTH WORKER — CPU 2 (AP loop)
; =============================================================================
role_earth:
xor r15d, r15d
lock or qword [READY_MASK], 4
.wait:
mov rax, [REQUEST_K]
cmp rax, r15
je .wait
mov r15, rax
call earth_compute
mov [DONE_EARTH], r15
jmp .wait
; =============================================================================
; WIND — CPU 3 (T(X) Fixed-Point Residual)
; =============================================================================
; T(X) = 1 + 1/X. Fixed point: X = phi.
; In Z[phi] with X = a*phi + b:
; T(X) - X residuals:
; phi coeff: a² + 2ab - a
; const coeff: a² + b² - b - 1
; Both zero iff X = phi (the fixed point).
;
; WU-WEI: residuals grow as Fibonacci grows.
; WIND_FIXED fires when both are zero (rare, meaningful event).
; WIND_DIVERGE fires when |res_a| + |res_b| exceeds threshold.
WIND_DIV_THRESH equ 0x1000000000 ; ~68 billion: divergence threshold
wind_compute:
mov r8, [STATE_A]
mov r9, [STATE_B]
; ── phi-coeff residual: a² + 2ab - a ──
mov rax, r8
imul rax, r8 ; a²
mov rbx, r8
imul rbx, r9 ; ab
add rbx, rbx ; 2ab
add rax, rbx ; a² + 2ab
sub rax, r8 ; a² + 2ab - a
mov [WIND_RES_A], rax
; ── const residual: a² + b² - b - 1 ──
mov rcx, r8
imul rcx, r8 ; a²
mov rdx, r9
imul rdx, r9 ; b²
add rcx, rdx ; a² + b²
sub rcx, r9 ; a² + b² - b
dec rcx ; a² + b² - b - 1
mov [WIND_RES_B], rcx
; ── Fixed point check ──
test rax, rax
jnz .not_fixed
test rcx, rcx
jnz .not_fixed
mov qword [WIND_FIX], 1
or qword [ORACLE], ORACLE_WIND_FIXED
ret
.not_fixed:
mov qword [WIND_FIX], 0
; ── Divergence check ──
; |res_a| + |res_b| > threshold?
mov rax, [WIND_RES_A]
test rax, rax
jns .pos_a
neg rax
.pos_a:
mov rbx, [WIND_RES_B]
test rbx, rbx
jns .pos_b
neg rbx
.pos_b:
add rax, rbx
mov r12, WIND_DIV_THRESH
cmp rax, r12
jbe .no_diverge
or qword [ORACLE], ORACLE_WIND_DIVERGE
jmp .wind_done
.no_diverge:
; Clear wind bits
mov rax, [ORACLE]
and rax, ~(ORACLE_WIND_FIXED | ORACLE_WIND_DIVERGE)
mov [ORACLE], rax
.wind_done:
ret
; =============================================================================
; WIND WORKER — CPU 3 (AP loop)
; =============================================================================
role_wind:
xor r15d, r15d
lock or qword [READY_MASK], 8
.wait:
mov rax, [REQUEST_K]
cmp rax, r15
je .wait
mov r15, rax
call wind_compute
mov [DONE_WIND], r15
jmp .wait
; =============================================================================
; AP TRAMPOLINE (16-bit, copied to 0x8000)
; =============================================================================
BITS 16
ap_trampoline:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
; Use GDT already loaded in boot sector (still at 0x7C00 in RAM)
lgdt [gdt_ptr]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword 0x08:AP_PM_PHYS
; AP: 32-bit pmode
BITS 32
ap_pm_entry:
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov esp, 0x00078000 ; temporary stack for AP
; PAE
mov eax, cr4
or eax, (1 << 5)
mov cr4, eax
; EFER.LME
mov ecx, 0xC0000080
rdmsr
or eax, (1 << 8)
wrmsr
; Use BSP page tables
mov eax, PML4_PHYS
mov cr3, eax
; Paging on
mov eax, cr0
or eax, (1 << 31)
mov cr0, eax
jmp dword 0x18:AP_LM_PHYS
; AP: 64-bit entry
BITS 64
ap_lm_entry:
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
; APIC ID -> stack assignment
mov eax, 1
cpuid
shr ebx, 24
and ebx, 0xFF
; Private stack: AP_STACK_BASE + apic_id * AP_STACK_STRIDE
mov rcx, AP_STACK_BASE
mov rdx, rbx
imul rdx, AP_STACK_STRIDE
add rcx, rdx
mov rsp, rcx
; Dispatch by APIC ID
cmp ebx, 1
je .water
cmp ebx, 2
je .earth
cmp ebx, 3
je .wind
jmp .dead
.water: call role_water
jmp .dead
.earth: call role_earth
jmp .dead
.wind: call role_wind
.dead:
cli
.halt:
hlt
jmp .halt
align 2
ap_trampoline_end:
; =============================================================================
; VGA INITIALIZATION
; =============================================================================
BITS 64
vga_init:
; Clear screen (2000 cells, attribute 0x07 = white on black)
mov rdi, VGA_BASE
mov ax, 0x0720
mov rcx, 2000
rep stosw
; Row 0: title
mov rdi, VGA_BASE + VGA_ROW * 0
mov rsi, str_title + PHYS_ADJ
mov bl, 0x0F ; bright white
call vga_puts_color
; Row 1: topology
mov rdi, VGA_BASE + VGA_ROW * 1
mov rsi, str_topology + PHYS_ADJ
mov bl, 0x0B ; cyan
call vga_puts_color
; Row 2: STATE header
mov rdi, VGA_BASE + VGA_ROW * 2
mov rsi, str_state + PHYS_ADJ
mov bl, 0x07
call vga_puts_color
; Row 3: FIRE header
mov rdi, VGA_BASE + VGA_ROW * 3
mov rsi, str_fire + PHYS_ADJ
mov bl, 0x0C ; bright red
call vga_puts_color
; Row 4: WATER header
mov rdi, VGA_BASE + VGA_ROW * 4
mov rsi, str_water + PHYS_ADJ
mov bl, 0x09 ; bright blue
call vga_puts_color
; Row 5: EARTH header
mov rdi, VGA_BASE + VGA_ROW * 5
mov rsi, str_earth + PHYS_ADJ
mov bl, 0x0A ; bright green
call vga_puts_color
; Row 6: WIND header
mov rdi, VGA_BASE + VGA_ROW * 6
mov rsi, str_wind + PHYS_ADJ
mov bl, 0x0E ; yellow
call vga_puts_color
; Row 7: ORACLE header
mov rdi, VGA_BASE + VGA_ROW * 7
mov rsi, str_oracle + PHYS_ADJ
mov bl, 0x0D ; bright magenta
call vga_puts_color
; Row 8: YIN header
mov rdi, VGA_BASE + VGA_ROW * 8
mov rsi, str_yin + PHYS_ADJ
mov bl, 0x07
call vga_puts_color
ret
; =============================================================================
; VGA UPDATE (called every PRINT_EVERY iterations)
; =============================================================================
; Column positions for values (each hex64 = 16 chars + 1 space = 17 cols)
; Labels end around col 10, values start at col 10 (byte offset = col*2)
vga_update:
; ── Row 2: STATE K= A= B= ──
mov rdi, VGA_BASE + VGA_ROW * 2 + 10*2
mov rax, [STATE_K]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 2 + 28*2
mov rax, [STATE_A]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 2 + 46*2
mov rax, [STATE_B]
call vga_hex64
; ── Row 3: FIRE A= B= ──
mov rdi, VGA_BASE + VGA_ROW * 3 + 10*2
mov rax, [FIRE_A]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 3 + 28*2
mov rax, [FIRE_B]
call vga_hex64
; ── Row 4: WATER A= B= ──
mov rdi, VGA_BASE + VGA_ROW * 4 + 10*2
mov rax, [WATER_A]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 4 + 28*2
mov rax, [WATER_B]
call vga_hex64
; ── Row 5: EARTH N= NF= DELTA= ──
mov rdi, VGA_BASE + VGA_ROW * 5 + 10*2
mov rax, [EARTH_N]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 5 + 28*2
mov rax, [EARTH_N_FIRE]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 5 + 46*2
mov rax, [EARTH_DELTA]
call vga_hex64
; ── Row 6: WIND RA= RB= FIX= ──
mov rdi, VGA_BASE + VGA_ROW * 6 + 10*2
mov rax, [WIND_RES_A]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 6 + 28*2
mov rax, [WIND_RES_B]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 6 + 46*2
mov rax, [WIND_FIX]
call vga_hex64
; ── Row 7: ORACLE= STRATEGY= ──
mov rdi, VGA_BASE + VGA_ROW * 7 + 10*2
mov rax, [ORACLE]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 7 + 28*2
mov rax, [STRATEGY]
call vga_hex64
; Strategy name
mov rdi, VGA_BASE + VGA_ROW * 7 + 46*2
mov rax, [STRATEGY]
call vga_strategy_name
; ── Row 8: YIN PH DEPTH ──
mov rdi, VGA_BASE + VGA_ROW * 8 + 10*2
mov rax, [YIN]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 8 + 28*2
mov rax, [PHASE]
call vga_hex64
mov rdi, VGA_BASE + VGA_ROW * 8 + 46*2
mov rax, [DEPTH]
call vga_hex64
ret
; ============================================================================
; vga_strategy_name: print strategy name at RDI
; Input: rax = STRATEGY index
; ============================================================================
vga_strategy_name:
cmp rax, STRATEGY_FLOWING
je .flowing
cmp rax, STRATEGY_NONACTION
je .nonaction
cmp rax, STRATEGY_REDIRECT
je .redirect
cmp rax, STRATEGY_CONVERGE
je .converge
cmp rax, STRATEGY_CRITICAL
je .critical
mov rsi, str_strat_unknown
jmp .print
.flowing:
mov rsi, str_strat_flowing
jmp .print
.nonaction:
mov rsi, str_strat_nonaction
jmp .print
.redirect:
mov rsi, str_strat_redirect
jmp .print
.converge:
mov rsi, str_strat_converge
jmp .print
.critical:
mov rsi, str_strat_critical
.print:
mov bl, 0x0D
jmp vga_puts_color ; tail call
; =============================================================================
; VGA HELPERS
; =============================================================================
; vga_puts_color: RDI=dest, RSI=string, BL=attribute
vga_puts_color:
.next:
lodsb
test al, al
jz .done
mov [rdi], al
mov [rdi + 1], bl
add rdi, 2
jmp .next
.done:
ret
; vga_hex64: RDI=dest, RAX=value, writes 16 hex digits
vga_hex64:
push rbx
push rcx
push rdx
push rdi
push rax
mov rcx, 16
mov rbx, rdi
.hloop:
mov rdx, rax
shr rdx, 60
and edx, 0x0F
movzx edx, byte [hex_digits + PHYS_ADJ + rdx]
mov [rbx], dl
mov byte [rbx + 1], 0x07
add rbx, 2
shl rax, 4
loop .hloop
pop rax
pop rdi
pop rdx
pop rcx
pop rbx
ret
; =============================================================================
; STRINGS
; =============================================================================
str_title:
db "HDGL Z[phi] WU-WEI SUBSTRATE FIRE/WATER/EARTH/WIND",0
str_topology:
db "CPU0=FIRE CPU1=WATER CPU2=EARTH CPU3=WIND",0
str_state:
db "STATE K= A= B=",0
str_fire:
db "FIRE A= B=",0
str_water:
db "WATER A= B=",0
str_earth:
db "EARTH N= NF= DELTA=",0
str_wind:
db "WIND RA= RB= FIX=",0
str_oracle:
db "ORACLE= STRATEGY=",0
str_yin:
db "YIN S= PH= DEPTH=",0
str_strat_flowing: db "FLOWING RIVER",0
str_strat_nonaction: db "NON-ACTION ",0
str_strat_redirect: db "REDIRECT ",0
str_strat_converge: db "CONVERGENCE ",0
str_strat_critical: db "!! CRITICAL !!",0
str_strat_unknown: db "UNKNOWN ",0
hex_digits:
db "0123456789ABCDEF"
; =============================================================================
; PHYSICAL ADDRESS CONSTANTS
; =============================================================================
;
; All labels are relative to ORG 0x7C00.
; Physical address of a label L in payload = 0x10000 + (L - boot_start) - 512
; because:
; - payload loads at physical 0x10000
; - boot_start = 0x7C00
; - sector 1 (boot sector) = 512 bytes, payload starts at file offset 512
; - So physical(L) = 0x10000 + (L - 0x7C00) - 512
; = 0x10000 + L - 0x7E00
; = L + (0x10000 - 0x7E00)
; = L + 0x8200
;
; Verify: protected_entry label value = 0x7C00 + 512 = 0x7E00
; physical = 0x7E00 + 0x8200 = 0x10200. Correct!
;
; For AP trampoline (copied to 0x8000):
; ap_trampoline label = 0x7C00 + (its file offset)
; AP_PM_PHYS = 0x8000 + (ap_pm_entry - ap_trampoline)
; AP_LM_PHYS = 0x8000 + (ap_lm_entry - ap_trampoline)
PROTECTED_ENTRY_PHYS equ protected_entry + (0x10000 - 0x7E00)
LONG_MODE_ENTRY_PHYS equ long_mode_entry + (0x10000 - 0x7E00)
AP_PM_PHYS equ AP_TRAMP_PHYS + (ap_pm_entry - ap_trampoline)
AP_LM_PHYS equ AP_TRAMP_PHYS + (ap_lm_entry - ap_trampoline)
; =============================================================================
; IMAGE PADDING TO EXACTLY 64 SECTORS
; =============================================================================
times (IMAGE_SECTORS * 512) - ($ - $$) db 0
