Nesta seção será descrito um programa feito por Jeff Prosise retirado da revista PC MAGAZINE BRASIL de abril de 1995. Chama-se WHATCPU e simplesmente coloca na tela uma mensagem identificando o processador da máquina em que está rodando, não entra em detalhes sobre diferentes tipos de um mesmo chip: SX, DX, DX2, DX4.

PROCESSADORES 8086 e 8088

       Apareceram nos primeiros PCs IBM e compatíveis. Eram bastante idênticos, o 8086 tinha 16 linhas de dados, fornecendo ao barramento de dados uma interface de 16 bits. Por outro lado, o 8088 só apresentava 8 linhas de dados, com uma interface de 8 bits. Como se nota, o 8086 era mais rápido, uma vez que era capaz de transportar uma palavra de 16 bits inteira de ou para o barramento de dados numa operação. Já o 8088 precisava de duas operações de 1 byte (8 bits) cada. Fora isso, o funcionamento dos dois processadores era similar, utilizando o mesmo conjunto de instruções e contendo 20 linhas de endereçamento, ou seja, acesso a 1Mb.

       Todos os membros da família x86 contêm um registrador FLAGS, que identifica o estado atual do processador. Os bits de 12 a 15 deste registrador estão sempre ativados (ativado significa conter o valor 1) no caso do 8086/8088, não importando o quanto se tente desativá-los. O que o programa WHATCPU faz é tentar ativar os bits 12 e 14 e limpar os bits 13 e 15, utilizando um sequência de instruções que copia os valores do registrador de e para a pilha, usando instruções AND e OR. Se os bits 12 a 15 permanecerem ativados, então o processador deve ser um 8086.

PROCESSADOR 80286

       Sucessor dos processadores 8086 e 8088, foi utilizado pela primeira vez no IBM PC/AT. Com o 80286 surgiram o modo protegido e quatro linhas novas de endereçamento, passando para 24 linhas no total, o que se traduzia num acesso de até 16Mb. Da mesma forma, é possível identificar este processador através dos bits de 12 a 15 do registrador FLAGS. Se estes bits estão sempre ativados num 8086 ou 8088, estão desativados num 80286 em modo real. Quando o teste que o programa executa é falso para o 8086 ou 8088, é verificado se os bits de 12 a 15 estão desativados. Se estiverem, é porque o processador deve ser um 80286.

PROCESSADOR 80386

       Aumentou ainda mais a capacidade de endereçamento e introduziu o modo virtual (V86). O 80386 possuía 32 linhas de endereçamento, acesso de até 4Gb. O modo V86 veio permitir a execução dos programas mais antigos em máquinas virtuais (VM ou Virtual Machines) como se fosse em modo real, conjuntamente com outros programas em modo protegido. O 80386 tinha duas versões, uma DX e uma SX. O 80386SX continha somente 24 linhas de endereçamento, enquanto que o 80386DX tinha 32 linhas. Contudo, do ponto de vista do software, eram idênticos. A diferença estava na largura da interface para barramento de dados.

       No 80386, o registrador FLAGS foi expandido de 16 para 32 bits e passou a se chamar EFLAGS. O bit 18 do registrador EFLAGS não foi definido e não poderá ser ativado. No 80486 este bit tornou-se o Alignment Check (AC), utilizado para capturar acessos à memória não-alinhados (tentativas de ler uma palavra num endereço que reside nos limites de um byte).

       Desta forma, o programa lê o registrador EFLAGS e tenta ativar o bit AC. Se o valor do bit não puder ser alterado, o programa pode concluir que a máquina é um 80386 e responde de acordo.

