From 15a6cfda7e974b669d82782a68ed070d1a8d3270 Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Fri, 14 Feb 2025 06:30:20 +0000 Subject: [PATCH] N32 tests pass, addition of N16 and N8 --- developer/amd64/test_N32 | Bin 0 -> 23072 bytes developer/amd64/test_setup | Bin 0 -> 16672 bytes "developer/cc\360\237\226\211/N16.lib.c" | 433 ++++++++++ "developer/cc\360\237\226\211/N32.lib.c" | 749 +++++++++--------- "developer/cc\360\237\226\211/N8.lib.c" | 433 ++++++++++ "developer/cc\360\237\226\211/test_N32.cli.c" | 239 ++++++ .../Approach_to_headers.txt" | 46 -- .../SectionedFileFormat.org" | 50 ++ 8 files changed, 1529 insertions(+), 421 deletions(-) create mode 100755 developer/amd64/test_N32 create mode 100755 developer/amd64/test_setup create mode 100644 "developer/cc\360\237\226\211/N16.lib.c" create mode 100644 "developer/cc\360\237\226\211/N8.lib.c" delete mode 100644 "developer/document\360\237\226\211/Approach_to_headers.txt" diff --git a/developer/amd64/test_N32 b/developer/amd64/test_N32 new file mode 100755 index 0000000000000000000000000000000000000000..36150b2e41718cfad8227435ebee45b8ced392a1 GIT binary patch literal 23072 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 AF8}}l literal 0 HcmV?d00001 diff --git a/developer/amd64/test_setup b/developer/amd64/test_setup new file mode 100755 index 0000000000000000000000000000000000000000..d5834b8f974884aa43fad2f6c1a9e607e33fa4f4 GIT binary patch literal 16672 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 QumAg 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 N16·DEBUG + +#ifndef FACE +#define N16·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N16·FACE +#define N16·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint16_t Extent; + typedef uint16_t Digit; + + typedef struct N16·T N16·T; + + extern N16·T *N16·zero; + extern N16·T *N16·one; + extern N16·T *N16·all_one_bit; + extern N16·T *N16·lsb; + extern N16·T *N16·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N16·Status·ok = 0 + ,N16·Status·overflow = 1 + ,N16·Status·accumulator1_overflow = 2 + ,N16·Status·carry = 3 + ,N16·Status·borrow = 4 + ,N16·Status·undefined_divide_by_zero = 5 + ,N16·Status·undefined_modulus_zero = 6 + ,N16·Status·gt_max_shift_count = 7 + ,N16·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N16·Status·one_word_product = 9 + ,N16·Status·two_word_product = 10 + } N16·Status; + + typedef enum{ + N16·Order_lt = -1 + ,N16·Order_eq = 0 + ,N16·Order_gt = 1 + } N16·Order; + + typedef N16·T *( *N16·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N16·T *(*allocate_array_zero)(Extent, N16·Allocate_MemoryFault); + N16·T *(*allocate_array)(Extent, N16·Allocate_MemoryFault); + void (*deallocate)(N16·T*); + + void (*copy)(N16·T*, N16·T*); + void (*bit_and)(N16·T*, N16·T*, N16·T*); + void (*bit_or)(N16·T*, N16·T*, N16·T*); + void (*bit_complement)(N16·T*, N16·T*); + void (*bit_twos_complement)(N16·T*, N16·T*); + N16·Order (*compare)(N16·T*, N16·T*); + bool (*lt)(N16·T*, N16·T*); + bool (*gt)(N16·T*, N16·T*); + bool (*eq)(N16·T*, N16·T*); + bool (*eq_zero)(N16·T*); + N16·Status (*accumulate)(N16·T *accumulator1 ,N16·T *accumulator0 ,...); + N16·Status (*add)(N16·T*, N16·T*, N16·T*); + bool (*increment)(N16·T *a); + N16·Status (*subtract)(N16·T*, N16·T*, N16·T*); + N16·Status (*multiply)(N16·T*, N16·T*, N16·T*, N16·T*); + N16·Status (*divide)(N16·T*, N16·T*, N16·T*, N16·T*); + N16·Status (*modulus)(N16·T*, N16·T*, N16·T*); + N16·Status (*shift_left)(Extent, N16·T*, N16·T*, N16·T*); + N16·Status (*shift_right)(Extent, N16·T*, N16·T*, N16·T*); + N16·Status (*arithmetic_shift_right)(Extent, N16·T*, N16·T*); + + N16·T* (*access)(N16·T*, Extent); + void (*from_uint32)(N16·T *destination ,uint32_t value); + } N16·Λ; + + Local const N16·Λ N16·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N16·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N16·T{ + Digit d0; + }; + + N16·T N16·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint16_t)0}, + {.d0 = 1 << 15} + }; + + N16·T *N16·zero = &N16·constant[0]; + N16·T *N16·one = &N16·constant[1]; + N16·T *N16·all_one_bit = &N16·constant[2]; + N16·T *N16·msb = &N16·constant[3]; + N16·T *N16·lsb = &N16·constant[1]; + + // the allocate an array of N16 + N16·T *N16·allocate_array(Extent extent ,N16·Allocate_MemoryFault memory_fault){ + N16·T *instance = malloc((extent + 1) * sizeof(N16·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N16·T *N16·allocate_array_zero(Extent extent ,N16·Allocate_MemoryFault memory_fault){ + N16·T *instance = calloc(extent + 1, sizeof(N16·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N16·deallocate(N16·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N16·T{ + Digit d0; + }; + + // temporary variables + Local N16·T N16·t[4]; + + // allocation + + extern N16·T *N16·allocate_array(Extent, N16·Allocate_MemoryFault); + extern N16·T *N16·allocate_array_zero(Extent, N16·Allocate_MemoryFault); + extern void N16·deallocate(N16·T *); + + // so the user can access numbers in an array allocation + Local N16·T* N16·access(N16·T *array ,Extent index){ + return &array[index]; + } + + Local void N16·from_uint32(N16·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint16_t)(value & 0xFFFF); + } + + // copy, convenience copy + + Local void N16·copy(N16·T *destination ,N16·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N16·set_to_zero(N16·T *instance){ + instance->d0 = 0; + } + + Local void N16·set_to_one(N16·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N16·bit_and(N16·T *result, N16·T *a, N16·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N16·bit_or(N16·T *result, N16·T *a, N16·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N16·bit_complement(N16·T *result, N16·T *a){ + result->d0 = ~a->d0; + } + + Local void N16·bit_twos_complement(N16·T *result ,N16·T *a){ + result->d0 = (uint16_t)(~a->d0 + 1); + } + + // test functions + + Local N16·Order N16·compare(N16·T *a, N16·T *b){ + if(a->d0 < b->d0) return N16·Order_lt; + if(a->d0 > b->d0) return N16·Order_gt; + return N16·Order_eq; + } + + Local bool N16·lt(N16·T *a ,N16·T *b){ + return a->d0 < b->d0; + } + + Local bool N16·gt(N16·T *a ,N16·T *b){ + return a->d0 > b->d0; + } + + Local bool N16·eq(N16·T *a ,N16·T *b){ + return a->d0 == b->d0; + } + + Local bool N16·eq_zero(N16·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N16·Status N16·accumulate(N16·T *accumulator1 ,N16·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N16·T *current; + + while( (current = va_arg(args ,N16·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N16·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint16_t)carry; + return N16·Status·ok; + } + + Local N16·Status N16·add(N16·T *sum ,N16·T *a ,N16·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint16_t)(result & 0xFFFF); + return (result >> 16) ? N16·Status·carry : N16·Status·ok; + } + + Local bool N16·increment(N16·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N16·Status N16·subtract(N16·T *difference ,N16·T *a ,N16·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint16_t)(diff & 0xFFFF); + return (diff > a->d0) ? N16·Status·borrow : N16·Status·ok; + } + + Local N16·Status N16·multiply(N16·T *product1 ,N16·T *product0 ,N16·T *a ,N16·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 N16·Status·one_word_product; + return N16·Status·two_word_product; + } + + Local N16·Status N16·divide(N16·T *remainder ,N16·T *quotient ,N16·T *a ,N16·T *b){ + if(b->d0 == 0) return N16·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 N16·Status·ok; + } + + Local N16·Status N16·modulus(N16·T *remainder ,N16·T *a ,N16·T *b){ + if(b->d0 == 0) return N16·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 N16·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 N16·Status N16·shift + ( + uint16_t shift_count + ,N16·T *spill + ,N16·T *operand + ,N16·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N16·Status·ok; + + if(operand == NULL){ + operand = &N16·t[0]; + N16·copy(operand, N16·zero); + } + + if(shift_count > 15) return N16·Status·gt_max_shift_count; + + N16·T *given_operand = &N16·t[1]; + N16·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)); + N16·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 N16·Status·ok; + } + + Local N16·Status + N16·shift_left(uint16_t shift_count, N16·T *spill, N16·T *operand, N16·T *fill){ + return N16·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N16·Status + N16·shift_right(uint16_t shift_count, N16·T *spill, N16·T *operand, N16·T *fill){ + return N16·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N16·Status + N16·arithmetic_shift_right(uint16_t shift_count, N16·T *operand, N16·T *spill){ + + if(shift_count > 15) return N16·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N16·t[0]; + N16·copy(operand, N16·zero); + } + + N16·T *fill = (operand->d0 & 0x8000) ? N16·all_one_bit : N16·zero; + return N16·shift_right(shift_count, spill, operand, fill); + } + + Local const N16·Λ N16·λ = { + + .allocate_array = N16·allocate_array + ,.allocate_array_zero = N16·allocate_array_zero + ,.deallocate = N16·deallocate + + ,.copy = N16·copy + ,.bit_and = N16·bit_and + ,.bit_or = N16·bit_or + ,.bit_complement = N16·bit_complement + ,.bit_twos_complement = N16·bit_twos_complement + ,.compare = N16·compare + ,.lt = N16·lt + ,.gt = N16·gt + ,.eq = N16·eq + ,.eq_zero = N16·eq_zero + ,.accumulate = N16·accumulate + ,.add = N16·add + ,.increment = N16·increment + ,.subtract = N16·subtract + ,.multiply = N16·multiply + ,.divide = N16·divide + ,.modulus = N16·modulus + ,.shift_left = N16·shift_left + ,.shift_right = N16·shift_right + ,.arithmetic_shift_right = N16·arithmetic_shift_right + + ,.access = N16·access + ,.from_uint32 = N16·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N32.lib.c" "b/developer/cc\360\237\226\211/N32.lib.c" index ff69120..fba3c21 100644 --- "a/developer/cc\360\237\226\211/N32.lib.c" +++ "b/developer/cc\360\237\226\211/N32.lib.c" @@ -36,85 +36,85 @@ #ifndef N32·FACE #define N32·FACE -#include -#include -#include -#include - -//---------------------------------------- -// 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 + #include + #include + #include + #include + + //---------------------------------------- + // 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 @@ -123,336 +123,335 @@ Local const N32·Λ N32·λ; // initialized in the LOCAL section #ifdef N32·IMPLEMENTATION -// this part goes into the library -#ifndef LOCAL - -#include -#include - -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); -} + // this part goes into the library + #ifndef LOCAL + + #include + #include + + 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; + } -#endif + 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; + } -// This part is included after the library user's code -#ifdef LOCAL + // bit operations -// instance + 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; + } -struct N32·T{ - Digit d0; -}; + // test functions -// 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·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 N32·T N32·t[4]; + 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; -// allocation + return N32·Status·ok; + } -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 *); + 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; + } -// so the user can access numbers in an array allocation -Local N32·T* N32·access(N32·T *array ,Extent index){ - return &array[index]; -} + 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 void N32·from_uint32(N32·T *destination ,uint32_t value){ - if(destination == NULL) return; - destination->d0 = value; -} -// copy, convenience copy + 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); -Local void N32·copy(N32·T *destination ,N32·T *source){ - if(source == destination) return; // that was easy! - *destination = *source; -} + if(product1->d0 == 0) return N32·Status·one_word_product; + return N32·Status·two_word_product; + } -Local void N32·set_to_zero(N32·T *instance){ - instance->d0 = 0; -} + 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; -Local void N32·set_to_one(N32·T *instance){ - instance->d0 = 1; -} + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); -// bit operations + return N32·Status·ok; + } -Local void N32·bit_and(N32·T *result, N32·T *a, N32·T *b){ - result->d0 = a->d0 & b->d0; -} + 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; + } -// 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; -} + // bit motion -// result can the same as the operand -Local void N32·bit_complement(N32·T *result, N32·T *a){ - result->d0 = ~a->d0; -} + typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); -// result can the same as the operand -Local void N32·bit_twos_complement(N32·T *result ,N32·T *a){ - result->d0 = ~a->d0 + 1; -} + Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ + return value << amount; + } -// test functions + Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ + return value >> amount; + } -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; -} + // 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); + } -Local bool N32·lt(N32·T *a ,N32·T *b){ - return a->d0 < b->d0; -} + // Shifting more than one word breaks our fill/spill model. + if(shift_count > 31) return N32·Status·gt_max_shift_count; -Local bool N32·gt(N32·T *a ,N32·T *b){ - return a->d0 > b->d0; -} + // 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); -Local bool N32·eq(N32·T *a ,N32·T *b){ - return a->d0 == b->d0; -} + // 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)); + } -Local bool N32·eq_zero(N32·T *a){ - return a->d0 == 0; -} + 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); + } -// arithmetic operations + 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); + } -// 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 ,...){ + Local N32·Status + N32·arithmetic_shift_right(uint32_t shift_count, N32·T *operand, N32·T *spill){ - va_list args; - va_start(args ,accumulator0); - uint32_t sum = accumulator0->d0; - uint32_t carry = 0; - N32·T *current; + // Guard against excessive shift counts + if(shift_count > 31) return N32·Status·gt_max_shift_count; - 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; + // 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); } - } - 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·alloc_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 + 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/developer/cc\360\237\226\211/N8.lib.c" "b/developer/cc\360\237\226\211/N8.lib.c" new file mode 100644 index 0000000..521666f --- /dev/null +++ "b/developer/cc\360\237\226\211/N8.lib.c" @@ -0,0 +1,433 @@ +/* + N8 - 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 N8·DEBUG + +#ifndef FACE +#define N8·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N8·FACE +#define N8·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint8_t Extent; + typedef uint8_t Digit; + + typedef struct N8·T N8·T; + + extern N8·T *N8·zero; + extern N8·T *N8·one; + extern N8·T *N8·all_one_bit; + extern N8·T *N8·lsb; + extern N8·T *N8·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N8·Status·ok = 0 + ,N8·Status·overflow = 1 + ,N8·Status·accumulator1_overflow = 2 + ,N8·Status·carry = 3 + ,N8·Status·borrow = 4 + ,N8·Status·undefined_divide_by_zero = 5 + ,N8·Status·undefined_modulus_zero = 6 + ,N8·Status·gt_max_shift_count = 7 + ,N8·Status·spill_eq_operand = 8 + ,N8·Status·one_word_product = 9 + ,N8·Status·two_word_product = 10 + } N8·Status; + + typedef enum{ + N8·Order_lt = -1 + ,N8·Order_eq = 0 + ,N8·Order_gt = 1 + } N8·Order; + + typedef N8·T *( *N8·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N8·T *(*allocate_array_zero)(Extent, N8·Allocate_MemoryFault); + N8·T *(*allocate_array)(Extent, N8·Allocate_MemoryFault); + void (*deallocate)(N8·T*); + + void (*copy)(N8·T*, N8·T*); + void (*bit_and)(N8·T*, N8·T*, N8·T*); + void (*bit_or)(N8·T*, N8·T*, N8·T*); + void (*bit_complement)(N8·T*, N8·T*); + void (*bit_twos_complement)(N8·T*, N8·T*); + N8·Order (*compare)(N8·T*, N8·T*); + bool (*lt)(N8·T*, N8·T*); + bool (*gt)(N8·T*, N8·T*); + bool (*eq)(N8·T*, N8·T*); + bool (*eq_zero)(N8·T*); + N8·Status (*accumulate)(N8·T *accumulator1 ,N8·T *accumulator0 ,...); + N8·Status (*add)(N8·T*, N8·T*, N8·T*); + bool (*increment)(N8·T *a); + N8·Status (*subtract)(N8·T*, N8·T*, N8·T*); + N8·Status (*multiply)(N8·T*, N8·T*, N8·T*, N8·T*); + N8·Status (*divide)(N8·T*, N8·T*, N8·T*, N8·T*); + N8·Status (*modulus)(N8·T*, N8·T*, N8·T*); + N8·Status (*shift_left)(Extent, N8·T*, N8·T*, N8·T*); + N8·Status (*shift_right)(Extent, N8·T*, N8·T*, N8·T*); + N8·Status (*arithmetic_shift_right)(Extent, N8·T*, N8·T*); + + N8·T* (*access)(N8·T*, Extent); + void (*from_uint32)(N8·T *destination ,uint32_t value); + } N8·Λ; + + Local const N8·Λ N8·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N8·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N8·T{ + Digit d0; + }; + + N8·T N8·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint8_t)0}, + {.d0 = 1 << 7} + }; + + N8·T *N8·zero = &N8·constant[0]; + N8·T *N8·one = &N8·constant[1]; + N8·T *N8·all_one_bit = &N8·constant[2]; + N8·T *N8·msb = &N8·constant[3]; + N8·T *N8·lsb = &N8·constant[1]; + + // the allocate an array of N8 + N8·T *N8·allocate_array(Extent extent ,N8·Allocate_MemoryFault memory_fault){ + N8·T *instance = malloc((extent + 1) * sizeof(N8·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N8·T *N8·allocate_array_zero(Extent extent ,N8·Allocate_MemoryFault memory_fault){ + N8·T *instance = calloc(extent + 1, sizeof(N8·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N8·deallocate(N8·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N8·T{ + Digit d0; + }; + + // temporary variables + Local N8·T N8·t[4]; + + // allocation + + extern N8·T *N8·allocate_array(Extent, N8·Allocate_MemoryFault); + extern N8·T *N8·allocate_array_zero(Extent, N8·Allocate_MemoryFault); + extern void N8·deallocate(N8·T *); + + // so the user can access numbers in an array allocation + Local N8·T* N8·access(N8·T *array ,Extent index){ + return &array[index]; + } + + Local void N8·from_uint32(N8·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint8_t)(value & 0xFF); + } + + // copy, convenience copy + + Local void N8·copy(N8·T *destination ,N8·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N8·set_to_zero(N8·T *instance){ + instance->d0 = 0; + } + + Local void N8·set_to_one(N8·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N8·bit_and(N8·T *result, N8·T *a, N8·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N8·bit_or(N8·T *result, N8·T *a, N8·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N8·bit_complement(N8·T *result, N8·T *a){ + result->d0 = ~a->d0; + } + + Local void N8·bit_twos_complement(N8·T *result ,N8·T *a){ + result->d0 = (uint8_t)(~a->d0 + 1); + } + + // test functions + + Local N8·Order N8·compare(N8·T *a, N8·T *b){ + if(a->d0 < b->d0) return N8·Order_lt; + if(a->d0 > b->d0) return N8·Order_gt; + return N8·Order_eq; + } + + Local bool N8·lt(N8·T *a ,N8·T *b){ + return a->d0 < b->d0; + } + + Local bool N8·gt(N8·T *a ,N8·T *b){ + return a->d0 > b->d0; + } + + Local bool N8·eq(N8·T *a ,N8·T *b){ + return a->d0 == b->d0; + } + + Local bool N8·eq_zero(N8·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N8·Status N8·accumulate(N8·T *accumulator1 ,N8·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N8·T *current; + + while( (current = va_arg(args ,N8·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N8·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint8_t)carry; + return N8·Status·ok; + } + + Local N8·Status N8·add(N8·T *sum ,N8·T *a ,N8·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint8_t)(result & 0xFF); + return (result >> 8) ? N8·Status·carry : N8·Status·ok; + } + + Local bool N8·increment(N8·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N8·Status N8·subtract(N8·T *difference ,N8·T *a ,N8·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint8_t)(diff & 0xFF); + return (diff > a->d0) ? N8·Status·borrow : N8·Status·ok; + } + + Local N8·Status N8·multiply(N8·T *product1 ,N8·T *product0 ,N8·T *a ,N8·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 N8·Status·one_word_product; + return N8·Status·two_word_product; + } + + Local N8·Status N8·divide(N8·T *remainder ,N8·T *quotient ,N8·T *a ,N8·T *b){ + if(b->d0 == 0) return N8·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 N8·Status·ok; + } + + Local N8·Status N8·modulus(N8·T *remainder ,N8·T *a ,N8·T *b){ + if(b->d0 == 0) return N8·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 N8·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 N8·Status N8·shift + ( + uint8_t shift_count + ,N8·T *spill + ,N8·T *operand + ,N8·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N8·Status·ok; + + if(operand == NULL){ + operand = &N8·t[0]; + N8·copy(operand, N8·zero); + } + + if(shift_count > 7) return N8·Status·gt_max_shift_count; + + N8·T *given_operand = &N8·t[1]; + N8·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)); + N8·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 N8·Status·ok; + } + + Local N8·Status + N8·shift_left(uint8_t shift_count, N8·T *spill, N8·T *operand, N8·T *fill){ + return N8·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N8·Status + N8·shift_right(uint8_t shift_count, N8·T *spill, N8·T *operand, N8·T *fill){ + return N8·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N8·Status + N8·arithmetic_shift_right(uint8_t shift_count, N8·T *operand, N8·T *spill){ + + if(shift_count > 7) return N8·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N8·t[0]; + N8·copy(operand, N8·zero); + } + + N8·T *fill = (operand->d0 & 0x80) ? N8·all_one_bit : N8·zero; + return N8·shift_right(shift_count, spill, operand, fill); + } + + Local const N8·Λ N8·λ = { + + .allocate_array = N8·allocate_array + ,.allocate_array_zero = N8·allocate_array_zero + ,.deallocate = N8·deallocate + + ,.copy = N8·copy + ,.bit_and = N8·bit_and + ,.bit_or = N8·bit_or + ,.bit_complement = N8·bit_complement + ,.bit_twos_complement = N8·bit_twos_complement + ,.compare = N8·compare + ,.lt = N8·lt + ,.gt = N8·gt + ,.eq = N8·eq + ,.eq_zero = N8·eq_zero + ,.accumulate = N8·accumulate + ,.add = N8·add + ,.increment = N8·increment + ,.subtract = N8·subtract + ,.multiply = N8·multiply + ,.divide = N8·divide + ,.modulus = N8·modulus + ,.shift_left = N8·shift_left + ,.shift_right = N8·shift_right + ,.arithmetic_shift_right = N8·arithmetic_shift_right + + ,.access = N8·access + ,.from_uint32 = N8·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/test_N32.cli.c" "b/developer/cc\360\237\226\211/test_N32.cli.c" index 6e79571..563711f 100644 --- "a/developer/cc\360\237\226\211/test_N32.cli.c" +++ "b/developer/cc\360\237\226\211/test_N32.cli.c" @@ -119,6 +119,245 @@ bool test_arithmetic(){ 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" diff --git "a/developer/document\360\237\226\211/Approach_to_headers.txt" "b/developer/document\360\237\226\211/Approach_to_headers.txt" deleted file mode 100644 index c929c4d..0000000 --- "a/developer/document\360\237\226\211/Approach_to_headers.txt" +++ /dev/null @@ -1,46 +0,0 @@ -✅ 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. 😆 diff --git "a/developer/document\360\237\226\211/SectionedFileFormat.org" "b/developer/document\360\237\226\211/SectionedFileFormat.org" index 46710ee..db89851 100644 --- "a/developer/document\360\237\226\211/SectionedFileFormat.org" +++ "b/developer/document\360\237\226\211/SectionedFileFormat.org" @@ -33,3 +33,53 @@ #+end_src - The `.lib.c` file is compiled into the library separately. + + +------- + +✅ 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. 😆 -- 2.20.1