From: Thomas Walker Lynch Date: Thu, 20 Feb 2025 10:50:46 +0000 (+0000) Subject: bespoke bit copy transfers to and from processor native types X-Git-Url: https://git.reasoningtechnology.com/style/static/git-logo.png?a=commitdiff_plain;h=0d355b4cda45ab66676233a289653f6fc456f22b;p=N bespoke bit copy transfers to and from processor native types --- diff --git "a/developer/Python\360\237\226\211/fill_template" "b/developer/Python\360\237\226\211/fill_template" index 4569e33..67e57ec 100755 --- "a/developer/Python\360\237\226\211/fill_template" +++ "b/developer/Python\360\237\226\211/fill_template" @@ -2,7 +2,6 @@ import sys from template_N import N -from make_constants import make_constants_block def write(code ,basename): filepath = "../cc/" + basename + ".lib.c" @@ -21,21 +20,35 @@ def main(): type_name = "N32_1x32" digit_type = "uint32_t" - digit_extent = 0 - - constants_block = make_constants_block(type_name, digit_type, digit_extent) - code = N(type_name ,digit_type ,digit_extent ,constants_block) + digit_array_extent_type = "uint32_t" + digit_array_extent = 0 + address_type = "uint64_t" + + code = N( + type_name + ,digit_type + ,digit_array_extent_type + ,digit_array_extent + ,address_type + ) write(code ,type_name); #---------------------------------------- # N32 made from 4 digits, each 8 bits. - type_name = "N32_4x8" - digit_type = "uint8_t" - digit_extent = 3 - - constants_block = make_constants_block(type_name, digit_type, digit_extent) - code = N(type_name ,digit_type ,digit_extent ,constants_block) + type_name = "N32_1x32" + digit_type = "uint32_t" + digit_array_extent_type = "uint8_t" + digit_array_extent = 3 + address_type = "uint64_t" + + code = N( + type_name + ,digit_type + ,digit_array_extent_type + ,digit_array_extent + ,address_type + ) write(code ,type_name); if __name__ == "__main__": diff --git "a/developer/Python\360\237\226\211/make_N_constants.py" "b/developer/Python\360\237\226\211/make_N_constants.py" new file mode 100755 index 0000000..6a51113 --- /dev/null +++ "b/developer/Python\360\237\226\211/make_N_constants.py" @@ -0,0 +1,59 @@ + +def make_N_constants( + namespace: str, + digit_type: str, + digit_array_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_array_extent + 1. + """ + digit_count = digit_array_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/Python\360\237\226\211/make_constants.py" "b/developer/Python\360\237\226\211/make_constants.py" deleted file mode 100755 index a177fde..0000000 --- "a/developer/Python\360\237\226\211/make_constants.py" +++ /dev/null @@ -1,56 +0,0 @@ -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/Python\360\237\226\211/template_N.py" "b/developer/Python\360\237\226\211/template_N.py" index bc2cc5e..8362083 100644 --- "a/developer/Python\360\237\226\211/template_N.py" +++ "b/developer/Python\360\237\226\211/template_N.py" @@ -1,23 +1,36 @@ + +from template_conversion import conversion +from make_N_constants import make_N_constants + def N( - namespace: str - ,digit_type: str - ,digit_array_extent_type: int - ,address_type: str - ,constants_block: str - ) -> str: - - """ - Returns a source code file for cc to munch on - """ - template = template_N() - code = template.format( - NS = namespace - ,DIGIT_TYPE = digit_type - ,DIGIT_ARRAY_EXTENT_TYPE = digit_array_extent_type - ,AddressType = address_type - ,CONSTANTS_BLOCK = constants_block - ) - return code + namespace + ,digit_type + ,digit_array_extent_type + ,digit_array_extent + ,address_type + ): + """ + Returns a source code file for cc to munch on. + """ + + template = template_N() + code = ( + template + .replace("NS" ,namespace) + .replace("DIGIT_TYPE" ,digit_type) + .replace("DIGIT_ARRAY_EXTENT_TYPE" ,str(digit_array_extent_type)) + .replace("DIGIT_ARRAY_EXTENT" ,str(digit_array_extent)) + .replace("ADDRESS_TYPE" ,address_type) + .replace("CONSTANTS_BLOCK" + ,make_N_constants(namespace ,digit_type ,digit_array_extent)) + .replace("CONV_8" ,conversion("uint8_t")) + .replace("CONV_16" ,conversion("uint16_t")) + .replace("CONV_32" ,conversion("uint32_t")) + .replace("CONV_64" ,conversion("uint64_t")) + .replace("CONV_128" ,conversion("__uint128_t")) + ) + + return code def template_N(): return r''' @@ -27,18 +40,18 @@ def template_N(): T - Is the type for the tableau. */ -#define {NS}·DEBUG +#define NS·DEBUG #ifndef FACE -#define {NS}·IMPLEMENTATION +#define NS·IMPLEMENTATION #define FACE #endif //-------------------------------------------------------------------------------- // Interface -#ifndef {NS}·FACE -#define {NS}·FACE +#ifndef NS·FACE +#define NS·FACE #include #include @@ -48,106 +61,157 @@ def template_N(): //---------------------------------------- // Instance Data (Declaration Only) - typedef {ADDRESS_TYPE} Address; -// +3 - 1 due to 0x and the trailing null character, and being an extent + typedef ADDRESS_TYPE Address; // tableau type, encapsulated data is unavailable to user code - typedef struct {NS}·T {NS}·T; + typedef struct NS·T NS·T; - extern {NS}·T *{NS}·zero; - extern {NS}·T *{NS}·one; - extern {NS}·T *{NS}·all_one_bit; - extern {NS}·T *{NS}·lsb; - extern {NS}·T *{NS}·msb; + extern NS·T *NS·zero; + extern NS·T *NS·one; + extern NS·T *NS·all_one_bit; + extern NS·T *NS·lsb; + extern NS·T *NS·msb; //---------------------------------------- // Return/Error Status and handlers - typedef enum{{ - {NS}·Status·ok = 0 - ,{NS}·Status·overflow = 1 - ,{NS}·Status·accumulator_overflow = 2 - ,{NS}·Status·carry = 3 - ,{NS}·Status·borrow = 4 - ,{NS}·Status·undefined_divide_by_zero = 5 - ,{NS}·Status·undefined_modulus_zero = 6 - ,{NS}·Status·gt_max_shift_count = 7 - ,{NS}·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value - ,{NS}·Status·one_word_product = 9 - ,{NS}·Status·two_word_product = 10 - }} {NS}·Status; - - typedef enum{{ - {NS}·Order_lt = -1 - ,{NS}·Order_eq = 0 - ,{NS}·Order_gt = 1 - }} {NS}·Order; + typedef enum{ + NS·Status·ok, + NS·Status·overflow, + NS·Status·accumulator_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, // not currently signaled, result will be spill value + NS·Status·one_word_product, + NS·Status·two_word_product, + NS·Status·ConversionOverflow + } NS·Status; + + typedef enum{ + NS·Order_lt = -1 + ,NS·Order_eq = 0 + ,NS·Order_gt = 1 + } NS·Order; + + // Incomplete conversion NS·T -> PNT, NS·T leftovers + typedef struct { + size_t scale; // this is in bytes + NS·T *d; // digits, programmer must point this to a register + } NS·Leftover_N; + + // Incomplete conversion PNT -> NS·T, PNT leftovers + #define NS·LEFTOVER_PNT(PNT)\ + typedef struct {\ + size_t scale; // this is in bytes\ + PNT leftover; // Residual value in PNT format\ + } NS·Leftover_##PNT; + + #ifdef UINT8_MAX + NS·LEFTOVER_PNT(uint8_t) + #endif + #ifdef UINT16_MAX + NS·LEFTOVER_PNT(uint16_t) + #endif + #ifdef UINT32_MAX + NS·LEFTOVER_PNT(uint32_t) + #endif + #ifdef UINT64_MAX + NS·LEFTOVER_PNT(uint64_t) + #endif + #ifdef __UINT128_MAX + NS·LEFTOVER_PNT(__uint128_t) + #endif // when alloc runs out of memory - typedef {NS}·T *( *{NS}·Allocate_MemoryFault )(Address); + typedef NS·T *( *NS·Allocate_MemoryFault )(Address); //---------------------------------------- // Interface - typedef struct{{ + #define NS·TO_TYPE(PNT) NS·Status (*to_##PNT)(const NS·T *, PNT *, NS·Leftover_N *) + #define NS·FROM_TYPE(PNT) NS·Status (*from_##PNT)(const PNT *, NS·T * ,NS·Leftover_##PNT *) + + typedef struct{ // memory allocation - {NS}·T *(*allocate_array_zero)(Address, {NS}·Allocate_MemoryFault); - {NS}·T *(*allocate_array)(Address, {NS}·Allocate_MemoryFault); - void (*deallocate)({NS}·T*); - {NS}·T* (*access)({NS}·T*, Address); + NS·T *(*allocate_array_zero)(Address, NS·Allocate_MemoryFault); + NS·T *(*allocate_array)(Address, NS·Allocate_MemoryFault); + void (*deallocate)(NS·T*); + NS·T* (*access)(NS·T*, Address); // results fits in operand type functions - void (*copy)({NS}·T*, {NS}·T*); - void (*bit_and)({NS}·T*, {NS}·T*, {NS}·T*); - void (*bit_or)({NS}·T*, {NS}·T*, {NS}·T*); - void (*bit_complement)({NS}·T*, {NS}·T*); - void (*bit_twos_complement)({NS}·T*, {NS}·T*); + void (*copy)(NS·T*, NS·T*); + void (*bit_and)(NS·T*, NS·T*, NS·T*); + void (*bit_or)(NS·T*, NS·T*, NS·T*); + void (*bit_complement)(NS·T*, NS·T*); + void (*bit_twos_complement)(NS·T*, NS·T*); // tests - {NS}·Order (*compare)({NS}·T*, {NS}·T*); - bool (*lt)({NS}·T*, {NS}·T*); - bool (*gt)({NS}·T*, {NS}·T*); - bool (*eq)({NS}·T*, {NS}·T*); - bool (*eq_zero)({NS}·T*); + NS·Order (*compare)(NS·T*, NS·T*); + bool (*lt)(NS·T*, NS·T*); + bool (*gt)(NS·T*, NS·T*); + bool (*eq)(NS·T*, NS·T*); + bool (*eq_zero)(NS·T*); // arithmetic - {NS}·Status (*accumulate)({NS}·T *accumulator1 ,{NS}·T *accumulator0 ,...); - {NS}·Status (*add)({NS}·T*, {NS}·T*, {NS}·T*); - bool (*increment)({NS}·T *a); - {NS}·Status (*subtract)({NS}·T*, {NS}·T*, {NS}·T*); - {NS}·Status (*multiply)({NS}·T*, {NS}·T*, {NS}·T*, {NS}·T*); - {NS}·Status (*divide)({NS}·T*, {NS}·T*, {NS}·T*, {NS}·T*); - {NS}·Status (*modulus)({NS}·T*, {NS}·T*, {NS}·T*); + NS·Status (*accumulate)(NS·T *accumulator1 ,NS·T *accumulator0 ,...); + NS·Status (*add)(NS·T*, NS·T*, NS·T*); + bool (*increment)(NS·T *a); + NS·Status (*subtract)(NS·T*, NS·T*, NS·T*); + NS·Status (*multiply)(NS·T*, NS·T*, NS·T*, NS·T*); + NS·Status (*divide)(NS·T*, NS·T*, NS·T*, NS·T*); + NS·Status (*modulus)(NS·T*, NS·T*, NS·T*); // shift - {NS}·Status (*shift_left)(Address, {NS}·T*, {NS}·T*, {NS}·T*); - {NS}·Status (*shift_right)(Address, {NS}·T*, {NS}·T*, {NS}·T*); - {NS}·Status (*arithmetic_shift_right)(Address, {NS}·T*, {NS}·T*); + NS·Status (*shift_left)(Address, NS·T*, NS·T*, NS·T*); + NS·Status (*shift_right)(Address, NS·T*, NS·T*, NS·T*); + NS·Status (*arithmetic_shift_right)(Address, NS·T*, NS·T*); // import/export - void (*to_string)(char [print_buffer_extent + 1] ,uint32_t value); - void (*from_uint32)({NS}·T *destination ,uint32_t value); + char *(*to_string)(NS·T *); + #ifdef UINT8_MAX + NS·TO_TYPE(uint8_t) + NS·FROM_TYPE(uint8_t) + #endif + #ifdef UINT16_MAX + NS·TO_TYPE(uint16_t) + NS·FROM_TYPE(uint16_t) + #endif + #ifdef UINT32_MAX + NS·TO_TYPE(uint32_t) + NS·FROM_TYPE(uint32_t) + #endif + #ifdef UINT64_MAX + NS·TO_TYPE(uint64_t) + NS·FROM_TYPE(uint64_t) + #endif + #ifdef __UINT128_MAX + NS·TO_TYPE(__uint128_t) + NS·FROM_TYPE(__uint128_t) + #endif - }} {NS}·M; + } NS·M; - Local const {NS}·M {NS}·m; // initialized in the LOCAL section + Local const NS·M NS·m; // initialized in the LOCAL section #endif //-------------------------------------------------------------------------------- // Implementation -#ifdef {NS}·IMPLEMENTATION +#ifdef NS·IMPLEMENTATION - typedef {DIGIT_TYPE} Digit; - const {DIGIT_ARRAY_EXTENT_TYPE} digit_array_extent = {DIGIT_ARRAY_EXTENT}; + typedef DIGIT_TYPE Digit; + const DIGIT_ARRAY_EXTENT_TYPE digit_array_extent = {DIGIT_ARRAY_EXTENT}; // full type definition for Tableau - struct {NS}·T{{ + struct NS·T{ Digit d[digit_array_extent + 1]; - }}; + }; // this part goes into Nlib.a #ifndef LOCAL @@ -157,27 +221,27 @@ def template_N(): #include // the allocate an array of N32 - {NS}·T *{NS}·allocate_array(Address extent ,{NS}·Allocate_MemoryFault memory_fault){{ - {NS}·T *instance = malloc((extent + 1) * sizeof({NS}·T) ); - if(!instance){{ + NS·T *NS·allocate_array(Address extent ,NS·Allocate_MemoryFault memory_fault){ + NS·T *instance = malloc((extent + 1) * sizeof(NS·T) ); + if(!instance){ return memory_fault ? memory_fault(extent) : NULL; - }} + } return instance; - }} + } - {NS}·T *{NS}·allocate_array_zero(Address extent ,{NS}·Allocate_MemoryFault memory_fault){{ - {NS}·T *instance = calloc( extent + 1 ,sizeof({NS}·T) ); - if(!instance){{ + NS·T *NS·allocate_array_zero(Address extent ,NS·Allocate_MemoryFault memory_fault){ + NS·T *instance = calloc( extent + 1 ,sizeof(NS·T) ); + if(!instance){ return memory_fault ? memory_fault(extent) : NULL; - }} + } return instance; - }} + } - void {NS}·deallocate({NS}·T *unencumbered){{ + void NS·deallocate(NS·T *unencumbered){ free(unencumbered); - }} + } - char *to_string({NS}·T *n) { + char *to_string(NS·T *n) { // Each byte requires two hex characters, plus "0x" prefix and null terminator const Address string_length = (sizeof(Digit) * (digit_array_extent + 1) * 2) + 3; char *buffer = malloc(string_length); @@ -204,356 +268,325 @@ def template_N(): // This part is included after the user's code. If the code at top is a 'header, then this is a 'tailer'. #ifdef LOCAL - {CONSTANTS_BLOCK} + CONSTANTS_BLOCK - {NS}·T *{NS}·zero = &{NS}·constant[0]; - {NS}·T *{NS}·one = &{NS}·constant[1]; - {NS}·T *{NS}·all_one_bit = &{NS}·constant[2]; - {NS}·T *{NS}·msb = &{NS}·constant[3]; - {NS}·T *{NS}·lsb = &{NS}·constant[1]; + NS·T *NS·zero = NS·constant + 0; + NS·T *NS·one = NS·constant + 1; + NS·T *NS·all_one_bit = NS·constant + 2; + NS·T *NS·msb = &NS·constant + 3; + NS·T *NS·lsb = &NS·constant + 1; // 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 {NS}·T {NS}·t[4]; + Local NS·T NS·t[4]; // allocation - extern {NS}·T *{NS}·allocate_array(Address, {NS}·Allocate_MemoryFault); - extern {NS}·T *{NS}·allocate_array_zero(Address, {NS}·Allocate_MemoryFault); - extern void {NS}·deallocate({NS}·T *); + extern NS·T *NS·allocate_array(Address, NS·Allocate_MemoryFault); + extern NS·T *NS·allocate_array_zero(Address, NS·Allocate_MemoryFault); + extern void NS·deallocate(NS·T *); // so the user can access numbers in an array allocation - Local {NS}·T* {NS}·access({NS}·T *array ,Address index){{ + Local NS·T* NS·access(NS·T *array ,Address index){ return array + index; - }} - - /* - // a hackish approach - void from_uint64_hack({NS}·T *n, uint64_t value) { - char buffer[24]; // Enough for "0xFFFFFFFFFFFFFFFF" - sprintf(buffer, "0x%llX", (unsigned long long)value); - from_string(n, buffer); - } - - // as it should expand out to: - void from_uint64({NS}·T *n, uint64_t value) { - Digit *pd = n->d; - for (int i = 0; i <= digit_array_extent; i++, pd++) { - *pd = (Digit)(value & ((1ULL << (sizeof(Digit) * 8)) - 1)); // Extract lower bits - value >>= sizeof(Digit) * 8; // Shift right to process next part - } - } - */ - - - #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - #define ENDIAN_DIRECTION -1 // Big-endian: Store high-to-low - #else - #define ENDIAN_DIRECTION 1 // Little-endian: Store low-to-high - #endif - - #define DEFINE_FROM_UINT(TYPE) \ - void from_##TYPE({{NS}}·T *n, TYPE value) {{ \ - const Digit digit_mask = (Digit)((1ULL << (sizeof(Digit) * 8)) - 1); \ - const Digit bits_in_digit = sizeof(Digit) * 8; - Digit *pd = (ENDIAN_DIRECTION == 1) ? n->d : (n->d + digit_array_extent); \ - for (int i = 0; i <= digit_array_extent; i++, pd += ENDIAN_DIRECTION) {{ \ - *pd = (Digit)(value & digit_mask); \ - value >>= bits_in_digit; \ - }} \ - }} - - #define DEFINE_TO_UINT(TYPE) \ - TYPE to_##TYPE(const {{NS}}·T *n) {{ \ - const Digit bits_in_digit = sizeof(Digit) * 8; \ - TYPE value = 0; \ - const Digit *pd = (ENDIAN_DIRECTION == 1) ? (n->d + digit_array_extent) : n->d; \ - for (int i = 0; i <= digit_array_extent; i++, pd -= ENDIAN_DIRECTION) {{ \ - value = (value << bits_in_digit) | *pd; \ - }} \ - return value; \ - }} - - - #ifdef UINT8_MAX - DEFINE_FROM_UINT(uint8_t) - DEFINE_TO_UINT(uint8_t) - #endif - - #ifdef UINT16_MAX - DEFINE_FROM_UINT(uint16_t) - DEFINE_TO_UINT(uint16_t) - #endif - - #ifdef UINT32_MAX - DEFINE_FROM_UINT(uint32_t) - DEFINE_TO_UINT(uint32_t) - #endif - - #ifdef UINT64_MAX - DEFINE_FROM_UINT(uint64_t) - DEFINE_TO_UINT(uint64_t) - #endif - - #ifdef __UINT128_MAX - DEFINE_FROM_UINT(__uint128_t) - DEFINE_TO_UINT(__uint128_t) - #endif + } // copy, convenience copy - Local void {NS}·copy({NS}·T *destination ,{NS}·T *source){{ + Local void NS·copy(NS·T *destination ,NS·T *source){ if(source == destination) return; // that was easy! *destination = *source; - }} + } - Local void {NS}·set_to_zero({NS}·T *instance){{ + Local void NS·set_to_zero(NS·T *instance){ instance->d0 = 0; - }} + } - Local void {NS}·set_to_one({NS}·T *instance){{ + Local void NS·set_to_one(NS·T *instance){ instance->d0 = 1; - }} + } // bit operations - Local void {NS}·bit_and({NS}·T *result, {NS}·T *a, {NS}·T *b){{ + Local void NS·bit_and(NS·T *result, NS·T *a, NS·T *b){ result->d0 = a->d0 & b->d0; - }} + } // result can be one of the operands - Local void {NS}·bit_or({NS}·T *result, {NS}·T *a, {NS}·T *b){{ + Local void NS·bit_or(NS·T *result, NS·T *a, NS·T *b){ result->d0 = a->d0 | b->d0; - }} + } // result can the same as the operand - Local void {NS}·bit_complement({NS}·T *result, {NS}·T *a){{ + Local void NS·bit_complement(NS·T *result, NS·T *a){ result->d0 = ~a->d0; - }} + } // result can the same as the operand - Local void {NS}·bit_twos_complement({NS}·T *result ,{NS}·T *a){{ + Local void NS·bit_twos_complement(NS·T *result ,NS·T *a){ result->d0 = ~a->d0 + 1; - }} + } // test functions - Local {NS}·Order {NS}·compare({NS}·T *a, {NS}·T *b){{ - if(a->d0 < b->d0) return {NS}·Order_lt; - if(a->d0 > b->d0) return {NS}·Order_gt; - return {NS}·Order_eq; - }} + Local NS·Order NS·compare(NS·T *a, NS·T *b){ + if(a->d0 < b->d0) return NS·Order_lt; + if(a->d0 > b->d0) return NS·Order_gt; + return NS·Order_eq; + } - Local bool {NS}·lt({NS}·T *a ,{NS}·T *b){{ + Local bool NS·lt(NS·T *a ,NS·T *b){ return a->d0 < b->d0; - }} + } - Local bool {NS}·gt({NS}·T *a ,{NS}·T *b){{ + Local bool NS·gt(NS·T *a ,NS·T *b){ return a->d0 > b->d0; - }} + } - Local bool {NS}·eq({NS}·T *a ,{NS}·T *b){{ + Local bool NS·eq(NS·T *a ,NS·T *b){ return a->d0 == b->d0; - }} + } - Local bool {NS}·eq_zero({NS}·T *a){{ + Local bool NS·eq_zero(NS·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 {NS}·Status·accumulator1_overflow + // 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 NS·Status·accumulator1_overflow // // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. - Local {NS}·Status {NS}·accumulate({NS}·T *accumulator1 ,{NS}·T *accumulator0 ,...){{ + Local NS·Status NS·accumulate(NS·T *accumulator1 ,NS·T *accumulator0 ,...){ va_list args; va_start(args ,accumulator0); uint32_t sum = accumulator0->d0; uint32_t carry = 0; - {NS}·T *current; + NS·T *current; - while( (current = va_arg(args ,{NS}·T *)) ){{ + while( (current = va_arg(args ,NS·T *)) ){ sum += current->d0; - if(sum < current->d0){{ // Accumulator1 into carry + if(sum < current->d0){ // Accumulator1 into carry (carry)++; - if(carry == 0){{ + if(carry == 0){ va_end(args); - return {NS}·Status·accumulator1_overflow; - }} - }} - }} + return NS·Status·accumulator1_overflow; + } + } + } va_end(args); // wipes out prior value of accumulator1 accumulator1->d0 = carry; - return {NS}·Status·ok; - }} + return NS·Status·ok; + } - Local {NS}·Status {NS}·add({NS}·T *sum ,{NS}·T *a ,{NS}·T *b){{ + Local NS·Status NS·add(NS·T *sum ,NS·T *a ,NS·T *b){ uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; sum->d0 = (uint32_t)result; - return (result >> 32) ? {NS}·Status·carry : {NS}·Status·ok; - }} + return (result >> 32) ? NS·Status·carry : NS·Status·ok; + } - Local bool {NS}·increment({NS}·T *a){{ + Local bool NS·increment(NS·T *a){ a->d0++; return a->d0 == 0; - }} + } - Local {NS}·Status {NS}·subtract({NS}·T *difference ,{NS}·T *a ,{NS}·T *b){{ + Local NS·Status NS·subtract(NS·T *difference ,NS·T *a ,NS·T *b){ uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; difference->d0 = (uint32_t)diff; - return (diff > a->d0) ? {NS}·Status·borrow : {NS}·Status·ok; - }} + return (diff > a->d0) ? NS·Status·borrow : NS·Status·ok; + } - Local {NS}·Status {NS}·multiply({NS}·T *product1 ,{NS}·T *product0 ,{NS}·T *a ,{NS}·T *b){{ + Local NS·Status NS·multiply(NS·T *product1 ,NS·T *product0 ,NS·T *a ,NS·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 {NS}·Status·one_word_product; - return {NS}·Status·two_word_product; - }} + if(product1->d0 == 0) return NS·Status·one_word_product; + return NS·Status·two_word_product; + } - Local {NS}·Status {NS}·divide({NS}·T *remainder ,{NS}·T *quotient ,{NS}·T *a ,{NS}·T *b){{ - if(b->d0 == 0) return {NS}·Status·undefined_divide_by_zero; + Local NS·Status NS·divide(NS·T *remainder ,NS·T *quotient ,NS·T *a ,NS·T *b){ + if(b->d0 == 0) return NS·Status·undefined_divide_by_zero; quotient->d0 = a->d0 / b->d0; remainder->d0 = a->d0 - (quotient->d0 * b->d0); - return {NS}·Status·ok; - }} + return NS·Status·ok; + } - Local {NS}·Status {NS}·modulus({NS}·T *remainder ,{NS}·T *a ,{NS}·T *b){{ - if(b->d0 == 0) return {NS}·Status·undefined_modulus_zero; + Local NS·Status NS·modulus(NS·T *remainder ,NS·T *a ,NS·T *b){ + if(b->d0 == 0) return NS·Status·undefined_modulus_zero; uint32_t quotient = a->d0 / b->d0; remainder->d0 = a->d0 - (quotient * b->d0); - return {NS}·Status·ok; - }} + return NS·Status·ok; + } // bit motion typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); - Local uint32_t shift_left_op(uint32_t value, uint32_t amount){{ + 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){{ + 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 {NS}·Status {NS}·shift + Local NS·Status NS·shift ( uint32_t shift_count - ,{NS}·T *spill - ,{NS}·T *operand - ,{NS}·T *fill + ,NS·T *spill + ,NS·T *operand + ,NS·T *fill ,ShiftOp shift_op ,ShiftOp complement_shift_op - ){{ + ){ // If no result is needed, return immediately. - if(operand == NULL && spill == NULL) return {NS}·Status·ok; + if(operand == NULL && spill == NULL) return NS·Status·ok; // Treat NULL operand as zero. - if(operand == NULL){{ - operand = &{NS}·t[0]; - {NS}·copy(operand, {NS}·zero); - }} + if(operand == NULL){ + operand = &NS·t[0]; + NS·copy(operand, NS·zero); + } // Shifting more than one word breaks our fill/spill model. - if(shift_count > 31) return {NS}·Status·gt_max_shift_count; + if(shift_count > 31) return NS·Status·gt_max_shift_count; // The given operand is still required after it is modified, so we copy it. - {NS}·T *given_operand = &{NS}·t[1]; - {NS}·copy(given_operand, operand); + NS·T *given_operand = &NS·t[1]; + NS·copy(given_operand, operand); // Perform the shift operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){{ + if(fill != NULL){ fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); - {NS}·bit_or(operand, operand, fill); - }} - if(spill != NULL){{ + NS·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 {NS}·Status·ok; - }} + return NS·Status·ok; + } // Define concrete shift functions using valid C function pointers - Local {NS}·Status - {NS}·shift_left(uint32_t shift_count, {NS}·T *spill, {NS}·T *operand, {NS}·T *fill){{ - return {NS}·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - }} + Local NS·Status + NS·shift_left(uint32_t shift_count, NS·T *spill, NS·T *operand, NS·T *fill){ + return NS·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } - Local {NS}·Status - {NS}·shift_right(uint32_t shift_count, {NS}·T *spill, {NS}·T *operand, {NS}·T *fill){{ - return {NS}·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - }} + Local NS·Status + NS·shift_right(uint32_t shift_count, NS·T *spill, NS·T *operand, NS·T *fill){ + return NS·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } - Local {NS}·Status - {NS}·arithmetic_shift_right(uint32_t shift_count, {NS}·T *operand, {NS}·T *spill){{ + Local NS·Status + NS·arithmetic_shift_right(uint32_t shift_count, NS·T *operand, NS·T *spill){ // Guard against excessive shift counts - if(shift_count > 31) return {NS}·Status·gt_max_shift_count; + if(shift_count > 31) return NS·Status·gt_max_shift_count; // A NULL operand is treated as zero - if(operand == NULL){{ - operand = &{NS}·t[0]; - {NS}·copy(operand, {NS}·zero); - }} + if(operand == NULL){ + operand = &NS·t[0]; + NS·copy(operand, NS·zero); + } // Pick the fill value based on the sign bit - {NS}·T *fill = (operand->d0 & 0x80000000) ? {NS}·all_one_bit : {NS}·zero; + NS·T *fill = (operand->d0 & 0x80000000) ? NS·all_one_bit : NS·zero; // Call shift_right with the appropriate fill - return {NS}·shift_right(shift_count, spill, operand, fill); - }} - - Local const {NS}·M {NS}·m = {{ - - .allocate_array = {NS}·allocate_array - ,.allocate_array_zero = {NS}·allocate_array_zero - ,.deallocate = {NS}·deallocate - - ,.copy = {NS}·copy - ,.bit_and = {NS}·bit_and - ,.bit_or = {NS}·bit_or - ,.bit_complement = {NS}·bit_complement - ,.bit_twos_complement = {NS}·bit_twos_complement - ,.compare = {NS}·compare - ,.lt = {NS}·lt - ,.gt = {NS}·gt - ,.eq = {NS}·eq - ,.eq_zero = {NS}·eq_zero - ,.accumulate = {NS}·accumulate - ,.add = {NS}·add - ,.increment = {NS}·increment - ,.subtract = {NS}·subtract - ,.multiply = {NS}·multiply - ,.divide = {NS}·divide - ,.modulus = {NS}·modulus - ,.shift_left = {NS}·shift_left - ,.shift_right = {NS}·shift_right - ,.arithmetic_shift_right = {NS}·arithmetic_shift_right - - ,.access = {NS}·access - ,.from_uint32 = {NS}·from_uint32 - }}; + return NS·shift_right(shift_count, spill, operand, fill); + } + + #ifdef UINT8_MAX + CONV_8 + #endif + #ifdef UINT16_MAX + CONV_16 + #endif + #ifdef UINT32_MAX + CONV_32 + #endif + #ifdef UINT64_MAX + CONV_64 + #endif + #ifdef __UINT128_MAX + CONV_128 + #endif + + Local const NS·M NS·m = { + + .allocate_array = NS·allocate_array + ,.allocate_array_zero = NS·allocate_array_zero + ,.deallocate = NS·deallocate + + ,.copy = NS·copy + ,.bit_and = NS·bit_and + ,.bit_or = NS·bit_or + ,.bit_complement = NS·bit_complement + ,.bit_twos_complement = NS·bit_twos_complement + ,.compare = NS·compare + ,.lt = NS·lt + ,.gt = NS·gt + ,.eq = NS·eq + ,.eq_zero = NS·eq_zero + ,.accumulate = NS·accumulate + ,.add = NS·add + ,.increment = NS·increment + ,.subtract = NS·subtract + ,.multiply = NS·multiply + ,.divide = NS·divide + ,.modulus = NS·modulus + ,.shift_left = NS·shift_left + ,.shift_right = NS·shift_right + ,.arithmetic_shift_right = NS·arithmetic_shift_right + + ,.access = NS·access + ,.from_uint32 = NS·from_uint32 + + #ifdef UINT8_MAX + ,.to_uint8_t = NS·to_uint8_t + ,.from_uint8_t = NS·from_uint8_t + #endif + #ifdef UINT16_MAX + ,.to_uint16_t = NS·to_uint16_t + ,.from_uint16_t = NS·from_uint16_t + #endif + #ifdef UINT32_MAX + ,.to_uint32_t = NS·to_uint32_t + ,.from_uint32_t = NS·from_uint32_t + #endif + #ifdef UINT64_MAX + ,.to_uint64_t = NS·to_uint64_t + ,.from_uint64_t = NS·from_uint64_t + #endif + #ifdef __UINT128_MAX + ,.to___uint128_t = NS·to___uint128_t + ,.from___uint128_t = NS·from___uint128_t + #endif + + }; #endif #endif ''' + + + + diff --git "a/developer/Python\360\237\226\211/template_conversion.py" "b/developer/Python\360\237\226\211/template_conversion.py" new file mode 100644 index 0000000..d751cdd --- /dev/null +++ "b/developer/Python\360\237\226\211/template_conversion.py" @@ -0,0 +1,94 @@ + +# gt_extent_type is large enough to hold a sizeof(NS·T)-1 or sizeof(TYPE)-1 +def conversion(type: str): + """ + Returns a source code file for cc to munch on + """ + template = template_conversion() + code = template.replace("TYPE", type) + return code + +# The Digit array is always least significant digit at d[0] +def template_conversion(): + return r''' + +// NS·T -> PNT, possible NS·T leftovers +NS·Status NS·to_TYPE + ( + const NS·T *source + ,TYPE *destination + ,NS·Leftover_N *leftover + ){ + + uint8_t *s = (uint8_t *)source; + uint8_t *d = (uint8_t *)destination; + + if( sizeof(NS·T) <= sizeof(TYPE) ){ + *destination = 0; + memcpy( d, s, sizeof(NS·T) ); + return NS·Status·ok; + } + + memcpy( destination ,s ,sizeof(TYPE) ); + s += sizeof(TYPE); + const size_t δ = sizeof(NS·T) - sizeof(TYPE); + + if( memcmp(NS·constant + 0 ,s ,δ) == 0 ){ + return NS·Status·ok; + } + // else there are leftovers + + if( leftover == NULL || leftover->d == NULL){ // then nowhere to put the leftovers + return NS·Status·ConversionOverflow; + } + + // copy the part leftover into the leftover struct + leftover->scale = sizeof(TYPE); + uint8_t *lod = (uint8_t *)(leftover->d); + memcpy(lod ,s ,δ); + + // zero out the upper bytes of the leftover struct + lod += δ; + memset(lod, 0, sizeof(NS·T) - δ); // Zero remaining bytes safely + + return NS·Status·ConversionOverflow; +} + +// PNT -> NS·T, possible PNT leftovers +NS·Status NS·from_TYPE + ( + const TYPE *s // source + ,NS·T *destination + ,NS·Leftover_PNT *leftover + ){ + + uint8_t *d = (uint8_t *)destination; // NS·T + + // source allocation smaller: copy then zero out the top of destination + if( sizeof(TYPE) <= sizeof(NS·T) ){ + memcpy( d, s, sizeof(TYPE) ); + d += sizeof(TYPE); + memset( d, 0, sizeof(NS·T) - sizeof(TYPE) ); // Zero out remaining bytes + return NS·Status·ok; + } + + // The source allocation is larger: copy then potentially spill to leftovers + + memcpy( d, s, sizeof(NS·T) ); + + TYPE mask = ~(TYPE)0 << (sizeof(NS·T) << 3); + TYPE unscaled_leftover = *source & mask; + + if(unscaled_leftover == 0) return NS·Status·ok; + + if(leftover == NULL){ // then nowhere to put the leftovers + return NS·Status·ConversionOverflow; + } + + leftover->scale = sizeof(NS·T); + leftover->leftover = unscaled_leftover >> (sizeof(NS·T) << 3); + + return NS·Status·ConversionOverflow; + +} +''' diff --git a/developer/experiment/try_letters_2.c b/developer/experiment/try_letters_2.c new file mode 100644 index 0000000..234e578 --- /dev/null +++ b/developer/experiment/try_letters_2.c @@ -0,0 +1,33 @@ +#include + +// Define interface and instance types +typedef struct { + void (*print_value)(int); +} N32·M; // 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·M N32·m = { + .print_value = print_value_function +}; + +int main() { + // Create an instance + N32·δ instance = { 99 }; + int Δ = 5; + + // Call function via interface + printf("Calling via interface: "); + N32·m.print_value(instance.value); + N32·m.print_value(Δ); + + return 0; +}