1
2#include <stdio.h>
3#include <stdlib.h>
4#include <assert.h>
5
6
7unsigned 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
21unsigned 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
32unsigned 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
43unsigned 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
58unsigned 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
76unsigned 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
94unsigned 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
112unsigned 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
135typedef unsigned int UInt;
136typedef unsigned char UChar;
137
138UInt rol1 ( UInt x )
139{
140  return (x << 1) | (x >> 31);
141}
142
143int 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, &reg); break;
193         case 1: c = btrl_reg(reg, bitoff, &reg); break;
194         case 2: c = btcl_reg(reg, bitoff, &reg); break;
195         case 3: c = btl_reg(reg, bitoff, &reg); 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