Na FreeHostingu Endora běží desítky tisíc webů. Přidejte se ještě dnes!

Vytvořit web zdarma

Na FreeHostingu Endora běží desítky tisíc webů. Přidejte se ještě dnes!

Vytvořit web zdarma

int21h

Pouit MMX v Turbo pascalu

Vtinou tu pu o Freepascalu, protoe programuji astji v nm a je mnohem modernj. Jene hodn lid zstalo z rznch dvod u starho Turbo pascalu a nebylo by fr je opomjet.
Bohuel jedno z omezen TP je, e jeho vestavn assembler zn pouze instrukce procesoru 286. Instrukce pozdjch procesor musme zapisovat pomoc strojovho kdu. Toto je hlavn dvod, pro programtoi v TP tak mlo pouvaj modern instrukn sady, jako je napklad sada MMX. Vce informac o MMX najdete jinde, jako dobr vchoz bod je nae sekce odkazy. Vhodn pouit tchto instrukc drasticky urychl vae programy. J vm uku jenom koprovn pamti a vyplovn pamti. MMX toho um mnohem vc, ale toto je asi nejpotebnj.
Podvejme se tedy na nhradu procedury Move
Procedure MoveMMX(var odkud; var kam; kolik:word);assembler;
asm
push ds
lds si,odkud
les di,kam
    mov dx,kolik
    shr dx,3
@znovu:
    db 0fh;db 6fh;db 0ch         {MovQ mm1,[si]}
    db 26h;db 0fh;db 7fh;db 0dh  {MovQ es:[di],mm1}
    add si,8
    add di,8
    dec dx
  jnz @znovu
