1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <assert.h>
5
myrandom(void)6 unsigned 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
btsl_mem(unsigned char * base,int bitno)18 unsigned 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
btrl_mem(unsigned char * base,int bitno)32 unsigned 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
btcl_mem(unsigned char * base,int bitno)43 unsigned 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
btl_mem(unsigned char * base,int bitno)54 unsigned 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
btsl_reg(unsigned int reg_in,int bitno,unsigned int * reg_out_p)69 unsigned 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
btrl_reg(unsigned int reg_in,int bitno,unsigned int * reg_out_p)87 unsigned 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
btcl_reg(unsigned int reg_in,int bitno,unsigned int * reg_out_p)105 unsigned 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
btl_reg(unsigned int reg_in,int bitno,unsigned int * reg_out_p)123 unsigned 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
146 typedef unsigned int UInt;
147 typedef unsigned char UChar;
148
rol1(UInt x)149 UInt rol1 ( UInt x )
150 {
151 return (x << 1) | (x >> 31);
152 }
153
main(void)154 int 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, ®); break;
204 case 1: c = btrl_reg(reg, bitoff, ®); break;
205 case 2: c = btcl_reg(reg, bitoff, ®); break;
206 case 3: c = btl_reg(reg, bitoff, ®); 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