/***** * * Michael Riff * Multiprecision main program version 1.0 Februar 2022. * * Main routine calling the assember implemented multiprecision routines: * div3.s : 128/16 bits division (using divu assembler instruction) * * March 2022 clear renaming of routines and reordering in the files: * Addition of a 128:95 bits division test * * May 2024 moved 96:63 and 128:63 tests here *****/ #include #include typedef struct { unsigned long high; unsigned long low; } Unsigned64; /* Unsigned 64 type defined in Toolbox as typdef struct { unsigned long high; unsignd long low; } Int64bit; */ // Signed 64 type defined typedef struct{ long high; //TBC unsigned long low; } Signed64; typedef struct { unsigned long high; unsigned long middle; unsigned long low; } Unsigned96; typedef struct { unsigned long high; unsigned long middle_u; unsigned long middle_l; unsigned long low; } Unsigned128; typedef struct { long high; long middle_u; long middle_l; long low; } Signed128; void div_128_95 (Unsigned128 *dvd, Unsigned96 *dvs, Unsigned128 *quot, Unsigned96 *rem); void div_128_16 (Unsigned128 *dvd, unsigned int dvs, Unsigned128 *quot, unsigned int *rem); Unsigned128 Test_128, Quot_128; Unsigned64 Divisor; Unsigned64 Remain_64; Unsigned96 Test_96, Divisor_96, Quot_96, Remain_96; char dummy; /* Backwards calculation for 96:64 bits division */ void Reverse96_64(Unsigned96 *Quotient, Unsigned64 *Remain, Unsigned64 *Divisor) { Unsigned64 Temp; Unsigned128 Result; Signed128 SResult; int xer; // Multiply Quotient with divisor in 2 steps Temp.high = Quotient->high; Temp.low = Quotient->middle; mul_64u (Divisor, &Temp, &Result); // Shift by 32 bits Result.high = 0; Result.middle_u = Result.middle_l; Result.middle_l = Result.low; Result.low = 0; Temp.high = 0; Temp.low = Quotient->low; mul_64u (Divisor, &Temp, (Unsigned128*)&SResult); add_128 ((Signed128*)&Result, &SResult, (Signed128*)&Result, &xer); SResult.high = 0; SResult.middle_u = 0; SResult.middle_l = Remain->high; SResult.low = Remain->low; add_128 (&SResult, (Signed128*)&Result, (Signed128*)&Result, &xer); printf("96 div rev %x %x %x %x, %x\n", Result.high, Result.middle_u, Result.middle_l, Result.low, xer); } /* Backwards calculation for 128:64 bits division */ void Reverse128_64(Unsigned128 *Quotient, Unsigned64 *Remain, Unsigned64 *Divisor) { Unsigned64 Temp; Unsigned128 Result; Signed128 SResult; int xer; // Multiply Quotient with divisor in 2 steps Temp.high = Quotient->high; Temp.low = Quotient->middle_u; mul_64u (Divisor, &Temp, &Result); // Shift by 64 bits Result.high = Result.middle_l; Result.middle_u = Result.low; Result.middle_l = 0; Result.low = 0; Temp.high = Quotient->middle_l; Temp.low = Quotient->low; mul_64u (Divisor, &Temp, (Unsigned128*)&SResult); add_128 ((Signed128*)&Result, &SResult, (Signed128*)&Result, &xer); // Add remainder SResult.high = 0; SResult.middle_u = 0; SResult.middle_l = Remain->high; SResult.low = Remain->low; add_128 (&SResult, (Signed128*)&Result, (Signed128*)&Result, &xer); printf("128 div rev %x %x %x %x, %x\n", Result.high, Result.middle_u, Result.middle_l, Result.low, xer); } /* Backwards test for 128:96 division */ void Back_128_96 (Unsigned96 *Divisor, Unsigned128 *Quot, Unsigned96 *Remain) { Unsigned64 tmp1, tmp2; Unsigned128 Result1, Result2; int xer; // First we check that the product of the 64 highest bits is 0 tmp1.high = Quot->high; tmp1.low = Quot->middle_u; tmp2.high = 0; tmp2.low = Divisor->high; mul_64u (&tmp1, &tmp2, &Result1); if (Result1.high !=0 || Result1.middle_u != 0 || Result1.middle_l != 0 || Result1.low !=0) { printf ("1 Error! 128 bits ovfw %x %x %x %x\n", Result1.high, Result1.middle_u, Result1.middle_l, Result1.low); } // Calculate the cross products tmp2.high = Divisor->middle; tmp2.low = Divisor->low; mul_64u (&tmp1, &tmp2, &Result1); tmp1.high = Quot->middle_l; tmp1.low = Quot->low; tmp2.high = 0; tmp2.low = Divisor->high; mul_64u (&tmp1, &tmp2, &Result2); add_128 ((Signed128*)&Result1, (Signed128*)&Result2, (Signed128*)&Result1, &xer); if (Result1.high !=0 || Result1.middle_u != 0) { printf ("2 Error! 128 bits ovfw %x %x %x %x\n", Result1.high, Result1.middle_u, Result1.middle_l, Result1.low); } // Shift result by 64 bits Result1.high = Result1.middle_l; Result1.middle_u = Result1.low; Result1.middle_l = 0x0; Result1.low = 0x0; // Calculate low product tmp2.high = Divisor->middle; tmp2.low = Divisor->low; mul_64u (&tmp1, &tmp2, &Result2); add_128 ((Signed128*)&Result1, (Signed128*)&Result2, (Signed128*)&Result1, &xer); // Extend remainder on 128 bits Result2.high = 0x0; Result2.middle_u = Remain->high; Result2.middle_l = Remain->middle; Result2.low = Remain->low; add_128 ((Signed128*)&Result1, (Signed128*)&Result2, (Signed128*)&Result2, &xer); printf ("128:96 rev %x %x %x %x\n", Result2.high, Result2.middle_u, Result2.middle_l, Result2.low); } int main() { unsigned int rem; printf("hello world\n"); /* 128 : 16 bits */ Divisor.high = 0x00000000; Divisor.low = 0x0000c3a8; Test_128.high = 0xabcd1234; Test_128.middle_u = 0x00000000; Test_128.middle_l = 0x00000000; Test_128.low = 0x00000000; div_128_16 (&Test_128, Divisor.low, &Quot_128, &rem); printf("128_16 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, rem); Remain_64.high = 0x00000000; Remain_64.low = rem; Reverse128_64(&Quot_128, &Remain_64, &Divisor); Divisor.high = 0x00000000; Divisor.low = 0x00004b8e; Test_128.high = 0x5679efab; Test_128.middle_u = 0x00000000; Test_128.middle_l = 0x00000000; Test_128.low = 0x00000000; div_128_16 (&Test_128, Divisor.low, &Quot_128, &rem); printf("--> 128_16 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, rem); Remain_64.high = 0x00000000; Remain_64.low = rem; Reverse128_64(&Quot_128, &Remain_64, &Divisor); /* 96 : 63 bits */ // Shift < 32 (22+5+1=28) 4*7 Divisor.high = 0x07F00000; Test_96.high = 0x00303030; Test_96.middle = 0x05050101; // dvsr 0x07F00000 Test_96.low = 0x13111121; // test_96 (&Test_96, &Divisor, &Quot_96, &Remain_64); printf("--> 96_63 div %x %x %x / %x %x|\t", Test_96.high, Test_96.middle, Test_96.low, Divisor.high, Divisor.low); div_96_63 (&Test_96, &Divisor, &Quot_96, &Remain_64); printf("%x %x %x + %x %x\n", Quot_96.high, Quot_96.middle, Quot_96.low, Remain_64.high, Remain_64.low); Reverse96_64(&Quot_96, &Remain_64, &Divisor); // Shift < 64 (28+19+1=48) 4*12 Divisor.high = 0x00001F00; Test_96.high = 0x0FF00001; Test_96.middle = 0x05810580; // dvsr 0x00001F00 Test_96.low = 0x13111121; // test_96 (&Test_96, &Divisor, &Quot_96, &Remain_64); printf("--> 96_63 div %x %x %x / %x %x|\t", Test_96.high, Test_96.middle, Test_96.low, Divisor.high, Divisor.low); div_96_63 (&Test_96, &Divisor, &Quot_96, &Remain_64); printf("%x %x %x + %x %x\n", Quot_96.high, Quot_96.middle, Quot_96.low, Remain_64.high, Remain_64.low); Reverse96_64(&Quot_96, &Remain_64, &Divisor); // Shift < 96 (32+32+3+1=68) 4*17 Divisor.high = 0x00000000; Divisor.low = 0x1F000000; Test_96.high = 0xF0F03030; Test_96.middle = 0x05050101; Test_96.low = 0x11111111; // dvsr 0x1F000000 // test_96 (&Test_96, &Divisor, &Quot_96, &Remain_64); printf("--> 96_63 div %x %x %x / %x %x|\t", Test_96.high, Test_96.middle, Test_96.low, Divisor.high, Divisor.low); div_96_63 (&Test_96, &Divisor, &Quot_96, &Remain_64); printf("%x %x %x + %x %x\n", Quot_96.high, Quot_96.middle, Quot_96.low, Remain_64.high, Remain_64.low); Reverse96_64(&Quot_96, &Remain_64, &Divisor); scanf("%c\r", &dummy); /* 128 : 63 bits */ // Shift < 32 (18+5+1=24) 4*6 Divisor.high = 0x07000000; Test_128.high = 0x00000000; Test_128.middle_u = 0x00035050; Test_128.middle_l = 0x03030303; // dvsr 0x0700000000 Test_128.low = 0x11111111; // test_128 (&Test_128, &Divisor, &Quot_128, &Remain_64); div_128_63 (&Test_128, &Divisor, &Quot_128, &Remain_64); printf("--> 128_63 div %x %x %x %x|\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_64.high, Remain_64.low); Reverse128_64(&Quot_128, &Remain_64, &Divisor); // Shift < 64 (19+32+8+1=60) 4*15 Divisor.high = 0x00F00000; Test_128.high = 0x0070303; Test_128.middle_u = 0x05050505; Test_128.middle_l = 0x03030303; // dvsr 0x00F00000 Test_128.low = 0x11111111; // test_128 (&Test_128, &Divisor, &Quot_128, &Remain_64); div_128_63 (&Test_128, &Divisor, &Quot_128, &Remain_64); printf("--> 128_63 div %x %x %x %x|\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_64.high, Remain_64.low); Reverse128_64(&Quot_128, &Remain_64, &Divisor); // Shift < 96 (23+32+32+4+1=92) 4*23 Divisor.high = 0x00000000; Divisor.low = 0x0F000000; Test_128.high = 0x00730303; Test_128.middle_u = 0x05050505; Test_128.middle_l = 0x03030303; Test_128.low = 0x11111111; // dvsr 0x0F000000 // test_128 (&Test_128, &Divisor, &Quot_128, &Remain_64); div_128_63 (&Test_128, &Divisor, &Quot_128, &Remain_64); printf("--> 128_63 div %x %x %x %x|\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_64.high, Remain_64.low); Reverse128_64(&Quot_128, &Remain_64, &Divisor); // Shift >= 96 (31+32+32+4+1=100) Test_128.high = 0x71030303; Test_128.middle_u = 0x05050505; Test_128.middle_l = 0x03030303; Test_128.low = 0x11111111; // dvsr 0x0F000000 // test_128 (&Test_128, &Divisor, &Quot_128, &Remain_64); div_128_63 (&Test_128, &Divisor, &Quot_128, &Remain_64); printf("--> 128_63 div %x %x %x %x|\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_64.high, Remain_64.low); Reverse128_64(&Quot_128, &Remain_64, &Divisor); scanf("%c\r", &dummy); /* 128 : 95 bits */ Divisor_96.high = 0x00303030; Divisor_96.middle = 0x05050101; Divisor_96.low = 0x13111121; Test_128.high = 0x71030303; Test_128.middle_u = 0x05050505; Test_128.middle_l = 0x03030303; Test_128.low = 0x11111111; div_128_95 (&Test_128, &Divisor_96, &Quot_128, &Remain_96); printf("--> 128_95 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_96.high, Remain_96.middle); Back_128_96 (&Divisor_96, &Quot_128, &Remain_96); Divisor_96.low = 0x1F000000; // Shift < 32 (18+5+1=24) 4*6 Divisor_96.high = 0x07000000; Test_128.high = 0x00000000; Test_128.middle_u = 0x00035050; // dvsr 0x07000000 Test_128.middle_l = 0x03030303; Test_128.low = 0x11111111; div_128_95 (&Test_128, &Divisor_96, &Quot_128, &Remain_96); printf("--> 128_95 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_96.middle, Remain_96.low); Back_128_96 (&Divisor_96, &Quot_128, &Remain_96); // Shift < 64 (19+32+8+1=60) 4*15 Divisor_96.high = 0x00F00000; Test_128.high = 0x0070303; Test_128.middle_u = 0x05050505; Test_128.middle_l = 0x03030303; // dvsr 0x00F00000 Test_128.low = 0x11111111; div_128_95 (&Test_128, &Divisor_96, &Quot_128, &Remain_96); printf("--> 128_95 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_96.middle, Remain_96.low); Back_128_96 (&Divisor_96, &Quot_128, &Remain_96); // Shift < 96 (23+32+32+4+1=92) 4*23 Divisor.high = 0x00000000; Divisor.low = 0x0F000000; Test_128.high = 0x00730303; Test_128.middle_u = 0x05050505; Test_128.middle_l = 0x03030303; Test_128.low = 0x11111111; // dvsr 0x0F000000 div_128_95 (&Test_128, &Divisor_96, &Quot_128, &Remain_96); printf("--> 128_95 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_96.middle, Remain_96.low); Back_128_96 (&Divisor_96, &Quot_128, &Remain_96); // Shift >= 96 (31+32+32+4+1=100) Test_128.high = 0x71030303; Test_128.middle_u = 0x05050505; Test_128.middle_l = 0x03030303; Test_128.low = 0x11111111; // dvsr 0x0F000000 div_128_95 (&Test_128, &Divisor_96, &Quot_128, &Remain_96); printf("--> 128_95 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_96.middle, Remain_96.low); Back_128_96 (&Divisor_96, &Quot_128, &Remain_96); // Additional Divisor.high = 0x00000000; Divisor.low = 0x4c5d6e7f; Test_128.high = 0x67a5b64c; Test_128.middle_u = 0x14d0e32f; Test_128.middle_l = 0x12345678; Test_128.low = 0xabcdef01; // dvsr 0x4c5d6e7f div_128_95 (&Test_128, &Divisor_96, &Quot_128, &Remain_96); printf("--> 128_95 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_96.middle, Remain_96.low); Back_128_96 (&Divisor_96, &Quot_128, &Remain_96); /* Additional division tests, to check the shift of a bit into the register of higher order than the divisor. See note! */ Test_128.high = 0x02020000; Test_128.middle_u = 0x00000000; Test_128.middle_l = 0x00000000; Test_128.low = 0x00000000; Divisor.high = 0x90000000; Divisor.low = 0x00000000; div_128_95 (&Test_128, &Divisor_96, &Quot_128, &Remain_96); printf("--> 128_95 div %x %x %x %x\t", Test_128.high, Test_128.middle_u , Test_128.middle_l, Test_128.low); printf("%x %x %x %x + %x %x\n", Quot_128.high, Quot_128.middle_u, Quot_128.middle_l, Quot_128.low, Remain_96.middle, Remain_96.low); Back_128_96 (&Divisor_96, &Quot_128, &Remain_96); return EXIT_SUCCESS; }