Minggu, 25 Desember 2016

Belajar Assembly MIPS / PIC32 Dengan MARS Simulator

Prosesor MIPS adalah pioner dari arsitektur prosesor RISC. Ia pernah berjaya di era 90-an di mana industri prosesor sedang gencar-gencarnya melakukan riset. Akan tetapi sekarang ini seperti mulai turun pamornya. Meski demikian MIPS memiliki kelebihan tersendiri, terutama dalam hal kesederhanaannya. Beberapa referensi juga mengatakan bahwa harga jual MIPS di pasaran relatif terjangkau. Tidak hern, di luar sana, MIPS banyak digunakan sebagai bahan riset dan penelitian akademisi dan peneliti. Untuk itu saya mulai tertarik dengan arsitektur prosesor ini.

Kenampakan prosesor MIPS
Grafik market share prosesor

Arsitektur MIPS juga diproduksi oleh industri semikonduktor lain, misalnya Microchip dengan PIC32 nya. Jadi, jika kalian mencoba development board PIC32, misalnya; kalian akan merasakan sensasi yang sama dengan menulis program untuk MIPS. Hal ini sama halnya dengan AMD yang membeli lisensi Intel untuk memproduksi varian prosesor dengan arsitektur serupa Intel. Cukup di sini basa-basinya. Langsung saja kita mulai bahasannya.

Untuk belajar assembly MIPS, saya sarankan menggunakan simulator MARS. Ini lebih baik dari pada praktik langsung dengan komputer asli berinti MIPS. Dengan simulator, kita bisa lebih mudah melacak dan melihat bagaimana nilai tiap register berubah seiring dengan berjalannya instruksi.

mips mars simulator
Download : http://courses.missouristate.edu/KenVollmar/mars/download.htm

Register
Arsitektur RISC umumnya lebih banyak beroperasi dengan register. Oleh karena itu, arsitektur MIPS dibilang arsitektur register-to-register. Jumlah registernya lebih banyak dari arsitektur CISC, namun memiliki jumlah instruksi yang terbatas. Jika dibandingkan dengan Intel, maka akan terlihat perbandingan yang jauh.


Conventional NameUsage
$0$zeroHard-wired to 0. Apapun yang kita baca dari sini akan selalu 0.
$1$atReserved for pseudo-instructions
$2 - $3$v0, $v1Return values from functions. Digunakan sebagai alamat return dalam pemanggilan fungsi/prosedur.
$4 - $7$a0 - $a3Arguments to functions - not preserved by subprograms. Menyimpan argumen fungsi.
$8 - $15$t0 - $t7Temporary data, not preserved by subprograms. Bisa digunakan dengan bebas, untuk keperluan apapun.
$16 - $23$s0 - $s7Saved registers, preserved by subprograms. Bisa digunakan bebas juga, namun setelah digunakan oleh sebuah fungsi, fungsi tersebut harus mengembalikan nilai register ke nilai semula. Kenapa demikian? anda akan tahu nanti.
$24 - $25$t8 - $t9More temporary registers, not preserved by subprograms. Bebas digunakan juga.
$26 - $27$k0 - $k1Reserved for kernel. Do not use. Hanya sistem operasi yang boleh menangani dan menggunakan nilai ini. Sementara, kita abaikan register ini.
$28$gpGlobal Area Pointer (base of global data segment). Untuk menunjuk alamat data area.
$29$spStack Pointer. Untuk menunjuk memori stack.
$30$fpFrame Pointer. Biasanya dimanfaatkan untuk menyimpan nilai $sp saat penanganan fungsi.
Sumber: http://www.cs.uwm.edu/classes/cs315/Bacon/Lecture/HTML/ch05s03.html
Selain register di atas, ada pula register hi dan lo yang berperan dalam operasi perkalian dan pembagian. Semuanya itu adalah register dasar yang harus diketahui. Setelah mengetahui ini, nanti kita akan membahas register coprocessor.






Instruksi
Syntax
INSTRUKSI [operand1], [operand2], [operand3]
Sebuah instruksi dapat ditulis tanpa operand, atau dengan operand hingga maksimal 3 operand. Operand dapat berupa register, nilai konstan (immediate), atau label yang merepresentasikan alamat suatu data.

label:
#komentar
Label diindikasikan dengan titik dua yang mengikuti nama label. Dan, komentar ditulis dengan prefix #.

.word
.set ...
Direktif adalah kode yang menginstruksikan assembler untuk melakukan sesuatu, diawali dengan simbol titik sebelum kode direktif. Untuk melihat dftar direktif, lihat menu Help di MARS.