PROCESSADOR 80486, PENTIUM e OUTROS

       O 80486 trouxe avanços sobre a linha 80386, projetados para elevar o desempenho. Trouxe incorporado no chip um código unificado e um cache de dados compostos de veloz RAM estática. A versão DX contém um coprocessador matemático integrado ou unidade de ponto flutuante (FPU ou Flooting Point Unit). Os modelos SX são equivalentes, só que com a FPU desativada. Os demais modelos 80486DX2 e 80486DX4 pertencem à classe DX, utilizam tecnologia multiplicadora de relógio para melhorar o desempenho.

       O Pentium trouxe mais velocidade aos processadores da família x86. Tem uma interface de 64 bits para o barramento de dados, arquitetura superescalar (pode executar mais de uma instrução ao mesmo tempo), caches de códigos e de dados separados e uma FPU com pipeline.

       Com a desativação dos processadores 8086, 8088, 80286 e 80386, um programa pode distinguir CPUs 80486SX, 80486DX e 80486DX2 de CPUs 80486DX4 e Pentium através de tentativas de ativação do bit 21 do registrador EFLAGS. Tanto no 80486DX4, quanto no Pentium, este bit é conhecido como bit ID. Estes dois últimos processadores incorporaram uma nova instrução chamada CPUID, que retorna a informação de identificação da CPU. Se o bit ID não puder ser alterado, é sinal seguro de que a CPU é um 80486 (o programa WHATCPU tenta ativar este bit, se não consegue é porque a máquina é um 80486). Entretanto se o bit ID puder ser ativado, devem ser realizados testes adicionais para determinar se o processador é um 80486DX4, um Pentium, ou processador mais recente.

       Se a instrução CPUID for chamada com o registrador EAX contendo o valor 1, o retorno da instrução será depositado no próprio registrador EAX, identificando o nível de passo da CPU (semelhante a um número de versão para software), modelo e família. O termo família, neste caso, se refere ao 80486, Pentium, etc. O código ID identificador de família está contido nos bits 8 a 11. Para separar os processadores Pentium de outras CPUs, o programa executa uma instrução CPUID e examina o resultante código ID de família. Um Pentium é identificado pelo valor 5, um valor 4 identifica um 80486DX4.

       O programa WHATCPU foi feito numa época onde ainda não existiam processadores como o MMX, desta forma novas CPUs poderão retornar diferentes códigos ID de família. Tentando driblar esta situação, o programa mostra o código ID de família seguido por "86", para códigos diferentes de 4 ou 5. Entretanto é provável que o programa não funcione perfeitamente com os sucessores do Pentium.

A seguir está a listagem do programa WHATCPU:


;Programa de Jeff Prosise, PC Magazine Abr 1995.
;E-mail: pcmagbr@eab.com.br

CPUID MACRO
       db 00Fh, 0A2h
                            ;Macro para a instrução CPUID
ENDM

code segment
       assume cs:code, ds:code
       org 100h

begin: jmp short main

msg_8086 db "É um 8086 ou um 8088!",13,10,"$"
msg_286 db "É um 286!",13,10,"$"
msg_386 db "É um 386!",13,10,"$"
msg_486 db "É um 486!",13,10,"$"
msg_586 db "É um Pentium!",13,10,"$"
msg_other db "É um ?86!",13,10,"$"

main proc near
;
; Procura um 8086 ou 8088 tentando limpar os bits de 12 a 15 do registrador
; FLAGS. Num 8086 ou 8088, estes bits estão sempre ativados.
;
       mov dx,offset msg_8086                ;Assume 8086/88
       cli                                                      ;Desativa interrupções
       pushf                                                  ;Salva FLAGS
       pushf                                                  ;Empilha FLAGS
       pop ax                                                ;Desempilha FLAGS em AX
       and ax, 0FFFh                                  ;Limpa bits 12 a 15
       or ax, 5000h                                   ;Ativa bits 12 e 14
       push ax                                              ;Empilha AX
       popf                                                    ;Desempilha AX em FLAGS
       pushf                                                  ;Empilha FLAGS
       pop ax                                                ;Desempilha FLAGS em AX
       popf                                                   ;Restaura FLAGS
       sti                                                      ;Ativa interrupções
       and ax, 0F000h                                ;Limpa bits de 0 a 11
       cmp ax, 0F000h                               ;Bits 12 a 15 estão ativados?
       jne check_286                                  ;Não, então é um 286 ou superior
       jmp done                                            ;Sim, então é um 8086/88
