1 ; Musepack audio compression 2 ; Copyright (C) 1999-2004 Buschmann/Klemm/Piecha/Wolf 3 ; 4 ; This library is free software; you can redistribute it and/or 5 ; modify it under the terms of the GNU Lesser General Public 6 ; License as published by the Free Software Foundation; either 7 ; version 2.1 of the License, or (at your option) any later version. 8 ; 9 ; This library is distributed in the hope that it will be useful, 10 ; but WITHOUT ANY WARRANTY; without even the implied warranty of 11 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 ; Lesser General Public License for more details. 13 ; 14 ; You should have received a copy of the GNU Lesser General Public 15 ; License along with this library; if not, write to the Free Software 16 ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 18 ; 19 ; Assembler routines to detect CPU features for Intel x86 compatible CPUs 20 ; (Intel, AMD, Rise, Cyrix). CPU must be at least a 386SX, otherwise the 21 ; detection routines fail with an "Illegal Instruction Trap". 22 ; 23 ; But note: 24 ; - you currently need at least a high end 486 CPU to run in realtime 25 ; - this is only important if you want to built a 16 bit executable 26 ; running on 80286 and on modern CPUs with Katmai/3DNow! support 27 ; 28 29 %include "tools.inc" 30 <1> ; 31 <1> ; (C) Ururi 1999 32 <1> ; 33 <1> 34 <1> BITS 32 35 <1> 36 <1> %ifdef WIN32 37 <1> %define _NAMING 38 <1> %define segment_code segment .text align=32 class=CODE use32 39 <1> %define segment_data segment .data align=32 class=DATA use32 40 <1> %ifdef __BORLANDC__ 41 <1> %define segment_bss segment .data align=32 class=DATA use32 42 <1> %else 43 <1> %define segment_bss segment .bss align=32 class=DATA use32 44 <1> %endif 45 <1> 46 <1> %elifdef AOUT 47 <1> %define _NAMING 48 <1> %define segment_code segment .text 49 <1> %define segment_data segment .data 50 <1> %define segment_bss segment .bss 51 <1> 52 <1> %else 53 <1> %define segment_code segment .text align=32 class=CODE use32 54 <1> %define segment_data segment .data align=32 class=DATA use32 55 <1> %define segment_bss segment .bss align=32 class=DATA use32 56 <1> %endif 57 <1> 58 <1> %define pmov movq 59 <1> %define pmovd movd 60 <1> 61 <1> %define pupldq punpckldq 62 <1> %define puphdq punpckhdq 63 <1> %define puplwd punpcklwd 64 <1> %define puphwd punpckhwd 65 <1> 66 <1> %imacro globaldef 1 67 <1> %ifdef _NAMING 68 <1> %define %1 _%1 69 <1> %endif 70 <1> global %1 71 <1> %endmacro 72 <1> 73 <1> %imacro externdef 1 74 <1> %ifdef _NAMING 75 <1> %define %1 _%1 76 <1> %endif 77 <1> extern %1 78 <1> %endmacro 79 <1> 80 <1> %imacro proc 1 81 <1> %push proc 82 <1> global _%1 83 <1> global %1 84 <1> _%1: 85 <1> %1: 86 <1> %assign %$STACK 0 87 <1> %assign %$STACKN 0 88 <1> %assign %$ARG 4 89 <1> %endmacro 90 <1> 91 <1> %imacro endproc 0 92 <1> %ifnctx proc 93 <1> %error expected 'proc' before 'endproc'. 94 <1> %else 95 <1> %if %$STACK > 0 96 <1> add esp, %$STACK 97 <1> %endif 98 <1> 99 <1> %if %$STACK <> (-%$STACKN) 100 <1> %error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd' 101 <1> %endif 102 <1> 103 <1> ret 104 <1> %pop 105 <1> %endif 106 <1> %endmacro 107 <1> 108 <1> %idefine sp(a) esp+%$STACK+a 109 <1> 110 <1> %imacro arg 1 111 <1> %00 equ %$ARG 112 <1> %assign %$ARG %$ARG+%1 113 <1> %endmacro 114 <1> 115 <1> %imacro local 1 116 <1> %assign %$STACKN %$STACKN-%1 117 <1> %00 equ %$STACKN 118 <1> %endmacro 119 <1> 120 <1> %imacro alloc 0 121 <1> sub esp, (-%$STACKN)-%$STACK 122 <1> %assign %$STACK (-%$STACKN) 123 <1> %endmacro 124 <1> 125 <1> %imacro pushd 1-* 126 <1> %rep %0 127 <1> push %1 128 <1> %assign %$STACK %$STACK+4 129 <1> %rotate 1 130 <1> %endrep 131 <1> %endmacro 132 <1> 133 <1> %imacro popd 1-* 134 <1> %rep %0 135 <1> %rotate -1 136 <1> pop %1 137 <1> %assign %$STACK %$STACK-4 138 <1> %endrep 139 <1> %endmacro 140 141 globaldef Has_MMX 142 <1> %ifdef _NAMING 143 <1> %define %1 _%1 144 <1> %endif 145 <1> global %1 146 globaldef Has_3DNow 147 <1> %ifdef _NAMING 148 <1> %define %1 _%1 149 <1> %endif 150 <1> global %1 151 globaldef Has_SIMD 152 <1> %ifdef _NAMING 153 <1> %define %1 _%1 154 <1> %endif 155 <1> global %1 156 globaldef Has_SIMD2 157 <1> %ifdef _NAMING 158 <1> %define %1 _%1 159 <1> %endif 160 <1> global %1 161 162 163 segment_code 164 165 testCPUID: 166 00000000 9C pushfd 167 00000001 58 pop eax 168 00000002 89C1 mov ecx,eax 169 00000004 3500002000 xor eax,0x200000 170 00000009 50 push eax 171 0000000A 9D popfd 172 0000000B 9C pushfd 173 0000000C 58 pop eax 174 0000000D 39C8 cmp eax,ecx 175 0000000F B801000000 mov eax,1 176 00000014 C3 ret 177 178 ;-------------------------------------; 179 ; bool_t Has_MMX (void) ; 180 ;-------------------------------------; 181 182 proc Has_MMX 183 <1> %push proc 184 <1> global _%1 185 <1> global %1 186 <1> _%1: 187 <1> %1: 188 <1> %assign %$STACK 0 189 <1> %assign %$STACKN 0 190 <1> %assign %$ARG 4 191 00000015 60 pushad 192 00000016 E8E5FFFFFF call testCPUID 193 0000001B 7439 jz return0 ; no CPUID command, so no MMX 194 195 0000001D 0FA2 CPUID 196 0000001F F7C200008000 test edx,0x800000 197 00000025 742F jz return0 ; no MMX support 198 00000027 EB28 jmp short return1 ; MMX support 199 endproc 200 <1> %ifnctx proc 201 <1> %error expected 'proc' before 'endproc'. 202 <1> %else 203 <1> %if %$STACK > 0 204 <1> add esp, %$STACK 205 <1> %endif 206 <1> 207 <1> %if %$STACK <> (-%$STACKN) 208 <1> %error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd' 209 <1> %endif 210 <1> 211 00000029 C3 <1> ret 212 <1> %pop 213 <1> %endif 214 215 ;-------------------------------------; 216 ; bool_t Has_SIMD (void) ; 217 ;-------------------------------------; 218 219 proc Has_SIMD 220 <1> %push proc 221 <1> global _%1 222 <1> global %1 223 <1> _%1: 224 <1> %1: 225 <1> %assign %$STACK 0 226 <1> %assign %$STACKN 0 227 <1> %assign %$ARG 4 228 0000002A 60 pushad 229 0000002B E8D0FFFFFF call testCPUID 230 00000030 7424 jz return0 ; no CPUID command, so no SIMD 231 232 00000032 0FA2 CPUID 233 00000034 F7C200000002 test edx,0x02000000 234 0000003A 741A jz return0 ; no SIMD support 235 0000003C EB13 jmp short return1 ; SIMD support 236 endproc 237 <1> %ifnctx proc 238 <1> %error expected 'proc' before 'endproc'. 239 <1> %else 240 <1> %if %$STACK > 0 241 <1> add esp, %$STACK 242 <1> %endif 243 <1> 244 <1> %if %$STACK <> (-%$STACKN) 245 <1> %error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd' 246 <1> %endif 247 <1> 248 0000003E C3 <1> ret 249 <1> %pop 250 <1> %endif 251 252 ;-------------------------------------; 253 ; bool_t Has_SIMD2 (void) ; 254 ;-------------------------------------; 255 256 proc Has_SIMD2 257 <1> %push proc 258 <1> global _%1 259 <1> global %1 260 <1> _%1: 261 <1> %1: 262 <1> %assign %$STACK 0 263 <1> %assign %$STACKN 0 264 <1> %assign %$ARG 4 265 0000003F 60 pushad 266 00000040 E8BBFFFFFF call testCPUID 267 00000045 740F jz return0 ; no CPUID command, so no SIMD2 268 269 00000047 0FA2 CPUID 270 00000049 F7C200000004 test edx,0x04000000 271 0000004F 7405 jz return0 ; no SIMD2 support 272 ; SIMD2 support 273 return1: 274 00000051 61 popad 275 00000052 31C0 xor eax,eax 276 00000054 40 inc eax 277 00000055 C3 ret 278 279 return0: 280 00000056 61 popad 281 00000057 31C0 xor eax,eax 282 00000059 C3 ret 283 284 endproc 285 <1> %ifnctx proc 286 <1> %error expected 'proc' before 'endproc'. 287 <1> %else 288 <1> %if %$STACK > 0 289 <1> add esp, %$STACK 290 <1> %endif 291 <1> 292 <1> %if %$STACK <> (-%$STACKN) 293 <1> %error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd' 294 <1> %endif 295 <1> 296 0000005A C3 <1> ret 297 <1> %pop 298 <1> %endif 299 300 ;-------------------------------------; 301 ; bool_t Has_3DNow (void) ; 302 ;-------------------------------------; 303 304 proc Has_3DNow 305 <1> %push proc 306 <1> global _%1 307 <1> global %1 308 <1> _%1: 309 <1> %1: 310 <1> %assign %$STACK 0 311 <1> %assign %$STACKN 0 312 <1> %assign %$ARG 4 313 0000005B 60 pushad 314 0000005C E89FFFFFFF call testCPUID 315 00000061 74F3 jz return0 ; no CPUID command, so no 3DNow! 316 317 00000063 B800000080 mov eax,0x80000000 318 00000068 0FA2 CPUID 319 0000006A 3D00000080 cmp eax,0x80000000 320 0000006F 76E5 jbe return0 ; no extended MSR(1), so no 3DNow! 321 322 00000071 B801000080 mov eax,0x80000001 323 00000076 0FA2 CPUID 324 00000078 F7C200000080 test edx,0x80000000 325 0000007E 74D6 jz return0 ; no 3DNow! support 326 00000080 EBCF jmp short return1 ; 3DNow! support 327 endproc 328 <1> %ifnctx proc 329 <1> %error expected 'proc' before 'endproc'. 330 <1> %else 331 <1> %if %$STACK > 0 332 <1> add esp, %$STACK 333 <1> %endif 334 <1> 335 <1> %if %$STACK <> (-%$STACKN) 336 <1> %error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd' 337 <1> %endif 338 <1> 339 00000082 C3 <1> ret 340 <1> %pop 341 <1> %endif 342 343 ;-------------------------------------; 344 ; void Init_FPU2 (void) ; 345 ;-------------------------------------; 346 347 348 proc Init_FPU2 349 <1> %push proc 350 <1> global _%1 351 <1> global %1 352 <1> _%1: 353 <1> %1: 354 <1> %assign %$STACK 0 355 <1> %assign %$STACKN 0 356 <1> %assign %$ARG 4 357 00000083 50 push eax 358 00000084 9BD93C24 fstcw [esp] 359 00000088 80642401FC and byte [esp+1], 0FCh 360 0000008D D92C24 fldcw [esp] 361 00000090 58 pop eax 362 endproc 363 <1> %ifnctx proc 364 <1> %error expected 'proc' before 'endproc'. 365 <1> %else 366 <1> %if %$STACK > 0 367 <1> add esp, %$STACK 368 <1> %endif 369 <1> 370 <1> %if %$STACK <> (-%$STACKN) 371 <1> %error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd' 372 <1> %endif 373 <1> 374 00000091 C3 <1> ret 375 <1> %pop 376 <1> %endif 377 378 end