From: Thomas Walker Lynch Date: Wed, 19 Feb 2025 03:36:04 +0000 (+0000) Subject: checkpoint before changing to Manifold notation X-Git-Url: https://git.reasoningtechnology.com/style/rt_dark_doc.css?a=commitdiff_plain;h=99a2c8ae685c657338f8494a4de14e1c9f243766;p=N checkpoint before changing to Manifold notation --- diff --git "a/developer/Python\360\237\226\211/fill_template" "b/developer/Python\360\237\226\211/fill_template" new file mode 100755 index 0000000..4569e33 --- /dev/null +++ "b/developer/Python\360\237\226\211/fill_template" @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +import sys +from template_N import N +from make_constants import make_constants_block + +def write(code ,basename): + filepath = "../cc/" + basename + ".lib.c" + with open(filepath, "w") as f: + f.write(code) + print("Generated " + filepath) + + +def main(): + """ + generates `.c` source code from templates + """ + + #---------------------------------------- + # N32 made from 1 digit, of 32 bits. + + 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) + 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) + write(code ,type_name); + +if __name__ == "__main__": + main() + diff --git "a/developer/Python\360\237\226\211/make_constants.py" "b/developer/Python\360\237\226\211/make_constants.py" new file mode 100755 index 0000000..a177fde --- /dev/null +++ "b/developer/Python\360\237\226\211/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/Python\360\237\226\211/template_N.py" "b/developer/Python\360\237\226\211/template_N.py" new file mode 100644 index 0000000..2ce8770 --- /dev/null +++ "b/developer/Python\360\237\226\211/template_N.py" @@ -0,0 +1,455 @@ +def N(namespace: str ,digit_type: str ,digit_extent: int ,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_EXTENT = digit_extent + ,CONSTANTS_BLOCK = constants_block + ) + return code + +def template_N(): + return r''' +/* + M - The type for the function dictionary. + m - A function dictionary. + T - Is the type for the tableau. The tableau is a memory shared among the functions + In the function dictionary. + +*/ +#define {NS}·DEBUG + +#ifndef FACE +#define {NS}·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef {NS}·FACE +#define {NS}·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint32_t Extent; + typedef uint32_t Digit; + + 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; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{{ + {NS}·Status·ok = 0 + ,{NS}·Status·overflow = 1 + ,{NS}·Status·accumulator1_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 {NS}·T *( *{NS}·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{{ + + {NS}·T *(*allocate_array_zero)(Extent, {NS}·Allocate_MemoryFault); + {NS}·T *(*allocate_array)(Extent, {NS}·Allocate_MemoryFault); + void (*deallocate)({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*); + {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}·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 (*shift_left)(Extent, {NS}·T*, {NS}·T*, {NS}·T*); + {NS}·Status (*shift_right)(Extent, {NS}·T*, {NS}·T*, {NS}·T*); + {NS}·Status (*arithmetic_shift_right)(Extent, {NS}·T*, {NS}·T*); + + {NS}·T* (*access)({NS}·T*, Extent); + void (*from_uint32)({NS}·T *destination ,uint32_t value); + }} {NS}·Λ; + + Local const {NS}·Λ {NS}·λ; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef {NS}·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct {NS}·T{{ + Digit d0; + }}; + + {NS}·T {NS}·constant[4] = {{ + {{.d0 = 0}}, + {{.d0 = 1}}, + {{.d0 = ~(uint32_t)0}}, + {{.d0 = 1 << 31}} + }}; + + {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]; + + // the allocate an array of N32 + {NS}·T *{NS}·allocate_array(Extent 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(Extent 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){{ + free(unencumbered); + }} + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct {NS}·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 {NS}·T {NS}·t[4]; + + + // allocation + + extern {NS}·T *{NS}·allocate_array(Extent, {NS}·Allocate_MemoryFault); + extern {NS}·T *{NS}·allocate_array_zero(Extent, {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 ,Extent index){{ + return &array[index]; + }} + + Local void {NS}·from_uint32({NS}·T *destination ,uint32_t value){{ + if(destination == NULL) return; + destination->d0 = value; + }} + + // copy, convenience copy + + 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){{ + instance->d0 = 0; + }} + + 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){{ + 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){{ + result->d0 = a->d0 | b->d0; + }} + + // result can the same as the operand + 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){{ + 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 bool {NS}·lt({NS}·T *a ,{NS}·T *b){{ + return a->d0 < b->d0; + }} + + 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){{ + return a->d0 == b->d0; + }} + + 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 + // + // 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 ,...){{ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + {NS}·T *current; + + while( (current = va_arg(args ,{NS}·T *)) ){{ + sum += current->d0; + if(sum < current->d0){{ // Accumulator1 into carry + (carry)++; + if(carry == 0){{ + va_end(args); + return {NS}·Status·accumulator1_overflow; + }} + }} + }} + va_end(args); + + // wipes out prior value of accumulator1 + accumulator1->d0 = carry; + + return {NS}·Status·ok; + }} + + 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; + }} + + 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){{ + 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; + }} + + + 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; + }} + + 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; + }} + + 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; + }} + + // 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 {NS}·Status {NS}·shift + ( + uint32_t shift_count + ,{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; + + // Treat NULL operand as 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; + + // 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); + + // 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)); + {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; + }} + + // 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_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){{ + + // Guard against excessive shift counts + 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); + }} + + // Pick the fill value based on the sign bit + {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}·Λ {NS}·λ = {{ + + .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 + }}; + + #endif + +#endif +''' diff --git "a/developer/document\360\237\226\211/About_Python_templates.org" "b/developer/document\360\237\226\211/About_Python_templates.org" new file mode 100644 index 0000000..414366f --- /dev/null +++ "b/developer/document\360\237\226\211/About_Python_templates.org" @@ -0,0 +1,232 @@ +#+TITLE: Python-Based Template Generation (Multi-Module Approach) +#+AUTHOR: Chat GPT + +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/document\360\237\226\211/adding_new_N_types.org" "b/developer/document\360\237\226\211/adding_new_N_types.org" new file mode 100644 index 0000000..efb018b --- /dev/null +++ "b/developer/document\360\237\226\211/adding_new_N_types.org" @@ -0,0 +1,23 @@ +#+TITLE: Adding new N types +#+AUTHOR: Thomas + +* Project Name + +N == Natural Number, aka 'unsigned int'. + +* Pencil directories / pencil suffix. + +The files in the pencil directory, e.g. cc🖉, are 'authored files'. The program 'rm_na' will not delete them. Use 'rm_na" in scripts. + +* Parameterized types + +The templated N type allows a user to specify a digit type, and number of digits. To generate a new multiple digit type, go into the `Python🖉/` directory, add a new write section to the `fill_template` file, and fill in the digit type and number of digits the new type will have. Run `fill_template` and the synthesized file will be written to the `cc/` directory. + + +* Custom types + +Some processors will have processor native types that the templating scheme does not take advantage of. + +Put custom `N_.lib.cc` files in the `cc🖉/` directory. Or new templates in the `Python🖉` directory. Be sure the file name is distinct from existing types, because the testing setup installs all the files. + + diff --git "a/developer/document\360\237\226\211/files.org" "b/developer/document\360\237\226\211/files.org" deleted file mode 100644 index 101b8e5..0000000 --- "a/developer/document\360\237\226\211/files.org" +++ /dev/null @@ -1,4 +0,0 @@ - -The currently the N{64,32,16,8} files make use of native types for 2x width accumulators. - -The generic multi-precision types with 0 digit array extent, will not have native types at 2x size but instead will use two digits. diff --git "a/developer/document\360\237\226\211/front_end.org" "b/developer/document\360\237\226\211/front_end.org" deleted file mode 100644 index b5ad881..0000000 --- "a/developer/document\360\237\226\211/front_end.org" +++ /dev/null @@ -1,232 +0,0 @@ -#+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/document\360\237\226\211/general_notes.org" "b/developer/document\360\237\226\211/general_notes.org" new file mode 100644 index 0000000..9090e71 --- /dev/null +++ "b/developer/document\360\237\226\211/general_notes.org" @@ -0,0 +1,10 @@ +#+TITLE: General notes +#+AUTHOR: Thomas + +* Files in the `cc/` directory are .gitignore and can be deleted by clean scripts. This directory is for the output of template generation. + +* There is a stylistic form for using these files. The `FACE` section include goes at the top and the `LOCAL` include at the bottom of the user's source files. Then link with `N.lib.a`. + +* Most of the work is done in the `LOCAL` section. + +* Compile with optimization to make the calls to the `LOCAL` functions compile out, leaving clean inline code. (That is the intention anyway, as of this writing development is still ongoing.) diff --git a/developer/python/fill_template b/developer/python/fill_template deleted file mode 100755 index 4569e33..0000000 --- a/developer/python/fill_template +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 - -import sys -from template_N import N -from make_constants import make_constants_block - -def write(code ,basename): - filepath = "../cc/" + basename + ".lib.c" - with open(filepath, "w") as f: - f.write(code) - print("Generated " + filepath) - - -def main(): - """ - generates `.c` source code from templates - """ - - #---------------------------------------- - # N32 made from 1 digit, of 32 bits. - - 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) - 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) - write(code ,type_name); - -if __name__ == "__main__": - main() - diff --git a/developer/python/make_constants.py b/developer/python/make_constants.py deleted file mode 100755 index a177fde..0000000 --- a/developer/python/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/template_N.py b/developer/python/template_N.py deleted file mode 100644 index dc90aaa..0000000 --- a/developer/python/template_N.py +++ /dev/null @@ -1,472 +0,0 @@ -def N(namespace: str ,digit_type: str ,digit_extent: int ,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_EXTENT = digit_extent - ,CONSTANTS_BLOCK = constants_block - ) - return code - -def template_N(): - return r'''/* - 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 {NS}·DEBUG - -#ifndef FACE -#define {NS}·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef {NS}·FACE -#define {NS}·FACE - - #include - #include - #include - #include - - //---------------------------------------- - // Instance Data (Declaration Only) - - typedef uint32_t Extent; - typedef uint32_t Digit; - - 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; - - //---------------------------------------- - // Return/Error Status and handlers - - typedef enum{{ - {NS}·Status·ok = 0 - ,{NS}·Status·overflow = 1 - ,{NS}·Status·accumulator1_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 {NS}·T *( *{NS}·Allocate_MemoryFault )(Extent); - - //---------------------------------------- - // Interface - - typedef struct{{ - - {NS}·T *(*allocate_array_zero)(Extent, {NS}·Allocate_MemoryFault); - {NS}·T *(*allocate_array)(Extent, {NS}·Allocate_MemoryFault); - void (*deallocate)({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*); - {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}·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 (*shift_left)(Extent, {NS}·T*, {NS}·T*, {NS}·T*); - {NS}·Status (*shift_right)(Extent, {NS}·T*, {NS}·T*, {NS}·T*); - {NS}·Status (*arithmetic_shift_right)(Extent, {NS}·T*, {NS}·T*); - - {NS}·T* (*access)({NS}·T*, Extent); - void (*from_uint32)({NS}·T *destination ,uint32_t value); - }} {NS}·Λ; - - Local const {NS}·Λ {NS}·λ; // initialized in the LOCAL section - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef {NS}·IMPLEMENTATION - - // this part goes into the library - #ifndef LOCAL - - #include - #include - - struct {NS}·T{{ - Digit d0; - }}; - - {NS}·T {NS}·constant[4] = {{ - {{.d0 = 0}}, - {{.d0 = 1}}, - {{.d0 = ~(uint32_t)0}}, - {{.d0 = 1 << 31}} - }}; - - {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]; - - // the allocate an array of N32 - {NS}·T *{NS}·allocate_array(Extent 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(Extent 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){{ - free(unencumbered); - }} - - #endif - - // This part is included after the library user's code - #ifdef LOCAL - - // instance - - struct {NS}·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 {NS}·T {NS}·t[4]; - - - // allocation - - extern {NS}·T *{NS}·allocate_array(Extent, {NS}·Allocate_MemoryFault); - extern {NS}·T *{NS}·allocate_array_zero(Extent, {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 ,Extent index){{ - return &array[index]; - }} - - Local void {NS}·from_uint32({NS}·T *destination ,uint32_t value){{ - if(destination == NULL) return; - destination->d0 = value; - }} - - // copy, convenience copy - - 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){{ - instance->d0 = 0; - }} - - 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){{ - 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){{ - result->d0 = a->d0 | b->d0; - }} - - // result can the same as the operand - 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){{ - 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 bool {NS}·lt({NS}·T *a ,{NS}·T *b){{ - return a->d0 < b->d0; - }} - - 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){{ - return a->d0 == b->d0; - }} - - 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 - // - // 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 ,...){{ - - va_list args; - va_start(args ,accumulator0); - uint32_t sum = accumulator0->d0; - uint32_t carry = 0; - {NS}·T *current; - - while( (current = va_arg(args ,{NS}·T *)) ){{ - sum += current->d0; - if(sum < current->d0){{ // Accumulator1 into carry - (carry)++; - if(carry == 0){{ - va_end(args); - return {NS}·Status·accumulator1_overflow; - }} - }} - }} - va_end(args); - - // wipes out prior value of accumulator1 - accumulator1->d0 = carry; - - return {NS}·Status·ok; - }} - - 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; - }} - - 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){{ - 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; - }} - - - 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; - }} - - 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; - }} - - 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; - }} - - // 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 {NS}·Status {NS}·shift - ( - uint32_t shift_count - ,{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; - - // Treat NULL operand as 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; - - // 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); - - // 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)); - {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; - }} - - // 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_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){{ - - // Guard against excessive shift counts - 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); - }} - - // Pick the fill value based on the sign bit - {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}·Λ {NS}·λ = {{ - - .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 - }}; - - #endif - -#endif -''' diff --git "a/developer/tool\360\237\226\211/release_ls" "b/developer/tool\360\237\226\211/release_ls" deleted file mode 100755 index 52550b6..0000000 --- "a/developer/tool\360\237\226\211/release_ls" +++ /dev/null @@ -1,23 +0,0 @@ -#!/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 - - release_dir=$(release_dir) - - if [ ! -d ${release_dir} ]; then - echo "$(script_fp):: no release directory: " ${release_dir} - exit 1 - fi - - ls $@ ${release_dir} - - diff --git "a/document\360\237\226\211/Manifold_analogy.org" "b/document\360\237\226\211/Manifold_analogy.org" new file mode 100644 index 0000000..e9e82e2 --- /dev/null +++ "b/document\360\237\226\211/Manifold_analogy.org" @@ -0,0 +1,177 @@ +#+TITLE: RT Tableau Method +#+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. + +* Working with `.lib.c` Files in RT C + +In the RT C design, each module’s interface **and** implementation are contained in +a single file named `something.lib.c`. Traditional `.h` headers are replaced by +preprocessor-guarded interface sections, while the main implementation and any +“local” (private) code appear in separate blocks. If you want to learn more about +this format, there is a dedicated document explaining how `.lib.c` files are structured, +along with how and why they’re compiled. + +Briefly: + +- **Interface Section** + Declares the memory format (`struct N32·T`, for instance) and the function dictionary + type (`N32·Λ`), along with any prototypes that external code needs. + +- **Implementation Section** + Provides the actual definitions of the functions from the interface, compiled into + an object file (e.g., `N32.lib.o`) that goes into a library (`.a` or `.so`). + +- **Local Section** + (Guarded by `#ifdef LOCAL`) Contains private utility functions or test helpers. + Only included when a `.cli.c` test or other special code explicitly requests it. + +This structure keeps all relevant code (interface, implementation, internal helpers) +in a single `.lib.c` file, yet still enforces encapsulation via preprocessor macros. +It aligns well with the *tableau* and *function dictionary* concepts described here: +the memory format and method table are declared in the interface section, their +implementations go in the implementation section, and if you need advanced debugging +routines or private details, you can optionally include the local section. + + +* More about Tableau (Taishou) + +Below is a minimal example that shows how an instance of a memory format (`N32·T`) can be exclusively manipulated by a *function dictionary* (`N32·Λ`). This concrete “tableau” (taishou) usage illustrates how the memory is bound to specific operations—no external code should modify the memory except through the provided dictionary functions. + +#+BEGIN_SRC c +#include +#include + +// 1. Define the memory format (tableau) +typedef struct { + uint32_t value; +} N32·T; // This struct is our 'tableau'. + +// 2. Provide some functions that operate on N32·T +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); +} + +// 3. Declare a function dictionary (method table) +typedef struct { + void (*copy)(N32·T*, const N32·T*); + void (*increment)(N32·T*); + void (*print)(const N32·T*); +} N32·Λ; + +// 4. Provide a concrete instance of the dictionary +const N32·Λ N32·λ = { + .copy = N32·copy, + .increment = N32·increment, + .print = N32·print +}; + +// 5. Demonstrate usage in a main function +int main(void) { + // Create an instance of N32·T (our tableau) + N32·T my_number = { .value = 10 }; + + // Manipulate it exclusively through the function dictionary + N32·λ.increment(&my_number); // Increment by 1 + N32·λ.print(&my_number); // Output should show "Value: 11" + + // Create another instance and copy its contents + N32·T another_number = { .value = 42 }; + N32·λ.copy(&my_number, &another_number); + N32·λ.print(&my_number); // Output should show "Value: 42" + + return 0; +} +#+END_SRC + +When compiled and run (e.g., `gcc example.c -o example && ./example`), the program +prints: + +#+BEGIN_EXAMPLE +Value: 11 +Value: 42 +#+END_EXAMPLE + +In this way, `my_number` is a tableau. All modifications happen via a *closed set of +functions*—here, the operations are defined in the function dictionary `N32·λ`. No +external code is allowed to poke into `my_number.value` directly (beyond this demonstration), +upholding the idea that a “tableau” is memory dedicated to a specific “function dictionary.” + + +* 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. diff --git "a/document\360\237\226\211/Manifold_interpretation.org" "b/document\360\237\226\211/Manifold_interpretation.org" new file mode 100644 index 0000000..e01e6af --- /dev/null +++ "b/document\360\237\226\211/Manifold_interpretation.org" @@ -0,0 +1,83 @@ +#+TITLE: Manifold Interpretation +#+AUTHOR: Thomas + + +* Space and Hyperreal Local Space + +Space is defined from the variables on the tableau taken as natural numbers. There are as many dimensions as variables on the tableau. + +A vector-valued function is defined with components being the values of all the functions in the dictionary. + +Hyperreal local space is then defined as this vector. Incremental changes in the function parameters determine the distance between points in the local space. It follows that local space is only Euclidean when the functions are arithmetic. + +* Reasoned Explanation + +** Proposed Setup + +*** Tableau Variables as Coordinates + +You have a tableau \( t \) whose variables are all natural-number-valued (in standard or nonstandard sense). The dimension of the "space" is the number of these variables. Each point in that space, therefore, is a tuple \( (t_0, t_1, ..., t_{n-1}) \) of naturals (or hypernaturals). + +*** Dictionary of Functions + +Suppose you have a "function dictionary" \( m \) with some finite number of function pointers \( \{ f_0, f_1, ..., f_{k-1} \} \). If you collect these into a vector-valued function, then for each point \( t \) (your tableau), you get: +\[ +F(t) = ( f_0(t), f_1(t), ..., f_{k-1}(t) ) +\] + +*** Hyperreal Local Space + +Locally, if you allow infinitesimal changes \( \Delta t_i \) to the tableau's coordinates, you look at how \( F(t) \) changes to \( F(t + \Delta t) \) with \( \Delta t \) in the (hyper)natural domain. The difference \( F(t + \Delta t) - F(t) \) is, from an external perspective, a vector of infinitesimal increments—provided each \( f_i \) is sufficiently "nice" (like a function admitting a finite-difference or nonstandard derivative). + +*** When is Local Space Euclidean? + +You say: "Local space is only Euclidean when the functions are arithmetic." Indeed: +- If each \( f_i \) is a linear or affine function of the tableau variables, then small increments in \( \Delta t \) produce changes in \( F(t) \) that mimic linear transformations in \( \mathbb{R}^n \). +- If the functions are more general (e.g., polynomial or nonlinear), then locally the geometry might not be "flat Euclidean," but you can still define a tangent space or local linear approximations (in the sense of finite differences or a "nonstandard derivative"). + +** Observations & Comments + +*** Discrete vs. Continuous + +- If all tableau variables are standard natural numbers (with no nonstandard extension), you get a purely discrete grid. Usually, that grid won’t be “locally Euclidean” in the classical sense—each point is isolated. +- If you incorporate nonstandard analysis with hypernatural indices, you can have infinitesimal increments \( \Delta t \). Externally, it “looks continuous,” internally it’s still a large discrete set. +- Hence, you can get a scenario that feels like \( \mathbb{R}^n \) locally, if your increments are infinitesimals. + +*** Manifold vs. Arithmetic + +- In classical manifold theory, local charts map open sets of your manifold to open sets of \( \mathbb{R}^n \). That can hold even if the manifold is nonlinear (like a sphere, which is “locally Euclidean” but globally curved). +- Being “arithmetic” or “linear” is not required for local Euclideanness in the manifold sense; you only need the ability to map small neighborhoods to an open set in \( \mathbb{R}^n \). Nonlinear functions can still do so, provided you track a smooth structure. +- You might need a “smoothness” assumption in your difference approach so that \( F \) locally has something akin to a Jacobian, letting you define a tangent space. + +*** When is it Exactly Euclidean? + +- If the manifold is globally flat (like \( \mathbb{R}^n \) itself), then yes, the structure is Euclidean. +- In your approach: if the dictionary of functions is linear in the tableau coordinates, you get a global linear map. That indeed yields a globally Euclidean geometry (assuming you define distance in a certain consistent way). +- If the dictionary is more complicated, you might only get local linear approximations—like expansions used in nonstandard or standard differential geometry. + +*** Distance Metric + +You mention “incremental changes in the function parameters determine the distance between points in local space.” This suggests you define a metric like: +\[ +d(t, t + \Delta t) = \| F(t + \Delta t) - F(t) \| +\] +or something analogous. +- If each \( f_i \) is linear, that metric can reduce to something Euclidean. +- If the \( f_i \) are nonlinear, you get a more complicated geometry (like a Riemannian structure if you handle second-order expansions). + +** Conclusion from o1: + +- Yes, with a hyperreal or hypernatural approach, you can treat a discrete set of tableau variables as “infinitesimally spaced.” +- Yes, you can define a vector of function outputs as your local coordinate system. +- Yes, if the dictionary’s functions are purely arithmetic/linear, you get a globally Euclidean structure in that local space. +- If the functions are more general, you can still have a “manifold” in the sense of local Euclideanness (via expansions or finite-difference approximations), but it may not be globally Euclidean. + +Your statement *“Space is only Euclidean if the functions are arithmetic”* can be rephrased: + +- *Globally Euclidean* if your function dictionary is linear or affine. +- *Locally you might still approximate Euclideanness* if you assume finite differences behave like differentials. + +Ultimately, you’re using nonstandard analysis to unify discrete and continuous perspectives on the tableau. This is a well-known strategy in internal hyperreal approaches to “smooth” or “manifold-like” structures. + + + diff --git "a/document\360\237\226\211/RT_C_namespace.org" "b/document\360\237\226\211/RT_C_namespace.org" index 87a637d..5c04139 100644 --- "a/document\360\237\226\211/RT_C_namespace.org" +++ "b/document\360\237\226\211/RT_C_namespace.org" @@ -1,5 +1,5 @@ #+TITLE: RT C Namespace Convention -#+AUTHOR: RT C Documentation +#+AUTHOR: Thomas * 1. Namespaces in RT C diff --git "a/document\360\237\226\211/RT_cli_c_file.org" "b/document\360\237\226\211/RT_cli_c_file.org" index 06889c5..07f3760 100644 --- "a/document\360\237\226\211/RT_cli_c_file.org" +++ "b/document\360\237\226\211/RT_cli_c_file.org" @@ -1,5 +1,5 @@ #+TITLE: Writing `.cli.c` Files in RT C -#+AUTHOR: RT C Documentation +#+AUTHOR: Thomas * Overview In RT C projects, a file with a “=.cli.c=” suffix typically implements a **command-line interface** i.e. a program that is run from a shell. Thus each `.cli.c` file produces an **executable** named . 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/User_manual.org" "b/document\360\237\226\211/User_manual.org" new file mode 100644 index 0000000..1b0a962 --- /dev/null +++ "b/document\360\237\226\211/User_manual.org" @@ -0,0 +1,32 @@ +#+TITLE: User manual +#+AUTHOR: Thomas + +* Sections + +* Compile + + +/* + 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.) + +*/ diff --git "a/document\360\237\226\211/unicode_character_use.org" "b/document\360\237\226\211/unicode_character_use.org" new file mode 100644 index 0000000..125e34b --- /dev/null +++ "b/document\360\237\226\211/unicode_character_use.org" @@ -0,0 +1,20 @@ +#+TITLE: Unicode Character Use +#+AUTHOR: RT C Documentation + +The following characters are used: + +🖉 - The pencil suffix is placed on the end of directory or file names. It indicates that + the contents of the directory contains authored files, or in the case of the suffix on the end of a file name, that the specific file is authored. + + Authored files should not be deleted by scripts. The command `rm_na` will not delete + authored files, and it is used in scripts. It can be found in the RT-project-share project. + +· - The center dot is a proposed namespace sepearator for C. Currently it is used ad + hoc as the prefix portion of identifiers. There is some support in Python scripts. + +Λ - This is used to name function dictionary type. Function dictionaries are struct types + full of functions, and act as interfaces. + +λ - A common name or prefix for an instance of a function dictionary type. This follows + the convention that type names are PascalCase, and instance names are snake_case. + diff --git a/tester/cc/test_N32_0.cli.c b/tester/cc/test_N32_0.cli.c new file mode 100644 index 0000000..5e2f792 --- /dev/null +++ b/tester/cc/test_N32_0.cli.c @@ -0,0 +1,364 @@ +#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(1 ,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(2 ,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; +} + +bool test_bitwise_operations(){ + // Allocate memory + N32·T *array = N32·λ.allocate_array(2, NULL); + if(!array) return false; + + N32·T *a = N32·λ.access(array, 0); + N32·T *b = N32·λ.access(array, 1); + N32·T *result = N32·λ.access(array, 2); + + // a = 0x0F0F0F0F, b = 0xF0F0F0F0 + N32·λ.from_uint32(a, 0x0F0F0F0F); + N32·λ.from_uint32(b, 0xF0F0F0F0); + + // bit_and => expect 0x00000000 + N32·λ.bit_and(result, a, b); + N32·λ.from_uint32(a, 0x00000000); + if(N32·λ.compare(result, a) != N32·Order_eq){ + N32·λ.deallocate(array); + return false; + } + + // Reset a to 0x0F0F0F0F for next tests + N32·λ.from_uint32(a, 0x0F0F0F0F); + + // bit_or => expect 0xFFFFFFFF + N32·λ.bit_or(result, a, b); + N32·λ.from_uint32(b, 0xFFFFFFFF); + if(N32·λ.compare(result, b) != N32·Order_eq){ + N32·λ.deallocate(array); + return false; + } + + // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0 + N32·λ.from_uint32(a, 0x0F0F0F0F); + N32·λ.bit_complement(result, a); + N32·λ.from_uint32(b, 0xF0F0F0F0); + if(N32·λ.compare(result, b) != N32·Order_eq){ + N32·λ.deallocate(array); + return false; + } + + // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1 + N32·λ.from_uint32(a, 0x0F0F0F0F); + N32·λ.bit_twos_complement(result, a); + N32·λ.from_uint32(b, 0xF0F0F0F1); + if(N32·λ.compare(result, b) != N32·Order_eq){ + N32·λ.deallocate(array); + return false; + } + + N32·λ.deallocate(array); + return true; +} + +bool test_comparisons(){ + // Allocate memory + N32·T *array = N32·λ.allocate_array(2, NULL); + if(!array) return false; + + N32·T *a = N32·λ.access(array, 0); + N32·T *b = N32·λ.access(array, 1); + N32·T *c = N32·λ.access(array, 2); + + // First set: a=0, b=42, c=42 + N32·λ.from_uint32(a, 0); + N32·λ.from_uint32(b, 42); + N32·λ.from_uint32(c, 42); + + // eq_zero(a) => true + if(!N32·λ.eq_zero(a)){ + N32·λ.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32·λ.eq_zero(b)){ + N32·λ.deallocate(array); + return false; + } + // eq(b, c) => true + if(!N32·λ.eq(b, c)){ + N32·λ.deallocate(array); + return false; + } + // eq(a, b) => false + if(N32·λ.eq(a, b)){ + N32·λ.deallocate(array); + return false; + } + // compare(a, b) => N32·Order_lt + if(N32·λ.compare(a, b) != N32·Order_lt){ + N32·λ.deallocate(array); + return false; + } + // compare(b, a) => N32·Order_gt + if(N32·λ.compare(b, a) != N32·Order_gt){ + N32·λ.deallocate(array); + return false; + } + // compare(b, c) => N32·Order_eq + if(N32·λ.compare(b, c) != N32·Order_eq){ + N32·λ.deallocate(array); + return false; + } + // lt(a, b) => true, gt(b, a) => true + if(!N32·λ.lt(a, b) || !N32·λ.gt(b, a)){ + N32·λ.deallocate(array); + return false; + } + + // Second set: a=100, b=50 + N32·λ.from_uint32(a, 100); + N32·λ.from_uint32(b, 50); + if(N32·λ.compare(a, b) != N32·Order_gt){ + N32·λ.deallocate(array); + return false; + } + // eq_zero(a) => false + if(N32·λ.eq_zero(a)){ + N32·λ.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32·λ.eq_zero(b)){ + N32·λ.deallocate(array); + return false; + } + + N32·λ.deallocate(array); + return true; +} + +bool test_shifts(){ + // Allocate memory for operand, fill, spill + N32·T *array = N32·λ.allocate_array(2, NULL); + if(!array) return false; + + N32·T *operand = N32·λ.access(array, 0); + N32·T *fill = N32·λ.access(array, 1); + N32·T *spill = N32·λ.access(array, 2); + + // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0 + N32·λ.from_uint32(operand, 1); + N32·λ.from_uint32(fill, 0); + N32·λ.from_uint32(spill, 0); + if(N32·λ.shift_left(4, spill, operand, fill) != N32·Status·ok){ + N32·λ.deallocate(array); + return false; + } + N32·T *temp = N32·λ.allocate_array(1, NULL); + if(!temp){ + N32·λ.deallocate(array); + return false; + } + N32·λ.from_uint32(temp, 16); + if(N32·λ.compare(operand, temp) != N32·Order_eq){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + if(N32·λ.compare(fill, N32·zero) != N32·Order_eq){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + if(N32·λ.compare(spill, N32·zero) != N32·Order_eq){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + + // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1 + N32·λ.from_uint32(operand, 0x80000000); + N32·λ.from_uint32(fill, 0); + N32·λ.from_uint32(spill, 0); + if(N32·λ.shift_left(1, spill, operand, fill) != N32·Status·ok){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + if(!N32·λ.eq_zero(operand)){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + N32·λ.from_uint32(temp, 1); + if(N32·λ.compare(spill, temp) != N32·Order_eq){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + + // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0 + N32·λ.from_uint32(operand, 0x80000000); + N32·λ.from_uint32(fill, 0); + N32·λ.from_uint32(spill, 0); + if(N32·λ.shift_right(1, spill, operand, fill) != N32·Status·ok){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + N32·λ.from_uint32(temp, 0x40000000); + if(N32·λ.compare(operand, temp) != N32·Order_eq){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + if(!N32·λ.eq_zero(spill)){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + + // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0 + N32·λ.from_uint32(operand, 0x80000000); + N32·λ.from_uint32(spill, 0); + if(N32·λ.arithmetic_shift_right(1, operand, spill) != N32·Status·ok){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + N32·λ.from_uint32(temp, 0xC0000000); + if(N32·λ.compare(operand, temp) != N32·Order_eq){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + if(!N32·λ.eq_zero(spill)){ + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return false; + } + + N32·λ.deallocate(temp); + N32·λ.deallocate(array); + return true; +} + + + +// Include the local section of N32.lib.c for testing +#define LOCAL +#include "N32.lib.c" +#undef LOCAL diff --git a/tester/cc/test_N32_1x32_0.cli.c b/tester/cc/test_N32_1x32_0.cli.c new file mode 100644 index 0000000..42cae99 --- /dev/null +++ b/tester/cc/test_N32_1x32_0.cli.c @@ -0,0 +1,364 @@ +#include +#include +#include +#include + +// Enable interface section +#define FACE +#include "N32_1x32.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_1x32·T *array = N32_1x32·λ.allocate_array(1 ,NULL); + if( !array ) return false; + + // Access elements via access function + N32_1x32·T *a = N32_1x32·λ.access(array ,0); + N32_1x32·T *b = N32_1x32·λ.access(array ,1); + + // Assign value and copy + N32_1x32·λ.from_uint32(a ,42); + N32_1x32·λ.copy(b ,a); + + bool success = ( N32_1x32·λ.compare(b ,a) == N32_1x32·Order_eq ); + N32_1x32·λ.deallocate(array); + return success; +} + +bool test_arithmetic(){ + // Allocate memory + N32_1x32·T *array = N32_1x32·λ.allocate_array(2 ,NULL); + if( !array ) return false; + + N32_1x32·T *a = N32_1x32·λ.access(array ,0); + N32_1x32·T *b = N32_1x32·λ.access(array ,1); + N32_1x32·T *result = N32_1x32·λ.access(array ,2); + + N32_1x32·λ.from_uint32(a ,20); + N32_1x32·λ.from_uint32(b ,22); + + if( N32_1x32·λ.add(result ,a ,b) != N32_1x32·Status·ok ) return false; + if( N32_1x32·λ.compare(result ,N32_1x32·λ.access(array ,0)) != N32_1x32·Order_gt ) return false; + + if( N32_1x32·λ.subtract(result ,b ,a) != N32_1x32·Status·ok ) return false; + if( N32_1x32·λ.compare(result ,N32_1x32·λ.access(array ,0)) != N32_1x32·Order_lt ) return false; + + N32_1x32·λ.deallocate(array); + return true; +} + +bool test_bitwise_operations(){ + // Allocate memory + N32_1x32·T *array = N32_1x32·λ.allocate_array(2, NULL); + if(!array) return false; + + N32_1x32·T *a = N32_1x32·λ.access(array, 0); + N32_1x32·T *b = N32_1x32·λ.access(array, 1); + N32_1x32·T *result = N32_1x32·λ.access(array, 2); + + // a = 0x0F0F0F0F, b = 0xF0F0F0F0 + N32_1x32·λ.from_uint32(a, 0x0F0F0F0F); + N32_1x32·λ.from_uint32(b, 0xF0F0F0F0); + + // bit_and => expect 0x00000000 + N32_1x32·λ.bit_and(result, a, b); + N32_1x32·λ.from_uint32(a, 0x00000000); + if(N32_1x32·λ.compare(result, a) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(array); + return false; + } + + // Reset a to 0x0F0F0F0F for next tests + N32_1x32·λ.from_uint32(a, 0x0F0F0F0F); + + // bit_or => expect 0xFFFFFFFF + N32_1x32·λ.bit_or(result, a, b); + N32_1x32·λ.from_uint32(b, 0xFFFFFFFF); + if(N32_1x32·λ.compare(result, b) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(array); + return false; + } + + // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0 + N32_1x32·λ.from_uint32(a, 0x0F0F0F0F); + N32_1x32·λ.bit_complement(result, a); + N32_1x32·λ.from_uint32(b, 0xF0F0F0F0); + if(N32_1x32·λ.compare(result, b) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(array); + return false; + } + + // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1 + N32_1x32·λ.from_uint32(a, 0x0F0F0F0F); + N32_1x32·λ.bit_twos_complement(result, a); + N32_1x32·λ.from_uint32(b, 0xF0F0F0F1); + if(N32_1x32·λ.compare(result, b) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(array); + return false; + } + + N32_1x32·λ.deallocate(array); + return true; +} + +bool test_comparisons(){ + // Allocate memory + N32_1x32·T *array = N32_1x32·λ.allocate_array(2, NULL); + if(!array) return false; + + N32_1x32·T *a = N32_1x32·λ.access(array, 0); + N32_1x32·T *b = N32_1x32·λ.access(array, 1); + N32_1x32·T *c = N32_1x32·λ.access(array, 2); + + // First set: a=0, b=42, c=42 + N32_1x32·λ.from_uint32(a, 0); + N32_1x32·λ.from_uint32(b, 42); + N32_1x32·λ.from_uint32(c, 42); + + // eq_zero(a) => true + if(!N32_1x32·λ.eq_zero(a)){ + N32_1x32·λ.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32_1x32·λ.eq_zero(b)){ + N32_1x32·λ.deallocate(array); + return false; + } + // eq(b, c) => true + if(!N32_1x32·λ.eq(b, c)){ + N32_1x32·λ.deallocate(array); + return false; + } + // eq(a, b) => false + if(N32_1x32·λ.eq(a, b)){ + N32_1x32·λ.deallocate(array); + return false; + } + // compare(a, b) => N32_1x32·Order_lt + if(N32_1x32·λ.compare(a, b) != N32_1x32·Order_lt){ + N32_1x32·λ.deallocate(array); + return false; + } + // compare(b, a) => N32_1x32·Order_gt + if(N32_1x32·λ.compare(b, a) != N32_1x32·Order_gt){ + N32_1x32·λ.deallocate(array); + return false; + } + // compare(b, c) => N32_1x32·Order_eq + if(N32_1x32·λ.compare(b, c) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(array); + return false; + } + // lt(a, b) => true, gt(b, a) => true + if(!N32_1x32·λ.lt(a, b) || !N32_1x32·λ.gt(b, a)){ + N32_1x32·λ.deallocate(array); + return false; + } + + // Second set: a=100, b=50 + N32_1x32·λ.from_uint32(a, 100); + N32_1x32·λ.from_uint32(b, 50); + if(N32_1x32·λ.compare(a, b) != N32_1x32·Order_gt){ + N32_1x32·λ.deallocate(array); + return false; + } + // eq_zero(a) => false + if(N32_1x32·λ.eq_zero(a)){ + N32_1x32·λ.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32_1x32·λ.eq_zero(b)){ + N32_1x32·λ.deallocate(array); + return false; + } + + N32_1x32·λ.deallocate(array); + return true; +} + +bool test_shifts(){ + // Allocate memory for operand, fill, spill + N32_1x32·T *array = N32_1x32·λ.allocate_array(2, NULL); + if(!array) return false; + + N32_1x32·T *operand = N32_1x32·λ.access(array, 0); + N32_1x32·T *fill = N32_1x32·λ.access(array, 1); + N32_1x32·T *spill = N32_1x32·λ.access(array, 2); + + // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0 + N32_1x32·λ.from_uint32(operand, 1); + N32_1x32·λ.from_uint32(fill, 0); + N32_1x32·λ.from_uint32(spill, 0); + if(N32_1x32·λ.shift_left(4, spill, operand, fill) != N32_1x32·Status·ok){ + N32_1x32·λ.deallocate(array); + return false; + } + N32_1x32·T *temp = N32_1x32·λ.allocate_array(1, NULL); + if(!temp){ + N32_1x32·λ.deallocate(array); + return false; + } + N32_1x32·λ.from_uint32(temp, 16); + if(N32_1x32·λ.compare(operand, temp) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + if(N32_1x32·λ.compare(fill, N32_1x32·zero) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + if(N32_1x32·λ.compare(spill, N32_1x32·zero) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + + // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1 + N32_1x32·λ.from_uint32(operand, 0x80000000); + N32_1x32·λ.from_uint32(fill, 0); + N32_1x32·λ.from_uint32(spill, 0); + if(N32_1x32·λ.shift_left(1, spill, operand, fill) != N32_1x32·Status·ok){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + if(!N32_1x32·λ.eq_zero(operand)){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + N32_1x32·λ.from_uint32(temp, 1); + if(N32_1x32·λ.compare(spill, temp) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + + // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0 + N32_1x32·λ.from_uint32(operand, 0x80000000); + N32_1x32·λ.from_uint32(fill, 0); + N32_1x32·λ.from_uint32(spill, 0); + if(N32_1x32·λ.shift_right(1, spill, operand, fill) != N32_1x32·Status·ok){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + N32_1x32·λ.from_uint32(temp, 0x40000000); + if(N32_1x32·λ.compare(operand, temp) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + if(!N32_1x32·λ.eq_zero(spill)){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + + // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0 + N32_1x32·λ.from_uint32(operand, 0x80000000); + N32_1x32·λ.from_uint32(spill, 0); + if(N32_1x32·λ.arithmetic_shift_right(1, operand, spill) != N32_1x32·Status·ok){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + N32_1x32·λ.from_uint32(temp, 0xC0000000); + if(N32_1x32·λ.compare(operand, temp) != N32_1x32·Order_eq){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + if(!N32_1x32·λ.eq_zero(spill)){ + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return false; + } + + N32_1x32·λ.deallocate(temp); + N32_1x32·λ.deallocate(array); + return true; +} + + + +// Include the local section of N32_1x32.lib.c for testing +#define LOCAL +#include "N32_1x32.lib.c" +#undef LOCAL diff --git a/tester/cc/test_N32_4x8_0.cli.c b/tester/cc/test_N32_4x8_0.cli.c new file mode 100644 index 0000000..daf0e11 --- /dev/null +++ b/tester/cc/test_N32_4x8_0.cli.c @@ -0,0 +1,364 @@ +#include +#include +#include +#include + +// Enable interface section +#define FACE +#include "N32_4x8.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_4x8·T *array = N32_4x8·λ.allocate_array(1 ,NULL); + if( !array ) return false; + + // Access elements via access function + N32_4x8·T *a = N32_4x8·λ.access(array ,0); + N32_4x8·T *b = N32_4x8·λ.access(array ,1); + + // Assign value and copy + N32_4x8·λ.from_uint32(a ,42); + N32_4x8·λ.copy(b ,a); + + bool success = ( N32_4x8·λ.compare(b ,a) == N32_4x8·Order_eq ); + N32_4x8·λ.deallocate(array); + return success; +} + +bool test_arithmetic(){ + // Allocate memory + N32_4x8·T *array = N32_4x8·λ.allocate_array(2 ,NULL); + if( !array ) return false; + + N32_4x8·T *a = N32_4x8·λ.access(array ,0); + N32_4x8·T *b = N32_4x8·λ.access(array ,1); + N32_4x8·T *result = N32_4x8·λ.access(array ,2); + + N32_4x8·λ.from_uint32(a ,20); + N32_4x8·λ.from_uint32(b ,22); + + if( N32_4x8·λ.add(result ,a ,b) != N32_4x8·Status·ok ) return false; + if( N32_4x8·λ.compare(result ,N32_4x8·λ.access(array ,0)) != N32_4x8·Order_gt ) return false; + + if( N32_4x8·λ.subtract(result ,b ,a) != N32_4x8·Status·ok ) return false; + if( N32_4x8·λ.compare(result ,N32_4x8·λ.access(array ,0)) != N32_4x8·Order_lt ) return false; + + N32_4x8·λ.deallocate(array); + return true; +} + +bool test_bitwise_operations(){ + // Allocate memory + N32_4x8·T *array = N32_4x8·λ.allocate_array(2, NULL); + if(!array) return false; + + N32_4x8·T *a = N32_4x8·λ.access(array, 0); + N32_4x8·T *b = N32_4x8·λ.access(array, 1); + N32_4x8·T *result = N32_4x8·λ.access(array, 2); + + // a = 0x0F0F0F0F, b = 0xF0F0F0F0 + N32_4x8·λ.from_uint32(a, 0x0F0F0F0F); + N32_4x8·λ.from_uint32(b, 0xF0F0F0F0); + + // bit_and => expect 0x00000000 + N32_4x8·λ.bit_and(result, a, b); + N32_4x8·λ.from_uint32(a, 0x00000000); + if(N32_4x8·λ.compare(result, a) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(array); + return false; + } + + // Reset a to 0x0F0F0F0F for next tests + N32_4x8·λ.from_uint32(a, 0x0F0F0F0F); + + // bit_or => expect 0xFFFFFFFF + N32_4x8·λ.bit_or(result, a, b); + N32_4x8·λ.from_uint32(b, 0xFFFFFFFF); + if(N32_4x8·λ.compare(result, b) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(array); + return false; + } + + // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0 + N32_4x8·λ.from_uint32(a, 0x0F0F0F0F); + N32_4x8·λ.bit_complement(result, a); + N32_4x8·λ.from_uint32(b, 0xF0F0F0F0); + if(N32_4x8·λ.compare(result, b) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(array); + return false; + } + + // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1 + N32_4x8·λ.from_uint32(a, 0x0F0F0F0F); + N32_4x8·λ.bit_twos_complement(result, a); + N32_4x8·λ.from_uint32(b, 0xF0F0F0F1); + if(N32_4x8·λ.compare(result, b) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(array); + return false; + } + + N32_4x8·λ.deallocate(array); + return true; +} + +bool test_comparisons(){ + // Allocate memory + N32_4x8·T *array = N32_4x8·λ.allocate_array(2, NULL); + if(!array) return false; + + N32_4x8·T *a = N32_4x8·λ.access(array, 0); + N32_4x8·T *b = N32_4x8·λ.access(array, 1); + N32_4x8·T *c = N32_4x8·λ.access(array, 2); + + // First set: a=0, b=42, c=42 + N32_4x8·λ.from_uint32(a, 0); + N32_4x8·λ.from_uint32(b, 42); + N32_4x8·λ.from_uint32(c, 42); + + // eq_zero(a) => true + if(!N32_4x8·λ.eq_zero(a)){ + N32_4x8·λ.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32_4x8·λ.eq_zero(b)){ + N32_4x8·λ.deallocate(array); + return false; + } + // eq(b, c) => true + if(!N32_4x8·λ.eq(b, c)){ + N32_4x8·λ.deallocate(array); + return false; + } + // eq(a, b) => false + if(N32_4x8·λ.eq(a, b)){ + N32_4x8·λ.deallocate(array); + return false; + } + // compare(a, b) => N32_4x8·Order_lt + if(N32_4x8·λ.compare(a, b) != N32_4x8·Order_lt){ + N32_4x8·λ.deallocate(array); + return false; + } + // compare(b, a) => N32_4x8·Order_gt + if(N32_4x8·λ.compare(b, a) != N32_4x8·Order_gt){ + N32_4x8·λ.deallocate(array); + return false; + } + // compare(b, c) => N32_4x8·Order_eq + if(N32_4x8·λ.compare(b, c) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(array); + return false; + } + // lt(a, b) => true, gt(b, a) => true + if(!N32_4x8·λ.lt(a, b) || !N32_4x8·λ.gt(b, a)){ + N32_4x8·λ.deallocate(array); + return false; + } + + // Second set: a=100, b=50 + N32_4x8·λ.from_uint32(a, 100); + N32_4x8·λ.from_uint32(b, 50); + if(N32_4x8·λ.compare(a, b) != N32_4x8·Order_gt){ + N32_4x8·λ.deallocate(array); + return false; + } + // eq_zero(a) => false + if(N32_4x8·λ.eq_zero(a)){ + N32_4x8·λ.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32_4x8·λ.eq_zero(b)){ + N32_4x8·λ.deallocate(array); + return false; + } + + N32_4x8·λ.deallocate(array); + return true; +} + +bool test_shifts(){ + // Allocate memory for operand, fill, spill + N32_4x8·T *array = N32_4x8·λ.allocate_array(2, NULL); + if(!array) return false; + + N32_4x8·T *operand = N32_4x8·λ.access(array, 0); + N32_4x8·T *fill = N32_4x8·λ.access(array, 1); + N32_4x8·T *spill = N32_4x8·λ.access(array, 2); + + // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0 + N32_4x8·λ.from_uint32(operand, 1); + N32_4x8·λ.from_uint32(fill, 0); + N32_4x8·λ.from_uint32(spill, 0); + if(N32_4x8·λ.shift_left(4, spill, operand, fill) != N32_4x8·Status·ok){ + N32_4x8·λ.deallocate(array); + return false; + } + N32_4x8·T *temp = N32_4x8·λ.allocate_array(1, NULL); + if(!temp){ + N32_4x8·λ.deallocate(array); + return false; + } + N32_4x8·λ.from_uint32(temp, 16); + if(N32_4x8·λ.compare(operand, temp) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + if(N32_4x8·λ.compare(fill, N32_4x8·zero) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + if(N32_4x8·λ.compare(spill, N32_4x8·zero) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + + // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1 + N32_4x8·λ.from_uint32(operand, 0x80000000); + N32_4x8·λ.from_uint32(fill, 0); + N32_4x8·λ.from_uint32(spill, 0); + if(N32_4x8·λ.shift_left(1, spill, operand, fill) != N32_4x8·Status·ok){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + if(!N32_4x8·λ.eq_zero(operand)){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + N32_4x8·λ.from_uint32(temp, 1); + if(N32_4x8·λ.compare(spill, temp) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + + // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0 + N32_4x8·λ.from_uint32(operand, 0x80000000); + N32_4x8·λ.from_uint32(fill, 0); + N32_4x8·λ.from_uint32(spill, 0); + if(N32_4x8·λ.shift_right(1, spill, operand, fill) != N32_4x8·Status·ok){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + N32_4x8·λ.from_uint32(temp, 0x40000000); + if(N32_4x8·λ.compare(operand, temp) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + if(!N32_4x8·λ.eq_zero(spill)){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + + // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0 + N32_4x8·λ.from_uint32(operand, 0x80000000); + N32_4x8·λ.from_uint32(spill, 0); + if(N32_4x8·λ.arithmetic_shift_right(1, operand, spill) != N32_4x8·Status·ok){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + N32_4x8·λ.from_uint32(temp, 0xC0000000); + if(N32_4x8·λ.compare(operand, temp) != N32_4x8·Order_eq){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + if(!N32_4x8·λ.eq_zero(spill)){ + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return false; + } + + N32_4x8·λ.deallocate(temp); + N32_4x8·λ.deallocate(array); + return true; +} + + + +// Include the local section of N32_4x8.lib.c for testing +#define LOCAL +#include "N32_4x8.lib.c" +#undef LOCAL diff --git "a/tester/document\360\237\226\211/build_procedure.org" "b/tester/document\360\237\226\211/build_procedure.org" new file mode 100644 index 0000000..08c1e44 --- /dev/null +++ "b/tester/document\360\237\226\211/build_procedure.org" @@ -0,0 +1,50 @@ +#+TITLE: Tester Build Proceedure +#+AUTHOR: RT C Documentation + +*. To enter the tester environment: + + Be sure the installation is complete, and that tool_shared/third_party/RT-project-share has been installed. See the tool_shared/document🖉/install.txt + + #BEGIN{SRC} + > cd N # enter the project + > . env_tester # to inititialie the test environment + #END{SRC} + + After initializing the environment you will be in the `tester` directory. + +*. To build the tests from the first time: + + #BEGIN{SRC} + > release_pull + > make cli + #END{SRC} + +*. After editing header inclusion structure the dependency file must be rebuilt + + #BEGIN{SRC} + > make dependency + #END{SRC} + +*. To rebuild the tests after other edits + + #BEGIN{SRC} + > make cli + #END{SRC} + +*. To resample the release. + + See which directory the developer places our platform release files + + #BEGIN{SRC} + > release_dir + #END{SRC} + + See the files in the release directory, accepts same arguments as ls + + #BEGIN{SRC} + > release_ls -l + #END{SRC} + + Note that `release_dir` and `release_ls` are in the `RT-project-share` project mentioned in the first point. + + diff --git a/tester/python/fill_template b/tester/python/fill_template index f94a8f2..b4a691c 100755 --- a/tester/python/fill_template +++ b/tester/python/fill_template @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import sys -from template_test_N32 import test_N32 +from template_test_N32_0 import test_N32_0 def write(code ,basename): filepath = "../cc/" + "test_" + basename + ".cli.c" @@ -17,13 +17,13 @@ def main(): # N32 processor native type_name = "N32" - code = test_N32(namespace = type_name) - write(code ,type_name); + code = test_N32_0(namespace = type_name) + write(code ,type_name + "_0"); # N32 1 digit of 32 bits type_name = "N32_1x32" - code = test_N32(namespace = type_name) - write(code ,type_name); + code = test_N32_0(namespace = type_name) + write(code ,type_name + "_0"); # N32 2 digits of 16 bits # type_name = "N32_4x8" @@ -32,8 +32,8 @@ def main(): # N32 4 digits of 8 bits type_name = "N32_4x8" - code = test_N32(namespace = type_name) - write(code ,type_name); + code = test_N32_0(namespace = type_name) + write(code ,type_name + "_0"); if __name__ == "__main__": diff --git a/tester/python/template_test_N32.py b/tester/python/template_test_N32.py deleted file mode 100644 index 7d26285..0000000 --- a/tester/python/template_test_N32.py +++ /dev/null @@ -1,381 +0,0 @@ -# {NS} must be a N32 type. -# -# test_N32 can be used to test any 32 bit natural number types. As examples: N32PN the processor native type; N32_4_by_8 a 32 bit natural number type made of 4 digits, where each digit is 8 bits. -# - -def test_N32(namespace: str) -> str: - """ - Returns a source code file for cc. - """ - template = template_test_N32() - code = template.format( - NS = namespace - ) - return code - -def template_test_N32(): - return r'''#include -#include -#include -#include - -// Enable interface section -#define FACE -#include "{NS}.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 - {NS}·T *array = {NS}·λ.allocate_array(2 ,NULL); - if( !array ) return false; - - // Access elements via access function - {NS}·T *a = {NS}·λ.access(array ,0); - {NS}·T *b = {NS}·λ.access(array ,1); - - // Assign value and copy - {NS}·λ.from_uint32(a ,42); - {NS}·λ.copy(b ,a); - - bool success = ( {NS}·λ.compare(b ,a) == {NS}·Order_eq ); - {NS}·λ.deallocate(array); - return success; -}} - -bool test_arithmetic(){{ - // Allocate memory - {NS}·T *array = {NS}·λ.allocate_array(3 ,NULL); - if( !array ) return false; - - {NS}·T *a = {NS}·λ.access(array ,0); - {NS}·T *b = {NS}·λ.access(array ,1); - {NS}·T *result = {NS}·λ.access(array ,2); - - {NS}·λ.from_uint32(a ,20); - {NS}·λ.from_uint32(b ,22); - - if( {NS}·λ.add(result ,a ,b) != {NS}·Status·ok ) return false; - if( {NS}·λ.compare(result ,{NS}·λ.access(array ,0)) != {NS}·Order_gt ) return false; - - if( {NS}·λ.subtract(result ,b ,a) != {NS}·Status·ok ) return false; - if( {NS}·λ.compare(result ,{NS}·λ.access(array ,0)) != {NS}·Order_lt ) return false; - - {NS}·λ.deallocate(array); - return true; -}} - -bool test_bitwise_operations(){{ - // Allocate memory - {NS}·T *array = {NS}·λ.allocate_array(3, NULL); - if(!array) return false; - - {NS}·T *a = {NS}·λ.access(array, 0); - {NS}·T *b = {NS}·λ.access(array, 1); - {NS}·T *result = {NS}·λ.access(array, 2); - - // a = 0x0F0F0F0F, b = 0xF0F0F0F0 - {NS}·λ.from_uint32(a, 0x0F0F0F0F); - {NS}·λ.from_uint32(b, 0xF0F0F0F0); - - // bit_and => expect 0x00000000 - {NS}·λ.bit_and(result, a, b); - {NS}·λ.from_uint32(a, 0x00000000); - if({NS}·λ.compare(result, a) != {NS}·Order_eq){{ - {NS}·λ.deallocate(array); - return false; - }} - - // Reset a to 0x0F0F0F0F for next tests - {NS}·λ.from_uint32(a, 0x0F0F0F0F); - - // bit_or => expect 0xFFFFFFFF - {NS}·λ.bit_or(result, a, b); - {NS}·λ.from_uint32(b, 0xFFFFFFFF); - if({NS}·λ.compare(result, b) != {NS}·Order_eq){{ - {NS}·λ.deallocate(array); - return false; - }} - - // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0 - {NS}·λ.from_uint32(a, 0x0F0F0F0F); - {NS}·λ.bit_complement(result, a); - {NS}·λ.from_uint32(b, 0xF0F0F0F0); - if({NS}·λ.compare(result, b) != {NS}·Order_eq){{ - {NS}·λ.deallocate(array); - return false; - }} - - // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1 - {NS}·λ.from_uint32(a, 0x0F0F0F0F); - {NS}·λ.bit_twos_complement(result, a); - {NS}·λ.from_uint32(b, 0xF0F0F0F1); - if({NS}·λ.compare(result, b) != {NS}·Order_eq){{ - {NS}·λ.deallocate(array); - return false; - }} - - {NS}·λ.deallocate(array); - return true; -}} - -bool test_comparisons(){{ - // Allocate memory - {NS}·T *array = {NS}·λ.allocate_array(3, NULL); - if(!array) return false; - - {NS}·T *a = {NS}·λ.access(array, 0); - {NS}·T *b = {NS}·λ.access(array, 1); - {NS}·T *c = {NS}·λ.access(array, 2); - - // First set: a=0, b=42, c=42 - {NS}·λ.from_uint32(a, 0); - {NS}·λ.from_uint32(b, 42); - {NS}·λ.from_uint32(c, 42); - - // eq_zero(a) => true - if(!{NS}·λ.eq_zero(a)){{ - {NS}·λ.deallocate(array); - return false; - }} - // eq_zero(b) => false - if({NS}·λ.eq_zero(b)){{ - {NS}·λ.deallocate(array); - return false; - }} - // eq(b, c) => true - if(!{NS}·λ.eq(b, c)){{ - {NS}·λ.deallocate(array); - return false; - }} - // eq(a, b) => false - if({NS}·λ.eq(a, b)){{ - {NS}·λ.deallocate(array); - return false; - }} - // compare(a, b) => {NS}·Order_lt - if({NS}·λ.compare(a, b) != {NS}·Order_lt){{ - {NS}·λ.deallocate(array); - return false; - }} - // compare(b, a) => {NS}·Order_gt - if({NS}·λ.compare(b, a) != {NS}·Order_gt){{ - {NS}·λ.deallocate(array); - return false; - }} - // compare(b, c) => {NS}·Order_eq - if({NS}·λ.compare(b, c) != {NS}·Order_eq){{ - {NS}·λ.deallocate(array); - return false; - }} - // lt(a, b) => true, gt(b, a) => true - if(!{NS}·λ.lt(a, b) || !{NS}·λ.gt(b, a)){{ - {NS}·λ.deallocate(array); - return false; - }} - - // Second set: a=100, b=50 - {NS}·λ.from_uint32(a, 100); - {NS}·λ.from_uint32(b, 50); - if({NS}·λ.compare(a, b) != {NS}·Order_gt){{ - {NS}·λ.deallocate(array); - return false; - }} - // eq_zero(a) => false - if({NS}·λ.eq_zero(a)){{ - {NS}·λ.deallocate(array); - return false; - }} - // eq_zero(b) => false - if({NS}·λ.eq_zero(b)){{ - {NS}·λ.deallocate(array); - return false; - }} - - {NS}·λ.deallocate(array); - return true; -}} - -bool test_shifts(){{ - // Allocate memory for operand, fill, spill - {NS}·T *array = {NS}·λ.allocate_array(3, NULL); - if(!array) return false; - - {NS}·T *operand = {NS}·λ.access(array, 0); - {NS}·T *fill = {NS}·λ.access(array, 1); - {NS}·T *spill = {NS}·λ.access(array, 2); - - // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0 - {NS}·λ.from_uint32(operand, 1); - {NS}·λ.from_uint32(fill, 0); - {NS}·λ.from_uint32(spill, 0); - if({NS}·λ.shift_left(4, spill, operand, fill) != {NS}·Status·ok){{ - {NS}·λ.deallocate(array); - return false; - }} - {NS}·T *temp = {NS}·λ.allocate_array(1, NULL); - if(!temp){{ - {NS}·λ.deallocate(array); - return false; - }} - {NS}·λ.from_uint32(temp, 16); - if({NS}·λ.compare(operand, temp) != {NS}·Order_eq){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - if({NS}·λ.compare(fill, {NS}·zero) != {NS}·Order_eq){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - if({NS}·λ.compare(spill, {NS}·zero) != {NS}·Order_eq){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - - // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1 - {NS}·λ.from_uint32(operand, 0x80000000); - {NS}·λ.from_uint32(fill, 0); - {NS}·λ.from_uint32(spill, 0); - if({NS}·λ.shift_left(1, spill, operand, fill) != {NS}·Status·ok){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - if(!{NS}·λ.eq_zero(operand)){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - {NS}·λ.from_uint32(temp, 1); - if({NS}·λ.compare(spill, temp) != {NS}·Order_eq){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - - // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0 - {NS}·λ.from_uint32(operand, 0x80000000); - {NS}·λ.from_uint32(fill, 0); - {NS}·λ.from_uint32(spill, 0); - if({NS}·λ.shift_right(1, spill, operand, fill) != {NS}·Status·ok){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - {NS}·λ.from_uint32(temp, 0x40000000); - if({NS}·λ.compare(operand, temp) != {NS}·Order_eq){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - if(!{NS}·λ.eq_zero(spill)){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - - // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0 - {NS}·λ.from_uint32(operand, 0x80000000); - {NS}·λ.from_uint32(spill, 0); - if({NS}·λ.arithmetic_shift_right(1, operand, spill) != {NS}·Status·ok){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - {NS}·λ.from_uint32(temp, 0xC0000000); - if({NS}·λ.compare(operand, temp) != {NS}·Order_eq){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - if(!{NS}·λ.eq_zero(spill)){{ - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return false; - }} - - {NS}·λ.deallocate(temp); - {NS}·λ.deallocate(array); - return true; -}} - - - -// Include the local section of {NS}.lib.c for testing -#define LOCAL -#include "{NS}.lib.c" -#undef LOCAL -''' diff --git a/tester/python/template_test_N32_0.py b/tester/python/template_test_N32_0.py new file mode 100644 index 0000000..5d07a5c --- /dev/null +++ b/tester/python/template_test_N32_0.py @@ -0,0 +1,381 @@ +# {NS} must be a N32 type. +# +# test_N32 can be used to test any 32 bit natural number types. As examples: N32PN the processor native type; N32_4_by_8 a 32 bit natural number type made of 4 digits, where each digit is 8 bits. +# + +def test_N32_0(namespace: str) -> str: + """ + Returns a source code file for cc. + """ + template = template_test_N32_0() + code = template.format( + NS = namespace + ) + return code + +def template_test_N32_0(): + return r'''#include +#include +#include +#include + +// Enable interface section +#define FACE +#include "{NS}.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 + {NS}·T *array = {NS}·λ.allocate_array(1 ,NULL); + if( !array ) return false; + + // Access elements via access function + {NS}·T *a = {NS}·λ.access(array ,0); + {NS}·T *b = {NS}·λ.access(array ,1); + + // Assign value and copy + {NS}·λ.from_uint32(a ,42); + {NS}·λ.copy(b ,a); + + bool success = ( {NS}·λ.compare(b ,a) == {NS}·Order_eq ); + {NS}·λ.deallocate(array); + return success; +}} + +bool test_arithmetic(){{ + // Allocate memory + {NS}·T *array = {NS}·λ.allocate_array(2 ,NULL); + if( !array ) return false; + + {NS}·T *a = {NS}·λ.access(array ,0); + {NS}·T *b = {NS}·λ.access(array ,1); + {NS}·T *result = {NS}·λ.access(array ,2); + + {NS}·λ.from_uint32(a ,20); + {NS}·λ.from_uint32(b ,22); + + if( {NS}·λ.add(result ,a ,b) != {NS}·Status·ok ) return false; + if( {NS}·λ.compare(result ,{NS}·λ.access(array ,0)) != {NS}·Order_gt ) return false; + + if( {NS}·λ.subtract(result ,b ,a) != {NS}·Status·ok ) return false; + if( {NS}·λ.compare(result ,{NS}·λ.access(array ,0)) != {NS}·Order_lt ) return false; + + {NS}·λ.deallocate(array); + return true; +}} + +bool test_bitwise_operations(){{ + // Allocate memory + {NS}·T *array = {NS}·λ.allocate_array(2, NULL); + if(!array) return false; + + {NS}·T *a = {NS}·λ.access(array, 0); + {NS}·T *b = {NS}·λ.access(array, 1); + {NS}·T *result = {NS}·λ.access(array, 2); + + // a = 0x0F0F0F0F, b = 0xF0F0F0F0 + {NS}·λ.from_uint32(a, 0x0F0F0F0F); + {NS}·λ.from_uint32(b, 0xF0F0F0F0); + + // bit_and => expect 0x00000000 + {NS}·λ.bit_and(result, a, b); + {NS}·λ.from_uint32(a, 0x00000000); + if({NS}·λ.compare(result, a) != {NS}·Order_eq){{ + {NS}·λ.deallocate(array); + return false; + }} + + // Reset a to 0x0F0F0F0F for next tests + {NS}·λ.from_uint32(a, 0x0F0F0F0F); + + // bit_or => expect 0xFFFFFFFF + {NS}·λ.bit_or(result, a, b); + {NS}·λ.from_uint32(b, 0xFFFFFFFF); + if({NS}·λ.compare(result, b) != {NS}·Order_eq){{ + {NS}·λ.deallocate(array); + return false; + }} + + // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0 + {NS}·λ.from_uint32(a, 0x0F0F0F0F); + {NS}·λ.bit_complement(result, a); + {NS}·λ.from_uint32(b, 0xF0F0F0F0); + if({NS}·λ.compare(result, b) != {NS}·Order_eq){{ + {NS}·λ.deallocate(array); + return false; + }} + + // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1 + {NS}·λ.from_uint32(a, 0x0F0F0F0F); + {NS}·λ.bit_twos_complement(result, a); + {NS}·λ.from_uint32(b, 0xF0F0F0F1); + if({NS}·λ.compare(result, b) != {NS}·Order_eq){{ + {NS}·λ.deallocate(array); + return false; + }} + + {NS}·λ.deallocate(array); + return true; +}} + +bool test_comparisons(){{ + // Allocate memory + {NS}·T *array = {NS}·λ.allocate_array(2, NULL); + if(!array) return false; + + {NS}·T *a = {NS}·λ.access(array, 0); + {NS}·T *b = {NS}·λ.access(array, 1); + {NS}·T *c = {NS}·λ.access(array, 2); + + // First set: a=0, b=42, c=42 + {NS}·λ.from_uint32(a, 0); + {NS}·λ.from_uint32(b, 42); + {NS}·λ.from_uint32(c, 42); + + // eq_zero(a) => true + if(!{NS}·λ.eq_zero(a)){{ + {NS}·λ.deallocate(array); + return false; + }} + // eq_zero(b) => false + if({NS}·λ.eq_zero(b)){{ + {NS}·λ.deallocate(array); + return false; + }} + // eq(b, c) => true + if(!{NS}·λ.eq(b, c)){{ + {NS}·λ.deallocate(array); + return false; + }} + // eq(a, b) => false + if({NS}·λ.eq(a, b)){{ + {NS}·λ.deallocate(array); + return false; + }} + // compare(a, b) => {NS}·Order_lt + if({NS}·λ.compare(a, b) != {NS}·Order_lt){{ + {NS}·λ.deallocate(array); + return false; + }} + // compare(b, a) => {NS}·Order_gt + if({NS}·λ.compare(b, a) != {NS}·Order_gt){{ + {NS}·λ.deallocate(array); + return false; + }} + // compare(b, c) => {NS}·Order_eq + if({NS}·λ.compare(b, c) != {NS}·Order_eq){{ + {NS}·λ.deallocate(array); + return false; + }} + // lt(a, b) => true, gt(b, a) => true + if(!{NS}·λ.lt(a, b) || !{NS}·λ.gt(b, a)){{ + {NS}·λ.deallocate(array); + return false; + }} + + // Second set: a=100, b=50 + {NS}·λ.from_uint32(a, 100); + {NS}·λ.from_uint32(b, 50); + if({NS}·λ.compare(a, b) != {NS}·Order_gt){{ + {NS}·λ.deallocate(array); + return false; + }} + // eq_zero(a) => false + if({NS}·λ.eq_zero(a)){{ + {NS}·λ.deallocate(array); + return false; + }} + // eq_zero(b) => false + if({NS}·λ.eq_zero(b)){{ + {NS}·λ.deallocate(array); + return false; + }} + + {NS}·λ.deallocate(array); + return true; +}} + +bool test_shifts(){{ + // Allocate memory for operand, fill, spill + {NS}·T *array = {NS}·λ.allocate_array(2, NULL); + if(!array) return false; + + {NS}·T *operand = {NS}·λ.access(array, 0); + {NS}·T *fill = {NS}·λ.access(array, 1); + {NS}·T *spill = {NS}·λ.access(array, 2); + + // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0 + {NS}·λ.from_uint32(operand, 1); + {NS}·λ.from_uint32(fill, 0); + {NS}·λ.from_uint32(spill, 0); + if({NS}·λ.shift_left(4, spill, operand, fill) != {NS}·Status·ok){{ + {NS}·λ.deallocate(array); + return false; + }} + {NS}·T *temp = {NS}·λ.allocate_array(1, NULL); + if(!temp){{ + {NS}·λ.deallocate(array); + return false; + }} + {NS}·λ.from_uint32(temp, 16); + if({NS}·λ.compare(operand, temp) != {NS}·Order_eq){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + if({NS}·λ.compare(fill, {NS}·zero) != {NS}·Order_eq){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + if({NS}·λ.compare(spill, {NS}·zero) != {NS}·Order_eq){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + + // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1 + {NS}·λ.from_uint32(operand, 0x80000000); + {NS}·λ.from_uint32(fill, 0); + {NS}·λ.from_uint32(spill, 0); + if({NS}·λ.shift_left(1, spill, operand, fill) != {NS}·Status·ok){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + if(!{NS}·λ.eq_zero(operand)){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + {NS}·λ.from_uint32(temp, 1); + if({NS}·λ.compare(spill, temp) != {NS}·Order_eq){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + + // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0 + {NS}·λ.from_uint32(operand, 0x80000000); + {NS}·λ.from_uint32(fill, 0); + {NS}·λ.from_uint32(spill, 0); + if({NS}·λ.shift_right(1, spill, operand, fill) != {NS}·Status·ok){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + {NS}·λ.from_uint32(temp, 0x40000000); + if({NS}·λ.compare(operand, temp) != {NS}·Order_eq){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + if(!{NS}·λ.eq_zero(spill)){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + + // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0 + {NS}·λ.from_uint32(operand, 0x80000000); + {NS}·λ.from_uint32(spill, 0); + if({NS}·λ.arithmetic_shift_right(1, operand, spill) != {NS}·Status·ok){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + {NS}·λ.from_uint32(temp, 0xC0000000); + if({NS}·λ.compare(operand, temp) != {NS}·Order_eq){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + if(!{NS}·λ.eq_zero(spill)){{ + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return false; + }} + + {NS}·λ.deallocate(temp); + {NS}·λ.deallocate(array); + return true; +}} + + + +// Include the local section of {NS}.lib.c for testing +#define LOCAL +#include "{NS}.lib.c" +#undef LOCAL +''' diff --git "a/tester/tool\360\237\226\211/clean" "b/tester/tool\360\237\226\211/clean" index cebc4c0..03d0380 100755 --- "a/tester/tool\360\237\226\211/clean" +++ "b/tester/tool\360\237\226\211/clean" @@ -15,9 +15,12 @@ set -x cd "$REPO_HOME"/tester || exit 1 -# remove library pulled from release and other scratchpad files +# remove test program dependency and objects rm_na scratchpad/{makefile-cc.deps,*.o} || true +# remove synthesized test sources + rm_na cc/test_*.c || true + # remove built executables rm_na -f machine/* || true diff --git "a/tester/tool\360\237\226\211/release" "b/tester/tool\360\237\226\211/release" deleted file mode 100755 index ecbf3ff..0000000 --- "a/tester/tool\360\237\226\211/release" +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# include tests in the project release - -# 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/tester/tool\360\237\226\211/release_pull" "b/tester/tool\360\237\226\211/release_pull" index 7c1182e..d76d7e3 100755 --- "a/tester/tool\360\237\226\211/release_pull" +++ "b/tester/tool\360\237\226\211/release_pull" @@ -1,32 +1,50 @@ #!/usr/bin/env bash script_afp=$(realpath "${BASH_SOURCE[0]}") -# pulls the library and include files down from the project release directory +# Pulls the library and include files down from the project release directory. +# Writes a list of installed files to a log file, `scratchpad/release_files.log`, while +# assuming no simultaneous writes. -# 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 - - 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 +# input guards +env_must_be="tester/tool🖉/env" +if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_afp):: error: must be run in the $env_must_be environment" + exit 1 +fi + +cd "$REPO_HOME"/tester || exit 1 + +if [ ! -d scratchpad ]; then + echo "$(script_afp):: no scratchpad directory" + exit 1 +fi + +release_dir=$(release_dir) + +if [ ! -d "$release_dir" ]; then + echo "$(script_afp):: no release directory to pull install files from" + exit 1 +fi + +log_file="scratchpad/release_files.log" +: >> "$log_file" # Create and append to the log file + +# Copy release files and track them +if ! cp -f "$release_dir/libN.a" scratchpad && realpath scratchpad/libN.a >> "$log_file"; then + echo "$(script_afp):: warning: no libN.a found" >&2 +fi + +for file in "$release_dir"/*.lib.c; do + if [ -f "$file" ]; then + if cp -f "$file" cc; then + realpath "cc/$(basename "$file")" >> "$log_file" + else + echo "$(script_afp):: warning: failed to copy $file" >&2 + fi + else + echo "$(script_afp):: warning: skipping non-regular file $file" >&2 fi +done - cp -f ${release_dir}/libN.a scratchpad || true - cp -f ${release_dir}/*.lib.c cc || true - -echo "$(script_fn) done." - +echo "$(script_afp) done." diff --git "a/tester/tool\360\237\226\211/release_remove" "b/tester/tool\360\237\226\211/release_remove" index 2e0da45..3fa7ede 100755 --- "a/tester/tool\360\237\226\211/release_remove" +++ "b/tester/tool\360\237\226\211/release_remove" @@ -1,28 +1,36 @@ #!/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 +# Removes release files that were previously pulled. +# Reads `scratchpad/release_files.log` and removes each file using `rm_na`. +# Input guards +env_must_be="tester/tool🖉/env" +if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_afp):: error: must be run in the $env_must_be environment" + exit 1 +fi cd "$REPO_HOME"/tester || exit 1 -# remove library pulled from release and other scratchpad files - rm_na -rf scratchpad/* || true +log_file="scratchpad/release_files.log" -# remove cc files pulled from release - rm_na -f cc/* || true +# Ensure log file exists and is not empty +if [ ! -s "$log_file" ]; then + echo "$(script_afp):: no release log found, nothing to remove." >&2 + exit 0 +fi + +# Remove files listed in the log +while IFS= read -r file; do + if [ -f "$file" ]; then + rm_na "$file" + else + echo "$(script_afp):: warning: expected release file not found: $file" >&2 + fi +done < "$log_file" -# remove built executables - rm_na -f machine/* || true +# Cleanup log file after successful removal +: > "$log_file" -set +x -echo "$(script_fn) done." +echo "$(script_afp) done."