structured for testing
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Sat, 15 Feb 2025 14:11:25 +0000 (14:11 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Sat, 15 Feb 2025 14:11:25 +0000 (14:11 +0000)
48 files changed:
.gitignore
developer/amd64/.githolder [deleted file]
developer/cc🖉/N16PN.lib.c [new file with mode: 0644]
developer/cc🖉/N16n.lib.c [deleted file]
developer/cc🖉/N32PN.lib.c [new file with mode: 0644]
developer/cc🖉/N32n.lib.c [deleted file]
developer/cc🖉/N64PN.lib.c [new file with mode: 0644]
developer/cc🖉/N64n.lib.c [deleted file]
developer/cc🖉/N8PN.lib.c [new file with mode: 0644]
developer/cc🖉/N8n.lib.c [deleted file]
developer/cc🖉/test_N32.cli.c [deleted file]
developer/document🖉/front_end.org [new file with mode: 0644]
developer/example/.githolder [new file with mode: 0644]
developer/m4/N_template.lib.c.m4 [deleted file]
developer/machine/.gitignore [new file with mode: 0644]
developer/python/N64.lib.c [new file with mode: 0644]
developer/python/fill_template.py [new file with mode: 0755]
developer/python/gen_N32_8_by_4.py [new file with mode: 0755]
developer/python/gen_n64_lib.py [new file with mode: 0755]
developer/python/get_template.py [new file with mode: 0755]
developer/python/make_constants.py [new file with mode: 0755]
developer/tool🖉/env
developer/tool🖉/make
developer/tool🖉/makefile
developer/tool🖉/release [new file with mode: 0755]
document🖉/#SectionApproach.org# [deleted file]
document🖉/SectionApproach.org
release/x86_64/fedora41/glibc_2.40/N16PN.lib.c [new file with mode: 0644]
release/x86_64/fedora41/glibc_2.40/N32PN.lib.c [new file with mode: 0644]
release/x86_64/fedora41/glibc_2.40/N64PN.lib.c [new file with mode: 0644]
release/x86_64/fedora41/glibc_2.40/N8PN.lib.c [new file with mode: 0644]
release/x86_64/fedora41/glibc_2.40/libN.a [new file with mode: 0644]
tester/cc/N16PN.lib.c [new file with mode: 0644]
tester/cc/N32.lib.c [new file with mode: 0644]
tester/cc/N32PN.lib.c [new file with mode: 0644]
tester/cc/N64PN.lib.c [new file with mode: 0644]
tester/cc/N8PN.lib.c [new file with mode: 0644]
tester/cc🖉/environment.h [new file with mode: 0644]
tester/cc🖉/test_N32.cli.c [new file with mode: 0644]
tester/cc🖉/test_setup.cli.c [new file with mode: 0644]
tester/machine/.gitignore [new file with mode: 0644]
tester/scratchpad/.gitignore [new file with mode: 0644]
tester/tool🖉/env [new file with mode: 0644]
tester/tool🖉/make [new file with mode: 0755]
tester/tool🖉/makefile [new file with mode: 0644]
tester/tool🖉/pull_release [new file with mode: 0755]
tester/tool🖉/release_test [new file with mode: 0755]
tool_shared/bespoke🖉/env

index bf925e3..c65f5b6 100644 (file)
@@ -2,5 +2,6 @@
 
 #*#
 *~
+__pycache__
 a.out
 .gradle/
diff --git a/developer/amd64/.githolder b/developer/amd64/.githolder
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/developer/cc🖉/N16PN.lib.c b/developer/cc🖉/N16PN.lib.c
new file mode 100644 (file)
index 0000000..d7a2e05
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+  N16 - a processor native type
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N16PN·DEBUG
+
+#ifndef FACE
+#define N16PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N16PN·FACE
+#define N16PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint16_t Extent;
+  typedef uint16_t Digit;
+
+  typedef struct N16PN·T N16PN·T;
+
+  extern N16PN·T *N16PN·zero;
+  extern N16PN·T *N16PN·one;
+  extern N16PN·T *N16PN·all_one_bit;
+  extern N16PN·T *N16PN·lsb;
+  extern N16PN·T *N16PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N16PN·Status·ok = 0
+   ,N16PN·Status·overflow = 1
+   ,N16PN·Status·accumulator1_overflow = 2
+   ,N16PN·Status·carry = 3
+   ,N16PN·Status·borrow = 4
+   ,N16PN·Status·undefined_divide_by_zero = 5
+   ,N16PN·Status·undefined_modulus_zero = 6
+   ,N16PN·Status·gt_max_shift_count = 7
+   ,N16PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+   ,N16PN·Status·one_word_product = 9
+   ,N16PN·Status·two_word_product = 10
+  } N16PN·Status;
+
+  typedef enum{
+    N16PN·Order_lt = -1
+   ,N16PN·Order_eq = 0
+   ,N16PN·Order_gt = 1
+  } N16PN·Order;
+
+  typedef N16PN·T *( *N16PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N16PN·T *(*allocate_array_zero)(Extent, N16PN·Allocate_MemoryFault);
+    N16PN·T *(*allocate_array)(Extent, N16PN·Allocate_MemoryFault);
+    void (*deallocate)(N16PN·T*);
+
+    void (*copy)(N16PN·T*, N16PN·T*);
+    void (*bit_and)(N16PN·T*, N16PN·T*, N16PN·T*);
+    void (*bit_or)(N16PN·T*, N16PN·T*, N16PN·T*);
+    void (*bit_complement)(N16PN·T*, N16PN·T*);
+    void (*bit_twos_complement)(N16PN·T*, N16PN·T*);
+    N16PN·Order (*compare)(N16PN·T*, N16PN·T*);
+    bool (*lt)(N16PN·T*, N16PN·T*);
+    bool (*gt)(N16PN·T*, N16PN·T*);
+    bool (*eq)(N16PN·T*, N16PN·T*);
+    bool (*eq_zero)(N16PN·T*);
+    N16PN·Status (*accumulate)(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...);
+    N16PN·Status (*add)(N16PN·T*, N16PN·T*, N16PN·T*);
+    bool (*increment)(N16PN·T *a);
+    N16PN·Status (*subtract)(N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*multiply)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*divide)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*modulus)(N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*shift_left)(Extent, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*shift_right)(Extent, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*arithmetic_shift_right)(Extent, N16PN·T*, N16PN·T*);
+
+    N16PN·T* (*access)(N16PN·T*, Extent);
+    void (*from_uint32)(N16PN·T *destination ,uint32_t value);
+  } N16PN·Λ;
+
+  Local const N16PN·Λ N16PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N16PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N16PN·T{
+      Digit d0;
+    };
+
+    N16PN·T N16PN·constant[4] = {
+    {.d0 = 0},
+    {.d0 = 1},
+    {.d0 = ~(uint16_t)0},
+    {.d0 = 1 << 15}
+    };
+
+    N16PN·T *N16PN·zero = &N16PN·constant[0];
+    N16PN·T *N16PN·one = &N16PN·constant[1];
+    N16PN·T *N16PN·all_one_bit = &N16PN·constant[2];
+    N16PN·T *N16PN·msb = &N16PN·constant[3];
+    N16PN·T *N16PN·lsb = &N16PN·constant[1];
+
+    // the allocate an array of N16
+    N16PN·T *N16PN·allocate_array(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){
+      N16PN·T *instance = malloc((extent + 1) * sizeof(N16PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N16PN·T *N16PN·allocate_array_zero(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){
+      N16PN·T *instance = calloc(extent + 1, sizeof(N16PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N16PN·deallocate(N16PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N16PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    Local N16PN·T N16PN·t[4];
+
+    // allocation 
+
+    extern N16PN·T *N16PN·allocate_array(Extent, N16PN·Allocate_MemoryFault);
+    extern N16PN·T *N16PN·allocate_array_zero(Extent, N16PN·Allocate_MemoryFault);
+    extern void N16PN·deallocate(N16PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N16PN·T* N16PN·access(N16PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N16PN·from_uint32(N16PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = (uint16_t)(value & 0xFFFF);
+    }
+
+    // copy, convenience copy
+
+    Local void N16PN·copy(N16PN·T *destination ,N16PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    Local void N16PN·set_to_zero(N16PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N16PN·set_to_one(N16PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N16PN·bit_and(N16PN·T *result, N16PN·T *a, N16PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N16PN·bit_or(N16PN·T *result, N16PN·T *a, N16PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N16PN·bit_complement(N16PN·T *result, N16PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N16PN·bit_twos_complement(N16PN·T *result ,N16PN·T *a){
+      result->d0 = (uint16_t)(~a->d0 + 1);
+    }
+
+    // test functions
+
+    Local N16PN·Order N16PN·compare(N16PN·T *a, N16PN·T *b){
+      if(a->d0 < b->d0) return N16PN·Order_lt;
+      if(a->d0 > b->d0) return N16PN·Order_gt;
+      return N16PN·Order_eq;
+    }
+
+    Local bool N16PN·lt(N16PN·T *a ,N16PN·T *b){
+      return a->d0 < b->d0;
+    }    
+
+    Local bool N16PN·gt(N16PN·T *a ,N16PN·T *b){
+      return a->d0 > b->d0;
+    }    
+
+    Local bool N16PN·eq(N16PN·T *a ,N16PN·T *b){
+      return a->d0 == b->d0;
+    }    
+
+    Local bool N16PN·eq_zero(N16PN·T *a){
+      return a->d0 == 0;
+    }    
+
+    // arithmetic operations
+
+    Local N16PN·Status N16PN·accumulate(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N16PN·T *current;
+
+      while( (current = va_arg(args ,N16PN·T*)) ){
+        sum += current->d0;
+        if(sum < current->d0){
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N16PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = (uint16_t)carry;
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·add(N16PN·T *sum ,N16PN·T *a ,N16PN·T *b){
+      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
+      sum->d0 = (uint16_t)(result & 0xFFFF);
+      return (result >> 16) ? N16PN·Status·carry : N16PN·Status·ok;
+    }
+
+    Local bool N16PN·increment(N16PN·T *a){
+      a->d0++;
+      return (a->d0 == 0);
+    }
+
+    Local N16PN·Status N16PN·subtract(N16PN·T *difference ,N16PN·T *a ,N16PN·T *b){
+      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
+      difference->d0 = (uint16_t)(diff & 0xFFFF);
+      return (diff > a->d0) ? N16PN·Status·borrow : N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·multiply(N16PN·T *product1 ,N16PN·T *product0 ,N16PN·T *a ,N16PN·T *b){
+      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
+      product0->d0 = (uint16_t)(product & 0xFFFF);
+      product1->d0 = (uint16_t)((product >> 16) & 0xFFFF);
+
+      if(product1->d0 == 0) return N16PN·Status·one_word_product;
+      return N16PN·Status·two_word_product;
+    }
+
+    Local N16PN·Status N16PN·divide(N16PN·T *remainder ,N16PN·T *quotient ,N16PN·T *a ,N16PN·T *b){
+      if(b->d0 == 0) return N16PN·Status·undefined_divide_by_zero;
+
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      quotient->d0 = (uint16_t)(dividend / divisor);
+      remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor));
+
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·modulus(N16PN·T *remainder ,N16PN·T *a ,N16PN·T *b){
+      if(b->d0 == 0) return N16PN·Status·undefined_modulus_zero;
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      uint32_t q = dividend / divisor;
+      remainder->d0 = (uint16_t)(dividend - (q * divisor));
+      return N16PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint16_t (*ShiftOp)(uint16_t, uint16_t);
+
+    Local uint16_t shift_left_op(uint16_t value, uint16_t amount){
+      return value << amount;
+    }
+
+    Local uint16_t shift_right_op(uint16_t value, uint16_t amount){
+      return (uint16_t)(value >> amount);
+    }
+
+    Local N16PN·Status N16PN·shift
+    (
+     uint16_t shift_count
+     ,N16PN·T *spill
+     ,N16PN·T *operand
+     ,N16PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+    ){
+
+      if(operand == NULL && spill == NULL) return N16PN·Status·ok;
+
+      if(operand == NULL){
+        operand = &N16PN·t[0];
+        N16PN·copy(operand, N16PN·zero);
+      }
+
+      if(shift_count > 15) return N16PN·Status·gt_max_shift_count;
+
+      N16PN·T *given_operand = &N16PN·t[1];
+      N16PN·copy(given_operand, operand);
+
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (16 - shift_count));
+        N16PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count));
+      }
+
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status 
+    N16PN·shift_left(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){
+      return N16PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N16PN·Status 
+    N16PN·shift_right(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){
+      return N16PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N16PN·Status 
+    N16PN·arithmetic_shift_right(uint16_t shift_count, N16PN·T *operand, N16PN·T *spill){
+
+      if(shift_count > 15) return N16PN·Status·gt_max_shift_count;
+
+      if(operand == NULL){
+        operand = &N16PN·t[0];
+        N16PN·copy(operand, N16PN·zero);
+      }
+
+      N16PN·T *fill = (operand->d0 & 0x8000) ? N16PN·all_one_bit : N16PN·zero;
+      return N16PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N16PN·Λ N16PN·λ = {
+
+      .allocate_array = N16PN·allocate_array
+     ,.allocate_array_zero = N16PN·allocate_array_zero
+     ,.deallocate = N16PN·deallocate
+
+     ,.copy = N16PN·copy
+     ,.bit_and = N16PN·bit_and
+     ,.bit_or = N16PN·bit_or
+     ,.bit_complement = N16PN·bit_complement
+     ,.bit_twos_complement = N16PN·bit_twos_complement
+     ,.compare = N16PN·compare
+     ,.lt = N16PN·lt
+     ,.gt = N16PN·gt
+     ,.eq = N16PN·eq
+     ,.eq_zero = N16PN·eq_zero
+     ,.accumulate = N16PN·accumulate
+     ,.add = N16PN·add
+     ,.increment = N16PN·increment
+     ,.subtract = N16PN·subtract
+     ,.multiply = N16PN·multiply
+     ,.divide = N16PN·divide
+     ,.modulus = N16PN·modulus
+     ,.shift_left = N16PN·shift_left
+     ,.shift_right = N16PN·shift_right
+     ,.arithmetic_shift_right = N16PN·arithmetic_shift_right
+
+     ,.access = N16PN·access
+     ,.from_uint32 = N16PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/developer/cc🖉/N16n.lib.c b/developer/cc🖉/N16n.lib.c
deleted file mode 100644 (file)
index c28ab29..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
-  N16 - a processor native type
-
-  For binary operations:  a op b -> c
-
-  See the document on the proper use of the Natural types.
-
-  On the subject of multiple pointers indicating the same location in memory:
-
-  When a routine has multiple results, and one or more of the result location
-  pointers point to the same storage, the routine will either return an error
-  status, or have defined behavior.
-
-  When a routine has multiple operands, in any combination, those
-  pointers can point to the same location, and the routine will
-  function as advertised.
-
-  When an operand functions as both an input and a result, perhaps due
-  to a result pointer pointing to the same place as an operand
-  pointer, the routine will function as advertised. (Internally the
-  routine might make a temporary copy of the operand to accomplish
-  this.)
-*/
-
-#define N16n·DEBUG
-
-#ifndef FACE
-#define N16n·IMPLEMENTATION
-#define FACE
-#endif
-
-//--------------------------------------------------------------------------------
-// Interface
-
-#ifndef N16n·FACE
-#define N16n·FACE
-
-  #include <stdint.h>
-  #include <stdbool.h>
-  #include <stdarg.h>
-  #include <stdlib.h>
-
-  //----------------------------------------
-  // Instance Data (Declaration Only)
-
-  typedef uint16_t Extent;
-  typedef uint16_t Digit;
-
-  typedef struct N16n·T N16n·T;
-
-  extern N16n·T *N16n·zero;
-  extern N16n·T *N16n·one;
-  extern N16n·T *N16n·all_one_bit;
-  extern N16n·T *N16n·lsb;
-  extern N16n·T *N16n·msb;
-
-  //----------------------------------------
-  // Return/Error Status and handlers
-
-  typedef enum{
-    N16n·Status·ok = 0
-   ,N16n·Status·overflow = 1
-   ,N16n·Status·accumulator1_overflow = 2
-   ,N16n·Status·carry = 3
-   ,N16n·Status·borrow = 4
-   ,N16n·Status·undefined_divide_by_zero = 5
-   ,N16n·Status·undefined_modulus_zero = 6
-   ,N16n·Status·gt_max_shift_count = 7
-   ,N16n·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
-   ,N16n·Status·one_word_product = 9
-   ,N16n·Status·two_word_product = 10
-  } N16n·Status;
-
-  typedef enum{
-    N16n·Order_lt = -1
-   ,N16n·Order_eq = 0
-   ,N16n·Order_gt = 1
-  } N16n·Order;
-
-  typedef N16n·T *( *N16n·Allocate_MemoryFault )(Extent);
-
-  //----------------------------------------
-  // Interface
-
-  typedef struct{
-
-    N16n·T *(*allocate_array_zero)(Extent, N16n·Allocate_MemoryFault);
-    N16n·T *(*allocate_array)(Extent, N16n·Allocate_MemoryFault);
-    void (*deallocate)(N16n·T*);
-
-    void (*copy)(N16n·T*, N16n·T*);
-    void (*bit_and)(N16n·T*, N16n·T*, N16n·T*);
-    void (*bit_or)(N16n·T*, N16n·T*, N16n·T*);
-    void (*bit_complement)(N16n·T*, N16n·T*);
-    void (*bit_twos_complement)(N16n·T*, N16n·T*);
-    N16n·Order (*compare)(N16n·T*, N16n·T*);
-    bool (*lt)(N16n·T*, N16n·T*);
-    bool (*gt)(N16n·T*, N16n·T*);
-    bool (*eq)(N16n·T*, N16n·T*);
-    bool (*eq_zero)(N16n·T*);
-    N16n·Status (*accumulate)(N16n·T *accumulator1 ,N16n·T *accumulator0 ,...);
-    N16n·Status (*add)(N16n·T*, N16n·T*, N16n·T*);
-    bool (*increment)(N16n·T *a);
-    N16n·Status (*subtract)(N16n·T*, N16n·T*, N16n·T*);
-    N16n·Status (*multiply)(N16n·T*, N16n·T*, N16n·T*, N16n·T*);
-    N16n·Status (*divide)(N16n·T*, N16n·T*, N16n·T*, N16n·T*);
-    N16n·Status (*modulus)(N16n·T*, N16n·T*, N16n·T*);
-    N16n·Status (*shift_left)(Extent, N16n·T*, N16n·T*, N16n·T*);
-    N16n·Status (*shift_right)(Extent, N16n·T*, N16n·T*, N16n·T*);
-    N16n·Status (*arithmetic_shift_right)(Extent, N16n·T*, N16n·T*);
-
-    N16n·T* (*access)(N16n·T*, Extent);
-    void (*from_uint32)(N16n·T *destination ,uint32_t value);
-  } N16n·Λ;
-
-  Local const N16n·Λ N16n·λ; // initialized in the LOCAL section
-
-#endif
-
-//--------------------------------------------------------------------------------
-// Implementation
-
-#ifdef N16n·IMPLEMENTATION
-
-  // this part goes into the library
-  #ifndef LOCAL
-
-    #include <stdarg.h>
-    #include <stdlib.h>
-
-    struct N16n·T{
-      Digit d0;
-    };
-
-    N16n·T N16n·constant[4] = {
-    {.d0 = 0},
-    {.d0 = 1},
-    {.d0 = ~(uint16_t)0},
-    {.d0 = 1 << 15}
-    };
-
-    N16n·T *N16n·zero = &N16n·constant[0];
-    N16n·T *N16n·one = &N16n·constant[1];
-    N16n·T *N16n·all_one_bit = &N16n·constant[2];
-    N16n·T *N16n·msb = &N16n·constant[3];
-    N16n·T *N16n·lsb = &N16n·constant[1];
-
-    // the allocate an array of N16
-    N16n·T *N16n·allocate_array(Extent extent ,N16n·Allocate_MemoryFault memory_fault){
-      N16n·T *instance = malloc((extent + 1) * sizeof(N16n·T));
-      if(!instance){
-        return memory_fault ? memory_fault(extent) : NULL;
-      }
-      return instance;
-    }
-
-    N16n·T *N16n·allocate_array_zero(Extent extent ,N16n·Allocate_MemoryFault memory_fault){
-      N16n·T *instance = calloc(extent + 1, sizeof(N16n·T));
-      if(!instance){
-        return memory_fault ? memory_fault(extent) : NULL;
-      }
-      return instance;
-    }
-
-    void N16n·deallocate(N16n·T *unencumbered){
-      free(unencumbered);
-    }
-
-
-  #endif
-
-  // This part is included after the library user's code
-  #ifdef LOCAL
-
-    // instance
-
-    struct N16n·T{
-      Digit d0;
-    };
-
-    // temporary variables
-    Local N16n·T N16n·t[4];
-
-    // allocation 
-
-    extern N16n·T *N16n·allocate_array(Extent, N16n·Allocate_MemoryFault);
-    extern N16n·T *N16n·allocate_array_zero(Extent, N16n·Allocate_MemoryFault);
-    extern void N16n·deallocate(N16n·T *);
-
-    // so the user can access numbers in an array allocation
-    Local N16n·T* N16n·access(N16n·T *array ,Extent index){
-      return &array[index];
-    }
-
-    Local void N16n·from_uint32(N16n·T *destination ,uint32_t value){
-      if(destination == NULL) return;
-      destination->d0 = (uint16_t)(value & 0xFFFF);
-    }
-
-    // copy, convenience copy
-
-    Local void N16n·copy(N16n·T *destination ,N16n·T *source){
-      if(source == destination) return;
-      *destination = *source;
-    }
-
-    Local void N16n·set_to_zero(N16n·T *instance){
-      instance->d0 = 0;
-    }
-
-    Local void N16n·set_to_one(N16n·T *instance){
-      instance->d0 = 1;
-    }
-
-    // bit operations
-
-    Local void N16n·bit_and(N16n·T *result, N16n·T *a, N16n·T *b){
-      result->d0 = a->d0 & b->d0;
-    }
-
-    Local void N16n·bit_or(N16n·T *result, N16n·T *a, N16n·T *b){
-      result->d0 = a->d0 | b->d0;
-    }
-
-    Local void N16n·bit_complement(N16n·T *result, N16n·T *a){
-      result->d0 = ~a->d0;
-    }
-
-    Local void N16n·bit_twos_complement(N16n·T *result ,N16n·T *a){
-      result->d0 = (uint16_t)(~a->d0 + 1);
-    }
-
-    // test functions
-
-    Local N16n·Order N16n·compare(N16n·T *a, N16n·T *b){
-      if(a->d0 < b->d0) return N16n·Order_lt;
-      if(a->d0 > b->d0) return N16n·Order_gt;
-      return N16n·Order_eq;
-    }
-
-    Local bool N16n·lt(N16n·T *a ,N16n·T *b){
-      return a->d0 < b->d0;
-    }    
-
-    Local bool N16n·gt(N16n·T *a ,N16n·T *b){
-      return a->d0 > b->d0;
-    }    
-
-    Local bool N16n·eq(N16n·T *a ,N16n·T *b){
-      return a->d0 == b->d0;
-    }    
-
-    Local bool N16n·eq_zero(N16n·T *a){
-      return a->d0 == 0;
-    }    
-
-    // arithmetic operations
-
-    Local N16n·Status N16n·accumulate(N16n·T *accumulator1 ,N16n·T *accumulator0 ,...){
-
-      va_list args;
-      va_start(args ,accumulator0);
-      uint32_t sum = accumulator0->d0;
-      uint32_t carry = 0;
-      N16n·T *current;
-
-      while( (current = va_arg(args ,N16n·T*)) ){
-        sum += current->d0;
-        if(sum < current->d0){
-          (carry)++;
-          if(carry == 0){
-            va_end(args);
-            return N16n·Status·accumulator1_overflow;
-          }
-        }
-      }
-      va_end(args);
-
-      accumulator1->d0 = (uint16_t)carry;
-      return N16n·Status·ok;
-    }
-
-    Local N16n·Status N16n·add(N16n·T *sum ,N16n·T *a ,N16n·T *b){
-      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
-      sum->d0 = (uint16_t)(result & 0xFFFF);
-      return (result >> 16) ? N16n·Status·carry : N16n·Status·ok;
-    }
-
-    Local bool N16n·increment(N16n·T *a){
-      a->d0++;
-      return (a->d0 == 0);
-    }
-
-    Local N16n·Status N16n·subtract(N16n·T *difference ,N16n·T *a ,N16n·T *b){
-      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
-      difference->d0 = (uint16_t)(diff & 0xFFFF);
-      return (diff > a->d0) ? N16n·Status·borrow : N16n·Status·ok;
-    }
-
-    Local N16n·Status N16n·multiply(N16n·T *product1 ,N16n·T *product0 ,N16n·T *a ,N16n·T *b){
-      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
-      product0->d0 = (uint16_t)(product & 0xFFFF);
-      product1->d0 = (uint16_t)((product >> 16) & 0xFFFF);
-
-      if(product1->d0 == 0) return N16n·Status·one_word_product;
-      return N16n·Status·two_word_product;
-    }
-
-    Local N16n·Status N16n·divide(N16n·T *remainder ,N16n·T *quotient ,N16n·T *a ,N16n·T *b){
-      if(b->d0 == 0) return N16n·Status·undefined_divide_by_zero;
-
-      uint32_t dividend = a->d0;
-      uint32_t divisor = b->d0;
-      quotient->d0 = (uint16_t)(dividend / divisor);
-      remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor));
-
-      return N16n·Status·ok;
-    }
-
-    Local N16n·Status N16n·modulus(N16n·T *remainder ,N16n·T *a ,N16n·T *b){
-      if(b->d0 == 0) return N16n·Status·undefined_modulus_zero;
-      uint32_t dividend = a->d0;
-      uint32_t divisor = b->d0;
-      uint32_t q = dividend / divisor;
-      remainder->d0 = (uint16_t)(dividend - (q * divisor));
-      return N16n·Status·ok;
-    }
-
-    // bit motion
-
-    typedef uint16_t (*ShiftOp)(uint16_t, uint16_t);
-
-    Local uint16_t shift_left_op(uint16_t value, uint16_t amount){
-      return value << amount;
-    }
-
-    Local uint16_t shift_right_op(uint16_t value, uint16_t amount){
-      return (uint16_t)(value >> amount);
-    }
-
-    Local N16n·Status N16n·shift
-    (
-     uint16_t shift_count
-     ,N16n·T *spill
-     ,N16n·T *operand
-     ,N16n·T *fill
-     ,ShiftOp shift_op
-     ,ShiftOp complement_shift_op
-    ){
-
-      if(operand == NULL && spill == NULL) return N16n·Status·ok;
-
-      if(operand == NULL){
-        operand = &N16n·t[0];
-        N16n·copy(operand, N16n·zero);
-      }
-
-      if(shift_count > 15) return N16n·Status·gt_max_shift_count;
-
-      N16n·T *given_operand = &N16n·t[1];
-      N16n·copy(given_operand, operand);
-
-      operand->d0 = shift_op(given_operand->d0, shift_count);
-      if(fill != NULL){
-        fill->d0 = complement_shift_op(fill->d0, (16 - shift_count));
-        N16n·bit_or(operand, operand, fill);
-      }
-      if(spill != NULL){
-        spill->d0 = shift_op(spill->d0, shift_count);
-        spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count));
-      }
-
-      return N16n·Status·ok;
-    }
-
-    Local N16n·Status 
-    N16n·shift_left(uint16_t shift_count, N16n·T *spill, N16n·T *operand, N16n·T *fill){
-      return N16n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
-    }
-
-    Local N16n·Status 
-    N16n·shift_right(uint16_t shift_count, N16n·T *spill, N16n·T *operand, N16n·T *fill){
-      return N16n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
-    }
-
-    Local N16n·Status 
-    N16n·arithmetic_shift_right(uint16_t shift_count, N16n·T *operand, N16n·T *spill){
-
-      if(shift_count > 15) return N16n·Status·gt_max_shift_count;
-
-      if(operand == NULL){
-        operand = &N16n·t[0];
-        N16n·copy(operand, N16n·zero);
-      }
-
-      N16n·T *fill = (operand->d0 & 0x8000) ? N16n·all_one_bit : N16n·zero;
-      return N16n·shift_right(shift_count, spill, operand, fill);
-    }
-
-    Local const N16n·Λ N16n·λ = {
-
-      .allocate_array = N16n·allocate_array
-     ,.allocate_array_zero = N16n·allocate_array_zero
-     ,.deallocate = N16n·deallocate
-
-     ,.copy = N16n·copy
-     ,.bit_and = N16n·bit_and
-     ,.bit_or = N16n·bit_or
-     ,.bit_complement = N16n·bit_complement
-     ,.bit_twos_complement = N16n·bit_twos_complement
-     ,.compare = N16n·compare
-     ,.lt = N16n·lt
-     ,.gt = N16n·gt
-     ,.eq = N16n·eq
-     ,.eq_zero = N16n·eq_zero
-     ,.accumulate = N16n·accumulate
-     ,.add = N16n·add
-     ,.increment = N16n·increment
-     ,.subtract = N16n·subtract
-     ,.multiply = N16n·multiply
-     ,.divide = N16n·divide
-     ,.modulus = N16n·modulus
-     ,.shift_left = N16n·shift_left
-     ,.shift_right = N16n·shift_right
-     ,.arithmetic_shift_right = N16n·arithmetic_shift_right
-
-     ,.access = N16n·access
-     ,.from_uint32 = N16n·from_uint32
-    };
-
-  #endif
-
-#endif
diff --git a/developer/cc🖉/N32PN.lib.c b/developer/cc🖉/N32PN.lib.c
new file mode 100644 (file)
index 0000000..952f570
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+  N32 - a processor native type
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+
+*/
+
+#define N32PN·DEBUG
+
+#ifndef FACE
+#define N32PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N32PN·FACE
+#define N32PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint32_t Extent;
+  typedef uint32_t Digit;
+
+  typedef struct N32PN·T N32PN·T;
+
+  extern N32PN·T *N32PN·zero;
+  extern N32PN·T *N32PN·one;
+  extern N32PN·T *N32PN·all_one_bit;
+  extern N32PN·T *N32PN·lsb;
+  extern N32PN·T *N32PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N32PN·Status·ok = 0
+    ,N32PN·Status·overflow = 1
+    ,N32PN·Status·accumulator1_overflow = 2
+    ,N32PN·Status·carry = 3
+    ,N32PN·Status·borrow = 4
+    ,N32PN·Status·undefined_divide_by_zero = 5
+    ,N32PN·Status·undefined_modulus_zero = 6
+    ,N32PN·Status·gt_max_shift_count = 7
+    ,N32PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+    ,N32PN·Status·one_word_product = 9
+    ,N32PN·Status·two_word_product = 10
+  } N32PN·Status;
+
+  typedef enum{
+    N32PN·Order_lt = -1
+    ,N32PN·Order_eq = 0
+    ,N32PN·Order_gt = 1
+  } N32PN·Order;
+
+  typedef N32PN·T *( *N32PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N32PN·T *(*allocate_array_zero)(Extent, N32PN·Allocate_MemoryFault);
+    N32PN·T *(*allocate_array)(Extent, N32PN·Allocate_MemoryFault);
+    void (*deallocate)(N32PN·T*);
+
+    void (*copy)(N32PN·T*, N32PN·T*);
+    void (*bit_and)(N32PN·T*, N32PN·T*, N32PN·T*);
+    void (*bit_or)(N32PN·T*, N32PN·T*, N32PN·T*);
+    void (*bit_complement)(N32PN·T*, N32PN·T*);
+    void (*bit_twos_complement)(N32PN·T*, N32PN·T*);
+    N32PN·Order (*compare)(N32PN·T*, N32PN·T*);
+    bool (*lt)(N32PN·T*, N32PN·T*);
+    bool (*gt)(N32PN·T*, N32PN·T*);
+    bool (*eq)(N32PN·T*, N32PN·T*);
+    bool (*eq_zero)(N32PN·T*);
+    N32PN·Status (*accumulate)(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...);
+    N32PN·Status (*add)(N32PN·T*, N32PN·T*, N32PN·T*);
+    bool (*increment)(N32PN·T *a);
+    N32PN·Status (*subtract)(N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*multiply)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*divide)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*modulus)(N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*shift_left)(Extent, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*shift_right)(Extent, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*arithmetic_shift_right)(Extent, N32PN·T*, N32PN·T*);
+
+    N32PN·T* (*access)(N32PN·T*, Extent);
+    void (*from_uint32)(N32PN·T *destination ,uint32_t value);
+  } N32PN·Λ;
+
+  Local const N32PN·Λ N32PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N32PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N32PN·T{
+      Digit d0;
+    };
+
+    N32PN·T N32PN·constant[4] = {
+      {.d0 = 0},
+      {.d0 = 1},
+      {.d0 = ~(uint32_t)0},
+      {.d0 = 1 << 31}
+    };
+
+    N32PN·T *N32PN·zero = &N32PN·constant[0];
+    N32PN·T *N32PN·one = &N32PN·constant[1];
+    N32PN·T *N32PN·all_one_bit = &N32PN·constant[2];
+    N32PN·T *N32PN·msb = &N32PN·constant[3];
+    N32PN·T *N32PN·lsb = &N32PN·constant[1];
+
+    // the allocate an array of N32
+    N32PN·T *N32PN·allocate_array(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){
+      N32PN·T *instance = malloc((extent + 1) * sizeof(N32PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N32PN·T *N32PN·allocate_array_zero(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){
+      N32PN·T *instance = calloc( extent + 1 ,sizeof(N32PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N32PN·deallocate(N32PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N32PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    // making these LOCAL rather than reserving one block in the library is thread safe
+    // allocating a block once is more efficient
+    // library code writes these, they are not on the interface
+
+    Local N32PN·T N32PN·t[4];
+
+
+    // allocation 
+
+    extern N32PN·T *N32PN·allocate_array(Extent, N32PN·Allocate_MemoryFault);
+    extern N32PN·T *N32PN·allocate_array_zero(Extent, N32PN·Allocate_MemoryFault);
+    extern void N32PN·deallocate(N32PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N32PN·T* N32PN·access(N32PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N32PN·from_uint32(N32PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = value;
+    }
+
+    // copy, convenience copy
+
+    Local void N32PN·copy(N32PN·T *destination ,N32PN·T *source){
+      if(source == destination) return; // that was easy! 
+      *destination = *source;
+    }
+
+    Local void N32PN·set_to_zero(N32PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N32PN·set_to_one(N32PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N32PN·bit_and(N32PN·T *result, N32PN·T *a, N32PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    // result can be one of the operands
+    Local void N32PN·bit_or(N32PN·T *result, N32PN·T *a, N32PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32PN·bit_complement(N32PN·T *result, N32PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32PN·bit_twos_complement(N32PN·T *result ,N32PN·T *a){
+      result->d0 = ~a->d0 + 1;
+    }
+
+    // test functions
+
+    Local N32PN·Order N32PN·compare(N32PN·T *a, N32PN·T *b){
+      if(a->d0 < b->d0) return N32PN·Order_lt;
+      if(a->d0 > b->d0) return N32PN·Order_gt;
+      return N32PN·Order_eq;
+    }
+
+    Local bool N32PN·lt(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 < b->d0;
+    }    
+
+    Local bool N32PN·gt(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 > b->d0;
+    }    
+
+    Local bool N32PN·eq(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 == b->d0;
+    }    
+
+    Local bool N32PN·eq_zero(N32PN·T *a){
+      return  a->d0 == 0;
+    }    
+
+
+    // arithmetic operations
+
+    // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32PN·Status·accumulator1_overflow
+    //
+    // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value.
+    Local N32PN·Status N32PN·accumulate(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N32PN·T *current;
+
+      while( (current = va_arg(args ,N32PN·T *)) ){
+        sum += current->d0;
+        if(sum < current->d0){  // Accumulator1 into carry
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N32PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      // wipes out prior value of accumulator1
+      accumulator1->d0 = carry;
+
+      return N32PN·Status·ok;
+    }
+
+    Local N32PN·Status N32PN·add(N32PN·T *sum ,N32PN·T *a ,N32PN·T *b){
+      uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0;
+      sum->d0 = (uint32_t)result;
+      return (result >> 32) ? N32PN·Status·carry : N32PN·Status·ok;
+    }
+
+    Local bool N32PN·increment(N32PN·T *a){
+      a->d0++;
+      return a->d0 == 0;
+    }
+
+    Local N32PN·Status N32PN·subtract(N32PN·T *difference ,N32PN·T *a ,N32PN·T *b){
+      uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0;
+      difference->d0 = (uint32_t)diff;
+      return (diff > a->d0) ? N32PN·Status·borrow : N32PN·Status·ok;
+    }
+
+
+    Local N32PN·Status N32PN·multiply(N32PN·T *product1 ,N32PN·T *product0 ,N32PN·T *a ,N32PN·T *b){
+      uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0;
+      product0->d0 = (uint32_t)product;
+      product1->d0 = (uint32_t)(product >> 32);
+
+      if(product1->d0 == 0) return N32PN·Status·one_word_product;
+      return N32PN·Status·two_word_product;
+    }
+
+    Local N32PN·Status N32PN·divide(N32PN·T *remainder ,N32PN·T *quotient ,N32PN·T *a ,N32PN·T *b){
+      if(b->d0 == 0) return N32PN·Status·undefined_divide_by_zero; 
+
+      quotient->d0 = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient->d0 * b->d0);
+
+      return N32PN·Status·ok;
+    }
+
+    Local N32PN·Status N32PN·modulus(N32PN·T *remainder ,N32PN·T *a ,N32PN·T *b){
+      if(b->d0 == 0) return N32PN·Status·undefined_modulus_zero; 
+      uint32_t quotient = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient * b->d0);
+      return N32PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint32_t (*ShiftOp)(uint32_t, uint32_t);
+
+    Local uint32_t shift_left_op(uint32_t value, uint32_t amount){
+      return value << amount;
+    }
+
+    Local uint32_t shift_right_op(uint32_t value, uint32_t amount){
+      return value >> amount;
+    }
+
+    // modifies all three of its operands
+    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, 
+    Local N32PN·Status N32PN·shift
+    (
+     uint32_t shift_count
+     ,N32PN·T *spill
+     ,N32PN·T *operand
+     ,N32PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+     ){
+
+      // If no result is needed, return immediately.
+      if(operand == NULL && spill == NULL) return N32PN·Status·ok;
+
+      // Treat NULL operand as zero.
+      if(operand == NULL){
+        operand = &N32PN·t[0];
+        N32PN·copy(operand, N32PN·zero);
+      }
+
+      // Shifting more than one word breaks our fill/spill model.
+      if(shift_count > 31) return N32PN·Status·gt_max_shift_count;
+
+      // The given operand is still required after it is modified, so we copy it.
+      N32PN·T *given_operand = &N32PN·t[1];
+      N32PN·copy(given_operand, operand);
+
+      // Perform the shift
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (32 - shift_count));
+        N32PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count));
+      }
+
+      return N32PN·Status·ok;
+    }
+
+    // Define concrete shift functions using valid C function pointers
+    Local N32PN·Status 
+    N32PN·shift_left(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){
+      return N32PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N32PN·Status 
+    N32PN·shift_right(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){
+      return N32PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N32PN·Status 
+    N32PN·arithmetic_shift_right(uint32_t shift_count, N32PN·T *operand, N32PN·T *spill){
+
+      // Guard against excessive shift counts
+      if(shift_count > 31) return N32PN·Status·gt_max_shift_count;
+
+      // A NULL operand is treated as zero
+      if(operand == NULL){
+        operand = &N32PN·t[0];
+        N32PN·copy(operand, N32PN·zero);
+      }
+
+      // Pick the fill value based on the sign bit
+      N32PN·T *fill = (operand->d0 & 0x80000000) ? N32PN·all_one_bit : N32PN·zero;
+
+      // Call shift_right with the appropriate fill
+      return N32PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N32PN·Λ N32PN·λ = {
+
+      .allocate_array = N32PN·allocate_array
+      ,.allocate_array_zero = N32PN·allocate_array_zero
+      ,.deallocate = N32PN·deallocate
+
+      ,.copy = N32PN·copy
+      ,.bit_and = N32PN·bit_and
+      ,.bit_or = N32PN·bit_or
+      ,.bit_complement = N32PN·bit_complement
+      ,.bit_twos_complement = N32PN·bit_twos_complement
+      ,.compare = N32PN·compare
+      ,.lt = N32PN·lt
+      ,.gt = N32PN·gt
+      ,.eq = N32PN·eq
+      ,.eq_zero = N32PN·eq_zero
+      ,.accumulate = N32PN·accumulate
+      ,.add = N32PN·add
+      ,.increment = N32PN·increment
+      ,.subtract = N32PN·subtract
+      ,.multiply = N32PN·multiply
+      ,.divide = N32PN·divide
+      ,.modulus = N32PN·modulus
+      ,.shift_left = N32PN·shift_left
+      ,.shift_right = N32PN·shift_right
+      ,.arithmetic_shift_right = N32PN·arithmetic_shift_right
+
+      ,.access = N32PN·access
+      ,.from_uint32 = N32PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/developer/cc🖉/N32n.lib.c b/developer/cc🖉/N32n.lib.c
deleted file mode 100644 (file)
index 7e12dfd..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
-  N32 - a processor native type
-
-  For binary operations:  a op b -> c
-
-  See the document on the proper use of the Natural types.
-
-  On the subject of multiple pointers indicating the same location in memory:
-
-  When a routine has multiple results, and one or more of the result location
-  pointers point to the same storage, the routine will either return an error
-  status, or have defined behavior.
-
-  When a routine has multiple operands, in any combination, those
-  pointers can point to the same location, and the routine will
-  function as advertised.
-
-  When an operand functions as both an input and a result, perhaps due
-  to a result pointer pointing to the same place as an operand
-  pointer, the routine will function as advertised. (Internally the
-  routine might make a temporary copy of the operand to accomplish
-  this.)
-
-*/
-
-#define N32n·DEBUG
-
-#ifndef FACE
-#define N32n·IMPLEMENTATION
-#define FACE
-#endif
-
-//--------------------------------------------------------------------------------
-// Interface
-
-#ifndef N32n·FACE
-#define N32n·FACE
-
-  #include <stdint.h>
-  #include <stdbool.h>
-  #include <stdarg.h>
-  #include <stdlib.h>
-
-  //----------------------------------------
-  // Instance Data (Declaration Only)
-
-  typedef uint32_t Extent;
-  typedef uint32_t Digit;
-
-  typedef struct N32n·T N32n·T;
-
-  extern N32n·T *N32n·zero;
-  extern N32n·T *N32n·one;
-  extern N32n·T *N32n·all_one_bit;
-  extern N32n·T *N32n·lsb;
-  extern N32n·T *N32n·msb;
-
-  //----------------------------------------
-  // Return/Error Status and handlers
-
-  typedef enum{
-    N32n·Status·ok = 0
-    ,N32n·Status·overflow = 1
-    ,N32n·Status·accumulator1_overflow = 2
-    ,N32n·Status·carry = 3
-    ,N32n·Status·borrow = 4
-    ,N32n·Status·undefined_divide_by_zero = 5
-    ,N32n·Status·undefined_modulus_zero = 6
-    ,N32n·Status·gt_max_shift_count = 7
-    ,N32n·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
-    ,N32n·Status·one_word_product = 9
-    ,N32n·Status·two_word_product = 10
-  } N32n·Status;
-
-  typedef enum{
-    N32n·Order_lt = -1
-    ,N32n·Order_eq = 0
-    ,N32n·Order_gt = 1
-  } N32n·Order;
-
-  typedef N32n·T *( *N32n·Allocate_MemoryFault )(Extent);
-
-  //----------------------------------------
-  // Interface
-
-  typedef struct{
-
-    N32n·T *(*allocate_array_zero)(Extent, N32n·Allocate_MemoryFault);
-    N32n·T *(*allocate_array)(Extent, N32n·Allocate_MemoryFault);
-    void (*deallocate)(N32n·T*);
-
-    void (*copy)(N32n·T*, N32n·T*);
-    void (*bit_and)(N32n·T*, N32n·T*, N32n·T*);
-    void (*bit_or)(N32n·T*, N32n·T*, N32n·T*);
-    void (*bit_complement)(N32n·T*, N32n·T*);
-    void (*bit_twos_complement)(N32n·T*, N32n·T*);
-    N32n·Order (*compare)(N32n·T*, N32n·T*);
-    bool (*lt)(N32n·T*, N32n·T*);
-    bool (*gt)(N32n·T*, N32n·T*);
-    bool (*eq)(N32n·T*, N32n·T*);
-    bool (*eq_zero)(N32n·T*);
-    N32n·Status (*accumulate)(N32n·T *accumulator1 ,N32n·T *accumulator0 ,...);
-    N32n·Status (*add)(N32n·T*, N32n·T*, N32n·T*);
-    bool (*increment)(N32n·T *a);
-    N32n·Status (*subtract)(N32n·T*, N32n·T*, N32n·T*);
-    N32n·Status (*multiply)(N32n·T*, N32n·T*, N32n·T*, N32n·T*);
-    N32n·Status (*divide)(N32n·T*, N32n·T*, N32n·T*, N32n·T*);
-    N32n·Status (*modulus)(N32n·T*, N32n·T*, N32n·T*);
-    N32n·Status (*shift_left)(Extent, N32n·T*, N32n·T*, N32n·T*);
-    N32n·Status (*shift_right)(Extent, N32n·T*, N32n·T*, N32n·T*);
-    N32n·Status (*arithmetic_shift_right)(Extent, N32n·T*, N32n·T*);
-
-    N32n·T* (*access)(N32n·T*, Extent);
-    void (*from_uint32)(N32n·T *destination ,uint32_t value);
-  } N32n·Λ;
-
-  Local const N32n·Λ N32n·λ; // initialized in the LOCAL section
-
-#endif
-
-//--------------------------------------------------------------------------------
-// Implementation
-
-#ifdef N32n·IMPLEMENTATION
-
-  // this part goes into the library
-  #ifndef LOCAL
-
-    #include <stdarg.h>
-    #include <stdlib.h>
-
-    struct N32n·T{
-      Digit d0;
-    };
-
-    N32n·T N32n·constant[4] = {
-      {.d0 = 0},
-      {.d0 = 1},
-      {.d0 = ~(uint32_t)0},
-      {.d0 = 1 << 31}
-    };
-
-    N32n·T *N32n·zero = &N32n·constant[0];
-    N32n·T *N32n·one = &N32n·constant[1];
-    N32n·T *N32n·all_one_bit = &N32n·constant[2];
-    N32n·T *N32n·msb = &N32n·constant[3];
-    N32n·T *N32n·lsb = &N32n·constant[1];
-
-    // the allocate an array of N32
-    N32n·T *N32n·allocate_array(Extent extent ,N32n·Allocate_MemoryFault memory_fault){
-      N32n·T *instance = malloc((extent + 1) * sizeof(N32n·T) );
-      if(!instance){
-        return memory_fault ? memory_fault(extent) : NULL;
-      }
-      return instance;
-    }
-
-    N32n·T *N32n·allocate_array_zero(Extent extent ,N32n·Allocate_MemoryFault memory_fault){
-      N32n·T *instance = calloc( extent + 1 ,sizeof(N32n·T) );
-      if(!instance){
-        return memory_fault ? memory_fault(extent) : NULL;
-      }
-      return instance;
-    }
-
-    void N32n·deallocate(N32n·T *unencumbered){
-      free(unencumbered);
-    }
-
-  #endif
-
-  // This part is included after the library user's code
-  #ifdef LOCAL
-
-    // instance
-
-    struct N32n·T{
-      Digit d0;
-    };
-
-    // temporary variables
-    // making these LOCAL rather than reserving one block in the library is thread safe
-    // allocating a block once is more efficient
-    // library code writes these, they are not on the interface
-
-    Local N32n·T N32n·t[4];
-
-
-    // allocation 
-
-    extern N32n·T *N32n·allocate_array(Extent, N32n·Allocate_MemoryFault);
-    extern N32n·T *N32n·allocate_array_zero(Extent, N32n·Allocate_MemoryFault);
-    extern void N32n·deallocate(N32n·T *);
-
-    // so the user can access numbers in an array allocation
-    Local N32n·T* N32n·access(N32n·T *array ,Extent index){
-      return &array[index];
-    }
-
-    Local void N32n·from_uint32(N32n·T *destination ,uint32_t value){
-      if(destination == NULL) return;
-      destination->d0 = value;
-    }
-
-    // copy, convenience copy
-
-    Local void N32n·copy(N32n·T *destination ,N32n·T *source){
-      if(source == destination) return; // that was easy! 
-      *destination = *source;
-    }
-
-    Local void N32n·set_to_zero(N32n·T *instance){
-      instance->d0 = 0;
-    }
-
-    Local void N32n·set_to_one(N32n·T *instance){
-      instance->d0 = 1;
-    }
-
-    // bit operations
-
-    Local void N32n·bit_and(N32n·T *result, N32n·T *a, N32n·T *b){
-      result->d0 = a->d0 & b->d0;
-    }
-
-    // result can be one of the operands
-    Local void N32n·bit_or(N32n·T *result, N32n·T *a, N32n·T *b){
-      result->d0 = a->d0 | b->d0;
-    }
-
-    // result can the same as the operand
-    Local void N32n·bit_complement(N32n·T *result, N32n·T *a){
-      result->d0 = ~a->d0;
-    }
-
-    // result can the same as the operand
-    Local void N32n·bit_twos_complement(N32n·T *result ,N32n·T *a){
-      result->d0 = ~a->d0 + 1;
-    }
-
-    // test functions
-
-    Local N32n·Order N32n·compare(N32n·T *a, N32n·T *b){
-      if(a->d0 < b->d0) return N32n·Order_lt;
-      if(a->d0 > b->d0) return N32n·Order_gt;
-      return N32n·Order_eq;
-    }
-
-    Local bool N32n·lt(N32n·T *a ,N32n·T *b){
-      return  a->d0 < b->d0;
-    }    
-
-    Local bool N32n·gt(N32n·T *a ,N32n·T *b){
-      return  a->d0 > b->d0;
-    }    
-
-    Local bool N32n·eq(N32n·T *a ,N32n·T *b){
-      return  a->d0 == b->d0;
-    }    
-
-    Local bool N32n·eq_zero(N32n·T *a){
-      return  a->d0 == 0;
-    }    
-
-
-    // arithmetic operations
-
-    // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32n·Status·accumulator1_overflow
-    //
-    // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value.
-    Local N32n·Status N32n·accumulate(N32n·T *accumulator1 ,N32n·T *accumulator0 ,...){
-
-      va_list args;
-      va_start(args ,accumulator0);
-      uint32_t sum = accumulator0->d0;
-      uint32_t carry = 0;
-      N32n·T *current;
-
-      while( (current = va_arg(args ,N32n·T *)) ){
-        sum += current->d0;
-        if(sum < current->d0){  // Accumulator1 into carry
-          (carry)++;
-          if(carry == 0){
-            va_end(args);
-            return N32n·Status·accumulator1_overflow;
-          }
-        }
-      }
-      va_end(args);
-
-      // wipes out prior value of accumulator1
-      accumulator1->d0 = carry;
-
-      return N32n·Status·ok;
-    }
-
-    Local N32n·Status N32n·add(N32n·T *sum ,N32n·T *a ,N32n·T *b){
-      uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0;
-      sum->d0 = (uint32_t)result;
-      return (result >> 32) ? N32n·Status·carry : N32n·Status·ok;
-    }
-
-    Local bool N32n·increment(N32n·T *a){
-      a->d0++;
-      return a->d0 == 0;
-    }
-
-    Local N32n·Status N32n·subtract(N32n·T *difference ,N32n·T *a ,N32n·T *b){
-      uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0;
-      difference->d0 = (uint32_t)diff;
-      return (diff > a->d0) ? N32n·Status·borrow : N32n·Status·ok;
-    }
-
-
-    Local N32n·Status N32n·multiply(N32n·T *product1 ,N32n·T *product0 ,N32n·T *a ,N32n·T *b){
-      uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0;
-      product0->d0 = (uint32_t)product;
-      product1->d0 = (uint32_t)(product >> 32);
-
-      if(product1->d0 == 0) return N32n·Status·one_word_product;
-      return N32n·Status·two_word_product;
-    }
-
-    Local N32n·Status N32n·divide(N32n·T *remainder ,N32n·T *quotient ,N32n·T *a ,N32n·T *b){
-      if(b->d0 == 0) return N32n·Status·undefined_divide_by_zero; 
-
-      quotient->d0 = a->d0 / b->d0;
-      remainder->d0 = a->d0 - (quotient->d0 * b->d0);
-
-      return N32n·Status·ok;
-    }
-
-    Local N32n·Status N32n·modulus(N32n·T *remainder ,N32n·T *a ,N32n·T *b){
-      if(b->d0 == 0) return N32n·Status·undefined_modulus_zero; 
-      uint32_t quotient = a->d0 / b->d0;
-      remainder->d0 = a->d0 - (quotient * b->d0);
-      return N32n·Status·ok;
-    }
-
-    // bit motion
-
-    typedef uint32_t (*ShiftOp)(uint32_t, uint32_t);
-
-    Local uint32_t shift_left_op(uint32_t value, uint32_t amount){
-      return value << amount;
-    }
-
-    Local uint32_t shift_right_op(uint32_t value, uint32_t amount){
-      return value >> amount;
-    }
-
-    // modifies all three of its operands
-    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, 
-    Local N32n·Status N32n·shift
-    (
-     uint32_t shift_count
-     ,N32n·T *spill
-     ,N32n·T *operand
-     ,N32n·T *fill
-     ,ShiftOp shift_op
-     ,ShiftOp complement_shift_op
-     ){
-
-      // If no result is needed, return immediately.
-      if(operand == NULL && spill == NULL) return N32n·Status·ok;
-
-      // Treat NULL operand as zero.
-      if(operand == NULL){
-        operand = &N32n·t[0];
-        N32n·copy(operand, N32n·zero);
-      }
-
-      // Shifting more than one word breaks our fill/spill model.
-      if(shift_count > 31) return N32n·Status·gt_max_shift_count;
-
-      // The given operand is still required after it is modified, so we copy it.
-      N32n·T *given_operand = &N32n·t[1];
-      N32n·copy(given_operand, operand);
-
-      // Perform the shift
-      operand->d0 = shift_op(given_operand->d0, shift_count);
-      if(fill != NULL){
-        fill->d0 = complement_shift_op(fill->d0, (32 - shift_count));
-        N32n·bit_or(operand, operand, fill);
-      }
-      if(spill != NULL){
-        spill->d0 = shift_op(spill->d0, shift_count);
-        spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count));
-      }
-
-      return N32n·Status·ok;
-    }
-
-    // Define concrete shift functions using valid C function pointers
-    Local N32n·Status 
-    N32n·shift_left(uint32_t shift_count, N32n·T *spill, N32n·T *operand, N32n·T *fill){
-      return N32n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
-    }
-
-    Local N32n·Status 
-    N32n·shift_right(uint32_t shift_count, N32n·T *spill, N32n·T *operand, N32n·T *fill){
-      return N32n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
-    }
-
-    Local N32n·Status 
-    N32n·arithmetic_shift_right(uint32_t shift_count, N32n·T *operand, N32n·T *spill){
-
-      // Guard against excessive shift counts
-      if(shift_count > 31) return N32n·Status·gt_max_shift_count;
-
-      // A NULL operand is treated as zero
-      if(operand == NULL){
-        operand = &N32n·t[0];
-        N32n·copy(operand, N32n·zero);
-      }
-
-      // Pick the fill value based on the sign bit
-      N32n·T *fill = (operand->d0 & 0x80000000) ? N32n·all_one_bit : N32n·zero;
-
-      // Call shift_right with the appropriate fill
-      return N32n·shift_right(shift_count, spill, operand, fill);
-    }
-
-    Local const N32n·Λ N32n·λ = {
-
-      .allocate_array = N32n·allocate_array
-      ,.allocate_array_zero = N32n·allocate_array_zero
-      ,.deallocate = N32n·deallocate
-
-      ,.copy = N32n·copy
-      ,.bit_and = N32n·bit_and
-      ,.bit_or = N32n·bit_or
-      ,.bit_complement = N32n·bit_complement
-      ,.bit_twos_complement = N32n·bit_twos_complement
-      ,.compare = N32n·compare
-      ,.lt = N32n·lt
-      ,.gt = N32n·gt
-      ,.eq = N32n·eq
-      ,.eq_zero = N32n·eq_zero
-      ,.accumulate = N32n·accumulate
-      ,.add = N32n·add
-      ,.increment = N32n·increment
-      ,.subtract = N32n·subtract
-      ,.multiply = N32n·multiply
-      ,.divide = N32n·divide
-      ,.modulus = N32n·modulus
-      ,.shift_left = N32n·shift_left
-      ,.shift_right = N32n·shift_right
-      ,.arithmetic_shift_right = N32n·arithmetic_shift_right
-
-      ,.access = N32n·access
-      ,.from_uint32 = N32n·from_uint32
-    };
-
-  #endif
-
-#endif
diff --git a/developer/cc🖉/N64PN.lib.c b/developer/cc🖉/N64PN.lib.c
new file mode 100644 (file)
index 0000000..583ad08
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+  N64 - a 64-bit native type
+
+  For binary operations: a op b -> c
+
+  Similar to N32, but now each Digit is 64 bits. Where a 128-bit
+  intermediate is necessary (e.g. multiplication), we handle it
+  manually using two 64-bit parts.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N64PN·DEBUG
+
+#ifndef FACE
+#define N64PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N64PN·FACE
+#define N64PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint64_t Extent;
+  typedef uint64_t Digit;
+
+  typedef struct N64PN·T N64PN·T;
+
+  extern N64PN·T *N64PN·zero;
+  extern N64PN·T *N64PN·one;
+  extern N64PN·T *N64PN·all_one_bit;
+  extern N64PN·T *N64PN·lsb;
+  extern N64PN·T *N64PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum {
+    N64PN·Status·ok = 0
+   ,N64PN·Status·overflow = 1
+   ,N64PN·Status·accumulator1_overflow = 2
+   ,N64PN·Status·carry = 3
+   ,N64PN·Status·borrow = 4
+   ,N64PN·Status·undefined_divide_by_zero = 5
+   ,N64PN·Status·undefined_modulus_zero = 6
+   ,N64PN·Status·gt_max_shift_count = 7
+   ,N64PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+   ,N64PN·Status·one_word_product = 9
+   ,N64PN·Status·two_word_product = 10
+  } N64PN·Status;
+
+  typedef enum {
+    N64PN·Order_lt = -1
+   ,N64PN·Order_eq = 0
+   ,N64PN·Order_gt = 1
+  } N64PN·Order;
+
+  typedef N64PN·T *(*N64PN·Allocate_MemoryFault)(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct {
+
+    N64PN·T *(*allocate_array_zero)(Extent, N64PN·Allocate_MemoryFault);
+    N64PN·T *(*allocate_array)(Extent, N64PN·Allocate_MemoryFault);
+    void   (*deallocate)(N64PN·T*);
+
+    void        (*copy)(N64PN·T*, N64PN·T*);
+    void        (*bit_and)(N64PN·T*, N64PN·T*, N64PN·T*);
+    void        (*bit_or)(N64PN·T*, N64PN·T*, N64PN·T*);
+    void        (*bit_complement)(N64PN·T*, N64PN·T*);
+    void        (*bit_twos_complement)(N64PN·T*, N64PN·T*);
+    N64PN·Order   (*compare)(N64PN·T*, N64PN·T*);
+    bool        (*lt)(N64PN·T*, N64PN·T*);
+    bool        (*gt)(N64PN·T*, N64PN·T*);
+    bool        (*eq)(N64PN·T*, N64PN·T*);
+    bool        (*eq_zero)(N64PN·T*);
+    N64PN·Status  (*accumulate)(N64PN·T *accumulator1, N64PN·T *accumulator0, ...);
+    N64PN·Status  (*add)(N64PN·T*, N64PN·T*, N64PN·T*);
+    bool        (*increment)(N64PN·T *a);
+    N64PN·Status  (*subtract)(N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*multiply)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*divide)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*modulus)(N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*shift_left)(Extent, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*shift_right)(Extent, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*arithmetic_shift_right)(Extent, N64PN·T*, N64PN·T*);
+
+    N64PN·T*      (*access)(N64PN·T*, Extent);
+    void        (*from_uint64)(N64PN·T *destination, uint64_t value);
+
+  } N64PN·Λ;
+
+  Local const N64PN·Λ N64PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N64PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N64PN·T {
+      Digit d0;
+    };
+
+    // For constants, we store them in an array for convenience
+    // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63)
+    N64PN·T N64PN·constant[4] = {
+      {.d0 = 0ULL},
+      {.d0 = 1ULL},
+      {.d0 = ~(uint64_t)0ULL},
+      {.d0 = 1ULL << 63}
+    };
+
+    N64PN·T *N64PN·zero = &N64PN·constant[0];
+    N64PN·T *N64PN·one = &N64PN·constant[1];
+    N64PN·T *N64PN·all_one_bit = &N64PN·constant[2];
+    N64PN·T *N64PN·msb = &N64PN·constant[3];
+    N64PN·T *N64PN·lsb = &N64PN·constant[1];
+
+    // allocate an array of N64
+    N64PN·T *N64PN·allocate_array(Extent extent, N64PN·Allocate_MemoryFault memory_fault){
+      N64PN·T *instance = malloc( (extent + 1) * sizeof(N64PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N64PN·T *N64PN·allocate_array_zero(Extent extent, N64PN·Allocate_MemoryFault memory_fault){
+      N64PN·T *instance = calloc(extent + 1, sizeof(N64PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N64PN·deallocate(N64PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N64PN·T {
+      Digit d0;
+    };
+
+    // local temporary variables
+    Local N64PN·T N64PN·t[4];
+
+    // allocation references
+    extern N64PN·T *N64PN·allocate_array(Extent, N64PN·Allocate_MemoryFault);
+    extern N64PN·T *N64PN·allocate_array_zero(Extent, N64PN·Allocate_MemoryFault);
+    extern void   N64PN·deallocate(N64PN·T *);
+
+    // Access array
+    Local N64PN·T* N64PN·access(N64PN·T *array, Extent index){
+      return &array[index];
+    }
+
+    Local void N64PN·from_uint64(N64PN·T *destination, uint64_t value){
+      if(destination == NULL) return;
+      destination->d0 = value;
+    }
+
+    // copy
+    Local void N64PN·copy(N64PN·T *destination, N64PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    // bit operations
+
+    Local void N64PN·bit_and(N64PN·T *result, N64PN·T *a, N64PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N64PN·bit_or(N64PN·T *result, N64PN·T *a, N64PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N64PN·bit_complement(N64PN·T *result, N64PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N64PN·bit_twos_complement(N64PN·T *result, N64PN·T *a){
+      result->d0 = ~a->d0 + 1ULL;
+    }
+
+    // compare & test functions
+
+    Local N64PN·Order N64PN·compare(N64PN·T *a, N64PN·T *b){
+      if(a->d0 < b->d0) return N64PN·Order_lt;
+      if(a->d0 > b->d0) return N64PN·Order_gt;
+      return N64PN·Order_eq;
+    }
+
+    Local bool N64PN·lt(N64PN·T *a, N64PN·T *b){
+      return (a->d0 < b->d0);
+    }
+
+    Local bool N64PN·gt(N64PN·T *a, N64PN·T *b){
+      return (a->d0 > b->d0);
+    }
+
+    Local bool N64PN·eq(N64PN·T *a, N64PN·T *b){
+      return (a->d0 == b->d0);
+    }
+
+    Local bool N64PN·eq_zero(N64PN·T *a){
+      return (a->d0 == 0ULL);
+    }
+
+    // arithmetic operations
+
+    // accumulate
+    Local N64PN·Status N64PN·accumulate(N64PN·T *accumulator1, N64PN·T *accumulator0, ...){
+      va_list args;
+      va_start(args, accumulator0);
+
+      uint64_t sum = accumulator0->d0;
+      uint64_t carry = 0;
+      N64PN·T *current;
+
+      while( (current = va_arg(args, N64PN·T*)) ){
+        uint64_t prior = sum;
+        sum += current->d0;
+        if(sum < prior){  // indicates carry
+          carry++;
+          // if carry overflowed a 64-bit, that's an accumulator1 overflow
+          if(carry == 0ULL){
+            va_end(args);
+            return N64PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = carry;
+      return N64PN·Status·ok;
+    }
+
+    // add
+    Local N64PN·Status N64PN·add(N64PN·T *sum, N64PN·T *a, N64PN·T *b){
+      __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0;
+      // But to avoid using a GNU extension, we can do the simpler approach:
+      // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits:
+      uint64_t temp = a->d0 + b->d0;
+      sum->d0 = temp;
+      if(temp < a->d0) return N64PN·Status·carry;  // means we overflowed
+      return N64PN·Status·ok;
+    }
+
+    Local bool N64PN·increment(N64PN·T *a){
+      uint64_t old = a->d0;
+      a->d0++;
+      // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF
+      return (a->d0 < old);
+    }
+
+    // subtract
+    Local N64PN·Status N64PN·subtract(N64PN·T *difference, N64PN·T *a, N64PN·T *b){
+      uint64_t tmpA = a->d0;
+      uint64_t tmpB = b->d0;
+      uint64_t diff = tmpA - tmpB;
+      difference->d0 = diff;
+      if(diff > tmpA) return N64PN·Status·borrow; // indicates we borrowed
+      return N64PN·Status·ok;
+    }
+
+    // multiply
+    // We'll do a 64x64->128 using two 64-bit accumulators
+    Local N64PN·Status N64PN·multiply(N64PN·T *product1, N64PN·T *product0, N64PN·T *a, N64PN·T *b){
+      uint64_t A = a->d0;
+      uint64_t B = b->d0;
+
+      // Break each operand into high & low 32 bits
+      uint64_t a_lo = (uint32_t)(A & 0xffffffffULL);
+      uint64_t a_hi = A >> 32;
+      uint64_t b_lo = (uint32_t)(B & 0xffffffffULL);
+      uint64_t b_hi = B >> 32;
+
+      // partial products
+      uint64_t low = a_lo * b_lo;                   // 64-bit
+      uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits
+      uint64_t high = a_hi * b_hi;                  // up to 64 bits
+
+      // incorporate cross into low, high
+      // cross is effectively the middle bits, so shift cross by 32 and add to low
+      uint64_t cross_low = (cross & 0xffffffffULL) << 32;  // lower part
+      uint64_t cross_high = cross >> 32;                   // upper part
+
+      // add cross_low to low, capture carry
+      uint64_t old_low = low;
+      low += cross_low;
+      if(low < old_low) cross_high++;
+
+      // final high
+      high += cross_high;
+
+      // store results
+      product0->d0 = low;
+      product1->d0 = high;
+
+      if(high == 0ULL) return N64PN·Status·one_word_product;
+      return N64PN·Status·two_word_product;
+    }
+
+    // divide
+    Local N64PN·Status N64PN·divide(N64PN·T *remainder, N64PN·T *quotient, N64PN·T *a, N64PN·T *b){
+      // we do not handle a > 64-bit, just the single 64-bit
+      if(b->d0 == 0ULL) return N64PN·Status·undefined_divide_by_zero;
+
+      uint64_t divd = a->d0; // dividend
+      uint64_t divs = b->d0; // divisor
+
+      quotient->d0 = divd / divs;
+      remainder->d0 = divd - (quotient->d0 * divs);
+
+      return N64PN·Status·ok;
+    }
+
+    // modulus
+    Local N64PN·Status N64PN·modulus(N64PN·T *remainder, N64PN·T *a, N64PN·T *b){
+      if(b->d0 == 0ULL) return N64PN·Status·undefined_modulus_zero;
+
+      uint64_t divd = a->d0;
+      uint64_t divs = b->d0;
+      uint64_t q = divd / divs;
+      remainder->d0 = divd - (q * divs);
+
+      return N64PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint64_t (*ShiftOp)(uint64_t, uint64_t);
+
+    Local uint64_t shift_left_op(uint64_t value, uint64_t amount){
+      return (value << amount);
+    }
+
+    Local uint64_t shift_right_op(uint64_t value, uint64_t amount){
+      return (value >> amount);
+    }
+
+    // modifies all three of its operands
+    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill
+    Local N64PN·Status N64PN·shift
+    (
+     uint64_t shift_count,
+     N64PN·T *spill,
+     N64PN·T *operand,
+     N64PN·T *fill,
+     ShiftOp shift_op,
+     ShiftOp complement_shift_op
+    ){
+      if(operand == NULL && spill == NULL) return N64PN·Status·ok;
+
+      // Treat NULL operand as zero
+      if(operand == NULL){
+        operand = &N64PN·t[0];
+        N64PN·copy(operand, N64PN·zero);
+      }
+
+      // Shifting more than 63 bits breaks fill/spill logic
+      if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count;
+
+      N64PN·T *given_operand = &N64PN·t[1];
+      N64PN·copy(given_operand, operand);
+
+      // Perform the shift
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count));
+        N64PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count));
+      }
+
+      return N64PN·Status·ok;
+    }
+
+    Local N64PN·Status N64PN·shift_left(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){
+      return N64PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N64PN·Status N64PN·shift_right(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){
+      return N64PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N64PN·Status N64PN·arithmetic_shift_right(uint64_t shift_count, N64PN·T *operand, N64PN·T *spill){
+      if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count;
+
+      // A NULL operand is treated as zero
+      if(operand == NULL){
+        operand = &N64PN·t[0];
+        N64PN·copy(operand, N64PN·zero);
+      }
+
+      // sign bit check
+      N64PN·T *fill = (operand->d0 & (1ULL << 63)) ? N64PN·all_one_bit : N64PN·zero;
+      return N64PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N64PN·Λ N64PN·λ = {
+      .allocate_array = N64PN·allocate_array
+     ,.allocate_array_zero = N64PN·allocate_array_zero
+     ,.deallocate = N64PN·deallocate
+
+     ,.copy = N64PN·copy
+     ,.bit_and = N64PN·bit_and
+     ,.bit_or = N64PN·bit_or
+     ,.bit_complement = N64PN·bit_complement
+     ,.bit_twos_complement = N64PN·bit_twos_complement
+     ,.compare = N64PN·compare
+     ,.lt = N64PN·lt
+     ,.gt = N64PN·gt
+     ,.eq = N64PN·eq
+     ,.eq_zero = N64PN·eq_zero
+     ,.accumulate = N64PN·accumulate
+     ,.add = N64PN·add
+     ,.increment = N64PN·increment
+     ,.subtract = N64PN·subtract
+     ,.multiply = N64PN·multiply
+     ,.divide = N64PN·divide
+     ,.modulus = N64PN·modulus
+     ,.shift_left = N64PN·shift_left
+     ,.shift_right = N64PN·shift_right
+     ,.arithmetic_shift_right = N64PN·arithmetic_shift_right
+
+     ,.access = N64PN·access
+     ,.from_uint64 = N64PN·from_uint64
+    };
+
+  #endif
+
+#endif
diff --git a/developer/cc🖉/N64n.lib.c b/developer/cc🖉/N64n.lib.c
deleted file mode 100644 (file)
index 2521fef..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
-  N64 - a 64-bit native type
-
-  For binary operations: a op b -> c
-
-  Similar to N32, but now each Digit is 64 bits. Where a 128-bit
-  intermediate is necessary (e.g. multiplication), we handle it
-  manually using two 64-bit parts.
-
-  On the subject of multiple pointers indicating the same location in memory:
-
-  When a routine has multiple results, and one or more of the result location
-  pointers point to the same storage, the routine will either return an error
-  status, or have defined behavior.
-
-  When a routine has multiple operands, in any combination, those
-  pointers can point to the same location, and the routine will
-  function as advertised.
-
-  When an operand functions as both an input and a result, perhaps due
-  to a result pointer pointing to the same place as an operand
-  pointer, the routine will function as advertised. (Internally the
-  routine might make a temporary copy of the operand to accomplish
-  this.)
-*/
-
-#define N64n·DEBUG
-
-#ifndef FACE
-#define N64n·IMPLEMENTATION
-#define FACE
-#endif
-
-//--------------------------------------------------------------------------------
-// Interface
-
-#ifndef N64n·FACE
-#define N64n·FACE
-
-  #include <stdint.h>
-  #include <stdbool.h>
-  #include <stdarg.h>
-  #include <stdlib.h>
-
-  //----------------------------------------
-  // Instance Data (Declaration Only)
-
-  typedef uint64_t Extent;
-  typedef uint64_t Digit;
-
-  typedef struct N64n·T N64n·T;
-
-  extern N64n·T *N64n·zero;
-  extern N64n·T *N64n·one;
-  extern N64n·T *N64n·all_one_bit;
-  extern N64n·T *N64n·lsb;
-  extern N64n·T *N64n·msb;
-
-  //----------------------------------------
-  // Return/Error Status and handlers
-
-  typedef enum {
-    N64n·Status·ok = 0
-   ,N64n·Status·overflow = 1
-   ,N64n·Status·accumulator1_overflow = 2
-   ,N64n·Status·carry = 3
-   ,N64n·Status·borrow = 4
-   ,N64n·Status·undefined_divide_by_zero = 5
-   ,N64n·Status·undefined_modulus_zero = 6
-   ,N64n·Status·gt_max_shift_count = 7
-   ,N64n·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
-   ,N64n·Status·one_word_product = 9
-   ,N64n·Status·two_word_product = 10
-  } N64n·Status;
-
-  typedef enum {
-    N64n·Order_lt = -1
-   ,N64n·Order_eq = 0
-   ,N64n·Order_gt = 1
-  } N64n·Order;
-
-  typedef N64n·T *(*N64n·Allocate_MemoryFault)(Extent);
-
-  //----------------------------------------
-  // Interface
-
-  typedef struct {
-
-    N64n·T *(*allocate_array_zero)(Extent, N64n·Allocate_MemoryFault);
-    N64n·T *(*allocate_array)(Extent, N64n·Allocate_MemoryFault);
-    void   (*deallocate)(N64n·T*);
-
-    void        (*copy)(N64n·T*, N64n·T*);
-    void        (*bit_and)(N64n·T*, N64n·T*, N64n·T*);
-    void        (*bit_or)(N64n·T*, N64n·T*, N64n·T*);
-    void        (*bit_complement)(N64n·T*, N64n·T*);
-    void        (*bit_twos_complement)(N64n·T*, N64n·T*);
-    N64n·Order   (*compare)(N64n·T*, N64n·T*);
-    bool        (*lt)(N64n·T*, N64n·T*);
-    bool        (*gt)(N64n·T*, N64n·T*);
-    bool        (*eq)(N64n·T*, N64n·T*);
-    bool        (*eq_zero)(N64n·T*);
-    N64n·Status  (*accumulate)(N64n·T *accumulator1, N64n·T *accumulator0, ...);
-    N64n·Status  (*add)(N64n·T*, N64n·T*, N64n·T*);
-    bool        (*increment)(N64n·T *a);
-    N64n·Status  (*subtract)(N64n·T*, N64n·T*, N64n·T*);
-    N64n·Status  (*multiply)(N64n·T*, N64n·T*, N64n·T*, N64n·T*);
-    N64n·Status  (*divide)(N64n·T*, N64n·T*, N64n·T*, N64n·T*);
-    N64n·Status  (*modulus)(N64n·T*, N64n·T*, N64n·T*);
-    N64n·Status  (*shift_left)(Extent, N64n·T*, N64n·T*, N64n·T*);
-    N64n·Status  (*shift_right)(Extent, N64n·T*, N64n·T*, N64n·T*);
-    N64n·Status  (*arithmetic_shift_right)(Extent, N64n·T*, N64n·T*);
-
-    N64n·T*      (*access)(N64n·T*, Extent);
-    void        (*from_uint64)(N64n·T *destination, uint64_t value);
-
-  } N64n·Λ;
-
-  Local const N64n·Λ N64n·λ; // initialized in the LOCAL section
-
-#endif
-
-//--------------------------------------------------------------------------------
-// Implementation
-
-#ifdef N64n·IMPLEMENTATION
-
-  // this part goes into the library
-  #ifndef LOCAL
-
-    #include <stdarg.h>
-    #include <stdlib.h>
-
-    struct N64n·T {
-      Digit d0;
-    };
-
-    // For constants, we store them in an array for convenience
-    // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63)
-    N64n·T N64n·constant[4] = {
-      {.d0 = 0ULL},
-      {.d0 = 1ULL},
-      {.d0 = ~(uint64_t)0ULL},
-      {.d0 = 1ULL << 63}
-    };
-
-    N64n·T *N64n·zero = &N64n·constant[0];
-    N64n·T *N64n·one = &N64n·constant[1];
-    N64n·T *N64n·all_one_bit = &N64n·constant[2];
-    N64n·T *N64n·msb = &N64n·constant[3];
-    N64n·T *N64n·lsb = &N64n·constant[1];
-
-    // allocate an array of N64
-    N64n·T *N64n·allocate_array(Extent extent, N64n·Allocate_MemoryFault memory_fault){
-      N64n·T *instance = malloc( (extent + 1) * sizeof(N64n·T) );
-      if(!instance){
-        return memory_fault ? memory_fault(extent) : NULL;
-      }
-      return instance;
-    }
-
-    N64n·T *N64n·allocate_array_zero(Extent extent, N64n·Allocate_MemoryFault memory_fault){
-      N64n·T *instance = calloc(extent + 1, sizeof(N64n·T));
-      if(!instance){
-        return memory_fault ? memory_fault(extent) : NULL;
-      }
-      return instance;
-    }
-
-    void N64n·deallocate(N64n·T *unencumbered){
-      free(unencumbered);
-    }
-
-  #endif
-
-  // This part is included after the library user's code
-  #ifdef LOCAL
-
-    // instance
-
-    struct N64n·T {
-      Digit d0;
-    };
-
-    // local temporary variables
-    Local N64n·T N64n·t[4];
-
-    // allocation references
-    extern N64n·T *N64n·allocate_array(Extent, N64n·Allocate_MemoryFault);
-    extern N64n·T *N64n·allocate_array_zero(Extent, N64n·Allocate_MemoryFault);
-    extern void   N64n·deallocate(N64n·T *);
-
-    // Access array
-    Local N64n·T* N64n·access(N64n·T *array, Extent index){
-      return &array[index];
-    }
-
-    Local void N64n·from_uint64(N64n·T *destination, uint64_t value){
-      if(destination == NULL) return;
-      destination->d0 = value;
-    }
-
-    // copy
-    Local void N64n·copy(N64n·T *destination, N64n·T *source){
-      if(source == destination) return;
-      *destination = *source;
-    }
-
-    // bit operations
-
-    Local void N64n·bit_and(N64n·T *result, N64n·T *a, N64n·T *b){
-      result->d0 = a->d0 & b->d0;
-    }
-
-    Local void N64n·bit_or(N64n·T *result, N64n·T *a, N64n·T *b){
-      result->d0 = a->d0 | b->d0;
-    }
-
-    Local void N64n·bit_complement(N64n·T *result, N64n·T *a){
-      result->d0 = ~a->d0;
-    }
-
-    Local void N64n·bit_twos_complement(N64n·T *result, N64n·T *a){
-      result->d0 = ~a->d0 + 1ULL;
-    }
-
-    // compare & test functions
-
-    Local N64n·Order N64n·compare(N64n·T *a, N64n·T *b){
-      if(a->d0 < b->d0) return N64n·Order_lt;
-      if(a->d0 > b->d0) return N64n·Order_gt;
-      return N64n·Order_eq;
-    }
-
-    Local bool N64n·lt(N64n·T *a, N64n·T *b){
-      return (a->d0 < b->d0);
-    }
-
-    Local bool N64n·gt(N64n·T *a, N64n·T *b){
-      return (a->d0 > b->d0);
-    }
-
-    Local bool N64n·eq(N64n·T *a, N64n·T *b){
-      return (a->d0 == b->d0);
-    }
-
-    Local bool N64n·eq_zero(N64n·T *a){
-      return (a->d0 == 0ULL);
-    }
-
-    // arithmetic operations
-
-    // accumulate
-    Local N64n·Status N64n·accumulate(N64n·T *accumulator1, N64n·T *accumulator0, ...){
-      va_list args;
-      va_start(args, accumulator0);
-
-      uint64_t sum = accumulator0->d0;
-      uint64_t carry = 0;
-      N64n·T *current;
-
-      while( (current = va_arg(args, N64n·T*)) ){
-        uint64_t prior = sum;
-        sum += current->d0;
-        if(sum < prior){  // indicates carry
-          carry++;
-          // if carry overflowed a 64-bit, that's an accumulator1 overflow
-          if(carry == 0ULL){
-            va_end(args);
-            return N64n·Status·accumulator1_overflow;
-          }
-        }
-      }
-      va_end(args);
-
-      accumulator1->d0 = carry;
-      return N64n·Status·ok;
-    }
-
-    // add
-    Local N64n·Status N64n·add(N64n·T *sum, N64n·T *a, N64n·T *b){
-      __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0;
-      // But to avoid using a GNU extension, we can do the simpler approach:
-      // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits:
-      uint64_t temp = a->d0 + b->d0;
-      sum->d0 = temp;
-      if(temp < a->d0) return N64n·Status·carry;  // means we overflowed
-      return N64n·Status·ok;
-    }
-
-    Local bool N64n·increment(N64n·T *a){
-      uint64_t old = a->d0;
-      a->d0++;
-      // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF
-      return (a->d0 < old);
-    }
-
-    // subtract
-    Local N64n·Status N64n·subtract(N64n·T *difference, N64n·T *a, N64n·T *b){
-      uint64_t tmpA = a->d0;
-      uint64_t tmpB = b->d0;
-      uint64_t diff = tmpA - tmpB;
-      difference->d0 = diff;
-      if(diff > tmpA) return N64n·Status·borrow; // indicates we borrowed
-      return N64n·Status·ok;
-    }
-
-    // multiply
-    // We'll do a 64x64->128 using two 64-bit accumulators
-    Local N64n·Status N64n·multiply(N64n·T *product1, N64n·T *product0, N64n·T *a, N64n·T *b){
-      uint64_t A = a->d0;
-      uint64_t B = b->d0;
-
-      // Break each operand into high & low 32 bits
-      uint64_t a_lo = (uint32_t)(A & 0xffffffffULL);
-      uint64_t a_hi = A >> 32;
-      uint64_t b_lo = (uint32_t)(B & 0xffffffffULL);
-      uint64_t b_hi = B >> 32;
-
-      // partial products
-      uint64_t low = a_lo * b_lo;                   // 64-bit
-      uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits
-      uint64_t high = a_hi * b_hi;                  // up to 64 bits
-
-      // incorporate cross into low, high
-      // cross is effectively the middle bits, so shift cross by 32 and add to low
-      uint64_t cross_low = (cross & 0xffffffffULL) << 32;  // lower part
-      uint64_t cross_high = cross >> 32;                   // upper part
-
-      // add cross_low to low, capture carry
-      uint64_t old_low = low;
-      low += cross_low;
-      if(low < old_low) cross_high++;
-
-      // final high
-      high += cross_high;
-
-      // store results
-      product0->d0 = low;
-      product1->d0 = high;
-
-      if(high == 0ULL) return N64n·Status·one_word_product;
-      return N64n·Status·two_word_product;
-    }
-
-    // divide
-    Local N64n·Status N64n·divide(N64n·T *remainder, N64n·T *quotient, N64n·T *a, N64n·T *b){
-      // we do not handle a > 64-bit, just the single 64-bit
-      if(b->d0 == 0ULL) return N64n·Status·undefined_divide_by_zero;
-
-      uint64_t divd = a->d0; // dividend
-      uint64_t divs = b->d0; // divisor
-
-      quotient->d0 = divd / divs;
-      remainder->d0 = divd - (quotient->d0 * divs);
-
-      return N64n·Status·ok;
-    }
-
-    // modulus
-    Local N64n·Status N64n·modulus(N64n·T *remainder, N64n·T *a, N64n·T *b){
-      if(b->d0 == 0ULL) return N64n·Status·undefined_modulus_zero;
-
-      uint64_t divd = a->d0;
-      uint64_t divs = b->d0;
-      uint64_t q = divd / divs;
-      remainder->d0 = divd - (q * divs);
-
-      return N64n·Status·ok;
-    }
-
-    // bit motion
-
-    typedef uint64_t (*ShiftOp)(uint64_t, uint64_t);
-
-    Local uint64_t shift_left_op(uint64_t value, uint64_t amount){
-      return (value << amount);
-    }
-
-    Local uint64_t shift_right_op(uint64_t value, uint64_t amount){
-      return (value >> amount);
-    }
-
-    // modifies all three of its operands
-    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill
-    Local N64n·Status N64n·shift
-    (
-     uint64_t shift_count,
-     N64n·T *spill,
-     N64n·T *operand,
-     N64n·T *fill,
-     ShiftOp shift_op,
-     ShiftOp complement_shift_op
-    ){
-      if(operand == NULL && spill == NULL) return N64n·Status·ok;
-
-      // Treat NULL operand as zero
-      if(operand == NULL){
-        operand = &N64n·t[0];
-        N64n·copy(operand, N64n·zero);
-      }
-
-      // Shifting more than 63 bits breaks fill/spill logic
-      if(shift_count > 63ULL) return N64n·Status·gt_max_shift_count;
-
-      N64n·T *given_operand = &N64n·t[1];
-      N64n·copy(given_operand, operand);
-
-      // Perform the shift
-      operand->d0 = shift_op(given_operand->d0, shift_count);
-      if(fill != NULL){
-        fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count));
-        N64n·bit_or(operand, operand, fill);
-      }
-      if(spill != NULL){
-        spill->d0 = shift_op(spill->d0, shift_count);
-        spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count));
-      }
-
-      return N64n·Status·ok;
-    }
-
-    Local N64n·Status N64n·shift_left(uint64_t shift_count, N64n·T *spill, N64n·T *operand, N64n·T *fill){
-      return N64n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
-    }
-
-    Local N64n·Status N64n·shift_right(uint64_t shift_count, N64n·T *spill, N64n·T *operand, N64n·T *fill){
-      return N64n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
-    }
-
-    Local N64n·Status N64n·arithmetic_shift_right(uint64_t shift_count, N64n·T *operand, N64n·T *spill){
-      if(shift_count > 63ULL) return N64n·Status·gt_max_shift_count;
-
-      // A NULL operand is treated as zero
-      if(operand == NULL){
-        operand = &N64n·t[0];
-        N64n·copy(operand, N64n·zero);
-      }
-
-      // sign bit check
-      N64n·T *fill = (operand->d0 & (1ULL << 63)) ? N64n·all_one_bit : N64n·zero;
-      return N64n·shift_right(shift_count, spill, operand, fill);
-    }
-
-    Local const N64n·Λ N64n·λ = {
-      .allocate_array = N64n·allocate_array
-     ,.allocate_array_zero = N64n·allocate_array_zero
-     ,.deallocate = N64n·deallocate
-
-     ,.copy = N64n·copy
-     ,.bit_and = N64n·bit_and
-     ,.bit_or = N64n·bit_or
-     ,.bit_complement = N64n·bit_complement
-     ,.bit_twos_complement = N64n·bit_twos_complement
-     ,.compare = N64n·compare
-     ,.lt = N64n·lt
-     ,.gt = N64n·gt
-     ,.eq = N64n·eq
-     ,.eq_zero = N64n·eq_zero
-     ,.accumulate = N64n·accumulate
-     ,.add = N64n·add
-     ,.increment = N64n·increment
-     ,.subtract = N64n·subtract
-     ,.multiply = N64n·multiply
-     ,.divide = N64n·divide
-     ,.modulus = N64n·modulus
-     ,.shift_left = N64n·shift_left
-     ,.shift_right = N64n·shift_right
-     ,.arithmetic_shift_right = N64n·arithmetic_shift_right
-
-     ,.access = N64n·access
-     ,.from_uint64 = N64n·from_uint64
-    };
-
-  #endif
-
-#endif
diff --git a/developer/cc🖉/N8PN.lib.c b/developer/cc🖉/N8PN.lib.c
new file mode 100644 (file)
index 0000000..9cfd66d
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+  N8PN - PN = refers to the use of processor native accumulator 
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N8PN·DEBUG
+
+#ifndef FACE
+#define N8PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N8PN·FACE
+#define N8PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint8_t Extent;
+  typedef uint8_t Digit;
+
+  typedef struct N8PN·T N8PN·T;
+
+  extern N8PN·T *N8PN·zero;
+  extern N8PN·T *N8PN·one;
+  extern N8PN·T *N8PN·all_one_bit;
+  extern N8PN·T *N8PN·lsb;
+  extern N8PN·T *N8PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N8PN·Status·ok = 0
+   ,N8PN·Status·overflow = 1
+   ,N8PN·Status·accumulator1_overflow = 2
+   ,N8PN·Status·carry = 3
+   ,N8PN·Status·borrow = 4
+   ,N8PN·Status·undefined_divide_by_zero = 5
+   ,N8PN·Status·undefined_modulus_zero = 6
+   ,N8PN·Status·gt_max_shift_count = 7
+   ,N8PN·Status·spill_eq_operand = 8
+   ,N8PN·Status·one_word_product = 9
+   ,N8PN·Status·two_word_product = 10
+  } N8PN·Status;
+
+  typedef enum{
+    N8PN·Order_lt = -1
+   ,N8PN·Order_eq = 0
+   ,N8PN·Order_gt = 1
+  } N8PN·Order;
+
+  typedef N8PN·T *( *N8PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N8PN·T *(*allocate_array_zero)(Extent, N8PN·Allocate_MemoryFault);
+    N8PN·T *(*allocate_array)(Extent, N8PN·Allocate_MemoryFault);
+    void (*deallocate)(N8PN·T*);
+
+    void (*copy)(N8PN·T*, N8PN·T*);
+    void (*bit_and)(N8PN·T*, N8PN·T*, N8PN·T*);
+    void (*bit_or)(N8PN·T*, N8PN·T*, N8PN·T*);
+    void (*bit_complement)(N8PN·T*, N8PN·T*);
+    void (*bit_twos_complement)(N8PN·T*, N8PN·T*);
+    N8PN·Order (*compare)(N8PN·T*, N8PN·T*);
+    bool (*lt)(N8PN·T*, N8PN·T*);
+    bool (*gt)(N8PN·T*, N8PN·T*);
+    bool (*eq)(N8PN·T*, N8PN·T*);
+    bool (*eq_zero)(N8PN·T*);
+    N8PN·Status (*accumulate)(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...);
+    N8PN·Status (*add)(N8PN·T*, N8PN·T*, N8PN·T*);
+    bool (*increment)(N8PN·T *a);
+    N8PN·Status (*subtract)(N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*multiply)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*divide)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*modulus)(N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*shift_left)(Extent, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*shift_right)(Extent, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*arithmetic_shift_right)(Extent, N8PN·T*, N8PN·T*);
+
+    N8PN·T* (*access)(N8PN·T*, Extent);
+    void (*from_uint32)(N8PN·T *destination ,uint32_t value);
+  } N8PN·Λ;
+
+  Local const N8PN·Λ N8PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N8PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  struct N8PN·T{
+    Digit d0;
+  };
+
+  N8PN·T N8PN·constant[4] = {
+  {.d0 = 0},
+  {.d0 = 1},
+  {.d0 = ~(uint8_t)0},
+  {.d0 = 1 << 7}
+  };
+
+  N8PN·T *N8PN·zero = &N8PN·constant[0];
+  N8PN·T *N8PN·one = &N8PN·constant[1];
+  N8PN·T *N8PN·all_one_bit = &N8PN·constant[2];
+  N8PN·T *N8PN·msb = &N8PN·constant[3];
+  N8PN·T *N8PN·lsb = &N8PN·constant[1];
+
+  // the allocate an array of N8
+  N8PN·T *N8PN·allocate_array(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){
+    N8PN·T *instance = malloc((extent + 1) * sizeof(N8PN·T));
+    if(!instance){
+      return memory_fault ? memory_fault(extent) : NULL;
+    }
+    return instance;
+  }
+
+  N8PN·T *N8PN·allocate_array_zero(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){
+    N8PN·T *instance = calloc(extent + 1, sizeof(N8PN·T));
+    if(!instance){
+      return memory_fault ? memory_fault(extent) : NULL;
+    }
+    return instance;
+  }
+
+  void N8PN·deallocate(N8PN·T *unencumbered){
+    free(unencumbered);
+  }
+
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N8PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    Local N8PN·T N8PN·t[4];
+
+    // allocation 
+
+    extern N8PN·T *N8PN·allocate_array(Extent, N8PN·Allocate_MemoryFault);
+    extern N8PN·T *N8PN·allocate_array_zero(Extent, N8PN·Allocate_MemoryFault);
+    extern void N8PN·deallocate(N8PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N8PN·T* N8PN·access(N8PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N8PN·from_uint32(N8PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = (uint8_t)(value & 0xFF);
+    }
+
+    // copy, convenience copy
+
+    Local void N8PN·copy(N8PN·T *destination ,N8PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    Local void N8PN·set_to_zero(N8PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N8PN·set_to_one(N8PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N8PN·bit_and(N8PN·T *result, N8PN·T *a, N8PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N8PN·bit_or(N8PN·T *result, N8PN·T *a, N8PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N8PN·bit_complement(N8PN·T *result, N8PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N8PN·bit_twos_complement(N8PN·T *result ,N8PN·T *a){
+      result->d0 = (uint8_t)(~a->d0 + 1);
+    }
+
+    // test functions
+
+    Local N8PN·Order N8PN·compare(N8PN·T *a, N8PN·T *b){
+      if(a->d0 < b->d0) return N8PN·Order_lt;
+      if(a->d0 > b->d0) return N8PN·Order_gt;
+      return N8PN·Order_eq;
+    }
+
+    Local bool N8PN·lt(N8PN·T *a ,N8PN·T *b){
+      return a->d0 < b->d0;
+    }    
+
+    Local bool N8PN·gt(N8PN·T *a ,N8PN·T *b){
+      return a->d0 > b->d0;
+    }    
+
+    Local bool N8PN·eq(N8PN·T *a ,N8PN·T *b){
+      return a->d0 == b->d0;
+    }    
+
+    Local bool N8PN·eq_zero(N8PN·T *a){
+      return a->d0 == 0;
+    }    
+
+    // arithmetic operations
+
+    Local N8PN·Status N8PN·accumulate(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N8PN·T *current;
+
+      while( (current = va_arg(args ,N8PN·T*)) ){
+        sum += current->d0;
+        if(sum < current->d0){
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N8PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = (uint8_t)carry;
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·add(N8PN·T *sum ,N8PN·T *a ,N8PN·T *b){
+      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
+      sum->d0 = (uint8_t)(result & 0xFF);
+      return (result >> 8) ? N8PN·Status·carry : N8PN·Status·ok;
+    }
+
+    Local bool N8PN·increment(N8PN·T *a){
+      a->d0++;
+      return (a->d0 == 0);
+    }
+
+    Local N8PN·Status N8PN·subtract(N8PN·T *difference ,N8PN·T *a ,N8PN·T *b){
+      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
+      difference->d0 = (uint8_t)(diff & 0xFF);
+      return (diff > a->d0) ? N8PN·Status·borrow : N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·multiply(N8PN·T *product1 ,N8PN·T *product0 ,N8PN·T *a ,N8PN·T *b){
+      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
+      product0->d0 = (uint8_t)(product & 0xFF);
+      product1->d0 = (uint8_t)((product >> 8) & 0xFF);
+
+      if(product1->d0 == 0) return N8PN·Status·one_word_product;
+      return N8PN·Status·two_word_product;
+    }
+
+    Local N8PN·Status N8PN·divide(N8PN·T *remainder ,N8PN·T *quotient ,N8PN·T *a ,N8PN·T *b){
+      if(b->d0 == 0) return N8PN·Status·undefined_divide_by_zero;
+
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      quotient->d0 = (uint8_t)(dividend / divisor);
+      remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor));
+
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·modulus(N8PN·T *remainder ,N8PN·T *a ,N8PN·T *b){
+      if(b->d0 == 0) return N8PN·Status·undefined_modulus_zero;
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      uint32_t q = dividend / divisor;
+      remainder->d0 = (uint8_t)(dividend - (q * divisor));
+      return N8PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint8_t (*ShiftOp)(uint8_t, uint8_t);
+
+    Local uint8_t shift_left_op(uint8_t value, uint8_t amount){
+      return (uint8_t)(value << amount);
+    }
+
+    Local uint8_t shift_right_op(uint8_t value, uint8_t amount){
+      return (uint8_t)(value >> amount);
+    }
+
+    Local N8PN·Status N8PN·shift
+    (
+     uint8_t shift_count
+     ,N8PN·T *spill
+     ,N8PN·T *operand
+     ,N8PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+    ){
+
+      if(operand == NULL && spill == NULL) return N8PN·Status·ok;
+
+      if(operand == NULL){
+        operand = &N8PN·t[0];
+        N8PN·copy(operand, N8PN·zero);
+      }
+
+      if(shift_count > 7) return N8PN·Status·gt_max_shift_count;
+
+      N8PN·T *given_operand = &N8PN·t[1];
+      N8PN·copy(given_operand, operand);
+
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (8 - shift_count));
+        N8PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count));
+      }
+
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status 
+    N8PN·shift_left(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){
+      return N8PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N8PN·Status 
+    N8PN·shift_right(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){
+      return N8PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N8PN·Status 
+    N8PN·arithmetic_shift_right(uint8_t shift_count, N8PN·T *operand, N8PN·T *spill){
+
+      if(shift_count > 7) return N8PN·Status·gt_max_shift_count;
+
+      if(operand == NULL){
+        operand = &N8PN·t[0];
+        N8PN·copy(operand, N8PN·zero);
+      }
+
+      N8PN·T *fill = (operand->d0 & 0x80) ? N8PN·all_one_bit : N8PN·zero;
+      return N8PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N8PN·Λ N8PN·λ = {
+
+      .allocate_array = N8PN·allocate_array
+     ,.allocate_array_zero = N8PN·allocate_array_zero
+     ,.deallocate = N8PN·deallocate
+
+     ,.copy = N8PN·copy
+     ,.bit_and = N8PN·bit_and
+     ,.bit_or = N8PN·bit_or
+     ,.bit_complement = N8PN·bit_complement
+     ,.bit_twos_complement = N8PN·bit_twos_complement
+     ,.compare = N8PN·compare
+     ,.lt = N8PN·lt
+     ,.gt = N8PN·gt
+     ,.eq = N8PN·eq
+     ,.eq_zero = N8PN·eq_zero
+     ,.accumulate = N8PN·accumulate
+     ,.add = N8PN·add
+     ,.increment = N8PN·increment
+     ,.subtract = N8PN·subtract
+     ,.multiply = N8PN·multiply
+     ,.divide = N8PN·divide
+     ,.modulus = N8PN·modulus
+     ,.shift_left = N8PN·shift_left
+     ,.shift_right = N8PN·shift_right
+     ,.arithmetic_shift_right = N8PN·arithmetic_shift_right
+
+     ,.access = N8PN·access
+     ,.from_uint32 = N8PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/developer/cc🖉/N8n.lib.c b/developer/cc🖉/N8n.lib.c
deleted file mode 100644 (file)
index d2aaeb4..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
-  N8n - a processor native type
-
-  For binary operations:  a op b -> c
-
-  See the document on the proper use of the Natural types.
-
-  On the subject of multiple pointers indicating the same location in memory:
-
-  When a routine has multiple results, and one or more of the result location
-  pointers point to the same storage, the routine will either return an error
-  status, or have defined behavior.
-
-  When a routine has multiple operands, in any combination, those
-  pointers can point to the same location, and the routine will
-  function as advertised.
-
-  When an operand functions as both an input and a result, perhaps due
-  to a result pointer pointing to the same place as an operand
-  pointer, the routine will function as advertised. (Internally the
-  routine might make a temporary copy of the operand to accomplish
-  this.)
-*/
-
-#define N8n·DEBUG
-
-#ifndef FACE
-#define N8n·IMPLEMENTATION
-#define FACE
-#endif
-
-//--------------------------------------------------------------------------------
-// Interface
-
-#ifndef N8n·FACE
-#define N8n·FACE
-
-  #include <stdint.h>
-  #include <stdbool.h>
-  #include <stdarg.h>
-  #include <stdlib.h>
-
-  //----------------------------------------
-  // Instance Data (Declaration Only)
-
-  typedef uint8_t Extent;
-  typedef uint8_t Digit;
-
-  typedef struct N8n·T N8n·T;
-
-  extern N8n·T *N8n·zero;
-  extern N8n·T *N8n·one;
-  extern N8n·T *N8n·all_one_bit;
-  extern N8n·T *N8n·lsb;
-  extern N8n·T *N8n·msb;
-
-  //----------------------------------------
-  // Return/Error Status and handlers
-
-  typedef enum{
-    N8n·Status·ok = 0
-   ,N8n·Status·overflow = 1
-   ,N8n·Status·accumulator1_overflow = 2
-   ,N8n·Status·carry = 3
-   ,N8n·Status·borrow = 4
-   ,N8n·Status·undefined_divide_by_zero = 5
-   ,N8n·Status·undefined_modulus_zero = 6
-   ,N8n·Status·gt_max_shift_count = 7
-   ,N8n·Status·spill_eq_operand = 8
-   ,N8n·Status·one_word_product = 9
-   ,N8n·Status·two_word_product = 10
-  } N8n·Status;
-
-  typedef enum{
-    N8n·Order_lt = -1
-   ,N8n·Order_eq = 0
-   ,N8n·Order_gt = 1
-  } N8n·Order;
-
-  typedef N8n·T *( *N8n·Allocate_MemoryFault )(Extent);
-
-  //----------------------------------------
-  // Interface
-
-  typedef struct{
-
-    N8n·T *(*allocate_array_zero)(Extent, N8n·Allocate_MemoryFault);
-    N8n·T *(*allocate_array)(Extent, N8n·Allocate_MemoryFault);
-    void (*deallocate)(N8n·T*);
-
-    void (*copy)(N8n·T*, N8n·T*);
-    void (*bit_and)(N8n·T*, N8n·T*, N8n·T*);
-    void (*bit_or)(N8n·T*, N8n·T*, N8n·T*);
-    void (*bit_complement)(N8n·T*, N8n·T*);
-    void (*bit_twos_complement)(N8n·T*, N8n·T*);
-    N8n·Order (*compare)(N8n·T*, N8n·T*);
-    bool (*lt)(N8n·T*, N8n·T*);
-    bool (*gt)(N8n·T*, N8n·T*);
-    bool (*eq)(N8n·T*, N8n·T*);
-    bool (*eq_zero)(N8n·T*);
-    N8n·Status (*accumulate)(N8n·T *accumulator1 ,N8n·T *accumulator0 ,...);
-    N8n·Status (*add)(N8n·T*, N8n·T*, N8n·T*);
-    bool (*increment)(N8n·T *a);
-    N8n·Status (*subtract)(N8n·T*, N8n·T*, N8n·T*);
-    N8n·Status (*multiply)(N8n·T*, N8n·T*, N8n·T*, N8n·T*);
-    N8n·Status (*divide)(N8n·T*, N8n·T*, N8n·T*, N8n·T*);
-    N8n·Status (*modulus)(N8n·T*, N8n·T*, N8n·T*);
-    N8n·Status (*shift_left)(Extent, N8n·T*, N8n·T*, N8n·T*);
-    N8n·Status (*shift_right)(Extent, N8n·T*, N8n·T*, N8n·T*);
-    N8n·Status (*arithmetic_shift_right)(Extent, N8n·T*, N8n·T*);
-
-    N8n·T* (*access)(N8n·T*, Extent);
-    void (*from_uint32)(N8n·T *destination ,uint32_t value);
-  } N8n·Λ;
-
-  Local const N8n·Λ N8n·λ; // initialized in the LOCAL section
-
-#endif
-
-//--------------------------------------------------------------------------------
-// Implementation
-
-#ifdef N8n·IMPLEMENTATION
-
-  // this part goes into the library
-  #ifndef LOCAL
-
-  #include <stdarg.h>
-  #include <stdlib.h>
-
-  struct N8n·T{
-    Digit d0;
-  };
-
-  N8n·T N8n·constant[4] = {
-  {.d0 = 0},
-  {.d0 = 1},
-  {.d0 = ~(uint8_t)0},
-  {.d0 = 1 << 7}
-  };
-
-  N8n·T *N8n·zero = &N8n·constant[0];
-  N8n·T *N8n·one = &N8n·constant[1];
-  N8n·T *N8n·all_one_bit = &N8n·constant[2];
-  N8n·T *N8n·msb = &N8n·constant[3];
-  N8n·T *N8n·lsb = &N8n·constant[1];
-
-  // the allocate an array of N8
-  N8n·T *N8n·allocate_array(Extent extent ,N8n·Allocate_MemoryFault memory_fault){
-    N8n·T *instance = malloc((extent + 1) * sizeof(N8n·T));
-    if(!instance){
-      return memory_fault ? memory_fault(extent) : NULL;
-    }
-    return instance;
-  }
-
-  N8n·T *N8n·allocate_array_zero(Extent extent ,N8n·Allocate_MemoryFault memory_fault){
-    N8n·T *instance = calloc(extent + 1, sizeof(N8n·T));
-    if(!instance){
-      return memory_fault ? memory_fault(extent) : NULL;
-    }
-    return instance;
-  }
-
-  void N8n·deallocate(N8n·T *unencumbered){
-    free(unencumbered);
-  }
-
-
-  #endif
-
-  // This part is included after the library user's code
-  #ifdef LOCAL
-
-    // instance
-
-    struct N8n·T{
-      Digit d0;
-    };
-
-    // temporary variables
-    Local N8n·T N8n·t[4];
-
-    // allocation 
-
-    extern N8n·T *N8n·allocate_array(Extent, N8n·Allocate_MemoryFault);
-    extern N8n·T *N8n·allocate_array_zero(Extent, N8n·Allocate_MemoryFault);
-    extern void N8n·deallocate(N8n·T *);
-
-    // so the user can access numbers in an array allocation
-    Local N8n·T* N8n·access(N8n·T *array ,Extent index){
-      return &array[index];
-    }
-
-    Local void N8n·from_uint32(N8n·T *destination ,uint32_t value){
-      if(destination == NULL) return;
-      destination->d0 = (uint8_t)(value & 0xFF);
-    }
-
-    // copy, convenience copy
-
-    Local void N8n·copy(N8n·T *destination ,N8n·T *source){
-      if(source == destination) return;
-      *destination = *source;
-    }
-
-    Local void N8n·set_to_zero(N8n·T *instance){
-      instance->d0 = 0;
-    }
-
-    Local void N8n·set_to_one(N8n·T *instance){
-      instance->d0 = 1;
-    }
-
-    // bit operations
-
-    Local void N8n·bit_and(N8n·T *result, N8n·T *a, N8n·T *b){
-      result->d0 = a->d0 & b->d0;
-    }
-
-    Local void N8n·bit_or(N8n·T *result, N8n·T *a, N8n·T *b){
-      result->d0 = a->d0 | b->d0;
-    }
-
-    Local void N8n·bit_complement(N8n·T *result, N8n·T *a){
-      result->d0 = ~a->d0;
-    }
-
-    Local void N8n·bit_twos_complement(N8n·T *result ,N8n·T *a){
-      result->d0 = (uint8_t)(~a->d0 + 1);
-    }
-
-    // test functions
-
-    Local N8n·Order N8n·compare(N8n·T *a, N8n·T *b){
-      if(a->d0 < b->d0) return N8n·Order_lt;
-      if(a->d0 > b->d0) return N8n·Order_gt;
-      return N8n·Order_eq;
-    }
-
-    Local bool N8n·lt(N8n·T *a ,N8n·T *b){
-      return a->d0 < b->d0;
-    }    
-
-    Local bool N8n·gt(N8n·T *a ,N8n·T *b){
-      return a->d0 > b->d0;
-    }    
-
-    Local bool N8n·eq(N8n·T *a ,N8n·T *b){
-      return a->d0 == b->d0;
-    }    
-
-    Local bool N8n·eq_zero(N8n·T *a){
-      return a->d0 == 0;
-    }    
-
-    // arithmetic operations
-
-    Local N8n·Status N8n·accumulate(N8n·T *accumulator1 ,N8n·T *accumulator0 ,...){
-
-      va_list args;
-      va_start(args ,accumulator0);
-      uint32_t sum = accumulator0->d0;
-      uint32_t carry = 0;
-      N8n·T *current;
-
-      while( (current = va_arg(args ,N8n·T*)) ){
-        sum += current->d0;
-        if(sum < current->d0){
-          (carry)++;
-          if(carry == 0){
-            va_end(args);
-            return N8n·Status·accumulator1_overflow;
-          }
-        }
-      }
-      va_end(args);
-
-      accumulator1->d0 = (uint8_t)carry;
-      return N8n·Status·ok;
-    }
-
-    Local N8n·Status N8n·add(N8n·T *sum ,N8n·T *a ,N8n·T *b){
-      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
-      sum->d0 = (uint8_t)(result & 0xFF);
-      return (result >> 8) ? N8n·Status·carry : N8n·Status·ok;
-    }
-
-    Local bool N8n·increment(N8n·T *a){
-      a->d0++;
-      return (a->d0 == 0);
-    }
-
-    Local N8n·Status N8n·subtract(N8n·T *difference ,N8n·T *a ,N8n·T *b){
-      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
-      difference->d0 = (uint8_t)(diff & 0xFF);
-      return (diff > a->d0) ? N8n·Status·borrow : N8n·Status·ok;
-    }
-
-    Local N8n·Status N8n·multiply(N8n·T *product1 ,N8n·T *product0 ,N8n·T *a ,N8n·T *b){
-      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
-      product0->d0 = (uint8_t)(product & 0xFF);
-      product1->d0 = (uint8_t)((product >> 8) & 0xFF);
-
-      if(product1->d0 == 0) return N8n·Status·one_word_product;
-      return N8n·Status·two_word_product;
-    }
-
-    Local N8n·Status N8n·divide(N8n·T *remainder ,N8n·T *quotient ,N8n·T *a ,N8n·T *b){
-      if(b->d0 == 0) return N8n·Status·undefined_divide_by_zero;
-
-      uint32_t dividend = a->d0;
-      uint32_t divisor = b->d0;
-      quotient->d0 = (uint8_t)(dividend / divisor);
-      remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor));
-
-      return N8n·Status·ok;
-    }
-
-    Local N8n·Status N8n·modulus(N8n·T *remainder ,N8n·T *a ,N8n·T *b){
-      if(b->d0 == 0) return N8n·Status·undefined_modulus_zero;
-      uint32_t dividend = a->d0;
-      uint32_t divisor = b->d0;
-      uint32_t q = dividend / divisor;
-      remainder->d0 = (uint8_t)(dividend - (q * divisor));
-      return N8n·Status·ok;
-    }
-
-    // bit motion
-
-    typedef uint8_t (*ShiftOp)(uint8_t, uint8_t);
-
-    Local uint8_t shift_left_op(uint8_t value, uint8_t amount){
-      return (uint8_t)(value << amount);
-    }
-
-    Local uint8_t shift_right_op(uint8_t value, uint8_t amount){
-      return (uint8_t)(value >> amount);
-    }
-
-    Local N8n·Status N8n·shift
-    (
-     uint8_t shift_count
-     ,N8n·T *spill
-     ,N8n·T *operand
-     ,N8n·T *fill
-     ,ShiftOp shift_op
-     ,ShiftOp complement_shift_op
-    ){
-
-      if(operand == NULL && spill == NULL) return N8n·Status·ok;
-
-      if(operand == NULL){
-        operand = &N8n·t[0];
-        N8n·copy(operand, N8n·zero);
-      }
-
-      if(shift_count > 7) return N8n·Status·gt_max_shift_count;
-
-      N8n·T *given_operand = &N8n·t[1];
-      N8n·copy(given_operand, operand);
-
-      operand->d0 = shift_op(given_operand->d0, shift_count);
-      if(fill != NULL){
-        fill->d0 = complement_shift_op(fill->d0, (8 - shift_count));
-        N8n·bit_or(operand, operand, fill);
-      }
-      if(spill != NULL){
-        spill->d0 = shift_op(spill->d0, shift_count);
-        spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count));
-      }
-
-      return N8n·Status·ok;
-    }
-
-    Local N8n·Status 
-    N8n·shift_left(uint8_t shift_count, N8n·T *spill, N8n·T *operand, N8n·T *fill){
-      return N8n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
-    }
-
-    Local N8n·Status 
-    N8n·shift_right(uint8_t shift_count, N8n·T *spill, N8n·T *operand, N8n·T *fill){
-      return N8n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
-    }
-
-    Local N8n·Status 
-    N8n·arithmetic_shift_right(uint8_t shift_count, N8n·T *operand, N8n·T *spill){
-
-      if(shift_count > 7) return N8n·Status·gt_max_shift_count;
-
-      if(operand == NULL){
-        operand = &N8n·t[0];
-        N8n·copy(operand, N8n·zero);
-      }
-
-      N8n·T *fill = (operand->d0 & 0x80) ? N8n·all_one_bit : N8n·zero;
-      return N8n·shift_right(shift_count, spill, operand, fill);
-    }
-
-    Local const N8n·Λ N8n·λ = {
-
-      .allocate_array = N8n·allocate_array
-     ,.allocate_array_zero = N8n·allocate_array_zero
-     ,.deallocate = N8n·deallocate
-
-     ,.copy = N8n·copy
-     ,.bit_and = N8n·bit_and
-     ,.bit_or = N8n·bit_or
-     ,.bit_complement = N8n·bit_complement
-     ,.bit_twos_complement = N8n·bit_twos_complement
-     ,.compare = N8n·compare
-     ,.lt = N8n·lt
-     ,.gt = N8n·gt
-     ,.eq = N8n·eq
-     ,.eq_zero = N8n·eq_zero
-     ,.accumulate = N8n·accumulate
-     ,.add = N8n·add
-     ,.increment = N8n·increment
-     ,.subtract = N8n·subtract
-     ,.multiply = N8n·multiply
-     ,.divide = N8n·divide
-     ,.modulus = N8n·modulus
-     ,.shift_left = N8n·shift_left
-     ,.shift_right = N8n·shift_right
-     ,.arithmetic_shift_right = N8n·arithmetic_shift_right
-
-     ,.access = N8n·access
-     ,.from_uint32 = N8n·from_uint32
-    };
-
-  #endif
-
-#endif
diff --git a/developer/cc🖉/test_N32.cli.c b/developer/cc🖉/test_N32.cli.c
deleted file mode 100644 (file)
index 563711f..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-#include <stdio.h>
-#include <stdbool.h>
-#include <signal.h>
-#include <setjmp.h>
-
-// Enable interface section
-#define FACE
-#include "N32.lib.c"
-#undef FACE
-
-// Jump buffer for signal handling
-static sigjmp_buf jump_buffer;
-
-// Signal handler for catching fatal errors
-void signal_handler(int signal){
-  siglongjmp(jump_buffer ,1); // Jump back to test_head on error
-}
-
-// Test function prototypes
-bool test_copy();
-bool test_bitwise_operations();
-bool test_comparisons();
-bool test_arithmetic();
-bool test_shifts();
-
-// Test array (null-terminated)
-typedef bool (*TestFunction)();
-typedef struct{
-  TestFunction function;
-  const char *name;
-}TestEntry;
-
-TestEntry test_list[] = {
-   {test_copy ,"test_copy"}
-  ,{test_bitwise_operations ,"test_bitwise_operations"}
-  ,{test_comparisons ,"test_comparisons"}
-  ,{test_arithmetic ,"test_arithmetic"}
-  ,{test_shifts ,"test_shifts"}
-  ,{NULL ,NULL}  // Null termination
-};
-
-// The test runner
-int test_head(){
-  int pass_count = 0;
-  int fail_count = 0;
-
-  // Set up signal handlers
-  signal(SIGSEGV ,signal_handler);  // Catch segmentation faults
-  signal(SIGFPE ,signal_handler);   // Catch floating point errors
-  signal(SIGABRT ,signal_handler);  // Catch abort() calls
-
-  for(TestEntry *entry = test_list; entry->function != NULL; entry++){
-    if( sigsetjmp(jump_buffer ,1) == 0 ){
-      // Run the test normally
-      if( !entry->function() ){
-        printf("Failed: %s\n" ,entry->name);
-        fail_count++;
-      }else{
-        pass_count++;
-      }
-    }else{
-      // If a signal was caught
-      printf("Failed due to signaling: %s\n" ,entry->name);
-      fail_count++;
-    }
-  }
-
-  printf("Tests passed: %d\n" ,pass_count);
-  printf("Tests failed: %d\n" ,fail_count);
-  return (fail_count == 0) ? 0 : 1;
-}
-
-// Main function
-int main(int argc ,char **argv){
-  return test_head();
-}
-
-//------------------------------------------------------------------------------
-// Test Implementations
-//------------------------------------------------------------------------------
-
-bool test_copy(){
-  // Allocate memory
-  N32·T *array = N32·λ.allocate_array(2 ,NULL);
-  if( !array ) return false;
-
-  // Access elements via access function
-  N32·T *a = N32·λ.access(array ,0);
-  N32·T *b = N32·λ.access(array ,1);
-
-  // Assign value and copy
-  N32·λ.from_uint32(a ,42);
-  N32·λ.copy(b ,a);
-
-  bool success = ( N32·λ.compare(b ,a) == N32·Order_eq );
-  N32·λ.deallocate(array);
-  return success;
-}
-
-bool test_arithmetic(){
-  // Allocate memory
-  N32·T *array = N32·λ.allocate_array(3 ,NULL);
-  if( !array ) return false;
-
-  N32·T *a = N32·λ.access(array ,0);
-  N32·T *b = N32·λ.access(array ,1);
-  N32·T *result = N32·λ.access(array ,2);
-
-  N32·λ.from_uint32(a ,20);
-  N32·λ.from_uint32(b ,22);
-
-  if( N32·λ.add(result ,a ,b) != N32·Status·ok ) return false;
-  if( N32·λ.compare(result ,N32·λ.access(array ,0)) != N32·Order_gt ) return false;
-
-  if( N32·λ.subtract(result ,b ,a) != N32·Status·ok ) return false;
-  if( N32·λ.compare(result ,N32·λ.access(array ,0)) != N32·Order_lt ) return false;
-
-  N32·λ.deallocate(array);
-  return true;
-}
-
-bool test_bitwise_operations(){
-  // Allocate memory
-  N32·T *array = N32·λ.allocate_array(3, NULL);
-  if(!array) return false;
-
-  N32·T *a = N32·λ.access(array, 0);
-  N32·T *b = N32·λ.access(array, 1);
-  N32·T *result = N32·λ.access(array, 2);
-
-  // a = 0x0F0F0F0F, b = 0xF0F0F0F0
-  N32·λ.from_uint32(a, 0x0F0F0F0F);
-  N32·λ.from_uint32(b, 0xF0F0F0F0);
-
-  // bit_and => expect 0x00000000
-  N32·λ.bit_and(result, a, b);
-  N32·λ.from_uint32(a, 0x00000000);
-  if(N32·λ.compare(result, a) != N32·Order_eq){
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  // Reset a to 0x0F0F0F0F for next tests
-  N32·λ.from_uint32(a, 0x0F0F0F0F);
-
-  // bit_or => expect 0xFFFFFFFF
-  N32·λ.bit_or(result, a, b);
-  N32·λ.from_uint32(b, 0xFFFFFFFF);
-  if(N32·λ.compare(result, b) != N32·Order_eq){
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0
-  N32·λ.from_uint32(a, 0x0F0F0F0F);
-  N32·λ.bit_complement(result, a);
-  N32·λ.from_uint32(b, 0xF0F0F0F0);
-  if(N32·λ.compare(result, b) != N32·Order_eq){
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1
-  N32·λ.from_uint32(a, 0x0F0F0F0F);
-  N32·λ.bit_twos_complement(result, a);
-  N32·λ.from_uint32(b, 0xF0F0F0F1);
-  if(N32·λ.compare(result, b) != N32·Order_eq){
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  N32·λ.deallocate(array);
-  return true;
-}
-
-bool test_comparisons(){
-  // Allocate memory
-  N32·T *array = N32·λ.allocate_array(3, NULL);
-  if(!array) return false;
-
-  N32·T *a = N32·λ.access(array, 0);
-  N32·T *b = N32·λ.access(array, 1);
-  N32·T *c = N32·λ.access(array, 2);
-
-  // First set: a=0, b=42, c=42
-  N32·λ.from_uint32(a, 0);
-  N32·λ.from_uint32(b, 42);
-  N32·λ.from_uint32(c, 42);
-
-  // eq_zero(a) => true
-  if(!N32·λ.eq_zero(a)){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // eq_zero(b) => false
-  if(N32·λ.eq_zero(b)){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // eq(b, c) => true
-  if(!N32·λ.eq(b, c)){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // eq(a, b) => false
-  if(N32·λ.eq(a, b)){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // compare(a, b) => N32·Order_lt
-  if(N32·λ.compare(a, b) != N32·Order_lt){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // compare(b, a) => N32·Order_gt
-  if(N32·λ.compare(b, a) != N32·Order_gt){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // compare(b, c) => N32·Order_eq
-  if(N32·λ.compare(b, c) != N32·Order_eq){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // lt(a, b) => true, gt(b, a) => true
-  if(!N32·λ.lt(a, b) || !N32·λ.gt(b, a)){
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  // Second set: a=100, b=50
-  N32·λ.from_uint32(a, 100);
-  N32·λ.from_uint32(b, 50);
-  if(N32·λ.compare(a, b) != N32·Order_gt){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // eq_zero(a) => false
-  if(N32·λ.eq_zero(a)){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  // eq_zero(b) => false
-  if(N32·λ.eq_zero(b)){
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  N32·λ.deallocate(array);
-  return true;
-}
-
-bool test_shifts(){
-  // Allocate memory for operand, fill, spill
-  N32·T *array = N32·λ.allocate_array(3, NULL);
-  if(!array) return false;
-
-  N32·T *operand = N32·λ.access(array, 0);
-  N32·T *fill    = N32·λ.access(array, 1);
-  N32·T *spill   = N32·λ.access(array, 2);
-
-  // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0
-  N32·λ.from_uint32(operand, 1);
-  N32·λ.from_uint32(fill, 0);
-  N32·λ.from_uint32(spill, 0);
-  if(N32·λ.shift_left(4, spill, operand, fill) != N32·Status·ok){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  N32·T *temp = N32·λ.allocate_array(1, NULL);
-  if(!temp){
-    N32·λ.deallocate(array);
-    return false;
-  }
-  N32·λ.from_uint32(temp, 16);
-  if(N32·λ.compare(operand, temp) != N32·Order_eq){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  if(N32·λ.compare(fill, N32·zero) != N32·Order_eq){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  if(N32·λ.compare(spill, N32·zero) != N32·Order_eq){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1
-  N32·λ.from_uint32(operand, 0x80000000);
-  N32·λ.from_uint32(fill, 0);
-  N32·λ.from_uint32(spill, 0);
-  if(N32·λ.shift_left(1, spill, operand, fill) != N32·Status·ok){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  if(!N32·λ.eq_zero(operand)){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  N32·λ.from_uint32(temp, 1);
-  if(N32·λ.compare(spill, temp) != N32·Order_eq){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0
-  N32·λ.from_uint32(operand, 0x80000000);
-  N32·λ.from_uint32(fill, 0);
-  N32·λ.from_uint32(spill, 0);
-  if(N32·λ.shift_right(1, spill, operand, fill) != N32·Status·ok){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  N32·λ.from_uint32(temp, 0x40000000);
-  if(N32·λ.compare(operand, temp) != N32·Order_eq){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  if(!N32·λ.eq_zero(spill)){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0
-  N32·λ.from_uint32(operand, 0x80000000);
-  N32·λ.from_uint32(spill, 0);
-  if(N32·λ.arithmetic_shift_right(1, operand, spill) != N32·Status·ok){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  N32·λ.from_uint32(temp, 0xC0000000);
-  if(N32·λ.compare(operand, temp) != N32·Order_eq){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-  if(!N32·λ.eq_zero(spill)){
-    N32·λ.deallocate(temp);
-    N32·λ.deallocate(array);
-    return false;
-  }
-
-  N32·λ.deallocate(temp);
-  N32·λ.deallocate(array);
-  return true;
-}
-
-
-
-// Include the local section of N32.lib.c for testing
-#define LOCAL
-#include "N32.lib.c"
-#undef LOCAL
diff --git a/developer/document🖉/front_end.org b/developer/document🖉/front_end.org
new file mode 100644 (file)
index 0000000..b5ad881
--- /dev/null
@@ -0,0 +1,232 @@
+#+TITLE: Python-Based Template Generation (Multi-Module Approach)
+#+AUTHOR: Example
+
+Below is a single Org-mode document containing **four** separate Python modules
+(or scripts). Each code block is top-level (not nested), ensuring they render
+correctly. Together, they demonstrate how to generate a parametric `.lib.c` file
+for an RT code format library.
+
+1. **get_template.py**: Returns a base template with `{named_blank}` placeholders.
+2. **make_constants.py**: Creates the compile-time constants block for zero, one, etc.
+3. **fill_template.py**: Combines the template and constants block, substituting parameters.
+4. **A "Main" generator script** (for instance, `gen_n64_lib.py`) that writes out a final file (like `N64.lib.c`).
+
+You can create additional “main” scripts to produce different `.lib.c` files (e.g., `N128.lib.c`).
+
+---
+
+*1. `get_template.py`*
+
+#+BEGIN_SRC python
+#!/usr/bin/env python3
+
+def get_template():
+    """
+    Returns the base RT C code template, with placeholders like:
+      {NAMESPACE}, {DIGIT_EXTENT}, {DIGIT_TYPE}, {EXTENT_TYPE}, {CONSTANTS_BLOCK}.
+    
+    The final generated .lib.c will replace these with user-specified values.
+    """
+    return r'''#define {NAMESPACE}DEBUG
+
+#ifndef FACE
+  #define {NAMESPACE}IMPLEMENTATION
+  #define FACE
+#endif
+
+#ifndef {NAMESPACE}FACE
+#define {NAMESPACE}FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  typedef {EXTENT_TYPE} ExtentType;
+  typedef {DIGIT_TYPE} Digit;
+
+  // Digit count is (DIGIT_EXTENT + 1)
+  #define {NAMESPACE}DIGIT_COUNT ( {DIGIT_EXTENT} + 1 )
+
+  typedef struct {NAMESPACE}T{{
+    Digit d[{NAMESPACE}DIGIT_COUNT];
+  }} {NAMESPACE}T;
+
+  // forward declarations for constants
+  extern {NAMESPACE}T *{NAMESPACE}zero;
+  extern {NAMESPACE}T *{NAMESPACE}one;
+  extern {NAMESPACE}T *{NAMESPACE}all_one_bit;
+  extern {NAMESPACE}T *{NAMESPACE}msb;
+
+  // forward declarations for allocations, etc.
+
+#endif // {NAMESPACE}FACE
+
+#ifdef {NAMESPACE}IMPLEMENTATION
+
+#ifndef LOCAL
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  // compile-time constants
+  {CONSTANTS_BLOCK}
+
+  {NAMESPACE}T *{NAMESPACE}zero        = &{NAMESPACE}constant[0];
+  {NAMESPACE}T *{NAMESPACE}one         = &{NAMESPACE}constant[1];
+  {NAMESPACE}T *{NAMESPACE}all_one_bit = &{NAMESPACE}constant[2];
+  {NAMESPACE}T *{NAMESPACE}msb         = &{NAMESPACE}constant[3];
+
+  // memory allocation prototypes, etc.
+
+#endif // not LOCAL
+
+#ifdef LOCAL
+  // local code: actual function bodies, add, subtract, etc.
+#endif // LOCAL
+
+#endif // {NAMESPACE}IMPLEMENTATION
+'''
+#+END_SRC
+
+---
+
+*2. `make_constants.py`*
+
+#+BEGIN_SRC python
+#!/usr/bin/env python3
+
+def make_constants_block(namespace: str,
+                         digit_type: str,
+                         digit_extent: int) -> str:
+    """
+    Returns a block of code defining static compile-time constants:
+      static {namespace}T {namespace}constant[4] = {
+        { { ...zero... } },
+        { { ...one... } },
+        { { ...allbits... } },
+        { { ...msb... } }
+      };
+
+    The total digit count is digit_extent + 1.
+    """
+    digit_count = digit_extent + 1
+
+    def digits_zero():
+        return ", ".join("0" for _ in range(digit_count))
+
+    def digits_one():
+        # index 0 => 1, rest => 0
+        return ", ".join("1" if i == 0 else "0" for i in range(digit_count))
+
+    def digits_allbits():
+        # each digit => (digit_type)(-1)
+        return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count))
+
+    def digits_msb():
+        # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1)
+        items = []
+        for i in range(digit_count):
+            if i == digit_count - 1:
+                items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)")
+            else:
+                items.append("0")
+        return ", ".join(items)
+
+    return f'''\
+static {namespace}T {namespace}constant[4] = {{
+  {{
+    // zero
+    {{ {digits_zero()} }}
+  }},
+  {{
+    // one
+    {{ {digits_one()} }}
+  }},
+  {{
+    // all bits
+    {{ {digits_allbits()} }}
+  }},
+  {{
+    // msb
+    {{ {digits_msb()} }}
+  }}
+}};'''
+
+#+END_SRC
+
+---
+
+*3. `fill_template.py`*
+
+#+BEGIN_SRC python
+#!/usr/bin/env python3
+
+from get_template import get_template
+from make_constants import make_constants_block
+
+def fill_template(namespace: str,
+                  digit_extent: int,
+                  digit_type: str,
+                  extent_type: str) -> str:
+    """
+    Renders the final .lib.c code by merging:
+      - the base template from get_template()
+      - the compile-time constants block from make_constants_block()
+      - placeholders for namespace, digit_extent, digit_type, extent_type
+    """
+    template = get_template()
+    constants_block = make_constants_block(namespace, digit_type, digit_extent)
+
+    # Substitute placeholders
+    code = template.format(
+        NAMESPACE = namespace,
+        DIGIT_EXTENT = digit_extent,
+        DIGIT_TYPE = digit_type,
+        EXTENT_TYPE = extent_type,
+        CONSTANTS_BLOCK = constants_block
+    )
+    return code
+#+END_SRC
+
+---
+
+*4. An Example “Main” Script, `gen_n64_lib.py`*
+
+#+BEGIN_SRC python
+#!/usr/bin/env python3
+
+import sys
+from fill_template import fill_template
+
+def main():
+    """
+    Example: generate a .lib.c with an 'N64·' namespace,
+    digit_extent=0 => 1 digit total,
+    digit_type='uint32_t',
+    extent_type='uint64_t'.
+    """
+    code = fill_template(
+        namespace = "N64·",
+        digit_extent = 0,     # => digit_count = 1 => 32-bit
+        digit_type = "uint32_t",
+        extent_type = "uint64_t"
+    )
+
+    with open("N64.lib.c", "w") as f:
+        f.write(code)
+    print("Generated N64.lib.c")
+
+if __name__ == "__main__":
+    main()
+#+END_SRC
+
+---
+
+### Usage
+
+1. **Place** these four files side-by-side in your project (e.g., a `scripts/` directory).
+2. **Mark** them as executable (`chmod +x`).  
+3. **Run** `./gen_n64_lib.py` to produce `N64.lib.c`. This file will appear in the same directory (or wherever you prefer).  
+4. **Compile** `N64.lib.c` using your RT C build system (`make -f tool🖉/makefile`, etc.).
+
+You can then create similar scripts like `gen_n128_lib.py` or unify them into a single driver that takes parameters for namespace, digit_extent, etc. The main advantage is that **Python code** for generating constants is much more readable than M4 macros, and you keep the RT code format in your template exactly as it should appear.
diff --git a/developer/example/.githolder b/developer/example/.githolder
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/developer/m4/N_template.lib.c.m4 b/developer/m4/N_template.lib.c.m4
deleted file mode 100644 (file)
index cabe6b5..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-changequote([,])dnl
-define(NS, __NAMESPACE__)dnl
-define(DE, __DIGIT_EXTENT__)dnl
-define(DT, __DIGIT_TYPE__)dnl
-define(ET, __EXTENT_TYPE__)dnl
-changequote(`,')dnl
-
-/*
-  [NS] - Parametric multi-digit type library (RT code format)
-
-  Parameters:
-    [NS]: Namespace prefix, e.g. N32·
-    [DE]: Digit extent => total digits = DE + 1
-    [DT]: Digit type, e.g. uint64_t or uint8_t
-    [ET]: Loop counter type, e.g. uint64_t
-*/
-
-#define [NS]DEBUG
-
-#ifndef FACE
-  #define [NS]IMPLEMENTATION
-  #define FACE
-#endif
-
-//------------------------------------------------------------------------------
-// Interface Section
-
-#ifndef [NS]FACE
-#define [NS]FACE
-
-  #include <stdint.h>
-  #include <stdbool.h>
-  #include <stdarg.h>
-  #include <stdlib.h>
-
-  // Digit count is DE + 1
-  #define [NS]DIGIT_COUNT (DE + 1)
-
-  typedef DT Digit;
-  typedef struct [NS]T [NS]T;
-
-  // For array allocations
-  typedef ET ExtentType;
-
-  // Status codes
-  typedef enum{
-    [NS]Status_ok = 0
-   ,[NS]Status_overflow
-   ,[NS]Status_accumulator1_overflow
-   ,[NS]Status_carry
-   ,[NS]Status_borrow
-   ,[NS]Status_undefined_divide_by_zero
-   ,[NS]Status_undefined_modulus_zero
-   ,[NS]Status_gt_max_shift_count
-   ,[NS]Status_spill_eq_operand
-   ,[NS]Status_one_word_product
-   ,[NS]Status_two_word_product
-  } [NS]Status;
-
-  typedef enum{
-    [NS]Order_lt = -1
-   ,[NS]Order_eq = 0
-   ,[NS]Order_gt = 1
-  } [NS]Order;
-
-  // Allocation
-  Digit *[NS]allocate_array(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType));
-  Digit *[NS]allocate_array_zero(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType));
-  void [NS]deallocate([NS]T *unencumbered);
-
-  // Constant setters (no static global constants)
-  void [NS]set_zero([NS]T *destination);
-  void [NS]set_one([NS]T *destination);
-  void [NS]set_all_bits([NS]T *destination);
-  void [NS]set_msb([NS]T *destination);
-
-  // Bitwise ops
-  void [NS]bit_and([NS]T *result ,[NS]T *a ,[NS]T *b);
-  void [NS]bit_or([NS]T *result ,[NS]T *a ,[NS]T *b);
-  void [NS]bit_complement([NS]T *result ,[NS]T *a);
-  void [NS]bit_twos_complement([NS]T *result ,[NS]T *a);
-
-  // Comparison ops
-  bool [NS]eq([NS]T *a ,[NS]T *b);
-  bool [NS]eq_zero([NS]T *a);
-  [NS]Order [NS]compare([NS]T *a ,[NS]T *b);
-
-  // Arithmetic
-  [NS]Status [NS]add([NS]T *sum ,[NS]T *a ,[NS]T *b);
-  [NS]Status [NS]subtract([NS]T *diff ,[NS]T *a ,[NS]T *b);
-
-  // Conversions
-  void [NS]from_uint64([NS]T *destination ,uint64_t value);
-
-#endif // [NS]FACE
-
-
-//------------------------------------------------------------------------------
-// Implementation Section
-
-#ifdef [NS]IMPLEMENTATION
-
-  #ifndef LOCAL
-
-    #include <stdarg.h>
-    #include <stdlib.h>
-
-    struct [NS]T{
-      Digit d[[NS]DIGIT_COUNT];
-    };
-
-    Digit *[NS]allocate_array(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)){
-      [NS]T *instance = malloc((extent + 1) * sizeof([NS]T));
-      if(!instance){
-        if(fault_handler) return (Digit*)fault_handler(extent);
-        return NULL;
-      }
-      return (Digit*)instance;
-    }
-
-    Digit *[NS]allocate_array_zero(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)){
-      [NS]T *instance = calloc(extent + 1 ,sizeof([NS]T));
-      if(!instance){
-        if(fault_handler) return (Digit*)fault_handler(extent);
-        return NULL;
-      }
-      return (Digit*)instance;
-    }
-
-    void [NS]deallocate([NS]T *unencumbered){
-      free(unencumbered);
-    }
-
-  #endif // LOCAL not defined
-
-
-  #ifdef LOCAL
-
-    // local code implementing everything
-    struct [NS]T{
-      Digit d[[NS]DIGIT_COUNT];
-    };
-
-    // Constant Setters
-
-    Local void [NS]set_zero([NS]T *destination){
-      if(!destination) return;
-      Digit *start = destination->d;
-      Digit *end = destination->d + [NS]DIGIT_COUNT;
-      for(Digit *p = start ; p < end ; p++){
-        *p = 0;
-      }
-    }
-
-    Local void [NS]set_one([NS]T *destination){
-      if(!destination) return;
-      [NS]set_zero(destination);
-      destination->d[0] = 1;
-    }
-
-    Local void [NS]set_all_bits([NS]T *destination){
-      if(!destination) return;
-      Digit *start = destination->d;
-      Digit *end = destination->d + [NS]DIGIT_COUNT;
-      for(Digit *p = start ; p < end ; p++){
-        *p = (Digit)(-1);
-      }
-    }
-
-    Local void [NS]set_msb([NS]T *destination){
-      if(!destination) return;
-      [NS]set_zero(destination);
-      // Set top bit in the highest digit
-      destination->d[[NS]DIGIT_COUNT - 1] = ((Digit)1 << ((sizeof(Digit)*8) - 1));
-    }
-
-    // Bitwise
-
-    Local void [NS]bit_and([NS]T *result ,[NS]T *a ,[NS]T *b){
-      for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-        result->d[i] = a->d[i] & b->d[i];
-      }
-    }
-
-    Local void [NS]bit_or([NS]T *result ,[NS]T *a ,[NS]T *b){
-      for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-        result->d[i] = a->d[i] | b->d[i];
-      }
-    }
-
-    Local void [NS]bit_complement([NS]T *result ,[NS]T *a){
-      if(result == a){
-        // same location
-        for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-          result->d[i] = ~result->d[i];
-        }
-      }else{
-        for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-          result->d[i] = ~a->d[i];
-        }
-      }
-    }
-
-    Local void [NS]bit_twos_complement([NS]T *result ,[NS]T *a){
-      // ~ + 1 across [NS]DIGIT_COUNT digits
-      // If result == a, we must do carefully
-      [NS]T temp;
-      if(result == a) {
-        for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-          temp.d[i] = ~a->d[i];
-        }
-      }else{
-        for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-          temp.d[i] = ~a->d[i];
-        }
-      }
-      // now add 1
-      Digit carry = 1;
-      for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-        unsigned __int128 v = (unsigned __int128)temp.d[i] + carry;
-        temp.d[i] = (Digit)v;
-        carry = (Digit)(v >> (sizeof(Digit)*8));
-      }
-      // copy back if needed
-      if(result == a){
-        for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-          a->d[i] = temp.d[i];
-        }
-      }else{
-        for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-          result->d[i] = temp.d[i];
-        }
-      }
-    }
-
-    // Comparison
-
-    Local [NS]Order [NS]compare([NS]T *a ,[NS]T *b){
-      // compare from top to bottom
-      for(ExtentType i = [NS]DIGIT_COUNT; i > 0 ; i--){
-        ExtentType idx = i - 1;
-        if(a->d[idx] < b->d[idx]) return [NS]Order_lt;
-        if(a->d[idx] > b->d[idx]) return [NS]Order_gt;
-      }
-      return [NS]Order_eq;
-    }
-
-    Local bool [NS]eq([NS]T *a ,[NS]T *b){
-      for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-        if(a->d[i] != b->d[i]) return false;
-      }
-      return true;
-    }
-
-    Local bool [NS]eq_zero([NS]T *a){
-      for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-        if(a->d[i] != 0) return false;
-      }
-      return true;
-    }
-
-    // Arithmetic
-
-    Local [NS]Status [NS]add([NS]T *sum ,[NS]T *a ,[NS]T *b){
-      if(!sum || !a || !b) return [NS]Status_overflow;
-      Digit carry = 0;
-      for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-        unsigned __int128 tmp = (unsigned __int128)a->d[i] + b->d[i] + carry;
-        sum->d[i] = (Digit)tmp;
-        carry = (Digit)(tmp >> (sizeof(Digit)*8));
-      }
-      return (carry != 0) ? [NS]Status_carry : [NS]Status_ok;
-    }
-
-    Local [NS]Status [NS]subtract([NS]T *diff ,[NS]T *a ,[NS]T *b){
-      if(!diff || !a || !b) return [NS]Status_overflow;
-      Digit borrow = 0;
-      for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){
-        unsigned __int128 tmpA = a->d[i];
-        unsigned __int128 tmpB = b->d[i] + borrow;
-        if(tmpA < tmpB){
-          diff->d[i] = (Digit)((((unsigned __int128)1 << (sizeof(Digit)*8)) + tmpA) - tmpB);
-          borrow = 1;
-        }else{
-          diff->d[i] = (Digit)(tmpA - tmpB);
-          borrow = 0;
-        }
-      }
-      return (borrow != 0) ? [NS]Status_borrow : [NS]Status_ok;
-    }
-
-    // Conversion
-
-    Local void [NS]from_uint64([NS]T *destination ,uint64_t value){
-      if(!destination) return;
-      [NS]set_zero(destination);
-      // store 'value' in the low words
-      // note: if (DE + 1) < 2, we might only store partial
-      destination->d[0] = (Digit)(value & 0xFFFFFFFFFFFFFFFFULL);
-      #if DE >= 1
-      if([NS]DIGIT_COUNT > 1){
-        // store top half if digit is 32 bits etc, or 8 bits
-        // we'll just do partial logic if digit < 64
-        // for 32-bit digit, that means the next digit has (value >> 32)
-        // for 8-bit digit, the next digits hold the rest, etc.
-        // We'll keep it simple. 
-        // A more complete solution would loop if needed.
-        if(sizeof(Digit)*8 < 64){
-          // multi-split if needed
-          // skipping for brevity
-        }
-      }
-      #endif
-    }
-
-  #endif // LOCAL
-
-#endif // [NS]IMPLEMENTATION
diff --git a/developer/machine/.gitignore b/developer/machine/.gitignore
new file mode 100644 (file)
index 0000000..120f485
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!/.gitignore
diff --git a/developer/python/N64.lib.c b/developer/python/N64.lib.c
new file mode 100644 (file)
index 0000000..8827b35
--- /dev/null
@@ -0,0 +1,74 @@
+#define N64·DEBUG
+
+#ifndef FACE
+  #define N64·IMPLEMENTATION
+  #define FACE
+#endif
+
+#ifndef N64·FACE
+#define N64·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  typedef uint8_t Digit;
+
+  // Digit count is (DIGIT_EXTENT + 1)
+  #define N64·DIGIT_COUNT ( 8 + 1 )
+
+  typedef struct N64·T{
+    Digit d[N64·DIGIT_COUNT];
+  } N64·T;
+
+  // forward declarations for constants
+  extern N64·T *N64·zero;
+  extern N64·T *N64·one;
+  extern N64·T *N64·all_one_bit;
+  extern N64·T *N64·msb;
+
+  // forward declarations for allocations, etc.
+
+#endif // N64·FACE
+
+#ifdef N64·IMPLEMENTATION
+
+#ifndef LOCAL
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  // compile-time constants
+  static N64·T N64·constant[4] = {
+  {
+    // zero
+    { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+  },
+  {
+    // one
+    { 1, 0, 0, 0, 0, 0, 0, 0, 0 }
+  },
+  {
+    // all one bits
+    { ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ) }
+  },
+  {
+    // msb
+    { 0, 0, 0, 0, 0, 0, 0, 0, ( uint8_t )1 << ((sizeof(uint8_t)*8) - 1) }
+  }
+};
+
+  N64·T *N64·zero        = &N64·constant[0];
+  N64·T *N64·one         = &N64·constant[1];
+  N64·T *N64·all_one_bit = &N64·constant[2];
+  N64·T *N64·msb         = &N64·constant[3];
+
+  // memory allocation prototypes, etc.
+
+#endif // not LOCAL
+
+#ifdef LOCAL
+  // local code: actual function bodies, add, subtract, etc.
+#endif // LOCAL
+
+#endif // N64·IMPLEMENTATION
diff --git a/developer/python/fill_template.py b/developer/python/fill_template.py
new file mode 100755 (executable)
index 0000000..bf73da9
--- /dev/null
@@ -0,0 +1,27 @@
+#+BEGIN_SRC python
+#!/usr/bin/env python3
+
+from get_template import get_template
+from make_constants import make_constants_block
+
+def fill_template(namespace: str,
+                  digit_extent: int,
+                  digit_type: str) -> str:
+    """
+    Renders the final .lib.c code by merging:
+      - the base template from get_template()
+      - the compile-time constants block from make_constants_block()
+      - placeholders for namespace, digit_extent, digit_type, extent_type
+    """
+    template = get_template()
+    constants_block = make_constants_block(namespace, digit_type, digit_extent)
+
+    # Substitute placeholders
+    code = template.format(
+        NAMESPACE = namespace,
+        DIGIT_EXTENT = digit_extent,
+        DIGIT_TYPE = digit_type,
+        CONSTANTS_BLOCK = constants_block
+    )
+    return code
+#+END_SRC
diff --git a/developer/python/gen_N32_8_by_4.py b/developer/python/gen_N32_8_by_4.py
new file mode 100755 (executable)
index 0000000..22ef30e
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+
+import sys
+from fill_template import fill_template
+
+def main():
+    """
+    Example: generate an N<type_name>.lib.c 
+    """
+
+    type_name = "N32";
+
+    # 4 x 8 bit 
+    code = fill_template(
+        namespace = type_name + "·",
+        digit_extent = 3,     
+        digit_type = "uint8_t",
+    )
+
+
+    filename = "../cc/" + type_name + ".lib.c" 
+    with open(filename, "w") as f:
+        f.write(code)
+    print("Generated " + filename)
+
+if __name__ == "__main__":
+    main()
diff --git a/developer/python/gen_n64_lib.py b/developer/python/gen_n64_lib.py
new file mode 100755 (executable)
index 0000000..6288b1d
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+
+import sys
+from fill_template import fill_template
+
+def main():
+    """
+    Example: generate a .lib.c with an 'N64·' namespace,
+    """
+    code = fill_template(
+        namespace = "N64·",
+        digit_extent = 8,     # => digit_count = 1 => 32-bit
+        digit_type = "uint8_t",
+    )
+
+    with open("N64.lib.c", "w") as f:
+        f.write(code)
+    print("Generated N64.lib.c")
+
+if __name__ == "__main__":
+    main()
diff --git a/developer/python/get_template.py b/developer/python/get_template.py
new file mode 100755 (executable)
index 0000000..a25336b
--- /dev/null
@@ -0,0 +1,65 @@
+def get_template():
+    """
+    Returns the base RT C code template, with placeholders like:
+      {NAMESPACE}, {DIGIT_EXTENT}, {DIGIT_TYPE}, {EXTENT_TYPE}, {CONSTANTS_BLOCK}.
+    
+    The final generated .lib.c will replace these with user-specified values.
+    """
+    return r'''#define {NAMESPACE}DEBUG
+
+#ifndef FACE
+  #define {NAMESPACE}IMPLEMENTATION
+  #define FACE
+#endif
+
+#ifndef {NAMESPACE}FACE
+#define {NAMESPACE}FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  typedef {DIGIT_TYPE} Digit;
+
+  // Digit count is (DIGIT_EXTENT + 1)
+  #define {NAMESPACE}DIGIT_COUNT ( {DIGIT_EXTENT} + 1 )
+
+  typedef struct {NAMESPACE}T{{
+    Digit d[{NAMESPACE}DIGIT_COUNT];
+  }} {NAMESPACE}T;
+
+  // forward declarations for constants
+  extern {NAMESPACE}T *{NAMESPACE}zero;
+  extern {NAMESPACE}T *{NAMESPACE}one;
+  extern {NAMESPACE}T *{NAMESPACE}all_one_bit;
+  extern {NAMESPACE}T *{NAMESPACE}msb;
+
+  // forward declarations for allocations, etc.
+
+#endif // {NAMESPACE}FACE
+
+#ifdef {NAMESPACE}IMPLEMENTATION
+
+#ifndef LOCAL
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  // compile-time constants
+  {CONSTANTS_BLOCK}
+
+  {NAMESPACE}T *{NAMESPACE}zero        = &{NAMESPACE}constant[0];
+  {NAMESPACE}T *{NAMESPACE}one         = &{NAMESPACE}constant[1];
+  {NAMESPACE}T *{NAMESPACE}all_one_bit = &{NAMESPACE}constant[2];
+  {NAMESPACE}T *{NAMESPACE}msb         = &{NAMESPACE}constant[3];
+
+  // memory allocation prototypes, etc.
+
+#endif // not LOCAL
+
+#ifdef LOCAL
+  // local code: actual function bodies, add, subtract, etc.
+#endif // LOCAL
+
+#endif // {NAMESPACE}IMPLEMENTATION
+'''
diff --git a/developer/python/make_constants.py b/developer/python/make_constants.py
new file mode 100755 (executable)
index 0000000..a177fde
--- /dev/null
@@ -0,0 +1,56 @@
+def make_constants_block(namespace: str,
+                         digit_type: str,
+                         digit_extent: int) -> str:
+    """
+    Returns a block of code defining static compile-time constants:
+      static {namespace}T {namespace}constant[4] = {
+        { { ...zero... } },
+        { { ...one... } },
+        { { ...allbits... } },
+        { { ...msb... } }
+      };
+
+    The total digit count is digit_extent + 1.
+    """
+    digit_count = digit_extent + 1
+
+    def digits_zero():
+        return ", ".join("0" for _ in range(digit_count))
+
+    def digits_one():
+        # index 0 => 1, rest => 0
+        return ", ".join("1" if i == 0 else "0" for i in range(digit_count))
+
+    def digits_allbits():
+        # each digit => (digit_type)(-1)
+        return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count))
+
+    def digits_msb():
+        # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1)
+        items = []
+        for i in range(digit_count):
+            if i == digit_count - 1:
+                items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)")
+            else:
+                items.append("0")
+        return ", ".join(items)
+
+    return f'''\
+static {namespace}T {namespace}constant[4] = {{
+  {{
+    // zero
+    {{ {digits_zero()} }}
+  }},
+  {{
+    // one
+    {{ {digits_one()} }}
+  }},
+  {{
+    // all one bits
+    {{ {digits_allbits()} }}
+  }},
+  {{
+    // msb
+    {{ {digits_msb()} }}
+  }}
+}};'''
index f9e2584..dfca640 100644 (file)
@@ -17,10 +17,13 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
   if $error_not_sourced; then exit 1; fi
   if $error_bad_env; then return 1; fi
 
+
+export ROLE=developer
+
 # so we can do the build
 
 export PATH=\
-"$REPO_HOME"/developer/tool🖉/\
+"$REPO_HOME"/${ROLE}/tool🖉/\
 :"$PATH"
 
 # misc
@@ -30,10 +33,8 @@ export PATH=\
 
 # some feedback to show all went well
 
-  export PROMPT_DECOR="$PROJECT"_developer
+  export PROMPT_DECOR="$PROJECT_$ROLE"
   export ENV=$(script_fp)
   echo ENV "$ENV"
-  cd "$REPO_HOME"/developer/
-
-
+  cd "$REPO_HOME/$ROLE"
 
index 6ff2855..0df0712 100755 (executable)
@@ -1,17 +1,20 @@
-#!/bin/env /bin/bash
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
 
-set -e
-cd ${REPO_HOME}/developer
+# input guards
 
-# # Example m4 invocation:
-# m4 -D__NAMESPACE__=N128· \
-#    -D__DIGIT_EXTENT__=1 \
-#    -D__DIGIT_TYPE__=uint64_t \
-#    -D__EXTENT_TYPE__=uint64_t \
-#    src/N_template.lib.c.m4 > src/N128.lib.c
+  env_must_be="developer/tool🖉/env"
+  if [ "$ENV" != "$env_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+    exit 1
+  fi
 
-# m4 -D__NAMESPACE__=N32· -D__DIGIT_EXTENT__=0 -D__DIGIT_TYPE__=uint32_t -D__EXTENT_TYPE__=uint32_t  m4🖉/N_template.lib.c.m4 > cc/N32.lib.c
+set -e
+set -x
 
+  cd "$REPO_HOME"/developer || exit 1
 
-/bin/make -f tool🖉/makefile $@
+  /bin/make -f tool🖉/makefile $@
 
+set +x
+echo "$(script_fn) done."
index a0da057..64bb614 100644 (file)
@@ -1,5 +1,4 @@
 
-
 RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release
 
 include $(RT-INCOMMON)/make/environment_RT_0
diff --git a/developer/tool🖉/release b/developer/tool🖉/release
new file mode 100755 (executable)
index 0000000..feb8bcf
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+# before running this, make library is built and is in the scratchpad directory
+
+# input guards
+
+  env_must_be="developer/tool🖉/env"
+  if [ "$ENV" != "$env_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+    exit 1
+  fi
+
+set -e
+set -x
+
+  cd "$REPO_HOME"/developer || exit 1
+
+  if [ ! -d scratchpad ]; then
+    echo "$(script_fp):: no scratchpad directory"
+    exit 1
+  fi
+
+  release_dir=$(release_dir)
+  mkdir -p ${release_dir}
+
+  install_file scratchpad/libN.a ${release_dir} "ug+r"
+
+  # header files
+  install_file {cc,cc🖉}/*.lib.c ${release_dir} "ug+r"
+
+
+set +x
+echo "$(script_fn) done."
+
diff --git a/document🖉/#SectionApproach.org# b/document🖉/#SectionApproach.org#
deleted file mode 100644 (file)
index e69de29..0000000
index 7cb4a1f..e69de29 100644 (file)
@@ -1,121 +0,0 @@
-#+TITLE: Sectioned Single-File Format
-#+AUTHOR: RT C Documentation Team
-#+OPTIONS: toc:2
-
-* Overview
-The sectioned single-file format provides a structured way to define a library in C,
-keeping all relevant code in a single file while ensuring proper separation between
-interface, implementation, and local static definitions. This approach avoids
-the common “.h + .c” split and instead uses conditional compilation blocks
-to expose only the needed parts.
-
-** Key Definitions
-- =IFACE=: A preprocessor symbol indicating we want to expose the library’s interface.
-- =LOCAL=: A preprocessor symbol indicating we want to expose static (private) helper code.
-- *Implementation (no symbol defined)*: The default, containing the shared implementation
-  of the library.
-
-** File Layout
-A typical =.lib.c= file has three sections:
-
-1. *Interface Section*  
-   Guarded by:
-   #+begin_src c
-     #ifndef NNN·FACE
-     #define NNN·FACE
-       // public typedefs, function declarations
-       // ...
-     #endif
-   #+end_src
-
-   Here, “=NNN=” is the library name (e.g., =N32=).  
-   You include this section in another file using:
-   #+begin_src c
-     #define IFACE
-     #include "my_library.lib.c"
-     #undef IFACE
-   #+end_src
-
-2. *Implementation Section*  
-   Defined when *neither* =IFACE= nor =LOCAL= is set. This is the main, global
-   portion of the library code that will be compiled into an object
-   (or archived into a static library):
-   #+begin_src c
-     #ifdef NNN·IMPLEMENTATION
-       // Implementation code
-       // ...
-     #endif
-   #+end_src
-
-   The build system compiles this =.lib.c= without =IFACE= or =LOCAL= defined
-   to produce the main library object.
-
-3. *Local (Static) Section*  
-   Guarded by:
-   #+begin_src c
-     #ifdef LOCAL
-       // In-library static declarations or definitions
-       // ...
-     #endif
-   #end_src
-
-   This block is typically included after the user code, letting you inline or
-   define “private” helper functions that only the user’s code should see
-   (in order to be optimized away if not used, for instance).
-
-** Why This Matters
-- *Single Source of Truth*: Instead of maintaining separate header and source files, 
-  everything for a module is in one place.
-- *Automatic Inlining*: In a traditional setup, “private” static functions would
-  live in the .c file and be invisible for cross-module inlining. With the local
-  section, the compiler sees everything when the user includes it, enabling more
-  optimizations.
-- *Reduced Mismatch Errors*: There’s zero chance your header becomes out-of-sync 
-  with the .c file because they’re literally the same file, gated by preprocessor macros.
-- *Cleaner Build Scripts*: The library is compiled once with the default macros. 
-  Tests or command-line programs that need the local portion define =LOCAL= or =IFACE=
-  as needed.
-
-** Example Usage
-1. *Library Compilation*  
-   #+begin_src bash
-     # No defines set:
-     $CC -c my_library.lib.c -o my_library.lib.o
-   #+end_src
-
-2. *Including the Interface in Another Source*  
-   #+begin_src c
-     #define IFACE
-     #include "my_library.lib.c"
-     #undef IFACE
-
-     int main(){
-       // Now we have the function declarations from the interface
-       // ...
-     }
-   #+end_src
-
-3. *Including the Local Section*  
-   #+begin_src c
-     #define LOCAL
-     #include "my_library.lib.c"
-     #undef LOCAL
-
-     // We can now use certain static or inline-like helpers
-     // ...
-   #+end_src
-
-** Makefile Integration
-The provided Makefile snippet shows how to compile =.lib.c= files separately, 
-then link them. The key is to define no macros (like =IFACE= or =LOCAL=) 
-when building the library, ensuring you get only the “Implementation Section.”
-
-For a command-line interface (CLI) or test harness, you can then define =IFACE= 
-or =LOCAL= before including the =.lib.c= to access the library’s interface 
-(or private/local stuff) on an as-needed basis.
-
-* Conclusion
-This method elegantly encapsulates a module’s interface, its global
-implementation, and its private helper code in a single file. It integrates
-nicely with existing make-based build systems and fosters a clear separation
-of concerns with minimal overhead or confusion.
diff --git a/release/x86_64/fedora41/glibc_2.40/N16PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N16PN.lib.c
new file mode 100644 (file)
index 0000000..d7a2e05
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+  N16 - a processor native type
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N16PN·DEBUG
+
+#ifndef FACE
+#define N16PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N16PN·FACE
+#define N16PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint16_t Extent;
+  typedef uint16_t Digit;
+
+  typedef struct N16PN·T N16PN·T;
+
+  extern N16PN·T *N16PN·zero;
+  extern N16PN·T *N16PN·one;
+  extern N16PN·T *N16PN·all_one_bit;
+  extern N16PN·T *N16PN·lsb;
+  extern N16PN·T *N16PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N16PN·Status·ok = 0
+   ,N16PN·Status·overflow = 1
+   ,N16PN·Status·accumulator1_overflow = 2
+   ,N16PN·Status·carry = 3
+   ,N16PN·Status·borrow = 4
+   ,N16PN·Status·undefined_divide_by_zero = 5
+   ,N16PN·Status·undefined_modulus_zero = 6
+   ,N16PN·Status·gt_max_shift_count = 7
+   ,N16PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+   ,N16PN·Status·one_word_product = 9
+   ,N16PN·Status·two_word_product = 10
+  } N16PN·Status;
+
+  typedef enum{
+    N16PN·Order_lt = -1
+   ,N16PN·Order_eq = 0
+   ,N16PN·Order_gt = 1
+  } N16PN·Order;
+
+  typedef N16PN·T *( *N16PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N16PN·T *(*allocate_array_zero)(Extent, N16PN·Allocate_MemoryFault);
+    N16PN·T *(*allocate_array)(Extent, N16PN·Allocate_MemoryFault);
+    void (*deallocate)(N16PN·T*);
+
+    void (*copy)(N16PN·T*, N16PN·T*);
+    void (*bit_and)(N16PN·T*, N16PN·T*, N16PN·T*);
+    void (*bit_or)(N16PN·T*, N16PN·T*, N16PN·T*);
+    void (*bit_complement)(N16PN·T*, N16PN·T*);
+    void (*bit_twos_complement)(N16PN·T*, N16PN·T*);
+    N16PN·Order (*compare)(N16PN·T*, N16PN·T*);
+    bool (*lt)(N16PN·T*, N16PN·T*);
+    bool (*gt)(N16PN·T*, N16PN·T*);
+    bool (*eq)(N16PN·T*, N16PN·T*);
+    bool (*eq_zero)(N16PN·T*);
+    N16PN·Status (*accumulate)(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...);
+    N16PN·Status (*add)(N16PN·T*, N16PN·T*, N16PN·T*);
+    bool (*increment)(N16PN·T *a);
+    N16PN·Status (*subtract)(N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*multiply)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*divide)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*modulus)(N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*shift_left)(Extent, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*shift_right)(Extent, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*arithmetic_shift_right)(Extent, N16PN·T*, N16PN·T*);
+
+    N16PN·T* (*access)(N16PN·T*, Extent);
+    void (*from_uint32)(N16PN·T *destination ,uint32_t value);
+  } N16PN·Λ;
+
+  Local const N16PN·Λ N16PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N16PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N16PN·T{
+      Digit d0;
+    };
+
+    N16PN·T N16PN·constant[4] = {
+    {.d0 = 0},
+    {.d0 = 1},
+    {.d0 = ~(uint16_t)0},
+    {.d0 = 1 << 15}
+    };
+
+    N16PN·T *N16PN·zero = &N16PN·constant[0];
+    N16PN·T *N16PN·one = &N16PN·constant[1];
+    N16PN·T *N16PN·all_one_bit = &N16PN·constant[2];
+    N16PN·T *N16PN·msb = &N16PN·constant[3];
+    N16PN·T *N16PN·lsb = &N16PN·constant[1];
+
+    // the allocate an array of N16
+    N16PN·T *N16PN·allocate_array(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){
+      N16PN·T *instance = malloc((extent + 1) * sizeof(N16PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N16PN·T *N16PN·allocate_array_zero(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){
+      N16PN·T *instance = calloc(extent + 1, sizeof(N16PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N16PN·deallocate(N16PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N16PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    Local N16PN·T N16PN·t[4];
+
+    // allocation 
+
+    extern N16PN·T *N16PN·allocate_array(Extent, N16PN·Allocate_MemoryFault);
+    extern N16PN·T *N16PN·allocate_array_zero(Extent, N16PN·Allocate_MemoryFault);
+    extern void N16PN·deallocate(N16PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N16PN·T* N16PN·access(N16PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N16PN·from_uint32(N16PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = (uint16_t)(value & 0xFFFF);
+    }
+
+    // copy, convenience copy
+
+    Local void N16PN·copy(N16PN·T *destination ,N16PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    Local void N16PN·set_to_zero(N16PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N16PN·set_to_one(N16PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N16PN·bit_and(N16PN·T *result, N16PN·T *a, N16PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N16PN·bit_or(N16PN·T *result, N16PN·T *a, N16PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N16PN·bit_complement(N16PN·T *result, N16PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N16PN·bit_twos_complement(N16PN·T *result ,N16PN·T *a){
+      result->d0 = (uint16_t)(~a->d0 + 1);
+    }
+
+    // test functions
+
+    Local N16PN·Order N16PN·compare(N16PN·T *a, N16PN·T *b){
+      if(a->d0 < b->d0) return N16PN·Order_lt;
+      if(a->d0 > b->d0) return N16PN·Order_gt;
+      return N16PN·Order_eq;
+    }
+
+    Local bool N16PN·lt(N16PN·T *a ,N16PN·T *b){
+      return a->d0 < b->d0;
+    }    
+
+    Local bool N16PN·gt(N16PN·T *a ,N16PN·T *b){
+      return a->d0 > b->d0;
+    }    
+
+    Local bool N16PN·eq(N16PN·T *a ,N16PN·T *b){
+      return a->d0 == b->d0;
+    }    
+
+    Local bool N16PN·eq_zero(N16PN·T *a){
+      return a->d0 == 0;
+    }    
+
+    // arithmetic operations
+
+    Local N16PN·Status N16PN·accumulate(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N16PN·T *current;
+
+      while( (current = va_arg(args ,N16PN·T*)) ){
+        sum += current->d0;
+        if(sum < current->d0){
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N16PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = (uint16_t)carry;
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·add(N16PN·T *sum ,N16PN·T *a ,N16PN·T *b){
+      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
+      sum->d0 = (uint16_t)(result & 0xFFFF);
+      return (result >> 16) ? N16PN·Status·carry : N16PN·Status·ok;
+    }
+
+    Local bool N16PN·increment(N16PN·T *a){
+      a->d0++;
+      return (a->d0 == 0);
+    }
+
+    Local N16PN·Status N16PN·subtract(N16PN·T *difference ,N16PN·T *a ,N16PN·T *b){
+      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
+      difference->d0 = (uint16_t)(diff & 0xFFFF);
+      return (diff > a->d0) ? N16PN·Status·borrow : N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·multiply(N16PN·T *product1 ,N16PN·T *product0 ,N16PN·T *a ,N16PN·T *b){
+      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
+      product0->d0 = (uint16_t)(product & 0xFFFF);
+      product1->d0 = (uint16_t)((product >> 16) & 0xFFFF);
+
+      if(product1->d0 == 0) return N16PN·Status·one_word_product;
+      return N16PN·Status·two_word_product;
+    }
+
+    Local N16PN·Status N16PN·divide(N16PN·T *remainder ,N16PN·T *quotient ,N16PN·T *a ,N16PN·T *b){
+      if(b->d0 == 0) return N16PN·Status·undefined_divide_by_zero;
+
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      quotient->d0 = (uint16_t)(dividend / divisor);
+      remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor));
+
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·modulus(N16PN·T *remainder ,N16PN·T *a ,N16PN·T *b){
+      if(b->d0 == 0) return N16PN·Status·undefined_modulus_zero;
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      uint32_t q = dividend / divisor;
+      remainder->d0 = (uint16_t)(dividend - (q * divisor));
+      return N16PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint16_t (*ShiftOp)(uint16_t, uint16_t);
+
+    Local uint16_t shift_left_op(uint16_t value, uint16_t amount){
+      return value << amount;
+    }
+
+    Local uint16_t shift_right_op(uint16_t value, uint16_t amount){
+      return (uint16_t)(value >> amount);
+    }
+
+    Local N16PN·Status N16PN·shift
+    (
+     uint16_t shift_count
+     ,N16PN·T *spill
+     ,N16PN·T *operand
+     ,N16PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+    ){
+
+      if(operand == NULL && spill == NULL) return N16PN·Status·ok;
+
+      if(operand == NULL){
+        operand = &N16PN·t[0];
+        N16PN·copy(operand, N16PN·zero);
+      }
+
+      if(shift_count > 15) return N16PN·Status·gt_max_shift_count;
+
+      N16PN·T *given_operand = &N16PN·t[1];
+      N16PN·copy(given_operand, operand);
+
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (16 - shift_count));
+        N16PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count));
+      }
+
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status 
+    N16PN·shift_left(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){
+      return N16PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N16PN·Status 
+    N16PN·shift_right(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){
+      return N16PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N16PN·Status 
+    N16PN·arithmetic_shift_right(uint16_t shift_count, N16PN·T *operand, N16PN·T *spill){
+
+      if(shift_count > 15) return N16PN·Status·gt_max_shift_count;
+
+      if(operand == NULL){
+        operand = &N16PN·t[0];
+        N16PN·copy(operand, N16PN·zero);
+      }
+
+      N16PN·T *fill = (operand->d0 & 0x8000) ? N16PN·all_one_bit : N16PN·zero;
+      return N16PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N16PN·Λ N16PN·λ = {
+
+      .allocate_array = N16PN·allocate_array
+     ,.allocate_array_zero = N16PN·allocate_array_zero
+     ,.deallocate = N16PN·deallocate
+
+     ,.copy = N16PN·copy
+     ,.bit_and = N16PN·bit_and
+     ,.bit_or = N16PN·bit_or
+     ,.bit_complement = N16PN·bit_complement
+     ,.bit_twos_complement = N16PN·bit_twos_complement
+     ,.compare = N16PN·compare
+     ,.lt = N16PN·lt
+     ,.gt = N16PN·gt
+     ,.eq = N16PN·eq
+     ,.eq_zero = N16PN·eq_zero
+     ,.accumulate = N16PN·accumulate
+     ,.add = N16PN·add
+     ,.increment = N16PN·increment
+     ,.subtract = N16PN·subtract
+     ,.multiply = N16PN·multiply
+     ,.divide = N16PN·divide
+     ,.modulus = N16PN·modulus
+     ,.shift_left = N16PN·shift_left
+     ,.shift_right = N16PN·shift_right
+     ,.arithmetic_shift_right = N16PN·arithmetic_shift_right
+
+     ,.access = N16PN·access
+     ,.from_uint32 = N16PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/release/x86_64/fedora41/glibc_2.40/N32PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N32PN.lib.c
new file mode 100644 (file)
index 0000000..952f570
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+  N32 - a processor native type
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+
+*/
+
+#define N32PN·DEBUG
+
+#ifndef FACE
+#define N32PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N32PN·FACE
+#define N32PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint32_t Extent;
+  typedef uint32_t Digit;
+
+  typedef struct N32PN·T N32PN·T;
+
+  extern N32PN·T *N32PN·zero;
+  extern N32PN·T *N32PN·one;
+  extern N32PN·T *N32PN·all_one_bit;
+  extern N32PN·T *N32PN·lsb;
+  extern N32PN·T *N32PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N32PN·Status·ok = 0
+    ,N32PN·Status·overflow = 1
+    ,N32PN·Status·accumulator1_overflow = 2
+    ,N32PN·Status·carry = 3
+    ,N32PN·Status·borrow = 4
+    ,N32PN·Status·undefined_divide_by_zero = 5
+    ,N32PN·Status·undefined_modulus_zero = 6
+    ,N32PN·Status·gt_max_shift_count = 7
+    ,N32PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+    ,N32PN·Status·one_word_product = 9
+    ,N32PN·Status·two_word_product = 10
+  } N32PN·Status;
+
+  typedef enum{
+    N32PN·Order_lt = -1
+    ,N32PN·Order_eq = 0
+    ,N32PN·Order_gt = 1
+  } N32PN·Order;
+
+  typedef N32PN·T *( *N32PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N32PN·T *(*allocate_array_zero)(Extent, N32PN·Allocate_MemoryFault);
+    N32PN·T *(*allocate_array)(Extent, N32PN·Allocate_MemoryFault);
+    void (*deallocate)(N32PN·T*);
+
+    void (*copy)(N32PN·T*, N32PN·T*);
+    void (*bit_and)(N32PN·T*, N32PN·T*, N32PN·T*);
+    void (*bit_or)(N32PN·T*, N32PN·T*, N32PN·T*);
+    void (*bit_complement)(N32PN·T*, N32PN·T*);
+    void (*bit_twos_complement)(N32PN·T*, N32PN·T*);
+    N32PN·Order (*compare)(N32PN·T*, N32PN·T*);
+    bool (*lt)(N32PN·T*, N32PN·T*);
+    bool (*gt)(N32PN·T*, N32PN·T*);
+    bool (*eq)(N32PN·T*, N32PN·T*);
+    bool (*eq_zero)(N32PN·T*);
+    N32PN·Status (*accumulate)(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...);
+    N32PN·Status (*add)(N32PN·T*, N32PN·T*, N32PN·T*);
+    bool (*increment)(N32PN·T *a);
+    N32PN·Status (*subtract)(N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*multiply)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*divide)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*modulus)(N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*shift_left)(Extent, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*shift_right)(Extent, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*arithmetic_shift_right)(Extent, N32PN·T*, N32PN·T*);
+
+    N32PN·T* (*access)(N32PN·T*, Extent);
+    void (*from_uint32)(N32PN·T *destination ,uint32_t value);
+  } N32PN·Λ;
+
+  Local const N32PN·Λ N32PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N32PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N32PN·T{
+      Digit d0;
+    };
+
+    N32PN·T N32PN·constant[4] = {
+      {.d0 = 0},
+      {.d0 = 1},
+      {.d0 = ~(uint32_t)0},
+      {.d0 = 1 << 31}
+    };
+
+    N32PN·T *N32PN·zero = &N32PN·constant[0];
+    N32PN·T *N32PN·one = &N32PN·constant[1];
+    N32PN·T *N32PN·all_one_bit = &N32PN·constant[2];
+    N32PN·T *N32PN·msb = &N32PN·constant[3];
+    N32PN·T *N32PN·lsb = &N32PN·constant[1];
+
+    // the allocate an array of N32
+    N32PN·T *N32PN·allocate_array(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){
+      N32PN·T *instance = malloc((extent + 1) * sizeof(N32PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N32PN·T *N32PN·allocate_array_zero(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){
+      N32PN·T *instance = calloc( extent + 1 ,sizeof(N32PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N32PN·deallocate(N32PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N32PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    // making these LOCAL rather than reserving one block in the library is thread safe
+    // allocating a block once is more efficient
+    // library code writes these, they are not on the interface
+
+    Local N32PN·T N32PN·t[4];
+
+
+    // allocation 
+
+    extern N32PN·T *N32PN·allocate_array(Extent, N32PN·Allocate_MemoryFault);
+    extern N32PN·T *N32PN·allocate_array_zero(Extent, N32PN·Allocate_MemoryFault);
+    extern void N32PN·deallocate(N32PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N32PN·T* N32PN·access(N32PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N32PN·from_uint32(N32PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = value;
+    }
+
+    // copy, convenience copy
+
+    Local void N32PN·copy(N32PN·T *destination ,N32PN·T *source){
+      if(source == destination) return; // that was easy! 
+      *destination = *source;
+    }
+
+    Local void N32PN·set_to_zero(N32PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N32PN·set_to_one(N32PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N32PN·bit_and(N32PN·T *result, N32PN·T *a, N32PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    // result can be one of the operands
+    Local void N32PN·bit_or(N32PN·T *result, N32PN·T *a, N32PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32PN·bit_complement(N32PN·T *result, N32PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32PN·bit_twos_complement(N32PN·T *result ,N32PN·T *a){
+      result->d0 = ~a->d0 + 1;
+    }
+
+    // test functions
+
+    Local N32PN·Order N32PN·compare(N32PN·T *a, N32PN·T *b){
+      if(a->d0 < b->d0) return N32PN·Order_lt;
+      if(a->d0 > b->d0) return N32PN·Order_gt;
+      return N32PN·Order_eq;
+    }
+
+    Local bool N32PN·lt(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 < b->d0;
+    }    
+
+    Local bool N32PN·gt(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 > b->d0;
+    }    
+
+    Local bool N32PN·eq(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 == b->d0;
+    }    
+
+    Local bool N32PN·eq_zero(N32PN·T *a){
+      return  a->d0 == 0;
+    }    
+
+
+    // arithmetic operations
+
+    // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32PN·Status·accumulator1_overflow
+    //
+    // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value.
+    Local N32PN·Status N32PN·accumulate(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N32PN·T *current;
+
+      while( (current = va_arg(args ,N32PN·T *)) ){
+        sum += current->d0;
+        if(sum < current->d0){  // Accumulator1 into carry
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N32PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      // wipes out prior value of accumulator1
+      accumulator1->d0 = carry;
+
+      return N32PN·Status·ok;
+    }
+
+    Local N32PN·Status N32PN·add(N32PN·T *sum ,N32PN·T *a ,N32PN·T *b){
+      uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0;
+      sum->d0 = (uint32_t)result;
+      return (result >> 32) ? N32PN·Status·carry : N32PN·Status·ok;
+    }
+
+    Local bool N32PN·increment(N32PN·T *a){
+      a->d0++;
+      return a->d0 == 0;
+    }
+
+    Local N32PN·Status N32PN·subtract(N32PN·T *difference ,N32PN·T *a ,N32PN·T *b){
+      uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0;
+      difference->d0 = (uint32_t)diff;
+      return (diff > a->d0) ? N32PN·Status·borrow : N32PN·Status·ok;
+    }
+
+
+    Local N32PN·Status N32PN·multiply(N32PN·T *product1 ,N32PN·T *product0 ,N32PN·T *a ,N32PN·T *b){
+      uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0;
+      product0->d0 = (uint32_t)product;
+      product1->d0 = (uint32_t)(product >> 32);
+
+      if(product1->d0 == 0) return N32PN·Status·one_word_product;
+      return N32PN·Status·two_word_product;
+    }
+
+    Local N32PN·Status N32PN·divide(N32PN·T *remainder ,N32PN·T *quotient ,N32PN·T *a ,N32PN·T *b){
+      if(b->d0 == 0) return N32PN·Status·undefined_divide_by_zero; 
+
+      quotient->d0 = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient->d0 * b->d0);
+
+      return N32PN·Status·ok;
+    }
+
+    Local N32PN·Status N32PN·modulus(N32PN·T *remainder ,N32PN·T *a ,N32PN·T *b){
+      if(b->d0 == 0) return N32PN·Status·undefined_modulus_zero; 
+      uint32_t quotient = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient * b->d0);
+      return N32PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint32_t (*ShiftOp)(uint32_t, uint32_t);
+
+    Local uint32_t shift_left_op(uint32_t value, uint32_t amount){
+      return value << amount;
+    }
+
+    Local uint32_t shift_right_op(uint32_t value, uint32_t amount){
+      return value >> amount;
+    }
+
+    // modifies all three of its operands
+    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, 
+    Local N32PN·Status N32PN·shift
+    (
+     uint32_t shift_count
+     ,N32PN·T *spill
+     ,N32PN·T *operand
+     ,N32PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+     ){
+
+      // If no result is needed, return immediately.
+      if(operand == NULL && spill == NULL) return N32PN·Status·ok;
+
+      // Treat NULL operand as zero.
+      if(operand == NULL){
+        operand = &N32PN·t[0];
+        N32PN·copy(operand, N32PN·zero);
+      }
+
+      // Shifting more than one word breaks our fill/spill model.
+      if(shift_count > 31) return N32PN·Status·gt_max_shift_count;
+
+      // The given operand is still required after it is modified, so we copy it.
+      N32PN·T *given_operand = &N32PN·t[1];
+      N32PN·copy(given_operand, operand);
+
+      // Perform the shift
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (32 - shift_count));
+        N32PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count));
+      }
+
+      return N32PN·Status·ok;
+    }
+
+    // Define concrete shift functions using valid C function pointers
+    Local N32PN·Status 
+    N32PN·shift_left(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){
+      return N32PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N32PN·Status 
+    N32PN·shift_right(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){
+      return N32PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N32PN·Status 
+    N32PN·arithmetic_shift_right(uint32_t shift_count, N32PN·T *operand, N32PN·T *spill){
+
+      // Guard against excessive shift counts
+      if(shift_count > 31) return N32PN·Status·gt_max_shift_count;
+
+      // A NULL operand is treated as zero
+      if(operand == NULL){
+        operand = &N32PN·t[0];
+        N32PN·copy(operand, N32PN·zero);
+      }
+
+      // Pick the fill value based on the sign bit
+      N32PN·T *fill = (operand->d0 & 0x80000000) ? N32PN·all_one_bit : N32PN·zero;
+
+      // Call shift_right with the appropriate fill
+      return N32PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N32PN·Λ N32PN·λ = {
+
+      .allocate_array = N32PN·allocate_array
+      ,.allocate_array_zero = N32PN·allocate_array_zero
+      ,.deallocate = N32PN·deallocate
+
+      ,.copy = N32PN·copy
+      ,.bit_and = N32PN·bit_and
+      ,.bit_or = N32PN·bit_or
+      ,.bit_complement = N32PN·bit_complement
+      ,.bit_twos_complement = N32PN·bit_twos_complement
+      ,.compare = N32PN·compare
+      ,.lt = N32PN·lt
+      ,.gt = N32PN·gt
+      ,.eq = N32PN·eq
+      ,.eq_zero = N32PN·eq_zero
+      ,.accumulate = N32PN·accumulate
+      ,.add = N32PN·add
+      ,.increment = N32PN·increment
+      ,.subtract = N32PN·subtract
+      ,.multiply = N32PN·multiply
+      ,.divide = N32PN·divide
+      ,.modulus = N32PN·modulus
+      ,.shift_left = N32PN·shift_left
+      ,.shift_right = N32PN·shift_right
+      ,.arithmetic_shift_right = N32PN·arithmetic_shift_right
+
+      ,.access = N32PN·access
+      ,.from_uint32 = N32PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/release/x86_64/fedora41/glibc_2.40/N64PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N64PN.lib.c
new file mode 100644 (file)
index 0000000..583ad08
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+  N64 - a 64-bit native type
+
+  For binary operations: a op b -> c
+
+  Similar to N32, but now each Digit is 64 bits. Where a 128-bit
+  intermediate is necessary (e.g. multiplication), we handle it
+  manually using two 64-bit parts.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N64PN·DEBUG
+
+#ifndef FACE
+#define N64PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N64PN·FACE
+#define N64PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint64_t Extent;
+  typedef uint64_t Digit;
+
+  typedef struct N64PN·T N64PN·T;
+
+  extern N64PN·T *N64PN·zero;
+  extern N64PN·T *N64PN·one;
+  extern N64PN·T *N64PN·all_one_bit;
+  extern N64PN·T *N64PN·lsb;
+  extern N64PN·T *N64PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum {
+    N64PN·Status·ok = 0
+   ,N64PN·Status·overflow = 1
+   ,N64PN·Status·accumulator1_overflow = 2
+   ,N64PN·Status·carry = 3
+   ,N64PN·Status·borrow = 4
+   ,N64PN·Status·undefined_divide_by_zero = 5
+   ,N64PN·Status·undefined_modulus_zero = 6
+   ,N64PN·Status·gt_max_shift_count = 7
+   ,N64PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+   ,N64PN·Status·one_word_product = 9
+   ,N64PN·Status·two_word_product = 10
+  } N64PN·Status;
+
+  typedef enum {
+    N64PN·Order_lt = -1
+   ,N64PN·Order_eq = 0
+   ,N64PN·Order_gt = 1
+  } N64PN·Order;
+
+  typedef N64PN·T *(*N64PN·Allocate_MemoryFault)(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct {
+
+    N64PN·T *(*allocate_array_zero)(Extent, N64PN·Allocate_MemoryFault);
+    N64PN·T *(*allocate_array)(Extent, N64PN·Allocate_MemoryFault);
+    void   (*deallocate)(N64PN·T*);
+
+    void        (*copy)(N64PN·T*, N64PN·T*);
+    void        (*bit_and)(N64PN·T*, N64PN·T*, N64PN·T*);
+    void        (*bit_or)(N64PN·T*, N64PN·T*, N64PN·T*);
+    void        (*bit_complement)(N64PN·T*, N64PN·T*);
+    void        (*bit_twos_complement)(N64PN·T*, N64PN·T*);
+    N64PN·Order   (*compare)(N64PN·T*, N64PN·T*);
+    bool        (*lt)(N64PN·T*, N64PN·T*);
+    bool        (*gt)(N64PN·T*, N64PN·T*);
+    bool        (*eq)(N64PN·T*, N64PN·T*);
+    bool        (*eq_zero)(N64PN·T*);
+    N64PN·Status  (*accumulate)(N64PN·T *accumulator1, N64PN·T *accumulator0, ...);
+    N64PN·Status  (*add)(N64PN·T*, N64PN·T*, N64PN·T*);
+    bool        (*increment)(N64PN·T *a);
+    N64PN·Status  (*subtract)(N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*multiply)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*divide)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*modulus)(N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*shift_left)(Extent, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*shift_right)(Extent, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*arithmetic_shift_right)(Extent, N64PN·T*, N64PN·T*);
+
+    N64PN·T*      (*access)(N64PN·T*, Extent);
+    void        (*from_uint64)(N64PN·T *destination, uint64_t value);
+
+  } N64PN·Λ;
+
+  Local const N64PN·Λ N64PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N64PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N64PN·T {
+      Digit d0;
+    };
+
+    // For constants, we store them in an array for convenience
+    // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63)
+    N64PN·T N64PN·constant[4] = {
+      {.d0 = 0ULL},
+      {.d0 = 1ULL},
+      {.d0 = ~(uint64_t)0ULL},
+      {.d0 = 1ULL << 63}
+    };
+
+    N64PN·T *N64PN·zero = &N64PN·constant[0];
+    N64PN·T *N64PN·one = &N64PN·constant[1];
+    N64PN·T *N64PN·all_one_bit = &N64PN·constant[2];
+    N64PN·T *N64PN·msb = &N64PN·constant[3];
+    N64PN·T *N64PN·lsb = &N64PN·constant[1];
+
+    // allocate an array of N64
+    N64PN·T *N64PN·allocate_array(Extent extent, N64PN·Allocate_MemoryFault memory_fault){
+      N64PN·T *instance = malloc( (extent + 1) * sizeof(N64PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N64PN·T *N64PN·allocate_array_zero(Extent extent, N64PN·Allocate_MemoryFault memory_fault){
+      N64PN·T *instance = calloc(extent + 1, sizeof(N64PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N64PN·deallocate(N64PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N64PN·T {
+      Digit d0;
+    };
+
+    // local temporary variables
+    Local N64PN·T N64PN·t[4];
+
+    // allocation references
+    extern N64PN·T *N64PN·allocate_array(Extent, N64PN·Allocate_MemoryFault);
+    extern N64PN·T *N64PN·allocate_array_zero(Extent, N64PN·Allocate_MemoryFault);
+    extern void   N64PN·deallocate(N64PN·T *);
+
+    // Access array
+    Local N64PN·T* N64PN·access(N64PN·T *array, Extent index){
+      return &array[index];
+    }
+
+    Local void N64PN·from_uint64(N64PN·T *destination, uint64_t value){
+      if(destination == NULL) return;
+      destination->d0 = value;
+    }
+
+    // copy
+    Local void N64PN·copy(N64PN·T *destination, N64PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    // bit operations
+
+    Local void N64PN·bit_and(N64PN·T *result, N64PN·T *a, N64PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N64PN·bit_or(N64PN·T *result, N64PN·T *a, N64PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N64PN·bit_complement(N64PN·T *result, N64PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N64PN·bit_twos_complement(N64PN·T *result, N64PN·T *a){
+      result->d0 = ~a->d0 + 1ULL;
+    }
+
+    // compare & test functions
+
+    Local N64PN·Order N64PN·compare(N64PN·T *a, N64PN·T *b){
+      if(a->d0 < b->d0) return N64PN·Order_lt;
+      if(a->d0 > b->d0) return N64PN·Order_gt;
+      return N64PN·Order_eq;
+    }
+
+    Local bool N64PN·lt(N64PN·T *a, N64PN·T *b){
+      return (a->d0 < b->d0);
+    }
+
+    Local bool N64PN·gt(N64PN·T *a, N64PN·T *b){
+      return (a->d0 > b->d0);
+    }
+
+    Local bool N64PN·eq(N64PN·T *a, N64PN·T *b){
+      return (a->d0 == b->d0);
+    }
+
+    Local bool N64PN·eq_zero(N64PN·T *a){
+      return (a->d0 == 0ULL);
+    }
+
+    // arithmetic operations
+
+    // accumulate
+    Local N64PN·Status N64PN·accumulate(N64PN·T *accumulator1, N64PN·T *accumulator0, ...){
+      va_list args;
+      va_start(args, accumulator0);
+
+      uint64_t sum = accumulator0->d0;
+      uint64_t carry = 0;
+      N64PN·T *current;
+
+      while( (current = va_arg(args, N64PN·T*)) ){
+        uint64_t prior = sum;
+        sum += current->d0;
+        if(sum < prior){  // indicates carry
+          carry++;
+          // if carry overflowed a 64-bit, that's an accumulator1 overflow
+          if(carry == 0ULL){
+            va_end(args);
+            return N64PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = carry;
+      return N64PN·Status·ok;
+    }
+
+    // add
+    Local N64PN·Status N64PN·add(N64PN·T *sum, N64PN·T *a, N64PN·T *b){
+      __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0;
+      // But to avoid using a GNU extension, we can do the simpler approach:
+      // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits:
+      uint64_t temp = a->d0 + b->d0;
+      sum->d0 = temp;
+      if(temp < a->d0) return N64PN·Status·carry;  // means we overflowed
+      return N64PN·Status·ok;
+    }
+
+    Local bool N64PN·increment(N64PN·T *a){
+      uint64_t old = a->d0;
+      a->d0++;
+      // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF
+      return (a->d0 < old);
+    }
+
+    // subtract
+    Local N64PN·Status N64PN·subtract(N64PN·T *difference, N64PN·T *a, N64PN·T *b){
+      uint64_t tmpA = a->d0;
+      uint64_t tmpB = b->d0;
+      uint64_t diff = tmpA - tmpB;
+      difference->d0 = diff;
+      if(diff > tmpA) return N64PN·Status·borrow; // indicates we borrowed
+      return N64PN·Status·ok;
+    }
+
+    // multiply
+    // We'll do a 64x64->128 using two 64-bit accumulators
+    Local N64PN·Status N64PN·multiply(N64PN·T *product1, N64PN·T *product0, N64PN·T *a, N64PN·T *b){
+      uint64_t A = a->d0;
+      uint64_t B = b->d0;
+
+      // Break each operand into high & low 32 bits
+      uint64_t a_lo = (uint32_t)(A & 0xffffffffULL);
+      uint64_t a_hi = A >> 32;
+      uint64_t b_lo = (uint32_t)(B & 0xffffffffULL);
+      uint64_t b_hi = B >> 32;
+
+      // partial products
+      uint64_t low = a_lo * b_lo;                   // 64-bit
+      uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits
+      uint64_t high = a_hi * b_hi;                  // up to 64 bits
+
+      // incorporate cross into low, high
+      // cross is effectively the middle bits, so shift cross by 32 and add to low
+      uint64_t cross_low = (cross & 0xffffffffULL) << 32;  // lower part
+      uint64_t cross_high = cross >> 32;                   // upper part
+
+      // add cross_low to low, capture carry
+      uint64_t old_low = low;
+      low += cross_low;
+      if(low < old_low) cross_high++;
+
+      // final high
+      high += cross_high;
+
+      // store results
+      product0->d0 = low;
+      product1->d0 = high;
+
+      if(high == 0ULL) return N64PN·Status·one_word_product;
+      return N64PN·Status·two_word_product;
+    }
+
+    // divide
+    Local N64PN·Status N64PN·divide(N64PN·T *remainder, N64PN·T *quotient, N64PN·T *a, N64PN·T *b){
+      // we do not handle a > 64-bit, just the single 64-bit
+      if(b->d0 == 0ULL) return N64PN·Status·undefined_divide_by_zero;
+
+      uint64_t divd = a->d0; // dividend
+      uint64_t divs = b->d0; // divisor
+
+      quotient->d0 = divd / divs;
+      remainder->d0 = divd - (quotient->d0 * divs);
+
+      return N64PN·Status·ok;
+    }
+
+    // modulus
+    Local N64PN·Status N64PN·modulus(N64PN·T *remainder, N64PN·T *a, N64PN·T *b){
+      if(b->d0 == 0ULL) return N64PN·Status·undefined_modulus_zero;
+
+      uint64_t divd = a->d0;
+      uint64_t divs = b->d0;
+      uint64_t q = divd / divs;
+      remainder->d0 = divd - (q * divs);
+
+      return N64PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint64_t (*ShiftOp)(uint64_t, uint64_t);
+
+    Local uint64_t shift_left_op(uint64_t value, uint64_t amount){
+      return (value << amount);
+    }
+
+    Local uint64_t shift_right_op(uint64_t value, uint64_t amount){
+      return (value >> amount);
+    }
+
+    // modifies all three of its operands
+    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill
+    Local N64PN·Status N64PN·shift
+    (
+     uint64_t shift_count,
+     N64PN·T *spill,
+     N64PN·T *operand,
+     N64PN·T *fill,
+     ShiftOp shift_op,
+     ShiftOp complement_shift_op
+    ){
+      if(operand == NULL && spill == NULL) return N64PN·Status·ok;
+
+      // Treat NULL operand as zero
+      if(operand == NULL){
+        operand = &N64PN·t[0];
+        N64PN·copy(operand, N64PN·zero);
+      }
+
+      // Shifting more than 63 bits breaks fill/spill logic
+      if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count;
+
+      N64PN·T *given_operand = &N64PN·t[1];
+      N64PN·copy(given_operand, operand);
+
+      // Perform the shift
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count));
+        N64PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count));
+      }
+
+      return N64PN·Status·ok;
+    }
+
+    Local N64PN·Status N64PN·shift_left(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){
+      return N64PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N64PN·Status N64PN·shift_right(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){
+      return N64PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N64PN·Status N64PN·arithmetic_shift_right(uint64_t shift_count, N64PN·T *operand, N64PN·T *spill){
+      if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count;
+
+      // A NULL operand is treated as zero
+      if(operand == NULL){
+        operand = &N64PN·t[0];
+        N64PN·copy(operand, N64PN·zero);
+      }
+
+      // sign bit check
+      N64PN·T *fill = (operand->d0 & (1ULL << 63)) ? N64PN·all_one_bit : N64PN·zero;
+      return N64PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N64PN·Λ N64PN·λ = {
+      .allocate_array = N64PN·allocate_array
+     ,.allocate_array_zero = N64PN·allocate_array_zero
+     ,.deallocate = N64PN·deallocate
+
+     ,.copy = N64PN·copy
+     ,.bit_and = N64PN·bit_and
+     ,.bit_or = N64PN·bit_or
+     ,.bit_complement = N64PN·bit_complement
+     ,.bit_twos_complement = N64PN·bit_twos_complement
+     ,.compare = N64PN·compare
+     ,.lt = N64PN·lt
+     ,.gt = N64PN·gt
+     ,.eq = N64PN·eq
+     ,.eq_zero = N64PN·eq_zero
+     ,.accumulate = N64PN·accumulate
+     ,.add = N64PN·add
+     ,.increment = N64PN·increment
+     ,.subtract = N64PN·subtract
+     ,.multiply = N64PN·multiply
+     ,.divide = N64PN·divide
+     ,.modulus = N64PN·modulus
+     ,.shift_left = N64PN·shift_left
+     ,.shift_right = N64PN·shift_right
+     ,.arithmetic_shift_right = N64PN·arithmetic_shift_right
+
+     ,.access = N64PN·access
+     ,.from_uint64 = N64PN·from_uint64
+    };
+
+  #endif
+
+#endif
diff --git a/release/x86_64/fedora41/glibc_2.40/N8PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N8PN.lib.c
new file mode 100644 (file)
index 0000000..9cfd66d
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+  N8PN - PN = refers to the use of processor native accumulator 
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N8PN·DEBUG
+
+#ifndef FACE
+#define N8PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N8PN·FACE
+#define N8PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint8_t Extent;
+  typedef uint8_t Digit;
+
+  typedef struct N8PN·T N8PN·T;
+
+  extern N8PN·T *N8PN·zero;
+  extern N8PN·T *N8PN·one;
+  extern N8PN·T *N8PN·all_one_bit;
+  extern N8PN·T *N8PN·lsb;
+  extern N8PN·T *N8PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N8PN·Status·ok = 0
+   ,N8PN·Status·overflow = 1
+   ,N8PN·Status·accumulator1_overflow = 2
+   ,N8PN·Status·carry = 3
+   ,N8PN·Status·borrow = 4
+   ,N8PN·Status·undefined_divide_by_zero = 5
+   ,N8PN·Status·undefined_modulus_zero = 6
+   ,N8PN·Status·gt_max_shift_count = 7
+   ,N8PN·Status·spill_eq_operand = 8
+   ,N8PN·Status·one_word_product = 9
+   ,N8PN·Status·two_word_product = 10
+  } N8PN·Status;
+
+  typedef enum{
+    N8PN·Order_lt = -1
+   ,N8PN·Order_eq = 0
+   ,N8PN·Order_gt = 1
+  } N8PN·Order;
+
+  typedef N8PN·T *( *N8PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N8PN·T *(*allocate_array_zero)(Extent, N8PN·Allocate_MemoryFault);
+    N8PN·T *(*allocate_array)(Extent, N8PN·Allocate_MemoryFault);
+    void (*deallocate)(N8PN·T*);
+
+    void (*copy)(N8PN·T*, N8PN·T*);
+    void (*bit_and)(N8PN·T*, N8PN·T*, N8PN·T*);
+    void (*bit_or)(N8PN·T*, N8PN·T*, N8PN·T*);
+    void (*bit_complement)(N8PN·T*, N8PN·T*);
+    void (*bit_twos_complement)(N8PN·T*, N8PN·T*);
+    N8PN·Order (*compare)(N8PN·T*, N8PN·T*);
+    bool (*lt)(N8PN·T*, N8PN·T*);
+    bool (*gt)(N8PN·T*, N8PN·T*);
+    bool (*eq)(N8PN·T*, N8PN·T*);
+    bool (*eq_zero)(N8PN·T*);
+    N8PN·Status (*accumulate)(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...);
+    N8PN·Status (*add)(N8PN·T*, N8PN·T*, N8PN·T*);
+    bool (*increment)(N8PN·T *a);
+    N8PN·Status (*subtract)(N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*multiply)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*divide)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*modulus)(N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*shift_left)(Extent, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*shift_right)(Extent, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*arithmetic_shift_right)(Extent, N8PN·T*, N8PN·T*);
+
+    N8PN·T* (*access)(N8PN·T*, Extent);
+    void (*from_uint32)(N8PN·T *destination ,uint32_t value);
+  } N8PN·Λ;
+
+  Local const N8PN·Λ N8PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N8PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  struct N8PN·T{
+    Digit d0;
+  };
+
+  N8PN·T N8PN·constant[4] = {
+  {.d0 = 0},
+  {.d0 = 1},
+  {.d0 = ~(uint8_t)0},
+  {.d0 = 1 << 7}
+  };
+
+  N8PN·T *N8PN·zero = &N8PN·constant[0];
+  N8PN·T *N8PN·one = &N8PN·constant[1];
+  N8PN·T *N8PN·all_one_bit = &N8PN·constant[2];
+  N8PN·T *N8PN·msb = &N8PN·constant[3];
+  N8PN·T *N8PN·lsb = &N8PN·constant[1];
+
+  // the allocate an array of N8
+  N8PN·T *N8PN·allocate_array(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){
+    N8PN·T *instance = malloc((extent + 1) * sizeof(N8PN·T));
+    if(!instance){
+      return memory_fault ? memory_fault(extent) : NULL;
+    }
+    return instance;
+  }
+
+  N8PN·T *N8PN·allocate_array_zero(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){
+    N8PN·T *instance = calloc(extent + 1, sizeof(N8PN·T));
+    if(!instance){
+      return memory_fault ? memory_fault(extent) : NULL;
+    }
+    return instance;
+  }
+
+  void N8PN·deallocate(N8PN·T *unencumbered){
+    free(unencumbered);
+  }
+
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N8PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    Local N8PN·T N8PN·t[4];
+
+    // allocation 
+
+    extern N8PN·T *N8PN·allocate_array(Extent, N8PN·Allocate_MemoryFault);
+    extern N8PN·T *N8PN·allocate_array_zero(Extent, N8PN·Allocate_MemoryFault);
+    extern void N8PN·deallocate(N8PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N8PN·T* N8PN·access(N8PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N8PN·from_uint32(N8PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = (uint8_t)(value & 0xFF);
+    }
+
+    // copy, convenience copy
+
+    Local void N8PN·copy(N8PN·T *destination ,N8PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    Local void N8PN·set_to_zero(N8PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N8PN·set_to_one(N8PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N8PN·bit_and(N8PN·T *result, N8PN·T *a, N8PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N8PN·bit_or(N8PN·T *result, N8PN·T *a, N8PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N8PN·bit_complement(N8PN·T *result, N8PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N8PN·bit_twos_complement(N8PN·T *result ,N8PN·T *a){
+      result->d0 = (uint8_t)(~a->d0 + 1);
+    }
+
+    // test functions
+
+    Local N8PN·Order N8PN·compare(N8PN·T *a, N8PN·T *b){
+      if(a->d0 < b->d0) return N8PN·Order_lt;
+      if(a->d0 > b->d0) return N8PN·Order_gt;
+      return N8PN·Order_eq;
+    }
+
+    Local bool N8PN·lt(N8PN·T *a ,N8PN·T *b){
+      return a->d0 < b->d0;
+    }    
+
+    Local bool N8PN·gt(N8PN·T *a ,N8PN·T *b){
+      return a->d0 > b->d0;
+    }    
+
+    Local bool N8PN·eq(N8PN·T *a ,N8PN·T *b){
+      return a->d0 == b->d0;
+    }    
+
+    Local bool N8PN·eq_zero(N8PN·T *a){
+      return a->d0 == 0;
+    }    
+
+    // arithmetic operations
+
+    Local N8PN·Status N8PN·accumulate(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N8PN·T *current;
+
+      while( (current = va_arg(args ,N8PN·T*)) ){
+        sum += current->d0;
+        if(sum < current->d0){
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N8PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = (uint8_t)carry;
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·add(N8PN·T *sum ,N8PN·T *a ,N8PN·T *b){
+      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
+      sum->d0 = (uint8_t)(result & 0xFF);
+      return (result >> 8) ? N8PN·Status·carry : N8PN·Status·ok;
+    }
+
+    Local bool N8PN·increment(N8PN·T *a){
+      a->d0++;
+      return (a->d0 == 0);
+    }
+
+    Local N8PN·Status N8PN·subtract(N8PN·T *difference ,N8PN·T *a ,N8PN·T *b){
+      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
+      difference->d0 = (uint8_t)(diff & 0xFF);
+      return (diff > a->d0) ? N8PN·Status·borrow : N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·multiply(N8PN·T *product1 ,N8PN·T *product0 ,N8PN·T *a ,N8PN·T *b){
+      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
+      product0->d0 = (uint8_t)(product & 0xFF);
+      product1->d0 = (uint8_t)((product >> 8) & 0xFF);
+
+      if(product1->d0 == 0) return N8PN·Status·one_word_product;
+      return N8PN·Status·two_word_product;
+    }
+
+    Local N8PN·Status N8PN·divide(N8PN·T *remainder ,N8PN·T *quotient ,N8PN·T *a ,N8PN·T *b){
+      if(b->d0 == 0) return N8PN·Status·undefined_divide_by_zero;
+
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      quotient->d0 = (uint8_t)(dividend / divisor);
+      remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor));
+
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·modulus(N8PN·T *remainder ,N8PN·T *a ,N8PN·T *b){
+      if(b->d0 == 0) return N8PN·Status·undefined_modulus_zero;
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      uint32_t q = dividend / divisor;
+      remainder->d0 = (uint8_t)(dividend - (q * divisor));
+      return N8PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint8_t (*ShiftOp)(uint8_t, uint8_t);
+
+    Local uint8_t shift_left_op(uint8_t value, uint8_t amount){
+      return (uint8_t)(value << amount);
+    }
+
+    Local uint8_t shift_right_op(uint8_t value, uint8_t amount){
+      return (uint8_t)(value >> amount);
+    }
+
+    Local N8PN·Status N8PN·shift
+    (
+     uint8_t shift_count
+     ,N8PN·T *spill
+     ,N8PN·T *operand
+     ,N8PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+    ){
+
+      if(operand == NULL && spill == NULL) return N8PN·Status·ok;
+
+      if(operand == NULL){
+        operand = &N8PN·t[0];
+        N8PN·copy(operand, N8PN·zero);
+      }
+
+      if(shift_count > 7) return N8PN·Status·gt_max_shift_count;
+
+      N8PN·T *given_operand = &N8PN·t[1];
+      N8PN·copy(given_operand, operand);
+
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (8 - shift_count));
+        N8PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count));
+      }
+
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status 
+    N8PN·shift_left(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){
+      return N8PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N8PN·Status 
+    N8PN·shift_right(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){
+      return N8PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N8PN·Status 
+    N8PN·arithmetic_shift_right(uint8_t shift_count, N8PN·T *operand, N8PN·T *spill){
+
+      if(shift_count > 7) return N8PN·Status·gt_max_shift_count;
+
+      if(operand == NULL){
+        operand = &N8PN·t[0];
+        N8PN·copy(operand, N8PN·zero);
+      }
+
+      N8PN·T *fill = (operand->d0 & 0x80) ? N8PN·all_one_bit : N8PN·zero;
+      return N8PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N8PN·Λ N8PN·λ = {
+
+      .allocate_array = N8PN·allocate_array
+     ,.allocate_array_zero = N8PN·allocate_array_zero
+     ,.deallocate = N8PN·deallocate
+
+     ,.copy = N8PN·copy
+     ,.bit_and = N8PN·bit_and
+     ,.bit_or = N8PN·bit_or
+     ,.bit_complement = N8PN·bit_complement
+     ,.bit_twos_complement = N8PN·bit_twos_complement
+     ,.compare = N8PN·compare
+     ,.lt = N8PN·lt
+     ,.gt = N8PN·gt
+     ,.eq = N8PN·eq
+     ,.eq_zero = N8PN·eq_zero
+     ,.accumulate = N8PN·accumulate
+     ,.add = N8PN·add
+     ,.increment = N8PN·increment
+     ,.subtract = N8PN·subtract
+     ,.multiply = N8PN·multiply
+     ,.divide = N8PN·divide
+     ,.modulus = N8PN·modulus
+     ,.shift_left = N8PN·shift_left
+     ,.shift_right = N8PN·shift_right
+     ,.arithmetic_shift_right = N8PN·arithmetic_shift_right
+
+     ,.access = N8PN·access
+     ,.from_uint32 = N8PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/release/x86_64/fedora41/glibc_2.40/libN.a b/release/x86_64/fedora41/glibc_2.40/libN.a
new file mode 100644 (file)
index 0000000..2818416
Binary files /dev/null and b/release/x86_64/fedora41/glibc_2.40/libN.a differ
diff --git a/tester/cc/N16PN.lib.c b/tester/cc/N16PN.lib.c
new file mode 100644 (file)
index 0000000..d7a2e05
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+  N16 - a processor native type
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N16PN·DEBUG
+
+#ifndef FACE
+#define N16PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N16PN·FACE
+#define N16PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint16_t Extent;
+  typedef uint16_t Digit;
+
+  typedef struct N16PN·T N16PN·T;
+
+  extern N16PN·T *N16PN·zero;
+  extern N16PN·T *N16PN·one;
+  extern N16PN·T *N16PN·all_one_bit;
+  extern N16PN·T *N16PN·lsb;
+  extern N16PN·T *N16PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N16PN·Status·ok = 0
+   ,N16PN·Status·overflow = 1
+   ,N16PN·Status·accumulator1_overflow = 2
+   ,N16PN·Status·carry = 3
+   ,N16PN·Status·borrow = 4
+   ,N16PN·Status·undefined_divide_by_zero = 5
+   ,N16PN·Status·undefined_modulus_zero = 6
+   ,N16PN·Status·gt_max_shift_count = 7
+   ,N16PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+   ,N16PN·Status·one_word_product = 9
+   ,N16PN·Status·two_word_product = 10
+  } N16PN·Status;
+
+  typedef enum{
+    N16PN·Order_lt = -1
+   ,N16PN·Order_eq = 0
+   ,N16PN·Order_gt = 1
+  } N16PN·Order;
+
+  typedef N16PN·T *( *N16PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N16PN·T *(*allocate_array_zero)(Extent, N16PN·Allocate_MemoryFault);
+    N16PN·T *(*allocate_array)(Extent, N16PN·Allocate_MemoryFault);
+    void (*deallocate)(N16PN·T*);
+
+    void (*copy)(N16PN·T*, N16PN·T*);
+    void (*bit_and)(N16PN·T*, N16PN·T*, N16PN·T*);
+    void (*bit_or)(N16PN·T*, N16PN·T*, N16PN·T*);
+    void (*bit_complement)(N16PN·T*, N16PN·T*);
+    void (*bit_twos_complement)(N16PN·T*, N16PN·T*);
+    N16PN·Order (*compare)(N16PN·T*, N16PN·T*);
+    bool (*lt)(N16PN·T*, N16PN·T*);
+    bool (*gt)(N16PN·T*, N16PN·T*);
+    bool (*eq)(N16PN·T*, N16PN·T*);
+    bool (*eq_zero)(N16PN·T*);
+    N16PN·Status (*accumulate)(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...);
+    N16PN·Status (*add)(N16PN·T*, N16PN·T*, N16PN·T*);
+    bool (*increment)(N16PN·T *a);
+    N16PN·Status (*subtract)(N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*multiply)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*divide)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*modulus)(N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*shift_left)(Extent, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*shift_right)(Extent, N16PN·T*, N16PN·T*, N16PN·T*);
+    N16PN·Status (*arithmetic_shift_right)(Extent, N16PN·T*, N16PN·T*);
+
+    N16PN·T* (*access)(N16PN·T*, Extent);
+    void (*from_uint32)(N16PN·T *destination ,uint32_t value);
+  } N16PN·Λ;
+
+  Local const N16PN·Λ N16PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N16PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N16PN·T{
+      Digit d0;
+    };
+
+    N16PN·T N16PN·constant[4] = {
+    {.d0 = 0},
+    {.d0 = 1},
+    {.d0 = ~(uint16_t)0},
+    {.d0 = 1 << 15}
+    };
+
+    N16PN·T *N16PN·zero = &N16PN·constant[0];
+    N16PN·T *N16PN·one = &N16PN·constant[1];
+    N16PN·T *N16PN·all_one_bit = &N16PN·constant[2];
+    N16PN·T *N16PN·msb = &N16PN·constant[3];
+    N16PN·T *N16PN·lsb = &N16PN·constant[1];
+
+    // the allocate an array of N16
+    N16PN·T *N16PN·allocate_array(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){
+      N16PN·T *instance = malloc((extent + 1) * sizeof(N16PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N16PN·T *N16PN·allocate_array_zero(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){
+      N16PN·T *instance = calloc(extent + 1, sizeof(N16PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N16PN·deallocate(N16PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N16PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    Local N16PN·T N16PN·t[4];
+
+    // allocation 
+
+    extern N16PN·T *N16PN·allocate_array(Extent, N16PN·Allocate_MemoryFault);
+    extern N16PN·T *N16PN·allocate_array_zero(Extent, N16PN·Allocate_MemoryFault);
+    extern void N16PN·deallocate(N16PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N16PN·T* N16PN·access(N16PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N16PN·from_uint32(N16PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = (uint16_t)(value & 0xFFFF);
+    }
+
+    // copy, convenience copy
+
+    Local void N16PN·copy(N16PN·T *destination ,N16PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    Local void N16PN·set_to_zero(N16PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N16PN·set_to_one(N16PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N16PN·bit_and(N16PN·T *result, N16PN·T *a, N16PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N16PN·bit_or(N16PN·T *result, N16PN·T *a, N16PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N16PN·bit_complement(N16PN·T *result, N16PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N16PN·bit_twos_complement(N16PN·T *result ,N16PN·T *a){
+      result->d0 = (uint16_t)(~a->d0 + 1);
+    }
+
+    // test functions
+
+    Local N16PN·Order N16PN·compare(N16PN·T *a, N16PN·T *b){
+      if(a->d0 < b->d0) return N16PN·Order_lt;
+      if(a->d0 > b->d0) return N16PN·Order_gt;
+      return N16PN·Order_eq;
+    }
+
+    Local bool N16PN·lt(N16PN·T *a ,N16PN·T *b){
+      return a->d0 < b->d0;
+    }    
+
+    Local bool N16PN·gt(N16PN·T *a ,N16PN·T *b){
+      return a->d0 > b->d0;
+    }    
+
+    Local bool N16PN·eq(N16PN·T *a ,N16PN·T *b){
+      return a->d0 == b->d0;
+    }    
+
+    Local bool N16PN·eq_zero(N16PN·T *a){
+      return a->d0 == 0;
+    }    
+
+    // arithmetic operations
+
+    Local N16PN·Status N16PN·accumulate(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N16PN·T *current;
+
+      while( (current = va_arg(args ,N16PN·T*)) ){
+        sum += current->d0;
+        if(sum < current->d0){
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N16PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = (uint16_t)carry;
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·add(N16PN·T *sum ,N16PN·T *a ,N16PN·T *b){
+      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
+      sum->d0 = (uint16_t)(result & 0xFFFF);
+      return (result >> 16) ? N16PN·Status·carry : N16PN·Status·ok;
+    }
+
+    Local bool N16PN·increment(N16PN·T *a){
+      a->d0++;
+      return (a->d0 == 0);
+    }
+
+    Local N16PN·Status N16PN·subtract(N16PN·T *difference ,N16PN·T *a ,N16PN·T *b){
+      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
+      difference->d0 = (uint16_t)(diff & 0xFFFF);
+      return (diff > a->d0) ? N16PN·Status·borrow : N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·multiply(N16PN·T *product1 ,N16PN·T *product0 ,N16PN·T *a ,N16PN·T *b){
+      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
+      product0->d0 = (uint16_t)(product & 0xFFFF);
+      product1->d0 = (uint16_t)((product >> 16) & 0xFFFF);
+
+      if(product1->d0 == 0) return N16PN·Status·one_word_product;
+      return N16PN·Status·two_word_product;
+    }
+
+    Local N16PN·Status N16PN·divide(N16PN·T *remainder ,N16PN·T *quotient ,N16PN·T *a ,N16PN·T *b){
+      if(b->d0 == 0) return N16PN·Status·undefined_divide_by_zero;
+
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      quotient->d0 = (uint16_t)(dividend / divisor);
+      remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor));
+
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status N16PN·modulus(N16PN·T *remainder ,N16PN·T *a ,N16PN·T *b){
+      if(b->d0 == 0) return N16PN·Status·undefined_modulus_zero;
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      uint32_t q = dividend / divisor;
+      remainder->d0 = (uint16_t)(dividend - (q * divisor));
+      return N16PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint16_t (*ShiftOp)(uint16_t, uint16_t);
+
+    Local uint16_t shift_left_op(uint16_t value, uint16_t amount){
+      return value << amount;
+    }
+
+    Local uint16_t shift_right_op(uint16_t value, uint16_t amount){
+      return (uint16_t)(value >> amount);
+    }
+
+    Local N16PN·Status N16PN·shift
+    (
+     uint16_t shift_count
+     ,N16PN·T *spill
+     ,N16PN·T *operand
+     ,N16PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+    ){
+
+      if(operand == NULL && spill == NULL) return N16PN·Status·ok;
+
+      if(operand == NULL){
+        operand = &N16PN·t[0];
+        N16PN·copy(operand, N16PN·zero);
+      }
+
+      if(shift_count > 15) return N16PN·Status·gt_max_shift_count;
+
+      N16PN·T *given_operand = &N16PN·t[1];
+      N16PN·copy(given_operand, operand);
+
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (16 - shift_count));
+        N16PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count));
+      }
+
+      return N16PN·Status·ok;
+    }
+
+    Local N16PN·Status 
+    N16PN·shift_left(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){
+      return N16PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N16PN·Status 
+    N16PN·shift_right(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){
+      return N16PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N16PN·Status 
+    N16PN·arithmetic_shift_right(uint16_t shift_count, N16PN·T *operand, N16PN·T *spill){
+
+      if(shift_count > 15) return N16PN·Status·gt_max_shift_count;
+
+      if(operand == NULL){
+        operand = &N16PN·t[0];
+        N16PN·copy(operand, N16PN·zero);
+      }
+
+      N16PN·T *fill = (operand->d0 & 0x8000) ? N16PN·all_one_bit : N16PN·zero;
+      return N16PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N16PN·Λ N16PN·λ = {
+
+      .allocate_array = N16PN·allocate_array
+     ,.allocate_array_zero = N16PN·allocate_array_zero
+     ,.deallocate = N16PN·deallocate
+
+     ,.copy = N16PN·copy
+     ,.bit_and = N16PN·bit_and
+     ,.bit_or = N16PN·bit_or
+     ,.bit_complement = N16PN·bit_complement
+     ,.bit_twos_complement = N16PN·bit_twos_complement
+     ,.compare = N16PN·compare
+     ,.lt = N16PN·lt
+     ,.gt = N16PN·gt
+     ,.eq = N16PN·eq
+     ,.eq_zero = N16PN·eq_zero
+     ,.accumulate = N16PN·accumulate
+     ,.add = N16PN·add
+     ,.increment = N16PN·increment
+     ,.subtract = N16PN·subtract
+     ,.multiply = N16PN·multiply
+     ,.divide = N16PN·divide
+     ,.modulus = N16PN·modulus
+     ,.shift_left = N16PN·shift_left
+     ,.shift_right = N16PN·shift_right
+     ,.arithmetic_shift_right = N16PN·arithmetic_shift_right
+
+     ,.access = N16PN·access
+     ,.from_uint32 = N16PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/tester/cc/N32.lib.c b/tester/cc/N32.lib.c
new file mode 100644 (file)
index 0000000..fba3c21
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+  N32 - a processor native type
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+
+*/
+
+#define N32·DEBUG
+
+#ifndef FACE
+#define N32·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N32·FACE
+#define N32·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint32_t Extent;
+  typedef uint32_t Digit;
+
+  typedef struct N32·T N32·T;
+
+  extern N32·T *N32·zero;
+  extern N32·T *N32·one;
+  extern N32·T *N32·all_one_bit;
+  extern N32·T *N32·lsb;
+  extern N32·T *N32·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N32·Status·ok = 0
+    ,N32·Status·overflow = 1
+    ,N32·Status·accumulator1_overflow = 2
+    ,N32·Status·carry = 3
+    ,N32·Status·borrow = 4
+    ,N32·Status·undefined_divide_by_zero = 5
+    ,N32·Status·undefined_modulus_zero = 6
+    ,N32·Status·gt_max_shift_count = 7
+    ,N32·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+    ,N32·Status·one_word_product = 9
+    ,N32·Status·two_word_product = 10
+  } N32·Status;
+
+  typedef enum{
+    N32·Order_lt = -1
+    ,N32·Order_eq = 0
+    ,N32·Order_gt = 1
+  } N32·Order;
+
+  typedef N32·T *( *N32·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N32·T *(*allocate_array_zero)(Extent, N32·Allocate_MemoryFault);
+    N32·T *(*allocate_array)(Extent, N32·Allocate_MemoryFault);
+    void (*deallocate)(N32·T*);
+
+    void (*copy)(N32·T*, N32·T*);
+    void (*bit_and)(N32·T*, N32·T*, N32·T*);
+    void (*bit_or)(N32·T*, N32·T*, N32·T*);
+    void (*bit_complement)(N32·T*, N32·T*);
+    void (*bit_twos_complement)(N32·T*, N32·T*);
+    N32·Order (*compare)(N32·T*, N32·T*);
+    bool (*lt)(N32·T*, N32·T*);
+    bool (*gt)(N32·T*, N32·T*);
+    bool (*eq)(N32·T*, N32·T*);
+    bool (*eq_zero)(N32·T*);
+    N32·Status (*accumulate)(N32·T *accumulator1 ,N32·T *accumulator0 ,...);
+    N32·Status (*add)(N32·T*, N32·T*, N32·T*);
+    bool (*increment)(N32·T *a);
+    N32·Status (*subtract)(N32·T*, N32·T*, N32·T*);
+    N32·Status (*multiply)(N32·T*, N32·T*, N32·T*, N32·T*);
+    N32·Status (*divide)(N32·T*, N32·T*, N32·T*, N32·T*);
+    N32·Status (*modulus)(N32·T*, N32·T*, N32·T*);
+    N32·Status (*shift_left)(Extent, N32·T*, N32·T*, N32·T*);
+    N32·Status (*shift_right)(Extent, N32·T*, N32·T*, N32·T*);
+    N32·Status (*arithmetic_shift_right)(Extent, N32·T*, N32·T*);
+
+    N32·T* (*access)(N32·T*, Extent);
+    void (*from_uint32)(N32·T *destination ,uint32_t value);
+  } N32·Λ;
+
+  Local const N32·Λ N32·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N32·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N32·T{
+      Digit d0;
+    };
+
+    N32·T N32·constant[4] = {
+      {.d0 = 0},
+      {.d0 = 1},
+      {.d0 = ~(uint32_t)0},
+      {.d0 = 1 << 31}
+    };
+
+    N32·T *N32·zero = &N32·constant[0];
+    N32·T *N32·one = &N32·constant[1];
+    N32·T *N32·all_one_bit = &N32·constant[2];
+    N32·T *N32·msb = &N32·constant[3];
+    N32·T *N32·lsb = &N32·constant[1];
+
+    // the allocate an array of N32
+    N32·T *N32·allocate_array(Extent extent ,N32·Allocate_MemoryFault memory_fault){
+      N32·T *instance = malloc((extent + 1) * sizeof(N32·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N32·T *N32·allocate_array_zero(Extent extent ,N32·Allocate_MemoryFault memory_fault){
+      N32·T *instance = calloc( extent + 1 ,sizeof(N32·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N32·deallocate(N32·T *unencumbered){
+      free(unencumbered);
+    }
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N32·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    // making these LOCAL rather than reserving one block in the library is thread safe
+    // allocating a block once is more efficient
+    // library code writes these, they are not on the interface
+
+    Local N32·T N32·t[4];
+
+
+    // allocation 
+
+    extern N32·T *N32·allocate_array(Extent, N32·Allocate_MemoryFault);
+    extern N32·T *N32·allocate_array_zero(Extent, N32·Allocate_MemoryFault);
+    extern void N32·deallocate(N32·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N32·T* N32·access(N32·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N32·from_uint32(N32·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = value;
+    }
+
+    // copy, convenience copy
+
+    Local void N32·copy(N32·T *destination ,N32·T *source){
+      if(source == destination) return; // that was easy! 
+      *destination = *source;
+    }
+
+    Local void N32·set_to_zero(N32·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N32·set_to_one(N32·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N32·bit_and(N32·T *result, N32·T *a, N32·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    // result can be one of the operands
+    Local void N32·bit_or(N32·T *result, N32·T *a, N32·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32·bit_complement(N32·T *result, N32·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32·bit_twos_complement(N32·T *result ,N32·T *a){
+      result->d0 = ~a->d0 + 1;
+    }
+
+    // test functions
+
+    Local N32·Order N32·compare(N32·T *a, N32·T *b){
+      if(a->d0 < b->d0) return N32·Order_lt;
+      if(a->d0 > b->d0) return N32·Order_gt;
+      return N32·Order_eq;
+    }
+
+    Local bool N32·lt(N32·T *a ,N32·T *b){
+      return  a->d0 < b->d0;
+    }    
+
+    Local bool N32·gt(N32·T *a ,N32·T *b){
+      return  a->d0 > b->d0;
+    }    
+
+    Local bool N32·eq(N32·T *a ,N32·T *b){
+      return  a->d0 == b->d0;
+    }    
+
+    Local bool N32·eq_zero(N32·T *a){
+      return  a->d0 == 0;
+    }    
+
+
+    // arithmetic operations
+
+    // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32·Status·accumulator1_overflow
+    //
+    // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value.
+    Local N32·Status N32·accumulate(N32·T *accumulator1 ,N32·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N32·T *current;
+
+      while( (current = va_arg(args ,N32·T *)) ){
+        sum += current->d0;
+        if(sum < current->d0){  // Accumulator1 into carry
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N32·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      // wipes out prior value of accumulator1
+      accumulator1->d0 = carry;
+
+      return N32·Status·ok;
+    }
+
+    Local N32·Status N32·add(N32·T *sum ,N32·T *a ,N32·T *b){
+      uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0;
+      sum->d0 = (uint32_t)result;
+      return (result >> 32) ? N32·Status·carry : N32·Status·ok;
+    }
+
+    Local bool N32·increment(N32·T *a){
+      a->d0++;
+      return a->d0 == 0;
+    }
+
+    Local N32·Status N32·subtract(N32·T *difference ,N32·T *a ,N32·T *b){
+      uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0;
+      difference->d0 = (uint32_t)diff;
+      return (diff > a->d0) ? N32·Status·borrow : N32·Status·ok;
+    }
+
+
+    Local N32·Status N32·multiply(N32·T *product1 ,N32·T *product0 ,N32·T *a ,N32·T *b){
+      uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0;
+      product0->d0 = (uint32_t)product;
+      product1->d0 = (uint32_t)(product >> 32);
+
+      if(product1->d0 == 0) return N32·Status·one_word_product;
+      return N32·Status·two_word_product;
+    }
+
+    Local N32·Status N32·divide(N32·T *remainder ,N32·T *quotient ,N32·T *a ,N32·T *b){
+      if(b->d0 == 0) return N32·Status·undefined_divide_by_zero; 
+
+      quotient->d0 = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient->d0 * b->d0);
+
+      return N32·Status·ok;
+    }
+
+    Local N32·Status N32·modulus(N32·T *remainder ,N32·T *a ,N32·T *b){
+      if(b->d0 == 0) return N32·Status·undefined_modulus_zero; 
+      uint32_t quotient = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient * b->d0);
+      return N32·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint32_t (*ShiftOp)(uint32_t, uint32_t);
+
+    Local uint32_t shift_left_op(uint32_t value, uint32_t amount){
+      return value << amount;
+    }
+
+    Local uint32_t shift_right_op(uint32_t value, uint32_t amount){
+      return value >> amount;
+    }
+
+    // modifies all three of its operands
+    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, 
+    Local N32·Status N32·shift
+    (
+     uint32_t shift_count
+     ,N32·T *spill
+     ,N32·T *operand
+     ,N32·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+     ){
+
+      // If no result is needed, return immediately.
+      if(operand == NULL && spill == NULL) return N32·Status·ok;
+
+      // Treat NULL operand as zero.
+      if(operand == NULL){
+        operand = &N32·t[0];
+        N32·copy(operand, N32·zero);
+      }
+
+      // Shifting more than one word breaks our fill/spill model.
+      if(shift_count > 31) return N32·Status·gt_max_shift_count;
+
+      // The given operand is still required after it is modified, so we copy it.
+      N32·T *given_operand = &N32·t[1];
+      N32·copy(given_operand, operand);
+
+      // Perform the shift
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (32 - shift_count));
+        N32·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count));
+      }
+
+      return N32·Status·ok;
+    }
+
+    // Define concrete shift functions using valid C function pointers
+    Local N32·Status 
+    N32·shift_left(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){
+      return N32·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N32·Status 
+    N32·shift_right(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){
+      return N32·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N32·Status 
+    N32·arithmetic_shift_right(uint32_t shift_count, N32·T *operand, N32·T *spill){
+
+      // Guard against excessive shift counts
+      if(shift_count > 31) return N32·Status·gt_max_shift_count;
+
+      // A NULL operand is treated as zero
+      if(operand == NULL){
+        operand = &N32·t[0];
+        N32·copy(operand, N32·zero);
+      }
+
+      // Pick the fill value based on the sign bit
+      N32·T *fill = (operand->d0 & 0x80000000) ? N32·all_one_bit : N32·zero;
+
+      // Call shift_right with the appropriate fill
+      return N32·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N32·Λ N32·λ = {
+
+      .allocate_array = N32·allocate_array
+      ,.allocate_array_zero = N32·allocate_array_zero
+      ,.deallocate = N32·deallocate
+
+      ,.copy = N32·copy
+      ,.bit_and = N32·bit_and
+      ,.bit_or = N32·bit_or
+      ,.bit_complement = N32·bit_complement
+      ,.bit_twos_complement = N32·bit_twos_complement
+      ,.compare = N32·compare
+      ,.lt = N32·lt
+      ,.gt = N32·gt
+      ,.eq = N32·eq
+      ,.eq_zero = N32·eq_zero
+      ,.accumulate = N32·accumulate
+      ,.add = N32·add
+      ,.increment = N32·increment
+      ,.subtract = N32·subtract
+      ,.multiply = N32·multiply
+      ,.divide = N32·divide
+      ,.modulus = N32·modulus
+      ,.shift_left = N32·shift_left
+      ,.shift_right = N32·shift_right
+      ,.arithmetic_shift_right = N32·arithmetic_shift_right
+
+      ,.access = N32·access
+      ,.from_uint32 = N32·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/tester/cc/N32PN.lib.c b/tester/cc/N32PN.lib.c
new file mode 100644 (file)
index 0000000..952f570
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+  N32 - a processor native type
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+
+*/
+
+#define N32PN·DEBUG
+
+#ifndef FACE
+#define N32PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N32PN·FACE
+#define N32PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint32_t Extent;
+  typedef uint32_t Digit;
+
+  typedef struct N32PN·T N32PN·T;
+
+  extern N32PN·T *N32PN·zero;
+  extern N32PN·T *N32PN·one;
+  extern N32PN·T *N32PN·all_one_bit;
+  extern N32PN·T *N32PN·lsb;
+  extern N32PN·T *N32PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N32PN·Status·ok = 0
+    ,N32PN·Status·overflow = 1
+    ,N32PN·Status·accumulator1_overflow = 2
+    ,N32PN·Status·carry = 3
+    ,N32PN·Status·borrow = 4
+    ,N32PN·Status·undefined_divide_by_zero = 5
+    ,N32PN·Status·undefined_modulus_zero = 6
+    ,N32PN·Status·gt_max_shift_count = 7
+    ,N32PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+    ,N32PN·Status·one_word_product = 9
+    ,N32PN·Status·two_word_product = 10
+  } N32PN·Status;
+
+  typedef enum{
+    N32PN·Order_lt = -1
+    ,N32PN·Order_eq = 0
+    ,N32PN·Order_gt = 1
+  } N32PN·Order;
+
+  typedef N32PN·T *( *N32PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N32PN·T *(*allocate_array_zero)(Extent, N32PN·Allocate_MemoryFault);
+    N32PN·T *(*allocate_array)(Extent, N32PN·Allocate_MemoryFault);
+    void (*deallocate)(N32PN·T*);
+
+    void (*copy)(N32PN·T*, N32PN·T*);
+    void (*bit_and)(N32PN·T*, N32PN·T*, N32PN·T*);
+    void (*bit_or)(N32PN·T*, N32PN·T*, N32PN·T*);
+    void (*bit_complement)(N32PN·T*, N32PN·T*);
+    void (*bit_twos_complement)(N32PN·T*, N32PN·T*);
+    N32PN·Order (*compare)(N32PN·T*, N32PN·T*);
+    bool (*lt)(N32PN·T*, N32PN·T*);
+    bool (*gt)(N32PN·T*, N32PN·T*);
+    bool (*eq)(N32PN·T*, N32PN·T*);
+    bool (*eq_zero)(N32PN·T*);
+    N32PN·Status (*accumulate)(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...);
+    N32PN·Status (*add)(N32PN·T*, N32PN·T*, N32PN·T*);
+    bool (*increment)(N32PN·T *a);
+    N32PN·Status (*subtract)(N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*multiply)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*divide)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*modulus)(N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*shift_left)(Extent, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*shift_right)(Extent, N32PN·T*, N32PN·T*, N32PN·T*);
+    N32PN·Status (*arithmetic_shift_right)(Extent, N32PN·T*, N32PN·T*);
+
+    N32PN·T* (*access)(N32PN·T*, Extent);
+    void (*from_uint32)(N32PN·T *destination ,uint32_t value);
+  } N32PN·Λ;
+
+  Local const N32PN·Λ N32PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N32PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N32PN·T{
+      Digit d0;
+    };
+
+    N32PN·T N32PN·constant[4] = {
+      {.d0 = 0},
+      {.d0 = 1},
+      {.d0 = ~(uint32_t)0},
+      {.d0 = 1 << 31}
+    };
+
+    N32PN·T *N32PN·zero = &N32PN·constant[0];
+    N32PN·T *N32PN·one = &N32PN·constant[1];
+    N32PN·T *N32PN·all_one_bit = &N32PN·constant[2];
+    N32PN·T *N32PN·msb = &N32PN·constant[3];
+    N32PN·T *N32PN·lsb = &N32PN·constant[1];
+
+    // the allocate an array of N32
+    N32PN·T *N32PN·allocate_array(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){
+      N32PN·T *instance = malloc((extent + 1) * sizeof(N32PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N32PN·T *N32PN·allocate_array_zero(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){
+      N32PN·T *instance = calloc( extent + 1 ,sizeof(N32PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N32PN·deallocate(N32PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N32PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    // making these LOCAL rather than reserving one block in the library is thread safe
+    // allocating a block once is more efficient
+    // library code writes these, they are not on the interface
+
+    Local N32PN·T N32PN·t[4];
+
+
+    // allocation 
+
+    extern N32PN·T *N32PN·allocate_array(Extent, N32PN·Allocate_MemoryFault);
+    extern N32PN·T *N32PN·allocate_array_zero(Extent, N32PN·Allocate_MemoryFault);
+    extern void N32PN·deallocate(N32PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N32PN·T* N32PN·access(N32PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N32PN·from_uint32(N32PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = value;
+    }
+
+    // copy, convenience copy
+
+    Local void N32PN·copy(N32PN·T *destination ,N32PN·T *source){
+      if(source == destination) return; // that was easy! 
+      *destination = *source;
+    }
+
+    Local void N32PN·set_to_zero(N32PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N32PN·set_to_one(N32PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N32PN·bit_and(N32PN·T *result, N32PN·T *a, N32PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    // result can be one of the operands
+    Local void N32PN·bit_or(N32PN·T *result, N32PN·T *a, N32PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32PN·bit_complement(N32PN·T *result, N32PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    // result can the same as the operand
+    Local void N32PN·bit_twos_complement(N32PN·T *result ,N32PN·T *a){
+      result->d0 = ~a->d0 + 1;
+    }
+
+    // test functions
+
+    Local N32PN·Order N32PN·compare(N32PN·T *a, N32PN·T *b){
+      if(a->d0 < b->d0) return N32PN·Order_lt;
+      if(a->d0 > b->d0) return N32PN·Order_gt;
+      return N32PN·Order_eq;
+    }
+
+    Local bool N32PN·lt(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 < b->d0;
+    }    
+
+    Local bool N32PN·gt(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 > b->d0;
+    }    
+
+    Local bool N32PN·eq(N32PN·T *a ,N32PN·T *b){
+      return  a->d0 == b->d0;
+    }    
+
+    Local bool N32PN·eq_zero(N32PN·T *a){
+      return  a->d0 == 0;
+    }    
+
+
+    // arithmetic operations
+
+    // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32PN·Status·accumulator1_overflow
+    //
+    // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value.
+    Local N32PN·Status N32PN·accumulate(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N32PN·T *current;
+
+      while( (current = va_arg(args ,N32PN·T *)) ){
+        sum += current->d0;
+        if(sum < current->d0){  // Accumulator1 into carry
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N32PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      // wipes out prior value of accumulator1
+      accumulator1->d0 = carry;
+
+      return N32PN·Status·ok;
+    }
+
+    Local N32PN·Status N32PN·add(N32PN·T *sum ,N32PN·T *a ,N32PN·T *b){
+      uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0;
+      sum->d0 = (uint32_t)result;
+      return (result >> 32) ? N32PN·Status·carry : N32PN·Status·ok;
+    }
+
+    Local bool N32PN·increment(N32PN·T *a){
+      a->d0++;
+      return a->d0 == 0;
+    }
+
+    Local N32PN·Status N32PN·subtract(N32PN·T *difference ,N32PN·T *a ,N32PN·T *b){
+      uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0;
+      difference->d0 = (uint32_t)diff;
+      return (diff > a->d0) ? N32PN·Status·borrow : N32PN·Status·ok;
+    }
+
+
+    Local N32PN·Status N32PN·multiply(N32PN·T *product1 ,N32PN·T *product0 ,N32PN·T *a ,N32PN·T *b){
+      uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0;
+      product0->d0 = (uint32_t)product;
+      product1->d0 = (uint32_t)(product >> 32);
+
+      if(product1->d0 == 0) return N32PN·Status·one_word_product;
+      return N32PN·Status·two_word_product;
+    }
+
+    Local N32PN·Status N32PN·divide(N32PN·T *remainder ,N32PN·T *quotient ,N32PN·T *a ,N32PN·T *b){
+      if(b->d0 == 0) return N32PN·Status·undefined_divide_by_zero; 
+
+      quotient->d0 = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient->d0 * b->d0);
+
+      return N32PN·Status·ok;
+    }
+
+    Local N32PN·Status N32PN·modulus(N32PN·T *remainder ,N32PN·T *a ,N32PN·T *b){
+      if(b->d0 == 0) return N32PN·Status·undefined_modulus_zero; 
+      uint32_t quotient = a->d0 / b->d0;
+      remainder->d0 = a->d0 - (quotient * b->d0);
+      return N32PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint32_t (*ShiftOp)(uint32_t, uint32_t);
+
+    Local uint32_t shift_left_op(uint32_t value, uint32_t amount){
+      return value << amount;
+    }
+
+    Local uint32_t shift_right_op(uint32_t value, uint32_t amount){
+      return value >> amount;
+    }
+
+    // modifies all three of its operands
+    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, 
+    Local N32PN·Status N32PN·shift
+    (
+     uint32_t shift_count
+     ,N32PN·T *spill
+     ,N32PN·T *operand
+     ,N32PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+     ){
+
+      // If no result is needed, return immediately.
+      if(operand == NULL && spill == NULL) return N32PN·Status·ok;
+
+      // Treat NULL operand as zero.
+      if(operand == NULL){
+        operand = &N32PN·t[0];
+        N32PN·copy(operand, N32PN·zero);
+      }
+
+      // Shifting more than one word breaks our fill/spill model.
+      if(shift_count > 31) return N32PN·Status·gt_max_shift_count;
+
+      // The given operand is still required after it is modified, so we copy it.
+      N32PN·T *given_operand = &N32PN·t[1];
+      N32PN·copy(given_operand, operand);
+
+      // Perform the shift
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (32 - shift_count));
+        N32PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count));
+      }
+
+      return N32PN·Status·ok;
+    }
+
+    // Define concrete shift functions using valid C function pointers
+    Local N32PN·Status 
+    N32PN·shift_left(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){
+      return N32PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N32PN·Status 
+    N32PN·shift_right(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){
+      return N32PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N32PN·Status 
+    N32PN·arithmetic_shift_right(uint32_t shift_count, N32PN·T *operand, N32PN·T *spill){
+
+      // Guard against excessive shift counts
+      if(shift_count > 31) return N32PN·Status·gt_max_shift_count;
+
+      // A NULL operand is treated as zero
+      if(operand == NULL){
+        operand = &N32PN·t[0];
+        N32PN·copy(operand, N32PN·zero);
+      }
+
+      // Pick the fill value based on the sign bit
+      N32PN·T *fill = (operand->d0 & 0x80000000) ? N32PN·all_one_bit : N32PN·zero;
+
+      // Call shift_right with the appropriate fill
+      return N32PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N32PN·Λ N32PN·λ = {
+
+      .allocate_array = N32PN·allocate_array
+      ,.allocate_array_zero = N32PN·allocate_array_zero
+      ,.deallocate = N32PN·deallocate
+
+      ,.copy = N32PN·copy
+      ,.bit_and = N32PN·bit_and
+      ,.bit_or = N32PN·bit_or
+      ,.bit_complement = N32PN·bit_complement
+      ,.bit_twos_complement = N32PN·bit_twos_complement
+      ,.compare = N32PN·compare
+      ,.lt = N32PN·lt
+      ,.gt = N32PN·gt
+      ,.eq = N32PN·eq
+      ,.eq_zero = N32PN·eq_zero
+      ,.accumulate = N32PN·accumulate
+      ,.add = N32PN·add
+      ,.increment = N32PN·increment
+      ,.subtract = N32PN·subtract
+      ,.multiply = N32PN·multiply
+      ,.divide = N32PN·divide
+      ,.modulus = N32PN·modulus
+      ,.shift_left = N32PN·shift_left
+      ,.shift_right = N32PN·shift_right
+      ,.arithmetic_shift_right = N32PN·arithmetic_shift_right
+
+      ,.access = N32PN·access
+      ,.from_uint32 = N32PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/tester/cc/N64PN.lib.c b/tester/cc/N64PN.lib.c
new file mode 100644 (file)
index 0000000..583ad08
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+  N64 - a 64-bit native type
+
+  For binary operations: a op b -> c
+
+  Similar to N32, but now each Digit is 64 bits. Where a 128-bit
+  intermediate is necessary (e.g. multiplication), we handle it
+  manually using two 64-bit parts.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N64PN·DEBUG
+
+#ifndef FACE
+#define N64PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N64PN·FACE
+#define N64PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint64_t Extent;
+  typedef uint64_t Digit;
+
+  typedef struct N64PN·T N64PN·T;
+
+  extern N64PN·T *N64PN·zero;
+  extern N64PN·T *N64PN·one;
+  extern N64PN·T *N64PN·all_one_bit;
+  extern N64PN·T *N64PN·lsb;
+  extern N64PN·T *N64PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum {
+    N64PN·Status·ok = 0
+   ,N64PN·Status·overflow = 1
+   ,N64PN·Status·accumulator1_overflow = 2
+   ,N64PN·Status·carry = 3
+   ,N64PN·Status·borrow = 4
+   ,N64PN·Status·undefined_divide_by_zero = 5
+   ,N64PN·Status·undefined_modulus_zero = 6
+   ,N64PN·Status·gt_max_shift_count = 7
+   ,N64PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
+   ,N64PN·Status·one_word_product = 9
+   ,N64PN·Status·two_word_product = 10
+  } N64PN·Status;
+
+  typedef enum {
+    N64PN·Order_lt = -1
+   ,N64PN·Order_eq = 0
+   ,N64PN·Order_gt = 1
+  } N64PN·Order;
+
+  typedef N64PN·T *(*N64PN·Allocate_MemoryFault)(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct {
+
+    N64PN·T *(*allocate_array_zero)(Extent, N64PN·Allocate_MemoryFault);
+    N64PN·T *(*allocate_array)(Extent, N64PN·Allocate_MemoryFault);
+    void   (*deallocate)(N64PN·T*);
+
+    void        (*copy)(N64PN·T*, N64PN·T*);
+    void        (*bit_and)(N64PN·T*, N64PN·T*, N64PN·T*);
+    void        (*bit_or)(N64PN·T*, N64PN·T*, N64PN·T*);
+    void        (*bit_complement)(N64PN·T*, N64PN·T*);
+    void        (*bit_twos_complement)(N64PN·T*, N64PN·T*);
+    N64PN·Order   (*compare)(N64PN·T*, N64PN·T*);
+    bool        (*lt)(N64PN·T*, N64PN·T*);
+    bool        (*gt)(N64PN·T*, N64PN·T*);
+    bool        (*eq)(N64PN·T*, N64PN·T*);
+    bool        (*eq_zero)(N64PN·T*);
+    N64PN·Status  (*accumulate)(N64PN·T *accumulator1, N64PN·T *accumulator0, ...);
+    N64PN·Status  (*add)(N64PN·T*, N64PN·T*, N64PN·T*);
+    bool        (*increment)(N64PN·T *a);
+    N64PN·Status  (*subtract)(N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*multiply)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*divide)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*modulus)(N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*shift_left)(Extent, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*shift_right)(Extent, N64PN·T*, N64PN·T*, N64PN·T*);
+    N64PN·Status  (*arithmetic_shift_right)(Extent, N64PN·T*, N64PN·T*);
+
+    N64PN·T*      (*access)(N64PN·T*, Extent);
+    void        (*from_uint64)(N64PN·T *destination, uint64_t value);
+
+  } N64PN·Λ;
+
+  Local const N64PN·Λ N64PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N64PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+    #include <stdarg.h>
+    #include <stdlib.h>
+
+    struct N64PN·T {
+      Digit d0;
+    };
+
+    // For constants, we store them in an array for convenience
+    // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63)
+    N64PN·T N64PN·constant[4] = {
+      {.d0 = 0ULL},
+      {.d0 = 1ULL},
+      {.d0 = ~(uint64_t)0ULL},
+      {.d0 = 1ULL << 63}
+    };
+
+    N64PN·T *N64PN·zero = &N64PN·constant[0];
+    N64PN·T *N64PN·one = &N64PN·constant[1];
+    N64PN·T *N64PN·all_one_bit = &N64PN·constant[2];
+    N64PN·T *N64PN·msb = &N64PN·constant[3];
+    N64PN·T *N64PN·lsb = &N64PN·constant[1];
+
+    // allocate an array of N64
+    N64PN·T *N64PN·allocate_array(Extent extent, N64PN·Allocate_MemoryFault memory_fault){
+      N64PN·T *instance = malloc( (extent + 1) * sizeof(N64PN·T) );
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    N64PN·T *N64PN·allocate_array_zero(Extent extent, N64PN·Allocate_MemoryFault memory_fault){
+      N64PN·T *instance = calloc(extent + 1, sizeof(N64PN·T));
+      if(!instance){
+        return memory_fault ? memory_fault(extent) : NULL;
+      }
+      return instance;
+    }
+
+    void N64PN·deallocate(N64PN·T *unencumbered){
+      free(unencumbered);
+    }
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N64PN·T {
+      Digit d0;
+    };
+
+    // local temporary variables
+    Local N64PN·T N64PN·t[4];
+
+    // allocation references
+    extern N64PN·T *N64PN·allocate_array(Extent, N64PN·Allocate_MemoryFault);
+    extern N64PN·T *N64PN·allocate_array_zero(Extent, N64PN·Allocate_MemoryFault);
+    extern void   N64PN·deallocate(N64PN·T *);
+
+    // Access array
+    Local N64PN·T* N64PN·access(N64PN·T *array, Extent index){
+      return &array[index];
+    }
+
+    Local void N64PN·from_uint64(N64PN·T *destination, uint64_t value){
+      if(destination == NULL) return;
+      destination->d0 = value;
+    }
+
+    // copy
+    Local void N64PN·copy(N64PN·T *destination, N64PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    // bit operations
+
+    Local void N64PN·bit_and(N64PN·T *result, N64PN·T *a, N64PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N64PN·bit_or(N64PN·T *result, N64PN·T *a, N64PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N64PN·bit_complement(N64PN·T *result, N64PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N64PN·bit_twos_complement(N64PN·T *result, N64PN·T *a){
+      result->d0 = ~a->d0 + 1ULL;
+    }
+
+    // compare & test functions
+
+    Local N64PN·Order N64PN·compare(N64PN·T *a, N64PN·T *b){
+      if(a->d0 < b->d0) return N64PN·Order_lt;
+      if(a->d0 > b->d0) return N64PN·Order_gt;
+      return N64PN·Order_eq;
+    }
+
+    Local bool N64PN·lt(N64PN·T *a, N64PN·T *b){
+      return (a->d0 < b->d0);
+    }
+
+    Local bool N64PN·gt(N64PN·T *a, N64PN·T *b){
+      return (a->d0 > b->d0);
+    }
+
+    Local bool N64PN·eq(N64PN·T *a, N64PN·T *b){
+      return (a->d0 == b->d0);
+    }
+
+    Local bool N64PN·eq_zero(N64PN·T *a){
+      return (a->d0 == 0ULL);
+    }
+
+    // arithmetic operations
+
+    // accumulate
+    Local N64PN·Status N64PN·accumulate(N64PN·T *accumulator1, N64PN·T *accumulator0, ...){
+      va_list args;
+      va_start(args, accumulator0);
+
+      uint64_t sum = accumulator0->d0;
+      uint64_t carry = 0;
+      N64PN·T *current;
+
+      while( (current = va_arg(args, N64PN·T*)) ){
+        uint64_t prior = sum;
+        sum += current->d0;
+        if(sum < prior){  // indicates carry
+          carry++;
+          // if carry overflowed a 64-bit, that's an accumulator1 overflow
+          if(carry == 0ULL){
+            va_end(args);
+            return N64PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = carry;
+      return N64PN·Status·ok;
+    }
+
+    // add
+    Local N64PN·Status N64PN·add(N64PN·T *sum, N64PN·T *a, N64PN·T *b){
+      __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0;
+      // But to avoid using a GNU extension, we can do the simpler approach:
+      // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits:
+      uint64_t temp = a->d0 + b->d0;
+      sum->d0 = temp;
+      if(temp < a->d0) return N64PN·Status·carry;  // means we overflowed
+      return N64PN·Status·ok;
+    }
+
+    Local bool N64PN·increment(N64PN·T *a){
+      uint64_t old = a->d0;
+      a->d0++;
+      // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF
+      return (a->d0 < old);
+    }
+
+    // subtract
+    Local N64PN·Status N64PN·subtract(N64PN·T *difference, N64PN·T *a, N64PN·T *b){
+      uint64_t tmpA = a->d0;
+      uint64_t tmpB = b->d0;
+      uint64_t diff = tmpA - tmpB;
+      difference->d0 = diff;
+      if(diff > tmpA) return N64PN·Status·borrow; // indicates we borrowed
+      return N64PN·Status·ok;
+    }
+
+    // multiply
+    // We'll do a 64x64->128 using two 64-bit accumulators
+    Local N64PN·Status N64PN·multiply(N64PN·T *product1, N64PN·T *product0, N64PN·T *a, N64PN·T *b){
+      uint64_t A = a->d0;
+      uint64_t B = b->d0;
+
+      // Break each operand into high & low 32 bits
+      uint64_t a_lo = (uint32_t)(A & 0xffffffffULL);
+      uint64_t a_hi = A >> 32;
+      uint64_t b_lo = (uint32_t)(B & 0xffffffffULL);
+      uint64_t b_hi = B >> 32;
+
+      // partial products
+      uint64_t low = a_lo * b_lo;                   // 64-bit
+      uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits
+      uint64_t high = a_hi * b_hi;                  // up to 64 bits
+
+      // incorporate cross into low, high
+      // cross is effectively the middle bits, so shift cross by 32 and add to low
+      uint64_t cross_low = (cross & 0xffffffffULL) << 32;  // lower part
+      uint64_t cross_high = cross >> 32;                   // upper part
+
+      // add cross_low to low, capture carry
+      uint64_t old_low = low;
+      low += cross_low;
+      if(low < old_low) cross_high++;
+
+      // final high
+      high += cross_high;
+
+      // store results
+      product0->d0 = low;
+      product1->d0 = high;
+
+      if(high == 0ULL) return N64PN·Status·one_word_product;
+      return N64PN·Status·two_word_product;
+    }
+
+    // divide
+    Local N64PN·Status N64PN·divide(N64PN·T *remainder, N64PN·T *quotient, N64PN·T *a, N64PN·T *b){
+      // we do not handle a > 64-bit, just the single 64-bit
+      if(b->d0 == 0ULL) return N64PN·Status·undefined_divide_by_zero;
+
+      uint64_t divd = a->d0; // dividend
+      uint64_t divs = b->d0; // divisor
+
+      quotient->d0 = divd / divs;
+      remainder->d0 = divd - (quotient->d0 * divs);
+
+      return N64PN·Status·ok;
+    }
+
+    // modulus
+    Local N64PN·Status N64PN·modulus(N64PN·T *remainder, N64PN·T *a, N64PN·T *b){
+      if(b->d0 == 0ULL) return N64PN·Status·undefined_modulus_zero;
+
+      uint64_t divd = a->d0;
+      uint64_t divs = b->d0;
+      uint64_t q = divd / divs;
+      remainder->d0 = divd - (q * divs);
+
+      return N64PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint64_t (*ShiftOp)(uint64_t, uint64_t);
+
+    Local uint64_t shift_left_op(uint64_t value, uint64_t amount){
+      return (value << amount);
+    }
+
+    Local uint64_t shift_right_op(uint64_t value, uint64_t amount){
+      return (value >> amount);
+    }
+
+    // modifies all three of its operands
+    // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill
+    Local N64PN·Status N64PN·shift
+    (
+     uint64_t shift_count,
+     N64PN·T *spill,
+     N64PN·T *operand,
+     N64PN·T *fill,
+     ShiftOp shift_op,
+     ShiftOp complement_shift_op
+    ){
+      if(operand == NULL && spill == NULL) return N64PN·Status·ok;
+
+      // Treat NULL operand as zero
+      if(operand == NULL){
+        operand = &N64PN·t[0];
+        N64PN·copy(operand, N64PN·zero);
+      }
+
+      // Shifting more than 63 bits breaks fill/spill logic
+      if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count;
+
+      N64PN·T *given_operand = &N64PN·t[1];
+      N64PN·copy(given_operand, operand);
+
+      // Perform the shift
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count));
+        N64PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count));
+      }
+
+      return N64PN·Status·ok;
+    }
+
+    Local N64PN·Status N64PN·shift_left(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){
+      return N64PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N64PN·Status N64PN·shift_right(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){
+      return N64PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N64PN·Status N64PN·arithmetic_shift_right(uint64_t shift_count, N64PN·T *operand, N64PN·T *spill){
+      if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count;
+
+      // A NULL operand is treated as zero
+      if(operand == NULL){
+        operand = &N64PN·t[0];
+        N64PN·copy(operand, N64PN·zero);
+      }
+
+      // sign bit check
+      N64PN·T *fill = (operand->d0 & (1ULL << 63)) ? N64PN·all_one_bit : N64PN·zero;
+      return N64PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N64PN·Λ N64PN·λ = {
+      .allocate_array = N64PN·allocate_array
+     ,.allocate_array_zero = N64PN·allocate_array_zero
+     ,.deallocate = N64PN·deallocate
+
+     ,.copy = N64PN·copy
+     ,.bit_and = N64PN·bit_and
+     ,.bit_or = N64PN·bit_or
+     ,.bit_complement = N64PN·bit_complement
+     ,.bit_twos_complement = N64PN·bit_twos_complement
+     ,.compare = N64PN·compare
+     ,.lt = N64PN·lt
+     ,.gt = N64PN·gt
+     ,.eq = N64PN·eq
+     ,.eq_zero = N64PN·eq_zero
+     ,.accumulate = N64PN·accumulate
+     ,.add = N64PN·add
+     ,.increment = N64PN·increment
+     ,.subtract = N64PN·subtract
+     ,.multiply = N64PN·multiply
+     ,.divide = N64PN·divide
+     ,.modulus = N64PN·modulus
+     ,.shift_left = N64PN·shift_left
+     ,.shift_right = N64PN·shift_right
+     ,.arithmetic_shift_right = N64PN·arithmetic_shift_right
+
+     ,.access = N64PN·access
+     ,.from_uint64 = N64PN·from_uint64
+    };
+
+  #endif
+
+#endif
diff --git a/tester/cc/N8PN.lib.c b/tester/cc/N8PN.lib.c
new file mode 100644 (file)
index 0000000..9cfd66d
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+  N8PN - PN = refers to the use of processor native accumulator 
+
+  For binary operations:  a op b -> c
+
+  See the document on the proper use of the Natural types.
+
+  On the subject of multiple pointers indicating the same location in memory:
+
+  When a routine has multiple results, and one or more of the result location
+  pointers point to the same storage, the routine will either return an error
+  status, or have defined behavior.
+
+  When a routine has multiple operands, in any combination, those
+  pointers can point to the same location, and the routine will
+  function as advertised.
+
+  When an operand functions as both an input and a result, perhaps due
+  to a result pointer pointing to the same place as an operand
+  pointer, the routine will function as advertised. (Internally the
+  routine might make a temporary copy of the operand to accomplish
+  this.)
+*/
+
+#define N8PN·DEBUG
+
+#ifndef FACE
+#define N8PN·IMPLEMENTATION
+#define FACE
+#endif
+
+//--------------------------------------------------------------------------------
+// Interface
+
+#ifndef N8PN·FACE
+#define N8PN·FACE
+
+  #include <stdint.h>
+  #include <stdbool.h>
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  //----------------------------------------
+  // Instance Data (Declaration Only)
+
+  typedef uint8_t Extent;
+  typedef uint8_t Digit;
+
+  typedef struct N8PN·T N8PN·T;
+
+  extern N8PN·T *N8PN·zero;
+  extern N8PN·T *N8PN·one;
+  extern N8PN·T *N8PN·all_one_bit;
+  extern N8PN·T *N8PN·lsb;
+  extern N8PN·T *N8PN·msb;
+
+  //----------------------------------------
+  // Return/Error Status and handlers
+
+  typedef enum{
+    N8PN·Status·ok = 0
+   ,N8PN·Status·overflow = 1
+   ,N8PN·Status·accumulator1_overflow = 2
+   ,N8PN·Status·carry = 3
+   ,N8PN·Status·borrow = 4
+   ,N8PN·Status·undefined_divide_by_zero = 5
+   ,N8PN·Status·undefined_modulus_zero = 6
+   ,N8PN·Status·gt_max_shift_count = 7
+   ,N8PN·Status·spill_eq_operand = 8
+   ,N8PN·Status·one_word_product = 9
+   ,N8PN·Status·two_word_product = 10
+  } N8PN·Status;
+
+  typedef enum{
+    N8PN·Order_lt = -1
+   ,N8PN·Order_eq = 0
+   ,N8PN·Order_gt = 1
+  } N8PN·Order;
+
+  typedef N8PN·T *( *N8PN·Allocate_MemoryFault )(Extent);
+
+  //----------------------------------------
+  // Interface
+
+  typedef struct{
+
+    N8PN·T *(*allocate_array_zero)(Extent, N8PN·Allocate_MemoryFault);
+    N8PN·T *(*allocate_array)(Extent, N8PN·Allocate_MemoryFault);
+    void (*deallocate)(N8PN·T*);
+
+    void (*copy)(N8PN·T*, N8PN·T*);
+    void (*bit_and)(N8PN·T*, N8PN·T*, N8PN·T*);
+    void (*bit_or)(N8PN·T*, N8PN·T*, N8PN·T*);
+    void (*bit_complement)(N8PN·T*, N8PN·T*);
+    void (*bit_twos_complement)(N8PN·T*, N8PN·T*);
+    N8PN·Order (*compare)(N8PN·T*, N8PN·T*);
+    bool (*lt)(N8PN·T*, N8PN·T*);
+    bool (*gt)(N8PN·T*, N8PN·T*);
+    bool (*eq)(N8PN·T*, N8PN·T*);
+    bool (*eq_zero)(N8PN·T*);
+    N8PN·Status (*accumulate)(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...);
+    N8PN·Status (*add)(N8PN·T*, N8PN·T*, N8PN·T*);
+    bool (*increment)(N8PN·T *a);
+    N8PN·Status (*subtract)(N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*multiply)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*divide)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*modulus)(N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*shift_left)(Extent, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*shift_right)(Extent, N8PN·T*, N8PN·T*, N8PN·T*);
+    N8PN·Status (*arithmetic_shift_right)(Extent, N8PN·T*, N8PN·T*);
+
+    N8PN·T* (*access)(N8PN·T*, Extent);
+    void (*from_uint32)(N8PN·T *destination ,uint32_t value);
+  } N8PN·Λ;
+
+  Local const N8PN·Λ N8PN·λ; // initialized in the LOCAL section
+
+#endif
+
+//--------------------------------------------------------------------------------
+// Implementation
+
+#ifdef N8PN·IMPLEMENTATION
+
+  // this part goes into the library
+  #ifndef LOCAL
+
+  #include <stdarg.h>
+  #include <stdlib.h>
+
+  struct N8PN·T{
+    Digit d0;
+  };
+
+  N8PN·T N8PN·constant[4] = {
+  {.d0 = 0},
+  {.d0 = 1},
+  {.d0 = ~(uint8_t)0},
+  {.d0 = 1 << 7}
+  };
+
+  N8PN·T *N8PN·zero = &N8PN·constant[0];
+  N8PN·T *N8PN·one = &N8PN·constant[1];
+  N8PN·T *N8PN·all_one_bit = &N8PN·constant[2];
+  N8PN·T *N8PN·msb = &N8PN·constant[3];
+  N8PN·T *N8PN·lsb = &N8PN·constant[1];
+
+  // the allocate an array of N8
+  N8PN·T *N8PN·allocate_array(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){
+    N8PN·T *instance = malloc((extent + 1) * sizeof(N8PN·T));
+    if(!instance){
+      return memory_fault ? memory_fault(extent) : NULL;
+    }
+    return instance;
+  }
+
+  N8PN·T *N8PN·allocate_array_zero(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){
+    N8PN·T *instance = calloc(extent + 1, sizeof(N8PN·T));
+    if(!instance){
+      return memory_fault ? memory_fault(extent) : NULL;
+    }
+    return instance;
+  }
+
+  void N8PN·deallocate(N8PN·T *unencumbered){
+    free(unencumbered);
+  }
+
+
+  #endif
+
+  // This part is included after the library user's code
+  #ifdef LOCAL
+
+    // instance
+
+    struct N8PN·T{
+      Digit d0;
+    };
+
+    // temporary variables
+    Local N8PN·T N8PN·t[4];
+
+    // allocation 
+
+    extern N8PN·T *N8PN·allocate_array(Extent, N8PN·Allocate_MemoryFault);
+    extern N8PN·T *N8PN·allocate_array_zero(Extent, N8PN·Allocate_MemoryFault);
+    extern void N8PN·deallocate(N8PN·T *);
+
+    // so the user can access numbers in an array allocation
+    Local N8PN·T* N8PN·access(N8PN·T *array ,Extent index){
+      return &array[index];
+    }
+
+    Local void N8PN·from_uint32(N8PN·T *destination ,uint32_t value){
+      if(destination == NULL) return;
+      destination->d0 = (uint8_t)(value & 0xFF);
+    }
+
+    // copy, convenience copy
+
+    Local void N8PN·copy(N8PN·T *destination ,N8PN·T *source){
+      if(source == destination) return;
+      *destination = *source;
+    }
+
+    Local void N8PN·set_to_zero(N8PN·T *instance){
+      instance->d0 = 0;
+    }
+
+    Local void N8PN·set_to_one(N8PN·T *instance){
+      instance->d0 = 1;
+    }
+
+    // bit operations
+
+    Local void N8PN·bit_and(N8PN·T *result, N8PN·T *a, N8PN·T *b){
+      result->d0 = a->d0 & b->d0;
+    }
+
+    Local void N8PN·bit_or(N8PN·T *result, N8PN·T *a, N8PN·T *b){
+      result->d0 = a->d0 | b->d0;
+    }
+
+    Local void N8PN·bit_complement(N8PN·T *result, N8PN·T *a){
+      result->d0 = ~a->d0;
+    }
+
+    Local void N8PN·bit_twos_complement(N8PN·T *result ,N8PN·T *a){
+      result->d0 = (uint8_t)(~a->d0 + 1);
+    }
+
+    // test functions
+
+    Local N8PN·Order N8PN·compare(N8PN·T *a, N8PN·T *b){
+      if(a->d0 < b->d0) return N8PN·Order_lt;
+      if(a->d0 > b->d0) return N8PN·Order_gt;
+      return N8PN·Order_eq;
+    }
+
+    Local bool N8PN·lt(N8PN·T *a ,N8PN·T *b){
+      return a->d0 < b->d0;
+    }    
+
+    Local bool N8PN·gt(N8PN·T *a ,N8PN·T *b){
+      return a->d0 > b->d0;
+    }    
+
+    Local bool N8PN·eq(N8PN·T *a ,N8PN·T *b){
+      return a->d0 == b->d0;
+    }    
+
+    Local bool N8PN·eq_zero(N8PN·T *a){
+      return a->d0 == 0;
+    }    
+
+    // arithmetic operations
+
+    Local N8PN·Status N8PN·accumulate(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...){
+
+      va_list args;
+      va_start(args ,accumulator0);
+      uint32_t sum = accumulator0->d0;
+      uint32_t carry = 0;
+      N8PN·T *current;
+
+      while( (current = va_arg(args ,N8PN·T*)) ){
+        sum += current->d0;
+        if(sum < current->d0){
+          (carry)++;
+          if(carry == 0){
+            va_end(args);
+            return N8PN·Status·accumulator1_overflow;
+          }
+        }
+      }
+      va_end(args);
+
+      accumulator1->d0 = (uint8_t)carry;
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·add(N8PN·T *sum ,N8PN·T *a ,N8PN·T *b){
+      uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0;
+      sum->d0 = (uint8_t)(result & 0xFF);
+      return (result >> 8) ? N8PN·Status·carry : N8PN·Status·ok;
+    }
+
+    Local bool N8PN·increment(N8PN·T *a){
+      a->d0++;
+      return (a->d0 == 0);
+    }
+
+    Local N8PN·Status N8PN·subtract(N8PN·T *difference ,N8PN·T *a ,N8PN·T *b){
+      uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0;
+      difference->d0 = (uint8_t)(diff & 0xFF);
+      return (diff > a->d0) ? N8PN·Status·borrow : N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·multiply(N8PN·T *product1 ,N8PN·T *product0 ,N8PN·T *a ,N8PN·T *b){
+      uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0;
+      product0->d0 = (uint8_t)(product & 0xFF);
+      product1->d0 = (uint8_t)((product >> 8) & 0xFF);
+
+      if(product1->d0 == 0) return N8PN·Status·one_word_product;
+      return N8PN·Status·two_word_product;
+    }
+
+    Local N8PN·Status N8PN·divide(N8PN·T *remainder ,N8PN·T *quotient ,N8PN·T *a ,N8PN·T *b){
+      if(b->d0 == 0) return N8PN·Status·undefined_divide_by_zero;
+
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      quotient->d0 = (uint8_t)(dividend / divisor);
+      remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor));
+
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status N8PN·modulus(N8PN·T *remainder ,N8PN·T *a ,N8PN·T *b){
+      if(b->d0 == 0) return N8PN·Status·undefined_modulus_zero;
+      uint32_t dividend = a->d0;
+      uint32_t divisor = b->d0;
+      uint32_t q = dividend / divisor;
+      remainder->d0 = (uint8_t)(dividend - (q * divisor));
+      return N8PN·Status·ok;
+    }
+
+    // bit motion
+
+    typedef uint8_t (*ShiftOp)(uint8_t, uint8_t);
+
+    Local uint8_t shift_left_op(uint8_t value, uint8_t amount){
+      return (uint8_t)(value << amount);
+    }
+
+    Local uint8_t shift_right_op(uint8_t value, uint8_t amount){
+      return (uint8_t)(value >> amount);
+    }
+
+    Local N8PN·Status N8PN·shift
+    (
+     uint8_t shift_count
+     ,N8PN·T *spill
+     ,N8PN·T *operand
+     ,N8PN·T *fill
+     ,ShiftOp shift_op
+     ,ShiftOp complement_shift_op
+    ){
+
+      if(operand == NULL && spill == NULL) return N8PN·Status·ok;
+
+      if(operand == NULL){
+        operand = &N8PN·t[0];
+        N8PN·copy(operand, N8PN·zero);
+      }
+
+      if(shift_count > 7) return N8PN·Status·gt_max_shift_count;
+
+      N8PN·T *given_operand = &N8PN·t[1];
+      N8PN·copy(given_operand, operand);
+
+      operand->d0 = shift_op(given_operand->d0, shift_count);
+      if(fill != NULL){
+        fill->d0 = complement_shift_op(fill->d0, (8 - shift_count));
+        N8PN·bit_or(operand, operand, fill);
+      }
+      if(spill != NULL){
+        spill->d0 = shift_op(spill->d0, shift_count);
+        spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count));
+      }
+
+      return N8PN·Status·ok;
+    }
+
+    Local N8PN·Status 
+    N8PN·shift_left(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){
+      return N8PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op);
+    }
+
+    Local N8PN·Status 
+    N8PN·shift_right(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){
+      return N8PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op);
+    }
+
+    Local N8PN·Status 
+    N8PN·arithmetic_shift_right(uint8_t shift_count, N8PN·T *operand, N8PN·T *spill){
+
+      if(shift_count > 7) return N8PN·Status·gt_max_shift_count;
+
+      if(operand == NULL){
+        operand = &N8PN·t[0];
+        N8PN·copy(operand, N8PN·zero);
+      }
+
+      N8PN·T *fill = (operand->d0 & 0x80) ? N8PN·all_one_bit : N8PN·zero;
+      return N8PN·shift_right(shift_count, spill, operand, fill);
+    }
+
+    Local const N8PN·Λ N8PN·λ = {
+
+      .allocate_array = N8PN·allocate_array
+     ,.allocate_array_zero = N8PN·allocate_array_zero
+     ,.deallocate = N8PN·deallocate
+
+     ,.copy = N8PN·copy
+     ,.bit_and = N8PN·bit_and
+     ,.bit_or = N8PN·bit_or
+     ,.bit_complement = N8PN·bit_complement
+     ,.bit_twos_complement = N8PN·bit_twos_complement
+     ,.compare = N8PN·compare
+     ,.lt = N8PN·lt
+     ,.gt = N8PN·gt
+     ,.eq = N8PN·eq
+     ,.eq_zero = N8PN·eq_zero
+     ,.accumulate = N8PN·accumulate
+     ,.add = N8PN·add
+     ,.increment = N8PN·increment
+     ,.subtract = N8PN·subtract
+     ,.multiply = N8PN·multiply
+     ,.divide = N8PN·divide
+     ,.modulus = N8PN·modulus
+     ,.shift_left = N8PN·shift_left
+     ,.shift_right = N8PN·shift_right
+     ,.arithmetic_shift_right = N8PN·arithmetic_shift_right
+
+     ,.access = N8PN·access
+     ,.from_uint32 = N8PN·from_uint32
+    };
+
+  #endif
+
+#endif
diff --git a/tester/cc🖉/environment.h b/tester/cc🖉/environment.h
new file mode 100644 (file)
index 0000000..cdea83c
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef Mpblock·ENVIRONMENT_H
+#define Mpblock·ENVIRONMENT_H
+
+
+#endif
diff --git a/tester/cc🖉/test_N32.cli.c b/tester/cc🖉/test_N32.cli.c
new file mode 100644 (file)
index 0000000..563711f
--- /dev/null
@@ -0,0 +1,364 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <setjmp.h>
+
+// Enable interface section
+#define FACE
+#include "N32.lib.c"
+#undef FACE
+
+// Jump buffer for signal handling
+static sigjmp_buf jump_buffer;
+
+// Signal handler for catching fatal errors
+void signal_handler(int signal){
+  siglongjmp(jump_buffer ,1); // Jump back to test_head on error
+}
+
+// Test function prototypes
+bool test_copy();
+bool test_bitwise_operations();
+bool test_comparisons();
+bool test_arithmetic();
+bool test_shifts();
+
+// Test array (null-terminated)
+typedef bool (*TestFunction)();
+typedef struct{
+  TestFunction function;
+  const char *name;
+}TestEntry;
+
+TestEntry test_list[] = {
+   {test_copy ,"test_copy"}
+  ,{test_bitwise_operations ,"test_bitwise_operations"}
+  ,{test_comparisons ,"test_comparisons"}
+  ,{test_arithmetic ,"test_arithmetic"}
+  ,{test_shifts ,"test_shifts"}
+  ,{NULL ,NULL}  // Null termination
+};
+
+// The test runner
+int test_head(){
+  int pass_count = 0;
+  int fail_count = 0;
+
+  // Set up signal handlers
+  signal(SIGSEGV ,signal_handler);  // Catch segmentation faults
+  signal(SIGFPE ,signal_handler);   // Catch floating point errors
+  signal(SIGABRT ,signal_handler);  // Catch abort() calls
+
+  for(TestEntry *entry = test_list; entry->function != NULL; entry++){
+    if( sigsetjmp(jump_buffer ,1) == 0 ){
+      // Run the test normally
+      if( !entry->function() ){
+        printf("Failed: %s\n" ,entry->name);
+        fail_count++;
+      }else{
+        pass_count++;
+      }
+    }else{
+      // If a signal was caught
+      printf("Failed due to signaling: %s\n" ,entry->name);
+      fail_count++;
+    }
+  }
+
+  printf("Tests passed: %d\n" ,pass_count);
+  printf("Tests failed: %d\n" ,fail_count);
+  return (fail_count == 0) ? 0 : 1;
+}
+
+// Main function
+int main(int argc ,char **argv){
+  return test_head();
+}
+
+//------------------------------------------------------------------------------
+// Test Implementations
+//------------------------------------------------------------------------------
+
+bool test_copy(){
+  // Allocate memory
+  N32·T *array = N32·λ.allocate_array(2 ,NULL);
+  if( !array ) return false;
+
+  // Access elements via access function
+  N32·T *a = N32·λ.access(array ,0);
+  N32·T *b = N32·λ.access(array ,1);
+
+  // Assign value and copy
+  N32·λ.from_uint32(a ,42);
+  N32·λ.copy(b ,a);
+
+  bool success = ( N32·λ.compare(b ,a) == N32·Order_eq );
+  N32·λ.deallocate(array);
+  return success;
+}
+
+bool test_arithmetic(){
+  // Allocate memory
+  N32·T *array = N32·λ.allocate_array(3 ,NULL);
+  if( !array ) return false;
+
+  N32·T *a = N32·λ.access(array ,0);
+  N32·T *b = N32·λ.access(array ,1);
+  N32·T *result = N32·λ.access(array ,2);
+
+  N32·λ.from_uint32(a ,20);
+  N32·λ.from_uint32(b ,22);
+
+  if( N32·λ.add(result ,a ,b) != N32·Status·ok ) return false;
+  if( N32·λ.compare(result ,N32·λ.access(array ,0)) != N32·Order_gt ) return false;
+
+  if( N32·λ.subtract(result ,b ,a) != N32·Status·ok ) return false;
+  if( N32·λ.compare(result ,N32·λ.access(array ,0)) != N32·Order_lt ) return false;
+
+  N32·λ.deallocate(array);
+  return true;
+}
+
+bool test_bitwise_operations(){
+  // Allocate memory
+  N32·T *array = N32·λ.allocate_array(3, NULL);
+  if(!array) return false;
+
+  N32·T *a = N32·λ.access(array, 0);
+  N32·T *b = N32·λ.access(array, 1);
+  N32·T *result = N32·λ.access(array, 2);
+
+  // a = 0x0F0F0F0F, b = 0xF0F0F0F0
+  N32·λ.from_uint32(a, 0x0F0F0F0F);
+  N32·λ.from_uint32(b, 0xF0F0F0F0);
+
+  // bit_and => expect 0x00000000
+  N32·λ.bit_and(result, a, b);
+  N32·λ.from_uint32(a, 0x00000000);
+  if(N32·λ.compare(result, a) != N32·Order_eq){
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  // Reset a to 0x0F0F0F0F for next tests
+  N32·λ.from_uint32(a, 0x0F0F0F0F);
+
+  // bit_or => expect 0xFFFFFFFF
+  N32·λ.bit_or(result, a, b);
+  N32·λ.from_uint32(b, 0xFFFFFFFF);
+  if(N32·λ.compare(result, b) != N32·Order_eq){
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0
+  N32·λ.from_uint32(a, 0x0F0F0F0F);
+  N32·λ.bit_complement(result, a);
+  N32·λ.from_uint32(b, 0xF0F0F0F0);
+  if(N32·λ.compare(result, b) != N32·Order_eq){
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1
+  N32·λ.from_uint32(a, 0x0F0F0F0F);
+  N32·λ.bit_twos_complement(result, a);
+  N32·λ.from_uint32(b, 0xF0F0F0F1);
+  if(N32·λ.compare(result, b) != N32·Order_eq){
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  N32·λ.deallocate(array);
+  return true;
+}
+
+bool test_comparisons(){
+  // Allocate memory
+  N32·T *array = N32·λ.allocate_array(3, NULL);
+  if(!array) return false;
+
+  N32·T *a = N32·λ.access(array, 0);
+  N32·T *b = N32·λ.access(array, 1);
+  N32·T *c = N32·λ.access(array, 2);
+
+  // First set: a=0, b=42, c=42
+  N32·λ.from_uint32(a, 0);
+  N32·λ.from_uint32(b, 42);
+  N32·λ.from_uint32(c, 42);
+
+  // eq_zero(a) => true
+  if(!N32·λ.eq_zero(a)){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // eq_zero(b) => false
+  if(N32·λ.eq_zero(b)){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // eq(b, c) => true
+  if(!N32·λ.eq(b, c)){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // eq(a, b) => false
+  if(N32·λ.eq(a, b)){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // compare(a, b) => N32·Order_lt
+  if(N32·λ.compare(a, b) != N32·Order_lt){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // compare(b, a) => N32·Order_gt
+  if(N32·λ.compare(b, a) != N32·Order_gt){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // compare(b, c) => N32·Order_eq
+  if(N32·λ.compare(b, c) != N32·Order_eq){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // lt(a, b) => true, gt(b, a) => true
+  if(!N32·λ.lt(a, b) || !N32·λ.gt(b, a)){
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  // Second set: a=100, b=50
+  N32·λ.from_uint32(a, 100);
+  N32·λ.from_uint32(b, 50);
+  if(N32·λ.compare(a, b) != N32·Order_gt){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // eq_zero(a) => false
+  if(N32·λ.eq_zero(a)){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  // eq_zero(b) => false
+  if(N32·λ.eq_zero(b)){
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  N32·λ.deallocate(array);
+  return true;
+}
+
+bool test_shifts(){
+  // Allocate memory for operand, fill, spill
+  N32·T *array = N32·λ.allocate_array(3, NULL);
+  if(!array) return false;
+
+  N32·T *operand = N32·λ.access(array, 0);
+  N32·T *fill    = N32·λ.access(array, 1);
+  N32·T *spill   = N32·λ.access(array, 2);
+
+  // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0
+  N32·λ.from_uint32(operand, 1);
+  N32·λ.from_uint32(fill, 0);
+  N32·λ.from_uint32(spill, 0);
+  if(N32·λ.shift_left(4, spill, operand, fill) != N32·Status·ok){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  N32·T *temp = N32·λ.allocate_array(1, NULL);
+  if(!temp){
+    N32·λ.deallocate(array);
+    return false;
+  }
+  N32·λ.from_uint32(temp, 16);
+  if(N32·λ.compare(operand, temp) != N32·Order_eq){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  if(N32·λ.compare(fill, N32·zero) != N32·Order_eq){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  if(N32·λ.compare(spill, N32·zero) != N32·Order_eq){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1
+  N32·λ.from_uint32(operand, 0x80000000);
+  N32·λ.from_uint32(fill, 0);
+  N32·λ.from_uint32(spill, 0);
+  if(N32·λ.shift_left(1, spill, operand, fill) != N32·Status·ok){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  if(!N32·λ.eq_zero(operand)){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  N32·λ.from_uint32(temp, 1);
+  if(N32·λ.compare(spill, temp) != N32·Order_eq){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0
+  N32·λ.from_uint32(operand, 0x80000000);
+  N32·λ.from_uint32(fill, 0);
+  N32·λ.from_uint32(spill, 0);
+  if(N32·λ.shift_right(1, spill, operand, fill) != N32·Status·ok){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  N32·λ.from_uint32(temp, 0x40000000);
+  if(N32·λ.compare(operand, temp) != N32·Order_eq){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  if(!N32·λ.eq_zero(spill)){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0
+  N32·λ.from_uint32(operand, 0x80000000);
+  N32·λ.from_uint32(spill, 0);
+  if(N32·λ.arithmetic_shift_right(1, operand, spill) != N32·Status·ok){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  N32·λ.from_uint32(temp, 0xC0000000);
+  if(N32·λ.compare(operand, temp) != N32·Order_eq){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+  if(!N32·λ.eq_zero(spill)){
+    N32·λ.deallocate(temp);
+    N32·λ.deallocate(array);
+    return false;
+  }
+
+  N32·λ.deallocate(temp);
+  N32·λ.deallocate(array);
+  return true;
+}
+
+
+
+// Include the local section of N32.lib.c for testing
+#define LOCAL
+#include "N32.lib.c"
+#undef LOCAL
diff --git a/tester/cc🖉/test_setup.cli.c b/tester/cc🖉/test_setup.cli.c
new file mode 100644 (file)
index 0000000..f1c6e68
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+
+  A placeholder to see if make etc. is working.
+
+*/
+
+#define IFACE
+#include <stdio.h>
+#include <stdlib.h>
+
+// No need to define IMPLEMENTATION as `main` is one and done.
+
+int main(int argc ,char *argv[] ,char *envp[]){
+  if(argc != 1){
+    fprintf(stderr, "Usage: %s\n", argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  fprintf(stderr, "%s done\n", argv[0]);
+
+  return 0;
+}
diff --git a/tester/machine/.gitignore b/tester/machine/.gitignore
new file mode 100644 (file)
index 0000000..120f485
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!/.gitignore
diff --git a/tester/scratchpad/.gitignore b/tester/scratchpad/.gitignore
new file mode 100644 (file)
index 0000000..120f485
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!/.gitignore
diff --git a/tester/tool🖉/env b/tester/tool🖉/env
new file mode 100644 (file)
index 0000000..355a02c
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+# input guards
+
+  env_must_be="tool_shared/bespoke🖉/env"
+  error_bad_env=false
+  error_not_sourced=false
+  if [ "$ENV" != "$env_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+    error_bad_env=true
+  fi
+  if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
+    echo "$script_afp:: This script must be sourced, not executed."
+    error_not_sourced=true
+  fi
+  if $error_not_sourced; then exit 1; fi
+  if $error_bad_env; then return 1; fi
+
+
+export ROLE=tester
+
+# so we can do the build
+
+export PATH=\
+"$REPO_HOME"/${ROLE}/tool🖉/\
+:"$PATH"
+
+# misc
+
+  # make .githolder and .gitignore visible
+  alias ls="ls -a"
+
+# some feedback to show all went well
+
+  export PROMPT_DECOR="$PROJECT_$ROLE"
+  export ENV=$(script_fp)
+  echo ENV "$ENV"
+  cd "$REPO_HOME/$ROLE"
+
+
+
diff --git a/tester/tool🖉/make b/tester/tool🖉/make
new file mode 100755 (executable)
index 0000000..e0f787f
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+# input guards
+
+  env_must_be="tester/tool🖉/env"
+  if [ "$ENV" != "$env_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+    exit 1
+  fi
+
+set -e
+set -x
+
+cd "$REPO_HOME"/tester || exit 1
+
+/bin/make -f tool🖉/makefile $@
+
+set +x
+echo "$(script_fn) done."
diff --git a/tester/tool🖉/makefile b/tester/tool🖉/makefile
new file mode 100644 (file)
index 0000000..a0da057
--- /dev/null
@@ -0,0 +1,18 @@
+
+
+RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release
+
+include $(RT-INCOMMON)/make/environment_RT_0
+
+CFLAGS+=-Werror -include "$(RT-INCOMMON)/make/RT_0.h"
+LINKFLAGS+= -l$(PROJECT)
+LIBFILE=$(LIBDIR)/lib$(PROJECT).a
+
+include $(RT-INCOMMON)/make/targets
+-include $(DEPFILE)
+
+
+
+
+
+
diff --git a/tester/tool🖉/pull_release b/tester/tool🖉/pull_release
new file mode 100755 (executable)
index 0000000..a083b91
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+# before running this script, gather everything needed for the release on the scratchpad
+
+# input guards
+
+  env_must_be="tester/tool🖉/env"
+  if [ "$ENV" != "$env_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+    exit 1
+  fi
+
+set -e
+set -x
+
+  cd "$REPO_HOME"/tester || exit 1
+
+  if [ ! -d scratchpad ]; then
+    echo "$(script_fp):: no scratchpad directory"
+    exit 1
+  fi
+
+  release_dir=$(release_dir)
+
+  if [ ! -d ${release_dir} ]; then
+    echo "$(script_fp):: no release directory to pull install files from"
+    exit 1
+  fi
+
+
+  cp ${release_dir}/libN.a scratchpad || true
+  cp ${release_dir}/*.lib.c cc || true
+
+set +x
+echo "$(script_fn) done."
+
diff --git a/tester/tool🖉/release_test b/tester/tool🖉/release_test
new file mode 100755 (executable)
index 0000000..3d31406
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+# release test machine code
+
+# input guards
+
+  env_must_be="tester/tool🖉/env"
+  if [ "$ENV" != "$env_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+    exit 1
+  fi
+
+set -e
+set -x
+
+  cd "$REPO_HOME"/tester || exit 1
+
+  if [ ! -d scratchpad ]; then
+    echo "$(script_fp):: no scratchpad directory"
+    exit 1
+  fi
+
+  release_dir=$(release_dir)
+
+  if [ ! -d ${release_dir} ]; then
+    echo "$(script_fp):: no release directory to pull install files from"
+    exit 1
+  fi
+
+  install_file machine/* ${release_dir} "ug+rx"
+
+
+
+
+set +x
+echo "$(script_fn) done."
+
index 01f47a3..f9671cc 100644 (file)
@@ -72,6 +72,44 @@ shopt -s nullglob
 
   export -f script_adp script_fn script_dp script_fp
 
+#--------------------------------------------------------------------------------
+# used by release scripts
+#
+
+  install_file() {
+    if [ "$#" -lt 3 ]; then
+      echo "Usage: install_file <source1> <source2> ... <target_dir> <permissions>"
+      return 1
+    fi
+
+    perms="${@: -1}"         # Last argument is permissions
+    target_dp="${@: -2:1}"   # Second-to-last argument is the target directory
+    sources=("${@:1:$#-2}")  # All other arguments are source files
+
+    if [ ! -d "$target_dp" ]; then
+      echo "Error: Target directory '$target_dp' does not exist."
+      return 1
+    fi
+
+    for source_fp in "${sources[@]}"; do
+      if [ ! -f "$source_fp" ]; then
+        echo "Error: Source file '$source_fp' does not exist."
+        return 1
+      fi
+
+      target_file="$target_dp/$(basename "$source_fp")"
+
+      if ! install -m "$perms" "$source_fp" "$target_file"; then
+        echo "Error: Failed to install $(basename "$source_fp") to $target_dp"
+        return 1
+      else
+        echo "Installed $(basename "$source_fp") to $target_dp with permissions $perms"
+      fi
+    done
+  }
+
+  export -f install_file
+
 # --------------------------------------------------------------------------------
 # closing
 #