Popis některých rysů programování procesorů Alpha v assembleru.


1. Kódování instrukcí

Při programování je nutné vzít v úvahu skutečnost, že Alpha je procesor RISC. Některé důsledky této skutečnosti lze shrnout do následujících bodů:

V registrové sadě je celkem 32 registrů pro celočíselné operace, označených $0 až $31. Registr $31 je "dummy register" - při čtení obsahuje 0, při zápisu se jeho obsah nemění. Ostatní registry jsou v podstatě rovnocenné, ale assembler a další překladače předpokládají jejich standardní využití. 12 registrů je určeno pro mezivýsledky a podobně, 6 dalších registrů je také určeno pro mezivýsledky - v procedurách jsou ukládány, 6 registrů slouží pro předávání argumentů do volané procedury, $26 obsahuje v proceduře návratovou adresu, $29 je "global pointer" pro adresování dat v paměti, $30 slouží jako stack pointer.

Při překladu nahrazuje překladač některé mnemonické kódy jinými instrukcemi se stejným výsledkem (tzv. pseudoinstrukce). Například instrukci

mov   $1,$2

pro přesun dat z 1 do 2 nahradí strojovou instrukcí

bis $1,$1,$2      .

(Instrukce mov vůbec není v souboru strojových instrukcí).

Některé mnemonické instrukce instrukce jsou vlastně makra - při překladu se mahradí několika instrukcemi ve strojovém kódu. Příklad lze najít v souboru program_1.s . Po jeho překladu dostaneme binární soubor, který lze zavést do paměti a prohlížet pomocí debuggeru dbx. Provedeme-li dump paměti ve formátu instrukcí (viz manuálové stránky dbx), lze prozkoumat způsob překladu jednotlivých instrukcí.

Pozn.: dbx používá pro označení registrů symboly r0, r2, ..., r31. Některé registry mají navíc v různých situacích další "alias", např $30 je sp nebo také $sp apod.

Proměnná var1 je definována v sekci .sdata, do které je v průběhu výpočtu možný přístup pomocí "global pointer" registru $29 (alias gp alias $gp). Proto je instrukce

ldl   $1,var1

přeložena jako

ldl   $1,-32768(gp)       .

Proměnná var2 je definována v sekci .data. Tato sekce svým umístěním v paměti nezaručuje možnost adresování pomocí gp. Proto je instrukce

ldl   $2,var2

přeložena do dvou instrukcí strojového kódu:

ldah  $2,-1(gp)
ldl    $2,32656($2)  
     .

První z nich uloží do $2 adresu proměnné var2 (resp. adresu sekce .data. Tato adresa je uložena v tzv. GOT - Global Offset Table, přístupné pomocí gp), druhá instrukce tuto adresu použije ke čtení var2 z paměti.

Podobně se překládají i instrukce sdl.

Dále je v programu vidět způsob překladu skokové instrukce. Původní instrukce

jmp   lab1

je přeložena jako relativní (vzhledem k PC) skok (tzv. branch). Protože instrukce vždy ukládá návratovou adresu do určeného registru, je v tomto případě jako registr pro uložení návratové adresy použit "dummy" registr $31:

bsr   $31,main+0x38(line 22)      .

Adresa main+0x38 je adresa cíle v symbolickém tvaru. Ve strojovém kódu má tato instrukce kód 0xD3E00002. 00002 je hodnota, která se po vynásobení konstantou 4 přičítá k PC (tedy 00002 znamená zvětšení PC o 8, tj. přeskočení 2 následujících instrukcí).

Instrukce

bis $31, $31, $31     ,

která se ve strojovém kódu několikrát objevuje, je generována překladačem místo instrukce nop.

K dispozici je zdrojová forma programu program_1.s a kopie okna debuggeru dbx s dumpem paměti ve formátu symbolických instrukcí.

Dále je k dispozici popis procesorů Alpha. a manuál Assembly Language Programmer's Guide pro programování v assembleru.


2. Volání procedur

Při volání procedur se doporučuje zachovávat konvence používané při překladu programů z jazyka C. Tyto konvence jsou ovšem poměrně komplikované a překladačem podle konkrétní situace různě upravované za účelem zvýšení efektivity programu (různé stupně optimalizace). Doporučovaný postup při psaní procedury v assembleru je napsat nejprve tuto proceduru v C a přeložit ji (gcc s volbou -S) do assembleru. Takto získanou proceduru v assembleru lze potom podle potřeby upravovat při zachování jejího prologu a epilogu.

Několik základních pravidel pro prolog procedury lze shrnout do následujících bodů:

  1. Vstupní bod procedury se definuje direktivou
             .ent
  2. Instrukcí ldgp gp,0($27) se naplní registr gp adresou ukazující do datového segmentu.
  3. Ukazatel zásobníku sp (je to ve skutečnosti registr $30) se posune o potřebnou velikost (framesize). Ta je dána součtem prostoru potřebného pro uložení lokálních proměnných, ukládaných registrů a případně pro argumenty dalších volaných funkcí (prvních 6 argumentů se předává v registrech).
  4. Pro potřeby debuggeru atd. by měla být v prologu direktiva
              .frame
    s příslušnými parametry (viz manuál).
  5. Pokud procedura používá některé z ukládaných registrů, musí se tyto uložit do zásobníku instrukcí stq (Alpha nemá instrukce push a pop, pro práci se zásobníkem se používají instrukce typu ldx a stx). Ukládané registry se vyznačí pomocí direktivy
                .mask .
  6. Konec prologu se označí direktivou
                .prologue          .

Postup při volání funkce lze sledovat např na programu program_2.c. Jeho překladem do assembleru je vytvořen soubor program_2.s, který demostruje výše uvedená pravidla. Podrobnosti lze najít v Assembly Language Programmer's Guide.


Poslední změna stránky byla provedena 12.12.2001