--- /dev/null
+/*
+ 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)(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 (*add)(N32·T*, N32·T*, N32·T*);
+ 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·Λ;
+
+extern const N32·Λ N32·λ;
+
+#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·T *(*memory_fault)(Extent) ){
+ N32·T *instance = malloc((extent + 1) * sizeof(N32·T) );
+ if(!instance){
+ return memory_fault ? memory_fault(extent) : NULL;
+ }
+ return instance;
+}
+
+N32·T *N32·alloc_array_zero( Extent extent ,N32·T *(*memory_fault)(Extent) ){
+ 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·alloc_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);
+
+ uint64_t *sum = &accumulator0->d0;
+ uint64_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);
+}
+
+// an interface instance
+
+Local const N32·Λ N32·λ = {
+ .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
+ ,.eq_one = N32·eq_one
+ ,.accumulate = N32·accumulate
+ ,.add = N32·add
+ ,.next = N32·next
+ ,.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
+ ,.allocate_array = N32·allocate_array
+ ,.allocate_array_zero = N32·alloc_array_zero
+ ,.deallocate = N32·deallocate
+ ,.access = N32·access
+ ,.from_uint32 = N32·from_uint32
+};
+
+#endif
+
+#endif
+++ /dev/null
-/*
- N_32 - 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 N_32·DEBUG
-
-#ifndef IFACE
-#define N_32·IMPLEMENTATION
-#define IFACE
-#endif
-
-//--------------------------------------------------------------------------------
-// Interface
-
-#ifndef N_32·IFACE
-#define N_32·IFACE
-
-#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 N_32 N_32;
-
-extern N_32 *N_32·zero;
-extern N_32 *N_32·one;
-extern N_32 *N_32·all_one_bit;
-extern N_32 *N_32·lsb;
-extern N_32 *N_32·msb;
-
-//----------------------------------------
-// Return/Error Status and handlers
-
-typedef enum{
- N_32·Status·ok = 0
- ,N_32·Status·overflow = 1
- ,N_32·Status·accumulator1_overflow = 2
- ,N_32·Status·carry = 3
- ,N_32·Status·borrow = 4
- ,N_32·Status·undefined_divide_by_zero = 5
- ,N_32·Status·undefined_modulus_zero = 6
- ,N_32·Status·gt_max_lsb_index = 7
- ,N_32·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value
- ,N_32·Status·one_word_product = 9
- ,N_32·Status·two_word_product = 10
-} N_32·Status;
-
-typedef enum{
- N_32·Order_lt = -1
- ,N_32·Order_eq = 0
- ,N_32·Order_gt = 1
-} N_32·Order;
-
-typedef N_32 *( *N_32·Allocate_MemoryFault )(Extent);
-
-//----------------------------------------
-// Interface
-
-typedef struct{
- N_32 *( *allocate )(Extent, N_32·Allocate_MemoryFault);
- void ( *deallocate )(N_32 *);
- void ( *copy )(N_32 *, N_32 *);
- void ( *bit_and )(N_32 *, N_32 *, N_32 *);
- void ( *bit_or )(N_32 *, N_32 *, N_32 *);
- void ( *bit_complement )(N_32 *, N_32 *);
- void ( *bit_twos_complement )(N_32 *, N_32 *);
- N_32·Order ( *compare )(N_32 *, N_32 *);
- bool ( *lt )(N_32 *, N_32 *);
- bool ( *gt )(N_32 *, N_32 *);
- bool ( *eq )(N_32 *, N_32 *);
- N_32·Status ( *add )(N_32 *, N_32 *, N_32 *);
- N_32·Status ( *subtract )(N_32 *, N_32 *, N_32 *);
- N_32·Status ( *multiply )(N_32 *, N_32 *, N_32 *, N_32 *);
- N_32·Status ( *divide )(N_32 *, N_32 *, N_32 *, N_32 *);
- void ( *shift_left )(Extent, N_32 *, N_32 *, N_32 *);
- void ( *shift_right )(Extent, N_32 *, N_32 *, N_32 *);
-} N_32·Interface;
-
-extern const N_32·Interface N_32·interface;
-
-#endif
-
-//--------------------------------------------------------------------------------
-// Implementation
-
-#ifdef N_32·IMPLEMENTATION
-
-// this part goes into the library
-#ifndef LOCAL
-
-#include <stdarg.h>
-#include <stdlib.h>
-
-struct N_32{
- Digit d0;
-};
-
-N_32 N_32·constant[4] ={
- {.d0 = 0},
- {.d0 = 1},
- {.d0 = ~(uint32_t)0},
- {.d0 = 1 << 31}
-};
-
-N_32 *N_32·zero = &N_32·constant[0];
-N_32 *N_32·one = &N_32·constant[1];
-N_32 *N_32·all_one_bit = &N_32·constant[2];
-N_32 *N_32·msb = &N_32·constant[3];
-N_32 *N_32·lsb = &N_32·constant[1];
-
-// the allocate an array of N_32
-N_32 *N_32·allocate_array( Extent extent ,N_32 *(*memory_fault)(Extent) ){
- N_32 *instance = malloc((extent + 1) * sizeof(N_32) );
- if(!instance){
- return memory_fault ? memory_fault(extent) : NULL;
- }
- return instance;
-}
-
-N_32 *N_32·alloc_array_zero( Extent extent ,N_32 *(*memory_fault)(Extent) ){
- N_32 *instance = calloc( extent + 1 ,sizeof(N_32) );
- if(!instance){
- return memory_fault ? memory_fault(extent) : NULL;
- }
- return instance;
-}
-
-void N_32·deallocate(N_32 *unencumbered){
- free(unencumbered);
-}
-
-
-#endif
-
-// This part is included after the library user's code
-#ifdef LOCAL
-
-// instance
-
-struct N_32{
- 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 N_32 N_32·t[4]
-
-
-// allocation
-
-extern N_32 *N_32·allocate_array(Extent, N_32·Allocate_MemoryFault);
-extern N_32 *N_32·alloc_array_zero(Extent, N_32·Allocate_MemoryFault);
-extern void N_32·deallocate(N_32 *);
-
-// copy, convenience copy
-
-Local void N_32·copy(N_32 *destination ,N_32 *source){
- if(source == destination) return; // that was easy!
- *destination = *source;
-}
-
-Local void N_32·set_to_zero(N_32 *instance){
- instance->d0 = 0;
-}
-
-Local void N_32·set_to_one(N_32 *instance){
- instance->d0 = 1;
-}
-
-// bit operations
-
-Local void N_32·bit_and(N_32 *result, N_32 *a, N_32 *b){
- result->d0 = a->d0 & b->d0;
-}
-
-// result can be one of the operands
-Local void N_32·bit_or(N_32 *result, N_32 *a, N_32 *b){
- result->d0 = a->d0 | b->d0;
-}
-
-// result can the same as the operand
-Local void N_32·bit_complement(N_32 *result, N_32 *a){
- result->d0 = ~a->d0;
-}
-
-// result can the same as the operand
-Local void N_32·bit_twos_complement(N_32 *result ,N_32 *a){
- result->d0 = ~a->d0 + 1;
-}
-
-// test functions
-
-Local N_32·Order N_32·compare(N_32 *a, N_32 *b){
- if (a->d0 < b->d0) return N_32·Order_lt;
- if (a->d0 > b->d0) return N_32·Order_gt;
- return N_32·Order_eq;
-}
-
-Local bool N_32·lt(N_32 *a ,N_32 *b){
- return a->d0 < b->d0;
-}
-
-Local bool N_32·gt(N_32 *a ,N_32 *b){
- return a->d0 > b->d0;
-}
-
-Local bool N_32·eq(N_32 *a ,N_32 *b){
- return a->d0 == b->d0;
-}
-
-Local bool N_32·eq_zero(N_32 *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 N_32·Status·accumulator1_overflow
-//
-// When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value.
-Local N_32·Status N_32·accumulate(N_32 *accumulator1 ,N_32 *accumulator0 ,...){
-
- va_list args;
- va_start(args ,accumulator0);
-
- uint64_t *sum = &accumulator0->d0;
- uint64_t *carry = 0;
- N_32 *current;
-
- while( (current = va_arg(args ,N_32 *)) ){
- *sum += current->d0;
- if(*sum < current->d0){ // Accumulator1 into carry
- (*carry)++;
- if(*carry == 0){
- va_end(args);
- return N_32·Status·accumulator1_overflow;
- }
- }
- }
- va_end(args);
-
- // wipes out prior value of accumulator1
- accumulator1->d0 = carry;
-
- return N_32·Status·ok;
-}
-
-Local N_32·Status N_32·add(N_32 *sum ,N_32 *a ,N_32 *b){
- uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0;
- sum->d0 = (uint32_t)result;
- return (result >> 32) ? N_32·Status·carry : N_32·Status·ok;
-}
-
-Local bool N_32·increment(N_32 *a){
- a->d0++;
- return a->d0 == 0;
-}
-
-Local N_32·Status N_32·subtract(N_32 *difference ,N_32 *a ,N_32 *b){
- uint64_t diff = (uint64_t)a->d0 - (uint64_t)b->d0;
- difference->d0 = (uint32_t)diff;
- return (diff > a->d0) ? N_32·Status·borrow : N_32·Status·ok;
-}
-
-
-Local N_32·Status N_32·multiply(N_32 *product1 ,N_32 *product0 ,N_32 *a ,N_32 *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 N_32·status·one_word_product;
- return N_32·status·two_word_product;
-}
-
-Local N_32·Status N_32·divide(N_32 *remainder ,N_32 *quotient ,N_32 *a ,N_32 *b){
- if(b->d0 == 0) return N_32·Status·undefined_divide_by_zero;
-
- quotient->d0 = a->d0 / b->d0;
- remainder->d0 = a->d0 - (quotient->d0 * b->d0);
-
- return N_32·Status·ok;
-}
-
-Local N_32·Status N_32·modulus(N_32 *remainder ,N_32 *a ,N_32 *b){
- if(b->d0 == 0) return N_32·Status·undefined_modulus_zero;
- uint32_t quotient = a->d0 / b->d0;
- remainder->d0 = a->d0 - (quotient * b->d0);
- return N_32·Status·ok;
-}
-
-// bit motion
-
-// This is a bit shift, not a word shift. If you have a general shift count, shift words by
-// the div of the shift count, then call this with the modulus 32 of the shift count.
-//
-// If spill and operand or fill are the same value, the result is the spill (for both).
-//
-// `new_lsb_index` aka the `shift_count`
-// shifts a binary number the lsb bit index to as far as 31
-// NULL operand treated as zero
-Local N_32·Status N_32·shift_left
- (
- uint32_t new_lsb_index
- ,N_32 *spill
- ,N_32 *operand
- ,N_32 *fill
- ){
-
- // If the caller doesn't want a result back, we are all done.
- if(operand == NULL && spill == NULL) return N_32·Status·ok;
-
- #ifdef N_32·DEBUG
- if( spill == operand ){
- fprintf(stderr, "N_32·shift_left spill == operand\n");
- }
- #endif
-
- // For the sake of setting spill, we will treat a NULL operand as zero.
- if(operand == NULL){
- operand = &N_32·t[0];
- N_32·copy(operand ,N_32·zero);
- }
-
- // Shifting more than one word breaks our fill/spill model.
- if(new_lsb_index > 31) return N_32·Status·gt_max_lsb_index;
-
- // The given operand is still required after it is modified, so we copy it.
- N_32 *given_operand = &N_32·t[1];
- N_32·copy(given_operand ,operand);
-
- // spill is overwritten with a new value
- operand->d0 = given_operand->d0 << new_lsb_index;
- if(fill != NULL){
- fill->d0 = fill->d0 >> (32 - new_lsb_index);
- N_32·bit_or(operand ,operand ,fill);
- }
- if(spill != NULL){
- spill->d0 = spill->d0 << new_lsb_index;
- spill->d0 += given_operand->d0 >> (32 - new_lsb_index);
- }
- return N_32·Status·ok;
-}
-
-Local N_32·Status N_32·shift_right
- (
- uint32_t msb_index_offset
- ,N_32 *spill
- ,N_32 *operand
- ,N_32 *fill
- ){
-
- // If the caller doesn't want a result back, we are all done.
- if(operand == NULL && spill == NULL) return N_32·Status·ok;
-
- // For the sake of setting spill, we will treat a NULL operand as zero.
- if(operand == NULL){
- operand = &N_32·t[0];
- N_32·copy(operand ,N_32·zero);
- }
-
- // Shifting more than one word breaks our fill/spill model.
- if(msb_index_offset > 31) return N_32·Status·gt_max_lsb_index;
-
- // In theory, fill should not have any bits in common with the shifted operand.
- #ifdef N_32·DEBUG
- if( !N_32·eq_zero(fill->d0 << (32 - msb_index_offset)) ){
- fprintf(stderr, "N_32·shift_right fill value overlaps with shifted operand\n");
- }
- #endif
-
- // The given operand is still required after it is modified, so we copy it.
- N_32 *given_operand = &N_32·t[1];
- N_32·copy(given_operand ,operand);
-
- // spill is overwritten with a new value
- operand->d0 = given_operand->d0 >> msb_index_offset;
- if(fill != NULL){
- fill->d0 = fill->d0 << (32 - msb_index_offset);
- N_32·bit_or(operand ,operand ,fill);
- }
- if(spill != NULL){
- spill->d0 = spill->d0 >> msb_index_offset;
- spill->d0 += given_operand->d0 << (32 - msb_index_offset);
- }
- return N_32·Status·ok;
-}
-
-
-Local void N_32·arithmetic_shift_right(Extent shift, N_32 *operand, N_32 *spill) {
-
- // caller wants us to do nothing, a little strange, but Ok ..
- if (operand == NULL || spill == NULL) return N_32·Status·ok;
-
- // check if we are shifting in ones or zeros
- N_32·bit_and(&N_32·t[0], operand, N_32·msb);
- N_32 *source_pt = N_32·eq_zero(&N_32·t[0]) ? N_32·zero : N_32·all_one_bit;
-
- // uses `t[2]` because shift_right uses `t[0]` and `t[1]`
- N_32·copy(&N_32·t[2], source_pt);
- N_32·shift_right(shift, &N_32·t[2], operand, spill);
-}
-
-// an interface instance
-
-Local const N_32·Interface N_32·interface = {
- .copy = N_32·copy
- ,.bit_and = N_32·bit_and
- ,.bit_or = N_32·bit_or
- ,.bit_complement = N_32·bit_complement
- ,.bit_twos_complement = N_32·bit_twos_complement
- ,.compare = N_32·compare
- ,.lt = N_32·lt
- ,.gt = N_32·gt
- ,.eq = N_32·eq
- ,.eq_zero = N_32·eq_zero
- ,.eq_one = N_32·eq_one
- ,.accumulate = N_32·accumulate
- ,.add = N_32·add
- ,.next = N_32·next
- ,.subtract = N_32·subtract
- ,.multiply = N_32·multiply
- ,.divide = N_32·divide
- ,.modulus = N_32·modulus
- ,.shift_left = N_32·shift_left
- ,.shift_right = N_32·shift_right
- ,.arithmetic_shift_right = N_32·arithmetic_shift_right
- ,.allocate_array = N_32·allocate_array
- ,.allocate_array_zero = N_32·alloc_array_zero
- ,.deallocate = N_32·deallocate
-};
-
-#endif
-
-#endif
#ifndef Mpblock·ENVIRONMENT_H
#define Mpblock·ENVIRONMENT_H
- #define FREE(pt) free(pt); (pt) = NULL;
#endif
--- /dev/null
+#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;
+}
+
+// Include the local section of N32.lib.c for testing
+#define LOCAL
+#include "N32.lib.c"
+#undef LOCAL
+++ /dev/null
-
-#include "environment.h"
-#include <stdio.h>
-#include <setjmp.h>
-#include <signal.h>
-
-#define IFACE
-#include "Natural_32.lib.c"
-
-#define TEST_COUNT 10 // Adjust as needed
-
-jmp_buf test_env;
-const char *current_test = NULL;
-
-void signal_handler(int sig){
- printf("Failed due to Exception: %s (Signal %d)\n", current_test, sig);
- longjmp(test_env, 1);
-}
-
-int main(void){
- bool test_results[TEST_COUNT] = {false};
- const char *test_names[TEST_COUNT] = {
- "Addition",
- "Subtraction",
- "Multiplication",
- "Division",
- "Modulus",
- "Shift Left",
- "Shift Right",
- "Comparison",
- "Complement",
- "Two's Complement"
- };
-
- int pass_count = 0, fail_count = 0;
- bool *test_ptr = test_results;
- const char **name_ptr = test_names;
-
- // Install signal handler
- signal(SIGFPE, signal_handler);
- signal(SIGSEGV, signal_handler);
- signal(SIGABRT, signal_handler);
-
- Natural_32 a, b, result, overflow;
- Natural_32·set_to_zero(&a);
- Natural_32·set_to_one(&b);
-
- // Macro to run tests with proper failure messaging
- #define RUN_TEST(expr) \
- current_test = *name_ptr; \
- if(setjmp(test_env) == 0){ \
- if(expr){ \
- *test_ptr++ = true; \
- pass_count++; \
- } else { \
- printf("Failed due to Bad Return Value: %s\n", *name_ptr); \
- *test_ptr++ = false; \
- fail_count++; \
- } \
- } else { \
- *test_ptr++ = false; \
- fail_count++; \
- } \
- name_ptr++;
-
- RUN_TEST(Natural_32·add(&result, &a, &b) == Natural_32·Status·ok && result.d0 == 1);
- RUN_TEST(Natural_32·subtract(&result, &b, &a) == Natural_32·Status·ok && result.d0 == 1);
- RUN_TEST(Natural_32·multiply(&overflow, &result, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0);
- RUN_TEST(Natural_32·divide(&result, &overflow, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0);
- RUN_TEST(Natural_32·modulus(&result, &b, &b) == Natural_32·Status·ok && result.d0 == 0);
-
- Natural_32·shift_left(1, &overflow, &result, &b);
- RUN_TEST(result.d0 == 2 && overflow.d0 == 0);
-
- Natural_32·shift_right(1, &b, &result, &overflow);
- RUN_TEST(result.d0 == 0 && overflow.d0 == 1);
-
- RUN_TEST(Natural_32·compare(&a, &b) == Natural_32·Order·lt);
-
- Natural_32·complement(&result, &a);
- RUN_TEST(result.d0 == ~0);
-
- Natural_32·twos_complement(&result, &b);
- RUN_TEST(result.d0 == (uint32_t)(-1));
-
- printf("Pass: %d, Fail: %d\n", pass_count, fail_count);
- return fail_count > 0 ? 1 : 0;
-}
--- /dev/null
+#include <stdio.h>
+#include <stdbool.h>
+#include "N_32.lib.h" // Include the module under test
+
+// 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;
+
+ for (TestEntry *entry = test_list; entry->function != NULL; entry++) {
+ if (!entry->function()) {
+ printf("Failed: %s\n", entry->name);
+ fail_count++;
+ } else {
+ pass_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() {
+ N_32 a = { .d0 = 42 };
+ N_32 b;
+ N_32·copy(&b, &a);
+ return b.d0 == 42;
+}
+
+bool test_bitwise_operations() {
+ N_32 a = { .d0 = 0b101010 };
+ N_32 b = { .d0 = 0b010101 };
+ N_32 result;
+
+ N_32·bit_and(&result, &a, &b);
+ if (result.d0 != 0b000000) return false;
+
+ N_32·bit_or(&result, &a, &b);
+ if (result.d0 != 0b111111) return false;
+
+ N_32·bit_complement(&result, &a);
+ if (result.d0 != ~0b101010) return false;
+
+ return true;
+}
+
+bool test_comparisons() {
+ N_32 a = { .d0 = 42 };
+ N_32 b = { .d0 = 42 };
+ N_32 c = { .d0 = 24 };
+
+ if (!N_32·eq(&a, &b)) return false;
+ if (N_32·eq(&a, &c)) return false;
+ if (!N_32·lt(&c, &a)) return false;
+ if (!N_32·gt(&a, &c)) return false;
+
+ return true;
+}
+
+bool test_arithmetic() {
+ N_32 a = { .d0 = 20 };
+ N_32 b = { .d0 = 22 };
+ N_32 result;
+
+ if (N_32·add(&result, &a, &b) != N_32·Status·ok) return false;
+ if (result.d0 != 42) return false;
+
+ if (N_32·subtract(&result, &b, &a) != N_32·Status·ok) return false;
+ if (result.d0 != 2) return false;
+
+ return true;
+}
+
+bool test_shifts() {
+ N_32 value = { .d0 = 1 };
+ N_32 spill;
+
+ if (N_32·shift_left(1, &spill, &value, NULL) != N_32·Status·ok) return false;
+ if (value.d0 != 2) return false;
+
+ if (N_32·shift_right(1, &spill, &value, NULL) != N_32·Status·ok) return false;
+ if (value.d0 != 1) return false;
+
+ return true;
+}
--- /dev/null
+
+#include "environment.h"
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+
+#define IFACE
+#include "Natural_32.lib.c"
+
+#define TEST_COUNT 10 // Adjust as needed
+
+jmp_buf test_env;
+const char *current_test = NULL;
+
+void signal_handler(int sig){
+ printf("Failed due to Exception: %s (Signal %d)\n", current_test, sig);
+ longjmp(test_env, 1);
+}
+
+int main(void){
+ bool test_results[TEST_COUNT] = {false};
+ const char *test_names[TEST_COUNT] = {
+ "Addition",
+ "Subtraction",
+ "Multiplication",
+ "Division",
+ "Modulus",
+ "Shift Left",
+ "Shift Right",
+ "Comparison",
+ "Complement",
+ "Two's Complement"
+ };
+
+ int pass_count = 0, fail_count = 0;
+ bool *test_ptr = test_results;
+ const char **name_ptr = test_names;
+
+ // Install signal handler
+ signal(SIGFPE, signal_handler);
+ signal(SIGSEGV, signal_handler);
+ signal(SIGABRT, signal_handler);
+
+ Natural_32 a, b, result, overflow;
+ Natural_32·set_to_zero(&a);
+ Natural_32·set_to_one(&b);
+
+ // Macro to run tests with proper failure messaging
+ #define RUN_TEST(expr) \
+ current_test = *name_ptr; \
+ if(setjmp(test_env) == 0){ \
+ if(expr){ \
+ *test_ptr++ = true; \
+ pass_count++; \
+ } else { \
+ printf("Failed due to Bad Return Value: %s\n", *name_ptr); \
+ *test_ptr++ = false; \
+ fail_count++; \
+ } \
+ } else { \
+ *test_ptr++ = false; \
+ fail_count++; \
+ } \
+ name_ptr++;
+
+ RUN_TEST(Natural_32·add(&result, &a, &b) == Natural_32·Status·ok && result.d0 == 1);
+ RUN_TEST(Natural_32·subtract(&result, &b, &a) == Natural_32·Status·ok && result.d0 == 1);
+ RUN_TEST(Natural_32·multiply(&overflow, &result, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0);
+ RUN_TEST(Natural_32·divide(&result, &overflow, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0);
+ RUN_TEST(Natural_32·modulus(&result, &b, &b) == Natural_32·Status·ok && result.d0 == 0);
+
+ Natural_32·shift_left(1, &overflow, &result, &b);
+ RUN_TEST(result.d0 == 2 && overflow.d0 == 0);
+
+ Natural_32·shift_right(1, &b, &result, &overflow);
+ RUN_TEST(result.d0 == 0 && overflow.d0 == 1);
+
+ RUN_TEST(Natural_32·compare(&a, &b) == Natural_32·Order·lt);
+
+ Natural_32·complement(&result, &a);
+ RUN_TEST(result.d0 == ~0);
+
+ Natural_32·twos_complement(&result, &b);
+ RUN_TEST(result.d0 == (uint32_t)(-1));
+
+ printf("Pass: %d, Fail: %d\n", pass_count, fail_count);
+ return fail_count > 0 ? 1 : 0;
+}
--- /dev/null
+✅ Benefits of the Approach
+Prevents Header/Implementation Mismatch
+
+With separate .h and .c files, it's easy for a developer to update one but forget the other.
+Your #define IFACE / #define LOCAL approach guarantees the interface and implementation always match.
+Improves Code Discovery
+
+Everything relevant to N_32 is in one place, avoiding the “where is this function actually defined?” problem.
+Easier for new programmers to understand a module without hunting through multiple files.
+Reduces Compilation Dependencies
+
+Traditional headers require careful include guards (#ifndef, #define, #endif), and changes to a .h file often trigger unnecessary recompilations across the whole project.
+Here, only the interface section is parsed where needed without polluting translation units.
+Encapsulates Local Code Cleanly
+
+The LOCAL section is truly private—functions that should not be exported remain invisible to the rest of the program.
+This avoids accidental linking to private helper functions.
+Better Optimizations
+
+The optimizer sees everything within a single .c file.
+It inlines functions, eliminates redundant code, and avoids unnecessary function calls more effectively than in a traditional header+implementation split.
+This is especially useful for compiler-assisted optimizations like constant propagation and dead code elimination.
+Encourages Reusable Programs
+
+Your philosophy of keeping main() only as an argument parser & function caller means that:
+Every program can be called as a function from another program.
+Testing frameworks and other programs can reuse code easily without needing to fork process calls.
+🧐 Any Downsides?
+May be unfamiliar to some developers
+
+Most C programmers expect .h + .c files.
+However, once they understand why this works, they'll likely appreciate the clarity.
+Can’t precompile interface headers (.h.gch)
+
+Some build systems optimize C++ headers with precompiled headers (PCH), but in C, this is less of an issue.
+Requires Careful #define Handling
+
+If a programmer forgets to #define LOCAL before including the file for a .cli.c, tests might silently lack static functions.
+A well-placed #error directive (#ifndef LOCAL) could help catch this early.
+🚀 Overall Verdict
+Your approach is engineered for correctness, clarity, and optimization.
+It reduces mistakes, eliminates unnecessary indirections, and streamlines testing & debugging.
+
+Would I use it? Absolutely.
+Would I teach it? Yes, but with an explanation.
+Would I want a make-based project full of fragmented .h files again? Not after this. 😆
--- /dev/null
+* Sectioned Single-File Format
+ The sectioned file format provides a structured way to define a library,
+ keeping all relevant code in a single file while ensuring proper separation
+ between interface, implementation, and static definitions.
+
+** Structure
+ The source file is divided into three sections:
+
+ - *Interface*: Enabled by defining `IFACE` before including the file.
+ - *Implementation*: Enabled when neither `IFACE` nor `LOCAL` is defined.
+ - *Local (Static) Implementation*: Enabled by defining `LOCAL` before including the file.
+
+** Benefits
+ - **Avoids Split Headers and Source Files**: Eliminates mismatches between `.h` and `.c` files.
+ - **Improves Compiler Optimization**: The compiler has full visibility of static functions.
+ - **Reduces File Clutter**: A single source file contains everything.
+ - **Ensures Correct Compilation**: The build system automatically compiles the correct sections.
+
+** Usage
+ - To include the interface in a `.cli.c` file:
+
+ #+begin_src c
+ #define IFACE
+ #include "module.lib.c"
+ #undef IFACE
+ #+end_src
+
+ - To include the local static implementation:
+
+ #+begin_src c
+ #define LOCAL
+ #include "module.lib.c"
+ #+end_src
+
+ - The `.lib.c` file is compiled into the library separately.
--- /dev/null
+* Sectioned Single-File Format
+
+ The sectioned file format provides a structured way to define a library,
+ keeping all relevant code in a single file while ensuring proper separation
+ between interface, implementation, and static definitions.
+
+
+** Structure
+ The source file is divided into three sections:
+
+ - *Interface*: Enabled by defining `IFACE` before including the file.
+ - *Implementation*: Enabled when neither `IFACE` nor `LOCAL` is defined.
+ - *Local (Static) Implementation*: Enabled by defining `LOCAL` before including the file.
+
+** Benefits
+ - **Avoids Split Headers and Source Files**: Eliminates mismatches between `.h` and `.c` files.
+ - **Improves Compiler Optimization**: The compiler has full visibility of static functions.
+ - **Reduces File Clutter**: A single source file contains everything.
+ - **Ensures Correct Compilation**: The build system automatically compiles the correct sections.
+
+** Usage
+ - To include the interface in a `.cli.c` file:
+
+ #+begin_src c
+ #define IFACE
+ #include "module.lib.c"
+ #undef IFACE
+ #+end_src
+
+ - To include the local static implementation:
+
+ #+begin_src c
+ #define LOCAL
+ #include "module.lib.c"
+ #+end_src
+
+ - The `.lib.c` file is compiled into the library separately.
--- /dev/null
+#include <stdio.h>
+
+// Define interface and instance types
+typedef struct {
+ void (*print_value)(int);
+} N32·Λ; // Interface type
+
+typedef struct {
+ int value;
+} N32·μ; // Instance type
+
+// Function implementation for the interface
+void print_value_function(int value) {
+ printf("Value: %d\n", value);
+}
+
+// Default interface instance
+const N32·Λ N32·λ = {
+ .print_value = print_value_function
+};
+
+int main() {
+ // Create an instance
+ N32·μ instance = { 99 };
+
+ // Call function via interface
+ printf("Calling via interface: ");
+ N32·λ.print_value(instance.value);
+
+ return 0;
+}
--- /dev/null
+* Using the N_32 Library
+
+ This document describes how to build, use, and test the N_32 library module.
+
+
+** 1. Overview
+ The `N_32` library provides a 32-bit natural number type with basic arithmetic,
+ bitwise, and shifting operations. It follows the **single-source file**
+ approach, where `N_32.lib.c` contains both interface and implementation.
+
+** 2. Building the Library
+
+ The library is compiled using the shared `make` infrastructure.
+
+ #+begin_src sh
+ make library
+ #+end_src
+
+ This will:
+ - Compile `N_32.lib.c` into an object file.
+ - Archive it into `libN.a` in `scratchpad/`.
+
+** 3. Using the Library in a Project
+ - Include `N_32.lib.c` directly in sources by defining `FACE`:
+ #+begin_src c
+ #define FACE
+ #include "N_32.lib.c"
+ #undef FACE
+ #+end_src
+ - Link against `libN.a` when compiling executables.
+
+** 4. Running Tests
+ The `test_N_32.cli.c` file provides unit tests.
+
+ - Build the test executable:
+ #+begin_src sh
+ make cli
+ #+end_src
+ - Run the test:
+ #+begin_src sh
+ ./tester/test_N_32
+ #+end_src
+ - The test system reports pass/fail counts:
+ #+begin_example
+ Passed: 25, Failed: 0
+ #+end_example
+
+** 5. Understanding the Sectioned File Approach
+ - `N_32.lib.c` contains both the interface and implementation.
+ - It is included twice:
+ 1. **Interface Section (`FACE`)**: Provides declarations.
+ 2. **Local Section (`LOCAL`)**: Provides static/internal functions.
+
+ - This method reduces duplication, avoids header mismatches, and enables
+ the optimizer to work on `LOCAL` functions effectively.
+
+** 6. Makefile Integration
+ The shared `make` system automates building and linking:
+ - `make library` → Builds `libN.a`.
+ - `make cli` → Builds test executables.
+ - `make dependency` → Generates dependency files.
+ - `make clean` → Removes intermediate files.
+
+ Custom projects can include the library with:
+ #+begin_src makefile
+ LIBS += -L$(LIBDIR) -lN
+ CFLAGS += -I$(SRCDIR)
+ #+end_src
+
+** 7. Best Practices
+ - Run `make dependency` to ensure dependencies are up to date.
+ - Use the test suite to validate changes before release.
+
--- /dev/null
+#+TITLE: Memory and Function Dictionaries
+#+AUTHOR: Thomas
+
+* Memory
+
+A *base-relative memory map* is a dictionary that associates symbol names with offsets from a base address. A C ~struct typedef~ is an example means for declaring a base-relative memory map. A base-relative memory map has a length associated with it.
+
+Another term for a *base-relative memory map* is *memory format*. A defined memory format can be bound to a name. The names are required to be distinct, though the formats bound to the names need not be.
+
+An *instance* of <X>, where <X> is the name of a memory format, is a region of memory that has been bound to memory format <X>.
+
+The *type* of an instance is the name of its memory format.
+
+* Pointer
+
+A *pointer* is a memory address that has been bound to a memory format. This technique is used to assure that writes to the memory address conform to the bound memory format. This helps programs to respect the bounds of memory allocations.
+
+The *type* of a pointer is the name of the memory format it has been bound to.
+
+* Function Pointer
+
+The address of a function can be bound to a name and an array of memory formats,
+one for each argument and the return value.
+
+The *type* of a function is defined by its name and its array of memory format names.
+
+The type of a function can be looked up from the function's name.
+
+* Function Dictionary
+
+A *function dictionary* is a list of function names and addresses, keyed by function names.
+
+A *function dictionary template* is a collection of function types associated with a specific memory format.
+
+A *function dictionary instance* is a collection of function implementations that conform to a function dictionary template.
+
+* Object
+
+If the potentially many instances of a given memory format are operated on exclusively by a closed set of functions, these functions can be collected into a dictionary called the memory format's *interface*.
+
+Conversely, there is no conventional name for an instance of memory that is manipulated by only a closed set of functions. In TTCA, the term *tableau* was introduced for such memory. (A *tableau* is a small chalkboard that was once used by students and could be erased and rewritten.)
+
+Another term that could be used for such memory is *taishou* (対象), meaning "subject" or "target" in Japanese.
+
+* More about Tableau (Taishou)
+
+In the case where an instance is exclusively operated on by a closed function dictionary,
+it can be referred to as a *tableau* (or *taishou* 対象). A *tableau* is memory that is
+subject to modification only through the functions of its function dictionary.
+
+This term avoids the ambiguity of *instance*, which is often used generically in other
+contexts. The word *tableau* refers to a reusable writing surface, much like the small
+chalkboards used by students in past centuries. The alternative term *taishou* 対象
+literally means *the subject of attention*, which closely aligns with its role in programming.
+
+#+BEGIN_SRC c
+// Example: Function Dictionary and Tableau
+typedef struct {
+ uint32_t value;
+} N32·T; // The tableau type (taishou type)
+
+typedef struct {
+ void (*copy)(N32·T *dst, const N32·T *src);
+ void (*increment)(N32·T *t);
+ void (*print)(const N32·T *t);
+} N32·Λ; // The function dictionary
+
+void N32·copy(N32·T *dst, const N32·T *src) { dst->value = src->value; }
+void N32·increment(N32·T *t) { t->value++; }
+void N32·print(const N32·T *t) { printf("Value: %u\n", t->value); }
+
+// Function dictionary instance
+const N32·Lambda N32·λ = { .copy = N32·copy, .increment = N32·increment, .print = N32·print };
+
+// Usage example
+N32·T my_number = { .value = 10 }; // creating a tableau
+N32·λ.increment(&my_number);
+N32·λ.print(&my_number); // Output: Value: 11
+#+END_SRC
+
+(Note, this is a contrived example, not legal usage of the N library. I should
+probably update it.)
+
+* Terminology Considerations
+
+The use of the word *type* in this document aligns with C’s conventions. However, other
+programming paradigms, such as those in C++ and Java, may define *types* differently.
+For example, C++ allows types to include behavior (methods), while C’s types only
+define memory structure.
+
+---
+
+**Summary of Key Terms:**
+- *Memory Format*: A named layout of memory.
+- *Instance*: A memory region adhering to a specific format.
+- *Pointer*: A memory address bound to a memory format.
+- *Function Dictionary*: A set of functions associated with a memory format.
+- *Tableau/Taishou*: A memory instance operated on exclusively by a function dictionary.
+- *Function Dictionary Template*: A function dictionary where function types replace function implementations.
+
+
+A *base-relative memory map* is a dictionary that associates symbol names with offsets
+from a base address. A C ~struct typedef~ is an example means for declaring a
+base-relative memory map. A base-relative memory map has a length associated with it.
+
+Another term for a *base-relative memory map* is *memory format*. A
+defined memory format can be bound to a name. The names are required
+to be distinct, though the formats bound to the names need not be.
+
+An *instance* of <X>, where <X> is the name of a memory format, is a region
+of memory that has been bound to memory format <X>.
+
+The *type* of an instance is the name of its memory format.