;
; Procura um 286 verificando se os bits de 12 a 15 estão limpos após a
; operação anterior. Num 286 executado em modo real, estes bits estarão
; sempre limpos.
;
check_286: mov dx, offset msg_286 ;Assume 286
       or ax, ax                                          ;Bits de 12 a 15 estão limpos?
       jne check_386                                 ;Não, então é um 386 ou superior
       jmp done                                            ;Sim, é um 286
;
; Procura um 386 tentando ativar o bit Alignment Check (AC) do registrador
; EFLAGS. Este bit não pode ser mudado num 386.
;
       .386
check_386: mov dx, offset msg_386
;Assume 386
       cli                                                      ;Desativa interrupções
       pushfd                                                ;Salva EFLAGS
       pushfd                                                ;Empilha EFLAGS
       pop eax                                              ;Desempilha EFLAGS em EAX
       mov ebx, eax                                   ;Armazena EAX em EBX
       xor eax, 40000h                              ;Alterna bit 18
       push eax                                            ;Empilha EAX
       popfd                                                 ;Desempilha EAX em FLAGS
       pushfd                                               ;Empilha em FLAGS
       pop eax                                              ;Desempilha EFLAGS em EAX
       popfd                                                  ;Restaura EFLAGS
       sti                                                     ;Ativa interrupções
       and eax, 40000h                              ;Limpa todos os bits, exceto o bit 18
       and ebx, 40000h                              ;em EAX e EBX
       cmp eax, ebx                                   ;Compara EAX e EBX
       je done                                              ;Se forem iguais, então é um 386
;
; Procura um 486 tentando ativar o bit ID do registrador EFLAGS. Este bit
; não pode ser ativado na maioria dos 486s.
;
    mov dx, offset msg_486             ;Assume 486
    cli                                                   ;Desativa interrupções
    pushfd                                             ;Salva EFLAGS
    pushfd
                                            ;Empilha EFLAGS
    pop eax
                                          ;Desempilha ELFLAGS em EAX
    mov ebx, eax
                                ;Armazena EAX em EBX
    xor eax, 200000h
                        ;Alterna bit 21
    push eax                                         ;Empilha EAX
    popfd
                                              ;Desempilha EAX em EFLAGS
    pushfd
                                            ;Empilha EFLAGS
    pop eax
                                          ;Desempilha EFLAGS em EAX
    popfd
                                              ;Restaura EFLAGS
    sti
                                                  ;Ativa interrupções
        and eax, 200000h                          ;Limpa todos os bits, exceto o bit 21
    and ebx, 200000h                         ;em EAX e EBX
    cmp eax, ebx
                                ;Compara EAX e EBX
    je done
                                          ;Se forem iguais, então é um 486
;
; Tivemos sucesso ao alterar o bit ID do processador. Provavelmente é um
; Pentium ou posterior. Mas poderia ser um 486. Por isso, tenha cuidado.
; Para identificar o processador, use o código ID de família informado
; pela instruçao CPUID.
;
       mov eax,1                                        ;Obtém o ID da CPU
        CPUID                                                ;Via instrução CPUID
    and eax, 0F00h
                            ;Limpa todos os bits, exceto os de 8 a 11
    shr eax, 8                                     ;Desloca 8 casas para a direita (EAX=ID família)
    mov dx, offset msg_586             ;Assume Pentium
    cmp eax, 5                                     ;O ID da família é 5?
    je done                                           ;Sim, então é um Pentium
    add al, 30h                                   ;Não é um Pentium,
    mov byte ptr msg_other[5],al  ;então reporta o ID
    mov dx, offset msg_other
        ;da família diretamente
;
; Mostre o tipo de processador e encerre a sessão.
;
       done: mov ah, 09h                         ;Mostra a mensagem
       int 21h                                             ;"É um ..."
       mov ah, 4Ch                                     ;Retorna ao S.O.
       int 21h                                              ;via função 4Ch

main endp
code ends
       end
begin


WG
Powered by WebGlimpse