db 0fh;db 77h                    {emms}
pop ds
end;
Vidte, e kopruju osm bajt najednou. Jasn, pokud koprujete pes FPU, tak jich koprujete najednou 16, ale FPU pracuje pomaleji, take to nen rychlej.
Kritick msto se d zapsat jedin ve strojovm kdu :-( nicmn do komente jsem napsal assemblerovsk pepis. A nakonec si vimnte, e na konci procedury volm instrukci EMMS, kter uklid stavov registr MMX a opt umon pracovat s desetinnmi sly. Jednotka pro MMX a FPU toti sdlej stejn obvody a jejich instrukce nelze mchat - mezi MMX instrukc a FPU instrukc mus bt vdy instrukce EMMS. Na prvnch MMX procesorech byla mimochodem dost pomal, na modernch CPU ovem trv jenom pr takt a u nezpomaluje.
Procedurka je to jednoduch ale nee ppadn pesuny blok, jejich dlka nen nsobkem osmi. Proto je vhodn proceduru troku rozit:
Procedure MoveMMX(var odkud; var kam; kolik:word);assembler;
asm
push ds
lds si,odkud
les di,kam
    mov dx,kolik
    mov cx,dx
    shr dx,3
    and cx,7
    cmp dx,0
    jz @malykus
@znovu:
    db 0fh;db 6fh;db 0ch         {MovQ mm1,[si]}
    db 26h;db 0fh;db 7fh;db 0dh  {MovQ es:[di],mm1}
    add si,8
    add di,8
    dec dx
  jnz @znovu
db 0fh;db 77h                    {emms}
@malykus:
rep movsb           {dodela pripadny zbytek}
pop ds
end;
Tmto mete zcela nahradit standardn Move.
O mlo sloitj je MMX varianta procedury FillChar. Pu sem rovnou variantu, kter oet bloky nedliteln osmi.
Procedure FillCharMMX(var kam;kolik:word;ceho:byte);assembler;
asm
    mov al,ceho
    mov ah,al
    mov bx,ax
    db 66h;shl ax,16
    mov ax,bx
    db 0fh;db 6eh;db 0c8h              {MovD mm1,eax}
    db 0fh;db 6eh;db 0d0h              {MovD mm2,eax}
    db 0fh;db 73h;db 0f1h;db 20h       {Psllq mm1,32}
    db 0fh;db 0ddh;db 0cah             {Paddusw mm1,mm2}
    mov dx,kolik
    mov cx,dx
    shr dx,3
    and cx,7
    cmp dx,0
    jz @malykus
les di,kam
@znovu:
    db 26h;db 0fh;db 7fh;db 0dh        {MovQ es:[di],mm1}
    add di,8
    dec dx
  jnz @znovu
db 0fh;db 77h                          {emms}
@malykus:
rep stosb
end;
Procedura je sloitj tm, e parametr Ceho musme naped rozkoprovat na 16 a poslze na 32 bit a umstit ho do EAX. Jene MMX registry nejsou 32-bitov, ale 64-bitov, take musme jet uvnit MMX registr hodnotu rozkoprovat na 64-bit. Vidte, e se to dl stejnm postupem, ale pomoc MMX ekvivalent instrukc SHL(psllq) a ADD(paddusw)

Problm je v tom, e je dost dobe mon, e uivatelv pota instrukce MMX nezn. Znm adu lid, kte doma maj dva potae. Na novm nadupanm PC maj windows XP a hraj nejmodernj hry a na starm maj DOS nebo windows 9x a hraj tam star vci a v neposledn ad na takovchto strojch pouvaj pascal. Nejjednodum eenm je, se uivatele prost zeptat, jestli jeho maina MMX podporuje. Zodpovdnost nechat na uivateli. Podle toho, co odpov nastavme procedurln promnnou buto na MoveMMX nebo na standardn Move (nebo na MoveFPU i Move32)
Nen to ale pli profesionln, take meme zkusit podporu MMX detekovat.
K tomu mme instrukci CPUID. Turbo pascal ji samozejm nezn, take ji musme zapsat ve strojovm kdu. Jene je to to sam. Instrukci CPUID podporuj jen procesory pentium a nkter 486. Take musme naped detekovat, zda pota zn CPUID. Ale aspo plat, e jestli nezn CPUID, tak urit nezn ani MMX.
Function Test_CPUID:boolean;
{zjisti, zda pocitac instrukci CPUID vubec podporuje}
begin
inline($66/$9C/$66/$58/$66/$0F/$BA/$E0/$15/$0F/$92/$C2/$66/$0F/$BA/$F8/$15/$66/$50/$66/$9D/
       $66/$9C/$66/$58/$66/$0F/$BA/$E0/$15/$0F/$92/$C1);
{PushfD
Pop eax
    Bt eax,21
    Setc dl
    Btc eax,21
Push eax
PopfD
PushfD
Pop eax
    Bt eax,21
    Setc cl}
asm
    Mov ax,0
    Cmp dl,cl
  Je @konec
    inc ax
@konec:
end;
end;
Tady u hodn pituhlo. Ds hrza a utrpen. Vn nechcete pejt na Freepascal? :-/
Kdy u se jednou budeme pachtit s instrukc CPUID, tak pro nevyut jej pln potencil a nedetekovat dky n vechno co se d?
Definujme si typ CPU_type, ve kterm budeme mt vechny informace vrcen instrukc CPUID.
type CPU_type = record
     Vendor       : String[13];
     CPUID        : String;
     Stepping_ID  : Byte;
     Modellnumber : Byte;
     generace     : Byte;
     MMX          : Boolean;
     FPU          : Boolean;
     CMOV         : Boolean;
     _3DNOW       : Boolean;
     End;

A slben procedura Get_CPU je zde:
Function Get_CPU(cpu:cpu_type):Boolean;
var      argument  : longint;
         a,p1,p2,p3     : longint;
         CPUResult    : Byte;
         VendorString : Array[0..11] of Char;
         p:Pchar;
Begin
CPU.Vendor    := 'neznamy';
CPU.CPUID     := 'neznama generace procesoru';
cpu.modellnumber:=$FF;
cpu.stepping_ID:=$FF;
cpu.mmx:=false;
cpu.fpu:=false;
cpu.cmov:=false;
cpu._3dnow:=false;
if test_cpuid=false then begin cpu.generace:=3;Exit;end; {nezna CPUID - nejsme asi na pentiu}
asm
db 66h;xor si,si
db 66h;xor ax,ax        { dotaz na nejvyssi mozny argument do EAX - nevidim v tom smysl }
db 0fh;db 0a2h  {CPUID}
db 66h;mov argument.word,ax       { nejvyssi mozny argument EAX - zde nevyuzito }

db 66h;mov p1.word,bx
db 66h;mov p2.word,dx
db 66h;mov p3.word,cx

mov ax,8000h;db 66h;shl ax,16;mov ax,1  {mov eax,80000001h, rozsirene info CPUID}
db 0fh;db 0a2h                          {CPUID}
db 66h;db 0fh;db 0bah;db 0e2h;db 1fh    {Bt edx,31 - 3Dnow?}
db 0fh;db 92h;db 0c0h;                  {setb al}
or al,al
jz @dale1
inc al;mov cpu._3dnow,al
@dale1:

db 66h;xor ax,ax;inc ax                 {mov eax,1}
db 0fh;db 0a2h                          {CPUID}
db 66h;push ax                          {push eax}
db 66h;db 0fh;db 0bah;db 0e2h;db 17h    {Bt edx,23 - MMX?}
db 0fh;db 92h;db 0c0h;                  {setb al}
or al,al
jz @dale2
inc al;mov cpu.mmx,al
@dale2:

db 66h;db 0fh;db 0bah;db 0e2h;db 00h    {Bt edx,0 - FPU?}
db 0fh;db 92h;db 0c0h;                  {setb al}
or al,al
jz @dale3
inc al;mov cpu.fpu,al
@dale3:

db 66h;db 0fh;db 0bah;db 0e2h;db 0Fh    {Bt edx,15 - cMov?}
db 0fh;db 92h;db 0c0h;                  {setb al}
or al,al
jz @dale4
inc al;mov cpu.cmov,al
@dale4:

db 66h;pop ax                           {pop eax}
db 66h;mov bx,ax                        {mov ebx,eax}
And ax,1111b                                         { Stepping_Id }
mov CPU.Stepping_Id,al
db 66h;mov ax,bx                        {mov eax,ebx}

db 66h;shr ax,4                         {shr eax,4}  { Modellnumber }
and ax,1111b
mov CPU.Modellnumber,al
db 66h;mov ax,bx                        {mov eax,ebx}

db 66h;shr ax,8                         {shr eax,8}  { generace }
and ax,1111b
mov CPU.generace,al
end;
case CPU.generace of
  0..2   : CPU.CPUID:= 'Neznama generace procesoru';
  7      : CPU.CPUID:= 'Neznama generace procesoru'; {mozna, mozna Pentium4}
  3      : CPU.CPUID:= '80386';
  4      : CPU.CPUID:= '80486';
  5      : CPU.CPUID:= 'Pentium (TM)';
  6      : CPU.CPUID:= 'Pentium Pro/II/III';
end;
p:=@cpu.vendor;
p^:=#12;inc(p);
move(p1,p^,4);inc(p,4);
move(p2,p^,4);inc(p,4);
move(p3,p^,4);
end;
Pro pochopen tto procedury si nkde najdte popis instrukce CPUID. Krom toho se tu zase opakuje martyrium s pepisem instrukc do strojku.
Zajmav je zjitn vrobce procesoru. V poli vendor budete mt buto GenuineIntel pro procesory od Intelu nebo AuthenticAMD od AMD nebo nco jinho od jinch vrobc.
A to je ve. Strojovmu kdu zdar! marj noho.
:-/
2006-11-30 | Laaca