News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

The CPUID Instruction

Started by baltoro, January 28, 2011, 10:48:22 PM

Previous topic - Next topic

baltoro

I've been reading this document from Intel: Intel Processor Identification and the CPUID Instruction, and, if you jump to page 55. there is an assembly language program, that identifies the Intel processor type and FPU type. I have no doubt that most of you guys have read this article.   
What I'm wondering is, can a single assembly program use many different values of the processor directive (.386, .486. and other variations)? And, if so, what does the compiler emit when this is done (is there some type of conditional block)? For example, if you read through the program, you'll notice that it begins with this (for 32-bit segments):
.386
.Model flat

The program then decalares a large .DATA section, and a couple of pages later, this is written:   
.CODE
.586

...and, then, half way down the page, it's back to:   
.386
...then, on the next page,...
.286
...some code is executed, and then,...
.386
...which, on the next page, is changed to:   
.486
...and, then,...
.586
...and, so on,...

My book on assembly language programming, states that you use this directive to indicate which instruction set is used for the program.
...So, I'm a little mystified. I have to assume that Intel knows alot about assembly programming, and would not release defunct code to the public,...
If, for instance, you used the highest possible value (.686), and the processor executing the code was an earlier architecture, this would generate an invalid opcode exception, correct (assuming that a more advanced opcode was actually compiled into the program)? What is this? Is the Intel method the best way to do this?
After searching here at the forum, I found this MSDN site explaining the various MASM directives: Directives Reference.
...Any enlightenment you can provide would be appreciated,...Thanks.
Baltoro

dedndave

it depends on the instruction, but yes - it can cause an exception
in many cases, the instructions work on older CPU's
they switch around because they want to test for older CPU's
that code isn't very useful in the real world, except as a guideline
that is because win 2000 and above require a pentium as a minimum
hence, if you are writing 32-bit code for windows, you can ignore all the 386, 286, and earlier stuff
although, win 95 will run on a 486, as i recall

another thing that makes that program somewhat useless is the fact that it only ID's Intel CPU's
the one AMD has only ID's AMD CPU's
to be of any real use, a routine has to ID all types   :bg

baltoro

Thanks, Dave.  :8)
Quote from: DEDNDAVEthat code isn't very useful in the real world, except as a guideline
that is because win 2000 and above require a pentium as a minimum
...I didn't know that,...
But, the main question: you CAN alter the processor directive any number of times within a single program?
YES
Baltoro

MichaelW

As far as I know their use of the processor directive is just a convenience, an easy way to restrict the available instructions to those supported by the target processor for a given section of code.
eschew obfuscation

dedndave

QuoteBut, the main question: you CAN alter the processor directive any number of times within a single program?

by all means, you can change the current processor type as many times as you like

a good example of how the code may be affected is the conditional branch instructions
for older processors, the distance had to be +/- 128 bytes
for newer processors (486 and above), they can be near (32-bits)
if you use a conditional branch instruction (like JZ) and make it branch over 128 bytes (can be 128 NOP's)
you can then change the processor directive and see the "Relative jump out of range" error generated by MASM

another example is to use, say, ECX to address memory
older processors will not allow it - newer ones will

to use the CPUID instruction, .586 or better is required, even though late 486's support the instruction

Tedd

You can set it to .686 once and leave it.
The point is only to limit the instructions you can use, the output is the same regardless (kind of the point of assembler). For example, if you do try to use CPUID with .386, you'll get an error "instruction or register not accepted in current CPU mode" because 386 doesn't support it.
You won't really gain anything by mixing them, other than a warning that you have a 'bad' instruction in the wrong place; but if you're checking for features, you should be conditionally executing functions based on those tests, not on general blocks of what a certain range of CPUs 'should' support.

So, before you call/jump to any code that might use CPUID, you should check that instruction is supported:
got_cpuid proc
    pushfd
    mov eax,[esp]
    xor eax,00200000h
    pushfd
    pop ecx
    popfd
    xor eax,ecx
    shr eax,21
    and eax,1
    ;return: 0=false, 1=true
    ret
got_cpuid endp


..and then check for the specific features you want, and either call the custom functions, or spew error messages and whine about it :bg
No snowflake in an avalanche feels responsible.

dedndave

Tedd,
in this case, they use the lower processor directives in order to restrict MASM from generating newer code
point being, if you are going to ID old processors like a 286, you can't start off by running 586 instructions
i really can't think of a case where their code is useful, though   :lol
if you are going to ID a 286, it will be running DOS or win3.1, at best
intel did not take the platform into consideration when they published that code

baltoro

Thanks to both Dave and Tedd (and, Michael).
Excellent responses. And, really useful information, too.
I appreciate it.  :toothy
Baltoro