| ; ============================================================================= | |
| ; nand_kernel.asm — NAND Boolean Kernel (x86-64 NASM, Linux) | |
| ; All boolean operations derived from NAND, matching the DSL BooleanKernel: | |
| ; NAND(a,b) = 1-ab | |
| ; NOT(x) = NAND(x,x) | |
| ; AND(a,b) = NAND(NAND(a,b), NAND(a,b)) | |
| ; OR(a,b) = NAND(NAND(a,a), NAND(b,b)) | |
| ; IMPLIES(a,b) = OR(NOT(a), b) | |
| ; EQUAL(a,b) = AND(IMPLIES(a,b), IMPLIES(b,a)) | |
| ; ============================================================================= | |
| ; Single-bit functions: rdi=a, rsi=b, return rax=0 or 1 | |
| ; Word functions: rdi=a, rsi=b, return rax=64-bit result | |
| ; Entropy constraint: H <= 0.20 ↔ popcount(word)/64 <= 0.20 ↔ popcount <= 12 | |
| ; ============================================================================= | |
| bits 64 | |
| default rel | |
| ; ─── Entropy threshold ──────────────────────────────────────────────────────── | |
| ; H = -sum(p * ln p) for a bit distribution | |
| ; For binary uniform-ish distribution, H ≈ popcount/64 * ln(64/popcount) + ... | |
| ; Conservative approximation: popcount <= 12 bits set satisfies H <= 0.20 nats | |
| ENTROPY_MAX_BITS_SET equ 12 ; max set bits for H <= 0.20 | |
| ; ============================================================================= | |
| ; .data | |
| ; ============================================================================= | |
| section .data | |
| msg_nand_init db "NAND kernel initialized.", 0x0A, 0 | |
| msg_entropy_ok db "ENTROPY: H <= 0.20 (ok)", 0x0A, 0 | |
| msg_entropy_err db "ENTROPY: H > 0.20 (reject)", 0x0A, 0 | |
| ; Precomputed NAND truth table (2x2): | |
| ; NAND(0,0)=1 NAND(0,1)=1 NAND(1,0)=1 NAND(1,1)=0 | |
| nand_truth: | |
| db 1, 1, 1, 0 ; [a*2+b] -> result | |
| ; Routing conflict table: expert pair (i,j) conflicts if they share a resource | |
| ; Represented as 8x8 bit matrix stored as 8 bytes | |
| ; Entry [i*8+j] = 1 means experts i and j conflict | |
| ; For demonstration: experts 0+1, 2+3, 4+5 conflict (paired resources) | |
| conflict_matrix: | |
| db 0,1,0,0,0,0,0,0 ; expert 0 conflicts with 1 | |
| db 1,0,0,0,0,0,0,0 ; expert 1 conflicts with 0 | |
| db 0,0,0,1,0,0,0,0 ; expert 2 conflicts with 3 | |
| db 0,0,1,0,0,0,0,0 ; expert 3 conflicts with 2 | |
| db 0,0,0,0,0,1,0,0 ; expert 4 conflicts with 5 | |
| db 0,0,0,0,1,0,0,0 ; expert 5 conflicts with 4 | |
| db 0,0,0,0,0,0,0,0 ; expert 6: no conflicts | |
| db 0,0,0,0,0,0,0,0 ; expert 7: no conflicts | |
| ; Popcount lookup table (nibble-based, 16 entries) | |
| ; popcount_nibble[n] = number of set bits in n (for n in 0..15) | |
| popcount_nibble: | |
| db 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 | |
| ; ============================================================================= | |
| ; .bss | |
| ; ============================================================================= | |
| section .bss | |
| align 8 | |
| nand_stats: | |
| .nand_calls resq 1 | |
| .and_calls resq 1 | |
| .or_calls resq 1 | |
| .not_calls resq 1 | |
| .entropy_checks resq 1 | |
| .entropy_rejects resq 1 | |
| ; ============================================================================= | |
| ; .text | |
| ; ============================================================================= | |
| section .text | |
| extern sys_write | |
| extern str_len | |
| global nand_bit | |
| global not_bit | |
| global and_bit | |
| global or_bit | |
| global xor_bit | |
| global implies_bit | |
| global equal_bit | |
| global nand_word | |
| global not_word | |
| global and_word | |
| global or_word | |
| global xor_word | |
| global implies_word | |
| global equal_word | |
| global entropy_check_word | |
| global popcount64 | |
| global nand_route_filter | |
| global nand_kernel_init | |
| global nand_selftest | |
| ; ============================================================================= | |
| ; nand_kernel_init — Initialize NAND kernel (print banner, zero stats) | |
| ; Arguments: none | |
| ; Returns: rax = 0 | |
| ; ============================================================================= | |
| nand_kernel_init: | |
| push rbp | |
| mov rbp, rsp | |
| ; Zero stats | |
| mov qword [rel nand_stats.nand_calls], 0 | |
| mov qword [rel nand_stats.and_calls], 0 | |
| mov qword [rel nand_stats.or_calls], 0 | |
| mov qword [rel nand_stats.not_calls], 0 | |
| mov qword [rel nand_stats.entropy_checks], 0 | |
| mov qword [rel nand_stats.entropy_rejects], 0 | |
| ; Print init message | |
| mov rdi, 1 | |
| lea rsi, [rel msg_nand_init] | |
| call str_len | |
| mov rdx, rax | |
| mov rdi, 1 | |
| lea rsi, [rel msg_nand_init] | |
| call sys_write | |
| xor rax, rax | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; nand_bit — Single-bit NAND: NAND(a, b) = NOT(a AND b) | |
| ; Arguments: rdi = a (0 or 1), rsi = b (0 or 1) | |
| ; Returns: rax = NAND(a, b) (0 or 1) | |
| ; Derivation: NAND(a,b) = 1 - a*b | |
| ; a=0,b=0 -> 1-0 = 1 | |
| ; a=0,b=1 -> 1-0 = 1 | |
| ; a=1,b=0 -> 1-0 = 1 | |
| ; a=1,b=1 -> 1-1 = 0 | |
| ; ============================================================================= | |
| nand_bit: | |
| push rbp | |
| mov rbp, rsp | |
| inc qword [rel nand_stats.nand_calls] | |
| ; Normalize inputs to 0/1 | |
| test rdi, rdi | |
| setnz al | |
| movzx rdi, al | |
| test rsi, rsi | |
| setnz al | |
| movzx rsi, al | |
| ; a*b | |
| mov rax, rdi | |
| imul rax, rsi ; rax = a*b (0 or 1) | |
| ; 1 - a*b | |
| xor rax, 1 ; toggle bit 0: 0->1, 1->0 | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; not_bit — Single-bit NOT via NAND: NOT(x) = NAND(x, x) | |
| ; Arguments: rdi = x (0 or 1) | |
| ; Returns: rax = NOT(x) | |
| ; ============================================================================= | |
| not_bit: | |
| push rbp | |
| mov rbp, rsp | |
| inc qword [rel nand_stats.not_calls] | |
| ; NOT(x) = NAND(x, x): pass same value twice | |
| mov rsi, rdi ; b = a = x | |
| call nand_bit | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; and_bit — Single-bit AND via NAND: AND(a,b) = NAND(NAND(a,b), NAND(a,b)) | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = AND(a, b) | |
| ; ============================================================================= | |
| and_bit: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| inc qword [rel nand_stats.and_calls] | |
| mov rbx, rdi ; save a | |
| mov r12, rsi ; save b | |
| ; n = NAND(a, b) | |
| call nand_bit ; rdi=a, rsi=b already set | |
| mov rdi, rax ; n | |
| mov rsi, rax ; n | |
| ; AND = NAND(n, n) | |
| call nand_bit | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; or_bit — Single-bit OR via NAND: OR(a,b) = NAND(NAND(a,a), NAND(b,b)) | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = OR(a, b) | |
| ; ============================================================================= | |
| or_bit: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| inc qword [rel nand_stats.or_calls] | |
| mov rbx, rdi ; save a | |
| mov r12, rsi ; save b | |
| ; na = NAND(a, a) = NOT(a) | |
| mov rsi, rbx | |
| call nand_bit ; rdi=a, rsi=a | |
| mov rbx, rax ; na | |
| ; nb = NAND(b, b) = NOT(b) | |
| mov rdi, r12 | |
| mov rsi, r12 | |
| call nand_bit ; rdi=b, rsi=b | |
| ; rax = nb | |
| ; OR = NAND(na, nb) | |
| mov rdi, rbx | |
| mov rsi, rax | |
| call nand_bit | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; xor_bit — Single-bit XOR via NAND: | |
| ; XOR(a,b) = AND(OR(a,b), NAND(a,b)) | |
| ; = NAND(NAND(OR(a,b), OR(a,b)), NAND(NAND(a,b), NAND(a,b))) | |
| ; (Simplified: use 4-NAND construction) | |
| ; a XOR b = NAND(NAND(a, NAND(a,b)), NAND(b, NAND(a,b))) | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = XOR(a, b) | |
| ; ============================================================================= | |
| xor_bit: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| push r13 | |
| mov rbx, rdi ; save a | |
| mov r12, rsi ; save b | |
| ; n = NAND(a, b) | |
| call nand_bit | |
| mov r13, rax ; n = NAND(a,b) | |
| ; p = NAND(a, n) | |
| mov rdi, rbx ; a | |
| mov rsi, r13 ; n | |
| call nand_bit | |
| push rax ; save p | |
| ; q = NAND(b, n) | |
| mov rdi, r12 ; b | |
| mov rsi, r13 ; n | |
| call nand_bit | |
| mov rsi, rax ; q | |
| pop rdi ; p | |
| ; XOR = NAND(p, q) | |
| call nand_bit | |
| pop r13 | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; implies_bit — Single-bit IMPLIES via NAND: IMPLIES(a,b) = OR(NOT(a), b) | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = IMPLIES(a, b) | |
| ; ============================================================================= | |
| implies_bit: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| mov rbx, rdi ; save a | |
| mov r12, rsi ; save b | |
| ; na = NOT(a) | |
| call not_bit ; rdi=a already set | |
| mov rbx, rax ; na | |
| ; OR(NOT(a), b) = OR(na, b) | |
| mov rdi, rbx | |
| mov rsi, r12 | |
| call or_bit | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; equal_bit — Single-bit EQUAL via NAND: EQUAL(a,b) = AND(IMPLIES(a,b), IMPLIES(b,a)) | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = EQUAL(a, b) (1 if a==b, 0 otherwise) | |
| ; ============================================================================= | |
| equal_bit: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| mov rbx, rdi ; save a | |
| mov r12, rsi ; save b | |
| ; p = IMPLIES(a, b) | |
| call implies_bit | |
| push rax ; save p | |
| ; q = IMPLIES(b, a) | |
| mov rdi, r12 ; b | |
| mov rsi, rbx ; a | |
| call implies_bit | |
| mov rsi, rax ; q | |
| pop rdi ; p | |
| ; EQUAL = AND(p, q) | |
| call and_bit | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; nand_word — 64-bit bitwise NAND: ~(a & b) | |
| ; Arguments: rdi = a (uint64), rsi = b (uint64) | |
| ; Returns: rax = NAND(a, b) = ~(a & b) | |
| ; Note: This is the direct bitwise implementation, not bit-serial. | |
| ; The bit-serial functions above are for single-bit logical operations. | |
| ; ============================================================================= | |
| nand_word: | |
| push rbp | |
| mov rbp, rsp | |
| inc qword [rel nand_stats.nand_calls] | |
| mov rax, rdi | |
| and rax, rsi ; a & b | |
| not rax ; ~(a & b) | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; not_word — 64-bit bitwise NOT via NAND: NOT(x) = NAND(x, x) = ~x | |
| ; Arguments: rdi = x (uint64) | |
| ; Returns: rax = ~x | |
| ; ============================================================================= | |
| not_word: | |
| push rbp | |
| mov rbp, rsp | |
| inc qword [rel nand_stats.not_calls] | |
| mov rax, rdi | |
| and rax, rdi ; x & x = x | |
| not rax ; ~x | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; and_word — 64-bit bitwise AND via NAND: AND = NAND(NAND(a,b), NAND(a,b)) | |
| ; = ~(~(a&b) & ~(a&b)) = ~(~(a&b)) = a&b | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = a & b | |
| ; ============================================================================= | |
| and_word: | |
| push rbp | |
| mov rbp, rsp | |
| inc qword [rel nand_stats.and_calls] | |
| ; Step 1: n = NAND(a, b) = ~(a & b) | |
| mov rax, rdi | |
| and rax, rsi ; a & b | |
| not rax ; ~(a & b) = n | |
| ; Step 2: AND = NAND(n, n) = ~(n & n) = ~n = ~~(a&b) = a&b | |
| not rax ; ~~(a&b) = a&b | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; or_word — 64-bit bitwise OR via NAND: OR = NAND(NAND(a,a), NAND(b,b)) | |
| ; = ~(~a & ~b) = ~(~a) | ~(~b) [De Morgan] = a | b | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = a | b | |
| ; ============================================================================= | |
| or_word: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| inc qword [rel nand_stats.or_calls] | |
| ; na = NAND(a, a) = ~a | |
| mov rbx, rdi | |
| and rbx, rdi | |
| not rbx ; na = ~a | |
| ; nb = NAND(b, b) = ~b | |
| mov rax, rsi | |
| and rax, rsi | |
| not rax ; nb = ~b | |
| ; OR = NAND(na, nb) = ~(na & nb) = ~(~a & ~b) = a | b | |
| and rax, rbx ; ~a & ~b | |
| not rax ; a | b | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; xor_word — 64-bit bitwise XOR via NAND (4-NAND construction) | |
| ; XOR(a,b) = NAND(NAND(a, NAND(a,b)), NAND(b, NAND(a,b))) | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = a ^ b | |
| ; ============================================================================= | |
| xor_word: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| mov rbx, rdi ; a | |
| mov r12, rsi ; b | |
| ; n = NAND(a, b) = ~(a & b) | |
| mov rax, rbx | |
| and rax, r12 | |
| not rax ; n = NAND(a,b) | |
| push rax ; save n | |
| ; p = NAND(a, n) | |
| mov rdi, rbx | |
| mov rsi, rax | |
| call nand_word | |
| push rax ; save p | |
| ; q = NAND(b, n) | |
| pop rcx ; restore n? No — we need n again | |
| ; Actually restore properly: | |
| pop rcx ; this is p | |
| push rcx ; re-save p | |
| ; We need n — recompute | |
| mov rax, rbx | |
| and rax, r12 | |
| not rax ; n again | |
| mov rdi, r12 ; b | |
| mov rsi, rax ; n | |
| call nand_word ; rax = q = NAND(b, n) | |
| mov rsi, rax ; q | |
| pop rdi ; p | |
| ; XOR = NAND(p, q) | |
| call nand_word | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; implies_word — 64-bit bitwise IMPLIES: IMPLIES(a,b) = OR(NOT(a), b) = ~a | b | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = ~a | b | |
| ; ============================================================================= | |
| implies_word: | |
| push rbp | |
| mov rbp, rsp | |
| ; ~a | b | |
| mov rax, rdi | |
| not rax ; ~a | |
| or rax, rsi ; ~a | b | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; equal_word — 64-bit bitwise EQUAL: EQUAL(a,b) = ~(a ^ b) [XNOR] | |
| ; Arguments: rdi = a, rsi = b | |
| ; Returns: rax = ~(a ^ b) | |
| ; ============================================================================= | |
| equal_word: | |
| push rbp | |
| mov rbp, rsp | |
| mov rax, rdi | |
| xor rax, rsi | |
| not rax ; XNOR = ~XOR | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; popcount64 — Count set bits in a 64-bit word using POPCNT instruction | |
| ; Arguments: rdi = word | |
| ; Returns: rax = popcount(word) | |
| ; ============================================================================= | |
| popcount64: | |
| push rbp | |
| mov rbp, rsp | |
| popcnt rax, rdi ; hardware POPCNT (SSE4.2) | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; entropy_check_word — Check H(word) <= 0.20 constraint | |
| ; Approximation: popcount(word) / 64 is the "density". | |
| ; For a Bernoulli-p distribution: H = -p*ln(p) - (1-p)*ln(1-p) | |
| ; H <= 0.20 nats is satisfied when p <= ~0.026 or p >= ~0.974 | |
| ; i.e., at most 12 bits set (p <= 12/64 = 0.1875 → H ≈ 0.45 nats... ) | |
| ; | |
| ; More precisely, we use the conservative check: | |
| ; If popcount <= ENTROPY_MAX_BITS_SET (12) OR popcount >= (64-12) = 52, H ≤ 0.20 | |
| ; (sparse or near-full masks have low entropy) | |
| ; | |
| ; For the routing use case, we only have a few active experts (sparse), | |
| ; so the "at most 12 bits" check is the relevant branch. | |
| ; | |
| ; Arguments: rdi = 64-bit word (activation mask) | |
| ; Returns: rax = 1 (H <= 0.20, ok), 0 (H > 0.20, reject) | |
| ; ============================================================================= | |
| entropy_check_word: | |
| push rbp | |
| mov rbp, rsp | |
| inc qword [rel nand_stats.entropy_checks] | |
| ; Count set bits | |
| popcnt rax, rdi | |
| ; Check sparse: popcount <= 12 | |
| cmp rax, ENTROPY_MAX_BITS_SET | |
| jle .entropy_ok | |
| ; Check near-full: popcount >= 52 | |
| cmp rax, 64 - ENTROPY_MAX_BITS_SET | |
| jge .entropy_ok | |
| ; H > 0.20 — reject | |
| inc qword [rel nand_stats.entropy_rejects] | |
| mov rdi, 2 | |
| lea rsi, [rel msg_entropy_err] | |
| call str_len | |
| mov rdx, rax | |
| mov rdi, 2 | |
| lea rsi, [rel msg_entropy_err] | |
| call sys_write | |
| xor rax, rax | |
| pop rbp | |
| ret | |
| .entropy_ok: | |
| mov rax, 1 | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; nand_route_filter — Filter expert activations using NAND conflict logic | |
| ; Any expert pair that would conflict is suppressed via NAND. | |
| ; Algorithm: | |
| ; conflicting = active & conflict_mask (computed per-bit via AND) | |
| ; suppressed = NAND(conflicting, conflicting) = NOT(conflicting) inverted | |
| ; filtered = active & NOT(conflicting) -- keep only non-conflicting | |
| ; In 64-bit word terms, where conflict_mask is the OR of all conflict bits | |
| ; for the active set: | |
| ; conflict_bits = (reduce conflict_matrix over active bits) | |
| ; filtered = active & NAND(active & conflict_bits, active & conflict_bits) | |
| ; = active & NOT(active & conflict_bits) | |
| ; = active & ~(active & conflict_bits) | |
| ; = active & ~conflict_bits (when conflict_bits is the full mask) | |
| ; | |
| ; For simplicity: use the 8-expert conflict matrix to compute conflict_bits. | |
| ; Arguments: | |
| ; rdi = active_mask (64-bit, each bit = one expert; only low 8 bits used) | |
| ; rsi = conflict_mask (64-bit bitmask of forbidden co-activations) | |
| ; Returns: rax = filtered_mask | |
| ; ============================================================================= | |
| nand_route_filter: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| push r13 | |
| mov rbx, rdi ; active_mask | |
| mov r12, rsi ; conflict_mask | |
| ; Step 1: Find which active experts have conflicts | |
| ; conflict_active = active_mask & conflict_mask | |
| mov r13, rbx | |
| and r13, r12 ; r13 = conflicting active experts | |
| ; Step 2: NAND(conflict_active, conflict_active) = NOT(conflict_active) | |
| ; Using the NAND identity: suppress conflicting experts | |
| mov rax, r13 | |
| and rax, r13 | |
| not rax ; rax = NOT(conflict_active) = ~r13 | |
| ; Step 3: filtered = active & NOT(conflict_active) | |
| ; This keeps only experts that are active AND not involved in a conflict | |
| and rax, rbx ; filtered = active & ~(active & conflict_mask) | |
| pop r13 | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |
| ; ============================================================================= | |
| ; nand_selftest — Run a suite of self-tests to verify NAND kernel correctness | |
| ; Tests all 4 combinations of single-bit NAND, then spot-checks AND/OR/XOR/EQUAL | |
| ; Arguments: none | |
| ; Returns: rax = 0 (all tests passed), N (number of failures) | |
| ; ============================================================================= | |
| nand_selftest: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| xor rbx, rbx ; failure count | |
| ; --- Test NAND truth table --- | |
| ; NAND(0,0) = 1 | |
| mov rdi, 0 | |
| mov rsi, 0 | |
| call nand_bit | |
| cmp rax, 1 | |
| je .nand00_ok | |
| inc rbx | |
| .nand00_ok: | |
| ; NAND(0,1) = 1 | |
| mov rdi, 0 | |
| mov rsi, 1 | |
| call nand_bit | |
| cmp rax, 1 | |
| je .nand01_ok | |
| inc rbx | |
| .nand01_ok: | |
| ; NAND(1,0) = 1 | |
| mov rdi, 1 | |
| mov rsi, 0 | |
| call nand_bit | |
| cmp rax, 1 | |
| je .nand10_ok | |
| inc rbx | |
| .nand10_ok: | |
| ; NAND(1,1) = 0 | |
| mov rdi, 1 | |
| mov rsi, 1 | |
| call nand_bit | |
| cmp rax, 0 | |
| je .nand11_ok | |
| inc rbx | |
| .nand11_ok: | |
| ; --- Test NOT --- | |
| ; NOT(0) = 1 | |
| mov rdi, 0 | |
| call not_bit | |
| cmp rax, 1 | |
| je .not0_ok | |
| inc rbx | |
| .not0_ok: | |
| ; NOT(1) = 0 | |
| mov rdi, 1 | |
| call not_bit | |
| cmp rax, 0 | |
| je .not1_ok | |
| inc rbx | |
| .not1_ok: | |
| ; --- Test AND --- | |
| ; AND(1,1) = 1 | |
| mov rdi, 1 | |
| mov rsi, 1 | |
| call and_bit | |
| cmp rax, 1 | |
| je .and11_ok | |
| inc rbx | |
| .and11_ok: | |
| ; AND(1,0) = 0 | |
| mov rdi, 1 | |
| mov rsi, 0 | |
| call and_bit | |
| cmp rax, 0 | |
| je .and10_ok | |
| inc rbx | |
| .and10_ok: | |
| ; --- Test OR --- | |
| ; OR(0,0) = 0 | |
| mov rdi, 0 | |
| mov rsi, 0 | |
| call or_bit | |
| cmp rax, 0 | |
| je .or00_ok | |
| inc rbx | |
| .or00_ok: | |
| ; OR(1,0) = 1 | |
| mov rdi, 1 | |
| mov rsi, 0 | |
| call or_bit | |
| cmp rax, 1 | |
| je .or10_ok | |
| inc rbx | |
| .or10_ok: | |
| ; --- Test XOR --- | |
| ; XOR(0,0) = 0 | |
| mov rdi, 0 | |
| mov rsi, 0 | |
| call xor_bit | |
| cmp rax, 0 | |
| je .xor00_ok | |
| inc rbx | |
| .xor00_ok: | |
| ; XOR(1,1) = 0 | |
| mov rdi, 1 | |
| mov rsi, 1 | |
| call xor_bit | |
| cmp rax, 0 | |
| je .xor11_ok | |
| inc rbx | |
| .xor11_ok: | |
| ; XOR(0,1) = 1 | |
| mov rdi, 0 | |
| mov rsi, 1 | |
| call xor_bit | |
| cmp rax, 1 | |
| je .xor01_ok | |
| inc rbx | |
| .xor01_ok: | |
| ; --- Test EQUAL --- | |
| ; EQUAL(0,0) = 1 | |
| mov rdi, 0 | |
| mov rsi, 0 | |
| call equal_bit | |
| cmp rax, 1 | |
| je .eq00_ok | |
| inc rbx | |
| .eq00_ok: | |
| ; EQUAL(0,1) = 0 | |
| mov rdi, 0 | |
| mov rsi, 1 | |
| call equal_bit | |
| cmp rax, 0 | |
| je .eq01_ok | |
| inc rbx | |
| .eq01_ok: | |
| ; --- Test word-level nand_word --- | |
| ; NAND_WORD(0xFFFF, 0xFFFF) = ~0xFFFF (low bits all 1, upper bits all 1) | |
| mov rdi, 0x000000000000FFFF | |
| mov rsi, 0x000000000000FFFF | |
| call nand_word | |
| cmp rax, 0xFFFFFFFFFFFF0000 | |
| je .nandw_ok | |
| inc rbx | |
| .nandw_ok: | |
| ; --- Test entropy_check_word --- | |
| ; 8 bits set: popcount = 8 <= 12, should pass | |
| mov rdi, 0x00000000000000FF | |
| call entropy_check_word | |
| cmp rax, 1 | |
| je .ent_ok | |
| inc rbx | |
| .ent_ok: | |
| ; 32 bits set: popcount = 32 > 12, should fail | |
| mov rdi, 0x00000000FFFFFFFF | |
| call entropy_check_word | |
| cmp rax, 0 | |
| je .ent_fail_ok | |
| inc rbx | |
| .ent_fail_ok: | |
| ; Return failure count | |
| mov rax, rbx | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| ret | |