BUKU AJAR BAHASA PEMROGRAMAN TINGKAT RENDAH (BPTR) PADA MESIN KOMPUTER IBM-PC COMPATIBLE
OLEH MAMAN ABDUROHMAN, ST.
SEKOLAH TINGGI TEKNOLOGI TELKOM BANDUNG 2002
KATA PENGANTAR
Bismillahiirrohmanirrohim, Alhamdulillahi hirobbil’alamin. Dengan rahmat-Nya, buku ajar “Bahasa Pemrograman Tingkat Rendah”, telah selesai disusun. Mudah-mudahan dapat membantu dalam memahami pemrograman bahasa tingkat rendah dengan bahasa assembly. Buku ajar ini berisi tentang sebagian materi Bahasa Pemrograman Tingkat Rendah yang terdapat pada kurikulum jurusan Teknik Informatika STT Telkom, yang terdiri dari 10 bab dengan masing-masing bab membahas : • Pengenalan : Mengenali bahasa assembly dan elemen-elemen dasarnya. • Arsitektur Perangkat Keras dan Perangkat lunak : Membahas tentang komponen arsitektur sistem yang terdiri dari perangkat keras dan perangkat lunak. • Dasar-Dasar Bahasa Assembly : Membahas Perintah-perintah dan instruksi serta mode pengalamatan pada bahasa assembly. • Layanan Masukan/Keluaran (Input/Output) : Membahas tentang interrupt untuk input/output. • Pemrosesan Kondisi : Insturksi-instruksi kondisi dan pencabangan. • Aritmetika : Instruksi Geser dan Putar, penjumlahan, pengurangan, perkalian dan pembagian. • Makro dan Struktur : Membahas tentang makro dan perintah-perintahnya • Hubungan Dengan Bahasa Tingkat Tinggi : Membahas cara untuk membangun antara muka dengan bahasa pemrograman tingkat tinggi yaitu Turbo Pascal dan Turbo C. • Contoh Program : Contoh-contoh program dalam bahasa assembly. Sebagian besar materi diambil dari buku “Assembly Language for the IBM-PC” karangan Kip R. Irvine. Ada beberapa bahasan yang diambil dari User’s Guide Turbo Assembler 3.00. Terima kasih banyak kepada semuanya yang telah membantu sehingga tersusunnya buku ajar ini. Jazakallah kepada Teteh yang telah menemani dengan setia selama pembuatannya. Buku ini dipersembahkan untuk si kecil Arina Dini Hanifa pada ulangtahunnya yang pertama, hari ini. Akhir kalam, tulisan kecil ini mudah-mudahan akan memberikan sedikit kemudahan bagi siapa saja yang berminat untuk mempelajari bahasa assembly dan pemrograman bahasa tingkat rendah. Segala kritik dan saran mohon ditujukan ke alamat email :
[email protected]. Bandung, 27-Agustus 2002 Penulis
DAFTAR ISI
Kata Pengantar Daftar Isi 1. Pengenalan 1.1. Pendahuluan 1.2. Representasi Data 1.3. Bahasa Assembly – Pengenalan 1.4. Elemen Dasar Bahasa Assembly 1.5. Contoh Program Hello 2. Arsitektur Perangkat Keras dan Perangkat lunak. 2.1. Komponen Mikrokomputer 2.2. Arsitektur Sistem 2.3. Perangkat Lunak Sistem dan Memori 3. Dasar-Dasar Bahasa Assembly 3.1. Perintah Definisi Data 3.2. Instruksi Transfer Data 3.3. Instruksi Aritmetik 3.4. Mode Pengalamatan 3.5. Struktur Program 4. Layanan Masukan/Keluaran (Input/Output) 4.1. Prosedur 4.2. Interrupt Perangkat Lunak 4.3. Fungsi Call DOS 4.4. Kendali Video Level Bios (INT 10h) 5. Pemrosesan Kondisi 5.1. Boolean dan Instruksi Perbandingan 5.2. Loncat Kondisional 5.3. Liupan Kondisional (Conditional Loops) 5.4. Struktur Logic Tingkat Tinggi 6. Aritmetika 6.1. Instruksi Gser (Shift) dan Putar (Rotate) 6.2. Aplikasi Contoh 6.3. Multi - Penjumlahan dan Pengurangan (Multiple Addition and Substraction) 6.4. Perkalian dan Pembagian 7. Makro dan Struktur 7.1. Pengenalan 7.2. Teknik Khusus 7.3. Operator Makro 7.4. Library Makro 7.5. Penggunaan Makro Lebih Lanjut 7.6. Operator dan Perintah Lanjut 7.7. Contoh Penggunaan Macro Dalam Program 8. Hubungan Dengan Bahasa Tingkat Tinggi 8.1. Hubungan Dengan Turbo Pascal 8.2. Turbo Built-In Assembler (BASM) 8.3. Pernyataan dan Perintah Inline 8.4. Antarmuka Turbo Assembler dengan Turbo Pascal
1 1 3 8 10 13 15 15 17 26 29 29 34 37 40 46 49 49 52 54 59 61 61 67 72 73 78 78 82 85 87 93 93 102 107 109 112 122 129 136 136 145 148 149
8.5. Hubungan dengan Turbo C 8.6. 8. 6. Antarmuka Turbo Assembler Dengan Borland C++ 9. Contoh Program 10. Daftar Pustaka
158 162 169 183
I. PENGENALAN
1.1. Pendahuluan Bahasa assembly membuka rahasia perangkat keras dan perangkat lunak komputer. Disini akan dipelajari bagaimana perangkat keras komputer dan sistem operasi bekerjasama dan bagaimana program aplikasi berkomunikasi dengan sistem operasi. Untuk memahami keseluruhan komputer dan sistem informasinya, seseorang perlu memahami perangkat lunak pada berbagai level. Pertama level program aplikasi, dimana program berinteraksi dengan DOS. Level bahasa tingkat tinggi, dimana perintah/pernyataan yang handal diuraikan kedalam instruksi-instruksi mesin. Pada level yang lebih rendah (lebih dekat dengan mesin), seseorang akan konsentrasi pada instruksi-instruksi yang dikenali oleh CPU, sebagaimana program berkomunikasi dengan DOS. Bahasa assembly meningkatkan pemahaman seseorang tentang level yang lebih rendah ini. Pada tulisan ini memberikan titik pandang bahwa bahasa assembly seharusnya dipelajari secara kontekstual, sehingga interaksi perangkat keras dan preangkat lunak komputer mungkin lebih mudah dipahami. Pada bab berikutnya, akan dibahas perangkat keras komputer, bahasa mesin, konsep sistem operasi dan struktur pemrograman. Apakah bahasa assembly? Bahasa assembly adalah bahasa pemrograman dengan korespondensi satu-satu antara perintah-perintah/pernyataannya dan bahasa mesin komputer. Bahasa assembly tidak satu jenis sebagaimana CPU komputer pun bermacam-macam. Setiap bahasa assembly secara langsung dipengaruhi oleh set instruksi mesin komputer dan arsitektur perangkat keras. Secara singkat, bahasa assembly IBM-PC mengacu pada istruksi-instruksi yang dikenali oleh keluargaa mikroprosesor Intel 8086-80486. Apa itu assembler? Assembler adalah program yang mengkonversi kode program sumber ke dalam bahasa mesin. Pada tuliasn ini akan mengacu pada assembler yang membuat instruksi mesin untuk mikrokomputer IBP yang sesuai. Semua kompter tersebut menggunakan mikroprosesor keluarga intel, mulai dari intel 8088 sampai 80486. Program akan berjalan dibawah sistem operasi PC-DOS/MS-DOS versi 3.0 atau lebih tinggi. Terdapat dua assembler yang dikenal baik untuk IBM-PC yaitu MASM (Microsoft Assembler) dan TASM (Turbo Assembler). Bahasa assembly adalah kumpulan instruksi yang spesifik untuk sistem komputer tertentu. Assembler adalah program yang menerjemahkan program yang ditulis dalam bahasa assembly ke dalam bahasa mesin, yang dapat dieksekusi oleh komputer. Setiap tipe komputer meiliki bahasa assembly yang berbeda, karena rancangan komputer mempengaruhi instruksi yang dapat dieksekusi.
Bahasa assembly disebut bahasa level-bawah karena dalam struktur dan fungsi dekat dengan bahasa mesin. Sebaliknya, bahasa tingkat tingggi seperti Pascal, Basic, Fortran dan Cobol mempunyai perintah-perintah yang handal yang diterjemahkan ke dalam berbagai instruksi mesin oleh kompiler. Mengapa mempelajari bahasa assembly? Berbagai alasan mengapa kita mempelajari bahasa assembly. Salah satu alasan adalah untuk mempelajari arsitektur komputer dan sistem operasi. Alasan lain adalah karena kegunaan pemrograman tertentu sulit atau tidak mungkin dikerjakan oleh bahasa tingkat tinggi. Contoh, kompunikasi langsung dengan sistem operasi komputer mungkin deperlukan. Program grafik warna kecepatan tinggi mungkin harus ditulis menggunakan memori minimum. Program khusus mungkin diperlukan sebagai penghubung antara printer dengan komputer. Sering juga perlu untuk menghilangkan keterbatasan bahasa tingkat tinggi, diluar keperluan, menentukan aturan-aturan tentang apa yang dibolehkan dalam program. Contoh, pascal tidak mengijinkan nilai karakter diberi nilai dalam variabel integerr. Pemrogram yang berpengalaman akan menemukan cara untuk keluar dari batasan ini, tapi dalam pelaksanaannya, membuat kode tidak dapat digunakan oleh sistem komputer lain dan sulit dibaca. Bahasa assembly, sebaliknya, memiliki sangat sedikit batasan atau aturan. Harga yang harus dibayar untuk keleluasaan itu adalah perlu menangani berbagai kerumitan dalam pemrograman. Aplikasi bahasa assembly Biasanya ktia membuat subrutin dalam bahasa assembly dan memanggilnya dari program bahasa tingkat tinggi. Keuntungan dapat diperoleh karena ketanya bahasa tingkat tinggi, dengan menggunakan bahasa tingkat rendah dalam membuat aplikasi. Subrutin bahasa assembly menangani operasi-operasi yang tidak tersedia dalam bahasa tingkat tinggi. Misal kita menulis program aplikasi bisnis dalam Cobol untuk IBM-PC. Kita memerlukan aplikasi untuk mengecek ruang bebas disk, membuat subdirektory, menulis proteksi file, dan membuat window yang overlap, semuanya dalam satu program. Misal kompilator Cobol tidak dapat melakukan semuanya, maka kita dapat mebuat subrutin bahasa assembly untuk menangani tugas-tugas tersebut. Bahasa mesin Sebelum lebih jauh secara rinci membahas bahasa assembly, mari kita lihat dalam suatu prespektif. Komputer kenyataannya tidak mengerti bahasa assembly, dia hanya mengikuti bahasa mesin. Bahasa mesin adalah bahasa yang dibangun oleh sejumlah angka yang dapat diinterpretasikan oleh CPU komputer. CPU biasanya mempunyai program kecil yang ditambahkan langsung ke dalam chip, disebut microcode. Penerjemah microcode mengubah langsung instruksi-instruksi mesin ke dalam sinyal perangkat keras. Dengan bahasa mesin memungkinkan untuk melaksanakan tugas-tugas umum oleh CPU, seperti pemindahan bilangan atau perhitungan aritmatik. Berikut contoh instruksi bahasa mesin yang memindahkan angka 5 ke dalam register AL.
1011000000000101 Deretan angka diatas ditulis dalam biner, sistem penomoran yang dibangun hanya oleh angka 1 dan 0. Delapan bit pertama adalah kode operasi (opcode) yang menunjukannya sebagai isntruksi yang memindahkan angka – 8 bit ke register AL. Delapan bit kedua adalah operand. Instruksi secara keseluruhan memindahkan angka 5 ke dalam register AL. Register adalah memori kecepatan tinggi yang berada di dalam CPU. Register diidentifikasikan oleh nama 2 huruf, seperti AH, AL, atau AX. Kumpulan instruksi (instruction set) CPU adalah sekumpulan instruksi mesin yang dapat dieksekusi CPU. Untuk keluarga CPU intel, set instruksi adalah downward-compatible, artinya bahwa instruksi yang bekerja pada prosesor level yang lebih rendah akan bekerja juga pada prosesor yang lebih tinggi. Contoh instruksi MOV bekerja pada 8088 dan karena itu harus bekerja pula pada 80286. Tetapi terdapat instruksi yang lebih maju dlam 80286 yang tidak dapat bekerja pada 8088. Dulu, semua program ditulis dalam bahasa mesin. Hal ini sangat menyulitkan bagi pemrogram baik dalam membacanya maupun menulisnya. Itulah sebabnya mengapa dibuat assembler dan kompiler yang akan mengkonversi instruksi yang mudah dibaca, dibuat dalam editor teks ke dalam bahasa mesin. Contoh instruksi diatas adalah : MOV AL,5 1.2. Representasi Data Karena kita akan bersentuhan dengan komputer pada level mesin, kita perlu untuk memeriksa isi memori dan register. Komputer yang ada saat ini adalah komputer biner yang sistem bilangannya terdiri angka 1 dan 0 yang kita kenal dengan istilah logic digital. Bilangan biner Komputer menyimpan semua instruksi dan data sebagai rangkaian digit biner, tanpa perbedaan antara keduanya. Contoh, tiga huruf pertama alfabet akan disimpan dalam IBM-PC sebagai : 010000010100001000011 = “ABC” Pada saat yang sama, instruksi untuk menjumlahkan dua buah bilangan akan disimpan di memori sebagai : 0000010000000101 Bit & Byte. Setiap digit dalam angka biner desebut bit. 8 buah bit desebut byte, yang merupakan unit terkecil penyimpanan pada komputer saat ini. Setiap lokasi dalam komputer menyimpan 1 byte, atau 8 bit. Tipe penyimpan yang lebih besar adalah word yang panjangnya 16 bit (2 byte).
byte byte 1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 word Setiap sistem penuliasan angka mempunyai basis, yaitu jumlah maksimum nillai pada suatu digit. Ini disebut radix atau basis. Sistem Biner Oktal Desimal Heksadesimal
Basis / radix 2 8 10 16
Digit yang mungkin 01 01234567 0123456789 0123456789ABCDEF
Dalam sistem bilangan heksadesimal, huruf A sampai F mewakili nilai desimal 10 sampai 15. Pada saat mengacu pada bilangan biner, oktal atau heksadesimal, sebuah huruf kecil akan ditambahkan pada akhir setiap bilangan untuk menunjukan basisnya. Contoh bilangan 45 heksadesimal akan ditulis sebagai 45h, 76 oktal akan ditulis 76o atau 76q, dan biner 11010011 akan terlihat 11010011b. Komputer pribadi IBM disebut komputer 16-bit karena instruksinya dapat mengoperasikan sejumlah 16-bit bilangan. Integer biasanya disimpan dalam memori sebagai byte, word atau double word. Untuk masing-masingnya mempunyai batasan bawah dan atasnya, sebagai berikut : Tipe penyimpan Byte Word Double word
Bit
Range (bawah-atas) 0-225 0-65,535 0-4,294,967,295
8 16 32
Walaupun masing-masing billangan membutuhkan jumlah bit yang berbeda-beda, pada kenyataannya semua bilangan disimpan di memori sebagai nilai biner karena arsitektur komputer adalah biner. Setiap bit memori adalah 1 atau 0, tetapi lokasi terkecil memori yang diberi alamat adalah byte. Pengubahan bilangan biner ke desimal Karena berbagai keperluan mungkin kita perlu mengubah bilangan dari biner ke desimal. Setiap posisi bit dalam bilangan biner adalah pangkat dari 2, seperti gambaran berikut : 27 Nilai 128
26 64
25 32
24 16
23 8
22 4
21 2
20 1
Untuk mendapatkan nilai desimal dari sebuah bilangan biner, kita harus menjumlahkan nilai setiap bit yang bernilai 1 dan memperoleh jumlah keseluruhannya. Misalkan terdapat bilangan biner 00001001 :
0
0
0
0
Desimal
1 8
0
0
1 1 = 9d
Bilangan heksadesimal Bilangan biner yang banyak susah untuk dibaca, sehingga bilangan heksadsimal biasanya sering digunakan untuk menggambarkan memori komputer atau instruksi. Setiap digit bilangan heksadesimal mewakili 4 bit bilangan biner, dan 2 digit bilangan heksadesimal mewakili satu byte. Pada contoh berikut terlihat bahwa bilangan biner 000101100000011110010100 digambarkan oleh bilangan heksadesimal 160794 : 0001 1
0110 6
0000 0
0111 7
1001 9
0100 4
Sebuah digit heksadesimal mungkin mempunyai nilai sampai 15 sehingga untuk angka 10 – 15 menggunakan huruf A – F. Tabel berikut menunjukan bagaimana setiap 4 bit biner diterjemahkan ke dalam desimal dan heksadesimal : Biner 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Desimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Heksadesimal 0 1 2 3 4 5 6 7 8 9 A B C D E F
Posisi digit heksadesimal. Setiap posisi digit heksadesimal mewakili bilangan pangkat dari 16. 163 Nilai 4096
162 256
161 16
160 1
Bilangan dapat dikonversi dari heksadesimal ke desimal dengan mengalikan masing-masing digit dengan nilai posisinya. Misalnya bilangan 3BA4h, hasilnya Nilai posisi Hasil kali
3 4096 12,288
B 256 2,816
A 16 160
4 1 4 = 15,268d
Pada saat perkalian huruf B diganti 11 dan A dengan 10. Bilangan bertanda Bilangan biner mungkin bertanda atau tidak bertanda. Byte bertanda menggunakan 8 bit seluruhnya untuk nilai angkanya. Contoh, 11111111 = 255. Karena itu, 255 adalah nilai tertinggi yang dapat disimpan dalam byte tidak bertanda. Nilai terbesar yang dapat disimpan dalam word tidak bertanda adalah 65,535. Byte bertanda hanya menggunakan 7 bit untuk nilai sedangkan bit paling kiri digunakan sebagai tanda. Bilangan mungkin positif atau negatif, jika tanda sama dengan 1 maka bilangan negatif sebaliknya jika tanda bernilai 0 maka bilangan positif : Bit tanda 10001010 00001010
(bilangan negatif) (bilangan positif)
Ones complement. Untuk menghitung bilangan ones complement dari suatu bilangan maka balikan seluruh nilai bitnya. Contoh, ones complement dari 11110000b adalah 00001111b. Twos complement. Untuk menyimpan nilai negetif maka digunakan bilangan twos complement. Twos complement diperoleh dengan menambah satu pada bilangan ones complement. Contoh twos complement dari +6 (00000110b), balikan nilai bitnya untuk mendapatkan ones compelent menjadi 11111001b, untuk memperoleh twos complementnya ditambah satu menjadi : 11111010b (ini nilai twos complement untuk -6). Untuk mendapatkan kembali nilai +6 sebagai berikut : 11111010 00000101 + 1 00000110
-6 ones complement tambah 1 +6
Nilai maksimum dan minimum. Karena nilai paling kiri pada bilangan bertanda digunakan untuk tanda bilangan, maka ukuran bilangan akan berkurang, yang digunakan hanya 7 bit sehingga nilai paling besar yang bisa dicapai adalah +127.
Tabel berikut menunjukan nilai maksimum dan minimum untuk byte, word dan double word bertanda : Tipe penyimpan Byte Word Double word
Nilai terendah
Nilai tertinggi
-127 -32,767 -2,147,483,647
+127 +32,767 +2,147,483,647
Penyimpan karakter Komputer hanya dapat menyimpan bilangan biner, jadi bagaimana menyimpan karakter seperti “A” dan “$” ? Telah dibuat suatu sistem menterjemahkan karakter ke dalam bilangan biner yaitu American Standard Code for Information Interchange (ASCII). Sistem lainnya, Extended Binary Code for Decimal Interchange (EBCDIC), digunakan oleh mini dan mainframe komputer IBM. Berikut ini tabel contoh kode ASCII : Kode ASCII 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A
Ctrl Ctrl – A Ctrl – B Ctrl – C Ctrl – D Ctrl – E Ctrl – F Ctrl – G Ctrl – H Ctrl – I Ctrl – J Ctrl – K Ctrl – L Ctrl – M Ctrl – N Ctrl – O Ctrl – P Ctrl – Q Ctrl – R Ctrl – S Ctrl – T Ctrl – U Ctrl – V Ctrl – W Ctrl – X Ctrl – Y Ctrl – Z
Mnemonic NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB
Penjelasan Karakter kosong Awal header Awal teks Akhir teks Akhir transmisi Pertanyaan (Enquiry) Pemberitahuan Bel Backspace Tab horison Line feed Tab vertikal Form feed Carriage return Shift out Shift in Data link escape Device control 1 Device control 2 Device control 3 Device control 4 Pemberitahuan negatif Synchronous idle Akhir transmisi blok Batal Akhir medium Pengurangan (substitusi)
1B 1C 1D 1E 1F
Ctrl – [ Ctrl – \ Ctrl – ] Ctrl – ^ Ctrl – -|
ESC FS GS RS US
Escape Pemisah file Pemisah grup Pemisah rekord Pemisah unit
Standar kode ASCII hanya menggunakan 7-bit kode sedangkan nilai selebihnya yang mungkin 7Fh. 8-bit lainya adalah pilihan, digunakan oleh IBM-PC untuk memperluas kumpulan karakter. Nilai 80h – FFh menggambarkan simbol grafik dan karakter Yunani. Nilai 0-1Fh adalah kode kendali untuk printer, komunikasi dan keluaran layar. Semua karakter, termasuk bilangan dan huruf, dibuat unik pada kode ASCII. Contoh, kode untuk karakter string “ABC123” adalah : Karakter A Kode ASCII 41h
B 42h
C 43h
1 30h
2 31h
3 32h
Penyimpanan bilangan. Setiap huruf atau digit memerlukan 1 byte memori. Namun ketika menyimpan bilangan, kita bisa lebih efisien, contoh, bilangan 123 dapat disimpan dalam memoori sebagai satu byte yaitu 01111011b. 1.3. Bahasa Assembly – Pengenalan Insturksi bahasa assembly Meskipun mungkin untuk membuat program bahasa mesin menggunakan angka, bahasa assembly membuat pekerjaan lebih mudah. Instruksi bahasa assembly adalah representasi simbolik instruksi mesin tunggal. Dalam bentuknya yang paling sederhana, terdiri dari satu mnemonic, kode alfabet singkat yang secara harfiah “membantu memori” dalam mengingat instruksi CPU. Mnemonic mungkin diikuti oleh operand berikut contohnaya : clc inc ax mov ax, bx
; hanya sebuah mnemonic ; operand tunggal ; dua operand
Setiap instruksi dapat diikuti oleh komentar, yang selalu diawali dengan titik koma (;). Operand, operand mungkin berupa register, variabel, lokasi memori atau nilai immediate. Contoh : 10 count AX [0200]
(nilai immediate) (variabel) (register) (lokasi memori)
Contoh program Program bahasa assembly dibangun oleh instruksi dan operand. Instruksi memerintahkan CPU untuk melaksanakan aksi, sedang variabel adalah lokasi memori dimana data disimpan. Variabel juga disebut operand memori. Operand langsung adalah konstanta seperti 5 dan 10. Berikut ini contoh program untuk menjumlahkan 3 bilangan dan menyimpannya dalam variabel yang disebut sum. Sum diasumsikan dalam heksadesimal. mov ax, 5 add ax, 10 add ax, 20 mov sum, ax int 20
; memindahkan 5 ke dalam register ax ; menambahkan nilai 10h terhadap register ax ; menambahkan nilai 20h terhadap register ax ; menyimpan ax dalam variabel sum ; akhir program
Instruksi MOV memerintahkan CPU untuk memindahkan atau menyalin data, dari operand sumber ke operand tujuan. Baris 1 memindahkan 5 ke dalam register AX. Baris 2 memindahkan 10 (hexa) ke dalam AX, membuatnya sama dengan 15. baris 3 menambahkan 20 ke AX, membuatnya sama dengan 35, dan baris 4 menyalin AX ke dalam variabel dalam memori yang disebut SUM. Baris terakhir menghentikan program. Perintah DEBUG untuk menyusun dan test program adalah sebagai berikut : Perintah
Komentar Assembly dimulai pada lokasi 100h Perintah program yang pertama
A 100 Mov ax, 5 Add ax, 10 Add ax, 20 Mov [0120] , ax Int 20
Hasil jumlah pada lokasi 0120h Akhir program (tekan Enter untuk mengakhiri assembly) Menampilkan register Trace satu instruksi
R T T T G Q
Ekseskusi sisa program Keluar dari Debug kembali ke DOS Setelah isntruksi yang kedua akan diperoleh tampilan hasil sebagai berikut : 1. 2. 3. 4.
mov ax, 5 add ax, 10 add ax, 20 mov sum, ax
ax : 05 ax : 10 ax : 35 ax : 35
sum : 35
AX = 0015 BP = 0000 SS = 23AD 23AD : 0106
BX = 0000 SI = 0000 CS = 23AD 052000
CX = 0000 DX = 0000 SP = FFEE DI = 0000 DS = 23AD ES = 23AD IP = 0106 NV UP EI PL NZ NA PO NC ADD AX, 0020
Gambar 1.1. Program contoh Register AX merupakan hasil penjumlahan 5 dan 10, sehingga AX = 15. Register IP menyimpan alamat instruksi berikutnya yang akan dieksekusi (0106). Instruksi berikutnya yang akan di eksekusi adalah ADD AX, 0020
1.3.1. Elemen Dasar Bahasa Assembly Gambar 1.2. menunjukan kumpulan karakter dasar assembler. Karakter-karakter tersebut mungkin digunakan unntuk membentuk nomor, nama, perintah dan parameter. Konstanta Konstanta adalah nilai yang diketahui dan dikalkulasikan pada saat penyusunan program. Konstanta mungkin nomor atau karakter string. Dia tidak dapat diubah pada saat program dijalankan. Kumpulan karakter dalam Assembly Letter : A-Z, a-z Digit : 0-9 Karakter khusus : ? @ _ $ : . [] () <> {} + / *
, (koma) “ & % ! ‘ ~ | / = # ^ ; `
Gambar 1.2. Kumpulan karakter assembly Variabel, sebaliknya, adalah lokasi memori yang dapat berubah pada saat program dijalankan. Contoh berikut adalah konstanta : ‘ABC’ 2134 5*6 (1+2)/3 Integer. Integer dibangun oleh digit-digit angka tanpa titik desimal, diikuti oleh karakter radix (d=desimal, h=hexa, q=octal, b=biner). Contoh : Contoh 11110000b 200 300d 4A6Bh 2047q 2047o
Radix Biner Desimal Desimal Heksadesimal Oktal Oktal
Bilangan real : angka real mengandung digit, titik desimal tunggal, eksponent (opsional) dan tanda awal (opsional). Sintaknya : [{+/-}] digit.digit [E{+/-}] digit Contoh 2.3 + 200.576 E +05 0.243526E –5 - 6.08 e3 Notasi sintak : dalam contoh sebelumnya dan pada contoh yang akan datang elemen opsional akan ditutup dengan kurung siku. Tanda kurung besar mengidentifikasikan pilihan yang diperlukan. Kata kunci yang diperlukan ditulis dalam huruf besar. Kata huruf kecil miring adalah istilah-istilah yang telah didefinisikan sebelumnya seperti identifier, operand dan register. Karakter atau konstanta string : karakter ASCII tunggal atau string karakter yang ditutup oleh tanda quotasi tunggal (‘’) atau ganda (“”), contoh : “a” ‘B’ “Stack Overflow” ‘012#?%&’
Konsatanta karakter panjangnya 1 byte. Panjang sebuah string ditentukan oleh jumlah karakter yang ada di dalamnya. Konstanta berikut panjangnya 5 byte : ‘ABCDE’ Apostrof (‘) ditutup diantara dua tanda quotasi (“”), atau tanda quotasi ganda (“”) ditutup oleh quotasi tunggal (‘’). Contoh berikut adalah benar : “That’s not all …….” ‘The file “First” was not found’ “The file ‘First’ was not found” Pernyataan Pernyataan/perintah bahasa assembly terdiri dari nama, mnemonic, oeprand dan komentar. Pernyataan secara umum dibagi ke dalam dua kelas yaitu instruksi dan perintah. Instruksi adalah pernyataan yang dapat dieksekusi, dan perintah adalah pernyataan yang menyediakan informasi untuk membantu assembler dalam menghasilkan kode yang dapat dieksekusi. Format umum sebuah kalimat. [name][mnemonic][operand][; coment] Kalimat harus ditulis pada baris tunggal dan tidak melebihi 128 kolom. Perintah, atau pseudo op, adalah pernyataan yang berefek pada daftar program atau cara kode mesin dibuat. Contoh, perintah DB memerintah assembler untuk membuat memori untuk variabel bernama count dan memberi nilai awal 50. Count DB 50 Isnturksi dieksekusi oleh mikroprosesor pada saat dijalankan. Instruksi dibagi ke dalam tipe-tipe-tipe umum : kendali program, transfer data, aritmetik, logic dan I/O. Instruksi-instruksi selalu diterjemahkan langsung ke dalam kode mesin oleh assembler. Setiap satu instruksi bahasa assembly diterjemahkan langsung ke dalam satu instruksi bahasa mesin. Nama Nama mengidentifikasikan label, variabel, simbol atau kata kunci. Nama mungkin mengandung salah satu karakter berikut : Karakter A … Z, a … z 0…9 ? _ @
Penjelasan Huruf Angka Tanda tanya Underscore Tanda @
$ .
Tanda dollar Titik
Nama mempunyai batasan sebagai berikut : - Hanya 31 karakter pertama yang dikenali - Tidak ada perbedaan antara huruf besar dan huruf kecil - Karakter pertama tidak boleh angka - Jika digunakan, tanda (.) hanya bisa digunakan sebagai karakter pertama - Tidak boleh memilih nama yang sama dengan kata kunci (perintah/direktif) Variabel dan konstanta. Nama digunakan sebelum perintah alokasi memori mengidentifikasikan lokasi dimana data disimpan dalam memori. Atau mungkin juga digunakan untuk mendefinisikan konstanta, sebagai berikut : Count1 db 50 Count2 equ 100
; variabel (alokasi memori) ; konstanta
Label. Jika nama tampil disamping instruksi program, ini disebut label. Label berfungsi sebagai penanda kapan saja program mau meloncat atau looping dari satu lokasi ke lokasi lain. Seperti contoh berikut dimana Label1 dan Label2 adalah label yang mengidentifikasikan lokasi dalam program : Label1 :
mov ax, 0 mov bx, 0 … …
Label2 : jmp label1 Kata kunci. Kata kunci atau reserved word selalu mempunyai arti yang sebelumnya telah didefinisikan. Keyword mungkin instruksi atau direktif. Contohnya : MOV, PROC, ADD, AX dan END. Kata kunci tidak dapat digunakan keluar dari konteknya atau sebagai identifier, contoh penggunaan ADD sebagai label adalah tidak benar : add : mov ax, 10 1.4. Contoh Program Hello Kita lihat gambar 1.3. yang menampilkan pesan “Hello, world!” pada layar. Baris 1 mengandung perintah title; semua karakter sisanya pada baris 1 dianggap komentar, sepreti pada baris 3. Sebelum menyelesaikan lebih lanjut, kita jelaskan dulu segmen, yaitu bagianbagian yang membangun program.
Segmen code adalah bagian dimana instruksi program disimpan, segemen data adalah bagian dimana variabel disimpan. Dan segmen stack dimana stack disimpan. Stack adalah daftar dalam memori dimana program dijaga dalam variabel sementara, kembali dari subrutin dan semacamnya. Direktif dosseg menunjukan segmen standar untuk code, data dan segmen stack. Perintah model small mengindikasikan bahwa program menggunakan microsoft assembler memory “small”. Direktif stack menset 100 H (256) byte ruang stack untuk program. Title Program Hello world ; program ini menampilkan pesan “Hello, world” dosseg . model small . stack 100h . data . hello_message db ‘Hello, world !’, 0dh, 0ah, ‘$’ . code main proc mov ax, @data mov ds, ax mov ah, 9 mov dx, offset hello_message int 21h mov ax, 4000h int 21h main endp endp main
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24]
Gambar 1.3. Program Hello.asm Direktif .code menandai awal segemen kode. Perintah .data menandai awal segmen data, dimana variabel dideklarasikan. Baris 9-10 mengandung segmen data, dimana variabel yang diberinama hello_message dideklarasikan. Huruf DB adalah direktif define byte yang meminta assembler untuk mengalokasikan serangkaian byte memori untuk data yang mengikutinya. Baris 13 menggunakan perintah proc untuk mendeklarasikan prosedur main (mungkin juga menggunakan nama lain). Baris 14-15 menyalin alamat segmen data ke dalam reg DS. Instruksi MOV selalu mempunyai 2 operand. Tujuan dan sumber.
Baris 17-19 menyebabkan string karakter dituliskan ke konsole. Mereka melakukannya dengan memanggil fungsi DOS yang menampilkan string yang alamatnya dalam register DX. Nomor fungsi diletakan dalam register AH. Baris 21-22 adalah perintah untuk berhenti dan kembali ke DOS. Baris 23 adalah akhir dari prosedur main dan baris 24 baris terakhir yang diassembly.
II. ARSITEKTUR PERANGKAT KERAS DAN PERANGKAT LUNAK
2.1. Komponen Mikrokomputer Video Display Kebanyakan PC yang dibuat sejak 1990 mempunya display warna VGA (Video Graphic Array). Display VGA standar yang mempunyai resolusi 640 (horisontal) kali 480 (vertikal) piksel. Display VGA minimal memiliki 16 warna berbeda secara bersamaan, dan ada juga sampai 256 warna. Terdapat juga display Super VGA (800 x 600) dan Ectended-VGA (1024 x 800), yang dapat meningkatkan pembacaan program yang berbasis grafik. Display warna yang digunakan oleh PC terdahulu adalah CGA (Color Graphics Adapter) dan EGA (Enhanced Graphic Adapter). Keduanya memiliki piksel yang lebih sedikit pada setiap baris dan kolomnya. IBM-PC yang asli mempunyai tampilan monokrom yang hanya dapat menampilkan karakter tekst ASCII (25 baris dan 80 kolom). Keyboard Semenjak IBM-PC dikenalkan, keyboard telah mengalami perkembangan. Model asalnya mempunyai 10 kunci fungsi, dan kunci panah kursor dibagi dengan kunci untuk angka. Komputer yang lebih banyak kuncinya dikenalkan bersamaan dengan kompuer IBM-AT dengan memiliki 12 kunci fungsi. Bahkan yang berikutnya, IBP seri PS/2 memperkenalkan keyboard dengan 12 kunci fungsi seperti top, kunci panah yang terpisah, home, end, pageup dan pageDown. Akhir-akhir ini fabrik komputer PC semuanya meniru format yang dimiliki keyboard IBM-PC Drive disk IBM-PC asli memiliki dua drive disk yaitu 5.25 inci berkapasitas 360 KB. Kemudian IBM-AT membawa drive disk 1.2 MB yang dapat juga membaca HD 360 KB. Kemudian drive disk 3.5 inci dikenalkan oleh komputer IBM seri PS/2, yang dapat membaca dua format : 720 K dan 1.44 MB. Unit sistem Unit sistem adalah “jantung” komputer yang sesungguhnya. Contoh PC 386compatible ditunjukan pada gambar 2.1. ini menggunakan prosesor Intel 386, mempunyai RAM 2 MB, 2 Floppy disk drive, 200 MB HD, 2 port parallel, 1 port serial dan backup tape luar, modem internal dan mouse. Board sistem (sering juga disebut motherboard) terhampar mendatar pada bagian bawah unit sistem. Didalamnya terdapat banyak chip mikroprosesor, termasuk CPU, RAM dan memory ROM, dan berbagai prosesor pendukung. Berikut ini adalah komponen utama.
Prosesor pendukung, satu prosesor adalah chip pengendali interupt yang menangani permintaan dari perangkat keras untuk mengintrupsi CPU. Chip pengendali DMA menangani transfer data ke dan dari memori melalui bus data. 16-bit VGA video controller
Serial and Parallel port
External tape backup connector
Bus mouse controller
Hard disk and ploppy disk controller
Keyboard connector
Intel 80386 DX processor
Internal 2400-baud modem
CPU
200-watt power suplay
Intel 80387 math coproscessor
32-bit memori expansion slot Half-height 200-MB HD
2-MB Ram on system board
ROM BIOS
Gambar 2.1. Komputer IBM-386 Rom Bios. Ini disebut firmware (perangkat keras dengan program tambahan) bagian dari sistem operasi PC. Biasanya ROM harus diganti karena untuk mendukung peripheral baru. RAM (Random Access Memory) : tempat meyimpan program dan data pada saat program dijalankan. Khususnya, RAM disebut RAM dinamis karena isinya akan hilang jika tidak menerima sinyal baru yang konstan dari CPU. CMOS RAM. Informasi setup sistem disimpan disini, sehingga kita dapat mengkonfigurasi komputer tanpa harus menggunakan switch mekanik Slot tambahan. Terdapat beberapa tempat pada motherboard yang dapat digunakan untuk menambah slot yang diperlukan seperti disk drive controller, tape drive
controller, video controller, network controller, I/O port, modem, mouse controller dll. Power supply. Kotak besi yang menkonversi voltase 110 v AC dari sumber luar ke dalam komputer. Parallel port. Kebanyakan printer terhubung dengan komputer melalui port parallel. Dengan parallel berarti 8 bit data dapat mengalir dari komputer ke printer secara bersamaan.DOS mendukung 3 port parallel yaitu LPT1, LPT2 dan LPT3. Serial port. Port serial digunakan untuk menghubungkan mouse, modem, atau perangkat serial lainnya ke sistem komputer. Dengan tipe port seperti ini, data biner dikirim satu per satu. DOS mendukung sampai 2 port serial yang disebut COM1 dan COM2. Keluarga mikroprosesor Intel Berikut ini daftar pemroses keluarga Intel dari yang terdahulu : 80x87. Chip co-prosesor matematika dikenalkan sebagai penyerta pada 8086/8088. Chip ini dapat menyelesaikan penghitungan floating-point dengan baik. 80186. 80186 merupakan pengembangan dari 8088, dengan 8 MHz clock dan instruksi baru dengan tujuan untuk meningkatkan efesiensi prosesor. 80286. 80286 dikenalkan pertama kali pada komputer IBM-AT. RAM yang bisa diakses sampai sebesar16 MB. Menggunakan 16-bit data dan mempunya kecepatan clock sampai 12-25 MHz. 80386. pada tahun 1985, Intel memperkenalkan prosesor 386 DX (dikenal sebagai 80386) yang mempunyai 32-register dan 32-bit bus data. Bersamaan dengannya dikeluarkan juga co-prosesor matematika 80287 dan 80387. 80486. 80486 pada dasarnya sama dengan 80386 dengan tambahan co-prosesor matematika built instruksi dan cache memori RAM kecepatan tinggi di dalamnya. Cache RAM meningkatkan kinerja komputer dengan mengijinkan CPU untuk mengambil instruksi dari memori kecepatan tinggi. Kecocokan. Perlu dicatat bahwa setiap prosesor baru dikenalkan oleh Intel adalah akan cocok dengan prosesor sebelumnya. Artinya perangkat lunak yang dibuat pada satu prosesor akan bisa juga digunakan pada komputer yang lebih baru. 2.2. Arsitektur Sistem CPU (Central Processing Unit)
Mikrokomputer menggunakan CPU tunggal, seperti pada gambara 2.2. dalam kenyataannya terdapat banyak chip yang mendukung PC, yang paling nampak adalah 80x87 co-prosesor matematika, tapi CPU masih menjadi pengatur utamanya. Tugas yang paling mendasar yang ditangani oleh CPU adalah : Menemukan dan load instruksi berikutnya Mengeksekusi instruksi : Fetch data dari memori/register Menyimpan data dalam memori/register Melaksanakan penghitungan dan perbandingan Memperbaharui penunjuk instruksi (pencabangan) Bus Data
Register Data Register Alamat
Unit Kendali (control unit)
Bus Alamat
Jalur keluaran
Arithmetic Logic Unit
Register Flag
Jalur keluaran
Gambar 2.2. Rancangan CPU sederhana CPU dibagi menjadi dua bagian : Arithmeticl Logic Unit (ALU) dan Control Unit (CU). ALU melaksanakan operasi aritmetik, logic, dan penggeseran, CU mengambil data dan instruksi dan menerjemahkan kode (decode) alamat untuk ALU. Seluruh sisi chip adalah pin yang ditancapkan ke dalam soket dalam board sistem, menghubungkannya ke bagian sistem komputer yang lain. Register berada dalam CPU. Ketika sesuatu diambil dari memori, alamatnya dihitung oleh unit kendali dan dikirm melalui bus alamat. Nilai dari memori (baik instruksi atau data) dikirim balik ke CPU melalui bus data. Clock melakukan sinkronisasi setiap operasi CPU. Bus data. Bus adalah kabel parallel yang mengirimkan data antara berbagai bagian CPU. Sinyal kendali dan bit data digunakan pada saat pengambilan word memori dan menempatkannya dalam register. Bus dikatakan bidireksional jika data dapat ditransfer dari dua arah. Register. Berada dalam CPU yaitu area penyimpan kecepatan tinggi, yang langsung terhubung ke unit kendali dan ALU. Karenanya, penggunaan register untuk eksekusi lebih cepat daripada menggunakan memori konvensional. Kumpulan instruksi Intel membutuhkan penggunaan setidaknya satu register untuk semua instruksi.
Clock. Setiap operasi yang dilakukan di CPU harus disinkronkan oleh clock. Unit waktu paling dasar untuk instruksi mesin yang disebut siklus mesin (machine cycle). Instruksi mesin dalam prosesor Intel umumnya dilaksanakan antara 3 dan 20 clock. Register Register adalah lingkungan kerja khusus dalam CPU, dirancang untuk diakses pada kecepatan tinggi. Register memiliki panjang 16 bit. Pengaksesan 4 register data dibagi dua bagian yaitu setengah bagian atasnya dan setengah bagian bawah. Register data
AX, BX, CX, DX (16 bit) AH, AL, BH, BL, CH, CL, DH, DL (8 bit) CS, DS, SS, ES SI, DI, BP IP, SP overflow, direction, interupt, tmp, sign, zero, auxiliary carry, parity, carry.
Register segemn Register indeks Register khusus Register flag
Diagram register 8086/8088 ditunjukan pada gambar 2.3. Register data. Empat register, dinamai register data atau register tujuan umum, digunakan untuk perhitungan aritmetik dan pemindahan data. Perhitungan setiap register dapat dialamati sebagai nilai 16-bit atau 8 bit. Contoh register AX adalah register 16-bit, 8 bit atasnya disebut AH dan 8 bit bawahnya dinamai AL. Posisi bit selalu diberi nomor dari kanan ke kiri dimulai dari nol. Bit
15 …………
…………..0
16-bit register AX Register AH Bit
Register AL
7 ……………..0 7 …………..0
Instruksi mungkin menunjuk 16 bit atau 18 bit register data dari daftar berikut : AX AH
AL
BX BH
BL
CX CH
CL
DX DH
DL
Jika kita memindahkan 126Fh ke dalam AX maka AL akan berubah menjadi 6F h. Tujuan Umum
AH
AL
AX Index BH
BL
BP
BX
SP CH
SI
CL
CX
DI DH
DL
DX
Segmen CS SS
Status dan Kendali Flag
DS ES
IP
Gambar 2.3. Flag Intel 8086/8088 Masing-masing register dengan tujuan umum memiliki atribut-atribut khusus. AX (akumulator) : AX disebut register akumulator karena digunakan oleh CPU untuk operasi aritemtik. Operasi-operasi lain juga sedkit lebih efisien dengan menggunakan AX.
BX (basis). Seperti register tujuan umum lainnya, register BX dapat melaksanakan operasi aritmetik dan perpindahan data dan BX memiliki kemampuan pengalamatan khusus. Dia dapat menyimpan alamat memori yang menunjuk pada variabel lain. Tiga register lain yang memiliki kemampuan ini adalah SI, DI dan BP. CX (counter). Register CX bekerja sebagai counter untuk instruksi pengulangan atau looping. Isntruksi-instruksi tersebut secara otomatis mengulang dan mengurangi CX dan keluar ketika CX sama dengan 0. DX (data). Register DX mempunyai peranan khusus dalam operasi perkalian dan pembagian. Pada saat perkalian, contohnya, DX menyimpan 16 bit perkalian. Register segmen. CPU mengandung 4 register segmen, digunakan sebagai lokasi basis untuk instruksi program, data dan stack. Register segmen sebagai berikut : CS (code segment) : register CS menyimpan lokasi basis semua instruksi yang dapat dieksekusi dalam program. DS (data segment). Register DS adalah lokasi basis default untuk variabelvariabel CPU menghitung lokasi variabel-variabel menggunakan nilai segmen dalam DS. SS (stack segment). Register SS mengandung lokasi basis stack. ES (extra segment). Register ES adalah lokasi basis tambahan untuk variabelvariabel memori. Register index. Register index mengandung offset variabel. Istilah offset mengacu pada jarak variabel, label atau instruksi dari segmen basisnya. Register index memprecepat pemrosesan string array dan struktur data lain yang mengandung banyak elemen. Register-register index adalah : SI (source index). Register ini mengambil nama dari instruksi epmindahan string, yang mana string sumber ditunjuk oleh register SI. SI biasanya mengandung nilai offset dari register DS. DI (destination index). Register DI bekerja sebagai tujuan instruksi pemindahan string. Biasanya mengandung offset dari register ES, BP (base pointer). Register BP megnandung offset ??? dari register SS. ??? registeer BP sering digunakan oleh subrutin untuk melokasikan variabel-variabel yang dilewatkan pada stack oleh program pemanggil. Register khusus : register IP dan SP merupakan register khusus sebagai berikut : IP (instruction pointer). Register IP selalu mengandung offset instruksi berikutnya yang akan dieksekusi. CP dan IP digabung untuk melaksanakan alamat komplit instruksi berikutnya yang akan dieksekusi. SP (stack pointer). Register SP mengandung offset atau jarak dari awal stack ke puncak stack. Register SS dan SP bersama melakukan alamat lengkap puncak stack. Register tambahan 80386. prosesor 8038x/80486 mengandung register 32-bit (gb), yang meningkatkan efisiensi program pada penggunaannya. Pada saat yang sama juga 80386/80486 dapat menggunakan register 16-bit yang sama seperti 8088.
Register flag. Register flag adalah register 16-bit khusus dengan posisi bit sendiri dibuat untuk menunjukan status CPU atau hasil operasi aritmetik. Setiap posisi bit yang relevan diberi nama, posisi lain tidak didefinisikan. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 x x x x O D I T SZ xA x P x C O = Overflow D = Directione I = Interrupt T = Trap X = tidak terdefinisi
S = Sign Z = Zero A = Auxiliary Carry P = Parity C = Carry
Kita tidak harus mengingat setiap posisi flag karena terdapat instruksi khusus untuk menguji dan manipulasi flag. Terdapat dua tipe dasar flag yaitu control flag dan status flag.
31 ………………………….0
EBP ESP ESI EDI
EAX |-------AX -----| 31 ………………………….0 EBX |-------BX -----| 31 ………………………….0 ECX |-------CX -----| 31 ………………………….0 EDX |-------DX -----| Status dan Kendali 31 ………………………….0 EFLAG
|-----FLAG----|
CS SS DS ES FS GS
Code Stack
}
Data
31 ………………………….0 EIP |------- IP ------|
Gambar 2.4. Register Extended 80386 Flag Flag Kendali. Sebuah bit mungkin diset dalam flag oleh pemrogram untuk mengendalikan operasi CPU. Terdapat flag Direction, Interrupt, dan Trap. Flag Direction mengendalikan petunjuk asumsi yang digunakan oleh instruksi pemroses string. Nilai flag 1 = up dan 0 = down. Pemrogram mengendalikan flag ini, menggunakan instruksi STD dan CLD. Flag Interrupt membuatnya mungkin untuk terjadinya interrupt dari eksternal. Interrupt ini disebabkan oleh perangkat keras seperti keyboard, disk drive dan timer clock sistem. Seringkali kita menonaktifkan interrupt pada saat melaksanakan operasi yang krritis yang tidak dapat diinterrupt. Nilai flag 1 = aktif, dan 0 = tidak aktif. Flag ini dikendalikan oleh perintah CLI dan STI. Flag trap menentukan apakah CPU berhenti atau tidak setelah instruksi. Debugger telah menset flag ini sehingga pemrogram dapat menelusuri setiap instruksi programnya satu per satu. Nilai flag 1 = trap on dan 0 = trap off; flag dapat diset oleh instruksi INT 3. Flag status. Bit-bit flag status menggambarkan keluaran operasi aritmetik dan logic yang dilaksanakan oleh CPU. Terdapat flag Overflow, Sign, Zero, Auxiliary Carry, Parity dan Carry. Flag Carry diset ketika hasil operasi aritmetik tidak bertanda lebih besar dari ukuran operand tujuan. Contoh, jika nilai 200 dan 56 dijumlahkan dan ditempatkan dalam register 8-bit (seperti AL), hasilnya akan terlalu besar dan tidak muat ; maka flag Carry akan diset. Nilai flag 1 = ada carry, 0 = tidak ada carry. Flag Overflow diset pada saat hasil operasi aritmetik bertanda terlalu besar untuk dimuat ke dalam operand tujuan. Nilai flag 1 = overflow dan 0 = tidak overflow. Flag Sign diset ketika hasil operasi aritmetik dan logic menghasilkan nilai negatif. Karena bilangan negatif selalu bernilai 1 pada bit posisi tertingginya, flag Sign selalu merupakan salinan bit tanda operand tujuan. Nilai flag 1 = negatif, 0 = positif. Flag Zero diset ketika hasil operasi aritmetik dan logic menghasilkan nilai 0. Flag sering digunakan oleh instruksi jump dan loop, untuk dapat mencabang ke logasi bari dalam program berdasarkkan perbandingan dua buah nilai. Nilai flag 1 = nol , 0 = bukan nol. Flag Auxiliary Carry diset ketika operasi menyebabkan carry dari bitn 3 ke bit 4 (atau meminjam dari bit 4 ke bit 3) operand. Flag ini jarang digunakan oleh pemrogram, nilai flag 1 = ada carry dan 0 = tidak ada carry. Flag Parity menggambarkan jumlah bit dalam hasil operasi yang diset. Jika terdapat bilangan genap maka Paritynya genap. Jika terdapat bilangan ganjil maka
paritinya ganjil. Flag ini digunakan oleh sistem operasi untuk memeriksa integritas memori atau memeriksa kebenaran transmisi data oleh perangkat lunak komunikasi. Stack Stack adalah memori buffer khusus yang digunakan sebagai temporary yang menyimpan alamat dan data. Stack terletak dalam segmen stack. Setiap lokasi 16-bit pada stack ditunjuk oleh register SP, yang disebut stack pointer. Stack pointer menyimpan alamat elemen data terakhir yang ditambahkan (di-push) ke dalam stack. Nilai terkahir yang dimasukan ke dalam stack adalah nilai yang pertama diambil dari stack pada saat di pop. Mekanisme ini diistilahkan dengan struktur LIFO (last in first out), yang terakhir masuk keluar duluan. Kita lihat stack program yang mengandung satu nilai, 0006, pada bagian sebelah kiri ilustrasi dibawah ini. SP menunjuk pada nilai yang terakhir ditambahkan.
Sebelum (high memory) 0006
Sesudah (high memory) SP
0006 00A5
(low memory)
SP
(low memory)
Push. Operasi PUSH menyalin nilai ke dalam stack. Ketika kita mendorong (push) nilai ke dalam stack, seperti yang digambarkan oleh bagian kanan ilustrasi, SP dikurangi nilainya sebelum nilai baru di push. Contoh berikut menggambarkan operasi push : mov ax, 00A5 push ax Instruksi tidak mengubah isi AX, tetapi hanya menyalinnya dan memasukannya ke dalam stack.
Sejalan dengan penambahan nilai ke dalam stack maka stack semakin kearah bagian bawah memori. Misalkan register BX dan CX bernilai 0001 dan 0002. instruksi berikut menyalin nilainya ke dalam stack : push bx push cx
Sekarang nilai 0001 dan 0002 telah dimasukan ke dalam stack, akan terlihat sebagai berikut : Sesudah (high memory) 0006 00A5 0001 0002
SP
(low memory) Pop. Operasi POP mengeluarkan nilai dari stack dan menempatkannya dalam register atau variabel. Sesudah nilai diambil dari stack, nilai stack pointer ditambah satu untuk menunjuk pada nilai sebelumnya dalam stack. Misalkan kita akan mengeksekusi instruksi berikut : pop ax Ilustrasi kondisi stack sebelum dan sesudah operasi ini adalah sebagai berikut : Sebelum (high memory)
Sesudah (high memory)
0006
0006
00A5
00A5
0001
0001
0002
SP
(0002)
SP (AX = 0002)
Setelah operasi POP dilakukan, register AX mengandung nilai yang berasal dari puncak stack (0002). Stack pointer pindah ke nilai stack sebelumnya yaitu 0001. Nilai yang di ambil (0002) tidak lagi ada dalam stack. Terdapat tiga standar menggunakan stack : 1. Stack membuat daerah penyimpan sementara yang baik untuk register jika kita ingin memelihara nilainya. Kita dapat menggunakan register dengan bebas dan mengambil kembali nilainya dari stack setelah selesai operasinya. 2. Ketika subrutin dipanggil, program menyimpan nilai alamat kembali pada stack, lokasi dimana program harus kembali setelah subrutin selesai. 3. Bahasa tingkat tinggi membuat darerah pada stack dalam subrutin yang disebut frame stack. Ini berada pada daerah dimana variabel-variabel lokal dibuat pada saat subrutin aktif. Siklus Eksekusi Instruksi Sebuah instruksi level-mesin masih harus diuraikan dalam serangkaian mikroinstruksi. Instruksi tersebut dieksekusi oleh penerjemah dalam CPU yang disebut mikroprogam. Kebanyakan mikroprogram disembunyikan, dirahasiakan, oleh fabrik CPU, karena program tersebut akan memudahkan pesaing utt meniru fungsi chipnya. Ketika CPU mengeksekusi instruksi untuk menambah nilai sebuah bilangan, contohnya, mikroprogram harus melaksanakan operasi pada level yang lebih rendah : menghitung alamat operand, menempatkan alamat operand bada bus alamat, menunggu memori untuk merespon, transfer operand dari bus data ke ALU, dan seterusnya. Untuk menyederhanakan, tedapat tiga operasi dasar yang dilaksanakan dalam CPU : fetch, decode, dan execute. Setiap tahap dalam siklus instruksi memerlukan minimal satu clock sistem, yang disebut siklur clock. Fetch : Unit kendali mengambil instruksi, menyalinnya dari memori ke dalam CPU. Decode : Unit kendali menambah nilai (increment) program counter dan menerjemahkan instruksi. Jika operand lain ditentukan oleh instruksi, unit kendali menerjemahkan alamat operand tersebut dan mengambilnya. Kemudian mengirim operand ke dalam ALU.
Execute : ALU mengeksekusi operasi dan mengirim operand hasil ke unit kendali, dimana nantinya dikembalikan ke register dan memori. 2.3. Perangkat Lunak Sistem dan Memori Arsitektur Memori Intel 8086 dapat mengakses memori 1,048,576 byte ( 1 MB) menggunakan alamat 20-bit (00000 - FFFFF). Memori dibagi menjadi RAM dan ROM. RAM mulai pada lokasi 00000 sampai alamat BFFFF. ROM mulai lokasi C0000 sampai FFFFF. Dibawah DOS, hanya 640 K pertama RAM yang disiapkan untuk program. Memori sisanya diguankan oleh perangkat keras sistem seperti untuk display video dan pengendali hard disk, atau oleh ROM BIOS. Berikut ini peta memori pada Intel 8086 : Alamat (hex) 00000 00400
9FFFF A0000 B0000 B8000 C0000 FFFFF
Interrupt Vector Table DOS data area Software BIOS DOS kernel, Device Driver, Etc Bagian Resident COMMAND.COM
640 K RAM
Bagian Transient COMMAND.COM EGA/VGA Graphics Buffer MDA Text Buffer CGA/EGA/VGA Text Buffer Reserved ROM BIOS Gambar 2.5. Peta 1 MB pertama Memori PC
Inisialisasi DOS 1,024 byte Memori paling bawah (alamat 0000-003FF) mengandung tabel verktor interrupt. Ini berisi alamat-alamat yang digunakan oleh CPU ketika memroses interrupt perangkat keras dan perangkat lunak. Diatasnya terdaapt BIOS, yang didalamnya terdapat rutin-rutin untuk mengelola, keyboard, konsol dan printer dan clock tiap hari. Rutin-rutin tersebut berasar dari file sistem tersembunyi setiap kali disk boot memanggil IO.SYS (IBMBIO.COM). Kernel DOS berisi kumpulan layanan-layanan DOS yang dapat dipanggil dari
program aplikasi. Diatas kernel DOS terdapat buffer file dan file driver devaice yang dapat dipasang (diambail dari CONFIG.SYS), diikuti oleh bagian resident COMMAND.COM. Kemudian disebut pemroses perintah DOS : ini akan menintrrupt perintah yang ditulis pada promt DOS dan memanggil dan mengesekusi program yang disimpan dalam disk. Video Display Video display adalah dipetakan di memori. Dari pada mengirim setiap karakter video melalui port ke video display, lebih efisien untuk memberikan setiap posisi layar pada alamat memori yang terpisah. Ketika DOS menulis karakter ke layar, dia akan memanggil subrutin dalam ROM BIOS, yang langsung menulis karakter ke alamat memori video. Read-Only Memory (ROM) Lokasi memori alamat C0000h sampai FFFFFh disediakan untuk khusus penggunaan ROM, termasuk pengeendali hard disk dan ROM BASIC. ROM BIOS adalah bagian yang penting pada sistem operasi komputer. Di dalamnya tertadapat diagnosa sistem, dan perangkat lunak konfigurasi, seperti halnya subrutin input-output level bawah yang digunakan oleh DOS. BIOS dikodekan dalam chip mikroprosesor dalam borad sistem, yang dibuat oleh fabrik.
III. DASAR-DASAR BAHASA ASSEMBLY
3.1. Perintah Definisi Data Variabel adalah nama simbolik untuk lokasi dalam memori dimana data disimpan. Dalam bahasa assembly, variabel diidentifikasikan oleh label. Setiap label menunjukan lokasi awal variabel. Kita katakan bahwa offset label adalah jarak dari awal segmen ke awal variabel. Label, tidak menunjukan berapa banyak byte memori yang dialokasikan untuk bariabel. Contoh, jika kita mendeklarasikan array 4 karakter, lebel aList hanya mengidentifikasikan offset karakter awal (A) Disimpan sebagai
Deklarasi AList db ‘ABCD’
A
B
C
D
Isi
1
2
3
4
Offset
Jadi jika huruf awal pada offset 0, maka selanjutnya pada offset 1, 2 dan seterusnya. Kita menggunakan memori berdasarkan pada tipe yang didefinisikan sebelumnya : Deskripsi Define byte Define word Define doubleword Define far pointer Define quadword Define tenbytes
DB DW DD DF, DP DQ DT
Byte 1 2 4 6 8 10
Atribut Byte Word Dobleword Far pointer Quadword Tenbyte
Define byte (DB) Perintah DB mengalokasikan memori untuk satu atau lebih nilai 8-bit. Diagram sintak berrikut menunjukan bahwa nama adalah pilihan, dan hanya satu initial value yang diperlukan. Jika diperlukan lebih dari satu maka dipisahkan dengan koma : [name] DB initialvalue [, initialvalue] … Initial value dapat berupa satu atau lebih nilai angka 8-bit, konstanta string, ekspresi konstan atau tanda tanya (?). jika nilai bertanda maka rangenya –128 - + 127, jika tidak bertanda rengenya 0-255. berikut contohnya :
char signed1 signed2 unsigned1 unsigned2
db db db db db
‘A’ -128 +127 0 255
Nilai banyak (multiple values), daftar bilangan-bilangan 8-bit mungkin dikelompokan dibawah satu label, dengan nilai dipisahkan oleh koma. Pada contoh berikut, kita umpamakan bahwa daftar disimpan pada offset 0000. Ini artinya bawha 10 disimpan pada offset 0000, 20 pada offset 0001, 30 pada offset 0002, dan 40 pada offset 0003. List db 10, 20, 30, 40 Karakter dan integer adalah satu dan sama. Variabel berikut mengandung nilai yang sama dan mungkin diproses dengan cara yang sama : char db ‘A’ hex db 41h dec db 65 bin db 01000001b oct db 101q Setiap konstanta mungkin menggunakan radix yang berbeda ketika daftar item didefinisikan, dan angka, karakter dan konstanta string mungkin dicampur secara bebas. Jika nomor heksadesimal mulai dengan huruf (A-F), maka nol diawal ditambahkan untuk membedakannya dengan label. Dalam conoh ini, list1 dan list2 mempunyai isi yang sama : list1 list2
db db
10, 32, 41h, 00100010b 0Ah, 20h, ‘A’, 22h
Isi variabel mungkin tidak didefinisikan, untuk hal seperti ini menggunakan operator tanda tanya (?). atau ekspresi bilangan dapat memberi nilai awal sebuah variabel dengan nilai yang dihitung pada saat diassembly. Contoh : count db ? ages db ?,?,?,?,? rowsize db 10*20 Varibel dapat diberi nilai string dimana variabel merupakan alwam byte awal. Contoh berikut menunjukan satu string diakhiri oleh byte nol (mengandung 0), dan string lain dengan panjangnya ditulis pada awal byte : c_string db “Good afternoon”, 0
pascal_string db 14, “Good afternoon” Perintah DB adalah perintah yang digunakan untuk menyimpan satu atau lebih baris teks. Variabel tunggal mungkin dilanjutkan untuk banyak baris tanpa perlu membuat label untuk masing-masing baris. String berikut diakhiri oleh akhir baris dan byte null : a_long_string db “This is a long string, that” db “clearly is going to take” db “several lines to store in an” db “assembly language program”, 0Dh, 0Ah, 0 Assembler dapat menghitung panjang string secara otomatis. Dengan menggunakan karakter $ yang menyimpan lokasi sekarang nilai counter. Pada contoh berikut a_string_len diset awal 16 : a_string db “This is a string” a_string_len db $- a_string Define Word (DW) Perintah DW membuat tempat penyimpan untuk satu atau lebih word 16-bit. Sintaknya adalah sebagai berikut [name] DW initialvalue [, initialvalue] … Initialvalue mungin berupa nilai bilangan 16-bit dari 0 – 65,535 (FFFFh). Jika initialvalue bertanda, range yang dapat diterima adalah dari –32,768 (8000h) sampai +32,767 (7FFFh). Konstanta karakter mungkin disimpan pada bagian bawah word. Kontanta string yang besar yang mungkin disimpan dalam word panjangnya 2 karakter, seperti ‘AB’. Mungkin juga membiarkan variabel tidak terinisiaslisasi dengan menggunakan operator (?). Pembalikan Format Penyimapan (Reversed Storage Format). Assembler membalik byte dalam nilai word ketiak disimpan dalam memori. Byte paling bawah berada pada alamat paling bawah. Ketika variabel dipindahkan ke register 16-bit, CPU akan membalik kembali byte tersebut. Ini ditunjukan pada ilustrasi berikut, dimana 2AB6h disimpan dalam memori sebagai B6 2A. Deklarasi data : Penyimpanan :
value1 dw 2AB6h
B6
2A
Berikut ini tambahan contoh untuk DW. Seperti pada DB, tanda tanya memerintahkan assembeler untuk tidak menginisialisasi loakasi memori dengan nilai tertentu : dw 1, 2, 3 ; mendefinisikan 3 word dw 0,65535 ; bilangan tidak bertanda tertendah dan tertinggi dw –32768, +32767 ; bilangan bertanda terendah dan tertinggi dw 256*2 ; ekspresi kontanta dw 4000h ; notasi heksadesimal dw 1111000011110000b ; notasi biner dw 1000h, 4096, ‘AB’, 0 ; notasi campuran dw ? ; word tunggal tidak diinsialisasi Pointer. Offset variabel atau subrutin mungkin disimpan dalam variabel lain yang disebut pointer. Pada contoh berikut, assembler menset P ke offest list. Kemudian PI mengandung alamat P. Akhirnya, aProc mengandung offset label yang disebut Clear_screen : list P P2 aProc
dw dw dw dw
256, 257, 258, 259 list P clear_screen
Define Doubleword (DD) Perintah DD membuat tempat penyimpan untuk satu atau lebih doublewords 32-bit. Sintaknya sebagai berikut : [name] DD initialvalue [, initialvalue] … Initialvalue dapat berupa nomor biner sampai 0FFFFFFFFh, alamat segmet-offset, 4byte bilangan real, atau bilangan real desimal. Byte-byter dalam variabel doubleword disimpan dengan urutan terbalik, sehingga digit yang paling berarti disimpan pada alamat paling bawah. Contoh, nilai 12345678h akan disimpan dalam memori sebagai : Offset : 00 01 02 03 Nilai : 78 56 34 12 Anda dapat mendefinisikan satu atau leibh doubleword. Dalam contoh berikut, far_pointer1 tidak diinsialisasi. Assembler langsung menginisialisasi far_pointer2 dengan 32-bit alamat segment offset subroutine1 :
signed_val far_pointer1 far_pointer2
dd dd dd
-2147483648 ? subroutine1
Operator DUP Operator DUP hanya tampil sessudah perintah pengalokasian memori (DB, DW, DD, DQ, DT). Dengan DUP, anda dapat mengulang satu atau lebih nilai ketika mengalokasian memori. Ini khususnya berguna ketika pengalokasian ruang untuk tabel atau array. Contoh-contoh berikut menginisialisasi tempat penyimpan dengan nilai default : db 20 dup (0) db 20 dup (?) db 4 dup (‘ABC’) db 4096 dup (0) dw 5 dup (1000h) dw 5 dup (?) dd 100h dup(?)
; 20 byte semuanya sama dengan nol ; 20 byte tidak diinisialisasi ; 12 byte : “ABCABCABCABC” ; 4096-byte , semuanya nol ; 5 word, masing-masing sama dengan nol ; 5 word, tidak diinisialisasi ; 256 doublewordk (1024 byte)
Operator DUP mungkin juga bersarang. Contoh pertama yang membuat tempat penyimpan yang mengandung 000XX000XX000XX000XX. Contoh kedua membuat tabel word dua dimensi dengan 3 baris dan 4 kolom. aTable db 4 dup ( 3 dup(0), 2 dup(‘X’)) aMatrix dw 3 dup (4 dup(0)) Pemeriksaan tipe. Ketika variabel dibuat dengan menggunakan DB, DW, DD atau perintah definisi data yang lain, assembler memberinya atribut asal (byte, word, doubleword) berdasarkan ukurnya. Tipe ini dicek ketika anda merujuk pada variabel tersebut, dan akan terjadi kesalahan jika tipenya tidak sesuai. Contohnya, anda ingin memindahkan byte paling rendah varibel 16-bit ke dalam register 8-bit. Instruksi MOV berikut akan salah karena count bertipe word dan AL adalah byte : mov al, count … …. count dw 20h
; error : ukuran operand harus cocok
Pemeriksaan tipe seperti itu bagus karena membantu untuk menghindari kesalahan logika. Jika diperlukan anda dapat menggunakan perintah LABEL untuk membuat nama baru (dan tipe data) pada alamat yang sama. Sekarang variabel dapat diakses menggunakan nama juga :
mov al, count_low mov cx, count … … count_low label byte count dw 20h 3.2. Instruksi Transfer Data Instruksi MOV Karena MOV menyalin data dari satu operand ke operand lain, maka ini disebut instruksi transfer data. Pada prosesor 8086 dan 80286, operandnya 8 atau 16 bit. Pada 80386 dan 80486, operand 32-bit juga mungkin digunakan. Sintaknya sebagai berikut : MOV tujuan, sumber Data benar-benar disalin sehingga operand sumber tidak berubah. Sumber mungkin berupa nilai, register, atau operand memori. Tujuan mungkin berupa nilai, register atau operand memori. Tujuan mungkin berupa register atau operand memori. Operand Register. Pemindahan hanya melibatkan register, ini paling efisien. Satu register berperan sebagai operand sumber, dan yang lainya, selain CS dan IP berperan sebagai operand tujuan. Operand immediate. Nilai langsung (konstanta integer) mungkin dipindahkan ke suatu register (kecuali register segemen atau IP) dan mungkin dipindahkan ke memori. Kesalahan umum disebabkan nilai lebih besar daripada operand tujuan. Operand langsung. Variabel mungkin salah satu (tapi tidak keduanya) operand dalam instruksi MOV. Isi variabel mungkin sumber atau tujuan move. Contoh MOV dengan semua tiga tipe seperti berikut : mov al, bl mov dx, cx mov bl, 1 mov bx, 8FE2h mov al, count mov total, ax mov total, 1000h … … count db 10 total dw 0
Operand mempunyai sedikit keterbatasan, yang berdasarkan rancangan fisik pemroses dan set instruksinya. Berikut ini tidak diperbolehkan : - CS atau IP sebagai register tujuan - Memindahkan data immediate ke register segmen - Memindahkan dari register segmen ke register segmen - Perbedaan ukuran antara operand sumber dan tujuan - Nilai immediate sebagai tujuan - Perpinadahan dari memori ke memori Contoh pemindahan yang tidak diperbolehkan : mov ip, ax mov ds, 1000h mov ds, es mov al, bx mov si, al mov word_1, al mov 1000h, ax mov word_2, word_1 … … word_1 dw word_2 dw
; ip sebagai tujuan ; immediate ke segmen ; segmen ke segmen ; ukuran operan tidak sama ; ukuran operan tidak sama ; ukuran operan tidak sama ; immediate sebagai tujuan ; memori ke memori 1000h 0
Offset Anda dapat menambahkan offset pada operand memori. Dengan ini maka anda dapat mengakses nilai data yang tidak mempunyai label. Misalkan kita punya daftar nomor 8-bit yang disebut array. Kemudian array+1 adalah nama yang mengacu pada offset 1 byte lebih dari array. Keduanya, array dan array+1 mempunyai offset yang dihitung oleh assembler sebagai offset fixed dari permulaan segemen data. Alamatalamat tersebut digunakan untuk mengakses memori pada offset yang diberikan, seperti contoh berikut : . data array db 10, 20, 30, 40, 50 . code mov al, array mov dl, array+1 mov dh, array+4
; isi = 10 ; isi = 20 ; isi = 50
Ukuran atribut kedua operand harus sesuai. Dalam contoh berikut, int_1 hanya dapat dipasangkan dengan register 16-bit. Juga, byte_1 hanya dapat dipasangkan dengan register 8-bit :
. data int_1 dw 1000h byte_1 db 10h . code mov ax, int_1 mov int_1, si mov al, byte_1 mov byte_1, dl Operator PTR. Biasanya kita menggunakan operator PTR untuk mengetahui tipe operand. Nama PTR tidak benar kalau dimaksudkan penggunaan pointer – ini bernar-benar mengidentifikasikan atribut operand memori. Pada contoh berikut, WORD PTR mengidentifikasikan count sebagai variabel berukuran word, dimana BYTE PTR mengidentifikasikan var2 sebagai operand 8-bit. mov word ptr count, 10 mov byte ptr var2, 5 Perintah XCHG Perintah XCHG menukarkan isi dari dua register atau antara register dengan variabel. Sintaknya sebagai berikut : XCHG op1, op2 Dua operand mungkin register atau operand memori, selama satu operandnya register. XCHG adalah cara yang efisien untuk menukarkan dua operand 8-bit atau 16-bit karena tidak memerlukan register ketiga untuk menyimpan nilai sementara. Khususnya dalam aplikasi pengurutan, instruksi ini mempunyai keuntungan karena kecepatannya. Satu atau kedua operand mungkin register, atau register mungkin dikombinasikan denan operand memori. Dua operand memori tidak boleh digunakan secara bersamaan. Contoh berikut adalah contoh yang benar : xchg ax, bx xchg ah, al xchg var1, bx Operasi stack Stack adalah buffer memori khusus yug digunakan untuk program aplikasi dan DOS. Dua register berperan dalam stack : register SS (stack segment) mengandung lokasi basis stack; register SP (stack pointer) mengandung alamat puncak stack, dimana nilai terakhir dimasukan. Beberapa istilah yang terdapat pada stack : operasi PUSH adalah meletakan nilai baru pada stack dan mengurangi nilai stack pointer; stack bergerak kearah bawah
dalam memori setiap nilai baru dimasukan. Operai POP mengeluarkan data dari stack dengan menyalin words kedalam register atau operand memori dan menambah nilai stack pointer. Setiap inputan stack panjangnya 2 byte, jadi hanya operand 16-bit yang mungkin dimasukan atau dikeluarkan. DOS membagi stack dengan program aplikasi, jadi ruang memori yang cukup harus disiapkan untuk menyediakan keduanya. Biasanya kita menggunakan 256 byte, menggunakan perintah .STACK. Instruksi PUSH. Instruksi PUSH mengurangi register SP dan menyalin isi register atau operand memori 16-bit kedalam stack pada lokasi yang ditunjuk oleh SP. Hanya pada prosesor 80286 atau yang lebih tinggi anda dapat memasukan nilai immediate. Berikut ini contoh penggunaanya : push ax push memval push 1000h Instruksi PUSH bisa digunakan untuk menyimpan nilai register sementara, untuk suatu saat diambil kembali. Instruksi POP. Instruksi POP menyalin isi stack yang ditunjukan oleh SP ke dalam register 16-bit atau variabel, dan menambah SP. Dua register, CS dan IP, tidak boleh digunakan sebagai operand. Contoh POP seperti terlihat dibawah ini. pop cx pop memval Menyiman dan mengambil kembali nilai register. Berbagai cara bisa dilakukan jika sebuah register akan digunakan ulang. Pada contoh berikut, pemanggilan DOS (int 21h) untuk menampilkan string pada layar. DX dan AX diasumsikan mempunyai nilai penting yang harus disimpan kembali sesudah tampilan. Karena stack berstruktur LIFO (last in first out) maka register yang terakhir disimpan pertama kali : push ax push dx mov ah, 9 mov dx offset message int 21h pop dx pop ax … … message db “Ini adalah pesan.$”
PUSHF dan POPF. Instruksi PSUHF memasukan register flag ke dalam stack, menjaganya agar tidak terjadi perubahan. Pada lain waktu, instruksi POPF dapat digunakan untuk mengembalikan nilai flag. Contoh berikut, kita menyimpan flag sebelum memanggil subrutin yang mungkin mengubah flag. 3.3. Instruksi Aritmetik Hampir semua program komputer dapat melaksanaklan operasi aritmetik. Set intruksi Intel mempunyai instruksi untuk aritmetik integer, menggunakan operand 8bit dan 16-bit. Operasi floating-point ditangani dalam salah satu dari ketiga cara berikut : 1. Chip koprosesor matematika khusus (8087, 80287, 80387). 2. Rutin perangkat lunak yang berfungsi sama dengan koprosesor, atau 3. Perangkat lunak yang mengkonversi nilai floating-point ke integer, menghitung, dan kemudian mengkonversi bilangan kembali ke floating-point. Instruksi INC dan DEC Instruksi INC dan DEC menambah 1 atau mengurang 1 nilai dari suatu operand, secara berurutan. Sintaknya sebagai berikut : INC tujuan DEC tujuan Tujuan mungkin register 8-bit atau 16-bit atau operand memori. INC dan DEC lebih cepat dari instruksi ADD dan SUB. Semua status flag dipengaruhi kecuali flag Carry. Contohnya sebagai berikut : inc al dec bx inc membyte dec byte ptr membyte dec memword inc word ptr memword Instruksi ADD Instruksi ADD menjumlahkan operand sumber 8 atau 16-bit ke operand tujuan pada ukuran yang sama. Sintaknya sebagai berikut : ADD tujuan, sumber Sumber tidak diubah oleh operasi. Ukuran operand harus sesuai dan hanya satu operand memori yang digunakan. Register segment tidak boleh jadi tujuan. Semua status flag dipengaruhi. Contoh sebagai berikut : add al, 1 add cl, al
add bx, 1000h add var1, ax add dx, var1 add var1, 10 Instruksi SUB Instruksi SUB mengurangkan operad sumber dari operand tujuan. Sintak SUB sebagai berikut : SUB tujuan, sumber Ukuran kedua operand harus sesuai, dan hanya boleh satu operand memori. Register segment tidak boleh jadi operand tujuan. Pada level bit, yang terjadi adalah operand source dinegasikan kemudian ditambahkan ke tujuan. Contoh, 4-1 adalah 4+(-1). Mengingat kembali bahwa notasi twos komplemen digunakan untuk menegasikan bilangan, jadi –1 disimban sebagai 11111111b : 0 0 0 0 0 1 0 0 (4) + 1 1 1 1 1 1 1 1 (-1) 0 0 0 0 0 0 1 1 (3) Penjumlahan ini menghasilkan carry pada bit yang paling tinggi (menset carry flag), tetapi carry sendiri diabaikan ketika bekerja dengan bilangan bertanda. Contoh SUB digunakan denganb berbagai tipe operand seperti berikut : sub al, 1 sub cl, al sub bx, 1000h sub var1, ax sub dx, var1 sub var1, 10 Flag yang dipengaruhi oleh ADD dan SUB Jika ADD atau SUB menghasilkan nilai nol, maka flag zero di set; jika hasil negatif maka flag tanda di set. Pada contoh beirkut, baris 2 menghasilkan nilai nol dan baris 4 menghasilkan nilai –1 (FFFFh) . mov ax, 10 sub ax, 10 mov bx, 1 sub bx, 2 Flag zero diset ketika hasil operasi aritmetik sama dengan nol. Catatan bahwa INC dan DEC mempengaruhi flag zero tapi tidak mempengaruhi flag carry :
mov bl, 4Fh add bl, 0B1h mov ax, 0FFFFh inc ax Keputusan kapan operand bertanda atau tidak bertanda seluruhnya diserahkan kepada pemrogram. CPU memperbaharui flag Carry dan overflow untuk menangani dua kemungkinan. Untuk alasan ini, kita perlu membahas dua tipe operasi secara terpisah. Operasi tidak bertanda (unsigned). Untuk aritmetika tidak bertanda, kita hanya peduli pada flag carry. Jika hasil operasi penjumlahan terlalu besar untuk operand tujuan, maka flag carry diset. Contoh, penjumlahan 0FFh + 1 seharusnya sama dengan 100h, tapi hanya dua digit paling bawah (00) yang pas untuk AL. maka operasi menset flag carry : mov ax, 00FFh add al, 1
; AX = 0000, CF = 1
Dalam kontek ini, ADD adalah operasi 8-bit karena AL yang digunakan. Jika kita ingin mendapatkan jawaban yang benar maka kita harus menambah 1 AX, membuatnya menjadi operasi 16-bit. mov ax, 00FFh add ax, 1
; AX = 0100, CF = 0
Situasai yang sama juga terjadi ketika kita mengurangkan operand yang lebih besar (2) kepada yang lebih kecil (1). Flag carry memberitahu kita hasilnya tidak berguna. mov ax, 5501h add ax, 2
; AX = 55FF, CF = 1
Operasi bertanda. Flag overflow diset ketika operasi penjumlahan atau pengurangan menghasilakan bilangan bertanda diluar range. Contoh 1 : mov al, + 126 add al, 2 Contoh 2 : mov al, -128 sub al, 2
01111110 + 00000010 10000000
AL = -128 ?, OF =1
10000000 - 00000010 01111110
AL = + 126?, OF = 1
3.4. Mode Pengalamatan Kumpulan instruksi Intel menyediakan cara yang bervariasi untuk menemukan lokasi memori – cara-cara ini disebut mode pengalamatan. Dengan cara ini dapat memudahkan pemrosesan list dan untuk mengacu struktur data yang komplek. Juga, kompile bahasa tingkat tinggi memerlukannya untuk membuat instruksi mesin yang lebih sedikit ketika set instruksi CPU menggunakan cara yang baik dalam pengacuan data. Terdapat lima tipe mode pengalamatan, ditunujukan dalam tabel mode pengalamatan dibawah. Dalam tabel, dispalecement berupa angka atau offset variabel. Effective address operand mengacu pada offset (jarak) data dari awal segment. BX dan BP adalah register basis, dan SI dan DI adalah register index. Setiap contoh berikut mengacu pada isi memori pada alamat efektif.
Mode pengalamatan Contoh
Mode
Keterangan Alamat efektif adalah displacement
Direct
Op1 bytelist [200]
Register Indirect
[bx] [si] [di]
EA adalah isi basis atau index
Based or Indexed
list [bx] [si+list] [bp+4] list [di] [bp-2]
EA adalah penjumlahan register basis atau index dengan displacement
Base-indexed
[bx + si] [bx][di] [bp-di]
EA adalah penjumlahan register basis dan register index
Base-indexed with displacement
[bx+si+2] list[bx+si] list [bx][si]
EA adalah penjumlahan register basis, register index dan dispalcement
Operand register Operand register mungkin berupa register 8 atau 16 bit. Secara umum, mode pengalamatan register adalah paling efisien karena register adalah bagian dari CPU
dan tidak diperlukan pengaksesan memori. Beberap contoh menggunakan instruksi MOV sebagai berikut : mov ax, bx mov cl, al mov si, ax Operand Immediate Operand immediate adalah ekspresi konstan, seperti angka, karakter atau ekspresi aritemetik. Assembler harus menentukan nilai operand immediate pada waktu asssembly. Nilainya disisiplak langsung kedalam instruksi mesin. Contoh operand immediate ditunjukan sebagai berikut. Contoh terkahir, (2+3)/5, adalah ekspresi yang dievaluasi apda saat assembly. Contoh 10 ‘A’ ‘AB’ 65535 (2+3)/5
Ukruan (bit) 8 8 16 16 8
Operand direct Operand direct mengacu pada isi memori pada offset variabel. Assembler menjaga nilai offset setiap label, membuatnya memungkinkan untuk menghitung alamat efektif operand direct. Pada contoh ini, isi memori pada lokasi count dipindah ke AL : count db 20 … … mov al, count
; AL = 20
Oprator OFFSET. Ketika diperlukan pemindahan offset label ke dalam register atau variabel, maka digunakan operator OFFSET. Karena assembler mengetahuai offset settiap label sebagai program yang sedang diassembly, maka mudah untuk menggantikan nilai offset kedalam isntruksi. Misalkan offset variabelaWord dalam contoh berikut adalah 0200h; instruksi MOV akan memindahkan 200h ke dalam BX langsung : aWord dw 1234 … mov bx, offset aWord Operand tidak langsung Jika offset variabel ditempatkan dalam register basis atau index, maka register menjadi pointer ke label. Untuk variabel yang mengandung element tunggal, maka
dia akan mempunyai nilai yang kecil, tetapi untuk daftar item, pointer mungkin akan ditambah untuk menunjuk setiap elemen. Contoh, jika kita membuat string dalam memori pada lokasi 0200h dan menset BX ke offset string, kita dapat memproses elemen dalam string dengan menjumlahkan offsetnya dengan BX. F terakhir berada pada offset 5 dalam contoh berikut : CODE : aString db “ABCDEFG” … … mov bx, offset aString add bx, 5 mov dl, [bx]
; BX = 0200 ; BX = 0205 ; DL = ‘F’
Ilustrasi 0200 A B C
D E F G … … …
aString
[bx]
Default segmen. Jika BX, SI atau DI digunakan, alamat efektif adalah default offset dari register DS (data segment). BP, disisi lain, merupakan offset dari register SS (Stack segment). Umpamanya segment stack dan segment data berada pada lokasi yang berbeda, dua pernyataan berikut akan menimbulkan efek yang berbeda : mov dl, [si] mov dl, [bp] Based dan Indexed Operand Operannd basis dan indeks pada dasarnya sama : register ditambahkan pada displacement untuk mendapatkan alamat efektif. Register yang dipakai harus SI, DI, BX atau BP. Displacement adalah angka atau label yang offsetnya diketahui pada waktu assembly. Notasi mungkin dalam bentuk yang sama : Register ditambahkan ke offset : mov dx, array[bx] mov dx, [di+array] mov dx, [array+si] Register ditambahkan ke konstanta : mov ax, [bp+2] mov dl, [di-2] mov dx, 2[si]
Contoh. Jika kita membuat array bernilai byte yang disimpan dal memori logaksi 0200h dan menset BX dengan 5, maka BX akan menunjuk bialngan pada offset 5 ke dalam array. Contoh berikut ini sebagai ilustrasi : Code : array db 2,16,4,22,13,19,42,64,44,88 … … mov bx, 5 mov al, array[bx] ilustrasi : 02 16 04 22 13 19 42 … … …
array
[BX] (BX = 0005)
Base-Indexed Operand Alamat efektif operand dibangun oleh penggabungan register basis dengan register index. Misalkan BX = 2002h dan SI = 6; instruksi berikut akan menghitung alamat efektif 208h : mov al, [bx +si] Teknik ini sering berguna untuk array dua dimensi, dimana BX dapat menunjuk offset baris dan SI offset kolom. Contoh berikut, alamat efektif yang dibangun oleh [bx+si] adalah 0157 : CODE : array db 10, 20, 30, 40, 50 db 60, 70, 80, 90, A0 db B0, C0, D0, E0, F0 …. mov bx, offset array ; menunjuk pada array (0150) add bx, 5 ; memilih baris kedua mov si, 2 ; memilih kolom ke tiga mov al, [bx + si] ; mengambil nilai pada alamat efektif 0157 Ilustrasi 0150 10 20 30 40 50 60 70 80 90 … … …
[BX]
[SI]
Dua buah register basis atau dua buah register index tidak dapat digabungkan, jadi contoh berikut akan salah : mov dl, [bp-bx] mov ax, [si-di]
; salah : dua register basis ; salah : dua register index
Base-Indexed dengan displacement Alamat efektif operand dibangun dengan menggabungkan register basis, register index dan displacement. Contohnya sebagai berikut : mov dx, array [bx] [si] mov ax, [bx + si + array] add dl, [bx + si + 3] sub cx, array [bp+si] Dengan menggunakan array dua dimensi kita tidak harus lagi menset BX ke awal array. Kita hanya menset BX pada offset baris kedua, relatif terhadap awal tabel. Ini akan menyebabkan kode lebih sederhana : CODE : array db 10, 20, 30, 40, 50 db 60, 70, 80, 90, A0 db B0, C0, D0, E0, F0 …. mov bx, 5 ; memilih baris kedua mov si, 2 ; memilih kolom ke tiga mov al, array[bx + si] ; mengambil nilai pada alamat efektif 0157
Ilustrasi 0150
0155
0157
10 20 30 40 50 60 70 80 90 … … … [BX]
[SI]
Penjumlahan serangkaian bilangan Contoh program berikut menunjukan bagaimana bermacam-macam mode pengalamatan bisa digunakan ketika mengakses elemen sebuah array. Array berada pada offset 150, dan hasil penjumlahan akan disimpan pada offset 153. Program berikut mungkin diassemble dan dijanlankan dalam Debug. A 150 db 10, 20, 30, 0 A 100 mov bx, 150 mov si, 2 mov al, [bx] add al, [bx+1] add al, [bx + si] mov [153], al int 20 t . . d 150, 153
3.5. Struktur Program Gambar 3.1. menunjukan program HELLO.ASM. Perintah untuk mengassembly dan link program ini ditunjukan oleh turbo assembler dan microsoft assembler sebagai berikut : Turbo Assembler tasm hello; tlink hello;
MASM masm hello; link hello;
Segment. Program yang jalan di DOS dibagi kedalam tiga segmen utama, masingmasingnya memiliki nilai tipe yang berbeda : segmen Code (ditunjukan oleh CS) mengandung kode program, segmen Data (ditunjukan oleh DS) mengandung variabel, segmen stack (ditunjukan oleh SS) mengandung stack program. Setiap segmen ditunjukan oleh register segmen. Sebuah segmen mungkin hanya 1 paragraf (10h byte) dan paling besar 64 K bytes. Setiap segmen mengandung instruksi atau data yang memiliki offset relatif terhadap register segmen (CS, DS, SS, atau ES). Offset adalah jarak objek dari permulaan segmennya.
Title Program Hello world ; program ini menampilkan pesan “Hello, world” dosseg . model small . stack 100h . data . hello_message db ‘Hello, world !’, 0dh, 0ah, ‘$’ . code main proc mov ax, @data mov ds, ax mov ah, 9 mov dx, offset hello_message int 21h mov ax, 4000h int 21h main endp endp main
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24]
Gambar 3.1. Contoh program Hello Segmen code. Segmen code adalah dimana instruksi mesin program berada. Register CS mengandung alamat segmennya, dan IP menunjuk instruksi pertama yang akan dieksekusi. Segmen data baisanya mengandung variabel program. Catatan bahwa tidak ada register yang menunjukan segmen ini, karena itu pada setiap program EXE dimasukan baris program berikut, untuk menset DS sebagai permulaan segmen data : mov ax, @data mov ds, ax Segmen stack. Asegmen stack mengaikuti .MODEL, dan biasanya kita menyediakan 256 byte ruang stack. Register SS mengandung alamat segmen ini, dan SP mengacu pada alamat berikutnya setalah akhir stack. Stack akan bertambah kearah bawah pada saat suatu nilai dimasukan ke dalam stack. Jika SP mencapai 0000, maka stack berarti penuh. Perintah. Perintah TITLE mendefinisikan judul prgram sampai 128 karakter. Perintah DOSSEG memberitahu assembler untuk menempatkan segmen program dalam urutan standar yang digunakan bahasa tingkat tinggi.
Model memori Perintah .MODEL memilih standar model memori untuk program bahasa assembly. Model memory mungkin sebagai blueprint standar atau konfigurasi, yang menentukan bagaimana segmen dihubungkan bersama. Setiap model memori memiliki sekumpulan batasan yang berbeda sebagai maksimum ruang yang tersedia untuk kode dan data. Secara umum, pemilihan model memori berarti membuat pilihan antara kecepatan eksekusi optimal dan fleksibilitas ukuran program. Model memori yang membatasi semua data ke segmen tunggal 64 K, contohnya, menjamin bahwa semua alamat data akan dekat, yaitu, 16-bit nilai. Data mungkin dapat diakses lebih cepat, karena alamat 16-bit mungkin diload dengan satu instruksi mesin. Disisi lain, model memori yang mengijinkan kode untuk diperluas sampai 64 K berakibat bahwa beberapa subrutin akan berada pada segmen yang berbeda. Ini berarti bahwa alamat 32-bit harus diload kedalam CS dan register IP ketika subrutin dipanggil. Hal ini membutuhkan dua instruksi mesin. Berbagai macam memori model didefinisikan oleh jumlah byte yang digunkan untuk kode (instruksi) dan data (variabel). Tabel berikut menunjukan rangkuman perbedaan antara berbagai tipe model : Model Tiny Small Medium Compact Large Huge
Penjelasan Kode dan data digabung harus <= 64 K Kode <= 64 K, data <= 64 K Data <= 64 K, kode ukuran sembarang Kode <=64 K, data ukuran sembarang Keduanya lebih besar dari 64 K Sama seperti model LARGE hanya array boleh lebih dari 64 K
Semua model keculai model Tiny menghasilkan program EXE. Model Tiny menghasilkan program COM. Peta file program Hello : Start 00000H 00020H 00030H
Stop 00010H 0002FH 0012FH
Length 00011H 00010H 00100H
Name _TEXT _DATA STACK
Class CODE DATA STACK
Diagram segmen : Misalkan program diload pada alamat absolut 20000 : Segmen Code
Alamat Absolut 20000 (20h byte)
Nilai Register Segmen 2000
Data
20020
2002
(10h byte) Stack
20030
2003
(100h byte) Gambar 3.2. Struktur segmen Hello.exe Program yang dapat dieksekusi (Executable program). Untuk mendapatkan gambaran yang lebih baik tentang program yang dapat dieksekusi setelah diisikan oleh DOS ke dalam memori, lihatlah gambar 3.2. yaitu prgram HELLO.ASM, yang diassemble dan dilink ke bentuk HELLO.EXE. Linker dapat menghasilkan file MAP, yang dengan baik menunjukan offset dan ukuran segmen program. Dalam contoh ini, segmen kode adalah 11h bytee, segemen datanya 10h byte, dan panjang stacknya 100h byte.
IV. LAYANAN MASUKAN/KELUARAN (INPUT/OUTPUT)
4.1. Prosedur Dalam istilah umum, prosedur adalah suatu blok instruksi yang secara logis berkaitan yang mungkin dipanggil oleh program atau prosedur lain. Dalam rancangan program yang baik, setiap prosedur mempunyai suatu tujuan dan leakukan tugasnya tidak tergantung pada program lain. Prosedur dapat digunakan berulang-ulang tergantung keperluan. Dalam bahasa tingkat tinggi, fungsi adalah subrutin yang mengembalikan hasil, sedangkan prosedur tidak. Kata subrutin mengacu pada suatu blok instruksi yang mungkin dipanggil dari tempat lain seperti halnya prosedur. Kata prosedur dan subrutin sering dipakai secara bergantian. Perintah PROC dan ENDP Dalam bahasa assembly perintah PROC dan ENDP menandai awal dan akhir prosedur. Program HELLO.ASM dibawah, contohnya, mempunyai prosedur yang dinamai main. Disamping itu terdapat juga prosedur call_me. Dalam prosedur main terdapat perintah call untuk memanggil prosedur call_me. Pada akhir prosedur call_me terdapat perintah ret yang berguna untuk memaksa prosedur kembali ke prosedur yang memanggilnya. .code main PROC … mov ax,1 mov dx, ax call call_me … … main ENDP call_me PROC .. mov cx, 2 mov bx, 3 … … call_me ENDP Gambar 4.1. Contoh prosedur call Contoh program : SUBS.ASM
Berikut ini contoh program yang memanggil 2 subrutin : prosedur input_char memasukan karakter dari keyboard dan mengembalikannya ke dalam AL. Prosedurnya sangat sederhana, karena hanya mengandung 2 instruksi yang diperlukan untuk memanggil fungsi 1 DOS (input keyboard). DOS otomatis mengembalikan karakter ke dalam AL, jadi nilai akan tersimpan disana ketika input_char kembali ke pemanggilnya, main. title Demonstrasi subrutin dosseg . model small . stack 100h . data char db ? array dw 100h, 200h, 300h, 400h, 500h array_size equ 5 sum dw ? . code main proc mov ax, @data mov ds, ax call input_char mov char, al mov bx, offset array mov cx, array_size call calc_sum mov sum, ax mov ax, 4000h int 21h main endp calc_sum proc push bx push cx mov ax, 0 cs1 : add ax, [bx] add bx, 2 loop cs1 pop cx pop bx ret calc_sum endp
end main Gambar 4.2. Demonstrasi pemanggilan subrutin Prosedur calc_sum menghitung jumlah isi array integer sampai 65,535 integer. Untuk memanggilnya, main menempatkan offset array dalam bx dan menghitung jumlah elemen dalam cx. Pemberian nilai dalam register yang sebelumnya ditentukan adalah protokol pemanggilan. Program pemanggil harus menyesuaikan dengan keperluan subrutin yang dipanggil, dengan keuntungan subritin calc_sum dapat digunakan berulang kali oleh pemanggil. Prosedur NEAR dan FAR Pemanggilan prosedur NEAR. Ketika pemanggil dan subrutin berada dalam segmen program yang sama, assembler membuat kode mesin untuk near Call. Sebelum mencabang ke subrutin, instruksi call menyimpan nilai IP sekarang ke dalam stack. Kemudian mengambil offsett subrutin ke dalam IP. Pada akhir subrutin, instruksi RET mengambil kembali nilai IP dari stack ke dalam IP dan meneruskan eksekusi dimana instruksi call berada. Gambar 4.3. menunjukan pemanggil prosedur near dengan contoh offset. Pemanggilan prosedur FAR. Ketika pemanggil dan subrutin berada pada segmen kode yang berbeda, assembler membuat kode mesin untuk far call. Sebelum mencabang ke subrutin, instruksi call menyimpan CS dan IP sekarang ke dalam stack. Kemudian mengambil alamat segmen subrutin ke dalam CS dan offsetnya ke dalam IP. Eksekusi mulai segera pada alamat baru. Progam pemanggil Main proc 0006 call subroutine1 0009 inc ax … … main endp
Subrutin Subroutine1 proc 0080 mov ax,1 … … … Subroutine1 endp
instruksi call menyimpan offset 0009 ke Instruksi RET mengambil 0009 dari dalam stack, dan memindahkan 0080 ke stack dan menyimpannya dalam register IP. Ini menyebabkan CPU dalam IP. melanjutkan eksekusi offset 0009. Stack 0000 0009
0009 dimasukan ke dalam stack
Stack 0000 0009
dipop ke dalam IP
Gambar 4.3. Pemanggilan prosedur dekat (near)
Gambar 4.4. menunjukan prosedur main membuat pemanggilan jauh ke subrutin dalam segmen kode lain. Deklarasi FAR harus ditambahkan sesudah nama subroutine1 dan operator FAR PTR ditambahkan pada instruksi call. Deklarasi subroutine1 meminta assembler uut membuat instruksi mesin khusu RETF daripada RET. Jika kita tidak mempunyainya, subrutin tidak dapat kembali kepada pemanggilnya. Waktu eksekusi untuk call ini lebih lambat daripa call near karena adanya penambahan push dan pop nilai segmen (CS). Program pemanggil Main proc 2FC0 : 0006 call FAR PTR subroutine1 2FC0 : 0009 inc ax … … main endp
Subrutin Subroutine1 PROC FAR 3AB6 : 0080 mov ax, 1 … … ret subroutine1 endp
instruksi call memasukan segmen 2FC0 dan offset 0009 pada stack. Kemudian memindahkan 3AB6 ke dalam CS dan 0080 ke dalam IP. Ini menyebabkan CPU meneruskan eksekusi padaa alamat 3AB6 : 0080.
instruksi RET mengambil 2FC0 dari stack ke dalam CD, dan kemudian 0009 ke dalam IP. Ini menyembabkan CPU meneruskan eksekusi pada alamat 2FC0 : 0009.
Stack 0000 2FC0 0009
Stack 0000 2FC0 segemen kembali dan nilai offset 0009 yang dipop ke dalam CS dan IP
CS dan IP dimasukan ke dalam stack
Gambar 4.4. pemanggilan prosedur FAR
4.2. Interrupt Perangkat Lunak Istilah interrupt digunakan pada dua cara yang berbeda : interrupt perangkat keras adalah sinyal yang dibuat oleh suatu bagian perangkat keras sistem yang memerlukan perhatian segera dari CPU. Interrupt perangkat lunak adalah pemanggilan ke salah satu rutin layanan interrupt BIOS atau DOS. Interrupt perangkat keras. Interrupt perangkat keras dibuat oleh chip khusus, controller interrupt 8259, yang memeberi sinyal kepada CPU untuk menangguhkan eksekusi program sekarang dan memroses interrupt. Keyboard menyediakan contoh yang baik dalam hal ini : menekan salah satu kunci (key) menyebabkan CPU menangguhkan program sekarang dan mengeksekusi rutin BIOS yang membaca karakter dari port input keyboard dan menyimpannya dalam buffer memori. CPU dapat melanjutkan instruksi sebelum terjadi interrupt.
Biasanya, program harus mematikan interrupt perangkat keras ketika melaksanakan operasi yang sensitif pada register segmen dan stack. Untuk itu, instruksi CLI (clear interrupt flag) digunakan dan STI (set interrupt flag) untuk mengaktifkannya kembali. Interrupt perangkat lunak. Dapat dikatakan bahwa interrupt perangkat lunak bukan interrupt sama sekali. Nama ini diperoleh karena sifatnya yang mirip dengan interrupt perangkat keras. Interrupt perangkat lunak menyediakan kakas untuk menangani rincian I/O. Instruksi INT meminta layanan dari sistem operasi, biasanya untuk I/O. Layanan ini adalah program kecil yang berlokasi dalam BIOS dan bagian resident DOS. Instruksi INT Perintah INT memanggil subrutin sistem operasi, diidentifikasikan dengan angka dalam range 0 – FFh. Sebelum instruksi INT dieksekusi, AH biasanya bernilai nomor fungsi yang mengidentifikasikan subrutin yang diinginkan. Nilai-nilai lain mungkin dilewatkan ke interrupt dalam register. Sintaknya : INT nomor Instruksi INT digunakan untuk konsol masukan/keluaran umum, manipulasi file dan vide dan berbagai layanan lain yang disediakan oleh BIOS dan DOS. Tabel vektor interrupt. CPU memroses instruksi interrupt dengan menggunakan tabel vektor interrupt, yaitu tabel alamat pada 1024 byte memori terendah. Setiap isi tabel ini adalah 32 bit alamat segmen-offset yang menunjuk ke subrutin sistem operasi. Gambar 5.5. mengilustrasikan langkah-langkah yang diambil oleh CPU pada saat instruksi INT ditemukan oleh program : 1. Nomor yang mengikuti INT memberitahu CPU lokasi data dalam tabel vektor interrupt. Dalam contoh, INT 10h meminta layanan video. 2. CPU lompat kke alamat yang tersimpan dalam tabel vektor interrupt (F000:F065) 3. Subrutin DOS yang menangani interrupt pada F000:F065 mulai mengeksekusi dan akan selesai ketika instruksi IRET dicapai. 4. IRET menyebabkan program meneruskan eksekusi instruksi berikutnya dalam program pemanggil asal. Program pemanggil … mov … int 10h add … …
3 1 2
F000 : F065 F066 F067 …
Penanganan interrupt sti cld push es push ds … IRET
Kembali ke pemanggil … 3069
F000:F065
F000 : AB62 …
4
Interrupt perangkat lunak umum. Interrupt perangkat lunak memanggil rutin layanan interrupt dalam BIOS atau DOS. Beberapa interrupt yang sering digunakan : - INT 10h : layanan video. Rutin tampilan video yang mengatur posisi kursor, geser layar, dan menampilkan grafik video. - INT 16h : layanan keyboard. Rutin yang membaca keyboard dan mengecek statusnya. - INT 17h : layanan printer. Runtin untuk insisialisasi, print dan mengembalikan status printer. - INT 1Ah : waktu hari. Rutin yang mendapat nomor jam pada saat mesin dinyalakan, atau menset pencacah dengan nilai baru. - INT 1Ch : interrupt waktu bagi pengguna. Rutin kosong yang dieksekusi 18.2 kali per detik. - NT 21h : layanan DOS. Rutin layanan DOS untuk masukan/keluaran, penanganan file, manajeman memori dan dikenal sebagai fungsi call DOS. 4.3. Fungsi Call DOS INT 21h disebut fungsi call DOS. Terdapat 87 fungsi berbeda yang didukung oleh interrupt ini, dididentifikasikan oleh nomor fungsi yang ditempatkan dalam register AH. Berikut ini daftar fungsi 00h smapai 0Ch : Nomor Fungsi 0 1 2 3 4 5 6
Penjelasan Menghentikan program yang sedang dijalankan Input konsol dengan echo. Menunggu karekter dari perangkat input standar. Karaker dikembalikan ke dalam AL dan ditampilkan. Dapat dihentikan denagn CTRL-BREAK. Keluaran karakter. Mengirim karakter dalam DL ke perangkat keluaran standar (konsol). Input bantu. Menunggu karakter dari asynchronous port. Karakter dikembalikan dalam AL (jarang digunakan). Output bantu. Mengirim karakter dalam DL ke asynchronous port (jarang digunakan). Output printer. Mengirim karakter dalam DALAM ke port printer parallel. I/O konsol langsung. Melakukan input karakter yang tersedia dari perangkat input standar atau mengirim karakter ke output standar.
7 8 9 0A 0B 0C
Kendali karakter tidak difilter. Input konsol. Menunggu karakter dari perangkat input standar. Karakter dikembalikan ke dalam AL, tapi tidak ditampilkan di konsol. Kendali karakter tidak difilter. Input konsol tanpa echo. Menunggu karakter dari perangkat input standar. Karakter dikembalikan ke dalam AL tapi tidak ditampilkan di konsol. Dapat dihentikan dengan CTRL-BREAK. Output string. Mengirim string karakter dari perangkat input standar. DX mengandung offset string. Input buffer. Menunggu string karakter dari perangkat input standar. Karakter disimpan dalam buffer yang diacu oleh DX. Mengambil status input konsol. Memeriksa apakah karakter input menunggu. Mengembalikan AL = 0FFh jika karakter siap dan AL = 0 jika tidak. Membersihkan buffer input, menemukan fungsi input. Membersihkan buffer input konsol dan kemudian mengeksekusi fungsi input yang dipilih oleh nomor dalam AL (hanya fungsi 1, 6, 7, 8 dan 0Ah yang diperbolehkan)
Buffer untuk karakter yang diketik keyboard. Buffer ini memuat 15 karakter secara sirkular digunakan oleh DOS untuk menyimpan karakter yang ditekan. Ini membuat kita dapat mengetik lebih cepat daripada program yang dapat bekerja pada input. Dos akan mengingat key yang ditekan. Jika buffer penuh, komputer akan berbunyi dan huruf selebihnya akan diabaikan. Karakteristik input. Fungsi DOS untuk input karakter (fungsi 1, 6, 7, dan 8) menampilkan berbagai prilaku. Beriut ini rangkuman karakteristik untuk fungsi DOS 1, 6, 7 dan 8.
Wait ? Echo ? Ctrl-Break ? Filter ?
1 Y Y Y Y
Nomor fungsi DOS 6 7 N Y N N N N N N
8 Y N Y N
01h : Input konsol dengan echo fungsi 1 dos menunggu karakter yang akan ditampilkan yang diinputkan dari konsol dan menyimpannya dalam AL. (karakter yang sedang berada dalam buffer secara otomatis akan dikembalikan ke dalam AL) CTRL-BREAK aktif. Dalam contoh berikut sebuah karakter diinput dan ditempatkan dalam varibel bernama char : mov ah, 1 int 21h mov char, al
02h : Output Karakter fungsi 2 DOS mengirim karakter ke konsol. CTRL-BREAK aktif. Karakter yang akan ditampilkan disimpan disimpan dalam DL, seperti contoh berikuut : mov ah, 2 mov dalam, ‘*’ int 21h Perhatian : AL diubah oleh DOS selama pemanggilan INT 21h, jadi kita dapat menyimpannya dalam stack sebelum pemanggilan INT 21h dan mengambil kembali sesudahnya. 05h : Output Printer Untuk mencetak karakter, tempatkan karakter dalam DL dan panggil fungsi 5. DOS menunggu sampai printer siap untuk menerima karakter. Jika perlu, kita dapat menghentikan penungguan dengan CTRL-BREAK. Output asal akan keluar ke printer 1 (nama perangkat LPT1), contoh berikut mencetak karakter dollar ($) : mov ah, 5 mov dalam, ‘$’ int 21h mov dalam, 0Dh int 21h 06h : Input Output Konsol Langsung Fungsi 6 DOS melakukan baca atau tulis di konsol. CTRL-BREAK tidak aktif dan tidak ada filter terhadap kendali karakter. Untuk meminta konsol input (tanpa menunggu), DL harus berinilai 0FFh. Karakter dikembalikan ke dalam AL. Contoh berikut untuk input/output : Input karakter mov ah, 6 mov dalam, 0FFh int 21h Output karakter mov ah, 6 mov dl, ‘&’ int 21h menghapus buffer keyboard. Program aplikasi biasanya diperlukan untuk mengahapus buffer keyboard. Berikut ini contoh porsedur yang menggabunggkan INT 21h dengan instruksi Loop untuk menghapus buffer : clear_keyboard proc
mov cx, 15 L1 : mov ah, 6 mov dalam, 0FFh int 21h loop L1 ret clear_keyboard endp
07h : Input Konsol Langsung Fungsi 7 menunggu karakter yang tidak terfilter dari konsol. Karakter tidak ditampilkan di konsol dan CTRL-BREAK tidak aktif. Fungsi input ini cocok untuk karakter khusus seperti karakter fungsi dan panah kursor, contoh : mov ah, 7 int 21h mov char, al 08h : Input Konsol Tanpa Echo Fungsi 8 menunggu karakter yang tidak difilter dari konsol tanpa menampilkannya dan CTRL-BREAK aktif. Karakter dikembaalikan dalam AL. fungsi input ini cocok untuk karakter khusus, contoh : mov ah, 8 int 21h mov char, al 09h : Output String Fungsi 9 menampilkan string karakter pada konsol. Alamat offset string harus ada dalam DX, dan string harus diakhiri oleh karakter dollar ($). Contoh : mov ah, 9 mov dx, offset string int 21h … … string db ‘This is a byte string.’, Odh, Oah, ‘$’ 0Ah : Buffer Input Konsol Fungsi 0Ah membaca string karakter sampai 255 karakter dari konsol dan menyimpannya dalam buffer. Enter digunakan untuk mengakhiri input. CTRLBREAK aktif dan seluruh karakter ditampilkan pada konsol. Sebelum fungsi dipanggil, DX harus mengandung offset area parameter keyboard. Format area sebagai berikut :
0
1
n
m
2
3
4
…
n+1
Jumlah karakter yang bernar-benar diinputkan Jumlah maksimum karakter yang diijinkan Dalam byte offset 0 ditempatkan jumlah maksimum karakter yang bisa diinput. Jika jumlahnya 5, misalnya, dos akan mengijinkan 4 karakter tambah enter yang diinput. Sesudah interrupt dipanggil, dos menempatkan jumlah karakter yang benarbenar dituliskan pada byte offset 1. Karakter tersebut disimpan mulai offset 2. contoh : mov ah, 0Ah mov dx, offset max_keys int 21h … … max_keys db 32 chars_input db ? buffer db 32 dup(0) misal kita menginputkan 21 karakter dari konsol : my name is Kip Irvine maka isi buffer akan sebagai berikut : max_key char_input 20 15 4D 79 20 6E 61 6D 65 20 69 73 20 4B 69 70 20 49 72 76 69 6E 65 0D Enter
my name is Kip Irvine
0B h : Mengambil Status Input Konsol Fungsi 0B h menerima buffer keyboard DOS untuk melihat ada karakter dalam buffer. Jika ada, DOS mengembalikan nilai 0FFh dalam AL, jika tidak, DOS mengembalikan 00 dalam AL. CTRL-BREAK aktif. Contoh : mov ah, 0Bh int 21h 0Ch : membersihkan buffer input, menemukan fungsi input Fungsi 0Ch membersihkan buffer keyboard dan memanggil fungsi input konsol. Fungsi yang dipanggil (1, 6, 7 dan 8) diidentifikasikan oleh nilai dalam AL. Karakter input akan dikembalikan dalam AL. contoh : mov ah, 0Ch mov al, 1 int 21h mov char, al Input keyboard level Bios (INT 16h) Cara langsung untuk mengambil input keyboard adalah dengan menggunkan INT 16h layanan keyboard dalam sistem BIOS. Berikut ini daftar layanan INT 16h : Nilai AH 1
2
3
4 5
Penjelasan Menunggu keyboard ditekan. Jika sedang menunggu penekanan keyboard, kode scan dikembalikan dalam AH dan kode karakter dikembalikan dalam AL. Jika tidak ada key yang ditunggu, rutin menunggu dalam loop untuk key yang ditekan. Memeriksa buffer keyboard. Memeriksa buffer ketikan keyboard untuk melihat apakah ada key yang sedang menunggu, jika ada maka layanan mengembalikan kode scan dalam AH dan kode karakter dalam AL, dan membersihkan flag zero. Sebaliknya, ZF = 1. Mengambil flag keyboard. Menunjukan status keyboard saat ini. Bit Arti jika bit = 1 0 rigt shift ditekan 1 left shift ditekan 2 ctrl ditekan 3 alt ditekan 4 scroll lock ditekan 5 numlock ditekan 6 capslock ditekan 7 insert ditekan Set typematic repeat rate. Memasukan key yang ditekan ke dalam buffer.
4.4. Kendali Video Level Bios (INT 10h) Ketika program aplikasi perlu menulis karakter pada layanan, mungkin langsung melihat pada memori video atau memunculkan instruksi INT untuk meminta layanan dari sistem operasi. Berikut ini rangkuman layanan fungsi INT 10h (0 – 0Fh) Nilai AH 0 1 2 3 4 5 6 7 8 9 0Ah 0Bh 0Ch 0Dh 0Eh 0Fh 11h
Penjelasan Set mode video Set baris kursor Set posisi kursor Mengambil posisi kursor Membaca pen terang Set halaman tampilan Geser window keatas Geser window kebawah Membaca karakter dan atribut Menulis karakter dan atribut Menulis karakter Set palet warna Menulis titik Membaca titik Menulis karakter Mengambil mode video Mengambil font ROM asal
V. PEMROSESAN KONDISI
5.1. Boolean dan Instruksi Perbandingan Beberapa perintah yang familiar dengan aljabar boolean yang sekaligus merupakan operator logic adalah AND, OR, NOT dan XOR. Keempat operator tersebut diimplementasikan dalam instruksi bahasa assembly langsung sesuai dengan namanya. Disamping itu terdapat juga perinah NEG, TEST dan CMP. Register flag Setiap instruksi tersebut berefek terhadap register flag. Beberapa flag yang digunakan dalam instruksi boolean dan perbandingan adalah flag zero, carry dan sign. 4 hal yang perlu diingat bahwa : - Flag zero diset ketika hasil operasi bernilai nol - Flag carry diset ketika hasil penjumlahan bilangan tidak bertanda lebih besar dari ukuran operand tujuan atau ketika pengurangan memerlukan pinjaman. - Flag sign diset ketika bit tertinggi operand tujuan diset, termasuk jika hasilnya negatif. - Flag overflow diset ketika operasi aritmetik bertanda menghasilkan nilai yang keluar dari range tipenya. Instruksi boolean berdasarkan pada operasi aljabar boolean. Operasi-operasi ini dapat melakukan modifikasi terhadap bit tunggal dalam biner, berikut ini ringkasannya : Operasi AND ORANG XOR NOT
Komentar Menghasilkan 1 jika kedua bit inputnya bernilai 1 Menghasilkan 1 jika salah satu inputnya bernilai 1 Menghasilkan 1 jika kedua inputnya berbeda (disebut exclusive-OR) Hasilnya merupakan kebalikan dari bit input (misal 1 menjadi 0)
Instruksi AND Instruksi AND melaksanakan operasi boolean AND menggunakan dua buah operand 8-bit atau 16-bit dan menempatkan hasil pada operand tujuan. Sintaknya sebagai berikut : AND tujuan, sumber Masing-masing operand harus mempunyai ukuran yang sama, dan hanya satu diantaranya yang mengacu ke memori (operand memori), untuk setiap bit yang sesuai dalam operand, jika kedua nilainya 1 maka hasilnya maka bit hasilnya 1, kalau tidak hasilnya 0. Flag-flag yang terpengaruh adalah : overflow, sign, zero, parity, dan auxiliary carry. Beriktu ini contoh operasi AND menggunakan bilangan 4–bit :
0 0 1 1 AND 0 1 0 1 Hasil 0 0 0 1 Ketika dua buah byte atau word di AND kan maka setiap posisi bit dihitung secara terpisah : mov al, 00111011b and al, 00001111b
; AL = 00001011b
Menghapus bit tertinggi. Beberapa program pemroses kata (misalnya ws) menset bit tertinggi kode ASCII karakter. Jika kita akan menampilkan file teks pada konsol maka kita harus menghapus bit tertinggi masing-masing karakter yang akan ditampilkan. contoh program berikut mengutip input yaitu serangkaian teks dari input standar, menghapus bit tertinggi, dan menulis byte yang diperbaiki ke output standar : L1 :
mov cx, 10000 mov ah,6 mov dalam, 0FFh int 21h and al, 01111111h mov dl, al mov ah, 2 int 21h loop L1
Menghapus nilai bit status. Aplikasi yang sama dalam AND berhubungan dengan byte status keyboard, yang berada pada alamat 0040:0017; bit 5 menandakan bahwa key NumLock sedang on. Untuk mematikan NumLock, cara yang mudah adalah menghapus bit tersebut : push ds mov ax, 40h mov ds, ax mov bx, 17h and byte ptr [bx], 11011111b pop ds Instruksi OR Instruksi OR melaksanakan operasi boolean OR menggunakan operand sumber dan tujuan dan meletakan hasilnya dalam operand tujuan. Sintaknya sebagai berikut : OR tujuan, sumber
Operand-operand tersebut mungkin 8-bit atau 16-bit asal ukurannya sama. Hanya satu saja yang bisa mengacu ke memori (operand memori). Untuk setiap bit yang sesuai pada kedua operand maka berlaku aturan, jika salah satu dari keduanya bernilai 1 maka hasilnya adalah 1. Jika kedua-duanya 0 maka hasilnya 0. Flag-flag yang terpengaruh : overflow, sign, zero, parity, auxiliary carry, dan carry. Tabel berikut menunjukan hasil operasi OR pada masing-masing bit : OR Hasil
0 0 1 1 0 1 0 1 0 1 1 1
Contohnya, misalkan 3Bh di OR dengan 0Fh. Maka hasilnya empat bit paling bawah diset dan 4 bit tertinggi bernilai tetap : mov al, 00111011b or al, 00001111b
; AL=3Fh
cara ini digunakan untuk mengonversi sebuah digit desimal ke ASCII dengan mengatur bit 4 dan 5. Contoh, jika AL = 05h, kita dapat mengonversinya ke dalam kode ASCII pada digit 5 (35h), kita OR angka tersebut dengan 30 : nilai biner boolean OR hasil :
00000101 00110000 00110101
(05h) (30h) (35h)
instruksi assembly untuk melaksanakan ini sebagai berikut : mov dl, 5 or dalam, 30
; nilai biner ; konversi ke ASCII
memeriksa tanda atau nilai. Instruksi OR dapat digunakan untuk menemukan apakah operand kurang dari atau sama dengan nol. Bilangan tersebut di OR kan dengan dirinya sendiri maka tidak akan berubah tetapi berefek pada flag : or al, al jika ZF = 1, maka AL sama dengan nol, jika SF = 1, maka AL negatif, jika ZF = 0 dan SF = 0 maka AL lebih dari nol. Menset nilai bit status. Seperti halnya AND yang digunakan untuk menghapus key status NumLock maka untuk menghidupkannya kembali adalah dengan menset bit 6, sebagai berikut : push ds mov ax, 40h
mov ds, ax mov bx, 17h or byte ptr [bx], 01000000b pop ds
; menyalakan CapsLock
Instruksi XOR Instruksi XOR melaksanakan operasi boolean XOR menggunakan operand sumber dan tujuan dan menempatkan hasil dalam operand tujuan. Sintaknya : OR tujuan, sumber Operand mungkin 8-bit atau 16-bit, asalkan panjangnya sama. Hanya salah satu operand yang mengacu pada memori (operand memori). Untuk setiap bit yang sama pada kedua operand, maka berlaku aturan : jika kedua bit bernilai sama (keduanya 0 atau 1) hasilnya 0, kalau tidak sama hasilnya 1. Flagflag yang terpengaruh adalah overflow, sign, zero, parity, auxiliary carry dan carry. Contoh berikut menunjukan efek XOR pada masing-masing bit : 0 0 1 1 XOR 0 1 0 1 Hasil 0 1 1 0 Instruksi berikut menghasilkan nilai 32h dalam AL : mov al, 10110100b xor al, 10000110b
; AL = 00110010b, atau 32h
Membalikan bit. Kelebihan instruksi XOR adalah dapat membalikan nilai dirinya sendiri jika dilakukan dua kali. Misalkan kita punya nilai x, kemudian di xor dengan y. menghasilkan z. Ketika z dixor lagi dengan y maka hasilnya akan sama dengan x. Contoh : XOR Hasil XOR Hasil
11010101 11110000 00100101 11110000 11010101
x y z y x
Membalik bit status. Kita dapat membolak-balik status key CapsLock dengan menset bit 6 flag status. Sebagai berikut : push ds mov ax, 20h mov ds, ax mov bx, 17h xor byte ptr [bx], 01000000b
pop ds Instruksi NOT Instruksi NOT membalikan semua bit dalam operand. Hasilnya disebut ones complement. Sintaknya sebagai berikut : NOT operand Contoh, ones complement F0h adalah 0Fh mov al, 11110000 not al
; AL = 11110000b ; AL = 00001111b
Instruksi NEG Instruksi NEG membalikan tanda bilangan dengan dengaan membalikannya menjadi twos complement. Sintaknya sebagai berikut : NEG tujuan Twos complement diperoleh dengan membalikan suatu bilangan dan menambahnya dengan 1. Flag-flag yang terpengaruh adalah : overflow, sign, zero, auxiliary carry, parity dan carry. Setelah melaksanakan operasi NEG, periksa flag overflow barangkali terjadi kesalahan pada operand hasil. Contoh, jika kita memindahkan –128 ke dalam AL dan kemudian menegasikannya, hasilnya masih tetap –128, dan overflow diset : mov al, -128 neg al
; AL = 10000000b ; AL = 10000000b, OF = 1
pada kasus lain, untuk bilangan + 127, hasilnya akan benar dan flag overflow bernilai 0. mov al, +127 neg al
; AL = 01111111b ; AL = 10000001b, OF = 0
Instruksi TEST Instruksi TEST melaksanakan operasi AND secara tidak langsung pada operand tujuan menggunakan operand sumber. Flag dipengaruhi, tapi operand tidak berubah. Sintaknya sebagai berikut : TEST tujuan, sumber Jika setiap posisi bit yang sesuai diset pada kedua operand maka ZF akan bernilai 0. Flag-flag yang terpengaruh : overflow, sign, zero, carry, auxiliary carry dan parity.
Memeriksa status printer. INT 17h memeriksa status printer dan mengembalikan satu byte dalam AL. Jika bit 5 = 1, maka printer tidak ada kertasnya. Tes berikut memeriksa status tersebut dan menolkan ZF jika bit 5 diset : mov ah, 2 int 17h test al, 00100000b
; ZF = 0 jika kertas tidak ada
Instruksi TEST dapat memeriksa beberapa bit seketika. Misalkan kita membaca byte dari perangkat I/O, dan kita ingin mengetahui apakah bit 0 dan 3 diset. Dari gambaran ini, kita lihat bahwa ZF = 1 jika kedua bit tersebut bernilai 0. Contoh 1 : bit 0 diset : 00100101 00001001 00000001
nilai input nilai test hasil; ZF = 0
Contoh 2 : bit 0 dan 3 bernilai 0 00100100 00001001 00000000
nilai input nilai test hasil : ZF = 1
Instruksi CMP Instruksi CMP menawarkan cara yang baik untuk membandingkan operand 8-bit dan 16-bit. Hasilnya ditunjukan oleh status register flag. Instruksi CMP melaksanakan pengurangan secara tidak langsung operand sumber dari operand tujuan, tanpa mengubah kedua operand. Sintaknya : CMP tujuan, sumber Hanya satu operand yang mengacu ke memori. Operand tujuan tidak boleh operand immediate atau register IP, tidak boleh juga register segmen. Flag-flag yang terpengaruh : overflow, sign, zero, carry, auxiliary carry dan parity. Konndisi flag. Umumnya hanya tiga flag yang penting. Tabel berikut menunjukan bagaimana flag terpengaruh. Sesudah CMP Tujuan < sumber Tujuan = sumber Tujuan > sumber Contoh-contoh dibandingkan :
Hasil Flag CF = 1 ZF = 1 CF = 0, ZF = 0 berikut
menunjukan bagaimana flag diset ketika nilai
Contoh 1 mov al, 5 cmp al, 10
; CF = 1
Contoh 2 mov ax, 1000 mov cx, 1000 cmp cx, ax
; ZF = 1
Contoh 3 mov si, 105 cmp si, 0
; ZF = 0 CF = 0
5.2. Loncat Kondisional (Conditional Jumps) Instruksi lompat kondisional Instruksi lompat kondisional memindahkan kendali ke alamat tujuan ketika kondisi flag bernilai benar. Sintaknya sebagai berikut : JCond tujuan Alamat tujuan harus antara –128 - +127 byte dari lokasi sekarang. Cond mengacu pada kondisi flag, mengidentigikasikan satu atau lebih keadaan. Contoh : Kondisi C NC Z NZ
Arti Carry Flag diset Carry Flag tidak diset (clear) Zero Flag diset Zero Flag tidak diset (clear)
Kita lihat bahwa flag diset oleh instruksi aritmetik, perbandingan dan boolean. Setiap instruksi jump kondisional memeriksa satu atau beberapa flag, mengembalikan hasil benar atau salah. Jika hasilnya benar, maka jump dilakukan, sebaliknya jika salah maka tidak ada yang dilakukan dan instruksi selanjutnya akan dilakukan. Penggunaan CMP. Misalkan akan jump ke lokasi equal pada saat AX dan BX sama. Pada contoh berikut, CMP set ZF jika AX=BX. Instruksi JE akan lompat jika ZF = 1. cmp ax, bx je equal not_equal : …
… jmp exit equal : … exit :
Daftar jump berdasarkan perbandingan tidak bertanda. Mnemonic JZ JE JNZ JNE JA JNBE JAE JNB JB JNAE JC JBE JNA JCXZ JP JNP
Penjelasan Loncat jika nol Loncat jika sama (jika op1=op2) Loncat jika tidak nol Loncat jika tidak sama (jika op1<>op2) Loncat jika diatas (jika op1>op2) Loncat jika tidak lebih rendah atau sama (jika op1 tidak <= op2) Loncat jika lebih atas atau sama (jika op1>= op2) Loncat jika tidak lebih rendah (jika op1 tidak < op2 ) Loncat jika lebih rendah (jika op1
= op2) Loncat jika ada carry Loncat jika lebih rendah atau sama (jika op1 <= op2) Loncat jika tidak lebih atas (jika op1 tidak > op2) Loncat jika CX = 0 Loncat jika parity genap Loncat jika tidak ada parity
Kondisi Flag ZF = 1 ZF = 0 CF = 0 dan ZF = 0 CF = 0
CF = 1
CF = 1 atau ZF =1
CX = 0 PF = 1 PF = 0
Aplikasi Menggunakan Jump Kondisional Bagain berikut menjelaskan aplikasi-aplikasi yang di dalamnya melibatkan instruksi jump kondisional. Daftar jump berdasarkan perbandingan bertanda. Mnemonic Penjelasan JG Loncat jika lebih besar
Kondisi Flag ZF = 0 dan SF = OF
JNLE JGE JNL JL JNGE JLE JNG JS JNS JO JNO
Loncat jika tidak lebih kecil atau sama dengan Loncat jika lebih besar atau sama dengan Loncat jika tidak lebih kecil Loncat jika lebih kecil Loncat jika tidak lebih besar atau sama dengan Loncat jika kurang atau sama dengan Loncat jika tidak lebih besar Loncat jika bertanda Loncat jika tidak bertanda Loncat jika overflow Loncat jika tidak overflow
SF = OF SF <> OF ZF = 1 atau SF <> OF SF = 1 SF = 0 OF = 1 OF = 0
Kunci keyboard tambahan. Rutin berikut menangani kode ASCII dan kunci tambahan :
L1 :
key db ? … … mov ah, 8 int 21h cmp al, 0 jne L1 int 21h mov key, al
Nilai lebih besar dari dua bilangan. Pada suatu waktu kita mungkin perlu untuk membandingkan nilai tidak bertanda dalam AX dan BX dan memindahkan nilai yang lebih besar ke dalam DX. Berikut ini contoh program : mov dx, ax cmp ax, bx jae quit mov dx, bx quit : Nilai terkecil dari tiga bilangan. Instruksi berikut membandingkan nilai tidak bertanda dalam AL, BL dan CL dan memindahkaan nilai yang paling kecil ke variabel small : mov small, al cmp small, bl jbe L1
L1 :
mov small, bl cmp small, cl jbe L2 mov samll, cl
L2 : Enkripsi file Berikut ini contoh penggunaan XOR digabungkan dengan JMP dan JZ untuk melaksanakan aplikasi enkripsi data : top :
mov ah, 6 mov dalam, 0FFh int 21h jz quit xor al, 239 mov ah, 2 mov dalam, al int 21h jmp top quit : mov ax, 4000h int 21h Konversi huruf besar Program upcase.asm dibawah mengonversi setiap karakter yang dituliskan menjadi huruf besar. Program akan berakhir jika ENTER ditekan. Instruksi CMP, JB dan JA bersama-sama membangun perintah kondisi yang memeriksa apakah karakter huruf kecil, sebagai berikut : title program tampilan huruf besar dosseg . model small . stack 100h
A1 :
A2 :
. code main proc mov ah,8 Int 21h cmp al, 0Dh je A3 cmp al, ‘a’ jb A2 cmp al, ‘z’ ja A2 sub al, 32 mov ah, 2
mov dl, al int 21h jmp A1 A3 : mov ax, 4000h int 21h main endp end main Gambar 5.1. Program tampilan huruf besar Konversi file text Beberapa program pemroses kata menset bit tertinggi karakater pada saat memformat file text. Karakter tersebut sulit untuk dibaca menggunakan tipe perintah DOS. Program CONVERT.ASM, dibawah berfungsi untuk membaca karakter dari input standar, mengeluarkan karakter yang tidak diinginkan, dan menulis karakter hasil pada output standar. Akhir setiap baris dalam file teks diakhiri dua byte yang mengandung 0Dh dan 0Ah, akhir file ditandai dengan sebuah byte yang mengandung 1Ah. Berikut ini contoh program konversi file : title program konversi file dosseg . model small . stack 100h ctrlz cr lf tab space
equ equ equ equ equ
1Ah 0Dh 0Ah 09h 20h
. code main proc A1 : mov ah, 6 mov dalam, 0FFh int 21h jz A3 cmp al, ctrlz je A3 and al, 01111111b cmp al, cr je A2 cmp al, lf je A2
cmp al, tab je A2 cmp al, space je A1 A2 : mov dalam, al mov ah, 2 int 21h jmp A1 A3 : mov ax, 4000h int 21h main endp end main Gambar 5.2. program konversi file teks
5.3. Liupan Kondisional (Conditional Loops) Instruksi LOOPZ (LOOPE) Instruksi LOOPZ (LOOPE) meliup ketika CX > 0 dan ZF = 1. tujuan harus berada dalam range –128 - +127 byte dari lokasi sekarang. Sintaknya sebagai berikut : LOOPZ tujuan LOOPE tujuan Pertama, CX ditentukan. Kemudian, jika CX > 0 dan ZF = 1, CPU loncat ke tujuan, sebaliknya, tidak ada yang terjadi dan akan melanjutkan pada instruksi berikutnya. Contoh : membaca array. Berikut ini contoh pembacaan array 100 elemen integer sampai ditemukan nilai bukan nol. Instruksi CMP membandingkan integer dengan 0, jika ketemu terus menset ZF=1. Jika ditemukan nilai bukan nol, LOOPZ tidak lagi meloncat ke atas : mov bx, offset intarray sub bx, 2 mov cx, 100 next : add bx, 2 cmp word ptr [bx], 0 loopz next … … intarray dw 100 dup(?)
baris 5 menset ZF=1 setiap kali elemen array yang ditemui sama dengan nol. Baris 6 meliup ke next jika CX > 0 dan ZF = 1. Instruksi LOOPNZ (LOOPNE) Instruksi LOOPNZ adalah kebalikan dari perintah LOOPZ. Liupan akan terus hanya jika CX > 0 dan ZF = 0. Contoh berikut membaca setiap bilangan dalam array 8-bit sampai menemukan nilai positif : array db -3, -6, -1, -10, 10, 30, 40, 4 array_len equ $- array … … mov si, offset array-1 mov cx, array_len next : inc si test byte ptr [si], 80h loopnz next
5.4. Struktur Logic Tingkat Tinggi Dalam bahasa assembly tidak ada struktur perintah IF, ELSE, WHILE dsb. Namun struktur perintah logic dalam bahasa tingkat tinggi tersebut dapat dilaksanakan dalam bahasa assembly dengan menggabungkan beberapa perintah sehingga secara princip sama dengan perintah tersebut. Pernyataan IF Perintah IF membandingkan dua buah nilai yang diikuti oleh perintah jika kondisi yang diperoleh benar, seperti contoh berikut : if (op1 = op2) then endif Berikut ini program dalam bahasa assembly yang serupa dengan program diatas : cmp op1, op2 jne next_label next_label : Menggabungkan IF dengan operator OR. Perhatikan contoh pseudocode berikut dimana salah satu dari empat kondisi menghasilkan pernyataan1 :
if (AL>op1) or (AL >= op2) or (AL = op3) or (AL < op4) then endif program diatas diterjemahkan ke dalam bahasa assembly dengan menggunakan perintah IF bersarang. cmp al, op1 jg L1 cmp al, op2 jge L1 cmp al, op3 je L1 cmp al, op4 jl L1 jmp L2 L1 : L2 : Menggabungkan IF dengan operator AND. Pada contoh pseudocode berikut, semua empat kondisi harus bernilai benar agar pernyataan1 dieksekusi : if (AL>op1) and (AL >= op2) and (AL = op3) and (AL < op4) then endif terjemahan dalam bahasa assembly dari program diatas adalah : cmp al, op1 jng next_label cmp al, op2 jnge next_label cmp al, op3 jne next_label cmp al, op4 jnl next_label next_label : Struktur WHILE Struktur WHILE pertama kali memeriksa kondisi sebelum melaksanakan satu blok perintah. Selama pemeriksaan bernilai benar maka perintah-perintah tersebut akan diulangi : do while (op1
enddo dalam assembly dapat dilakukan sebagai berikut : do_while : cmp op1, op2 jnl enddo jmp do_while enddo : Struktur Repeat … Until Struktur Repeat … Until mengeksekusi satu atau lebih perintah dalam sebuah blok minimal sekali dan melaksanakan pemeriksaan kondisi pada bagain bawah liupan. Contoh berikut, dua kondisi diperiksa sebelum liupan diulangi : repeat until (op1 = op2) or (op1 > op2) dalam bahasa assembly, hasil pemeriksaan pertama dimasukan ke dalam stack, setelah pemeriksaan kedua, hasil pertama diambil dari stack dan di OR kan dengan hasil kedua. Berikut ini contoh terjemahan dalam bahasa assemblynya : repeat : test1 : mov ax, 0 cmp op1, op2 jne test2 mov ax, 0FFh test2 : push ax mov ax, 0 cmp op1, op3 jng test3 mov ax, 0FFh test3 : pop dx or dx, ax jz endup jmp repeat
endup : Aplikasi diatas tidak efisien. Berikut ini contoh program yang lebih efisien untuk melaksanakan struktur Repeat … until repeat : test1 : cmp op1, op2 je endup test2 : cmp op1, op3 jng repeat endup : Struktur CASE Struktur CASE melakukan pencabangan banyak dengan membandingkan sebuah nilai terhadap beberapa nilai. Berikut ini contoh pemilihan aksi berdasarkan nilai variabel input, dalam pascal : case input of ‘A’ : proses_A; ‘B’ : proses_B; ‘C’ : proses_C; ‘D’ : proses_D; end; dalam bahasa assembly setiap pilihan kasus dibuat dalam perbandingan secara terpisah, diikuti oleh loncat ke label : mov al, input cmp al, ‘A’ je proses_A cmp al, ‘B’ je proses_B cmp al, ‘C’ je proses_C cmp al, ‘D’ je proses_D jika kita akan memanggil prosedur untuk setiap kasus maka kita harus menyisipkan perintah call pada setiap kasus yang dipilih, sebagai berikut : mov al, input
L1 :
L2 :
L3 :
cmp al, ‘A’ jne L1 call proses_A jmp L4 cmp al, ‘B’ jne L2 call proses_B jmp L4 cmp al, ‘C’ jne L3 call proses_C jmp L4 cmp al, ‘D’ jne L4 call proses_D jmp L4
L4 : Tabel offset Cara yang lebih efisien untuk memproses struktur CASE adalah dengan membuat tabel offset yang mengandung ofset label atau prosedur. Asembler dapat menghitung offset label dan menempatkannya dalam variabel. Tabel offset sangat efektif diterapkan pada perbandingan yang banyak. Pernyataan berikut mendefinisikan tabel yang mengandung nilai dan alamat prosedur yang akan dipanggil : Casetable
db dw db dw db dw db dw
‘A’ proses_A ‘B’ proses_B ‘C’ proses_C ‘D’ proses_C
misalkan proses_A, proses_B, proses_C, dan proses_D berada pada alamat 0120h, 0130h, 0140h dan 0150h, berturut-turut. Tabel akan disusun dalam memori sebagai berikut : ‘A’
0120
‘B’
0130
‘C’
0140
‘D’ 0150
AL dibandingkan terhadap setiap isi dalam tabel, menggunakan liupan. Yang pertama sesuai ditemukan dalam tabel menyebabkan pemanggilan offset prosedur yang disimpan sesudah nilainya :
L1 :
L2 :
mov al, input mov bx, offset casetable mov cx, 4 cmp al, [bx] jne L2 call word ptr [bx +1] jmp L3 add bx, 3 loop L1
L3 : Cara ini memerlukan tambahan inisialisasi, tapi dapat membantu program sehingga lebih efisien. Dengan tabel tersebut dapat menangani perbandingan yang banyak dan mudah diperbaiki dari pada menggunakan perbandingan, lompat dan pemanggilan prosedur yang banyak.
VI. ARITMETIKA Aritemetik dalam assembly melibatkan berbagai tipe bilangan diantaranya integer dan floating point. Untuk menyelesaikan penghitungan aritmetik tersebut diperlukan berbagai instruksi, seperti instruksi geser, putar, penjumlahan, pengurangan, perkalian, pembagian dan perintah-perintah lain yang berfungsi dengan operand 8-bit dan 16-bit. 61. Instruksi Geser (Shift) dan Putar (Rotate) Instruksi geser dan putar menyediakan cara untuk memindahkan bit operand. Instruksi-instruksi tersebut adalah : SHL SHR SAL SAR
Shift left Shift right Shift arithmetic left Shift arithmetic right
ROL ROR RCL RCR
Rotate left Rotate right Rotate carry left Rotate carry right
Instruksi SHL Instruksi SHL menggeser setiap bit dalam operand ke kiri, mengisi bit terendah dengan nol. Bit tertinggi dipindah ke CF, dan bit dalam CF hilang. 0 CF Terdapat dua format SHL. Pertama geser register atau operand memori 1 bit ke kiri. Kedua menggunakan penghitung geser dalam register CL untuk menentukan berapa banyak operand tujuan digeser. SHL SHL
dest, 1 dest, CL
CL tidak diubah ketika SHL menggunakannya untuk sebagai penghitung geser. Berikut ini contoh penggunaan kedua operand memori : shl bl, 1 shl wordval, 1 shl byte ptr[si], 1
mov cl, 4 shl al, cl Pada contoh berikut, BL digeser sekali ke keiri. Bit tertinggi disalin ke dalam CF (carry flag), dan bit paling rendah diisi dengan nol : mov bl, 8Fh shl bl, 1
; BL = 10001111b ; BL = 00011110b, CF = 1
contoh berikut akan menggeser DX ke kiri sebanyak 3 bit : mov dx, 000Fh mov cl, 4 shl dx, cl
; DX = 0000000000001111b ; jumlah geser = 3 ; DX = 0000000000111000b
Perkalian, salah satu penggunaan instruksi SHL adalah untuk melaksanakan operasi perkalian kecepatan tinggi. Perkalian harus pangkat 2, dan jumlah penggeseran adalah eksponennya. Contoh, penggeseran ke kiri 1 kali sama dengan mengalikan dengan 21, menggeser dua posisi sama dengan perkalian dengan 22 dan seterusnya. Contoh berikut menunjukan nilai desimal dalam DL sesudah setiap penggeseran : mov dl, 1 shl dl, 1 shl dl, 1 shl dl, 1 shl dl, 1
; DL = 1 ; DL = 2 ; DL = 4 ; DL = 8 ; DL = 16
Instruksi SHR Instruksi SHR menggeser setiap bit ke kanan dan mengganti bit tertinggi dengan nol. Bit paling rendah disalin ke dalam CF, dan bit dalam CF hilang : 0 CF Terdapa dua format SHR. Pertama menggeser operand register atau memori 1 bit ke kanan. Kedua menggunakan nilai CL untuk mengulang penggeseran : SHR dest, 1 SHR dest. CL CL tidak berubah. Contoh menggunakan kedua operand register dan memori sebagai berikut : shr bl, 1
shr wordval, 1 shr byte ptr[si], 1 mov cl, 4 shr al, cl instruksi SHR dapat digunakan untuk membagi bilangan dengan 2. contoh, kita dapat membagi 32 dengan 2, sebagai berikut : mov dl, 32 shr dl, 1
; DL = 00100000b ; DL = 00010000b = 16
Instruksi SAL (shift arithmetic left) dan SAR (shift arithemetic right) Instruksi SAL dan SAR adalah instruksi penggeseran yang khusu untuk bilangan bertanda. Instruksi SAL mirip dengan instruksi SHL dan disertakan dalam set instruksi hanya untuk pelengkap. SAR menggeser setiap bit ke kanan dan menyalin bit tanda :
CF SAR menyalin bit terendah operand tujuan ke dalam CF dan menggeser seluruh bit 1 kali ke kanan, dan membuat salinan bit tanda asal (bit posisi paling kiri). Jumlah shift juga dapat ditempakan dalam CL. Sintak SAR dan SHR mirip dengan SHL dan SHR : SAR dest, 1 SAR dest, CL SHR dest, 1 SHR dest, CL Contoh berikut menunjukan bagaimana SAR menggandakan bit tanda. AL bernilai negatif sebelum dan sesudah di geser kanan : mov al, 0F0h sar al, 1
; AL = 11110000b (-16) ; AL = 11111000b (-8), CF = 0
contoh berikut, -32768 digeser kanan 5 kali, yang sama dengan membaginya dengan 25 (32). Hasilnya –1024; mov dx, 8000h mov cl, 5 sar dx, cl Instruksi ROL (rotate left)
; DX = 1000000000000000b ; DX = 1111110000000000b
Instruksi ROL memindahkan setiap bit ke kiri. Bit tertinggi dislain ke CF dan ke bit terendah sebagai berikut :
CF Secara umum, instruksi rotasi berbeda dengan instruksi geser karena tidak ada bit yang hilang. Terdapat dua format yang sama dengan instruksi geser : ROL dest, 1 ROL dest, CL Contoh berikut menggambarkan penggunaan ROL pada nilai byte dan word : byte_value : mov cl, 4 mov cl, 26h rol al, cl rol byteval, cl word_value : mov cl, 8 mov ax, 0203h rol ax, cl rol wordval, cl … … byteval db 0Fh wordval dw 1234h Instruksi ROR Instruksi ROR (rotete right) memindahkan setiap bit ke kanan. Bit paling rendah disalin ke dalam CF dan ke bit tertinggi pada saat yang sama :
CF Terdapat dua sintak ROR yang sama dengan instruksi ROL : ROR dest, 1 ROR dest, CL
Contoh berikut menggambarkan, bit terendah disalin ke dalam CF dan ke dalam bit tertinggi : mov al, 01h ror al, 1 ror al, 1
; AL = 00000001b ; AL = 10000000b, CF = 1 ; AL = 01000000b, CF = 0
Instruksi RCL (rotete carry left) dan RCR (rotete carry right) Instruksi RCL menggeser setiap bit ke kiri dan menyalin bit tertinggi ke dalam CF. CF disalin ke dalam bit terendah, sebagai berikut : CF
Dalam contoh ini, instruksi CLC menghapus nilai CF. instruksi RCL pertama memindahkan tinggi ke dalam CF, dan menggeser semua bit lainnya ke kiri. Instruksi RCL kedua memindahkan CF ke dalam posisi bit terendah, dan menggeser semua bit yang lain ke kiri : cc mov bl, 88h rcl bl, 1 rcl bl, 1
; CF = 0 ; BL = 10001000b ; BL = 00010000b, CF = 1 ; BL = 00100001b, CF = 0
Instruksi RCR. Instruksi ini menggeser setiap bit ke kanan dan menyalin bit terendah ke dalam CF. CF disalin ke dalam bit tertinggi : CF
Pada contoh berikut, STC menset CF sebelum melaksanakan rotasi : stc mov ah, 10h rcr ah, 1
; CF = 1 ; AH = 00010000b, CF = 1 ; AH = 10001000b, CF = 0
6.2. Aplikasi Contoh Instruksi geser dan rotasi digunakan sewaktu-waktu. Berikut ini beberapa contoh aplikasi yang mengunakan perintah tersebut.
Menggeser banyak byte Misalkan kita akan menggeser seua bit dalam tabel ke kanan, seperti pada gambar grafik bit- map. Menggunakan tiga byte operand misalnya, kita dapat mulai dengan byte yang paling kiri, menggeser bit rendahnya ke dalam CF, hasil penggeseran sekali ke kanan adalah sebagai berikut : Sebelum : Sesudah :
byte1 byte2 byte3 00111011 01000110 11111111 00011101 10100011 01111111
Setelah digeserkan, byte1 sama dengan 00011101 dan CF = 1, kemudian RCR digunakan untuk merotasi byte2 ke kanan ketika menyalin isi CF ke dalam bit posisi tertinggi byte2. Sesudah rotasi, byte2 sama dengan 10100011b. Terakhir, byte3 dirotasi ke kanan, menghasilkan nilai 01111111b. Tiga tahap diulangi setiap kali kita menggeser semua bit dalam ketiga byte. Instruksi berikut menggeser bit dalam semua byte ke kenan empat kali : mov cx, 4 shr byte1, 1 rcr byte2, 1 rcr byte3, 1 loop L1 byte1 db 3Bh byte2 db 46h byte3 db 0FFh L1 :
Perkalian dan Pembagian Seperti yang dijelaskan sebelumnya bahwa instruksi SHL dan SHR melaksanakan operasi perkalian dan pembagian dengan efesien ketika minimal satu operandnya merupakan pangkat dari 2. (misal 2,4,8,16 … ) Jika operandnya bukan pangkat dari 2, kita bisa memfaktorkannya sehingga salah satu faktornya adalah bilangan pangkat dari 2. Misal, untuk mengalikan bilangan nilai dalam BX dengan 36, maka kita memanfaatkan keuntungan dengan aturan perkalian distribusi sebagai berikut : BX * 36 = BX * (32 + 4) = (BX * 32) + (BX * 4) Berikut ini contoh menunjukan bagaimana variabel 16-bit yang disebut intval dikalikan dengan 36. Hasilnya, 360, merupakan penjumlahan dua perkalian yaitu 320 dan 40 : mov bx, intval mov cl, 5 shl bx, cl mov product, bx
mov bx, intval shl bx, 1 shl bx, 1 add product, bx … … intval dw 0Ah product dw ? Menampilkan Bilangan Dalam Biner ASCII Cara yang baik untuk mengaplikasikan instruksi SHL adalah menampilkan byte dalam format biner ASCII. Kita dapat mengambil keuntungan karena bit tertinggi disalin ke dalam CF setiap kali byte digeser ke kiri. Program BIN.ASM berikut menampilkan setiap bit dalam register AL. Keluarannya adalah pola bit 6Ch : 01101100. title Tampilan ASCII biner dosseg . model small . stack 100h . code main proc mov al, 6Ch mov cx, 8 L1 : shl al, 1 mov dl, ‘0’ jnc L2 mov dalam, ‘1’ L2 : push ax mov ah, 2 int 21h pop ax loop L1 mov ax, 4000h int 21h main endp end main Mengisolasi String Bit Sering suatu byte ataau word mengandung lebih dari satu field, sehingga kita mengambil rangkaian bit yang pendek, yang disebut string bit. Misalnya, fungsi 57h DOS mengembalikan tanggal file dalam DX. (tanggal menunjukan data pada kapan terakhir file dimodifikasi). Bit 0-4 mewakili angka hari dari 1-31, bit 5-8 adalah angka bulan, dan bit 9-15 adalah angka tahun. Data tanggal file akan terlihat sebagai berikut dalam register DX (angka tahun relatif terhadap tahun 1980)
DH 0
DL
0 0 1 0 0 1 0 0 1 1 0 1 0 1 0 tahun
bulan
hari
Untuk mengambil sebuah field, kita menggeser bit-bit ke dalam bagian terendah DX, menggunakan instruksi SHR, dan kemudian bit yang tidak relevan di AND kan dengan nol. Berikut ini contoh mengambil hari : mov al, dl and al, 00011111b mov day, al untuk mengambil nilai bulan, berikut ini contohnya : mov ax, dx mov cl, 5 shr ax, cl and al, 00001111b mov month, al untuk mengambil nilai tahun sebagai berikut : mov al, dh shr al, 1 mov ah, 0 add ax, 1980 mov year, ax 6.3. Multi - Penjumlahan dan Pengurangan (Multiple Addition and Substraction) Instruksi ADC (add with carry) Instruksi ADC mengijinkan penjumlahan dan epngurangan dengan operand banyak byte dan banyak word. Operand sumber dan CF keduanya ditambahkan ke operand tujuan. Sintaknya sebagai berikut : ADC tujuan, sumber Operand sumber dan tujuan bisa nilai 8-bit ataupun 16-bit. Berikut ini contoh penjumlahan dua operand multiword dan menyimpannya dalam memori. Fungsi ini dilaksanakan oleh prosedur MULTIWORD_ADD. Ketika prosedur ini dipanggil, terdapat pointer yang dilewatikan yang mengacu pada
operand input dalam SI dan DI, pointer ke hasil dalam BX dan jumlah word yang ditambahkan dalam CX. Prosedur mengasumsikan bahwa setiap nilai disimpan dengan word least significant nya pada alamat paling rendah : title contoh penjumlahan multiword dosseg . model small . stack 100h .code main proc mov ax, @data mov ds, ax mov si, offset op1 mov di, offset op2 mov bx, offset result mov cx, 2 call multiword_add mov ax, 4000h int 21h main endp . data op1 op2 result
dd dd dw
02B2A406h 080108700h 3 dup(0)
. code multiword_add proc push ax push bx push cx push si push di clc L1: mov ax, [si] adc ax, [di] pushf mov [bx], ax add si, 2 add di, 2 add bx, 2 popf
loop L1 adc word ptr[bx], 0 pop di pop si pop cx pop bx pop ax ret multiword_add endp end main Instruksi SBB (substract with borrow) Instruksi SBB berguna untuk pengurangan multibyte atau multiword. Sintaknya sebagai berikut : SBB tujuan, sumber Operand tujuan dan sumber mungkin bernilai 8-bit atau 16-bit. Pertama, operand sumber dikurangkan dari tujuan; kemudian CF dikurangkan dari tujuan . Contoh quadword, dalam contoh berikut, operand quadword (8-byte) dikurangi dari yang lain sebagai berikut : mov cx, 8 mov si, 0 clc L1 : mov al, byte ptr op1[si] sbb al, byte ptr op2[si] mov byte ptr result [si], al inc si loop L1 … … op1 dq 20403004362047A1h op2 dq 055210304A2630B2h result dq 0 instruksi SBB pada baris 6 mengurangkan CF dan isi dari op2 dari AL. perintah DQ menyimpan byte dalam memori dengan urutan terbalik. Pengurangan dapat diringkas sebagai berikut : op1 op2 hasil
20 40 30 04 36 20 47 A1h 05 52 10 30 4A 26 30 B2h 1A EE 1F D3 EB FA 16 EF
Pada contoh ini op1 lebih besar dari op2 sehingga hasilnya positif. Jika hasilnya negatif, CF akan diset juga setelah loop selesai, dan hasilnya akan disimpan dalam bentuk twos complement. 6.4. Perkalian dan Pembagian Terdapat instruksi untuk melaksanakan perkalian dan pembagian integer pada bilangan 8-bit dan 16-bit. Semua operand diasumsikan bilangan biner, jadi jika terdapat operand bilangan desimal maka harus dibuat seluruh penyesuaian. Operasing floataing-point ditangani ole coprosesor matematika Intel terpisah atau emulasi perangkat lunak yang didukung oleh library dalam bahasa pemrograma. Instruksi MUL (multiply) dan DIV (divide) digaunakan untuk operasi integer biner tidak bertanda. Instruksi IMUL dan IDIV digunakan untuk bilangan integer binter bertanda. Instruksi MUL dan IMUL Instruksi MUL dan IMUL mengalikan operand 8-bit atau 16-bit dengan AL atau AX. Jika operand sumber 8-bit disediakan maka otomatis perkalian dengan AL dan hasilnya disimpan dalam AX. Jika operand sumber 16-bit yang disediakan maka dikalikan dengan AX dan hasilnya disimpan dalam DX dan AX (16 bit yang lebih tinggi dalam DX) . Format sintaknya sebagai berikut : MUL sumber IMUL sumber Operand sumber mungkin operand register atau memori, tapi tidak boleh data immediate. Contoh perkalian AL dengan 10h : mov al, 5h mov bl, 10h mul bl mov ax, val1 mul val2 … … val1 dw 2000h val2 dw 0010h Perkalian integer1 dengan byte1 dan menyimpan hasilnya dalam variabel 32-bit yang diberinama result : mov ax, integer1 mov bh, 0 mov bl, byte1 mul bx
mov word ptr result, ax mov word ptr result+2, dx … … byte1 db 20h integer1 dw 1234h result dd ? Instruksi IMUL. Instruksi IMUL mengalikan nilai biner tidak bertanda. Untuk perkalian 8-bit, IMUL menset CF dan OF jika AH yang dihasilkan bukan tambahan tanda AL (misalkan, jika hasil kali lebih besar dari 8-bit) . Untuk perkalian 16-bit, CF dan OF diset jika DX bukan tambahan tanda AX (hasil kali lebih dari 16 bit). Tiga contoh berikut mengilustrasikannya : Operasi 8-bit : 48 x 4 = 192 mov al, 48 mov bl, 4 imul bl hasil kali dalam AX adalah 00C0h (+192). Karena AH bukan perpanjangan tanda AL, CF dan OF diset. Hal ini memberi tahu kita bahwa sign magnitude hasil lebih besar dari 8 bit : Operasi 8-bit : -4 x 4 = -16 mov al, -4 mov bl, 4 imul bl hasil kali dalam AX adalah FFF0h (-16) dan AH adalah perpanjangan tanda AL. Dalam kata lain, hail bertanda pas dalam AL. Operasi 16-bit : 48 x 4 = 192 mov ax, 48 mov bx, 4 imul bx hasil kali dalam DX : AX adalah 000000C0h. Karena tanda DX dan AX adalah sama (positif), hasilnya pas dalam AX, CF = 0 dan OF = 0. Instruksi DIV dan IDIV Instruksi DIV dan IDIV melaksanakan pembagian bilangan 8-bit atau 16-bit, bertanda dan tidak bertanda. Operand tunggal disediakan (operand register atau
memori), yang diasumsikan sebagai pembagi. Format sintak DIV dan IDIV sebagai berikut : DIV sumber IDIV sumber Jika pembagi panjangnya 8-bit, AX adalah yang akan dibagi, AL hasil bagi dan AH sisanya. Jika pembagi 16 bit, DX:AX yang akan dibagi, AX hasilb agi dan DX sisanya. Yang dibagi AX DX:AX
/
Pembagi operand operand
= AX
Hasil bagi AL BX
Sisa AH
Contoh 1. pembagian 8-bit (83h/2=41h, sisa 3) : mov ax, 0083h mov bl, 2 div bl
; yang akan dibagi ; pembagi ; AL = 41h dan AH = 01h
Contoh 2. pembagian 16-bit (8003h/100h = 80h, sisa 3). DX mengandung bagian tinggi yang akan dibagi, jadi kita harus mengosongkannya sebelum pembagian. Sesudah pembagian, hasil baginya adalah AX dan sisanya DX : mov dx, 0 mov ax, 8003h mov cx, 100h div cx Contoh 3. pembagian 16-bit menggunakan operand memori sebagai pembagi : mov dx, 0 mov ax, dividend div divisor … … dividend dw 8003h divisor dw 100h Instruksi IDIV. Instruksi IDIV melaksanakan operasi pembagian bertanda. Untuk pembagian 8-bit, yang akan dibagi berada dalam AX, jadi tandanya ditentukan oleh bit 15. Contoh, kita akan membagi –48 dengan 5, menghasilkan AL = -9 dan AH = 3.
mov ax, -48 mov bl, 5 idiv bl
; AX = FFD0h
Satu kesalahan umum adalah mempersiapkan yang akan dibagi dengan memindahkan –48 ke dalam AL. Jika AH sama dengan 00h, maka IDIV akan salah mengasumsikan yang akan dibagi + 208 (00D0h) . Instruksi CBW(convert byte to word) dan CWD (convert word to byte) Jika nilai yang akan dibagi dalam AL harus bertanda diperluas dalam AH, maka instruksi CBW digunakan. Misalkan kita akan membagi operand memori 8-bit dengan 10. Instruksi CBW sebaiknya mempersiapkan hasilbagi, mengonversi 80h ke FF80h : aByte db –128 … … mov al, aByte cbw mov bl, 10 idiv Untuk nilai yang akan dibagi 32-bit, CWD memperpanjang tanda AX ke dalam DX : mov ax, -5000 cwd mov bx, 256 idiv bx Overflow pembagian Jika opearsipembagian menyebabkan hasil yang terlalu luas, maka kondisi overflow terjadi, yang memanggil sistem interrupt 0. Pada beberapa mesin hal ini menyebabkan hang pada komputer. Pembagian dengan nol juga akan menghasilkan overflow pembagian. Bahasa tingkat tinggi telah membuat perlindungan untuk mengatasi hal ini, tetapi CPU sendiri tidak melaksanakan pengecekan kesalahan sebelum pembagian. Satu cara untuk hal ini adalah dengan memecah yang dibagi 32-bit menjadi dua bagian bernilai word. Contoh, jika kita membagi 08010020h dengan 10h, kita akan menghasilan overflow pembagian karena hasil bagi (0801002h) tidak pas untuk AX. Pembagian mungkin dilakukan dengan dua tahap, sebagai berikut : mov ax, dividend + 2 cwd mov cx, divisor div cx
mov bx, ax mov ax, dividend div cx mov remainder, dx … … … dividend label word dd 08010020h divisor dw 10h remainder dw ? pertama, kita membagi word yang paling tinggi yang akan dibagi. Baris 1 dan 2 mengambil nilai yang akan dibagi ke dalam AX dan tanda diperluas ke dalam DX. Baris 4 membagi bagian lebih tinggi dari nilai yang dibagi (0801h) dengan 10h. Hasil bagi 0080h dan sisanya 0001h : 0000:0801h (DX:AX)
/
10h = (CX)
0800h, sisa 1 (AX) (DX)
Baris ke 5 menyimpan hasil bagi dalam BX. Sisa bagi (DX) akan menjadi bagian paling penting dari nilai yang akan dibagi baru. Baris ke 6 mengambil data AX denga pada setengah bagian bawah nilai yang akan dibagi, DX : AX sama dengan 0001 : 0020h. dimana dia akan dibagi oleh 10h, hasil baginya (AX) sama dengan 1002h dan sisa baginya (DX) adalah nol : 0001:0020h (DX:AX)
/
10h = (CX)
1002h, sisa 0000h (AX) (DX)
Oleh karena itu, hasil bagi 32-bit yang berada dalam BX : AX sama dengan 0080 : 1002h.
VII. MAKRO DAN STRUKTUR
7.1. Pengenalan Macro adalah nama simbolik dari string teks atau satu blok kode yang akan digunakan berulang-ulang dalam program. Pada turbo assembler disediakan operator macro yang mudah dan fleksibel dengan kemampuan yang handal. Disamping itu juga terdapat fasilitas macro beberapa (multiline macros) baris dengan argumennya. Macro teks adalah simbol yang mewakili karakter-karakter teks. Ketika turbo assembler menemukan simbol dalam ekspresi (atau situasi lain), maka assembler akan menggantikannya dengan karakter teks simbol tersebut. Contoh, jika DoneMsg adalah teks macro yang mempunyai nilai “Returning to DOS”, maka statemen berikut : GoodBye DB DoneMsg Menghasilkan GoodBye DB ‘Returning to DOS’ EQU Perintah EQU digunakan untuk mendefiniskan macro. Berikut ini sintaks untuk mendefinisikan macro : Name EQU text_string Text_string berhubungan dengan macro teks yang bernama Name. Text_string ditulis di dalam notasi tanda <>, contoh : DoneMsg EQU <’Returning to DOS’> Berikut ini kemungkinan terjadi kesalahan pada pendefinisian macro, contoh Bumi EQU tanah Planet EQU Bumi Planet EQU <Bumi>
; Bumi = “tanah” ; Planet = “tanah” (Salah !) ; Planet = “Bumi” (Benar !)
CATSTR Perintah ini mendefinisikan macro teks baru dengan menggabungkan beberapa string secara bersamaan. CATSTR mempunyai sintak sebagai berikut : Name CATSTR string[,string] …
CATSTR menggabungkan string dari kiri ke kanan. Turbo assembler membuat macro teks baru dengan nama name. SUBSTR Perintah ini mendefinisikan macro teks baru yang merupakan sebagian string dari sebuah string. Sintaknya sebagai berikut : Name SUBSTR string, position_expression[,size_expression] Macro teks yang baru, Name terdiri dari bagian string yang dimulai dari karakter position_expression, dengan panjang sebanyak size_expression karakter. Jika size_expression tidak dituliskan maka secara otomatis seluruh sisa karakter dari mulai position_expression akan dimasukan ke dalam macro teks name. Turbo assembler menganggap karakter pertama string sebagai posisi 1. INSTR Perintah ini mengembalikan posisi suatu string di dalam string yang lain. Sintaknya sebagi berikut : Name INSTR [start_expression,]string1,string2 Turbo assembler memberikan name niali numerik posisi string2 dalam string1. Karakter pertama pada string1 mempunyai posisi 1. Jika string2 tidak ada dalam string1 maka nilai posisinya 0. Jika start_expression dituliskan maka pencarian dimulai dari karekter start_expression tersebut dan karakter pertama string adalah 1. SIZESTR Perintah ini mengembalikan nilai banyaknya karekter dalam sebuah macro teks (jumlah karakter dalam string). Sintaknya sebagai berikut : Name SIZESTR string Name diberi nilai numerik panjang dari string. String null <> mempunyai panjang nol. Contoh manipulasi macro teks VERSION T300 ABC EQU ; ABC = “abc” ABC2 EQU ABC ; ABC2 = “ABC” ABC EQU <def> ; ABC = “def” (definisi ulang) ABC3 CATSTR ABC2,<,>,ABC,<,>,ABC2 ; ABC3= “ABC,DEF,ABC” ABCLEN SIZESTR ABC ; ABCLEN = 3 ABC3LEN SIZESTR ABC3 ; ABC3STR = 11 COMMA1 INSTR ABC3,<,> ; COMMA1 = 4
COMMA2 ABC4 ABC5 ABC6 ABC7 ABC8
INSTR SUBSTR SUBSTR EQU EQU EQU
COMMA1+1,ABC3,<,> ; COMMA2 = 8 ABC3,5 ; ABC4 = “def,ABC” ABC3,5,3 ; ABC5 = “def” 3+2+1 ; ABC6 = 6 %3+2+1 ; ABC7 = “6” %COMMA1 ; ABC8 = “4”
Macro Banyak Baris Fasilitas macro banyak baris digunakan untuk mendefiniskan batang tubuh instruksi, perintah, atau macro lain yang disertakan ke dalam program, dimana saja macro tersebut ditempatkan. Argumen diberikan dalam macro dan turbo assembler akan menggantikan batang tubuh macro dalam module jika disertakan di dalamnya. Sintak untuk mendefiniskan macro banyak baris secara umum : Name MACRO parameter_list Macro_body ENDM Name adalah nama macro banyak baris yang didefinisikan. Macro_body mengandung statemen-statemen yang membangun batang tubuh macro. Kita dapat menempatkan berbagai statemen valid turbo assembler dalam macro. ENDM adalah kata kunci untuk menutup macro. Contoh berikut macro yang diberi nama PUSHALL, ketika dimasukan ke dalama program, maka akan disertakan semua perintah yang ada di dalamnya. PUSHALL MACRO PUSH AX BX CX DX PUSH DS SI PUSH ES DI ENDM Parameter_list adalah simbol argumen dami untuk macro, sintaknya sebagai berikut : [argumen_dami[, argumen_dami … ]] Kita bisa membuat argumen dami sepanjang baris atau dengan menggunakan karakter \ dappat meneruskan pada baris berikutnya. Contoh : ADDUP MACRO dest,\ s1, s2 MOV dest, s1 ADD dest,s2 ENDM
Setiap argumen dami mempunyai sintak : Nama_dami [: tipe_dami] Nama_dami adalah nama simbolik yang digunakan untuk tempat menyimpan argumen aktual yang ditransfer ke dalam macro pada saat di panggil. Tipe_dami adalah pilihan yang menspesifikasikan sesuatu bentuk dimana argumen aktual harus mengambilnya ketiak macro disisipkan. Makro adalah nama simbol yang diberikan terhadap satu atau banyak perintah bahasa assembly. Ketika dibuat, makro mungkin digunakan dalam program berulang kali sesuai dengan keperluan. Keuntungan mendefinisikan makro adalah perintah ini hanya dibuat sekali : setiap kali makro dipanggil, assembler membangkitkan perintah di dalamnya. Misalkan kita akan menuliskan instruksi berikut untuk menampilkan isi DL berkali-kali dalam program : mov ah, 2 int 21h Kita bisa menyimpan instruksi-instruksi tersebut dalam prosedur dan memanggilnya setiap kali diperlukan. Tapi cara ini memerlukan instruksi tambahan yaitu CALL dan RET, yang menyebabkan program menjadi lambat. Cara yang lebih baik adalah membuat makro misal diberi nama PUTCHAR. Sekali PUTCHAR didefinisikan, dia dapat dipanggil dari mana saja dalam program. Memanggil makro berbeda dengan memanggil prosedur – ini berarti perintah-perintah dalam makro disisipkan dalam program dimana dia dipanggil. Misalkan kita definikan makro bernama PUTCHAR : putchar macro mov ah, 2 int 21h endm
; mulai pendefinisian makro ; akhir pendefinisian makro
dalam segmen kode kita dapat memanggil PUTCHAR hanya menggunakan namanya. Setiap kali makro dipanggil, assembler menyisipkan instruksi-instruksi yang ada dalam definisi makro ke dalam kode program : Kode Sumber . code main proc … … mov dl, ‘A’
Kode yang diperluas . code main proc … … mov dl, ‘A’
puthcar … … … mov dl, ‘*’ putchar … …
mov ah, 2 int 21h … … mov dl, ‘*’ mov ah, 2 int 21h …
Perluasan tersebut dilaksanakan oleh assembler selama pembacaan pertama terhadap file sumber dan hasilnya ditunjukan dalam file listing (.LST). Makro dieksekusi lebih cepat daripada prosedur karena tidak membutuhkan instruksi CALL dan RET seperti pada prosedur. Melewatkan parameter. Satu fitur utama makro adalah kemampuannya untuk menanangani parameter yang dikirim. Ketika memanggil PUTCHAR, mislnya, kita akan memberikan nilai DL dengan karakater yang akan ditampilkan sebelum memanggil makro. Tapi jika kita menambah parameter pada definisi makro (char), kita dapat melewatkan karakter pada baris yang sama pada saat memanggil makro : putchar macro char mov ah, 2 mov dl, char int 21h endm . code … … putchar ‘A’ Pengiriman parameter dalam makro membuatnya lebih fleksibel dan baik dan dapat digunakan kapan saja. Makro untuk membuat data. Makro mungkin dipanggildari segmen data. Misalkan, makro dapat digunakan untuk mengalokasikan ruang untuk variabel. Pada contoh berikut, setiap isi tabel dibuat oleh marko ALLOC yang derifi dari empat ruang dan empat byte nol : alloc macro varname, numbyte varname db numbyte dup (‘ ’, 0, 0, 0, 0) endm … … . data alloc value1, 20 alloc value2, 50
kode yang diperluas : value1 db 20 dup(‘ ’, 0, 0, 0, 0) value2 db 50 dup(‘ ’, 0, 0, 0, 0) varname dan numbytes adalah parameter yang diperoleh dari arugemen yang dikirim pada saat makro dipanggil. Pendeklarasian dan pemanggilan makro Makro dapat dideklarasikan dimana saja dalam program, menggunakan perintah MACRO dan ENDM, sintaknya sebagai berikut : macroname MACRO [parameter-1][, parameter-2] … statements ENDM Perintah-perintah antara MACRO dan ENDM tidak diassemble sampai makro ditemukan. Macroname mungkin suatu nama simbol. Paramter adalah pilihan. Mungkin terdapat lebih dari satu paramter dalam definisi makro, asalkan dipisahkan oleh koma dan ditulis pada baris yang sama. Parameter-paramter ini sering disebut parameter dummy, mewakili nilai yang akan dikirim ketika makro digunakan. Semua statemen sebelum ENDM dianggap sebagai bagian dari makro. Pamanggilan makro. Suatu makro dipanggil pada saat namanya ditemukan beserta nilai-nilai yang akan dikirimnya. Pemanggilan makro berarti menyisipkan perintah-perintah dalam makro langsung dalam program. Sintak pemanggilan makro : Macroname [argumen-1][, argumen-2] … Macroname harus merupakan nama makro yang telah didefinisikan sebelumnya dalam file sumber. Setiap argumen adalah nilai yang dilewatkan ke makro, yang akan dikembalikan menimpa parameter dalam definisi makro asal. Urutan argumen harus sesuai dengan parameter asal, tapi jumlah paramter tidak boleh lebih banyak dari jumlah paramter asal. Jika terlalu banyak maka paramter selebihnya akan diabaikan. Jika paramternya kurang maka nilai parameter sisianya akan diset dengan string null : Contoh : makro DISPLAY. Untuk mengetahui bagaimana semua ini bekerja, kita buat sebuah makro yang diberina DISPLAY yang menampilkan string yang ditunjuk oleh DX. Tidak ada parameter yang dispesifikasikan oleh makro. display macro push ax mov ah, 9 int 21h pop ax endm
seperti dalam prosedur, kita sering push dan pop register dalam makro dengan tujuan untuk menjaga nilainya. Berikut ini untuk memanggil makro tersebut : mov dx, offset message display … … Pengiriman parameter Dengan menggunkan parameter dalam definisi makro, membuatnya lebih fleksibel. Kita tulis kembali makro DISPLAY menggunakan paramter yang disebut string, yaitu nama string yang akan ditampilkan : display macro string push ax push dx mov ah, 9 mov dx, offset string int 21h pop dx pop ax endm jadi, paramter string ditimpa setiap kali makro dipanggil. Jika kita ingin menampilkan tiga string, kita dapat memanggil makro tiga kali, mengirim argumen yang berbeda tiap kali : display msg1 display msg2 display msg3 … … msg1 db ‘Ini pesan perama’ msg2 db ‘Ini pesan kedua’ msg3 db ‘Ini pesan ketiga’ nama yang digunakan parameter dummy tidak akan tampil dalam listing program. Pengiriman argumen membuat makro DISPLAY berguna. Kita dapat menghindari komplikasi umum yang terlibat dalam pengiriman paramter ke prosedur. Kode berikut menunjukan kode yang dibangkitkan oleh assembler. Kita harus membayar harga kemudahan makro dengan ukuran program yang besar : display msg1 push ax push dx
mov ah, 9 mov dx, offset msg1 int 21h pop dx pop ax display msg2 push ax push dx mov ah, 9 mov dx, offset msg2 int 21h pop dx pop ax display msg3 push ax push dx mov ah, 9 mov dx, offset msg3 int 21h pop dx pop ax Makro LOCATE. Makro LOCATE meletakan kursor pada kolom dan baris yang diinginkan dalam layar : locate macro row, column push ax push bx push dx mov bx, 0 mov ah, 2 mov dh, row mov dl, column int 10h pop dx pop bx pop ax endm LOCATE mungkin dipanggil dengan mengirimkan nilai immediate, oeprand memori, atau nilai register selama panjangnya 8 bit. : locate 10, 20 locate row, col locate ch, cl
hati-hati dalam mengirim register sebagai argumen karena mungkin terjadi konflik dengan register yang sama yang digunakan dalam makro. Makro STARTUP. Makro STARTUP menginisialisasi register DS dan ES ke lokasi segmen data dan menyimpan alamat segemen PSP dalam variabel. STARTUP dirancang untuk bekerja dengan perintah segmen sederhana : startup macro pspseg push ds mov ax, @data mov dx, ax mov es, ax pop pspseg endm contoh pemanggilan startup myPSP Makro bersarang Salah satu cara untuk menyederhanakan makro adalah menggunakan makro yang sudah ada. Makro bersarang akan memanggil makro lain. Misalkan dibuat makro yang disebut DISPLAY_AT yang menampilkan string pada baris dan kolom yang diminta. Makro ini memanggil makro LOCATE dan DISPLAY dengan mengambil paramter yang dimilikinya dan mengirimnya sebagai argumen ke makro lain : display_at macro row, col, string locate row, col display string endm contoh pemanggilan display_at 10, 15, greeting … greeting db ‘Helllo dari baris 10, kolom 15’ Perintah LOCAL Perintah LOCAL memaksa assembler untuk membuat nama unik untuk label setiap kali makro dipanggil. Sintaknya sebagai berikut : LOCAL labelname Makro mungkin memerlukan lbel sebagi titik acuan untuk instruksi loncat (jump) atau loop. Ktia buat makro yang diberi nama REPEAT yang menampilkan karakte yang diminta berulang kali. Perintah LOCAL menyuruh assembeler untuk mengubah L1 menjadi nama yang unik setiap kali makro dipanggil :
repeat macro char, count local L1 mov cx, count L1 : mov ah, 2 mov dl, char int 21h loop L1 endm Jika kita memanggil REPEAT lebih daris sekali, kita akan melihat bagaimana assembler membuat label yang berbeda setiap kali. Assembler memberi nomor label dari 0000h sampai FFFFh dan mendahuluinya dengan tanda tanya. repeat ‘A’, 10 mov cx, 10 ??0000 : mov ah, 2 mov dl, ‘A’ int 21h loop ??0000 repeat ‘*’, 20 mov cx, 20 ??0001 : mov ah, 2 mov dl, ‘*’ int 21h loop ??0001 7.2. Teknik Khusus Prosedur Pemanggilan Macro Salah satu kekurangan yang dimiliki penggunaan makro adalah : makro meningkatkan jumlah kode yang dibangkitkan oleh assembler, karena setiap makro yang dipanggil merupakan salinan dari seluruh perintah dalam makro tersebut. Dari sisi ukuran program, prosedur lebih ekonomis. Kompromi terbaik antara keduaaanya adalah mempersingkat pengiriman parameter untuk pemanggilan prosedur. Menggunakan prosedur jika instruksi yang sama harus digunakan lebih dari sekali. Makro dapat menempatkan setiap parameter yang dikirim ke dalam register yang benar dan kemudian memanggil prosedur. Kita gunakan teknik ini untuk memanggil prosedur WRITEINT, yang menampilkan integer tidak bertanda pada konsol. Pemanggilan prosedur WRITEINT. Makro CALL_WRITEINT memanggil prosedur WRITEINTdari CONSOLE.LIB. Dua parameter, value dan radix, yang diload ke dalam AX dan BX. Kita menyimpan dan mengambil kembali kedua
register sebelum dan sesudah pemanggilan prosedur untuk meminimalkan dampaknya pada keseluruhan program : call_writeint macro value, radix push ax push bx mov ax, value mov bx, radix call writeint pop bx pop ax endm Kita dapat memanggil makro menggunakan register, variabel atau konstanta yang membuat prosedur lebih fleksibel. Tiga nilai yang ditampilkan oleh WRITEINT dalam contoh berikut adalah 8192, 1234 dan 1000000000000 : mov dx, 1234 call_writeint 2000h, 10 call_writeint dx, 16 call_writeint wordval, 2 … … wordval dw 1000h Perintah Assembly-Kondisional Dua belas perintah assembly-kondisional yang berbeda dapat digunakan bersamaan dengan makro untuk membuatnya lebih handal. Sintak umum perintah assembly-kondisional adalah : IF condition Statement [ELSE Statement ] ENDIF Beberapa perintah kondisi berikut akan diproses dalam perintah diatas : IF Sintak : IF ekspresi Mengijinkan assembly jika nilai ekspresi benar (tidak nol). Contoh berikut mengijinkan assembly jika count kurang dari 20 : IF count LT 20 Operator yang berkaian yang mungkin : LT, GT, EQ, NE, LE dan GE
IFE
Sintak : IFE ekspresi Mengijinkan assembly jika nilai ekspresi salah atau nol. Contoh berikut mengijinkan assembly jika count = 10 : IFE (count-10)
IF1
Sintak : IF1 Mengijinkan assembly jika nilai sekarang merupakan nilai pertama dari file sumber (hanya Microsoft Assembly).
IF2
Sintak : IF2 Mengijinkan assembly jika nilai sekarang merupakan nilai kedua dari file sumber (hanya Microsoft Assembly).
IFB
Sintak : IFB <argumen> Mengijinkan assembly jika argumen kosong. Nama argumen harus berada dalam kurung siku.
IFNB Sintak : IFNB <argumen> Mengijinkan assembly jika argumen tidak kosong. IFIDN Sintak : IFIDN <argumen1>,<argumen2> Mengijinkan assembly jika kedua argumen identik. Jika menggunakan perintah IFIDNI maka perbandingannya case sensitif. IFDIF Sintak : IFDIF <argumen1>,<argumen2> Mengijinkan assembly jika kedua argumen tidak identik. menggunakan perintah IFDIFI maka perbandingannya case sensitif.
Jika
IFDEF Sintak : IFDEF name Mengijinkan assembly jika name telah didefinisikan. IFNDEF Sintak : IFNDEF name Mengijinkan assembly jika name belum didefinisikan. ENDIF akhir blok yang dimulan dengan menggunakan perintah kondisional. ELSE mengassembly semua perintah sebelum ENDIF jika kondisi yang diperoleh pada kondisi IF bernilai salah. Pemeriksaan Argumen Makro. Makro mungkin mempunyai satu atau lebih parameter pilihan. Ini harus memeriksa untuk melihat apakah setiap argumen benarbenar dikirim. Jika tidak, assembly mengembalikan nilai blank untuk parameter dalam makro. Misalkan kita memanggil makro CALL_WRITEINT, tanpa mengirim nilai radix. Pada baris lima akan diassembli dengan instruksi yang salah :
Pemanggilan MACRO : call_writeint 1000h 1: 2: 3: 4: 5: 6: 7: 8:
Perintah perintah yang dibangkitkan call_writeint push ax push bx mov ax, 1000h ; nilai yang akan ditampilkan mov bx, ; radik yang digunakan (?) call writeint ; menampilkan AX dalam konsol pop bx pop ax
Perintah IFB akan mengembalikan nilai benar jika argumen makro kosong, dan IFNB mengembalikan nilai benar jika argumen makro ada isinya. Contoh, makro berikut yang diberi nama MYMAC, memeriksa nilai parm1 apakah nilainya ada pada saat dipanggil. Jika MYMAC dipanggil tanpa argumen, peritnah EXITM akan mencegah program lainnya untuk dibangkitkan : mymac macro parm1 ifb <parm1> exitm endif …. …. .code mymac mymac val1 Perintah EXITM Perintah EXITM memerintahkan assembler untuk keluar dari makro dan menghentikan pembangkitan kode. Ini mengurangi jumlah koda pada program akhir. Jika tidak diperlukan, instruksi dapat dihilangkan. Misalkan kita buat makro yang disebut GOTOXY yang memposisikan kursor pada layar pada posisi yang diberikan X, Y. Kita ingin keluar dari makro jika kedua argumen kurang dari nol. Kondisi IF membandingkan xval dengan nol menggunakan LT dan keluar jika nilainya benar. Begitu juga untuk xval : gotoCY macro xval, yval if xval LT 0 exitm endif if yval LT 0 exitm endif mov bx, 0
mov ah, 2 mov dh, yval mov dl, xval int 10h endm Perintah kondisi seperti IF harus diikuti oleh ekspresi yang dapat dievaluasi nilai benar atau salahnya pada saat assembly. Hal ini tidak akan bekerja pada nilai dalam register atau variabel memori. Menampilkan pesan selama assembly. Perintah %OUT digunakan untuk menampilkan pesan selama assembly untuk menunjukan progress, sebagai berikut: gotoCY macro xval, yval if xval LT 0 %out Argumen (xval) yang dikirim ke GOTOXY tidak benar. %out (nilai harus >= 0) endif if yval LT 0 %out Argumen (yval) yang dikirim ke GOTOXY tidak benar. %out (nilai harus >= 0) endif mov bx, 0 mov ah, 2 mov dh, yval mov dl, xval int 10h endm Jika kita memanggil GOTOXY dengan argumen –1 dan –2, maka akan ditampilkan pesan berikut : Argumen (-1) yang dikirim ke GOTOXY tidak benar. (Nilai harus >= 0) Argumen (-2) yang dikirim ke GOTOXY tidak benar. (Nilai harus >= 0) Makro WRITE. Berikut ini makro yang disebut WRITE yang menulis huruf ke output standar. Huruf dikirim sebagai argumen tunggal : write macro text, creturn local string, crlf push ax push dx mov ah, 9 mov dx, offset string
int 21h ifnb mov dx, offset crlf int 21h endif pop dx pop ax . data string db text, ‘$’ crlf db 0Dh, 0Ah, ‘$’ .code endm Perintah .DATA ditulis sebelum definisi variabel, ini diperlukan ketika menggunakan peritnah segmen sederhana, karena assembler selalu menghitung offset varibael dari segmen data. Dua variabel yang dibuat akan disimpan dalam segmen data. Perintah LOCAL diguankan dengan string dan crlf pada awal makro, sehingga nama ganda tidak akan dibuat ketiak makro dipanggil lebih dari satu kali. Makro WRITE baik khususnya untuk menampilkan pesan pada konsol, karena membuat program sumber mudah untuk dibaca. Berikut ini conoh pemanggailan makro WRITE : Write ‘Hello tthere’, N Write ‘No return on this line’ 7.3. Operator Makro Terdapat lima operator makro yang membuat makro lebih fleksibel ketika dipanggil. Berikut ini kelima operator tersebut : & operator substitusi <> operator teks-harfiah ! operator karakter-harfiah % operator ekspresi ;; komentar makro Operator substritusi (&). Dengan operator & kita dapat mengganti parameter dengan nilai yang telah dikirim sebagai argumen. Sintaknya : ¶meter Operator ini berguna khususnya ketika teks yang dikirim sebagai argumen harus disisipkan ke dalam string atau instruksi dalam makro. Contoh, makro DOSmsg berikut untuk membuat ruang memori untuk string yang dikirm sebagai argumen :
DOSmsg macro num, string msg&num db ‘DOS error : &String’, 0 endm Tabel berikut menunjukan contoh pemanggilan DOSmsg beserta hasilnya : Dipanggil DOSmsg 1, DOSmsg 2, DOSmsg3, <Path not found>
Kode yang diperluas msg1 db ‘DOS Error : Invalid function’,0 msg1 db ‘DOS Error : File not found’,0 msg1 db ‘DOS Error : Path not found’,0
Operator Ekspresi (%). Kadang-kadang hasil ekspresi harus dikirim sebagai argumen makro. Operator % digunakan pada awal ekspresi untuk memberitahu assembler bahwa hasil ekspresinya, bukan ekspresinya sendiri, dikrim ke makro. Berikut ini makro MEMDISPLAY yang menulis string langsung ke buffer video. Kita dapat memanggil makro baik menggunakan nilai angka tunggal atau ekspresi : memdisplay macro offset, string mov ax, videoseg mov es, ax mov di, ofset … … … endm Ketika pemanggilan MEMDISPLAY, argumen pertama adalah offset ke dalam buffer video untuk karakter pertama yang akan ditampilkan. Argumen kedua adalah nama string. Offset dapat berupa nilai tunggal seperti 320, atau dapat berupa hasil ekspresi yang melibatkan simbol konstanta : row = 10 col = 40 … … memdisplay %((row * 160)+(col*2)), string1 memdisplay 320, string2
Operator teks-harfiah (<>). Operator teks-harfiah mengelompokan serangkaian karakter ke dalam sebuah string. Ini menghindari kesalahan assembler dari interpretasi bahwa isi rangkaian tersebut merupakan argumen terpisah. Berikut ini contoh makro MESSAGE sebagai contoh : message macro text db ‘&text’, 0 endm pemanggilan makro berikut : message <Efficiensy is 50 %, & falling;> akan diassembly sebagai berikut : db ‘Efficiensy is 50 %, & falling;’,0 Operator karakter-harfiah (!). Operator karakter-harfiah ditemukan dengan tujuan yang sama seperti operator teks-harfiah. Operator ini memaksa assembler untuk memperlakukan karakter khusus. Berikut ini contoh penggunaannya : message <Efficiency is !> than 50%> ini akan diassembly sebagai db ‘Efficiency is > than 50%’, 0
7.4. Library Makro Makro CCALL. Salah satu penggunaan makro yang sangat baik adalah meningkatkan set instruksi Intel - ini akan memudahkan program untuk ditulis. Makro CCALL (condition call) memungkinkan untuk memanggil prosedur berdasarkan flag, menggunakan instruksi tunggal : Ccall macro cond, procname local L1, L2 j&cond L1 jmp L2 L1 : call procname L2 : exitm endm
makro dapat berdasarkan kondisi flag tertentu. Contoh, kita dapat memanggil prosedur DOS_ERROR ketika CF diset. Misalkan sebagai berikut : Ccall c, DOS_error Atau kita memanggil LOWER jika value1 kurang dari ata sama dengan AX : Asal cmp value1, ax Ccall le, lower
Kode yang dibangkitkan cmp value1, ax jle ??0002 jmp ??0003 ??0002 : call lower ??0003 :
kita dapat memanggil NOT_EQUAL jika AX tidak sama dengan BX : cmp ax, bx Ccall ne, not_equal Setelah membandingkan dua stirng, kita dapat memanggil EXCHANGE : call compare Ccall a, exvhange Makro CMPJ. Makro CMPJ (compare and jump) membandingkan dua operand dan loncat ke label berdasarkan flag : cmpj macro dest, flag, source, label cmp dest, source j&flag label endm contoh pemanggilan cmpj ax, le, bx, label1 cmpj cx, e, count, exit
; jika AX <= BX, loncat ke label1 ; jika CX = count, loncat ke exit
Makro MULT. Seperti kita ketahui, instruksi MUL menyebabkan keterbatasan tertentu; AL atau AX merupakan operand tujuan otomatis, dan operand sumber immediate tidak diperbolehkan. Makro MULT pada contoh berikut melakukan perkalian operand 16-bit oleh register, operand memori, atau operand immediate : mult macro dest, soruce push ax
push bx mov ax, dest mov bx, source mul bx mov dest, ax pop bx pop ax endm Makro MULT mengalikan dest dengan source, menempatkan hasilnya dalam dest. Jika hasilnya lebih besar dari 16 bit, maka CF diset, dan bagian atas hasilnya disimpan dalam DX. Contoh berikut memanggil MULT mendemonstrasikan flexibilitas dalam perkalian operand berbagai tipe : mov cx, value1 mult cx, 5 mult value1, value2 mult value2, 5 … … value1 dw 100h value2 dw 2 Makro MMOVE. Set instruksi Intel tidak mempunyai instruksi pemindahan dari memori ke memori. Makro MMOVE dapat melakukan hal ini. Seperti contoh berikut : mmove macro dest, source push ax if (type dest) EQ 1 mov al, source mov dest, al else if (type dest) EQ 2 mov ax, source mov dest, ax endif endif pop ax endm Contoh pemanggilan mmove word2, word1 mmove byte2, byte1
; 16-bit move ; 8-bit move
Karena operator TYPE digunakan pada makaro ini, maka pesan kesalahan akan ditampilkan jika tidak terdapat perintah .DATA pada file sumber sebelum definisi makro. Hal ini terjadi karena assembler memerlukan untuk meletakan varibel sebelum dapat mengevaluasi tipenya. Segmen berikut mungkin bisa digunakan : . stack 100h . data (variabel) (definisi makro) . code (instruksi) Loncat Kondisional dan Liupan (Conditional Jumps and Loops). Set instruksi Intel mempunyai batasan jangkauan instruksi loncat kondisional – termasuk LOOP – sampai 127 byte kedepan atau 128 byte ke belakang. Khususnya ketika program mempunyai sejumlah pemanggilan makro dalam jangkauan loncat kondisional atau liupan, ini mungkin menyebabkan keluar dari range. Misalkan kita akan mengkonversi prosedur WRITESTRING, READSTRING dan WRITEINT menjadi makro dan menggunakannya dalam program : L1 :
mov cx, 10 writestring promt readstring buffer writeint 1000h, 10 loop L1
Contoh ini akan menyebabakan kesalahan sintak karena kode menghasilkan dengan makro didalamnya, liupan yang lebih dari 127 byte. Maka LOOP akan keluar range. Makro LLOOP. Makro LLOOP (long loop) mengijinkan kita untuk meliup ke suatu label dalam segmen sekarang. Dia melakukan ini dengan meliup ke instruksi JMP yang meloncat ke tujuan. JMP, tidak seperti LOOP, dapat menjangkau suatu label dalam segmen : LLoop macro dest local A1, A2 loop A1 jmp A2 A1 : jmp dest A2 : endm
Makro ini menggunakan instruksi LOOP tidak seperti biasanya. Dia meloncat ke depan ke label A1. Pada lokasi ini, instruksi JMP kembali loncat ke dest. Ketika CX = 0, LOOP terjadi dan loncat ke A2, yaitu lokasi instruksi berikutnya. 7.5. Penggunaan Makro Lebih Lanjut Pendefinisian Blok Berulang Satu atau lebih perintah dapat diulang menggunkana perntah REPT, IRP dan IRPC. Hal ini memungkinkan bagi sebuah makro untuk membuat struktur data yang besar. Perintah REPT. Perintah REPT mengulang satu blok instrukti berdasarkan pencacah. Sintaknya sebagai berikut : REPT ekspresi statemen ENDM Ekspresi menentukan jumlah pengulangan dan mengevaluasi bilangan tidak bertanda 16-bit. Misalkan kita ingin menggunakan REPT untuk mendefinisikan ruang untuk tabel yang mengandung data 100 mahasiswa : index label byte rept 100 db ? dup (?) db 20 dup (‘ ‘) dw ? endm kita bisa menggunakan cara yang sama untuk membuat makro yang dapat menggeser operand ke kiri dengan jumlah tertentu. Contoh berikut, count menentukan jumlah instruksi SHL yang dibangkitkan oleh assembler : mshl macro dest, count rept count shl dest, 1 endm endm ini merupakan definisi makro bersarang. Kita dapat melihat bagaimana makro ini dipanggil dengan dua cara, seperti berikut ini : mshl ax, 1 mshl bx, 4
kode yang diperluas shl ax, 1 shl bx, 1 shl bx, 1 shl bx, 1 shl bx, 1 Perintah IRP. Perintah IRP membuat pengulangan blok jika setiap pengulangan mengandung nilai yang berbeda. Sintaknya sebagai berikut : IRP parameter, <argumen [, argumen] …> Statemen ENDM Blok diulang sekali untuk setiap argumen: begitu dia mengulang, nilai argumen sekarang digantikan untuk parameter. Perintah ini berguna untuk menginisialisasi tabel atau blok data dimana terdapat nilainya yang bervariasi. Argumen mungkin berupa nama simbol, string atau konstanta numerik. Statemen sumber irp parm, <10, 20, 30, 40> dw parm, parm*2, parm * 3, parm * 4 endm Dibangkitkan oleh assembler dw 10, 10* 2, 10*3, 10*4 dw 20, 20* 2, 20*3, 20*4 dw 30, 30* 2, 30*3, 30*4 dw 40, 40* 2, 40*3, 40*4 IRP dapat menginisialisasi tabel offset prosedur. Ini membuktikan kegunaan jika kita ingin mengkodekan pencabangan dengan berbagai cara berdasarkan nilai index. Contoh : mov bx, indexvalue ; memilih tabel entry call proctable[bx] ; pemanggilan tidak langsung Empat nama prosedur dikirim sebagai argumen dalam contoh IRP berikut. Masing-masing disisipkan ketika procname tampil, menghasilkan dalam tabel yang mengandung offset prosedur : proctable label word irp procname, <movup, movdn, movlft, movrt>
dw procname endm perintah-perintah berikut akan dibangkitkan : proctable label word dw movup dw movdn dw movlft dw movrt Makro Jump Tambahan. Program yang menggunakan loncat kondisional atau loop memungkinkan masuk dalam masalah ketika keluar dari range yaitu 127 byte. Seperti dalam makro LLOOP yang telah dibuat, kita dapat membuat makro extended jump yang mengijinkan loncat kondisional ke label terdekat. Sebagai berikut : jxe macro dest local L1, L2 je L1 jmp short L2 L1 : jmp dest L2 : endm Dengan makro ini kita dapat membuat instruksi sebagai berikut, dimana loopTop dapat berada dimana saja dalam program. jxe loopTop Masalanya disini adalah kita harus membuat makro yang terpisah untuk masingmasing instruksi jump yang berbeda. Disinilah kelebihan instruksi IRP yang hanya perlu satu blok instruksi saja untuk mengakomodasi seluruh kondisi jump, sebagai berikut : irp cond, jxe&cond macro dest local L1, L2 j&cond L1 jmp short L2 L1 : jmp dest L2 : endm endm Berikut ini contoh pemanggilan yang dapat dilakukan : jxa L1
; jump extended if above
jxae L3 jxz L1 jxne L4 jxg L2 jxo L1
; jump extended if above or equal ; jump extended if zero ; jump extended if not equal ; jump extended if greater ; jump extended on overflow
Makro Penggeseran Generik. Diatas telah dibuah makro MSHL yang dapat melakukan penggeseran operand ke kiri sejumlah yang kita inginkan. Dengan mengkombinasikan perintah IRP dan makro tersebut kita dapat membuat suatu prosedur penggeseran yang lebih handal, sebagai berikut : irp styp, <shl, shr, sal, sar, rol, ror, rcl, rcr> m&styp macro dest, count rept count &styp dest, 1 endm endm endm Contoh pemanggialan makro tersebut adalah : mshl ax, 3 mrcl count, 2 mshr bx, 4 mror ax, 5 Instruksi yang dibangkitkan oleh assembler adalah sebagai berikut : mshl ax, 3 shl ax, 1 shl ax, 1 shl ax, 1 mrcl count, 2 rcl count, 1 rcl count, 1 Perintah IRPC. Perintah IRPC pada dasarnya sama dengan IRP, kecuali jumlah karakter dalam string argumen menentukan jumlah pengulangan. Sintaknya sebagai berikut : IRPC parameter, string Statemen ENDM String harus ditutup dengan kurung siku (<>) jika mengandung spasi, atau karakter khusus lainnya. Contoh berikut membangkitkan lima variabel (value_A,
value_B, dan sebagainya) menggunakan karakter dalam string ABCD sebagai argumen : irpc parm, ABCDE value_&parm db ‘&parm’ endm Menghasilkan perintah sebagai berikut : value_A db ‘A’ value_B db ‘B’ value_C db ‘C’ value_D db ‘D’ value_E db ‘E’ Tip-tip Tambabahan Menyimpan Macro dalam File Include. Setelah membuat kumpulan makro, akan menjadi tidak baik kalau harus menyalin semuanya pada setiap program baru. Terdapat cara yang lebih baik yang dengan membuat file yang berisi makro dan dengan menggunakan perintah INCLUDE untuk menyalinnya pada waktu assembly. Hanya makro yang digunakan yang menjadi bagian dari program akhir. Jika kita menggunakan two-pass assembler seperti Microsoft Assembler, akan lebih baik untuk menyimpan perintah INCLUDE dalam lingkungan pengecekan kondisi IF1, yang memerintah assembler untuk melibatkan makro hanya pada saat pertama kali saja : if1 include lib1.mac endif Berikut contoh file makro yang dapat digunakan pada aplikasi yang memerlukan salah satu makro yang ada di dalamnya : ; Macro.Inc ; File ini harus di-include kan pada setuap program sumber yang memerlukan. ; Program juga harus di link ke CONSOLE.LIB call_WriteInt cCall cmpj display_at exit getYN inputInt inputStr
locate mDisplay mMove mshl mult putchar repeat startup
jx_ lLoop
write
extern ReadInt : proc, ReadString : proc ; menulis integer ke konsol caall_WriteInt macro value, radix push ax push bx mov ax, value mov bx, value call writeint pop bx pop ax endm ; pemanggilana prosedur kondisional cCall macro cond, procname local L1, L2 j&cond L1 jmp L2 L1 : call procname L2 : exitm endm ; membandingkan dua operand dan loncat ke <dest> ; berdasarkan flag cmpj macro dest, flag, source, label cmp dest, source j&flag label endm ; menampilkan string pada baris, kolom dalam konsol display_at macro row, col, string locate row, col mDisplay string endm ; keluar ke Doss dan emngambalikan kode exit macro ecode mov ah, 4Ch
mov al, ecode int 21h endm ; mengambil respon Y/N (y/n). Argumen <exact> harus ; huruf besar yang akan menset ZF. GetYN macro prompt, exact write prompt mov ah, 1 int 21h sub al, 32 cmp al, exact endm ; menampilkan promt huruf pada , dan ; menginpun integer dan menyimpannya pada <dest> inputInt macro row, col, promt, dest locate row, col write prompt call ReadInt mov dest, ax endm ; menampilkan prompt huruf pada , . Kemudian memasukan ; string ASCIIZ dan menyimpannya ke <dest>. Maksimum karakter = <max> inputStr macro row, col, prompt, dest, max locate row, col write prompt push cx push dx mov dx, offset dest mov cx, max call ReadString pop dx pop cx endm ; Jump eXtended (JX_); loncat kondisional ; ke label NEAR (dimana saja dalam segmen) irp cond, jxe&cond macro dest local L1, L2
j&cond L1 jmp short L2 L1 : jmp dest L2 : endm endm ; Loop ke label NEAR (dimana saja dalam segmen) lLoop macro dest local A1, A2 loop A1 jmp A2 A1: jmp dest A2 : endm ; meletakan kursor pada , pada video halaman 0. locate macro row, column push ax push bx push dx mov bx, 0 mov ah, 2 mov dh, row mov dl, column int 10h pop dx pop bx pop ax endm ; menampilkan $-terminated string mDisplay macro string push ax push dx push ah, 9 mov dx, offset string int 21h pop dx pop ax endm ; memindahkan word atau byte dari memori ke memori
mmove macro dest, source push ax if (type dest) EQ 1 mov al, source mov dest, al else if (type dest) EQ 2 mov ax, source mov dest, ax endif endif pop ax endm ; menggeser <dest> ke kiri, kali dengan melakukan sekumpulan ; instruksi penggeseran tunggal mshl macro dest, count rept count shl dest, 1 endm endm ; mengalikan dua operand mult macro dest, source push ax push bx mov ax, dest mov bx, source mul bx mov dest, ax pop bx pop ax endm ; mengeluarkan karakter ke konsol putchar macro char mov ah, 2 mov dl, char int 21h endm ; mengeluarkan karakter kali
repeat macro char, count local L1 mov cx, count L1 : mov ah, 2 mov dl, char int 21h loop L1 endm ; set DS dan ES ke segmen data. Menyimpan ; alamat segmen PSP dalam variabel startup macro pspSeg push ds mov ax, @data mov ds, ax mov es, ax pop pspSeg endm ; makro WRITE menulis huruf ke output standar. adalah string ; yang berada antara tanda kutip. Jika tidak kosong, ; mengindikasikan bahwa carriage return ditampilkan. write macro text, creturn local string, crlf push ax push dx mov ah, 9 mov dx, offset string int 21h ifnb mov dx, offset crlf int 21h endif pop dx pop ax . data string db text, ‘$’ crlf db 0Dh, 0Ah, ‘$’ .code endm ; makro berikut menghasilkan delapan makro, yang bernama MSHL,
; MSHR, MSAR, MROL, MROR, MRCL, dan MRCR irp styp, <shl, shr, sal, sar, rol, ror, rcl, rcr> m&styp macro dest, count rept count &styp dest, 1 endm endm endm 7.6. Operator dan Perintah Lanjut Operator Tipe Semua operator assembler berikut adalah type atau atribut suatu variabel atau label. Operator-operator tersebut adalah sebagai berikut : Sinak HIGH ekspresi LENGTH variabel LOW ekpresi OFFSET ekpresi type PTR ekpresi SEG ekspresi SHORT label SIZE variabel THIS type
Nilai yang dikembalikan Byte bagian-atas sebuah ekspresi Jumlah elemen dalam sebuah variabel Byte bagian-bawah sebuah ekspressi Alamat offset sebuah ekspresi Memaksa ekspresi menjadi tipe yang diinginkan Alamat segmen sebuah ekspresi Set label bertipe SHORT Panjang variabel kali tipenya Membuat operand tipe yang diinginkan pada lokasi sekarang. . TYPE ekpresi Mode dan lingkup ekspresi TYPE ekspresi Jumlab byte dalam variabel/struktur Operator SEG. Operatro SEG mengembalikan alamat segmen sebuah label, variabel, nama segmen, nama grup atau operand memori lain. Contoh berikut memindahkan segmen array ke dalam AX kemudian menyalinnya ke dalam DS : mov ax, seg array mov ds, ax Operator SHORT. Operator ini sering kali digunakan denan instruksi JMP ketika kita ketahui loncat ke depan akan kurang dari atau sama dengan 127 byte dari lokasi sekarang. Ini mengijinkan assembler untuk membangkitkan 2-byte instruksi jump pendek daripada 3-byte instruksi jump near. Operator TYPE. Operator type mengembalikan ukuran, dalam byte, elemen tunggal sebuah variabel. Contoh, variabel 8-bit akan mengembalikan tipe 1, variabel 32-bit akan mengembalikan 4, array byte akan mengembalikan 1 dan array 16-bit integer akan mengembalikan 2. Tipe label near adalah FFFFh, dan tipe label far adalah FFFEh. Contoh :
var1 db 20h var2 dw 1000h var3 dd ? var4 db 10, 20, 30, 40, 50 msg db ‘File not found’, 0 … L1 : mov ax, type var1 mov ax, type var2 mov ax, type var3 mov ax, type var4 mov ax, type msg mov ax, type L1 Operator LENGTH. Operator Length menghitung jumlah elemen individual dalam variabel yang telah didefinisikan menggunakan DUP. Jika DUP tidak digunakan, length akan mengambalikan nilai 1. Contoh : val1 dw 1000h val2 db 10, 20, 30 array dw 32 dup(0) array2 dw 5 dup(3 dup(0)) message db ‘File not found’, 0 … mov ax, length val1 mov ax, length val2 mov ax, length array mov ax, length array2 mov ax, length message Variabel string mengembalikan nilai 1. Jika operator DUP bersarang digunakan, hanya yang paling luar saja yang dihitung oleh LENGTH. Operator SIZE. Operator ini sama dengan perkalian antara panjang variabel dengan nilai tipenya. Conoth, array berikut nilai 16-bit mempunyai TYPE 2 dan LENGTH 32. maka SIZE nya adalah 64 : intArray dw 32 dup(0) String berikut mempunya SIZE i kareng LENGTH dan TYPE nya sama-sama satu : Message db ‘This is a message’,0
Perintah STRUC Perintah STRUC mendefinisikan struktur (template atau pola) yang mungkin membebani ruang memori. Struktur juga dapat menginisialisasi area dalam program ke nilai default. Bagian individu struktur disebut field. Kita mendefinisikan struktur banyak kesamaannya dengan makro. Contoh, kita dapat mendefinisikan struktur menjelaskan field dari record mahasiswa. Definisi struktur berikut harus ditempatkan dalam file sumber dimana saja di depan segmen data : StudentStruc struc stnumber db ‘0000000’ lastname db ‘ credits dw 0 status dw 0 StudentStruc ends
; awal struktur ‘
; 20 spasi ; akhir struktur
Field dalam struktur berjumlah sampai 30 byte. Dalam segmen data kita dapat mendefinisikan varibel struktur, dengan alokasi 30 byte memori. . data srec StudentStruc <> Tanda kurung siku (<>) diperlukan untuk memerintahkan assembler menjaga nilai field default yang disediakan dalam definisi struktur. Penggantian nilai default. Kita dapat mengganti nilai default dengan nilai baaaru. Nilai baru harus dipisah dengan koma. Contoh berikut penimpahan berbagai field dalam StudentStruc : srec myRecord yourRecord
StudentStruc <’12345567’, ‘Dedi’, 30, 1> StudentStruc <,,50,0> StudentStruc <,’Dodi’>
; seluruh field ; 2 field terakhir ; field ke 2
Field yang menggunakan oprator DUP dalam deklarasi struktur asal tidak dapat dikesampingkan. Misal filed lastname dalam deklarasi StudentStruc adalah : lastname db 20 dup (‘ ’) Usaha berikut yang mencoba mengganti field ini akan menimbulkan kesalahan sintak : srec StudentStruc <, ‘Joni’> Menggunakan Variabel Struktur. Ketika variabel struktur dibuat, pengacuan terhadap field individual dibuat dengan pemisahan nama variabel dan nama field oleh tanda titik :
mov dl, srec.stnumber mov ax, srec.credits Assembler menambah offset variabel struktur ke offset field dalam struktur unt membuat alamat efektif. Dalam struktur StudentStruc, offset stnumber adalah 0 karena ini merupakan awal field dalam struktur. Offset kredit adalah 27, offset lastname adalah 7 dan seterusnya. Jika register basis menunjuk ke variabel struktur, tanda titik memisahkan index dengan field : mov bx, offset srec … … mov ax, [bx].credits mov dl, [bx].status berbagai mode pangalamatan yang mungkin digunakan : mov ax, srec[si].credits mov dl, [bx+si].status mov dl, srec [bx+di].stnumber Contoh Program Input Struktur. Berikut ini program yang mendemonstrasikan strukur, dengan menggunakan beberapa makro dai file MACRO.INC. Program terhubung dengan CONSOLE.LIB dan include file MACRO.INC. title Program Input Struktur dosseg . model small . stack 100h extrn Clrscr:proc include macro.inc stnumberSz = ? lastnameSz = 20 StudentStruc struc stnumber db stnumberSz dup(0), 0 lastname db lastnameSz dup(0), 0 credits dw 0 StudentStruc ends .data srec StudentStruc <>
pspSeg dw ? progTitle db ‘Contoh Input Struktur Student’ .code main proc startup pspSeg L1 : call ClrScr display_at 2, 20, progTitle inputStr 4, 10, ‘Student Number : ’, srec.stnumber, stnumberSz inputStr 6, 10, ‘ Last Name : ’, srec.lastname, lastnameSz inputInt 8, 10, ‘Credits Taken : ’, srec.credits locate 12, 10 getYN ‘More input (Y/n) ?’, ‘Y’ jxe L1 call ClrScr exit 0 main endp end main Variabel srec mengimplementasikan STRUC yang disebut StudentStruc, sehingga pengacuan srec dilakukan dengan format : srec.stnumber srec.lastname srec.credits makro inputStr dalam MACRO.INC melakukan input keyboard untuk program ini. Argumen yang dikirm ke makro adalah row, column, prompt, input nama field, dan panjang field. Makro DISPLAY_AT menampilkan stirng pada baris dan kolom tertentu di layar. Makro GETYN adalah makro untuk mengambil respon pengguna apakah akan meneruskan lagi atau tidak. Akhirnya makro jxe (jump extended equal) diperlukan karena instruksi JE konvensional akan menyebabkan kesalahan “jump out of range”. Perintah RECORD Perintah RECORD merupakan penjelasan kumpulan bit dalam suatu operand byte atau word. Kita menggunakan perintah ini untuk membuat masking bit dan penggeseran bit lebih mudah. Pertama, record harus didefinisikan deng nama record dan nama dan lebar setiap field. Sintak untuk pendefinisian record adalah : recordname RECORD field [, field] … Sintak untuk filed adalah
fieldname : width [= ekspresi] fieldname adalah nama filed tertentu dalam record, dan field awal disimpan dalam bit yang paling berarti dari byte atau word. Berikut ini contoh penggunaan perintah RECORD untuk mendefiniskan susunan bit tanggal 16-bit yang disimpan dalam direktori disk. Tanggal dalam bit-terpetakan, dengan 7 bit untuk tahun, 4 bit untuk bulan dan 5 bit untuk hari : 1111111111111111 tahun bulan hari penggunaan yang sesuai dengan perintah RECORD untuk tanggal adalah : date_record record year:7, month:4, day:5 catatan : setiap nama field harus diikuti oleh lebarnya, diekspresikan oleh jumlah bit. Mungkin juga memberikan nilai default terhadap field. Misalkan recordnya diinisialisasi tanggal 1 Januari 1980 (nilai tahun 0 menandakan tahun 1980) : date_record record year:7=0, month:4=1, day:5=1 jika kita mendefinisikan record yang mengandung 8 bit atau kurang, record secara otomatis akan mengacu pada byte – selebihnya, akan mengacu pada word. Jika semua posisi bit tidak digunakan, field bit adalah rapat kanan. Contoh, record berikut hanya mendefinisikan 12 bit. Assembler menset bit posisi rendah dalam field dan menset 4 bit atas tidak bertanda dengan nol : bitrec record field1:6=111111b, field2:6=111111b nilai seluruh 16 bit adalah : 0000111111111111 Pembuatan Variabel Record. Ketika record telah didefinisikan, mungkin digunakan untuk membuat variabel record. Sintaknya adalah : [name] recordname <[initialvalue[, initialvalue]]…> Kita dapat memberikan nilai awal pada field tertentu. Jika nilai yang diberikan terlalu besar, maka assembler akan menampilkan pesan kesalahan. Berikut ini contoh variabel record menggunakan definisi date_record diatas, sebagai berikut : date_record record year:7=0, montah:4=1, day:5=1 … …
daterec date_record <> dengan cara lain, kita dapat menginisialisasi daterec dengan 30 May 1990 : daterec date_record <10, 5, 30> Penggeseran dan Masking. Akhir dari semuanya, nama field dalam record membantu kita untuk menggeser dan mask dengan lebih mudah. Contoh penyimpanan record 10 Maret 1989 : 0001001 0011 01010 tahun = 9 bulan=3 hari=10 Misalkan tanggal dipindah ke AX, kita dapat mengisolasi bit yang membuat bulan dengan meng-AND-kan AX kemudian menggesernya ke kanan : and ax, 0000000111100000b mov cl, 5 shr ax, cl Operator MASK. Jika kita menggunakan perintah RECORD untuk mendefinisikan date_record, kita dapat meningkatkan perintah sebelumnya. Operator MASK membuat mask terhadap bit : semua bit yang berkorespondensi dengan posisi bit diset, dan semua bit lain di nolkan : mov ax, file_date and ax, mask month mov cl, month shr ax, cl Pada saat date_record didefinisikan, assembler otomatis membuat nilai angka pada masing-masing field, tergantung pada nilai penggeserannya. Ini dapat diinterpretasikan sebagai offset bit field dari posisi 0. Pada contoh sebelumnya month dipindah ke CL, menyebabkan jumlah penggeseran. Tabel berikut menunjukan nilai geser setiap field : 0001001 0011 01010 tahun = 9 bulan=3 hari=10 Field Year Month Day
Nilai geser 9 5 0
Operator WIDTH. Operator WIDTH mengambalikan jumlah bit dalam field record. Contoh berikut mengakses lebar masing-masing field dalam date_record dalam berbagai cara. Berikut ini nilai-nilai pada saat assembly : date_record record year:7=0, month:4=1, day:5=1 … daterec date_record <> size_of_year equ width year size_of_month equ width month … … mov ax, width day if (width, date_record) gt 8 mov ax, daterec else mov al, daterec endif
7.7. Contoh Penggunaan Macro Dalam Program .MODEL SMALL .STACK 300h ClrScr MACRO push ax push bx push cx push dx mov ah,06h mov cx,0000h mov al,00h mov bh,07H mov dh,24h mov dl,79h int 10h pop dx pop cx pop bx pop ax ENDM
;u/ clear screen
;siapin service & attr layar
;pake interupt 10h
GoToXY MACRO col,row push ax push bx push dx mov dh,row mov dl,col mov ah,02h mov bh,00 int 10h pop dx pop bx pop ax ENDM
;u/ goto cursor
;simpan baris di dh ;simpan kolom di dl ;warna biasa ;pake int 10h
PrintIt MACRO buffer push ax push dx lea dx,buffer mov ah,09h int 21h pop dx pop ax ENDM
;u/ cetak kelayar
OpenFile MACRO mov al,02h mov ah,3dh lea dx,FileName int 21h mov FileHand,ax ENDM
;u/ open file
ReadFile MACRO mov ah,3fh mov bx,FileHand mov cx,81 lea dx,InfoData int 21h ENDM CloseFile MACRO mov ah,3eh mov bx,FileHand int 21h ENDM
;pakai servis 09h u/ print string ;pake int 21h
;buka file dengan nama filename ;simpan penanganannya ke variabel ;filehand ;u/ untuk read file ;dari variabel filehand ;sebanyak 81 karakter ;simpan isi file pada variabel ;infodata ;u/ close file ;var filehand ditutup
SendFile MACRO mov ah,40h mov bx,FileHand mov ch,0 mov cl,InfoLine lea dx,InfoData int 21h ENDM
;u/ write to file ;ke variabel filehand ;sebanyak cx=banyak karakter ;karakter yg disimpan diambil dr ;variabel infodata
FileIndex MACRO mov al,02h mov ah,42h mov bx,FileHand mov cx,0h mov dx,0h int 21h ENDM
;u/ file pointer ;tidak jadi diimplementaikan ;karena program tidak dapat melakukan ;reedit. ;fungsi:u/ nunjuk ke EOF
CreateFile MACRO mov ah,3ch mov cx,00 lea dx,FileName int 21h ENDM
;u/ bikin file
Clearence MACRO push cx mov ch,00 mov cl,02 RepeatClearence: GotoXY 00,cl PrintIt BlankLine inc cx cmp cx,22 jne RepeatClearence pop cx ENDM
;dengan type file biasa ;dengan nama filename
;u/ ngapus editor
;kosongkan baris ;dari baris 2 sampai baris 22 ;dari cl=2 sampa cl=22
.DATA MainMenu DB 'X:Exit S:Save O:Open$' BlankLine DB ' $' GiveLine '===============================================$' Interface DB 'Tekan ESC untuk Menu$ ' MsgFileSaved DB 'File Disimpan!$'
DB
MsgFileOpen DB 'Masukkan nama file :$' NewLine DB 0AH,0DH,'$' Space DP 20H,'$' Line DB 2 ;nyimpen posisi baris Column DB 0 ;nyimpen posisi kolom FileNameInf DB 41 dup(' '),'$' FileStruct LABEL BYTE ;struktur u/ nama file MaxLen DB 40 ;panjang max namafile ActLen DB ? ;panjang namafile saat ini FileName DB 40 dup(' '),0 ;isi nama file InfoStruct LABEL BYTE ;struktur u/ isi file MLength DB 80 ;panjang maksimum file InfoLine DB ? ;panjang file saat ini InfoData DB 81 dup(' '),'$' ;isi file FileHand DW ? ;file handler u/ op. file .CODE start: main PROC FAR mov ax,DGROUP mov ds,ax mov es,ax CLRSCR GoTOXY 00,01 PrintIT GiveLine GotoXY 00,22 PrintIt GIveLine GotoXY 00,23 PrintIt Interface GotoXY 00,02 lea mov input: mov int cmp je cmp je cmp je
dx,InfoStruct InfoLine,00 ah,07 21h al,1Bh OpenMenu al,0dh AddLine al,08h ToBackSPACE
;Awal Program ;tunjuk segmen data
;format layar ;baris 1 pake garis ;baris 22 pake garis ;tulis help u/ menu ;tunjuk alamat mem u/ file ;set isi buffer mem 0 ;input caracter ;wait 4 input ;esc char check ;enter check ;Backspace Chek
cmp al,20h jnl disp cmp al,7Eh jng disp jmp input
;cek apakah input karakter yg legal ;antara 20h s/d 7eh ;klo ya, tampilin ke layar ;klo enggak, minta input lagi
disp: mov dl,al mov ah,02 int 21h inc Column
;display char ;tambahan counter kolom
mov InfoData[si],al ;insert to mem inc InfoLine ;increment counter cmp si,79 ;klo belum 80 karakter jne NextInput ;ulangi proses pengetikan jmp Finish ;else keluar NextInput: inc si ;increment string index jmp input ToBackSpace: jmp BackSpace
;bantuan u/ ke jmp ke BACKSPACE
AddLine: ;untuk membuat baris baru mov infodata[si],0dh ;+ENTER di mem inc si inc InfoLine inc Line mov Column,0 mov infodata[si],0ah ;+kolom baru di mem inc si inc InfoLine cmp si,79 ;klo belum 80 char jne NextAddLine ;tampilin newline jmp Finish ;else keluar NextAddLine: mov ah,09h ;tampilin baris baru lea dx,NewLine int 21h jmp input OpenMenu: GotoXY 0,23 PrintIt BlankLine GotoXY 0,23
;bersihin baris 23
PrintIt MainMenu ;cetak menu mov ah,07 int 21h cmp al,'x' ;cek x jne Comps jmp Finish ;klo x exit CompS: cmp al,'s' ;cek s jne CompO jmp SaveMe ;klo s save CompO: cmp al,'o' ;cek o jne CompRev jmp OpenMe ;klo o open CompRev: cmp al,1BH ;cek ESC jne NextOpenMenu ;klo ya ulang bikin menu jmp Revert ;klo tdk, balik ke mode ngetik NextOpenMenu: jmp OpenMenu SaveMe: GotoXY 00,24 PrintIt BlankLine GotoXY 00,24 PrintIt MsgFileOpen lea dx,FileStruct mov ah,0ah int 21h mov mov mov
;
lea dx,InfoStruct SendFile GotoXY 00,24 PrintIt BlankLine
;tampilin pesen minta file ;load struktur file ;minta nama file dari keybd
bh,0 bl,actlen fileName[bx],' '
CreateFile OpenFile FileIndex
;kosongkan baris 24
;ilangin enter pada namafile
;bikin filenya ;buka filenya ;ini u/ reedit file. ;tidak jadi diimpelementasikan ;karena ketertbatasan interface ;load struktur file ;simpan ke file ;tampilin pesen bahwa file
GotoXY 00,24 PrintIt MsgFileSaved jmp Revert
;berhasil disimpan
OpenMe: GotoXY 00,24 PrintIt BlankLine GotoXY 00,24 PrintIt MsgFileOpen
;rutin pembacaan file ;kosongkan baris pesan ;pesan minta file
lea dx,FileStruct mov ah,0ah int 21h mov mov
;load struktur file ;minta file dari input keybd
bh,0 bl,actlen
mov Filename[bx],'$' GotoXY 00,00 PrintIt BlankLine GotoXY 00,04 PrintIt BlankLine GotoXY 00,00 PrintIt FileName mov
Filename[bx],' '
Clearence OpenFile cld lea di,infodata mov cx,40 mov ax,2020h rep stosw lea dx,InfoStruct ReadFile GotoXY 00,02 PrintIt InfoData CloseFile jmp Revert Revert:
;beri tanda endstr pada nama file
;tampilin nama file di baris plg atas ;kosongkan endstr nama file ;bersihin editor ;buka file
;hapus isi buffer infodata saat ini ;biar enggak ngganggu tampilan ;sebanyak 40x2 karakter ;isi dengan karakter spasi ;repeat untuk all byte infodata ;load struktur isi file ;baca filenya ;pindahin kursor ;tulis isi filenya ;tutup file ;kembali ke mode edit
GotoXY 00,23 ;u/ kembali ke mode edit PrintIt BlankLine ;kosongkan baris 23 GotoXY 00,23 PrintIt Interface ;tampilan pesan u/ menu GotoXY Column,Line ;kembali ke baris editor jmp Input ;minta input lagi Finish: ClrScr GotoXY 00,00 mov ah,4ch int 21h BackSpace: cmp Column,00 je ToInput
;bersihin layar ;keluar dari program
;klo udah diawal baris ;lewati bag ini
mov infodata[si],' ' ;hapus tanda karakter backspace dec si ;di mem dec InfoLine dec Column mov infodata[si],' ' ;hapus karakter dikiri kursor di mem GotoXY Column,Line ;pindahkan kursor PrintIt Space ;hapus karakter dilayar GotoXY Column,Line ;pindahkan kursor ToInput: jmp input main ENDP END start
VIII. HUBUNGAN DENGAN BAHASA TINGKAT TINGGI
8.1. Hubungan Dengan Turbo Pascal Subrutin bahasa assembly yang dipanggil oleh Turbo Pascal harus diassembly dulu ke dalam file .OBJ kemudian di-link ke program utama oleh kompilator Pascal. Subrutin mendeklarasikan nama dan variabel public-nya dengan menggunakan perintah PUBLIC. Dalam program Pascal utama, kita menggunakan perintah EXTERNAL untuk mendeklarasikan nama subrutin. Contoh deklarasi prosedur dan fungsi sebagai berikut : procedure Locate (row, col : integer) ; external, function StrtoUpper (sultan : string):string; external ; Perintah $L. Perintah ini mengidentifikasikan file .OBJ yang mengandung subrutin eksternal yang akan dihubungkan dengan program utama. Kompilator Turbo Pascal otomatis mengkonversi file objek dari format objek Intel ke format yang dimiliki Borland. Jika, contohnya, kita ingin menghubungkan program Pascal ke program yang telah diassemble, ASMRTN.OBJ, perintah $L harus ditempatkan pada progam pascal sebelum perintah BEGIN untuk program utama. Ataum jika dihubungkan dengan unit Pascal maka ditulis sebelum BEGIN utama unit tersebut : {SL ASMRTN} Pemanggilan NEAR dan FAR. Turbo Pascal otomatis memilih tipe yang benar dari pemanggilan (near atau far) berdasarkan deklarasi prosedurnya. Prosedur atau fungsi FAR dideklarasikan dalam bagian interface unit dan dapat dipanggol dari program atau unit lain. Prosedur NEAR dideklarasikan dalan program atau pada bagian implementasi unit dan dapat dipanggil hanya dalam program atau unit yang sama. Kita harus mendeklarasikan prosedur bahasa assembly sebagai NEAR atau FAR, instruksi kecocokan interpretasi Pascal. Berikut ini contoh assembler menghasilkan tipe instruksi RET (RET atau RETF) yang benar : Deklarasi Prosedur assembler subroutine_1 proc near subroutine_2 proc far
Type instruksi RET yang dibangkitkan oleh assembler RET (near) RETF (far)
Nama Segmen. Pascal memerlukan nama segmen khusus untuk digunakan dalam subrutin bahasa assembly : kode dan instruksi harus ditempatkan dalam segmen diberi nama CODE (atau CSEG), dan variabel harus ditempatkan dalam segmen diberi nama DATA (atau DSEG). Variabel tidak dapat diinisialisasi dengan nilia awal, seperti yang dilakukan pada bahasa assembly.
Argumen. Argumen-argumen Pascal dimasukan ke dalam stack sebelum prosedur atau fungsi dipanggil. Jumlah argumen ditentukan oleh jumlah parameter dalam deklarasi prosedur atau fungsi. Register. Register BP, SP, SS dan DS harus tetap dalam subrutin bahasa assembly. Register lain boleh dimodifikasi. Prosedur Contoh Misalkan terdapat subrutin yang diberi nama LOCATE, yang akan dipanggil oleh Turbo pascal. Kita akan memanggilnya untuk meletakan kursor apda baris dan kolom tertentu di layar. Dua parameter integer dispesifikasikan dalam deklarasi prosedur : procedure Locate (trow, tcol : integer); berbagai perubahan yang dilakukan terhadap parameter dalam LOCATE tidak akan berpengaruh terhadap variabel yang dikirim sebenarnya, karena LOCATE tidak mempunyai akses ke lokasinya. Misalkan subrutin ditempatkan dalam segmen kode yang sama, pemanggilan yang dekat dieksekusi : locate (row, col); Listing program LOCATE.PAS dan LOCATE.ASM seperti berikut ini : Program Calling_Locate; Uses crt; Procedure Locate (trow, tcol : byte); external; {$L LOCATE} const row = 10; col = 20; Begin ClrScr; Locate(row, col); Write (‘*’); End. Program dalam bahasa assembly LOCATE.ASM title Prosedur LOCATE, yang dipanggil oleh Turbo pascal code segment assume cs:code public locate
locate proc near push bp mov bp, sp mov dx, [bp+6] mov dh, dl or dx, [bp+4] dec dh dec dl mov ah, 2 mov bh, 0 int 10h sub sp, 4 mov ax, [bp+6] mov [bp-2], ax mov ax, [bp+4] mov [bp-4], ax mov sp, bp pop bp ret 4 locate endp code ends end Pada program diatas diasumsikan baris dan kolomnya sama dengan 10 dan 20. Pascal menyimpan nilainya dalam stack, diikuti oleh alamat kembali 16-bit. Pascal selalu menyimpan argumen dari kiri ke kanan, sehingga baris dimasukan ke dalam stack duluan. Pada ilustrasi berikut, kita akan melihat bagaimana instruksi dieksekusi oleh progam pemanggil : Instruksi push row push col call Locate
Stack 10 20 ret addr
Ketika LOCATE mengendalikan, SP menunjuk alamat kembali (return address). Kita memasukan salinan BP ke dalam stack untuk menjaga nilainya, kemudian menset BP ke SP :
Instruksi
Stack 10 20 ret addr BP
push bp mov bp, sp
SP
Variabel Lokal. Subrutin membuat variabel lokal dengan menyediakan rung untuknya dalam stack, dibawah penunjuk stack (SP). Dia melakukan hal ini dengan mengurngi SP sesuai dengan ukuran variabel lokal. Misalkan subrutin LOCATE mempunyai duaa variabel lokal, row_val, daan col_val. Masing-masing variabel panjangnya 2 byte, sehingga kita mengurangi SP dengan 4. Dari titik acuan, subrutin mengacu row_val sebagai [BP-2] dan col_val sebagai [BP-4] : Instruksi
Stack
sub sp, 4
SP
[BP+6] [BP+4] [BP+2] BP [BP-2] [BP-4]
10 20 ret addr BP xx xx
row_val col_val
Gabungan dari alamat kembali (return address), parameter yang dikirim, dan variabel lokal disebut stack frame. Subrutin LOCATE mengakses variabel lokal dengan mengurangkan offset dari BP, dan parameter yang dikirim diakses dengan menambah offset terhadap BP. Untuk menunjukan eprbedaannya, berikut ini contoh instruksi menulis untuk menyalin parameter yang dikirim ke dalam variabel lokal : mov ax, [bx + 6] mov [bp-2], ax mov ax, [bp+4] mov [bp-4], ax Pada saat subrutin siap untuk dikembalikan ke program pemanggil, dia akan menset ulang SP ke nilai asalnya dan mengembalikan BP.
Instruksi
Stack
mov sp, bp pop bp ret 4
10 20 ret addr
SP
Akhirnya perintah ret 4 memerintahkan CPU untuk menambah SP dengan 4 sesudah mengambil alamat kembali ke dalam IP. Mengirim Argumen Dengan Nilai (Passing Arguments by Value) Ketika Turbo pascal mengirim argumen dengan nilai, ukuran dan tipe variabel menentukan bagaimana dia akan dikirim. Jika paramter panjangnya 1, 2, atau 4 byte, nilainya mungkin disimpan dalam stack. Jika nilai parameter lebih besar dari 4 maka alamtnya akan disimpan dalam stack. Kemudian subrutin harus menyalin parameter ke dalam variabel memori lokal. Parameter byte dikirim sebagai sebuah word dalam stack, dengan kode ASCII karakter pada byte bawah. Sedang byte atas tidak didefinisikan. Parameter character selau dikirim sebagai byte. Parameter boolean dikirm sebagai byte dengan nilai 1 atau 0. Paramter tipe enumerasi dikirim sebagai byte tidak bertanda jika mempunya nilai 256 atau lebih sedikit, jika lebih besar maka dikirim sebagai word tidak bertanda. Contoh Procedure Sub1 (ch : char; flag : boolean) Stack frame Inside Sub1 :
BP =SP
ch flag ret addr BP
[BP+6] [BP+4] [BP+2]
Dalam subrutin kita harus menghapus byte atas setiap paramter karena nilainya tidak didefinisikan. and [bp+4], 0FFh and [bp+6], 0FFh
Argumen bilangan real langsung dikirim ke dalam stack. Format default turbo pascal untuk bilangan real adalah 6-byte real khusus. Parameter pointer dikirmi sebagai dua word ke dalam stack. Bagian segmen dimasukan terlebih dulu diikuti oleh offsetnya. Gambaran berikut menunjukan bagaimana stack setelah pointer dimasukan ke dalamnya :
Stack frame Inside Sub2 : BP =SP
segment offset ret addr BP
[BP+6] [BP+4] [BP+2]
Jadi, [BP+6] mengandung nilai segmen pointer, dan [BP+4] mengandung nilai offset. Hal ini memudahkan subrutin untuk mengambil pointer menggunakan LDS atau LES ke dalam segmen dan register index. Seperti contoh berikut : push ds lds si, [bp+4] Argumen String atau Array dikirim sebagai alamat 16-bit. Jika argumen dikirim sebagai nilai, subrutin menyalin string atau array ke dalam stack sehingga variabel asal tidak akan diubah. Misalkan kita mempunyai program pascal yang didalamnya menyertakan prosedur WRITEUPCASE, yang dideklarasikan sebagai berikut : procedure WriteUpCase (st : string); berikut ini tampilan pada Turbo Debugger : WRITEUPCASE : begin push bp mov bp, sp sub sp, 0104 les di, [bp+04] push es push di lea di, [bp-0100] push ss push di mov ax, 00FF push ax call 668F:0670
Terdapat overhead yang harus diperhatikan (stack dan waktu eksekusi) jika string disalin ke dalam stack. Menggunakan pointer ke string mungkin lebih efisien. Mengirim Argumen dengan Acuan (Passing Arguments by Reference) Pascal juga dapat menangani pengirim argumen dengan acuan. Hal ini menyebabkan alamat variabel 32-bit dikirim. Prosedur yang dipanggil mempunyai pilihan pengubahan variabel. Contoh, berikut ini contoh prosedur SWAPINT yang menukarkan dua integer tidak bertanda, keduanya dikirim dengan acuan. Kita mengasumsikan kedua variabel berada dalam segmen yang sama : public SwapInt SwapInt proc near push bp mov bp, sp push ds lds bx, [bp+8] mov ax, [bx] lds bx, [bp+4] xchg ax, [bx] mov [bx+8],ax pop ds pop bp ret 4 SwapInt endp Contoh : Fungsi COUNT_CHAR Subrutin COUNT_CHAR menghitung berapa kali karakter tertentu ditemukan dalam string. Program pemanggila mengirim sebuah karakter dan alamat string. Subrutin bahasa assembly mengembalikan jumlah sebagai integer dari karakter yang dikirim tersebut. Sebagai berikut : Program Pascal_Contoh_1; Uses crt; {$L PASEX1A} VAR St : string; Ch : character; Count : integer; Function Count_Char (st:string; c:char):integer; external; BEGIN Write (‘Masukan string : ’);
Readln (St); Write (‘Karakter yang akan dihitung : ’); Ch:=ReadKey; Writeln (ch); Count := count_char(st, ch); Writeln (‘Karakter ’, ch, ‘ditemukan ’, count, ‘kali.’); END. title prosedur Count_Char char equ [bp+4] string equ [bp+6] public count_char code segment assume cs:code count_char proc near push bp mov bp, sp push ds mov bx, 0 mov ax, 0 mov dl, char lds si, string lodsb mov cx, ax L1 : lodsb Cmp al, dl jne L2 inc bx L2 : loop L1 mov ax, bx pop ds pop bp ret 6 count_char endp code ends end
Program Pascal menggunakan perintah $L untuk mengidentifikasi nama program objek yang diassembly : {$L PASEX1A} deklarasi fungsi EXTERNAL :
Pascal
untuk
COUNT_CHAR
menyertakan
peringah
count := Count_char (st, ch); dalam modul bahasa assembly mengandung COUNT_CHAR, kita menamai segmen CODE sehingga subrutin akan sesuai dengan nama segmen default Pascal. Nama COUNT_CHAR dideklarasikan PUBLIC, sehingga linker akan mengirim informasi ke program Pascal. Identifier yang Dideklarasikan dalam Modul Pascal Program bahasa assembly juga dapat mengakses data dan subrutin yang di deklarasikan dalam program Turbo C atau Turbo Pascal. Contoh berikut menunjukan program assembly yang menggunakan rutin Pascal untuk tampilan dan masukan data : title AddNumbers dosseg .model small .code public addNums extrn getNum : near extrn dispRresult : near addNums proc near push bp xor cx, cx @1 : push cx call getNum pop cx cmp ax, 0 je @2 add cx, ax jmp @1 @2 : push cx call dispResult pop bp ret addNums endp
code ends end Berikut ini program Pascal yang memanggil addNums : Program AddNums Uses crt; {$L cnums} Procedure addNums; external; Function getNum : Integer; var temp : integer; begin write (Masukan bilangan, 0 untuk keluar : ’); readln (temp); getNum := temp; end; Procedure dispResult (res : Integer); var ch : char; begin write (‘Hasilnya adalah : ’, res); ch := readKey; end; begin addNums; end. Program pascal diatas tidak memanggil rutin yang dimilikinya, malahan memanggil rutin addNums yang ada di modul assembly. Semua rutin lain dalam Pascal dipanggil oleh modul bahasa assembly. 8.2. Turbo Built-In Assembler (BASM) Baik Turbo C maupun Turbo Pascal mempunyai pemroses bahasa assembly built-instruksi, yang dikenal sebagai BASM (built-in assembler). Dengan BASM perintah-perintah bahasa assembly dapat dikodekan langsung dalam bahasa tingkat tinggi. Sintak BASM pada Turbo Pascal
Dalan Turbo pascal, instruksi bahasa assembly harus dikodekan di antara kata kunci asm dan end. Semua perintah diantara kedua kata kunci ini harus merupakan instruksi bahasa assembly. Selain itu diperbolehkan adanya komentar yang berada diantara tanda komentar Pascal yaitu {}. Berikut ini contoh penggunaan BASM : asm mov ax, int1 xchg ax, int2 mov int1, ax end; Dalam program Turbo pascal, blok asm …. end harus berada dalam blok begin … end dari sebuah prosedur atau fungsi atau blok utama program :
Procedure showAsm; Begin (Kode Pascal) asm (perintah-perintah bahasa assembly) end; End; Kekecualian lain adalah jika deklarasi prosedur atau fungsi mengandung perintah assembler ; maka sintaknya sebagai berikut : Procedure showAsm; assembler; asm (perintah bahasa assembly) end; Contoh berikut adalah prosedur yang disebut SwapInt, dituliskan dalam BASM Procedure SwapInt (var int1, int2 : integer); var t1, t2 : integer; begin t1 : = int1; t2 : = int2; asm mov ax, t1 xchg ax, t2 mov t1, ax end; int1 : = t1;
int2 : = t2; end; Parameter int1 dan int2 dikirim dengan referensi (passed by refference), dan t1 dan t2 adalah variabel lokal yang diassign oleh int1 dan int2. Nilai variabel lokal dipertukarkan dan kemudian diassign balik ke parameter int1 dan int2. Kita juga dapat langsung tanpa menggunakan variabel sementara : Procedure SwapInt (var int1, int2 : integer); assembler; asm lds bx, int1 push bx mov ax, [bx] lds bx, int2 xchg ax, [bx] pop bx mov [bx], ax end; Disini kita dapat mengambil alamat yang dikirim dalam int1 dan int2 dan mengaksesny melalui DS:BX. Dengan bekerja langsung dengan alamat variabel, kita dapat mempertukarkan isinya tanpa menggunakan variabel sementara. Juga, prosedur ini tidak mempunyai blok begin …. end. Ketika perintah assembler disertakan dalam deklarasi prosedur, maka perintah begin tidak digunakan. Semua instruksi yang dikodekan dalam prosedur harus instruksi bahasa assembly. Perintah assembler dalam deklarasi prosedur mempengaruhi cara kompilator membangkitkan kode untuk rutin; perintah ini memaksa kompilator untuk melaksanakan minimal dua optimalitas : Parameter nilai tidak disalin ke dalam variabel lokal (dialokasikan dalam stack). Paramter nilai lain yang ukurannya 1, 2, 4 byte harus dideklarasikan dan diakses sebagai parameter var. Tidak ada frame stack dibangkitkan untuk rutin yang tidak mempunyai paramter dan tidak ada variabel lokal. Fungsi yang menggunakan perintah assembler harus mengembalikan hasil sebagai berikut : Tipe integer, char, dan boolean harus mengembalikan nilainya dalam AL untuk nilai 8-bit, AX untuk nilai 16-bit dan DX:AX untuk nilai 32-bit. Tipe Real harus mengembalikan nilainya dalam DX:BX:AX. Tipe pointer harus dikembalikan dalam DX:AX. Tipe string dikembalikn dalam lokasi sementara, yang diacu oleh simbol fungsi khusus @Result. Berikut ini fungsi Count_Char, yang dikodekan sebagai fungsi assembler Pascal : Function count_char (str : string; c:char):integer; assembler; Label L2; asm
mov bx, 0 mov ax, 0 mov dalam, c lds si, str loadsb mov cx, ax @1 : lodsb cmp al, dl jne L2 inc bx L2 : loop @1 mov ax, bx end; Jumlah karakter diakumulasikan dalam register BX. Diatas loop yang ada, nilai dalam BX dipindahkan ke dalam AX dan dikembalikan untuk memanggil rutin sebagai hasil fungsi integer. Fungsi ini mengilustrasikan penggunaan label normal dan lokal. Label normal harus dideklarasikan sebelumnya dengan menggunakan perintah LABEL, seperti pada label L2. Label local diproses menggunakan simbol @ dan tidak perlu di deklarasikan. Label lokal terbatas pada blok dimana mereka digunakan, sementara label normal dapat diakses dari luar lingkungannya. Contoh berikut menunjukan rutin konversi huruf besar dalam rutin BASM : Function UpCase (stg : string): string; assembler; asm push ds cld lds si, stg les di, @Result lodsb stosb xor ah, ah mov cx, ax jcxz @3 @1 : lodsb cmp al, ‘a’ jb @2 cmp al, ‘z’ ja @2 xor al, 20h @2 : stosb loop @1 @3 : pop ds end;
@Result merupakan identifier standar Turbo pascal untuk variabel hasil fungsi. Kita juga dapat menggunakan simbol @Return untuk mengembalikan tipe hasil untuk fungsi yang dideklarasikan tanpa perintah assembler. 8.3. Pernyataan dan Perintah Inline Pada Turbo C dan Pascal juga terdapat penggunaan kode assembly inline. Ini merupakan kode bahasa assembly dimana byte bahasa mesinnya dikodekan dalam perintah. Conth kode BASM untuk menghapus layar akan menjadi sebagai berikut Procedure clrScr; assembler; asm mov ah, 0Fh int 10h mov ah, 0 int 10h mov ah, 2 mov dx, 0000h mov bh, 0 int 10h end; Berikut ini prosedur yang menggunakan perintah inline : Procedure ClrScr; Begin Inline ( $B4/$0F/ {mov ah, 0F $CD/$10/ {int 10h} $B4/$00/ {mov ah, 0 $CD/$10) {int 10h} $B4,$02/ {mov ah, 2 $BA/$00 {mov dx, 0 $B7/$00 {mov bh, 0 $CD/$10 {int 10h} End;
mengambil mode video} menset mode video } posisi kursor } pada baris , kolom} pada halaman video 0}
8.4. Antarmuka Turbo Assembler dengan Turbo Pascal Turbo Assembler menyediakan fasilitas yang banyak dan handal untuk menggabungkan program bahasa assembly ke program turbo pascal. Mengapa turbo assembler perlu ditambahkan dalam program pascal Melakukan perintah yang tidak terdapat dalam turbo pascal
Kecepatan yang lebih baik dengan langsung mengakses bahasa assembler. Perintah Kompilator $L, External Dengan menggunakan perintah {$L MYFILE.OBJ} menyebabkan turbo pascal akan mencari file MYFILE.OBJ Setiap prosedur atau fungsi turbo assembler yang akan disertakan dalam turbo pascal harus dideklarasikan sebagai simbol PUBLIC. Sintak prosedur dan fungsi external adalah : Procedure AsmProc( a : Integer ; b : Real ); external; Function AsmFunc ( c : Word ; d : Byte); external; Deklarasi prosedur external harus diletakan pada level paling luar dari program atau unit. Perintah PUBLIC Hanya label yang dideklarasikan PUBLIC dalam modul bahasa asembly yang terlihat ke Turbo Pascal. Label merupakan objek yang dapat diekspor dari bahasa assembly ke turbo pascal. Lebih jauh, setiap label yang dibuat PUBLIC harus mempunyai prosedur atau fungsi yang bersesuaian yang dideklarasikan dalam program turbo pascal. Label public tidak harus merupakan bagian dari deklarasi PROC. Dalam turbo pascal, asmLabel
PROC FAR PUBLIC Bar
dan asmLabel : PUBLIC Bar adalah sama saja. Pendefinisian simbol PUBLIC hanya dilakukan dalam segmen CODE. Turbo pascal tidak mengijinkan pendefinisian simbol PUBLIC dalam segmen data. Perintah EXTRN Modul dalam turbo assembler dapat mengakses prosedur, fungsi, variabel, atau konstanta pada turbo pascal yang dideklarasikan level program atau unit yang paling luar yang di-link. Label turbo pascal dan konstanta biasa tidak terlihat dalam bahasa assembly. Misalkan program turbo pascal mendeklarasikan variabel global berikut : Var a : Byte; b : Word;
c : Shortint; d : Integer; e : Real; f : Single; g : Double; h : Ectended; i : Comp; j : Pointer; Variabel-variabel diatas dapatdiakses oleh program bahasa assembly dengan deklarasi EXTRN, seperti berikut : EXTRN A : BYTE; EXTRN B : WORD; EXTRN C : BYTE; EXTRN D : WORD; EXTRN E : FWORD EXTRN F : DWORD; EXTRN G : QWORD; EXTRN H : TBYTE; EXTRN I : QWORD; EXTRN J : DWORD; Prosedur dan fungsi pada turbo pascal dapat diakses dengan cara yang sama. Misal terdapat unit turbo pascal sebagai berikut : Unit sample; {unit contoh yang mendefinisikan beberapa prosedur turbo pascal yang dapat dipanggil dari prosedur bahasa assembly} interface procedure TestSample; procedure PublicProc; implementation var A : word; Procedure AsmProc; near; external; {$L ASMPROC.OBJ} procedure PublicProc; begin {PublicProc} Writeln(‘In PublicProc’); End; {PublicProc} Procedure NearProc near; Begin Writeln(‘In NearProc’); End;
Procedure FarProc; far; Begin Writelan(‘In FarProc’); End; Procedure TestSample; Begin Writeln(‘Value of A before ASMPROC = ’, A); A:=10; Writeln(‘Value of A after ASMPROC = ’,A); End; End. Prosedur AsmProc dapat memanggil prosedur PublicProc, NearProc, atau FarProc dengan menggunakan perintah EXTRN sebagai berikut : DATA
SEGMENT WORD PUBLIC ASSUME DS : DATA EXTRN A : WORD DATA ENDS CODE SEGMENT BYTE PUBLIC ASSUME CS:CODE EXTRN PublicProc : FAR EXTRN NearProc EXTRN FarProc : FAR AsmProc PROC PUBLIC AsmProc Call FAR PTR PublicProc Call NearProc Call FAR PTR FarProc Mov cx,ds:A Sub cx,2 Mov ds:A,cx Ret AsmProc ENDP CODE ENDS END
:
Program utama untuk mencoba unit pascal dan kode assembler adl : Program Tsample; Uses Sample; Begin TesSample; End.
NEAR NEAR
Untuk membangun program contoh dengan perintah baris sbb: TASM ASMPROC TPC /B TSAMPLE TSAMPLE Peraturan Pengiriman Parameter Dalam Turbo Pascal Turbo pascal melewatkan parameter menggunakan stack CPU. Parameter selalu dievaluasi dan dimasukan ke dalam stack secara terurut. Parameter Nilai. Parameter nilai adalah parameter yang tidak dapat diubah oleh subprogram yang dipanggil. Tipe Skalar. Parameter nilai untuk semua tipe skalar (boolean, char, shorint, byte, integer, word, longint, subrange dan enumerasi) dilewatkan sebagai nilai dalam stack CPU. Jika objek berukuran 1 byte, maka dimasukan penuh 16-bit word; jika objek berukuran 2 byte, maka dimasukan sesuai dengan datanya. Jika objek 4 byte maka dimasukan dua kali 16-bit word. Tipe Real. Parameter nilai tipe real dimasukan sebagai 6 byte pada stack. Tipe Pointer. Paramater nilai semua tipe pointer dimasukan langsung ke dalam stack – pertama word yang mengandung segment, kemudian yang lain yang mengandung offset. Paramter String. Parameter ini tidak memperhatikan ukuran, biasanya tidak dimasukan ke dalam stack. Turbo pascal menyimpan pointer dari string tersebut, yang bertanggung jawab untuk memanggil subprogram tidak untuk mengubah string yang diacu oleh pointer. Subprogram harus membuat dan bekerja pada duplikat string tersebut, jika memerlukan. Tipe Record dan Array. Record dan array yang kenyataannya 1,2 atau 4 byte adalah diduplikasi langsung ke dalam stack ketika dilewatkan sebagai parameter nilai. Jika objek array atau record berukuran lain (misal 3 byte), maka pointer yang menunjuknya disertakan dalam stack. Tipe Set. Set, seperti string, biasanya tidak dimasukan secara harfiah kedalam stack. Pointer yang menunjuknya yang dimasukan ke dalam stack. Pointer yang diterima oleh subprogram akan menunjuk ke “biasanya” 32-byte representasi set. Parameter variabel. Semua parameter variabel dilewatkan dengan cara yang sama.
Pengelolaan Stack Dalam turbo pascal semua parameter dalam stack CPU akan dibersihkan sebelum subprogram yang dipanggil selesai. Ada dua cara untuk mengatur stack. Menggunakan instruksi RETN (dimana N adalah jumlah byte parameter yang dilewatkan), atau menyimpan alamat kembali dalam register (atau dalam memory) dan mengambil parameter satu per satu. Mengakses parameter. Pada saat rutin turbo assembler menerima kontrol, puncak stack mengandung alamat return (dua atau empat byte, tergantung apakah rutin tersebut dekat atau jauh). Terdapat tiga teknik dasar untuk pengaksesan parameter yang dilewatkan dari turbo pascal ke rutin turbo assembler : Menggunakan register BP untuk menunjuk stack. Menggunakan register basis atau index yang lain untuk memperoleh parameter. Mengambil alamat kemabli, kemudian mengambil parameter Cara pertama dan kedua sering menyebabkan konflik sedang cara ketiga lebih baik. Menggunakan BP untuk menunjuk stack Teknik pertama (dan sering digunakan) untuk mengakses parameter yang dilewatkan dari turbo pascal ke turbo assembler adalah menggunakan register BP, sebagai berikut : CODE
SEGMENT ASSUME cs : CODE MyProc PROC FAR PUBLIC MyProc J EQU WORD PTR [bp+6] I EQU WORD PTR [bp+8] Push bp Mov bp,sp Mov ax,I …
; procedure MyProc(i,j : integer); ; j diatas bp & alamat kembali ; I diatas j ; mempersiapkan BP pemanggil ; BP menunjuk pada puncak stack ; alamat I via BP
Perintah ARG Turbo assembler mempunyai cara lain untuk menghitung offset stack dan melaksanakan persamaan teks yaitu perintah ARG. Perintah ini digunakan di dalam PROC. Perintah ARG secara otomatis menentukan ofset parameter relatif terhadap BP. Perintah ini juga menghitung ukuran blok parameter untuk penggunaan instruksi RET. Karena simbol-simbol yang dibuat oleh perintah ARG didefinisikan didalam lingkup PROC, maka tidak diperlukan nama parameter yang unik untuk setiap prosedur atau fungsi. Berikut ini penggunaan perintah ARG untuk contoh diatas. CODE
SEGMENT ASSUME cs : CODE
MyProc
PROC FAR PUBLIC MyProc ARG j : WORD, i : WORD = RetBytes Push bp Mov bp, sp Mov ax, i …
Perintah ARG membuat simbol lokal untuk parameter i dan j, pada baris perintah : ARG j : WORD, i : WORD = RetBytes Secara otomatis mempersamakan simbol i ke [WORD PTR BP+6], simbol j ke [WORD PTR BP+8] dan simbol RetBytes ke nomor 4 (ukuran blok parameter dalam byte) selama prosedur. Perintah .MODEL Perintah .MODEL melakukan segmentasi yang mudah pada rutin turbo assembler dan memberikan keleluasaan untuk menspesifikasikan model memori dan dukungan bahasa. Berikut ini contoh penggunaan .MODEL
MyProc
. MODEL large, PASCAL . CODE PROC FAR i : BYTE, j:BYTE RETURNS result : DWORD PUBLIC MyProc Mov ax,i … ret
Penggunaan perintah .MODEL melakukan kebiasaan pemanggilan dalam turbo pascal, seperti mendefinisikan nama segmen, melakukan PUSH BP dan MOV BP,SP dan juga melakukan return dengan POP BP dan RET N. Menggunakan Register Basis atau Index yang Lain Teknik kedua untuk mengakses parameter adalah menggunakan register basis atau register index – BX, SI atau DI – untuk mengambil parameter dari stack. Segemen default untuk register-register tersebut adalah DS. Berikut ini penggunaan BX untuk mendapatkan parameter : CODE MyProc
SEGMENT ASSUME cs : CODE PROC FAR PUBLIC MyProc
J I
EQU WORD PTR ss:[bx+4] EQU WORD PTR ss:[bx+6] Mov bx,sp Mov ax, i …
Pada rutin yang menggunakan sedikit pengacuan ke parameter, teknik ini dapat menghemat waktu dan ruang karena BX tidak perlu disimpan, tidak seperti BP. Hasil Fungsi Dalam Turbo Pascal Fungsi Skalar. Hasil fungsi tipe skalar dikembalikan ke dalam register CPU. Nilai 1 byte disimpan dalam AL, 2-byte nilai dalam AX, dan 4-byte nilai dalam DX:AX Fungsi Real. Hasil fungsi tipe real 6-byte tipe real disimpan dalam register CPU. Most-significant word disimpan dalam DX, word tengah dalam BX dan paling terakhir dalam AX. Fungsi 8087. Hasil fungsi tipe 8087 dikembalikan pada register (puncak stack) 8087, ST(0). Fungsi String. Hasil fungsi string dikembalikan di daerah sementara yang dialokasikan turbo pascal sebelum pemanggilan. Pointer yang menunjuk daerah ini disimpan dalam stack sebelum parameter pertama dimasukan. Fungsi Pointer. Hasil fungsi pointer disimpan dalam register DX : AX (segment : offset) Pengalokasian Ruang untuk Data Lokal Pengalokasian memori stasis pribadi Turbo pascal mengijinkan program turbo assembler untuk menyediakan memori untuk variabel statis dalam segment data global (DATA atau DSEG). Untuk mengalokasikan memori dengan menggunakan perintah DB, DB dll, seperti berikut ini : DATA MyInt MyByte … DATA
SEGMENT PUBLIC DW? DB? ENDS
Pengalokasian memori dinamis Rutin turbo assembler juga dapat mengalokasikan memori tidak tetap (variabel local) pada stack selama waktu pemanggilan. Berikut ini contoh pengunaan alokasi memori dinamis : CODE
SEGMENT ASSUME cs : CODE
MyProc
PROC FAR PUBLIC MyProc LOCAL a : WORD, b : WORD = LocalSpace i EQU WORD PTR [bp+6] Push bp Mov bp,sp Sub sp,LocalSapce Mov ax, 42 Mov a, ax Xor ax, ax Mov b, ax … mov sp, bp pop bp ret 2 MyProc ENDP CODE ENDS END Kalimat LOCAL a : WORD, b : WORD = LocalSpace Menyamakan simbol a ke [BP-2], simbol b ke [BP-4], dan simbol LocalSpace ke nomor 4 (ukuran area variabel lokal) selama prosedur dilakukan. Tidak ada kalimat yang bersesuaian untuk membuat simbol yang mengacu pada parameter karena itu persamaan i ke [BP+6] tetap ada. Cara yang lebih baik untuk inisialisasi variabel lokal adahan memaskukan nilainya daripada mengurangi SP. Maka SUB SP dapat diganti dengan Mov ax, 42 Push ax Xor ax, ax Push ax Contoh-contoh rutin yang dapat dipanggil oleh turbo pascal : Rutin konversi hexa tujuan umum. CODE SEGMENT ASSUME cs : CODE, ds : NOTHING ByteCount EQU BYTE PTR ss:[bp+6] Num EQU DWORD PTR ss : [bp + 8] ResultPtr EQU DWORD PTR ss : [bp + 12] HexStr PROC FAR PUBLIC HexStr Push bp Mov bp, sp Les di, resultPtr Mov dx, ds
Lds si, num Mov al, byteCount Xor ah, ah Mov cx, ax Add si, ax Dec si Shl ax, 1 Cld Stosb HexLoop : Std Lodsb Mov ah, al Shr al, 1 Shr al, 1 Shr al, 1 Shr al, 1 Add al, 90 H Daa Adc al, 40H Daa Cld
HexStr CODE
Stosb Mov al, ah And al, 0Fh Add al, 90h Daa Adc al, 40h Daa Stosb Loop HexLoop Mov ds, dx Pop bp Ret 6 ENDP ENDS END
Contoh program pascal yang menggunakan HexStrm hex.pas : Program HexTest; Var Num : word; Function HexStr (var num; byteCount : Byte) : string; far; external; {$L HEXSTR.OBJ} begin
num : = $face; Writeln (‘The Converted Hex String is “’, HexStr(num, sizeof(num),’”’); End. 8.5. Hubungan dengan Turbo C Kompile dan Link Integrated Development Environment (IDE). Dengan Turbo C, kita dapat menggunakan IDE (TC.EXE), yang di dalamnya terdapat editor, compiler dan debugger. Dalam mode ini, kita harus membuat file project ketika me-link modul bahasa assembly ke program C. Misalkan kita punya program utama ex1.c yang memanggil subrutin bahasa assembly yang berada dalam modul ex1a.asm. Berikut ini cara untuk mengkompile dan menjalankan program : Pilih peirntah Project/Open dalam menu Turbo C, dan beri nama project dengan example1.prj. Pilih perintah Project/Add dan pilih file ex1.c dan ex1a.asm. Pilih Transfer/Turbo assembler dari menu sistem (alt-space). Jika Turbo C diinstal dengan benar maka dia akan menjalankan turbo assembler (TASM.EXE ) dan mengasemly ex1a.asm. Tekan F9 untuk mengkompile dan link program. Linker akan menghubungkan ex1.obj dengan ex1a.obj dan menghasilkan example.exe. Rangkuman file-file yang diperlukan sebagai berikut : Nama File Penjelasan Ex1.c File Sumber Bahasa C Ex1a.asm File Sumber Bahasa Assembly Ex1.obj Modul C yang sudah dikompilasi Ex1a.obj Modul Assmbly yang sudah dikompilasi Example1.prj File Project Example1.exe Progam yang dapat dieksekusi Kompilasi Perintah-Baris. Untuk mengkompilasi modul program, dalam Turbo C menggunkakan model memory small, tapi kita dapat mengubahnya dengan pilihan pada perintah-baris. Untuk mengkompilasi dan menghubungkan (link) program ex1.c dan ex1a.asm dan menghasilkan example.exe, kita harus menuliskan perintah berikut : tcc –eexample1 ex1 ex1a.asm Opsi –e menunjukan nama file program yang dapat dieksekusi akhir. Turbo C mengasumsikan bahwa nama file ex1 mengacu pada program C. file ex1a.asm harus menggunakan ekstention, untuk memaksa compilator untuk menjalankan assembler. Karena itu TASM.EXE harus tersedia pada direktori yang sama.
Memanggil fungsi ADDEM Misal kita membuat program C yang memanggil subrutin bahasa assembly yang disebut ADDEM. Subrutin ini menjumlahkan nilai tiga buah integer dan mengembalikan hasil jumlahnya. Dalam program C, kita memberi nilai pada variabel a, b, dan c dan mengirim nilainya ke ADDEM. Hasil yang dikembalikan terdapat pada variabel total. Program C untuk fungsi tersebut sebagai berikut : #include <stdio.h> extern int addem(int p1, intp2, int p3) int a, b, c, total; main() { int total = 0, a=1, b=2, c=3; printf (“\n Adding 1+2+3 : total = addem(a,b,c); printf(“Total = %d\n”, total); return 0; }
”);
Program C mengirimkan nilai argumen, karena itu fungsi addem() tidak dapat mengubahnya. Jika kita ingin mengirimkan alamat a, b, dan c maka kita harus menambah dengan operator alamat : total = addem(&a, &b, &c); Subrutin ADDEM. Kita tidak anggap bahwa ADDEM meningkatkan performansi program C. Kenyataannya, terdapat overhead yang perlu dipertimbangkan (tujuh atau delapan instruksi) dilibatkan hanya untuk memanggil subrutin. Berikut ini cara bekerja sistemnya. Fungsi C selalu mengembalikan hasil fungsi 16-bit dalam AX, jadi ADDEM melakukan hal yang sama. Catatan, semua simbol public, termasuk register, dikodekan dengan diawali karakter garisbawah ( _ ) title Subrutin yang dipanggil oleh EX1.C public _addem dosseg .model small .code _addem proc near push bp mov bp, sp mov ax, [bp + 8] mov ax, [bp + 6] mov ax, [bp + 4] pop bp
ret _addem endp end Stack Frame. Seperti pada contoh sebelumnya, kita memasukan BP dan menset BP dengan SP pada awal rutin. Catatan, bahwa RET tidak mengandung konstanta, seperti yang berlaku pada contoh pascal. Dalam C, program program pemanggil bertanggung jawab untuk set ulang stack pada keadaan awal sesudah subrutin kembali. Program C pemanggil memasukan tiga argumen ke dalam staack dengan urutan terbalik. Gambar stack sesudah memasukan BP adalah sebagai berikut :
[BP + 8] [BP + 6] [BP + 4] [BP + 2] BP -->
0003 0002 0001 ret addr BP
c b a Å SP
Berikut ini program C pemanggil yang diurai. Nilai setiap argumennya dimasukan dalam stack sebagai pemanggilan. Setelah pemanggilan, 6 diatambahkan pada SP untuk mengembalikannya pada nilai asal, dan hasil fungsi dalam AX dipindahkan ke dalam total : Offset 018E 0192 0196 019A 019D 01A0
Instruksi push [0352] push [034C] push [0350] call 01B1 add SP, +06 mov [034E], AX
Case Sensitivity. Program C adalah case sensitive, artinya bahwa identifier seperti addem adalah diperlakukan berbeda dengan Addem, ADDEM, addDEM dan sebagainya. Hal ini merupkan potensi masalah yang akan timbul dengan subrutin assembly karena assembler secara otomatis mengkonversi semua nama menjadi huruf besar. Pada Tubro C ++ terdapat perintah /mx untuk mencegah pengubahaan oleh assembler menjadi huruf besar. Contoh Enkripsi File Berikut ini program C yang disebut ENCODE, yang membuka file untuk input dalam mode biner, memabaca satu blok data ke dalam buffer, mengirim buffer ke subrutin bahasa assembly, dan menulis buffer ke file output. Proses ini berulang
sampai akhir file input dicapai. Subrutin assembly mengenkripsi semua karakter dalam buffer dengan operasi XOR karakter dengan suatu nilai. Berikut #include <stdio.h> #include <stdlib.h> #define BUFSIZE 20000 extern void translate_buffer (char *buf, unsigned int count, char eChar); main (int argc, char *argv[]) { unsigned int count; char encryptChar = 241; FILE *inf, *outf; char buffer [BUFSIZE] inf = fopen(argv[1], “rb”); outf = fopen(argv[2], “wb”); count = fread (buffer, 1, BUFSIZE, inf); While (count!=0) { translate_buffer(buffer, count, encryptChar); fwrite(buffer, 1, count, outf); count = fread (buffer, 1, BUFSIZE, inf); } return 0; } Pada program diatas, fungsi eksternal dideklarasikan sebagai translate_buffer. Argumen yang dikirim ke fungsi melibatkan pointer ke buffer input, count memberitahu rutin berapa karakter yang akan ditranslasikan, dan karakter yang digunakan untuk penerjemahan. Tidak ada nilai kembali yang diperlukan, karena buffer diubah pada tempatnya : extern void translate_buffer(char *buf, unsigned int count, char eChar); Translate_buffer. Modul bahasa assembly yang dipanggil oleh ENCODE.C adalah ENCODE_A.ASM, sebagai berikut : title subrutin translate_buffer (ENCODE_A.ASM) dosseg .model small .code
public C translate_buffer translate_buffer proc C near bufptr:word, count:word, char:byte mov bx, bufptr mov cx, count mov dl, char cmp cx, 0 je @2 @1 : xor byte ptr[bx], dl inc bx loop @1 @2 : ret translate_buffer endp end 8. 6. Antarmuka Turbo Assembler Dengan Borland C++ Memanggil fungsi turbo assembler dari borland C++ : C++ dan assembler telah dapat disatukan dengan menulis modul yang berbeda yang seluruhnya dalam C++ atau assembler. Berikut ini proses penggabungan modul-modul dalam C++ dan assembler. File Sumber C++ FILENAME.CPP
Borland C++
File Sumber Assembler : FILENAME.ASM
COMPILE
File Objek FILENAME.OBJ
Turbo assembler
File Objek FILENAME.OBJ
TLINK
File yang dapat dieksekusi FILENAME.EXE
ASSEMBLE
File yang dapat dieksekusi dihasilkan dari penggabungan file sumber C++ dan assembler. Siklus ini dimulai dengan perintah : Bcc filenam1.cpp filenam2.asm Instruksi ini pertama kali mengkompile FILENAM1.CPP menjadi FILENAM1.OBJ, kemudian memanggil turbo assembler untuk mengassemble FILENAM2.ASM menjadi FILENAM2.OBJ, dan terakhir memanggil TLINK untuk me-link FILENAM1.OBJ dan FILENAM2.OBJ ke dalam FILENAM1.EXE. Program dengan ukuran yang besar sebaiknya kompilasi dilakukan secara terpisah. Pemrogram harus mengurus semua detail antar muka antara borland C++ dengan kode turbo assembler. Dimana borland C++ menangani spesifikasi segmen, parameter yang dilewatkan, mengacu pada variabel C++, pengelolaan variabel register dll. Terdapat dua aspek utama untuk menghubungkan antara borland C++ dan turbo assembler. Pertama, berbagai bagian borland C++ dan kode turbo assembler harus dihubungkan dengan baik, dan fungsi dan variabel pada masing bagian kode harus dibuat tersedia bagi kode yang lain sesuai dengan keperluannya. Kedua, kode turbo assembler harus menangani cara pemanggilan fungsi C++ dengan baik. Hal ini menyangkut di dalamnya pengaksesan parameter yang dilewatkan, nilai yang dikembalikan, dan mengikuti aturan penyediaan register yang diperlukan oleh fungsi C++. Kerangka Kerja Tiga hal yang harus dilakukan untuk menghubungkan modul borland C++ dan turbo assembler : Modul turbo assembler harus menggunakan skema penamaan segmen yang cocok dalam Borland C++ Modul Borland C++ dan Turbo assembler harus berbagi nama fungsi dan variable yang seusuai dalam bentuk yang dapat diterima oleh Borland C++ TLINK harus digunakan untuk menggabungkan modul-modul ke dalam program yang dapat dieksekusi. Contoh berikut menunjukan empat definisi fragmen yang berbeda dengan nama fungsi test : void test() { } void test(int) { } void test(int,int) { } void test(float, double)
{ } Jika kode tersebut dikompile menggunakan pilihan –S, kompiler akan menghasilkan file keluaran bahasa assembly (.ASM). Dalam bahasa assembler prosedur ditulis sebagai berikut : ; void test() @test$qv
ret @test$qv
proc near push bp mov bp, sp pop bp endp
; void test(int) @test$qi proc
near push bp
mov bp,sp pop bp ret @test$qi
endp
;void test(int, int) @test$qii proc near push bp mov bp, sp pop bp ret @test$qii endp ;void test(float, double) @test$qfd proc near push bp mov bp, sp pop bp ret @test$qfd endp Menggunakan Extern “C” Pada Borland C++ memungkinkan untuk mendefinisikan nama fungsi standar C dalam program C++. Contoh : Extern “C” { Int add(int *a, int b);
} Berikut ini definisi prosedur assembler yang sesuai. Public _add _add proc Pendeklarasian fungsi assembler dalam blok perintah extern dalam “C” akan memudahkan dalam pengelolaan kode. Model memori dan segmen Untuk fungsi assembler yang dapat dipanggil dari C++, harus menggunakan model memori yang sama seperti program C++ dan harus menggunakan segmen kode yang bersesuaian dengan C++. Begitu juga, data yang didefinisikan dalam modul assembler yang akan diakses oleh kode C++ (atau untuk data C++ yang akan diakses oleh kode assembler), kode assembler harus mengikuti atuaran penamaan segmen data C++. Model memori dan penanganan segmen dapat benar-benar komplek untuk diimplementasikan dalam assembler. Untungnya turbo assembler melakukan model memori dan segmen yang bersesuaian dengan C++ secara virtual untk melaksanakan perintah segmen yang disederhanakan. Public dan eksternal Turbo assembler dapat memanggil fungsi C++ dan mengacu pada variabel eksternal C++. Demikian juga kode borland C++ dapat memanggil fungsi public turbo assembler dan dapat mengacu variabel-variabel dalam turbo assembler. Underscore dan bahasa C Dalam pemrograman C atau C++, semua label eksternal harus dimulai dengan karakter underscore ( _ ). Kompiler C dan C++ otomatis menambahkan underscore pada semua fungsi dan nama varibel eksternal ketika digunakan dalam kode C/C++. Semua assembler yang mengacu pada fungsi atau variabel C atau C++ harus dimulai dengan underscore. Dan begitu juga semua fungsi dan variabel yang dibuat public dan diacu oleh kode C/C++ harus dimulai dengan underscore. Contoh kode C berikut (link2asm.cpp) : Int ToggleFlag(); Int Flag; Main () { ToggleFlag(); } Terhubung dengan program assembler berikut (CASMLINK.ASM) : . MODEL . DATA
small
EXTRN
_Flag : Word
. CODE PUBLIC _ToggleFlag _ToggleFlag PROC cmp [ _Flag],0 jz SetFlag mov [ _Flag],0 jmp short EndToggleFlag SetFlag : ; label yang tidak diacu oleh C ; tidak perlu menggunakan underscore mov [ _Flag],1 EndToggleFlag : Ret _ToggleFlag ENDP END Antara Turbo assembler dan Borland C++ Terdapat tiga hal yang penting dalam pemanggilan modul assembler oleh C atau sebaliknya : Penerimaan parameter yang dilewatkan Penggunaan register Pengembalian nilai kepada kode yang pamanggil. Borland C++ melewatkan parameter ke fungsi dalam bentuk stack. Sebelum memanggil fungsi, Borland C++ pertama kali memasukan parameter ke fungsi tersebut ke dalam stack, mulai dari parameter paling kanan. Fungsi pemanggilan C++ … … Test (i, j, l) … … Jika dikompile melakukan mov ax,1 push ax push WORD PTR DGROUP:_j push WORD PTR DGROUP:_i call NEAR PTR _Test add sp, 6 Pertama kali l dimasukan kemudian j dan i. Pemanggilan fungsi Assembler dari C++
Modul turbo assembler berikut, COUNT.ASM, mengandung fungsi LineCount, yang mengembalikan jumlah baris dan karakter dalam string yang dilewatkan. NEWLINE EQU 0ah .MODEL small .CODE PUBLIC _LineCount _LineCount PROC push bp mov bp, sp push si mov si, [bp+4] sub cx, cx mov dx, dx LineCountLoop : lodsb and al,al jz EndLineCount inc cx cmp al, NEWLINE jnz LineCountLoop inc dx jmp LineCountLoop EndLineCount : inc dx mov bx, [bp+6] mov [bx], cx mov ax, dx pcp si pop bp ret _LineCount EDP END Program C++ berikut (CALLCT.CPP) adalah contoh kode yang memanggil fungsi LineCount : Char * TestString=Line 1\nline 2\nline 3”; extrn “C” { unsigned int LineCount (Char * StringToCount, unsigned int * CharacterCountPtr); } main () { unsigned int LCount; unsigned int CCount;
LCount = LineCount (); printf(“Lines : %d\n Characters : %d\n”, LCount, CCount); } Perintah berikut untuk mengkompilasi kedua modul diatas bcc – ms callct.cpp count.asm Pemanggilan Borland C++ dari Turbo Assembler Berikut ini contoh pemanggilan fungsi borland C++ dari turbo assembler. Program CALCAVG.CPP #include <stdio.h> extern “C” float Average(int far * ValuePtr, int NumberOfValues); const int NUMBER_OF_TEST_VALUES=10; int TestValues[NUMBER_OF_TEST_VALUES] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; main () { printf(“The Average value is : %f\n”, Average ( TestValues, NUMBER_OF_TEST_VALUES)); } extern “C” float IntDivide(int Dividend, int Divisor) { return ((float) Dividend/(float) Divisor); } Kode assembler yang berikut (AVERAGE.ASM) memanggil modul diatas : .MODEL small EXTRN _IntDivide:PROC .CODE PUBLIC _Average _Average PROC push bp mov bp, sp les bx, [bp+4] mov cx, [bp+8] mov ax, 0 AverageLoop: add ax, es:[bx] add bx, 2 loop AverageLoop
push push call add pop ret _Average END
WORD PTR [bp+8] ax _IntDivide sp, 4 bp ENDP
IX. CONTOH PROGRAM Program Untuk Proteksi DOS 1. SOURCE CODE DIRPASS.ASM code segment assume cs:code org 100h mulai : jmp start ofs2f dw 0 seg2f dw 0 buff db 300 dup(0) pesan : db 13,10 db 'DIR PASS version 1.0',13,10 db 'In order to see directories, you enter passsword !!',13,10 db 'Enter password : $' benar : db 13,10 db 'Password checking passed ',13,10,'$' salah : db 13,10 db 'Wrong Password !!',13,10 db 'DIR command aborted !!',13,10 db 13,10,'$' password : db not 'D',not 'I',not 'R',not 'P',not 'A',not 'S',not 'S' db not 13,not 0 cek :
cmp word ptr [si],'MI' jnz resident2 cmp word ptr [si+2],'4T' jnz resident2 mov ax,1111h iret
resident: cmp ax,5555h jz cek resident2 : cmp ax,0ae00h jz ganti keluar: jmp dword ptr cs:ofs2f
ganti : cmp byte ptr [si],3 jz terus1 jmp keluar terus1: push es push si push di push ax push cx mov cx,0 mov cl,byte ptr [si] inc si mov ax,cs mov es,ax mov di, offset buff rep movsb pop cx pop ax pop di pop si pop es cmp word ptr cs:buff,'ID' jz terus2 jmp keluar terus2: cmp byte ptr cs:buff+2,'R' jz terus3 jmp keluar terus3: push ds push ax push dx push si push cs pop ds mov ah,9 mov dx,offset password int 21h ask0 : mov si,offset password ask1 : mov dl,ds:[si] not dl cmp dl,0 jz ask6
ask2 : mov ah,0 int 16h cmp al,13 jz ask3 cmp al,dl jz ask4 jmp ask0 ask3 : cmp si,offset password jz ask3_a inc si jmp ask1 ask3_a: mov ah,9 mov dx,offset salah int 21h jmp ask5 ask4 : inc si jmp ask1 ask5 : pop si pop dx pop ax pop ds mov byte ptr [si],0 mov al,0ffh iret ask6 : mov ah,9 mov dx,offset benar int 21h pop si pop dx pop ax pop ds jmp keluar start : mov ah,9 mov dx,offset nama int 21h mov ax,5555h mov si,offset code int 2fh cmp ax,1111h jnz start2
mov ah,9 mov dx,offset sudah int 21h int 20h start2: mov ax,352fh int 21h mov ofs2f,bx mov seg2f,es mov ax,252fh mov dx,offset resident int 21h mov ah,9 mov dx,offset sukses int 21h mov dx,offset start int 27h nama : db 13,10 db 'DIR PASS version 1.0',13,10 db 'Created by BPTR Club',13,10 db '(c) 2002 by STTTelkom',13,10 db 13,10,'$' kode : db 'Iri-X' sudah : db 13,10 db 'Sorry',13,10 db 'Program sudah pernah diinstall',13,10 db 13,10,'$' sukses: db 13,10 db '========Installed========',13,10 db 13,10,'$' code ends end mulai 2. SOURCE CODE NOCOPY.ASM code segment assume cs:code org 100h mulai: jmp start ofs2f dw 0 seg2f dw 0 buff db 300 dup(0)
pesan: db 13,10 db 'NO COPY version 1.0',13,10 db 'Warning !!!',13,10 db 'It''s illegal to duplicate files without permission !!',13,10 db 'COPY command aborted !!',13,10 db 13,10,'$' cek: cmp word ptr [si],'MI' jnz resident2 cmp word ptr [si+2],'1T' jnz resident2 mov ax,1111h iret resident: cmp ax,5555h jz cek resident2: cmp ax,0ae00h jz ganti keluar: jmp dword ptr cs:ofs2f ganti: cmp byte ptr [si],4 jz terus1 jmp keluar terus1: push es push si push di push ax push cx mov cx,0 mov cl,byte ptr [si] inc si mov ax,cs mov es,ax mov di,offset buff rep movsb pop cx pop ax pop di pop si pop es cmp word ptr cs:buff,'OC' jz terus2 jmp keluar terus2: cmp word ptr cs:buff+2,'YP' jz terus3 jmp keluar terus3: push ds push ax push dx
push cs pop ds mov ah,9 mov dx,offset pesan int 21h pop dx pop ax pop ds mov byte ptr [si],0 mov al,0ffh iret start: mov ah,9 mov dx,offset nama int 21h mov ax,5555h mov si,offset kode int 2fh cmp ax,1111h jnz start2 mov ah,9 mov dx,offset sudah int 21h int 20h start2: mov ax,352fh int 21h mov ofs2f,bx mov seg2f,es mov ax,252fh mov dx,offset resident int 21h mov ah,9 mov dx,offset sukses int 21h mov dx,offset start int 27h nama: db 13,10 db 'NO COPY version 1.0',13,10 db 'Created by IF',13,10 db '(c).2002 by STTTelkom',13,10 db 13,10,'$' kode: db 'INT1' sudah: db 13,10 db 'Sorry,',13,10 db 'This program has been installed before',13,10 db 13,10,'$' sukses: db 13,10
db '*** Installed ***',13,10 db 13,10,'$' code ends end mulai 3. SOURCE CODE NODEL.ASM code segment assume cs:code org 100h mulai: jmp start ofs2f dw 0 seg2f dw 0 buff db 100 dup(0) pesan: db 13,10 db 'NO DEL version 1.0',13,10 db 'Warning !!!',13,10 db 'It''s illegal to delete iles without permission !!',13,10 db 'DEL / DELETE / ERASE command aborted !!',13,10 db 13,10,'$' cek: cmp word ptr [si],'MI' jnz resident2 cmp word ptr [si+2],'2T' jnz resident2 mov ax,1111h iret resident: cmp ax,5555h jz cek resident2: cmp ax,0ae00h jz ganti keluar: jmp dword ptr cs:ofs2f ganti: cmp byte ptr [si],3 jz DEL_terus1 cmp byte ptr [si],6 jz DELETE_terus1 cmp byte ptr [si],5 jz ERASE_terus1 jmp keluar DEL_terus1: push es push si push di push ax push cx mov cx,0 mov cl,byte ptr [si] inc si
mov ax,cs mov es,ax mov di,offset buff rep movsb pop cx pop ax pop di pop si pop es cmp word ptr cs:buff,'ED' jz DEL_terus2 jmp keluar DEL_terus2: cmp byte ptr cs:buff+2,'L' jz ALL_terus3 jmp keluar DELETE_terus1: push es push si push di push ax push cx mov cx,0 mov cl,byte ptr [si] inc si mov ax,cs mov es,ax mov di,offset buff rep movsb pop cx pop ax pop di pop si pop es cmp word ptr cs:buff,'ED' jz DELETE_terus2 jmp keluar DELETE_terus2: cmp word ptr cs:buff+2,'EL' jz DELETE_terus3 jmp keluar DELETE_terus3: cmp word ptr cs:buff+4,'ET' jz ALL_terus3 jmp keluar ERASE_terus1: push es push si push di push ax push cx
mov cx,0 mov cl,byte ptr [si] inc si mov ax,cs mov es,ax mov di,offset buff rep movsb pop cx pop ax pop di pop si pop es cmp word ptr cs:buff,'RE' jz ERASE_terus2 jmp keluar ERASE_terus2: cmp word ptr cs:buff+2,'SA' jz ERASE_terus3 jmp keluar ERASE_terus3: cmp byte ptr cs:buff+4,'E' jz ALL_terus3 jmp keluar ALL_terus3: push ds push ax push dx push cs pop ds mov ah,9 mov dx,offset pesan int 21h pop dx pop ax pop ds mov byte ptr [si],0 mov al,0ffh iret start: mov ah,9 mov dx,offset nama int 21h mov ax,5555h mov si,offset kode int 2fh cmp ax,1111h jnz start2 mov ah,9 mov dx,offset sudah int 21h
int 20h start2: mov ax,352fh int 21h mov ofs2f,bx mov seg2f,es mov ax,252fh mov dx,offset resident int 21h mov ah,9 mov dx,offset sukses int 21h mov dx,offset start int 27h nama: db 13,10 db 'NO COPY version 1.0',13,10 db 'Created by IF',13,10 db '(c).2002 by STTTelkom',13,10 db 13,10,'$' kode: db 'INT1' sudah: db 13,10 db 'Sorry,',13,10 db 'This program has been installed before',13,10 db 13,10,'$' sukses: db 13,10 db '*** Installed ***',13,10 db 13,10,'$' code ends end mulai SOURCE CODE PASSDOS.ASM code segment assume cs:code org 100h mulai: jmp start ofs2f dw 0 seg2f dw 0 buff db 300 dup (0) benar : db 13,10
db' PASS DOSS ',13,10 db' Version 1.0 ',13,10 db' Created by INFINITY ',13,10 db' (c) copyrigth Juni 2002 ',13,10 db' by : ',13,10 db 13,10,'$' salah: db ' Bad command or file name $' password : db not 'P', not 'A', not 'S', not 's', not 'D', not 'O', not 'S' resident : cmp ax,0ae00h jz ganti jmp dword ptr cs:ofs2f ganti : cmp byte ptr [si],7 jz terus1 keluar : mov byte ptr [si],7 push ds push dx push ax push cs pop ds mov ah,9 mov dx,offset salah int 21h pop ax pop dx pop ds mov al,0ffh iret terus1: push es push si push di push ax push cx
mov cx,0 mov cl,byte ptr [si] inc si mov ax,cs mov es,ax mov di,offset buff rep movsb pop cx pop ax pop di pop si pop es push ax push bx push cx push dx push ds push es push si push di push cs pop ds push cs pop es cek_pass0: mov si,offset password mov di,offset buff mov cx,7 cek_pass1: mov al,ds:[si] mov bl,es:[di] not al cmp al,bl jz cek_pass2 pop di pop si pop es
pop ds pop dx pop cx pop bx pop ax jmp keluar cek_pass2: inc si inc di dec cx jz cek_pass3 jmp cek_pass1 cek_pass3: push cs pop ds mov ah,9 mov dx,offset benar int 21h pop di pop si pop es pop ds pop dx pop cx pop bx pop ax push ds push es push ax push cx mov ax,0 mov es,ax push cs pop ds mov si,offset ofs2f mov di,2fh*4 mov cx,4 cli rep movsb
sti push cs pop es mov ah,49h int 21h pop cx pop ax pop es pop ds mov ax,4c00h int 21h start: mov ah,9 mov dx,offset nama int 21h mov ax,352fh int 21h mov ofs2f,bx mov seg2f,es mov ax,252fh mov dx,offset resident int 21h mov ah,9 mov dx,offset sukses int 21h mov dx,offset start int 27h nama : db 13,10 db ' PASS DOS version 1.0 ',13,10 db ' Created by INFINITY ',13,10 db ' (c) Juni 2002 by STT TELKOM ',13,10 db 13,10,'$' sukses: db 13,10 db ' *****Installed***** ',13,10 db 13,10,'$' code ends end mulai
DAFTAR PUSTAKA Irvine, Kip. [1993], Assembly Language for The IBM-PC, MacMillan, United State of America. User’s Guide, Turbo Assembler 3.00. T