Składnia

Dyrektywy

Wyróżniamy trzy najważniejsze dyrektywy: .data, .text i .word. Dwie pierwsze (.data i .text) służą do wyznaczenia sekcji kodu i deklaracji zmiennych. Ostatnia (.word) daje możliwość zaalokowania i zainicjalizowania pamięci dla zmiennej. Jeśli chcemy podać wartości w systemie szesnastkowym, to poprzedzamy je "0x".

        .data           ! start a group of variable declarations
x:      .word   23      ! int x = 23;
y:      .word   0x3fce  ! int y = 0x3fce;
z:      .word   42      ! int z = 42;
	    

Rejestry

SPARC dostarcza nam trzydzieści dwa rejestry ogólnego przeznaczenia. Każdy z nich jest 32-bitowy. Rejestry nazywają się następująco:

Litery g, o, l, i łączą rejestry w specjalne grupy (global, output, local, input) o których będzie mowa poźniej.

Ważną rzeczą o której wspomnieć należy już na samym początku jest fakt, że rejestr %g0 (%r0) jest zawsze zerem. Jeśli jakaś instrukcja wykorzysta go jako rejestr przeznaczenia, to wynik zostanie porzucony.

Operacja set

Operacja ta służy do załadowania 32-bitowej liczby całkowitej do wskazanego rejestru.

	       set 0x42, %r2
	       set x, %r3
	    

Operacja pierwsza załaduje wartość 0x42 do rejestru %r2. Druga natomiast do rejestru %r3 wprowadzi adres zmiennej x.

SPARC przyjął następującą składnie dla instrukcji: rejestr podany na końcu jest rejestrem przeznaczenia, a wszystkie wcześniejsze są argumentami tej instrukcji.

Operacja load i store

Bardzo charakterystyczną cechą SPARC jest to, że opiera się on na architekturze load/store. Oznacza to, że WSZYSTKIE operacje na danych muszą odbywać się w rejestrach.

W szczególności oznacza to, że jeśli w dwóch rejestrach mamy adresy do liczb, to nie możemy ich tak po prostu dodać. Najpierw trzeba korzystając z instrukcji load(ld) przepisać te liczby do wolnych rejestrów, wykonać obliczenie, a na koniec za pomocą instrukcji store(st) wysłać wynik w odpowiednie miejsce w pamięci.

	       ld [%r2], %r3  ! do rejestru %r3 wpisujemy to co znajduje się pod adresem w %r2
	       st %r3, [%r4]  ! zawartość %r3 wysyłamy do pamięci wskazywanej przez %r4
	    

Dodawanie i odejmowanie

SPARC dostarcza nam dwie instrukcje dla każdej z tych operacji. Obydwie jako pierwszy argument i przeznaczenie przyjmują rejestr, ale jako drugi argument mogą przyjmować zarówno rejestr, jak i liczbę (small constant value - oznacza to, że jej reprezentacja musi się zmieścić w 13-tu bitach). Obliczenia są przeprowadzane w arytmetyce 32-bitowej.

Poniższy przykład oblicza następujące wyrażenie: a = (a+b) - (c-d).

        .data
a:      .word   0x42
b:      .word   0x43
c:      .word   0x44
d:      .word   0x45
        .text
start:  set     a, %r1
        ld      [%r1], %r2       ! $a$ --> %r2
        set     b, %r1
        ld      [%r1], %r3       ! $b$ --> %r3
        set     c, %r1
        ld      [%r1], %r4       ! $c$ --> %r4
        set     d, %r1
        ld      [%r1], %r5       ! $d$ --> %r5

        add     %r2, %r3, %r2    ! $a+b$ --> %r2
        sub     %r4, %r5, %r3    ! $c-d$ --> %r3
        sub     %r2, %r3, %r2    ! $(a+b)-(c-d)$ --> %r2
        set     a, %r1
        st      %r2, [%r1]       ! $(a+b)-(c-d)$ --> a
end:    ta      0
	    

Operacja mov

Operacja ta umożliwia przeniesienie wartości przechowywanej w jednym rejestrze, do drugiego. Ma ona prostą postać:

	      mov %r1, %r2 ! przeniesienie wartości z %r1 do % r2
	      mov 5, %r2 ! robi to samo co set 5, %r2
	    

Rejestry warunkowe i rozgałęzienia

Rejestry warunkowe w SPARC składają się z czterech bitów: Z(zero), N(negative), C(carry), V(overflow). Standardowe operacje arytmetyczne nie zmieniają tych flag. Istnieje natomiast specjalny zestaw operacji służący ich ustawianiu (m.in. cmp - compare)

Korzystając z tych flag możemy poruszać się po kodzie. Służą do tego operacje nazywane Branch (w INTEL-u to po prostu Jump) Podstawowe z nich to ba - branch always; be - branch if equal, bg - branch if greater.