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