TEKNIK ELEKTRO ITB
Modul Praktikum Arsitektur Sistem Komputer ‐ I EL3110
2012
Modul Ini telah direvisi dan dilengkapi oleh : Andri Haryono (Teknik Elektro 2006) Frillazeus Goltha (Teknik Elektro 2006) Niko Robbel (Teknik Elektro 2006) Ardianto Satriawan (Teknik Elektro 2007) Gilang Ilham (Teknik Elektro 2007) Muhammad Johan A (Teknik Elektro 2007) Umar Abdul Aziz (Teknik Elektro 2007) Tommy Gunawan (Teknik Elektro 2008)
2
PETUNJUK PRAKTIKUM ARSITEKTUR KOMPUTER I KOMPOSISI NILAI Buku Catatan Laboratorium (BCL)
: 20%
PRAKTIKUM
: 40 %
Ada 6 percobaan dengan bobot 40% dari total penilaian. berikut nilai tiap percobaan (total 100%). NILAI AKTIVITAS PRAKTIKUM
: 35 %
SOURCE CODE
: 40 %
NILAI TEST AKHIR
: 25%
LAPORAN
: 40%
TOLERANSI KETERLAMBATAN 15 MENIT Keterlambatan lebih dari 15 menit (berdasarkan jam di lab) tidak diperbolehkan masuk ke lab.
3
Petunjuk Pembuatan Laporan 1. Laporan hanya terdiri atas identitas praktikan, abstrak, data praktikum, analisis, dan kesimpulan. Lampiran dan hal lainnya disertakan bila diperlukan. Format terlampir 2. Ketika melampirkan gambar terminal/command terminal/command promt berwarna putih.
prompt,
pastikan
background
3. Gunakan font courier new pada kode program yang dilampirkan. #define int accum = START_VAL;
START_VAL
0
int sum(int x, int y) { int t = x + y; accum += t; return t; } 4. Hapus folder pekerjaan Anda setiap selesai menggunakan komputer. 5. Disarankan mencoba praktikum terlebih dahulu di rumah.
4
Bahasa C
5
PRAKTIKUM ARSITEKTUR KOMPUTER MODUL 1 KOMPILASI DAN DISASSAMBLE PROGRAM
TUJUAN Memahami tahap‐tahap kompilasi dari bahasa tingkat tinggi hingga diperoleh file eksekusi. Memahami cara memeriksa suatu program berbasis bahasa assembly.
ALAT PERCOBAAN Personal Computer – PC. Compiler GCC pada Operating System
DASAR TEORI Sistem Kompilasi Suatu program akan mudah dibaca dan dimengerti oleh manusia jika ditulis dalam bahasa tingkat tinggi, seperti high‐level C program. Tetapi, agar program dapat dijalankan pada sistem komputer, maka setiap baris pernyataan pada C harus diterjemahkan oleh suatu program lain menjadi urutan instruksi bahasa mesin tingkat rendah. Instruksi‐instruksi tersebut kemudian dikemas dalam suatu bentuk yang disebut executable object program dan disimpan dalam file biner. Langkah‐langkah menerjemahkan baris‐baris kode program pada C menjadi file eksekusi dilakukan dalam empat langkah meliputi pre‐processor, compiler, assembler, dan linker, yang seluruhnya disebut sistem kompilasi. program.c Source program (text)
Preprocessor (cpp)
program i Modified Source program (text)
Compiler (ccl)
program.s Assembly program (text)
Assembler (as)
program.o Relocatable object program (binary)
Linker (ld)
program Executable object program (binary)
Misalkan kita menulis program C dalam dua file p1.c dan p2.c. Kemudian kita mengkompilasi kode program tersebut dengan mengetikkan command line : $ gcc –O2 –o prog p1.c p2.c Perintah gcc merupakan compiler default pada Linux yang menggunakan GNU C Compiler. Secara sederhana kita juga dapat menggunakan perintah cc. Flag –O2 memerintahkan compiler untuk melakukan optimasi tingkat‐2. Secara umum, jika tingkat optimasi meningkat maka program akan berjalan lebih cepat, tetapi hal ini beresiko meningkatkan waktu kompilasi dan meningkatkan 6
kesulitan ketika melakukan debugging kode program. Optimasi tingkat‐2 merupakan kompromi yang baik antara kinerja optimasi dan kemudahan debugging. Flag –o memerintahkan compiler untuk memberi nama file eksekusi yang dihasilkan dengan nama prog. Perintah gcc di atas menerjemahkan kode program menjadi file eksekusi dengan melalui empat langkah. Pertama C pre‐processor akan memproses semua preprocessor directive, misalnya #define, atau memasukkan isi file‐file yang tertulis #include directive ke kode program. Kedua, compiler menghasilkan kode assembly untuk setiap file, menjadi p1.s dan p2.s. Selanjutnya, assembler mengkonversi kode assembly menjadi file kode objek biner p1.o dan p2.o. Terakhir, linker menggabungkan kedua file kode objek dengan kode‐kode yang mengimplementasikan fungsi‐ fungsi library Unix standar (mis. printf) dan menghasilkan file eksekusi. Untuk hanya melakukan preprocessing, kita dapat menggunakan opsi “-E” pada command line : $ gcc –E p1.c Untuk melihat kode assembly yang dihasilkan oleh compiler C, kita dapat menggunakan opsi “-S” pada command line : $ gcc –O2 –S p1.c Perintah ini akan menyebabkan compiler hanya menghasilkan file assembly p1.s dan tidak melakukan langkah berikutnya. Kode assembly yang dihasilkan sesuai dengan format GAS (“Gnu Assembler”). Jika pada command line digunakan opsi “-c”, maka GCC akan melakukan ‘compile’ dan ‘assemble’ kode program : $ gcc –O2 –c p1.c Perintah ini akan menghasilkan file kode object p1.o, dalam bentuk format biner dan tidak dapat dilihat secara langsung. Untuk memeriksa isi dari file kode objek, terdapat suatu program yang bernama disassembler. Program tersebut dapat melakukan konversi file kode objek menjadi format assembly. Pada sistem Unix/Linux, program OBJDUMP (singkatan dari “OBJect DUMP”) dapat dipanggil menggunakan flag “-d” : $ objdump –d p1.o Untuk menghasilkan kode yang dapat dieksekusi, kita harus menjalankan linker pada seluruh file kode objek. Program eksekusi akan dihasilkan dengan menggabungkan seluruh file kode objek pada command line : $ gcc –O2 –o prog code.o main.c File program eksekusi prog yang dihasilkan berisi tidak hanya kode yang kita masukkan, tetapi juga informasi yang digunakan untuk memulai dan mengakhiri program. Kita juga dapat melakukan dissasamble file prog : $ objdump –d prog Disassembler akan mengekstrak berbagai urutan kode yang terdapat pada file eksekusi prog.
7
PERCOBAAN Percobaan 1 : 1. Buat direktori baru dengan NIM Anda. 2. Buat kode program berikut dengan menggunakan teks editor. #define START_VAL 0 int accum = START_VAL; int sum(int x, int y) { int t = x + y; accum += t; return t; }
Simpan kode program tersebut dengan nama code.c dalam direktori yang telah Anda buat tadi.
Percobaan 2 : 1. Preprocess code.c dan lihat hasilnya : $ gcc –E code.c 2. Compile code.c untuk menghasilkan kode assembly : $ gcc –O2 –S code.c 3. Compile dan assemble code.c untuk menghasilkan file kode objek : $ gcc –O2 –c code.c 4. Compile dan assemble akan menghasilkan object code. Apa sebetulnya object code ini? Bagaimana komputer menyimpannya sebagai file? 5. Agar dapat diperoleh program eksekusi, diperlukan adanya fungsi main pada salah satu file kode objek‐nya. Buatlah file baru dan beri nama main.c. 6. Compile seluruh kode untuk menghasilkan program eksekusi. Beri nama program eksekusi tersebut prog. $ gcc –O2 –o prog code.c main.c 7. Bagaimana caranya agar pada main.c variabel accum dan fungsi sum() dapat digunakan? Beri penjelasan! 8. Buka file code.s dan code.o dengan teks editor. Beri komentar.
8
Percobaan 3 : 1. Lakukan disassembler pada file kode objek, code.o. $ objdump –d code.o Apa fungsi opsi ‘–d’ pada command line disassembler ? 2. Lakukan disassembler pada file program eksekusi, prog. $ objdump –d prog 3. Bandingkan hasil disassembler file kode object dan file prog. Percobaan 4 : 1. Lakukan kompilasi (seperti percobaan 2) dan disassembler (seperti percobaan 3) dengan tingkat optimasi yang berbeda, yaitu dengan opsi –O1. 2. Bandingkan kode assembler yang dihasilkan antara tingkat optimasi –O1 dengan tingkat optimasi –O2 seperti yang dilakukan pada percobaan 2 dan 3. 3. Bagaimana dengan -O3 dan -Os? 4. Bagaimana pengaruh tingkat optimasi yang berbeda terhadap size dan speed (terutama antara O2 dan -O3)?
Percobaan 5 : 1. Buat kode program berikut dengan menggunakan teks editor. #include "text.h"
void main() { test(); }
Simpan kode program tersebut dengan nama main_text.c dalam direktori yang telah Anda buat tadi.
2. Buat kode program berikut dengan menggunakan teks editor. #include <stdio.h> #include "text.h"
9
void test() { printf("Arsitektur Komputer I !\n"); } Simpan kode program tersebut dengan nama text.c dalam direktori yang telah Anda buat tadi.
3. Buat kode program berikut dengan menggunakan teks editor. #ifndef TES_H #define TES_H 100
void test();
#endif Simpan kode program tersebut dengan nama text.h dalam direktori yang telah Anda buat tadi.
4. Buat makefile berikut dengan menggunakan teks editor. all: coba
coba: main2.o coba.o gcc main2.o coba.o -o coba
main_text.o: main_text.c gcc -c main_text.c
text.o: text.c 10
gcc -c text.c
Simpan kode program tersebut dengan nama makefile dalam direktori yang telah Anda buat tadi.
5. Jalankan perintah make pada command prompt (NB: Atur terlebih dahulu working direktori Anda pada direktori yang Anda buat tadi). 6. Perhatikan! Apa yang terjadi? Beri komentar. 7. Sekarang edit kode program text.c yang telah Anda buat tadi menjadi: #include <stdio.h> #include "text.h"
void test() { printf("TES_H = %d\n",TES_H); }
8. Ulangi langkah 5 dan 6.
TUGAS Buat program fibonacci sederhana, yaitu program yang akan mengeluarkan deret seperti berikut ini 1, 1, 2, 3, 5, 8, 13, … Jumlah deret diinputkan oleh user melalui keyboard. Misal n = 4 akan keluar deret 1, 1, 2, 3. Program terdiri dari dua file C yaitu fibo.c dan inputn.c. inputn.c akan mengatur masalah input n yang dimasukkan dan fibo.c akan menghitung nilai berdasarkan input n. buatlah makefile yang akan mengkompilasi program ini. Lampirkan semua kode yang dibuat pada Lampiran Laporan.
11
PRAKTIKUM ARSITEKTUR KOMPUTER MODUL 2 REPRESENTASI DAN MANIPULASI LEVEL BIT
TUJUAN Memahami representasi informasi pada level bit Melatih melakukan manipulasi informasi pada level bit
ALAT PERCOBAAN Personal Computer – PC Software compiler C misalnya MinGW atau GCC
DASAR TEORI Bahasa pemrograman C mendukung operasi Boolean level bit. Simbol yang biasa digunakan untuk melakukan operasi Boolean pada C adalah : | untuk OR, & untuk AND, ~ untuk NOT, dan ^ untuk EXCLUSIVE‐OR. Operasi‐operasi ini dapat dilakukan pada berbagai tipe data, seperti char, int, short, long atau unsigned. Pada operasi logika, C juga mendukung dengan simbol : || untuk operasi logika OR, && untuk operasi logika AND, dan ! untuk operasi logika NOT. Operasi ini mudah tertukar dengan operasi Boolean level bit, tetapi sebenarnya kedua operasi ini sangat berbeda. Pada operasi logika, setiap argumen yang bukan nol merepresentasikan TRUE, sementara argumen nol (0) merepresentasikan FALSE. Fungsi logika mengembalikan nilai 1 dan 0, yang mengindikasikan TRUE dan FALSE. Selain operasi Boolean dan operasi logika, terdapat juga operasi shift. C dapat melakukan operasi shift pada level bit ke kiri dan ke kanan. Pada umumnya, seluruh mesin dapat mendukung dua bentuk operasi right shift : logical dan arithmetic. Logical right shift mengisi sisi paling kiri dengan bit 0, sementara arithmetic right shift mengisi sisi paling kiri dengan bit tanda yang direpresentasikan pada MSB.
PERCOBAAN Pada percobaan ini anda diminta untuk membuat 10 buah fungsi yang berhubungan dengan representasi dan manipulasi informasi pada level bit. Setiap fungsi harus dilengkapi dengan fungsi main dan dikompilasi hingga diperoleh file eksekusi‐nya. Penilaian dilakukan berdasarkan kebenaran dari program serta efisiensi penggunaan kode. Persiapan lingkungan kerja : Pindah ke direktori kerja anda (nama direktori sama dengan NIM anda). Simpan seluruh program anda pada direktori tersebut. 12
Fungsi 1 : bitXor(x,y) Buat fungsi yang memiliki perilaku serupa dengan operasi ^. Operator yang boleh digunakan hanya & dan ~. Contoh : bitXor(4,5) = 1 Prototype fungsi : int bitXor(intx, int y) Fungsi 2 : oddBits(void) Fungsi evenBits memberikan nilai return satu word, dimana seluruh bit ganjil diset menjadi 1. Setiap bit pada satu word diberi nomor dari 0 (LSB) hingga 31 (MSB). Prototype fungsi : int oddBits(void) Fungsi 3 : getByte(x,n) Fungsi getByte mengekstrak byte n dari word data x. Urutan byte dalam word diberi nomor dari 0 (LSB) hingga 3 (MSB). Contoh : getByte(0x12345678,1) = 0x56 Prototype fungsi : int getByte(int x, int n) Fungsi 4 : bitMask(highbit,lowbit) Fungsi bitMask menghasilkan suatu mask dimana seluruh bit antara highbit dan lowbit diset menjadi 1, dan bit sisanya diset menjadi 0. Asumsi 0 <= lowbit <= 31 dan 0 <= highbit <= 31. Jika lowbit > highbit, mask seluruhnya 0. Contoh : bitMask(5,3) = 0x38 Prototype fungsi : int bitMask(int highbit, int lowbit) Fungsi 5 : reverseBytes(x) Fungsi reverseBytes membalikkan urutan byte dari input word dengan menukar byte 0 dengan byte 3, byte 1 dengan byte 2. Urutan byte pada word berurutan dari 0 (LSB) hingga 3 (MSB). Contoh : reverseBytes(0x01020304) = 0x04030201
13
Prototype fungsi : int reverseBytes(int x) Fungsi 6 : tmax(void) Fungsi tmax mengembalikan nilai two’s complement integer terbesar. Prototype fungsi : int tmax(void) Fungsi 7 : minBytes(x) Fungsi minBytes menghitung nilai dari byte data pertama dikurangi byte data kedua. Sistem bilangan negaif yang digunakan adalah two’s complement. Tidak boleh menggunakan operator pengurangan (‐), hanya boleh menggunakan penambahan (+) dan invers (~). Contoh : minBytes(0x15,0x07) = 0x0E Prototype fungsi : int minBytes(int x, int y) Fungsi 8 : shiftRegister(x) Fungsi untuk memasukkan data berdasarkan fungsi shift register pada sistem digital. Asunsi jumlah bit adalah 32 bit, dan setiap nilai yang dimasukkan adalah 5 bit. Nilai awal register adalah 0x00000000. Contoh : shiftRegister(0x04)= 0x00000004
(dlm biner 0x...0000000100)
shiftRegister(0x13)= 0x00000093
(dlm biner 0x...0010010011)
ket : input sebelumnya berpengaruh pada nilai sekarang. Prototype fungsi : int shiftRegister (int x) TUGAS
Buatlah sebuah program enkripsi sederhana yang berfungsi untuk menyamarkan 9 digit angka. Enkripsi yang akan dibuat adalah dengan melakukan operasi XOR setiap 8 bit dari 32 bit input dengan sebuah angka desimal 8 bit. Contoh : Input angka 123456789 (00000111 01011011 11001101 00010101), angka desimal untuk enkripsi 85. Maka output hasil enkripsi adalah 1376688192 (01010010 00001110 10011000 01000000). Input 9 digit angka dan angka desimal untuk mengenkripsi merupakan input keyboard. Buat juga program untuk dekripsinya! Buatlah makefile yang akan mengkompilasi program ini.
14
PRAKTIKUM SISTEM KOMPUTER MODUL 3 POINTER DAN ARRAY
TUJUAN Memahami konsep array, pointer dan alokasi memori Melatih penggunaan array dan pointer dalam C dan assembler
ALAT PERCOBAAN Personal Computer – PC Software compiler C misalnya MinGW atau GCC
DASAR TEORI Array adalah kumpulan lokasi penyimpanan data, setiap data menyimpan tipe data yang sama. Setiap lokasi penyimpanan disebut elemen array Anda tahu bahwa semua bahasa pemrograman tingkat tinggi menggunakan variabel. Sedangkan pada bahasa pemrograman tingkat rendah variabel didefinisikan dengan cara yang lebih rumit. Di sinilah salah satu kelebihan C ditunjukkan, dimana ia dapat menjembatani antara bahasa kelas tinggi (unggul dengan kemudahan karena konsepnya manusiawi) dengan bahasa tingkat rendah (powerfull, karena akses maksimal terhadap hardware). Dalam C, programmer memiliki akses terhadap memory secara langsung dengan menggunakan p o i n t e r . Untuk memahami konsep pointer, anda perlu mempelajari konsep pengalamatan mempory. Definisi pointer adalah variabel yang menyimpan alamat memory.
PERCOBAAN Percobaan 1 : 9.
Masukkan kode program berikut dengan menggunakan teks editor. Simpan kode program tersebut dengan nama coba.c
void coba(int* x, int* y, int* z) { int a = *x; int b = *y; int c = *z; int d = a + b; *y = d ;
15
*z = b ; *x = c ; }
10. 11.
Kemudian kompilasi program tersebut agar didapat coba.s, pada file coba.s terdapat angka‐ angka yang menunjukkan penggunaan memory, apa arti angka‐angka tersebut. pada file coba.c ganti keyword int dengan double, kemudian kompilasi file coba.c yang sudah diubah, lihat kode assembler yang dihasilkan, apakah berbeda dengan yang sebelumnya ? Mengapa ? seperti sebelumnya pada kode assembler yang dihasilkan akan muncul angka‐angka, apa arti angka‐angka ini dalam penggunaan memory?
Percobaan 2 : Pada percobaan ini anda diminta untuk membuat beberapa fungsi yang berkaitan dengan array dan pointer. Berikan juga penjelasan cara kerja programnya di laporan, terutama yang berhubungan dengan array dan pointer. Fungsi 1 : Buat fungsi yang dapat membaca beberapa karakter dalam array (1 elemen array terdapat 1 karakter) dan menghasilkan output dalam susunan yang terbalik. Contoh: H E L L O menjadi O L L E H Fungsi 2 : Buat fungsi yang dapat melakukan penyimpanan sebuah list (Nama) dalam “two‐dimensional array of char” untuk menampilkan nama. Contoh: Bob
Alice
Jude
Newton
Fungsi 3 : Buat fungsi seperti pada Fungsi 2, namun dengan menggunakan “array of pointers” yang menunjuk pada penyimpanan (Nama). Jelaskan perbedaan antara Fungsi 3 dengan Fungsi 2.
16
Fungsi 4 : Buat fungsi yang dapat melakukan perkalian pada dua matriks. Keluaran dari fungsi merupakan matriks hasil perkalian tersebut. Dalam melakukan operasi perkalian matriks gunakan proses loop Contoh : mulMatriks(int A[m][n], int B[n][o]) = C[m][o] = A[m][n] * B[n][o] Catatan: Pada fungsi di atas, anda harus dapat membuat agar fungsi mengoutput sebuah matriks. Ada beberapa cara untuk melakukan ini, misalnya cara paling sederhana adalah membuat matriks hasilnya sebagai parameter fungsi dan diubah‐ubah nilainya di dalam fungsi (misal C adalah outputnya): void addMatriks(int A[m][n], int B[m][n], int C[m][n]);
Tetapi prototype ini memunculkan pertanyaan mengenai kemungkinan implementasi dan cara pemakaian fungsinya: apakah dari fungsi yang memanggil matriks C hanya merupakan pointer dan akan dialokasikan nilainya di dalam fungsi, atau matriks C sudah terbentuk sebagai array dan tinggal diubah nilainya? Biasanya prototype seperti ini lebih cenderung ke cara yang kedua, yaitu array C sudah ada dan tinggal digunakan. Yang menjadi masalah, dari dalam fungsi tidak ada jaminan bahwa array C sudah teralokasikan dengan benar dan memiliki ukuran yang benar. Apabila ternyata salah, ada kemungkinan fungsi menulis data ke alamat memori yang sebetulnya bukan milik C (misalnya karena melebihi batas indeks maksimum array yang dialokasikan untuk C). Cara lain yang lebih aman adalah membuat fungsi mereturn pointer dari matriks yang dialokasikan secara dinamik di dalam fungsi: int** addMatriks(int A[m][n], int B[m][n]);
Perhatikan juga bahwa anda harus dapat memberitahukan kepada fungsi berapa nilai m, n, dan o (ukuran matriks) dari fungsi yang memanggilnya. Cara paling mudah adalah membuat m, n, dan o sebagai global variable. Namun demikian cara ini biasanya tidak disukai karena penggunaan global variable membuat alur dan struktur program menjadi kurang jelas, selain membuat fungsi anda menjadi kurang fleksibel. Cara lain adalah membuat m, n, dan o menjadi parameter fungsi, : 17
int** mulMatriks(int m, int n, int o, int A[m][n], int B[n][o]);
tetapi ini membuat jumlah parameter fungsi menjadi banyak. Selain itu, dengan menyimpan ukuran matriks pada variabel terpisah, berarti perlu dibuat dua variabel tambahan, yang secara struktural dalam program tidak ada hubungannya dengan array matriksnya, untuk menyimpan ukuran matriks. Salah satu solusi adalah dengan menyimpan matriks dalam suatu struktur data, misalnya yang sederhana saja: struct Matriks { int jumlahBaris; int jumlahKolom; int** nilai; // ini akan menjadi dynamic array 2 dimensi };
sehingga prototype fungsi menjadi: struct Matriks mulMatriks(struct Matriks A, struct Matriks B);
atau jika ingin lebih efisien memori: struct Matriks* mulMatriks(struct Matriks* pA, struct Matriks* pB);
Anda bebas memilih cara apapun yang disebutkan di atas, atau menggunakan cara lain jika menurut anda lebih baik.
TUGAS Buatlah sebuah program yang mensimulasikan operasi aritmatika pada level bit 2’s complement dengan menggunakan array. Array yang digunakan terdiri dari 8 bit saja dan hanya boleh diisi oleh angka 1 dan 0. Operasi aritmatika yang akan disimulasikan hanya penjumlahan dan pengurangan. Contoh : penjumlahan antara 7 dan 8. Angka 7 dimasukkan ke dalam array menjadi 00000111 dan angka 8 menjadi 00001000, maka hasil penjumlahan adalah 00001111 dan kemudian diubah kembali menjadi angka desimal, yaitu 15. Buatlah makefile yang akan mengkompilasi program ini.
18