From f0ea0c065c9fa8e6af3eb721db1cdb8a8a297835 Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Sat, 15 Feb 2025 14:11:25 +0000 Subject: [PATCH] structured for testing --- .gitignore | 1 + "developer/cc\360\237\226\211/N16PN.lib.c" | 433 ++++++++++++++++ "developer/cc\360\237\226\211/N16n.lib.c" | 433 ---------------- "developer/cc\360\237\226\211/N32PN.lib.c" | 457 +++++++++++++++++ "developer/cc\360\237\226\211/N32n.lib.c" | 457 ----------------- "developer/cc\360\237\226\211/N64PN.lib.c" | 477 ++++++++++++++++++ "developer/cc\360\237\226\211/N64n.lib.c" | 477 ------------------ "developer/cc\360\237\226\211/N8PN.lib.c" | 433 ++++++++++++++++ "developer/cc\360\237\226\211/N8n.lib.c" | 433 ---------------- .../document\360\237\226\211/front_end.org" | 232 +++++++++ developer/{amd64 => example}/.githolder | 0 developer/m4/N_template.lib.c.m4 | 318 ------------ developer/machine/.gitignore | 2 + developer/python/N64.lib.c | 74 +++ developer/python/fill_template.py | 27 + developer/python/gen_N32_8_by_4.py | 27 + developer/python/gen_n64_lib.py | 21 + developer/python/get_template.py | 65 +++ developer/python/make_constants.py | 56 ++ "developer/tool\360\237\226\211/env" | 11 +- "developer/tool\360\237\226\211/make" | 25 +- "developer/tool\360\237\226\211/makefile" | 1 - "developer/tool\360\237\226\211/release" | 35 ++ .../#SectionApproach.org#" | 0 .../SectionApproach.org" | 121 ----- .../x86_64/fedora41/glibc_2.40/N16PN.lib.c | 433 ++++++++++++++++ .../x86_64/fedora41/glibc_2.40/N32PN.lib.c | 457 +++++++++++++++++ .../x86_64/fedora41/glibc_2.40/N64PN.lib.c | 477 ++++++++++++++++++ release/x86_64/fedora41/glibc_2.40/N8PN.lib.c | 433 ++++++++++++++++ release/x86_64/fedora41/glibc_2.40/libN.a | Bin 0 -> 16002 bytes tester/cc/N16PN.lib.c | 433 ++++++++++++++++ tester/cc/N32.lib.c | 457 +++++++++++++++++ tester/cc/N32PN.lib.c | 457 +++++++++++++++++ tester/cc/N64PN.lib.c | 477 ++++++++++++++++++ tester/cc/N8PN.lib.c | 433 ++++++++++++++++ "tester/cc\360\237\226\211/environment.h" | 5 + .../cc\360\237\226\211/test_N32.cli.c" | 0 "tester/cc\360\237\226\211/test_setup.cli.c" | 22 + tester/machine/.gitignore | 2 + tester/scratchpad/.gitignore | 2 + "tester/tool\360\237\226\211/env" | 42 ++ "tester/tool\360\237\226\211/make" | 20 + "tester/tool\360\237\226\211/makefile" | 18 + "tester/tool\360\237\226\211/pull_release" | 37 ++ "tester/tool\360\237\226\211/release_test" | 38 ++ "tool_shared/bespoke\360\237\226\211/env" | 38 ++ 46 files changed, 6641 insertions(+), 2256 deletions(-) create mode 100644 "developer/cc\360\237\226\211/N16PN.lib.c" delete mode 100644 "developer/cc\360\237\226\211/N16n.lib.c" create mode 100644 "developer/cc\360\237\226\211/N32PN.lib.c" delete mode 100644 "developer/cc\360\237\226\211/N32n.lib.c" create mode 100644 "developer/cc\360\237\226\211/N64PN.lib.c" delete mode 100644 "developer/cc\360\237\226\211/N64n.lib.c" create mode 100644 "developer/cc\360\237\226\211/N8PN.lib.c" delete mode 100644 "developer/cc\360\237\226\211/N8n.lib.c" create mode 100644 "developer/document\360\237\226\211/front_end.org" rename developer/{amd64 => example}/.githolder (100%) delete mode 100644 developer/m4/N_template.lib.c.m4 create mode 100644 developer/machine/.gitignore create mode 100644 developer/python/N64.lib.c create mode 100755 developer/python/fill_template.py create mode 100755 developer/python/gen_N32_8_by_4.py create mode 100755 developer/python/gen_n64_lib.py create mode 100755 developer/python/get_template.py create mode 100755 developer/python/make_constants.py create mode 100755 "developer/tool\360\237\226\211/release" delete mode 100644 "document\360\237\226\211/#SectionApproach.org#" create mode 100644 release/x86_64/fedora41/glibc_2.40/N16PN.lib.c create mode 100644 release/x86_64/fedora41/glibc_2.40/N32PN.lib.c create mode 100644 release/x86_64/fedora41/glibc_2.40/N64PN.lib.c create mode 100644 release/x86_64/fedora41/glibc_2.40/N8PN.lib.c create mode 100644 release/x86_64/fedora41/glibc_2.40/libN.a create mode 100644 tester/cc/N16PN.lib.c create mode 100644 tester/cc/N32.lib.c create mode 100644 tester/cc/N32PN.lib.c create mode 100644 tester/cc/N64PN.lib.c create mode 100644 tester/cc/N8PN.lib.c create mode 100644 "tester/cc\360\237\226\211/environment.h" rename "developer/cc\360\237\226\211/test_N32.cli.c" => "tester/cc\360\237\226\211/test_N32.cli.c" (100%) create mode 100644 "tester/cc\360\237\226\211/test_setup.cli.c" create mode 100644 tester/machine/.gitignore create mode 100644 tester/scratchpad/.gitignore create mode 100644 "tester/tool\360\237\226\211/env" create mode 100755 "tester/tool\360\237\226\211/make" create mode 100644 "tester/tool\360\237\226\211/makefile" create mode 100755 "tester/tool\360\237\226\211/pull_release" create mode 100755 "tester/tool\360\237\226\211/release_test" diff --git a/.gitignore b/.gitignore index bf925e3..c65f5b6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ #*# *~ +__pycache__ a.out .gradle/ diff --git "a/developer/cc\360\237\226\211/N16PN.lib.c" "b/developer/cc\360\237\226\211/N16PN.lib.c" new file mode 100644 index 0000000..d7a2e05 --- /dev/null +++ "b/developer/cc\360\237\226\211/N16PN.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 N16PN·DEBUG + +#ifndef FACE +#define N16PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N16PN·FACE +#define N16PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint16_t Extent; + typedef uint16_t Digit; + + typedef struct N16PN·T N16PN·T; + + extern N16PN·T *N16PN·zero; + extern N16PN·T *N16PN·one; + extern N16PN·T *N16PN·all_one_bit; + extern N16PN·T *N16PN·lsb; + extern N16PN·T *N16PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N16PN·Status·ok = 0 + ,N16PN·Status·overflow = 1 + ,N16PN·Status·accumulator1_overflow = 2 + ,N16PN·Status·carry = 3 + ,N16PN·Status·borrow = 4 + ,N16PN·Status·undefined_divide_by_zero = 5 + ,N16PN·Status·undefined_modulus_zero = 6 + ,N16PN·Status·gt_max_shift_count = 7 + ,N16PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N16PN·Status·one_word_product = 9 + ,N16PN·Status·two_word_product = 10 + } N16PN·Status; + + typedef enum{ + N16PN·Order_lt = -1 + ,N16PN·Order_eq = 0 + ,N16PN·Order_gt = 1 + } N16PN·Order; + + typedef N16PN·T *( *N16PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N16PN·T *(*allocate_array_zero)(Extent, N16PN·Allocate_MemoryFault); + N16PN·T *(*allocate_array)(Extent, N16PN·Allocate_MemoryFault); + void (*deallocate)(N16PN·T*); + + void (*copy)(N16PN·T*, N16PN·T*); + void (*bit_and)(N16PN·T*, N16PN·T*, N16PN·T*); + void (*bit_or)(N16PN·T*, N16PN·T*, N16PN·T*); + void (*bit_complement)(N16PN·T*, N16PN·T*); + void (*bit_twos_complement)(N16PN·T*, N16PN·T*); + N16PN·Order (*compare)(N16PN·T*, N16PN·T*); + bool (*lt)(N16PN·T*, N16PN·T*); + bool (*gt)(N16PN·T*, N16PN·T*); + bool (*eq)(N16PN·T*, N16PN·T*); + bool (*eq_zero)(N16PN·T*); + N16PN·Status (*accumulate)(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...); + N16PN·Status (*add)(N16PN·T*, N16PN·T*, N16PN·T*); + bool (*increment)(N16PN·T *a); + N16PN·Status (*subtract)(N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*multiply)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*divide)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*modulus)(N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*shift_left)(Extent, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*shift_right)(Extent, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*arithmetic_shift_right)(Extent, N16PN·T*, N16PN·T*); + + N16PN·T* (*access)(N16PN·T*, Extent); + void (*from_uint32)(N16PN·T *destination ,uint32_t value); + } N16PN·Λ; + + Local const N16PN·Λ N16PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N16PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N16PN·T{ + Digit d0; + }; + + N16PN·T N16PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint16_t)0}, + {.d0 = 1 << 15} + }; + + N16PN·T *N16PN·zero = &N16PN·constant[0]; + N16PN·T *N16PN·one = &N16PN·constant[1]; + N16PN·T *N16PN·all_one_bit = &N16PN·constant[2]; + N16PN·T *N16PN·msb = &N16PN·constant[3]; + N16PN·T *N16PN·lsb = &N16PN·constant[1]; + + // the allocate an array of N16 + N16PN·T *N16PN·allocate_array(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){ + N16PN·T *instance = malloc((extent + 1) * sizeof(N16PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N16PN·T *N16PN·allocate_array_zero(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){ + N16PN·T *instance = calloc(extent + 1, sizeof(N16PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N16PN·deallocate(N16PN·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N16PN·T{ + Digit d0; + }; + + // temporary variables + Local N16PN·T N16PN·t[4]; + + // allocation + + extern N16PN·T *N16PN·allocate_array(Extent, N16PN·Allocate_MemoryFault); + extern N16PN·T *N16PN·allocate_array_zero(Extent, N16PN·Allocate_MemoryFault); + extern void N16PN·deallocate(N16PN·T *); + + // so the user can access numbers in an array allocation + Local N16PN·T* N16PN·access(N16PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N16PN·from_uint32(N16PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint16_t)(value & 0xFFFF); + } + + // copy, convenience copy + + Local void N16PN·copy(N16PN·T *destination ,N16PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N16PN·set_to_zero(N16PN·T *instance){ + instance->d0 = 0; + } + + Local void N16PN·set_to_one(N16PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N16PN·bit_and(N16PN·T *result, N16PN·T *a, N16PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N16PN·bit_or(N16PN·T *result, N16PN·T *a, N16PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N16PN·bit_complement(N16PN·T *result, N16PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N16PN·bit_twos_complement(N16PN·T *result ,N16PN·T *a){ + result->d0 = (uint16_t)(~a->d0 + 1); + } + + // test functions + + Local N16PN·Order N16PN·compare(N16PN·T *a, N16PN·T *b){ + if(a->d0 < b->d0) return N16PN·Order_lt; + if(a->d0 > b->d0) return N16PN·Order_gt; + return N16PN·Order_eq; + } + + Local bool N16PN·lt(N16PN·T *a ,N16PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N16PN·gt(N16PN·T *a ,N16PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N16PN·eq(N16PN·T *a ,N16PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N16PN·eq_zero(N16PN·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N16PN·Status N16PN·accumulate(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N16PN·T *current; + + while( (current = va_arg(args ,N16PN·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N16PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint16_t)carry; + return N16PN·Status·ok; + } + + Local N16PN·Status N16PN·add(N16PN·T *sum ,N16PN·T *a ,N16PN·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint16_t)(result & 0xFFFF); + return (result >> 16) ? N16PN·Status·carry : N16PN·Status·ok; + } + + Local bool N16PN·increment(N16PN·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N16PN·Status N16PN·subtract(N16PN·T *difference ,N16PN·T *a ,N16PN·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint16_t)(diff & 0xFFFF); + return (diff > a->d0) ? N16PN·Status·borrow : N16PN·Status·ok; + } + + Local N16PN·Status N16PN·multiply(N16PN·T *product1 ,N16PN·T *product0 ,N16PN·T *a ,N16PN·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint16_t)(product & 0xFFFF); + product1->d0 = (uint16_t)((product >> 16) & 0xFFFF); + + if(product1->d0 == 0) return N16PN·Status·one_word_product; + return N16PN·Status·two_word_product; + } + + Local N16PN·Status N16PN·divide(N16PN·T *remainder ,N16PN·T *quotient ,N16PN·T *a ,N16PN·T *b){ + if(b->d0 == 0) return N16PN·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint16_t)(dividend / divisor); + remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor)); + + return N16PN·Status·ok; + } + + Local N16PN·Status N16PN·modulus(N16PN·T *remainder ,N16PN·T *a ,N16PN·T *b){ + if(b->d0 == 0) return N16PN·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint16_t)(dividend - (q * divisor)); + return N16PN·Status·ok; + } + + // bit motion + + typedef uint16_t (*ShiftOp)(uint16_t, uint16_t); + + Local uint16_t shift_left_op(uint16_t value, uint16_t amount){ + return value << amount; + } + + Local uint16_t shift_right_op(uint16_t value, uint16_t amount){ + return (uint16_t)(value >> amount); + } + + Local N16PN·Status N16PN·shift + ( + uint16_t shift_count + ,N16PN·T *spill + ,N16PN·T *operand + ,N16PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N16PN·Status·ok; + + if(operand == NULL){ + operand = &N16PN·t[0]; + N16PN·copy(operand, N16PN·zero); + } + + if(shift_count > 15) return N16PN·Status·gt_max_shift_count; + + N16PN·T *given_operand = &N16PN·t[1]; + N16PN·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (16 - shift_count)); + N16PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count)); + } + + return N16PN·Status·ok; + } + + Local N16PN·Status + N16PN·shift_left(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){ + return N16PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N16PN·Status + N16PN·shift_right(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){ + return N16PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N16PN·Status + N16PN·arithmetic_shift_right(uint16_t shift_count, N16PN·T *operand, N16PN·T *spill){ + + if(shift_count > 15) return N16PN·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N16PN·t[0]; + N16PN·copy(operand, N16PN·zero); + } + + N16PN·T *fill = (operand->d0 & 0x8000) ? N16PN·all_one_bit : N16PN·zero; + return N16PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N16PN·Λ N16PN·λ = { + + .allocate_array = N16PN·allocate_array + ,.allocate_array_zero = N16PN·allocate_array_zero + ,.deallocate = N16PN·deallocate + + ,.copy = N16PN·copy + ,.bit_and = N16PN·bit_and + ,.bit_or = N16PN·bit_or + ,.bit_complement = N16PN·bit_complement + ,.bit_twos_complement = N16PN·bit_twos_complement + ,.compare = N16PN·compare + ,.lt = N16PN·lt + ,.gt = N16PN·gt + ,.eq = N16PN·eq + ,.eq_zero = N16PN·eq_zero + ,.accumulate = N16PN·accumulate + ,.add = N16PN·add + ,.increment = N16PN·increment + ,.subtract = N16PN·subtract + ,.multiply = N16PN·multiply + ,.divide = N16PN·divide + ,.modulus = N16PN·modulus + ,.shift_left = N16PN·shift_left + ,.shift_right = N16PN·shift_right + ,.arithmetic_shift_right = N16PN·arithmetic_shift_right + + ,.access = N16PN·access + ,.from_uint32 = N16PN·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N16n.lib.c" "b/developer/cc\360\237\226\211/N16n.lib.c" deleted file mode 100644 index c28ab29..0000000 --- "a/developer/cc\360\237\226\211/N16n.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 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/N32PN.lib.c" "b/developer/cc\360\237\226\211/N32PN.lib.c" new file mode 100644 index 0000000..952f570 --- /dev/null +++ "b/developer/cc\360\237\226\211/N32PN.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 N32PN·DEBUG + +#ifndef FACE +#define N32PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N32PN·FACE +#define N32PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint32_t Extent; + typedef uint32_t Digit; + + typedef struct N32PN·T N32PN·T; + + extern N32PN·T *N32PN·zero; + extern N32PN·T *N32PN·one; + extern N32PN·T *N32PN·all_one_bit; + extern N32PN·T *N32PN·lsb; + extern N32PN·T *N32PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N32PN·Status·ok = 0 + ,N32PN·Status·overflow = 1 + ,N32PN·Status·accumulator1_overflow = 2 + ,N32PN·Status·carry = 3 + ,N32PN·Status·borrow = 4 + ,N32PN·Status·undefined_divide_by_zero = 5 + ,N32PN·Status·undefined_modulus_zero = 6 + ,N32PN·Status·gt_max_shift_count = 7 + ,N32PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N32PN·Status·one_word_product = 9 + ,N32PN·Status·two_word_product = 10 + } N32PN·Status; + + typedef enum{ + N32PN·Order_lt = -1 + ,N32PN·Order_eq = 0 + ,N32PN·Order_gt = 1 + } N32PN·Order; + + typedef N32PN·T *( *N32PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N32PN·T *(*allocate_array_zero)(Extent, N32PN·Allocate_MemoryFault); + N32PN·T *(*allocate_array)(Extent, N32PN·Allocate_MemoryFault); + void (*deallocate)(N32PN·T*); + + void (*copy)(N32PN·T*, N32PN·T*); + void (*bit_and)(N32PN·T*, N32PN·T*, N32PN·T*); + void (*bit_or)(N32PN·T*, N32PN·T*, N32PN·T*); + void (*bit_complement)(N32PN·T*, N32PN·T*); + void (*bit_twos_complement)(N32PN·T*, N32PN·T*); + N32PN·Order (*compare)(N32PN·T*, N32PN·T*); + bool (*lt)(N32PN·T*, N32PN·T*); + bool (*gt)(N32PN·T*, N32PN·T*); + bool (*eq)(N32PN·T*, N32PN·T*); + bool (*eq_zero)(N32PN·T*); + N32PN·Status (*accumulate)(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...); + N32PN·Status (*add)(N32PN·T*, N32PN·T*, N32PN·T*); + bool (*increment)(N32PN·T *a); + N32PN·Status (*subtract)(N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*multiply)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*divide)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*modulus)(N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*shift_left)(Extent, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*shift_right)(Extent, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*arithmetic_shift_right)(Extent, N32PN·T*, N32PN·T*); + + N32PN·T* (*access)(N32PN·T*, Extent); + void (*from_uint32)(N32PN·T *destination ,uint32_t value); + } N32PN·Λ; + + Local const N32PN·Λ N32PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N32PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N32PN·T{ + Digit d0; + }; + + N32PN·T N32PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint32_t)0}, + {.d0 = 1 << 31} + }; + + N32PN·T *N32PN·zero = &N32PN·constant[0]; + N32PN·T *N32PN·one = &N32PN·constant[1]; + N32PN·T *N32PN·all_one_bit = &N32PN·constant[2]; + N32PN·T *N32PN·msb = &N32PN·constant[3]; + N32PN·T *N32PN·lsb = &N32PN·constant[1]; + + // the allocate an array of N32 + N32PN·T *N32PN·allocate_array(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){ + N32PN·T *instance = malloc((extent + 1) * sizeof(N32PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N32PN·T *N32PN·allocate_array_zero(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){ + N32PN·T *instance = calloc( extent + 1 ,sizeof(N32PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N32PN·deallocate(N32PN·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N32PN·T{ + Digit d0; + }; + + // temporary variables + // making these LOCAL rather than reserving one block in the library is thread safe + // allocating a block once is more efficient + // library code writes these, they are not on the interface + + Local N32PN·T N32PN·t[4]; + + + // allocation + + extern N32PN·T *N32PN·allocate_array(Extent, N32PN·Allocate_MemoryFault); + extern N32PN·T *N32PN·allocate_array_zero(Extent, N32PN·Allocate_MemoryFault); + extern void N32PN·deallocate(N32PN·T *); + + // so the user can access numbers in an array allocation + Local N32PN·T* N32PN·access(N32PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N32PN·from_uint32(N32PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy, convenience copy + + Local void N32PN·copy(N32PN·T *destination ,N32PN·T *source){ + if(source == destination) return; // that was easy! + *destination = *source; + } + + Local void N32PN·set_to_zero(N32PN·T *instance){ + instance->d0 = 0; + } + + Local void N32PN·set_to_one(N32PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N32PN·bit_and(N32PN·T *result, N32PN·T *a, N32PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + // result can be one of the operands + Local void N32PN·bit_or(N32PN·T *result, N32PN·T *a, N32PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + // result can the same as the operand + Local void N32PN·bit_complement(N32PN·T *result, N32PN·T *a){ + result->d0 = ~a->d0; + } + + // result can the same as the operand + Local void N32PN·bit_twos_complement(N32PN·T *result ,N32PN·T *a){ + result->d0 = ~a->d0 + 1; + } + + // test functions + + Local N32PN·Order N32PN·compare(N32PN·T *a, N32PN·T *b){ + if(a->d0 < b->d0) return N32PN·Order_lt; + if(a->d0 > b->d0) return N32PN·Order_gt; + return N32PN·Order_eq; + } + + Local bool N32PN·lt(N32PN·T *a ,N32PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N32PN·gt(N32PN·T *a ,N32PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N32PN·eq(N32PN·T *a ,N32PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N32PN·eq_zero(N32PN·T *a){ + return a->d0 == 0; + } + + + // arithmetic operations + + // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32PN·Status·accumulator1_overflow + // + // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. + Local N32PN·Status N32PN·accumulate(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N32PN·T *current; + + while( (current = va_arg(args ,N32PN·T *)) ){ + sum += current->d0; + if(sum < current->d0){ // Accumulator1 into carry + (carry)++; + if(carry == 0){ + va_end(args); + return N32PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + // wipes out prior value of accumulator1 + accumulator1->d0 = carry; + + return N32PN·Status·ok; + } + + Local N32PN·Status N32PN·add(N32PN·T *sum ,N32PN·T *a ,N32PN·T *b){ + uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; + sum->d0 = (uint32_t)result; + return (result >> 32) ? N32PN·Status·carry : N32PN·Status·ok; + } + + Local bool N32PN·increment(N32PN·T *a){ + a->d0++; + return a->d0 == 0; + } + + Local N32PN·Status N32PN·subtract(N32PN·T *difference ,N32PN·T *a ,N32PN·T *b){ + uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; + difference->d0 = (uint32_t)diff; + return (diff > a->d0) ? N32PN·Status·borrow : N32PN·Status·ok; + } + + + Local N32PN·Status N32PN·multiply(N32PN·T *product1 ,N32PN·T *product0 ,N32PN·T *a ,N32PN·T *b){ + uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; + product0->d0 = (uint32_t)product; + product1->d0 = (uint32_t)(product >> 32); + + if(product1->d0 == 0) return N32PN·Status·one_word_product; + return N32PN·Status·two_word_product; + } + + Local N32PN·Status N32PN·divide(N32PN·T *remainder ,N32PN·T *quotient ,N32PN·T *a ,N32PN·T *b){ + if(b->d0 == 0) return N32PN·Status·undefined_divide_by_zero; + + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); + + return N32PN·Status·ok; + } + + Local N32PN·Status N32PN·modulus(N32PN·T *remainder ,N32PN·T *a ,N32PN·T *b){ + if(b->d0 == 0) return N32PN·Status·undefined_modulus_zero; + uint32_t quotient = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient * b->d0); + return N32PN·Status·ok; + } + + // bit motion + + typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); + + Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ + return value << amount; + } + + Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ + return value >> amount; + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, + Local N32PN·Status N32PN·shift + ( + uint32_t shift_count + ,N32PN·T *spill + ,N32PN·T *operand + ,N32PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + // If no result is needed, return immediately. + if(operand == NULL && spill == NULL) return N32PN·Status·ok; + + // Treat NULL operand as zero. + if(operand == NULL){ + operand = &N32PN·t[0]; + N32PN·copy(operand, N32PN·zero); + } + + // Shifting more than one word breaks our fill/spill model. + if(shift_count > 31) return N32PN·Status·gt_max_shift_count; + + // The given operand is still required after it is modified, so we copy it. + N32PN·T *given_operand = &N32PN·t[1]; + N32PN·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); + N32PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); + } + + return N32PN·Status·ok; + } + + // Define concrete shift functions using valid C function pointers + Local N32PN·Status + N32PN·shift_left(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){ + return N32PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N32PN·Status + N32PN·shift_right(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){ + return N32PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N32PN·Status + N32PN·arithmetic_shift_right(uint32_t shift_count, N32PN·T *operand, N32PN·T *spill){ + + // Guard against excessive shift counts + if(shift_count > 31) return N32PN·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N32PN·t[0]; + N32PN·copy(operand, N32PN·zero); + } + + // Pick the fill value based on the sign bit + N32PN·T *fill = (operand->d0 & 0x80000000) ? N32PN·all_one_bit : N32PN·zero; + + // Call shift_right with the appropriate fill + return N32PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N32PN·Λ N32PN·λ = { + + .allocate_array = N32PN·allocate_array + ,.allocate_array_zero = N32PN·allocate_array_zero + ,.deallocate = N32PN·deallocate + + ,.copy = N32PN·copy + ,.bit_and = N32PN·bit_and + ,.bit_or = N32PN·bit_or + ,.bit_complement = N32PN·bit_complement + ,.bit_twos_complement = N32PN·bit_twos_complement + ,.compare = N32PN·compare + ,.lt = N32PN·lt + ,.gt = N32PN·gt + ,.eq = N32PN·eq + ,.eq_zero = N32PN·eq_zero + ,.accumulate = N32PN·accumulate + ,.add = N32PN·add + ,.increment = N32PN·increment + ,.subtract = N32PN·subtract + ,.multiply = N32PN·multiply + ,.divide = N32PN·divide + ,.modulus = N32PN·modulus + ,.shift_left = N32PN·shift_left + ,.shift_right = N32PN·shift_right + ,.arithmetic_shift_right = N32PN·arithmetic_shift_right + + ,.access = N32PN·access + ,.from_uint32 = N32PN·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N32n.lib.c" "b/developer/cc\360\237\226\211/N32n.lib.c" deleted file mode 100644 index 7e12dfd..0000000 --- "a/developer/cc\360\237\226\211/N32n.lib.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 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/N64PN.lib.c" "b/developer/cc\360\237\226\211/N64PN.lib.c" new file mode 100644 index 0000000..583ad08 --- /dev/null +++ "b/developer/cc\360\237\226\211/N64PN.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 N64PN·DEBUG + +#ifndef FACE +#define N64PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N64PN·FACE +#define N64PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint64_t Extent; + typedef uint64_t Digit; + + typedef struct N64PN·T N64PN·T; + + extern N64PN·T *N64PN·zero; + extern N64PN·T *N64PN·one; + extern N64PN·T *N64PN·all_one_bit; + extern N64PN·T *N64PN·lsb; + extern N64PN·T *N64PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum { + N64PN·Status·ok = 0 + ,N64PN·Status·overflow = 1 + ,N64PN·Status·accumulator1_overflow = 2 + ,N64PN·Status·carry = 3 + ,N64PN·Status·borrow = 4 + ,N64PN·Status·undefined_divide_by_zero = 5 + ,N64PN·Status·undefined_modulus_zero = 6 + ,N64PN·Status·gt_max_shift_count = 7 + ,N64PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N64PN·Status·one_word_product = 9 + ,N64PN·Status·two_word_product = 10 + } N64PN·Status; + + typedef enum { + N64PN·Order_lt = -1 + ,N64PN·Order_eq = 0 + ,N64PN·Order_gt = 1 + } N64PN·Order; + + typedef N64PN·T *(*N64PN·Allocate_MemoryFault)(Extent); + + //---------------------------------------- + // Interface + + typedef struct { + + N64PN·T *(*allocate_array_zero)(Extent, N64PN·Allocate_MemoryFault); + N64PN·T *(*allocate_array)(Extent, N64PN·Allocate_MemoryFault); + void (*deallocate)(N64PN·T*); + + void (*copy)(N64PN·T*, N64PN·T*); + void (*bit_and)(N64PN·T*, N64PN·T*, N64PN·T*); + void (*bit_or)(N64PN·T*, N64PN·T*, N64PN·T*); + void (*bit_complement)(N64PN·T*, N64PN·T*); + void (*bit_twos_complement)(N64PN·T*, N64PN·T*); + N64PN·Order (*compare)(N64PN·T*, N64PN·T*); + bool (*lt)(N64PN·T*, N64PN·T*); + bool (*gt)(N64PN·T*, N64PN·T*); + bool (*eq)(N64PN·T*, N64PN·T*); + bool (*eq_zero)(N64PN·T*); + N64PN·Status (*accumulate)(N64PN·T *accumulator1, N64PN·T *accumulator0, ...); + N64PN·Status (*add)(N64PN·T*, N64PN·T*, N64PN·T*); + bool (*increment)(N64PN·T *a); + N64PN·Status (*subtract)(N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*multiply)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*divide)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*modulus)(N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*shift_left)(Extent, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*shift_right)(Extent, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*arithmetic_shift_right)(Extent, N64PN·T*, N64PN·T*); + + N64PN·T* (*access)(N64PN·T*, Extent); + void (*from_uint64)(N64PN·T *destination, uint64_t value); + + } N64PN·Λ; + + Local const N64PN·Λ N64PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N64PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N64PN·T { + Digit d0; + }; + + // For constants, we store them in an array for convenience + // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63) + N64PN·T N64PN·constant[4] = { + {.d0 = 0ULL}, + {.d0 = 1ULL}, + {.d0 = ~(uint64_t)0ULL}, + {.d0 = 1ULL << 63} + }; + + N64PN·T *N64PN·zero = &N64PN·constant[0]; + N64PN·T *N64PN·one = &N64PN·constant[1]; + N64PN·T *N64PN·all_one_bit = &N64PN·constant[2]; + N64PN·T *N64PN·msb = &N64PN·constant[3]; + N64PN·T *N64PN·lsb = &N64PN·constant[1]; + + // allocate an array of N64 + N64PN·T *N64PN·allocate_array(Extent extent, N64PN·Allocate_MemoryFault memory_fault){ + N64PN·T *instance = malloc( (extent + 1) * sizeof(N64PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N64PN·T *N64PN·allocate_array_zero(Extent extent, N64PN·Allocate_MemoryFault memory_fault){ + N64PN·T *instance = calloc(extent + 1, sizeof(N64PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N64PN·deallocate(N64PN·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N64PN·T { + Digit d0; + }; + + // local temporary variables + Local N64PN·T N64PN·t[4]; + + // allocation references + extern N64PN·T *N64PN·allocate_array(Extent, N64PN·Allocate_MemoryFault); + extern N64PN·T *N64PN·allocate_array_zero(Extent, N64PN·Allocate_MemoryFault); + extern void N64PN·deallocate(N64PN·T *); + + // Access array + Local N64PN·T* N64PN·access(N64PN·T *array, Extent index){ + return &array[index]; + } + + Local void N64PN·from_uint64(N64PN·T *destination, uint64_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy + Local void N64PN·copy(N64PN·T *destination, N64PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + // bit operations + + Local void N64PN·bit_and(N64PN·T *result, N64PN·T *a, N64PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N64PN·bit_or(N64PN·T *result, N64PN·T *a, N64PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N64PN·bit_complement(N64PN·T *result, N64PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N64PN·bit_twos_complement(N64PN·T *result, N64PN·T *a){ + result->d0 = ~a->d0 + 1ULL; + } + + // compare & test functions + + Local N64PN·Order N64PN·compare(N64PN·T *a, N64PN·T *b){ + if(a->d0 < b->d0) return N64PN·Order_lt; + if(a->d0 > b->d0) return N64PN·Order_gt; + return N64PN·Order_eq; + } + + Local bool N64PN·lt(N64PN·T *a, N64PN·T *b){ + return (a->d0 < b->d0); + } + + Local bool N64PN·gt(N64PN·T *a, N64PN·T *b){ + return (a->d0 > b->d0); + } + + Local bool N64PN·eq(N64PN·T *a, N64PN·T *b){ + return (a->d0 == b->d0); + } + + Local bool N64PN·eq_zero(N64PN·T *a){ + return (a->d0 == 0ULL); + } + + // arithmetic operations + + // accumulate + Local N64PN·Status N64PN·accumulate(N64PN·T *accumulator1, N64PN·T *accumulator0, ...){ + va_list args; + va_start(args, accumulator0); + + uint64_t sum = accumulator0->d0; + uint64_t carry = 0; + N64PN·T *current; + + while( (current = va_arg(args, N64PN·T*)) ){ + uint64_t prior = sum; + sum += current->d0; + if(sum < prior){ // indicates carry + carry++; + // if carry overflowed a 64-bit, that's an accumulator1 overflow + if(carry == 0ULL){ + va_end(args); + return N64PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = carry; + return N64PN·Status·ok; + } + + // add + Local N64PN·Status N64PN·add(N64PN·T *sum, N64PN·T *a, N64PN·T *b){ + __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0; + // But to avoid using a GNU extension, we can do the simpler approach: + // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits: + uint64_t temp = a->d0 + b->d0; + sum->d0 = temp; + if(temp < a->d0) return N64PN·Status·carry; // means we overflowed + return N64PN·Status·ok; + } + + Local bool N64PN·increment(N64PN·T *a){ + uint64_t old = a->d0; + a->d0++; + // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF + return (a->d0 < old); + } + + // subtract + Local N64PN·Status N64PN·subtract(N64PN·T *difference, N64PN·T *a, N64PN·T *b){ + uint64_t tmpA = a->d0; + uint64_t tmpB = b->d0; + uint64_t diff = tmpA - tmpB; + difference->d0 = diff; + if(diff > tmpA) return N64PN·Status·borrow; // indicates we borrowed + return N64PN·Status·ok; + } + + // multiply + // We'll do a 64x64->128 using two 64-bit accumulators + Local N64PN·Status N64PN·multiply(N64PN·T *product1, N64PN·T *product0, N64PN·T *a, N64PN·T *b){ + uint64_t A = a->d0; + uint64_t B = b->d0; + + // Break each operand into high & low 32 bits + uint64_t a_lo = (uint32_t)(A & 0xffffffffULL); + uint64_t a_hi = A >> 32; + uint64_t b_lo = (uint32_t)(B & 0xffffffffULL); + uint64_t b_hi = B >> 32; + + // partial products + uint64_t low = a_lo * b_lo; // 64-bit + uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits + uint64_t high = a_hi * b_hi; // up to 64 bits + + // incorporate cross into low, high + // cross is effectively the middle bits, so shift cross by 32 and add to low + uint64_t cross_low = (cross & 0xffffffffULL) << 32; // lower part + uint64_t cross_high = cross >> 32; // upper part + + // add cross_low to low, capture carry + uint64_t old_low = low; + low += cross_low; + if(low < old_low) cross_high++; + + // final high + high += cross_high; + + // store results + product0->d0 = low; + product1->d0 = high; + + if(high == 0ULL) return N64PN·Status·one_word_product; + return N64PN·Status·two_word_product; + } + + // divide + Local N64PN·Status N64PN·divide(N64PN·T *remainder, N64PN·T *quotient, N64PN·T *a, N64PN·T *b){ + // we do not handle a > 64-bit, just the single 64-bit + if(b->d0 == 0ULL) return N64PN·Status·undefined_divide_by_zero; + + uint64_t divd = a->d0; // dividend + uint64_t divs = b->d0; // divisor + + quotient->d0 = divd / divs; + remainder->d0 = divd - (quotient->d0 * divs); + + return N64PN·Status·ok; + } + + // modulus + Local N64PN·Status N64PN·modulus(N64PN·T *remainder, N64PN·T *a, N64PN·T *b){ + if(b->d0 == 0ULL) return N64PN·Status·undefined_modulus_zero; + + uint64_t divd = a->d0; + uint64_t divs = b->d0; + uint64_t q = divd / divs; + remainder->d0 = divd - (q * divs); + + return N64PN·Status·ok; + } + + // bit motion + + typedef uint64_t (*ShiftOp)(uint64_t, uint64_t); + + Local uint64_t shift_left_op(uint64_t value, uint64_t amount){ + return (value << amount); + } + + Local uint64_t shift_right_op(uint64_t value, uint64_t amount){ + return (value >> amount); + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill + Local N64PN·Status N64PN·shift + ( + uint64_t shift_count, + N64PN·T *spill, + N64PN·T *operand, + N64PN·T *fill, + ShiftOp shift_op, + ShiftOp complement_shift_op + ){ + if(operand == NULL && spill == NULL) return N64PN·Status·ok; + + // Treat NULL operand as zero + if(operand == NULL){ + operand = &N64PN·t[0]; + N64PN·copy(operand, N64PN·zero); + } + + // Shifting more than 63 bits breaks fill/spill logic + if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count; + + N64PN·T *given_operand = &N64PN·t[1]; + N64PN·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count)); + N64PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count)); + } + + return N64PN·Status·ok; + } + + Local N64PN·Status N64PN·shift_left(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){ + return N64PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N64PN·Status N64PN·shift_right(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){ + return N64PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N64PN·Status N64PN·arithmetic_shift_right(uint64_t shift_count, N64PN·T *operand, N64PN·T *spill){ + if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N64PN·t[0]; + N64PN·copy(operand, N64PN·zero); + } + + // sign bit check + N64PN·T *fill = (operand->d0 & (1ULL << 63)) ? N64PN·all_one_bit : N64PN·zero; + return N64PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N64PN·Λ N64PN·λ = { + .allocate_array = N64PN·allocate_array + ,.allocate_array_zero = N64PN·allocate_array_zero + ,.deallocate = N64PN·deallocate + + ,.copy = N64PN·copy + ,.bit_and = N64PN·bit_and + ,.bit_or = N64PN·bit_or + ,.bit_complement = N64PN·bit_complement + ,.bit_twos_complement = N64PN·bit_twos_complement + ,.compare = N64PN·compare + ,.lt = N64PN·lt + ,.gt = N64PN·gt + ,.eq = N64PN·eq + ,.eq_zero = N64PN·eq_zero + ,.accumulate = N64PN·accumulate + ,.add = N64PN·add + ,.increment = N64PN·increment + ,.subtract = N64PN·subtract + ,.multiply = N64PN·multiply + ,.divide = N64PN·divide + ,.modulus = N64PN·modulus + ,.shift_left = N64PN·shift_left + ,.shift_right = N64PN·shift_right + ,.arithmetic_shift_right = N64PN·arithmetic_shift_right + + ,.access = N64PN·access + ,.from_uint64 = N64PN·from_uint64 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N64n.lib.c" "b/developer/cc\360\237\226\211/N64n.lib.c" deleted file mode 100644 index 2521fef..0000000 --- "a/developer/cc\360\237\226\211/N64n.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 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/N8PN.lib.c" "b/developer/cc\360\237\226\211/N8PN.lib.c" new file mode 100644 index 0000000..9cfd66d --- /dev/null +++ "b/developer/cc\360\237\226\211/N8PN.lib.c" @@ -0,0 +1,433 @@ +/* + N8PN - PN = refers to the use of processor native accumulator + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N8PN·DEBUG + +#ifndef FACE +#define N8PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N8PN·FACE +#define N8PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint8_t Extent; + typedef uint8_t Digit; + + typedef struct N8PN·T N8PN·T; + + extern N8PN·T *N8PN·zero; + extern N8PN·T *N8PN·one; + extern N8PN·T *N8PN·all_one_bit; + extern N8PN·T *N8PN·lsb; + extern N8PN·T *N8PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N8PN·Status·ok = 0 + ,N8PN·Status·overflow = 1 + ,N8PN·Status·accumulator1_overflow = 2 + ,N8PN·Status·carry = 3 + ,N8PN·Status·borrow = 4 + ,N8PN·Status·undefined_divide_by_zero = 5 + ,N8PN·Status·undefined_modulus_zero = 6 + ,N8PN·Status·gt_max_shift_count = 7 + ,N8PN·Status·spill_eq_operand = 8 + ,N8PN·Status·one_word_product = 9 + ,N8PN·Status·two_word_product = 10 + } N8PN·Status; + + typedef enum{ + N8PN·Order_lt = -1 + ,N8PN·Order_eq = 0 + ,N8PN·Order_gt = 1 + } N8PN·Order; + + typedef N8PN·T *( *N8PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N8PN·T *(*allocate_array_zero)(Extent, N8PN·Allocate_MemoryFault); + N8PN·T *(*allocate_array)(Extent, N8PN·Allocate_MemoryFault); + void (*deallocate)(N8PN·T*); + + void (*copy)(N8PN·T*, N8PN·T*); + void (*bit_and)(N8PN·T*, N8PN·T*, N8PN·T*); + void (*bit_or)(N8PN·T*, N8PN·T*, N8PN·T*); + void (*bit_complement)(N8PN·T*, N8PN·T*); + void (*bit_twos_complement)(N8PN·T*, N8PN·T*); + N8PN·Order (*compare)(N8PN·T*, N8PN·T*); + bool (*lt)(N8PN·T*, N8PN·T*); + bool (*gt)(N8PN·T*, N8PN·T*); + bool (*eq)(N8PN·T*, N8PN·T*); + bool (*eq_zero)(N8PN·T*); + N8PN·Status (*accumulate)(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...); + N8PN·Status (*add)(N8PN·T*, N8PN·T*, N8PN·T*); + bool (*increment)(N8PN·T *a); + N8PN·Status (*subtract)(N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*multiply)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*divide)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*modulus)(N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*shift_left)(Extent, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*shift_right)(Extent, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*arithmetic_shift_right)(Extent, N8PN·T*, N8PN·T*); + + N8PN·T* (*access)(N8PN·T*, Extent); + void (*from_uint32)(N8PN·T *destination ,uint32_t value); + } N8PN·Λ; + + Local const N8PN·Λ N8PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N8PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N8PN·T{ + Digit d0; + }; + + N8PN·T N8PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint8_t)0}, + {.d0 = 1 << 7} + }; + + N8PN·T *N8PN·zero = &N8PN·constant[0]; + N8PN·T *N8PN·one = &N8PN·constant[1]; + N8PN·T *N8PN·all_one_bit = &N8PN·constant[2]; + N8PN·T *N8PN·msb = &N8PN·constant[3]; + N8PN·T *N8PN·lsb = &N8PN·constant[1]; + + // the allocate an array of N8 + N8PN·T *N8PN·allocate_array(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){ + N8PN·T *instance = malloc((extent + 1) * sizeof(N8PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N8PN·T *N8PN·allocate_array_zero(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){ + N8PN·T *instance = calloc(extent + 1, sizeof(N8PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N8PN·deallocate(N8PN·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N8PN·T{ + Digit d0; + }; + + // temporary variables + Local N8PN·T N8PN·t[4]; + + // allocation + + extern N8PN·T *N8PN·allocate_array(Extent, N8PN·Allocate_MemoryFault); + extern N8PN·T *N8PN·allocate_array_zero(Extent, N8PN·Allocate_MemoryFault); + extern void N8PN·deallocate(N8PN·T *); + + // so the user can access numbers in an array allocation + Local N8PN·T* N8PN·access(N8PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N8PN·from_uint32(N8PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint8_t)(value & 0xFF); + } + + // copy, convenience copy + + Local void N8PN·copy(N8PN·T *destination ,N8PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N8PN·set_to_zero(N8PN·T *instance){ + instance->d0 = 0; + } + + Local void N8PN·set_to_one(N8PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N8PN·bit_and(N8PN·T *result, N8PN·T *a, N8PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N8PN·bit_or(N8PN·T *result, N8PN·T *a, N8PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N8PN·bit_complement(N8PN·T *result, N8PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N8PN·bit_twos_complement(N8PN·T *result ,N8PN·T *a){ + result->d0 = (uint8_t)(~a->d0 + 1); + } + + // test functions + + Local N8PN·Order N8PN·compare(N8PN·T *a, N8PN·T *b){ + if(a->d0 < b->d0) return N8PN·Order_lt; + if(a->d0 > b->d0) return N8PN·Order_gt; + return N8PN·Order_eq; + } + + Local bool N8PN·lt(N8PN·T *a ,N8PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N8PN·gt(N8PN·T *a ,N8PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N8PN·eq(N8PN·T *a ,N8PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N8PN·eq_zero(N8PN·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N8PN·Status N8PN·accumulate(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N8PN·T *current; + + while( (current = va_arg(args ,N8PN·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N8PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint8_t)carry; + return N8PN·Status·ok; + } + + Local N8PN·Status N8PN·add(N8PN·T *sum ,N8PN·T *a ,N8PN·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint8_t)(result & 0xFF); + return (result >> 8) ? N8PN·Status·carry : N8PN·Status·ok; + } + + Local bool N8PN·increment(N8PN·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N8PN·Status N8PN·subtract(N8PN·T *difference ,N8PN·T *a ,N8PN·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint8_t)(diff & 0xFF); + return (diff > a->d0) ? N8PN·Status·borrow : N8PN·Status·ok; + } + + Local N8PN·Status N8PN·multiply(N8PN·T *product1 ,N8PN·T *product0 ,N8PN·T *a ,N8PN·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint8_t)(product & 0xFF); + product1->d0 = (uint8_t)((product >> 8) & 0xFF); + + if(product1->d0 == 0) return N8PN·Status·one_word_product; + return N8PN·Status·two_word_product; + } + + Local N8PN·Status N8PN·divide(N8PN·T *remainder ,N8PN·T *quotient ,N8PN·T *a ,N8PN·T *b){ + if(b->d0 == 0) return N8PN·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint8_t)(dividend / divisor); + remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor)); + + return N8PN·Status·ok; + } + + Local N8PN·Status N8PN·modulus(N8PN·T *remainder ,N8PN·T *a ,N8PN·T *b){ + if(b->d0 == 0) return N8PN·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint8_t)(dividend - (q * divisor)); + return N8PN·Status·ok; + } + + // bit motion + + typedef uint8_t (*ShiftOp)(uint8_t, uint8_t); + + Local uint8_t shift_left_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value << amount); + } + + Local uint8_t shift_right_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value >> amount); + } + + Local N8PN·Status N8PN·shift + ( + uint8_t shift_count + ,N8PN·T *spill + ,N8PN·T *operand + ,N8PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N8PN·Status·ok; + + if(operand == NULL){ + operand = &N8PN·t[0]; + N8PN·copy(operand, N8PN·zero); + } + + if(shift_count > 7) return N8PN·Status·gt_max_shift_count; + + N8PN·T *given_operand = &N8PN·t[1]; + N8PN·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (8 - shift_count)); + N8PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count)); + } + + return N8PN·Status·ok; + } + + Local N8PN·Status + N8PN·shift_left(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){ + return N8PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N8PN·Status + N8PN·shift_right(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){ + return N8PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N8PN·Status + N8PN·arithmetic_shift_right(uint8_t shift_count, N8PN·T *operand, N8PN·T *spill){ + + if(shift_count > 7) return N8PN·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N8PN·t[0]; + N8PN·copy(operand, N8PN·zero); + } + + N8PN·T *fill = (operand->d0 & 0x80) ? N8PN·all_one_bit : N8PN·zero; + return N8PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N8PN·Λ N8PN·λ = { + + .allocate_array = N8PN·allocate_array + ,.allocate_array_zero = N8PN·allocate_array_zero + ,.deallocate = N8PN·deallocate + + ,.copy = N8PN·copy + ,.bit_and = N8PN·bit_and + ,.bit_or = N8PN·bit_or + ,.bit_complement = N8PN·bit_complement + ,.bit_twos_complement = N8PN·bit_twos_complement + ,.compare = N8PN·compare + ,.lt = N8PN·lt + ,.gt = N8PN·gt + ,.eq = N8PN·eq + ,.eq_zero = N8PN·eq_zero + ,.accumulate = N8PN·accumulate + ,.add = N8PN·add + ,.increment = N8PN·increment + ,.subtract = N8PN·subtract + ,.multiply = N8PN·multiply + ,.divide = N8PN·divide + ,.modulus = N8PN·modulus + ,.shift_left = N8PN·shift_left + ,.shift_right = N8PN·shift_right + ,.arithmetic_shift_right = N8PN·arithmetic_shift_right + + ,.access = N8PN·access + ,.from_uint32 = N8PN·from_uint32 + }; + + #endif + +#endif diff --git "a/developer/cc\360\237\226\211/N8n.lib.c" "b/developer/cc\360\237\226\211/N8n.lib.c" deleted file mode 100644 index d2aaeb4..0000000 --- "a/developer/cc\360\237\226\211/N8n.lib.c" +++ /dev/null @@ -1,433 +0,0 @@ -/* - N8n - a processor native type - - For binary operations: a op b -> c - - See the document on the proper use of the Natural types. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) -*/ - -#define N8n·DEBUG - -#ifndef FACE -#define N8n·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef N8n·FACE -#define N8n·FACE - - #include - #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/document\360\237\226\211/front_end.org" "b/developer/document\360\237\226\211/front_end.org" new file mode 100644 index 0000000..b5ad881 --- /dev/null +++ "b/developer/document\360\237\226\211/front_end.org" @@ -0,0 +1,232 @@ +#+TITLE: Python-Based Template Generation (Multi-Module Approach) +#+AUTHOR: Example + +Below is a single Org-mode document containing **four** separate Python modules +(or scripts). Each code block is top-level (not nested), ensuring they render +correctly. Together, they demonstrate how to generate a parametric `.lib.c` file +for an RT code format library. + +1. **get_template.py**: Returns a base template with `{named_blank}` placeholders. +2. **make_constants.py**: Creates the compile-time constants block for zero, one, etc. +3. **fill_template.py**: Combines the template and constants block, substituting parameters. +4. **A "Main" generator script** (for instance, `gen_n64_lib.py`) that writes out a final file (like `N64.lib.c`). + +You can create additional “main” scripts to produce different `.lib.c` files (e.g., `N128.lib.c`). + +--- + +*1. `get_template.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +def get_template(): + """ + Returns the base RT C code template, with placeholders like: + {NAMESPACE}, {DIGIT_EXTENT}, {DIGIT_TYPE}, {EXTENT_TYPE}, {CONSTANTS_BLOCK}. + + The final generated .lib.c will replace these with user-specified values. + """ + return r'''#define {NAMESPACE}DEBUG + +#ifndef FACE + #define {NAMESPACE}IMPLEMENTATION + #define FACE +#endif + +#ifndef {NAMESPACE}FACE +#define {NAMESPACE}FACE + + #include + #include + #include + #include + + typedef {EXTENT_TYPE} ExtentType; + typedef {DIGIT_TYPE} Digit; + + // Digit count is (DIGIT_EXTENT + 1) + #define {NAMESPACE}DIGIT_COUNT ( {DIGIT_EXTENT} + 1 ) + + typedef struct {NAMESPACE}T{{ + Digit d[{NAMESPACE}DIGIT_COUNT]; + }} {NAMESPACE}T; + + // forward declarations for constants + extern {NAMESPACE}T *{NAMESPACE}zero; + extern {NAMESPACE}T *{NAMESPACE}one; + extern {NAMESPACE}T *{NAMESPACE}all_one_bit; + extern {NAMESPACE}T *{NAMESPACE}msb; + + // forward declarations for allocations, etc. + +#endif // {NAMESPACE}FACE + +#ifdef {NAMESPACE}IMPLEMENTATION + +#ifndef LOCAL + #include + #include + + // compile-time constants + {CONSTANTS_BLOCK} + + {NAMESPACE}T *{NAMESPACE}zero = &{NAMESPACE}constant[0]; + {NAMESPACE}T *{NAMESPACE}one = &{NAMESPACE}constant[1]; + {NAMESPACE}T *{NAMESPACE}all_one_bit = &{NAMESPACE}constant[2]; + {NAMESPACE}T *{NAMESPACE}msb = &{NAMESPACE}constant[3]; + + // memory allocation prototypes, etc. + +#endif // not LOCAL + +#ifdef LOCAL + // local code: actual function bodies, add, subtract, etc. +#endif // LOCAL + +#endif // {NAMESPACE}IMPLEMENTATION +''' +#+END_SRC + +--- + +*2. `make_constants.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +def make_constants_block(namespace: str, + digit_type: str, + digit_extent: int) -> str: + """ + Returns a block of code defining static compile-time constants: + static {namespace}T {namespace}constant[4] = { + { { ...zero... } }, + { { ...one... } }, + { { ...allbits... } }, + { { ...msb... } } + }; + + The total digit count is digit_extent + 1. + """ + digit_count = digit_extent + 1 + + def digits_zero(): + return ", ".join("0" for _ in range(digit_count)) + + def digits_one(): + # index 0 => 1, rest => 0 + return ", ".join("1" if i == 0 else "0" for i in range(digit_count)) + + def digits_allbits(): + # each digit => (digit_type)(-1) + return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count)) + + def digits_msb(): + # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1) + items = [] + for i in range(digit_count): + if i == digit_count - 1: + items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)") + else: + items.append("0") + return ", ".join(items) + + return f'''\ +static {namespace}T {namespace}constant[4] = {{ + {{ + // zero + {{ {digits_zero()} }} + }}, + {{ + // one + {{ {digits_one()} }} + }}, + {{ + // all bits + {{ {digits_allbits()} }} + }}, + {{ + // msb + {{ {digits_msb()} }} + }} +}};''' + +#+END_SRC + +--- + +*3. `fill_template.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +from get_template import get_template +from make_constants import make_constants_block + +def fill_template(namespace: str, + digit_extent: int, + digit_type: str, + extent_type: str) -> str: + """ + Renders the final .lib.c code by merging: + - the base template from get_template() + - the compile-time constants block from make_constants_block() + - placeholders for namespace, digit_extent, digit_type, extent_type + """ + template = get_template() + constants_block = make_constants_block(namespace, digit_type, digit_extent) + + # Substitute placeholders + code = template.format( + NAMESPACE = namespace, + DIGIT_EXTENT = digit_extent, + DIGIT_TYPE = digit_type, + EXTENT_TYPE = extent_type, + CONSTANTS_BLOCK = constants_block + ) + return code +#+END_SRC + +--- + +*4. An Example “Main” Script, `gen_n64_lib.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +import sys +from fill_template import fill_template + +def main(): + """ + Example: generate a .lib.c with an 'N64·' namespace, + digit_extent=0 => 1 digit total, + digit_type='uint32_t', + extent_type='uint64_t'. + """ + code = fill_template( + namespace = "N64·", + digit_extent = 0, # => digit_count = 1 => 32-bit + digit_type = "uint32_t", + extent_type = "uint64_t" + ) + + with open("N64.lib.c", "w") as f: + f.write(code) + print("Generated N64.lib.c") + +if __name__ == "__main__": + main() +#+END_SRC + +--- + +### Usage + +1. **Place** these four files side-by-side in your project (e.g., a `scripts/` directory). +2. **Mark** them as executable (`chmod +x`). +3. **Run** `./gen_n64_lib.py` to produce `N64.lib.c`. This file will appear in the same directory (or wherever you prefer). +4. **Compile** `N64.lib.c` using your RT C build system (`make -f tool🖉/makefile`, etc.). + +You can then create similar scripts like `gen_n128_lib.py` or unify them into a single driver that takes parameters for namespace, digit_extent, etc. The main advantage is that **Python code** for generating constants is much more readable than M4 macros, and you keep the RT code format in your template exactly as it should appear. diff --git a/developer/amd64/.githolder b/developer/example/.githolder similarity index 100% rename from developer/amd64/.githolder rename to developer/example/.githolder diff --git a/developer/m4/N_template.lib.c.m4 b/developer/m4/N_template.lib.c.m4 deleted file mode 100644 index cabe6b5..0000000 --- a/developer/m4/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/machine/.gitignore b/developer/machine/.gitignore new file mode 100644 index 0000000..120f485 --- /dev/null +++ b/developer/machine/.gitignore @@ -0,0 +1,2 @@ +* +!/.gitignore diff --git a/developer/python/N64.lib.c b/developer/python/N64.lib.c new file mode 100644 index 0000000..8827b35 --- /dev/null +++ b/developer/python/N64.lib.c @@ -0,0 +1,74 @@ +#define N64·DEBUG + +#ifndef FACE + #define N64·IMPLEMENTATION + #define FACE +#endif + +#ifndef N64·FACE +#define N64·FACE + + #include + #include + #include + #include + + typedef uint8_t Digit; + + // Digit count is (DIGIT_EXTENT + 1) + #define N64·DIGIT_COUNT ( 8 + 1 ) + + typedef struct N64·T{ + Digit d[N64·DIGIT_COUNT]; + } N64·T; + + // forward declarations for constants + extern N64·T *N64·zero; + extern N64·T *N64·one; + extern N64·T *N64·all_one_bit; + extern N64·T *N64·msb; + + // forward declarations for allocations, etc. + +#endif // N64·FACE + +#ifdef N64·IMPLEMENTATION + +#ifndef LOCAL + #include + #include + + // compile-time constants + static N64·T N64·constant[4] = { + { + // zero + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + // one + { 1, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + // all one bits + { ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ), ( uint8_t )( -1 ) } + }, + { + // msb + { 0, 0, 0, 0, 0, 0, 0, 0, ( uint8_t )1 << ((sizeof(uint8_t)*8) - 1) } + } +}; + + N64·T *N64·zero = &N64·constant[0]; + N64·T *N64·one = &N64·constant[1]; + N64·T *N64·all_one_bit = &N64·constant[2]; + N64·T *N64·msb = &N64·constant[3]; + + // memory allocation prototypes, etc. + +#endif // not LOCAL + +#ifdef LOCAL + // local code: actual function bodies, add, subtract, etc. +#endif // LOCAL + +#endif // N64·IMPLEMENTATION diff --git a/developer/python/fill_template.py b/developer/python/fill_template.py new file mode 100755 index 0000000..bf73da9 --- /dev/null +++ b/developer/python/fill_template.py @@ -0,0 +1,27 @@ +#+BEGIN_SRC python +#!/usr/bin/env python3 + +from get_template import get_template +from make_constants import make_constants_block + +def fill_template(namespace: str, + digit_extent: int, + digit_type: str) -> str: + """ + Renders the final .lib.c code by merging: + - the base template from get_template() + - the compile-time constants block from make_constants_block() + - placeholders for namespace, digit_extent, digit_type, extent_type + """ + template = get_template() + constants_block = make_constants_block(namespace, digit_type, digit_extent) + + # Substitute placeholders + code = template.format( + NAMESPACE = namespace, + DIGIT_EXTENT = digit_extent, + DIGIT_TYPE = digit_type, + CONSTANTS_BLOCK = constants_block + ) + return code +#+END_SRC diff --git a/developer/python/gen_N32_8_by_4.py b/developer/python/gen_N32_8_by_4.py new file mode 100755 index 0000000..22ef30e --- /dev/null +++ b/developer/python/gen_N32_8_by_4.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +import sys +from fill_template import fill_template + +def main(): + """ + Example: generate an N.lib.c + """ + + type_name = "N32"; + + # 4 x 8 bit + code = fill_template( + namespace = type_name + "·", + digit_extent = 3, + digit_type = "uint8_t", + ) + + + filename = "../cc/" + type_name + ".lib.c" + with open(filename, "w") as f: + f.write(code) + print("Generated " + filename) + +if __name__ == "__main__": + main() diff --git a/developer/python/gen_n64_lib.py b/developer/python/gen_n64_lib.py new file mode 100755 index 0000000..6288b1d --- /dev/null +++ b/developer/python/gen_n64_lib.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +import sys +from fill_template import fill_template + +def main(): + """ + Example: generate a .lib.c with an 'N64·' namespace, + """ + code = fill_template( + namespace = "N64·", + digit_extent = 8, # => digit_count = 1 => 32-bit + digit_type = "uint8_t", + ) + + with open("N64.lib.c", "w") as f: + f.write(code) + print("Generated N64.lib.c") + +if __name__ == "__main__": + main() diff --git a/developer/python/get_template.py b/developer/python/get_template.py new file mode 100755 index 0000000..a25336b --- /dev/null +++ b/developer/python/get_template.py @@ -0,0 +1,65 @@ +def get_template(): + """ + Returns the base RT C code template, with placeholders like: + {NAMESPACE}, {DIGIT_EXTENT}, {DIGIT_TYPE}, {EXTENT_TYPE}, {CONSTANTS_BLOCK}. + + The final generated .lib.c will replace these with user-specified values. + """ + return r'''#define {NAMESPACE}DEBUG + +#ifndef FACE + #define {NAMESPACE}IMPLEMENTATION + #define FACE +#endif + +#ifndef {NAMESPACE}FACE +#define {NAMESPACE}FACE + + #include + #include + #include + #include + + typedef {DIGIT_TYPE} Digit; + + // Digit count is (DIGIT_EXTENT + 1) + #define {NAMESPACE}DIGIT_COUNT ( {DIGIT_EXTENT} + 1 ) + + typedef struct {NAMESPACE}T{{ + Digit d[{NAMESPACE}DIGIT_COUNT]; + }} {NAMESPACE}T; + + // forward declarations for constants + extern {NAMESPACE}T *{NAMESPACE}zero; + extern {NAMESPACE}T *{NAMESPACE}one; + extern {NAMESPACE}T *{NAMESPACE}all_one_bit; + extern {NAMESPACE}T *{NAMESPACE}msb; + + // forward declarations for allocations, etc. + +#endif // {NAMESPACE}FACE + +#ifdef {NAMESPACE}IMPLEMENTATION + +#ifndef LOCAL + #include + #include + + // compile-time constants + {CONSTANTS_BLOCK} + + {NAMESPACE}T *{NAMESPACE}zero = &{NAMESPACE}constant[0]; + {NAMESPACE}T *{NAMESPACE}one = &{NAMESPACE}constant[1]; + {NAMESPACE}T *{NAMESPACE}all_one_bit = &{NAMESPACE}constant[2]; + {NAMESPACE}T *{NAMESPACE}msb = &{NAMESPACE}constant[3]; + + // memory allocation prototypes, etc. + +#endif // not LOCAL + +#ifdef LOCAL + // local code: actual function bodies, add, subtract, etc. +#endif // LOCAL + +#endif // {NAMESPACE}IMPLEMENTATION +''' diff --git a/developer/python/make_constants.py b/developer/python/make_constants.py new file mode 100755 index 0000000..a177fde --- /dev/null +++ b/developer/python/make_constants.py @@ -0,0 +1,56 @@ +def make_constants_block(namespace: str, + digit_type: str, + digit_extent: int) -> str: + """ + Returns a block of code defining static compile-time constants: + static {namespace}T {namespace}constant[4] = { + { { ...zero... } }, + { { ...one... } }, + { { ...allbits... } }, + { { ...msb... } } + }; + + The total digit count is digit_extent + 1. + """ + digit_count = digit_extent + 1 + + def digits_zero(): + return ", ".join("0" for _ in range(digit_count)) + + def digits_one(): + # index 0 => 1, rest => 0 + return ", ".join("1" if i == 0 else "0" for i in range(digit_count)) + + def digits_allbits(): + # each digit => (digit_type)(-1) + return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count)) + + def digits_msb(): + # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1) + items = [] + for i in range(digit_count): + if i == digit_count - 1: + items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)") + else: + items.append("0") + return ", ".join(items) + + return f'''\ +static {namespace}T {namespace}constant[4] = {{ + {{ + // zero + {{ {digits_zero()} }} + }}, + {{ + // one + {{ {digits_one()} }} + }}, + {{ + // all one bits + {{ {digits_allbits()} }} + }}, + {{ + // msb + {{ {digits_msb()} }} + }} +}};''' diff --git "a/developer/tool\360\237\226\211/env" "b/developer/tool\360\237\226\211/env" index f9e2584..dfca640 100644 --- "a/developer/tool\360\237\226\211/env" +++ "b/developer/tool\360\237\226\211/env" @@ -17,10 +17,13 @@ script_afp=$(realpath "${BASH_SOURCE[0]}") if $error_not_sourced; then exit 1; fi if $error_bad_env; then return 1; fi + +export ROLE=developer + # so we can do the build export PATH=\ -"$REPO_HOME"/developer/tool🖉/\ +"$REPO_HOME"/${ROLE}/tool🖉/\ :"$PATH" # misc @@ -30,10 +33,8 @@ export PATH=\ # some feedback to show all went well - export PROMPT_DECOR="$PROJECT"_developer + export PROMPT_DECOR="$PROJECT_$ROLE" export ENV=$(script_fp) echo ENV "$ENV" - cd "$REPO_HOME"/developer/ - - + cd "$REPO_HOME/$ROLE" diff --git "a/developer/tool\360\237\226\211/make" "b/developer/tool\360\237\226\211/make" index 6ff2855..0df0712 100755 --- "a/developer/tool\360\237\226\211/make" +++ "b/developer/tool\360\237\226\211/make" @@ -1,17 +1,20 @@ -#!/bin/env /bin/bash +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") -set -e -cd ${REPO_HOME}/developer +# input guards -# # Example m4 invocation: -# m4 -D__NAMESPACE__=N128· \ -# -D__DIGIT_EXTENT__=1 \ -# -D__DIGIT_TYPE__=uint64_t \ -# -D__EXTENT_TYPE__=uint64_t \ -# src/N_template.lib.c.m4 > src/N128.lib.c + env_must_be="developer/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi -# m4 -D__NAMESPACE__=N32· -D__DIGIT_EXTENT__=0 -D__DIGIT_TYPE__=uint32_t -D__EXTENT_TYPE__=uint32_t m4🖉/N_template.lib.c.m4 > cc/N32.lib.c +set -e +set -x + cd "$REPO_HOME"/developer || exit 1 -/bin/make -f tool🖉/makefile $@ + /bin/make -f tool🖉/makefile $@ +set +x +echo "$(script_fn) done." diff --git "a/developer/tool\360\237\226\211/makefile" "b/developer/tool\360\237\226\211/makefile" index a0da057..64bb614 100644 --- "a/developer/tool\360\237\226\211/makefile" +++ "b/developer/tool\360\237\226\211/makefile" @@ -1,5 +1,4 @@ - RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release include $(RT-INCOMMON)/make/environment_RT_0 diff --git "a/developer/tool\360\237\226\211/release" "b/developer/tool\360\237\226\211/release" new file mode 100755 index 0000000..feb8bcf --- /dev/null +++ "b/developer/tool\360\237\226\211/release" @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# before running this, make library is built and is in the scratchpad directory + +# input guards + + env_must_be="developer/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + cd "$REPO_HOME"/developer || exit 1 + + if [ ! -d scratchpad ]; then + echo "$(script_fp):: no scratchpad directory" + exit 1 + fi + + release_dir=$(release_dir) + mkdir -p ${release_dir} + + install_file scratchpad/libN.a ${release_dir} "ug+r" + + # header files + install_file {cc,cc🖉}/*.lib.c ${release_dir} "ug+r" + + +set +x +echo "$(script_fn) done." + diff --git "a/document\360\237\226\211/#SectionApproach.org#" "b/document\360\237\226\211/#SectionApproach.org#" deleted file mode 100644 index e69de29..0000000 diff --git "a/document\360\237\226\211/SectionApproach.org" "b/document\360\237\226\211/SectionApproach.org" index 7cb4a1f..e69de29 100644 --- "a/document\360\237\226\211/SectionApproach.org" +++ "b/document\360\237\226\211/SectionApproach.org" @@ -1,121 +0,0 @@ -#+TITLE: Sectioned Single-File Format -#+AUTHOR: RT C Documentation Team -#+OPTIONS: toc:2 - -* Overview -The sectioned single-file format provides a structured way to define a library in C, -keeping all relevant code in a single file while ensuring proper separation between -interface, implementation, and local static definitions. This approach avoids -the common “.h + .c” split and instead uses conditional compilation blocks -to expose only the needed parts. - -** Key Definitions -- =IFACE=: A preprocessor symbol indicating we want to expose the library’s interface. -- =LOCAL=: A preprocessor symbol indicating we want to expose static (private) helper code. -- *Implementation (no symbol defined)*: The default, containing the shared implementation - of the library. - -** File Layout -A typical =.lib.c= file has three sections: - -1. *Interface Section* - Guarded by: - #+begin_src c - #ifndef NNN·FACE - #define NNN·FACE - // public typedefs, function declarations - // ... - #endif - #+end_src - - Here, “=NNN=” is the library name (e.g., =N32=). - You include this section in another file using: - #+begin_src c - #define IFACE - #include "my_library.lib.c" - #undef IFACE - #+end_src - -2. *Implementation Section* - Defined when *neither* =IFACE= nor =LOCAL= is set. This is the main, global - portion of the library code that will be compiled into an object - (or archived into a static library): - #+begin_src c - #ifdef NNN·IMPLEMENTATION - // Implementation code - // ... - #endif - #+end_src - - The build system compiles this =.lib.c= without =IFACE= or =LOCAL= defined - to produce the main library object. - -3. *Local (Static) Section* - Guarded by: - #+begin_src c - #ifdef LOCAL - // In-library static declarations or definitions - // ... - #endif - #end_src - - This block is typically included after the user code, letting you inline or - define “private” helper functions that only the user’s code should see - (in order to be optimized away if not used, for instance). - -** Why This Matters -- *Single Source of Truth*: Instead of maintaining separate header and source files, - everything for a module is in one place. -- *Automatic Inlining*: In a traditional setup, “private” static functions would - live in the .c file and be invisible for cross-module inlining. With the local - section, the compiler sees everything when the user includes it, enabling more - optimizations. -- *Reduced Mismatch Errors*: There’s zero chance your header becomes out-of-sync - with the .c file because they’re literally the same file, gated by preprocessor macros. -- *Cleaner Build Scripts*: The library is compiled once with the default macros. - Tests or command-line programs that need the local portion define =LOCAL= or =IFACE= - as needed. - -** Example Usage -1. *Library Compilation* - #+begin_src bash - # No defines set: - $CC -c my_library.lib.c -o my_library.lib.o - #+end_src - -2. *Including the Interface in Another Source* - #+begin_src c - #define IFACE - #include "my_library.lib.c" - #undef IFACE - - int main(){ - // Now we have the function declarations from the interface - // ... - } - #+end_src - -3. *Including the Local Section* - #+begin_src c - #define LOCAL - #include "my_library.lib.c" - #undef LOCAL - - // We can now use certain static or inline-like helpers - // ... - #+end_src - -** Makefile Integration -The provided Makefile snippet shows how to compile =.lib.c= files separately, -then link them. The key is to define no macros (like =IFACE= or =LOCAL=) -when building the library, ensuring you get only the “Implementation Section.” - -For a command-line interface (CLI) or test harness, you can then define =IFACE= -or =LOCAL= before including the =.lib.c= to access the library’s interface -(or private/local stuff) on an as-needed basis. - -* Conclusion -This method elegantly encapsulates a module’s interface, its global -implementation, and its private helper code in a single file. It integrates -nicely with existing make-based build systems and fosters a clear separation -of concerns with minimal overhead or confusion. diff --git a/release/x86_64/fedora41/glibc_2.40/N16PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N16PN.lib.c new file mode 100644 index 0000000..d7a2e05 --- /dev/null +++ b/release/x86_64/fedora41/glibc_2.40/N16PN.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 N16PN·DEBUG + +#ifndef FACE +#define N16PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N16PN·FACE +#define N16PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint16_t Extent; + typedef uint16_t Digit; + + typedef struct N16PN·T N16PN·T; + + extern N16PN·T *N16PN·zero; + extern N16PN·T *N16PN·one; + extern N16PN·T *N16PN·all_one_bit; + extern N16PN·T *N16PN·lsb; + extern N16PN·T *N16PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N16PN·Status·ok = 0 + ,N16PN·Status·overflow = 1 + ,N16PN·Status·accumulator1_overflow = 2 + ,N16PN·Status·carry = 3 + ,N16PN·Status·borrow = 4 + ,N16PN·Status·undefined_divide_by_zero = 5 + ,N16PN·Status·undefined_modulus_zero = 6 + ,N16PN·Status·gt_max_shift_count = 7 + ,N16PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N16PN·Status·one_word_product = 9 + ,N16PN·Status·two_word_product = 10 + } N16PN·Status; + + typedef enum{ + N16PN·Order_lt = -1 + ,N16PN·Order_eq = 0 + ,N16PN·Order_gt = 1 + } N16PN·Order; + + typedef N16PN·T *( *N16PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N16PN·T *(*allocate_array_zero)(Extent, N16PN·Allocate_MemoryFault); + N16PN·T *(*allocate_array)(Extent, N16PN·Allocate_MemoryFault); + void (*deallocate)(N16PN·T*); + + void (*copy)(N16PN·T*, N16PN·T*); + void (*bit_and)(N16PN·T*, N16PN·T*, N16PN·T*); + void (*bit_or)(N16PN·T*, N16PN·T*, N16PN·T*); + void (*bit_complement)(N16PN·T*, N16PN·T*); + void (*bit_twos_complement)(N16PN·T*, N16PN·T*); + N16PN·Order (*compare)(N16PN·T*, N16PN·T*); + bool (*lt)(N16PN·T*, N16PN·T*); + bool (*gt)(N16PN·T*, N16PN·T*); + bool (*eq)(N16PN·T*, N16PN·T*); + bool (*eq_zero)(N16PN·T*); + N16PN·Status (*accumulate)(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...); + N16PN·Status (*add)(N16PN·T*, N16PN·T*, N16PN·T*); + bool (*increment)(N16PN·T *a); + N16PN·Status (*subtract)(N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*multiply)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*divide)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*modulus)(N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*shift_left)(Extent, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*shift_right)(Extent, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*arithmetic_shift_right)(Extent, N16PN·T*, N16PN·T*); + + N16PN·T* (*access)(N16PN·T*, Extent); + void (*from_uint32)(N16PN·T *destination ,uint32_t value); + } N16PN·Λ; + + Local const N16PN·Λ N16PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N16PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N16PN·T{ + Digit d0; + }; + + N16PN·T N16PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint16_t)0}, + {.d0 = 1 << 15} + }; + + N16PN·T *N16PN·zero = &N16PN·constant[0]; + N16PN·T *N16PN·one = &N16PN·constant[1]; + N16PN·T *N16PN·all_one_bit = &N16PN·constant[2]; + N16PN·T *N16PN·msb = &N16PN·constant[3]; + N16PN·T *N16PN·lsb = &N16PN·constant[1]; + + // the allocate an array of N16 + N16PN·T *N16PN·allocate_array(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){ + N16PN·T *instance = malloc((extent + 1) * sizeof(N16PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N16PN·T *N16PN·allocate_array_zero(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){ + N16PN·T *instance = calloc(extent + 1, sizeof(N16PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N16PN·deallocate(N16PN·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N16PN·T{ + Digit d0; + }; + + // temporary variables + Local N16PN·T N16PN·t[4]; + + // allocation + + extern N16PN·T *N16PN·allocate_array(Extent, N16PN·Allocate_MemoryFault); + extern N16PN·T *N16PN·allocate_array_zero(Extent, N16PN·Allocate_MemoryFault); + extern void N16PN·deallocate(N16PN·T *); + + // so the user can access numbers in an array allocation + Local N16PN·T* N16PN·access(N16PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N16PN·from_uint32(N16PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint16_t)(value & 0xFFFF); + } + + // copy, convenience copy + + Local void N16PN·copy(N16PN·T *destination ,N16PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N16PN·set_to_zero(N16PN·T *instance){ + instance->d0 = 0; + } + + Local void N16PN·set_to_one(N16PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N16PN·bit_and(N16PN·T *result, N16PN·T *a, N16PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N16PN·bit_or(N16PN·T *result, N16PN·T *a, N16PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N16PN·bit_complement(N16PN·T *result, N16PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N16PN·bit_twos_complement(N16PN·T *result ,N16PN·T *a){ + result->d0 = (uint16_t)(~a->d0 + 1); + } + + // test functions + + Local N16PN·Order N16PN·compare(N16PN·T *a, N16PN·T *b){ + if(a->d0 < b->d0) return N16PN·Order_lt; + if(a->d0 > b->d0) return N16PN·Order_gt; + return N16PN·Order_eq; + } + + Local bool N16PN·lt(N16PN·T *a ,N16PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N16PN·gt(N16PN·T *a ,N16PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N16PN·eq(N16PN·T *a ,N16PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N16PN·eq_zero(N16PN·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N16PN·Status N16PN·accumulate(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N16PN·T *current; + + while( (current = va_arg(args ,N16PN·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N16PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint16_t)carry; + return N16PN·Status·ok; + } + + Local N16PN·Status N16PN·add(N16PN·T *sum ,N16PN·T *a ,N16PN·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint16_t)(result & 0xFFFF); + return (result >> 16) ? N16PN·Status·carry : N16PN·Status·ok; + } + + Local bool N16PN·increment(N16PN·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N16PN·Status N16PN·subtract(N16PN·T *difference ,N16PN·T *a ,N16PN·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint16_t)(diff & 0xFFFF); + return (diff > a->d0) ? N16PN·Status·borrow : N16PN·Status·ok; + } + + Local N16PN·Status N16PN·multiply(N16PN·T *product1 ,N16PN·T *product0 ,N16PN·T *a ,N16PN·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint16_t)(product & 0xFFFF); + product1->d0 = (uint16_t)((product >> 16) & 0xFFFF); + + if(product1->d0 == 0) return N16PN·Status·one_word_product; + return N16PN·Status·two_word_product; + } + + Local N16PN·Status N16PN·divide(N16PN·T *remainder ,N16PN·T *quotient ,N16PN·T *a ,N16PN·T *b){ + if(b->d0 == 0) return N16PN·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint16_t)(dividend / divisor); + remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor)); + + return N16PN·Status·ok; + } + + Local N16PN·Status N16PN·modulus(N16PN·T *remainder ,N16PN·T *a ,N16PN·T *b){ + if(b->d0 == 0) return N16PN·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint16_t)(dividend - (q * divisor)); + return N16PN·Status·ok; + } + + // bit motion + + typedef uint16_t (*ShiftOp)(uint16_t, uint16_t); + + Local uint16_t shift_left_op(uint16_t value, uint16_t amount){ + return value << amount; + } + + Local uint16_t shift_right_op(uint16_t value, uint16_t amount){ + return (uint16_t)(value >> amount); + } + + Local N16PN·Status N16PN·shift + ( + uint16_t shift_count + ,N16PN·T *spill + ,N16PN·T *operand + ,N16PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N16PN·Status·ok; + + if(operand == NULL){ + operand = &N16PN·t[0]; + N16PN·copy(operand, N16PN·zero); + } + + if(shift_count > 15) return N16PN·Status·gt_max_shift_count; + + N16PN·T *given_operand = &N16PN·t[1]; + N16PN·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (16 - shift_count)); + N16PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count)); + } + + return N16PN·Status·ok; + } + + Local N16PN·Status + N16PN·shift_left(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){ + return N16PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N16PN·Status + N16PN·shift_right(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){ + return N16PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N16PN·Status + N16PN·arithmetic_shift_right(uint16_t shift_count, N16PN·T *operand, N16PN·T *spill){ + + if(shift_count > 15) return N16PN·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N16PN·t[0]; + N16PN·copy(operand, N16PN·zero); + } + + N16PN·T *fill = (operand->d0 & 0x8000) ? N16PN·all_one_bit : N16PN·zero; + return N16PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N16PN·Λ N16PN·λ = { + + .allocate_array = N16PN·allocate_array + ,.allocate_array_zero = N16PN·allocate_array_zero + ,.deallocate = N16PN·deallocate + + ,.copy = N16PN·copy + ,.bit_and = N16PN·bit_and + ,.bit_or = N16PN·bit_or + ,.bit_complement = N16PN·bit_complement + ,.bit_twos_complement = N16PN·bit_twos_complement + ,.compare = N16PN·compare + ,.lt = N16PN·lt + ,.gt = N16PN·gt + ,.eq = N16PN·eq + ,.eq_zero = N16PN·eq_zero + ,.accumulate = N16PN·accumulate + ,.add = N16PN·add + ,.increment = N16PN·increment + ,.subtract = N16PN·subtract + ,.multiply = N16PN·multiply + ,.divide = N16PN·divide + ,.modulus = N16PN·modulus + ,.shift_left = N16PN·shift_left + ,.shift_right = N16PN·shift_right + ,.arithmetic_shift_right = N16PN·arithmetic_shift_right + + ,.access = N16PN·access + ,.from_uint32 = N16PN·from_uint32 + }; + + #endif + +#endif diff --git a/release/x86_64/fedora41/glibc_2.40/N32PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N32PN.lib.c new file mode 100644 index 0000000..952f570 --- /dev/null +++ b/release/x86_64/fedora41/glibc_2.40/N32PN.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 N32PN·DEBUG + +#ifndef FACE +#define N32PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N32PN·FACE +#define N32PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint32_t Extent; + typedef uint32_t Digit; + + typedef struct N32PN·T N32PN·T; + + extern N32PN·T *N32PN·zero; + extern N32PN·T *N32PN·one; + extern N32PN·T *N32PN·all_one_bit; + extern N32PN·T *N32PN·lsb; + extern N32PN·T *N32PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N32PN·Status·ok = 0 + ,N32PN·Status·overflow = 1 + ,N32PN·Status·accumulator1_overflow = 2 + ,N32PN·Status·carry = 3 + ,N32PN·Status·borrow = 4 + ,N32PN·Status·undefined_divide_by_zero = 5 + ,N32PN·Status·undefined_modulus_zero = 6 + ,N32PN·Status·gt_max_shift_count = 7 + ,N32PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N32PN·Status·one_word_product = 9 + ,N32PN·Status·two_word_product = 10 + } N32PN·Status; + + typedef enum{ + N32PN·Order_lt = -1 + ,N32PN·Order_eq = 0 + ,N32PN·Order_gt = 1 + } N32PN·Order; + + typedef N32PN·T *( *N32PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N32PN·T *(*allocate_array_zero)(Extent, N32PN·Allocate_MemoryFault); + N32PN·T *(*allocate_array)(Extent, N32PN·Allocate_MemoryFault); + void (*deallocate)(N32PN·T*); + + void (*copy)(N32PN·T*, N32PN·T*); + void (*bit_and)(N32PN·T*, N32PN·T*, N32PN·T*); + void (*bit_or)(N32PN·T*, N32PN·T*, N32PN·T*); + void (*bit_complement)(N32PN·T*, N32PN·T*); + void (*bit_twos_complement)(N32PN·T*, N32PN·T*); + N32PN·Order (*compare)(N32PN·T*, N32PN·T*); + bool (*lt)(N32PN·T*, N32PN·T*); + bool (*gt)(N32PN·T*, N32PN·T*); + bool (*eq)(N32PN·T*, N32PN·T*); + bool (*eq_zero)(N32PN·T*); + N32PN·Status (*accumulate)(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...); + N32PN·Status (*add)(N32PN·T*, N32PN·T*, N32PN·T*); + bool (*increment)(N32PN·T *a); + N32PN·Status (*subtract)(N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*multiply)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*divide)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*modulus)(N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*shift_left)(Extent, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*shift_right)(Extent, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*arithmetic_shift_right)(Extent, N32PN·T*, N32PN·T*); + + N32PN·T* (*access)(N32PN·T*, Extent); + void (*from_uint32)(N32PN·T *destination ,uint32_t value); + } N32PN·Λ; + + Local const N32PN·Λ N32PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N32PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N32PN·T{ + Digit d0; + }; + + N32PN·T N32PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint32_t)0}, + {.d0 = 1 << 31} + }; + + N32PN·T *N32PN·zero = &N32PN·constant[0]; + N32PN·T *N32PN·one = &N32PN·constant[1]; + N32PN·T *N32PN·all_one_bit = &N32PN·constant[2]; + N32PN·T *N32PN·msb = &N32PN·constant[3]; + N32PN·T *N32PN·lsb = &N32PN·constant[1]; + + // the allocate an array of N32 + N32PN·T *N32PN·allocate_array(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){ + N32PN·T *instance = malloc((extent + 1) * sizeof(N32PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N32PN·T *N32PN·allocate_array_zero(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){ + N32PN·T *instance = calloc( extent + 1 ,sizeof(N32PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N32PN·deallocate(N32PN·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N32PN·T{ + Digit d0; + }; + + // temporary variables + // making these LOCAL rather than reserving one block in the library is thread safe + // allocating a block once is more efficient + // library code writes these, they are not on the interface + + Local N32PN·T N32PN·t[4]; + + + // allocation + + extern N32PN·T *N32PN·allocate_array(Extent, N32PN·Allocate_MemoryFault); + extern N32PN·T *N32PN·allocate_array_zero(Extent, N32PN·Allocate_MemoryFault); + extern void N32PN·deallocate(N32PN·T *); + + // so the user can access numbers in an array allocation + Local N32PN·T* N32PN·access(N32PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N32PN·from_uint32(N32PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy, convenience copy + + Local void N32PN·copy(N32PN·T *destination ,N32PN·T *source){ + if(source == destination) return; // that was easy! + *destination = *source; + } + + Local void N32PN·set_to_zero(N32PN·T *instance){ + instance->d0 = 0; + } + + Local void N32PN·set_to_one(N32PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N32PN·bit_and(N32PN·T *result, N32PN·T *a, N32PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + // result can be one of the operands + Local void N32PN·bit_or(N32PN·T *result, N32PN·T *a, N32PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + // result can the same as the operand + Local void N32PN·bit_complement(N32PN·T *result, N32PN·T *a){ + result->d0 = ~a->d0; + } + + // result can the same as the operand + Local void N32PN·bit_twos_complement(N32PN·T *result ,N32PN·T *a){ + result->d0 = ~a->d0 + 1; + } + + // test functions + + Local N32PN·Order N32PN·compare(N32PN·T *a, N32PN·T *b){ + if(a->d0 < b->d0) return N32PN·Order_lt; + if(a->d0 > b->d0) return N32PN·Order_gt; + return N32PN·Order_eq; + } + + Local bool N32PN·lt(N32PN·T *a ,N32PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N32PN·gt(N32PN·T *a ,N32PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N32PN·eq(N32PN·T *a ,N32PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N32PN·eq_zero(N32PN·T *a){ + return a->d0 == 0; + } + + + // arithmetic operations + + // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32PN·Status·accumulator1_overflow + // + // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. + Local N32PN·Status N32PN·accumulate(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N32PN·T *current; + + while( (current = va_arg(args ,N32PN·T *)) ){ + sum += current->d0; + if(sum < current->d0){ // Accumulator1 into carry + (carry)++; + if(carry == 0){ + va_end(args); + return N32PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + // wipes out prior value of accumulator1 + accumulator1->d0 = carry; + + return N32PN·Status·ok; + } + + Local N32PN·Status N32PN·add(N32PN·T *sum ,N32PN·T *a ,N32PN·T *b){ + uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; + sum->d0 = (uint32_t)result; + return (result >> 32) ? N32PN·Status·carry : N32PN·Status·ok; + } + + Local bool N32PN·increment(N32PN·T *a){ + a->d0++; + return a->d0 == 0; + } + + Local N32PN·Status N32PN·subtract(N32PN·T *difference ,N32PN·T *a ,N32PN·T *b){ + uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; + difference->d0 = (uint32_t)diff; + return (diff > a->d0) ? N32PN·Status·borrow : N32PN·Status·ok; + } + + + Local N32PN·Status N32PN·multiply(N32PN·T *product1 ,N32PN·T *product0 ,N32PN·T *a ,N32PN·T *b){ + uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; + product0->d0 = (uint32_t)product; + product1->d0 = (uint32_t)(product >> 32); + + if(product1->d0 == 0) return N32PN·Status·one_word_product; + return N32PN·Status·two_word_product; + } + + Local N32PN·Status N32PN·divide(N32PN·T *remainder ,N32PN·T *quotient ,N32PN·T *a ,N32PN·T *b){ + if(b->d0 == 0) return N32PN·Status·undefined_divide_by_zero; + + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); + + return N32PN·Status·ok; + } + + Local N32PN·Status N32PN·modulus(N32PN·T *remainder ,N32PN·T *a ,N32PN·T *b){ + if(b->d0 == 0) return N32PN·Status·undefined_modulus_zero; + uint32_t quotient = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient * b->d0); + return N32PN·Status·ok; + } + + // bit motion + + typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); + + Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ + return value << amount; + } + + Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ + return value >> amount; + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, + Local N32PN·Status N32PN·shift + ( + uint32_t shift_count + ,N32PN·T *spill + ,N32PN·T *operand + ,N32PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + // If no result is needed, return immediately. + if(operand == NULL && spill == NULL) return N32PN·Status·ok; + + // Treat NULL operand as zero. + if(operand == NULL){ + operand = &N32PN·t[0]; + N32PN·copy(operand, N32PN·zero); + } + + // Shifting more than one word breaks our fill/spill model. + if(shift_count > 31) return N32PN·Status·gt_max_shift_count; + + // The given operand is still required after it is modified, so we copy it. + N32PN·T *given_operand = &N32PN·t[1]; + N32PN·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); + N32PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); + } + + return N32PN·Status·ok; + } + + // Define concrete shift functions using valid C function pointers + Local N32PN·Status + N32PN·shift_left(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){ + return N32PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N32PN·Status + N32PN·shift_right(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){ + return N32PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N32PN·Status + N32PN·arithmetic_shift_right(uint32_t shift_count, N32PN·T *operand, N32PN·T *spill){ + + // Guard against excessive shift counts + if(shift_count > 31) return N32PN·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N32PN·t[0]; + N32PN·copy(operand, N32PN·zero); + } + + // Pick the fill value based on the sign bit + N32PN·T *fill = (operand->d0 & 0x80000000) ? N32PN·all_one_bit : N32PN·zero; + + // Call shift_right with the appropriate fill + return N32PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N32PN·Λ N32PN·λ = { + + .allocate_array = N32PN·allocate_array + ,.allocate_array_zero = N32PN·allocate_array_zero + ,.deallocate = N32PN·deallocate + + ,.copy = N32PN·copy + ,.bit_and = N32PN·bit_and + ,.bit_or = N32PN·bit_or + ,.bit_complement = N32PN·bit_complement + ,.bit_twos_complement = N32PN·bit_twos_complement + ,.compare = N32PN·compare + ,.lt = N32PN·lt + ,.gt = N32PN·gt + ,.eq = N32PN·eq + ,.eq_zero = N32PN·eq_zero + ,.accumulate = N32PN·accumulate + ,.add = N32PN·add + ,.increment = N32PN·increment + ,.subtract = N32PN·subtract + ,.multiply = N32PN·multiply + ,.divide = N32PN·divide + ,.modulus = N32PN·modulus + ,.shift_left = N32PN·shift_left + ,.shift_right = N32PN·shift_right + ,.arithmetic_shift_right = N32PN·arithmetic_shift_right + + ,.access = N32PN·access + ,.from_uint32 = N32PN·from_uint32 + }; + + #endif + +#endif diff --git a/release/x86_64/fedora41/glibc_2.40/N64PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N64PN.lib.c new file mode 100644 index 0000000..583ad08 --- /dev/null +++ b/release/x86_64/fedora41/glibc_2.40/N64PN.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 N64PN·DEBUG + +#ifndef FACE +#define N64PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N64PN·FACE +#define N64PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint64_t Extent; + typedef uint64_t Digit; + + typedef struct N64PN·T N64PN·T; + + extern N64PN·T *N64PN·zero; + extern N64PN·T *N64PN·one; + extern N64PN·T *N64PN·all_one_bit; + extern N64PN·T *N64PN·lsb; + extern N64PN·T *N64PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum { + N64PN·Status·ok = 0 + ,N64PN·Status·overflow = 1 + ,N64PN·Status·accumulator1_overflow = 2 + ,N64PN·Status·carry = 3 + ,N64PN·Status·borrow = 4 + ,N64PN·Status·undefined_divide_by_zero = 5 + ,N64PN·Status·undefined_modulus_zero = 6 + ,N64PN·Status·gt_max_shift_count = 7 + ,N64PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N64PN·Status·one_word_product = 9 + ,N64PN·Status·two_word_product = 10 + } N64PN·Status; + + typedef enum { + N64PN·Order_lt = -1 + ,N64PN·Order_eq = 0 + ,N64PN·Order_gt = 1 + } N64PN·Order; + + typedef N64PN·T *(*N64PN·Allocate_MemoryFault)(Extent); + + //---------------------------------------- + // Interface + + typedef struct { + + N64PN·T *(*allocate_array_zero)(Extent, N64PN·Allocate_MemoryFault); + N64PN·T *(*allocate_array)(Extent, N64PN·Allocate_MemoryFault); + void (*deallocate)(N64PN·T*); + + void (*copy)(N64PN·T*, N64PN·T*); + void (*bit_and)(N64PN·T*, N64PN·T*, N64PN·T*); + void (*bit_or)(N64PN·T*, N64PN·T*, N64PN·T*); + void (*bit_complement)(N64PN·T*, N64PN·T*); + void (*bit_twos_complement)(N64PN·T*, N64PN·T*); + N64PN·Order (*compare)(N64PN·T*, N64PN·T*); + bool (*lt)(N64PN·T*, N64PN·T*); + bool (*gt)(N64PN·T*, N64PN·T*); + bool (*eq)(N64PN·T*, N64PN·T*); + bool (*eq_zero)(N64PN·T*); + N64PN·Status (*accumulate)(N64PN·T *accumulator1, N64PN·T *accumulator0, ...); + N64PN·Status (*add)(N64PN·T*, N64PN·T*, N64PN·T*); + bool (*increment)(N64PN·T *a); + N64PN·Status (*subtract)(N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*multiply)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*divide)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*modulus)(N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*shift_left)(Extent, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*shift_right)(Extent, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*arithmetic_shift_right)(Extent, N64PN·T*, N64PN·T*); + + N64PN·T* (*access)(N64PN·T*, Extent); + void (*from_uint64)(N64PN·T *destination, uint64_t value); + + } N64PN·Λ; + + Local const N64PN·Λ N64PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N64PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N64PN·T { + Digit d0; + }; + + // For constants, we store them in an array for convenience + // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63) + N64PN·T N64PN·constant[4] = { + {.d0 = 0ULL}, + {.d0 = 1ULL}, + {.d0 = ~(uint64_t)0ULL}, + {.d0 = 1ULL << 63} + }; + + N64PN·T *N64PN·zero = &N64PN·constant[0]; + N64PN·T *N64PN·one = &N64PN·constant[1]; + N64PN·T *N64PN·all_one_bit = &N64PN·constant[2]; + N64PN·T *N64PN·msb = &N64PN·constant[3]; + N64PN·T *N64PN·lsb = &N64PN·constant[1]; + + // allocate an array of N64 + N64PN·T *N64PN·allocate_array(Extent extent, N64PN·Allocate_MemoryFault memory_fault){ + N64PN·T *instance = malloc( (extent + 1) * sizeof(N64PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N64PN·T *N64PN·allocate_array_zero(Extent extent, N64PN·Allocate_MemoryFault memory_fault){ + N64PN·T *instance = calloc(extent + 1, sizeof(N64PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N64PN·deallocate(N64PN·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N64PN·T { + Digit d0; + }; + + // local temporary variables + Local N64PN·T N64PN·t[4]; + + // allocation references + extern N64PN·T *N64PN·allocate_array(Extent, N64PN·Allocate_MemoryFault); + extern N64PN·T *N64PN·allocate_array_zero(Extent, N64PN·Allocate_MemoryFault); + extern void N64PN·deallocate(N64PN·T *); + + // Access array + Local N64PN·T* N64PN·access(N64PN·T *array, Extent index){ + return &array[index]; + } + + Local void N64PN·from_uint64(N64PN·T *destination, uint64_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy + Local void N64PN·copy(N64PN·T *destination, N64PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + // bit operations + + Local void N64PN·bit_and(N64PN·T *result, N64PN·T *a, N64PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N64PN·bit_or(N64PN·T *result, N64PN·T *a, N64PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N64PN·bit_complement(N64PN·T *result, N64PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N64PN·bit_twos_complement(N64PN·T *result, N64PN·T *a){ + result->d0 = ~a->d0 + 1ULL; + } + + // compare & test functions + + Local N64PN·Order N64PN·compare(N64PN·T *a, N64PN·T *b){ + if(a->d0 < b->d0) return N64PN·Order_lt; + if(a->d0 > b->d0) return N64PN·Order_gt; + return N64PN·Order_eq; + } + + Local bool N64PN·lt(N64PN·T *a, N64PN·T *b){ + return (a->d0 < b->d0); + } + + Local bool N64PN·gt(N64PN·T *a, N64PN·T *b){ + return (a->d0 > b->d0); + } + + Local bool N64PN·eq(N64PN·T *a, N64PN·T *b){ + return (a->d0 == b->d0); + } + + Local bool N64PN·eq_zero(N64PN·T *a){ + return (a->d0 == 0ULL); + } + + // arithmetic operations + + // accumulate + Local N64PN·Status N64PN·accumulate(N64PN·T *accumulator1, N64PN·T *accumulator0, ...){ + va_list args; + va_start(args, accumulator0); + + uint64_t sum = accumulator0->d0; + uint64_t carry = 0; + N64PN·T *current; + + while( (current = va_arg(args, N64PN·T*)) ){ + uint64_t prior = sum; + sum += current->d0; + if(sum < prior){ // indicates carry + carry++; + // if carry overflowed a 64-bit, that's an accumulator1 overflow + if(carry == 0ULL){ + va_end(args); + return N64PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = carry; + return N64PN·Status·ok; + } + + // add + Local N64PN·Status N64PN·add(N64PN·T *sum, N64PN·T *a, N64PN·T *b){ + __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0; + // But to avoid using a GNU extension, we can do the simpler approach: + // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits: + uint64_t temp = a->d0 + b->d0; + sum->d0 = temp; + if(temp < a->d0) return N64PN·Status·carry; // means we overflowed + return N64PN·Status·ok; + } + + Local bool N64PN·increment(N64PN·T *a){ + uint64_t old = a->d0; + a->d0++; + // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF + return (a->d0 < old); + } + + // subtract + Local N64PN·Status N64PN·subtract(N64PN·T *difference, N64PN·T *a, N64PN·T *b){ + uint64_t tmpA = a->d0; + uint64_t tmpB = b->d0; + uint64_t diff = tmpA - tmpB; + difference->d0 = diff; + if(diff > tmpA) return N64PN·Status·borrow; // indicates we borrowed + return N64PN·Status·ok; + } + + // multiply + // We'll do a 64x64->128 using two 64-bit accumulators + Local N64PN·Status N64PN·multiply(N64PN·T *product1, N64PN·T *product0, N64PN·T *a, N64PN·T *b){ + uint64_t A = a->d0; + uint64_t B = b->d0; + + // Break each operand into high & low 32 bits + uint64_t a_lo = (uint32_t)(A & 0xffffffffULL); + uint64_t a_hi = A >> 32; + uint64_t b_lo = (uint32_t)(B & 0xffffffffULL); + uint64_t b_hi = B >> 32; + + // partial products + uint64_t low = a_lo * b_lo; // 64-bit + uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits + uint64_t high = a_hi * b_hi; // up to 64 bits + + // incorporate cross into low, high + // cross is effectively the middle bits, so shift cross by 32 and add to low + uint64_t cross_low = (cross & 0xffffffffULL) << 32; // lower part + uint64_t cross_high = cross >> 32; // upper part + + // add cross_low to low, capture carry + uint64_t old_low = low; + low += cross_low; + if(low < old_low) cross_high++; + + // final high + high += cross_high; + + // store results + product0->d0 = low; + product1->d0 = high; + + if(high == 0ULL) return N64PN·Status·one_word_product; + return N64PN·Status·two_word_product; + } + + // divide + Local N64PN·Status N64PN·divide(N64PN·T *remainder, N64PN·T *quotient, N64PN·T *a, N64PN·T *b){ + // we do not handle a > 64-bit, just the single 64-bit + if(b->d0 == 0ULL) return N64PN·Status·undefined_divide_by_zero; + + uint64_t divd = a->d0; // dividend + uint64_t divs = b->d0; // divisor + + quotient->d0 = divd / divs; + remainder->d0 = divd - (quotient->d0 * divs); + + return N64PN·Status·ok; + } + + // modulus + Local N64PN·Status N64PN·modulus(N64PN·T *remainder, N64PN·T *a, N64PN·T *b){ + if(b->d0 == 0ULL) return N64PN·Status·undefined_modulus_zero; + + uint64_t divd = a->d0; + uint64_t divs = b->d0; + uint64_t q = divd / divs; + remainder->d0 = divd - (q * divs); + + return N64PN·Status·ok; + } + + // bit motion + + typedef uint64_t (*ShiftOp)(uint64_t, uint64_t); + + Local uint64_t shift_left_op(uint64_t value, uint64_t amount){ + return (value << amount); + } + + Local uint64_t shift_right_op(uint64_t value, uint64_t amount){ + return (value >> amount); + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill + Local N64PN·Status N64PN·shift + ( + uint64_t shift_count, + N64PN·T *spill, + N64PN·T *operand, + N64PN·T *fill, + ShiftOp shift_op, + ShiftOp complement_shift_op + ){ + if(operand == NULL && spill == NULL) return N64PN·Status·ok; + + // Treat NULL operand as zero + if(operand == NULL){ + operand = &N64PN·t[0]; + N64PN·copy(operand, N64PN·zero); + } + + // Shifting more than 63 bits breaks fill/spill logic + if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count; + + N64PN·T *given_operand = &N64PN·t[1]; + N64PN·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count)); + N64PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count)); + } + + return N64PN·Status·ok; + } + + Local N64PN·Status N64PN·shift_left(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){ + return N64PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N64PN·Status N64PN·shift_right(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){ + return N64PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N64PN·Status N64PN·arithmetic_shift_right(uint64_t shift_count, N64PN·T *operand, N64PN·T *spill){ + if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N64PN·t[0]; + N64PN·copy(operand, N64PN·zero); + } + + // sign bit check + N64PN·T *fill = (operand->d0 & (1ULL << 63)) ? N64PN·all_one_bit : N64PN·zero; + return N64PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N64PN·Λ N64PN·λ = { + .allocate_array = N64PN·allocate_array + ,.allocate_array_zero = N64PN·allocate_array_zero + ,.deallocate = N64PN·deallocate + + ,.copy = N64PN·copy + ,.bit_and = N64PN·bit_and + ,.bit_or = N64PN·bit_or + ,.bit_complement = N64PN·bit_complement + ,.bit_twos_complement = N64PN·bit_twos_complement + ,.compare = N64PN·compare + ,.lt = N64PN·lt + ,.gt = N64PN·gt + ,.eq = N64PN·eq + ,.eq_zero = N64PN·eq_zero + ,.accumulate = N64PN·accumulate + ,.add = N64PN·add + ,.increment = N64PN·increment + ,.subtract = N64PN·subtract + ,.multiply = N64PN·multiply + ,.divide = N64PN·divide + ,.modulus = N64PN·modulus + ,.shift_left = N64PN·shift_left + ,.shift_right = N64PN·shift_right + ,.arithmetic_shift_right = N64PN·arithmetic_shift_right + + ,.access = N64PN·access + ,.from_uint64 = N64PN·from_uint64 + }; + + #endif + +#endif diff --git a/release/x86_64/fedora41/glibc_2.40/N8PN.lib.c b/release/x86_64/fedora41/glibc_2.40/N8PN.lib.c new file mode 100644 index 0000000..9cfd66d --- /dev/null +++ b/release/x86_64/fedora41/glibc_2.40/N8PN.lib.c @@ -0,0 +1,433 @@ +/* + N8PN - PN = refers to the use of processor native accumulator + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N8PN·DEBUG + +#ifndef FACE +#define N8PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N8PN·FACE +#define N8PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint8_t Extent; + typedef uint8_t Digit; + + typedef struct N8PN·T N8PN·T; + + extern N8PN·T *N8PN·zero; + extern N8PN·T *N8PN·one; + extern N8PN·T *N8PN·all_one_bit; + extern N8PN·T *N8PN·lsb; + extern N8PN·T *N8PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N8PN·Status·ok = 0 + ,N8PN·Status·overflow = 1 + ,N8PN·Status·accumulator1_overflow = 2 + ,N8PN·Status·carry = 3 + ,N8PN·Status·borrow = 4 + ,N8PN·Status·undefined_divide_by_zero = 5 + ,N8PN·Status·undefined_modulus_zero = 6 + ,N8PN·Status·gt_max_shift_count = 7 + ,N8PN·Status·spill_eq_operand = 8 + ,N8PN·Status·one_word_product = 9 + ,N8PN·Status·two_word_product = 10 + } N8PN·Status; + + typedef enum{ + N8PN·Order_lt = -1 + ,N8PN·Order_eq = 0 + ,N8PN·Order_gt = 1 + } N8PN·Order; + + typedef N8PN·T *( *N8PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N8PN·T *(*allocate_array_zero)(Extent, N8PN·Allocate_MemoryFault); + N8PN·T *(*allocate_array)(Extent, N8PN·Allocate_MemoryFault); + void (*deallocate)(N8PN·T*); + + void (*copy)(N8PN·T*, N8PN·T*); + void (*bit_and)(N8PN·T*, N8PN·T*, N8PN·T*); + void (*bit_or)(N8PN·T*, N8PN·T*, N8PN·T*); + void (*bit_complement)(N8PN·T*, N8PN·T*); + void (*bit_twos_complement)(N8PN·T*, N8PN·T*); + N8PN·Order (*compare)(N8PN·T*, N8PN·T*); + bool (*lt)(N8PN·T*, N8PN·T*); + bool (*gt)(N8PN·T*, N8PN·T*); + bool (*eq)(N8PN·T*, N8PN·T*); + bool (*eq_zero)(N8PN·T*); + N8PN·Status (*accumulate)(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...); + N8PN·Status (*add)(N8PN·T*, N8PN·T*, N8PN·T*); + bool (*increment)(N8PN·T *a); + N8PN·Status (*subtract)(N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*multiply)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*divide)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*modulus)(N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*shift_left)(Extent, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*shift_right)(Extent, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*arithmetic_shift_right)(Extent, N8PN·T*, N8PN·T*); + + N8PN·T* (*access)(N8PN·T*, Extent); + void (*from_uint32)(N8PN·T *destination ,uint32_t value); + } N8PN·Λ; + + Local const N8PN·Λ N8PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N8PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N8PN·T{ + Digit d0; + }; + + N8PN·T N8PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint8_t)0}, + {.d0 = 1 << 7} + }; + + N8PN·T *N8PN·zero = &N8PN·constant[0]; + N8PN·T *N8PN·one = &N8PN·constant[1]; + N8PN·T *N8PN·all_one_bit = &N8PN·constant[2]; + N8PN·T *N8PN·msb = &N8PN·constant[3]; + N8PN·T *N8PN·lsb = &N8PN·constant[1]; + + // the allocate an array of N8 + N8PN·T *N8PN·allocate_array(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){ + N8PN·T *instance = malloc((extent + 1) * sizeof(N8PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N8PN·T *N8PN·allocate_array_zero(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){ + N8PN·T *instance = calloc(extent + 1, sizeof(N8PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N8PN·deallocate(N8PN·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N8PN·T{ + Digit d0; + }; + + // temporary variables + Local N8PN·T N8PN·t[4]; + + // allocation + + extern N8PN·T *N8PN·allocate_array(Extent, N8PN·Allocate_MemoryFault); + extern N8PN·T *N8PN·allocate_array_zero(Extent, N8PN·Allocate_MemoryFault); + extern void N8PN·deallocate(N8PN·T *); + + // so the user can access numbers in an array allocation + Local N8PN·T* N8PN·access(N8PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N8PN·from_uint32(N8PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint8_t)(value & 0xFF); + } + + // copy, convenience copy + + Local void N8PN·copy(N8PN·T *destination ,N8PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N8PN·set_to_zero(N8PN·T *instance){ + instance->d0 = 0; + } + + Local void N8PN·set_to_one(N8PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N8PN·bit_and(N8PN·T *result, N8PN·T *a, N8PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N8PN·bit_or(N8PN·T *result, N8PN·T *a, N8PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N8PN·bit_complement(N8PN·T *result, N8PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N8PN·bit_twos_complement(N8PN·T *result ,N8PN·T *a){ + result->d0 = (uint8_t)(~a->d0 + 1); + } + + // test functions + + Local N8PN·Order N8PN·compare(N8PN·T *a, N8PN·T *b){ + if(a->d0 < b->d0) return N8PN·Order_lt; + if(a->d0 > b->d0) return N8PN·Order_gt; + return N8PN·Order_eq; + } + + Local bool N8PN·lt(N8PN·T *a ,N8PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N8PN·gt(N8PN·T *a ,N8PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N8PN·eq(N8PN·T *a ,N8PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N8PN·eq_zero(N8PN·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N8PN·Status N8PN·accumulate(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N8PN·T *current; + + while( (current = va_arg(args ,N8PN·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N8PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint8_t)carry; + return N8PN·Status·ok; + } + + Local N8PN·Status N8PN·add(N8PN·T *sum ,N8PN·T *a ,N8PN·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint8_t)(result & 0xFF); + return (result >> 8) ? N8PN·Status·carry : N8PN·Status·ok; + } + + Local bool N8PN·increment(N8PN·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N8PN·Status N8PN·subtract(N8PN·T *difference ,N8PN·T *a ,N8PN·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint8_t)(diff & 0xFF); + return (diff > a->d0) ? N8PN·Status·borrow : N8PN·Status·ok; + } + + Local N8PN·Status N8PN·multiply(N8PN·T *product1 ,N8PN·T *product0 ,N8PN·T *a ,N8PN·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint8_t)(product & 0xFF); + product1->d0 = (uint8_t)((product >> 8) & 0xFF); + + if(product1->d0 == 0) return N8PN·Status·one_word_product; + return N8PN·Status·two_word_product; + } + + Local N8PN·Status N8PN·divide(N8PN·T *remainder ,N8PN·T *quotient ,N8PN·T *a ,N8PN·T *b){ + if(b->d0 == 0) return N8PN·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint8_t)(dividend / divisor); + remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor)); + + return N8PN·Status·ok; + } + + Local N8PN·Status N8PN·modulus(N8PN·T *remainder ,N8PN·T *a ,N8PN·T *b){ + if(b->d0 == 0) return N8PN·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint8_t)(dividend - (q * divisor)); + return N8PN·Status·ok; + } + + // bit motion + + typedef uint8_t (*ShiftOp)(uint8_t, uint8_t); + + Local uint8_t shift_left_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value << amount); + } + + Local uint8_t shift_right_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value >> amount); + } + + Local N8PN·Status N8PN·shift + ( + uint8_t shift_count + ,N8PN·T *spill + ,N8PN·T *operand + ,N8PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N8PN·Status·ok; + + if(operand == NULL){ + operand = &N8PN·t[0]; + N8PN·copy(operand, N8PN·zero); + } + + if(shift_count > 7) return N8PN·Status·gt_max_shift_count; + + N8PN·T *given_operand = &N8PN·t[1]; + N8PN·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (8 - shift_count)); + N8PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count)); + } + + return N8PN·Status·ok; + } + + Local N8PN·Status + N8PN·shift_left(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){ + return N8PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N8PN·Status + N8PN·shift_right(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){ + return N8PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N8PN·Status + N8PN·arithmetic_shift_right(uint8_t shift_count, N8PN·T *operand, N8PN·T *spill){ + + if(shift_count > 7) return N8PN·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N8PN·t[0]; + N8PN·copy(operand, N8PN·zero); + } + + N8PN·T *fill = (operand->d0 & 0x80) ? N8PN·all_one_bit : N8PN·zero; + return N8PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N8PN·Λ N8PN·λ = { + + .allocate_array = N8PN·allocate_array + ,.allocate_array_zero = N8PN·allocate_array_zero + ,.deallocate = N8PN·deallocate + + ,.copy = N8PN·copy + ,.bit_and = N8PN·bit_and + ,.bit_or = N8PN·bit_or + ,.bit_complement = N8PN·bit_complement + ,.bit_twos_complement = N8PN·bit_twos_complement + ,.compare = N8PN·compare + ,.lt = N8PN·lt + ,.gt = N8PN·gt + ,.eq = N8PN·eq + ,.eq_zero = N8PN·eq_zero + ,.accumulate = N8PN·accumulate + ,.add = N8PN·add + ,.increment = N8PN·increment + ,.subtract = N8PN·subtract + ,.multiply = N8PN·multiply + ,.divide = N8PN·divide + ,.modulus = N8PN·modulus + ,.shift_left = N8PN·shift_left + ,.shift_right = N8PN·shift_right + ,.arithmetic_shift_right = N8PN·arithmetic_shift_right + + ,.access = N8PN·access + ,.from_uint32 = N8PN·from_uint32 + }; + + #endif + +#endif diff --git a/release/x86_64/fedora41/glibc_2.40/libN.a b/release/x86_64/fedora41/glibc_2.40/libN.a new file mode 100644 index 0000000000000000000000000000000000000000..281841616e4f46c16fce99ea4aae41826b1aab65 GIT binary patch literal 16002 zcmeHOU1(g#6`qyd#I<8fZWC~EnqD`i$fRDcR94 z8pb7Gsn%;M)~2c|RVF4zB{e$s64fTB$24yumPD&IUTIWEEA@J1rdiYjN4@GVR9V0b z_vhcb?Xn=*h9R`H3&1wppKs~5O|r1$Xlapx;(|2G+iu&U>;=1>0BW~wj^FLUftH@w zr0a#krxo-M5GCUSG(RZj~|%rMY+RK)EzGv|PG=ZP{FTT%sk@*axlB zjq^)$@2vd&gFSzQ(g!KN9r~Wb@fR89MpnxxT(!)O)UaAu3fGnsM~R5o30WjUu@|CYKa4 zT_&>tj3J|Gj-^L6BlF5RleyZHIrzxKyKYM6KYaem-h^C z3FmQ(^GD+RZvdBY5I5$3&1M5h4CvQR^Y4|U%pD1Dz$2oVG0m4?Q42mM@qV)-u130S z!(q7tXPWUb#e1AuoPSdB0|EZL;!%LZ7O1~Bz(*zh39tXwrh+x(Vw+mTM&FY=^r>fU zEZ9%vO49$S>i$jW<=2 zh_)h*i4B4NC(d^&vbh+8?%m@^r2mPt9_k}a3{@0ylR%t)FI%*U)4wJ=Ju}&;j7i+6 zyZ92NdUc|bZB(x|OxB7QDvgTCj!jQXy5fWPBio!Ou7i%i2z}cTTbp3$w4IdPJP~-!c_#~8E zWZe8<;`f<;d`j|BXLE*d1$JpeIW5nKB9_MBQF=0iWQea2@bld`XOBJ7Z6hPp2Z{;*u3 zdO?AM>8?a%bLMM(1B`w8O*Kd)Gx{!3~bbuVfAv--f8i_lJ3 z{^Np$z8A=pp)BDI7sdC`e)}aSseGg_)J$B`31NBpedANps1rBs>mSsgn``H$w>;+* zZ8wT$kAXFv?=W+VIE(bEVUsyfTHCN$Iv4RCPAkBAl<`I+*OE^OzF%;rIToH&oMVdk z=M|46Mj-wLkx@^tMVmN&tXgNvQhx70dRo^$|LNF2*aNr@Q4?uDh_j#UA92iqHmtH{ zB`;U&Sf<#<24bu!=yTed6jlvgKVVG&7QUB7RSM@cjt9*)heUvFiv%=&UmGfG8g_;s zXm9!l;|5sR{$;_ELfC(-Nx;H>vV5mC;b|=&w)L|R&~(`TbAl(W39qSs*e^c6X4}5| zxfgb3dD<^+PR8#cglAn8-^2c=&BeKHO0AL>)khb ztz64~!C6?9zxTVIi}wS#Uog^=|9qT(KkXOv=*T!MF@Dc8%{c>eA#lze#JOJ(X?fz@ zFX#<$?ib_&Jlrp^HWi&t`vugqHWvL(`vshvJMR~8auL1Hx)|tx;>?RwfjGwj z{ZE|Si2f%Y)`NA;U)zdWKXLlK9N_ftR^Ko9vpzQ?*wGK0wO?Qt9cifGHzqR23t@0W z__RnskpriFFy7c6)`yoz=lw4PgUUIqkMua*`z)sYh91jq{kMH&o?n43%Tr?O5Br4?N{8ZredD za365jb8tk=UB4W2Q*u|kFCXVO&%*8}?i%44Bpj9t95q5h0y)Srk(17-$X&@rs88<7 zHI6vBYY~-8ARcm8Yg5VZ#9gV!vyV>P^_RBQwVZWv@)GW9zf%BrwL+7-+N9&IR@~s1 z66CJ7uGP4!RY>Npkv<=$c%QpYd$`YC|K#C5ca0Rs{G-c-MS26A{-gh?PcB3M6DRjA zrqmNDPL8U{m;(`~-^+nM{kzq<>jDjL zC`hMq*I8}g%7IrgmBtfS6LMowH%{}g2riQUA-895-=b7f$cL+ zJL`Hu%ll;^vmEg>?)svZ=le!|+K=g)))_YUssgk>^~3UMXI;w)<7Yi*T^vxe`oQZw z>zdWc=nZyUI9di!&X{4;NafYsa&${NRB5)N&o)VcqP&UEOzBugYgwf8b|W z>EB?9N~e8Q`&pM?-8`(;PF>^gx;oaG!dx>evw?X(n#ucso1TT`WA53$ulm)N{IfB4 z{V=#G_({@tSf3OeT$6$PHkRee<3jf_f>x`a+1E`q#Q4W zw1F>YNl8)7YK#>5ZG`j*`!tR}!q?mvg?$j0jjhOal{Dp zH*v0kkkV+$Lw%HI9Z)UeCV@EpT()Qvr$4tk7oFGVW<>ijoyJ9XC2$Fp zrN8M%yx+j-FV<^8N#tU{2`o=Ijf;+Kkc;NR2h|2cIE{-IRdJCW)i?^$XdYE?U;f=+`OsC!EGbd)CTD`|~5i-bSkbFQ4T9 z1PrWuAN5uzF4}r1zkS9}=RPR$1HeT`V9S`Rez<4+c=waI=wpKWT$G&SNyVAwnsZcf zu3f~j2B4luVg%xto0B*vYymt6WeL>(y2wdfbW(8k1^NuwKlQmN>P7gWTuJ&r799FK z111-JJw+eq`8ql2mxS(&-)E!$v%gW1jkf>8s`bAB$Zun#@&FRH&-R@iwmK)h*R%be z1Wo~Z!1s^ubtg_*P%|?M-?cPO`r-yT>GppCoW*lAyvFn&;hG5Wt5QJ1W~2WFcrRi6 Y{69G9Z{sI&f>PWVP2;2o*2qc!3m?5w@&Et; literal 0 HcmV?d00001 diff --git a/tester/cc/N16PN.lib.c b/tester/cc/N16PN.lib.c new file mode 100644 index 0000000..d7a2e05 --- /dev/null +++ b/tester/cc/N16PN.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 N16PN·DEBUG + +#ifndef FACE +#define N16PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N16PN·FACE +#define N16PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint16_t Extent; + typedef uint16_t Digit; + + typedef struct N16PN·T N16PN·T; + + extern N16PN·T *N16PN·zero; + extern N16PN·T *N16PN·one; + extern N16PN·T *N16PN·all_one_bit; + extern N16PN·T *N16PN·lsb; + extern N16PN·T *N16PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N16PN·Status·ok = 0 + ,N16PN·Status·overflow = 1 + ,N16PN·Status·accumulator1_overflow = 2 + ,N16PN·Status·carry = 3 + ,N16PN·Status·borrow = 4 + ,N16PN·Status·undefined_divide_by_zero = 5 + ,N16PN·Status·undefined_modulus_zero = 6 + ,N16PN·Status·gt_max_shift_count = 7 + ,N16PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N16PN·Status·one_word_product = 9 + ,N16PN·Status·two_word_product = 10 + } N16PN·Status; + + typedef enum{ + N16PN·Order_lt = -1 + ,N16PN·Order_eq = 0 + ,N16PN·Order_gt = 1 + } N16PN·Order; + + typedef N16PN·T *( *N16PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N16PN·T *(*allocate_array_zero)(Extent, N16PN·Allocate_MemoryFault); + N16PN·T *(*allocate_array)(Extent, N16PN·Allocate_MemoryFault); + void (*deallocate)(N16PN·T*); + + void (*copy)(N16PN·T*, N16PN·T*); + void (*bit_and)(N16PN·T*, N16PN·T*, N16PN·T*); + void (*bit_or)(N16PN·T*, N16PN·T*, N16PN·T*); + void (*bit_complement)(N16PN·T*, N16PN·T*); + void (*bit_twos_complement)(N16PN·T*, N16PN·T*); + N16PN·Order (*compare)(N16PN·T*, N16PN·T*); + bool (*lt)(N16PN·T*, N16PN·T*); + bool (*gt)(N16PN·T*, N16PN·T*); + bool (*eq)(N16PN·T*, N16PN·T*); + bool (*eq_zero)(N16PN·T*); + N16PN·Status (*accumulate)(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...); + N16PN·Status (*add)(N16PN·T*, N16PN·T*, N16PN·T*); + bool (*increment)(N16PN·T *a); + N16PN·Status (*subtract)(N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*multiply)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*divide)(N16PN·T*, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*modulus)(N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*shift_left)(Extent, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*shift_right)(Extent, N16PN·T*, N16PN·T*, N16PN·T*); + N16PN·Status (*arithmetic_shift_right)(Extent, N16PN·T*, N16PN·T*); + + N16PN·T* (*access)(N16PN·T*, Extent); + void (*from_uint32)(N16PN·T *destination ,uint32_t value); + } N16PN·Λ; + + Local const N16PN·Λ N16PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N16PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N16PN·T{ + Digit d0; + }; + + N16PN·T N16PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint16_t)0}, + {.d0 = 1 << 15} + }; + + N16PN·T *N16PN·zero = &N16PN·constant[0]; + N16PN·T *N16PN·one = &N16PN·constant[1]; + N16PN·T *N16PN·all_one_bit = &N16PN·constant[2]; + N16PN·T *N16PN·msb = &N16PN·constant[3]; + N16PN·T *N16PN·lsb = &N16PN·constant[1]; + + // the allocate an array of N16 + N16PN·T *N16PN·allocate_array(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){ + N16PN·T *instance = malloc((extent + 1) * sizeof(N16PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N16PN·T *N16PN·allocate_array_zero(Extent extent ,N16PN·Allocate_MemoryFault memory_fault){ + N16PN·T *instance = calloc(extent + 1, sizeof(N16PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N16PN·deallocate(N16PN·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N16PN·T{ + Digit d0; + }; + + // temporary variables + Local N16PN·T N16PN·t[4]; + + // allocation + + extern N16PN·T *N16PN·allocate_array(Extent, N16PN·Allocate_MemoryFault); + extern N16PN·T *N16PN·allocate_array_zero(Extent, N16PN·Allocate_MemoryFault); + extern void N16PN·deallocate(N16PN·T *); + + // so the user can access numbers in an array allocation + Local N16PN·T* N16PN·access(N16PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N16PN·from_uint32(N16PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint16_t)(value & 0xFFFF); + } + + // copy, convenience copy + + Local void N16PN·copy(N16PN·T *destination ,N16PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N16PN·set_to_zero(N16PN·T *instance){ + instance->d0 = 0; + } + + Local void N16PN·set_to_one(N16PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N16PN·bit_and(N16PN·T *result, N16PN·T *a, N16PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N16PN·bit_or(N16PN·T *result, N16PN·T *a, N16PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N16PN·bit_complement(N16PN·T *result, N16PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N16PN·bit_twos_complement(N16PN·T *result ,N16PN·T *a){ + result->d0 = (uint16_t)(~a->d0 + 1); + } + + // test functions + + Local N16PN·Order N16PN·compare(N16PN·T *a, N16PN·T *b){ + if(a->d0 < b->d0) return N16PN·Order_lt; + if(a->d0 > b->d0) return N16PN·Order_gt; + return N16PN·Order_eq; + } + + Local bool N16PN·lt(N16PN·T *a ,N16PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N16PN·gt(N16PN·T *a ,N16PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N16PN·eq(N16PN·T *a ,N16PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N16PN·eq_zero(N16PN·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N16PN·Status N16PN·accumulate(N16PN·T *accumulator1 ,N16PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N16PN·T *current; + + while( (current = va_arg(args ,N16PN·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N16PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint16_t)carry; + return N16PN·Status·ok; + } + + Local N16PN·Status N16PN·add(N16PN·T *sum ,N16PN·T *a ,N16PN·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint16_t)(result & 0xFFFF); + return (result >> 16) ? N16PN·Status·carry : N16PN·Status·ok; + } + + Local bool N16PN·increment(N16PN·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N16PN·Status N16PN·subtract(N16PN·T *difference ,N16PN·T *a ,N16PN·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint16_t)(diff & 0xFFFF); + return (diff > a->d0) ? N16PN·Status·borrow : N16PN·Status·ok; + } + + Local N16PN·Status N16PN·multiply(N16PN·T *product1 ,N16PN·T *product0 ,N16PN·T *a ,N16PN·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint16_t)(product & 0xFFFF); + product1->d0 = (uint16_t)((product >> 16) & 0xFFFF); + + if(product1->d0 == 0) return N16PN·Status·one_word_product; + return N16PN·Status·two_word_product; + } + + Local N16PN·Status N16PN·divide(N16PN·T *remainder ,N16PN·T *quotient ,N16PN·T *a ,N16PN·T *b){ + if(b->d0 == 0) return N16PN·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint16_t)(dividend / divisor); + remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor)); + + return N16PN·Status·ok; + } + + Local N16PN·Status N16PN·modulus(N16PN·T *remainder ,N16PN·T *a ,N16PN·T *b){ + if(b->d0 == 0) return N16PN·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint16_t)(dividend - (q * divisor)); + return N16PN·Status·ok; + } + + // bit motion + + typedef uint16_t (*ShiftOp)(uint16_t, uint16_t); + + Local uint16_t shift_left_op(uint16_t value, uint16_t amount){ + return value << amount; + } + + Local uint16_t shift_right_op(uint16_t value, uint16_t amount){ + return (uint16_t)(value >> amount); + } + + Local N16PN·Status N16PN·shift + ( + uint16_t shift_count + ,N16PN·T *spill + ,N16PN·T *operand + ,N16PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N16PN·Status·ok; + + if(operand == NULL){ + operand = &N16PN·t[0]; + N16PN·copy(operand, N16PN·zero); + } + + if(shift_count > 15) return N16PN·Status·gt_max_shift_count; + + N16PN·T *given_operand = &N16PN·t[1]; + N16PN·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (16 - shift_count)); + N16PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count)); + } + + return N16PN·Status·ok; + } + + Local N16PN·Status + N16PN·shift_left(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){ + return N16PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N16PN·Status + N16PN·shift_right(uint16_t shift_count, N16PN·T *spill, N16PN·T *operand, N16PN·T *fill){ + return N16PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N16PN·Status + N16PN·arithmetic_shift_right(uint16_t shift_count, N16PN·T *operand, N16PN·T *spill){ + + if(shift_count > 15) return N16PN·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N16PN·t[0]; + N16PN·copy(operand, N16PN·zero); + } + + N16PN·T *fill = (operand->d0 & 0x8000) ? N16PN·all_one_bit : N16PN·zero; + return N16PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N16PN·Λ N16PN·λ = { + + .allocate_array = N16PN·allocate_array + ,.allocate_array_zero = N16PN·allocate_array_zero + ,.deallocate = N16PN·deallocate + + ,.copy = N16PN·copy + ,.bit_and = N16PN·bit_and + ,.bit_or = N16PN·bit_or + ,.bit_complement = N16PN·bit_complement + ,.bit_twos_complement = N16PN·bit_twos_complement + ,.compare = N16PN·compare + ,.lt = N16PN·lt + ,.gt = N16PN·gt + ,.eq = N16PN·eq + ,.eq_zero = N16PN·eq_zero + ,.accumulate = N16PN·accumulate + ,.add = N16PN·add + ,.increment = N16PN·increment + ,.subtract = N16PN·subtract + ,.multiply = N16PN·multiply + ,.divide = N16PN·divide + ,.modulus = N16PN·modulus + ,.shift_left = N16PN·shift_left + ,.shift_right = N16PN·shift_right + ,.arithmetic_shift_right = N16PN·arithmetic_shift_right + + ,.access = N16PN·access + ,.from_uint32 = N16PN·from_uint32 + }; + + #endif + +#endif diff --git a/tester/cc/N32.lib.c b/tester/cc/N32.lib.c new file mode 100644 index 0000000..fba3c21 --- /dev/null +++ b/tester/cc/N32.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 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/tester/cc/N32PN.lib.c b/tester/cc/N32PN.lib.c new file mode 100644 index 0000000..952f570 --- /dev/null +++ b/tester/cc/N32PN.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 N32PN·DEBUG + +#ifndef FACE +#define N32PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N32PN·FACE +#define N32PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint32_t Extent; + typedef uint32_t Digit; + + typedef struct N32PN·T N32PN·T; + + extern N32PN·T *N32PN·zero; + extern N32PN·T *N32PN·one; + extern N32PN·T *N32PN·all_one_bit; + extern N32PN·T *N32PN·lsb; + extern N32PN·T *N32PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N32PN·Status·ok = 0 + ,N32PN·Status·overflow = 1 + ,N32PN·Status·accumulator1_overflow = 2 + ,N32PN·Status·carry = 3 + ,N32PN·Status·borrow = 4 + ,N32PN·Status·undefined_divide_by_zero = 5 + ,N32PN·Status·undefined_modulus_zero = 6 + ,N32PN·Status·gt_max_shift_count = 7 + ,N32PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N32PN·Status·one_word_product = 9 + ,N32PN·Status·two_word_product = 10 + } N32PN·Status; + + typedef enum{ + N32PN·Order_lt = -1 + ,N32PN·Order_eq = 0 + ,N32PN·Order_gt = 1 + } N32PN·Order; + + typedef N32PN·T *( *N32PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N32PN·T *(*allocate_array_zero)(Extent, N32PN·Allocate_MemoryFault); + N32PN·T *(*allocate_array)(Extent, N32PN·Allocate_MemoryFault); + void (*deallocate)(N32PN·T*); + + void (*copy)(N32PN·T*, N32PN·T*); + void (*bit_and)(N32PN·T*, N32PN·T*, N32PN·T*); + void (*bit_or)(N32PN·T*, N32PN·T*, N32PN·T*); + void (*bit_complement)(N32PN·T*, N32PN·T*); + void (*bit_twos_complement)(N32PN·T*, N32PN·T*); + N32PN·Order (*compare)(N32PN·T*, N32PN·T*); + bool (*lt)(N32PN·T*, N32PN·T*); + bool (*gt)(N32PN·T*, N32PN·T*); + bool (*eq)(N32PN·T*, N32PN·T*); + bool (*eq_zero)(N32PN·T*); + N32PN·Status (*accumulate)(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...); + N32PN·Status (*add)(N32PN·T*, N32PN·T*, N32PN·T*); + bool (*increment)(N32PN·T *a); + N32PN·Status (*subtract)(N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*multiply)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*divide)(N32PN·T*, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*modulus)(N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*shift_left)(Extent, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*shift_right)(Extent, N32PN·T*, N32PN·T*, N32PN·T*); + N32PN·Status (*arithmetic_shift_right)(Extent, N32PN·T*, N32PN·T*); + + N32PN·T* (*access)(N32PN·T*, Extent); + void (*from_uint32)(N32PN·T *destination ,uint32_t value); + } N32PN·Λ; + + Local const N32PN·Λ N32PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N32PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N32PN·T{ + Digit d0; + }; + + N32PN·T N32PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint32_t)0}, + {.d0 = 1 << 31} + }; + + N32PN·T *N32PN·zero = &N32PN·constant[0]; + N32PN·T *N32PN·one = &N32PN·constant[1]; + N32PN·T *N32PN·all_one_bit = &N32PN·constant[2]; + N32PN·T *N32PN·msb = &N32PN·constant[3]; + N32PN·T *N32PN·lsb = &N32PN·constant[1]; + + // the allocate an array of N32 + N32PN·T *N32PN·allocate_array(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){ + N32PN·T *instance = malloc((extent + 1) * sizeof(N32PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N32PN·T *N32PN·allocate_array_zero(Extent extent ,N32PN·Allocate_MemoryFault memory_fault){ + N32PN·T *instance = calloc( extent + 1 ,sizeof(N32PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N32PN·deallocate(N32PN·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N32PN·T{ + Digit d0; + }; + + // temporary variables + // making these LOCAL rather than reserving one block in the library is thread safe + // allocating a block once is more efficient + // library code writes these, they are not on the interface + + Local N32PN·T N32PN·t[4]; + + + // allocation + + extern N32PN·T *N32PN·allocate_array(Extent, N32PN·Allocate_MemoryFault); + extern N32PN·T *N32PN·allocate_array_zero(Extent, N32PN·Allocate_MemoryFault); + extern void N32PN·deallocate(N32PN·T *); + + // so the user can access numbers in an array allocation + Local N32PN·T* N32PN·access(N32PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N32PN·from_uint32(N32PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy, convenience copy + + Local void N32PN·copy(N32PN·T *destination ,N32PN·T *source){ + if(source == destination) return; // that was easy! + *destination = *source; + } + + Local void N32PN·set_to_zero(N32PN·T *instance){ + instance->d0 = 0; + } + + Local void N32PN·set_to_one(N32PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N32PN·bit_and(N32PN·T *result, N32PN·T *a, N32PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + // result can be one of the operands + Local void N32PN·bit_or(N32PN·T *result, N32PN·T *a, N32PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + // result can the same as the operand + Local void N32PN·bit_complement(N32PN·T *result, N32PN·T *a){ + result->d0 = ~a->d0; + } + + // result can the same as the operand + Local void N32PN·bit_twos_complement(N32PN·T *result ,N32PN·T *a){ + result->d0 = ~a->d0 + 1; + } + + // test functions + + Local N32PN·Order N32PN·compare(N32PN·T *a, N32PN·T *b){ + if(a->d0 < b->d0) return N32PN·Order_lt; + if(a->d0 > b->d0) return N32PN·Order_gt; + return N32PN·Order_eq; + } + + Local bool N32PN·lt(N32PN·T *a ,N32PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N32PN·gt(N32PN·T *a ,N32PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N32PN·eq(N32PN·T *a ,N32PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N32PN·eq_zero(N32PN·T *a){ + return a->d0 == 0; + } + + + // arithmetic operations + + // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32PN·Status·accumulator1_overflow + // + // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. + Local N32PN·Status N32PN·accumulate(N32PN·T *accumulator1 ,N32PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N32PN·T *current; + + while( (current = va_arg(args ,N32PN·T *)) ){ + sum += current->d0; + if(sum < current->d0){ // Accumulator1 into carry + (carry)++; + if(carry == 0){ + va_end(args); + return N32PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + // wipes out prior value of accumulator1 + accumulator1->d0 = carry; + + return N32PN·Status·ok; + } + + Local N32PN·Status N32PN·add(N32PN·T *sum ,N32PN·T *a ,N32PN·T *b){ + uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; + sum->d0 = (uint32_t)result; + return (result >> 32) ? N32PN·Status·carry : N32PN·Status·ok; + } + + Local bool N32PN·increment(N32PN·T *a){ + a->d0++; + return a->d0 == 0; + } + + Local N32PN·Status N32PN·subtract(N32PN·T *difference ,N32PN·T *a ,N32PN·T *b){ + uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; + difference->d0 = (uint32_t)diff; + return (diff > a->d0) ? N32PN·Status·borrow : N32PN·Status·ok; + } + + + Local N32PN·Status N32PN·multiply(N32PN·T *product1 ,N32PN·T *product0 ,N32PN·T *a ,N32PN·T *b){ + uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; + product0->d0 = (uint32_t)product; + product1->d0 = (uint32_t)(product >> 32); + + if(product1->d0 == 0) return N32PN·Status·one_word_product; + return N32PN·Status·two_word_product; + } + + Local N32PN·Status N32PN·divide(N32PN·T *remainder ,N32PN·T *quotient ,N32PN·T *a ,N32PN·T *b){ + if(b->d0 == 0) return N32PN·Status·undefined_divide_by_zero; + + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); + + return N32PN·Status·ok; + } + + Local N32PN·Status N32PN·modulus(N32PN·T *remainder ,N32PN·T *a ,N32PN·T *b){ + if(b->d0 == 0) return N32PN·Status·undefined_modulus_zero; + uint32_t quotient = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient * b->d0); + return N32PN·Status·ok; + } + + // bit motion + + typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); + + Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ + return value << amount; + } + + Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ + return value >> amount; + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, + Local N32PN·Status N32PN·shift + ( + uint32_t shift_count + ,N32PN·T *spill + ,N32PN·T *operand + ,N32PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + // If no result is needed, return immediately. + if(operand == NULL && spill == NULL) return N32PN·Status·ok; + + // Treat NULL operand as zero. + if(operand == NULL){ + operand = &N32PN·t[0]; + N32PN·copy(operand, N32PN·zero); + } + + // Shifting more than one word breaks our fill/spill model. + if(shift_count > 31) return N32PN·Status·gt_max_shift_count; + + // The given operand is still required after it is modified, so we copy it. + N32PN·T *given_operand = &N32PN·t[1]; + N32PN·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); + N32PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); + } + + return N32PN·Status·ok; + } + + // Define concrete shift functions using valid C function pointers + Local N32PN·Status + N32PN·shift_left(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){ + return N32PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N32PN·Status + N32PN·shift_right(uint32_t shift_count, N32PN·T *spill, N32PN·T *operand, N32PN·T *fill){ + return N32PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N32PN·Status + N32PN·arithmetic_shift_right(uint32_t shift_count, N32PN·T *operand, N32PN·T *spill){ + + // Guard against excessive shift counts + if(shift_count > 31) return N32PN·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N32PN·t[0]; + N32PN·copy(operand, N32PN·zero); + } + + // Pick the fill value based on the sign bit + N32PN·T *fill = (operand->d0 & 0x80000000) ? N32PN·all_one_bit : N32PN·zero; + + // Call shift_right with the appropriate fill + return N32PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N32PN·Λ N32PN·λ = { + + .allocate_array = N32PN·allocate_array + ,.allocate_array_zero = N32PN·allocate_array_zero + ,.deallocate = N32PN·deallocate + + ,.copy = N32PN·copy + ,.bit_and = N32PN·bit_and + ,.bit_or = N32PN·bit_or + ,.bit_complement = N32PN·bit_complement + ,.bit_twos_complement = N32PN·bit_twos_complement + ,.compare = N32PN·compare + ,.lt = N32PN·lt + ,.gt = N32PN·gt + ,.eq = N32PN·eq + ,.eq_zero = N32PN·eq_zero + ,.accumulate = N32PN·accumulate + ,.add = N32PN·add + ,.increment = N32PN·increment + ,.subtract = N32PN·subtract + ,.multiply = N32PN·multiply + ,.divide = N32PN·divide + ,.modulus = N32PN·modulus + ,.shift_left = N32PN·shift_left + ,.shift_right = N32PN·shift_right + ,.arithmetic_shift_right = N32PN·arithmetic_shift_right + + ,.access = N32PN·access + ,.from_uint32 = N32PN·from_uint32 + }; + + #endif + +#endif diff --git a/tester/cc/N64PN.lib.c b/tester/cc/N64PN.lib.c new file mode 100644 index 0000000..583ad08 --- /dev/null +++ b/tester/cc/N64PN.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 N64PN·DEBUG + +#ifndef FACE +#define N64PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N64PN·FACE +#define N64PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint64_t Extent; + typedef uint64_t Digit; + + typedef struct N64PN·T N64PN·T; + + extern N64PN·T *N64PN·zero; + extern N64PN·T *N64PN·one; + extern N64PN·T *N64PN·all_one_bit; + extern N64PN·T *N64PN·lsb; + extern N64PN·T *N64PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum { + N64PN·Status·ok = 0 + ,N64PN·Status·overflow = 1 + ,N64PN·Status·accumulator1_overflow = 2 + ,N64PN·Status·carry = 3 + ,N64PN·Status·borrow = 4 + ,N64PN·Status·undefined_divide_by_zero = 5 + ,N64PN·Status·undefined_modulus_zero = 6 + ,N64PN·Status·gt_max_shift_count = 7 + ,N64PN·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N64PN·Status·one_word_product = 9 + ,N64PN·Status·two_word_product = 10 + } N64PN·Status; + + typedef enum { + N64PN·Order_lt = -1 + ,N64PN·Order_eq = 0 + ,N64PN·Order_gt = 1 + } N64PN·Order; + + typedef N64PN·T *(*N64PN·Allocate_MemoryFault)(Extent); + + //---------------------------------------- + // Interface + + typedef struct { + + N64PN·T *(*allocate_array_zero)(Extent, N64PN·Allocate_MemoryFault); + N64PN·T *(*allocate_array)(Extent, N64PN·Allocate_MemoryFault); + void (*deallocate)(N64PN·T*); + + void (*copy)(N64PN·T*, N64PN·T*); + void (*bit_and)(N64PN·T*, N64PN·T*, N64PN·T*); + void (*bit_or)(N64PN·T*, N64PN·T*, N64PN·T*); + void (*bit_complement)(N64PN·T*, N64PN·T*); + void (*bit_twos_complement)(N64PN·T*, N64PN·T*); + N64PN·Order (*compare)(N64PN·T*, N64PN·T*); + bool (*lt)(N64PN·T*, N64PN·T*); + bool (*gt)(N64PN·T*, N64PN·T*); + bool (*eq)(N64PN·T*, N64PN·T*); + bool (*eq_zero)(N64PN·T*); + N64PN·Status (*accumulate)(N64PN·T *accumulator1, N64PN·T *accumulator0, ...); + N64PN·Status (*add)(N64PN·T*, N64PN·T*, N64PN·T*); + bool (*increment)(N64PN·T *a); + N64PN·Status (*subtract)(N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*multiply)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*divide)(N64PN·T*, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*modulus)(N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*shift_left)(Extent, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*shift_right)(Extent, N64PN·T*, N64PN·T*, N64PN·T*); + N64PN·Status (*arithmetic_shift_right)(Extent, N64PN·T*, N64PN·T*); + + N64PN·T* (*access)(N64PN·T*, Extent); + void (*from_uint64)(N64PN·T *destination, uint64_t value); + + } N64PN·Λ; + + Local const N64PN·Λ N64PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N64PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N64PN·T { + Digit d0; + }; + + // For constants, we store them in an array for convenience + // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63) + N64PN·T N64PN·constant[4] = { + {.d0 = 0ULL}, + {.d0 = 1ULL}, + {.d0 = ~(uint64_t)0ULL}, + {.d0 = 1ULL << 63} + }; + + N64PN·T *N64PN·zero = &N64PN·constant[0]; + N64PN·T *N64PN·one = &N64PN·constant[1]; + N64PN·T *N64PN·all_one_bit = &N64PN·constant[2]; + N64PN·T *N64PN·msb = &N64PN·constant[3]; + N64PN·T *N64PN·lsb = &N64PN·constant[1]; + + // allocate an array of N64 + N64PN·T *N64PN·allocate_array(Extent extent, N64PN·Allocate_MemoryFault memory_fault){ + N64PN·T *instance = malloc( (extent + 1) * sizeof(N64PN·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N64PN·T *N64PN·allocate_array_zero(Extent extent, N64PN·Allocate_MemoryFault memory_fault){ + N64PN·T *instance = calloc(extent + 1, sizeof(N64PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N64PN·deallocate(N64PN·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N64PN·T { + Digit d0; + }; + + // local temporary variables + Local N64PN·T N64PN·t[4]; + + // allocation references + extern N64PN·T *N64PN·allocate_array(Extent, N64PN·Allocate_MemoryFault); + extern N64PN·T *N64PN·allocate_array_zero(Extent, N64PN·Allocate_MemoryFault); + extern void N64PN·deallocate(N64PN·T *); + + // Access array + Local N64PN·T* N64PN·access(N64PN·T *array, Extent index){ + return &array[index]; + } + + Local void N64PN·from_uint64(N64PN·T *destination, uint64_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy + Local void N64PN·copy(N64PN·T *destination, N64PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + // bit operations + + Local void N64PN·bit_and(N64PN·T *result, N64PN·T *a, N64PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N64PN·bit_or(N64PN·T *result, N64PN·T *a, N64PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N64PN·bit_complement(N64PN·T *result, N64PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N64PN·bit_twos_complement(N64PN·T *result, N64PN·T *a){ + result->d0 = ~a->d0 + 1ULL; + } + + // compare & test functions + + Local N64PN·Order N64PN·compare(N64PN·T *a, N64PN·T *b){ + if(a->d0 < b->d0) return N64PN·Order_lt; + if(a->d0 > b->d0) return N64PN·Order_gt; + return N64PN·Order_eq; + } + + Local bool N64PN·lt(N64PN·T *a, N64PN·T *b){ + return (a->d0 < b->d0); + } + + Local bool N64PN·gt(N64PN·T *a, N64PN·T *b){ + return (a->d0 > b->d0); + } + + Local bool N64PN·eq(N64PN·T *a, N64PN·T *b){ + return (a->d0 == b->d0); + } + + Local bool N64PN·eq_zero(N64PN·T *a){ + return (a->d0 == 0ULL); + } + + // arithmetic operations + + // accumulate + Local N64PN·Status N64PN·accumulate(N64PN·T *accumulator1, N64PN·T *accumulator0, ...){ + va_list args; + va_start(args, accumulator0); + + uint64_t sum = accumulator0->d0; + uint64_t carry = 0; + N64PN·T *current; + + while( (current = va_arg(args, N64PN·T*)) ){ + uint64_t prior = sum; + sum += current->d0; + if(sum < prior){ // indicates carry + carry++; + // if carry overflowed a 64-bit, that's an accumulator1 overflow + if(carry == 0ULL){ + va_end(args); + return N64PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = carry; + return N64PN·Status·ok; + } + + // add + Local N64PN·Status N64PN·add(N64PN·T *sum, N64PN·T *a, N64PN·T *b){ + __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0; + // But to avoid using a GNU extension, we can do the simpler approach: + // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits: + uint64_t temp = a->d0 + b->d0; + sum->d0 = temp; + if(temp < a->d0) return N64PN·Status·carry; // means we overflowed + return N64PN·Status·ok; + } + + Local bool N64PN·increment(N64PN·T *a){ + uint64_t old = a->d0; + a->d0++; + // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF + return (a->d0 < old); + } + + // subtract + Local N64PN·Status N64PN·subtract(N64PN·T *difference, N64PN·T *a, N64PN·T *b){ + uint64_t tmpA = a->d0; + uint64_t tmpB = b->d0; + uint64_t diff = tmpA - tmpB; + difference->d0 = diff; + if(diff > tmpA) return N64PN·Status·borrow; // indicates we borrowed + return N64PN·Status·ok; + } + + // multiply + // We'll do a 64x64->128 using two 64-bit accumulators + Local N64PN·Status N64PN·multiply(N64PN·T *product1, N64PN·T *product0, N64PN·T *a, N64PN·T *b){ + uint64_t A = a->d0; + uint64_t B = b->d0; + + // Break each operand into high & low 32 bits + uint64_t a_lo = (uint32_t)(A & 0xffffffffULL); + uint64_t a_hi = A >> 32; + uint64_t b_lo = (uint32_t)(B & 0xffffffffULL); + uint64_t b_hi = B >> 32; + + // partial products + uint64_t low = a_lo * b_lo; // 64-bit + uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits + uint64_t high = a_hi * b_hi; // up to 64 bits + + // incorporate cross into low, high + // cross is effectively the middle bits, so shift cross by 32 and add to low + uint64_t cross_low = (cross & 0xffffffffULL) << 32; // lower part + uint64_t cross_high = cross >> 32; // upper part + + // add cross_low to low, capture carry + uint64_t old_low = low; + low += cross_low; + if(low < old_low) cross_high++; + + // final high + high += cross_high; + + // store results + product0->d0 = low; + product1->d0 = high; + + if(high == 0ULL) return N64PN·Status·one_word_product; + return N64PN·Status·two_word_product; + } + + // divide + Local N64PN·Status N64PN·divide(N64PN·T *remainder, N64PN·T *quotient, N64PN·T *a, N64PN·T *b){ + // we do not handle a > 64-bit, just the single 64-bit + if(b->d0 == 0ULL) return N64PN·Status·undefined_divide_by_zero; + + uint64_t divd = a->d0; // dividend + uint64_t divs = b->d0; // divisor + + quotient->d0 = divd / divs; + remainder->d0 = divd - (quotient->d0 * divs); + + return N64PN·Status·ok; + } + + // modulus + Local N64PN·Status N64PN·modulus(N64PN·T *remainder, N64PN·T *a, N64PN·T *b){ + if(b->d0 == 0ULL) return N64PN·Status·undefined_modulus_zero; + + uint64_t divd = a->d0; + uint64_t divs = b->d0; + uint64_t q = divd / divs; + remainder->d0 = divd - (q * divs); + + return N64PN·Status·ok; + } + + // bit motion + + typedef uint64_t (*ShiftOp)(uint64_t, uint64_t); + + Local uint64_t shift_left_op(uint64_t value, uint64_t amount){ + return (value << amount); + } + + Local uint64_t shift_right_op(uint64_t value, uint64_t amount){ + return (value >> amount); + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill + Local N64PN·Status N64PN·shift + ( + uint64_t shift_count, + N64PN·T *spill, + N64PN·T *operand, + N64PN·T *fill, + ShiftOp shift_op, + ShiftOp complement_shift_op + ){ + if(operand == NULL && spill == NULL) return N64PN·Status·ok; + + // Treat NULL operand as zero + if(operand == NULL){ + operand = &N64PN·t[0]; + N64PN·copy(operand, N64PN·zero); + } + + // Shifting more than 63 bits breaks fill/spill logic + if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count; + + N64PN·T *given_operand = &N64PN·t[1]; + N64PN·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count)); + N64PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count)); + } + + return N64PN·Status·ok; + } + + Local N64PN·Status N64PN·shift_left(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){ + return N64PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N64PN·Status N64PN·shift_right(uint64_t shift_count, N64PN·T *spill, N64PN·T *operand, N64PN·T *fill){ + return N64PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N64PN·Status N64PN·arithmetic_shift_right(uint64_t shift_count, N64PN·T *operand, N64PN·T *spill){ + if(shift_count > 63ULL) return N64PN·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N64PN·t[0]; + N64PN·copy(operand, N64PN·zero); + } + + // sign bit check + N64PN·T *fill = (operand->d0 & (1ULL << 63)) ? N64PN·all_one_bit : N64PN·zero; + return N64PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N64PN·Λ N64PN·λ = { + .allocate_array = N64PN·allocate_array + ,.allocate_array_zero = N64PN·allocate_array_zero + ,.deallocate = N64PN·deallocate + + ,.copy = N64PN·copy + ,.bit_and = N64PN·bit_and + ,.bit_or = N64PN·bit_or + ,.bit_complement = N64PN·bit_complement + ,.bit_twos_complement = N64PN·bit_twos_complement + ,.compare = N64PN·compare + ,.lt = N64PN·lt + ,.gt = N64PN·gt + ,.eq = N64PN·eq + ,.eq_zero = N64PN·eq_zero + ,.accumulate = N64PN·accumulate + ,.add = N64PN·add + ,.increment = N64PN·increment + ,.subtract = N64PN·subtract + ,.multiply = N64PN·multiply + ,.divide = N64PN·divide + ,.modulus = N64PN·modulus + ,.shift_left = N64PN·shift_left + ,.shift_right = N64PN·shift_right + ,.arithmetic_shift_right = N64PN·arithmetic_shift_right + + ,.access = N64PN·access + ,.from_uint64 = N64PN·from_uint64 + }; + + #endif + +#endif diff --git a/tester/cc/N8PN.lib.c b/tester/cc/N8PN.lib.c new file mode 100644 index 0000000..9cfd66d --- /dev/null +++ b/tester/cc/N8PN.lib.c @@ -0,0 +1,433 @@ +/* + N8PN - PN = refers to the use of processor native accumulator + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N8PN·DEBUG + +#ifndef FACE +#define N8PN·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N8PN·FACE +#define N8PN·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint8_t Extent; + typedef uint8_t Digit; + + typedef struct N8PN·T N8PN·T; + + extern N8PN·T *N8PN·zero; + extern N8PN·T *N8PN·one; + extern N8PN·T *N8PN·all_one_bit; + extern N8PN·T *N8PN·lsb; + extern N8PN·T *N8PN·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N8PN·Status·ok = 0 + ,N8PN·Status·overflow = 1 + ,N8PN·Status·accumulator1_overflow = 2 + ,N8PN·Status·carry = 3 + ,N8PN·Status·borrow = 4 + ,N8PN·Status·undefined_divide_by_zero = 5 + ,N8PN·Status·undefined_modulus_zero = 6 + ,N8PN·Status·gt_max_shift_count = 7 + ,N8PN·Status·spill_eq_operand = 8 + ,N8PN·Status·one_word_product = 9 + ,N8PN·Status·two_word_product = 10 + } N8PN·Status; + + typedef enum{ + N8PN·Order_lt = -1 + ,N8PN·Order_eq = 0 + ,N8PN·Order_gt = 1 + } N8PN·Order; + + typedef N8PN·T *( *N8PN·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N8PN·T *(*allocate_array_zero)(Extent, N8PN·Allocate_MemoryFault); + N8PN·T *(*allocate_array)(Extent, N8PN·Allocate_MemoryFault); + void (*deallocate)(N8PN·T*); + + void (*copy)(N8PN·T*, N8PN·T*); + void (*bit_and)(N8PN·T*, N8PN·T*, N8PN·T*); + void (*bit_or)(N8PN·T*, N8PN·T*, N8PN·T*); + void (*bit_complement)(N8PN·T*, N8PN·T*); + void (*bit_twos_complement)(N8PN·T*, N8PN·T*); + N8PN·Order (*compare)(N8PN·T*, N8PN·T*); + bool (*lt)(N8PN·T*, N8PN·T*); + bool (*gt)(N8PN·T*, N8PN·T*); + bool (*eq)(N8PN·T*, N8PN·T*); + bool (*eq_zero)(N8PN·T*); + N8PN·Status (*accumulate)(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...); + N8PN·Status (*add)(N8PN·T*, N8PN·T*, N8PN·T*); + bool (*increment)(N8PN·T *a); + N8PN·Status (*subtract)(N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*multiply)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*divide)(N8PN·T*, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*modulus)(N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*shift_left)(Extent, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*shift_right)(Extent, N8PN·T*, N8PN·T*, N8PN·T*); + N8PN·Status (*arithmetic_shift_right)(Extent, N8PN·T*, N8PN·T*); + + N8PN·T* (*access)(N8PN·T*, Extent); + void (*from_uint32)(N8PN·T *destination ,uint32_t value); + } N8PN·Λ; + + Local const N8PN·Λ N8PN·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N8PN·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N8PN·T{ + Digit d0; + }; + + N8PN·T N8PN·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint8_t)0}, + {.d0 = 1 << 7} + }; + + N8PN·T *N8PN·zero = &N8PN·constant[0]; + N8PN·T *N8PN·one = &N8PN·constant[1]; + N8PN·T *N8PN·all_one_bit = &N8PN·constant[2]; + N8PN·T *N8PN·msb = &N8PN·constant[3]; + N8PN·T *N8PN·lsb = &N8PN·constant[1]; + + // the allocate an array of N8 + N8PN·T *N8PN·allocate_array(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){ + N8PN·T *instance = malloc((extent + 1) * sizeof(N8PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N8PN·T *N8PN·allocate_array_zero(Extent extent ,N8PN·Allocate_MemoryFault memory_fault){ + N8PN·T *instance = calloc(extent + 1, sizeof(N8PN·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N8PN·deallocate(N8PN·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N8PN·T{ + Digit d0; + }; + + // temporary variables + Local N8PN·T N8PN·t[4]; + + // allocation + + extern N8PN·T *N8PN·allocate_array(Extent, N8PN·Allocate_MemoryFault); + extern N8PN·T *N8PN·allocate_array_zero(Extent, N8PN·Allocate_MemoryFault); + extern void N8PN·deallocate(N8PN·T *); + + // so the user can access numbers in an array allocation + Local N8PN·T* N8PN·access(N8PN·T *array ,Extent index){ + return &array[index]; + } + + Local void N8PN·from_uint32(N8PN·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint8_t)(value & 0xFF); + } + + // copy, convenience copy + + Local void N8PN·copy(N8PN·T *destination ,N8PN·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N8PN·set_to_zero(N8PN·T *instance){ + instance->d0 = 0; + } + + Local void N8PN·set_to_one(N8PN·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N8PN·bit_and(N8PN·T *result, N8PN·T *a, N8PN·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N8PN·bit_or(N8PN·T *result, N8PN·T *a, N8PN·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N8PN·bit_complement(N8PN·T *result, N8PN·T *a){ + result->d0 = ~a->d0; + } + + Local void N8PN·bit_twos_complement(N8PN·T *result ,N8PN·T *a){ + result->d0 = (uint8_t)(~a->d0 + 1); + } + + // test functions + + Local N8PN·Order N8PN·compare(N8PN·T *a, N8PN·T *b){ + if(a->d0 < b->d0) return N8PN·Order_lt; + if(a->d0 > b->d0) return N8PN·Order_gt; + return N8PN·Order_eq; + } + + Local bool N8PN·lt(N8PN·T *a ,N8PN·T *b){ + return a->d0 < b->d0; + } + + Local bool N8PN·gt(N8PN·T *a ,N8PN·T *b){ + return a->d0 > b->d0; + } + + Local bool N8PN·eq(N8PN·T *a ,N8PN·T *b){ + return a->d0 == b->d0; + } + + Local bool N8PN·eq_zero(N8PN·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N8PN·Status N8PN·accumulate(N8PN·T *accumulator1 ,N8PN·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N8PN·T *current; + + while( (current = va_arg(args ,N8PN·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N8PN·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint8_t)carry; + return N8PN·Status·ok; + } + + Local N8PN·Status N8PN·add(N8PN·T *sum ,N8PN·T *a ,N8PN·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint8_t)(result & 0xFF); + return (result >> 8) ? N8PN·Status·carry : N8PN·Status·ok; + } + + Local bool N8PN·increment(N8PN·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N8PN·Status N8PN·subtract(N8PN·T *difference ,N8PN·T *a ,N8PN·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint8_t)(diff & 0xFF); + return (diff > a->d0) ? N8PN·Status·borrow : N8PN·Status·ok; + } + + Local N8PN·Status N8PN·multiply(N8PN·T *product1 ,N8PN·T *product0 ,N8PN·T *a ,N8PN·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint8_t)(product & 0xFF); + product1->d0 = (uint8_t)((product >> 8) & 0xFF); + + if(product1->d0 == 0) return N8PN·Status·one_word_product; + return N8PN·Status·two_word_product; + } + + Local N8PN·Status N8PN·divide(N8PN·T *remainder ,N8PN·T *quotient ,N8PN·T *a ,N8PN·T *b){ + if(b->d0 == 0) return N8PN·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint8_t)(dividend / divisor); + remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor)); + + return N8PN·Status·ok; + } + + Local N8PN·Status N8PN·modulus(N8PN·T *remainder ,N8PN·T *a ,N8PN·T *b){ + if(b->d0 == 0) return N8PN·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint8_t)(dividend - (q * divisor)); + return N8PN·Status·ok; + } + + // bit motion + + typedef uint8_t (*ShiftOp)(uint8_t, uint8_t); + + Local uint8_t shift_left_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value << amount); + } + + Local uint8_t shift_right_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value >> amount); + } + + Local N8PN·Status N8PN·shift + ( + uint8_t shift_count + ,N8PN·T *spill + ,N8PN·T *operand + ,N8PN·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N8PN·Status·ok; + + if(operand == NULL){ + operand = &N8PN·t[0]; + N8PN·copy(operand, N8PN·zero); + } + + if(shift_count > 7) return N8PN·Status·gt_max_shift_count; + + N8PN·T *given_operand = &N8PN·t[1]; + N8PN·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (8 - shift_count)); + N8PN·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count)); + } + + return N8PN·Status·ok; + } + + Local N8PN·Status + N8PN·shift_left(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){ + return N8PN·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N8PN·Status + N8PN·shift_right(uint8_t shift_count, N8PN·T *spill, N8PN·T *operand, N8PN·T *fill){ + return N8PN·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N8PN·Status + N8PN·arithmetic_shift_right(uint8_t shift_count, N8PN·T *operand, N8PN·T *spill){ + + if(shift_count > 7) return N8PN·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N8PN·t[0]; + N8PN·copy(operand, N8PN·zero); + } + + N8PN·T *fill = (operand->d0 & 0x80) ? N8PN·all_one_bit : N8PN·zero; + return N8PN·shift_right(shift_count, spill, operand, fill); + } + + Local const N8PN·Λ N8PN·λ = { + + .allocate_array = N8PN·allocate_array + ,.allocate_array_zero = N8PN·allocate_array_zero + ,.deallocate = N8PN·deallocate + + ,.copy = N8PN·copy + ,.bit_and = N8PN·bit_and + ,.bit_or = N8PN·bit_or + ,.bit_complement = N8PN·bit_complement + ,.bit_twos_complement = N8PN·bit_twos_complement + ,.compare = N8PN·compare + ,.lt = N8PN·lt + ,.gt = N8PN·gt + ,.eq = N8PN·eq + ,.eq_zero = N8PN·eq_zero + ,.accumulate = N8PN·accumulate + ,.add = N8PN·add + ,.increment = N8PN·increment + ,.subtract = N8PN·subtract + ,.multiply = N8PN·multiply + ,.divide = N8PN·divide + ,.modulus = N8PN·modulus + ,.shift_left = N8PN·shift_left + ,.shift_right = N8PN·shift_right + ,.arithmetic_shift_right = N8PN·arithmetic_shift_right + + ,.access = N8PN·access + ,.from_uint32 = N8PN·from_uint32 + }; + + #endif + +#endif diff --git "a/tester/cc\360\237\226\211/environment.h" "b/tester/cc\360\237\226\211/environment.h" new file mode 100644 index 0000000..cdea83c --- /dev/null +++ "b/tester/cc\360\237\226\211/environment.h" @@ -0,0 +1,5 @@ +#ifndef Mpblock·ENVIRONMENT_H +#define Mpblock·ENVIRONMENT_H + + +#endif diff --git "a/developer/cc\360\237\226\211/test_N32.cli.c" "b/tester/cc\360\237\226\211/test_N32.cli.c" similarity index 100% rename from "developer/cc\360\237\226\211/test_N32.cli.c" rename to "tester/cc\360\237\226\211/test_N32.cli.c" diff --git "a/tester/cc\360\237\226\211/test_setup.cli.c" "b/tester/cc\360\237\226\211/test_setup.cli.c" new file mode 100644 index 0000000..f1c6e68 --- /dev/null +++ "b/tester/cc\360\237\226\211/test_setup.cli.c" @@ -0,0 +1,22 @@ +/* + + A placeholder to see if make etc. is working. + +*/ + +#define IFACE +#include +#include + +// No need to define IMPLEMENTATION as `main` is one and done. + +int main(int argc ,char *argv[] ,char *envp[]){ + if(argc != 1){ + fprintf(stderr, "Usage: %s\n", argv[0]); + return EXIT_FAILURE; + } + + fprintf(stderr, "%s done\n", argv[0]); + + return 0; +} diff --git a/tester/machine/.gitignore b/tester/machine/.gitignore new file mode 100644 index 0000000..120f485 --- /dev/null +++ b/tester/machine/.gitignore @@ -0,0 +1,2 @@ +* +!/.gitignore diff --git a/tester/scratchpad/.gitignore b/tester/scratchpad/.gitignore new file mode 100644 index 0000000..120f485 --- /dev/null +++ b/tester/scratchpad/.gitignore @@ -0,0 +1,2 @@ +* +!/.gitignore diff --git "a/tester/tool\360\237\226\211/env" "b/tester/tool\360\237\226\211/env" new file mode 100644 index 0000000..355a02c --- /dev/null +++ "b/tester/tool\360\237\226\211/env" @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="tool_shared/bespoke🖉/env" + error_bad_env=false + error_not_sourced=false + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + error_bad_env=true + fi + if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + echo "$script_afp:: This script must be sourced, not executed." + error_not_sourced=true + fi + if $error_not_sourced; then exit 1; fi + if $error_bad_env; then return 1; fi + + +export ROLE=tester + +# so we can do the build + +export PATH=\ +"$REPO_HOME"/${ROLE}/tool🖉/\ +:"$PATH" + +# misc + + # make .githolder and .gitignore visible + alias ls="ls -a" + +# some feedback to show all went well + + export PROMPT_DECOR="$PROJECT_$ROLE" + export ENV=$(script_fp) + echo ENV "$ENV" + cd "$REPO_HOME/$ROLE" + + + diff --git "a/tester/tool\360\237\226\211/make" "b/tester/tool\360\237\226\211/make" new file mode 100755 index 0000000..e0f787f --- /dev/null +++ "b/tester/tool\360\237\226\211/make" @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="tester/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + +cd "$REPO_HOME"/tester || exit 1 + +/bin/make -f tool🖉/makefile $@ + +set +x +echo "$(script_fn) done." diff --git "a/tester/tool\360\237\226\211/makefile" "b/tester/tool\360\237\226\211/makefile" new file mode 100644 index 0000000..a0da057 --- /dev/null +++ "b/tester/tool\360\237\226\211/makefile" @@ -0,0 +1,18 @@ + + +RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release + +include $(RT-INCOMMON)/make/environment_RT_0 + +CFLAGS+=-Werror -include "$(RT-INCOMMON)/make/RT_0.h" +LINKFLAGS+= -l$(PROJECT) +LIBFILE=$(LIBDIR)/lib$(PROJECT).a + +include $(RT-INCOMMON)/make/targets +-include $(DEPFILE) + + + + + + diff --git "a/tester/tool\360\237\226\211/pull_release" "b/tester/tool\360\237\226\211/pull_release" new file mode 100755 index 0000000..a083b91 --- /dev/null +++ "b/tester/tool\360\237\226\211/pull_release" @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# before running this script, gather everything needed for the release on the scratchpad + +# input guards + + env_must_be="tester/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + cd "$REPO_HOME"/tester || exit 1 + + if [ ! -d scratchpad ]; then + echo "$(script_fp):: no scratchpad directory" + exit 1 + fi + + release_dir=$(release_dir) + + if [ ! -d ${release_dir} ]; then + echo "$(script_fp):: no release directory to pull install files from" + exit 1 + fi + + + cp ${release_dir}/libN.a scratchpad || true + cp ${release_dir}/*.lib.c cc || true + +set +x +echo "$(script_fn) done." + diff --git "a/tester/tool\360\237\226\211/release_test" "b/tester/tool\360\237\226\211/release_test" new file mode 100755 index 0000000..3d31406 --- /dev/null +++ "b/tester/tool\360\237\226\211/release_test" @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# release test machine code + +# input guards + + env_must_be="tester/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + cd "$REPO_HOME"/tester || exit 1 + + if [ ! -d scratchpad ]; then + echo "$(script_fp):: no scratchpad directory" + exit 1 + fi + + release_dir=$(release_dir) + + if [ ! -d ${release_dir} ]; then + echo "$(script_fp):: no release directory to pull install files from" + exit 1 + fi + + install_file machine/* ${release_dir} "ug+rx" + + + + +set +x +echo "$(script_fn) done." + diff --git "a/tool_shared/bespoke\360\237\226\211/env" "b/tool_shared/bespoke\360\237\226\211/env" index 01f47a3..f9671cc 100644 --- "a/tool_shared/bespoke\360\237\226\211/env" +++ "b/tool_shared/bespoke\360\237\226\211/env" @@ -72,6 +72,44 @@ shopt -s nullglob export -f script_adp script_fn script_dp script_fp +#-------------------------------------------------------------------------------- +# used by release scripts +# + + install_file() { + if [ "$#" -lt 3 ]; then + echo "Usage: install_file ... " + return 1 + fi + + perms="${@: -1}" # Last argument is permissions + target_dp="${@: -2:1}" # Second-to-last argument is the target directory + sources=("${@:1:$#-2}") # All other arguments are source files + + if [ ! -d "$target_dp" ]; then + echo "Error: Target directory '$target_dp' does not exist." + return 1 + fi + + for source_fp in "${sources[@]}"; do + if [ ! -f "$source_fp" ]; then + echo "Error: Source file '$source_fp' does not exist." + return 1 + fi + + target_file="$target_dp/$(basename "$source_fp")" + + if ! install -m "$perms" "$source_fp" "$target_file"; then + echo "Error: Failed to install $(basename "$source_fp") to $target_dp" + return 1 + else + echo "Installed $(basename "$source_fp") to $target_dp with permissions $perms" + fi + done + } + + export -f install_file + # -------------------------------------------------------------------------------- # closing # -- 2.20.1