Format
Sama seperti arsitektur RISC lain, MIPS menyederhanakan eksekusi dengan membatasi ukuran tiap instruksi. Seluruh instruksi di MIPS akan selalui berukuran 32 bit (4 byte). Setiap instruksi akan dijalankan dalan waktu yang sama, yaitu satu siklus waktu CPU. Berbeda dengan arsitektur CISC yang memiliki panjang instruksi dan waktu eksekusi berbeda-beda tiap instruksinya.





Gambar di atas menunjukkan beberapa macam varian format instruksi MIPS. Varian pertama (R) digunakan pada instruksi untuk memproses data dari 3 parameter register. Misalnya instruksi ADDU, SUBU, OR, AND.

addu $t0, $t1, $t2

# ADDU rd,rs, rt
# $t0 = $t1 + $t2)

Opcode (op) ADDU adalah 100001b. Sesuai tabel register di atas, register $t0 bernomor 8 (01000b) berperan sebagai rd, register $t1 bernomor 9(01001b) berperan sebagai rs, dan register $t2 bernomor 9 (01010b) berperan sebagai rt. Nilai shamt 0, nilai ini hanya digunakan untuk instruksi bit shift. Terakhir, instruksi ADDU memiliki nilai variant funct 100001. Dari penjabaran ini, maka diperoleh hasil decode instruksi:
100001 01000 10111 01010 00000 100001

Varian berikutnya adalah varian untuk mengolah data dari register dan nilai immediate (I). Immediate adalah sebutan untuk nilai konstan yang diberikan secara langsung untuk diproses oleh instruksi. Contoh instruksi immediate adalah LUI, ADDI, SUBI, SUBIU, ORI, ANDI.

subiu $t0,$t1,100
# SUBIU rd, rs, immediate
# $t0 = $t1 + 100

Meski MIPS memiliki varian prosesor  berarsitektur 32-bit dan 64-bit, instruksinya terbatas untuk meload instruksi immediate. Dalam instruksi yang mengolah nilai immediate, nilai maksimum yang diperbolehkan hanyalah sebesar 16-bit (0 - 65535). Oleh karena itu, saat ingin meload nilai immediate 32-bit, kita perlu menggunakain instruksi LUI (Load Upper Immediate).

#load nilai 0x00A12B78
lui $t1, 0x00A1
addi $t1, $t1, 0x2B78
# $t1 = 0x00A10000 + 0x00002B78

Terakhir, varian J digunakan untuk instruksi jump dan branching. Target address yang digunakan bersifat relatif terhadap posisi instruksi tersebut. Karena bernilai 26 bit, maka instruksi ini dapat melompat ke instruksi yang jauhnya 33.554.430 byte ke kiri atau ke kanan. Contoh instruksi dalam kelompok ini adalah J, B dan JAL.
label:
...
j label
# J label

Referensi :
- https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats#I_Format
- http://alumni.cs.ucr.edu/~vladimir/cs161/mips.html

Pseudo instruction
Karena keterbatasan instruksi MIPS, beberapa instruksi harus ditulis untuk melakukan satu tahap pekerjaan yang terbilang sederhana, sehingga cenderung terlihat kompleks. Oleh karena itu, MIPS dan prosesor RISC lainnya menyediakan dukungan pseudo instruction pada assemblernya. Beberapa contoh pseudo-instruction antara lain:

Branch if less than (blt)
The blt instruction compares 2 registers, treating them as signed integers, and takes a branch if one register is less than another.
blt $8, $9, label

diterjemahkan menjadi:
slt $1, $8, $9
bne $1, $0, label


Load Immediate (li)
The li pseudo instruction loads an immediate value into a register.
li $8, 0x3BF20

diterjemahkan menjadi:
lui $8, 0x0003
ori $8, $8, 0xBF20


Move (move)
The move pseudo instruction moves the contents of one register into another register.
move $1, $2

diterjemahkan menjadi:
add $1, $2, $0

Load Address (la)
la $a0,address

diterjemahkan menjadi:
lui $at, %hi(address)
ori $a0,$at,%lo(address)

Ayo Belajar
Tips : aktifkan pseudo instruction melalui settings simulator MARS. Untuk melihat daftar instruksi lihat menu Help.

Operasi matematika dasar (pi-po-lon-do) --IYKWIM
Misalnya kita inin menambahkan nilai 100 + 100 instruksinya seperti ini
li $t0, 100
addiu $t0, $t0, 100


