From: Thomas Walker Lynch Date: Fri, 14 Feb 2025 16:24:57 +0000 (+0000) Subject: 'n' versions use native type double word accumulators. restructured for development... X-Git-Url: https://git.reasoningtechnology.com/style/static/git-logo.png?a=commitdiff_plain;h=230ec35f2ecb5a4e723b2ba4223e67d5512818e5;p=N 'n' versions use native type double word accumulators. restructured for development with m4 generated cc files --- diff --git a/developer/cc/.gitignore b/developer/cc/.gitignore new file mode 100644 index 0000000..120f485 --- /dev/null +++ b/developer/cc/.gitignore @@ -0,0 +1,2 @@ +* +!/.gitignore diff --git "a/developer/cc\360\237\226\211/N16.lib.c" "b/developer/cc\360\237\226\211/N16.lib.c" deleted file mode 100644 index 3b77116..0000000 --- "a/developer/cc\360\237\226\211/N16.lib.c" +++ /dev/null @@ -1,433 +0,0 @@ -/* - N16 - a processor native type - - For binary operations: a op b -> c - - See the document on the proper use of the Natural types. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) -*/ - -#define 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/N16n.lib.c" "b/developer/cc\360\237\226\211/N16n.lib.c" new file mode 100644 index 0000000..c28ab29 --- /dev/null +++ "b/developer/cc\360\237\226\211/N16n.lib.c" @@ -0,0 +1,433 @@ +/* + N16 - a processor native type + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N16n·DEBUG + +#ifndef FACE +#define N16n·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N16n·FACE +#define N16n·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint16_t Extent; + typedef uint16_t Digit; + + typedef struct N16n·T N16n·T; + + extern N16n·T *N16n·zero; + extern N16n·T *N16n·one; + extern N16n·T *N16n·all_one_bit; + extern N16n·T *N16n·lsb; + extern N16n·T *N16n·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N16n·Status·ok = 0 + ,N16n·Status·overflow = 1 + ,N16n·Status·accumulator1_overflow = 2 + ,N16n·Status·carry = 3 + ,N16n·Status·borrow = 4 + ,N16n·Status·undefined_divide_by_zero = 5 + ,N16n·Status·undefined_modulus_zero = 6 + ,N16n·Status·gt_max_shift_count = 7 + ,N16n·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N16n·Status·one_word_product = 9 + ,N16n·Status·two_word_product = 10 + } N16n·Status; + + typedef enum{ + N16n·Order_lt = -1 + ,N16n·Order_eq = 0 + ,N16n·Order_gt = 1 + } N16n·Order; + + typedef N16n·T *( *N16n·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N16n·T *(*allocate_array_zero)(Extent, N16n·Allocate_MemoryFault); + N16n·T *(*allocate_array)(Extent, N16n·Allocate_MemoryFault); + void (*deallocate)(N16n·T*); + + void (*copy)(N16n·T*, N16n·T*); + void (*bit_and)(N16n·T*, N16n·T*, N16n·T*); + void (*bit_or)(N16n·T*, N16n·T*, N16n·T*); + void (*bit_complement)(N16n·T*, N16n·T*); + void (*bit_twos_complement)(N16n·T*, N16n·T*); + N16n·Order (*compare)(N16n·T*, N16n·T*); + bool (*lt)(N16n·T*, N16n·T*); + bool (*gt)(N16n·T*, N16n·T*); + bool (*eq)(N16n·T*, N16n·T*); + bool (*eq_zero)(N16n·T*); + N16n·Status (*accumulate)(N16n·T *accumulator1 ,N16n·T *accumulator0 ,...); + N16n·Status (*add)(N16n·T*, N16n·T*, N16n·T*); + bool (*increment)(N16n·T *a); + N16n·Status (*subtract)(N16n·T*, N16n·T*, N16n·T*); + N16n·Status (*multiply)(N16n·T*, N16n·T*, N16n·T*, N16n·T*); + N16n·Status (*divide)(N16n·T*, N16n·T*, N16n·T*, N16n·T*); + N16n·Status (*modulus)(N16n·T*, N16n·T*, N16n·T*); + N16n·Status (*shift_left)(Extent, N16n·T*, N16n·T*, N16n·T*); + N16n·Status (*shift_right)(Extent, N16n·T*, N16n·T*, N16n·T*); + N16n·Status (*arithmetic_shift_right)(Extent, N16n·T*, N16n·T*); + + N16n·T* (*access)(N16n·T*, Extent); + void (*from_uint32)(N16n·T *destination ,uint32_t value); + } N16n·Λ; + + Local const N16n·Λ N16n·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N16n·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N16n·T{ + Digit d0; + }; + + N16n·T N16n·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint16_t)0}, + {.d0 = 1 << 15} + }; + + N16n·T *N16n·zero = &N16n·constant[0]; + N16n·T *N16n·one = &N16n·constant[1]; + N16n·T *N16n·all_one_bit = &N16n·constant[2]; + N16n·T *N16n·msb = &N16n·constant[3]; + N16n·T *N16n·lsb = &N16n·constant[1]; + + // the allocate an array of N16 + N16n·T *N16n·allocate_array(Extent extent ,N16n·Allocate_MemoryFault memory_fault){ + N16n·T *instance = malloc((extent + 1) * sizeof(N16n·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N16n·T *N16n·allocate_array_zero(Extent extent ,N16n·Allocate_MemoryFault memory_fault){ + N16n·T *instance = calloc(extent + 1, sizeof(N16n·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N16n·deallocate(N16n·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N16n·T{ + Digit d0; + }; + + // temporary variables + Local N16n·T N16n·t[4]; + + // allocation + + extern N16n·T *N16n·allocate_array(Extent, N16n·Allocate_MemoryFault); + extern N16n·T *N16n·allocate_array_zero(Extent, N16n·Allocate_MemoryFault); + extern void N16n·deallocate(N16n·T *); + + // so the user can access numbers in an array allocation + Local N16n·T* N16n·access(N16n·T *array ,Extent index){ + return &array[index]; + } + + Local void N16n·from_uint32(N16n·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint16_t)(value & 0xFFFF); + } + + // copy, convenience copy + + Local void N16n·copy(N16n·T *destination ,N16n·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N16n·set_to_zero(N16n·T *instance){ + instance->d0 = 0; + } + + Local void N16n·set_to_one(N16n·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N16n·bit_and(N16n·T *result, N16n·T *a, N16n·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N16n·bit_or(N16n·T *result, N16n·T *a, N16n·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N16n·bit_complement(N16n·T *result, N16n·T *a){ + result->d0 = ~a->d0; + } + + Local void N16n·bit_twos_complement(N16n·T *result ,N16n·T *a){ + result->d0 = (uint16_t)(~a->d0 + 1); + } + + // test functions + + Local N16n·Order N16n·compare(N16n·T *a, N16n·T *b){ + if(a->d0 < b->d0) return N16n·Order_lt; + if(a->d0 > b->d0) return N16n·Order_gt; + return N16n·Order_eq; + } + + Local bool N16n·lt(N16n·T *a ,N16n·T *b){ + return a->d0 < b->d0; + } + + Local bool N16n·gt(N16n·T *a ,N16n·T *b){ + return a->d0 > b->d0; + } + + Local bool N16n·eq(N16n·T *a ,N16n·T *b){ + return a->d0 == b->d0; + } + + Local bool N16n·eq_zero(N16n·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N16n·Status N16n·accumulate(N16n·T *accumulator1 ,N16n·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N16n·T *current; + + while( (current = va_arg(args ,N16n·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N16n·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint16_t)carry; + return N16n·Status·ok; + } + + Local N16n·Status N16n·add(N16n·T *sum ,N16n·T *a ,N16n·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint16_t)(result & 0xFFFF); + return (result >> 16) ? N16n·Status·carry : N16n·Status·ok; + } + + Local bool N16n·increment(N16n·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N16n·Status N16n·subtract(N16n·T *difference ,N16n·T *a ,N16n·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint16_t)(diff & 0xFFFF); + return (diff > a->d0) ? N16n·Status·borrow : N16n·Status·ok; + } + + Local N16n·Status N16n·multiply(N16n·T *product1 ,N16n·T *product0 ,N16n·T *a ,N16n·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint16_t)(product & 0xFFFF); + product1->d0 = (uint16_t)((product >> 16) & 0xFFFF); + + if(product1->d0 == 0) return N16n·Status·one_word_product; + return N16n·Status·two_word_product; + } + + Local N16n·Status N16n·divide(N16n·T *remainder ,N16n·T *quotient ,N16n·T *a ,N16n·T *b){ + if(b->d0 == 0) return N16n·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint16_t)(dividend / divisor); + remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor)); + + return N16n·Status·ok; + } + + Local N16n·Status N16n·modulus(N16n·T *remainder ,N16n·T *a ,N16n·T *b){ + if(b->d0 == 0) return N16n·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint16_t)(dividend - (q * divisor)); + return N16n·Status·ok; + } + + // bit motion + + typedef uint16_t (*ShiftOp)(uint16_t, uint16_t); + + Local uint16_t shift_left_op(uint16_t value, uint16_t amount){ + return value << amount; + } + + Local uint16_t shift_right_op(uint16_t value, uint16_t amount){ + return (uint16_t)(value >> amount); + } + + Local N16n·Status N16n·shift + ( + uint16_t shift_count + ,N16n·T *spill + ,N16n·T *operand + ,N16n·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N16n·Status·ok; + + if(operand == NULL){ + operand = &N16n·t[0]; + N16n·copy(operand, N16n·zero); + } + + if(shift_count > 15) return N16n·Status·gt_max_shift_count; + + N16n·T *given_operand = &N16n·t[1]; + N16n·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (16 - shift_count)); + N16n·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count)); + } + + return N16n·Status·ok; + } + + Local N16n·Status + N16n·shift_left(uint16_t shift_count, N16n·T *spill, N16n·T *operand, N16n·T *fill){ + return N16n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N16n·Status + N16n·shift_right(uint16_t shift_count, N16n·T *spill, N16n·T *operand, N16n·T *fill){ + return N16n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N16n·Status + N16n·arithmetic_shift_right(uint16_t shift_count, N16n·T *operand, N16n·T *spill){ + + if(shift_count > 15) return N16n·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N16n·t[0]; + N16n·copy(operand, N16n·zero); + } + + N16n·T *fill = (operand->d0 & 0x8000) ? N16n·all_one_bit : N16n·zero; + return N16n·shift_right(shift_count, spill, operand, fill); + } + + Local const N16n·Λ N16n·λ = { + + .allocate_array = N16n·allocate_array + ,.allocate_array_zero = N16n·allocate_array_zero + ,.deallocate = N16n·deallocate + + ,.copy = N16n·copy + ,.bit_and = N16n·bit_and + ,.bit_or = N16n·bit_or + ,.bit_complement = N16n·bit_complement + ,.bit_twos_complement = N16n·bit_twos_complement + ,.compare = N16n·compare + ,.lt = N16n·lt + ,.gt = N16n·gt + ,.eq = N16n·eq + ,.eq_zero = N16n·eq_zero + ,.accumulate = N16n·accumulate + ,.add = N16n·add + ,.increment = N16n·increment + ,.subtract = N16n·subtract + ,.multiply = N16n·multiply + ,.divide = N16n·divide + ,.modulus = N16n·modulus + ,.shift_left = N16n·shift_left + ,.shift_right = N16n·shift_right + ,.arithmetic_shift_right = N16n·arithmetic_shift_right + + ,.access = N16n·access + ,.from_uint32 = N16n·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N32.lib_std.c" "b/developer/cc\360\237\226\211/N32.lib_std.c" deleted file mode 100644 index fba3c21..0000000 --- "a/developer/cc\360\237\226\211/N32.lib_std.c" +++ /dev/null @@ -1,457 +0,0 @@ -/* - N32 - a processor native type - - For binary operations: a op b -> c - - See the document on the proper use of the Natural types. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) - -*/ - -#define N32·DEBUG - -#ifndef FACE -#define N32·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#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 - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#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); - } - - #endif - - // This part is included after the library user's code - #ifdef LOCAL - - // instance - - struct N32·T{ - Digit d0; - }; - - // temporary variables - // making these LOCAL rather than reserving one block in the library is thread safe - // allocating a block once is more efficient - // library code writes these, they are not on the interface - - Local N32·T N32·t[4]; - - - // allocation - - extern N32·T *N32·allocate_array(Extent, N32·Allocate_MemoryFault); - extern N32·T *N32·allocate_array_zero(Extent, N32·Allocate_MemoryFault); - extern void N32·deallocate(N32·T *); - - // so the user can access numbers in an array allocation - Local N32·T* N32·access(N32·T *array ,Extent index){ - return &array[index]; - } - - Local void N32·from_uint32(N32·T *destination ,uint32_t value){ - if(destination == NULL) return; - destination->d0 = value; - } - - // copy, convenience copy - - Local void N32·copy(N32·T *destination ,N32·T *source){ - if(source == destination) return; // that was easy! - *destination = *source; - } - - Local void N32·set_to_zero(N32·T *instance){ - instance->d0 = 0; - } - - Local void N32·set_to_one(N32·T *instance){ - instance->d0 = 1; - } - - // bit operations - - Local void N32·bit_and(N32·T *result, N32·T *a, N32·T *b){ - result->d0 = a->d0 & b->d0; - } - - // result can be one of the operands - Local void N32·bit_or(N32·T *result, N32·T *a, N32·T *b){ - result->d0 = a->d0 | b->d0; - } - - // result can the same as the operand - Local void N32·bit_complement(N32·T *result, N32·T *a){ - result->d0 = ~a->d0; - } - - // result can the same as the operand - Local void N32·bit_twos_complement(N32·T *result ,N32·T *a){ - result->d0 = ~a->d0 + 1; - } - - // test functions - - Local N32·Order N32·compare(N32·T *a, N32·T *b){ - if(a->d0 < b->d0) return N32·Order_lt; - if(a->d0 > b->d0) return N32·Order_gt; - return N32·Order_eq; - } - - Local bool N32·lt(N32·T *a ,N32·T *b){ - return a->d0 < b->d0; - } - - Local bool N32·gt(N32·T *a ,N32·T *b){ - return a->d0 > b->d0; - } - - Local bool N32·eq(N32·T *a ,N32·T *b){ - return a->d0 == b->d0; - } - - Local bool N32·eq_zero(N32·T *a){ - return a->d0 == 0; - } - - - // arithmetic operations - - // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32·Status·accumulator1_overflow - // - // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. - Local N32·Status N32·accumulate(N32·T *accumulator1 ,N32·T *accumulator0 ,...){ - - va_list args; - va_start(args ,accumulator0); - uint32_t sum = accumulator0->d0; - uint32_t carry = 0; - N32·T *current; - - while( (current = va_arg(args ,N32·T *)) ){ - sum += current->d0; - if(sum < current->d0){ // Accumulator1 into carry - (carry)++; - if(carry == 0){ - va_end(args); - return N32·Status·accumulator1_overflow; - } - } - } - va_end(args); - - // wipes out prior value of accumulator1 - accumulator1->d0 = carry; - - return N32·Status·ok; - } - - Local N32·Status N32·add(N32·T *sum ,N32·T *a ,N32·T *b){ - uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; - sum->d0 = (uint32_t)result; - return (result >> 32) ? N32·Status·carry : N32·Status·ok; - } - - Local bool N32·increment(N32·T *a){ - a->d0++; - return a->d0 == 0; - } - - Local N32·Status N32·subtract(N32·T *difference ,N32·T *a ,N32·T *b){ - uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; - difference->d0 = (uint32_t)diff; - return (diff > a->d0) ? N32·Status·borrow : N32·Status·ok; - } - - - Local N32·Status N32·multiply(N32·T *product1 ,N32·T *product0 ,N32·T *a ,N32·T *b){ - uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; - product0->d0 = (uint32_t)product; - product1->d0 = (uint32_t)(product >> 32); - - if(product1->d0 == 0) return N32·Status·one_word_product; - return N32·Status·two_word_product; - } - - Local N32·Status N32·divide(N32·T *remainder ,N32·T *quotient ,N32·T *a ,N32·T *b){ - if(b->d0 == 0) return N32·Status·undefined_divide_by_zero; - - quotient->d0 = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient->d0 * b->d0); - - return N32·Status·ok; - } - - Local N32·Status N32·modulus(N32·T *remainder ,N32·T *a ,N32·T *b){ - if(b->d0 == 0) return N32·Status·undefined_modulus_zero; - uint32_t quotient = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient * b->d0); - return N32·Status·ok; - } - - // bit motion - - typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); - - Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ - return value << amount; - } - - Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ - return value >> amount; - } - - // modifies all three of its operands - // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, - Local N32·Status N32·shift - ( - uint32_t shift_count - ,N32·T *spill - ,N32·T *operand - ,N32·T *fill - ,ShiftOp shift_op - ,ShiftOp complement_shift_op - ){ - - // If no result is needed, return immediately. - if(operand == NULL && spill == NULL) return N32·Status·ok; - - // Treat NULL operand as zero. - if(operand == NULL){ - operand = &N32·t[0]; - N32·copy(operand, N32·zero); - } - - // Shifting more than one word breaks our fill/spill model. - if(shift_count > 31) return N32·Status·gt_max_shift_count; - - // The given operand is still required after it is modified, so we copy it. - N32·T *given_operand = &N32·t[1]; - N32·copy(given_operand, operand); - - // Perform the shift - operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){ - fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); - N32·bit_or(operand, operand, fill); - } - if(spill != NULL){ - spill->d0 = shift_op(spill->d0, shift_count); - spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); - } - - return N32·Status·ok; - } - - // Define concrete shift functions using valid C function pointers - Local N32·Status - N32·shift_left(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){ - return N32·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - } - - Local N32·Status - N32·shift_right(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){ - return N32·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - } - - Local N32·Status - N32·arithmetic_shift_right(uint32_t shift_count, N32·T *operand, N32·T *spill){ - - // Guard against excessive shift counts - if(shift_count > 31) return N32·Status·gt_max_shift_count; - - // A NULL operand is treated as zero - if(operand == NULL){ - operand = &N32·t[0]; - N32·copy(operand, N32·zero); - } - - // Pick the fill value based on the sign bit - N32·T *fill = (operand->d0 & 0x80000000) ? N32·all_one_bit : N32·zero; - - // Call shift_right with the appropriate fill - return N32·shift_right(shift_count, spill, operand, fill); - } - - Local const N32·Λ N32·λ = { - - .allocate_array = N32·allocate_array - ,.allocate_array_zero = N32·allocate_array_zero - ,.deallocate = N32·deallocate - - ,.copy = N32·copy - ,.bit_and = N32·bit_and - ,.bit_or = N32·bit_or - ,.bit_complement = N32·bit_complement - ,.bit_twos_complement = N32·bit_twos_complement - ,.compare = N32·compare - ,.lt = N32·lt - ,.gt = N32·gt - ,.eq = N32·eq - ,.eq_zero = N32·eq_zero - ,.accumulate = N32·accumulate - ,.add = N32·add - ,.increment = N32·increment - ,.subtract = N32·subtract - ,.multiply = N32·multiply - ,.divide = N32·divide - ,.modulus = N32·modulus - ,.shift_left = N32·shift_left - ,.shift_right = N32·shift_right - ,.arithmetic_shift_right = N32·arithmetic_shift_right - - ,.access = N32·access - ,.from_uint32 = N32·from_uint32 - }; - - #endif - -#endif diff --git "a/developer/cc\360\237\226\211/N32n.lib.c" "b/developer/cc\360\237\226\211/N32n.lib.c" new file mode 100644 index 0000000..7e12dfd --- /dev/null +++ "b/developer/cc\360\237\226\211/N32n.lib.c" @@ -0,0 +1,457 @@ +/* + N32 - a processor native type + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) + +*/ + +#define N32n·DEBUG + +#ifndef FACE +#define N32n·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N32n·FACE +#define N32n·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint32_t Extent; + typedef uint32_t Digit; + + typedef struct N32n·T N32n·T; + + extern N32n·T *N32n·zero; + extern N32n·T *N32n·one; + extern N32n·T *N32n·all_one_bit; + extern N32n·T *N32n·lsb; + extern N32n·T *N32n·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N32n·Status·ok = 0 + ,N32n·Status·overflow = 1 + ,N32n·Status·accumulator1_overflow = 2 + ,N32n·Status·carry = 3 + ,N32n·Status·borrow = 4 + ,N32n·Status·undefined_divide_by_zero = 5 + ,N32n·Status·undefined_modulus_zero = 6 + ,N32n·Status·gt_max_shift_count = 7 + ,N32n·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N32n·Status·one_word_product = 9 + ,N32n·Status·two_word_product = 10 + } N32n·Status; + + typedef enum{ + N32n·Order_lt = -1 + ,N32n·Order_eq = 0 + ,N32n·Order_gt = 1 + } N32n·Order; + + typedef N32n·T *( *N32n·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N32n·T *(*allocate_array_zero)(Extent, N32n·Allocate_MemoryFault); + N32n·T *(*allocate_array)(Extent, N32n·Allocate_MemoryFault); + void (*deallocate)(N32n·T*); + + void (*copy)(N32n·T*, N32n·T*); + void (*bit_and)(N32n·T*, N32n·T*, N32n·T*); + void (*bit_or)(N32n·T*, N32n·T*, N32n·T*); + void (*bit_complement)(N32n·T*, N32n·T*); + void (*bit_twos_complement)(N32n·T*, N32n·T*); + N32n·Order (*compare)(N32n·T*, N32n·T*); + bool (*lt)(N32n·T*, N32n·T*); + bool (*gt)(N32n·T*, N32n·T*); + bool (*eq)(N32n·T*, N32n·T*); + bool (*eq_zero)(N32n·T*); + N32n·Status (*accumulate)(N32n·T *accumulator1 ,N32n·T *accumulator0 ,...); + N32n·Status (*add)(N32n·T*, N32n·T*, N32n·T*); + bool (*increment)(N32n·T *a); + N32n·Status (*subtract)(N32n·T*, N32n·T*, N32n·T*); + N32n·Status (*multiply)(N32n·T*, N32n·T*, N32n·T*, N32n·T*); + N32n·Status (*divide)(N32n·T*, N32n·T*, N32n·T*, N32n·T*); + N32n·Status (*modulus)(N32n·T*, N32n·T*, N32n·T*); + N32n·Status (*shift_left)(Extent, N32n·T*, N32n·T*, N32n·T*); + N32n·Status (*shift_right)(Extent, N32n·T*, N32n·T*, N32n·T*); + N32n·Status (*arithmetic_shift_right)(Extent, N32n·T*, N32n·T*); + + N32n·T* (*access)(N32n·T*, Extent); + void (*from_uint32)(N32n·T *destination ,uint32_t value); + } N32n·Λ; + + Local const N32n·Λ N32n·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N32n·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N32n·T{ + Digit d0; + }; + + N32n·T N32n·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint32_t)0}, + {.d0 = 1 << 31} + }; + + N32n·T *N32n·zero = &N32n·constant[0]; + N32n·T *N32n·one = &N32n·constant[1]; + N32n·T *N32n·all_one_bit = &N32n·constant[2]; + N32n·T *N32n·msb = &N32n·constant[3]; + N32n·T *N32n·lsb = &N32n·constant[1]; + + // the allocate an array of N32 + N32n·T *N32n·allocate_array(Extent extent ,N32n·Allocate_MemoryFault memory_fault){ + N32n·T *instance = malloc((extent + 1) * sizeof(N32n·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N32n·T *N32n·allocate_array_zero(Extent extent ,N32n·Allocate_MemoryFault memory_fault){ + N32n·T *instance = calloc( extent + 1 ,sizeof(N32n·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N32n·deallocate(N32n·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N32n·T{ + Digit d0; + }; + + // temporary variables + // making these LOCAL rather than reserving one block in the library is thread safe + // allocating a block once is more efficient + // library code writes these, they are not on the interface + + Local N32n·T N32n·t[4]; + + + // allocation + + extern N32n·T *N32n·allocate_array(Extent, N32n·Allocate_MemoryFault); + extern N32n·T *N32n·allocate_array_zero(Extent, N32n·Allocate_MemoryFault); + extern void N32n·deallocate(N32n·T *); + + // so the user can access numbers in an array allocation + Local N32n·T* N32n·access(N32n·T *array ,Extent index){ + return &array[index]; + } + + Local void N32n·from_uint32(N32n·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy, convenience copy + + Local void N32n·copy(N32n·T *destination ,N32n·T *source){ + if(source == destination) return; // that was easy! + *destination = *source; + } + + Local void N32n·set_to_zero(N32n·T *instance){ + instance->d0 = 0; + } + + Local void N32n·set_to_one(N32n·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N32n·bit_and(N32n·T *result, N32n·T *a, N32n·T *b){ + result->d0 = a->d0 & b->d0; + } + + // result can be one of the operands + Local void N32n·bit_or(N32n·T *result, N32n·T *a, N32n·T *b){ + result->d0 = a->d0 | b->d0; + } + + // result can the same as the operand + Local void N32n·bit_complement(N32n·T *result, N32n·T *a){ + result->d0 = ~a->d0; + } + + // result can the same as the operand + Local void N32n·bit_twos_complement(N32n·T *result ,N32n·T *a){ + result->d0 = ~a->d0 + 1; + } + + // test functions + + Local N32n·Order N32n·compare(N32n·T *a, N32n·T *b){ + if(a->d0 < b->d0) return N32n·Order_lt; + if(a->d0 > b->d0) return N32n·Order_gt; + return N32n·Order_eq; + } + + Local bool N32n·lt(N32n·T *a ,N32n·T *b){ + return a->d0 < b->d0; + } + + Local bool N32n·gt(N32n·T *a ,N32n·T *b){ + return a->d0 > b->d0; + } + + Local bool N32n·eq(N32n·T *a ,N32n·T *b){ + return a->d0 == b->d0; + } + + Local bool N32n·eq_zero(N32n·T *a){ + return a->d0 == 0; + } + + + // arithmetic operations + + // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32n·Status·accumulator1_overflow + // + // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. + Local N32n·Status N32n·accumulate(N32n·T *accumulator1 ,N32n·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N32n·T *current; + + while( (current = va_arg(args ,N32n·T *)) ){ + sum += current->d0; + if(sum < current->d0){ // Accumulator1 into carry + (carry)++; + if(carry == 0){ + va_end(args); + return N32n·Status·accumulator1_overflow; + } + } + } + va_end(args); + + // wipes out prior value of accumulator1 + accumulator1->d0 = carry; + + return N32n·Status·ok; + } + + Local N32n·Status N32n·add(N32n·T *sum ,N32n·T *a ,N32n·T *b){ + uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; + sum->d0 = (uint32_t)result; + return (result >> 32) ? N32n·Status·carry : N32n·Status·ok; + } + + Local bool N32n·increment(N32n·T *a){ + a->d0++; + return a->d0 == 0; + } + + Local N32n·Status N32n·subtract(N32n·T *difference ,N32n·T *a ,N32n·T *b){ + uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; + difference->d0 = (uint32_t)diff; + return (diff > a->d0) ? N32n·Status·borrow : N32n·Status·ok; + } + + + Local N32n·Status N32n·multiply(N32n·T *product1 ,N32n·T *product0 ,N32n·T *a ,N32n·T *b){ + uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; + product0->d0 = (uint32_t)product; + product1->d0 = (uint32_t)(product >> 32); + + if(product1->d0 == 0) return N32n·Status·one_word_product; + return N32n·Status·two_word_product; + } + + Local N32n·Status N32n·divide(N32n·T *remainder ,N32n·T *quotient ,N32n·T *a ,N32n·T *b){ + if(b->d0 == 0) return N32n·Status·undefined_divide_by_zero; + + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); + + return N32n·Status·ok; + } + + Local N32n·Status N32n·modulus(N32n·T *remainder ,N32n·T *a ,N32n·T *b){ + if(b->d0 == 0) return N32n·Status·undefined_modulus_zero; + uint32_t quotient = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient * b->d0); + return N32n·Status·ok; + } + + // bit motion + + typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); + + Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ + return value << amount; + } + + Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ + return value >> amount; + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, + Local N32n·Status N32n·shift + ( + uint32_t shift_count + ,N32n·T *spill + ,N32n·T *operand + ,N32n·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + // If no result is needed, return immediately. + if(operand == NULL && spill == NULL) return N32n·Status·ok; + + // Treat NULL operand as zero. + if(operand == NULL){ + operand = &N32n·t[0]; + N32n·copy(operand, N32n·zero); + } + + // Shifting more than one word breaks our fill/spill model. + if(shift_count > 31) return N32n·Status·gt_max_shift_count; + + // The given operand is still required after it is modified, so we copy it. + N32n·T *given_operand = &N32n·t[1]; + N32n·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); + N32n·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); + } + + return N32n·Status·ok; + } + + // Define concrete shift functions using valid C function pointers + Local N32n·Status + N32n·shift_left(uint32_t shift_count, N32n·T *spill, N32n·T *operand, N32n·T *fill){ + return N32n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N32n·Status + N32n·shift_right(uint32_t shift_count, N32n·T *spill, N32n·T *operand, N32n·T *fill){ + return N32n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N32n·Status + N32n·arithmetic_shift_right(uint32_t shift_count, N32n·T *operand, N32n·T *spill){ + + // Guard against excessive shift counts + if(shift_count > 31) return N32n·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N32n·t[0]; + N32n·copy(operand, N32n·zero); + } + + // Pick the fill value based on the sign bit + N32n·T *fill = (operand->d0 & 0x80000000) ? N32n·all_one_bit : N32n·zero; + + // Call shift_right with the appropriate fill + return N32n·shift_right(shift_count, spill, operand, fill); + } + + Local const N32n·Λ N32n·λ = { + + .allocate_array = N32n·allocate_array + ,.allocate_array_zero = N32n·allocate_array_zero + ,.deallocate = N32n·deallocate + + ,.copy = N32n·copy + ,.bit_and = N32n·bit_and + ,.bit_or = N32n·bit_or + ,.bit_complement = N32n·bit_complement + ,.bit_twos_complement = N32n·bit_twos_complement + ,.compare = N32n·compare + ,.lt = N32n·lt + ,.gt = N32n·gt + ,.eq = N32n·eq + ,.eq_zero = N32n·eq_zero + ,.accumulate = N32n·accumulate + ,.add = N32n·add + ,.increment = N32n·increment + ,.subtract = N32n·subtract + ,.multiply = N32n·multiply + ,.divide = N32n·divide + ,.modulus = N32n·modulus + ,.shift_left = N32n·shift_left + ,.shift_right = N32n·shift_right + ,.arithmetic_shift_right = N32n·arithmetic_shift_right + + ,.access = N32n·access + ,.from_uint32 = N32n·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N64.lib.c" "b/developer/cc\360\237\226\211/N64.lib.c" deleted file mode 100644 index 9d98d58..0000000 --- "a/developer/cc\360\237\226\211/N64.lib.c" +++ /dev/null @@ -1,477 +0,0 @@ -/* - N64 - a 64-bit native type - - For binary operations: a op b -> c - - Similar to N32, but now each Digit is 64 bits. Where a 128-bit - intermediate is necessary (e.g. multiplication), we handle it - manually using two 64-bit parts. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) -*/ - -#define N64·DEBUG - -#ifndef FACE -#define N64·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef N64·FACE -#define N64·FACE - - #include - #include - #include - #include - - //---------------------------------------- - // Instance Data (Declaration Only) - - typedef uint64_t Extent; - typedef uint64_t Digit; - - typedef struct N64·T N64·T; - - extern N64·T *N64·zero; - extern N64·T *N64·one; - extern N64·T *N64·all_one_bit; - extern N64·T *N64·lsb; - extern N64·T *N64·msb; - - //---------------------------------------- - // Return/Error Status and handlers - - typedef enum { - N64·Status·ok = 0 - ,N64·Status·overflow = 1 - ,N64·Status·accumulator1_overflow = 2 - ,N64·Status·carry = 3 - ,N64·Status·borrow = 4 - ,N64·Status·undefined_divide_by_zero = 5 - ,N64·Status·undefined_modulus_zero = 6 - ,N64·Status·gt_max_shift_count = 7 - ,N64·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value - ,N64·Status·one_word_product = 9 - ,N64·Status·two_word_product = 10 - } N64·Status; - - typedef enum { - N64·Order_lt = -1 - ,N64·Order_eq = 0 - ,N64·Order_gt = 1 - } N64·Order; - - typedef N64·T *(*N64·Allocate_MemoryFault)(Extent); - - //---------------------------------------- - // Interface - - typedef struct { - - N64·T *(*allocate_array_zero)(Extent, N64·Allocate_MemoryFault); - N64·T *(*allocate_array)(Extent, N64·Allocate_MemoryFault); - void (*deallocate)(N64·T*); - - void (*copy)(N64·T*, N64·T*); - void (*bit_and)(N64·T*, N64·T*, N64·T*); - void (*bit_or)(N64·T*, N64·T*, N64·T*); - void (*bit_complement)(N64·T*, N64·T*); - void (*bit_twos_complement)(N64·T*, N64·T*); - N64·Order (*compare)(N64·T*, N64·T*); - bool (*lt)(N64·T*, N64·T*); - bool (*gt)(N64·T*, N64·T*); - bool (*eq)(N64·T*, N64·T*); - bool (*eq_zero)(N64·T*); - N64·Status (*accumulate)(N64·T *accumulator1, N64·T *accumulator0, ...); - N64·Status (*add)(N64·T*, N64·T*, N64·T*); - bool (*increment)(N64·T *a); - N64·Status (*subtract)(N64·T*, N64·T*, N64·T*); - N64·Status (*multiply)(N64·T*, N64·T*, N64·T*, N64·T*); - N64·Status (*divide)(N64·T*, N64·T*, N64·T*, N64·T*); - N64·Status (*modulus)(N64·T*, N64·T*, N64·T*); - N64·Status (*shift_left)(Extent, N64·T*, N64·T*, N64·T*); - N64·Status (*shift_right)(Extent, N64·T*, N64·T*, N64·T*); - N64·Status (*arithmetic_shift_right)(Extent, N64·T*, N64·T*); - - N64·T* (*access)(N64·T*, Extent); - void (*from_uint64)(N64·T *destination, uint64_t value); - - } N64·Λ; - - Local const N64·Λ N64·λ; // initialized in the LOCAL section - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef N64·IMPLEMENTATION - - // this part goes into the library - #ifndef LOCAL - - #include - #include - - struct N64·T { - Digit d0; - }; - - // For constants, we store them in an array for convenience - // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63) - N64·T N64·constant[4] = { - {.d0 = 0ULL}, - {.d0 = 1ULL}, - {.d0 = ~(uint64_t)0ULL}, - {.d0 = 1ULL << 63} - }; - - N64·T *N64·zero = &N64·constant[0]; - N64·T *N64·one = &N64·constant[1]; - N64·T *N64·all_one_bit = &N64·constant[2]; - N64·T *N64·msb = &N64·constant[3]; - N64·T *N64·lsb = &N64·constant[1]; - - // allocate an array of N64 - N64·T *N64·allocate_array(Extent extent, N64·Allocate_MemoryFault memory_fault){ - N64·T *instance = malloc( (extent + 1) * sizeof(N64·T) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - N64·T *N64·allocate_array_zero(Extent extent, N64·Allocate_MemoryFault memory_fault){ - N64·T *instance = calloc(extent + 1, sizeof(N64·T)); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - void N64·deallocate(N64·T *unencumbered){ - free(unencumbered); - } - - #endif - - // This part is included after the library user's code - #ifdef LOCAL - - // instance - - struct N64·T { - Digit d0; - }; - - // local temporary variables - Local N64·T N64·t[4]; - - // allocation references - extern N64·T *N64·allocate_array(Extent, N64·Allocate_MemoryFault); - extern N64·T *N64·allocate_array_zero(Extent, N64·Allocate_MemoryFault); - extern void N64·deallocate(N64·T *); - - // Access array - Local N64·T* N64·access(N64·T *array, Extent index){ - return &array[index]; - } - - Local void N64·from_uint64(N64·T *destination, uint64_t value){ - if(destination == NULL) return; - destination->d0 = value; - } - - // copy - Local void N64·copy(N64·T *destination, N64·T *source){ - if(source == destination) return; - *destination = *source; - } - - // bit operations - - Local void N64·bit_and(N64·T *result, N64·T *a, N64·T *b){ - result->d0 = a->d0 & b->d0; - } - - Local void N64·bit_or(N64·T *result, N64·T *a, N64·T *b){ - result->d0 = a->d0 | b->d0; - } - - Local void N64·bit_complement(N64·T *result, N64·T *a){ - result->d0 = ~a->d0; - } - - Local void N64·bit_twos_complement(N64·T *result, N64·T *a){ - result->d0 = ~a->d0 + 1ULL; - } - - // compare & test functions - - Local N64·Order N64·compare(N64·T *a, N64·T *b){ - if(a->d0 < b->d0) return N64·Order_lt; - if(a->d0 > b->d0) return N64·Order_gt; - return N64·Order_eq; - } - - Local bool N64·lt(N64·T *a, N64·T *b){ - return (a->d0 < b->d0); - } - - Local bool N64·gt(N64·T *a, N64·T *b){ - return (a->d0 > b->d0); - } - - Local bool N64·eq(N64·T *a, N64·T *b){ - return (a->d0 == b->d0); - } - - Local bool N64·eq_zero(N64·T *a){ - return (a->d0 == 0ULL); - } - - // arithmetic operations - - // accumulate - Local N64·Status N64·accumulate(N64·T *accumulator1, N64·T *accumulator0, ...){ - va_list args; - va_start(args, accumulator0); - - uint64_t sum = accumulator0->d0; - uint64_t carry = 0; - N64·T *current; - - while( (current = va_arg(args, N64·T*)) ){ - uint64_t prior = sum; - sum += current->d0; - if(sum < prior){ // indicates carry - carry++; - // if carry overflowed a 64-bit, that's an accumulator1 overflow - if(carry == 0ULL){ - va_end(args); - return N64·Status·accumulator1_overflow; - } - } - } - va_end(args); - - accumulator1->d0 = carry; - return N64·Status·ok; - } - - // add - Local N64·Status N64·add(N64·T *sum, N64·T *a, N64·T *b){ - __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0; - // But to avoid using a GNU extension, we can do the simpler approach: - // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits: - uint64_t temp = a->d0 + b->d0; - sum->d0 = temp; - if(temp < a->d0) return N64·Status·carry; // means we overflowed - return N64·Status·ok; - } - - Local bool N64·increment(N64·T *a){ - uint64_t old = a->d0; - a->d0++; - // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF - return (a->d0 < old); - } - - // subtract - Local N64·Status N64·subtract(N64·T *difference, N64·T *a, N64·T *b){ - uint64_t tmpA = a->d0; - uint64_t tmpB = b->d0; - uint64_t diff = tmpA - tmpB; - difference->d0 = diff; - if(diff > tmpA) return N64·Status·borrow; // indicates we borrowed - return N64·Status·ok; - } - - // multiply - // We'll do a 64x64->128 using two 64-bit accumulators - Local N64·Status N64·multiply(N64·T *product1, N64·T *product0, N64·T *a, N64·T *b){ - uint64_t A = a->d0; - uint64_t B = b->d0; - - // Break each operand into high & low 32 bits - uint64_t a_lo = (uint32_t)(A & 0xffffffffULL); - uint64_t a_hi = A >> 32; - uint64_t b_lo = (uint32_t)(B & 0xffffffffULL); - uint64_t b_hi = B >> 32; - - // partial products - uint64_t low = a_lo * b_lo; // 64-bit - uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits - uint64_t high = a_hi * b_hi; // up to 64 bits - - // incorporate cross into low, high - // cross is effectively the middle bits, so shift cross by 32 and add to low - uint64_t cross_low = (cross & 0xffffffffULL) << 32; // lower part - uint64_t cross_high = cross >> 32; // upper part - - // add cross_low to low, capture carry - uint64_t old_low = low; - low += cross_low; - if(low < old_low) cross_high++; - - // final high - high += cross_high; - - // store results - product0->d0 = low; - product1->d0 = high; - - if(high == 0ULL) return N64·Status·one_word_product; - return N64·Status·two_word_product; - } - - // divide - Local N64·Status N64·divide(N64·T *remainder, N64·T *quotient, N64·T *a, N64·T *b){ - // we do not handle a > 64-bit, just the single 64-bit - if(b->d0 == 0ULL) return N64·Status·undefined_divide_by_zero; - - uint64_t divd = a->d0; // dividend - uint64_t divs = b->d0; // divisor - - quotient->d0 = divd / divs; - remainder->d0 = divd - (quotient->d0 * divs); - - return N64·Status·ok; - } - - // modulus - Local N64·Status N64·modulus(N64·T *remainder, N64·T *a, N64·T *b){ - if(b->d0 == 0ULL) return N64·Status·undefined_modulus_zero; - - uint64_t divd = a->d0; - uint64_t divs = b->d0; - uint64_t q = divd / divs; - remainder->d0 = divd - (q * divs); - - return N64·Status·ok; - } - - // bit motion - - typedef uint64_t (*ShiftOp)(uint64_t, uint64_t); - - Local uint64_t shift_left_op(uint64_t value, uint64_t amount){ - return (value << amount); - } - - Local uint64_t shift_right_op(uint64_t value, uint64_t amount){ - return (value >> amount); - } - - // modifies all three of its operands - // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill - Local N64·Status N64·shift - ( - uint64_t shift_count, - N64·T *spill, - N64·T *operand, - N64·T *fill, - ShiftOp shift_op, - ShiftOp complement_shift_op - ){ - if(operand == NULL && spill == NULL) return N64·Status·ok; - - // Treat NULL operand as zero - if(operand == NULL){ - operand = &N64·t[0]; - N64·copy(operand, N64·zero); - } - - // Shifting more than 63 bits breaks fill/spill logic - if(shift_count > 63ULL) return N64·Status·gt_max_shift_count; - - N64·T *given_operand = &N64·t[1]; - N64·copy(given_operand, operand); - - // Perform the shift - operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){ - fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count)); - N64·bit_or(operand, operand, fill); - } - if(spill != NULL){ - spill->d0 = shift_op(spill->d0, shift_count); - spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count)); - } - - return N64·Status·ok; - } - - Local N64·Status N64·shift_left(uint64_t shift_count, N64·T *spill, N64·T *operand, N64·T *fill){ - return N64·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - } - - Local N64·Status N64·shift_right(uint64_t shift_count, N64·T *spill, N64·T *operand, N64·T *fill){ - return N64·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - } - - Local N64·Status N64·arithmetic_shift_right(uint64_t shift_count, N64·T *operand, N64·T *spill){ - if(shift_count > 63ULL) return N64·Status·gt_max_shift_count; - - // A NULL operand is treated as zero - if(operand == NULL){ - operand = &N64·t[0]; - N64·copy(operand, N64·zero); - } - - // sign bit check - N64·T *fill = (operand->d0 & (1ULL << 63)) ? N64·all_one_bit : N64·zero; - return N64·shift_right(shift_count, spill, operand, fill); - } - - Local const N64·Λ N64·λ = { - .allocate_array = N64·allocate_array - ,.allocate_array_zero = N64·allocate_array_zero - ,.deallocate = N64·deallocate - - ,.copy = N64·copy - ,.bit_and = N64·bit_and - ,.bit_or = N64·bit_or - ,.bit_complement = N64·bit_complement - ,.bit_twos_complement = N64·bit_twos_complement - ,.compare = N64·compare - ,.lt = N64·lt - ,.gt = N64·gt - ,.eq = N64·eq - ,.eq_zero = N64·eq_zero - ,.accumulate = N64·accumulate - ,.add = N64·add - ,.increment = N64·increment - ,.subtract = N64·subtract - ,.multiply = N64·multiply - ,.divide = N64·divide - ,.modulus = N64·modulus - ,.shift_left = N64·shift_left - ,.shift_right = N64·shift_right - ,.arithmetic_shift_right = N64·arithmetic_shift_right - - ,.access = N64·access - ,.from_uint64 = N64·from_uint64 - }; - - #endif - -#endif diff --git "a/developer/cc\360\237\226\211/N64n.lib.c" "b/developer/cc\360\237\226\211/N64n.lib.c" new file mode 100644 index 0000000..2521fef --- /dev/null +++ "b/developer/cc\360\237\226\211/N64n.lib.c" @@ -0,0 +1,477 @@ +/* + N64 - a 64-bit native type + + For binary operations: a op b -> c + + Similar to N32, but now each Digit is 64 bits. Where a 128-bit + intermediate is necessary (e.g. multiplication), we handle it + manually using two 64-bit parts. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N64n·DEBUG + +#ifndef FACE +#define N64n·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N64n·FACE +#define N64n·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint64_t Extent; + typedef uint64_t Digit; + + typedef struct N64n·T N64n·T; + + extern N64n·T *N64n·zero; + extern N64n·T *N64n·one; + extern N64n·T *N64n·all_one_bit; + extern N64n·T *N64n·lsb; + extern N64n·T *N64n·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum { + N64n·Status·ok = 0 + ,N64n·Status·overflow = 1 + ,N64n·Status·accumulator1_overflow = 2 + ,N64n·Status·carry = 3 + ,N64n·Status·borrow = 4 + ,N64n·Status·undefined_divide_by_zero = 5 + ,N64n·Status·undefined_modulus_zero = 6 + ,N64n·Status·gt_max_shift_count = 7 + ,N64n·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N64n·Status·one_word_product = 9 + ,N64n·Status·two_word_product = 10 + } N64n·Status; + + typedef enum { + N64n·Order_lt = -1 + ,N64n·Order_eq = 0 + ,N64n·Order_gt = 1 + } N64n·Order; + + typedef N64n·T *(*N64n·Allocate_MemoryFault)(Extent); + + //---------------------------------------- + // Interface + + typedef struct { + + N64n·T *(*allocate_array_zero)(Extent, N64n·Allocate_MemoryFault); + N64n·T *(*allocate_array)(Extent, N64n·Allocate_MemoryFault); + void (*deallocate)(N64n·T*); + + void (*copy)(N64n·T*, N64n·T*); + void (*bit_and)(N64n·T*, N64n·T*, N64n·T*); + void (*bit_or)(N64n·T*, N64n·T*, N64n·T*); + void (*bit_complement)(N64n·T*, N64n·T*); + void (*bit_twos_complement)(N64n·T*, N64n·T*); + N64n·Order (*compare)(N64n·T*, N64n·T*); + bool (*lt)(N64n·T*, N64n·T*); + bool (*gt)(N64n·T*, N64n·T*); + bool (*eq)(N64n·T*, N64n·T*); + bool (*eq_zero)(N64n·T*); + N64n·Status (*accumulate)(N64n·T *accumulator1, N64n·T *accumulator0, ...); + N64n·Status (*add)(N64n·T*, N64n·T*, N64n·T*); + bool (*increment)(N64n·T *a); + N64n·Status (*subtract)(N64n·T*, N64n·T*, N64n·T*); + N64n·Status (*multiply)(N64n·T*, N64n·T*, N64n·T*, N64n·T*); + N64n·Status (*divide)(N64n·T*, N64n·T*, N64n·T*, N64n·T*); + N64n·Status (*modulus)(N64n·T*, N64n·T*, N64n·T*); + N64n·Status (*shift_left)(Extent, N64n·T*, N64n·T*, N64n·T*); + N64n·Status (*shift_right)(Extent, N64n·T*, N64n·T*, N64n·T*); + N64n·Status (*arithmetic_shift_right)(Extent, N64n·T*, N64n·T*); + + N64n·T* (*access)(N64n·T*, Extent); + void (*from_uint64)(N64n·T *destination, uint64_t value); + + } N64n·Λ; + + Local const N64n·Λ N64n·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N64n·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N64n·T { + Digit d0; + }; + + // For constants, we store them in an array for convenience + // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63) + N64n·T N64n·constant[4] = { + {.d0 = 0ULL}, + {.d0 = 1ULL}, + {.d0 = ~(uint64_t)0ULL}, + {.d0 = 1ULL << 63} + }; + + N64n·T *N64n·zero = &N64n·constant[0]; + N64n·T *N64n·one = &N64n·constant[1]; + N64n·T *N64n·all_one_bit = &N64n·constant[2]; + N64n·T *N64n·msb = &N64n·constant[3]; + N64n·T *N64n·lsb = &N64n·constant[1]; + + // allocate an array of N64 + N64n·T *N64n·allocate_array(Extent extent, N64n·Allocate_MemoryFault memory_fault){ + N64n·T *instance = malloc( (extent + 1) * sizeof(N64n·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N64n·T *N64n·allocate_array_zero(Extent extent, N64n·Allocate_MemoryFault memory_fault){ + N64n·T *instance = calloc(extent + 1, sizeof(N64n·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N64n·deallocate(N64n·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N64n·T { + Digit d0; + }; + + // local temporary variables + Local N64n·T N64n·t[4]; + + // allocation references + extern N64n·T *N64n·allocate_array(Extent, N64n·Allocate_MemoryFault); + extern N64n·T *N64n·allocate_array_zero(Extent, N64n·Allocate_MemoryFault); + extern void N64n·deallocate(N64n·T *); + + // Access array + Local N64n·T* N64n·access(N64n·T *array, Extent index){ + return &array[index]; + } + + Local void N64n·from_uint64(N64n·T *destination, uint64_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy + Local void N64n·copy(N64n·T *destination, N64n·T *source){ + if(source == destination) return; + *destination = *source; + } + + // bit operations + + Local void N64n·bit_and(N64n·T *result, N64n·T *a, N64n·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N64n·bit_or(N64n·T *result, N64n·T *a, N64n·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N64n·bit_complement(N64n·T *result, N64n·T *a){ + result->d0 = ~a->d0; + } + + Local void N64n·bit_twos_complement(N64n·T *result, N64n·T *a){ + result->d0 = ~a->d0 + 1ULL; + } + + // compare & test functions + + Local N64n·Order N64n·compare(N64n·T *a, N64n·T *b){ + if(a->d0 < b->d0) return N64n·Order_lt; + if(a->d0 > b->d0) return N64n·Order_gt; + return N64n·Order_eq; + } + + Local bool N64n·lt(N64n·T *a, N64n·T *b){ + return (a->d0 < b->d0); + } + + Local bool N64n·gt(N64n·T *a, N64n·T *b){ + return (a->d0 > b->d0); + } + + Local bool N64n·eq(N64n·T *a, N64n·T *b){ + return (a->d0 == b->d0); + } + + Local bool N64n·eq_zero(N64n·T *a){ + return (a->d0 == 0ULL); + } + + // arithmetic operations + + // accumulate + Local N64n·Status N64n·accumulate(N64n·T *accumulator1, N64n·T *accumulator0, ...){ + va_list args; + va_start(args, accumulator0); + + uint64_t sum = accumulator0->d0; + uint64_t carry = 0; + N64n·T *current; + + while( (current = va_arg(args, N64n·T*)) ){ + uint64_t prior = sum; + sum += current->d0; + if(sum < prior){ // indicates carry + carry++; + // if carry overflowed a 64-bit, that's an accumulator1 overflow + if(carry == 0ULL){ + va_end(args); + return N64n·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = carry; + return N64n·Status·ok; + } + + // add + Local N64n·Status N64n·add(N64n·T *sum, N64n·T *a, N64n·T *b){ + __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0; + // But to avoid using a GNU extension, we can do the simpler approach: + // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits: + uint64_t temp = a->d0 + b->d0; + sum->d0 = temp; + if(temp < a->d0) return N64n·Status·carry; // means we overflowed + return N64n·Status·ok; + } + + Local bool N64n·increment(N64n·T *a){ + uint64_t old = a->d0; + a->d0++; + // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF + return (a->d0 < old); + } + + // subtract + Local N64n·Status N64n·subtract(N64n·T *difference, N64n·T *a, N64n·T *b){ + uint64_t tmpA = a->d0; + uint64_t tmpB = b->d0; + uint64_t diff = tmpA - tmpB; + difference->d0 = diff; + if(diff > tmpA) return N64n·Status·borrow; // indicates we borrowed + return N64n·Status·ok; + } + + // multiply + // We'll do a 64x64->128 using two 64-bit accumulators + Local N64n·Status N64n·multiply(N64n·T *product1, N64n·T *product0, N64n·T *a, N64n·T *b){ + uint64_t A = a->d0; + uint64_t B = b->d0; + + // Break each operand into high & low 32 bits + uint64_t a_lo = (uint32_t)(A & 0xffffffffULL); + uint64_t a_hi = A >> 32; + uint64_t b_lo = (uint32_t)(B & 0xffffffffULL); + uint64_t b_hi = B >> 32; + + // partial products + uint64_t low = a_lo * b_lo; // 64-bit + uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits + uint64_t high = a_hi * b_hi; // up to 64 bits + + // incorporate cross into low, high + // cross is effectively the middle bits, so shift cross by 32 and add to low + uint64_t cross_low = (cross & 0xffffffffULL) << 32; // lower part + uint64_t cross_high = cross >> 32; // upper part + + // add cross_low to low, capture carry + uint64_t old_low = low; + low += cross_low; + if(low < old_low) cross_high++; + + // final high + high += cross_high; + + // store results + product0->d0 = low; + product1->d0 = high; + + if(high == 0ULL) return N64n·Status·one_word_product; + return N64n·Status·two_word_product; + } + + // divide + Local N64n·Status N64n·divide(N64n·T *remainder, N64n·T *quotient, N64n·T *a, N64n·T *b){ + // we do not handle a > 64-bit, just the single 64-bit + if(b->d0 == 0ULL) return N64n·Status·undefined_divide_by_zero; + + uint64_t divd = a->d0; // dividend + uint64_t divs = b->d0; // divisor + + quotient->d0 = divd / divs; + remainder->d0 = divd - (quotient->d0 * divs); + + return N64n·Status·ok; + } + + // modulus + Local N64n·Status N64n·modulus(N64n·T *remainder, N64n·T *a, N64n·T *b){ + if(b->d0 == 0ULL) return N64n·Status·undefined_modulus_zero; + + uint64_t divd = a->d0; + uint64_t divs = b->d0; + uint64_t q = divd / divs; + remainder->d0 = divd - (q * divs); + + return N64n·Status·ok; + } + + // bit motion + + typedef uint64_t (*ShiftOp)(uint64_t, uint64_t); + + Local uint64_t shift_left_op(uint64_t value, uint64_t amount){ + return (value << amount); + } + + Local uint64_t shift_right_op(uint64_t value, uint64_t amount){ + return (value >> amount); + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill + Local N64n·Status N64n·shift + ( + uint64_t shift_count, + N64n·T *spill, + N64n·T *operand, + N64n·T *fill, + ShiftOp shift_op, + ShiftOp complement_shift_op + ){ + if(operand == NULL && spill == NULL) return N64n·Status·ok; + + // Treat NULL operand as zero + if(operand == NULL){ + operand = &N64n·t[0]; + N64n·copy(operand, N64n·zero); + } + + // Shifting more than 63 bits breaks fill/spill logic + if(shift_count > 63ULL) return N64n·Status·gt_max_shift_count; + + N64n·T *given_operand = &N64n·t[1]; + N64n·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count)); + N64n·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count)); + } + + return N64n·Status·ok; + } + + Local N64n·Status N64n·shift_left(uint64_t shift_count, N64n·T *spill, N64n·T *operand, N64n·T *fill){ + return N64n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N64n·Status N64n·shift_right(uint64_t shift_count, N64n·T *spill, N64n·T *operand, N64n·T *fill){ + return N64n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N64n·Status N64n·arithmetic_shift_right(uint64_t shift_count, N64n·T *operand, N64n·T *spill){ + if(shift_count > 63ULL) return N64n·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N64n·t[0]; + N64n·copy(operand, N64n·zero); + } + + // sign bit check + N64n·T *fill = (operand->d0 & (1ULL << 63)) ? N64n·all_one_bit : N64n·zero; + return N64n·shift_right(shift_count, spill, operand, fill); + } + + Local const N64n·Λ N64n·λ = { + .allocate_array = N64n·allocate_array + ,.allocate_array_zero = N64n·allocate_array_zero + ,.deallocate = N64n·deallocate + + ,.copy = N64n·copy + ,.bit_and = N64n·bit_and + ,.bit_or = N64n·bit_or + ,.bit_complement = N64n·bit_complement + ,.bit_twos_complement = N64n·bit_twos_complement + ,.compare = N64n·compare + ,.lt = N64n·lt + ,.gt = N64n·gt + ,.eq = N64n·eq + ,.eq_zero = N64n·eq_zero + ,.accumulate = N64n·accumulate + ,.add = N64n·add + ,.increment = N64n·increment + ,.subtract = N64n·subtract + ,.multiply = N64n·multiply + ,.divide = N64n·divide + ,.modulus = N64n·modulus + ,.shift_left = N64n·shift_left + ,.shift_right = N64n·shift_right + ,.arithmetic_shift_right = N64n·arithmetic_shift_right + + ,.access = N64n·access + ,.from_uint64 = N64n·from_uint64 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N8.lib.c" "b/developer/cc\360\237\226\211/N8.lib.c" deleted file mode 100644 index 521666f..0000000 --- "a/developer/cc\360\237\226\211/N8.lib.c" +++ /dev/null @@ -1,433 +0,0 @@ -/* - 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/N8n.lib.c" "b/developer/cc\360\237\226\211/N8n.lib.c" new file mode 100644 index 0000000..d2aaeb4 --- /dev/null +++ "b/developer/cc\360\237\226\211/N8n.lib.c" @@ -0,0 +1,433 @@ +/* + N8n - a processor native type + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N8n·DEBUG + +#ifndef FACE +#define N8n·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N8n·FACE +#define N8n·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint8_t Extent; + typedef uint8_t Digit; + + typedef struct N8n·T N8n·T; + + extern N8n·T *N8n·zero; + extern N8n·T *N8n·one; + extern N8n·T *N8n·all_one_bit; + extern N8n·T *N8n·lsb; + extern N8n·T *N8n·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N8n·Status·ok = 0 + ,N8n·Status·overflow = 1 + ,N8n·Status·accumulator1_overflow = 2 + ,N8n·Status·carry = 3 + ,N8n·Status·borrow = 4 + ,N8n·Status·undefined_divide_by_zero = 5 + ,N8n·Status·undefined_modulus_zero = 6 + ,N8n·Status·gt_max_shift_count = 7 + ,N8n·Status·spill_eq_operand = 8 + ,N8n·Status·one_word_product = 9 + ,N8n·Status·two_word_product = 10 + } N8n·Status; + + typedef enum{ + N8n·Order_lt = -1 + ,N8n·Order_eq = 0 + ,N8n·Order_gt = 1 + } N8n·Order; + + typedef N8n·T *( *N8n·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N8n·T *(*allocate_array_zero)(Extent, N8n·Allocate_MemoryFault); + N8n·T *(*allocate_array)(Extent, N8n·Allocate_MemoryFault); + void (*deallocate)(N8n·T*); + + void (*copy)(N8n·T*, N8n·T*); + void (*bit_and)(N8n·T*, N8n·T*, N8n·T*); + void (*bit_or)(N8n·T*, N8n·T*, N8n·T*); + void (*bit_complement)(N8n·T*, N8n·T*); + void (*bit_twos_complement)(N8n·T*, N8n·T*); + N8n·Order (*compare)(N8n·T*, N8n·T*); + bool (*lt)(N8n·T*, N8n·T*); + bool (*gt)(N8n·T*, N8n·T*); + bool (*eq)(N8n·T*, N8n·T*); + bool (*eq_zero)(N8n·T*); + N8n·Status (*accumulate)(N8n·T *accumulator1 ,N8n·T *accumulator0 ,...); + N8n·Status (*add)(N8n·T*, N8n·T*, N8n·T*); + bool (*increment)(N8n·T *a); + N8n·Status (*subtract)(N8n·T*, N8n·T*, N8n·T*); + N8n·Status (*multiply)(N8n·T*, N8n·T*, N8n·T*, N8n·T*); + N8n·Status (*divide)(N8n·T*, N8n·T*, N8n·T*, N8n·T*); + N8n·Status (*modulus)(N8n·T*, N8n·T*, N8n·T*); + N8n·Status (*shift_left)(Extent, N8n·T*, N8n·T*, N8n·T*); + N8n·Status (*shift_right)(Extent, N8n·T*, N8n·T*, N8n·T*); + N8n·Status (*arithmetic_shift_right)(Extent, N8n·T*, N8n·T*); + + N8n·T* (*access)(N8n·T*, Extent); + void (*from_uint32)(N8n·T *destination ,uint32_t value); + } N8n·Λ; + + Local const N8n·Λ N8n·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N8n·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N8n·T{ + Digit d0; + }; + + N8n·T N8n·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint8_t)0}, + {.d0 = 1 << 7} + }; + + N8n·T *N8n·zero = &N8n·constant[0]; + N8n·T *N8n·one = &N8n·constant[1]; + N8n·T *N8n·all_one_bit = &N8n·constant[2]; + N8n·T *N8n·msb = &N8n·constant[3]; + N8n·T *N8n·lsb = &N8n·constant[1]; + + // the allocate an array of N8 + N8n·T *N8n·allocate_array(Extent extent ,N8n·Allocate_MemoryFault memory_fault){ + N8n·T *instance = malloc((extent + 1) * sizeof(N8n·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N8n·T *N8n·allocate_array_zero(Extent extent ,N8n·Allocate_MemoryFault memory_fault){ + N8n·T *instance = calloc(extent + 1, sizeof(N8n·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N8n·deallocate(N8n·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N8n·T{ + Digit d0; + }; + + // temporary variables + Local N8n·T N8n·t[4]; + + // allocation + + extern N8n·T *N8n·allocate_array(Extent, N8n·Allocate_MemoryFault); + extern N8n·T *N8n·allocate_array_zero(Extent, N8n·Allocate_MemoryFault); + extern void N8n·deallocate(N8n·T *); + + // so the user can access numbers in an array allocation + Local N8n·T* N8n·access(N8n·T *array ,Extent index){ + return &array[index]; + } + + Local void N8n·from_uint32(N8n·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint8_t)(value & 0xFF); + } + + // copy, convenience copy + + Local void N8n·copy(N8n·T *destination ,N8n·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N8n·set_to_zero(N8n·T *instance){ + instance->d0 = 0; + } + + Local void N8n·set_to_one(N8n·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N8n·bit_and(N8n·T *result, N8n·T *a, N8n·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N8n·bit_or(N8n·T *result, N8n·T *a, N8n·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N8n·bit_complement(N8n·T *result, N8n·T *a){ + result->d0 = ~a->d0; + } + + Local void N8n·bit_twos_complement(N8n·T *result ,N8n·T *a){ + result->d0 = (uint8_t)(~a->d0 + 1); + } + + // test functions + + Local N8n·Order N8n·compare(N8n·T *a, N8n·T *b){ + if(a->d0 < b->d0) return N8n·Order_lt; + if(a->d0 > b->d0) return N8n·Order_gt; + return N8n·Order_eq; + } + + Local bool N8n·lt(N8n·T *a ,N8n·T *b){ + return a->d0 < b->d0; + } + + Local bool N8n·gt(N8n·T *a ,N8n·T *b){ + return a->d0 > b->d0; + } + + Local bool N8n·eq(N8n·T *a ,N8n·T *b){ + return a->d0 == b->d0; + } + + Local bool N8n·eq_zero(N8n·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N8n·Status N8n·accumulate(N8n·T *accumulator1 ,N8n·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N8n·T *current; + + while( (current = va_arg(args ,N8n·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N8n·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint8_t)carry; + return N8n·Status·ok; + } + + Local N8n·Status N8n·add(N8n·T *sum ,N8n·T *a ,N8n·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint8_t)(result & 0xFF); + return (result >> 8) ? N8n·Status·carry : N8n·Status·ok; + } + + Local bool N8n·increment(N8n·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N8n·Status N8n·subtract(N8n·T *difference ,N8n·T *a ,N8n·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint8_t)(diff & 0xFF); + return (diff > a->d0) ? N8n·Status·borrow : N8n·Status·ok; + } + + Local N8n·Status N8n·multiply(N8n·T *product1 ,N8n·T *product0 ,N8n·T *a ,N8n·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint8_t)(product & 0xFF); + product1->d0 = (uint8_t)((product >> 8) & 0xFF); + + if(product1->d0 == 0) return N8n·Status·one_word_product; + return N8n·Status·two_word_product; + } + + Local N8n·Status N8n·divide(N8n·T *remainder ,N8n·T *quotient ,N8n·T *a ,N8n·T *b){ + if(b->d0 == 0) return N8n·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint8_t)(dividend / divisor); + remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor)); + + return N8n·Status·ok; + } + + Local N8n·Status N8n·modulus(N8n·T *remainder ,N8n·T *a ,N8n·T *b){ + if(b->d0 == 0) return N8n·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint8_t)(dividend - (q * divisor)); + return N8n·Status·ok; + } + + // bit motion + + typedef uint8_t (*ShiftOp)(uint8_t, uint8_t); + + Local uint8_t shift_left_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value << amount); + } + + Local uint8_t shift_right_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value >> amount); + } + + Local N8n·Status N8n·shift + ( + uint8_t shift_count + ,N8n·T *spill + ,N8n·T *operand + ,N8n·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N8n·Status·ok; + + if(operand == NULL){ + operand = &N8n·t[0]; + N8n·copy(operand, N8n·zero); + } + + if(shift_count > 7) return N8n·Status·gt_max_shift_count; + + N8n·T *given_operand = &N8n·t[1]; + N8n·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (8 - shift_count)); + N8n·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count)); + } + + return N8n·Status·ok; + } + + Local N8n·Status + N8n·shift_left(uint8_t shift_count, N8n·T *spill, N8n·T *operand, N8n·T *fill){ + return N8n·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N8n·Status + N8n·shift_right(uint8_t shift_count, N8n·T *spill, N8n·T *operand, N8n·T *fill){ + return N8n·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N8n·Status + N8n·arithmetic_shift_right(uint8_t shift_count, N8n·T *operand, N8n·T *spill){ + + if(shift_count > 7) return N8n·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N8n·t[0]; + N8n·copy(operand, N8n·zero); + } + + N8n·T *fill = (operand->d0 & 0x80) ? N8n·all_one_bit : N8n·zero; + return N8n·shift_right(shift_count, spill, operand, fill); + } + + Local const N8n·Λ N8n·λ = { + + .allocate_array = N8n·allocate_array + ,.allocate_array_zero = N8n·allocate_array_zero + ,.deallocate = N8n·deallocate + + ,.copy = N8n·copy + ,.bit_and = N8n·bit_and + ,.bit_or = N8n·bit_or + ,.bit_complement = N8n·bit_complement + ,.bit_twos_complement = N8n·bit_twos_complement + ,.compare = N8n·compare + ,.lt = N8n·lt + ,.gt = N8n·gt + ,.eq = N8n·eq + ,.eq_zero = N8n·eq_zero + ,.accumulate = N8n·accumulate + ,.add = N8n·add + ,.increment = N8n·increment + ,.subtract = N8n·subtract + ,.multiply = N8n·multiply + ,.divide = N8n·divide + ,.modulus = N8n·modulus + ,.shift_left = N8n·shift_left + ,.shift_right = N8n·shift_right + ,.arithmetic_shift_right = N8n·arithmetic_shift_right + + ,.access = N8n·access + ,.from_uint32 = N8n·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N_template.lib.c.m4" "b/developer/cc\360\237\226\211/N_template.lib.c.m4" deleted file mode 100644 index cabe6b5..0000000 --- "a/developer/cc\360\237\226\211/N_template.lib.c.m4" +++ /dev/null @@ -1,318 +0,0 @@ -changequote([,])dnl -define(NS, __NAMESPACE__)dnl -define(DE, __DIGIT_EXTENT__)dnl -define(DT, __DIGIT_TYPE__)dnl -define(ET, __EXTENT_TYPE__)dnl -changequote(`,')dnl - -/* - [NS] - Parametric multi-digit type library (RT code format) - - Parameters: - [NS]: Namespace prefix, e.g. N32· - [DE]: Digit extent => total digits = DE + 1 - [DT]: Digit type, e.g. uint64_t or uint8_t - [ET]: Loop counter type, e.g. uint64_t -*/ - -#define [NS]DEBUG - -#ifndef FACE - #define [NS]IMPLEMENTATION - #define FACE -#endif - -//------------------------------------------------------------------------------ -// Interface Section - -#ifndef [NS]FACE -#define [NS]FACE - - #include - #include - #include - #include - - // Digit count is DE + 1 - #define [NS]DIGIT_COUNT (DE + 1) - - typedef DT Digit; - typedef struct [NS]T [NS]T; - - // For array allocations - typedef ET ExtentType; - - // Status codes - typedef enum{ - [NS]Status_ok = 0 - ,[NS]Status_overflow - ,[NS]Status_accumulator1_overflow - ,[NS]Status_carry - ,[NS]Status_borrow - ,[NS]Status_undefined_divide_by_zero - ,[NS]Status_undefined_modulus_zero - ,[NS]Status_gt_max_shift_count - ,[NS]Status_spill_eq_operand - ,[NS]Status_one_word_product - ,[NS]Status_two_word_product - } [NS]Status; - - typedef enum{ - [NS]Order_lt = -1 - ,[NS]Order_eq = 0 - ,[NS]Order_gt = 1 - } [NS]Order; - - // Allocation - Digit *[NS]allocate_array(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)); - Digit *[NS]allocate_array_zero(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)); - void [NS]deallocate([NS]T *unencumbered); - - // Constant setters (no static global constants) - void [NS]set_zero([NS]T *destination); - void [NS]set_one([NS]T *destination); - void [NS]set_all_bits([NS]T *destination); - void [NS]set_msb([NS]T *destination); - - // Bitwise ops - void [NS]bit_and([NS]T *result ,[NS]T *a ,[NS]T *b); - void [NS]bit_or([NS]T *result ,[NS]T *a ,[NS]T *b); - void [NS]bit_complement([NS]T *result ,[NS]T *a); - void [NS]bit_twos_complement([NS]T *result ,[NS]T *a); - - // Comparison ops - bool [NS]eq([NS]T *a ,[NS]T *b); - bool [NS]eq_zero([NS]T *a); - [NS]Order [NS]compare([NS]T *a ,[NS]T *b); - - // Arithmetic - [NS]Status [NS]add([NS]T *sum ,[NS]T *a ,[NS]T *b); - [NS]Status [NS]subtract([NS]T *diff ,[NS]T *a ,[NS]T *b); - - // Conversions - void [NS]from_uint64([NS]T *destination ,uint64_t value); - -#endif // [NS]FACE - - -//------------------------------------------------------------------------------ -// Implementation Section - -#ifdef [NS]IMPLEMENTATION - - #ifndef LOCAL - - #include - #include - - struct [NS]T{ - Digit d[[NS]DIGIT_COUNT]; - }; - - Digit *[NS]allocate_array(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)){ - [NS]T *instance = malloc((extent + 1) * sizeof([NS]T)); - if(!instance){ - if(fault_handler) return (Digit*)fault_handler(extent); - return NULL; - } - return (Digit*)instance; - } - - Digit *[NS]allocate_array_zero(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)){ - [NS]T *instance = calloc(extent + 1 ,sizeof([NS]T)); - if(!instance){ - if(fault_handler) return (Digit*)fault_handler(extent); - return NULL; - } - return (Digit*)instance; - } - - void [NS]deallocate([NS]T *unencumbered){ - free(unencumbered); - } - - #endif // LOCAL not defined - - - #ifdef LOCAL - - // local code implementing everything - struct [NS]T{ - Digit d[[NS]DIGIT_COUNT]; - }; - - // Constant Setters - - Local void [NS]set_zero([NS]T *destination){ - if(!destination) return; - Digit *start = destination->d; - Digit *end = destination->d + [NS]DIGIT_COUNT; - for(Digit *p = start ; p < end ; p++){ - *p = 0; - } - } - - Local void [NS]set_one([NS]T *destination){ - if(!destination) return; - [NS]set_zero(destination); - destination->d[0] = 1; - } - - Local void [NS]set_all_bits([NS]T *destination){ - if(!destination) return; - Digit *start = destination->d; - Digit *end = destination->d + [NS]DIGIT_COUNT; - for(Digit *p = start ; p < end ; p++){ - *p = (Digit)(-1); - } - } - - Local void [NS]set_msb([NS]T *destination){ - if(!destination) return; - [NS]set_zero(destination); - // Set top bit in the highest digit - destination->d[[NS]DIGIT_COUNT - 1] = ((Digit)1 << ((sizeof(Digit)*8) - 1)); - } - - // Bitwise - - Local void [NS]bit_and([NS]T *result ,[NS]T *a ,[NS]T *b){ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - result->d[i] = a->d[i] & b->d[i]; - } - } - - Local void [NS]bit_or([NS]T *result ,[NS]T *a ,[NS]T *b){ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - result->d[i] = a->d[i] | b->d[i]; - } - } - - Local void [NS]bit_complement([NS]T *result ,[NS]T *a){ - if(result == a){ - // same location - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - result->d[i] = ~result->d[i]; - } - }else{ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - result->d[i] = ~a->d[i]; - } - } - } - - Local void [NS]bit_twos_complement([NS]T *result ,[NS]T *a){ - // ~ + 1 across [NS]DIGIT_COUNT digits - // If result == a, we must do carefully - [NS]T temp; - if(result == a) { - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - temp.d[i] = ~a->d[i]; - } - }else{ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - temp.d[i] = ~a->d[i]; - } - } - // now add 1 - Digit carry = 1; - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - unsigned __int128 v = (unsigned __int128)temp.d[i] + carry; - temp.d[i] = (Digit)v; - carry = (Digit)(v >> (sizeof(Digit)*8)); - } - // copy back if needed - if(result == a){ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - a->d[i] = temp.d[i]; - } - }else{ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - result->d[i] = temp.d[i]; - } - } - } - - // Comparison - - Local [NS]Order [NS]compare([NS]T *a ,[NS]T *b){ - // compare from top to bottom - for(ExtentType i = [NS]DIGIT_COUNT; i > 0 ; i--){ - ExtentType idx = i - 1; - if(a->d[idx] < b->d[idx]) return [NS]Order_lt; - if(a->d[idx] > b->d[idx]) return [NS]Order_gt; - } - return [NS]Order_eq; - } - - Local bool [NS]eq([NS]T *a ,[NS]T *b){ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - if(a->d[i] != b->d[i]) return false; - } - return true; - } - - Local bool [NS]eq_zero([NS]T *a){ - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - if(a->d[i] != 0) return false; - } - return true; - } - - // Arithmetic - - Local [NS]Status [NS]add([NS]T *sum ,[NS]T *a ,[NS]T *b){ - if(!sum || !a || !b) return [NS]Status_overflow; - Digit carry = 0; - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - unsigned __int128 tmp = (unsigned __int128)a->d[i] + b->d[i] + carry; - sum->d[i] = (Digit)tmp; - carry = (Digit)(tmp >> (sizeof(Digit)*8)); - } - return (carry != 0) ? [NS]Status_carry : [NS]Status_ok; - } - - Local [NS]Status [NS]subtract([NS]T *diff ,[NS]T *a ,[NS]T *b){ - if(!diff || !a || !b) return [NS]Status_overflow; - Digit borrow = 0; - for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ - unsigned __int128 tmpA = a->d[i]; - unsigned __int128 tmpB = b->d[i] + borrow; - if(tmpA < tmpB){ - diff->d[i] = (Digit)((((unsigned __int128)1 << (sizeof(Digit)*8)) + tmpA) - tmpB); - borrow = 1; - }else{ - diff->d[i] = (Digit)(tmpA - tmpB); - borrow = 0; - } - } - return (borrow != 0) ? [NS]Status_borrow : [NS]Status_ok; - } - - // Conversion - - Local void [NS]from_uint64([NS]T *destination ,uint64_t value){ - if(!destination) return; - [NS]set_zero(destination); - // store 'value' in the low words - // note: if (DE + 1) < 2, we might only store partial - destination->d[0] = (Digit)(value & 0xFFFFFFFFFFFFFFFFULL); - #if DE >= 1 - if([NS]DIGIT_COUNT > 1){ - // store top half if digit is 32 bits etc, or 8 bits - // we'll just do partial logic if digit < 64 - // for 32-bit digit, that means the next digit has (value >> 32) - // for 8-bit digit, the next digits hold the rest, etc. - // We'll keep it simple. - // A more complete solution would loop if needed. - if(sizeof(Digit)*8 < 64){ - // multi-split if needed - // skipping for brevity - } - } - #endif - } - - #endif // LOCAL - -#endif // [NS]IMPLEMENTATION diff --git "a/developer/document\360\237\226\211/files.org" "b/developer/document\360\237\226\211/files.org" new file mode 100644 index 0000000..101b8e5 --- /dev/null +++ "b/developer/document\360\237\226\211/files.org" @@ -0,0 +1,4 @@ + +The currently the N{64,32,16,8} files make use of native types for 2x width accumulators. + +The generic multi-precision types with 0 digit array extent, will not have native types at 2x size but instead will use two digits. diff --git "a/developer/document\360\237\226\211/todo.org" "b/developer/document\360\237\226\211/todo.org" new file mode 100644 index 0000000..c69a1fd --- /dev/null +++ "b/developer/document\360\237\226\211/todo.org" @@ -0,0 +1,5 @@ + +* 2025-02-14T16:12:47Z new namespace names for the current `.lib_std` files. +done + +* 2025-02-14T16:20:52Z consider adding macros to replace multi-digit sequences with native types when available in some situations. diff --git a/developer/m4/N_template.lib.c.m4 b/developer/m4/N_template.lib.c.m4 new file mode 100644 index 0000000..cabe6b5 --- /dev/null +++ b/developer/m4/N_template.lib.c.m4 @@ -0,0 +1,318 @@ +changequote([,])dnl +define(NS, __NAMESPACE__)dnl +define(DE, __DIGIT_EXTENT__)dnl +define(DT, __DIGIT_TYPE__)dnl +define(ET, __EXTENT_TYPE__)dnl +changequote(`,')dnl + +/* + [NS] - Parametric multi-digit type library (RT code format) + + Parameters: + [NS]: Namespace prefix, e.g. N32· + [DE]: Digit extent => total digits = DE + 1 + [DT]: Digit type, e.g. uint64_t or uint8_t + [ET]: Loop counter type, e.g. uint64_t +*/ + +#define [NS]DEBUG + +#ifndef FACE + #define [NS]IMPLEMENTATION + #define FACE +#endif + +//------------------------------------------------------------------------------ +// Interface Section + +#ifndef [NS]FACE +#define [NS]FACE + + #include + #include + #include + #include + + // Digit count is DE + 1 + #define [NS]DIGIT_COUNT (DE + 1) + + typedef DT Digit; + typedef struct [NS]T [NS]T; + + // For array allocations + typedef ET ExtentType; + + // Status codes + typedef enum{ + [NS]Status_ok = 0 + ,[NS]Status_overflow + ,[NS]Status_accumulator1_overflow + ,[NS]Status_carry + ,[NS]Status_borrow + ,[NS]Status_undefined_divide_by_zero + ,[NS]Status_undefined_modulus_zero + ,[NS]Status_gt_max_shift_count + ,[NS]Status_spill_eq_operand + ,[NS]Status_one_word_product + ,[NS]Status_two_word_product + } [NS]Status; + + typedef enum{ + [NS]Order_lt = -1 + ,[NS]Order_eq = 0 + ,[NS]Order_gt = 1 + } [NS]Order; + + // Allocation + Digit *[NS]allocate_array(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)); + Digit *[NS]allocate_array_zero(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)); + void [NS]deallocate([NS]T *unencumbered); + + // Constant setters (no static global constants) + void [NS]set_zero([NS]T *destination); + void [NS]set_one([NS]T *destination); + void [NS]set_all_bits([NS]T *destination); + void [NS]set_msb([NS]T *destination); + + // Bitwise ops + void [NS]bit_and([NS]T *result ,[NS]T *a ,[NS]T *b); + void [NS]bit_or([NS]T *result ,[NS]T *a ,[NS]T *b); + void [NS]bit_complement([NS]T *result ,[NS]T *a); + void [NS]bit_twos_complement([NS]T *result ,[NS]T *a); + + // Comparison ops + bool [NS]eq([NS]T *a ,[NS]T *b); + bool [NS]eq_zero([NS]T *a); + [NS]Order [NS]compare([NS]T *a ,[NS]T *b); + + // Arithmetic + [NS]Status [NS]add([NS]T *sum ,[NS]T *a ,[NS]T *b); + [NS]Status [NS]subtract([NS]T *diff ,[NS]T *a ,[NS]T *b); + + // Conversions + void [NS]from_uint64([NS]T *destination ,uint64_t value); + +#endif // [NS]FACE + + +//------------------------------------------------------------------------------ +// Implementation Section + +#ifdef [NS]IMPLEMENTATION + + #ifndef LOCAL + + #include + #include + + struct [NS]T{ + Digit d[[NS]DIGIT_COUNT]; + }; + + Digit *[NS]allocate_array(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)){ + [NS]T *instance = malloc((extent + 1) * sizeof([NS]T)); + if(!instance){ + if(fault_handler) return (Digit*)fault_handler(extent); + return NULL; + } + return (Digit*)instance; + } + + Digit *[NS]allocate_array_zero(ExtentType extent ,[NS]T *(*fault_handler)(ExtentType)){ + [NS]T *instance = calloc(extent + 1 ,sizeof([NS]T)); + if(!instance){ + if(fault_handler) return (Digit*)fault_handler(extent); + return NULL; + } + return (Digit*)instance; + } + + void [NS]deallocate([NS]T *unencumbered){ + free(unencumbered); + } + + #endif // LOCAL not defined + + + #ifdef LOCAL + + // local code implementing everything + struct [NS]T{ + Digit d[[NS]DIGIT_COUNT]; + }; + + // Constant Setters + + Local void [NS]set_zero([NS]T *destination){ + if(!destination) return; + Digit *start = destination->d; + Digit *end = destination->d + [NS]DIGIT_COUNT; + for(Digit *p = start ; p < end ; p++){ + *p = 0; + } + } + + Local void [NS]set_one([NS]T *destination){ + if(!destination) return; + [NS]set_zero(destination); + destination->d[0] = 1; + } + + Local void [NS]set_all_bits([NS]T *destination){ + if(!destination) return; + Digit *start = destination->d; + Digit *end = destination->d + [NS]DIGIT_COUNT; + for(Digit *p = start ; p < end ; p++){ + *p = (Digit)(-1); + } + } + + Local void [NS]set_msb([NS]T *destination){ + if(!destination) return; + [NS]set_zero(destination); + // Set top bit in the highest digit + destination->d[[NS]DIGIT_COUNT - 1] = ((Digit)1 << ((sizeof(Digit)*8) - 1)); + } + + // Bitwise + + Local void [NS]bit_and([NS]T *result ,[NS]T *a ,[NS]T *b){ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + result->d[i] = a->d[i] & b->d[i]; + } + } + + Local void [NS]bit_or([NS]T *result ,[NS]T *a ,[NS]T *b){ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + result->d[i] = a->d[i] | b->d[i]; + } + } + + Local void [NS]bit_complement([NS]T *result ,[NS]T *a){ + if(result == a){ + // same location + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + result->d[i] = ~result->d[i]; + } + }else{ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + result->d[i] = ~a->d[i]; + } + } + } + + Local void [NS]bit_twos_complement([NS]T *result ,[NS]T *a){ + // ~ + 1 across [NS]DIGIT_COUNT digits + // If result == a, we must do carefully + [NS]T temp; + if(result == a) { + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + temp.d[i] = ~a->d[i]; + } + }else{ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + temp.d[i] = ~a->d[i]; + } + } + // now add 1 + Digit carry = 1; + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + unsigned __int128 v = (unsigned __int128)temp.d[i] + carry; + temp.d[i] = (Digit)v; + carry = (Digit)(v >> (sizeof(Digit)*8)); + } + // copy back if needed + if(result == a){ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + a->d[i] = temp.d[i]; + } + }else{ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + result->d[i] = temp.d[i]; + } + } + } + + // Comparison + + Local [NS]Order [NS]compare([NS]T *a ,[NS]T *b){ + // compare from top to bottom + for(ExtentType i = [NS]DIGIT_COUNT; i > 0 ; i--){ + ExtentType idx = i - 1; + if(a->d[idx] < b->d[idx]) return [NS]Order_lt; + if(a->d[idx] > b->d[idx]) return [NS]Order_gt; + } + return [NS]Order_eq; + } + + Local bool [NS]eq([NS]T *a ,[NS]T *b){ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + if(a->d[i] != b->d[i]) return false; + } + return true; + } + + Local bool [NS]eq_zero([NS]T *a){ + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + if(a->d[i] != 0) return false; + } + return true; + } + + // Arithmetic + + Local [NS]Status [NS]add([NS]T *sum ,[NS]T *a ,[NS]T *b){ + if(!sum || !a || !b) return [NS]Status_overflow; + Digit carry = 0; + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + unsigned __int128 tmp = (unsigned __int128)a->d[i] + b->d[i] + carry; + sum->d[i] = (Digit)tmp; + carry = (Digit)(tmp >> (sizeof(Digit)*8)); + } + return (carry != 0) ? [NS]Status_carry : [NS]Status_ok; + } + + Local [NS]Status [NS]subtract([NS]T *diff ,[NS]T *a ,[NS]T *b){ + if(!diff || !a || !b) return [NS]Status_overflow; + Digit borrow = 0; + for(ExtentType i = 0 ; i < [NS]DIGIT_COUNT ; i++){ + unsigned __int128 tmpA = a->d[i]; + unsigned __int128 tmpB = b->d[i] + borrow; + if(tmpA < tmpB){ + diff->d[i] = (Digit)((((unsigned __int128)1 << (sizeof(Digit)*8)) + tmpA) - tmpB); + borrow = 1; + }else{ + diff->d[i] = (Digit)(tmpA - tmpB); + borrow = 0; + } + } + return (borrow != 0) ? [NS]Status_borrow : [NS]Status_ok; + } + + // Conversion + + Local void [NS]from_uint64([NS]T *destination ,uint64_t value){ + if(!destination) return; + [NS]set_zero(destination); + // store 'value' in the low words + // note: if (DE + 1) < 2, we might only store partial + destination->d[0] = (Digit)(value & 0xFFFFFFFFFFFFFFFFULL); + #if DE >= 1 + if([NS]DIGIT_COUNT > 1){ + // store top half if digit is 32 bits etc, or 8 bits + // we'll just do partial logic if digit < 64 + // for 32-bit digit, that means the next digit has (value >> 32) + // for 8-bit digit, the next digits hold the rest, etc. + // We'll keep it simple. + // A more complete solution would loop if needed. + if(sizeof(Digit)*8 < 64){ + // multi-split if needed + // skipping for brevity + } + } + #endif + } + + #endif // LOCAL + +#endif // [NS]IMPLEMENTATION diff --git "a/developer/tool\360\237\226\211/make" "b/developer/tool\360\237\226\211/make" index 6b10a14..6ff2855 100755 --- "a/developer/tool\360\237\226\211/make" +++ "b/developer/tool\360\237\226\211/make" @@ -10,7 +10,7 @@ cd ${REPO_HOME}/developer # -D__EXTENT_TYPE__=uint64_t \ # src/N_template.lib.c.m4 > src/N128.lib.c -# m4 -D__NAMESPACE__=N32· -D__DIGIT_EXTENT__=0 -D__DIGIT_TYPE__=uint32_t -D__EXTENT_TYPE__=uint32_t cc🖉/N_template.lib.c.m4 > cc🖉N32.lib.c +# m4 -D__NAMESPACE__=N32· -D__DIGIT_EXTENT__=0 -D__DIGIT_TYPE__=uint32_t -D__EXTENT_TYPE__=uint32_t m4🖉/N_template.lib.c.m4 > cc/N32.lib.c /bin/make -f tool🖉/makefile $@