1 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <assert.h> 5 6 7 unsigned int btsl_mem ( unsigned char* base, int bitno ) 8 { 9 unsigned char res; 10 __asm__ 11 __volatile__("btsl\t%2, %0\n\t" 12 "setc\t%1" 13 : "=m" (*base), "=q" (res) 14 : "r" (bitno)); 15 /* Pretty meaningless to dereference base here, but that's what you 16 have to do to get a btsl insn which refers to memory starting at 17 base. */ 18 return res; 19 } 20 21 unsigned int btrl_mem ( unsigned char* base, int bitno ) 22 { 23 unsigned char res; 24 __asm__ 25 __volatile__("btrl\t%2, %0\n\t" 26 "setc\t%1" 27 : "=m" (*base), "=q" (res) 28 : "r" (bitno)); 29 return res; 30 } 31 32 unsigned int btcl_mem ( unsigned char* base, int bitno ) 33 { 34 unsigned char res; 35 __asm__ 36 __volatile__("btcl\t%2, %0\n\t" 37 "setc\t%1" 38 : "=m" (*base), "=q" (res) 39 : "r" (bitno)); 40 return res; 41 } 42 43 unsigned int btl_mem ( unsigned char* base, int bitno ) 44 { 45 unsigned char res; 46 __asm__ 47 __volatile__("btl\t%2, %0\n\t" 48 "setc\t%1" 49 : "=m" (*base), "=q" (res) 50 : "r" (bitno) 51 : "cc", "memory"); 52 return res; 53 } 54 55 56 57 58 unsigned int btsl_reg ( unsigned int reg_in, int bitno, 59 unsigned int* reg_out_p ) 60 { 61 unsigned char res; 62 unsigned int reg_out; 63 __asm__ 64 __volatile__("movl\t%3, %%eax\n\t" 65 "btsl\t%2, %%eax\n\t" 66 "movl\t%%eax, %1\n\t" 67 "setc\t%0" 68 : "=q" (res), "=r" (reg_out) 69 : "r" (bitno), "r" (reg_in) 70 : "cc", "eax"); 71 *reg_out_p = reg_out; 72 return res; 73 } 74 75 76 unsigned int btrl_reg ( unsigned int reg_in, int bitno, 77 unsigned int* reg_out_p ) 78 { 79 unsigned char res; 80 unsigned int reg_out; 81 __asm__ 82 __volatile__("movl\t%3, %%eax\n\t" 83 "btrl\t%2, %%eax\n\t" 84 "movl\t%%eax, %1\n\t" 85 "setc\t%0" 86 : "=q" (res), "=r" (reg_out) 87 : "r" (bitno), "r" (reg_in) 88 : "cc", "eax"); 89 *reg_out_p = reg_out; 90 return res; 91 } 92 93 94 unsigned int btcl_reg ( unsigned int reg_in, int bitno, 95 unsigned int* reg_out_p ) 96 { 97 unsigned char res; 98 unsigned int reg_out; 99 __asm__ 100 __volatile__("movl\t%3, %%eax\n\t" 101 "btcl\t%2, %%eax\n\t" 102 "movl\t%%eax, %1\n\t" 103 "setc\t%0" 104 : "=q" (res), "=r" (reg_out) 105 : "r" (bitno), "r" (reg_in) 106 : "cc", "eax"); 107 *reg_out_p = reg_out; 108 return res; 109 } 110 111 112 unsigned int btl_reg ( unsigned int reg_in, int bitno, 113 unsigned int* reg_out_p ) 114 { 115 unsigned char res; 116 unsigned int reg_out; 117 __asm__ 118 __volatile__("movl\t%3, %%eax\n\t" 119 "btl\t%2, %%eax\n\t" 120 "movl\t%%eax, %1\n\t" 121 "setc\t%0" 122 : "=q" (res), "=r" (reg_out) 123 : "r" (bitno), "r" (reg_in) 124 : "cc", "eax"); 125 *reg_out_p = reg_out; 126 return res; 127 } 128 129 130 131 132 133 134 135 typedef unsigned int UInt; 136 typedef unsigned char UChar; 137 138 UInt rol1 ( UInt x ) 139 { 140 return (x << 1) | (x >> 31); 141 } 142 143 int main ( void ) 144 { 145 UInt n, bitoff, op; 146 UInt carrydep, c, res; 147 UChar* block; 148 UInt reg; 149 150 /*------------------------ MEM-L -----------------------*/ 151 152 carrydep = 0; 153 block = calloc(200,1); 154 block += 100; 155 /* Valid bit offsets are -800 .. 799 inclusive. */ 156 157 for (n = 0; n < 10000; n++) { 158 bitoff = (random() % 1600) - 800; 159 op = random() % 4; 160 c = 2; 161 switch (op) { 162 case 0: c = btsl_mem(block, bitoff); break; 163 case 1: c = btrl_mem(block, bitoff); break; 164 case 2: c = btcl_mem(block, bitoff); break; 165 case 3: c = btl_mem(block, bitoff); break; 166 } 167 assert(c == 0 || c == 1); 168 carrydep = c ? (rol1(carrydep) ^ bitoff) : carrydep; 169 } 170 171 /* Compute final result */ 172 block -= 100; 173 res = 0; 174 for (n = 0; n < 200; n++) { 175 UChar ch = block[n]; 176 /* printf("%d ", (int)block[n]); */ 177 res = rol1(res) ^ (UInt)ch; 178 } 179 180 printf("MEM-L: final res 0x%x, carrydep 0x%x\n", res, carrydep); 181 182 /*------------------------ REG-L -----------------------*/ 183 184 carrydep = 0; 185 reg = 0; 186 187 for (n = 0; n < 1000; n++) { 188 bitoff = (random() % 100) - 50; 189 op = random() % 4; 190 c = 2; 191 switch (op) { 192 case 0: c = btsl_reg(reg, bitoff, ®); break; 193 case 1: c = btrl_reg(reg, bitoff, ®); break; 194 case 2: c = btcl_reg(reg, bitoff, ®); break; 195 case 3: c = btl_reg(reg, bitoff, ®); break; 196 } 197 assert(c == 0 || c == 1); 198 carrydep = c ? (rol1(carrydep) ^ bitoff) : carrydep; 199 } 200 201 printf("REG-L: final res 0x%x, carrydep 0x%x\n", reg, carrydep); 202 203 block += 100; 204 205 /* Just try one of these at once; more than one can cause a 206 confusing merging of error messages. */ 207 //btsl_mem(block, -800); /* should not complain */ 208 //btsl_mem(block, -801); /* should complain */ 209 //btsl_mem(block, 799); /* should not complain */ 210 //btsl_mem(block, 800); /* should complain */ 211 212 block -= 100; 213 free(block); 214 215 return 0; 216 } 217 218