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