bcdsub.c (2933B)
1#include <assert.h> 2#include <unistd.h> 3#include <signal.h> 4 5#define CRF_LT (1 << 3) 6#define CRF_GT (1 << 2) 7#define CRF_EQ (1 << 1) 8#define CRF_SO (1 << 0) 9#define UNDEF 0 10 11#define BCDSUB(vra, vrb, ps) \ 12 asm ("bcdsub. %1,%2,%3,%4;" \ 13 "mfocrf %0,0b10;" \ 14 : "=r" (cr), "=v" (vrt) \ 15 : "v" (vra), "v" (vrb), "i" (ps) \ 16 : ); 17 18#define TEST(vra, vrb, ps, exp_res, exp_cr6) \ 19 do { \ 20 __int128 vrt = 0; \ 21 int cr = 0; \ 22 BCDSUB(vra, vrb, ps); \ 23 if (exp_res) \ 24 assert(vrt == exp_res); \ 25 assert((cr >> 4) == exp_cr6); \ 26 } while (0) 27 28 29/* 30 * Unbounded result is equal to zero: 31 * sign = (PS) ? 0b1111 : 0b1100 32 * CR6 = 0b0010 33 */ 34void test_bcdsub_eq(void) 35{ 36 __int128 a, b; 37 38 /* maximum positive BCD value */ 39 a = b = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c); 40 41 TEST(a, b, 0, 0xc, CRF_EQ); 42 TEST(a, b, 1, 0xf, CRF_EQ); 43} 44 45/* 46 * Unbounded result is greater than zero: 47 * sign = (PS) ? 0b1111 : 0b1100 48 * CR6 = (overflow) ? 0b0101 : 0b0100 49 */ 50void test_bcdsub_gt(void) 51{ 52 __int128 a, b, c; 53 54 /* maximum positive BCD value */ 55 a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c); 56 57 /* negative one BCD value */ 58 b = (__int128) 0x1d; 59 60 TEST(a, b, 0, 0xc, (CRF_GT | CRF_SO)); 61 TEST(a, b, 1, 0xf, (CRF_GT | CRF_SO)); 62 63 c = (((__int128) 0x9999999999999999) << 64 | 0x999999999999998c); 64 65 TEST(c, b, 0, a, CRF_GT); 66 TEST(c, b, 1, (a | 0x3), CRF_GT); 67} 68 69/* 70 * Unbounded result is less than zero: 71 * sign = 0b1101 72 * CR6 = (overflow) ? 0b1001 : 0b1000 73 */ 74void test_bcdsub_lt(void) 75{ 76 __int128 a, b; 77 78 /* positive zero BCD value */ 79 a = (__int128) 0xc; 80 81 /* positive one BCD value */ 82 b = (__int128) 0x1c; 83 84 TEST(a, b, 0, 0x1d, CRF_LT); 85 TEST(a, b, 1, 0x1d, CRF_LT); 86 87 /* maximum negative BCD value */ 88 a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999d); 89 90 /* positive one BCD value */ 91 b = (__int128) 0x1c; 92 93 TEST(a, b, 0, 0xd, (CRF_LT | CRF_SO)); 94 TEST(a, b, 1, 0xd, (CRF_LT | CRF_SO)); 95} 96 97void test_bcdsub_invalid(void) 98{ 99 __int128 a, b; 100 101 /* positive one BCD value */ 102 a = (__int128) 0x1c; 103 b = 0xf00; 104 105 TEST(a, b, 0, UNDEF, CRF_SO); 106 TEST(a, b, 1, UNDEF, CRF_SO); 107 108 TEST(b, a, 0, UNDEF, CRF_SO); 109 TEST(b, a, 1, UNDEF, CRF_SO); 110 111 a = 0xbad; 112 113 TEST(a, b, 0, UNDEF, CRF_SO); 114 TEST(a, b, 1, UNDEF, CRF_SO); 115} 116 117int main(void) 118{ 119 struct sigaction action; 120 121 action.sa_handler = _exit; 122 sigaction(SIGABRT, &action, NULL); 123 124 test_bcdsub_eq(); 125 test_bcdsub_gt(); 126 test_bcdsub_lt(); 127 test_bcdsub_invalid(); 128 129 return 0; 130}