Selain ADDIU, ada juga ADDU, ADDI dan ADD. Apa bedanya?
Pada dasarnya semuanya berguna untuk menambah nilai hnya saja terdapat perbedaan behavior pada implementasinya. instruksi yang memiliki mnemonic tambahan U, seperti ADDIU (Add immediate without overflow), akan mengabaikan adanya overflow. Saya belum tahu pada prakteknya seperti apa. Menurut dokumentasi, ketika terjadi overflow akan memicu prosesor untuk menghasilkan exception. Nah, pertanyaannya, apakah sistem operasi akan menangani exception ini, ataukan mengakhiri program yang menghasilkan exception?

Perkalian dan pembagian sedikit berbeda dengan instruksi matematika biasa. Jika menggunakan instruksi pseudo, perkalian cukup sederhana:

mul $t0, $t1, $t2
# $t0 = $t1 x $t2

Sebenarnya, jika diterjemahkan, instruksi perkalian dan pembagian akan melibatkan register hi dan lo. Instruksi non-pseudo berikut akan mengalikan $t0 dan $t1. Lalu, dimanakah hasilnya?
mult $t0,$t1

Hasilnya disimpan pada register lo. Apabila hasil perkalian menghasilkan lebih dari batasan nilai 32 bit, sejumlah 32 bit tertinggi akan disimpan pada register hi. Untuk mengakses kedua register ini kita bisa menggunakan instruksi mfhi, mflo, mthi, mtlo (move from hi, move from lo, move to hi, move to lo).

Untuk instruksi pembagian, perlakukan register hi dan lo sedikit berbeda. Hasil pembagian akan disimpan pada register lo, dan apabila pembagian bersisa, sisa tersebut berada pada register hi.
li $t0,1000
li $t0,10
div $t0,$t1
#simpan hasil ke $t3
mflo $t3
#simpan sisa ke $t4
mfhi $t4



Macam Data dan Cara Mengaksesnya
MIPS mengenal 3 macam data: byte (8 bit), halfword(16 bit) dan word (32 bit). Ingat, MIPS berarsitektur register-to-register, jadi kita tidak bisa langsung mengoperasikan data tersebut, ya. Nilai data tersebut pertama-tama harus diload ke register. Ada beberapa instruksi yang berguna untuk meload dan menyimpan (store) data:
LB (Load Byte)
LH (Load Halw-word)
LW (Load Word)
SB (Store Byte)
SH (Store Half-word)
SW (Store Word)

Untuk mendeklarasikan data, gunakan direktif .byte, .half, atau .word; dengan diawali label sebagai nama data tersebut. Perlu diketahui juga, penempatan instruksi dan data harus terpisah. Dari MARS, tersedia direktif .text sebagai indikasi awal instruksi dan .data sebagai indikasi awal bagian menampung data.

.text
    #load nilai dataA ke $t0, tambah dengan 100
    #hasilnya simpan ke dataB
    lw $t0,dataA
    addiu $t0,$t0,100
    sw $t0,dataB

.data
    dataA:
    .word 100

    dataB:
    .word 0


Jump dan Branch
Instruksi dasar lainnya yang akan dibahas adalah mengenai jump dan branch. Tujuan instruksi ini adalah untuk melompat ke segmen instruksi tertentu. Ada 2 macam instruksi yang perlu diketahui.

Uncoditional jump/branch
Unconditional jump/branch dilakukan secara langsung untuk melompat ke suatu instruksi. Instruksi semacam ini misalnya J, B, JAL, JALR.
main:
    j exit:
    ...

exit:
    ...
 
Conditional branch
Conditional jump adalah instruksi yang bekerja ketika suatu kondisi ditemukan benar. Misalnya BEQ (Branch if Equal), BGEZ (Branch if Greater or Equal to Zero), dll. Selengkapnya lihat menu Help,ya.
main:
    li $t0,1
    li $t1,2
    #lompat ke label 'sama', jika $t0 == $t1
    beq $t0,$t1,sama
beda:
    ...
sama:
    ...


Ternyata instruksi MIPS tidak kalah kerennya dengan instruksi Intel, ya. Yang membuat lebih keren, MIPS tergolong arsitektur RISC, jadi jumlah instruksinya sedikit. Meski jumlah registernya lebih banyak dari CISC, semua registernya mudah diingat, tak masalah.

Mungkin sampai disini dulu belajarnya, nanti disambung lain waktu. Terima kasih sudah membaca. See youu later...

Load disqus comments

0 comments